1. 前言
有时候因为CYW20819资源不足或者其他原因不能满足产品设计需求,仅想将CYW20819作为一个蓝牙模组来使用,此时主控需要通过HCI接口来控制CYW20819。
HCI接口物理层上可以是UART,SPI或者USB。在应用过程中,我们更加需要去关注HCI命令格式,比如发送什么数据代表什么意思。可以参考 HCI Control Protocol,命令解析代码芯片厂家一般都是做好了的,可以直接拿来用。
本文将介绍通过电脑上位机ClinentControl来控制 CYW20819。
2. ClientControl
ClientControl是赛普拉斯的HCI上位机,通过它可以向DEMO板通过串口发送HCI命令或者升级。
2.1 连接demo板
ClientControl是通过UART控制DEMO板的,选择WICED HCI UART,其他默认。
点击打开Open port。
2.2 发送HCI命令
ClientControl本身将集成了各种各样HCI命令,可以通过界面来操作,在这之前,也要保证DEMO板里面的固件是支持解析HCI命令的。
比如发现附近的BLE 设备,点击Start:
结果:
2.3 升级
选择编译结果里的Hcd文件:
注意CYW20819不支持升级:
3. HCI命令解析
如果将 CYW20819 当做蓝牙模组来使用,那么 CYW20819 需要支持HCI命令解析的功能。官方例子 Audio-20819EVB02 支持该功能。
3.1 开始广播
将该例子编译下载进去,是可以正常跑的,比如通过ClientControl控制DEMO开始广播,通过nRF Connect是可以扫描到的。
3.2 Audio-20819EVB02 打印问题
Audio-20819EVB02例子跑起来的时候串口打印是没有输出的,查了半天没找到问题,最后发现将波特率改小些(改为115200)可以正常运行了。
// wiced_hal_puart_configuration(3000000, PARITY_NONE, STOP_BIT_2);
wiced_hal_puart_configuration(115200, PARITY_NONE, STOP_BIT_2);
4. 代码框架
4.1 HCI串口初始化
const wiced_transport_cfg_t transport_cfg =
{
.type = WICED_TRANSPORT_UART,
.cfg =
{
.uart_cfg =
{
.mode = WICED_TRANSPORT_UART_HCI_MODE,
.baud_rate = HCI_UART_DEFAULT_BAUD},
},
.rx_buff_pool_cfg =
{
.buffer_size = TRANS_UART_BUFFER_SIZE,
.buffer_count = WICED_TRANSPORT_BUFFER_COUNT},
.p_status_handler = hci_control_transport_status,
.p_data_handler = hci_control_proc_rx_cmd,
.p_tx_complete_cback = hci_control_transport_tx_cplt_cback};
可以看到除了初始化UART外设之后,这个结构体里面还包括三个回调函数:
- hci_control_transport_status (外设状态回调)
- hci_control_proc_rx_cmd (命令接收)
- hci_control_transport_tx_cplt_cback (发送完成回调)
我们主要关注hci_control_proc_rx_cmd,这个接口是对上位机发过来的命令进行解析。
4.2 hci_control_proc_rx_cmd
该函数是 HCI Control Protocol 的部分实践。
/*
* Handle received command over UART. Please refer to the WICED Smart Ready
* Software User Manual (WICED-Smart-Ready-SWUM100-R) for details on the
* HCI UART control protocol.
*/
static uint32_t hci_control_proc_rx_cmd(uint8_t *p_buffer, uint32_t length)
{
uint16_t opcode;
uint16_t payload_len;
uint8_t *p_data = p_buffer;
uint8_t buffer_processed = WICED_TRUE;
if (!p_buffer)
{
return HCI_CONTROL_STATUS_INVALID_ARGS;
}
// Expected minimum 4 byte as the wiced header
if ((length < 4) || (p_data == NULL))
{
WICED_BT_TRACE("invalid params\n");
wiced_transport_free_buffer(p_buffer);
return HCI_CONTROL_STATUS_INVALID_ARGS;
}
STREAM_TO_UINT16(opcode, p_data); // Get OpCode
STREAM_TO_UINT16(payload_len, p_data); // Gen Payload Length
WICED_BT_TRACE("cmd_opcode 0x%02x\n", opcode);
switch ((opcode >> 8) & 0xff)
{
case HCI_CONTROL_GROUP_DEVICE:
hci_control_device_handle_command(opcode, p_data, payload_len);
break;
#if (WICED_APP_LE_INCLUDED == WICED_TRUE)
case HCI_CONTROL_GROUP_LE:
case HCI_CONTROL_GROUP_GATT:
hci_control_le_handle_command(opcode, p_data, payload_len);
break;
#endif
#if (WICED_APP_AUDIO_SRC_INCLUDED == WICED_TRUE)
case HCI_CONTROL_GROUP_AUDIO:
hci_control_audio_handle_command(opcode, p_data, payload_len);
break;
#endif
#if (WICED_APP_AUDIO_RC_TG_INCLUDED == WICED_TRUE)
case HCI_CONTROL_GROUP_AVRC_TARGET:
hci_control_avrc_handle_command(opcode, p_data, payload_len);
break;
#endif
case HCI_CONTROL_GROUP_AVRC_CONTROLLER:
#if (WICED_APP_AUDIO_RC_TG_INCLUDED == WICED_TRUE)
if ((avrcp_profile_role == AVRCP_TARGET_ROLE) &&
(hci_control_rc_target_is_connected()))
{
hci_control_avrc_handle_command(opcode, p_data, payload_len);
}
else
{
#endif
#if (WICED_APP_LE_SLAVE_CLIENT_INCLUDED == WICED_TRUE)
if (wiced_bt_ams_client_connection_check())
{
hci_control_ams_handle_command(opcode, p_data, payload_len);
}
else
#endif
#if (WICED_APP_AUDIO_RC_CT_INCLUDED == WICED_TRUE)
{
hci_control_avrc_handle_ctrlr_command(opcode, p_data, payload_len);
}
}
#endif
break;
#if (WICED_APP_TEST_INCLUDED == WICED_TRUE)
case HCI_CONTROL_GROUP_TEST:
hci_control_test_handle_command(opcode, p_data, payload_len);
break;
#endif
#if (WICED_APP_ANCS_INCLUDED == WICED_TRUE)
case HCI_CONTROL_GROUP_ANCS:
hci_control_ancs_handle_command(opcode, p_data, payload_len);
break;
#endif
#if (WICED_APP_HFP_AG_INCLUDED == WICED_TRUE)
case HCI_CONTROL_GROUP_AG:
hci_control_ag_handle_command(opcode, p_data, payload_len);
break;
#endif
case HCI_CONTROL_GROUP_MISC:
hci_control_misc_handle_command(opcode, p_data, payload_len);
break;
default:
WICED_BT_TRACE("unknown class code (opcode:%x)\n", opcode);
break;
}
if (buffer_processed)
{
// Freeing the buffer in which data is received
wiced_transport_free_buffer(p_buffer);
}
return HCI_CONTROL_STATUS_SUCCESS;
}
5. 写在最后
本文介绍了HCI接口的实现以及使用ClientControl控制通过HCI接口控制DEMO,本质上是 HCI Control Protocol 的实践。