一、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_tbt_vendor_opcode_tbt_vendor_callbacks_t 等类型和接口。

OpenHarmony HDI 层定义了自己的 vendor 接口规范(BtVendorInterfaceTBtOpcodeTBtVendorCallbacksT),其中 OPCODE 的拆分粒度、回调函数的数量、结构体字段命名等方面与 AOSP 接口存在差异。

本次9612U 适配方案采用头文件兼容层(Wrapper Header) 方式,通过在 vendor lib 侧增加一个包装头文件,利用编译期 typedef 类型别名和 #define 宏映射,将 AOSP 接口符号静默转换为 OpenHarmony 接口符号,实现零运行时开销的接口适配。

2.2 适配方案架构

img


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_cbscocfg_cblpm_cb)合并为 1 个 initCb。因为在 9612U 实际使用中,SCO 配置和 LPM 配置的完成通知与固件配置完成通知语义相同(都是通知 HDI 层初始化操作的结果),无需区分。


3.3 OPCODE 枚举差异

OpenHarmony 定义的 BtOpcodeT

typedef enum {
    BT_OP_POWER_ON,          // 上电(独立 OPBT_OP_POWER_OFF,         // 下电(独立 OPBT_OP_HCI_CHANNEL_OPEN,  // 打开 HCI 通道
    BT_OP_HCI_CHANNEL_CLOSE, // 关闭 HCI 通道
    BT_OP_INIT,              // 初始化(合并了 FW_CFG + SCO_CFGBT_OP_GET_LPM_TIMER,     // 获取 LPM 超时
    BT_OP_LPM_ENABLE,        // 使能 LPM(独立 OPBT_OP_LPM_DISABLE,       // 禁用 LPM(独立 OPBT_OP_WAKEUP_LOCK,       // 唤醒锁定(独立 OPBT_OP_WAKEUP_UNLOCK,     // 唤醒解锁(独立 OPBT_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_cbscocfg_cblpm_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.cop() 函数 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 模组蓝牙驱动接口适配的核心方案如下:

  1. 采用 Wrapper Header 编译期适配方案
    通过一个包装头文件 bt_vendor_lib.h,使用 typedef 类型别名和 #define 宏映射,将厂商 AOSP 风格接口符号静默转换为 OpenHarmony 接口符号,零运行时开销。

  2. vendor lib 编译产物最终命名为 libbt_vendor.z.so
    HDI 层通过固定名称 dlopen("libbt_vendor.z.so") 加载动态库(定义在 bt_hal_constant.hBT_VENDOR_NAME 常量)。

  3. vendor lib 必须导出 BLUETOOTH_VENDOR_LIB_INTERFACE 符号
    OpenHarmony HDI 通过 dlsym() 获取该 BtVendorInterfaceT 结构体指针,进而调用 init/op/close

  4. OPCODE 从 AOSP 的"参数区分模式"改为 OHOS 的"独立 OP 模式"
    BT_VND_OP_POWER_CTRL 拆为 BT_OP_POWER_ON/BT_OP_POWER_OFFBT_VND_OP_LPM_SET_MODE 拆为 BT_OP_LPM_ENABLE/BT_OP_LPM_DISABLEBT_VND_OP_LPM_WAKE_SET_STATE 拆为 BT_OP_WAKEUP_LOCK/BT_OP_WAKEUP_UNLOCK。拆分后消除了 switch-case 内部的 if/else 嵌套判断,语义更清晰。

  5. 回调字段从 3 个合并为 1 个
    AOSP 的 fwcfg_cbscocfg_cblpm_cb 通过宏统一映射到 OHOS 的 initCb,实际使用中 SCO 和 LPM 的回调在 9612U 上无独立处理逻辑,合并不影响功能。

  6. 整体方案不需要大规模修改 OpenHarmony 蓝牙框架代码
    仅需在 device/board 目录下新增包装头文件并对厂商入口文件做约 20 行修改,即可完成适配。

Logo

社区规范:仅讨论OpenHarmony相关问题。

更多推荐