From 0198bc91c1c81cb02cb1d328bdd68d659fca8971 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Tue, 28 Nov 2017 20:23:23 +0100 Subject: [PATCH] Rework multisensor plugin --- guh-plugins.pro | 2 +- multisensor/devicepluginmultisensor.cpp | 115 +++-- multisensor/devicepluginmultisensor.h | 15 +- multisensor/multisensor.pro | 2 + multisensor/sensortag-old.cpp | 337 ++++++++++++++ multisensor/sensortag-old.h | 79 ++++ multisensor/sensortag.cpp | 591 ++++++++++++------------ multisensor/sensortag.h | 125 ++--- plugins.pri | 2 +- 9 files changed, 874 insertions(+), 394 deletions(-) create mode 100644 multisensor/sensortag-old.cpp create mode 100644 multisensor/sensortag-old.h diff --git a/guh-plugins.pro b/guh-plugins.pro index 58e56866..7f3a7a5d 100644 --- a/guh-plugins.pro +++ b/guh-plugins.pro @@ -32,7 +32,7 @@ PLUGIN_DIRS = \ pushbullet \ usbwde \ #senic \ - #multisensor \ + multisensor \ gpio \ diff --git a/multisensor/devicepluginmultisensor.cpp b/multisensor/devicepluginmultisensor.cpp index f3026b59..7bd84266 100644 --- a/multisensor/devicepluginmultisensor.cpp +++ b/multisensor/devicepluginmultisensor.cpp @@ -44,17 +44,20 @@ #include "plugininfo.h" #include "devicemanager.h" -#include "bluetooth/bluetoothlowenergydevice.h" +#include "bluetooth/bluetoothlowenergymanager.h" #include "devicepluginmultisensor.h" +// http://processors.wiki.ti.com/index.php/SensorTag_User_Guide + DevicePluginMultiSensor::DevicePluginMultiSensor() { } -DeviceManager::HardwareResources DevicePluginMultiSensor::requiredHardware() const +void DevicePluginMultiSensor::init() { - return DeviceManager::HardwareResourceBluetoothLE; + m_measureTimer = hardwareManager()->pluginTimerManager()->registerTimer(60); + connect(m_measureTimer, &PluginTimer::timeout, this, &DevicePluginMultiSensor::onPluginTimer); } DeviceManager::DeviceError DevicePluginMultiSensor::discoverDevices(const DeviceClassId &deviceClassId, const ParamList ¶ms) @@ -64,48 +67,35 @@ DeviceManager::DeviceError DevicePluginMultiSensor::discoverDevices(const Device if (deviceClassId != sensortagDeviceClassId) return DeviceManager::DeviceErrorDeviceClassNotFound; - if (!discoverBluetooth()) + if (!hardwareManager()->bluetoothLowEnergyManager()->available()) return DeviceManager::DeviceErrorHardwareNotAvailable; + if (!hardwareManager()->bluetoothLowEnergyManager()->enabled()) + return DeviceManager::DeviceErrorHardwareNotAvailable; + + BluetoothDiscoveryReply *reply = hardwareManager()->bluetoothLowEnergyManager()->discoverDevices(); + connect(reply, &BluetoothDiscoveryReply::finished, this, &DevicePluginMultiSensor::onBluetoothDiscoveryFinished); return DeviceManager::DeviceErrorAsync; } -void DevicePluginMultiSensor::bluetoothDiscoveryFinished(const QList &deviceInfos) -{ - QList deviceDescriptors; - foreach (auto deviceInfo, deviceInfos) { - if (deviceInfo.name().contains("SensorTag")) { - if (!verifyExistingDevices(deviceInfo)) { - DeviceDescriptor descriptor(sensortagDeviceClassId, "SensorTag", deviceInfo.address().toString()); - ParamList params; - params.append(Param(nameParamTypeId, deviceInfo.name())); - params.append(Param(macParamTypeId, deviceInfo.address().toString())); - descriptor.setParams(params); - deviceDescriptors.append(descriptor); - } - } - } - - emit devicesDiscovered(sensortagDeviceClassId, deviceDescriptors); -} - DeviceManager::DeviceSetupStatus DevicePluginMultiSensor::setupDevice(Device *device) { - qCDebug(dcMultiSensor) << "Setting up MultiSensor" << device->name() << device->params(); + qCDebug(dcMultiSensor) << "Setting up Multi Sensor" << device->name() << device->params(); if (device->deviceClassId() == sensortagDeviceClassId) { - auto address = QBluetoothAddress(device->paramValue(macParamTypeId).toString()); - auto name = device->paramValue(nameParamTypeId).toString(); - auto deviceInfo = QBluetoothDeviceInfo(address, name, 0); - QSharedPointer tag{new SensorTag(deviceInfo, QLowEnergyController::PublicAddress, this)}; - connect(tag.data(), &SensorTag::valueChanged, this, - [device, this](StateTypeId state, QVariant value) { device->setStateValue(state, value); }); - connect(tag.data(), &SensorTag::event, this, - [device, this](EventTypeId event) { emit emitEvent(Event(event, device->id())); }); - m_tags.insert(tag, device); + QBluetoothAddress address = QBluetoothAddress(device->paramValue(macParamTypeId).toString()); + QString name = device->paramValue(nameParamTypeId).toString(); + QBluetoothDeviceInfo deviceInfo = QBluetoothDeviceInfo(address, name, 0); - tag->connectDevice(); + BluetoothLowEnergyDevice *bluetoothDevice = hardwareManager()->bluetoothLowEnergyManager()->registerDevice(deviceInfo, QLowEnergyController::PublicAddress); + + SensorTag *sensor = new SensorTag(device, bluetoothDevice, this); + connect(sensor, &SensorTag::leftKeyPressed, this, &DevicePluginMultiSensor::onSensorLeftButtonPressed); + connect(sensor, &SensorTag::rightKeyPressed, this, &DevicePluginMultiSensor::onSensorRightButtonPressed); + + m_sensors.insert(device, sensor); + sensor->bluetoothDevice()->connectDevice(); return DeviceManager::DeviceSetupStatusSuccess; } @@ -115,16 +105,18 @@ DeviceManager::DeviceSetupStatus DevicePluginMultiSensor::setupDevice(Device *de void DevicePluginMultiSensor::deviceRemoved(Device *device) { - if (!m_tags.values().contains(device)) + if (!m_sensors.contains(device)) return; - auto tag= m_tags.key(device); - m_tags.remove(tag); + SensorTag *sensor = m_sensors.value(device); + m_sensors.remove(device); + hardwareManager()->bluetoothLowEnergyManager()->unregisterDevice(sensor->bluetoothDevice()); + sensor->deleteLater(); } bool DevicePluginMultiSensor::verifyExistingDevices(const QBluetoothDeviceInfo &deviceInfo) { - foreach (Device *device, myDevices()) { + foreach (Device *device, m_sensors.keys()) { if (device->paramValue(macParamTypeId).toString() == deviceInfo.address().toString()) return true; } @@ -132,4 +124,51 @@ bool DevicePluginMultiSensor::verifyExistingDevices(const QBluetoothDeviceInfo & return false; } +void DevicePluginMultiSensor::onPluginTimer() +{ + foreach (SensorTag *sensor, m_sensors) { + sensor->measure(); + } +} + +void DevicePluginMultiSensor::onSensorLeftButtonPressed() +{ + SensorTag *sensor = static_cast(sender()); + emit emitEvent(Event(leftKeyEventTypeId, sensor->device()->id())); +} + +void DevicePluginMultiSensor::onSensorRightButtonPressed() +{ + SensorTag *sensor = static_cast(sender()); + emit emitEvent(Event(rightKeyEventTypeId, sensor->device()->id())); +} + +void DevicePluginMultiSensor::onBluetoothDiscoveryFinished() +{ + BluetoothDiscoveryReply *reply = static_cast(sender()); + if (reply->error() != BluetoothDiscoveryReply::BluetoothDiscoveryReplyErrorNoError) { + qCWarning(dcMultiSensor()) << "Bluetooth discovery error:" << reply->error(); + reply->deleteLater(); + emit devicesDiscovered(sensortagDeviceClassId, QList()); + return; + } + + QList deviceDescriptors; + foreach (const QBluetoothDeviceInfo &deviceInfo, reply->discoveredDevices()) { + if (deviceInfo.name().contains("SensorTag")) { + if (!verifyExistingDevices(deviceInfo)) { + DeviceDescriptor descriptor(sensortagDeviceClassId, "Sensor Tag", deviceInfo.address().toString()); + ParamList params; + params.append(Param(nameParamTypeId, deviceInfo.name())); + params.append(Param(macParamTypeId, deviceInfo.address().toString())); + descriptor.setParams(params); + deviceDescriptors.append(descriptor); + } + } + } + + reply->deleteLater(); + emit devicesDiscovered(sensortagDeviceClassId, deviceDescriptors); +} + #endif // BLUETOOTH_LE diff --git a/multisensor/devicepluginmultisensor.h b/multisensor/devicepluginmultisensor.h index 1e587de1..23d7a56a 100644 --- a/multisensor/devicepluginmultisensor.h +++ b/multisensor/devicepluginmultisensor.h @@ -30,6 +30,7 @@ #include #include "plugin/deviceplugin.h" #include "devicemanager.h" +#include "plugintimer.h" #include "bluetooth/bluetoothlowenergydevice.h" #include "sensortag.h" @@ -42,16 +43,24 @@ class DevicePluginMultiSensor : public DevicePlugin public: explicit DevicePluginMultiSensor(); - DeviceManager::HardwareResources requiredHardware() const override; + void init() override; DeviceManager::DeviceError discoverDevices(const DeviceClassId &deviceClassId, const ParamList ¶ms) override; - void bluetoothDiscoveryFinished(const QList &deviceInfos) override; DeviceManager::DeviceSetupStatus setupDevice(Device *device) override; void deviceRemoved(Device *device) override; private: + PluginTimer *m_measureTimer = nullptr; + QHash m_sensors; + bool verifyExistingDevices(const QBluetoothDeviceInfo &deviceInfo); - QHash,QPointer> m_tags; +private slots: + void onPluginTimer(); + + void onSensorLeftButtonPressed(); + void onSensorRightButtonPressed(); + + void onBluetoothDiscoveryFinished(); }; #endif // BLUETOOTH_LE diff --git a/multisensor/multisensor.pro b/multisensor/multisensor.pro index 0e6250d4..4b719202 100644 --- a/multisensor/multisensor.pro +++ b/multisensor/multisensor.pro @@ -8,8 +8,10 @@ TARGET = $$qtLibraryTarget(guh_devicepluginmultisensor) SOURCES += \ devicepluginmultisensor.cpp \ + #sensortag-old.cpp \ sensortag.cpp HEADERS += \ devicepluginmultisensor.h \ + #sensortag-old.h \ sensortag.h diff --git a/multisensor/sensortag-old.cpp b/multisensor/sensortag-old.cpp new file mode 100644 index 00000000..7b5f2e29 --- /dev/null +++ b/multisensor/sensortag-old.cpp @@ -0,0 +1,337 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * * + * Copyright (C) 2015 Simon Stürz * + * Copyright (C) 2016 nicc * + * * + * This file is part of guh. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either * + * version 2.1 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; If not, see * + * . * + * * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifdef BLUETOOTH_LE + +#include +#include +#include +#include "extern-plugininfo.h" +#include "sensortag-old.h" + +SensorTag::SensorTag(const QBluetoothDeviceInfo &deviceInfo, const QLowEnergyController::RemoteAddressType &addressType, QObject *parent) : + BluetoothLowEnergyDevice(deviceInfo, addressType, parent) +{ + connect(this, SIGNAL(connectionStatusChanged()), this,SLOT(onConnectionStatusChanged())); + connect(this, SIGNAL(servicesDiscoveryFinished()), this, SLOT(setupServices())); +} + +double SensorTag::calculateMeanValue(const QList &list) +{ + double sum = 0; + foreach (const double &value, list) + sum += value; + + return sum / list.count(); +} + +void SensorTag::setupServices() +{ + foreach (auto id, m_services.keys()) { + if (!controller()->services().contains(id)) { + qCWarning(dcMultiSensor) << "Service not found for device" << name() << address().toString(); + return; + } + + if (m_services.value(id)) { + qCWarning(dcMultiSensor) << "Attention! bad implementation of service handling!!"; + return; + } + + qCDebug(dcMultiSensor) << "Setup service"; + + // service for temperature + QSharedPointer service{controller()->createServiceObject(id, this)}; + + if (service.isNull()) { + qCWarning(dcMultiSensor) << "Could not create service for device" << name() << address().toString(); + return; + } + + m_services.insert(id, service); + + connect(service.data(), SIGNAL(error(QLowEnergyService::ServiceError)), this, SLOT(onServiceError(QLowEnergyService::ServiceError))); + connect(service.data(), &QLowEnergyService::stateChanged, this, &SensorTag::onServiceStateChanged); + connect(service.data(), &QLowEnergyService::characteristicChanged, this, &SensorTag::onServiceCharacteristicChanged); +#if (QT_VERSION >= QT_VERSION_CHECK(5, 5, 0)) + connect(service.data(), &QLowEnergyService::characteristicRead, this, &SensorTag::onServiceCharacteristicChanged); +#endif + + service->discoverDetails(); + } +} + +void SensorTag::onConnectionStatusChanged() +{ + if (!isConnected()) { + // delete the services, they need to be recreated and + // rediscovered once the device will be reconnected + foreach (QSharedPointer service, m_services) + service->deleteLater(); + + emit valueChanged(connectedStateTypeId, false); + } else { + emit valueChanged(connectedStateTypeId, true); + } +} + +void SensorTag::onServiceStateChanged(const QLowEnergyService::ServiceState &state) +{ + QPointer service = qobject_cast(sender()); + + switch (state) { + case QLowEnergyService::DiscoveringServices: + qCDebug(dcMultiSensor) << "Start discovering service" << service->serviceUuid(); + break; + case QLowEnergyService::ServiceDiscovered: + if (m_services.contains(service->serviceUuid())) { + qCDebug(dcMultiSensor) << "... service discovered."; + + auto dataId = service->serviceUuid(); + dataId.data1 += 1; + auto sensorCharacteristic = service->characteristic(dataId); + + if (!sensorCharacteristic.isValid()) { + qCWarning(dcMultiSensor) << "Characteristic not found for device " << name() << address().toString(); + break; + } + + const auto notificationDescriptor = sensorCharacteristic.descriptor( + QBluetoothUuid::ClientCharacteristicConfiguration); + + if (notificationDescriptor.isValid()) { + service->writeDescriptor(notificationDescriptor, QByteArray::fromHex("0100")); + qCDebug(dcMultiSensor) << "Measuring"; + } + + if (service->serviceUuid().data1 == 0xffe0) + break; + + auto configId = service->serviceUuid(); + configId.data1 += 2; + auto sensorConfig = service->characteristic(configId); + + if (!sensorConfig.isValid()) { + qCWarning(dcMultiSensor) << "Characteristic not found for device " << name() << address().toString(); + break; + } + + if (service->serviceUuid().data1 == 0xf000aa50) { + service->writeCharacteristic(sensorConfig, QByteArray::fromHex("07")); + } else { + service->writeCharacteristic(sensorConfig, QByteArray::fromHex("01")); + } + + if (service->serviceUuid().data1 == 0xf000aa40) { + service->writeCharacteristic(sensorConfig, QByteArray::fromHex("02")); + auto calibId = service->serviceUuid(); + calibId.data1 += 3; +#if (QT_VERSION >= QT_VERSION_CHECK(5, 5, 0)) + service->readCharacteristic(service->characteristic(calibId)); +#endif + } + + // TODO: initialize the states with the current value + + } + break; + default: + break; + } +} + +inline quint16 buildUINT16(quint8 loByte, quint8 hiByte) { + return ((quint16)(((loByte) & 0x00FF) + (((hiByte) & 0x00FF) << 8))); +} + +void SensorTag::onServiceCharacteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &value) +{ + qCDebug(dcMultiSensor) << "Service characteristic changed" << characteristic.uuid().toString() << value.toHex(); + + auto id = characteristic.uuid(); + id.data1 -= 1; + switch (characteristic.uuid().data1) { + case 0xf000aa01: { + const quint16 *data = reinterpret_cast(value.constData()); + qint16 rawTamb = data[1]; + m_temperatureValues.append((double)rawTamb / 128); + if (m_temperatureValues.count() % 60 == 0) { + emit valueChanged(temperatureStateTypeId, calculateMeanValue(m_temperatureValues)); + m_temperatureValues.clear(); + } + + qint16 Vobj2 = (double)data[0]; + Vobj2 *= 0.00000015625; + double Tdie2 = ((double)rawTamb / 128) + 273.15; + const double S0 = 6.4E-14; // Calibration factor + const double a1 = 1.75E-3; + const double a2 = -1.678E-5; + const double b0 = -2.94E-5; + const double b1 = -5.7E-7; + const double b2 = 4.63E-9; + const double c2 = 13.4; + const double Tref = 298.15; + double S = S0*(1+a1*(Tdie2 - Tref)+a2*qPow((Tdie2 - Tref),2)); + double Vos = b0 + b1*(Tdie2 - Tref) + b2*qPow((Tdie2 - Tref),2); + double fObj = (Vobj2 - Vos) + c2*qPow((Vobj2 - Vos),2); + double tObj = qPow(qPow(Tdie2,4) + (fObj/S),.25); + m_irTemperatureValues.append(tObj - 273.15); + if (m_irTemperatureValues.count() % 60 == 0) { + emit valueChanged(IRtemperatureStateTypeId, calculateMeanValue(m_irTemperatureValues)); + m_irTemperatureValues.clear(); + } + + break; + } + case 0xf000aa11: { + // TODO: evaluate movement + + // const qint8 *data = reinterpret_cast(value.constData()); + // emit valueChanged(accelerationXStateTypeId, (double)data[0] / 64); + // emit valueChanged(accelerationYStateTypeId, (double)data[1] / 64); + // emit valueChanged(accelerationZStateTypeId, (double)data[2] / 64); + break; + } + case 0xf000aa21: { + const quint16 *data = reinterpret_cast(value.constData()); + quint16 rawH = data[1]; + rawH &= ~0x0003; + m_humidityValues.append(-6.0 + 125.0/65536 * (double)rawH); + if (m_humidityValues.count() % 60 == 0) { + emit valueChanged(humidityStateTypeId, calculateMeanValue(m_humidityValues)); + m_humidityValues.clear(); + } + break; + } + case 0xf000aa31: { + // TODO: evaluate movement + // const qint16 *data = reinterpret_cast(value.constData()); + // emit valueChanged(magneticFieldXStateTypeId, (double)data[0] / 32.768); + // emit valueChanged(magneticFieldYStateTypeId, (double)data[1] / 32.768); + // emit valueChanged(magneticFieldZStateTypeId, (double)data[2] / 32.768); + break; + } + case 0xf000aa41: { + if (m_c.empty()) + break; + const quint16 *data = reinterpret_cast(value.constData()); + quint16 Pr = data[1]; + qint16 Tr = data[0]; + // Sensitivity + qint64 s = (qint64)m_c[2]; + qint64 val = (qint64)m_c[3] * Tr; + s += (val >> 17); + val = (qint64)m_c2[0] * Tr * Tr; + s += (val >> 34); + // Offset + qint64 o = (qint64)m_c2[1] << 14; + val = (qint64)m_c2[2] * Tr; + o += (val >> 3); + val = (qint64)m_c2[3] * Tr * Tr; + o += (val >> 19); + // Pressure (Pa) + qint64 pres = ((qint64)(s * Pr) + o) >> 14; + m_pressureValues.append((double)pres/100); + if (m_pressureValues.count() % 60 == 0) { + emit valueChanged(pressureStateTypeId, calculateMeanValue(m_pressureValues)); + m_pressureValues.clear(); + } + + break; + } + case 0xf000aa43: { + const quint8 *data = reinterpret_cast(value.constData()); + m_c.resize(4); + m_c2.resize(4); + m_c[0] = buildUINT16(data[0],data[1]); + m_c[1] = buildUINT16(data[2],data[3]); + m_c[2] = buildUINT16(data[4],data[5]); + m_c[3] = buildUINT16(data[6],data[7]); + m_c2[0] = buildUINT16(data[8],data[9]); + m_c2[1] = buildUINT16(data[10],data[11]); + m_c2[2] = buildUINT16(data[12],data[13]); + m_c2[3] = buildUINT16(data[14],data[15]); + break; + } + case 0xf000aa51: { + // TODO: evaluate movement + // const qint16 *data = reinterpret_cast(value.constData()); + // emit valueChanged(rotationXStateTypeId, (double)data[0] / 131.072); + // emit valueChanged(rotationYStateTypeId, (double)data[1] / 131.072); + // emit valueChanged(rotationZStateTypeId, (double)data[2] / 131.072); + break; + } + case 0xffe1: { + const quint8 *data = reinterpret_cast(value.constData()); + if (*data & 1) + emit event(leftKeyEventTypeId); + if (*data & 2) + emit event(rightKeyEventTypeId); + break; + } + default: + break; + } +} + +void SensorTag::onServiceError(const QLowEnergyService::ServiceError &error) +{ + QString errorString; + switch (error) { + case QLowEnergyService::NoError: + errorString = "No error"; + break; + case QLowEnergyService::OperationError: + errorString = "Operation error"; + break; +#if (QT_VERSION >= QT_VERSION_CHECK(5, 5, 0)) + case QLowEnergyService::CharacteristicReadError: + errorString = "Characteristic read error"; + break; +#endif + case QLowEnergyService::CharacteristicWriteError: + errorString = "Characteristic write error"; + break; +#if (QT_VERSION >= QT_VERSION_CHECK(5, 5, 0)) + case QLowEnergyService::DescriptorReadError: + errorString = "Descriptor read error"; + break; +#endif + case QLowEnergyService::DescriptorWriteError: + errorString = "Descriptor write error"; + break; +#if (QT_VERSION >= QT_VERSION_CHECK(5, 5, 0)) + case QLowEnergyService::UnknownError: + errorString = "Unknown error"; + break; +#endif + default: + errorString = "Unknown error"; + break; + } + + + qCWarning(dcMultiSensor) << "Service of " << name() << address().toString() << ":" << errorString; +} + +#endif // BLUETOOTH_LE diff --git a/multisensor/sensortag-old.h b/multisensor/sensortag-old.h new file mode 100644 index 00000000..4c7bb9ec --- /dev/null +++ b/multisensor/sensortag-old.h @@ -0,0 +1,79 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * * + * Copyright (C) 2015 Simon Stürz * + * Copyright (C) 2016 nicc * + * * + * This file is part of guh. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either * + * version 2.1 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; If not, see * + * . * + * * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef SENSORTAG_H +#define SENSORTAG_H + +#ifdef BLUETOOTH_LE + +#include +#include +#include +#include + +#include "bluetooth/bluetoothlowenergydevice.h" +#include "extern-plugininfo.h" + +class SensorTag : public BluetoothLowEnergyDevice +{ + Q_OBJECT +public: + explicit SensorTag(const QBluetoothDeviceInfo &deviceInfo, const QLowEnergyController::RemoteAddressType &addressType, QObject *parent = 0); + +signals: + void valueChanged(StateTypeId state, QVariant value); + void event(EventTypeId event); + +private: + QHash> m_services{ + {QBluetoothUuid(QUuid("f000aa00-0451-4000-b000-000000000000")), QSharedPointer()}, + {QBluetoothUuid(QUuid("f000aa10-0451-4000-b000-000000000000")), QSharedPointer()}, + {QBluetoothUuid(QUuid("f000aa20-0451-4000-b000-000000000000")), QSharedPointer()}, + {QBluetoothUuid(QUuid("f000aa30-0451-4000-b000-000000000000")), QSharedPointer()}, + {QBluetoothUuid(QUuid("f000aa40-0451-4000-b000-000000000000")), QSharedPointer()}, + {QBluetoothUuid(QUuid("f000aa50-0451-4000-b000-000000000000")), QSharedPointer()}, + {QBluetoothUuid(QUuid("0000ffe0-0000-1000-8000-00805f9b34fb")), QSharedPointer()} + }; + + QVector m_c; + QVector m_c2; + + QList m_temperatureValues; + QList m_irTemperatureValues; + QList m_humidityValues; + QList m_pressureValues; + + double calculateMeanValue(const QList &list); + +private slots: + void setupServices(); + void onConnectionStatusChanged(); + + // Service + void onServiceStateChanged(const QLowEnergyService::ServiceState &state); + void onServiceCharacteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &value); + void onServiceError(const QLowEnergyService::ServiceError &error); +}; +#endif // BLUETOOTH_LE + +#endif // SENSORTAG_H diff --git a/multisensor/sensortag.cpp b/multisensor/sensortag.cpp index f496410c..3038067b 100644 --- a/multisensor/sensortag.cpp +++ b/multisensor/sensortag.cpp @@ -1,337 +1,342 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * * - * Copyright (C) 2015 Simon Stürz * - * Copyright (C) 2016 nicc * - * * - * This file is part of guh. * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; If not, see * - * . * - * * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifdef BLUETOOTH_LE - -#include -#include -#include -#include "extern-plugininfo.h" #include "sensortag.h" +#include "extern-plugininfo.h" -SensorTag::SensorTag(const QBluetoothDeviceInfo &deviceInfo, const QLowEnergyController::RemoteAddressType &addressType, QObject *parent) : - BluetoothLowEnergyDevice(deviceInfo, addressType, parent) +SensorTag::SensorTag(Device *device, BluetoothLowEnergyDevice *bluetoothDevice, QObject *parent) : + QObject(parent), + m_device(device), + m_bluetoothDevice(bluetoothDevice) { - connect(this, SIGNAL(connectionStatusChanged()), this,SLOT(onConnectionStatusChanged())); - connect(this, SIGNAL(servicesDiscoveryFinished()), this, SLOT(setupServices())); + connect(m_bluetoothDevice, &BluetoothLowEnergyDevice::connectedChanged, this, &SensorTag::onConnectedChanged); + connect(m_bluetoothDevice, &BluetoothLowEnergyDevice::servicesDiscoveryFinished, this, &SensorTag::onServiceDiscoveryFinished); } -double SensorTag::calculateMeanValue(const QList &list) +Device *SensorTag::device() { - double sum = 0; - foreach (const double &value, list) - sum += value; - - return sum / list.count(); + return m_device; } -void SensorTag::setupServices() +BluetoothLowEnergyDevice *SensorTag::bluetoothDevice() { - foreach (auto id, m_services.keys()) { - if (!controller()->services().contains(id)) { - qCWarning(dcMultiSensor) << "Service not found for device" << name() << address().toString(); + return m_bluetoothDevice; +} + +void SensorTag::updateInfraredValue(const QByteArray &value) +{ + qCDebug(dcMultiSensor()) << "Infrared value" << value; +} + +void SensorTag::updateButtonValue(const QByteArray &value) +{ + const quint8 *data = reinterpret_cast(value.constData()); + if (*data & 1) + emit leftKeyPressed(); + if (*data & 2) + emit rightKeyPressed(); +} + +void SensorTag::updateHumidityValue(const QByteArray &value) +{ + qCDebug(dcMultiSensor()) << "Humidity value" << value; +} + +void SensorTag::updatePressureValue(const QByteArray &value) +{ + qCDebug(dcMultiSensor()) << "Pressure value" << value; +} + +void SensorTag::onConnectedChanged(const bool &connected) +{ + qCDebug(dcMultiSensor()) << "Sensor" << m_bluetoothDevice->name() << m_bluetoothDevice->address().toString() << (connected ? "connected" : "disconnected"); + m_device->setStateValue(connectedStateTypeId, connected); + + if (!connected) { + // Clean up services + m_infraredService->deleteLater(); + m_buttonService->deleteLater(); + m_humidityService->deleteLater(); + m_pressureService->deleteLater(); + + m_infraredService = nullptr; + m_buttonService = nullptr; + m_humidityService = nullptr; + m_pressureService = nullptr; + } + +} + +void SensorTag::onServiceDiscoveryFinished() +{ + if (!m_bluetoothDevice->serviceUuids().contains(infraredServiceUuid)) { + qCWarning(dcMultiSensor()) << "Could not find infrared service"; + return; + } + + if (!m_bluetoothDevice->serviceUuids().contains(accelerometerServiceUuid)) { + qCWarning(dcMultiSensor()) << "Could not find accelereometer service"; + return; + } + + if (!m_bluetoothDevice->serviceUuids().contains(humidityServiceUuid)) { + qCWarning(dcMultiSensor()) << "Could not find humidity service"; + return; + } + + if (!m_bluetoothDevice->serviceUuids().contains(magnetometerServiceUuid)) { + qCWarning(dcMultiSensor()) << "Could not find magnetometer service"; + return; + } + + if (!m_bluetoothDevice->serviceUuids().contains(pressureServiceUuid)) { + qCWarning(dcMultiSensor()) << "Could not find pressure service"; + return; + } + + if (!m_bluetoothDevice->serviceUuids().contains(gyroscopeServiceUuid)) { + qCWarning(dcMultiSensor()) << "Could not find magnetometer service"; + return; + } + + // IR Temperature + if (!m_infraredService) { + m_infraredService = m_bluetoothDevice->controller()->createServiceObject(infraredServiceUuid, this); + if (!m_infraredService) { + qCWarning(dcMultiSensor()) << "Could not create infrared service."; return; } - if (m_services.value(id)) { - qCWarning(dcMultiSensor) << "Attention! bad implementation of service handling!!"; + connect(m_infraredService, &QLowEnergyService::stateChanged, this, &SensorTag::onInfraredServiceStateChanged); + connect(m_infraredService, &QLowEnergyService::characteristicChanged, this, &SensorTag::onInfraredServiceCharacteristicChanged); + + if (m_infraredService->state() == QLowEnergyService::DiscoveryRequired) { + m_infraredService->discoverDetails(); + } + } + + // Buttons + if (!m_buttonService) { + m_buttonService = m_bluetoothDevice->controller()->createServiceObject(buttonServiceUuid, this); + if (!m_buttonService) { + qCWarning(dcMultiSensor()) << "Could not create button service."; return; } - qCDebug(dcMultiSensor) << "Setup service"; + connect(m_buttonService, &QLowEnergyService::stateChanged, this, &SensorTag::onButtonServiceStateChanged); + connect(m_buttonService, &QLowEnergyService::characteristicChanged, this, &SensorTag::onButtonServiceCharacteristicChanged); - // service for temperature - QSharedPointer service{controller()->createServiceObject(id, this)}; + if (m_buttonService->state() == QLowEnergyService::DiscoveryRequired) { + m_buttonService->discoverDetails(); + } + } - if (service.isNull()) { - qCWarning(dcMultiSensor) << "Could not create service for device" << name() << address().toString(); + // Humidity + if (!m_humidityService) { + m_humidityService = m_bluetoothDevice->controller()->createServiceObject(humidityServiceUuid, this); + if (!m_humidityService) { + qCWarning(dcMultiSensor()) << "Could not create humidity service."; return; } - m_services.insert(id, service); - - connect(service.data(), SIGNAL(error(QLowEnergyService::ServiceError)), this, SLOT(onServiceError(QLowEnergyService::ServiceError))); - connect(service.data(), &QLowEnergyService::stateChanged, this, &SensorTag::onServiceStateChanged); - connect(service.data(), &QLowEnergyService::characteristicChanged, this, &SensorTag::onServiceCharacteristicChanged); -#if (QT_VERSION >= QT_VERSION_CHECK(5, 5, 0)) - connect(service.data(), &QLowEnergyService::characteristicRead, this, &SensorTag::onServiceCharacteristicChanged); -#endif - - service->discoverDetails(); + connect(m_humidityService, &QLowEnergyService::stateChanged, this, &SensorTag::onHumidityServiceStateChanged); + connect(m_humidityService, &QLowEnergyService::characteristicChanged, this, &SensorTag::onHumidityServiceCharacteristicChanged); + if (m_humidityService->state() == QLowEnergyService::DiscoveryRequired) { + m_humidityService->discoverDetails(); + } } + + // Pressure + if (!m_pressureService) { + m_pressureService = m_bluetoothDevice->controller()->createServiceObject(pressureServiceUuid, this); + if (!m_pressureService) { + qCWarning(dcMultiSensor()) << "Could not create pressure service."; + return; + } + + connect(m_pressureService, &QLowEnergyService::stateChanged, this, &SensorTag::onPressureServiceStateChanged); + connect(m_pressureService, &QLowEnergyService::characteristicChanged, this, &SensorTag::onPressureServiceCharacteristicChanged); + if (m_pressureService->state() == QLowEnergyService::DiscoveryRequired) { + m_pressureService->discoverDetails(); + } + } + } -void SensorTag::onConnectionStatusChanged() +void SensorTag::onInfraredServiceStateChanged(const QLowEnergyService::ServiceState &state) { - if (!isConnected()) { - // delete the services, they need to be recreated and - // rediscovered once the device will be reconnected - foreach (QSharedPointer service, m_services) - service->deleteLater(); + // Only continue if discovered + if (state != QLowEnergyService::ServiceDiscovered) + return; - emit valueChanged(connectedStateTypeId, false); - } else { - emit valueChanged(connectedStateTypeId, true); + qCDebug(dcMultiSensor()) << "Infrared sensor service discovered."; + + foreach (const QLowEnergyCharacteristic &characteristic, m_infraredService->characteristics()) { + qCDebug(dcMultiSensor()) << " -->" << characteristic.name() << characteristic.uuid().toString() << characteristic.value(); + foreach (const QLowEnergyDescriptor &desciptor, characteristic.descriptors()) { + qCDebug(dcMultiSensor()) << " -->" << desciptor.name() << desciptor.uuid().toString() << desciptor.value(); + } } + + // Data characteristic + m_infraredDataCharacteristic = m_infraredService->characteristic(QBluetoothUuid(QUuid("f000aa01-0451-4000-b000-000000000000"))); + if (!m_infraredDataCharacteristic.isValid()) { + qCWarning(dcMultiSensor()) << "Invalid infrared data characteristic."; + } + + // Enable notifications + QLowEnergyDescriptor notificationDescriptor = m_infraredDataCharacteristic.descriptor(QBluetoothUuid::ClientCharacteristicConfiguration); + m_infraredService->writeDescriptor(notificationDescriptor, QByteArray::fromHex("0100")); + + + // Config characteristic + m_infraredConfigCharacteristic = m_infraredService->characteristic(QBluetoothUuid(QUuid("f000aa02-0451-4000-b000-000000000000"))); + if (!m_infraredConfigCharacteristic.isValid()) { + qCWarning(dcMultiSensor()) << "Invalid infrared configuration characteristic."; + } + + // Enable measuring + m_infraredService->writeCharacteristic(m_infraredConfigCharacteristic, QByteArray::fromHex("01")); } -void SensorTag::onServiceStateChanged(const QLowEnergyService::ServiceState &state) +void SensorTag::onInfraredServiceCharacteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &value) { - QPointer service = qobject_cast(sender()); + if (characteristic == m_infraredDataCharacteristic) { + updateInfraredValue(value); - switch (state) { - case QLowEnergyService::DiscoveringServices: - qCDebug(dcMultiSensor) << "Start discovering service" << service->serviceUuid(); - break; - case QLowEnergyService::ServiceDiscovered: - if (m_services.contains(service->serviceUuid())) { - qCDebug(dcMultiSensor) << "... service discovered."; - - auto dataId = service->serviceUuid(); - dataId.data1 += 1; - auto sensorCharacteristic = service->characteristic(dataId); - - if (!sensorCharacteristic.isValid()) { - qCWarning(dcMultiSensor) << "Characteristic not found for device " << name() << address().toString(); - break; - } - - const auto notificationDescriptor = sensorCharacteristic.descriptor( - QBluetoothUuid::ClientCharacteristicConfiguration); - - if (notificationDescriptor.isValid()) { - service->writeDescriptor(notificationDescriptor, QByteArray::fromHex("0100")); - qCDebug(dcMultiSensor) << "Measuring"; - } - - if (service->serviceUuid().data1 == 0xffe0) - break; - - auto configId = service->serviceUuid(); - configId.data1 += 2; - auto sensorConfig = service->characteristic(configId); - - if (!sensorConfig.isValid()) { - qCWarning(dcMultiSensor) << "Characteristic not found for device " << name() << address().toString(); - break; - } - - if (service->serviceUuid().data1 == 0xf000aa50) { - service->writeCharacteristic(sensorConfig, QByteArray::fromHex("07")); - } else { - service->writeCharacteristic(sensorConfig, QByteArray::fromHex("01")); - } - - if (service->serviceUuid().data1 == 0xf000aa40) { - service->writeCharacteristic(sensorConfig, QByteArray::fromHex("02")); - auto calibId = service->serviceUuid(); - calibId.data1 += 3; -#if (QT_VERSION >= QT_VERSION_CHECK(5, 5, 0)) - service->readCharacteristic(service->characteristic(calibId)); -#endif - } - - // TODO: initialize the states with the current value - - } - break; - default: - break; + // FIXME: Disable measuring + // m_infraredService->writeCharacteristic(m_infraredConfigCharacteristic, QByteArray::fromHex("00")); } } -inline quint16 buildUINT16(quint8 loByte, quint8 hiByte) { - return ((quint16)(((loByte) & 0x00FF) + (((hiByte) & 0x00FF) << 8))); -} - -void SensorTag::onServiceCharacteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &value) +void SensorTag::onButtonServiceStateChanged(const QLowEnergyService::ServiceState &state) { - qCDebug(dcMultiSensor) << "Service characteristic changed" << characteristic.uuid().toString() << value.toHex(); + // Only continue if discovered + if (state != QLowEnergyService::ServiceDiscovered) + return; - auto id = characteristic.uuid(); - id.data1 -= 1; - switch (characteristic.uuid().data1) { - case 0xf000aa01: { - const quint16 *data = reinterpret_cast(value.constData()); - qint16 rawTamb = data[1]; - m_temperatureValues.append((double)rawTamb / 128); - if (m_temperatureValues.count() % 60 == 0) { - emit valueChanged(temperatureStateTypeId, calculateMeanValue(m_temperatureValues)); - m_temperatureValues.clear(); + qCDebug(dcMultiSensor()) << "Button sensor service discovered."; + + foreach (const QLowEnergyCharacteristic &characteristic, m_buttonService->characteristics()) { + qCDebug(dcMultiSensor()) << " -->" << characteristic.name() << characteristic.uuid().toString() << characteristic.value(); + foreach (const QLowEnergyDescriptor &desciptor, characteristic.descriptors()) { + qCDebug(dcMultiSensor()) << " -->" << desciptor.name() << desciptor.uuid().toString() << desciptor.value(); } + } - qint16 Vobj2 = (double)data[0]; - Vobj2 *= 0.00000015625; - double Tdie2 = ((double)rawTamb / 128) + 273.15; - const double S0 = 6.4E-14; // Calibration factor - const double a1 = 1.75E-3; - const double a2 = -1.678E-5; - const double b0 = -2.94E-5; - const double b1 = -5.7E-7; - const double b2 = 4.63E-9; - const double c2 = 13.4; - const double Tref = 298.15; - double S = S0*(1+a1*(Tdie2 - Tref)+a2*qPow((Tdie2 - Tref),2)); - double Vos = b0 + b1*(Tdie2 - Tref) + b2*qPow((Tdie2 - Tref),2); - double fObj = (Vobj2 - Vos) + c2*qPow((Vobj2 - Vos),2); - double tObj = qPow(qPow(Tdie2,4) + (fObj/S),.25); - m_irTemperatureValues.append(tObj - 273.15); - if (m_irTemperatureValues.count() % 60 == 0) { - emit valueChanged(IRtemperatureStateTypeId, calculateMeanValue(m_irTemperatureValues)); - m_irTemperatureValues.clear(); - } + // Data characteristic + m_buttonCharacteristic = m_buttonService->characteristic(QBluetoothUuid(QUuid("0000ffe1-0000-1000-8000-00805f9b34fb"))); + if (!m_buttonCharacteristic.isValid()) { + qCWarning(dcMultiSensor()) << "Invalid button data characteristic."; + } - break; - } - case 0xf000aa11: { - // TODO: evaluate movement - - // const qint8 *data = reinterpret_cast(value.constData()); - // emit valueChanged(accelerationXStateTypeId, (double)data[0] / 64); - // emit valueChanged(accelerationYStateTypeId, (double)data[1] / 64); - // emit valueChanged(accelerationZStateTypeId, (double)data[2] / 64); - break; - } - case 0xf000aa21: { - const quint16 *data = reinterpret_cast(value.constData()); - quint16 rawH = data[1]; - rawH &= ~0x0003; - m_humidityValues.append(-6.0 + 125.0/65536 * (double)rawH); - if (m_humidityValues.count() % 60 == 0) { - emit valueChanged(humidityStateTypeId, calculateMeanValue(m_humidityValues)); - m_humidityValues.clear(); - } - break; - } - case 0xf000aa31: { - // TODO: evaluate movement - // const qint16 *data = reinterpret_cast(value.constData()); - // emit valueChanged(magneticFieldXStateTypeId, (double)data[0] / 32.768); - // emit valueChanged(magneticFieldYStateTypeId, (double)data[1] / 32.768); - // emit valueChanged(magneticFieldZStateTypeId, (double)data[2] / 32.768); - break; - } - case 0xf000aa41: { - if (m_c.empty()) - break; - const quint16 *data = reinterpret_cast(value.constData()); - quint16 Pr = data[1]; - qint16 Tr = data[0]; - // Sensitivity - qint64 s = (qint64)m_c[2]; - qint64 val = (qint64)m_c[3] * Tr; - s += (val >> 17); - val = (qint64)m_c2[0] * Tr * Tr; - s += (val >> 34); - // Offset - qint64 o = (qint64)m_c2[1] << 14; - val = (qint64)m_c2[2] * Tr; - o += (val >> 3); - val = (qint64)m_c2[3] * Tr * Tr; - o += (val >> 19); - // Pressure (Pa) - qint64 pres = ((qint64)(s * Pr) + o) >> 14; - m_pressureValues.append((double)pres/100); - if (m_pressureValues.count() % 60 == 0) { - emit valueChanged(pressureStateTypeId, calculateMeanValue(m_pressureValues)); - m_pressureValues.clear(); - } - - break; - } - case 0xf000aa43: { - const quint8 *data = reinterpret_cast(value.constData()); - m_c.resize(4); - m_c2.resize(4); - m_c[0] = buildUINT16(data[0],data[1]); - m_c[1] = buildUINT16(data[2],data[3]); - m_c[2] = buildUINT16(data[4],data[5]); - m_c[3] = buildUINT16(data[6],data[7]); - m_c2[0] = buildUINT16(data[8],data[9]); - m_c2[1] = buildUINT16(data[10],data[11]); - m_c2[2] = buildUINT16(data[12],data[13]); - m_c2[3] = buildUINT16(data[14],data[15]); - break; - } - case 0xf000aa51: { - // TODO: evaluate movement - // const qint16 *data = reinterpret_cast(value.constData()); - // emit valueChanged(rotationXStateTypeId, (double)data[0] / 131.072); - // emit valueChanged(rotationYStateTypeId, (double)data[1] / 131.072); - // emit valueChanged(rotationZStateTypeId, (double)data[2] / 131.072); - break; - } - case 0xffe1: { - const quint8 *data = reinterpret_cast(value.constData()); - if (*data & 1) - emit event(leftKeyEventTypeId); - if (*data & 2) - emit event(rightKeyEventTypeId); - break; - } - default: - break; - } + // Enable notifications + QLowEnergyDescriptor notificationDescriptor = m_buttonCharacteristic.descriptor(QBluetoothUuid::ClientCharacteristicConfiguration); + m_buttonService->writeDescriptor(notificationDescriptor, QByteArray::fromHex("0100")); } -void SensorTag::onServiceError(const QLowEnergyService::ServiceError &error) +void SensorTag::onButtonServiceCharacteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &value) { - QString errorString; - switch (error) { - case QLowEnergyService::NoError: - errorString = "No error"; - break; - case QLowEnergyService::OperationError: - errorString = "Operation error"; - break; -#if (QT_VERSION >= QT_VERSION_CHECK(5, 5, 0)) - case QLowEnergyService::CharacteristicReadError: - errorString = "Characteristic read error"; - break; -#endif - case QLowEnergyService::CharacteristicWriteError: - errorString = "Characteristic write error"; - break; -#if (QT_VERSION >= QT_VERSION_CHECK(5, 5, 0)) - case QLowEnergyService::DescriptorReadError: - errorString = "Descriptor read error"; - break; -#endif - case QLowEnergyService::DescriptorWriteError: - errorString = "Descriptor write error"; - break; -#if (QT_VERSION >= QT_VERSION_CHECK(5, 5, 0)) - case QLowEnergyService::UnknownError: - errorString = "Unknown error"; - break; -#endif - default: - errorString = "Unknown error"; - break; + if (characteristic == m_buttonCharacteristic) { + updateButtonValue(value); } - - - qCWarning(dcMultiSensor) << "Service of " << name() << address().toString() << ":" << errorString; } -#endif // BLUETOOTH_LE +void SensorTag::onHumidityServiceStateChanged(const QLowEnergyService::ServiceState &state) +{ + // Only continue if discovered + if (state != QLowEnergyService::ServiceDiscovered) + return; + + qCDebug(dcMultiSensor()) << "Humidity sensor service discovered."; + + foreach (const QLowEnergyCharacteristic &characteristic, m_humidityService->characteristics()) { + qCDebug(dcMultiSensor()) << " -->" << characteristic.name() << characteristic.uuid().toString() << characteristic.value(); + foreach (const QLowEnergyDescriptor &desciptor, characteristic.descriptors()) { + qCDebug(dcMultiSensor()) << " -->" << desciptor.name() << desciptor.uuid().toString() << desciptor.value(); + } + } + + // Data characteristic + m_humidityDataCharacteristic = m_humidityService->characteristic(QBluetoothUuid(QUuid("f000aa21-0451-4000-b000-000000000000"))); + if (!m_humidityDataCharacteristic.isValid()) { + qCWarning(dcMultiSensor()) << "Invalid humidity data characteristic."; + } + + // Enable notifications + QLowEnergyDescriptor notificationDescriptor = m_humidityDataCharacteristic.descriptor(QBluetoothUuid::ClientCharacteristicConfiguration); + m_humidityService->writeDescriptor(notificationDescriptor, QByteArray::fromHex("0100")); + + // Config characteristic + m_humidityConfigCharacteristic = m_humidityService->characteristic(QBluetoothUuid(QUuid("f000aa22-0451-4000-b000-000000000000"))); + if (!m_humidityConfigCharacteristic.isValid()) { + qCWarning(dcMultiSensor()) << "Invalid humidity configuration characteristic."; + } + + // Enable measuring + m_humidityService->writeCharacteristic(m_humidityConfigCharacteristic, QByteArray::fromHex("01")); +} + +void SensorTag::onHumidityServiceCharacteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &value) +{ + if (characteristic == m_humidityDataCharacteristic) { + updateHumidityValue(value); + // FIXME: Disable measuring + // m_humidityService->writeCharacteristic(m_humidityConfigCharacteristic, QByteArray::fromHex("00")); + } +} + +void SensorTag::onPressureServiceStateChanged(const QLowEnergyService::ServiceState &state) +{ + // Only continue if discovered + if (state != QLowEnergyService::ServiceDiscovered) + return; + + qCDebug(dcMultiSensor()) << "Pressure sensor service discovered."; + + foreach (const QLowEnergyCharacteristic &characteristic, m_pressureService->characteristics()) { + qCDebug(dcMultiSensor()) << " -->" << characteristic.name() << characteristic.uuid().toString() << characteristic.value(); + foreach (const QLowEnergyDescriptor &desciptor, characteristic.descriptors()) { + qCDebug(dcMultiSensor()) << " -->" << desciptor.name() << desciptor.uuid().toString() << desciptor.value(); + } + } + + // Data characteristic + m_pressureDataCharacteristic = m_pressureService->characteristic(QBluetoothUuid(QUuid("f000aa41-0451-4000-b000-000000000000"))); + if (!m_pressureDataCharacteristic.isValid()) { + qCWarning(dcMultiSensor()) << "Invalid pressure data characteristic."; + } + + // Enable notifications + QLowEnergyDescriptor notificationDescriptor = m_pressureDataCharacteristic.descriptor(QBluetoothUuid::ClientCharacteristicConfiguration); + m_pressureService->writeDescriptor(notificationDescriptor, QByteArray::fromHex("0100")); + + // Config characteristic + m_pressureConfigCharacteristic = m_pressureService->characteristic(QBluetoothUuid(QUuid("f000aa42-0451-4000-b000-000000000000"))); + if (!m_pressureConfigCharacteristic.isValid()) { + qCWarning(dcMultiSensor()) << "Invalid pressure configuration characteristic."; + } + + // Enable measuring + m_pressureService->writeCharacteristic(m_pressureConfigCharacteristic, QByteArray::fromHex("01")); +} + +void SensorTag::onPressureServiceCharacteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &value) +{ + if (characteristic == m_pressureDataCharacteristic) { + updatePressureValue(value); + // FIXME: Disable measuring + // m_pressureService->writeCharacteristic(m_pressureConfigCharacteristic, QByteArray::fromHex("00")); + } +} + +void SensorTag::measure() +{ + if (!m_bluetoothDevice->connected()) + return; + +// qCDebug(dcMultiSensor()) << "Measure data" << m_bluetoothDevice->name() << m_bluetoothDevice->address().toString(); + +// m_infraredService->writeCharacteristic(m_infraredConfigCharacteristic, QByteArray::fromHex("01")); +// m_humidityService->writeCharacteristic(m_humidityConfigCharacteristic, QByteArray::fromHex("01")); +// m_pressureService->writeCharacteristic(m_pressureConfigCharacteristic, QByteArray::fromHex("01")); + +} + diff --git a/multisensor/sensortag.h b/multisensor/sensortag.h index 4c7bb9ec..98556753 100644 --- a/multisensor/sensortag.h +++ b/multisensor/sensortag.h @@ -1,79 +1,88 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * * - * Copyright (C) 2015 Simon Stürz * - * Copyright (C) 2016 nicc * - * * - * This file is part of guh. * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; If not, see * - * . * - * * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - #ifndef SENSORTAG_H #define SENSORTAG_H -#ifdef BLUETOOTH_LE +#include -#include -#include -#include -#include - -#include "bluetooth/bluetoothlowenergydevice.h" +#include "plugin/device.h" #include "extern-plugininfo.h" +#include "bluetooth/bluetoothlowenergydevice.h" -class SensorTag : public BluetoothLowEnergyDevice +static QBluetoothUuid infraredServiceUuid = QBluetoothUuid(QUuid("f000aa00-0451-4000-b000-000000000000")); +static QBluetoothUuid accelerometerServiceUuid = QBluetoothUuid(QUuid("f000aa10-0451-4000-b000-000000000000")); +static QBluetoothUuid humidityServiceUuid = QBluetoothUuid(QUuid("f000aa20-0451-4000-b000-000000000000")); +static QBluetoothUuid magnetometerServiceUuid = QBluetoothUuid(QUuid("f000aa30-0451-4000-b000-000000000000")); +static QBluetoothUuid pressureServiceUuid = QBluetoothUuid(QUuid("f000aa40-0451-4000-b000-000000000000")); +static QBluetoothUuid gyroscopeServiceUuid = QBluetoothUuid(QUuid("f000aa50-0451-4000-b000-000000000000")); +static QBluetoothUuid testServiceUuid = QBluetoothUuid(QUuid("f000aa60-0451-4000-b000-000000000000")); +static QBluetoothUuid otaServiceUuid = QBluetoothUuid(QUuid("f000aac0-0451-4000-b000-000000000000")); +static QBluetoothUuid buttonServiceUuid = QBluetoothUuid(QUuid("0000ffe0-0000-1000-8000-00805f9b34fb")); + +// Currently unused services + +class SensorTag : public QObject { Q_OBJECT public: - explicit SensorTag(const QBluetoothDeviceInfo &deviceInfo, const QLowEnergyController::RemoteAddressType &addressType, QObject *parent = 0); + explicit SensorTag(Device *device, BluetoothLowEnergyDevice *bluetoothDevice, QObject *parent = nullptr); -signals: - void valueChanged(StateTypeId state, QVariant value); - void event(EventTypeId event); + Device *device(); + BluetoothLowEnergyDevice *bluetoothDevice(); private: - QHash> m_services{ - {QBluetoothUuid(QUuid("f000aa00-0451-4000-b000-000000000000")), QSharedPointer()}, - {QBluetoothUuid(QUuid("f000aa10-0451-4000-b000-000000000000")), QSharedPointer()}, - {QBluetoothUuid(QUuid("f000aa20-0451-4000-b000-000000000000")), QSharedPointer()}, - {QBluetoothUuid(QUuid("f000aa30-0451-4000-b000-000000000000")), QSharedPointer()}, - {QBluetoothUuid(QUuid("f000aa40-0451-4000-b000-000000000000")), QSharedPointer()}, - {QBluetoothUuid(QUuid("f000aa50-0451-4000-b000-000000000000")), QSharedPointer()}, - {QBluetoothUuid(QUuid("0000ffe0-0000-1000-8000-00805f9b34fb")), QSharedPointer()} - }; + Device *m_device; + BluetoothLowEnergyDevice *m_bluetoothDevice; - QVector m_c; - QVector m_c2; + // Services + QLowEnergyService *m_infraredService = nullptr; + QLowEnergyService *m_buttonService = nullptr; + QLowEnergyService *m_humidityService = nullptr; + QLowEnergyService *m_pressureService = nullptr; + QLowEnergyService *m_accelerometerService = nullptr; + QLowEnergyService *m_magnetometerService = nullptr; + QLowEnergyService *m_gyroscopeService = nullptr; - QList m_temperatureValues; - QList m_irTemperatureValues; - QList m_humidityValues; - QList m_pressureValues; + // Characteristics + QLowEnergyCharacteristic m_infraredDataCharacteristic; + QLowEnergyCharacteristic m_infraredConfigCharacteristic; + QLowEnergyCharacteristic m_buttonCharacteristic; + QLowEnergyCharacteristic m_humidityDataCharacteristic; + QLowEnergyCharacteristic m_humidityConfigCharacteristic; + QLowEnergyCharacteristic m_pressureDataCharacteristic; + QLowEnergyCharacteristic m_pressureConfigCharacteristic; - double calculateMeanValue(const QList &list); + + void updateInfraredValue(const QByteArray &value); + void updateButtonValue(const QByteArray &value); + void updateHumidityValue(const QByteArray &value); + void updatePressureValue(const QByteArray &value); + +signals: + void leftKeyPressed(); + void rightKeyPressed(); private slots: - void setupServices(); - void onConnectionStatusChanged(); + void onConnectedChanged(const bool &connected); + void onServiceDiscoveryFinished(); - // Service - void onServiceStateChanged(const QLowEnergyService::ServiceState &state); - void onServiceCharacteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &value); - void onServiceError(const QLowEnergyService::ServiceError &error); + // Infrared sensor service + void onInfraredServiceStateChanged(const QLowEnergyService::ServiceState &state); + void onInfraredServiceCharacteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &value); + + // Button service + void onButtonServiceStateChanged(const QLowEnergyService::ServiceState &state); + void onButtonServiceCharacteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &value); + + // Humidity sensor service + void onHumidityServiceStateChanged(const QLowEnergyService::ServiceState &state); + void onHumidityServiceCharacteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &value); + + // Pressure sensor service + void onPressureServiceStateChanged(const QLowEnergyService::ServiceState &state); + void onPressureServiceCharacteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &value); + + +public slots: + void measure(); }; -#endif // BLUETOOTH_LE #endif // SENSORTAG_H diff --git a/plugins.pri b/plugins.pri index f726b786..7d54a109 100644 --- a/plugins.pri +++ b/plugins.pri @@ -1,7 +1,7 @@ TEMPLATE = lib CONFIG += plugin -QT += network bluetooth +QT += network bluetooth dbus QMAKE_CXXFLAGS += -Werror -std=c++11 -g QMAKE_LFLAGS += -std=c++11