From 27e6cb7b025ef39dc8329502cec753063c00103d Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Thu, 6 Feb 2020 17:27:41 -0800 Subject: [PATCH 1/3] Add support for multiple values in manufacturer data --- adafruit_ble/advertising/standard.py | 44 ++++++++++++++++++++++++---- 1 file changed, 39 insertions(+), 5 deletions(-) diff --git a/adafruit_ble/advertising/standard.py b/adafruit_ble/advertising/standard.py index 39225fc..090bc07 100644 --- a/adafruit_ble/advertising/standard.py +++ b/adafruit_ble/advertising/standard.py @@ -211,18 +211,52 @@ def __str__(self): return "".format(self.company_id, hex_data) class ManufacturerDataField: - """A single piece of data within the manufacturer specific data.""" - def __init__(self, key, key_format): + """A single piece of data within the manufacturer specific data. The format can be repeated.""" + def __init__(self, key, value_format, field_names=None): self._key = key - self._format = key_format + self._format = value_format + self.element_count = len(value_format.strip("> 1 and (not field_names or len(field_names) != self.element_count): + raise ValueError("Provide field_names when multiple values are in the format") + self._entry_length = struct.calcsize(value_format) + self.field_names = field_names def __get__(self, obj, cls): - return struct.unpack_from(self._format, obj.manufacturer_data.data[self._key])[0] + if self._key not in obj.manufacturer_data.data: + return None + packed = obj.manufacturer_data.data[self._key] + if self._entry_length == len(packed): + unpacked = struct.unpack_from(self._format, packed) + if self.element_count == 1: + unpacked = unpacked[0] + return unpacked + if len(packed) % self._entry_length != 0: + raise RuntimeError("Invalid data length") + entry_count = len(packed) // self._entry_length + unpacked = [None] * entry_count + for i in range(entry_count): + offset = i * self._entry_length + unpacked[i] = struct.unpack_from(self._format, packed, offset=offset) + if self.element_count == 1: + unpacked[i] = unpacked[i][0] + return tuple(unpacked) def __set__(self, obj, value): if not obj.mutable: raise AttributeError() - obj.manufacturer_data.data[self._key] = struct.pack(self._format, value) + if isinstance(value, tuple) and (self.element_count == 1 or isinstance(value[0], tuple)): + packed = bytearray(self._entry_length * len(value)) + for i, entry in enumerate(value): + offset = i * self._entry_length + if self.element_count > 1: + struct.pack_into(self._format, packed, offset, *entry) + else: + struct.pack_into(self._format, packed, offset, entry) + obj.manufacturer_data.data[self._key] = bytes(packed) + elif self.element_count == 1: + obj.manufacturer_data.data[self._key] = struct.pack(self._format, value) + else: + obj.manufacturer_data.data[self._key] = struct.pack(self._format, *value) # TODO: Handle service data. From 2505ce25ab56c4003527984edf13826fd3674f5e Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Thu, 6 Feb 2020 17:28:24 -0800 Subject: [PATCH 2/3] Do not add a scan response when using extended advertising. --- adafruit_ble/__init__.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/adafruit_ble/__init__.py b/adafruit_ble/__init__.py index 2b7d761..b6c4b8d 100755 --- a/adafruit_ble/__init__.py +++ b/adafruit_ble/__init__.py @@ -164,12 +164,16 @@ def start_advertising(self, advertisement, scan_response=None, interval=0.1): `BLERadio.name` and `BLERadio.tx_power`. :param float interval: advertising interval, in seconds """ - if not scan_response: + advertisement_bytes = bytes(advertisement) + scan_response_bytes = b"" + if not scan_response and len(advertisement_bytes) <= 31: scan_response = Advertisement() scan_response.complete_name = self.name scan_response.tx_power = self.tx_power - self._adapter.start_advertising(bytes(advertisement), - scan_response=bytes(scan_response), + if scan_response: + scan_response_bytes = bytes(scan_response) + self._adapter.start_advertising(advertisement_bytes, + scan_response=scan_response_bytes, connectable=advertisement.connectable, interval=interval) From 5b00d8f83fe43738fe97878f9445a1604393c783 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Wed, 12 Feb 2020 12:09:16 -0800 Subject: [PATCH 3/3] Fix element count when numbers are in the format. --- adafruit_ble/advertising/standard.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/adafruit_ble/advertising/standard.py b/adafruit_ble/advertising/standard.py index 090bc07..01b1e5b 100644 --- a/adafruit_ble/advertising/standard.py +++ b/adafruit_ble/advertising/standard.py @@ -215,7 +215,9 @@ class ManufacturerDataField: def __init__(self, key, value_format, field_names=None): self._key = key self._format = value_format - self.element_count = len(value_format.strip("> 1 and (not field_names or len(field_names) != self.element_count): raise ValueError("Provide field_names when multiple values are in the format") self._entry_length = struct.calcsize(value_format)