@@ -260,10 +260,71 @@ 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
+ 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
264
310
265
- # SERVICE_DATA_128BIT_UUID = 0x21
266
- # """Service data with 128 bit UUID."""
267
311
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