Added feature : notification of GATT char Changed Value 80/187980/4
authorAmit Purwar <amit.purwar@samsung.com>
Fri, 31 Aug 2018 11:30:37 +0000 (17:00 +0530)
committerAmit Purwar <amit.purwar@samsung.com>
Fri, 31 Aug 2018 11:30:37 +0000 (17:00 +0530)
Change-Id: I387bb74f169da38481ee4a03a65817f0ec0e89f9
Signed-off-by: Amit Purwar <amit.purwar@samsung.com>
bt-api/bt-event-handler.c
bt-oal/bluez_hal/inc/bt-hal-msg.h
bt-oal/bluez_hal/src/bt-hal-event-receiver.c
bt-oal/bluez_hal/src/bt-hal-gatt-client.c
bt-oal/bluez_hal/src/bt-hal-gatt-client.h
bt-oal/bluez_hal/src/bt-hal-gatt.c
bt-oal/bluez_hal/src/bt-hal-internal.h
bt-oal/include/oal-event.h
bt-oal/oal-gatt.c
bt-service-adaptation/services/gatt/bt-service-gatt.c

index ef23dad..d79bebc 100644 (file)
@@ -3508,10 +3508,17 @@ static void __bt_gatt_client_event_filter(GDBusConnection *connection,
                BT_INFO("GATT Client Char value changed in remote Server [%s]", address);
                BT_INFO("GATT Client Char Val len: [%d]", char_prop.val_len);
 
-               /* Copy Data */
-               memcpy(&char_prop.value, g_variant_get_data(data_var), char_prop.val_len);
+               if (char_prop.val_len > 0) {
+                       /* Copy Data */
+                       memcpy(&char_prop.value, g_variant_get_data(data_var), char_prop.val_len);
+               }
+
                memcpy(&char_prop.prop.uuid, g_variant_get_data(char_uuid_var), 16);
 
+               /* Copy SVC data */
+               memcpy(&char_prop.svc_prop.uuid, g_variant_get_data(svc_uuid_var), 16);
+               char_prop.svc_prop.instance_id = svc_inst;
+
                /* DEBUG */
                for (i = 0; i < char_prop.val_len; i++)
                        BT_INFO("Data[%d] = [0x%x]", i, char_prop.value[i]);
index a8a3a9c..c8c3478 100644 (file)
@@ -738,7 +738,7 @@ struct hal_ev_gatt_server_acquire_write_res {
        uint8_t bdaddr[6];
 } __attribute__((packed));
 
-#define HAL_EV_GATT_SERVER_ACQUIRE_NOTIFY_RES  0XC10
+#define HAL_EV_GATT_SERVER_ACQUIRE_NOTIFY_RES  0XCA
 struct hal_ev_gatt_server_acquire_notify {
        int32_t mtu;
        int32_t trans_id;
@@ -747,6 +747,17 @@ struct hal_ev_gatt_server_acquire_notify {
        char *path;
 } __attribute__((packed));
 
-
+#define HAL_EV_GATT_CLIENT_NOTIFY_CHANGED_VALUE 0XCB
+struct hal_ev_gatt_client_notify_changed_value {
+       int32_t conn_id;
+       uint8_t value[600];
+       int32_t len;
+       uint8_t bdaddr[6];
+       int32_t is_primary;
+       int32_t inst_id;
+       uint8_t svc_uuid[16];
+       uint8_t char_uuid[16];
+       uint8_t is_notify;
+} __attribute__((packed));
 
 #endif //_BT_HAL_MSG_H_
index 8161fdc..a634552 100644 (file)
@@ -435,7 +435,7 @@ static void __bt_hal_adapter_property_changed_event(GVariant *msg)
                        GVariantIter *iter = NULL;
                        g_variant_get(value, "as", &iter);
                        bt_local_le_features_t le_features;
-                        gboolean le_features_present = FALSE;
+                       gboolean le_features_present = FALSE;
 
                        if (iter == NULL)
                                continue;
@@ -906,6 +906,36 @@ static gboolean __bt_hal_parse_interface(GVariant *msg)
        return FALSE;
 }
 
+void __bt_hal_handle_gatt_char_event(GVariant *parameters, const char *signal_name)
+{
+       DBG("+");
+
+       if (signal_name == NULL)
+               return;
+
+       if (strcasecmp(signal_name, "GattValueChanged") == 0) {
+               DBG("GattValueChanged event received");
+
+               int result = 0;
+               const char *char_handle = NULL;
+               GVariant *char_value_var = NULL;
+               int len = 0;
+               char *char_value = NULL;
+
+               g_variant_get(parameters, "(i&s@ay)", &result, &char_handle, &char_value_var);
+               DBG("char handle: %s", char_handle);
+
+               len = g_variant_get_size(char_value_var);
+               if (len > 0)
+                       char_value = (char *)g_variant_get_data(char_value_var);
+
+               _bt_hal_handle_gattc_value_changed_event(result, char_handle, char_value, len);
+
+               g_variant_unref(char_value_var);
+       }
+}
+
+
 static gboolean __bt_hal_event_manager(gpointer data)
 {
        bt_hal_event_type_t bt_event = 0x00;
@@ -1011,6 +1041,9 @@ static gboolean __bt_hal_event_manager(gpointer data)
        } else if (g_strcmp0(param->interface_name, BT_HAL_MEDIATRANSPORT_INTERFACE) == 0) {
                DBG("Manager Event: Interface Name: BT_HAL_MEDIATRANSPORT_INTERFACE");
                __bt_hal_handle_avrcp_transport_events(param->parameters, param->signal_name, param->object_path);
+       } else if (g_strcmp0(param->interface_name, BT_HAL_GATT_CHAR_INTERFACE) == 0) {
+               DBG("Manager Event: Interface Name: BT_HAL_GATT_CHAR_INTERFACE");
+               __bt_hal_handle_gatt_char_event(param->parameters, param->signal_name);
        }
 
 
@@ -1259,6 +1292,34 @@ static int __bt_hal_register_input_subscribe_signal(GDBusConnection *conn, int s
        return 0;
 }
 
+static int __bt_hal_register_gatt_subscribe_signal(GDBusConnection *conn,
+               int subscribe)
+{
+       static int subs_gatt_id = -1;
+
+       DBG("+");
+
+       if (subscribe) {
+               if (subs_gatt_id == -1) {
+                       subs_gatt_id = g_dbus_connection_signal_subscribe(conn,
+                                       NULL, BT_HAL_GATT_CHAR_INTERFACE,
+                                       NULL, NULL, NULL, 0,
+                                       __bt_hal_manager_event_filter,
+                                       NULL, NULL);
+               }
+       } else {
+               if (subs_gatt_id == -1) {
+                       g_dbus_connection_signal_unsubscribe(conn,
+                                       subs_gatt_id);
+                       subs_gatt_id = -1;
+               }
+       }
+
+       return BT_HAL_ERROR_NONE;
+}
+
+
+
 static int __bt_hal_register_service_event(GDBusConnection *g_conn, int event_type)
 {
        DBG("+");
@@ -1280,6 +1341,9 @@ static int __bt_hal_register_service_event(GDBusConnection *g_conn, int event_ty
        case BT_HAL_HEADSET_EVENT:
                 __bt_hal_register_audio_subscribe_signal(g_conn, TRUE);
                break;
+       case BT_HAL_GATT_EVENT:
+               __bt_hal_register_gatt_subscribe_signal(g_conn, TRUE);
+               break;
        default:
                INFO_C("Register Event: event_type [%d]", event_type);
                return BT_HAL_ERROR_NOT_SUPPORT;
@@ -1355,6 +1419,9 @@ static int __bt_hal_initialize_manager_receiver(void)
        if (__bt_hal_register_service_event(manager_conn,
                                BT_HAL_HEADSET_EVENT) != BT_HAL_ERROR_NONE)
                goto fail;
+       if (__bt_hal_register_service_event(manager_conn,
+                               BT_HAL_GATT_EVENT) != BT_HAL_ERROR_NONE)
+               goto fail;
        return BT_HAL_ERROR_NONE;
 fail:
        if (manager_conn) {
index 0bfd12d..61c4af9 100644 (file)
@@ -117,6 +117,7 @@ typedef struct {
 typedef struct {
        gchar *svc_path;
        bt_uuid_t svc_uuid;
+       int is_primary;
        GSList *gatt_list_chars;
 } hal_gattc_service_t;
 
@@ -565,6 +566,28 @@ static hal_gattc_char_t* _gattc_find_char_from_uuid(hal_gattc_service_t *gattc_s
        return NULL;
 }
 
+static hal_gattc_char_t* _gattc_find_char_from_uuid_for_notify(hal_gattc_service_t *gattc_svc, bt_uuid_t *char_uuid)
+{
+       DBG("+");
+
+       GSList *l;
+       hal_gattc_char_t *info = NULL;
+
+       for (l = gattc_svc->gatt_list_chars; l != NULL; l = g_slist_next(l)) {
+               info = (hal_gattc_char_t*)l->data;
+               if (info == NULL)
+                       continue;
+
+               if (!memcmp(&info->chr_uuid, char_uuid, sizeof(bt_uuid_t)) &&
+                       ((info->permission & HAL_GATT_CHARACTERISTIC_PROPERTY_NOTIFY) ||
+                               (info->permission & HAL_GATT_CHARACTERISTIC_PROPERTY_INDICATE))) {
+                       INFO("Found GATT char uuid");
+                       return info;
+               }
+       }
+       return NULL;
+}
+
 static hal_gattc_desc_t* _gattc_find_desc_from_uuid(hal_gattc_char_t *gattc_char, bt_uuid_t *desc_uuid)
 {
        DBG("+");
@@ -587,7 +610,7 @@ static hal_gattc_desc_t* _gattc_find_desc_from_uuid(hal_gattc_char_t *gattc_char
 
 
 static hal_gattc_service_t* _hal_gatt_client_add_service(hal_gattc_server_info_t *conn_info,
-               const char *uuid_str, char *object_path)
+               const char *uuid_str, char *object_path, int is_primary)
 {
        DBG("+");
        hal_gattc_service_t *gattc_service = NULL;
@@ -595,6 +618,7 @@ static hal_gattc_service_t* _hal_gatt_client_add_service(hal_gattc_server_info_t
        gattc_service = g_malloc0(sizeof(hal_gattc_service_t));
        gattc_service->svc_path = g_strdup(object_path);
        _bt_hal_convert_uuid_string_to_type(gattc_service->svc_uuid.uu, uuid_str);
+       gattc_service->is_primary = is_primary;
 
        DBG("service count[%d]", g_slist_length(conn_info->gatt_list_services));
 
@@ -629,7 +653,7 @@ static void _gattc_create_new_service(hal_gattc_server_info_t *conn_info, gboole
        DBG("+");
 
        /* add the service */
-       gatt_svc = _hal_gatt_client_add_service(conn_info, uuid_str, object_path);
+       gatt_svc = _hal_gatt_client_add_service(conn_info, uuid_str, object_path, is_primary);
        if (gatt_svc == NULL) {
                ERR("Failed to add service");
                return;
@@ -2406,8 +2430,7 @@ static bt_status_t _hal_register_for_notification(int client_if,
 
 
        /* find characteristic */
-       gattc_char = _gattc_find_char_from_uuid(gattc_service, &char_id->uuid,
-                       HAL_GATT_CHARACTERISTIC_PROPERTY_NOTIFY);
+       gattc_char = _gattc_find_char_from_uuid_for_notify(gattc_service, &char_id->uuid);
        if (NULL == gattc_char) {
                DBG("Failed to get the gatt char");
                return BT_STATUS_FAIL;
@@ -2572,8 +2595,7 @@ static bt_status_t _hal_deregister_for_notification(int client_if,
 
 
        /* find characteristic */
-       gattc_char = _gattc_find_char_from_uuid(gattc_service, &char_id->uuid,
-                       HAL_GATT_CHARACTERISTIC_PROPERTY_NOTIFY);
+       gattc_char = _gattc_find_char_from_uuid_for_notify(gattc_service, &char_id->uuid);
        if (NULL == gattc_char) {
                DBG("Failed to get the gatt char");
                return BT_STATUS_FAIL;
@@ -3339,3 +3361,86 @@ static void _bt_hal_send_search_service_complete_event(int conn_id, int status)
 
        event_cb(HAL_EV_GATT_CLIENT_SEARCH_COMPLETE, (void *)&ev, sizeof(ev));
 }
+
+static void _bt_hal_send_value_changed_event(hal_gattc_server_info_t *conn_info,
+               hal_gattc_service_t *svc_info, hal_gattc_char_t *char_info,
+               char *char_value, int len)
+{
+       struct hal_ev_gatt_client_notify_changed_value ev;
+       hal_gattc_client_info_t *gattc_client = NULL;
+
+       if (!event_cb) {
+               ERR("gatt client callback not registered");
+               return;
+       }
+
+       gattc_client = __bt_find_gatt_client_info(&conn_info->bd_addr);
+       if (NULL == gattc_client) {
+               ERR("failed to get the gatt client info");
+               return ;
+       }
+
+       //send event
+       DBG("sending gatt client connected status  event");
+       memset(&ev, 0, sizeof(ev));
+
+       ev.conn_id = gattc_client->conn_id;
+       ev.inst_id = conn_info->inst_id;
+       ev.is_primary = svc_info->is_primary;
+       memcpy(ev.svc_uuid, svc_info->svc_uuid.uu, sizeof(ev.svc_uuid));
+       memcpy(ev.char_uuid, char_info->chr_uuid.uu, sizeof(ev.char_uuid));
+
+       memcpy(ev.bdaddr, conn_info->bd_addr.address, BT_HAL_ADDRESS_LENGTH_MAX);
+
+       if (len > 0 && (char_value != NULL)) {
+               memcpy(ev.value, char_value, len);
+               ev.len = len;
+       }
+
+       event_cb(HAL_EV_GATT_CLIENT_NOTIFY_CHANGED_VALUE, (void *)&ev, sizeof(ev));
+}
+
+void _bt_hal_handle_gattc_value_changed_event(int result, const char *char_handle,
+                                               char *char_value, int len)
+{
+       char device_address[BT_HAL_ADDRESS_STRING_SIZE] = { 0 };
+       hal_gattc_server_info_t *conn_info = NULL;
+       bt_bdaddr_t bd_addr;
+       GSList *l;
+       GSList *k;
+       hal_gattc_service_t *svc_info = NULL;
+       hal_gattc_char_t *char_info = NULL;
+
+       DBG("+");
+
+       _bt_hal_convert_device_path_to_address(char_handle, device_address);
+       device_address[BT_HAL_ADDRESS_STRING_SIZE - 1] = '\0';
+       DBG("device address:[%s]", device_address);
+       DBG("char handle:[%s]", char_handle);
+
+       _bt_hal_convert_addr_string_to_type(bd_addr.address, device_address);
+       conn_info =  __bt_find_gatt_conn_info(&bd_addr);
+
+       //find service for notified char path
+       for (l = conn_info->gatt_list_services; l != NULL; l = g_slist_next(l)) {
+               svc_info = (hal_gattc_service_t*)l->data;
+               if (svc_info == NULL)
+                       continue;
+
+               /* find characteristic object path */
+               for (k = svc_info->gatt_list_chars; k != NULL; k = g_slist_next(k)) {
+                       char_info = (hal_gattc_char_t *)k->data;
+                       if (char_info == NULL)
+                               continue;
+
+                       if (g_strcmp0(char_info->chr_path, char_handle) == 0) {
+                               DBG("Found char handle[%s]", char_info->chr_path);
+
+                               //send event
+                               _bt_hal_send_value_changed_event(conn_info, svc_info,
+                                               char_info, char_value, len);
+                               return;
+                       }
+               }
+       }
+}
index 82e85f0..a4e58b8 100644 (file)
@@ -39,6 +39,8 @@ void _bt_hal_register_gatt_client_handler_cb(handle_stack_msg cb);
 void _bt_hal_unregister_gatt_client_handler_cb(void);
 
 void _bt_hal_handle_gattc_connected_event(char* address, gboolean connected);
+void  _bt_hal_handle_gattc_value_changed_event(int result, const char *char_handle,
+               char *char_value, int len);
 
 #ifdef TIZEN_BT_HAL
 int _bt_hal_gatt_client_get_le_scan_type(void);
index 33378b8..dbeed8c 100644 (file)
@@ -84,6 +84,7 @@ static void __bt_handle_gatt_client_read_desc(void *buf, uint16_t len);
 static void __bt_handle_gatt_client_write_char(void *buf, uint16_t len);
 static void __bt_handle_gatt_client_write_desc(void *buf, uint16_t len);
 static void __bt_handle_gatt_client_watch_notification(void *buf, uint16_t len);
+static void __bt_handle_gatt_client_changed_value(void *buf, uint16_t len);
 /*****************************************************************************************************/
 
 static bool interface_ready(void)
@@ -399,6 +400,10 @@ static void __bt_hal_gatt_events(int message, void *buf, uint16_t len)
                __bt_handle_gatt_client_watch_notification(buf, len);
                break;
        }
+       case HAL_EV_GATT_CLIENT_NOTIFY_CHANGED_VALUE: {
+               __bt_handle_gatt_client_changed_value(buf, len);
+               break;
+       }
        case HAL_EV_GATT_SERVER_ACQUIRE_WRITE_RES:{
                __bt_hal_handle_gatt_server_acquire_write_requested(buf, len);
                break;
@@ -631,6 +636,29 @@ static void __bt_handle_gatt_client_watch_notification(void *buf, uint16_t len)
                                ev->registered, ev->status, &gatt_srvc_id, &gatt_char_id);
 }
 
+static void __bt_handle_gatt_client_changed_value(void *buf, uint16_t len)
+{
+       struct hal_ev_gatt_client_notify_changed_value *ev = buf;
+       btgatt_notify_params_t changd_value_parm;
+
+       changd_value_parm.srvc_id.is_primary = ev->is_primary;
+       changd_value_parm.srvc_id.id.inst_id = ev->inst_id;
+       memcpy(changd_value_parm.srvc_id.id.uuid.uu, ev->svc_uuid, 16);
+
+       changd_value_parm.char_id.inst_id = ev->inst_id;
+       memcpy(changd_value_parm.char_id.uuid.uu, ev->char_uuid, 16);
+       changd_value_parm.is_notify = ev->is_notify;
+
+       memcpy(changd_value_parm.bda.address, ev->bdaddr, 6);
+
+       changd_value_parm.len = ev->len;
+       if (ev->len > 0)
+               memcpy(changd_value_parm.value, ev->value, ev->len);
+
+       if (bt_gatt_callbacks->client->notify_cb)
+               bt_gatt_callbacks->client->notify_cb(ev->conn_id, &changd_value_parm);
+}
+
 static bt_hal_le_adv_info_t *__bt_hal_get_adv_ind_info(char *addr)
 {
        GSList *l;
index 3629b35..80c6fc9 100644 (file)
@@ -50,6 +50,7 @@ typedef enum {
        BT_HAL_AVRCP_CONTROL_EVENT,
        BT_HAL_A2DP_SOURCE_EVENT,
        BT_HAL_HID_DEVICE_EVENT,
+       BT_HAL_GATT_EVENT,
        /* Will be added */
 } bt_hal_event_type_t;
 
index a484750..1639420 100644 (file)
@@ -464,6 +464,15 @@ typedef struct {
 #define BLE_READ_NOTIFY_DATA_LENGTH     600
 
 typedef struct {
+       int is_notify;
+       uint16_t data_len;
+       uint8_t data[BLE_READ_NOTIFY_DATA_LENGTH];
+       bt_address_t address;
+       oal_gatt_id_t char_id;
+       oal_gatt_srvc_id_t srvc_id;
+} event_gattc_notify_data;
+
+typedef struct {
        uint16_t value_type;
        uint16_t data_len;
        uint8_t data[BLE_READ_NOTIFY_DATA_LENGTH];
index f80599f..3731335 100644 (file)
@@ -212,6 +212,7 @@ static void cb_gattc_write_characteristic(int conn_id, int status, btgatt_write_
 static void cb_gattc_write_descriptor(int conn_id, int status, btgatt_write_params_t *p_data);
 static void cb_gattc_register_for_notification(int conn_id, int registered, int status,
                        btgatt_srvc_id_t *srvc_id, btgatt_gatt_id_t *char_id);
+static void cb_gattc_notify(int conn_id, btgatt_notify_params_t *p_data);
 
 /*TODO GATT CLient callbacks will be implemented in subsequent patches */
 static const btgatt_client_callbacks_t btgatt_client_callbacks = {
@@ -225,7 +226,7 @@ static const btgatt_client_callbacks_t btgatt_client_callbacks = {
        cb_gattc_get_descriptor, /*cb_gattc_get_descriptor*/
        NULL, /*cb_gattc_get_included_service*/
        cb_gattc_register_for_notification, /*cb_gattc_register_for_notification*/
-       NULL, /*cb_gattc_notify*/
+       cb_gattc_notify, /*cb_gattc_notify*/
        cb_gattc_read_characteristic, /*cb_gattc_read_characteristic*/
        cb_gattc_write_characteristic, /*cb_gattc_write_characteristic*/
        cb_gattc_read_descriptor, /*cb_gattc_read_descriptor*/
@@ -1535,6 +1536,47 @@ static void cb_gattc_register_for_notification(int client_if, int registered, in
        send_event(event_type, event, sizeof(*event));
 }
 
+static void cb_gattc_notify(int conn_id, btgatt_notify_params_t *p_data)
+{
+       bdstr_t bdstr;
+       char uuid_str1[2*BT_UUID_STRING_MAX];
+       char uuid_str2[2*BT_UUID_STRING_MAX];
+
+       BT_INFO("BTGATT Client Notify Callback, conn_id:%d", conn_id);
+       BT_INFO("Server Address:[%s], is_notify:[%d], len:[%d]",
+               bdt_bd2str((bt_address_t *)&(p_data->bda), &bdstr), p_data->is_notify, p_data->len);
+
+       uuid_to_stringname((oal_uuid_t *)&(p_data->srvc_id.id.uuid), uuid_str1);
+       uuid_to_stringname((oal_uuid_t *)&(p_data->char_id.uuid), uuid_str2);
+
+       BT_INFO("Service=> UUID: [%s], Inst_id: [%u], Type: [%s]",
+               uuid_str1, p_data->srvc_id.id.inst_id, p_data->srvc_id.is_primary ? "Primary" : "Secondary");
+       BT_INFO("Charac=> UUID: [%s], Inst_id: [%u]", uuid_str2, p_data->char_id.inst_id);
+
+       if (p_data->len > 0) {
+               char *data = NULL;
+               data = g_malloc(3*p_data->len+1);
+               if (!data) {
+                       BT_ERR("memory allocation failed");
+                       return;
+               }
+
+               convert_hex_2_str((unsigned char *)p_data->value, p_data->len, data);
+               BT_INFO("Notified Data: [%s]", data);
+
+               event_gattc_notify_data *event = g_new0(event_gattc_notify_data, 1);
+               memcpy(event->address.addr, p_data->bda.address, BT_ADDRESS_BYTES_NUM);
+               event->is_notify = p_data->is_notify;
+               event->data_len = p_data->len;
+               memcpy(event->data, p_data->value, event->data_len);
+               memcpy(&(event->char_id), &(p_data->char_id), sizeof(oal_gatt_id_t));
+               memcpy(&(event->srvc_id), &(p_data->srvc_id), sizeof(oal_gatt_srvc_id_t));
+
+               send_event_bda_trace(OAL_EVENT_GATTC_NOTIFY_DATA, event, sizeof(*event), (bt_address_t *)&p_data->bda);
+               g_free(data);
+       }
+}
+
 
 static void cb_gattc_read_characteristic(int conn_id, int status, btgatt_read_params_t *p_data)
 {
index 4448648..8e5db8e 100644 (file)
@@ -255,6 +255,7 @@ static int __bt_do_unregister_gatt_instance(int instance_id);
 static void __bt_hanlde_le_device_disconnection(event_dev_conn_status_t *event_data);
 static void __bt_handle_client_notification_registered(event_gattc_regdereg_notify_t *event_data,
                gboolean is_registered);
+static void __bt_handle_client_notification_data(event_gattc_notify_data *event_data);
 
 #endif
 
@@ -2118,6 +2119,11 @@ static void __bt_gatt_event_handler(int event_type, gpointer event_data)
                __bt_handle_client_notification_registered((event_gattc_regdereg_notify_t *) event_data, FALSE);
                break;
        }
+       case OAL_EVENT_GATTC_NOTIFY_DATA: {
+               BT_INFO("OAL Event: GATT Client Notification Data");
+               __bt_handle_client_notification_data((event_gattc_notify_data *) event_data);
+
+       }
 #endif
        default:
                break;
@@ -3906,6 +3912,91 @@ static void __bt_handle_client_notification_registered(
                        sizeof(bt_gatt_notif_reg_info_t));
 }
 
+static void __bt_handle_client_notification_data(event_gattc_notify_data *event_data)
+{
+       /* No status in this event from OAL */
+       int result = BLUETOOTH_ERROR_NONE;
+
+       /* Read Information data structures */
+       GVariant *param = NULL;
+       GVariant *data = NULL;
+       GVariant *data_svc_uuid = NULL;
+       GVariant *data_char_uuid = NULL;
+       char *read_val = NULL;
+       char *svc_uuid = NULL;
+       char *char_uuid = NULL;
+       char *addr = NULL;
+       int i;
+       int uuid_len = 16;
+       BT_INFO("+");
+
+       BT_INFO("Notifcation of charc data changed");
+
+       if (event_data->data_len > 0) {
+               /* DEBUG */
+               for (i = 0; i < event_data->data_len; i++)
+                       BT_INFO("Data[%d] = [0x%x]", i, event_data->data[i]);
+
+               /* Fill address */
+               addr = g_malloc0(BT_ADDRESS_STRING_SIZE);
+               _bt_convert_addr_type_to_string(addr,
+                               (unsigned char *)&(event_data->address.addr));
+
+               /* Read data */
+               read_val = g_memdup(&event_data->data[0], event_data->data_len);
+
+               data = g_variant_new_from_data(
+                               G_VARIANT_TYPE_BYTESTRING,
+                               read_val,
+                               event_data->data_len,
+                               TRUE, NULL, NULL);
+               /* SVC uuid */
+               svc_uuid = g_memdup(&event_data->srvc_id.id.uuid.uuid[0], uuid_len);
+
+               data_svc_uuid = g_variant_new_from_data(
+                               G_VARIANT_TYPE_BYTESTRING,
+                               svc_uuid,
+                               uuid_len,
+                               TRUE, NULL, NULL);
+
+               /* Char uuid */
+               char_uuid = g_memdup(&event_data->char_id.uuid.uuid[0], uuid_len);
+
+               data_char_uuid = g_variant_new_from_data(
+                               G_VARIANT_TYPE_BYTESTRING,
+                               char_uuid,
+                               uuid_len,
+                               TRUE, NULL, NULL);
+
+               /* Build Param */
+               param = g_variant_new("(isn@ayin@ayin@ay)", result,
+                               addr,
+                               16,
+                               data_svc_uuid,
+                               event_data->srvc_id.id.inst_id,
+                               16,
+                               data_char_uuid,
+                               event_data->char_id.inst_id,
+                               event_data->data_len,
+                               data);
+
+               /* Send Event */
+               _bt_send_event(BT_GATT_CLIENT_EVENT,
+                               BLUETOOTH_EVENT_GATT_CHAR_VAL_CHANGED,
+                               param);
+       } else {
+               BT_ERR("No Data!!");
+       }
+       /* Free data */
+       if (read_val)
+               g_free(read_val);
+       if (svc_uuid)
+               g_free(svc_uuid);
+       if (char_uuid)
+               g_free(char_uuid);
+       if (addr)
+               g_free(addr);
+}
 
 gboolean _bt_is_remote_gatt_device_connected(bluetooth_device_address_t *address)
 {