Line data Source code
1 : // SPDX-FileCopyrightText: 2022 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 `Pokit Status` 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 1547 : QString MultimeterService::toString(const Mode &mode)
42 : {
43 1547 : switch (mode) {
44 108 : case Mode::Idle: return tr("Idle");
45 48 : case Mode::DcVoltage: return tr("DC voltage");
46 48 : case Mode::AcVoltage: return tr("AC voltage");
47 48 : case Mode::DcCurrent: return tr("DC current");
48 48 : case Mode::AcCurrent: return tr("AC current");
49 48 : case Mode::Resistance: return tr("Resistance");
50 48 : case Mode::Diode: return tr("Diode");
51 90 : case Mode::Continuity: return tr("Continuity");
52 48 : 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 425 : QString MultimeterService::toString(const VoltageRange &range)
63 : {
64 425 : switch (range) {
65 18 : case VoltageRange::_0_to_300mV: return tr("0 to 300mV");
66 78 : case VoltageRange::_300mV_to_2V: return tr("300mV to 2V");
67 6 : case VoltageRange::_2V_to_6V: return tr("2V to 6V");
68 6 : case VoltageRange::_6V_to_12V: return tr("6V to 12V");
69 6 : case VoltageRange::_12V_to_30V: return tr("12V to 30V");
70 18 : case VoltageRange::_30V_to_60V: return tr("30V to 60V");
71 6 : 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 357 : QVariant MultimeterService::minValue(const VoltageRange &range)
86 : {
87 357 : switch (range) {
88 17 : case VoltageRange::_0_to_300mV: return 0;
89 221 : case VoltageRange::_300mV_to_2V: return 300;
90 17 : case VoltageRange::_2V_to_6V: return 2000;
91 17 : case VoltageRange::_6V_to_12V: return 6000;
92 17 : case VoltageRange::_12V_to_30V: return 12000;
93 17 : case VoltageRange::_30V_to_60V: return 30000;
94 20 : 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 4267 : QVariant MultimeterService::maxValue(const VoltageRange &range)
104 : {
105 4267 : switch (range) {
106 1071 : case VoltageRange::_0_to_300mV: return 300;
107 1122 : case VoltageRange::_300mV_to_2V: return 2000;
108 748 : case VoltageRange::_2V_to_6V: return 6000;
109 578 : case VoltageRange::_6V_to_12V: return 12000;
110 425 : case VoltageRange::_12V_to_30V: return 30000;
111 272 : case VoltageRange::_30V_to_60V: return 60000;
112 20 : 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 408 : QString MultimeterService::toString(const CurrentRange &range)
123 : {
124 408 : switch (range) {
125 18 : case CurrentRange::_0_to_10mA: return tr("0 to 10mA");
126 6 : case CurrentRange::_10mA_to_30mA: return tr("10mA to 30mA");
127 42 : case CurrentRange::_30mA_to_150mA: return tr("30mA to 150mA");
128 6 : case CurrentRange::_150mA_to_300mA: return tr("150mA to 300mA");
129 54 : case CurrentRange::_300mA_to_3A: return tr("300mA to 3A");
130 6 : 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 340 : QVariant MultimeterService::minValue(const CurrentRange &range)
145 : {
146 340 : switch (range) {
147 17 : case CurrentRange::_0_to_10mA: return 0;
148 17 : case CurrentRange::_10mA_to_30mA: return 10;
149 119 : case CurrentRange::_30mA_to_150mA: return 30;
150 17 : case CurrentRange::_150mA_to_300mA: return 150;
151 119 : case CurrentRange::_300mA_to_3A: return 300;
152 20 : 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 3281 : QVariant MultimeterService::maxValue(const CurrentRange &range)
162 : {
163 3281 : switch (range) {
164 918 : case CurrentRange::_0_to_10mA: return 10;
165 765 : case CurrentRange::_10mA_to_30mA: return 30;
166 714 : case CurrentRange::_30mA_to_150mA: return 150;
167 442 : case CurrentRange::_150mA_to_300mA: return 300;
168 391 : case CurrentRange::_300mA_to_3A: return 3000;
169 20 : 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 289 : QString MultimeterService::toString(const ResistanceRange &range)
180 : {
181 289 : switch (range) {
182 6 : case ResistanceRange::_0_to_160: return tr("0 to 160 ohms");
183 6 : case ResistanceRange::_160_to_330: return tr("160 to 330 ohms");
184 6 : case ResistanceRange::_330_to_890: return tr("330 to 890 ohms");
185 6 : case ResistanceRange::_890_to_1K5: return tr("890 to 1.5K ohms");
186 42 : case ResistanceRange::_1K5_to_10K: return tr("1.5K to 10K ohms");
187 6 : case ResistanceRange::_10K_to_100K: return tr("10K to 100K ohms");
188 6 : case ResistanceRange::_100K_to_470K: return tr("100K to 470K ohms");
189 6 : case ResistanceRange::_470K_to_1M: return tr("470K to 1M ohms");
190 6 : 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 289 : QVariant MultimeterService::minValue(const ResistanceRange &range)
200 : {
201 289 : switch (range) {
202 17 : case ResistanceRange::_0_to_160: return 0;
203 17 : case ResistanceRange::_160_to_330: return 160;
204 17 : case ResistanceRange::_330_to_890: return 330;
205 17 : case ResistanceRange::_890_to_1K5: return 890;
206 119 : case ResistanceRange::_1K5_to_10K: return 1500;
207 17 : case ResistanceRange::_10K_to_100K: return 10000;
208 17 : case ResistanceRange::_100K_to_470K: return 100000;
209 17 : case ResistanceRange::_470K_to_1M: return 470000;
210 20 : 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 4505 : QVariant MultimeterService::maxValue(const ResistanceRange &range)
220 : {
221 4505 : switch (range) {
222 901 : case ResistanceRange::_0_to_160: return 160;
223 799 : case ResistanceRange::_160_to_330: return 330;
224 697 : case ResistanceRange::_330_to_890: return 890;
225 595 : case ResistanceRange::_890_to_1K5: return 1500;
226 595 : case ResistanceRange::_1K5_to_10K: return 10000;
227 391 : case ResistanceRange::_10K_to_100K: return 100000;
228 289 : case ResistanceRange::_100K_to_470K: return 470000;
229 187 : case ResistanceRange::_470K_to_1M: return 1000000;
230 20 : 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 1921 : MultimeterService::Range::Range() : voltageRange(static_cast<MultimeterService::VoltageRange>(0))
244 : {
245 :
246 1921 : }
247 :
248 : /// Constructs a new MultimeterService::Range instance with \a range.
249 2843 : MultimeterService::Range::Range(const MultimeterService::VoltageRange range) : voltageRange(range)
250 : {
251 :
252 2837 : }
253 :
254 : /// Constructs a new MultimeterService::Range instance with \a range.
255 833 : MultimeterService::Range::Range(const MultimeterService::CurrentRange range) : currentRange(range)
256 : {
257 :
258 833 : }
259 :
260 : /// Constructs a new MultimeterService::Range instance with \a range.
261 476 : MultimeterService::Range::Range(const MultimeterService::ResistanceRange range) : resistanceRange(range)
262 : {
263 :
264 476 : }
265 :
266 : /// Returns \a range as a user-friendly string, or a null QString if \a mode has no ranges.
267 153 : QString MultimeterService::toString(const Range &range, const Mode &mode)
268 : {
269 153 : switch (mode) {
270 68 : case Mode::DcVoltage:
271 : case Mode::AcVoltage:
272 68 : return toString(range.voltageRange);
273 68 : case Mode::DcCurrent:
274 : case Mode::AcCurrent:
275 68 : 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 2176 : bool operator==(const MultimeterService::Range &lhs, const MultimeterService::Range &rhs)
283 : {
284 2176 : return static_cast<std::underlying_type_t<MultimeterService::VoltageRange>>(lhs.voltageRange)
285 2176 : == 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 17 : bool operator!=(const MultimeterService::Range &lhs, const MultimeterService::Range &rhs)
290 : {
291 17 : return static_cast<std::underlying_type_t<MultimeterService::VoltageRange>>(lhs.voltageRange)
292 17 : != 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 17 : bool operator< (const MultimeterService::Range &lhs, const MultimeterService::Range &rhs)
297 : {
298 17 : return static_cast<std::underlying_type_t<MultimeterService::VoltageRange>>(lhs.voltageRange)
299 17 : < 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 17 : bool operator> (const MultimeterService::Range &lhs, const MultimeterService::Range &rhs)
304 : {
305 17 : return static_cast<std::underlying_type_t<MultimeterService::VoltageRange>>(lhs.voltageRange)
306 17 : > 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 34 : bool operator<=(const MultimeterService::Range &lhs, const MultimeterService::Range &rhs)
311 : {
312 34 : return static_cast<std::underlying_type_t<MultimeterService::VoltageRange>>(lhs.voltageRange)
313 34 : <= 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 34 : bool operator>=(const MultimeterService::Range &lhs, const MultimeterService::Range &rhs)
318 : {
319 34 : return static_cast<std::underlying_type_t<MultimeterService::VoltageRange>>(lhs.voltageRange)
320 34 : >= 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 187 : MultimeterService::MultimeterService(QLowEnergyController * const controller, QObject * parent)
336 187 : : AbstractPokitService(new MultimeterServicePrivate(controller, this), parent)
337 : {
338 :
339 187 : }
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 170 : MultimeterService::~MultimeterService()
357 : {
358 :
359 170 : }
360 :
361 17 : bool MultimeterService::readCharacteristics()
362 : {
363 17 : 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 28 : bool MultimeterService::readReadingCharacteristic()
376 : {
377 22 : Q_D(MultimeterService);
378 34 : 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 17 : bool MultimeterService::setSettings(const Settings &settings)
389 : {
390 11 : Q_D(const MultimeterService);
391 : const QLowEnergyCharacteristic characteristic =
392 28 : d->getCharacteristic(CharacteristicUuids::settings);
393 17 : if (!characteristic.isValid()) {
394 : return false;
395 : }
396 :
397 0 : const QByteArray value = d->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 6 : }
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 17 : MultimeterService::Reading MultimeterService::reading() const
421 : {
422 11 : Q_D(const MultimeterService);
423 : const QLowEnergyCharacteristic characteristic =
424 17 : d->getCharacteristic(CharacteristicUuids::reading);
425 28 : return (characteristic.isValid()) ? MultimeterServicePrivate::parseReading(characteristic.value())
426 : : Reading{ MeterStatus::Error, std::numeric_limits<float>::quiet_NaN(),
427 34 : Mode::Idle, VoltageRange::AutoRange };
428 6 : }
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 17 : bool MultimeterService::enableReadingNotifications()
440 : {
441 11 : Q_D(MultimeterService);
442 17 : 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 17 : bool MultimeterService::disableReadingNotifications()
453 : {
454 11 : Q_D(MultimeterService);
455 17 : 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 121 : MultimeterServicePrivate::MultimeterServicePrivate(
486 187 : QLowEnergyController * controller, MultimeterService * const q)
487 187 : : AbstractPokitServicePrivate(MultimeterService::serviceUuid, controller, q)
488 : {
489 :
490 121 : }
491 :
492 : /*!
493 : * Returns \a settings in the format Pokit devices expect.
494 : */
495 68 : 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 12 : QByteArray value;
502 112 : QDataStream stream(&value, QIODevice::WriteOnly);
503 68 : stream.setByteOrder(QDataStream::LittleEndian);
504 68 : stream.setFloatingPointPrecision(QDataStream::SinglePrecision); // 32-bit floats, not 64-bit.
505 68 : stream << (quint8)settings.mode << (quint8)settings.range.voltageRange << settings.updateInterval;
506 :
507 : Q_ASSERT(value.size() == 6);
508 68 : return value;
509 24 : }
510 :
511 : /*!
512 : * Parses the `Reading` \a value into a MultimeterService::Reading struct.
513 : */
514 85 : MultimeterService::Reading MultimeterServicePrivate::parseReading(const QByteArray &value)
515 : {
516 85 : MultimeterService::Reading reading{
517 : MultimeterService::MeterStatus::Error,
518 : std::numeric_limits<float>::quiet_NaN(),
519 : MultimeterService::Mode::Idle,
520 : MultimeterService::VoltageRange::AutoRange
521 55 : };
522 :
523 100 : if (!checkSize(QLatin1String("Reading"), value, 7, 7)) {
524 34 : return reading;
525 : }
526 :
527 51 : reading.status = MultimeterService::MeterStatus(value.at(0));
528 60 : reading.value = qFromLittleEndian<float>(value.mid(1,4));
529 51 : reading.mode = static_cast<MultimeterService::Mode>(value.at(5));
530 51 : reading.range.voltageRange = static_cast<MultimeterService::VoltageRange>(value.at(6));
531 51 : 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 17 : void MultimeterServicePrivate::characteristicRead(const QLowEnergyCharacteristic &characteristic,
539 : const QByteArray &value)
540 : {
541 17 : AbstractPokitServicePrivate::characteristicRead(characteristic, value);
542 :
543 11 : Q_Q(MultimeterService);
544 17 : if (characteristic.uuid() == MultimeterService::CharacteristicUuids::reading) {
545 0 : emit q->readingRead(parseReading(value));
546 0 : return;
547 : }
548 :
549 17 : 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 51 : qCWarning(lc).noquote() << tr("Unknown characteristic read for Multimeter service")
556 17 : << 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 17 : void MultimeterServicePrivate::characteristicWritten(const QLowEnergyCharacteristic &characteristic,
564 : const QByteArray &newValue)
565 : {
566 17 : AbstractPokitServicePrivate::characteristicWritten(characteristic, newValue);
567 :
568 11 : Q_Q(MultimeterService);
569 17 : if (characteristic.uuid() == MultimeterService::CharacteristicUuids::settings) {
570 0 : emit q->settingsWritten();
571 0 : return;
572 : }
573 :
574 17 : 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 51 : qCWarning(lc).noquote() << tr("Unknown characteristic written for Multimeter service")
581 17 : << 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 17 : void MultimeterServicePrivate::characteristicChanged(const QLowEnergyCharacteristic &characteristic,
589 : const QByteArray &newValue)
590 : {
591 17 : AbstractPokitServicePrivate::characteristicChanged(characteristic, newValue);
592 :
593 11 : Q_Q(MultimeterService);
594 17 : 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 17 : if (characteristic.uuid() == MultimeterService::CharacteristicUuids::reading) {
601 0 : emit q->readingRead(parseReading(newValue));
602 0 : return;
603 : }
604 :
605 51 : qCWarning(lc).noquote() << tr("Unknown characteristic notified for Multimeter service")
606 17 : << serviceUuid << characteristic.name() << characteristic.uuid();
607 : }
608 :
609 : /// \endcond
|