CN / EN
CN / EN

应用固件如何整合DTM功能 GR551x

已解决

Chester

2022-04-19 11:12

实际应用开发过程中经常需要整合DTM固件到应用工程中,本文以ble_app_uart工程中增加DTM测试功能为例进行介绍。整合后的功能大致如下:通过串口发送指定指令进入DTM模式,该模式下只运行DTM固件,方便自动化测试、通过串口发送指定指令开关广播、通过串口发送指定指令读取蓝牙MAC地址、通过串口发送指定指令退出DTM模式。关于DTM测试及工具说明,可以参考以下2个链接介绍:

GR5xx DTM测试指南

GR551x DTM测试工具分享—V1.5.01


准备工作: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整合到应用固件中的功能了。

2收藏

3赞成

最佳答案

Chester

2022-04-19 17:42

有任何问题可再本帖下直接回复~

1条评论

1赞成

1收藏

您的评论

登录后可回答问题,请 注册

我们时刻倾听您的声音
联系销售

扫描关注公众号

打开微信,使用“扫一扫”即可关注