本文主要分析esp32的蓝牙驱动如何被集成进Zephyr的驱动,并不涉及esp32 蓝牙驱动本身API的说明。
架构
Zephyr的esp32蓝牙驱动架构非常清晰简单,就是Zephyr调用esp32 VHCI接口基于esp32提供的VHCI进行蓝牙数据通信,和esp32自身采用的Bluedroid->VHCI架构一样,只是在Zephyr上VHCI上是自己的蓝牙协议栈。如下图,左边是esp-idf内的价格,右边是zephyr的架构,颜色相同的部分等同,更多请见文末参考
实现
Zephyr的蓝牙驱动也可以分为初始化,收,发来分析
初始化
SYS_INIT注册的初始化函数bt_esp32_init将在系统启动的POST_KERNEL阶段被调用,在bt_esp32_init中使用bt_hci_driver_register将bt_hci_driver注册入host,蓝牙在APPLICATION阶段被初始化,会调用bt_esp32_open1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66static const struct bt_hci_driver drv = {
.name = "BT ESP32",
.open = bt_esp32_open,
.send = bt_esp32_send,
.bus = BT_HCI_DRIVER_BUS_IPM,
#if defined(CONFIG_BT_DRIVER_QUIRK_NO_AUTO_DLE)
.quirks = BT_QUIRK_NO_AUTO_DLE,
#endif
};
static int bt_esp32_init(const struct device *unused)
{
ARG_UNUSED(unused);
//注册hci driver
bt_hci_driver_register(&drv);
return 0;
}
//注册驱动初始化函数
SYS_INIT(bt_esp32_init, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE);
//APPLICATION阶段被调用
static int bt_esp32_open(void)
{
int err;
err = bt_esp32_ble_init();
if (err) {
return err;
}
BT_DBG("ESP32 BT started");
return 0;
}
static int bt_esp32_ble_init(void)
{
int ret;
///调用esp的蓝牙驱动初始化
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
#ifdef CONFIG_BT_BREDR
esp_bt_mode_t mode = ESP_BT_MODE_BTDM;
#else
esp_bt_mode_t mode = ESP_BT_MODE_BLE;
#endif
ret = esp_bt_controller_init(&bt_cfg);
if (ret) {
BT_ERR("Bluetooth controller init failed %d", ret);
return ret;
}
ret = esp_bt_controller_enable(mode);
if (ret) {
BT_ERR("Bluetooth controller enable failed: %d", ret);
return ret;
}
//注册接收数据callback
esp_vhci_host_register_callback(&vhci_host_cb);
return 0;
接收
接收数据是依靠注册的callback1
2
3
4static esp_vhci_host_callback_t vhci_host_cb = {
hci_esp_controller_rcv_pkt_ready,
hci_esp_host_rcv_pkt
};
当数据接收完成后调用hci_esp_controller_rcv_pkt_ready,通知没有在接收数据, 之后才能发送数据1
2
3
4
5static void hci_esp_controller_rcv_pkt_ready(void)
{
//通过sem通知接收已经完成,发送可以进行
k_sem_give(&hci_send_sem);
}
当esp32蓝牙驱动收到数据后调用hci_esp_host_rcv_pkt,进行数据接收处理1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37static int hci_esp_host_rcv_pkt(uint8_t *data, uint16_t len)
{
uint8_t pkt_indicator;
struct net_buf *buf = NULL;
size_t remaining = len;
BT_HEXDUMP_DBG(data, len, "host packet data:");
pkt_indicator = *data++;
remaining -= sizeof(pkt_indicator);
//分类别处理数据
switch (pkt_indicator) {
case HCI_EVT:
buf = bt_esp_evt_recv(data, remaining);
break;
case HCI_ACL:
buf = bt_esp_acl_recv(data, remaining);
break;
case HCI_SCO:
buf = bt_esp_iso_recv(data, remaining);
break;
default:
BT_ERR("Unknown HCI type %u", pkt_indicator);
return -1;
}
if (buf) {
BT_DBG("Calling bt_recv(%p)", buf);
//将数据送到host
bt_recv(buf);
}
return 0;
}
发送
Zephyr蓝牙Host内通过下列流程调用到bt_hci_driver_register提供的send函数bt_esp32_send1
2
3
4
5
6
7
8
9
10
11
12int bt_send(struct net_buf *buf)
{
BT_DBG("buf %p len %u type %u", buf, buf->len, bt_buf_get_type(buf));
bt_monitor_send(bt_monitor_opcode(buf), buf->data, buf->len);
if (IS_ENABLED(CONFIG_BT_TINYCRYPT_ECC)) {
return bt_hci_ecc_send(buf);
}
return bt_dev.drv->send(buf);
}
bt_esp32_send使用ESP32提供的VHCI将数据发送出去1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45static int bt_esp32_send(struct net_buf *buf)
{
int err = 0;
uint8_t pkt_indicator;
BT_DBG("buf %p type %u len %u", buf, bt_buf_get_type(buf), buf->len);
//转换类型识别
switch (bt_buf_get_type(buf)) {
case BT_BUF_ACL_OUT:
pkt_indicator = HCI_ACL;
break;
case BT_BUF_CMD:
pkt_indicator = HCI_CMD;
break;
case BT_BUF_ISO_OUT:
pkt_indicator = HCI_ISO;
break;
default:
BT_ERR("Unknown type %u", bt_buf_get_type(buf));
goto done;
}
net_buf_push_u8(buf, pkt_indicator);
BT_HEXDUMP_DBG(buf->data, buf->len, "Final HCI buffer:");
//检查vhci是否可以发送
if (!esp_vhci_host_check_send_available()) {
BT_WARN("Controller not ready to receive packets");
}
//等待接收完成,才能发送
if (k_sem_take(&hci_send_sem, HCI_BT_ESP32_TIMEOUT) == 0) {
//使用vhci进行发送
esp_vhci_host_send_packet(buf->data, buf->len);
} else {
BT_ERR("Send packet timeout error");
err = -ETIMEDOUT;
}
done:
net_buf_unref(buf);
k_sem_give(&hci_send_sem);
return err;
}
参考
https://www.espressif.com/sites/default/files/documentation/esp32_bluetooth_architecture_cn.pdf
https://docs.zephyrproject.org/latest/guides/bluetooth/bluetooth-arch.html