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]);
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;
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_
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;
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;
} 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);
}
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("+");
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;
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) {
typedef struct {
gchar *svc_path;
bt_uuid_t svc_uuid;
+ int is_primary;
GSList *gatt_list_chars;
} hal_gattc_service_t;
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("+");
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;
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));
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;
/* 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;
/* 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;
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;
+ }
+ }
+ }
+}
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);
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)
__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;
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;
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;
#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];
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 = {
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*/
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)
{
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
__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;
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)
{