aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apps/ble-inspect-device.cpp56
-rw-r--r--apps/sm-get-value.cpp27
-rw-r--r--ble/Bluetooth.cpp10
-rw-r--r--ble/Bluetooth.h39
-rw-r--r--ble/BluetoothImpl.h57
-rw-r--r--ble/LinuxBluetooth.cpp96
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]);