forked from espressif/esp-idf
Merge branch 'feature/support_bt_pba_client' into 'master'
feature(bt/bluedroid): Support bt pba client Closes BT-3326 and IDFGH-10260 See merge request espressif/esp-idf!34260
This commit is contained in:
@@ -146,6 +146,7 @@ if(CONFIG_BT_ENABLED)
|
||||
host/bluedroid/bta/hd/include
|
||||
host/bluedroid/bta/hh/include
|
||||
host/bluedroid/bta/jv/include
|
||||
host/bluedroid/bta/pba/include
|
||||
host/bluedroid/bta/sdp/include
|
||||
host/bluedroid/bta/sys/include
|
||||
host/bluedroid/device/include
|
||||
@@ -194,6 +195,7 @@ if(CONFIG_BT_ENABLED)
|
||||
"host/bluedroid/api/esp_spp_api.c"
|
||||
"host/bluedroid/api/esp_sdp_api.c"
|
||||
"host/bluedroid/api/esp_l2cap_bt_api.c"
|
||||
"host/bluedroid/api/esp_pbac_api.c"
|
||||
"host/bluedroid/bta/ar/bta_ar.c"
|
||||
"host/bluedroid/bta/av/bta_av_aact.c"
|
||||
"host/bluedroid/bta/av/bta_av_act.c"
|
||||
@@ -257,6 +259,10 @@ if(CONFIG_BT_ENABLED)
|
||||
"host/bluedroid/bta/hf_client/bta_hf_client_rfc.c"
|
||||
"host/bluedroid/bta/hf_client/bta_hf_client_sco.c"
|
||||
"host/bluedroid/bta/hf_client/bta_hf_client_sdp.c"
|
||||
"host/bluedroid/bta/pba/bta_pba_client_act.c"
|
||||
"host/bluedroid/bta/pba/bta_pba_client_api.c"
|
||||
"host/bluedroid/bta/pba/bta_pba_client_main.c"
|
||||
"host/bluedroid/bta/pba/bta_pba_client_sdp.c"
|
||||
"host/bluedroid/bta/sdp/bta_sdp.c"
|
||||
"host/bluedroid/bta/sdp/bta_sdp_act.c"
|
||||
"host/bluedroid/bta/sdp/bta_sdp_api.c"
|
||||
@@ -299,6 +305,7 @@ if(CONFIG_BT_ENABLED)
|
||||
"host/bluedroid/btc/profile/std/spp/btc_spp.c"
|
||||
"host/bluedroid/btc/profile/std/sdp/btc_sdp.c"
|
||||
"host/bluedroid/btc/profile/std/l2cap/btc_l2cap.c"
|
||||
"host/bluedroid/btc/profile/std/pba/btc_pba_client.c"
|
||||
"host/bluedroid/device/bdaddr.c"
|
||||
"host/bluedroid/device/controller.c"
|
||||
"host/bluedroid/device/interop.c"
|
||||
@@ -411,6 +418,7 @@ if(CONFIG_BT_ENABLED)
|
||||
"host/bluedroid/stack/obex/obex_api.c"
|
||||
"host/bluedroid/stack/obex/obex_main.c"
|
||||
"host/bluedroid/stack/obex/obex_tl_l2cap.c"
|
||||
"host/bluedroid/stack/obex/obex_tl_rfcomm.c"
|
||||
"host/bluedroid/stack/rfcomm/port_api.c"
|
||||
"host/bluedroid/stack/rfcomm/port_rfc.c"
|
||||
"host/bluedroid/stack/rfcomm/port_utils.c"
|
||||
|
@@ -57,6 +57,9 @@
|
||||
#if BTC_HH_INCLUDED == TRUE
|
||||
#include "btc_hh.h"
|
||||
#endif /* BTC_HH_INCLUDED */
|
||||
#if BTC_PBA_CLIENT_INCLUDED
|
||||
#include "btc_pba_client.h"
|
||||
#endif
|
||||
#endif /* #if CLASSIC_BT_INCLUDED */
|
||||
#endif
|
||||
|
||||
@@ -155,6 +158,9 @@ static const btc_func_t profile_tab[BTC_PID_NUM] = {
|
||||
#if BTC_HH_INCLUDED
|
||||
[BTC_PID_HH] = {btc_hh_call_handler, btc_hh_cb_handler },
|
||||
#endif
|
||||
#if BTC_PBA_CLIENT_INCLUDED
|
||||
[BTC_PID_PBA_CLIENT] = {btc_pba_client_call_handler, btc_pba_client_cb_handler},
|
||||
#endif
|
||||
#endif /* #if CLASSIC_BT_INCLUDED */
|
||||
#endif
|
||||
#if CONFIG_BLE_MESH
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -67,6 +67,9 @@ typedef enum {
|
||||
#if (BTC_HF_CLIENT_INCLUDED == TRUE)
|
||||
BTC_PID_HF_CLIENT,
|
||||
#endif /* BTC_HF_CLIENT_INCLUDED */
|
||||
#if (BTC_PBA_CLIENT_INCLUDED == TRUE)
|
||||
BTC_PID_PBA_CLIENT,
|
||||
#endif /* BTC_PBA_CLIENT_INCLUDED */
|
||||
#endif /* CLASSIC_BT_INCLUDED */
|
||||
#if CONFIG_BLE_MESH
|
||||
BTC_PID_PROV,
|
||||
@@ -123,8 +126,8 @@ extern "C" {
|
||||
/**
|
||||
* transfer an message to another module in the different task.
|
||||
* @param msg message
|
||||
* @param arg paramter
|
||||
* @param arg_len length of paramter
|
||||
* @param arg parameter
|
||||
* @param arg_len length of parameter
|
||||
* @param copy_func deep copy function
|
||||
* @param free_func deep free function
|
||||
* @return BT_STATUS_SUCCESS: success
|
||||
@@ -134,7 +137,7 @@ bt_status_t btc_transfer_context(btc_msg_t *msg, void *arg, int arg_len, btc_arg
|
||||
btc_arg_deep_free_t free_func);
|
||||
|
||||
/**
|
||||
* transfer an message to another module in tha same task.
|
||||
* transfer an message to another module in the same task.
|
||||
* @param msg message
|
||||
* @return BT_STATUS_SUCCESS: success
|
||||
* others: fail
|
||||
|
@@ -191,6 +191,29 @@ config BT_HID_DEVICE_ENABLED
|
||||
help
|
||||
This enables the BT HID Device
|
||||
|
||||
menuconfig BT_PBAC_ENABLED
|
||||
bool "PBAP Client"
|
||||
depends on BT_CLASSIC_ENABLED
|
||||
default n
|
||||
select BT_GOEPC_ENABLED
|
||||
help
|
||||
This enables the Phone Book Access Profile Client
|
||||
|
||||
config BT_PBAC_SUPPORTED_FEAT
|
||||
hex "PBAP Client Supported Features"
|
||||
depends on BT_PBAC_ENABLED
|
||||
default 0x000003FF
|
||||
help
|
||||
Set the supported features of PBAP Client, the default value is supported all features
|
||||
|
||||
config BT_PBAC_PREFERRED_MTU
|
||||
int "PBAP Client Preferred MTU"
|
||||
depends on BT_PBAC_ENABLED
|
||||
default 0
|
||||
help
|
||||
MTU is limited by the max MTU of transport layer, and should not be smaller than 255,
|
||||
but can be set to zero to use a default MTU of transport layer
|
||||
|
||||
config BT_GOEPC_ENABLED
|
||||
bool
|
||||
depends on BT_CLASSIC_ENABLED
|
||||
|
251
components/bt/host/bluedroid/api/esp_pbac_api.c
Normal file
251
components/bt/host/bluedroid/api/esp_pbac_api.c
Normal file
@@ -0,0 +1,251 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include "esp_err.h"
|
||||
#include "esp_bt_main.h"
|
||||
#include "esp_pbac_api.h"
|
||||
#include "btc/btc_manage.h"
|
||||
#include "btc_pba_client.h"
|
||||
|
||||
#if BTC_PBA_CLIENT_INCLUDED
|
||||
|
||||
esp_err_t esp_pbac_init(void)
|
||||
{
|
||||
if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
btc_msg_t msg;
|
||||
|
||||
msg.sig = BTC_SIG_API_CALL;
|
||||
msg.pid = BTC_PID_PBA_CLIENT;
|
||||
msg.act = BTC_PBA_CLIENT_INIT_EVT;
|
||||
|
||||
/* Switch to BTC context */
|
||||
bt_status_t stat = btc_transfer_context(&msg, NULL, 0, NULL, NULL);
|
||||
return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
|
||||
}
|
||||
|
||||
esp_err_t esp_pbac_deinit(void)
|
||||
{
|
||||
if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
btc_msg_t msg;
|
||||
|
||||
msg.sig = BTC_SIG_API_CALL;
|
||||
msg.pid = BTC_PID_PBA_CLIENT;
|
||||
msg.act = BTC_PBA_CLIENT_DEINIT_EVT;
|
||||
|
||||
/* Switch to BTC context */
|
||||
bt_status_t stat = btc_transfer_context(&msg, NULL, 0, NULL, NULL);
|
||||
return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
|
||||
}
|
||||
|
||||
esp_err_t esp_pbac_register_callback(esp_pbac_callback_t callback)
|
||||
{
|
||||
if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
if (callback == NULL) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
btc_profile_cb_set(BTC_PID_PBA_CLIENT, callback);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_pbac_connect(esp_bd_addr_t bd_addr)
|
||||
{
|
||||
if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
if (bd_addr == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
btc_msg_t msg;
|
||||
msg.sig = BTC_SIG_API_CALL;
|
||||
msg.pid = BTC_PID_PBA_CLIENT;
|
||||
msg.act = BTC_PBA_CLIENT_CONNECT_EVT;
|
||||
|
||||
btc_pba_client_args_t args = {0};
|
||||
memcpy(args.connect.bd_addr.address, bd_addr, sizeof(esp_bd_addr_t));
|
||||
|
||||
/* Switch to BTC context */
|
||||
bt_status_t stat = btc_transfer_context(&msg, &args, sizeof(btc_pba_client_args_t), NULL, NULL);
|
||||
return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
|
||||
}
|
||||
|
||||
esp_err_t esp_pbac_disconnect(esp_pbac_conn_hdl_t handle)
|
||||
{
|
||||
if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
if (handle == ESP_PBAC_INVALID_HANDLE) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
btc_msg_t msg;
|
||||
msg.sig = BTC_SIG_API_CALL;
|
||||
msg.pid = BTC_PID_PBA_CLIENT;
|
||||
msg.act = BTC_PBA_CLIENT_DISCONNECT_EVT;
|
||||
|
||||
btc_pba_client_args_t args = {0};
|
||||
args.disconnect.handle = handle;
|
||||
|
||||
/* Switch to BTC context */
|
||||
bt_status_t stat = btc_transfer_context(&msg, &args, sizeof(btc_pba_client_args_t), NULL, NULL);
|
||||
return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
|
||||
}
|
||||
|
||||
|
||||
esp_err_t esp_pbac_pull_phone_book(esp_pbac_conn_hdl_t handle, const char *name, esp_pbac_pull_phone_book_app_param_t *app_param)
|
||||
{
|
||||
if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
if (handle == ESP_PBAC_INVALID_HANDLE || name == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
btc_msg_t msg;
|
||||
msg.sig = BTC_SIG_API_CALL;
|
||||
msg.pid = BTC_PID_PBA_CLIENT;
|
||||
msg.act = BTC_PBA_CLIENT_PULL_PHONE_BOOK_EVT;
|
||||
|
||||
btc_pba_client_args_t args = {0};
|
||||
args.pull_phone_book.handle = handle;
|
||||
args.pull_phone_book.name = (char *)name;
|
||||
if (app_param != NULL) {
|
||||
args.pull_phone_book.include_app_param = true;
|
||||
memcpy(&args.pull_phone_book.app_param, app_param, sizeof(esp_pbac_pull_phone_book_app_param_t));
|
||||
}
|
||||
else {
|
||||
args.pull_phone_book.include_app_param = false;
|
||||
}
|
||||
|
||||
/* Switch to BTC context */
|
||||
bt_status_t stat = btc_transfer_context(&msg, &args, sizeof(btc_pba_client_args_t), btc_pba_client_args_deep_copy, btc_pba_client_args_deep_free);
|
||||
return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
|
||||
}
|
||||
|
||||
esp_err_t esp_pbac_set_phone_book(esp_pbac_conn_hdl_t handle, esp_pbac_set_phone_book_flags_t flags, const char *name)
|
||||
{
|
||||
if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
/* since ESP_PBAC_SET_PHONE_BOOK_FLAGS_ROOT is equal to ESP_PBAC_SET_PHONE_BOOK_FLAGS_DOWN, we dont check XXX_DOWN */
|
||||
if (handle == ESP_PBAC_INVALID_HANDLE || (flags != ESP_PBAC_SET_PHONE_BOOK_FLAGS_ROOT && flags != ESP_PBAC_SET_PHONE_BOOK_FLAGS_UP)) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
btc_msg_t msg;
|
||||
msg.sig = BTC_SIG_API_CALL;
|
||||
msg.pid = BTC_PID_PBA_CLIENT;
|
||||
msg.act = BTC_PBA_CLIENT_SET_PHONE_BOOK_EVT;
|
||||
|
||||
btc_pba_client_args_t args = {0};
|
||||
args.set_phone_book.handle = handle;
|
||||
args.set_phone_book.flags = flags;
|
||||
/* set phone book name is allowed to be NULL */
|
||||
args.set_phone_book.name = (char *)name;
|
||||
|
||||
/* Switch to BTC context */
|
||||
bt_status_t stat = btc_transfer_context(&msg, &args, sizeof(btc_pba_client_args_t), btc_pba_client_args_deep_copy, btc_pba_client_args_deep_free);
|
||||
return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
|
||||
}
|
||||
|
||||
esp_err_t esp_pbac_set_phone_book2(esp_pbac_conn_hdl_t handle, const char *path)
|
||||
{
|
||||
if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
btc_msg_t msg;
|
||||
msg.sig = BTC_SIG_API_CALL;
|
||||
msg.pid = BTC_PID_PBA_CLIENT;
|
||||
msg.act = BTC_PBA_CLIENT_SET_PHONE_BOOK2_EVT;
|
||||
|
||||
btc_pba_client_args_t args = {0};
|
||||
args.set_phone_book.handle = handle;
|
||||
args.set_phone_book.name = (char *)path;
|
||||
|
||||
/* Switch to BTC context */
|
||||
bt_status_t stat = btc_transfer_context(&msg, &args, sizeof(btc_pba_client_args_t), btc_pba_client_args_deep_copy, btc_pba_client_args_deep_free);
|
||||
return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
|
||||
}
|
||||
|
||||
esp_err_t esp_pbac_pull_vcard_listing(esp_pbac_conn_hdl_t handle, const char *name, esp_pbac_pull_vcard_listing_app_param_t *app_param)
|
||||
{
|
||||
if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
if (handle == ESP_PBAC_INVALID_HANDLE || name == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
btc_msg_t msg;
|
||||
msg.sig = BTC_SIG_API_CALL;
|
||||
msg.pid = BTC_PID_PBA_CLIENT;
|
||||
msg.act = BTC_PBA_CLIENT_PULL_VCARD_LISTING_EVT;
|
||||
|
||||
btc_pba_client_args_t args = {0};
|
||||
args.pull_vcard_listing.handle = handle;
|
||||
args.pull_vcard_listing.name = (char *)name;
|
||||
if (app_param != NULL) {
|
||||
args.pull_vcard_listing.include_app_param = true;
|
||||
memcpy(&args.pull_vcard_listing.app_param, app_param, sizeof(esp_pbac_pull_vcard_listing_app_param_t));
|
||||
}
|
||||
else {
|
||||
args.pull_vcard_listing.include_app_param = false;
|
||||
}
|
||||
|
||||
/* Switch to BTC context */
|
||||
bt_status_t stat = btc_transfer_context(&msg, &args, sizeof(btc_pba_client_args_t), btc_pba_client_args_deep_copy, btc_pba_client_args_deep_free);
|
||||
return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
|
||||
}
|
||||
|
||||
esp_err_t esp_pbac_pull_vcard_entry(esp_pbac_conn_hdl_t handle, const char *name, esp_pbac_pull_vcard_entry_app_param_t *app_param)
|
||||
{
|
||||
if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
if (handle == ESP_PBAC_INVALID_HANDLE || name == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
btc_msg_t msg;
|
||||
msg.sig = BTC_SIG_API_CALL;
|
||||
msg.pid = BTC_PID_PBA_CLIENT;
|
||||
msg.act = BTC_PBA_CLIENT_PULL_VCARD_ENTRY_EVT;
|
||||
|
||||
btc_pba_client_args_t args = {0};
|
||||
args.pull_vcard_entry.handle = handle;
|
||||
args.pull_vcard_entry.name = (char *)name;
|
||||
if (app_param != NULL) {
|
||||
args.pull_vcard_entry.include_app_param = true;
|
||||
memcpy(&args.pull_vcard_entry.app_param, app_param, sizeof(esp_pbac_pull_vcard_entry_app_param_t));
|
||||
}
|
||||
else {
|
||||
args.pull_vcard_entry.include_app_param = false;
|
||||
}
|
||||
|
||||
/* Switch to BTC context */
|
||||
bt_status_t stat = btc_transfer_context(&msg, &args, sizeof(btc_pba_client_args_t), btc_pba_client_args_deep_copy, btc_pba_client_args_deep_free);
|
||||
return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
|
||||
}
|
||||
|
||||
#endif
|
27
components/bt/host/bluedroid/api/include/api/esp_pba_defs.h
Normal file
27
components/bt/host/bluedroid/api/include/api/esp_pba_defs.h
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "esp_bt_defs.h"
|
||||
|
||||
/* Supported repositories bit mask */
|
||||
#define ESP_PBA_SUPPORTED_REPO_LOCAL_PHONE_BOOK 0x01
|
||||
#define ESP_PBA_SUPPORTED_REPO_SIM_CARD 0x02
|
||||
#define ESP_PBA_SUPPORTED_REPO_SPEED_DIAL 0x04
|
||||
#define ESP_PBA_SUPPORTED_REPO_FAVORITES 0x08
|
||||
|
||||
/* Supported features bit mask */
|
||||
#define ESP_PBA_SUPPORTED_FEAT_DOWNLOAD 0x0001
|
||||
#define ESP_PBA_SUPPORTED_FEAT_BROWSING 0x0002
|
||||
#define ESP_PBA_SUPPORTED_FEAT_DATABASE_IDENTIFIER 0x0004
|
||||
#define ESP_PBA_SUPPORTED_FEAT_FOLDER_VERSION_COUNTERS 0x0008
|
||||
#define ESP_PBA_SUPPORTED_FEAT_VCARD_SELECTING 0x0010
|
||||
#define ESP_PBA_SUPPORTED_FEAT_ENHANCED_MISSED_CALLS 0x0020
|
||||
#define ESP_PBA_SUPPORTED_FEAT_X_BT_UCI_VCARD_PROPERTY 0x0040
|
||||
#define ESP_PBA_SUPPORTED_FEAT_X_BT_UID_VCARD_PROPERTY 0x0080
|
||||
#define ESP_PBA_SUPPORTED_FEAT_CONTACT_REFERENCING 0x0100
|
||||
#define ESP_PBA_SUPPORTED_FEAT_DEFAULT_CONTACT_IMAGE_FORMAT 0x0200
|
340
components/bt/host/bluedroid/api/include/api/esp_pbac_api.h
Normal file
340
components/bt/host/bluedroid/api/include/api/esp_pbac_api.h
Normal file
@@ -0,0 +1,340 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "esp_err.h"
|
||||
#include "esp_bt_defs.h"
|
||||
#include "esp_pba_defs.h"
|
||||
|
||||
#define ESP_PBAC_INVALID_HANDLE 0 /*!< invalid handle value */
|
||||
|
||||
typedef uint16_t esp_pbac_conn_hdl_t;
|
||||
|
||||
/**
|
||||
* @brief PBA client callback events
|
||||
*/
|
||||
typedef enum {
|
||||
ESP_PBAC_INIT_EVT, /*!< PBA client initialized event */
|
||||
ESP_PBAC_DEINIT_EVT, /*!< PBA client de-initialized event */
|
||||
ESP_PBAC_CONNECTION_STATE_EVT, /*!< PBA client connection state changed event */
|
||||
ESP_PBAC_PULL_PHONE_BOOK_RESPONSE_EVT, /*!< Response of pull phone book */
|
||||
ESP_PBAC_SET_PHONE_BOOK_RESPONSE_EVT, /*!< Response of set phone book */
|
||||
ESP_PBAC_PULL_VCARD_LISTING_RESPONSE_EVT, /*!< Response of pull vCard listing */
|
||||
ESP_PBAC_PULL_VCARD_ENTRY_RESPONSE_EVT, /*!< Response of pull vCard entry */
|
||||
} esp_pbac_event_t;
|
||||
|
||||
/**
|
||||
* @brief PBA client status code
|
||||
*/
|
||||
typedef enum {
|
||||
ESP_PBAC_SUCCESS = 0, /*!< Operation success */
|
||||
ESP_PBAC_FAILURE, /*!< Generic failure */
|
||||
ESP_PBAC_ALREADY_CONN, /*!< Connection to peer device already exist */
|
||||
ESP_PBAC_NO_RESOURCE, /*!< No more resource */
|
||||
ESP_PBAC_SDP_FAIL, /*!< Connection failed in SDP */
|
||||
ESP_PBAC_GOEP_FAIL, /*!< Operation failed in GOEP */
|
||||
ESP_PBAC_AUTH_FAIL, /*!< Connection failed in OBEX authentication */
|
||||
ESP_PBAC_DEINIT, /*!< Connection closed due to pba client is deinit */
|
||||
|
||||
/* these error code is related to OBEX */
|
||||
ESP_PBAC_BAD_REQUEST = 0xC0, /*!< Server couldn't understand request */
|
||||
ESP_PBAC_UNAUTHORIZED = 0xC1, /*!< Unauthorized */
|
||||
ESP_PBAC_FORBIDDEN = 0xC3, /*!< Operation is understood but refused */
|
||||
ESP_PBAC_NOT_FOUND = 0xC4, /*!< Not found */
|
||||
ESP_PBAC_NOT_ACCEPTABLE = 0xC6, /*!< Not Acceptable */
|
||||
ESP_PBAC_PRECONDITION_FAILED = 0xCC, /*!< Precondition failed */
|
||||
ESP_PBAC_NOT_IMPLEMENTED = 0xD1, /*!< Not implemented */
|
||||
ESP_PBAC_SERVICE_UNAVAILABLE = 0xD3, /*!< Service unavailable */
|
||||
} esp_pbac_status_t;
|
||||
|
||||
/**
|
||||
* @brief PBA client set phone book flags
|
||||
*/
|
||||
typedef enum {
|
||||
ESP_PBAC_SET_PHONE_BOOK_FLAGS_ROOT = 0x02, /*!< Go back to root, name should set to empty string, not NULL */
|
||||
ESP_PBAC_SET_PHONE_BOOK_FLAGS_DOWN = 0x02, /*!< Go down 1 level, name should set to child folder */
|
||||
ESP_PBAC_SET_PHONE_BOOK_FLAGS_UP = 0x03, /*!< Go up 1 level, name is optional */
|
||||
} esp_pbac_set_phone_book_flags_t;
|
||||
|
||||
/**
|
||||
* @brief PBA client pull phone book optional application parameter
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t include_property_selector : 1; /*!< 1 if app param include property_selector */
|
||||
uint8_t include_format : 1; /*!< 1 if app param include format */
|
||||
uint8_t include_max_list_count : 1; /*!< 1 if app param include max_list_count */
|
||||
uint8_t include_list_start_offset : 1; /*!< 1 if app param include list_start_offset */
|
||||
uint8_t include_reset_new_missed_calls : 1; /*!< 1 if app param include reset_new_missed_calls */
|
||||
uint8_t include_vcard_selector : 1; /*!< 1 if app param include vcard_selector */
|
||||
uint8_t include_vcard_selector_operator : 1; /*!< 1 if app param include vcard_selector_operator */
|
||||
uint8_t format; /*!< 0x00 = 2.1, 0x01 = 3.0 */
|
||||
uint8_t reset_new_missed_calls; /*!< 0x01 = Reset */
|
||||
uint8_t vcard_selector_operator; /*!< 0x00 = OR, 0x01 = AND */
|
||||
uint16_t max_list_count; /*!< 0x0000 to 0xFFFF */
|
||||
uint16_t list_start_offset; /*!< 0x0000 to 0xFFFF */
|
||||
uint64_t property_selector; /*!< 64 bits mask */
|
||||
uint64_t vcard_selector; /*!< 64 bits mask */
|
||||
} esp_pbac_pull_phone_book_app_param_t;
|
||||
|
||||
/**
|
||||
* @brief PBA client pull vCard listing optional application parameter
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t include_order : 1; /*!< 1 if app param include order */
|
||||
uint8_t include_search_value : 1; /*!< 1 if app param include search_value */
|
||||
uint8_t include_search_property : 1; /*!< 1 if app param include search_property */
|
||||
uint8_t include_max_list_count : 1; /*!< 1 if app param include max_list_count */
|
||||
uint8_t include_list_start_offset : 1; /*!< 1 if app param include list_start_offset */
|
||||
uint8_t include_reset_new_missed_calls : 1; /*!< 1 if app param include reset_new_missed_calls */
|
||||
uint8_t include_vcard_selector : 1; /*!< 1 if app param include vcard_selector */
|
||||
uint8_t include_vcard_selector_operator : 1; /*!< 1 if app param include vcard_selector_operator */
|
||||
uint8_t order; /*!< 0x00 = indexed, 0x01 = alphanumeric */
|
||||
uint8_t search_property; /*!< 0x00 = Name, 0x01 = Number, 0x02 = Sound */
|
||||
uint8_t reset_new_missed_calls; /*!< 0x01 = Reset */
|
||||
uint8_t vcard_selector_operator; /*!< 0x00 = OR, 0x01 = AND */
|
||||
uint16_t max_list_count; /*!< 0x0000 to 0xFFFF */
|
||||
uint16_t list_start_offset; /*!< 0x0000 to 0xFFFF */
|
||||
char *search_value; /*!< Text */
|
||||
uint64_t vcard_selector; /*!< 64 bits mask */
|
||||
} esp_pbac_pull_vcard_listing_app_param_t;
|
||||
|
||||
/**
|
||||
* @brief PBA client pull vCard entry optional application parameter
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t include_property_selector : 1; /*!< 1 if app param include property_selector */
|
||||
uint8_t include_format : 1; /*!< 1 if app param include format */
|
||||
uint8_t format; /*!< 0x00 = 2.1, 0x01 = 3.0 */
|
||||
uint64_t property_selector; /*!< 64 bits mask */
|
||||
} esp_pbac_pull_vcard_entry_app_param_t;
|
||||
|
||||
/**
|
||||
* @brief PBA client callback parameters
|
||||
*/
|
||||
typedef union {
|
||||
/**
|
||||
* @brief ESP_PBAC_CONNECTION_STATE_EVT
|
||||
*/
|
||||
struct pbac_conn_stat_param {
|
||||
bool connected; /*!< whether pba client is connected to server */
|
||||
esp_pbac_conn_hdl_t handle; /*!< connection handle, non zeros if exist */
|
||||
uint8_t peer_supported_repo; /*!< peer supported repositories */
|
||||
uint32_t peer_supported_feat; /*!< peer supported features */
|
||||
esp_bd_addr_t remote_bda; /*!< remote bluetooth device address */
|
||||
esp_pbac_status_t reason; /*!< reason if disconnect */
|
||||
} conn_stat; /*!< PBA client connection status */
|
||||
|
||||
/**
|
||||
* @brief ESP_PBAC_PULL_PHONE_BOOK_RESPONSE_EVT
|
||||
*/
|
||||
struct pbac_pull_phone_book_rsp_param {
|
||||
esp_pbac_conn_hdl_t handle; /*!< PBA client connection handle */
|
||||
esp_pbac_status_t result; /*!< operation result, ESP_PBAC_SUCCESS if success */
|
||||
bool final; /*!< whether this is the final response packet */
|
||||
uint8_t *data; /*!< response data */
|
||||
uint16_t data_len; /*!< response data len */
|
||||
/* The following are the application parameters */
|
||||
uint8_t include_phone_book_size : 1; /*!< 1 if app param include phone_book_size */
|
||||
uint8_t include_new_missed_calls : 1; /*!< 1 if app param include new_missed_calls */
|
||||
uint8_t include_primary_folder_version : 1; /*!< 1 if app param include primary_folder_version */
|
||||
uint8_t include_secondary_folder_version : 1; /*!< 1 if app param include secondary_folder_version */
|
||||
uint8_t include_database_identifier : 1; /*!< 1 if app param include database_identifier */
|
||||
uint8_t new_missed_calls; /*!< 0x00 to 0xFF */
|
||||
uint16_t phone_book_size; /*!< 0x0000 to 0xFFFF */
|
||||
uint8_t *primary_folder_version; /*!< 0 to (2^128 -1) */
|
||||
uint8_t *secondary_folder_version; /*!< 0 to (2^128 -1) */
|
||||
uint8_t *database_identifier; /*!< 0 to (2^128 -1) */
|
||||
} pull_phone_book_rsp; /*!< pull phone book response */
|
||||
|
||||
/**
|
||||
* @brief ESP_PBAC_SET_PHONE_BOOK_RESPONSE_EVT
|
||||
*/
|
||||
struct pbac_set_phone_book_rsp_param {
|
||||
esp_pbac_conn_hdl_t handle; /*!< PBA client connection handle */
|
||||
esp_pbac_status_t result; /*!< operation result, ESP_PBAC_SUCCESS if success */
|
||||
} set_phone_book_rsp; /*!< set phone book response, always the final response */
|
||||
|
||||
/**
|
||||
* @brief ESP_PBAC_PULL_VCARD_LISTING_RESPONSE_EVT
|
||||
*/
|
||||
struct pbac_pull_vcard_listing_rsp_param {
|
||||
esp_pbac_conn_hdl_t handle; /*!< PBA client connection handle */
|
||||
esp_pbac_status_t result; /*!< operation result, ESP_PBAC_SUCCESS if success */
|
||||
bool final; /*!< whether this is the final response packet */
|
||||
uint8_t *data; /*!< response data */
|
||||
uint16_t data_len; /*!< response data len */
|
||||
/* The following are the application parameters */
|
||||
uint8_t include_phone_book_size : 1; /*!< 1 if app param include phone_book_size */
|
||||
uint8_t include_new_missed_calls : 1; /*!< 1 if app param include new_missed_calls */
|
||||
uint8_t include_primary_folder_version : 1; /*!< 1 if app param include primary_folder_version */
|
||||
uint8_t include_secondary_folder_version : 1; /*!< 1 if app param include secondary_folder_version */
|
||||
uint8_t include_database_identifier : 1; /*!< 1 if app param include database_identifier */
|
||||
uint8_t new_missed_calls; /*!< 0x00 to 0xFF */
|
||||
uint16_t phone_book_size; /*!< 0x0000 to 0xFFFF */
|
||||
uint8_t *primary_folder_version; /*!< 0 to (2^128 -1) */
|
||||
uint8_t *secondary_folder_version; /*!< 0 to (2^128 -1) */
|
||||
uint8_t *database_identifier; /*!< 0 to (2^128 -1) */
|
||||
} pull_vcard_listing_rsp; /*!< pull vcard listing response */
|
||||
|
||||
/**
|
||||
* @brief ESP_PBAC_PULL_VCARD_ENTRY_RESPONSE_EVT
|
||||
*/
|
||||
struct pbac_pull_vcard_entry_rsp_param {
|
||||
esp_pbac_conn_hdl_t handle; /*!< PBA client connection handle */
|
||||
esp_pbac_status_t result; /*!< operation result, ESP_PBAC_SUCCESS if success */
|
||||
bool final; /*!< whether this is the final response packet */
|
||||
uint8_t *data; /*!< response data */
|
||||
uint16_t data_len; /*!< response data len */
|
||||
/* The following are the application parameters */
|
||||
uint8_t include_database_identifier : 1; /*!< 1 if app param include database_identifier */
|
||||
uint8_t *database_identifier; /*!< 0 to (2^128 -1) */
|
||||
} pull_vcard_entry_rsp; /*!< pull vcard listing response */
|
||||
} esp_pbac_param_t;
|
||||
|
||||
/**
|
||||
* @brief PBA client callback function type
|
||||
*
|
||||
* @param event : Event type
|
||||
*
|
||||
* @param param : Pointer to callback parameter
|
||||
*/
|
||||
typedef void (*esp_pbac_callback_t)(esp_pbac_event_t event, esp_pbac_param_t *param);
|
||||
|
||||
|
||||
/**
|
||||
* @brief This function is called to register a user callbacks in PBA client.
|
||||
*
|
||||
* @param[in] callback: pointer to the user callback function.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: success
|
||||
* - other: failed
|
||||
*/
|
||||
esp_err_t esp_pbac_register_callback(esp_pbac_callback_t callback);
|
||||
|
||||
/**
|
||||
* @brief Initializes PBA client interface. This function should be called after bluedroid
|
||||
* enable successfully, and should be called after esp_pbac_register_callback.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: success
|
||||
* - other: failed
|
||||
*/
|
||||
esp_err_t esp_pbac_init(void);
|
||||
|
||||
/**
|
||||
* @brief De-initializes PBA client interface. This will close all PBA client connection.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: success
|
||||
* - other: failed
|
||||
*/
|
||||
esp_err_t esp_pbac_deinit(void);
|
||||
|
||||
/**
|
||||
* @brief Start the process to establish a connection to PBA server.
|
||||
*
|
||||
* @param[in] bd_addr: peer bluetooth device address
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: success
|
||||
* - other: failed
|
||||
*/
|
||||
esp_err_t esp_pbac_connect(esp_bd_addr_t bd_addr);
|
||||
|
||||
/**
|
||||
* @brief Disconnects from the current connected PBA server.
|
||||
*
|
||||
* @param[in] handle: connection handle retrieved from ESP_PBAC_CONNECTION_STATE_EVT
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: success
|
||||
* - other: failed
|
||||
*/
|
||||
esp_err_t esp_pbac_disconnect(esp_pbac_conn_hdl_t handle);
|
||||
|
||||
/**
|
||||
* @brief Send a request to pull phone book.
|
||||
*
|
||||
* @param[in] handle: connection handle retrieved from ESP_PBAC_CONNECTION_STATE_EVT
|
||||
*
|
||||
* @param[in] name: phone book object path and name, shall contain the absolute path
|
||||
* in the virtual folder architecture
|
||||
*
|
||||
* @param[in] app_param: optional application parameter
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: success
|
||||
* - other: failed
|
||||
*/
|
||||
esp_err_t esp_pbac_pull_phone_book(esp_pbac_conn_hdl_t handle, const char *name, esp_pbac_pull_phone_book_app_param_t *app_param);
|
||||
|
||||
/**
|
||||
* @brief Send a request to set the current folder in the virtual folder architecture.
|
||||
*
|
||||
* @param[in] handle: connection handle retrieved from ESP_PBAC_CONNECTION_STATE_EVT
|
||||
*
|
||||
* @param[in] flags: operation flags, one of ESP_PBAC_SET_PHONE_BOOK_FLAGS_XXX
|
||||
*
|
||||
* @param[in] name: folder name, if flags is set to ROOT, name should be empty string (""),
|
||||
* if flags is set to UP, name is optional, if flags is set to DOWN, name
|
||||
* is mandatory
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: success
|
||||
* - other: failed
|
||||
*/
|
||||
esp_err_t esp_pbac_set_phone_book(esp_pbac_conn_hdl_t handle, esp_pbac_set_phone_book_flags_t flags, const char *name);
|
||||
|
||||
/**
|
||||
* @brief Set the current folder in the virtual folder architecture, use absolute path.
|
||||
*
|
||||
* @param[in] handle: connection handle retrieved from ESP_PBAC_CONNECTION_STATE_EVT
|
||||
*
|
||||
* @param[in] path: absolute path of the folder intend to set. NULL or empty string will
|
||||
* set to ROOT
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: success
|
||||
* - other: failed
|
||||
*/
|
||||
esp_err_t esp_pbac_set_phone_book2(esp_pbac_conn_hdl_t handle, const char *path);
|
||||
|
||||
/**
|
||||
* @brief Send a request to pull vCard listing.
|
||||
*
|
||||
* @param[in] handle: connection handle retrieved from ESP_PBAC_CONNECTION_STATE_EVT
|
||||
*
|
||||
* @param[in] name: specifies the name of the folder to be retrieved, uses relative paths,
|
||||
* shall not include any path information. An empty name (empty string "")
|
||||
* may be sent to retrieve the vCard Listing object of the current folder.
|
||||
* However, it is illegal to issue a pull vCard listing request with an
|
||||
* empty name header from the ‘telecom/’ folder
|
||||
*
|
||||
* @param[in] app_param: optional application parameter
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: success
|
||||
* - other: failed
|
||||
*/
|
||||
esp_err_t esp_pbac_pull_vcard_listing(esp_pbac_conn_hdl_t handle, const char *name, esp_pbac_pull_vcard_listing_app_param_t *app_param);
|
||||
|
||||
/**
|
||||
* @brief Send a request to pull vCard entry.
|
||||
*
|
||||
* @param[in] handle: connection handle retrieved from ESP_PBAC_CONNECTION_STATE_EVT
|
||||
*
|
||||
* @param[in] name: vCard name or, if supported, the X-BT-UID of the object to be retrieved.
|
||||
* uses relative paths,shall not include any path information
|
||||
*
|
||||
* @param[in] app_param: optional application parameter
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: success
|
||||
* - other: failed
|
||||
*/
|
||||
esp_err_t esp_pbac_pull_vcard_entry(esp_pbac_conn_hdl_t handle, const char *name, esp_pbac_pull_vcard_entry_app_param_t *app_param);
|
@@ -278,6 +278,7 @@ void bta_av_ca_api_get(tBTA_AV_RCB *p_rcb, tBTA_AV_DATA *p_data)
|
||||
GOEPC_RequestAddHeader(p_rcb->cover_art_goep_hdl, COVER_ART_HEADER_ID_IMG_HANDLE, (UINT8 *)image_handle_utf16, BTA_AV_CA_IMG_HDL_UTF16_LEN);
|
||||
if (p_data->api_ca_get.type == BTA_AV_CA_GET_IMAGE) {
|
||||
GOEPC_RequestAddHeader(p_rcb->cover_art_goep_hdl, COVER_ART_HEADER_ID_IMG_DESCRIPTOR, (UINT8 *)p_data->api_ca_get.image_descriptor, p_data->api_ca_get.image_descriptor_len);
|
||||
osi_free(p_data->api_ca_get.image_descriptor);
|
||||
}
|
||||
/* always request to enable srm */
|
||||
GOEPC_RequestSetSRM(p_rcb->cover_art_goep_hdl, TRUE, FALSE);
|
||||
|
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/bt_target.h"
|
||||
#include "stack/obex_api.h"
|
||||
#include "bta/bta_pba_defs.h"
|
||||
|
||||
#if BTA_PBA_CLIENT_INCLUDED
|
||||
|
||||
/* Phone Book Access Profile (client) version */
|
||||
#define PBAP_PCE_VERSION 0x102 /* v1.2 */
|
||||
#define PBAP_PCE_SUPPORTED_FEATURES 0x0000003F /* support all features */
|
||||
|
||||
/* PBA Client callback events */
|
||||
#define BTA_PBA_CLIENT_ENABLE_EVT 0 /* PBA Client enabled */
|
||||
#define BTA_PBA_CLIENT_DISABLE_EVT 1 /* PBA Client disabled */
|
||||
#define BTA_PBA_CLIENT_REGISTER_EVT 2 /* PBA Client registered */
|
||||
#define BTA_PBA_CLIENT_DEREGISTER_EVT 3 /* PBA Client deregistered */
|
||||
#define BTA_PBA_CLIENT_CONN_OPEN_EVT 4 /* PBA Client connection opened */
|
||||
#define BTA_PBA_CLIENT_CONN_CLOSE_EVT 5 /* PBA Client connection closed */
|
||||
#define BTA_PBA_CLIENT_PULL_PHONE_BOOK_RSP_EVT 6 /* PBA Client pull phone book response */
|
||||
#define BTA_PBA_CLIENT_SET_PHONE_BOOK_RSP_EVT 7 /* PBA Client set phone book response */
|
||||
#define BTA_PBA_CLIENT_PULL_VCARD_LISTING_RSP_EVT 8 /* PBA Client pull vCard listing response */
|
||||
#define BTA_PBA_CLIENT_PULL_VCARD_ENTRY_RSP_EVT 9 /* PBA Client pull vCard entry response */
|
||||
|
||||
typedef enum {
|
||||
BTA_PBA_CLIENT_NO_ERROR, /* operation success */
|
||||
BTA_PBA_CLIENT_FAIL, /* general fail */
|
||||
BTA_PBA_CLIENT_ALREADY_CONN, /* connection to peer device already exist */
|
||||
BTA_PBA_CLIENT_NO_RESOURCE, /* no resource */
|
||||
BTA_PBA_CLIENT_SDP_ERROR, /* error in sdp */
|
||||
BTA_PBA_CLIENT_GOEP_ERROR, /* error in goep */
|
||||
BTA_PBA_CLIENT_AUTH_FAIL, /* authenticate failed */
|
||||
BTA_PBA_CLIENT_DISABLE, /* operation failed due to pba client is disable */
|
||||
|
||||
/* these error code is related to OBEX */
|
||||
BTA_PBA_CLIENT_BAD_REQUEST = 0xC0, /* Server couldn't understand request */
|
||||
BTA_PBA_CLIENT_UNAUTHORIZED = 0xC1, /* Unauthorized */
|
||||
BTA_PBA_CLIENT_FORBIDDEN = 0xC3, /* Operation is understood but refused > */
|
||||
BTA_PBA_CLIENT_NOT_FOUND = 0xC4, /* Not found */
|
||||
BTA_PBA_CLIENT_NOT_ACCEPTABLE = 0xC6, /* Not Acceptable */
|
||||
BTA_PBA_CLIENT_PRECONDITION_FAILED = 0xCC, /* Precondition failed */
|
||||
BTA_PBA_CLIENT_NOT_IMPLEMENTED = 0xD1, /* Not implemented */
|
||||
BTA_PBA_CLIENT_SERVICE_UNAVAILABLE = 0xD3, /* Service unavailable */
|
||||
} tBTA_PBA_CLIENT_ERR;
|
||||
|
||||
typedef struct {
|
||||
UINT16 handle; /* connection handle */
|
||||
tBTA_PBA_CLIENT_ERR error; /* error code */
|
||||
BD_ADDR bd_addr; /* peer BD addr */
|
||||
UINT8 peer_supported_repo; /* peer supported repositories */
|
||||
UINT32 peer_supported_feat; /* peer supported feature */
|
||||
} tBTA_PBA_CLIENT_CONN;
|
||||
|
||||
typedef struct {
|
||||
tBTA_PBA_CLIENT_ERR status;
|
||||
UINT16 handle; /* connection handle */
|
||||
BOOLEAN final; /* final data event */
|
||||
UINT8 *data; /* body data in response packet */
|
||||
UINT16 data_len; /* body data length */
|
||||
UINT8 *app_param; /* application parameters */
|
||||
UINT16 app_param_len; /* application parameters length */
|
||||
BT_HDR *pkt; /* raw buff that store all data, should be freed before return */
|
||||
} tBTA_PBA_CLIENT_RESPONSE;
|
||||
|
||||
/* union of data associated with PBA Client callback */
|
||||
typedef union {
|
||||
tBTA_PBA_CLIENT_CONN conn; /* CONN_OPEN_EVT, CONN_CLOSE_EVT */
|
||||
tBTA_PBA_CLIENT_RESPONSE response; /* XXX_RSP_EVT */
|
||||
} tBTA_PBA_CLIENT;
|
||||
|
||||
typedef UINT8 tBTA_PBA_CLIENT_EVT;
|
||||
|
||||
typedef void (tBTA_PBA_CLIENT_CBACK)(tBTA_PBA_CLIENT_EVT event, tBTA_PBA_CLIENT *p_data);
|
||||
|
||||
void BTA_PbaClientEnable(tBTA_PBA_CLIENT_CBACK *p_cback);
|
||||
void BTA_PbaClientDisable(void);
|
||||
void BTA_PbaClientRegister(const char *server_name);
|
||||
void BTA_PbaClientDeregister(void);
|
||||
void BTA_PbaClientOpen(BD_ADDR bd_addr, tBTA_SEC sec_mask, UINT32 supported_feat, UINT16 mtu);
|
||||
void BTA_PbaClientClose(UINT16 handle);
|
||||
void BTA_PbaClientPullPhoneBook(UINT16 handle, char *name, UINT8 *app_param, UINT16 app_param_len);
|
||||
void BTA_PbaClientSetPhoneBook(UINT16 handle, UINT8 flags, char *name);
|
||||
void BTA_PbaClientPullvCardListing(UINT16 handle, char *name, UINT8 *app_param, UINT16 app_param_len);
|
||||
void BTA_PbaClientPullvCardEntry(UINT16 handle, char *name, UINT8 *app_param, UINT16 app_param_len);
|
||||
|
||||
#endif
|
93
components/bt/host/bluedroid/bta/include/bta/bta_pba_defs.h
Normal file
93
components/bt/host/bluedroid/bta/include/bta/bta_pba_defs.h
Normal file
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/* PBAP supported repositories */
|
||||
#define BTA_PBAP_REPO_LOCAL_PHONEBOOK 0x01
|
||||
#define BTA_PBAP_REPO_SIM_CARD 0x02
|
||||
#define BTA_PBAP_REPO_SPEED_DIAL 0x04
|
||||
#define BTA_PBAP_REPO_FAVORITES 0x08
|
||||
|
||||
/* PBAP supported features */
|
||||
#define BTA_PBAP_FEAT_DOWNLOAD 0x0001
|
||||
#define BTA_PBAP_FEAT_BROWSING 0x0002
|
||||
#define BTA_PBAP_FEAT_DATABASE_IDENTIFIER 0x0004
|
||||
#define BTA_PBAP_FEAT_FLODER_VERSION_COUNTER 0x0008
|
||||
#define BTA_PBAP_FEAT_VCARD_SELECTING 0x0010
|
||||
#define BTA_PBAP_FEAT_ENHANCED_MISSED_CALLS 0x0020
|
||||
#define BTA_PBAP_FEAT_X_BT_UCI_VCARD_PROPERTY 0x0040
|
||||
#define BTA_PBAP_FEAT_X_BT_UID_VCARD_PROPERTY 0x0080
|
||||
#define BTA_PBAP_FEAT_CONTACT_REFERENCING 0x0100
|
||||
#define BTA_PBAP_FEAT_DEFAULT_CONTACT_IMAGE_FORMAT 0x0200
|
||||
|
||||
/* PBAP default supported features */
|
||||
#define BTA_PBAP_DEFAULT_SUPPORTED_FEATURES 0x0003
|
||||
|
||||
/* Application parameters tag id */
|
||||
#define BTA_PBAP_APP_PARAM_ORDER 0x01
|
||||
#define BTA_PBAP_APP_PARAM_SEARCH_VALUE 0x02
|
||||
#define BTA_PBAP_APP_PARAM_SEARCH_PROPERTY 0x03
|
||||
#define BTA_PBAP_APP_PARAM_MAX_LIST_COUNT 0x04
|
||||
#define BTA_PBAP_APP_PARAM_LIST_START_OFFSET 0x05
|
||||
#define BTA_PBAP_APP_PARAM_PROPERTY_SELECTOR 0x06
|
||||
#define BTA_PBAP_APP_PARAM_FORMAT 0x07
|
||||
#define BTA_PBAP_APP_PARAM_PHONE_BOOK_SIZE 0x08
|
||||
#define BTA_PBAP_APP_PARAM_NEW_MISSED_CALLS 0x09
|
||||
#define BTA_PBAP_APP_PARAM_PRIMARY_FOLDER_VERSION 0x0A
|
||||
#define BTA_PBAP_APP_PARAM_SECONDARY_FOLDER_VERSION 0x0B
|
||||
#define BTA_PBAP_APP_PARAM_VCARD_SELECTOR 0x0C
|
||||
#define BTA_PBAP_APP_PARAM_DATABASE_IDENTIFIER 0x0D
|
||||
#define BTA_PBAP_APP_PARAM_VCARD_SELECTOR_OPERATOR 0x0E
|
||||
#define BTA_PBAP_APP_PARAM_RESET_NEW_MISSED_CALLS 0x0F
|
||||
#define BTA_PBAP_APP_PARAM_PBAP_SUPPORTED_FEATURES 0x10
|
||||
|
||||
/* Application parameters length (except SearchValue) */
|
||||
#define BTA_PBAP_APP_PARAM_LENGTH_ORDER 1
|
||||
#define BTA_PBAP_APP_PARAM_LENGTH_SEARCH_PROPERTY 1
|
||||
#define BTA_PBAP_APP_PARAM_LENGTH_MAX_LIST_COUNT 2
|
||||
#define BTA_PBAP_APP_PARAM_LENGTH_LIST_START_OFFSET 2
|
||||
#define BTA_PBAP_APP_PARAM_LENGTH_PROPERTY_SELECTOR 8
|
||||
#define BTA_PBAP_APP_PARAM_LENGTH_FORMAT 1
|
||||
#define BTA_PBAP_APP_PARAM_LENGTH_PHONE_BOOK_SIZE 2
|
||||
#define BTA_PBAP_APP_PARAM_LENGTH_NEW_MISSED_CALLS 1
|
||||
#define BTA_PBAP_APP_PARAM_LENGTH_PRIMARY_FOLDER_VERSION 16
|
||||
#define BTA_PBAP_APP_PARAM_LENGTH_SECONDARY_FOLDER_VERSION 16
|
||||
#define BTA_PBAP_APP_PARAM_LENGTH_VCARD_SELECTOR 8
|
||||
#define BTA_PBAP_APP_PARAM_LENGTH_DATABASE_IDENTIFIER 16
|
||||
#define BTA_PBAP_APP_PARAM_LENGTH_VCARD_SELECTOR_OPERATOR 1
|
||||
#define BTA_PBAP_APP_PARAM_LENGTH_RESET_NEW_MISSED_CALLS 1
|
||||
#define BTA_PBAP_APP_PARAM_LENGTH_PBAP_SUPPORTED_FEATURES 4
|
||||
|
||||
/* Application parameter tag (1 byte) + Application parameter length (1 byte) */
|
||||
#define BTA_PBAP_APP_PARAM_HEADER_LENGTH 2
|
||||
|
||||
/* The minimal buff size that can hold all pull phone book application parameters */
|
||||
#define BTA_PBAP_PULL_PHONE_BOOK_APP_PARAM_BUFF_SIZE_MIN 37
|
||||
|
||||
/* The minimal buff size that can hold pull vCard listing application parameters, except the value of SearchValue */
|
||||
#define BTA_PBAP_PULL_VCARD_LISTING_APP_PARAM_BUFF_SIZE_MIN 34
|
||||
|
||||
/* The minimal buff size that can hold all pull vCard entry application parameters */
|
||||
#define BTA_PBAP_PULL_VCARD_ENTRY_APP_PARAM_BUFF_SIZE_MIN 13
|
||||
|
||||
/* Application parameters bit mask */
|
||||
#define PBAP_APP_PARAM_BIT_MASK_ORDER 0x0001
|
||||
#define PBAP_APP_PARAM_BIT_MASK_SEARCH_VALUE 0x0002
|
||||
#define PBAP_APP_PARAM_BIT_MASK_SEARCH_PROPERTY 0x0004
|
||||
#define PBAP_APP_PARAM_BIT_MASK_MAX_LIST_COUNT 0x0008
|
||||
#define PBAP_APP_PARAM_BIT_MASK_LIST_START_OFFSET 0x0010
|
||||
#define PBAP_APP_PARAM_BIT_MASK_PROPERTY_SELECTOR 0x0020
|
||||
#define PBAP_APP_PARAM_BIT_MASK_FORMAT 0x0040
|
||||
#define PBAP_APP_PARAM_BIT_MASK_PHONE_BOOK_SIZE 0x0080
|
||||
#define PBAP_APP_PARAM_BIT_MASK_NEW_MISSED_CALLS 0x0100
|
||||
#define PBAP_APP_PARAM_BIT_MASK_PRIMARY_FOLDER_VERSION 0x0200
|
||||
#define PBAP_APP_PARAM_BIT_MASK_SECONDARY_FOLDER_VERSION 0x0400
|
||||
#define PBAP_APP_PARAM_BIT_MASK_VCARD_SELECTOR 0x0800
|
||||
#define PBAP_APP_PARAM_BIT_MASK_DATABASE_IDENTIFIER 0x1000
|
||||
#define PBAP_APP_PARAM_BIT_MASK_VCARD_SELECTOR_OPERATOR 0x2000
|
||||
#define PBAP_APP_PARAM_BIT_MASK_RESET_NEW_MISSED_CALLS 0x4000
|
||||
#define PBAP_APP_PARAM_BIT_MASK_PBAP_SUPPORTED_FEATURES 0x8000
|
702
components/bt/host/bluedroid/bta/pba/bta_pba_client_act.c
Normal file
702
components/bt/host/bluedroid/bta/pba/bta_pba_client_act.c
Normal file
@@ -0,0 +1,702 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "osi/allocator.h"
|
||||
#include "common/bt_target.h"
|
||||
#include "stack/bt_types.h"
|
||||
#include "stack/obex_api.h"
|
||||
#include "stack/goep_common.h"
|
||||
#include "stack/goepc_api.h"
|
||||
#include "bta_pba_client_int.h"
|
||||
|
||||
#if BTA_PBA_CLIENT_INCLUDED
|
||||
|
||||
static const UINT8 pbap_target_uuid[16] = {0x79, 0x61, 0x35, 0xf0, 0xf0, 0xc5, 0x11, 0xd8, 0x09, 0x66, 0x08, 0x00, 0x20, 0x0c, 0x9a, 0x66};
|
||||
static const char *type_pull_phone_book = "x-bt/phonebook";
|
||||
static const char *type_pull_vcard_listing = "x-bt/vcard-listing";
|
||||
static const char *type_pull_vcard_entry = "x-bt/vcard";
|
||||
|
||||
#define TYPE_LEN_PULL_PHONE_BOOK 15
|
||||
#define TYPE_LEN_PULL_VCARD_LISTING 19
|
||||
#define TYPE_LEN_PULL_VCARD_ENTRY 11
|
||||
|
||||
static void free_ccb(tBTA_PBA_CLIENT_CCB *p_ccb)
|
||||
{
|
||||
/* free sdp db */
|
||||
bta_pba_client_free_db(p_ccb);
|
||||
|
||||
/* clear all field, set allocated to 0 */
|
||||
memset(p_ccb, 0, sizeof(tBTA_PBA_CLIENT_CCB));
|
||||
}
|
||||
|
||||
static void close_goepc_and_report(tBTA_PBA_CLIENT_CCB *p_ccb, tBTA_PBA_CLIENT_ERR reason)
|
||||
{
|
||||
/* remove goep connection */
|
||||
if (p_ccb->goep_handle != 0) {
|
||||
GOEPC_Close(p_ccb->goep_handle);
|
||||
p_ccb->goep_handle = 0;
|
||||
}
|
||||
|
||||
/* report connection closed event */
|
||||
tBTA_PBA_CLIENT_CONN conn;
|
||||
conn.handle = p_ccb->allocated;
|
||||
conn.error = reason;
|
||||
bdcpy(conn.bd_addr, p_ccb->bd_addr);
|
||||
bta_pba_client_cb.p_cback(BTA_PBA_CLIENT_CONN_CLOSE_EVT, (tBTA_PBA_CLIENT *)&conn);
|
||||
|
||||
/* free ccb */
|
||||
free_ccb(p_ccb);
|
||||
}
|
||||
|
||||
static void build_and_send_empty_get_req(tBTA_PBA_CLIENT_CCB *p_ccb)
|
||||
{
|
||||
tOBEX_PARSE_INFO info = {0};
|
||||
info.opcode = OBEX_OPCODE_GET_FINAL;
|
||||
/* empty get request, try to use a smaller buff size */
|
||||
UINT16 tx_buff_size = BT_SMALL_BUFFER_SIZE < p_ccb->max_tx ? BT_SMALL_BUFFER_SIZE : p_ccb->max_tx;
|
||||
UINT16 ret = GOEPC_PrepareRequest(p_ccb->goep_handle, &info, tx_buff_size);
|
||||
ret |= GOEPC_RequestAddHeader(p_ccb->goep_handle, OBEX_HEADER_ID_CONNECTION_ID, (UINT8 *)(&p_ccb->goep_cid), 4);
|
||||
ret |= GOEPC_SendRequest(p_ccb->goep_handle);
|
||||
if (ret != GOEP_SUCCESS) {
|
||||
close_goepc_and_report(p_ccb, BTA_PBA_CLIENT_GOEP_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t get_operation_response_event(tBTA_PBA_CLIENT_OP operation)
|
||||
{
|
||||
uint8_t event = 0;
|
||||
switch (operation)
|
||||
{
|
||||
case BTA_PBA_CLIENT_OP_PULL_PHONE_BOOK:
|
||||
event = BTA_PBA_CLIENT_PULL_PHONE_BOOK_RSP_EVT;
|
||||
break;
|
||||
case BTA_PBA_CLIENT_OP_SET_PHONE_BOOK:
|
||||
event = BTA_PBA_CLIENT_SET_PHONE_BOOK_RSP_EVT;
|
||||
break;
|
||||
case BTA_PBA_CLIENT_OP_PULL_VCARD_LISTING:
|
||||
event = BTA_PBA_CLIENT_PULL_VCARD_LISTING_RSP_EVT;
|
||||
break;
|
||||
case BTA_PBA_CLIENT_OP_PULL_VCARD_ENTRY:
|
||||
event = BTA_PBA_CLIENT_PULL_VCARD_ENTRY_RSP_EVT;
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
return event;
|
||||
}
|
||||
|
||||
static tBTA_PBA_CLIENT_ERR calculate_response_error(uint8_t response_code)
|
||||
{
|
||||
tBTA_PBA_CLIENT_ERR error = BTA_PBA_CLIENT_FAIL;
|
||||
/* always treat error response code as final response */
|
||||
response_code |= OBEX_FINAL_BIT_MASK;
|
||||
switch (response_code)
|
||||
{
|
||||
case (OBEX_RESPONSE_CODE_BAD_REQUEST | OBEX_FINAL_BIT_MASK):
|
||||
error = BTA_PBA_CLIENT_BAD_REQUEST;
|
||||
break;
|
||||
case (OBEX_RESPONSE_CODE_UNAUTHORIZED | OBEX_FINAL_BIT_MASK):
|
||||
error = BTA_PBA_CLIENT_UNAUTHORIZED;
|
||||
break;
|
||||
case (OBEX_RESPONSE_CODE_FORBIDDEN | OBEX_FINAL_BIT_MASK):
|
||||
error = BTA_PBA_CLIENT_FORBIDDEN;
|
||||
break;
|
||||
case (OBEX_RESPONSE_CODE_NOT_FOUND | OBEX_FINAL_BIT_MASK):
|
||||
error = BTA_PBA_CLIENT_NOT_FOUND;
|
||||
break;
|
||||
case (OBEX_RESPONSE_CODE_NOT_ACCEPTABLE | OBEX_FINAL_BIT_MASK):
|
||||
error = BTA_PBA_CLIENT_NOT_ACCEPTABLE;
|
||||
break;
|
||||
case (OBEX_RESPONSE_CODE_PRECONDITION_FAILED | OBEX_FINAL_BIT_MASK):
|
||||
error = BTA_PBA_CLIENT_PRECONDITION_FAILED;
|
||||
break;
|
||||
case (OBEX_RESPONSE_CODE_NOT_IMPLEMENTED | OBEX_FINAL_BIT_MASK):
|
||||
error = BTA_PBA_CLIENT_NOT_IMPLEMENTED;
|
||||
break;
|
||||
case (OBEX_RESPONSE_CODE_SERVICE_UNAVAILABLE | OBEX_FINAL_BIT_MASK):
|
||||
error = BTA_PBA_CLIENT_SERVICE_UNAVAILABLE;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
static void report_data_event(tBTA_PBA_CLIENT_CCB *p_ccb, UINT8 *data, UINT16 data_len, UINT8 *app_param,
|
||||
UINT16 app_param_len, BOOLEAN final, BT_HDR *pkt)
|
||||
{
|
||||
uint8_t event = get_operation_response_event(p_ccb->operation);
|
||||
tBTA_PBA_CLIENT_RESPONSE response;
|
||||
response.status = BTA_PBA_CLIENT_NO_ERROR;
|
||||
response.handle = p_ccb->allocated;
|
||||
response.final = final;
|
||||
response.data_len = data_len;
|
||||
response.data = data;
|
||||
response.app_param_len = app_param_len;
|
||||
response.app_param = app_param;
|
||||
response.pkt = pkt;
|
||||
bta_pba_client_cb.p_cback(event, (tBTA_PBA_CLIENT *)&response);
|
||||
}
|
||||
|
||||
static void report_error_data_event(tBTA_PBA_CLIENT_CCB *p_ccb, tBTA_PBA_CLIENT_ERR status)
|
||||
{
|
||||
uint8_t event = get_operation_response_event(p_ccb->operation);
|
||||
tBTA_PBA_CLIENT_RESPONSE response;
|
||||
memset(&response, 0, sizeof(tBTA_PBA_CLIENT_RESPONSE));
|
||||
response.status = status;
|
||||
response.handle = p_ccb->allocated;
|
||||
response.final = TRUE;
|
||||
bta_pba_client_cb.p_cback(event, (tBTA_PBA_CLIENT *)&response);
|
||||
}
|
||||
|
||||
static void ascii_to_utf16(const UINT8 *src, UINT16 len, UINT8 *dst)
|
||||
{
|
||||
UINT16 pos = 0;
|
||||
for (int i = 0 ; i < len ; i++){
|
||||
dst[pos++] = 0;
|
||||
dst[pos++] = src[i];
|
||||
}
|
||||
}
|
||||
|
||||
void bta_pba_client_api_enable(tBTA_PBA_CLIENT_DATA *p_data)
|
||||
{
|
||||
/* initialize control block */
|
||||
memset(&bta_pba_client_cb, 0, sizeof(tBTA_PBA_CLIENT_CB));
|
||||
|
||||
/* store callback function */
|
||||
bta_pba_client_cb.p_cback = p_data->api_enable.p_cback;
|
||||
|
||||
bta_pba_client_cb.p_cback(BTA_PBA_CLIENT_ENABLE_EVT, NULL);
|
||||
}
|
||||
|
||||
void bta_pba_client_api_disable(tBTA_PBA_CLIENT_DATA *p_data)
|
||||
{
|
||||
if (!bta_sys_is_register(BTA_ID_PBC)) {
|
||||
return;
|
||||
}
|
||||
/* deregister with BTA system manager */
|
||||
bta_sys_deregister(BTA_ID_PBC);
|
||||
|
||||
/* close all connections */
|
||||
for (int i = 0; i < PBA_CLIENT_MAX_CONNECTION; ++i) {
|
||||
if (bta_pba_client_cb.ccb[i].allocated) {
|
||||
close_goepc_and_report(&bta_pba_client_cb.ccb[i], BTA_PBA_CLIENT_DISABLE);
|
||||
}
|
||||
}
|
||||
|
||||
/* store and clear callback function */
|
||||
tBTA_PBA_CLIENT_CBACK *p_cback = bta_pba_client_cb.p_cback;
|
||||
bta_pba_client_cb.p_cback = NULL;
|
||||
|
||||
if(p_cback) {
|
||||
p_cback(BTA_PBA_CLIENT_DISABLE_EVT, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void bta_pba_client_api_register(tBTA_PBA_CLIENT_DATA *p_data)
|
||||
{
|
||||
/* create SDP records */
|
||||
bta_pba_client_create_record(p_data->api_register.name);
|
||||
|
||||
bta_pba_client_cb.p_cback(BTA_PBA_CLIENT_REGISTER_EVT, NULL);
|
||||
}
|
||||
|
||||
void bta_pba_client_api_deregister(tBTA_PBA_CLIENT_DATA *p_data)
|
||||
{
|
||||
/* delete SDP records */
|
||||
bta_pba_client_del_record();
|
||||
|
||||
bta_pba_client_cb.p_cback(BTA_PBA_CLIENT_DEREGISTER_EVT, NULL);
|
||||
}
|
||||
|
||||
void bta_pba_client_api_open(tBTA_PBA_CLIENT_CCB *p_ccb, tBTA_PBA_CLIENT_DATA *p_data)
|
||||
{
|
||||
p_ccb->sec_mask = p_data->api_open.sec_mask;
|
||||
if (p_data->api_open.mtu < PBA_CLIENT_MIN_MTU || p_data->api_open.mtu > PBA_CLIENT_MAX_MTU) {
|
||||
p_ccb->max_rx = PBA_CLIENT_MAX_MTU;
|
||||
p_ccb->max_tx = PBA_CLIENT_MAX_MTU;
|
||||
}
|
||||
else {
|
||||
p_ccb->max_rx = p_data->api_open.mtu;
|
||||
p_ccb->max_tx = p_data->api_open.mtu;
|
||||
}
|
||||
bdcpy(p_ccb->bd_addr, p_data->api_open.bd_addr);
|
||||
p_ccb->our_supported_feat = p_data->api_open.supported_feat;
|
||||
if (!bta_pba_client_do_disc(p_ccb)) {
|
||||
close_goepc_and_report(p_ccb, BTA_PBA_CLIENT_SDP_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
void bta_pba_client_api_close(tBTA_PBA_CLIENT_CCB *p_ccb, tBTA_PBA_CLIENT_DATA *p_data)
|
||||
{
|
||||
UNUSED(p_data);
|
||||
tOBEX_PARSE_INFO info = {0};
|
||||
|
||||
info.opcode = OBEX_OPCODE_DISCONNECT;
|
||||
UINT16 tx_buff_size = BT_SMALL_BUFFER_SIZE < p_ccb->max_tx ? BT_SMALL_BUFFER_SIZE : p_ccb->max_tx;
|
||||
UINT16 ret = GOEPC_PrepareRequest(p_ccb->goep_handle, &info, tx_buff_size);
|
||||
ret |= GOEPC_RequestAddHeader(p_ccb->goep_handle, OBEX_HEADER_ID_CONNECTION_ID, (UINT8 *)(&p_ccb->goep_cid), 4);
|
||||
ret |= GOEPC_SendRequest(p_ccb->goep_handle);
|
||||
|
||||
if (ret != GOEP_SUCCESS) {
|
||||
/* anyway, this close operation is requested by upper, set reason to success */
|
||||
close_goepc_and_report(p_ccb, BTA_PBA_CLIENT_NO_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
void bta_pba_client_api_req(tBTA_PBA_CLIENT_CCB *p_ccb, tBTA_PBA_CLIENT_DATA *p_data)
|
||||
{
|
||||
tOBEX_PARSE_INFO info = {0};
|
||||
UINT16 ret;
|
||||
|
||||
if (p_data->api_req.operation == BTA_PBA_CLIENT_OP_SET_PHONE_BOOK) {
|
||||
info.opcode = OBEX_OPCODE_SETPATH;
|
||||
info.flags = p_data->api_req.flags;
|
||||
}
|
||||
else {
|
||||
info.opcode = OBEX_OPCODE_GET_FINAL;
|
||||
}
|
||||
ret = GOEPC_PrepareRequest(p_ccb->goep_handle, &info, p_ccb->max_tx);
|
||||
if (ret != GOEP_SUCCESS) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
ret |= GOEPC_RequestAddHeader(p_ccb->goep_handle, OBEX_HEADER_ID_CONNECTION_ID, (UINT8 *)(&p_ccb->goep_cid), 4);
|
||||
|
||||
if (p_data->api_req.operation != BTA_PBA_CLIENT_OP_SET_PHONE_BOOK) {
|
||||
ret |= GOEPC_RequestSetSRM(p_ccb->goep_handle, TRUE, FALSE);
|
||||
}
|
||||
|
||||
if (p_data->api_req.name) {
|
||||
UINT16 name_len = strlen(p_data->api_req.name) + 1;
|
||||
if (name_len == 1) {
|
||||
/* empty string, add empty name header */
|
||||
ret |= GOEPC_RequestAddHeader(p_ccb->goep_handle, OBEX_HEADER_ID_NAME, NULL, 0);
|
||||
}
|
||||
else {
|
||||
UINT8 *utf16_name = osi_malloc(2 * name_len);
|
||||
assert(utf16_name != NULL);
|
||||
ascii_to_utf16((UINT8 *)p_data->api_req.name, name_len, utf16_name);
|
||||
ret |= GOEPC_RequestAddHeader(p_ccb->goep_handle, OBEX_HEADER_ID_NAME, utf16_name, 2 * name_len);
|
||||
osi_free(utf16_name);
|
||||
}
|
||||
osi_free(p_data->api_req.name);
|
||||
p_data->api_req.name = NULL;
|
||||
}
|
||||
|
||||
switch (p_data->api_req.operation)
|
||||
{
|
||||
case BTA_PBA_CLIENT_OP_PULL_PHONE_BOOK:
|
||||
ret |= GOEPC_RequestAddHeader(p_ccb->goep_handle, OBEX_HEADER_ID_TYPE, (const UINT8 *)type_pull_phone_book, TYPE_LEN_PULL_PHONE_BOOK);
|
||||
break;
|
||||
case BTA_PBA_CLIENT_OP_PULL_VCARD_LISTING:
|
||||
ret |= GOEPC_RequestAddHeader(p_ccb->goep_handle, OBEX_HEADER_ID_TYPE, (const UINT8 *)type_pull_vcard_listing, TYPE_LEN_PULL_VCARD_LISTING);
|
||||
break;
|
||||
case BTA_PBA_CLIENT_OP_PULL_VCARD_ENTRY:
|
||||
ret |= GOEPC_RequestAddHeader(p_ccb->goep_handle, OBEX_HEADER_ID_TYPE, (const UINT8 *)type_pull_vcard_entry, TYPE_LEN_PULL_VCARD_ENTRY);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (p_data->api_req.app_param) {
|
||||
ret |= GOEPC_RequestAddHeader(p_ccb->goep_handle, OBEX_HEADER_ID_APP_PARAM, p_data->api_req.app_param, p_data->api_req.app_param_len);
|
||||
osi_free(p_data->api_req.app_param);
|
||||
}
|
||||
|
||||
ret |= GOEPC_SendRequest(p_ccb->goep_handle);
|
||||
p_ccb->operation = p_data->api_req.operation;
|
||||
if (ret != GOEP_SUCCESS) {
|
||||
goto error;
|
||||
}
|
||||
return;
|
||||
|
||||
error:
|
||||
if (p_data->api_req.name) {
|
||||
osi_free(p_data->api_req.name);
|
||||
}
|
||||
if (p_data->api_req.app_param) {
|
||||
osi_free(p_data->api_req.app_param);
|
||||
}
|
||||
close_goepc_and_report(p_ccb, BTA_PBA_CLIENT_GOEP_ERROR);
|
||||
}
|
||||
|
||||
static void goep_event_callback(UINT16 handle, UINT8 event, tGOEPC_MSG *p_msg)
|
||||
{
|
||||
tBTA_PBA_CLIENT_DATA *p_data = NULL;
|
||||
|
||||
switch (event)
|
||||
{
|
||||
case GOEPC_OPENED_EVT:
|
||||
p_data = (tBTA_PBA_CLIENT_DATA *)osi_malloc(sizeof(tBTA_PBA_CLIENT_GOEP_CONNECT));
|
||||
assert(p_data != NULL);
|
||||
p_data->goep_connect.hdr.event = BTA_PBA_CLIENT_GOEP_CONNECT_EVT;
|
||||
p_data->goep_connect.hdr.layer_specific = handle;
|
||||
p_data->goep_connect.our_mtu = p_msg->opened.our_mtu;
|
||||
p_data->goep_connect.peer_mtu = p_msg->opened.peer_mtu;
|
||||
break;
|
||||
case GOEPC_CLOSED_EVT:
|
||||
p_data = (tBTA_PBA_CLIENT_DATA *)osi_malloc(sizeof(tBTA_PBA_CLIENT_GOEP_DISCONNECT));
|
||||
assert(p_data != NULL);
|
||||
p_data->goep_disconnect.hdr.event = BTA_PBA_CLIENT_GOEP_DISCONNECT_EVT;
|
||||
p_data->goep_disconnect.hdr.layer_specific = handle;
|
||||
p_data->goep_disconnect.reason = p_msg->closed.reason;
|
||||
break;
|
||||
case GOEPC_RESPONSE_EVT:
|
||||
p_data = (tBTA_PBA_CLIENT_DATA *)osi_malloc(sizeof(tBTA_PBA_CLIENT_GOEP_RESPONSE));
|
||||
assert(p_data != NULL);
|
||||
p_data->goep_response.hdr.layer_specific = handle;
|
||||
p_data->goep_response.pkt = p_msg->response.pkt;
|
||||
p_data->goep_response.opcode = p_msg->response.opcode;
|
||||
p_data->goep_response.srm_en = p_msg->response.srm_en;
|
||||
p_data->goep_response.srm_wait = p_msg->response.srm_wait;
|
||||
if (p_msg->response.final) {
|
||||
p_data->goep_response.hdr.event = BTA_PBA_CLIENT_RESPONSE_FINAL_EVT;
|
||||
}
|
||||
else {
|
||||
p_data->hdr.event = BTA_PBA_CLIENT_RESPONSE_EVT;
|
||||
}
|
||||
break;
|
||||
case GOEPC_MTU_CHANGED_EVT:
|
||||
case GOEPC_CONGEST_EVT:
|
||||
case GOEPC_UNCONGEST_EVT:
|
||||
/* ignore these event */
|
||||
break;
|
||||
default:
|
||||
APPL_TRACE_WARNING("%s, unknown goep event: %d", __FUNCTION__, event);
|
||||
break;
|
||||
}
|
||||
if (p_data != NULL) {
|
||||
bta_sys_sendmsg(p_data);
|
||||
}
|
||||
}
|
||||
|
||||
void bta_pba_client_do_connect(tBTA_PBA_CLIENT_CCB *p_ccb, tBTA_PBA_CLIENT_DATA *p_data)
|
||||
{
|
||||
tBTA_PBA_CLIENT_ERR reason = BTA_PBA_CLIENT_FAIL;
|
||||
|
||||
/* find attr in sdp discovery result */
|
||||
BOOLEAN found = bta_pba_client_sdp_find_attr(p_ccb);
|
||||
if (found) {
|
||||
tOBEX_SVR_INFO svr = {0};
|
||||
if (p_ccb->peer_l2cap_psm != 0) {
|
||||
/* peer support obex over l2cap, use it */
|
||||
svr.tl = OBEX_OVER_L2CAP;
|
||||
svr.l2cap.psm = p_ccb->peer_l2cap_psm;
|
||||
svr.l2cap.sec_mask = p_ccb->sec_mask;
|
||||
svr.l2cap.pref_mtu = 0;
|
||||
bdcpy(svr.l2cap.addr, p_ccb->bd_addr);
|
||||
}
|
||||
else {
|
||||
/* otherwise, use obex over rfcomm */
|
||||
svr.tl = OBEX_OVER_RFCOMM;
|
||||
svr.rfcomm.scn = p_ccb->peer_rfcomm_scn;
|
||||
svr.rfcomm.sec_mask = p_ccb->sec_mask;
|
||||
svr.rfcomm.pref_mtu = 0;
|
||||
bdcpy(svr.rfcomm.addr, p_ccb->bd_addr);
|
||||
}
|
||||
|
||||
if (GOEPC_Open(&svr, goep_event_callback, &p_ccb->goep_handle) == GOEP_SUCCESS) {
|
||||
/* start connection success */
|
||||
return;
|
||||
}
|
||||
else {
|
||||
reason = BTA_PBA_CLIENT_GOEP_ERROR;
|
||||
}
|
||||
}
|
||||
else {
|
||||
reason = BTA_PBA_CLIENT_SDP_ERROR;
|
||||
}
|
||||
|
||||
/* critical sdp attribute not found or start goep connection failed */
|
||||
tBTA_PBA_CLIENT_CONN conn;
|
||||
conn.handle = 0;
|
||||
conn.error = reason;
|
||||
bdcpy(conn.bd_addr, p_ccb->bd_addr);
|
||||
bta_pba_client_cb.p_cback(BTA_PBA_CLIENT_CONN_CLOSE_EVT, (tBTA_PBA_CLIENT *)&conn);
|
||||
|
||||
/* free ccb */
|
||||
free_ccb(p_ccb);
|
||||
}
|
||||
|
||||
void bta_pba_client_authenticate(tBTA_PBA_CLIENT_CCB *p_ccb, tBTA_PBA_CLIENT_DATA *p_data)
|
||||
{
|
||||
/* [todo]: support authenticate */
|
||||
}
|
||||
|
||||
void bta_pba_client_connect(tBTA_PBA_CLIENT_CCB *p_ccb, tBTA_PBA_CLIENT_DATA *p_data)
|
||||
{
|
||||
tBTA_PBA_CLIENT_CONN conn;
|
||||
conn.handle = p_ccb->allocated;
|
||||
conn.peer_supported_repo = p_ccb->peer_supported_repo;
|
||||
conn.peer_supported_feat = p_ccb->peer_supported_feat;
|
||||
conn.error = BTA_PBA_CLIENT_NO_ERROR;
|
||||
bdcpy(conn.bd_addr, p_ccb->bd_addr);
|
||||
bta_pba_client_cb.p_cback(BTA_PBA_CLIENT_CONN_OPEN_EVT, (tBTA_PBA_CLIENT *)&conn);
|
||||
}
|
||||
|
||||
void bta_pba_client_force_disconnect(tBTA_PBA_CLIENT_CCB *p_ccb, tBTA_PBA_CLIENT_DATA *p_data)
|
||||
{
|
||||
UNUSED(p_data);
|
||||
|
||||
/* force disconnect is requested by upper, set reason to success */
|
||||
close_goepc_and_report(p_ccb, BTA_PBA_CLIENT_NO_ERROR);
|
||||
}
|
||||
|
||||
void bta_pba_client_response(tBTA_PBA_CLIENT_CCB *p_ccb, tBTA_PBA_CLIENT_DATA *p_data)
|
||||
{
|
||||
tOBEX_PARSE_INFO info;
|
||||
tBTA_PBA_CLIENT_ERR reason = BTA_PBA_CLIENT_GOEP_ERROR;
|
||||
|
||||
OBEX_ParseResponse(p_data->goep_response.pkt, p_data->goep_response.opcode, &info);
|
||||
if (p_data->goep_response.opcode == OBEX_OPCODE_GET_FINAL &&
|
||||
(info.response_code == OBEX_RESPONSE_CODE_CONTINUE || info.response_code == (OBEX_RESPONSE_CODE_CONTINUE | OBEX_FINAL_BIT_MASK))) {
|
||||
UINT8 *header = NULL;
|
||||
UINT8 *body_data = NULL;
|
||||
UINT16 body_data_len = 0;
|
||||
UINT8 *app_param = NULL;
|
||||
UINT16 app_param_len = 0;
|
||||
while((header = OBEX_GetNextHeader(p_data->goep_response.pkt, &info)) != NULL) {
|
||||
switch (*header)
|
||||
{
|
||||
case OBEX_HEADER_ID_BODY:
|
||||
case OBEX_HEADER_ID_END_OF_BODY:
|
||||
if (body_data == NULL) {
|
||||
/* first body header */
|
||||
body_data = header + 3; /* skip opcode, length */
|
||||
body_data_len = OBEX_GetHeaderLength(header) - 3;
|
||||
}
|
||||
else {
|
||||
/* another body header found */
|
||||
report_data_event(p_ccb, body_data, body_data_len, NULL, 0, FALSE, NULL);
|
||||
body_data = header + 3; /* skip opcode, length */
|
||||
body_data_len = OBEX_GetHeaderLength(header) - 3;
|
||||
}
|
||||
break;
|
||||
case OBEX_HEADER_ID_APP_PARAM:
|
||||
app_param = header + 3;
|
||||
app_param_len = OBEX_GetHeaderLength(header) - 3;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (body_data != NULL || app_param != NULL) {
|
||||
/* report body data and app param, dont free packet here */
|
||||
report_data_event(p_ccb, body_data, body_data_len, app_param, app_param_len, FALSE, p_data->goep_response.pkt);
|
||||
}
|
||||
else {
|
||||
/* not any body data or app param */
|
||||
osi_free(p_data->goep_response.pkt);
|
||||
}
|
||||
|
||||
/* if SRM not enable, we need to send a empty get request */
|
||||
if (!p_data->goep_response.srm_en || p_data->goep_response.srm_wait) {
|
||||
build_and_send_empty_get_req(p_ccb);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* unexpected opcode or response code */
|
||||
reason = calculate_response_error(info.response_code);
|
||||
goto error;
|
||||
}
|
||||
return;
|
||||
|
||||
error:
|
||||
if (p_data->goep_response.pkt != NULL) {
|
||||
osi_free(p_data->goep_response.pkt);
|
||||
}
|
||||
close_goepc_and_report(p_ccb, reason);
|
||||
}
|
||||
|
||||
void bta_pba_client_response_final(tBTA_PBA_CLIENT_CCB *p_ccb, tBTA_PBA_CLIENT_DATA *p_data)
|
||||
{
|
||||
tOBEX_PARSE_INFO info;
|
||||
UINT8 *header = NULL;
|
||||
tBTA_PBA_CLIENT_ERR reason = BTA_PBA_CLIENT_FAIL;
|
||||
|
||||
OBEX_ParseResponse(p_data->goep_response.pkt, p_data->goep_response.opcode, &info);
|
||||
if (p_data->goep_response.opcode == OBEX_OPCODE_CONNECT) {
|
||||
if (info.response_code == (OBEX_RESPONSE_CODE_OK | OBEX_FINAL_BIT_MASK)) {
|
||||
/* obex connect success */
|
||||
if (info.max_packet_length < 255) {
|
||||
p_ccb->max_tx = 255;
|
||||
}
|
||||
else if (p_ccb->max_tx > info.max_packet_length) {
|
||||
p_ccb->max_tx = info.max_packet_length;
|
||||
}
|
||||
BOOLEAN cid_found = false;
|
||||
while((header = OBEX_GetNextHeader(p_data->goep_response.pkt, &info)) != NULL) {
|
||||
if (*header == OBEX_HEADER_ID_CONNECTION_ID) {
|
||||
cid_found = true;
|
||||
memcpy((UINT8 *)(&p_ccb->goep_cid), header + 1, 4);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!cid_found) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
BT_HDR *p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR));
|
||||
assert(p_buf != NULL);
|
||||
p_buf->event = BTA_PBA_CLIENT_CONNECT_EVT;
|
||||
p_buf->layer_specific = p_ccb->allocated;
|
||||
bta_sys_sendmsg(p_buf);
|
||||
}
|
||||
else if (info.response_code == (OBEX_RESPONSE_CODE_UNAUTHORIZED | OBEX_FINAL_BIT_MASK)){
|
||||
/* need to authenticate */
|
||||
if (p_ccb->authenticate) {
|
||||
/* already try to authenticate, but failed */
|
||||
reason = BTA_PBA_CLIENT_AUTH_FAIL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
p_ccb->authenticate = TRUE;
|
||||
/* [todo]: we don't support authenticate currently */
|
||||
goto error;
|
||||
}
|
||||
else {
|
||||
/* other unexpected response code */
|
||||
goto error;
|
||||
}
|
||||
osi_free(p_data->goep_response.pkt);
|
||||
}
|
||||
else if (p_data->goep_response.opcode == OBEX_OPCODE_GET_FINAL) {
|
||||
/* check response code is success */
|
||||
if (info.response_code == (OBEX_RESPONSE_CODE_OK | OBEX_FINAL_BIT_MASK)) {
|
||||
UINT8 *body_data = NULL;
|
||||
UINT16 body_data_len = 0;
|
||||
UINT8 *app_param = NULL;
|
||||
UINT16 app_param_len = 0;
|
||||
while((header = OBEX_GetNextHeader(p_data->goep_response.pkt, &info)) != NULL) {
|
||||
switch (*header)
|
||||
{
|
||||
/* actually, BODY should not in this final response */
|
||||
case OBEX_HEADER_ID_BODY:
|
||||
case OBEX_HEADER_ID_END_OF_BODY:
|
||||
if (body_data == NULL) {
|
||||
/* first body header */
|
||||
body_data = header + 3; /* skip opcode, length */
|
||||
body_data_len = OBEX_GetHeaderLength(header) - 3;
|
||||
}
|
||||
else {
|
||||
/* another body header found */
|
||||
report_data_event(p_ccb, body_data, body_data_len, NULL, 0, FALSE, NULL);
|
||||
body_data = header + 3; /* skip opcode, length */
|
||||
body_data_len = OBEX_GetHeaderLength(header) - 3;
|
||||
}
|
||||
break;
|
||||
case OBEX_HEADER_ID_APP_PARAM:
|
||||
app_param = header + 3;
|
||||
app_param_len = OBEX_GetHeaderLength(header) - 3;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (body_data != NULL || app_param != NULL) {
|
||||
/* report body data and app param, dont free packet here */
|
||||
report_data_event(p_ccb, body_data, body_data_len, app_param, app_param_len, TRUE, p_data->goep_response.pkt);
|
||||
/* done, return */
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* unexpected response code or body data not found */
|
||||
reason = calculate_response_error(info.response_code);
|
||||
report_error_data_event(p_ccb, reason);
|
||||
osi_free(p_data->goep_response.pkt);
|
||||
|
||||
/* state machine is good, don't goto error */
|
||||
}
|
||||
else if (p_data->goep_response.opcode == OBEX_OPCODE_SETPATH) {
|
||||
if (info.response_code == (OBEX_RESPONSE_CODE_OK | OBEX_FINAL_BIT_MASK)) {
|
||||
report_data_event(p_ccb, NULL, 0, NULL, 0, TRUE, NULL);
|
||||
}
|
||||
else {
|
||||
reason = calculate_response_error(info.response_code);
|
||||
report_error_data_event(p_ccb, reason);
|
||||
}
|
||||
osi_free(p_data->goep_response.pkt);
|
||||
}
|
||||
else if (p_data->goep_response.opcode == OBEX_OPCODE_DISCONNECT) {
|
||||
/* received disconnect response, close goep connection now */
|
||||
reason = BTA_PBA_CLIENT_NO_ERROR;
|
||||
close_goepc_and_report(p_ccb, reason);
|
||||
osi_free(p_data->goep_response.pkt);
|
||||
}
|
||||
else {
|
||||
/* unexpected opcode or response code */
|
||||
reason = calculate_response_error(info.response_code);
|
||||
goto error;
|
||||
}
|
||||
return;
|
||||
|
||||
error:
|
||||
if (p_data->goep_response.pkt != NULL) {
|
||||
osi_free(p_data->goep_response.pkt);
|
||||
}
|
||||
close_goepc_and_report(p_ccb, reason);
|
||||
}
|
||||
|
||||
void bta_pba_client_goep_connect(tBTA_PBA_CLIENT_CCB *p_ccb, tBTA_PBA_CLIENT_DATA *p_data)
|
||||
{
|
||||
/* limit max rx to our goep mtu */
|
||||
if (p_ccb->max_rx > p_data->goep_connect.our_mtu) {
|
||||
p_ccb->max_rx = p_data->goep_connect.our_mtu;
|
||||
}
|
||||
/* limit max tx to peer goep mtu */
|
||||
if (p_ccb->max_tx > p_data->goep_connect.peer_mtu) {
|
||||
p_ccb->max_tx = p_data->goep_connect.peer_mtu;
|
||||
}
|
||||
|
||||
/* build and send obex connect request */
|
||||
tOBEX_PARSE_INFO info = {0};
|
||||
info.opcode = OBEX_OPCODE_CONNECT;
|
||||
info.obex_version_number = OBEX_VERSION_NUMBER;
|
||||
info.max_packet_length = p_ccb->max_rx;
|
||||
/* before obex connect response, we dont know the real max_tx, use BT_SMALL_BUFFER_SIZE as tx buff size */
|
||||
UINT16 ret = GOEPC_PrepareRequest(p_ccb->goep_handle, &info, BT_SMALL_BUFFER_SIZE);
|
||||
/* add target header */
|
||||
ret |= GOEPC_RequestAddHeader(p_ccb->goep_handle, OBEX_HEADER_ID_TARGET, pbap_target_uuid, 16);
|
||||
if (p_ccb->send_supported_feat) {
|
||||
/* add application parameters with supported features */
|
||||
UINT8 app_param[6];
|
||||
app_param[0] = BTA_PBAP_APP_PARAM_PBAP_SUPPORTED_FEATURES;
|
||||
app_param[1] = BTA_PBAP_APP_PARAM_LENGTH_PBAP_SUPPORTED_FEATURES;
|
||||
UINT32_TO_FIELD(&app_param[2], p_ccb->our_supported_feat);
|
||||
ret |= GOEPC_RequestAddHeader(p_ccb->goep_handle, OBEX_HEADER_ID_APP_PARAM, app_param, 6);
|
||||
}
|
||||
ret |= GOEPC_SendRequest(p_ccb->goep_handle);
|
||||
if (ret != GOEP_SUCCESS) {
|
||||
close_goepc_and_report(p_ccb, BTA_PBA_CLIENT_GOEP_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
void bta_pba_client_goep_disconnect(tBTA_PBA_CLIENT_CCB *p_ccb, tBTA_PBA_CLIENT_DATA *p_data)
|
||||
{
|
||||
p_ccb->goep_handle = 0;
|
||||
|
||||
/* report connection closed event */
|
||||
tBTA_PBA_CLIENT_CONN conn;
|
||||
conn.handle = p_ccb->allocated;
|
||||
bdcpy(conn.bd_addr, p_ccb->bd_addr);
|
||||
conn.error = BTA_PBA_CLIENT_GOEP_ERROR;
|
||||
bta_pba_client_cb.p_cback(BTA_PBA_CLIENT_CONN_CLOSE_EVT, (tBTA_PBA_CLIENT *)&conn);
|
||||
free_ccb(p_ccb);
|
||||
}
|
||||
|
||||
void bta_pba_client_free_response(tBTA_PBA_CLIENT_CCB *p_ccb, tBTA_PBA_CLIENT_DATA *p_data)
|
||||
{
|
||||
if (p_data->goep_response.pkt != NULL) {
|
||||
osi_free(p_data->goep_response.pkt);
|
||||
}
|
||||
close_goepc_and_report(p_ccb, BTA_PBA_CLIENT_GOEP_ERROR);
|
||||
}
|
||||
|
||||
#endif
|
161
components/bt/host/bluedroid/bta/pba/bta_pba_client_api.c
Normal file
161
components/bt/host/bluedroid/bta/pba/bta_pba_client_api.c
Normal file
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "osi/allocator.h"
|
||||
#include "common/bt_target.h"
|
||||
#include "stack/obex_api.h"
|
||||
#include "stack/goep_common.h"
|
||||
#include "stack/goepc_api.h"
|
||||
#include "bta/bta_sys.h"
|
||||
#include "bta/bta_api.h"
|
||||
#include "bta_pba_client_int.h"
|
||||
|
||||
#if BTA_PBA_CLIENT_INCLUDED
|
||||
|
||||
static const tBTA_SYS_REG bta_pba_client_reg = {
|
||||
bta_pba_client_hdl_event,
|
||||
BTA_PbaClientDisable
|
||||
};
|
||||
|
||||
void BTA_PbaClientEnable(tBTA_PBA_CLIENT_CBACK *p_cback)
|
||||
{
|
||||
tBTA_PBA_CLIENT_API_ENABLE *p_buf;
|
||||
|
||||
if (bta_sys_is_register(BTA_ID_PBC)) {
|
||||
APPL_TRACE_ERROR("BTA PBA Client already enabled");
|
||||
return;
|
||||
}
|
||||
|
||||
/* register with BTA system manager */
|
||||
bta_sys_register(BTA_ID_PBC, &bta_pba_client_reg);
|
||||
|
||||
if ((p_buf = (tBTA_PBA_CLIENT_API_ENABLE *)osi_malloc(sizeof(tBTA_PBA_CLIENT_API_ENABLE))) != NULL) {
|
||||
p_buf->hdr.event = BTA_PBA_CLIENT_API_ENABLE_EVT;
|
||||
p_buf->p_cback = p_cback;
|
||||
bta_sys_sendmsg(p_buf);
|
||||
}
|
||||
}
|
||||
|
||||
void BTA_PbaClientDisable(void)
|
||||
{
|
||||
BT_HDR *p_buf;
|
||||
|
||||
if ((p_buf = (BT_HDR *) osi_malloc(sizeof(BT_HDR))) != NULL) {
|
||||
p_buf->event = BTA_PBA_CLIENT_API_DISABLE_EVT;
|
||||
bta_sys_sendmsg(p_buf);
|
||||
}
|
||||
}
|
||||
|
||||
void BTA_PbaClientRegister(const char *server_name)
|
||||
{
|
||||
tBTA_PBA_CLIENT_API_REGISTER *p_buf;
|
||||
|
||||
if ((p_buf = (tBTA_PBA_CLIENT_API_REGISTER *) osi_malloc(sizeof(tBTA_PBA_CLIENT_API_REGISTER))) != NULL) {
|
||||
p_buf->hdr.event = BTA_PBA_CLIENT_API_REGISTER_EVT;
|
||||
memcpy(p_buf->name, server_name, strlen(server_name) + 1);
|
||||
bta_sys_sendmsg(p_buf);
|
||||
}
|
||||
}
|
||||
|
||||
void BTA_PbaClientDeregister(void)
|
||||
{
|
||||
BT_HDR *p_buf;
|
||||
|
||||
if ((p_buf = (BT_HDR *) osi_malloc(sizeof(BT_HDR))) != NULL) {
|
||||
p_buf->event = BTA_PBA_CLIENT_API_DEREGISTER_EVT;
|
||||
bta_sys_sendmsg(p_buf);
|
||||
}
|
||||
}
|
||||
|
||||
void BTA_PbaClientOpen(BD_ADDR bd_addr, tBTA_SEC sec_mask, UINT32 supported_feat, UINT16 mtu)
|
||||
{
|
||||
tBTA_PBA_CLIENT_API_OPEN *p_buf;
|
||||
|
||||
if ((p_buf = (tBTA_PBA_CLIENT_API_OPEN *)osi_malloc(sizeof(tBTA_PBA_CLIENT_API_OPEN))) != NULL) {
|
||||
p_buf->hdr.event = BTA_PBA_CLIENT_API_OPEN_EVT;
|
||||
p_buf->sec_mask = sec_mask;
|
||||
p_buf->mtu = mtu;
|
||||
bdcpy(p_buf->bd_addr, bd_addr);
|
||||
bta_sys_sendmsg(p_buf);
|
||||
}
|
||||
}
|
||||
|
||||
void BTA_PbaClientClose(UINT16 handle)
|
||||
{
|
||||
BT_HDR *p_buf;
|
||||
|
||||
if ((p_buf = (BT_HDR *) osi_malloc(sizeof(BT_HDR))) != NULL) {
|
||||
p_buf->event = BTA_PBA_CLIENT_API_CLOSE_EVT;
|
||||
p_buf->layer_specific = handle;
|
||||
bta_sys_sendmsg(p_buf);
|
||||
}
|
||||
}
|
||||
|
||||
void BTA_PbaClientPullPhoneBook(UINT16 handle, char *name, UINT8 *app_param, UINT16 app_param_len)
|
||||
{
|
||||
tBTA_PBA_CLIENT_API_REQ *p_buf;
|
||||
|
||||
if ((p_buf = (tBTA_PBA_CLIENT_API_REQ *) osi_malloc(sizeof(tBTA_PBA_CLIENT_API_REQ))) != NULL) {
|
||||
p_buf->hdr.event = BTA_PBA_CLIENT_API_REQ_EVT;
|
||||
p_buf->hdr.layer_specific = handle;
|
||||
p_buf->operation = BTA_PBA_CLIENT_OP_PULL_PHONE_BOOK;
|
||||
p_buf->name = name;
|
||||
p_buf->app_param = app_param;
|
||||
p_buf->app_param_len = app_param_len;
|
||||
bta_sys_sendmsg(p_buf);
|
||||
}
|
||||
}
|
||||
|
||||
void BTA_PbaClientSetPhoneBook(UINT16 handle, UINT8 flags, char *name)
|
||||
{
|
||||
tBTA_PBA_CLIENT_API_REQ *p_buf;
|
||||
|
||||
if ((p_buf = (tBTA_PBA_CLIENT_API_REQ *) osi_malloc(sizeof(tBTA_PBA_CLIENT_API_REQ))) != NULL) {
|
||||
p_buf->hdr.event = BTA_PBA_CLIENT_API_REQ_EVT;
|
||||
p_buf->hdr.layer_specific = handle;
|
||||
p_buf->operation = BTA_PBA_CLIENT_OP_SET_PHONE_BOOK;
|
||||
p_buf->flags = flags;
|
||||
p_buf->name = name;
|
||||
p_buf->app_param = NULL;
|
||||
p_buf->app_param_len = 0;
|
||||
bta_sys_sendmsg(p_buf);
|
||||
}
|
||||
}
|
||||
|
||||
void BTA_PbaClientPullvCardListing(UINT16 handle, char *name, UINT8 *app_param, UINT16 app_param_len)
|
||||
{
|
||||
tBTA_PBA_CLIENT_API_REQ *p_buf;
|
||||
|
||||
if ((p_buf = (tBTA_PBA_CLIENT_API_REQ *) osi_malloc(sizeof(tBTA_PBA_CLIENT_API_REQ))) != NULL) {
|
||||
p_buf->hdr.event = BTA_PBA_CLIENT_API_REQ_EVT;
|
||||
p_buf->hdr.layer_specific = handle;
|
||||
p_buf->operation = BTA_PBA_CLIENT_OP_PULL_VCARD_LISTING;
|
||||
p_buf->name = name;
|
||||
p_buf->app_param = app_param;
|
||||
p_buf->app_param_len = app_param_len;
|
||||
bta_sys_sendmsg(p_buf);
|
||||
}
|
||||
}
|
||||
|
||||
void BTA_PbaClientPullvCardEntry(UINT16 handle, char *name, UINT8 *app_param, UINT16 app_param_len)
|
||||
{
|
||||
tBTA_PBA_CLIENT_API_REQ *p_buf;
|
||||
|
||||
if ((p_buf = (tBTA_PBA_CLIENT_API_REQ *) osi_malloc(sizeof(tBTA_PBA_CLIENT_API_REQ))) != NULL) {
|
||||
p_buf->hdr.event = BTA_PBA_CLIENT_API_REQ_EVT;
|
||||
p_buf->hdr.layer_specific = handle;
|
||||
p_buf->operation = BTA_PBA_CLIENT_OP_PULL_VCARD_ENTRY;
|
||||
p_buf->name = name;
|
||||
p_buf->app_param = app_param;
|
||||
p_buf->app_param_len = app_param_len;
|
||||
bta_sys_sendmsg(p_buf);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
293
components/bt/host/bluedroid/bta/pba/bta_pba_client_main.c
Normal file
293
components/bt/host/bluedroid/bta/pba/bta_pba_client_main.c
Normal file
@@ -0,0 +1,293 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "osi/allocator.h"
|
||||
#include "common/bt_target.h"
|
||||
|
||||
#include "stack/obex_api.h"
|
||||
#include "stack/goep_common.h"
|
||||
#include "stack/goepc_api.h"
|
||||
#include "bta_pba_client_int.h"
|
||||
|
||||
#if BTA_PBA_CLIENT_INCLUDED
|
||||
|
||||
/* state machine states */
|
||||
enum {
|
||||
BTA_PBA_CLIENT_INIT_ST,
|
||||
BTA_PBA_CLIENT_OPENING_ST,
|
||||
BTA_PBA_CLIENT_OPENED_ST,
|
||||
BTA_PBA_CLIENT_REQUESTING_ST,
|
||||
BTA_PBA_CLIENT_CLOSING_ST
|
||||
};
|
||||
|
||||
/* state machine action enumeration list */
|
||||
enum {
|
||||
BTA_PBA_CLIENT_API_OPEN,
|
||||
BTA_PBA_CLIENT_API_CLOSE,
|
||||
BTA_PBA_CLIENT_API_REQ,
|
||||
BTA_PBA_CLIENT_DO_CONNECT,
|
||||
BTA_PBA_CLIENT_AUTHENTICATE,
|
||||
BTA_PBA_CLIENT_CONNECT,
|
||||
BTA_PBA_CLIENT_RESPONSE,
|
||||
BTA_PBA_CLIENT_RESPONSE_FINAL,
|
||||
BTA_PBA_CLIENT_GOEP_CONNECT,
|
||||
BTA_PBA_CLIENT_GOEP_DISCONNECT,
|
||||
BTA_PBA_CLIENT_FORCE_DISCONNECT,
|
||||
BTA_PBA_CLIENT_FREE_RESPONSE,
|
||||
BTA_PBA_CLIENT_NUM_ACTIONS
|
||||
};
|
||||
|
||||
#define BTA_PBA_CLIENT_IGNORE BTA_PBA_CLIENT_NUM_ACTIONS
|
||||
|
||||
/* type for action functions */
|
||||
typedef void (*tBTA_PBA_CLIENT_ACTION)(tBTA_PBA_CLIENT_CCB *p_ccb, tBTA_PBA_CLIENT_DATA *p_data);
|
||||
|
||||
/* action functions table, indexed with action enum */
|
||||
const tBTA_PBA_CLIENT_ACTION bta_pba_client_action[] = {
|
||||
/* BTA_PBA_CLIENT_API_OPEN */ bta_pba_client_api_open,
|
||||
/* BTA_PBA_CLIENT_API_CLOSE */ bta_pba_client_api_close,
|
||||
/* BTA_PBA_CLIENT_API_REQ */ bta_pba_client_api_req,
|
||||
/* BTA_PBA_CLIENT_DO_CONNECT */ bta_pba_client_do_connect,
|
||||
/* BTA_PBA_CLIENT_AUTHENTICATE */ bta_pba_client_authenticate,
|
||||
/* BTA_PBA_CLIENT_CONNECT */ bta_pba_client_connect,
|
||||
/* BTA_PBA_CLIENT_RESPONSE */ bta_pba_client_response,
|
||||
/* BTA_PBA_CLIENT_RESPONSE_FINAL */ bta_pba_client_response_final,
|
||||
/* BTA_PBA_CLIENT_GOEP_CONNECT */ bta_pba_client_goep_connect,
|
||||
/* BTA_PBA_CLIENT_GOEP_DISCONNECT*/ bta_pba_client_goep_disconnect,
|
||||
/* BTA_PBA_CLIENT_FORCE_DISCONNECT */ bta_pba_client_force_disconnect,
|
||||
/* BTA_PBA_CLIENT_FREE_RESPONSE */ bta_pba_client_free_response,
|
||||
};
|
||||
|
||||
/* state table information */
|
||||
#define BTA_PBA_CLIENT_ACTION 0 /* position of action */
|
||||
#define BTA_PBA_CLIENT_NEXT_STATE 1 /* position of next state */
|
||||
#define BTA_PBA_CLIENT_NUM_COLS 2 /* number of columns */
|
||||
|
||||
const uint8_t bta_pba_client_st_init[][BTA_PBA_CLIENT_NUM_COLS] = {
|
||||
/* Event Action Next state */
|
||||
/* BTA_PBA_CLIENT_API_OPEN_EVT */ {BTA_PBA_CLIENT_API_OPEN, BTA_PBA_CLIENT_OPENING_ST},
|
||||
/* BTA_PBA_CLIENT_API_CLOSE_EVT */ {BTA_PBA_CLIENT_IGNORE, BTA_PBA_CLIENT_INIT_ST},
|
||||
/* BTA_PBA_CLIENT_API_REQ_EVT */ {BTA_PBA_CLIENT_IGNORE, BTA_PBA_CLIENT_INIT_ST},
|
||||
/* BTA_PBA_CLIENT_DISC_RES_EVT */ {BTA_PBA_CLIENT_IGNORE, BTA_PBA_CLIENT_INIT_ST},
|
||||
/* BTA_PBA_CLIENT_AUTHENTICATE_EVT */ {BTA_PBA_CLIENT_IGNORE, BTA_PBA_CLIENT_INIT_ST},
|
||||
/* BTA_PBA_CLIENT_CONNECT_EVT */ {BTA_PBA_CLIENT_IGNORE, BTA_PBA_CLIENT_INIT_ST},
|
||||
/* BTA_PBA_CLIENT_RESPONSE_EVT */ {BTA_PBA_CLIENT_IGNORE, BTA_PBA_CLIENT_INIT_ST},
|
||||
/* BTA_PBA_CLIENT_RESPONSE_FINAL_EVT */ {BTA_PBA_CLIENT_IGNORE, BTA_PBA_CLIENT_INIT_ST},
|
||||
/* BTA_PBA_CLIENT_GOEP_CONNECT_EVT */ {BTA_PBA_CLIENT_IGNORE, BTA_PBA_CLIENT_INIT_ST},
|
||||
/* BTA_PBA_CLIENT_GOEP_DISCONNECT_EVT */ {BTA_PBA_CLIENT_IGNORE, BTA_PBA_CLIENT_INIT_ST},
|
||||
};
|
||||
|
||||
const uint8_t bta_pba_client_st_opening[][BTA_PBA_CLIENT_NUM_COLS] = {
|
||||
/* Event Action Next state */
|
||||
/* BTA_PBA_CLIENT_API_OPEN_EVT */ {BTA_PBA_CLIENT_IGNORE, BTA_PBA_CLIENT_OPENING_ST},
|
||||
/* BTA_PBA_CLIENT_API_CLOSE_EVT */ {BTA_PBA_CLIENT_FORCE_DISCONNECT, BTA_PBA_CLIENT_INIT_ST},
|
||||
/* BTA_PBA_CLIENT_API_REQ_EVT */ {BTA_PBA_CLIENT_IGNORE, BTA_PBA_CLIENT_OPENING_ST},
|
||||
/* BTA_PBA_CLIENT_DISC_RES_EVT */ {BTA_PBA_CLIENT_DO_CONNECT, BTA_PBA_CLIENT_OPENING_ST},
|
||||
/* BTA_PBA_CLIENT_AUTHENTICATE_EVT */ {BTA_PBA_CLIENT_AUTHENTICATE, BTA_PBA_CLIENT_OPENING_ST},
|
||||
/* BTA_PBA_CLIENT_CONNECT_EVT */ {BTA_PBA_CLIENT_CONNECT, BTA_PBA_CLIENT_OPENED_ST},
|
||||
/* BTA_PBA_CLIENT_RESPONSE_EVT */ {BTA_PBA_CLIENT_FREE_RESPONSE, BTA_PBA_CLIENT_OPENING_ST},
|
||||
/* BTA_PBA_CLIENT_RESPONSE_FINAL_EVT */ {BTA_PBA_CLIENT_RESPONSE_FINAL, BTA_PBA_CLIENT_OPENING_ST},
|
||||
/* BTA_PBA_CLIENT_GOEP_CONNECT_EVT */ {BTA_PBA_CLIENT_GOEP_CONNECT, BTA_PBA_CLIENT_OPENING_ST},
|
||||
/* BTA_PBA_CLIENT_GOEP_DISCONNECT_EVT */ {BTA_PBA_CLIENT_GOEP_DISCONNECT, BTA_PBA_CLIENT_INIT_ST},
|
||||
};
|
||||
|
||||
const uint8_t bta_pba_client_st_opened[][BTA_PBA_CLIENT_NUM_COLS] = {
|
||||
/* Event Action Next state */
|
||||
/* BTA_PBA_CLIENT_API_OPEN_EVT */ {BTA_PBA_CLIENT_IGNORE, BTA_PBA_CLIENT_OPENED_ST},
|
||||
/* BTA_PBA_CLIENT_API_CLOSE_EVT */ {BTA_PBA_CLIENT_API_CLOSE, BTA_PBA_CLIENT_CLOSING_ST},
|
||||
/* BTA_PBA_CLIENT_API_REQ_EVT */ {BTA_PBA_CLIENT_API_REQ, BTA_PBA_CLIENT_REQUESTING_ST},
|
||||
/* BTA_PBA_CLIENT_DISC_RES_EVT */ {BTA_PBA_CLIENT_IGNORE, BTA_PBA_CLIENT_OPENED_ST},
|
||||
/* BTA_PBA_CLIENT_AUTHENTICATE_EVT */ {BTA_PBA_CLIENT_IGNORE, BTA_PBA_CLIENT_OPENED_ST},
|
||||
/* BTA_PBA_CLIENT_CONNECT_EVT */ {BTA_PBA_CLIENT_IGNORE, BTA_PBA_CLIENT_OPENED_ST},
|
||||
/* BTA_PBA_CLIENT_RESPONSE_EVT */ {BTA_PBA_CLIENT_FREE_RESPONSE, BTA_PBA_CLIENT_OPENED_ST},
|
||||
/* BTA_PBA_CLIENT_RESPONSE_FINAL_EVT */ {BTA_PBA_CLIENT_FREE_RESPONSE, BTA_PBA_CLIENT_OPENED_ST},
|
||||
/* BTA_PBA_CLIENT_GOEP_CONNECT_EVT */ {BTA_PBA_CLIENT_IGNORE, BTA_PBA_CLIENT_OPENED_ST},
|
||||
/* BTA_PBA_CLIENT_GOEP_DISCONNECT_EVT */ {BTA_PBA_CLIENT_GOEP_DISCONNECT, BTA_PBA_CLIENT_INIT_ST},
|
||||
};
|
||||
|
||||
const uint8_t bta_pba_client_st_getting[][BTA_PBA_CLIENT_NUM_COLS] = {
|
||||
/* Event Action Next state */
|
||||
/* BTA_PBA_CLIENT_API_OPEN_EVT */ {BTA_PBA_CLIENT_IGNORE, BTA_PBA_CLIENT_REQUESTING_ST},
|
||||
/* BTA_PBA_CLIENT_API_CLOSE_EVT */ {BTA_PBA_CLIENT_FORCE_DISCONNECT, BTA_PBA_CLIENT_INIT_ST},
|
||||
/* BTA_PBA_CLIENT_API_REQ_EVT */ {BTA_PBA_CLIENT_IGNORE, BTA_PBA_CLIENT_REQUESTING_ST},
|
||||
/* BTA_PBA_CLIENT_DISC_RES_EVT */ {BTA_PBA_CLIENT_IGNORE, BTA_PBA_CLIENT_REQUESTING_ST},
|
||||
/* BTA_PBA_CLIENT_AUTHENTICATE_EVT */ {BTA_PBA_CLIENT_IGNORE, BTA_PBA_CLIENT_REQUESTING_ST},
|
||||
/* BTA_PBA_CLIENT_CONNECT_EVT */ {BTA_PBA_CLIENT_IGNORE, BTA_PBA_CLIENT_REQUESTING_ST},
|
||||
/* BTA_PBA_CLIENT_RESPONSE_EVT */ {BTA_PBA_CLIENT_RESPONSE, BTA_PBA_CLIENT_REQUESTING_ST},
|
||||
/* BTA_PBA_CLIENT_RESPONSE_FINAL_EVT */ {BTA_PBA_CLIENT_RESPONSE_FINAL, BTA_PBA_CLIENT_OPENED_ST},
|
||||
/* BTA_PBA_CLIENT_GOEP_CONNECT_EVT */ {BTA_PBA_CLIENT_IGNORE, BTA_PBA_CLIENT_REQUESTING_ST},
|
||||
/* BTA_PBA_CLIENT_GOEP_DISCONNECT_EVT */ {BTA_PBA_CLIENT_GOEP_DISCONNECT, BTA_PBA_CLIENT_INIT_ST},
|
||||
};
|
||||
|
||||
const uint8_t bta_pba_client_st_closing[][BTA_PBA_CLIENT_NUM_COLS] = {
|
||||
/* Event Action Next state */
|
||||
/* BTA_PBA_CLIENT_API_OPEN_EVT */ {BTA_PBA_CLIENT_IGNORE, BTA_PBA_CLIENT_CLOSING_ST},
|
||||
/* BTA_PBA_CLIENT_API_CLOSE_EVT */ {BTA_PBA_CLIENT_FORCE_DISCONNECT, BTA_PBA_CLIENT_INIT_ST},
|
||||
/* BTA_PBA_CLIENT_API_REQ_EVT */ {BTA_PBA_CLIENT_IGNORE, BTA_PBA_CLIENT_CLOSING_ST},
|
||||
/* BTA_PBA_CLIENT_DISC_RES_EVT */ {BTA_PBA_CLIENT_IGNORE, BTA_PBA_CLIENT_CLOSING_ST},
|
||||
/* BTA_PBA_CLIENT_AUTHENTICATE_EVT */ {BTA_PBA_CLIENT_IGNORE, BTA_PBA_CLIENT_CLOSING_ST},
|
||||
/* BTA_PBA_CLIENT_CONNECT_EVT */ {BTA_PBA_CLIENT_IGNORE, BTA_PBA_CLIENT_CLOSING_ST},
|
||||
/* BTA_PBA_CLIENT_RESPONSE_EVT */ {BTA_PBA_CLIENT_IGNORE, BTA_PBA_CLIENT_CLOSING_ST},
|
||||
/* BTA_PBA_CLIENT_RESPONSE_FINAL_EVT */ {BTA_PBA_CLIENT_RESPONSE_FINAL, BTA_PBA_CLIENT_INIT_ST},
|
||||
/* BTA_PBA_CLIENT_GOEP_CONNECT_EVT */ {BTA_PBA_CLIENT_IGNORE, BTA_PBA_CLIENT_CLOSING_ST},
|
||||
/* BTA_PBA_CLIENT_GOEP_DISCONNECT_EVT */ {BTA_PBA_CLIENT_GOEP_DISCONNECT, BTA_PBA_CLIENT_INIT_ST},
|
||||
};
|
||||
|
||||
/* type for state table */
|
||||
typedef const UINT8 (*tBTA_PBA_CLIENT_ST_TBL)[BTA_PBA_CLIENT_NUM_COLS];
|
||||
|
||||
/* state table */
|
||||
const tBTA_PBA_CLIENT_ST_TBL bta_pba_client_st_tbl[] = {
|
||||
bta_pba_client_st_init,
|
||||
bta_pba_client_st_opening,
|
||||
bta_pba_client_st_opened,
|
||||
bta_pba_client_st_getting,
|
||||
bta_pba_client_st_closing
|
||||
};
|
||||
|
||||
/* PBA Client control block */
|
||||
#if BTA_DYNAMIC_MEMORY == FALSE
|
||||
tBTA_PBA_CLIENT_CB bta_pba_client_cb;
|
||||
#else
|
||||
tBTA_PBA_CLIENT_CB *bta_pba_client_cb_ptr;
|
||||
#endif
|
||||
|
||||
static tBTA_PBA_CLIENT_CCB *allocate_ccb(void)
|
||||
{
|
||||
tBTA_PBA_CLIENT_CCB *p_ccb = NULL;
|
||||
for (int i = 0; i < PBA_CLIENT_MAX_CONNECTION; ++i) {
|
||||
if (bta_pba_client_cb.ccb[i].allocated == 0) {
|
||||
bta_pba_client_cb.ccb[i].allocated = i + 1;
|
||||
p_ccb = &bta_pba_client_cb.ccb[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
return p_ccb;
|
||||
}
|
||||
|
||||
static tBTA_PBA_CLIENT_CCB *find_ccb_by_handle(UINT16 handle)
|
||||
{
|
||||
tBTA_PBA_CLIENT_CCB *p_ccb = NULL;
|
||||
for (int i = 0; i < PBA_CLIENT_MAX_CONNECTION; ++i) {
|
||||
if (bta_pba_client_cb.ccb[i].allocated != 0 && bta_pba_client_cb.ccb[i].allocated == handle) {
|
||||
p_ccb = &bta_pba_client_cb.ccb[i];
|
||||
}
|
||||
}
|
||||
return p_ccb;
|
||||
}
|
||||
|
||||
static tBTA_PBA_CLIENT_CCB *find_ccb_by_goep_handle(UINT16 goep_handle)
|
||||
{
|
||||
tBTA_PBA_CLIENT_CCB *p_ccb = NULL;
|
||||
for (int i = 0; i < PBA_CLIENT_MAX_CONNECTION; ++i) {
|
||||
if (bta_pba_client_cb.ccb[i].allocated != 0 && bta_pba_client_cb.ccb[i].goep_handle == goep_handle) {
|
||||
p_ccb = &bta_pba_client_cb.ccb[i];
|
||||
}
|
||||
}
|
||||
return p_ccb;
|
||||
}
|
||||
|
||||
static tBTA_PBA_CLIENT_CCB *find_ccb_by_bd_addr(BD_ADDR bd_addr)
|
||||
{
|
||||
tBTA_PBA_CLIENT_CCB *p_ccb = NULL;
|
||||
for (int i = 0; i < PBA_CLIENT_MAX_CONNECTION; ++i) {
|
||||
if (bta_pba_client_cb.ccb[i].allocated != 0 && bdcmp(bta_pba_client_cb.ccb[i].bd_addr, bd_addr) == 0) {
|
||||
p_ccb = &bta_pba_client_cb.ccb[i];
|
||||
}
|
||||
}
|
||||
return p_ccb;
|
||||
}
|
||||
|
||||
void bta_pba_client_sm_execute(tBTA_PBA_CLIENT_CCB *p_ccb, UINT16 event, tBTA_PBA_CLIENT_DATA *p_data)
|
||||
{
|
||||
tBTA_PBA_CLIENT_ST_TBL state_table;
|
||||
UINT8 action;
|
||||
|
||||
state_table = bta_pba_client_st_tbl[p_ccb->state];
|
||||
|
||||
event &= 0xff;
|
||||
|
||||
p_ccb->state = state_table[event][BTA_PBA_CLIENT_NEXT_STATE];
|
||||
|
||||
if ((action = state_table[event][BTA_PBA_CLIENT_ACTION]) != BTA_PBA_CLIENT_IGNORE) {
|
||||
(*bta_pba_client_action[action])(p_ccb, p_data);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
BOOLEAN bta_pba_client_hdl_event(BT_HDR *p_msg)
|
||||
{
|
||||
tBTA_PBA_CLIENT_CCB *p_ccb = NULL;
|
||||
BOOLEAN execute_sm = FALSE;
|
||||
tBTA_PBA_CLIENT_CONN conn = {0};
|
||||
tBTA_PBA_CLIENT_DATA *p_data = (tBTA_PBA_CLIENT_DATA *)p_msg;
|
||||
|
||||
switch (p_msg->event) {
|
||||
case BTA_PBA_CLIENT_API_ENABLE_EVT:
|
||||
bta_pba_client_api_enable(p_data);
|
||||
break;
|
||||
case BTA_PBA_CLIENT_API_DISABLE_EVT:
|
||||
bta_pba_client_api_disable(p_data);
|
||||
break;
|
||||
case BTA_PBA_CLIENT_API_REGISTER_EVT:
|
||||
bta_pba_client_api_register(p_data);
|
||||
break;
|
||||
case BTA_PBA_CLIENT_API_DEREGISTER_EVT:
|
||||
bta_pba_client_api_deregister(p_data);
|
||||
break;
|
||||
case BTA_PBA_CLIENT_API_OPEN_EVT:
|
||||
if (find_ccb_by_bd_addr(p_data->api_open.bd_addr) != NULL) {
|
||||
/* already connected */
|
||||
conn.handle = 0;
|
||||
conn.error = BTA_PBA_CLIENT_ALREADY_CONN;
|
||||
bdcpy(conn.bd_addr, p_data->api_open.bd_addr);
|
||||
bta_pba_client_cb.p_cback(BTA_PBA_CLIENT_CONN_OPEN_EVT, (tBTA_PBA_CLIENT *)&conn);
|
||||
/* break, don't execute sm */
|
||||
break;
|
||||
}
|
||||
p_ccb = allocate_ccb();
|
||||
if (p_ccb == NULL) {
|
||||
/* no resource to allocate ccb */
|
||||
conn.handle = 0;
|
||||
conn.error = BTA_PBA_CLIENT_NO_RESOURCE;
|
||||
bdcpy(conn.bd_addr, p_data->api_open.bd_addr);
|
||||
bta_pba_client_cb.p_cback(BTA_PBA_CLIENT_CONN_OPEN_EVT, (tBTA_PBA_CLIENT *)&conn);
|
||||
/* break, don't execute sm */
|
||||
break;
|
||||
}
|
||||
execute_sm = TRUE;
|
||||
break;
|
||||
case BTA_PBA_CLIENT_GOEP_CONNECT_EVT:
|
||||
case BTA_PBA_CLIENT_GOEP_DISCONNECT_EVT:
|
||||
case BTA_PBA_CLIENT_RESPONSE_EVT:
|
||||
case BTA_PBA_CLIENT_RESPONSE_FINAL_EVT:
|
||||
p_ccb = find_ccb_by_goep_handle(p_msg->layer_specific);
|
||||
if (p_ccb == NULL) {
|
||||
/* ignore event with invalid goep handle */
|
||||
break;
|
||||
}
|
||||
execute_sm = TRUE;
|
||||
break;
|
||||
default:
|
||||
p_ccb = find_ccb_by_handle(p_msg->layer_specific);
|
||||
if (p_ccb == NULL) {
|
||||
/* ignore event with invalid handle */
|
||||
break;
|
||||
}
|
||||
execute_sm = TRUE;
|
||||
}
|
||||
|
||||
if (execute_sm) {
|
||||
bta_pba_client_sm_execute(p_ccb, p_msg->event, (tBTA_PBA_CLIENT_DATA *) p_msg);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#endif
|
280
components/bt/host/bluedroid/bta/pba/bta_pba_client_sdp.c
Normal file
280
components/bt/host/bluedroid/bta/pba/bta_pba_client_sdp.c
Normal file
@@ -0,0 +1,280 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include "osi/allocator.h"
|
||||
#include "common/bt_defs.h"
|
||||
#include "stack/sdp_api.h"
|
||||
#include "bta/bta_api.h"
|
||||
#include "bta/bta_pba_defs.h"
|
||||
#include "bta/bta_pba_client_api.h"
|
||||
#include "bta_pba_client_int.h"
|
||||
|
||||
#if BTA_PBA_CLIENT_INCLUDED
|
||||
|
||||
/* Number of elements in service class id list. */
|
||||
#define BTA_PBA_CLIENT_NUM_SVC_ELEMS 1
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function bta_pba_client_sdp_cback
|
||||
**
|
||||
** Description SDP callback function.
|
||||
**
|
||||
**
|
||||
** Returns void
|
||||
**
|
||||
*******************************************************************************/
|
||||
static void bta_pba_client_sdp_cback(UINT16 status, void *user_data)
|
||||
{
|
||||
tBTA_PBA_CLIENT_DISC_RESULT *p_buf;
|
||||
tBTA_PBA_CLIENT_CCB *p_ccb = (tBTA_PBA_CLIENT_CCB *)user_data;
|
||||
|
||||
APPL_TRACE_DEBUG("bta_pba_client_sdp_cback status:0x%x", status);
|
||||
|
||||
if ((p_buf = (tBTA_PBA_CLIENT_DISC_RESULT *) osi_malloc(sizeof(tBTA_PBA_CLIENT_DISC_RESULT))) != NULL) {
|
||||
p_buf->hdr.event = BTA_PBA_CLIENT_DISC_RES_EVT;
|
||||
p_buf->hdr.layer_specific = p_ccb->allocated;
|
||||
p_buf->status = status;
|
||||
bta_sys_sendmsg(p_buf);
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
**
|
||||
** Function bta_pba_client_add_record
|
||||
**
|
||||
** Description Add PBA Client information to an SDP record. Prior to
|
||||
** calling this function the application must call
|
||||
** SDP_CreateRecord() to create an SDP record.
|
||||
**
|
||||
** Returns TRUE if function execution succeeded,
|
||||
** FALSE if function execution failed.
|
||||
**
|
||||
******************************************************************************/
|
||||
static BOOLEAN bta_pba_client_add_record(const char *p_service_name, UINT32 sdp_handle)
|
||||
{
|
||||
UINT16 svc_class_id_list[BTA_PBA_CLIENT_NUM_SVC_ELEMS];
|
||||
UINT16 version;
|
||||
UINT16 profile_uuid;
|
||||
BOOLEAN result = TRUE;
|
||||
|
||||
APPL_TRACE_DEBUG("bta_pba_client_add_record");
|
||||
|
||||
/* add service class id list */
|
||||
svc_class_id_list[0] = UUID_SERVCLASS_PBAP_PCE;
|
||||
result &= SDP_AddServiceClassIdList(sdp_handle, BTA_PBA_CLIENT_NUM_SVC_ELEMS, svc_class_id_list);
|
||||
|
||||
/* add service name */
|
||||
if (p_service_name != NULL && p_service_name[0] != 0) {
|
||||
result &= SDP_AddAttribute(sdp_handle, ATTR_ID_SERVICE_NAME, TEXT_STR_DESC_TYPE,
|
||||
(UINT32)(strlen(p_service_name) + 1), (UINT8 *) p_service_name);
|
||||
}
|
||||
|
||||
/* add profile descriptor list */
|
||||
profile_uuid = UUID_SERVCLASS_PHONE_ACCESS;
|
||||
version = PBAP_PCE_VERSION;
|
||||
result &= SDP_AddProfileDescriptorList(sdp_handle, profile_uuid, version);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function bta_pba_client_create_record
|
||||
**
|
||||
** Description Create SDP record for registered service.
|
||||
**
|
||||
**
|
||||
** Returns void
|
||||
**
|
||||
*******************************************************************************/
|
||||
void bta_pba_client_create_record(const char *p_service_name)
|
||||
{
|
||||
/* add sdp record if not already registered */
|
||||
if (bta_pba_client_cb.sdp_handle == 0) {
|
||||
bta_pba_client_cb.sdp_handle = SDP_CreateRecord();
|
||||
bta_pba_client_add_record(p_service_name, bta_pba_client_cb.sdp_handle);
|
||||
bta_sys_add_uuid(UUID_SERVCLASS_PBAP_PCE);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function bta_pba_client_del_record
|
||||
**
|
||||
** Description Delete SDP record for registered service.
|
||||
**
|
||||
**
|
||||
** Returns void
|
||||
**
|
||||
*******************************************************************************/
|
||||
void bta_pba_client_del_record(void)
|
||||
{
|
||||
APPL_TRACE_DEBUG("bta_pba_client_del_record");
|
||||
|
||||
if (bta_pba_client_cb.sdp_handle != 0) {
|
||||
SDP_DeleteRecord(bta_pba_client_cb.sdp_handle);
|
||||
bta_pba_client_cb.sdp_handle = 0;
|
||||
bta_sys_remove_uuid(UUID_SERVCLASS_PBAP_PCE);
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function bta_pba_client_sdp_find_attr
|
||||
**
|
||||
** Description Process SDP discovery results to find requested attribute
|
||||
**
|
||||
**
|
||||
** Returns TRUE if results found, FALSE otherwise.
|
||||
**
|
||||
*******************************************************************************/
|
||||
BOOLEAN bta_pba_client_sdp_find_attr(tBTA_PBA_CLIENT_CCB *p_ccb)
|
||||
{
|
||||
tSDP_DISC_REC *p_rec = NULL;
|
||||
tSDP_DISC_ATTR *p_attr;
|
||||
tSDP_PROTOCOL_ELEM pe;
|
||||
BOOLEAN result = FALSE;
|
||||
|
||||
/* loop through all records we found */
|
||||
while (TRUE) {
|
||||
/* get next record; if none found, we're done */
|
||||
if ((p_rec = SDP_FindServiceInDb(p_ccb->p_disc_db, UUID_SERVCLASS_PBAP_PSE, p_rec)) == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* get rfcomm scn from proto desc list */
|
||||
if (SDP_FindProtocolListElemInRec(p_rec, UUID_PROTOCOL_RFCOMM, &pe)) {
|
||||
p_ccb->peer_rfcomm_scn = (UINT8) pe.params[0];
|
||||
}
|
||||
else {
|
||||
/* not found, go to next record */
|
||||
continue;
|
||||
}
|
||||
|
||||
/* get supported repositories */
|
||||
if ((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_SUPPORTED_REPOSITORIES)) != NULL) {
|
||||
/* Found attribute, get value */
|
||||
p_ccb->peer_supported_repo = p_attr->attr_value.v.u8;
|
||||
}
|
||||
else {
|
||||
/* not found, clear rfcomm scn and go to next record */
|
||||
p_ccb->peer_rfcomm_scn = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* get profile version */
|
||||
SDP_FindProfileVersionInRec(p_rec, UUID_SERVCLASS_PHONE_ACCESS, &p_ccb->peer_version);
|
||||
|
||||
/* get GOEP L2CAP PSM */
|
||||
if ((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_GOEP_L2CAP_PSM)) != NULL) {
|
||||
/* Found attribute, get value */
|
||||
p_ccb->peer_l2cap_psm = p_attr->attr_value.v.u16;
|
||||
}
|
||||
|
||||
/* try to get supported features */
|
||||
if ((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_PBAP_SUPPORTED_FEATURES)) != NULL) {
|
||||
/* found attribute, get value */
|
||||
p_ccb->peer_supported_feat = p_attr->attr_value.v.u32;
|
||||
p_ccb->send_supported_feat = TRUE;
|
||||
}
|
||||
else {
|
||||
/* assume as default value if not found in sdp record */
|
||||
p_ccb->peer_supported_feat = BTA_PBAP_DEFAULT_SUPPORTED_FEATURES;
|
||||
p_ccb->send_supported_feat = FALSE;
|
||||
}
|
||||
|
||||
/* found what we needed */
|
||||
result = TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
APPL_TRACE_DEBUG("%s peer_version:0x%x, supported repositories:0x%x, supported features:0x%x",
|
||||
__FUNCTION__, p_ccb->peer_version, p_ccb->peer_supported_repo, p_ccb->peer_supported_feat);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function bta_pba_client_do_disc
|
||||
**
|
||||
** Description Do service discovery.
|
||||
**
|
||||
**
|
||||
** Returns TRUE if start service discovery successfully
|
||||
**
|
||||
*******************************************************************************/
|
||||
BOOLEAN bta_pba_client_do_disc(tBTA_PBA_CLIENT_CCB *p_ccb)
|
||||
{
|
||||
tSDP_UUID uuid_list[1];
|
||||
UINT16 num_uuid = 1;
|
||||
UINT16 attr_list[4];
|
||||
UINT8 num_attr;
|
||||
BOOLEAN db_inited = FALSE;
|
||||
|
||||
/* get proto list and features */
|
||||
attr_list[0] = ATTR_ID_SERVICE_CLASS_ID_LIST;
|
||||
attr_list[1] = ATTR_ID_PROTOCOL_DESC_LIST;
|
||||
attr_list[2] = ATTR_ID_BT_PROFILE_DESC_LIST;
|
||||
attr_list[3] = ATTR_ID_GOEP_L2CAP_PSM;
|
||||
attr_list[4] = ATTR_ID_SUPPORTED_REPOSITORIES;
|
||||
attr_list[5] = ATTR_ID_PBAP_SUPPORTED_FEATURES;
|
||||
num_attr = 6;
|
||||
uuid_list[0].uu.uuid16 = UUID_SERVCLASS_PBAP_PSE;
|
||||
uuid_list[0].len = LEN_UUID_16;
|
||||
|
||||
if (p_ccb->p_disc_db != NULL) {
|
||||
APPL_TRACE_WARNING("%s service discovery already in progress", __FUNCTION__);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* allocate buffer for sdp database */
|
||||
p_ccb->p_disc_db = (tSDP_DISCOVERY_DB *) osi_malloc(BT_DEFAULT_BUFFER_SIZE);
|
||||
|
||||
if (p_ccb->p_disc_db) {
|
||||
/* set up service discovery database; attr happens to be attr_list len */
|
||||
db_inited = SDP_InitDiscoveryDb(p_ccb->p_disc_db, BT_DEFAULT_BUFFER_SIZE, num_uuid,
|
||||
uuid_list, num_attr, attr_list);
|
||||
}
|
||||
|
||||
if (db_inited) {
|
||||
/*start service discovery */
|
||||
/* todo: avoid p_ccb being free during sdp */
|
||||
db_inited = SDP_ServiceSearchAttributeRequest2(p_ccb->bd_addr, p_ccb->p_disc_db,
|
||||
bta_pba_client_sdp_cback, p_ccb);
|
||||
}
|
||||
|
||||
if (!db_inited) {
|
||||
/*free discover db */
|
||||
bta_pba_client_free_db(p_ccb);
|
||||
APPL_TRACE_ERROR("%s start service discovery failed", __FUNCTION__);
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function bta_hf_client_free_db
|
||||
**
|
||||
** Description Free discovery database.
|
||||
**
|
||||
**
|
||||
** Returns void
|
||||
**
|
||||
*******************************************************************************/
|
||||
void bta_pba_client_free_db(tBTA_PBA_CLIENT_CCB *p_ccb)
|
||||
{
|
||||
if (p_ccb->p_disc_db != NULL) {
|
||||
osi_free(p_ccb->p_disc_db);
|
||||
p_ccb->p_disc_db = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
@@ -0,0 +1,177 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "osi/list.h"
|
||||
#include "common/bt_target.h"
|
||||
#include "stack/sdp_api.h"
|
||||
#include "stack/obex_api.h"
|
||||
#include "bta/bta_sys.h"
|
||||
#include "bta/bta_api.h"
|
||||
#include "bta/bta_pba_client_api.h"
|
||||
|
||||
#if BTA_PBA_CLIENT_INCLUDED
|
||||
|
||||
#define PBA_CLIENT_MAX_CONNECTION 2
|
||||
|
||||
#define PBA_CLIENT_MAX_MTU L2CAP_MTU_SIZE /* RFCOMM is base on L2CAP, its MTU will smaller than this */
|
||||
#define PBA_CLIENT_MIN_MTU 255
|
||||
|
||||
enum {
|
||||
/* these events are handled by the state machine */
|
||||
BTA_PBA_CLIENT_API_OPEN_EVT = BTA_SYS_EVT_START(BTA_ID_PBC),
|
||||
BTA_PBA_CLIENT_API_CLOSE_EVT,
|
||||
BTA_PBA_CLIENT_API_REQ_EVT,
|
||||
BTA_PBA_CLIENT_DISC_RES_EVT,
|
||||
BTA_PBA_CLIENT_AUTHENTICATE_EVT,
|
||||
BTA_PBA_CLIENT_CONNECT_EVT,
|
||||
BTA_PBA_CLIENT_RESPONSE_EVT,
|
||||
BTA_PBA_CLIENT_RESPONSE_FINAL_EVT,
|
||||
BTA_PBA_CLIENT_GOEP_CONNECT_EVT,
|
||||
BTA_PBA_CLIENT_GOEP_DISCONNECT_EVT,
|
||||
|
||||
/* these events are handled outside of the state machine */
|
||||
BTA_PBA_CLIENT_API_ENABLE_EVT,
|
||||
BTA_PBA_CLIENT_API_DISABLE_EVT,
|
||||
BTA_PBA_CLIENT_API_REGISTER_EVT,
|
||||
BTA_PBA_CLIENT_API_DEREGISTER_EVT,
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
BTA_PBA_CLIENT_OP_PULL_PHONE_BOOK,
|
||||
BTA_PBA_CLIENT_OP_SET_PHONE_BOOK,
|
||||
BTA_PBA_CLIENT_OP_PULL_VCARD_LISTING,
|
||||
BTA_PBA_CLIENT_OP_PULL_VCARD_ENTRY,
|
||||
} tBTA_PBA_CLIENT_OP;
|
||||
|
||||
typedef struct {
|
||||
BT_HDR hdr;
|
||||
tBTA_PBA_CLIENT_CBACK *p_cback;
|
||||
} tBTA_PBA_CLIENT_API_ENABLE;
|
||||
|
||||
typedef struct {
|
||||
BT_HDR hdr;
|
||||
char name[BTA_SERVICE_NAME_LEN + 1];
|
||||
} tBTA_PBA_CLIENT_API_REGISTER;
|
||||
|
||||
typedef struct {
|
||||
BT_HDR hdr;
|
||||
BD_ADDR bd_addr;
|
||||
tBTA_SEC sec_mask;
|
||||
UINT16 mtu;
|
||||
UINT32 supported_feat;
|
||||
} tBTA_PBA_CLIENT_API_OPEN;
|
||||
|
||||
typedef struct {
|
||||
BT_HDR hdr;
|
||||
UINT8 operation;
|
||||
UINT8 flags;
|
||||
char *name;
|
||||
UINT16 app_param_len;
|
||||
UINT8 *app_param;
|
||||
} tBTA_PBA_CLIENT_API_REQ;
|
||||
|
||||
typedef struct {
|
||||
BT_HDR hdr;
|
||||
UINT16 status;
|
||||
} tBTA_PBA_CLIENT_DISC_RESULT;
|
||||
|
||||
typedef struct {
|
||||
BT_HDR hdr;
|
||||
UINT16 our_mtu;
|
||||
UINT16 peer_mtu;
|
||||
} tBTA_PBA_CLIENT_GOEP_CONNECT;
|
||||
|
||||
typedef struct {
|
||||
BT_HDR hdr;
|
||||
UINT16 reason;
|
||||
} tBTA_PBA_CLIENT_GOEP_DISCONNECT;
|
||||
|
||||
typedef struct {
|
||||
BT_HDR hdr;
|
||||
BT_HDR *pkt;
|
||||
UINT8 opcode;
|
||||
BOOLEAN srm_en;
|
||||
BOOLEAN srm_wait;
|
||||
} tBTA_PBA_CLIENT_GOEP_RESPONSE;
|
||||
|
||||
typedef union {
|
||||
BT_HDR hdr;
|
||||
tBTA_PBA_CLIENT_API_ENABLE api_enable;
|
||||
tBTA_PBA_CLIENT_API_REGISTER api_register;
|
||||
tBTA_PBA_CLIENT_API_OPEN api_open;
|
||||
tBTA_PBA_CLIENT_API_REQ api_req;
|
||||
tBTA_PBA_CLIENT_DISC_RESULT disc_result;
|
||||
tBTA_PBA_CLIENT_GOEP_CONNECT goep_connect;
|
||||
tBTA_PBA_CLIENT_GOEP_DISCONNECT goep_disconnect;
|
||||
tBTA_PBA_CLIENT_GOEP_RESPONSE goep_response;
|
||||
} tBTA_PBA_CLIENT_DATA;
|
||||
|
||||
typedef struct {
|
||||
BD_ADDR bd_addr; /* peer BD address */
|
||||
tSDP_DISCOVERY_DB *p_disc_db; /* pointer to discovery database */
|
||||
tBTA_SEC sec_mask; /* security mask */
|
||||
UINT16 peer_version; /* peer profile version */
|
||||
UINT16 peer_l2cap_psm; /* peer l2cap psm */
|
||||
UINT8 peer_rfcomm_scn; /* peer rfcomm scn */
|
||||
UINT8 peer_supported_repo; /* peer supported repositories */
|
||||
UINT32 peer_supported_feat; /* peer supported features */
|
||||
UINT32 our_supported_feat; /* we supported features */
|
||||
BOOLEAN send_supported_feat; /* whether we should send supported features in connect request */
|
||||
UINT16 goep_handle; /* goep connection handle */
|
||||
UINT32 goep_cid; /* goep connection id */
|
||||
UINT16 max_rx; /* max rx bytes */
|
||||
UINT16 max_tx; /* max tx bytes */
|
||||
BOOLEAN authenticate; /* whether we are authenticated */
|
||||
tBTA_PBA_CLIENT_OP operation; /* ongoing or last operations */
|
||||
UINT8 state; /* main state machine */
|
||||
UINT8 allocated; /* index + 1 if allocated, otherwise 0 */
|
||||
} tBTA_PBA_CLIENT_CCB;
|
||||
|
||||
typedef struct {
|
||||
tBTA_PBA_CLIENT_CCB ccb[PBA_CLIENT_MAX_CONNECTION]; /* connection control block */
|
||||
tBTA_PBA_CLIENT_CBACK *p_cback; /* message callback to upper */
|
||||
UINT32 sdp_handle; /* sdp record handle */
|
||||
UINT8 trace_level; /* debug trace level */
|
||||
} tBTA_PBA_CLIENT_CB;
|
||||
|
||||
#if BTA_DYNAMIC_MEMORY == FALSE
|
||||
extern tBTA_PBA_CLIENT_CB bta_pba_client_cb;
|
||||
#else
|
||||
extern tBTA_PBA_CLIENT_CB *bta_pba_client_cb_ptr;
|
||||
#define bta_pba_client_cb (*bta_pba_client_cb_ptr)
|
||||
#endif
|
||||
|
||||
extern void bta_pba_client_api_enable(tBTA_PBA_CLIENT_DATA *p_data);
|
||||
extern void bta_pba_client_api_disable(tBTA_PBA_CLIENT_DATA *p_data);
|
||||
extern void bta_pba_client_api_register(tBTA_PBA_CLIENT_DATA *p_data);
|
||||
extern void bta_pba_client_api_deregister(tBTA_PBA_CLIENT_DATA *p_data);
|
||||
extern void bta_pba_client_api_open(tBTA_PBA_CLIENT_CCB *p_ccb, tBTA_PBA_CLIENT_DATA *p_data);
|
||||
extern void bta_pba_client_api_close(tBTA_PBA_CLIENT_CCB *p_ccb, tBTA_PBA_CLIENT_DATA *p_data);
|
||||
extern void bta_pba_client_api_req(tBTA_PBA_CLIENT_CCB *p_ccb, tBTA_PBA_CLIENT_DATA *p_data);
|
||||
extern void bta_pba_client_do_connect(tBTA_PBA_CLIENT_CCB *p_ccb, tBTA_PBA_CLIENT_DATA *p_data);
|
||||
extern void bta_pba_client_authenticate(tBTA_PBA_CLIENT_CCB *p_ccb, tBTA_PBA_CLIENT_DATA *p_data);
|
||||
extern void bta_pba_client_force_disconnect(tBTA_PBA_CLIENT_CCB *p_ccb, tBTA_PBA_CLIENT_DATA *p_data);
|
||||
|
||||
extern void bta_pba_client_connect(tBTA_PBA_CLIENT_CCB *p_ccb, tBTA_PBA_CLIENT_DATA *p_data);
|
||||
extern void bta_pba_client_response(tBTA_PBA_CLIENT_CCB *p_ccb, tBTA_PBA_CLIENT_DATA *p_data);
|
||||
extern void bta_pba_client_response_final(tBTA_PBA_CLIENT_CCB *p_ccb, tBTA_PBA_CLIENT_DATA *p_data);
|
||||
void bta_pba_client_goep_connect(tBTA_PBA_CLIENT_CCB *p_ccb, tBTA_PBA_CLIENT_DATA *p_data);
|
||||
void bta_pba_client_goep_disconnect(tBTA_PBA_CLIENT_CCB *p_ccb, tBTA_PBA_CLIENT_DATA *p_data);
|
||||
void bta_pba_client_free_response(tBTA_PBA_CLIENT_CCB *p_ccb, tBTA_PBA_CLIENT_DATA *p_data);
|
||||
void bta_pba_client_free_sdp_db(tBTA_PBA_CLIENT_CCB *p_ccb, tBTA_PBA_CLIENT_DATA *p_data);
|
||||
|
||||
extern void bta_pba_client_create_record(const char *p_service_name);
|
||||
extern void bta_pba_client_del_record(void);
|
||||
extern BOOLEAN bta_pba_client_sdp_find_attr(tBTA_PBA_CLIENT_CCB *p_ccb);
|
||||
extern BOOLEAN bta_pba_client_do_disc(tBTA_PBA_CLIENT_CCB *p_ccb);
|
||||
extern void bta_pba_client_free_db(tBTA_PBA_CLIENT_CCB *p_ccb);
|
||||
|
||||
extern void bta_pba_client_sm_execute(tBTA_PBA_CLIENT_CCB *p_ccb, UINT16 event, tBTA_PBA_CLIENT_DATA *p_data);
|
||||
extern BOOLEAN bta_pba_client_hdl_event(BT_HDR *p_msg);
|
||||
|
||||
#endif
|
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/bt_defs.h"
|
||||
#include "esp_pbac_api.h"
|
||||
|
||||
#if BTC_PBA_CLIENT_INCLUDED
|
||||
|
||||
typedef enum {
|
||||
BTC_PBA_CLIENT_INIT_EVT = 0,
|
||||
BTC_PBA_CLIENT_DEINIT_EVT,
|
||||
BTC_PBA_CLIENT_CONNECT_EVT,
|
||||
BTC_PBA_CLIENT_DISCONNECT_EVT,
|
||||
BTC_PBA_CLIENT_PULL_PHONE_BOOK_EVT,
|
||||
BTC_PBA_CLIENT_SET_PHONE_BOOK_EVT,
|
||||
BTC_PBA_CLIENT_SET_PHONE_BOOK2_EVT,
|
||||
BTC_PBA_CLIENT_PULL_VCARD_LISTING_EVT,
|
||||
BTC_PBA_CLIENT_PULL_VCARD_ENTRY_EVT
|
||||
} BTC_PBA_CLIENT_EVT;
|
||||
|
||||
/* equal to BTA max conn */
|
||||
#define BTC_PBA_CLIENT_MAX_CONN_NUM 2
|
||||
|
||||
typedef struct {
|
||||
uint16_t handle;
|
||||
bt_bdaddr_t bd_addr;
|
||||
char *path;
|
||||
uint16_t path_len;
|
||||
uint16_t path_pos;
|
||||
bool busy;
|
||||
} btc_pba_client_ccb_t;
|
||||
|
||||
typedef struct {
|
||||
btc_pba_client_ccb_t ccb[BTC_PBA_CLIENT_MAX_CONN_NUM];
|
||||
} btc_pba_client_cb_t;
|
||||
|
||||
typedef union {
|
||||
// BTC_PBA_CLIENT_CONNECT_EVT
|
||||
struct pba_client_connect_arg {
|
||||
bt_bdaddr_t bd_addr;
|
||||
} connect;
|
||||
|
||||
// BTC_PBA_CLIENT_DISCONNECT_EVT
|
||||
struct pba_client_disconnect_arg {
|
||||
uint16_t handle;
|
||||
} disconnect;
|
||||
|
||||
// BTC_PBA_CLIENT_PULL_PHONE_BOOK_EVT
|
||||
struct pba_client_pull_phone_book_arg {
|
||||
uint16_t handle;
|
||||
char *name;
|
||||
bool include_app_param;
|
||||
esp_pbac_pull_phone_book_app_param_t app_param;
|
||||
} pull_phone_book;
|
||||
|
||||
// BTC_PBA_CLIENT_SET_PHONE_BOOK_EVT
|
||||
struct pba_client_set_phone_book_arg {
|
||||
uint16_t handle;
|
||||
uint8_t flags;
|
||||
char *name;
|
||||
} set_phone_book;
|
||||
|
||||
// BTC_PBA_CLIENT_PULL_VCARD_LISTING_EVT
|
||||
struct pba_client_pull_vcard_listing_arg {
|
||||
uint16_t handle;
|
||||
char *name;
|
||||
bool include_app_param;
|
||||
esp_pbac_pull_vcard_listing_app_param_t app_param;
|
||||
} pull_vcard_listing;
|
||||
|
||||
// BTC_PBA_CLIENT_PULL_VCARD_ENTRY_EVT
|
||||
struct pba_client_pull_vcard_entry_arg {
|
||||
uint16_t handle;
|
||||
char *name;
|
||||
bool include_app_param;
|
||||
esp_pbac_pull_vcard_entry_app_param_t app_param;
|
||||
} pull_vcard_entry;
|
||||
} btc_pba_client_args_t;
|
||||
|
||||
void btc_pba_client_call_handler(btc_msg_t *msg);
|
||||
void btc_pba_client_cb_handler(btc_msg_t *msg);
|
||||
void btc_pba_client_args_deep_free(btc_msg_t *msg);
|
||||
void btc_pba_client_args_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src);
|
||||
|
||||
#endif
|
@@ -0,0 +1,971 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "osi/allocator.h"
|
||||
|
||||
#include "bta/bta_api.h"
|
||||
#include "bta/bta_pba_defs.h"
|
||||
#include "bta/bta_pba_client_api.h"
|
||||
#include "btc/btc_profile_queue.h"
|
||||
#include "btc/btc_manage.h"
|
||||
#include "btc/btc_task.h"
|
||||
#include "btc_pba_client.h"
|
||||
#include "esp_pbac_api.h"
|
||||
|
||||
#if BTC_PBA_CLIENT_INCLUDED
|
||||
|
||||
#define BTC_PBA_CLIENT_SECURITY (BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT)
|
||||
|
||||
static bool s_btc_pba_client_init = 0;
|
||||
|
||||
btc_pba_client_cb_t btc_pba_client_cb;
|
||||
|
||||
static void bte_pba_client_evt(tBTA_PBA_CLIENT_EVT event, tBTA_PBA_CLIENT *p_data)
|
||||
{
|
||||
bt_status_t status;
|
||||
int param_len = 0;
|
||||
bool ignore = false;
|
||||
|
||||
switch (event) {
|
||||
case BTA_PBA_CLIENT_CONN_OPEN_EVT:
|
||||
case BTA_PBA_CLIENT_CONN_CLOSE_EVT:
|
||||
param_len = sizeof(tBTA_PBA_CLIENT_CONN);
|
||||
break;
|
||||
case BTA_PBA_CLIENT_PULL_PHONE_BOOK_RSP_EVT:
|
||||
case BTA_PBA_CLIENT_SET_PHONE_BOOK_RSP_EVT:
|
||||
case BTA_PBA_CLIENT_PULL_VCARD_LISTING_RSP_EVT:
|
||||
case BTA_PBA_CLIENT_PULL_VCARD_ENTRY_RSP_EVT:
|
||||
param_len = sizeof(tBTA_PBA_CLIENT_RESPONSE);
|
||||
break;
|
||||
case BTA_PBA_CLIENT_REGISTER_EVT:
|
||||
param_len = 0;
|
||||
break;
|
||||
case BTA_PBA_CLIENT_DISABLE_EVT:
|
||||
param_len = 0;
|
||||
break;
|
||||
case BTA_PBA_CLIENT_ENABLE_EVT:
|
||||
case BTA_PBA_CLIENT_DEREGISTER_EVT:
|
||||
default:
|
||||
ignore = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (ignore) {
|
||||
return;
|
||||
}
|
||||
|
||||
btc_msg_t msg;
|
||||
msg.sig = BTC_SIG_API_CB;
|
||||
msg.pid = BTC_PID_PBA_CLIENT;
|
||||
msg.act = event;
|
||||
|
||||
status = btc_transfer_context(&msg, p_data, param_len, NULL, NULL);
|
||||
if (status != BT_STATUS_SUCCESS) {
|
||||
BTC_TRACE_ERROR("context transfer failed");
|
||||
}
|
||||
}
|
||||
|
||||
static void btc_pba_client_callback_to_app(esp_pbac_event_t event, esp_pbac_param_t *param)
|
||||
{
|
||||
esp_pbac_callback_t callback = (esp_pbac_callback_t)btc_profile_cb_get(BTC_PID_PBA_CLIENT);
|
||||
if (callback) {
|
||||
callback(event, param);
|
||||
}
|
||||
}
|
||||
|
||||
static void btc_pba_client_init(void)
|
||||
{
|
||||
if (!s_btc_pba_client_init) {
|
||||
s_btc_pba_client_init = true;
|
||||
memset(&btc_pba_client_cb, 0, sizeof(btc_pba_client_cb_t));
|
||||
/* enable pba client */
|
||||
BTA_PbaClientEnable(bte_pba_client_evt);
|
||||
/* register sdp record */
|
||||
BTA_PbaClientRegister("Phonebook Access PCE");
|
||||
}
|
||||
}
|
||||
|
||||
static void btc_pba_client_deinit(void)
|
||||
{
|
||||
if (s_btc_pba_client_init) {
|
||||
s_btc_pba_client_init = false;
|
||||
/* deregister sdp record */
|
||||
BTA_PbaClientDeregister();
|
||||
/* disable pba client */
|
||||
BTA_PbaClientDisable();
|
||||
}
|
||||
}
|
||||
|
||||
static BOOLEAN is_connected(bt_bdaddr_t *bd_addr)
|
||||
{
|
||||
for (int i = 0; i < BTC_PBA_CLIENT_MAX_CONN_NUM; ++i) {
|
||||
if (btc_pba_client_cb.ccb[i].handle != 0 && bdcmp(bd_addr->address, btc_pba_client_cb.ccb[i].bd_addr.address) == 0) {
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static bt_status_t connect_int(bt_bdaddr_t *bd_addr, uint16_t uuid)
|
||||
{
|
||||
if (is_connected(bd_addr)) {
|
||||
return BT_STATUS_BUSY;
|
||||
}
|
||||
|
||||
BTA_PbaClientOpen(bd_addr->address, BTC_PBA_CLIENT_SECURITY, (uint32_t)BTC_PBA_SUPPORTED_FEAT, (uint16_t)BTC_PBA_PREFERRED_MTU);
|
||||
|
||||
return BT_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static void btc_pba_client_connect(bt_bdaddr_t *bd_addr)
|
||||
{
|
||||
if (!s_btc_pba_client_init) {
|
||||
return;
|
||||
}
|
||||
|
||||
btc_queue_connect(UUID_SERVCLASS_PBAP_PCE, bd_addr, connect_int);
|
||||
}
|
||||
|
||||
static void btc_pba_client_disconnect(uint16_t handle)
|
||||
{
|
||||
do {
|
||||
if (!s_btc_pba_client_init) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (handle == 0 || handle > BTC_PBA_CLIENT_MAX_CONN_NUM) {
|
||||
/* invalid handle value */
|
||||
break;
|
||||
}
|
||||
|
||||
btc_pba_client_ccb_t *p_ccb = &btc_pba_client_cb.ccb[handle - 1];
|
||||
if (p_ccb->handle != handle) {
|
||||
/* not connect */
|
||||
break;
|
||||
}
|
||||
|
||||
BTA_PbaClientClose(handle);
|
||||
} while (0);
|
||||
}
|
||||
|
||||
static bool btc_pba_client_pull_phone_book(uint16_t handle, char *name, bool include_app_param, esp_pbac_pull_phone_book_app_param_t *app_param)
|
||||
{
|
||||
bt_status_t err = BT_STATUS_FAIL;
|
||||
uint8_t *app_param_buff = NULL;
|
||||
uint16_t app_param_len = 0;
|
||||
|
||||
do {
|
||||
if (!s_btc_pba_client_init) {
|
||||
/* pba client not init */
|
||||
err = BT_STATUS_NOT_READY;
|
||||
break;
|
||||
}
|
||||
|
||||
if (handle == 0 || handle > BTC_PBA_CLIENT_MAX_CONN_NUM) {
|
||||
/* invalid handle value */
|
||||
err = BT_STATUS_PARM_INVALID;
|
||||
break;
|
||||
}
|
||||
|
||||
btc_pba_client_ccb_t *p_ccb = &btc_pba_client_cb.ccb[handle - 1];
|
||||
if (p_ccb->handle != handle) {
|
||||
/* not connect */
|
||||
err = BT_STATUS_PARM_INVALID;
|
||||
break;
|
||||
}
|
||||
|
||||
if (p_ccb->busy) {
|
||||
/* busy */
|
||||
err = BT_STATUS_BUSY;
|
||||
break;
|
||||
}
|
||||
|
||||
if (include_app_param) {
|
||||
app_param_buff = osi_malloc(BTA_PBAP_PULL_PHONE_BOOK_APP_PARAM_BUFF_SIZE_MIN);
|
||||
if (app_param_buff == NULL) {
|
||||
err = BT_STATUS_NOMEM;
|
||||
break;
|
||||
}
|
||||
uint8_t *p = app_param_buff;
|
||||
if (app_param->include_property_selector) {
|
||||
UINT8_TO_BE_STREAM(p, BTA_PBAP_APP_PARAM_PROPERTY_SELECTOR);
|
||||
UINT8_TO_BE_STREAM(p, BTA_PBAP_APP_PARAM_LENGTH_PROPERTY_SELECTOR);
|
||||
UINT64_TO_BE_STREAM(p, app_param->property_selector);
|
||||
}
|
||||
if (app_param->include_format) {
|
||||
UINT8_TO_BE_STREAM(p, BTA_PBAP_APP_PARAM_FORMAT);
|
||||
UINT8_TO_BE_STREAM(p, BTA_PBAP_APP_PARAM_LENGTH_FORMAT);
|
||||
UINT8_TO_BE_STREAM(p, app_param->format);
|
||||
}
|
||||
if (app_param->include_max_list_count) {
|
||||
UINT8_TO_BE_STREAM(p, BTA_PBAP_APP_PARAM_MAX_LIST_COUNT);
|
||||
UINT8_TO_BE_STREAM(p, BTA_PBAP_APP_PARAM_LENGTH_MAX_LIST_COUNT);
|
||||
UINT16_TO_BE_STREAM(p, app_param->max_list_count);
|
||||
}
|
||||
if (app_param->include_list_start_offset) {
|
||||
UINT8_TO_BE_STREAM(p, BTA_PBAP_APP_PARAM_LIST_START_OFFSET);
|
||||
UINT8_TO_BE_STREAM(p, BTA_PBAP_APP_PARAM_LENGTH_LIST_START_OFFSET);
|
||||
UINT16_TO_BE_STREAM(p, app_param->list_start_offset);
|
||||
}
|
||||
if (app_param->include_reset_new_missed_calls) {
|
||||
UINT8_TO_BE_STREAM(p, BTA_PBAP_APP_PARAM_RESET_NEW_MISSED_CALLS);
|
||||
UINT8_TO_BE_STREAM(p, BTA_PBAP_APP_PARAM_LENGTH_RESET_NEW_MISSED_CALLS);
|
||||
UINT8_TO_BE_STREAM(p, app_param->reset_new_missed_calls);
|
||||
}
|
||||
if (app_param->include_vcard_selector) {
|
||||
UINT8_TO_BE_STREAM(p, BTA_PBAP_APP_PARAM_VCARD_SELECTOR);
|
||||
UINT8_TO_BE_STREAM(p, BTA_PBAP_APP_PARAM_LENGTH_VCARD_SELECTOR);
|
||||
UINT64_TO_BE_STREAM(p, app_param->vcard_selector);
|
||||
}
|
||||
if (app_param->include_vcard_selector_operator) {
|
||||
UINT8_TO_BE_STREAM(p, BTA_PBAP_APP_PARAM_VCARD_SELECTOR_OPERATOR);
|
||||
UINT8_TO_BE_STREAM(p, BTA_PBAP_APP_PARAM_LENGTH_VCARD_SELECTOR_OPERATOR);
|
||||
UINT8_TO_BE_STREAM(p, app_param->vcard_selector_operator);
|
||||
}
|
||||
app_param_len = p - app_param_buff;
|
||||
assert(app_param_len <= BTA_PBAP_PULL_PHONE_BOOK_APP_PARAM_BUFF_SIZE_MIN);
|
||||
if (app_param_len == 0) {
|
||||
/* user give us an empty app param, allow but not recommend */
|
||||
osi_free(app_param_buff);
|
||||
app_param_buff = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
p_ccb->busy = true;
|
||||
BTA_PbaClientPullPhoneBook(handle, name, app_param_buff, app_param_len);
|
||||
err = BT_STATUS_SUCCESS;
|
||||
} while (0);
|
||||
|
||||
if (err != BT_STATUS_SUCCESS) {
|
||||
BTC_TRACE_WARNING("%s failed, handle: %d, reason: %d", __FUNCTION__, handle, err);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool btc_pba_client_set_phone_book(uint16_t handle, uint8_t flags, char *name)
|
||||
{
|
||||
bt_status_t err = BT_STATUS_FAIL;
|
||||
|
||||
do {
|
||||
if (!s_btc_pba_client_init) {
|
||||
/* pba client not init */
|
||||
err = BT_STATUS_NOT_READY;
|
||||
break;
|
||||
}
|
||||
|
||||
if (handle == 0 || handle > BTC_PBA_CLIENT_MAX_CONN_NUM) {
|
||||
/* invalid handle value */
|
||||
err = BT_STATUS_PARM_INVALID;
|
||||
break;
|
||||
}
|
||||
|
||||
btc_pba_client_ccb_t *p_ccb = &btc_pba_client_cb.ccb[handle - 1];
|
||||
if (p_ccb->handle != handle) {
|
||||
/* not connect */
|
||||
err = BT_STATUS_PARM_INVALID;
|
||||
break;
|
||||
}
|
||||
|
||||
if (p_ccb->busy) {
|
||||
/* busy */
|
||||
err = BT_STATUS_BUSY;
|
||||
break;
|
||||
}
|
||||
|
||||
p_ccb->busy = true;
|
||||
BTA_PbaClientSetPhoneBook(handle, flags, (char *)name);
|
||||
err = BT_STATUS_SUCCESS;
|
||||
} while (0);
|
||||
|
||||
if (err != BT_STATUS_SUCCESS) {
|
||||
BTC_TRACE_WARNING("%s failed, handle: %d, reason: %d", __FUNCTION__, handle, err);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool btc_pba_client_set_phone_book2(uint16_t handle, char *path)
|
||||
{
|
||||
bt_status_t err = BT_STATUS_FAIL;
|
||||
|
||||
do {
|
||||
if (!s_btc_pba_client_init) {
|
||||
/* pba client not init */
|
||||
err = BT_STATUS_NOT_READY;
|
||||
break;
|
||||
}
|
||||
|
||||
if (handle == 0 || handle > BTC_PBA_CLIENT_MAX_CONN_NUM) {
|
||||
/* invalid handle value */
|
||||
err = BT_STATUS_PARM_INVALID;
|
||||
break;
|
||||
}
|
||||
|
||||
btc_pba_client_ccb_t *p_ccb = &btc_pba_client_cb.ccb[handle - 1];
|
||||
if (p_ccb->handle != handle) {
|
||||
/* not connect */
|
||||
err = BT_STATUS_PARM_INVALID;
|
||||
break;
|
||||
}
|
||||
|
||||
if (p_ccb->busy) {
|
||||
/* busy */
|
||||
err = BT_STATUS_BUSY;
|
||||
break;
|
||||
}
|
||||
|
||||
p_ccb->busy = true;
|
||||
if (path != NULL) {
|
||||
p_ccb->path_len = strlen(path) + 1;
|
||||
/* ignore the first slash */
|
||||
if (path[0] == '/') {
|
||||
p_ccb->path_pos = 1;
|
||||
}
|
||||
else {
|
||||
p_ccb->path_pos = 0;
|
||||
}
|
||||
/* since we use absolute path, treat empty path as go to ROOT */
|
||||
if (p_ccb->path_len == p_ccb->path_pos + 1) {
|
||||
p_ccb->path_len = 0;
|
||||
p_ccb->path_pos = 0;
|
||||
osi_free(path);
|
||||
path = NULL;
|
||||
}
|
||||
else {
|
||||
p_ccb->path = path;
|
||||
}
|
||||
}
|
||||
/* anyway, go to ROOT first */
|
||||
char *empty_name = osi_malloc(1);
|
||||
assert(empty_name != NULL);
|
||||
*empty_name = '\0';
|
||||
BTA_PbaClientSetPhoneBook(handle, ESP_PBAC_SET_PHONE_BOOK_FLAGS_ROOT, empty_name);
|
||||
err = BT_STATUS_SUCCESS;
|
||||
} while (0);
|
||||
|
||||
if (err != BT_STATUS_SUCCESS) {
|
||||
BTC_TRACE_WARNING("%s failed, handle: %d, reason: %d", __FUNCTION__, handle, err);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool btc_pba_client_pull_vcard_listing(uint16_t handle, char *name, bool include_app_param, esp_pbac_pull_vcard_listing_app_param_t *app_param)
|
||||
{
|
||||
bt_status_t err = BT_STATUS_FAIL;
|
||||
uint8_t *app_param_buff = NULL;
|
||||
uint16_t app_param_len = 0;
|
||||
|
||||
do {
|
||||
if (!s_btc_pba_client_init) {
|
||||
/* pba client not init */
|
||||
err = BT_STATUS_NOT_READY;
|
||||
break;
|
||||
}
|
||||
|
||||
if (handle == 0 || handle > BTC_PBA_CLIENT_MAX_CONN_NUM) {
|
||||
/* invalid handle value */
|
||||
err = BT_STATUS_PARM_INVALID;
|
||||
break;
|
||||
}
|
||||
|
||||
btc_pba_client_ccb_t *p_ccb = &btc_pba_client_cb.ccb[handle - 1];
|
||||
if (p_ccb->handle != handle) {
|
||||
/* not connect */
|
||||
err = BT_STATUS_PARM_INVALID;
|
||||
break;
|
||||
}
|
||||
|
||||
if (p_ccb->busy) {
|
||||
/* busy */
|
||||
err = BT_STATUS_BUSY;
|
||||
break;
|
||||
}
|
||||
|
||||
if (include_app_param) {
|
||||
uint8_t search_value_len = 0;
|
||||
if (app_param->include_search_value) {
|
||||
search_value_len = strlen(app_param->search_value) + 1;
|
||||
}
|
||||
app_param_buff = osi_malloc(BTA_PBAP_PULL_VCARD_LISTING_APP_PARAM_BUFF_SIZE_MIN + search_value_len);
|
||||
if (app_param_buff == NULL) {
|
||||
err = BT_STATUS_NOMEM;
|
||||
break;
|
||||
}
|
||||
|
||||
uint8_t *p = app_param_buff;
|
||||
if (app_param->include_order) {
|
||||
UINT8_TO_BE_STREAM(p, BTA_PBAP_APP_PARAM_ORDER);
|
||||
UINT8_TO_BE_STREAM(p, BTA_PBAP_APP_PARAM_LENGTH_ORDER);
|
||||
UINT8_TO_BE_STREAM(p, app_param->order);
|
||||
}
|
||||
if (app_param->include_search_value) {
|
||||
UINT8_TO_BE_STREAM(p, BTA_PBAP_APP_PARAM_SEARCH_VALUE);
|
||||
UINT8_TO_BE_STREAM(p, search_value_len);
|
||||
memcpy(p, app_param->search_value, search_value_len);
|
||||
p += search_value_len;
|
||||
}
|
||||
if (app_param->include_search_property) {
|
||||
UINT8_TO_BE_STREAM(p, BTA_PBAP_APP_PARAM_SEARCH_PROPERTY);
|
||||
UINT8_TO_BE_STREAM(p, BTA_PBAP_APP_PARAM_LENGTH_SEARCH_PROPERTY);
|
||||
UINT8_TO_BE_STREAM(p, app_param->search_property);
|
||||
}
|
||||
if (app_param->include_max_list_count) {
|
||||
UINT8_TO_BE_STREAM(p, BTA_PBAP_APP_PARAM_MAX_LIST_COUNT);
|
||||
UINT8_TO_BE_STREAM(p, BTA_PBAP_APP_PARAM_LENGTH_MAX_LIST_COUNT);
|
||||
UINT16_TO_BE_STREAM(p, app_param->max_list_count);
|
||||
}
|
||||
if (app_param->include_list_start_offset) {
|
||||
UINT8_TO_BE_STREAM(p, BTA_PBAP_APP_PARAM_LIST_START_OFFSET);
|
||||
UINT8_TO_BE_STREAM(p, BTA_PBAP_APP_PARAM_LENGTH_LIST_START_OFFSET);
|
||||
UINT16_TO_BE_STREAM(p, app_param->list_start_offset);
|
||||
}
|
||||
if (app_param->include_reset_new_missed_calls) {
|
||||
UINT8_TO_BE_STREAM(p, BTA_PBAP_APP_PARAM_RESET_NEW_MISSED_CALLS);
|
||||
UINT8_TO_BE_STREAM(p, BTA_PBAP_APP_PARAM_LENGTH_RESET_NEW_MISSED_CALLS);
|
||||
UINT8_TO_BE_STREAM(p, app_param->reset_new_missed_calls);
|
||||
}
|
||||
if (app_param->include_vcard_selector) {
|
||||
UINT8_TO_BE_STREAM(p, BTA_PBAP_APP_PARAM_VCARD_SELECTOR);
|
||||
UINT8_TO_BE_STREAM(p, BTA_PBAP_APP_PARAM_LENGTH_VCARD_SELECTOR);
|
||||
UINT64_TO_BE_STREAM(p, app_param->vcard_selector);
|
||||
}
|
||||
if (app_param->include_vcard_selector_operator) {
|
||||
UINT8_TO_BE_STREAM(p, BTA_PBAP_APP_PARAM_VCARD_SELECTOR_OPERATOR);
|
||||
UINT8_TO_BE_STREAM(p, BTA_PBAP_APP_PARAM_LENGTH_VCARD_SELECTOR_OPERATOR);
|
||||
UINT8_TO_BE_STREAM(p, app_param->vcard_selector_operator);
|
||||
}
|
||||
app_param_len = p - app_param_buff;
|
||||
assert(app_param_len <= BTA_PBAP_PULL_VCARD_LISTING_APP_PARAM_BUFF_SIZE_MIN + search_value_len);
|
||||
if (app_param_len == 0) {
|
||||
/* user give us an empty app param, allow but not recommend */
|
||||
osi_free(app_param_buff);
|
||||
app_param_buff = NULL;
|
||||
}
|
||||
/* free search_value (allocated by deep_copy) */
|
||||
if (app_param->include_search_value && app_param->search_value) {
|
||||
osi_free(app_param->search_value);
|
||||
app_param->search_value = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
p_ccb->busy = true;
|
||||
BTA_PbaClientPullvCardListing(handle, (char *)name, app_param_buff, app_param_len);
|
||||
err = BT_STATUS_SUCCESS;
|
||||
} while (0);
|
||||
|
||||
if (err != BT_STATUS_SUCCESS) {
|
||||
BTC_TRACE_WARNING("%s failed, handle: %d, reason: %d", __FUNCTION__, handle, err);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool btc_pba_client_pull_vcard_entry(uint16_t handle, char *name, bool include_app_param, esp_pbac_pull_vcard_entry_app_param_t *app_param)
|
||||
{
|
||||
bt_status_t err = BT_STATUS_FAIL;
|
||||
uint8_t *app_param_buff = NULL;
|
||||
uint16_t app_param_len = 0;
|
||||
|
||||
do {
|
||||
if (!s_btc_pba_client_init) {
|
||||
/* pba client not init */
|
||||
err = BT_STATUS_NOT_READY;
|
||||
break;
|
||||
}
|
||||
|
||||
if (handle == 0 || handle > BTC_PBA_CLIENT_MAX_CONN_NUM) {
|
||||
/* invalid handle value */
|
||||
err = BT_STATUS_PARM_INVALID;
|
||||
break;
|
||||
}
|
||||
|
||||
btc_pba_client_ccb_t *p_ccb = &btc_pba_client_cb.ccb[handle - 1];
|
||||
if (p_ccb->handle != handle) {
|
||||
/* not connect */
|
||||
err = BT_STATUS_PARM_INVALID;
|
||||
break;
|
||||
}
|
||||
|
||||
if (p_ccb->busy) {
|
||||
/* busy */
|
||||
err = BT_STATUS_BUSY;
|
||||
break;
|
||||
}
|
||||
|
||||
if (include_app_param) {
|
||||
app_param_buff = osi_malloc(BTA_PBAP_PULL_VCARD_ENTRY_APP_PARAM_BUFF_SIZE_MIN);
|
||||
if (app_param_buff == NULL) {
|
||||
err = BT_STATUS_NOMEM;
|
||||
break;
|
||||
}
|
||||
uint8_t *p = app_param_buff;
|
||||
if (app_param->include_property_selector) {
|
||||
UINT8_TO_BE_STREAM(p, BTA_PBAP_APP_PARAM_PROPERTY_SELECTOR);
|
||||
UINT8_TO_BE_STREAM(p, BTA_PBAP_APP_PARAM_LENGTH_PROPERTY_SELECTOR);
|
||||
UINT64_TO_BE_STREAM(p, app_param->property_selector);
|
||||
}
|
||||
if (app_param->include_format) {
|
||||
UINT8_TO_BE_STREAM(p, BTA_PBAP_APP_PARAM_FORMAT);
|
||||
UINT8_TO_BE_STREAM(p, BTA_PBAP_APP_PARAM_LENGTH_FORMAT);
|
||||
UINT8_TO_BE_STREAM(p, app_param->format);
|
||||
}
|
||||
app_param_len = p - app_param_buff;
|
||||
assert(app_param_len <= BTA_PBAP_PULL_VCARD_ENTRY_APP_PARAM_BUFF_SIZE_MIN);
|
||||
if (app_param_len == 0) {
|
||||
/* user give us an empty app param, allow but not recommend */
|
||||
osi_free(app_param_buff);
|
||||
app_param_buff = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
p_ccb->busy = true;
|
||||
BTA_PbaClientPullvCardEntry(handle, (char *)name, app_param_buff, app_param_len);
|
||||
err = BT_STATUS_SUCCESS;
|
||||
} while (0);
|
||||
|
||||
if (err != BT_STATUS_SUCCESS) {
|
||||
BTC_TRACE_WARNING("%s failed, handle: %d, reason: %d", __FUNCTION__, handle, err);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void btc_pba_client_args_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src)
|
||||
{
|
||||
btc_pba_client_args_t *dst = (btc_pba_client_args_t *)p_dest;
|
||||
btc_pba_client_args_t *src = (btc_pba_client_args_t *)p_src;
|
||||
size_t len;
|
||||
|
||||
switch (msg->act) {
|
||||
case BTC_PBA_CLIENT_PULL_PHONE_BOOK_EVT:
|
||||
len = strlen(src->pull_phone_book.name) + 1;
|
||||
dst->pull_phone_book.name = (char *)osi_malloc(len);
|
||||
if (dst->pull_phone_book.name) {
|
||||
memcpy(dst->pull_phone_book.name, src->pull_phone_book.name, len);
|
||||
} else {
|
||||
BTC_TRACE_ERROR("%s %d no mem\n", __FUNCTION__, msg->act);
|
||||
}
|
||||
break;
|
||||
case BTC_PBA_CLIENT_PULL_VCARD_LISTING_EVT:
|
||||
len = strlen(src->pull_vcard_listing.name) + 1;
|
||||
dst->pull_vcard_listing.name = (char *)osi_malloc(len);
|
||||
if (dst->pull_vcard_listing.name) {
|
||||
memcpy(dst->pull_vcard_listing.name, src->pull_vcard_listing.name, len);
|
||||
} else {
|
||||
BTC_TRACE_ERROR("%s %d no mem\n", __FUNCTION__, msg->act);
|
||||
}
|
||||
if (src->pull_vcard_listing.include_app_param && src->pull_vcard_listing.app_param.include_search_value) {
|
||||
len = strlen(src->pull_vcard_listing.app_param.search_value) + 1;
|
||||
dst->pull_vcard_listing.app_param.search_value = (char *)osi_malloc(len);
|
||||
if (dst->pull_vcard_listing.app_param.search_value) {
|
||||
memcpy(dst->pull_vcard_listing.app_param.search_value, src->pull_vcard_listing.app_param.search_value, len);
|
||||
} else {
|
||||
BTC_TRACE_ERROR("%s %d no mem\n", __FUNCTION__, msg->act);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BTC_PBA_CLIENT_PULL_VCARD_ENTRY_EVT:
|
||||
len = strlen(src->pull_vcard_entry.name) + 1;
|
||||
dst->pull_vcard_entry.name = (char *)osi_malloc(len);
|
||||
if (dst->pull_vcard_entry.name) {
|
||||
memcpy(dst->pull_vcard_entry.name, src->pull_vcard_entry.name, len);
|
||||
} else {
|
||||
BTC_TRACE_ERROR("%s %d no mem\n", __FUNCTION__, msg->act);
|
||||
}
|
||||
break;
|
||||
case BTC_PBA_CLIENT_SET_PHONE_BOOK_EVT:
|
||||
case BTC_PBA_CLIENT_SET_PHONE_BOOK2_EVT:
|
||||
/* set phone book name may be NULL */
|
||||
if (src->set_phone_book.name) {
|
||||
len = strlen(src->set_phone_book.name) + 1;
|
||||
dst->set_phone_book.name = (char *)osi_malloc(len);
|
||||
if (dst->set_phone_book.name) {
|
||||
memcpy(dst->set_phone_book.name, src->set_phone_book.name, len);
|
||||
} else {
|
||||
BTC_TRACE_ERROR("%s %d no mem\n", __FUNCTION__, msg->act);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
BTC_TRACE_DEBUG("%s Unhandled deep copy %d\n", __FUNCTION__, msg->act);
|
||||
UNUSED(dst);
|
||||
UNUSED(src);
|
||||
UNUSED(len);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void btc_pba_client_args_deep_free(btc_msg_t *msg)
|
||||
{
|
||||
btc_pba_client_args_t *arg = (btc_pba_client_args_t *)msg->arg;
|
||||
|
||||
switch (msg->act) {
|
||||
case BTC_PBA_CLIENT_PULL_PHONE_BOOK_EVT:
|
||||
if (arg->pull_phone_book.name) {
|
||||
osi_free(arg->pull_phone_book.name);
|
||||
}
|
||||
break;
|
||||
case BTC_PBA_CLIENT_PULL_VCARD_LISTING_EVT:
|
||||
if (arg->pull_vcard_listing.name) {
|
||||
osi_free(arg->pull_vcard_listing.name);
|
||||
}
|
||||
if (arg->pull_vcard_listing.include_app_param
|
||||
&& arg->pull_vcard_listing.app_param.include_search_value
|
||||
&& arg->pull_vcard_listing.app_param.search_value) {
|
||||
osi_free(arg->pull_vcard_listing.app_param.search_value);
|
||||
}
|
||||
break;
|
||||
case BTC_PBA_CLIENT_PULL_VCARD_ENTRY_EVT:
|
||||
if (arg->pull_vcard_entry.name) {
|
||||
osi_free(arg->pull_vcard_entry.name);
|
||||
}
|
||||
break;
|
||||
case BTC_PBA_CLIENT_SET_PHONE_BOOK_EVT:
|
||||
case BTC_PBA_CLIENT_SET_PHONE_BOOK2_EVT:
|
||||
if (arg->set_phone_book.name) {
|
||||
osi_free(arg->set_phone_book.name);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
BTC_TRACE_DEBUG("%s Unhandled deep free %d\n", __FUNCTION__, msg->act);
|
||||
UNUSED(arg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void btc_pba_client_call_handler(btc_msg_t *msg)
|
||||
{
|
||||
bool ret = true;
|
||||
btc_pba_client_args_t *arg = (btc_pba_client_args_t *)(msg->arg);
|
||||
switch (msg->act) {
|
||||
case BTC_PBA_CLIENT_INIT_EVT:
|
||||
btc_pba_client_init();
|
||||
break;
|
||||
case BTC_PBA_CLIENT_DEINIT_EVT:
|
||||
btc_pba_client_deinit();
|
||||
break;
|
||||
case BTC_PBA_CLIENT_CONNECT_EVT:
|
||||
btc_pba_client_connect(&arg->connect.bd_addr);
|
||||
break;
|
||||
case BTC_PBA_CLIENT_DISCONNECT_EVT:
|
||||
btc_pba_client_disconnect(arg->disconnect.handle);
|
||||
break;
|
||||
case BTC_PBA_CLIENT_PULL_PHONE_BOOK_EVT:
|
||||
ret = btc_pba_client_pull_phone_book(arg->pull_phone_book.handle, arg->pull_phone_book.name, arg->pull_phone_book.include_app_param, &arg->pull_phone_book.app_param);
|
||||
break;
|
||||
case BTC_PBA_CLIENT_SET_PHONE_BOOK_EVT:
|
||||
ret = btc_pba_client_set_phone_book(arg->set_phone_book.handle, arg->set_phone_book.flags, arg->set_phone_book.name);
|
||||
break;
|
||||
case BTC_PBA_CLIENT_SET_PHONE_BOOK2_EVT:
|
||||
ret = btc_pba_client_set_phone_book2(arg->set_phone_book.handle, arg->set_phone_book.name);
|
||||
break;
|
||||
case BTC_PBA_CLIENT_PULL_VCARD_LISTING_EVT:
|
||||
ret = btc_pba_client_pull_vcard_listing(arg->pull_vcard_listing.handle, arg->pull_vcard_listing.name, arg->pull_vcard_listing.include_app_param, &arg->pull_vcard_listing.app_param);
|
||||
break;
|
||||
case BTC_PBA_CLIENT_PULL_VCARD_ENTRY_EVT:
|
||||
ret = btc_pba_client_pull_vcard_entry(arg->pull_vcard_entry.handle, arg->pull_vcard_entry.name, arg->pull_vcard_entry.include_app_param, &arg->pull_vcard_entry.app_param);
|
||||
break;
|
||||
default:
|
||||
BTC_TRACE_WARNING("unknown pba client action %i", msg->act);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!ret) {
|
||||
/* operation failed, do deep free */
|
||||
btc_pba_client_args_deep_free(msg);
|
||||
}
|
||||
}
|
||||
|
||||
static void parse_pull_phone_book_app_param(esp_pbac_param_t *param, uint8_t *app_param, uint16_t app_param_len)
|
||||
{
|
||||
if (app_param == NULL || app_param_len == 0) {
|
||||
return;
|
||||
}
|
||||
uint8_t *ptr = app_param;
|
||||
while(ptr < app_param + app_param_len) {
|
||||
switch (*ptr)
|
||||
{
|
||||
case BTA_PBAP_APP_PARAM_PHONE_BOOK_SIZE:
|
||||
param->pull_phone_book_rsp.include_phone_book_size = 1;
|
||||
ptr += BTA_PBAP_APP_PARAM_HEADER_LENGTH;
|
||||
BE_STREAM_TO_UINT16(param->pull_phone_book_rsp.phone_book_size, ptr);
|
||||
break;
|
||||
case BTA_PBAP_APP_PARAM_NEW_MISSED_CALLS:
|
||||
param->pull_phone_book_rsp.include_new_missed_calls = 1;
|
||||
ptr += BTA_PBAP_APP_PARAM_HEADER_LENGTH;
|
||||
BE_STREAM_TO_UINT8(param->pull_phone_book_rsp.new_missed_calls, ptr);
|
||||
break;
|
||||
case BTA_PBAP_APP_PARAM_PRIMARY_FOLDER_VERSION:
|
||||
param->pull_phone_book_rsp.include_primary_folder_version = 1;
|
||||
ptr += BTA_PBAP_APP_PARAM_HEADER_LENGTH;
|
||||
/* don't copy */
|
||||
param->pull_phone_book_rsp.primary_folder_version = ptr;
|
||||
ptr += BTA_PBAP_APP_PARAM_LENGTH_PRIMARY_FOLDER_VERSION;
|
||||
break;
|
||||
case BTA_PBAP_APP_PARAM_SECONDARY_FOLDER_VERSION:
|
||||
param->pull_phone_book_rsp.include_secondary_folder_version = 1;
|
||||
ptr += BTA_PBAP_APP_PARAM_HEADER_LENGTH;
|
||||
/* don't copy */
|
||||
param->pull_phone_book_rsp.secondary_folder_version = ptr;
|
||||
ptr += BTA_PBAP_APP_PARAM_LENGTH_SECONDARY_FOLDER_VERSION;
|
||||
break;
|
||||
case BTA_PBAP_APP_PARAM_DATABASE_IDENTIFIER:
|
||||
param->pull_phone_book_rsp.include_database_identifier = 1;
|
||||
ptr += BTA_PBAP_APP_PARAM_HEADER_LENGTH;
|
||||
/* don't copy */
|
||||
param->pull_phone_book_rsp.database_identifier = ptr;
|
||||
ptr += BTA_PBAP_APP_PARAM_LENGTH_DATABASE_IDENTIFIER;
|
||||
break;
|
||||
default:
|
||||
goto error;
|
||||
break;
|
||||
}
|
||||
}
|
||||
error:
|
||||
return;
|
||||
}
|
||||
|
||||
static void parse_pull_vcard_listing_app_param(esp_pbac_param_t *param, uint8_t *app_param, uint16_t app_param_len)
|
||||
{
|
||||
if (app_param == NULL || app_param_len == 0) {
|
||||
return;
|
||||
}
|
||||
uint8_t *ptr = app_param;
|
||||
while(ptr < app_param + app_param_len) {
|
||||
switch (*ptr)
|
||||
{
|
||||
case BTA_PBAP_APP_PARAM_PHONE_BOOK_SIZE:
|
||||
param->pull_vcard_listing_rsp.include_phone_book_size = 1;
|
||||
ptr += BTA_PBAP_APP_PARAM_HEADER_LENGTH;
|
||||
BE_STREAM_TO_UINT16(param->pull_vcard_listing_rsp.phone_book_size, ptr);
|
||||
break;
|
||||
case BTA_PBAP_APP_PARAM_NEW_MISSED_CALLS:
|
||||
param->pull_vcard_listing_rsp.include_new_missed_calls = 1;
|
||||
ptr += BTA_PBAP_APP_PARAM_HEADER_LENGTH;
|
||||
BE_STREAM_TO_UINT8(param->pull_vcard_listing_rsp.new_missed_calls, ptr);
|
||||
break;
|
||||
case BTA_PBAP_APP_PARAM_PRIMARY_FOLDER_VERSION:
|
||||
param->pull_vcard_listing_rsp.include_primary_folder_version = 1;
|
||||
ptr += BTA_PBAP_APP_PARAM_HEADER_LENGTH;
|
||||
/* don't copy */
|
||||
param->pull_vcard_listing_rsp.primary_folder_version = ptr;
|
||||
ptr += BTA_PBAP_APP_PARAM_LENGTH_PRIMARY_FOLDER_VERSION;
|
||||
break;
|
||||
case BTA_PBAP_APP_PARAM_SECONDARY_FOLDER_VERSION:
|
||||
param->pull_vcard_listing_rsp.include_secondary_folder_version = 1;
|
||||
ptr += BTA_PBAP_APP_PARAM_HEADER_LENGTH;
|
||||
/* don't copy */
|
||||
param->pull_vcard_listing_rsp.secondary_folder_version = ptr;
|
||||
ptr += BTA_PBAP_APP_PARAM_LENGTH_SECONDARY_FOLDER_VERSION;
|
||||
break;
|
||||
case BTA_PBAP_APP_PARAM_DATABASE_IDENTIFIER:
|
||||
param->pull_vcard_listing_rsp.include_database_identifier = 1;
|
||||
ptr += BTA_PBAP_APP_PARAM_HEADER_LENGTH;
|
||||
/* don't copy */
|
||||
param->pull_vcard_listing_rsp.database_identifier = ptr;
|
||||
ptr += BTA_PBAP_APP_PARAM_LENGTH_DATABASE_IDENTIFIER;
|
||||
break;
|
||||
default:
|
||||
goto error;
|
||||
break;
|
||||
}
|
||||
}
|
||||
error:
|
||||
return;
|
||||
}
|
||||
|
||||
static void parse_pull_vcard_entry_app_param(esp_pbac_param_t *param, uint8_t *app_param, uint16_t app_param_len)
|
||||
{
|
||||
if (app_param == NULL || app_param_len == 0) {
|
||||
return;
|
||||
}
|
||||
uint8_t *ptr = app_param;
|
||||
while(ptr < app_param + app_param_len) {
|
||||
switch (*ptr)
|
||||
{
|
||||
case BTA_PBAP_APP_PARAM_DATABASE_IDENTIFIER:
|
||||
param->pull_vcard_entry_rsp.include_database_identifier = 1;
|
||||
ptr += BTA_PBAP_APP_PARAM_HEADER_LENGTH;
|
||||
/* don't copy */
|
||||
param->pull_vcard_entry_rsp.database_identifier = ptr;
|
||||
ptr += BTA_PBAP_APP_PARAM_LENGTH_DATABASE_IDENTIFIER;
|
||||
break;
|
||||
default:
|
||||
goto error;
|
||||
break;
|
||||
}
|
||||
}
|
||||
error:
|
||||
return;
|
||||
}
|
||||
|
||||
static uint16_t get_next_dir_len_from_path(char *path, uint16_t path_len, uint16_t path_pos)
|
||||
{
|
||||
uint16_t ret = 0;
|
||||
for (int i = path_pos; i < path_len; ++i) {
|
||||
if (path[i] == '/' || path[i] == '\0') {
|
||||
break;
|
||||
}
|
||||
else {
|
||||
++ret;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void btc_pba_client_cb_handler(btc_msg_t *msg)
|
||||
{
|
||||
uint16_t event = msg->act;
|
||||
tBTA_PBA_CLIENT *p_data = (tBTA_PBA_CLIENT *)msg->arg;
|
||||
btc_pba_client_ccb_t *p_ccb = NULL;
|
||||
esp_pbac_param_t param = {0};
|
||||
|
||||
switch (event) {
|
||||
case BTA_PBA_CLIENT_CONN_OPEN_EVT:
|
||||
if (p_data->conn.error == BTA_PBA_CLIENT_NO_ERROR) {
|
||||
/* allocate ccb */
|
||||
p_ccb = &btc_pba_client_cb.ccb[p_data->conn.handle - 1];
|
||||
p_ccb->handle = p_data->conn.handle;
|
||||
bdcpy(p_ccb->bd_addr.address, p_data->conn.bd_addr);
|
||||
p_ccb->busy = false;
|
||||
param.conn_stat.connected = true;
|
||||
param.conn_stat.peer_supported_repo = p_data->conn.peer_supported_repo;
|
||||
param.conn_stat.peer_supported_feat = p_data->conn.peer_supported_feat;
|
||||
param.conn_stat.reason = BTA_PBA_CLIENT_NO_ERROR;
|
||||
}
|
||||
else {
|
||||
param.conn_stat.connected = false;
|
||||
/* error codes are compatible */
|
||||
param.conn_stat.reason = p_data->conn.error;
|
||||
}
|
||||
bdcpy(param.conn_stat.remote_bda, p_data->conn.bd_addr);
|
||||
param.conn_stat.handle = p_data->conn.handle;
|
||||
btc_pba_client_callback_to_app(ESP_PBAC_CONNECTION_STATE_EVT, ¶m);
|
||||
btc_queue_advance();
|
||||
break;
|
||||
case BTA_PBA_CLIENT_CONN_CLOSE_EVT:
|
||||
/* clear ccb */
|
||||
p_ccb = &btc_pba_client_cb.ccb[p_data->conn.handle - 1];
|
||||
p_ccb->handle = 0;
|
||||
p_ccb->busy = false;
|
||||
p_ccb->path_len = 0;
|
||||
p_ccb->path_pos = 0;
|
||||
if (p_ccb->path) {
|
||||
osi_free(p_ccb->path);
|
||||
p_ccb->path = NULL;
|
||||
}
|
||||
memset(p_ccb->bd_addr.address, 0, BD_ADDR_LEN);
|
||||
param.conn_stat.connected = false;
|
||||
bdcpy(param.conn_stat.remote_bda, p_data->conn.bd_addr);
|
||||
param.conn_stat.handle = p_data->conn.handle;
|
||||
/* error codes are compatible */
|
||||
param.conn_stat.reason = p_data->conn.error;
|
||||
btc_pba_client_callback_to_app(ESP_PBAC_CONNECTION_STATE_EVT, ¶m);
|
||||
btc_queue_advance();
|
||||
break;
|
||||
case BTA_PBA_CLIENT_PULL_PHONE_BOOK_RSP_EVT:
|
||||
if (p_data->response.final) {
|
||||
p_ccb = &btc_pba_client_cb.ccb[p_data->response.handle - 1];
|
||||
p_ccb->busy = false;
|
||||
}
|
||||
param.pull_phone_book_rsp.handle = p_data->response.handle;
|
||||
param.pull_phone_book_rsp.final = p_data->response.final;
|
||||
param.pull_phone_book_rsp.result = p_data->response.status;
|
||||
param.pull_phone_book_rsp.data = p_data->response.data;
|
||||
param.pull_phone_book_rsp.data_len = p_data->response.data_len;
|
||||
parse_pull_phone_book_app_param(¶m, p_data->response.app_param, p_data->response.app_param_len);
|
||||
btc_pba_client_callback_to_app(ESP_PBAC_PULL_PHONE_BOOK_RESPONSE_EVT, ¶m);
|
||||
if (p_data->response.pkt != NULL) {
|
||||
osi_free(p_data->response.pkt);
|
||||
}
|
||||
break;
|
||||
case BTA_PBA_CLIENT_SET_PHONE_BOOK_RSP_EVT:
|
||||
p_ccb = &btc_pba_client_cb.ccb[p_data->response.handle - 1];
|
||||
if (p_data->response.status == BTA_PBA_CLIENT_NO_ERROR && p_ccb->path_pos < p_ccb->path_len) {
|
||||
/* since path_len is not zero, path should not be NULL, use asset to check */
|
||||
assert(p_ccb->path != NULL);
|
||||
uint16_t dir_name_len = get_next_dir_len_from_path(p_ccb->path, p_ccb->path_len, p_ccb->path_pos);
|
||||
if (dir_name_len > 0) {
|
||||
char *dir_name = osi_malloc(dir_name_len + 1);
|
||||
assert(dir_name != NULL);
|
||||
memcpy(dir_name, p_ccb->path + p_ccb->path_pos, dir_name_len);
|
||||
dir_name[dir_name_len] = '\0';
|
||||
p_ccb->path_pos += dir_name_len + 1;
|
||||
BTA_PbaClientSetPhoneBook(p_data->response.handle, ESP_PBAC_SET_PHONE_BOOK_FLAGS_DOWN, dir_name);
|
||||
/* break here, don't report event to upper */
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* set path done or failed, clear status */
|
||||
p_ccb->path_len = 0;
|
||||
p_ccb->path_pos = 0;
|
||||
if (p_ccb->path) {
|
||||
osi_free(p_ccb->path);
|
||||
p_ccb->path = NULL;
|
||||
}
|
||||
p_ccb->busy = false;
|
||||
param.set_phone_book_rsp.handle = p_data->response.handle;
|
||||
param.set_phone_book_rsp.result = p_data->response.status;
|
||||
btc_pba_client_callback_to_app(ESP_PBAC_SET_PHONE_BOOK_RESPONSE_EVT, ¶m);
|
||||
if (p_data->response.pkt != NULL) {
|
||||
osi_free(p_data->response.pkt);
|
||||
}
|
||||
break;
|
||||
case BTA_PBA_CLIENT_PULL_VCARD_LISTING_RSP_EVT:
|
||||
if (p_data->response.final) {
|
||||
p_ccb = &btc_pba_client_cb.ccb[p_data->response.handle - 1];
|
||||
p_ccb->busy = false;
|
||||
}
|
||||
param.pull_vcard_listing_rsp.handle = p_data->response.handle;
|
||||
param.pull_vcard_listing_rsp.final = p_data->response.final;
|
||||
param.pull_vcard_listing_rsp.result = p_data->response.status;
|
||||
param.pull_vcard_listing_rsp.data = p_data->response.data;
|
||||
param.pull_vcard_listing_rsp.data_len = p_data->response.data_len;
|
||||
parse_pull_vcard_listing_app_param(¶m, p_data->response.app_param, p_data->response.app_param_len);
|
||||
btc_pba_client_callback_to_app(ESP_PBAC_PULL_VCARD_LISTING_RESPONSE_EVT, ¶m);
|
||||
if (p_data->response.pkt != NULL) {
|
||||
osi_free(p_data->response.pkt);
|
||||
}
|
||||
break;
|
||||
case BTA_PBA_CLIENT_PULL_VCARD_ENTRY_RSP_EVT:
|
||||
if (p_data->response.final) {
|
||||
p_ccb = &btc_pba_client_cb.ccb[p_data->response.handle - 1];
|
||||
p_ccb->busy = false;
|
||||
}
|
||||
param.pull_vcard_entry_rsp.handle = p_data->response.handle;
|
||||
param.pull_vcard_entry_rsp.final = p_data->response.final;
|
||||
param.pull_vcard_entry_rsp.result = p_data->response.status;
|
||||
param.pull_vcard_entry_rsp.data = p_data->response.data;
|
||||
param.pull_vcard_entry_rsp.data_len = p_data->response.data_len;
|
||||
parse_pull_vcard_entry_app_param(¶m, p_data->response.app_param, p_data->response.app_param_len);
|
||||
btc_pba_client_callback_to_app(ESP_PBAC_PULL_VCARD_ENTRY_RESPONSE_EVT, ¶m);
|
||||
if (p_data->response.pkt != NULL) {
|
||||
osi_free(p_data->response.pkt);
|
||||
}
|
||||
break;
|
||||
case BTA_PBA_CLIENT_REGISTER_EVT:
|
||||
/* init process: Enable -> Register */
|
||||
btc_pba_client_callback_to_app(ESP_PBAC_INIT_EVT, NULL);
|
||||
break;
|
||||
case BTA_PBA_CLIENT_DISABLE_EVT:
|
||||
/* deinit process: Deregister -> Disable */
|
||||
btc_pba_client_callback_to_app(ESP_PBAC_DEINIT_EVT, NULL);
|
||||
break;
|
||||
default:
|
||||
BTC_TRACE_WARNING("%s: unknown event (%d)", __func__, event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
@@ -124,6 +124,25 @@
|
||||
#define UC_BT_ENC_KEY_SIZE_CTRL_MODE 0
|
||||
#endif
|
||||
|
||||
//PBAP Client
|
||||
#ifdef CONFIG_BT_PBAC_ENABLED
|
||||
#define UC_BT_PBAC_ENABLED CONFIG_BT_PBAC_ENABLED
|
||||
#else
|
||||
#define UC_BT_PBAC_ENABLED FALSE
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BT_PBAC_SUPPORTED_FEAT
|
||||
#define UC_BT_PBAC_SUPPORTED_FEAT CONFIG_BT_PBAC_SUPPORTED_FEAT
|
||||
#else
|
||||
#define UC_BT_PBAC_SUPPORTED_FEAT 0x00
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BT_PBAC_PREFERRED_MTU
|
||||
#define UC_BT_PBAC_PREFERRED_MTU CONFIG_BT_PBAC_PREFERRED_MTU
|
||||
#else
|
||||
#define UC_BT_PBAC_PREFERRED_MTU 0
|
||||
#endif
|
||||
|
||||
//GOEPC (BT)
|
||||
#ifdef CONFIG_BT_GOEPC_ENABLED
|
||||
#define UC_BT_GOEPC_ENABLED CONFIG_BT_GOEPC_ENABLED
|
||||
|
@@ -177,12 +177,22 @@
|
||||
#endif /* UC_BT_HID_DEVICE_ENABLED */
|
||||
|
||||
#if UC_BT_GOEPC_ENABLED
|
||||
#ifndef RFCOMM_INCLUDED
|
||||
#define RFCOMM_INCLUDED TRUE
|
||||
#endif
|
||||
#ifndef OBEX_INCLUDED
|
||||
#define OBEX_INCLUDED TRUE
|
||||
#endif
|
||||
#define GOEPC_INCLUDED TRUE
|
||||
#endif /* UC_BT_GOEPC_ENABLED */
|
||||
|
||||
#if UC_BT_PBAC_ENABLED
|
||||
#define BTC_PBA_CLIENT_INCLUDED TRUE
|
||||
#define BTC_PBA_SUPPORTED_FEAT UC_BT_PBAC_SUPPORTED_FEAT
|
||||
#define BTC_PBA_PREFERRED_MTU UC_BT_PBAC_PREFERRED_MTU
|
||||
#define BTA_PBA_CLIENT_INCLUDED TRUE
|
||||
#endif
|
||||
|
||||
#endif /* UC_BT_CLASSIC_ENABLED */
|
||||
|
||||
/* This is set to enable use of GAP L2CAP connections. */
|
||||
|
@@ -330,6 +330,13 @@ static inline void trc_dump_buffer(const char *prefix, uint8_t *data, uint16_t l
|
||||
#define OBEX_TL_L2CAP_TRACE_EVENT(fmt, args...) {if (obex_tl_l2cap_cb.trace_level >= BT_TRACE_LEVEL_EVENT && BT_LOG_LEVEL_CHECK(AVRC,EVENT)) BT_PRINT_D("OBEX_TL_L2CAP", fmt, ## args);}
|
||||
#define OBEX_TL_L2CAP_TRACE_DEBUG(fmt, args...) {if (obex_tl_l2cap_cb.trace_level >= BT_TRACE_LEVEL_DEBUG && BT_LOG_LEVEL_CHECK(AVRC,DEBUG)) BT_PRINT_D("OBEX_TL_L2CAP", fmt, ## args);}
|
||||
|
||||
/* Define tracing for OBEX_TL_RFCOMM */
|
||||
#define OBEX_TL_RFCOMM_TRACE_ERROR(fmt, args...) {if (obex_tl_rfcomm_cb.trace_level >= BT_TRACE_LEVEL_ERROR && BT_LOG_LEVEL_CHECK(AVRC, ERROR)) BT_PRINT_E("OBEX_TL_RFCOMM", fmt, ## args);}
|
||||
#define OBEX_TL_RFCOMM_TRACE_WARNING(fmt, args...) {if (obex_tl_rfcomm_cb.trace_level >= BT_TRACE_LEVEL_WARNING && BT_LOG_LEVEL_CHECK(AVRC, WARNING)) BT_PRINT_W("OBEX_TL_RFCOMM", fmt, ## args);}
|
||||
#define OBEX_TL_RFCOMM_TRACE_API(fmt, args...) {if (obex_tl_rfcomm_cb.trace_level >= BT_TRACE_LEVEL_API && BT_LOG_LEVEL_CHECK(AVRC,API)) BT_PRINT_I("OBEX_TL_RFCOMM", fmt, ## args);}
|
||||
#define OBEX_TL_RFCOMM_TRACE_EVENT(fmt, args...) {if (obex_tl_rfcomm_cb.trace_level >= BT_TRACE_LEVEL_EVENT && BT_LOG_LEVEL_CHECK(AVRC,EVENT)) BT_PRINT_D("OBEX_TL_RFCOMM", fmt, ## args);}
|
||||
#define OBEX_TL_RFCOMM_TRACE_DEBUG(fmt, args...) {if (obex_tl_rfcomm_cb.trace_level >= BT_TRACE_LEVEL_DEBUG && BT_LOG_LEVEL_CHECK(AVRC,DEBUG)) BT_PRINT_D("OBEX_TL_RFCOMM", fmt, ## args);}
|
||||
|
||||
/* Define tracing for GOEPC */
|
||||
#define GOEPC_TRACE_ERROR(fmt, args...) {if (goepc_cb.trace_level >= BT_TRACE_LEVEL_ERROR && BT_LOG_LEVEL_CHECK(AVRC, ERROR)) BT_PRINT_E("BT_GOEPC", fmt, ## args);}
|
||||
#define GOEPC_TRACE_WARNING(fmt, args...) {if (goepc_cb.trace_level >= BT_TRACE_LEVEL_WARNING && BT_LOG_LEVEL_CHECK(AVRC, WARNING)) BT_PRINT_W("BT_GOEPC", fmt, ## args);}
|
||||
@@ -512,12 +519,20 @@ extern UINT8 btif_trace_level;
|
||||
#define OBEX_TRACE_EVENT(fmt, args...)
|
||||
#define OBEX_TRACE_DEBUG(fmt, args...)
|
||||
|
||||
/* Define tracing for OBEX L2CAP transport layer */
|
||||
#define OBEX_TL_L2CAP_TRACE_ERROR(fmt, args...)
|
||||
#define OBEX_TL_L2CAP_TRACE_WARNING(fmt, args...)
|
||||
#define OBEX_TL_L2CAP_TRACE_API(fmt, args...)
|
||||
#define OBEX_TL_L2CAP_TRACE_EVENT(fmt, args...)
|
||||
#define OBEX_TL_L2CAP_TRACE_DEBUG(fmt, args...)
|
||||
|
||||
/* Define tracing for OBEX RFCOMM transport layer */
|
||||
#define OBEX_TL_RFCOMM_TRACE_ERROR(fmt, args...)
|
||||
#define OBEX_TL_RFCOMM_TRACE_WARNING(fmt, args...)
|
||||
#define OBEX_TL_RFCOMM_TRACE_API(fmt, args...)
|
||||
#define OBEX_TL_RFCOMM_TRACE_EVENT(fmt, args...)
|
||||
#define OBEX_TL_RFCOMM_TRACE_DEBUG(fmt, args...)
|
||||
|
||||
/* Define tracing for GOEPC */
|
||||
#define GOEPC_TRACE_ERROR(fmt, args...)
|
||||
#define GOEPC_TRACE_WARNING(fmt, args...)
|
||||
|
@@ -156,6 +156,10 @@
|
||||
#include "bta_pan_int.h"
|
||||
#endif
|
||||
|
||||
#if BTA_PBA_CLIENT_INCLUDED == TRUE
|
||||
#include "bta_pba_client_int.h"
|
||||
#endif
|
||||
|
||||
#include "bta_sys_int.h"
|
||||
|
||||
// control block for patch ram downloading
|
||||
@@ -184,6 +188,12 @@ void BTE_DeinitStack(void)
|
||||
{
|
||||
//BTA Modules
|
||||
#if (BTA_INCLUDED == TRUE && BTA_DYNAMIC_MEMORY == TRUE)
|
||||
#if BTA_PBA_CLIENT_INCLUDED == TRUE
|
||||
if (bta_pba_client_cb_ptr) {
|
||||
osi_free(bta_pba_client_cb_ptr);
|
||||
bta_pba_client_cb_ptr = NULL;
|
||||
}
|
||||
#endif
|
||||
#if GATTS_INCLUDED == TRUE
|
||||
if (bta_gatts_cb_ptr){
|
||||
osi_free(bta_gatts_cb_ptr);
|
||||
@@ -521,6 +531,12 @@ bt_status_t BTE_InitStack(void)
|
||||
#if BTA_PAN_INCLUDED==TRUE
|
||||
memset((void *)bta_pan_cb_ptr, 0, sizeof(tBTA_PAN_CB));
|
||||
#endif
|
||||
#if BTA_PBA_CLIENT_INCLUDED == TRUE
|
||||
if ((bta_pba_client_cb_ptr = (tBTA_PBA_CLIENT_CB *)osi_malloc(sizeof(tBTA_PBA_CLIENT_CB))) == NULL) {
|
||||
goto error_exit;
|
||||
}
|
||||
memset((void *)bta_pba_client_cb_ptr, 0, sizeof(tBTA_PBA_CLIENT_CB));
|
||||
#endif
|
||||
|
||||
#endif // BTA_INCLUDED == TRUE
|
||||
return BT_STATUS_SUCCESS;
|
||||
|
@@ -359,7 +359,7 @@ UINT16 GOEPC_RequestAddHeader(UINT16 handle, UINT8 header_id, const UINT8 *data,
|
||||
break;
|
||||
}
|
||||
|
||||
if (data == NULL || data_len == 0) {
|
||||
if ((data == NULL) ^ (data_len == 0)) {
|
||||
ret = GOEP_INVALID_PARAM;
|
||||
break;
|
||||
}
|
||||
|
@@ -8,11 +8,12 @@
|
||||
|
||||
#include "common/bt_target.h"
|
||||
|
||||
#define GOEP_SUCCESS 0 /* Operation successful */
|
||||
#define GOEP_FAILURE 1 /* Operation failed */
|
||||
#define GOEP_NO_RESOURCES 3 /* Not enough resources */
|
||||
#define GOEP_BAD_HANDLE 4 /* Bad handle */
|
||||
#define GOEP_INVALID_PARAM 5 /* Invalid parameter */
|
||||
#define GOEP_INVALID_STATE 6 /* Operation not allow in current state */
|
||||
#define GOEP_CONGEST 7 /* Congest */
|
||||
#define GOEP_TL_ERROR 8 /* Lower transport layer error */
|
||||
/* GOEP Client or Server(not supported yet) API return code */
|
||||
#define GOEP_SUCCESS 0x00 /* Operation successful */
|
||||
#define GOEP_FAILURE 0x01 /* Operation failed */
|
||||
#define GOEP_NO_RESOURCES 0x02 /* Not enough resources */
|
||||
#define GOEP_BAD_HANDLE 0x04 /* Bad handle */
|
||||
#define GOEP_INVALID_PARAM 0x08 /* Invalid parameter */
|
||||
#define GOEP_INVALID_STATE 0x10 /* Operation not allow in current state */
|
||||
#define GOEP_CONGEST 0x20 /* Congest */
|
||||
#define GOEP_TL_ERROR 0x40 /* Lower transport layer error */
|
||||
|
@@ -19,8 +19,6 @@
|
||||
#define OBEX_NOT_OPEN 6 /* Connection not open */
|
||||
#define OBEX_PACKET_TOO_LARGE 7 /* Packet size large than MTU */
|
||||
#define OBEX_ERROR_TL 8 /* Operation failed in transport layer */
|
||||
#define OBEX_TRY_AGAIN 9 /* Operation failed, connection congestion, try again */
|
||||
|
||||
|
||||
/*
|
||||
* OBEX profile definitions
|
||||
@@ -162,12 +160,21 @@ typedef struct
|
||||
BD_ADDR addr; /* peer bluetooth device address */
|
||||
} tOBEX_OVER_L2CAP_SVR;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
UINT8 scn; /* service channel number */
|
||||
UINT16 sec_mask; /* security mask */
|
||||
UINT16 pref_mtu; /* preferred mtu, limited by rfcomm mtu */
|
||||
BD_ADDR addr; /* peer bluetooth device address */
|
||||
} tOBEX_OVER_RFCOMM_SVR;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
UINT8 tl; /* transport type, OBEX_OVER_L2CAP or OBEX_OVER_RFCOMM */
|
||||
union
|
||||
{
|
||||
tOBEX_OVER_L2CAP_SVR l2cap;
|
||||
tOBEX_OVER_RFCOMM_SVR rfcomm;
|
||||
};
|
||||
} tOBEX_SVR_INFO;
|
||||
|
||||
|
@@ -14,7 +14,13 @@
|
||||
|
||||
#if (OBEX_INCLUDED == TRUE)
|
||||
|
||||
#define OBEX_BT_HDR_MIN_OFFSET OBEX_TL_L2CAP_BT_HDR_MIN_OFFSET /* should set to max value of all transport layer */
|
||||
#if (RFCOMM_INCLUDED == TRUE)
|
||||
#define OBEX_BT_HDR_MIN_OFFSET OBEX_TL_RFCOMM_BT_HDR_MIN_OFFSET /* should set to max value of all transport layer */
|
||||
#define OBEX_BT_HDR_RESERVE_LEN OBEX_TL_RFCOMM_BT_HDR_RESERVE_LEN /* should set to max value of all transport layer */
|
||||
#else
|
||||
#define OBEX_BT_HDR_MIN_OFFSET OBEX_TL_L2CAP_BT_HDR_OFFSET_MIN
|
||||
#define OBEX_BT_HDR_RESERVE_LEN OBEX_TL_L2CAP_BT_HDR_RESERVE_LEN
|
||||
#endif
|
||||
|
||||
#define OBEX_ROLE_CLIENT 0x01
|
||||
#define OBEX_ROLE_SERVER 0x02
|
||||
@@ -24,10 +30,6 @@
|
||||
#define OBEX_STATE_OPENING 1 /* Starting to open a connection */
|
||||
#define OBEX_STATE_OPENED 2 /* Connection opened */
|
||||
|
||||
/* Store 16 bits data in big endian format, not modify the p_buf */
|
||||
#define STORE16BE(p_buf, data) do { *p_buf = ((data)>>8)&0xff; \
|
||||
*(p_buf+1) = (data)&0xff;} while(0)
|
||||
|
||||
/* OBEX Connection Control block */
|
||||
typedef struct {
|
||||
tOBEX_MSG_CBACK *callback; /* Connection msg callback function */
|
||||
@@ -65,6 +67,7 @@ extern tOBEX_CB *obex_cb_ptr;
|
||||
#endif
|
||||
|
||||
void obex_tl_l2cap_callback(tOBEX_TL_EVT evt, tOBEX_TL_MSG *msg);
|
||||
void obex_tl_rfcomm_callback(tOBEX_TL_EVT evt, tOBEX_TL_MSG *msg);
|
||||
tOBEX_CCB *obex_allocate_ccb(void);
|
||||
tOBEX_SCB *obex_allocate_scb(void);
|
||||
void obex_free_ccb(tOBEX_CCB *p_ccb);
|
||||
|
@@ -68,9 +68,18 @@ typedef struct
|
||||
BD_ADDR addr; /* peer bluetooth device address */
|
||||
} tOBEX_TL_L2CAP_SVR;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
UINT8 scn; /* service channel number */
|
||||
UINT16 sec_mask; /* security mask */
|
||||
UINT16 pref_mtu; /* preferred mtu, limited by rfcomm mtu */
|
||||
BD_ADDR addr; /* peer bluetooth device address */
|
||||
} tOBEX_TL_RFCOMM_SVR;
|
||||
|
||||
typedef union
|
||||
{
|
||||
tOBEX_TL_L2CAP_SVR l2cap;
|
||||
tOBEX_TL_RFCOMM_SVR rfcomm;
|
||||
} tOBEX_TL_SVR_INFO;
|
||||
|
||||
typedef void (tOBEX_TL_CBACK)(tOBEX_TL_EVT evt, tOBEX_TL_MSG *msg);
|
||||
|
@@ -10,7 +10,8 @@
|
||||
|
||||
#if (OBEX_INCLUDED == TRUE)
|
||||
|
||||
#define OBEX_TL_L2CAP_BT_HDR_MIN_OFFSET 13 /* L2CAP_MIN_OFFSET */
|
||||
#define OBEX_TL_L2CAP_BT_HDR_MIN_OFFSET 13 /* equal to L2CAP_MIN_OFFSET */
|
||||
#define OBEX_TL_L2CAP_BT_HDR_RESERVE_LEN 0 /* not require any additional byte */
|
||||
|
||||
tOBEX_TL_OPS *obex_tl_l2cap_ops_get(void);
|
||||
|
||||
|
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "obex_tl.h"
|
||||
|
||||
#if (OBEX_INCLUDED == TRUE && RFCOMM_INCLUDED == TRUE)
|
||||
|
||||
#define OBEX_TL_RFCOMM_BT_HDR_MIN_OFFSET 18 /* RFCOMM_MIN_OFFSET + L2CAP_MIN_OFFSET */
|
||||
#define OBEX_TL_RFCOMM_BT_HDR_RESERVE_LEN 1 /* reserve 1 byte for rfcomm fcs */
|
||||
|
||||
tOBEX_TL_OPS *obex_tl_rfcomm_ops_get(void);
|
||||
|
||||
#endif /* #if (OBEX_INCLUDED == TRUE && RFCOMM_INCLUDED == TRUE) */
|
@@ -14,6 +14,7 @@
|
||||
#include "obex_int.h"
|
||||
#include "obex_tl.h"
|
||||
#include "obex_tl_l2cap.h"
|
||||
#include "obex_tl_rfcomm.h"
|
||||
|
||||
#if (OBEX_INCLUDED == TRUE)
|
||||
|
||||
@@ -25,6 +26,12 @@ static inline void obex_server_to_tl_server(tOBEX_SVR_INFO *server, tOBEX_TL_SVR
|
||||
tl_server->l2cap.pref_mtu = server->l2cap.pref_mtu;
|
||||
bdcpy(tl_server->l2cap.addr, server->l2cap.addr);
|
||||
}
|
||||
else if (server->tl == OBEX_OVER_RFCOMM) {
|
||||
tl_server->rfcomm.scn = server->rfcomm.scn;
|
||||
tl_server->rfcomm.sec_mask = server->rfcomm.sec_mask;
|
||||
tl_server->rfcomm.pref_mtu = server->rfcomm.pref_mtu;
|
||||
bdcpy(tl_server->rfcomm.addr, server->rfcomm.addr);
|
||||
}
|
||||
else {
|
||||
OBEX_TRACE_ERROR("Unsupported OBEX transport type\n");
|
||||
assert(0);
|
||||
@@ -34,7 +41,7 @@ static inline void obex_server_to_tl_server(tOBEX_SVR_INFO *server, tOBEX_TL_SVR
|
||||
static inline void obex_updata_packet_length(BT_HDR *p_buf, UINT16 len)
|
||||
{
|
||||
UINT8 *p_pkt_len = (UINT8 *)(p_buf + 1) + p_buf->offset + 1;
|
||||
STORE16BE(p_pkt_len, len);
|
||||
UINT16_TO_BE_FIELD(p_pkt_len, len);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
@@ -62,13 +69,12 @@ UINT16 OBEX_Init(void)
|
||||
if (obex_cb.tl_ops[OBEX_OVER_L2CAP]->init != NULL) {
|
||||
obex_cb.tl_ops[OBEX_OVER_L2CAP]->init(obex_tl_l2cap_callback);
|
||||
}
|
||||
/* Not implement yet */
|
||||
/*
|
||||
#if (RFCOMM_INCLUDED == TRUE)
|
||||
obex_cb.tl_ops[OBEX_OVER_RFCOMM] = obex_tl_rfcomm_ops_get();
|
||||
if (obex_cb.tl_ops[OBEX_OVER_RFCOMM]->init != NULL) {
|
||||
obex_cb.tl_ops[OBEX_OVER_RFCOMM]->init(obex_tl_rfcomm_callback);
|
||||
}
|
||||
*/
|
||||
#endif
|
||||
obex_cb.trace_level = BT_TRACE_LEVEL_ERROR;
|
||||
return OBEX_SUCCESS;
|
||||
}
|
||||
@@ -317,7 +323,7 @@ UINT16 OBEX_BuildRequest(tOBEX_PARSE_INFO *info, UINT16 buff_size, BT_HDR **out_
|
||||
if (buff_size < OBEX_MIN_PACKET_SIZE || info == NULL || out_pkt == NULL) {
|
||||
return OBEX_INVALID_PARAM;
|
||||
}
|
||||
buff_size += sizeof(BT_HDR) + OBEX_BT_HDR_MIN_OFFSET;
|
||||
buff_size += sizeof(BT_HDR) + OBEX_BT_HDR_MIN_OFFSET + OBEX_BT_HDR_RESERVE_LEN;
|
||||
|
||||
BT_HDR *p_buf= (BT_HDR *)osi_malloc(buff_size);
|
||||
if (p_buf == NULL) {
|
||||
@@ -327,7 +333,7 @@ UINT16 OBEX_BuildRequest(tOBEX_PARSE_INFO *info, UINT16 buff_size, BT_HDR **out_
|
||||
UINT16 pkt_len = OBEX_MIN_PACKET_SIZE;
|
||||
p_buf->offset = OBEX_BT_HDR_MIN_OFFSET;
|
||||
/* use layer_specific to store the max data length allowed */
|
||||
p_buf->layer_specific = buff_size - sizeof(BT_HDR) - OBEX_BT_HDR_MIN_OFFSET;
|
||||
p_buf->layer_specific = buff_size - sizeof(BT_HDR) - OBEX_BT_HDR_MIN_OFFSET - OBEX_BT_HDR_RESERVE_LEN;
|
||||
UINT8 *p_data = (UINT8 *)(p_buf + 1) + p_buf->offset;
|
||||
/* byte 0: opcode */
|
||||
*p_data++ = info->opcode;
|
||||
@@ -343,7 +349,7 @@ UINT16 OBEX_BuildRequest(tOBEX_PARSE_INFO *info, UINT16 buff_size, BT_HDR **out_
|
||||
/* byte 4: flags */
|
||||
*p_data++ = info->flags;
|
||||
/* byte 5, 6: maximum OBEX packet length, recommend to set as our mtu*/
|
||||
STORE16BE(p_data, info->max_packet_length);
|
||||
UINT16_TO_BE_FIELD(p_data, info->max_packet_length);
|
||||
pkt_len += 4;
|
||||
break;
|
||||
case OBEX_OPCODE_SETPATH:
|
||||
@@ -357,7 +363,7 @@ UINT16 OBEX_BuildRequest(tOBEX_PARSE_INFO *info, UINT16 buff_size, BT_HDR **out_
|
||||
break;
|
||||
}
|
||||
|
||||
STORE16BE(p_pkt_len, pkt_len);
|
||||
UINT16_TO_BE_FIELD(p_pkt_len, pkt_len);
|
||||
p_buf->len = pkt_len;
|
||||
*out_pkt = p_buf;
|
||||
return OBEX_SUCCESS;
|
||||
@@ -378,7 +384,7 @@ UINT16 OBEX_BuildResponse(tOBEX_PARSE_INFO *info, UINT16 buff_size, BT_HDR **out
|
||||
if (buff_size < OBEX_MIN_PACKET_SIZE || info == NULL || out_pkt == NULL) {
|
||||
return OBEX_INVALID_PARAM;
|
||||
}
|
||||
buff_size += sizeof(BT_HDR) + OBEX_BT_HDR_MIN_OFFSET;
|
||||
buff_size += sizeof(BT_HDR) + OBEX_BT_HDR_MIN_OFFSET + OBEX_BT_HDR_RESERVE_LEN;
|
||||
|
||||
BT_HDR *p_buf= (BT_HDR *)osi_malloc(buff_size);
|
||||
if (p_buf == NULL) {
|
||||
@@ -388,7 +394,7 @@ UINT16 OBEX_BuildResponse(tOBEX_PARSE_INFO *info, UINT16 buff_size, BT_HDR **out
|
||||
UINT16 pkt_len = OBEX_MIN_PACKET_SIZE;
|
||||
p_buf->offset = OBEX_BT_HDR_MIN_OFFSET;
|
||||
/* use layer_specific to store the max data length allowed */
|
||||
p_buf->layer_specific = buff_size - sizeof(BT_HDR) - OBEX_BT_HDR_MIN_OFFSET;
|
||||
p_buf->layer_specific = buff_size - sizeof(BT_HDR) - OBEX_BT_HDR_MIN_OFFSET - OBEX_BT_HDR_RESERVE_LEN;
|
||||
UINT8 *p_data = (UINT8 *)(p_buf + 1) + p_buf->offset;
|
||||
/* byte 0: response code */
|
||||
*p_data++ = info->response_code;
|
||||
@@ -405,14 +411,14 @@ UINT16 OBEX_BuildResponse(tOBEX_PARSE_INFO *info, UINT16 buff_size, BT_HDR **out
|
||||
/* byte 4: flags */
|
||||
*p_data++ = info->flags;
|
||||
/* byte 5, 6: maximum OBEX packet length, recommend to set as our mtu */
|
||||
STORE16BE(p_data, info->max_packet_length);
|
||||
UINT16_TO_BE_FIELD(p_data, info->max_packet_length);
|
||||
pkt_len += 4;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
STORE16BE(p_pkt_len, pkt_len);
|
||||
UINT16_TO_BE_FIELD(p_pkt_len, pkt_len);
|
||||
p_buf->len = pkt_len;
|
||||
*out_pkt = p_buf;
|
||||
return OBEX_SUCCESS;
|
||||
@@ -465,7 +471,7 @@ UINT16 OBEX_AppendHeader(BT_HDR *pkt, const UINT8 *header)
|
||||
pkt->len += header_len;
|
||||
/* point to packet len */
|
||||
p_data++;
|
||||
STORE16BE(p_data, pkt->len);
|
||||
UINT16_TO_BE_FIELD(p_data, pkt->len);
|
||||
return OBEX_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -481,7 +487,11 @@ UINT16 OBEX_AppendHeader(BT_HDR *pkt, const UINT8 *header)
|
||||
*******************************************************************************/
|
||||
UINT16 OBEX_AppendHeaderRaw(BT_HDR *pkt, UINT8 header_id, const UINT8 *data, UINT16 data_len)
|
||||
{
|
||||
if (pkt == NULL || data == NULL) {
|
||||
if (pkt == NULL) {
|
||||
return OBEX_INVALID_PARAM;
|
||||
}
|
||||
|
||||
if ((data == NULL) ^ (data_len == 0)) {
|
||||
return OBEX_INVALID_PARAM;
|
||||
}
|
||||
|
||||
@@ -524,15 +534,17 @@ UINT16 OBEX_AppendHeaderRaw(BT_HDR *pkt, UINT8 header_id, const UINT8 *data, UIN
|
||||
*p_start++ = header_id;
|
||||
if (store_header_len) {
|
||||
/* store header length */
|
||||
STORE16BE(p_start, header_len);
|
||||
UINT16_TO_BE_FIELD(p_start, header_len);
|
||||
p_start+= 2;
|
||||
}
|
||||
/* store data */
|
||||
memcpy(p_start, data, data_len);
|
||||
if (data != NULL) {
|
||||
/* store data */
|
||||
memcpy(p_start, data, data_len);
|
||||
}
|
||||
pkt->len += header_len;
|
||||
/* point to packet len */
|
||||
p_data++;
|
||||
STORE16BE(p_data, pkt->len);
|
||||
UINT16_TO_BE_FIELD(p_data, pkt->len);
|
||||
return OBEX_SUCCESS;
|
||||
}
|
||||
|
||||
|
@@ -208,4 +208,9 @@ void obex_tl_l2cap_callback(tOBEX_TL_EVT evt, tOBEX_TL_MSG *msg)
|
||||
obex_tl_evt_handler(OBEX_OVER_L2CAP, evt, msg);
|
||||
}
|
||||
|
||||
void obex_tl_rfcomm_callback(tOBEX_TL_EVT evt, tOBEX_TL_MSG *msg)
|
||||
{
|
||||
obex_tl_evt_handler(OBEX_OVER_RFCOMM, evt, msg);
|
||||
}
|
||||
|
||||
#endif /* #if (OBEX_INCLUDED == TRUE) */
|
||||
|
@@ -484,6 +484,10 @@ void obex_tl_l2cap_disconnect_ind(UINT16 lcid, BOOLEAN is_conf_needed)
|
||||
return;
|
||||
}
|
||||
|
||||
if (p_ccb->initiator && find_scb_by_psm(p_ccb->vpsm) == NULL) {
|
||||
L2CA_Deregister(p_ccb->vpsm);
|
||||
}
|
||||
|
||||
tOBEX_TL_MSG msg = {0};
|
||||
msg.any.hdl = p_ccb->allocated;
|
||||
obex_tl_l2cap_cb.callback(OBEX_TL_DIS_CONN_EVT, &msg);
|
||||
|
439
components/bt/host/bluedroid/stack/obex/obex_tl_rfcomm.c
Normal file
439
components/bt/host/bluedroid/stack/obex/obex_tl_rfcomm.c
Normal file
@@ -0,0 +1,439 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "osi/osi.h"
|
||||
#include "osi/allocator.h"
|
||||
#include "common/bt_target.h"
|
||||
|
||||
#include "stack/port_api.h"
|
||||
#include "stack/btm_api.h"
|
||||
#include "stack/sdpdefs.h"
|
||||
#include "obex_tl.h"
|
||||
#include "obex_tl_rfcomm.h"
|
||||
|
||||
#if (OBEX_INCLUDED == TRUE && RFCOMM_INCLUDED == TRUE)
|
||||
|
||||
#define OBEX_TL_RFCOMM_NUM_CONN 4
|
||||
#define OBEX_TL_RFCOMM_NUM_SERVER 2
|
||||
|
||||
#define OBEX_TL_RFCOMM_EVENT_MARK (PORT_EV_FC | PORT_EV_FCS)
|
||||
|
||||
typedef struct {
|
||||
UINT16 rfc_handle; /* rfcomm handle */
|
||||
UINT16 mtu; /* rfcomm mtu */
|
||||
BOOLEAN initiator; /* TRUE if is initiator, otherwise FALSE */
|
||||
UINT8 scn; /* service channel number */
|
||||
BD_ADDR addr; /* peer bluetooth device address */
|
||||
UINT8 allocated; /* 0 if not allocated, otherwise, index + 1, equal to handle */
|
||||
} tOBEX_TL_RFCOMM_CCB;
|
||||
|
||||
typedef struct {
|
||||
UINT16 rfc_handle; /* rfcomm handle */
|
||||
UINT8 scn; /* service channel number */
|
||||
UINT8 allocated; /* 0 if not allocated, otherwise, index + 1, handle of server will left shift 8 bits */
|
||||
} tOBEX_TL_RFCOMM_SCB;
|
||||
|
||||
typedef struct {
|
||||
tOBEX_TL_CBACK *callback; /* Upper layer callback */
|
||||
tOBEX_TL_RFCOMM_CCB ccb[OBEX_TL_RFCOMM_NUM_CONN];
|
||||
tOBEX_TL_RFCOMM_SCB scb[OBEX_TL_RFCOMM_NUM_SERVER];
|
||||
UINT8 trace_level; /* trace level */
|
||||
} tOBEX_TL_RFCOMM_CB;
|
||||
|
||||
#if OBEX_DYNAMIC_MEMORY == FALSE
|
||||
static tOBEX_TL_RFCOMM_CB obex_tl_rfcomm_cb;
|
||||
#else
|
||||
static tOBEX_TL_RFCOMM_CB *obex_tl_rfcomm_cb_ptr = NULL;
|
||||
#define obex_tl_rfcomm_cb (*obex_tl_rfcomm_cb_ptr)
|
||||
#endif
|
||||
|
||||
static tOBEX_TL_RFCOMM_CCB *allocate_ccb(void)
|
||||
{
|
||||
tOBEX_TL_RFCOMM_CCB *p_ccb = NULL;
|
||||
for(int i = 0; i < OBEX_TL_RFCOMM_NUM_CONN; ++i) {
|
||||
if (obex_tl_rfcomm_cb.ccb[i].allocated == 0) {
|
||||
obex_tl_rfcomm_cb.ccb[i].allocated = i + 1;
|
||||
p_ccb = &obex_tl_rfcomm_cb.ccb[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
return p_ccb;
|
||||
}
|
||||
|
||||
static tOBEX_TL_RFCOMM_SCB *allocate_scb(void)
|
||||
{
|
||||
tOBEX_TL_RFCOMM_SCB *p_scb = NULL;
|
||||
for(int i = 0; i < OBEX_TL_RFCOMM_NUM_SERVER; ++i) {
|
||||
if (obex_tl_rfcomm_cb.scb[i].allocated == 0) {
|
||||
obex_tl_rfcomm_cb.scb[i].allocated = i + 1;
|
||||
p_scb = &obex_tl_rfcomm_cb.scb[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
return p_scb;
|
||||
}
|
||||
|
||||
static void free_ccb(tOBEX_TL_RFCOMM_CCB *p_ccb)
|
||||
{
|
||||
memset(p_ccb, 0, sizeof(tOBEX_TL_RFCOMM_CCB));
|
||||
}
|
||||
|
||||
static void free_scb(tOBEX_TL_RFCOMM_SCB *p_scb)
|
||||
{
|
||||
memset(p_scb, 0, sizeof(tOBEX_TL_RFCOMM_SCB));
|
||||
}
|
||||
|
||||
static tOBEX_TL_RFCOMM_CCB *find_ccb_by_handle(UINT16 handle)
|
||||
{
|
||||
tOBEX_TL_RFCOMM_CCB *p_ccb = NULL;
|
||||
if (handle > 0 && handle <= OBEX_TL_RFCOMM_NUM_CONN) {
|
||||
if (obex_tl_rfcomm_cb.ccb[handle-1].allocated == handle) {
|
||||
p_ccb = &obex_tl_rfcomm_cb.ccb[handle-1];
|
||||
}
|
||||
}
|
||||
return p_ccb;
|
||||
}
|
||||
|
||||
static tOBEX_TL_RFCOMM_CCB *find_ccb_by_rfc_handle(UINT16 rfc_handle)
|
||||
{
|
||||
tOBEX_TL_RFCOMM_CCB *p_ccb = NULL;
|
||||
for(int i = 0; i < OBEX_TL_RFCOMM_NUM_CONN; ++i) {
|
||||
if (obex_tl_rfcomm_cb.ccb[i].allocated && obex_tl_rfcomm_cb.ccb[i].rfc_handle == rfc_handle) {
|
||||
p_ccb = &obex_tl_rfcomm_cb.ccb[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
return p_ccb;
|
||||
}
|
||||
|
||||
static tOBEX_TL_RFCOMM_SCB *find_scb_by_handle(UINT16 handle)
|
||||
{
|
||||
tOBEX_TL_RFCOMM_SCB *p_scb = NULL;
|
||||
handle = handle >> 8;
|
||||
if (handle > 0 && handle <= OBEX_TL_RFCOMM_NUM_SERVER) {
|
||||
if (obex_tl_rfcomm_cb.scb[handle-1].allocated == handle) {
|
||||
p_scb = &obex_tl_rfcomm_cb.scb[handle-1];
|
||||
}
|
||||
}
|
||||
return p_scb;
|
||||
}
|
||||
|
||||
static tOBEX_TL_RFCOMM_SCB *find_scb_by_rfc_handle(UINT16 rfc_handle)
|
||||
{
|
||||
tOBEX_TL_RFCOMM_SCB *p_scb = NULL;
|
||||
for(int i = 0; i < OBEX_TL_RFCOMM_NUM_SERVER; ++i) {
|
||||
if (obex_tl_rfcomm_cb.scb[i].allocated && obex_tl_rfcomm_cb.scb[i].rfc_handle == rfc_handle) {
|
||||
p_scb = &obex_tl_rfcomm_cb.scb[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
return p_scb;
|
||||
}
|
||||
|
||||
static tOBEX_TL_RFCOMM_SCB *find_scb_by_scn(UINT16 scn)
|
||||
{
|
||||
tOBEX_TL_RFCOMM_SCB *p_scb = NULL;
|
||||
for(int i = 0; i < OBEX_TL_RFCOMM_NUM_SERVER; ++i) {
|
||||
if (obex_tl_rfcomm_cb.scb[i].allocated && obex_tl_rfcomm_cb.scb[i].scn == scn) {
|
||||
p_scb = &obex_tl_rfcomm_cb.scb[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
return p_scb;
|
||||
}
|
||||
|
||||
static void rfcomm_mgmt_event_handler(tOBEX_TL_RFCOMM_CCB *p_ccb, UINT32 code)
|
||||
{
|
||||
tOBEX_TL_MSG msg = {0};
|
||||
msg.any.hdl = p_ccb->allocated;
|
||||
switch (code)
|
||||
{
|
||||
case PORT_SUCCESS:
|
||||
/* event already handled, do nothing */
|
||||
break;
|
||||
default:
|
||||
/* other event, disconnect */
|
||||
obex_tl_rfcomm_cb.callback(OBEX_TL_DIS_CONN_EVT, &msg);
|
||||
free_ccb(p_ccb);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void rfcomm_client_mgmt_callback(UINT32 code, UINT16 rfc_handle, void* data)
|
||||
{
|
||||
tOBEX_TL_RFCOMM_CCB *p_ccb = find_ccb_by_rfc_handle(rfc_handle);
|
||||
if (p_ccb == NULL) {
|
||||
OBEX_TL_RFCOMM_TRACE_DEBUG("No ccb to handle rfcomm event\n");
|
||||
return;
|
||||
}
|
||||
/* connection opened, handle event here */
|
||||
if (code == PORT_SUCCESS) {
|
||||
assert(data != NULL);
|
||||
tPORT_MGMT_CL_CALLBACK_ARG *cl_mgmt_cb_arg = (tPORT_MGMT_CL_CALLBACK_ARG *)data;
|
||||
p_ccb->mtu = cl_mgmt_cb_arg->peer_mtu;
|
||||
|
||||
tOBEX_TL_MSG msg = {0};
|
||||
msg.conn_open.hdl = p_ccb->allocated;
|
||||
msg.conn_open.peer_mtu = p_ccb->mtu;
|
||||
msg.conn_open.our_mtu = p_ccb->mtu;
|
||||
obex_tl_rfcomm_cb.callback(OBEX_TL_CONN_OPEN_EVT, &msg);
|
||||
}
|
||||
rfcomm_mgmt_event_handler(p_ccb, code);
|
||||
}
|
||||
|
||||
static void rfcomm_server_mgmt_callback(UINT32 code, UINT16 rfc_handle, void* data)
|
||||
{
|
||||
tOBEX_TL_RFCOMM_CCB *p_ccb = NULL;
|
||||
/* incoming connection, handle event here */
|
||||
if (code == PORT_SUCCESS) {
|
||||
assert(data != NULL);
|
||||
tOBEX_TL_RFCOMM_SCB *p_scb = find_scb_by_rfc_handle(rfc_handle);
|
||||
tPORT_MGMT_SR_CALLBACK_ARG *sr_mgmt_cb_arg = (tPORT_MGMT_SR_CALLBACK_ARG *)data;
|
||||
if (p_scb == NULL) {
|
||||
OBEX_TL_RFCOMM_TRACE_WARNING("No scb to this rfcomm connection\n");
|
||||
/* tell rfcomm to reject this connection */
|
||||
sr_mgmt_cb_arg->accept = FALSE;
|
||||
return;
|
||||
}
|
||||
|
||||
/* try to find p_ccb with this rfc_handle, we expect to get a NULL */
|
||||
p_ccb = find_ccb_by_rfc_handle(rfc_handle);
|
||||
if (p_ccb == NULL) {
|
||||
p_ccb = allocate_ccb();
|
||||
if (p_ccb == NULL) {
|
||||
OBEX_TL_RFCOMM_TRACE_WARNING("can not allocate a ccb for new connection\n");
|
||||
sr_mgmt_cb_arg->accept = FALSE;
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
OBEX_TL_RFCOMM_TRACE_WARNING("found duplicate rfcomm connection\n");
|
||||
}
|
||||
|
||||
p_ccb->initiator = FALSE;
|
||||
p_ccb->rfc_handle = rfc_handle;
|
||||
p_ccb->scn = p_scb->scn;
|
||||
p_ccb->mtu = sr_mgmt_cb_arg->peer_mtu;
|
||||
/* get peer bd_addr */
|
||||
PORT_CheckConnection(rfc_handle, FALSE, p_ccb->addr, NULL);
|
||||
|
||||
tOBEX_TL_MSG msg = {0};
|
||||
msg.conn_income.hdl = p_ccb->allocated;
|
||||
msg.conn_income.peer_mtu = p_ccb->mtu;
|
||||
msg.conn_income.our_mtu = p_ccb->mtu;
|
||||
msg.conn_income.svr_hdl = (p_scb->allocated << 8);
|
||||
obex_tl_rfcomm_cb.callback(OBEX_TL_CONN_INCOME_EVT, &msg);
|
||||
}
|
||||
else {
|
||||
/* other event, it means server is connected */
|
||||
p_ccb = find_ccb_by_rfc_handle(rfc_handle);
|
||||
if (p_ccb == NULL) {
|
||||
OBEX_TL_RFCOMM_TRACE_DEBUG("No ccb to handle rfcomm event\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
rfcomm_mgmt_event_handler(p_ccb, code);
|
||||
}
|
||||
|
||||
static int rfcomm_data_callback(UINT16 rfc_handle, UINT8 *p_buf, UINT16 len, int type)
|
||||
{
|
||||
tOBEX_TL_RFCOMM_CCB *p_ccb = find_ccb_by_rfc_handle(rfc_handle);
|
||||
if (p_ccb != NULL && type == DATA_CO_CALLBACK_TYPE_INCOMING) {
|
||||
tOBEX_TL_MSG msg = {0};
|
||||
msg.data.hdl = p_ccb->allocated;
|
||||
msg.data.p_buf = (BT_HDR *)p_buf;
|
||||
obex_tl_rfcomm_cb.callback(OBEX_TL_DATA_EVT, &msg);
|
||||
PORT_FlowControl_GiveCredit(rfc_handle, TRUE, 1);
|
||||
}
|
||||
else if(p_buf != NULL) {
|
||||
osi_free(p_buf);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void rfcomm_event_callback(UINT32 code, UINT16 rfc_handle)
|
||||
{
|
||||
tOBEX_TL_RFCOMM_CCB *p_ccb = find_ccb_by_rfc_handle(rfc_handle);
|
||||
if (p_ccb == NULL) {
|
||||
OBEX_TL_RFCOMM_TRACE_WARNING("No ccb to handle rfcomm event\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (code & PORT_EV_FC) {
|
||||
tOBEX_TL_MSG msg = {0};
|
||||
msg.any.hdl = p_ccb->allocated;
|
||||
if (code & PORT_EV_FCS) {
|
||||
obex_tl_rfcomm_cb.callback(OBEX_TL_UNCONGEST_EVT, &msg);
|
||||
}
|
||||
else {
|
||||
obex_tl_rfcomm_cb.callback(OBEX_TL_CONGEST_EVT, &msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void obex_tl_rfcomm_init(tOBEX_TL_CBACK *callback)
|
||||
{
|
||||
assert(callback != NULL);
|
||||
#if (OBEX_DYNAMIC_MEMORY)
|
||||
if (!obex_tl_rfcomm_cb_ptr) {
|
||||
obex_tl_rfcomm_cb_ptr = (tOBEX_TL_RFCOMM_CB *)osi_malloc(sizeof(tOBEX_TL_RFCOMM_CB));
|
||||
if (!obex_tl_rfcomm_cb_ptr) {
|
||||
OBEX_TL_RFCOMM_TRACE_ERROR("OBEX over RFCOMM transport layer initialize failed, no memory\n");
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
#endif /* #if (OBEX_DYNAMIC_MEMORY) */
|
||||
memset(&obex_tl_rfcomm_cb, 0, sizeof(tOBEX_TL_RFCOMM_CB));
|
||||
obex_tl_rfcomm_cb.callback = callback;
|
||||
obex_tl_rfcomm_cb.trace_level = BT_TRACE_LEVEL_ERROR;
|
||||
}
|
||||
|
||||
void obex_tl_rfcomm_deinit(void)
|
||||
{
|
||||
#if (OBEX_DYNAMIC_MEMORY)
|
||||
if (obex_tl_rfcomm_cb_ptr) {
|
||||
osi_free(obex_tl_rfcomm_cb_ptr);
|
||||
obex_tl_rfcomm_cb_ptr = NULL;
|
||||
}
|
||||
#endif /* #if (OBEX_DYNAMIC_MEMORY) */
|
||||
}
|
||||
|
||||
UINT16 obex_tl_rfcomm_connect(tOBEX_TL_SVR_INFO *server)
|
||||
{
|
||||
tOBEX_TL_RFCOMM_CCB *p_ccb = allocate_ccb();
|
||||
if (p_ccb == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
BTM_SetSecurityLevel(TRUE, "", BTM_SEC_SERVICE_OBEX, server->rfcomm.sec_mask, BT_PSM_RFCOMM, BTM_SEC_PROTO_RFCOMM, server->rfcomm.scn);
|
||||
if (RFCOMM_CreateConnection(UUID_PROTOCOL_OBEX, server->rfcomm.scn, FALSE, server->rfcomm.pref_mtu,
|
||||
server->rfcomm.addr, &p_ccb->rfc_handle, rfcomm_client_mgmt_callback) != PORT_SUCCESS) {
|
||||
free_ccb(p_ccb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* set up data callback, event mask and event callback */
|
||||
PORT_SetDataCOCallback(p_ccb->rfc_handle, rfcomm_data_callback);
|
||||
PORT_SetEventMask(p_ccb->rfc_handle, OBEX_TL_RFCOMM_EVENT_MARK);
|
||||
PORT_SetEventCallback(p_ccb->rfc_handle, rfcomm_event_callback);
|
||||
|
||||
bdcpy(p_ccb->addr, server->rfcomm.addr);
|
||||
p_ccb->scn = server->rfcomm.scn;
|
||||
p_ccb->initiator = TRUE;
|
||||
|
||||
return p_ccb->allocated;
|
||||
}
|
||||
|
||||
void obex_tl_rfcomm_disconnect(UINT16 handle)
|
||||
{
|
||||
tOBEX_TL_RFCOMM_CCB *p_ccb = find_ccb_by_handle(handle);
|
||||
if (p_ccb != NULL) {
|
||||
RFCOMM_RemoveConnection(p_ccb->rfc_handle);
|
||||
free_ccb(p_ccb);
|
||||
}
|
||||
}
|
||||
|
||||
UINT16 obex_tl_rfcomm_send(UINT16 handle, BT_HDR *p_buf)
|
||||
{
|
||||
UINT16 ret = OBEX_TL_FAILED;
|
||||
tOBEX_TL_RFCOMM_CCB *p_ccb = find_ccb_by_handle(handle);
|
||||
do {
|
||||
if (p_ccb == NULL) {
|
||||
osi_free(p_buf);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Can not send data size larger than MTU */
|
||||
/* Offset should not smaller than OBEX_TL_RFCOMM_BT_HDR_MIN_OFFSET */
|
||||
if (p_buf->len > p_ccb->mtu || p_buf->offset < OBEX_TL_RFCOMM_BT_HDR_MIN_OFFSET) {
|
||||
osi_free(p_buf);
|
||||
break;
|
||||
}
|
||||
|
||||
if (PORT_Write(p_ccb->rfc_handle, p_buf) == PORT_SUCCESS) {
|
||||
ret = OBEX_TL_SUCCESS;
|
||||
}
|
||||
} while (0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
UINT16 obex_tl_rfcomm_bind(tOBEX_TL_SVR_INFO *server)
|
||||
{
|
||||
tOBEX_TL_RFCOMM_SCB *p_scb = find_scb_by_scn(server->rfcomm.scn);
|
||||
if (p_scb != NULL) {
|
||||
/* scn already used */
|
||||
return 0;
|
||||
}
|
||||
|
||||
p_scb = allocate_scb();
|
||||
if (p_scb == NULL) {
|
||||
OBEX_TL_RFCOMM_TRACE_WARNING("Can not allocate scb, out of number\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
BTM_SetSecurityLevel(FALSE, "", BTM_SEC_SERVICE_OBEX, server->rfcomm.sec_mask, BT_PSM_RFCOMM, BTM_SEC_PROTO_RFCOMM, server->rfcomm.scn);
|
||||
if (RFCOMM_CreateConnection(UUID_PROTOCOL_OBEX, server->rfcomm.scn, TRUE, server->rfcomm.pref_mtu,
|
||||
server->rfcomm.addr, &p_scb->rfc_handle, rfcomm_server_mgmt_callback) != PORT_SUCCESS) {
|
||||
free_scb(p_scb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* set up data callback, event mask and event callback */
|
||||
PORT_SetDataCOCallback(p_scb->rfc_handle, rfcomm_data_callback);
|
||||
PORT_SetEventMask(p_scb->rfc_handle, OBEX_TL_RFCOMM_EVENT_MARK);
|
||||
PORT_SetEventCallback(p_scb->rfc_handle, rfcomm_event_callback);
|
||||
|
||||
p_scb->scn = server->rfcomm.scn;
|
||||
|
||||
/* left shift 8 bits as server handle, avoid confuse with connection handle */
|
||||
return (p_scb->allocated << 8);
|
||||
}
|
||||
|
||||
void obex_tl_rfcomm_unbind(UINT16 handle)
|
||||
{
|
||||
tOBEX_TL_RFCOMM_SCB *p_scb = find_scb_by_handle(handle);
|
||||
if (p_scb) {
|
||||
tOBEX_TL_RFCOMM_CCB *p_ccb = NULL;
|
||||
while ((p_ccb = find_ccb_by_rfc_handle(p_scb->rfc_handle)) != NULL) {
|
||||
RFCOMM_RemoveConnection(p_ccb->rfc_handle);
|
||||
tOBEX_TL_MSG msg = {0};
|
||||
msg.any.hdl = p_ccb->allocated;
|
||||
obex_tl_rfcomm_cb.callback(OBEX_TL_DIS_CONN_EVT, &msg);
|
||||
free_ccb(p_ccb);
|
||||
}
|
||||
RFCOMM_RemoveServer(p_scb->rfc_handle);
|
||||
free_scb(p_scb);
|
||||
}
|
||||
}
|
||||
|
||||
static tOBEX_TL_OPS obex_tl_rfcomm_ops = {
|
||||
.init = obex_tl_rfcomm_init,
|
||||
.deinit = obex_tl_rfcomm_deinit,
|
||||
.connect = obex_tl_rfcomm_connect,
|
||||
.disconnect = obex_tl_rfcomm_disconnect,
|
||||
.bind = obex_tl_rfcomm_bind,
|
||||
.unbind = obex_tl_rfcomm_unbind,
|
||||
.send = obex_tl_rfcomm_send
|
||||
};
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function obex_tl_rfcomm_ops_get
|
||||
**
|
||||
** Description Get the operation function structure pointer of OBEX over
|
||||
** RFCOMM transport layer
|
||||
**
|
||||
** Returns Pointer to operation function structure
|
||||
**
|
||||
*******************************************************************************/
|
||||
tOBEX_TL_OPS *obex_tl_rfcomm_ops_get(void)
|
||||
{
|
||||
return &obex_tl_rfcomm_ops;
|
||||
}
|
||||
|
||||
#endif /* #if (OBEX_INCLUDED == TRUE && RFCOMM_INCLUDED == TRUE) */
|
@@ -64,6 +64,18 @@ PCM Signal supports three configurations in menuconfig: PCM Role, PCM Polar and
|
||||
- The default configuration is `Stereo Mode`, you can change the PCM Channel mode in `menuconfig` path:
|
||||
`Component config --> Bluetooth --> Controller Options --> PCM Signal Configurations --> PCM Signal Configurations: Role, Polar and Channel Mode(Stereo/Mono) --> Channel Mode(Stereo/Mono)`
|
||||
|
||||
### Special Configurations for PBA Client
|
||||
|
||||
To use PBA Client function, we need to enable PBA Client in `menuconfig` path: `Component config --> Bluetooth --> Bluedroid Options --> Classic Bluetooth --> Classic BT PBA Client`, this example already enable PBA Client by `sdkconfig.defaults`.
|
||||
|
||||
Step to initialize PBA Client connection:
|
||||
|
||||
- Register user callback: `esp_pbac_register_callback(bt_app_pbac_cb)`
|
||||
- Initialize PBA Client API: `esp_pbac_init()`
|
||||
- Connect to peer device ...
|
||||
- Call `esp_pbac_connect(peer_addr, supported_features, 0)`, this will initiate service discover and try to connect to PBA Server.
|
||||
- After the operation done, whether success or not, we will receive a `ESP_PBAC_CONNECTION_STATE_EVT` event in user callback.
|
||||
|
||||
### Codec Choice
|
||||
|
||||
ESP32 supports two types of codec for HFP audio data: `CVSD` and `mSBC`.
|
||||
|
@@ -2,6 +2,7 @@ idf_component_register(SRCS "app_hf_msg_set.c"
|
||||
"bt_app_core.c"
|
||||
"bt_app_hf.c"
|
||||
"gpio_pcm_config.c"
|
||||
"bt_app_pbac.c"
|
||||
"main.c"
|
||||
PRIV_REQUIRES bt nvs_flash esp_driver_gpio console esp_ringbuf
|
||||
INCLUDE_DIRS ".")
|
||||
|
@@ -17,6 +17,7 @@
|
||||
#include "esp_bt_device.h"
|
||||
#include "esp_gap_bt_api.h"
|
||||
#include "esp_hf_client_api.h"
|
||||
#include "esp_pbac_api.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/queue.h"
|
||||
@@ -244,6 +245,9 @@ void bt_app_hf_client_cb(esp_hf_client_cb_event_t event, esp_hf_client_cb_param_
|
||||
param->conn_stat.peer_feat,
|
||||
param->conn_stat.chld_feat);
|
||||
memcpy(peer_addr,param->conn_stat.remote_bda,ESP_BD_ADDR_LEN);
|
||||
if (param->conn_stat.state == ESP_HF_CLIENT_CONNECTION_STATE_SLC_CONNECTED) {
|
||||
esp_pbac_connect(peer_addr);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "esp_log.h"
|
||||
#include "esp_bt.h"
|
||||
#include "esp_pbac_api.h"
|
||||
#include "bt_app_core.h"
|
||||
#include "bt_app_pbac.h"
|
||||
|
||||
#define BT_PBAC_TAG "BT_PBAC"
|
||||
|
||||
esp_pbac_conn_hdl_t pba_conn_handle;
|
||||
|
||||
void bt_app_pbac_cb(esp_pbac_event_t event, esp_pbac_param_t *param)
|
||||
{
|
||||
switch (event)
|
||||
{
|
||||
case ESP_PBAC_CONNECTION_STATE_EVT:
|
||||
ESP_LOGI(BT_PBAC_TAG, "PBA client connection event, state: %s, reason: 0x%x", (param->conn_stat.connected ? "Connected" : "Disconnected"), param->conn_stat.reason);
|
||||
ESP_LOGI(BT_PBAC_TAG, "Peer supported repositories: 0x%x, supported features: 0x%lx", param->conn_stat.peer_supported_repo, param->conn_stat.peer_supported_feat);
|
||||
if (param->conn_stat.connected) {
|
||||
pba_conn_handle = param->conn_stat.handle;
|
||||
/* set phone book to "telecom" folder, just to test set phone book function */
|
||||
esp_pbac_set_phone_book(pba_conn_handle, ESP_PBAC_SET_PHONE_BOOK_FLAGS_DOWN, "telecom");
|
||||
}
|
||||
break;
|
||||
case ESP_PBAC_PULL_PHONE_BOOK_RESPONSE_EVT:
|
||||
/* if multiple PBA connection, we should check param->pull_phone_book_rsp.handle */
|
||||
ESP_LOGI(BT_PBAC_TAG, "PBA client pull phone book response, handle:%d, result: 0x%x", param->pull_phone_book_rsp.handle, param->pull_phone_book_rsp.result);
|
||||
if (param->pull_phone_book_rsp.result == ESP_PBAC_SUCCESS && param->pull_phone_book_rsp.data_len > 0) {
|
||||
printf("%.*s\n", param->pull_phone_book_rsp.data_len, param->pull_phone_book_rsp.data);
|
||||
/* copy data to other buff before return, if phone book size is too large, it will be sent in multiple response event */
|
||||
}
|
||||
if (param->pull_phone_book_rsp.final) {
|
||||
ESP_LOGI(BT_PBAC_TAG, "PBA client pull phone book final response");
|
||||
/* pull phone book done, now we can perform other operation */
|
||||
if (param->pull_phone_book_rsp.result == ESP_PBAC_SUCCESS && param->pull_phone_book_rsp.include_phone_book_size) {
|
||||
ESP_LOGI(BT_PBAC_TAG, "Phone Book Size:%d", param->pull_phone_book_rsp.phone_book_size);
|
||||
esp_pbac_pull_phone_book_app_param_t app_param = {0};
|
||||
app_param.include_property_selector = 1;
|
||||
/* property bit mask, filter out photo, refer to Phone Book Access Profile */
|
||||
app_param.property_selector = 0xFFFFFFF7;
|
||||
/* pull again, without 'max_list_count = 0', then we can get the entire phone book */
|
||||
esp_pbac_pull_phone_book(pba_conn_handle, "telecom/pb.vcf", &app_param);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ESP_PBAC_SET_PHONE_BOOK_RESPONSE_EVT:
|
||||
ESP_LOGI(BT_PBAC_TAG, "PBA client set phone book response, handle:%d, result: 0x%x", param->set_phone_book_rsp.handle, param->set_phone_book_rsp.result);
|
||||
/* done, set phone book response will always be a final response */
|
||||
if (param->set_phone_book_rsp.result == ESP_PBAC_SUCCESS) {
|
||||
esp_pbac_pull_phone_book_app_param_t app_param = {0};
|
||||
app_param.include_max_list_count = 1;
|
||||
/* set max_list_count to zero, then we can get phone book size in peer response */
|
||||
app_param.max_list_count = 0;
|
||||
/* pull phone book use a absolute path; if no app param, we can pass a NULL to API */
|
||||
esp_pbac_pull_phone_book(pba_conn_handle, "telecom/pb.vcf", &app_param);
|
||||
}
|
||||
break;
|
||||
case ESP_PBAC_PULL_VCARD_LISTING_RESPONSE_EVT:
|
||||
ESP_LOGI(BT_PBAC_TAG, "PBA client pull vCard listing response, handle:%d, result: 0x%x", param->pull_vcard_listing_rsp.handle, param->pull_vcard_listing_rsp.result);
|
||||
if (param->pull_vcard_listing_rsp.result == ESP_PBAC_SUCCESS) {
|
||||
printf("%.*s\n", param->pull_vcard_listing_rsp.data_len, param->pull_vcard_listing_rsp.data);
|
||||
}
|
||||
if (param->pull_vcard_listing_rsp.final) {
|
||||
ESP_LOGI(BT_PBAC_TAG, "PBA client pull vCard listing final response");
|
||||
}
|
||||
break;
|
||||
case ESP_PBAC_PULL_VCARD_ENTRY_RESPONSE_EVT:
|
||||
ESP_LOGI(BT_PBAC_TAG, "PBA client pull vCard entry response, handle:%d, result: 0x%x", param->pull_vcard_entry_rsp.handle, param->pull_vcard_entry_rsp.result);
|
||||
if (param->pull_vcard_entry_rsp.result == ESP_PBAC_SUCCESS) {
|
||||
printf("%.*s\n", param->pull_vcard_entry_rsp.data_len, param->pull_vcard_entry_rsp.data);
|
||||
}
|
||||
if (param->pull_vcard_entry_rsp.final) {
|
||||
ESP_LOGI(BT_PBAC_TAG, "PBA client pull vCard entry final response");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "esp_bt.h"
|
||||
#include "esp_pbac_api.h"
|
||||
|
||||
void bt_app_pbac_cb(esp_pbac_event_t event, esp_pbac_param_t *param);
|
@@ -21,10 +21,12 @@
|
||||
#include "esp_bt_device.h"
|
||||
#include "esp_gap_bt_api.h"
|
||||
#include "esp_hf_client_api.h"
|
||||
#include "esp_pbac_api.h"
|
||||
#include "bt_app_hf.h"
|
||||
#include "gpio_pcm_config.h"
|
||||
#include "esp_console.h"
|
||||
#include "app_hf_msg_set.h"
|
||||
#include "bt_app_pbac.h"
|
||||
|
||||
esp_bd_addr_t peer_addr = {0};
|
||||
static char peer_bdname[ESP_BT_GAP_MAX_BDNAME_LEN + 1];
|
||||
@@ -251,6 +253,8 @@ static void bt_hf_client_hdl_stack_evt(uint16_t event, void *p_param)
|
||||
esp_bt_gap_register_callback(esp_bt_gap_cb);
|
||||
esp_hf_client_register_callback(bt_app_hf_client_cb);
|
||||
esp_hf_client_init();
|
||||
esp_pbac_register_callback(bt_app_pbac_cb);
|
||||
esp_pbac_init();
|
||||
|
||||
#if (CONFIG_EXAMPLE_SSP_ENABLED == true)
|
||||
/* Set default parameters for Secure Simple Pairing */
|
||||
|
@@ -8,3 +8,4 @@ CONFIG_BT_BLUEDROID_ENABLED=y
|
||||
CONFIG_BT_CLASSIC_ENABLED=y
|
||||
CONFIG_BT_HFP_ENABLE=y
|
||||
CONFIG_BT_HFP_CLIENT_ENABLE=y
|
||||
CONFIG_BT_PBAC_ENABLED=y
|
||||
|
Reference in New Issue
Block a user