Bluedroid:蓝牙协议栈源码剖析
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
Bluedroid:蓝⽛协议栈源码剖析
⼀、基础知识介绍
1.缩略语
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
2.蓝⽛协议栈框架图:
1.基带层(BB)提供了两种不同的物理链路(同步⾯向连接链路SCO Synchronous Connection Oriented和异步⽆连接链路ACL Asynchronous Connection Less),负责跳频和蓝⽛数据及信息帧的传输,且对所有类型的数据包提供了不同层次的前向纠错码(FEC Frequency Error Correction)或循环沉余度差错校验(CTC Cyclic Redundancy Check);
2.LMP层负责两个或多个设备链路的建⽴和拆除及链路的安全和控制,如鉴权和加密、控制和协商基带包的⼤⼩等,它为上层软件模块提供了不同的访问⼊⼝;
3.蓝⽛主机控制器接⼝HCI (Host Controller Interface)由基带控制器、连接管理器、控制和事件寄存器等组成。
它是蓝⽛协议中软硬件之间的接⼝,它提供了⼀个调⽤下层BB、LM、状态和控制寄存器等硬件的统⼀命令,上、下两个模块接⼝之间的消息和数据的传递必须通过HCI的解释才能进⾏。
HCI层以上的协议软件实体运⾏在主机上,⽽HCI以下的功能由蓝⽛设备⽾完成,⼆者之间通过传输层进⾏交互。
4.中间协议层由逻辑链路控制与适配协议L2CAP (Logical Link Control and Adaptation Protocol)、服务发现协议 SDP (Service Discovery Protocol)、串⼝仿真协议或称线缆替换协议 RFCOM 和⼆进制电话控制协议 TCS (Telephony Control protocol Spectocol)组成。
L2CAP 是蓝⽛协议栈的核⼼组成部分,也是其它协议实现的基础。
它位于基带之上,向上层提供⾯向连接的和⽆连接的数据服务。
它主要完成数据的拆装、服务质量控制,协议的复⽤、分组的分割和重组(Segmentation And Reassembly)及组提取等功能。
L2CAP允许⾼达64KB的数据分组。
5.SDP是⼀个基于客户/服务器结构的协议。
它⼯作在 L2CAP层之上,为上层应⽤程序提供⼀种机制来发现可⽤的服务及其属性,⽽服务的属性包括服务的类型及该服务所需的机制或协议信息。
6.RFCOMM 是⼀个仿真有线链路的⽆线数据仿真协议,符合ETSI 标准的 TS 0
7.10串⼝仿真协议。
它在蓝⽛基带上仿真RS-232的控制和数据信号,为原先使⽤串⾏连接的上层业务提供传送能⼒。
7.TCS是⼀个基于 ITU-T Q.931 建议的采⽤⾯向⽐特的协议,它定义了⽤于蓝⽛设备之间建⽴语⾳和数据呼叫的控制信令(Call Control Signalling),并负责处理蓝⽛设备组的移动管理过程。
整个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");
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;
return0;
}
解析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);
}
return0;
}
--->
/*******************************************************************************
**
** 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->yer_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));
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_yer_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_yer_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_yer_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_yer_specific;
break;
default:
/* invalid handle, call bad API event */
APPL_TRACE_ERROR("wrong device handle: [%d]", p_data->yer_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] ;。