BTIF: Bluetooth Interface
BTU : Bluetooth Upper Layer
BTM: Bluetooth Manager
BTE: Bluetooth embedded system
BTA :Blueetooth application layer
CO: call out\CI: call in
HF : Handsfree Profile
HH: HID Host Profile
HL: Health Device Profile
V:audio\vidio
ag: audio gateway
r: audio/video registration
gattc: GATT client
BLE: Bluetooth Low Energy
整个bluedroid可以分为两大模块:BTIF,BTE
BTIF:提供bluedroid对外的接口
BTE:bluedroid的内部处理,又细分为BTA,BTU,BTM和HCI
BTA:bluedroid中各profile的逻辑实现和处理
BTU:承接BTA与HCI
BTM:蓝牙配对与链路管理
HCI:读取或写入数据到蓝牙hw
二、代码分析(写hidraw节点数据流程):
1.初始化:
external\bluetooth\bluedroid\btif\src\bluetooth.c
static const bt_interface_t bluetoothInterface = {
sizeof(bluetoothInterface),
init,
enable,
disable,
cleanup,
get_adapter_properties,
get_adapter_property,
set_adapter_property,
get_remote_device_properties,
get_remote_device_property,
set_remote_device_property,
get_remote_service_record,
get_remote_services,
start_discovery,
cancel_discovery,
create_bond,
remove_bond,
cancel_bond,
get_connection_state,
pin_reply,
ssp_reply,
get_profile_interface, //根据profile获得对应的接口
dut_mode_configure,
dut_mode_send,
#if BLE_INCLUDED == TRUE
le_test_mode,
#else
NULL,
#endif
config_hci_snoop_log,
set_os_callouts,
read_energy_info,
};
......
if (is_profile(profile_id, BT_PROFILE_HIDHOST_ID))
return btif_hh_get_interface(); //获得HID Host Profile
external\bluetooth\bluedroid\btif\src\btif_hh.c
static const bthh_interface_t bthhInterface = {
sizeof(bthhInterface),
init,
connect,
disconnect,
virtual_unplug,
set_info,
get_protocol,
set_protocol,
// get_idle_time,
// set_idle_time,
get_report,
set_report,
send_data,
cleanup,
};
init函数里注册传入的回调函数:
/*******************************************************************************
**
** Function btif_hh_init
**
** Description initializes the hh interface
**
** Returns bt_status_t
**
*******************************************************************************/
static bt_status_t init( bthh_callbacks_t* callbacks )
{
UINT32 i;
BTIF_TRACE_EVENT("%s", __FUNCTION__);
bt_hh_callbacks = callbacks;
memset(&btif_hh_cb, 0, sizeof(btif_hh_cb));
for (i = 0; i < BTIF_HH_MAX_HID; i++){
btif_hh_cb.devices[i].dev_status = BTHH_CONN_STATE_UNKNOWN;
}
/* Invoke the enable service API to the core to set the appropriate service_id */
btif_enable_service(BTA_HID_SERVICE_ID);
return BT_STATUS_SUCCESS;
}
external\bluetooth\bluedroid\btif\src\btif_core.c
/*******************************************************************************
**
** Function btif_enable_service
**
** Description Enables the service 'service_ID' to the service_mask.
** Upon BT enable, BTIF core shall invoke the BTA APIs to
** enable the profiles
**
** Returns bt_status_t
**
*******************************************************************************/
bt_status_t btif_enable_service(tBTA_SERVICE_ID service_id)
{
tBTA_SERVICE_ID *p_id = &service_id;
/* If BT is enabled, we need to switch to BTIF context and trigger the
* enable for that profile
*
* Otherwise, we just set the flag. On BT_Enable, the DM will trigger
* enable for the profiles that have been enabled */
btif_enabled_services |= (1 << service_id);
BTIF_TRACE_DEBUG("%s: current services:0x%x", __FUNCTION__, btif_enabled_services);
if (btif_is_enabled())
{ //注册回调,发送消息
btif_transfer_context(btif_dm_execute_service_request,
BTIF_DM_ENABLE_SERVICE,
(char*)p_id, sizeof(tBTA_SERVICE_ID), NULL);
}
return BT_STATUS_SUCCESS;
}
2.创建线程和准备启动调度:
/*******************************************************************************
**
** Function btif_init_bluetooth
**
** Description Creates BTIF task and prepares BT scheduler for startup
**
** Returns bt_status_t
**
*******************************************************************************/
bt_status_t btif_init_bluetooth()
{
UINT8 status;
btif_config_init();
bte_main_boot_entry();
/* As part of the init, fetch the local BD ADDR */
memset(&btif_local_bd_addr, 0, sizeof(bt_bdaddr_t));
btif_fetch_local_bdaddr(&btif_local_bd_addr);
/* start btif task */
status = GKI_create_task(btif_task, BTIF_TASK, BTIF_TASK_STR,
(UINT16 *) ((UINT8 *)btif_task_stack + BTIF_TASK_STACK_SIZE),
sizeof(btif_task_stack));
if (status != GKI_SUCCESS)
return BT_STATUS_FAIL;
return BT_STATUS_SUCCESS;
}
处理线程函数:
/*******************************************************************************
**
** Function btif_task
**
** Description BTIF task handler managing all messages being passed
** Bluetooth HAL and BTA.
**
** Returns void
**
*******************************************************************************/
static void btif_task(UINT32 params)
{
UINT16 event;
BT_HDR *p_msg;
UNUSED(params);
BTIF_TRACE_DEBUG("btif task starting");
btif_associate_evt();
for(;;)
{
/* wait for specified events */
event = GKI_wait(0xFFFF, 0);
/*
* Wait for the trigger to init chip and stack. This trigger will
* be received by btu_task once the UART is opened and ready
*/
if (event == BT_EVT_TRIGGER_STACK_INIT)
{
BTIF_TRACE_DEBUG("btif_task: received trigger stack init event");
#if (BLE_INCLUDED == TRUE)
btif_dm_load_ble_local_keys();
#endif
BTA_EnableBluetooth(bte_dm_evt);
}
/*
* Failed to initialize controller hardware, reset state and bring
* down all threads
*/
if (event == BT_EVT_HARDWARE_INIT_FAIL)
{
BTIF_TRACE_DEBUG("btif_task: hardware init failed");
bte_main_disable();
btif_queue_release();
GKI_task_self_cleanup(BTIF_TASK);
bte_main_shutdown();
btif_dut_mode = 0;
btif_core_state = BTIF_CORE_STATE_DISABLED;
HAL_CBACK(bt_hal_cbacks,adapter_state_changed_cb,BT_STATE_OFF);
break;
}
if (event & EVENT_MASK(GKI_SHUTDOWN_EVT))
break;
if(event & TASK_MBOX_1_EVT_MASK)
{
while((p_msg = GKI_read_mbox(BTU_BTIF_MBOX)) != NULL) //读取消息
{
BTIF_TRACE_VERBOSE("btif task fetched event %x", p_msg->event);
switch (p_msg->event)
{
case BT_EVT_CONTEXT_SWITCH_EVT:
btif_context_switched(p_msg); //传递消息给注册的回调函数
break;
default:
BTIF_TRACE_ERROR("unhandled btif event (%d)", p_msg->event & BT_EVT_MASK);
break;
}
GKI_freebuf(p_msg);
}
}
}
btif_disassociate_evt();
BTIF_TRACE_DEBUG("btif task exiting");
}
之前先开启了蓝牙服务:
/*******************************************************************************
**
** Function BTA_EnableBluetooth
**
** Description Enables bluetooth service. This function must be
** called before any other functions in the BTA API are called.
**
**
** Returns tBTA_STATUS
**
*******************************************************************************/
tBTA_STATUS BTA_EnableBluetooth(tBTA_DM_SEC_CBACK *p_cback)
{
tBTA_DM_API_ENABLE *p_msg;
/* Bluetooth disabling is in progress */
if (bta_dm_cb.disabling)
return BTA_FAILURE;
memset(&bta_dm_cb, 0, sizeof(bta_dm_cb));
bta_sys_register (BTA_ID_DM, &bta_dm_reg );
bta_sys_register (BTA_ID_DM_SEARCH, &bta_dm_search_reg );
/* if UUID list is not provided as static data */
bta_sys_eir_register(bta_dm_eir_update_uuid);
if ((p_msg = (tBTA_DM_API_ENABLE *) GKI_getbuf(sizeof(tBTA_DM_API_ENABLE))) != NULL)
{
p_msg->hdr.event = BTA_DM_API_ENABLE_EVT;
p_msg->p_sec_cback = p_cback;
bta_sys_sendmsg(p_msg);
return BTA_SUCCESS;
}
return BTA_FAILURE;
}
external\bluetooth\bluedroid\btif\src\btif_dm.c
根据消息请求对应服务:
void btif_dm_execute_service_request(UINT16 event, char *p_param)
{
BOOLEAN b_enable = FALSE;
bt_status_t status;
if (event == BTIF_DM_ENABLE_SERVICE)
{
b_enable = TRUE;
}
status = btif_in_execute_service_request(*((tBTA_SERVICE_ID*)p_param), b_enable); //执行服务请求
if (status == BT_STATUS_SUCCESS)
{
bt_property_t property;
bt_uuid_t local_uuids[BT_MAX_NUM_UUIDS];
/* Now send the UUID_PROPERTY_CHANGED event to the upper layer */
BTIF_STORAGE_FILL_PROPERTY(&property, BT_PROPERTY_UUIDS,
sizeof(local_uuids), local_uuids);
btif_storage_get_adapter_property(&property);
HAL_CBACK(bt_hal_cbacks, adapter_properties_cb,
BT_STATUS_SUCCESS, 1, &property);
}
return;
}
执行A2DP/HID/HFP等服务
bt_status_t btif_in_execute_service_request(tBTA_SERVICE_ID service_id,
BOOLEAN b_enable)
{
/* Check the service_ID and invoke the profile's BT state changed API */
switch (service_id)
{
case BTA_HFP_SERVICE_ID:
case BTA_HSP_SERVICE_ID:
{
btif_hf_execute_service(b_enable);
}break;
case BTA_A2DP_SERVICE_ID:
{
btif_av_execute_service(b_enable);
}break;
case BTA_HID_SERVICE_ID:
{
btif_hh_execute_service(b_enable);
}break;
case BTA_HFP_HS_SERVICE_ID:
{
btif_hf_client_execute_service(b_enable);
}break;
case BTA_MAP_SERVICE_ID:
{
btif_mce_execute_service(b_enable);
}break;
default:
BTIF_TRACE_ERROR("%s: Unknown service being enabled", __FUNCTION__);
return BT_STATUS_FAIL;
}
return BT_STATUS_SUCCESS;
}
external\bluetooth\bluedroid\btif\src\btif_hh.c
启动/关闭 HID服务
/*******************************************************************************
**
** Function btif_hh_execute_service
**
** Description Initializes/Shuts down the service
**
** Returns BT_STATUS_SUCCESS on success, BT_STATUS_FAIL otherwise
**
*******************************************************************************/
bt_status_t btif_hh_execute_service(BOOLEAN b_enable)
{
if (b_enable)
{
/* Enable and register with BTA-HH */
BTA_HhEnable(BTA_SEC_ENCRYPT, bte_hh_evt);
}
else {
/* Disable HH */
BTA_HhDisable();
}
return BT_STATUS_SUCCESS;
}
external\bluetooth\bluedroid\bta\hh\bta_hh_api.c
/*******************************************************************************
**
** Function BTA_HhEnable
**
** Description Enable the HID host. This function must be called before
** any other functions in the HID host API are called. When the
** enable operation is complete the callback function will be
** called with BTA_HH_ENABLE_EVT.
**
**
** Returns void
**
*******************************************************************************/
void BTA_HhEnable(tBTA_SEC sec_mask, tBTA_HH_CBACK *p_cback)
{
tBTA_HH_API_ENABLE *p_buf;
/* register with BTA system manager */
bta_sys_register(BTA_ID_HH, &bta_hh_reg); //注册主处理函数
APPL_TRACE_ERROR("Calling BTA_HhEnable");
p_buf = (tBTA_HH_API_ENABLE *)GKI_getbuf((UINT16)sizeof(tBTA_HH_API_ENABLE));
if (p_buf != NULL)
{
memset(p_buf, 0, sizeof(tBTA_HH_API_ENABLE));
p_buf->hdr.event = BTA_HH_API_ENABLE_EVT;
p_buf->p_cback = p_cback;
p_buf->sec_mask = sec_mask;
bta_sys_sendmsg(p_buf);
}
}
external\bluetooth\bluedroid\btif\co\bta_hh_co.c
HID Host Profile 部分初始化,创建HID事件监听线程:btif_hh_poll_event_thread
/*******************************************************************************
**
** 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 dev_handle, UINT8 sub_class, tBTA_HH_ATTR_MASK attr_mask,
UINT8 app_id)
{
UINT32 i;
btif_hh_device_t *p_dev = NULL;
if (dev_handle == BTA_HH_INVALID_HANDLE) {
APPL_TRACE_WARNING("%s: Oops, dev_handle (%d) is invalid...", __FUNCTION__, dev_handle);
return;
}
for (i = 0; i < BTIF_HH_MAX_HID; i++) {
p_dev = &btif_hh_cb.devices[i];
if (p_dev->dev_status != BTHH_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",__FUNCTION__,
p_dev->dev_status);
APPL_TRACE_WARNING("%s: bd_addr = [%02X:%02X:%02X:%02X:%02X:]", __FUNCTION__,
p_dev->bd_addr.address[0], p_dev->bd_addr.address[1], p_dev->bd_addr.address[2],
p_dev->bd_addr.address[3], p_dev->bd_addr.address[4]);
APPL_TRACE_WARNING("%s: attr_mask = 0x%04x, sub_class = 0x%02x, app_id = %d",
__FUNCTION__, p_dev->attr_mask, p_dev->sub_class, p_dev->app_id);
if(p_dev->fd<0) {
p_dev->fd = open(dev_path, O_RDWR | O_CLOEXEC);
if (p_dev->fd < 0){
APPL_TRACE_ERROR("%s: Error: failed to open uhid, err:%s",
__FUNCTION__,strerror(errno));
}else
APPL_TRACE_DEBUG("%s: uhid fd = %d", __FUNCTION__, p_dev->fd);
}
p_dev->hh_keep_polling = 1;
p_dev->hh_poll_thread_id = create_thread(btif_hh_poll_event_thread, p_dev);
break;
}
p_dev = NULL;
}
if (p_dev == NULL) {
// Did not find a device reconnection case. Find an empty slot now.
for (i = 0; i < BTIF_HH_MAX_HID; i++) {
if (btif_hh_cb.devices[i].dev_status == BTHH_CONN_STATE_UNKNOWN) {
p_dev = &btif_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;
btif_hh_cb.device_num++;
// This is a new device,open the uhid driver now.
p_dev->fd = open(dev_path, O_RDWR | O_CLOEXEC);
if (p_dev->fd < 0){
APPL_TRACE_ERROR("%s: Error: failed to open uhid, err:%s",
__FUNCTION__,strerror(errno));
}else{
APPL_TRACE_DEBUG("%s: uhid fd = %d", __FUNCTION__, p_dev->fd);
p_dev->hh_keep_polling = 1;
p_dev->hh_poll_thread_id = create_thread(btif_hh_poll_event_thread, p_dev);
}
break;
}
}
}
if (p_dev == NULL) {
APPL_TRACE_ERROR("%s: Error: too many HID devices are connected", __FUNCTION__);
return;
}
p_dev->dev_status = BTHH_CONN_STATE_CONNECTED;
APPL_TRACE_DEBUG("%s: Return device status %d", __FUNCTION__, p_dev->dev_status);
}
poll监听HID驱动的事件:
/*******************************************************************************
**
** Function btif_hh_poll_event_thread
**
** Description the polling thread which polls for event from UHID driver
**
** Returns void
**
*******************************************************************************/
static void *btif_hh_poll_event_thread(void *arg)
{
btif_hh_device_t *p_dev = arg;
APPL_TRACE_DEBUG("%s: Thread created fd = %d", __FUNCTION__, p_dev->fd);
struct pollfd pfds[1];
int ret;
pfds[0].fd = p_dev->fd;
pfds[0].events = POLLIN;
while(p_dev->hh_keep_polling){
ret = poll(pfds, 1, 50);
if (ret < 0) {
APPL_TRACE_ERROR("%s: Cannot poll for fds: %s\n", __FUNCTION__, strerror(errno));
break;
}
if (pfds[0].revents & POLLIN) {
APPL_TRACE_DEBUG("btif_hh_poll_event_thread: POLLIN");
ret = uhid_event(p_dev);
if (ret){
break;
}
}
}
p_dev->hh_poll_thread_id = -1;
return 0;
}
解析HID驱动的事件:
/* Internal function to parse the events received from UHID driver*/
static int uhid_event(btif_hh_device_t *p_dev)
{
struct uhid_event ev;
ssize_t ret;
memset(&ev, 0, sizeof(ev));
if(!p_dev)
{
APPL_TRACE_ERROR("%s: Device not found",__FUNCTION__)
return -1;
}
ret = read(p_dev->fd, &ev, sizeof(ev));
if (ret == 0) {
APPL_TRACE_ERROR("%s: Read HUP on uhid-cdev %s", __FUNCTION__,
strerror(errno));
return -EFAULT;
} else if (ret < 0) {
APPL_TRACE_ERROR("%s:Cannot read uhid-cdev: %s", __FUNCTION__,
strerror(errno));
return -errno;
} else if (ret != sizeof(ev)) {
APPL_TRACE_ERROR("%s:Invalid size read from uhid-dev: %ld != %lu",
__FUNCTION__, ret, sizeof(ev));
return -EFAULT;
}
switch (ev.type) {
case UHID_START:
APPL_TRACE_DEBUG("UHID_START from uhid-dev\n");
break;
case UHID_STOP:
APPL_TRACE_DEBUG("UHID_STOP from uhid-dev\n");
break;
case UHID_OPEN:
APPL_TRACE_DEBUG("UHID_OPEN from uhid-dev\n");
break;
case UHID_CLOSE:
APPL_TRACE_DEBUG("UHID_CLOSE from uhid-dev\n");
break;
case UHID_OUTPUT:
APPL_TRACE_DEBUG("UHID_OUTPUT: Report type = %d, report_size = %d"
,ev.u.output.rtype, ev.u.output.size);
//Send SET_REPORT with feature report if the report type in output event is FEATURE
if(ev.u.output.rtype == UHID_FEATURE_REPORT)
btif_hh_setreport(p_dev,BTHH_FEATURE_REPORT,ev.u.output.size,ev.u.output.data);
else if(ev.u.output.rtype == UHID_OUTPUT_REPORT)
btif_hh_setreport(p_dev,BTHH_OUTPUT_REPORT,ev.u.output.size,ev.u.output.data);
else
btif_hh_setreport(p_dev,BTHH_INPUT_REPORT,ev.u.output.size,ev.u.output.data);
break;
case UHID_OUTPUT_EV:
APPL_TRACE_DEBUG("UHID_OUTPUT_EV from uhid-dev\n");
break;
case UHID_FEATURE:
APPL_TRACE_DEBUG("UHID_FEATURE from uhid-dev\n");
break;
case UHID_FEATURE_ANSWER:
APPL_TRACE_DEBUG("UHID_FEATURE_ANSWER from uhid-dev\n");
break;
default:
APPL_TRACE_DEBUG("Invalid event from uhid-dev: %u\n", ev.type);
}
return 0;
}
--->
/*******************************************************************************
**
** Function btif_btif_hh_setreport
**
** Description setreport initiated from the BTIF thread context
**
** Returns void
**
*******************************************************************************/
#define COMMAND_PATCH
void btif_hh_setreport(btif_hh_device_t *p_dev, bthh_report_type_t r_type, UINT16 size,
UINT8* report)
{
BT_HDR* p_buf = create_pbuf(size, report);
if (p_buf == NULL) {
APPL_TRACE_ERROR("%s: Error, failed to allocate RPT buffer, size = %d", __FUNCTION__, size);
return;
}
#ifdef COMMAND_PATCH
if(report[0] != 0x5B) /*判断report id!=0x5B,执行默认的request,需要response*/
BTA_HhSetReport(p_dev->dev_handle, r_type, p_buf);
else{ /*判断report id==0x5B,发送command,不需要response*/
BD_ADDR* bda = (BD_ADDR*)&p_dev->bd_addr;
BTIF_TRACE_DEBUG("Send Command Size %",size);
p_buf->layer_specific = BTA_HH_RPTT_OUTPUT;
BTA_HhSendData(p_dev->dev_handle,*bda,p_buf);
}
#else
BTA_HhSetReport(p_dev->dev_handle, r_type, p_buf);
#endif
}
发送数据到HID设备:
/*******************************************************************************
**
** Function BTA_HhSendData
**
** Description This function send DATA transaction to HID device.
**
** Parameter dev_handle: device handle
** dev_bda: remote device address
** p_data: data to be sent in the DATA transaction; or
** the data to be write into the Output Report of a LE HID
** device. The report is identified the report ID which is
** the value of the byte (UINT8 *)(p_buf + 1) + p_buf->offset.
** p_data->layer_specific needs to be set to the report type,
** it can be OUTPUT report, or FEATURE report.
**
** Returns void
**
*******************************************************************************/
void BTA_HhSendData(UINT8 dev_handle, BD_ADDR dev_bda, BT_HDR *p_data)
{
UNUSED(dev_bda);
#if (defined BTA_HH_LE_INCLUDED && BTA_HH_LE_INCLUDED == TRUE)
if (p_data->layer_specific != BTA_HH_RPTT_OUTPUT)
{
APPL_TRACE_ERROR("ERROR! Wrong report type! Write Command only valid for output report!");
return;
}
#endif
bta_hh_snd_write_dev(dev_handle, HID_TRANS_DATA, (UINT8)p_data->layer_specific, 0, 0, p_data);
}
-->
/*******************************************************************************
**
** Function bta_hh_snd_write_dev
**
*******************************************************************************/
static void bta_hh_snd_write_dev(UINT8 dev_handle, UINT8 t_type, UINT8 param,
UINT16 data, UINT8 rpt_id, BT_HDR *p_data)
{
tBTA_HH_CMD_DATA *p_buf;
UINT16 len = (UINT16) (sizeof(tBTA_HH_CMD_DATA) );
if ((p_buf = (tBTA_HH_CMD_DATA *)GKI_getbuf(len))!= NULL)
{
memset(p_buf, 0, sizeof(tBTA_HH_CMD_DATA));
p_buf->hdr.event = BTA_HH_API_WRITE_DEV_EVT;
p_buf->hdr.layer_specific = (UINT16) dev_handle;
p_buf->t_type = t_type;
p_buf->data = data;
p_buf->param = param;
p_buf->p_data = p_data;
p_buf->rpt_id = rpt_id;
bta_sys_sendmsg(p_buf); //发送数据到hid处理进程
}
}
external\bluetooth\bluedroid\bta\hh\bta_hh_main.c
BTA_HhEnable时注册的HID主处理函数进行数据接收和处理:
/*******************************************************************************
**
** Function bta_hh_hdl_event
**
** Description HID host main event handling function.
**
**
** Returns void
**
*******************************************************************************/
BOOLEAN bta_hh_hdl_event(BT_HDR *p_msg)
{
UINT8 index = BTA_HH_IDX_INVALID;
tBTA_HH_DEV_CB *p_cb = NULL;
switch (p_msg->event)
{
case BTA_HH_API_ENABLE_EVT:
bta_hh_api_enable((tBTA_HH_DATA *) p_msg);
break;
case BTA_HH_API_DISABLE_EVT:
bta_hh_api_disable();
break;
case BTA_HH_DISC_CMPL_EVT: /* disable complete */
bta_hh_disc_cmpl();
break;
default:
/* all events processed in state machine need to find corresponding
CB before proceed */
if (p_msg->event == BTA_HH_API_OPEN_EVT)
{
index = bta_hh_find_cb(((tBTA_HH_API_CONN *)p_msg)->bd_addr);
}
else if (p_msg->event == BTA_HH_API_MAINT_DEV_EVT)
{
/* if add device */
if (((tBTA_HH_MAINT_DEV *)p_msg)->sub_event == BTA_HH_ADD_DEV_EVT)
{
index = bta_hh_find_cb(((tBTA_HH_MAINT_DEV *)p_msg)->bda);
}
else /* else remove device by handle */
{
index = bta_hh_dev_handle_to_cb_idx((UINT8)p_msg->layer_specific);
// btla-specific ++
/* If BT disable is done while the HID device is connected and Link_Key uses unauthenticated combination
* then we can get into a situation where remove_bonding is called with the index set to 0 (without getting
* cleaned up). Only when VIRTUAL_UNPLUG is called do we cleanup the index and make it MAX_KNOWN.
* So if REMOVE_DEVICE is called and in_use is FALSE then we should treat this as a NULL p_cb. Hence we
* force the index to be IDX_INVALID
*/
if ((index != BTA_HH_IDX_INVALID) &&
(bta_hh_cb.kdev[index].in_use == FALSE)) {
index = BTA_HH_IDX_INVALID;
}
// btla-specific --
}
}
else if (p_msg->event == BTA_HH_INT_OPEN_EVT)
{
index = bta_hh_find_cb(((tBTA_HH_CBACK_DATA *)p_msg)->addr);
}
else
index = bta_hh_dev_handle_to_cb_idx((UINT8)p_msg->layer_specific);
if (index != BTA_HH_IDX_INVALID)
p_cb = &bta_hh_cb.kdev[index];
#if BTA_HH_DEBUG
APPL_TRACE_DEBUG("bta_hh_hdl_event:: handle = %d dev_cb[%d] ", p_msg->layer_specific, index);
#endif
bta_hh_sm_execute(p_cb, p_msg->event, (tBTA_HH_DATA *) p_msg); //状态机处理函数
}
return (TRUE);
}
HID状态机事件处理函数
/*******************************************************************************
**
** Function bta_hh_sm_execute
**
** Description State machine event handling function for HID Host
**
**
** Returns void
**
*******************************************************************************/
void bta_hh_sm_execute(tBTA_HH_DEV_CB *p_cb, UINT16 event, tBTA_HH_DATA * p_data)
{
tBTA_HH_ST_TBL state_table;
UINT8 action;
tBTA_HH cback_data;
tBTA_HH_EVT cback_event = 0;
#if BTA_HH_DEBUG == TRUE
tBTA_HH_STATE in_state ;
UINT16 debug_event = event;
#endif
memset(&cback_data, 0, sizeof(tBTA_HH));
/* handle exception, no valid control block was found */
if (!p_cb)
{
/* BTA HH enabled already? otherwise ignore the event although it's bad*/
if (bta_hh_cb.p_cback != NULL)
{
switch (event)
{
/* no control block available for new connection */
case BTA_HH_API_OPEN_EVT:
cback_event = BTA_HH_OPEN_EVT;
/* build cback data */
bdcpy(cback_data.conn.bda, ((tBTA_HH_API_CONN *)p_data)->bd_addr);
cback_data.conn.status = BTA_HH_ERR_DB_FULL;
cback_data.conn.handle = BTA_HH_INVALID_HANDLE;
break;
/* DB full, BTA_HhAddDev */
case BTA_HH_API_MAINT_DEV_EVT:
cback_event = p_data->api_maintdev.sub_event;
if (p_data->api_maintdev.sub_event == BTA_HH_ADD_DEV_EVT)
{
bdcpy(cback_data.dev_info.bda, p_data->api_maintdev.bda);
cback_data.dev_info.status = BTA_HH_ERR_DB_FULL;
cback_data.dev_info.handle = BTA_HH_INVALID_HANDLE;
}
else
{
cback_data.dev_info.status = BTA_HH_ERR_HDL;
cback_data.dev_info.handle = (UINT8)p_data->api_maintdev.hdr.layer_specific;
}
break;
case BTA_HH_API_WRITE_DEV_EVT:
cback_event = (p_data->api_sndcmd.t_type - BTA_HH_FST_BTE_TRANS_EVT) +
BTA_HH_FST_TRANS_CB_EVT;
if (p_data->api_sndcmd.p_data != NULL)
{
GKI_freebuf(p_data->api_sndcmd.p_data);
}
if (p_data->api_sndcmd.t_type == HID_TRANS_SET_PROTOCOL ||
p_data->api_sndcmd.t_type == HID_TRANS_SET_REPORT ||
p_data->api_sndcmd.t_type == HID_TRANS_SET_IDLE)
{
cback_data.dev_status.status = BTA_HH_ERR_HDL;
cback_data.dev_status.handle = (UINT8)p_data->api_sndcmd.hdr.layer_specific;
}
else if (p_data->api_sndcmd.t_type != HID_TRANS_DATA &&
p_data->api_sndcmd.t_type != HID_TRANS_CONTROL)
{
cback_data.hs_data.handle = (UINT8)p_data->api_sndcmd.hdr.layer_specific;
cback_data.hs_data.status = BTA_HH_ERR_HDL;
/* hs_data.rsp_data will be all zero, which is not valid value */
}
else if (p_data->api_sndcmd.t_type == HID_TRANS_CONTROL &&
p_data->api_sndcmd.param == BTA_HH_CTRL_VIRTUAL_CABLE_UNPLUG)
{
cback_data.status = BTA_HH_ERR_HDL;
cback_event = BTA_HH_VC_UNPLUG_EVT;
}
else
cback_event = 0;
break;
case BTA_HH_API_CLOSE_EVT:
cback_event = BTA_HH_CLOSE_EVT;
cback_data.dev_status.status = BTA_HH_ERR_HDL;
cback_data.dev_status.handle = (UINT8)p_data->api_sndcmd.hdr.layer_specific;
break;
default:
/* invalid handle, call bad API event */
APPL_TRACE_ERROR("wrong device handle: [%d]", p_data->hdr.layer_specific);
/* Free the callback buffer now */
if (p_data != NULL && p_data->hid_cback.p_data != NULL)
{
GKI_freebuf(p_data->hid_cback.p_data);
p_data->hid_cback.p_data = NULL;
}
break;
}
if (cback_event)
(* bta_hh_cb.p_cback)(cback_event, &cback_data);
}
}
/* corresponding CB is found, go to state machine */
else
{
#if BTA_HH_DEBUG == TRUE
in_state = p_cb->state;
APPL_TRACE_EVENT("bta_hh_sm_execute: State 0x%02x [%s], Event [%s]",
in_state, bta_hh_state_code(in_state),
bta_hh_evt_code(debug_event));
#endif
if ((p_cb->state == BTA_HH_NULL_ST) || (p_cb->state >= BTA_HH_INVALID_ST))
{
APPL_TRACE_ERROR("bta_hh_sm_execute: Invalid state State = 0x%x, Event = %d",
p_cb->state,event);
return;
}
state_table = bta_hh_st_tbl[p_cb->state - 1];
event &= 0xff;
p_cb->state = state_table[event][BTA_HH_NEXT_STATE] ;
if ((action = state_table[event][BTA_HH_ACTION]) != BTA_HH_IGNORE)
{
(*bta_hh_action[action])(p_cb, p_data); //各事件处理函数列表,写节点为action(8)-> bta_hh_write_dev_act
}
#if BTA_HH_DEBUG == TRUE
if (in_state != p_cb->state)
{
APPL_TRACE_DEBUG("HH State Change: [%s] -> [%s] after Event [%s]",
bta_hh_state_code(in_state),
bta_hh_state_code(p_cb->state),
bta_hh_evt_code(debug_event));
}
#endif
}
return;
}
--->
/*******************************************************************************
**
** Function bta_hh_write_dev_act
**
** Description Write device action. can be SET/GET/DATA transaction.
**
** Returns void
**
*******************************************************************************/
void bta_hh_write_dev_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data)
{
tBTA_HH_CBDATA cbdata = {BTA_HH_OK, 0};
UINT16 event = (p_data->api_sndcmd.t_type - BTA_HH_FST_BTE_TRANS_EVT) +
BTA_HH_FST_TRANS_CB_EVT;
#if BTA_HH_LE_INCLUDED == TRUE
if (p_cb->is_le_device){
//调用到这里t_type为10(HID_TRANS_DATA)即开始通过 BTA_HhSendData 函数发送数据方式:
APPL_TRACE_DEBUG("bta_hh_le_write_dev_act : p_data->api_sndcmd.t_type = %d ",p_data->api_sndcmd.t_type);
bta_hh_le_write_dev_act(p_cb, p_data);
}
else
#endif
{
cbdata.handle = p_cb->hid_handle;
/* match up BTE/BTA report/boot mode def */
if (p_data->api_sndcmd.t_type == HID_TRANS_SET_PROTOCOL)
{
p_data->api_sndcmd.param = ( p_data->api_sndcmd.param == BTA_HH_PROTO_RPT_MODE) ?\
HID_PAR_PROTOCOL_REPORT :HID_PAR_PROTOCOL_BOOT_MODE;
}
if (HID_HostWriteDev (p_cb->hid_handle,
p_data->api_sndcmd.t_type,
p_data->api_sndcmd.param,
p_data->api_sndcmd.data,
p_data->api_sndcmd.rpt_id,
p_data->api_sndcmd.p_data) != HID_SUCCESS)
{
APPL_TRACE_ERROR("HID_HostWriteDev Error ");
cbdata.status = BTA_HH_ERR;
if (p_data->api_sndcmd.t_type != HID_TRANS_CONTROL &&
p_data->api_sndcmd.t_type != HID_TRANS_DATA)
(* bta_hh_cb.p_cback)(event, (tBTA_HH *)&cbdata);
else if (p_data->api_sndcmd.param == BTA_HH_CTRL_VIRTUAL_CABLE_UNPLUG)
(* bta_hh_cb.p_cback)(BTA_HH_VC_UNPLUG_EVT, (tBTA_HH *)&cbdata);
}
else
{
switch(p_data->api_sndcmd.t_type)
{
case HID_TRANS_SET_PROTOCOL:
/* fall through */
case HID_TRANS_GET_REPORT:
/* fall through */
case HID_TRANS_SET_REPORT:
/* fall through */
case HID_TRANS_GET_PROTOCOL:
/* fall through */
case HID_TRANS_GET_IDLE:
/* fall through */
case HID_TRANS_SET_IDLE:/* set w4_handsk event name for callback function use */
p_cb->w4_evt = event;
break;
case HID_TRANS_DATA: /* output report */
/* fall through */
case HID_TRANS_CONTROL:
/* no handshake event will be generated */
/* if VC_UNPLUG is issued, set flag */
if (p_data->api_sndcmd.param == BTA_HH_CTRL_VIRTUAL_CABLE_UNPLUG)
p_cb->vp = TRUE;
break;
/* currently not expected */
case HID_TRANS_DATAC:
default:
APPL_TRACE_DEBUG("bta_hh_write_dev_act:: cmd type = %d",
p_data->api_sndcmd.t_type);
break;
}
/* if not control type transaction, notify PM for energy control */
if (p_data->api_sndcmd.t_type != HID_TRANS_CONTROL)
{
/* inform PM for mode change */
bta_sys_busy(BTA_ID_HH, p_cb->app_id, p_cb->addr);
bta_sys_idle(BTA_ID_HH, p_cb->app_id, p_cb->addr);
}
else if (p_data->api_sndcmd.param == BTA_HH_CTRL_SUSPEND)
{
bta_sys_sco_close(BTA_ID_HH, p_cb->app_id, p_cb->addr);
}
else if (p_data->api_sndcmd.param == BTA_HH_CTRL_EXIT_SUSPEND)
{
bta_sys_busy(BTA_ID_HH, p_cb->app_id, p_cb->addr);
}
}
}
return;
}
--->
/*******************************************************************************
**
** Function bta_hh_le_write_dev_act
**
** Description Write LE device action. can be SET/GET/DATA transaction.
**
** Returns void
**
*******************************************************************************/
void bta_hh_le_write_dev_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data)
{
switch(p_data->api_sndcmd.t_type) //上面打印结果是10,即对应:HID_TRANS_DATA
{
case HID_TRANS_SET_PROTOCOL:
p_cb->w4_evt = BTA_HH_SET_PROTO_EVT;
bta_hh_le_set_protocol_mode(p_cb, p_data->api_sndcmd.param);
break;
case HID_TRANS_GET_PROTOCOL:
bta_hh_le_get_protocol_mode(p_cb);
break;
case HID_TRANS_GET_REPORT:
bta_hh_le_get_rpt(p_cb,
BTA_HH_LE_SRVC_DEF,
p_data->api_sndcmd.param,
p_data->api_sndcmd.rpt_id);
break;
case HID_TRANS_SET_REPORT:
bta_hh_le_write_rpt(p_cb,
BTA_HH_LE_SRVC_DEF,
BTA_GATTC_TYPE_WRITE,
p_data->api_sndcmd.param,
p_data->api_sndcmd.p_data,
BTA_HH_SET_RPT_EVT);
break;
case HID_TRANS_DATA: /* output report */
bta_hh_le_write_rpt(p_cb,
BTA_HH_LE_SRVC_DEF,
BTA_GATTC_TYPE_WRITE_NO_RSP,
p_data->api_sndcmd.param,
p_data->api_sndcmd.p_data,
BTA_HH_DATA_EVT);
break;
case HID_TRANS_CONTROL:
/* no handshake event will be generated */
/* if VC_UNPLUG is issued, set flag */
if (p_data->api_sndcmd.param == BTA_HH_CTRL_SUSPEND ||
p_data->api_sndcmd.param == BTA_HH_CTRL_EXIT_SUSPEND)
{
bta_hh_le_suspend(p_cb, p_data->api_sndcmd.param);
}
break;
default:
APPL_TRACE_ERROR("%s unsupported transaction for BLE HID device: %d",
__func__, p_data->api_sndcmd.t_type);
break;
}
}
-->
/*******************************************************************************
**
** Function bta_hh_le_write_rpt
**
** Description SET_REPORT/or DATA output on a LE HID Report
**
** Returns void
**
*******************************************************************************/
void bta_hh_le_write_rpt(tBTA_HH_DEV_CB *p_cb, UINT8 srvc_inst,
tBTA_GATTC_WRITE_TYPE write_type,
tBTA_HH_RPT_TYPE r_type,
BT_HDR *p_buf, UINT16 w4_evt )
{
tBTA_HH_LE_RPT *p_rpt;
tBTA_GATTC_CHAR_ID char_id;
UINT8 *p_value, rpt_id;
if (p_buf == NULL || p_buf->len == 0)
{
APPL_TRACE_ERROR("bta_hh_le_write_rpt: Illegal data");
return;
}
/* strip report ID from the data */
p_value = (UINT8 *)(p_buf + 1) + p_buf->offset;
STREAM_TO_UINT8(rpt_id, p_value);
p_buf->len -= 1;
p_rpt = bta_hh_le_find_rpt_by_idtype(p_cb->hid_srvc[srvc_inst].report, p_cb->mode, r_type, rpt_id);
if (p_rpt == NULL)
{
APPL_TRACE_ERROR("bta_hh_le_write_rpt: no matching report 0x%02x",rpt_id);
GKI_freebuf(p_buf);
return;
}
APPL_TRACE_ERROR("bta_hh_le_write_rpt: ReportID: 0x%02x Data Len: %d", rpt_id, p_buf->len);
p_cb->w4_evt = w4_evt;
bta_hh_le_fill_16bits_srvc_id(TRUE, srvc_inst, UUID_SERVCLASS_LE_HID, &char_id.srvc_id);
bta_hh_le_fill_16bits_char_id(p_rpt->inst_id, p_rpt->uuid, &char_id.char_id);
LOG_DEBUG("%s: BTA_GATTC_WriteCharValue::", __FUNCTION__);
BTA_GATTC_WriteCharValue(p_cb->conn_id,
&char_id,
write_type, /* default to use write request */ //之前reportid 0x5b的patch使 write_type为BTA_GATTC_TYPE_WRITE_NO_RSP
p_buf->len,
p_value,
BTA_GATT_AUTH_REQ_NONE);
}
-->
/*******************************************************************************
**
** Function BTA_GATTC_WriteCharValue
**
** Description This function is called to write characteristic value.
**
** Parameters conn_id - connection ID.
** p_char_id - characteristic ID to write.
** write_type - type of write.
** len: length of the data to be written.
** p_value - the value to be written.
**
** Returns None
**
*******************************************************************************/
void BTA_GATTC_WriteCharValue ( UINT16 conn_id,
tBTA_GATTC_CHAR_ID *p_char_id,
tBTA_GATTC_WRITE_TYPE write_type,
UINT16 len,
UINT8 *p_value,
tBTA_GATT_AUTH_REQ auth_req)
{
tBTA_GATTC_API_WRITE *p_buf;
if ((p_buf = (tBTA_GATTC_API_WRITE *) GKI_getbuf((UINT16)(sizeof(tBTA_GATTC_API_WRITE) + len))) != NULL)
{
memset(p_buf, 0, sizeof(tBTA_GATTC_API_WRITE) + len);
p_buf->hdr.event = BTA_GATTC_API_WRITE_EVT;
p_buf->hdr.layer_specific = conn_id;
p_buf->auth_req = auth_req;
memcpy(&p_buf->srvc_id, &p_char_id->srvc_id, sizeof(tBTA_GATT_SRVC_ID));
memcpy(&p_buf->char_id, &p_char_id->char_id, sizeof(tBTA_GATT_ID));
APPL_TRACE_DEBUG("BTA_GATTC_WriteCharValue : write_type=%d",write_type);
p_buf->write_type = write_type;
p_buf->len = len;
if (p_value && len > 0)
{
p_buf->p_value = (UINT8 *)(p_buf + 1);
memcpy(p_buf->p_value, p_value, len);
}
bta_sys_sendmsg(p_buf); //设置数据类型后发送到gatt层
}
return;
}
应用层传下来的消息到GATT层:
external\bluetooth\bluedroid\stack\btu\btu_task.c
/*******************************************************************************
**
** Function btu_task
**
** Description This is the main task of the Bluetooth Upper Layers unit.
** It sits in a loop waiting for messages, and dispatches them
** to the appropiate handlers.
**
** Returns should never return
**
*******************************************************************************/
BTU_API UINT32 btu_task (UINT32 param)
{
UINT16 event;
BT_HDR *p_msg;
UINT8 i;
UINT16 mask;
BOOLEAN handled;
UNUSED(param);
#if (defined(HCISU_H4_INCLUDED) && HCISU_H4_INCLUDED == TRUE)
/* wait an event that HCISU is ready */
BT_TRACE(TRACE_LAYER_BTU, TRACE_TYPE_API,
"btu_task pending for preload complete event");
for (;;)
{
event = GKI_wait (0xFFFF, 0);
if (event & EVENT_MASK(GKI_SHUTDOWN_EVT))
{
/* indicates BT ENABLE abort */
BT_TRACE(TRACE_LAYER_BTU, TRACE_TYPE_WARNING,
"btu_task start abort!");
return (0);
}
else if (event & BT_EVT_PRELOAD_CMPL)
{
break;
}
else
{
BT_TRACE(TRACE_LAYER_BTU, TRACE_TYPE_WARNING,
"btu_task ignore evt %04x while pending for preload complete",
event);
}
}
BT_TRACE(TRACE_LAYER_BTU, TRACE_TYPE_API,
"btu_task received preload complete event");
#endif
/* Initialize the mandatory core stack control blocks
(BTU, BTM, L2CAP, and SDP)
*/
btu_init_core();
/* Initialize any optional stack components */
BTE_InitStack();
#if (defined(BTU_BTA_INCLUDED) && BTU_BTA_INCLUDED == TRUE)
bta_sys_init();
#endif
/* Initialise platform trace levels at this point as BTE_InitStack() and bta_sys_init()
* reset the control blocks and preset the trace level with XXX_INITIAL_TRACE_LEVEL
*/
#if ( BT_USE_TRACES==TRUE )
BTE_InitTraceLevels();
#endif
/* Send a startup evt message to BTIF_TASK to kickstart the init procedure */
GKI_send_event(BTIF_TASK, BT_EVT_TRIGGER_STACK_INIT);
prctl(PR_SET_NAME, (unsigned long)"BTU TASK", 0, 0, 0);
raise_priority_a2dp(TASK_HIGH_BTU);
/* Wait for, and process, events */
for (;;)
{
event = GKI_wait (0xFFFF, 0);
if (event & TASK_MBOX_0_EVT_MASK)
{
/* Process all messages in the queue */
while ((p_msg = (BT_HDR *) GKI_read_mbox (BTU_HCI_RCV_MBOX)) != NULL)
{
/* Determine the input message type. */
switch (p_msg->event & BT_EVT_MASK)
{
case BT_EVT_TO_BTU_HCI_ACL:
/* All Acl Data goes to L2CAP */
l2c_rcv_acl_data (p_msg);
break;
case BT_EVT_TO_BTU_L2C_SEG_XMIT:
/* L2CAP segment transmit complete */
l2c_link_segments_xmitted (p_msg);
break;
case BT_EVT_TO_BTU_HCI_SCO:
#if BTM_SCO_INCLUDED == TRUE
btm_route_sco_data (p_msg);
break;
#endif
case BT_EVT_TO_BTU_HCI_EVT:
btu_hcif_process_event ((UINT8)(p_msg->event & BT_SUB_EVT_MASK), p_msg);
GKI_freebuf(p_msg);
#if (defined(HCILP_INCLUDED) && HCILP_INCLUDED == TRUE)
/* If host receives events which it doesn't response to, */
/* host should start idle timer to enter sleep mode. */
btu_check_bt_sleep ();
#endif
break;
case BT_EVT_TO_BTU_HCI_CMD:
btu_hcif_send_cmd ((UINT8)(p_msg->event & BT_SUB_EVT_MASK), p_msg);
break;
#if (defined(OBX_INCLUDED) && OBX_INCLUDED == TRUE)
#if (defined(OBX_SERVER_INCLUDED) && OBX_SERVER_INCLUDED == TRUE)
case BT_EVT_TO_OBX_SR_MSG:
obx_sr_proc_evt((tOBX_PORT_EVT *)(p_msg + 1));
GKI_freebuf (p_msg);
break;
case BT_EVT_TO_OBX_SR_L2C_MSG:
obx_sr_proc_l2c_evt((tOBX_L2C_EVT_MSG *)(p_msg + 1));
GKI_freebuf (p_msg);
break;
#endif
#if (defined(OBX_CLIENT_INCLUDED) && OBX_CLIENT_INCLUDED == TRUE)
case BT_EVT_TO_OBX_CL_MSG:
obx_cl_proc_evt((tOBX_PORT_EVT *)(p_msg + 1));
GKI_freebuf (p_msg);
break;
case BT_EVT_TO_OBX_CL_L2C_MSG:
obx_cl_proc_l2c_evt((tOBX_L2C_EVT_MSG *)(p_msg + 1));
GKI_freebuf (p_msg);
break;
#endif
#if (defined(BIP_INCLUDED) && BIP_INCLUDED == TRUE)
case BT_EVT_TO_BIP_CMDS :
bip_proc_btu_event(p_msg);
GKI_freebuf (p_msg);
break;
#endif /* BIP */
#if (BPP_SND_INCLUDED == TRUE || BPP_INCLUDED == TRUE)
case BT_EVT_TO_BPP_PR_CMDS:
bpp_pr_proc_event(p_msg);
GKI_freebuf (p_msg);
break;
case BT_EVT_TO_BPP_SND_CMDS:
bpp_snd_proc_event(p_msg);
GKI_freebuf (p_msg);
break;
#endif /* BPP */
#endif /* OBX */
#if (defined(SAP_SERVER_INCLUDED) && SAP_SERVER_INCLUDED == TRUE)
case BT_EVT_TO_BTU_SAP :
sap_proc_btu_event(p_msg);
GKI_freebuf (p_msg);
break;
#endif /* SAP */
#if (defined(GAP_CONN_INCLUDED) && GAP_CONN_INCLUDED == TRUE && GAP_CONN_POST_EVT_INCLUDED == TRUE)
case BT_EVT_TO_GAP_MSG :
gap_proc_btu_event(p_msg);
GKI_freebuf (p_msg);
break;
#endif
case BT_EVT_TO_START_TIMER :
/* Start free running 1 second timer for list management */
GKI_start_timer (TIMER_0, GKI_SECS_TO_TICKS (1), TRUE);
GKI_freebuf (p_msg);
break;
case BT_EVT_TO_STOP_TIMER:
if (GKI_timer_queue_is_empty(&btu_cb.timer_queue)) {
GKI_stop_timer(TIMER_0);
}
GKI_freebuf (p_msg);
break;
case BT_EVT_TO_START_TIMER_ONESHOT:
if (!GKI_timer_queue_is_empty(&btu_cb.timer_queue_oneshot)) {
TIMER_LIST_ENT *tle = GKI_timer_getfirst(&btu_cb.timer_queue_oneshot);
// Start non-repeating timer.
GKI_start_timer(TIMER_3, tle->ticks, FALSE);
} else {
BTM_TRACE_WARNING("Oneshot timer queue empty when received start request");
}
GKI_freebuf(p_msg);
break;
case BT_EVT_TO_STOP_TIMER_ONESHOT:
if (GKI_timer_queue_is_empty(&btu_cb.timer_queue_oneshot)) {
GKI_stop_timer(TIMER_3);
} else {
BTM_TRACE_WARNING("Oneshot timer queue not empty when received stop request");
}
GKI_freebuf (p_msg);
break;
#if defined(QUICK_TIMER_TICKS_PER_SEC) && (QUICK_TIMER_TICKS_PER_SEC > 0)
case BT_EVT_TO_START_QUICK_TIMER :
GKI_start_timer (TIMER_2, QUICK_TIMER_TICKS, TRUE);
GKI_freebuf (p_msg);
break;
#endif
default:
i = 0;
mask = (UINT16) (p_msg->event & BT_EVT_MASK);
handled = FALSE;
for (; !handled && i < BTU_MAX_REG_EVENT; i++)
{
if (btu_cb.event_reg[i].event_cb == NULL)
continue;
if (mask == btu_cb.event_reg[i].event_range)
{
if (btu_cb.event_reg[i].event_cb)
{
btu_cb.event_reg[i].event_cb(p_msg);
handled = TRUE;
}
}
}
if (handled == FALSE)
GKI_freebuf (p_msg);
break;
}
}
}
if (event & TIMER_0_EVT_MASK) {
GKI_update_timer_list (&btu_cb.timer_queue, 1);
while (!GKI_timer_queue_is_empty(&btu_cb.timer_queue)) {
TIMER_LIST_ENT *p_tle = GKI_timer_getfirst(&btu_cb.timer_queue);
if (p_tle->ticks != 0)
break;
GKI_remove_from_timer_list(&btu_cb.timer_queue, p_tle);
switch (p_tle->event) {
case BTU_TTYPE_BTM_DEV_CTL:
btm_dev_timeout(p_tle);
break;
case BTU_TTYPE_BTM_ACL:
btm_acl_timeout(p_tle);
break;
case BTU_TTYPE_L2CAP_LINK:
case BTU_TTYPE_L2CAP_CHNL:
case BTU_TTYPE_L2CAP_HOLD:
case BTU_TTYPE_L2CAP_INFO:
case BTU_TTYPE_L2CAP_FCR_ACK:
l2c_process_timeout (p_tle);
break;
case BTU_TTYPE_SDP:
sdp_conn_timeout ((tCONN_CB *)p_tle->param);
break;
case BTU_TTYPE_BTM_RMT_NAME:
btm_inq_rmt_name_failed();
break;
#if (defined(RFCOMM_INCLUDED) && RFCOMM_INCLUDED == TRUE)
case BTU_TTYPE_RFCOMM_MFC:
case BTU_TTYPE_RFCOMM_PORT:
rfcomm_process_timeout (p_tle);
break;
#endif /* If defined(RFCOMM_INCLUDED) && RFCOMM_INCLUDED == TRUE */
#if ((defined(BNEP_INCLUDED) && BNEP_INCLUDED == TRUE))
case BTU_TTYPE_BNEP:
bnep_process_timeout(p_tle);
break;
#endif
#if (defined(AVDT_INCLUDED) && AVDT_INCLUDED == TRUE)
case BTU_TTYPE_AVDT_CCB_RET:
case BTU_TTYPE_AVDT_CCB_RSP:
case BTU_TTYPE_AVDT_CCB_IDLE:
case BTU_TTYPE_AVDT_SCB_TC:
avdt_process_timeout(p_tle);
break;
#endif
#if (defined(OBX_INCLUDED) && OBX_INCLUDED == TRUE)
#if (defined(OBX_CLIENT_INCLUDED) && OBX_CLIENT_INCLUDED == TRUE)
case BTU_TTYPE_OBX_CLIENT_TO:
obx_cl_timeout(p_tle);
break;
#endif
#if (defined(OBX_SERVER_INCLUDED) && OBX_SERVER_INCLUDED == TRUE)
case BTU_TTYPE_OBX_SERVER_TO:
obx_sr_timeout(p_tle);
break;
case BTU_TTYPE_OBX_SVR_SESS_TO:
obx_sr_sess_timeout(p_tle);
break;
#endif
#endif
#if (defined(SAP_SERVER_INCLUDED) && SAP_SERVER_INCLUDED == TRUE)
case BTU_TTYPE_SAP_TO:
sap_process_timeout(p_tle);
break;
#endif
case BTU_TTYPE_BTU_CMD_CMPL:
btu_hcif_cmd_timeout((UINT8)(p_tle->event - BTU_TTYPE_BTU_CMD_CMPL));
break;
#if (defined(HID_HOST_INCLUDED) && HID_HOST_INCLUDED == TRUE)
case BTU_TTYPE_HID_HOST_REPAGE_TO :
hidh_proc_repage_timeout(p_tle);
break;
#endif
#if (defined(BLE_INCLUDED) && BLE_INCLUDED == TRUE)
case BTU_TTYPE_BLE_INQUIRY:
case BTU_TTYPE_BLE_GAP_LIM_DISC:
case BTU_TTYPE_BLE_GAP_FAST_ADV:
case BTU_TTYPE_BLE_OBSERVE:
btm_ble_timeout(p_tle);
break;
case BTU_TTYPE_ATT_WAIT_FOR_RSP:
gatt_rsp_timeout(p_tle);
break;
case BTU_TTYPE_ATT_WAIT_FOR_IND_ACK:
gatt_ind_ack_timeout(p_tle);
break;
#if (defined(SMP_INCLUDED) && SMP_INCLUDED == TRUE)
case BTU_TTYPE_SMP_PAIRING_CMD:
smp_rsp_timeout(p_tle);
break;
#endif
#endif
#if (MCA_INCLUDED == TRUE)
case BTU_TTYPE_MCA_CCB_RSP:
mca_process_timeout(p_tle);
break;
#endif
case BTU_TTYPE_USER_FUNC:
{
tUSER_TIMEOUT_FUNC *p_uf = (tUSER_TIMEOUT_FUNC *)p_tle->param;
(*p_uf)(p_tle);
}
break;
default:
i = 0;
handled = FALSE;
for (; !handled && i < BTU_MAX_REG_TIMER; i++)
{
if (btu_cb.timer_reg[i].timer_cb == NULL)
continue;
if (btu_cb.timer_reg[i].p_tle == p_tle)
{
btu_cb.timer_reg[i].timer_cb(p_tle);
handled = TRUE;
}
}
break;
}
}
/* if timer list is empty stop periodic GKI timer */
if (btu_cb.timer_queue.p_first == NULL)
{
GKI_stop_timer(TIMER_0);
}
}
#if defined(QUICK_TIMER_TICKS_PER_SEC) && (QUICK_TIMER_TICKS_PER_SEC > 0)
if (event & TIMER_2_EVT_MASK)
{
btu_process_quick_timer_evt();
}
#endif
#if (RPC_INCLUDED == TRUE)
/* if RPC message queue event */
if (event & RPCGEN_MSG_EVT)
{
if ((p_msg = (BT_HDR *) GKI_read_mbox(RPCGEN_MSG_MBOX)) != NULL)
RPCT_RpcgenMsg(p_msg); /* handle RPC message queue */
}
#endif
#if (defined(BTU_BTA_INCLUDED) && BTU_BTA_INCLUDED == TRUE)
if (event & TASK_MBOX_2_EVT_MASK)
{
while ((p_msg = (BT_HDR *) GKI_read_mbox(TASK_MBOX_2)) != NULL)
{
bta_sys_event(p_msg); //处理上层传来的消息
}
}
if (event & TIMER_1_EVT_MASK)
{
bta_sys_timer_update();
}
#endif
if (event & TIMER_3_EVT_MASK) {
BTM_TRACE_API("Received oneshot timer event complete");
if (!GKI_timer_queue_is_empty(&btu_cb.timer_queue_oneshot)) {
TIMER_LIST_ENT *p_tle = GKI_timer_getfirst(&btu_cb.timer_queue_oneshot);
INT32 ticks_since_last_update = GKI_timer_ticks_getinitial(GKI_timer_getfirst(&btu_cb.timer_queue_oneshot));
GKI_update_timer_list(&btu_cb.timer_queue_oneshot, ticks_since_last_update);
}
while (!GKI_timer_queue_is_empty(&btu_cb.timer_queue_oneshot)) {
TIMER_LIST_ENT *p_tle = GKI_timer_getfirst(&btu_cb.timer_queue_oneshot);
if (p_tle->ticks != 0)
break;
GKI_remove_from_timer_list(&btu_cb.timer_queue_oneshot, p_tle);
switch (p_tle->event) {
#if (defined(BLE_INCLUDED) && BLE_INCLUDED == TRUE)
case BTU_TTYPE_BLE_RANDOM_ADDR:
btm_ble_timeout(p_tle);
break;
#endif
case BTU_TTYPE_USER_FUNC:
{
tUSER_TIMEOUT_FUNC *p_uf = (tUSER_TIMEOUT_FUNC *)p_tle->param;
(*p_uf)(p_tle);
}
break;
default:
// FAIL
BTM_TRACE_WARNING("Received unexpected oneshot timer event:0x%x\n",
p_tle->event);
break;
}
}
/* Update GKI timer with new tick value from first timer. */
if (!GKI_timer_queue_is_empty(&btu_cb.timer_queue_oneshot)) {
TIMER_LIST_ENT *p_tle = GKI_timer_getfirst(&btu_cb.timer_queue_oneshot);
if (p_tle->ticks > 0)
GKI_start_timer(TIMER_3, p_tle->ticks, FALSE);
} else {
GKI_stop_timer(TIMER_3);
}
}
if (event & EVENT_MASK(APPL_EVT_7))
break;
}
return(0);
}
应用层注册的回调函数被调用:
/*******************************************************************************
**
** Function bta_sys_event
**
** Description BTA event handler; called from task event handler.
**
**
** Returns void
**
*******************************************************************************/
BTA_API void bta_sys_event(BT_HDR *p_msg)
{
UINT8 id;
BOOLEAN freebuf = TRUE;
APPL_TRACE_EVENT("BTA got event 0x%x", p_msg->event); //event = BTA_HH_API_WRITE_DEV_EVT
/* get subsystem id from event */
id = (UINT8) (p_msg->event >> 8);
/* verify id and call subsystem event handler */
if ((id < BTA_ID_MAX) && (bta_sys_cb.reg[id] != NULL))
{
freebuf = (*bta_sys_cb.reg[id]->evt_hdlr)(p_msg); //Id为0x17,即BTA_ID_HH,回调函数为bta_hh_hdl_event,前面已分析
//Id为0x1f,即为BTA_ID_GATTC,回调函数为bta_gattc_hdl_event,继续往后看
}
else
{
APPL_TRACE_WARNING("BTA got unregistered event id %d", id);
}
if (freebuf)
{
GKI_freebuf(p_msg);
}
}
gatt client事件处理函数:
/*******************************************************************************
**
** Function bta_gattc_hdl_event
**
** Description GATT client main event handling function.
**
**
** Returns BOOLEAN
**
*******************************************************************************/
BOOLEAN bta_gattc_hdl_event(BT_HDR *p_msg)
{
tBTA_GATTC_CB *p_cb = &bta_gattc_cb;
tBTA_GATTC_CLCB *p_clcb = NULL;
tBTA_GATTC_RCB *p_clreg;
BOOLEAN rt = TRUE;
#if BTA_GATT_DEBUG == TRUE
APPL_TRACE_DEBUG("bta_gattc_hdl_event: Event [%s]", gattc_evt_code(p_msg->event));
#endif
switch (p_msg->event)
{
case BTA_GATTC_API_DISABLE_EVT:
bta_gattc_disable(p_cb);
break;
case BTA_GATTC_API_REG_EVT:
bta_gattc_register(p_cb, (tBTA_GATTC_DATA *) p_msg);
break;
case BTA_GATTC_INT_START_IF_EVT:
bta_gattc_start_if(p_cb, (tBTA_GATTC_DATA *) p_msg);
break;
case BTA_GATTC_API_DEREG_EVT:
p_clreg = bta_gattc_cl_get_regcb(((tBTA_GATTC_DATA *)p_msg)->api_dereg.client_if);
bta_gattc_deregister(p_cb, p_clreg);
break;
case BTA_GATTC_API_OPEN_EVT:
bta_gattc_process_api_open(p_cb, (tBTA_GATTC_DATA *) p_msg);
break;
case BTA_GATTC_API_CANCEL_OPEN_EVT:
bta_gattc_process_api_open_cancel(p_cb, (tBTA_GATTC_DATA *) p_msg);
break;
case BTA_GATTC_API_REFRESH_EVT:
bta_gattc_process_api_refresh(p_cb, (tBTA_GATTC_DATA *) p_msg);
break;
#if BLE_INCLUDED == TRUE
case BTA_GATTC_API_LISTEN_EVT:
bta_gattc_listen(p_cb, (tBTA_GATTC_DATA *) p_msg);
break;
case BTA_GATTC_API_BROADCAST_EVT:
bta_gattc_broadcast(p_cb, (tBTA_GATTC_DATA *) p_msg);
break;
#endif
case BTA_GATTC_ENC_CMPL_EVT:
bta_gattc_process_enc_cmpl(p_cb, (tBTA_GATTC_DATA *) p_msg);
break;
default:
if (p_msg->event == BTA_GATTC_INT_CONN_EVT)
p_clcb = bta_gattc_find_int_conn_clcb((tBTA_GATTC_DATA *) p_msg);
else if (p_msg->event == BTA_GATTC_INT_DISCONN_EVT)
p_clcb = bta_gattc_find_int_disconn_clcb((tBTA_GATTC_DATA *) p_msg);
else
p_clcb = bta_gattc_find_clcb_by_conn_id(p_msg->layer_specific);
if (p_clcb != NULL)
{
rt = bta_gattc_sm_execute(p_clcb, p_msg->event, (tBTA_GATTC_DATA *) p_msg); //事件处理
}
else
{
APPL_TRACE_DEBUG("Ignore unknown conn ID: %d", p_msg->layer_specific);
}
break;
}
return rt;
}
gatt client事件处理状态机
/*******************************************************************************
**
** Function bta_gattc_sm_execute
**
** Description State machine event handling function for GATTC
**
**
** Returns BOOLEAN : TRUE if queued client request buffer can be immediately released
** else FALSE
**
*******************************************************************************/
BOOLEAN bta_gattc_sm_execute(tBTA_GATTC_CLCB *p_clcb, UINT16 event, tBTA_GATTC_DATA *p_data)
{
tBTA_GATTC_ST_TBL state_table;
UINT8 action;
int i;
BOOLEAN rt = TRUE;
#if BTA_GATT_DEBUG == TRUE
tBTA_GATTC_STATE in_state = p_clcb->state;
UINT16 in_event = event;
APPL_TRACE_DEBUG("bta_gattc_sm_execute: State 0x%02x [%s], Event 0x%x[%s]", in_state,
gattc_state_code(in_state),
in_event,
gattc_evt_code(in_event));
#endif
/* look up the state table for the current state */
state_table = bta_gattc_st_tbl[p_clcb->state];
event &= 0x00FF;
/* set next state */
p_clcb->state = state_table[event][BTA_GATTC_NEXT_STATE];
/* execute action functions */
for (i = 0; i < BTA_GATTC_ACTIONS; i++)
{
if ((action = state_table[event][i]) != BTA_GATTC_IGNORE)
{
(*bta_gattc_action[action])(p_clcb, p_data); //执行bta_gattc_write,
if (p_clcb->p_q_cmd == p_data) {
/* buffer is queued, don't free in the bta dispatcher.
* we free it ourselves when a completion event is received.
*/
rt = FALSE;
}
}
else
{
break;
}
}
#if BTA_GATT_DEBUG == TRUE
if (in_state != p_clcb->state)
{
APPL_TRACE_DEBUG("GATTC [%d] State Change: [%s] -> [%s] after Event [%s]",p_clcb->bta_conn_id,
gattc_state_code(in_state),
gattc_state_code(p_clcb->state),
gattc_evt_code(in_event));
}
#endif
return rt;
}
->
/*******************************************************************************
**
** Function bta_gattc_write
**
** Description Write an attribute
**
** Returns None.
**
*******************************************************************************/
void bta_gattc_write(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data)
{
UINT16 handle = 0;
tGATT_VALUE attr = {0};
tBTA_GATTC_OP_CMPL op_cmpl;
tBTA_GATT_STATUS status = BTA_GATT_OK;
if (bta_gattc_enqueue(p_clcb, p_data))
{
if ((handle = bta_gattc_id2handle(p_clcb->p_srcb,
&p_data->api_write.srvc_id,
&p_data->api_write.char_id,
p_data->api_write.p_descr_type)) == 0)
{
status = BTA_GATT_ERROR;
}
else
{
attr.handle= handle;
attr.offset = p_data->api_write.offset;
attr.len = p_data->api_write.len;
attr.auth_req = p_data->api_write.auth_req;
if (p_data->api_write.p_value)
memcpy(attr.value, p_data->api_write.p_value, p_data->api_write.len);
status = GATTC_Write(p_clcb->bta_conn_id, p_data->api_write.write_type, &attr);
}
/* write fail */
if (status != BTA_GATT_OK)
{
memset(&op_cmpl, 0, sizeof(tBTA_GATTC_OP_CMPL));
op_cmpl.status = status;
op_cmpl.op_code = GATTC_OPTYPE_WRITE;
op_cmpl.p_cmpl = NULL;
bta_gattc_sm_execute(p_clcb, BTA_GATTC_OP_CMPL_EVT, (tBTA_GATTC_DATA *)&op_cmpl);
}
}
}
->
/*******************************************************************************
**
** Function GATTC_Write
**
** Description This function is called to write the value of an attribute to
** the server.
**
** Parameters conn_id: connection identifier.
** type - attribute write type.
** p_write - write operation parameters.
**
** Returns GATT_SUCCESS if command started successfully.
**
*******************************************************************************/
tGATT_STATUS GATTC_Write (UINT16 conn_id, tGATT_WRITE_TYPE type, tGATT_VALUE *p_write)
{
tGATT_STATUS status = GATT_SUCCESS;
tGATT_CLCB *p_clcb;
tGATT_VALUE *p;
tGATT_IF gatt_if=GATT_GET_GATT_IF(conn_id);
UINT8 tcb_idx = GATT_GET_TCB_IDX(conn_id);
tGATT_TCB *p_tcb = gatt_get_tcb_by_idx(tcb_idx);
tGATT_REG *p_reg = gatt_get_regcb(gatt_if);
if ( (p_tcb == NULL) || (p_reg==NULL) || (p_write == NULL) ||
((type != GATT_WRITE) && (type != GATT_WRITE_PREPARE) && (type != GATT_WRITE_NO_RSP)) )
{
GATT_TRACE_ERROR("GATT_Write Illegal param: conn_id %d, type 0%d,", conn_id, type);
return GATT_ILLEGAL_PARAMETER;
}
if (gatt_is_clcb_allocated(conn_id))
{
GATT_TRACE_ERROR("GATTC_Write GATT_BUSY conn_id = %d", conn_id);
return GATT_BUSY;
}
if ((p_clcb = gatt_clcb_alloc(conn_id)) != NULL )
{
p_clcb->operation = GATTC_OPTYPE_WRITE;
p_clcb->op_subtype = type;
p_clcb->auth_req = p_write->auth_req;
if (( p_clcb->p_attr_buf = (UINT8 *)GKI_getbuf((UINT16)sizeof(tGATT_VALUE))) != NULL)
{
memcpy(p_clcb->p_attr_buf, (void *)p_write, sizeof(tGATT_VALUE));
p = (tGATT_VALUE *)p_clcb->p_attr_buf;
if (type == GATT_WRITE_PREPARE)
{
p_clcb->start_offset = p_write->offset;
p->offset = 0;
}
if (gatt_security_check_start(p_clcb) == FALSE)
{
status = GATT_NO_RESOURCES;
}
}
else
{
status = GATT_NO_RESOURCES;
}
if (status == GATT_NO_RESOURCES)
gatt_clcb_dealloc(p_clcb);
}
else
{
status = GATT_NO_RESOURCES;
}
return status;
}
->
/*******************************************************************************
**
** Function gatt_check_enc_req
**
** Description check link security.
**
** Returns TRUE if encrypted, otherwise FALSE.
**
*******************************************************************************/
BOOLEAN gatt_security_check_start(tGATT_CLCB *p_clcb)
{
tGATT_TCB *p_tcb = p_clcb->p_tcb;
tGATT_SEC_ACTION gatt_sec_act;
tBTM_BLE_SEC_ACT btm_ble_sec_act;
BOOLEAN status = TRUE;
tBTM_STATUS btm_status;
tGATT_SEC_ACTION sec_act_old = gatt_get_sec_act(p_tcb);
gatt_sec_act = gatt_determine_sec_act(p_clcb);
if (sec_act_old == GATT_SEC_NONE)
gatt_set_sec_act(p_tcb, gatt_sec_act);
switch (gatt_sec_act )
{
case GATT_SEC_SIGN_DATA:
GATT_TRACE_DEBUG("gatt_security_check_start: Do data signing");
gatt_sign_data(p_clcb);
break;
case GATT_SEC_ENCRYPT:
case GATT_SEC_ENCRYPT_NO_MITM:
case GATT_SEC_ENCRYPT_MITM:
if (sec_act_old < GATT_SEC_ENCRYPT)
{
GATT_TRACE_DEBUG("gatt_security_check_start: Encrypt now or key upgreade first");
gatt_convert_sec_action(gatt_sec_act, &btm_ble_sec_act);
btm_status = BTM_SetEncryption(p_tcb->peer_bda, p_tcb->transport , gatt_enc_cmpl_cback, &btm_ble_sec_act);
if ( (btm_status != BTM_SUCCESS) && (btm_status != BTM_CMD_STARTED))
{
GATT_TRACE_ERROR("gatt_security_check_start BTM_SetEncryption failed btm_status=%d", btm_status);
status = FALSE;
}
}
if (status)
gatt_add_pending_enc_channel_clcb (p_tcb, p_clcb);
break;
case GATT_SEC_ENC_PENDING:
gatt_add_pending_enc_channel_clcb (p_tcb, p_clcb);
/* wait for link encrypotion to finish */
break;
default:
gatt_sec_check_complete(TRUE, p_clcb, gatt_sec_act);
break;
}
if (status == FALSE)
{
gatt_set_sec_act(p_tcb, GATT_SEC_NONE);
gatt_set_ch_state(p_tcb, GATT_CH_OPEN);
}
return status;
}
->
/*******************************************************************************
**
** Function gatt_sec_check_complete
**
** Description security check complete and proceed to data sending action.
**
** Returns void.
**
*******************************************************************************/
void gatt_sec_check_complete(BOOLEAN sec_check_ok, tGATT_CLCB *p_clcb, UINT8 sec_act)
{
if (p_clcb && p_clcb->p_tcb && GKI_queue_is_empty(&p_clcb->p_tcb->pending_enc_clcb))
gatt_set_sec_act(p_clcb->p_tcb, GATT_SEC_NONE);
if (!sec_check_ok)
{
gatt_end_operation(p_clcb, GATT_AUTH_FAIL, NULL);
}
else if (p_clcb->operation == GATTC_OPTYPE_WRITE)
{
gatt_act_write(p_clcb, sec_act);
}
else if (p_clcb->operation == GATTC_OPTYPE_READ)
{
gatt_act_read(p_clcb, p_clcb->counter);
}
}
->
/*******************************************************************************
**
** Function gatt_act_write
**
** Description GATT write operation.
**
** Returns void.
**
*******************************************************************************/
void gatt_act_write (tGATT_CLCB *p_clcb, UINT8 sec_act)
{
tGATT_TCB *p_tcb = p_clcb->p_tcb;
UINT8 rt = GATT_SUCCESS, op_code = 0;
tGATT_VALUE *p_attr = (tGATT_VALUE *)p_clcb->p_attr_buf;
if (p_attr)
{
switch (p_clcb->op_subtype)
{
case GATT_WRITE_NO_RSP:
p_clcb->s_handle = p_attr->handle;
op_code = (sec_act == GATT_SEC_SIGN_DATA) ? GATT_SIGN_CMD_WRITE : GATT_CMD_WRITE;
rt = gatt_send_write_msg(p_tcb,
p_clcb->clcb_idx,
op_code,
p_attr->handle,
p_attr->len,
0,
p_attr->value);
break;
case GATT_WRITE:
if (p_attr->len <= (p_tcb->payload_size - GATT_HDR_SIZE))
{
p_clcb->s_handle = p_attr->handle;
rt = gatt_send_write_msg(p_tcb,
p_clcb->clcb_idx,
GATT_REQ_WRITE,
p_attr->handle,
p_attr->len,
0,
p_attr->value);
}
else /* prepare write for long attribute */
{
gatt_send_prepare_write(p_tcb, p_clcb);
}
break;
case GATT_WRITE_PREPARE:
gatt_send_prepare_write(p_tcb, p_clcb);
break;
default:
rt = GATT_INTERNAL_ERROR;
GATT_TRACE_ERROR("Unknown write type: %d", p_clcb->op_subtype);
break;
}
}
else
rt = GATT_INTERNAL_ERROR;
if ((rt != GATT_SUCCESS && rt != GATT_CMD_STARTED && rt != GATT_CONGESTED)
|| (rt != GATT_CMD_STARTED && p_clcb->op_subtype == GATT_WRITE_NO_RSP))
{
if (rt != GATT_SUCCESS)
{
GATT_TRACE_ERROR("gatt_act_write() failed op_code=0x%x", op_code);
}
gatt_end_operation(p_clcb, rt, NULL);
}
}
->
/*******************************************************************************
**
** Function gatt_send_write_msg
**
** Description This real function send out the ATT message for write.
**
** Returns status code
**
*******************************************************************************/
UINT8 gatt_send_write_msg (tGATT_TCB *p_tcb, UINT16 clcb_idx, UINT8 op_code,
UINT16 handle, UINT16 len,
UINT16 offset, UINT8 *p_data)
{
tGATT_CL_MSG msg;
msg.attr_value.handle = handle;
msg.attr_value.len = len;
msg.attr_value.offset = offset;
memcpy (msg.attr_value.value, p_data, len);
/* write by handle */
return attp_send_cl_msg(p_tcb, clcb_idx, op_code, &msg);
}
->
/*******************************************************************************
**
** Function attp_send_cl_msg
**
** Description This function sends the client request or confirmation message
** to server.
**
** Parameter p_tcb: pointer to the connectino control block.
** clcb_idx: clcb index
** op_code: message op code.
** p_msg: pointer to message parameters structure.
**
** Returns GATT_SUCCESS if sucessfully sent; otherwise error code.
**
**
*******************************************************************************/
tGATT_STATUS attp_send_cl_msg (tGATT_TCB *p_tcb, UINT16 clcb_idx, UINT8 op_code, tGATT_CL_MSG *p_msg)
{
tGATT_STATUS status = GATT_NO_RESOURCES;
BT_HDR *p_cmd = NULL;
UINT16 offset = 0, handle;
if (p_tcb != NULL)
{
switch (op_code)
{
case GATT_REQ_MTU:
if (p_msg->mtu <= GATT_MAX_MTU_SIZE)
{
p_tcb->payload_size = p_msg->mtu;
p_cmd = attp_build_mtu_cmd(GATT_REQ_MTU, p_msg->mtu);
}
else
status = GATT_ILLEGAL_PARAMETER;
break;
case GATT_REQ_FIND_INFO:
case GATT_REQ_READ_BY_TYPE:
case GATT_REQ_READ_BY_GRP_TYPE:
if (GATT_HANDLE_IS_VALID (p_msg->browse.s_handle) &&
GATT_HANDLE_IS_VALID (p_msg->browse.e_handle) &&
p_msg->browse.s_handle <= p_msg->browse.e_handle)
{
p_cmd = attp_build_browse_cmd(op_code,
p_msg->browse.s_handle,
p_msg->browse.e_handle,
p_msg->browse.uuid);
}
else
status = GATT_ILLEGAL_PARAMETER;
break;
case GATT_REQ_READ_BLOB:
offset = p_msg->read_blob.offset;
/* fall through */
case GATT_REQ_READ:
handle = (op_code == GATT_REQ_READ) ? p_msg->handle: p_msg->read_blob.handle;
/* handle checking */
if (GATT_HANDLE_IS_VALID (handle))
{
p_cmd = attp_build_handle_cmd(op_code, handle, offset);
}
else
status = GATT_ILLEGAL_PARAMETER;
break;
case GATT_HANDLE_VALUE_CONF:
p_cmd = attp_build_opcode_cmd(op_code);
break;
case GATT_REQ_PREPARE_WRITE:
offset = p_msg->attr_value.offset;
/* fall through */
case GATT_REQ_WRITE:
case GATT_CMD_WRITE:
case GATT_SIGN_CMD_WRITE:
if (GATT_HANDLE_IS_VALID (p_msg->attr_value.handle))
{
//先调用这里
p_cmd = attp_build_value_cmd (p_tcb->payload_size,
op_code, p_msg->attr_value.handle,
offset,
p_msg->attr_value.len,
p_msg->attr_value.value);
}
else
status = GATT_ILLEGAL_PARAMETER;
break;
case GATT_REQ_EXEC_WRITE:
p_cmd = attp_build_exec_write_cmd(op_code, p_msg->exec_write);
break;
case GATT_REQ_FIND_TYPE_VALUE:
p_cmd = attp_build_read_by_type_value_cmd(p_tcb->payload_size, &p_msg->find_type_value);
break;
case GATT_REQ_READ_MULTI:
p_cmd = attp_build_read_multi_cmd(p_tcb->payload_size,
p_msg->read_multi.num_handles,
p_msg->read_multi.handles);
break;
default:
break;
}
//再调用这里
if (p_cmd != NULL)
status = attp_cl_send_cmd(p_tcb, clcb_idx, op_code, p_cmd);
}
else
{
GATT_TRACE_ERROR("Peer device not connected");
}
return status;
}
-->
/*******************************************************************************
**
** Function attp_build_value_cmd
**
** Description Build a attribute value request
**
** Returns None.
**
*******************************************************************************/
BT_HDR *attp_build_value_cmd (UINT16 payload_size, UINT8 op_code, UINT16 handle,
UINT16 offset, UINT16 len, UINT8 *p_data)
{
BT_HDR *p_buf = NULL;
UINT8 *p, *pp, pair_len, *p_pair_len;
if ((p_buf = (BT_HDR *)GKI_getbuf((UINT16)(sizeof(BT_HDR) + payload_size + L2CAP_MIN_OFFSET))) != NULL)
{
p = pp =(UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
UINT8_TO_STREAM (p, op_code);
p_buf->offset = L2CAP_MIN_OFFSET;
p_buf->len = 1;
if (op_code == GATT_RSP_READ_BY_TYPE)
{
p_pair_len = p;
pair_len = len + 2;
UINT8_TO_STREAM (p, pair_len);
p_buf->len += 1;
}
if (op_code != GATT_RSP_READ_BLOB && op_code != GATT_RSP_READ)
{
UINT16_TO_STREAM (p, handle);
p_buf->len += 2;
}
if (op_code == GATT_REQ_PREPARE_WRITE ||op_code == GATT_RSP_PREPARE_WRITE )
{
UINT16_TO_STREAM (p, offset);
p_buf->len += 2;
}
if (len > 0 && p_data != NULL)
{
/* ensure data not exceed MTU size */
if (payload_size - p_buf->len < len)
{
len = payload_size - p_buf->len;
/* update handle value pair length */
if (op_code == GATT_RSP_READ_BY_TYPE)
*p_pair_len = (len + 2);
GATT_TRACE_WARNING("attribute value too long, to be truncated to %d", len);
}
ARRAY_TO_STREAM (p, p_data, len);
p_buf->len += len;
}
}
return p_buf;
}
—>
/*******************************************************************************
**
** Function attp_cl_send_cmd
**
** Description Send a ATT command or enqueue it.
**
** Returns GATT_SUCCESS if command sent
** GATT_CONGESTED if command sent but channel congested
** GATT_CMD_STARTED if command queue up in GATT
** GATT_ERROR if command sending failure
**
*******************************************************************************/
tGATT_STATUS attp_cl_send_cmd(tGATT_TCB *p_tcb, UINT16 clcb_idx, UINT8 cmd_code, BT_HDR *p_cmd)
{
tGATT_STATUS att_ret = GATT_SUCCESS;
if (p_tcb != NULL)
{
cmd_code &= ~GATT_AUTH_SIGN_MASK;
/* no pending request or value confirmation */
if (p_tcb->pending_cl_req == p_tcb->next_slot_inq ||
cmd_code == GATT_HANDLE_VALUE_CONF)
{
att_ret = attp_send_msg_to_l2cap(p_tcb, p_cmd); //发送数据到l2cap层
if (att_ret == GATT_CONGESTED || att_ret == GATT_SUCCESS)
{
/* do not enq cmd if handle value confirmation or set request */
if (cmd_code != GATT_HANDLE_VALUE_CONF && cmd_code != GATT_CMD_WRITE)
{
gatt_start_rsp_timer (clcb_idx); //如果是write request数据类型,则会创建定时器等待respond(5s超时)
gatt_cmd_enq(p_tcb, clcb_idx, FALSE, cmd_code, NULL);
}
}
else
att_ret = GATT_INTERNAL_ERROR;
}
else
{
att_ret = GATT_CMD_STARTED;
gatt_cmd_enq(p_tcb, clcb_idx, TRUE, cmd_code, p_cmd);
}
}
else
att_ret = GATT_ERROR;
return att_ret;
}
->
->
/*******************************************************************************
**
** Function attp_send_msg_to_l2cap
**
** Description Send message to L2CAP.
**
*******************************************************************************/
tGATT_STATUS attp_send_msg_to_l2cap(tGATT_TCB *p_tcb, BT_HDR *p_toL2CAP)
{
UINT16 l2cap_ret;
if (p_tcb->att_lcid == L2CAP_ATT_CID)
l2cap_ret = L2CA_SendFixedChnlData (L2CAP_ATT_CID, p_tcb->peer_bda, p_toL2CAP);
else
l2cap_ret = (UINT16) L2CA_DataWrite (p_tcb->att_lcid, p_toL2CAP);
if (l2cap_ret == L2CAP_DW_FAILED)
{
GATT_TRACE_ERROR("ATT failed to pass msg:0x%0x to L2CAP",
*((UINT8 *)(p_toL2CAP + 1) + p_toL2CAP->offset));
return GATT_INTERNAL_ERROR;
}
else if (l2cap_ret == L2CAP_DW_CONGESTED)
{
GATT_TRACE_DEBUG("ATT congested, message accepted");
return GATT_CONGESTED;
}
return GATT_SUCCESS;
}
->
/*******************************************************************************
**
** Function L2CA_SendFixedChnlData
**
** Description Write data on a fixed channel.
**
** Parameters: Fixed CID
** BD Address of remote
** Pointer to buffer of type BT_HDR
**
** Return value L2CAP_DW_SUCCESS, if data accepted
** L2CAP_DW_FAILED, if error
**
*******************************************************************************/
UINT16 L2CA_SendFixedChnlData (UINT16 fixed_cid, BD_ADDR rem_bda, BT_HDR *p_buf)
{
tL2C_LCB *p_lcb;
tBT_TRANSPORT transport = BT_TRANSPORT_BR_EDR;
L2CAP_TRACE_API ("L2CA_SendFixedChnlData() CID: 0x%04x BDA: %08x%04x", fixed_cid,
(rem_bda[0]<<24)+(rem_bda[1]<<16)+(rem_bda[2]<<8)+rem_bda[3], (rem_bda[4]<<8)+rem_bda[5]);
#if BLE_INCLUDED == TRUE
if (fixed_cid >= L2CAP_ATT_CID && fixed_cid <= L2CAP_SMP_CID)
transport = BT_TRANSPORT_LE;
#endif
/* Check CID is valid and registered */
if ( (fixed_cid < L2CAP_FIRST_FIXED_CHNL) || (fixed_cid > L2CAP_LAST_FIXED_CHNL)
|| (l2cb.fixed_reg[fixed_cid - L2CAP_FIRST_FIXED_CHNL].pL2CA_FixedData_Cb == NULL) )
{
L2CAP_TRACE_ERROR ("L2CA_SendFixedChnlData() Invalid CID: 0x%04x", fixed_cid);
GKI_freebuf (p_buf);
return (L2CAP_DW_FAILED);
}
/* Fail if BT is not yet up */
if (!BTM_IsDeviceUp())
{
L2CAP_TRACE_WARNING ("L2CA_SendFixedChnlData(0x%04x) - BTU not ready", fixed_cid);
GKI_freebuf (p_buf);
return (L2CAP_DW_FAILED);
}
/* We need to have a link up */
if ((p_lcb = l2cu_find_lcb_by_bd_addr (rem_bda, transport)) == NULL ||
/* if link is disconnecting, also report data sending failure */
p_lcb->link_state == LST_DISCONNECTING)
{
L2CAP_TRACE_WARNING ("L2CA_SendFixedChnlData(0x%04x) - no LCB", fixed_cid);
GKI_freebuf (p_buf);
return (L2CAP_DW_FAILED);
}
if ((p_lcb->peer_chnl_mask[0] & (1 << fixed_cid)) == 0)
{
L2CAP_TRACE_WARNING ("L2CA_SendFixedChnlData() - peer does not support fixed chnl: 0x%04x", fixed_cid);
GKI_freebuf (p_buf);
return (L2CAP_DW_FAILED);
}
p_buf->event = 0;
p_buf->layer_specific = L2CAP_FLUSHABLE_CH_BASED;
if (!p_lcb->p_fixed_ccbs[fixed_cid - L2CAP_FIRST_FIXED_CHNL])
{
if (!l2cu_initialize_fixed_ccb (p_lcb, fixed_cid, &l2cb.fixed_reg[fixed_cid - L2CAP_FIRST_FIXED_CHNL].fixed_chnl_opts))
{
L2CAP_TRACE_WARNING ("L2CA_SendFixedChnlData() - no CCB for chnl: 0x%4x", fixed_cid);
GKI_freebuf (p_buf);
return (L2CAP_DW_FAILED);
}
}
/* If already congested, do not accept any more packets */
if (p_lcb->p_fixed_ccbs[fixed_cid - L2CAP_FIRST_FIXED_CHNL]->cong_sent)
{
L2CAP_TRACE_ERROR ("L2CAP - CID: 0x%04x cannot send, already congested \
xmit_hold_q.count: %u buff_quota: %u", fixed_cid,
p_lcb->p_fixed_ccbs[fixed_cid - L2CAP_FIRST_FIXED_CHNL]->xmit_hold_q.count,
p_lcb->p_fixed_ccbs[fixed_cid - L2CAP_FIRST_FIXED_CHNL]->buff_quota);
GKI_freebuf (p_buf);
return (L2CAP_DW_FAILED);
}
l2c_enqueue_peer_data (p_lcb->p_fixed_ccbs[fixed_cid - L2CAP_FIRST_FIXED_CHNL], p_buf);
l2c_link_check_send_pkts (p_lcb, NULL, NULL);
/* If there is no dynamic CCB on the link, restart the idle timer each time something is sent */
if (p_lcb->in_use && p_lcb->link_state == LST_CONNECTED && !p_lcb->ccb_queue.p_first_ccb)
{
l2cu_no_dynamic_ccbs (p_lcb);
}
if (p_lcb->p_fixed_ccbs[fixed_cid - L2CAP_FIRST_FIXED_CHNL]->cong_sent)
return (L2CAP_DW_CONGESTED);
return (L2CAP_DW_SUCCESS);
}
调用 l2c_enqueue_peer_data 让数据进入到当前 ccb 的 xmit_hold_q 队列中,暂存此数据包。
/*******************************************************************************
**
** Function l2c_enqueue_peer_data
**
** Description Enqueues data destined for the peer in the ccb. Handles
** FCR segmentation and checks for congestion.
**
** Returns void
**
*******************************************************************************/
void l2c_enqueue_peer_data (tL2C_CCB *p_ccb, BT_HDR *p_buf)
{
UINT8 *p;
if (p_ccb->peer_cfg.fcr.mode != L2CAP_FCR_BASIC_MODE)
{
p_buf->event = 0;
}
else
{
/* Save the channel ID for faster counting */
p_buf->event = p_ccb->local_cid;
/* Step back to add the L2CAP header */
p_buf->offset -= L2CAP_PKT_OVERHEAD;
p_buf->len += L2CAP_PKT_OVERHEAD;
/* Set the pointer to the beginning of the data */
p = (UINT8 *)(p_buf + 1) + p_buf->offset;
/* Now the L2CAP header */
UINT16_TO_STREAM (p, p_buf->len - L2CAP_PKT_OVERHEAD);
UINT16_TO_STREAM (p, p_ccb->remote_cid);
}
GKI_enqueue (&p_ccb->xmit_hold_q, p_buf);
l2cu_check_channel_congestion (p_ccb); //检测当前 Channel 拥堵情况
#if (L2CAP_ROUND_ROBIN_CHANNEL_SERVICE == TRUE)
/* if new packet is higher priority than serving ccb and it is not overrun */
if (( p_ccb->p_lcb->rr_pri > p_ccb->ccb_priority )
&&( p_ccb->p_lcb->rr_serv[p_ccb->ccb_priority].quota > 0))
{
/* send out higher priority packet */
p_ccb->p_lcb->rr_pri = p_ccb->ccb_priority;
}
#endif
/* if we are doing a round robin scheduling, set the flag */
if (p_ccb->p_lcb->link_xmit_quota == 0)
l2cb.check_round_robin = TRUE;
}
-->
/******************************************************************************
**
** Function l2cu_check_channel_congestion
**
** Description check if any change in congestion status
**
** Returns None
**
*******************************************************************************/
void l2cu_check_channel_congestion (tL2C_CCB *p_ccb)
{
UINT16 q_count = GKI_queue_length(&p_ccb->xmit_hold_q);
#if (L2CAP_UCD_INCLUDED == TRUE)
if ( p_ccb->local_cid == L2CAP_CONNECTIONLESS_CID )
{
q_count += p_ccb->p_lcb->ucd_out_sec_pending_q.count;
}
#endif
/* If the CCB queue limit is subject to a quota, check for congestion */
/* if this channel has outgoing traffic */
if (p_ccb->buff_quota != 0)
{
/* If this channel was congested */
if ( p_ccb->cong_sent )
{
/* If the channel is not congested now, tell the app */
//在函数 l2c_link_adjust_chnl_allocation 中配置此值
//p_ccb->buff_quota = quota_per_weighted_chnls[p_ccb->ertm_info.user_tx_pool_id] * p_ccb->tx_data_rate;
if (q_count <= (p_ccb->buff_quota / 2)) //当前CCB中的 xmit_hold_q 小于 buffer_quota 值的一半,即认为已经不拥堵
{
p_ccb->cong_sent = FALSE;
if (p_ccb->p_rcb && p_ccb->p_rcb->api.pL2CA_CongestionStatus_Cb)
{
L2CAP_TRACE_DEBUG ("L2CAP - Calling CongestionStatus_Cb (FALSE), CID: 0x%04x xmit_hold_q.count: %u buff_quota: %u",
p_ccb->local_cid, q_count, p_ccb->buff_quota);
/* Prevent recursive calling */
l2cb.is_cong_cback_context = TRUE;
(*p_ccb->p_rcb->api.pL2CA_CongestionStatus_Cb)(p_ccb->local_cid, FALSE);
l2cb.is_cong_cback_context = FALSE;
}
#if (L2CAP_UCD_INCLUDED == TRUE)
else if ( p_ccb->p_rcb && p_ccb->local_cid == L2CAP_CONNECTIONLESS_CID )
{
if ( p_ccb->p_rcb->ucd.cb_info.pL2CA_UCD_Congestion_Status_Cb )
{
L2CAP_TRACE_DEBUG ("L2CAP - Calling UCD CongestionStatus_Cb (FALSE), SecPendingQ:%u,XmitQ:%u,Quota:%u",
p_ccb->p_lcb->ucd_out_sec_pending_q.count,
p_ccb->xmit_hold_q.count, p_ccb->buff_quota);
p_ccb->p_rcb->ucd.cb_info.pL2CA_UCD_Congestion_Status_Cb( p_ccb->p_lcb->remote_bd_addr, FALSE );
}
}
#endif
#if (L2CAP_NUM_FIXED_CHNLS > 0)
else
{
UINT8 xx;
for (xx = 0; xx < L2CAP_NUM_FIXED_CHNLS; xx ++)
{
if (p_ccb->p_lcb->p_fixed_ccbs[xx] == p_ccb)
{
if (l2cb.fixed_reg[xx].pL2CA_FixedCong_Cb != NULL)
(* l2cb.fixed_reg[xx].pL2CA_FixedCong_Cb)(p_ccb->p_lcb->remote_bd_addr, FALSE);
break;
}
}
}
#endif
}
}
else
{
/* If this channel was not congested but it is congested now, tell the app */
if (q_count > p_ccb->buff_quota)
{
p_ccb->cong_sent = TRUE;
if (p_ccb->p_rcb && p_ccb->p_rcb->api.pL2CA_CongestionStatus_Cb)
{
L2CAP_TRACE_DEBUG ("L2CAP - Calling CongestionStatus_Cb (TRUE),CID:0x%04x,XmitQ:%u,Quota:%u",
p_ccb->local_cid, q_count, p_ccb->buff_quota);
(*p_ccb->p_rcb->api.pL2CA_CongestionStatus_Cb)(p_ccb->local_cid, TRUE);
}
#if (L2CAP_UCD_INCLUDED == TRUE)
else if ( p_ccb->p_rcb && p_ccb->local_cid == L2CAP_CONNECTIONLESS_CID )
{
if ( p_ccb->p_rcb->ucd.cb_info.pL2CA_UCD_Congestion_Status_Cb )
{
L2CAP_TRACE_DEBUG ("L2CAP - Calling UCD CongestionStatus_Cb (TRUE), SecPendingQ:%u,XmitQ:%u,Quota:%u",
p_ccb->p_lcb->ucd_out_sec_pending_q.count,
p_ccb->xmit_hold_q.count, p_ccb->buff_quota);
p_ccb->p_rcb->ucd.cb_info.pL2CA_UCD_Congestion_Status_Cb( p_ccb->p_lcb->remote_bd_addr, TRUE );
}
}
#endif
#if (L2CAP_NUM_FIXED_CHNLS > 0)
else
{
UINT8 xx;
for (xx = 0; xx < L2CAP_NUM_FIXED_CHNLS; xx ++)
{
if (p_ccb->p_lcb->p_fixed_ccbs[xx] == p_ccb)
{
if (l2cb.fixed_reg[xx].pL2CA_FixedCong_Cb != NULL)
(* l2cb.fixed_reg[xx].pL2CA_FixedCong_Cb)(p_ccb->p_lcb->remote_bd_addr, TRUE);
break;
}
}
}
#endif
}
}
}
}
L2CAP层是通过 l2c_link_check_send_pkts 这个函数发送数据包:
/*******************************************************************************
**
** Function l2c_link_check_send_pkts
**
** Description This function is called to check if it can send packets
** to the Host Controller. It may be passed the address of
** a packet to send.
**
** Returns void
**
*******************************************************************************/
void l2c_link_check_send_pkts (tL2C_LCB *p_lcb, tL2C_CCB *p_ccb, BT_HDR *p_buf)
{
int xx;
BOOLEAN single_write = FALSE; //最后 Link Disc 用来把 CCB 中的数据包放到 Link 上的队列发,速度加快
/* Save the channel ID for faster counting */
if (p_buf)//一般数据包都为空,只有发送 L2CAP 发送 command/response 或 发送 S-Frame 才用到
{
if (p_ccb != NULL) //这个 case 就是 当前 Link 即将断开的情况了
{
p_buf->event = p_ccb->local_cid;
single_write = TRUE;
}
else
p_buf->event = 0;
p_buf->layer_specific = 0;
//把这个数据包放到 当前 link 上的 link_xmit_data_q队列中
GKI_enqueue (&p_lcb->link_xmit_data_q, p_buf);
//没有发送窗口了,需要 RR 看看有没有别的数据包可以发
if (p_lcb->link_xmit_quota == 0)
{
#if BLE_INCLUDED == TRUE
if (p_lcb->transport == BT_TRANSPORT_LE)
l2cb.ble_check_round_robin = TRUE;
else
#endif
l2cb.check_round_robin = TRUE;
}
}
/* If this is called from uncongested callback context break recursive calling.
** This LCB will be served when receiving number of completed packet event.
*/
if (l2cb.is_cong_cback_context)//当前 Link 拥堵了,不发送数据包直接返回
return;
/* If we are in a scenario where there are not enough buffers for each link to
** have at least 1, then do a round-robin for all the LCBs
*/
if ( (p_lcb == NULL) || (p_lcb->link_xmit_quota == 0) )
{
if (p_lcb == NULL)
p_lcb = l2cb.lcb_pool;
else if (!single_write)
p_lcb++;
/* Loop through, starting at the next */
//没有足够buffer发送窗口了,在所有的 Link 上做一次 RR
for (xx = 0; xx < MAX_L2CAP_LINKS; xx++, p_lcb++)
{
/* If controller window is full, nothing to do */
if ( (l2cb.controller_xmit_window == 0
#if (BLE_INCLUDED == TRUE)
&& (p_lcb->transport == BT_TRANSPORT_BR_EDR)
#endif
)
#if (BLE_INCLUDED == TRUE)
|| (p_lcb->transport == BT_TRANSPORT_LE && l2cb.controller_le_xmit_window == 0 )
#endif
|| (l2cb.round_robin_unacked >= l2cb.round_robin_quota) )
break;
/* Check for wraparound */
if (p_lcb == &l2cb.lcb_pool[MAX_L2CAP_LINKS])
p_lcb = &l2cb.lcb_pool[0];
if ( (!p_lcb->in_use)
|| (p_lcb->partial_segment_being_sent)
|| (p_lcb->link_state != LST_CONNECTED)
|| (p_lcb->link_xmit_quota != 0)
|| (L2C_LINK_CHECK_POWER_MODE (p_lcb)) )
continue;
/* See if we can send anything from the Link Queue */
//首先从当前 Link 上的 link_xmit_data_q 中取出数据包并发送
if ((p_buf = (BT_HDR *)GKI_dequeue (&p_lcb->link_xmit_data_q)) != NULL)
{
l2c_link_send_to_lower (p_lcb, p_buf);
}
else if (single_write)//如果是 single_write 设置为 TRUE,说明数据包 已经在 link_xmit_data_q 发送了,没必要在执行下面的 code 了
{
/* If only doing one write, break out */
break;
}
/* If nothing on the link queue, check the channel queue */
//Link 上的 Queue 中没有东西可以发送,查找 CCB 中的 Queue,直到找到一个为止。
else if ((p_buf = l2cu_get_next_buffer_to_send (p_lcb)) != NULL)
{
l2c_link_send_to_lower (p_lcb, p_buf);
}
}
/* If we finished without using up our quota, no need for a safety check */
if ( (l2cb.controller_xmit_window > 0)
&& (l2cb.round_robin_unacked < l2cb.round_robin_quota)
#if (BLE_INCLUDED == TRUE)
&& (p_lcb->transport == BT_TRANSPORT_BR_EDR)
#endif
)
l2cb.check_round_robin = FALSE;
#if (BLE_INCLUDED == TRUE)
if ( (l2cb.controller_le_xmit_window > 0)
&& (l2cb.ble_round_robin_unacked < l2cb.ble_round_robin_quota)
&& (p_lcb->transport == BT_TRANSPORT_LE))
l2cb.ble_check_round_robin = FALSE;
#endif
}
else /* if this is not round-robin service */
{
/* If a partial segment is being sent, can't send anything else */
if ( (p_lcb->partial_segment_being_sent)
|| (p_lcb->link_state != LST_CONNECTED)
|| (L2C_LINK_CHECK_POWER_MODE (p_lcb)) )
return;
/* See if we can send anything from the link queue */
#if (BLE_INCLUDED == TRUE)
while ( ((l2cb.controller_xmit_window != 0 && (p_lcb->transport == BT_TRANSPORT_BR_EDR)) ||
(l2cb.controller_le_xmit_window != 0 && (p_lcb->transport == BT_TRANSPORT_LE)))
&& (p_lcb->sent_not_acked < p_lcb->link_xmit_quota))
#else
while ( (l2cb.controller_xmit_window != 0)
&& (p_lcb->sent_not_acked < p_lcb->link_xmit_quota))
#endif
{
if ((p_buf = (BT_HDR *)GKI_dequeue (&p_lcb->link_xmit_data_q)) == NULL)
break;
if (!l2c_link_send_to_lower (p_lcb, p_buf))
break;
}
if (!single_write)//确保不是在链路 disc 状态下
{
/* See if we can send anything for any channel */
#if (BLE_INCLUDED == TRUE)
while ( ((l2cb.controller_xmit_window != 0 && (p_lcb->transport == BT_TRANSPORT_BR_EDR)) ||
(l2cb.controller_le_xmit_window != 0 && (p_lcb->transport == BT_TRANSPORT_LE)))
&& (p_lcb->sent_not_acked < p_lcb->link_xmit_quota))
#else
while ((l2cb.controller_xmit_window != 0) && (p_lcb->sent_not_acked < p_lcb->link_xmit_quota))
#endif
{
if ((p_buf = l2cu_get_next_buffer_to_send (p_lcb)) == NULL)//找到一个数据包来发送
break;
if (!l2c_link_send_to_lower (p_lcb, p_buf))
break;
}
}
/* There is a special case where we have readjusted the link quotas and */
/* this link may have sent anything but some other link sent packets so */
/* so we may need a timer to kick off this link's transmissions. */
if ( (p_lcb->link_xmit_data_q.count) && (p_lcb->sent_not_acked < p_lcb->link_xmit_quota) )
btu_start_timer (&p_lcb->timer_entry, BTU_TTYPE_L2CAP_LINK, L2CAP_LINK_FLOW_CONTROL_TOUT);
}
}
最终 l2c_link_check_send_pkts 把数据包交给了 l2c_link_send_to_lower 来做处理,我们的音乐数据包最终也被从某个 CCB 中的队列出队列给了 l2c_link_send_to_lower。l2c_link_send_to_lower 主要做了这些事情:
/*******************************************************************************
**
** Function l2c_link_send_to_lower
**
** Description This function queues the buffer for HCI transmission
**
** Returns TRUE for success, FALSE for fail
**
*******************************************************************************/
static BOOLEAN l2c_link_send_to_lower (tL2C_LCB *p_lcb, BT_HDR *p_buf)
{
UINT16 num_segs;
UINT16 xmit_window, acl_data_size;
if ((p_buf->len <= btu_cb.hcit_acl_pkt_size
#if (BLE_INCLUDED == TRUE)
&& (p_lcb->transport == BT_TRANSPORT_BR_EDR)) ||
((p_lcb->transport == BT_TRANSPORT_LE) && (p_buf->len <= btu_cb.hcit_ble_acl_pkt_size))
#else
)
#endif
)
{
if (p_lcb->link_xmit_quota == 0)
{
#if (BLE_INCLUDED == TRUE)
if (p_lcb->transport == BT_TRANSPORT_LE)
l2cb.ble_round_robin_unacked++;
else
#endif
l2cb.round_robin_unacked++;
}
p_lcb->sent_not_acked++;
p_buf->layer_specific = 0;
#if (BLE_INCLUDED == TRUE)
if (p_lcb->transport == BT_TRANSPORT_LE)
{
l2cb.controller_le_xmit_window--;
L2C_LINK_SEND_BLE_ACL_DATA (p_buf);
}
else
#endif
{
l2cb.controller_xmit_window--;
L2C_LINK_SEND_ACL_DATA (p_buf);
}
}
else
{
#if BLE_INCLUDED == TRUE
if (p_lcb->transport == BT_TRANSPORT_LE)
{
acl_data_size = btu_cb.hcit_ble_acl_data_size;
xmit_window = l2cb.controller_le_xmit_window;
}
else
#endif
{
acl_data_size = btu_cb.hcit_acl_data_size;
xmit_window = l2cb.controller_xmit_window;
}
num_segs = (p_buf->len - HCI_DATA_PREAMBLE_SIZE + acl_data_size - 1) / acl_data_size;
/* If doing round-robin, then only 1 segment each time */
if (p_lcb->link_xmit_quota == 0)
{
num_segs = 1;
p_lcb->partial_segment_being_sent = TRUE;
}
else
{
/* Multi-segment packet. Make sure it can fit */
if (num_segs > xmit_window)
{
num_segs = xmit_window;
p_lcb->partial_segment_being_sent = TRUE;
}
if (num_segs > (p_lcb->link_xmit_quota - p_lcb->sent_not_acked))
{
num_segs = (p_lcb->link_xmit_quota - p_lcb->sent_not_acked);
p_lcb->partial_segment_being_sent = TRUE;
}
}
p_buf->layer_specific = num_segs;
#if BLE_INCLUDED == TRUE
if (p_lcb->transport == BT_TRANSPORT_LE)
{
l2cb.controller_le_xmit_window -= num_segs;
if (p_lcb->link_xmit_quota == 0)
l2cb.ble_round_robin_unacked += num_segs;
}
else
#endif
{
l2cb.controller_xmit_window -= num_segs;
if (p_lcb->link_xmit_quota == 0)
l2cb.round_robin_unacked += num_segs;
}
p_lcb->sent_not_acked += num_segs;
#if BLE_INCLUDED == TRUE
if (p_lcb->transport == BT_TRANSPORT_LE)
{
L2C_LINK_SEND_BLE_ACL_DATA(p_buf);
}
else
#endif
{
L2C_LINK_SEND_ACL_DATA (p_buf);
}
}
#if (L2CAP_HCI_FLOW_CONTROL_DEBUG == TRUE)
#if (BLE_INCLUDED == TRUE)
if (p_lcb->transport == BT_TRANSPORT_LE)
{
L2CAP_TRACE_DEBUG ("TotalWin=%d,Hndl=0x%x,Quota=%d,Unack=%d,RRQuota=%d,RRUnack=%d",
l2cb.controller_le_xmit_window,
p_lcb->handle,
p_lcb->link_xmit_quota, p_lcb->sent_not_acked,
l2cb.ble_round_robin_quota, l2cb.ble_round_robin_unacked);
}
else
#endif
{
L2CAP_TRACE_DEBUG ("TotalWin=%d,Hndl=0x%x,Quota=%d,Unack=%d,RRQuota=%d,RRUnack=%d",
l2cb.controller_xmit_window,
p_lcb->handle,
p_lcb->link_xmit_quota, p_lcb->sent_not_acked,
l2cb.round_robin_quota, l2cb.round_robin_unacked);
}
#endif
return TRUE;
}
l2c_link_send_to_lower 把数据交给了 L2C_LINK_SEND_ACL_DATA,L2C_LINK_SEND_ACL_DATA 其实是 bte_main_hci_send 函数,bte_main_hci_send 函数通过调用 hci 的接口 transmit_buf 来转送数据包。transmit_buf 函数作用比较简单,将此数据包入 tx_q 队列,串口(H5)的守护线程 bt_hc_worker_thread 会从 tx_q 队列中获取数据包,并将其发送。
/******************************************************************************
**
** Function bte_main_hci_send
**
** Description BTE MAIN API - This function is called by the upper stack to
** send an HCI message. The function displays a protocol trace
** message (if enabled), and then calls the 'transmit' function
** associated with the currently selected HCI transport
**
** Returns None
**
******************************************************************************/
void bte_main_hci_send (BT_HDR *p_msg, UINT16 event)
{
UINT16 sub_event = event & BT_SUB_EVT_MASK; /* local controller ID */
p_msg->event = event;
OS_PRINTF("bte_main_hci_send event 0x%2x\n",event);
if((sub_event == LOCAL_BR_EDR_CONTROLLER_ID) || \
(sub_event == LOCAL_BLE_CONTROLLER_ID))
{
if (bt_hc_if)
bt_hc_if->transmit_buf((TRANSAC)p_msg, \
(char *) (p_msg + 1), \
p_msg->len);
else
GKI_freebuf(p_msg);
}
else
{
APPL_TRACE_ERROR("Invalid Controller ID. Discarding message.");
GKI_freebuf(p_msg);
}
}
在hci中,数据被写入bt driver中
static int transmit_buf(TRANSAC transac, char *p_buf, int len)
{
utils_enqueue(&tx_q, (void *) transac);
bthc_signal_event(HC_EVENT_TX);
return BT_HC_STATUS_SUCCESS;
}
external\bluetooth\bluedroid\hci\src\bt_hci_bdroid.c
bt_hc_worker_thread负责处理hci事件
/*******************************************************************************
**
** Function bt_hc_worker_thread
**
** Description Mian worker thread
**
** Returns void *
**
*******************************************************************************/
static void *bt_hc_worker_thread(void *arg)
{
uint16_t events;
HC_BT_HDR *p_msg, *p_next_msg;
ALOGI("bt_hc_worker_thread started");
prctl(PR_SET_NAME, (unsigned long)"bt_hc_worker", 0, 0, 0);
tx_cmd_pkts_pending = FALSE;
raise_priority_a2dp(TASK_HIGH_HCI_WORKER);
while (lib_running)
{
pthread_mutex_lock(&hc_cb.mutex);
while (ready_events == 0)
{
pthread_cond_wait(&hc_cb.cond, &hc_cb.mutex);
}
events = ready_events;
ready_events = 0;
pthread_mutex_unlock(&hc_cb.mutex);
#ifndef HCI_USE_MCT
if (events & HC_EVENT_RX)
{
p_hci_if->rcv();
if ((tx_cmd_pkts_pending == TRUE) && (num_hci_cmd_pkts > 0))
{
/* Got HCI Cmd Credits from Controller.
* Prepare to send prior pending Cmd packets in the
* following HC_EVENT_TX session.
*/
events |= HC_EVENT_TX;
}
}
#endif
if (events & HC_EVENT_PRELOAD)
{
userial_open(USERIAL_PORT_1);
/* Calling vendor-specific part */
if (bt_vnd_if)
{
bt_vnd_if->op(BT_VND_OP_FW_CFG, NULL);
}
else
{
if (bt_hc_cbacks)
bt_hc_cbacks->preload_cb(NULL, BT_HC_PRELOAD_FAIL);
}
}
if (events & HC_EVENT_POSTLOAD)
{
/* Start from SCO related H/W configuration, if SCO configuration
* is required. Then, follow with reading requests of getting
* ACL data length for both BR/EDR and LE.
*/
int result = -1;
/* Calling vendor-specific part */
if (bt_vnd_if)
result = bt_vnd_if->op(BT_VND_OP_SCO_CFG, NULL);
if (result == -1)
p_hci_if->get_acl_max_len();
}
if (events & HC_EVENT_TX)
{
/*
* We will go through every packets in the tx queue.
* Fine to clear tx_cmd_pkts_pending.
*/
tx_cmd_pkts_pending = FALSE;
HC_BT_HDR * sending_msg_que[64];
int sending_msg_count = 0;
int sending_hci_cmd_pkts_count = 0;
utils_lock();
p_next_msg = tx_q.p_first;
while (p_next_msg && sending_msg_count <
(int)sizeof(sending_msg_que)/sizeof(sending_msg_que[0]))
{
if ((p_next_msg->event & MSG_EVT_MASK)==MSG_STACK_TO_HC_HCI_CMD)
{
/*
* if we have used up controller's outstanding HCI command
* credits (normally is 1), skip all HCI command packets in
* the queue.
* The pending command packets will be sent once controller
* gives back us credits through CommandCompleteEvent or
* CommandStatusEvent.
*/
if ((tx_cmd_pkts_pending == TRUE) ||
(sending_hci_cmd_pkts_count >= num_hci_cmd_pkts))
{
tx_cmd_pkts_pending = TRUE;
p_next_msg = utils_getnext(p_next_msg);
continue;
}
sending_hci_cmd_pkts_count++;
}
p_msg = p_next_msg;
p_next_msg = utils_getnext(p_msg);
utils_remove_from_queue_unlocked(&tx_q, p_msg);
sending_msg_que[sending_msg_count++] = p_msg;
}
utils_unlock();
int i;
for(i = 0; i < sending_msg_count; i++)
p_hci_if->send(sending_msg_que[i]);
if (tx_cmd_pkts_pending == TRUE)
BTHCDBG("Used up Tx Cmd credits");
}
if (events & HC_EVENT_LPM_ENABLE)
{
lpm_enable(TRUE);
}
if (events & HC_EVENT_LPM_DISABLE)
{
lpm_enable(FALSE);
}
if (events & HC_EVENT_LPM_IDLE_TIMEOUT)
{
lpm_wake_deassert();
}
if (events & HC_EVENT_LPM_ALLOW_SLEEP)
{
lpm_allow_bt_device_sleep();
}
if (events & HC_EVENT_LPM_WAKE_DEVICE)
{
lpm_wake_assert();
}
if (events & HC_EVENT_EPILOG)
{
/* Calling vendor-specific part */
if (bt_vnd_if)
bt_vnd_if->op(BT_VND_OP_EPILOG, NULL);
else
break; // equivalent to HC_EVENT_EXIT
}
if (events & HC_EVENT_EXIT)
break;
}
ALOGI("bt_hc_worker_thread exiting");
lib_running = 0;
pthread_exit(NULL);
return NULL; // compiler friendly
}
send to : userial.c
最终write 系统调操作driver的 fops 操作接口集:
/*******************************************************************************
**
** Function userial_write
**
** Description Write data to the userial port
**
** Returns Number of bytes actually written to the userial port. This
** may be less than len.
**
*******************************************************************************/
uint16_t userial_write(uint16_t msg_id, uint8_t *p_data, uint16_t len)
{
int ret, total = 0;
while(len != 0)
{
#if defined(ENABLE_USERIAL_TIMING_LOGS) && (ENABLE_USERIAL_TIMING_LOGS==TRUE)
log_userial_tx_timing(len);
#endif
ret = write(userial_cb.fd, p_data+total, len);
total += ret;
len -= ret;
}
return ((uint16_t)total);
}