From 5cf2bc6d96baec8c23370f463076022f0ff17c9f Mon Sep 17 00:00:00 2001 From: Gowtham Anandha Babu Date: Wed, 24 May 2017 13:53:15 +0530 Subject: [OTP] Expose APIs for read object contents Change-Id: I2011fc945b6f4e0ce859b34d8ea95a519d5526cc Signed-off-by: Gowtham Anandha Babu --- src/bluetooth-common.c | 9 + src/bluetooth-otp.c | 458 ++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 440 insertions(+), 27 deletions(-) (limited to 'src') diff --git a/src/bluetooth-common.c b/src/bluetooth-common.c index f24f952..081b1c1 100644 --- a/src/bluetooth-common.c +++ b/src/bluetooth-common.c @@ -1056,6 +1056,7 @@ static bool __bt_need_to_handle(int event) case BLUETOOTH_EVENT_OTP_NOTIFICATION_ENABLED: case BLUETOOTH_EVENT_OTP_WRITE_CHAR_VAL: case BLUETOOTH_EVENT_OTP_INDICATION: + case BLUETOOTH_EVENT_OTC_STATE_CHANGED: return true; default: break; @@ -2975,6 +2976,14 @@ static void __bt_event_proxy(int event, bluetooth_event_param_t *param, void *us BT_DBG("Handle [%s]", otp_ind_info->handle); _bt_otp_client_indication(_bt_get_error_code(param->result), otp_ind_info); break; + } case BLUETOOTH_EVENT_OTC_STATE_CHANGED: { + BT_DBG("BLUETOOTH_EVENT_OTC_STATE_CHANGED"); /* LCOV_EXCL_LINE */ + bluetooth_otc_info_t *otc_info = NULL; + otc_info = (bluetooth_otc_info_t *)(param->param_data); + + BT_ERR("Address [%s]", otc_info->address); + _bt_otc_connection_state_changed(_bt_get_error_code(param->result), otc_info); + break; } default: BT_INFO("Unknown function"); diff --git a/src/bluetooth-otp.c b/src/bluetooth-otp.c index 020491e..3224664 100644 --- a/src/bluetooth-otp.c +++ b/src/bluetooth-otp.c @@ -82,13 +82,52 @@ #define OLCP_NO_OBJ 0x07 #define OLCP_OJECT_ID_NOT_FOUND 0x08 +/* OACP opcodes */ +#define OACP_CREATE 0x01 +#define OACP_DELETE 0x02 +#define OACP_CALC_CHECKSUM 0x03 +#define OACP_EXECUTE 0x04 +#define OACP_READ 0x05 +#define OACP_WRITE 0x06 +#define OACP_ABORT 0x07 +#define OACP_RESPONSE 0x60 + +/* OACP error codes */ +#define OACP_SUCCESS 0x01 +#define OACP_OPCODE_NOT_SUPPORTED 0x02 +#define OACP_INVALID_PARAM 0x03 +#define OACP_INSUFFICIENT_RESOURCES 0x04 +#define OACP_INVALID_OBJ 0x05 +#define OACP_CHANNEL_UNAVAILABLE 0x06 +#define OACP_UNSUPPORTED_TYPE 0x07 +#define OACP_PROCEDURE_NOT_SUPPORTED 0x08 +#define OACP_OBJECT_LOCKED 0x09 +#define OACP_OPERATION_FAILED 0x0A + +/* Object Properties */ +#define OBJECT_DELETE 0x00000001 +#define OBJECT_EXECUTE 0x00000002 +#define OBJECT_READ 0x00000004 +#define OBJECT_WRITE 0x00000008 +#define OBJECT_APPEND 0x00000010 +#define OBJECT_TRUNCATE 0x00000020 +#define OBJECT_PATCH 0x00000040 +#define OBJECT_MARK 0x00000080 + #define BT_OTP_CLIENT_BASE_DIR "/home/owner/media/otp-client/" #define BT_FILE_PATH_MAX_LEN 262 #define BT_OTP_FEATURE_LENGTH 8 #define BT_ADDR_LENGTH 18 -#define IS_OACP_SUPPORTED(feature) feature & 0xffffffff00000000 -#define IS_OLCP_SUPPORTED(feature) feature & 0x00000000ffffffff +#define BT_OTC_CONNECTION_MAX_TIMEOUT 30000 /* Timeout for OTC Connection in msec */ + +#define BT_L2CAP_BUFFER_LEN 672 + +#define BT_OTP_IS_OACP_SUPPORTED(feature) feature & 0xffffffff00000000 +#define BT_OTP_IS_OLCP_SUPPORTED(feature) feature & 0x00000000ffffffff +#define BT_OTP_IS_OACP_READ_SUPPORTED(feature) feature & 0x0800000000000000 + +#define BT_OTP_IS_READ_PERMITTED(props) props & OBJECT_READ typedef struct { char *name; @@ -111,6 +150,9 @@ typedef struct { const void *object_discovery_complete_cb; void *discovery_user_data; + const void *object_read_complete_cb; + void *read_object_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 */ @@ -134,17 +176,31 @@ typedef struct { bool multiple_obj_supp; /* Indicates whether remote server supports * multiple-objects or not */ - + bool oacp_read_status; /* Indicate whether oacp read is completed or not */ GSList *object_list; /* List of server objects */ uint64_t object_id; /* ID of current object */ } bt_otp_client_s; -GSList *otp_client_list; +typedef struct { + uint32_t offset; + uint32_t length; + uint32_t size; + char *file_path; + FILE *fp; +} bt_otp_client_read_op; + static bool is_otp_server_initialized = false; -object_metadata *metadata; +bt_otp_client_read_op *oacp_read_op = NULL; +bool otc_connection_status = FALSE; bt_otp_object_list_s *obj_list; +object_metadata *metadata; +GSList *otp_client_list; +unsigned int timeout_id; +guint id; 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); int __bt_check_otp_server_init_status(void) { @@ -288,6 +344,7 @@ int bt_otp_client_set_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_OTP_SUPPORT(); BT_CHECK_INIT_STATUS(); BT_CHECK_INPUT_PARAMETER(otp_client_s); BT_CHECK_INPUT_PARAMETER(callback); @@ -308,6 +365,7 @@ 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_OTP_SUPPORT(); BT_CHECK_INIT_STATUS(); BT_CHECK_INPUT_PARAMETER(otp_client_s); @@ -544,6 +602,7 @@ int bt_otp_client_create(const char *remote_address, bt_otp_client_h *otp_client BT_INFO("+"); BT_CHECK_LE_SUPPORT(); + BT_CHECK_OTP_SUPPORT(); BT_CHECK_INIT_STATUS(); BT_CHECK_INPUT_PARAMETER(remote_address); BT_CHECK_INPUT_PARAMETER(otp_client); @@ -595,6 +654,7 @@ int bt_otp_client_create(const char *remote_address, bt_otp_client_h *otp_client otp_client_s->oacp_cccd_enabled = FALSE; otp_client_s->object_discovery = FALSE; otp_client_s->multiple_obj_supp = FALSE; + otp_client_s->oacp_read_status = FALSE; otp_client_list = g_slist_append(otp_client_list, otp_client_s); *otp_client = (bt_otp_client_h)otp_client_s; @@ -608,6 +668,7 @@ 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_OTP_SUPPORT(); BT_CHECK_INIT_STATUS(); BT_CHECK_INPUT_PARAMETER(otp_client_s); @@ -630,6 +691,7 @@ int bt_otp_client_connect(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_OTP_SUPPORT(); BT_CHECK_INIT_STATUS(); BT_CHECK_INPUT_PARAMETER(otp_client_s); @@ -654,6 +716,7 @@ int bt_otp_client_disconnect(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_OTP_SUPPORT(); BT_CHECK_INIT_STATUS(); BT_CHECK_INPUT_PARAMETER(otp_client_s); @@ -722,7 +785,7 @@ void _bt_otp_send_discovery_callback(int result, bt_otp_client_s *otp_client_s) } void _bt_otp_client_read_value_response(int result, char *char_path, - char *value, int len) + char *value, int len) { bt_otp_client_s *otp_client_s = NULL; char remote_address[BT_ADDR_LENGTH]; @@ -731,7 +794,7 @@ void _bt_otp_client_read_value_response(int result, char *char_path, _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); + char_path, value, len); if (result != BLUETOOTH_ERROR_NONE) BT_INFO("Read failed for [%s]", char_path); @@ -751,7 +814,7 @@ void _bt_otp_client_read_value_response(int result, char *char_path, otp_client_s->otp_feature = feature; BT_INFO("OTP Feature [%lld]", feature); - if (IS_OACP_SUPPORTED(otp_client_s->otp_feature) + if (BT_OTP_IS_OACP_SUPPORTED(otp_client_s->otp_feature) && !otp_client_s->oacp_cccd_enabled && otp_client_s->otp_oacp_control_point) { @@ -760,7 +823,7 @@ void _bt_otp_client_read_value_response(int result, char *char_path, 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) + if (BT_OTP_IS_OLCP_SUPPORTED(otp_client_s->otp_feature) && !otp_client_s->olcp_cccd_enabled && otp_client_s->otp_olcp_control_point) { error_code = bluetooth_otp_enable_notification(otp_client_s->otp_olcp_control_point); @@ -980,8 +1043,15 @@ void _bt_otp_client_write_value_response(int result, char *handle) if (result != BLUETOOTH_ERROR_NONE) { BT_DBG("OTP Write Failed"); - otp_client_s->object_discovery = FALSE; - _bt_otp_send_discovery_callback(result, otp_client_s); + if (otp_client_s->object_discovery) { + _bt_otp_send_discovery_callback(result, otp_client_s); + otp_client_s->object_discovery = FALSE; + } + if (otp_client_s->oacp_read_status) { + _bt_otp_client_notify_read_object_status(result, + NULL, otp_client_s); + otp_client_s->oacp_read_status = FALSE; + } } } @@ -999,14 +1069,16 @@ void _bt_otp_client_notification_enabled(int result, char *handle) 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); + 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); + 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; } @@ -1027,45 +1099,101 @@ void _bt_otp_client_indication(int result, bluetooth_otp_resp_info_t *info) return; if (!g_strcmp0(otp_client_s->otp_oacp_control_point, info->handle)) { - /* TODO: Handle OACP Indication response */ - } else if (!g_strcmp0(otp_client_s->otp_olcp_control_point, info->handle)) { uint8_t resp_code = info->data[0]; uint8_t req_opcode = info->data[1]; uint8_t result_code = info->data[2]; - if (result != BLUETOOTH_ERROR_NONE) { - /* Indication failed/timeout occured */ - if (otp_client_s->object_discovery) - _bt_otp_send_discovery_callback(result, otp_client_s); + BT_INFO("Resp_code [0x%x], Req_opcode [0x%x], result_code [0x%x]", + resp_code, req_opcode, result_code); + + if (resp_code != OACP_RESPONSE) { + BT_INFO("Indication Response Failed : Wrong Response Code"); + result = BLUETOOTH_ERROR_INTERNAL; + goto oacp_fail; } + if (result_code != OACP_SUCCESS) { + BT_INFO("Indication Response Fail [0x%x]", result_code); + result = BLUETOOTH_ERROR_INTERNAL; + goto oacp_fail; + } + + switch (req_opcode) { + case OACP_CREATE: + case OACP_DELETE: + case OACP_CALC_CHECKSUM: + case OACP_EXECUTE: + break; + case OACP_READ: + BT_INFO("OACP_READ Indication Response received"); + bluetooth_device_address_t addr_hex = { {0,} }; + _bt_convert_address_to_hex(&addr_hex, otp_client_s->remote_address); + if (otc_connection_status) { + BT_INFO("OTC Connected already"); + break; + } + error_code = bluetooth_otp_connect_otc(&addr_hex); + if (error_code != BLUETOOTH_ERROR_NONE) { + BT_INFO("OTC Connection Failed %s(0x%08x)", + _bt_convert_error_to_string(error_code), error_code); + result = error_code; + goto oacp_fail; + } + break; + case OACP_WRITE: + case OACP_ABORT: + break; + default: + BT_INFO("Indication Failed : Wrong Req Opcode [0x%x], Reason [0x%x]", + req_opcode, result_code); + result = BLUETOOTH_ERROR_INTERNAL; + goto oacp_fail; + break; + } + return; +oacp_fail: + if (otp_client_s->oacp_read_status) { + _bt_otp_client_notify_read_object_status(result, NULL, otp_client_s); + otp_client_s->oacp_read_status = FALSE; + } + } else if (!g_strcmp0(otp_client_s->otp_olcp_control_point, info->handle)) { + uint8_t resp_code = info->data[0]; + uint8_t req_opcode = info->data[1]; + uint8_t result_code = info->data[2]; + + /* Indication failed/timeout occured */ + if (result != BLUETOOTH_ERROR_NONE) + goto olcp_fail; + BT_INFO("Resp_code [0x%x], Req_opcode [0x%x], result_code [0x%x]", - resp_code, req_opcode, result_code); + resp_code, req_opcode, result_code); if (resp_code != OLCP_RESPONSE) { - otp_client_s->object_discovery = FALSE; BT_INFO("Indication Response Failed : Wrong Response Code"); - return; + result = BLUETOOTH_ERROR_INTERNAL; + goto olcp_fail; } if (result_code != OLCP_SUCCESS) { - otp_client_s->object_discovery = FALSE; switch (result_code) { case OLCP_NO_OBJ: BT_INFO("No Object Found on server"); + result = BLUETOOTH_ERROR_INTERNAL; break; case OLCP_OUT_OF_BOUNDS: - /* All object discovered, notify application via callback */ - _bt_otp_send_discovery_callback(BLUETOOTH_ERROR_NONE, otp_client_s); + /* All object discovered succesfully, notify application via callback */ + result = BLUETOOTH_ERROR_NONE; break; case OLCP_OJECT_ID_NOT_FOUND: BT_INFO("Object ID not found"); + result = BLUETOOTH_ERROR_INTERNAL; break; default: BT_INFO("Indication Response Fail [0x%x]", result_code); + result = BLUETOOTH_ERROR_INTERNAL; break; } - return; + goto olcp_fail; } switch (req_opcode) { @@ -1083,7 +1211,8 @@ void _bt_otp_client_indication(int result, bluetooth_otp_resp_info_t *info) error_code = bluetooth_otp_read_characteristic_value(otp_client_s->otp_name_obj_path); if (error_code != BLUETOOTH_ERROR_NONE) { BT_INFO("Read Charc Value Failed %s(0x%08x)", _bt_convert_error_to_string(error_code), error_code); - otp_client_s->object_discovery = FALSE; + result = error_code; + goto olcp_fail; } } break; case OLCP_GOTO: /* TODO: */ @@ -1091,8 +1220,16 @@ void _bt_otp_client_indication(int result, bluetooth_otp_resp_info_t *info) 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; break; } + return; +olcp_fail: + if (otp_client_s->object_discovery) { + _bt_otp_send_discovery_callback(result, otp_client_s); + otp_client_s->object_discovery = FALSE; + } } } @@ -1103,6 +1240,7 @@ int bt_otp_client_discover_all_objects(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_OTP_SUPPORT(); BT_CHECK_INIT_STATUS(); BT_CHECK_INPUT_PARAMETER(otp_client_s); @@ -1146,3 +1284,269 @@ int bt_otp_client_discover_all_objects(bt_otp_client_h otp_client, fail: return error_code; } + + +static bool __bt_otc_connection_timeout_cb(gpointer user_data) +{ + bluetooth_otc_info_t *otc_info = (bluetooth_otc_info_t *)user_data; + char *address = otc_info->address; + bluetooth_device_address_t addr_hex = { {0,} }; + + /* TODO: Write OACP Abort opcode, then disconnect */ + + BT_DBG("OTC Connection timer Expired [%s]", address); + _bt_convert_address_to_hex(&addr_hex, address); + bluetooth_otp_disconnect_otc(&addr_hex); + + return FALSE; +} + +static gboolean __client_data_received_cb(GIOChannel *chan, GIOCondition cond, + gpointer data) +{ + bluetooth_otc_info_t *otc_info = (bluetooth_otc_info_t *)data; + char *remote_addr = otc_info->address; + GIOStatus status = G_IO_STATUS_NORMAL; + GError *err = NULL; + char *buffer = NULL; + gsize len = 0; + int written; + int fd; + + BT_DBG(""); + + fd = g_io_channel_unix_get_fd(chan); + if (cond & (G_IO_NVAL | G_IO_HUP | G_IO_ERR)) { + otc_connection_status = FALSE; + BT_ERR("OTC Client disconnected: %d", fd); + close(fd); + g_source_remove(id); + return FALSE; + } + + buffer = g_malloc0(BT_L2CAP_BUFFER_LEN + 1); + + status = g_io_channel_read_chars(chan, buffer, + BT_L2CAP_BUFFER_LEN, + &len, &err); + if (status != G_IO_STATUS_NORMAL) { + BT_ERR("IO Channel read is failed with %d", status); + + g_free(buffer); + if (err) { + otc_connection_status = FALSE; + BT_ERR("IO Channel read error [%s]", err->message); + if (status == G_IO_STATUS_ERROR) { + BT_ERR("cond : %d", cond); + g_error_free(err); + close(fd); + g_source_remove(id); + return FALSE; + } + g_error_free(err); + } + return TRUE; + } + + BT_DBG("Received data length %d, remote_addr = %s", len, remote_addr); + + if (!oacp_read_op) { + char file_path[BT_FILE_PATH_MAX_LEN] = {0, }; + bt_otp_client_s *otp_client_s = NULL; + object_metadata *object_info; + uint64_t obj_id; + FILE *fp = NULL; + + otp_client_s = _bt_otp_client_find(remote_addr); + obj_id = otp_client_s->object_id; + + object_info = _bt_otp_client_find_object(otp_client_s->object_list, obj_id); + if (!object_info) { + BT_INFO("Object Not Found [%llu]", obj_id); + return TRUE; + } + + snprintf(file_path, sizeof(file_path), "%s%s", + BT_OTP_CLIENT_BASE_DIR, object_info->name); + BT_DBG("file_path = [%s]", file_path); + + fp = fopen(file_path, "w"); + if (!fp) { + BT_DBG("fopen() failed : %s", strerror(errno)); + return TRUE; + } + + oacp_read_op = g_malloc0(sizeof(bt_otp_client_read_op)); + oacp_read_op->offset = 0; + oacp_read_op->length = 0; + oacp_read_op->fp = fp; + oacp_read_op->size = object_info->curr_size; + oacp_read_op->file_path = g_strdup(file_path); + } else { + oacp_read_op->offset += (oacp_read_op->length - oacp_read_op->offset); + } + + fseek(oacp_read_op->fp, oacp_read_op->offset, SEEK_SET); + written = fwrite(buffer, 1, len, oacp_read_op->fp); + oacp_read_op->length += len; + BT_DBG("written [%d], offset [%lu], length [%lu], size [%lu]", + written, oacp_read_op->offset, + oacp_read_op->length, oacp_read_op->size); + if (timeout_id > 0) { + g_source_remove(timeout_id); + timeout_id = g_timeout_add(BT_OTC_CONNECTION_MAX_TIMEOUT, + (GSourceFunc)__bt_otc_connection_timeout_cb, (gpointer)otc_info); + } + + g_free(buffer); + return TRUE; +} + +static void _bt_otp_client_notify_read_object_status(int result, + char *file_path, bt_otp_client_s *otp_client_s) +{ + + ((bt_otp_client_read_object_complete_cb)otp_client_s->object_read_complete_cb)( + result, otp_client_s->remote_address, + file_path, otp_client_s->read_object_user_data); +} + +void _bt_otc_connection_state_changed(int result, bluetooth_otc_info_t *otc_info) +{ + GIOChannel *data_io; + char *file_path = NULL; + + BT_DBG("OTC Channel status [%d], fd [%d]", otc_info->connected, otc_info->fd); + + if (oacp_read_op) { + if (!otc_info->connected) + file_path = g_strdup(oacp_read_op->file_path); + /* + * Remove request in both connected/disconnected case. + * So that new request can proceed. + */ + fclose(oacp_read_op->fp); + g_free(oacp_read_op->file_path); + g_free(oacp_read_op); + oacp_read_op = NULL; + } + + if (otc_info->connected) { + BT_DBG("OTC Connected"); + otc_connection_status = TRUE; + + data_io = g_io_channel_unix_new(otc_info->fd); + + g_io_channel_set_encoding(data_io, NULL, NULL); + g_io_channel_set_flags(data_io, G_IO_FLAG_NONBLOCK, NULL); + + id = g_io_add_watch(data_io, + G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL, + __client_data_received_cb, (gpointer)otc_info); + + timeout_id = g_timeout_add(BT_OTC_CONNECTION_MAX_TIMEOUT, + (GSourceFunc)__bt_otc_connection_timeout_cb, (gpointer)otc_info); + } else { + BT_DBG("OTC Disconnected"); + otc_connection_status = FALSE; + if (timeout_id > 0) { + g_source_remove(timeout_id); + timeout_id = 0; + } + bt_otp_client_s *otp_client_s = NULL; + otp_client_s = _bt_otp_client_find(otc_info->address); + + if (otp_client_s->oacp_read_status) { + _bt_otp_client_notify_read_object_status(BLUETOOTH_ERROR_NONE, + file_path, otp_client_s); + otp_client_s->oacp_read_status = FALSE; + } + } +} + +object_metadata *_bt_otp_client_find_object(GSList *list, uint64_t id) +{ + GSList *l; + + for (l = list; l; l = g_slist_next(l)) { + + if (((object_metadata *)l->data)->id == id) + return ((object_metadata *)l->data); + } + return NULL; +} + +int bt_otp_client_read_object_contents(bt_otp_client_h otp_client, + bt_otp_client_read_object_complete_cb callback, + void *user_data) +{ + bt_otp_client_s *otp_client_s = (bt_otp_client_s *)otp_client; + object_metadata *object_info = NULL; + uint64_t obj_id; + int error_code; + + 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; + } + + obj_id = otp_client_s->object_id; + + BT_DBG("OTP client Read objects Contents from Remote device [%s] for Object [%llu]", + otp_client_s->remote_address, obj_id); + + object_info = _bt_otp_client_find_object(otp_client_s->object_list, obj_id); + if (!object_info) { + BT_INFO("Object Not Found [%llu]", obj_id); + return BT_ERROR_OPERATION_FAILED; + } + + if (~BT_OTP_IS_OACP_READ_SUPPORTED(otp_client_s->otp_feature)) { + BT_INFO("OACP Read not supported"); + return BT_ERROR_OPERATION_FAILED; + } + + if (~BT_OTP_IS_READ_PERMITTED(object_info->props)) { + BT_INFO("Read not permitted"); + return BT_ERROR_OPERATION_FAILED; + } + + otp_client_s->object_read_complete_cb = callback; + otp_client_s->read_object_user_data = user_data; + otp_client_s->oacp_read_status = TRUE; + + uint32_t offset = 0; + uint32_t length = object_info->curr_size; + + BT_INFO("Object ID [%llu],Offset [%lu], Length [%lu], curr_soze [%lu]", + obj_id, offset, length, object_info->curr_size); + uint8_t value[9] = {0x00}; + + value[0] = OACP_READ; + value[1] = (offset) & 0xFF; + value[2] = (offset >> 8) & 0xFF; + value[3] = (offset >> 16) & 0xFF; + value[4] = (offset >> 24) & 0xFF; + value[5] = (length) & 0xFF; + value[6] = (length >> 8) & 0xFF; + value[7] = (length >> 16) & 0xFF; + value[8] = (length >> 24) & 0xFF; + + error_code = bluetooth_otp_write_characteristics_value(otp_client_s->otp_oacp_control_point, + value, 9); + 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); + otp_client_s->oacp_read_status = FALSE; + } + + return error_code; +} -- cgit v1.2.3