gatt_client: allow to listen to characteristic value updates for service

This commit is contained in:
Matthias Ringwald 2024-08-28 09:03:05 +02:00
parent 2c937a6644
commit 1a4874dc54
2 changed files with 83 additions and 4 deletions

View File

@ -72,6 +72,7 @@
static btstack_linked_list_t gatt_client_connections;
static btstack_linked_list_t gatt_client_value_listeners;
static btstack_linked_list_t gatt_client_service_value_listeners;
#ifdef ENABLE_GATT_CLIENT_SERVICE_CHANGED
static btstack_linked_list_t gatt_client_service_changed_handler;
#endif
@ -105,6 +106,8 @@ static void gatt_client_le_enhanced_retry(btstack_timer_source_t * ts);
void gatt_client_init(void){
gatt_client_connections = NULL;
gatt_client_value_listeners = NULL;
gatt_client_service_value_listeners = NULL;
#ifdef ENABLE_GATT_CLIENT_SERVICE_CHANGED
gatt_client_service_changed_handler = NULL;
#endif
@ -1167,16 +1170,29 @@ static void report_gatt_included_service_uuid128(gatt_client_t * gatt_client, ui
}
static void report_gatt_characteristic_value_change(gatt_client_t *gatt_client, uint8_t event_type, uint16_t value_handle, uint8_t *value, int length) {
uint8_t * packet;
uint8_t * packet = setup_characteristic_value_packet(gatt_client, event_type, value_handle,
value, length, 0, 0);
// Single Characteristic listener, setup packet with service + connection id = 0
packet = setup_characteristic_value_packet(gatt_client, event_type, value_handle, value, length, 0, 0);
btstack_linked_list_iterator_t it;
btstack_linked_list_iterator_init(&it, &gatt_client_value_listeners);
while (btstack_linked_list_iterator_has_next(&it)) {
gatt_client_notification_t *notification = (gatt_client_notification_t *) btstack_linked_list_iterator_next(&it);
if ((notification->con_handle != GATT_CLIENT_ANY_CONNECTION) && (notification->con_handle != gatt_client->con_handle)) continue;
if ((notification->attribute_handle != GATT_CLIENT_ANY_VALUE_HANDLE) && (notification->attribute_handle != value_handle)) continue;
(*notification->callback)(HCI_EVENT_PACKET, 0, packet, CHARACTERISTIC_VALUE_EVENT_HEADER_SIZE + length);
}
// Service characteristics
btstack_linked_list_iterator_init(&it, &gatt_client_service_value_listeners);
while (btstack_linked_list_iterator_has_next(&it)){
const gatt_client_service_notification_t * notification = (gatt_client_service_notification_t*) btstack_linked_list_iterator_next(&it);
if (notification->con_handle != gatt_client->con_handle) continue;
if (notification->start_group_handle > value_handle) continue;
if (notification->end_group_handle < value_handle) continue;
// (re)setup value packet with service and connection id (to avoid patching event later)
packet = setup_characteristic_value_packet(gatt_client, event_type, value_handle, value, length, notification->service_id, notification->connection_id);
(*notification->callback)(HCI_EVENT_PACKET, 0, packet, CHARACTERISTIC_VALUE_EVENT_HEADER_SIZE + length);
}
}
@ -1331,6 +1347,30 @@ void gatt_client_stop_listening_for_characteristic_value_updates(gatt_client_not
btstack_linked_list_remove(&gatt_client_value_listeners, (btstack_linked_item_t*) notification);
}
void gatt_client_listen_for_service_characteristic_value_updates(gatt_client_service_notification_t * notification,
btstack_packet_handler_t callback,
hci_con_handle_t con_handle,
gatt_client_service_t * service,
uint16_t service_id,
uint16_t connection_id){
notification->callback = callback;
notification->con_handle = con_handle;
notification->start_group_handle = service->start_group_handle;
notification->end_group_handle = service->end_group_handle;
notification->service_id = 0;
notification->connection_id = 0;
btstack_linked_list_add(&gatt_client_value_listeners, (btstack_linked_item_t*) notification);
};
/**
* @brief Stop listening to characteristic value updates for registered service with
* the gatt_client_listen_for_characteristic_value_updates function.
* @param notification struct used in gatt_client_listen_for_characteristic_value_updates
*/
void gatt_client_stop_listening_for_service_characteristic_value_updates(gatt_client_service_notification_t * notification){
btstack_linked_list_remove(&gatt_client_service_value_listeners, (btstack_linked_item_t*) notification);
}
static bool is_value_valid(gatt_client_t *gatt_client, uint8_t *packet, uint16_t size){
uint16_t attribute_handle = little_endian_read_16(packet, 1);
uint16_t value_offset = little_endian_read_16(packet, 3);

View File

@ -288,13 +288,26 @@ typedef struct gatt_client{
} gatt_client_t;
typedef struct gatt_client_notification {
// Single characteristic, with wildcards for con_handle and attribute_handle
typedef struct {
btstack_linked_item_t item;
btstack_packet_handler_t callback;
hci_con_handle_t con_handle;
uint16_t attribute_handle;
} gatt_client_notification_t;
// Attribute range, aka service, no wildcards, used for implementing GATT Service clients
typedef struct {
btstack_linked_item_t item;
btstack_packet_handler_t callback;
hci_con_handle_t con_handle;
uint16_t start_group_handle;
uint16_t end_group_handle;
// Context
uint16_t service_id;
uint16_t connection_id;
} gatt_client_service_notification_t;
/* API_START */
typedef struct {
@ -1163,6 +1176,32 @@ void gatt_client_listen_for_characteristic_value_updates(gatt_client_notificatio
*/
void gatt_client_stop_listening_for_characteristic_value_updates(gatt_client_notification_t * notification);
/**
* @brief Register for notifications and indications of characteristic in a service
* the gatt_client_write_client_characteristic_configuration function.
* @param notification struct used to store registration
* @param callback
* @param con_handle or GATT_CLIENT_ANY_CONNECTION to receive updates from all connected devices
* @param service
* @param end_handle
* @param service_id - context provided to callback in events
* @param connection_id - contest provided to callback in events
*/
void gatt_client_listen_for_service_characteristic_value_updates(gatt_client_service_notification_t * notification,
btstack_packet_handler_t callback,
hci_con_handle_t con_handle,
gatt_client_service_t * service,
uint16_t service_id,
uint16_t connection_id);
/**
* @brief Stop listening to characteristic value updates for registered service with
* the gatt_client_listen_for_characteristic_value_updates function.
* @param notification struct used in gatt_client_listen_for_characteristic_value_updates
*/
void gatt_client_stop_listening_for_service_characteristic_value_updates(gatt_client_service_notification_t * notification);
/**
* @brief Transactional write. It can be called as many times as it is needed to write the characteristics within the same transaction.
* Call the gatt_client_execute_write function to commit the transaction.