Closed sfyang closed 6 years ago
We really appreciate such helpful issue report. If I understood correctly, this involves 2 major issues in the LBLE library:
LBLEClient fails to enumerate many attributes, e.g. 000000190000100080000026bb765291
in your case.
The current interface assumes that characteristic UUIDs and characteristic instances are 1-to-1 mapped. This assumption is convenient but wrong. Therefore the interface and implementation cannot properly handle the case that the multiple characteristics using the same UUID within a device.
For the 1st issue, we need to look further into that bug.
For the 2nd issue, you have described the problem and solution clearly. The LBLEClient has to be redesigned. It should allow enumerations of characteristics from either services or UUIDs. The result should be a collection of characteristic objects, which are in fact attribute handles in the underlying implementation.
For example, instead of calling client.readCharacteristicChar(0x2A06)
, one would call client.readCharacteristicChar(c)
where c
is an element in a collection returned from client.discoverCharacteristics(some_service)
.
There are several issues concerning the LBLEClient class declared in LBLECentral.h and implemented in LBLECentral.cpp, and this is one of them.
With current implementation of the
LBLEClient
class, a flat characteristic listm_characteristics
implemented withstd::map
container using the UUID of the characteristic as the key and the value handle as the value is used to store the characteristic found by the protectedLBLEClient::discoverCharacteristicsOfService()
method. This way of the implementation could have the following problems:std::map
container is a sorted associative container that contains key-value pairs with unique keys, this means that if the peripheral contains services having identical characteristics, a characteristic could never be recorded to the list if other characteristic with the same UUID from other services had been discovered and inserted to the list before it, since thestd::map::insert()
in this case returns the iterator for the first occurrence of the element with the same key preventing the insertion of the new element.LBLEClient
class to output a service-characteristic list showing which characteristic is associated to which service.To demonstrate this issue, consider the following slightly modified version of the 'ConnectPeripheral.ino' example code from the LBLE library, which is extended to add methods and code segment for dumping the content of the characteristic list:
Now run the code on the LinkIt 7697 HDK and connect to a peripheral having several custom services which have some common characteristic with UUID 'E604E95D-A759-4817-87D3-AA005083A0D1' (yes, this is a nRF52-dk running Apple HomeKit server, and the peripheral list of the scanning result is shortened.):
Here is a Node.js code
main.js
using the noble library to perform similar tasks as the ConnectPeripheral.ino does:And the output of the above-mentioned code connecting to the same device:
Other than quite some obviously missing characteristics which itself is another serious issue to the LBLE library, the characteristic list from the
ABLEClient
class, a extended version of theLBLEClient
class, does not show the duplicated characteristics with UUID 'E604E95D-A759-4817-87D3-AA005083A0D1'. This also means that those duplicated characteristics missing from the list can never be written using theLBLEClient::writeCharacteristic()
method under current implementation if they are writable characteristics.By the way, since the implementation of the
LBLEClient::readCharacteristic()
does not even use theLBLEClient::m_characteristics
list during its operation, it, in theory, does not be affected directly by this issue. However, due to the way the read request is constructed by specifying the handle range to be the full range from 0x0001 to 0xFFFF, if theLBLEClient::readCharacteristic()
method is used to read characteristics affected by this issue (that is, characteristics with identical UUID but belonging to different services on the same peripheral), according to "Read Using Characteristic UUID" from Bluetooth Core Specification v4.2 Vol.3 Part G, the GATT server returns a list of Attribute Handle and Attribute Value pairs, which is not really what theLBLEClient::readCharacteristic()
is designed for, and this could break theLBLEClient::readCharacteristic()
wrapper methods likeLBLEClient::readCharacteristicInt
, etc.