@@ -260,10 +260,71 @@ def __set__(self, obj, value):
260260 else :
261261 obj .manufacturer_data .data [self ._key ] = struct .pack (self ._format , * value )
262262
263- # TODO: Handle service data.
263+ class ServiceData (AdvertisingDataField ):
264+ """Encapsulates service data. It is read as a memoryview which can be manipulated or set as a
265+ bytearray to change the size."""
266+ def __init__ (self , service ):
267+ if isinstance (service .uuid , StandardUUID ):
268+ self ._adt = 0x16
269+ elif isinstance (service .uuid , VendorUUID ):
270+ self ._adt = 0x21
271+ self ._prefix = bytes (service .uuid )
272+
273+ def __get__ (self , obj , cls ):
274+ # If not present at all and mutable, then we init it, otherwise None.
275+ if self ._adt not in obj .data_dict :
276+ if obj .mutable :
277+ obj .data_dict [self ._adt ] = bytearray (self ._prefix )
278+ else :
279+ return None
280+
281+ all_service_data = obj .data_dict [self ._adt ]
282+ # Handle a list of existing data. This doesn't support multiple service data ADTs for the
283+ # same service.
284+ if isinstance (all_service_data , list ):
285+ for i , service_data in enumerate (all_service_data ):
286+ if service_data .startswith (self ._prefix ):
287+ if not isinstance (service_data , bytearray ):
288+ service_data = bytearray (service_data )
289+ all_service_data [i ] = service_data
290+ return memoryview (service_data )[len (self ._prefix ):]
291+ if obj .mutable :
292+ service_data = bytearray (self ._prefix )
293+ all_service_data .append (service_data )
294+ return memoryview (service_data )[len (self ._prefix ):]
295+ # Existing data is a single set of bytes.
296+ elif isinstance (all_service_data , (bytes , bytearray )):
297+ service_data = all_service_data
298+ if not bytes (service_data ).startswith (self ._prefix ):
299+ if not obj .mutable :
300+ return None
301+ # Upgrade the value to a list.
302+ service_data = bytearray (self ._prefix )
303+ obj .data_dict [self ._adt ] = [service_data , service_data ]
304+ if not isinstance (service_data , bytearray ):
305+ service_data = bytearray (service_data )
306+ obj .data_dict [self ._adt ] = service_data
307+ return memoryview (service_data )[len (self ._prefix ):]
308+
309+ return None
264310
265- # SERVICE_DATA_128BIT_UUID = 0x21
266- # """Service data with 128 bit UUID."""
267311
268- # SERVICE_DATA_16_BIT_UUID = 0x16
269- # """Service data with 16 bit UUID."""
312+ def __set__ (self , obj , value ):
313+ if not obj .mutable :
314+ raise RuntimeError ("Advertisement immutable" )
315+ if not isinstance (value , bytearray ):
316+ raise TypeError ("Value must be bytearray" )
317+ full_value = bytearray (self ._prefix ) + value
318+ if self ._adt not in obj .data_dict :
319+ obj .data_dict [self ._adt ] = full_value
320+ return
321+
322+ all_service_data = obj .data_dict [self ._adt ]
323+ if isinstance (all_service_data , list ):
324+ for i , service_data in enumerate (all_service_data ):
325+ if service_data .startswith (self ._prefix ):
326+ all_service_data [i ] = full_value
327+ return
328+ all_service_data .append (full_value )
329+ elif isinstance (all_service_data , (bytes , bytearray )):
330+ obj .data_dict [self ._adt ] = full_value
0 commit comments