芯片解决方案--SL8541e-OpenHarmony蓝牙适配分析及方案
OpenHarmony 8541E 蓝牙适配分析及方案 一、OpenHarmony 蓝牙架构Bluetooth service 处理上层js接口发送的消息; Bluetooth stack 蓝牙协议栈的实现; ble 接口的处理主要在btm中,处理host下发的命令。 hci 是host与control间的接口也在协议栈中。 Bluetooth HDI 蓝牙底层设备接口; Bluetooth
芯片解决方案--SL8541e-OpenHarmony蓝牙适配分析及方案
一、OpenHarmony 蓝牙架构
-
APP 蓝牙应用程序,通过调用蓝牙接口(interface)实现应用程序的功能。
-
Bluetooth 蓝牙框架层,主要包括interface和services, interface负责向上层应用程序提供功能接口。services则负责interface接口和蓝牙协议栈的实现。
-
HDF 硬件驱动框架,包含了OpenHarmony定义的vendor interface以及厂商的vendor lib。
-
HardWare 蓝牙硬件设备,主要为内核态驱动。
二、OpenHarmony 蓝牙适配方法
蓝牙芯片厂商通常会提供hal层的vendor lib,OpenHarmony蓝牙的适配只需要将HDI接口对接到厂商的lib就可以从上到下打通蓝牙功能。由于芯片厂商vendor lib的接口可能与OpenHarmony Bluetooth HDI定义的接口不完全一致,需要增加适配层来进行接口的转换。
OpenHarmony HDI调用厂商lib的实现
js接口enableBluetooth()在RK3568上的实现:
-
上层调用到HDI层的HdiInit函数时,会调用IHciInterface这个对外接口类的Init函数。而该函数实际的实现为HciInterfaceImpl::Init()。此时流程进到了driver层。
-
driver层定义了VendorInterface类作为与vendor lib间的接口。
VendorInterface::Initialize函数用于动态加载厂商lib,并且获取到lib的接口保存到vendorInterface_中。这样HDI与厂商lib间的钩子函数就挂接上了。
-
宏BT_VENDOR_INTERFACE_SYMBOL_NAME定义为"BLUETOOTH_VENDOR_LIB_INTERFACE",就是厂商lib对应so文件中定义的接口名字,在VendorInterface::Initialize函数中会调用对应的init和op函数,用来使能BLE。
bool VendorInterface::Initialize( InitializeCompleteCallback initializeCompleteCallback, const ReceiveCallback &receiveCallback) { ... // -->加载 vendor lib,动态库的名字必须为libbt_vendor.z.so vendorHandle_ = dlopen(BT_VENDOR_NAME, RTLD_NOW); if (vendorHandle_ == nullptr) { HDF_LOGE("VendorInterface dlopen %{public}s failed, error code: %{public}s", BT_VENDOR_NAME, dlerror()); return false; } // -->读取符号 BLUETOOTH_VENDOR_LIB_INTERFACE vendorInterface_ = reinterpret_cast<bt_vendor_interface_t *>(dlsym(vendorHandle_, BT_VENDOR_INTERFACE_SYMBOL_NAME)); if (vendorInterface_ == nullptr) { HDF_LOGE("VendorInterface dlsym %{public}s failed.", BT_VENDOR_INTERFACE_SYMBOL_NAME); return false; } ... // -->调用vendor lib中的init函数,vendorCallbacks_为hci的callback函数 int result = vendorInterface_->init(&vendorCallbacks_, address.data()); if (result != 0) { HDF_LOGE("vendorInterface_->init failed."); return false; } // -->调用vendor lib中的op函数,opcode为BT_OP_POWER_ON result = vendorInterface_->op(bt_opcode_t::BT_OP_POWER_ON, nullptr); if (result != 0) { HDF_LOGE("vendorInterface_->op BT_OP_POWER_ON failed."); return false; } ... // --> 调用vendor lib中的op函数,opcode为BT_OP_INIT vendorInterface_->op(bt_opcode_t::BT_OP_INIT, nullptr); return true; }
挂接vendor lib接口
HDI层定义了vendor lib的接口,具体参考
/foundation/communication/bluetooth/services/bluetooth/hardware/include/bt_vendor_lib.h文件。BLE的适配也就是要将以下3处接口挂接上并实现。
-
bt_vendor_interface_t结构体,定义了vendor lib对外的接口,其中包括3个函数: init, op, close,适配的主要工作就是实现这3个函数。
typedef struct { /** * Set to sizeof(bt_vndor_interface_t) */ size_t size; /** * Caller will open the interface and pass in the callback routines * to the implemenation of this interface. */ int (*init)(const bt_vendor_callbacks_t* p_cb, unsigned char* local_bdaddr); /** * Vendor specific operations */ int (*op)(bt_opcode_t opcode, void* param); /** * Closes the interface */ void (*close)(void); } bt_vendor_interface_t;
需要在vendor lib中定义bt_vendor_interface_t,以下为参考代码:
// vendor lib接口定义 const bt_vendor_interface_t BLUETOOTH_VENDOR_LIB_INTERFACE = { sizeof(bt_vendor_interface_t), init, op, cleanup };
-
bt_vendor_callbacks_t是OpenHarmony提供给厂商lib调用的钩子函数,在调用bt_vendor_interface_t.init函数时,需要把bt_vendor_callbacks_t传递给厂商lib。具体请看VendorInterface::Initialize()函数。
/**
* initialization callback.
*/
typedef void (*init_callback)(bt_op_result_t result);
/**
* call the callback to malloc a size of buf.
*/
typedef void* (*malloc_callback)(int size);
/**
* call the callback to free buf
*/
typedef void (*free_callback)(void* buf);
/**
* hci command packet transmit callback
* Vendor lib calls cmd_xmit_cb function in order to send a HCI Command
* packet to BT Controller.
*
* The opcode parameter gives the HCI OpCode (combination of OGF and OCF) of
* HCI Command packet. For example, opcode = 0x0c03 for the HCI_RESET command
* packet.
*/
typedef size_t (*cmd_xmit_callback)(uint16_t opcode, void* p_buf);
typedef struct {
/**
* set to sizeof(bt_vendor_callbacks_t)
*/
size_t size;
/* notifies caller result of init request */
init_callback init_cb;
/* buffer allocation request */
malloc_callback alloc;
/* buffer free request */
free_callback dealloc;
/* hci command packet transmit request */
cmd_xmit_callback xmit_cb;
} bt_vendor_callbacks_t;
-
init_cb 用于通知配置结果;
-
alloc 用于申请内存;
-
dealloc 用于释放内存;
-
xmit_cb 用于下发hci命令;
OpenHarmony中这些钩子函数的定义
// vendor_interface.cpp
bt_vendor_callbacks_t VendorInterface::vendorCallbacks_ = {
.size = sizeof(bt_vendor_callbacks_t),
.init_cb = VendorInterface::OnInitCallback,
.alloc = VendorInterface::OnMallocCallback,
.dealloc = VendorInterface::OnFreeCallback,
.xmit_cb = VendorInterface::OnCmdXmitCallback,
};
- 各op操作的实现
op函数要对以下各op code做相应的处理。
/**
* BT vendor lib cmd.
*/
typedef enum {
/**
* Power on the BT Controller.
* @return 0 if success.
*/
BT_OP_POWER_ON,
/**
* Power off the BT Controller.
* @return 0 if success.
*/
BT_OP_POWER_OFF,
/**
* Establish hci channels. it will be called after BT_OP_POWER_ON.
* @param int (*)[HCI_MAX_CHANNEL].
* @return fd count.
*/
BT_OP_HCI_CHANNEL_OPEN,
/**
* Close all the hci channels which is opened.
*/
BT_OP_HCI_CHANNEL_CLOSE,
/**
* initialization the BT Controller. it will be called after BT_OP_HCI_CHANNEL_OPEN.
* Controller Must call init_cb to notify the host once it has been done.
*/
BT_OP_INIT,
/**
* Get the LPM idle timeout in milliseconds.
* @param (uint_32 *)milliseconds, btc will return the value of lpm timer.
* @return 0 if success.
*/
BT_OP_GET_LPM_TIMER,
/**
* Enable LPM mode on BT Controller.
*/
BT_OP_LPM_ENABLE,
/**
* Disable LPM mode on BT Controller.
*/
BT_OP_LPM_DISABLE,
/**
* Wakeup lock the BTC.
*/
BT_OP_WAKEUP_LOCK,
/**
* Wakeup unlock the BTC.
*/
BT_OP_WAKEUP_UNLOCK,
/**
* transmit event response to vendor lib.
* @param (void *)buf, struct of HC_BT_HDR.
*/
BT_OP_EVENT_CALLBACK
} bt_opcode_t;
- 厂商lib文件名字 因为HDI在加载厂商lib时是写死了so的名字,因此要保证厂商提供的lib文件名字为libbt_vendor.z.so。
三、8541E 蓝牙开源lib接口适配分析
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;
8541E定义的bt_vendor_interface_t结构体中定义的三个函数原型与OpenHarmony一致,只是关闭lib库的cleanup函数与OpenHarmony中的close函数名不同,适配时只需要封装转换函数即可。
bt_vendor_callbacks_t 结构体
此结构体是由协议层实现的函数,通过钩子函数的形式传递到底层厂商lib中进行调用。其中xmit_cb是用于下发hci命令的。
/* vendor initialize/configuration callback */
typedef void (*cfg_result_cb)(bt_vendor_op_result_t result);
/* datapath buffer allocation callback (callout)
*
* Vendor Lib needs to request a buffer through the alloc callout function
* from HCI lib if the buffer is for constructing a HCI Command packet which
* will be sent through xmit_cb to BT Controller.
*
* For each buffer allocation, the requested size needs to be big enough to
* accommodate the below header plus a complete HCI packet --
* typedef struct
* {
* uint16_t event;
* uint16_t len;
* uint16_t offset;
* uint16_t layer_specific;
* } HC_BT_HDR;
*
* HCI lib returns a pointer to the buffer where Vendor lib should use to
* construct a HCI command packet as below format:
*
* --------------------------------------------
* | HC_BT_HDR | HCI command |
* --------------------------------------------
* where
* HC_BT_HDR.event = 0x2000;
* HC_BT_HDR.len = length of HCI command;
* HC_BT_HDR.offset = 0;
* HC_BT_HDR.layer_specific = 0;
* For example, a HCI_RESET Command will be formed as
* ------------------------
* | HCI_BT_HDR |03|0c|00|
* ------------------------
* with
* HC_BT_HDR.event = 0x2000;
* HC_BT_HDR.len = 3;
* HC_BT_HDR.offset = 0;
* HC_BT_HDR.layer_specific = 0;
*/
typedef void* (*malloc_cb)(int size);
/* datapath buffer deallocation callback (callout) */
typedef void (*mdealloc_cb)(void *p_buf);
/* define callback of the cmd_xmit_cb
*
* The callback function which HCI lib will call with the return of command
* complete packet. Vendor lib is responsible for releasing the buffer passed
* in at the p_mem parameter by calling dealloc callout function.
*/
typedef void (*tINIT_CMD_CBACK)(void *p_mem);
/* hci command packet transmit callbac (callout)
*
* Vendor lib calls xmit_cb callout function in order to send a HCI Command
* packet to BT Controller. The buffer carrying HCI Command packet content
* needs to be first allocated through the alloc callout function.
* HCI lib will release the buffer for Vendor lib once it has delivered the
* packet content to BT Controller.
*
* Vendor lib needs also provide a callback function (p_cback) which HCI lib
* will call with the return of command complete packet.
*
* The opcode parameter gives the HCI OpCode (combination of OGF and OCF) of
* HCI Command packet. For example, opcode = 0x0c03 for the HCI_RESET command
* packet.
*/
typedef uint8_t (*cmd_xmit_cb)(uint16_t opcode, void *p_buf,
tINT_CMD_CBACK p_cback);
typedef void (*cfg_a2dp_cb)(bt_vendor_op_result_t result, bt_vendor_opcode_t op,
uint8_t bta_av_handle);
typedef struct {
size_t size;
/* notifise caller result of firmward configuration request */
cfg_result_cb fwcfg_cb;
/* notifies caller result of sco configuration request */
cfg_result_cb scocfg_cb;
/* notifies caller result of lpm enable/disable */
cfg_result_cb lpm_cb;
/* notifies the result of codec setting */
cfg_result_cb audio_state_cb;
/* buffer allocation request */
malloc_cb alloc;
/* buffer deallocation request */
mdealloc_cb dealloc;
/* hci command packet transmit request */
cmd_xmit_cb xmit_cb;
/* notifies caller completion of epilog process */
cfg_result_cb epilog_cb;
/* notifies status of a2dp offload cmd's */
cfg_a2dp_cb a2dp_offload_cb;
} bt_vendor_callbacks_t;
下图为二者定义的bt_vendor_callbacks_t的差异
-
OpenHarmony定义bt_vendor_callbacks_t中的init_cb与854d1E厂商lib中bt_vendor_callbacks_t的fwcfg_cb作用相同,可以直接适配。
-
OpenHarmony与厂商xmit_cb定义的作用相同,但是函数原型不同,厂商lib的xmit_cb定义中多了tINT_CMD_CBACK p_cback参数。需要在适配层实现一个与厂商xmit_cb原型一致的适配函数,其中调用OpenHarmony定义的xmit_cb,这样来实现xmit_cb的功能。
xmit_cb函数的适配包括以下:
1、p_cback的适配
p_cback是厂商lib提供的函数,用于在发送完hci command后,处理接收到command complete event的。
OpenHarmony定义的xmit_cb没有p_cback参数,而处理收到的cmd complete event是通过op BT_OP_EVENT_CALLBACK通知厂商lib的。
适配方法:
适配层实现一个与厂商xmit_cb原型一致的函数adapter_xmit_cb,其中调用OpenHarmony定义的xmit_cb。
并且adapter_xmit_cb中保存hci command值以及p_cback,在OpenHarmony HDI调用op BT_OP_EVENT_CALLBACK时根据hci command调用对应的p_cback函数。
2、p_cback钩子函数参数p_mem的适配
p_cback的参数p_mem是command complete event报文的buffer,根据厂商lib定义的说明会在p_cback函数中释放这个buffer。
而OpenHarmony框架上收到command complete event时,会调用vendorInterface_.op函数,参数op code为BT_OP_EVENT_CALLBACK,参数buff为hci event报文数据,而buff是由OpenHarmony HDI负责释放。这里需要处理这种重复释放的情况。
适配方法:在op BT_OP_EVENT_CALLBACK针对command complete event的处理中,先申请与buff相同大小的内存并拷贝buff的内容,再根据command调用保存的厂商p_cback钩子函数,并将新申请的内存传递给p_cback函数由其处理并释放。而传递给op函数的buff则由OpenHarmony HDI来释放。
-
其他8541E独有的callback函数scocfg_cb、lpm_cb、audio_state_cb、epilog_cb、a2dp_offload_cb都是用于通知配置结果,只单独实现简单的函数不做任何处理即可。
op code
OpenHarmony的bt_opcode_t与厂商的bt_vendor_opcode_t的差异不大,只是在调用的形式上有些差异,可以通过适配层的转换函数进行适配。
-
OpenHarmony的BT_OP_PORER_ON和BT_OP_POWER_OFF与厂商的BT_VND_OP_POWER_CTRL
-
OpenHarmony的BT_OP_GET_LPM_TIMER与厂商的BT_VND_OP_GET_LPM_IDLE_TIMEOUT
-
OpenHarmony的BT_OP_LPM_ENABLE和BT_OP_LPM_DISABLE与厂商的BT_VND_OP_LPM_SET_MODE
-
OpenHarmony的BT_OP_WAKEUP_LOCK和BT_OP_WAKEUP_UNLOCK与厂商的BT_VND_OP_LPM_WAKE_SET_STATE
-
OpenHarmony的BT_OP_HCI_CHANNEL_OPEN与厂商的BT_VND_OP_USERIAL_OPEN
-
OpenHarmony的BT_OP_HCI_CHANNEL_CLOSE与厂商的BT_VND_OP_USERIAL_CLOSE
-
OpenHarmony的BT_OP_INIT与厂商的BT_VND_OP_FW_CFG
-
OpenHarmony的BT_OP_EVENT_CALLBACK与厂商的BT_VND_OP_EVENT_CALLBACK
OpenHarmony BT_OP_EVENT_CALLBACK是用于处理收到的cmd complete event(0x0E)和vendor specific event(0xFF)事件。
而8541E厂商的BT_VND_OP_EVENT_CALLBACK是用于调试,属于厂商自定义的。因此在适配时分别对二个event进行处理:
1、cmd complete event调用适配层保存的厂商钩子函数p_cback。
在厂商调用xmit_cb时,适配层需要根据不同的command保存对应的p_cback钩子函数。
2、vendor specific event调用厂商的op BT_VND_OP_EVENT_CALLBACK;
更多推荐
所有评论(0)