Skip to content

Commit

Permalink
BLESession.setNotifications: Lookup CCCD to start or stop notifications
Browse files Browse the repository at this point in the history
Per Bluetooth Core Specification Vol.3, Part G, Section 3.3.1.1, if
Notify property is set for a Characteristic, the Client Characteristic
Configuration Descriptor, or CCCD, shall exist. As noted in section
3.3.3.3 of the specification, notification of the Characteristic is
enabled or disabled by setting bit 0 of the CCCD.

This CCCD exists within the characteristic definition following the
Characteristic Value declaration, and section 3.3.3 of the specification
warns that the order of characteristic declaration shall not be assumed.
However, current pyscrlink code assumes that the CCCD comes just after
the Characteristic Value and CCCD handle is obtained just adding 1 to
the handle of the Characteristic Value. This works many of the BLE
devices but does not work all of them.

To get correct CCCD handle, look up descriptors of the Characteristic to
find out the CCCD.

Signed-off-by: Shin'ichiro Kawasaki <kawasaki@juno.dti.ne.jp>
  • Loading branch information
kawasaki committed Jan 3, 2022
1 parent 48e460b commit 2d48932
Showing 1 changed file with 11 additions and 1 deletion.
12 changes: 11 additions & 1 deletion pyscrlink/scratch_link.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@
HOSTNAME="device-manager.scratch.mit.edu"
scan_seconds=10.0

CCCD_UUID = 0x2902

class Session():
"""Base class for BTSession and BLESession"""
def __init__(self, websocket, loop):
Expand Down Expand Up @@ -705,11 +707,19 @@ def setNotifications(self, service_id, chara_id, value):
service = self._get_service(service_id)
c = self._get_characteristic(chara_id)
handle = c.getHandle()
# get CCCD or Client Characterstic Configuration Descriptor
cccd = None
for d in c.getDescriptors():
if d.uuid == UUID(CCCD_UUID):
cccd = d
if not cccd:
logger.error("Characteristic {char_id} does not have CCCD")
return
# prepare notification handler
self.delegate.add_handle(service_id, chara_id, handle)
# request notification to the BLE device
with self.lock:
self.perip.writeCharacteristic(handle + 1, value, True)
self.perip.writeCharacteristic(cccd.handle, value, True)

def startNotifications(self, service_id, chara_id):
logger.debug(f"start notification for {chara_id}")
Expand Down

0 comments on commit 2d48932

Please sign in to comment.