From: Anupam Roy Date: Mon, 16 Jan 2017 11:00:16 +0000 (+0530) Subject: [TDS] Implement TDS Seeker role CAPI's X-Git-Tag: submit/tizen_3.0/20170118.073413^0 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=8d2c77c3a5220c37a294519eca69723cbe3e8f83;p=platform%2Fcore%2Fapi%2Fbluetooth.git [TDS] Implement TDS Seeker role CAPI's This patch implements the Seeker role of TDS Connection handover profile. Following CAPI's AND callbacks are handled in this patch 1/ Find Remote TDS providers- BLE Scan to find all devices which support TDS Service 2/ TDS Seeker Create/Destroy 3/ TDS Connect/Disconnect 4/ TDS Read Transport specific complete data 5/ Activate TDS Control point- This will attempt to activate Alternate transport in TDS Provider from GATT database of remote TDS provider Change-Id: Iaf4f79d23093da3e4e597c4c3974a06764206493 Signed-off-by: Anupam Roy --- diff --git a/include/bluetooth_private.h b/include/bluetooth_private.h index 63b0b06..c7781c7 100644 --- a/include/bluetooth_private.h +++ b/include/bluetooth_private.h @@ -161,6 +161,7 @@ typedef enum { BT_EVENT_MAP_CLIENT_GET_MESSAGE, /**< MAP - getMessage event*/ BT_EVENT_MAP_CLIENT_PUSH_MESSAGE, /**< MAP - pushMessage event*/ BT_EVENT_TDS_ACTIVATION_REQUESTED, /**< TDS - transport activation requested event */ + BT_EVENT_TDS_PROVIDER_FOUND_RESULT, /**< TDS - CUSTOM Provider */ BT_EVENT_MAX } bt_event_e; @@ -214,6 +215,7 @@ typedef enum { BT_ADAPTER_LE_ADVERTISING_DATA_128_BIT_SERVICE_SOLICITATION_UUIDS = 0x15, /**< List of 128-bit Service Solicitation UUIDs*/ BT_ADAPTER_LE_ADVERTISING_DATA_SERVICE_DATA = 0x16, /**< Service data */ BT_ADAPTER_LE_ADVERTISING_DATA_APPEARANCE = 0x19, /**< Appearance*/ + BT_ADAPTER_LE_ADVERTISING_DATA_TRANSPORT_DISCOVERY = 0x26, /**< Transport Discovery*/ BT_ADAPTER_LE_ADVERTISING_DATA_MANUFACTURER_SPECIFIC_DATA = 0xff, /**< Manufacturer data */ } bt_adapter_le_advertising_data_type_e; @@ -637,6 +639,13 @@ int _bt_get_error_code(int origin_error); int _bt_get_bt_device_info_s(bt_device_info_s **dest_dev, bluetooth_device_info_t *source_dev); +/** + * @internal + * @brief Filter Advertising data based on AD type. + */ +int _bt_get_ad_data_by_type(char *in_data, int in_len, + char in_type, char **data, int *data_len); + /** * @internal * @brief Free bt_device_info_s. @@ -847,6 +856,48 @@ int _bt_check_proximity_is_initialized(bool *is_initialized); */ int _bt_proximity_connection_set_state_changed(int result, const char *remote_address, bool connected); +/** + * @internal + * @brief Send GATT connection state changed status with remote TDS provider. + */ +void _bt_tds_update_seeker_connection_state_changed(int result, const char *remote_address, bool connected); + +/** + * @internal + * @brief Parses TDS AD Type data recived in scan, to extract meaningful transport specific data. + */ +int _bt_tds_parse_transport_blocks(bt_tds_transport_block_list_s **info, char *data, int data_len); + +/** + * @internal + * @brief Handles complete TDS specific data to be sent to application. + */ +void _bt_tds_send_complete_transport_data(int result, const char *address, char *data, int data_len); + +/** + * @internal + * @brief Send Result of TDS specific CCCD enabled event of Remote TDS provider. + */ +void _bt_tds_control_point_enabled_update(int result, const char *remote_address); + +/** + * @internal + * @brief Send Result of TDS control point activate ACK event. + */ +void _bt_tds_control_point_activation_result_update(int result, const char *remote_address); + +/** + * @internal + * @brief Send TDS Indication response from remote TDS provider. + */ +void _bt_tds_control_point_indication_response_update(const char *address, bluetooth_tds_indication_res_t *info); + +/** + * @internal + * @brief Sends GATT primary service status changed of Remote Provider. + */ +void _bt_tds_check_service_changed(char *address, bt_gatt_service_change_t *service_change); + #ifdef __cplusplus } #endif diff --git a/include/mobile/bluetooth_internal.h b/include/mobile/bluetooth_internal.h index a2e6c87..aeed803 100644 --- a/include/mobile/bluetooth_internal.h +++ b/include/mobile/bluetooth_internal.h @@ -3889,6 +3889,69 @@ int bt_tds_set_transport_activation_requested_cb( */ int bt_tds_unset_transport_activation_requested_cb(void); +/** + * @internal + * @brief TDS Seeker Profile API to start seeking Remote TDS providers only + */ +int bt_tds_start_seeking_providers(bt_tds_provider_scan_result_cb cb, void *user_data); + +/** + * @internal + * @brief TDS Seeker Profile API to stop seeking Remote TDS providers + */ +int bt_tds_stop_seeking_providers(void); + +/** + * @internal + * @brief TDS Seeker Profile API to create Seeker Role associated with Remote TDS provider + */ +int bt_tds_seeker_create(const char *remote_address, bt_tds_seeker_h *seeker); + +/** + * @internal + * @brief TDS Seeker Profile API to destroy Seeker Role associated with Remote TDS provider + */ +int bt_tds_seeker_destroy(bt_tds_seeker_h seeker); + +/** + * @internal + * @brief TDS Seeker Profile API to set connection state changed event associated with Remote TDS provider + */ +int bt_tds_seeker_set_connection_state_changed_cb(bt_tds_seeker_h seeker, + bt_tds_seeker_connection_state_changed_cb callback, void *user_data); + +/** + * @internal + * @brief TDS Seeker Profile API to unset connection state changed event associated with Remote TDS provider + */ +int bt_tds_seeker_unset_connection_state_changed_cb(bt_tds_seeker_h seeker); + +/** + * @internal + * @brief TDS Seeker Profile API to connect to Remote TDS provider + */ +int bt_tds_seeker_connect(bt_tds_seeker_h seeker); + +/** + * @internal + * @brief TDS Seeker Profile API to disconnect to Remote TDS provider + */ +int bt_tds_seeker_disconnect(bt_tds_seeker_h seeker); + +/** + * @internal + * @brief TDS Seeker Profile API to read complete TDS block data which is stored in Remote TDS provider's GATT database + */ +int bt_tds_seeker_get_complete_transport_blocks(bt_tds_seeker_h seeker, + bt_tds_seeker_complete_transport_data_cb callback, void *user_data); + +/** + * @internal + * @brief TDS Seeker Profile API to Activate ALternate transport supported by Remote TDS provider + */ +int bt_tds_seeker_activate_control_point(bt_tds_seeker_h seeker, + bt_tds_transport_e transport, unsigned char *buffer, int len, + bt_tds_control_point_activation_indication_cb callback, void *user_data); /** * @} */ diff --git a/include/mobile/bluetooth_type_internal.h b/include/mobile/bluetooth_type_internal.h index 50b2426..96dd8d2 100644 --- a/include/mobile/bluetooth_type_internal.h +++ b/include/mobile/bluetooth_type_internal.h @@ -710,9 +710,9 @@ typedef void (*bt_proximity_reporter_connection_state_changed_cb) * @since_tizen 3.0 */ typedef enum { - BT_TDS_TRANSPORT_STATE_OFF, - BT_TDS_TRANSPORT_STATE_ON, - BT_TDS_TRANSPORT_STATE_UNAVAILABLE, + BT_TDS_TRANSPORT_STATE_OFF, /**< Transport is currently in OFF state */ + BT_TDS_TRANSPORT_STATE_ON, /**< Transport is currently in ON state */ + BT_TDS_TRANSPORT_STATE_UNAVAILABLE, /**< Transport is temporarily unavailable */ } bt_tds_transport_state_e; /** @@ -727,6 +727,29 @@ typedef enum { BT_TDS_TRANSPORT_INVALID } bt_tds_transport_e; +/** + * @internal + * @brief The structure type of TDS transport data block + * @since_tizen 3.0 + */ +typedef struct { + bt_tds_transport_e transport; + bt_tds_transport_state_e state; + bool is_data_complete; + char *data; + int length; +} tds_transport_data_s; + +/** + * @internal + * @brief The structure type of list of TDS transport data block + * @since_tizen 3.0 + */ +typedef struct { + int num_transport_block; /**< Number of Transport Data Blocks */ + tds_transport_data_s **data; /**< Array of Transport Data Block */ +} bt_tds_transport_block_list_s; + /** * @internal * @ingroup CAPI_NETWORK_BLUETOOTH_ADAPTER_MODULE @@ -801,6 +824,47 @@ typedef void *bt_tds_provider_h; */ typedef void (*bt_tds_activation_requested_cb)(char *remote_bd_addr, bt_tds_transport_e transport, unsigned char *buf, int len, void *user_data); + +/** + * @ingroup CAPI_NETWORK_BLUETOOTH_ADAPTER_LE_MODULE + * @brief The handle of a TDS Seeker client which is associated with a remote TDS provider + * @since_tizen 3.0 + */ +typedef void *bt_tds_seeker_h; + +/** + * @internal + * @since_tizen 3.0 + * @brief TDS Seeker profile Scan result callback containing filtered TDS service information and + * complete LE discovery informations + */ +typedef void (*bt_tds_provider_scan_result_cb)(int result, const char *remote_address, + bt_tds_transport_block_list_s *info, bt_adapter_le_device_scan_result_info_s *scan_info, + void *user_data); + +/** + * @internal + * @since_tizen 3.0 + * @brief TDS Seeker profile Connection State changed callback which is associated with a remote TDS provider + */ +typedef void (*bt_tds_seeker_connection_state_changed_cb) + (int result, const char *remote_address, bt_tds_seeker_h seeker, bool connected, void *user_data); + +/** + * @internal + * @since_tizen 3.0 + * @brief TDS Seeker profile complete TDS data block read callback from remote TDS provider + */ +typedef void (*bt_tds_seeker_complete_transport_data_cb) + (int result, const char *remote_address, bt_tds_transport_block_list_s *info, void *user_data); + +/** + * @internal + * @since_tizen 3.0 + * @brief TDS Seeker profile TDS Control Point Activation request callback which is associated with remote TDS provider + */ +typedef void (*bt_tds_control_point_activation_indication_cb) + (int result, const char *remote_address, unsigned char *data, int data_length, void *user_data); /** * @} */ diff --git a/include/tv/bluetooth_internal.h b/include/tv/bluetooth_internal.h index a2e6c87..aeed803 100644 --- a/include/tv/bluetooth_internal.h +++ b/include/tv/bluetooth_internal.h @@ -3889,6 +3889,69 @@ int bt_tds_set_transport_activation_requested_cb( */ int bt_tds_unset_transport_activation_requested_cb(void); +/** + * @internal + * @brief TDS Seeker Profile API to start seeking Remote TDS providers only + */ +int bt_tds_start_seeking_providers(bt_tds_provider_scan_result_cb cb, void *user_data); + +/** + * @internal + * @brief TDS Seeker Profile API to stop seeking Remote TDS providers + */ +int bt_tds_stop_seeking_providers(void); + +/** + * @internal + * @brief TDS Seeker Profile API to create Seeker Role associated with Remote TDS provider + */ +int bt_tds_seeker_create(const char *remote_address, bt_tds_seeker_h *seeker); + +/** + * @internal + * @brief TDS Seeker Profile API to destroy Seeker Role associated with Remote TDS provider + */ +int bt_tds_seeker_destroy(bt_tds_seeker_h seeker); + +/** + * @internal + * @brief TDS Seeker Profile API to set connection state changed event associated with Remote TDS provider + */ +int bt_tds_seeker_set_connection_state_changed_cb(bt_tds_seeker_h seeker, + bt_tds_seeker_connection_state_changed_cb callback, void *user_data); + +/** + * @internal + * @brief TDS Seeker Profile API to unset connection state changed event associated with Remote TDS provider + */ +int bt_tds_seeker_unset_connection_state_changed_cb(bt_tds_seeker_h seeker); + +/** + * @internal + * @brief TDS Seeker Profile API to connect to Remote TDS provider + */ +int bt_tds_seeker_connect(bt_tds_seeker_h seeker); + +/** + * @internal + * @brief TDS Seeker Profile API to disconnect to Remote TDS provider + */ +int bt_tds_seeker_disconnect(bt_tds_seeker_h seeker); + +/** + * @internal + * @brief TDS Seeker Profile API to read complete TDS block data which is stored in Remote TDS provider's GATT database + */ +int bt_tds_seeker_get_complete_transport_blocks(bt_tds_seeker_h seeker, + bt_tds_seeker_complete_transport_data_cb callback, void *user_data); + +/** + * @internal + * @brief TDS Seeker Profile API to Activate ALternate transport supported by Remote TDS provider + */ +int bt_tds_seeker_activate_control_point(bt_tds_seeker_h seeker, + bt_tds_transport_e transport, unsigned char *buffer, int len, + bt_tds_control_point_activation_indication_cb callback, void *user_data); /** * @} */ diff --git a/include/tv/bluetooth_type_internal.h b/include/tv/bluetooth_type_internal.h index b9d8af8..8b2404c 100644 --- a/include/tv/bluetooth_type_internal.h +++ b/include/tv/bluetooth_type_internal.h @@ -710,9 +710,9 @@ typedef void (*bt_proximity_reporter_connection_state_changed_cb) * @since_tizen 3.0 */ typedef enum { - BT_TDS_TRANSPORT_STATE_OFF, - BT_TDS_TRANSPORT_STATE_ON, - BT_TDS_TRANSPORT_STATE_UNAVAILABLE, + BT_TDS_TRANSPORT_STATE_OFF, /**< Transport is currently in OFF state */ + BT_TDS_TRANSPORT_STATE_ON, /**< Transport is currently in ON state */ + BT_TDS_TRANSPORT_STATE_UNAVAILABLE, /**< Transport is temporarily unavailable */ } bt_tds_transport_state_e; /** @@ -727,6 +727,29 @@ typedef enum { BT_TDS_TRANSPORT_INVALID } bt_tds_transport_e; +/** + * @internal + * @brief The structure type of TDS transport data block + * @since_tizen 3.0 + */ +typedef struct { + bt_tds_transport_e transport; + bt_tds_transport_state_e state; + bool is_data_complete; + char *data; + int length; +} tds_transport_data_s; + +/** + * @internal + * @brief The structure type of list of TDS transport data block + * @since_tizen 3.0 + */ +typedef struct { + int num_transport_block; /**< Number of Transport Data Blocks */ + tds_transport_data_s **data; /**< Array of Transport Data Block */ +} bt_tds_transport_block_list_s; + /** * @internal * @ingroup CAPI_NETWORK_BLUETOOTH_ADAPTER_MODULE @@ -801,6 +824,50 @@ typedef void *bt_tds_provider_h; */ typedef void (*bt_tds_activation_requested_cb)(char *remote_bd_addr, bt_tds_transport_e transport, unsigned char *buf, int len, void *user_data); + +/** + * @ingroup CAPI_NETWORK_BLUETOOTH_ADAPTER_LE_MODULE + * @brief The handle of a TDS Seeker client which is associated with a remote TDS provider + * @since_tizen 3.0 + */ +typedef void *bt_tds_seeker_h; + +/** + * @internal + * @since_tizen 3.0 + * @brief TDS Seeker profile Scan result callback containing filtered TDS service information and + * complete LE discovery informations + */ +typedef void (*bt_tds_provider_scan_result_cb)(int result, const char *remote_address, + bt_tds_transport_block_list_s *info, bt_adapter_le_device_scan_result_info_s *scan_info, + void *user_data); + +/** + * @internal + * @since_tizen 3.0 + * @brief TDS Seeker profile Connection State changed callback which is associated with a remote TDS provider + */ +typedef void (*bt_tds_seeker_connection_state_changed_cb) + (int result, const char *remote_address, + bt_tds_seeker_h seeker, bool connected, void *user_data); + +/** + * @internal + * @since_tizen 3.0 + * @brief TDS Seeker profile complete TDS data block read callback from remote TDS provider + */ +typedef void (*bt_tds_seeker_complete_transport_data_cb) + (int result, const char *remote_address, + bt_tds_transport_block_list_s *info, void *user_data); + +/** + * @internal + * @since_tizen 3.0 + * @brief TDS Seeker profile TDS Control Point Activation request callback which is associated with remote TDS provider + */ +typedef void (*bt_tds_control_point_activation_indication_cb) + (int result, const char *remote_address, + unsigned char *data, int data_length, void *user_data); /** * @} */ diff --git a/include/wearable/bluetooth_internal.h b/include/wearable/bluetooth_internal.h index 776bff6..af664b3 100644 --- a/include/wearable/bluetooth_internal.h +++ b/include/wearable/bluetooth_internal.h @@ -4070,6 +4070,69 @@ int bt_tds_set_transport_activation_requested_cb( */ int bt_tds_unset_transport_activation_requested_cb(void); +/** + * @internal + * @brief TDS Seeker Profile API to start seeking Remote TDS providers only + */ +int bt_tds_start_seeking_providers(bt_tds_provider_scan_result_cb cb, void *user_data); + +/** + * @internal + * @brief TDS Seeker Profile API to stop seeking Remote TDS providers + */ +int bt_tds_stop_seeking_providers(void); + +/** + * @internal + * @brief TDS Seeker Profile API to create Seeker Role associated with Remote TDS provider + */ +int bt_tds_seeker_create(const char *remote_address, bt_tds_seeker_h *seeker); + +/** + * @internal + * @brief TDS Seeker Profile API to destroy Seeker Role associated with Remote TDS provider + */ +int bt_tds_seeker_destroy(bt_tds_seeker_h seeker); + +/** + * @internal + * @brief TDS Seeker Profile API to set connection state changed event associated with Remote TDS provider + */ +int bt_tds_seeker_set_connection_state_changed_cb(bt_tds_seeker_h seeker, + bt_tds_seeker_connection_state_changed_cb callback, void *user_data); + +/** + * @internal + * @brief TDS Seeker Profile API to unset connection state changed event associated with Remote TDS provider + */ +int bt_tds_seeker_unset_connection_state_changed_cb(bt_tds_seeker_h seeker); + +/** + * @internal + * @brief TDS Seeker Profile API to connect to Remote TDS provider + */ +int bt_tds_seeker_connect(bt_tds_seeker_h seeker); + +/** + * @internal + * @brief TDS Seeker Profile API to disconnect to Remote TDS provider + */ +int bt_tds_seeker_disconnect(bt_tds_seeker_h seeker); + +/** + * @internal + * @brief TDS Seeker Profile API to read complete TDS block data which is stored in Remote TDS provider's GATT database + */ +int bt_tds_seeker_get_complete_transport_blocks(bt_tds_seeker_h seeker, + bt_tds_seeker_complete_transport_data_cb callback, void *user_data); + +/** + * @internal + * @brief TDS Seeker Profile API to Activate ALternate transport supported by Remote TDS provider + */ +int bt_tds_seeker_activate_control_point(bt_tds_seeker_h seeker, + bt_tds_transport_e transport, unsigned char *buffer, int len, + bt_tds_control_point_activation_indication_cb callback, void *user_data); /** * @} */ diff --git a/include/wearable/bluetooth_type_internal.h b/include/wearable/bluetooth_type_internal.h index 814c6cb..f7a3851 100644 --- a/include/wearable/bluetooth_type_internal.h +++ b/include/wearable/bluetooth_type_internal.h @@ -743,9 +743,9 @@ typedef void (*bt_proximity_reporter_connection_state_changed_cb) * @since_tizen 3.0 */ typedef enum { - BT_TDS_TRANSPORT_STATE_OFF, - BT_TDS_TRANSPORT_STATE_ON, - BT_TDS_TRANSPORT_STATE_UNAVAILABLE, + BT_TDS_TRANSPORT_STATE_OFF, /**< Transport is currently in OFF state */ + BT_TDS_TRANSPORT_STATE_ON, /**< Transport is currently in ON state */ + BT_TDS_TRANSPORT_STATE_UNAVAILABLE, /**< Transport is temporarily unavailable */ } bt_tds_transport_state_e; /** @@ -760,6 +760,29 @@ typedef enum { BT_TDS_TRANSPORT_INVALID } bt_tds_transport_e; +/** + * @internal + * @brief The structure type of TDS transport data block + * @since_tizen 3.0 + */ +typedef struct { + bt_tds_transport_e transport; + bt_tds_transport_state_e state; + bool is_data_complete; + char *data; + int length; +} tds_transport_data_s; + +/** + * @internal + * @brief The structure type of list of TDS transport data block + * @since_tizen 3.0 + */ +typedef struct { + int num_transport_block; /**< Number of Transport Data Blocks */ + tds_transport_data_s **data; /**< Array of Transport Data Block */ +} bt_tds_transport_block_list_s; + /** * @internal * @ingroup CAPI_NETWORK_BLUETOOTH_ADAPTER_MODULE @@ -847,6 +870,50 @@ typedef void *bt_tds_provider_h; */ typedef void (*bt_tds_activation_requested_cb)(char *remote_bd_addr, bt_tds_transport_e transport, unsigned char *buf, int len, void *user_data); + +/** + * @ingroup CAPI_NETWORK_BLUETOOTH_ADAPTER_LE_MODULE + * @brief The handle of a TDS Seeker client which is associated with a remote TDS provider + * @since_tizen 3.0 + */ +typedef void *bt_tds_seeker_h; + +/** + * @internal + * @since_tizen 3.0 + * @brief TDS Seeker profile Scan result callback containing filtered TDS service information and + * complete LE discovery informations + */ +typedef void (*bt_tds_provider_scan_result_cb)(int result, const char *remote_address, + bt_tds_transport_block_list_s *info, bt_adapter_le_device_scan_result_info_s *scan_info, + void *user_data); + +/** + * @internal + * @since_tizen 3.0 + * @brief TDS Seeker profile Connection State changed callback which is associated with a remote TDS provider + */ +typedef void (*bt_tds_seeker_connection_state_changed_cb) + (int result, const char *remote_address, + bt_tds_seeker_h seeker, bool connected, void *user_data); + +/** + * @internal + * @since_tizen 3.0 + * @brief TDS Seeker profile complete TDS data block read callback from remote TDS provider + */ +typedef void (*bt_tds_seeker_complete_transport_data_cb) + (int result, const char *remote_address, + bt_tds_transport_block_list_s *info, void *user_data); + +/** + * @internal + * @since_tizen 3.0 + * @brief TDS Seeker profile TDS Control Point Activation request callback which is associated with remote TDS provider + */ +typedef void (*bt_tds_control_point_activation_indication_cb) + (int result, const char *remote_address, + unsigned char *data, int data_length, void *user_data); /** * @} */ diff --git a/src/bluetooth-common.c b/src/bluetooth-common.c index 023dab3..f17bb6a 100644 --- a/src/bluetooth-common.c +++ b/src/bluetooth-common.c @@ -51,6 +51,9 @@ static void __bt_free_bt_adapter_device_discovery_info_s(bt_adapter_device_disco static int __bt_get_bt_adapter_le_device_scan_info_s(bt_adapter_le_device_scan_result_info_s **scan_info, bluetooth_le_device_info_t *source_info); static void __bt_free_bt_adapter_le_device_scan_info_s(bt_adapter_le_device_scan_result_info_s *scan_info); +/* TDS Forward declarations */ +static void __bt_free_tds_scan_result_info_s(bt_tds_transport_block_list_s *discovery_info); + #if !defined(TIZEN_PROFILE_WEARABLE) && !defined(TIZEN_PROFILE_IVI) static int __bt_get_bt_adapter_le_device_discovery_info_s(bt_adapter_le_device_discovery_info_s **le_discovery_info, bluetooth_le_device_info_t *source_info); static void __bt_free_bt_adapter_le_device_discovery_info_s(bt_adapter_le_device_discovery_info_s *discovery_info); @@ -487,6 +490,55 @@ void _bt_free_bt_device_info_s(bt_device_info_s *device_info) } /* LCOV_EXCL_STOP */ +int _bt_get_ad_data_by_type(char *in_data, int in_len, + char in_type, char **data, int *data_len) +{ + if (in_data == NULL || data == NULL || data_len == NULL) + return BLUETOOTH_ERROR_INTERNAL; + + if (in_len < 0) + return BLUETOOTH_ERROR_INTERNAL; + + int i; + int len = 0; + int type = 0; + + for (i = 0; i < in_len; i++) { + len = in_data[i]; + if (len <= 0 || i + 1 >= in_len) { + BT_ERR("Invalid advertising data"); + return BLUETOOTH_ERROR_INTERNAL; + } + + type = in_data[i + 1]; + if (type == in_type) { + i = i + 2; + len--; + break; + } + + i += len; + len = 0; + } + + if (i + len > in_len) { + BT_ERR("Invalid advertising data"); + return BLUETOOTH_ERROR_INTERNAL; + } else if (len == 0) { + BT_DBG("AD Type 0x%02x data is not set", in_type); + *data = NULL; + *data_len = 0; + return BLUETOOTH_ERROR_NONE; + } + + *data = g_memdup(&in_data[i], len); + if (*data == NULL) + return BLUETOOTH_ERROR_OUT_OF_MEMORY; + *data_len = len; + + return BLUETOOTH_ERROR_NONE; +} + int _bt_convert_address_to_string(char **addr_str, bluetooth_device_address_t *addr_hex) { char address[18] = { 0, }; @@ -999,6 +1051,10 @@ static bool __bt_need_to_handle(int event) case BLUETOOTH_EVENT_GATT_SERVER_READ_REQUESTED: case BLUETOOTH_EVENT_GATT_SERVER_NOTIFICATION_COMPLETED: case BLUETOOTH_EVENT_GATT_CLIENT_SERVICE_CHANGED: + case BLUETOOTH_EVENT_TDS_TRANSPORT_DATA_RECEIVED: + case BLUETOOTH_EVENT_TDS_ACTIVATION_RESULT: + case BLUETOOTH_EVENT_TDS_CONTROL_POINT_ENABLED: + case BLUETOOTH_EVENT_TDS_ACTIVATION_INDICATION: return true; default: break; @@ -1937,6 +1993,9 @@ static void __bt_event_proxy(int event, bluetooth_event_param_t *param, void *us if (is_pxp_initialized) _bt_proximity_connection_set_state_changed(param->result, device_addr, TRUE); + /* TDS Seeker */ + _bt_tds_update_seeker_connection_state_changed(param->result, device_addr, TRUE); + g_free(device_addr); device_addr = NULL; break; @@ -1961,6 +2020,9 @@ static void __bt_event_proxy(int event, bluetooth_event_param_t *param, void *us if (is_pxp_initialized) _bt_proximity_connection_set_state_changed(param->result, device_addr, FALSE); + /* TDS Seeker */ + _bt_tds_update_seeker_connection_state_changed(param->result, device_addr, FALSE); + g_free(device_addr); device_addr = NULL; break; @@ -2255,6 +2317,9 @@ static void __bt_event_proxy(int event, bluetooth_event_param_t *param, void *us _bt_convert_address_to_string(&device_addr, &service_change->device_addr); + /* Check if TDS Service removed */ + _bt_tds_check_service_changed(device_addr, service_change); + client = _bt_gatt_get_client(device_addr); g_free(device_addr); device_addr = NULL; @@ -2746,6 +2811,63 @@ static void __bt_event_proxy(int event, bluetooth_event_param_t *param, void *us free(device_addr); /* LCOV_EXCL_STOP */ break; } + case BLUETOOTH_EVENT_TDS_TRANSPORT_DATA_RECEIVED: { + BT_DBG("BLUETOOTH_EVENT_TDS_TRANSPORT_DATA_RECEIVED"); /* LCOV_EXCL_LINE */ + bluetooth_tds_transport_data_info_t *info = NULL; + bluetooth_device_address_t *addr = NULL; + + if (_bt_get_error_code(param->result) == BT_ERROR_NONE) { + info = (bluetooth_tds_transport_data_info_t *)(param->param_data); + _bt_convert_address_to_string(&device_addr, &info->device_address); + _bt_tds_send_complete_transport_data(_bt_get_error_code(param->result), device_addr, + info->data, info->data_length); + } else { + BT_ERR("TDS Complete data Read request failed!!!"); + addr = (bluetooth_device_address_t *)(param->param_data); + _bt_convert_address_to_string(&device_addr, addr); + _bt_tds_send_complete_transport_data(_bt_get_error_code(param->result), device_addr, + NULL, 0); + } + BT_DBG("TDS Complete data blocks received: Remote provider address [%s]", device_addr); + if (device_addr != NULL) + free(device_addr); /* LCOV_EXCL_STOP */ + break; + } + case BLUETOOTH_EVENT_TDS_ACTIVATION_RESULT: { + BT_DBG("BLUETOOTH_EVENT_TDS_ACTIVATION_RESULT"); /* LCOV_EXCL_LINE */ + _bt_convert_address_to_string(&device_addr, + (bluetooth_device_address_t *)(param->param_data)); + + _bt_tds_control_point_activation_result_update(_bt_get_error_code(param->result), device_addr); + + if (device_addr != NULL) + free(device_addr); /* LCOV_EXCL_STOP */ + break; + } + case BLUETOOTH_EVENT_TDS_CONTROL_POINT_ENABLED: { + BT_DBG("BLUETOOTH_EVENT_TDS_CONTROL_POINT_ENABLED"); /* LCOV_EXCL_LINE */ + _bt_convert_address_to_string(&device_addr, + (bluetooth_device_address_t *)(param->param_data)); + + _bt_tds_control_point_enabled_update(_bt_get_error_code(param->result), device_addr); + + if (device_addr != NULL) + free(device_addr); /* LCOV_EXCL_STOP */ + break; + } case BLUETOOTH_EVENT_TDS_ACTIVATION_INDICATION: { + BT_DBG("BLUETOOTH_EVENT_TDS_ACTIVATION_INDICATION"); /* LCOV_EXCL_LINE */ + bluetooth_tds_indication_res_t *tds_act_ind_res = NULL; + tds_act_ind_res = (bluetooth_tds_indication_res_t *)(param->param_data); + + _bt_convert_address_to_string(&device_addr, &tds_act_ind_res->rem_addr); + + BT_ERR("Address [%s]", device_addr); + _bt_tds_control_point_indication_response_update(device_addr, tds_act_ind_res); + + if (device_addr != NULL) + free(device_addr); /* LCOV_EXCL_STOP */ + break; + } default: BT_INFO("Unknown function"); break; @@ -2798,7 +2920,6 @@ static void __bt_le_event_proxy(int event, bluetooth_event_param_t *param, void if (__bt_get_bt_adapter_le_device_scan_info_s(&scan_info, (bluetooth_le_device_info_t *)(param->param_data)) == BT_ERROR_NONE) { ((bt_adapter_le_scan_result_cb)bt_event_slot_container[event_index].callback) (_bt_get_error_code(param->result), scan_info, bt_event_slot_container[event_index].user_data); - __bt_free_bt_adapter_le_device_scan_info_s(scan_info); } else { ((bt_adapter_le_scan_result_cb)bt_event_slot_container[event_index].callback) (_bt_get_error_code(param->result), NULL, bt_event_slot_container[event_index].user_data); @@ -2817,8 +2938,43 @@ static void __bt_le_event_proxy(int event, bluetooth_event_param_t *param, void } } #endif - break; + /* TDS Provider Search: Uses Scan Info */ + if (bt_event_slot_container[BT_EVENT_TDS_PROVIDER_FOUND_RESULT].callback != NULL) { + char *data = NULL; + int data_len = 0; + if (!scan_info) { + /* Get Scan Info */ + if (__bt_get_bt_adapter_le_device_scan_info_s(&scan_info, + (bluetooth_le_device_info_t *)(param->param_data)) != BT_ERROR_NONE) { /* LCOV_EXCL_LINE */ + break; + } + } + _bt_get_ad_data_by_type((char*)scan_info->adv_data, scan_info->adv_data_len, + BT_ADAPTER_LE_ADVERTISING_DATA_TRANSPORT_DISCOVERY, + &data, &data_len); + if (data != NULL) { + BT_DBG("TDS Service available Data length[%d]", data_len); + bt_tds_transport_block_list_s *info = g_malloc0(sizeof(bt_tds_transport_block_list_s)); + + if (_bt_tds_parse_transport_blocks(&info, data, data_len) == BT_ERROR_NONE) { + ((bt_tds_provider_scan_result_cb)bt_event_slot_container[BT_EVENT_TDS_PROVIDER_FOUND_RESULT].callback) /* LCOV_EXCL_LINE */ + (_bt_get_error_code(param->result), + scan_info->remote_address, info, + scan_info, + bt_event_slot_container[BT_EVENT_TDS_PROVIDER_FOUND_RESULT].user_data); + } + __bt_free_tds_scan_result_info_s(info); + + if (data) { + g_free(data); + data = NULL; + } + } + } + if (scan_info) + __bt_free_bt_adapter_le_device_scan_info_s(scan_info); + break; default: break; } @@ -2960,6 +3116,23 @@ static void __bt_free_bt_adapter_le_device_scan_info_s(bt_adapter_le_device_scan scan_info = NULL; } /* LCOV_EXCL_STOP */ +static void __bt_free_tds_scan_result_info_s(bt_tds_transport_block_list_s *discovery_info) +{ + int k; + + if (discovery_info == NULL) + return; + + for (k = 0; k < discovery_info->num_transport_block; k++) { + g_free(discovery_info->data[k]->data); + g_free(discovery_info->data[k]); + } + + g_free(discovery_info); + discovery_info = NULL; + +} + /* LCOV_EXCL_START */ #if !defined(TIZEN_PROFILE_WEARABLE) && !defined(TIZEN_PROFILE_IVI) static int __bt_get_bt_adapter_le_device_discovery_info_s( diff --git a/src/bluetooth-tds.c b/src/bluetooth-tds.c index 16aa5c6..5445053 100644 --- a/src/bluetooth-tds.c +++ b/src/bluetooth-tds.c @@ -32,14 +32,51 @@ BT_CHECK_SUPPORTED_FEATURE(BT_FEATURE_LE); \ } +#define BT_TDS_SERVICE_UUID "00001824-0000-1000-8000-00805f9b34fb" +#define BT_TDS_CONTROL_POINT_UUID "00002abc-0000-1000-8000-00805f9b34fb" +#define BT_TDS_USER_DATA_DESCRIPTOR "00002a56-0000-1000-8000-00805f9b34fb" + typedef struct { unsigned int tds_handle; bluetooth_tds_transport_t transport; bluetooth_tds_transport_state_t state; } bt_tds_provider_s; +typedef struct bt_tds_transport_slot_s { + bool is_seek_ongoing; +} bt_tds_transport_slot_s; + +typedef struct { + char *remote_address; + bool connected; + + const void *connection_callback; + void *conn_cb_user_data; + + const void *complete_data_callback; /* Callback for receiving complete TDS data block */ + void *complete_data_cb_user_data; /* User data for complete TDS data block callback */ + + char *tds_service_handle; /* TDS Primary Service Handle */ + char *tds_control_point; /* TDS Control Point characteristic handle */ + char *tds_control_point_cccd; /* TDS Control Point CCCD handle */ + char *tds_user_data_desciptor; /* TDS User descriptor handle: This will store the Entire TDS block data in GATT Server */ + + bool cccd_enabled; /* TDS Control Point CCCD is enabled or not */ + + bool tds_activation_ongoing; /* TDS Actvation is ongoing or not */ + void *control_point_act_cb; /* TDS Control Point Activation Response callback */ + void *control_point_act_user_data; /* User data for TDS Control Point Activation Response callback*/ + + unsigned char *activation_data; /* TDS Activation data */ + int data_len; +} bt_tds_seeker_s; + gboolean tds_provider_registered = FALSE; GSList *providers_list; +GSList *tds_seeker_list; + +static int __bt_update_tds_transport_data(bluetooth_device_address_t *address, bt_tds_seeker_s *seeker_s); +static void __bt_tds_reset_seeker_data(bt_tds_seeker_s *seeker); int bt_tds_set_transport_activation_requested_cb( bt_tds_activation_requested_cb callback, void *user_data) @@ -303,3 +340,840 @@ int bt_tds_provider_set_manufacturer_data(unsigned char *buf, int length) return error_code; } + +static bt_tds_seeker_s *_bt_tds_seeker_find(const char *remote_address) +{ + GSList *l; + + for (l = tds_seeker_list; l; l = g_slist_next(l)) { + + if (!g_ascii_strcasecmp(((bt_tds_seeker_s *)l->data)->remote_address, remote_address)) + return ((bt_tds_seeker_s *)l->data); + } + return NULL; +} + +static void __bt_tds_free_transport_data(bt_tds_transport_block_list_s *info) +{ + int k; + + if (info == NULL) + return; + + for (k = 0; k < info->num_transport_block; k++) { + g_free(info->data[k]->data); + g_free(info->data[k]); + } + + g_free(info); +} + +void _bt_tds_check_service_changed(char *address, bt_gatt_service_change_t *service_change) +{ + bt_tds_seeker_s *seeker_s = NULL; + int error_code = BLUETOOTH_ERROR_NONE; + bluetooth_device_address_t addr_hex = { {0,} }; + if (!address) { + BT_ERR("Abnormal Result!!"); + return; + } + seeker_s = _bt_tds_seeker_find(address); + BT_DBG("GATT Service state changed [%d]", service_change->change_type); + BT_DBG("GATT Service [%s]", service_change->svc_path); + if (seeker_s) { + if (service_change->change_type == BLUETOOTH_GATT_SERVICE_CHANGE_TYPE_REMOVE) { + if (seeker_s->tds_service_handle && + g_strcmp0(seeker_s->tds_service_handle, service_change->svc_path) == 0) { + BT_ERR("TDS Primary Service removed abnormally from Remote Provider [%s]", address); + __bt_tds_reset_seeker_data(seeker_s); + } + } else { + _bt_convert_address_to_hex(&addr_hex, address); + + /* Attempt to update TDS Service data if service added is TDS service */ + if (__bt_update_tds_transport_data(&addr_hex, seeker_s) == BLUETOOTH_ERROR_NONE) { + BT_INFO("TDS Primary Service added in Remote Provider [%s]", address); + /* Set Service changed Watcher */ + error_code = bluetooth_gatt_set_service_change_watcher(&addr_hex, true); + if (error_code != BLUETOOTH_ERROR_NONE) + BT_ERR("%s(0x%08x)", _bt_convert_error_to_string(error_code), error_code); + } + } + } + BT_DBG("-"); +} + +void _bt_tds_send_complete_transport_data(int result, const char *address, char *data, int data_len) +{ + bt_tds_seeker_s *seeker_s = NULL; + + if (!address) { + BT_ERR("Abnormal Result!!"); + return; + } + + seeker_s = _bt_tds_seeker_find(address); + + if (seeker_s && (seeker_s)->complete_data_callback) { + BT_DBG("Complete TDS Data recv callback is set by app"); + + if (result == BT_ERROR_NONE) { + bt_tds_transport_block_list_s *info = g_malloc0(sizeof(bt_tds_transport_block_list_s)); + + if (_bt_tds_parse_transport_blocks(&info, data, data_len) == BT_ERROR_NONE) { + ((bt_tds_seeker_complete_transport_data_cb)((seeker_s)->complete_data_callback))(result, + address, info, + (seeker_s)->complete_data_cb_user_data); + } else { + BT_ERR("Error parsing data blocks"); + ((bt_tds_seeker_complete_transport_data_cb)((seeker_s)->complete_data_callback))(result, + address, NULL, + (seeker_s)->complete_data_cb_user_data); + } + __bt_tds_free_transport_data(info); + } else { + BT_ERR("TDS Data read failed!!"); + ((bt_tds_seeker_complete_transport_data_cb)((seeker_s)->complete_data_callback))(result, + address, NULL, + (seeker_s)->complete_data_cb_user_data); + } + } +} + +void _bt_tds_control_point_indication_response_update(const char *address, bluetooth_tds_indication_res_t *info) +{ + bt_tds_seeker_s *seeker_s = NULL; + + if (!address) { + BT_ERR("Abnormal Result!!"); + return; + } + + seeker_s = _bt_tds_seeker_find(address); + int result = BT_ERROR_NONE; + int k; + + if (seeker_s) { + BT_DBG("TDS Control point Activation Indication Response"); + BT_DBG("Data length [%d]", info->tds_data.length); + BT_DBG("Address[%s]", address); + + /* DEBUG */ + for (k = 0; k < info->tds_data.length; k++) + BT_DBG("Data[%d] [0x%x]", info->tds_data.data[k]); + + if (seeker_s->tds_activation_ongoing == true) { + (seeker_s)->tds_activation_ongoing = false; + + if (info->tds_data.length < 2) + result = BT_ERROR_OPERATION_FAILED; + else { + if (info->tds_data.data[1] == 0x00) { + BT_DBG("Provider has enabled transport"); + result = BT_ERROR_NONE; + } else + result = BT_ERROR_OPERATION_FAILED; + } + + if ((seeker_s)->control_point_act_cb) + ((bt_tds_control_point_activation_indication_cb)((seeker_s)->control_point_act_cb))(result, + address, info->tds_data.data, info->tds_data.length, (seeker_s)->control_point_act_user_data); + if (seeker_s->activation_data) { + g_free(seeker_s->activation_data); + seeker_s->activation_data = NULL; + } + } + } +} + +void _bt_tds_control_point_activation_result_update(int result, const char *remote_address) +{ + bt_tds_seeker_s *seeker_s = NULL; + if (!remote_address) { + BT_ERR("Abnormal Result!!"); + return; + } + seeker_s = _bt_tds_seeker_find(remote_address); + + if (seeker_s) { + BT_DBG("TDS Control point Activation response [%d] address [%s]", result, remote_address); + + if ((seeker_s)->tds_activation_ongoing == true) { + /* Send Pending Activation Request callback with error */ + if (result != BT_ERROR_NONE) { + (seeker_s)->tds_activation_ongoing = false; + if ((seeker_s)->control_point_act_cb) + ((bt_tds_control_point_activation_indication_cb)((seeker_s)->control_point_act_cb))(BT_ERROR_OPERATION_FAILED, + remote_address, NULL, 0, (seeker_s)->control_point_act_user_data); + if (seeker_s->activation_data) { + g_free(seeker_s->activation_data); + seeker_s->activation_data = NULL; + } + return; + } else + BT_DBG("TDS Activation request successfully accepted by Provider, wait for Indication"); + } else + BT_DBG("TDS Control point activation request is not ongoing"); + } +} + +void _bt_tds_control_point_enabled_update(int result, const char *remote_address) +{ + bt_tds_seeker_s *seeker_s = NULL; + if (!remote_address) { + BT_ERR("Abnormal Result!!"); + return; + } + seeker_s = _bt_tds_seeker_find(remote_address); + int ret = BT_ERROR_NONE; + bluetooth_device_address_t addr_hex = { {0,} }; + _bt_convert_address_to_hex(&addr_hex, remote_address); + + if (seeker_s) { + BT_DBG("TDS Control point Enable result [%d] address [%s]", result, remote_address); + + /* Send Pending Activation Request callback with error */ + if (result != BT_ERROR_NONE) { + (seeker_s)->tds_activation_ongoing = false; + + if ((seeker_s)->control_point_act_cb) + ((bt_tds_control_point_activation_indication_cb)((seeker_s)->control_point_act_cb))(BT_ERROR_OPERATION_FAILED, + remote_address, NULL, 0, (seeker_s)->control_point_act_user_data); + + if (seeker_s->activation_data) { + g_free(seeker_s->activation_data); + seeker_s->activation_data = NULL; + } + return; + } else { + BT_DBG("TDS Control Point enabled successfully!!"); + seeker_s->cccd_enabled = true; + ret = _bt_get_error_code(bluetooth_tds_activate_control_point(&addr_hex, + seeker_s->tds_control_point, seeker_s->activation_data, + seeker_s->data_len)); + if (ret != BT_ERROR_NONE) { + (seeker_s)->tds_activation_ongoing = false; + + if ((seeker_s)->control_point_act_cb) + ((bt_tds_control_point_activation_indication_cb)((seeker_s)->control_point_act_cb))(BT_ERROR_OPERATION_FAILED, + remote_address, NULL, 0, (seeker_s)->control_point_act_user_data); + + if (seeker_s->activation_data) { + g_free(seeker_s->activation_data); + seeker_s->activation_data = NULL; + } + } + BT_DBG("Activation request sent, wait for response and Indication"); + } + } +} + +int _bt_tds_parse_transport_blocks(bt_tds_transport_block_list_s **info, + char *data, int data_len) +{ + int numblocks = 0; + int index = 2; + uint8_t flags; + int k; + GSList *info_list = NULL; + GSList *l = NULL; + + if (data_len < 3) { + BT_ERR("Invalid TDS data, can not process!!"); + return BT_ERROR_INVALID_PARAMETER; + } + + tds_transport_data_s *td; + + while (index < data_len) { + + /* Check if Provider Role is supported by Remote */ + flags = data[index-1]; + + if (!(flags & 0x02)) { + /* Move to Next Block */ + index = index + data[index] + 3; + BT_ERR("TDS Block is not Provider Role"); + continue; + } + + td = g_malloc(sizeof(tds_transport_data_s)); + td->length = data[index]; + + td->data = g_malloc0(td->length); + + /* Fill Transport Block Data excluding Flag and Org ID */ + for (k = 0; k < td->length; k++) + td->data[k] = data[k+index+1]; + + /* Get Transport Name */ + td->transport = data[index -2]; + + /* Get Transport Data Block Incomplete status */ + if (flags & 0x04) + td->is_data_complete = false; + else + td->is_data_complete = true; + + /* Get Transport's current state */ + if (flags & 0x08) + td->state = BT_TDS_TRANSPORT_STATE_ON; + else if (flags & 0x10) + td->state = BT_TDS_TRANSPORT_STATE_UNAVAILABLE; + else + td->state = BT_TDS_TRANSPORT_STATE_OFF; + + /* Move to Next Block */ + index = index + data[index] + 3; + info_list = g_slist_append(info_list, td); + + (*info)->num_transport_block = ++numblocks; + BT_DBG("Transport Block data length [%d] Flags [0x%x] Transport Name [0x%x] Block Num [%d]", + td->length, flags, td->transport, numblocks); + + } + + if (info_list != NULL) { + (*info)->data = (tds_transport_data_s**)g_malloc0(g_slist_length(info_list) * sizeof(tds_transport_data_s)); + for (l = info_list, k = 0; l; l = g_slist_next(l), k++) + (*info)->data[k] = (tds_transport_data_s*)l->data; + return BT_ERROR_NONE; + } + return BT_ERROR_NO_DATA; +} + +static void __bt_tds_reset_seeker_data(bt_tds_seeker_s *seeker) +{ + if ((seeker)->tds_control_point) { + g_free((seeker)->tds_control_point); + (seeker)->tds_control_point = NULL; + } + + if ((seeker)->tds_control_point_cccd) { + g_free((seeker)->tds_control_point_cccd); + (seeker)->tds_control_point_cccd = NULL; + } + + if ((seeker)->tds_user_data_desciptor) { + g_free((seeker)->tds_user_data_desciptor); + (seeker)->tds_user_data_desciptor = NULL; + } + + if ((seeker)->tds_service_handle) { + g_free((seeker)->tds_service_handle); + (seeker)->tds_service_handle = NULL; + } + + if ((seeker)->activation_data) { + g_free((seeker)->activation_data); + (seeker)->activation_data = NULL; + } + + /* Reset CCCD */ + (seeker)->cccd_enabled = false; +} + +void _bt_tds_update_seeker_connection_state_changed(int result, + const char *remote_address, bool connected) +{ + int error_code = BLUETOOTH_ERROR_NONE; + bt_tds_seeker_s *seeker_s = NULL; + BT_DBG("TDS Seeker Connection state changed result [%d] connected [%d]", result, connected ? TRUE : FALSE); + + /* GATT Connect Request failed */ + seeker_s = _bt_tds_seeker_find(remote_address); + if (seeker_s) { + BT_DBG("Seeker 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_tds_reset_seeker_data(seeker_s); + bluetooth_gatt_set_service_change_watcher(&addr_hex, false); + + if ((seeker_s)->connection_callback) + ((bt_tds_seeker_connection_state_changed_cb)(seeker_s)->connection_callback) + (result, remote_address, seeker_s, connected, (seeker_s)->conn_cb_user_data); + return; + } + /* Update TDS Control point values */ + if (connected) { + BT_DBG("Remote Provider connected successfully"); + /* Attempt to update TDS Service data */ + error_code = __bt_update_tds_transport_data(&addr_hex, seeker_s); + if (error_code != BLUETOOTH_ERROR_NONE) + BT_ERR("%s(0x%08x)", _bt_convert_error_to_string(error_code), error_code); + + /* Set Service changed Watcher */ + error_code = bluetooth_gatt_set_service_change_watcher(&addr_hex, true); + if (error_code != BLUETOOTH_ERROR_NONE) + BT_ERR("%s(0x%08x)", _bt_convert_error_to_string(error_code), error_code); + } else { + BT_DBG("Remote Provider disconnected successfully"); + /* Disconnected */ + __bt_tds_reset_seeker_data(seeker_s); + bluetooth_gatt_set_service_change_watcher(&addr_hex, false); + } + (seeker_s)->connected = connected; + + if ((seeker_s)->connection_callback) + ((bt_tds_seeker_connection_state_changed_cb)(seeker_s)->connection_callback) + (result, remote_address, seeker_s, connected, (seeker_s)->conn_cb_user_data); + } else { + BT_DBG("TDS Seeker not found!"); + } +} + +int bt_tds_start_seeking_providers(bt_tds_provider_scan_result_cb cb, void *user_data) +{ + int error_code = BT_ERROR_NONE; + + BT_CHECK_TDS_SUPPORT(); + BT_CHECK_INIT_STATUS(); + BT_CHECK_INPUT_PARAMETER(cb); + BT_DBG("+"); + + /* LE Event handler registered */ + if (_bt_le_adapter_init() != BLUETOOTH_ERROR_NONE) + return BT_ERROR_OPERATION_FAILED; + + /* Start LE discovery with default scan params if already not started */ + if (bluetooth_is_le_scanning() == false) + error_code = _bt_get_error_code(bluetooth_start_le_discovery()); + + if (error_code != BT_ERROR_NONE && + error_code != BT_ERROR_NOW_IN_PROGRESS) { + BT_ERR("%s(0x%08x)", _bt_convert_error_to_string(error_code), + error_code); + } else { + BT_DBG("LE Discovery ON..Wait for TDS Configuration Service from Remote Providers"); + _bt_set_cb(BT_EVENT_TDS_PROVIDER_FOUND_RESULT, cb, user_data); + } + + return error_code; +} + +int bt_tds_stop_seeking_providers(void) +{ + int error_code = BT_ERROR_NONE; + + BT_CHECK_TDS_SUPPORT(); + BT_CHECK_INIT_STATUS(); + BT_DBG("+"); + + if (bluetooth_is_le_scanning() == true) + error_code = _bt_get_error_code(bluetooth_stop_le_discovery()); + if (error_code != BT_ERROR_NONE) { + BT_ERR("%s(0x%08x)", _bt_convert_error_to_string(error_code), + error_code); + } + + _bt_unset_cb(BT_EVENT_TDS_PROVIDER_FOUND_RESULT); + return BT_ERROR_NONE; +} + +static int __bt_update_tds_transport_data(bluetooth_device_address_t *address, bt_tds_seeker_s *seeker_s) +{ + int ret = BLUETOOTH_ERROR_INTERNAL; + bt_gatt_service_property_t service; + int count; + + ret = bluetooth_gatt_get_service_from_uuid(address, BT_TDS_SERVICE_UUID, &service); + if (ret != BLUETOOTH_ERROR_NONE) { + BT_ERR("Failed to find TDS configuration service"); + return ret; + } + + /* Find all characteristics of TDS service and their properties */ + 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_TDS_CONTROL_POINT_UUID)) { + BT_DBG("TDS 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 TDS Control point"); + bluetooth_gatt_free_service_property(&service); + bluetooth_gatt_free_char_property(&characteristic); + bluetooth_gatt_free_desc_property(&desc_property); + goto fail; + } + if ((seeker_s)->tds_control_point) + g_free((seeker_s)->tds_control_point); + (seeker_s)->tds_control_point = g_strdup(characteristic.handle); + + if ((seeker_s)->tds_control_point_cccd) + g_free((seeker_s)->tds_control_point_cccd); + (seeker_s)->tds_control_point_cccd = g_strdup(desc_property.handle); + + BT_DBG("TDS Control point handle [%s]", (seeker_s)->tds_control_point); + BT_DBG("TDS Control point CCCD handle [%s]", (seeker_s)->tds_control_point_cccd); + } else { + /* Fetch Descriptors for the discovered characteristic */ + int c; + int p; + + for (c = 0; c < characteristic.char_desc_handle.count; c++) { + + bt_gatt_char_descriptor_property_t desc_property; + memset(&desc_property, 0x00, sizeof(desc_property)); + + ret = bluetooth_gatt_get_char_descriptor_property( + characteristic.char_desc_handle.handle[c], &desc_property); + + if (ret != BLUETOOTH_ERROR_NONE) { + BT_ERR("Failed to discover Descriptor Property for characteristic [%s]", + characteristic.handle); + bluetooth_gatt_free_service_property(&service); + bluetooth_gatt_free_char_property(&characteristic); + bluetooth_gatt_free_desc_property(&desc_property); + goto fail; + } else { + /* Descriptor property discovered */ + BT_DBG("Descriptor handle [%s]", desc_property.handle); + BT_DBG("Descriptor UUID [%s]", desc_property.uuid); + BT_DBG("Descriptor val len [%d]", desc_property.val_len); + + if (g_strstr_len(desc_property.uuid, -1, BT_TDS_USER_DATA_DESCRIPTOR)) { + BT_DBG("User data descriptor handle discovered"); + if ((seeker_s)->tds_user_data_desciptor) + g_free((seeker_s)->tds_user_data_desciptor); + (seeker_s)->tds_user_data_desciptor = g_strdup(desc_property.handle); + } + + for (p = 0; p < desc_property.val_len; p++) + BT_DBG("Descriptor data[%d] = [0x%x]", p, desc_property.val[p]); + } /* Descriptor property get successful */ + bluetooth_gatt_free_desc_property(&desc_property); + } /* Next Descriptor */ + } /* Control Point characteristic */ + } /* Characteristic property get successful */ + bluetooth_gatt_free_char_property(&characteristic); + } /* Next Charatceristic */ + + if ((seeker_s)->tds_service_handle) + g_free((seeker_s)->tds_service_handle); + + (seeker_s)->tds_service_handle = g_strdup(service.handle); + bluetooth_gatt_free_service_property(&service); + return ret; +fail: + __bt_tds_reset_seeker_data(seeker_s); + return ret; +} + +int bt_tds_seeker_set_connection_state_changed_cb(bt_tds_seeker_h seeker, + bt_tds_seeker_connection_state_changed_cb callback, void *user_data) +{ + bt_tds_seeker_s *seeker_s = (bt_tds_seeker_s *)seeker; + + BT_CHECK_TDS_SUPPORT(); + BT_CHECK_INIT_STATUS(); + BT_CHECK_INPUT_PARAMETER(seeker_s); + BT_CHECK_INPUT_PARAMETER(callback); + + if (_bt_tds_seeker_find(seeker_s->remote_address) == NULL) + return BT_ERROR_NOT_INITIALIZED; + + BT_DBG("Set TDS Seeker Connection State changed callback"); + /* register the callback */ + seeker_s->connection_callback = callback; + seeker_s->conn_cb_user_data = user_data; + + return BT_ERROR_NONE; +} + +int bt_tds_seeker_unset_connection_state_changed_cb(bt_tds_seeker_h seeker) +{ + bt_tds_seeker_s *seeker_s = (bt_tds_seeker_s *)seeker; + + BT_CHECK_TDS_SUPPORT(); + BT_CHECK_INIT_STATUS(); + BT_CHECK_INPUT_PARAMETER(seeker_s); + + if (_bt_tds_seeker_find(seeker_s->remote_address) == NULL) + return BT_ERROR_NOT_INITIALIZED; + + BT_DBG("UnSet TDS Seeker Connection State changed callback"); + /* unregister the callback */ + seeker_s->connection_callback = NULL; + seeker_s->conn_cb_user_data = NULL; + + return BT_ERROR_NONE; +} + +int bt_tds_seeker_activate_control_point(bt_tds_seeker_h seeker, + bt_tds_transport_e transport, unsigned char *buffer, int len, + bt_tds_control_point_activation_indication_cb callback, void *user_data) +{ + bt_tds_seeker_s *seeker_s = (bt_tds_seeker_s *)seeker; + bluetooth_device_address_t addr_hex = { {0,} }; + int ret = BT_ERROR_NONE; + unsigned char *buf; + + BT_CHECK_TDS_SUPPORT(); + BT_CHECK_INIT_STATUS(); + BT_CHECK_INPUT_PARAMETER(seeker_s); + BT_CHECK_INPUT_PARAMETER(buffer); + BT_CHECK_INPUT_PARAMETER(callback); + + if (len > 255) + return BT_ERROR_INVALID_PARAMETER; + + if (_bt_tds_seeker_find(seeker_s->remote_address) == NULL) + return BT_ERROR_NOT_INITIALIZED; + + if (seeker_s->connected == false) + return BT_ERROR_REMOTE_DEVICE_NOT_CONNECTED; + + if (seeker_s->tds_activation_ongoing == true) + return BT_ERROR_NOW_IN_PROGRESS; + + /* Check if both TDS Control Point char & Control Point CCCD are valid or discovered */ + if (!(seeker_s->tds_control_point) || + !(seeker_s->tds_control_point_cccd)) + return BT_ERROR_OPERATION_FAILED; + + BT_DBG("Activate Control Point [%s] transport [%d] current CCCD state [%d]", + seeker_s->remote_address, transport, seeker_s->cccd_enabled); + + _bt_convert_address_to_hex(&addr_hex, seeker_s->remote_address); + + /* Activate Control Point */ + buf = g_malloc0(len+2); + + buf[0] = 0x01; /* Activate control point Opcode */ + buf[1] = transport; /* Activate control point Opcode */ + memcpy(buf+2, buffer, len); + + /* Check if TDS control Point is already enabled or not */ + if (seeker_s->cccd_enabled == FALSE) { + /* Enable TDS Control point CCCD to enable */ + BT_DBG("TDS Control point is disabled, enable it"); + ret = _bt_get_error_code(bluetooth_tds_enable_control_point(&addr_hex, seeker_s->tds_control_point)); + if (ret != BT_ERROR_NONE) { + BT_ERR("%s(0x%08x)", _bt_convert_error_to_string(ret), ret); + g_free(buf); + return ret; + } + } else { + BT_DBG("TDS Control point is already enabled"); + ret = _bt_get_error_code(bluetooth_tds_activate_control_point(&addr_hex, seeker_s->tds_control_point, buf, len)); + if (ret != BT_ERROR_NONE) { + BT_ERR("%s(0x%08x)", _bt_convert_error_to_string(ret), ret); + g_free(buf); + return ret; + } + } + + /* Register the callback */ + seeker_s->tds_activation_ongoing = true; + seeker_s->control_point_act_cb = callback; + seeker_s->control_point_act_user_data = user_data; + + /* Save actvation data and trigger when CCCD is actually enabled */ + seeker_s->activation_data = buf; + seeker_s->data_len = len; + + BT_DBG("-"); + return ret; +} + +int bt_tds_seeker_get_complete_transport_blocks(bt_tds_seeker_h seeker, + bt_tds_seeker_complete_transport_data_cb callback, void *user_data) +{ + bt_tds_seeker_s *seeker_s = (bt_tds_seeker_s *)seeker; + bluetooth_device_address_t addr_hex = { {0,} }; + int ret = BT_ERROR_NONE; + + BT_CHECK_TDS_SUPPORT(); + BT_CHECK_INIT_STATUS(); + BT_CHECK_INPUT_PARAMETER(seeker_s); + BT_CHECK_INPUT_PARAMETER(callback); + + if (_bt_tds_seeker_find(seeker_s->remote_address) == NULL) + return BT_ERROR_NOT_INITIALIZED; + + if (seeker_s->connected == false) + return BT_ERROR_REMOTE_DEVICE_NOT_CONNECTED; + + if (!seeker_s->tds_user_data_desciptor) + return BT_ERROR_OPERATION_FAILED; + + BT_DBG("Set TDS Seeker Get complete callback"); + _bt_convert_address_to_hex(&addr_hex, seeker_s->remote_address); + + /* Read Data from Transport Data block desciptor */ + ret = _bt_get_error_code(bluetooth_tds_read_transport_data(&addr_hex, seeker_s->tds_user_data_desciptor)); + if (ret != BT_ERROR_NONE) { + BT_ERR("%s(0x%08x)", _bt_convert_error_to_string(ret), ret); + return ret; + } + /* register the callback */ + seeker_s->complete_data_callback = callback; + seeker_s->complete_data_cb_user_data = user_data; + + return ret; +} + +int bt_tds_seeker_create(const char *remote_address, bt_tds_seeker_h *seeker) +{ + int error_code = BT_ERROR_NONE; + bt_tds_seeker_s *seeker_s = NULL; + bool connected = false; + bluetooth_device_address_t addr_hex = { {0,} }; + GSList *l; + BT_INFO("+"); + + BT_CHECK_TDS_SUPPORT(); + BT_CHECK_INIT_STATUS(); + BT_CHECK_INPUT_PARAMETER(remote_address); + BT_CHECK_INPUT_PARAMETER(seeker); + + for (l = tds_seeker_list; l; l = g_slist_next(l)) { + bt_tds_seeker_s *c = (bt_tds_seeker_s *)l->data; + + if (!g_ascii_strcasecmp(c->remote_address, remote_address)) { + BT_ERR("TDS Seeker for Remote Provider [%s] is already created", + remote_address); + *seeker = (bt_tds_seeker_h)c; + return BT_ERROR_ALREADY_DONE; + } + } + + seeker_s = g_malloc0(sizeof(*seeker_s)); + if (seeker_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"); + seeker_s->connected = connected; + + _bt_convert_address_to_hex(&addr_hex, remote_address); + + if (seeker_s->connected == true) { + error_code = __bt_update_tds_transport_data(&addr_hex, seeker_s); + if (error_code != BLUETOOTH_ERROR_NONE) { + g_free(seeker_s); + return BT_ERROR_OPERATION_FAILED; + } + error_code = bluetooth_gatt_set_service_change_watcher(&addr_hex, true); + if (error_code != BLUETOOTH_ERROR_NONE) { + g_free(seeker_s); + return BT_ERROR_OPERATION_FAILED; + } + } + + seeker_s->remote_address = g_strdup(remote_address); + if (seeker_s->remote_address == NULL) { + free(seeker_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; + } + + seeker_s->cccd_enabled = FALSE; + seeker_s->activation_data = NULL; + + tds_seeker_list = g_slist_append(tds_seeker_list, seeker_s); + *seeker = (bt_tds_seeker_h)seeker_s; + + BT_DBG("TDS Seeker Created"); + return BT_ERROR_NONE; +} + +int bt_tds_seeker_destroy(bt_tds_seeker_h seeker) +{ + bt_tds_seeker_s *seeker_s = (bt_tds_seeker_s *)seeker; + + BT_CHECK_TDS_SUPPORT(); + BT_CHECK_INIT_STATUS(); + BT_CHECK_INPUT_PARAMETER(seeker_s); + + if (_bt_tds_seeker_find(seeker_s->remote_address) == NULL) + return BT_ERROR_NOT_INITIALIZED; + + BT_DBG("TDS Seeker destroy Remote Provider [%s]", seeker_s->remote_address); + __bt_tds_reset_seeker_data(seeker_s); + + tds_seeker_list = g_slist_remove(tds_seeker_list, seeker_s); + g_free(seeker_s); + seeker_s = NULL; + + return BT_ERROR_NONE; +} + +int bt_tds_seeker_connect(bt_tds_seeker_h seeker) +{ + int error_code; + bt_tds_seeker_s *seeker_s = (bt_tds_seeker_s *)seeker; + + BT_CHECK_TDS_SUPPORT(); + BT_CHECK_INIT_STATUS(); + BT_CHECK_INPUT_PARAMETER(seeker_s); + + if (_bt_tds_seeker_find(seeker_s->remote_address) == NULL) + return BT_ERROR_NOT_INITIALIZED; + + if (seeker_s->connected) + return BT_ERROR_NONE; + + BT_DBG("TDS Seeker connect Remote Provider [%s]", seeker_s->remote_address); + error_code = bt_gatt_connect(seeker_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_tds_seeker_disconnect(bt_tds_seeker_h seeker) +{ + int error_code; + bt_tds_seeker_s *seeker_s = (bt_tds_seeker_s *)seeker; + + BT_CHECK_TDS_SUPPORT(); + BT_CHECK_INIT_STATUS(); + BT_CHECK_INPUT_PARAMETER(seeker_s); + + if (_bt_tds_seeker_find(seeker_s->remote_address) == NULL) + return BT_ERROR_NOT_INITIALIZED; + + if (seeker_s->connected == false) { + BT_ERR("Remote Provider [%s] is not conencted", seeker_s->remote_address); + return BT_ERROR_OPERATION_FAILED; + } + + BT_DBG("TDS Seeker Disconnect Remote Provider [%s]", seeker_s->remote_address); + error_code = bt_gatt_disconnect(seeker_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; +} diff --git a/test/bt_unit_test.c b/test/bt_unit_test.c index 82d0274..dffe4c5 100644 --- a/test/bt_unit_test.c +++ b/test/bt_unit_test.c @@ -125,6 +125,7 @@ bt_scan_filter_h pxp_scan_filter; bt_tds_provider_h provider; char *tds_act_address; +bt_tds_seeker_h seeker; #ifdef TIZEN_FEATURE_ENABLE_LEGACY_GATT_CLIENT bt_gatt_attribute_h service_clone[MAX_SERVICES]; @@ -186,8 +187,10 @@ tc_table_t tc_main[] = { #endif {"etc.(Automated test, AppControl)" , BT_UNIT_TEST_TABLE_ETC}, - {"TDS" - , BT_UNIT_TEST_TABLE_TDS}, + {"TDS Provider" + , BT_UNIT_TEST_TABLE_TDS_PROVIDER}, + {"TDS Seeker" + , BT_UNIT_TEST_TABLE_TDS_SEEKER}, {"Initialize All" , BT_UNIT_TEST_FUNCTION_INITIALIZE_ALL}, {"FINISH" @@ -1098,8 +1101,8 @@ tc_table_t tc_pbap_client[] = { }; #endif -tc_table_t tc_tds[] = { - /* TDS functions */ +tc_table_t tc_tds_provider[] = { + /* TDS provider functions */ {"BACK" , BT_UNIT_TEST_FUNCTION_BACK}, {"TDS Provider(Register)" @@ -1123,6 +1126,34 @@ tc_table_t tc_tds[] = { {NULL , 0x0000}, }; +tc_table_t tc_tds_seeker[] = { + /* TDS Seeker functions */ + {"BACK" + , BT_UNIT_TEST_FUNCTION_BACK}, + {"TDS Seeker Start Discovering Provider" + , BT_UNIT_TEST_FUNCTION_TDS_START_DISCOVERING_PROVIDER}, + {"TDS Seeker Stop Discovering Provider" + , BT_UNIT_TEST_FUNCTION_TDS_STOP_DISCOVERING_PROVIDER}, + {"TDS Seeker(Create)" + , BT_UNIT_TEST_FUNCTION_TDS_SEEKER_CREATE}, + {"TDS Seeker(Destroy)" + , BT_UNIT_TEST_FUNCTION_TDS_SEEKER_DESTROY}, + {"TDS Set Seeker Connection cb" + , BT_UNIT_TEST_FUNCTION_TDS_SEEKER_SET_CONNECTION_CALLBACK}, + {"TDS Seeker Connect(remote)" + , BT_UNIT_TEST_FUNCTION_TDS_SEEKER_CONNECT}, + {"TDS Seeker DisConnect(remote)" + , BT_UNIT_TEST_FUNCTION_TDS_SEEKER_DISCONNECT}, + {"TDS UnSet Seeker Connection cb" + , BT_UNIT_TEST_FUNCTION_TDS_SEEKER_UNSET_CONNECTION_CALLBACK}, + {"TDS Read Complete Transport Data (remote)" + , BT_UNIT_TEST_FUNCTION_TDS_SEEKER_GET_COMPLETE_DATA}, + {"TDS Activate Control Point (remote)" + , BT_UNIT_TEST_FUNCTION_TDS_SEEKER_ACTIVATE_CONTROL_POINT}, + {NULL , 0x0000}, +}; + + tc_table_t tc_automated_test[] = { /* Automated test Functions*/ {"BACK" , BT_UNIT_TEST_FUNCTION_BACK}, @@ -1220,8 +1251,11 @@ void tc_usage_print(void) __bt_initialize_all(); TC_PRT("Key 0 : usage BACK"); return; - case BT_UNIT_TEST_TABLE_TDS: - tc_table = tc_tds; + case BT_UNIT_TEST_TABLE_TDS_PROVIDER: + tc_table = tc_tds_provider; + break; + case BT_UNIT_TEST_TABLE_TDS_SEEKER: + tc_table = tc_tds_seeker; break; case BT_UNIT_TEST_TABLE_MAIN: default: @@ -3075,6 +3109,85 @@ void __bt_repeat_test_adapter_state_changed_cb(int result, bt_onoff_cnt++; } +/* TDS Seeker Callbacks */ +static void __bt_tds_provider_scan_result_cb(int result, const char *remote_address, + bt_tds_transport_block_list_s *info, bt_adapter_le_device_scan_result_info_s *scan_info, + void *user_data) +{ + int k; + int l; + TC_PRT("__bt_tds_provider_scan_result_cb"); + TC_PRT("result: %s", __bt_get_error_message(result)); + + TC_PRT("Result: %s", __bt_get_error_message(result)); + TC_PRT("Remote addr [%s]", remote_address); + TC_PRT("Number of Transport Block [%d]", info->num_transport_block); + + if (result == BT_ERROR_NONE) { + for (k = 0; k < info->num_transport_block; k++) { + TC_PRT("Block Num[%d] Transport Name [%d]", k+1, info->data[k]->transport); + TC_PRT("Block Num[%d] Transport state [%d]", k+1, info->data[k]->state); + TC_PRT("Block Num[%d] Is Data complete [%d]", k+1, info->data[k]->is_data_complete); + TC_PRT("Block Num[%d] Length of TDS Block data [%d]", k+1, info->data[k]->length); + + for (l = 0; l < info->data[k]->length; l++) + TC_PRT("Transport Specific data [%d] = [0x%x]", l, info->data[k]->data[l]); + } + } +} + +static void __bt_tds_seeker_connection_state_changed_cb(int result, const char *remote_address, + bt_tds_seeker_h seeker, bool connected, void *user_data) +{ + TC_PRT("Result: %s", __bt_get_error_message(result)); + if (result == BT_ERROR_NONE) { + if (connected) + TC_PRT("TDS Seeker connected(address = %s)", remote_address); + else + TC_PRT("TDS Seeker Disconnected (address = %s)", remote_address); + } else + BT_ERR("TDS Connection failed!"); +} + +static void __bt_tds_seeker_complete_transport_data_cb(int result, const char *remote_address, + bt_tds_transport_block_list_s *info, void *user_data) +{ + int k; + int l; + TC_PRT("__bt_tds_seeker_complete_transport_data_cb"); + TC_PRT("Result: %s", __bt_get_error_message(result)); + TC_PRT("Remote addr [%s]", remote_address); + + if (result == BT_ERROR_NONE) { + TC_PRT("Number of Transport Block [%d]", info->num_transport_block); + for (k = 0; k < info->num_transport_block; k++) { + TC_PRT("Block Num[%d] Transport Name [%d]", k+1, info->data[k]->transport); + TC_PRT("Block Num[%d] Transport state [%d]", k+1, info->data[k]->state); + TC_PRT("Block Num[%d] Is Data complete [%d]", k+1, info->data[k]->is_data_complete); + TC_PRT("Block Num[%d] Length of TDS Block data [%d]", k+1, info->data[k]->length); + + for (l = 0; l < info->data[k]->length; l++) + TC_PRT("Transport Specific data [%d] = [0x%x]", l, info->data[k]->data[l]); + } + } else + BT_ERR("TDS Data receive request failed!"); +} + +static void __bt_tds_control_point_activation_result_cb(int result, const char *remote_address, + unsigned char *data, int length, void *user_data) +{ + int k; + TC_PRT("__bt_tds_control_point_activation_result_cb"); + TC_PRT("Result [%d]", result); + TC_PRT("Address[%s]", remote_address); + + if (result == BT_ERROR_NONE) { + TC_PRT("Data length [%d]", length); + for (k = 0; k < length; k++) + TC_PRT("Data[%d] [0x%x]", k, data[k]); + } +} + static void __bt_initialize_all(void) { int ret; @@ -9626,7 +9739,7 @@ int test_input_callback(void *data) break; } #endif - case BT_UNIT_TEST_TABLE_TDS: { + case BT_UNIT_TEST_TABLE_TDS_PROVIDER: { switch (test_id) { case BT_UNIT_TEST_FUNCTION_TDS_PROVIDER_REGISTER: { ret = bt_tds_provider_register(); @@ -9694,6 +9807,85 @@ int test_input_callback(void *data) } break; } + case BT_UNIT_TEST_TABLE_TDS_SEEKER: { + switch (test_id) { + case BT_UNIT_TEST_FUNCTION_TDS_START_DISCOVERING_PROVIDER: { + ret = bt_tds_start_seeking_providers(__bt_tds_provider_scan_result_cb, NULL); + TC_PRT("returns %s\n", __bt_get_error_message(ret)); + break; + } + case BT_UNIT_TEST_FUNCTION_TDS_STOP_DISCOVERING_PROVIDER: { + ret = bt_tds_stop_seeking_providers(); + TC_PRT("returns %s\n", __bt_get_error_message(ret)); + break; + } + case BT_UNIT_TEST_FUNCTION_TDS_SEEKER_CREATE: { + if (seeker) + seeker = NULL; + ret = bt_tds_seeker_create(remote_addr, &seeker); + TC_PRT("returns %s\n", __bt_get_error_message(ret)); + break; + } + case BT_UNIT_TEST_FUNCTION_TDS_SEEKER_DESTROY: { + if (seeker) { + ret = bt_tds_seeker_destroy(seeker); + TC_PRT("returns %s\n", __bt_get_error_message(ret)); + } + break; + } + case BT_UNIT_TEST_FUNCTION_TDS_SEEKER_SET_CONNECTION_CALLBACK: { + if (seeker) { + ret = bt_tds_seeker_set_connection_state_changed_cb(seeker, + __bt_tds_seeker_connection_state_changed_cb, NULL); + TC_PRT("returns %s\n", __bt_get_error_message(ret)); + } + break; + } + case BT_UNIT_TEST_FUNCTION_TDS_SEEKER_CONNECT: { + if (seeker) { + ret = bt_tds_seeker_connect(seeker); + TC_PRT("returns %s\n", __bt_get_error_message(ret)); + } + break; + } + case BT_UNIT_TEST_FUNCTION_TDS_SEEKER_DISCONNECT: { + if (seeker) { + ret = bt_tds_seeker_disconnect(seeker); + TC_PRT("returns %s\n", __bt_get_error_message(ret)); + } + break; + } + case BT_UNIT_TEST_FUNCTION_TDS_SEEKER_UNSET_CONNECTION_CALLBACK: { + if (seeker) { + ret = bt_tds_seeker_unset_connection_state_changed_cb(seeker); + TC_PRT("returns %s\n", __bt_get_error_message(ret)); + } + break; + } + case BT_UNIT_TEST_FUNCTION_TDS_SEEKER_GET_COMPLETE_DATA: { + if (seeker) { + ret = bt_tds_seeker_get_complete_transport_blocks(seeker, + __bt_tds_seeker_complete_transport_data_cb, NULL); + TC_PRT("returns %s\n", __bt_get_error_message(ret)); + } + break; + } + case BT_UNIT_TEST_FUNCTION_TDS_SEEKER_ACTIVATE_CONTROL_POINT: { + if (seeker) { + unsigned char buf[] = {0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, /* Mac */ + 0x0A, 0x0B}; /* Channel Info */ + bt_tds_transport_e transport = BT_TDS_TRANSPORT_CUSTOM; + ret = bt_tds_seeker_activate_control_point(seeker, transport, buf, sizeof(buf), + __bt_tds_control_point_activation_result_cb, NULL); + TC_PRT("returns %s\n", __bt_get_error_message(ret)); + } + break; + } + default: + break; + } + break; + } case BT_UNIT_TEST_TABLE_ETC: { static unsigned int delay = 0; bt_onoff_cnt = 0; diff --git a/test/bt_unit_test.h b/test/bt_unit_test.h index 537f30c..f754880 100644 --- a/test/bt_unit_test.h +++ b/test/bt_unit_test.h @@ -53,7 +53,8 @@ typedef enum { #endif BT_UNIT_TEST_TABLE_ETC, BT_UNIT_TEST_FUNCTION_INITIALIZE_ALL, - BT_UNIT_TEST_TABLE_TDS, + BT_UNIT_TEST_TABLE_TDS_PROVIDER, + BT_UNIT_TEST_TABLE_TDS_SEEKER, BT_UNIT_TEST_TABLE_FINISH = 0xFF, } bt_unit_test_table_e; @@ -464,6 +465,7 @@ typedef enum { BT_UNIT_TEST_FUNCTION_PXP_MONITOR_READ_IMMEDIATE_ALERT, BT_UNIT_TEST_FUNCTION_PXP_MONITOR_READ_SIGNAL_LEVEL, + /* TDS Provider */ BT_UNIT_TEST_FUNCTION_TDS_PROVIDER_REGISTER = 1, BT_UNIT_TEST_FUNCTION_TDS_PROVIDER_UNREGISTER, BT_UNIT_TEST_FUNCTION_TDS_PROVIDER_SET_ACT_REQ_CB, @@ -473,6 +475,19 @@ typedef enum { BT_UNIT_TEST_FUNCTION_TDS_CUSTOM_PROVIDER_SET_TRANSPORT_DATA, BT_UNIT_TEST_FUNCTION_TDS_CUSTOM_PROVIDER_SET_MANUF_DATA, BT_UNIT_TEST_FUNCTION_TDS_CUSTOM_PROVIDER_SEND_ACTIVATION_RESP, + + /* TDS Seeker */ + BT_UNIT_TEST_FUNCTION_TDS_START_DISCOVERING_PROVIDER = 1, + BT_UNIT_TEST_FUNCTION_TDS_STOP_DISCOVERING_PROVIDER, + BT_UNIT_TEST_FUNCTION_TDS_SEEKER_CREATE, + BT_UNIT_TEST_FUNCTION_TDS_SEEKER_DESTROY, + BT_UNIT_TEST_FUNCTION_TDS_SEEKER_SET_CONNECTION_CALLBACK, + BT_UNIT_TEST_FUNCTION_TDS_SEEKER_CONNECT, + BT_UNIT_TEST_FUNCTION_TDS_SEEKER_DISCONNECT, + BT_UNIT_TEST_FUNCTION_TDS_SEEKER_UNSET_CONNECTION_CALLBACK, + BT_UNIT_TEST_FUNCTION_TDS_SEEKER_GET_COMPLETE_DATA, + BT_UNIT_TEST_FUNCTION_TDS_SEEKER_ACTIVATE_CONTROL_POINT, + BT_UNIT_TEST_FUNCTION_ACTIVATE_FLAG_TO_SET_PARAMETERS = 0XFF, } bt_unit_test_function_e;