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 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 : /// UUID of the "Calibration" service. 21 : const QBluetoothUuid CalibrationService:: 22 : serviceUuid(QLatin1String("6f53be2f-780b-49b8-a7c3-e8a052b3ae2c")); 23 : 24 : /// \struct CalibrationService::CharacteristicUuids 25 : /// \brief Characteristics available via the `Calibration` service. 26 : 27 : /// UUID of the `Calibration` service's `Temperature` characterstic. 28 : const QBluetoothUuid CalibrationService::CharacteristicUuids:: 29 : temperature(QLatin1String("0cd0f713-f5aa-4572-9e23-f8049f6bcaaa")); 30 : 31 : /*! 32 : * Constructs a new Pokit service with \a parent. 33 : */ 34 85 : CalibrationService::CalibrationService(QLowEnergyController * const controller, QObject * parent) 35 85 : : AbstractPokitService(new CalibrationServicePrivate(controller, this), parent) 36 : { 37 : 38 85 : } 39 : 40 : /*! 41 : * \cond internal 42 : * Constructs a new Pokit service with \a parent, and private implementation \a d. 43 : */ 44 0 : CalibrationService::CalibrationService( 45 0 : CalibrationServicePrivate * const d, QObject * const parent) 46 0 : : AbstractPokitService(d, parent) 47 : { 48 : 49 0 : } 50 : /// \endcond 51 : 52 : /*! 53 : * Destroys this CalibrationService object. 54 : */ 55 68 : CalibrationService::~CalibrationService() 56 : { 57 : 58 68 : } 59 : 60 : /*! 61 : * \copybrief AbstractPokitService::readCharacteristics 62 : * 63 : * This implementation always returns `true`, since the Calibration service provides no *readable* 64 : * characteristics (they're all write-only). 65 : */ 66 17 : bool CalibrationService::readCharacteristics() 67 : { 68 : Q_D(CalibrationService); 69 17 : qCDebug(d->lc).noquote() << tr("Ignoring read request; the Calibration service is write-only."); 70 17 : return true; 71 : } 72 : 73 : /*! 74 : * Set's the Pokit device's name to \a name. 75 : * 76 : * Returns `true` if the write request was successfully queued, `false` otherwise. 77 : * 78 : * Emits deviceNameWritten() if/when the \a name has been set. 79 : */ 80 34 : bool CalibrationService::calibrateTemperature(const float ambientTemperature) 81 : { 82 : static_assert(sizeof(float) == 4, "Pokit devices expect 32-bit floats"); 83 22 : Q_D(const CalibrationService); 84 : const QLowEnergyCharacteristic characteristic = 85 56 : d->getCharacteristic(CharacteristicUuids::temperature); 86 34 : if (!characteristic.isValid()) { 87 : return false; 88 : } 89 : 90 0 : const QByteArray newValue = d->encodeTemperature(ambientTemperature); 91 0 : qCDebug(d->lc).noquote() << tr("Writing new temperature %1 (0x%2).") 92 0 : .arg(ambientTemperature).arg(QLatin1String(newValue.toHex())); 93 0 : d->service->writeCharacteristic(characteristic, newValue); 94 0 : return (d->service->error() != QLowEnergyService::ServiceError::CharacteristicWriteError); 95 12 : } 96 : 97 : /*! 98 : * \fn CalibrationService::temperatureCalibrated 99 : * 100 : * This signal is emitted when the `Temperature` characteristic has been written succesfully. 101 : * 102 : * \see calibrateTemperature 103 : */ 104 : 105 : /*! 106 : * \cond internal 107 : * \class CalibrationServicePrivate 108 : * 109 : * The CalibrationServicePrivate class provides private implementation for CalibrationService. 110 : */ 111 : 112 : /*! 113 : * \internal 114 : * Constructs a new CalibrationServicePrivate object with public implementation \a q. 115 : */ 116 55 : CalibrationServicePrivate::CalibrationServicePrivate( 117 85 : QLowEnergyController * controller, CalibrationService * const q) 118 85 : : AbstractPokitServicePrivate(CalibrationService::serviceUuid, controller, q) 119 : { 120 : 121 55 : } 122 : 123 : /*! 124 : * Returns \a value in a format Pokit devices expect. Specifically, this just enocdes \a value as 125 : * a 32-bit float in litte-endian byte order. 126 : */ 127 85 : QByteArray CalibrationServicePrivate::encodeTemperature(const float value) 128 : { 129 : static_assert(sizeof(value) == 4, "Pokit devices expect 32-bit floats"); 130 85 : QByteArray bytes(sizeof(float), '\0'); 131 : qToLittleEndian<float>(value, bytes.data()); 132 85 : return bytes; 133 0 : } 134 : 135 : /*! 136 : * Implements AbstractPokitServicePrivate::characteristicWritten to parse \a newValue, then emit a 137 : * specialised signal, for each supported \a characteristic. 138 : */ 139 17 : void CalibrationServicePrivate::characteristicWritten(const QLowEnergyCharacteristic &characteristic, 140 : const QByteArray &newValue) 141 : { 142 17 : AbstractPokitServicePrivate::characteristicWritten(characteristic, newValue); 143 : 144 11 : Q_Q(CalibrationService); 145 17 : if (characteristic.uuid() == CalibrationService::CharacteristicUuids::temperature) { 146 0 : emit q->temperatureCalibrated(); 147 0 : return; 148 : } 149 : 150 51 : qCWarning(lc).noquote() << tr("Unknown characteristic written for Calibration service") 151 17 : << serviceUuid << characteristic.name() << characteristic.uuid(); 152 : } 153 : 154 : /// \endcond