diff --git a/src/shared/gatt-client.c b/src/shared/gatt-client.c
index cc0a894..3f092ac 100644
--- a/src/shared/gatt-client.c
+++ b/src/shared/gatt-client.c
}
}
+static void service_list_insert_services(struct service_list **head,
+ struct service_list **tail,
+ struct service_list *svc_head,
+ struct service_list *svc_tail)
+{
+ struct service_list *cur, *prev;
+
+ if (!(*head) || !(*tail)) {
+ *head = svc_head;
+ *tail = svc_tail;
+ return;
+ }
+
+ prev = NULL;
+ cur = *head;
+ while (cur) {
+ if (svc_tail->service.end_handle < cur->service.start_handle) {
+ if (!prev)
+ *head = svc_head;
+ else
+ prev->next = svc_head;
+
+ svc_tail->next = cur;
+ return;
+ }
+
+ prev = cur;
+ cur = cur->next;
+ }
+
+ if (prev != *tail)
+ return;
+
+ prev->next = svc_head;
+ *tail = svc_tail;
+}
+
static void gatt_client_remove_all_notify_in_range(
struct bt_gatt_client *client,
uint16_t start_handle, uint16_t end_handle)
static void process_service_changed(struct bt_gatt_client *client,
uint16_t start_handle,
+ uint16_t end_handle);
+
+static void service_changed_complete(struct discovery_op *op, bool success,
+ uint8_t att_ecode)
+{
+ struct bt_gatt_client *client = op->client;
+ struct service_changed_op *next_sc_op;
+
+ client->in_svc_chngd = false;
+
+ if (!success) {
+ util_debug(client->debug_callback, client->debug_data,
+ "Failed to discover services within changed range - "
+ "error: 0x%02x", att_ecode);
+ return;
+ }
+
+ /* No new services in the modified range */
+ if (!op->result_head || !op->result_tail)
+ return;
+
+ /* Insert all newly discovered services in their correct place as a
+ * contiguous chunk */
+ service_list_insert_services(&client->svc_head, &client->svc_tail,
+ op->result_head, op->result_tail);
+
+ /* Process any queued events */
+ next_sc_op = queue_pop_head(client->svc_chngd_queue);
+ if (next_sc_op) {
+ process_service_changed(client, next_sc_op->start_handle,
+ next_sc_op->end_handle);
+ free(next_sc_op);
+ return;
+ }
+
+ /* TODO: if the GATT service has changed then register a handler
+ * for "Service Changed".
+ */
+}
+
+static void process_service_changed(struct bt_gatt_client *client,
+ uint16_t start_handle,
uint16_t end_handle)
{
+ struct discovery_op *op;
+
/* Invalidate and remove all effected notify callbacks */
gatt_client_remove_all_notify_in_range(client, start_handle,
end_handle);
service_list_clear_range(&client->svc_head, &client->svc_tail,
start_handle, end_handle);
- /* TODO Rediscover all services within the modified service range. If
- * the GATT service was effected, then register a new handler for
- * "Service Changed"
- */
+ op = new0(struct discovery_op, 1);
+ if (!op) {
+ util_debug(client->debug_callback, client->debug_data,
+ "Failed to initiate primary service discovery"
+ " after Service Changed");
+ return;
+ }
+
+ op->client = client;
+ op->complete_func = service_changed_complete;
+
+ if (!bt_gatt_discover_primary_services(client->att, NULL,
+ start_handle, end_handle,
+ discover_primary_cb,
+ discovery_op_ref(op),
+ discovery_op_unref)) {
+ util_debug(client->debug_callback, client->debug_data,
+ "Failed to initiate primary service discovery"
+ " after Service Changed");
+ free(op);
+ return;
+ }
+
+ client->in_svc_chngd = true;
}
static void service_changed_cb(uint16_t value_handle, const uint8_t *value,
if (!client || !chrc_value_handle || !callback)
return false;
- if (!bt_gatt_client_is_ready(client))
+ if (!bt_gatt_client_is_ready(client) || client->in_svc_chngd)
return false;
/* Check that chrc_value_handle belongs to a known characteristic */