[Adapt]Implement HAL based Health Device Profile 04/93104/1
authorAtul Rai <a.rai@samsung.com>
Mon, 17 Oct 2016 05:16:58 +0000 (10:46 +0530)
committerAtul Rai <a.rai@samsung.com>
Mon, 17 Oct 2016 05:16:58 +0000 (10:46 +0530)
This patch modify bt-api implementation to make it compatible with
HAL based Health Device Profile implementation.

Change-Id: I5425845f73247f677c72fbdc28d36ab8c4116e4f
Signed-off-by: Atul Rai <a.rai@samsung.com>
bt-api/bt-common.c
bt-api/bt-event-handler.c
bt-api/bt-hdp.c
bt-api/bt-request-sender.c
bt-api/include/bt-common.h

index 515d4ce..5e0518c 100644 (file)
@@ -1632,6 +1632,9 @@ BT_EXPORT_API int bluetooth_register_callback(bluetooth_cb_func_ptr callback_ptr
        if (ret != BLUETOOTH_ERROR_NONE)
                goto fail;
 #endif
+       ret = _bt_register_event(BT_HDP_EVENT, (void *)callback_ptr, user_data);
+       if (ret != BLUETOOTH_ERROR_NONE)
+               goto fail;
 
        _bt_register_name_owner_changed();
 
index 5730250..cf6f74f 100644 (file)
@@ -2423,6 +2423,68 @@ void __bt_hf_agent_event_filter(GDBusConnection *connection,
        BT_DBG("-\n");
 }
 
+void __bt_hdp_event_filter(GDBusConnection *connection,
+                                                const gchar *sender_name,
+                                                const gchar *object_path,
+                                                const gchar *interface_name,
+                                                const gchar *signal_name,
+                                                GVariant *parameters,
+                                                gpointer user_data)
+{
+       bt_event_info_t *event_info;
+       int result = BLUETOOTH_ERROR_NONE;
+
+       BT_DBG("+");
+       event_info = (bt_event_info_t *)user_data;
+       ret_if(event_info == NULL);
+
+       if (strcasecmp(object_path, BT_HDP_DEVICE_PATH) != 0)
+               return;
+       if (strcasecmp(interface_name, BT_EVENT_SERVICE) != 0)
+               return;
+
+       ret_if(signal_name == NULL);
+
+       if (strcasecmp(signal_name, BT_HDP_CONNECTED) == 0) {
+               const char *address = NULL;
+               char *app_handle = NULL;
+               bt_hdp_connected_t conn_info;
+
+               g_variant_get(parameters, "(i&s&sui)", &result,
+                               &address, &app_handle,
+                               &(conn_info.channel_id), &(conn_info.type));
+
+               g_strlcpy(conn_info.app_handle, app_handle, BT_MAX_HANDLE_LENGTH);
+
+               BT_DBG("address: %s, app_handle: %s, ch_id: %d, ch_type: %d",
+                       address, conn_info.app_handle, conn_info.channel_id, conn_info.type);
+               _bt_convert_addr_string_to_type(conn_info.device_address.addr, address);
+
+               if (BLUETOOTH_ERROR_NONE == result)
+                       result = _bt_hdp_app_acquire_fd(&conn_info);
+
+               _bt_common_event_cb(BLUETOOTH_EVENT_HDP_CONNECTED,
+                               result, &conn_info,
+                               event_info->cb, event_info->user_data);
+       } else if (strcasecmp(signal_name, BT_HDP_DISCONNECTED) == 0) {
+               const char *address = NULL;
+               bt_hdp_disconnected_t disconn_info;
+
+               g_variant_get(parameters, "(i&su)", &result,
+                               &address, &(disconn_info.channel_id));
+
+               BT_DBG("address: %s", address);
+               _bt_convert_addr_string_to_type(disconn_info.device_address.addr, address);
+
+               _bt_hdp_app_remove_obj_info(disconn_info.channel_id);
+               _bt_common_event_cb(BLUETOOTH_EVENT_HDP_DISCONNECTED,
+                               result, &disconn_info,
+                               event_info->cb, event_info->user_data);
+       }
+
+       BT_DBG("-");
+}
+
 static void __bt_remove_all_events(void)
 {
        GSList *l;
@@ -2646,6 +2708,11 @@ int _bt_register_event(int event_type, void *event_cb, void *user_data)
                path = NULL;
                break;
 #endif
+       case BT_HDP_EVENT:
+               BT_DBG("BT_HID_DEVICE_EVENT");
+               event_func = __bt_hdp_event_filter;
+               path = BT_HDP_DEVICE_PATH;
+               break;
        default:
                BT_ERR("Unknown event");
                return BLUETOOTH_ERROR_INTERNAL;
index 29a8068..52fb3d9 100755 (executable)
 #include "bluetooth-api.h"
 #include "bt-common.h"
 #include "bt-internal-types.h"
+#include "bt-request-sender.h"
 
-/**********************************************************************
-*              Static Functions declaration                            *
-***********************************************************************/
+#define HDP_BUFFER_SIZE 1024
+#define BLUEZ_HDP_MANAGER_INTERFACE  "org.bluez.HealthManager1"
+#define BLUEZ_HDP_DEVICE_INTERFACE  "org.bluez.HealthDevice1"
+#define BLUEZ_HDP_CHANNEL_INTERFACE  "org.bluez.HealthChannel1"
+
+typedef struct {
+       int fd;
+       unsigned int channel_id;
+       guint watch_id;
+       void *app_handle;
+} hdp_obj_info_t;
+
+typedef struct {
+       void *app_handle;
+       GSList *obj_info;
+} hdp_app_list_t;
+
+static GSList *g_app_list = NULL;
+
+/* Variable for privilege, only for write API,
+ * before we should reduce time to bt-service dbus calling
+ * -1 : Don't have a permission to access API
+ * 0 : Initial value, not yet check
+ * 1 : Have a permission to access API
+ */
+static int privilege_token;
+
+static void __bt_hdp_obj_info_free(hdp_obj_info_t *info)
+{
+       if (info) {
+               g_source_remove(info->watch_id);
+               close(info->fd);
+               g_free(info);
+       }
+}
+
+static hdp_app_list_t *__bt_hdp_internal_gslist_find_app_handler(void *app_handle)
+{
+       GSList *l;
+
+       retv_if(g_app_list == NULL, NULL);
+
+       BT_DBG("List length = %d\n", g_slist_length(g_app_list));
+
+       for (l = g_app_list; l != NULL; l = l->next) {
+               hdp_app_list_t *list = l->data;
+
+               if (list) {
+                       if (0 == g_strcmp0((char *)list->app_handle,
+                                               (char *)app_handle))
+                               return list;
+               }
+       }
+
+       return NULL;
+}
+
+static hdp_obj_info_t *__bt_hdp_internal_gslist_obj_find_using_ch_id(unsigned int channel_id)
+{
+       GSList *l;
+       GSList *iter;
+
+       retv_if(g_app_list == NULL, NULL);
+
+       BT_DBG("List length = %d\n", g_slist_length(g_app_list));
+
+       for (l = g_app_list; l != NULL; l = l->next) {
+               hdp_app_list_t *list = l->data;
+               if (!list)
+                       return NULL;
+
+               for (iter = list->obj_info; iter != NULL; iter = iter->next) {
+                       hdp_obj_info_t *info = iter->data;
+                       if (!info)
+                               return NULL;
+
+                       if (channel_id == info->channel_id)
+                               return info;
+               }
+       }
+
+       return NULL;
+}
+
+static gboolean __bt_hdp_internal_data_received(GIOChannel *gio,
+                                       GIOCondition cond, gpointer data)
+{
+       int fd;
+       gsize len = 0;
+       bt_user_info_t *user_info;
+       char buff[HDP_BUFFER_SIZE] = { 0, };
+       GError *err = NULL;
+       GIOStatus status = G_IO_STATUS_NORMAL;
+       hdp_obj_info_t *info = data;
+
+       BT_DBG("+");
+
+       retv_if(NULL == info, FALSE);
+
+       fd = g_io_channel_unix_get_fd(gio);
+       if (cond & (G_IO_NVAL | G_IO_HUP | G_IO_ERR)) {
+               BT_DBG("GIOCondition %d", cond);
+               g_io_channel_shutdown(gio, TRUE, NULL);
+               g_io_channel_unref(gio);
+               _bt_hdp_app_remove_obj_info(info->channel_id);
+               /* TODO: call hdp_disconnect and send disconnect event if needed */
+               return FALSE;
+       }
+
+       status = g_io_channel_read_chars(gio, buff, HDP_BUFFER_SIZE, &len, &err);
+       if (status != G_IO_STATUS_NORMAL) {
+               BT_ERR("IO Channel read is failed with %d", status);
+               if (err) {
+                       BT_ERR("IO Channel read error [%s]", err->message);
+                       g_error_free(err);
+               }
+               return FALSE;
+       }
+
+       BT_DBG("fd: %d, len: %d, buffer: %s", fd, len, buff);
+
+       user_info = _bt_get_user_data(BT_COMMON);
+       if (user_info->cb) {
+               bt_hdp_data_ind_t data_ind = { 0, };
+
+               data_ind.channel_id = info->channel_id;
+               data_ind.buffer = buff;
+               data_ind.size = len;
+               _bt_common_event_cb(BLUETOOTH_EVENT_HDP_DATA_RECEIVED,
+                               BLUETOOTH_ERROR_NONE, &data_ind,
+                               user_info->cb, user_info->user_data);
+       }
+
+       BT_DBG("-");
+       return TRUE;
+}
+
+static void __hdp_handle_new_connection(bt_hdp_connected_t *conn_info, int fd)
+{
+       hdp_obj_info_t *info;
+       hdp_app_list_t *list;
+       GIOChannel *gio;
+
+       BT_DBG("+");
+
+       list = __bt_hdp_internal_gslist_find_app_handler((void *)conn_info->app_handle);
+       if (NULL == list) {
+               BT_ERR("**** Could not locate the list for %s*****\n", conn_info->app_handle);
+               return;
+       }
+
+       info = g_new0(hdp_obj_info_t, 1);
+       info->channel_id = conn_info->channel_id;
+       info->app_handle = list->app_handle;
+       info->fd = fd;
+
+       gio = g_io_channel_unix_new(fd);
+       g_io_channel_set_close_on_unref(gio, TRUE);
+       info->watch_id = g_io_add_watch(gio, G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
+                       __bt_hdp_internal_data_received, (void *)info);
+       g_io_channel_unref(gio);
+       list->obj_info = g_slist_append(list->obj_info, info);
+
+       BT_DBG("-");
+}
+
+void _bt_hdp_app_remove_obj_info(unsigned int channel_id)
+{
+       hdp_app_list_t *list;
+       hdp_obj_info_t *info;
+
+       BT_DBG("+");
+
+       info = __bt_hdp_internal_gslist_obj_find_using_ch_id(channel_id);
+       ret_if(NULL == info);
+
+       list = __bt_hdp_internal_gslist_find_app_handler(info->app_handle);
+       ret_if(NULL == list);
+
+       list->obj_info = g_slist_remove(list->obj_info, info);
+       __bt_hdp_obj_info_free(info);
+
+       BT_DBG("-");
+}
+
+int _bt_hdp_app_acquire_fd(bt_hdp_connected_t *conn_info)
+{
+       int result;
+       GUnixFDList *out_fd_list = NULL;
+
+       BT_INIT_PARAMS();
+       BT_ALLOC_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param);
+
+       g_array_append_vals(in_param1, &conn_info->channel_id, sizeof(int));
+       result = _bt_send_request_with_unix_fd_list(BT_BLUEZ_SERVICE, BT_HDP_GET_FD,
+                       in_param1, in_param2, in_param3, in_param4, NULL, &out_param, &out_fd_list);
+
+       BT_FREE_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param);
+
+       BT_DBG("result: %x", result);
+       if (result != BLUETOOTH_ERROR_NONE || NULL == out_fd_list) {
+               BT_ERR("out_fd_list is NULL");
+               bluetooth_hdp_disconnect(conn_info->channel_id, &conn_info->device_address);
+               return BLUETOOTH_ERROR_INTERNAL;
+       } else {
+               int *fd_list_array;
+               int len = 0;
+
+               fd_list_array = g_unix_fd_list_steal_fds(out_fd_list, &len);
+               BT_INFO("Num fds in fd_list is : %d, fd_list[0]: %d", len, fd_list_array[0]);
+               __hdp_handle_new_connection(conn_info, fd_list_array[0]);
+               g_free(fd_list_array);
+               g_object_unref(out_fd_list);
+       }
+
+       BT_DBG("-");
+       return BLUETOOTH_ERROR_NONE;
+}
 
 /**********************************************************************
 *                      Health device APIs (HDP)                        *
 ***********************************************************************/
-
 BT_EXPORT_API int bluetooth_hdp_activate(unsigned short data_type,
                                        bt_hdp_role_type_t role,
                                        bt_hdp_qos_type_t channel_type,
                                        char **app_handle)
 {
-       return BLUETOOTH_ERROR_NONE;
+       int result = BLUETOOTH_ERROR_NONE;
+
+       BT_DBG("+");
+
+       BT_CHECK_ENABLED(return);
+
+       /*For source role is mandatory */
+       if (role == HDP_ROLE_SOURCE && channel_type == HDP_QOS_ANY) {
+               BT_ERR("For source, type is mandatory - Reliable/Streaming");
+               return BLUETOOTH_ERROR_INVALID_PARAM;
+       }
+
+       BT_INIT_PARAMS();
+       BT_ALLOC_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param);
+
+       g_array_append_vals(in_param1, &data_type, sizeof(short));
+       g_array_append_vals(in_param2, &role, sizeof(bt_hdp_role_type_t));
+       g_array_append_vals(in_param3, &channel_type, sizeof(bt_hdp_qos_type_t));
+
+       result = _bt_send_request(BT_BLUEZ_SERVICE, BT_HDP_CREATE_APPLICATION,
+               in_param1, in_param2, in_param3, in_param4, &out_param);
+
+       if (result == BLUETOOTH_ERROR_NONE) {
+               char *buf;
+               hdp_app_list_t *list;
+
+               buf = &g_array_index(out_param, char, 0);
+               BT_DBG("Created app: %s", buf);
+
+               list = g_new0(hdp_app_list_t, 1);
+               list->app_handle = (void *)g_strdup(buf);
+               *app_handle = list->app_handle;
+               g_app_list = g_slist_append(g_app_list, list);
+       }
+
+       BT_FREE_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param);
+
+       BT_DBG("-");
+       return result;
 }
 
 BT_EXPORT_API int bluetooth_hdp_deactivate(const char *app_handle)
 {
-       return BLUETOOTH_ERROR_NONE;
+       int result;
+       hdp_app_list_t *list;
+
+       BT_DBG("+");
+
+       BT_CHECK_ENABLED(return);
+       BT_CHECK_PARAMETER(app_handle, return);
+
+       list = __bt_hdp_internal_gslist_find_app_handler((void *)app_handle);
+       if (NULL == list) {
+               BT_ERR("**** list not found for %s ******\n", app_handle);
+               return BLUETOOTH_ERROR_INVALID_PARAM;
+       }
+
+       BT_DBG("app_handle: %s", app_handle);
+
+       BT_INIT_PARAMS();
+       BT_ALLOC_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param);
+
+       g_array_append_vals(in_param1, app_handle, (strlen(app_handle) + 1));
+
+       result = _bt_send_request(BT_BLUEZ_SERVICE, BT_HDP_DESTROY_APPLICATION,
+               in_param1, in_param2, in_param3, in_param4, &out_param);
+       if (result == BLUETOOTH_ERROR_NONE) {
+               g_app_list = g_slist_remove(g_app_list, list);
+               g_free(list->app_handle);
+               g_slist_foreach(list->obj_info, (GFunc)__bt_hdp_obj_info_free, NULL);
+               g_free(list);
+       }
+
+       BT_FREE_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param);
+
+       return result;
 }
 
 BT_EXPORT_API int bluetooth_hdp_send_data(unsigned int channel_id,
                                            const char *buffer,
                                            unsigned int size)
 {
+       int wbytes = 0;
+       int written = 0;
+       hdp_obj_info_t *info;
+       int result;
+
+       BT_DBG("+");
+
+       BT_CHECK_ENABLED(return);
+
+       retv_if (NULL == buffer, BLUETOOTH_ERROR_INVALID_PARAM);
+       retv_if (0 == size, BLUETOOTH_ERROR_INVALID_PARAM);
+
+       info = __bt_hdp_internal_gslist_obj_find_using_ch_id(channel_id);
+       if (NULL == info) {
+               BT_ERR("*** Could not locate the info for %d*****", channel_id);
+               return BLUETOOTH_ERROR_INVALID_PARAM;
+       }
+
+       switch (privilege_token) {
+       case 0:
+               result = _bt_check_privilege(BT_BLUEZ_SERVICE, BT_HDP_SEND_DATA);
+
+               if (result == BLUETOOTH_ERROR_NONE) {
+                       privilege_token = 1; /* Have a permission */
+               } else if (result == BLUETOOTH_ERROR_PERMISSION_DEINED) {
+                       BT_ERR("Don't have a privilege to use this API");
+                       privilege_token = -1; /* Don't have a permission */
+                       return BLUETOOTH_ERROR_PERMISSION_DEINED;
+               } else {
+                       /* Just break - It is not related with permission error */
+               }
+               break;
+       case 1:
+               /* Already have a privilege */
+               break;
+       case -1:
+               return BLUETOOTH_ERROR_PERMISSION_DEINED;
+       default:
+               /* Invalid privilge token value */
+               return BLUETOOTH_ERROR_INTERNAL;
+       }
+
+       while (wbytes < size) {
+               written = write(info->fd, (buffer + wbytes), (size - wbytes));
+               if (written <= 0) {
+                       BT_ERR("write failed..\n");
+                       return BLUETOOTH_ERROR_NOT_IN_OPERATION;
+               }
+               wbytes += written;
+       }
+
        return BLUETOOTH_ERROR_NONE;
 }
 
@@ -58,11 +394,76 @@ BT_EXPORT_API int bluetooth_hdp_connect(const char *app_handle,
                        bt_hdp_qos_type_t channel_type,
                        const bluetooth_device_address_t *device_address)
 {
-       return BLUETOOTH_ERROR_NONE;
+       int result;
+       hdp_app_list_t *list;
+       bt_user_info_t *user_info;
+
+       BT_CHECK_ENABLED(return);
+       BT_CHECK_PARAMETER(app_handle, return);
+       BT_CHECK_PARAMETER(device_address, return);
+
+        user_info = _bt_get_user_data(BT_COMMON);
+       retv_if(user_info->cb == NULL, BLUETOOTH_ERROR_INTERNAL);
+
+       list = __bt_hdp_internal_gslist_find_app_handler((void *)app_handle);
+       if (NULL == list) {
+               BT_ERR("**** list not found for %s ******\n", app_handle);
+               return BLUETOOTH_ERROR_INVALID_PARAM;
+       }
+
+       BT_DBG("app_handle: %s", app_handle);
+
+       BT_INIT_PARAMS();
+       BT_ALLOC_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param);
+
+       g_array_append_vals(in_param1, app_handle, (strlen(app_handle) + 1));
+       g_array_append_vals(in_param2, &channel_type, sizeof(bt_hdp_qos_type_t));
+       g_array_append_vals(in_param3, device_address, sizeof(bluetooth_device_address_t));
+
+       result = _bt_send_request_async(BT_BLUEZ_SERVICE,
+                       BT_HDP_CONNECT, in_param1, in_param2, in_param3, in_param4,
+                       user_info->cb, user_info->user_data);
+
+       if (result != BLUETOOTH_ERROR_NONE)
+               BT_ERR("BT_HDP_CONNECT failed");
+
+       BT_FREE_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param);
+
+       return result;
 }
 
 BT_EXPORT_API int bluetooth_hdp_disconnect(unsigned int channel_id,
                        const bluetooth_device_address_t *device_address)
 {
-       return BLUETOOTH_ERROR_NONE;
+       int result;
+       hdp_obj_info_t *info;
+       bt_user_info_t *user_info;
+
+       BT_CHECK_ENABLED(return);
+       BT_CHECK_PARAMETER(device_address, return);
+
+        user_info = _bt_get_user_data(BT_COMMON);
+       retv_if(user_info->cb == NULL, BLUETOOTH_ERROR_INTERNAL);
+
+       BT_DBG("channel_id: %d", channel_id);
+       info = __bt_hdp_internal_gslist_obj_find_using_ch_id(channel_id);
+       if (NULL == info) {
+               BT_ERR("*** Could not locate the info for %d*****", channel_id);
+               return BLUETOOTH_ERROR_INVALID_PARAM;
+       }
+
+       BT_INIT_PARAMS();
+       BT_ALLOC_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param);
+
+       g_array_append_vals(in_param1, &channel_id, sizeof(int));
+       g_array_append_vals(in_param2, device_address, sizeof(bluetooth_device_address_t));
+
+       result = _bt_send_request_async(BT_BLUEZ_SERVICE, BT_HDP_DISCONNECT,
+                       in_param1, in_param2, in_param3, in_param4,
+                       user_info->cb, user_info->user_data);
+       if (result != BLUETOOTH_ERROR_NONE)
+               BT_ERR("BT_HDP_DISCONNECT failed");
+
+       BT_FREE_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param);
+       return result;
 }
index 2d87ea8..bcc3c2a 100644 (file)
@@ -221,6 +221,20 @@ void _bt_get_event_info(int service_function, GArray *output,
                *param_data = &g_array_index(output,
                                bluetooth_device_address_t, 0);
                break;
+       case BT_HDP_CONNECT:
+               *event_type = BT_HDP_EVENT;
+               *event = BLUETOOTH_EVENT_HDP_CONNECTED;
+               ret_if(output == NULL);
+               *param_data = &g_array_index(output,
+                               bt_hdp_connected_t, 0);
+               break;
+       case BT_HDP_DISCONNECT:
+               *event_type = BT_HDP_EVENT;
+               *event = BLUETOOTH_EVENT_HDP_DISCONNECTED;
+               ret_if(output == NULL);
+               *param_data = &g_array_index(output,
+                               bt_hdp_disconnected_t, 0);
+               break;
        default:
                BT_ERR("Unknown function");
                return;
@@ -353,6 +367,9 @@ static void __send_request_cb(GDBusProxy *proxy,
                ((bluetooth_cb_func_ptr)cb_data->cb)(bt_event.event,
                                &bt_event,
                                cb_data->user_data);
+       } else if (event_type == BT_HDP_EVENT) {
+               ((bluetooth_cb_func_ptr)cb_data->cb)(bt_event.event,
+                       &bt_event, cb_data->user_data);
        } else {
                BT_INFO("Not handled event type : %d", event_type);
        }
index f97c9f6..3f77709 100755 (executable)
@@ -355,6 +355,9 @@ int _get_rfcomm_server_id(char *uuid, gboolean *auto_accept);
 void _bt_rfcomm_server_set_pending_conn(int server_id, char *address);
 #endif
 
+void _bt_hdp_app_remove_obj_info(unsigned int channe_id);
+int _bt_hdp_app_acquire_fd(bt_hdp_connected_t *conn_info);
+
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */