Fork ESP-IDF's bluetooth component

i want better sbc encoding, and no cla will stop me
This commit is contained in:
jacqueline
2024-03-28 14:32:49 +11:00
parent 239e6d8950
commit ee29c25b29
1761 changed files with 737738 additions and 0 deletions
@@ -0,0 +1,334 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdint.h>
#include <string.h>
#include <stdbool.h>
#include <stdio.h>
#include "common/bt_target.h"
#include "common/bt_trace.h"
#include "stack/bt_types.h"
#include "stack/gatt_api.h"
#include "bta/bta_api.h"
#include "bta/bta_gatt_api.h"
#include "bta_gatts_int.h"
#include "button_pro.h"
#include "prf_defs.h"
#if (BUT_PROFILE_CFG)
#define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0]))
button_env_cb_t button_cb_env;
/*****************************************************************************
** Constants
*****************************************************************************/
static void button_profile_cb(esp_gatts_evt_t event, esp_gatts_t *p_data);
/*******************************************************************************
**
** Function button_profile_cb
**
** Description the callback function after the profile has been register to the BTA manager module
**
** Returns NULL
**
*******************************************************************************/
static void button_profile_cb(esp_gatts_evt_t event, esp_gatts_t *p_data)
{
esp_gatts_rsp_t rsp;
esp_bt_uuid_t uuid = {LEN_UUID_16, {ATT_SVC_BUTTON}};
but_inst_t *p_inst = &button_cb_env.button_inst;
uint8_t net_event = 0xff;
uint8_t len = 0;
uint8_t *p_rec_data = NULL;
//BTC_TRACE_ERROR("p_data->status = %x\n",p_data->status);
//if(p_data->status != BTA_GATT_OK){
// BTC_TRACE_ERROR("button profile register failed\n");
// return;
//}
BTC_TRACE_ERROR("button profile cb event = %x\n", event);
switch (event) {
case ESP_GATTS_REG_EVT:
BTC_TRACE_ERROR("p_data->reg_oper.status = %x\n", p_data->reg_oper.status);
BTC_TRACE_ERROR("(p_data->reg_oper.uuid.uu.uuid16=%x\n", p_data->reg_oper.uuid.uu.uuid16);
if (p_data->reg_oper.status != BTA_GATT_OK) {
BTC_TRACE_ERROR("button profile register failed\n");
}
button_cb_env.gatt_if = p_data->reg_oper.server_if;
button_cb_env.enabled = true;
//button_cb_env.button_inst.app_id = p_data->reg_oper.uuid;
//create the button service to the service data base.
if (p_data->reg_oper.uuid.uu.uuid16 == ATT_SVC_BUTTON) {
Button_CreateService();
}
break;
case ESP_GATTS_READ_EVT:
//tBTA_GATTS_RSP rsp;
memset(&rsp, 0, sizeof(tBTA_GATTS_API_RSP));
rsp.attr_value.handle = p_data->req_data.p_data->read_req.handle;
rsp.attr_value.len = 2;
esp_ble_gatts_send_rsp(p_data->req_data.conn_id, p_data->req_data.trans_id,
p_data->req_data.status, &rsp);
break;
case ESP_GATTS_WRITE_EVT:
esp_ble_gatts_send_rsp(p_data->req_data.conn_id, p_data->req_data.trans_id,
p_data->req_data.status, NULL);
BTC_TRACE_ERROR("Received button data:");
for (int i = 0; i < p_data->req_data.p_data->write_req.len; i++) {
BTC_TRACE_ERROR("%x", p_data->req_data.p_data->write_req.value[i]);
}
BTC_TRACE_ERROR("\n");
if (p_data->req_data.p_data->write_req.handle == button_cb_env.button_inst.but_wirt_hdl) {
p_rec_data = &p_data->req_data.p_data->write_req.value[0];
// button_msg_notify(len,p_rec_data);
(*p_inst->p_cback)(button_cb_env.button_inst.app_id, net_event, len, p_rec_data);
}
break;
case ESP_GATTS_CFM_EVT:
break;
case ESP_GATTS_CREATE_EVT:
//tBT_UUID uuid_butt_write;
uuid.uu.uuid16 = ATT_CHAR_BUTTON_WIT;
//tBTA_GATT_PERM perm = (GATT_PERM_WRITE|GATT_PERM_READ);
//tBTA_GATT_CHAR_PROP prop = (GATT_CHAR_PROP_BIT_READ|GATT_CHAR_PROP_BIT_WRITE);
//uuid = {LEN_UUID_16, {ATT_SVC_BUTTON}};
button_cb_env.clcb.cur_srvc_id = p_data->create.service_id;
button_cb_env.is_primery = p_data->create.is_primary;
//uuid = {LEN_UUID_16, {ATT_CHAR_BUTTON_WIT}};
//start the button service after created
esp_ble_gatts_start_srvc(p_data->create.service_id);
//add the frist button characteristic --> write characteristic
esp_ble_gatts_add_char(button_cb_env.clcb.cur_srvc_id, &uuid,
(GATT_PERM_WRITE | GATT_PERM_READ),
(GATT_CHAR_PROP_BIT_READ | GATT_CHAR_PROP_BIT_WRITE));
break;
case ESP_GATTS_ADD_CHAR_EVT:
if (p_data->add_result.char_uuid.uu.uuid16 == ATT_CHAR_BUTTON_WIT) {
uuid.uu.uuid16 = ATT_CHAR_BUTTON_NTF;
//tBTA_GATT_PERM perm = GATT_PERM_READ;
tBTA_GATT_CHAR_PROP prop = (GATT_CHAR_PROP_BIT_READ | GATT_CHAR_PROP_BIT_NOTIFY);
//save the att handle to the env
button_cb_env.button_inst.but_wirt_hdl = p_data->add_result.attr_id;
//add the frist button characteristic --> Notify characteristic
esp_ble_gatts_add_char(button_cb_env.clcb.cur_srvc_id, &uuid,
GATT_PERM_READ, (GATT_CHAR_PROP_BIT_READ | GATT_CHAR_PROP_BIT_NOTIFY));
} else if (p_data->add_result.char_uuid.uu.uuid16 == ATT_CHAR_BUTTON_NTF) { // add the gattc config descriptor to the notify charateristic
//tBTA_GATT_PERM perm = (GATT_PERM_WRITE|GATT_PERM_WRITE);
uuid.uu.uuid16 = GATT_UUID_CHAR_CLIENT_CONFIG;
button_cb_env.button_inst.but_ntf_hdl = p_data->add_result.attr_id;
esp_ble_gatts_add_char_descr (button_cb_env.clcb.cur_srvc_id,
(GATT_PERM_WRITE | GATT_PERM_WRITE),
&uuid);
}
break;
case ESP_GATTS_ADD_CHAR_DESCR_EVT:
if (p_data->add_result.char_uuid.uu.uuid16 == GATT_UUID_CHAR_CLIENT_CONFIG) {
button_cb_env.button_inst.but_cfg_hdl = p_data->add_result.attr_id;
}
///Start advertising
BTC_TRACE_ERROR("\n*******Start sent the ADV.*************\n");
//esp_ble_start_advertising (&adv_params);
//BTA_GATTS_Listen(button_cb_env.gatt_if, true, NULL);
break;
case ESP_GATTS_CONNECT_EVT:
BTC_TRACE_ERROR("############BUTTON CONNCET EVT################\n");
//esp_ble_stop_advertising();
//set the connection flag to true
button_env_clcb_alloc(p_data->conn.conn_id, p_data->conn.remote_bda);
break;
case ESP_GATTS_DISCONNECT_EVT:
//set the connection flag to true
button_cb_env.clcb.connected = false;
break;
case ESP_GATTS_OPEN_EVT:
///stop the advertising after connected
break;
case ESP_GATTS_CLOSE_EVT:
if (button_cb_env.clcb.connected && (button_cb_env.clcb.conn_id == p_data->conn.conn_id)) {
//set the connection channal congested flag to true
button_cb_env.clcb.congest = p_data->congest.congested;
}
break;
case ESP_GATTS_CONGEST_EVT:
break;
default:
break;
}
}
/*******************************************************************************
**
** Function Button_CreateService
**
** Description Create a Service for the button profile
**
** Returns NULL
**
*******************************************************************************/
void Button_CreateService(void)
{
esp_gatts_if_t server_if ;
esp_bt_uuid_t uuid = {LEN_UUID_16, {ATT_SVC_BUTTON}};
uint16_t num_handle = KEY_IDX_NB;
uint8_t inst = 0x00;
server_if = button_cb_env.gatt_if;
button_cb_env.inst_id = inst;
//if(!button_cb_env.enabled)
//{
// BTC_TRACE_ERROR("button service added error.");
//}
esp_ble_gatts_create_srvc(server_if, &uuid, inst, num_handle, true);
}
/*******************************************************************************
**
** Function button_env_clcb_alloc
**
** Description The function allocates a GATT profile connection link control block
**
** Returns NULL if not found. Otherwise pointer to the connection link block.
**
*******************************************************************************/
but_clcb_t *button_env_clcb_alloc (uint16_t conn_id, BD_ADDR remote_bda)
{
but_clcb_t *p_clcb = NULL;
p_clcb = &button_cb_env.clcb;
if (!p_clcb->in_use) {
p_clcb->in_use = TRUE;
p_clcb->conn_id = conn_id;
BTC_TRACE_ERROR("p_clcb->conn_id = %x\n", conn_id);
p_clcb->connected = TRUE;
memcpy(p_clcb->remote_bda, remote_bda, BD_ADDR_LEN);
}
return p_clcb;
}
/*******************************************************************************
**
** Function button_env_find_conn_id_by_bd_adddr
**
** Description The function searches all LCB with macthing bd address
**
** Returns total number of clcb found.
**
*******************************************************************************/
uint16_t button_env_find_conn_id_by_bd_adddr(BD_ADDR remote_bda)
{
uint8_t i_clcb;
but_clcb_t *p_clcb = NULL;
for (i_clcb = 0, p_clcb = &button_cb_env.clcb; i_clcb < BUTT_MAX_APPS; i_clcb++, p_clcb++) {
if (p_clcb->in_use && p_clcb->connected && memcmp(p_clcb->remote_bda, remote_bda, BD_ADDR_LEN)) {
return p_clcb->conn_id;
}
}
return GATT_INVALID_CONN_ID;
}
/*******************************************************************************
**
** Function button_env_clcb_dealloc
**
** Description The function deallocates a GATT profile connection link control block
**
** Returns True the deallocation is successful
**
*******************************************************************************/
BOOLEAN button_env_clcb_dealloc(uint16_t conn_id)
{
uint16_t i_clcb = 0;
but_clcb_t *p_clcb = NULL;
for (i_clcb = 0, p_clcb = &button_cb_env.clcb; i_clcb < 1; i_clcb++, p_clcb++) {
if (p_clcb->in_use && p_clcb->connected && (p_clcb->conn_id == conn_id)) {
memset(p_clcb, 0, sizeof(but_clcb_t));
return TRUE;
}
}
return FALSE;
}
/*******************************************************************************
**
** Function button_init
**
** Description Initializa the GATT Service for button profiles.
**
*******************************************************************************/
esp_gatt_status_t button_init (but_prf_cb_t call_back)
{
tBT_UUID app_uuid = {LEN_UUID_16, {ATT_SVC_BUTTON}};
BTC_TRACE_ERROR("\n=============================button_init==============================================\n");
if (button_cb_env.enabled) {
BTC_TRACE_ERROR("button svc already initaliezd\n");
return ESP_GATT_ERROR;
} else {
memset(&button_cb_env, 0, sizeof(button_env_cb_t));
}
if (call_back != NULL) {
button_cb_env.button_inst.p_cback = call_back;
}
/* register the button profile to the BTA_GATTS module*/
esp_ble_gatts_app_register(&app_uuid, button_profile_cb);
button_cb_env.enabled = TRUE;
return ESP_GATT_OK;
}
void button_disable(uint16_t connid)
{
button_env_clcb_dealloc(connid);
}
void button_msg_notify(uint16_t len, uint8_t *button_msg)
{
BOOLEAN conn_status = button_cb_env.clcb.connected;
uint16_t conn_id = button_cb_env.clcb.conn_id;
uint16_t attr_id = button_cb_env.button_inst.but_ntf_hdl;
//notify rsp==false; indicate rsp==true.
BOOLEAN rsp = false;
if (!conn_status && button_cb_env.clcb.congest) {
BTC_TRACE_ERROR("the conneciton for button profile has been loss\n");
return;
}
esp_ble_gatts_hdl_val_indica (conn_id, attr_id, len,
button_msg, rsp);
}
#endif ///BUT_PROFILE_CFG
@@ -0,0 +1,112 @@
#include "prf_defs.h"
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#if (BUT_PROFILE_CFG)
#include "common/bt_target.h"
#include "stack/gatt_api.h"
#include "stack/gattdefs.h"
#include "esp_gatt_api.h"
#define KEY_SUCCESS GATT_SUCCESS
#define KEY_ILLEGAL_PARAM GATT_ILLEGAL_PARAMETER
#define KEY_NO_RESOURCES GATT_NO_RESOURCES
//define the key serivce uuid
#define ATT_SVC_BUTTON 0xFFFF
//define the key Char uuid
#define ATT_CHAR_BUTTON_WIT 0xFF01
#define ATT_CHAR_BUTTON_NTF 0xFF02
#define BUTTON_PRESS_NTF_CFG 0x01
#define BUTTON_VAL_MAX_LEN (10)
#define BUTT_MAX_APPS GATT_CL_MAX_LCB
#define BUT_MAX_STRING_DATA 7
typedef void (*but_prf_cb_t)(uint8_t app_id, uint8_t event, uint16_t len, uint8_t *value);
#ifndef BUT_MAX_INT_NUM
#define BUT_MAX_INT_NUM 4
#endif
enum {
RECEIVE_NET_PASSWD_EVT,
RECEIVE_NET_SSD_EVT,
RECEIVE_EVT_MAX
};
/// button Service Attributes Indexes
enum {
KEY_IDX_SVC,
KEY_IDX_BUTTON_WIT_CHAR,
KEY_IDX_BUTTON_WIT_VAL,
KEY_IDX_BUTTON_NTF_CHAR,
KEY_IDX_BUTTON_NTF_VAL,
KEY_IDX_BUTTON_NTF_CFG,
KEY_IDX_NB,
};
typedef struct {
BD_ADDR remote_bda;
BOOLEAN need_rsp;
uint16_t clt_cfg;
} but_write_data_t;
typedef struct {
BOOLEAN in_use;
BOOLEAN congest;
uint16_t conn_id;
BOOLEAN connected;
BD_ADDR remote_bda;
uint32_t trans_id;
uint8_t cur_srvc_id;
} but_clcb_t;
typedef struct {
uint8_t app_id;
uint16_t but_wirt_hdl;
uint16_t but_ntf_hdl;
uint16_t but_cfg_hdl;
but_prf_cb_t p_cback;
} but_inst_t;
/* service engine control block */
typedef struct {
but_clcb_t clcb; /* connection link*/
esp_gatt_if_t gatt_if;
BOOLEAN enabled;
BOOLEAN is_primery;
but_inst_t button_inst;
uint8_t inst_id;
} button_env_cb_t;
void Button_CreateService(void);
but_clcb_t *button_env_clcb_alloc(uint16_t conn_id, BD_ADDR bda);
uint16_t button_env_find_conn_id_by_bd_adddr(BD_ADDR bda);
BOOLEAN button_env_clcb_dealloc(uint16_t conn_id);
esp_gatt_status_t button_init(but_prf_cb_t call_back);
void button_disable(uint16_t connid);
void button_msg_notify(uint16_t len, uint8_t *button_msg);
extern button_env_cb_t button_cb_env;
#endif ///BUT_PROFILE_CFG
@@ -0,0 +1,102 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "prf_defs.h"
#if (WX_AIRSYNC_CFG)
#include "common/bt_target.h"
#include "stack/gatt_api.h"
#include "stack/gattdefs.h"
#include "bt_app_api.h"
/// Maximum Transmission Unit
#define ATT_DEFAULT_MTU (23)
#define BLE_WECHAT_MAX_DATA_LEN (ATT_DEFAULT_MTU - 3)
//define the key serivce uuid
#define ATT_SVC_AIRSYNC 0xFEE7
//define the airsync Char uuid
#define ATT_CHAR_AIRSYNC_WIT 0xFEC7
#define ATT_CHAR_AIRSYBC_NTF 0xFEC8
#define ATT_CHAR_AIRSYNC_READ 0xFEC9
typedef void (tAIRSYNC_CBACK)(UINT8 app_id, UINT8 event, UINT8 len, UINT8 *data);
/// WX AirSync Service Attributes Indexes
enum {
WX_IDX_SVC,
WX_IDX_AIRSYNC_WIT_CHAR,
WX_IDX_AIRSYNC_WIT_VAL,
WX_IDX_AIRSYNC_NTF_CHAR,
WX_IDX_AIRSYNC_NTF_VAL,
WX_IDX_AIRSYNC_READ_CHAR,
WX_IDX_AIRSYNC_READ_VAL,
WX_IDX_AIRSYNC_NTF_CFG,
WX_IDX_NB,
};
typedef struct {
BD_ADDR remote_bda;
BOOLEAN need_rsp;
UINT16 clt_cfg;
} tAirSync_WRITE_DATA;
typedef struct {
BOOLEAN in_use;
BOOLEAN congest;
UINT16 conn_id;
BOOLEAN connected;
BD_ADDR remote_bda;
UINT32 trans_id;
UINT8 cur_srvc_id;
} tAirSync_CLCB;
typedef struct {
UINT8 app_id;
UINT16 airsync_wirt_hdl;
UINT16 airsync_ntf_hdl;
UINT16 airsync_read_hdl;
UINT16 airsync_cfg_hdl;
tAIRSYNC_CBACK *p_cback;
} tAirSync_INST;
/* service engine control block */
typedef struct {
tAirSync_CLCB clcb; /* connection link*/
tGATT_IF gatt_if;
BOOLEAN enabled;
BOOLEAN is_primery;
tAirSync_INST airsync_inst;
UINT8 inst_id;
} tAIRSYNC_CB_ENV;
void AirSync_CreateService(void);
tAirSync_CLCB *airsync_env_clcb_alloc (UINT16 conn_id, BD_ADDR remote_bda);
UINT16 AirSync_env_find_conn_id_by_bd_adddr(BD_ADDR bda);
BOOLEAN AirSync_env_clcb_dealloc(UINT16 conn_id);
tGATT_STATUS AirSync_Init(tAIRSYNC_CBACK *call_back);
void AirSync_msg_notify(UINT8 len, UINT8 *button_msg);
extern tAIRSYNC_CB_ENV airsync_cb_env;
#endif ///WX_AIRSYNC_CFG
@@ -0,0 +1,263 @@
#include "wx_airsync_prf.h"
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#if (WX_AIRSYNC_CFG)
#include <stdint.h>
#include <string.h>
#include <stdbool.h>
#include <stdio.h>
#include "common/bt_target.h"
#include "common/bt_trace.h"
#include "stack/bt_types.h"
#include "stack/gatt_api.h"
#include "bta/bta_api.h"
#include "bta/bta_gatt_api.h"
#include "bta_gatts_int.h"
tAIRSYNC_CB_ENV airsync_cb_env;
/*****************************************************************************
** Constants
*****************************************************************************/
static void airsync_profile_cb(esp_gatts_evt_t event, esp_gatts_t *p_data);
/*******************************************************************************
**
** Function airsync_profile_cb
**
** Description the callback function after the profile has been register to the BTA manager module
**
** Returns NULL
**
*******************************************************************************/
static void airsync_profile_cb(esp_gatts_evt_t event, esp_gatts_t *p_data)
{
esp_gatts_rsp_t rsp;
esp_bt_uuid_t uuid = {LEN_UUID_16, {ATT_SVC_AIRSYNC}};
tAirSync_INST *p_inst = &airsync_cb_env.airsync_inst;
BTC_TRACE_ERROR("airsync profile cb event = %x\n", event);
switch (event) {
case ESP_GATTS_REG_EVT:
if (p_data->reg_oper.status != BTA_GATT_OK) {
BTC_TRACE_ERROR("button profile register failed\n");
}
airsync_cb_env.gatt_if = p_data->reg_oper.server_if;
airsync_cb_env.enabled = true;
if (p_data->reg_oper.uuid.uu.uuid16 == ATT_SVC_AIRSYNC) {
AirSync_CreateService();
}
break;
case ESP_GATTS_READ_EVT:
if (airsync_cb_env.clcb.connected && airsync_cb_env.enabled) {
//tBTA_GATTS_RSP rsp;
memset(&rsp, 0, sizeof(tBTA_GATTS_API_RSP));
rsp.attr_value.handle = p_data->req_data.p_data->read_req.handle;
rsp.attr_value.len = 2;
esp_ble_gatts_send_rsp(p_data->req_data.conn_id, p_data->req_data.trans_id,
p_data->req_data.status, &rsp);
}
break;
case ESP_GATTS_WRITE_EVT:
if (airsync_cb_env.clcb.connected && airsync_cb_env.enabled) {
esp_ble_gatts_send_rsp(p_data->req_data.conn_id, p_data->req_data.trans_id,
p_data->req_data.status, NULL);
}
break;
case ESP_GATTS_CFM_EVT:
break;
case ESP_GATTS_CREATE_EVT:
uuid.uu.uuid16 = ATT_CHAR_AIRSYNC_WIT;
airsync_cb_env.clcb.cur_srvc_id = p_data->create.service_id;
airsync_cb_env.is_primery = p_data->create.is_primary;
//start the airsync service after created
esp_ble_gatts_start_srvc(p_data->create.service_id);
//add the frist airsync characteristic --> write characteristic
esp_ble_gatts_add_char(airsync_cb_env.clcb.cur_srvc_id, &uuid,
(GATT_PERM_WRITE | GATT_PERM_READ),
(GATT_CHAR_PROP_BIT_READ | GATT_CHAR_PROP_BIT_WRITE));
break;
case ESP_GATTS_ADD_CHAR_EVT:
if (p_data->add_result.char_uuid.uu.uuid16 == ATT_CHAR_AIRSYNC_WIT) {
uuid.uu.uuid16 = ATT_CHAR_AIRSYBC_NTF;
//tBTA_GATT_PERM perm = GATT_PERM_READ;
//tBTA_GATT_CHAR_PROP prop = (GATT_CHAR_PROP_BIT_READ|GATT_CHAR_PROP_BIT_NOTIFY);
//save the att handle to the env
airsync_cb_env.airsync_inst.airsync_wirt_hdl = p_data->add_result.attr_id;
//add the second airsync characteristic --> Notify characteristic
esp_ble_gatts_add_char(airsync_cb_env.clcb.cur_srvc_id, &uuid,
GATT_PERM_READ, (GATT_CHAR_PROP_BIT_READ | GATT_CHAR_PROP_BIT_INDICATE));
} else if (p_data->add_result.char_uuid.uu.uuid16 == ATT_CHAR_AIRSYBC_NTF) {
//tBTA_GATT_PERM perm = (GATT_PERM_WRITE|GATT_PERM_WRITE);
uuid.uu.uuid16 = GATT_UUID_CHAR_CLIENT_CONFIG;
airsync_cb_env.airsync_inst.airsync_ntf_hdl = p_data->add_result.attr_id;
esp_ble_gatts_add_char_descr (airsync_cb_env.clcb.cur_srvc_id,
(GATT_PERM_WRITE | GATT_PERM_WRITE),
&uuid);
uuid.uu.uuid16 = ATT_CHAR_AIRSYNC_READ;
//add the third airsync characteristic --> Read characteristic
esp_ble_gatts_add_char(airsync_cb_env.clcb.cur_srvc_id, &uuid,
GATT_PERM_READ,
GATT_CHAR_PROP_BIT_READ);
} else if (p_data->add_result.char_uuid.uu.uuid16 == ATT_CHAR_AIRSYNC_READ) {
airsync_cb_env.airsync_inst.airsync_read_hdl = p_data->add_result.attr_id;
}
break;
case ESP_GATTS_ADD_CHAR_DESCR_EVT:
if (p_data->add_result.char_uuid.uu.uuid16 == GATT_UUID_CHAR_CLIENT_CONFIG) {
airsync_cb_env.airsync_inst.airsync_cfg_hdl = p_data->add_result.attr_id;
}
break;
case ESP_GATTS_CONNECT_EVT:
//set the connection flag to true
airsync_env_clcb_alloc(p_data->conn.conn_id, p_data->conn.remote_bda);
break;
case ESP_GATTS_DISCONNECT_EVT:
//set the connection flag to true
airsync_cb_env.clcb.connected = false;
break;
case ESP_GATTS_OPEN_EVT:
break;
case ESP_GATTS_CLOSE_EVT:
if (airsync_cb_env.clcb.connected && (airsync_cb_env.clcb.conn_id == p_data->conn.conn_id)) {
//set the connection channal congested flag to true
airsync_cb_env.clcb.congest = p_data->congest.congested;
}
break;
case ESP_GATTS_CONGEST_EVT:
//set the congest flag
airsync_cb_env.clcb.congest = p_data->congest.congested;
break;
default:
break;
}
}
/*******************************************************************************
**
** Function AirSync_CreateService
**
** Description Create a Service for the airsync profile
**
** Returns NULL
**
*******************************************************************************/
void AirSync_CreateService(void)
{
esp_gatts_if_t server_if ;
esp_bt_uuid_t uuid = {LEN_UUID_16, {ATT_SVC_AIRSYNC}};
UINT16 num_handle = WX_IDX_NB;
UINT8 inst = 0x00;
server_if = airsync_cb_env.gatt_if;
airsync_cb_env.inst_id = inst;
esp_ble_gatts_create_srvc(server_if, &uuid, inst, num_handle, true);
}
/*******************************************************************************
**
** Function airsync_env_clcb_alloc
**
** Description The function allocates a GATT profile connection link control block
**
** Returns NULL if not found. Otherwise pointer to the connection link block.
**
*******************************************************************************/
tAirSync_CLCB *airsync_env_clcb_alloc (UINT16 conn_id, BD_ADDR remote_bda)
{
tAirSync_CLCB *p_clcb = NULL;
p_clcb = &airsync_cb_env.clcb;
if (!p_clcb->in_use) {
p_clcb->in_use = TRUE;
p_clcb->conn_id = conn_id;
BTC_TRACE_ERROR("p_clcb->conn_id = %x\n", conn_id);
p_clcb->connected = TRUE;
memcpy(p_clcb->remote_bda, remote_bda, BD_ADDR_LEN);
}
return p_clcb;
}
/*******************************************************************************
**
** Function airsync_env_find_conn_id_by_bd_adddr
**
** Description The function searches all LCB with macthing bd address
**
** Returns total number of clcb found.
**
*******************************************************************************/
UINT16 airsync_env_find_conn_id_by_bd_adddr(BD_ADDR remote_bda)
{
UINT8 i_clcb;
tAirSync_CLCB *p_clcb = NULL;
for (i_clcb = 0, p_clcb = &airsync_cb_env.clcb; i_clcb < 1; i_clcb++, p_clcb++) {
if (p_clcb->in_use && p_clcb->connected && memcmp(p_clcb->remote_bda, remote_bda, BD_ADDR_LEN)) {
return p_clcb->conn_id;
}
}
return GATT_INVALID_CONN_ID;
}
/*******************************************************************************
**
** Function airsync_init
**
** Description Initializa the GATT Service for airsync profiles.
**
*******************************************************************************/
tGATT_STATUS AirSync_Init(tAIRSYNC_CBACK *call_back)
{
esp_bt_uuid_t app_uuid = {LEN_UUID_16, {ATT_SVC_AIRSYNC}};
if (airsync_cb_env.enabled) {
BTC_TRACE_ERROR("airsync svc already initaliezd\n");
return ESP_GATT_ERROR;
} else {
memset(&airsync_cb_env, 0, sizeof(tAIRSYNC_CB_ENV));
}
if (call_back != NULL) {
airsync_cb_env.airsync_inst.p_cback = call_back;
}
/* register the airsync profile to the BTA_GATTS module*/
esp_ble_gatts_app_register(&app_uuid, airsync_profile_cb);
airsync_cb_env.enabled = TRUE;
return ESP_GATT_OK;
}
#endif ///WX_AIRSYNC_CFG
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,146 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/*****************************************************************************
*
* Filename: btc_a2dp.c
*
*****************************************************************************/
#include "common/bt_target.h"
#include "common/bt_trace.h"
#include "bta/bta_api.h"
#include "bta/bta_av_api.h"
#include "btc_av.h"
#include "btc_av_co.h"
#include "btc_a2dp.h"
#include "btc_a2dp_control.h"
#include "btc_a2dp_sink.h"
#include "btc_a2dp_source.h"
#if BTC_AV_INCLUDED
/*****************************************************************************
**
** Function btc_a2dp_on_init
**
*******************************************************************************/
void btc_a2dp_on_init(void)
{
BTC_TRACE_EVENT("A2DP Initialized.");
}
/*****************************************************************************
**
** Function btc_a2dp_on_idle
**
*******************************************************************************/
void btc_a2dp_on_idle(void)
{
APPL_TRACE_EVENT("## ON A2DP IDLE ## peer_sep = %d, service id = %d", btc_av_get_peer_sep(),
btc_av_get_service_id());
#if BTC_AV_SRC_INCLUDED
if (btc_av_get_peer_sep() == AVDT_TSEP_SNK && btc_av_get_service_id() == BTA_A2DP_SOURCE_SERVICE_ID) {
btc_a2dp_source_on_idle();
}
#endif // BTC_AV_SRC_INCLUDED
bta_av_co_init();
#if BTC_AV_SINK_INCLUDED
if (btc_av_get_peer_sep() == AVDT_TSEP_SRC && btc_av_get_service_id() == BTA_A2DP_SINK_SERVICE_ID) {
btc_a2dp_sink_on_idle();
}
#endif // BTC_AV_SINK_INCLUDED
}
/*****************************************************************************
**
** Function btc_a2dp_on_started
**
** Description
**
** Returns
**
*******************************************************************************/
BOOLEAN btc_a2dp_on_started(tBTA_AV_START *p_av, BOOLEAN pending_start)
{
BOOLEAN ack = FALSE;
APPL_TRACE_EVENT("## ON A2DP STARTED ##");
#if BTC_AV_SRC_INCLUDED
if (p_av == NULL) {
/* ack back a local start request */
btc_a2dp_control_command_ack(ESP_A2D_MEDIA_CTRL_ACK_SUCCESS);
return TRUE;
}
if (p_av->status == BTA_AV_SUCCESS) {
if (p_av->suspending == FALSE) {
if (p_av->initiator) {
if (pending_start) {
btc_a2dp_control_command_ack(ESP_A2D_MEDIA_CTRL_ACK_SUCCESS);
ack = TRUE;
}
} else {
/* we were remotely started, make sure codec
is setup before datapath is started */
btc_a2dp_source_setup_codec();
}
/* media task is autostarted upon a2dp audiopath connection */
}
} else if (pending_start) {
btc_a2dp_control_command_ack(ESP_A2D_MEDIA_CTRL_ACK_FAILURE);
ack = TRUE;
}
#endif /* BTC_AV_SRC_INCLUDED */
return ack;
}
/*****************************************************************************
**
** Function btc_a2dp_on_stopped
**
*******************************************************************************/
void btc_a2dp_on_stopped(tBTA_AV_SUSPEND *p_av)
{
APPL_TRACE_EVENT("## ON A2DP STOPPED ##");
#if BTC_AV_SINK_INCLUDED
if (btc_av_get_peer_sep() == AVDT_TSEP_SRC && btc_av_get_service_id() == BTA_A2DP_SINK_SERVICE_ID) {
btc_a2dp_sink_on_stopped(p_av);
return;
}
#endif // BTC_AV_SINK_INCLUDED
#if BTC_AV_SRC_INCLUDED
btc_a2dp_source_on_stopped(p_av);
#endif // BTC_AV_SRC_INCLUDED
}
/*****************************************************************************
**
** Function btc_a2dp_on_suspended
**
*******************************************************************************/
void btc_a2dp_on_suspended(tBTA_AV_SUSPEND *p_av)
{
APPL_TRACE_EVENT("## ON A2DP SUSPENDED ##");
#if BTC_AV_SINK_INCLUDED
if (btc_av_get_peer_sep() == AVDT_TSEP_SRC && btc_av_get_service_id() == BTA_A2DP_SINK_SERVICE_ID) {
btc_a2dp_sink_on_suspended(p_av);
return;
}
#endif // BTC_AV_SINK_INCLUDED
#if BTC_AV_SRC_INCLUDED
btc_a2dp_source_on_suspended(p_av);
#endif // BTC_AV_SRC_INCLUDED
}
#endif /* #if BTC_AV_INCLUDED */
@@ -0,0 +1,189 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/*****************************************************************************
*
* Filename: btc_a2dp_control.c
*
*****************************************************************************/
#include "common/bt_target.h"
#include <string.h>
#include "common/bt_trace.h"
#include "bta/bta_api.h"
#include "bta/bta_av_api.h"
#include "btc/btc_manage.h"
#include "btc_av.h"
#include "btc_a2dp.h"
#include "btc_a2dp_control.h"
#include "btc_a2dp_sink.h"
#include "btc_a2dp_source.h"
#include "esp_a2dp_api.h"
#if BTC_AV_INCLUDED
typedef struct {
BOOLEAN data_channel_open; /* used only by A2DP sink */
UINT8 a2dp_cmd_pending; /* we can have max one command pending */
} tBTC_AA_CTRL_CB;
static tBTC_AA_CTRL_CB btc_aa_ctrl_cb;
static inline void btc_a2d_cb_to_app(esp_a2d_cb_event_t event, esp_a2d_cb_param_t *param)
{
esp_a2d_cb_t btc_a2d_cb = (esp_a2d_cb_t)btc_profile_cb_get(BTC_PID_A2DP);
if (btc_a2d_cb) {
btc_a2d_cb(event, param);
}
}
static inline void a2dp_cmd_acknowledge(int cmd, int status)
{
esp_a2d_cb_param_t param;
param.media_ctrl_stat.cmd = cmd;
param.media_ctrl_stat.status = status;
btc_a2d_cb_to_app(ESP_A2D_MEDIA_CTRL_ACK_EVT, &param);
}
void btc_a2dp_control_command_ack(int status)
{
/* sanity check */
if (btc_aa_ctrl_cb.a2dp_cmd_pending == ESP_A2D_MEDIA_CTRL_NONE) {
APPL_TRACE_ERROR("warning : no command pending, ignore ack");
return;
}
/* clear pending */
int cmd = btc_aa_ctrl_cb.a2dp_cmd_pending;
btc_aa_ctrl_cb.a2dp_cmd_pending = ESP_A2D_MEDIA_CTRL_NONE;
a2dp_cmd_acknowledge(cmd, status);
}
static void btc_a2dp_datapath_open(void)
{
#if BTC_AV_SRC_INCLUDED
if (btc_av_get_peer_sep() == AVDT_TSEP_SNK && btc_av_get_service_id() == BTA_A2DP_SOURCE_SERVICE_ID) {
/* Start the media task to encode SBC */
btc_a2dp_source_start_audio_req();
/* make sure we update any changed sbc encoder params */
btc_a2dp_source_encoder_update();
}
#endif
#if (BTC_AV_SINK_INCLUDED == TRUE)
btc_aa_ctrl_cb.data_channel_open = TRUE;
#endif
}
BOOLEAN btc_a2dp_control_get_datachnl_stat(void)
{
return btc_aa_ctrl_cb.data_channel_open;
}
void btc_a2dp_control_set_datachnl_stat(BOOLEAN open)
{
btc_aa_ctrl_cb.data_channel_open = open;
}
void btc_a2dp_control_media_ctrl(esp_a2d_media_ctrl_t ctrl)
{
APPL_TRACE_DEBUG("BTC MEDIA (A2DP-DATA) EVENT %u", ctrl);
if (btc_aa_ctrl_cb.a2dp_cmd_pending != ESP_A2D_MEDIA_CTRL_NONE) {
APPL_TRACE_WARNING("un-acked a2dp cmd: %u", btc_aa_ctrl_cb.a2dp_cmd_pending);
a2dp_cmd_acknowledge(ctrl, ESP_A2D_MEDIA_CTRL_ACK_BUSY);
return;
}
btc_aa_ctrl_cb.a2dp_cmd_pending = ctrl;
switch (ctrl) {
case ESP_A2D_MEDIA_CTRL_CHECK_SRC_RDY:
#if BTC_AV_SRC_INCLUDED
if (btc_av_get_service_id() == BTA_A2DP_SOURCE_SERVICE_ID) {
if (btc_a2dp_source_is_task_shutting_down()) {
btc_a2dp_control_command_ack(ESP_A2D_MEDIA_CTRL_ACK_FAILURE);
} else if ((btc_av_stream_ready() == TRUE) ||
(btc_av_stream_started_ready() == TRUE)) {
/* check whether av is ready to setup a2dp datapath */
btc_a2dp_control_command_ack(ESP_A2D_MEDIA_CTRL_ACK_SUCCESS);
} else {
btc_a2dp_control_command_ack(ESP_A2D_MEDIA_CTRL_ACK_FAILURE);
}
} else {
btc_a2dp_control_command_ack(ESP_A2D_MEDIA_CTRL_ACK_FAILURE);
}
#else /* BTC_AV_SRC_INCLUDED */
btc_a2dp_control_command_ack(ESP_A2D_MEDIA_CTRL_ACK_FAILURE);
#endif /* #if BTC_AV_SRC_INCLUDED */
break;
case ESP_A2D_MEDIA_CTRL_START:
if (btc_av_stream_ready() == TRUE ) {
/* post start event */
btc_dispatch_sm_event(BTC_AV_START_STREAM_REQ_EVT, NULL, 0);
#if (BTC_AV_SINK_INCLUDED == TRUE)
if (btc_av_get_peer_sep() == AVDT_TSEP_SRC && btc_av_get_service_id() == BTA_A2DP_SINK_SERVICE_ID) {
btc_a2dp_control_command_ack(ESP_A2D_MEDIA_CTRL_ACK_SUCCESS);
}
#endif
} else if (btc_av_stream_started_ready()) {
btc_a2dp_control_command_ack(ESP_A2D_MEDIA_CTRL_ACK_SUCCESS);
} else {
btc_a2dp_control_command_ack(ESP_A2D_MEDIA_CTRL_ACK_FAILURE);
}
break;
case ESP_A2D_MEDIA_CTRL_SUSPEND:
/* local suspend */
if (btc_av_stream_started_ready()) {
btc_dispatch_sm_event(BTC_AV_SUSPEND_STREAM_REQ_EVT, NULL, 0);
#if (BTC_AV_SINK_INCLUDED == TRUE)
if (btc_av_get_peer_sep() == AVDT_TSEP_SRC && btc_av_get_service_id() == BTA_A2DP_SINK_SERVICE_ID) {
btc_a2dp_control_command_ack(ESP_A2D_MEDIA_CTRL_ACK_SUCCESS);
}
#endif
} else if (btc_av_is_connected() == TRUE) {
/* we are not in started state; just ack back ok. This can happen if we are
remotely suspended; clear REMOTE SUSPEND Flag */
btc_av_clear_remote_suspend_flag();
btc_a2dp_control_command_ack(ESP_A2D_MEDIA_CTRL_ACK_SUCCESS);
} else {
btc_a2dp_control_command_ack(ESP_A2D_MEDIA_CTRL_ACK_FAILURE);
}
break;
default :
APPL_TRACE_ERROR("### A2DP-MEDIA EVENT %u NOT HANDLED ###", ctrl);
btc_a2dp_control_command_ack(ESP_A2D_MEDIA_CTRL_ACK_FAILURE);
break;
}
}
void btc_a2dp_control_datapath_ctrl(uint32_t dp_evt)
{
switch (dp_evt) {
case BTC_AV_DATAPATH_OPEN_EVT: {
btc_a2dp_datapath_open();
break;
}
default:
break;
}
return;
}
bool btc_a2dp_control_init(void)
{
memset(&btc_aa_ctrl_cb, 0, sizeof(tBTC_AA_CTRL_CB));
return true;
}
void btc_a2dp_control_cleanup(void)
{
memset(&btc_aa_ctrl_cb, 0, sizeof(tBTC_AA_CTRL_CB));
}
#endif /* #if BTC_AV_INCLUDED */
@@ -0,0 +1,752 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/******************************************************************************
**
** Name: btc_a2dp_sink.c
**
******************************************************************************/
#include "common/bt_target.h"
#include "common/bt_trace.h"
#include <string.h>
#include <stdint.h>
#include "common/bt_defs.h"
#include "osi/allocator.h"
#include "osi/mutex.h"
#include "osi/thread.h"
#include "osi/fixed_queue.h"
#include "stack/a2d_api.h"
#include "stack/a2d_sbc.h"
#include "bta/bta_av_api.h"
#include "bta/bta_av_ci.h"
#include "btc_av_co.h"
#include "btc_a2dp.h"
#include "btc_a2dp_control.h"
#include "btc_a2dp_sink.h"
#include "btc/btc_manage.h"
#include "btc_av.h"
#include "btc/btc_util.h"
#include "esp_a2dp_api.h"
#include "oi_codec_sbc.h"
#include "oi_status.h"
#include "osi/future.h"
#include <assert.h>
#if (BTC_AV_SINK_INCLUDED == TRUE)
/*****************************************************************************
** Constants
*****************************************************************************/
/* BTC media cmd event definition : BTC_MEDIA_TASK_CMD */
enum {
BTC_MEDIA_TASK_SINK_INIT,
BTC_MEDIA_TASK_SINK_CLEAN_UP,
BTC_MEDIA_FLUSH_AA_RX,
BTC_MEDIA_AUDIO_SINK_CFG_UPDATE,
BTC_MEDIA_AUDIO_SINK_CLEAR_TRACK,
};
enum {
BTC_A2DP_SINK_STATE_OFF = 0,
BTC_A2DP_SINK_STATE_ON = 1,
BTC_A2DP_SINK_STATE_SHUTTING_DOWN = 2
};
/*
* CONGESTION COMPENSATION CTRL ::
*
* Thus setting controls how many buffers we will hold in media task
* during temp link congestion. Together with the stack buffer queues
* it controls much temporary a2dp link congestion we can
* compensate for. It however also depends on the default run level of sinks
* jitterbuffers. Depending on type of sink this would vary.
* Ideally the (SRC) max tx buffer capacity should equal the sinks
* jitterbuffer runlevel including any intermediate buffers on the way
* towards the sinks codec.
*/
/* fixme -- define this in pcm time instead of buffer count */
/* The typical runlevel of the tx queue size is ~1 buffer
but due to link flow control or thread preemption in lower
layers we might need to temporarily buffer up data */
/* 18 frames is equivalent to 6.89*18*2.9 ~= 360 ms @ 44.1 khz, 20 ms mediatick */
#define MAX_OUTPUT_A2DP_SNK_FRAME_QUEUE_SZ (25)
#define BTC_A2DP_SNK_DATA_QUEUE_IDX (1)
typedef struct {
uint32_t sig;
void *param;
} a2dp_sink_task_evt_t;
typedef struct {
UINT16 num_frames_to_be_processed;
UINT16 len;
UINT16 offset;
UINT16 layer_specific;
} tBT_SBC_HDR;
typedef struct {
BOOLEAN rx_flush; /* discards any incoming data when true */
UINT8 channel_count;
struct osi_event *data_ready_event;
fixed_queue_t *RxSbcQ;
UINT32 sample_rate;
} tBTC_A2DP_SINK_CB;
typedef struct {
uint16_t expected_seq_num;
bool seq_num_recount;
} a2dp_sink_media_pkt_seq_num_t;
typedef struct {
tBTC_A2DP_SINK_CB btc_aa_snk_cb;
osi_thread_t *btc_aa_snk_task_hdl;
OI_CODEC_SBC_DECODER_CONTEXT context;
OI_UINT32 contextData[CODEC_DATA_WORDS(2, SBC_CODEC_FAST_FILTER_BUFFERS)];
OI_INT16 pcmData[15 * SBC_MAX_SAMPLES_PER_FRAME * SBC_MAX_CHANNELS];
a2dp_sink_media_pkt_seq_num_t media_pkt_seq_num;
} a2dp_sink_local_param_t;
static void btc_a2dp_sink_thread_init(UNUSED_ATTR void *context);
static void btc_a2dp_sink_thread_cleanup(UNUSED_ATTR void *context);
static void btc_a2dp_sink_flush_q(fixed_queue_t *p_q);
static void btc_a2dp_sink_rx_flush(void);
static int btc_a2dp_sink_get_track_frequency(UINT8 frequency);
static int btc_a2dp_sink_get_track_channel_count(UINT8 channeltype);
/* Handle incoming media packets A2DP SINK streaming*/
static void btc_a2dp_sink_handle_inc_media(tBT_SBC_HDR *p_msg);
static void btc_a2dp_sink_handle_decoder_reset(tBTC_MEDIA_SINK_CFG_UPDATE *p_msg);
static void btc_a2dp_sink_handle_clear_track(void);
static BOOLEAN btc_a2dp_sink_clear_track(void);
static void btc_a2dp_sink_data_ready(void *context);
static int btc_a2dp_sink_state = BTC_A2DP_SINK_STATE_OFF;
static esp_a2d_sink_data_cb_t bt_aa_snk_data_cb = NULL;
#if A2D_DYNAMIC_MEMORY == FALSE
static a2dp_sink_local_param_t a2dp_sink_local_param;
#else
static a2dp_sink_local_param_t *a2dp_sink_local_param_ptr;
#define a2dp_sink_local_param (*a2dp_sink_local_param_ptr)
#endif ///A2D_DYNAMIC_MEMORY == FALSE
void btc_a2dp_sink_reg_data_cb(esp_a2d_sink_data_cb_t callback)
{
// todo: critical section protection
bt_aa_snk_data_cb = callback;
}
static inline void btc_a2d_data_cb_to_app(const uint8_t *data, uint32_t len)
{
// todo: critical section protection
if (bt_aa_snk_data_cb) {
bt_aa_snk_data_cb(data, len);
}
}
/*****************************************************************************
** Misc helper functions
*****************************************************************************/
static inline void btc_a2d_cb_to_app(esp_a2d_cb_event_t event, esp_a2d_cb_param_t *param)
{
esp_a2d_cb_t btc_aa_cb = (esp_a2d_cb_t)btc_profile_cb_get(BTC_PID_A2DP);
if (btc_aa_cb) {
btc_aa_cb(event, param);
}
}
/*****************************************************************************
** BTC ADAPTATION
*****************************************************************************/
static bool btc_a2dp_sink_ctrl(uint32_t sig, void *param)
{
switch (sig) {
case BTC_MEDIA_TASK_SINK_INIT:
btc_a2dp_sink_thread_init(NULL);
break;
case BTC_MEDIA_TASK_SINK_CLEAN_UP:
btc_a2dp_sink_thread_cleanup(NULL);
break;
case BTC_MEDIA_AUDIO_SINK_CFG_UPDATE:
btc_a2dp_sink_handle_decoder_reset(param);
break;
case BTC_MEDIA_AUDIO_SINK_CLEAR_TRACK:
btc_a2dp_sink_handle_clear_track();
break;
case BTC_MEDIA_FLUSH_AA_RX:
btc_a2dp_sink_rx_flush();
break;
default:
APPL_TRACE_WARNING("media task unhandled evt: 0x%x\n", sig);
}
if (param != NULL) {
osi_free(param);
}
return true;
}
bool btc_a2dp_sink_startup(void)
{
if (btc_a2dp_sink_state != BTC_A2DP_SINK_STATE_OFF) {
APPL_TRACE_ERROR("warning : media task already running");
return false;
}
#if A2D_DYNAMIC_MEMORY == TRUE
if ((a2dp_sink_local_param_ptr = (a2dp_sink_local_param_t *)osi_malloc(sizeof(a2dp_sink_local_param_t))) == NULL) {
APPL_TRACE_ERROR("%s malloc failed!", __func__);
return false;
}
memset((void *)a2dp_sink_local_param_ptr, 0, sizeof(a2dp_sink_local_param_t));
#endif
APPL_TRACE_EVENT("## A2DP SINK START MEDIA THREAD ##");
a2dp_sink_local_param.btc_aa_snk_task_hdl = btc_get_current_thread();
if (btc_a2dp_sink_ctrl(BTC_MEDIA_TASK_SINK_INIT, NULL) == false) {
goto error_exit;
}
APPL_TRACE_EVENT("## A2DP SINK MEDIA THREAD STARTED ##\n");
return true;
error_exit:;
APPL_TRACE_ERROR("%s unable to start up media thread\n", __func__);
a2dp_sink_local_param.btc_aa_snk_task_hdl = NULL;
#if A2D_DYNAMIC_MEMORY == TRUE
osi_free(a2dp_sink_local_param_ptr);
a2dp_sink_local_param_ptr = NULL;
#endif
return false;
}
void btc_a2dp_sink_shutdown(void)
{
APPL_TRACE_EVENT("## A2DP SINK STOP MEDIA THREAD ##\n");
// Exit thread
btc_a2dp_sink_state = BTC_A2DP_SINK_STATE_SHUTTING_DOWN;
btc_a2dp_sink_ctrl(BTC_MEDIA_TASK_SINK_CLEAN_UP, NULL);
a2dp_sink_local_param.btc_aa_snk_task_hdl = NULL;
#if A2D_DYNAMIC_MEMORY == TRUE
osi_free(a2dp_sink_local_param_ptr);
a2dp_sink_local_param_ptr = NULL;
#endif
}
/*****************************************************************************
**
** Function btc_a2dp_sink_on_idle
**
*******************************************************************************/
void btc_a2dp_sink_on_idle(void)
{
a2dp_sink_local_param.btc_aa_snk_cb.rx_flush = TRUE;
btc_a2dp_sink_rx_flush_req();
btc_a2dp_sink_clear_track();
APPL_TRACE_DEBUG("Stopped BT track");
}
/*****************************************************************************
**
** Function btc_a2dp_sink_on_stopped
**
*******************************************************************************/
void btc_a2dp_sink_on_stopped(tBTA_AV_SUSPEND *p_av)
{
a2dp_sink_local_param.btc_aa_snk_cb.rx_flush = TRUE;
btc_a2dp_sink_rx_flush_req();
btc_a2dp_control_set_datachnl_stat(FALSE);
}
/*****************************************************************************
**
** Function btc_a2dp_on_suspended
**
*******************************************************************************/
void btc_a2dp_sink_on_suspended(tBTA_AV_SUSPEND *p_av)
{
a2dp_sink_local_param.btc_aa_snk_cb.rx_flush = TRUE;
btc_a2dp_sink_rx_flush_req();
return;
}
/*******************************************************************************
**
** Function btc_a2dp_sink_clear_track
**
** Description
**
** Returns TRUE is success
**
*******************************************************************************/
static BOOLEAN btc_a2dp_sink_clear_track(void)
{
return btc_a2dp_sink_ctrl(BTC_MEDIA_AUDIO_SINK_CLEAR_TRACK, NULL);
}
/* when true media task discards any rx frames */
void btc_a2dp_sink_set_rx_flush(BOOLEAN enable)
{
APPL_TRACE_EVENT("## DROP RX %d ##\n", enable);
if (enable == FALSE) {
a2dp_sink_local_param.media_pkt_seq_num.expected_seq_num = 0x1;
a2dp_sink_local_param.media_pkt_seq_num.seq_num_recount = true;
}
a2dp_sink_local_param.btc_aa_snk_cb.rx_flush = enable;
}
/*****************************************************************************
**
** Function btc_a2dp_sink_reset_decoder
**
** Description
**
** Returns
**
*******************************************************************************/
void btc_a2dp_sink_reset_decoder(UINT8 *p_av)
{
APPL_TRACE_EVENT("btc reset decoder");
APPL_TRACE_DEBUG("btc reset decoder p_codec_info[%x:%x:%x:%x:%x:%x]\n",
p_av[1], p_av[2], p_av[3],
p_av[4], p_av[5], p_av[6]);
tBTC_MEDIA_SINK_CFG_UPDATE *p_buf;
if (NULL == (p_buf = osi_malloc(sizeof(tBTC_MEDIA_SINK_CFG_UPDATE)))) {
APPL_TRACE_ERROR("btc reset decoder No Buffer ");
return;
}
memcpy(p_buf->codec_info, p_av, AVDT_CODEC_SIZE);
btc_a2dp_sink_ctrl(BTC_MEDIA_AUDIO_SINK_CFG_UPDATE, p_buf);
}
static void btc_a2dp_sink_data_ready(UNUSED_ATTR void *context)
{
tBT_SBC_HDR *p_msg;
int nb_of_msgs_to_process = 0;
if (fixed_queue_is_empty(a2dp_sink_local_param.btc_aa_snk_cb.RxSbcQ)) {
APPL_TRACE_DEBUG(" QUE EMPTY ");
} else {
if (a2dp_sink_local_param.btc_aa_snk_cb.rx_flush == TRUE) {
btc_a2dp_sink_flush_q(a2dp_sink_local_param.btc_aa_snk_cb.RxSbcQ);
return;
}
nb_of_msgs_to_process = fixed_queue_length(a2dp_sink_local_param.btc_aa_snk_cb.RxSbcQ);
APPL_TRACE_DEBUG("nb:%d", nb_of_msgs_to_process);
while (nb_of_msgs_to_process > 0) {
if (btc_a2dp_sink_state != BTC_A2DP_SINK_STATE_ON){
return;
}
p_msg = (tBT_SBC_HDR *)fixed_queue_dequeue(a2dp_sink_local_param.btc_aa_snk_cb.RxSbcQ, 0);
if ( p_msg == NULL ) {
APPL_TRACE_ERROR("Insufficient data in que ");
break;
}
btc_a2dp_sink_handle_inc_media(p_msg);
osi_free(p_msg);
nb_of_msgs_to_process--;
}
APPL_TRACE_DEBUG(" Process Frames - ");
if (!fixed_queue_is_empty(a2dp_sink_local_param.btc_aa_snk_cb.RxSbcQ)) {
osi_thread_post_event(a2dp_sink_local_param.btc_aa_snk_cb.data_ready_event, OSI_THREAD_MAX_TIMEOUT);
}
}
}
/*******************************************************************************
**
** Function btc_a2dp_sink_handle_decoder_reset
**
** Description
**
** Returns void
**
*******************************************************************************/
static void btc_a2dp_sink_handle_decoder_reset(tBTC_MEDIA_SINK_CFG_UPDATE *p_msg)
{
tBTC_MEDIA_SINK_CFG_UPDATE *p_buf = p_msg;
tA2D_STATUS a2d_status;
tA2D_SBC_CIE sbc_cie;
OI_STATUS status;
UINT32 freq_multiple = 48 * 20; /* frequency multiple for 20ms of data , initialize with 48K*/
UINT32 num_blocks = 16;
UINT32 num_subbands = 8;
APPL_TRACE_EVENT("%s p_codec_info[%x:%x:%x:%x:%x:%x]\n", __FUNCTION__,
p_buf->codec_info[1], p_buf->codec_info[2], p_buf->codec_info[3],
p_buf->codec_info[4], p_buf->codec_info[5], p_buf->codec_info[6]);
a2d_status = A2D_ParsSbcInfo(&sbc_cie, p_buf->codec_info, FALSE);
if (a2d_status != A2D_SUCCESS) {
APPL_TRACE_ERROR("ERROR dump_codec_info A2D_ParsSbcInfo fail:%d\n", a2d_status);
return;
}
a2dp_sink_local_param.btc_aa_snk_cb.sample_rate = btc_a2dp_sink_get_track_frequency(sbc_cie.samp_freq);
a2dp_sink_local_param.btc_aa_snk_cb.channel_count = btc_a2dp_sink_get_track_channel_count(sbc_cie.ch_mode);
a2dp_sink_local_param.btc_aa_snk_cb.rx_flush = FALSE;
APPL_TRACE_EVENT("Reset to sink role");
status = OI_CODEC_SBC_DecoderReset(&a2dp_sink_local_param.context, a2dp_sink_local_param.contextData,
sizeof(a2dp_sink_local_param.contextData), a2dp_sink_local_param.btc_aa_snk_cb.channel_count,
a2dp_sink_local_param.btc_aa_snk_cb.channel_count, FALSE, FALSE);
if (!OI_SUCCESS(status)) {
APPL_TRACE_ERROR("OI_CODEC_SBC_DecoderReset failed with error code %d\n", status);
}
btc_a2dp_control_set_datachnl_stat(TRUE);
switch (sbc_cie.samp_freq) {
case A2D_SBC_IE_SAMP_FREQ_16:
APPL_TRACE_DEBUG("\tsamp_freq:%d (16000)\n", sbc_cie.samp_freq);
freq_multiple = 16 * 20;
break;
case A2D_SBC_IE_SAMP_FREQ_32:
APPL_TRACE_DEBUG("\tsamp_freq:%d (32000)\n", sbc_cie.samp_freq);
freq_multiple = 32 * 20;
break;
case A2D_SBC_IE_SAMP_FREQ_44:
APPL_TRACE_DEBUG("\tsamp_freq:%d (44100)\n", sbc_cie.samp_freq);
freq_multiple = 441 * 2;
break;
case A2D_SBC_IE_SAMP_FREQ_48:
APPL_TRACE_DEBUG("\tsamp_freq:%d (48000)\n", sbc_cie.samp_freq);
freq_multiple = 48 * 20;
break;
default:
APPL_TRACE_DEBUG(" Unknown Frequency ");
break;
}
switch (sbc_cie.ch_mode) {
case A2D_SBC_IE_CH_MD_MONO:
APPL_TRACE_DEBUG("\tch_mode:%d (Mono)\n", sbc_cie.ch_mode);
break;
case A2D_SBC_IE_CH_MD_DUAL:
APPL_TRACE_DEBUG("\tch_mode:%d (DUAL)\n", sbc_cie.ch_mode);
break;
case A2D_SBC_IE_CH_MD_STEREO:
APPL_TRACE_DEBUG("\tch_mode:%d (STEREO)\n", sbc_cie.ch_mode);
break;
case A2D_SBC_IE_CH_MD_JOINT:
APPL_TRACE_DEBUG("\tch_mode:%d (JOINT)\n", sbc_cie.ch_mode);
break;
default:
APPL_TRACE_DEBUG(" Unknown Mode ");
break;
}
switch (sbc_cie.block_len) {
case A2D_SBC_IE_BLOCKS_4:
APPL_TRACE_DEBUG("\tblock_len:%d (4)\n", sbc_cie.block_len);
num_blocks = 4;
break;
case A2D_SBC_IE_BLOCKS_8:
APPL_TRACE_DEBUG("\tblock_len:%d (8)\n", sbc_cie.block_len);
num_blocks = 8;
break;
case A2D_SBC_IE_BLOCKS_12:
APPL_TRACE_DEBUG("\tblock_len:%d (12)\n", sbc_cie.block_len);
num_blocks = 12;
break;
case A2D_SBC_IE_BLOCKS_16:
APPL_TRACE_DEBUG("\tblock_len:%d (16)\n", sbc_cie.block_len);
num_blocks = 16;
break;
default:
APPL_TRACE_DEBUG(" Unknown BlockLen ");
break;
}
switch (sbc_cie.num_subbands) {
case A2D_SBC_IE_SUBBAND_4:
APPL_TRACE_DEBUG("\tnum_subbands:%d (4)\n", sbc_cie.num_subbands);
num_subbands = 4;
break;
case A2D_SBC_IE_SUBBAND_8:
APPL_TRACE_DEBUG("\tnum_subbands:%d (8)\n", sbc_cie.num_subbands);
num_subbands = 8;
break;
default:
APPL_TRACE_DEBUG(" Unknown SubBands ");
break;
}
switch (sbc_cie.alloc_mthd) {
case A2D_SBC_IE_ALLOC_MD_S:
APPL_TRACE_DEBUG("\talloc_mthd:%d (SNR)\n", sbc_cie.alloc_mthd);
break;
case A2D_SBC_IE_ALLOC_MD_L:
APPL_TRACE_DEBUG("\talloc_mthd:%d (Loudness)\n", sbc_cie.alloc_mthd);
break;
default:
APPL_TRACE_DEBUG(" Unknown Allocation Method");
break;
}
APPL_TRACE_EVENT("\tBit pool Min:%d Max:%d\n", sbc_cie.min_bitpool, sbc_cie.max_bitpool);
int frames_to_process = ((freq_multiple) / (num_blocks * num_subbands)) + 1;
APPL_TRACE_EVENT(" Frames to be processed in 20 ms %d\n", frames_to_process);
UNUSED(frames_to_process);
}
/*******************************************************************************
**
** Function btc_a2dp_sink_handle_inc_media
**
** Description
**
** Returns void
**
*******************************************************************************/
static void btc_a2dp_sink_handle_inc_media(tBT_SBC_HDR *p_msg)
{
UINT8 *sbc_start_frame = ((UINT8 *)(p_msg + 1) + p_msg->offset + 1);
int count;
UINT32 pcmBytes, availPcmBytes;
OI_INT16 *pcmDataPointer = a2dp_sink_local_param.pcmData; /*Will be overwritten on next packet receipt*/
OI_STATUS status;
int num_sbc_frames = p_msg->num_frames_to_be_processed;
UINT32 sbc_frame_len = p_msg->len - 1;
availPcmBytes = sizeof(a2dp_sink_local_param.pcmData);
/* XXX: Check if the below check is correct, we are checking for peer to be sink when we are sink */
if (btc_av_get_peer_sep() == AVDT_TSEP_SNK || (a2dp_sink_local_param.btc_aa_snk_cb.rx_flush)) {
APPL_TRACE_DEBUG(" State Changed happened in this tick ");
return;
}
// ignore data if no one is listening
if (!btc_a2dp_control_get_datachnl_stat()) {
return;
}
if (p_msg->layer_specific != a2dp_sink_local_param.media_pkt_seq_num.expected_seq_num) {
/* Because the sequence number of some devices is not recounted */
if (!a2dp_sink_local_param.media_pkt_seq_num.seq_num_recount ||
a2dp_sink_local_param.media_pkt_seq_num.expected_seq_num != 0x1) {
APPL_TRACE_WARNING("Sequence numbers error, recv:0x%x, expect:0x%x, recount:0x%x",
p_msg->layer_specific, a2dp_sink_local_param.media_pkt_seq_num.expected_seq_num,
a2dp_sink_local_param.media_pkt_seq_num.seq_num_recount);
}
}
a2dp_sink_local_param.media_pkt_seq_num.expected_seq_num = p_msg->layer_specific + 1;
a2dp_sink_local_param.media_pkt_seq_num.seq_num_recount = false;
APPL_TRACE_DEBUG("Number of sbc frames %d, frame_len %d\n", num_sbc_frames, sbc_frame_len);
for (count = 0; count < num_sbc_frames && sbc_frame_len != 0; count ++) {
pcmBytes = availPcmBytes;
status = OI_CODEC_SBC_DecodeFrame(&a2dp_sink_local_param.context, (const OI_BYTE **)&sbc_start_frame,
(OI_UINT32 *)&sbc_frame_len,
(OI_INT16 *)pcmDataPointer,
(OI_UINT32 *)&pcmBytes);
if (!OI_SUCCESS(status)) {
APPL_TRACE_ERROR("Decoding failure: %d\n", status);
break;
}
availPcmBytes -= pcmBytes;
pcmDataPointer += pcmBytes / 2;
p_msg->offset += (p_msg->len - 1) - sbc_frame_len;
p_msg->len = sbc_frame_len + 1;
}
btc_a2d_data_cb_to_app((uint8_t *)a2dp_sink_local_param.pcmData, (sizeof(a2dp_sink_local_param.pcmData) - availPcmBytes));
}
/*******************************************************************************
**
** Function btc_a2dp_sink_rx_flush_req
**
** Description
**
** Returns TRUE is success
**
*******************************************************************************/
BOOLEAN btc_a2dp_sink_rx_flush_req(void)
{
if (fixed_queue_is_empty(a2dp_sink_local_param.btc_aa_snk_cb.RxSbcQ) == TRUE) { /* Que is already empty */
return TRUE;
}
return btc_a2dp_sink_ctrl(BTC_MEDIA_FLUSH_AA_RX, NULL);
}
/*******************************************************************************
**
** Function btc_a2dp_sink_rx_flush
**
** Description
**
** Returns void
**
*******************************************************************************/
static void btc_a2dp_sink_rx_flush(void)
{
/* Flush all enqueued SBC buffers (encoded) */
APPL_TRACE_DEBUG("btc_a2dp_sink_rx_flush");
btc_a2dp_sink_flush_q(a2dp_sink_local_param.btc_aa_snk_cb.RxSbcQ);
}
static int btc_a2dp_sink_get_track_frequency(UINT8 frequency)
{
int freq = 48000;
switch (frequency) {
case A2D_SBC_IE_SAMP_FREQ_16:
freq = 16000;
break;
case A2D_SBC_IE_SAMP_FREQ_32:
freq = 32000;
break;
case A2D_SBC_IE_SAMP_FREQ_44:
freq = 44100;
break;
case A2D_SBC_IE_SAMP_FREQ_48:
freq = 48000;
break;
}
return freq;
}
static int btc_a2dp_sink_get_track_channel_count(UINT8 channeltype)
{
int count = 1;
switch (channeltype) {
case A2D_SBC_IE_CH_MD_MONO:
count = 1;
break;
case A2D_SBC_IE_CH_MD_DUAL:
case A2D_SBC_IE_CH_MD_STEREO:
case A2D_SBC_IE_CH_MD_JOINT:
count = 2;
break;
}
return count;
}
/*******************************************************************************
**
** Function btc_a2dp_sink_enque_buf
**
** Description This function is called by the av_co to fill A2DP Sink Queue
**
**
** Returns size of the queue
*******************************************************************************/
UINT8 btc_a2dp_sink_enque_buf(BT_HDR *p_pkt)
{
tBT_SBC_HDR *p_msg;
if (btc_a2dp_sink_state != BTC_A2DP_SINK_STATE_ON){
return 0;
}
if (a2dp_sink_local_param.btc_aa_snk_cb.rx_flush == TRUE) { /* Flush enabled, do not enque*/
return fixed_queue_length(a2dp_sink_local_param.btc_aa_snk_cb.RxSbcQ);
}
if (fixed_queue_length(a2dp_sink_local_param.btc_aa_snk_cb.RxSbcQ) >= MAX_OUTPUT_A2DP_SNK_FRAME_QUEUE_SZ) {
APPL_TRACE_WARNING("Pkt dropped\n");
return fixed_queue_length(a2dp_sink_local_param.btc_aa_snk_cb.RxSbcQ);
}
APPL_TRACE_DEBUG("btc_a2dp_sink_enque_buf + ");
/* allocate and Queue this buffer */
if ((p_msg = (tBT_SBC_HDR *) osi_malloc(sizeof(tBT_SBC_HDR) +
p_pkt->offset + p_pkt->len)) != NULL) {
memcpy(p_msg, p_pkt, (sizeof(BT_HDR) + p_pkt->offset + p_pkt->len));
p_msg->num_frames_to_be_processed = (*((UINT8 *)(p_msg + 1) + p_msg->offset)) & 0x0f;
APPL_TRACE_VERBOSE("btc_a2dp_sink_enque_buf %d + \n", p_msg->num_frames_to_be_processed);
fixed_queue_enqueue(a2dp_sink_local_param.btc_aa_snk_cb.RxSbcQ, p_msg, FIXED_QUEUE_MAX_TIMEOUT);
osi_thread_post_event(a2dp_sink_local_param.btc_aa_snk_cb.data_ready_event, OSI_THREAD_MAX_TIMEOUT);
} else {
/* let caller deal with a failed allocation */
APPL_TRACE_WARNING("btc_a2dp_sink_enque_buf No Buffer left - ");
}
return fixed_queue_length(a2dp_sink_local_param.btc_aa_snk_cb.RxSbcQ);
}
static void btc_a2dp_sink_handle_clear_track (void)
{
APPL_TRACE_DEBUG("%s", __FUNCTION__);
}
/*******************************************************************************
**
** Function btc_a2dp_sink_flush_q
**
** Description
**
** Returns void
**
*******************************************************************************/
static void btc_a2dp_sink_flush_q(fixed_queue_t *p_q)
{
while (! fixed_queue_is_empty(p_q)) {
osi_free(fixed_queue_dequeue(p_q, 0));
}
}
static void btc_a2dp_sink_thread_init(UNUSED_ATTR void *context)
{
APPL_TRACE_EVENT("%s\n", __func__);
memset(&a2dp_sink_local_param.btc_aa_snk_cb, 0, sizeof(a2dp_sink_local_param.btc_aa_snk_cb));
btc_a2dp_sink_state = BTC_A2DP_SINK_STATE_ON;
struct osi_event *data_event = osi_event_create(btc_a2dp_sink_data_ready, NULL);
assert (data_event != NULL);
osi_event_bind(data_event, a2dp_sink_local_param.btc_aa_snk_task_hdl, BTC_A2DP_SNK_DATA_QUEUE_IDX);
a2dp_sink_local_param.btc_aa_snk_cb.data_ready_event = data_event;
a2dp_sink_local_param.btc_aa_snk_cb.RxSbcQ = fixed_queue_new(QUEUE_SIZE_MAX);
btc_a2dp_control_init();
}
static void btc_a2dp_sink_thread_cleanup(UNUSED_ATTR void *context)
{
btc_a2dp_control_set_datachnl_stat(FALSE);
/* Clear task flag */
btc_a2dp_sink_state = BTC_A2DP_SINK_STATE_OFF;
btc_a2dp_control_cleanup();
fixed_queue_free(a2dp_sink_local_param.btc_aa_snk_cb.RxSbcQ, osi_free_func);
a2dp_sink_local_param.btc_aa_snk_cb.RxSbcQ = NULL;
osi_event_delete(a2dp_sink_local_param.btc_aa_snk_cb.data_ready_event);
a2dp_sink_local_param.btc_aa_snk_cb.data_ready_event = NULL;
}
#endif /* BTC_AV_SINK_INCLUDED */
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,221 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __BTC_AV_CO_H__
#define __BTC_AV_CO_H__
#include "btc_a2dp.h"
#include "bta/bta_av_co.h"
#if (BTA_AV_INCLUDED == TRUE)
/*******************************************************************************
** Constants & Macros
********************************************************************************/
enum {
BTC_SV_AV_AA_SBC_INDEX = 0,
BTC_SV_AV_AA_SBC_SINK_INDEX,
BTC_SV_AV_AA_SEP_INDEX /* Last index */
};
/*****************************************************************************
** Local data
*****************************************************************************/
typedef struct {
UINT8 sep_info_idx; /* local SEP index (in BTA tables) */
UINT8 seid; /* peer SEP index (in peer tables) */
UINT8 codec_type; /* peer SEP codec type */
UINT8 codec_caps[AVDT_CODEC_SIZE]; /* peer SEP codec capabilities */
UINT8 num_protect; /* peer SEP number of CP elements */
UINT8 protect_info[BTA_AV_CP_INFO_LEN]; /* peer SEP content protection info */
} tBTA_AV_CO_SINK;
typedef struct {
BD_ADDR addr; /* address of audio/video peer */
tBTA_AV_CO_SINK snks[BTC_SV_AV_AA_SEP_INDEX]; /* array of supported sinks */
tBTA_AV_CO_SINK srcs[BTC_SV_AV_AA_SEP_INDEX]; /* array of supported srcs */
UINT8 num_snks; /* total number of sinks at peer */
UINT8 num_srcs; /* total number of srcs at peer */
UINT8 num_seps; /* total number of seids at peer */
UINT8 num_rx_snks; /* number of received sinks */
UINT8 num_rx_srcs; /* number of received srcs */
UINT8 num_sup_snks; /* number of supported sinks in the snks array */
UINT8 num_sup_srcs; /* number of supported srcs in the srcs array */
tBTA_AV_CO_SINK *p_snk; /* currently selected sink */
tBTA_AV_CO_SINK *p_src; /* currently selected src */
UINT8 codec_cfg[AVDT_CODEC_SIZE]; /* current codec configuration */
BOOLEAN cp_active; /* current CP configuration */
BOOLEAN acp; /* acceptor */
BOOLEAN recfg_needed; /* reconfiguration is needed */
BOOLEAN opened; /* opened */
UINT16 mtu; /* maximum transmit unit size */
UINT16 uuid_to_connect; /* uuid of peer device */
BOOLEAN got_disc_res; /* got the results of initiating discovery */
} tBTA_AV_CO_PEER;
typedef struct {
BOOLEAN active;
UINT8 flag;
} tBTA_AV_CO_CP;
typedef struct {
/* Connected peer information */
tBTA_AV_CO_PEER peers[BTA_AV_NUM_STRS];
/* Current codec configuration - access to this variable must be protected */
tBTC_AV_CODEC_INFO codec_cfg;
tBTC_AV_CODEC_INFO codec_cfg_setconfig; /* remote peer setconfig preference */
tBTA_AV_CO_CP cp;
} tBTA_AV_CO_CB;
/* Control block instance */
#if AVRC_DYNAMIC_MEMORY == FALSE
extern tBTA_AV_CO_CB bta_av_co_cb;
#else
extern tBTA_AV_CO_CB *bta_av_co_cb_ptr;
#define bta_av_co_cb (*bta_av_co_cb_ptr)
#endif
/*******************************************************************************
** Functions
********************************************************************************/
/*******************************************************************************
**
** Function bta_av_co_cp_is_active
**
** Description Get the current configuration of content protection
**
** Returns TRUE if the current streaming has CP, FALSE otherwise
**
*******************************************************************************/
BOOLEAN bta_av_co_cp_is_active(void);
/*******************************************************************************
**
** Function bta_av_co_cp_get_flag
**
** Description Get content protection flag
** BTA_AV_CP_SCMS_COPY_NEVER
** BTA_AV_CP_SCMS_COPY_ONCE
** BTA_AV_CP_SCMS_COPY_FREE
**
** Returns The current flag value
**
*******************************************************************************/
UINT8 bta_av_co_cp_get_flag(void);
/*******************************************************************************
**
** Function bta_av_co_cp_set_flag
**
** Description Set content protection flag
** BTA_AV_CP_SCMS_COPY_NEVER
** BTA_AV_CP_SCMS_COPY_ONCE
** BTA_AV_CP_SCMS_COPY_FREE
**
** Returns TRUE if setting the SCMS flag is supported else FALSE
**
*******************************************************************************/
BOOLEAN bta_av_co_cp_set_flag(UINT8 cp_flag);
/*******************************************************************************
**
** Function bta_av_co_audio_codec_reset
**
** Description Reset the current codec configuration
**
** Returns void
**
*******************************************************************************/
void bta_av_co_audio_codec_reset(void);
/*******************************************************************************
**
** Function bta_av_co_audio_codec_supported
**
** Description Check if all opened connections are compatible with a codec
** configuration
**
** Returns TRUE if all opened devices support this codec, FALSE otherwise
**
*******************************************************************************/
BOOLEAN bta_av_co_audio_codec_supported(tBTC_AV_STATUS *p_status);
/*******************************************************************************
**
** Function bta_av_co_audio_set_codec
**
** Description Set the current codec configuration from the feeding type.
** This function is starting to modify the configuration, it
** should be protected.
**
** Returns TRUE if successful, FALSE otherwise
**
*******************************************************************************/
BOOLEAN bta_av_co_audio_set_codec(const tBTC_AV_MEDIA_FEEDINGS *p_feeding, tBTC_AV_STATUS *p_status);
/*******************************************************************************
**
** Function bta_av_co_audio_get_sbc_config
**
** Description Retrieves the SBC codec configuration. If the codec in use
** is not SBC, return the default SBC codec configuration.
**
** Returns TRUE if codec is SBC, FALSE otherwise
**
*******************************************************************************/
BOOLEAN bta_av_co_audio_get_sbc_config(tA2D_SBC_CIE *p_sbc_config, UINT16 *p_minmtu);
/*******************************************************************************
**
** Function bta_av_co_audio_discard_config
**
** Description Discard the codec configuration of a connection
**
** Returns Nothing
**
*******************************************************************************/
void bta_av_co_audio_discard_config(tBTA_AV_HNDL hndl);
/*******************************************************************************
**
** Function bta_av_co_init
**
** Description Initialization
**
** Returns Nothing
**
*******************************************************************************/
void bta_av_co_init(void);
/*******************************************************************************
**
** Function bta_av_co_peer_cp_supported
**
** Description Checks if the peer supports CP
**
** Returns TRUE if the peer supports CP
**
*******************************************************************************/
BOOLEAN bta_av_co_peer_cp_supported(tBTA_AV_HNDL hndl);
/*******************************************************************************
**
** Function bta_av_co_get_remote_bitpool_pref
**
** Description Check if remote side did a setconfig within the limits
** of our exported bitpool range. If set we will set the
** remote preference.
**
** Returns TRUE if config set, FALSE otherwize
**
*******************************************************************************/
BOOLEAN bta_av_co_get_remote_bitpool_pref(UINT8 *min, UINT8 *max);
#endif ///BTA_AV_INCLUDED == TRUE
#endif
@@ -0,0 +1,99 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/******************************************************************************
*
* This is the AVRC call-out function implementation for BTC.
*
******************************************************************************/
/*****************************************************************************
*
* Filename: bta_avrc_co.c
*
* Description: Bluetooth AVRC implementation
*
*****************************************************************************/
#include <stdint.h>
#include "common/bt_target.h"
#include "bta/bta_sys.h"
#include "bta/bta_av_api.h"
#include "btc_avrc.h"
#if BTC_AV_INCLUDED
/*******************************************************************************
**
** Function bta_avrc_co_cmd_allowed
**
** Description Check if local AVRCP TG configuration supports a specific
** PASSTHROUGH command with the given operation_id
**
** Returns TRUE if operation_id is supported, FALSE otherwise
**
*******************************************************************************/
BOOLEAN bta_avrc_co_cmd_allowed(tBTA_AV_RC rc_id)
{
if (rc_id >= BTA_AV_VENDOR) {
return FALSE;
}
const uint16_t *rc_cmd = btc_avrc_tg_get_supported_command();
if (rc_cmd[rc_id >> 4] & ((uint16_t)1 << (rc_id & 0x0F))) {
return TRUE;
} else {
return FALSE;
}
}
/*******************************************************************************
**
** Function bta_avrc_co_rn_evt_cap
**
** Description get the event notifcation capabilities on AVRCP target
**
** Returns number of event_ids supported
**
*******************************************************************************/
UINT8 bta_avrc_co_rn_evt_cap(UINT8 *event_ids)
{
if (event_ids == 0) {
return 0;
}
UINT16 event_bits = btc_avrc_tg_get_rn_supported_evt();
UINT8 count = 0;
for (UINT8 i = 0; i < 16; ++i, event_bits >>= 1) {
if (event_bits & 0x01) {
event_ids[count++] = i;
}
}
return count;
}
/*******************************************************************************
**
** Function bta_avrc_co_evt_supported
**
** Description Check if local AVRCP TG configuration supports the given
** event_id
**
** Returns TRUE if operation_id is supported, FALSE otherwise
**
*******************************************************************************/
BOOLEAN bta_avrc_co_rn_evt_supported(UINT8 event_id)
{
return btc_avrc_tg_rn_evt_supported(event_id) ?
TRUE : FALSE;
}
/* the call out functions for AVRC */
tBTA_AVRC_CO_FUNCTS bta_avrc_cos = {
bta_avrc_co_cmd_allowed,
bta_avrc_co_rn_evt_cap,
bta_avrc_co_rn_evt_supported,
};
#endif /* #if BTC_AV_INCLUDED */
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,597 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdint.h>
#include <string.h>
#include <stdbool.h>
#include <stdio.h>
//#include "bluedroid_test.h"
#include "bta/bta_api.h"
#include "bta/bta_gatt_api.h"
#include "device/controller.h"
#include "gatt_int.h"
#include "common/bt_trace.h"
#include "stack/btm_api.h"
#include "stack/bt_types.h"
#include "dis_api.h"
#if BLE_INCLUDED == true
#define BA_MAX_CHAR_NUM 1
#define BA_MAX_ATTR_NUM (BA_MAX_CHAR_NUM * 5 + 1)
/*max 3 descriptors, 1 desclaration and 1 value*/
#ifndef BATTER_LEVEL_PROP
#define BATTER_LEVEL_PROP (GATT_CHAR_PROP_BIT_READ|GATT_CHAR_PROP_BIT_NOTIFY)
#endif
#ifndef BATTER_LEVEL_PERM
#define BATTER_LEVEL_PERM (GATT_PERM_READ)
#endif
#define BT_BD_ADDR_STR "%02x:%02x:%02x:%02x:%02x:%02x"
#define BT_BD_ADDR_HEX(addr) addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]
esp_gatts_if_t server_if;
tBATTERY_CB battery_cb;
tGATT_CHAR_PROP prop = GATT_CHAR_PROP_BIT_READ;
tBA_REG_INFO ba_reg_info;
UINT8 attr_handle_bit = 0x00;
extern tDIS_CB dis_cb;
esp_bt_uuid_t bas_uuid = {LEN_UUID_16, {UUID_SERVCLASS_BATTERY}};
/******************************************************************************
** Function bas_gatts_callback
**
** Description battery service register callback function
*******************************************************************************/
static void bas_gatts_callback(esp_gatts_evt_t event, tBTA_GATTS *p_data)
{
switch (event) {
case ESP_GATTS_REG_EVT: {
esp_gatt_status_t status = p_data->reg_oper.status;
server_if = p_data->reg_oper.server_if;
BTC_TRACE_ERROR("BAS register completed: event=%d, status=%d, server_if=%d\n",
event, status, server_if);
UINT8 app_id = 0xff;
bas_init(server_if, app_id);
tDIS_ATTR_MASK mask = 0x01ff;
DIS_Init(server_if, mask);
}
break;
/*connect callback*/
case ESP_GATTS_CONNECT_EVT: {
BTC_TRACE_ERROR("\ndevice is connected "BT_BD_ADDR_STR", server_if=%d,reason=0x%x,connect_id=%d\n",
BT_BD_ADDR_HEX(p_data->conn.remote_bda), p_data->conn.server_if,
p_data->conn.reason, p_data->conn.conn_id);
/*return whether the remote device is currently connected*/
int is_connected = BTA_DmGetConnectionState(p_data->conn.remote_bda);
BTC_TRACE_ERROR("is_connected=%d\n", is_connected);
}
break;
/*create service callback*/
case ESP_GATTS_CREATE_EVT: {
BTC_TRACE_ERROR("create service:server_if=%d,service_id=0x%x,service_uuid=0x%x\n",
p_data->create.server_if, p_data->create.service_id,
p_data->create.uuid.uu.uuid16);
UINT16 service_uuid = p_data->create.uuid.uu.uuid16;
UINT16 service_id = p_data->create.service_id;
if (service_uuid == 0x180f) {
tBT_UUID uuid = {LEN_UUID_16, {GATT_UUID_BATTERY_LEVEL}};
bas_AddChar(service_id, &uuid);
}
if (service_uuid == 0x180a) {
dis_cb.service_handle = service_id;
dis_cb.max_handle = service_id + DIS_MAX_ATTR_NUM;
dis_AddChar(service_id);
}
}
break;
case ESP_GATTS_ADD_CHAR_EVT: {
BTC_TRACE_ERROR("create characteristic:server_if=%d,service_id=0x%x,char_uuid=0x%x\n",
p_data->add_result.server_if, p_data->add_result.service_id,
p_data->add_result.char_uuid.uu.uuid16);
UINT16 char_uuid = p_data->add_result.char_uuid.uu.uuid16;
UINT16 service_id = p_data->add_result.service_id;
UINT16 uuid_len = p_data->add_result.char_uuid.len;
if (uuid_len == ESP_UUID_LEN_16) {
if (char_uuid == GATT_UUID_BATTERY_LEVEL) {
bas_AddCharDescr(service_id, p_data->add_result.attr_id);
}
switch (char_uuid) {
case GATT_UUID_SYSTEM_ID:
dis_cb.dis_attr[0].handle = service_id; break;
case GATT_UUID_MODEL_NUMBER_STR:
dis_cb.dis_attr[1].handle = service_id; break;
case GATT_UUID_SERIAL_NUMBER_STR:
dis_cb.dis_attr[2].handle = service_id; break;
case GATT_UUID_FW_VERSION_STR:
dis_cb.dis_attr[3].handle = service_id; break;
case GATT_UUID_HW_VERSION_STR:
dis_cb.dis_attr[4].handle = service_id; break;
case GATT_UUID_SW_VERSION_STR:
dis_cb.dis_attr[5].handle = service_id; break;
case GATT_UUID_MANU_NAME:
dis_cb.dis_attr[6].handle = service_id; break;
case GATT_UUID_IEEE_DATA:
dis_cb.dis_attr[7].handle = service_id; break;
case GATT_UUID_PNP_ID:
dis_cb.dis_attr[8].handle = service_id; break;
}
default:
break;
}
}
break;
case ESP_GATTS_ADD_CHAR_DESCR_EVT: {
BTC_TRACE_ERROR("create descriptor:server_if=%d,service_id=0x%x,attr_id=0x%x,char_uuid=0x%x\n",
p_data->add_result.server_if, p_data->add_result.service_id,
p_data->add_result.attr_id, p_data->add_result.char_uuid.uu.uuid16);
bas_AddCharDescr(p_data->add_result.service_id, p_data->add_result.attr_id);
}
break;
case ESP_GATTS_START_EVT: {
BTC_TRACE_ERROR("start service:server_if=%d,service_id=0x%x\n", p_data->srvc_oper.server_if,
p_data->srvc_oper.service_id);
bas_service_cmpl(p_data->srvc_oper.service_id, p_data->srvc_oper.status);
/*start advertising*/
//if(p_data->srvc_oper.status == GATT_SUCCESS)
// BTA_GATTS_Listen(server_if, true, NULL);
// BTA_GATTC_Broadcast(client_if, true); //non-connectable
}
break;
case ESP_GATTS_READ_EVT: {
UINT32 trans_id = p_data->req_data.trans_id;
UINT16 conn_id = p_data->req_data.conn_id;
UINT16 handle = p_data->req_data.p_data->read_req.handle;
bool is_long = p_data->req_data.p_data->read_req.is_long;
BTC_TRACE_ERROR("read request:event=0x%x,handle=0x%x,trans_id=0x%x,conn_id=0x%x\n",
event, handle, trans_id, conn_id);
if (dis_valid_handle_range(handle)) {
tGATT_VALUE p_value;
p_value.handle = handle;
p_value.conn_id = conn_id;
p_value.offset = p_data->req_data.p_data->read_req.offset;
dis_s_read_attr_value(p_data->req_data.p_data, &p_value, trans_id, conn_id);
} else {
bas_s_read_attr_value(p_data->req_data.p_data, trans_id, conn_id);
}
}
break;
case ESP_GATTS_WRITE_EVT: {
UINT32 trans_id = p_data->req_data.trans_id;
UINT16 conn_id = p_data->req_data.conn_id;
UINT16 handle = p_data->req_data.p_data->write_req.handle;
BTC_TRACE_ERROR("write request:event=0x%x,handle=0x%x,trans_id=0x%x,conn_id=0x%x\n",
event, handle, trans_id, conn_id);
bas_s_write_attr_value(p_data->req_data.p_data, trans_id, conn_id,
p_data->req_data.remote_bda);
}
break;
case ESP_GATTS_EXEC_WRITE_EVT: {
UINT32 trans_id = p_data->req_data.trans_id;
UINT16 conn_id = p_data->req_data.conn_id;
UINT8 exec_write = p_data->req_data.p_data->exec_write;
BTC_TRACE_ERROR("execute write request:event=0x%x,exce_write=0x%x,trans_id=0x%x,conn_id=0x%x\n",
event, exec_write, trans_id, conn_id);
}
break;
case ESP_GATTS_MTU_EVT: {
UINT32 trans_id = p_data->req_data.trans_id;
UINT16 conn_id = p_data->req_data.conn_id;
UINT16 mtu = p_data->req_data.p_data->mtu;
BTC_TRACE_ERROR("exchange mtu request:event=0x%x,mtu=0x%x,trans_id=0x%x,conn_id=0x%x\n",
event, mtu, trans_id, conn_id);
}
break;
case ESP_GATTS_CFM_EVT: {
UINT32 trans_id = p_data->req_data.trans_id;
UINT16 conn_id = p_data->req_data.conn_id;
BTC_TRACE_ERROR("configue request:trans_id=0x%x,conn_id=0x%x\n",
trans_id, conn_id);
}
break;
default:
BTC_TRACE_ERROR("unsettled event: %d\n", event);
break;
}
}
/******************************************************************************
** Function bas_callback
**
** Description battery service callback for client request
*******************************************************************************/
static void bas_callback(UINT32 trans_id, UINT16 conn_id, UINT8 app_id,
UINT8 event, tBA_WRITE_DATA *p_data)
{
tBA_RSP_DATA p_rsp;
tGATT_STATUS st = ESP_GATT_OK;
switch (event) {
case BA_READ_LEVEL_REQ : {
BTC_TRACE_ERROR("read battery level\n");
p_rsp.ba_level = 60; //battery level
Battery_Rsp(trans_id, conn_id, app_id, st, event, &p_rsp);
}
break;
case BA_READ_PRE_FMT_REQ : {
BTC_TRACE_ERROR("read presentation format\n");
}
break;
case BA_READ_CLT_CFG_REQ : {
BTC_TRACE_ERROR("read client characteristic configuration request\n");
p_rsp.clt_cfg = 0x0001; //notification
Battery_Rsp(trans_id, conn_id, app_id, st, event, &p_rsp);
}
break;
case BA_READ_RPT_REF_REQ : {
BTC_TRACE_ERROR("read report reference descriptor\n");
}
break;
/*battery level notify*/
case BA_WRITE_CLT_CFG_REQ : {
BTC_TRACE_ERROR("write client characteristic configuration request\n");
Battery_Rsp(trans_id, conn_id, app_id, st, event, NULL);
int battery_level = 50;
Battery_Notify(conn_id, app_id, p_data->remote_bda, battery_level);
}
break;
default:
break;
}
return;
}
/*****************************************************************************
** Function bas_s_read_attr_value
**
** Description it will be called when client sends a read request
******************************************************************************/
void bas_s_read_attr_value(tGATTS_DATA *p_data, UINT32 trans_id, UINT16 conn_id)
{
tBA_INST *p_inst = &battery_cb.battery_inst[0];
UINT8 i;
esp_gatt_status_t st = ESP_GATT_NOT_FOUND;
UINT16 handle = p_data->read_req.handle;
for (i = 0; i < BA_MAX_INT_NUM; i ++, p_inst ++) {
// read battery level
if (handle == p_inst->ba_level_hdl ||
handle == p_inst->clt_cfg_hdl ||
handle == p_inst->rpt_ref_hdl ||
handle == p_inst->pres_fmt_hdl) {
if (p_data->read_req.is_long) {
st = ESP_GATT_NOT_LONG;
}
if (p_inst->p_cback) {
if (handle == p_inst->ba_level_hdl) {
p_inst->pending_evt = BA_READ_LEVEL_REQ;
}
if (handle == p_inst->clt_cfg_hdl) {
p_inst->pending_evt = BA_READ_CLT_CFG_REQ;
}
if (handle == p_inst->pres_fmt_hdl) {
p_inst->pending_evt = BA_READ_PRE_FMT_REQ;
}
if (handle == p_inst->rpt_ref_hdl) {
p_inst->pending_evt = BA_READ_RPT_REF_REQ ;
}
// p_inst->pending_clcb_idx = clcb_idx;
p_inst->pending_handle = handle;
//act = SRVC_ACT_PENDING;
(*p_inst->p_cback)(trans_id, conn_id, p_inst->app_id, p_inst->pending_evt, NULL);
} else { /* application is not registered */
st = ESP_GATT_ERR_UNLIKELY;
}
break;
}
/* else attribute not found */
}
}
/*****************************************************************************
** Function bas_s_write_attr_value
**
** Description it will be called when client sends a write request
******************************************************************************/
void bas_s_write_attr_value(tGATTS_DATA *p_data, UINT32 trans_id, UINT16 conn_id, BD_ADDR bd_addr)
{
tBA_WRITE_DATA cfg;
UINT8 *p = p_data->write_req.value;
tBA_INST *p_inst = &battery_cb.battery_inst[0];
UINT8 i;
esp_gatt_status_t st = ESP_GATT_NOT_FOUND;
UINT16 handle = p_data->write_req.handle;
for (i = 0; i < BA_MAX_INT_NUM; i ++, p_inst ++) {
if (handle == p_inst->clt_cfg_hdl) {
memcpy(cfg.remote_bda, bd_addr, BD_ADDR_LEN);
STREAM_TO_UINT16(cfg.clt_cfg, p);
if (p_inst->p_cback) {
p_inst->pending_evt = BA_WRITE_CLT_CFG_REQ;
p_inst->pending_handle = handle;
cfg.need_rsp = p_data->write_req.need_rsp;
(*p_inst->p_cback)(trans_id, conn_id, p_inst->app_id, p_inst->pending_evt, &cfg);
} else { /* all other handle is not writable */
st = ESP_GATT_WRITE_NOT_PERMIT;
}
break;
}
}
}
/***************************************************************
**
** Function bas_register
**
** Description register app for battery service
**
****************************************************************/
void bas_register(void)
{
esp_ble_gatts_app_register(&bas_uuid, bas_gatts_callback);
}
/***************************************************************
**
** Function bas_init
**
** Description register battery service
**
****************************************************************/
void bas_init(tBTA_GATTS_IF gatt_if, UINT16 app_id)
{
tBA_INST *p_inst;
ba_reg_info.is_pri = true;
ba_reg_info.ba_level_descr = BA_LEVEL_NOTIFY;
ba_reg_info.transport = GATT_TRANSPORT_LE;
ba_reg_info.p_cback = bas_callback;
if (battery_cb.inst_id == BA_MAX_INT_NUM) {
GATT_TRACE_ERROR("MAX battery service has been reached\n");
return;
}
p_inst = &battery_cb.battery_inst[battery_cb.inst_id];
BTC_TRACE_ERROR("create battery service\n");
BTC_TRACE_ERROR("inst_id=%d\n", battery_cb.inst_id);
esp_ble_gatts_create_srvc (gatt_if, &bas_uuid, battery_cb.inst_id ,
BA_MAX_ATTR_NUM, ba_reg_info.is_pri);
battery_cb.inst_id ++;
p_inst->app_id = app_id;
p_inst->p_cback = ba_reg_info.p_cback;
}
/***************************************************************
**
** Function bas_AddChar
**
** Description add characteristic for battery service
**
****************************************************************/
void bas_AddChar(UINT16 service_id, tBT_UUID *char_uuid)
{
if (ba_reg_info.ba_level_descr & BA_LEVEL_NOTIFY) {
prop |= GATT_CHAR_PROP_BIT_NOTIFY;
}
attr_handle_bit = 0x01;
esp_ble_gatts_add_char(service_id, char_uuid, BATTER_LEVEL_PERM, prop);
}
/***************************************************************
**
** Function bas_AddCharDescr
**
** Description add descriptor for battery service if needed
**
****************************************************************/
void bas_AddCharDescr(UINT16 service_id, UINT16 attr_id)
{
tBT_UUID uuid;
uuid.len = LEN_UUID_16;
battery_cb.inst_id --;
tBA_INST *p_inst = &battery_cb.battery_inst[battery_cb.inst_id++];
/*store the attribute handles*/
if (attr_handle_bit == 0x01) {
p_inst->ba_level_hdl = attr_id;
} else if (attr_handle_bit == 0x02) {
p_inst->clt_cfg_hdl = attr_id;
} else if (attr_handle_bit == 0x04) {
p_inst->pres_fmt_hdl = attr_id;
} else if (attr_handle_bit == 0x08) {
p_inst->rpt_ref_hdl = attr_id;
}
if (ba_reg_info.ba_level_descr != 0) {
if (ba_reg_info.ba_level_descr & BA_LEVEL_NOTIFY) {
uuid.uu.uuid16 = GATT_UUID_CHAR_CLIENT_CONFIG;
ba_reg_info.ba_level_descr &= 0xfe;
attr_handle_bit = 0x02;
esp_ble_gatts_add_char_descr(service_id, (GATT_PERM_READ | GATT_PERM_WRITE), &uuid);
return;
}
/* need presentation format descriptor? */
if (ba_reg_info.ba_level_descr & BA_LEVEL_PRE_FMT) {
uuid.uu.uuid16 = GATT_UUID_CHAR_PRESENT_FORMAT;
esp_ble_gatts_add_char_descr(service_id, GATT_PERM_READ, &uuid);
ba_reg_info.ba_level_descr &= 0xfd;
attr_handle_bit = 0x04;
return;
}
/* need report reference format descriptor? */
if (ba_reg_info.ba_level_descr & BA_LEVEL_RPT_REF) {
uuid.uu.uuid16 = GATT_UUID_RPT_REF_DESCR;
ba_reg_info.ba_level_descr &= 0xfb;
esp_ble_gatts_add_char_descr(service_id, GATT_PERM_READ, &uuid);
attr_handle_bit = 0x08;
return;
}
}
else {
esp_ble_gatts_start_srvc(service_id);
}
}
/***************************************************************
**
** Function bas_service_cmpl
**
** Description create battery service complete
**
****************************************************************/
void bas_service_cmpl(UINT16 service_id, esp_gatt_status_t status)
{
if (status != ESP_GATT_OK) {
battery_cb.inst_id --;
esp_ble_gatts_dele_srvc(service_id);
}
}
/*******************************************************************************
**
** Function Battery_Rsp
**
** Description Respond to a battery service request
**
*******************************************************************************/
void Battery_Rsp (UINT32 trans_id, UINT16 conn_id, UINT8 app_id,
esp_gatt_status_t st, UINT8 event, tBA_RSP_DATA *p_rsp)
{
tBA_INST *p_inst = &battery_cb.battery_inst[0];
tGATTS_RSP rsp;
UINT8 *pp;
UINT8 i = 0;
while (i < BA_MAX_INT_NUM) {
if (p_inst->app_id == app_id && p_inst->ba_level_hdl != 0) {
break;
}
i ++;
}
if (i == BA_MAX_INT_NUM) {
return;
}
memset(&rsp, 0, sizeof(tGATTS_RSP));
if (p_inst->pending_evt == event) {
switch (event) {
case BA_READ_CLT_CFG_REQ:
rsp.attr_value.handle = p_inst->pending_handle;
rsp.attr_value.len = 2;
pp = rsp.attr_value.value;
UINT16_TO_STREAM(pp, p_rsp->clt_cfg);
esp_ble_gatts_send_rsp(conn_id, trans_id, st, &rsp);
//srvc_sr_rsp(p_inst->pending_clcb_idx, st, &rsp);
break;
case BA_READ_LEVEL_REQ:
rsp.attr_value.handle = p_inst->pending_handle;
rsp.attr_value.len = 1;
pp = rsp.attr_value.value;
UINT8_TO_STREAM(pp, p_rsp->ba_level);
esp_ble_gatts_send_rsp(conn_id, trans_id, st, &rsp);
//srvc_sr_rsp(p_inst->pending_clcb_idx, st, &rsp);
break;
case BA_WRITE_CLT_CFG_REQ:
esp_ble_gatts_send_rsp(conn_id, trans_id, st, NULL);
//srvc_sr_rsp(p_inst->pending_clcb_idx, st, NULL);
break;
case BA_READ_RPT_REF_REQ:
rsp.attr_value.handle = p_inst->pending_handle;
rsp.attr_value.len = 2;
pp = rsp.attr_value.value;
UINT8_TO_STREAM(pp, p_rsp->rpt_ref.rpt_id);
UINT8_TO_STREAM(pp, p_rsp->rpt_ref.rpt_type);
esp_ble_gatts_send_rsp(conn_id, trans_id, st, &rsp);
//srvc_sr_rsp(p_inst->pending_clcb_idx, st, &rsp);
break;
default:
break;
}
// p_inst->pending_clcb_idx = 0;
p_inst->pending_evt = 0;
p_inst->pending_handle = 0;
}
return;
}
/*******************************************************************************
**
** Function Battery_Notify
**
** Description Send battery level notification
**
*******************************************************************************/
void Battery_Notify (UINT16 conn_id, UINT8 app_id, BD_ADDR remote_bda, UINT8 battery_level)
{
tBA_INST *p_inst = &battery_cb.battery_inst[0];
UINT8 i = 0;
while (i < BA_MAX_INT_NUM) {
if (p_inst->app_id == app_id && p_inst->ba_level_hdl != 0) {
break;
}
i ++;
}
if (i == BA_MAX_INT_NUM || p_inst->clt_cfg_hdl == 0) {
return;
}
esp_ble_gatts_hdl_val_indica(conn_id, p_inst->ba_level_hdl, 1, &battery_level, false);
//srvc_sr_notify(remote_bda, p_inst->ba_level_hdl, 1, &battery_level);
}
#endif
@@ -0,0 +1,79 @@
/******************************************************************************
*
* Copyright (C) 1999-2012 Broadcom Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
#ifndef SRVC_BATTERY_INT_H
#define SRVC_BATTERY_INT_H
#include "common/bt_target.h"
#include "srvc_api.h"
#include "stack/gatt_api.h"
#ifndef BA_MAX_INT_NUM
#define BA_MAX_INT_NUM 4
#endif
#define BATTERY_LEVEL_SIZE 1
typedef struct {
UINT8 app_id;
UINT16 ba_level_hdl;
UINT16 clt_cfg_hdl;
UINT16 rpt_ref_hdl;
UINT16 pres_fmt_hdl;
tBA_CBACK *p_cback;
UINT16 pending_handle;
UINT8 pending_clcb_idx;
UINT8 pending_evt;
} tBA_INST;
typedef struct {
tBA_INST battery_inst[BA_MAX_INT_NUM];
UINT8 inst_id;
BOOLEAN enabled;
} tBATTERY_CB;
#ifdef __cplusplus
extern "C" {
#endif
/* Global GATT data */
#if GATT_DYNAMIC_MEMORY == FALSE
extern tBATTERY_CB battery_cb;
#else
extern tBATTERY_CB *battery_cb_ptr;
#define battery_cb (*battery_cb_ptr)
#endif
extern BOOLEAN battery_valid_handle_range(UINT16 handle);
extern UINT8 battery_s_write_attr_value(UINT8 clcb_idx, tGATT_WRITE_REQ *p_value,
tGATT_STATUS *p_status);
extern UINT8 battery_s_read_attr_value (UINT8 clcb_idx, UINT16 handle, tGATT_VALUE *p_value, BOOLEAN is_long, tGATT_STATUS *p_status);
#ifdef __cplusplus
}
#endif
#endif
@@ -0,0 +1,291 @@
/******************************************************************************
*
* Copyright (C) 1999-2013 Broadcom Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
#include "common/bt_target.h"
//#include "bt_utils.h"
//#include "stack/gatt_api.h"
#define LOG_TAG "bt_srvc"
//#include "osi/include/log.h"
#include "stdio.h"
#include "stdint.h"
#include "string.h"
#include "bta/bta_api.h"
#include "bta/bta_gatt_api.h"
#include "device/controller.h"
#include "gatt_int.h"
#include "common/bt_trace.h"
#include "stack/btm_api.h"
#include "stack/bt_types.h"
#include "dis_api.h"
#if BLE_INCLUDED == TRUE
#define UINT64_TO_STREAM(p, u64) {*(p)++ = (UINT8)(u64); *(p)++ = (UINT8)((u64) >> 8);*(p)++ = (UINT8)((u64) >> 16); *(p)++ = (UINT8)((u64) >> 24); \
*(p)++ = (UINT8)((u64) >> 32); *(p)++ = (UINT8)((u64) >> 40);*(p)++ = (UINT8)((u64) >> 48); *(p)++ = (UINT8)((u64) >> 56);}
#define STREAM_TO_UINT64(u64, p) {u64 = (((UINT64)(*(p))) + ((((UINT64)(*((p) + 1)))) << 8) + ((((UINT64)(*((p) + 2)))) << 16) + ((((UINT64)(*((p) + 3)))) << 24) \
+ ((((UINT64)(*((p) + 4)))) << 32) + ((((UINT64)(*((p) + 5)))) << 40) + ((((UINT64)(*((p) + 6)))) << 48) + ((((UINT64)(*((p) + 7)))) << 56)); (p) += 8;}
esp_bt_uuid_t uuid = {LEN_UUID_16, {UUID_SERVCLASS_DEVICE_INFO}};
UINT16 i = 0;
tDIS_ATTR_MASK dis_mask;
static const UINT16 dis_attr_uuid[DIS_MAX_CHAR_NUM] = {
GATT_UUID_SYSTEM_ID,
GATT_UUID_MODEL_NUMBER_STR,
GATT_UUID_SERIAL_NUMBER_STR,
GATT_UUID_FW_VERSION_STR,
GATT_UUID_HW_VERSION_STR,
GATT_UUID_SW_VERSION_STR,
GATT_UUID_MANU_NAME,
GATT_UUID_IEEE_DATA,
GATT_UUID_PNP_ID
};
tDIS_CB dis_cb;
static tDIS_ATTR_MASK dis_uuid_to_attr(UINT16 uuid)
{
switch (uuid) {
case GATT_UUID_SYSTEM_ID:
return DIS_ATTR_SYS_ID_BIT;
case GATT_UUID_MODEL_NUMBER_STR:
return DIS_ATTR_MODEL_NUM_BIT;
case GATT_UUID_SERIAL_NUMBER_STR:
return DIS_ATTR_SERIAL_NUM_BIT;
case GATT_UUID_FW_VERSION_STR:
return DIS_ATTR_FW_NUM_BIT;
case GATT_UUID_HW_VERSION_STR:
return DIS_ATTR_HW_NUM_BIT;
case GATT_UUID_SW_VERSION_STR:
return DIS_ATTR_SW_NUM_BIT;
case GATT_UUID_MANU_NAME:
return DIS_ATTR_MANU_NAME_BIT;
case GATT_UUID_IEEE_DATA:
return DIS_ATTR_IEEE_DATA_BIT;
case GATT_UUID_PNP_ID:
return DIS_ATTR_PNP_ID_BIT;
default:
return 0;
};
}
/*******************************************************************************
** dis_valid_handle_range
**
** validate a handle to be a DIS attribute handle or not.
*******************************************************************************/
BOOLEAN dis_valid_handle_range(UINT16 handle)
{
if (handle >= dis_cb.service_handle && handle <= dis_cb.max_handle) {
return TRUE;
} else {
return FALSE;
}
}
/*******************************************************************************
** dis_write_attr_value
**
** Process write DIS attribute request.
*******************************************************************************/
UINT8 dis_write_attr_value(tGATT_WRITE_REQ *p_data, esp_gatt_status_t *p_status)
{
UNUSED(p_data);
*p_status = GATT_WRITE_NOT_PERMIT;
return ESP_GATT_OK;
}
/*******************************************************************************
** DIS Attributes Database Server Request callback
*******************************************************************************/
/*******************************************************************************
** dis_s_read_attr_value
**
** Process read DIS attribute request.
*******************************************************************************/
void dis_s_read_attr_value (tGATTS_DATA *p_data, tGATT_VALUE *p_value, UINT32 trans_id, UINT16 conn_id)
{
tDIS_DB_ENTRY *p_db_attr = dis_cb.dis_attr;
UINT8 *p = p_value->value, i, *pp;
UINT16 offset = p_data->read_req.offset;
tGATT_STATUS st = ESP_GATT_NOT_FOUND;
UINT16 handle = p_data->read_req.handle;
bool is_long = p_data->read_req.is_long;
for (i = 0; i < DIS_MAX_CHAR_NUM; i ++, p_db_attr ++) {
if (handle == p_db_attr->handle) {
if ((p_db_attr->uuid == GATT_UUID_PNP_ID || p_db_attr->uuid == GATT_UUID_SYSTEM_ID) &&
is_long == TRUE) {
st = ESP_GATT_NOT_LONG;
break;
}
st = ESP_GATT_NOT_FOUND;
switch (p_db_attr->uuid) {
case GATT_UUID_MANU_NAME:
case GATT_UUID_MODEL_NUMBER_STR:
case GATT_UUID_SERIAL_NUMBER_STR:
case GATT_UUID_FW_VERSION_STR:
case GATT_UUID_HW_VERSION_STR:
case GATT_UUID_SW_VERSION_STR:
case GATT_UUID_IEEE_DATA:
pp = dis_cb.dis_value.data_string[p_db_attr->uuid - GATT_UUID_MODEL_NUMBER_STR];
if (pp != NULL) {
if (strlen ((char *)pp) > GATT_MAX_ATTR_LEN) {
p_value->len = GATT_MAX_ATTR_LEN;
} else {
p_value->len = (UINT16)strlen ((char *)pp);
}
} else {
p_value->len = 0;
}
if (offset > p_value->len) {
st = ESP_GATT_INVALID_OFFSET;
break;
} else {
p_value->len -= offset;
pp += offset;
ARRAY_TO_STREAM(p, pp, p_value->len);
GATT_TRACE_EVENT("GATT_UUID_MANU_NAME len=0x%04x", p_value->len);
}
break;
case GATT_UUID_SYSTEM_ID:
UINT64_TO_STREAM(p, dis_cb.dis_value.system_id); /* int_min */
p_value->len = DIS_SYSTEM_ID_SIZE;
break;
case GATT_UUID_PNP_ID:
UINT8_TO_STREAM(p, dis_cb.dis_value.pnp_id.vendor_id_src);
UINT16_TO_STREAM(p, dis_cb.dis_value.pnp_id.vendor_id);
UINT16_TO_STREAM(p, dis_cb.dis_value.pnp_id.product_id);
UINT16_TO_STREAM(p, dis_cb.dis_value.pnp_id.product_version);
p_value->len = DIS_PNP_ID_SIZE;
break;
}
break;
}
}
tGATTS_RSP rsp;
rsp.attr_value = *p_value;
esp_ble_gatts_send_rsp(conn_id, trans_id, st, &rsp);
}
/*******************************************************************************
**
** Function DIS_Init
**
** Description Initialize the Device Information Service Server.
**
*******************************************************************************/
void DIS_Init (esp_gatts_if_t gatt_if, tDIS_ATTR_MASK dis_attr_mask)
{
tGATT_STATUS status;
dis_mask = dis_attr_mask;
if (dis_cb.enabled) {
GATT_TRACE_ERROR("DIS already initalized");
return;
}
memset(&dis_cb, 0, sizeof(tDIS_CB));
esp_ble_gatts_create_srvc (gatt_if , &uuid, 0, DIS_MAX_ATTR_NUM, TRUE);
}
/*******************************************************************************
**
** Function dis_AddChar
**
** Description add characteristic for dis
**
*******************************************************************************/
void dis_AddChar(UINT16 service_id)
{
//dis_cb.service_handle = service_id;
//dis_cb.max_handle = service_id + DIS_MAX_ATTR_NUM;
tDIS_DB_ENTRY *p_db_attr = &dis_cb.dis_attr[0];
while (dis_mask != 0 && i < DIS_MAX_CHAR_NUM) {
uuid.uu.uuid16 = p_db_attr->uuid = dis_attr_uuid[i];
esp_ble_gatts_add_char(dis_cb.service_handle, &uuid, GATT_PERM_READ,
GATT_CHAR_PROP_BIT_READ);
p_db_attr ++;
i ++;
dis_mask >>= 1;
}
/*start service*/
esp_ble_gatts_start_srvc(dis_cb.service_handle);
dis_cb.enabled = TRUE;
}
/*******************************************************************************
**
** Function DIS_SrUpdate
**
** Description Update the DIS server attribute values
**
*******************************************************************************/
tDIS_STATUS DIS_SrUpdate(tDIS_ATTR_BIT dis_attr_bit, tDIS_ATTR *p_info)
{
UINT8 i = 1;
tDIS_STATUS st = DIS_SUCCESS;
if (dis_attr_bit & DIS_ATTR_SYS_ID_BIT) {
dis_cb.dis_value.system_id = p_info->system_id;
} else if (dis_attr_bit & DIS_ATTR_PNP_ID_BIT) {
dis_cb.dis_value.pnp_id.vendor_id = p_info->pnp_id.vendor_id;
dis_cb.dis_value.pnp_id.vendor_id_src = p_info->pnp_id.vendor_id_src;
dis_cb.dis_value.pnp_id.product_id = p_info->pnp_id.product_id;
dis_cb.dis_value.pnp_id.product_version = p_info->pnp_id.product_version;
} else {
st = DIS_ILLEGAL_PARAM;
while (dis_attr_bit && i < (DIS_MAX_CHAR_NUM - 1 )) {
if (dis_attr_bit & (UINT16)(1 << i)) {
if (dis_cb.dis_value.data_string[i - 1] != NULL) {
osi_free(dis_cb.dis_value.data_string[i - 1]);
}
/* coverity[OVERRUN-STATIC] False-positive : when i = 8, (1 << i) == DIS_ATTR_PNP_ID_BIT, and it will never come down here
CID 49902: Out-of-bounds read (OVERRUN_STATIC)
Overrunning static array "dis_cb.dis_value.data_string", with 7 elements, at position 7 with index variable "i".
*/
if ((dis_cb.dis_value.data_string[i - 1] = (UINT8 *)osi_malloc((UINT16)(p_info->data_str.len + 1))) != NULL) {
memcpy(dis_cb.dis_value.data_string[i - 1], p_info->data_str.p_data, p_info->data_str.len);
dis_cb.dis_value.data_string[i - 1][p_info->data_str.len] = 0; /* make sure null terminate */
st = DIS_SUCCESS;
} else {
st = DIS_NO_RESOURCES;
}
break;
}
i ++;
}
}
return st;
}
#endif /* BLE_INCLUDED */
@@ -0,0 +1,82 @@
/******************************************************************************
*
* Copyright (C) 1999-2012 Broadcom Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
#ifndef SRVC_DIS_INT_H
#define SRVC_DIS_INT_H
#include "common/bt_target.h"
#include "srvc_api.h"
#include "stack/gatt_api.h"
#define DIS_MAX_CHAR_NUM 9
typedef struct {
UINT16 uuid;
UINT16 handle;
} tDIS_DB_ENTRY;
#define DIS_SYSTEM_ID_SIZE 8
#define DIS_PNP_ID_SIZE 7
typedef struct {
tDIS_DB_ENTRY dis_attr[DIS_MAX_CHAR_NUM];
tDIS_VALUE dis_value;
tDIS_READ_CBACK *p_read_dis_cback;
UINT16 service_handle;
UINT16 max_handle;
BOOLEAN enabled;
UINT8 dis_read_uuid_idx;
tDIS_ATTR_MASK request_mask;
} tDIS_CB;
#ifdef __cplusplus
extern "C" {
#endif
/* Global GATT data */
#if GATT_DYNAMIC_MEMORY == FALSE
extern tDIS_CB dis_cb;
#else
extern tDIS_CB *dis_cb_ptr;
#define dis_cb (*dis_cb_ptr)
#endif
extern BOOLEAN dis_valid_handle_range(UINT16 handle);
extern UINT8 dis_read_attr_value (UINT8 clcb_idx, UINT16 handle, tGATT_VALUE *p_value,
BOOLEAN is_long, tGATT_STATUS *p_status);
extern UINT8 dis_write_attr_value(tGATT_WRITE_REQ *p_data, tGATT_STATUS *p_status);
extern void dis_c_cmpl_cback (tSRVC_CLCB *p_clcb, tGATTC_OPTYPE op,
tGATT_STATUS status, tGATT_CL_COMPLETE *p_data);
#ifdef __cplusplus
}
#endif
#endif
@@ -0,0 +1,32 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <string.h>
#include "btc_gap_bt.h"
#include "btc/btc_util.h"
#if (BTC_GAP_BT_INCLUDED == TRUE)
void btc_gap_bt_config_eir_cmpl_callback (uint8_t status, uint8_t eir_type_num, uint8_t *eir_type)
{
esp_bt_gap_cb_param_t param;
bt_status_t ret;
btc_msg_t msg;
msg.sig = BTC_SIG_API_CB;
msg.pid = BTC_PID_GAP_BT;
msg.act = BTC_GAP_BT_CONFIG_EIR_DATA_EVT;
param.config_eir_data.stat = btc_bta_status_to_esp_status(status);
param.config_eir_data.eir_type_num = eir_type_num;
memcpy(param.config_eir_data.eir_type, eir_type, eir_type_num);
ret = btc_transfer_context(&msg, &param,
sizeof(esp_bt_gap_cb_param_t), NULL, NULL);
if (ret != BT_STATUS_SUCCESS) {
BTC_TRACE_ERROR("%s btc_transfer_context failed\n", __func__);
}
}
#endif /// (BTC_GAP_BT_INCLUDED == TRUE)
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,38 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "btc/btc_task.h"
#include "btc/btc_main.h"
#include "btc/btc_dm.h"
#include "osi/future.h"
#include "esp_err.h"
#include "btc/btc_config.h"
#include "osi/alarm.h"
#include "btc/btc_ble_storage.h"
#include "btc_gatt_common.h"
#include "bta/bta_gatt_common.h"
static void btc_set_local_mtu(uint16_t mtu)
{
BTA_GATT_SetLocalMTU(mtu);
}
void btc_gatt_com_call_handler(btc_msg_t *msg)
{
BTC_TRACE_DEBUG("%s act %d\n", __func__, msg->act);
switch (msg->act) {
case BTC_GATT_ACT_SET_LOCAL_MTU:
{
btc_ble_gatt_com_args_t *arg = (btc_ble_gatt_com_args_t *)(msg->arg);
btc_set_local_mtu(arg->set_mtu.mtu);
break;
}
default:
BTC_TRACE_ERROR("%s UNKNOWN ACT %d\n", __func__, msg->act);
break;
}
}
@@ -0,0 +1,193 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "btc_gatt_util.h"
#define GATTC_READ_VALUE_TYPE_VALUE 0x0000 /* Attribute value itself */
#define GATTC_READ_VALUE_TYPE_AGG_FORMAT 0x2905 /* Characteristic Aggregate Format*/
static const unsigned char BASE_UUID[16] = {
0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
/*******************************************************************************
* BTIF -> BTA conversion functions
*******************************************************************************/
int uuidType(unsigned char *p_uuid)
{
int i = 0;
int match = 0;
int all_zero = 1;
for (i = 0; i != 16; ++i) {
if (i == 12 || i == 13) {
continue;
}
if (p_uuid[i] == BASE_UUID[i]) {
++match;
}
if (p_uuid[i] != 0) {
all_zero = 0;
}
}
if (all_zero) {
return 0;
}
if (match == 12) {
return LEN_UUID_32;
}
if (match == 14) {
return LEN_UUID_16;
}
return LEN_UUID_128;
}
void btc128_to_bta_uuid(tBT_UUID *p_dest, uint8_t *p_src)
{
int i = 0;
p_dest->len = uuidType(p_src);
switch (p_dest->len) {
case LEN_UUID_16:
p_dest->uu.uuid16 = (p_src[13] << 8) + p_src[12];
break;
case LEN_UUID_32:
p_dest->uu.uuid32 = (p_src[13] << 8) + p_src[12];
p_dest->uu.uuid32 += (p_src[15] << 24) + (p_src[14] << 16);
break;
case LEN_UUID_128:
for (i = 0; i != 16; ++i) {
p_dest->uu.uuid128[i] = p_src[i];
}
break;
default:
BTC_TRACE_ERROR("%s: Unknown UUID length %d!", __FUNCTION__, p_dest->len);
break;
}
}
/*******************************************************************************
* BTC -> BTA conversion functions
*******************************************************************************/
void btc_to_bta_uuid(tBT_UUID *p_dest, esp_bt_uuid_t *p_src)
{
p_dest->len = p_src->len;
if (p_src->len == LEN_UUID_16) {
p_dest->uu.uuid16 = p_src->uuid.uuid16;
} else if (p_src->len == LEN_UUID_32) {
p_dest->uu.uuid32 = p_src->uuid.uuid32;
} else if (p_src->len == LEN_UUID_128) {
memcpy(&p_dest->uu.uuid128, p_src->uuid.uuid128, p_dest->len);
} else if (p_src->len == 0) {
/* do nothing for now, there's some scenario will input 0 */
} else {
BTC_TRACE_ERROR("%s UUID len is invalid %d\n", __func__, p_src->len);
}
}
void btc_to_bta_gatt_id(tBTA_GATT_ID *p_dest, esp_gatt_id_t *p_src)
{
p_dest->inst_id = p_src->inst_id;
btc_to_bta_uuid(&p_dest->uuid, &p_src->uuid);
}
void btc_to_bta_srvc_id(tBTA_GATT_SRVC_ID *p_dest, esp_gatt_srvc_id_t *p_src)
{
p_dest->is_primary = p_src->is_primary;
btc_to_bta_gatt_id(&p_dest->id, &p_src->id);
}
/*******************************************************************************
* BTA -> BTC conversion functions
*******************************************************************************/
void bta_to_btc_uuid(esp_bt_uuid_t *p_dest, tBT_UUID *p_src)
{
p_dest->len = p_src->len;
if (p_src->len == LEN_UUID_16) {
p_dest->uuid.uuid16 = p_src->uu.uuid16;
} else if (p_src->len == LEN_UUID_32) {
p_dest->uuid.uuid32 = p_src->uu.uuid32;
} else if (p_src->len == LEN_UUID_128) {
memcpy(&p_dest->uuid.uuid128, p_src->uu.uuid128, p_dest->len);
} else if (p_src->len == 0) {
/* do nothing for now, there's some scenario will input 0
such as, receive notify, the descriptor may be 0 */
} else {
BTC_TRACE_ERROR("%s UUID len is invalid %d\n", __func__, p_src->len);
}
}
void bta_to_btc_gatt_id(esp_gatt_id_t *p_dest, tBTA_GATT_ID *p_src)
{
p_dest->inst_id = p_src->inst_id;
bta_to_btc_uuid(&p_dest->uuid, &p_src->uuid);
}
void bta_to_btc_srvc_id(esp_gatt_srvc_id_t *p_dest, tBTA_GATT_SRVC_ID *p_src)
{
p_dest->is_primary = p_src->is_primary;
bta_to_btc_gatt_id(&p_dest->id, &p_src->id);
}
void btc_to_bta_response(tBTA_GATTS_RSP *p_dest, esp_gatt_rsp_t *p_src)
{
p_dest->attr_value.auth_req = p_src->attr_value.auth_req;
p_dest->attr_value.handle = p_src->attr_value.handle;
p_dest->attr_value.len = p_src->attr_value.len;
p_dest->attr_value.offset = p_src->attr_value.offset;
memcpy(p_dest->attr_value.value, p_src->attr_value.value, ESP_GATT_MAX_ATTR_LEN);
}
uint16_t get_uuid16(tBT_UUID *p_uuid)
{
if (p_uuid->len == LEN_UUID_16) {
return p_uuid->uu.uuid16;
} else if (p_uuid->len == LEN_UUID_128) {
UINT16 u16;
UINT8 *p = &p_uuid->uu.uuid128[LEN_UUID_128 - 4];
STREAM_TO_UINT16(u16, p);
return u16;
} else { /* p_uuid->len == LEN_UUID_32 */
return (UINT16) p_uuid->uu.uuid32;
}
}
uint16_t set_read_value(uint8_t *gattc_if, esp_ble_gattc_cb_param_t *p_dest, tBTA_GATTC_READ *p_src)
{
uint16_t len = 0;
p_dest->read.status = p_src->status;
p_dest->read.conn_id = BTC_GATT_GET_CONN_ID(p_src->conn_id);
*gattc_if = BTC_GATT_GET_GATT_IF(p_src->conn_id);
p_dest->read.status = p_src->status;
p_dest->read.handle = p_src->handle;
if (( p_src->status == BTA_GATT_OK ) && (p_src->p_value != NULL))
{
BTC_TRACE_DEBUG("%s len = %d ", __func__, p_src->p_value->len);
p_dest->read.value_len = p_src->p_value->len;
if ( p_src->p_value->len > 0 && p_src->p_value->p_value != NULL ) {
p_dest->read.value = p_src->p_value->p_value;
}
len += p_src->p_value->len;
} else {
p_dest->read.value_len = 0;
}
return len;
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,992 @@
/*
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <string.h>
#include "bta/bta_gatt_api.h"
#include "btc/btc_task.h"
#include "btc/btc_manage.h"
#include "btc_gatts.h"
#include "btc_gatt_util.h"
#include "osi/future.h"
#include "osi/allocator.h"
#include "btc/btc_main.h"
#include "esp_gatts_api.h"
#include "btc/btc_storage.h"
#include "common/bt_defs.h"
#if (GATTS_INCLUDED == TRUE)
#define A2C_GATTS_EVT(_bta_event) (_bta_event) //BTA TO BTC EVT
#define C2A_GATTS_EVT(_btc_event) (_btc_event) //BTC TO BTA EVT
#if GATT_DYNAMIC_MEMORY == FALSE
static esp_btc_creat_tab_t btc_creat_tab_env;
#else
esp_btc_creat_tab_t *btc_creat_tab_env_ptr;
#endif
static esp_gatt_status_t btc_gatts_check_valid_attr_tab(esp_gatts_attr_db_t *gatts_attr_db,
uint8_t max_nb_attr);
static inline void btc_gatts_cb_to_app(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param)
{
esp_gatts_cb_t btc_gatts_cb = (esp_gatts_cb_t)btc_profile_cb_get(BTC_PID_GATTS);
if (btc_gatts_cb) {
btc_gatts_cb(event, gatts_if, param);
}
}
static inline void btc_gatts_uuid_format_convert(esp_bt_uuid_t* dest_uuid, uint16_t src_uuid_len, uint8_t* src_uuid_p)
{
dest_uuid->len = src_uuid_len;
if(src_uuid_len == ESP_UUID_LEN_16){
dest_uuid->uuid.uuid16 = src_uuid_p[0] + (src_uuid_p[1]<<8);
}
else if(src_uuid_len == ESP_UUID_LEN_32){
dest_uuid->uuid.uuid32 = src_uuid_p[0] + (src_uuid_p[1]<<8) + (src_uuid_p[2]<<16) + (src_uuid_p[3]<<24);
}
else if(src_uuid_len == ESP_UUID_LEN_128){
memcpy(dest_uuid->uuid.uuid128, src_uuid_p, src_uuid_len);
}
else{
BTC_TRACE_ERROR("%s wrong uuid length %d\n", __func__, src_uuid_len);
}
}
void btc_gatts_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src)
{
btc_ble_gatts_args_t *dst = (btc_ble_gatts_args_t *) p_dest;
btc_ble_gatts_args_t *src = (btc_ble_gatts_args_t *)p_src;
switch (msg->act) {
case BTC_GATTS_ACT_SEND_INDICATE: {
if (src->send_ind.value && (src->send_ind.value_len > 0)) {
dst->send_ind.value = (uint8_t *) osi_malloc(src->send_ind.value_len);
if (dst->send_ind.value) {
memcpy(dst->send_ind.value, src->send_ind.value, src->send_ind.value_len);
} else {
BTC_TRACE_ERROR("%s %d no mem\n", __func__, msg->act);
}
} else {
dst->send_ind.value = NULL;
if (src->send_ind.value) {
BTC_TRACE_ERROR("%s %d, invalid length", __func__, msg->act);
}
}
break;
}
case BTC_GATTS_ACT_SEND_RESPONSE: {
if (src->send_rsp.rsp) {
dst->send_rsp.rsp = (esp_gatt_rsp_t *) osi_malloc(sizeof(esp_gatt_rsp_t));
if (dst->send_rsp.rsp) {
memcpy(dst->send_rsp.rsp, src->send_rsp.rsp, sizeof(esp_gatt_rsp_t));
} else {
BTC_TRACE_ERROR("%s %d no mem\n", __func__, msg->act);
}
}
break;
}
case BTC_GATTS_ACT_ADD_CHAR: {
if (src->add_char.char_val.attr_value && (src->add_char.char_val.attr_len > 0)) {
dst->add_char.char_val.attr_value = (uint8_t *) osi_malloc(src->add_char.char_val.attr_len);
if (dst->add_char.char_val.attr_value) {
memcpy(dst->add_char.char_val.attr_value, src->add_char.char_val.attr_value,
src->add_char.char_val.attr_len);
} else {
BTC_TRACE_ERROR("%s %d no mem\n", __func__, msg->act);
}
} else {
dst->add_char.char_val.attr_value = NULL;
if (src->add_char.char_val.attr_value) {
BTC_TRACE_ERROR("%s %d, invalid length", __func__, msg->act);
}
}
break;
}
case BTC_GATTS_ACT_ADD_CHAR_DESCR: {
if (src->add_descr.descr_val.attr_value && (src->add_descr.descr_val.attr_len > 0)) {
dst->add_descr.descr_val.attr_value = (uint8_t *) osi_malloc(src->add_descr.descr_val.attr_len);
if (dst->add_descr.descr_val.attr_value) {
memcpy(dst->add_descr.descr_val.attr_value, src->add_descr.descr_val.attr_value,
src->add_descr.descr_val.attr_len);
} else {
BTC_TRACE_ERROR("%s %d no mem\n", __func__, msg->act);
}
} else {
dst->add_descr.descr_val.attr_value = NULL;
if (src->add_descr.descr_val.attr_value) {
BTC_TRACE_ERROR("%s %d, invalid length", __func__, msg->act);
}
}
break;
}
case BTC_GATTS_ACT_CREATE_ATTR_TAB: {
uint16_t num_attr = src->create_attr_tab.max_nb_attr;
if (src->create_attr_tab.gatts_attr_db && (num_attr > 0)) {
dst->create_attr_tab.gatts_attr_db = (esp_gatts_attr_db_t *) osi_malloc(sizeof(esp_gatts_attr_db_t) * num_attr);
if (dst->create_attr_tab.gatts_attr_db) {
memcpy(dst->create_attr_tab.gatts_attr_db, src->create_attr_tab.gatts_attr_db,
sizeof(esp_gatts_attr_db_t) * num_attr);
} else {
BTC_TRACE_ERROR("%s %d no mem\n",__func__, msg->act);
}
} else {
BTC_TRACE_ERROR("%s %d, NULL data", __func__, msg->act);
}
break;
}
case BTC_GATTS_ACT_SET_ATTR_VALUE: {
if (src->set_attr_val.value && (src->set_attr_val.length > 0)) {
dst->set_attr_val.value = (uint8_t *) osi_malloc(src->set_attr_val.length);
if (dst->set_attr_val.value) {
memcpy(dst->set_attr_val.value, src->set_attr_val.value, src->set_attr_val.length);
} else {
BTC_TRACE_ERROR("%s %d no mem\n",__func__, msg->act);
}
} else {
dst->set_attr_val.value = NULL;
if (src->set_attr_val.value) {
BTC_TRACE_ERROR("%s %d, invalid length", __func__, msg->act);
} else {
BTC_TRACE_WARNING("%s %d, NULL value", __func__, msg->act);
}
}
break;
}
default:
BTC_TRACE_DEBUG("%s Unhandled deep copy %d\n", __func__, msg->act);
break;
}
}
void btc_gatts_arg_deep_free(btc_msg_t *msg)
{
btc_ble_gatts_args_t *arg = (btc_ble_gatts_args_t *)msg->arg;
switch (msg->act) {
case BTC_GATTS_ACT_SEND_INDICATE: {
if (arg->send_ind.value) {
osi_free(arg->send_ind.value);
}
break;
}
case BTC_GATTS_ACT_SEND_RESPONSE: {
if (arg->send_rsp.rsp) {
osi_free(arg->send_rsp.rsp);
}
break;
}
case BTC_GATTS_ACT_ADD_CHAR:{
if (arg->add_char.char_val.attr_value != NULL) {
osi_free(arg->add_char.char_val.attr_value);
}
break;
}
case BTC_GATTS_ACT_ADD_CHAR_DESCR:{
if (arg->add_descr.descr_val.attr_value != NULL){
osi_free(arg->add_descr.descr_val.attr_value);
}
break;
}
case BTC_GATTS_ACT_CREATE_ATTR_TAB:{
if (arg->create_attr_tab.gatts_attr_db != NULL){
osi_free(arg->create_attr_tab.gatts_attr_db);
}
break;
}
case BTC_GATTS_ACT_SET_ATTR_VALUE:{
if (arg->set_attr_val.value != NULL){
osi_free(arg->set_attr_val.value);
}
}
break;
default:
BTC_TRACE_DEBUG("%s Unhandled deep free %d\n", __func__, msg->act);
break;
}
}
static void btc_gatts_act_create_attr_tab(esp_gatts_attr_db_t *gatts_attr_db,
esp_gatt_if_t gatts_if,
uint16_t max_nb_attr,
uint8_t srvc_inst_id)
{
uint16_t uuid = 0;
future_t *future_p;
esp_ble_gatts_cb_param_t param;
param.add_attr_tab.status = ESP_GATT_OK;
param.add_attr_tab.num_handle = max_nb_attr;
if (param.add_attr_tab.status != ESP_GATT_OK) {
btc_gatts_cb_to_app(ESP_GATTS_CREAT_ATTR_TAB_EVT, gatts_if, &param);
//reset the env after sent the data to app
memset(&btc_creat_tab_env, 0, sizeof(esp_btc_creat_tab_t));
return;
}
// Check the attribute table is valid or not
if ((param.add_attr_tab.status = btc_gatts_check_valid_attr_tab(gatts_attr_db, max_nb_attr)) != ESP_GATT_OK) {
//sent the callback event to the application
btc_gatts_cb_to_app(ESP_GATTS_CREAT_ATTR_TAB_EVT, gatts_if, &param);
return;
}
//set the attribute table create service flag to true
btc_creat_tab_env.is_tab_creat_svc = true;
btc_creat_tab_env.num_handle = max_nb_attr;
for(int i = 0; i < max_nb_attr; i++){
if(gatts_attr_db[i].att_desc.uuid_length == ESP_UUID_LEN_16){
uuid = (gatts_attr_db[i].att_desc.uuid_p[1] << 8) + (gatts_attr_db[i].att_desc.uuid_p[0]);
}
else{
continue;
}
future_p = future_new();
if (future_p == NULL) {
BTC_TRACE_ERROR("%s failed:no mem\n", __func__);
return ;
}
btc_creat_tab_env.complete_future = future_p;
btc_creat_tab_env.handle_idx = i;
switch(uuid)
{
case ESP_GATT_UUID_PRI_SERVICE:{
tBTA_GATT_SRVC_ID srvc_id;
esp_gatt_srvc_id_t esp_srvc_id;
esp_srvc_id.id.inst_id = srvc_inst_id;
btc_gatts_uuid_format_convert(&esp_srvc_id.id.uuid,gatts_attr_db[i].att_desc.length,
gatts_attr_db[i].att_desc.value);
btc_to_bta_srvc_id(&srvc_id, &esp_srvc_id);
if (btc_creat_tab_env.is_use_svc != true) {
BTA_GATTS_CreateService(gatts_if, &srvc_id.id.uuid,
srvc_inst_id, max_nb_attr, true);
btc_creat_tab_env.is_use_svc = true;
} else {
BTC_TRACE_ERROR("Each service table can only created one primary service.");
param.add_attr_tab.status = ESP_GATT_ERROR;
btc_gatts_cb_to_app(ESP_GATTS_CREAT_ATTR_TAB_EVT, gatts_if, &param);
//reset the env after sent the data to app
memset(&btc_creat_tab_env, 0, sizeof(esp_btc_creat_tab_t));
return;
}
if (future_await(future_p) == FUTURE_FAIL) {
BTC_TRACE_ERROR("%s failed\n", __func__);
return;
}
break;
}
case ESP_GATT_UUID_SEC_SERVICE:{
tBTA_GATT_SRVC_ID srvc_id = {0};
esp_gatt_srvc_id_t esp_srvc_id;
esp_srvc_id.id.inst_id = srvc_inst_id;
btc_gatts_uuid_format_convert(&esp_srvc_id.id.uuid,gatts_attr_db[i].att_desc.length,
gatts_attr_db[i].att_desc.value);
btc_to_bta_srvc_id(&srvc_id, &esp_srvc_id);
if (btc_creat_tab_env.is_use_svc != true) {
BTA_GATTS_CreateService(gatts_if, &srvc_id.id.uuid,
srvc_inst_id, max_nb_attr, false);
btc_creat_tab_env.is_use_svc = true;
} else {
BTC_TRACE_ERROR("Each service table can only created one secondary service.");
param.add_attr_tab.status = ESP_GATT_ERROR;
btc_gatts_cb_to_app(ESP_GATTS_CREAT_ATTR_TAB_EVT, gatts_if, &param);
//reset the env after sent the data to app
memset(&btc_creat_tab_env, 0, sizeof(esp_btc_creat_tab_t));
return;
}
if (future_await(future_p) == FUTURE_FAIL) {
BTC_TRACE_ERROR("%s failed\n", __func__);
return;
}
break;
}
case ESP_GATT_UUID_INCLUDE_SERVICE:{
esp_gatts_incl_svc_desc_t *incl_svc_desc = (esp_gatts_incl_svc_desc_t *)gatts_attr_db[i].att_desc.value;
if(incl_svc_desc!= NULL){
if(btc_creat_tab_env.svc_start_hdl != 0){
BTA_GATTS_AddIncludeService(btc_creat_tab_env.svc_start_hdl,
incl_svc_desc->start_hdl);
if (future_await(future_p) == FUTURE_FAIL) {
BTC_TRACE_ERROR("%s failed\n", __func__);
return;
}
}
}
break;
}
case ESP_GATT_UUID_CHAR_DECLARE:{
uint16_t svc_hal = 0;
tBT_UUID bta_char_uuid;
tGATT_ATTR_VAL attr_val;
esp_bt_uuid_t uuid_temp;
tBTA_GATT_PERM perm;
tBTA_GATTS_ATTR_CONTROL control;
uint8_t char_property;
if(btc_creat_tab_env.svc_start_hdl != 0){
svc_hal = btc_creat_tab_env.svc_start_hdl;
if((gatts_attr_db[i].att_desc.value) == NULL){
BTC_TRACE_ERROR("%s Characteristic declaration should not be NULL\n", __func__);
}
else{
char_property = (uint8_t)(*(uint8_t*)(gatts_attr_db[i].att_desc.value));
perm = gatts_attr_db[i+1].att_desc.perm;
attr_val.attr_len = gatts_attr_db[i+1].att_desc.length;
attr_val.attr_max_len = gatts_attr_db[i+1].att_desc.max_length;
btc_gatts_uuid_format_convert(&uuid_temp, gatts_attr_db[i+1].att_desc.uuid_length,gatts_attr_db[i+1].att_desc.uuid_p);
btc_to_bta_uuid(&bta_char_uuid, &uuid_temp);
attr_val.attr_val = gatts_attr_db[i+1].att_desc.value;
control.auto_rsp = gatts_attr_db[i+1].attr_control.auto_rsp;
BTA_GATTS_AddCharacteristic (svc_hal, &bta_char_uuid,
perm, char_property, &attr_val, &control);
if (future_await(future_p) == FUTURE_FAIL) {
BTC_TRACE_ERROR("%s failed\n", __func__);
return;
}
}
}
break;
}
case ESP_GATT_UUID_CHAR_EXT_PROP:
case ESP_GATT_UUID_CHAR_DESCRIPTION:
case ESP_GATT_UUID_CHAR_CLIENT_CONFIG:
case ESP_GATT_UUID_CHAR_SRVR_CONFIG:
case ESP_GATT_UUID_CHAR_PRESENT_FORMAT:
case ESP_GATT_UUID_CHAR_AGG_FORMAT:
case ESP_GATT_UUID_CHAR_VALID_RANGE:
case ESP_GATT_UUID_EXT_RPT_REF_DESCR:
case ESP_GATT_UUID_RPT_REF_DESCR:
case ESP_GATT_UUID_NUM_DIGITALS_DESCR:
case ESP_GATT_UUID_VALUE_TRIGGER_DESCR:
case ESP_GATT_UUID_ENV_SENSING_CONFIG_DESCR:
case ESP_GATT_UUID_ENV_SENSING_MEASUREMENT_DESCR:
case ESP_GATT_UUID_ENV_SENSING_TRIGGER_DESCR:
case ESP_GATT_UUID_TIME_TRIGGER_DESCR: {
uint16_t svc_hal = btc_creat_tab_env.svc_start_hdl;
tBT_UUID bta_char_uuid;
esp_bt_uuid_t uuid_temp;
tGATT_ATTR_VAL attr_val;
tBTA_GATT_PERM perm = gatts_attr_db[i].att_desc.perm;
tBTA_GATTS_ATTR_CONTROL control;
if(svc_hal != 0){
attr_val.attr_len = gatts_attr_db[i].att_desc.length;
attr_val.attr_max_len = gatts_attr_db[i].att_desc.max_length;
attr_val.attr_val = gatts_attr_db[i].att_desc.value;
btc_gatts_uuid_format_convert(&uuid_temp, gatts_attr_db[i].att_desc.uuid_length,
gatts_attr_db[i].att_desc.uuid_p);
btc_to_bta_uuid(&bta_char_uuid, &uuid_temp);
control.auto_rsp = gatts_attr_db[i].attr_control.auto_rsp;
BTA_GATTS_AddCharDescriptor(svc_hal, perm, &bta_char_uuid, &attr_val, &control);
if (future_await(future_p) == FUTURE_FAIL) {
BTC_TRACE_ERROR("%s failed\n", __func__);
return;
}
}
break;
}
default:
future_free(future_p);
break;
}
}
param.add_attr_tab.handles = btc_creat_tab_env.handles;
memcpy(&param.add_attr_tab.svc_uuid, &btc_creat_tab_env.svc_uuid, sizeof(esp_bt_uuid_t));
param.add_attr_tab.svc_inst_id = srvc_inst_id;
btc_gatts_cb_to_app(ESP_GATTS_CREAT_ATTR_TAB_EVT, gatts_if, &param);
//reset the env after sent the data to app
memset(&btc_creat_tab_env, 0, sizeof(esp_btc_creat_tab_t));
//set the flag value to false after the service is created.
btc_creat_tab_env.is_tab_creat_svc = false;
}
static esp_gatt_status_t btc_gatts_check_valid_attr_tab(esp_gatts_attr_db_t *gatts_attr_db,
uint8_t max_nb_attr)
{
uint8_t svc_num = 0;
uint16_t uuid = 0;
for(int i = 0; i < max_nb_attr; i++) {
if(gatts_attr_db[i].att_desc.uuid_length != ESP_UUID_LEN_16) {
continue;
}
uuid = (gatts_attr_db[i].att_desc.uuid_p[1] << 8) + (gatts_attr_db[i].att_desc.uuid_p[0]);
switch(uuid) {
case ESP_GATT_UUID_PRI_SERVICE:
case ESP_GATT_UUID_SEC_SERVICE:
if (++svc_num > 1) {
BTC_TRACE_ERROR("Each service table can only created one primary service or secondary service.");
return ESP_GATT_ERROR;
}
break;
case ESP_GATT_UUID_INCLUDE_SERVICE: {
esp_gatts_incl_svc_desc_t *svc_desc = (esp_gatts_incl_svc_desc_t *)gatts_attr_db[i].att_desc.value;
if(svc_desc == NULL) {
BTC_TRACE_ERROR("%s, The include service attribute should not be NULL.", __func__);
return ESP_GATT_INVALID_PDU;
} else if((svc_desc->start_hdl == 0) || (svc_desc->end_hdl == 0) ||
(svc_desc->start_hdl == svc_desc->end_hdl)) {
BTC_TRACE_ERROR("%s, The include service attribute handle is invalid, start_hanlde = %d, end_handle = %d",\
__func__, svc_desc->start_hdl, svc_desc->end_hdl);
return ESP_GATT_INVALID_HANDLE;
}
break;
}
case ESP_GATT_UUID_CHAR_DECLARE:
if((gatts_attr_db[i].att_desc.value) == NULL) {
BTC_TRACE_ERROR("%s, Characteristic declaration should not be NULL.", __func__);
return ESP_GATT_INVALID_PDU;
}
if(gatts_attr_db[i+1].att_desc.uuid_length != ESP_UUID_LEN_16 &&
gatts_attr_db[i+1].att_desc.uuid_length != ESP_UUID_LEN_32 &&
gatts_attr_db[i+1].att_desc.uuid_length != ESP_UUID_LEN_128) {
BTC_TRACE_ERROR("%s, The Charateristic uuid length = %d is invalid", __func__,\
gatts_attr_db[i+1].att_desc.uuid_length);
return ESP_GATT_INVALID_ATTR_LEN;
}
if(gatts_attr_db[i+1].att_desc.uuid_length == ESP_UUID_LEN_16) {
uuid = (gatts_attr_db[i+1].att_desc.uuid_p[1] << 8) + (gatts_attr_db[i+1].att_desc.uuid_p[0]);
if(uuid == ESP_GATT_UUID_CHAR_DECLARE || uuid == ESP_GATT_UUID_CHAR_EXT_PROP ||
uuid == ESP_GATT_UUID_CHAR_DESCRIPTION || uuid == ESP_GATT_UUID_CHAR_CLIENT_CONFIG ||
uuid == ESP_GATT_UUID_CHAR_SRVR_CONFIG || uuid == ESP_GATT_UUID_CHAR_PRESENT_FORMAT ||
uuid == ESP_GATT_UUID_CHAR_AGG_FORMAT || uuid == ESP_GATT_UUID_CHAR_VALID_RANGE ||
uuid == ESP_GATT_UUID_EXT_RPT_REF_DESCR || uuid == ESP_GATT_UUID_RPT_REF_DESCR) {
BTC_TRACE_ERROR("%s, The charateristic value uuid = %d is invalid", __func__, uuid);
return ESP_GATT_INVALID_PDU;
}
}
break;
default:
break;
}
}
return ESP_GATT_OK;
}
esp_gatt_status_t btc_gatts_get_attr_value(uint16_t attr_handle, uint16_t *length, uint8_t **value)
{
return BTA_GetAttributeValue(attr_handle, length, value);
}
esp_gatt_status_t btc_gatts_show_local_database(void)
{
BTA_GATTS_ShowLocalDatabase();
return ESP_GATT_OK;
}
static void btc_gatts_cb_param_copy_req(btc_msg_t *msg, void *p_dest, void *p_src)
{
uint16_t event = msg->act;
tBTA_GATTS *p_dest_data = (tBTA_GATTS *) p_dest;
tBTA_GATTS *p_src_data = (tBTA_GATTS *) p_src;
if (!p_src_data || !p_dest_data) {
return;
}
// Copy basic structure first
memcpy(p_dest_data, p_src_data, sizeof(tBTA_GATTS));
// Allocate buffer for request data if necessary
switch (event) {
case BTA_GATTS_READ_EVT:
case BTA_GATTS_WRITE_EVT:
case BTA_GATTS_EXEC_WRITE_EVT:
case BTA_GATTS_MTU_EVT:
p_dest_data->req_data.p_data = osi_malloc(sizeof(tBTA_GATTS_REQ_DATA));
if (p_dest_data->req_data.p_data != NULL) {
memcpy(p_dest_data->req_data.p_data, p_src_data->req_data.p_data,
sizeof(tBTA_GATTS_REQ_DATA));
} else {
BTC_TRACE_ERROR("%s %d no mem\n", __func__, msg->act);
}
break;
default:
break;
}
}
static void btc_gatts_cb_param_copy_free(btc_msg_t *msg)
{
uint16_t event = msg->act;
tBTA_GATTS *p_data = (tBTA_GATTS *)msg->arg;
switch (event) {
case BTA_GATTS_READ_EVT:
case BTA_GATTS_WRITE_EVT:
case BTA_GATTS_EXEC_WRITE_EVT:
case BTA_GATTS_MTU_EVT:
if (p_data && p_data->req_data.p_data) {
osi_free(p_data->req_data.p_data);
}
break;
case BTA_GATTS_CONF_EVT:
break;
default:
break;
}
}
static void btc_gatts_inter_cb(tBTA_GATTS_EVT event, tBTA_GATTS *p_data)
{
bt_status_t status;
btc_msg_t msg = {0};
msg.sig = BTC_SIG_API_CB;
msg.pid = BTC_PID_GATTS;
msg.act = event;
if(btc_creat_tab_env.is_tab_creat_svc && btc_creat_tab_env.complete_future) {
switch(event) {
case BTA_GATTS_CREATE_EVT: {
//save the service handle to the btc module after used
//the attribute table method to creat a service
bta_to_btc_uuid(&btc_creat_tab_env.svc_uuid, &p_data->create.uuid);
uint16_t index = btc_creat_tab_env.handle_idx;
btc_creat_tab_env.svc_start_hdl = p_data->create.service_id;
btc_creat_tab_env.handles[index] = p_data->create.service_id;
break;
}
case BTA_GATTS_ADD_INCL_SRVC_EVT: {
uint16_t index = btc_creat_tab_env.handle_idx;
btc_creat_tab_env.handles[index] = p_data->add_result.attr_id;
break;
}
case BTA_GATTS_ADD_CHAR_EVT: {
uint16_t index = btc_creat_tab_env.handle_idx;
btc_creat_tab_env.handles[index] = p_data->add_result.attr_id - 1;
btc_creat_tab_env.handles[index+1] = p_data->add_result.attr_id;
break;
}
case BTA_GATTS_ADD_CHAR_DESCR_EVT: {
uint16_t index = btc_creat_tab_env.handle_idx;
btc_creat_tab_env.handles[index] = p_data->add_result.attr_id;
break;
}
default:
break;
}
future_ready(btc_creat_tab_env.complete_future, FUTURE_SUCCESS);
return;
}
status = btc_transfer_context(&msg, p_data, sizeof(tBTA_GATTS),
btc_gatts_cb_param_copy_req, btc_gatts_cb_param_copy_free);
if (status != BT_STATUS_SUCCESS) {
BTC_TRACE_ERROR("%s btc_transfer_context failed\n", __func__);
}
}
void btc_gatts_call_handler(btc_msg_t *msg)
{
btc_ble_gatts_args_t *arg = (btc_ble_gatts_args_t *)msg->arg;
switch (msg->act) {
case BTC_GATTS_ACT_APP_REGISTER: {
tBT_UUID uuid;
uuid.len = LEN_UUID_16;
uuid.uu.uuid16 = arg->app_reg.app_id;
BTA_GATTS_AppRegister(&uuid, btc_gatts_inter_cb);
break;
}
case BTC_GATTS_ACT_APP_UNREGISTER:
BTA_GATTS_AppDeregister(arg->app_unreg.gatts_if);
break;
case BTC_GATTS_ACT_CREATE_SERVICE: {
tBTA_GATT_SRVC_ID srvc_id;
btc_to_bta_srvc_id(&srvc_id, &arg->create_srvc.service_id);
BTA_GATTS_CreateService(arg->create_srvc.gatts_if, &srvc_id.id.uuid,
srvc_id.id.inst_id, arg->create_srvc.num_handle,
srvc_id.is_primary);
break;
}
case BTC_GATTS_ACT_CREATE_ATTR_TAB:
btc_gatts_act_create_attr_tab(arg->create_attr_tab.gatts_attr_db,
arg->create_attr_tab.gatts_if,
arg->create_attr_tab.max_nb_attr,
arg->create_attr_tab.srvc_inst_id);
break;
case BTC_GATTS_ACT_DELETE_SERVICE:
BTA_GATTS_DeleteService(arg->delete_srvc.service_handle);
break;
case BTC_GATTS_ACT_START_SERVICE:
BTA_GATTS_StartService(arg->start_srvc.service_handle, BTA_GATT_TRANSPORT_LE);
break;
case BTC_GATTS_ACT_STOP_SERVICE:
BTA_GATTS_StopService(arg->stop_srvc.service_handle);
break;
case BTC_GATTS_ACT_ADD_INCLUDE_SERVICE:
BTA_GATTS_AddIncludeService(arg->add_incl_srvc.service_handle, arg->add_incl_srvc.included_service_handle);
break;
case BTC_GATTS_ACT_ADD_CHAR: {
tBT_UUID uuid;
btc_to_bta_uuid(&uuid, &arg->add_char.char_uuid);
BTA_GATTS_AddCharacteristic(arg->add_char.service_handle, &uuid,
arg->add_char.perm, arg->add_char.property,
(tGATT_ATTR_VAL *)&arg->add_char.char_val,
(tBTA_GATTS_ATTR_CONTROL *)&arg->add_char.attr_control);
break;
}
case BTC_GATTS_ACT_ADD_CHAR_DESCR: {
tBT_UUID uuid;
btc_to_bta_uuid(&uuid, &arg->add_descr.descr_uuid);
BTA_GATTS_AddCharDescriptor(arg->add_descr.service_handle, arg->add_descr.perm, &uuid,
(tBTA_GATT_ATTR_VAL *)&arg->add_descr.descr_val,
(tBTA_GATTS_ATTR_CONTROL *)&arg->add_descr.attr_control);
break;
}
case BTC_GATTS_ACT_SEND_INDICATE:
BTA_GATTS_HandleValueIndication(arg->send_ind.conn_id, arg->send_ind.attr_handle,
arg->send_ind.value_len, arg->send_ind.value, arg->send_ind.need_confirm);
break;
case BTC_GATTS_ACT_SEND_RESPONSE: {
esp_ble_gatts_cb_param_t param;
esp_gatt_rsp_t *p_rsp = arg->send_rsp.rsp;
if (p_rsp) {
tBTA_GATTS_RSP rsp_struct;
btc_to_bta_response(&rsp_struct, p_rsp);
BTA_GATTS_SendRsp(arg->send_rsp.conn_id, arg->send_rsp.trans_id,
arg->send_rsp.status, &rsp_struct);
param.rsp.handle = rsp_struct.attr_value.handle;
} else {
BTA_GATTS_SendRsp(arg->send_rsp.conn_id, arg->send_rsp.trans_id,
arg->send_rsp.status, NULL);
}
param.rsp.status = 0;
btc_gatts_cb_to_app(ESP_GATTS_RESPONSE_EVT, BTC_GATT_GET_GATT_IF(arg->send_rsp.conn_id), &param);
break;
}
case BTC_GATTS_ACT_SET_ATTR_VALUE:
BTA_SetAttributeValue(arg->set_attr_val.handle, arg->set_attr_val.length,
arg->set_attr_val.value);
break;
case BTC_GATTS_ACT_OPEN: {
// Ensure device is in inquiry database
tBTA_GATT_TRANSPORT transport = BTA_GATT_TRANSPORT_LE;
//TODO : implement address type and device type
#if 0
if (_get_address_type(arg->remote_bda, &addr_type) &&
btif_get_device_type(arg->remote_bda, &device_type) &&
device_type != BT_DEVICE_TYPE_BREDR) {
BTA_DmAddBleDevice(p_cb->bd_addr.address, addr_type, device_type);
}
#else
//BTA_DmAddBleDevice(p_cb->bd_addr.address, addr_type, device_type);
#endif
/*
not support background connection
// Mark background connections
if (!arg->open.is_direct) {
BTA_DmBleSetBgConnType(BTM_BLE_CONN_AUTO, NULL);
}
*/
transport = BTA_GATT_TRANSPORT_LE;
// Connect!
BTA_GATTS_Open(arg->open.gatts_if, arg->open.remote_bda,
arg->open.is_direct, transport);
break;
}
case BTC_GATTS_ACT_CLOSE:
// TODO : implement cancel open
// Cancel pending foreground/background connections
//BTA_GATTS_CancelOpen(p_cb->server_if, p_cb->bd_addr.address, TRUE);
//BTA_GATTS_CancelOpen(p_cb->server_if, p_cb->bd_addr.address, FALSE);
// Close active connection
if (arg->close.conn_id != 0) {
BTA_GATTS_Close(arg->close.conn_id);
}
break;
case BTC_GATTS_ACT_SEND_SERVICE_CHANGE: {
BD_ADDR remote_bda;
memcpy(remote_bda, arg->send_service_change.remote_bda, BD_ADDR_LEN);
BTA_GATTS_SendServiceChangeIndication(arg->send_service_change.gatts_if, remote_bda);
break;
}
case BTC_GATTS_ACT_SHOW_LOCAL_DATABASE:
BTA_GATTS_ShowLocalDatabase();
break;
default:
break;
}
btc_gatts_arg_deep_free(msg);
}
void btc_gatts_cb_handler(btc_msg_t *msg)
{
esp_ble_gatts_cb_param_t param;
tBTA_GATTS *p_data = (tBTA_GATTS *)msg->arg;
esp_gatt_if_t gatts_if;
switch (msg->act) {
case BTA_GATTS_REG_EVT: {
gatts_if = p_data->reg_oper.server_if;
param.reg.status = p_data->reg_oper.status;
param.reg.app_id = p_data->reg_oper.uuid.uu.uuid16;
btc_gatts_cb_to_app(ESP_GATTS_REG_EVT, gatts_if, &param);
break;
}
case BTA_GATTS_DEREG_EVT: {
gatts_if = p_data->reg_oper.server_if;
btc_gatts_cb_to_app(ESP_GATTS_UNREG_EVT, gatts_if, NULL);
break;
}
case BTA_GATTS_READ_EVT: {
gatts_if = BTC_GATT_GET_GATT_IF(p_data->req_data.conn_id);
param.read.conn_id = BTC_GATT_GET_CONN_ID(p_data->req_data.conn_id);
param.read.trans_id = p_data->req_data.trans_id;
memcpy(param.read.bda, p_data->req_data.remote_bda, ESP_BD_ADDR_LEN);
param.read.handle = p_data->req_data.p_data->read_req.handle;
param.read.offset = p_data->req_data.p_data->read_req.offset;
param.read.is_long = p_data->req_data.p_data->read_req.is_long;
param.read.need_rsp = p_data->req_data.p_data->read_req.need_rsp;
btc_gatts_cb_to_app(ESP_GATTS_READ_EVT, gatts_if, &param);
break;
}
case BTA_GATTS_WRITE_EVT: {
gatts_if = BTC_GATT_GET_GATT_IF(p_data->req_data.conn_id);
param.write.conn_id = BTC_GATT_GET_CONN_ID(p_data->req_data.conn_id);
param.write.trans_id = p_data->req_data.trans_id;
memcpy(param.write.bda, p_data->req_data.remote_bda, ESP_BD_ADDR_LEN);
if (p_data->req_data.p_data == NULL) {
break;
}
param.write.handle = p_data->req_data.p_data->write_req.handle;
param.write.offset = p_data->req_data.p_data->write_req.offset;
param.write.need_rsp = p_data->req_data.p_data->write_req.need_rsp;
param.write.is_prep = p_data->req_data.p_data->write_req.is_prep;
param.write.len = p_data->req_data.p_data->write_req.len;
param.write.value = p_data->req_data.p_data->write_req.value;
btc_gatts_cb_to_app(ESP_GATTS_WRITE_EVT, gatts_if, &param);
break;
}
case BTA_GATTS_EXEC_WRITE_EVT: {
gatts_if = BTC_GATT_GET_GATT_IF(p_data->req_data.conn_id);
param.exec_write.conn_id = BTC_GATT_GET_CONN_ID(p_data->req_data.conn_id);
param.exec_write.trans_id = p_data->req_data.trans_id;
memcpy(param.exec_write.bda, p_data->req_data.remote_bda, ESP_BD_ADDR_LEN);
if (p_data->req_data.p_data == NULL) {
break;
}
param.exec_write.exec_write_flag = p_data->req_data.p_data->exec_write;
btc_gatts_cb_to_app(ESP_GATTS_EXEC_WRITE_EVT, gatts_if, &param);
break;
}
case BTA_GATTS_MTU_EVT:
gatts_if = BTC_GATT_GET_GATT_IF(p_data->req_data.conn_id);
param.mtu.conn_id = BTC_GATT_GET_CONN_ID(p_data->req_data.conn_id);
param.mtu.mtu = p_data->req_data.p_data->mtu;
btc_gatts_cb_to_app(ESP_GATTS_MTU_EVT, gatts_if, &param);
break;
case BTA_GATTS_CONF_EVT:
gatts_if = BTC_GATT_GET_GATT_IF(p_data->req_data.conn_id);
param.conf.conn_id = BTC_GATT_GET_CONN_ID(p_data->req_data.conn_id);
param.conf.status = p_data->req_data.status;
param.conf.handle = p_data->req_data.handle;
if (p_data->req_data.status != ESP_GATT_OK && p_data->req_data.value){
param.conf.len = p_data->req_data.data_len;
param.conf.value = p_data->req_data.value;
}else{
param.conf.len = 0;
}
btc_gatts_cb_to_app(ESP_GATTS_CONF_EVT, gatts_if, &param);
break;
case BTA_GATTS_CREATE_EVT:
gatts_if = p_data->create.server_if;
param.create.status = p_data->create.status;
param.create.service_handle = p_data->create.service_id;
param.create.service_id.is_primary = p_data->create.is_primary;
param.create.service_id.id.inst_id = p_data->create.svc_instance;
bta_to_btc_uuid(&param.create.service_id.id.uuid, &p_data->create.uuid);
btc_gatts_cb_to_app(ESP_GATTS_CREATE_EVT, gatts_if, &param);
break;
case BTA_GATTS_ADD_INCL_SRVC_EVT:
gatts_if = p_data->add_result.server_if;
param.add_incl_srvc.status = p_data->add_result.status;
param.add_incl_srvc.attr_handle = p_data->add_result.attr_id;
param.add_incl_srvc.service_handle = p_data->add_result.service_id;
btc_gatts_cb_to_app(ESP_GATTS_ADD_INCL_SRVC_EVT, gatts_if, &param);
break;
case BTA_GATTS_ADD_CHAR_EVT:
gatts_if = p_data->add_result.server_if;
param.add_char.status = p_data->add_result.status;
param.add_char.attr_handle = p_data->add_result.attr_id;
param.add_char.service_handle = p_data->add_result.service_id;
bta_to_btc_uuid(&param.add_char.char_uuid, &p_data->add_result.char_uuid);
btc_gatts_cb_to_app(ESP_GATTS_ADD_CHAR_EVT, gatts_if, &param);
break;
case BTA_GATTS_ADD_CHAR_DESCR_EVT:
gatts_if = p_data->add_result.server_if;
param.add_char_descr.status = p_data->add_result.status;
param.add_char_descr.attr_handle = p_data->add_result.attr_id;
param.add_char_descr.service_handle = p_data->add_result.service_id;
bta_to_btc_uuid(&param.add_char_descr.descr_uuid, &p_data->add_result.char_uuid);
btc_gatts_cb_to_app(ESP_GATTS_ADD_CHAR_DESCR_EVT, gatts_if, &param);
break;
case BTA_GATTS_DELELTE_EVT:
gatts_if = p_data->srvc_oper.server_if;
param.del.status = p_data->srvc_oper.status;
param.del.service_handle = p_data->srvc_oper.service_id;
btc_gatts_cb_to_app(ESP_GATTS_DELETE_EVT, gatts_if, &param);
break;
case BTA_GATTS_START_EVT:
gatts_if = p_data->srvc_oper.server_if;
param.start.status = p_data->srvc_oper.status;
param.start.service_handle = p_data->srvc_oper.service_id;
btc_gatts_cb_to_app(ESP_GATTS_START_EVT, gatts_if, &param);
break;
case BTA_GATTS_STOP_EVT:
gatts_if = p_data->srvc_oper.server_if;
param.stop.status = p_data->srvc_oper.status;
param.stop.service_handle = p_data->srvc_oper.service_id;
btc_gatts_cb_to_app(ESP_GATTS_STOP_EVT, gatts_if, &param);
break;
case BTA_GATTS_CONNECT_EVT: {
#if (SMP_INCLUDED == TRUE)
bt_bdaddr_t bt_addr;
memcpy(bt_addr.address, p_data->conn.remote_bda, sizeof(bt_addr.address));
if (btc_storage_update_active_device(&bt_addr)) {
BTC_TRACE_EVENT("Device: %02x:%02x:%02x:%02x:%02x:%02x, is not in bond list",
bt_addr.address[0], bt_addr.address[1],
bt_addr.address[2], bt_addr.address[3],
bt_addr.address[4], bt_addr.address[5]);
}
#endif ///SMP_INCLUDED == TRUE
gatts_if = p_data->conn.server_if;
param.connect.conn_id = BTC_GATT_GET_CONN_ID(p_data->conn.conn_id);
param.connect.link_role = p_data->conn.link_role;
memcpy(param.connect.remote_bda, p_data->conn.remote_bda, ESP_BD_ADDR_LEN);
param.connect.conn_params.interval = p_data->conn.conn_params.interval;
param.connect.conn_params.latency = p_data->conn.conn_params.latency;
param.connect.conn_params.timeout = p_data->conn.conn_params.timeout;
param.connect.ble_addr_type = p_data->conn.ble_addr_type;
param.connect.conn_handle = p_data->conn.conn_handle;
btc_gatts_cb_to_app(ESP_GATTS_CONNECT_EVT, gatts_if, &param);
break;
}
case BTA_GATTS_DISCONNECT_EVT:
gatts_if = p_data->conn.server_if;
param.disconnect.conn_id = BTC_GATT_GET_CONN_ID(p_data->conn.conn_id);
param.disconnect.reason = p_data->conn.reason;
memcpy(param.disconnect.remote_bda, p_data->conn.remote_bda, ESP_BD_ADDR_LEN);
btc_gatts_cb_to_app(ESP_GATTS_DISCONNECT_EVT, gatts_if, &param);
break;
case BTA_GATTS_OPEN_EVT:
gatts_if = p_data->open.server_if;
param.open.status = p_data->open.status;
btc_gatts_cb_to_app(BTA_GATTS_OPEN_EVT, gatts_if, &param);
break;
case BTA_GATTS_CANCEL_OPEN_EVT:
gatts_if = p_data->cancel_open.server_if;
param.cancel_open.status = p_data->cancel_open.status;
btc_gatts_cb_to_app(BTA_GATTS_CANCEL_OPEN_EVT, gatts_if, &param);
break;
case BTA_GATTS_CLOSE_EVT:
gatts_if = BTC_GATT_GET_GATT_IF(p_data->close.conn_id);
param.close.status = p_data->close.status;
param.close.conn_id = BTC_GATT_GET_CONN_ID(p_data->close.conn_id);
btc_gatts_cb_to_app(BTA_GATTS_CLOSE_EVT, gatts_if, &param);
break;
case BTA_GATTS_SEND_SERVICE_CHANGE_EVT:
gatts_if = p_data->service_change.server_if;
param.service_change.status = p_data->service_change.status;
btc_gatts_cb_to_app(ESP_GATTS_SEND_SERVICE_CHANGE_EVT, gatts_if, &param);
break;
case BTA_GATTS_LISTEN_EVT:
// do nothing
break;
case BTA_GATTS_CONGEST_EVT:
gatts_if = BTC_GATT_GET_GATT_IF(p_data->congest.conn_id);
param.congest.conn_id = BTC_GATT_GET_CONN_ID(p_data->congest.conn_id);
param.congest.congested = p_data->congest.congested;
btc_gatts_cb_to_app(ESP_GATTS_CONGEST_EVT, gatts_if, &param);
break;
case BTA_GATTS_SET_ATTR_VAL_EVT:
gatts_if = p_data->attr_val.server_if;
param.set_attr_val.srvc_handle = p_data->attr_val.service_id;
param.set_attr_val.attr_handle = p_data->attr_val.attr_id;
param.set_attr_val.status = p_data->attr_val.status;
btc_gatts_cb_to_app(ESP_GATTS_SET_ATTR_VAL_EVT, gatts_if, &param);
break;
default:
// do nothing
break;
}
btc_gatts_cb_param_copy_free(msg);
}
void btc_congest_callback(tBTA_GATTS *param)
{
esp_ble_gatts_cb_param_t esp_param;
esp_gatt_if_t gatts_if = BTC_GATT_GET_GATT_IF(param->congest.conn_id);
esp_param.congest.conn_id = BTC_GATT_GET_CONN_ID(param->congest.conn_id);
esp_param.congest.congested = param->congest.congested;
btc_gatts_cb_to_app(ESP_GATTS_CONGEST_EVT, gatts_if, &esp_param);
}
#endif ///GATTS_INCLUDED
@@ -0,0 +1,590 @@
/******************************************************************************
*
* Copyright (C) 2009-2012 Broadcom Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
#define LOG_TAG "bt_btc_bta_ag"
#include "btc_hf_ag.h"
#include "bta_ag_int.h"
#include "bta/bta_api.h"
#include "bta/bta_ag_api.h"
#include "bta/bta_ag_co.h"
#include "bta/bta_dm_co.h"
#include "common/bt_target.h"
#include "hci/hci_audio.h"
#include "osi/allocator.h"
#include <string.h>
#if (BTA_AG_INCLUDED == TRUE)
/*******************************************************************************
* CONST
********************************************************************************/
#if (BTM_SCO_HCI_INCLUDED == TRUE)
#include "oi_codec_sbc.h"
#include "oi_status.h"
#include "sbc_encoder.h"
#if (PLC_INCLUDED == TRUE)
#include "sbc_plc.h"
typedef struct {
bool first_good_frame_found;
sbc_plc_state_t plc_state;
int16_t sbc_plc_out[SBC_FS];
} bta_hf_ct_plc_t;
#if HFP_DYNAMIC_MEMORY == FALSE
static bta_hf_ct_plc_t bta_hf_ct_plc;
#else
static bta_hf_ct_plc_t *bta_hf_ct_plc_ptr;
#define bta_hf_ct_plc (*bta_hf_ct_plc_ptr)
#endif ///HFP_DYNAMIC_MEMORY == FALSE
#endif ///(PLC_INCLUDED == TRUE)
#define HF_SBC_DEC_CONTEXT_DATA_LEN (CODEC_DATA_WORDS(1, SBC_CODEC_FAST_FILTER_BUFFERS))
#define HF_SBC_DEC_RAW_DATA_SIZE 240
#define HF_SBC_ENC_RAW_DATA_SIZE 240
/* BTA-AG-CO control block to map bdaddr to BTA handle */
typedef struct
{
OI_CODEC_SBC_DECODER_CONTEXT decoder_context;
OI_UINT32 decoder_context_data[HF_SBC_DEC_CONTEXT_DATA_LEN];
OI_INT16 decode_raw_data[HF_SBC_DEC_RAW_DATA_SIZE];
SBC_ENC_PARAMS encoder;
UINT8 sequence_number;
bool is_bad_frame;
bool decode_first_pkt;
OI_BYTE decode_msbc_data[BTM_MSBC_FRAME_SIZE];
bool encode_first_pkt;
OI_BYTE encode_msbc_data[BTM_MSBC_FRAME_SIZE];
} bta_ag_co_cb_t;
#if HFP_DYNAMIC_MEMORY == FALSE
static bta_ag_co_cb_t bta_ag_co_cb;
#else
static bta_ag_co_cb_t *bta_ag_co_cb_ptr;
#define bta_ag_co_cb (*bta_ag_co_cb_ptr)
#endif /* HFP_DYNAMIC_MEMORY == FALSE */
static UINT8 hf_air_mode = BTM_SCO_AIR_MODE_UNKNOWN;
static UINT8 hf_inout_pkt_size = 0;
/* =========================================================================
* AG pass-through mode handle
*===========================================================================*/
/*******************************************************************************
**
** Function bta_ag_co_tx_write
**
** Description This function is called by the AG to send data to the
** phone when the AG is configured for AT command pass-through.
** The implementation of this function must copy the data to
** the phones memory.
**
** Returns void
**
*******************************************************************************/
void bta_ag_co_tx_write(UINT16 handle, UNUSED_ATTR UINT8 * p_data, UINT16 len)
{
BTIF_TRACE_DEBUG( "bta_ag_co_tx_write: handle: %d, len: %d", handle, len );
}
/******************************************************************************
**
** Function bta_ag_ci_rx_write
**
** Description This function is called to send data to the AG when the AG
** is configured for AT command pass-through. The function
** copies data to an event buffer and sends it.
**
** Returns void
**
******************************************************************************/
void bta_ag_ci_rx_write(UINT16 handle, char *p_data, UINT16 len)
{
tBTA_AG_CI_RX_WRITE *p_buf;
UINT16 len_remaining = len;
char *p_data_area;
if (len > (BT_DEFAULT_BUFFER_SIZE - sizeof(tBTA_AG_CI_RX_WRITE) - 1)) {
len = BT_DEFAULT_BUFFER_SIZE - sizeof(tBTA_AG_CI_RX_WRITE) - 1;
}
while (len_remaining) {
if (len_remaining < len) {
len = len_remaining;
}
if ((p_buf = (tBTA_AG_CI_RX_WRITE *) osi_malloc((UINT16)(sizeof(tBTA_AG_CI_RX_WRITE) + len + 1))) != NULL) {
p_buf->hdr.event = BTA_AG_CI_RX_WRITE_EVT;
p_buf->hdr.layer_specific = handle;
p_data_area = (char *)(p_buf+1); /* Point to data area after header */
strncpy(p_data_area, p_data, len);
p_data_area[len] = 0;
bta_sys_sendmsg(p_buf);
} else {
APPL_TRACE_ERROR("ERROR: Unable to allocate buffer to hold AT response code. len=%i", len);
break;
}
len_remaining-=len;
p_data+=len;
}
}
/******************************************************************************
**
** Function bta_ag_ci_slc_ready
**
** Description This function is called to notify AG that SLC is up at
** the application. This funcion is only used when the app
** is running in pass-through mode.
**
** Returns void
**
******************************************************************************/
void bta_ag_ci_slc_ready(UINT16 handle)
{
tBTA_AG_DATA *p_buf;
if ((p_buf = (tBTA_AG_DATA *)osi_malloc(sizeof(tBTA_AG_DATA))) != NULL) {
p_buf->hdr.event = BTA_AG_CI_SLC_READY_EVT;
p_buf->hdr.layer_specific = handle;
bta_sys_sendmsg(p_buf);
}
}
/*******************************************************************************
* H2 & DEC
********************************************************************************/
/*******************************************************************************
**
** Function bta_ag_h2_header
**
** Description This function is called to fill in H2 header
**
** Returns void
**
*******************************************************************************/
static void bta_ag_h2_header(UINT16 *p_buf)
{
// H2: Header with synchronization word and sequence number
#define BTA_HF_H2_HEADER 0x0801
#define BTA_HF_H2_HEADER_BIT0_MASK (1 << 0)
#define BTA_HF_H2_HEADER_BIT1_MASK (1 << 1)
#define BTA_HF_H2_HEADER_SN0_BIT_OFFSET1 12
#define BTA_HF_H2_HEADER_SN0_BIT_OFFSET2 13
#define BTA_HF_H2_HEADER_SN1_BIT_OFFSET1 14
#define BTA_HF_H2_HEADER_SN1_BIT_OFFSET2 15
UINT16 h2_header = BTA_HF_H2_HEADER;
UINT8 h2_header_sn0 = bta_ag_co_cb.sequence_number & BTA_HF_H2_HEADER_BIT0_MASK;
UINT8 h2_header_sn1 = bta_ag_co_cb.sequence_number & BTA_HF_H2_HEADER_BIT1_MASK;
h2_header |= (h2_header_sn0 << BTA_HF_H2_HEADER_SN0_BIT_OFFSET1
| h2_header_sn0 << BTA_HF_H2_HEADER_SN0_BIT_OFFSET2
| h2_header_sn1 << (BTA_HF_H2_HEADER_SN1_BIT_OFFSET1 - 1)
| h2_header_sn1 << (BTA_HF_H2_HEADER_SN1_BIT_OFFSET2 - 1)
);
bta_ag_co_cb.sequence_number++;
*p_buf = h2_header;
}
/*******************************************************************************
**
** Function bta_hf_dec_init
**
** Description Initialize decoding task
**
** Returns void
**
*******************************************************************************/
static void bta_hf_dec_init(void)
{
#if (PLC_INCLUDED == TRUE)
sbc_plc_init(&(bta_hf_ct_plc.plc_state));
#endif ///(PLC_INCLUDED == TRUE)
OI_STATUS status = OI_CODEC_SBC_DecoderReset(&bta_ag_co_cb.decoder_context, bta_ag_co_cb.decoder_context_data,
HF_SBC_DEC_CONTEXT_DATA_LEN * sizeof(OI_UINT32), 1, 1, FALSE, TRUE);
if (!OI_SUCCESS(status)) {
APPL_TRACE_ERROR("OI_CODEC_SBC_DecoderReset failed with error code %d\n", status);
}
}
/*******************************************************************************
**
** Function bta_hf_enc_init
**
** Description Initialize encoding task for mSBC
**
** Returns void
**
*******************************************************************************/
static void bta_hf_enc_init(void)
{
bta_ag_co_cb.sequence_number = 0;
bta_ag_co_cb.decode_first_pkt = true;
bta_ag_co_cb.encode_first_pkt = true;
bta_ag_co_cb.is_bad_frame = false;
bta_ag_co_cb.encoder.sbc_mode = SBC_MODE_MSBC;
bta_ag_co_cb.encoder.s16NumOfBlocks = 15;
bta_ag_co_cb.encoder.s16NumOfSubBands = 8;
bta_ag_co_cb.encoder.s16AllocationMethod = SBC_LOUDNESS;
bta_ag_co_cb.encoder.s16BitPool = 26;
bta_ag_co_cb.encoder.s16ChannelMode = SBC_MONO;
bta_ag_co_cb.encoder.s16NumOfChannels = 1;
bta_ag_co_cb.encoder.s16SamplingFreq = SBC_sf16000;
SBC_Encoder_Init(&(bta_ag_co_cb.encoder));
}
/*******************************************************************************
**
** Function bta_ag_decode_msbc_frame
**
** Description This function is called decode a mSBC frame
**
** Returns void
**
*******************************************************************************/
static void bta_ag_decode_msbc_frame(UINT8 **data, UINT8 *length, BOOLEAN is_bad_frame)
{
OI_STATUS status;
const OI_BYTE *zero_signal_frame_data;
UINT8 zero_signal_frame_len = BTM_MSBC_FRAME_DATA_SIZE;
UINT32 sbc_raw_data_size = HF_SBC_DEC_RAW_DATA_SIZE;
if (is_bad_frame) {
status = OI_CODEC_SBC_CHECKSUM_MISMATCH;
} else {
status = OI_CODEC_SBC_DecodeFrame(&bta_ag_co_cb.decoder_context, (const OI_BYTE **)data,
(OI_UINT32 *)length,
(OI_INT16 *)bta_ag_co_cb.decode_raw_data,
(OI_UINT32 *)&sbc_raw_data_size);
}
// PLC_INCLUDED will be set to TRUE when enabling Wide Band Speech
#if (PLC_INCLUDED == TRUE)
switch(status) {
case OI_OK:
{
bta_hf_ct_plc.first_good_frame_found = TRUE;
sbc_plc_good_frame(&(bta_hf_ct_plc.plc_state), (int16_t *)bta_ag_co_cb.decode_raw_data, bta_hf_ct_plc.sbc_plc_out);
}
case OI_CODEC_SBC_NOT_ENOUGH_HEADER_DATA:
case OI_CODEC_SBC_NOT_ENOUGH_BODY_DATA:
case OI_CODEC_SBC_NOT_ENOUGH_AUDIO_DATA:
break;
case OI_CODEC_SBC_NO_SYNCWORD:
case OI_CODEC_SBC_CHECKSUM_MISMATCH:
{
if (!bta_hf_ct_plc.first_good_frame_found) {
break;
}
zero_signal_frame_data = sbc_plc_zero_signal_frame();
sbc_raw_data_size = HF_SBC_DEC_RAW_DATA_SIZE;
status = OI_CODEC_SBC_DecodeFrame(&bta_ag_co_cb.decoder_context, &zero_signal_frame_data,
(OI_UINT32 *)&zero_signal_frame_len,
(OI_INT16 *)bta_ag_co_cb.decode_raw_data,
(OI_UINT32 *)&sbc_raw_data_size);
sbc_plc_bad_frame(&(bta_hf_ct_plc.plc_state), bta_ag_co_cb.decode_raw_data, bta_hf_ct_plc.sbc_plc_out);
APPL_TRACE_DEBUG("bad frame, using PLC to fix it.");
break;
}
case OI_STATUS_INVALID_PARAMETERS:
{
// This caused by corrupt frames.
// The codec apparently does not recover from this.
// Re-initialize the codec.
APPL_TRACE_ERROR("Frame decode error: OI_STATUS_INVALID_PARAMETERS");
if (!OI_SUCCESS(OI_CODEC_SBC_DecoderReset(&bta_ag_co_cb.decoder_context, bta_ag_co_cb.decoder_context_data,
HF_SBC_DEC_CONTEXT_DATA_LEN * sizeof(OI_UINT32), 1, 1, FALSE, TRUE))) {
APPL_TRACE_ERROR("OI_CODEC_SBC_DecoderReset failed with error code %d\n", status);
}
break;
}
default:
APPL_TRACE_ERROR("Frame decode error: %d", status);
break;
}
#endif ///(PLC_INCLUDED == TRUE)
if (OI_SUCCESS(status)) {
btc_hf_incoming_data_cb_to_app((const uint8_t *)(bta_hf_ct_plc.sbc_plc_out), sbc_raw_data_size);
}
}
/*******************************************************************************
* BTA AG SCO CO FUNCITONS
********************************************************************************/
/*******************************************************************************
**
** Function bta_ag_sco_audio_state
**
** Description This function is called by the AG before the audio connection
** is brought up, after it comes up, and after it goes down.
**
** Parameters handle - handle of the AG instance
** state - Audio state
** codec - if WBS support is compiled in, codec to going to be used is provided
** and when in SCO_STATE_SETUP, BTM_I2SPCMConfig() must be called with
** the correct platform parameters.
** in the other states codec type should not be ignored
**
** Returns void
**
*******************************************************************************/
#if (BTM_WBS_INCLUDED == TRUE)
void bta_ag_sco_audio_state(UINT16 handle, UINT8 app_id, UINT8 state, tBTA_AG_PEER_CODEC codec)
#else
void bta_ag_sco_audio_state(UINT16 handle, UINT8 app_id, UINT8 state)
#endif
{
BTIF_TRACE_DEBUG("bta_ag_sco_audio_state: handle %d, state %d", handle, state);
switch (state) {
case SCO_STATE_ON:
case SCO_STATE_OFF:
case SCO_STATE_OFF_TRANSFER:
case SCO_STATE_SETUP:
default:
break;
}
}
/*******************************************************************************
**
** Function bta_ag_sco_co_init
**
** Description Set default data path for SCO/eSCO.
**
**
** Returns Void.
**
*******************************************************************************/
tBTA_HFP_SCO_ROUTE_TYPE bta_ag_sco_co_init(UINT32 rx_bw, UINT32 tx_bw, tBTA_HFP_CODEC_INFO *p_codec_info, UINT8 app_id)
{
APPL_TRACE_EVENT("%s rx_bw %d, tx_bw %d, codec %d", __FUNCTION__, rx_bw, tx_bw, p_codec_info->codec_type);
return BTA_HFP_SCO_ROUTE_HCI;
}
/*******************************************************************************
**
** Function bta_ag_sco_co_open
**
** Description This function is executed by AG when a service level connection
** is opened.
**
**
** Returns void
**
*******************************************************************************/
void bta_ag_sco_co_open(UINT16 handle, tBTM_SCO_AIR_MODE_TYPE air_mode, UINT8 inout_pkt_size, UINT16 event)
{
APPL_TRACE_EVENT("%s hdl %x, pkt_sz %u, event %u", __FUNCTION__, handle, inout_pkt_size, event);
hf_air_mode = air_mode;
hf_inout_pkt_size = inout_pkt_size;
if (air_mode == BTM_SCO_AIR_MODE_TRANSPNT) {
#if (HFP_DYNAMIC_MEMORY == TRUE)
bta_ag_co_cb_ptr = osi_calloc(sizeof(bta_ag_co_cb_t));
if (!bta_ag_co_cb_ptr) {
APPL_TRACE_ERROR("%s allocate failed", __FUNCTION__);
goto error_exit;
}
#if (PLC_INCLUDED == TRUE)
bta_hf_ct_plc_ptr = (bta_hf_ct_plc_t *)osi_calloc(sizeof(bta_hf_ct_plc_t));
if (!bta_hf_ct_plc_ptr) {
APPL_TRACE_ERROR("%s malloc fail.", __FUNCTION__);
goto error_exit;
}
#endif ///(PLC_INCLUDED == TRUE)
#endif /// (HFP_DYNAMIC_MEMORY == TRUE)
bta_hf_dec_init();
bta_hf_enc_init();
return;
} else {
return; // Nothing to do
}
#if (HFP_DYNAMIC_MEMORY == TRUE)
error_exit:;
hf_air_mode = BTM_SCO_AIR_MODE_UNKNOWN;
hf_inout_pkt_size = 0;
if (bta_ag_co_cb_ptr) {
osi_free(bta_ag_co_cb_ptr);
bta_ag_co_cb_ptr = NULL;
}
#if (PLC_INCLUDED == TRUE)
if (bta_hf_ct_plc_ptr) {
osi_free(bta_hf_ct_plc_ptr);
bta_hf_ct_plc_ptr = NULL;
}
#endif ///(PLC_INCLUDED == TRUE)
#endif /// (HFP_DYNAMIC_MEMORY == TRUE)
return;
}
/*******************************************************************************
**
** Function bta_ag_sco_co_close
**
** Description Nothing but print some log.
**
** Returns void
**
*******************************************************************************/
void bta_ag_sco_co_close(void)
{
APPL_TRACE_EVENT("%s", __FUNCTION__);
if (hf_air_mode == BTM_SCO_AIR_MODE_TRANSPNT) {
#if (PLC_INCLUDED == TRUE)
sbc_plc_deinit(&(bta_hf_ct_plc.plc_state));
bta_hf_ct_plc.first_good_frame_found = FALSE;
#if (HFP_DYNAMIC_MEMORY == TRUE)
osi_free(bta_hf_ct_plc_ptr);
bta_hf_ct_plc_ptr = NULL;
#endif /// (HFP_DYNAMIC_MEMORY == TRUE)
#endif ///(PLC_INCLUDED == TRUE)
#if (HFP_DYNAMIC_MEMORY == TRUE)
osi_free(bta_ag_co_cb_ptr);
bta_ag_co_cb_ptr = NULL;
#endif /* HFP_DYNAMIC_MEMORY == TRUE */
} else {
// Nothing to do
}
hf_air_mode = BTM_SCO_AIR_MODE_UNKNOWN;
hf_inout_pkt_size = 0;
}
/*******************************************************************************
**
** Function bta_ag_sco_co_out_data
**
** Description This function is called to send SCO data over HCI.
**
** Returns number of bytes got from application
**
*******************************************************************************/
uint32_t bta_ag_sco_co_out_data(UINT8 *p_buf)
{
if (hf_air_mode == BTM_SCO_AIR_MODE_CVSD) {
// CVSD
uint32_t hf_raw_pkt_size = hf_inout_pkt_size;
return btc_hf_outgoing_data_cb_to_app(p_buf, hf_raw_pkt_size);
} else if (hf_air_mode == BTM_SCO_AIR_MODE_TRANSPNT) {
// mSBC
if (hf_inout_pkt_size == BTM_MSBC_FRAME_SIZE / 2) {
if (bta_ag_co_cb.encode_first_pkt) {
UINT32 size = btc_hf_outgoing_data_cb_to_app((UINT8 *)bta_ag_co_cb.encoder.as16PcmBuffer, HF_SBC_ENC_RAW_DATA_SIZE);
if (size != HF_SBC_ENC_RAW_DATA_SIZE) {
return 0;
}
bta_ag_h2_header((UINT16 *)bta_ag_co_cb.encode_msbc_data);
bta_ag_co_cb.encoder.pu8Packet = bta_ag_co_cb.encode_msbc_data + 2;
SBC_Encoder(&bta_ag_co_cb.encoder);
memcpy(p_buf, bta_ag_co_cb.encode_msbc_data, hf_inout_pkt_size);
bta_ag_co_cb.encode_first_pkt = !bta_ag_co_cb.encode_first_pkt;
return hf_inout_pkt_size;
} else {
memcpy(p_buf, bta_ag_co_cb.encode_msbc_data + hf_inout_pkt_size, hf_inout_pkt_size);
bta_ag_co_cb.encode_first_pkt = !bta_ag_co_cb.encode_first_pkt;
return hf_inout_pkt_size;
}
} else if (hf_inout_pkt_size == BTM_MSBC_FRAME_SIZE) {
UINT32 size = btc_hf_outgoing_data_cb_to_app((UINT8 *)bta_ag_co_cb.encoder.as16PcmBuffer, HF_SBC_ENC_RAW_DATA_SIZE);
if (size != HF_SBC_ENC_RAW_DATA_SIZE) {
return 0;
}
bta_ag_h2_header((UINT16 *)p_buf);
bta_ag_co_cb.encoder.pu8Packet = p_buf + 2;
SBC_Encoder(&bta_ag_co_cb.encoder);
return hf_inout_pkt_size;
} else {
//Never run to here.
}
} else {
APPL_TRACE_ERROR("%s invaild air mode: %d", __FUNCTION__, hf_air_mode);
}
return 0;
}
/*******************************************************************************
**
** Function bta_ag_sco_co_in_data
**
** Description This function is called to send incoming SCO data to application.
**
** Returns void
**
*******************************************************************************/
void bta_ag_sco_co_in_data(BT_HDR *p_buf, tBTM_SCO_DATA_FLAG status)
{
UINT8 *p = (UINT8 *)(p_buf + 1) + p_buf->offset;
UINT8 pkt_size = 0;
STREAM_SKIP_UINT16(p);
STREAM_TO_UINT8(pkt_size, p);
if (hf_air_mode == BTM_SCO_AIR_MODE_CVSD) {
// CVSD
if(status != BTM_SCO_DATA_CORRECT) {
APPL_TRACE_DEBUG("%s: not a correct frame(%d).", __func__, status);
}
btc_hf_incoming_data_cb_to_app(p, pkt_size);
} else if (hf_air_mode == BTM_SCO_AIR_MODE_TRANSPNT) {
// mSBC
UINT8 *data = NULL;
if (pkt_size != hf_inout_pkt_size) {
bta_ag_co_cb.is_bad_frame = true;
}
if (status != BTM_SCO_DATA_CORRECT) {
bta_ag_co_cb.is_bad_frame = true;
}
if (hf_inout_pkt_size == BTM_MSBC_FRAME_SIZE / 2) {
if (bta_ag_co_cb.decode_first_pkt) {
if (!bta_ag_co_cb.is_bad_frame) {
memcpy(bta_ag_co_cb.decode_msbc_data, p, pkt_size);
}
} else {
if (!bta_ag_co_cb.is_bad_frame) {
memcpy(bta_ag_co_cb.decode_msbc_data + BTM_MSBC_FRAME_SIZE / 2, p, pkt_size);
}
data = bta_ag_co_cb.decode_msbc_data;
bta_ag_decode_msbc_frame(&data, &pkt_size, bta_ag_co_cb.is_bad_frame);
bta_ag_co_cb.is_bad_frame = false;
}
bta_ag_co_cb.decode_first_pkt = !bta_ag_co_cb.decode_first_pkt;
} else if (hf_inout_pkt_size == BTM_MSBC_FRAME_SIZE) {
data = p;
bta_ag_decode_msbc_frame(&data, &pkt_size, bta_ag_co_cb.is_bad_frame);
bta_ag_co_cb.is_bad_frame = false;
} else {
//Never run to here.
}
} else {
APPL_TRACE_ERROR("%s invaild air mode: %d", __FUNCTION__, hf_air_mode);
}
}
#endif /* #if (BTM_SCO_HCI_INCLUDED == TRUE) */
#endif /* #if (BTA_AG_INCLUDED == TRUE) */
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,505 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "bta/bta_hf_client_co.h"
#include "hci/hci_audio.h"
#include "btc_hf_client.h"
#include "osi/allocator.h"
#include <string.h>
#if (BTA_HF_INCLUDED == TRUE)
#if (BTM_SCO_HCI_INCLUDED == TRUE)
#include "oi_codec_sbc.h"
#include "oi_status.h"
#include "sbc_encoder.h"
#if (PLC_INCLUDED == TRUE)
#include "sbc_plc.h"
typedef struct {
bool first_good_frame_found;
sbc_plc_state_t plc_state;
int16_t sbc_plc_out[SBC_FS];
} bta_hf_ct_plc_t;
#if HFP_DYNAMIC_MEMORY == FALSE
static bta_hf_ct_plc_t bta_hf_ct_plc;
#else
static bta_hf_ct_plc_t *bta_hf_ct_plc_ptr;
#define bta_hf_ct_plc (*bta_hf_ct_plc_ptr)
#endif
#endif ///(PLC_INCLUDED == TRUE)
#define HF_SBC_DEC_CONTEXT_DATA_LEN (CODEC_DATA_WORDS(1, SBC_CODEC_FAST_FILTER_BUFFERS))
#define HF_SBC_DEC_RAW_DATA_SIZE 240
#define HF_SBC_ENC_RAW_DATA_SIZE 240
/* BTA-HF-CO control block to map bdaddr to BTA handle */
typedef struct
{
OI_CODEC_SBC_DECODER_CONTEXT decoder_context;
OI_UINT32 decoder_context_data[HF_SBC_DEC_CONTEXT_DATA_LEN];
OI_INT16 decode_raw_data[HF_SBC_DEC_RAW_DATA_SIZE];
SBC_ENC_PARAMS encoder;
UINT8 sequence_number;
bool is_bad_frame;
bool decode_first_pkt;
OI_BYTE decode_msbc_data[BTM_MSBC_FRAME_SIZE];
bool encode_first_pkt;
OI_BYTE encode_msbc_data[BTM_MSBC_FRAME_SIZE];
} bta_hf_client_co_cb_t;
#if HFP_DYNAMIC_MEMORY == FALSE
static bta_hf_client_co_cb_t bta_hf_client_co_cb;
#else
static bta_hf_client_co_cb_t *bta_hf_client_co_cb_ptr;
#define bta_hf_client_co_cb (*bta_hf_client_co_cb_ptr)
#endif /* HFP_DYNAMIC_MEMORY == FALSE */
static UINT8 hf_air_mode = BTM_SCO_AIR_MODE_UNKNOWN;
static UINT8 hf_inout_pkt_size = 0;
/*******************************************************************************
**
** Function bta_hf_client_co_audio_state
**
** Description This function is called by the HF CLIENT before the audio connection
** is brought up, after it comes up, and after it goes down.
**
** Parameters handle - handle of the AG instance
** state - Audio state
** codec - if WBS support is compiled in, codec to going to be used is provided
** and when in SCO_STATE_SETUP, BTM_I2SPCMConfig() must be called with
** the correct platform parameters.
** in the other states codec type should not be ignored
**
** Returns void
**
*******************************************************************************/
void bta_hf_client_co_audio_state(UINT16 handle, UINT8 state, tBTA_HFP_PEER_CODEC codec)
{
switch (state)
{
case SCO_STATE_ON:
case SCO_STATE_OFF:
case SCO_STATE_OFF_TRANSFER:
case SCO_STATE_SETUP:
default:
break;
}
}
/*******************************************************************************
**
** Function bta_hf_client_sco_co_init
**
** Description This function can be used by the phone to initialize audio
** codec or for other initialization purposes before SCO connection
** is opened.
**
**
** Returns Void.
**
*******************************************************************************/
tBTA_HFP_SCO_ROUTE_TYPE bta_hf_client_sco_co_init(UINT32 rx_bw, UINT32 tx_bw,
tBTA_HFP_CODEC_INFO *p_codec_info, UINT8 app_id)
{
APPL_TRACE_EVENT("%s rx_bw %d, tx_bw %d, codec %d", __FUNCTION__, rx_bw, tx_bw,
p_codec_info->codec_type);
return BTA_HFP_SCO_ROUTE_HCI;
}
/*******************************************************************************
**
** Function bta_hf_dec_init
**
** Description Initialize decoding task
**
** Returns void
**
*******************************************************************************/
static void bta_hf_dec_init(void) {
#if (PLC_INCLUDED == TRUE)
sbc_plc_init(&(bta_hf_ct_plc.plc_state));
#endif ///(PLC_INCLUDED == TRUE)
OI_STATUS status;
status = OI_CODEC_SBC_DecoderReset(&bta_hf_client_co_cb.decoder_context, bta_hf_client_co_cb.decoder_context_data,
HF_SBC_DEC_CONTEXT_DATA_LEN * sizeof(OI_UINT32), 1, 1, FALSE, TRUE);
if (!OI_SUCCESS(status)) {
APPL_TRACE_ERROR("OI_CODEC_SBC_DecoderReset failed with error code %d\n", status);
}
}
/*******************************************************************************
**
** Function bta_hf_enc_init
**
** Description Initialize encoding task
**
** Returns void
**
*******************************************************************************/
static void bta_hf_enc_init(void) {
bta_hf_client_co_cb.sequence_number = 0;
bta_hf_client_co_cb.decode_first_pkt = true;
bta_hf_client_co_cb.encode_first_pkt = true;
bta_hf_client_co_cb.is_bad_frame = false;
bta_hf_client_co_cb.encoder.sbc_mode = SBC_MODE_MSBC;
bta_hf_client_co_cb.encoder.s16NumOfBlocks = 15;
bta_hf_client_co_cb.encoder.s16NumOfSubBands = 8;
bta_hf_client_co_cb.encoder.s16AllocationMethod = SBC_LOUDNESS;
bta_hf_client_co_cb.encoder.s16BitPool = 26;
bta_hf_client_co_cb.encoder.s16ChannelMode = SBC_MONO;
bta_hf_client_co_cb.encoder.s16NumOfChannels = 1;
bta_hf_client_co_cb.encoder.s16SamplingFreq = SBC_sf16000;
SBC_Encoder_Init(&(bta_hf_client_co_cb.encoder));
}
/*******************************************************************************
**
** Function bta_hf_client_sco_co_open
**
** Description This function is executed when a SCO connection is open.
**
**
** Returns void
**
*******************************************************************************/
void bta_hf_client_sco_co_open(UINT16 handle, UINT8 air_mode, UINT8 inout_pkt_size, UINT16 event)
{
APPL_TRACE_EVENT("%s hdl %x, pkt_sz %u, event %u", __FUNCTION__, handle,
inout_pkt_size, event);
hf_air_mode = air_mode;
hf_inout_pkt_size = inout_pkt_size;
if (air_mode == BTM_SCO_AIR_MODE_TRANSPNT) {
#if (HFP_DYNAMIC_MEMORY == TRUE)
bta_hf_client_co_cb_ptr = osi_calloc(sizeof(bta_hf_client_co_cb_t));
if (!bta_hf_client_co_cb_ptr) {
APPL_TRACE_ERROR("%s allocate failed", __FUNCTION__);
goto error_exit;
}
#if (PLC_INCLUDED == TRUE)
bta_hf_ct_plc_ptr = (bta_hf_ct_plc_t *)osi_calloc(sizeof(bta_hf_ct_plc_t));
if (!bta_hf_ct_plc_ptr) {
APPL_TRACE_ERROR("%s malloc fail.", __FUNCTION__);
goto error_exit;
}
#endif ///(PLC_INCLUDED == TRUE)
#endif /// (HFP_DYNAMIC_MEMORY == TRUE)
bta_hf_dec_init();
bta_hf_enc_init();
return;
} else {
return;
// Nothing to do
}
#if (HFP_DYNAMIC_MEMORY == TRUE)
error_exit:;
hf_air_mode = BTM_SCO_AIR_MODE_UNKNOWN;
hf_inout_pkt_size = 0;
if (bta_hf_client_co_cb_ptr) {
osi_free(bta_hf_client_co_cb_ptr);
bta_hf_client_co_cb_ptr = NULL;
}
#if (PLC_INCLUDED == TRUE)
if (bta_hf_ct_plc_ptr) {
osi_free(bta_hf_ct_plc_ptr);
bta_hf_ct_plc_ptr = NULL;
}
#endif ///(PLC_INCLUDED == TRUE)
#endif /// (HFP_DYNAMIC_MEMORY == TRUE)
return;
}
/*******************************************************************************
**
** Function bta_hf_client_sco_co_close
**
** Description This function is called when a SCO connection is closed
**
**
** Returns void
**
*******************************************************************************/
void bta_hf_client_sco_co_close(void)
{
APPL_TRACE_EVENT("%s", __FUNCTION__);
if (hf_air_mode == BTM_SCO_AIR_MODE_TRANSPNT) {
#if (PLC_INCLUDED == TRUE)
sbc_plc_deinit(&(bta_hf_ct_plc.plc_state));
bta_hf_ct_plc.first_good_frame_found = FALSE;
#if (HFP_DYNAMIC_MEMORY == TRUE)
osi_free(bta_hf_ct_plc_ptr);
bta_hf_ct_plc_ptr = NULL;
#endif /// (HFP_DYNAMIC_MEMORY == TRUE)
#endif ///(PLC_INCLUDED == TRUE)
#if (HFP_DYNAMIC_MEMORY == TRUE)
osi_free(bta_hf_client_co_cb_ptr);
bta_hf_client_co_cb_ptr = NULL;
#endif /* HFP_DYNAMIC_MEMORY == TRUE */
} else {
// Nothing to do
}
hf_air_mode = BTM_SCO_AIR_MODE_UNKNOWN;
hf_inout_pkt_size = 0;
}
/*******************************************************************************
**
** Function bta_hf_client_h2_header
**
** Description This function is called to fill in H2 header
**
** Returns void
**
*******************************************************************************/
static void bta_hf_client_h2_header(UINT16 *p_buf)
{
// H2: Header with synchronization word and sequence number
#define BTA_HF_H2_HEADER 0x0801
#define BTA_HF_H2_HEADER_BIT0_MASK (1 << 0)
#define BTA_HF_H2_HEADER_BIT1_MASK (1 << 1)
#define BTA_HF_H2_HEADER_SN0_BIT_OFFSET1 12
#define BTA_HF_H2_HEADER_SN0_BIT_OFFSET2 13
#define BTA_HF_H2_HEADER_SN1_BIT_OFFSET1 14
#define BTA_HF_H2_HEADER_SN1_BIT_OFFSET2 15
UINT16 h2_header = BTA_HF_H2_HEADER;
UINT8 h2_header_sn0 = bta_hf_client_co_cb.sequence_number & BTA_HF_H2_HEADER_BIT0_MASK;
UINT8 h2_header_sn1 = bta_hf_client_co_cb.sequence_number & BTA_HF_H2_HEADER_BIT1_MASK;
h2_header |= (h2_header_sn0 << BTA_HF_H2_HEADER_SN0_BIT_OFFSET1
| h2_header_sn0 << BTA_HF_H2_HEADER_SN0_BIT_OFFSET2
| h2_header_sn1 << (BTA_HF_H2_HEADER_SN1_BIT_OFFSET1 - 1)
| h2_header_sn1 << (BTA_HF_H2_HEADER_SN1_BIT_OFFSET2 - 1)
);
bta_hf_client_co_cb.sequence_number++;
*p_buf = h2_header;
}
/*******************************************************************************
**
** Function bta_hf_client_sco_co_out_data
**
** Description This function is called to send SCO data over HCI.
**
** Returns number of bytes got from application
**
*******************************************************************************/
uint32_t bta_hf_client_sco_co_out_data(UINT8 *p_buf)
{
if (hf_air_mode == BTM_SCO_AIR_MODE_CVSD) {
// CVSD
uint32_t hf_raw_pkt_size = hf_inout_pkt_size;
return btc_hf_client_outgoing_data_cb_to_app(p_buf, hf_raw_pkt_size);
} else if (hf_air_mode == BTM_SCO_AIR_MODE_TRANSPNT) {
// mSBC
#if (HFP_DYNAMIC_MEMORY == TRUE)
if(bta_hf_client_co_cb_ptr == NULL) {
return 0;
}
#endif /* HFP_DYNAMIC_MEMORY == TRUE */
if (hf_inout_pkt_size == BTM_MSBC_FRAME_SIZE / 2) {
if (bta_hf_client_co_cb.encode_first_pkt){
UINT32 size = btc_hf_client_outgoing_data_cb_to_app((UINT8 *)bta_hf_client_co_cb.encoder.as16PcmBuffer, HF_SBC_ENC_RAW_DATA_SIZE);
if (size != HF_SBC_ENC_RAW_DATA_SIZE){
return 0;
}
bta_hf_client_h2_header((UINT16 *)bta_hf_client_co_cb.encode_msbc_data);
bta_hf_client_co_cb.encoder.pu8Packet = bta_hf_client_co_cb.encode_msbc_data + 2;
SBC_Encoder(&bta_hf_client_co_cb.encoder);
memcpy(p_buf, bta_hf_client_co_cb.encode_msbc_data, hf_inout_pkt_size);
bta_hf_client_co_cb.encode_first_pkt = !bta_hf_client_co_cb.encode_first_pkt;
return hf_inout_pkt_size;
} else {
memcpy(p_buf, bta_hf_client_co_cb.encode_msbc_data + hf_inout_pkt_size, hf_inout_pkt_size);
bta_hf_client_co_cb.encode_first_pkt = !bta_hf_client_co_cb.encode_first_pkt;
return hf_inout_pkt_size;
}
} else if (hf_inout_pkt_size == BTM_MSBC_FRAME_SIZE) {
UINT32 size = btc_hf_client_outgoing_data_cb_to_app((UINT8 *)bta_hf_client_co_cb.encoder.as16PcmBuffer, HF_SBC_ENC_RAW_DATA_SIZE);
if (size != HF_SBC_ENC_RAW_DATA_SIZE){
return 0;
}
bta_hf_client_h2_header((UINT16 *)p_buf);
bta_hf_client_co_cb.encoder.pu8Packet = p_buf + 2;
SBC_Encoder(&bta_hf_client_co_cb.encoder);
return hf_inout_pkt_size;
} else {
//Never run to here.
}
} else {
APPL_TRACE_ERROR("%s invaild air mode: %d", __FUNCTION__, hf_air_mode);
}
return 0;
}
/*******************************************************************************
**
** Function bta_hf_client_decode_msbc_frame
**
** Description This function is called decode a mSBC frame
**
** Returns void
**
*******************************************************************************/
static void bta_hf_client_decode_msbc_frame(UINT8 **data, UINT8 *length, BOOLEAN is_bad_frame){
OI_STATUS status;
const OI_BYTE *zero_signal_frame_data;
UINT8 zero_signal_frame_len = BTM_MSBC_FRAME_DATA_SIZE;
UINT32 sbc_raw_data_size = HF_SBC_DEC_RAW_DATA_SIZE;
if (is_bad_frame){
status = OI_CODEC_SBC_CHECKSUM_MISMATCH;
} else {
status = OI_CODEC_SBC_DecodeFrame(&bta_hf_client_co_cb.decoder_context, (const OI_BYTE **)data,
(OI_UINT32 *)length,
(OI_INT16 *)bta_hf_client_co_cb.decode_raw_data,
(OI_UINT32 *)&sbc_raw_data_size);
}
// PLC_INCLUDED will be set to TRUE when enabling Wide Band Speech
#if (PLC_INCLUDED == TRUE)
switch(status){
case OI_OK:
bta_hf_ct_plc.first_good_frame_found = TRUE;
sbc_plc_good_frame(&(bta_hf_ct_plc.plc_state), (int16_t *)bta_hf_client_co_cb.decode_raw_data, bta_hf_ct_plc.sbc_plc_out);
case OI_CODEC_SBC_NOT_ENOUGH_HEADER_DATA:
case OI_CODEC_SBC_NOT_ENOUGH_BODY_DATA:
case OI_CODEC_SBC_NOT_ENOUGH_AUDIO_DATA:
break;
case OI_CODEC_SBC_NO_SYNCWORD:
case OI_CODEC_SBC_CHECKSUM_MISMATCH:
if (!bta_hf_ct_plc.first_good_frame_found) {
break;
}
zero_signal_frame_data = sbc_plc_zero_signal_frame();
sbc_raw_data_size = HF_SBC_DEC_RAW_DATA_SIZE;
status = OI_CODEC_SBC_DecodeFrame(&bta_hf_client_co_cb.decoder_context, &zero_signal_frame_data,
(OI_UINT32 *)&zero_signal_frame_len,
(OI_INT16 *)bta_hf_client_co_cb.decode_raw_data,
(OI_UINT32 *)&sbc_raw_data_size);
sbc_plc_bad_frame(&(bta_hf_ct_plc.plc_state), bta_hf_client_co_cb.decode_raw_data, bta_hf_ct_plc.sbc_plc_out);
APPL_TRACE_DEBUG("bad frame, using PLC to fix it.");
break;
case OI_STATUS_INVALID_PARAMETERS:
// This caused by corrupt frames.
// The codec apparently does not recover from this.
// Re-initialize the codec.
APPL_TRACE_ERROR("Frame decode error: OI_STATUS_INVALID_PARAMETERS");
if (!OI_SUCCESS(OI_CODEC_SBC_DecoderReset(&bta_hf_client_co_cb.decoder_context, bta_hf_client_co_cb.decoder_context_data,
HF_SBC_DEC_CONTEXT_DATA_LEN * sizeof(OI_UINT32), 1, 1, FALSE, TRUE))) {
APPL_TRACE_ERROR("OI_CODEC_SBC_DecoderReset failed with error code %d\n", status);
}
break;
default:
APPL_TRACE_ERROR("Frame decode error: %d", status);
break;
}
#endif ///(PLC_INCLUDED == TRUE)
if (OI_SUCCESS(status)){
btc_hf_client_incoming_data_cb_to_app((const uint8_t *)(bta_hf_ct_plc.sbc_plc_out), sbc_raw_data_size);
}
}
/*******************************************************************************
**
** Function bta_hf_client_sco_co_in_data
**
** Description This function is called to send incoming SCO data to application.
**
** Returns void
**
*******************************************************************************/
void bta_hf_client_sco_co_in_data(BT_HDR *p_buf, tBTM_SCO_DATA_FLAG status)
{
UINT8 *p = (UINT8 *)(p_buf + 1) + p_buf->offset;
UINT8 pkt_size = 0;
STREAM_SKIP_UINT16(p);
STREAM_TO_UINT8 (pkt_size, p);
if (hf_air_mode == BTM_SCO_AIR_MODE_CVSD) {
// CVSD
if(status != BTM_SCO_DATA_CORRECT){
APPL_TRACE_DEBUG("%s: not a correct frame(%d).", __func__, status);
}
btc_hf_client_incoming_data_cb_to_app(p, pkt_size);
} else if (hf_air_mode == BTM_SCO_AIR_MODE_TRANSPNT) {
// mSBC
UINT8 *data = NULL;
if (pkt_size != hf_inout_pkt_size) {
bta_hf_client_co_cb.is_bad_frame = true;
}
if (status != BTM_SCO_DATA_CORRECT) {
bta_hf_client_co_cb.is_bad_frame = true;
}
if (hf_inout_pkt_size == BTM_MSBC_FRAME_SIZE / 2) {
if (bta_hf_client_co_cb.decode_first_pkt){
if (!bta_hf_client_co_cb.is_bad_frame){
memcpy(bta_hf_client_co_cb.decode_msbc_data, p, pkt_size);
}
} else {
if (!bta_hf_client_co_cb.is_bad_frame){
memcpy(bta_hf_client_co_cb.decode_msbc_data + BTM_MSBC_FRAME_SIZE / 2, p, pkt_size);
}
data = bta_hf_client_co_cb.decode_msbc_data;
bta_hf_client_decode_msbc_frame(&data, &pkt_size, bta_hf_client_co_cb.is_bad_frame);
bta_hf_client_co_cb.is_bad_frame = false;
}
bta_hf_client_co_cb.decode_first_pkt = !bta_hf_client_co_cb.decode_first_pkt;
} else if (hf_inout_pkt_size == BTM_MSBC_FRAME_SIZE) {
data = p;
bta_hf_client_decode_msbc_frame(&data, &pkt_size, bta_hf_client_co_cb.is_bad_frame);
bta_hf_client_co_cb.is_bad_frame = false;
} else {
//Never run to here.
}
} else {
APPL_TRACE_ERROR("%s invaild air mode: %d", __FUNCTION__, hf_air_mode);
}
}
#endif /* #if (BTM_SCO_HCI_INCLUDED == TRUE) */
#endif /* #if (BTA_HF_INCLUDED == TRUE) */
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,152 @@
#include "btc_hh.h"
#include "osi/allocator.h"
#include "string.h"
#if HID_HOST_INCLUDED == TRUE
/*******************************************************************************
*
* Function bta_hh_co_open
*
* Description When connection is opened, this call-out function is executed
* by HH to do platform specific initialization.
*
* Returns void.
******************************************************************************/
void bta_hh_co_open(uint8_t dev_handle, uint8_t sub_class, tBTA_HH_ATTR_MASK attr_mask, uint8_t app_id)
{
uint32_t i;
btc_hh_device_t *p_dev = NULL;
if (dev_handle == BTA_HH_INVALID_HANDLE) {
APPL_TRACE_WARNING("%s: Oops, dev_handle (%d) is invalid...", __func__, dev_handle);
return;
}
for (i = 0; i < BTC_HH_MAX_HID; i++) {
p_dev = &btc_hh_cb.devices[i];
if (p_dev->dev_status != ESP_HIDH_CONN_STATE_UNKNOWN && p_dev->dev_handle == dev_handle) {
// We found a device with the same handle. Must be a device reconnected.
APPL_TRACE_WARNING("%s: Found an existing device with the same handle dev_status=%d, "
"dev_handle=0x%2x, attr_mask=0x%04x, sub_class=0x%02x, app_id=%d",
__func__, p_dev->dev_status, dev_handle, p_dev->attr_mask, p_dev->sub_class,
p_dev->app_id);
break;
}
p_dev = NULL;
}
if (p_dev == NULL) {
// Did not find a device reconnection case. Find an empty slot now.
for (i = 0; i < BTC_HH_MAX_HID; i++) {
if (btc_hh_cb.devices[i].dev_status == ESP_HIDH_CONN_STATE_UNKNOWN) {
p_dev = &btc_hh_cb.devices[i];
p_dev->dev_handle = dev_handle;
p_dev->attr_mask = attr_mask;
p_dev->sub_class = sub_class;
p_dev->app_id = app_id;
p_dev->local_vup = false;
btc_hh_cb.device_num++;
break;
}
}
}
if (p_dev == NULL) {
APPL_TRACE_ERROR("%s: Error: too many HID devices are connected", __func__);
return;
}
p_dev->dev_status = ESP_HIDH_CONN_STATE_CONNECTED;
APPL_TRACE_DEBUG("%s: Return device status %d", __func__, p_dev->dev_status);
}
/*******************************************************************************
*
* Function bta_hh_co_close
*
* Description When connection is closed, this call-out function is executed
* by HH to do platform specific finalization.
*
* Parameters dev_handle - device handle
* app_id - application id
*
* Returns void.
******************************************************************************/
void bta_hh_co_close(uint8_t dev_handle, uint8_t app_id)
{
uint32_t i;
btc_hh_device_t *p_dev = NULL;
APPL_TRACE_WARNING("%s: dev_handle = %d, app_id = %d", __func__, dev_handle, app_id);
if (dev_handle == BTA_HH_INVALID_HANDLE) {
APPL_TRACE_WARNING("%s: Oops, dev_handle (%d) is invalid...", __func__, dev_handle);
return;
}
for (i = 0; i < BTC_HH_MAX_HID; i++) {
p_dev = &btc_hh_cb.devices[i];
if (p_dev->dev_status != ESP_HIDH_CONN_STATE_UNKNOWN && p_dev->dev_handle == dev_handle) {
APPL_TRACE_WARNING("%s: Found an existing device with the same handle "
"dev_status = %d, dev_handle =%d",
__func__, p_dev->dev_status, p_dev->dev_handle);
break;
}
}
}
/*******************************************************************************
*
* Function bta_hh_co_data
*
* Description This function is executed by BTA when HID host receive a
* data report on interrupt channel.
*
* Parameters dev_handle - device handle
* *p_rpt - pointer to the report data
* len - length of report data
* mode - Hid host Protocol Mode
* sub_clas - Device Subclass
* app_id - application id
*
* Returns void
******************************************************************************/
void bta_hh_co_data(UINT8 dev_handle, UINT8 *p_rpt, UINT16 len, tBTA_HH_PROTO_MODE mode, UINT8 sub_class, UINT8 ctry_code,
BD_ADDR peer_addr, UINT8 app_id)
{
btc_msg_t msg;
tBTA_HH p_data;
BT_HDR *p_buf = NULL;
bt_status_t status;
tBTA_HH_STATUS ret = BTA_HH_OK;
msg.sig = BTC_SIG_API_CB;
msg.pid = BTC_PID_HH;
msg.act = BTA_HH_DATA_IND_EVT;
APPL_TRACE_DEBUG("%s: dev_handle = %d, subclass = 0x%02X, mode = %d, "
"ctry_code = %d, app_id = %d",
__func__, dev_handle, sub_class, mode, ctry_code, app_id);
do {
if ((p_buf = osi_malloc(sizeof(BT_HDR) + len)) == NULL) {
APPL_TRACE_ERROR("%s malloc failed!", __func__);
ret = BTA_HH_ERR_NO_RES;
break;
}
p_buf->offset = 0;
p_buf->len = len;
p_buf->event = 0;
p_buf->layer_specific = dev_handle;
memcpy(p_buf->data, p_rpt, len);
} while (0);
p_data.int_data.status = ret;
p_data.int_data.handle = dev_handle;
p_data.int_data.p_data = p_buf;
p_data.int_data.proto_mode = mode;
status = btc_transfer_context(&msg, &p_data, sizeof(tBTA_HH), NULL, NULL);
assert(status == BT_STATUS_SUCCESS);
}
#endif /* HID_HOST_INCLUDED == TRUE */
@@ -0,0 +1,964 @@
/******************************************************************************
*
* Copyright (C) 2016 The Android Open Source Project
* Copyright (C) 2009-2012 Broadcom Corporation
* Copyright (C) 2019 Blake Felt
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
/************************************************************************************
*
* Filename: btc_hd.c
*
* Description: HID Device Profile Bluetooth Interface
*
*
***********************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "bta/bta_api.h"
#include "bta/bta_hd_api.h"
#include "bta/bta_hh_api.h"
#include "bta/utl.h"
#include "btc/btc_storage.h"
#include "btc/btc_util.h"
#include "btc/btc_manage.h"
#include "btc_hd.h"
#include "osi/allocator.h"
#include "esp_hidd_api.h"
#if HID_DEV_INCLUDED == TRUE
#include "bta_dm_int.h"
/* HD request events */
typedef enum { BTC_HD_DUMMY_REQ_EVT = 0 } btc_hd_req_evt_t;
/*******************************************************************************
* Static variables
******************************************************************************/
btc_hd_cb_t btc_hd_cb = {0};
// static tBTA_HD_APP_INFO app_info;
// static tBTA_HD_QOS_INFO in_qos;
// static tBTA_HD_QOS_INFO out_qos;
/******************************************************************************
* Constants & Macros
*****************************************************************************/
#define BTC_HD_APP_NAME_LEN 50
#define BTC_HD_APP_DESCRIPTION_LEN 50
#define BTC_HD_APP_PROVIDER_LEN 50
#define BTC_HD_APP_DESCRIPTOR_LEN 2048
#define COD_HID_KEYBOARD 0x0540
#define COD_HID_POINTING 0x0580
#define COD_HID_COMBO 0x05C0
#define COD_HID_MAJOR 0x0500
#define is_hidd_init() (btc_hd_cb.status > BTC_HD_DISABLED)
#define is_hidd_app_register() (btc_hd_cb.app_registered)
typedef void (bt_hid_copy_cb_t)(btc_msg_t *msg, void *p_dest, void *p_src);
static inline void btc_hd_cb_to_app(esp_hidd_cb_event_t event, esp_hidd_cb_param_t *param)
{
esp_hd_cb_t btc_hd_cb = (esp_hd_cb_t)btc_profile_cb_get(BTC_PID_HD);
if (btc_hd_cb) {
btc_hd_cb(event, param);
}
}
static void free_app_info_param(void)
{
utl_freebuf((void **)&btc_hd_cb.app_info.descriptor.dsc_list);
utl_freebuf((void **)&btc_hd_cb.app_info.p_provider);
utl_freebuf((void **)&btc_hd_cb.app_info.p_description);
utl_freebuf((void **)&btc_hd_cb.app_info.p_name);
}
static void bte_hd_arg_deep_copy(btc_msg_t *msg, void *p_dst, void *p_src)
{
tBTA_HD *p_dst_data = (tBTA_HD *)p_dst;
tBTA_HD *p_src_data = (tBTA_HD *)p_src;
switch (msg->act)
{
case BTA_HD_SET_REPORT_EVT: {
uint8_t *src_data = p_src_data->set_report.p_data;
if (src_data) {
p_dst_data->set_report.p_data = osi_malloc(p_src_data->set_report.len);
if (p_dst_data->set_report.p_data == NULL) {
BTC_TRACE_ERROR("%s malloc set_report data failed!", __func__);
break;
}
memcpy(p_dst_data->set_report.p_data, src_data, p_src_data->set_report.len);
}
break;
}
case BTA_HD_INTR_DATA_EVT: {
uint8_t *src_data = p_src_data->intr_data.p_data;
if (src_data) {
p_dst_data->intr_data.p_data = osi_malloc(p_src_data->intr_data.len);
if (p_dst_data->intr_data.p_data == NULL) {
BTC_TRACE_ERROR("%s malloc intr_data data failed!", __func__);
break;
}
memcpy(p_dst_data->intr_data.p_data, src_data, p_src_data->intr_data.len);
}
break;
}
default:
break;
}
}
/*******************************************************************************
*
* Function btc_hd_remove_device
*
* Description Removes plugged device
*
* Returns void
*
******************************************************************************/
void btc_hd_remove_device(bt_bdaddr_t bd_addr)
{
BTA_HdRemoveDevice((uint8_t *)&bd_addr);
// btc_storage_remove_hidd(&bd_addr);
}
/*******************************************************************************
*
* Function bte_hd_evt
*
* Description Switches context from BTE to BTC for all BT-HD events
*
* Returns void
*
******************************************************************************/
static void bte_hd_evt(tBTA_HD_EVT event, tBTA_HD *p_data)
{
bt_status_t status;
int param_len = 0;
BTC_TRACE_API("%s event=%d", __func__, event);
switch (event) {
case BTA_HD_ENABLE_EVT:
case BTA_HD_DISABLE_EVT:
case BTA_HD_UNREGISTER_APP_EVT:
param_len = sizeof(tBTA_HD_STATUS);
break;
case BTA_HD_REGISTER_APP_EVT:
param_len = sizeof(tBTA_HD_REG_STATUS);
break;
case BTA_HD_OPEN_EVT:
case BTA_HD_CLOSE_EVT:
case BTA_HD_VC_UNPLUG_EVT:
param_len = sizeof(tBTA_HD_CONN);
break;
case BTA_HD_GET_REPORT_EVT:
param_len += sizeof(tBTA_HD_GET_REPORT);
break;
case BTA_HD_SET_REPORT_EVT:
param_len = sizeof(tBTA_HD_SET_REPORT);
break;
case BTA_HD_SET_PROTOCOL_EVT:
param_len += sizeof(p_data->set_protocol);
break;
case BTA_HD_INTR_DATA_EVT:
param_len = sizeof(tBTA_HD_INTR_DATA);
break;
case BTA_HD_SEND_REPORT_EVT:
param_len = sizeof(tBTA_HD_API_SEND_REPORT);
break;
case BTA_HD_REPORT_ERR_EVT:
param_len = sizeof(tBTA_HD_API_REPORT_ERR);
break;
}
btc_msg_t msg;
msg.sig = BTC_SIG_API_CB;
msg.pid = BTC_PID_HD;
msg.act = event;
status = btc_transfer_context(&msg, p_data, param_len, bte_hd_arg_deep_copy, btc_hd_cb_arg_deep_free);
if (status != BT_STATUS_SUCCESS) {
BTC_TRACE_ERROR("context transfer failed");
}
}
/*******************************************************************************
*
* Function btc_hd_init
*
* Description Initializes BT-HD interface
*
* Returns void
*
******************************************************************************/
static void btc_hd_init(void)
{
BTC_TRACE_API("%s", __func__);
esp_hidd_status_t ret = ESP_HIDD_SUCCESS;
do {
if (is_hidd_init()) {
BTC_TRACE_ERROR("%s HD has been initiated, shall uninit first!", __func__);
ret = ESP_HIDD_NEED_DEINIT;
break;
}
memset(&btc_hd_cb, 0, sizeof(btc_hd_cb));
/* enable HD */
BTA_HdEnable(bte_hd_evt);
} while (0);
if (ret != ESP_HIDD_SUCCESS) {
esp_hidd_cb_param_t param;
param.init.status = ret;
btc_hd_cb_to_app(ESP_HIDD_INIT_EVT, &param);
}
}
/*******************************************************************************
*
* Function btc_hd_deinit
*
* Description de-initializes the hd interface
*
* Returns void
*
******************************************************************************/
static void btc_hd_unregister_app(bool need_deinit);
static void btc_hd_deinit(void)
{
BTC_TRACE_API("%s", __func__);
esp_hidd_status_t ret = ESP_HIDD_SUCCESS;
do {
if (!is_hidd_init()) {
BTC_TRACE_ERROR("%s HD has not been initiated, shall init first!", __func__);
ret = ESP_HIDD_NEED_INIT;
break;
}
if (btc_hd_cb.status == BTC_HD_DISABLING) {
BTC_TRACE_ERROR("%s is disabling, try later!", __func__);
ret = ESP_HIDD_BUSY;
break;
}
btc_hd_cb.service_dereg_active = FALSE;
// unresgister app will also relase the connection
// and disable after receiving unregister event from lower layer
if (is_hidd_app_register()) {
btc_hd_unregister_app(true);
} else {
btc_hd_cb.status = BTC_HD_DISABLING;
BTC_TRACE_WARNING("%s disabling hid device service now", __func__);
BTA_HdDisable();
}
} while (0);
if (ret != ESP_HIDD_SUCCESS) {
esp_hidd_cb_param_t param;
param.deinit.status = ret;
btc_hd_cb_to_app(ESP_HIDD_DEINIT_EVT, &param);
}
}
/*******************************************************************************
*
* Function btc_hd_register_app
*
* Description Registers HID Device application
*
* Returns void
*
******************************************************************************/
static void btc_hd_register_app(esp_hidd_app_param_t *p_app_param, esp_hidd_qos_param_t *p_in_qos,
esp_hidd_qos_param_t *p_out_qos)
{
BTC_TRACE_API("%s", __func__);
esp_hidd_status_t ret = ESP_HIDD_SUCCESS;
do {
if (!is_hidd_init()) {
BTC_TRACE_ERROR("%s HD has not been initiated, shall init first!", __func__);
ret = ESP_HIDD_NEED_INIT;
break;
} else if (btc_hd_cb.status == BTC_HD_DISABLING) {
BTC_TRACE_ERROR("%s: deinit is in progress!", __func__);
ret = ESP_HIDD_BUSY;
break;
}
if (is_hidd_app_register()) {
BTC_TRACE_ERROR("%s: application already registered, shall deregister first!", __func__);
ret = ESP_HIDD_NEED_DEREG;
break;
}
if ((btc_hd_cb.app_info.p_name = (char *)osi_malloc(BTC_HD_APP_NAME_LEN)) == NULL ||
(btc_hd_cb.app_info.p_description = (char *)osi_malloc(BTC_HD_APP_DESCRIPTION_LEN)) == NULL ||
(btc_hd_cb.app_info.p_provider = (char *)osi_malloc(BTC_HD_APP_PROVIDER_LEN)) == NULL ||
(btc_hd_cb.app_info.descriptor.dsc_list = (uint8_t *)osi_malloc(p_app_param->desc_list_len)) == NULL) {
BTC_TRACE_ERROR(
"%s malloc app_info failed! p_name:%p, p_description:%p, p_provider:%p, descriptor.dsc_list:%p",
__func__, btc_hd_cb.app_info.p_name, btc_hd_cb.app_info.p_description, btc_hd_cb.app_info.p_provider,
btc_hd_cb.app_info.descriptor.dsc_list);
ret = ESP_HIDD_NO_RES;
break;
}
memcpy(btc_hd_cb.app_info.p_name, p_app_param->name, BTC_HD_APP_NAME_LEN);
memcpy(btc_hd_cb.app_info.p_description, p_app_param->description, BTC_HD_APP_DESCRIPTION_LEN);
memcpy(btc_hd_cb.app_info.p_provider, p_app_param->provider, BTC_HD_APP_PROVIDER_LEN);
memcpy(btc_hd_cb.app_info.descriptor.dsc_list, p_app_param->desc_list, p_app_param->desc_list_len);
btc_hd_cb.app_info.subclass = p_app_param->subclass;
btc_hd_cb.app_info.descriptor.dl_len = p_app_param->desc_list_len;
btc_hd_cb.in_qos.service_type = p_in_qos->service_type;
btc_hd_cb.in_qos.token_rate = p_in_qos->token_rate;
btc_hd_cb.in_qos.token_bucket_size = p_in_qos->token_bucket_size;
btc_hd_cb.in_qos.peak_bandwidth = p_in_qos->peak_bandwidth;
btc_hd_cb.in_qos.access_latency = p_in_qos->access_latency;
btc_hd_cb.in_qos.delay_variation = p_in_qos->delay_variation;
btc_hd_cb.out_qos.service_type = p_out_qos->service_type;
btc_hd_cb.out_qos.token_rate = p_out_qos->token_rate;
btc_hd_cb.out_qos.token_bucket_size = p_out_qos->token_bucket_size;
btc_hd_cb.out_qos.peak_bandwidth = p_out_qos->peak_bandwidth;
btc_hd_cb.out_qos.access_latency = p_out_qos->access_latency;
btc_hd_cb.out_qos.delay_variation = p_out_qos->delay_variation;
BTA_HdRegisterApp(&btc_hd_cb.app_info, &btc_hd_cb.in_qos, &btc_hd_cb.out_qos);
} while(0);
if (ret != ESP_HIDD_SUCCESS) {
esp_hidd_cb_param_t param;
param.register_app.status = ret;
param.register_app.in_use = false;
memset(param.register_app.bd_addr, 0, BD_ADDR_LEN);
btc_hd_cb_to_app(ESP_HIDD_REGISTER_APP_EVT, &param);
}
free_app_info_param();
}
/*******************************************************************************
*
* Function btc_hd_unregister_app
*
* Description Unregisters HID Device application
*
* Returns void
*
******************************************************************************/
static void btc_hd_unregister_app(bool need_deinit)
{
BTC_TRACE_API("%s", __func__);
esp_hidd_status_t ret = ESP_HIDD_SUCCESS;
do {
if (!is_hidd_init()) {
BTC_TRACE_ERROR("%s HD has not been initiated, shall init first!", __func__);
ret = ESP_HIDD_NEED_INIT;
break;
} else if (btc_hd_cb.status == BTC_HD_DISABLING) {
BTC_TRACE_ERROR("%s: deinit is in progress!", __func__);
ret = ESP_HIDD_BUSY;
break;
}
if (!is_hidd_app_register()) {
BTC_TRACE_ERROR("%s: application has not been registered, shall register first!", __func__);
ret = ESP_HIDD_NEED_REG;
break;
}
if (btc_hd_cb.service_dereg_active) {
BTC_TRACE_ERROR("%s: BT-HD deregistering in progress", __func__);
ret = ESP_HIDD_BUSY;
break;
}
btc_hd_cb.service_dereg_active = TRUE;
if (need_deinit) {
btc_hd_cb.status = BTC_HD_DISABLING;
}
BTA_HdUnregisterApp();
} while(0);
if (ret != ESP_HIDD_SUCCESS) {
esp_hidd_cb_param_t param = {0};
param.unregister_app.status = ret;
btc_hd_cb_to_app(ESP_HIDD_UNREGISTER_APP_EVT, &param);
}
}
/*******************************************************************************
*
* Function btc_hd_connect
*
* Description Connects to host
*
* Returns void
*
******************************************************************************/
static void btc_hd_connect(BD_ADDR bd_addr)
{
BTC_TRACE_API("%s", __func__);
esp_hidd_status_t ret = ESP_HIDD_SUCCESS;
do {
switch (btc_hd_cb.status) {
case BTC_HD_DISABLED:
BTC_TRACE_ERROR("%s HD has not been initiated, shall init first!", __func__);
ret = ESP_HIDD_NEED_INIT;
break;
case BTC_HD_DISABLING:
BTC_TRACE_ERROR("%s: deinit is in progress!", __func__);
ret = ESP_HIDD_BUSY;
break;
case BTC_HD_CONNECTING:
case BTC_HD_DISCONNECTING:
BTC_TRACE_ERROR("%s: busy now, status:%d, try later!", __func__, btc_hd_cb.status);
ret = ESP_HIDD_BUSY;
break;
case BTC_HD_CONNECTED:
BTC_TRACE_ERROR("%s: already connect to the other HID host!", __func__);
ret = ESP_HIDD_NO_RES;
break;
default:
break;
}
if (ret != ESP_HIDD_SUCCESS) {
break;
}
if (!is_hidd_app_register()) {
BTC_TRACE_ERROR("%s: application has not been registered, shall register first!", __func__);
ret = ESP_HIDD_NEED_REG;
break;
}
BTA_HdConnect(bd_addr);
btc_hd_cb.status = BTC_HD_CONNECTING;
} while (0);
if (ret != ESP_HIDD_SUCCESS) {
esp_hidd_cb_param_t param = {0};
param.open.status = ret;
param.open.conn_status = ESP_HIDD_CONN_STATE_DISCONNECTED;
memcpy(param.open.bd_addr, bd_addr, BD_ADDR_LEN);
btc_hd_cb_to_app(ESP_HIDD_OPEN_EVT, &param);
}
}
/*******************************************************************************
*
* Function btc_hd_disconnect
*
* Description Disconnects from host
*
* Returns void
*
******************************************************************************/
static void btc_hd_disconnect(void)
{
BTC_TRACE_API("%s", __func__);
esp_hidd_status_t ret = ESP_HIDD_SUCCESS;
do {
switch (btc_hd_cb.status) {
case BTC_HD_DISABLED:
BTC_TRACE_ERROR("%s HD has not been initiated, shall init first!", __func__);
ret = ESP_HIDD_NEED_INIT;
break;
case BTC_HD_DISABLING:
BTC_TRACE_ERROR("%s: deinit is in progress!", __func__);
ret = ESP_HIDD_BUSY;
break;
case BTC_HD_CONNECTING:
case BTC_HD_DISCONNECTING:
BTC_TRACE_ERROR("%s: busy now, status:%d, try later!", __func__, btc_hd_cb.status);
ret = ESP_HIDD_BUSY;
break;
case BTC_HD_ENABLED:
case BTC_HD_DISCONNECTED:
BTC_TRACE_ERROR("%s: no connection!", __func__);
ret = ESP_HIDD_NO_CONNECTION;
break;
default:
break;
}
if (ret != ESP_HIDD_SUCCESS) {
break;
}
if (!is_hidd_app_register()) {
BTC_TRACE_ERROR("%s: application has not been registered, shall register first!", __func__);
ret = ESP_HIDD_NEED_REG;
break;
}
BTA_HdDisconnect();
btc_hd_cb.status = BTC_HD_DISCONNECTING;
} while (0);
if (ret != ESP_HIDD_SUCCESS) {
esp_hidd_cb_param_t param = {0};
param.close.status = ret;
param.close.conn_status = ESP_HIDD_CONN_STATE_DISCONNECTED;
btc_hd_cb_to_app(ESP_HIDD_CLOSE_EVT, &param);
}
}
/*******************************************************************************
*
* Function btc_hd_send_report
*
* Description Sends Reports to hid host
*
* Returns void
*
******************************************************************************/
static void btc_hd_send_report(esp_hidd_report_type_t type, uint8_t id, uint16_t len, uint8_t *p_data)
{
BTC_TRACE_API("%s: type=%d id=%d len=%d", __func__, type, id, len);
tBTA_HD_REPORT report = {0};
esp_hidd_status_t ret = ESP_HIDD_SUCCESS;
do {
switch (btc_hd_cb.status) {
case BTC_HD_DISABLED:
BTC_TRACE_ERROR("%s HD has not been initiated, shall init first!", __func__);
ret = ESP_HIDD_NEED_INIT;
break;
case BTC_HD_DISABLING:
BTC_TRACE_ERROR("%s: deinit is in progress!", __func__);
ret = ESP_HIDD_BUSY;
break;
case BTC_HD_CONNECTING:
case BTC_HD_DISCONNECTING:
BTC_TRACE_ERROR("%s: busy now, status:%d, try later!", __func__, btc_hd_cb.status);
ret = ESP_HIDD_BUSY;
break;
case BTC_HD_ENABLED:
case BTC_HD_DISCONNECTED:
if (type == ESP_HIDD_REPORT_TYPE_INTRDATA) {
BTC_TRACE_WARNING("%s: no connection, try to reconnect!", __func__);
btc_hd_cb.status = BTC_HD_CONNECTING;
} else {
BTC_TRACE_ERROR("%s: no connection!", __func__);
ret = ESP_HIDD_NO_CONNECTION;
}
break;
default:
break;
}
if (ret != ESP_HIDD_SUCCESS) {
break;
}
if (!is_hidd_app_register()) {
BTC_TRACE_ERROR("%s: application has not been registered, shall register first!", __func__);
ret = ESP_HIDD_NEED_REG;
break;
}
if (type == ESP_HIDD_REPORT_TYPE_INTRDATA) {
report.type = ESP_HIDD_REPORT_TYPE_INPUT;
report.use_intr = TRUE;
} else {
report.type = (type & 0x03);
report.use_intr = FALSE;
}
report.id = id;
report.len = len;
report.p_data = p_data;
BTA_HdSendReport(&report);
} while (0);
if (ret != ESP_HIDD_SUCCESS) {
esp_hidd_cb_param_t param = {0};
param.send_report.status = ret;
param.send_report.reason = 0;
param.send_report.report_type = report.type;
param.send_report.report_id = report.id;
btc_hd_cb_to_app(ESP_HIDD_SEND_REPORT_EVT, &param);
}
}
/*******************************************************************************
*
* Function btc_hd_report_error
*
* Description Sends HANDSHAKE with error info for invalid SET_REPORT
*
* Returns void
*
******************************************************************************/
static void btc_hd_report_error(uint8_t error)
{
BTC_TRACE_API("%s", __func__);
esp_hidd_status_t ret = ESP_HIDD_SUCCESS;
do {
if (!is_hidd_init()) {
BTC_TRACE_ERROR("%s HD has not been initiated, shall init first!", __func__);
ret = ESP_HIDD_NEED_INIT;
break;
}
if (!is_hidd_app_register()) {
BTC_TRACE_ERROR("%s: application has not been registered, shall register first!", __func__);
ret = ESP_HIDD_NEED_REG;
break;
}
if (btc_hd_cb.status != BTC_HD_CONNECTED) {
BTC_TRACE_ERROR("%s: no connection!", __func__);
ret = ESP_HIDD_NO_CONNECTION;
break;
}
BTA_HdReportError(error);
} while (0);
if (ret != ESP_HIDD_SUCCESS) {
esp_hidd_cb_param_t param = {0};
param.report_err.status = ret;
param.report_err.reason = 0;
btc_hd_cb_to_app(ESP_HIDD_REPORT_ERR_EVT, &param);
}
}
/*******************************************************************************
*
* Function btc_hd_virtual_cable_unplug
*
* Description Sends Virtual Cable Unplug to host
*
* Returns void
*
******************************************************************************/
static void btc_hd_virtual_cable_unplug(void)
{
BTC_TRACE_API("%s", __func__);
esp_hidd_status_t ret = ESP_HIDD_SUCCESS;
do {
switch (btc_hd_cb.status) {
case BTC_HD_DISABLED:
BTC_TRACE_ERROR("%s HD has not been initiated, shall init first!", __func__);
ret = ESP_HIDD_NEED_INIT;
break;
case BTC_HD_DISABLING:
BTC_TRACE_ERROR("%s: deinit is in progress!", __func__);
ret = ESP_HIDD_BUSY;
break;
case BTC_HD_CONNECTING:
case BTC_HD_DISCONNECTING:
BTC_TRACE_ERROR("%s: busy now, status:%d, try later!", __func__, btc_hd_cb.status);
ret = ESP_HIDD_BUSY;
break;
default:
break;
}
if (ret != ESP_HIDD_SUCCESS) {
break;
}
if (!is_hidd_app_register()) {
BTC_TRACE_ERROR("%s: application has not been registered, shall register first!", __func__);
ret = ESP_HIDD_NEED_REG;
break;
}
BTA_HdVirtualCableUnplug();
if (btc_hd_cb.status == BTC_HD_CONNECTED) {
btc_hd_cb.status = BTC_HD_DISCONNECTING;
}
} while (0);
if (ret != ESP_HIDD_SUCCESS) {
esp_hidd_cb_param_t param = {0};
param.vc_unplug.status = ret;
param.vc_unplug.conn_status = ESP_HIDD_CONN_STATE_DISCONNECTED;
btc_hd_cb_to_app(ESP_HIDD_VC_UNPLUG_EVT, &param);
}
}
static void btc_hd_call_arg_deep_free(btc_msg_t *msg)
{
btc_hidd_args_t *arg = (btc_hidd_args_t *)msg->arg;
switch (msg->act) {
case BTC_HD_SEND_REPORT_EVT:
utl_freebuf((void **)&arg->send_report.data);
break;
default:
break;
}
}
void btc_hd_call_handler(btc_msg_t *msg)
{
btc_hidd_args_t *arg = (btc_hidd_args_t *)(msg->arg);
switch (msg->act) {
case BTC_HD_INIT_EVT:
btc_hd_init();
break;
case BTC_HD_DEINIT_EVT:
btc_hd_deinit();
break;
case BTC_HD_REGISTER_APP_EVT:
btc_hd_register_app(arg->register_app.app_param, arg->register_app.in_qos, arg->register_app.out_qos);
break;
case BTC_HD_UNREGISTER_APP_EVT:
btc_hd_unregister_app(false);
break;
case BTC_HD_CONNECT_EVT:
btc_hd_connect(arg->connect.bd_addr);
break;
case BTC_HD_DISCONNECT_EVT:
btc_hd_disconnect();
break;
case BTC_HD_SEND_REPORT_EVT:
btc_hd_send_report(arg->send_report.type, arg->send_report.id, arg->send_report.len, arg->send_report.data);
break;
case BTC_HD_REPORT_ERROR_EVT:
btc_hd_report_error(arg->error);
break;
case BTC_HD_UNPLUG_EVT:
btc_hd_virtual_cable_unplug();
break;
default:
BTC_TRACE_WARNING("unknown hidd action %i", msg->act);
break;
}
btc_hd_call_arg_deep_free(msg);
}
void btc_hd_cb_arg_deep_free(btc_msg_t *msg)
{
tBTA_HD *arg = (tBTA_HD *)msg->arg;
switch (msg->act) {
case BTA_HD_SET_REPORT_EVT:
utl_freebuf((void **)&arg->set_report.p_data);
break;
case BTA_HD_INTR_DATA_EVT:
utl_freebuf((void **)&arg->intr_data.p_data);
break;
default:
break;
}
}
void btc_hd_cb_handler(btc_msg_t *msg)
{
uint16_t event = msg->act;
tBTA_HD *p_data = (tBTA_HD *)msg->arg;
esp_hidd_cb_param_t param = {0};
BTC_TRACE_API("%s: event=%s", __func__, dump_hd_event(event));
switch (event) {
case BTA_HD_ENABLE_EVT:
BTC_TRACE_DEBUG("%s: status=%d", __func__, p_data->status);
if (p_data->status == BTA_HD_OK) {
btc_storage_load_hidd();
btc_hd_cb.status = BTC_HD_ENABLED;
} else {
btc_hd_cb.status = BTC_HD_DISABLED;
BTC_TRACE_WARNING("Failed to enable BT-HD, status=%d", p_data->status);
}
param.init.status = p_data->status;
btc_hd_cb_to_app(ESP_HIDD_INIT_EVT, &param);
break;
case BTA_HD_DISABLE_EVT:
BTC_TRACE_DEBUG("%s: status=%d", __func__, p_data->status);
if (p_data->status == BTA_HD_OK){
btc_hd_cb.status = BTC_HD_DISABLED;
if (btc_hd_cb.service_dereg_active) {
btc_hd_cb.service_dereg_active = FALSE;
}
free_app_info_param();
memset(&btc_hd_cb, 0, sizeof(btc_hd_cb));
} else {
BTC_TRACE_WARNING("Failed to disable BT-HD, status=%d", p_data->status);
}
param.deinit.status = p_data->status;
btc_hd_cb_to_app(ESP_HIDD_DEINIT_EVT, &param);
break;
case BTA_HD_REGISTER_APP_EVT:
if (p_data->reg_status.status == BTA_HD_OK) {
btc_hd_cb.app_registered = TRUE;
}
param.register_app.status = p_data->reg_status.status;
param.register_app.in_use = p_data->reg_status.in_use;
if (!p_data->reg_status.in_use) {
memset(param.register_app.bd_addr, 0, BD_ADDR_LEN);
} else {
memcpy(param.register_app.bd_addr, p_data->reg_status.bda, BD_ADDR_LEN);
}
btc_hd_cb_to_app(ESP_HIDD_REGISTER_APP_EVT, &param);
break;
case BTA_HD_UNREGISTER_APP_EVT:
btc_hd_cb.app_registered = FALSE;
param.unregister_app.status = p_data->status;
btc_hd_cb_to_app(ESP_HIDD_UNREGISTER_APP_EVT, &param);
if (btc_hd_cb.status == BTC_HD_DISABLING) {
BTC_TRACE_WARNING("disabling hid device service now");
BTA_HdDisable();
}
break;
case BTA_HD_OPEN_EVT: {
bt_bdaddr_t *addr = (bt_bdaddr_t *)&p_data->conn.bda;
BTC_TRACE_EVENT("BTA_HD_OPEN_EVT, address (%02x:%02x:%02x:%02x:%02x:%02x)", addr->address[0], addr->address[1],
addr->address[2], addr->address[3], addr->address[4], addr->address[5]);
if (p_data->conn.status == BTA_HD_OK && p_data->conn.conn_status == BTA_HD_CONN_STATE_CONNECTED) {
// /* Check if the connection is from hid host and not hid device */
// if (check_cod_hid(addr)) {
// /* Incoming connection from hid device, reject it */
// BTC_TRACE_WARNING("remote device is not hid host, disconnecting");
// btc_hd_cb.forced_disc = TRUE;
// BTA_HdDisconnect();
// break;
// }
// btc_storage_set_hidd((bt_bdaddr_t *)&p_data->conn.bda);
btc_hd_cb.status = BTC_HD_CONNECTED;
}
param.open.status = p_data->conn.status;
param.open.conn_status = p_data->conn.conn_status;
memcpy(param.open.bd_addr, p_data->conn.bda, BD_ADDR_LEN);
btc_hd_cb_to_app(ESP_HIDD_OPEN_EVT, &param);
break;
}
case BTA_HD_CLOSE_EVT:
if (p_data->conn.conn_status == BTA_HD_CONN_STATE_DISCONNECTED) {
btc_hd_cb.status = BTC_HD_DISCONNECTED;
if (btc_hd_cb.forced_disc) {
bt_bdaddr_t *addr = (bt_bdaddr_t *)&p_data->conn.bda;
BTC_TRACE_WARNING("remote device was forcefully disconnected");
btc_hd_remove_device(*addr);
btc_hd_cb.forced_disc = FALSE;
break;
}
}
param.close.status = p_data->conn.status;
param.close.conn_status = p_data->conn.conn_status;
btc_hd_cb_to_app(ESP_HIDD_CLOSE_EVT, &param);
break;
case BTA_HD_GET_REPORT_EVT:
param.get_report.report_type = p_data->get_report.report_type;
param.get_report.report_id = p_data->get_report.report_id;
param.get_report.buffer_size = p_data->get_report.buffer_size;
btc_hd_cb_to_app(ESP_HIDD_GET_REPORT_EVT, &param);
break;
case BTA_HD_SET_REPORT_EVT:
param.set_report.report_type = p_data->set_report.report_type;
param.set_report.report_id = p_data->set_report.report_id;
param.set_report.len = p_data->set_report.len;
param.set_report.data = p_data->set_report.p_data;
btc_hd_cb_to_app(ESP_HIDD_SET_REPORT_EVT, &param);
break;
case BTA_HD_SET_PROTOCOL_EVT:
switch (p_data->set_protocol) {
case HID_PAR_PROTOCOL_BOOT_MODE:
param.set_protocol.protocol_mode = ESP_HIDD_BOOT_MODE;
break;
case HID_PAR_PROTOCOL_REPORT:
param.set_protocol.protocol_mode = ESP_HIDD_REPORT_MODE;
break;
default:
param.set_protocol.protocol_mode = ESP_HIDD_UNSUPPORTED_MODE;
break;
}
btc_hd_cb_to_app(ESP_HIDD_SET_PROTOCOL_EVT, &param);
break;
case BTA_HD_INTR_DATA_EVT:
param.intr_data.report_id = p_data->intr_data.report_id;
param.intr_data.len = p_data->intr_data.len;
param.intr_data.data = p_data->intr_data.p_data;
btc_hd_cb_to_app(ESP_HIDD_INTR_DATA_EVT, &param);
break;
case BTA_HD_VC_UNPLUG_EVT: {
bt_bdaddr_t *bd_addr = (bt_bdaddr_t *)&p_data->conn.bda;
if (bta_dm_check_if_only_hd_connected(p_data->conn.bda)) {
BTC_TRACE_DEBUG("%s: Removing bonding as only HID profile connected", __func__);
BTA_DmRemoveDevice((uint8_t *)&p_data->conn.bda, BT_TRANSPORT_BR_EDR);
} else {
BTC_TRACE_DEBUG("%s: Only removing HID data as some other profiles connected", __func__);
btc_hd_remove_device(*bd_addr);
}
if (btc_hd_cb.status == BTC_HD_DISCONNECTING || btc_hd_cb.status == BTC_HD_CONNECTING ||
btc_hd_cb.status == BTC_HD_CONNECTED) {
btc_hd_cb.status = BTC_HD_DISCONNECTED;
param.close.status = p_data->conn.status;
param.close.conn_status = p_data->conn.conn_status;
btc_hd_cb_to_app(ESP_HIDD_CLOSE_EVT, &param);
}
param.vc_unplug.status = p_data->conn.status;
param.vc_unplug.conn_status = p_data->conn.conn_status;
btc_hd_cb_to_app(ESP_HIDD_VC_UNPLUG_EVT, &param);
break;
}
case BTA_HD_SEND_REPORT_EVT:
param.send_report.status = p_data->send_report.status;
param.send_report.reason = p_data->send_report.reason;
param.send_report.report_type = p_data->send_report.report_type;
param.send_report.report_id = p_data->send_report.report_id;
btc_hd_cb_to_app(ESP_HIDD_SEND_REPORT_EVT, &param);
break;
case BTA_HD_REPORT_ERR_EVT:
param.report_err.status = p_data->report_err.status;
param.report_err.reason = p_data->report_err.reason;
btc_hd_cb_to_app(ESP_HIDD_REPORT_ERR_EVT, &param);
break;
default:
BTC_TRACE_WARNING("%s: unknown event (%d)", __func__, event);
break;
}
btc_hd_cb_arg_deep_free(msg);
}
void btc_hd_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src)
{
btc_hidd_args_t *dst = (btc_hidd_args_t *)p_dest;
btc_hidd_args_t *src = (btc_hidd_args_t *)p_src;
switch (msg->act) {
case BTC_HD_SEND_REPORT_EVT:
dst->send_report.data = (uint8_t *)osi_malloc(src->send_report.len);
if (dst->send_report.data) {
memcpy(dst->send_report.data, src->send_report.data, src->send_report.len);
} else {
BTC_TRACE_ERROR("%s %d osi_malloc failed\n", __func__, msg->act);
}
break;
default:
break;
}
}
#endif // HID_DEV_INCLUDED==TRUE
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,112 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __BT_SDP_H__
#define __BT_SDP_H__
#include <stdint.h>
// #include "bluetooth.h"
#include "common/bt_defs.h"
#include "esp_bt_defs.h"
#define SDP_OPP_SUPPORTED_FORMATS_MAX_LENGTH 15
/**
* These events are handled by the state machine
*/
typedef enum {
SDP_TYPE_RAW, // Used to carry raw SDP search data for unknown UUIDs
SDP_TYPE_MAP_MAS, // Message Access Profile - Server
SDP_TYPE_MAP_MNS, // Message Access Profile - Client (Notification Server)
SDP_TYPE_PBAP_PSE, // Phone Book Profile - Server
SDP_TYPE_PBAP_PCE, // Phone Book Profile - Client
SDP_TYPE_OPP_SERVER, // Object Push Profile
SDP_TYPE_SAP_SERVER // SIM Access Profile
} bluetooth_sdp_types;
typedef struct _bluetooth_sdp_hdr {
bluetooth_sdp_types type;
esp_bt_uuid_t uuid;
uint32_t service_name_length;
char *service_name;
int32_t rfcomm_channel_number;
int32_t l2cap_psm;
int32_t profile_version;
} bluetooth_sdp_hdr;
/**
* Some signals need additional pointers, hence we introduce a
* generic way to handle these pointers.
*/
typedef struct _bluetooth_sdp_hdr_overlay {
bluetooth_sdp_types type;
esp_bt_uuid_t bt_uuid;
uint32_t service_name_length;
char *service_name;
int32_t rfcomm_channel_number;
int32_t l2cap_psm;
int32_t profile_version;
// User pointers, only used for some signals - see bluetooth_sdp_ops_record
int user1_ptr_len;
uint8_t *user1_ptr;
int user2_ptr_len;
uint8_t *user2_ptr;
} bluetooth_sdp_hdr_overlay;
typedef struct _bluetooth_sdp_mas_record {
bluetooth_sdp_hdr_overlay hdr;
uint32_t mas_instance_id;
uint32_t supported_features;
uint32_t supported_message_types;
} bluetooth_sdp_mas_record;
typedef struct _bluetooth_sdp_mns_record {
bluetooth_sdp_hdr_overlay hdr;
uint32_t supported_features;
} bluetooth_sdp_mns_record;
typedef struct _bluetooth_sdp_pse_record {
bluetooth_sdp_hdr_overlay hdr;
uint32_t supported_features;
uint32_t supported_repositories;
} bluetooth_sdp_pse_record;
typedef struct _bluetooth_sdp_pce_record {
bluetooth_sdp_hdr_overlay hdr;
} bluetooth_sdp_pce_record;
typedef struct _bluetooth_sdp_ops_record {
bluetooth_sdp_hdr_overlay hdr;
int supported_formats_list_len;
uint8_t supported_formats_list[SDP_OPP_SUPPORTED_FORMATS_MAX_LENGTH];
} bluetooth_sdp_ops_record;
typedef struct _bluetooth_sdp_sap_record {
bluetooth_sdp_hdr_overlay hdr;
} bluetooth_sdp_sap_record;
typedef union {
bluetooth_sdp_hdr_overlay hdr;
bluetooth_sdp_mas_record mas;
bluetooth_sdp_mns_record mns;
bluetooth_sdp_pse_record pse;
bluetooth_sdp_pce_record pce;
bluetooth_sdp_ops_record ops;
bluetooth_sdp_sap_record sap;
} bluetooth_sdp_record;
#endif /* __BT_SDP_H__ */
@@ -0,0 +1,100 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/*******************************************************************************
*
* Filename: btc_a2dp.h
*
* Description: Common definitions for A2DP
*
*******************************************************************************/
#ifndef __BTC_A2DP_H__
#define __BTC_A2DP_H__
#include <stdbool.h>
#include "common/bt_target.h"
#include "bta/bta_api.h"
#include "btc_av_api.h"
#include "esp_a2dp_api.h"
#if BTC_AV_INCLUDED
/*******************************************************************************
** Constants
*******************************************************************************/
#define BTC_AV_SUCCESS (0)
/**
* AV (Audio Video source) Errors
*/
#define BTC_ERROR_SRV_AV_NOT_ENABLED 700 /* AV is not enabled */
#define BTC_ERROR_SRV_AV_FEEDING_NOT_SUPPORTED 701 /* Requested Feeding not supported */
#define BTC_ERROR_SRV_AV_BUSY 702 /* Another operation ongoing */
#define BTC_ERROR_SRV_AV_NOT_OPENED 703 /* No AV link opened */
#define BTC_ERROR_SRV_AV_NOT_STARTED 704 /* AV is not started */
#define BTC_ERROR_SRV_AV_CP_NOT_SUPPORTED 705 /* Content protection is not supported by all headsets */
/* Transcoding definition for TxTranscoding and RxTranscoding */
#define BTC_MEDIA_TRSCD_OFF 0
#define BTC_MEDIA_TRSCD_PCM_2_SBC 1 /* Tx */
/*******************************************************************************
** Data types
*******************************************************************************/
typedef int tBTC_AV_STATUS;
/*******************************************************************************
** Public functions
*******************************************************************************/
void btc_a2dp_on_init(void);
/*******************************************************************************
**
** Function btc_a2dp_on_idle
**
** Description Process 'idle' request from BTC AV state machine during
** initialization
**
*******************************************************************************/
void btc_a2dp_on_idle(void);
/*******************************************************************************
**
** Function btc_a2dp_on_started
**
** Description Process 'start' request from BTC AV state machine to prepare
** for A2DP streaming
**
** Return TRUE if an ACK for the local command is sent
**
*******************************************************************************/
BOOLEAN btc_a2dp_on_started(tBTA_AV_START *p_av, BOOLEAN pending_start);
/*******************************************************************************
**
** Function btc_a2dp_on_stopped
**
** Description Process 'stop' request from BTC AV state machine to stop
** A2DP streaming
**
*******************************************************************************/
void btc_a2dp_on_stopped(tBTA_AV_SUSPEND *p_av);
/*******************************************************************************
**
** Function btc_a2dp_on_suspended
**
** Description Process 'stop' request from BTC AV state machine to suspend
** A2DP streaming
**
*******************************************************************************/
void btc_a2dp_on_suspended(tBTA_AV_SUSPEND *p_av);
#endif /* #if BTC_AV_INCLUDED */
#endif /* __BTC_A2DP_H__ */
@@ -0,0 +1,102 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/*******************************************************************************
*
* Filename: btc_a2dp_control.h
*
*******************************************************************************/
#ifndef __BTC_A2DP_CONTROL_H__
#define __BTC_A2DP_CONTROL_H__
#include <stdbool.h>
#include "common/bt_target.h"
#include "bta/bta_api.h"
#include "btc_av_api.h"
#include "esp_a2dp_api.h"
#if BTC_AV_INCLUDED
/*******************************************************************************
** Public functions
*******************************************************************************/
/*******************************************************************************
**
** Function btc_a2dp_control_media_ctrl
**
** Description Handle the media_ctrl command
**
*******************************************************************************/
void btc_a2dp_control_media_ctrl(esp_a2d_media_ctrl_t ctrl);
/*******************************************************************************
**
** Function btc_a2dp_control_datapath_ctrl
**
** Description Handle the media datapath event, which is adapted from UIPC
** data channel from bluedroid
**
*******************************************************************************/
void btc_a2dp_control_datapath_ctrl(uint32_t dp_evt);
/*******************************************************************************
**
** Function btc_a2dp_control_command_ack
**
** Description Acknowledge the pending media_ctrl command
**
*******************************************************************************/
void btc_a2dp_control_command_ack(int status);
/*******************************************************************************
**
** Function btc_a2dp_control_get_datachnl_stat
**
** Description Check whether the data channel state is open
**
** Return TRUE if the data channel state is open
**
*******************************************************************************/
BOOLEAN btc_a2dp_control_get_datachnl_stat(void);
/*******************************************************************************
**
** Function btc_a2dp_control_set_datachnl_stat
**
** Description Set the data channel state flag
**
*******************************************************************************/
void btc_a2dp_control_set_datachnl_stat(BOOLEAN open);
/*******************************************************************************
**
** Function btc_a2dp_control_init
**
** Description Initialize the A2DP control module. It should be called during
** the startup stage of A2DP streaming.
**
*******************************************************************************/
bool btc_a2dp_control_init(void);
/*******************************************************************************
**
** Function btc_a2dp_control_cleanup
**
** Description Cleanup the A2DP control module
**
*******************************************************************************/
void btc_a2dp_control_cleanup(void);
#endif /* #if BTC_AV_INCLUDED */
#endif /* __BTC_A2DP_CONTROL_H__ */
@@ -0,0 +1,131 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/*******************************************************************************
*
* Filename: btc_a2dp_sink.h
*
*******************************************************************************/
#ifndef __BTC_A2DP_SINK_H__
#define __BTC_A2DP_SINK_H__
#include <stdbool.h>
#include "common/bt_target.h"
#include "bta/bta_api.h"
#include "btc_av_api.h"
#include "esp_a2dp_api.h"
#if BTC_AV_SINK_INCLUDED
/*******************************************************************************
** Data types
*******************************************************************************/
typedef struct {
BT_HDR hdr;
UINT8 codec_info[AVDT_CODEC_SIZE];
} tBTC_MEDIA_SINK_CFG_UPDATE;
/*******************************************************************************
** Public functions
*******************************************************************************/
/*******************************************************************************
**
** Function btc_a2dp_sink_startup
**
** Description Initialize and startup the A2DP sink module. This function
** should be called by the BTC AV state machine prior to using
** the module.
**
** Returns true if success
**
*******************************************************************************/
bool btc_a2dp_sink_startup(void);
/*******************************************************************************
**
** Function btc_a2dp_sink_shutdown
**
** Description Shutdown and cleanup the A2DP sink module
**
*******************************************************************************/
void btc_a2dp_sink_shutdown(void);
/*******************************************************************************
**
** Function btc_a2dp_sink_rx_flush_req
**
** Description Request to flush audio decoding pipe
**
** Returns TRUE if success
**
*******************************************************************************/
BOOLEAN btc_a2dp_sink_rx_flush_req(void);
/*******************************************************************************
**
** Function btc_a2dp_sink_enque_buf
**
** Description Enqueue a Advance Audio media buffer to be processed by btc media task.
**
** Returns size of the queue
**
*******************************************************************************/
UINT8 btc_a2dp_sink_enque_buf(BT_HDR *p_buf);
/*******************************************************************************
**
** Function btc_a2dp_sink_on_idle
**
** Description Process 'idle' request from the BTC AV state machine during
** initialization
**
*******************************************************************************/
void btc_a2dp_sink_on_idle(void);
/*******************************************************************************
**
** Function btc_a2dp_sink_on_stopped
**
** Description Process 'stop' request from the BTC AV state machine to stop
** A2DP streaming
**
*******************************************************************************/
void btc_a2dp_sink_on_stopped(tBTA_AV_SUSPEND *p_av);
/*******************************************************************************
**
** Function btc_a2dp_sink_on_suspended
**
** Description Process 'suspend' request from the BTC AV state machine to
** suspend A2DP streaming
**
*******************************************************************************/
void btc_a2dp_sink_on_suspended(tBTA_AV_SUSPEND *p_av);
/*******************************************************************************
**
** Function btc_a2dp_sink_set_rx_flush
**
** Description enable/disabel discarding of received A2DP frames
**
*******************************************************************************/
void btc_a2dp_sink_set_rx_flush(BOOLEAN enable);
/*******************************************************************************
**
** Function btc_a2dp_sink_reset_decoder
**
** Description Reset decoder parameters according to configuration from remote
** device
**
*******************************************************************************/
void btc_a2dp_sink_reset_decoder(UINT8 *p_av);
#endif /* #if BTC_AV_SINK_INCLUDED */
#endif /* __BTC_A2DP_SINK_H__ */
@@ -0,0 +1,245 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/*******************************************************************************
*
* Filename: btc_a2dp_source.h
*
*******************************************************************************/
#ifndef __BTC_A2DP_SOURCE_H__
#define __BTC_A2DP_SOURCE_H__
#include <stdbool.h>
#include "common/bt_target.h"
#include "bta/bta_api.h"
#include "btc_av_api.h"
#include "esp_a2dp_api.h"
#if BTC_AV_SRC_INCLUDED
/*******************************************************************************
** Data types
*******************************************************************************/
/* tBTC_MEDIA_INIT_AUDIO msg structure */
typedef struct {
BT_HDR hdr;
UINT16 SamplingFreq; /* 16k, 32k, 44.1k or 48k*/
UINT8 ChannelMode; /* mono, dual, stereo or joint stereo*/
UINT8 NumOfSubBands; /* 4 or 8 */
UINT8 NumOfBlocks; /* 4, 8, 12 or 16*/
UINT8 AllocationMethod; /* loudness or SNR*/
UINT16 MtuSize; /* peer mtu size */
} tBTC_MEDIA_INIT_AUDIO;
/* tBTC_MEDIA_UPDATE_AUDIO msg structure */
typedef struct {
BT_HDR hdr;
UINT16 MinMtuSize; /* Minimum peer mtu size */
UINT8 MaxBitPool; /* Maximum peer bitpool */
UINT8 MinBitPool; /* Minimum peer bitpool */
} tBTC_MEDIA_UPDATE_AUDIO;
/* tBTC_MEDIA_INIT_AUDIO_FEEDING msg structure */
typedef struct {
BT_HDR hdr;
tBTC_AV_FEEDING_MODE feeding_mode;
tBTC_AV_MEDIA_FEEDINGS feeding;
} tBTC_MEDIA_INIT_AUDIO_FEEDING;
/*******************************************************************************
** Public functions
*******************************************************************************/
/*******************************************************************************
**
** Function btc_a2dp_source_startup
**
** Description Initialize and startup the A2DP source module. This function
** should be called by the BTC AV state machine prior to using
** the module
**
** Returns TRUE is success
**
*******************************************************************************/
bool btc_a2dp_source_startup(void);
/*******************************************************************************
**
** Function btc_a2dp_source_shutdown
**
** Description Shutdown and cleanup the A2DP source module.
**
*******************************************************************************/
void btc_a2dp_source_shutdown(void);
/*******************************************************************************
**
** Function btc_a2dp_source_enc_init_req
**
** Description Request to initialize the media task encoder
**
** Returns TRUE is success
**
*******************************************************************************/
BOOLEAN btc_a2dp_source_enc_init_req(tBTC_MEDIA_INIT_AUDIO *p_msg);
/*******************************************************************************
**
** Function btc_a2dp_source_enc_udpate_req
**
** Description Request to update the media task encoder
**
** Returns TRUE is success
**
*******************************************************************************/
BOOLEAN btc_a2dp_source_enc_update_req(tBTC_MEDIA_UPDATE_AUDIO *p_msg);
/*******************************************************************************
**
** Function btc_a2dp_source_start_audio_req
**
** Description Request to start audio encoding task
**
** Returns TRUE is success
**
*******************************************************************************/
BOOLEAN btc_a2dp_source_start_audio_req(void);
/*******************************************************************************
**
** Function btc_a2dp_source_stop_audio_req
**
** Description Request to stop audio encoding task
**
** Returns TRUE is success
**
*******************************************************************************/
BOOLEAN btc_a2dp_source_stop_audio_req(void);
/*******************************************************************************
**
** Function btc_a2dp_source_tx_flush_req
**
** Description Request to flush audio encoding pipe
**
** Returns TRUE is success
**
*******************************************************************************/
BOOLEAN btc_a2dp_source_tx_flush_req(void);
/*******************************************************************************
**
** Function btc_a2dp_source_audio_readbuf
**
** Description Read an audio buffer from the BTC media TX queue
**
** Returns pointer on a aa buffer ready to send
**
*******************************************************************************/
BT_HDR *btc_a2dp_source_audio_readbuf(void);
/*******************************************************************************
**
** Function btc_a2dp_source_audio_feeding_init_req
**
** Description Request to initialize audio feeding
**
** Returns TRUE if success
**
*******************************************************************************/
BOOLEAN btc_a2dp_source_audio_feeding_init_req(tBTC_MEDIA_INIT_AUDIO_FEEDING *p_msg);
/*******************************************************************************
**
** Function btc_a2dp_source_is_streaming
**
** Description Check whether A2DP source is in streaming state
**
*******************************************************************************/
bool btc_a2dp_source_is_streaming(void);
/*******************************************************************************
**
** Function btc_a2dp_source_is_task_shutting_down
**
** Description Check whether A2DP source media task is shutting down
**
*******************************************************************************/
bool btc_a2dp_source_is_task_shutting_down(void);
/*******************************************************************************
**
** Function btc_a2dp_source_on_idle
**
** Description Request 'idle' request from BTC AV state machine during
** initialization
**
*******************************************************************************/
void btc_a2dp_source_on_idle(void);
/*******************************************************************************
**
** Function btc_a2dp_source_on_stopped
**
** Description Process 'stop' request from the BTC AV state machine to stop
** A2DP streaming
**
*******************************************************************************/
void btc_a2dp_source_on_stopped(tBTA_AV_SUSPEND *p_av);
/*******************************************************************************
**
** Function btc_a2dp_source_on_suspended
**
** Description Process 'suspend' request from the BTC AV state machine to stop
** A2DP streaming
**
*******************************************************************************/
void btc_a2dp_source_on_suspended(tBTA_AV_SUSPEND *p_av);
/*******************************************************************************
**
** Function btc_a2dp_source_setup_codec
**
** Description initialize the encoder parameters
**
*******************************************************************************/
void btc_a2dp_source_setup_codec(void);
/*******************************************************************************
**
** Function btc_a2dp_source_set_tx_flush
**
** Description enable/disable discarding of transmitted frames
**
*******************************************************************************/
void btc_a2dp_source_set_tx_flush(BOOLEAN enable);
/*******************************************************************************
**
** Function btc_a2dp_source_encoder_update
**
** Description update changed SBC encoder parameters
**
*******************************************************************************/
void btc_a2dp_source_encoder_update(void);
/*****************************************************************************
**
** Function btc_source_report_delay_value
**
** Description Report sink delay report value
**
*******************************************************************************/
void btc_source_report_delay_value(UINT16 delay_value);
#endif /* #if BTC_AV_SRC_INCLUDED */
#endif /* __BTC_A2DP_SOURCE_H__ */
@@ -0,0 +1,228 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/*******************************************************************************
*
* Filename: btc_av.h
*
* Description: Main API header file for all BTC AV functions accessed
* from internal stack.
*
*******************************************************************************/
#ifndef __BTC_AV_H__
#define __BTC_AV_H__
#include "common/bt_target.h"
#include "esp_a2dp_api.h"
#include "btc/btc_task.h"
#include "btc/btc_common.h"
#include "btc/btc_sm.h"
#include "bta/bta_av_api.h"
#if (BTC_AV_INCLUDED == TRUE)
// global variable to inidcate avrc is initialized with a2dp
extern bool g_av_with_rc;
// global variable to indicate a2dp is initialized
extern bool g_a2dp_on_init;
// global variable to indicate a2dp is deinitialized
extern bool g_a2dp_on_deinit;
// global variable to indicate a2dp source deinitialization is ongoing
extern bool g_a2dp_source_ongoing_deinit;
// global variable to indicate a2dp sink deinitialization is ongoing
extern bool g_a2dp_sink_ongoing_deinit;
/*******************************************************************************
** Type definitions for callback functions
********************************************************************************/
enum {
BTC_AV_DATAPATH_OPEN_EVT, // original UIPC_OPEN_EVT for data channel in bluedroid
BTC_AV_DATAPATH_MAX_EVT,
};
typedef enum {
BTC_AV_CONNECT_REQ_EVT = BTA_AV_MAX_EVT,
BTC_AV_DISCONNECT_REQ_EVT,
BTC_AV_START_STREAM_REQ_EVT,
BTC_AV_SUSPEND_STREAM_REQ_EVT,
BTC_AV_SINK_CONFIG_REQ_EVT,
} btc_av_sm_event_t;
typedef enum {
#if BTC_AV_SINK_INCLUDED
BTC_AV_SINK_API_INIT_EVT = 0,
BTC_AV_SINK_API_DEINIT_EVT,
BTC_AV_SINK_API_CONNECT_EVT,
BTC_AV_SINK_API_DISCONNECT_EVT,
BTC_AV_SINK_API_REG_DATA_CB_EVT,
BTC_AV_SINK_API_SET_DELAY_VALUE_EVT,
BTC_AV_SINK_API_GET_DELAY_VALUE_EVT,
#endif /* BTC_AV_SINK_INCLUDED */
#if BTC_AV_SRC_INCLUDED
BTC_AV_SRC_API_INIT_EVT,
BTC_AV_SRC_API_DEINIT_EVT,
BTC_AV_SRC_API_CONNECT_EVT,
BTC_AV_SRC_API_DISCONNECT_EVT,
BTC_AV_SRC_API_REG_DATA_CB_EVT,
#endif /* BTC_AV_SRC_INCLUDED */
BTC_AV_API_MEDIA_CTRL_EVT,
} btc_av_act_t;
/* btc_av_args_t */
typedef union {
#if BTC_AV_SINK_INCLUDED
// BTC_AV_SINK_CONFIG_REQ_EVT -- internal event
esp_a2d_mcc_t mcc;
// BTC_AV_SINK_API_CONNECT_EVT
bt_bdaddr_t connect;
// BTC_AV_SINK_API_DISCONNECT_EVT
bt_bdaddr_t disconn;
// BTC_AV_SINK_API_REG_DATA_CB_EVT
esp_a2d_sink_data_cb_t data_cb;
// BTC_AV_SINK_API_SET_DELAY_VALUE_EVT
uint16_t delay_value;
#endif /* BTC_AV_SINK_INCLUDED */
#if BTC_AV_SRC_INCLUDED
// BTC_AV_SRC_API_REG_DATA_CB_EVT
esp_a2d_source_data_cb_t src_data_cb;
// BTC_AV_SRC_API_CONNECT
bt_bdaddr_t src_connect;
// BTC_AV_SRC_API_DISCONNECT_EVT
bt_bdaddr_t src_disconn;
#endif /* BTC_AV_SRC_INCLUDED */
// BTC_AV_API_MEDIA_CTRL_EVT
esp_a2d_media_ctrl_t ctrl;
} btc_av_args_t;
/*******************************************************************************
** BTC AV API
********************************************************************************/
void btc_a2dp_call_handler(btc_msg_t *msg);
void btc_a2dp_cb_handler(btc_msg_t *msg);
void btc_a2dp_sink_reg_data_cb(esp_a2d_sink_data_cb_t callback);
void btc_a2dp_src_reg_data_cb(esp_a2d_source_data_cb_t callback);
/*******************************************************************************
**
** Function btc_av_get_sm_handle
**
** Description Fetches current av SM handle
**
** Returns None
**
*******************************************************************************/
btc_sm_handle_t btc_av_get_sm_handle(void);
/*******************************************************************************
**
** Function btc_av_stream_ready
**
** Description Checks whether AV is ready for starting a stream
**
** Returns None
**
*******************************************************************************/
BOOLEAN btc_av_stream_ready(void);
/*******************************************************************************
**
** Function btc_av_stream_started_ready
**
** Description Checks whether AV ready for media start in streaming state
**
** Returns None
**
*******************************************************************************/
BOOLEAN btc_av_stream_started_ready(void);
/*******************************************************************************
**
** Function btc_dispatch_sm_event
**
** Description Send event to AV statemachine
**
** Returns None
**
*******************************************************************************/
/* used to pass events to AV statemachine from other tasks */
void btc_dispatch_sm_event(btc_av_sm_event_t event, void *p_data, int len);
/*******************************************************************************
**
** Function btc_av_is_connected
**
** Description Checks if av has a connected sink
**
** Returns BOOLEAN
**
*******************************************************************************/
BOOLEAN btc_av_is_connected(void);
/*******************************************************************************
*
* Function btc_av_get_peer_sep
*
* Description Get the stream endpoint type.
*
* Returns The stream endpoint type: either AVDT_TSEP_SRC or
* AVDT_TSEP_SNK.
*
******************************************************************************/
uint8_t btc_av_get_peer_sep(void);
/*******************************************************************************
**
** Function btc_av_is_peer_edr
**
** Description Check if the connected a2dp device supports
** EDR or not. Only when connected this function
** will accurately provide a true capability of
** remote peer. If not connected it will always be false.
**
** Returns TRUE if remote device is capable of EDR
**
*******************************************************************************/
BOOLEAN btc_av_is_peer_edr(void);
/******************************************************************************
**
** Function btc_av_clear_remote_suspend_flag
**
** Description Clears remote suspended flag
**
** Returns Void
********************************************************************************/
void btc_av_clear_remote_suspend_flag(void);
/*******************************************************************************
*
* Function btc_av_get_service_id
*
* Description Get the current AV service ID.
*
* Returns The stream endpoint type: either BTA_A2DP_SOURCE_SERVICE_ID or
* BTA_A2DP_SINK_SERVICE_ID.
*
******************************************************************************/
uint8_t btc_av_get_service_id(void);
#endif ///BTC_AV_INCLUDED == TRUE
#endif /* __BTC_AV_H__ */
@@ -0,0 +1,193 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/*****************************************************************************
**
** Name: btc_av_api.h
**
** Description: This is the public interface file for the advanced
** audio/video streaming (AV) subsystem of BTC.
**
*****************************************************************************/
#ifndef __BTC_AV_API_H__
#define __BTC_AV_API_H__
#include "common/bt_target.h"
#include "bta/bta_av_api.h"
#include "stack/a2d_api.h"
#include "stack/a2d_sbc.h"
#if (BTC_AV_INCLUDED == TRUE)
/*****************************************************************************
** Constants and data types
*****************************************************************************/
/* Codec type */
#define BTC_AV_CODEC_NONE 0xFF
#define BTC_AV_CODEC_SBC A2D_MEDIA_CT_SBC /* SBC media codec type */
#define BTC_AV_CODEC_PCM 0x5 /* Raw PCM */
typedef UINT8 tBTC_AV_CODEC_ID;
/* AV features masks */
#define BTC_AV_FEAT_RCTG BTA_AV_FEAT_RCTG /* remote control target */
#define BTC_AV_FEAT_RCCT BTA_AV_FEAT_RCCT /* remote control controller */
#define BTC_AV_FEAT_METADATA BTA_AV_FEAT_METADATA /* remote control Metadata Transfer command/response */
typedef UINT16 tBTC_AV_FEAT;
/* AV channel values */
#define BTC_AV_CHNL_MSK BTA_AV_CHNL_MSK
#define BTC_AV_CHNL_AUDIO BTA_AV_CHNL_AUDIO /* audio channel */
#define BTC_AV_CHNL_VIDEO BTA_AV_CHNL_VIDEO /* video channel */
typedef UINT8 tBTC_AV_CHNL;
typedef UINT8 tBTC_AV_HNDL;
/* Operation id list for BTC_AvRemoteCmd */
#define BTC_AV_ID_SELECT 0x00 /* select */
#define BTC_AV_ID_UP 0x01 /* up */
#define BTC_AV_ID_DOWN 0x02 /* down */
#define BTC_AV_ID_LEFT 0x03 /* left */
#define BTC_AV_ID_RIGHT 0x04 /* right */
#define BTC_AV_ID_RIGHT_UP 0x05 /* right-up */
#define BTC_AV_ID_RIGHT_DOWN 0x06 /* right-down */
#define BTC_AV_ID_LEFT_UP 0x07 /* left-up */
#define BTC_AV_ID_LEFT_DOWN 0x08 /* left-down */
#define BTC_AV_ID_ROOT_MENU 0x09 /* root menu */
#define BTC_AV_ID_SETUP_MENU 0x0A /* setup menu */
#define BTC_AV_ID_CONT_MENU 0x0B /* contents menu */
#define BTC_AV_ID_FAV_MENU 0x0C /* favorite menu */
#define BTC_AV_ID_EXIT 0x0D /* exit */
#define BTC_AV_ID_0 0x20 /* 0 */
#define BTC_AV_ID_1 0x21 /* 1 */
#define BTC_AV_ID_2 0x22 /* 2 */
#define BTC_AV_ID_3 0x23 /* 3 */
#define BTC_AV_ID_4 0x24 /* 4 */
#define BTC_AV_ID_5 0x25 /* 5 */
#define BTC_AV_ID_6 0x26 /* 6 */
#define BTC_AV_ID_7 0x27 /* 7 */
#define BTC_AV_ID_8 0x28 /* 8 */
#define BTC_AV_ID_9 0x29 /* 9 */
#define BTC_AV_ID_DOT 0x2A /* dot */
#define BTC_AV_ID_ENTER 0x2B /* enter */
#define BTC_AV_ID_CLEAR 0x2C /* clear */
#define BTC_AV_ID_CHAN_UP 0x30 /* channel up */
#define BTC_AV_ID_CHAN_DOWN 0x31 /* channel down */
#define BTC_AV_ID_PREV_CHAN 0x32 /* previous channel */
#define BTC_AV_ID_SOUND_SEL 0x33 /* sound select */
#define BTC_AV_ID_INPUT_SEL 0x34 /* input select */
#define BTC_AV_ID_DISP_INFO 0x35 /* display information */
#define BTC_AV_ID_HELP 0x36 /* help */
#define BTC_AV_ID_PAGE_UP 0x37 /* page up */
#define BTC_AV_ID_PAGE_DOWN 0x38 /* page down */
#define BTC_AV_ID_POWER 0x40 /* power */
#define BTC_AV_ID_VOL_UP 0x41 /* volume up */
#define BTC_AV_ID_VOL_DOWN 0x42 /* volume down */
#define BTC_AV_ID_MUTE 0x43 /* mute */
#define BTC_AV_ID_PLAY 0x44 /* play */
#define BTC_AV_ID_STOP 0x45 /* stop */
#define BTC_AV_ID_PAUSE 0x46 /* pause */
#define BTC_AV_ID_RECORD 0x47 /* record */
#define BTC_AV_ID_REWIND 0x48 /* rewind */
#define BTC_AV_ID_FAST_FOR 0x49 /* fast forward */
#define BTC_AV_ID_EJECT 0x4A /* eject */
#define BTC_AV_ID_FORWARD 0x4B /* forward */
#define BTC_AV_ID_BACKWARD 0x4C /* backward */
#define BTC_AV_ID_ANGLE 0x50 /* angle */
#define BTC_AV_ID_SUBPICT 0x51 /* subpicture */
#define BTC_AV_ID_F1 0x71 /* F1 */
#define BTC_AV_ID_F2 0x72 /* F2 */
#define BTC_AV_ID_F3 0x73 /* F3 */
#define BTC_AV_ID_F4 0x74 /* F4 */
#define BTC_AV_ID_F5 0x75 /* F5 */
#define BTC_AV_ID_VENDOR 0x7E /* vendor unique */
#define BTC_AV_KEYPRESSED_RELEASE 0x80
typedef UINT8 tBTC_AV_RC;
/* State flag for pass through command */
#define BTC_AV_STATE_PRESS 0 /* key pressed */
#define BTC_AV_STATE_RELEASE 1 /* key released */
typedef UINT8 tBTC_AV_STATE;
typedef UINT8 tBTC_AV_RC_HNDL;
/* Command codes for BTC_AvVendorCmd */
#define BTC_AV_CMD_CTRL 0
#define BTC_AV_CMD_STATUS 1
#define BTC_AV_CMD_SPEC_INQ 2
#define BTC_AV_CMD_NOTIF 3
#define BTC_AV_CMD_GEN_INQ 4
typedef UINT8 tBTC_AV_CMD;
/* AV callback events */
#define BTC_AV_OPEN_EVT 0 /* connection opened */
#define BTC_AV_CLOSE_EVT 1 /* connection closed */
#define BTC_AV_START_EVT 2 /* stream data transfer started */
#define BTC_AV_STOP_EVT 3 /* stream data transfer stopped */
#define BTC_AV_RC_OPEN_EVT 4 /* remote control channel open */
#define BTC_AV_RC_CLOSE_EVT 5 /* remote control channel closed */
#define BTC_AV_REMOTE_CMD_EVT 6 /* remote control command */
#define BTC_AV_REMOTE_RSP_EVT 7 /* remote control response */
#define BTC_AV_META_MSG_EVT 8 /* metadata messages */
typedef UINT8 tBTC_AV_EVT;
#define BTC_AV_FEEDING_ASYNCHRONOUS 0 /* asynchronous feeding, use tx av timer */
#define BTC_AV_FEEDING_SYNCHRONOUS 1 /* synchronous feeding, no av tx timer */
#define BTC_AV_MAX_SYNCHRONOUS_LATENCY 80 /* max latency in ms for BTC_AV_FEEDING_SYNCHRONOUS */
#define BTC_AV_MIN_SYNCHRONOUS_LATENCY 4 /* min latency in ms for BTC_AV_FEEDING_SYNCHRONOUS */
typedef UINT8 tBTC_AV_FEEDING_MODE;
#define BTC_AV_CHANNEL_MODE_MONO A2D_SBC_IE_CH_MD_MONO
#define BTC_AV_CHANNEL_MODE_STEREO A2D_SBC_IE_CH_MD_STEREO
#define BTC_AV_CHANNEL_MODE_JOINT A2D_SBC_IE_CH_MD_JOINT
#define BTC_AV_CHANNEL_MODE_DUAL A2D_SBC_IE_CH_MD_DUAL
typedef UINT8 tBTC_AV_CHANNEL_MODE;
/**
* Structure used to configure the AV codec capabilities/config
*/
typedef struct {
tBTC_AV_CODEC_ID id; /* Codec ID (in terms of BTC) */
UINT8 info[AVDT_CODEC_SIZE]; /* Codec info (can be config or capabilities) */
} tBTC_AV_CODEC_INFO;
/**
* Structure used to configure the AV media feeding
*/
typedef struct {
UINT16 sampling_freq; /* 44100, 48000 etc */
UINT16 num_channel; /* 1 for mono or 2 stereo */
UINT8 bit_per_sample; /* Number of bits per sample (8, 16) */
} tBTC_AV_MEDIA_FEED_CFG_PCM;
typedef union {
tBTC_AV_MEDIA_FEED_CFG_PCM pcm; /* Raw PCM feeding format */
} tBTC_AV_MEDIA_FEED_CFG;
typedef struct {
tBTC_AV_CODEC_ID format; /* Media codec identifier */
tBTC_AV_MEDIA_FEED_CFG cfg; /* Media codec configuration */
} tBTC_AV_MEDIA_FEEDINGS;
#ifdef __cplusplus
}
#endif
#endif ///BTC_AV_INCLUDED == TRUE
#endif /* __BTC_AV_API_H__ */
@@ -0,0 +1,185 @@
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __BTC_AVRC_H__
#define __BTC_AVRC_H__
#include <stdint.h>
#include <stdbool.h>
#include "common/bt_defs.h"
#include "stack/bt_types.h"
#include "bta/bta_av_api.h"
#include "btc/btc_task.h"
#include "esp_avrc_api.h"
#if (BTC_AV_INCLUDED == TRUE)
#ifndef BTC_AVRC_TGT_INCLUDED
#define BTC_AVRC_TGT_INCLUDED FALSE
#endif
typedef enum {
BTC_AVRC_CT_API_INIT_EVT = 0,
BTC_AVRC_CT_API_DEINIT_EVT,
BTC_AVRC_CTRL_API_SND_PTCMD_EVT,
BTC_AVRC_STATUS_API_SND_META_EVT,
BTC_AVRC_STATUS_API_SND_PLAY_STATUS_EVT,
BTC_AVRC_STATUS_API_SND_GET_RN_CAPS_EVT,
BTC_AVRC_NOTIFY_API_SND_REG_NOTIFY_EVT,
BTC_AVRC_CTRL_API_SND_SET_PLAYER_SETTING_EVT,
BTC_AVRC_CTRL_API_SND_SET_ABSOLUTE_VOLUME_EVT
} btc_avrc_act_t;
typedef struct {
uint8_t tl; /* transaction label */
uint8_t key_code;
uint8_t key_state;
} pt_cmd_t;
typedef struct {
uint8_t tl;
uint8_t attr_mask;
} md_cmd_t;
typedef struct {
uint8_t tl;
uint8_t event_id;
uint32_t event_parameter;
} rn_cmd_t;
typedef struct {
uint8_t tl;
uint8_t attr_id;
uint8_t value_id;
} ps_cmd_t;
typedef struct {
uint8_t tl;
} get_caps_cmd_t;
#define BTC_AVRC_MIN_VOLUME 0x00
#define BTC_AVRC_MAX_VOLUME 0x7f
typedef struct {
uint8_t tl;
uint8_t volume;
} set_abs_vol_cmd_t;
/* btc_avrc_args_t */
typedef union {
pt_cmd_t pt_cmd;
md_cmd_t md_cmd;
rn_cmd_t rn_cmd;
ps_cmd_t ps_cmd;
get_caps_cmd_t get_caps_cmd;
set_abs_vol_cmd_t set_abs_vol_cmd;
} btc_avrc_args_t;
/* btc_avrc_tg_act_t */
typedef enum {
BTC_AVRC_TG_API_INIT_EVT = 0,
BTC_AVRC_TG_API_DEINIT_EVT,
BTC_AVRC_TG_API_SET_RN_SUPPORTED_EVT,
BTC_AVRC_TG_API_SET_PSTH_SUPPORTED_CMD_EVT,
BTC_AVRC_TG_API_SEND_RN_RSP_EVT,
} btc_avrc_tg_act_t;
/*****************************************************************************
** Constants & Macros
******************************************************************************/
/* for AVRC 1.4 need to change this */
#define BTC_RC_CT_INIT_MAGIC 0x20181128
#define BTC_RC_TG_INIT_MAGIC 0x20181129
#define MAX_RC_NOTIFICATIONS (13) // refer to ESP_AVRC_RN_MAX_EVT
#define CHECK_ESP_RC_CONNECTED do { \
BTC_TRACE_DEBUG("## %s ##", __FUNCTION__); \
if (btc_rc_cb.rc_connected == FALSE) { \
BTC_TRACE_WARNING("Function %s() called when RC is not connected", __FUNCTION__); \
return ESP_ERR_INVALID_STATE; \
} \
} while (0)
/*****************************************************************************
** Local type definitions
******************************************************************************/
typedef struct {
BOOLEAN registered;
UINT8 label;
} btc_rc_reg_ntf_t;
typedef struct {
BOOLEAN rc_connected;
UINT8 rc_handle;
tBTA_AV_FEAT rc_features;
UINT16 rc_ct_features;
UINT16 rc_tg_features;
BD_ADDR rc_addr;
btc_rc_reg_ntf_t rc_ntf[MAX_RC_NOTIFICATIONS];
} btc_rc_cb_t;
/*****************************************************************************
** Static variables
******************************************************************************/
#if AVRC_DYNAMIC_MEMORY == TRUE
extern btc_rc_cb_t *btc_rc_cb_ptr;
#define btc_rc_cb (*btc_rc_cb_ptr)
#endif ///AVRC_DYNAMIC_MEMORY == FALSE
typedef struct {
esp_avrc_rn_event_ids_t event_id;
esp_avrc_rn_rsp_t rsp;
esp_avrc_rn_param_t param;
} rn_rsp_t;
/* btc_avrc_tg_args_t */
typedef union {
rn_rsp_t rn_rsp; /* BTC_AVRC_TG_API_SEND_RN_RSP_EVT */
uint16_t set_rn_evt; /* BTC_AVRC_TG_API_SET_RN_SUPPORTED_EVT */
uint16_t *set_psth_cmd; /* BTC_AVRC_TG_API_SET_PSTH_SUPPORTED_CMD_EVT */
} btc_avrc_tg_args_t;
void btc_rc_handler(tBTA_AV_EVT event, tBTA_AV *p_data);
BOOLEAN btc_rc_get_connected_peer(BD_ADDR peer_addr);
/*******************************************************************************
** BTC AVRC API
********************************************************************************/
void btc_avrc_ct_call_handler(btc_msg_t *msg);
void btc_avrc_tg_call_handler(btc_msg_t *msg);
void btc_avrc_tg_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src);
void btc_avrc_tg_arg_deep_free(btc_msg_t *msg);
bool btc_avrc_tg_init_p(void);
bool btc_avrc_ct_init_p(void);
bool btc_avrc_tg_connected_p(void);
bool btc_avrc_ct_connected_p(void);
const uint16_t *btc_avrc_tg_get_supported_command(void);
const uint16_t *btc_avrc_tg_get_allowed_command(void);
bool btc_avrc_tg_check_supported_command(const uint16_t *cmd_set);
uint16_t btc_avrc_tg_get_rn_allowed_evt(void);
uint16_t btc_avrc_tg_get_rn_supported_evt(void);
bool btc_avrc_tg_check_rn_supported_evt(uint16_t evt_set);
bool btc_avrc_tg_rn_evt_supported(uint8_t event_id);
bool btc_avrc_ct_rn_evt_supported(uint8_t event_id);
#endif ///BTC_AV_INCLUDED == TRUE
#endif /* __BTC_AVRC_H__ */
@@ -0,0 +1,421 @@
/*
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __BTC_GAP_BLE_H__
#define __BTC_GAP_BLE_H__
#include "esp_bt_defs.h"
#include "esp_gap_ble_api.h"
#if BTC_DYNAMIC_MEMORY == TRUE
#include "bta/bta_api.h"
extern tBTA_BLE_ADV_DATA *gl_bta_adv_data_ptr;
extern tBTA_BLE_ADV_DATA *gl_bta_scan_rsp_data_ptr;
#define gl_bta_adv_data (*gl_bta_adv_data_ptr)
#define gl_bta_scan_rsp_data (*gl_bta_scan_rsp_data_ptr)
#endif
#define BLE_ISVALID_PARAM(x, min, max) (((x) >= (min) && (x) <= (max)))
typedef enum {
#if (BLE_42_FEATURE_SUPPORT == TRUE)
BTC_GAP_BLE_ACT_CFG_ADV_DATA = 0,
BTC_GAP_BLE_ACT_SET_SCAN_PARAM,
BTC_GAP_BLE_ACT_START_SCAN,
BTC_GAP_BLE_ACT_STOP_SCAN,
BTC_GAP_BLE_ACT_START_ADV,
BTC_GAP_BLE_ACT_STOP_ADV,
#endif // #if (BLE_42_FEATURE_SUPPORT == TRUE)
BTC_GAP_BLE_ACT_UPDATE_CONN_PARAM = 6,
BTC_GAP_BLE_ACT_SET_PKT_DATA_LEN,
BTC_GAP_BLE_ACT_SET_RAND_ADDRESS,
BTC_GAP_BLE_ACT_CLEAR_RAND_ADDRESS,
BTC_GAP_BLE_ACT_CONFIG_LOCAL_PRIVACY,
BTC_GAP_BLE_ACT_CONFIG_LOCAL_ICON,
BTC_GAP_BLE_ACT_UPDATE_WHITE_LIST,
BTC_GAP_BLE_ACT_CLEAR_WHITE_LIST,
#if (BLE_42_FEATURE_SUPPORT == TRUE)
BTC_GAP_BLE_ACT_SET_CONN_PARAMS,
#endif // #if (BLE_42_FEATURE_SUPPORT == TRUE)
BTC_GAP_BLE_ACT_SET_DEV_NAME = 15,
#if (BLE_42_FEATURE_SUPPORT == TRUE)
BTC_GAP_BLE_ACT_CFG_ADV_DATA_RAW,
BTC_GAP_BLE_ACT_CFG_SCAN_RSP_DATA_RAW,
#endif // #if (BLE_42_FEATURE_SUPPORT == TRUE)
BTC_GAP_BLE_ACT_READ_RSSI = 18,
BTC_GAP_BLE_SET_ENCRYPTION_EVT,
BTC_GAP_BLE_SET_SECURITY_PARAM_EVT,
BTC_GAP_BLE_SECURITY_RSP_EVT,
BTC_GAP_BLE_PASSKEY_REPLY_EVT,
BTC_GAP_BLE_CONFIRM_REPLY_EVT,
BTC_GAP_BLE_DISCONNECT_EVT,
BTC_GAP_BLE_REMOVE_BOND_DEV_EVT,
BTC_GAP_BLE_OOB_REQ_REPLY_EVT,
BTC_GAP_BLE_SC_OOB_REQ_REPLY_EVT,
BTC_GAP_BLE_SC_CR_OOB_DATA_EVT,
BTC_GAP_BLE_UPDATE_DUPLICATE_SCAN_EXCEPTIONAL_LIST,
BTC_GAP_BLE_SET_AFH_CHANNELS,
#if (BLE_50_FEATURE_SUPPORT == TRUE)
BTC_GAP_BLE_READ_PHY,
BTC_GAP_BLE_SET_PREFERED_DEF_PHY,
BTC_GAP_BLE_SET_DEF_PHY,
BTC_GAP_BLE_SET_EXT_ADV_RAND_ADDR,
BTC_GAP_BLE_SET_EXT_ADV_PARAMS,
BTC_GAP_BLE_CFG_EXT_ADV_DATA_RAW,
BTC_GAP_BLE_CFG_EXT_SCAN_RSP_DATA_RAW,
BTC_GAP_BLE_EXT_ADV_START,
BTC_GAP_BLE_EXT_ADV_STOP,
BTC_GAP_BLE_EXT_ADV_SET_REMOVE,
BTC_GAP_BLE_EXT_ADV_SET_CLEAR,
BTC_GAP_BLE_SET_PERIODIC_ADV_PARAMS,
BTC_GAP_BLE_CFG_PERIODIC_ADV_DATA_RAW,
BTC_GAP_BLE_PERIODIC_ADV_START,
BTC_GAP_BLE_PERIODIC_ADV_STOP,
BTC_GAP_BLE_PERIODIC_ADV_CREATE_SYNC,
BTC_GAP_BLE_PERIODIC_ADV_SYNC_CANCEL,
BTC_GAP_BLE_PERIODIC_ADV_SYNC_TERMINATE,
BTC_GAP_BLE_PERIODIC_ADV_ADD_DEV_TO_LIST,
BTC_GAP_BLE_PERIODIC_REMOVE_ADD_DEV_FROM_LIST,
BTC_GAP_BLE_PERIODIC_CLEAR_DEV,
BTC_GAP_BLE_SET_EXT_SCAN_PARAMS,
BTC_GAP_BLE_START_EXT_SCAN,
BTC_GAP_BLE_STOP_EXT_SCAN,
BTC_GAP_BLE_SET_EXT_PEFER_CONNET_PARAMS,
BTC_GAP_BLE_DTM_ENH_TX_START,
BTC_GAP_BLE_DTM_ENH_RX_START,
#endif // #if (BLE_50_FEATURE_SUPPORT == TRUE)
BTC_GAP_BLE_ACT_GET_DEV_NAME,
#if (BLE_FEAT_PERIODIC_ADV_SYNC_TRANSFER == TRUE)
BTC_GAP_BLE_PERIODIC_ADV_RECV_ENABLE,
BTC_GAP_BLE_PERIODIC_ADV_SYNC_TRANS,
BTC_GAP_BLE_PERIODIC_ADV_SET_INFO_TRANS,
BTC_GAP_BLE_SET_PERIODIC_ADV_SYNC_TRANS_PARAMS,
#endif //#if (BLE_FEAT_PERIODIC_ADV_SYNC_TRANSFER == TRUE)
#if (BLE_42_FEATURE_SUPPORT == TRUE)
BTC_GAP_BLE_DTM_TX_START,
BTC_GAP_BLE_DTM_RX_START,
#endif // #if (BLE_42_FEATURE_SUPPORT == TRUE)
BTC_GAP_BLE_DTM_STOP,
#if (BLE_42_FEATURE_SUPPORT == TRUE)
BTC_GAP_BLE_ACT_CLEAR_ADV,
#endif // #if (BLE_42_FEATURE_SUPPORT == TRUE)
} btc_gap_ble_act_t;
/* btc_ble_gap_args_t */
typedef union {
#if (BLE_42_FEATURE_SUPPORT == TRUE)
//BTC_GAP_BLE_ACT_CFG_ADV_DATA = 0,
struct config_adv_data_args {
esp_ble_adv_data_t adv_data;
} cfg_adv_data;
//BTC_GAP_BLE_ACT_SET_SCAN_PARAM,
struct set_scan_params_args {
esp_ble_scan_params_t scan_params;
} set_scan_param;
//BTC_GAP_BLE_ACT_START_SCAN,
struct start_scan_args {
uint32_t duration;
} start_scan;
//BTC_GAP_BLE_ACT_STOP_SCAN, no args
//BTC_GAP_BLE_ACT_START_ADV,
struct start_adv_args {
esp_ble_adv_params_t adv_params;
} start_adv;
//BTC_GAP_BLE_ACT_STOP_ADV, no args
#endif // #if (BLE_42_FEATURE_SUPPORT == TRUE)
//BTC_GAP_BLE_ACT_UPDATE_CONN_PARAM,
struct conn_update_params_args {
esp_ble_conn_update_params_t conn_params;
} conn_update_params;
//BTC_GAP_BLE_ACT_SET_PKT_DATA_LEN
struct set_pkt_data_len_args {
esp_bd_addr_t remote_device;
uint16_t tx_data_length;
} set_pkt_data_len;
//BTC_GAP_BLE_ACT_SET_RAND_ADDRESS,
struct set_rand_addr_args {
esp_bd_addr_t rand_addr;
} set_rand_addr;
//BTC_GAP_BLE_ACT_CONFIG_LOCAL_PRIVACY,
struct cfg_local_privacy_args {
bool privacy_enable;
} cfg_local_privacy;
//BTC_GAP_BLE_ACT_CONFIG_LOCAL_ICON,
struct cfg_local_icon_args {
uint16_t icon;
} cfg_local_icon;
//BTC_GAP_BLE_ACT_UPDATE_WHITE_LIST
struct update_white_list_args {
bool add_remove;
esp_bd_addr_t remote_bda;
esp_ble_wl_addr_type_t wl_addr_type;
} update_white_list;
#if (BLE_42_FEATURE_SUPPORT == TRUE)
//BTC_GAP_BLE_UPDATE_DUPLICATE_SCAN_EXCEPTIONAL_LIST
struct update_duplicate_exceptional_list_args {
uint8_t subcode;
uint32_t info_type;
esp_duplicate_info_t device_info;
} update_duplicate_exceptional_list;
//BTC_GAP_BLE_ACT_SET_CONN_PARAMS
struct set_conn_params_args {
esp_bd_addr_t bd_addr;
uint16_t min_conn_int;
uint16_t max_conn_int;
uint16_t slave_latency;
uint16_t supervision_tout;
} set_conn_params;
#endif // #if (BLE_42_FEATURE_SUPPORT == TRUE)
//BTC_GAP_BLE_ACT_SET_DEV_NAME,
struct set_dev_name_args {
#define ESP_GAP_DEVICE_NAME_MAX (32)
char device_name[ESP_GAP_DEVICE_NAME_MAX + 1];
} set_dev_name;
#if (BLE_42_FEATURE_SUPPORT == TRUE)
//BTC_GAP_BLE_ACT_CFG_ADV_DATA_RAW,
struct config_adv_data_raw_args {
uint8_t *raw_adv;
uint32_t raw_adv_len;
} cfg_adv_data_raw;
//BTC_GAP_BLE_ACT_CFG_SCAN_RSP_DATA_RAW,
struct config_scan_rsp_data_raw_args {
uint8_t *raw_scan_rsp;
uint32_t raw_scan_rsp_len;
} cfg_scan_rsp_data_raw;
#endif // #if (BLE_42_FEATURE_SUPPORT == TRUE)
//BTC_GAP_BLE_SET_ENCRYPTION_EVT
struct set_encryption_args {
esp_bd_addr_t bd_addr;
esp_ble_sec_act_t sec_act;
} set_encryption;
//BTC_GAP_BLE_SET_SECURITY_PARAM_EVT
struct set_security_param_args {
esp_ble_sm_param_t param_type;
uint8_t len;
uint8_t *value;
} set_security_param;
//BTC_GAP_BLE_SECURITY_RSP_EVT
struct enc_rsp_args {
esp_bd_addr_t bd_addr;
bool accept;
} sec_rsp;
//BTC_GAP_BLE_PASSKEY_REPLY_EVT
struct enc_passkey_reply_args {
esp_bd_addr_t bd_addr;
bool accept;
uint32_t passkey;
} enc_passkey_replay;
//BTC_GAP_BLE_CONFIRM_REPLY_EVT
struct enc_comfirm_reply_args {
esp_bd_addr_t bd_addr;
bool accept;
} enc_comfirm_replay;
//BTC_GAP_BLE_OOB_DATA_REPLY_EVT
struct oob_req_reply_args {
esp_bd_addr_t bd_addr;
uint8_t len;
uint8_t *p_value;
} oob_req_reply;
struct sc_oob_req_reply_args {
esp_bd_addr_t bd_addr;
uint8_t *p_c;
uint8_t *p_r;
} sc_oob_req_reply;
//BTC_GAP_BLE_DISCONNECT_EVT
struct disconnect_args {
esp_bd_addr_t remote_device;
} disconnect;
//BTC_GAP_BLE_REMOVE_BOND_DEV_EVT
struct remove_bond_device_args {
esp_bd_addr_t bd_addr;
} remove_bond_device;
//BTC_GAP_BLE_ACT_READ_RSSI
struct read_rssi_args {
esp_bd_addr_t remote_addr;
} read_rssi;
// BTC_GAP_BLE_SET_AFH_CHANNELS
struct set_channels_args {
esp_gap_ble_channels channels;
} set_channels;
struct dtm_tx_start_args {
uint8_t tx_channel;
uint8_t len_of_data;
uint8_t pkt_payload;
} dtm_tx_start;
struct dtm_rx_start_args {
uint8_t rx_channel;
} dtm_rx_start;
} btc_ble_gap_args_t;
#if (BLE_50_FEATURE_SUPPORT == TRUE)
typedef union {
struct read_phy_args {
esp_bd_addr_t bd_addr;
} read_phy;
struct set_perf_def_phy_args {
esp_ble_gap_phy_mask_t tx_phy_mask;
esp_ble_gap_phy_mask_t rx_phy_mask;
} set_perf_def_phy;
struct set_def_phy_args {
esp_bd_addr_t bd_addr;
esp_ble_gap_all_phys_t all_phys_mask;
esp_ble_gap_phy_mask_t tx_phy_mask;
esp_ble_gap_phy_mask_t rx_phy_mask;
uint16_t phy_options;
} set_def_phy;
struct ext_adv_set_rand_addr_args {
uint8_t instance;
esp_bd_addr_t rand_addr;
} ext_adv_set_rand_addr;
struct ext_adv_set_params_args {
uint8_t instance;
esp_ble_gap_ext_adv_params_t params;
} ext_adv_set_params;
struct ext_adv_cfg_data_args {
uint8_t instance;
uint16_t length;
uint8_t *data;
} ext_adv_cfg_data;
struct ext_adv_cfg_scan_rsp_args {
uint8_t instance;
uint16_t length;
uint8_t *data;
} cfg_scan_rsp;
struct ext_adv_start_args {
uint8_t num_adv;
esp_ble_gap_ext_adv_t *ext_adv;
} ext_adv_start;
struct ext_adv_stop_args {
uint8_t num_adv;
uint8_t *ext_adv_inst;
} ext_adv_stop;
struct ext_adv_set_remove_args {
uint8_t instance;
} ext_adv_set_remove;
struct peridic_adv_set_params_args {
uint8_t instance;
esp_ble_gap_periodic_adv_params_t params;
} peridic_adv_set_params;
struct periodic_adv_cfg_data_args {
uint8_t instance;
uint16_t len;
uint8_t *data;
bool only_update_did;
} periodic_adv_cfg_data;
struct periodic_adv_start_args {
bool include_adi;
uint8_t instance;
} periodic_adv_start;
struct periodic_adv_stop_args {
uint8_t instance;
} periodic_adv_stop;
struct periodic_adv_create_sync_args {
esp_ble_gap_periodic_adv_sync_params_t params;
} periodic_adv_create_sync;
struct periodic_adv_sync_term_args {
uint16_t sync_handle;
} periodic_adv_sync_term;
struct periodic_adv_add_dev_args {
esp_ble_addr_type_t addr_type;
esp_bd_addr_t addr;
uint16_t sid;
} periodic_adv_add_dev;
struct periodic_adv_remove_dev_args {
esp_ble_addr_type_t addr_type;
esp_bd_addr_t addr;
uint16_t sid;
} periodic_adv_remove_dev;
struct set_ext_scan_params_args {
esp_ble_ext_scan_params_t params;
} set_ext_scan_params;
struct start_ext_scan_args {
uint32_t duration;
uint16_t period;
} start_ext_scan;
struct set_ext_conn_params_args {
esp_bd_addr_t addr;
uint8_t phy_mask;
esp_ble_gap_conn_params_t phy_1m_conn_params;
esp_ble_gap_conn_params_t phy_2m_conn_params;
esp_ble_gap_conn_params_t phy_coded_conn_params;
} set_ext_conn_params;
struct ext_conn_args {
esp_ble_addr_type_t own_addr_type;
esp_bd_addr_t peer_addr;
} ext_conn;
#if (BLE_FEAT_PERIODIC_ADV_SYNC_TRANSFER == TRUE)
struct periodic_adv_recv_en_args {
uint16_t sync_handle;
uint8_t enable;
} periodic_adv_recv_en;
struct periodic_adv_sync_trans_args {
esp_bd_addr_t addr;
uint16_t service_data;
uint16_t sync_handle;
} periodic_adv_sync_trans;
struct periodic_adv_set_info_trans_args {
esp_bd_addr_t addr;
uint16_t service_data;
uint16_t adv_handle;
} periodic_adv_set_info_trans;
struct set_periodic_adv_sync_trans_params_args {
esp_bd_addr_t addr;
esp_ble_gap_past_params_t params;
} set_periodic_adv_sync_trans_params;
#endif
struct dtm_enh_tx_start_args {
uint8_t tx_channel;
uint8_t len_of_data;
uint8_t pkt_payload;
uint8_t phy;
} dtm_enh_tx_start;
struct dtm_enh_rx_start_args {
uint8_t rx_channel;
uint8_t phy;
uint8_t modulation_index;
} dtm_enh_rx_start;
} btc_ble_5_gap_args_t;
#endif // #if (BLE_50_FEATURE_SUPPORT == TRUE)
void btc_gap_ble_call_handler(btc_msg_t *msg);
void btc_gap_ble_cb_handler(btc_msg_t *msg);
void btc_get_whitelist_size(uint16_t *length);
void btc_gap_ble_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src);
void btc_gap_ble_arg_deep_free(btc_msg_t *msg);
void btc_gap_ble_cb_deep_free(btc_msg_t *msg);
void btc_gap_ble_cb_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src);
void btc_gap_callback_init(void);
bool btc_gap_ble_init(void);
void btc_gap_ble_deinit(void);
void btc_adv_list_init(void);
void btc_adv_list_deinit(void);
#endif /* __BTC_GAP_BLE_H__ */
@@ -0,0 +1,179 @@
/*
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __BTC_GAP_BT_H__
#define __BTC_GAP_BT_H__
#include "common/bt_target.h"
#include "common/bt_defs.h"
#include "esp_bt_defs.h"
#include "esp_gap_bt_api.h"
#include "btc/btc_task.h"
#include "bta/utl.h"
#if (BTC_GAP_BT_INCLUDED == TRUE)
typedef enum {
BTC_GAP_BT_SEARCH_DEVICES_EVT = 0,
BTC_GAP_BT_SEARCH_SERVICES_EVT,
BTC_GAP_BT_SEARCH_SERVICE_RECORD_EVT,
BTC_GAP_BT_AUTH_CMPL_EVT,
BTC_GAP_BT_ENC_CHG_EVT,
BTC_GAP_BT_PIN_REQ_EVT,
BTC_GAP_BT_CFM_REQ_EVT,
BTC_GAP_BT_KEY_NOTIF_EVT,
BTC_GAP_BT_KEY_REQ_EVT,
BTC_GAP_BT_READ_RSSI_DELTA_EVT,
BTC_GAP_BT_CONFIG_EIR_DATA_EVT,
BTC_GAP_BT_SET_AFH_CHANNELS_EVT,
BTC_GAP_BT_READ_REMOTE_NAME_EVT,
BTC_GAP_BT_MODE_CHG_EVT,
BTC_GAP_BT_REMOVE_BOND_DEV_COMPLETE_EVT,
BTC_GAP_BT_QOS_EVT,
BTC_GAP_BT_SET_PAGE_TO_EVT,
BTC_GAP_BT_GET_PAGE_TO_EVT,
BTC_GAP_BT_SET_ACL_PKT_TYPES_EVT,
}btc_gap_bt_evt_t;
typedef enum {
BTC_GAP_BT_ACT_SET_SCAN_MODE = 0,
BTC_GAP_BT_ACT_START_DISCOVERY,
BTC_GAP_BT_ACT_CANCEL_DISCOVERY,
BTC_GAP_BT_ACT_GET_REMOTE_SERVICES,
BTC_GAP_BT_ACT_GET_REMOTE_SERVICE_RECORD,
BTC_GAP_BT_ACT_SET_COD,
BTC_GAP_BT_ACT_READ_RSSI_DELTA,
BTC_GAP_BT_ACT_REMOVE_BOND_DEVICE,
BTC_GAP_BT_ACT_SET_PIN_TYPE,
BTC_GAP_BT_ACT_PIN_REPLY,
BTC_GAP_BT_ACT_SET_SECURITY_PARAM,
BTC_GAP_BT_ACT_PASSKEY_REPLY,
BTC_GAP_BT_ACT_CONFIRM_REPLY,
BTC_GAP_BT_ACT_CONFIG_EIR,
BTC_GAP_BT_ACT_SET_AFH_CHANNELS,
BTC_GAP_BT_ACT_READ_REMOTE_NAME,
BTC_GAP_BT_ACT_SET_QOS,
BTC_GAP_BT_ACT_SET_PAGE_TIMEOUT,
BTC_GAP_BT_ACT_GET_PAGE_TIMEOUT,
BTC_GAP_BT_ACT_SET_ACL_PKT_TYPES,
} btc_gap_bt_act_t;
/* btc_bt_gap_args_t */
typedef union {
// BTC_BT_GAP_ACT_SET_SCAN_MODE,
struct set_bt_scan_mode_args {
esp_bt_connection_mode_t c_mode;
esp_bt_discovery_mode_t d_mode;
} set_scan_mode;
// BTC_GAP_BT_ACT_START_DISCOVERY
struct start_disc_args {
esp_bt_inq_mode_t mode;
uint8_t inq_len;
uint8_t num_rsps;
} start_disc;
// BTC_GAP_BT_ACT_GET_REMOTE_SERVICES
bt_bdaddr_t bda;
// BTC_GAP_BT_ACT_GET_REMOTE_SERVICE_RECORD
struct get_rmt_srv_rcd_args {
bt_bdaddr_t bda;
esp_bt_uuid_t uuid;
} get_rmt_srv_rcd;
// BTC_GAP_BT_ACT_SET_COD
struct set_cod_args {
esp_bt_cod_t cod;
esp_bt_cod_mode_t mode;
} set_cod;
//BTC_GAP_BT_ACT_READ_RSSI_DELTA,
struct bt_read_rssi_delta_args {
bt_bdaddr_t bda;
} read_rssi_delta;
// BTC_GAP_BT_ACT_REMOVE_BOND_DEVICE
struct rm_bond_device_args {
bt_bdaddr_t bda;
} rm_bond_device;
// BTC_GAP_BT_ACT_SET_PIN_TYPE
struct set_pin_type_args {
esp_bt_pin_type_t pin_type;
uint8_t pin_code_len;
esp_bt_pin_code_t pin_code;
} set_pin_type;
// BTC_GAP_BT_ACT_PIN_REPLY
struct pin_reply_args {
bt_bdaddr_t bda;
bool accept;
uint8_t pin_code_len;
esp_bt_pin_code_t pin_code;
} pin_reply;
// BTC_GAP_BT_ACT_SET_SECURITY_PARAM
struct set_sec_param_args {
esp_bt_sp_param_t param_type;
uint8_t len;
uint8_t *value;
} set_security_param;
// BTC_GAP_BT_ACT_PASSKEY_REPLY
struct passkey_reply_args {
bt_bdaddr_t bda;
bool accept;
uint32_t passkey;
} passkey_reply;
// BTC_GAP_BT_ACT_CONFIRM_REPLY
struct confirm_reply_args {
bt_bdaddr_t bda;
bool accept;
} confirm_reply;
// BTC_GAP_BT_ACT_CONFIG_EIR
struct config_eir_args {
esp_bt_eir_data_t eir_data;
} config_eir;
// BTC_GAP_BT_ACT_SET_AFH_CHANNELS
struct set_afh_channels_args {
esp_bt_gap_afh_channels channels;
} set_afh_channels;
// BTC_GAP_BT_ACT_READ_REMOTE_NAME
bt_bdaddr_t rmt_name_bda;
// BTC_GAP_BT_ACT_SET_QOS
struct set_qos_args {
bt_bdaddr_t bda;
uint32_t t_poll;
} set_qos;
// BTC_GAP_BT_ACT_SET_PAGE_TIMEOUT
struct set_page_to_args {
uint16_t page_to;
} set_page_to;
// BTC_GAP_BT_ACT_SET_ACL_PKT_TYPES
struct set_acl_pkt_types_args {
bt_bdaddr_t bda;
uint16_t pkt_types;
} set_acl_pkt_types;
} btc_gap_bt_args_t;
void btc_gap_bt_call_handler(btc_msg_t *msg);
void btc_gap_bt_cb_handler(btc_msg_t *msg);
void btc_gap_bt_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src);
void btc_gap_bt_arg_deep_free(btc_msg_t *msg);
void btc_gap_bt_busy_level_updated(uint8_t bl_flags);
esp_err_t btc_gap_bt_get_cod(esp_bt_cod_t *cod);
#endif /* #if BTC_GAP_BT_INCLUDED */
#endif /* __BTC_GAP_BT_H__ */
@@ -0,0 +1,29 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __BTC_GATT_COMMON_H__
#define __BTC_GATT_COMMON_H__
#include "osi/future.h"
#include "stack/bt_types.h"
#include "bta/bta_api.h"
#include "btc/btc_main.h"
#include "btc/btc_task.h"
typedef enum {
BTC_GATT_ACT_SET_LOCAL_MTU = 0,
} btc_gatt_com_act_t;
/* btc_ble_gattc_args_t */
typedef union {
//BTC_GATT_ACT_SET_LOCAL_MTU,
struct set_mtu_arg {
uint16_t mtu;
} set_mtu;
} btc_ble_gatt_com_args_t;
void btc_gatt_com_call_handler(btc_msg_t *msg);
#endif /* __BTC_GATT_COMMON_H__ */
@@ -0,0 +1,32 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __BTC_GATT_UTIL_H__
#define __BTC_GATT_UTIL_H__
#include "stack/bt_types.h"
#include "bta/bta_gatt_api.h"
#include "esp_bt_defs.h"
#include "esp_gatt_defs.h"
#include "esp_gattc_api.h"
#define BTC_GATT_CREATE_CONN_ID(gatt_if, conn_id) ((uint16_t) ((((uint8_t)(conn_id)) << 8) | ((uint8_t)(gatt_if))))
#define BTC_GATT_GET_CONN_ID(conn_id) (((uint16_t)(conn_id)) >> 8)
#define BTC_GATT_GET_GATT_IF(conn_id) ((uint8_t)(conn_id))
void btc128_to_bta_uuid(tBT_UUID *p_dest, uint8_t *p_src);
void btc_to_bta_uuid(tBT_UUID *p_dest, esp_bt_uuid_t *p_src);
void btc_to_bta_gatt_id(tBTA_GATT_ID *p_dest, esp_gatt_id_t *p_src);
void btc_to_bta_srvc_id(tBTA_GATT_SRVC_ID *p_dest, esp_gatt_srvc_id_t *p_src);
void btc_to_bta_response(tBTA_GATTS_RSP *rsp_struct, esp_gatt_rsp_t *p_rsp);
void bta_to_btc_uuid(esp_bt_uuid_t *p_dest, tBT_UUID *p_src);
void bta_to_btc_gatt_id(esp_gatt_id_t *p_dest, tBTA_GATT_ID *p_src);
void bta_to_btc_srvc_id(esp_gatt_srvc_id_t *p_dest, tBTA_GATT_SRVC_ID *p_src);
uint16_t set_read_value(uint8_t *gattc_if, esp_ble_gattc_cb_param_t *p_dest, tBTA_GATTC_READ *p_src);
#endif /* __BTC_GATT_UTIL_H__*/
@@ -0,0 +1,252 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __BTC_GATTC_H__
#define __BTC_GATTC_H__
#include "btc/btc_task.h"
#include "esp_bt_defs.h"
#include "esp_gatt_defs.h"
#include "esp_gattc_api.h"
typedef enum {
BTC_GATTC_ACT_APP_REGISTER = 0,
BTC_GATTC_ACT_APP_UNREGISTER,
BTC_GATTC_ACT_OPEN,
#if (BLE_50_FEATURE_SUPPORT == TRUE)
BTC_GATTC_ACT_AUX_OPEN,
#endif // #if (BLE_50_FEATURE_SUPPORT == TRUE)
BTC_GATTC_ACT_CLOSE,
BTC_GATTC_ACT_CFG_MTU,
BTC_GATTC_ACT_SEARCH_SERVICE,
BTC_GATTC_ACT_READ_CHAR,
BTC_GATTC_ACT_READ_MULTIPLE_CHAR,
BTC_GATTC_ACT_READ_MULTIPLE_VARIABLE_CHAR,
BTC_GATTC_ACT_READ_CHAR_DESCR,
BTC_GATTC_ACT_READ_BY_TYPE,
BTC_GATTC_ACT_WRITE_CHAR,
BTC_GATTC_ACT_WRITE_CHAR_DESCR,
BTC_GATTC_ACT_PREPARE_WRITE,
BTC_GATTC_ACT_PREPARE_WRITE_CHAR_DESCR,
BTC_GATTC_ACT_EXECUTE_WRITE,
BTC_GATTC_ACT_REG_FOR_NOTIFY,
BTC_GATTC_ACT_UNREG_FOR_NOTIFY,
BTC_GATTC_ACT_CACHE_REFRESH,
BTC_GATTC_ACT_CACHE_ASSOC,
BTC_GATTC_ATC_CACHE_GET_ADDR_LIST,
BTC_GATTC_ACT_CACHE_CLEAN,
} btc_gattc_act_t;
/* btc_ble_gattc_args_t */
typedef union {
//BTC_GATTC_ACT_APP_REGISTER,
struct app_reg_arg {
uint16_t app_id;
} app_reg;
//BTC_GATTC_ACT_APP_UNREGISTER,
struct app_unreg_arg {
esp_gatt_if_t gattc_if;
} app_unreg;
//BTC_GATTC_ACT_OPEN,
struct open_arg {
esp_gatt_if_t gattc_if;
esp_bd_addr_t remote_bda;
esp_ble_addr_type_t remote_addr_type;
bool is_direct;
bool is_aux;
} open;
//BTC_GATTC_ACT_CLOSE,
struct close_arg {
uint16_t conn_id;
} close;
//BTC_GATTC_ACT_CFG_MTU,
struct cfg_mtu_arg {
uint16_t conn_id;
} cfg_mtu;
//BTC_GATTC_ACT_SEARCH_SERVICE,
struct search_srvc_arg {
uint16_t conn_id;
bool filter_uuid_enable;
esp_bt_uuid_t filter_uuid;
} search_srvc;
//BTC_GATTC_ACT_GET_CHAR,
struct get_char_arg {
uint16_t conn_id;
uint16_t handle;
} get_char;
//BTC_GATTC_ACT_GET_DESCR,
struct get_descr_arg {
uint16_t conn_id;
uint16_t handle;
} get_descr;
//BTC_GATTC_ACT_GET_FIRST_INCL_SERVICE,
struct get_first_incl_srvc_arg {
uint16_t conn_id;
uint16_t handle;
} get_first_incl_srvc;
//BTC_GATTC_ACT_GET_NEXT_INCL_SERVICE,
struct get_next_incl_srvc_arg {
uint16_t conn_id;
uint16_t handle;
} get_next_incl_srvc;
//BTC_GATTC_ACT_READ_CHAR,
struct read_char_arg {
uint16_t conn_id;
uint16_t handle;
esp_gatt_auth_req_t auth_req;
} read_char;
//BTC_GATTC_ACT_READ_MULTIPLE_CHAR
struct read_multiple_arg {
uint16_t conn_id;
uint8_t num_attr;
uint16_t handles[ESP_GATT_MAX_READ_MULTI_HANDLES];
esp_gatt_auth_req_t auth_req;
} read_multiple;
//BTC_GATTC_ACT_READ_CHAR_DESCR,
struct read_descr_arg {
uint16_t conn_id;
uint16_t handle;
esp_gatt_auth_req_t auth_req;
} read_descr;
// BTC_GATTC_ACT_READ_BY_TYPE
struct read_by_type_arg {
uint16_t conn_id;
uint16_t s_handle;
uint16_t e_handle;
esp_bt_uuid_t uuid;
esp_gatt_auth_req_t auth_req;
} read_by_type;
//BTC_GATTC_ACT_WRITE_CHAR,
struct write_char_arg {
uint16_t conn_id;
uint16_t value_len;
uint16_t handle;
uint8_t *value;
esp_gatt_write_type_t write_type;
esp_gatt_auth_req_t auth_req;
} write_char;
//BTC_GATTC_ACT_WRITE_CHAR_DESCR,
struct write_descr_arg {
uint16_t conn_id;
uint16_t value_len;
uint16_t handle;
uint8_t *value;
esp_gatt_write_type_t write_type;
esp_gatt_auth_req_t auth_req;
} write_descr;
//BTC_GATTC_ACT_PREPARE_WRITE,
struct prep_write_arg {
uint16_t conn_id;
uint16_t handle;
uint16_t offset;
uint16_t value_len;
uint8_t *value;
esp_gatt_auth_req_t auth_req;
} prep_write;
//BTC_GATTC_ACT_PREPARE_WRITE_CHAR_DESCR,
struct prep_write_descr_arg {
uint16_t conn_id;
uint16_t handle;
uint16_t offset;
uint16_t value_len;
uint8_t *value;
esp_gatt_auth_req_t auth_req;
} prep_write_descr;
//BTC_GATTC_ACT_EXECUTE_WRITE,
struct exec_write_arg {
uint16_t conn_id;
bool is_execute;
} exec_write;
//BTC_GATTC_ACT_REG_FOR_NOTIFY,
struct reg_for_notify_arg {
esp_gatt_if_t gattc_if;
esp_bd_addr_t remote_bda;
uint16_t handle;
} reg_for_notify;
//BTC_GATTC_ACT_UNREG_FOR_NOTIFY
struct unreg_for_notify_arg {
esp_gatt_if_t gattc_if;
esp_bd_addr_t remote_bda;
uint16_t handle;
} unreg_for_notify;
//BTC_GATTC_ACT_CACHE_REFRESH,
struct cache_refresh_arg {
esp_bd_addr_t remote_bda;
} cache_refresh;
//BTC_GATTC_ACT_CACHE_ASSOC
struct cache_assoc_arg {
esp_gatt_if_t gattc_if;
esp_bd_addr_t src_addr;
esp_bd_addr_t assoc_addr;
bool is_assoc;
} cache_assoc;
//BTC_GATTC_ATC_CACHE_GET_ADDR_LIST
struct cache_get_addr_list_arg {
esp_gatt_if_t gattc_if;
}get_addr_list;
//BTC_GATTC_ACT_CACHE_CLEAN,
struct cache_clean_arg {
esp_bd_addr_t remote_bda;
} cache_clean;
} btc_ble_gattc_args_t;
void btc_gattc_call_handler(btc_msg_t *msg);
void btc_gattc_cb_handler(btc_msg_t *msg);
void btc_gattc_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src);
void btc_gattc_arg_deep_free(btc_msg_t *msg);
esp_gatt_status_t btc_ble_gattc_get_service(uint16_t conn_id, esp_bt_uuid_t *svc_uuid,
esp_gattc_service_elem_t *result,
uint16_t *count, uint16_t offset);
esp_gatt_status_t btc_ble_gattc_get_all_char(uint16_t conn_id,
uint16_t start_handle,
uint16_t end_handle,
esp_gattc_char_elem_t *result,
uint16_t *count, uint16_t offset);
esp_gatt_status_t btc_ble_gattc_get_all_descr(uint16_t conn_id,
uint16_t char_handle,
esp_gattc_descr_elem_t *result,
uint16_t *count, uint16_t offset);
esp_gatt_status_t btc_ble_gattc_get_char_by_uuid(uint16_t conn_id,
uint16_t start_handle,
uint16_t end_handle,
esp_bt_uuid_t char_uuid,
esp_gattc_char_elem_t *result,
uint16_t *count);
esp_gatt_status_t btc_ble_gattc_get_descr_by_uuid(uint16_t conn_id,
uint16_t start_handle,
uint16_t end_handle,
esp_bt_uuid_t char_uuid,
esp_bt_uuid_t descr_uuid,
esp_gattc_descr_elem_t *result,
uint16_t *count);
esp_gatt_status_t btc_ble_gattc_get_descr_by_char_handle(uint16_t conn_id,
uint16_t char_handle,
esp_bt_uuid_t descr_uuid,
esp_gattc_descr_elem_t *result,
uint16_t *count);
esp_gatt_status_t btc_ble_gattc_get_include_service(uint16_t conn_id,
uint16_t start_handle,
uint16_t end_handle,
esp_bt_uuid_t *incl_uuid,
esp_gattc_incl_svc_elem_t *result,
uint16_t *count);
esp_gatt_status_t btc_ble_gattc_get_attr_count(uint16_t conn_id,
esp_gatt_db_attr_type_t type,
uint16_t start_handle,
uint16_t end_handle,
uint16_t char_handle,
uint16_t *count);
esp_gatt_status_t btc_ble_gattc_get_db(uint16_t conn_id, uint16_t start_handle, uint16_t end_handle,
esp_gattc_db_elem_t *db, uint16_t *count);
#endif /* __BTC_GATTC_H__ */
@@ -0,0 +1,171 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __BTC_GATTS_H__
#define __BTC_GATTS_H__
#include "btc/btc_task.h"
#include "esp_bt_defs.h"
#include "esp_gatt_defs.h"
#include "esp_gatts_api.h"
#include "osi/future.h"
typedef enum {
BTC_GATTS_ACT_APP_REGISTER = 0,
BTC_GATTS_ACT_APP_UNREGISTER,
BTC_GATTS_ACT_CREATE_SERVICE,
BTC_GATTS_ACT_CREATE_ATTR_TAB,
BTC_GATTS_ACT_DELETE_SERVICE,
BTC_GATTS_ACT_START_SERVICE,
BTC_GATTS_ACT_STOP_SERVICE,
BTC_GATTS_ACT_ADD_INCLUDE_SERVICE,
BTC_GATTS_ACT_ADD_CHAR,
BTC_GATTS_ACT_ADD_CHAR_DESCR,
BTC_GATTS_ACT_SEND_INDICATE,
BTC_GATTS_ACT_SEND_RESPONSE,
BTC_GATTS_ACT_SET_ATTR_VALUE,
BTC_GATTS_ACT_OPEN,
BTC_GATTS_ACT_CLOSE,
BTC_GATTS_ACT_SEND_SERVICE_CHANGE,
BTC_GATTS_ACT_SHOW_LOCAL_DATABASE,
} btc_gatts_act_t;
/* btc_ble_gatts_args_t */
typedef union {
//BTC_GATTS_ACT_APP_REGISTER = 0,
struct app_reg_args {
uint16_t app_id;
} app_reg;
//BTC_GATTS_ACT_APP_UNREGISTER,
struct app_unreg_args {
esp_gatt_if_t gatts_if;
} app_unreg;
//BTC_GATTS_ACT_CREATE_SERVICE,
struct create_srvc_args {
esp_gatt_if_t gatts_if;
esp_gatt_srvc_id_t service_id;
uint16_t num_handle;
} create_srvc;
//BTC_GATTS_ACT_CREATE_ATTR_TAB
struct create_attr_tab_args{
esp_gatt_if_t gatts_if;
uint8_t srvc_inst_id;
uint16_t max_nb_attr;
esp_gatts_attr_db_t *gatts_attr_db;
}create_attr_tab;
//BTC_GATTS_ACT_DELETE_SERVICE,
struct delete_srvc_args {
uint16_t service_handle;
} delete_srvc;
//BTC_GATTS_ACT_START_SERVICE,
struct start_srvc_args {
uint16_t service_handle;
} start_srvc;
//BTC_GATTS_ACT_STOP_SERVICE,
struct stop_srvc_args {
uint16_t service_handle;
} stop_srvc;
//BTC_GATTS_ACT_ADD_INCLUDE_SERVICE,
struct add_incl_srvc_args {
uint16_t service_handle;
uint16_t included_service_handle;
} add_incl_srvc;
//BTC_GATTS_ACT_ADD_CHAR,
struct add_char_args {
uint16_t service_handle;
esp_bt_uuid_t char_uuid;
esp_gatt_perm_t perm;
esp_gatt_char_prop_t property;
esp_attr_control_t attr_control;
esp_attr_value_t char_val;
} add_char;
//BTC_GATTS_ACT_ADD_CHAR_DESCR,
struct add_descr_args {
uint16_t service_handle;
esp_bt_uuid_t descr_uuid;
esp_gatt_perm_t perm;
esp_attr_control_t attr_control;
esp_attr_value_t descr_val;
} add_descr;
//BTC_GATTS_ACT_SEND_INDICATE,
struct send_indicate_args {
uint16_t conn_id;
uint16_t attr_handle;
bool need_confirm;
uint16_t value_len;
uint8_t *value;
} send_ind;
//BTC_GATTS_ACT_SEND_RESPONSE,
struct send_rsp_args {
uint16_t conn_id;
uint32_t trans_id;
esp_gatt_status_t status;
esp_gatt_rsp_t *rsp;
} send_rsp;
//BTC_GATTS_SET_ATTR_VALUE
struct set_attr_val_args {
uint16_t handle;
uint16_t length;
uint8_t *value;
} set_attr_val;
//BTC_GATTS_ACT_OPEN,
struct open_args {
esp_gatt_if_t gatts_if;
esp_bd_addr_t remote_bda;
bool is_direct;
} open;
//BTC_GATTS_ACT_CLOSE,
struct close_args {
uint16_t conn_id;
} close;
//BTC_GATTS_ACT_SEND_SERVICE_CHANGE,
struct send_service_change_args {
esp_gatt_if_t gatts_if;
esp_bd_addr_t remote_bda;
} send_service_change;
} btc_ble_gatts_args_t;
typedef struct {
future_t *complete_future;
uint16_t svc_start_hdl;
esp_bt_uuid_t svc_uuid;
bool is_tab_creat_svc;
bool is_use_svc;
uint16_t num_handle;
uint16_t handle_idx;
uint16_t handles[ESP_GATT_ATTR_HANDLE_MAX];
} esp_btc_creat_tab_t;
#if GATT_DYNAMIC_MEMORY == TRUE
extern esp_btc_creat_tab_t *btc_creat_tab_env_ptr;
#define btc_creat_tab_env (*btc_creat_tab_env_ptr)
#endif
void btc_gatts_call_handler(btc_msg_t *msg);
void btc_gatts_cb_handler(btc_msg_t *msg);
void btc_gatts_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src);
void btc_gatts_arg_deep_free(btc_msg_t *msg);
esp_gatt_status_t btc_gatts_get_attr_value(uint16_t attr_handle, uint16_t *length, uint8_t **value);
esp_gatt_status_t btc_gatts_show_local_database(void);
#endif /* __BTC_GATTS_H__ */
@@ -0,0 +1,112 @@
/******************************************************************************
*
* Copyright (C) 2016 The Android Open Source Project
* Copyright (C) 2009-2012 Broadcom Corporation
* Copyright (C) 2019 Blake Felt
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
#ifndef BTC_HD_H
#define BTC_HD_H
#if BTC_HD_INCLUDED == TRUE
#include <stdint.h>
#include "bta/bta_hd_api.h"
#include "btc/btc_task.h"
#include "esp_hidd_api.h"
typedef enum {
BTC_HD_INIT_EVT = 0,
BTC_HD_DEINIT_EVT,
BTC_HD_REGISTER_APP_EVT,
BTC_HD_UNREGISTER_APP_EVT,
BTC_HD_CONNECT_EVT,
BTC_HD_DISCONNECT_EVT,
BTC_HD_SEND_REPORT_EVT,
BTC_HD_REPORT_ERROR_EVT,
BTC_HD_UNPLUG_EVT,
} BTC_HD_EVT;
typedef enum {
BTC_HD_DISABLED = 0,
BTC_HD_ENABLED,
BTC_HD_DISABLING,
BTC_HD_CONNECTING,
BTC_HD_CONNECTED,
BTC_HD_DISCONNECTING,
BTC_HD_DISCONNECTED,
} BTC_HD_STATUS;
/* BTIF-HD control block */
typedef struct {
BTC_HD_STATUS status;
bool app_registered;
bool service_dereg_active;
bool forced_disc;
tBTA_HD_APP_INFO app_info;
tBTA_HD_QOS_INFO in_qos;
tBTA_HD_QOS_INFO out_qos;
} btc_hd_cb_t;
/* btc_hidd_args_t */
typedef union {
// BTC_HD_CONNECT_EVT
struct hd_connect_arg {
BD_ADDR bd_addr;
} connect;
// BTC_HD_REGISTER_APP_EVT
struct register_app_arg {
esp_hidd_app_param_t *app_param;
esp_hidd_qos_param_t *in_qos;
esp_hidd_qos_param_t *out_qos;
} register_app;
// BTC_HD_SEND_REPORT_EVT
struct send_report_arg {
esp_hidd_report_type_t type;
uint8_t id;
uint16_t len;
uint8_t *data;
} send_report;
// BTC_HD_REPORT_ERROR_EVT
uint8_t error;
} btc_hidd_args_t;
#ifdef __cplusplus
extern "C" {
#endif
/******************************************************************************
* Functions
******************************************************************************/
void btc_hd_call_handler(btc_msg_t *msg);
void btc_hd_cb_handler(btc_msg_t *msg);
// extern btc_hd_cb_t btc_hd_cb;
// extern void btc_hd_remove_device(bt_bdaddr_t bd_addr);
// extern void btc_hd_service_registration();
void btc_hd_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src);
void btc_hd_cb_arg_deep_free(btc_msg_t *msg);
#ifdef __cplusplus
}
#endif
#endif /* BTC_HD_INCLUDED == TRUE */
#endif /* BTC_HD_H */
@@ -0,0 +1,255 @@
/*
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/*******************************************************************************
*
* Filename: btc_hf_ag.h
*
* Description: Main API header file for all BTC HF AG functions accessed
* from internal stack.
*
*******************************************************************************/
#ifndef __BTC_HF_AG_H__
#define __BTC_HF_AG_H__
#include "common/bt_target.h"
#include "btc/btc_task.h"
#include "btc/btc_common.h"
#include "bta/bta_ag_api.h"
#include "esp_hf_ag_api.h"
#if (BTC_HF_INCLUDED == TRUE)
/*******************************************************************************
** Type Defs
********************************************************************************/
/* btc_hf_act_t */
typedef enum
{
//INIT
BTC_HF_INIT_EVT,
BTC_HF_DEINIT_EVT,
BTC_HF_CONNECT_EVT,
BTC_HF_DISCONNECT_EVT,
BTC_HF_CONNECT_AUDIO_EVT,
BTC_HF_DISCONNECT_AUDIO_EVT,
BTC_HF_VRA_EVT,
BTC_HF_VOLUME_CONTROL_EVT,
//AT_RESPONSE
BTC_HF_UNAT_RESPONSE_EVT,
BTC_HF_CME_ERR_EVT,
BTC_HF_IND_NOTIFICATION_EVT,
BTC_HF_CIEV_REPORT_EVT,
BTC_HF_CIND_RESPONSE_EVT,
BTC_HF_COPS_RESPONSE_EVT,
BTC_HF_CLCC_RESPONSE_EVT,
BTC_HF_CNUM_RESPONSE_EVT,
BTC_HF_INBAND_RING_EVT,
//CALL_HANDLE
BTC_HF_AC_INCALL_EVT,
BTC_HF_RJ_INCALL_EVT,
BTC_HF_OUT_CALL_EVT,
BTC_HF_END_CALL_EVT,
//REG
BTC_HF_REGISTER_DATA_CALLBACK_EVT,
BTC_HF_REQUEST_PKT_STAT_EVT
} btc_hf_act_t;
/* btc_hf_args_t */
typedef union
{
// BTC_HF_CONNECT_EVT
bt_bdaddr_t connect;
// BTC_HF_DISCONNECT_EVT
bt_bdaddr_t disconnect;
// BTC_HF_CONNECT_AUDIO_EVT
bt_bdaddr_t connect_audio;
// BTC_HF_DISCONNECT_AUDIO_EVT
bt_bdaddr_t disconnect_audio;
//BTC_HF_VRA_EVT
struct vra_param {
bt_bdaddr_t remote_addr;
esp_hf_vr_state_t value;
} vra_rep;
// BTC_HF_VOLUME_CONTROL_EVT
struct volcon_args {
bt_bdaddr_t remote_addr;
esp_hf_volume_control_target_t target_type;
int volume;
} volcon;
//BTC_HF_UNAT_RESPONSE_EVT
struct unat_param {
bt_bdaddr_t remote_addr;
char *unat;
} unat_rep;
//BTC_HF_CME_ERR_EVT
struct at_ok_err_args {
bt_bdaddr_t remote_addr;
esp_hf_at_response_code_t response_code;
esp_hf_cme_err_t error_code;
} ext_at;
// BTC_HF_IND_NOTIFICATION_EVT
struct indchange_status {
bt_bdaddr_t remote_addr;
esp_hf_call_status_t call_state;
esp_hf_call_setup_status_t call_setup_state;
esp_hf_network_state_t ntk_state;
int signal;
} ind_change;
//BTC_HF_CIEV_REPORT_EVT
struct ciev_args {
bt_bdaddr_t remote_addr;
tBTA_AG_IND ind;
} ciev_rep;
//BTC_HF_CIND_RESPONSE_EVT
struct cind_args {
bt_bdaddr_t remote_addr;
esp_hf_call_status_t call_state;
esp_hf_call_setup_status_t call_setup_state;
esp_hf_network_state_t ntk_state;
int signal;
esp_hf_roaming_status_t roam;
int batt_lev;
esp_hf_call_held_status_t call_held_state;
} cind_rep;
//BTC_HF_COPS_RESPONSE_EVT
struct cops_args {
bt_bdaddr_t remote_addr;
char *name;
} cops_rep;
// BTC_HF_CLCC_RESPONSE_EVT
struct clcc_args {
bt_bdaddr_t remote_addr;
int index;
esp_hf_current_call_direction_t dir;
esp_hf_current_call_status_t current_call_state;
esp_hf_current_call_mode_t mode;
esp_hf_current_call_mpty_type_t mpty;
char *number;
esp_hf_call_addr_type_t type;
} clcc_rep;
// BTC_HF_CNUM_RESPONSE_EVT
struct cnum_args {
bt_bdaddr_t remote_addr;
char *number;
int number_type;
esp_hf_subscriber_service_type_t service_type;
} cnum_rep;
//BTC_HF_NREC_RESPONSE_EVT
bt_bdaddr_t nrec_rep;
//BTC_HF_VTC_RESPONSE_EVT
struct bts_args {
bt_bdaddr_t remote_addr;
char *code;
} vts_rep;
//BTC_HF_INBAND_RING_EVT
struct bsir_args {
bt_bdaddr_t remote_addr;
esp_hf_in_band_ring_state_t state;
} bsir;
// BTC_HF_AC_INCALL_EVT
// BTC_HF_RJ_INCALL_EVT
// BTC_HF_OUT_CALL_EVT
// BTC_HF_END_CALL_EVT
struct phone_args {
bt_bdaddr_t remote_addr;
int num_active;
int num_held;
esp_hf_call_status_t call_state;
esp_hf_call_setup_status_t call_setup_state;
char *number;
esp_hf_call_addr_type_t call_addr_type;
} phone;
// BTC_HF_REGISTER_DATA_CALLBACK_EVT
struct ag_reg_data_callback {
esp_hf_incoming_data_cb_t recv;
esp_hf_outgoing_data_cb_t send;
} reg_data_cb;
// BTC_HF_REQUEST_PKT_STAT_EVT
struct ag_req_pkt_stat_sync_handle {
UINT16 sync_conn_handle;
} pkt_sync_hd;
} btc_hf_args_t;
/************************************************************************************
** Local definitions
************************************************************************************/
/* Number of BTC-HF-AG control blocks */
#define BTC_HF_NUM_CB 1
/* Handsfree AG app ids for service registration */
/* APP ID definition*/
#define BTC_HF_ID_1 0
/* BTC-AG control block to map bdaddr to BTA handle */
typedef struct
{
bool initialized;
UINT16 handle;
bt_bdaddr_t connected_bda;
tBTA_AG_PEER_FEAT peer_feat;
tBTA_AG_CHLD_FEAT chld_feat;
struct timespec call_end_timestamp;
struct timespec connected_timestamp;
esp_hf_connection_state_t connection_state;
esp_hf_vr_state_t vr_state;
int num_active;
int num_held;
esp_hf_call_status_t call_state;
esp_hf_call_setup_status_t call_setup_state;
} btc_hf_cb_t;
typedef struct
{
int hf_idx;
UINT32 btc_hf_features;
btc_hf_cb_t btc_hf_cb;
esp_hf_incoming_data_cb_t btc_hf_incoming_data_cb;
esp_hf_outgoing_data_cb_t btc_hf_outgoing_data_cb;
} hf_local_param_t;
/*******************************************************************************
** BTC HF AG Handle Hub
********************************************************************************/
void btc_hf_call_handler(btc_msg_t *msg); // act the cmd from esp-application
void btc_hf_cb_handler(btc_msg_t *msg); //handle the event from bta
void btc_hf_incoming_data_cb_to_app(const uint8_t *data, uint32_t len);
uint32_t btc_hf_outgoing_data_cb_to_app(uint8_t *data, uint32_t len);
void btc_hf_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src);
void btc_hf_arg_deep_free(btc_msg_t *msg);
bt_status_t btc_hf_ci_sco_data(void);
#endif // BTC_HF_INCLUDED == TRUE
#endif /* __BTC_HF_AG_H__ */
@@ -0,0 +1,170 @@
/*
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/*******************************************************************************
*
* Filename: btc_hf_client.h
*
* Description: Main API header file for all BTC HF client functions accessed
* from internal stack.
*
*******************************************************************************/
#ifndef __BTC_HF_CLIENT_H__
#define __BTC_HF_CLIENT_H__
#include "common/bt_target.h"
#include "esp_hf_client_api.h"
#include "btc/btc_task.h"
#include "btc/btc_common.h"
#include "bta/bta_hf_client_api.h"
#if (BTC_HF_CLIENT_INCLUDED == TRUE)
/*******************************************************************************
** Type definitions for callback functions
********************************************************************************/
typedef enum {
BTC_HF_CLIENT_INIT_EVT,
BTC_HF_CLIENT_DEINIT_EVT,
BTC_HF_CLIENT_CONNECT_EVT,
BTC_HF_CLIENT_DISCONNECT_EVT,
BTC_HF_CLIENT_CONNECT_AUDIO_EVT,
BTC_HF_CLIENT_DISCONNECT_AUDIO_EVT,
BTC_HF_CLIENT_START_VOICE_RECOGNITION_EVT,
BTC_HF_CLIENT_STOP_VOICE_RECOGNITION_EVT,
BTC_HF_CLIENT_VOLUME_UPDATE_EVT,
BTC_HF_CLIENT_DIAL_EVT,
BTC_HF_CLIENT_DIAL_MEMORY_EVT,
BTC_HF_CLIENT_SEND_CHLD_CMD_EVT,
BTC_HF_CLIENT_SEND_BTRH_CMD_EVT,
BTC_HF_CLIENT_ANSWER_CALL_EVT,
BTC_HF_CLIENT_REJECT_CALL_EVT,
BTC_HF_CLIENT_QUERY_CURRENT_CALLS_EVT,
BTC_HF_CLIENT_QUERY_CURRENT_OPERATOR_NAME_EVT,
BTC_HF_CLIENT_RETRIEVE_SUBSCRIBER_INFO_EVT,
BTC_HF_CLIENT_SEND_DTMF_EVT,
BTC_HF_CLIENT_REQUEST_LAST_VOICE_TAG_NUMBER_EVT,
BTC_HF_CLIENT_REGISTER_DATA_CALLBACK_EVT,
BTC_HF_CLIENT_SEND_NREC_EVT,
BTC_HF_CLIENT_SEND_XAPL_EVT,
BTC_HF_CLIENT_SEND_IPHONEACCEV_EVT,
BTC_HF_CLIENT_REQUEST_PKT_STAT_EVT,
} btc_hf_client_act_t;
/* btc_hf_client_args_t */
typedef union {
// BTC_HF_CLIENT_CONNECT_EVT
bt_bdaddr_t connect;
// BTC_HF_CLIENT_DISCONNECT_EVT
bt_bdaddr_t disconnect;
// BTC_HF_CLIENT_CONNECT_AUDIO_EVT
bt_bdaddr_t connect_audio;
// BTC_HF_CLIENT_DISCONNECT_AUDIO_EVT
bt_bdaddr_t disconnect_audio;
// BTC_HF_CLIENT_VOLUME_UPDATE_EVT,
struct volume_update_args {
esp_hf_volume_control_target_t type;
int volume;
} volume_update;
// BTC_HF_CLIENT_DIAL_EVT
struct dial_args {
char number[ESP_BT_HF_CLIENT_NUMBER_LEN + 1];
} dial;
// BTC_HF_CLIENT_DIAL_MEMORY_EVT
struct dial_memory_args {
int location;
} dial_memory;
// BTC_HF_CLIENT_SEND_CHLD_CMD_EVT
struct send_chld_cmd_args {
esp_hf_chld_type_t type;
int idx;
} chld;
// BTC_HF_CLIENT_SEND_BTRH_CMD_EVT
struct send_btrh_cmd_args {
esp_hf_btrh_cmd_t cmd;
} btrh;
// BTC_HF_CLIENT_SEND_DTMF_EVT
struct send_dtmf {
char code;
} send_dtmf;
// BTC_HF_CLIENT_REGISTER_DATA_CALLBACK_EVT
struct hf_client_reg_data_callback {
esp_hf_client_incoming_data_cb_t recv;
esp_hf_client_outgoing_data_cb_t send;
} reg_data_cb;
//BTC_HF_CLIENT_SEND_XAPL_EVT
struct send_xapl_args {
char information[ESP_BT_HF_AT_SEND_XAPL_LEN + 1];
uint32_t features;
} send_xapl;
// BTC_HF_CLIENT_SEND_IPHONEACCEV_EVT
struct send_iphoneaccev_args {
uint32_t bat_level;
bool docked;
} send_iphoneaccev;
// BTC_HF_CLIENT_REQUEST_PKT_STAT_EVT
struct hf_client_req_pkt_stat_sync_handle {
UINT16 sync_conn_handle;
} pkt_sync_hd;
} btc_hf_client_args_t;
/************************************************************************************
** Local type definitions
************************************************************************************/
/* BTC-HF control block to map bdaddr to BTA handle */
typedef struct
{
bool initialized;
UINT16 handle;
bt_bdaddr_t connected_bda;
esp_hf_client_connection_state_t state;
esp_hf_vr_state_t vr_state;
tBTA_HF_CLIENT_PEER_FEAT peer_feat;
tBTA_HF_CLIENT_CHLD_FEAT chld_feat;
} btc_hf_client_cb_t;
typedef struct
{
UINT32 btc_hf_client_features;
btc_hf_client_cb_t btc_hf_client_cb;
esp_hf_client_incoming_data_cb_t btc_hf_client_incoming_data_cb;
esp_hf_client_outgoing_data_cb_t btc_hf_client_outgoing_data_cb;
}hf_client_local_param_t;
#if HFP_DYNAMIC_MEMORY == TRUE
extern hf_client_local_param_t *hf_client_local_param_ptr;
#define hf_client_local_param (*hf_client_local_param_ptr)
#endif
/*******************************************************************************
** BTC HF AG API
********************************************************************************/
void btc_hf_client_call_handler(btc_msg_t *msg);
void btc_hf_client_cb_handler(btc_msg_t *msg);
void btc_hf_client_incoming_data_cb_to_app(const uint8_t *data, uint32_t len);
uint32_t btc_hf_client_outgoing_data_cb_to_app(uint8_t *data, uint32_t len);
#endif ///BTC_HF_CLIENT_INCLUDED == TRUE
#endif /* __BTC_HF_CLIENT_H__ */
@@ -0,0 +1,189 @@
/******************************************************************************
*
* Copyright (C) 2016 The Android Open Source Project
* Copyright (C) 2009-2012 Broadcom Corporation
* Copyright (C) 2019 Blake Felt
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
#ifndef BTC_HH_H
#define BTC_HH_H
#include <stdint.h>
#include "bta/bta_hh_api.h"
#include "btc/btc_task.h"
#include "osi/alarm.h"
#include "esp_hidh_api.h"
#define BTC_HH_MAX_HID 8
#define BTC_HH_MAX_ADDED_DEV 32
#define BTC_HH_MAX_KEYSTATES 3
#define BTC_HH_KEYSTATE_MASK_NUMLOCK 0x01
#define BTC_HH_KEYSTATE_MASK_CAPSLOCK 0x02
#define BTC_HH_KEYSTATE_MASK_SCROLLLOCK 0x04
#define BTC_HH_MAX_POLLING_ATTEMPTS 10
#define BTC_HH_POLLING_SLEEP_DURATION_US 5000
/*******************************************************************************
* Type definitions and return values
******************************************************************************/
typedef enum {
BTC_HH_INIT_EVT = 0,
BTC_HH_CONNECT_EVT,
BTC_HH_DISCONNECT_EVT,
BTC_HH_UNPLUG_EVT,
BTC_HH_SET_INFO_EVT,
BTC_HH_GET_PROTO_EVT,
BTC_HH_SET_PROTO_EVT,
BTC_HH_GET_IDLE_EVT,
BTC_HH_SET_IDLE_EVT,
BTC_HH_GET_REPORT_EVT,
BTC_HH_SET_REPORT_EVT,
BTC_HH_SEND_DATA_EVT,
BTC_HH_DEINIT_EVT,
} BTC_HH_EVT;
typedef enum {
BTC_HH_DISABLED = 0,
BTC_HH_ENABLED,
BTC_HH_DISABLING,
BTC_HH_DEV_UNKNOWN,
BTC_HH_DEV_CONNECTING,
BTC_HH_DEV_CONNECTED,
BTC_HH_DEV_DISCONNECTED
} BTC_HH_STATUS;
typedef struct {
esp_hidh_connection_state_t dev_status;
uint8_t dev_handle;
BD_ADDR bd_addr;
uint16_t attr_mask;
uint8_t sub_class;
uint8_t app_id;
bool ready_for_data;
osi_alarm_t *vup_timer;
bool local_vup; // Indicated locally initiated VUP
} btc_hh_device_t;
/* Control block to maintain properties of devices */
typedef struct {
uint8_t dev_handle;
BD_ADDR bd_addr;
uint16_t attr_mask;
} btc_hh_added_device_t;
/**
* BTC-HH control block to maintain added devices and currently
* connected hid devices
*/
typedef struct {
BTC_HH_STATUS status;
btc_hh_device_t devices[BTC_HH_MAX_HID];
uint32_t device_num;
BTC_HH_EVT add_event;
btc_hh_added_device_t added_devices[BTC_HH_MAX_ADDED_DEV];
btc_hh_device_t *p_curr_dev;
bool service_dereg_active;
BD_ADDR pending_conn_address;
} btc_hh_cb_t;
/* btc_spp_args_t */
typedef union {
// BTC_HH_CONNECT_EVT
struct hh_connect_arg {
BD_ADDR bd_addr;
} connect;
// BTC_HH_DISCONNECT_EVT
struct disconnect_arg {
BD_ADDR bd_addr;
} disconnect;
// BTC_HH_UNPLUG_EVT
struct unplug_arg {
BD_ADDR bd_addr;
} unplug;
// BTC_HH_SET_INFO_EVT
struct set_info_arg {
BD_ADDR bd_addr;
esp_hidh_hid_info_t *hid_info;
} set_info;
// BTC_HH_GET_PROTO_EVT
struct get_protocol_arg {
BD_ADDR bd_addr;
} get_protocol;
// BTC_HH_SET_PROTO_EVT
struct set_protocol_arg {
BD_ADDR bd_addr;
esp_hidh_protocol_mode_t protocol_mode;
} set_protocol;
// BTC_HH_GET_IDLE_EVT
struct get_idle_arg {
BD_ADDR bd_addr;
} get_idle;
// BTC_HH_SET_IDLE_EVT
struct set_idle_arg {
BD_ADDR bd_addr;
uint16_t idle_time;
} set_idle;
// BTC_HH_GET_REPORT_EVT
struct get_report_arg {
BD_ADDR bd_addr;
esp_hidh_report_type_t report_type;
uint8_t report_id;
int buffer_size;
} get_report;
// BTC_HH_SET_REPORT_EVT
struct set_report_arg {
BD_ADDR bd_addr;
esp_hidh_report_type_t report_type;
size_t len;
uint8_t *report;
} set_report;
// BTC_HH_SEND_DATA_EVT
struct send_data_arg {
BD_ADDR bd_addr;
size_t len;
uint8_t *data;
} send_data;
} btc_hidh_args_t;
/*******************************************************************************
* Variables
******************************************************************************/
extern btc_hh_cb_t btc_hh_cb;
/*******************************************************************************
* Functions
******************************************************************************/
void btc_hh_call_handler(btc_msg_t *msg);
void btc_hh_cb_handler(btc_msg_t *msg);
void btc_hh_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src);
void btc_hh_cb_arg_deep_free(btc_msg_t *msg);
bool btc_hh_add_added_dev(BD_ADDR bd_addr, uint16_t attr_mask);
#endif /* BTC_HH_H */
@@ -0,0 +1,72 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __BTC_L2CAP_H__
#define __BTC_L2CAP_H__
#include "btc/btc_task.h"
#include "esp_bt_defs.h"
#include "esp_l2cap_bt_api.h"
#include "common/bt_target.h"
#include "bta/bta_jv_api.h"
#if (defined BTC_L2CAP_INCLUDED && BTC_L2CAP_INCLUDED == TRUE)
#define BTC_L2CAP_INVALID_PSM 0x00
typedef enum {
BTC_L2CAP_ACT_INIT = 0,
BTC_L2CAP_ACT_UNINIT,
BTC_L2CAP_ACT_START_DISCOVERY,
BTC_L2CAP_ACT_CONNECT,
BTC_L2CAP_ACT_START_SRV,
BTC_L2CAP_ACT_STOP_SRV,
} btc_l2cap_act_t;
/* btc_l2cap_args_t */
typedef union {
//BTC_L2CAP_ACT_INIT
struct l2cap_init_arg {
} init;
//BTC_L2CAP_ACT_UNINIT
struct l2cap_uninit_arg {
} uninit;
//BTC_L2CAP_ACT_START_DISCOVERY
struct l2cap_start_discovery_arg {
BD_ADDR bd_addr;
UINT16 num_uuid;
tSDP_UUID *p_uuid_list;
} start_discovery;
//BTC_L2CAP_ACT_CONNECT
struct l2cap_connect_arg {
UINT16 sec_mask;
UINT16 remote_psm;
esp_bd_addr_t peer_bd_addr;
} connect;
//BTC_L2CAP_ACT_START_SRV
struct l2cap_start_srv_arg {
UINT16 sec_mask;
UINT16 local_psm;
} start_srv;
//BTC_L2CAP_ACT_STOP_SRV
struct l2cap_stop_srv_arg {
UINT16 psm;
} stop_srv;
} btc_l2cap_args_t;
void btc_l2cap_call_handler(btc_msg_t *msg);
void btc_l2cap_cb_handler(btc_msg_t *msg);
esp_err_t btc_l2cap_vfs_register(void);
esp_err_t btc_l2cap_vfs_unregister(void);
#endif ///defined BTC_L2CAP_INCLUDED && BTC_L2CAP_INCLUDED == TRUE
#endif ///__BTC_L2CAP_H__
@@ -0,0 +1,53 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __BTC_SDP_H__
#define __BTC_SDP_H__
#include "btc/btc_task.h"
#include "esp_bt_defs.h"
#include "common/bt_target.h"
#include "bta/bta_sdp_api.h"
#include "bt_sdp.h"
#if (defined BTC_SDP_INCLUDED && BTC_SDP_INCLUDED == TRUE)
typedef enum {
BTC_SDP_ACT_INIT = 0,
BTC_SDP_ACT_DEINIT,
BTC_SDP_ACT_SEARCH,
BTC_SDP_ACT_CREATE_RECORD,
BTC_SDP_ACT_REMOVE_RECORD,
} btc_sdp_act_t;
/* btc_sdp_args_t */
typedef union {
//BTC_SDP_ACT_SEARCH
struct search_record_arg {
BD_ADDR bd_addr;
tSDP_UUID sdp_uuid;
} search;
//BTC_SDP_ACT_CREATE_RECORD
struct creat_record_arg {
bluetooth_sdp_record *record;
} creat_record;
//BTC_SDP_ACT_REMOVE_RECORD
struct remove_record_arg {
int record_handle;
} remove_record;
} btc_sdp_args_t;
void btc_sdp_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src);
void btc_sdp_arg_deep_free(btc_msg_t *msg);
void btc_sdp_call_handler(btc_msg_t *msg);
void btc_sdp_cb_handler(btc_msg_t *msg);
#endif ///defined BTC_SDP_INCLUDED && BTC_SDP_INCLUDED == TRUE
#endif ///__BTC_SDP_H__
@@ -0,0 +1,94 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __BTC_SPP_H__
#define __BTC_SPP_H__
#include "btc/btc_task.h"
#include "esp_bt_defs.h"
#include "esp_spp_api.h"
#include "common/bt_target.h"
#include "bta/bta_jv_api.h"
#if (defined BTC_SPP_INCLUDED && BTC_SPP_INCLUDED == TRUE)
#define ESP_SPP_MAX_SESSION BTA_JV_MAX_RFC_SR_SESSION
#define ESP_SPP_SERVER_NAME_MAX 32
#define BTC_SPP_INVALID_SCN 0x00
typedef enum {
BTC_SPP_ACT_INIT = 0,
BTC_SPP_ACT_UNINIT,
BTC_SPP_ACT_START_DISCOVERY,
BTC_SPP_ACT_CONNECT,
BTC_SPP_ACT_DISCONNECT,
BTC_SPP_ACT_START_SRV,
BTC_SPP_ACT_STOP_SRV,
BTC_SPP_ACT_WRITE,
BTC_SPP_ACT_VFS_REGISTER,
BTC_SPP_ACT_VFS_UNREGISTER,
} btc_spp_act_t;
/* btc_spp_args_t */
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 {
} uninit;
//BTC_SPP_ACT_START_DISCOVERY
struct start_discovery_arg {
BD_ADDR bd_addr;
UINT16 num_uuid;
tSDP_UUID *p_uuid_list;
} start_discovery;
//BTC_SPP_ACT_CONNECT
struct conn_arg {
esp_spp_sec_t sec_mask;
esp_spp_role_t role;
UINT8 remote_scn;
esp_bd_addr_t peer_bd_addr;
} connect;
//BTC_SPP_ACT_DISCONNECT
struct disconn_arg {
UINT32 handle;
} disconnect;
//BTC_SPP_ACT_START_SRV
struct start_srv_arg {
esp_spp_sec_t sec_mask;
esp_spp_role_t role;
UINT8 local_scn;
UINT8 max_session;
char name[ESP_SPP_SERVER_NAME_MAX + 1];
} start_srv;
//BTC_SPP_ACT_STOP_SRV
struct stop_srv_arg {
UINT8 scn;
} stop_srv;
//BTC_SPP_ACT_WRITE
struct write_arg {
UINT32 handle;
int len;
UINT8 *p_data;
} write;
} btc_spp_args_t;
void btc_spp_call_handler(btc_msg_t *msg);
void btc_spp_cb_handler(btc_msg_t *msg);
void btc_spp_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src);
void btc_spp_arg_deep_free(btc_msg_t *msg);
esp_err_t spp_send_data_to_btc(uint32_t handle, int len, uint8_t *p_data, esp_spp_mode_t spp_mode);
#endif ///defined BTC_SPP_INCLUDED && BTC_SPP_INCLUDED == TRUE
#endif ///__BTC_SPP_H__
@@ -0,0 +1,338 @@
/******************************************************************************
*
* Copyright (C) 1999-2013 Broadcom Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
/*******************************************************************************
**
** Header file for profile folder.
**
********************************************************************************/
#ifndef SRVC_DIS_API_H
#define SRVC_DIS_API_H
#include "common/bt_target.h"
#include "stack/gatt_api.h"
#include "stack/gattdefs.h"
#include "esp_gatts_api.h"
#define DIS_SUCCESS GATT_SUCCESS
#define DIS_ILLEGAL_PARAM GATT_ILLEGAL_PARAMETER
#define DIS_NO_RESOURCES GATT_NO_RESOURCES
typedef UINT8 tDIS_STATUS;
/*****************************************************************************
** Data structure for DIS
*****************************************************************************/
#define DIS_ATTR_SYS_ID_BIT 0x0001
#define DIS_ATTR_MODEL_NUM_BIT 0x0002
#define DIS_ATTR_SERIAL_NUM_BIT 0x0004
#define DIS_ATTR_FW_NUM_BIT 0x0008
#define DIS_ATTR_HW_NUM_BIT 0x0010
#define DIS_ATTR_SW_NUM_BIT 0x0020
#define DIS_ATTR_MANU_NAME_BIT 0x0040
#define DIS_ATTR_IEEE_DATA_BIT 0x0080
#define DIS_ATTR_PNP_ID_BIT 0x0100
typedef UINT16 tDIS_ATTR_MASK;
#define DIS_ATTR_ALL_MASK 0xffff
typedef tDIS_ATTR_MASK tDIS_ATTR_BIT ;
#define DIS_MAX_NUM_INC_SVR 0
#define DIS_MAX_CHAR_NUM 9
#define DIS_MAX_ATTR_NUM (DIS_MAX_CHAR_NUM * 2 + DIS_MAX_NUM_INC_SVR + 1)
#ifndef DIS_ATTR_DB_SIZE
#define DIS_ATTR_DB_SIZE GATT_DB_MEM_SIZE(DIS_MAX_NUM_INC_SVR, DIS_MAX_CHAR_NUM, 0)
#endif
#define DIS_SYSTEM_ID_SIZE 8
#define DIS_PNP_ID_SIZE 7
typedef struct {
UINT16 uuid;
UINT16 handle;
} tDIS_DB_ENTRY;
typedef struct {
UINT16 len;
UINT8 *p_data;
} tDIS_STRING;
typedef struct {
UINT16 vendor_id;
UINT16 product_id;
UINT16 product_version;
UINT8 vendor_id_src;
} tDIS_PNP_ID;
typedef union {
UINT64 system_id;
tDIS_PNP_ID pnp_id;
tDIS_STRING data_str;
} tDIS_ATTR;
#define DIS_MAX_STRING_DATA 7
typedef struct {
UINT16 attr_mask;
UINT64 system_id;
tDIS_PNP_ID pnp_id;
UINT8 *data_string[DIS_MAX_STRING_DATA];
} tDIS_VALUE;
//typedef void (tDIS_READ_CBACK)(BD_ADDR addr, tDIS_VALUE *p_dis_value);
typedef struct {
tDIS_DB_ENTRY dis_attr[DIS_MAX_CHAR_NUM];
tDIS_VALUE dis_value;
// tDIS_READ_CBACK *p_read_dis_cback;
UINT16 service_handle;
UINT16 max_handle;
bool enabled;
// UINT8 dis_read_uuid_idx;
// tDIS_ATTR_MASK request_mask;
} tDIS_CB;
/*****************************************************************************
** Data structure used by Battery Service
*****************************************************************************/
#ifndef BA_MAX_INT_NUM
#define BA_MAX_INT_NUM 4
#endif
#define BATTERY_LEVEL_SIZE 1
typedef struct {
BD_ADDR remote_bda;
BOOLEAN need_rsp;
UINT16 clt_cfg;
} tBA_WRITE_DATA;
#define BA_READ_CLT_CFG_REQ 1
#define BA_READ_PRE_FMT_REQ 2
#define BA_READ_RPT_REF_REQ 3
#define BA_READ_LEVEL_REQ 4
#define BA_WRITE_CLT_CFG_REQ 5
typedef void (tBA_CBACK)(UINT32 trans_id, UINT16 conn_id, UINT8 app_id, UINT8 event, tBA_WRITE_DATA *p_data);
#define BA_LEVEL_NOTIFY 0x01
#define BA_LEVEL_PRE_FMT 0x02
#define BA_LEVEL_RPT_REF 0x04
typedef UINT8 tBA_LEVEL_DESCR;
typedef struct {
BOOLEAN is_pri;
tBA_LEVEL_DESCR ba_level_descr;
tGATT_TRANSPORT transport;
tBA_CBACK *p_cback;
} tBA_REG_INFO;
typedef union {
UINT8 ba_level;
UINT16 clt_cfg;
tGATT_CHAR_RPT_REF rpt_ref;
tGATT_CHAR_PRES pres_fmt;
} tBA_RSP_DATA;
typedef struct {
UINT8 app_id;
UINT16 ba_level_hdl;
UINT16 clt_cfg_hdl;
UINT16 rpt_ref_hdl;
UINT16 pres_fmt_hdl;
tBA_CBACK *p_cback;
UINT16 pending_handle;
//UINT8 pending_clcb_idx;
UINT8 pending_evt;
} tBA_INST;
typedef struct {
tBA_INST battery_inst[BA_MAX_INT_NUM];
UINT8 inst_id;
bool enabled;
} tBATTERY_CB;
/*****************************************************************************
** External Function Declarations
*****************************************************************************/
#ifdef __cplusplus
extern "C"
{
#endif
/*****************************************************************************
** Service Engine API
*****************************************************************************/
/*******************************************************************************
**
** Function srvc_eng_init
**
** Description Initializa the GATT Service engine, register a GATT application
** as for a central service management.
**
*******************************************************************************/
//extern tGATT_STATUS srvc_eng_init (void);
/*****************************************************************************
** DIS Server Function
*****************************************************************************/
extern bool dis_valid_handle_range(UINT16 handle);
/*******************************************************************************
**
** Function DIS_Init
**
** Description Initializa the Device Information Service Server.
**
*******************************************************************************/
extern void DIS_Init (tBTA_GATTS_IF gatt_if, tDIS_ATTR_MASK dis_attr_mask);
/*******************************************************************************
**
** Function DIS_SrUpdate
**
** Description Update the DIS server attribute values
**
*******************************************************************************/
extern tDIS_STATUS DIS_SrUpdate(tDIS_ATTR_BIT dis_attr_bit, tDIS_ATTR *p_info);
/*******************************************************************************
**
** Function dis_AddChar
**
** Description add characteristic for dis
**
*******************************************************************************/
extern void dis_AddChar(UINT16 service_id);
/*******************************************************************************
** dis_s_read_attr_value
**
** Process read DIS attribute request.
*******************************************************************************/
extern void dis_s_read_attr_value (tGATTS_DATA *p_data, tGATT_VALUE *p_value,
UINT32 trans_id, UINT16 conn_id);
/*****************************************************************************
** DIS Client Function
*****************************************************************************/
/*******************************************************************************
**
** Function DIS_ReadDISInfo
**
** Description Read remote device DIS information.
**
** Returns void
**
*******************************************************************************/
//extern BOOLEAN DIS_ReadDISInfo(BD_ADDR peer_bda, tDIS_READ_CBACK *p_cback,
// tDIS_ATTR_MASK mask);
/*******************************************************************************
** BATTERY SERVICE API
*******************************************************************************/
/***************************************************************
**
** Function bas_register
**
** Description register app for battery service
**
****************************************************************/
extern void bas_register(void);
/***************************************************************
**
** Function bas_init
**
** Description register battery service
**
****************************************************************/
extern void bas_init(tBTA_GATTS_IF gatt_if, UINT16 app_id);
/***************************************************************
**
** Function bas_AddChar
**
** Description add characteristic for battery service
**
****************************************************************/
extern void bas_AddChar(UINT16 service_id, tBT_UUID *char_uuid);
/***************************************************************
**
** Function bas_AddCharDescr
**
** Description add descriptor for battery service if needed
**
****************************************************************/
extern void bas_AddCharDescr(UINT16 service_id, UINT16 attr_id);
/***************************************************************
**
** Function bas_service_cmpl
**
** Description create battery service complete
**
****************************************************************/
extern void bas_service_cmpl(UINT16 service_id, tBTA_GATT_STATUS status);
/*******************************************************************************
**
** Function Battery_Rsp
**
** Description Respond to a battery service request
**
*******************************************************************************/
extern void Battery_Rsp (UINT32 trans_id, UINT16 conn_id, UINT8 app_id,
tGATT_STATUS st, UINT8 event, tBA_RSP_DATA *p_rsp);
/*******************************************************************************
**
** Function Battery_Notify
**
** Description Send battery level notification
**
*******************************************************************************/
extern void Battery_Notify (UINT16 conn_id, UINT8 app_id, BD_ADDR remote_bda, UINT8 battery_level);
/*****************************************************************************
** Function bas_s_read_attr_value
**
** Description it will be called when client send a read request
******************************************************************************/
extern void bas_s_read_attr_value(tGATTS_DATA *p_data, UINT32 trans_id, UINT16 conn_id);
/*****************************************************************************
** Function bas_s_write_attr_value
**
** Description it will be called when client send a write request
******************************************************************************/
extern void bas_s_write_attr_value(tGATTS_DATA *p_data, UINT32 trans_id,
UINT16 conn_id, BD_ADDR bd_addr);
extern void gatts_server_test(void);
#ifdef __cplusplus
}
#endif
#endif
@@ -0,0 +1,210 @@
/******************************************************************************
*
* Copyright (C) 1999-2013 Broadcom Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
#ifndef SRVC_DIS_API_H
#define SRVC_DIS_API_H
#include "common/bt_target.h"
#include "stack/gatt_api.h"
#include "stack/gattdefs.h"
#define DIS_SUCCESS GATT_SUCCESS
#define DIS_ILLEGAL_PARAM GATT_ILLEGAL_PARAMETER
#define DIS_NO_RESOURCES GATT_NO_RESOURCES
typedef UINT8 tDIS_STATUS;
/*****************************************************************************
** Data structure for DIS
*****************************************************************************/
#define DIS_ATTR_SYS_ID_BIT 0x0001
#define DIS_ATTR_MODEL_NUM_BIT 0x0002
#define DIS_ATTR_SERIAL_NUM_BIT 0x0004
#define DIS_ATTR_FW_NUM_BIT 0x0008
#define DIS_ATTR_HW_NUM_BIT 0x0010
#define DIS_ATTR_SW_NUM_BIT 0x0020
#define DIS_ATTR_MANU_NAME_BIT 0x0040
#define DIS_ATTR_IEEE_DATA_BIT 0x0080
#define DIS_ATTR_PNP_ID_BIT 0x0100
typedef UINT16 tDIS_ATTR_MASK;
#define DIS_ATTR_ALL_MASK 0xffff
typedef tDIS_ATTR_MASK tDIS_ATTR_BIT ;
typedef struct {
UINT16 len;
UINT8 *p_data;
} tDIS_STRING;
typedef struct {
UINT16 vendor_id;
UINT16 product_id;
UINT16 product_version;
UINT8 vendor_id_src;
} tDIS_PNP_ID;
typedef union {
UINT64 system_id;
tDIS_PNP_ID pnp_id;
tDIS_STRING data_str;
} tDIS_ATTR;
#define DIS_MAX_STRING_DATA 7
typedef struct {
UINT16 attr_mask;
UINT64 system_id;
tDIS_PNP_ID pnp_id;
UINT8 *data_string[DIS_MAX_STRING_DATA];
} tDIS_VALUE;
typedef void (tDIS_READ_CBACK)(BD_ADDR addr, tDIS_VALUE *p_dis_value);
/*****************************************************************************
** Data structure used by Battery Service
*****************************************************************************/
typedef struct {
BD_ADDR remote_bda;
BOOLEAN need_rsp;
UINT16 clt_cfg;
} tBA_WRITE_DATA;
#define BA_READ_CLT_CFG_REQ 1
#define BA_READ_PRE_FMT_REQ 2
#define BA_READ_RPT_REF_REQ 3
#define BA_READ_LEVEL_REQ 4
#define BA_WRITE_CLT_CFG_REQ 5
typedef void (tBA_CBACK)(UINT8 app_id, UINT8 event, tBA_WRITE_DATA *p_data);
#define BA_LEVEL_NOTIFY 0x01
#define BA_LEVEL_PRE_FMT 0x02
#define BA_LEVEL_RPT_REF 0x04
typedef UINT8 tBA_LEVEL_DESCR;
typedef struct {
BOOLEAN is_pri;
tBA_LEVEL_DESCR ba_level_descr;
tGATT_TRANSPORT transport;
tBA_CBACK *p_cback;
} tBA_REG_INFO;
typedef union {
UINT8 ba_level;
UINT16 clt_cfg;
tGATT_CHAR_RPT_REF rpt_ref;
tGATT_CHAR_PRES pres_fmt;
} tBA_RSP_DATA;
/*****************************************************************************
** External Function Declarations
*****************************************************************************/
#ifdef __cplusplus
extern "C"
{
#endif
/*****************************************************************************
** Service Engine API
*****************************************************************************/
/*******************************************************************************
**
** Function srvc_eng_init
**
** Description Initializa the GATT Service engine, register a GATT application
** as for a central service management.
**
*******************************************************************************/
extern tGATT_STATUS srvc_eng_init (void);
/*****************************************************************************
** DIS Server Function
*****************************************************************************/
/*******************************************************************************
**
** Function DIS_SrInit
**
** Description Initializa the Device Information Service Server.
**
*******************************************************************************/
extern tDIS_STATUS DIS_SrInit (tDIS_ATTR_MASK dis_attr_mask);
/*******************************************************************************
**
** Function DIS_SrUpdate
**
** Description Update the DIS server attribute values
**
*******************************************************************************/
extern tDIS_STATUS DIS_SrUpdate(tDIS_ATTR_BIT dis_attr_bit, tDIS_ATTR *p_info);
/*****************************************************************************
** DIS Client Function
*****************************************************************************/
/*******************************************************************************
**
** Function DIS_ReadDISInfo
**
** Description Read remote device DIS information.
**
** Returns void
**
*******************************************************************************/
extern BOOLEAN DIS_ReadDISInfo(BD_ADDR peer_bda, tDIS_READ_CBACK *p_cback,
tDIS_ATTR_MASK mask);
/*******************************************************************************
** BATTERY SERVICE API
*******************************************************************************/
/*******************************************************************************
**
** Function Battery_Instantiate
**
** Description Instantiate a Battery service
**
*******************************************************************************/
extern UINT16 Battery_Instantiate (UINT8 app_id, tBA_REG_INFO *p_reg_info);
/*******************************************************************************
**
** Function Battery_Rsp
**
** Description Respond to a battery service request
**
*******************************************************************************/
extern void Battery_Rsp (UINT8 app_id, tGATT_STATUS st, UINT8 event, tBA_RSP_DATA *p_rsp);
/*******************************************************************************
**
** Function Battery_Notify
**
** Description Send battery level notification
**
*******************************************************************************/
extern void Battery_Notify (UINT8 app_id, BD_ADDR remote_bda, UINT8 battery_level);
#ifdef __cplusplus
}
#endif
#endif
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,93 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdlib.h> // standard library
#include <string.h>
#include "esp_sec_api.h"
extern void srand (unsigned int seed);
extern int random (void);
/// Application Security Environment Structure
tAPP_SEC_ENV app_sec_env;
/*******************************************************************************
**
** Function app_ble_sec_gen_tk
**
** Description This function is called to generate the ble tk
**
** Returns the generate tk value
**
*******************************************************************************/
UINT32 app_ble_sec_gen_tk(void)
{
// Generate a PIN Code (Between 100000 and 999999)
return (100000 + (random() % 900000));
}
/*******************************************************************************
**
** Function app_ble_sec_gen_ltk
**
** Description This function is called to generate the ble ltk
**
** Returns NULL
**
*******************************************************************************/
void app_ble_sec_gen_ltk(UINT8 key_size)
{
// Counter
UINT8 i;
app_sec_env.key_size = key_size;
// Randomly generate the LTK and the Random Number
for (i = 0; i < RAND_NB_LEN; i++) {
app_sec_env.rand_nb.nb[i] = random() % 256;
}
// Randomly generate the end of the LTK
for (i = 0; i < SEC_KEY_LEN; i++) {
app_sec_env.ltk.key[i] = (((key_size) < (16 - i)) ? 0 : random() % 256);
}
// Randomly generate the EDIV
app_sec_env.ediv = random() % 65536;
}
/*******************************************************************************
**
** Function app_ble_sec_init
**
** Description This function is init the security env and function
**
** Returns NULL
**
*******************************************************************************/
void app_ble_sec_init(void)
{
// Reset Security Environment
memset(&app_sec_env, 0, sizeof(app_sec_env));
}
/*******************************************************************************
**
** Function app_ble_security_start
**
** Description This function is called by the slave when the seurity start
**
** Returns NULL
**
*******************************************************************************/
void app_ble_security_start(void)
{
}
@@ -0,0 +1,71 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __ESP_SEC_API_H__
#define __ESP_SEC_API_H__
#include "stack/bt_types.h"
#define APP_SEC_IRK_FLAG (0)
#define RAND_NB_LEN 0x08
#define SEC_KEY_LEN 0x10
/*
* STRUCTURES DEFINITIONS
****************************************************************************************
*/
/// Generic Security key structure
typedef struct {
/// Key value MSB -> LSB
UINT8 key[SEC_KEY_LEN];
} smp_sec_key;
///Random number structure
typedef struct {
///8-byte array for random number
UINT8 nb[RAND_NB_LEN];
} rand_nb;
typedef struct {
// LTK
smp_sec_key ltk;
// Random Number
rand_nb rand_nb;
// EDIV
UINT16 ediv;
// LTK key size
UINT8 key_size;
// Last paired peer address type
UINT8 peer_addr_type;
// Last paired peer address
BD_ADDR peer_addr;
// authentication level
UINT8 auth;
} tAPP_SEC_ENV;
extern tAPP_SEC_ENV app_sec_env;
/*
* GLOBAL FUNCTIONS DECLARATIONS
****************************************************************************************
*/
void app_ble_sec_init(void);
void app_ble_sec_pairing_cmp_evt_send(UINT8);
UINT32 app_ble_sec_gen_tk(void);
void app_ble_sec_gen_ltk(UINT8 key_size);
void app_ble_security_start(void);
#endif /* __ESP_SEC_API_H__ */
File diff suppressed because it is too large Load Diff