Skip to content

Commit 4ab856d

Browse files
authored
Merge pull request #67 from tannewt/service_data
Add support for service data
2 parents fb91fcb + 9b5b533 commit 4ab856d

File tree

2 files changed

+73
-5
lines changed

2 files changed

+73
-5
lines changed

adafruit_ble/advertising/standard.py

+66-5
Original file line numberDiff line numberDiff line change
@@ -260,10 +260,71 @@ def __set__(self, obj, value):
260260
else:
261261
obj.manufacturer_data.data[self._key] = struct.pack(self._format, *value)
262262

263-
# TODO: Handle service data.
263+
class ServiceData(AdvertisingDataField):
264+
"""Encapsulates service data. It is read as a memoryview which can be manipulated or set as a
265+
bytearray to change the size."""
266+
def __init__(self, service):
267+
if isinstance(service.uuid, StandardUUID):
268+
self._adt = 0x16
269+
elif isinstance(service.uuid, VendorUUID):
270+
self._adt = 0x21
271+
self._prefix = bytes(service.uuid)
272+
273+
def __get__(self, obj, cls):
274+
# If not present at all and mutable, then we init it, otherwise None.
275+
if self._adt not in obj.data_dict:
276+
if obj.mutable:
277+
obj.data_dict[self._adt] = bytearray(self._prefix)
278+
else:
279+
return None
280+
281+
all_service_data = obj.data_dict[self._adt]
282+
# Handle a list of existing data. This doesn't support multiple service data ADTs for the
283+
# same service.
284+
if isinstance(all_service_data, list):
285+
for i, service_data in enumerate(all_service_data):
286+
if service_data.startswith(self._prefix):
287+
if not isinstance(service_data, bytearray):
288+
service_data = bytearray(service_data)
289+
all_service_data[i] = service_data
290+
return memoryview(service_data)[len(self._prefix):]
291+
if obj.mutable:
292+
service_data = bytearray(self._prefix)
293+
all_service_data.append(service_data)
294+
return memoryview(service_data)[len(self._prefix):]
295+
# Existing data is a single set of bytes.
296+
elif isinstance(all_service_data, (bytes, bytearray)):
297+
service_data = all_service_data
298+
if not bytes(service_data).startswith(self._prefix):
299+
if not obj.mutable:
300+
return None
301+
# Upgrade the value to a list.
302+
service_data = bytearray(self._prefix)
303+
obj.data_dict[self._adt] = [service_data, service_data]
304+
if not isinstance(service_data, bytearray):
305+
service_data = bytearray(service_data)
306+
obj.data_dict[self._adt] = service_data
307+
return memoryview(service_data)[len(self._prefix):]
308+
309+
return None
264310

265-
# SERVICE_DATA_128BIT_UUID = 0x21
266-
# """Service data with 128 bit UUID."""
267311

268-
# SERVICE_DATA_16_BIT_UUID = 0x16
269-
# """Service data with 16 bit UUID."""
312+
def __set__(self, obj, value):
313+
if not obj.mutable:
314+
raise RuntimeError("Advertisement immutable")
315+
if not isinstance(value, bytearray):
316+
raise TypeError("Value must be bytearray")
317+
full_value = bytearray(self._prefix) + value
318+
if self._adt not in obj.data_dict:
319+
obj.data_dict[self._adt] = full_value
320+
return
321+
322+
all_service_data = obj.data_dict[self._adt]
323+
if isinstance(all_service_data, list):
324+
for i, service_data in enumerate(all_service_data):
325+
if service_data.startswith(self._prefix):
326+
all_service_data[i] = full_value
327+
return
328+
all_service_data.append(full_value)
329+
elif isinstance(all_service_data, (bytes, bytearray)):
330+
obj.data_dict[self._adt] = full_value

adafruit_ble/uuid/__init__.py

+7
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,13 @@ def __eq__(self, other):
4949
def __str__(self):
5050
return str(self.bleio_uuid)
5151

52+
def __bytes__(self):
53+
if self.bleio_uuid.size == 128:
54+
return self.bleio_uuid.uuid128
55+
b = bytearray(2)
56+
self.bleio_uuid.pack_into(b)
57+
return bytes(b)
58+
5259
def pack_into(self, buffer, offset=0):
5360
"""Packs the UUID into the buffer at the given offset."""
5461
self.bleio_uuid.pack_into(buffer, offset=offset)

0 commit comments

Comments
 (0)