赞
踩
https://source.android.com/docs/core/connect/bluetooth?hl=zh-cn
https://android.googlesource.com/platform/hardware/interfaces/+/master/bluetooth/
蓝牙整体硬件架构上分为主机(计算机或MCU)和主机控制器(实际蓝牙芯片组)两部分;主机和控制器之间的通信遵循主机控制器接口(HCI),如下所示:
HCI定义了如何交换命令,事件,异步和同步数据包。异步数据包(ACL)用于数据传输,而同步数据包(SCO)用于带有耳机和免提配置文件的语音。
vendorlib部署在主机侧,可以认为是主机侧对蓝牙芯片驱动层,屏蔽不同蓝牙芯片的技术细节。从代码层面解读,其主要功能有两个:
1、为协议栈提供蓝牙芯片之间的通道(串口的文件描述符)
2、提供特定芯片的具体控制方法
bt_vendor_lib.h 路径:
该文件定义了协议栈和vendor_lib交互接口,分为两组:
typedef struct { /** * Set to sizeof(bt_vendor_interface_t) */ size_t size; /** * Caller will open the interface and pass in the callback routines * to the implementation 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;
协议栈启动时的基本流程如下:
1.1、协议栈动态打开libbt-vendor.so,并调用init函数,初始化vendorlib
1.2、协议栈调用op函数,分别调用BT_VND_OP_POWER_CTRL、BT_VND_OP_USERIAL_OPEN、BT_VND_OP_FW_CFG三个opcode;
typedef struct { /** set to sizeof(bt_vendor_callbacks_t) */ size_t size; /* * Callback and callout functions have implemented in HCI libray * (libbt-hci.so). */ /* notifies caller result of firmware configuration request */ cfg_result_cb fwcfg_cb; /* buffer allocation request */ malloc_cb alloc; /* buffer deallocation request */ mdealloc_cb dealloc; /* hci command packet transmit request */ cmd_xmit_cb xmit_cb; } bt_vendor_callbacks_t;
fwcfg_cb在BT_VND_OP_FW_CFG完成后调用
alloc/dealloc用于发送HCI消息时申请/释放消息控件
xmit_cb发送HCI Commands
vendor_lib实现的几个重要函数
static int init(const bt_vendor_callbacks_t *p_cb, unsigned char *local_bdaddr)
{
/* * ... */
userial_vendor_init();
upio_init();
vnd_load_conf(VENDOR_LIB_CONF_FILE);
/* store reference to user callbacks */
bt_vendor_cbacks = (bt_vendor_callbacks_t *)p_cb;
/* This is handed over from the stack */
memcpy(vnd_local_bd_addr, BD_ADDR_LEN, local_bdaddr, 6);
return 0;
}
vendorlib被调用的第一个函数,vendorlib保存好协议栈的callback和mac地址即可。
这个操作理论上需要拉高电源管脚电平;该函数中使用rfill设备来处理 通过write->/sys/class/rfkill/rfkill[num]/state
case BT_VND_OP_POWER_CTRL:
{
int *state = (int *) param;
upio_set_bluetooth_power(UPIO_BT_POWER_OFF);
if (*state == BT_VND_PWR_ON)
{
ALOGW("NOTE: BT_VND_PWR_ON now forces power-off first");
upio_set_bluetooth_power(UPIO_BT_POWER_ON);
} else {
/* Make sure wakelock is released */
hw_lpm_set_wake_state(false);
}
}
break;
case BT_VND_OP_USERIAL_OPEN:
{
int (*fd_array)[] = (int (*)[]) param;
int fd, idx;
fd = userial_vendor_open((tUSERIAL_CFG *) &userial_init_cfg);
if (fd != -1)
{
for (idx=0; idx < CH_MAX; idx++)
(*fd_array)[idx] = fd;
retval = 1;
}
/* retval contains numbers of open fd of HCI channels */
}
break;
userial_vendor_open函数打开串口设备(UART)并设置(UART)得到文件描述符(fd),通过op的参数param返回该fd
该操作码要求对蓝牙芯片进行初始化,具体要进行的处理和蓝牙芯片强相关。以本次调测的AP6275pr3芯片为例,初始化过程中主要是下发蓝牙固件。
初始化结束后,必须调用init_cb回调函数(参见bt_vendor_callbacks_t)通知协议栈初始化结果,否则会阻塞协议栈线程导致蓝牙相关功能无法正常使用。协议栈的具体处理如下:
协议栈调用BT_VND_OP_FW_CFG后会等待信号量,该信号量由init_cb函数置位
开发时一定要关注芯片固件,有些蓝牙芯片可能无需升级固件,有些则必须升级固件;固件下发时需要注意如下两点:
5.1、对于AP6275芯片,因为蓝牙芯片内并没有类似flash存储,要求芯片上下电后必须重新下发
5.2、按照芯片本身的要求处理,最好能找到厂商的参考代码;以Broadcom系列芯片为例,其固件下发过程比较复杂,通过一个状态机驱动;共如下9个状态
/ Hardware Configuration State */
enum {
HW_CFG_START = 1,
HW_CFG_SET_UART_CLOCK,
HW_CFG_SET_UART_BAUD_1,
HW_CFG_READ_LOCAL_NAME,
HW_CFG_DL_MINIDRIVER,
HW_CFG_DL_FW_PATCH,
HW_CFG_SET_UART_BAUD_2,
HW_CFG_SET_BD_ADDR,
HW_CFG_READ_BD_ADDR
};
在收到BT_VND_OP_FW_CFG后初始化状态机,然后发送HCI_REST命令,切换状态为HW_CFG_START;
void hw_config_start(void) { HC_BT_HDR *p_buf = NULL; uint8_t *p; hw_cfg_cb.state = 0; hw_cfg_cb.fw_fd = -1; hw_cfg_cb.f_set_baud_2 = FALSE; if (bt_vendor_cbacks) { p_buf = (HC_BT_HDR *)bt_vendor_cbacks->alloc(BT_HC_HDR_SIZE + HCI_CMD_PREAMBLE_SIZE); } if (p_buf) { p_buf->event = MSG_STACK_TO_HC_HCI_CMD; p_buf->offset = 0; p_buf->layer_specific = 0; p_buf->len = HCI_CMD_PREAMBLE_SIZE; p = (uint8_t *)(p_buf + 1); UINT16_TO_STREAM(p, HCI_RESET); *p = 0; hw_cfg_cb.state = HW_CFG_START; bt_vendor_cbacks->xmit_cb(HCI_RESET, p_buf); } else { if (bt_vendor_cbacks) { HILOGE("vendor lib fw conf aborted [no buffer]"); bt_vendor_cbacks->init_cb(BTC_OP_RESULT_FAIL); } } }
收到芯片返回的HCI_RESET完成事件后,继续切换到下一个状态机并发送下一个COMMAND,一直到状态机完成固件下发。
详细实现请参见hw_config_cback函数。
参考:
https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/porting/porting-dayu200-on_standard-demo.md#hci%E6%8E%A5%E5%8F%A3
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。