diff options
Diffstat (limited to 'ble/LinuxBluetooth.cpp')
-rw-r--r-- | ble/LinuxBluetooth.cpp | 169 |
1 files changed, 118 insertions, 51 deletions
diff --git a/ble/LinuxBluetooth.cpp b/ble/LinuxBluetooth.cpp index 444e3a2..cc6516d 100644 --- a/ble/LinuxBluetooth.cpp +++ b/ble/LinuxBluetooth.cpp @@ -38,8 +38,9 @@ class LinuxBluetoothManager; class LinuxBluetoothGattService : public DefaultBluetoothGattService<LinuxBluetoothDevice> { public: - explicit LinuxBluetoothGattService(LinuxBluetoothDevice &device, const Uuid& uuid, const uint16_t handle, - const uint16_t endGroupHandle) : DefaultBluetoothGattService(device, uuid, handle, endGroupHandle) { + explicit LinuxBluetoothGattService(LinuxBluetoothDevice &device, const Uuid &uuid, const uint16_t handle, + const uint16_t endGroupHandle) : + DefaultBluetoothGattService(device, uuid, handle, endGroupHandle) { }; LinuxBluetoothGattService(const LinuxBluetoothGattService &o) = delete; @@ -53,7 +54,7 @@ public: LinuxBluetoothAdapter(const LinuxBluetoothAdapter &) = delete; - LinuxBluetoothAdapter& operator=(const LinuxBluetoothAdapter&) = delete; + LinuxBluetoothAdapter &operator=(const LinuxBluetoothAdapter &) = delete; void runScan(std::function<void(const shared_ptr<BluetoothDevice> &device)>) override; @@ -81,7 +82,7 @@ public: LinuxBluetoothDevice(const LinuxBluetoothDevice &) = delete; - LinuxBluetoothDevice& operator=(const LinuxBluetoothDevice&) = delete; + LinuxBluetoothDevice &operator=(const LinuxBluetoothDevice &) = delete; shared_ptr<BluetoothGatt> connectGatt() override; @@ -95,9 +96,9 @@ public: ~LinuxBluetoothGatt() override; - LinuxBluetoothGatt(const LinuxBluetoothGatt&) = delete; + LinuxBluetoothGatt(const LinuxBluetoothGatt &) = delete; - LinuxBluetoothGatt& operator=(const LinuxBluetoothGatt&) = delete; + LinuxBluetoothGatt &operator=(const LinuxBluetoothGatt &) = delete; bool isConnected() const override; @@ -105,7 +106,9 @@ public: void writeValue(const BluetoothGattCharacteristicPtr &c, const ByteBuffer &bytes) override; - ByteBuffer readValue(const BluetoothGattCharacteristicPtr &c, ByteBuffer& response) override; + void write(const BluetoothGattDescriptorPtr &c) override; + + ByteBuffer readValue(const BluetoothGattCharacteristicPtr &c, ByteBuffer &response) override; void setCharacteristicNotification(const BluetoothGattDescriptorPtr &c, bool enable) override; @@ -118,9 +121,13 @@ private: vector<AttributeData> discoverCharacteristics(uint16_t startHandle, uint16_t endHandle); + void discoverDescriptors(shared_ptr<DefaultBluetoothGattCharacteristic> &c); + + void writeHandle(uint16_t handle, const ByteBuffer &bytes); + void writeL2cap(ByteBuffer &buffer); - void writeAndRead(const ByteBuffer &buffer, ByteBuffer& response); + void writeAndRead(const ByteBuffer &buffer, ByteBuffer &response); AttVariant processAvailableMessages(ByteBuffer &buffer); @@ -130,7 +137,7 @@ private: template<typename T, typename clock = std::chrono::system_clock> T exchangeAndWaitFor(ByteBuffer &buffer, std::chrono::time_point<clock> time, bool fail_on_error); - void logError(const ErrorRes&); + void logError(const ErrorRes &); uint16_t mtu = 256; @@ -160,7 +167,7 @@ Mac parseMac(bdaddr_t &a) { // ----------------------------------------------------------------------- LinuxBluetoothDevice::LinuxBluetoothDevice(LinuxBluetoothAdapter &adapter, Mac &mac) : - DefaultBluetoothDevice(adapter, mac), gatt(nullptr) { + DefaultBluetoothDevice(adapter, mac), gatt(nullptr) { } LinuxBluetoothDevice::~LinuxBluetoothDevice() { @@ -183,7 +190,7 @@ shared_ptr<BluetoothGatt> LinuxBluetoothDevice::connectGatt() { // ----------------------------------------------------------------------- LinuxBluetoothGatt::LinuxBluetoothGatt(LinuxBluetoothDevice &device) : - DefaultBluetoothGatt(device), l2cap() { + DefaultBluetoothGatt(device), l2cap() { connect(); } @@ -229,12 +236,12 @@ void LinuxBluetoothGatt::connect() { addr.l2_cid = htobs(ATT_CID); addr.l2_bdaddr_type = BDADDR_LE_RANDOM; device.getMac().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]); + 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); @@ -261,8 +268,10 @@ Uuid readUuid(BluetoothDevice *device, ByteBuffer &bytes) { return Uuid(bs); } else if (bytesLeft == 16) { uint8_t bs[16] = { - bytes.get8(15), bytes.get8(14), bytes.get8(13), bytes.get8(12), bytes.get8(11), bytes.get8(10), bytes.get8(9), bytes.get8(8), - bytes.get8(7), bytes.get8(6), bytes.get8(5), bytes.get8(4), bytes.get8(3), bytes.get8(2), bytes.get8(1), bytes.get8(0), + bytes.get8(15), bytes.get8(14), bytes.get8(13), bytes.get8(12), + bytes.get8(11), bytes.get8(10), bytes.get8(9), bytes.get8(8), + bytes.get8(7), bytes.get8(6), bytes.get8(5), bytes.get8(4), + bytes.get8(3), bytes.get8(2), bytes.get8(1), bytes.get8(0), }; bytes.skip(16); @@ -275,17 +284,39 @@ Uuid readUuid(BluetoothDevice *device, ByteBuffer &bytes) { void LinuxBluetoothGatt::writeValue(const BluetoothGattCharacteristicPtr &c, const ByteBuffer &bytes) { LOG_DEBUG("Writing to characteristic " << c->getUuid() << ": " << bytes.toString()); + writeHandle(c->getValueHandle(), bytes); +} + +void LinuxBluetoothGatt::write(const BluetoothGattDescriptorPtr &d) { + auto bytes = d->getValue(); + + LOG_DEBUG("Writing to descriptor " << d->getUuid() << ": " << bytes.toString()); + + writeHandle(d->getHandle(), bytes); +} + +void LinuxBluetoothGatt::writeHandle(uint16_t handle, const ByteBuffer &bytes) { uint8_t b[mtu]; ByteBuffer buffer{b, mtu}; - AttPdu::makeWrite(buffer, c->getValueHandle(), bytes); + AttPdu::makeWrite(buffer, handle, bytes); writeAndRead(buffer, buffer); + auto cursor = buffer.getPosition(); + buffer.setPosition(0); + AttPdu::parseWrite(buffer); + + auto extra_bytes = cursor - buffer.getPosition(); + LOG_DEBUG("WRITE response has " + to_string(extra_bytes) + " extra bytes"); + + if (extra_bytes) { + throw BluetoothException(&device, "Got extra bytes from ::read(): " + to_string(extra_bytes)); + } } -ByteBuffer LinuxBluetoothGatt::readValue(const BluetoothGattCharacteristicPtr &c, ByteBuffer& response) { +ByteBuffer LinuxBluetoothGatt::readValue(const BluetoothGattCharacteristicPtr &c, ByteBuffer &response) { uint8_t b[mtu]; ByteBuffer buffer{b, mtu}; @@ -293,12 +324,12 @@ ByteBuffer LinuxBluetoothGatt::readValue(const BluetoothGattCharacteristicPtr &c writeAndRead(buffer, response); - auto cursor = response.getCursor(); - response.setCursor(0); + auto cursor = response.getPosition(); + response.setPosition(0); AttPdu::parseRead(response); - auto view = response.view(cursor - response.getCursor()); + auto view = response.viewForward(cursor - response.getPosition()); LOG_DEBUG("READ response has " + to_string(view.getSize()) + " bytes"); LOG_DEBUG("Value of characteristic " << c->getUuid() << "=" << view.toString()); @@ -306,7 +337,11 @@ ByteBuffer LinuxBluetoothGatt::readValue(const BluetoothGattCharacteristicPtr &c return view; } -void LinuxBluetoothGatt::setCharacteristicNotification(const BluetoothGattDescriptorPtr &c, bool enable) { +void LinuxBluetoothGatt::setCharacteristicNotification(const BluetoothGattDescriptorPtr &d, bool enable) { + uint8_t b[mtu]; + ByteBuffer buffer{b, mtu}; + +// AttPdu::makeWrite(buffer, d->getValueHandle()); } void LinuxBluetoothGatt::discoverServices() { @@ -330,16 +365,14 @@ void LinuxBluetoothGatt::discoverServices() { endGroupHandle = data.value.read16le(); LOG_DEBUG("service handle: 0x" << hex << setw(4) << setfill('0') << data.handle << - ", endGroupHandle: 0x" << hex << setw(4) << setfill('0') << endGroupHandle << - ", value: " << data.value.toString()); + ", endGroupHandle: 0x" << hex << setw(4) << setfill('0') << endGroupHandle << + ", value: " << data.value.toString()); auto u = readUuid(&device, data.value); addService(make_shared<LinuxBluetoothGattService>(device, u, data.handle, endGroupHandle)); } -// auto last = values.back(); - startHandle = endGroupHandle; } while (startHandle != 0xffff); @@ -349,7 +382,7 @@ void LinuxBluetoothGatt::discoverServices() { // } auto it = services.begin(), - end = services.end(); + end = services.end(); if (it == end) { return; @@ -381,49 +414,56 @@ void LinuxBluetoothGatt::discoverServices() { auto uuid = readUuid(&device, c.value); LOG_DEBUG("characteristic: handle: " << setw(2) << setfill('0') << hex << (int) c.handle << - ", properties: " << setw(2) << setfill('0') << hex << (int) properties << - ", valueHandle: 0x" << setw(4) << setfill('0') << hex << (int) valueHandle << - ", uuid: " << uuid); + ", properties: " << setw(2) << setfill('0') << hex << (int) properties + << + ", valueHandle: 0x" << setw(4) << setfill('0') << hex + << (int) valueHandle << + ", uuid: " << uuid); + + auto characteristic = make_shared<DefaultBluetoothGattCharacteristic>( + s, c.handle, uuid, properties, valueHandle); - s->addCharacteristic(std::move(make_shared<DefaultBluetoothGattCharacteristic>(s, c.handle, uuid, properties, valueHandle))); + discoverDescriptors(characteristic); + + s->addCharacteristic(std::move(characteristic)); } startHandle = lastHandle + (uint8_t) 2; } while (startHandle != 0xffff); } -void LinuxBluetoothGatt::writeAndRead(const ByteBuffer &buffer, ByteBuffer& response) { +void LinuxBluetoothGatt::writeAndRead(const ByteBuffer &buffer, ByteBuffer &response) { // LOG_DEBUG("pdu size=" << out.getCursor()); - auto to_be_written = buffer.getCursor(); + auto to_be_written = buffer.getPosition(); - ssize_t written = write(l2cap, buffer.cbegin(), to_be_written); + ssize_t written = ::write(l2cap, buffer.cbegin(), to_be_written); if (to_be_written != written) { throw BluetoothException(&device, "Expected to write " + to_string(to_be_written) + " but wrote only " + - to_string(written)); + to_string(written)); } // LOG_DEBUG("written=" << written); - ssize_t r = read(l2cap, response.begin(), response.getSize()); + ssize_t r = read(l2cap, response.underlying(), response.getSize()); if (r == -1) { throw BluetoothException(&device, "read(): " + errnoAsString()); } - LOG_DEBUG("read: " << r << " bytes: " << response.toString()); - response.setCursor(static_cast<size_t>(r)); + response.setPosition(static_cast<size_t>(r)); + LOG_DEBUG("read: " << r << " bytes: " << response.viewBeginningToCursor().toString()); } void LinuxBluetoothGatt::writeL2cap(ByteBuffer &buffer) { - auto to_be_written = buffer.getCursor(); - ssize_t written = write(l2cap, buffer.cbegin(), to_be_written); + auto to_be_written = buffer.getPosition(); + ssize_t written = ::write(l2cap, buffer.cbegin(), to_be_written); if (to_be_written != written) { throw BluetoothException(&device, "Expected to write " + to_string(to_be_written) + " but wrote only " + to_string(written)); } - buffer.reset(); + buffer.setPosition(0); } AttVariant LinuxBluetoothGatt::processAvailableMessages(ByteBuffer &buffer) { @@ -433,13 +473,13 @@ AttVariant LinuxBluetoothGatt::processAvailableMessages(ByteBuffer &buffer) { // LOG_DEBUG("ret=" << to_string(ret) << "/" << errnoAsString(ret) << // ", bytes available: " << to_string(bytes_available)); - while(!ret && bytes_available) { - ssize_t r = read(l2cap, buffer.begin(), buffer.getBytesLeft()); + while (!ret && bytes_available) { + ssize_t r = read(l2cap, buffer.underlying(), buffer.getBytesLeft()); if (r == -1) { throw BluetoothException(&device, "read(): " + errnoAsString()); } - auto packet_buffer = buffer.view(size_t(r)); + auto packet_buffer = buffer.viewForward(size_t(r)); auto type = static_cast<AttPduType>(packet_buffer.get8(0)); LOG_DEBUG("Got ATT message " << to_string(type) << ", size: " << to_string(r)); @@ -474,7 +514,7 @@ static BluetoothException makeUnexpectedTypeException(const AttVariant &variant) template<typename T> static void assertIsVariant(const AttVariant &variant) { - if(holds_alternative<T>(variant)) { + if (holds_alternative<T>(variant)) { return; } @@ -561,13 +601,13 @@ vector<AttributeData> LinuxBluetoothGatt::discoverCharacteristics(uint16_t start auto res = exchangeAndWaitFor(buffer, std::chrono::system_clock::now() + 10s); - if(holds_alternative<ReadByTypeRes>(res)) { + if (holds_alternative<ReadByTypeRes>(res)) { auto values = get<ReadByTypeRes>(res).attributes; LOG_DEBUG("READ_BY_TYPE response has " + to_string(values.size()) + " values"); return values; } - if(holds_alternative<ErrorRes>(res)) { + if (holds_alternative<ErrorRes>(res)) { ErrorRes err = get<ErrorRes>(res); if (err.errorCode == ErrorCode::ATTRIBUTE_NOT_FOUND) { @@ -580,12 +620,39 @@ vector<AttributeData> LinuxBluetoothGatt::discoverCharacteristics(uint16_t start throw makeUnexpectedTypeException(res); } +void LinuxBluetoothGatt::discoverDescriptors(shared_ptr<DefaultBluetoothGattCharacteristic> &c) { + + auto p = c->getProperties(); + + if (!p.indicate() && !p.notify()) { + return; + } + + uint8_t bytes[mtu]; + ByteBuffer buffer{bytes, mtu}; + + uint16_t handle = c->getValueHandle() + uint16_t(1); + AttPdu::makeFindInformationReq(buffer, handle, handle); + + auto res = exchangeAndWaitFor(buffer, std::chrono::system_clock::now() + 10s); + + if (holds_alternative<FindInformationRes>(res)) { + auto values = get<FindInformationRes>(res).information; + LOG_DEBUG("FIND_INFORMATION response has " + to_string(values.size()) + " values"); + + for (auto &value : values) { + c->addDescriptor(std::move(make_shared<DefaultBluetoothGattDescriptor>(c, value.handle, value.uuid))); + LOG_DEBUG("UUID=" + value.uuid.str()); + } + } +} + // ----------------------------------------------------------------------- // Adapter // ----------------------------------------------------------------------- LinuxBluetoothAdapter::LinuxBluetoothAdapter(int hciDeviceId, Mac &mac) : DefaultBluetoothAdapter(mac), - scanning(false), hciFilter() { + scanning(false), hciFilter() { LOG_DEBUG("hciDeviceId=" << hciDeviceId); this->hciDeviceId = hciDeviceId; |