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