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 系统管理实现

参考

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342

推荐阅读更多精彩内容