HCI

  • 可这么认为,bt协议栈、HDIL-bt都和硬件无关。HDIL-vendor,以及它要打开的linux驱动,和硬件相关。
  • Android设备怎么确定蓝牙地址?——为让同一个android镜像能生成不同蓝牙地址,烧写镜像后,是没有确定地址。android第一次启动,执行hci_initialize(),它会执行到BluetoothAddress::get_local_address(local_bda)。第一次get_local_address时,prop变量persist.service.bdroid.bdaddr值是空,于是会生成一个随机地址,然后存入prop变量persist.service.bdroid.bdaddr。这样下次启动时,prop变量persist.service.bdroid.bdaddr不再是空,就取它值为地址,这android设备就一直是这地址了。
图1 bt协议栈、HDIL-bt、HDIL_vendor

一、“DISCOVERY && SRVC_ALL”时发送req、接收resp

这里以“连接进入发现阶段(bta_gattc_start_discover),目的是获取该peripherl有哪些service”为例,看center如何向peripheral发送请求,以及接收应答。

1.1 发送请求

以gatt_act_discovery为分析的起始函数,看它是如何构造请求,并通过之前调用L2CA_ConnectFixedChnl()分配的L2CAP通道,发送请求。

  1. [stack/gatt/att_protocol.c]attp_send_cl_msg(op_code:GATT_REQ_READ_BY_GRP_TYPE)。调用attp_build_browse_cmd()构造“通用”格式的请求。BT_HDR.offset: 13,BT_HDR.len: 7。
  2. [stack/gatt/att_protocol.c]attp_cl_send_cmd()。
  3. [stack/gatt/att_protocol.c]attp_send_msg_to_l2cap()。此时p_tcb->att_lcid == L2CAP_ATT_CID(4)。
  4. [stack/l2cap/l2c_api.c]L2CA_SendFixedChnlData(L2CAP_ATT_CID, ...)。调用l2c_enqueue_peer_data让数据进入到当前ccb的xmit_hold_q队列中,暂存此数据包。经过l2c_enqueue_peer_data后,BT_HDR.offset: 9,BT_HDR.len: 11。l2c_enqueue_peer_data较为复杂,参考“L2CAP数据发送和接收”。进入到当前ccb的xmit_hold_q队列时调用“fixed_queue_enqueue(p_ccb->xmit_hold_q, p_buf)”,但对xmit_hold_q没使用fixed_queue_enqueus机制,下一步就会用fixed_queue_try_dequeue(p_ccb->xmit_hold_q)获取这个新进入的p_buf。
  5. [stack/l2cap/l2c_link.c]l2c_link_check_send_pkts(tL2C_LCB *p_lcb, tL2C_CCB *p_ccb, BT_HDR *p_buf)。输入参数p_buf是nullptr!内中要调用l2cu_get_next_buffer_to_send(peer_cfg.fcr.mode: L2CAP_FCR_BASIC_MODE,L2CAP_NUM_FIXED_CHNLS: 32),后者通过fixed_queue_try_dequeue(p_ccb->xmit_hold_q),从xmit_hold_q取出BT_HDR赋值给p_buf,紧接调用l2cu_set_acl_hci_header,第三次调整BT_HDR,从BT_HDR.offset: 9,BT_HDR.len: 11改到BT_HDR.offset: 5, BT_HDR.len: 15。
  6. [stack/l2cap/l2c_link.c]l2c_link_send_to_lower()。
  7. [main/bte_main.c]bte_main_hci_send()。
  8. [hci/src/hci_layer.c]transmit_downward()。以BT_HDR结构的请求作为data,把它放入packet_queue队列。

因为packet_queue有新对象进入,触发该队列关联的event_packet_ready。(较老bt协议栈,hci部分有问题。新的参考图1)

  1. [hci/src/hci_layer.c]event_packet_ready()。
  2. [hci/src/packet_fragmenter.c]fragment_and_dispatch()。此时BT_HDR.event: 0x2100,BT_HDR.offset: 5, BT_HDR.len: 15。
  3. [hci/src/hci_hal_h4.c]transmit_fragment()。BT_HDR.event值0x2100(MSG_STACK_TO_HC_HCI_ACL),经过event_to_data_type后,得到type值2(DATA_TYPE_ACL)。send_transmit_finished: true。
  4. [hci/src/hci_hal_h4.c]transmit_data()。调用write(uart_fd, ...),把15字节的数据写入串口,即发向了蓝牙硬件模块。

1.2 接收应答

hci_thread线程一直poll设备节点,有数据就会调用event_uart_has_bytes来处理。(较老bt协议栈,hci部分有问题。新的参考图1)

  1. [hci/src/hci_hal_h4.c]event_uart_has_bytes()。从串口read数据。
  2. [hci/src/hci_layer.c]hal_says_data_ready(serial_data_type_t type:DATA_TYPE_ACL(2))。type值有1、2、3、4,针对每种type,hci_layer.c各开辟一个接收缓冲区incoming_packets[idx]。但由于不会收到DATA_TYPE_COMMAND(1),这个incoming_packets长度(INBOUND_PACKET_TYPE_COUNT)是3,“type - 2”可算出该type在incoming_packets内索引。由于输入参数type值是DATA_TYPE_ACL,回调的是“packet_fragmenter->reassemble_and_dispatch(incoming->buffer)”。
  3. [hci/src/packet_fragmenter.c]reassemble_and_dispatch()。
  4. [hci/src/hci_layer.c]dispatch_reassembled()。成员upwards_data_queue指向btu_hci_msg_queue,收到的BT_HDR格式packet放到btu_hci_msg_queue,BT_HDR.event: 0x1100。

因为btu_hci_msg_queue有新对象进入,触发该队列关联的btu_hci_msg_ready。

  1. [stack/btu/btu_task.c]btu_hci_msg_ready()。
  2. [stack/btu/btu_task.c]btu_hci_msg_process()。BT_HDR.event值是0x1100(BT_EVT_TO_BTU_HCI_ACL),调用l2c_rcv_acl_data。
  3. [stack/l2cap/l2c_main.c]l2c_rcv_acl_data()。调用pL2CA_FixedData_Cb,这一个函数指针,指向gatt_le_data_ind。
  4. [stack/gatt/gatt_main.c]gatt_le_data_ind()。
  5. [stack/gatt/gatt_main.c]gatt_data_process()。
  6. [stack/gatt/gatt_cl.c]gatt_client_handle_server_rsp()。op_code值0x11(GATT_RSP_READ_BY_GRP_TYPE),调用gatt_process_read_by_type_rsp。
  7. [stack/gatt/gatt_cl.c]gatt_process_read_by_type_rsp()。p_clcb->operation == GATTC_OPTYPE_DISCOVERY && p_clcb->op_subtype == GATT_DISC_SRVC_ALL && op_code == GATT_RSP_READ_BY_GRP_TYPE。

 

二、VendorInterface::Open

<aosp>/hardware/interfaces/bluetooth/1.0/default/vendor_interface.cc
---
bool VendorInterface::Open(InitializeCompleteCallback initialize_complete_cb,
                           PacketReadCallback event_cb,
                           PacketReadCallback acl_cb,
                           PacketReadCallback sco_cb,
                           PacketReadCallback iso_cb) {
  initialize_complete_cb_ = initialize_complete_cb;
  char vendor_lib_name[32];

  // Initialize vendor interface
  if (wifi_type[0] == 0)
	  check_wifi_chip_type_string(wifi_type);
  if ((0 == strncmp(wifi_type, "RTL", 3)) ||
      (0 == strncmp(wifi_type, "SSV", 3))) { // for ssv6051 wifi + rtl8761 bt
    strcpy(vendor_lib_name, VENDOR_REALTEK_LIBRARY_NAME);
  } else {
    strcpy(vendor_lib_name, VENDOR_LIBRARY_NAME);
  }

  ALOGD("%s: %s", __func__, vendor_lib_name);
  lib_handle_ = dlopen(vendor_lib_name, RTLD_NOW);

wifi_type: RTL8822CE。vendor_lib_name:libbt-vendor-realtek.so。

调用dlopen加载libbt-vendor-realtek.so

  if (!lib_handle_) {
    ALOGE("%s unable to open %s (%s)", __func__, vendor_lib_name,
          dlerror());
    return false;
  }

  lib_interface_ = reinterpret_cast<bt_vendor_interface_t*>(
      dlsym(lib_handle_, VENDOR_LIBRARY_SYMBOL_NAME));
  if (!lib_interface_) {
    ALOGE("%s unable to find symbol %s in %s (%s)", __func__,
          VENDOR_LIBRARY_SYMBOL_NAME, vendor_lib_name, dlerror());
    return false;
  }

VENDOR_LIBRARY_SYMBOL_NAME变量值是“BLUETOOTH_VENDOR_LIB_INTERFACE”。厂商库需定义一个名叫“BLUETOOTH_VENDOR_LIB_INTERFACE”的变量,而且类型需是bt_vendor_interface_t。对rtkbt,这BLUETOOTH_VENDOR_LIB_INTERFACE变量见图1左下角。

  // Get the local BD address

  uint8_t local_bda[BluetoothAddress::kBytes];
  if (!BluetoothAddress::get_local_address(local_bda)) {
    LOG_ALWAYS_FATAL("%s: No Bluetooth Address!", __func__);
  }

BluetoothAddress::get_local_address用于得到蓝牙地址,输出参数local_bda存储着结果。它是怎么得到地址的?——为让同一个android镜像能生成不同蓝牙地址,烧写镜像后,是没有确定地址。android第一次启动,第一次get_local_address时,prop变量persist.service.bdroid.bdaddr值是空,于是会生成一个随机地址,然后存入prop变量persist.service.bdroid.bdaddr。这样下次启动时,prop变量persist.service.bdroid.bdaddr不再是空,就取它值为地址,这android设备就一直是这地址了。

  int status = lib_interface_->init(&lib_callbacks, (unsigned char*)local_bda);

调用{<aosp>/hardware/realtek/rtkbt/code/libbt-vendor/src/bt_vendor_rtk.c}init()。

  if (status) {
    ALOGE("%s unable to initialize vendor library: %d", __func__, status);
    return false;
  }

  ALOGD("%s vendor library loaded", __func__);

  // Power on the controller

  int power_state = BT_VND_PWR_ON;
  lib_interface_->op(BT_VND_OP_POWER_CTRL, &power_state);

调用{<aosp>/hardware/realtek/rtkbt/code/libbt-vendor/src/bt_vendor_rtk.c}op(),操作id:BT_VND_OP_POWER_CTRL。

  // Get the UART socket(s)

  int fd_list[CH_MAX] = {0};
  int fd_count = lib_interface_->op(BT_VND_OP_USERIAL_OPEN, &fd_list);

CH_MAX值是4,表示蓝牙有4类通道,下文引的bt_vendor_hci_channels_t可查看是哪4类通道。操作id:BT_VND_OP_USERIAL_OPEN。让打开4条通道。那这里是不是必须返回4个fd呢?——芯片往往只用一个fd设备,它是怎么做的:fd_list的4个单元都填是fd,返回值fd_count是1。针对minipci插槽的RTL8822ce,深入op(BT_VND_OP_USERIAL_OPEN, ...)。此时rtkbt_transtype:0x22。没有RTKBT_TRANS_UART标记。它依次做两件事。

  1. userial_vendor_usb_open()。打开一个设备:/dev/rtkbt_dev。变量vnd_userial.port_name存储着这文件名。
  2. fd = userial_socket_open()。使用socketpair进程间通信机制,两个套接字存储在数组vnd_userial.uart_fd[2],其中uart_fd[0]会做为返回值。
  if (fd_count < 1 || fd_count > CH_MAX - 1) {
    ALOGE("%s: fd_count %d is invalid!", __func__, fd_count);
    return false;
  }

  for (int i = 0; i < fd_count; i++) {
    if (fd_list[i] == INVALID_FD) {
      ALOGE("%s: fd %d is invalid!", __func__, fd_list[i]);
      return false;
    }
  }

  event_cb_ = event_cb;
  PacketReadCallback intercept_events = [this](const hidl_vec<uint8_t>& event) {
    HandleIncomingEvent(event);
  };

  if (fd_count == 1) {
    hci::H4Protocol* h4_hci =
        new hci::H4Protocol(fd_list[0], intercept_events, acl_cb, sco_cb, iso_cb);
    fd_watcher_.WatchFdForNonBlockingReads(
        fd_list[0], [h4_hci](int fd) { h4_hci->OnDataReady(fd); });
    hci_ = h4_hci;

对roc-rk3588s-pc/lubancat4,是进这个入口。依次执行了两个任务,一是创建H4Protocal对象。二是调用WatchFdForNonBlockingReads,它会创建一个线程,该线程的线程函数就是不断调用“h4_hci->OnDataReady(fd)”,后者作用就是从fd读数据,从而实现不断地从蓝牙芯片读出数据,装配成包,向上传去bt协议栈,参考图1“操作:HCI_BLE_EVENT”中底下部分。“NonBlockingReads”指的会用select机制,只有select认为有数据可读了,才会调用read。

  } else {
    hci::MctProtocol* mct_hci =
        new hci::MctProtocol(fd_list, intercept_events, acl_cb);
    fd_watcher_.WatchFdForNonBlockingReads(
        fd_list[CH_EVT], [mct_hci](int fd) { mct_hci->OnEventDataReady(fd); });
    fd_watcher_.WatchFdForNonBlockingReads(
        fd_list[CH_ACL_IN], [mct_hci](int fd) { mct_hci->OnAclDataReady(fd); });
    hci_ = mct_hci;
  }

  // Initially, the power management is off.
  lpm_wake_deasserted = true;

  // Start configuring the firmware
  firmware_startup_timer_ = new FirmwareStartupTimer();
  lib_interface_->op(BT_VND_OP_FW_CFG, nullptr);

  return true;
}

realtek厂商库定义的名叫“BLUETOOTH_VENDOR_LIB_INTERFACE”的变量,按规则,类型须是bt_vendor_interface_t。

<aosp>/hardware/interfaces/bluetooth/1.0/default/bt_vendor_lib.h
typedef enum {
  CH_CMD,      // HCI Command channel
  CH_EVT,      // HCI Event channel
  CH_ACL_OUT,  // HCI ACL downstream channel
  CH_ACL_IN,   // HCI ACL upstream channel

  CH_MAX  // Total channels
} bt_vendor_hci_channels_t;

CH_MAX指示蓝牙通道数。

 

 

全部评论: 0

    写评论: