Skip to content

Add support for service data #67

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Feb 14, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 66 additions & 5 deletions adafruit_ble/advertising/standard.py
Original file line number Diff line number Diff line change
Expand Up @@ -260,10 +260,71 @@ def __set__(self, obj, value):
else:
obj.manufacturer_data.data[self._key] = struct.pack(self._format, *value)

# TODO: Handle service data.
class ServiceData(AdvertisingDataField):
"""Encapsulates service data. It is read as a memoryview which can be manipulated or set as a
bytearray to change the size."""
def __init__(self, service):
if isinstance(service.uuid, StandardUUID):
self._adt = 0x16
elif isinstance(service.uuid, VendorUUID):
self._adt = 0x21
self._prefix = bytes(service.uuid)

def __get__(self, obj, cls):
# If not present at all and mutable, then we init it, otherwise None.
if self._adt not in obj.data_dict:
if obj.mutable:
obj.data_dict[self._adt] = bytearray(self._prefix)
else:
return None

all_service_data = obj.data_dict[self._adt]
# Handle a list of existing data. This doesn't support multiple service data ADTs for the
# same service.
if isinstance(all_service_data, list):
for i, service_data in enumerate(all_service_data):
if service_data.startswith(self._prefix):
if not isinstance(service_data, bytearray):
service_data = bytearray(service_data)
all_service_data[i] = service_data
return memoryview(service_data)[len(self._prefix):]
if obj.mutable:
service_data = bytearray(self._prefix)
all_service_data.append(service_data)
return memoryview(service_data)[len(self._prefix):]
# Existing data is a single set of bytes.
elif isinstance(all_service_data, (bytes, bytearray)):
service_data = all_service_data
if not bytes(service_data).startswith(self._prefix):
if not obj.mutable:
return None
# Upgrade the value to a list.
service_data = bytearray(self._prefix)
obj.data_dict[self._adt] = [service_data, service_data]
if not isinstance(service_data, bytearray):
service_data = bytearray(service_data)
obj.data_dict[self._adt] = service_data
return memoryview(service_data)[len(self._prefix):]

return None

# SERVICE_DATA_128BIT_UUID = 0x21
# """Service data with 128 bit UUID."""

# SERVICE_DATA_16_BIT_UUID = 0x16
# """Service data with 16 bit UUID."""
def __set__(self, obj, value):
if not obj.mutable:
raise RuntimeError("Advertisement immutable")
if not isinstance(value, bytearray):
raise TypeError("Value must be bytearray")
full_value = bytearray(self._prefix) + value
if self._adt not in obj.data_dict:
obj.data_dict[self._adt] = full_value
return

all_service_data = obj.data_dict[self._adt]
if isinstance(all_service_data, list):
for i, service_data in enumerate(all_service_data):
if service_data.startswith(self._prefix):
all_service_data[i] = full_value
return
all_service_data.append(full_value)
elif isinstance(all_service_data, (bytes, bytearray)):
obj.data_dict[self._adt] = full_value
7 changes: 7 additions & 0 deletions adafruit_ble/uuid/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,13 @@ def __eq__(self, other):
def __str__(self):
return str(self.bleio_uuid)

def __bytes__(self):
if self.bleio_uuid.size == 128:
return self.bleio_uuid.uuid128
b = bytearray(2)
self.bleio_uuid.pack_into(b)
return bytes(b)

def pack_into(self, buffer, offset=0):
"""Packs the UUID into the buffer at the given offset."""
self.bleio_uuid.pack_into(buffer, offset=offset)
Expand Down