美文网首页蓝牙和WIFI
蓝牙笔记 | 蓝牙协议栈代码跟踪分析

蓝牙笔记 | 蓝牙协议栈代码跟踪分析

作者: 力卉编程 | 来源:发表于2019-12-31 20:35 被阅读0次

整个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)、蓝牙的数据发送和接收。

完~~~

文 | 力卉编程

相关文章

网友评论

    本文标题:蓝牙笔记 | 蓝牙协议栈代码跟踪分析

    本文链接:https://www.haomeiwen.com/subject/fuumoctx.html