diff options
-rw-r--r-- | Bluetooth.cpp | 221 | ||||
-rw-r--r-- | Bluetooth.h | 177 | ||||
-rw-r--r-- | BluetoothImpl.h | 14 | ||||
-rw-r--r-- | ByteBuffer.cpp | 23 | ||||
-rw-r--r-- | CMakeLists.txt | 3 | ||||
-rw-r--r-- | LinuxBluetooth.cpp | 457 | ||||
-rw-r--r-- | main.cpp | 16 | ||||
-rw-r--r-- | test/ByteBufferTest.cpp | 37 |
8 files changed, 512 insertions, 436 deletions
diff --git a/Bluetooth.cpp b/Bluetooth.cpp index dd9e48e..e6d6d28 100644 --- a/Bluetooth.cpp +++ b/Bluetooth.cpp @@ -2,137 +2,170 @@ #include <iomanip> #include <string.h> #include "Bluetooth.h" +#include "BluetoothImpl.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); +} - AttPdu::AttPdu(ByteBuffer &bytes, AttPduType type) : bytes(bytes) { - bytes.add8(type); +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); +} + +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: " + t); } +} - 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); +vector<AttributeData> AttPdu::parseReadByGroupType(ByteBuffer &bytes) { + DF << "bytes: " << bytes.toString(); + + checkType(bytes, READ_BY_GROUP_TYPE_RES); + + if (bytes.getSize() < 4) { + throw BluetoothException("Bad READ_BY_GROUP_TYPE_RES packet, expected at least 4 octets, got " + bytes.getSize()); } - void AttPdu::checkType(ByteBuffer &bytes, AttPduType type) { - if (bytes.getSize() == 0) { - throw BluetoothException("PDU is too small"); - } + uint8_t length = bytes.get8(); + DF << "length=" << (int) length; - bytes.setCursor(0); - AttPduType t = (AttPduType) bytes.get8(); + size_t count = (bytes.getSize() - 2) / length; + DF << "count=" << count; - if (t != type) { - throw BluetoothException("Unexpected type: " + t); - } + vector<AttributeData> values; + for (int i = 0; i < count; i++) { + values.push_back(AttributeData::fromByteBuffer(bytes, length)); } - vector<AttributeData> AttPdu::parseReadByGroupType(ByteBuffer &bytes) { - checkType(bytes, READ_BY_GROUP_TYPE_RES); + return values; +} - if (bytes.getSize() < 4) { - throw BluetoothException("Bad READ_BY_GROUP_TYPE_RES packet, expected at least 4 octets, got " + bytes.getSize()); - } +// ----------------------------------------------------------------------- +// AttributeData +// ----------------------------------------------------------------------- - uint8_t length = bytes.get8(); - DF << "length=" << (int) length; +AttributeData AttributeData::fromByteBuffer(ByteBuffer &bytes, uint8_t length) { + uint16_t handle = bytes.get16le(); + uint16_t groupEndHandle = bytes.get16le(); - size_t count = (bytes.getSize() - 2) / length; - DF << "count=" << count; + return AttributeData(handle, groupEndHandle, bytes.view(length - 4)); +} - vector<AttributeData> values; - for (int i = 0; i < count; i++) { - values.push_back(AttributeData::fromByteBuffer(bytes, length)); - } +AttributeData::AttributeData(uint16_t handle, uint16_t groupEndHandle, ByteBuffer value) : + handle(handle), groupEndHandle(groupEndHandle), value(value) { +} - return values; - } +AttributeData::~AttributeData() { +} - // ----------------------------------------------------------------------- - // AttributeData - // ----------------------------------------------------------------------- +// ----------------------------------------------------------------------- +// Adapter +// ----------------------------------------------------------------------- - AttributeData AttributeData::fromByteBuffer(ByteBuffer &bytes, uint8_t length) { - uint16_t handle = bytes.get16le(); - uint16_t groupEndHandle = bytes.get16le(); +BluetoothAdapter::BluetoothAdapter() { +} - return AttributeData(handle, groupEndHandle, bytes.view(length)); - } +BluetoothAdapter::~BluetoothAdapter() { +} - AttributeData::AttributeData(uint16_t handle, uint16_t groupEndHandle, ByteBuffer value) : - handle(handle), groupEndHandle(groupEndHandle), value(value) { - } +/* +map<int, LinuxBluetoothAdapter *> adapters; - AttributeData::~AttributeData() { +BluetoothAdapter &getAdapter(int hciDevice) { + map<int, LinuxBluetoothAdapter *>::iterator it = adapters.find(hciDevice); + + 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 15ef171..7ed7b8c 100644 --- a/Bluetooth.h +++ b/Bluetooth.h @@ -21,125 +21,130 @@ #define UUID_SECONDARY_SERVICE 0x2801 namespace trygvis { - using namespace std; +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 BluetoothAdapter; + string str() const; - class BluetoothDevice; + bool operator==(Mac &other) const; - class BluetoothException : public runtime_error { - public: - BluetoothException(const BluetoothAdapter *adapter, string const &what) : - runtime_error(what), adapter(adapter), device(nullptr) { - } + bool operator!=(Mac &other) const; - BluetoothException(const BluetoothDevice *device, string const &what) : - runtime_error(what), adapter(nullptr), device(device) { - } + void copy(uint8_t &_0, uint8_t &_1, uint8_t &_2, uint8_t &_3, uint8_t &_4, uint8_t &_5) const; - BluetoothException(string const &what) : - runtime_error(what), adapter(nullptr), device(nullptr) { - } + static Mac parseMac(string s) throw(BluetoothException); - const BluetoothAdapter *adapter; - const BluetoothDevice *device; - }; + friend bool operator<(const Mac &a, const Mac &b); - 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; - }; +private: + uint8_t bytes[6]; +}; - string str() const; +class BluetoothDevice { +public: + virtual Mac const &mac() = 0; - bool operator==(Mac &other) const; + virtual BluetoothAdapter &adapter() = 0; - bool operator!=(Mac &other) const; + virtual void connect() = 0; - void copy(uint8_t &_0, uint8_t &_1, uint8_t &_2, uint8_t &_3, uint8_t &_4, uint8_t &_5) const; + virtual void disconnect() = 0; - static Mac *parseMac(string s) throw(BluetoothException); + virtual void discoverServices() = 0; +}; - friend bool operator<(const Mac &a, const Mac &b); - private: - uint8_t bytes[6]; - }; +class BluetoothAdapter { +public: + virtual void stopScan() = 0; - class BluetoothDevice { - public: - virtual Mac const &mac() = 0; + virtual void runScan(void (callback)(BluetoothDevice &device)) = 0; - virtual BluetoothAdapter &adapter() = 0; + virtual BluetoothDevice &getDevice(Mac &mac) = 0; - virtual void connect() = 0; +protected: + BluetoothAdapter(); - virtual void disconnect() = 0; + virtual ~BluetoothAdapter(); +}; - virtual void discoverServices() = 0; - }; +enum AttPduType { + ERROR = 0x00, + READ_BY_GROUP_TYPE_REQ = 0x10, + READ_BY_GROUP_TYPE_RES = 0x11 +}; - class BluetoothAdapter { - public: - BluetoothAdapter() { - }; +class AttributeData; - virtual ~BluetoothAdapter(); +class AttPdu { +public: + AttPdu(ByteBuffer &bytes); - virtual void stopScan() = 0; + AttPdu(ByteBuffer &bytes, AttPduType type); - virtual void runScan(void (callback)(BluetoothDevice &device)) = 0; + AttPduType getType(); - virtual BluetoothDevice &getDevice(Mac& mac) = 0; - }; + static vector<AttributeData> parseReadByGroupType(ByteBuffer &bytes); - enum AttPduType { - ERROR = 0x00, - READ_BY_GROUP_TYPE_REQ = 0x10, - READ_BY_GROUP_TYPE_RES = 0x11 - }; + static void makeReadByGroupType(ByteBuffer &bytes, uint16_t startHandle, uint16_t endHandle, uint16_t uuid); - class AttributeData; +private: + static void checkType(ByteBuffer &bytes, AttPduType type); - class AttPdu { - public: - AttPdu(ByteBuffer &bytes); + ByteBuffer &bytes; +}; - AttPdu(ByteBuffer &bytes, AttPduType type); +class AttributeData { +public: + ~AttributeData(); - AttPduType getType(); + static AttributeData fromByteBuffer(ByteBuffer &value, uint8_t length); - static vector <AttributeData> parseReadByGroupType(ByteBuffer &bytes); + const uint16_t handle; + const uint16_t groupEndHandle; + const ByteBuffer value; - static void makeReadByGroupType(ByteBuffer &bytes, uint16_t startHandle, uint16_t endHandle, uint16_t uuid); +private: + AttributeData(uint16_t handle, uint16_t groupEndHandle, ByteBuffer value); +}; - private: - static void checkType(ByteBuffer &bytes, AttPduType type); +BluetoothAdapter &getAdapter(int hciDevice); - ByteBuffer &bytes; - }; +void shutdown(); - class AttributeData { - public: - ~AttributeData(); - - static AttributeData fromByteBuffer(ByteBuffer &value, uint8_t length); - - const uint16_t handle; - const uint16_t groupEndHandle; - const ByteBuffer value; - - private: - AttributeData(uint16_t handle, uint16_t groupEndHandle, ByteBuffer value); - }; - -// 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 f27deeb..a33589e 100644 --- a/ByteBuffer.cpp +++ b/ByteBuffer.cpp @@ -10,54 +10,55 @@ using namespace std; ByteBuffer::ByteBuffer(uint8_t *bytes, size_t capacity, size_t size, size_t zero) : bytes(bytes), capacity(capacity), size(size), cursor(zero), zero(zero) { assert(zero <= size); + assert(size <= capacity); } ByteBuffer &ByteBuffer::add8(uint8_t value) { checkAndUpdateSize(1); - bytes[zero + cursor++] = value; + bytes[cursor++] = value; return *this; } ByteBuffer &ByteBuffer::add16le(uint16_t value) { checkAndUpdateSize(2); - bytes[zero + cursor++] = (uint8_t) (value & 0xff); - bytes[zero + cursor++] = (uint8_t) ((value >> 8) & 0xff); + bytes[cursor++] = (uint8_t) (value & 0xff); + bytes[cursor++] = (uint8_t) ((value >> 8) & 0xff); return *this; } uint8_t ByteBuffer::get8(size_t index) { canAccessIndex(index); - return bytes[zero + cursor]; + return bytes[cursor]; } uint8_t ByteBuffer::get8() { canAccessIndex(cursor); - return bytes[zero + cursor++]; + return bytes[cursor++]; } uint16_t ByteBuffer::get16le() { canAccessIndex(cursor + 1); uint16_t value; - value = bytes[zero + cursor++]; - value |= ((uint16_t) bytes[zero + cursor++]) << 8; + value = bytes[cursor++]; + value |= ((uint16_t) bytes[cursor++]) << 8; return value; } void ByteBuffer::copy(uint8_t *bytes, size_t length) { - canAccessIndex(cursor + length); + canAccessIndex(length); - memcpy(bytes, &this->bytes[zero + cursor], length); + memcpy(bytes, &this->bytes[cursor], length); cursor += length; } ByteBuffer ByteBuffer::view(size_t length) { canAccessIndex(cursor + length); - size_t s = zero + cursor + length; + size_t s = cursor + length; return ByteBuffer(bytes, s, s, cursor); } void ByteBuffer::checkAndUpdateSize(size_t newBytes) { - size_t newSize = zero + cursor + newBytes; + size_t newSize = cursor + newBytes; if (newSize >= capacity) { throw ByteBufferException(string("Out of bounds! zero=") + to_string(zero) + ", cursor=" + to_string(cursor) + ", size=" + to_string(size) + ", capacity=" + to_string(capacity) + ", newSize=" + to_string(newSize)); } diff --git a/CMakeLists.txt b/CMakeLists.txt index 1220f20..1098415 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -27,7 +27,10 @@ target_link_libraries(ble_toys ble) enable_testing() find_package(Boost COMPONENTS 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 c30a2b7..5a00f53 100644 --- a/LinuxBluetooth.cpp +++ b/LinuxBluetooth.cpp @@ -18,323 +18,338 @@ #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)); + void runScan(void (*callback)(BluetoothDevice &device)); - BluetoothDevice &getDevice(Mac &mac) override; + BluetoothDevice &getDevice(Mac &mac) override; - private: - void startScan(); +private: + void startScan(); - void stopScan(); + void stopScan(); - 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; - } - - void LinuxBluetoothDevice::connect() { - struct sockaddr_l2 addr; +Mac const &LinuxBluetoothDevice::mac() { + return _mac; +} - D << "connect: mac=" << _mac.str(); +LinuxBluetoothAdapter &LinuxBluetoothDevice::adapter() { + return _adapter; +} - l2cap = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP); - if (l2cap < 0) { - throw BluetoothException(this, "LinuxBluetoothDevice::connect(): socket(): " + errnoAsString()); - } +void LinuxBluetoothDevice::connect() { + struct sockaddr_l2 addr; - 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; + D << "connect: mac=" << _mac.str(); - if (bind(l2cap, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - close(l2cap); - throw BluetoothException(this, "LinuxBluetoothDevice::connect(): bind(): " + errnoAsString()); - } + l2cap = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP); + if (l2cap < 0) { + throw BluetoothException(this, "LinuxBluetoothDevice::connect(): socket(): " + errnoAsString()); + } - 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_bdaddr = {{0, 0, 0, 0, 0, 0}}; + addr.l2_cid = htobs(ATT_CID); + addr.l2_bdaddr_type = BDADDR_LE_PUBLIC; - 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, 0); +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, 0); - D << "written=" << written; + AttPdu::makeReadByGroupType(out, 0x0001, 0xffff, UUID_PRIMARY_SERVICE); - ssize_t r = read(l2cap, buffer, MAX_MTU); - ByteBuffer in = ByteBuffer(buffer, MAX_MTU, r); + D << "pdu.size()=" << out.getSize(); + ssize_t written = write(l2cap, buffer, out.getSize()); - D << "read: " << r << " bytes"; + D << "written=" << written; - vector<AttributeData> values = AttPdu::parseReadByGroupType(in); + ssize_t r = read(l2cap, buffer, MAX_MTU); + ByteBuffer in = ByteBuffer(buffer, MAX_MTU, r); - D << "READ_BY_GROUP_TYPE response has " + to_string(values.size()) + " values"; + D << "read: " << r << " bytes"; - 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 " + 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 " + 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: " + 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: " + hciDeviceId); - } + if (hci_devinfo(hciDeviceId, &di) < 0) { + throw BluetoothException(this, "hci_devinfo: " + 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=" << 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; - 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; +} - startScan(); +void LinuxBluetoothAdapter::runScan(void (*callback)(BluetoothDevice &device)) { + fd_set rfds; + FD_ZERO(&rfds); + FD_SET(hciSocket, &rfds); - while (scanning) { - // Linux can change tv, so it has to be reinitialized - struct timeval tv; - tv.tv_sec = 1; - tv.tv_usec = 0; + startScan(); - int selected = select(hciSocket + 1, &rfds, NULL, NULL, &tv); + while (scanning) { + // Linux can change tv, so it has to be reinitialized + struct timeval tv; + tv.tv_sec = 1; + tv.tv_usec = 0; - if (selected == -1) { - throw BluetoothException(this, "select() failed"); - } + int selected = select(hciSocket + 1, &rfds, NULL, NULL, &tv); - if (selected == 0) { - D << "timeout"; - // Timeout, just continue - continue; - } + if (selected == -1) { + throw BluetoothException(this, "select() failed"); + } - unsigned char hciEventBuf[HCI_MAX_EVENT_SIZE]; + if (selected == 0) { + D << "timeout"; + // Timeout, just continue + continue; + } - 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); + unsigned char hciEventBuf[HCI_MAX_EVENT_SIZE]; - D << "metaEvent->subevent = " << std::hex << (int) metaEvent->subevent; + 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); - if (metaEvent->subevent == EVT_LE_ADVERTISING_REPORT) { - le_advertising_info *advertisingInfo = (le_advertising_info *) (metaEvent->data + 1); + D << "metaEvent->subevent = " << std::hex << (int) metaEvent->subevent; - Mac mac = parseMac(advertisingInfo->bdaddr); + if (metaEvent->subevent == EVT_LE_ADVERTISING_REPORT) { + le_advertising_info *advertisingInfo = (le_advertising_info *) (metaEvent->data + 1); - BluetoothDevice &device = getDevice(mac); + Mac mac = parseMac(advertisingInfo->bdaddr); - callback(device); - } + BluetoothDevice &device = getDevice(mac); + + callback(device); } } +} + +}}} - // ----------------------------------------------------------------------- - // - // ----------------------------------------------------------------------- +// ----------------------------------------------------------------------- +// Implementation of platform-specific method. +// ----------------------------------------------------------------------- - /* - map<int, LinuxBluetoothAdapter *> adapters; +namespace trygvis { +namespace bluetooth { +using namespace trygvis::bluetooth::linux; - BluetoothAdapter &getAdapter(int hciDevice) { - map<int, LinuxBluetoothAdapter *>::iterator it = adapters.find(hciDevice); +map<int, LinuxBluetoothAdapter *> adapters; - if (it == adapters.end()) { - LinuxBluetoothAdapter *adapter = new LinuxBluetoothAdapter(hciDevice); - adapters[hciDevice] = adapter; - return *adapter; - } +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 f98a770..70a98ab 100644 --- a/test/ByteBufferTest.cpp +++ b/test/ByteBufferTest.cpp @@ -1,12 +1,20 @@ #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> +class Utils { +public: + uint8_t bytes[1000]; + + Utils() { + for (int i = 0; i < sizeof(bytes); i++) { + bytes[i] = (uint8_t) i; + } + } +}; + void checkBuffer(ByteBuffer& buffer, size_t size, size_t capacity, size_t cursor) { BOOST_CHECK(buffer.getSize() == size); BOOST_CHECK(buffer.getCapacity() == capacity); @@ -14,13 +22,8 @@ void checkBuffer(ByteBuffer& buffer, size_t size, size_t capacity, size_t cursor } BOOST_AUTO_TEST_CASE(empty_buffer) { - uint8_t bytes[1000]; - - for (int i = 0; i < sizeof(bytes); i++) { - bytes[i] = (uint8_t) i; - } - - ByteBuffer buffer(bytes, sizeof(bytes), 0, 0); + Utils u; + ByteBuffer buffer(u.bytes, sizeof(u.bytes), 0, 0); checkBuffer(buffer, 0, 1000, 0); @@ -32,13 +35,17 @@ BOOST_AUTO_TEST_CASE(empty_buffer) { } BOOST_AUTO_TEST_CASE(basic) { - uint8_t bytes[1000]; + Utils u; + ByteBuffer buffer(u.bytes, sizeof(u.bytes), 10, 0); + checkBuffer(buffer, 10, 1000, 0); - for (int i = 0; i < sizeof(bytes); i++) { - bytes[i] = (uint8_t) i; - } + buffer.get8(); + checkBuffer(buffer, 10, 1000, 1); +} - ByteBuffer buffer(bytes, sizeof(bytes), 10, 0); +BOOST_AUTO_TEST_CASE(view) { + Utils u; + ByteBuffer buffer(u.bytes, sizeof(u.bytes), 10, 0); checkBuffer(buffer, 10, 1000, 0); buffer.get8(); |