aboutsummaryrefslogtreecommitdiff
path: root/apps
diff options
context:
space:
mode:
authorTrygve Laugstøl <trygvis@inamo.no>2015-07-26 18:33:15 +0200
committerTrygve Laugstøl <trygvis@inamo.no>2015-07-26 18:41:40 +0200
commitd720fa36ad4768ed1b948a92ba5287c30093fbec (patch)
tree3d566e0d4ab47981af85a783f81ebbd363d57f15 /apps
parent33c537c84fea53c899fb5275256518598f66101e (diff)
downloadble-toys-d720fa36ad4768ed1b948a92ba5287c30093fbec.tar.gz
ble-toys-d720fa36ad4768ed1b948a92ba5287c30093fbec.tar.bz2
ble-toys-d720fa36ad4768ed1b948a92ba5287c30093fbec.tar.xz
ble-toys-d720fa36ad4768ed1b948a92ba5287c30093fbec.zip
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.
Diffstat (limited to 'apps')
-rw-r--r--apps/SoilMoisture.cpp64
-rw-r--r--apps/SoilMoisture.h15
-rw-r--r--apps/ble-inspect-device.cpp10
-rw-r--r--apps/ble-scan.cpp15
-rw-r--r--apps/sm-get-value.cpp21
5 files changed, 96 insertions, 29 deletions
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 <bitset>
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<uint8_t>(sm_cmd_code::SM_CMD_GET_SENSOR_COUNT));
}
+static
ByteBuffer createGetValue(uint8_t sensor) {
return ByteBuffer::alloc(100) //
.write8(static_cast<uint8_t>(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<uint8_t>(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<uint8_t>(sm_cmd_code::SM_CMD_SET_SENSOR_NAME))
@@ -39,10 +48,12 @@ ByteBuffer createSetSensorName(uint8_t sensor, string name) {
.write(reinterpret_cast<const uint8_t *>(name.c_str()), name.length());
}
+static
ByteBuffer createGetSensorName(uint8_t sensor) {
return ByteBuffer::alloc(100).write8(static_cast<uint8_t>(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<uint8_t>(sm_cmd_code::SM_CMD_SET_UPDATE_INTERVAL))
@@ -65,13 +76,18 @@ SoilMoisture SoilMoisture::create(shared_ptr<BluetoothGatt> 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<BluetoothGatt> gatt, BluetoothGattService &s, BluetoothGattCharacteristic &c)
- : gatt(std::move(gatt)), s(s), c(c) {}
+SoilMoisture::SoilMoisture(const shared_ptr<BluetoothGatt> &gatt, BluetoothGattService &s,
+ const BluetoothGattCharacteristic &soilMoistureCharacteristic,
+ const o<const BluetoothGattCharacteristic &> 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<double> SoilMoisture::readTemperature() {
+ if (!temperatureCharacteristic) {
+ return o<double>();
+ }
+
+ 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<double>(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 <typename T>
+using o = boost::optional<T>;
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<double> readTemperature();
+
private:
- SoilMoisture(shared_ptr<BluetoothGatt> gatt, BluetoothGattService &s, BluetoothGattCharacteristic &c);
+ SoilMoisture(const shared_ptr<BluetoothGatt> &gatt, BluetoothGattService &s,
+ const BluetoothGattCharacteristic &soilMoistureCharacteristic,
+ const o<const BluetoothGattCharacteristic &> temperatureCharacteristic);
- ByteBuffer writeAndRead(ByteBuffer &requestBytes);
+ ByteBuffer writeAndRead(const BluetoothGattCharacteristic &c, ByteBuffer &requestBytes);
shared_ptr<BluetoothGatt> gatt;
BluetoothGattService &s;
- BluetoothGattCharacteristic &c;
+ const BluetoothGattCharacteristic &soilMoistureCharacteristic;
+ const o<const BluetoothGattCharacteristic &> 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<string>()->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<BluetoothDevice> &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<BluetoothAdapter> 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<int>()->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<int>();
-
- adapter = getAdapter(adapter_index);
+ adapter = bluetoothSystem.getAdapter(adapter_name);
set<Mac> 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++;
}