Chester
实际应用开发过程中经常需要整合DTM固件到应用工程中,本文以ble_app_uart工程中增加DTM测试功能为例进行介绍。整合后的功能大致如下:通过串口发送指定指令进入DTM模式,该模式下只运行DTM固件,方便自动化测试、通过串口发送指定指令开关广播、通过串口发送指定指令读取蓝牙MAC地址、通过串口发送指定指令退出DTM模式。关于DTM测试及工具说明,可以参考以下2个链接介绍:
准备工作:SK板、Micro-Usb线,SDK中任意工程,相关GR551x如何接线请参考 GR551X如何使用工具下载固件 。
整合过程主要分为以下几个步骤:
A、定义指令解析函数,主要完成指定指令的数据解析过程;
B、进入DTM模式后重新初始化串口,重定义HCI串口至当前串口;
C、实现退出的自定义指令,并完成系统重启;
接下来一一解析每一个步骤:
1、指令解析:在user_periph_setup.c文件中增加以下代码,该代码为指定命令解析函数,主要完成指定指令的解析工作以及进入DTM模式的一些初始化操作;
static uint8_t s_hci_buffer[256] = {0};
uint8_t dtm_mode = 0;
void Cmd_Parse(uint8_t data[244])
{
switch (data[0])
{
case 0x01://dtm mode
{
if (data[1] == 0x01 && data[2] == 0x01)
{
enter_dtm_mode();
}
break;
}
case 0x02:
{
if(data[1] == 0x01)
{
if (data[2] == 0x01)//start adv
{
APP_LOG_INFO("start_adv!\r\n");
start_adv();
}
else if (data[2] == 0x02)//stop adv
{
APP_LOG_INFO("stop_adv!\r\n");
stop_adv();
}
}
break;
}
case 0x03://find ble addr
{
if (data[1] == 0x01 && data[2] == 0x01)
{
sdk_err_t error_code;
gap_bdaddr_t addr;
error_code = ble_gap_addr_get(&addr);
APP_ERROR_CHECK(error_code);
APP_LOG_INFO("The Addr is : X:X:X:X:X:X.", addr.gap_addr.addr[5],addr.gap_addr.addr[4],addr.gap_addr.addr[3],addr.gap_addr.addr[2],addr.gap_addr.addr[1],addr.gap_addr.addr[0]);
}
break;
}
default:
break;
}
}
2、重新初始化串口并重定义串口callbak函数:同样的在user_periph_setup.c文件中增加以下代码:
void enter_dtm_mode(void)
{
ble_gap_disconnect(0);
ble_gap_adv_stop(0);
ble_hci_uart_init(s_hci_buffer, sizeof(s_hci_buffer));
dtm_mode = 1;
APP_LOG_INFO("enter dtm mode!\r\n");
}
并且重新定义串口的callback函数,主要为了保证进入DTM模式后串口只用于DTM中的串口数据交互,在uart_evt_handler函数中重新定义callback函数:
static void uart_evt_handler(app_uart_evt_t *p_evt)
{
if (APP_UART_EVT_RX_DATA == p_evt->type)
{
if (dtm_mode == 0)
{
uart_to_ble_push(s_uart_rx_buffer, p_evt->data.size);
Cmd_Parse(s_uart_rx_buffer);
app_uart_receive_async(APP_UART_ID, s_uart_rx_buffer, UART_RX_BUFFER_SIZE);
}
else if (dtm_mode == 1)
{
hci_uart0_read(s_uart_rx_buffer,p_evt->data.size,NULL,NULL);
}
}
else if (APP_UART_EVT_TX_CPLT == p_evt->type)
{
if (dtm_mode == 0)
update_ble_flow_ctrl_state();
else if (dtm_mode == 1)
{
hci_uart0_write(s_uart_tx_buffer,p_evt->data.size,NULL,NULL);
}
}
}
至此,可以发送010101命令进入DTM模式了;接下来需要完成开启广播以及关闭广播的相关接口,可在user_app.c文件中增加以下语句:
void start_adv(void)
{
sdk_err_t error_code;
error_code = ble_gap_adv_start(0, &s_gap_adv_time_param);
APP_ERROR_CHECK(error_code);
}
void stop_adv(void)
{
sdk_err_t error_code;
error_code = ble_gap_adv_stop(0);
APP_ERROR_CHECK(error_code);
}
并在相关头文件进行申明,方便user_periph_setup.c文件进行引用;至此,可以发送020101来开启广播,发送020102关闭广播,发送040101读取蓝牙MAC地址;
3、下一步需要完成最后一步,发送指定命令完成DTM模式的退出,因需要配合标准DTM指令才能被解析,所以需要在hci_uart.c文件中进行如下操作:
在该文件中定义一个数据:
static app_uart_tx_buf_t uart_rx_ptr;
在hci_uart_callback函数的APP_UART_EVT_RX_DATA == p_evt->type分支中加入以下代码(以自定义指令0134200400010203)为例:
else if (APP_UART_EVT_RX_DATA == p_evt->type)
{
if(p_evt->data.size == 4&&uart_rx_ptr.tx_buf[0]==0x00&&uart_rx_ptr.tx_buf[1]==0x01&&uart_rx_ptr.tx_buf[2]==0x02&&uart_rx_ptr.tx_buf[3]==0x03)
{
hal_nvic_system_reset();
}
// Retrieve callback pointer
callback = uart_env.rx.callback;
data = uart_env.rx.p_dummy;
......
}
其中00010203可以自定义,其余数据因需要适配DTM标准指令不可更改;同时需要在发送接收数据中进行数据的赋值方便自定义指令的解析,在hci_uart0_write函数和hci_uart0_read函数中增加以下代码:
void hci_uart0_read(uint8_t *p_buffer, uint32_t size, void (*callback)(void*, uint8_t), void *p_dummy)
{
uart_rx_ptr.tx_buf = p_buffer;
hci_uart_read(APP_UART_ID_0, p_buffer, size, callback, p_dummy);
}
void hci_uart0_write(uint8_t *p_buffer, uint32_t size, void (*callback)(void*, uint8_t), void *p_dummy)
{
uart_rx_ptr.tx_buf = p_buffer;
hci_uart_write(APP_UART_ID_0, p_buffer, size, callback, p_dummy);
}
最后,为防止在执行DTM过程中被应用程序干扰,需要在while(1)循环中判断为DTM模式时不进行任何上层应用:
// Loop
while (1){
if (dtm_mode == 0) {
//以下为应用层需要运行的代码
app_log_flush();
transport_schedule();
pwr_mgmt_schedule();
}
}
至此,编译下载,即可完成本文所描述的DTM整合到应用固件中的功能了。
Chester
有任何问题可再本帖下直接回复~
打开微信,使用“扫一扫”即可关注