串口的数据接收和AT命令的解析程序入口:components\libraries\cli\ble_at_module.c
串口接收中断函数
components\libraries\cli\ble_at_module.c->AT_UART_IRQHandler,在这里解析判断串口数据是AT命令还是普通数据。符合cmdstr[0] == 'A' && cmdstr[1] == 'T' && (cmdstr[cmdlen-3] == '\r') && (cmdstr[cmdlen-2] == '\n') && (cmdstr[cmdlen-1] == '\0')这个条件的都认为是AT命令,如果是AT命令则通过事件AT_PROCESS_UART_RX_CMD_EVT发布出来,如果不是则通过事件AT_PROCESS_TRANSPARENT_SEND发布出来做蓝牙转发。
AT命令处理
1) 预处理
收到串口数据后,长度先减3,去掉\r\n\03个字节,然后原始数据结尾处理t_str[t_len] = '\0';,如下处理
if (t_len != 0)
{
t_len -= 3;
t_str[t_len] = '\0';
for (size_t i = 0; i < strlen(t_str); i++)
{
log_printf("%02X ", t_str[i]);
}
log_printf("\n");
int sta = CLI_process_line_manual(
t_str,
t_len);
}
2) 数据分拆
在函数components\libraries\cli\cliface.c->CLI_process_line_manual中解析命令的属性,提取携带的参数。
根据命令的格式,先提取属性值放在argv的argv[0]中,携带的第一个参数放在argv[1]中,如下处理:
if ((*cmd == '=') || (*cmd == ':'))
{
argv[argc++] = cmd;
argv[argc++] = (cmd + 1);
}
后续其他参数根据分隔符((' ' == (ch)) || ('\t' == (ch)) || ('\r' == (ch)) || ('\n' == (ch)) || (',' == (ch)))来解析分拆出来分别存放在argv中,处理如下:
else if ('\0' == (*(cmd - 1)))
{
argv[argc++] = cmd;
}
3) 命令匹配
在这里循环判断命令,匹配上对应的命令后,调用g_cli_cmd_list[index].cmd_hdlr(argc, argv)执行对应的方法,这些方法定义在example\ble_peripheral\VG7346T240N0S1-SWPRJ\source\at_ble_cmd.c->ble_at_cmd_list
for (index = 0; index < g_cli_cmd_len; index++)
{
if (0 == memcmp(buffer, g_cli_cmd_list[index].cmd, strlen(g_cli_cmd_list[index].cmd)) && atNameLen==strlen(g_cli_cmd_list[index].cmd))
{
// AT_LOG("-- match at fun --\r\n");
uint8_t atType = CMDT_NONE;
char typeName[][20] = {"NONE","TEST","READ","WRITE","EXECUTE"};
if(argv[0][0] == '=' && argv[1][0] != '?' && argv[1][0] != '\0')
{
atType = CMDT_WRITE;
}
else if(argv[0][0] == '=' && argv[1][0] == '?' && argv[1][1] == '\0')
{
atType = CMDT_READ;
}
else if(argv[0][0] == '\0' || argc == 0)
{
atType = CMDT_EXECUTE;
}
else if(argv[0][0] == '?')
{
atType = CMDT_TEST;
}
else
{
matchflag = 0;
}
log_printf("argc=%d\r\n", argc);
log_printf("argv[0][0]=%c(%02X) argv[1][0]=%c(%02X) argv[1][1]=%c(%02X)\r\n", argv[0][0], argv[0][0], argv[1][0], argv[1][0], argv[1][1], argv[1][1]);
log_printf("atType (%d)= %s\r\n", atType, typeName[atType]);
if (atType)
{
log_printf("match AT=%s\r\n", g_cli_cmd_list[index].cmd);
g_cli_cmd_list[index].cmd_hdlr(atType, argc, argv);
matchflag = 1;
break;
}
}
}
4) 命令处理
如下
static uint16_t at_set_advint(uint8_t at_type, uint32_t argc, unsigned char *argv[])
{
// argv[1]为第一个参数,以此类推,`,`为分隔符
switch (at_type)
{
case CMDT_TEST:
{
}break;
case CMDT_READ:
{
}break;
case CMDT_WRITE:
{
}break;
case CMDT_EXECUTE:
{
}break;
default:
break;
}
}