[OTP] Expose Object Create API 07/133807/2
authorGowtham Anandha Babu <gowtham.ab@samsung.com>
Tue, 13 Jun 2017 10:33:28 +0000 (16:03 +0530)
committerGowtham Anandha Babu <gowtham.ab@samsung.com>
Tue, 13 Jun 2017 11:01:16 +0000 (16:31 +0530)
Change-Id: Ie344d4b176889b1acb99dfea234ece1c5b337621
Signed-off-by: Gowtham Anandha Babu <gowtham.ab@samsung.com>
include/bluetooth_internal.h
include/bluetooth_type_internal.h
src/bluetooth-otp.c
test/bt_unit_test.c
test/bt_unit_test.h

index d9a8e32..c6e73f6 100644 (file)
@@ -4108,7 +4108,14 @@ int bt_otp_client_select_object(bt_otp_client_h otp_client, unsigned long long i
  */
 int bt_otp_client_read_object_contents(bt_otp_client_h otp_client,
                                        bt_otp_client_read_object_complete_cb callback, void *user_data);
-
+/**
+ * @internal
+ * @brief OTP client API to create object on remote server
+ */
+int bt_otp_client_create_object(bt_otp_client_h otp_client,
+                                                       const char *file_path,
+                                                       bt_otp_client_object_create_cb callback,
+                                                       void *user_data);
 /**
  * @}
  */
index 8438238..3319304 100644 (file)
@@ -980,6 +980,14 @@ typedef void (*bt_otp_client_read_object_complete_cb)
                (int result, const char *remote_address, char *file_path, void *user_data);
 
 /**
+ * @internal
+ * @since_tizen 4.0
+ * @brief OTP Client profile object create callback
+ */
+typedef void (*bt_otp_client_object_create_cb)
+               (int result, const char *remote_address, unsigned long long obj_id, void *user_data);
+
+/**
  * @}
  */
 
index b2755e1..26e0127 100644 (file)
@@ -20,6 +20,7 @@
 #include <stdio.h>
 #include <stdbool.h>
 #include <string.h>
+#include <sys/stat.h>
 #include <bluetooth-api.h>
 
 #include "bluetooth.h"
 #define BT_OTP_FEATURE_LENGTH 8
 #define BT_ADDR_LENGTH 18
 
-#define BT_OTC_CONNECTION_MAX_TIMEOUT 30000 /* Timeout for OTC Connection in msec */
+#define BT_OTC_CONNECTION_MAX_TIMEOUT 10000 /* 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_OACP_CREATE_SUPPORTED(feature)       feature & 0x8000000000000000
 
 #define BT_OTP_IS_READ_PERMITTED(props)        props & OBJECT_READ
 
+/* OTP Object Type Custom UUIDs */
+/* In SIG Assigned numbers not available */
+#define UNSUPPORTED_OBJECT_TYPE_UUID   "7fb0"
+#define FIRMWARE_UUID                                  "7fb1"
+#define ROUTE_GPX_UUID                                 "7fb2"
+#define TRACK_GPX_UUID                                 "7fb3"
+
 typedef enum {
        BT_OTP_NO_OPERATION = 0,
        BT_OTP_OBJECT_DISCOVERY,
        BT_OTP_OBJECT_READ,
        BT_OTP_OBJECT_SELECT,
+       BT_OTP_OBJECT_CREATE,
 } bt_otp_api_info_e;
 
 typedef struct {
@@ -193,7 +203,16 @@ typedef struct {
        FILE *fp;
 } bt_otp_client_read_op;
 
+typedef struct {
+       char *filename;
+       char *type_uuid;
+       time_t first_created;
+       uint64_t id;
+       uint32_t size;
+} bt_otp_client_create_op;
+
 static bool is_otp_server_initialized = false;
+bt_otp_client_create_op *oacp_create_op = NULL;
 bt_otp_client_read_op *oacp_read_op = NULL;
 bool otc_connection_status = FALSE;
 bt_otp_object_list_s *obj_list;
@@ -209,6 +228,8 @@ static void _bt_otp_client_notify_read_object_status(int result,
 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);
+static void _bt_otp_send_create_object_callback(int result,
+                               uint64_t id, bt_otp_client_s *otp_client_s);
 
 int __bt_check_otp_server_init_status(void)
 {
@@ -346,6 +367,20 @@ static void __bt_otp_client_reset_server_data(bt_otp_client_s *otp_client_s)
                g_free(obj_list);
                obj_list = NULL;
        }
+
+       if (oacp_read_op) {
+               fclose(oacp_read_op->fp);
+               g_free(oacp_read_op->file_path);
+               g_free(oacp_read_op);
+               oacp_read_op = NULL;
+       }
+
+       if (oacp_create_op) {
+               g_free(oacp_create_op->filename);
+               g_free(oacp_create_op->type_uuid);
+               g_free(oacp_create_op);
+               oacp_create_op = NULL;
+       }
 }
 
 int bt_otp_client_set_connection_state_changed_cb(bt_otp_client_h otp_client,
@@ -1047,6 +1082,19 @@ void _bt_otp_client_read_value_response(int result, char *char_path,
                                        BT_ERR("Failed to write control point : %s(0x%08x)", _bt_convert_error_to_string(error_code), error_code);
                                        goto read_fail;
                                }
+                       } else if (otp_client_s->curr_op == BT_OTP_OBJECT_CREATE) {
+                               metadata = g_malloc0(sizeof(object_metadata));
+                               metadata->name = g_strdup(oacp_create_op->filename);
+                               metadata->type = g_strdup(oacp_create_op->type_uuid);
+                               metadata->curr_size = oacp_create_op->size;
+                               metadata->alloc_size = oacp_create_op->size;
+                               /* Dont hard code */
+                               metadata->props = OBJECT_READ | OBJECT_WRITE;
+                               metadata->first_created = oacp_create_op->first_created;
+                               metadata->last_modified = oacp_create_op->first_created;
+                               metadata->id = id;
+                               otp_client_s->object_id = metadata->id;
+                               otp_client_s->object_list = g_slist_append(otp_client_s->object_list, metadata);
                        }
                }
 read_fail:
@@ -1059,6 +1107,11 @@ read_fail:
                                __bt_otp_reset_api_info(otp_client_s);
                        }
                }
+               if (otp_client_s->curr_op == BT_OTP_OBJECT_CREATE) {
+                       _bt_otp_send_create_object_callback(result,
+                                       otp_client_s->object_id, otp_client_s);
+                       __bt_otp_reset_api_info(otp_client_s);
+               }
        }
 }
 
@@ -1073,18 +1126,77 @@ void _bt_otp_client_write_value_response(int result, char *handle)
 
        if (result != BLUETOOTH_ERROR_NONE) {
                BT_DBG("OTP Write Failed");
-               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_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);
+               goto fail;
+       }
+
+       if (otp_client_s->curr_op == BT_OTP_OBJECT_CREATE) {
+               if ((!g_strcmp0(otp_client_s->otp_name_obj_path, handle) ||
+                       !g_strcmp0(otp_client_s->otp_first_created_obj_path, handle)) &&
+                                                                       oacp_create_op) {
+                       struct tm fc_tm;
+                       uint8_t value[8];
+                       int error_code;
+                       memset(value, 0, 8);
+                       localtime_r(&(oacp_create_op->first_created), &fc_tm);
+
+                       value[1] = ((fc_tm.tm_year+1900) >> 8) & 0xFF;
+                       value[0] = (fc_tm.tm_year+1900) & 0xFF;
+                       value[2] = (fc_tm.tm_mon+1) & 0xFF;
+                       value[3] = fc_tm.tm_mday & 0xFF;
+                       value[4] = fc_tm.tm_hour & 0xFF;
+                       value[5] = fc_tm.tm_min & 0xFF;
+                       value[6] = fc_tm.tm_sec & 0xFF;
+
+                       if (!g_strcmp0(otp_client_s->otp_name_obj_path, handle)) {
+                               /* Write First-Created */
+                               error_code = bluetooth_otp_write_characteristics_value(otp_client_s->otp_first_created_obj_path,
+                                                                                                       value, sizeof(value));
+                       } else {
+                               /* Write Last-Modified */
+                               error_code = bluetooth_otp_write_characteristics_value(otp_client_s->otp_last_modified_obj_path,
+                                                                                                       value, sizeof(value));
+                       }
+
+                       if (error_code != BT_ERROR_NONE) {
+                               BT_ERR("Failed to write first_created / last_modified : %s(0x%08x)",
+                                               _bt_convert_error_to_string(error_code), error_code);
+                               result = error_code;
+                               goto fail;
+                       }
+               } else if (!g_strcmp0(otp_client_s->otp_last_modified_obj_path, handle)) {
+                       /* Read Object ID */
+                       int error_code;
+                       error_code = bluetooth_otp_read_characteristic_value(otp_client_s->otp_id_obj_path);
+                       if (error_code != BLUETOOTH_ERROR_NONE) {
+                               BT_INFO("Read object ID Failed %s(0x%08x)", _bt_convert_error_to_string(error_code), error_code);
+                               result = error_code;
+                               goto fail;
+                       }
                }
        }
+       return;
+fail:
+       switch (otp_client_s->curr_op) {
+       case BT_OTP_OBJECT_DISCOVERY:
+               _bt_otp_send_discovery_callback(result, otp_client_s);
+               __bt_otp_reset_api_info(otp_client_s);
+               break;
+       case BT_OTP_OBJECT_READ:
+               _bt_otp_client_notify_read_object_status(result,
+                                                       NULL, otp_client_s);
+               __bt_otp_reset_api_info(otp_client_s);
+               break;
+       case BT_OTP_OBJECT_SELECT:
+               _bt_otp_client_send_select_object_callback(result, otp_client_s);
+               __bt_otp_reset_api_info(otp_client_s);
+               break;
+       case BT_OTP_OBJECT_CREATE:
+               _bt_otp_send_create_object_callback(result, 0, otp_client_s);
+               __bt_otp_reset_api_info(otp_client_s);
+               break;
+       case BT_OTP_NO_OPERATION:
+               break;
+       }
 }
 
 void _bt_otp_client_notification_enabled(int result, char *handle)
@@ -1152,6 +1264,21 @@ void _bt_otp_client_indication(int result, bluetooth_otp_resp_info_t *info)
 
                switch (req_opcode) {
                case OACP_CREATE:
+                       BT_INFO("OACP_CREATE Indication received");
+                       if ((otp_client_s->curr_op == BT_OTP_OBJECT_CREATE) && oacp_create_op) {
+                               int len = strlen(oacp_create_op->filename);
+                               uint8_t *value = (uint8_t *)malloc(len * sizeof(uint8_t));
+                               memcpy(value, oacp_create_op->filename, len);
+                               error_code = bluetooth_otp_write_characteristics_value(otp_client_s->otp_name_obj_path,
+                                                                                                               value, len);
+                               if (error_code != BT_ERROR_NONE) {
+                                       BT_ERR("Failed to write object name : %s(0x%08x)",
+                                                       _bt_convert_error_to_string(error_code), error_code);
+                                       result = error_code;
+                                       goto oacp_done;
+                               }
+                       }
+                       break;
                case OACP_DELETE:
                case OACP_CALC_CHECKSUM:
                case OACP_EXECUTE:
@@ -1187,6 +1314,9 @@ 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);
+               } else  if (otp_client_s->curr_op == BT_OTP_OBJECT_CREATE) {
+                       _bt_otp_send_create_object_callback(result, 0, otp_client_s);
+                       __bt_otp_reset_api_info(otp_client_s);
                }
        } else if (!g_strcmp0(otp_client_s->otp_olcp_control_point, info->handle)) {
                uint8_t resp_code = info->data[0];
@@ -1668,3 +1798,106 @@ int bt_otp_client_read_object_contents(bt_otp_client_h otp_client,
 
        return error_code;
 }
+
+static void _bt_otp_send_create_object_callback(int result,
+                               uint64_t id, bt_otp_client_s *otp_client_s)
+{
+
+       ((bt_otp_client_object_create_cb)otp_client_s->callback)(
+                               result, otp_client_s->remote_address,
+                               id, otp_client_s->user_data);
+
+       if (oacp_create_op) {
+               g_free(oacp_create_op->filename);
+               g_free(oacp_create_op->type_uuid);
+               g_free(oacp_create_op);
+               oacp_create_op = NULL;
+       }
+}
+
+int bt_otp_client_create_object(bt_otp_client_h otp_client,
+                                                       const char *file_path,
+                                                       bt_otp_client_object_create_cb callback,
+                                                       void *user_data)
+{
+       int error_code;
+       bt_otp_client_s *otp_client_s = (bt_otp_client_s *)otp_client;
+       struct stat st;
+       uint32_t size;
+       char *file_name, *last_token;
+       time_t curr_time;
+       char *type_uuid;
+
+       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;
+       }
+
+       if (otp_client_s->curr_op != BT_OTP_NO_OPERATION) {
+               BT_DBG("OTP Client is busy");
+               return BT_ERROR_OPERATION_FAILED;
+       }
+
+       if (~BT_OTP_IS_OACP_CREATE_SUPPORTED(otp_client_s->otp_feature)) {
+               BT_INFO("OACP Create not supported");
+               return BT_ERROR_OPERATION_FAILED;
+       }
+
+       otp_client_s->callback = callback;
+       otp_client_s->user_data = user_data;
+       otp_client_s->curr_op = BT_OTP_OBJECT_CREATE;
+
+       BT_DBG("OTP client create object [%s] in Remote device [%s]",
+                                                       file_path, otp_client_s->remote_address);
+
+       /* Get file_name & size from file_path */
+       if (stat(file_path, &st) == -1) {
+               BT_INFO("stat failed: %s (%d)\n", strerror(errno), errno);
+               return BLUETOOTH_ERROR_INTERNAL;
+       }
+
+       size = (uint32_t)st.st_size;
+       last_token = strrchr(file_path, '/');
+       file_name = last_token + 1;
+
+       BT_INFO("Filepath [%s], Filename [%s], Size[%llu]\n",
+                                                               file_path, file_name, size);
+
+       oacp_create_op = g_malloc0(sizeof(bt_otp_client_create_op));
+       oacp_create_op->size = size;
+       oacp_create_op->filename = g_strdup(file_name);
+
+       time(&curr_time);
+       oacp_create_op->first_created = curr_time;
+
+       /* There isn't clear description for Object Type in spec */
+       type_uuid = g_strdup(UNSUPPORTED_OBJECT_TYPE_UUID);
+       oacp_create_op->type_uuid = g_strdup(type_uuid);
+
+       /* UUIDs can be 128/64/16 bits */
+       uint8_t value[40] = {0x00};
+       value[0] = OACP_CREATE;
+       value[1] = size & 0xFF;
+       value[2] = (size >> 8) & 0xFF;
+       value[3] = (size >> 16) & 0xFF;
+       value[4] = (size >> 24) & 0xFF;
+
+       memcpy(value + 5, type_uuid, strlen(type_uuid));
+
+       error_code = bluetooth_otp_write_characteristics_value(otp_client_s->otp_oacp_control_point,
+                                                                                               value, 5 + strlen(type_uuid));
+       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);
+       }
+       g_free(type_uuid);
+       return error_code;
+}
index 53ea832..9ff394c 100644 (file)
@@ -1182,6 +1182,8 @@ tc_table_t tc_otp[] = {
                , BT_UNIT_TEST_FUNCTION_OTP_CLIENT_SELECT_OBJ},
        {"bt_otp_client_read_object_contents"
                , BT_UNIT_TEST_FUNCTION_OTP_CLIENT_READ_OBJ_CONTENTS},
+       {"bt_otp_client_create_object"
+               , BT_UNIT_TEST_FUNCTION_OTP_CLIENT_CREATE_OBJ},
        {NULL                                   , 0x0000},
 };
 
@@ -3293,6 +3295,15 @@ static void __bt_otp_client_read_object_complete_cb(int result, const char *remo
                BT_ERR("Read object failed!");
 }
 
+static void __bt_otp_client_object_create_cb(int result, const char *remote_address,
+                       unsigned long long obj_id, void *user_data)
+{
+       if (result == BT_ERROR_NONE) {
+               TC_PRT("Object[%llu] created successfully in remote server!", obj_id);
+       } else
+               BT_ERR("Object creation failed!");
+}
+
 static void __bt_initialize_all(void)
 {
        int ret;
@@ -4952,6 +4963,41 @@ int test_set_params(int test_id, char *param)
 
                        break;
                }
+               case BT_UNIT_TEST_FUNCTION_OTP_CLIENT_CREATE_OBJ: {
+                       if (param_index == 0) {
+                               g_test_param.param_count = 1;
+                               g_test_param.params = g_malloc0(sizeof(char *) *g_test_param.param_count);
+                       }
+
+                       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 string");
+                               break;
+                       }
+
+                       param_index++;
+
+                       break;
+               }
                default:
                        TC_PRT("There is no param to set\n");
                        need_to_set_params = false;
@@ -10378,6 +10424,27 @@ int test_input_callback(void *data)
                        }
                        break;
                }
+               case BT_UNIT_TEST_FUNCTION_OTP_CLIENT_CREATE_OBJ: {
+                       char *file_path = NULL;
+                       if (g_test_param.param_count < 1) {
+                                       TC_PRT("Input parameters first");
+                                       break;
+                       }
+
+                       file_path = g_test_param.params[0];
+                       TC_PRT("%s", file_path);
+
+                       if (otp_client) {
+                               ret = bt_otp_client_create_object(otp_client,
+                                               file_path, __bt_otp_client_object_create_cb, NULL);
+                               if (ret < BT_ERROR_NONE)
+                                       TC_PRT("failed with [0x%04x]", ret);
+                               else if (ret == BT_ERROR_NONE)
+                                       TC_PRT("Success");
+                       }
+                       __bt_free_test_param(&g_test_param);
+                       break;
+               }
                case BT_UNIT_TEST_FUNCTION_ACTIVATE_FLAG_TO_SET_PARAMETERS:
                        need_to_set_params = true;
                        TC_PRT("Select the function again");
index e591e11..4f09eba 100644 (file)
@@ -496,6 +496,7 @@ typedef enum {
        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_OTP_CLIENT_CREATE_OBJ,
 
        BT_UNIT_TEST_FUNCTION_ACTIVATE_FLAG_TO_SET_PARAMETERS = 0XFF,
 } bt_unit_test_function_e;