407 lines
12 KiB
C
407 lines
12 KiB
C
/****************************************************************************
|
||
|
||
Copyright(c) 2019 by Aerospace C.Power (Chongqing) Microelectronics. ALL RIGHTS RESERVED.
|
||
|
||
This Information is proprietary to Aerospace C.Power (Chongqing) Microelectronics and MAY NOT
|
||
be copied by any method or incorporated into another program without
|
||
the express written consent of Aerospace C.Power. This Information or any portion
|
||
thereof remains the property of Aerospace C.Power. The Information contained herein
|
||
is believed to be accurate and Aerospace C.Power assumes no responsibility or
|
||
liability for its use in any way and conveys no license or title under
|
||
any patent or copyright and makes no representation or warranty that this
|
||
Information is free from patent or copyright infringement.
|
||
|
||
****************************************************************************/
|
||
|
||
#include "app_main.h"
|
||
#include "app_uart.h"
|
||
#include "app_common.h"
|
||
#include "app_atcmd_proc.h"
|
||
#include "app_atcmd_handle.h"
|
||
#include "app_cus_task.h"
|
||
|
||
static uint16_t g_echo_flag = 0;
|
||
static app_source_e g_source = APP_SOURCE_UART;
|
||
static uint8_t g_source_mac[IOT_MAC_ADDR_LEN] = {0};
|
||
|
||
static int atcmd_parse_line(char *line, char *argv[])
|
||
{
|
||
int nargs = 0;
|
||
uint8_t index = 0;
|
||
|
||
while (nargs < ATCMD_MAXARGS) {
|
||
/* skip any white space */
|
||
while ((*line == ' ') || (*line == '\t') || (*line == ',')) {
|
||
++line;
|
||
}
|
||
|
||
/* end of line, no more args */
|
||
if (*line == '\0') {
|
||
argv[nargs] = 0;
|
||
return nargs;
|
||
}
|
||
|
||
/* argument include space should be bracketed by quotation mark */
|
||
if (*line == '<') {
|
||
/* skip quotation mark */
|
||
line++;
|
||
|
||
index = 1;
|
||
|
||
/* begin of argument string */
|
||
argv[nargs++] = line;
|
||
|
||
/* until end of argument */
|
||
while (*line && (*line != '>')) {
|
||
++line;
|
||
}
|
||
|
||
index = 0;
|
||
} else if ((index == 0) && (*line == '\"')) {
|
||
/* skip quotation mark */
|
||
line++;
|
||
|
||
/* begin of argument string */
|
||
argv[nargs++] = line;
|
||
|
||
/* until end of argument */
|
||
while (*line && (*line != '\"')) {
|
||
++line;
|
||
}
|
||
} else {
|
||
/* begin of argument string */
|
||
argv[nargs++] = line;
|
||
|
||
/* find end of string */
|
||
while (*line && (*line != ',') && (*line != '=')) {
|
||
++line;
|
||
}
|
||
}
|
||
|
||
/* end of line, no more args */
|
||
if (*line == '\0') {
|
||
argv[nargs] = 0;
|
||
return nargs;
|
||
}
|
||
|
||
/* terminate current arg */
|
||
*line++ = '\0';
|
||
}
|
||
|
||
return nargs;
|
||
}
|
||
|
||
static uint8_t atcmd_find_query(char *cmd)
|
||
{
|
||
uint32_t len;
|
||
|
||
if (iot_strstr((char *)cmd, "?") != NULL) {
|
||
len = iot_strlen(cmd);
|
||
cmd[len-1] = '\0';
|
||
return ATCMD_QUERY_FLAG;
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
static AT_RET atcmd_run_cmd(cmd_tbl_t *cmd_tbl, uint32_t argc, char *argv[], uint8_t flag)
|
||
{
|
||
if ((argc == 1) && (flag == ATCMD_QUERY_FLAG)) {
|
||
/* AT+<cmd>? */
|
||
if (cmd_tbl->query_cmd == NULL) {
|
||
return AT_RET_FAIL;
|
||
}
|
||
return (cmd_tbl->query_cmd)(argc, argv);
|
||
} else if((argc == 1) && (flag != ATCMD_QUERY_FLAG)) {
|
||
/* AT+<cmd> */
|
||
if (cmd_tbl->exe_cmd == NULL) {
|
||
return AT_RET_FAIL;
|
||
}
|
||
return (cmd_tbl->exe_cmd)(argc, argv);
|
||
} else if ((argc == 2) && (iot_strstr((char *)argv[1], "?") != NULL)) {
|
||
/* AT+<cmd>=? */
|
||
if (cmd_tbl->test_cmd == NULL) {
|
||
return AT_RET_FAIL;
|
||
}
|
||
return (cmd_tbl->test_cmd)(argc, argv);
|
||
} else {
|
||
/* AT+<cmd>=<parameter>,... */
|
||
if (cmd_tbl->setup_cmd == NULL) {
|
||
return AT_RET_FAIL;
|
||
}
|
||
return (cmd_tbl->setup_cmd)(argc, argv);
|
||
}
|
||
|
||
return AT_RET_FAIL;
|
||
}
|
||
|
||
static uint16_t atcmd_parse_command(char *cmd)
|
||
{
|
||
cmd_tbl_t *cmd_tbl;
|
||
char *argv[ATCMD_MAXARGS];
|
||
uint32_t argc;
|
||
uint8_t flag = 0;
|
||
|
||
if (g_echo_flag) {
|
||
AT_RESP("%s\r\n", cmd);
|
||
}
|
||
|
||
APP_PRINTF("%s", cmd);
|
||
/* extract arguments */
|
||
if (0 == (argc = atcmd_parse_line(cmd, argv))) {
|
||
AT_RESP_ERROR();
|
||
APP_PRINTF("[ERR] %s Parse Cmd Failed : %s !!", __FUNCTION__, cmd);
|
||
return ERR_FAIL;
|
||
}
|
||
|
||
/* find query cmd */
|
||
flag = atcmd_find_query(argv[0]);
|
||
|
||
/* Look up command in command table */
|
||
if ((cmd_tbl = atcmd_find_cmd(argv[0])) == NULL) {
|
||
AT_RESP_ERROR();
|
||
APP_PRINTF("[ERR] %s Find Cmd Failed : %s !!", __FUNCTION__, cmd);
|
||
return ERR_FAIL;
|
||
}
|
||
|
||
/* check max args */
|
||
if (argc > ATCMD_MAXARGS) {
|
||
AT_RESP_ERROR();
|
||
return ERR_FAIL;
|
||
}
|
||
|
||
/* call function to run the command */
|
||
AT_RET ret = atcmd_run_cmd(cmd_tbl, argc, argv, flag);
|
||
switch (ret) {
|
||
case AT_RET_OK:
|
||
AT_RESP_OK();
|
||
break;
|
||
|
||
case AT_RET_ERR:
|
||
AT_RESP_ERROR();
|
||
break;
|
||
|
||
case AT_RET_FAIL:
|
||
AT_RESP_FAIL();
|
||
break;
|
||
|
||
default:
|
||
break;
|
||
}
|
||
|
||
return ERR_OK;
|
||
}
|
||
|
||
app_source_e app_atcmd_get_source(void)
|
||
{
|
||
return g_source;
|
||
}
|
||
|
||
uint8_t *app_atcmd_get_source_mac(void)
|
||
{
|
||
return g_source_mac;
|
||
}
|
||
|
||
uint16_t app_atcmd_get_echo(void)
|
||
{
|
||
return g_echo_flag;
|
||
}
|
||
|
||
void app_atcmd_set_echo(uint16_t flag)
|
||
{
|
||
g_echo_flag = flag;
|
||
}
|
||
|
||
uint16_t app_atcmd_frame_tx(uint8_t *data,uint16_t data_length, app_source_e source)
|
||
{
|
||
uint8_t *dst_addr;
|
||
|
||
switch (source) {
|
||
case APP_SOURCE_UART:
|
||
return app_tx_to_cus_uart_msg(data, data_length);
|
||
|
||
case APP_SOURCE_PLC:
|
||
dst_addr = app_atcmd_get_source_mac();
|
||
return app_plc_tx(data, data_length, dst_addr, ID_PLC_REMOTE_AT, NULL);
|
||
|
||
default:
|
||
break;
|
||
}
|
||
|
||
return ERR_NOSUPP;
|
||
}
|
||
|
||
/* Printing szie cannot exceed MAX_RSP_DATA_LEN zise ,or program will crash*/
|
||
void app_atcmd_printf(const char *fmt, ...)
|
||
{
|
||
va_list args;
|
||
uint16_t len = 0;
|
||
app_entity_t *app_entry = app_get_main_entry();
|
||
|
||
os_mem_set(app_entry->out_buf, 0, MAX_RSP_DATA_LEN);
|
||
va_start(args, fmt);
|
||
len = iot_vsnprintf((char *)app_entry->out_buf, MAX_RSP_DATA_LEN, fmt, args);
|
||
va_end(args);
|
||
|
||
app_atcmd_frame_tx((uint8_t *)app_entry->out_buf, len, g_source);
|
||
|
||
return;
|
||
}
|
||
|
||
static void app_atcmd_format_process(uint8_t * buffer, uint32_t buffer_len, app_source_e source)
|
||
{
|
||
char *tmp, *cmd_end, *cmd_start;
|
||
uint16_t pos = 0;
|
||
uint16_t cmd_len = 0;
|
||
|
||
/* 将buffer 按换行拆分成不同的命令进行处理,需要加入pos 检查,
|
||
* 使用 iot_strstr查询\r\n,并去掉"AT"字符串之前的无效字符。
|
||
* 比如: 00 04 41 66 41 54 00 00 41 54 2B 48 45 4C 50 3F 0D 0A ,
|
||
* 要去掉前面的00 04 41 66 41 54 00 00 */
|
||
while (pos < buffer_len) {
|
||
if (buffer_len - pos < 2) {
|
||
return;
|
||
}
|
||
cmd_start = (char*)(buffer + pos);
|
||
/* 查找“AT”的位置 */
|
||
if(*cmd_start != 'A' || *(cmd_start + 1) != 'T') {
|
||
APP_PRINTF("Invalid char:0x%02x",*cmd_start);
|
||
pos++;
|
||
continue;
|
||
}
|
||
/* 查找“\r\n”的位置 */
|
||
cmd_end = iot_strstr(cmd_start, "\r\n");
|
||
if (cmd_end == NULL) {
|
||
/* 去掉AT没有“\r\n”的无效字符串,中间有遇到结束符的情况,
|
||
* 需要加上“AT”到结束符的长度 */
|
||
APP_PRINTF("Invalid AT string:%s",cmd_start);
|
||
pos += iot_strlen(cmd_start);
|
||
continue;
|
||
} else {
|
||
cmd_len = cmd_end - cmd_start;
|
||
/* 需要加上\r\n 的长度 */
|
||
pos += cmd_len + iot_strlen("\r\n");
|
||
}
|
||
|
||
/* 在at命令最后加一个0作为结束,防止后续直接使用字符串处理时出现越界问题 */
|
||
iot_pkt_t *pkt = iot_pkt_alloc(cmd_len + 1, IOT_APP_DEMO_MID);
|
||
if (NULL == pkt) {
|
||
APP_PRINTF("[ERR] %s Packet Alloc Failed !!", __FUNCTION__);
|
||
return;
|
||
}
|
||
tmp = (char *)iot_pkt_put(pkt, cmd_len + 1);
|
||
os_mem_cpy(tmp, cmd_start, cmd_len);
|
||
|
||
/* save source for handle */
|
||
g_source = source;
|
||
if (ERR_OK != atcmd_parse_command(tmp)) {
|
||
APP_PRINTF("[ERR] %s AT Command Failed !!", __FUNCTION__);
|
||
}
|
||
iot_pkt_free(pkt);
|
||
}
|
||
/* reset source */
|
||
g_source = APP_SOURCE_UART;
|
||
}
|
||
|
||
void app_atcmd_data_parse(uint8_t * buffer, uint32_t buffer_len, app_source_e source)
|
||
{
|
||
uint8_t *tmp;
|
||
int16_t index = 0;
|
||
uart_handle_buffer *uart_buffer;
|
||
|
||
if ((NULL == buffer) || (0 == buffer_len)) {
|
||
return;
|
||
}
|
||
|
||
uart_buffer = app_get_uart_buf_info();
|
||
|
||
APP_PRINTF("%s handle=%d", __FUNCTION__, uart_buffer->handle);
|
||
|
||
uart_buffer->handle = true;
|
||
/* 断帧数据清除 */
|
||
app_uart_buf_clear(source);
|
||
|
||
iot_pkt_t *pkt = iot_pkt_alloc(uart_buffer->buff_len + buffer_len, IOT_APP_DEMO_MID);
|
||
if (NULL == pkt) {
|
||
APP_PRINTF("[ERR] %s Packet Alloc Failed !!", __FUNCTION__);
|
||
return;
|
||
}
|
||
tmp = iot_pkt_put(pkt, uart_buffer->buff_len + buffer_len);
|
||
/* 合并断帧和新接收到数据 */
|
||
if (uart_buffer->buff_len > 0) {
|
||
/* 先拷贝之前的断帧 */
|
||
os_mem_cpy(tmp, uart_buffer->buff_tmp, uart_buffer->buff_len);
|
||
os_mem_set(uart_buffer->buff_tmp, 0, uart_buffer->buff_len);
|
||
}
|
||
os_mem_cpy(tmp + uart_buffer->buff_len, buffer, buffer_len);
|
||
|
||
/* 查找最后一个 \r\n 位置,用于计算断帧长度 */
|
||
for (index = uart_buffer->buff_len + buffer_len - 2; index >= 0 ; index--) {
|
||
if (tmp[index] == '\r' && tmp[index+1] == '\n') {
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (index > 0) {
|
||
/* 加上\r\n的长度 */
|
||
index += 2;
|
||
} else {
|
||
index = 0;
|
||
}
|
||
/* 计算断帧长度,并备份 */
|
||
uart_buffer->buff_len = uart_buffer->buff_len + buffer_len - index;
|
||
if (uart_buffer->buff_len > UART_BUF_MAX_LEN) {
|
||
/* 计算新的断帧长度超过最大可存储数据长度时,更新断帧数据,保留新收到的数据 */
|
||
os_mem_cpy(uart_buffer->buff_tmp,
|
||
tmp + uart_buffer->buff_len - UART_BUF_MAX_LEN, UART_BUF_MAX_LEN);
|
||
uart_buffer->buff_len = UART_BUF_MAX_LEN;
|
||
} else if (uart_buffer->buff_len > 0) {
|
||
os_mem_cpy(uart_buffer->buff_tmp, tmp + index, uart_buffer->buff_len);
|
||
}
|
||
|
||
if (index > 0) {
|
||
/* 处理带 \r\n的帧数据 */
|
||
app_atcmd_format_process(iot_pkt_data(pkt), index, source);
|
||
}
|
||
iot_pkt_free(pkt);
|
||
|
||
/*判断断帧是否为 +++进入AT模式命令 */
|
||
if ((uart_buffer->buff_len == CHECK_ATCMD_BUF_SIZE) &&
|
||
iot_strstr((char *)uart_buffer->buff_tmp, "+++")) {
|
||
AT_RESP("Already in AT mode.\r\n");
|
||
os_mem_set(uart_buffer->buff_tmp, 0, uart_buffer->buff_len);
|
||
uart_buffer->buff_len = 0;
|
||
}
|
||
|
||
uart_buffer->handle = false;
|
||
}
|
||
|
||
void app_atcmd_data_handle(uint16_t data_id, app_source_e data_src,
|
||
uint8_t *data, uint32_t data_len, void *info)
|
||
{
|
||
recv_info_t *rx_info = (recv_info_t*)info;
|
||
|
||
if (data_id == ID_PLC_REMOTE_AT) {
|
||
if (iot_plc_is_client_mode()) {
|
||
iot_mac_addr_cpy(g_source_mac, rx_info->mac);
|
||
app_atcmd_data_parse(data, data_len, data_src);
|
||
} else {
|
||
APP_PRINTF("send at remote to cco");
|
||
app_tx_to_cus_uart_msg(data, data_len);
|
||
}
|
||
} else if (data_id == ID_PLC_AT_DATA) {
|
||
app_atcmd_uart_tx(data, data_len, rx_info->mac, 0, rx_info->recv_flag);
|
||
} else if (data_id == ID_PLC_AT_STRING) {
|
||
app_atcmd_uart_tx(data, data_len, rx_info->mac, 1, rx_info->recv_flag);
|
||
} else if (data_id == ID_PLC_AT_DELAYTIME) {
|
||
app_atcmd_plc_linktest_handle(data, data_len, rx_info->mac);
|
||
} else if (data_id == ID_PLC_DATA_TEST) {
|
||
app_atcmd_signal_test_handle(data, data_len, rx_info);
|
||
} else {
|
||
APP_PRINTF("mode not support data");
|
||
}
|
||
|
||
return;
|
||
}
|
||
|