From f79e90ce028c61cb1502ba9bac76aac61a8e0ee4 Mon Sep 17 00:00:00 2001 From: Olivier Martin Date: Thu, 11 Apr 2024 22:00:24 +0200 Subject: [PATCH] gattlib-py: Added support for manufacturer data from GATT advertising --- gattlib-py/gattlib/__init__.py | 14 ++++++++++++-- gattlib-py/gattlib/adapter.py | 28 ++++++++++++++++------------ gattlib-py/gattlib/device.py | 27 +++++++++++++++------------ 3 files changed, 43 insertions(+), 26 deletions(-) diff --git a/gattlib-py/gattlib/__init__.py b/gattlib-py/gattlib/__init__.py index 52d6169..a5eec07 100644 --- a/gattlib-py/gattlib/__init__.py +++ b/gattlib-py/gattlib/__init__.py @@ -103,6 +103,16 @@ class GattlibAdvertisementData(Structure): ("data", c_void_p), ("data_length", c_size_t)] +# typedef struct { +# uint16_t manufacturer_id; +# uint8_t* data; +# size_t data_size; +# } gattlib_manufacturer_data_t; +class GattlibManufacturerData(Structure): + _fields_ = [("manufacturer_id", c_ushort), + ("data", c_void_p), + ("data_size", c_size_t)] + # int gattlib_adapter_open(const char* adapter_name, gattlib_adapter_t** adapter); gattlib_adapter_open = gattlib.gattlib_adapter_open @@ -212,13 +222,13 @@ class GattlibAdvertisementData(Structure): # gattlib_advertisement_data_t **advertisement_data, size_t *advertisement_data_count, # gattlib_manufacturer_data_t** manufacturer_data, size_t* manufacturer_data_count) gattlib_get_advertisement_data = gattlib.gattlib_get_advertisement_data -gattlib_get_advertisement_data.argtypes = [c_void_p, POINTER(POINTER(GattlibAdvertisementData)), POINTER(c_size_t), POINTER(c_uint16), POINTER(c_void_p), POINTER(c_size_t)] +gattlib_get_advertisement_data.argtypes = [c_void_p, POINTER(POINTER(GattlibAdvertisementData)), POINTER(c_size_t), POINTER(POINTER(GattlibManufacturerData)), POINTER(c_size_t)] # int gattlib_get_advertisement_data_from_mac(gattlib_adapter_t* adapter, const char *mac_address, # gattlib_advertisement_data_t **advertisement_data, size_t *advertisement_data_length, # gattlib_manufacturer_data_t** manufacturer_data, size_t* manufacturer_data_count) gattlib_get_advertisement_data_from_mac = gattlib.gattlib_get_advertisement_data_from_mac -gattlib_get_advertisement_data_from_mac.argtypes = [c_void_p, c_char_p, POINTER(POINTER(GattlibAdvertisementData)), POINTER(c_size_t), POINTER(c_uint16), POINTER(c_void_p), POINTER(c_size_t)] +gattlib_get_advertisement_data_from_mac.argtypes = [c_void_p, c_char_p, POINTER(POINTER(GattlibAdvertisementData)), POINTER(c_size_t), POINTER(POINTER(GattlibManufacturerData)), POINTER(c_size_t)] # int gattlib_mainloop_python(PyObject *handler, PyObject *user_data) gattlib_mainloop = gattlib.gattlib_mainloop_python diff --git a/gattlib-py/gattlib/adapter.py b/gattlib-py/gattlib/adapter.py index 50490fb..3da984a 100644 --- a/gattlib-py/gattlib/adapter.py +++ b/gattlib-py/gattlib/adapter.py @@ -9,7 +9,7 @@ from gattlib import * from .device import Device -from .exception import handle_return, AdapterNotOpened +from .exception import handle_return from .uuid import gattlib_uuid_to_int GATTLIB_DISCOVER_FILTER_USE_UUID = (1 << 0) @@ -238,18 +238,16 @@ def gattlib_get_advertisement_data_from_mac(self, mac_address): _advertisement_data = POINTER(GattlibAdvertisementData)() _advertisement_data_count = c_size_t(0) - _manufacturer_id = c_uint16(0) - _manufacturer_data = c_void_p(None) + _manufacturer_data = POINTER(GattlibManufacturerData)() _manufacturer_data_len = c_size_t(0) ret = gattlib_get_advertisement_data_from_mac(self._adapter, mac_address, byref(_advertisement_data), byref(_advertisement_data_count), - byref(_manufacturer_id), byref(_manufacturer_data), byref(_manufacturer_data_len)) handle_return(ret) advertisement_data = {} - manufacturer_data = None + manufacturer_data = {} for i in range(0, _advertisement_data_count.value): service_data = _advertisement_data[i] @@ -264,15 +262,21 @@ def gattlib_get_advertisement_data_from_mac(self, mac_address): advertisement_data[uuid] = data - if _manufacturer_data_len.value > 0: - pointer_type = POINTER(c_byte * _manufacturer_data_len.value) - c_bytearray = cast(_manufacturer_data, pointer_type) + for i in range(0, _manufacturer_data_len.value): + _manufacturer_data = _manufacturer_data[i] - manufacturer_data = bytearray(_manufacturer_data_len.value) - for i in range(_manufacturer_data_len.value): - manufacturer_data[i] = c_bytearray.contents[i] & 0xFF + pointer_type = POINTER(c_byte * _manufacturer_data.data_size.value) + c_bytearray = cast(_manufacturer_data.data, pointer_type) + + data = bytearray(_manufacturer_data.data_size.value) + for j in range(_manufacturer_data.data_size.value): + data[j] = c_bytearray.contents[j] & 0xFF + + manufacturer_data[_manufacturer_data.manufacturer_id] = data + + gattlib_free_mem(_manufacturer_data.data) gattlib_free_mem(_advertisement_data) gattlib_free_mem(_manufacturer_data) - return advertisement_data, _manufacturer_id.value, manufacturer_data + return advertisement_data, manufacturer_data diff --git a/gattlib-py/gattlib/device.py b/gattlib-py/gattlib/device.py index f061671..161c21e 100644 --- a/gattlib-py/gattlib/device.py +++ b/gattlib-py/gattlib/device.py @@ -182,25 +182,22 @@ def discover(self): def get_advertisement_data(self): _advertisement_data = POINTER(GattlibAdvertisementData)() _advertisement_data_count = c_size_t(0) - _manufacturer_id = c_uint16(0) - _manufacturer_data = c_void_p(None) + _manufacturer_data = POINTER(GattlibManufacturerData)() _manufacturer_data_len = c_size_t(0) if self._connection is None: ret = gattlib_get_advertisement_data_from_mac(self._adapter._adapter, self._addr, byref(_advertisement_data), byref(_advertisement_data_count), - byref(_manufacturer_id), byref(_manufacturer_data), byref(_manufacturer_data_len)) else: ret = gattlib_get_advertisement_data(self._connection, byref(_advertisement_data), byref(_advertisement_data_count), - byref(_manufacturer_id), byref(_manufacturer_data), byref(_manufacturer_data_len)) handle_return(ret) advertisement_data = {} - manufacturer_data = None + manufacturer_data = {} for i in range(0, _advertisement_data_count.value): service_data = _advertisement_data[i] @@ -215,18 +212,24 @@ def get_advertisement_data(self): advertisement_data[uuid] = data - if _manufacturer_data_len.value > 0: - pointer_type = POINTER(c_byte * _manufacturer_data_len.value) - c_bytearray = cast(_manufacturer_data, pointer_type) + for i in range(0, _manufacturer_data_len.value): + _manufacturer_data = _manufacturer_data[i] - manufacturer_data = bytearray(_manufacturer_data_len.value) - for i in range(_manufacturer_data_len.value): - manufacturer_data[i] = c_bytearray.contents[i] & 0xFF + pointer_type = POINTER(c_byte * _manufacturer_data.data_size.value) + c_bytearray = cast(_manufacturer_data.data, pointer_type) + + data = bytearray(_manufacturer_data.data_size.value) + for j in range(_manufacturer_data.data_size.value): + data[j] = c_bytearray.contents[j] & 0xFF + + manufacturer_data[_manufacturer_data.manufacturer_id] = data + + gattlib_free_mem(_manufacturer_data.data) gattlib_free_mem(_advertisement_data) gattlib_free_mem(_manufacturer_data) - return advertisement_data, _manufacturer_id.value, manufacturer_data + return advertisement_data, manufacturer_data @property def services(self):