From b89d3dfc605009e410c5b000f0b69ccb8b9d4533 Mon Sep 17 00:00:00 2001 From: Gowtham Anandha Babu Date: Wed, 7 Jun 2017 20:34:47 +0530 Subject: [PATCH] [OTP] Expose Object Select API Change-Id: I7cb2de1136ddf7f681f2744ac31eed8c947bc4ea Signed-off-by: Gowtham Anandha Babu --- include/bluetooth_internal.h | 6 ++ include/bluetooth_type_internal.h | 21 +++-- src/bluetooth-otp.c | 130 ++++++++++++++++++++++++------ test/bt_unit_test.c | 67 +++++++++++++++ test/bt_unit_test.h | 1 + 5 files changed, 195 insertions(+), 30 deletions(-) diff --git a/include/bluetooth_internal.h b/include/bluetooth_internal.h index ecc491a..d9a8e32 100644 --- a/include/bluetooth_internal.h +++ b/include/bluetooth_internal.h @@ -4096,6 +4096,12 @@ int bt_otp_client_disconnect(bt_otp_client_h otp_client); int bt_otp_client_discover_all_objects(bt_otp_client_h otp_client, bt_otp_client_object_discovery_cb callback, void *user_data); +/** + * @internal + * @brief OTP client API to select object in Remote OTP Server + */ +int bt_otp_client_select_object(bt_otp_client_h otp_client, unsigned long long id, + bt_otp_client_object_select_cb callback, void *user_data); /** * @internal * @brief OTP client API to read remote objects contents diff --git a/include/bluetooth_type_internal.h b/include/bluetooth_type_internal.h index d7a473f..8438238 100644 --- a/include/bluetooth_type_internal.h +++ b/include/bluetooth_type_internal.h @@ -914,6 +914,7 @@ typedef void (*bt_tds_control_point_activation_indication_cb) /** * @internal + * @since_tizen 4.0 * @brief Called when OTP Server is Enabled or Disabled. */ typedef void (*bt_otp_server_state_changed_cb)(int result, bool connected); @@ -922,14 +923,14 @@ 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 + * @since_tizen 4.0 */ typedef void *bt_otp_client_h; /** * @internal * @brief The structure type of OTP object metadata - * @since_tizen 3.0 + * @since_tizen 4.0 */ typedef struct { unsigned long long id; @@ -939,7 +940,7 @@ typedef struct { /** * @internal * @brief The structure type of list of OTP discovered objects - * @since_tizen 3.0 + * @since_tizen 4.0 */ typedef struct { int num_objects; /**< Number of Objects Discovered */ @@ -948,7 +949,7 @@ typedef struct { /** * @internal - * @since_tizen 3.0 + * @since_tizen 4.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) @@ -956,7 +957,7 @@ typedef void (*bt_otp_client_state_changed_cb) /** * @internal - * @since_tizen 3.0 + * @since_tizen 4.0 * @brief OTP Client profile remote object discovery callback */ typedef void (*bt_otp_client_object_discovery_cb) @@ -964,7 +965,15 @@ typedef void (*bt_otp_client_object_discovery_cb) /** * @internal - * @since_tizen 3.0 + * @since_tizen 4.0 + * @brief OTP Client profile select object callback + */ +typedef void (*bt_otp_client_object_select_cb) + (int result, const char *remote_address, unsigned long long obj_id, void *user_data); + +/** + * @internal + * @since_tizen 4.0 * @brief OTP Client profile remote object read complete callback */ typedef void (*bt_otp_client_read_object_complete_cb) diff --git a/src/bluetooth-otp.c b/src/bluetooth-otp.c index 05fbb3d..b2755e1 100644 --- a/src/bluetooth-otp.c +++ b/src/bluetooth-otp.c @@ -133,6 +133,7 @@ typedef enum { BT_OTP_NO_OPERATION = 0, BT_OTP_OBJECT_DISCOVERY, BT_OTP_OBJECT_READ, + BT_OTP_OBJECT_SELECT, } bt_otp_api_info_e; typedef struct { @@ -196,6 +197,7 @@ static bool is_otp_server_initialized = false; bt_otp_client_read_op *oacp_read_op = NULL; bool otc_connection_status = FALSE; bt_otp_object_list_s *obj_list; +uint64_t select_obj_id = 0; object_metadata *metadata; GSList *otp_client_list; unsigned int timeout_id; @@ -205,6 +207,8 @@ object_metadata *_bt_otp_client_find_object(GSList *list, uint64_t id); static void _bt_otp_client_notify_read_object_status(int result, char *file_path, bt_otp_client_s *otp_client_s); void __bt_otp_reset_api_info(bt_otp_client_s *otp_client_s); +static void _bt_otp_client_send_select_object_callback(int result, + bt_otp_client_s *otp_client_s); int __bt_check_otp_server_init_status(void) { @@ -279,11 +283,13 @@ int bt_otp_unset_server_state_changed_cb(void) static bt_otp_client_s *_bt_otp_client_find(const char *remote_address) { GSList *l; + bt_otp_client_s *info; for (l = otp_client_list; l; l = g_slist_next(l)) { + info = l->data; - if (!g_ascii_strcasecmp(((bt_otp_client_s *)l->data)->remote_address, remote_address)) - return ((bt_otp_client_s *)l->data); + if (info && !g_ascii_strcasecmp(info->remote_address, remote_address)) + return info; } return NULL; } @@ -602,6 +608,7 @@ int bt_otp_client_create(const char *remote_address, bt_otp_client_h *otp_client bt_otp_client_s *otp_client_s = NULL; bool connected = false; bluetooth_device_address_t addr_hex = { {0,} }; + bt_otp_client_s *info; GSList *l; BT_INFO("+"); @@ -612,12 +619,12 @@ int bt_otp_client_create(const char *remote_address, bt_otp_client_h *otp_client 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; + info = l->data; - if (!g_ascii_strcasecmp(c->remote_address, remote_address)) { + if (info && !g_ascii_strcasecmp(info->remote_address, remote_address)) { BT_ERR("OTP Client for Remote device [%s] is already created", remote_address); - *otp_client = (bt_otp_client_h)c; + *otp_client = (bt_otp_client_h)info; return BT_ERROR_ALREADY_DONE; } } @@ -753,6 +760,7 @@ void _bt_otp_get_remote_address(char *handle, char *remote_address) void _bt_otp_send_discovery_callback(int result, bt_otp_client_s *otp_client_s) { + object_metadata *metadata; GSList *l; int k; if (result != BLUETOOTH_ERROR_NONE) { @@ -775,8 +783,10 @@ void _bt_otp_send_discovery_callback(int result, bt_otp_client_s *otp_client_s) obj_list->num_objects = g_slist_length(otp_client_s->object_list); obj_list->data = (otp_object_metadata_s **)g_malloc0(sizeof(otp_object_metadata_s)*obj_list->num_objects); k = 0; - for (l = otp_client_s->object_list; l != NULL; l = g_slist_next(l)) { - object_metadata *metadata = l->data; + for (l = otp_client_s->object_list; l; l = g_slist_next(l)) { + metadata = l->data; + if (metadata == NULL) + continue; otp_object_metadata_s *m_data = g_malloc0(sizeof(otp_object_metadata_s)); m_data->id = metadata->id; m_data->name = g_strdup(metadata->name); @@ -1066,11 +1076,13 @@ void _bt_otp_client_write_value_response(int result, char *handle) if (otp_client_s->curr_op == BT_OTP_OBJECT_DISCOVERY) { _bt_otp_send_discovery_callback(result, otp_client_s); __bt_otp_reset_api_info(otp_client_s); - } - if (otp_client_s->curr_op == BT_OTP_OBJECT_READ) { + } else if (otp_client_s->curr_op == BT_OTP_OBJECT_READ) { _bt_otp_client_notify_read_object_status(result, NULL, otp_client_s); __bt_otp_reset_api_info(otp_client_s); + } else if (otp_client_s->curr_op == BT_OTP_OBJECT_SELECT) { + _bt_otp_client_send_select_object_callback(result, otp_client_s); + __bt_otp_reset_api_info(otp_client_s); } } } @@ -1129,13 +1141,13 @@ void _bt_otp_client_indication(int result, bluetooth_otp_resp_info_t *info) if (resp_code != OACP_RESPONSE) { BT_INFO("Indication Response Failed : Wrong Response Code"); result = BLUETOOTH_ERROR_INTERNAL; - goto oacp_fail; + goto oacp_done; } if (result_code != OACP_SUCCESS) { BT_INFO("Indication Response Fail [0x%x]", result_code); result = BLUETOOTH_ERROR_INTERNAL; - goto oacp_fail; + goto oacp_done; } switch (req_opcode) { @@ -1157,7 +1169,7 @@ void _bt_otp_client_indication(int result, bluetooth_otp_resp_info_t *info) BT_INFO("OTC Connection Failed %s(0x%08x)", _bt_convert_error_to_string(error_code), error_code); result = error_code; - goto oacp_fail; + goto oacp_done; } break; case OACP_WRITE: @@ -1167,11 +1179,11 @@ void _bt_otp_client_indication(int result, bluetooth_otp_resp_info_t *info) BT_INFO("Indication Failed : Wrong Req Opcode [0x%x], Reason [0x%x]", req_opcode, result_code); result = BLUETOOTH_ERROR_INTERNAL; - goto oacp_fail; + goto oacp_done; break; } return; -oacp_fail: +oacp_done: if (otp_client_s->curr_op == BT_OTP_OBJECT_READ) { _bt_otp_client_notify_read_object_status(result, NULL, otp_client_s); __bt_otp_reset_api_info(otp_client_s); @@ -1183,7 +1195,7 @@ oacp_fail: /* Indication failed/timeout occured */ if (result != BLUETOOTH_ERROR_NONE) - goto olcp_fail; + goto olcp_done; BT_INFO("Resp_code [0x%x], Req_opcode [0x%x], result_code [0x%x]", resp_code, req_opcode, result_code); @@ -1191,7 +1203,7 @@ oacp_fail: if (resp_code != OLCP_RESPONSE) { BT_INFO("Indication Response Failed : Wrong Response Code"); result = BLUETOOTH_ERROR_INTERNAL; - goto olcp_fail; + goto olcp_done; } if (result_code != OLCP_SUCCESS) { @@ -1213,7 +1225,7 @@ oacp_fail: result = BLUETOOTH_ERROR_INTERNAL; break; } - goto olcp_fail; + goto olcp_done; } switch (req_opcode) { @@ -1232,23 +1244,30 @@ oacp_fail: if (error_code != BLUETOOTH_ERROR_NONE) { BT_INFO("Read Charc Value Failed %s(0x%08x)", _bt_convert_error_to_string(error_code), error_code); result = error_code; - goto olcp_fail; + goto olcp_done; } } break; - case OLCP_GOTO: /* TODO: */ + case OLCP_GOTO: + /* Update the object id & notify client app*/ + otp_client_s->object_id = select_obj_id; + select_obj_id = 0; + goto olcp_done; break; default: BT_INFO("Indication Response Failed : Wrong Req Opcode [0x%x], Reason [0x%x]", req_opcode, result_code); result = BLUETOOTH_ERROR_INTERNAL; - goto olcp_fail; + goto olcp_done; break; } return; -olcp_fail: +olcp_done: if (otp_client_s->curr_op == BT_OTP_OBJECT_DISCOVERY) { _bt_otp_send_discovery_callback(result, otp_client_s); __bt_otp_reset_api_info(otp_client_s); + } else if (otp_client_s->curr_op == BT_OTP_OBJECT_SELECT) { + _bt_otp_client_send_select_object_callback(result, otp_client_s); + __bt_otp_reset_api_info(otp_client_s); } } } @@ -1309,7 +1328,6 @@ int bt_otp_client_discover_all_objects(bt_otp_client_h otp_client, error_code = bluetooth_otp_write_characteristics_value(otp_client_s->otp_olcp_control_point, value, 1); if (error_code != BT_ERROR_NONE) { BT_ERR("Failed to write control point : %s(0x%08x)", _bt_convert_error_to_string(error_code), error_code); - error_code = BT_ERROR_OPERATION_FAILED; __bt_otp_reset_api_info(otp_client_s); } } @@ -1317,6 +1335,68 @@ int bt_otp_client_discover_all_objects(bt_otp_client_h otp_client, return error_code; } +static void _bt_otp_client_send_select_object_callback(int result, + bt_otp_client_s *otp_client_s) +{ + ((bt_otp_client_object_select_cb)otp_client_s->callback)( + result, otp_client_s->remote_address, + otp_client_s->object_id, otp_client_s->user_data); +} + +int bt_otp_client_select_object(bt_otp_client_h otp_client, unsigned long long id, + bt_otp_client_object_select_cb callback, void *user_data) +{ + int error_code; + bt_otp_client_s *otp_client_s = (bt_otp_client_s *)otp_client; + + BT_CHECK_LE_SUPPORT(); + BT_CHECK_OTP_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; + } + + if (otp_client_s->object_id == id) { + BT_INFO("Object already selected"); + return BLUETOOTH_ERROR_NONE; + } + if (otp_client_s->curr_op != BT_OTP_NO_OPERATION) { + BT_DBG("OTP client is busy"); + return BT_ERROR_OPERATION_FAILED; + } + + BT_DBG("OTP client select object [%llu] from Remote device [%s]", id, otp_client_s->remote_address); + otp_client_s->curr_op = BT_OTP_OBJECT_SELECT; + otp_client_s->callback = callback; + otp_client_s->user_data = user_data; + + select_obj_id = id; + + uint8_t value[7] = {0x00}; + value[0] = OLCP_GOTO; + value[1] = select_obj_id & 0xFF; + value[2] = (select_obj_id >> 8) & 0xFF; + value[3] = (select_obj_id >> 16) & 0xFF; + value[4] = (select_obj_id >> 24) & 0xFF; + value[5] = (select_obj_id >> 32) & 0xFF; + value[6] = (select_obj_id >> 40) & 0xFF; + + error_code = bluetooth_otp_write_characteristics_value(otp_client_s->otp_olcp_control_point, + value, 7); + if (error_code != BT_ERROR_NONE) { + BT_ERR("Failed to write control point : %s(0x%08x)", + _bt_convert_error_to_string(error_code), error_code); + __bt_otp_reset_api_info(otp_client_s); + } + + return error_code; +} static bool __bt_otc_connection_timeout_cb(gpointer user_data) { @@ -1498,11 +1578,13 @@ void _bt_otc_connection_state_changed(int result, bluetooth_otc_info_t *otc_info object_metadata *_bt_otp_client_find_object(GSList *list, uint64_t id) { GSList *l; + object_metadata *info; for (l = list; l; l = g_slist_next(l)) { + info = l->data; - if (((object_metadata *)l->data)->id == id) - return ((object_metadata *)l->data); + if (info && (info->id == id)) + return info; } return NULL; } diff --git a/test/bt_unit_test.c b/test/bt_unit_test.c index 10ecf09..53ea832 100644 --- a/test/bt_unit_test.c +++ b/test/bt_unit_test.c @@ -1178,6 +1178,8 @@ tc_table_t tc_otp[] = { , BT_UNIT_TEST_FUNCTION_OTP_CLIENT_DISCONNECT}, {"bt_otp_client_discover_all_objects" , BT_UNIT_TEST_FUNCTION_OTP_CLIENT_DISCOVER_ALL_OBJECTS}, + {"bt_otp_client_select_object" + , BT_UNIT_TEST_FUNCTION_OTP_CLIENT_SELECT_OBJ}, {"bt_otp_client_read_object_contents" , BT_UNIT_TEST_FUNCTION_OTP_CLIENT_READ_OBJ_CONTENTS}, {NULL , 0x0000}, @@ -3269,6 +3271,19 @@ static void __bt_otp_client_object_discovery_cb(int result, const char *remote_a BT_ERR("Object discovery failed!"); } +static void __bt_otp_client_object_select_cb(int result, const char *remote_address, + unsigned long long obj_id, void *user_data) +{ + TC_PRT("__bt_otp_client_object_select_cb"); + TC_PRT("Result: %s", __bt_get_error_message(result)); + TC_PRT("Remote addr [%s]", remote_address); + + if (result == BT_ERROR_NONE) + TC_PRT("Object selected successfully! Current object[%llu]", obj_id); + else + BT_ERR("Object selection failed! Current object[%llu]", obj_id); +} + static void __bt_otp_client_read_object_complete_cb(int result, const char *remote_address, char *file_path, void *user_data) { @@ -4901,6 +4916,42 @@ int test_set_params(int test_id, char *param) break; } + case BT_UNIT_TEST_FUNCTION_OTP_CLIENT_SELECT_OBJ: { + if (param_index == 0) { + g_test_param.param_count = 1; + g_test_param.params = g_malloc0(sizeof(char *) *g_test_param.param_count); + param_type = BT_UNIT_TEST_PARAM_TYPE_INT; + } + + if (param_index > 0) { + int len = strlen(param); + g_test_param.params[param_index - 1] = g_malloc0(len + 1); + /* Remove new line character */ + param[len - 1] = '\0'; + strncpy(g_test_param.params[param_index - 1], param, strlen(param)); + } + + if (param_index == g_test_param.param_count) { + need_to_set_params = false; +#ifdef ARCH64 + test_input_callback((void *)(uintptr_t)test_id); +#else + test_input_callback((void *)test_id); +#endif + param_index = 0; + return 0; + } + + switch (param_index) { + case 0: + TC_PRT("Input Value in uint64_t"); + break; + } + + param_index++; + + break; + } default: TC_PRT("There is no param to set\n"); need_to_set_params = false; @@ -10303,6 +10354,22 @@ int test_input_callback(void *data) } break; } + case BT_UNIT_TEST_FUNCTION_OTP_CLIENT_SELECT_OBJ: { + if (otp_client) { + unsigned long long id; + if (g_test_param.param_count < 1) { + TC_PRT("Input parameters first"); + break; + } + + id = atoi(g_test_param.params[0]); + TC_PRT("Object ID[%llu]", id); + ret = bt_otp_client_select_object(otp_client, id, + __bt_otp_client_object_select_cb, NULL); + TC_PRT("returns %s\n", __bt_get_error_message(ret)); + } + break; + } case BT_UNIT_TEST_FUNCTION_OTP_CLIENT_READ_OBJ_CONTENTS: { if (otp_client) { ret = bt_otp_client_read_object_contents(otp_client, diff --git a/test/bt_unit_test.h b/test/bt_unit_test.h index 9172922..e591e11 100644 --- a/test/bt_unit_test.h +++ b/test/bt_unit_test.h @@ -494,6 +494,7 @@ typedef enum { BT_UNIT_TEST_FUNCTION_OTP_CLIENT_CONNECT, BT_UNIT_TEST_FUNCTION_OTP_CLIENT_DISCONNECT, BT_UNIT_TEST_FUNCTION_OTP_CLIENT_DISCOVER_ALL_OBJECTS, + BT_UNIT_TEST_FUNCTION_OTP_CLIENT_SELECT_OBJ, BT_UNIT_TEST_FUNCTION_OTP_CLIENT_READ_OBJ_CONTENTS, BT_UNIT_TEST_FUNCTION_ACTIVATE_FLAG_TO_SET_PARAMETERS = 0XFF, -- 2.34.1