Skip to content

Commit 27e6cb7

Browse files
committed
Add support for multiple values in manufacturer data
1 parent 7adbb88 commit 27e6cb7

File tree

1 file changed

+39
-5
lines changed

1 file changed

+39
-5
lines changed

adafruit_ble/advertising/standard.py

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -211,18 +211,52 @@ def __str__(self):
211211
return "<ManufacturerData company_id={:04x} data={} >".format(self.company_id, hex_data)
212212

213213
class ManufacturerDataField:
214-
"""A single piece of data within the manufacturer specific data."""
215-
def __init__(self, key, key_format):
214+
"""A single piece of data within the manufacturer specific data. The format can be repeated."""
215+
def __init__(self, key, value_format, field_names=None):
216216
self._key = key
217-
self._format = key_format
217+
self._format = value_format
218+
self.element_count = len(value_format.strip("><!=@").replace("x", ""))
219+
if self.element_count > 1 and (not field_names or len(field_names) != self.element_count):
220+
raise ValueError("Provide field_names when multiple values are in the format")
221+
self._entry_length = struct.calcsize(value_format)
222+
self.field_names = field_names
218223

219224
def __get__(self, obj, cls):
220-
return struct.unpack_from(self._format, obj.manufacturer_data.data[self._key])[0]
225+
if self._key not in obj.manufacturer_data.data:
226+
return None
227+
packed = obj.manufacturer_data.data[self._key]
228+
if self._entry_length == len(packed):
229+
unpacked = struct.unpack_from(self._format, packed)
230+
if self.element_count == 1:
231+
unpacked = unpacked[0]
232+
return unpacked
233+
if len(packed) % self._entry_length != 0:
234+
raise RuntimeError("Invalid data length")
235+
entry_count = len(packed) // self._entry_length
236+
unpacked = [None] * entry_count
237+
for i in range(entry_count):
238+
offset = i * self._entry_length
239+
unpacked[i] = struct.unpack_from(self._format, packed, offset=offset)
240+
if self.element_count == 1:
241+
unpacked[i] = unpacked[i][0]
242+
return tuple(unpacked)
221243

222244
def __set__(self, obj, value):
223245
if not obj.mutable:
224246
raise AttributeError()
225-
obj.manufacturer_data.data[self._key] = struct.pack(self._format, value)
247+
if isinstance(value, tuple) and (self.element_count == 1 or isinstance(value[0], tuple)):
248+
packed = bytearray(self._entry_length * len(value))
249+
for i, entry in enumerate(value):
250+
offset = i * self._entry_length
251+
if self.element_count > 1:
252+
struct.pack_into(self._format, packed, offset, *entry)
253+
else:
254+
struct.pack_into(self._format, packed, offset, entry)
255+
obj.manufacturer_data.data[self._key] = bytes(packed)
256+
elif self.element_count == 1:
257+
obj.manufacturer_data.data[self._key] = struct.pack(self._format, value)
258+
else:
259+
obj.manufacturer_data.data[self._key] = struct.pack(self._format, *value)
226260

227261
# TODO: Handle service data.
228262

0 commit comments

Comments
 (0)