diff options
-rw-r--r-- | apps/ble-inspect-device.cpp | 56 | ||||
-rw-r--r-- | apps/sm-get-value.cpp | 27 | ||||
-rw-r--r-- | ble/Bluetooth.cpp | 10 | ||||
-rw-r--r-- | ble/Bluetooth.h | 39 | ||||
-rw-r--r-- | ble/BluetoothImpl.h | 57 | ||||
-rw-r--r-- | ble/LinuxBluetooth.cpp | 96 |
6 files changed, 191 insertions, 94 deletions
diff --git a/apps/ble-inspect-device.cpp b/apps/ble-inspect-device.cpp index 361311c..e50f6ae 100644 --- a/apps/ble-inspect-device.cpp +++ b/apps/ble-inspect-device.cpp @@ -7,25 +7,16 @@ using namespace std; using namespace trygvis::bluetooth; -Mac *targetMac; +void scan_callback(BluetoothDevice & device) { + cout << "Inspecting device: " << device.getMac().str() << endl; -void scan_callback(BluetoothDevice &device) { - device.adapter().stopScan(); + auto &gatt = device.connectGatt(); - if (device.mac() != *targetMac) { - cout << "found device: " << device.mac().str() << ", but not the one we want " << targetMac->str() << endl; - return; - } - - cout << "Connecting to device: " << device.mac().str() << endl; - - device.connect(); + gatt.discoverServices(); - device.discoverServices(); - - vector<BluetoothGattService *> services = device.getServices(); + vector < BluetoothGattService * > services = gatt.getServices(); cout << "Device has " << services.size() << " services" << endl; - + for (auto &s: services) { const vector<BluetoothGattCharacteristic *> characteristics = s->getCharacteristics(); @@ -36,7 +27,7 @@ void scan_callback(BluetoothDevice &device) { } } - device.disconnect(); + gatt.disconnect(); } int main(int argc, char *argv[]) { @@ -45,28 +36,23 @@ int main(int argc, char *argv[]) { return EXIT_FAILURE; } - int e; -// try { - Mac mac = Mac::parseMac(argv[1]); - targetMac = &mac; + BluetoothSystem bluetoothSystem; - BluetoothAdapter &adapter = getAdapter(0); + try { + Mac mac = Mac::parseMac(argv[1]); - BluetoothDevice &device = adapter.getDevice(mac); + BluetoothAdapter &adapter = getAdapter(0); - scan_callback(device); + BluetoothDevice &device = adapter.getDevice(mac); -// adapter->runScan(scan_callback); + scan_callback(device); - e = EXIT_SUCCESS; -// } catch (std::runtime_error ex) { -// W << "std::runtime_error: " << ex.what(); -// e = EXIT_FAILURE; -// } catch (std::exception ex) { -// W << "std::exception: " << ex.what(); -// e = EXIT_FAILURE; -// } - - shutdown(); - return e; + return EXIT_SUCCESS; + } catch (std::runtime_error ex) { + W << "std::runtime_error: " << ex.what(); + return EXIT_FAILURE; + } catch (std::exception ex) { + W << "std::exception: " << ex.what(); + return EXIT_FAILURE; + } } diff --git a/apps/sm-get-value.cpp b/apps/sm-get-value.cpp index 6d7c578..9e6ae2c 100644 --- a/apps/sm-get-value.cpp +++ b/apps/sm-get-value.cpp @@ -2,11 +2,14 @@ #include <boost/uuid/uuid_io.hpp> #include <boost/optional.hpp> #include "Bluetooth.h" +#include "log.h" using namespace std; using namespace trygvis::bluetooth; typedef boost::uuids::uuid uuid_t; +template<class T> +using o = boost::optional<T>; #define BLUETOOTH_UUID_INITIALIZER \ { \ @@ -25,6 +28,7 @@ uuid_t trygvis_io_base_uuid = { 0xbc, 0x8e, 0x4a, 0x1f, 0xd8, 0x3f}; uuid_t soil_moisture_service = makeUuid(trygvis_io_base_uuid, 0x00, 0x10); +uuid_t soil_moisture_characteristic = makeUuid(trygvis_io_base_uuid, 0x00, 0x11); int main(int argc, char *argv[]) { if (argc != 2) { @@ -32,30 +36,35 @@ int main(int argc, char *argv[]) { return EXIT_FAILURE; } - int e; - BluetoothSystem bluetoothSystem; try { Mac mac = Mac::parseMac(argv[1]); - BluetoothAdapter &adapter = getAdapter(0); + auto &adapter = getAdapter(0); - BluetoothDevice &device = adapter.getDevice(mac); + auto &device = adapter.getDevice(mac); - cout << "Connecting to device: " << device.mac().str() << endl; + cout << "Connecting to device: " << device.getMac().str() << endl; - device.connect(); + auto &gatt = device.connectGatt(); - device.discoverServices(); + gatt.discoverServices(); - boost::optional<BluetoothGattService *> service = device.findService(soil_moisture_service); + auto service = gatt.findService(soil_moisture_service); if (!service) { cout << "The device is missing the soil moisture service" << endl; return EXIT_FAILURE; } - device.disconnect(); + auto c = (*service)->findCharacteristic(soil_moisture_characteristic); + + if (!c) { + cout << "The device is missing the soil moisture characteristic" << endl; + return EXIT_FAILURE; + } + + gatt.disconnect(); return EXIT_SUCCESS; } catch (std::runtime_error ex) { W << "std::runtime_error: " << ex.what(); diff --git a/ble/Bluetooth.cpp b/ble/Bluetooth.cpp index 4ceb3b6..31f82e3 100644 --- a/ble/Bluetooth.cpp +++ b/ble/Bluetooth.cpp @@ -146,6 +146,16 @@ AttributeData::~AttributeData() { } // ----------------------------------------------------------------------- +// Gatt +// ----------------------------------------------------------------------- + +BluetoothGatt::BluetoothGatt() { +} + +BluetoothGatt::~BluetoothGatt() { +} + +// ----------------------------------------------------------------------- // Device // ----------------------------------------------------------------------- diff --git a/ble/Bluetooth.h b/ble/Bluetooth.h index e7b163b..1dd5022 100644 --- a/ble/Bluetooth.h +++ b/ble/Bluetooth.h @@ -15,7 +15,9 @@ using namespace std; struct SpecUuid { public: - SpecUuid(uint16_t value) : value(value) {} + SpecUuid(uint16_t value) : value(value) { + } + uint16_t value; }; @@ -109,18 +111,18 @@ public: virtual const vector<BluetoothGattCharacteristic *> getCharacteristics() const = 0; - virtual void addCharacteristic(BluetoothGattCharacteristic* characteristic) = 0; + virtual void addCharacteristic(BluetoothGattCharacteristic *characteristic) = 0; + + virtual const boost::optional<BluetoothGattCharacteristic *> findCharacteristic(boost::uuids::uuid uuid) const = 0; }; -class BluetoothDevice { +class BluetoothGatt { public: - BluetoothDevice(); + BluetoothGatt(); - virtual ~BluetoothDevice(); - - virtual Mac const &mac() = 0; + virtual ~BluetoothGatt(); - virtual BluetoothAdapter &adapter() = 0; +// virtual BluetoothDevice &getDevice() = 0; virtual void connect() = 0; @@ -130,7 +132,20 @@ public: virtual const vector<BluetoothGattService *> getServices() const = 0; - virtual const boost::optional<BluetoothGattService*> findService(boost::uuids::uuid uuid) const = 0; + virtual const boost::optional<BluetoothGattService *> findService(boost::uuids::uuid uuid) const = 0; +}; + +class BluetoothDevice { +public: + BluetoothDevice(); + + virtual ~BluetoothDevice(); + + virtual Mac const &getMac() = 0; + + virtual BluetoothAdapter &getAdapter() = 0; + + virtual BluetoothGatt &connectGatt() = 0; }; class BluetoothAdapter { @@ -150,11 +165,12 @@ protected: }; /** - * RAII support. - */ +* RAII support. +*/ class BluetoothSystem { public: BluetoothSystem(); + ~BluetoothSystem(); }; @@ -187,6 +203,7 @@ public: private: static void checkType(ByteBuffer &bytes, AttPduType type); + static vector<AttributeData> parse(ByteBuffer &bytes, AttPduType type); ByteBuffer &bytes; diff --git a/ble/BluetoothImpl.h b/ble/BluetoothImpl.h index 69fac6e..7801771 100644 --- a/ble/BluetoothImpl.h +++ b/ble/BluetoothImpl.h @@ -18,7 +18,7 @@ namespace trygvis { namespace bluetooth { typedef boost::uuids::uuid uuid_t; -template <class t> +template<class t> using o = boost::optional<t>; class DefaultBluetoothGattCharacteristic : public BluetoothGattCharacteristic { @@ -94,6 +94,16 @@ public: characteristics.push_back(characteristic); } + virtual const o<BluetoothGattCharacteristic *> findCharacteristic(uuid_t uuid) const { + for (auto c: characteristics) { + if (memcmp(c->getUuid().data, uuid.data, 16) == 0) { + return o<BluetoothGattCharacteristic *>(c); + } + } + + return o<BluetoothGattCharacteristic *>(); + } + protected: BluetoothDevice &device; const uuid_t uuid; @@ -110,20 +120,55 @@ protected: } }; +template<class A> class DefaultBluetoothDevice : public BluetoothDevice { public: + + virtual Mac const &getMac() override { + return mac; + } + + virtual A &getAdapter() override { + return adapter; + } + +protected: + DefaultBluetoothDevice(A adapter, Mac &mac) : + adapter(adapter), mac(mac) { + DF; + } + + virtual ~DefaultBluetoothDevice() { + DF; + removeServices(); + } + + void removeServices() { + for (auto s: services) { + delete s; + } + services.clear(); + } + + A adapter; + Mac &mac; + vector<BluetoothGattService *> services; +}; + +class DefaultBluetoothGatt : public BluetoothGatt { +public: virtual const vector<BluetoothGattService *> getServices() const { return services; }; - virtual const o<BluetoothGattService*> findService(boost::uuids::uuid uuid) const { + virtual const o<BluetoothGattService *> findService(uuid_t uuid) const { for (auto s: services) { if (memcmp(s->getUuid().data, uuid.data, 16) == 0) { - return o<BluetoothGattService*>(s); + return o<BluetoothGattService *>(s); } } - return o<BluetoothGattService*>(); + return o<BluetoothGattService *>(); } virtual void addService(BluetoothGattService *service) { @@ -131,11 +176,11 @@ public: } protected: - DefaultBluetoothDevice() { + DefaultBluetoothGatt() { DF; } - virtual ~DefaultBluetoothDevice() { + virtual ~DefaultBluetoothGatt() { DF; removeServices(); } diff --git a/ble/LinuxBluetooth.cpp b/ble/LinuxBluetooth.cpp index b687807..a5d092b 100644 --- a/ble/LinuxBluetooth.cpp +++ b/ble/LinuxBluetooth.cpp @@ -21,6 +21,8 @@ namespace linux { using namespace uuids; +class LinuxBluetoothGatt; + class LinuxBluetoothDevice; class LinuxBluetoothAdapter; @@ -50,13 +52,24 @@ private: map<Mac, LinuxBluetoothDevice *> devices; }; -class LinuxBluetoothDevice : public DefaultBluetoothDevice { +class LinuxBluetoothDevice : public DefaultBluetoothDevice<LinuxBluetoothAdapter> { public: - LinuxBluetoothDevice(LinuxBluetoothAdapter &adapter, Mac mac); + LinuxBluetoothDevice(LinuxBluetoothAdapter &adapter, Mac &mac); + ~LinuxBluetoothDevice(); + + BluetoothGatt &connectGatt() override; + +private: + LinuxBluetoothGatt* gatt; + int l2cap; +}; - Mac const &mac() override; +class LinuxBluetoothGatt : public DefaultBluetoothGatt { +public: + LinuxBluetoothGatt(LinuxBluetoothDevice &device, int l2cap); + ~LinuxBluetoothGatt(); - LinuxBluetoothAdapter &adapter() override; +// LinuxBluetoothDevice &getDevice() override; void connect() override; @@ -71,10 +84,7 @@ private: ByteBuffer writeAndRead(ByteBuffer &out, shared_ptr<uint8_t> buffer, size_t size); - uuid_t readUuid(const ByteBuffer &bytes) const; - - LinuxBluetoothAdapter &_adapter; - Mac _mac; + LinuxBluetoothDevice &device; int l2cap; }; @@ -96,26 +106,45 @@ Mac parseMac(bdaddr_t &a) { // Device // ----------------------------------------------------------------------- -LinuxBluetoothDevice::LinuxBluetoothDevice(LinuxBluetoothAdapter &adapter, Mac mac) : - DefaultBluetoothDevice(), _adapter(adapter), _mac(mac) { +LinuxBluetoothDevice::LinuxBluetoothDevice(LinuxBluetoothAdapter &adapter, Mac &mac) : + DefaultBluetoothDevice(adapter, mac), gatt(nullptr) { } -Mac const &LinuxBluetoothDevice::mac() { - return _mac; +LinuxBluetoothDevice::~LinuxBluetoothDevice() { + if (gatt) { + delete gatt; + } +}; + +BluetoothGatt &LinuxBluetoothDevice::connectGatt() { + if (!gatt) { + gatt = new LinuxBluetoothGatt(*this, l2cap); + } + + gatt->connect(); + + return *gatt; +} + +// ----------------------------------------------------------------------- +// Gatt +// ----------------------------------------------------------------------- + +LinuxBluetoothGatt::LinuxBluetoothGatt(LinuxBluetoothDevice &device, int l2cap) : + device(device), l2cap(l2cap) { } -LinuxBluetoothAdapter &LinuxBluetoothDevice::adapter() { - return _adapter; +LinuxBluetoothGatt::~LinuxBluetoothGatt() { } -void LinuxBluetoothDevice::connect() { +void LinuxBluetoothGatt::connect() { struct sockaddr_l2 addr; - D << "connect: mac=" << _mac.str(); + D << "connect: mac=" << device.getMac().str(); l2cap = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP); if (l2cap < 0) { - throw BluetoothException(this, "LinuxBluetoothDevice::connect(): socket(): " + errnoAsString()); + throw BluetoothException(&device, "LinuxBluetoothDevice::connect(): socket(): " + errnoAsString()); } memset(&addr, 0, sizeof(addr)); @@ -126,7 +155,7 @@ void LinuxBluetoothDevice::connect() { if (bind(l2cap, (struct sockaddr *) &addr, sizeof(addr)) < 0) { close(l2cap); - throw BluetoothException(this, "LinuxBluetoothDevice::connect(): bind(): " + errnoAsString()); + throw BluetoothException(&device, "LinuxBluetoothDevice::connect(): bind(): " + errnoAsString()); } struct bt_security btsec; @@ -134,14 +163,15 @@ void LinuxBluetoothDevice::connect() { btsec.level = BT_SECURITY_LOW; if (setsockopt(l2cap, SOL_BLUETOOTH, BT_SECURITY, &btsec, sizeof(btsec)) != 0) { close(l2cap); - throw BluetoothException(this, "LinuxBluetoothDevice::connect(): setsockopt(): " + errnoAsString()); + throw BluetoothException(&device, "LinuxBluetoothDevice::connect(): setsockopt(): " + errnoAsString()); } memset(&addr, 0, sizeof(addr)); addr.l2_family = AF_BLUETOOTH; addr.l2_cid = htobs(ATT_CID); addr.l2_bdaddr_type = BDADDR_LE_RANDOM; - _mac.copy(addr.l2_bdaddr.b[5], + device.getMac().copy( + addr.l2_bdaddr.b[5], addr.l2_bdaddr.b[4], addr.l2_bdaddr.b[3], addr.l2_bdaddr.b[2], @@ -150,16 +180,16 @@ void LinuxBluetoothDevice::connect() { if (::connect(l2cap, (struct sockaddr *) &addr, sizeof(addr)) < 0) { close(l2cap); - throw BluetoothException(this, "LinuxBluetoothDevice::connect(): connect(): " + errnoAsString()); + throw BluetoothException(&device, "LinuxBluetoothDevice::connect(): connect(): " + errnoAsString()); } } -void LinuxBluetoothDevice::disconnect() { - DF << "mac = " << _mac.str(); +void LinuxBluetoothGatt::disconnect() { + DF << "mac = " << device.getMac().str(); close(l2cap); } -uuid_t LinuxBluetoothDevice::readUuid(const ByteBuffer &bytes) const { +uuid_t readUuid(BluetoothDevice *device, const ByteBuffer &bytes) { size_t bytesLeft = bytes.getBytesLeft(); uuid_t u; @@ -189,13 +219,13 @@ uuid_t LinuxBluetoothDevice::readUuid(const ByteBuffer &bytes) const { bs[0] = bytes.get8(15); memcpy(&u, bs, 16); } else { - throw BluetoothException(this, "Unexpected bytes left: " + to_string(bytesLeft)); + throw BluetoothException(device, "Unexpected bytes left: " + to_string(bytesLeft)); } return u; } -void LinuxBluetoothDevice::discoverServices() { +void LinuxBluetoothGatt::discoverServices() { uint16_t startHandle = 0x0001; removeServices(); @@ -217,9 +247,9 @@ void LinuxBluetoothDevice::discoverServices() { // ", endGroupHandle: 0x" << hex << setw(4) << setfill('0') << endGroupHandle << // ", value: " << data.value.toString(); - uuid_t u = readUuid(data.value); + uuid_t u = readUuid(&device, data.value); - addService(new DefaultBluetoothGattService(*this, u, data.handle, endGroupHandle)); + addService(new DefaultBluetoothGattService(device, u, data.handle, endGroupHandle)); } auto last = values.back(); @@ -263,7 +293,7 @@ void LinuxBluetoothDevice::discoverServices() { uint8_t properties = c.value.read8(); uint16_t valueHandle = c.value.read16le(); - uuid_t uuid = readUuid(c.value); + uuid_t uuid = readUuid(&device, c.value); // D << "characteristic: handle: " << setw(2) << setfill('0') << hex << (int) c.handle << // ", properties: " << setw(2) << setfill('0') << hex << (int) properties << @@ -279,7 +309,7 @@ void LinuxBluetoothDevice::discoverServices() { } while (startHandle != 0xffff); } -ByteBuffer LinuxBluetoothDevice::writeAndRead(ByteBuffer &out, shared_ptr<uint8_t> buffer, size_t size) { +ByteBuffer LinuxBluetoothGatt::writeAndRead(ByteBuffer &out, shared_ptr<uint8_t> buffer, size_t size) { D << "pdu size=" << out.getCursor(); ssize_t written = write(l2cap, buffer.get(), out.getCursor()); @@ -288,7 +318,7 @@ ByteBuffer LinuxBluetoothDevice::writeAndRead(ByteBuffer &out, shared_ptr<uint8_ ssize_t r = read(l2cap, buffer.get(), size); if (r == -1) { - throw BluetoothException(this, "read(): " + errnoAsString()); + throw BluetoothException(&device, "read(): " + errnoAsString()); } auto in = ByteBuffer(buffer, (size_t) r); @@ -298,7 +328,7 @@ ByteBuffer LinuxBluetoothDevice::writeAndRead(ByteBuffer &out, shared_ptr<uint8_ return in; } -vector<AttributeData> LinuxBluetoothDevice::discoverServices(uint16_t startHandle) { +vector<AttributeData> LinuxBluetoothGatt::discoverServices(uint16_t startHandle) { DF; shared_ptr<uint8_t> buffer(new uint8_t[MAX_MTU]); @@ -315,7 +345,7 @@ vector<AttributeData> LinuxBluetoothDevice::discoverServices(uint16_t startHandl return values; } -vector<AttributeData> LinuxBluetoothDevice::discoverCharacteristics(uint16_t startHandle, uint16_t endHandle) { +vector<AttributeData> LinuxBluetoothGatt::discoverCharacteristics(uint16_t startHandle, uint16_t endHandle) { DF; shared_ptr<uint8_t> buffer(new uint8_t[MAX_MTU]); |