diff options
-rw-r--r-- | Bluetooth.cpp | 227 | ||||
-rw-r--r-- | Bluetooth.h | 179 | ||||
-rw-r--r-- | BluetoothImpl.h | 14 | ||||
-rw-r--r-- | ByteBuffer.cpp | 12 | ||||
-rw-r--r-- | ByteBuffer.h | 6 | ||||
-rw-r--r-- | CMakeLists.txt | 3 | ||||
-rw-r--r-- | LinuxBluetooth.cpp | 464 | ||||
-rw-r--r-- | main.cpp | 16 | ||||
-rw-r--r-- | test/ByteBufferTest.cpp | 11 |
9 files changed, 496 insertions, 436 deletions
diff --git a/Bluetooth.cpp b/Bluetooth.cpp index f589d1f..ebdd527 100644 --- a/Bluetooth.cpp +++ b/Bluetooth.cpp @@ -1,144 +1,175 @@ #include "Bluetooth.h" +#include "BluetoothImpl.h" #include <sstream> #include <iomanip> #include <string.h> namespace trygvis { - using namespace std; +namespace bluetooth { +using namespace std; - // ----------------------------------------------------------------------- - // Mac - // ----------------------------------------------------------------------- +// ----------------------------------------------------------------------- +// Mac +// ----------------------------------------------------------------------- - string Mac::str() const { - std::ostringstream buf; +string Mac::str() const { + std::ostringstream buf; - buf - << setw(2) << hex << setfill('0') << (int) bytes[0] << ":" - << setw(2) << hex << setfill('0') << (int) bytes[1] << ":" - << setw(2) << hex << setfill('0') << (int) bytes[2] << ":" - << setw(2) << hex << setfill('0') << (int) bytes[3] << ":" - << setw(2) << hex << setfill('0') << (int) bytes[4] << ":" - << setw(2) << hex << setfill('0') << (int) bytes[5]; + buf + << setw(2) << hex << setfill('0') << (int) bytes[0] << ":" + << setw(2) << hex << setfill('0') << (int) bytes[1] << ":" + << setw(2) << hex << setfill('0') << (int) bytes[2] << ":" + << setw(2) << hex << setfill('0') << (int) bytes[3] << ":" + << setw(2) << hex << setfill('0') << (int) bytes[4] << ":" + << setw(2) << hex << setfill('0') << (int) bytes[5]; - return buf.str(); - } + return buf.str(); +} - bool Mac::operator==(Mac &other) const { - const uint8_t* b = bytes; - return memcmp(b, other.bytes, sizeof(bytes)) == 0; - } +bool Mac::operator==(Mac &other) const { + const uint8_t *b = bytes; + return memcmp(b, other.bytes, sizeof(bytes)) == 0; +} - bool Mac::operator!=(Mac &other) const { - return !operator==(other); - } +bool Mac::operator!=(Mac &other) const { + return !operator==(other); +} - bool operator<(const Mac &a, const Mac &b) { - return memcmp(a.bytes, b.bytes, sizeof(a.bytes)) < 0; - } +bool operator<(const Mac &a, const Mac &b) { + return memcmp(a.bytes, b.bytes, sizeof(a.bytes)) < 0; +} + +void Mac::copy(uint8_t &_0, uint8_t &_1, uint8_t &_2, uint8_t &_3, uint8_t &_4, uint8_t &_5) const { + _0 = bytes[0]; + _1 = bytes[1]; + _2 = bytes[2]; + _3 = bytes[3]; + _4 = bytes[4]; + _5 = bytes[5]; +} - void Mac::copy(uint8_t &_0, uint8_t &_1, uint8_t &_2, uint8_t &_3, uint8_t &_4, uint8_t &_5) const { - _0 = bytes[0]; - _1 = bytes[1]; - _2 = bytes[2]; - _3 = bytes[3]; - _4 = bytes[4]; - _5 = bytes[5]; +Mac Mac::parseMac(string s) throw(BluetoothException) { + unsigned int bytes[6]; + int count = sscanf(s.c_str(), "%02x:%02x:%02x:%02x:%02x:%02x", + &bytes[0], &bytes[1], &bytes[2], &bytes[3], &bytes[4], &bytes[5]); + + if (count != 6) { + throw BluetoothException("Unable to parse mac: " + s); } - Mac *Mac::parseMac(string s) throw(BluetoothException) { - unsigned int bytes[6]; - int count = sscanf(s.c_str(), "%02x:%02x:%02x:%02x:%02x:%02x", - &bytes[0], &bytes[1], &bytes[2], &bytes[3], &bytes[4], &bytes[5]); + return Mac((uint8_t) bytes[0], (uint8_t) bytes[1], (uint8_t) bytes[2], (uint8_t) bytes[3], (uint8_t) bytes[4], (uint8_t) bytes[5]); +} - if (count != 6) { - throw BluetoothException("Unable to parse mac: " + s); - } +AttPdu::AttPdu(ByteBuffer &bytes) : bytes(bytes) { +} - return new Mac((uint8_t) bytes[0], (uint8_t) bytes[1], (uint8_t) bytes[2], (uint8_t) bytes[3], (uint8_t) bytes[4], (uint8_t) bytes[5]); - } +AttPdu::AttPdu(ByteBuffer &bytes, AttPduType type) : bytes(bytes) { + bytes.add8(type); +} - AttPdu::AttPdu(ByteBuffer &bytes) : bytes(bytes) { - } +AttPduType AttPdu::getType() { + return (AttPduType) bytes.get8(0); +} + +void AttPdu::makeReadByGroupType(ByteBuffer &bytes, uint16_t startHandle, uint16_t endHandle, uint16_t uuid) { + bytes.setCursor(0); + bytes.add8(AttPduType::READ_BY_GROUP_TYPE_REQ); + bytes.add16le(startHandle); + bytes.add16le(endHandle); + bytes.add16le(uuid); +} - AttPdu::AttPdu(ByteBuffer &bytes, AttPduType type) : bytes(bytes) { - bytes.add8(type); +void AttPdu::checkType(ByteBuffer &bytes, AttPduType type) { + if (bytes.getSize() == 0) { + throw BluetoothException("PDU is too small"); } - AttPduType AttPdu::getType() { - return (AttPduType) bytes.get8(0); + bytes.setCursor(0); + AttPduType t = (AttPduType) bytes.get8(); + + if (t != type) { + throw BluetoothException("Unexpected type: " + to_string(t)); } +} + +vector<AttributeData> AttPdu::parseReadByGroupType(ByteBuffer &bytes) { + DF << "bytes: " << bytes.toString(); + + checkType(bytes, READ_BY_GROUP_TYPE_RES); - void AttPdu::makeReadByGroupType(ByteBuffer &bytes, uint16_t startHandle, uint16_t endHandle, uint16_t uuid) { - bytes.setCursor(0); - bytes.add8(AttPduType::READ_BY_GROUP_TYPE_REQ); - bytes.add16le(startHandle); - bytes.add16le(endHandle); - bytes.add16le(uuid); + if (bytes.getSize() < 4) { + throw BluetoothException("Bad READ_BY_GROUP_TYPE_RES packet, expected at least 4 octets, got " + to_string(bytes.getSize())); } - void AttPdu::checkType(ByteBuffer &bytes, AttPduType type) { - if (bytes.getSize() == 0) { - throw BluetoothException("PDU is too small"); - } + uint8_t length = bytes.get8(); + D << "length=" << (int) length; - bytes.setCursor(0); - AttPduType t = (AttPduType) bytes.get8(); + size_t count = (bytes.getSize() - 2) / length; + D << "count=" << count; - if (t != type) { - throw BluetoothException("Unexpected type: " + to_string(t)); - } + vector<AttributeData> values; + for (int i = 0; i < count; i++) { + auto data = bytes.view(length); + D << "data, size=" << data.getSize() << ", bytes=" << data.toString(); + bytes.skip(length); + values.push_back(AttributeData::fromByteBuffer(data)); } - vector<AttributeData> AttPdu::parseReadByGroupType(ByteBuffer &bytes) { - DF; + return values; +} - checkType(bytes, READ_BY_GROUP_TYPE_RES); +// ----------------------------------------------------------------------- +// AttributeData +// ----------------------------------------------------------------------- - if (bytes.getSize() < 4) { - throw BluetoothException("Bad READ_BY_GROUP_TYPE_RES packet, expected at least 4 octets, got " + to_string(bytes.getSize())); - } +AttributeData AttributeData::fromByteBuffer(ByteBuffer &bytes) { + uint16_t handle = bytes.get16le(); + uint16_t groupEndHandle = bytes.get16le(); - uint8_t length = bytes.get8(); - D << "length=" << (int) length; + return AttributeData(handle, groupEndHandle, bytes.view()); +} - size_t count = (bytes.getSize() - 2) / length; - D << "count=" << count; +AttributeData::AttributeData(uint16_t handle, uint16_t groupEndHandle, ByteBuffer value) : + handle(handle), groupEndHandle(groupEndHandle), value(value) { +} - vector<AttributeData> values; - for (int i = 0; i < count; i++) { - auto data = bytes.view(length); - D << "data, size=" << data.getSize() << ", bytes=" << data.toString(); - bytes.skip(length); - values.push_back(AttributeData::fromByteBuffer(data)); - } +AttributeData::~AttributeData() { +} - return values; - } +// ----------------------------------------------------------------------- +// Adapter +// ----------------------------------------------------------------------- - // ----------------------------------------------------------------------- - // AttributeData - // ----------------------------------------------------------------------- +BluetoothAdapter::BluetoothAdapter() { +} - AttributeData AttributeData::fromByteBuffer(ByteBuffer &bytes) { - uint16_t handle = bytes.get16le(); - uint16_t groupEndHandle = bytes.get16le(); +BluetoothAdapter::~BluetoothAdapter() { +} - return AttributeData(handle, groupEndHandle, bytes.view()); - } +/* +map<int, LinuxBluetoothAdapter *> adapters; - AttributeData::AttributeData(uint16_t handle, uint16_t groupEndHandle, ByteBuffer value) : - handle(handle), groupEndHandle(groupEndHandle), value(value) { - } +BluetoothAdapter &getAdapter(int hciDevice) { + map<int, LinuxBluetoothAdapter *>::iterator it = adapters.find(hciDevice); - AttributeData::~AttributeData() { + if (it == adapters.end()) { + LinuxBluetoothAdapter *adapter = new LinuxBluetoothAdapter(hciDevice); + adapters[hciDevice] = adapter; + return *adapter; } - // ----------------------------------------------------------------------- - // Adapter - // ----------------------------------------------------------------------- + return *it->second; +} +*/ - BluetoothAdapter::~BluetoothAdapter() { - } +BluetoothAdapter &getAdapter(int hciDevice) { + return getAdapterImpl(hciDevice); +} + +void shutdown() { + shutdownImpl(); +} + +} }; diff --git a/Bluetooth.h b/Bluetooth.h index 7bc5bc3..1b5d5f0 100644 --- a/Bluetooth.h +++ b/Bluetooth.h @@ -10,127 +10,130 @@ #include "ByteBuffer.h" namespace trygvis { - using namespace std; - - class BluetoothAdapter; - - class BluetoothDevice; - - class BluetoothException : public runtime_error { - public: - 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(string const &what) : - runtime_error(what), adapter(nullptr), device(nullptr) { - } - - const BluetoothAdapter *adapter; - const BluetoothDevice *device; +namespace bluetooth { +using namespace std; + +class BluetoothAdapter; + +class BluetoothDevice; + +class BluetoothException : public runtime_error { +public: + 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(string const &what) : + runtime_error(what), adapter(nullptr), device(nullptr) { + } + + const BluetoothAdapter *adapter; + const BluetoothDevice *device; +}; + +class Mac { +public: + Mac(uint8_t _0, uint8_t _1, uint8_t _2, uint8_t _3, uint8_t _4, uint8_t _5) { + bytes[0] = _0; + bytes[1] = _1; + bytes[2] = _2; + bytes[3] = _3; + bytes[4] = _4; + bytes[5] = _5; }; - class Mac { - public: - Mac(uint8_t _0, uint8_t _1, uint8_t _2, uint8_t _3, uint8_t _4, uint8_t _5) { - bytes[0] = _0; - bytes[1] = _1; - bytes[2] = _2; - bytes[3] = _3; - bytes[4] = _4; - bytes[5] = _5; - }; + string str() const; - string str() const; + bool operator==(Mac &other) const; - bool operator==(Mac &other) const; + bool operator!=(Mac &other) const; - bool operator!=(Mac &other) const; + void copy(uint8_t &_0, uint8_t &_1, uint8_t &_2, uint8_t &_3, uint8_t &_4, uint8_t &_5) const; - void copy(uint8_t &_0, uint8_t &_1, uint8_t &_2, uint8_t &_3, uint8_t &_4, uint8_t &_5) const; + static Mac parseMac(string s) throw(BluetoothException); - static Mac *parseMac(string s) throw(BluetoothException); + friend bool operator<(const Mac &a, const Mac &b); - friend bool operator<(const Mac &a, const Mac &b); - private: - uint8_t bytes[6]; - }; +private: + uint8_t bytes[6]; +}; - class BluetoothDevice { - public: - virtual Mac const &mac() = 0; +class BluetoothDevice { +public: + virtual Mac const &mac() = 0; - virtual BluetoothAdapter &adapter() = 0; + virtual BluetoothAdapter &adapter() = 0; - virtual void connect() = 0; + virtual void connect() = 0; - virtual void disconnect() = 0; + virtual void disconnect() = 0; - virtual void discoverServices() = 0; - }; + virtual void discoverServices() = 0; +}; - class BluetoothAdapter { - public: - BluetoothAdapter() { - }; +class BluetoothAdapter { +public: + virtual void stopScan() = 0; - virtual ~BluetoothAdapter(); + virtual void runScan(void (callback)(BluetoothDevice &device)) = 0; - virtual void runScan(void (callback)(BluetoothDevice &device)) = 0; + virtual BluetoothDevice &getDevice(Mac &mac) = 0; - virtual void stopScan() = 0; +protected: + BluetoothAdapter(); - virtual void startScan() = 0; + virtual ~BluetoothAdapter(); +}; - virtual BluetoothDevice &getDevice(Mac& mac) = 0; - }; +enum AttPduType { + ERROR = 0x00, + READ_BY_GROUP_TYPE_REQ = 0x10, + READ_BY_GROUP_TYPE_RES = 0x11 +}; - enum AttPduType { - ERROR = 0x00, - READ_BY_GROUP_TYPE_REQ = 0x10, - READ_BY_GROUP_TYPE_RES = 0x11 - }; +class AttributeData; - class AttributeData; +class AttPdu { +public: + AttPdu(ByteBuffer &bytes); - class AttPdu { - public: - AttPdu(ByteBuffer &bytes); + AttPdu(ByteBuffer &bytes, AttPduType type); - AttPdu(ByteBuffer &bytes, AttPduType type); + AttPduType getType(); - AttPduType getType(); + static vector<AttributeData> parseReadByGroupType(ByteBuffer &bytes); - static vector <AttributeData> parseReadByGroupType(ByteBuffer &bytes); + static void makeReadByGroupType(ByteBuffer &bytes, uint16_t startHandle, uint16_t endHandle, uint16_t uuid); - static void makeReadByGroupType(ByteBuffer &bytes, uint16_t startHandle, uint16_t endHandle, uint16_t uuid); +private: + static void checkType(ByteBuffer &bytes, AttPduType type); - private: - static void checkType(ByteBuffer &bytes, AttPduType type); + ByteBuffer &bytes; +}; - ByteBuffer &bytes; - }; +class AttributeData { +public: + ~AttributeData(); - class AttributeData { - public: - ~AttributeData(); + static AttributeData fromByteBuffer(ByteBuffer &value); - static AttributeData fromByteBuffer(ByteBuffer &value); + const uint16_t handle; + const uint16_t groupEndHandle; + const ByteBuffer value; - const uint16_t handle; - const uint16_t groupEndHandle; - const ByteBuffer value; +private: + AttributeData(uint16_t handle, uint16_t groupEndHandle, ByteBuffer value); +}; - private: - AttributeData(uint16_t handle, uint16_t groupEndHandle, ByteBuffer value); - }; +BluetoothAdapter &getAdapter(int hciDevice); + +void shutdown(); -// BluetoothAdapter &getAdapter(int hciDevice); - BluetoothAdapter *getAdapter(int hciDevice); +} } #endif diff --git a/BluetoothImpl.h b/BluetoothImpl.h new file mode 100644 index 0000000..ba44853 --- /dev/null +++ b/BluetoothImpl.h @@ -0,0 +1,14 @@ +#ifndef BLUETOOTH_IMPL_H +#define BLUETOOTH_IMPL_H + +namespace trygvis { +namespace bluetooth { + +BluetoothAdapter &getAdapterImpl(int hciDevice); + +void shutdownImpl(); + +} +}; + +#endif diff --git a/ByteBuffer.cpp b/ByteBuffer.cpp index 2b2f33b..2d4a258 100644 --- a/ByteBuffer.cpp +++ b/ByteBuffer.cpp @@ -2,14 +2,11 @@ #include <string.h> #include <sstream> #include <iomanip> -#include <cassert> -#include <elf.h> -#include <stdint-gcc.h> using namespace std; ByteBuffer::ByteBuffer(const uint8_t *bytes, size_t capacity) : - bytes(bytes), capacity(capacity), zero(&bytes[0]), end(&bytes[0]) { + bytes(bytes), capacity(capacity), zero(&bytes[0]), end(&bytes[capacity]) { ptr = (uint8_t *) &bytes[0]; } @@ -78,10 +75,9 @@ ByteBuffer ByteBuffer::view(uint8_t *ptr, const uint8_t *end) const { void ByteBuffer::checkAndUpdateEnd(size_t newBytes) { uint8_t *newPtr = ptr + newBytes; if (newPtr >= end) { - throw ByteBufferException(string("New size is too large! cursor=") + to_string(getCursor()) + ", size=" + to_string(getSize()) + ", capacity=" + to_string(capacity)); - } - - if (newPtr > end) { + if (newPtr >= &zero[capacity]) { + throw ByteBufferException(string("New size is too large! cursor=") + to_string(getCursor()) + ", size=" + to_string(getSize()) + ", capacity=" + to_string(capacity)); + } end = newPtr; } } diff --git a/ByteBuffer.h b/ByteBuffer.h index 479a227..d1d02bb 100644 --- a/ByteBuffer.h +++ b/ByteBuffer.h @@ -17,8 +17,14 @@ public: class ByteBuffer { public: + /** + * Wrapping constructor, the size will be equal to the capacity. + */ ByteBuffer(const uint8_t *bytes, size_t capacity); + /** + * Wrapping constructor. + */ ByteBuffer(const uint8_t *bytes, size_t capacity, size_t zero, size_t size); inline size_t getSize() const { diff --git a/CMakeLists.txt b/CMakeLists.txt index 82dcfc8..5c596e8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -27,7 +27,10 @@ target_link_libraries(ble_toys ble) enable_testing() find_package(Boost COMPONENTS log unit_test_framework REQUIRED) + +# If we can change directory here add_definition and test-specific stuff could be moved to the test directory file(GLOB TEST_SRCS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} test/*.cpp) +add_definitions(-DBOOST_TEST_DYN_LINK) foreach(testSrc ${TEST_SRCS}) #Extract the filename without an extension (NAME_WE) diff --git a/LinuxBluetooth.cpp b/LinuxBluetooth.cpp index 1399161..3efa7e5 100644 --- a/LinuxBluetooth.cpp +++ b/LinuxBluetooth.cpp @@ -18,329 +18,343 @@ #define MAX_MTU 256 namespace trygvis { +namespace bluetooth { +namespace linux { - class LinuxBluetoothDevice; +class LinuxBluetoothDevice; - class LinuxBluetoothAdapter; +class LinuxBluetoothAdapter; - class LinuxBluetoothManager; +class LinuxBluetoothManager; - class LinuxBluetoothAdapter : public BluetoothAdapter { - public: - LinuxBluetoothAdapter(int hciDeviceId); +class LinuxBluetoothAdapter : public BluetoothAdapter { +public: + LinuxBluetoothAdapter(int hciDeviceId); - ~LinuxBluetoothAdapter(); + ~LinuxBluetoothAdapter(); - void runScan(void (*callback)(BluetoothDevice &device)) override; + void runScan(void (*callback)(BluetoothDevice &device)) override; - BluetoothDevice &getDevice(Mac &mac) override; + BluetoothDevice &getDevice(Mac &mac) override; - void startScan() override; +private: + void startScan(); - void stopScan() override; + void stopScan(); - private: + int hciDeviceId; + int hciSocket; + struct hci_filter hciFilter; + bool scanning; - int hciDeviceId; - int hciSocket; - struct hci_filter hciFilter; - bool scanning; - }; - - class LinuxBluetoothDevice : public BluetoothDevice { - public: - LinuxBluetoothDevice(LinuxBluetoothAdapter &adapter, Mac mac); + map<Mac, LinuxBluetoothDevice *> devices; +}; - Mac const &mac() override; +class LinuxBluetoothDevice : public BluetoothDevice { +public: + LinuxBluetoothDevice(LinuxBluetoothAdapter &adapter, Mac mac); - LinuxBluetoothAdapter &adapter() override; + Mac const &mac() override; - void connect() override; + LinuxBluetoothAdapter &adapter() override; - void disconnect() override; + void connect() override; - void discoverServices() override; + void disconnect() override; - private: - LinuxBluetoothAdapter &_adapter; - Mac _mac; - int l2cap; - }; + void discoverServices() override; - // Utilities +private: + LinuxBluetoothAdapter &_adapter; + Mac _mac; + int l2cap; +}; - string errnoAsString() { - return string(strerror(errno)); - }; +// Utilities - // ----------------------------------------------------------------------- - // Mac - // ----------------------------------------------------------------------- +string errnoAsString() { + return string(strerror(errno)); +}; - Mac parseMac(bdaddr_t &a) { - return Mac(a.b[0], a.b[1], a.b[2], a.b[3], a.b[4], a.b[5]); - } +// ----------------------------------------------------------------------- +// Mac +// ----------------------------------------------------------------------- - // ----------------------------------------------------------------------- - // Device - // ----------------------------------------------------------------------- +Mac parseMac(bdaddr_t &a) { + return Mac(a.b[0], a.b[1], a.b[2], a.b[3], a.b[4], a.b[5]); +} - LinuxBluetoothDevice::LinuxBluetoothDevice(LinuxBluetoothAdapter &adapter, Mac mac) : - _adapter(adapter), _mac(mac) { - } +// ----------------------------------------------------------------------- +// Device +// ----------------------------------------------------------------------- - Mac const &LinuxBluetoothDevice::mac() { - return _mac; - } +LinuxBluetoothDevice::LinuxBluetoothDevice(LinuxBluetoothAdapter &adapter, Mac mac) : + _adapter(adapter), _mac(mac) { +} - LinuxBluetoothAdapter &LinuxBluetoothDevice::adapter() { - return _adapter; - } +Mac const &LinuxBluetoothDevice::mac() { + return _mac; +} - void LinuxBluetoothDevice::connect() { - struct sockaddr_l2 addr; +LinuxBluetoothAdapter &LinuxBluetoothDevice::adapter() { + return _adapter; +} - D << "connect: mac=" << _mac.str(); +void LinuxBluetoothDevice::connect() { + struct sockaddr_l2 addr; - l2cap = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP); - if (l2cap < 0) { - throw BluetoothException(this, "LinuxBluetoothDevice::connect(): socket(): " + errnoAsString()); - } + D << "connect: mac=" << _mac.str(); - memset(&addr, 0, sizeof(addr)); - addr.l2_family = AF_BLUETOOTH; - addr.l2_bdaddr = {{0, 0, 0, 0, 0, 0}}; - addr.l2_cid = htobs(ATT_CID); - addr.l2_bdaddr_type = BDADDR_LE_PUBLIC; + l2cap = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP); + if (l2cap < 0) { + throw BluetoothException(this, "LinuxBluetoothDevice::connect(): socket(): " + errnoAsString()); + } - if (bind(l2cap, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - close(l2cap); - throw BluetoothException(this, "LinuxBluetoothDevice::connect(): bind(): " + errnoAsString()); - } + memset(&addr, 0, sizeof(addr)); + addr.l2_family = AF_BLUETOOTH; + addr.l2_bdaddr = {{0, 0, 0, 0, 0, 0}}; + addr.l2_cid = htobs(ATT_CID); + addr.l2_bdaddr_type = BDADDR_LE_PUBLIC; - 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) { - close(l2cap); - throw BluetoothException(this, "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], - addr.l2_bdaddr.b[4], - addr.l2_bdaddr.b[3], - addr.l2_bdaddr.b[2], - addr.l2_bdaddr.b[1], - addr.l2_bdaddr.b[0]); - - if (::connect(l2cap, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - close(l2cap); - throw BluetoothException(this, "LinuxBluetoothDevice::connect(): connect(): " + errnoAsString()); - } + if (bind(l2cap, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + close(l2cap); + throw BluetoothException(this, "LinuxBluetoothDevice::connect(): bind(): " + errnoAsString()); } - void LinuxBluetoothDevice::disconnect() { - DF << "mac=" << _mac.str(); + 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) { close(l2cap); + throw BluetoothException(this, "LinuxBluetoothDevice::connect(): setsockopt(): " + errnoAsString()); } - void LinuxBluetoothDevice::discoverServices() { - DF; + 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], + addr.l2_bdaddr.b[4], + addr.l2_bdaddr.b[3], + addr.l2_bdaddr.b[2], + addr.l2_bdaddr.b[1], + addr.l2_bdaddr.b[0]); + + if (::connect(l2cap, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + close(l2cap); + throw BluetoothException(this, "LinuxBluetoothDevice::connect(): connect(): " + errnoAsString()); + } +} - uint8_t buffer[MAX_MTU]; - ByteBuffer out = ByteBuffer(buffer, MAX_MTU); +void LinuxBluetoothDevice::disconnect() { + DF << "mac=" << _mac.str(); + close(l2cap); +} - AttPdu::makeReadByGroupType(out, 0x0001, 0xffff, UUID_PRIMARY_SERVICE); +void LinuxBluetoothDevice::discoverServices() { + DF; - D << "pdu.size()=" << out.getSize(); - ssize_t written = write(l2cap, buffer, out.getSize()); + uint8_t buffer[MAX_MTU]; + ByteBuffer out = ByteBuffer(buffer, MAX_MTU); - D << "written=" << written; + AttPdu::makeReadByGroupType(out, 0x0001, 0xffff, UUID_PRIMARY_SERVICE); - ssize_t r = read(l2cap, buffer, MAX_MTU); + D << "pdu.size()=" << out.getSize(); + ssize_t written = write(l2cap, buffer, out.getSize()); - if (r == -1) { - throw BluetoothException(this, "read(): " + errnoAsString()); - } + D << "written=" << written; - ByteBuffer in = ByteBuffer(buffer, r); + ssize_t r = read(l2cap, buffer, MAX_MTU); - D << "read: " << r << " bytes: " << in.toString(); + if (r == -1) { + throw BluetoothException(this, "read(): " + errnoAsString()); + } - vector<AttributeData> values = AttPdu::parseReadByGroupType(in); + ByteBuffer in = ByteBuffer(buffer, r); - D << "READ_BY_GROUP_TYPE response has " + to_string(values.size()) + " values"; + D << "read: " << r << " bytes: " << in.toString(); - for (auto &data: values) { - D << "handle: " << data.handle << ", value: " << data.value.toString(); - } - } + vector<AttributeData> values = AttPdu::parseReadByGroupType(in); - // ----------------------------------------------------------------------- - // Adapter - // ----------------------------------------------------------------------- + D << "READ_BY_GROUP_TYPE response has " + to_string(values.size()) + " values"; + for (auto &data: values) { + D << "handle: " << data.handle << ", groupEndHandle: " << data.groupEndHandle << ", value: " << data.value.toString(); + } +} - LinuxBluetoothAdapter::LinuxBluetoothAdapter(int hciDeviceId) { - DF << "hciDeviceId=" << hciDeviceId; +// ----------------------------------------------------------------------- +// Adapter +// ----------------------------------------------------------------------- - this->hciDeviceId = hciDeviceId; - hciSocket = ::hci_open_dev(hciDeviceId); +LinuxBluetoothAdapter::LinuxBluetoothAdapter(int hciDeviceId) : + scanning(false) { + DF << "hciDeviceId=" << hciDeviceId; - D << "HCI socket: " << hciSocket; + this->hciDeviceId = hciDeviceId; + hciSocket = ::hci_open_dev(hciDeviceId); - if (hciSocket == -1) { - throw BluetoothException(this, "Could not open HCI device " + to_string(hciDeviceId)); - } + D << "HCI socket: " << hciSocket; - hci_filter_clear(&hciFilter); - hci_filter_set_ptype(HCI_EVENT_PKT, &hciFilter); - hci_filter_set_event(EVT_LE_META_EVENT, &hciFilter); - hci_filter_set_event(EVT_LE_ADVERTISING_REPORT, &hciFilter); - setsockopt(hciSocket, SOL_HCI, HCI_FILTER, &hciFilter, sizeof(hciFilter)); + if (hciSocket == -1) { + throw BluetoothException(this, "Could not open HCI device " + to_string(hciDeviceId)); } - LinuxBluetoothAdapter::~LinuxBluetoothAdapter() { - DF; + hci_filter_clear(&hciFilter); + hci_filter_set_ptype(HCI_EVENT_PKT, &hciFilter); + hci_filter_set_event(EVT_LE_META_EVENT, &hciFilter); + hci_filter_set_event(EVT_LE_ADVERTISING_REPORT, &hciFilter); + setsockopt(hciSocket, SOL_HCI, HCI_FILTER, &hciFilter, sizeof(hciFilter)); +} - stopScan(); +LinuxBluetoothAdapter::~LinuxBluetoothAdapter() { + DF; - close(hciSocket); - } + stopScan(); - void LinuxBluetoothAdapter::startScan() { - DF; + close(hciSocket); - struct hci_dev_info di; + D << "Depeting " << devices.size() << " devices"; - if (hci_devinfo(hciDeviceId, &di) < 0) { - throw BluetoothException(this, "hci_devinfo: " + to_string(hciDeviceId)); - } + for (auto &pair : devices) { + delete pair.second; + } +} - D << "hciDeviceId.dev_id=" << di.dev_id; - D << "hciDeviceId.bdaddr=" << parseMac(di.bdaddr).str(); - D << "hciDeviceId.flags=" << hex << setw(8) << setfill('0') << di.flags; - D << "hciDeviceId.flags RUNNING = " << hci_test_bit(HCI_RUNNING, &di.flags); - D << "hciDeviceId.flags UP = " << hci_test_bit(HCI_UP, &di.flags); - D << "hciDeviceId.flags PSCAN = " << hci_test_bit(HCI_PSCAN, &di.flags); - D << "hciDeviceId.flags ISCAN = " << hci_test_bit(HCI_ISCAN, &di.flags); - D << "hciDeviceId.name=" << di.name; +void LinuxBluetoothAdapter::startScan() { + DF; - int up = hci_test_bit(HCI_UP, &di.flags); + struct hci_dev_info di; - if (!up) { - throw BluetoothException(this, "HCI adapter is not up: " + to_string(hciDeviceId)); - } + if (hci_devinfo(hciDeviceId, &di) < 0) { + throw BluetoothException(this, "HCI adapter is not up: " + to_string(hciDeviceId)); + } - if (hci_le_set_scan_parameters(hciSocket, 0x01, htobs(0x0010), htobs(0x0010), 0x00, 0, 1000) < 0) { - throw BluetoothException(this, "hci_le_set_scan_parameters: " + errnoAsString()); - } + D << "hciDeviceId.dev_id=" << di.dev_id; + D << "hciDeviceId.bdaddr=" << parseMac(di.bdaddr).str(); + D << "hciDeviceId.flags=" << setw(8) << setfill('0') << hex << di.flags; + D << "hciDeviceId.flags RUNNING = " << hci_test_bit(HCI_RUNNING, &di.flags); + D << "hciDeviceId.flags UP = " << hci_test_bit(HCI_UP, &di.flags); + D << "hciDeviceId.flags PSCAN = " << hci_test_bit(HCI_PSCAN, &di.flags); + D << "hciDeviceId.flags ISCAN = " << hci_test_bit(HCI_ISCAN, &di.flags); + D << "hciDeviceId.name=" << di.name; - if (hci_le_set_scan_enable(hciSocket, 1, 0, 1000)) { - throw BluetoothException(this, "Could not start scanning: other" + errnoAsString()); - } + int up = hci_test_bit(HCI_UP, &di.flags); - scanning = true; + if (!up) { + throw BluetoothException(this, "HCI adapter is not up: " + hciDeviceId); } - void LinuxBluetoothAdapter::stopScan() { - DF; + if (hci_le_set_scan_parameters(hciSocket, 0x01, htobs(0x0010), htobs(0x0010), 0x00, 0, 1000) < 0) { + throw BluetoothException(this, "hci_le_set_scan_parameters: " + errnoAsString()); + } - if (!scanning) { - return; - } + if (hci_le_set_scan_enable(hciSocket, 1, 0, 1000)) { + throw BluetoothException(this, "Could not start scanning: other" + errnoAsString()); + } - scanning = false; + scanning = true; +} - if (hci_le_set_scan_enable(hciSocket, 0, 0, 1000) < 0) { - W << "stopScan: hci_le_set_scan_enable: " << errnoAsString(); - } +void LinuxBluetoothAdapter::stopScan() { + DF; + + if (!scanning) { + return; } - BluetoothDevice &LinuxBluetoothAdapter::getDevice(Mac &mac) { - static map<Mac, LinuxBluetoothDevice *> devices; + scanning = false; - map<Mac, LinuxBluetoothDevice *>::iterator it = devices.find(mac); + if (hci_le_set_scan_enable(hciSocket, 0, 0, 1000) < 0) { + W << "stopScan: hci_le_set_scan_enable: " << errnoAsString(); + } +} - if (it == devices.end()) { - LinuxBluetoothDevice *device = new LinuxBluetoothDevice(*this, mac); - devices[mac] = device; - return *device; - } +BluetoothDevice &LinuxBluetoothAdapter::getDevice(Mac &mac) { + map<Mac, LinuxBluetoothDevice *>::iterator it = devices.find(mac); - return *it->second; + if (it == devices.end()) { + LinuxBluetoothDevice *device = new LinuxBluetoothDevice(*this, mac); + devices[mac] = device; + return *device; } - void LinuxBluetoothAdapter::runScan(void (*callback)(BluetoothDevice &device)) { - fd_set rfds; - FD_ZERO(&rfds); - FD_SET(hciSocket, &rfds); + return *it->second; +} + +void LinuxBluetoothAdapter::runScan(void (*callback)(BluetoothDevice &device)) { + fd_set rfds; + FD_ZERO(&rfds); + FD_SET(hciSocket, &rfds); - startScan(); + startScan(); - while (scanning) { - // Linux can change tv, so it has to be reinitialized - struct timeval tv; - tv.tv_sec = 1; - tv.tv_usec = 0; + while (scanning) { + // Linux can change tv, so it has to be reinitialized + struct timeval tv; + tv.tv_sec = 1; + tv.tv_usec = 0; - int selected = select(hciSocket + 1, &rfds, NULL, NULL, &tv); + int selected = select(hciSocket + 1, &rfds, NULL, NULL, &tv); - if (selected == -1) { - throw BluetoothException(this, "select() failed"); - } + if (selected == -1) { + throw BluetoothException(this, "select() failed"); + } - if (selected == 0) { - D << "timeout"; - // Timeout, just continue - continue; - } + if (selected == 0) { + D << "timeout"; + // Timeout, just continue + continue; + } - unsigned char hciEventBuf[HCI_MAX_EVENT_SIZE]; + unsigned char hciEventBuf[HCI_MAX_EVENT_SIZE]; - ssize_t len = read(hciSocket, hciEventBuf, sizeof(hciEventBuf)); - evt_le_meta_event *metaEvent = (evt_le_meta_event *) (hciEventBuf + (1 + HCI_EVENT_HDR_SIZE)); - len -= (1 + HCI_EVENT_HDR_SIZE); + ssize_t len = read(hciSocket, hciEventBuf, sizeof(hciEventBuf)); + evt_le_meta_event *metaEvent = (evt_le_meta_event *) (hciEventBuf + (1 + HCI_EVENT_HDR_SIZE)); + len -= (1 + HCI_EVENT_HDR_SIZE); - D << "metaEvent->subevent = " << std::hex << (int) metaEvent->subevent; + D << "metaEvent->subevent = " << std::hex << (int) metaEvent->subevent; - if (metaEvent->subevent == EVT_LE_ADVERTISING_REPORT) { - le_advertising_info *advertisingInfo = (le_advertising_info *) (metaEvent->data + 1); + if (metaEvent->subevent == EVT_LE_ADVERTISING_REPORT) { + le_advertising_info *advertisingInfo = (le_advertising_info *) (metaEvent->data + 1); - Mac mac = parseMac(advertisingInfo->bdaddr); + Mac mac = parseMac(advertisingInfo->bdaddr); - BluetoothDevice &device = getDevice(mac); + BluetoothDevice &device = getDevice(mac); - callback(device); - } + callback(device); } } +} - // ----------------------------------------------------------------------- - // - // ----------------------------------------------------------------------- +}}} - /* - map<int, LinuxBluetoothAdapter *> adapters; +// ----------------------------------------------------------------------- +// Implementation of platform-specific method. +// ----------------------------------------------------------------------- - BluetoothAdapter &getAdapter(int hciDevice) { - map<int, LinuxBluetoothAdapter *>::iterator it = adapters.find(hciDevice); +namespace trygvis { +namespace bluetooth { +using namespace trygvis::bluetooth::linux; - if (it == adapters.end()) { - LinuxBluetoothAdapter *adapter = new LinuxBluetoothAdapter(hciDevice); - adapters[hciDevice] = adapter; - return *adapter; - } +map<int, LinuxBluetoothAdapter *> adapters; + +LinuxBluetoothAdapter &getAdapterImpl(int hciDevice) { + map<int, LinuxBluetoothAdapter *>::iterator it = adapters.find(hciDevice); - return *it->second; + if (it == adapters.end()) { + LinuxBluetoothAdapter *adapter = new LinuxBluetoothAdapter(hciDevice); + adapters[hciDevice] = adapter; + return *adapter; } - */ - BluetoothAdapter *getAdapter(int hciDevice) { - return new LinuxBluetoothAdapter(hciDevice); + return *it->second; +} + +void shutdownImpl() { + for (auto &pair: adapters) { + delete pair.second; } -}; +} + +}} @@ -3,9 +3,9 @@ #include "Bluetooth.h" using namespace std; -using namespace trygvis; +using namespace trygvis::bluetooth; -static Mac *targetMac; +Mac *targetMac; void scan_callback(BluetoothDevice &device) { device.adapter().stopScan(); @@ -30,14 +30,14 @@ int main(int argc, char *argv[]) { return EXIT_FAILURE; } - BluetoothAdapter *adapter = nullptr; int e; // try { - targetMac = Mac::parseMac(argv[1]); + Mac mac = Mac::parseMac(argv[1]); + targetMac = &mac; - adapter = trygvis::getAdapter(0); + BluetoothAdapter &adapter = getAdapter(0); - BluetoothDevice &device = adapter->getDevice(*targetMac); + BluetoothDevice &device = adapter.getDevice(mac); scan_callback(device); @@ -52,8 +52,6 @@ int main(int argc, char *argv[]) { // e = EXIT_FAILURE; // } - if (adapter != nullptr) { - delete adapter; - } + shutdown(); return e; } diff --git a/test/ByteBufferTest.cpp b/test/ByteBufferTest.cpp index ed842f2..2a9bb8c 100644 --- a/test/ByteBufferTest.cpp +++ b/test/ByteBufferTest.cpp @@ -1,8 +1,5 @@ #include "ByteBuffer.h" -#define BOOST_TEST_DYN_LINK - -//Define our Module name (prints at testing) #define BOOST_TEST_MODULE "ByteBuffer" #include <boost/test/unit_test.hpp> @@ -35,12 +32,11 @@ public: size_t capacity; }; -/* BOOST_AUTO_TEST_CASE(empty_buffer) { - Bytes b(1000); - ByteBuffer buffer(b.bytes, b.capacity, 0, 0); + Bytes b(0); + ByteBuffer buffer(b.bytes, b.capacity); - checkBuffer(buffer, 0, 1000, 0); + checkBuffer(buffer, 0, 0, 0); try { buffer.get8(); @@ -48,7 +44,6 @@ BOOST_AUTO_TEST_CASE(empty_buffer) { } catch (ByteBufferException e) { } } -*/ BOOST_AUTO_TEST_CASE(basic) { Bytes b(1000); |