@@ -211,18 +211,54 @@ def __str__(self):
211211 return "<ManufacturerData company_id={:04x} data={} >" .format (self .company_id , hex_data )
212212
213213class 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+ # TODO: Support format strings that use numbers to repeat a given type. For now, we strip
219+ # numbers because Radio specifies string length with it.
220+ self .element_count = len (value_format .strip ("><!=@0123456789" ).replace ("x" , "" ))
221+ if self .element_count > 1 and (not field_names or len (field_names ) != self .element_count ):
222+ raise ValueError ("Provide field_names when multiple values are in the format" )
223+ self ._entry_length = struct .calcsize (value_format )
224+ self .field_names = field_names
218225
219226 def __get__ (self , obj , cls ):
220- return struct .unpack_from (self ._format , obj .manufacturer_data .data [self ._key ])[0 ]
227+ if self ._key not in obj .manufacturer_data .data :
228+ return None
229+ packed = obj .manufacturer_data .data [self ._key ]
230+ if self ._entry_length == len (packed ):
231+ unpacked = struct .unpack_from (self ._format , packed )
232+ if self .element_count == 1 :
233+ unpacked = unpacked [0 ]
234+ return unpacked
235+ if len (packed ) % self ._entry_length != 0 :
236+ raise RuntimeError ("Invalid data length" )
237+ entry_count = len (packed ) // self ._entry_length
238+ unpacked = [None ] * entry_count
239+ for i in range (entry_count ):
240+ offset = i * self ._entry_length
241+ unpacked [i ] = struct .unpack_from (self ._format , packed , offset = offset )
242+ if self .element_count == 1 :
243+ unpacked [i ] = unpacked [i ][0 ]
244+ return tuple (unpacked )
221245
222246 def __set__ (self , obj , value ):
223247 if not obj .mutable :
224248 raise AttributeError ()
225- obj .manufacturer_data .data [self ._key ] = struct .pack (self ._format , value )
249+ if isinstance (value , tuple ) and (self .element_count == 1 or isinstance (value [0 ], tuple )):
250+ packed = bytearray (self ._entry_length * len (value ))
251+ for i , entry in enumerate (value ):
252+ offset = i * self ._entry_length
253+ if self .element_count > 1 :
254+ struct .pack_into (self ._format , packed , offset , * entry )
255+ else :
256+ struct .pack_into (self ._format , packed , offset , entry )
257+ obj .manufacturer_data .data [self ._key ] = bytes (packed )
258+ elif self .element_count == 1 :
259+ obj .manufacturer_data .data [self ._key ] = struct .pack (self ._format , value )
260+ else :
261+ obj .manufacturer_data .data [self ._key ] = struct .pack (self ._format , * value )
226262
227263# TODO: Handle service data.
228264
0 commit comments