/*
* Copyright (c) 20019-2020, wanweiyingchuang
*
* Change Logs:
* Date Author Notes
* 2022-02-18 denghengli the first version
*/
#include "at.h"
#define AT_RESP_END_OK_UPCASE "OK"
#define AT_RESP_END_OK_LWCASE "ok"
#define AT_RESP_END_ERROR "ERROR"
#define AT_RESP_END_FAIL "FAIL"
#define AT_END_CR_LF "\r\n"
static struct at_client at_client_table[AT_CLIENT_NUM_MAX];
/**
* Create response object.
*
* @param buf_size the maximum response buffer size
* @param line_num the number of setting response lines
* = 0: the response data will auto return when received 'OK' or 'ERROR'
* != 0: the response data will return when received setting lines number data
* @param timeout the maximum response time
*
* @return != NULL: response object
* = NULL: no memory
*/
at_response_t at_create_resp(uint16_t buf_size, uint16_t line_num, uint32_t timeout)
{
at_response_t resp = NULL;
resp = (at_response_t) pvPortMalloc(sizeof(struct at_response));
if (resp == NULL)
{
LOG_PRINT(DEBUG_AT, "AT create response object failed! No memory for response object!");
return NULL;
}
memset(resp, 0, sizeof(struct at_response));
resp->buf = (char *) pvPortMalloc(buf_size);
if (resp->buf == NULL)
{
LOG_PRINT(DEBUG_AT, "AT create response object failed! No memory for response buffer!");
vPortFree(resp);
return NULL;
}
resp->buf_size = buf_size;
resp->line_num = line_num;
resp->line_counts = 0;
resp->timeout = timeout;
return resp;
}
/**
* Delete and free response object.
*
* @param resp response object
*/
void at_delete_resp(at_response_t resp)
{
if (resp && resp->buf)
{
vPortFree(resp->buf);
}
if (resp)
{
vPortFree(resp);
resp = NULL;
}
}
/**
* Set response object information
*
* @param resp response object
* @param buf_size the maximum response buffer size
* @param line_num the number of setting response lines
* = 0: the response data will auto return when received 'OK' or 'ERROR'
* != 0: the response data will return when received setting lines number data
* @param timeout the maximum response time
*
* @return != NULL: response object
* = NULL: no memory
*/
at_response_t at_resp_set_info(at_response_t resp, int buf_size, int line_num, uint32_t timeout)
{
char *p_temp = NULL;
assert(resp);
if (resp->buf_size != buf_size)
{
resp->buf_size = buf_size;
vPortFree(resp->buf);
p_temp = (char *) pvPortMalloc(buf_size);
if (p_temp == NULL)
{
LOG_PRINT(DEBUG_AT, "No memory for realloc response buffer size(%d).", buf_size);
return NULL;
}
else
{
resp->buf = p_temp;
memset(p_temp, 0, buf_size);
}
}
resp->line_num = line_num;
resp->timeout = timeout;
return resp;
}
/**
* Get one line AT response buffer by line number.
*
* @param resp response object
* @param resp_line line number, start from '1'
*
* @return != NULL: response line buffer
* = NULL: input response line error
*/
const char *at_resp_get_line(at_response_t resp, int resp_line)
{
char *resp_buf = resp->buf;
char *resp_line_buf = NULL;
int line_num = 1;
assert(resp);
if (resp_line > resp->line_counts || resp_line <= 0)
{
LOG_PRINT(DEBUG_AT, "AT response get line failed! Input response line(%d) error!", resp_line);
return NULL;
}
for (line_num = 1; line_num <= resp->line_counts; line_num++)
{
if (resp_line == line_num)
{
resp_line_buf = resp_buf;
/* remove the last "\r\n". '\n' has been set to '\0' in line parsing */
if (resp_line_buf[strlen(resp_buf) - 1] == '\r')
{
resp_line_buf[strlen(resp_buf) - 1] = '\0';
}
return resp_line_buf;
}
resp_buf += strlen(resp_buf) + 1;
}
return NULL;
}
/**
* Get one line AT response buffer by keyword
*
* @param resp response object
* @param keyword query keyword
*
* @return != NULL: response line buffer
* = NULL: no matching data
*/
const char *at_resp_get_line_by_kw(at_response_t resp, const char *keyword)
{
char *resp_buf = resp->buf;
char *resp_line_buf = NULL;
int line_num = 1;
assert(resp);
assert(keyword);
for (line_num = 1; line_num <= resp->line_counts; line_num++)
{
if (strstr(resp_buf, keyword))
{
resp_line_buf = resp_buf;
/* remove the last "\r\n". '\n' has been set to '\0' in line parsing */
if (resp_line_buf[strlen(resp_buf) - 1] == '\r')
{
resp_line_buf[strlen(resp_buf) - 1] = '\0';
}
return resp_line_buf;
}
resp_buf += strlen(resp_buf) + 1;
}
return NULL;
}
/**
* Get and parse AT response buffer arguments by line number.
*
* @param resp response object
* @param resp_line line number, start from '1'
* @param resp_expr response buffer expression
*
* @return -1 : input response line number error or get line buffer error
* 0 : parsed without match
* >0 : the number of arguments successfully parsed
*/
int at_resp_parse_line_args(at_response_t resp, int resp_line, const char *resp_expr, ...)
{
va_list args;
int resp_args_num = 0;
const char *resp_line_buf = NULL;
assert(resp);
assert(resp_expr);
if ((resp_line_buf = at_resp_get_line(resp, resp_line)) == NULL)
{
return -1;
}
va_start(args, resp_expr);
resp_args_num = vsscanf(resp_line_buf, resp_expr, args);
va_end(args);
return resp_args_num;
}
/**
* Get and parse AT response buffer arguments by keyword.
*
* @param resp response object
* @param keyword query keyword
* @param resp_expr response buffer expression
*
* @return -1 : input keyword error or get line buffer error
* 0 : parsed without match
* >0 : the number of arguments successfully parsed
*/
int at_resp_parse_line_args_by_kw(at_response_t resp, const char *keyword, const char *resp_expr, ...)
{
va_list args;
int resp_args_num = 0;
const char *resp_line_buf = NULL;
assert(resp);
assert(resp_expr);
if ((resp_line_buf = at_resp_get_line_by_kw(resp, keyword)) == NULL)
{
return -1;
}
va_start(args, resp_expr);
resp_args_num = vsscanf(resp_line_buf, resp_expr, args);
va_end(args);
return resp_args_num;
}
/**
* Send commands to AT server and wait response.
*
* @param client current AT client object
* @param resp AT response object, using NULL when you don't care response
* @param cmd_expr AT commands expression
*
* @return 0 : success
* -1 : response status error
* -2 : wait timeout
* -7 : enter AT CLI mode
* result = at_exec_cmd(resp, "AT+CIFSR");
*/
int at_obj_exec_cmd(at_client_t client, at_response_t resp, const char *cmd_expr, ...)
{
va_list args;
uint16_t cmd_size = 0;
int result = RT_EOK;
const char *cmd = NULL;
if (client == NULL)
{
LOG_PRINT(DEBUG_AT, "input AT Client object is NULL, please create or get AT Client object!");
return -RT_ERROR;
}
/* check AT CLI mode */
if (client->status == AT_STATUS_CLI && resp)
{
return -RT_EBUSY;
}
xSemaphoreTake(client->lock, portMAX_DELAY);
client->resp_status = AT_RESP_OK;
client->resp = res
评论3