forked from espressif/esp-idf
feat(bt/bluedroid): Support PBAP client role
Closes https://github.com/espressif/esp-idf/issues/11522
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"
|
||||
|
@ -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);
|
@ -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
|
||||
|
@ -186,6 +186,13 @@
|
||||
#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. */
|
||||
|
@ -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;
|
||||
|
Reference in New Issue
Block a user