From c83b35d6456c8a77e5b8f6a08c9262122c3cbcfc Mon Sep 17 00:00:00 2001 From: Trygve Laugstøl Date: Mon, 19 Nov 2018 22:09:59 +0100 Subject: ByteBuffer: o Reducing silliness, no allocations by ByteBuffer. o Create StaticByteBuffer as a nice one-liner to create a buffer. LinuxBluetooth: methods that want a buffer needs to pass it in, ByteBuffer is not allocating anymore. --- apps/SoilMoisture.cpp | 69 +++++++++++++++++++++------------------- apps/SoilMoisture.h | 2 +- apps/ble-inspect-device.cpp | 2 +- apps/ble-read-characteristic.cpp | 69 +++++++++++++++++++++++++++++++++------- ble/ByteBuffer.cpp | 17 +++++----- ble/LinuxBluetooth.cpp | 30 +++++++++-------- ble/misc.cpp | 2 +- include/ble/Bluetooth.h | 2 +- include/ble/ByteBuffer.h | 29 ++++++++++------- 9 files changed, 142 insertions(+), 80 deletions(-) diff --git a/apps/SoilMoisture.cpp b/apps/SoilMoisture.cpp index 03aeb00..79f168f 100644 --- a/apps/SoilMoisture.cpp +++ b/apps/SoilMoisture.cpp @@ -22,42 +22,43 @@ using namespace trygvis::bluetooth; using std::to_string; static -ByteBuffer createGetSensorCount() { - return ByteBuffer::alloc(100) // +void createGetSensorCount(ByteBuffer &buffer) { + buffer .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)) // +void createGetValue(ByteBuffer &buffer, uint8_t sensor) { + buffer + .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) +void createSetWarningValue(ByteBuffer &buffer, uint8_t sensor, uint16_t warning_value) { + buffer .write8(static_cast(sm_cmd_code::SM_CMD_SET_WARNING_VALUE)) .write8(sensor) .write16le(warning_value); } static -ByteBuffer createSetSensorName(uint8_t sensor, string name) { - return ByteBuffer::alloc(100) +void createSetSensorName(ByteBuffer &buffer, uint8_t sensor, string name) { + buffer .write8(static_cast(sm_cmd_code::SM_CMD_SET_SENSOR_NAME)) .write8(sensor) .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); +void createGetSensorName(ByteBuffer &buffer, uint8_t sensor) { + buffer + .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) +void createSetUpdateInterval(ByteBuffer buffer, uint8_t sensor, uint8_t interval_in_seconds) { + buffer .write8(static_cast(sm_cmd_code::SM_CMD_SET_UPDATE_INTERVAL)) .write8(sensor) .write8(interval_in_seconds); @@ -93,47 +94,49 @@ SoilMoisture::SoilMoisture(const shared_ptr &gatt, const o temperatureCharacteristic, const o lightCharacteristic) : gatt(gatt), s(s), soilMoistureCharacteristic(soilMoistureCharacteristic), - temperatureCharacteristic(temperatureCharacteristic), lightCharacteristic(lightCharacteristic) { } + temperatureCharacteristic(temperatureCharacteristic), lightCharacteristic(lightCharacteristic) {} -ByteBuffer SoilMoisture::writeAndRead(const BluetoothGattCharacteristicPtr &c, ByteBuffer &requestBytes) { - requestBytes.setCursor(0); +void SoilMoisture::writeAndRead(const BluetoothGattCharacteristicPtr &c, ByteBuffer &buffer) { + buffer.setCursor(0); - uint8_t expectedCode = requestBytes.peek8(0); + uint8_t expectedCode = buffer.peek8(0); - gatt->writeValue(c, requestBytes); + gatt->writeValue(c, buffer); - auto responseBytes = gatt->readValue(c); + gatt->readValue(c, buffer); - if (responseBytes.getSize() < 1) { - throw runtime_error("Unexpected number of bytes read: " + to_string(responseBytes.getSize())); + if (buffer.getSize() < 1) { + throw runtime_error("Unexpected number of bytes read: " + to_string(buffer.getSize())); } - uint8_t actualCode = responseBytes.read8(); + uint8_t actualCode = buffer.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(soilMoistureCharacteristic, buffer).read8(); + StaticByteBuffer<100> buffer; + createGetSensorCount(buffer); + writeAndRead(soilMoistureCharacteristic, buffer); + return buffer.read8(); } uint16_t SoilMoisture::getValue(uint8_t sensor) { - auto req = createGetValue(sensor); + StaticByteBuffer<100> buffer; + createGetValue(buffer, sensor); - auto buffer = writeAndRead(soilMoistureCharacteristic, req); + writeAndRead(soilMoistureCharacteristic, buffer); buffer.read8(); // sensor index return buffer.read16le(); } string SoilMoisture::getName(uint8_t sensor) { - auto req = createGetSensorName(sensor); + StaticByteBuffer<100> buffer; + createGetSensorName(buffer, sensor); - auto buffer = writeAndRead(soilMoistureCharacteristic, req); + writeAndRead(soilMoistureCharacteristic, buffer); size_t bytesLeft = buffer.getBytesLeft(); uint8_t bytes[bytesLeft]; buffer.copy(bytes, bytesLeft); @@ -158,7 +161,8 @@ o SoilMoisture::readTemperature() { return o(); } - auto responseBytes = gatt->readValue(*temperatureCharacteristic); + StaticByteBuffer<100> responseBytes; + gatt->readValue(*temperatureCharacteristic, responseBytes); if (responseBytes.getSize() < 2) { throw runtime_error("Unexpected number of bytes read: " + to_string(responseBytes.getSize())); @@ -180,7 +184,8 @@ void SoilMoisture::setLight(uint8_t light, uint8_t value) { return; } - auto responseBytes = gatt->readValue(*lightCharacteristic); + StaticByteBuffer<100> responseBytes; + gatt->readValue(*lightCharacteristic, responseBytes); if (responseBytes.getSize() < 2) { throw runtime_error("Unexpected number of bytes read: " + to_string(responseBytes.getSize())); diff --git a/apps/SoilMoisture.h b/apps/SoilMoisture.h index 499c9f6..3bfd0d8 100644 --- a/apps/SoilMoisture.h +++ b/apps/SoilMoisture.h @@ -50,7 +50,7 @@ private: const o temperatureCharacteristic, const o lightCharacteristic); - ByteBuffer writeAndRead(const BluetoothGattCharacteristicPtr &c, ByteBuffer &requestBytes); + void writeAndRead(const BluetoothGattCharacteristicPtr &c, ByteBuffer &requestBytes); shared_ptr gatt; shared_ptr s; diff --git a/apps/ble-inspect-device.cpp b/apps/ble-inspect-device.cpp index a06d86a..c07879b 100644 --- a/apps/ble-inspect-device.cpp +++ b/apps/ble-inspect-device.cpp @@ -27,7 +27,7 @@ public: } void with_device(const shared_ptr &device) { - cout << "Inspecting device: " << device->getMac().str() << endl; + cout << "Connecting to device: " << device->getMac().str() << endl; auto gatt = device->connectGatt(); cout << "Connected, discovering services" << endl; diff --git a/apps/ble-read-characteristic.cpp b/apps/ble-read-characteristic.cpp index 0aa5fdc..19bbfa3 100644 --- a/apps/ble-read-characteristic.cpp +++ b/apps/ble-read-characteristic.cpp @@ -12,24 +12,63 @@ using namespace std; using namespace trygvis::bluetooth; using namespace trygvis::apps; -class ble_inspect_device : public app { +namespace { +enum class op { + READ, NOTIFY, LISTEN +}; + +std::istream &operator>>(std::istream &in, op &op) { + std::string token; + in >> token; + if (token == "read") { + op = op::READ; + } else if (token == "notify") { + op = op::NOTIFY; + } else if (token == "listen") { + op = op::LISTEN; + } else { + in.setstate(std::ios_base::failbit); + } + return in; +} + +std::ostream &operator<<(std::ostream &out, const op op) { + if (op == op::READ) { + out << "read"; + } else if (op == op::NOTIFY) { + out << "notify"; + } else if (op == op::LISTEN) { + out << "listen"; + } else { + out.setstate(std::ios_base::failbit); + } + return out; +} +} + +class ble_read_characteristic : public app { public: - ble_inspect_device() : app("ble-inspect-device") {} + ble_read_characteristic() : app("ble-read-characteristic") {} - ~ble_inspect_device() override = default; + ~ble_read_characteristic() override = default; - string adapter_name; + string adapter_name = "0"; + enum op op_mode = op::READ; void add_options(po::options_description_easy_init &options) override { - auto adapter_value = po::value<>(&adapter_name)->default_value("0"); + auto adapter_value = po::value<>(&adapter_name)->default_value(adapter_name); options("adapter", adapter_value, "Which adapter to use."); options("device", po::value()->required(), "The MAC of the device to inspect"); options("service", po::value()->required(), "The UUID of the service to read"); options("characteristic", po::value()->required(), "The UUID of the characteristic to read"); + + auto mode_value = po::value<>(&op_mode)->default_value(op_mode); + options("mode", mode_value, "Operation mode"); } - int with_device(const shared_ptr &device, const Uuid &service_uuid, const Uuid &characteristic_uuid) { - cout << "Inspecting device: " << device->getMac().str() << endl; + int with_device(const shared_ptr &device, const Uuid &service_uuid, + const Uuid &characteristic_uuid) { + cout << "Connecting to device: " << device->getMac().str() << endl; auto gatt = device->connectGatt(); cout << "Connected, discovering services" << endl; @@ -52,7 +91,14 @@ public: auto characteristic = characteristicO.value(); - gatt->readValue(characteristic); + if (op_mode == op::READ) { + cout << "Reading data" << endl; + + StaticByteBuffer<100> buf; + auto response = gatt->readValue(characteristic, buf); + + cout << "Got data, size=" << response.getSize() << endl; + } return EXIT_SUCCESS; } @@ -84,11 +130,12 @@ public: } } }; -} -} + +} // namespace apps +} // namespace trygvis int main(int argc, const char *argv[]) { using namespace trygvis::apps; - return real_main(new ble_inspect_device(), argc, argv); + return real_main(new ble_read_characteristic(), argc, argv); } diff --git a/ble/ByteBuffer.cpp b/ble/ByteBuffer.cpp index 1a294f1..40ba06c 100644 --- a/ble/ByteBuffer.cpp +++ b/ble/ByteBuffer.cpp @@ -7,13 +7,8 @@ #include #include - using namespace std; -ByteBuffer ByteBuffer::alloc(std::size_t size) { - return {new uint8_t[size], size}; -} - ByteBuffer::ByteBuffer(uint8_t* bytes, size_t size) : zero(bytes), end_(&bytes[size]), cursor(bytes) { } @@ -47,7 +42,7 @@ ByteBuffer &ByteBuffer::write(const ByteBuffer &value) { ByteBuffer &ByteBuffer::write(const uint8_t *bytes, size_t len) { assertCanAccessRelative(len); - memcpy(cursor, bytes, len); + std::memcpy(cursor, bytes, len); cursor += len; @@ -174,7 +169,13 @@ double ByteBuffer::readFLOAT() { void ByteBuffer::copy(uint8_t *bytes, size_t length) const { assertCanAccessRelative(length - 1); - memcpy(bytes, cursor, length); + std::memcpy(bytes, cursor, length); +} + +void ByteBuffer::copy(ByteBuffer& other) const { + other.assertCanAccessRelative(getBytesLeft()); + + std::memcpy(other.cursor, cursor, getBytesLeft()); } void ByteBuffer::reset() { @@ -182,7 +183,7 @@ void ByteBuffer::reset() { } ByteBuffer ByteBuffer::view() const { -// DF << "cursor=" << getCursor() << ", size=" << getSize() << ", new size=" << end_ - cursor << ", cursor=" << (uint64_t) cursor << ", zero=" << (uint64_t) zero; +// LOG_DEBUG("cursor=" << getCursor() << ", size=" << getSize() << ", new size=" << end_ - cursor << ", cursor=" << (uint64_t) cursor << ", zero=" << (uint64_t) zero); return {cursor, getBytesLeft()}; } diff --git a/ble/LinuxBluetooth.cpp b/ble/LinuxBluetooth.cpp index e567d62..d3fe80b 100644 --- a/ble/LinuxBluetooth.cpp +++ b/ble/LinuxBluetooth.cpp @@ -103,7 +103,7 @@ public: void writeValue(const BluetoothGattCharacteristicPtr &c, const ByteBuffer &bytes) override; - ByteBuffer readValue(const BluetoothGattCharacteristicPtr &c) override; + ByteBuffer readValue(const BluetoothGattCharacteristicPtr &c, ByteBuffer& response) override; private: void connect(); @@ -116,7 +116,7 @@ private: void writeL2cap(ByteBuffer &buffer); - void writeAndRead(ByteBuffer &buffer); + void writeAndRead(const ByteBuffer &buffer, ByteBuffer& response); AttVariant processAvailableMessages(ByteBuffer &buffer); @@ -276,28 +276,30 @@ void LinuxBluetoothGatt::writeValue(const BluetoothGattCharacteristicPtr &c, con AttPdu::makeWrite(buffer, c->getValueHandle(), bytes); - writeAndRead(buffer); + writeAndRead(buffer, buffer); AttPdu::parseWrite(buffer); } -ByteBuffer LinuxBluetoothGatt::readValue(const BluetoothGattCharacteristicPtr &c) { +ByteBuffer LinuxBluetoothGatt::readValue(const BluetoothGattCharacteristicPtr &c, ByteBuffer& response) { uint8_t b[mtu]; ByteBuffer buffer{b, mtu}; AttPdu::makeRead(buffer, c->getValueHandle()); - writeAndRead(buffer); + writeAndRead(buffer, response); - AttPdu::parseRead(buffer); + auto cursor = response.getCursor(); + response.setCursor(0); -// D << "READ response has " + to_string(in.getBytesLeft()) + " bytes"; + AttPdu::parseRead(response); - auto response = buffer.view(); + auto view = response.view(cursor - response.getCursor()); - LOG_DEBUG("Value of characteristic " << c->getUuid() << "=" << response.toString()); + LOG_DEBUG("READ response has " + to_string(view.getSize()) + " bytes"); + LOG_DEBUG("Value of characteristic " << c->getUuid() << "=" << view.toString()); - return response; + return view; } void LinuxBluetoothGatt::discoverServices() { @@ -383,7 +385,7 @@ void LinuxBluetoothGatt::discoverServices() { } while (startHandle != 0xffff); } -void LinuxBluetoothGatt::writeAndRead(ByteBuffer &buffer) { +void LinuxBluetoothGatt::writeAndRead(const ByteBuffer &buffer, ByteBuffer& response) { // LOG_DEBUG("pdu size=" << out.getCursor()); auto to_be_written = buffer.getCursor(); @@ -396,14 +398,14 @@ void LinuxBluetoothGatt::writeAndRead(ByteBuffer &buffer) { // LOG_DEBUG("written=" << written); - buffer.reset(); - ssize_t r = read(l2cap, buffer.begin(), buffer.getBytesLeft()); + ssize_t r = read(l2cap, response.begin(), response.getSize()); if (r == -1) { throw BluetoothException(&device, "read(): " + errnoAsString()); } -// LOG_DEBUG("read: " << r << " bytes: " << buffer.toString()); + LOG_DEBUG("read: " << r << " bytes: " << response.toString()); + response.setCursor(static_cast(r)); } void LinuxBluetoothGatt::writeL2cap(ByteBuffer &buffer) { diff --git a/ble/misc.cpp b/ble/misc.cpp index a8df2cb..a4f4b57 100644 --- a/ble/misc.cpp +++ b/ble/misc.cpp @@ -50,7 +50,7 @@ o Uuid::fromString(const std::string &str) { } auto tmp = str.substr(i, 2); - cout << "str=" << tmp << endl; + // cout << "str=" << tmp << endl; unsigned long x = std::stoul(tmp, nullptr, 16); if (x > std::numeric_limits::max()) { diff --git a/include/ble/Bluetooth.h b/include/ble/Bluetooth.h index 477bd29..d95d843 100644 --- a/include/ble/Bluetooth.h +++ b/include/ble/Bluetooth.h @@ -129,7 +129,7 @@ public: virtual void writeValue(const BluetoothGattCharacteristicPtr &c, const ByteBuffer &bytes) = 0; - virtual ByteBuffer readValue(const BluetoothGattCharacteristicPtr &c) = 0; + virtual ByteBuffer readValue(const BluetoothGattCharacteristicPtr &c, ByteBuffer& response) = 0; virtual void discoverServices() = 0; diff --git a/include/ble/ByteBuffer.h b/include/ble/ByteBuffer.h index 5e904c2..09deca5 100644 --- a/include/ble/ByteBuffer.h +++ b/include/ble/ByteBuffer.h @@ -1,13 +1,9 @@ #ifndef BYTE_STREAM_WRAPPER_H #define BYTE_STREAM_WRAPPER_H -#include #include -#include -#include #include #include -#include namespace FLOAT { static const uint32_t positive_infinity = 0x007FFFFE; @@ -38,8 +34,6 @@ public: class ByteBuffer { public: - static ByteBuffer alloc(std::size_t capacity); - template explicit ByteBuffer(uint8_t (&bytes)[N]) : zero(bytes), end_(&bytes[N]), cursor(bytes) {} @@ -58,7 +52,9 @@ public: } inline ByteBuffer &setCursor(size_t newCursor) { - cursor = (uint8_t *) &zero[newCursor]; + auto tmp = (uint8_t *) &zero[newCursor]; + assertCanAccessIndex(tmp); + cursor = tmp; return *this; } @@ -66,19 +62,19 @@ public: cursor += length; } - inline const uint8_t *cbegin() { + inline const uint8_t *cbegin() const { return zero; } - inline const uint8_t *cend() { + inline const uint8_t *cend() const { return end_; } - inline uint8_t *begin() { + inline uint8_t *begin() const { return const_cast(zero); } - inline uint8_t *end() { + inline uint8_t *end() const { return const_cast(end_); } @@ -120,6 +116,8 @@ public: void copy(uint8_t *bytes, size_t length) const; + void copy(ByteBuffer& other) const; + void reset(); /** @@ -147,4 +145,13 @@ private: uint8_t *cursor; }; +template +class StaticByteBuffer : public ByteBuffer { +public: + StaticByteBuffer() : ByteBuffer(raw) {} + +private: + uint8_t raw[N] = {}; +}; + #endif -- cgit v1.2.3