bluedroid中的start discovery代码流程

本文详细解析了Android 4.4系统中蓝牙搜索的代码流程,从JNI层的startDiscoveryNative函数开始,经由bluetoothInterface的start_discovery入口,深入到btif_dm_start_discovery函数,设置搜索参数并调用BTA_DmSearch执行蓝牙设备搜索。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

    之前看到某位大神的博客android -- 蓝牙 bluetooth (三)搜索蓝牙,介绍了Android中蓝牙的搜索过程,从framework到service,再到JNI、bluetooth stack,大致的流程讲得很清楚。这里我了解了一下Android4.4中bluetooth stack中的代码流程,总结如下。

    在JNI层中调用startDiscoveryNative函数,最终指向stack层bluetoothInterface(bluetooth.c)结构的成员函数start_discovery,这便是stack层的入口。在btif_dm_start_discovery(btif_dm.c)函数中设置了discovery的相关参数,并调用BTA_DmSearch(&inq_params, services, bte_search_devices_evt)来执行。这个函数的内容如下:

void BTA_DmSearch(tBTA_DM_INQ *p_dm_inq, tBTA_SERVICE_MASK services, tBTA_DM_SEARCH_CBACK *p_cback)
{

    tBTA_DM_API_SEARCH    *p_msg;

    if ((p_msg = (tBTA_DM_API_SEARCH *) GKI_getbuf(sizeof(tBTA_DM_API_SEARCH))) != NULL)
    {
        memset(p_msg, 0, sizeof(tBTA_DM_API_SEARCH));

        p_msg->hdr.event = BTA_DM_API_SEARCH_EVT;
        memcpy(&p_msg->inq_params, p_dm_inq, sizeof(tBTA_DM_INQ));
        p_msg->services = services;
        p_msg->p_cback = p_cback;
        p_msg->rs_res  = BTA_DM_RS_NONE;
        bta_sys_sendmsg(p_msg);
    }

}

可以看到,该函数构造了一个消息p_msg,设置了事件类型以及回调函数。在这里,回调函数即前面的bte_search_devices_evt,它处理搜索的结果,并最终通过JNI提供的callback返回给上层。这个消息被发送到btu_task,由bta模块处理,代码如下:

BTA_API void bta_sys_event(BT_HDR *p_msg)
{
    UINT8       id;
    BOOLEAN     freebuf = TRUE;

    APPL_TRACE_EVENT1("BTA got event 0x%x", p_msg->event);

    /* 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);
    }
    else
    {
        APPL_TRACE_WARNING1("BTA got unregistered event id %d", id);
    }

    if (freebuf)
    {
        GKI_freebuf(p_msg);
    }

}

其内容很简单,就是暗中event的id来调相应的函数来处理。对于search过程来说,他的处理函数早在蓝牙初始化中调用函数BTA_EnableBluetooth中注册:

bta_sys_register (BTA_ID_DM_SEARCH, &bta_dm_search_reg );

从而,代码转入bta_dm_search_reg的成员函数bta_dm_search_sm_execute。它的实现跟上面的bta_sys_event很类似,根据不同的state来调用相应状态下的函数。代码如下:

BOOLEAN bta_dm_search_sm_execute(BT_HDR *p_msg)
{
    tBTA_DM_ST_TBL      state_table;
    UINT8               action;
    int                 i;

    APPL_TRACE_EVENT2("bta_dm_search_sm_execute state:%d, event:0x%x",
        bta_dm_search_cb.state, p_msg->event);

    /* look up the state table for the current state */
    state_table = bta_dm_search_st_tbl[bta_dm_search_cb.state];

    bta_dm_search_cb.state = state_table[p_msg->event & 0x00ff][BTA_DM_SEARCH_NEXT_STATE];


    /* execute action functions */
    for (i = 0; i < BTA_DM_SEARCH_ACTIONS; i++)
    {
        if ((action = state_table[p_msg->event & 0x00ff][i]) != BTA_DM_SEARCH_IGNORE)
        {
            (*bta_dm_search_action[action])( (tBTA_DM_MSG*) p_msg);
        }
        else
        {
            break;
        }
    }
    return TRUE;
}

刚进入这个函数时,由于bta_dm_search_cb.state为0,故state_table为bta_dm_search_idle_st_table;由于前面在BTA_DmSearch中设置的event为BTA_DM_API_SEARCH_EVT(0x0200),从而第一个真正的执行函数为bta_dm_search_start。它的关键部分如下:

void bta_dm_search_start (tBTA_DM_MSG *p_data)
{
    ......
    /* save search params */
    bta_dm_search_cb.p_search_cback = p_data->search.p_cback;
    bta_dm_search_cb.services = p_data->search.services;

    ......
    result.status = BTM_StartInquiry(   (tBTM_INQ_PARMS*)&p_data->search.inq_params,
                        bta_dm_inq_results_cb,
                        (tBTM_CMPL_CB*) bta_dm_inq_cmpl_cb);

    ......
}

在第一部分,它注册了search的回调函数给全局变量bta_dm_search_cb的成员;同时,它在第二部分调用BTM_StartInquiry去执行inquiry(扯了这么多其实还没到真正发HCI command的地方)。同样的,将函数BTM_StartInquiry的关键部分贴在下面:

*******************************************************************************/
tBTM_STATUS BTM_StartInquiry (tBTM_INQ_PARMS *p_inqparms, tBTM_INQ_RESULTS_CB *p_results_cb,
                              tBTM_CMPL_CB *p_cmpl_cb)
{
    tBTM_STATUS  status = BTM_CMD_STARTED;
    tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars;
    ......

    /* Initialize the inquiry variables */
    p_inq->state = BTM_INQ_ACTIVE_STATE;
    p_inq->p_inq_cmpl_cb = p_cmpl_cb;
    p_inq->p_inq_results_cb = p_results_cb;
    p_inq->inq_cmpl_info.num_resp = 0;         /* Clear the results counter */
    p_inq->inq_active = p_inqparms->mode;

   
    ......
}

很简单,它再次设置了bta_dm_search_cb的一些成员,最重要的即扫描结果的回调函数p_results_cb(即bta_dm_inq_results_cb)和扫描完成(超时或者收到results的数目超过设定)的处理函数p_cmpl_cb(即bta_dm_inq_cmpl_cb)。这样,在收到inquiry的results后便有相应的处理函数。在设置完这些参数后,函数后半段便要开始执行扫描了,最终通过btu_hcif_send_cmd将BR\EDR或者LE扫描的HCI指令发送给controller。同时,它还会对上层进行通知,告知执行已经执行,现在的状态是discovery_started。而当收到扫描的report时,调用callback函数上报device_found。只有当用于通过UI选择与某一个设备进行配对时,才会进入后面的配对鉴权、加密等过程,这些留待以后慢慢学习。



 



 


 

<think>嗯,用户问的是ESP-IDF的蓝牙Host代码配置。我需要先回忆一下ESP-IDF的蓝牙架构。ESP-IDF使用的是基于Bluedroid蓝牙协议栈,分为Controller和Host两部分。Host部分主要负责高层协议的处理,比如GATT、SMP、GAP等。用户可能需要知道如何配置Host相关的参数或者启用某些功能。 首先,用户可能需要了解如何通过menuconfig进行配置。我应该提到进入menuconfig的步骤,比如使用idf.py menuconfig,然后找到蓝牙相关的配置选项。比如,Component config → BluetoothBluetooth controller → Bluetooth Host Controller Interface (HCI) 的选择,这里通常选VHCI或者基于UART的HCI,不过大部分情况下默认的VHCI就够用了。 接下来,Host相关的配置可能包括启用经典蓝牙或BLE。需要说明在menuconfig里如何选择蓝牙模式,比如BluetoothBluetooth mode → (SPP/BLE/双模)。不同的模式对应不同的协议支持,比如SPP需要Classic Bluetooth,而BLE则是低功耗。 另外,内存池的配置也很重要。Bluedroid需要动态内存管理,用户可能需要调整BT/BLE内存的分配,比如设置BT/BLE Host的TX和RX缓冲区大小。这部分在Component config → BluetoothBluedroid Options里设置。 还有,Host层的一些功能模块,比如GATT、SMP、GAP的配置。用户可能需要启用或调整这些参数,比如设置GATT客户端的数量,MTU大小,或者SMP的安全参数。这里需要具体说明每个选项的作用和推荐值。 然后,可能涉及到API的使用,比如初始化Host的流程,调用esp_bluedroid_init()和esp_bluedroid_enable(),以及注册回调函数处理事件。这部分需要给出代码示例,说明初始化的步骤和注意事项,比如错误检查的顺序。 用户可能遇到的问题是配置错误导致初始化失败,或者功能无法使用。我需要提醒常见的配置错误,比如内存不足导致分配失败,或者没有正确选择蓝牙模式。另外,双模配置时资源消耗较大,需要注意内存和性能的影响。 还要提到日志调试的重要性,建议开启蓝牙调试日志,设置不同的日志级别,方便排查问题。比如在menuconfig里调整Component config → Log output → Default log verbosity为Debug或Verbose。 最后,参考官方文档和示例的重要性,比如推荐用户查看esp-idf/examples/bluetooth目录下的示例代码,按照readme步骤操作。可能还需要注意版本差异,不同版本的ESP-IDF配置选项可能有变化,建议用户确认自己的SDK版本。</think>好的,我来分步骤介绍ESP-IDF中蓝牙Host代码的配置要点: 1. **环境准备** - 确保ESP-IDF版本≥v4.0(推荐v5.0+) - 安装必要工具链: ```bash $ cd ~/esp/esp-idf $ ./install.sh ``` 2. **menuconfig配置** ```bash $ idf.py menuconfig ``` 需配置以下关键项: - **Component config → Bluetooth →** - ✅ Enable Bluetooth - Controller Options → Bluetooth Host Controller Interface (HCI) → 选择VHCI(默认) - Bluedroid Options → - 调整内存池大小(根据应用需求) - 启用GATT/SMP/GAP等协议 3. **双模配置示例** ```c // 在sdkconfig.defaults中添加: CONFIG_BT_BLUEDROID_ENABLED=y CONFIG_BT_CLASSIC_ENABLED=y CONFIG_BT_BLE_ENABLED=y ``` 4. **Host初始化代码结构** ```c void app_main() { // 初始化NVS esp_err_t ret = nvs_flash_init(); // 初始化Bluedroid ret = esp_bluedroid_init(); ret = esp_bluedroid_enable(); // 注册GAP回调 esp_bt_gap_register_callback(gap_event_handler); // 设置设备可见模式 esp_bt_gap_set_scan_mode(ESP_BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE); } ``` 5. **关键API说明** | API函数 | 功能说明 | |-------------------------------|-----------------------------------| | `esp_bluedroid_init()` | 初始化Bluedroid协议栈 | | `esp_bt_gap_start_discovery()`| 启动设备发现 | | `esp_ble_gap_config_adv_data()`| 配置BLE广播数据 | 6. **常见问题处理** - **内存不足**:调整`CONFIG_BT_BLE_HOST_QUEUE_CONGESTION_NUM` - **连接不稳定**:检查`CONFIG_BT_BLE_ACT_SCAN_REP_ADV_SCAN` - **协议冲突**:检查`CONFIG_BT_STACK_NO_LOG`是否误开启 7. **调试建议** ```c // 启用详细日志 esp_log_level_set("BT", ESP_LOG_VERBOSE); ``` 8. **参考示例** - BLE基础示例:`esp-idf/examples/bluetooth/bluedroid/ble/gatt_server` - 经典蓝牙示例:`esp-idf/examples/bluetooth/bluedroid/classic_bt/a2dp_sink` 实际开发中建议结合具体应用场景: - BLE设备:重点关注GATT服务配置 - 音频设备:需要配置A2DP/HFP协议 - 双模设备:注意资源竞争问题 建议定期同步最新IDF版本,蓝牙协议栈更新频率较高,新版通常会优化性能和修复问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值