@@ -211,18 +211,52 @@ def __str__(self):
211
211
return "<ManufacturerData company_id={:04x} data={} >" .format (self .company_id , hex_data )
212
212
213
213
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 ):
216
216
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
218
223
219
224
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 )
221
243
222
244
def __set__ (self , obj , value ):
223
245
if not obj .mutable :
224
246
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 )
226
260
227
261
# TODO: Handle service data.
228
262
0 commit comments