From 25d82b0c52120c81cfed5bc1f245408f08203b7b Mon Sep 17 00:00:00 2001 From: Trygve Laugstøl Date: Thu, 30 Aug 2018 22:17:06 +0200 Subject: Fixing lots of small nits: o boost::uuid didn't give much, use our own and add new short uuid type. o Fixing nits from clang-tidy. --- apps/CMakeLists.txt | 1 + apps/SoilMoisture.cpp | 16 ++--- apps/SoilMoisture.h | 4 +- apps/ble-bts.cpp | 108 +++++++++++++++++++++++++++++++++ apps/ble-inspect-device.cpp | 2 +- apps/sm-get-value.cpp | 4 +- ble/Bluetooth.cpp | 52 +++++++--------- ble/BluetoothImpl.h | 77 +++++++++++------------- ble/LinuxBluetooth.cpp | 83 ++++++++++--------------- include/ble/Bluetooth.h | 143 ++++++++++++++++++++++++++++++++++---------- 10 files changed, 325 insertions(+), 165 deletions(-) create mode 100644 apps/ble-bts.cpp diff --git a/apps/CMakeLists.txt b/apps/CMakeLists.txt index 8f8feb3..6491ef1 100644 --- a/apps/CMakeLists.txt +++ b/apps/CMakeLists.txt @@ -100,6 +100,7 @@ endfunction() add_app(NAME ble-inspect-device) add_app(NAME ble-scan) +add_app(NAME ble-bts) add_app(NAME sample-add-timestamp) add_app(NAME sample-convert) add_app(NAME sample-select) diff --git a/apps/SoilMoisture.cpp b/apps/SoilMoisture.cpp index 4b9dfe5..d92752d 100644 --- a/apps/SoilMoisture.cpp +++ b/apps/SoilMoisture.cpp @@ -7,16 +7,16 @@ namespace sensor { #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}; +Uuid trygvis_io_base_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}; +Uuid bluetooth_base_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); -const boost::uuids::uuid light_characteristic = makeUuid(trygvis_io_base_uuid, 0x00, 0x12); +const Uuid soil_moisture_service = makeUuid(trygvis_io_base_uuid, 0x00, 0x10); +const Uuid soil_moisture_characteristic = makeUuid(trygvis_io_base_uuid, 0x00, 0x11); +const Uuid temperature_characteristic = makeUuid(bluetooth_base_uuid, 0x2a, 0x1e); +const Uuid light_characteristic = makeUuid(trygvis_io_base_uuid, 0x00, 0x12); using namespace trygvis::bluetooth; diff --git a/apps/SoilMoisture.h b/apps/SoilMoisture.h index 0ad1d15..499c9f6 100644 --- a/apps/SoilMoisture.h +++ b/apps/SoilMoisture.h @@ -24,8 +24,8 @@ enum class sm_cmd_code : uint8_t { SM_CMD_FAIL = 255, }; -extern const boost::uuids::uuid soil_moisture_service; -extern const boost::uuids::uuid soil_moisture_characteristic; +extern const Uuid soil_moisture_service; +extern const Uuid soil_moisture_characteristic; class SoilMoisture { public: diff --git a/apps/ble-bts.cpp b/apps/ble-bts.cpp new file mode 100644 index 0000000..1e76f60 --- /dev/null +++ b/apps/ble-bts.cpp @@ -0,0 +1,108 @@ +#include "ble/Bluetooth.h" +#include "apps.h" + +#include +#include "apps.h" + +namespace trygvis { +namespace apps { + +using namespace std; +using namespace trygvis::bluetooth; +using namespace trygvis::apps; + +namespace ble_bts_utils { + +static std::function onSignal; + +static void signal_handler(int signal) { + onSignal(signal); +} +} + +class ble_bts : public app { +public: + ble_bts() : app("ble-scan") {} + + ~ble_bts() override = default; + + string adapter_name; + + void add_options(po::options_description_easy_init &options) override { + auto adapter_value = po::value<>(&adapter_name)->default_value("0"); + options("adapter", adapter_value, "Which adapter to use."); + options("device", po::value()->required(), "The MAC of the device to inspect"); + } + + int main(app_execution &execution) override { + BluetoothSystem bluetoothSystem; + shared_ptr adapter; + + struct sigaction sigIntHandler{}; + + ble_bts_utils::onSignal = [&](int signal) { adapter->stopScan(); }; + + sigIntHandler.sa_handler = &ble_bts_utils::signal_handler; + sigemptyset(&sigIntHandler.sa_mask); + sigIntHandler.sa_flags = 0; + + sigaction(SIGINT, &sigIntHandler, nullptr); + + try { + adapter = bluetoothSystem.getAdapter(adapter_name); + + string mac_str = execution.vm["device"].as(); + Mac mac = Mac::parseMac(mac_str); + + auto device = adapter->getDevice(mac); + + auto gatt = device->connectGatt(); + cout << "Connected" << endl; + + auto bts = gatt->findService(uuids::HealthTermometerService); + if (!bts) { + cout << "Device does not implement Health thermometer service" << endl; + return EXIT_FAILURE; + } + + auto tmc = bts->get()->findCharacteristic(uuids::TemperatureMeasurement); + + if (!tmc) { + cout << "The device does not have temperature measurement characteristic" << endl; + return EXIT_FAILURE; + } + + with_connection(gatt, tmc.value()); + + return EXIT_SUCCESS; + } catch (std::runtime_error &ex) { + cout << "std::runtime_error: " << ex.what() << endl; + return EXIT_FAILURE; + } catch (std::exception &ex) { + cout << "std::exception: " << ex.what() << endl; + return EXIT_FAILURE; + } + } + + void with_connection(BluetoothGattPtr gatt, BluetoothGattCharacteristicPtr tmc) { + auto svc = tmc->getService(); + + cout << "Reading temp value" << endl; + + auto buf = gatt->readValue(tmc); + + cout << "bytes " << buf.getSize() << endl; + + for (int i = 0; i < buf.getSize(); i++) { + cout << "byte " << i << " = " << hex << buf.get8(i) << endl; + } + } +}; +} +} + +int main(int argc, const char *argv[]) { + using namespace trygvis::apps; + + return real_main(new ble_bts(), argc, argv); +} diff --git a/apps/ble-inspect-device.cpp b/apps/ble-inspect-device.cpp index baee93a..8f85e5c 100644 --- a/apps/ble-inspect-device.cpp +++ b/apps/ble-inspect-device.cpp @@ -16,7 +16,7 @@ class ble_inspect_device : public app { public: ble_inspect_device() : app("ble-inspect-device") {} - ~ble_inspect_device() = default; + ~ble_inspect_device() override = default; void add_options(po::options_description_easy_init &options) override { options("device", po::value()->required(), "The MAC of the device to inspect"); diff --git a/apps/sm-get-value.cpp b/apps/sm-get-value.cpp index 483df70..eb7a141 100644 --- a/apps/sm-get-value.cpp +++ b/apps/sm-get-value.cpp @@ -153,7 +153,7 @@ public: } // If the user didn't specify any sensors, add all. - if (sensors.size() == 0) { + if (sensors.empty()) { for (unsigned int i = 0; i < sensorCount; i++) { sensorIndexes.push_back(i); } @@ -165,7 +165,7 @@ public: return; } - sensors.push_back(make_pair(i, soilMoisture.getName(i))); + sensors.emplace_back(make_pair(i, soilMoisture.getName(i))); }); } auto mac = gatt->getDevice().getMac().str(); diff --git a/ble/Bluetooth.cpp b/ble/Bluetooth.cpp index 13c81b3..4160acc 100644 --- a/ble/Bluetooth.cpp +++ b/ble/Bluetooth.cpp @@ -71,14 +71,14 @@ AttPduType AttPdu::getType() { return (AttPduType) bytes.get8(0); } -void AttPdu::makeReadByGroupType(ByteBuffer &bytes, uint16_t startHandle, uint16_t endHandle, SpecUuid uuid) { +void AttPdu::makeReadByGroupType(ByteBuffer &bytes, uint16_t startHandle, uint16_t endHandle, ShortUuid uuid) { bytes.write8(AttPduType::READ_BY_GROUP_TYPE_REQ); bytes.write16le(startHandle); bytes.write16le(endHandle); bytes.write16le(uuid.value); } -void AttPdu::makeReadByType(ByteBuffer &bytes, uint16_t startHandle, uint16_t endHandle, SpecUuid uuid) { +void AttPdu::makeReadByType(ByteBuffer &bytes, uint16_t startHandle, uint16_t endHandle, ShortUuid uuid) { bytes.write8(AttPduType::READ_BY_TYPE_REQ); bytes.write16le(startHandle); bytes.write16le(endHandle); @@ -99,14 +99,14 @@ void AttPdu::makeWrite(ByteBuffer &req, uint16_t handle, const ByteBuffer &bytes vector AttPdu::parse(ByteBuffer &bytes, AttPduType type) { // cout << "bytes: " << bytes.toString(); - AttPduType t = (AttPduType) bytes.read8(); + auto t = static_cast(bytes.read8()); - if (t == INVALID_HANDLE) { + if (t == ERROR) { return vector(); } if (t != type) { - throw BluetoothException("Unexpected type: " + to_string(t)); + throw BluetoothException("Unexpected type: " + to_string(t) + ", expected " + to_string(type)); } if (bytes.getSize() < 4) { @@ -138,11 +138,13 @@ vector AttPdu::parseReadByType(ByteBuffer &bytes) { return parse(bytes, READ_BY_TYPE_RES); } +static uint16_t parseExchangeMtuReq(ByteBuffer &bytes); + void AttPdu::parseRead(ByteBuffer &bytes) { AttPduType t = (AttPduType) bytes.read8(); if (t != READ_RES) { - throw BluetoothException("Unexpected type: " + to_string(t)); + throw BluetoothException("Unexpected type: " + to_string(t) + ", expected " + to_string(READ_RES)); } } @@ -150,7 +152,7 @@ void AttPdu::parseWrite(ByteBuffer &bytes) { AttPduType t = (AttPduType) bytes.read8(); if (t != WRITE_RES) { - throw BluetoothException("Unexpected type: " + to_string(t)); + throw BluetoothException("Unexpected type: " + to_string(t) + ", expected " + to_string(WRITE_RES)); } } @@ -168,45 +170,36 @@ AttributeData::AttributeData(uint16_t handle, ByteBuffer value) : handle(handle), value(value) { } -AttributeData::~AttributeData() { -} +AttributeData::~AttributeData() = default; // ----------------------------------------------------------------------- // Gatt // ----------------------------------------------------------------------- -BluetoothGatt::BluetoothGatt() { -} +BluetoothGatt::BluetoothGatt() = default; -BluetoothGatt::~BluetoothGatt() { -} +BluetoothGatt::~BluetoothGatt() = default; // ----------------------------------------------------------------------- // Device // ----------------------------------------------------------------------- -BluetoothDevice::BluetoothDevice() { -} +BluetoothDevice::BluetoothDevice() = default; -BluetoothDevice::~BluetoothDevice() { -} +BluetoothDevice::~BluetoothDevice() = default; // ----------------------------------------------------------------------- // Adapter // ----------------------------------------------------------------------- -BluetoothAdapter::BluetoothAdapter() { -} - -BluetoothAdapter::~BluetoothAdapter() { -} +BluetoothAdapter::BluetoothAdapter() = default; +BluetoothAdapter::~BluetoothAdapter() = default; // ----------------------------------------------------------------------- // Bluetooth System. This is not sub-classed by implementations. // ----------------------------------------------------------------------- -BluetoothSystem::BluetoothSystem() { -} +BluetoothSystem::BluetoothSystem() = default; BluetoothSystem::~BluetoothSystem() { adapters.clear(); @@ -223,11 +216,12 @@ shared_ptr BluetoothSystem::getAdapter(string name) { return it->second; } -uuid_t makeUuid(const uuid_t base, uint8_t a, uint8_t b) { - uuid_t c = base; - c.data[2] = a; - c.data[3] = b; - return c; +Uuid makeUuid(const Uuid &base, uint8_t a, uint8_t b) { + uint8_t value[16]; + memcpy(value, base.value, 16); + value[2] = a; + value[3] = b; + return Uuid{value}; } } diff --git a/ble/BluetoothImpl.h b/ble/BluetoothImpl.h index 8663b20..c660b4b 100644 --- a/ble/BluetoothImpl.h +++ b/ble/BluetoothImpl.h @@ -25,14 +25,13 @@ namespace trygvis { namespace bluetooth { // Utility typedefs -typedef boost::uuids::uuid uuid_t; using namespace log4cplus; // Logging class LogSetup { public: - LogSetup(std::string name) : logger(Logger::getInstance(LOG4CPLUS_TEXT(name))) { + explicit LogSetup(const std::string &name) : logger(Logger::getInstance(LOG4CPLUS_TEXT(name))) { } protected: @@ -61,7 +60,7 @@ struct constify2 { template class CollectionImpl : public Collection { public: - CollectionImpl(B &b) : b(b) { + explicit CollectionImpl(B &b) : b(b) { } private: @@ -70,47 +69,46 @@ private: class DefaultBluetoothGattCharacteristic : protected LogSetup, public BluetoothGattCharacteristic { public: - DefaultBluetoothGattCharacteristic(const BluetoothGattServicePtr &service, uint16_t handle, uuid_t uuid, + DefaultBluetoothGattCharacteristic(const BluetoothGattServicePtr &service, uint16_t handle, Uuid uuid, uint8_t properties, uint16_t valueHandle) - : LogSetup("BluetoothGattCharacteristic"), service(service), handle(handle), uuid(uuid), - properties(properties), valueHandle(valueHandle) { + : LogSetup("BluetoothGattCharacteristic"), service(service), handle(handle), uuid(uuid), + properties(properties), valueHandle(valueHandle) { } - virtual ~DefaultBluetoothGattCharacteristic() { - } + ~DefaultBluetoothGattCharacteristic() override = default; - BluetoothGattServicePtr getService() const { + BluetoothGattServicePtr getService() const override { return service; } - uint16_t getHandle() const { + uint16_t getHandle() const override { return handle; } - const uuid_t getUuid() const { + const Uuid getUuid() const override { return uuid; } - uint8_t getProperties() const { + uint8_t getProperties() const override { return properties; } - uint16_t getValueHandle() const { + uint16_t getValueHandle() const override { return valueHandle; } protected: BluetoothGattServicePtr service; uint16_t handle; - uuid_t uuid; + Uuid uuid; uint8_t properties; uint16_t valueHandle; }; -template +template class DefaultBluetoothGattService : public BluetoothGattService { public: - DefaultBluetoothGattService(DeviceType &device, const uuid_t uuid, const uint16_t handle, + DefaultBluetoothGattService(DeviceType &device, const Uuid uuid, const uint16_t handle, const uint16_t endGroupHandle) : device(device), uuid(uuid), handle(handle), endGroupHandle(endGroupHandle) { } @@ -122,48 +120,47 @@ public: endGroupHandle(std::move(o.endGroupHandle)), characteristics(std::move(o.characteristics)) { } - virtual ~DefaultBluetoothGattService() { - } + ~DefaultBluetoothGattService() override = default; - virtual BluetoothDevice &getDevice() const { + BluetoothDevice &getDevice() const override { return device; } - virtual uuid_t getUuid() const { + Uuid getUuid() const override { return uuid; } - virtual uint16_t getHandle() const { + uint16_t getHandle() const override { return handle; } - virtual uint16_t getEndGroupHandle() const { + uint16_t getEndGroupHandle() const override { return endGroupHandle; } - virtual vector> getCharacteristics() const { + vector> getCharacteristics() const override { vector> cs(characteristics.size()); std::copy(begin(characteristics), end(characteristics), begin(cs)); return cs; } - virtual void addCharacteristic(shared_ptr &&characteristic) { + virtual void addCharacteristic(shared_ptr &&characteristic) { characteristics.emplace_back(characteristic); } - virtual o> findCharacteristic(uuid_t uuid) { + o> findCharacteristic(Uuid uuid) override { for (auto &c: characteristics) { - if (memcmp(c->getUuid().data, uuid.data, 16) == 0) { - return o>(c); + if (c->getUuid() == uuid) { + return {c}; } } - return o>(); + return {}; } protected: DeviceType &device; - const uuid_t uuid; + const Uuid uuid; const uint16_t handle; const uint16_t endGroupHandle; vector> characteristics; @@ -172,7 +169,7 @@ protected: template class DefaultBluetoothGatt : protected LogSetup, public BluetoothGatt { public: - virtual _D &getDevice() const { + _D &getDevice() const override { return device; } @@ -180,15 +177,15 @@ public: // return CollectionImpl>(services); // } - virtual vector> getServices() const { + vector> getServices() const override { vector> ss(services.size()); std::copy(begin(services), end(services), begin(ss)); return ss; } - virtual o findService(uuid_t uuid) { + o findService(Uuid uuid) override { for (auto &s: services) { - if (memcmp(s->getUuid().data, uuid.data, 16) == 0) { + if (s->getUuid() == uuid) { return o>(s); } } @@ -201,12 +198,10 @@ public: } protected: - DefaultBluetoothGatt(_D &device) : LogSetup("BluetoothGatt"), device(device) { + explicit DefaultBluetoothGatt(_D &device) : LogSetup("BluetoothGatt"), device(device) { } - virtual ~DefaultBluetoothGatt() { -// removeServices(); - } + ~DefaultBluetoothGatt() override = default; void removeServices() { // for (auto s: services) { @@ -223,11 +218,11 @@ template class DefaultBluetoothDevice : protected LogSetup, public BluetoothDevice { public: - virtual Mac const &getMac() override { + Mac const &getMac() override { return mac; } - virtual A &getAdapter() override { + A &getAdapter() override { return adapter; } @@ -240,7 +235,7 @@ protected: LogSetup("BluetoothDevice"), adapter(std::move(o.adapter)), mac(std::move(o.mac)) { } - virtual ~DefaultBluetoothDevice() { + ~DefaultBluetoothDevice() override { removeServices(); } @@ -259,7 +254,7 @@ protected: class DefaultBluetoothAdapter : protected LogSetup, public BluetoothAdapter { public: protected: - DefaultBluetoothAdapter(Mac &mac) : + explicit DefaultBluetoothAdapter(Mac &mac) : LogSetup("BluetoothAdapter"), mac(mac) { } diff --git a/ble/LinuxBluetooth.cpp b/ble/LinuxBluetooth.cpp index d4073d1..7e7c9dc 100644 --- a/ble/LinuxBluetooth.cpp +++ b/ble/LinuxBluetooth.cpp @@ -28,9 +28,9 @@ class LinuxBluetoothAdapter; class LinuxBluetoothManager; -class LinuxBluetoothGattService : public DefaultBluetoothGattService { +class LinuxBluetoothGattService : public DefaultBluetoothGattService { public: - LinuxBluetoothGattService(LinuxBluetoothDevice &device, const uuid_t uuid, const uint16_t handle, + LinuxBluetoothGattService(LinuxBluetoothDevice &device, const Uuid uuid, const uint16_t handle, const uint16_t endGroupHandle) : DefaultBluetoothGattService(device, uuid, handle, endGroupHandle) { }; @@ -41,7 +41,7 @@ class LinuxBluetoothAdapter final : public DefaultBluetoothAdapter { public: LinuxBluetoothAdapter(int hciDeviceId, Mac &mac); - ~LinuxBluetoothAdapter(); + ~LinuxBluetoothAdapter() override; LinuxBluetoothAdapter(const LinuxBluetoothAdapter &) = delete; @@ -67,9 +67,9 @@ private: class LinuxBluetoothDevice final : public DefaultBluetoothDevice, public std::enable_shared_from_this { public: - LinuxBluetoothDevice(LinuxBluetoothAdapter &adapter, Mac &mac); + explicit LinuxBluetoothDevice(LinuxBluetoothAdapter &adapter, Mac &mac); - virtual ~LinuxBluetoothDevice(); + ~LinuxBluetoothDevice() override; LinuxBluetoothDevice(const LinuxBluetoothDevice &) = delete; @@ -83,9 +83,9 @@ private: class LinuxBluetoothGatt final : public DefaultBluetoothGatt { public: - LinuxBluetoothGatt(LinuxBluetoothDevice &device); + explicit LinuxBluetoothGatt(LinuxBluetoothDevice &device); - ~LinuxBluetoothGatt(); + ~LinuxBluetoothGatt() override; LinuxBluetoothGatt(const LinuxBluetoothGatt&) = delete; @@ -110,6 +110,7 @@ private: ByteBuffer writeAndRead(ByteBuffer &out, shared_ptr buffer, size_t size); + int l2cap; }; @@ -124,7 +125,7 @@ string errnoAsString() { // ----------------------------------------------------------------------- Mac parseMac(bdaddr_t &a) { - return Mac(a.b[5], a.b[4], a.b[3], a.b[2], a.b[1], a.b[0]); + return Mac{a.b[5], a.b[4], a.b[3], a.b[2], a.b[1], a.b[0]}; } // ----------------------------------------------------------------------- @@ -137,16 +138,13 @@ LinuxBluetoothDevice::LinuxBluetoothDevice(LinuxBluetoothAdapter &adapter, Mac & LinuxBluetoothDevice::~LinuxBluetoothDevice() { LOG_DEBUG("Closing device " << mac.str()); - if (gatt) { - delete gatt; - } + + delete gatt; }; shared_ptr LinuxBluetoothDevice::connectGatt() { // Make sure that we close the old connection and create a new one when the user asks for it. - if (gatt) { - delete gatt; - } + delete gatt; gatt = new LinuxBluetoothGatt(*this); @@ -158,7 +156,7 @@ shared_ptr LinuxBluetoothDevice::connectGatt() { // ----------------------------------------------------------------------- LinuxBluetoothGatt::LinuxBluetoothGatt(LinuxBluetoothDevice &device) : - DefaultBluetoothGatt(device) { + DefaultBluetoothGatt(device), l2cap() { connect(); } @@ -171,7 +169,7 @@ bool LinuxBluetoothGatt::isConnected() const { } void LinuxBluetoothGatt::connect() { - struct sockaddr_l2 addr; + struct sockaddr_l2 addr{}; LOG_DEBUG("connect: mac=" << device.getMac().str()); @@ -191,7 +189,7 @@ void LinuxBluetoothGatt::connect() { throw BluetoothException(&device, "bind(): " + errnoAsString()); } - struct bt_security btsec; + struct bt_security btsec{}; memset(&btsec, 0, sizeof(btsec)); btsec.level = BT_SECURITY_LOW; if (setsockopt(l2cap, SOL_BLUETOOTH, BT_SECURITY, &btsec, sizeof(btsec)) != 0) { @@ -225,40 +223,21 @@ void LinuxBluetoothGatt::disconnect() { close(l2cap); } -uuid_t readUuid(BluetoothDevice *device, const ByteBuffer &bytes) { +Uuid readUuid(BluetoothDevice *device, const ByteBuffer &bytes) { size_t bytesLeft = bytes.getBytesLeft(); - uuid_t u; - if (bytesLeft == 2) { uint8_t bs[16] = BLUETOOTH_UUID_INITIALIZER; bs[2] = bytes.get8(1); bs[3] = bytes.get8(0); - memcpy(&u, bs, 16); + + return Uuid(bs); } else if (bytesLeft == 16) { - uint8_t bs[16]; - bs[15] = bytes.get8(0); - bs[14] = bytes.get8(1); - bs[13] = bytes.get8(2); - bs[12] = bytes.get8(3); - bs[11] = bytes.get8(4); - bs[10] = bytes.get8(5); - bs[9] = bytes.get8(6); - bs[8] = bytes.get8(7); - bs[7] = bytes.get8(8); - bs[6] = bytes.get8(9); - bs[5] = bytes.get8(10); - bs[4] = bytes.get8(11); - bs[3] = bytes.get8(12); - bs[2] = bytes.get8(13); - bs[1] = bytes.get8(14); - bs[0] = bytes.get8(15); - memcpy(&u, bs, 16); + return {bytes.get8(0), bytes.get8(1), bytes.get8(2), bytes.get8(3), bytes.get8(4), bytes.get8(5), bytes.get8(6), bytes.get8(7), + bytes.get8(8), bytes.get8(9), bytes.get8(10), bytes.get8(11), bytes.get8(12), bytes.get8(13), bytes.get8(14), bytes.get8(15)}; } else { throw BluetoothException(device, "Unexpected bytes left: " + to_string(bytesLeft)); } - - return u; } void LinuxBluetoothGatt::writeValue(const BluetoothGattCharacteristicPtr &c, const ByteBuffer &bytes) { @@ -302,7 +281,7 @@ void LinuxBluetoothGatt::discoverServices() { vector values = discoverServices(startHandle); // Shouldn't happen, but you never know. - if (values.size() == 0) { + if (values.empty()) { break; } @@ -315,7 +294,7 @@ void LinuxBluetoothGatt::discoverServices() { // ", endGroupHandle: 0x" << hex << setw(4) << setfill('0') << endGroupHandle << // ", value: " << data.value.toString(); - uuid_t u = readUuid(&device, data.value); + auto u = readUuid(&device, data.value); addService(make_shared(device, u, data.handle, endGroupHandle)); } @@ -344,7 +323,7 @@ void LinuxBluetoothGatt::discoverServices() { do { vector values = discoverCharacteristics(startHandle, 0xffff); - if (values.size() == 0) { + if (values.empty()) { break; } @@ -360,7 +339,7 @@ void LinuxBluetoothGatt::discoverServices() { uint8_t properties = c.value.read8(); uint16_t valueHandle = c.value.read16le(); - uuid_t uuid = readUuid(&device, c.value); + auto uuid = readUuid(&device, c.value); // D << "characteristic: handle: " << setw(2) << setfill('0') << hex << (int) c.handle << // ", properties: " << setw(2) << setfill('0') << hex << (int) properties << @@ -435,7 +414,7 @@ vector LinuxBluetoothGatt::discoverCharacteristics(uint16_t start // ----------------------------------------------------------------------- LinuxBluetoothAdapter::LinuxBluetoothAdapter(int hciDeviceId, Mac &mac) : DefaultBluetoothAdapter(mac), - scanning(false) { + scanning(false), hciFilter() { LOG_DEBUG("hciDeviceId=" << hciDeviceId); this->hciDeviceId = hciDeviceId; @@ -466,7 +445,7 @@ LinuxBluetoothAdapter::~LinuxBluetoothAdapter() { } void LinuxBluetoothAdapter::startScan() { - struct hci_dev_info di; + struct hci_dev_info di{}; if (hci_devinfo(hciDeviceId, &di) < 0) { throw BluetoothException(this, "Could not query device info: " + errnoAsString()); @@ -541,11 +520,11 @@ void LinuxBluetoothAdapter::runScan(std::functionsubevent = " << std::hex << (int) metaEvent->subevent); if (metaEvent->subevent == EVT_LE_ADVERTISING_REPORT) { - le_advertising_info *advertisingInfo = (le_advertising_info *) (metaEvent->data + 1); + auto *advertisingInfo = (le_advertising_info *) (metaEvent->data + 1); Mac mac = parseMac(advertisingInfo->bdaddr); @@ -605,7 +584,7 @@ shared_ptr getAdapterImpl(string name) { throw BluetoothException("Bad device name: " + name); } - struct hci_dev_info di; + struct hci_dev_info di{}; if (hci_devinfo(hciDevice, &di) < 0) { throw BluetoothException("Could not query device info: " + errnoAsString()); } diff --git a/include/ble/Bluetooth.h b/include/ble/Bluetooth.h index d5875a5..abddc94 100644 --- a/include/ble/Bluetooth.h +++ b/include/ble/Bluetooth.h @@ -1,14 +1,15 @@ #ifndef BLUETOOTH_H #define BLUETOOTH_H -#include #include #include +#include #include #include #include #include #include +#include #include "ByteBuffer.h" @@ -19,44 +20,95 @@ using namespace std; template using o = std::experimental::optional; -struct SpecUuid { +struct Uuid { + uint8_t value[16]; + + explicit Uuid(uint8_t value[16]) noexcept : value() { + memcpy(this->value, value, 16); + } + + Uuid(uint8_t b0, uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4, uint8_t b5, uint8_t b6, uint8_t b7, + uint8_t b8, uint8_t b9, uint8_t b10, uint8_t b11, uint8_t b12, uint8_t b13, uint8_t b14, uint8_t b15) noexcept : value{ + b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b11, b12, b13, b14, b15} {} + + bool operator==(const Uuid &other) { + return std::memcmp(value, other.value, 16) == 0; + } + + bool operator==(const Uuid &other) const { + return std::memcmp(value, other.value, 16) == 0; + } + + friend std::ostream &operator<<(std::ostream &s, Uuid const &uuid) { + auto &v = uuid.value; + s << std::hex << + v[0] << v[1] << ":" << + v[2] << v[3] << ":" << + v[4] << v[5] << ":" << + v[6] << v[7] << ":" << + v[8] << v[9] << ":" << + v[10] << v[11] << ":" << + v[12] << v[13] << ":" << + v[14] << v[15] << ":" << + std::endl; + return s; + } + + static Uuid fromShort(uint8_t b2, uint8_t b3) { + return {0x00, 0x00, b2, b3, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb}; + } +}; + +struct ShortUuid { +private: public: - SpecUuid(uint16_t value) : value(value) { + explicit ShortUuid(uint16_t value) : value(value) {} + + Uuid toLong() + { + auto b2 = static_cast(value >> 8); + auto b3 = static_cast(value & 0xff); + return Uuid::fromShort(b2, b3); } uint16_t value; }; + namespace uuids { -const SpecUuid PRIMARY_SERVICE = SpecUuid(0x2800); -const SpecUuid SECONDARY_SERVICE = SpecUuid(0x2801); -const SpecUuid CHARACTERISTIC = SpecUuid(0x2803); + +const ShortUuid HealthTermometerService{0x1809}; +const ShortUuid DeviceInformationService{0x180a}; +const ShortUuid BatteryService{0x180f}; + +const ShortUuid PRIMARY_SERVICE{0x2800}; +const ShortUuid SECONDARY_SERVICE{0x2801}; +const ShortUuid CHARACTERISTIC{0x2803}; + +const ShortUuid TemperatureMeasurement{0x2A1C}; } class BluetoothAdapter; class BluetoothDevice; +class BluetoothGatt; + class BluetoothGattService; class BluetoothGattCharacteristic; +typedef shared_ptr BluetoothGattPtr; typedef shared_ptr BluetoothGattCharacteristicPtr; typedef shared_ptr BluetoothGattServicePtr; class BluetoothException : public runtime_error { public: - BluetoothException(const BluetoothAdapter *adapter, string const &what) : - runtime_error(what), adapter(adapter), device(nullptr) { - } + BluetoothException(const BluetoothAdapter *adapter, string const &what) : runtime_error(what), adapter(adapter), device(nullptr) {} - BluetoothException(const BluetoothDevice *device, string const &what) : - runtime_error(what), adapter(nullptr), device(device) { - } + BluetoothException(const BluetoothDevice *device, string const &what) : runtime_error(what), adapter(nullptr), device(device) {} - BluetoothException(string const &what) : - runtime_error(what), adapter(nullptr), device(nullptr) { - } + explicit BluetoothException(string const &what) : runtime_error(what), adapter(nullptr), device(nullptr) {} const BluetoothAdapter *adapter; const BluetoothDevice *device; @@ -64,7 +116,7 @@ public: class Mac { public: - Mac(uint8_t _5, uint8_t _4, uint8_t _3, uint8_t _2, uint8_t _1, uint8_t _0) { + explicit Mac(uint8_t _5, uint8_t _4, uint8_t _3, uint8_t _2, uint8_t _1, uint8_t _0) : bytes() { bytes[5] = _5; bytes[4] = _4; bytes[3] = _3; @@ -105,14 +157,13 @@ public: class BluetoothGattCharacteristic { public: - virtual ~BluetoothGattCharacteristic() { - }; + virtual ~BluetoothGattCharacteristic() = default; virtual BluetoothGattServicePtr getService() const = 0; virtual uint16_t getHandle() const = 0; - virtual const boost::uuids::uuid getUuid() const = 0; + virtual const Uuid getUuid() const = 0; virtual uint8_t getProperties() const = 0; @@ -121,12 +172,11 @@ public: class BluetoothGattService { public: - virtual ~BluetoothGattService() { - }; + virtual ~BluetoothGattService() = default; virtual BluetoothDevice &getDevice() const = 0; - virtual boost::uuids::uuid getUuid() const = 0; + virtual Uuid getUuid() const = 0; virtual uint16_t getHandle() const = 0; @@ -134,7 +184,11 @@ public: virtual vector> getCharacteristics() const = 0; - virtual o findCharacteristic(boost::uuids::uuid uuid) = 0; + virtual o findCharacteristic(Uuid uuid) = 0; + + o findCharacteristic(ShortUuid uuid) { + return findCharacteristic(uuid.toLong()); + }; }; class BluetoothGatt { @@ -160,7 +214,11 @@ public: virtual vector> getServices() const = 0; - virtual o findService(boost::uuids::uuid uuid) = 0; + virtual o findService(Uuid uuid) = 0; + + o findService(ShortUuid uuid) { + return findService(uuid.toLong()); + } }; class BluetoothDevice { @@ -211,24 +269,47 @@ private: map> adapters; }; +/** + * BLUETOOTH SPECIFICATION Version 4.0 [Vol 3] - Attribute Protocol (ATT) - 3.4.8 Attribute Opcode Summary + * Table 3.37 + */ enum AttPduType { - ERROR = 0x00, - INVALID_HANDLE = 0x01, + ERROR = 0x01, + EXCHANGE_MTU_REQ = 0x02, + EXCHANGE_MTU_RES = 0x03, + FIND_INFORMATION_REQ = 0x04, + FIND_INFORMATION_RES = 0x05, + FIND_BY_TYPE_VALUE_REQ = 0x06, + FIND_BY_TYPE_VALUE_RES = 0x07, READ_BY_TYPE_REQ = 0x08, READ_BY_TYPE_RES = 0x09, READ_REQ = 0x0a, READ_RES = 0x0b, + READ_BLOB_REQ = 0x0c, + READ_BLOB_RES = 0x0d, + READ_MULTIPLE_REQ = 0x0e, + READ_MULTIPLE_RES = 0x0f, READ_BY_GROUP_TYPE_REQ = 0x10, READ_BY_GROUP_TYPE_RES = 0x11, WRITE_REQ = 0x12, WRITE_RES = 0x13, + + WRITE_CMD = 0x52, + PREPARE_WRITE_REQ = 0x16, + PREPARE_WRITE_RES = 0x17, + EXECUTE_WRITE_REQ = 0x18, + EXECUTE_WRITE_RES = 0x19, + HANDLE_VALUE_NOTIFICATION = 0x1b, + HANDLE_VALUE_INDICATION = 0x1d, + HANDLE_VALUE_CONFIRMATION = 0x1e, + SIGNED_WRITE_COMMAND = 0xd2, }; class AttributeData; class AttPdu { public: - AttPdu(ByteBuffer &bytes); + explicit AttPdu(ByteBuffer &bytes); AttPdu(ByteBuffer &bytes, AttPduType type); @@ -238,13 +319,15 @@ public: static vector parseReadByType(ByteBuffer &bytes); + static uint16_t parseExchangeMtuReq(ByteBuffer &bytes); + static void parseRead(ByteBuffer &bytes); static void parseWrite(ByteBuffer &bytes); - static void makeReadByGroupType(ByteBuffer &bytes, uint16_t startHandle, uint16_t endHandle, SpecUuid uuid); + static void makeReadByGroupType(ByteBuffer &bytes, uint16_t startHandle, uint16_t endHandle, ShortUuid uuid); - static void makeReadByType(ByteBuffer &bytes, uint16_t startHandle, uint16_t endHandle, SpecUuid uuid); + static void makeReadByType(ByteBuffer &bytes, uint16_t startHandle, uint16_t endHandle, ShortUuid uuid); static void makeRead(ByteBuffer &bytes, uint16_t handle); @@ -271,7 +354,7 @@ private: AttributeData(uint16_t handle, ByteBuffer value); }; -boost::uuids::uuid makeUuid(const boost::uuids::uuid base, uint8_t a, uint8_t b); +Uuid makeUuid(const Uuid& base, uint8_t a, uint8_t b); } } -- cgit v1.2.3