From d0fb1850606ce003887259675e271a9aade4fda0 Mon Sep 17 00:00:00 2001 From: Trygve Laugstøl Date: Sun, 22 Feb 2015 16:16:48 +0100 Subject: o Starting a new class for all SoilMoisture GATT stuff. --- apps/CMakeLists.txt | 3 +- apps/SoilMoisture.cpp | 121 ++++++++++++++++++++++++++++++++++++++++++++++ apps/SoilMoisture.h | 47 ++++++++++++++++++ apps/sm-get-value.cpp | 120 ++-------------------------------------------- apps/soil-moisture.h | 122 ----------------------------------------------- include/ble/ByteBuffer.h | 7 +-- 6 files changed, 179 insertions(+), 241 deletions(-) create mode 100644 apps/SoilMoisture.cpp create mode 100644 apps/SoilMoisture.h delete mode 100644 apps/soil-moisture.h diff --git a/apps/CMakeLists.txt b/apps/CMakeLists.txt index aefb0fb..e210716 100644 --- a/apps/CMakeLists.txt +++ b/apps/CMakeLists.txt @@ -1,4 +1,5 @@ set(APPS sm-get-value ble-inspect-device) +set(shared_sources SoilMoisture.cpp) # Boost find_package(Boost COMPONENTS system log thread REQUIRED) @@ -12,7 +13,7 @@ find_package(Threads REQUIRED) foreach(app ${APPS}) include_directories("${PROJECT_SOURCE_DIR}/include") - add_executable(${app} ${app}.cpp) + add_executable(${app} ${app}.cpp ${shared_sources}) add_dependencies(${app} ble) target_link_libraries(${app} ble) diff --git a/apps/SoilMoisture.cpp b/apps/SoilMoisture.cpp new file mode 100644 index 0000000..0fed8ab --- /dev/null +++ b/apps/SoilMoisture.cpp @@ -0,0 +1,121 @@ +#include "SoilMoisture.h" + +namespace trygvis { +namespace soil_moisture { + + +#define BLUETOOTH_UUID_INITIALIZER \ + { \ + 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, \ + 0x10, 0x00, \ + 0x80, 0x00, \ + 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb \ + }; + +auto trygvis_io_base_uuid = boost::uuids::uuid { + 0x32, 0xd0, 0x00, 0x00, + 0x03, 0x5d, + 0x59, 0xc5, + 0x70, 0xd3, + 0xbc, 0x8e, 0x4a, 0x1f, 0xd8, 0x3f}; + +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); + +using namespace trygvis::bluetooth; + +ByteBuffer createGetSensorCount() { + return ByteBuffer::alloc(100). + write8(static_cast(sm_cmd_code::SM_CMD_GET_SENSOR_COUNT)); +} + +ByteBuffer createGetValue(uint8_t sensor) { + return ByteBuffer::alloc(100). + write8(static_cast(sm_cmd_code::SM_CMD_GET_VALUE)). + write16le(sensor); +} + +ByteBuffer createSetWarningValue(uint8_t sensor, uint16_t warning_value) { + return ByteBuffer::alloc(100). + write8(static_cast(sm_cmd_code::SM_CMD_SET_WARNING_VALUE)). + write8(sensor). + write16le(warning_value); +} + +ByteBuffer createSetSensorName(uint8_t sensor, string name) { + return ByteBuffer::alloc(100). + write8(static_cast(sm_cmd_code::SM_CMD_SET_SENSOR_NAME)). + write8(sensor). + write(reinterpret_cast(name.c_str()), name.length()); +} + +ByteBuffer createGetSensorName(uint8_t sensor) { + return ByteBuffer::alloc(100). + write8(static_cast(sm_cmd_code::SM_CMD_GET_SENSOR_NAME)). + write8(sensor); +} + +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)). + write8(sensor). + write8(interval_in_seconds); +} + +SoilMoisture SoilMoisture::create(BluetoothGatt & gatt) { + gatt.discoverServices(); + + auto service = gatt.findService(soil_moisture_service); + + if (!service) { + throw runtime_error("The device is missing the soil moisture service"); + } + + auto c = service->findCharacteristic(soil_moisture_characteristic); + + if (!c) { + throw runtime_error("The device is missing the soil moisture characteristic"); + } + + return SoilMoisture(gatt, *service, *c); +} + +SoilMoisture::SoilMoisture(BluetoothGatt & gatt, BluetoothGattService &s, BluetoothGattCharacteristic &c) : + gatt(gatt), s(s), c(c) { +} + +ByteBuffer SoilMoisture::writeAndRead(ByteBuffer &requestBytes) { + requestBytes.setCursor(0); + + uint8_t expectedCode = requestBytes.get8(0); + + gatt.writeValue(c, requestBytes); + + auto responseBytes = gatt.readValue(c); + + if (responseBytes.getSize() < 1) { + throw runtime_error("Unexpected number of bytes read: " + to_string(requestBytes.getSize())); + } + + uint8_t actualCode = responseBytes.read8(); + if (actualCode != expectedCode) { + throw runtime_error("Unexpected response code: " + to_string(actualCode) + ", expected " + to_string(expectedCode)); + } + + return responseBytes; +} + +uint8_t SoilMoisture::getSensorCount() { + auto buffer = createGetSensorCount(); + return writeAndRead(buffer).read8(); +} + +uint16_t SoilMoisture::getValue(uint8_t sensor) { + auto req = createGetValue(sensor); + + return writeAndRead(req).read16le(); +} + +} +} diff --git a/apps/SoilMoisture.h b/apps/SoilMoisture.h new file mode 100644 index 0000000..ea64032 --- /dev/null +++ b/apps/SoilMoisture.h @@ -0,0 +1,47 @@ +#ifndef SOIL_MOISTURE_H +#define SOIL_MOISTURE_H + +#include +#include + +namespace trygvis { +namespace soil_moisture { + +using namespace trygvis::bluetooth; + +enum class sm_cmd_code : uint8_t { + SM_CMD_GET_SENSOR_COUNT = 1, + SM_CMD_GET_VALUE = 2, + SM_CMD_SET_WARNING_VALUE = 3, + SM_CMD_GET_WARNING_VALUE = 4, + SM_CMD_SET_SENSOR_NAME = 5, + SM_CMD_GET_SENSOR_NAME = 6, + SM_CMD_SET_UPDATE_INTERVAL = 7, + SM_CMD_FAIL = 255, +}; + +extern const boost::uuids::uuid soil_moisture_service; +extern const boost::uuids::uuid soil_moisture_characteristic; + +class SoilMoisture { +public: + static SoilMoisture create(BluetoothGatt &gatt); + + uint8_t getSensorCount(); + + uint16_t getValue(uint8_t sensor); + +private: + SoilMoisture(BluetoothGatt &gatt, BluetoothGattService &s, BluetoothGattCharacteristic &c); + + ByteBuffer writeAndRead(ByteBuffer &requestBytes); + + BluetoothGatt &gatt; + BluetoothGattService &s; + BluetoothGattCharacteristic &c; +}; + +} +} + +#endif diff --git a/apps/sm-get-value.cpp b/apps/sm-get-value.cpp index e4ddc16..46177f2 100644 --- a/apps/sm-get-value.cpp +++ b/apps/sm-get-value.cpp @@ -2,100 +2,22 @@ #include #include #include "ble/Bluetooth.h" -#include "soil-moisture.h" +#include "SoilMoisture.h" using namespace std; using namespace trygvis::bluetooth; - -#define BLUETOOTH_UUID_INITIALIZER \ - { \ - 0x00, 0x00, 0x00, 0x00, \ - 0x00, 0x00, \ - 0x10, 0x00, \ - 0x80, 0x00, \ - 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb \ - }; - -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 soil_moisture_service = makeUuid(trygvis_io_base_uuid, 0x00, 0x10); -auto soil_moisture_characteristic = makeUuid(trygvis_io_base_uuid, 0x00, 0x11); - -ByteBuffer &operator<<(ByteBuffer &bytes, const sm_req &req); +using namespace trygvis::soil_moisture; bool loop = true; -ByteBuffer writeAndRead(BluetoothGatt &gatt, const BluetoothGattCharacteristic &c, const ByteBuffer &requestBytes) { - uint8_t expectedCode = requestBytes.get8(0); - - gatt.writeValue(c, requestBytes); - - auto responseBytes = gatt.readValue(c); - - if (responseBytes.getSize() < 1) { - throw runtime_error("Unexpected number of bytes read: " + to_string(requestBytes.getSize())); - } - - uint8_t actualCode = responseBytes.read8(); - if (actualCode != expectedCode) { - throw runtime_error("Unexpected response code: " + to_string(actualCode) + ", expected " + to_string(expectedCode)); - } - - return responseBytes; -} - -uint8_t getSensorCount(BluetoothGatt &gatt, BluetoothGattCharacteristic &c) { - sm_req req = { - .code = SM_CMD_GET_SENSOR_COUNT, - }; - - auto requestBytes = ByteBuffer::alloc(sizeof(struct sm_req)); - requestBytes << req; - requestBytes.setCursor(0); - - return writeAndRead(gatt, c, requestBytes).read8(); -} - -uint16_t getValue(BluetoothGatt &gatt, BluetoothGattCharacteristic &c, uint8_t sensor) { - sm_req req = { - .code = SM_CMD_GET_VALUE, - }; - req.get_value = { - .sensor = sensor, - }; - - auto requestBytes = ByteBuffer::alloc(sizeof(struct sm_req)); - requestBytes << req; - requestBytes.setCursor(0); - - return writeAndRead(gatt, c, requestBytes).read16le(); -} - void withConnection(BluetoothGatt &gatt) { - gatt.discoverServices(); + SoilMoisture soilMoisture = SoilMoisture::create(gatt); - auto service = gatt.findService(soil_moisture_service); - - if (!service) { - throw runtime_error("The device is missing the soil moisture service"); - } - - auto c = service->findCharacteristic(soil_moisture_characteristic); - - if (!c) { - throw runtime_error("The device is missing the soil moisture characteristic"); - } - - int sensorCount = getSensorCount(gatt, *c); + int sensorCount = soilMoisture.getSensorCount(); while (loop) { for (uint8_t i = 0; i < sensorCount; i++) { - uint16_t value = getValue(gatt, *c, i); + uint16_t value = soilMoisture.getValue(i); cout << "sensor=" << to_string(i) << ", value=" << (int) value << endl; } @@ -141,35 +63,3 @@ int main(int argc, char *argv[]) { return EXIT_FAILURE; } } - -ByteBuffer &operator<<(ByteBuffer &bytes, const sm_req &req) { - bytes.write8(req.code); - switch (req.code) { - case SM_CMD_GET_SENSOR_COUNT: - return bytes; - case SM_CMD_GET_VALUE: - return bytes. - write8(req.get_value.sensor); - case SM_CMD_SET_WARNING_VALUE: - return bytes. - write8(req.set_warning_value.sensor). - write16le(req.set_warning_value.warning_value); - case SM_CMD_GET_WARNING_VALUE: - return bytes. - write8(req.set_warning_value.sensor); - case SM_CMD_SET_SENSOR_NAME: - return bytes. - write8(req.set_sensor_name.sensor). - write8(req.set_sensor_name.length). - write(req.set_sensor_name.name, req.set_sensor_name.length); - case SM_CMD_GET_SENSOR_NAME: - return bytes. - write8(req.get_sensor_name.sensor); - case SM_CMD_SET_UPDATE_INTERVAL: - return bytes. - write8(req.set_update_interval.sensor). - write8(req.set_update_interval.interval_in_seconds); - default: - throw runtime_error("Unknown code: " + to_string(req.code)); - } -} diff --git a/apps/soil-moisture.h b/apps/soil-moisture.h deleted file mode 100644 index c960f79..0000000 --- a/apps/soil-moisture.h +++ /dev/null @@ -1,122 +0,0 @@ -#ifndef SOIL_MOISTURE_H -#define SOIL_MOISTURE_H - -#define SENSOR_NAME_LEN 10 - -enum sm_cmd_code { - SM_CMD_GET_SENSOR_COUNT = 1, - SM_CMD_GET_VALUE = 2, - SM_CMD_SET_WARNING_VALUE = 3, - SM_CMD_GET_WARNING_VALUE = 4, - SM_CMD_SET_SENSOR_NAME = 5, - SM_CMD_GET_SENSOR_NAME = 6, - SM_CMD_SET_UPDATE_INTERVAL = 7, - SM_CMD_FAIL = 255, -}; - -struct sm_get_sensor_count_req { -} __attribute__((packed)); - -struct sm_get_sensor_count_res { - uint8_t count; -} __attribute__((packed)); - -struct sm_get_value_req { - uint8_t sensor; -} __attribute__((packed)); - -struct sm_get_value_res { - uint16_t value; -} __attribute__((packed)); - -struct sm_set_warning_value_req { - uint8_t sensor; - uint16_t warning_value; -} __attribute__((packed)); - -struct sm_set_warning_value_res { -} __attribute__((packed)); - -struct sm_get_warning_value_req { - uint8_t sensor; -} __attribute__((packed)); - -struct sm_get_warning_value_res { - uint16_t warning_value; -} __attribute__((packed)); - -struct sm_set_sensor_name_req { - uint8_t sensor; - uint8_t length; - uint8_t name[SENSOR_NAME_LEN]; -} __attribute__((packed)); - -struct sm_set_sensor_name_res { -} __attribute__((packed)); - -struct sm_get_sensor_name_req { - uint8_t sensor; -} __attribute__((packed)); - -struct sm_get_sensor_name_res { - uint8_t length; - uint8_t name[SENSOR_NAME_LEN]; -} __attribute__((packed)); - -struct sm_set_update_interval_req { - uint8_t sensor; - uint8_t interval_in_seconds; -} __attribute__((packed)); - -struct sm_set_update_interval_res { -} __attribute__((packed)); - -#define SM_REQ_HEADER_SIZE 1 - -struct sm_req { - // header - uint8_t code; - - // body - union { - struct sm_get_sensor_count_req get_sensor_count; - struct sm_get_value_req get_value; - struct sm_set_warning_value_req set_warning_value; - struct sm_get_warning_value_req get_warning_value; - struct sm_set_sensor_name_req set_sensor_name; - struct sm_get_sensor_name_req get_sensor_name; - struct sm_set_update_interval_req set_update_interval; - } __attribute__((packed)); -} __attribute__((packed)); - -#define SM_RES_HEADER_SIZE 1 - -struct sm_res { - // header - uint8_t code; - - // body - union { - struct sm_get_sensor_count_res get_sensor_count; - struct sm_get_value_res get_value; - struct sm_set_warning_value_res set_warning_value; - struct sm_get_warning_value_res get_warning_value; - struct sm_set_sensor_name_res set_sensor_name; - struct sm_get_sensor_name_res get_sensor_name; - struct sm_set_update_interval_res set_update_interval; - } __attribute__((packed)); -} __attribute__((packed)); - -#ifndef SM_DEBUG -#define SM_DEBUG 1 -#endif - -#if SM_DEBUG == 1 - -void write_req(struct sm_req const &req); - -void write_res(struct sm_res const &res); - -#endif - -#endif diff --git a/include/ble/ByteBuffer.h b/include/ble/ByteBuffer.h index f884d6e..74a1bf7 100644 --- a/include/ble/ByteBuffer.h +++ b/include/ble/ByteBuffer.h @@ -39,8 +39,9 @@ public: return end - ptr; } - inline void setCursor(size_t newCursor) { + inline ByteBuffer &setCursor(size_t newCursor) { ptr = (uint8_t *) &zero[newCursor]; + return *this; } inline void skip(size_t length) { @@ -52,8 +53,8 @@ public: ByteBuffer &write16le(uint16_t value); /** - * Appends the entire buffer. Make a view if you want to write a part of it. - */ + * Appends the entire buffer. Make a view if you want to write a part of it. + */ ByteBuffer &write(const ByteBuffer &value); ByteBuffer &write(const uint8_t *bytes, size_t len); -- cgit v1.2.3