share/gatt-client: Introduce idle callback
authorLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
Wed, 1 Mar 2023 00:05:47 +0000 (16:05 -0800)
committerAyush Garg <ayush.garg@samsung.com>
Fri, 5 Jan 2024 10:21:48 +0000 (15:51 +0530)
This introduces the concept of idle callback which can be used to get
notified when there is no more pending requests by the client.

src/shared/gatt-client.c
src/shared/gatt-client.h

index f0fd6bd..1bb1890 100644 (file)
@@ -50,6 +50,12 @@ struct ready_cb {
        void *data;
 };
 
+struct idle_cb {
+       bt_gatt_client_idle_callback_t callback;
+       bt_gatt_client_destroy_func_t destroy;
+       void *data;
+};
+
 struct bt_gatt_client {
        struct bt_att *att;
        int ref_count;
@@ -59,6 +65,7 @@ struct bt_gatt_client {
        struct queue *clones;
 
        struct queue *ready_cbs;
+       struct queue *idle_cbs;
 
        bt_gatt_client_service_changed_callback_t svc_chngd_callback;
        bt_gatt_client_destroy_func_t svc_chngd_destroy;
@@ -176,9 +183,38 @@ static struct request *request_create(struct bt_gatt_client *client)
        return request_ref(req);
 }
 
+static void idle_destroy(void *data)
+{
+       struct idle_cb *idle = data;
+
+       if (idle->destroy)
+               idle->destroy(idle->data);
+
+       free(idle);
+}
+
+static bool idle_notify(const void *data, const void *user_data)
+{
+       const struct idle_cb *idle = data;
+
+       idle->callback(idle->data);
+
+       return true;
+}
+
+static void notify_client_idle(struct bt_gatt_client *client)
+{
+       bt_gatt_client_ref(client);
+
+       queue_remove_all(client->idle_cbs, idle_notify, NULL, idle_destroy);
+
+       bt_gatt_client_unref(client);
+}
+
 static void request_unref(void *data)
 {
        struct request *req = data;
+       struct bt_gatt_client *client = req->client;
 
        if (__sync_sub_and_fetch(&req->ref_count, 1))
                return;
@@ -186,8 +222,11 @@ static void request_unref(void *data)
        if (req->destroy)
                req->destroy(req->data);
 
-       if (!req->removed)
-               queue_remove(req->client->pending_requests, req);
+       if (!req->removed) {
+               queue_remove(client->pending_requests, req);
+               if (queue_isempty(client->pending_requests))
+                       notify_client_idle(client);
+       }
 
        free(req);
 }
@@ -2553,6 +2592,7 @@ static void bt_gatt_client_free(struct bt_gatt_client *client)
        queue_destroy(client->notify_list, notify_data_cleanup);
 
        queue_destroy(client->ready_cbs, ready_destroy);
+       queue_destroy(client->idle_cbs, idle_destroy);
 
        if (client->debug_destroy)
                client->debug_destroy(client->debug_data);
@@ -2628,6 +2668,7 @@ static struct bt_gatt_client *gatt_client_new(struct gatt_db *db,
 
        client->clones = queue_new();
        client->ready_cbs = queue_new();
+       client->idle_cbs = queue_new();
        client->long_write_queue = queue_new();
        client->svc_chngd_queue = queue_new();
        client->notify_list = queue_new();
@@ -4162,6 +4203,39 @@ int bt_gatt_client_get_security(struct bt_gatt_client *client)
        return bt_att_get_security(client->att, NULL);
 }
 
+unsigned int bt_gatt_client_idle_register(struct bt_gatt_client *client,
+                                       bt_gatt_client_idle_callback_t callback,
+                                       void *user_data,
+                                       bt_gatt_client_destroy_func_t destroy)
+{
+       struct idle_cb *idle;
+
+       if (!client)
+               return 0;
+
+       idle = new0(struct idle_cb, 1);
+       idle->callback = callback;
+       idle->destroy = destroy;
+       idle->data = user_data;
+
+       queue_push_tail(client->idle_cbs, idle);
+
+       return PTR_TO_UINT(idle);
+}
+
+bool bt_gatt_client_idle_unregister(struct bt_gatt_client *client,
+                                               unsigned int id)
+{
+       struct idle_cb *idle = UINT_TO_PTR(id);
+
+       if (queue_remove(client->idle_cbs, idle)) {
+               idle_destroy(idle);
+               return true;
+       }
+
+       return false;
+}
+
 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
 char *bt_gatt_client_get_gap_device_name(struct bt_gatt_client *client)
 {
index a9c6799..17921dc 100755 (executable)
@@ -26,6 +26,7 @@ struct bt_gatt_client *bt_gatt_client_ref(struct bt_gatt_client *client);
 void bt_gatt_client_unref(struct bt_gatt_client *client);
 
 typedef void (*bt_gatt_client_destroy_func_t)(void *user_data);
+typedef void (*bt_gatt_client_idle_callback_t)(void *user_data);
 typedef void (*bt_gatt_client_callback_t)(bool success, uint8_t att_ecode,
                                                        void *user_data);
 typedef void (*bt_gatt_client_debug_func_t)(const char *str, void *user_data);
@@ -137,6 +138,12 @@ bool bt_gatt_client_unregister_notify(struct bt_gatt_client *client,
 
 bool bt_gatt_client_set_security(struct bt_gatt_client *client, int level);
 int bt_gatt_client_get_security(struct bt_gatt_client *client);
+unsigned int bt_gatt_client_idle_register(struct bt_gatt_client *client,
+                                       bt_gatt_client_idle_callback_t callback,
+                                       void *user_data,
+                                       bt_gatt_client_destroy_func_t destroy);
+bool bt_gatt_client_idle_unregister(struct bt_gatt_client *client,
+                                               unsigned int id);
 
 #if defined TIZEN_FEATURE_BLUEZ_MODIFY
 bool bt_gatt_discover_services(struct bt_gatt_client *client);