兆通微 9612U 模组蓝牙驱动接口适配方案
一、OpenHarmony 蓝牙架构
OpenHarmony 蓝牙系统整体可分为应用层、蓝牙框架层、硬件驱动框架层以及硬件层。各层职责如下:
| 层级 | 说明 |
|---|---|
| APP | 蓝牙应用程序,通过调用蓝牙接口实现应用功能 |
| Bluetooth | 蓝牙框架层,主要包括 interface 和 services |
| interface | 向上层应用程序提供蓝牙功能接口 |
| services | 负责 interface 接口和蓝牙协议栈的实现 |
| HDF | 硬件驱动框架,包含 OpenHarmony 定义的 vendor interface 以及厂商 vendor lib |
| Hardware | 蓝牙硬件设备,主要为内核驱动 |
OpenHarmony 蓝牙适配的核心思路是:
通过 HDF/HDI 层将 OpenHarmony 蓝牙框架与厂商提供的蓝牙 vendor lib 对接,从而打通从应用到硬件的蓝牙功能链路。
二、9612U 蓝牙适配总体方案
2.1 方案概述
兆通微(ZTop)9612U 模组厂商提供了基于 AOSP(Android Open Source Project)蓝牙 HAL 接口的 vendor lib 源码。该源码使用 AOSP 定义的 bt_vendor_interface_t、bt_vendor_opcode_t、bt_vendor_callbacks_t 等类型和接口。
OpenHarmony HDI 层定义了自己的 vendor 接口规范(BtVendorInterfaceT、BtOpcodeT、BtVendorCallbacksT),其中 OPCODE 的拆分粒度、回调函数的数量、结构体字段命名等方面与 AOSP 接口存在差异。
本次9612U 适配方案采用头文件兼容层(Wrapper Header) 方式,通过在 vendor lib 侧增加一个包装头文件,利用编译期 typedef 类型别名和 #define 宏映射,将 AOSP 接口符号静默转换为 OpenHarmony 接口符号,实现零运行时开销的接口适配。
2.2 适配方案架构

2.3 HDI 调用厂商 lib 的实现
HDI 层在 VendorInterface::Initialize() 中通过 dlopen/dlsym 动态加载厂商 lib。
关键加载逻辑:
// 加载 libbt_vendor.z.so(HDI 写死动态库名称)
vendorHandle_ = dlopen(BT_VENDOR_NAME, RTLD_NOW);
// 读取导出的符号 BLUETOOTH_VENDOR_LIB_INTERFACE
vendorInterface_ =
reinterpret_cast<BtVendorInterfaceT *>(
dlsym(vendorHandle_, BT_VENDOR_INTERFACE_SYMBOL_NAME));
其中:
BT_VENDOR_NAME定义为"libbt_vendor.z.so"BT_VENDOR_INTERFACE_SYMBOL_NAME定义为"BLUETOOTH_VENDOR_LIB_INTERFACE"
然后按固定顺序调用 vendor lib 的接口函数,完成蓝牙初始化:
// Step 1: 调用 init,传入 HDI 侧准备好的回调钩子
vendorInterface_->init(&vendorCallbacks_, address.data());
// Step 2: 上电
vendorInterface_->op(BtOpcodeT::BT_OP_POWER_ON, nullptr);
// Step 3: 打开 HCI 通道,获取通信 fd
int channel[HCI_MAX_CHANNEL] = {0};
int channelCount = vendorInterface_->op(BtOpcodeT::BT_OP_HCI_CHANNEL_OPEN, channel);
// Step 4: 固件初始化
vendorInterface_->op(BtOpcodeT::BT_OP_INIT, nullptr);
三、OpenHarmony 与 9612U 厂商接口差异分析
3.1 bt_vendor_interface_t 结构体差异
OpenHarmony 定义的 BtVendorInterfaceT:
typedef struct {
size_t size;
int (*init)(const BtVendorCallbacksT* pCb, unsigned char* localBdaddr);
int (*op)(BtOpcodeT opcode, void* param);
void (*close)(void);
} BtVendorInterfaceT;
9612U 厂商使用的 AOSP 风格 bt_vendor_interface_t:
typedef struct {
size_t size;
int (*init)(const bt_vendor_callbacks_t *p_cb, unsigned char *local_bdaddr);
int (*op)(bt_vendor_opcode_t opcode, void *param);
void (*cleanup)(void);
} bt_vendor_interface_t;
差异分析:
| 差异项 | OpenHarmony | 厂商 AOSP | 适配方式 |
|---|---|---|---|
| 接口类型名 | BtVendorInterfaceT |
bt_vendor_interface_t |
typedef BtVendorInterfaceT bt_vendor_interface_t |
| 回调参数类型 | BtVendorCallbacksT* |
bt_vendor_callbacks_t* |
typedef BtVendorCallbacksT bt_vendor_callbacks_t |
| OPCODE 类型 | BtOpcodeT |
bt_vendor_opcode_t |
typedef BtOpcodeT bt_vendor_opcode_t |
| 关闭函数名 | close |
cleanup |
厂商源码中实现 cleanup,结构体赋值时填入 cleanup,编译无报错 |
3.2 bt_vendor_callbacks_t 结构体差异
OpenHarmony 定义的 BtVendorCallbacksT:
typedef struct {
size_t size;
InitCallback initCb; // 仅一个初始化回调
MallocCallback alloc;
FreeCallback dealloc;
CmdXmitCallback xmitCb;
} BtVendorCallbacksT;
9612U 厂商使用的 AOSP 风格 bt_vendor_callbacks_t:
typedef struct {
size_t size;
cfg_result_cb fwcfg_cb; // 固件配置回调
cfg_result_cb scocfg_cb; // SCO 配置回调
cfg_result_cb lpm_cb; // LPM 使能/禁用回调
malloc_cb alloc;
mdealloc_cb dealloc;
cmd_xmit_cb xmit_cb;
} bt_vendor_callbacks_t;
差异分析:
| OpenHarmony 字段 | 厂商 AOSP 字段 | 适配方式 |
|---|---|---|
| initCb | fwcfg_cb | #define fwcfg_cb initCb,宏展开后厂商源码中所有 fwcfg_cb 变为 initCb |
| 无对应 | scocfg_cb | #define scocfg_cb initCb,合并到 initCb,厂商调用 scocfg_cb 实际触发 initCb |
| 无对应 | lpm_cb | #define lpm_cb initCb,合并到 initCb |
| alloc | alloc | 直接兼容 |
| dealloc | dealloc | 直接兼容 |
| xmitCb | xmit_cb | #define xmit_cb xmitCb,宏映射 |
关键设计决策:OpenHarmony 将 AOSP 的 3 个独立回调(fwcfg_cb、scocfg_cb、lpm_cb)合并为 1 个 initCb。因为在 9612U 实际使用中,SCO 配置和 LPM 配置的完成通知与固件配置完成通知语义相同(都是通知 HDI 层初始化操作的结果),无需区分。
3.3 OPCODE 枚举差异
OpenHarmony 定义的 BtOpcodeT:
typedef enum {
BT_OP_POWER_ON, // 上电(独立 OP)
BT_OP_POWER_OFF, // 下电(独立 OP)
BT_OP_HCI_CHANNEL_OPEN, // 打开 HCI 通道
BT_OP_HCI_CHANNEL_CLOSE, // 关闭 HCI 通道
BT_OP_INIT, // 初始化(合并了 FW_CFG + SCO_CFG)
BT_OP_GET_LPM_TIMER, // 获取 LPM 超时
BT_OP_LPM_ENABLE, // 使能 LPM(独立 OP)
BT_OP_LPM_DISABLE, // 禁用 LPM(独立 OP)
BT_OP_WAKEUP_LOCK, // 唤醒锁定(独立 OP)
BT_OP_WAKEUP_UNLOCK, // 唤醒解锁(独立 OP)
BT_OP_EVENT_CALLBACK // 事件回调
} BtOpcodeT;
9612U 厂商使用的 AOSP 风格 bt_vendor_opcode_t:
typedef enum {
BT_VND_OP_POWER_CTRL, // 上下电(通过参数区分)
BT_VND_OP_FW_CFG, // 固件配置
BT_VND_OP_SCO_CFG, // SCO 配置
BT_VND_OP_USERIAL_OPEN, // 打开串口
BT_VND_OP_USERIAL_CLOSE, // 关闭串口
BT_VND_OP_GET_LPM_IDLE_TIMEOUT, // 获取 LPM 超时
BT_VND_OP_LPM_SET_MODE, // LPM 模式设置(通过参数区分使能/禁用)
BT_VND_OP_LPM_WAKE_SET_STATE, // LPM 唤醒状态设置(通过参数区分)
BT_OP_EVENT_CALLBACK // 事件回调
} bt_vendor_opcode_t;
3.4 OPCODE 映射关系总表
OpenHarmony 的设计理念是将 AOSP 中"一个 OP + 参数枚举判断方向"的模式拆分为多个独立 OP,消除运行时判断:
| OpenHarmony opcode | 厂商 AOSP opcode | 映射方式 | 说明 |
|---|---|---|---|
| BT_OP_POWER_ON | BT_VND_OP_POWER_CTRL | 厂商源码 switch-case 中直接使用 OHOS OPCODE | AOSP 通过 int* 参数区分 ON/OFF,OHOS 拆为两个独立 OP,语义更清晰 |
| BT_OP_POWER_OFF | BT_VND_OP_POWER_CTRL | 同上 | 同上 |
| BT_OP_HCI_CHANNEL_OPEN | BT_VND_OP_USERIAL_OPEN | #define BT_VND_OP_USERIAL_OPEN BT_OP_HCI_CHANNEL_OPEN |
一一对应,直接宏映射 |
| BT_OP_HCI_CHANNEL_CLOSE | BT_VND_OP_USERIAL_CLOSE | #define BT_VND_OP_USERIAL_CLOSE BT_OP_HCI_CHANNEL_CLOSE |
一一对应,直接宏映射 |
| BT_OP_INIT | BT_VND_OP_FW_CFG | #define BT_VND_OP_FW_CFG BT_OP_INIT |
AOSP 的 SCO_CFG 在 9612U 中为空实现,仅 FW_CFG 有效,故合并 |
| BT_OP_GET_LPM_TIMER | BT_VND_OP_GET_LPM_IDLE_TIMEOUT | #define BT_VND_OP_GET_LPM_IDLE_TIMEOUT BT_OP_GET_LPM_TIMER |
一一对应,直接宏映射 |
| BT_OP_LPM_ENABLE | BT_VND_OP_LPM_SET_MODE | 厂商源码 switch-case 中直接使用 OHOS OPCODE | 原 AOSP 通过参数 BT_VND_LPM_ENABLE/BT_VND_LPM_DISABLE 区分 |
| BT_OP_LPM_DISABLE | BT_VND_OP_LPM_SET_MODE | 同上 | 同上 |
| BT_OP_WAKEUP_LOCK | BT_VND_OP_LPM_WAKE_SET_STATE | 厂商源码 switch-case 中直接使用 OHOS OPCODE | 原 AOSP 通过参数 BT_VND_LPM_WAKE_ASSERT/BT_VND_LPM_WAKE_DEASSERT 区分 |
| BT_OP_WAKEUP_UNLOCK | BT_VND_OP_LPM_WAKE_SET_STATE | 同上 | 同上 |
| BT_OP_EVENT_CALLBACK | BT_OP_EVENT_CALLBACK | 同名,直接兼容 | 事件回调处理 |
四、适配实现详解
4.1 包装头文件结构
适配的核心文件为 device/board/hisilicon/shaolingun/bluetooth/include/bt_vendor_lib.h,其结构分为四个层次:
bt_vendor_lib.h
├── 第一层:OHOS 原生类型定义
│ ├── BtOpResultT (枚举: BTC_OP_RESULT_SUCCESS/FAIL)
│ ├── BtOpcodeT (枚举: BT_OP_POWER_ON 等)
│ ├── hci_channels_t (枚举: HCI_CMD/HCI_EVT/HCI_ACL_OUT/HCI_ACL_IN)
│ ├── BtVendorCallbacksT (结构体: initCb/alloc/dealloc/xmitCb)
│ ├── BtVendorInterfaceT (结构体: init/op/close)
│ └── HC_BT_HDR (HCI 数据包头)
├── 第二层:AOSP 类型别名 (typedef)
│ ├── typedef BtOpcodeT bt_vendor_opcode_t
│ ├── typedef BtVendorCallbacksT bt_vendor_callbacks_t
│ └── typedef BtVendorInterfaceT bt_vendor_interface_t
├── 第三层:回调字段宏映射 (#define)
│ ├── #define fwcfg_cb initCb
│ ├── #define scocfg_cb initCb
│ ├── #define lpm_cb initCb
│ └── #define xmit_cb xmitCb
├── 第四层:OPCODE 宏映射 (#define)
│ ├── #define BT_VND_OP_USERIAL_OPEN BT_OP_HCI_CHANNEL_OPEN
│ ├── #define BT_VND_OP_USERIAL_CLOSE BT_OP_HCI_CHANNEL_CLOSE
│ ├── #define BT_VND_OP_GET_LPM_IDLE_TIMEOUT BT_OP_GET_LPM_TIMER
│ ├── #define BT_VND_OP_FW_CFG BT_OP_INIT
│ ├── #define BT_VND_OP_POWER_CTRL 0x100 (不映射,独立值)
│ ├── #define BT_VND_OP_LPM_SET_MODE 0x101
│ ├── #define BT_VND_OP_LPM_WAKE_SET_STATE 0x102
│ └── #define BT_VND_OP_SCO_CFG 0x103
└── 附加:AOSP 兼容枚举类型 (enum)
├── bt_vendor_hci_channels_t (CH_CMD = HCI_CMD, ...)
├── bt_vendor_power_state_t (BT_VND_PWR_OFF/ON)
├── bt_vendor_lpm_mode_t (BT_VND_LPM_DISABLE/ENABLE)
└── bt_vendor_lpm_wake_state_t (BT_VND_LPM_WAKE_ASSERT/DEASSERT)
4.2 typedef 类型别名机制
通过 typedef 将 OHOS 新类型名与 AOSP 旧类型名关联,使厂商源码中的所有 AOSP 类型声明自动指向 OHOS 类型:
// OHOS 原生定义(在 bt_vendor_lib.h 中第一层定义)
typedef enum { BT_OP_POWER_ON, BT_OP_POWER_OFF, ... } BtOpcodeT;
typedef struct { size_t size; InitCallback initCb; ... } BtVendorCallbacksT;
typedef struct { size_t size; int (*init)(...); int (*op)(...); void (*close)(...); } BtVendorInterfaceT;
// AOSP 别名(第二层),编译器层面生效
typedef BtOpcodeT bt_vendor_opcode_t; // 厂商源码中的 bt_vendor_opcode_t → BtOpcodeT
typedef BtVendorCallbacksT bt_vendor_callbacks_t; // 厂商源码中的 bt_vendor_callbacks_t → BtVendorCallbacksT
typedef BtVendorInterfaceT bt_vendor_interface_t; // 厂商源码中的 bt_vendor_interface_t → BtVendorInterfaceT
厂商源码中的全局变量声明:
// bt_vendor_ztop.c 源码
bt_vendor_callbacks_t *bt_vendor_cbacks = NULL;
// 经 typedef 展开后实际编译为:
// BtVendorCallbacksT *bt_vendor_cbacks = NULL;
4.3 回调字段宏映射机制
AOSP 接口有独立的 fwcfg_cb、scocfg_cb、lpm_cb 三个回调字段,而 OHOS 只有 initCb 一个。通过宏将它们全部映射到 initCb:
#define fwcfg_cb initCb
#define scocfg_cb initCb
#define lpm_cb initCb
#define xmit_cb xmitCb
厂商源码中调用 fwcfg_cb 的示例:
// hardware.c 中的源码(看起来是 AOSP 风格)
if (bt_vendor_cbacks) {
bt_vendor_cbacks->fwcfg_cb(BT_VND_OP_RESULT_FAIL);
}
// 预处理器展开后实际编译的代码:
// if (bt_vendor_cbacks) {
// bt_vendor_cbacks->initCb(BTC_OP_RESULT_FAIL);
// }
//
// 其中 bt_vendor_cbacks 经 typedef 展开为 BtVendorCallbacksT*
// BT_VND_OP_RESULT_FAIL 经 #define 展开为 BTC_OP_RESULT_FAIL
厂商源码中 vendor lib 导出符号定义:
// bt_vendor_ztop.c 源码
const bt_vendor_interface_t BLUETOOTH_VENDOR_LIB_INTERFACE = {
sizeof(bt_vendor_interface_t),
init,
op,
cleanup // 厂商函数名为 cleanup
};
// 展开后:
// const BtVendorInterfaceT BLUETOOTH_VENDOR_LIB_INTERFACE = {
// sizeof(BtVendorInterfaceT),
// init,
// op,
// cleanup // 字段名为 close,但赋值为 cleanup 函数指针,完全合法
// };
4.4 OPCODE 宏映射机制
对于一一对应的 OPCODE,直接 #define 映射:
// 预处理器层面,编译前即完成替换
#define BT_VND_OP_USERIAL_OPEN BT_OP_HCI_CHANNEL_OPEN
#define BT_VND_OP_USERIAL_CLOSE BT_OP_HCI_CHANNEL_CLOSE
#define BT_VND_OP_GET_LPM_IDLE_TIMEOUT BT_OP_GET_LPM_TIMER
#define BT_VND_OP_FW_CFG BT_OP_INIT
对于被拆分的 OPCODE(AOSP 一个 OP 对应 OHOS 多个 OP),9612U 的 bt_vendor_ztop.c 源码在 switch-case 中直接使用 OHOS 原生 OPCODE:
// bt_vendor_ztop.c 的 op() 函数
static int op(bt_vendor_opcode_t opcode, void *param) // 参数类型经 typedef 展开为 BtOpcodeT
{
switch(opcode)
{
// 直接使用 OHOS 原生枚举值,不做任何映射
case BT_OP_POWER_ON:
{ /* 上电时序: usleep 等待电容稳定 */ }
break;
case BT_OP_POWER_OFF:
{ /* 下电时序 */ }
break;
case BT_OP_INIT: // 替代 AOSP 的 BT_VND_OP_FW_CFG
{ /* 固件下载 + 硬件初始化 */ }
break;
case BT_OP_HCI_CHANNEL_OPEN: // 替代 AOSP 的 BT_VND_OP_USERIAL_OPEN
{ /* 打开 /dev/ztopbt_dev, 返回 fd */ }
break;
case BT_OP_HCI_CHANNEL_CLOSE:
{ /* 关闭设备 */ }
break;
case BT_OP_LPM_DISABLE:
{ /* 禁用 LPM,设置接口状态为关闭 */ }
break;
// 以下 OPCODE 在 OHOS 接口中存在,但 9612U 实现为空操作
case BT_OP_GET_LPM_TIMER:
case BT_OP_LPM_ENABLE:
case BT_OP_WAKEUP_LOCK:
case BT_OP_WAKEUP_UNLOCK:
break;
case BT_OP_EVENT_CALLBACK:
hw_process_event((HC_BT_HDR *)param, ztopbt_transtype);
break;
}
return retval;
}
五、BT_OP_EVENT_CALLBACK 处理机制
5.1 HDI 侧事件注入
HDI 层 VendorInterface::OnEventReceived() 在收到 HCI Event 后,判断是否需要回调 vendor lib:
void VendorInterface::OnEventReceived(const std::vector<uint8_t> &data)
{
// 场景1: Vendor Specific Event (0xFF) → 直接回调 vendor lib
if (data[0] == Hci::HCI_EVENT_CODE_VENDOR_SPECIFIC) {
HC_BT_HDR *buff =
/* 构造 HC_BT_HDR 并拷贝 data */;
vendorInterface_->op(BtOpcodeT::BT_OP_EVENT_CALLBACK, buff);
delete[] buff;
}
// 场景2: Command Complete Event (0x0E) → 匹配 opcode 后回调 vendor lib
else if (vendorSentOpcode_ != 0 && data[0] == Hci::HCI_EVENT_CODE_COMMAND_COMPLETE) {
uint16_t opcode =
/* 从 data 中解析 opcode */;
if (opcode == vendorSentOpcode_) {
HC_BT_HDR *buff =
/* 构造 HC_BT_HDR 并拷贝 data */;
vendorSentOpcode_ = 0; // 清除已匹配的 opcode
vendorInterface_->op(BtOpcodeT::BT_OP_EVENT_CALLBACK, buff);
delete[] buff;
}
}
// 继续上报给上层 Service
eventDataCallback_(data);
}
5.2 厂商侧事件处理
9612U 厂商 lib 中的 hw_process_event() 根据 HCI Command 的 opcode 分发到对应的回调处理函数:
void hw_process_event(HC_BT_HDR *p_buf, char transtype)
{
uint16_t opcode = /* 从 event buffer 解析 command opcode */;
switch (opcode) {
case HCI_VSC_WRITE_BD_ADDR: // 写 BDADDR 完成
case HCI_VSC_DOWNLOAD_FW_PATCH: // 固件下载完成
case HCI_READ_LMP_VERSION: // 读 LMP 版本完成
case HCI_VSC_H5_INIT: // H5 初始化完成
case HCI_VENDOR_RESET: // 厂商复位完成
// 根据传输类型(USB/UART)调用对应回调
hw_config_cback(p_buf); // 或 hw_usb_config_cback(p_buf)
break;
}
}
六、bt_vendor_ztop.c 中厂商源码的修改点
9612U 适配方案对厂商原始 AOSP 源码的修改集中在 bt_vendor_ztop.c 的 op() 函数 switch-case 中:
6.1 上下电 OPCODE 拆分
原 AOSP 代码使用单一 OP + 参数判断:
// 原始 AOSP 风格(修改前)
case BT_VND_OP_POWER_CTRL:
{
int *state = (int *) param;
if (*state == BT_VND_PWR_OFF) {
// 下电逻辑
} else if (*state == BT_VND_PWR_ON) {
// 上电逻辑
}
}
break;
适配后拆分为两个独立 case:
// OHOS 适配后(修改后)
case BT_OP_POWER_ON:
{
// 上电逻辑
}
break;
case BT_OP_POWER_OFF:
{
// 下电逻辑
}
break;
6.2 LPM OPCODE 拆分
原 AOSP 代码使用单一 OP + 参数判断 LPM 模式:
// 原始 AOSP 风格(修改前)
case BT_VND_OP_LPM_SET_MODE:
{
bt_vendor_lpm_mode_t mode = *(bt_vendor_lpm_mode_t *) param;
if (mode == BT_VND_LPM_DISABLE) {
userial_set_bt_interface_state(0);
}
// BT_VND_LPM_ENABLE 下无操作
}
break;
适配后拆分为两个独立 case(仅 DISABLE 有实际操作):
// OHOS 适配后(修改后)
case BT_OP_LPM_DISABLE:
{
userial_set_bt_interface_state(0);
}
break;
case BT_OP_LPM_ENABLE:
// 9612U 无额外操作
break;
6.3 Wakeup OPCODE 拆分
// OHOS 适配后(修改后)
case BT_OP_WAKEUP_LOCK:
// 9612U 无额外操作
break;
case BT_OP_WAKEUP_UNLOCK:
// 9612U 无额外操作
break;
6.4 修改量统计
| 文件 | 修改内容 | 修改规模 |
|---|---|---|
| bt_vendor_ztop.c | op() 函数 switch-case:原 BT_VND_OP_POWER_CTRL 拆为 BT_OP_POWER_ON/BT_OP_POWER_OFF;原 BT_VND_OP_LPM_SET_MODE 拆为 BT_OP_LPM_ENABLE/BT_OP_LPM_DISABLE;新增 BT_OP_WAKEUP_LOCK/BT_OP_WAKEUP_UNLOCK case |
约 20 行 |
| bt_vendor_lib.h | 全新编写包装头文件 | 约 200 行(一次性工作) |
| 其他厂商源文件 | 无需修改 | 0 行 |
七、BUILD.gn 编译配置
7.1 Vendor Lib 编译配置
ohos_shared_library("libbt_vendor") {
output_name = "libbt_vendor"
sources = [
"src/bt_vendor_ztop.c", # 入口(已适配 OHOS OPCODE)
"src/hardware.c", # 固件下载
"src/hci_h5.c", # H5 协议
"src/userial_vendor.c", # 串口/USB管理
# ... 其他厂商源文件,无需修改 ...
]
include_dirs = [
"include", # bt_vendor_lib.h (Wrapper Header)
"//drivers/peripheral/bluetooth/hci/hdi_service/implement", # ohos_bt_vendor_lib.h (HDI 侧定义)
"//commonlibrary/c_utils/base/include",
"//base/hiviewdfx/interfaces/innerkits/libhilog/include",
]
external_deps = [
"c_utils:utils",
"hilog:libhilog",
]
install_enable = true
install_images = [ chipset_base_dir ]
}
关键要点:
output_name必须为"libbt_vendor",最终编译产物在 chipset_base_dir 镜像下自动命名为libbt_vendor.z.so,与 HDI 层dlopen("libbt_vendor.z.so")对应include_dirs同时包含 vendor lib 自己的include/和 HDI service 的implement/目录- vendor lib 编译时会优先找到自己
include/下的bt_vendor_lib.h(Wrapper Header),而非 HDI 侧的ohos_bt_vendor_lib.h
7.2 HDI Service 编译配置
HDI Service 侧通过独立的 BUILD.gn 编译,其 include 路径仅引用 HDI service 自身目录下的 ohos_bt_vendor_lib.h(纯净 OHOS 接口),不依赖 vendor lib 目录下的 bt_vendor_lib.h。
这样 HDI Service 和 Vendor Lib 两个编译单元完全隔离,各自使用各自的头文件,互不干扰。
八、适配文件清单
8.1 新增/重写文件
| 文件路径 | 作用 | 说明 |
|---|---|---|
| device/board/hisilicon/shaolingun/bluetooth/include/bt_vendor_lib.h | Wrapper Header,接口适配核心 | 全新编写,约 215 行 |
| device/board/hisilicon/shaolingun/bluetooth/BUILD.gn | 编译配置 | 配置编译目标、include 路径和依赖 |
8.2 修改的厂商源文件
| 文件路径 | 修改范围 | 说明 |
|---|---|---|
| device/board/hisilicon/shaolingun/bluetooth/src/bt_vendor_ztop.c | op() 函数 switch-case 分支 | 将 AOSP OPCODE 替换为 OHOS OPCODE,约 20 行改动 |
九、总结
兆通微 9612U 模组蓝牙驱动接口适配的核心方案如下:
-
采用 Wrapper Header 编译期适配方案
通过一个包装头文件bt_vendor_lib.h,使用typedef类型别名和#define宏映射,将厂商 AOSP 风格接口符号静默转换为 OpenHarmony 接口符号,零运行时开销。 -
vendor lib 编译产物最终命名为
libbt_vendor.z.so
HDI 层通过固定名称dlopen("libbt_vendor.z.so")加载动态库(定义在bt_hal_constant.h的BT_VENDOR_NAME常量)。 -
vendor lib 必须导出
BLUETOOTH_VENDOR_LIB_INTERFACE符号
OpenHarmony HDI 通过dlsym()获取该BtVendorInterfaceT结构体指针,进而调用init/op/close。 -
OPCODE 从 AOSP 的"参数区分模式"改为 OHOS 的"独立 OP 模式"
BT_VND_OP_POWER_CTRL拆为BT_OP_POWER_ON/BT_OP_POWER_OFF;BT_VND_OP_LPM_SET_MODE拆为BT_OP_LPM_ENABLE/BT_OP_LPM_DISABLE;BT_VND_OP_LPM_WAKE_SET_STATE拆为BT_OP_WAKEUP_LOCK/BT_OP_WAKEUP_UNLOCK。拆分后消除了 switch-case 内部的 if/else 嵌套判断,语义更清晰。 -
回调字段从 3 个合并为 1 个
AOSP 的fwcfg_cb、scocfg_cb、lpm_cb通过宏统一映射到 OHOS 的initCb,实际使用中 SCO 和 LPM 的回调在 9612U 上无独立处理逻辑,合并不影响功能。 -
整体方案不需要大规模修改 OpenHarmony 蓝牙框架代码
仅需在 device/board 目录下新增包装头文件并对厂商入口文件做约 20 行修改,即可完成适配。
更多推荐


所有评论(0)