AT-Command/at.c
2020-09-22 22:14:09 +08:00

367 lines
9.1 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.

/*******************************************************************************
* @file at.h
* @brief AT<41><54><EFBFBD><EFBFBD>ͨ<EFBFBD>Ź<EFBFBD><C5B9><EFBFBD>
*
* @version 5.0
* @date 2020-05-11
* @author roger.luo
*
* Change Logs:
* Date Author Notes
* 2016-01-22 roger.luo Initial version.
* 2017-05-21 roger.luo 1.1 <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>״̬<D7B4><CCAC><EFBFBD><EFBFBD>
* 2018-02-11 roger.luo 3.0
* 2020-01-02 roger.luo 4.0 <20><><EFBFBD><EFBFBD>os<6F>
*******************************************************************************/
#include "at.h"
#include <stdarg.h>
#include <string.h>
#include <stdio.h>
//<2F><>ʱ<EFBFBD>ж<EFBFBD>
#define AT_IS_TIMEOUT(start, time) (at_get_ms() - (start) > (time))
static LIST_HEAD(atlist); /*<2A><><EFBFBD><EFBFBD>ͷ<EFBFBD><CDB7><EFBFBD><EFBFBD> ----------------*/
/*
* @brief <20><><EFBFBD><EFBFBD><EFBFBD>ַ<EFBFBD><D6B7><EFBFBD>
*/
static void put_string(at_obj_t *at, const char *s)
{
while (*s != '\0')
at->cfg.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->cfg.debug("->\r\n%s\r\n", s);
}
//<2F><>ӡ<EFBFBD><D3A1><EFBFBD><EFBFBD>
static void at_print(at_obj_t *at, const char *cmd, ...)
{
va_list args;
va_start(args, cmd);
char buf[MAX_AT_CMD_LEN];
vsnprintf(buf, sizeof(buf), cmd, args);
put_line(at, buf);
va_end(args);
}
/*
* @brief <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݻ<EFBFBD><DDBB><EFBFBD><EFBFBD><EFBFBD>
*/
static void recvbuf_clr(at_obj_t *at)
{
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->resp = r;
at->ret = AT_RET_TIMEOUT;
at->resp_timer = at_get_ms();
recvbuf_clr(at); //<2F><><EFBFBD>ս<EFBFBD><D5BD>ջ<EFBFBD><D5BB><EFBFBD>
at->wait = 1;
at_sem_wait(&at->completed, r->timeout);
at->cfg.debug("<-\r\n%s\r\n", r->recvbuf);
at->resp = NULL;
at->wait = 0;
return at->ret;
}
/*
* @brief ͬ<><CDAC><EFBFBD><EFBFBD>ӦAT<41><54>Ӧ
* @param[in] resp - <20>ȴ<EFBFBD><C8B4><EFBFBD><EFBFBD>մ<EFBFBD>(<28><>"OK",">")
* @param[in] timeout - <20>ȴ<EFBFBD><C8B4><EFBFBD>ʱʱ<CAB1><CAB1>
*/
at_return wait_resp_sync(struct at_obj *at, const char *resp,
unsigned int timeout)
{
char buf[64];
int cnt = 0, len;
at_return ret = AT_RET_TIMEOUT;
unsigned int timer = at_get_ms();
while (at_get_ms() - timer < timeout) {
len = at->cfg.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->cfg.debug("%s", buf);
return ret;
}
/*
* @brief AT<41>ں<EFBFBD><DABA><EFBFBD><EFBFBD><EFBFBD>
*/
void at_obj_create(at_obj_t *at, const at_conf_t cfg)
{
at_work_env_t *e;
at->cfg = cfg;
at->rcv_cnt = 0;
at_sem_init(&at->cmd_lock, 1);
at_sem_init(&at->completed, 0);
e = &at->env;
e->at = at;
e->printf = at_print;
e->recvclr = recvbuf_clr;
e->read = cfg.read;
e->write = cfg.write;
e->wait_resp = wait_resp_sync;
list_add_tail(&at->node, &atlist);
}
/*
* @brief <20><><EFBFBD><EFBFBD>AT
*/
void at_obj_destroy(at_obj_t *at)
{
list_del(&at->node);
}
/*
* @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>3s
* @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), 3000};
if (r == NULL) {
r = &default_resp; //Ĭ<><C4AC><EFBFBD><EFBFBD>Ӧ
}
if (!at_sem_wait(&at->cmd_lock, r->timeout)) {
return AT_RET_TIMEOUT;
}
while (at->urc_cnt) {
at_delay(10);
}
put_line(at, cmd);
ret = wait_resp(at, r);
at_sem_post(&at->cmd_lock);
return ret;
}
/*
* @brief ִ<><D6B4>AT<41><54>ҵ
* @param[in] urc
* @return none
*/
int at_do_work(at_obj_t *at, at_work work, void *params)
{
int ret;
if (!at_sem_wait(&at->cmd_lock, 150 * 1000)) {
return AT_RET_TIMEOUT;
}
at->env.params = params;
at->dowork = true;
ret = work(&at->env);
at->dowork = false;
at_sem_post(&at->cmd_lock);
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>
* @return <20><><EFBFBD><EFBFBD>
*/
int at_split_respond_lines(char *recvbuf, char *lines[], int count)
{
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 none
*/
static void urc_handler_entry(at_obj_t *at, char *urcline, unsigned int size)
{
int i, n;
utc_item_t *tbl = at->cfg.utc_tbl;
for (i = 0; i < at->cfg.urc_tbl_count; i++){
n = strlen(tbl->prefix);
if (n > 0 && strncmp(urcline, tbl->prefix, n) == 0) {
tbl->handler(urcline, size);
at->cfg.debug("<=\r\n%s\r\n", urcline);
return;
}
tbl++;
}
if (size >= 2 && !at->wait) //<2F>Զ<EFBFBD><D4B6><EFBFBD><EFBFBD><EFBFBD>
at->cfg.debug("%s\r\n", urcline);
}
/*
* @brief urc <20><><EFBFBD>մ<EFBFBD><D5B4><EFBFBD>
* @param[in] buf - <20><><EFBFBD>ջ<EFBFBD><D5BB><EFBFBD>
* @return none
*/
static void urc_recv_process(at_obj_t *at, const char *buf, unsigned int size)
{
char *urc_buf;
unsigned short urc_size;
unsigned char c;
urc_buf = (char *)at->cfg.urc_buf;
urc_size = at->cfg.urc_bufsize;
if (at->urc_cnt > 0 && size == 0) {
if (AT_IS_TIMEOUT(at->urc_timer, 100)) { //100ms<6D><73>ʱ
urc_buf[at->urc_cnt] = '\0';
at->urc_cnt = 0;
at->cfg.debug("urc recv timeout=>%s\r\n", urc_buf);
}
} else {
at->urc_timer = at_get_ms();
while (size--) {
c = *buf++;
if (c == '\r' || c == '\n') { //<2F>յ<EFBFBD>1<EFBFBD><31>
urc_buf[at->urc_cnt] = '\0';
if (at->urc_cnt > 2)
urc_handler_entry(at, urc_buf, at->urc_cnt);
at->urc_cnt = 0;
} else {
urc_buf[at->urc_cnt++] = c;
if (at->urc_cnt >= urc_size) //<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
at->urc_cnt = 0;
}
}
}
}
/*
* @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 || size == 0)
return;
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->cfg.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 (!at->wait)
return;
if (strstr(rcv_buf, resp->matcher)) { //<2F><><EFBFBD><EFBFBD>ƥ<EFBFBD><C6A5>
at->ret = AT_RET_OK;
} else if (strstr(rcv_buf, "ERROR")) {
at->ret = AT_RET_ERROR;
} else if (AT_IS_TIMEOUT(at->resp_timer, resp->timeout)) {
at->ret = AT_RET_TIMEOUT;
} else if (at->suspend) //ǿ<><C7BF><EFBFBD><EFBFBD>ֹ
at->ret = AT_RET_ABORT;
else
return;
at_sem_post(&at->completed);
}
/*
* @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->wait == 0 && AT_IS_TIMEOUT(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_thread(void)
{
at_obj_t *at;
struct list_head *list ,*n = NULL;
int len;
char buf[32];
while (1) {
/*<2A><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>at_obj<62><6A><EFBFBD><EFBFBD>*/
list_for_each_safe(list, n, &atlist) {
at = list_entry(list, at_obj_t, node);
if (!at->dowork) {
#warning "<22><>ȡ<EFBFBD>Ż<EFBFBD>(readline) ..."
len = at->cfg.read(buf, sizeof(buf));
urc_recv_process(at, (char *)buf, len);
if (len > 0) {
resp_recv_process(at, buf, len);
}
}
}
at_delay(1);
}
}