diff --git a/src/shared/gatt-client.c b/src/shared/gatt-client.c
index d0c12df..1a6fd86 100644
--- a/src/shared/gatt-client.c
+++ b/src/shared/gatt-client.c
#define UUID_BYTES (BT_GATT_UUID_SIZE * sizeof(uint8_t))
+#define GATT_SVC_UUID 0x1801
+#define SVC_CHNGD_UUID 0x2a05
+
struct chrc_data {
/* The public characteristic entry. */
bt_gatt_characteristic_t chrc_external;
unsigned int notify_id, ind_id;
bool in_notify;
bool need_notify_cleanup;
+
+ /* Handles of the GATT Service and the Service Changed characteristic
+ * value handle. These will have the value 0 if they are not present on
+ * the remote peripheral.
+ */
+ uint16_t gatt_svc_handle;
+ uint16_t svc_chngd_val_handle;
+ unsigned int svc_chngd_ind_id;
};
static bool service_list_add_service(struct service_list **head,
goto done;
}
+ if (uuid_cmp(chrcs[i].chrc_external.uuid, SVC_CHNGD_UUID) == 0)
+ client->svc_chngd_val_handle =
+ chrcs[i].chrc_external.value_handle;
+
i++;
}
success = false;
goto done;
}
+
+ if (uuid_cmp(uuid, GATT_SVC_UUID) == 0)
+ client->gatt_svc_handle = start;
}
/* Complete the process if the service list is empty */
discovery_op_unref(op);
}
+static void service_changed_cb(uint16_t value_handle, const uint8_t *value,
+ uint16_t length, void *user_data)
+{
+ struct bt_gatt_client *client = user_data;
+ uint16_t start, end;
+
+ if (value_handle != client->svc_chngd_val_handle || length != 4)
+ return;
+
+ start = get_le16(value);
+ end = get_le16(value + 2);
+
+ util_debug(client->debug_callback, client->debug_data,
+ "Service Changed received - start: 0x%04x end: 0x%04x",
+ start, end);
+
+ /* TODO: Process changed services */
+}
+
+static void service_changed_register_cb(unsigned int id, uint16_t att_ecode,
+ void *user_data)
+{
+ bool success;
+ struct bt_gatt_client *client = user_data;
+
+ if (!id || att_ecode) {
+ util_debug(client->debug_callback, client->debug_data,
+ "Failed to register handler for \"Service Changed\"");
+ success = false;
+ goto done;
+ }
+
+ client->svc_chngd_ind_id = id;
+ client->ready = true;
+ success = true;
+ util_debug(client->debug_callback, client->debug_data,
+ "Registered handler for \"Service Changed\": %u", id);
+
+done:
+ if (client->ready_callback)
+ client->ready_callback(success, att_ecode, client->ready_data);
+}
+
static void init_complete(struct discovery_op *op, bool success,
uint8_t att_ecode)
{
struct bt_gatt_client *client = op->client;
+ bool registered;
client->in_init = false;
- if (success) {
- client->svc_head = op->result_head;
- client->svc_tail = op->result_tail;
+ if (!success)
+ goto fail;
+
+ client->svc_head = op->result_head;
+ client->svc_tail = op->result_tail;
+
+ if (!client->svc_chngd_val_handle) {
client->ready = true;
- } else
- service_list_clear(&op->result_head, &op->result_tail);
+ goto done;
+ }
+
+ /* Register an indication handler for the "Service Changed"
+ * characteristic and report ready only if the handler is registered
+ * successfully. Temporarily set "ready" to true so that we can register
+ * the handler using the existing framework.
+ */
+ client->ready = true;
+ registered = bt_gatt_client_register_notify(client,
+ client->svc_chngd_val_handle,
+ service_changed_register_cb,
+ service_changed_cb,
+ client, NULL);
+ client->ready = false;
+
+ if (registered)
+ return;
+ util_debug(client->debug_callback, client->debug_data,
+ "Failed to register handler for \"Service Changed\"");
+
+ client->svc_head = client->svc_tail = NULL;
+
+fail:
+ util_debug(client->debug_callback, client->debug_data,
+ "Failed to initialize gatt-client");
+ service_list_clear(&op->result_head, &op->result_tail);
+
+done:
if (client->ready_callback)
client->ready_callback(success, att_ecode, client->ready_data);
}