diff options
-rw-r--r-- | include/bluetooth_internal.h | 37 | ||||
-rw-r--r-- | include/bluetooth_private.h | 19 | ||||
-rw-r--r-- | include/bluetooth_type_internal.h | 16 | ||||
-rw-r--r-- | src/bluetooth-common.c | 36 | ||||
-rw-r--r-- | src/bluetooth-otp.c | 581 | ||||
-rw-r--r-- | test/bt_unit_test.c | 70 | ||||
-rw-r--r-- | test/bt_unit_test.h | 6 |
7 files changed, 762 insertions, 3 deletions
diff --git a/include/bluetooth_internal.h b/include/bluetooth_internal.h index a7c7027..99d7ec8 100644 --- a/include/bluetooth_internal.h +++ b/include/bluetooth_internal.h @@ -4053,6 +4053,43 @@ int bt_otp_set_server_state_changed_cb(bt_otp_server_state_changed_cb callback, int bt_otp_unset_server_state_changed_cb(void); /** + * @internal + * @brief OTP Client Profile API to create Client Role associated with Remote OTP Server + */ +int bt_otp_client_create(const char *remote_address, bt_otp_client_h *otp_client); + +/** + * @internal + * @brief OTP Client Profile API to destroy Client Role associated with Remote OTP Server + */ +int bt_otp_client_destroy(bt_otp_client_h otp_client); + +/** + * @internal + * @brief OTP Client Profile API to set connection state changed event associated with Remote OTP Server + */ +int bt_otp_client_set_connection_state_changed_cb(bt_otp_client_h otp_client, + bt_otp_client_state_changed_cb callback, void *user_data); + +/** + * @internal + * @brief OTP Client Profile API to unset connection state changed event associated with Remote OTP Server + */ +int bt_otp_client_unset_connection_state_changed_cb(bt_otp_client_h otp_client); + +/** + * @internal + * @brief OTP client API to connect to Remote OTP Server + */ +int bt_otp_client_connect(bt_otp_client_h otp_client); + +/** + * @internal + * @brief OTP client API to disconnect to Remote OTP Server + */ +int bt_otp_client_disconnect(bt_otp_client_h otp_client); + +/** * @} */ diff --git a/include/bluetooth_private.h b/include/bluetooth_private.h index 193e0f1..b8ad8ad 100644 --- a/include/bluetooth_private.h +++ b/include/bluetooth_private.h @@ -864,6 +864,25 @@ void _bt_tds_control_point_indication_response_update(const char *address, bluet */ void _bt_tds_check_service_changed(char *address, bt_gatt_service_change_t *service_change); +/** + * @internal + * @brief Send GATT connection state changed status with remote OTP Server. + */ +void _bt_otp_client_connection_state_changed(int result, const char *remote_address, bool connected); + +/** + * @internal + * @brief Send GATT Read Response status got from remote OTP Server. + */ +void _bt_otp_client_read_value_response(int result, char *char_path, + char *char_value, int val_len); + +/** + * @internal + * @brief Send GATT Notification Enabled Response status got from remote OTP Server. + */ +void _bt_otp_client_notification_enabled(int result, char *handle); + typedef enum { _PROFILE_UNKNOWN = 0, _PROFILE_MOBILE = 0x1, diff --git a/include/bluetooth_type_internal.h b/include/bluetooth_type_internal.h index 67770e1..c7d83a1 100644 --- a/include/bluetooth_type_internal.h +++ b/include/bluetooth_type_internal.h @@ -917,6 +917,22 @@ typedef void (*bt_tds_control_point_activation_indication_cb) */ typedef void (*bt_otp_server_state_changed_cb)(int result, bool connected); + +/** + * @ingroup CAPI_NETWORK_BLUETOOTH_ADAPTER_LE_MODULE + * @brief The handle of a OTP client which is associated with a remote OTP Server + * @since_tizen 3.0 + */ +typedef void *bt_otp_client_h; + +/** + * @internal + * @since_tizen 3.0 + * @brief OTP Client profile Connection State changed callback which is associated with a remote OTP Server + */ +typedef void (*bt_otp_client_state_changed_cb) + (int result, const char *remote_address, bt_otp_client_h otp_client, bool connected, void *user_data); + /** * @} */ diff --git a/src/bluetooth-common.c b/src/bluetooth-common.c index 08e4a0f..5e3c5c1 100644 --- a/src/bluetooth-common.c +++ b/src/bluetooth-common.c @@ -1053,6 +1053,8 @@ static bool __bt_need_to_handle(int event) case BLUETOOTH_EVENT_TDS_ACTIVATION_RESULT: case BLUETOOTH_EVENT_TDS_CONTROL_POINT_ENABLED: case BLUETOOTH_EVENT_TDS_ACTIVATION_INDICATION: + case BLUETOOTH_EVENT_OTP_READ_CHAR_VAL: + case BLUETOOTH_EVENT_OTP_NOTIFICATION_ENABLED: return true; default: break; @@ -1992,6 +1994,9 @@ static void __bt_event_proxy(int event, bluetooth_event_param_t *param, void *us /* TDS Seeker */ _bt_tds_update_seeker_connection_state_changed(param->result, device_addr, TRUE); + /* OTP Client */ + _bt_otp_client_connection_state_changed(param->result, device_addr, TRUE); + g_free(device_addr); device_addr = NULL; break; @@ -2019,6 +2024,9 @@ static void __bt_event_proxy(int event, bluetooth_event_param_t *param, void *us /* TDS Seeker */ _bt_tds_update_seeker_connection_state_changed(param->result, device_addr, FALSE); + /* OTP Client */ + _bt_otp_client_connection_state_changed(param->result, device_addr, FALSE); + g_free(device_addr); device_addr = NULL; break; @@ -2918,7 +2926,8 @@ static void __bt_event_proxy(int event, bluetooth_event_param_t *param, void *us if (device_addr != NULL) free(device_addr); /* LCOV_EXCL_STOP */ break; - } case BLUETOOTH_EVENT_OTP_SERVER_STATE_CHANGED: { + } + case BLUETOOTH_EVENT_OTP_SERVER_STATE_CHANGED: { bt_otp_server_state_changed_cb cb = bt_event_slot_container[event_index].callback; bool *status = (bool *)(param->param_data); @@ -2927,6 +2936,31 @@ static void __bt_event_proxy(int event, bluetooth_event_param_t *param, void *us cb(_bt_get_error_code(param->result), *status ? true : false); break; } + case BLUETOOTH_EVENT_OTP_READ_CHAR_VAL: { + BT_DBG("BLUETOOTH_EVENT_OTP_READ_CHAR_VAL"); /* LCOV_EXCL_LINE */ + bluetooth_otp_resp_info_t *info = NULL; + char *handle = NULL; + + if (_bt_get_error_code(param->result) == BT_ERROR_NONE) { + info = (bluetooth_otp_resp_info_t *)(param->param_data); + BT_ERR("Read Success Handle [%s]", info->handle); + _bt_otp_client_read_value_response(_bt_get_error_code(param->result), + info->handle, info->data, info->data_length); + } else { + handle = (char *)(param->param_data); + BT_ERR("Read Fail Handle [%s]", handle); + _bt_otp_client_read_value_response(_bt_get_error_code(param->result), + handle, NULL, 0); + } + break; + } + case BLUETOOTH_EVENT_OTP_NOTIFICATION_ENABLED: { + BT_DBG("BLUETOOTH_EVENT_OTP_NOTIFICATION_ENABLED"); /* LCOV_EXCL_LINE */ + char *handle = (char *)(param->param_data); + BT_ERR("Handle [%s]", handle); + _bt_otp_client_notification_enabled(_bt_get_error_code(param->result), handle); + break; + } default: BT_INFO("Unknown function"); break; diff --git a/src/bluetooth-otp.c b/src/bluetooth-otp.c index 464c5a5..4da35f3 100644 --- a/src/bluetooth-otp.c +++ b/src/bluetooth-otp.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved * * Licensed under the Apache License, Version 2.0 (the License); * you may not use this file except in compliance with the License. @@ -49,6 +49,53 @@ return BT_ERROR_NOT_INITIALIZED; \ } +#define BT_OTP_SERVICE_UUID "00001825-0000-1000-8000-00805f9b34fb" +#define BT_OTP_FEATURE_UUID "00002abd-0000-1000-8000-00805f9b34fb" +#define BT_OTP_OACP_CONTROL_POINT_UUID "00002ac5-0000-1000-8000-00805f9b34fb" +#define BT_OTP_OLCP_CONTROL_POINT_UUID "00002ac6-0000-1000-8000-00805f9b34fb" +#define BT_OTP_OBJECT_NAME_UUID "00002abe-0000-1000-8000-00805f9b34fb" +#define BT_OTP_OBJECT_TYPE_UUID "00002abf-0000-1000-8000-00805f9b34fb" +#define BT_OTP_OBJECT_SIZE_UUID "00002ac0-0000-1000-8000-00805f9b34fb" +#define BT_OTP_OBJECT_FIRST_CREATED_UUID "00002ac1-0000-1000-8000-00805f9b34fb" +#define BT_OTP_OBJECT_LAST_MODIFIED_UUID "00002ac2-0000-1000-8000-00805f9b34fb" +#define BT_OTP_OBJECT_ID_UUID "00002ac3-0000-1000-8000-00805f9b34fb" +#define BT_OTP_OBJECT_PROP_UUID "00002ac4-0000-1000-8000-00805f9b34fb" + +#define BT_ADDR_LENGTH 18 +#define BT_OTP_FEATURE_LENGTH 8 + +#define IS_OACP_SUPPORTED(feature) feature & 0xffffffff00000000 +#define IS_OLCP_SUPPORTED(feature) feature & 0x00000000ffffffff + +typedef struct { + char *remote_address; + bool connected; + + const void *connection_callback; + void *conn_cb_user_data; + + char *otp_service_handle; /* OTP Service Handle */ + char *otp_feature_obj_path; /* OTP feature characteristic handle */ + uint64_t otp_feature; /* OTP feature value */ + char *otp_oacp_control_point; /* OTP OACP Control Point characteristic handle */ + char *otp_oacp_cccd; /* OTP OACP Control Point CCCD handle */ + char *otp_olcp_control_point; /* OTP OLCP Control Point characteristic handle */ + char *otp_olcp_cccd; /* OTP OLCP Control Point CCCD handle */ + + /* Object Metadata paths */ + char *otp_name_obj_path; /* OTP Object Name characteristic handle */ + char *otp_type_obj_path; /* OTP Object Type characteristic handle */ + char *otp_size_obj_path; /* OTP Object Size characteristic handle */ + char *otp_first_created_obj_path; /* OTP Object Frist Created characteristic handle */ + char *otp_last_modified_obj_path; /* OTP Object Last Modified characteristic handle */ + char *otp_id_obj_path; /* OTP Object ID characteristic handle */ + char *otp_props_obj_path; /* OTP Object Properties characteristic handle */ + + bool oacp_cccd_enabled; /* OTP OACP Control Point CCCD is enabled or not */ + bool olcp_cccd_enabled; /* OTP OLCP Control Point CCCD is enabled or not */ +} bt_otp_client_s; + +GSList *otp_client_list; static bool is_otp_server_initialized = false; int __bt_check_otp_server_init_status(void) @@ -119,4 +166,534 @@ int bt_otp_unset_server_state_changed_cb(void) if (_bt_check_cb(BT_EVENT_OTP_SERVER_STATE_CHANGED) == true) _bt_unset_cb(BT_EVENT_OTP_SERVER_STATE_CHANGED); return BT_ERROR_NONE; -}
\ No newline at end of file +} + +static bt_otp_client_s *_bt_otp_client_find(const char *remote_address) +{ + GSList *l; + + for (l = otp_client_list; l; l = g_slist_next(l)) { + + if (!g_ascii_strcasecmp(((bt_otp_client_s *)l->data)->remote_address, remote_address)) + return ((bt_otp_client_s *)l->data); + } + return NULL; +} + +char *free_object_path(char *path) +{ + if (path) + g_free(path); + return NULL; +} + +static void __bt_otp_client_reset_server_data(bt_otp_client_s *otp_client_s) +{ + otp_client_s->otp_service_handle = + free_object_path(otp_client_s->otp_service_handle); + otp_client_s->otp_feature_obj_path = + free_object_path(otp_client_s->otp_feature_obj_path); + otp_client_s->otp_oacp_control_point = + free_object_path(otp_client_s->otp_oacp_control_point); + otp_client_s->otp_oacp_cccd = + free_object_path(otp_client_s->otp_oacp_cccd); + otp_client_s->otp_olcp_control_point = + free_object_path(otp_client_s->otp_olcp_control_point); + otp_client_s->otp_olcp_cccd = + free_object_path(otp_client_s->otp_olcp_cccd); + otp_client_s->otp_name_obj_path = + free_object_path(otp_client_s->otp_name_obj_path); + otp_client_s->otp_type_obj_path = + free_object_path(otp_client_s->otp_type_obj_path); + otp_client_s->otp_size_obj_path = + free_object_path(otp_client_s->otp_size_obj_path); + otp_client_s->otp_first_created_obj_path = + free_object_path(otp_client_s->otp_first_created_obj_path); + otp_client_s->otp_last_modified_obj_path = + free_object_path(otp_client_s->otp_last_modified_obj_path); + otp_client_s->otp_id_obj_path = + free_object_path(otp_client_s->otp_id_obj_path); + otp_client_s->otp_props_obj_path = + free_object_path(otp_client_s->otp_props_obj_path); + + /* Reset CCCD */ + otp_client_s->oacp_cccd_enabled = FALSE; + otp_client_s->olcp_cccd_enabled = FALSE; +} + +int bt_otp_client_set_connection_state_changed_cb(bt_otp_client_h otp_client, + bt_otp_client_state_changed_cb callback, void *user_data) +{ + bt_otp_client_s *otp_client_s = (bt_otp_client_s *)otp_client; + + BT_CHECK_LE_SUPPORT(); + BT_CHECK_INIT_STATUS(); + BT_CHECK_INPUT_PARAMETER(otp_client_s); + BT_CHECK_INPUT_PARAMETER(callback); + + if (_bt_otp_client_find(otp_client_s->remote_address) == NULL) + return BT_ERROR_NOT_INITIALIZED; + + BT_DBG("Set OTP Client Connection State changed callback"); + /* register the callback */ + otp_client_s->connection_callback = callback; + otp_client_s->conn_cb_user_data = user_data; + + return BT_ERROR_NONE; +} + +int bt_otp_client_unset_connection_state_changed_cb(bt_otp_client_h otp_client) +{ + bt_otp_client_s *otp_client_s = (bt_otp_client_s *)otp_client; + + BT_CHECK_LE_SUPPORT(); + BT_CHECK_INIT_STATUS(); + BT_CHECK_INPUT_PARAMETER(otp_client_s); + + if (_bt_otp_client_find(otp_client_s->remote_address) == NULL) + return BT_ERROR_NOT_INITIALIZED; + + BT_DBG("UnSet OTP Client Connection State changed callback"); + /* unregister the callback */ + otp_client_s->connection_callback = NULL; + otp_client_s->conn_cb_user_data = NULL; + + return BT_ERROR_NONE; +} + +static int __bt_update_otp_server_data(bluetooth_device_address_t *address, bt_otp_client_s *otp_client_s) +{ + int ret = BLUETOOTH_ERROR_INTERNAL; + bt_gatt_service_property_t service; + int count; + + ret = bluetooth_gatt_get_service_from_uuid(address, BT_OTP_SERVICE_UUID, &service); + if (ret != BLUETOOTH_ERROR_NONE) { + BT_ERR("Failed to find OTP service on the remote device [%s]", address); + return ret; + } + + /* Discover all charc & desc of OTP service */ + for (count = 0; count < service.char_handle.count; count++) { + bt_gatt_char_property_t characteristic; + memset(&characteristic, 0x00, sizeof(characteristic)); + + BT_DBG("Get properties for Char [%s]", service.char_handle.handle[count]); + + ret = bluetooth_gatt_get_characteristics_property(service.char_handle.handle[count], + &characteristic); + + if (ret != BLUETOOTH_ERROR_NONE) { + BT_ERR("Get characteristic property failed(0x%08x)", ret); + bluetooth_gatt_free_service_property(&service); + bluetooth_gatt_free_char_property(&characteristic); + goto fail; + } else { + if (g_strstr_len(characteristic.uuid, -1, BT_OTP_FEATURE_UUID)) { + BT_DBG("OTP feature characteristic discovered"); + + if (otp_client_s->otp_feature_obj_path) + g_free(otp_client_s->otp_feature_obj_path); + otp_client_s->otp_feature_obj_path = g_strdup(characteristic.handle); + + ret = _bt_get_error_code(bluetooth_otp_read_characteristic_value(otp_client_s->otp_feature_obj_path)); + if (ret != BT_ERROR_NONE) + BT_ERR("Failed to read OTP Feature : %s(0x%08x)", _bt_convert_error_to_string(ret), ret); + + BT_DBG("OTP feature handle [%s]", otp_client_s->otp_feature_obj_path); + } else if (g_strstr_len(characteristic.uuid, -1, BT_OTP_OACP_CONTROL_POINT_UUID)) { + BT_DBG("OTP OACP Control Point discovered"); + bt_gatt_char_descriptor_property_t desc_property; + memset(&desc_property, 0x00, sizeof(desc_property)); + + /* Get CCCD for Control Point */ + ret = bluetooth_gatt_get_char_descriptor_property( + characteristic.char_desc_handle.handle[0], &desc_property); + + if (ret != BLUETOOTH_ERROR_NONE) { + BT_ERR("Failed to discover CCCD for OACP Control point"); + bluetooth_gatt_free_service_property(&service); + bluetooth_gatt_free_char_property(&characteristic); + bluetooth_gatt_free_desc_property(&desc_property); + goto fail; + } + if (otp_client_s->otp_oacp_control_point) + g_free(otp_client_s->otp_oacp_control_point); + otp_client_s->otp_oacp_control_point = g_strdup(characteristic.handle); + + if (otp_client_s->otp_oacp_cccd) + g_free(otp_client_s->otp_oacp_cccd); + otp_client_s->otp_oacp_cccd = g_strdup(desc_property.handle); + + BT_DBG("OACP Control point handle [%s]", otp_client_s->otp_oacp_control_point); + BT_DBG("OACP Control point CCCD handle [%s]", otp_client_s->otp_oacp_cccd); + } else if (g_strstr_len(characteristic.uuid, -1, BT_OTP_OLCP_CONTROL_POINT_UUID)) { + BT_DBG("OTP OLCP Control Point discovered"); + bt_gatt_char_descriptor_property_t desc_property; + memset(&desc_property, 0x00, sizeof(desc_property)); + + /* Get CCCD for Control Point */ + ret = bluetooth_gatt_get_char_descriptor_property( + characteristic.char_desc_handle.handle[0], &desc_property); + + if (ret != BLUETOOTH_ERROR_NONE) { + BT_ERR("Failed to discover CCCD for OLCP Control point"); + bluetooth_gatt_free_service_property(&service); + bluetooth_gatt_free_char_property(&characteristic); + bluetooth_gatt_free_desc_property(&desc_property); + goto fail; + } + if (otp_client_s->otp_olcp_control_point) + g_free(otp_client_s->otp_olcp_control_point); + otp_client_s->otp_olcp_control_point = g_strdup(characteristic.handle); + + if (otp_client_s->otp_olcp_cccd) + g_free(otp_client_s->otp_olcp_cccd); + otp_client_s->otp_olcp_cccd = g_strdup(desc_property.handle); + + BT_DBG("OLCP Control point handle [%s]", otp_client_s->otp_olcp_control_point); + BT_DBG("OLCP Control point CCCD handle [%s]", otp_client_s->otp_olcp_cccd); + } else if (g_strstr_len(characteristic.uuid, -1, BT_OTP_OBJECT_NAME_UUID)) { + BT_DBG("OTP Object Name characteristic discovered"); + + if (otp_client_s->otp_name_obj_path) + g_free(otp_client_s->otp_name_obj_path); + otp_client_s->otp_name_obj_path = g_strdup(characteristic.handle); + + BT_DBG("OTP Object Name handle [%s]", otp_client_s->otp_name_obj_path); + } else if (g_strstr_len(characteristic.uuid, -1, BT_OTP_OBJECT_TYPE_UUID)) { + BT_DBG("OTP Object Type characteristic discovered"); + + if (otp_client_s->otp_type_obj_path) + g_free(otp_client_s->otp_type_obj_path); + otp_client_s->otp_type_obj_path = g_strdup(characteristic.handle); + + BT_DBG("OTP Object Type handle [%s]", otp_client_s->otp_type_obj_path); + } else if (g_strstr_len(characteristic.uuid, -1, BT_OTP_OBJECT_SIZE_UUID)) { + BT_DBG("OTP Object Size characteristic discovered"); + + if (otp_client_s->otp_size_obj_path) + g_free(otp_client_s->otp_size_obj_path); + otp_client_s->otp_size_obj_path = g_strdup(characteristic.handle); + + BT_DBG("OTP Object Size handle [%s]", otp_client_s->otp_size_obj_path); + } else if (g_strstr_len(characteristic.uuid, -1, BT_OTP_OBJECT_FIRST_CREATED_UUID)) { + BT_DBG("OTP Object First Created characteristic discovered"); + + if (otp_client_s->otp_first_created_obj_path) + g_free(otp_client_s->otp_first_created_obj_path); + otp_client_s->otp_first_created_obj_path = g_strdup(characteristic.handle); + + BT_DBG("OTP Object First Created handle [%s]", otp_client_s->otp_first_created_obj_path); + } else if (g_strstr_len(characteristic.uuid, -1, BT_OTP_OBJECT_LAST_MODIFIED_UUID)) { + BT_DBG("OTP Object Last Modified characteristic discovered"); + + if (otp_client_s->otp_last_modified_obj_path) + g_free(otp_client_s->otp_last_modified_obj_path); + otp_client_s->otp_last_modified_obj_path = g_strdup(characteristic.handle); + + BT_DBG("OTP Object Last Modified handle [%s]", otp_client_s->otp_last_modified_obj_path); + } else if (g_strstr_len(characteristic.uuid, -1, BT_OTP_OBJECT_ID_UUID)) { + BT_DBG("OTP Object ID characteristic discovered"); + + if (otp_client_s->otp_id_obj_path) + g_free(otp_client_s->otp_id_obj_path); + otp_client_s->otp_id_obj_path = g_strdup(characteristic.handle); + + BT_DBG("OTP Object ID handle [%s]", otp_client_s->otp_id_obj_path); + } else if (g_strstr_len(characteristic.uuid, -1, BT_OTP_OBJECT_PROP_UUID)) { + BT_DBG("OTP Object Properties characteristic discovered"); + + if (otp_client_s->otp_props_obj_path) + g_free(otp_client_s->otp_props_obj_path); + otp_client_s->otp_props_obj_path = g_strdup(characteristic.handle); + + BT_DBG("OTP Object Properties handle [%s]", otp_client_s->otp_props_obj_path); + } else { + BT_DBG("Other OTP Characteristic handle [%s]", g_strdup(characteristic.handle)); + BT_DBG("UUID [%s]", g_strdup(characteristic.uuid)); + } /* Control Point characteristic */ + } /* Characteristic property get successful */ + bluetooth_gatt_free_char_property(&characteristic); + } /* Next Charatceristic */ + + if (otp_client_s->otp_service_handle) + g_free(otp_client_s->otp_service_handle); + + otp_client_s->otp_service_handle = g_strdup(service.handle); + bluetooth_gatt_free_service_property(&service); + return ret; +fail: + __bt_otp_client_reset_server_data(otp_client_s); + return ret; +} + +void _bt_otp_client_connection_state_changed(int result, + const char *remote_address, bool connected) +{ + bt_otp_client_s *otp_client_s = NULL; + BT_DBG("OTP Client Connection state changed result [%d] connected [%d]", result, connected ? TRUE : FALSE); + + otp_client_s = _bt_otp_client_find(remote_address); + if (otp_client_s) { + BT_DBG("OTP Client found against address [%s]", remote_address); + + bluetooth_device_address_t addr_hex = { {0,} }; + _bt_convert_address_to_hex(&addr_hex, remote_address); + + if (result != BT_ERROR_NONE) { + BT_ERR("GATT Connect Request failed Address [%s]", remote_address); + __bt_otp_client_reset_server_data(otp_client_s); + + if (otp_client_s->connection_callback) + ((bt_otp_client_state_changed_cb)otp_client_s->connection_callback) + (result, remote_address, otp_client_s, connected, otp_client_s->conn_cb_user_data); + return; + } + /* Update OTP Service values */ + if (connected) { + int error_code = BLUETOOTH_ERROR_NONE; + BT_DBG("Remote device connected successfully"); + /* Attempt to update OTP Service data */ + error_code = __bt_update_otp_server_data(&addr_hex, otp_client_s); + if (error_code != BLUETOOTH_ERROR_NONE) + BT_ERR("%s(0x%08x)", _bt_convert_error_to_string(error_code), error_code); + } else { + BT_DBG("Remote device disconnected successfully"); + /* Disconnected */ + __bt_otp_client_reset_server_data(otp_client_s); + } + otp_client_s->connected = connected; + + if (otp_client_s->connection_callback) + ((bt_otp_client_state_changed_cb)otp_client_s->connection_callback) + (result, remote_address, otp_client_s, connected, otp_client_s->conn_cb_user_data); + } else { + BT_DBG("OTP client not found!"); + } +} + +int bt_otp_client_create(const char *remote_address, bt_otp_client_h *otp_client) +{ + int error_code = BT_ERROR_NONE; + bt_otp_client_s *otp_client_s = NULL; + bool connected = false; + bluetooth_device_address_t addr_hex = { {0,} }; + GSList *l; + BT_INFO("+"); + + BT_CHECK_LE_SUPPORT(); + BT_CHECK_INIT_STATUS(); + BT_CHECK_INPUT_PARAMETER(remote_address); + BT_CHECK_INPUT_PARAMETER(otp_client); + + for (l = otp_client_list; l; l = g_slist_next(l)) { + bt_otp_client_s *c = (bt_otp_client_s *)l->data; + + if (!g_ascii_strcasecmp(c->remote_address, remote_address)) { + BT_ERR("OTP Client for Remote device [%s] is already created", + remote_address); + *otp_client = (bt_otp_client_h)c; + return BT_ERROR_ALREADY_DONE; + } + } + + otp_client_s = g_malloc0(sizeof(*otp_client_s)); + if (otp_client_s == NULL) { + error_code = BT_ERROR_OUT_OF_MEMORY; + BT_ERR("%s(0x%08x)", _bt_convert_error_to_string(error_code), error_code); + return error_code; + } + + if (bt_device_is_profile_connected(remote_address, BT_PROFILE_GATT, + &connected) != BT_ERROR_NONE) + BT_ERR("bt_device_is_profile_connected is failed"); + otp_client_s->connected = connected; + + _bt_convert_address_to_hex(&addr_hex, remote_address); + + if (otp_client_s->connected == true) { + /* Update all serv & charc */ + error_code = __bt_update_otp_server_data(&addr_hex, otp_client_s); + if (error_code != BLUETOOTH_ERROR_NONE) { + g_free(otp_client_s); + return BT_ERROR_OPERATION_FAILED; + } + } + + otp_client_s->remote_address = g_strdup(remote_address); + if (otp_client_s->remote_address == NULL) { + free(otp_client_s); + error_code = BT_ERROR_OUT_OF_MEMORY; + BT_ERR("%s(0x%08x)", _bt_convert_error_to_string(error_code), error_code); + return error_code; + } + + otp_client_s->olcp_cccd_enabled = FALSE; + otp_client_s->oacp_cccd_enabled = FALSE; + + otp_client_list = g_slist_append(otp_client_list, otp_client_s); + *otp_client = (bt_otp_client_h)otp_client_s; + + BT_DBG("OTP Client Created"); + return BT_ERROR_NONE; +} + +int bt_otp_client_destroy(bt_otp_client_h otp_client) +{ + bt_otp_client_s *otp_client_s = (bt_otp_client_s *)otp_client; + + BT_CHECK_LE_SUPPORT(); + BT_CHECK_INIT_STATUS(); + BT_CHECK_INPUT_PARAMETER(otp_client_s); + + if (_bt_otp_client_find(otp_client_s->remote_address) == NULL) + return BT_ERROR_NOT_INITIALIZED; + + BT_DBG("OTP client Remote device [%s]", otp_client_s->remote_address); + __bt_otp_client_reset_server_data(otp_client_s); + + otp_client_list = g_slist_remove(otp_client_list, otp_client_s); + g_free(otp_client_s); + otp_client_s = NULL; + + return BT_ERROR_NONE; +} + +int bt_otp_client_connect(bt_otp_client_h otp_client) +{ + int error_code; + bt_otp_client_s *otp_client_s = (bt_otp_client_s *)otp_client; + + BT_CHECK_LE_SUPPORT(); + BT_CHECK_INIT_STATUS(); + BT_CHECK_INPUT_PARAMETER(otp_client_s); + + if (_bt_otp_client_find(otp_client_s->remote_address) == NULL) + return BT_ERROR_NOT_INITIALIZED; + + if (otp_client_s->connected) + return BT_ERROR_NONE; + + BT_DBG("OTP client connect Remote device [%s]", otp_client_s->remote_address); + error_code = bt_gatt_connect(otp_client_s->remote_address, FALSE); + + if (error_code != BT_ERROR_NONE) + BT_ERR("%s(0x%08x)", _bt_convert_error_to_string(error_code), error_code); + + return error_code; +} + +int bt_otp_client_disconnect(bt_otp_client_h otp_client) +{ + int error_code; + bt_otp_client_s *otp_client_s = (bt_otp_client_s *)otp_client; + + BT_CHECK_LE_SUPPORT(); + BT_CHECK_INIT_STATUS(); + BT_CHECK_INPUT_PARAMETER(otp_client_s); + + if (_bt_otp_client_find(otp_client_s->remote_address) == NULL) + return BT_ERROR_NOT_INITIALIZED; + + if (otp_client_s->connected == false) { + BT_ERR("Remote device [%s] is not conencted", otp_client_s->remote_address); + return BT_ERROR_OPERATION_FAILED; + } + + BT_DBG("OTP client Disconnect Remote device [%s]", otp_client_s->remote_address); + error_code = bt_gatt_disconnect(otp_client_s->remote_address); + + if (error_code != BT_ERROR_NONE) + BT_ERR("%s(0x%08x)", _bt_convert_error_to_string(error_code), error_code); + + return error_code; +} + +void _bt_otp_get_remote_address(char *handle, char *remote_address) +{ + char *dev_path; + dev_path = strstr(handle, "dev_"); + dev_path += 4; + /* 18 -> Length of BT ADDR in path */ + g_strlcpy(remote_address, dev_path, BT_ADDR_LENGTH); + g_strdelimit(remote_address, "_", ':'); + BT_INFO("[%s] --> [%s]", handle, remote_address); +} + +void _bt_otp_client_read_value_response(int result, char *char_path, + char *value, int len) +{ + bt_otp_client_s *otp_client_s = NULL; + char remote_address[BT_ADDR_LENGTH]; + + _bt_otp_get_remote_address(char_path, remote_address); + + BT_DBG("OTP client Read Value Response [%d] [%s] [%s] [%d]", result, + char_path, value, len); + if (result != BLUETOOTH_ERROR_NONE) + BT_INFO("Read failed for [%s]", char_path); + + otp_client_s = _bt_otp_client_find(remote_address); + if (otp_client_s == NULL) + return; + + if (!g_strcmp0(otp_client_s->otp_feature_obj_path, char_path)) { + int error_code; + uint64_t feature = (uint64_t)(value[0] & 0xFF) << 56 | + (uint64_t)(value[1] & 0xFF) << 48 | + (uint64_t)(value[2] & 0xFF) << 40 | + (uint64_t)(value[3] & 0xFF) << 32 | + (uint64_t)(value[4] & 0xFF) << 24 | + (uint64_t)(value[5] & 0xFF) << 16 | + (uint64_t)(value[6] & 0xFF) << 8 | + (uint64_t)(value[7] & 0xFF); + otp_client_s->otp_feature = feature; + BT_INFO("OTP Feature [%lld]", feature); + + if (IS_OACP_SUPPORTED(otp_client_s->otp_feature) + && !otp_client_s->oacp_cccd_enabled) { + + error_code = bluetooth_otp_enable_notification(otp_client_s->otp_oacp_control_point); + if (error_code != BT_ERROR_NONE) + BT_ERR("OACP Notification enable failed %s(0x%08x)", _bt_convert_error_to_string(error_code), error_code); + } + + if (IS_OLCP_SUPPORTED(otp_client_s->otp_feature) + && !otp_client_s->olcp_cccd_enabled) { + error_code = bluetooth_otp_enable_notification(otp_client_s->otp_olcp_control_point); + if (error_code != BT_ERROR_NONE) + BT_ERR("OLCP Notification enable failed %s(0x%08x)", _bt_convert_error_to_string(error_code), error_code); + } + } else { + /* Handle other Object Metadata read response */ + } +} + +void _bt_otp_client_notification_enabled(int result, char *handle) +{ + bt_otp_client_s *otp_client_s = NULL; + char remote_address[BT_ADDR_LENGTH]; + BT_DBG("OTP notificaton [%d] [%s]", result, handle); + _bt_otp_get_remote_address(handle, remote_address); + + otp_client_s = _bt_otp_client_find(remote_address); + if (otp_client_s == NULL) + return; + + if (!g_strcmp0(otp_client_s->otp_oacp_control_point, handle)) { + if (result != BLUETOOTH_ERROR_NONE) { + otp_client_s->oacp_cccd_enabled = FALSE; + BT_ERR("Failed to enable OACP notification : %s(0x%08x)", _bt_convert_error_to_string(result), result); + } else { + otp_client_s->oacp_cccd_enabled = TRUE; + } + } else if (!g_strcmp0(otp_client_s->otp_olcp_control_point, handle)) { + if (result != BLUETOOTH_ERROR_NONE) { + otp_client_s->olcp_cccd_enabled = FALSE; + BT_ERR("Failed to enable OLCP notification : %s(0x%08x)", _bt_convert_error_to_string(result), result); + } else { + otp_client_s->olcp_cccd_enabled = TRUE; + } + } +} diff --git a/test/bt_unit_test.c b/test/bt_unit_test.c index 0e11664..bbe3174 100644 --- a/test/bt_unit_test.c +++ b/test/bt_unit_test.c @@ -125,6 +125,8 @@ bt_tds_provider_h provider; char *tds_act_address; bt_tds_seeker_h seeker; +bt_otp_client_h otp_client; + bt_gatt_attribute_h service_clone[MAX_SERVICES]; bt_gatt_attribute_h characteristics[MAX_SERVICES]; bt_gatt_attribute_h characteristics_services[MAX_SERVICES]; @@ -1162,6 +1164,18 @@ tc_table_t tc_otp[] = { , BT_UNIT_TEST_FUNCTION_OTP_SET_SERVER_STATE_CHANGED_CB}, {"bt_otp_unset_server_state_changed_cb" , BT_UNIT_TEST_FUNCTION_OTP_UNSET_SERVER_STATE_CHANGED_CB}, + {"bt_otp_client_create" + , BT_UNIT_TEST_FUNCTION_OTP_CLIENT_CREATE}, + {"bt_otp_client_destroy" + , BT_UNIT_TEST_FUNCTION_OTP_CLIENT_DESTROY}, + {"bt_otp_client_set_connection_state_changed_cb" + , BT_UNIT_TEST_FUNCTION_OTP_CLIENT_SET_CONNECTION_CALLBACK}, + {"bt_otp_client_unset_connection_state_changed_cb" + , BT_UNIT_TEST_FUNCTION_OTP_CLIENT_UNSET_CONNECTION_CALLBACK}, + {"bt_otp_client_connect" + , BT_UNIT_TEST_FUNCTION_OTP_CLIENT_CONNECT}, + {"bt_otp_client_disconnect" + , BT_UNIT_TEST_FUNCTION_OTP_CLIENT_DISCONNECT}, {NULL , 0x0000}, }; @@ -3221,6 +3235,19 @@ void __bt_otp_server_state_changed_cb(int result, bool status) TC_PRT("Server Status: %s", status ? "enabled" : "disabled"); } +static void __bt_otp_client_connection_state_changed_cb(int result, const char *remote_address, + bt_otp_client_h otp_client, bool connected, void *user_data) +{ + TC_PRT("Result: %s", __bt_get_error_message(result)); + if (result == BT_ERROR_NONE) { + if (connected) + TC_PRT("OTP Client connected(address = %s)", remote_address); + else + TC_PRT("OTP Client Disconnected (address = %s)", remote_address); + } else + BT_ERR("OTP Connection failed!"); +} + static void __bt_initialize_all(void) { int ret; @@ -10195,6 +10222,49 @@ int test_input_callback(void *data) TC_PRT("returns %s\n", __bt_get_error_message(ret)); break; } + case BT_UNIT_TEST_FUNCTION_OTP_CLIENT_CREATE: { + if (otp_client) + otp_client = NULL; + ret = bt_otp_client_create(remote_addr, &otp_client); + TC_PRT("returns %s\n", __bt_get_error_message(ret)); + break; + } + case BT_UNIT_TEST_FUNCTION_OTP_CLIENT_DESTROY: { + if (otp_client) { + ret = bt_otp_client_destroy(otp_client); + TC_PRT("returns %s\n", __bt_get_error_message(ret)); + } + break; + } + case BT_UNIT_TEST_FUNCTION_OTP_CLIENT_SET_CONNECTION_CALLBACK: { + if (otp_client) { + ret = bt_otp_client_set_connection_state_changed_cb(otp_client, + __bt_otp_client_connection_state_changed_cb, NULL); + TC_PRT("returns %s\n", __bt_get_error_message(ret)); + } + break; + } + case BT_UNIT_TEST_FUNCTION_OTP_CLIENT_CONNECT: { + if (otp_client) { + ret = bt_otp_client_connect(otp_client); + TC_PRT("returns %s\n", __bt_get_error_message(ret)); + } + break; + } + case BT_UNIT_TEST_FUNCTION_OTP_CLIENT_DISCONNECT: { + if (otp_client) { + ret = bt_otp_client_disconnect(otp_client); + TC_PRT("returns %s\n", __bt_get_error_message(ret)); + } + break; + } + case BT_UNIT_TEST_FUNCTION_OTP_CLIENT_UNSET_CONNECTION_CALLBACK: { + if (otp_client) { + ret = bt_otp_client_unset_connection_state_changed_cb(otp_client); + TC_PRT("returns %s\n", __bt_get_error_message(ret)); + } + break; + } case BT_UNIT_TEST_FUNCTION_ACTIVATE_FLAG_TO_SET_PARAMETERS: need_to_set_params = true; TC_PRT("Select the function again"); diff --git a/test/bt_unit_test.h b/test/bt_unit_test.h index 35a06a5..30920cc 100644 --- a/test/bt_unit_test.h +++ b/test/bt_unit_test.h @@ -487,6 +487,12 @@ typedef enum { BT_UNIT_TEST_FUNCTION_OTP_SERVER_DEINIT, BT_UNIT_TEST_FUNCTION_OTP_SET_SERVER_STATE_CHANGED_CB, BT_UNIT_TEST_FUNCTION_OTP_UNSET_SERVER_STATE_CHANGED_CB, + BT_UNIT_TEST_FUNCTION_OTP_CLIENT_CREATE, + BT_UNIT_TEST_FUNCTION_OTP_CLIENT_DESTROY, + BT_UNIT_TEST_FUNCTION_OTP_CLIENT_SET_CONNECTION_CALLBACK, + BT_UNIT_TEST_FUNCTION_OTP_CLIENT_UNSET_CONNECTION_CALLBACK, + BT_UNIT_TEST_FUNCTION_OTP_CLIENT_CONNECT, + BT_UNIT_TEST_FUNCTION_OTP_CLIENT_DISCONNECT, BT_UNIT_TEST_FUNCTION_ACTIVATE_FLAG_TO_SET_PARAMETERS = 0XFF, } bt_unit_test_function_e; |