LCOV - code coverage report
Current view: top level - src/app - devicecommand.cpp (source / functions) Hit Total Coverage
Project: QtPokit Lines: 43 61 70.5 %
Version: Functions: 9 10 90.0 %

          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             : #include "devicecommand.h"
       5             : 
       6             : #include <qtpokit/abstractpokitservice.h>
       7             : #include <qtpokit/pokitdevice.h>
       8             : #include <qtpokit/pokitdiscoveryagent.h>
       9             : 
      10             : /*!
      11             :  * \class DeviceCommand
      12             :  *
      13             :  * The AbstractCommand class extends AbstractCommand to add a PokitDevice instance.
      14             :  */
      15             : 
      16             : /*!
      17             :  * Construct a new DeviceCommand object with \a parent.
      18             :  */
      19       11592 : DeviceCommand::DeviceCommand(QObject * const parent) : AbstractCommand(parent), device(nullptr),
      20        5796 :     exitCodeOnDisconnect(EXIT_FAILURE)
      21             : {
      22             : 
      23        5796 : }
      24             : 
      25             : /*!
      26             :  * Begins scanning for the Pokit device.
      27             :  */
      28          34 : bool DeviceCommand::start()
      29             : {
      30          68 :     qCInfo(lc).noquote() << ((deviceToScanFor.isNull())
      31          62 :         ? tr("Looking for first available Pokit device...")
      32          71 :         : tr("Looking for device \"%1\"...").arg(deviceToScanFor));
      33          34 :     discoveryAgent->start();
      34          34 :     return true;
      35             : }
      36             : 
      37             : /*!
      38             :  * Disconnects the underlying Pokit device, and sets \a exitCode to be return to the OS once the
      39             :  * disconnection has taken place.
      40             :  */
      41         441 : void DeviceCommand::disconnect(int exitCode)
      42             : {
      43         441 :     qCDebug(lc).noquote() << tr("Disconnecting Pokit device...");
      44             :     Q_ASSERT(device);
      45             :     Q_ASSERT(device->controller());
      46         441 :     exitCodeOnDisconnect = exitCode;
      47         441 :     device->controller()->disconnectFromDevice();
      48         441 : }
      49             : 
      50             : /*!
      51             :  * \fn virtual AbstractPokitService * DeviceCommand::getService() = 0
      52             :  *
      53             :  * Returns a Pokit service object for the derived command class. This will be called by
      54             :  * deviceDiscovered() when the requested Pokit device has been found, after which
      55             :  * deviceDiscovered() will connect the returned service's common signals, and kick off the
      56             :  * device's connection process.
      57             :  */
      58             : 
      59             : /*!
      60             :  * Handles controller error events. This base implementation simply logs \a error and then exits
      61             :  * with `EXIT_FAILURE`. Derived classes may override this slot to implement their own error
      62             :  * handing if desired.
      63             :  */
      64          34 : void DeviceCommand::controllerError(QLowEnergyController::Error error)
      65             : {
      66         102 :     qCWarning(lc).noquote() << tr("Bluetooth controller error:") << error;
      67          34 :     QCoreApplication::exit(EXIT_FAILURE);
      68          34 : }
      69             : 
      70             : /*!
      71             :  * Handles devics disconnection events. This base implementation simply logs and exits the
      72             :  * application (via QCoreApplication::exit) with the current exitCodeOnDisconnect value, which is
      73             :  * initialise to `EXIT_FAILURE` in the constructor, but should be set to `EXIT_SUCESS` if/when
      74             :  * the derived command class has completed its actions and requested the disconnection (as opposed
      75             :  * to a spontaneous disconnection on error).
      76             :  */
      77          17 : void DeviceCommand::deviceDisconnected()
      78             : {
      79          17 :     qCDebug(lc).noquote() << tr("Pokit device disconnected. Exiting with code %1.")
      80           0 :         .arg(exitCodeOnDisconnect);
      81          17 :     QCoreApplication::exit(exitCodeOnDisconnect);
      82          17 : }
      83             : 
      84             : /*!
      85             :  * Handles service error events. This base implementation simply logs \a error and then exits
      86             :  * with `EXIT_FAILURE`. Derived classes may override this slot to implement their own error
      87             :  * handing if desired.
      88             :  *
      89             :  * \note As this base class does not construct services (derived classed do), its up to the derived
      90             :  * classed to connect this slot to the relevant service's error signal if desired.
      91             :  */
      92          34 : void DeviceCommand::serviceError(const QLowEnergyService::ServiceError error)
      93             : {
      94         102 :     qCWarning(lc).noquote() << tr("Bluetooth service error:") << error;
      95          34 :     QCoreApplication::exit(EXIT_FAILURE);
      96          34 : }
      97             : 
      98             : /*!
      99             :  * Handles service detail discovery events. This base implementation simply logs the event, and
     100             :  * nothing more. Derived classes may (usually do) override this slot to provide their own processing
     101             :  * when a services details have been discovered.
     102             :  */
     103         322 : void DeviceCommand::serviceDetailsDiscovered()
     104             : {
     105         322 :     qCDebug(lc).noquote() << tr("Service details discovered.");
     106         322 : }
     107             : 
     108             : /*!
     109             :  * Checks if \a info is the device (if any) we're looking for, and if so, create a contoller and
     110             :  * service, and begins connecting to the device.
     111             :  */
     112          17 : void DeviceCommand::deviceDiscovered(const QBluetoothDeviceInfo &info)
     113             : {
     114          17 :     if (device) {
     115           0 :         qCDebug(lc).noquote() << tr("Ignoring additional Pokit device \"%1\" (%2) at (%3).")
     116           0 :             .arg(info.name(), info.deviceUuid().toString(), info.address().toString());
     117           0 :         return;
     118             :     }
     119             : 
     120          51 :     if ((deviceToScanFor.isEmpty()) || (deviceToScanFor == info.name()) ||
     121          68 :         ((!info.address().isNull()) && (info.address() == QBluetoothAddress(deviceToScanFor))) ||
     122          34 :         ((!info.deviceUuid().isNull()) && (info.deviceUuid() == QBluetoothUuid(deviceToScanFor))))
     123             :     {
     124           0 :         qCDebug(lc).noquote() << tr("Found Pokit device \"%1\" (%2) at (%3).")
     125           0 :             .arg(info.name(), info.deviceUuid().toString(), info.address().toString());
     126           0 :         discoveryAgent->stop();
     127             : 
     128           0 :         device = new PokitDevice(info, this);
     129           0 :         connect(device->controller(), &QLowEnergyController::disconnected,
     130             :                 this, &DeviceCommand::deviceDisconnected);
     131           0 :         connect(device->controller(),
     132             :             #if (QT_VERSION < QT_VERSION_CHECK(6, 2, 0))
     133             :             QOverload<QLowEnergyController::Error>::of(&QLowEnergyController::error),
     134             :             #else
     135             :             &QLowEnergyController::errorOccurred,
     136             :             #endif
     137             :             this, &DeviceCommand::controllerError, Qt::QueuedConnection);
     138             : 
     139           0 :         AbstractPokitService * const service = getService();
     140             : 
     141             :         Q_ASSERT(service);
     142           0 :         connect(service, &AbstractPokitService::serviceDetailsDiscovered,
     143             :                 this, &DeviceCommand::serviceDetailsDiscovered);
     144           0 :         connect(service, &AbstractPokitService::serviceErrorOccurred,
     145             :                 this, &DeviceCommand::serviceError);
     146             : 
     147           0 :         qCDebug(lc).noquote() << tr("Connecting to Pokit device \"%1\" (%2) at (%3).")
     148           0 :             .arg(info.name(), info.deviceUuid().toString(), info.address().toString());
     149           0 :         device->controller()->connectToDevice();
     150           0 :         return;
     151             :     }
     152             : 
     153          17 :     qCDebug(lc).noquote() << tr("Ignoring non-matching Pokit device \"%1\" (%2) at (%3).")
     154           0 :         .arg(info.name(), info.deviceUuid().toString(), info.address().toString());
     155           2 :     return;
     156             : }
     157             : 
     158             : /*!
     159             :  * Checks that the requested device was discovered, and if not, reports and error and exits.
     160             :  */
     161          34 : void DeviceCommand::deviceDiscoveryFinished()
     162             : {
     163          34 :     if (!device) {
     164          68 :         qCWarning(lc).noquote() << ((deviceToScanFor.isNull())
     165          62 :             ? tr("Failed to find any Pokit device.")
     166          71 :             : tr("Failed to find device \"%1\".").arg(deviceToScanFor));
     167          34 :         QCoreApplication::exit(EXIT_FAILURE);
     168             :     }
     169          34 : }

Generated by: LCOV version 1.14