Dokit
Internal development documentation
Loading...
Searching...
No Matches
pokitdevice.cpp
Go to the documentation of this file.
1// SPDX-FileCopyrightText: 2022-2024 Paul Colby <git@colby.id.au>
2// SPDX-License-Identifier: LGPL-3.0-or-later
3
4/*!
5 * \file
6 * Defines the PokitDevice and PokitDevicePrivate classes.
7 */
8
10
14#include <qtpokit/dsoservice.h>
17
18#include "pokitdevice_p.h"
19
20#include <QMutexLocker>
21
22/*!
23 * \class PokitDevice
24 *
25 * The PokitDevice class simplifies Pokit device access.
26 *
27 * It does this by wrapping QLowEnergyController to provide:
28 * * convenient Pokit service factory methods (dataLogger(), deviceInformation(), dso(),
29 multimeter() and status()); and
30 * * consistent debug logging of QLowEnergyController events.
31 *
32 * But this class is entirely optional, in that all features of all other QtPokit classes can be
33 * used wihtout this class. It's just a (meaningful) convenience.
34 */
35
36/*!
37 * Constructs a new Pokit device controller wrapper for \a deviceInfo, with \a parent.
38 *
39 * Though not strictly necessary, \a deviceInfo should normally come from a
40 * PokitDiscoveryAgent instance (or a QBluetoothDeviceDiscoveryAgent), otherwise connection
41 * is likely to fail with QLowEnergyController::UnknownRemoteDeviceError.
42 */
44 : QObject(parent), d_ptr(new PokitDevicePrivate(this))
45{
46 Q_D(PokitDevice);
47 d->setController(QLowEnergyController::createCentral(deviceInfo, this));
48}
49
50/*!
51 * Constructs a new Pokit device controller wrapper for \a controller, with \a parent.
52 */
54 : QObject(parent), d_ptr(new PokitDevicePrivate(this))
55{
56 Q_D(PokitDevice);
57 d->setController(controller);
58}
59
60/*!
61 * \cond internal
62 * Constructs a new Pokit device controller wrapper with \a parent, and private implementation \a d.
63 *
64 * Derived classes using this constructor should use PokitDevicePrivate::setController to assign
65 * the BLE controller as some point.
66 */
68 : QObject(parent), d_ptr(d)
69{
70
71}
72/// \endcond
73
74/*!
75 * Destroys this PokitDevice object.
76 */
78{
79 delete d_ptr;
80}
81
82/*!
83 * Returns a non-const pointer to the controller used to access the Pokit device.
84 */
86{
87 Q_D(PokitDevice);
88 return d->controller;
89}
90
91/*!
92 * Returns a const pointer to the controller used to access the Pokit device.
93 */
95{
96 Q_D(const PokitDevice);
97 return d->controller;
98}
99
100/// \cond
101#define QTPOKIT_INTERNAL_GET_SERVICE(typeName, varName) \
102 Q_D(PokitDevice); \
103 const QMutexLocker scopedLock(&d->varName##Mutex);\
104 if (d->varName == nullptr) { \
105 d->varName = new typeName(d->controller); \
106 } \
107 return d->varName \
108/// \endcond
109
110/*!
111 * Returns a pointer to a CalibrationService instance that uses this device's controller for access.
112 *
113 * This is a convenience function, that always returns the same pointer (for this PokitDevice
114 * instance), but the service itself is lazily created (in a threadsafe manner) on the first
115 * invocation of this function.
116 */
118{
119 QTPOKIT_INTERNAL_GET_SERVICE(CalibrationService, calibration);
120}
121
122/*!
123 * Returns a pointer to a DataLoggerService instance that uses this device's controller for access.
124 *
125 * This is a convenience function, that always returns the same pointer (for this PokitDevice
126 * instance), but the service itself is lazily created (in a threadsafe manner) on the first
127 * invocation of this function.
128 */
130{
131 QTPOKIT_INTERNAL_GET_SERVICE(DataLoggerService, dataLogger);
132}
133
134/*!
135 * Returns a pointer to DeviceInformationService instance that uses this device's controller for
136 * access.
137 *
138 * This is a convenience function, that always returns the same pointer (for this PokitDevice
139 * instance), but the service itself is lazily created (in a threadsafe manner) on the first
140 * invocation of this function.
141 */
143{
144 QTPOKIT_INTERNAL_GET_SERVICE(DeviceInfoService, deviceInfo);
145}
146
147/*!
148 * Returns a pointer to DsoService instance that uses this device's controller for access.
149 *
150 * This is a convenience function, that always returns the same pointer (for this PokitDevice
151 * instance), but the service itself is lazily created (in a threadsafe manner) on the first
152 * invocation of this function.
153 */
155{
156 QTPOKIT_INTERNAL_GET_SERVICE(DsoService, dso);
157}
158
159/*!
160 * Returns a pointer to MultimeterService instance that uses this device's controller for access.
161 *
162 * This is a convenience function, that always returns the same pointer (for this PokitDevice
163 * instance), but the service itself is lazily created (in a threadsafe manner) on the first
164 * invocation of this function.
165 */
167{
168 QTPOKIT_INTERNAL_GET_SERVICE(MultimeterService, multimeter);
169}
170
171/*!
172 * Returns a pointer to StatusService instance that uses this device's controller for access.
173 *
174 * This is a convenience function, that always returns the same pointer (for this PokitDevice
175 * instance), but the service itself is lazily created (in a threadsafe manner) on the first
176 * invocation of this function.
177 */
179{
180 QTPOKIT_INTERNAL_GET_SERVICE(StatusService, status);
181}
182#undef QTPOKIT_INTERNAL_GET_SERVICE
183
184/*!
185 * Returns a human-readable name for the \a uuid service, or a null QString if unknonw.
186 *
187 * This is equivalent to QBluetoothUuid::serviceClassToString() but for services provided by Pokit
188 * devices.
189 */
191{
192 static const QHash<QBluetoothUuid, QString> hash{
193 { CalibrationService::serviceUuid, tr("Calibration") },
194 { DataLoggerService::serviceUuid, tr("Data Logger") },
195 { DsoService::serviceUuid, tr("DSO") },
196 { MultimeterService::serviceUuid, tr("Multimeter") },
197 { StatusService::ServiceUuids::pokitMeter, tr("Status (Pokit Meter)") },
198 { StatusService::ServiceUuids::pokitPro, tr("Status (Pokit Pro)") },
200 QBluetoothUuid::serviceClassToString(QBluetoothUuid::ServiceClassUuid::DeviceInformation) },
201
202 // The following are not specifically supported by this library, but strings provided for nicer debug output.
203 { QBluetoothUuid::ServiceClassUuid::GenericAccess,
204 QBluetoothUuid::serviceClassToString(QBluetoothUuid::ServiceClassUuid::GenericAccess) },
205 { QBluetoothUuid::ServiceClassUuid::GenericAttribute,
206 QBluetoothUuid::serviceClassToString(QBluetoothUuid::ServiceClassUuid::GenericAttribute) },
207 { QBluetoothUuid(QStringLiteral("1d14d6ee-fd63-4fa1-bfa4-8f47b42119f0")), tr("OTA Firmware Update") },
208 };
209 return hash.value(uuid);
210}
211
212/*!
213 * Returns a human-readable name for the \a uuid characteristic, or a null QString if unknown.
214 *
215 * This is equivalent to QBluetoothUuid::characteristicToString() but for characteristics provided
216 * by Pokit devices.
217 */
219{
220 static const QHash<QBluetoothUuid, QString> hash{
224
228
232
235
242
244 QBluetoothUuid::characteristicToString(QBluetoothUuid::CharacteristicType::FirmwareRevisionString) },
246 QBluetoothUuid::characteristicToString(QBluetoothUuid::CharacteristicType::HardwareRevisionString) },
248 QBluetoothUuid::characteristicToString(QBluetoothUuid::CharacteristicType::ManufacturerNameString) },
250 QBluetoothUuid::characteristicToString(QBluetoothUuid::CharacteristicType::ModelNumberString) },
252 QBluetoothUuid::characteristicToString(QBluetoothUuid::CharacteristicType::SoftwareRevisionString) },
254 QBluetoothUuid::characteristicToString(QBluetoothUuid::CharacteristicType::SerialNumberString) },
255
256 // The next two are not specifically supported by this library, but strings provided for nicer debug output.
257 { QBluetoothUuid(QStringLiteral("f7bf3564-fb6d-4e53-88a4-5e37e0326063")), tr("OTA Control") },
258 { QBluetoothUuid(QStringLiteral("984227f3-34fc-4045-a5d0-2c581f81a153")), tr("OTA Data Transfer") },
259 };
260 return hash.value(uuid);
261}
262
263/*!
264 * \cond internal
265 * \class PokitDevicePrivate
266 *
267 * The PokitDevicePrivate class provides private implementation for PokitDevice.
268 */
269
270/*!
271 * Constructs a new PokitDevicePrivate object with public implementation \a q.
272 */
274{
275
276}
277
278/*!
279 * Sets \a newController to be used for accessing Pokit devices.
280 *
281 * If a controller has already been set (and is not the same pointer), then the previous controller
282 * will be disconnected, and replaced with \a newController.
283 *
284 * This function will not take ownership of the new controller. The caller is responsible for
285 * ensuring that \a newContorller remains valid for the lifetime of this instance, or until this
286 * function is used again to replace \a newController with another one (which may be a nullptr).
287 *
288 * \see controller
289 * \see PokitDevice::controller()
290 */
292{
293 if (newController == this->controller) {
294 qCDebug(lc).noquote() << tr("Controller already set to:") << newController;
295 return;
296 }
297
298 if (this->controller) {
299 qCDebug(lc).noquote() << tr("Disconnecting signals from previous controller:")
300 << controller;
301 disconnect(this->controller, nullptr, this, nullptr);
302 }
303
304 qCDebug(lc).noquote() << tr("Setting new controller:") << newController;
305 this->controller = newController;
306 if (!newController) {
307 return; // Don't bother continuing to connect if new controller is null.
308 }
309
310 qCDebug(lc).noquote() << tr(R"(Set new controller "%1" (%2) at (%3).)").arg(
313
316
319
322
325
326
328 #if (QT_VERSION < QT_VERSION_CHECK(6, 2, 0))
329 QOverload<QLowEnergyController::Error>::of(&QLowEnergyController::error),
330 #else
331 &QLowEnergyController::errorOccurred,
332 #endif
334
335
338
341}
342
343/*!
344 * Handle connected signals.
345 */
347{
348 if (controller == nullptr) {
349 qCCritical(lc).noquote() << tr("PokitDevicePrivate::connected slot invoked without a controller.");
350 return; // Just to avoid the nullptr dereference below.
351 }
352 qCDebug(lc).noquote() << tr(R"(Connected to "%1" (%2) at (%3).)").arg(
355}
356
357/*!
358 * Handle connectionUpdated signals.
359 */
361{
362 qCDebug(lc).noquote() << tr("Connection updated:") << newParameters.latency()
363 << newParameters.minimumInterval() << newParameters.maximumInterval()
364 << newParameters.supervisionTimeout();
365}
366
367/*!
368 * Handle disconnected signals.
369 */
371{
372 qCDebug(lc).noquote() << tr("Device disconnected.");
373}
374
375/*!
376 * Handle discoveryFinished signals.
377 */
379{
380 qCDebug(lc).noquote() << tr("Service discovery finished.");
381}
382
383/*!
384 * Handle error signals.
385 */
387{
388 qCDebug(lc).noquote() << tr("Controller error:") << newError;
389}
390
391/*!
392 * Handle serviceDiscovered signals.
393 */
395{
396 qCDebug(lc).noquote() << tr(R"(Service discovered: %1 "%2")")
397 .arg(newService.toString(), PokitDevice::serviceToString(newService));
398}
399
400/*!
401 * Handle stateChanged signals.
402 */
404{
405 qCDebug(lc).noquote() << tr("State changed to:") << state;
406}
407
408/// \endcond
Declares the CalibrationService class.
The CalibrationService class accesses the Calibrartion service of Pokit devices.
static const QBluetoothUuid serviceUuid
UUID of the Calibration service.
The DataLoggerService class accesses the Data Logger service of Pokit devices.
static const QBluetoothUuid serviceUuid
UUID of the "DataLogger" service.
The DeviceInfoService class accesses the Device Info service of Pokit devices.
static const QBluetoothUuid serviceUuid
UUID of the "Device Info" service.
The DsoService class accesses the DSO (Digital Storage Oscilloscope) service of Pokit devices.
Definition dsoservice.h:24
static const QBluetoothUuid serviceUuid
UUID of the "DSO" service.
Definition dsoservice.h:29
The MultimeterService class accesses the Multimeter service of Pokit devices.
static const QBluetoothUuid serviceUuid
UUID of the Multimeter service.
The PokitDevicePrivate class provides private implementation for PokitDevice.
PokitDevicePrivate(PokitDevice *const q)
Constructs a new PokitDevicePrivate object with public implementation q.
void connected() const
Handle connected signals.
void disconnected() const
Handle disconnected signals.
void errorOccurred(QLowEnergyController::Error newError) const
Handle error signals.
void stateChanged(QLowEnergyController::ControllerState state) const
Handle stateChanged signals.
void setController(QLowEnergyController *newController)
Sets newController to be used for accessing Pokit devices.
void connectionUpdated(const QLowEnergyConnectionParameters &newParameters) const
Handle connectionUpdated signals.
QLowEnergyController * controller
BLE controller for accessing the Pokit device.
void discoveryFinished() const
Handle discoveryFinished signals.
void serviceDiscovered(const QBluetoothUuid &newService) const
Handle serviceDiscovered signals.
The PokitDevice class simplifies Pokit device access.
Definition pokitdevice.h:31
static QString charcteristicToString(const QBluetoothUuid &uuid)
Returns a human-readable name for the uuid characteristic, or a null QString if unknown.
DeviceInfoService * deviceInformation()
Returns a pointer to DeviceInformationService instance that uses this device's controller for access.
QLowEnergyController * controller()
Returns a non-const pointer to the controller used to access the Pokit device.
virtual ~PokitDevice()
Destroys this PokitDevice object.
DsoService * dso()
Returns a pointer to DsoService instance that uses this device's controller for access.
PokitDevice(const QBluetoothDeviceInfo &deviceInfo, QObject *parent=nullptr)
Constructs a new Pokit device controller wrapper for deviceInfo, with parent.
PokitDevicePrivate * d_ptr
Internal d-pointer.
Definition pokitdevice.h:58
DataLoggerService * dataLogger()
Returns a pointer to a DataLoggerService instance that uses this device's controller for access.
MultimeterService * multimeter()
Returns a pointer to MultimeterService instance that uses this device's controller for access.
CalibrationService * calibration()
Returns a pointer to a CalibrationService instance that uses this device's controller for access.
static QString serviceToString(const QBluetoothUuid &uuid)
Returns a human-readable name for the uuid service, or a null QString if unknonw.
StatusService * status()
Returns a pointer to StatusService instance that uses this device's controller for access.
The StatusService class accesses the Pokit Status service of Pokit devices.
Declares the DataLoggerService class.
Declares the DeviceInfoService class.
Declares the DsoService class.
Declares the MultimeterService class.
Declares the PokitDevice class.
Declares the PokitDevicePrivate class.
QString toString() const const
QString characteristicToString(QBluetoothUuid::CharacteristicType uuid)
QString serviceClassToString(QBluetoothUuid::ServiceClassUuid uuid)
double maximumInterval() const const
double minimumInterval() const const
int supervisionTimeout() const const
void connectionUpdated(const QLowEnergyConnectionParameters &newParameters)
QLowEnergyController * createCentral(const QBluetoothDeviceInfo &remoteDevice, QObject *parent)
QLowEnergyController::Error error() const const
QBluetoothAddress remoteAddress() const const
QBluetoothUuid remoteDeviceUuid() const const
QString remoteName() const const
void serviceDiscovered(const QBluetoothUuid &newService)
void stateChanged(QLowEnergyController::ControllerState state)
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *method)
QString tr(const char *sourceText, const char *disambiguation, int n)
QString arg(qlonglong a, int fieldWidth, int base, QChar fillChar) const const
QString toString() const const
Declares the StatusService class.
static const QBluetoothUuid temperature
UUID of the Calibration service's Temperature characterstic.
static const QBluetoothUuid metadata
UUID of the DataLogger service's Metadata characterstic.
static const QBluetoothUuid settings
UUID of the DataLogger service's Settings characterstic.
static const QBluetoothUuid reading
UUID of the DataLogger service's Reading characterstic.
static const QBluetoothUuid manufacturerName
UUID of the Device Info service's Manufacturer Name String characterstic.
static const QBluetoothUuid hardwareRevision
UUID of the Device Info service's Hardware Revision String characterstic.
static const QBluetoothUuid softwareRevision
UUID of the Device Info service's Software Revision String characterstic.
static const QBluetoothUuid serialNumber
UUID of the Device Info service's Serial Number String characterstic.
static const QBluetoothUuid firmwareRevision
UUID of the Device Info service's Firmware Revision String characterstic.
static const QBluetoothUuid modelNumber
UUID of the Device Info service's Model Number String characterstic.
static const QBluetoothUuid metadata
UUID of the DSO service's Metadata characterstic.
Definition dsoservice.h:37
static const QBluetoothUuid reading
UUID of the DSO service's Reading characterstic.
Definition dsoservice.h:40
static const QBluetoothUuid settings
UUID of the DSO service's Settings characterstic.
Definition dsoservice.h:34
static const QBluetoothUuid reading
UUID of the Multimeter service's Reading characterstic.
static const QBluetoothUuid settings
UUID of the Multimeter service's Settings characterstic.
static const QBluetoothUuid name
UUID of the Pokit Status service's Device Name characterstic.
static const QBluetoothUuid torch
UUID of the Pokit Status service's (undocumented) Torch characterstic.
static const QBluetoothUuid deviceCharacteristics
UUID of the Pokit Status service's Device Characteristics characterstic.
static const QBluetoothUuid buttonPress
UUID of the Pokit Status service's (undocumented) Button Press characterstic.
static const QBluetoothUuid flashLed
UUID of the Pokit Status service's Flash LED characterstic.
static const QBluetoothUuid status
UUID of the Pokit Status service's Status characterstic.
static const QBluetoothUuid pokitPro
UUID of the Pokit Pro's Pokit Status service.
static const QBluetoothUuid pokitMeter
UUID of the Pokit Meter's Pokit Status service.