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 MultimeterService and MultimeterServicePrivate classes.
7 : */
8 :
9 : #include <qtpokit/multimeterservice.h>
10 : #include "multimeterservice_p.h"
11 :
12 : #include <QDataStream>
13 : #include <QIODevice>
14 : #include <QtEndian>
15 :
16 : /*!
17 : * \class MultimeterService
18 : *
19 : * The MultimeterService class accesses the `Multimeter` service of Pokit devices.
20 : */
21 :
22 : /// UUID of the "Multimeter" service.
23 : const QBluetoothUuid MultimeterService::
24 : serviceUuid(QLatin1String("e7481d2f-5781-442e-bb9a-fd4e3441dadc"));
25 :
26 : /// \struct MultimeterService::CharacteristicUuids
27 : /// \brief Characteristics available via the `Multimeter` service.
28 :
29 : /// UUID of the `Multimeter` service's `Settings` characterstic.
30 : const QBluetoothUuid MultimeterService::CharacteristicUuids::
31 : settings(QLatin1String("53dc9a7a-bc19-4280-b76b-002d0e23b078"));
32 :
33 : /// UUID of the `Multimeter` service's `Reading` characterstic.
34 : const QBluetoothUuid MultimeterService::CharacteristicUuids::
35 : reading(QLatin1String("047d3559-8bee-423a-b229-4417fa603b90"));
36 :
37 : /// \enum MultimeterService::Mode
38 : /// \brief Values supported by the `Mode` attribute of the `Settings` and `Reading` characteristics.
39 :
40 : /// Returns \a mode as a user-friendly string.
41 1638 : QString MultimeterService::toString(const Mode &mode)
42 : {
43 1638 : switch (mode) {
44 324 : case Mode::Idle: return tr("Idle");
45 144 : case Mode::DcVoltage: return tr("DC voltage");
46 144 : case Mode::AcVoltage: return tr("AC voltage");
47 144 : case Mode::DcCurrent: return tr("DC current");
48 144 : case Mode::AcCurrent: return tr("AC current");
49 144 : case Mode::Resistance: return tr("Resistance");
50 144 : case Mode::Diode: return tr("Diode");
51 270 : case Mode::Continuity: return tr("Continuity");
52 144 : case Mode::Temperature: return tr("Temperature");
53 : default: return QString();
54 : }
55 : }
56 :
57 : /// \enum MultimeterService::VoltageRange
58 : /// \brief Values supported by the `Range` attribute of the `Settings` and `Reading` characteristics,
59 : /// when `Mode` is AC or DC voltage.
60 :
61 : /// Returns \a range as a user-friendly string.
62 450 : QString MultimeterService::toString(const VoltageRange &range)
63 : {
64 450 : switch (range) {
65 54 : case VoltageRange::_0_to_300mV: return tr("0 to 300mV");
66 234 : case VoltageRange::_300mV_to_2V: return tr("300mV to 2V");
67 18 : case VoltageRange::_2V_to_6V: return tr("2V to 6V");
68 18 : case VoltageRange::_6V_to_12V: return tr("6V to 12V");
69 18 : case VoltageRange::_12V_to_30V: return tr("12V to 30V");
70 54 : case VoltageRange::_30V_to_60V: return tr("30V to 60V");
71 18 : case VoltageRange::AutoRange: return tr("Auto-range");
72 : default: return QString();
73 : }
74 : }
75 :
76 : /*!
77 : * Returns the minimum value for \a range in (integer) millivolts, or the string "Auto".
78 : * If \a range is not known valid value, then an null QVariant is returned.
79 : *
80 : * Note, this is an *absolute* minimum. That is, the true range for DC measurements is from
81 : * `-maxValue(range)` to `+maxValue(range)`. In this sense, `minValue(range)` indicates the
82 : * magnitude (ignore signs) that can be measured accurately for the given \a range. As AC voltage
83 : * can never be negative, this is relevant for DC voltage only.
84 : */
85 378 : QVariant MultimeterService::minValue(const VoltageRange &range)
86 : {
87 378 : switch (range) {
88 18 : case VoltageRange::_0_to_300mV: return 0;
89 234 : case VoltageRange::_300mV_to_2V: return 300;
90 18 : case VoltageRange::_2V_to_6V: return 2000;
91 18 : case VoltageRange::_6V_to_12V: return 6000;
92 18 : case VoltageRange::_12V_to_30V: return 12000;
93 18 : case VoltageRange::_30V_to_60V: return 30000;
94 22 : case VoltageRange::AutoRange: return tr("Auto");
95 : default: return QVariant();
96 : }
97 : }
98 :
99 : /*!
100 : * Returns the maximum value for \a range in (integer) millivolts, or the string "Auto".
101 : * If \a range is not known valid value, then an null QVariant is returned.
102 : */
103 4518 : QVariant MultimeterService::maxValue(const VoltageRange &range)
104 : {
105 4518 : switch (range) {
106 1134 : case VoltageRange::_0_to_300mV: return 300;
107 1188 : case VoltageRange::_300mV_to_2V: return 2000;
108 792 : case VoltageRange::_2V_to_6V: return 6000;
109 612 : case VoltageRange::_6V_to_12V: return 12000;
110 450 : case VoltageRange::_12V_to_30V: return 30000;
111 288 : case VoltageRange::_30V_to_60V: return 60000;
112 22 : case VoltageRange::AutoRange: return tr("Auto");
113 : default: return QVariant();
114 : }
115 : }
116 :
117 : /// \enum MultimeterService::CurrentRange
118 : /// \brief Values supported by the `Range` attribute of the `Settings` and `Reading` characteristics,
119 : /// when `Mode` is AC or DC current.
120 :
121 : /// Returns \a range as a user-friendly string.
122 432 : QString MultimeterService::toString(const CurrentRange &range)
123 : {
124 432 : switch (range) {
125 54 : case CurrentRange::_0_to_10mA: return tr("0 to 10mA");
126 18 : case CurrentRange::_10mA_to_30mA: return tr("10mA to 30mA");
127 126 : case CurrentRange::_30mA_to_150mA: return tr("30mA to 150mA");
128 18 : case CurrentRange::_150mA_to_300mA: return tr("150mA to 300mA");
129 162 : case CurrentRange::_300mA_to_3A: return tr("300mA to 3A");
130 18 : case CurrentRange::AutoRange: return tr("Auto-range");
131 : default: return QString();
132 : }
133 : }
134 :
135 : /*!
136 : * Returns the minimum value for \a range in (integer) milliamps, or the string "Auto".
137 : * If \a range is not known valid value, then an null QVariant is returned.
138 : *
139 : * Note, this is an *absolute* minimum. That is, the true range for DC measurements is from
140 : * `-maxValue(range)` to `+maxValue(range)`. In this sense, `minValue(range)` indicates the
141 : * magnitude (ignore signs) that can be measured accurately for the given \a range. As AC current
142 : * can never be negative, this is relevant for DC current only.
143 : */
144 360 : QVariant MultimeterService::minValue(const CurrentRange &range)
145 : {
146 360 : switch (range) {
147 18 : case CurrentRange::_0_to_10mA: return 0;
148 18 : case CurrentRange::_10mA_to_30mA: return 10;
149 126 : case CurrentRange::_30mA_to_150mA: return 30;
150 18 : case CurrentRange::_150mA_to_300mA: return 150;
151 126 : case CurrentRange::_300mA_to_3A: return 300;
152 22 : case CurrentRange::AutoRange: return tr("Auto");
153 : default: return QVariant();
154 : }
155 : }
156 :
157 : /*!
158 : * Returns the maximum value for \a range in (integer) milliamps, or the string "Auto".
159 : * If \a range is not known valid value, then an null QVariant is returned.
160 : */
161 3474 : QVariant MultimeterService::maxValue(const CurrentRange &range)
162 : {
163 3474 : switch (range) {
164 972 : case CurrentRange::_0_to_10mA: return 10;
165 810 : case CurrentRange::_10mA_to_30mA: return 30;
166 756 : case CurrentRange::_30mA_to_150mA: return 150;
167 468 : case CurrentRange::_150mA_to_300mA: return 300;
168 414 : case CurrentRange::_300mA_to_3A: return 3000;
169 22 : case CurrentRange::AutoRange: return tr("Auto");
170 : default: return QVariant();
171 : }
172 : }
173 :
174 : /// \enum MultimeterService::ResistanceRange
175 : /// \brief Values supported by the `Range` attribute of the `Settings` and `Reading` characteristics,
176 : /// when `Mode` is resistance.
177 :
178 : /// Returns \a range as a user-friendly string.
179 306 : QString MultimeterService::toString(const ResistanceRange &range)
180 : {
181 306 : switch (range) {
182 18 : case ResistanceRange::_0_to_160: return tr("0 to 160 ohms");
183 18 : case ResistanceRange::_160_to_330: return tr("160 to 330 ohms");
184 18 : case ResistanceRange::_330_to_890: return tr("330 to 890 ohms");
185 18 : case ResistanceRange::_890_to_1K5: return tr("890 to 1.5K ohms");
186 126 : case ResistanceRange::_1K5_to_10K: return tr("1.5K to 10K ohms");
187 18 : case ResistanceRange::_10K_to_100K: return tr("10K to 100K ohms");
188 18 : case ResistanceRange::_100K_to_470K: return tr("100K to 470K ohms");
189 18 : case ResistanceRange::_470K_to_1M: return tr("470K to 1M ohms");
190 18 : case ResistanceRange::AutoRange: return tr("Auto-range");
191 : default: return QString();
192 : }
193 : }
194 :
195 : /*!
196 : * Returns the minimum value for \a range in (integer) ohms, or the string "Auto".
197 : * If \a range is not known valid value, then an null QVariant is returned.
198 : */
199 306 : QVariant MultimeterService::minValue(const ResistanceRange &range)
200 : {
201 306 : switch (range) {
202 18 : case ResistanceRange::_0_to_160: return 0;
203 18 : case ResistanceRange::_160_to_330: return 160;
204 18 : case ResistanceRange::_330_to_890: return 330;
205 18 : case ResistanceRange::_890_to_1K5: return 890;
206 126 : case ResistanceRange::_1K5_to_10K: return 1500;
207 18 : case ResistanceRange::_10K_to_100K: return 10000;
208 18 : case ResistanceRange::_100K_to_470K: return 100000;
209 18 : case ResistanceRange::_470K_to_1M: return 470000;
210 22 : case ResistanceRange::AutoRange: return tr("Auto");
211 : default: return QVariant();
212 : }
213 : }
214 :
215 : /*!
216 : * Returns the maximum value for \a range in (integer) ohms, or the string "Auto".
217 : * If \a range is not known valid value, then an null QVariant is returned.
218 : */
219 4770 : QVariant MultimeterService::maxValue(const ResistanceRange &range)
220 : {
221 4770 : switch (range) {
222 954 : case ResistanceRange::_0_to_160: return 160;
223 846 : case ResistanceRange::_160_to_330: return 330;
224 738 : case ResistanceRange::_330_to_890: return 890;
225 630 : case ResistanceRange::_890_to_1K5: return 1500;
226 630 : case ResistanceRange::_1K5_to_10K: return 10000;
227 414 : case ResistanceRange::_10K_to_100K: return 100000;
228 306 : case ResistanceRange::_100K_to_470K: return 470000;
229 198 : case ResistanceRange::_470K_to_1M: return 1000000;
230 22 : case ResistanceRange::AutoRange: return tr("Auto");
231 : default: return QVariant();
232 : }
233 : }
234 :
235 : /// \union MultimeterService::Range
236 : /// \brief Values supported by the `Range` attribute of the `Settings` characteristic.
237 :
238 : static_assert(std::is_same<std::underlying_type_t<MultimeterService::VoltageRange>,
239 : std::underlying_type_t<MultimeterService::CurrentRange>>::value,
240 : "MultimeterService::Range members must all have the same underlying type.");
241 :
242 : /// Constructs a new MultimeterService::Range instance with 0. This should be considered
243 2034 : MultimeterService::Range::Range() : voltageRange(static_cast<MultimeterService::VoltageRange>(0))
244 : {
245 :
246 2034 : }
247 :
248 : /// Constructs a new MultimeterService::Range instance with \a range.
249 3012 : MultimeterService::Range::Range(const MultimeterService::VoltageRange range) : voltageRange(range)
250 : {
251 :
252 3006 : }
253 :
254 : /// Constructs a new MultimeterService::Range instance with \a range.
255 882 : MultimeterService::Range::Range(const MultimeterService::CurrentRange range) : currentRange(range)
256 : {
257 :
258 882 : }
259 :
260 : /// Constructs a new MultimeterService::Range instance with \a range.
261 504 : MultimeterService::Range::Range(const MultimeterService::ResistanceRange range) : resistanceRange(range)
262 : {
263 :
264 504 : }
265 :
266 : /// Returns \a range as a user-friendly string, or a null QString if \a mode has no ranges.
267 162 : QString MultimeterService::toString(const Range &range, const Mode &mode)
268 : {
269 162 : switch (mode) {
270 72 : case Mode::DcVoltage:
271 : case Mode::AcVoltage:
272 72 : return toString(range.voltageRange);
273 72 : case Mode::DcCurrent:
274 : case Mode::AcCurrent:
275 72 : return toString(range.currentRange);
276 : default:
277 : return QString();
278 : }
279 : }
280 :
281 : /// Returns \c true if \a lhs is numerically equal to \a rhs, \c false otherwise.
282 2304 : bool operator==(const MultimeterService::Range &lhs, const MultimeterService::Range &rhs)
283 : {
284 2304 : return static_cast<std::underlying_type_t<MultimeterService::VoltageRange>>(lhs.voltageRange)
285 2304 : == static_cast<std::underlying_type_t<MultimeterService::VoltageRange>>(rhs.voltageRange);
286 : }
287 :
288 : /// Returns \c true if \a lhs is numerically not-equal to \a rhs, \c false otherwise.
289 18 : bool operator!=(const MultimeterService::Range &lhs, const MultimeterService::Range &rhs)
290 : {
291 18 : return static_cast<std::underlying_type_t<MultimeterService::VoltageRange>>(lhs.voltageRange)
292 18 : != static_cast<std::underlying_type_t<MultimeterService::VoltageRange>>(rhs.voltageRange);
293 : }
294 :
295 : /// Returns \c true if \a lhs is numerically less than \a rhs, \c false otherwise.
296 18 : bool operator< (const MultimeterService::Range &lhs, const MultimeterService::Range &rhs)
297 : {
298 18 : return static_cast<std::underlying_type_t<MultimeterService::VoltageRange>>(lhs.voltageRange)
299 18 : < static_cast<std::underlying_type_t<MultimeterService::VoltageRange>>(rhs.voltageRange);
300 : }
301 :
302 : /// Returns \c true if \a lhs is numerically greater than \a rhs, \c false otherwise.
303 18 : bool operator> (const MultimeterService::Range &lhs, const MultimeterService::Range &rhs)
304 : {
305 18 : return static_cast<std::underlying_type_t<MultimeterService::VoltageRange>>(lhs.voltageRange)
306 18 : > static_cast<std::underlying_type_t<MultimeterService::VoltageRange>>(rhs.voltageRange);
307 : }
308 :
309 : /// Returns \c true if \a lhs is numerically less than or equal to \a rhs, \c false otherwise.
310 36 : bool operator<=(const MultimeterService::Range &lhs, const MultimeterService::Range &rhs)
311 : {
312 36 : return static_cast<std::underlying_type_t<MultimeterService::VoltageRange>>(lhs.voltageRange)
313 36 : <= static_cast<std::underlying_type_t<MultimeterService::VoltageRange>>(rhs.voltageRange);
314 : }
315 :
316 : /// Returns \c true if \a lhs is numerically greater than or equal to \a rhs, \c false otherwise.
317 36 : bool operator>=(const MultimeterService::Range &lhs, const MultimeterService::Range &rhs)
318 : {
319 36 : return static_cast<std::underlying_type_t<MultimeterService::VoltageRange>>(lhs.voltageRange)
320 36 : >= static_cast<std::underlying_type_t<MultimeterService::VoltageRange>>(rhs.voltageRange);
321 : }
322 :
323 : /// \struct MultimeterService::Settings
324 : /// \brief Attributes included in the `Settings` characterstic.
325 :
326 : /// \enum MultimeterService::MeterStatus
327 : /// \brief Values supported by the `Status` attribute of the `Settings` characteristic.
328 :
329 : /// \struct MultimeterService::Reading
330 : /// \brief Attributes included in the `Reading` characterstic.
331 :
332 : /*!
333 : * Constructs a new Pokit service with \a parent.
334 : */
335 198 : MultimeterService::MultimeterService(QLowEnergyController * const controller, QObject * parent)
336 198 : : AbstractPokitService(new MultimeterServicePrivate(controller, this), parent)
337 : {
338 :
339 198 : }
340 :
341 : /*!
342 : * \cond internal
343 : * Constructs a new Pokit service with \a parent, and private implementation \a d.
344 : */
345 0 : MultimeterService::MultimeterService(
346 0 : MultimeterServicePrivate * const d, QObject * const parent)
347 0 : : AbstractPokitService(d, parent)
348 : {
349 :
350 0 : }
351 : /// \endcond
352 :
353 : /*!
354 : * Destroys this MultimeterService object.
355 : */
356 180 : MultimeterService::~MultimeterService()
357 : {
358 :
359 180 : }
360 :
361 18 : bool MultimeterService::readCharacteristics()
362 : {
363 18 : return readReadingCharacteristic();
364 : }
365 :
366 : /*!
367 : * Read the `Multimeter` service's `Reading` characteristic.
368 : *
369 : * Returns `true` is the read request is succesfully queued, `false` otherwise (ie if the
370 : * underlying controller it not yet connected to the Pokit device, or the device's services have
371 : * not yet been discovered).
372 : *
373 : * Emits readingRead() if/when the characteristic has been read successfully.
374 : */
375 30 : bool MultimeterService::readReadingCharacteristic()
376 : {
377 : Q_D(MultimeterService);
378 36 : return d->readCharacteristic(CharacteristicUuids::reading);
379 : }
380 :
381 : /*!
382 : * Configures the Pokit device's multimeter mode.
383 : *
384 : * Returns `true` if the write request was successfully queued, `false` otherwise.
385 : *
386 : * Emits settingsWritten() if/when the \a settings have been writtem successfully.
387 : */
388 18 : bool MultimeterService::setSettings(const Settings &settings)
389 : {
390 : Q_D(const MultimeterService);
391 : const QLowEnergyCharacteristic characteristic =
392 18 : d->getCharacteristic(CharacteristicUuids::settings);
393 18 : if (!characteristic.isValid()) {
394 : return false;
395 : }
396 :
397 0 : const QByteArray value = MultimeterServicePrivate::encodeSettings(settings);
398 0 : if (value.isNull()) {
399 : return false;
400 : }
401 :
402 0 : d->service->writeCharacteristic(characteristic, value);
403 0 : return (d->service->error() != QLowEnergyService::ServiceError::CharacteristicWriteError);
404 18 : }
405 :
406 : /*!
407 : * Returns the most recent value of the `Multimeter` service's `Reading` characteristic.
408 : *
409 : * The returned value, if any, is from the underlying Bluetooth stack's cache. If no such value is
410 : * currently available (ie the serviceDetailsDiscovered signal has not been emitted yet), then the
411 : * returned MultimeterService::Reading::value member will be a quiet NaN, which can be checked like:
412 : *
413 : * ```
414 : * const MultimeterService::Reading reading = multimeterService->reading();
415 : * if (qIsNaN(reading.value)) {
416 : * // Handle failure.
417 : * }
418 : * ```
419 : */
420 18 : MultimeterService::Reading MultimeterService::reading() const
421 : {
422 : Q_D(const MultimeterService);
423 : const QLowEnergyCharacteristic characteristic =
424 18 : d->getCharacteristic(CharacteristicUuids::reading);
425 18 : return (characteristic.isValid()) ? MultimeterServicePrivate::parseReading(characteristic.value())
426 : : Reading{ MeterStatus::Error, std::numeric_limits<float>::quiet_NaN(),
427 36 : Mode::Idle, VoltageRange::AutoRange };
428 18 : }
429 :
430 : /*!
431 : * Enables client-side notifications of meter readings.
432 : *
433 : * This is an alternative to manually requesting individual reads via readReadingCharacteristic().
434 : *
435 : * Returns `true` is the request was successfully submited to the device queue, `false` otherwise.
436 : *
437 : * Successfully read values (if any) will be emitted via the readingRead() signal.
438 : */
439 18 : bool MultimeterService::enableReadingNotifications()
440 : {
441 : Q_D(MultimeterService);
442 18 : return d->enableCharacteristicNotificatons(CharacteristicUuids::reading);
443 : }
444 :
445 : /*!
446 : * Disables client-side notifications of meter readings.
447 : *
448 : * Instantaneous reads can still be fetched by readReadingCharacteristic().
449 : *
450 : * Returns `true` is the request was successfully submited to the device queue, `false` otherwise.
451 : */
452 18 : bool MultimeterService::disableReadingNotifications()
453 : {
454 : Q_D(MultimeterService);
455 18 : return d->disableCharacteristicNotificatons(CharacteristicUuids::reading);
456 : }
457 :
458 : /*!
459 : * \fn MultimeterService::readingRead
460 : *
461 : * This signal is emitted when the `Reading` characteristic has been read successfully.
462 : *
463 : * \see readReadingCharacteristic
464 : */
465 :
466 : /*!
467 : * \fn MultimeterService::settingsWritten
468 : *
469 : * This signal is emitted when the `Settings` characteristic has been written successfully.
470 : *
471 : * \see setSettings
472 : */
473 :
474 : /*!
475 : * \cond internal
476 : * \class MultimeterServicePrivate
477 : *
478 : * The MultimeterServicePrivate class provides private implementation for MultimeterService.
479 : */
480 :
481 : /*!
482 : * \internal
483 : * Constructs a new MultimeterServicePrivate object with public implementation \a q.
484 : */
485 132 : MultimeterServicePrivate::MultimeterServicePrivate(
486 198 : QLowEnergyController * controller, MultimeterService * const q)
487 198 : : AbstractPokitServicePrivate(MultimeterService::serviceUuid, controller, q)
488 : {
489 :
490 132 : }
491 :
492 : /*!
493 : * Returns \a settings in the format Pokit devices expect.
494 : */
495 72 : QByteArray MultimeterServicePrivate::encodeSettings(const MultimeterService::Settings &settings)
496 : {
497 : static_assert(sizeof(settings.mode) == 1, "Expected to be 1 byte.");
498 : static_assert(sizeof(settings.range) == 1, "Expected to be 1 byte.");
499 : static_assert(sizeof(settings.updateInterval) == 4, "Expected to be 4 bytes.");
500 :
501 16 : QByteArray value;
502 72 : QDataStream stream(&value, QIODevice::WriteOnly);
503 72 : stream.setByteOrder(QDataStream::LittleEndian);
504 72 : stream.setFloatingPointPrecision(QDataStream::SinglePrecision); // 32-bit floats, not 64-bit.
505 72 : stream << (quint8)settings.mode << (quint8)settings.range.voltageRange << settings.updateInterval;
506 :
507 : Q_ASSERT(value.size() == 6);
508 72 : return value;
509 72 : }
510 :
511 : /*!
512 : * Parses the `Reading` \a value into a MultimeterService::Reading struct.
513 : */
514 90 : MultimeterService::Reading MultimeterServicePrivate::parseReading(const QByteArray &value)
515 : {
516 90 : MultimeterService::Reading reading{
517 : MultimeterService::MeterStatus::Error,
518 : std::numeric_limits<float>::quiet_NaN(),
519 : MultimeterService::Mode::Idle,
520 : MultimeterService::VoltageRange::AutoRange
521 60 : };
522 :
523 110 : if (!checkSize(QLatin1String("Reading"), value, 7, 7)) {
524 36 : return reading;
525 : }
526 :
527 54 : reading.status = MultimeterService::MeterStatus(value.at(0));
528 66 : reading.value = qFromLittleEndian<float>(value.mid(1,4));
529 54 : reading.mode = static_cast<MultimeterService::Mode>(value.at(5));
530 54 : reading.range.voltageRange = static_cast<MultimeterService::VoltageRange>(value.at(6));
531 54 : return reading;
532 : }
533 :
534 : /*!
535 : * Implements AbstractPokitServicePrivate::characteristicRead to parse \a value, then emit a
536 : * specialised signal, for each supported \a characteristic.
537 : */
538 18 : void MultimeterServicePrivate::characteristicRead(const QLowEnergyCharacteristic &characteristic,
539 : const QByteArray &value)
540 : {
541 18 : AbstractPokitServicePrivate::characteristicRead(characteristic, value);
542 :
543 : Q_Q(MultimeterService);
544 18 : if (characteristic.uuid() == MultimeterService::CharacteristicUuids::reading) {
545 0 : emit q->readingRead(parseReading(value));
546 0 : return;
547 : }
548 :
549 18 : if (characteristic.uuid() == MultimeterService::CharacteristicUuids::settings) {
550 0 : qCWarning(lc).noquote() << tr("Settings characteristic is write-only, but somehow read")
551 0 : << serviceUuid << characteristic.name() << characteristic.uuid();
552 0 : return;
553 : }
554 :
555 54 : qCWarning(lc).noquote() << tr("Unknown characteristic read for Multimeter service")
556 24 : << serviceUuid << characteristic.name() << characteristic.uuid();
557 : }
558 :
559 : /*!
560 : * Implements AbstractPokitServicePrivate::characteristicWritten to parse \a newValue, then emit a
561 : * specialised signal, for each supported \a characteristic.
562 : */
563 18 : void MultimeterServicePrivate::characteristicWritten(const QLowEnergyCharacteristic &characteristic,
564 : const QByteArray &newValue)
565 : {
566 18 : AbstractPokitServicePrivate::characteristicWritten(characteristic, newValue);
567 :
568 : Q_Q(MultimeterService);
569 18 : if (characteristic.uuid() == MultimeterService::CharacteristicUuids::settings) {
570 0 : emit q->settingsWritten();
571 0 : return;
572 : }
573 :
574 18 : if (characteristic.uuid() == MultimeterService::CharacteristicUuids::reading) {
575 0 : qCWarning(lc).noquote() << tr("Reading characteristic is read/notify, but somehow written")
576 0 : << serviceUuid << characteristic.name() << characteristic.uuid();
577 0 : return;
578 : }
579 :
580 54 : qCWarning(lc).noquote() << tr("Unknown characteristic written for Multimeter service")
581 24 : << serviceUuid << characteristic.name() << characteristic.uuid();
582 : }
583 :
584 : /*!
585 : * Implements AbstractPokitServicePrivate::characteristicChanged to parse \a newValue, then emit a
586 : * specialised signal, for each supported \a characteristic.
587 : */
588 18 : void MultimeterServicePrivate::characteristicChanged(const QLowEnergyCharacteristic &characteristic,
589 : const QByteArray &newValue)
590 : {
591 18 : AbstractPokitServicePrivate::characteristicChanged(characteristic, newValue);
592 :
593 : Q_Q(MultimeterService);
594 18 : if (characteristic.uuid() == MultimeterService::CharacteristicUuids::settings) {
595 0 : qCWarning(lc).noquote() << tr("Settings characteristic is write-only, but somehow updated")
596 0 : << serviceUuid << characteristic.name() << characteristic.uuid();
597 0 : return;
598 : }
599 :
600 18 : if (characteristic.uuid() == MultimeterService::CharacteristicUuids::reading) {
601 0 : emit q->readingRead(parseReading(newValue));
602 0 : return;
603 : }
604 :
605 54 : qCWarning(lc).noquote() << tr("Unknown characteristic notified for Multimeter service")
606 24 : << serviceUuid << characteristic.name() << characteristic.uuid();
607 : }
608 :
609 : /// \endcond
|