BlueDroid 蓝牙底层通信

蓝牙协议栈里面组件之间通过队列进行消息通信。

方法

与队列相关的方法

  • fixed_queue_register_dequeue 注册队列,关联队列和处理消息方法
  • fixed_queue_enqueue 消息入队方法
  • fixed_queue_dequeue是出队方法

例如在btu_init.c btu_task.c

// Communication queue between btu_task and bta.
//btu_task和bta 关联队列
extern fixed_queue_t *btu_bta_msg_queue;

// Communication queue between btu_task and hci.
//btu_task 和hci 关联队列
extern fixed_queue_t *btu_hci_msg_queue;

btu_hci_msg_queue

btu_hci_msg_queue队列初始化在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);

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

有了消息队列,就需要相应的方法来读取消息队列中的消息,bluedroid中通过**fixed_queue_register_dequeue**方法来关联消息队列和读取线程。

在btu task启动的时候,会关联相应的队列,如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 消息队列
  //bt_workqueue_thread 工作线程
  
  //btu_bta_msg_ready 消息处理方法,
  //发送到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队列和btu_hci_msg_ready方法关联起来,
当btu_bta_msg_queue队列中有数据时,btu_bta_msg_ready便会读取数据,并处理

消息发送
消息入队方法 fixed_queue_enqueue方法,发送消息可以调用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队列的方法

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);
}

获取队列消息后由btu_hci_msg_process方法处理。

btu_bta_msg_queue

btu_bta_msg_queue队列初始化在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之间关联队列
    btu_bta_msg_queue = fixed_queue_new(SIZE_MAX);
    if (btu_bta_msg_queue == NULL)
        goto error_exit;

    ..........
}

与btu_hci_msg_queue一样,队列关联是在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);

消息发送

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方法调用fixed_queue_enqueue实现消息的入队。

bta消息一般都是btif事件产生,比如启动蓝牙EnableBluetooth,就会发送事件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;
        //发送一个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 */
    //获取对应的时间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的回调函数处理该事件
        freebuf = (*bta_sys_cb.reg[id]->evt_hdlr)(p_msg);
    }
    else
    {
        APPL_TRACE_WARNING("BTA got unregistered event id %d", id);
    }

    if (freebuf)
    {   //释放内存
        GKI_freebuf(p_msg);
    }

}

bta_sys_event方法里面没有实际的处理消息的方法。根据消息id,查询是否存在注册该id的回调函数,存在则调用回调函数处理该消息。

回调函数在何时被注册?
函数指针的赋值在一般在各个profile初始化的时候,调用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;
}

在蓝牙启动的时候注册,即方法BTA_EnableBluetooth
bta_sys_register (BTA_ID_DM, &bta_dm_reg );

static const tBTA_SYS_REG bta_dm_reg =
{   //状态机处理消息
    bta_dm_sm_execute,
    bta_dm_sm_disable
};

当发送消息类型为BTA_ID_DM时,交由bta_dm_sm_execute方法处理,bta_dm_sm_execute里面会使用状态机处理各类消息。

BTA_DM_API_ENABLE_EVT = BTA_SYS_EVT_START(BTA_ID_DM),BTA_SYS_EVT_START会将数字左移8位;方法bta_sys_event首先将id右移8位,BTA_DM_API_ENABLE_EVT经过移位后是BTA_ID_DM,调用bta_dm_sm_execute处理,BTA_DM_API_ENABLE_EVT经过& 0x00ff得到bta_dm_action数组中对应的方法,即bta_dm_enable方法。

一些数据结构

tBTA_DM_SEARCH_CB 在bta层
tBTM_CB 在btm层,里面包含回调指针函数
cb含义是control block

事件传递
BTIF->BTA->BTM->BTU->HCI
获取数据后
HCI->BTU->BTM->BTA->BTIF层层上传,将数据传传递到上层。

BlueDroid入口函数bte_main.c中 bte_main_enable方法。

  • bta_sys_main.c BTA 系统管理实现

参考

    原文作者:stdying
    原文地址: https://www.jianshu.com/p/4d9eac60156e
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞