AT-Command/at.c
魔罗技术 8f56581724 1.删除at_obj中的at_work_ctx_t域,减少内存使用
2.解决重复释放信号量导致命令出现等待超时的问题
2021-04-18 14:47:22 +08:00

393 lines
10 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.

/**
******************************************************************************
* @brief AT<41><54><EFBFBD><EFBFBD>ͨ<EFBFBD>Ź<EFBFBD><C5B9><EFBFBD>(OS<4F>汾)
*
* Copyright (c) 2020, <morro_luo@163.com>
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2020-01-02 Morro Initial version.
* 2021-02-01 Morro ֧<><D6A7>URC<52>ص<EFBFBD><D8B5>н<EFBFBD><D0BD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>.
* 2021-02-05 Morro 1.<2E>޸<EFBFBD>struct at_obj,ȥ<><C8A5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* 2.ɾ<><C9BE> at_obj_destroy<6F>ӿ<EFBFBD>
* 2021-03-21 Morro ɾ<><C9BE>at_obj<62>е<EFBFBD>at_work_ctx_t<5F><74>,<2C><><EFBFBD><EFBFBD><EFBFBD>ڴ<EFBFBD>ʹ<EFBFBD><CAB9>
* 2021-04-08 Morro <20><><EFBFBD><EFBFBD><EFBFBD>ظ<EFBFBD><D8B8>ͷ<EFBFBD><CDB7>ź<EFBFBD><C5BA><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵȴ<D6B5><C8B4><EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
******************************************************************************
*/
#include "at.h"
#include "comdef.h"
#include <stdarg.h>
#include <string.h>
#include <stdio.h>
#include <stddef.h>
/**
* @brief Ĭ<>ϵ<EFBFBD><CFB5>Խӿ<D4BD>
*/
static void nop_dbg(const char *fmt, ...){}
/**
* @brief <20><><EFBFBD><EFBFBD><EFBFBD>ַ<EFBFBD><D6B7><EFBFBD>
*/
static void put_string(at_obj_t *at, const char *s)
{
while (*s != '\0')
at->adap.write(s++, 1);
}
/**
* @brief <20><><EFBFBD><EFBFBD><EFBFBD>ַ<EFBFBD><D6B7><EFBFBD>(<28><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>)
*/
static void put_line(at_obj_t *at, const char *s)
{
put_string(at, s);
put_string(at, "\r\n");
at->adap.debug("->\r\n%s\r\n", s);
}
//<2F><>ӡ<EFBFBD><D3A1><EFBFBD><EFBFBD>
static void at_print(struct at_work_ctx *e, const char *cmd, ...)
{
va_list args;
va_start(args, cmd);
char buf[MAX_AT_CMD_LEN];
vsnprintf(buf, sizeof(buf), cmd, args);
put_line(e->at, buf);
va_end(args);
}
/**
* @brief <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݻ<EFBFBD><DDBB><EFBFBD><EFBFBD><EFBFBD>
*/
static void recvbuf_clr(struct at_work_ctx *e)
{
e->at->rcv_cnt = 0;
}
//<2F>ȴ<EFBFBD>AT<41><54><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ӧ
static at_return wait_resp(at_obj_t *at, at_respond_t *r)
{
at->ret = AT_RET_TIMEOUT;
at->resp_timer = at_get_ms();
at->rcv_cnt = 0; //<2F><><EFBFBD>ս<EFBFBD><D5BD>ջ<EFBFBD><D5BB><EFBFBD>
at->resp = r;
at_sem_wait(at->completed, r->timeout);
at->adap.debug("<-\r\n%s\r\n", r->recvbuf);
at->resp = NULL;
return at->ret;
}
/**
* @brief <20>ȴ<EFBFBD><C8B4><EFBFBD><EFBFBD>յ<EFBFBD>ָ<EFBFBD><D6B8><EFBFBD><EFBFBD>
* @param[in] resp - <20>ڴ<EFBFBD><DAB4><EFBFBD><EFBFBD><EFBFBD><EFBFBD>մ<EFBFBD>(<28><>"OK",">")
* @param[in] timeout - <20>ȴ<EFBFBD><C8B4><EFBFBD>ʱʱ<CAB1><CAB1>
*/
at_return wait_recv(struct at_work_ctx *e, const char *resp,
unsigned int timeout)
{
char buf[64];
int cnt = 0, len;
at_obj_t *at = e->at;
at_return ret = AT_RET_TIMEOUT;
unsigned int timer = at_get_ms();
while (at_get_ms() - timer < timeout) {
len = at->adap.read(buf, sizeof(buf) - cnt);
cnt += len;
buf[cnt] = '\0';
if (strstr(buf, resp)) {
ret = AT_RET_OK;
break;
} else if (strstr(buf, "ERROR")) {
ret = AT_RET_ERROR;
break;
}
at_delay(10);
}
at->adap.debug("%s\r\n", buf);
return ret;
}
/**
* @brief <20><><EFBFBD><EFBFBD>AT<41><54><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @param[in] adap - AT<41>ӿ<EFBFBD><D3BF><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
*/
void at_obj_init(at_obj_t *at, const at_adapter_t *adap)
{
at->adap = *adap;
at->rcv_cnt = 0;
at->cmd_lock = ril_sem_new(1);
at->completed = ril_sem_new(0);
if (at->adap.debug == NULL)
at->adap.debug = nop_dbg;
}
/**
* @brief ִ<><D6B4><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @param[in] fmt - <20><>ʽ<EFBFBD><CABD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @param[in] r - <20><>Ӧ<EFBFBD><D3A6><EFBFBD><EFBFBD>,<2C><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>NULL, Ĭ<>Ϸ<EFBFBD><CFB7><EFBFBD>OK<4F><4B>ʾ<EFBFBD>ɹ<EFBFBD>,<2C>ȴ<EFBFBD>5s
* @param[in] args - <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>б<EFBFBD>
*/
at_return at_do_cmd(at_obj_t *at, at_respond_t *r, const char *cmd)
{
at_return ret;
char defbuf[64];
at_respond_t default_resp = {"OK", defbuf, sizeof(defbuf), 5000};
if (r == NULL) {
r = &default_resp; //Ĭ<><C4AC><EFBFBD><EFBFBD>Ӧ
}
if (!at_sem_wait(at->cmd_lock, r->timeout)) {
return AT_RET_TIMEOUT;
}
at->busy = true;
while (at->urc_cnt) {
at_delay(10);
}
put_line(at, cmd);
ret = wait_resp(at, r);
at_sem_post(at->cmd_lock);
at->busy = false;
return ret;
}
/**
* @brief ִ<><D6B4>AT<41><54>ҵ
* @param[in] at - AT<41><54><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @param[in] work - <20><>ҵ<EFBFBD><D2B5><EFBFBD>ں<EFBFBD><DABA><EFBFBD>(<28><><EFBFBD><EFBFBD> - int (*)(at_work_ctx_t *))
* @param[in] params- <20><>ҵ<EFBFBD><D2B5><EFBFBD><EFBFBD>
* @return <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>work<72>ķ<EFBFBD><C4B7><EFBFBD>ֵ
*/
int at_do_work(at_obj_t *at, at_work work, void *params)
{
at_work_ctx_t ctx;
int ret;
if (!at_sem_wait(at->cmd_lock, 150 * 1000)) {
return AT_RET_TIMEOUT;
}
at->busy = true;
while (at->urc_cnt) { //<2F>ȴ<EFBFBD>URC<52><43><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
at_delay(1);
}
//<2F><><EFBFBD><EFBFBD>at_work_ctx_t
ctx.params = params;
ctx.printf = at_print;
ctx.recvclr = recvbuf_clr;
ctx.read = at->adap.read;
ctx.write = at->adap.write;
ctx.wait_resp = wait_recv;
ctx.at = at;
at->dowork = true;
at->rcv_cnt = 0;
ret = work(&ctx);
at->dowork = false;
at_sem_post(at->cmd_lock);
at->busy = false;
return ret;
}
/**
* @brief <20>ָ<EFBFBD><D6B8><EFBFBD>Ӧ<EFBFBD><D3A6>
* @param[in] recvbuf - <20><><EFBFBD>ջ<EFBFBD><D5BB><EFBFBD><EFBFBD><EFBFBD>
* @param[out] lines - <20><>Ӧ<EFBFBD><D3A6><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @param[in] separator- <20>ָ<EFBFBD><D6B8><EFBFBD>(, \n)
* @return <20><><EFBFBD><EFBFBD>
*/
int at_split_respond_lines(char *recvbuf, char *lines[], int count, char separator)
{
char *s = recvbuf;
size_t i = 0;
if (s == NULL || lines == NULL)
return 0;
lines[i++] = s;
while(*s && i < count) {
if (*s == ',') {
*s = '\0';
lines[i++] = s + 1; /*ָ<><D6B8><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD>Ӵ<EFBFBD>*/
}
s++;
}
return i;
}
/**
* @brief urc <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @param[in] urcline - URC<52><43>
* @return true - <20><><EFBFBD><EFBFBD>ʶ<EFBFBD>𲢴<EFBFBD><F0B2A2B4><EFBFBD>, false - δʶ<CEB4><CAB6>URC
*/
static bool urc_handler_entry(at_obj_t *at, char *urcline, unsigned int size)
{
int i;
int ch = urcline[size - 1];
at_urc_ctx_t context = {at->adap.read, urcline, at->adap.urc_bufsize, size};
const utc_item_t *tbl = at->adap.utc_tbl;
if (tbl == NULL)
return true;
for (i = 0; i < at->adap.urc_tbl_count; i++) {
if (strstr(urcline, tbl->prefix)) { /* ƥ<><C6A5>ǰ׺*/
if (tbl->end_mark) { /* ƥ<><C6A5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>*/
if (!strchr(tbl->end_mark, ch))
return false;
} else if (!(ch == '\r' || ch == '\n'|| ch == '\0'))
return false;
at->adap.debug("<=\r\n%s\r\n", urcline);
tbl->handler(&context); /* <20>ݽ<EFBFBD><DDBD><EFBFBD><EFBFBD>ϲ<CFB2><E3B4A6> */
return true;
}
tbl++;
}
return false;
}
/**
* @brief urc <20><><EFBFBD>մ<EFBFBD><D5B4><EFBFBD>
* @param[in] ch - <20><><EFBFBD><EFBFBD><EFBFBD>ַ<EFBFBD>
* @return none
*/
static void urc_recv_process(at_obj_t *at, const char *buf, unsigned int size)
{
register char *urc_buf;
int ch;
urc_buf = at->adap.urc_buf;
//<2F><><EFBFBD>ճ<EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD><><C4AC>MAX_URC_RECV_TIMEOUT
if (at->urc_cnt > 0 && at_istimeout(at->urc_timer, MAX_URC_RECV_TIMEOUT)) {
urc_buf[at->urc_cnt] = '\0';
at->urc_cnt = 0;
if (at->urc_cnt > 2)
at->adap.debug("urc recv timeout=>%s\r\n", urc_buf);
}
while (size--) {
at->urc_timer = at_get_ms();
ch = *buf++;
urc_buf[at->urc_cnt++] = ch;
if (strchr(SPEC_URC_END_MARKS, ch) || ch == '\0') { //<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
urc_buf[at->urc_cnt] = '\0';
if (ch == '\r' || ch == '\n'|| ch == '\0') { //<2F><><EFBFBD>⵽1<E2B5BD><31>URC
if (at->urc_cnt > 2) {
if (!urc_handler_entry(at, urc_buf, at->urc_cnt) && !at->busy)
at->adap.debug("%s\r\n", urc_buf); //δʶ<CEB4>𵽵<EFBFBD>URC
}
at->urc_cnt = 0;
} else if (urc_handler_entry(at, urc_buf, at->urc_cnt)) {
at->urc_cnt = 0;
}
} else if (at->urc_cnt >= at->adap.urc_bufsize) //<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
at->urc_cnt = 0;
}
}
/**
* @brief <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ӧ֪ͨ
* @return none
*/
static void resp_notification(at_obj_t *at, at_return ret)
{
at->ret = ret;
at_sem_post(at->completed);
}
/**
* @brief ָ<><D6B8><EFBFBD><EFBFBD>Ӧ<EFBFBD><D3A6><EFBFBD>մ<EFBFBD><D5B4><EFBFBD>
* @param[in] buf - <20><><EFBFBD>ջ<EFBFBD><D5BB><EFBFBD><EFBFBD><EFBFBD>
* @param[in] size - <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݳ<EFBFBD><DDB3><EFBFBD>
* @return none
*/
static void resp_recv_process(at_obj_t *at, const char *buf, unsigned int size)
{
char *rcv_buf;
unsigned short rcv_size;
at_respond_t *resp = at->resp;
if (resp == NULL) //<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
return;
if (size) {
rcv_buf = (char *)resp->recvbuf;
rcv_size = resp->bufsize;
if (at->rcv_cnt + size >= rcv_size) { //<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
at->rcv_cnt = 0;
at->adap.debug("Receive overflow:%s", rcv_buf);
}
/*<2A><><EFBFBD><EFBFBD><EFBFBD>յ<EFBFBD><D5B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݷ<EFBFBD><DDB7><EFBFBD>rcv_buf<75><66> ---------------------------------------------*/
memcpy(rcv_buf + at->rcv_cnt, buf, size);
at->rcv_cnt += size;
rcv_buf[at->rcv_cnt] = '\0';
if (strstr(rcv_buf, resp->matcher)) { //<2F><><EFBFBD><EFBFBD>ƥ<EFBFBD><C6A5>
resp_notification(at, AT_RET_OK);
return;
} else if (strstr(rcv_buf, "ERROR")) {
resp_notification(at, AT_RET_ERROR);
return;
}
}
if (at_istimeout(at->resp_timer, resp->timeout)) //<2F><><EFBFBD>ճ<EFBFBD>ʱ
resp_notification(at, AT_RET_TIMEOUT);
else if (at->suspend) //ǿ<><C7BF><EFBFBD><EFBFBD>ֹ
resp_notification(at, AT_RET_ABORT);
}
/**
* @brief ATæ<54>ж<EFBFBD>
* @return true - <20><>ATָ<54><D6B8><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ִ<EFBFBD><D6B4><EFBFBD><EFBFBD>
*/
bool at_obj_busy(at_obj_t *at)
{
return !at->busy && at_istimeout(at->urc_timer, 2000);
}
/**
* @brief <20><><EFBFBD><EFBFBD>AT<41><54>ҵ
* @return none
*/
void at_suspend(at_obj_t *at)
{
at->suspend = 1;
}
/**
* @brief <20>ָ<EFBFBD>AT<41><54>ҵ
* @return none
*/
void at_resume(at_obj_t *at)
{
at->suspend = 0;
}
/**
* @brief AT<41><54><EFBFBD><EFBFBD>
* @return none
*/
void at_process(at_obj_t *at)
{
char c;
unsigned int len;
if (at->dowork) /* <20>Զ<EFBFBD><D4B6><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EEB4A6> */
return;
do {
len = at->adap.read(&c, 1);
urc_recv_process(at, &c,len);
resp_recv_process(at, &c, len);
} while (len);
}