[OTP] Expose APIs for read object contents 83/130883/2
authorGowtham Anandha Babu <gowtham.ab@samsung.com>
Wed, 24 May 2017 08:23:15 +0000 (13:53 +0530)
committerGowtham Anandha Babu <gowtham.ab@samsung.com>
Fri, 26 May 2017 07:40:39 +0000 (13:10 +0530)
Change-Id: I2011fc945b6f4e0ce859b34d8ea95a519d5526cc
Signed-off-by: Gowtham Anandha Babu <gowtham.ab@samsung.com>
include/bluetooth_internal.h
include/bluetooth_private.h
include/bluetooth_type_internal.h
src/bluetooth-common.c
src/bluetooth-otp.c
test/bt_unit_test.c
test/bt_unit_test.h

index a2fb9d70e95005c40e8448e0664b29ed84c9d381..ecc491a466dca533dd223756bc7ce62a40f801bc 100644 (file)
@@ -4096,6 +4096,13 @@ 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 read remote objects contents
+ */
+int bt_otp_client_read_object_contents(bt_otp_client_h otp_client,
+                                       bt_otp_client_read_object_complete_cb callback, void *user_data);
+
 /**
  * @}
  */
index 66787b6b4597eb74a362d6b3105c5c8ad3050f42..f1eab2f3d93ccdb42e6d6af647d457b4d109c813 100644 (file)
@@ -896,6 +896,12 @@ void _bt_otp_client_notification_enabled(int result, char *handle);
  */
 void _bt_otp_client_indication(int result, bluetooth_otp_resp_info_t *info);
 
+/**
+ * @internal
+ * @brief Send OTC connection status to application.
+ */
+void _bt_otc_connection_state_changed(int result, bluetooth_otc_info_t *otc_info);
+
 typedef enum {
        _PROFILE_UNKNOWN = 0,
        _PROFILE_MOBILE = 0x1,
index 87c7e8ae4120b25aff2aaf54f0770c40cc6db9fc..d7a473f0bf8ab7eda0430d9c873c709a71dcf28a 100644 (file)
@@ -957,11 +957,19 @@ typedef void (*bt_otp_client_state_changed_cb)
 /**
  * @internal
  * @since_tizen 3.0
- * @brief OTP Client profile Connection State changed callback which is associated with a remote OTP Server
+ * @brief OTP Client profile remote object discovery callback
  */
 typedef void (*bt_otp_client_object_discovery_cb)
                (int result, const char *remote_address, bt_otp_object_list_s *obj_list, void *user_data);
 
+/**
+ * @internal
+ * @since_tizen 3.0
+ * @brief OTP Client profile remote object read complete callback
+ */
+typedef void (*bt_otp_client_read_object_complete_cb)
+               (int result, const char *remote_address, char *file_path, void *user_data);
+
 /**
  * @}
  */
index f24f952d13a5de8d28209145596eeaa1f48f1349..081b1c17850769a2b2569da56fa7fc0cc9c18652 100644 (file)
@@ -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");
index 020491e77391a81442e144a61a236f836c69ee96..3224664d551fac57bcd112b0231162eb460e25ba 100644 (file)
 #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;
+}
index 9cc9e76ea5f98c7063dba4097a903c48cbebdb97..10ecf09fcc7f41aabcef3679d37d2f9157f189d6 100644 (file)
@@ -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_read_object_contents"
+               , BT_UNIT_TEST_FUNCTION_OTP_CLIENT_READ_OBJ_CONTENTS},
        {NULL                                   , 0x0000},
 };
 
@@ -3267,6 +3269,15 @@ static void __bt_otp_client_object_discovery_cb(int result, const char *remote_a
                BT_ERR("Object discovery failed!");
 }
 
+static void __bt_otp_client_read_object_complete_cb(int result, const char *remote_address,
+                       char *file_path, void *user_data)
+{
+       if (result == BT_ERROR_NONE) {
+               TC_PRT("Read object success!, File location [%s]", file_path);
+       } else
+               BT_ERR("Read object failed!");
+}
+
 static void __bt_initialize_all(void)
 {
        int ret;
@@ -10292,6 +10303,14 @@ int test_input_callback(void *data)
                        }
                        break;
                }
+               case BT_UNIT_TEST_FUNCTION_OTP_CLIENT_READ_OBJ_CONTENTS:        {
+                       if (otp_client) {
+                               ret = bt_otp_client_read_object_contents(otp_client,
+                                                       __bt_otp_client_read_object_complete_cb, NULL);
+                               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");
index 74bede2cb712120e42d8581c5ef0f0cabddeac5f..91729226ea4b8019acfdab0f2f049ed6e4a76799 100644 (file)
@@ -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_READ_OBJ_CONTENTS,
 
        BT_UNIT_TEST_FUNCTION_ACTIVATE_FLAG_TO_SET_PARAMETERS = 0XFF,
 } bt_unit_test_function_e;