整个bluedroid可以分为两大模块:BTIF,BTE
BTIF:提供bluedroid对外的接口
BTE:bluedroid的内部处理,又细分为BTA,BTU,BTM和HCI
BTA:bluedroid中各profile的逻辑实现和处理
BTU:承接BTA与HCI
BTM:蓝牙配对与链路管理
HCI:读取或写入数据到蓝牙hw
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
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,
};</pre>
2、init函数里注册传入的回调函数:
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;
}
3、启动btservice
//external\bluetooth\bluedroid\btif\src\btif_core.c
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;
}
4、创建线程和准备启动调度:
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;
}
4.1、服务进程函数
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");
}
4.2、回调时的注册函数
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;
}
4.3、回调函数的函数体(协议栈处理对应的事件)
a) btif_in_execute_service_request :执行对应的请求
b) btif_storage_get_adapter_property: 协议栈的相关属性处理
c) bt_hal_cbacks : 回调hal层的callback函数,进行硬件相关操作
//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;
}
4.4、执行A2DP/HID/HFP等服务
a) 底层的硬件调用
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;
}
5、启动/关闭 HID服务
//external\bluetooth\bluedroid\btif\src\btif_hh.c
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
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);
}
}
6、HID Host Profile 部分初始化,
a) 打开蓝牙接口:p_dev->fd = open(dev_path, O_RDWR | O_CLOEXEC);
b) 创建HID事件监听线程:p_dev->hh_poll_thread_id = create_thread(btif_hh_poll_event_thread, p_dev);
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));
//code ...
}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);
}
6.1 poll监听HID驱动的事件:
select() 和 poll() 系统调用的本质一样,poll() 的机制与 select() 类似,与 select() 在本质上没有多大差别,管理多个描述符也是进行轮询,根据描述符的状态进行处理。
1、优点
(1)poll() 不要求开发者计算最大文件描述符加一的大小。
(2)poll() 在应付大数目的文件描述符的时候速度更快,相比于select。
(3)它没有最大连接数的限制,原因是它是基于链表来存储的。
(4)在调用函数时,只需要对参数进行一次设置就好了
2、缺点
(1)大量的fd的数组被整体复制于用户态和内核地址空间之间,而不管这样的复制是不是有意义。
(2)与select一样,poll返回后,需要轮询pollfd来获取就绪的描述符,这样会使性能下降
(3)同时连接的大量客户端在一时刻可能只有很少的就绪状态,因此随着监视的描述符数量的增长,其效率也会线性下降
{
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;
}
6.2、解析HID驱动的事件:uhid_event
整个函数就一句:ret = read(p_dev->fd, &ev, sizeof(ev));
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;
}
7、蓝牙发送数据报
最后是通过:bta_sys_sendmsg 发送数据
#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
}
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);
}
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处理进程
}
}
8、数据接收
BTA_HhEnable是在注册的HID主处理函数进行数据接收和处理:
//external\bluetooth\bluedroid\bta\hh\bta_hh_main.c
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);
}
协议栈的代码跟踪流程如上,包括:
蓝牙的启动、初始化、蓝牙的service启动、蓝牙硬件操作(open)、蓝牙的数据发送和接收。
完~~~
文 | 力卉编程
网友评论