Zephyr ESP32 蓝牙驱动简析

本文简要分析zephyr上esp32的蓝牙驱动实现。

本文主要分析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_open

static 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;

接收 链接到标题

接收数据是依靠注册的callback

static 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,通知没有在接收数据, 之后才能发送数据

static void hci_esp_controller_rcv_pkt_ready(void)
{
	//通过sem通知接收已经完成,发送可以进行
	k_sem_give(&hci_send_sem);
}

当esp32蓝牙驱动收到数据后调用hci_esp_host_rcv_pkt,进行数据接收处理

static 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_send

int 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将数据发送出去

static 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