aboutsummaryrefslogtreecommitdiff
path: root/LinuxBluetooth.cpp
diff options
context:
space:
mode:
authorTrygve Laugstøl <trygvis@inamo.no>2015-02-15 23:29:17 +0100
committerTrygve Laugstøl <trygvis@inamo.no>2015-02-15 23:35:36 +0100
commit0d0543e4daeb1c6b01d4799736026b6f3aef9779 (patch)
tree0f14cac6264710700c70f18c79e41a8aaa6a8cfd /LinuxBluetooth.cpp
parent60d5440dd3514e71b87948ff5ed30ee38445b8a5 (diff)
downloadble-toys-0d0543e4daeb1c6b01d4799736026b6f3aef9779.tar.gz
ble-toys-0d0543e4daeb1c6b01d4799736026b6f3aef9779.tar.bz2
ble-toys-0d0543e4daeb1c6b01d4799736026b6f3aef9779.tar.xz
ble-toys-0d0543e4daeb1c6b01d4799736026b6f3aef9779.zip
valgrind tests
Diffstat (limited to 'LinuxBluetooth.cpp')
-rw-r--r--LinuxBluetooth.cpp457
1 files changed, 236 insertions, 221 deletions
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;
}
-};
+}
+
+}}