Merge branch 'bugfix/spp_50005_crash_v5.0' into 'release/v5.0'

bt: Added esp_spp_enhanced_init() API to indicate whether to enable L2CAP ERTM(v5.0)

See merge request espressif/esp-idf!20822
This commit is contained in:
Wang Meng Yang
2022-12-12 11:00:28 +08:00
23 changed files with 437 additions and 179 deletions

View File

@ -34,16 +34,36 @@ esp_err_t esp_spp_register_callback(esp_spp_cb_t callback)
esp_err_t esp_spp_init(esp_spp_mode_t mode)
{
esp_spp_cfg_t bt_spp_cfg = {
.mode = mode,
.enable_l2cap_ertm = true,
.tx_buffer_size = ESP_SPP_MAX_TX_BUFFER_SIZE,
};
return esp_spp_enhanced_init(&bt_spp_cfg);
}
esp_err_t esp_spp_enhanced_init(const esp_spp_cfg_t *cfg)
{
btc_msg_t msg;
btc_spp_args_t arg;
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
if (cfg->mode == ESP_SPP_MODE_VFS && (cfg->tx_buffer_size < ESP_SPP_MIN_TX_BUFFER_SIZE ||
cfg->tx_buffer_size > ESP_SPP_MAX_TX_BUFFER_SIZE)) {
LOG_WARN("Invalid tx buffer size");
return ESP_ERR_INVALID_ARG;
}
msg.sig = BTC_SIG_API_CALL;
msg.pid = BTC_PID_SPP;
msg.act = BTC_SPP_ACT_INIT;
arg.init.mode = mode;
arg.init.mode = cfg->mode;
arg.init.enable_l2cap_ertm = cfg->enable_l2cap_ertm;
arg.init.tx_buffer_size = cfg->tx_buffer_size;
return (btc_transfer_context(&msg, &arg, sizeof(btc_spp_args_t), NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL);
}

View File

@ -14,17 +14,19 @@
extern "C" {
#endif
typedef enum {
ESP_SPP_SUCCESS = 0, /*!< Successful operation. */
ESP_SPP_FAILURE, /*!< Generic failure. */
ESP_SPP_BUSY, /*!< Temporarily can not handle this request. */
ESP_SPP_NO_DATA, /*!< No data */
ESP_SPP_NO_RESOURCE, /*!< No more resource */
ESP_SPP_NEED_INIT, /*!< SPP module shall init first */
ESP_SPP_NEED_DEINIT, /*!< SPP module shall deinit first */
ESP_SPP_NO_CONNECTION, /*!< Connection may have been closed */
ESP_SPP_NO_SERVER, /*!< No SPP server */
} esp_spp_status_t;
#define ESP_SPP_MAX_MTU (3*330) /*!< SPP max MTU */
#define ESP_SPP_MAX_SCN 31 /*!< SPP max SCN */
#define ESP_SPP_MIN_TX_BUFFER_SIZE 100 /*!< SPP min tx buffer */
#define ESP_SPP_MAX_TX_BUFFER_SIZE (ESP_SPP_MAX_MTU * 10) /*!< SPP max tx buffer size */
/**
* @brief SPP default configuration
*/
#define BT_SPP_DEFAULT_CONFIG() { \
.mode = ESP_SPP_MODE_VFS, \
.enable_l2cap_ertm = true, \
.tx_buffer_size = ESP_SPP_MAX_TX_BUFFER_SIZE, \
}
/* Security Setting Mask
Use these three mask mode:
@ -41,6 +43,18 @@ Use these three mask mode:
#define ESP_SPP_SEC_IN_16_DIGITS 0x4000 /*!< Min 16 digit for pin code relate to BTA_SEC_IN_16_DIGITS in bta/bta_api.h*/
typedef uint16_t esp_spp_sec_t;
typedef enum {
ESP_SPP_SUCCESS = 0, /*!< Successful operation. */
ESP_SPP_FAILURE, /*!< Generic failure. */
ESP_SPP_BUSY, /*!< Temporarily can not handle this request. */
ESP_SPP_NO_DATA, /*!< No data */
ESP_SPP_NO_RESOURCE, /*!< No more resource */
ESP_SPP_NEED_INIT, /*!< SPP module shall init first */
ESP_SPP_NEED_DEINIT, /*!< SPP module shall deinit first */
ESP_SPP_NO_CONNECTION, /*!< Connection may have been closed */
ESP_SPP_NO_SERVER, /*!< No SPP server */
} esp_spp_status_t;
typedef enum {
ESP_SPP_ROLE_MASTER = 0, /*!< Role: master */
ESP_SPP_ROLE_SLAVE = 1, /*!< Role: slave */
@ -51,8 +65,15 @@ typedef enum {
ESP_SPP_MODE_VFS = 1, /*!< Use VFS to write/read data */
} esp_spp_mode_t;
#define ESP_SPP_MAX_MTU (3*330) /*!< SPP max MTU */
#define ESP_SPP_MAX_SCN 31 /*!< SPP max SCN */
/**
* @brief SPP configuration parameters
*/
typedef struct {
esp_spp_mode_t mode; /*!< Choose the mode of SPP, ESP_SPP_MODE_CB or ESP_SPP_MODE_VFS. */
bool enable_l2cap_ertm; /*!< Enable/disable Logical Link Control and Adaptation Layer Protocol enhanced retransmission mode. */
uint16_t tx_buffer_size; /*!< Tx buffer size for a new SPP channel. A smaller setting can save memory, but may incur a decrease in throughput. Only for ESP_SPP_MODE_VFS mode. */
} esp_spp_cfg_t;
/**
* @brief SPP callback function events
*/
@ -221,14 +242,31 @@ esp_err_t esp_spp_register_callback(esp_spp_cb_t callback);
* - ESP_OK: success
* - other: failed
*/
esp_err_t esp_spp_init(esp_spp_mode_t mode);
esp_err_t esp_spp_init(esp_spp_mode_t mode) __attribute__((deprecated("Please use esp_spp_enhanced_init")));
/**
* @brief This function is called to init SPP module.
* When the operation is completed, the callback function will be called with ESP_SPP_INIT_EVT.
* This function should be called after esp_bluedroid_enable() completes successfully.
*
* @param[in] cfg: SPP configuration.
*
* @note The member variable enable_l2cap_etrm in esp_spp_cfg_t can affect all L2CAP channel
* configurations of the upper layer RFCOMM protocol.
*
* @return
* - ESP_OK: success
* - other: failed
*/
esp_err_t esp_spp_enhanced_init(const esp_spp_cfg_t *cfg);
/**
* @brief This function is called to uninit SPP module.
* The operation will close all active SPP connection first, then the callback function will be called
* with ESP_SPP_CLOSE_EVT, and the number of ESP_SPP_CLOSE_EVT is equal to the number of connection.
* When the operation is completed, the callback function will be called with ESP_SPP_UNINIT_EVT.
* This function should be called after esp_spp_init() completes successfully.
* This function should be called after esp_spp_init()/esp_spp_enhanced_init() completes successfully.
*
* @return
* - ESP_OK: success
@ -240,7 +278,7 @@ esp_err_t esp_spp_deinit(void);
/**
* @brief This function is called to performs service discovery for the services provided by the given peer device.
* When the operation is completed, the callback function will be called with ESP_SPP_DISCOVERY_COMP_EVT.
* This function must be called after esp_spp_init() successful and before esp_spp_deinit().
* This function must be called after esp_spp_init()/esp_spp_enhanced_init() successful and before esp_spp_deinit().
*
* @param[in] bd_addr: Remote device bluetooth device address.
*
@ -254,7 +292,7 @@ esp_err_t esp_spp_start_discovery(esp_bd_addr_t bd_addr);
* @brief This function makes an SPP connection to a remote BD Address.
* When the connection is initiated or failed to initiate, the callback is called with ESP_SPP_CL_INIT_EVT.
* When the connection is established or failed, the callback is called with ESP_SPP_OPEN_EVT.
* This function must be called after esp_spp_init() successful and before esp_spp_deinit().
* This function must be called after esp_spp_init()/esp_spp_enhanced_init() successful and before esp_spp_deinit().
*
* @param[in] sec_mask: Security Setting Mask. Suggest to use ESP_SPP_SEC_NONE, ESP_SPP_SEC_AUTHORIZE or ESP_SPP_SEC_AUTHENTICATE only.
* @param[in] role: Master or slave.
@ -270,7 +308,7 @@ esp_err_t esp_spp_connect(esp_spp_sec_t sec_mask, esp_spp_role_t role, uint8_t r
/**
* @brief This function closes an SPP connection.
* When the operation is completed, the callback function will be called with ESP_SPP_CLOSE_EVT.
* This function must be called after esp_spp_init() successful and before esp_spp_deinit().
* This function must be called after esp_spp_init()/esp_spp_enhanced_init() successful and before esp_spp_deinit().
*
* @param[in] handle: The connection handle.
*
@ -285,7 +323,7 @@ esp_err_t esp_spp_disconnect(uint32_t handle);
* SPP connection request from a remote Bluetooth device.
* When the server is started successfully, the callback is called with ESP_SPP_START_EVT.
* When the connection is established, the callback is called with ESP_SPP_SRV_OPEN_EVT.
* This function must be called after esp_spp_init() successful and before esp_spp_deinit().
* This function must be called after esp_spp_init()/esp_spp_enhanced_init() successful and before esp_spp_deinit().
*
* @param[in] sec_mask: Security Setting Mask. Suggest to use ESP_SPP_SEC_NONE, ESP_SPP_SEC_AUTHORIZE or ESP_SPP_SEC_AUTHENTICATE only.
* @param[in] role: Master or slave.
@ -304,7 +342,7 @@ esp_err_t esp_spp_start_srv(esp_spp_sec_t sec_mask, esp_spp_role_t role, uint8_t
* The operation will close all active SPP connection first, then the callback function will be called
* with ESP_SPP_CLOSE_EVT, and the number of ESP_SPP_CLOSE_EVT is equal to the number of connection.
* When the operation is completed, the callback is called with ESP_SPP_SRV_STOP_EVT.
* This function must be called after esp_spp_init() successful and before esp_spp_deinit().
* This function must be called after esp_spp_init()/esp_spp_enhanced_init() successful and before esp_spp_deinit().
*
* @return
* - ESP_OK: success
@ -318,7 +356,7 @@ esp_err_t esp_spp_stop_srv(void);
* The operation will close all active SPP connection first on the specific SPP server, then the callback function will be called
* with ESP_SPP_CLOSE_EVT, and the number of ESP_SPP_CLOSE_EVT is equal to the number of connection.
* When the operation is completed, the callback is called with ESP_SPP_SRV_STOP_EVT.
* This function must be called after esp_spp_init() successful and before esp_spp_deinit().
* This function must be called after esp_spp_init()/esp_spp_enhanced_init() successful and before esp_spp_deinit().
*
* @param[in] scn: Server channel number.
*

View File

@ -53,6 +53,7 @@ typedef UINT8 tBTA_JV_STATUS;
#define BTA_JV_MAX_L2C_CONN GAP_MAX_CONNECTIONS /* GAP handle is used as index, hence do not change this value */
#define BTA_JV_MAX_SCN PORT_MAX_RFC_PORTS /* same as BTM_MAX_SCN (in btm_int.h) */
#define BTA_JV_MAX_RFC_CONN MAX_RFC_PORTS
#define BTA_JV_MAX_CREDIT_NUM PORT_RX_BUF_HIGH_WM
#ifndef BTA_JV_DEF_RFC_MTU
#define BTA_JV_DEF_RFC_MTU (3*330)
@ -286,6 +287,7 @@ typedef struct {
/* data associated with BTA_JV_RFCOMM_OPEN_EVT */
typedef struct {
tBTA_JV_STATUS status; /* Whether the operation succeeded or failed. */
UINT16 peer_mtu; /* Max MTU that port can send */
UINT32 handle; /* The connection handle */
BD_ADDR rem_bda; /* The peer address */
} tBTA_JV_RFCOMM_OPEN;
@ -293,6 +295,7 @@ typedef struct {
/* data associated with BTA_JV_RFCOMM_SRV_OPEN_EVT */
typedef struct {
tBTA_JV_STATUS status; /* Whether the operation succeeded or failed. */
UINT16 peer_mtu; /* Max MTU that port can send */
UINT32 handle; /* The connection handle */
UINT32 new_listen_handle; /* The new listen handle */
BD_ADDR rem_bda; /* The peer address */
@ -802,6 +805,19 @@ extern tBTA_JV_STATUS BTA_JvL2capWriteFixed(UINT16 channel, BD_ADDR *addr, UINT3
#endif /* BTA_JV_L2CAP_INCLUDED */
#if BTA_JV_RFCOMM_INCLUDED
/*******************************************************************************
**
** Function BTA_JvRfcommConfig
**
** Description This function is to configure RFCOMM.
**
**
** Returns BTA_JV_SUCCESS, if the request is being processed.
** BTA_JV_FAILURE, otherwise.
**
*******************************************************************************/
extern tBTA_JV_STATUS BTA_JvRfcommConfig(BOOLEAN enable_l2cap_ertm);
/*******************************************************************************
**
** Function BTA_JvRfcommConnect

View File

@ -1685,6 +1685,7 @@ static void bta_jv_port_mgmt_cl_cback(UINT32 code, UINT16 port_handle, void* dat
BD_ADDR rem_bda = {0};
UINT16 lcid;
tBTA_JV_RFCOMM_CBACK *p_cback; /* the callback function */
tPORT_MGMT_CL_CALLBACK_ARG *p_mgmt_cb_arg = (tPORT_MGMT_CL_CALLBACK_ARG *)data;
APPL_TRACE_DEBUG( "bta_jv_port_mgmt_cl_cback:code:%d, port_handle%d", code, port_handle);
if (NULL == p_cb || NULL == p_cb->p_cback) {
@ -1701,6 +1702,9 @@ static void bta_jv_port_mgmt_cl_cback(UINT32 code, UINT16 port_handle, void* dat
evt_data.rfc_open.status = BTA_JV_SUCCESS;
bdcpy(evt_data.rfc_open.rem_bda, rem_bda);
p_pcb->state = BTA_JV_ST_CL_OPEN;
if (p_mgmt_cb_arg) {
evt_data.rfc_open.peer_mtu = p_mgmt_cb_arg->peer_mtu;
}
p_cb->p_cback(BTA_JV_RFCOMM_OPEN_EVT, &evt_data, p_pcb->user_data);
} else {
evt_data.rfc_close.handle = p_pcb->handle;
@ -1760,6 +1764,22 @@ static void bta_jv_port_event_cl_cback(UINT32 code, UINT16 port_handle)
}
}
/*******************************************************************************
**
** Function bta_jv_rfcomm_config
**
** Description Configure RFCOMM
**
** Returns void
**
*******************************************************************************/
void bta_jv_rfcomm_config(tBTA_JV_MSG *p_data)
{
APPL_TRACE_DEBUG("%s enable_l2cap_ertm:%d", __func__, p_data->rfcomm_config.enable_l2cap_ertm);
PORT_SetL2capErtm(p_data->rfcomm_config.enable_l2cap_ertm);
}
/*******************************************************************************
**
** Function bta_jv_rfcomm_connect
@ -1981,6 +2001,7 @@ static void bta_jv_port_mgmt_sr_cback(UINT32 code, UINT16 port_handle, void *dat
}
evt_data.rfc_srv_open.handle = p_pcb->handle;
evt_data.rfc_srv_open.status = BTA_JV_SUCCESS;
evt_data.rfc_srv_open.peer_mtu = p_mgmt_cb_arg->peer_mtu;
bdcpy(evt_data.rfc_srv_open.rem_bda, rem_bda);
tBTA_JV_PCB *p_pcb_new_listen = bta_jv_add_rfc_port(p_cb, p_pcb);
if (p_pcb_new_listen) {

View File

@ -862,6 +862,33 @@ tBTA_JV_STATUS BTA_JvL2capWriteFixed(UINT16 channel, BD_ADDR *addr, UINT32 req_i
#endif /* BTA_JV_L2CAP_INCLUDED */
#if BTA_JV_RFCOMM_INCLUDED
/*******************************************************************************
**
** Function BTA_JvRfcommConfig
**
** Description This function is to configure RFCOMM.
**
** Returns BTA_JV_SUCCESS, if the request is being processed.
** BTA_JV_FAILURE, otherwise.
**
*******************************************************************************/
tBTA_JV_STATUS BTA_JvRfcommConfig(BOOLEAN enable_l2cap_ertm)
{
tBTA_JV_STATUS status = BTA_JV_FAILURE;
tBTA_JV_API_RFCOMM_CONFIG *p_msg;
APPL_TRACE_API( "%s", __func__);
if ((p_msg = (tBTA_JV_API_RFCOMM_CONFIG *)osi_malloc(sizeof(tBTA_JV_API_RFCOMM_CONFIG))) != NULL) {
p_msg->hdr.event = BTA_JV_API_RFCOMM_CONFIG_EVT;
p_msg->enable_l2cap_ertm = enable_l2cap_ertm;
bta_sys_sendmsg(p_msg);
status = BTA_JV_SUCCESS;
}
return (status);
}
/*******************************************************************************
**
** Function BTA_JvRfcommConnect

View File

@ -63,6 +63,7 @@ const tBTA_JV_ACTION bta_jv_action[] = {
bta_jv_l2cap_write, /* BTA_JV_API_L2CAP_WRITE_EVT */
#endif /* BTA_JV_L2CAP_INCLUDED */
#if BTA_JV_RFCOMM_INCLUDED
bta_jv_rfcomm_config, /* BTA_JV_API_RFCOMM_CONFIG_EVT */
bta_jv_rfcomm_connect, /* BTA_JV_API_RFCOMM_CONNECT_EVT */
bta_jv_rfcomm_close, /* BTA_JV_API_RFCOMM_CLOSE_EVT */
bta_jv_rfcomm_start_server, /* BTA_JV_API_RFCOMM_START_SERVER_EVT */
@ -70,7 +71,7 @@ const tBTA_JV_ACTION bta_jv_action[] = {
bta_jv_rfcomm_read, /* BTA_JV_API_RFCOMM_READ_EVT */
bta_jv_rfcomm_write, /* BTA_JV_API_RFCOMM_WRITE_EVT */
bta_jv_rfcomm_flow_control, /* BTA_JV_API_RFCOMM_FLOW_CONTROL_EVT */
#endif /* BTA_JV_RFCOMM_INCLUDED */
#endif /* BTA_JV_RFCOMM_INCLUDED */
bta_jv_set_pm_profile, /* BTA_JV_API_SET_PM_PROFILE_EVT */
bta_jv_change_pm_state, /* BTA_JV_API_PM_STATE_CHANGE_EVT */
#if BTA_JV_L2CAP_INCLUDED

View File

@ -57,6 +57,7 @@ enum {
BTA_JV_API_L2CAP_WRITE_EVT,
#endif /* BTA_JV_L2CAP_INCLUDED */
#if BTA_JV_RFCOMM_INCLUDED
BTA_JV_API_RFCOMM_CONFIG_EVT,
BTA_JV_API_RFCOMM_CONNECT_EVT,
BTA_JV_API_RFCOMM_CLOSE_EVT,
BTA_JV_API_RFCOMM_START_SERVER_EVT,
@ -83,7 +84,7 @@ enum {
/* data type for BTA_JV_API_ENABLE_EVT */
typedef struct {
BT_HDR hdr;
BT_HDR hdr;
tBTA_JV_DM_CBACK *p_cback;
} tBTA_JV_API_ENABLE;
@ -257,6 +258,12 @@ typedef struct {
#endif /* BTA_JV_L2CAP_INCLUDED */
#if BTA_JV_RFCOMM_INCLUDED
/* data type for BTA_JV_API_RFCOMM_CONFIG_EVT */
typedef struct {
BT_HDR hdr;
BOOLEAN enable_l2cap_ertm;
} tBTA_JV_API_RFCOMM_CONFIG;
/* data type for BTA_JV_API_RFCOMM_CONNECT_EVT */
typedef struct {
BT_HDR hdr;
@ -392,6 +399,7 @@ typedef union {
tBTA_JV_API_L2CAP_WRITE_FIXED l2cap_write_fixed;
#endif /* BTA_JV_L2CAP_INCLUDED */
#if BTA_JV_RFCOMM_INCLUDED
tBTA_JV_API_RFCOMM_CONFIG rfcomm_config;
tBTA_JV_API_RFCOMM_CONNECT rfcomm_connect;
tBTA_JV_API_RFCOMM_READ rfcomm_read;
tBTA_JV_API_RFCOMM_WRITE rfcomm_write;
@ -463,6 +471,7 @@ extern void bta_jv_l2cap_read (tBTA_JV_MSG *p_data);
extern void bta_jv_l2cap_write (tBTA_JV_MSG *p_data);
#endif /* BTA_JV_L2CAP_INCLUDED */
#if BTA_JV_RFCOMM_INCLUDED
extern void bta_jv_rfcomm_config (tBTA_JV_MSG *p_data);
extern void bta_jv_rfcomm_connect (tBTA_JV_MSG *p_data);
extern void bta_jv_rfcomm_close (tBTA_JV_MSG *p_data);
extern void bta_jv_rfcomm_start_server (tBTA_JV_MSG *p_data);

View File

@ -18,8 +18,6 @@
#define ESP_SPP_MAX_SESSION BTA_JV_MAX_RFC_SR_SESSION
#define ESP_SPP_SERVER_NAME_MAX 32
#define ESP_SPP_RINGBUF_SIZE 1000
#define BTC_SPP_INVALID_SCN 0x00
typedef enum {
@ -38,6 +36,8 @@ typedef union {
//BTC_SPP_ACT_INIT
struct init_arg {
esp_spp_mode_t mode;
bool enable_l2cap_ertm;
UINT16 tx_buffer_size;
} init;
//BTC_SPP_ACT_UNINIT
struct uninit_arg {

View File

@ -49,11 +49,14 @@ typedef struct {
typedef struct {
bool connected;
bool is_server;
bool is_writing;
uint8_t serial;
uint8_t scn;
uint8_t max_session;
uint16_t mtu;
uint16_t credit_rx;
uint16_t write_data_len;
uint32_t id;
uint32_t mtu;//unused
uint32_t sdp_handle;
uint32_t rfc_handle;
uint32_t rfc_port_handle;
@ -64,12 +67,16 @@ typedef struct {
esp_spp_sec_t security;
esp_bd_addr_t addr;
slot_data_t rx;
slot_data_t tx;
union {
slot_data_t tx;
RingbufHandle_t ringbuf_write;
};
uint8_t service_uuid[16];
char service_name[ESP_SPP_SERVER_NAME_MAX + 1];
} spp_slot_t;
typedef struct {
uint16_t tx_buffer_size;
spp_slot_t *spp_slots[MAX_RFC_PORTS + 1];
uint32_t spp_slot_id;
esp_spp_mode_t spp_mode;
@ -133,7 +140,11 @@ static spp_slot_t *spp_malloc_slot(void)
(*slot)->fd = -1;
(*slot)->connected = false;
(*slot)->is_server = false;
(*slot)->mtu = 0;
(*slot)->credit_rx = BTA_JV_MAX_CREDIT_NUM;
(*slot)->write_data = NULL;
(*slot)->write_data_len = 0;
(*slot)->is_writing = false;
(*slot)->close_alarm = NULL;
/* clear the old event bits */
if (spp_local_param.tx_event_group) {
@ -145,12 +156,18 @@ static spp_slot_t *spp_malloc_slot(void)
err_no = 1;
goto err;
}
if (init_slot_data(&(*slot)->tx, SLOT_TX_QUEUE_SIZE)) {
BTC_TRACE_ERROR("%s unable to malloc tx queue!", __func__);
err_no = 2;
goto err;
}
if (spp_local_param.spp_mode == ESP_SPP_MODE_VFS) {
if (spp_local_param.spp_mode == ESP_SPP_MODE_CB) {
if (init_slot_data(&(*slot)->tx, SLOT_TX_QUEUE_SIZE)) {
BTC_TRACE_ERROR("%s unable to malloc tx queue!", __func__);
err_no = 2;
goto err;
}
} else {
if (((*slot)->ringbuf_write = xRingbufferCreate(spp_local_param.tx_buffer_size, RINGBUF_TYPE_BYTEBUF)) == NULL) {
BTC_TRACE_ERROR("%s write ringbuffer create error!", __func__);
err_no = 2;
goto err;
}
if (esp_vfs_register_fd(spp_local_param.spp_vfs_id, &(*slot)->fd) != ESP_OK) {
BTC_TRACE_ERROR("%s unable to register fd!", __func__);
err_no = 3;
@ -165,7 +182,9 @@ static spp_slot_t *spp_malloc_slot(void)
err:
switch (err_no) {
case 3:
free_slot_data(&(*slot)->tx);
if (spp_local_param.spp_mode == ESP_SPP_MODE_VFS) {
vRingbufferDelete((*slot)->ringbuf_write);
}
case 2:
free_slot_data(&(*slot)->rx);
case 1:
@ -238,7 +257,7 @@ static void close_timeout_handler(void *arg)
status = btc_transfer_context(&msg, arg, sizeof(tBTA_JV), NULL);
if (arg) {
free(arg);
osi_free(arg);
}
if (status != BT_STATUS_SUCCESS) {
@ -255,8 +274,10 @@ static void spp_free_slot(spp_slot_t *slot)
if (spp_local_param.spp_mode == ESP_SPP_MODE_VFS) {
(void) esp_vfs_unregister_fd(spp_local_param.spp_vfs_id, slot->fd);
xEventGroupSetBits(spp_local_param.tx_event_group, SLOT_CLOSE_BIT(slot->serial));
vRingbufferDelete(slot->ringbuf_write);
} else {
free_slot_data(&slot->tx);
}
free_slot_data(&slot->tx);
free_slot_data(&slot->rx);
if (slot->close_alarm) {
osi_alarm_free(slot->close_alarm);
@ -333,6 +354,7 @@ static void *btc_spp_rfcomm_inter_cb(tBTA_JV_EVT event, tBTA_JV *p_data, void *u
slot_new->max_session = slot->max_session;
strcpy(slot_new->service_name, slot->service_name);
slot_new->sdp_handle = slot->sdp_handle;
slot_new->mtu = p_data->rfc_srv_open.peer_mtu;
slot_new->rfc_handle = p_data->rfc_srv_open.handle;
slot_new->rfc_port_handle = BTA_JvRfcommGetPortHdl(slot_new->rfc_handle);
BTA_JvSetPmProfile(p_data->rfc_srv_open.handle, BTA_JV_PM_ALL, BTA_JV_CONN_OPEN);
@ -375,6 +397,7 @@ static void *btc_spp_rfcomm_inter_cb(tBTA_JV_EVT event, tBTA_JV *p_data, void *u
}
slot->connected = true;
slot->rfc_handle = p_data->rfc_open.handle;
slot->mtu = p_data->rfc_open.peer_mtu;
slot->rfc_port_handle = BTA_JvRfcommGetPortHdl(p_data->rfc_open.handle);
BTA_JvSetPmProfile(p_data->rfc_open.handle, BTA_JV_PM_ID_1, BTA_JV_CONN_OPEN);
break;
@ -525,7 +548,9 @@ static void btc_spp_init(btc_spp_args_t *arg)
}
spp_local_param.spp_mode = arg->init.mode;
spp_local_param.spp_slot_id = 0;
spp_local_param.tx_buffer_size = arg->init.tx_buffer_size;
BTA_JvEnable((tBTA_JV_DM_CBACK *)btc_spp_dm_inter_cb);
BTA_JvRfcommConfig(arg->init.enable_l2cap_ertm);
} while (0);
if (ret != ESP_SPP_SUCCESS) {
@ -731,7 +756,7 @@ static void btc_spp_stop_srv(btc_spp_args_t *arg)
esp_spp_status_t ret = ESP_SPP_SUCCESS;
bool is_remove_all = false;
uint8_t i, j, srv_cnt = 0;
uint8_t *srv_scn_arr = osi_malloc(MAX_RFC_PORTS);
uint8_t *srv_scn_arr = NULL;
if (arg->stop_srv.scn == BTC_SPP_INVALID_SCN) {
is_remove_all = true;
}
@ -742,6 +767,7 @@ static void btc_spp_stop_srv(btc_spp_args_t *arg)
ret = ESP_SPP_NEED_INIT;
break;
}
srv_scn_arr = osi_malloc(MAX_RFC_PORTS);
if (srv_scn_arr == NULL) {
BTC_TRACE_ERROR("%s malloc srv_scn_arr failed\n", __func__);
ret = ESP_SPP_NO_RESOURCE;
@ -834,6 +860,7 @@ static void btc_spp_stop_srv(btc_spp_args_t *arg)
static void btc_spp_write(btc_spp_args_t *arg)
{
esp_spp_status_t ret = ESP_SPP_SUCCESS;
do {
if (!is_spp_init()) {
BTC_TRACE_ERROR("%s SPP have not been init\n", __func__);
@ -854,18 +881,23 @@ static void btc_spp_write(btc_spp_args_t *arg)
break;
}
if (spp_local_param.spp_mode == ESP_SPP_MODE_VFS) {
BT_HDR *p_buf;
if ((p_buf = fixed_queue_try_peek_first(slot->tx.queue)) != NULL && p_buf->layer_specific == 0) {
p_buf->event++;
p_buf->layer_specific = 1;
BTA_JvRfcommWrite(arg->write.handle, slot->id, p_buf->len, p_buf->data + p_buf->offset);
if (slot->is_writing) {
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
return;
}
size_t item_size = 0;
uint8_t *data = xRingbufferReceiveUpTo(slot->ringbuf_write, &item_size, 0, slot->mtu);
if (item_size > 0) {
slot->write_data = data;
slot->write_data_len = item_size;
slot->is_writing = true;
BTA_JvRfcommWrite(arg->write.handle, slot->id, item_size, data);
}
} else {
if (fixed_queue_enqueue(slot->tx.queue, arg->write.p_data, 0)) {
BTA_JvRfcommWrite(arg->write.handle, slot->id, arg->write.len, arg->write.p_data);
} else {
ret = ESP_SPP_NO_RESOURCE;
break;
}
}
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
@ -1063,37 +1095,44 @@ void btc_spp_cb_handler(btc_msg_t *msg)
}
} else {
if (slot) {
BT_HDR *p_buf;
size_t item_size = 0;
size_t items_waiting = 0;
serial = slot->serial;
if ((p_buf = fixed_queue_try_peek_first(slot->tx.queue)) == NULL) {
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
break;
}
if (p_data->rfc_write.status == BTA_JV_SUCCESS) {
p_buf->len -= p_data->rfc_write.len;
p_buf->offset += p_data->rfc_write.len;
p_buf->layer_specific = 0;
if (p_buf->len == 0) {
osi_free(fixed_queue_dequeue(slot->tx.queue, FIXED_QUEUE_MAX_TIMEOUT));
if (fixed_queue_length(slot->tx.queue) <= SLOT_TX_QUEUE_LOW_WM) {
xEventGroupSetBits(spp_local_param.tx_event_group, SLOT_WRITE_BIT(serial));
}
vRingbufferReturnItem(slot->ringbuf_write,slot->write_data);
slot->write_data = NULL;
slot->is_writing = false;
slot->write_data_len = 0;
vRingbufferGetInfo(slot->ringbuf_write, NULL, NULL, NULL, NULL, &items_waiting);
if (spp_local_param.tx_buffer_size > items_waiting) {
xEventGroupSetBits(spp_local_param.tx_event_group, SLOT_WRITE_BIT(serial));
}
if ((p_buf = fixed_queue_try_peek_first(slot->tx.queue)) != NULL && p_buf->layer_specific == 0 &&
!p_data->rfc_write.cong) {
p_buf->layer_specific = 1;
p_buf->event++;
BTA_JvRfcommWrite(p_data->rfc_write.handle, slot->id, p_buf->len, p_buf->data + p_buf->offset);
if (items_waiting == 0) {
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
break;
}
if (!p_data->rfc_write.cong) {
uint8_t *data = xRingbufferReceiveUpTo(slot->ringbuf_write, &item_size, 0, slot->mtu);
if (item_size > 0) {
slot->write_data = data;
slot->write_data_len = item_size;
slot->is_writing = true;
BTA_JvRfcommWrite(p_data->rfc_write.handle, slot->id, item_size, data);
}
}
} else {
if (!p_data->rfc_write.old_cong) {
// PORT_WriteDataCO failed
BTC_TRACE_ERROR("PORT_WriteDataCO failed p_buf:%p, handle:%d\n", p_buf,
BTC_TRACE_ERROR("PORT_WriteDataCO failed p_buf:%p, handle:%d\n", slot->write_data,
p_data->rfc_write.handle);
} else {
// need rewrite
p_buf->layer_specific = 0;
if (!p_data->rfc_write.cong && slot->connected) {
slot->is_writing = true;
BTA_JvRfcommWrite(p_data->rfc_write.handle, slot->id, slot->write_data_len, slot->write_data);
} else {
slot->is_writing = false;
}
}
}
}
@ -1185,12 +1224,19 @@ void btc_spp_cb_handler(btc_msg_t *msg)
BTC_TRACE_ERROR("%s unable to find RFCOMM slot, event:%d!", __func__, event);
break;
}
if (!p_data->rfc_cong.cong) {
BT_HDR *p_buf;
if ((p_buf = fixed_queue_try_peek_first(slot->tx.queue)) != NULL && p_buf->layer_specific == 0) {
p_buf->event++;
p_buf->layer_specific = 1;
BTA_JvRfcommWrite(p_data->rfc_cong.handle, slot->id, p_buf->len, p_buf->data + p_buf->offset);
if (!p_data->rfc_cong.cong && !slot->is_writing) {
if (slot->write_data == NULL && slot->write_data_len == 0) {
size_t item_size = 0;
uint8_t *data = xRingbufferReceiveUpTo(slot->ringbuf_write, &item_size, 0, slot->mtu);
if (item_size > 0) {
slot->write_data = data;
slot->write_data_len = item_size;
slot->is_writing = true;
BTA_JvRfcommWrite(p_data->rfc_cong.handle, slot->id, item_size, data);
}
} else {
slot->is_writing = true;
BTA_JvRfcommWrite(p_data->rfc_cong.handle, slot->id, slot->write_data_len, slot->write_data);
}
}
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
@ -1236,6 +1282,9 @@ void btc_spp_cb_handler(btc_msg_t *msg)
}
}
if (count != 0) {
osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
slot->credit_rx += count;
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
BTA_JvRfcommFlowControl(p_data->data_ind.handle, count);
BTC_TRACE_DEBUG("%s give credits:%d\n", __func__, count);
}
@ -1301,16 +1350,17 @@ int bta_co_rfc_data_incoming(void *user_data, BT_HDR *p_buf)
BTC_TRACE_DEBUG("%s data post! %d, %d", __func__, slot->rfc_handle, rx_len);
status = btc_transfer_context(&msg, &p_data, sizeof(tBTA_JV), NULL);
assert(status == BT_STATUS_SUCCESS);
} else if (fixed_queue_length(slot->rx.queue) > 2) {
BTC_TRACE_DEBUG("%s data post stop! %d %d", __func__, slot->rfc_handle, fixed_queue_length(slot->rx.queue));
ret = 0; // reserved for other flow control
}
} else {
fixed_queue_enqueue(slot->rx.queue, p_buf, FIXED_QUEUE_MAX_TIMEOUT);
if (fixed_queue_length(slot->rx.queue) > 2) {
BTC_TRACE_DEBUG("%s data post stop! %d %d", __func__, slot->rfc_handle, fixed_queue_length(slot->rx.queue));
ret = 0; // reserved for other flow control
}
}
if (--slot->credit_rx == 0) {
BTC_TRACE_DEBUG("%s data post stop! %d %d", __func__, slot->rfc_handle, fixed_queue_length(slot->rx.queue));
ret = 0; // reserved for other flow control
}
if (slot->credit_rx > BTA_JV_MAX_CREDIT_NUM) {
BTC_TRACE_WARNING("%s credit %d", __func__, slot->credit_rx);
assert(0);
}
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
return ret;
@ -1375,77 +1425,67 @@ static ssize_t spp_vfs_write(int fd, const void * data, size_t size)
serial = slot->serial;
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
ssize_t sent = 0, write_size = 0;
size_t tx_len;
BT_HDR *p_buf = NULL;
bool enqueue_status= false;
ssize_t sent = 0;
size_t items_waiting = 0;
size_t item_size = 0;
EventBits_t tx_event_group_val = 0;
while (1) {
BaseType_t done = false;
while (size) {
tx_event_group_val = 0;
if (size) {
if (p_buf == NULL) {
write_size = size < BTA_JV_DEF_RFC_MTU ? size : BTA_JV_DEF_RFC_MTU;
if ((p_buf = osi_malloc(sizeof(BT_HDR) + write_size)) == NULL) {
BTC_TRACE_ERROR("%s malloc failed!", __func__);
errno = ENOMEM;
sent = -1;
break;
}
p_buf->offset = 0;
p_buf->len = write_size;
p_buf->event = 0; // indicate the p_buf be sent count
p_buf->layer_specific = 0; // indicate the p_buf whether to be sent, 0 - ready to send; 1 - have sent
memcpy((UINT8 *)(p_buf + 1), data + sent, write_size);
}
} else {
break;
}
osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
if ((slot = spp_local_param.spp_slots[serial]) != NULL) {
tx_len = fixed_queue_length(slot->tx.queue);
enqueue_status = fixed_queue_enqueue(slot->tx.queue, p_buf, 0);
if (!enqueue_status) {
BTC_TRACE_DEBUG("%s tx_len:%d, fd:%d\n", __func__, fixed_queue_length(slot->tx.queue), fd);
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
//block untill under water level, be closed or time out
tx_event_group_val =
xEventGroupWaitBits(spp_local_param.tx_event_group, SLOT_WRITE_BIT(serial) | SLOT_CLOSE_BIT(serial), pdTRUE,
pdFALSE, VFS_WRITE_TIMEOUT / portTICK_PERIOD_MS);
if (tx_event_group_val & SLOT_CLOSE_BIT(serial)) {
BTC_TRACE_ERROR("%s exit for RFCOMM close, fd:%d!", __func__, fd);
errno = EPIPE;
sent = -1;
break;
} else if (tx_event_group_val & SLOT_WRITE_BIT(serial)) {
slot = spp_local_param.spp_slots[serial];
if (slot && slot->connected) {
items_waiting = 0;
item_size = 0;
vRingbufferGetInfo(slot->ringbuf_write, NULL, NULL, NULL, NULL, &items_waiting);
if (items_waiting < spp_local_param.tx_buffer_size) {
if ((spp_local_param.tx_buffer_size - items_waiting) > size) {
item_size = size;
done = xRingbufferSend(slot->ringbuf_write, (void *)data + sent, item_size, 0);
} else {
item_size = spp_local_param.tx_buffer_size - items_waiting;
done = xRingbufferSend(slot->ringbuf_write, (void *)data + sent, item_size, 0);
}
if (done) {
sent += item_size;
size -= item_size;
if (slot->write_data == NULL) {
spp_send_data_to_btc(slot->rfc_handle, 0, NULL, ESP_SPP_MODE_VFS);
}
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
continue;
} else if (tx_event_group_val == 0) {
BTC_TRACE_ERROR("%s exit for time out, fd:%d!", __func__, fd);
errno = EBUSY;
sent = -1;
break;
}
}
if (tx_len == 0) {
spp_send_data_to_btc(slot->rfc_handle, 0, NULL, ESP_SPP_MODE_VFS);
BTC_TRACE_DEBUG("%s items_waiting:%d, fd:%d\n", __func__, items_waiting, fd);
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
// block untill under water level, be closed or time out
tx_event_group_val =
xEventGroupWaitBits(spp_local_param.tx_event_group, SLOT_WRITE_BIT(serial) | SLOT_CLOSE_BIT(serial), pdTRUE,
pdFALSE, VFS_WRITE_TIMEOUT / portTICK_PERIOD_MS);
if (tx_event_group_val & SLOT_CLOSE_BIT(serial)) {
BTC_TRACE_ERROR("%s exit for RFCOMM close, fd:%d!", __func__, fd);
errno = EPIPE;
sent = -1;
break;
} else if (tx_event_group_val & SLOT_WRITE_BIT(serial)) {
continue;
} else if (tx_event_group_val == 0) {
BTC_TRACE_ERROR("%s exit for time out, fd:%d!", __func__, fd);
errno = EBUSY;
sent = -1;
break;
}
sent += write_size;
size -= write_size;
p_buf = NULL;
} else {
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
errno = EPIPE;
sent = -1;
break;
}
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
}
//errors occur, need to cleanup
if (p_buf) {
osi_free(p_buf);
p_buf = NULL;
}
return sent;
}
@ -1549,6 +1589,7 @@ static ssize_t spp_vfs_read(int fd, void * dst, size_t size)
}
if (count > 0) {
osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
slot->credit_rx += count;
if ((slot = spp_local_param.spp_slots[serial]) != NULL) {
BTA_JvRfcommFlowControl(slot->rfc_handle, count);
BTC_TRACE_DEBUG("%s give credits:%d\n", __func__, count);

View File

@ -1578,7 +1578,7 @@
/* ERTM Tx window size */
#ifndef RFC_FCR_OPT_TX_WINDOW_SIZE
#define RFC_FCR_OPT_TX_WINDOW_SIZE 20
#define RFC_FCR_OPT_TX_WINDOW_SIZE 10
#endif
/* ERTM Maximum transmissions before disconnecting */

View File

@ -113,8 +113,16 @@ typedef void (tPORT_MGMT_CALLBACK) (UINT32 code, UINT16 port_handle, void* data)
typedef struct {
BOOLEAN accept; /* If upper layer accepts the incoming connection */
BOOLEAN ignore_rfc_state; /* If need to ignore rfc state for PORT_CheckConnection */
UINT16 peer_mtu; /* Max MTU that port can send */
} tPORT_MGMT_SR_CALLBACK_ARG;
/**
* Define the client port manage callback function argument
*/
typedef struct {
UINT16 peer_mtu; /* Max MTU that port can send */
} tPORT_MGMT_CL_CALLBACK_ARG;
/*
** Define events that registered application can receive in the callback
*/
@ -684,6 +692,17 @@ extern UINT8 PORT_SetTraceLevel (UINT8 new_level);
*******************************************************************************/
extern const char *PORT_GetResultString (const uint8_t result_code);
/*******************************************************************************
**
** Function PORT_SetL2capErtm
**
** Description This function sets whether RFCOMM uses L2CAP ERTM.
**
** Returns void
**
*******************************************************************************/
extern void PORT_SetL2capErtm (BOOLEAN enable_l2cap_ertm);
#ifdef __cplusplus
}
#endif

View File

@ -928,6 +928,9 @@ static BOOLEAN process_reqseq (tL2C_CCB *p_ccb, UINT16 ctrl_word)
full_sdus_xmitted++;
}
osi_free(p_tmp);
if (p_ccb->cong_sent) {
l2cu_check_channel_congestion(p_ccb);
}
}
/* If we are still in a wait_ack state, do not mess with the timer */

View File

@ -3613,6 +3613,9 @@ void l2cu_set_acl_hci_header (BT_HDR *p_buf, tL2C_CCB *p_ccb)
void l2cu_check_channel_congestion (tL2C_CCB *p_ccb)
{
size_t q_count = fixed_queue_length(p_ccb->xmit_hold_q);
#if (CLASSIC_BT_INCLUDED == TRUE)
size_t q_waiting_ack_count = fixed_queue_length(p_ccb->fcrb.waiting_for_ack_q);
#endif
#if (L2CAP_UCD_INCLUDED == TRUE)
if ( p_ccb->local_cid == L2CAP_CONNECTIONLESS_CID ) {
@ -3625,7 +3628,11 @@ void l2cu_check_channel_congestion (tL2C_CCB *p_ccb)
/* If this channel was congested */
if ( p_ccb->cong_sent ) {
/* If the channel is not congested now, tell the app */
if (q_count <= (p_ccb->buff_quota / 2)) {
if (q_count <= (p_ccb->buff_quota / 2)
#if (CLASSIC_BT_INCLUDED == TRUE)
&& (p_ccb->peer_cfg.fcr.mode == L2CAP_FCR_BASIC_MODE || q_waiting_ack_count < p_ccb->our_cfg.fcr.tx_win_sz)
#endif
) {
p_ccb->cong_sent = FALSE;
if (p_ccb->p_rcb && p_ccb->p_rcb->api.pL2CA_CongestionStatus_Cb) {
L2CAP_TRACE_DEBUG ("L2CAP - Calling CongestionStatus_Cb (FALSE), CID: 0x%04x xmit_hold_q.count: %u buff_quota: %u",
@ -3664,7 +3671,11 @@ void l2cu_check_channel_congestion (tL2C_CCB *p_ccb)
} else {
tL2C_LCB *p_lcb = p_ccb->p_lcb;
/* If this channel was not congested but it is congested now, tell the app */
if (q_count > p_ccb->buff_quota || (p_lcb && (p_lcb->link_xmit_data_q) && (list_length(p_lcb->link_xmit_data_q) + q_count) > p_ccb->buff_quota)) {
if (q_count > p_ccb->buff_quota || (p_lcb && (p_lcb->link_xmit_data_q) && (list_length(p_lcb->link_xmit_data_q) + q_count) > p_ccb->buff_quota)
#if (CLASSIC_BT_INCLUDED == TRUE)
|| (p_ccb->peer_cfg.fcr.mode != L2CAP_FCR_BASIC_MODE && q_waiting_ack_count >= p_ccb->our_cfg.fcr.tx_win_sz)
#endif
) {
p_ccb->cong_sent = TRUE;
if (p_ccb->p_rcb && p_ccb->p_rcb->api.pL2CA_CongestionStatus_Cb) {
L2CAP_TRACE_DEBUG ("L2CAP - Calling CongestionStatus_Cb (TRUE),CID:0x%04x,XmitQ:%u,Quota:%u",

View File

@ -209,6 +209,7 @@ typedef struct t_port_info tPORT;
typedef struct {
tPORT port[MAX_RFC_PORTS]; /* Port info pool */
tRFC_MCB rfc_mcb[MAX_BD_CONNECTIONS]; /* RFCOMM bd_connections pool */
BOOLEAN enable_l2cap_ertm; /* enable/disable l2cap ertm */
} tPORT_CB;
#ifdef __cplusplus

View File

@ -1866,4 +1866,18 @@ const char *PORT_GetResultString (const uint8_t result_code)
return result_code_strings[result_code];
}
/*******************************************************************************
**
** Function PORT_SetL2capErtm
**
** Description This function sets whether RFCOMM uses L2CAP ERTM.
**
** Returns void
**
*******************************************************************************/
void PORT_SetL2capErtm (BOOLEAN enable_l2cap_ertm)
{
rfc_cb.port.enable_l2cap_ertm = enable_l2cap_ertm;
}
#endif ///(defined RFCOMM_INCLUDED && RFCOMM_INCLUDED == TRUE)

View File

@ -427,9 +427,11 @@ void PORT_ParNegCnf (tRFC_MCB *p_mcb, UINT8 dlci, UINT16 mtu, UINT8 cl, UINT8 k)
void PORT_DlcEstablishInd (tRFC_MCB *p_mcb, UINT8 dlci, UINT16 mtu)
{
tPORT *p_port = port_find_mcb_dlci_port (p_mcb, dlci);
tPORT_MGMT_SR_CALLBACK_ARG mgmt_cb_arg = {
tPORT_MGMT_CL_CALLBACK_ARG cl_mgmt_cb_arg = {0};
tPORT_MGMT_SR_CALLBACK_ARG sr_mgmt_cb_arg = {
.accept = TRUE,
.ignore_rfc_state = FALSE,
.peer_mtu = 0,
};
RFCOMM_TRACE_DEBUG ("PORT_DlcEstablishInd p_mcb:%p, dlci:%d mtu:%di, p_port:%p", p_mcb, dlci, mtu, p_port);
@ -464,22 +466,29 @@ void PORT_DlcEstablishInd (tRFC_MCB *p_mcb, UINT8 dlci, UINT16 mtu)
}
if (p_port->p_mgmt_callback) {
/**
* @note
* 1. The manage callback function may change the value of accept in mgmt_cb_arg.
* 2. Use mgmt_cb_arg.ignore_rfc_state to work around the issue caused by sending
* RFCOMM establish response after the manage callback function.
*/
mgmt_cb_arg.ignore_rfc_state = TRUE;
p_port->p_mgmt_callback (PORT_SUCCESS, p_port->inx, &mgmt_cb_arg);
if (p_port->is_server) {
sr_mgmt_cb_arg.peer_mtu = p_port->peer_mtu;
/**
* @note
* 1. The manage callback function may change the value of accept in mgmt_cb_arg.
* 2. Use mgmt_cb_arg.ignore_rfc_state to work around the issue caused by sending
* RFCOMM establish response after the manage callback function.
*/
sr_mgmt_cb_arg.ignore_rfc_state = TRUE;
p_port->p_mgmt_callback (PORT_SUCCESS, p_port->inx, &sr_mgmt_cb_arg);
if (!sr_mgmt_cb_arg.accept) {
RFCOMM_DlcEstablishRsp(p_mcb, dlci, 0, RFCOMM_LOW_RESOURCES);
return;
}
} else {
cl_mgmt_cb_arg.peer_mtu = p_port->peer_mtu;
p_port->p_mgmt_callback (PORT_SUCCESS, p_port->inx, &cl_mgmt_cb_arg);
}
}
if (mgmt_cb_arg.accept) {
RFCOMM_DlcEstablishRsp(p_mcb, dlci, p_port->mtu, RFCOMM_SUCCESS);
p_port->state = PORT_STATE_OPENED;
} else {
RFCOMM_DlcEstablishRsp(p_mcb, dlci, 0, RFCOMM_LOW_RESOURCES);
}
RFCOMM_DlcEstablishRsp(p_mcb, dlci, p_port->mtu, RFCOMM_SUCCESS);
p_port->state = PORT_STATE_OPENED;
}
@ -496,6 +505,8 @@ void PORT_DlcEstablishInd (tRFC_MCB *p_mcb, UINT8 dlci, UINT16 mtu)
void PORT_DlcEstablishCnf (tRFC_MCB *p_mcb, UINT8 dlci, UINT16 mtu, UINT16 result)
{
tPORT *p_port = port_find_mcb_dlci_port (p_mcb, dlci);
tPORT_MGMT_SR_CALLBACK_ARG sr_mgmt_cb_arg = {0};
tPORT_MGMT_CL_CALLBACK_ARG cl_mgmt_cb_arg = {0};
RFCOMM_TRACE_EVENT ("PORT_DlcEstablishCnf dlci:%d mtu:%d result:%d", dlci, mtu, result);
@ -522,7 +533,13 @@ void PORT_DlcEstablishCnf (tRFC_MCB *p_mcb, UINT8 dlci, UINT16 mtu, UINT16 resul
}
if (p_port->p_mgmt_callback) {
p_port->p_mgmt_callback (PORT_SUCCESS, p_port->inx, NULL);
if (p_port->is_server) {
sr_mgmt_cb_arg.peer_mtu = p_port->peer_mtu;
p_port->p_mgmt_callback (PORT_SUCCESS, p_port->inx, &sr_mgmt_cb_arg);
} else {
cl_mgmt_cb_arg.peer_mtu = p_port->peer_mtu;
p_port->p_mgmt_callback (PORT_SUCCESS, p_port->inx, &cl_mgmt_cb_arg);
}
}
p_port->state = PORT_STATE_OPENED;

View File

@ -128,8 +128,8 @@ void RFCOMM_ConnectInd (BD_ADDR bd_addr, UINT16 lcid, UINT16 psm, UINT8 id)
}
if (p_mcb == NULL) {
// L2CA_ConnectRsp (bd_addr, id, lcid, L2CAP_CONN_NO_RESOURCES, 0);
L2CA_ErtmConnectRsp (bd_addr, id, lcid, L2CAP_CONN_NO_RESOURCES, 0, &rfc_l2c_etm_opt);
tL2CAP_ERTM_INFO *ertm_opt = rfc_cb.port.enable_l2cap_ertm ? &rfc_l2c_etm_opt : NULL;
L2CA_ErtmConnectRsp (bd_addr, id, lcid, L2CAP_CONN_NO_RESOURCES, 0, ertm_opt);
return;
}
p_mcb->lcid = lcid;
@ -189,10 +189,9 @@ void RFCOMM_ConnectCnf (UINT16 lcid, UINT16 result)
} else {
RFCOMM_TRACE_DEBUG ("RFCOMM_ConnectCnf peer gave up pending LCID(0x%x)", p_mcb->pending_lcid);
tL2CAP_ERTM_INFO *ertm_opt = rfc_cb.port.enable_l2cap_ertm ? &rfc_l2c_etm_opt : NULL;
/* Peer gave up his connection request, make sure cleaning up L2CAP channel */
// L2CA_ConnectRsp (p_mcb->bd_addr, p_mcb->pending_id, p_mcb->pending_lcid, L2CAP_CONN_NO_RESOURCES, 0);
L2CA_ErtmConnectRsp (p_mcb->bd_addr, p_mcb->pending_id, p_mcb->pending_lcid, L2CAP_CONN_NO_RESOURCES, 0,
&rfc_l2c_etm_opt);
L2CA_ErtmConnectRsp (p_mcb->bd_addr, p_mcb->pending_id, p_mcb->pending_lcid, L2CAP_CONN_NO_RESOURCES, 0, ertm_opt);
p_mcb->pending_lcid = 0;
}

View File

@ -136,15 +136,20 @@ void rfc_mx_sm_execute (tRFC_MCB *p_mcb, UINT16 event, void *p_data)
*******************************************************************************/
void rfc_mx_sm_state_idle (tRFC_MCB *p_mcb, UINT16 event, void *p_data)
{
tL2CAP_ERTM_INFO *ertm_opt = NULL;
RFCOMM_TRACE_EVENT ("rfc_mx_sm_state_idle - evt:%d", event);
switch (event) {
case RFC_MX_EVENT_START_REQ:
/* Initialize L2CAP MTU */
p_mcb->peer_l2cap_mtu = L2CAP_DEFAULT_MTU - RFCOMM_MIN_OFFSET - 1;
// if ((p_mcb->lcid = L2CA_ConnectReq (BT_PSM_RFCOMM, p_mcb->bd_addr)) == 0) {
if ((p_mcb->lcid = L2CA_ErtmConnectReq (BT_PSM_RFCOMM, p_mcb->bd_addr, &rfc_l2c_etm_opt)) == 0) {
ertm_opt = rfc_cb.port.enable_l2cap_ertm ? &rfc_l2c_etm_opt : NULL;
p_mcb->lcid = L2CA_ErtmConnectReq (BT_PSM_RFCOMM, p_mcb->bd_addr, ertm_opt);
if (p_mcb->lcid == 0) {
PORT_StartCnf (p_mcb, RFCOMM_ERROR);
return;
}
@ -164,8 +169,8 @@ void rfc_mx_sm_state_idle (tRFC_MCB *p_mcb, UINT16 event, void *p_data)
case RFC_MX_EVENT_CONN_IND:
rfc_timer_start (p_mcb, RFCOMM_CONN_TIMEOUT);
// L2CA_ConnectRsp (p_mcb->bd_addr, *((UINT8 *)p_data), p_mcb->lcid, L2CAP_CONN_OK, 0);
L2CA_ErtmConnectRsp (p_mcb->bd_addr, *((UINT8 *)p_data), p_mcb->lcid, L2CAP_CONN_OK, 0, &rfc_l2c_etm_opt);
ertm_opt = rfc_cb.port.enable_l2cap_ertm ? &rfc_l2c_etm_opt : NULL;
L2CA_ErtmConnectRsp (p_mcb->bd_addr, *((UINT8 *)p_data), p_mcb->lcid, L2CAP_CONN_OK, 0, ertm_opt);
rfc_mx_send_config_req (p_mcb);
@ -502,9 +507,11 @@ void rfc_mx_sm_state_disc_wait_ua (tRFC_MCB *p_mcb, UINT16 event, void *p_data)
L2CA_DisconnectReq (p_mcb->lcid);
if (p_mcb->restart_required) {
tL2CAP_ERTM_INFO *ertm_opt = rfc_cb.port.enable_l2cap_ertm ? &rfc_l2c_etm_opt : NULL;
/* Start Request was received while disconnecting. Execute it again */
// if ((p_mcb->lcid = L2CA_ConnectReq (BT_PSM_RFCOMM, p_mcb->bd_addr)) == 0) {
if ((p_mcb->lcid = L2CA_ErtmConnectReq (BT_PSM_RFCOMM, p_mcb->bd_addr, &rfc_l2c_etm_opt)) == 0) {
p_mcb->lcid = L2CA_ErtmConnectReq(BT_PSM_RFCOMM, p_mcb->bd_addr, ertm_opt);
if (p_mcb->lcid == 0) {
PORT_StartCnf (p_mcb, RFCOMM_ERROR);
return;
}
@ -576,8 +583,10 @@ static void rfc_mx_send_config_req (tRFC_MCB *p_mcb)
cfg.mtu_present = TRUE;
cfg.mtu = L2CAP_MTU_SIZE;
cfg.fcr_present = TRUE;
cfg.fcr = rfc_l2c_fcr_opts_def;
if (rfc_cb.port.enable_l2cap_ertm) {
cfg.fcr_present = TRUE;
cfg.fcr = rfc_l2c_fcr_opts_def;
}
/* Defaults set by memset
cfg.flush_to_present = FALSE;

View File

@ -188,7 +188,8 @@ tRFC_MCB *rfc_alloc_multiplexer_channel (BD_ADDR bd_addr, BOOLEAN is_initiator)
return (NULL);
}
void osi_free_fun(void *p){
void osi_free_fun(void *p)
{
osi_free(p);
}
/*******************************************************************************

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
@ -30,6 +30,7 @@
#define SPP_SHOW_MODE SPP_SHOW_SPEED /*Choose show mode: show data or speed*/
static const esp_spp_mode_t esp_spp_mode = ESP_SPP_MODE_CB;
static const bool esp_spp_enable_l2cap_ertm = true;
static struct timeval time_new, time_old;
static long data_num = 0;
@ -241,7 +242,12 @@ void app_main(void)
return;
}
if ((ret = esp_spp_init(esp_spp_mode)) != ESP_OK) {
esp_spp_cfg_t bt_spp_cfg = {
.mode = esp_spp_mode,
.enable_l2cap_ertm = esp_spp_enable_l2cap_ertm,
.tx_buffer_size = 0, /* Only used for ESP_SPP_MODE_VFS mode */
};
if ((ret = esp_spp_enhanced_init(&bt_spp_cfg)) != ESP_OK) {
ESP_LOGE(SPP_TAG, "%s spp init failed: %s\n", __func__, esp_err_to_name(ret));
return;
}

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
@ -31,6 +31,7 @@
#define SPP_SHOW_MODE SPP_SHOW_SPEED /*Choose show mode: show data or speed*/
static const esp_spp_mode_t esp_spp_mode = ESP_SPP_MODE_CB;
static const bool esp_spp_enable_l2cap_ertm = true;
static struct timeval time_new, time_old;
static long data_num = 0;
@ -384,7 +385,12 @@ void app_main(void)
return;
}
if ((ret = esp_spp_init(esp_spp_mode)) != ESP_OK) {
esp_spp_cfg_t bt_spp_cfg = {
.mode = esp_spp_mode,
.enable_l2cap_ertm = esp_spp_enable_l2cap_ertm,
.tx_buffer_size = 0, /* Only used for ESP_SPP_MODE_VFS mode */
};
if ((ret = esp_spp_enhanced_init(&bt_spp_cfg)) != ESP_OK) {
ESP_LOGE(SPP_TAG, "%s spp init failed: %s\n", __func__, esp_err_to_name(ret));
return;
}

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
@ -38,8 +38,6 @@
#define SPP_SERVER_NAME "SPP_SERVER"
#define EXAMPLE_DEVICE_NAME "ESP_SPP_ACCEPTOR"
static const esp_spp_mode_t esp_spp_mode = ESP_SPP_MODE_VFS;
static const esp_spp_sec_t sec_mask = ESP_SPP_SEC_AUTHENTICATE;
static const esp_spp_role_t role_slave = ESP_SPP_ROLE_SLAVE;
@ -250,7 +248,8 @@ void app_main(void)
spp_task_task_start_up();
if (esp_spp_init(esp_spp_mode) != ESP_OK) {
esp_spp_cfg_t bt_spp_cfg = BT_SPP_DEFAULT_CONFIG();
if (esp_spp_enhanced_init(&bt_spp_cfg) != ESP_OK) {
ESP_LOGE(SPP_TAG, "%s spp init failed", __func__);
return;
}

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
@ -37,8 +37,6 @@
#define SPP_TAG "SPP_INITIATOR_DEMO"
#define EXAMPLE_DEVICE_NAME "ESP_SPP_INITIATOR"
static const esp_spp_mode_t esp_spp_mode = ESP_SPP_MODE_VFS;
static const esp_spp_sec_t sec_mask = ESP_SPP_SEC_AUTHENTICATE;
static const esp_spp_role_t role_master = ESP_SPP_ROLE_MASTER;
@ -332,7 +330,9 @@ void app_main(void)
}
spp_task_task_start_up();
if (esp_spp_init(esp_spp_mode) != ESP_OK) {
esp_spp_cfg_t bt_spp_cfg = BT_SPP_DEFAULT_CONFIG();
if (esp_spp_enhanced_init(&bt_spp_cfg) != ESP_OK) {
ESP_LOGE(SPP_TAG, "%s spp init failed", __func__);
return;
}