From 2034b1bb10720a2f0e6cc97427346f2320c115bc Mon Sep 17 00:00:00 2001 From: Trygve Laugstøl Date: Fri, 23 Nov 2018 09:40:48 +0100 Subject: o Starting to handle notifications and indications Cleaning up: o Using more of the shared_ptr typedefs. o Adding code styles used by CLion. --- .gitignore | 10 +++++--- .idea/codeStyles/Project.xml | 23 +++++++++++++++++ .idea/codeStyles/codeStyleConfig.xml | 5 ++++ apps/SoilMoisture.cpp | 16 ++++++------ apps/SoilMoisture.h | 12 ++++----- apps/ble-read-characteristic.cpp | 8 ++++-- ble/BluetoothImpl.h | 40 +++++++++++++----------------- ble/LinuxBluetooth.cpp | 48 ++++++++++++++++++++++++++---------- ble/att.cpp | 15 ++++++++++- include/ble/Bluetooth.h | 38 +++++++++++++++++----------- include/ble/att.h | 21 +++++++++++++++- 11 files changed, 165 insertions(+), 71 deletions(-) create mode 100644 .idea/codeStyles/Project.xml create mode 100644 .idea/codeStyles/codeStyleConfig.xml diff --git a/.gitignore b/.gitignore index f8bef31..9517086 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,12 @@ -noble -.idea +!.idea +.idea/* +!.idea/codeStyles +!.idea/codeStyles/* + build +cmake-build-* + *.log *.tmp.* tmp.* *.tmp -cmake-build-* diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml new file mode 100644 index 0000000..b3ca777 --- /dev/null +++ b/.idea/codeStyles/Project.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 0000000..79ee123 --- /dev/null +++ b/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/apps/SoilMoisture.cpp b/apps/SoilMoisture.cpp index 3129564..fcf81bd 100644 --- a/apps/SoilMoisture.cpp +++ b/apps/SoilMoisture.cpp @@ -62,18 +62,18 @@ void createSetUpdateInterval(ByteBuffer buffer, uint8_t sensor, uint8_t interval .write8(interval_in_seconds); } -SoilMoisture SoilMoisture::create(shared_ptr gatt) { +SoilMoisture SoilMoisture::create(BluetoothGattPtr gatt) { gatt->discoverServices(); - o> s = gatt->findService(soil_moisture_service); + auto s = gatt->findService(soil_moisture_service); if (!s) { throw runtime_error("The device is missing the soil moisture service"); } - shared_ptr &service = *s; + auto &service = *s; - o> c = service->findCharacteristic(soil_moisture_characteristic); + auto c = service->findCharacteristic(soil_moisture_characteristic); if (!c) { throw runtime_error("The device is missing the soil moisture characteristic"); @@ -86,8 +86,8 @@ SoilMoisture SoilMoisture::create(shared_ptr gatt) { return SoilMoisture(gatt, service, c.operator*(), temperature, light); } -SoilMoisture::SoilMoisture(const shared_ptr &gatt, - const shared_ptr &s, +SoilMoisture::SoilMoisture(const BluetoothGattPtr &gatt, + const BluetoothGattServicePtr &s, const BluetoothGattCharacteristicPtr &soilMoistureCharacteristic, const o temperatureCharacteristic, const o lightCharacteristic) @@ -192,5 +192,5 @@ void SoilMoisture::setLight(uint8_t light, uint8_t value) { bitset<8> b0 = responseBytes.read8(); } -} -} +} // namespace sensor +} // namespace trygvis diff --git a/apps/SoilMoisture.h b/apps/SoilMoisture.h index 4e6ae17..a46afeb 100644 --- a/apps/SoilMoisture.h +++ b/apps/SoilMoisture.h @@ -29,7 +29,7 @@ extern const Uuid soil_moisture_characteristic; class SoilMoisture { public: - static SoilMoisture create(shared_ptr gatt); + static SoilMoisture create(BluetoothGattPtr gatt); uint8_t getSensorCount(); @@ -44,16 +44,16 @@ public: void setLight(uint8_t light, uint8_t value); private: - SoilMoisture(const shared_ptr &gatt, - const shared_ptr &s, - const shared_ptr &soilMoistureCharacteristic, + SoilMoisture(const BluetoothGattPtr &gatt, + const BluetoothGattServicePtr &s, + const BluetoothGattCharacteristicPtr &soilMoistureCharacteristic, const o temperatureCharacteristic, const o lightCharacteristic); void writeAndRead(const BluetoothGattCharacteristicPtr &c, ByteBuffer &requestBytes); - shared_ptr gatt; - shared_ptr s; + BluetoothGattPtr gatt; + BluetoothGattServicePtr s; const BluetoothGattCharacteristicPtr soilMoistureCharacteristic; const o temperatureCharacteristic; const o lightCharacteristic; diff --git a/apps/ble-read-characteristic.cpp b/apps/ble-read-characteristic.cpp index 8efcb3b..ecdb471 100644 --- a/apps/ble-read-characteristic.cpp +++ b/apps/ble-read-characteristic.cpp @@ -109,8 +109,12 @@ public: cccd->setValue(ByteBuffer::wrapInitialized(BluetoothGattDescriptor::ENABLE_NOTIFICATION_VALUE)); gatt->write(cccd); - cout << "sleeping" << endl; - std::this_thread::sleep_for(10s); + auto end = std::chrono::system_clock::now() + 10s; + + do { + cerr << "Processing messages" << endl; + gatt->process(2s); + } while(std::chrono::system_clock::now() < end); } } else { cout << "Unsupported op mode." << endl; diff --git a/ble/BluetoothImpl.h b/ble/BluetoothImpl.h index 5b53cd4..c41712c 100644 --- a/ble/BluetoothImpl.h +++ b/ble/BluetoothImpl.h @@ -110,7 +110,7 @@ public: return valueHandle; } - shared_ptr getDescriptor(Uuid uuid) const override { + BluetoothGattDescriptorPtr getDescriptor(Uuid uuid) const override { for (auto &d: descriptors) { if (d->getUuid() == uuid) { return d; @@ -120,7 +120,7 @@ public: return {}; } - void addDescriptor(shared_ptr &&d) { + void addDescriptor(BluetoothGattDescriptorPtr &&d) { descriptors.push_back(std::move(d)); } @@ -166,17 +166,17 @@ public: return endGroupHandle; } - vector> getCharacteristics() const override { - vector> cs(characteristics.size()); + 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(BluetoothGattCharacteristicPtr &&characteristic) { characteristics.emplace_back(characteristic); } - o> findCharacteristic(Uuid uuid) override { + o findCharacteristic(Uuid uuid) override { for (auto &c: characteristics) { if (c->getUuid() == uuid) { return {c}; @@ -191,7 +191,7 @@ protected: const Uuid uuid; const uint16_t handle; const uint16_t endGroupHandle; - vector> characteristics; + vector characteristics; }; template @@ -201,12 +201,8 @@ public: return device; } -// virtual Collection getServices() const { -// return CollectionImpl>(services); -// } - - vector> getServices() const override { - vector> ss(services.size()); + vector getServices() const override { + vector ss(services.size()); std::copy(begin(services), end(services), begin(ss)); return ss; } @@ -214,32 +210,30 @@ public: o findService(Uuid uuid) override { for (auto &s: services) { if (s->getUuid() == uuid) { - return o>(s); + return o(s); } } - return o>(); + return {}; } - void addService(shared_ptr<_S> service) { + void addService(std::shared_ptr<_S> service) { services.emplace_back(service); } protected: - explicit DefaultBluetoothGatt(_D &device) : LogSetup("BluetoothGatt"), device(device) { - } + explicit DefaultBluetoothGatt(_D &device, BluetoothCallback *callback) : + LogSetup("BluetoothGatt"), device(device), callback(callback) {} ~DefaultBluetoothGatt() override = default; void removeServices() { -// for (auto s: services) { -// delete s; -// } services.clear(); } _D &device; - vector> services; + vector > services; + BluetoothCallback *callback; }; template @@ -293,7 +287,7 @@ protected: Mac &mac; }; -shared_ptr getAdapterImpl(string name); +BluetoothAdapterPtr getAdapterImpl(string name); template struct overloaded : Ts... { using Ts::operator()...; }; template overloaded(Ts...) -> overloaded; diff --git a/ble/LinuxBluetooth.cpp b/ble/LinuxBluetooth.cpp index 99762cb..9e7193f 100644 --- a/ble/LinuxBluetooth.cpp +++ b/ble/LinuxBluetooth.cpp @@ -84,7 +84,7 @@ public: LinuxBluetoothDevice &operator=(const LinuxBluetoothDevice &) = delete; - shared_ptr connectGatt() override; + shared_ptr connectGatt(BluetoothCallback* callback) override; private: LinuxBluetoothGatt *gatt; @@ -92,7 +92,7 @@ private: class LinuxBluetoothGatt final : public DefaultBluetoothGatt { public: - explicit LinuxBluetoothGatt(LinuxBluetoothDevice &device); + explicit LinuxBluetoothGatt(LinuxBluetoothDevice &device, BluetoothCallback *callback); ~LinuxBluetoothGatt() override; @@ -104,9 +104,11 @@ public: void discoverServices() override; - void writeValue(const BluetoothGattCharacteristicPtr &c, const ByteBuffer &bytes) override; + void process(std::chrono::system_clock::duration max_duration) override; - void write(const BluetoothGattDescriptorPtr &c) override; + void writeValue(const BluetoothGattCharacteristicPtr &characteristic, const ByteBuffer &bytes) override; + + void write(const BluetoothGattDescriptorPtr &descriptor) override; ByteBuffer readValue(const BluetoothGattCharacteristicPtr &c, ByteBuffer &response) override; @@ -132,6 +134,9 @@ private: template AttVariant exchangeAndWaitFor(ByteBuffer &buffer, std::chrono::time_point time); + template + AttVariant waitFor(ByteBuffer &buffer, std::chrono::time_point time); + template T exchangeAndWaitFor(ByteBuffer &buffer, std::chrono::time_point time, bool fail_on_error); @@ -174,11 +179,11 @@ LinuxBluetoothDevice::~LinuxBluetoothDevice() { delete gatt; }; -shared_ptr LinuxBluetoothDevice::connectGatt() { +shared_ptr LinuxBluetoothDevice::connectGatt(BluetoothCallback* callback) { // Make sure that we close the old connection and create a new one when the user asks for it. delete gatt; - gatt = new LinuxBluetoothGatt(*this); + gatt = new LinuxBluetoothGatt(*this, callback); return shared_ptr(shared_from_this(), gatt); } @@ -187,8 +192,8 @@ shared_ptr LinuxBluetoothDevice::connectGatt() { // Gatt // ----------------------------------------------------------------------- -LinuxBluetoothGatt::LinuxBluetoothGatt(LinuxBluetoothDevice &device) : - DefaultBluetoothGatt(device), l2cap() { +LinuxBluetoothGatt::LinuxBluetoothGatt(LinuxBluetoothDevice &device, BluetoothCallback *callback) : + DefaultBluetoothGatt(device, callback), l2cap() { connect(); } @@ -436,7 +441,7 @@ void LinuxBluetoothGatt::writeAndRead(const ByteBuffer &buffer, ByteBuffer &resp // LOG_DEBUG("written=" << written); - ssize_t r = read(l2cap, response.underlying(), response.getSize()); + ssize_t r = ::read(l2cap, response.underlying(), response.getSize()); if (r == -1) { throw BluetoothException(&device, "read(): " + errnoAsString()); @@ -465,7 +470,7 @@ AttVariant LinuxBluetoothGatt::processAvailableMessages(ByteBuffer &buffer) { // ", bytes available: " << to_string(bytes_available)); while (!ret && bytes_available) { - ssize_t r = read(l2cap, buffer.underlying(), buffer.getBytesLeft()); + ssize_t r = ::read(l2cap, buffer.underlying(), buffer.getBytesLeft()); if (r == -1) { throw BluetoothException(&device, "read(): " + errnoAsString()); } @@ -484,6 +489,9 @@ AttVariant LinuxBluetoothGatt::processAvailableMessages(ByteBuffer &buffer) { AttPdu::makeExchangeMtuRes(buffer, mtu); writeL2cap(buffer); + } else if (holds_alternative(v)) { + auto value = get(v); + LOG_DEBUG("got notification: " + to_string(value.data.getSize()) + ", pos=" + to_string(value.data.getSize())); } else { return v; } @@ -544,6 +552,11 @@ AttVariant LinuxBluetoothGatt::exchangeAndWaitFor(ByteBuffer &buffer, std::chron LOG_DEBUG("Writing message " << to_string(static_cast(buffer.get8(0)))); this->writeL2cap(buffer); + return waitFor(buffer, time); +} + +template +AttVariant LinuxBluetoothGatt::waitFor(ByteBuffer &buffer, std::chrono::time_point time) { fd_set rfds; struct timeval tv{}; @@ -638,6 +651,15 @@ void LinuxBluetoothGatt::discoverDescriptors(shared_ptr AttPdu::parseAttributeData(ByteBuffer &bytes) { } AttVariant AttPdu::parse(ByteBuffer &bytes) { - switch (static_cast(bytes.read8())) { + auto type = static_cast(bytes.read8()); + switch (type) { case AttPduType::ERROR: return ErrorRes::parse(bytes); case AttPduType::EXCHANGE_MTU_REQ: @@ -166,6 +167,10 @@ AttVariant AttPdu::parse(ByteBuffer &bytes) { return ReadByGroupTypeRes{parseAttributeData(bytes)}; case AttPduType::READ_BY_TYPE_RES: return ReadByTypeRes{parseAttributeData(bytes)}; + case AttPduType::HANDLE_VALUE_NOTIFICATION: + return parseHandleValueNotification(bytes); + case AttPduType::HANDLE_VALUE_INDICATION: + return parseHandleValueIndication(bytes); default: return {}; } @@ -196,6 +201,14 @@ FindInformationRes AttPdu::parseFindInformationRes(ByteBuffer &bytes) { return {format, information}; } +HandleValueNotification AttPdu::parseHandleValueNotification(ByteBuffer &bytes) { + return {bytes.read16le(), bytes.viewCursorToEnd()}; +} + +HandleValueIndication AttPdu::parseHandleValueIndication(ByteBuffer &bytes) { + return {bytes.read16le(), bytes.viewCursorToEnd()}; +} + void AttPdu::parseRead(ByteBuffer &bytes) { auto t = static_cast(bytes.read8()); diff --git a/include/ble/Bluetooth.h b/include/ble/Bluetooth.h index 914dc26..5f7cd17 100644 --- a/include/ble/Bluetooth.h +++ b/include/ble/Bluetooth.h @@ -10,6 +10,7 @@ #include #include #include +#include #include "ble/ByteBuffer.h" #include "ble/att.h" @@ -17,7 +18,6 @@ namespace trygvis { namespace bluetooth { -using std::shared_ptr; using std::string; using std::vector; using std::map; @@ -33,10 +33,12 @@ class BluetoothGattService; class BluetoothGattCharacteristic; class BluetoothGattDescriptor; -typedef shared_ptr BluetoothGattPtr; -typedef shared_ptr BluetoothGattServicePtr; -typedef shared_ptr BluetoothGattCharacteristicPtr; -typedef shared_ptr BluetoothGattDescriptorPtr; +typedef std::shared_ptr BluetoothGattPtr; +typedef std::shared_ptr BluetoothGattServicePtr; +typedef std::shared_ptr BluetoothGattCharacteristicPtr; +typedef std::shared_ptr BluetoothGattDescriptorPtr; +typedef std::shared_ptr BluetoothDevicePtr; +typedef std::shared_ptr BluetoothAdapterPtr; class Mac { public: @@ -65,6 +67,12 @@ private: uint8_t bytes[6]; }; +class BluetoothCallback { + virtual ~BluetoothCallback() = default; + + virtual void onCharacteristicChanged(BluetoothGattPtr& gatt, BluetoothGattCharacteristicPtr& characteristic) = 0; +}; + class BluetoothGattDescriptor { public: static const uint8_t DISABLE_NOTIFICATION_VALUE[2]; @@ -104,9 +112,9 @@ public: virtual uint16_t getValueHandle() const = 0; - virtual shared_ptr getDescriptor(Uuid uuid) const = 0; + virtual BluetoothGattDescriptorPtr getDescriptor(Uuid uuid) const = 0; - virtual shared_ptr getDescriptor(ShortUuid uuid) const { + virtual BluetoothGattDescriptorPtr getDescriptor(ShortUuid uuid) const { return getDescriptor(uuid.toLong()); }; }; @@ -123,7 +131,7 @@ public: virtual uint16_t getEndGroupHandle() const = 0; - virtual vector> getCharacteristics() const = 0; + virtual vector getCharacteristics() const = 0; virtual o findCharacteristic(Uuid uuid) = 0; @@ -155,7 +163,9 @@ public: virtual void discoverServices() = 0; - virtual vector> getServices() const = 0; + virtual void process(std::chrono::system_clock::duration max_duration) = 0; + + virtual vector getServices() const = 0; virtual o findService(Uuid uuid) = 0; @@ -174,7 +184,7 @@ public: virtual BluetoothAdapter &getAdapter() = 0; - virtual shared_ptr connectGatt() = 0; + virtual BluetoothGattPtr connectGatt(BluetoothCallback* callback = nullptr) = 0; }; class BluetoothAdapter { @@ -185,9 +195,9 @@ public: virtual void stopScan() = 0; - virtual void runScan(std::function &device)>) = 0; + virtual void runScan(std::function) = 0; - virtual shared_ptr getDevice(Mac &mac) = 0; + virtual BluetoothDevicePtr getDevice(Mac &mac) = 0; protected: BluetoothAdapter(); @@ -206,10 +216,10 @@ public: ~BluetoothSystem(); - shared_ptr getAdapter(string name); + BluetoothAdapterPtr getAdapter(string name); private: - map> adapters; + map adapters; }; } // namespace bluetooth diff --git a/include/ble/att.h b/include/ble/att.h index db21d2e..152a779 100644 --- a/include/ble/att.h +++ b/include/ble/att.h @@ -130,11 +130,26 @@ struct ReadByTypeRes { std::vector attributes; }; +struct HandleValueNotification { + static constexpr auto att_pdu_type = AttPduType::HANDLE_VALUE_NOTIFICATION; + + uint16_t handle; + ByteBuffer data; +}; + +struct HandleValueIndication { + static constexpr auto att_pdu_type = AttPduType::HANDLE_VALUE_INDICATION; + + uint16_t handle; + ByteBuffer data; +}; + using AttVariant = std::variant; + ReadByGroupTypeRes, ReadByTypeRes, + HandleValueNotification, HandleValueIndication>; o attPduType(const AttVariant &v); @@ -154,6 +169,10 @@ public: static FindInformationRes parseFindInformationRes(ByteBuffer &bytes); + static HandleValueNotification parseHandleValueNotification(ByteBuffer &bytes); + + static HandleValueIndication parseHandleValueIndication(ByteBuffer &bytes); + static void parseRead(ByteBuffer &bytes); static void parseWrite(ByteBuffer &bytes); -- cgit v1.2.3