Line data Source code
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 CalibrationService and CalibrationServicePrivate classes.
7 : */
8 :
9 : #include <qtpokit/calibrationservice.h>
10 : #include "calibrationservice_p.h"
11 :
12 : #include <QtEndian>
13 :
14 : /*!
15 : * \class CalibrationService
16 : *
17 : * The CalibrationService class accesses the `Calibrartion` service of Pokit devices.
18 : */
19 :
20 :
21 : /*!
22 : * Constructs a new Pokit service with \a parent.
23 : */
24 190 : CalibrationService::CalibrationService(QLowEnergyController * const controller, QObject * parent)
25 270 : : AbstractPokitService(new CalibrationServicePrivate(controller, this), parent)
26 192 : {
27 :
28 382 : }
29 :
30 : /*!
31 : * \cond internal
32 : * Constructs a new Pokit service with \a parent, and private implementation \a d.
33 : */
34 0 : CalibrationService::CalibrationService(
35 0 : CalibrationServicePrivate * const d, QObject * const parent)
36 0 : : AbstractPokitService(d, parent)
37 0 : {
38 :
39 0 : }
40 : /// \endcond
41 :
42 : /*!
43 : * \copybrief AbstractPokitService::readCharacteristics
44 : *
45 : * This implementation always returns `true`, since the Calibration service provides no *readable*
46 : * characteristics (they're all write-only).
47 : */
48 38 : bool CalibrationService::readCharacteristics()
49 16 : {
50 16 : Q_D(CalibrationService);
51 62 : qCDebug(d->lc).noquote() << tr("Ignoring read request; the Calibration service is write-only.");
52 54 : return true;
53 16 : }
54 :
55 : /*!
56 : * Calibrates the Pokit device's temperature to \a ambientTemperature.
57 : *
58 : * Returns `true` if the write request was successfully queued, `false` otherwise.
59 : *
60 : * Emits temperatureCalibrated() if/when the \a name has been set.
61 : */
62 76 : bool CalibrationService::calibrateTemperature(const float ambientTemperature)
63 88 : {
64 88 : static_assert(sizeof(float) == 4, "Pokit devices expect 32-bit floats");
65 88 : Q_D(const CalibrationService);
66 88 : const QLowEnergyCharacteristic characteristic =
67 164 : d->getCharacteristic(CharacteristicUuids::temperature);
68 164 : if (!characteristic.isValid()) {
69 88 : return false;
70 88 : }
71 :
72 0 : const QByteArray newValue = CalibrationServicePrivate::encodeTemperature(ambientTemperature);
73 0 : qCDebug(d->lc).noquote() << tr("Writing new temperature %1 (0x%2).")
74 0 : .arg(ambientTemperature).arg(QLatin1String(newValue.toHex()));
75 0 : d->service->writeCharacteristic(characteristic, newValue);
76 0 : return (d->service->error() != QLowEnergyService::ServiceError::CharacteristicWriteError);
77 164 : }
78 :
79 : /*!
80 : * \fn CalibrationService::temperatureCalibrated
81 : *
82 : * This signal is emitted when the `Temperature` characteristic has been written succesfully.
83 : *
84 : * \see calibrateTemperature
85 : */
86 :
87 : /*!
88 : * \cond internal
89 : * \class CalibrationServicePrivate
90 : *
91 : * The CalibrationServicePrivate class provides private implementation for CalibrationService.
92 : */
93 :
94 : /*!
95 : * \internal
96 : * Constructs a new CalibrationServicePrivate object with public implementation \a q.
97 : */
98 80 : CalibrationServicePrivate::CalibrationServicePrivate(
99 190 : QLowEnergyController * controller, CalibrationService * const q)
100 270 : : AbstractPokitServicePrivate(CalibrationService::serviceUuid, controller, q)
101 192 : {
102 :
103 272 : }
104 :
105 : /*!
106 : * Returns \a value in a format Pokit devices expect. Specifically, this just enocdes \a value as
107 : * a 32-bit float in litte-endian byte order.
108 : */
109 190 : QByteArray CalibrationServicePrivate::encodeTemperature(const float value)
110 220 : {
111 220 : static_assert(sizeof(value) == 4, "Pokit devices expect 32-bit floats");
112 410 : QByteArray bytes(sizeof(float), '\0');
113 220 : qToLittleEndian<float>(value, bytes.data());
114 410 : return bytes;
115 220 : }
116 :
117 : /*!
118 : * Implements AbstractPokitServicePrivate::characteristicWritten to parse \a newValue, then emit a
119 : * specialised signal, for each supported \a characteristic.
120 : */
121 38 : void CalibrationServicePrivate::characteristicWritten(const QLowEnergyCharacteristic &characteristic,
122 : const QByteArray &newValue)
123 44 : {
124 82 : AbstractPokitServicePrivate::characteristicWritten(characteristic, newValue);
125 :
126 44 : Q_Q(CalibrationService);
127 82 : if (characteristic.uuid() == CalibrationService::CharacteristicUuids::temperature) {
128 0 : Q_EMIT q->temperatureCalibrated();
129 0 : return;
130 0 : }
131 :
132 179 : qCWarning(lc).noquote() << tr("Unknown characteristic written for Calibration service")
133 135 : << serviceUuid << characteristic.name() << characteristic.uuid();
134 44 : }
135 :
136 : /// \endcond
|