Files
kunlun/app/iot_cus_at_app/at/app_atcmd_proc.c
2024-09-28 14:24:04 +08:00

407 lines
12 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/****************************************************************************
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;
}