@@ -260,10 +260,70 @@ def __set__(self, obj, value):
260
260
else :
261
261
obj .manufacturer_data .data [self ._key ] = struct .pack (self ._format , * value )
262
262
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
+ all_service_data .append (bytearray (self ._prefix ))
293
+ return memoryview (service_data )[len (self ._prefix ):]
294
+ # Existing data is a single set of bytes.
295
+ elif isinstance (all_service_data , (bytes , bytearray )):
296
+ service_data = all_service_data
297
+ if not bytes (service_data ).startswith (self ._prefix ):
298
+ if not obj .mutable :
299
+ return None
300
+ # Upgrade the value to a list.
301
+ service_data = bytearray (self ._prefix )
302
+ obj .data_dict [self ._adt ] = [service_data , service_data ]
303
+ if not isinstance (service_data , bytearray ):
304
+ service_data = bytearray (service_data )
305
+ obj .data_dict [self ._adt ] = service_data
306
+ return memoryview (service_data )[len (self ._prefix ):]
307
+
308
+ return None
264
309
265
- # SERVICE_DATA_128BIT_UUID = 0x21
266
- # """Service data with 128 bit UUID."""
267
310
268
- # SERVICE_DATA_16_BIT_UUID = 0x16
269
- # """Service data with 16 bit UUID."""
311
+ def __set__ (self , obj , value ):
312
+ if not obj .mutable :
313
+ raise RuntimeError ("Advertisement immutable" )
314
+ if not isinstance (value , bytearray ):
315
+ raise TypeError ("Value must be bytearray" )
316
+ full_value = bytearray (self ._prefix ) + value
317
+ if self ._adt not in obj .data_dict :
318
+ obj .data_dict [self ._adt ] = full_value
319
+ return
320
+
321
+ all_service_data = obj .data_dict [self ._adt ]
322
+ if isinstance (all_service_data , list ):
323
+ for i , service_data in enumerate (all_service_data ):
324
+ if service_data .startswith (self ._prefix ):
325
+ all_service_data [i ] = full_value
326
+ return
327
+ all_service_data .append (full_value )
328
+ elif isinstance (all_service_data , (bytes , bytearray )):
329
+ obj .data_dict [self ._adt ] = full_value
0 commit comments