BlueDroid 藍(lán)牙底層通信

藍(lán)牙協(xié)議棧里面組件之間通過隊(duì)列進(jìn)行消息通信。

方法

與隊(duì)列相關(guān)的方法

  • fixed_queue_register_dequeue 注冊隊(duì)列,關(guān)聯(lián)隊(duì)列和處理消息方法
  • fixed_queue_enqueue 消息入隊(duì)方法
  • fixed_queue_dequeue是出隊(duì)方法

例如在btu_init.c btu_task.c

// Communication queue between btu_task and bta.
//btu_task和bta 關(guān)聯(lián)隊(duì)列
extern fixed_queue_t *btu_bta_msg_queue;

// Communication queue between btu_task and hci.
//btu_task 和hci 關(guān)聯(lián)隊(duì)列
extern fixed_queue_t *btu_hci_msg_queue;

btu_hci_msg_queue

btu_hci_msg_queue隊(duì)列初始化在bte_main.c的bte_main_boot_entry方法

void bte_main_boot_entry(void)
{
    module_init(get_module(GKI_MODULE));
    module_init(get_module(COUNTER_MODULE));

    hci = hci_layer_get_interface();
    if (!hci)
      LOG_ERROR("%s could not get hci layer interface.", __func__);

    btu_hci_msg_queue = fixed_queue_new(SIZE_MAX);

......省略.......
}

有了消息隊(duì)列,就需要相應(yīng)的方法來讀取消息隊(duì)列中的消息,bluedroid中通過**fixed_queue_register_dequeue**方法來關(guān)聯(lián)消息隊(duì)列和讀取線程。

在btu task啟動的時候,會關(guān)聯(lián)相應(yīng)的隊(duì)列,如btu_bta_msg_queue、btu_hci_msg_queue、btu_general_alarm_queue、btu_oneshot_alarm_queue、btu_l2cap_alarm_queue

```java
void btu_task_start_up(UNUSED_ATTR void *context) {
  BT_TRACE(TRACE_LAYER_BTU, TRACE_TYPE_API,
      "btu_task pending for preload complete event");

  LOG_INFO("Bluetooth chip preload is complete");

  BT_TRACE(TRACE_LAYER_BTU, TRACE_TYPE_API,
      "btu_task received preload complete event");


  /* Initialize the mandatory core stack control blocks
    初始化核心堆棧控制塊
     (BTU, BTM, L2CAP, and SDP)
   */
  btu_init_core();

  /* Initialize any optional stack components */
  BTE_InitStack();

  bta_sys_init();

  /* 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 )
  module_init(get_module(BTE_LOGMSG_MODULE));
#endif

  // Inform the bt jni thread initialization is ok.
  btif_transfer_context(btif_init_ok, 0, NULL, 0, NULL);

  //btu_bta_msg_queue 消息隊(duì)列
  //bt_workqueue_thread 工作線程
  
  //btu_bta_msg_ready 消息處理方法,
  //發(fā)送到btu_bta_msg_queue消息,會被btu_bta_msg_ready讀取
  
  //btu_hci_msg_ready 消息處理方法
  
  fixed_queue_register_dequeue(btu_bta_msg_queue,
      thread_get_reactor(bt_workqueue_thread),
      btu_bta_msg_ready,
      NULL);

  fixed_queue_register_dequeue(btu_hci_msg_queue,
      thread_get_reactor(bt_workqueue_thread),
      btu_hci_msg_ready,
      NULL);

.........省略.............
}

fixed_queue_register_dequeue方法將btu_hci_msg_queue隊(duì)列和btu_hci_msg_ready方法關(guān)聯(lián)起來,
當(dāng)btu_bta_msg_queue隊(duì)列中有數(shù)據(jù)時,btu_bta_msg_ready便會讀取數(shù)據(jù),并處理

消息發(fā)送
消息入隊(duì)方法 fixed_queue_enqueue方法,發(fā)送消息可以調(diào)用btu_hcif_command_complete_evt或btu_hcif_command_status_evt方法。

static void btu_hcif_command_status_evt(uint8_t status, BT_HDR *command, void *context)
{
    BT_HDR *event = osi_calloc(sizeof(BT_HDR) + sizeof(command_status_hack_t));
    command_status_hack_t *hack = (command_status_hack_t *)&event->data[0];

    hack->callback = btu_hcif_command_status_evt_on_task;
    hack->status = status;
    hack->command = command;
    hack->context = context;

    event->event = BTU_POST_TO_TASK_NO_GOOD_HORRIBLE_HACK;

    fixed_queue_enqueue(btu_hci_msg_queue, event);
}

消息處理
btu_hci_msg_ready會取出存入btu_hci_msg_queue隊(duì)列的方法

void btu_hci_msg_ready(fixed_queue_t *queue, UNUSED_ATTR void *context) {
    BT_HDR *p_msg = (BT_HDR *)fixed_queue_dequeue(queue);
    btu_hci_msg_process(p_msg);
}

獲取隊(duì)列消息后由btu_hci_msg_process方法處理。

btu_bta_msg_queue

btu_bta_msg_queue隊(duì)列初始化在btu_init.c的方法BTU_StartUp

void BTU_StartUp(void)
{
    
    memset (&btu_cb, 0, sizeof (tBTU_CB));
    btu_cb.trace_level = HCI_INITIAL_TRACE_LEVEL;

    //初始化btu_task and bta之間關(guān)聯(lián)隊(duì)列
    btu_bta_msg_queue = fixed_queue_new(SIZE_MAX);
    if (btu_bta_msg_queue == NULL)
        goto error_exit;

    ..........
}

與btu_hci_msg_queue一樣,隊(duì)列關(guān)聯(lián)是在btu task啟動的時候,即方法btu_task_start_up;

  fixed_queue_register_dequeue(btu_bta_msg_queue,
      thread_get_reactor(bt_workqueue_thread),
      btu_bta_msg_ready,
      NULL);

消息發(fā)送

void bta_sys_sendmsg(void *p_msg)
{
    // There is a race condition that occurs if the stack is shut down while
    // there is a procedure in progress that can schedule a task via this
    // message queue. This causes |btu_bta_msg_queue| to get cleaned up before
    // it gets used here; hence we check for NULL before using it.
    if (btu_bta_msg_queue)
        fixed_queue_enqueue(btu_bta_msg_queue, p_msg);
}

bta_sys_sendmsg方法調(diào)用fixed_queue_enqueue實(shí)現(xiàn)消息的入隊(duì)。

bta消息一般都是btif事件產(chǎn)生,比如啟動藍(lán)牙EnableBluetooth,就會發(fā)送事件id為BTA_DM_API_ENABLE_EVT的消息

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;
        //發(fā)送一個bta_sys信息
        bta_sys_sendmsg(p_msg);
        return BTA_SUCCESS;
    }
    return BTA_FAILURE;

}

消息處理
下面btu_bta_msg_ready方法,如何處理消息

void btu_bta_msg_ready(fixed_queue_t *queue, UNUSED_ATTR void *context) {
    BT_HDR *p_msg = (BT_HDR *)fixed_queue_dequeue(queue);
    bta_sys_event(p_msg);
}

btu_bta_msg_ready取出最新消息后,交由方法bta_sys_event處理

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

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

    /* get subsystem id from event */
    //獲取對應(yīng)的時間id
    id = (UINT8) (p_msg->event >> 8);

    /* verify id and call subsystem event handler */
    if ((id < BTA_ID_MAX) && (bta_sys_cb.reg[id] != NULL))
    {
        //交由事件id的回調(diào)函數(shù)處理該事件
        freebuf = (*bta_sys_cb.reg[id]->evt_hdlr)(p_msg);
    }
    else
    {
        APPL_TRACE_WARNING("BTA got unregistered event id %d", id);
    }

    if (freebuf)
    {   //釋放內(nèi)存
        GKI_freebuf(p_msg);
    }

}

bta_sys_event方法里面沒有實(shí)際的處理消息的方法。根據(jù)消息id,查詢是否存在注冊該id的回調(diào)函數(shù),存在則調(diào)用回調(diào)函數(shù)處理該消息。

回調(diào)函數(shù)在何時被注冊?
函數(shù)指針的賦值在一般在各個profile初始化的時候,調(diào)用bta_sys_main.c的方法bta_sys_register賦值

void bta_sys_register(UINT8 id, const tBTA_SYS_REG *p_reg)
{
    bta_sys_cb.reg[id] = (tBTA_SYS_REG *) p_reg;
    bta_sys_cb.is_reg[id] = TRUE;
}

在藍(lán)牙啟動的時候注冊,即方法BTA_EnableBluetooth
bta_sys_register (BTA_ID_DM, &bta_dm_reg );

static const tBTA_SYS_REG bta_dm_reg =
{   //狀態(tài)機(jī)處理消息
    bta_dm_sm_execute,
    bta_dm_sm_disable
};

當(dāng)發(fā)送消息類型為BTA_ID_DM時,交由bta_dm_sm_execute方法處理,bta_dm_sm_execute里面會使用狀態(tài)機(jī)處理各類消息。

BTA_DM_API_ENABLE_EVT = BTA_SYS_EVT_START(BTA_ID_DM),BTA_SYS_EVT_START會將數(shù)字左移8位;方法bta_sys_event首先將id右移8位,BTA_DM_API_ENABLE_EVT經(jīng)過移位后是BTA_ID_DM,調(diào)用bta_dm_sm_execute處理,BTA_DM_API_ENABLE_EVT經(jīng)過& 0x00ff得到bta_dm_action數(shù)組中對應(yīng)的方法,即bta_dm_enable方法。

一些數(shù)據(jù)結(jié)構(gòu)

tBTA_DM_SEARCH_CB 在bta層
tBTM_CB 在btm層,里面包含回調(diào)指針函數(shù)
cb含義是control block

事件傳遞
BTIF->BTA->BTM->BTU->HCI
獲取數(shù)據(jù)后
HCI->BTU->BTM->BTA->BTIF層層上傳,將數(shù)據(jù)傳傳遞到上層。

BlueDroid入口函數(shù)bte_main.c中 bte_main_enable方法。

  • bta_sys_main.c BTA 系統(tǒng)管理實(shí)現(xiàn)

參考

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容