From d720fa36ad4768ed1b948a92ba5287c30093fbec Mon Sep 17 00:00:00 2001 From: Trygve Laugstøl Date: Sun, 26 Jul 2015 18:33:15 +0200 Subject: o Overhaul of the bluetooth code. - Adding support for reading FLOAT (specified in IEEE 11073-20601) values from a bluetooth device. - More shared pointers to help keep track of the object's lifecycle. Makes sure that the connections are released back to Linux, Linux is way to sensitive with crashing applications. o Adding support for reading the temperature sensors from the SoilMoisture device. --- apps/SoilMoisture.cpp | 64 +++++++++++++++++++++++++++++++++++++++------ apps/SoilMoisture.h | 15 ++++++++--- apps/ble-inspect-device.cpp | 10 +++---- apps/ble-scan.cpp | 15 ++++++----- apps/sm-get-value.cpp | 21 ++++++++++----- 5 files changed, 96 insertions(+), 29 deletions(-) (limited to 'apps') diff --git a/apps/SoilMoisture.cpp b/apps/SoilMoisture.cpp index 1d6888c..88f881a 100644 --- a/apps/SoilMoisture.cpp +++ b/apps/SoilMoisture.cpp @@ -1,4 +1,5 @@ #include "SoilMoisture.h" +#include namespace trygvis { namespace sensor { @@ -9,22 +10,29 @@ namespace sensor { auto trygvis_io_base_uuid = boost::uuids::uuid{0x32, 0xd0, 0x00, 0x00, 0x03, 0x5d, 0x59, 0xc5, 0x70, 0xd3, 0xbc, 0x8e, 0x4a, 0x1f, 0xd8, 0x3f}; +auto bluetooth_base_uuid = + boost::uuids::uuid{0x00, 0x00, 0x18, 0x0f, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb}; + const boost::uuids::uuid soil_moisture_service = makeUuid(trygvis_io_base_uuid, 0x00, 0x10); const boost::uuids::uuid soil_moisture_characteristic = makeUuid(trygvis_io_base_uuid, 0x00, 0x11); +const boost::uuids::uuid temperature_characteristic = makeUuid(bluetooth_base_uuid, 0x2a, 0x1e); using namespace trygvis::bluetooth; +static ByteBuffer createGetSensorCount() { return ByteBuffer::alloc(100) // .write8(static_cast(sm_cmd_code::SM_CMD_GET_SENSOR_COUNT)); } +static ByteBuffer createGetValue(uint8_t sensor) { return ByteBuffer::alloc(100) // .write8(static_cast(sm_cmd_code::SM_CMD_GET_VALUE)) // .write16le(sensor); } +static ByteBuffer createSetWarningValue(uint8_t sensor, uint16_t warning_value) { return ByteBuffer::alloc(100) .write8(static_cast(sm_cmd_code::SM_CMD_SET_WARNING_VALUE)) @@ -32,6 +40,7 @@ ByteBuffer createSetWarningValue(uint8_t sensor, uint16_t warning_value) { .write16le(warning_value); } +static ByteBuffer createSetSensorName(uint8_t sensor, string name) { return ByteBuffer::alloc(100) .write8(static_cast(sm_cmd_code::SM_CMD_SET_SENSOR_NAME)) @@ -39,10 +48,12 @@ ByteBuffer createSetSensorName(uint8_t sensor, string name) { .write(reinterpret_cast(name.c_str()), name.length()); } +static ByteBuffer createGetSensorName(uint8_t sensor) { return ByteBuffer::alloc(100).write8(static_cast(sm_cmd_code::SM_CMD_GET_SENSOR_NAME)).write8(sensor); } +static ByteBuffer createSetUpdateInterval(uint8_t sensor, uint8_t interval_in_seconds) { return ByteBuffer::alloc(100) .write8(static_cast(sm_cmd_code::SM_CMD_SET_UPDATE_INTERVAL)) @@ -65,13 +76,18 @@ SoilMoisture SoilMoisture::create(shared_ptr gatt) { throw runtime_error("The device is missing the soil moisture characteristic"); } - return SoilMoisture(gatt, *service, *c); + auto temperature = service->findCharacteristic(temperature_characteristic); + + return SoilMoisture(gatt, *service, c.get(), temperature); } -SoilMoisture::SoilMoisture(shared_ptr gatt, BluetoothGattService &s, BluetoothGattCharacteristic &c) - : gatt(std::move(gatt)), s(s), c(c) {} +SoilMoisture::SoilMoisture(const shared_ptr &gatt, BluetoothGattService &s, + const BluetoothGattCharacteristic &soilMoistureCharacteristic, + const o temperatureCharacteristic) + : gatt(gatt), s(s), soilMoistureCharacteristic(soilMoistureCharacteristic), + temperatureCharacteristic(temperatureCharacteristic) {} -ByteBuffer SoilMoisture::writeAndRead(ByteBuffer &requestBytes) { +ByteBuffer SoilMoisture::writeAndRead(const BluetoothGattCharacteristic &c, ByteBuffer &requestBytes) { requestBytes.setCursor(0); uint8_t expectedCode = requestBytes.get8(0); @@ -81,7 +97,7 @@ ByteBuffer SoilMoisture::writeAndRead(ByteBuffer &requestBytes) { auto responseBytes = gatt->readValue(c); if (responseBytes.getSize() < 1) { - throw runtime_error("Unexpected number of bytes read: " + to_string(requestBytes.getSize())); + throw runtime_error("Unexpected number of bytes read: " + to_string(responseBytes.getSize())); } uint8_t actualCode = responseBytes.read8(); @@ -95,13 +111,13 @@ ByteBuffer SoilMoisture::writeAndRead(ByteBuffer &requestBytes) { uint8_t SoilMoisture::getSensorCount() { auto buffer = createGetSensorCount(); - return writeAndRead(buffer).read8(); + return writeAndRead(soilMoistureCharacteristic, buffer).read8(); } uint16_t SoilMoisture::getValue(uint8_t sensor) { auto req = createGetValue(sensor); - auto buffer = writeAndRead(req); + auto buffer = writeAndRead(soilMoistureCharacteristic, req); buffer.read8(); // sensor index return buffer.read16le(); } @@ -109,12 +125,44 @@ uint16_t SoilMoisture::getValue(uint8_t sensor) { string SoilMoisture::getName(uint8_t sensor) { auto req = createGetSensorName(sensor); - auto buffer = writeAndRead(req); + auto buffer = writeAndRead(soilMoistureCharacteristic, req); size_t bytesLeft = buffer.getBytesLeft(); uint8_t bytes[bytesLeft]; buffer.copy(bytes, bytesLeft); return string((char *) bytes, (unsigned long) bytesLeft); } + +bool SoilMoisture::hasTemperatureSensor() { + return temperatureCharacteristic.is_initialized(); +} + +/** + * https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.intermediate_temperature.xml + */ +o SoilMoisture::readTemperature() { + if (!temperatureCharacteristic) { + return o(); + } + + auto &c = temperatureCharacteristic.get(); + + auto responseBytes = gatt->readValue(c); + + if (responseBytes.getSize() < 2) { + throw runtime_error("Unexpected number of bytes read: " + to_string(responseBytes.getSize())); + } + + bitset<8> b0 = responseBytes.read8(); + + bool is_fahrenheit = b0.test(0); + bool has_timestamp = b0.test(1); + bool has_type = b0.test(2); + + double temperature = responseBytes.readFLOAT(); + + return o(temperature); +} + } } diff --git a/apps/SoilMoisture.h b/apps/SoilMoisture.h index b5a8749..99b698d 100644 --- a/apps/SoilMoisture.h +++ b/apps/SoilMoisture.h @@ -7,6 +7,8 @@ namespace trygvis { namespace sensor { using namespace trygvis::bluetooth; +template +using o = boost::optional; enum class sm_cmd_code : uint8_t { SM_CMD_GET_SENSOR_COUNT = 1, @@ -32,14 +34,21 @@ public: string getName(uint8_t sensor); + bool hasTemperatureSensor(); + + o readTemperature(); + private: - SoilMoisture(shared_ptr gatt, BluetoothGattService &s, BluetoothGattCharacteristic &c); + SoilMoisture(const shared_ptr &gatt, BluetoothGattService &s, + const BluetoothGattCharacteristic &soilMoistureCharacteristic, + const o temperatureCharacteristic); - ByteBuffer writeAndRead(ByteBuffer &requestBytes); + ByteBuffer writeAndRead(const BluetoothGattCharacteristic &c, ByteBuffer &requestBytes); shared_ptr gatt; BluetoothGattService &s; - BluetoothGattCharacteristic &c; + const BluetoothGattCharacteristic &soilMoistureCharacteristic; + const o temperatureCharacteristic; }; } } diff --git a/apps/ble-inspect-device.cpp b/apps/ble-inspect-device.cpp index 6330512..2140e03 100644 --- a/apps/ble-inspect-device.cpp +++ b/apps/ble-inspect-device.cpp @@ -22,10 +22,10 @@ public: options("device", po::value()->required(), "The MAC of the device to inspect"); } - void scan_callback(BluetoothDevice &device) { - cout << "Inspecting device: " << device.getMac().str() << endl; + void scan_callback(const shared_ptr &device) { + cout << "Inspecting device: " << device->getMac().str() << endl; - auto gatt = device.connectGatt(); + auto gatt = device->connectGatt(); gatt->discoverServices(); @@ -53,9 +53,9 @@ public: try { Mac mac = Mac::parseMac(mac_str); - shared_ptr adapter = getAdapter(0); + auto adapter = bluetoothSystem.getAdapter("0"); - BluetoothDevice &device = adapter->getDevice(mac); + auto device = adapter->getDevice(mac); scan_callback(device); diff --git a/apps/ble-scan.cpp b/apps/ble-scan.cpp index 839a9fa..158af14 100644 --- a/apps/ble-scan.cpp +++ b/apps/ble-scan.cpp @@ -26,8 +26,11 @@ public: ~ble_scan() = default; + string adapter_name; + void add_options(po::options_description_easy_init &options) override { - options("adapter", po::value()->default_value(0), "Which adapter to use."); + auto adapter_value = po::value<>(&adapter_name)->default_value("0"); + options("adapter", adapter_value, "Which adapter to use."); } int main(app_execution &execution) override { @@ -45,16 +48,14 @@ public: sigaction(SIGINT, &sigIntHandler, NULL); try { - auto adapter_index = execution.vm["adapter"].as(); - - adapter = getAdapter(adapter_index); + adapter = bluetoothSystem.getAdapter(adapter_name); set seen_devices; - cout << "Scanning with adapter #" << adapter_index << ", mac=" << adapter->getMac().str() << endl; + cout << "Scanning with adapter " << adapter_name << ", mac=" << adapter->getMac().str() << endl; - adapter->runScan([&](BluetoothDevice &device) { - auto mac = device.getMac(); + adapter->runScan([&](auto device) { + auto mac = device->getMac(); cout << "Found: " << mac.str() << endl; diff --git a/apps/sm-get-value.cpp b/apps/sm-get-value.cpp index 92ef5f9..5d66320 100644 --- a/apps/sm-get-value.cpp +++ b/apps/sm-get-value.cpp @@ -50,7 +50,7 @@ public: } int main(app_execution &execution) override { - __attribute__((unused)) BluetoothSystem bluetoothSystem; + BluetoothSystem bluetoothSystem; auto desc = execution.desc; auto vm = execution.vm; @@ -66,18 +66,20 @@ public: Mac mac = Mac::parseMac(mac_string); - auto adapter = getAdapter(0); + auto adapter = bluetoothSystem.getAdapter("0"); - auto &device = adapter->getDevice(mac); + auto device = adapter->getDevice(mac); loop = sleepTime > 0; do { try { - LOG4CPLUS_INFO(execution.logger, "Connecting to device: " << device.getMac().str()); - auto gatt = device.connectGatt(); + LOG4CPLUS_INFO(execution.logger, "Connecting to device: " << device->getMac().str()); + auto gatt = device->connectGatt(); withConnection(format, gatt); + } catch (BluetoothException &e) { + LOG4CPLUS_ERROR(execution.logger, "Bluetooth error: " << e.what()); } catch (runtime_error &e) { LOG4CPLUS_ERROR(execution.logger, "Exception: " << e.what()); } @@ -112,6 +114,11 @@ public: .set(device_key, mac) .set(timestamp_key, std::to_string(timestamp)); + auto tempO = soilMoisture.readTemperature(); + if (tempO) { + sample.set(dict.indexOf("temperature"), std::to_string(tempO.get())); + } + int i = 0; for (auto s : sensors) { auto sensor = s.first; @@ -122,7 +129,9 @@ public: auto sensor_key = dict.indexOf("sensor" + std::to_string(i)); auto sensor_name_key = dict.indexOf("sensor_name" + std::to_string(i)); - sample.set(sensor_key, std::to_string(value)).set(sensor_name_key, name); + sample + .set(sensor_key, std::to_string(value)) + .set(sensor_name_key, name); i++; } -- cgit v1.2.3