Dokit
Internal development documentation
Loading...
Searching...
No Matches
pokitdevice.cpp
Go to the documentation of this file.
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 PokitDevice and PokitDevicePrivate classes.
7 */
8
10
14#include <qtpokit/dsoservice.h>
18
19#include "pokitdevice_p.h"
20
21#include <QMutexLocker>
22
23/*!
24 * \class PokitDevice
25 *
26 * The PokitDevice class simplifies Pokit device access.
27 *
28 * It does this by wrapping QLowEnergyController to provide:
29 * * convenient Pokit service factory methods (dataLogger(), deviceInformation(), dso(),
30 * genericAccess(), multimeter() and status()); and
31 * * consistent debug logging of QLowEnergyController events.
32 *
33 * But this class is entirely optional, in that all features of all other QtPokit classes can be
34 * used wihtout this class. It's just a (meaningful) convenience.
35 */
36
37/*!
38 * Constructs a new Pokit device controller wrapper for \a deviceInfo, with \a parent.
39 *
40 * Though not strictly necessary, \a deviceInfo should normally come from a
41 * PokitDiscoveryAgent instance (or a QBluetoothDeviceDiscoveryAgent), otherwise connection
42 * is likely to fail with QLowEnergyController::UnknownRemoteDeviceError.
43 */
45 : QObject(parent), d_ptr(new PokitDevicePrivate(this))
46{
47 Q_D(PokitDevice);
48 d->setController(QLowEnergyController::createCentral(deviceInfo, this));
49}
50
51/*!
52 * Constructs a new Pokit device controller wrapper for \a controller, with \a parent.
53 */
55 : QObject(parent), d_ptr(new PokitDevicePrivate(this))
56{
57 Q_D(PokitDevice);
58 d->setController(controller);
59}
60
61/*!
62 * \cond internal
63 * Constructs a new Pokit device controller wrapper with \a parent, and private implementation \a d.
64 *
65 * Derived classes using this constructor should use PokitDevicePrivate::setController to assign
66 * the BLE controller as some point.
67 */
69 : QObject(parent), d_ptr(d)
70{
71
72}
73/// \endcond
74
75/*!
76 * Destroys this PokitDevice object.
77 */
79{
80 delete d_ptr;
81}
82
83/*!
84 * Returns a non-const pointer to the controller used to access the Pokit device.
85 */
87{
88 Q_D(PokitDevice);
89 return d->controller;
90}
91
92/*!
93 * Returns a const pointer to the controller used to access the Pokit device.
94 */
96{
97 Q_D(const PokitDevice);
98 return d->controller;
99}
100
101/// \cond
102#define QTPOKIT_INTERNAL_GET_SERVICE(typeName, varName) \
103 Q_D(PokitDevice); \
104 const QMutexLocker scopedLock(&d->varName##Mutex);\
105 if (d->varName == nullptr) { \
106 d->varName = new typeName(d->controller); \
107 } \
108 return d->varName \
109/// \endcond
110
111/*!
112 * Returns a pointer to a CalibrationService instance that uses this device's controller for access.
113 *
114 * This is a convenience function, that always returns the same pointer (for this PokitDevice
115 * instance), but the service itself is lazily created (in a threadsafe manner) on the first
116 * invocation of this function.
117 */
119{
120 QTPOKIT_INTERNAL_GET_SERVICE(CalibrationService, calibration);
121}
122
123/*!
124 * Returns a pointer to a DataLoggerService instance that uses this device's controller for access.
125 *
126 * This is a convenience function, that always returns the same pointer (for this PokitDevice
127 * instance), but the service itself is lazily created (in a threadsafe manner) on the first
128 * invocation of this function.
129 */
131{
132 QTPOKIT_INTERNAL_GET_SERVICE(DataLoggerService, dataLogger);
133}
134
135/*!
136 * Returns a pointer to DeviceInformationService instance that uses this device's controller for
137 * access.
138 *
139 * This is a convenience function, that always returns the same pointer (for this PokitDevice
140 * instance), but the service itself is lazily created (in a threadsafe manner) on the first
141 * invocation of this function.
142 */
144{
145 QTPOKIT_INTERNAL_GET_SERVICE(DeviceInfoService, deviceInfo);
146}
147
148/*!
149 * Returns a pointer to DsoService instance that uses this device's controller for access.
150 *
151 * This is a convenience function, that always returns the same pointer (for this PokitDevice
152 * instance), but the service itself is lazily created (in a threadsafe manner) on the first
153 * invocation of this function.
154 */
156{
157 QTPOKIT_INTERNAL_GET_SERVICE(DsoService, dso);
158}
159
160/*!
161 * Returns a pointer to GenericAccessService instance that uses this device's controller for access.
162 *
163 * This is a convenience function, that always returns the same pointer (for this PokitDevice
164 * instance), but the service itself is lazily created (in a threadsafe manner) on the first
165 * invocation of this function.
166 */
171
172/*!
173 * Returns a pointer to MultimeterService instance that uses this device's controller for access.
174 *
175 * This is a convenience function, that always returns the same pointer (for this PokitDevice
176 * instance), but the service itself is lazily created (in a threadsafe manner) on the first
177 * invocation of this function.
178 */
180{
181 QTPOKIT_INTERNAL_GET_SERVICE(MultimeterService, multimeter);
182}
183
184/*!
185 * Returns a pointer to StatusService instance that uses this device's controller for access.
186 *
187 * This is a convenience function, that always returns the same pointer (for this PokitDevice
188 * instance), but the service itself is lazily created (in a threadsafe manner) on the first
189 * invocation of this function.
190 */
192{
193 QTPOKIT_INTERNAL_GET_SERVICE(StatusService, status);
194}
195#undef QTPOKIT_INTERNAL_GET_SERVICE
196
197/*!
198 * Returns a human-readable name for the \a uuid service, or a null QString if unknonw.
199 *
200 * This is equivalent to QBluetoothUuid::serviceClassToString() but for services provided by Pokit
201 * devices.
202 */
204{
206 { CalibrationService::serviceUuid, tr("Calibration") },
207 { DataLoggerService::serviceUuid, tr("Data Logger") },
208 { DsoService::serviceUuid, tr("DSO") },
209 { MultimeterService::serviceUuid, tr("Multimeter") },
210 { StatusService::ServiceUuids::pokitMeter, tr("Status (Pokit Meter)") },
211 { StatusService::ServiceUuids::pokitPro, tr("Status (Pokit Pro)") },
213 QBluetoothUuid::serviceClassToString(QBluetoothUuid::ServiceClassUuid::DeviceInformation) },
215 QBluetoothUuid::serviceClassToString(QBluetoothUuid::ServiceClassUuid::GenericAccess) },
216 // The next two are not specifically supported by this library, but strings provided for nicer debug output.
217 { QBluetoothUuid::ServiceClassUuid::GenericAttribute,
218 QBluetoothUuid::serviceClassToString(QBluetoothUuid::ServiceClassUuid::GenericAttribute) },
219 { QBluetoothUuid(QStringLiteral("1d14d6ee-fd63-4fa1-bfa4-8f47b42119f0")), tr("OTA Firmware Update") },
220 };
221 return hash.value(uuid);
222}
223
224/*!
225 * Returns a human-readable name for the \a uuid characteristic, or a null QString if unknown.
226 *
227 * This is equivalent to QBluetoothUuid::characteristicToString() but for characteristics provided
228 * by Pokit devices.
229 */
231{
236
240
244
247
254
256 QBluetoothUuid::characteristicToString(QBluetoothUuid::CharacteristicType::FirmwareRevisionString) },
258 QBluetoothUuid::characteristicToString(QBluetoothUuid::CharacteristicType::HardwareRevisionString) },
260 QBluetoothUuid::characteristicToString(QBluetoothUuid::CharacteristicType::ManufacturerNameString) },
262 QBluetoothUuid::characteristicToString(QBluetoothUuid::CharacteristicType::ModelNumberString) },
264 QBluetoothUuid::characteristicToString(QBluetoothUuid::CharacteristicType::SoftwareRevisionString) },
266 QBluetoothUuid::characteristicToString(QBluetoothUuid::CharacteristicType::SerialNumberString) },
267
269 QBluetoothUuid::characteristicToString(QBluetoothUuid::CharacteristicType::Appearance) },
271 QBluetoothUuid::characteristicToString(QBluetoothUuid::CharacteristicType::DeviceName) },
272
273 // The next two are not specifically supported by this library, but strings provided for nicer debug output.
274 { QBluetoothUuid(QStringLiteral("f7bf3564-fb6d-4e53-88a4-5e37e0326063")), tr("OTA Control") },
275 { QBluetoothUuid(QStringLiteral("984227f3-34fc-4045-a5d0-2c581f81a153")), tr("OTA Data Transfer") },
276 };
277 return hash.value(uuid);
278}
279
280/*!
281 * \cond internal
282 * \class PokitDevicePrivate
283 *
284 * The PokitDevicePrivate class provides private implementation for PokitDevice.
285 */
286
287/*!
288 * Constructs a new PokitDevicePrivate object with public implementation \a q.
289 */
291{
292
293}
294
295/*!
296 * Sets \a newController to be used for accessing Pokit devices.
297 *
298 * If a controller has already been set (and is not the same pointer), then the previous controller
299 * will be disconnected, and replaced with \a newController.
300 *
301 * This function will not take ownership of the new controller. The caller is responsible for
302 * ensuring that \a newContorller remains valid for the lifetime of this instance, or until this
303 * function is used again to replace \a newController with another one (which may be a nullptr).
304 *
305 * \see controller
306 * \see PokitDevice::controller()
307 */
309{
310 if (newController == this->controller) {
311 qCDebug(lc).noquote() << tr("Controller already set to:") << newController;
312 return;
313 }
314
315 if (this->controller) {
316 qCDebug(lc).noquote() << tr("Disconnecting signals from previous controller:")
317 << controller;
318 disconnect(this->controller, nullptr, this, nullptr);
319 }
320
321 qCDebug(lc).noquote() << tr("Setting new controller:") << newController;
322 this->controller = newController;
323 if (!newController) {
324 return; // Don't bother continuing to connect if new controller is null.
325 }
326
327 qCDebug(lc).noquote() << tr(R"(Set new controller "%1" (%2) at (%3).)").arg(
330
333
336
339
342
343
345 #if (QT_VERSION < QT_VERSION_CHECK(6, 2, 0))
346 QOverload<QLowEnergyController::Error>::of(&QLowEnergyController::error),
347 #else
348 &QLowEnergyController::errorOccurred,
349 #endif
351
352
355
358}
359
360/*!
361 * Handle connected signals.
362 */
364{
365 if (controller == nullptr) {
366 qCCritical(lc).noquote() << tr("PokitDevicePrivate::connected slot invoked without a controller.");
367 return; // Just to avoid the nullptr dereference below.
368 }
369 qCDebug(lc).noquote() << tr(R"(Connected to "%1" (%2) at (%3).)").arg(
372}
373
374/*!
375 * Handle connectionUpdated signals.
376 */
378{
379 qCDebug(lc).noquote() << tr("Connection updated:") << newParameters.latency()
380 << newParameters.minimumInterval() << newParameters.maximumInterval()
381 << newParameters.supervisionTimeout();
382}
383
384/*!
385 * Handle disconnected signals.
386 */
388{
389 qCDebug(lc).noquote() << tr("Device disconnected.");
390}
391
392/*!
393 * Handle discoveryFinished signals.
394 */
396{
397 qCDebug(lc).noquote() << tr("Service discovery finished.");
398}
399
400/*!
401 * Handle error signals.
402 */
404{
405 qCDebug(lc).noquote() << tr("Controller error:") << newError;
406}
407
408/*!
409 * Handle serviceDiscovered signals.
410 */
412{
413 qCDebug(lc).noquote() << tr(R"(Service discovered: %1 "%2")")
414 .arg(newService.toString(), PokitDevice::serviceToString(newService));
415}
416
417/*!
418 * Handle stateChanged signals.
419 */
421{
422 qCDebug(lc).noquote() << tr("State changed to:") << state;
423}
424
425/// \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 GenericAccessService class accesses the Generic Access service of Pokit devices.
static const QBluetoothUuid serviceUuid
UUID of the Generic Access service.
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:32
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.
GenericAccessService * genericAccess()
Returns a pointer to GenericAccessService 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:60
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 GenericAccessService 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 deviceName
UUID of the Generic Access service's Device Name characterstic.
static const QBluetoothUuid appearance
UUID of the Generic Access service's Appearance characterstic.
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.