aboutsummaryrefslogtreecommitdiff
path: root/ble/LinuxBluetooth.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'ble/LinuxBluetooth.cpp')
-rw-r--r--ble/LinuxBluetooth.cpp169
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;