From 0479ecb0bb790157fd01f61a113c92f9c718adbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Thu, 22 Feb 2018 23:24:43 +0100 Subject: [PATCH] Add first version of new sensor tag --- multisensor/devicepluginmultisensor.cpp | 31 +- multisensor/devicepluginmultisensor.h | 9 +- multisensor/devicepluginmultisensor.json | 155 ++++-- multisensor/sensortag.cpp | 639 ++++++++++++++++++----- multisensor/sensortag.h | 167 ++++-- 5 files changed, 779 insertions(+), 222 deletions(-) diff --git a/multisensor/devicepluginmultisensor.cpp b/multisensor/devicepluginmultisensor.cpp index fb362375..e1e9aadb 100644 --- a/multisensor/devicepluginmultisensor.cpp +++ b/multisensor/devicepluginmultisensor.cpp @@ -1,6 +1,6 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Copyright (C) 2015 Simon Stuerz * + * Copyright (C) 2015-2018 Simon Stuerz * * Copyright (C) 2016 nicc * * * * This file is part of nymea. * @@ -52,10 +52,15 @@ DevicePluginMultiSensor::DevicePluginMultiSensor() } +DevicePluginMultiSensor::~DevicePluginMultiSensor() +{ + hardwareManager()->pluginTimerManager()->unregisterTimer(m_reconnectTimer); +} + void DevicePluginMultiSensor::init() { - m_measureTimer = hardwareManager()->pluginTimerManager()->registerTimer(60); - connect(m_measureTimer, &PluginTimer::timeout, this, &DevicePluginMultiSensor::onPluginTimer); + m_reconnectTimer = hardwareManager()->pluginTimerManager()->registerTimer(10); + connect(m_reconnectTimer, &PluginTimer::timeout, this, &DevicePluginMultiSensor::onPluginTimer); } DeviceManager::DeviceError DevicePluginMultiSensor::discoverDevices(const DeviceClassId &deviceClassId, const ParamList ¶ms) @@ -89,8 +94,6 @@ DeviceManager::DeviceSetupStatus DevicePluginMultiSensor::setupDevice(Device *de 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(); @@ -124,23 +127,13 @@ bool DevicePluginMultiSensor::verifyExistingDevices(const QBluetoothDeviceInfo & void DevicePluginMultiSensor::onPluginTimer() { - foreach (SensorTag *sensor, m_sensors) { - sensor->measure(); + foreach (SensorTag *sensor, m_sensors.values()) { + if (!sensor->bluetoothDevice()->connected()) { + sensor->bluetoothDevice()->connectDevice(); + } } } -void DevicePluginMultiSensor::onSensorLeftButtonPressed() -{ - SensorTag *sensor = static_cast(sender()); - emit emitEvent(Event(sensortagLeftKeyEventTypeId, sensor->device()->id())); -} - -void DevicePluginMultiSensor::onSensorRightButtonPressed() -{ - SensorTag *sensor = static_cast(sender()); - emit emitEvent(Event(sensortagRightKeyEventTypeId, sensor->device()->id())); -} - void DevicePluginMultiSensor::onBluetoothDiscoveryFinished() { BluetoothDiscoveryReply *reply = static_cast(sender()); diff --git a/multisensor/devicepluginmultisensor.h b/multisensor/devicepluginmultisensor.h index 0731b207..22206770 100644 --- a/multisensor/devicepluginmultisensor.h +++ b/multisensor/devicepluginmultisensor.h @@ -1,6 +1,6 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Copyright (C) 2015 Simon Stuerz * + * Copyright (C) 2015-2018 Simon Stuerz * * Copyright (C) 2016 nicc * * * * This file is part of nymea. * @@ -41,6 +41,7 @@ class DevicePluginMultiSensor : public DevicePlugin public: explicit DevicePluginMultiSensor(); + ~DevicePluginMultiSensor(); void init() override; DeviceManager::DeviceError discoverDevices(const DeviceClassId &deviceClassId, const ParamList ¶ms) override; @@ -48,17 +49,13 @@ public: void deviceRemoved(Device *device) override; private: - PluginTimer *m_measureTimer = nullptr; + PluginTimer *m_reconnectTimer = nullptr; QHash m_sensors; bool verifyExistingDevices(const QBluetoothDeviceInfo &deviceInfo); private slots: void onPluginTimer(); - - void onSensorLeftButtonPressed(); - void onSensorRightButtonPressed(); - void onBluetoothDiscoveryFinished(); }; diff --git a/multisensor/devicepluginmultisensor.json b/multisensor/devicepluginmultisensor.json index 93711f0f..f71831a8 100644 --- a/multisensor/devicepluginmultisensor.json +++ b/multisensor/devicepluginmultisensor.json @@ -2,6 +2,47 @@ "displayName": "MultiSensor", "name": "MultiSensor", "id": "23bf0d8d-df7d-4bee-80ee-f015c5a7f52e", + "paramTypes": [ + { + "id": "5786c91a-d94d-461a-8d22-f978dd1438ab", + "name": "accelerometerEnabled", + "displayName": "Accelerometer enabled", + "type": "bool", + "defaultValue": true + }, + { + "id": "94517544-cb97-4816-8993-cb4cf2651a1e", + "name": "gyroscopeEnabled", + "displayName": "Gyroscope enabled", + "type": "bool", + "defaultValue": false + }, + { + "id": "96aae111-b1c1-48a1-9b1f-b56efa546d0d", + "name": "magnetometerEnabled", + "displayName": "Magnetometer enabled", + "type": "bool", + "defaultValue": false + }, + { + "id": "5237c89c-c21d-4d78-ac99-8be661b40da7", + "name": "measurementPeriodMovement", + "displayName": "Measurement period movement sensor", + "type": "int", + "minValue": 10, + "maxValue": 2500, + "defaultValue": 2000 + }, + { + "id": "c5308565-5dc9-409e-ae99-577c212c7a92", + "name": "measurementPeriod", + "displayName": "Measurement period for enviromental sensors", + "type": "int", + "minValue": 10, + "maxValue": 2500, + "defaultValue": 500 + } + ], "vendors": [ { "id": "2edf543e-dc2c-4693-bb0c-e76c0d305fad", @@ -9,12 +50,12 @@ "displayName": "Texas Instruments", "deviceClasses": [ { - "displayName": "Sensor Tag", - "name": "sensortag", "id": "158a06b6-b27f-4951-957e-6f1e3b44f604", + "name": "sensortag", + "displayName": "Sensor Tag (CC2650)", "createMethods": ["discovery"], "deviceIcon": "Thermometer", - "criticalStateTypeId": "a9629b11-0f34-47f0-a0f0-f758a6aec2b4", + "interfaces": ["connectable", "humiditysensor", "temperaturesensor"], "basicTags": [ "Device", "Sensor" @@ -23,14 +64,14 @@ { "id": "bdb9d684-2f98-45f5-889c-f184c1e73dc7", "name": "name", - "displayName": "name", + "displayName": "Name", "type": "QString", "inputType": "TextLine" }, { "id": "d51ed68e-c84a-4136-a5b5-be2f95fd5a0f", "name": "mac", - "displayName": "mac address", + "displayName": "MAC address", "type": "QString", "inputType": "MacAddress" } @@ -39,29 +80,12 @@ { "id": "a9629b11-0f34-47f0-a0f0-f758a6aec2b4", "name": "connected", - "displayName": "connected", - "displayNameEvent": "connected changed", + "displayName": "Connected", + "displayNameEvent": "Connected changed", "type": "bool", + "cached": false, "defaultValue": false }, - { - "id": "c664e9ec-a045-49ba-add1-1642ceba7c4f", - "name": "IRtemperature", - "displayName": "IR temperature", - "displayNameEvent": "IR temperature changed", - "type": "double", - "unit": "DegreeCelsius", - "defaultValue": 0 - }, - { - "id": "e83a50ff-96c9-4b6d-889f-f4238353e794", - "name": "humidity", - "displayName": "humidity", - "displayNameEvent": "humidity changed", - "type": "double", - "unit": "Percentage", - "defaultValue": 0 - }, { "id": "8359ada9-df1c-4e60-bb87-9e21d05ee2e2", "name": "temperature", @@ -71,34 +95,79 @@ "unit": "DegreeCelsius", "defaultValue": 0 }, + { + "id": "c664e9ec-a045-49ba-add1-1642ceba7c4f", + "name": "objectTemperature", + "displayName": "Object temperature", + "displayNameEvent": "Object temperature changed", + "type": "double", + "unit": "DegreeCelsius", + "defaultValue": 0 + }, + { + "id": "e83a50ff-96c9-4b6d-889f-f4238353e794", + "name": "humidity", + "displayName": "Humidity", + "displayNameEvent": "Humidity changed", + "type": "double", + "minValue": 0, + "maxValue": 100, + "unit": "Percentage", + "defaultValue": 0 + }, { "id": "645633ad-77d4-45b2-8be8-d6ca7a12eb7a", "name": "pressure", - "displayName": "pressure", - "displayNameEvent": "pressure changed", + "displayName": "Barometric pressure", + "displayNameEvent": "Barometric pressure changed", "type": "double", "unit": "HectoPascal", "defaultValue": 0 }, { - "id": "4be5ca26-0565-419d-b18b-2a5a385d2a3d", - "name": "moving", - "displayName": "moving", - "displayNameEvent": "moving changed", - "type": "bool", - "defaultValue": false - } - ], - "eventTypes": [ - { - "id": "61478490-bed0-4fed-9d58-f13c35b4f220", - "name": "leftKey", - "displayName": "left key pressed" + "id": "6635dce4-2d8d-4608-a836-768c3014f356", + "name": "lightIntensity", + "displayName": "Light intensity", + "displayNameEvent": "Light intensity changed", + "type": "double", + "unit": "Lux", + "defaultValue": 0 }, { - "id": "b7e927db-af28-4fdc-8eb7-edb02258ff5a", - "name": "rightKey", - "displayName": "right key pressed" + "id": "4be5ca26-0565-419d-b18b-2a5a385d2a3d", + "name": "moving", + "displayName": "Moving", + "displayNameEvent": "Moving changed", + "type": "bool", + "cached": false, + "defaultValue": false + }, + { + "id": "758d9b39-7390-40f5-8e19-d8b0f4a0a0c6", + "name": "magnetDetected", + "displayName": "Magnet detected", + "displayNameEvent": "Magnet detected changed", + "type": "bool", + "cached": false, + "defaultValue": false + }, + { + "id": "8995e49e-ca2d-4dd9-a22f-de6c566c2115", + "name": "leftButtonPressed", + "displayName": "Left button pressed", + "displayNameEvent": "Left button pressed changed", + "type": "bool", + "cached": false, + "defaultValue": false + }, + { + "id": "ef8eedc5-6a45-4dfb-bb55-ada1a931b20b", + "name": "rightButtonPressed", + "displayName": "Right button pressed", + "displayNameEvent": "Right button pressed changed", + "type": "bool", + "cached": false, + "defaultValue": false } ] } diff --git a/multisensor/sensortag.cpp b/multisensor/sensortag.cpp index 6d261e7b..8e331e4e 100644 --- a/multisensor/sensortag.cpp +++ b/multisensor/sensortag.cpp @@ -1,6 +1,30 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * * + * Copyright (C) 2015-2018 Simon Stuerz * + * * + * 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 * + * . * + * * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + #include "sensortag.h" #include "extern-plugininfo.h" +#include + SensorTag::SensorTag(Device *device, BluetoothLowEnergyDevice *bluetoothDevice, QObject *parent) : QObject(parent), m_device(device), @@ -20,28 +44,212 @@ BluetoothLowEnergyDevice *SensorTag::bluetoothDevice() return m_bluetoothDevice; } -void SensorTag::updateInfraredValue(const QByteArray &value) +void SensorTag::setAccelerometerEnabled(bool enabled) { - qCDebug(dcMultiSensor()) << "Infrared value" << value; + m_accelerometerEnabled = enabled; } -void SensorTag::updateButtonValue(const QByteArray &value) +void SensorTag::configurePeriod(QLowEnergyService *serice, const QLowEnergyCharacteristic &characteristic, int measurementPeriod) { - const quint8 *data = reinterpret_cast(value.constData()); - if (*data & 1) - emit leftKeyPressed(); - if (*data & 2) - emit rightKeyPressed(); + Q_ASSERT(measurementPeriod % 10 == 0); + QByteArray payload; + QDataStream stream(&payload, QIODevice::WriteOnly); + stream << static_cast(measurementPeriod / 10); + + qCDebug(dcMultiSensor()) << "Configure period to" << measurementPeriod << payload.toHex(); + serice->writeCharacteristic(characteristic, payload); } -void SensorTag::updateHumidityValue(const QByteArray &value) +void SensorTag::configureMovement(bool gyroscopeEnabled, bool accelerometerEnabled, bool magnetometerEnabled, bool wakeOnMotion) { - qCDebug(dcMultiSensor()) << "Humidity value" << value; + if (!m_movementService || !m_movementConfigurationCharacteristic.isValid()) + return; + + quint16 configuration = 0; + if (gyroscopeEnabled) { + configuration |= (1 << 0); // enable x-axis + configuration |= (1 << 1); // enable y-axis + configuration |= (1 << 2); // enable z-axis + } + + if (accelerometerEnabled) { + configuration |= (1 << 3); // enable x-axis + configuration |= (1 << 4); // enable y-axis + configuration |= (1 << 5); // enable z-axis + } + + if (magnetometerEnabled) { + configuration |= (1 << 6); // enable all axis + } + + if (wakeOnMotion) { + configuration |= (1 << 8); // enable + } + + // Accelerometer 2 Bit ( 0 = 2G, 1 = 4G, 2 = 8G, 3 = 16G) + // Default 0 + + QByteArray data; + QDataStream stream(&data, QIODevice::WriteOnly); + stream.setByteOrder(QDataStream::BigEndian); + stream << configuration; + + qCDebug(dcMultiSensor()) << "Configure movement sensor" << data.toHex(); + m_movementService->writeCharacteristic(m_movementConfigurationCharacteristic, data); } -void SensorTag::updatePressureValue(const QByteArray &value) +void SensorTag::processTemperatureData(const QByteArray &data) { - qCDebug(dcMultiSensor()) << "Pressure value" << value; + Q_ASSERT(data.count() == 4); + + quint16 rawObjectTemperature = 0; + quint16 rawAmbientTemperature = 0; + + QByteArray payload(data); + QDataStream stream(&payload, QIODevice::ReadOnly); + stream.setByteOrder(QDataStream::LittleEndian); + stream >> rawObjectTemperature >> rawAmbientTemperature ; + + float scaleFactor = 0.03125; + float objectTemperature = static_cast(rawObjectTemperature) / 4 * scaleFactor; + float ambientTemperature = static_cast(rawAmbientTemperature) / 4 * scaleFactor; + + //qCDebug(dcMultiSensor()) << "Temperature value" << data.toHex(); + //qCDebug(dcMultiSensor()) << "Object temperature" << roundValue(objectTemperature) << "°C"; + //qCDebug(dcMultiSensor()) << "Ambient temperature" << roundValue(ambientTemperature) << "°C"; + + m_device->setStateValue(sensortagObjectTemperatureStateTypeId, roundValue(objectTemperature)); + m_device->setStateValue(sensortagTemperatureStateTypeId, roundValue(ambientTemperature)); +} + +void SensorTag::processKeyData(const QByteArray &data) +{ + Q_ASSERT(data.count() == 1); + quint8 flags = static_cast(data.at(0)); + setLeftButtonPressed(testBitUint8(flags, 0)); + setRightButtonPressed(testBitUint8(flags, 1)); + setMagnetDetected(!testBitUint8(flags, 2)); +} + +void SensorTag::processHumidityData(const QByteArray &data) +{ + Q_ASSERT(data.count() == 4); + quint16 rawHumidityTemperature = 0; + quint16 rawHumidity = 0; + + QByteArray payload(data); + QDataStream stream(&payload, QIODevice::ReadOnly); + stream.setByteOrder(QDataStream::LittleEndian); + stream >> rawHumidityTemperature >> rawHumidity ; + + //double humidityTemperature = (rawHumidityTemperature / 65536.0 * 165.0) - 40; + double humidity = rawHumidity / 65536.0 * 100.0; + + //qCDebug(dcMultiSensor()) << "Humidity" << humidity << "%" << humidityTemperature << "°C"; + m_device->setStateValue(sensortagHumidityStateTypeId, roundValue(humidity)); +} + +void SensorTag::processPressureData(const QByteArray &data) +{ + Q_ASSERT(data.count() == 6); + + QByteArray pressureData(data.right(3)); + quint32 rawPressure = static_cast(pressureData.at(2)); + rawPressure <<= 8; + rawPressure |= static_cast(pressureData.at(1)); + rawPressure <<= 8; + rawPressure |= static_cast(pressureData.at(0)); + + //qCDebug(dcMultiSensor()) << "Pressure:" << roundValue(rawPressure / 100.0) << "mBar"; + m_device->setStateValue(sensortagPressureStateTypeId, roundValue(rawPressure / 100.0)); +} + +void SensorTag::processOpticalData(const QByteArray &data) +{ + Q_ASSERT(data.count() == 2); + + quint16 rawOptical = 0; + QByteArray payload(data); + QDataStream stream(&payload, QIODevice::ReadOnly); + stream.setByteOrder(QDataStream::LittleEndian); + stream >> rawOptical; + + quint16 lumm = rawOptical & 0x0FFF; + quint16 lume = (rawOptical & 0xF000) >> 12; + + double lux = lumm * (0.01 * pow(2,lume)); + + //qCDebug(dcMultiSensor()) << "Lux:" << lux; + device()->setStateValue(sensortagLightIntensityStateTypeId, roundValue(lux)); +} + +void SensorTag::processMovementData(const QByteArray &data) +{ + qCDebug(dcMultiSensor()) << "Movement value" << data.toHex(); + + QByteArray payload(data); + QDataStream stream(&payload, QIODevice::ReadOnly); + + qint16 gyroXRaw = 0; qint16 gyroYRaw = 0; qint16 gyroZRaw = 0; + stream >> gyroXRaw >> gyroYRaw >> gyroZRaw; + + qint16 accXRaw = 0; qint16 accYRaw = 0; qint16 accZRaw = 0; + stream >> accXRaw >> accYRaw >> accZRaw; + + qint16 magXRaw = 0; qint16 magYRaw = 0; qint16 magZRaw = 0; + stream >> magXRaw >> magYRaw >> magZRaw; + + + // Calculate rotation, unit deg/s, range -250, +250 + double gyroX = static_cast(gyroXRaw) / (65536 / 500); + double gyroY = static_cast(gyroYRaw) / (65536 / 500); + double gyroZ = static_cast(gyroZRaw) / (65536 / 500); + qCDebug(dcMultiSensor()) << "Gyroscope x:" << gyroX << " y:" << gyroY << " z:" << gyroZ; + +} + +void SensorTag::setLeftButtonPressed(bool pressed) +{ + if (m_leftButtonPressed == pressed) + return; + + qCDebug(dcMultiSensor()) << "Left button" << (pressed ? "pressed" : "released"); + m_leftButtonPressed = pressed; + emit leftButtonPressedChainged(m_leftButtonPressed); + m_device->setStateValue(sensortagLeftButtonPressedStateTypeId, m_leftButtonPressed); +} + +void SensorTag::setRightButtonPressed(bool pressed) +{ + if (m_rightButtonPressed == pressed) + return; + + qCDebug(dcMultiSensor()) << "Right button" << (pressed ? "pressed" : "released"); + m_rightButtonPressed = pressed; + emit rightButtonPressedChainged(m_rightButtonPressed); + m_device->setStateValue(sensortagRightButtonPressedStateTypeId, m_rightButtonPressed); +} + +void SensorTag::setMagnetDetected(bool detected) +{ + if (m_magnetDetected == detected) + return; + + qCDebug(dcMultiSensor()) << "Magnet detector" << (detected ? "active" : "inactive"); + m_magnetDetected = detected; + emit magnetDetectedChainged(m_magnetDetected); + m_device->setStateValue(sensortagMagnetDetectedStateTypeId, m_magnetDetected); +} + +bool SensorTag::testBitUint8(quint8 value, int bitPosition) +{ + return (((value)>> (bitPosition)) & 1); +} + +double SensorTag::roundValue(float value) +{ + int tmpValue = static_cast(value * 10); + return static_cast(tmpValue) / 10.0; } void SensorTag::onConnectedChanged(const bool &connected) @@ -51,80 +259,79 @@ void SensorTag::onConnectedChanged(const bool &connected) if (!connected) { // Clean up services - m_infraredService->deleteLater(); - m_buttonService->deleteLater(); + m_temperatureService->deleteLater(); m_humidityService->deleteLater(); m_pressureService->deleteLater(); + m_opticalService->deleteLater(); + m_keyService->deleteLater(); + m_movementService->deleteLater(); - m_infraredService = nullptr; - m_buttonService = nullptr; + m_temperatureService = nullptr; m_humidityService = nullptr; m_pressureService = nullptr; + m_opticalService = nullptr; + m_keyService = nullptr; + m_movementService = nullptr; } - } void SensorTag::onServiceDiscoveryFinished() { - if (!m_bluetoothDevice->serviceUuids().contains(infraredServiceUuid)) { - qCWarning(dcMultiSensor()) << "Could not find infrared service"; - return; + foreach (const QBluetoothUuid serviceUuid, m_bluetoothDevice->serviceUuids()) { + qCDebug(dcMultiSensor()) << "-->" << serviceUuid; } - if (!m_bluetoothDevice->serviceUuids().contains(accelerometerServiceUuid)) { - qCWarning(dcMultiSensor()) << "Could not find accelereometer service"; + if (!m_bluetoothDevice->serviceUuids().contains(temperatureServiceUuid)) { + qCWarning(dcMultiSensor()) << "Could not find temperature service"; + m_bluetoothDevice->disconnectDevice(); 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"; + m_bluetoothDevice->disconnectDevice(); return; } if (!m_bluetoothDevice->serviceUuids().contains(pressureServiceUuid)) { qCWarning(dcMultiSensor()) << "Could not find pressure service"; + m_bluetoothDevice->disconnectDevice(); return; } - if (!m_bluetoothDevice->serviceUuids().contains(gyroscopeServiceUuid)) { - qCWarning(dcMultiSensor()) << "Could not find magnetometer service"; + if (!m_bluetoothDevice->serviceUuids().contains(opticalServiceUuid)) { + qCWarning(dcMultiSensor()) << "Could not find optical service"; + m_bluetoothDevice->disconnectDevice(); return; } + if (!m_bluetoothDevice->serviceUuids().contains(keyServiceUuid)) { + qCWarning(dcMultiSensor()) << "Could not find key service"; + m_bluetoothDevice->disconnectDevice(); + return; + } + + if (!m_bluetoothDevice->serviceUuids().contains(movementServiceUuid)) { + qCWarning(dcMultiSensor()) << "Could not find movement service"; + m_bluetoothDevice->disconnectDevice(); + return; + } + + // IR Temperature - if (!m_infraredService) { - m_infraredService = m_bluetoothDevice->controller()->createServiceObject(infraredServiceUuid, this); - if (!m_infraredService) { - qCWarning(dcMultiSensor()) << "Could not create infrared service."; + if (!m_temperatureService) { + m_temperatureService = m_bluetoothDevice->controller()->createServiceObject(temperatureServiceUuid, this); + if (!m_temperatureService) { + qCWarning(dcMultiSensor()) << "Could not create temperature service."; + m_bluetoothDevice->disconnectDevice(); return; } - connect(m_infraredService, &QLowEnergyService::stateChanged, this, &SensorTag::onInfraredServiceStateChanged); - connect(m_infraredService, &QLowEnergyService::characteristicChanged, this, &SensorTag::onInfraredServiceCharacteristicChanged); + connect(m_temperatureService, &QLowEnergyService::stateChanged, this, &SensorTag::onTemperatureServiceStateChanged); + connect(m_temperatureService, &QLowEnergyService::characteristicChanged, this, &SensorTag::onTemperatureServiceCharacteristicChanged); - 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; - } - - connect(m_buttonService, &QLowEnergyService::stateChanged, this, &SensorTag::onButtonServiceStateChanged); - connect(m_buttonService, &QLowEnergyService::characteristicChanged, this, &SensorTag::onButtonServiceCharacteristicChanged); - - if (m_buttonService->state() == QLowEnergyService::DiscoveryRequired) { - m_buttonService->discoverDetails(); + if (m_temperatureService->state() == QLowEnergyService::DiscoveryRequired) { + m_temperatureService->discoverDetails(); } } @@ -133,6 +340,7 @@ void SensorTag::onServiceDiscoveryFinished() m_humidityService = m_bluetoothDevice->controller()->createServiceObject(humidityServiceUuid, this); if (!m_humidityService) { qCWarning(dcMultiSensor()) << "Could not create humidity service."; + m_bluetoothDevice->disconnectDevice(); return; } @@ -148,6 +356,7 @@ void SensorTag::onServiceDiscoveryFinished() m_pressureService = m_bluetoothDevice->controller()->createServiceObject(pressureServiceUuid, this); if (!m_pressureService) { qCWarning(dcMultiSensor()) << "Could not create pressure service."; + m_bluetoothDevice->disconnectDevice(); return; } @@ -157,17 +366,69 @@ void SensorTag::onServiceDiscoveryFinished() m_pressureService->discoverDetails(); } } + + + // Optical + if (!m_opticalService) { + m_opticalService = m_bluetoothDevice->controller()->createServiceObject(opticalServiceUuid, this); + if (!m_opticalService) { + qCWarning(dcMultiSensor()) << "Could not create optical service."; + m_bluetoothDevice->disconnectDevice(); + return; + } + + connect(m_opticalService, &QLowEnergyService::stateChanged, this, &SensorTag::onOpticalServiceStateChanged); + connect(m_opticalService, &QLowEnergyService::characteristicChanged, this, &SensorTag::onOpticalServiceCharacteristicChanged); + + if (m_opticalService->state() == QLowEnergyService::DiscoveryRequired) { + m_opticalService->discoverDetails(); + } + } + + // Key + if (!m_keyService) { + m_keyService = m_bluetoothDevice->controller()->createServiceObject(keyServiceUuid, this); + if (!m_keyService) { + qCWarning(dcMultiSensor()) << "Could not create key service."; + m_bluetoothDevice->disconnectDevice(); + return; + } + + connect(m_keyService, &QLowEnergyService::stateChanged, this, &SensorTag::onKeyServiceStateChanged); + connect(m_keyService, &QLowEnergyService::characteristicChanged, this, &SensorTag::onKeyServiceCharacteristicChanged); + + if (m_keyService->state() == QLowEnergyService::DiscoveryRequired) { + m_keyService->discoverDetails(); + } + } + + // Movement + if (!m_movementService) { + m_movementService = m_bluetoothDevice->controller()->createServiceObject(movementServiceUuid, this); + if (!m_movementService) { + qCWarning(dcMultiSensor()) << "Could not create movement service."; + m_bluetoothDevice->disconnectDevice(); + return; + } + + connect(m_movementService, &QLowEnergyService::stateChanged, this, &SensorTag::onMovementServiceStateChanged); + connect(m_movementService, &QLowEnergyService::characteristicChanged, this, &SensorTag::onMovementServiceCharacteristicChanged); + + if (m_movementService->state() == QLowEnergyService::DiscoveryRequired) { + m_movementService->discoverDetails(); + } + } } -void SensorTag::onInfraredServiceStateChanged(const QLowEnergyService::ServiceState &state) +void SensorTag::onTemperatureServiceStateChanged(const QLowEnergyService::ServiceState &state) { // Only continue if discovered if (state != QLowEnergyService::ServiceDiscovered) return; - qCDebug(dcMultiSensor()) << "Infrared sensor service discovered."; + qCDebug(dcMultiSensor()) << "Temperature sensor service discovered."; - foreach (const QLowEnergyCharacteristic &characteristic, m_infraredService->characteristics()) { + foreach (const QLowEnergyCharacteristic &characteristic, m_temperatureService->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(); @@ -175,66 +436,47 @@ void SensorTag::onInfraredServiceStateChanged(const QLowEnergyService::ServiceSt } // Data characteristic - m_infraredDataCharacteristic = m_infraredService->characteristic(QBluetoothUuid(QUuid("f000aa01-0451-4000-b000-000000000000"))); - if (!m_infraredDataCharacteristic.isValid()) { - qCWarning(dcMultiSensor()) << "Invalid infrared data characteristic."; + m_temperatureDataCharacteristic = m_temperatureService->characteristic(QBluetoothUuid(QUuid("f000aa01-0451-4000-b000-000000000000"))); + if (!m_temperatureDataCharacteristic.isValid()) { + qCWarning(dcMultiSensor()) << "Invalid temperature data characteristic."; + m_bluetoothDevice->disconnectDevice(); + return; } // Enable notifications - QLowEnergyDescriptor notificationDescriptor = m_infraredDataCharacteristic.descriptor(QBluetoothUuid::ClientCharacteristicConfiguration); - m_infraredService->writeDescriptor(notificationDescriptor, QByteArray::fromHex("0100")); + QLowEnergyDescriptor notificationDescriptor = m_temperatureDataCharacteristic.descriptor(QBluetoothUuid::ClientCharacteristicConfiguration); + m_temperatureService->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."; + m_temperatureConfigurationCharacteristic = m_temperatureService->characteristic(temperatureConfigurationCharacteristicUuid); + if (!m_temperatureConfigurationCharacteristic.isValid()) { + qCWarning(dcMultiSensor()) << "Invalid temperature configuration characteristic."; + m_bluetoothDevice->disconnectDevice(); + return; } + // Period characteristic + m_temperaturePeriodCharacteristic = m_temperatureService->characteristic(temperaturePeriodCharacteristicUuid); + if (!m_temperaturePeriodCharacteristic.isValid()) { + qCWarning(dcMultiSensor()) << "Invalid temperature period characteristic."; + m_bluetoothDevice->disconnectDevice(); + return; + } + + configurePeriod(m_temperatureService, m_temperaturePeriodCharacteristic, m_temperaturePeriod); + // Enable measuring - m_infraredService->writeCharacteristic(m_infraredConfigCharacteristic, QByteArray::fromHex("01")); + m_temperatureService->writeCharacteristic(m_temperatureConfigurationCharacteristic, QByteArray::fromHex("01")); } -void SensorTag::onInfraredServiceCharacteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &value) +void SensorTag::onTemperatureServiceCharacteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &value) { - if (characteristic == m_infraredDataCharacteristic) { - updateInfraredValue(value); + if (characteristic == m_temperatureDataCharacteristic) { + processTemperatureData(value); // FIXME: Disable measuring - // m_infraredService->writeCharacteristic(m_infraredConfigCharacteristic, QByteArray::fromHex("00")); - } -} - -void SensorTag::onButtonServiceStateChanged(const QLowEnergyService::ServiceState &state) -{ - // Only continue if discovered - if (state != QLowEnergyService::ServiceDiscovered) - return; - - 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(); - } - } - - // Data characteristic - m_buttonCharacteristic = m_buttonService->characteristic(QBluetoothUuid(QUuid("0000ffe1-0000-1000-8000-00805f9b34fb"))); - if (!m_buttonCharacteristic.isValid()) { - qCWarning(dcMultiSensor()) << "Invalid button data characteristic."; - } - - // Enable notifications - QLowEnergyDescriptor notificationDescriptor = m_buttonCharacteristic.descriptor(QBluetoothUuid::ClientCharacteristicConfiguration); - m_buttonService->writeDescriptor(notificationDescriptor, QByteArray::fromHex("0100")); -} - -void SensorTag::onButtonServiceCharacteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &value) -{ - if (characteristic == m_buttonCharacteristic) { - updateButtonValue(value); + // m_temperatureService->writeCharacteristic(m_temperatureConfigCharacteristic, QByteArray::fromHex("00")); } } @@ -254,9 +496,11 @@ void SensorTag::onHumidityServiceStateChanged(const QLowEnergyService::ServiceSt } // Data characteristic - m_humidityDataCharacteristic = m_humidityService->characteristic(QBluetoothUuid(QUuid("f000aa21-0451-4000-b000-000000000000"))); + m_humidityDataCharacteristic = m_humidityService->characteristic(humidityDataCharacteristicUuid); if (!m_humidityDataCharacteristic.isValid()) { qCWarning(dcMultiSensor()) << "Invalid humidity data characteristic."; + m_bluetoothDevice->disconnectDevice(); + return; } // Enable notifications @@ -264,19 +508,31 @@ void SensorTag::onHumidityServiceStateChanged(const QLowEnergyService::ServiceSt 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()) { + m_humidityConfigurationCharacteristic = m_humidityService->characteristic(humidityConfigurationCharacteristicUuid); + if (!m_humidityConfigurationCharacteristic.isValid()) { qCWarning(dcMultiSensor()) << "Invalid humidity configuration characteristic."; + m_bluetoothDevice->disconnectDevice(); + return; } + // Period characteristic + m_humidityPeriodCharacteristic = m_humidityService->characteristic(humidityPeriodCharacteristicUuid); + if (!m_humidityPeriodCharacteristic.isValid()) { + qCWarning(dcMultiSensor()) << "Invalid humidity period characteristic."; + m_bluetoothDevice->disconnectDevice(); + return; + } + + configurePeriod(m_humidityService, m_humidityPeriodCharacteristic, m_humidityPeriod); + // Enable measuring - m_humidityService->writeCharacteristic(m_humidityConfigCharacteristic, QByteArray::fromHex("01")); + m_humidityService->writeCharacteristic(m_humidityConfigurationCharacteristic, QByteArray::fromHex("01")); } void SensorTag::onHumidityServiceCharacteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &value) { if (characteristic == m_humidityDataCharacteristic) { - updateHumidityValue(value); + processHumidityData(value); // FIXME: Disable measuring // m_humidityService->writeCharacteristic(m_humidityConfigCharacteristic, QByteArray::fromHex("00")); } @@ -298,9 +554,11 @@ void SensorTag::onPressureServiceStateChanged(const QLowEnergyService::ServiceSt } // Data characteristic - m_pressureDataCharacteristic = m_pressureService->characteristic(QBluetoothUuid(QUuid("f000aa41-0451-4000-b000-000000000000"))); + m_pressureDataCharacteristic = m_pressureService->characteristic(pressureDataCharacteristicUuid); if (!m_pressureDataCharacteristic.isValid()) { qCWarning(dcMultiSensor()) << "Invalid pressure data characteristic."; + m_bluetoothDevice->disconnectDevice(); + return; } // Enable notifications @@ -308,36 +566,179 @@ void SensorTag::onPressureServiceStateChanged(const QLowEnergyService::ServiceSt 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()) { + m_pressureConfigurationCharacteristic = m_pressureService->characteristic(pressureConfigurationCharacteristicUuid); + if (!m_pressureConfigurationCharacteristic.isValid()) { qCWarning(dcMultiSensor()) << "Invalid pressure configuration characteristic."; + m_bluetoothDevice->disconnectDevice(); + return; } + // Period characteristic + m_pressurePeriodCharacteristic = m_pressureService->characteristic(pressurePeriodCharacteristicUuid); + if (!m_pressurePeriodCharacteristic.isValid()) { + qCWarning(dcMultiSensor()) << "Invalid pressure period characteristic."; + m_bluetoothDevice->disconnectDevice(); + return; + } + + configurePeriod(m_pressureService, m_pressurePeriodCharacteristic, m_pressurePeriod); + // Enable measuring - m_pressureService->writeCharacteristic(m_pressureConfigCharacteristic, QByteArray::fromHex("01")); + m_pressureService->writeCharacteristic(m_pressureConfigurationCharacteristic, QByteArray::fromHex("01")); } void SensorTag::onPressureServiceCharacteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &value) { if (characteristic == m_pressureDataCharacteristic) { - updatePressureValue(value); + processPressureData(value); // FIXME: Disable measuring // m_pressureService->writeCharacteristic(m_pressureConfigCharacteristic, QByteArray::fromHex("00")); } } -void SensorTag::measure() +void SensorTag::onOpticalServiceStateChanged(const QLowEnergyService::ServiceState &state) { - if (!m_bluetoothDevice->connected()) + // Only continue if discovered + if (state != QLowEnergyService::ServiceDiscovered) return; - // TODO: measure using plugintimer to save energy + qCDebug(dcMultiSensor()) << "Optical sensor service discovered."; -// qCDebug(dcMultiSensor()) << "Measure data" << m_bluetoothDevice->name() << m_bluetoothDevice->address().toString(); + 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(); + } + } -// m_infraredService->writeCharacteristic(m_infraredConfigCharacteristic, QByteArray::fromHex("01")); -// m_humidityService->writeCharacteristic(m_humidityConfigCharacteristic, QByteArray::fromHex("01")); -// m_pressureService->writeCharacteristic(m_pressureConfigCharacteristic, QByteArray::fromHex("01")); + // Data characteristic + m_opticalDataCharacteristic = m_opticalService->characteristic(opticalDataCharacteristicUuid); + if (!m_opticalDataCharacteristic.isValid()) { + qCWarning(dcMultiSensor()) << "Invalid optical data characteristic."; + m_bluetoothDevice->disconnectDevice(); + return; + } + + // Enable notifications + QLowEnergyDescriptor notificationDescriptor = m_opticalDataCharacteristic.descriptor(QBluetoothUuid::ClientCharacteristicConfiguration); + m_opticalService->writeDescriptor(notificationDescriptor, QByteArray::fromHex("0100")); + + // Config characteristic + m_opticalConfigurationCharacteristic = m_opticalService->characteristic(opticalConfigurationCharacteristicUuid); + if (!m_opticalConfigurationCharacteristic.isValid()) { + qCWarning(dcMultiSensor()) << "Invalid optical configuration characteristic."; + m_bluetoothDevice->disconnectDevice(); + } + + // Period characteristic + m_opticalPeriodCharacteristic = m_opticalService->characteristic(opticalPeriodCharacteristicUuid); + if (!m_opticalPeriodCharacteristic.isValid()) { + qCWarning(dcMultiSensor()) << "Invalid optical period characteristic."; + m_bluetoothDevice->disconnectDevice(); + } + + // Set measurement period + configurePeriod(m_opticalService, m_opticalPeriodCharacteristic, m_opticalPeriod); + + // Enable measuring + m_opticalService->writeCharacteristic(m_opticalConfigurationCharacteristic, QByteArray::fromHex("01")); +} + +void SensorTag::onOpticalServiceCharacteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &value) +{ + if (characteristic == m_opticalDataCharacteristic) { + processOpticalData(value); + // FIXME: Disable measuring + // m_opticalService->writeCharacteristic(m_pressureopticalCharacteristic, QByteArray::fromHex("00")); + } } +void SensorTag::onKeyServiceStateChanged(const QLowEnergyService::ServiceState &state) +{ + // Only continue if discovered + if (state != QLowEnergyService::ServiceDiscovered) + return; + + qCDebug(dcMultiSensor()) << "Key service discovered."; + foreach (const QLowEnergyCharacteristic &characteristic, m_keyService->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_keyDataCharacteristic = m_keyService->characteristic(keyDataCharacteristicUuid); + if (!m_keyDataCharacteristic.isValid()) { + qCWarning(dcMultiSensor()) << "Invalid button data characteristic."; + m_bluetoothDevice->disconnectDevice(); + } + + // Enable notifications + QLowEnergyDescriptor notificationDescriptor = m_keyDataCharacteristic.descriptor(QBluetoothUuid::ClientCharacteristicConfiguration); + m_keyService->writeDescriptor(notificationDescriptor, QByteArray::fromHex("0100")); +} + +void SensorTag::onKeyServiceCharacteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &value) +{ + if (characteristic == m_keyDataCharacteristic) { + processKeyData(value); + } +} + +void SensorTag::onMovementServiceStateChanged(const QLowEnergyService::ServiceState &state) +{ + // Only continue if discovered + if (state != QLowEnergyService::ServiceDiscovered) + return; + + qCDebug(dcMultiSensor()) << "Movement 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_movementDataCharacteristic = m_movementService->characteristic(movementDataCharacteristicUuid); + if (!m_movementDataCharacteristic.isValid()) { + qCWarning(dcMultiSensor()) << "Invalid movement data characteristic."; + m_bluetoothDevice->disconnectDevice(); + } + + // Enable notifications + QLowEnergyDescriptor notificationDescriptor = m_movementDataCharacteristic.descriptor(QBluetoothUuid::ClientCharacteristicConfiguration); + m_movementService->writeDescriptor(notificationDescriptor, QByteArray::fromHex("0100")); + + // Config characteristic + m_movementConfigurationCharacteristic = m_movementService->characteristic(movementConfigurationCharacteristicUuid); + if (!m_movementConfigurationCharacteristic.isValid()) { + qCWarning(dcMultiSensor()) << "Invalid movement configuration characteristic."; + m_bluetoothDevice->disconnectDevice(); + } + + // Period characteristic + m_movementPeriodCharacteristic = m_movementService->characteristic(movementPeriodCharacteristicUuid); + if (!m_movementPeriodCharacteristic.isValid()) { + qCWarning(dcMultiSensor()) << "Invalid movement period characteristic."; + m_bluetoothDevice->disconnectDevice(); + } + + // Set measurement period + configurePeriod(m_movementService, m_movementPeriodCharacteristic, m_movementPeriod); + + configureMovement(); + + // Enable measuring + m_movementService->writeCharacteristic(m_movementConfigurationCharacteristic, QByteArray::fromHex("01")); +} + +void SensorTag::onMovementServiceCharacteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &value) +{ + if (characteristic == m_movementDataCharacteristic) { + processMovementData(value); + } +} diff --git a/multisensor/sensortag.h b/multisensor/sensortag.h index d1a18833..ad98702b 100644 --- a/multisensor/sensortag.h +++ b/multisensor/sensortag.h @@ -1,3 +1,25 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * * + * Copyright (C) 2015-2018 Simon Stuerz * + * * + * 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 @@ -7,17 +29,40 @@ #include "extern-plugininfo.h" #include "hardware/bluetoothlowenergy/bluetoothlowenergydevice.h" -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")); +// http://processors.wiki.ti.com/index.php/CC2650_SensorTag_User's_Guide + +static QBluetoothUuid temperatureServiceUuid = QBluetoothUuid(QUuid("f000aa00-0451-4000-b000-000000000000")); +static QBluetoothUuid temperatureDataCharacteristicUuid = QBluetoothUuid(QUuid("f000aa01-0451-4000-b000-000000000000")); +static QBluetoothUuid temperatureConfigurationCharacteristicUuid = QBluetoothUuid(QUuid("f000aa02-0451-4000-b000-000000000000")); +static QBluetoothUuid temperaturePeriodCharacteristicUuid = QBluetoothUuid(QUuid("f000aa03-0451-4000-b000-000000000000")); + +static QBluetoothUuid humidityServiceUuid = QBluetoothUuid(QUuid("f000aa20-0451-4000-b000-000000000000")); +static QBluetoothUuid humidityDataCharacteristicUuid = QBluetoothUuid(QUuid("f000aa21-0451-4000-b000-000000000000")); +static QBluetoothUuid humidityConfigurationCharacteristicUuid = QBluetoothUuid(QUuid("f000aa22-0451-4000-b000-000000000000")); +static QBluetoothUuid humidityPeriodCharacteristicUuid = QBluetoothUuid(QUuid("f000aa23-0451-4000-b000-000000000000")); + +static QBluetoothUuid pressureServiceUuid = QBluetoothUuid(QUuid("f000aa40-0451-4000-b000-000000000000")); +static QBluetoothUuid pressureDataCharacteristicUuid = QBluetoothUuid(QUuid("f000aa41-0451-4000-b000-000000000000")); +static QBluetoothUuid pressureConfigurationCharacteristicUuid = QBluetoothUuid(QUuid("f000aa42-0451-4000-b000-000000000000")); +static QBluetoothUuid pressurePeriodCharacteristicUuid = QBluetoothUuid(QUuid("f000aa44-0451-4000-b000-000000000000")); + +static QBluetoothUuid opticalServiceUuid = QBluetoothUuid(QUuid("f000aa70-0451-4000-b000-000000000000")); +static QBluetoothUuid opticalDataCharacteristicUuid = QBluetoothUuid(QUuid("f000aa71-0451-4000-b000-000000000000")); +static QBluetoothUuid opticalConfigurationCharacteristicUuid = QBluetoothUuid(QUuid("f000aa72-0451-4000-b000-000000000000")); +static QBluetoothUuid opticalPeriodCharacteristicUuid = QBluetoothUuid(QUuid("f000aa73-0451-4000-b000-000000000000")); + +static QBluetoothUuid keyServiceUuid = QBluetoothUuid(QUuid("0000ffe0-0000-1000-8000-00805f9b34fb")); +static QBluetoothUuid keyDataCharacteristicUuid = QBluetoothUuid(QUuid("0000ffe1-0000-1000-8000-00805f9b34fb")); + +static QBluetoothUuid ioServiceUuid = QBluetoothUuid(QUuid("f000aa64-0451-4000-b000-000000000000")); +static QBluetoothUuid ioDataCharacteristicUuid = QBluetoothUuid(QUuid("f000aa65-0451-4000-b000-000000000000")); +static QBluetoothUuid ioConfigurationCharacteristicUuid = QBluetoothUuid(QUuid("f000aa66-0451-4000-b000-000000000000")); + +static QBluetoothUuid movementServiceUuid = QBluetoothUuid(QUuid("f000aa80-0451-4000-b000-000000000000")); +static QBluetoothUuid movementDataCharacteristicUuid = QBluetoothUuid(QUuid("f000aa81-0451-4000-b000-000000000000")); +static QBluetoothUuid movementConfigurationCharacteristicUuid = QBluetoothUuid(QUuid("f000aa82-0451-4000-b000-000000000000")); +static QBluetoothUuid movementPeriodCharacteristicUuid = QBluetoothUuid(QUuid("f000aa83-0451-4000-b000-000000000000")); -// Currently unused services class SensorTag : public QObject { @@ -28,49 +73,93 @@ public: Device *device(); BluetoothLowEnergyDevice *bluetoothDevice(); + void setAccelerometerEnabled(bool enabled); + void setGyroscopeEnabled(bool enabled); + void setMagnetometerEnabled(bool enabled); + void setMeasurementPeriod(int period); + private: Device *m_device; BluetoothLowEnergyDevice *m_bluetoothDevice; // Services - QLowEnergyService *m_infraredService = nullptr; - QLowEnergyService *m_buttonService = nullptr; + QLowEnergyService *m_temperatureService = nullptr; QLowEnergyService *m_humidityService = nullptr; QLowEnergyService *m_pressureService = nullptr; - QLowEnergyService *m_accelerometerService = nullptr; - QLowEnergyService *m_magnetometerService = nullptr; - QLowEnergyService *m_gyroscopeService = nullptr; + QLowEnergyService *m_opticalService = nullptr; + QLowEnergyService *m_keyService = nullptr; + QLowEnergyService *m_movementService = nullptr; // Characteristics - QLowEnergyCharacteristic m_infraredDataCharacteristic; - QLowEnergyCharacteristic m_infraredConfigCharacteristic; - QLowEnergyCharacteristic m_buttonCharacteristic; + QLowEnergyCharacteristic m_temperatureDataCharacteristic; + QLowEnergyCharacteristic m_temperatureConfigurationCharacteristic; + QLowEnergyCharacteristic m_temperaturePeriodCharacteristic; + QLowEnergyCharacteristic m_humidityDataCharacteristic; - QLowEnergyCharacteristic m_humidityConfigCharacteristic; + QLowEnergyCharacteristic m_humidityConfigurationCharacteristic; + QLowEnergyCharacteristic m_humidityPeriodCharacteristic; + QLowEnergyCharacteristic m_pressureDataCharacteristic; - QLowEnergyCharacteristic m_pressureConfigCharacteristic; + QLowEnergyCharacteristic m_pressureConfigurationCharacteristic; + QLowEnergyCharacteristic m_pressurePeriodCharacteristic; + QLowEnergyCharacteristic m_opticalDataCharacteristic; + QLowEnergyCharacteristic m_opticalConfigurationCharacteristic; + QLowEnergyCharacteristic m_opticalPeriodCharacteristic; - void updateInfraredValue(const QByteArray &value); - void updateButtonValue(const QByteArray &value); - void updateHumidityValue(const QByteArray &value); - void updatePressureValue(const QByteArray &value); + QLowEnergyCharacteristic m_keyDataCharacteristic; + + QLowEnergyCharacteristic m_movementDataCharacteristic; + QLowEnergyCharacteristic m_movementConfigurationCharacteristic; + QLowEnergyCharacteristic m_movementPeriodCharacteristic; + + // Measure periods + int m_temperaturePeriod = 2500; + int m_humidityPeriod = 2500; + int m_pressurePeriod = 2500; + int m_opticalPeriod = 2500; + int m_movementPeriod = 500; + + bool m_leftButtonPressed = false; + bool m_rightButtonPressed = false; + bool m_magnetDetected = false; + + // Plugin configs + bool m_accelerometerEnabled = true; + bool m_gyroscopeEnabled = false; + bool m_magnetometerEnabled = false; + + void configurePeriod(QLowEnergyService *serice, const QLowEnergyCharacteristic &characteristic, int measurementPeriod); + void configureMovement(bool gyroscopeEnabled = false, bool accelerometerEnabled = true, bool magnetometerEnabled = true, bool wakeOnMotion = true); + + void processTemperatureData(const QByteArray &data); + void processKeyData(const QByteArray &data); + void processHumidityData(const QByteArray &data); + void processPressureData(const QByteArray &data); + void processOpticalData(const QByteArray &data); + void processMovementData(const QByteArray &data); + + // Set methods + void setLeftButtonPressed(bool pressed); + void setRightButtonPressed(bool pressed); + void setMagnetDetected(bool detected); + + // Helper + bool testBitUint8(quint8 value, int bitPosition); + double roundValue(float value); signals: - void leftKeyPressed(); - void rightKeyPressed(); + void leftButtonPressedChainged(bool pressed); + void rightButtonPressedChainged(bool pressed); + void magnetDetectedChainged(bool detected); private slots: void onConnectedChanged(const bool &connected); void onServiceDiscoveryFinished(); - // 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); + // Temperature sensor service + void onTemperatureServiceStateChanged(const QLowEnergyService::ServiceState &state); + void onTemperatureServiceCharacteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &value); // Humidity sensor service void onHumidityServiceStateChanged(const QLowEnergyService::ServiceState &state); @@ -80,9 +169,17 @@ private slots: void onPressureServiceStateChanged(const QLowEnergyService::ServiceState &state); void onPressureServiceCharacteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &value); + // Optical sensor service + void onOpticalServiceStateChanged(const QLowEnergyService::ServiceState &state); + void onOpticalServiceCharacteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &value); -public slots: - void measure(); + // Button service + void onKeyServiceStateChanged(const QLowEnergyService::ServiceState &state); + void onKeyServiceCharacteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &value); + + // Movement service + void onMovementServiceStateChanged(const QLowEnergyService::ServiceState &state); + void onMovementServiceCharacteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &value); };