Bluedroid HCI初始化流程

说明:数据流文字说明部分借鉴了另外一篇(因为写的很好了), 也修正了原来的一些笔误, 结尾给出了链接, 侵删.

Bluedroid HCI初始化流程

一. bluedroid init初始化

这里主要是从JNI调用下来的, 主要创建了一个stack_manager线程, 然后event_init_stack()就是在stack_manager线程中完成的.

主要新增线程: stack_manager

1_event_init_stack

bte_main_boot_entry()流程, 这里主要是各个模块回调函数的初始化.

2_bte_main_boot_entry

二. Bluedroid Enable功能

3_bt_enable_0525

这部分主要是bluedroid使能部分, 也是从JNI调用下来的.

主要新增线程:

线程: snoop;

线程: hci_thread;

线程: hci_inject

线程: hci_single_channel //用于从串口读数据

线程: bt_workquene_thread

新增timer:

timer:startup_timer //启动完成之后, 就会消除这个timer

timer:epilog_timer

timer:command_response_timer

新增队列:

queue:btu_hci_msg_queue //hci thread to bt_workqueue, bte_main_boot_entry创建的.

queue: packet_queue; //数据

queue: command_queue; //*指令

queue:btu_bta_msg_queue //bta thread to bt_workqueue, BTU_StartUp函数创建的.

queue:btu_general_alarm_queue //BTU_StartUp函数创建的. 各指令超时的timer都有用.上层(BTM,BTU)?

list: commands_pending_response ; // 和上面btu_general_alarm_queue 类似? 但主要在hci_layer.c层?

数据流:

command_queue:

这里主要关注一下队列的绑定,当往command_queue里面塞数据的时候,event_command_ready就会被调用来处理这个数据,注意这里都是在hci_thread里面执行的。同理往数据队列里面塞数据,event_packet_ready就会被执行。

1. 数据的发送

看代码可以发现,event_command_ready和event_packet_ready 他们都会调用同一个接口来发送数据,packet_fragmenter模块里面的:

packet_fragmenter->fragment_and_dispatch(wait_entry->command);

2. 数据的接收

eager_reader_register(uart_stream, thread_get_reactor(thread), event_uart_has_bytes, NULL);//hci_thread线程一直poll设备节点,有数据就会调用event_uart_has_bytes来处理

只要底层有数据传上来,那么hal层的函数event_uart_has_bytes就会去处理这些数据,那么看看event_uart_has_bytes的实现:

static void event_uart_has_bytes(eager_reader_t *reader, UNUSED_ATTR void *context) {
  if (stream_has_interpretation) {
    callbacks->data_ready(current_data_type);//最终调用该函数
  } else {
    uint8_t type_byte;
    if (eager_reader_read(reader, &type_byte, 1, true) == 0) {
      LOG_ERROR("%s could not read HCI message type", __func__);
      return;
    }
...
    stream_has_interpretation = true;
    current_data_type = type_byte;
  }
}

最终调用:

static const hci_hal_callbacks_t hal_callbacks = {
hal_says_data_ready
};
static void hal_says_data_ready(serial_data_type_t type) {
  packet_receive_data_t *incoming = &incoming_packets[PACKET_TYPE_TO_INBOUND_INDEX(type)];
  uint8_t byte;
  while (hal->read_data(type, &byte, 1, false) != 0) {
    switch (incoming->state) {
      case BRAND_NEW:
...
      case BODY:
        incoming->buffer->data[incoming->index] = byte;
...
        break;
      case IGNORE:
        incoming->bytes_remaining--;
...
          hal->packet_finished(type);
          return;
        }
        break;
      case FINISHED:
        LOG_ERROR("%s the state machine should not have been left in the finished state.", __func__);
        break;
    }

    if (incoming->state == FINISHED) {
      incoming->buffer->len = incoming->index;
      btsnoop->capture(incoming->buffer, true);//保存btsnoop文件

      if (type != DATA_TYPE_EVENT) {
        packet_fragmenter->reassemble_and_dispatch(incoming->buffer);//acl data处理流程
      } else if (!filter_incoming_event(incoming->buffer)) {//event 处理流程
        // Dispatch the event by event code
        uint8_t *stream = incoming->buffer->data;
        uint8_t event_code;
        STREAM_TO_UINT8(event_code, stream);

        data_dispatcher_dispatch(
          interface.event_dispatcher,
          event_code,
          incoming->buffer
        );
      }

      // We don't control the buffer anymore
      incoming->buffer = NULL;
      incoming->state = BRAND_NEW;
      hal->packet_finished(type);

      // We return after a packet is finished for two reasons:
      // 1. The type of the next packet could be different.
      // 2. We don't want to hog cpu time.
      return;
    }
  }
}

从上面的代码我们发现,主要是经过两个路径来上报数据的:

  1. **packet_fragmenter->reassemble_and_dispatch(incoming->buffer); **
  2. data_dispatcher_dispatch(interface.event_dispatcher,event_code,incoming->buffer);

首先看一下 第一个路径:

static void reassemble_and_dispatch(UNUSED_ATTR BT_HDR *packet) {
...
    callbacks->reassembled(packet);
}

上面的callback 定义在hci_layer.c

static void dispatch_reassembled(BT_HDR *packet) {
...
  if (upwards_data_queue) {
    fixed_queue_enqueue(upwards_data_queue, packet);//把数据放到upwards_data_queue,这个队列其实就是btu_hci_msg_queue
  }
}

这个队列是在bte_main_boot_entry 时候注册的:

hci = hci_layer_get_interface();
    btu_hci_msg_queue = fixed_queue_new(SIZE_MAX);
    data_dispatcher_register_default(hci->event_dispatcher, btu_hci_msg_queue);
    hci->set_data_queue(btu_hci_msg_queue);//设置upwards_data_queue

从这里我们知道,最终的数据送到了btu_hci_msg_queue,那么就由btu 线程继续处理了。

下面继续看看data_dispatcher_dispatch(interface.event_dispatcher,event_code,incoming->buffer);

bool data_dispatcher_dispatch(data_dispatcher_t *dispatcher, data_dispatcher_type_t type, void *data) {
  fixed_queue_t *queue = hash_map_get(dispatcher->dispatch_table, (void *)type);
  if (!queue)
    queue = dispatcher->default_queue;//这里的queue其实也是btu_hci_msg_queue

  if (queue)
    fixed_queue_enqueue(queue, data);

  return queue != NULL;
}

上面的queue也是在bte_main_boot_entry 里面注册的。

 data_dispatcher_register_default(hci->event_dispatcher, btu_hci_msg_queue);
void data_dispatcher_register_default(data_dispatcher_t *dispatcher, fixed_queue_t *queue) {
  assert(dispatcher != NULL);
  dispatcher->default_queue = queue;
}

我们知道hci->event_dispatcher->default_queue = btu_hci_msg_queue

那和上面的第一种case一样:最终的数据送到了btu_hci_msg_queue,那么就由btu 线程继续处理了。

3. 小结

最后总结一下hci_thread处理的数据流程:

  1. 当hci向下发送数据的时候,会将数据放置到packet_queue,然后调用到fragment_and_dispatch,然后经过HAL模块发write到串口fd,最后抵达controller.
  2. 当controller有数据上传的时候,底层的bt driver会将数据发送到host与controller的通信节点。hci_thread会一直poll这个节点,调用 hal_says_data_ready读出数据,数据经过hal以及fragment_and_dispatch(或者data_dispatcher_dispatch),将数据送到btu_hci_msg_queue(前面这部分是hci_thread),然后由btu 线程继续处理。

三. 参考文献

  1. Bluedroid协议栈HCI线程分析

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值