292 lines
7.2 KiB
C
292 lines
7.2 KiB
C
/*
|
|
* Copyright 2022 MindMotion Microelectronics Co., Ltd.
|
|
* All rights reserved.
|
|
*
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*/
|
|
|
|
#include "at_server.h"
|
|
|
|
/*
|
|
* Macros.
|
|
*/
|
|
|
|
|
|
/*
|
|
* Declerations.
|
|
*/
|
|
|
|
/* at command parse. */
|
|
void at_parse(at_server_t * server);
|
|
/* get the at command name from at receive command buffer.*/
|
|
static bool at_cmd_get_name(char * cmd_buffer, char * cmd_name);
|
|
/* find the at command name from at command list. */
|
|
static at_cmd_t * at_find_cmd(at_server_t * server, char * cmd);
|
|
/* process the at command. */
|
|
static bool at_cmd_process(at_server_t * server, at_cmd_t * cmd, char * cmd_args);
|
|
/* check the ar command parameter format. */
|
|
static bool at_check_args(char * args, char * args_format);
|
|
|
|
/*
|
|
* Variables.
|
|
*/
|
|
|
|
/*
|
|
* Functions.
|
|
*/
|
|
|
|
void at_server_init(at_server_t * server,at_adapter_t * adapter)
|
|
{
|
|
adapter->init();
|
|
server->adapter = adapter;
|
|
server->remaining = adapter->buf_size;
|
|
memcpy(server->end_mark, AT_CMD_END_MARK_DEFAULT, sizeof(AT_CMD_END_MARK_DEFAULT));
|
|
}
|
|
|
|
void at_server_set_cmd_list(at_server_t * server, at_cmd_t * cmd_list[], uint32_t cmd_num)
|
|
{
|
|
server->cmd_list = cmd_list;
|
|
server->cmd_num = cmd_num;
|
|
}
|
|
|
|
void at_server_write(at_server_t * server, char * buf, uint32_t len)
|
|
{
|
|
server->adapter->write(buf, len);
|
|
}
|
|
|
|
uint32_t at_server_read(at_server_t * server, char * buf, uint32_t len)
|
|
{
|
|
return server->adapter->read(buf, len);
|
|
}
|
|
|
|
void at_server_task(at_server_t * server)
|
|
{
|
|
char * matchstr=NULL; /* Represents the string left after being returned using the strstr function. */
|
|
char * buf = &(server->adapter->buf[server->adapter->buf_size - server->remaining]);
|
|
uint32_t len = at_server_read(server, buf, server->remaining);
|
|
|
|
if (0u != len)
|
|
{
|
|
server->remaining -= len;
|
|
while(1) /* wait for all recipients in the received data to be compared. */
|
|
{
|
|
matchstr = strstr(server->adapter->buf, server->end_mark);
|
|
if (NULL != matchstr)
|
|
{
|
|
at_parse(server);
|
|
/* not copy the last matching terminator. */
|
|
memcpy(server->adapter->buf, matchstr+strlen(server->end_mark), strlen(server->adapter->buf));
|
|
server->remaining = server->adapter->buf_size - strlen(matchstr);
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*parse the receive datas.*/
|
|
void at_parse(at_server_t * server)
|
|
{
|
|
char cur_cmd_name[AT_CMD_NAME_LEN] = { 0 };
|
|
at_cmd_t * cur_cmd = NULL;
|
|
char * cur_cmd_args = NULL;
|
|
char * buf = server->adapter->buf;
|
|
|
|
if (at_cmd_get_name(buf, cur_cmd_name) == false)
|
|
{
|
|
AT_LOG("ERROR CMD MATCH FAILED!\r\n");
|
|
|
|
return;
|
|
}
|
|
|
|
cur_cmd = at_find_cmd(server, cur_cmd_name);
|
|
if (cur_cmd == false)
|
|
{
|
|
AT_LOG("ERROR CMD MATCH FAILED!\r\n");
|
|
|
|
return;
|
|
}
|
|
|
|
cur_cmd_args = buf + strlen(cur_cmd_name);
|
|
if (at_cmd_process(server, cur_cmd, cur_cmd_args) == false)
|
|
{
|
|
AT_LOG("ERROR PARSE ARGS FAILED!\r\n");
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
/* get at command name from at server receive buffer. */
|
|
static bool at_cmd_get_name(char * cmd_buffer, char * cmd_name)
|
|
{
|
|
uint32_t cmd_name_len = 0u;
|
|
|
|
for (uint32_t i = 0; i < strlen(cmd_buffer) + 1; i++)
|
|
{
|
|
if ( (*(cmd_buffer + i) == AT_CMD_QUESTION_MARK) || (*(cmd_buffer + i) == AT_CMD_EQUAL_MARK)
|
|
|| (*(cmd_buffer + i) == AT_CMD_CR)
|
|
|| ( (*(cmd_buffer + i) >= AT_CMD_CHAR_0) && (*(cmd_buffer + i) <= AT_CMD_CHAR_9) ) )
|
|
{
|
|
cmd_name_len = i;
|
|
memcpy(cmd_name, cmd_buffer, cmd_name_len);
|
|
*(cmd_name + cmd_name_len) = '\0';
|
|
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/* find if the current at command name is in the at command list. */
|
|
static at_cmd_t * at_find_cmd(at_server_t * server, char * cmd)
|
|
{
|
|
for (uint32_t i = 0; i < server->cmd_num; i++)
|
|
{
|
|
if (!strcasecmp(cmd,server->cmd_list[i]->name))
|
|
{
|
|
return server->cmd_list[i];
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/* parse command parameters and execute corresponding command functions. */
|
|
static bool at_cmd_process(at_server_t * server, at_cmd_t * cmd, char * cmd_args)
|
|
{
|
|
at_result_t result = AT_RESULT_OK;
|
|
|
|
if ( (cmd_args[0] == AT_CMD_EQUAL_MARK) && (cmd_args[1] == AT_CMD_QUESTION_MARK) && (cmd_args[2] == AT_CMD_CR) )
|
|
{
|
|
if (cmd->test == NULL)
|
|
{
|
|
AT_LOG("ERROR CHECK ARGS FORMAT FAILED!\r\n");
|
|
|
|
return false;
|
|
}
|
|
|
|
result = cmd->test(server->adapter->write);
|
|
}
|
|
|
|
else if ( (cmd_args[0] == AT_CMD_QUESTION_MARK) && (cmd_args[1] == AT_CMD_CR) )
|
|
{
|
|
if (cmd->query == NULL)
|
|
{
|
|
AT_LOG("ERROR CHECK ARGS FORMAT FAILED!\r\n");
|
|
|
|
return false;
|
|
}
|
|
result = cmd->query(server->adapter->write);
|
|
}
|
|
|
|
else if ( (cmd_args[0] == AT_CMD_EQUAL_MARK)
|
|
|| ( (cmd_args[0] >= AT_CMD_CHAR_0) && (cmd_args[0] <= AT_CMD_CHAR_9) && (cmd_args[1] == AT_CMD_CR) ) )
|
|
{
|
|
if (cmd->setup == NULL)
|
|
{
|
|
AT_LOG("ERROR CHECK ARGS FORMAT FAILED!\r\n");
|
|
|
|
return false;
|
|
}
|
|
|
|
if(at_check_args(cmd_args, cmd->args_expr) == false)
|
|
{
|
|
AT_LOG("ERROR CHECK ARGS FORMAT FAILED!\r\n");;
|
|
|
|
return false;
|
|
}
|
|
|
|
result = cmd->setup(server->adapter->write, cmd_args);
|
|
}
|
|
|
|
else if (cmd_args[0] == AT_CMD_CR)
|
|
{
|
|
if (cmd->exec == NULL)
|
|
{
|
|
|
|
return false;
|
|
}
|
|
|
|
result = cmd->exec(server->adapter->write);
|
|
}
|
|
|
|
else
|
|
{
|
|
return result;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/* check the ar command parameter format. */
|
|
static bool at_check_args(char * args, char * args_format)
|
|
{
|
|
uint32_t left_sq_bracket_num = 0, right_sq_bracket_num = 0;
|
|
uint32_t left_angle_bracket_num = 0, right_angle_bracket_num = 0;
|
|
uint32_t comma_mark_num = 0;
|
|
|
|
for (uint32_t i = 0; i < strlen(args_format); i++)
|
|
{
|
|
switch (args_format[i])
|
|
{
|
|
case AT_CMD_L_SQ_BRACKET:
|
|
left_sq_bracket_num++;
|
|
break;
|
|
|
|
case AT_CMD_R_SQ_BRACKET:
|
|
right_sq_bracket_num++;
|
|
break;
|
|
|
|
case AT_CMD_L_ANGLE_BRACKET:
|
|
left_angle_bracket_num++;
|
|
break;
|
|
|
|
case AT_CMD_R_ANGLE_BRACKET:
|
|
right_angle_bracket_num++;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( (left_sq_bracket_num != right_sq_bracket_num) || (left_angle_bracket_num != right_angle_bracket_num)
|
|
|| (left_sq_bracket_num > left_angle_bracket_num) )
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
for (uint32_t i = 0; i < strlen(args); i++)
|
|
{
|
|
if (args[i] == AT_CMD_COMMA_MARK)
|
|
{
|
|
comma_mark_num++;
|
|
}
|
|
}
|
|
|
|
if ( (comma_mark_num + 1 < left_angle_bracket_num - left_sq_bracket_num)
|
|
|| (comma_mark_num + 1 > left_angle_bracket_num) )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/* parse the number of arguments to the at request instruction. */
|
|
int at_req_parse_args(const char * req_args, const char * req_expr, ...)
|
|
{
|
|
va_list args;
|
|
int req_args_num = 0;
|
|
|
|
va_start(args, req_expr);
|
|
req_args_num = vsscanf(req_args, req_expr, args);
|
|
va_end(args);
|
|
|
|
return req_args_num;
|
|
}
|
|
|
|
/* EOF. */
|