LCOV - code coverage report
Current view: top level - src/lib - deviceinfoservice.cpp (source / functions) Hit Total Coverage
Project: Dokit Lines: 64 92 69.6 %
Version: Functions: 19 23 82.6 %

          Line data    Source code
       1             : // SPDX-FileCopyrightText: 2022-2023 Paul Colby <git@colby.id.au>
       2             : // SPDX-License-Identifier: LGPL-3.0-or-later
       3             : 
       4             : /*!
       5             :  * \file
       6             :  * Defines the DeviceInfoService and DeviceInfoServicePrivate classes.
       7             :  */
       8             : 
       9             : #include <qtpokit/deviceinfoservice.h>
      10             : #include "deviceinfoservice_p.h"
      11             : 
      12             : #include <QtEndian>
      13             : 
      14             : /*!
      15             :  * \class DeviceInfoService
      16             :  *
      17             :  * The DeviceInfoService class accesses the `Device Info` service of Pokit devices.
      18             :  */
      19             : 
      20             : /*!
      21             :  * Constructs a new Pokit service with \a parent.
      22             :  */
      23         600 : DeviceInfoService::DeviceInfoService(QLowEnergyController * const controller, QObject * parent)
      24         600 :     : AbstractPokitService(new DeviceInfoServicePrivate(controller, this), parent)
      25             : {
      26             : 
      27         600 : }
      28             : 
      29             : /*!
      30             :  * \cond internal
      31             :  * Constructs a new Pokit service with \a parent, and private implementation \a d.
      32             :  */
      33           0 : DeviceInfoService::DeviceInfoService(
      34           0 :     DeviceInfoServicePrivate * const d, QObject * const parent)
      35           0 :     : AbstractPokitService(d, parent)
      36             : {
      37             : 
      38           0 : }
      39             : /// \endcond
      40             : 
      41             : /*!
      42             :  * Destroys this DeviceInfoService object.
      43             :  */
      44         270 : DeviceInfoService::~DeviceInfoService()
      45             : {
      46             : 
      47         270 : }
      48             : 
      49          18 : bool DeviceInfoService::readCharacteristics()
      50             : {
      51          12 :     const bool r1 = readFirmwareRevisionCharacteristic();
      52          12 :     const bool r2 = readHardwareRevisionCharacteristic();
      53          12 :     const bool r3 = readSoftwareRevisionCharacteristic();
      54          12 :     const bool r4 = readManufacturerCharacteristics();
      55          12 :     const bool r5 = readModelNumberCharacteristic();
      56          30 :     const bool r6 = ((service() != nullptr) && (service()->characteristic(CharacteristicUuids::serialNumber).isValid()))
      57          18 :         ? readSerialNumberCharacteristic() : true;
      58          30 :     return (r1 && r2 && r3 && r4 && r5 && r6);
      59             : }
      60             : 
      61             : /*!
      62             :  * Read the `Device Info` service's `Firmware Revision` characteristic.
      63             :  *
      64             :  * Returns `true` is the read request is succesfully queued, `false` otherwise (ie if the
      65             :  * underlying controller it not yet connected to the Pokit device, or the device's services have
      66             :  * not yet been discovered).
      67             :  *
      68             :  * Emits firmwareRevisionRead() if/when the characteristic has been read successfully.
      69             :  */
      70          30 : bool DeviceInfoService::readFirmwareRevisionCharacteristic()
      71             : {
      72             :     Q_D(DeviceInfoService);
      73          36 :     return d->readCharacteristic(CharacteristicUuids::firmwareRevision);
      74             : }
      75             : 
      76             : /*!
      77             :  * Read the `Device Info` service's `Hardware Revision` characteristic.
      78             :  *
      79             :  * Returns `true` is the read request is succesfully queued, `false` otherwise (ie if the
      80             :  * underlying controller it not yet connected to the Pokit device, or the device's services have
      81             :  * not yet been discovered).
      82             :  *
      83             :  * Emits hardwareRevisionRead() if/when the characteristic has been read successfully.
      84             :  */
      85          30 : bool DeviceInfoService::readHardwareRevisionCharacteristic()
      86             : {
      87             :     Q_D(DeviceInfoService);
      88          36 :     return d->readCharacteristic(CharacteristicUuids::hardwareRevision);
      89             : }
      90             : 
      91             : /*!
      92             :  * Read the `Device Info` service's `Manufacturer Name` characteristic.
      93             :  *
      94             :  * Returns `true` is the read request is succesfully queued, `false` otherwise (ie if the
      95             :  * underlying controller it not yet connected to the Pokit device, or the device's services have
      96             :  * not yet been discovered).
      97             :  *
      98             :  * Emits manufacturerNameRead() if/when the characteristic has been read successfully.
      99             :  */
     100          30 : bool DeviceInfoService::readManufacturerCharacteristics()
     101             : {
     102             :     Q_D(DeviceInfoService);
     103          36 :     return d->readCharacteristic(CharacteristicUuids::manufacturerName);
     104             : }
     105             : 
     106             : /*!
     107             :  * Read the `Device Info` service's `Model Number` characteristic.
     108             :  *
     109             :  * Returns `true` is the read request is succesfully queued, `false` otherwise (ie if the
     110             :  * underlying controller it not yet connected to the Pokit device, or the device's services have
     111             :  * not yet been discovered).
     112             :  *
     113             :  * Emits modelNumberRead() if/when the characteristic has been read successfully.
     114             :  */
     115          30 : bool DeviceInfoService::readModelNumberCharacteristic()
     116             : {
     117             :     Q_D(DeviceInfoService);
     118          36 :     return d->readCharacteristic(CharacteristicUuids::modelNumber);
     119             : }
     120             : 
     121             : /*!
     122             :  * Read the `Device Info` service's `Software Revision` characteristic.
     123             :  *
     124             :  * Returns `true` is the read request is succesfully queued, `false` otherwise (ie if the
     125             :  * underlying controller it not yet connected to the Pokit device, or the device's services have
     126             :  * not yet been discovered).
     127             :  *
     128             :  * Emits softwareRevisionRead() if/when the characteristic has been read successfully.
     129             :  */
     130          30 : bool DeviceInfoService::readSoftwareRevisionCharacteristic()
     131             : {
     132             :     Q_D(DeviceInfoService);
     133          36 :     return d->readCharacteristic(CharacteristicUuids::softwareRevision);
     134             : }
     135             : 
     136             : /*!
     137             :  * Read the `Device Info` service's (undocumented) `Serial Number` characteristic.
     138             :  *
     139             :  * Returns `true` is the read request is succesfully queued, `false` otherwise (ie if the
     140             :  * underlying controller it not yet connected to the Pokit device, or the device's services have
     141             :  * not yet been discovered).
     142             :  *
     143             :  * Emits serialNumberRead() if/when the characteristic has been read successfully.
     144             :  */
     145          18 : bool DeviceInfoService::readSerialNumberCharacteristic()
     146             : {
     147             :     Q_D(DeviceInfoService);
     148          18 :     return d->readCharacteristic(CharacteristicUuids::serialNumber);
     149             : }
     150             : 
     151             : /*!
     152             :  * Returns the most recent value of the `Device Info` service's `Manufacturer Name` characteristic.
     153             :  *
     154             :  * The returned value, if any, is from the underlying Bluetooth stack's cache. If no such value is
     155             :  * currently available (ie the serviceDetailsDiscovered signal has not been emitted yet), then a
     156             :  * null QString is returned.
     157             :  */
     158         330 : QString DeviceInfoService::manufacturer() const
     159             : {
     160             :     Q_D(const DeviceInfoService);
     161             :     const QLowEnergyCharacteristic characteristic =
     162         330 :         d->getCharacteristic(CharacteristicUuids::manufacturerName);
     163         660 :     return (characteristic.isValid()) ? QString::fromUtf8(characteristic.value()) : QString();
     164         330 : }
     165             : 
     166             : /*!
     167             :  * Returns the most recent value of the `Device Info` service's `Model Number` characteristic.
     168             :  *
     169             :  * The returned value, if any, is from the underlying Bluetooth stack's cache. If no such value is
     170             :  * currently available (ie the serviceDetailsDiscovered signal has not been emitted yet), then a
     171             :  * null QString is returned.
     172             :  */
     173         330 : QString DeviceInfoService::modelNumber() const
     174             : {
     175             :     Q_D(const DeviceInfoService);
     176             :     const QLowEnergyCharacteristic characteristic =
     177         330 :         d->getCharacteristic(CharacteristicUuids::modelNumber);
     178         660 :     return (characteristic.isValid()) ? QString::fromUtf8(characteristic.value()) : QString();
     179         330 : }
     180             : 
     181             : /*!
     182             :  * Returns the most recent value of the `Device Info` service's `Hardware Revision` characteristic.
     183             :  *
     184             :  * The returned value, if any, is from the underlying Bluetooth stack's cache. If no such value is
     185             :  * currently available (ie the serviceDetailsDiscovered signal has not been emitted yet), then a
     186             :  * null QString is returned.
     187             :  */
     188         330 : QString DeviceInfoService::hardwareRevision() const
     189             : {
     190             :     Q_D(const DeviceInfoService);
     191             :     const QLowEnergyCharacteristic characteristic =
     192         330 :         d->getCharacteristic(CharacteristicUuids::hardwareRevision);
     193         660 :     return (characteristic.isValid()) ? QString::fromUtf8(characteristic.value()) : QString();
     194         330 : }
     195             : 
     196             : /*!
     197             :  * Returns the most recent value of the `Device Info` service's `Firmware Revision` characteristic.
     198             :  *
     199             :  * The returned value, if any, is from the underlying Bluetooth stack's cache. If no such value is
     200             :  * currently available (ie the serviceDetailsDiscovered signal has not been emitted yet), then a
     201             :  * null QString is returned.
     202             :  */
     203         330 : QString DeviceInfoService::firmwareRevision() const
     204             : {
     205             :     Q_D(const DeviceInfoService);
     206             :     const QLowEnergyCharacteristic characteristic =
     207         330 :         d->getCharacteristic(CharacteristicUuids::firmwareRevision);
     208         660 :     return (characteristic.isValid()) ? QString::fromUtf8(characteristic.value()) : QString();
     209         330 : }
     210             : 
     211             : /*!
     212             :  * Returns the most recent value of the `Device Info` service's `Software Revision` characteristic.
     213             :  *
     214             :  * The returned value, if any, is from the underlying Bluetooth stack's cache. If no such value is
     215             :  * currently available (ie the serviceDetailsDiscovered signal has not been emitted yet), then a
     216             :  * null QString is returned.
     217             :  */
     218         330 : QString DeviceInfoService::softwareRevision() const
     219             : {
     220             :     Q_D(const DeviceInfoService);
     221             :     const QLowEnergyCharacteristic characteristic =
     222         330 :         d->getCharacteristic(CharacteristicUuids::softwareRevision);
     223         660 :     return (characteristic.isValid()) ? QString::fromUtf8(characteristic.value()) : QString();
     224         330 : }
     225             : 
     226             : /*!
     227             :  * Returns the most recent value of the `Device Info` service's (undocumented) `Serial Number`
     228             :  * characteristic.
     229             :  *
     230             :  * The returned value, if any, is from the underlying Bluetooth stack's cache. If no such value is
     231             :  * currently available (ie the serviceDetailsDiscovered signal has not been emitted yet), then a
     232             :  * null QString is returned.
     233             :  */
     234         330 : QString DeviceInfoService::serialNumber() const
     235             : {
     236             :     Q_D(const DeviceInfoService);
     237             :     const QLowEnergyCharacteristic characteristic =
     238         330 :         d->getCharacteristic(CharacteristicUuids::serialNumber);
     239             :     /*!
     240             :      * \cond internal
     241             :      * \pokitApi Unlike other string characteristics, Pokit (Pro) devices always appear to add a trailing
     242             :      * `null` byte to serial number strings. So here we strip any that are present.
     243             :      * \endcond
     244             :      */
     245         660 :     return (characteristic.isValid()) ? QString::fromUtf8(characteristic.value()).remove(QLatin1Char('\0')) : QString();
     246         330 : }
     247             : 
     248             : /*!
     249             :  * \fn DeviceInfoService::manufacturerRead
     250             :  *
     251             :  * This signal is emitted when the `Manufacturer Name` characteristic has been read successfully.
     252             :  *
     253             :  * \see readManufacturerCharacteristic
     254             :  * \see manufacturer
     255             :  */
     256             : 
     257             : /*!
     258             :  * \fn DeviceInfoService::modelNumberRead
     259             :  *
     260             :  * This signal is emitted when the `Model Number` characteristic has been read successfully.
     261             :  *
     262             :  * \see readModelNumberCharacteristic
     263             :  * \see modelNumber
     264             :  */
     265             : 
     266             : /*!
     267             :  * \fn DeviceInfoService::hardwareRevisionRead
     268             :  *
     269             :  * This signal is emitted when the `Hardware Revision` characteristic has been read successfully.
     270             :  *
     271             :  * \see readHardwareRevisionCharacteristic
     272             :  * \see hardwareRevision
     273             :  */
     274             : 
     275             : /*!
     276             :  * \fn DeviceInfoService::firmwareRevisionRead
     277             :  *
     278             :  * This signal is emitted when the `Firmware Revision` characteristic has been read successfully.
     279             :  *
     280             :  * \see readFirmwareRevisionCharacteristic
     281             :  * \see firmwareRevision
     282             :  */
     283             : 
     284             : /*!
     285             :  * \fn DeviceInfoService::softwareRevisionRead
     286             :  *
     287             :  * This signal is emitted when the `Software Revision` characteristic has been read successfully.
     288             :  *
     289             :  * \see readSoftwareRevisionCharacteristic
     290             :  * \see softwareRevision
     291             :  */
     292             : 
     293             : /*!
     294             :  * \fn DeviceInfoService::serialNumberRead
     295             :  *
     296             :  * This signal is emitted when the `Serial Number` characteristic has been read successfully.
     297             :  *
     298             :  * \see readSerialNumberCharacteristic
     299             :  * \see serialNumber
     300             :  */
     301             : 
     302             : /*!
     303             :  * \cond internal
     304             :  * \class DeviceInfoServicePrivate
     305             :  *
     306             :  * The DeviceInfoServicePrivate class provides private implementation for DeviceInfoService.
     307             :  */
     308             : 
     309             : /*!
     310             :  * \internal
     311             :  * Constructs a new DeviceInfoServicePrivate object with public implementation \a q.
     312             :  */
     313         420 : DeviceInfoServicePrivate::DeviceInfoServicePrivate(
     314         600 :     QLowEnergyController * controller, DeviceInfoService * const q)
     315         600 :     : AbstractPokitServicePrivate(DeviceInfoService::serviceUuid, controller, q)
     316             : {
     317             : 
     318         420 : }
     319             : 
     320             : /*!
     321             :  * Implements AbstractPokitServicePrivate::characteristicRead to parse \a value, then emit a
     322             :  * specialised signal, for each supported \a characteristic.
     323             :  */
     324          18 : void DeviceInfoServicePrivate::characteristicRead(const QLowEnergyCharacteristic &characteristic,
     325             :                                               const QByteArray &value)
     326             : {
     327          18 :     AbstractPokitServicePrivate::characteristicRead(characteristic, value);
     328             : 
     329             :     Q_Q(DeviceInfoService);
     330          18 :     if (characteristic.uuid() == DeviceInfoService::CharacteristicUuids::manufacturerName) {
     331           0 :         const QString name = QString::fromUtf8(value);
     332           0 :         qCDebug(lc).noquote() << tr(R"(Manufacturer name: "%1")").arg(name);
     333           0 :         emit q->manufacturerRead(name);
     334             :         return;
     335           0 :     }
     336             : 
     337          18 :     if (characteristic.uuid() == DeviceInfoService::CharacteristicUuids::modelNumber) {
     338           0 :         const QString model = QString::fromUtf8(value);
     339           0 :         qCDebug(lc).noquote() << tr(R"(Model number: "%1")").arg(model);
     340           0 :         emit q->modelNumberRead(model);
     341             :         return;
     342           0 :     }
     343             : 
     344          18 :     if (characteristic.uuid() == DeviceInfoService::CharacteristicUuids::hardwareRevision) {
     345           0 :         const QString revision = QString::fromUtf8(value);
     346           0 :         qCDebug(lc).noquote() << tr(R"(Hardware revision: "%1")").arg(revision);
     347           0 :         emit q->hardwareRevisionRead(revision);
     348             :         return;
     349           0 :     }
     350             : 
     351          18 :     if (characteristic.uuid() == DeviceInfoService::CharacteristicUuids::firmwareRevision) {
     352           0 :         const QString revision = QString::fromUtf8(value);
     353           0 :         qCDebug(lc).noquote() << tr(R"(Firmware revision: "%1")").arg(revision);
     354           0 :         emit q->firmwareRevisionRead(revision);
     355             :         return;
     356           0 :     }
     357             : 
     358          18 :     if (characteristic.uuid() == DeviceInfoService::CharacteristicUuids::softwareRevision) {
     359           0 :         const QString revision = QString::fromUtf8(value);
     360           0 :         qCDebug(lc).noquote() << tr(R"(Software revision: "%1")").arg(revision);
     361           0 :         emit q->softwareRevisionRead(revision);
     362             :         return;
     363           0 :     }
     364             : 
     365          18 :     if (characteristic.uuid() == DeviceInfoService::CharacteristicUuids::serialNumber) {
     366           0 :         const QString serialNumber = QString::fromUtf8(value);
     367           0 :         qCDebug(lc).noquote() << tr(R"(Serial number: "%1")").arg(serialNumber);
     368           0 :         emit q->serialNumberRead(serialNumber);
     369             :         return;
     370           0 :     }
     371             : 
     372          54 :     qCWarning(lc).noquote() << tr("Unknown characteristic read for Device Info service")
     373          24 :         << serviceUuid << characteristic.name() << characteristic.uuid();
     374             : }
     375             : 
     376             : /// \endcond

Generated by: LCOV version 1.14