From 84bfaa01c45720b22226669c602e709f678dbe25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=AD=94=E7=BD=97=E6=8A=80=E6=9C=AF?= Date: Wed, 20 Jan 2021 22:17:53 +0800 Subject: [PATCH] =?UTF-8?q?1.=E8=A7=A3=E5=86=B3=E9=93=BE=E8=A1=A8=E6=9C=AA?= =?UTF-8?q?=E5=88=9D=E5=A7=8B=E5=8C=96=E5=AF=BC=E8=87=B4=E6=AE=B5=E9=94=99?= =?UTF-8?q?=E8=AF=AF=E9=97=AE=E9=A2=98=E3=80=82=202.=E8=B0=83=E9=80=9A?= =?UTF-8?q?=E5=8D=95=E8=A1=8C=E5=91=BD=E4=BB=A4=E3=80=81=E5=A4=9A=E8=A1=8C?= =?UTF-8?q?=E5=91=BD=E4=BB=A4=E3=80=81=E8=87=AA=E5=AE=9A=E4=B9=89=E5=91=BD?= =?UTF-8?q?=E4=BB=A4=E6=94=B6=E5=8F=91=E5=8A=9F=E8=83=BD=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- at_chat.c | 238 ++++++++++++++++++++++++++++++++---------------------- at_chat.h | 43 ++++++---- 2 files changed, 169 insertions(+), 112 deletions(-) diff --git a/at_chat.c b/at_chat.c index d1d90ed..5322174 100644 --- a/at_chat.c +++ b/at_chat.c @@ -1,13 +1,15 @@ /****************************************************************************** - * @brief AT指令通信 + * @brief AT指令通信管理 * - * Copyright (c) 2020, + * Copyright (c) 2020~2021, * * SPDX-License-Identifier: Apathe-2.0 * * Change Logs: * Date Author Notes * 2020-01-02 Morro 初版 + * 2021-01-20 Morro 增加debug调试接口, 解决链表未初始化导至段错误的问题 + * 调通单行命令、多行命令、自定义命令等接口 ******************************************************************************/ #include "at_chat.h" @@ -16,13 +18,17 @@ #include //超时判断 -#define AT_IS_TIMEOUT(start, time) (at_get_ms() - (start) > (time)) +#define AT_IS_TIMEOUT(start, time) (AT_GET_TICK() - (start) > (time)) /**AT作业类型(实际是4种类型的状态机轮询程序) -----------------------------------*/ #define AT_TYPE_WORK 0 /* 普通作业 ----------*/ #define AT_TYPE_CMD 1 /* 标准命令 ----------*/ -#define AT_TYPE_MULTILINE 3 /* 多行命令 ----------*/ -#define AT_TYPE_SINGLLINE 4 /* 单行命令 ----------*/ +#define AT_TYPE_MULTILINE 2 /* 多行命令 ----------*/ +#define AT_TYPE_SINGLLINE 3 /* 单行命令 ----------*/ + +#ifndef AT_DEBUG + #define AT_DEBUG(...) do {}while(0) +#endif typedef int (*base_work)(at_obj_t *at, ...); @@ -33,9 +39,9 @@ static const inline at_adapter_t *__get_adapter(at_obj_t *at) return &at->adap; } -static bool is_timeout(at_obj_t *at, unsigned int ms) +static bool at_is_timeout(at_obj_t *at, unsigned int ms) { - return AT_IS_TIMEOUT(at->resp_timer, ms); + return AT_IS_TIMEOUT(at->timer, ms); } /** * @brief 发送数据 @@ -85,13 +91,20 @@ static char *search_string(at_obj_t *at, const char *str) return strstr(get_recv_buf(at), str); } -/**前向查找字串*/ +/** + * @brief 终止执行 + */ static bool at_isabort(at_obj_t *at) { return at->cursor ? at->cursor->abort : 1; } - - +/** + * @brief 重置计时器 + */ +static void at_reset_timer(at_obj_t *at) +{ + at->timer = AT_GET_TICK(); +} /** * @brief AT执行回调 */ @@ -110,27 +123,7 @@ static void do_at_callbatk(at_obj_t *a, at_item_t *i, at_callbatk_t cb, at_retur } } -/** - * @brief AT控制器初始化 - * @param[in] cfg - AT响应 - */ -void at_core_init(at_obj_t *at, const at_adapter_t *adap) -{ - at_env_t *e; - at->adap = *adap; - e = &at->env; - at->recv_cnt = 0; - - e->is_timeout = is_timeout; - e->printf = print; - e->recvbuf = get_recv_buf; - e->recvclr = recv_buf_clear; - e->recvlen = get_recv_count; - e->find = search_string; - e->abort = at_isabort; -} - -/**添加作业到队列*/ +/* 添加作业到队列*/ static bool add_work(at_obj_t *at, void *params, void *info, int type) { at_item_t *i; @@ -152,14 +145,14 @@ static bool add_work(at_obj_t *at, void *params, void *info, int type) static int do_work_handler(at_obj_t *at) { at_item_t *i = at->cursor; - return ((int (*)(at_env_t *e))i->info)(i->param); + return ((int (*)(at_env_t *e))i->info)(&at->env); } -/******************************************************************************* - * @brief 通用命令执行 - * @param[in] a - AT管理器 - * @return 0 - 保持工作,非0 - 结束工作 - ******************************************************************************/ +/** + * @brief 通用命令处理 + * @param[in] a - AT控制器 + * @return true - 结束作业, false - 保持作业, + */ static int do_cmd_handler(at_obj_t *a) { at_item_t *i = a->cursor; @@ -172,28 +165,30 @@ static int do_cmd_handler(at_obj_t *a) e->reset_timer(a); e->recvclr(a); break; - case 1: /*接收状态 -----------------------------------0-------------------*/ - if (search_string(a, c->matcher)) { + case 1: + if (search_string(a, c->matcher)) { //接收匹配 + AT_DEBUG("<-\r\n%s\r\n", get_recv_buf(a)); do_at_callbatk(a, i, c->cb, AT_RET_OK); return true; - } else if (search_string(a, "ERROR")) { + } else if (search_string(a, "ERROR")) { + AT_DEBUG("<-\r\n%s\r\n", get_recv_buf(a)); if (++e->i >= c->retry) { do_at_callbatk(a, i, c->cb, AT_RET_ERROR); return true; } e->state = 2; /* 出错之后延时一段时间*/ e->reset_timer(a); /* 重置定时器*/ - } else if (e->is_timeout(a, c->timeout)) { + } else if (e->is_timeout(a, c->timeout)) { /* 响应超时*/ if (++e->i >= c->retry) { do_at_callbatk(a, i, c->cb, AT_RET_TIMEOUT); return true; } - e->state = 0; /**返回上一状态*/ + e->state = 0; /*返回上一状态*/ } break; case 2: if (e->is_timeout(a, 500)) - e->state = 0; /**返回初始状态*/ + e->state = 0; /*返回初始状态*/ break; default: e->state = 0; @@ -201,11 +196,11 @@ static int do_cmd_handler(at_obj_t *a) return false; } -/******************************************************************************* +/** * @brief 单行命令处理 - * @param[in] a - AT管理器 - * @return 0 - 保持工作,非0 - 结束工作 - ******************************************************************************/ + * @param[in] a - AT控制器 + * @return true - 结束作业, false - 保持作业, + */ static int send_signlline_handler(at_obj_t *a) { at_item_t *i = a->cursor; @@ -220,23 +215,25 @@ static int send_signlline_handler(at_obj_t *a) e->reset_timer(a); e->recvclr(a); break; - case 1: /*接收状态 -------------------------------------------------------*/ - if (search_string(a, "OK")) { - do_at_callbatk(a, i, cb, AT_RET_OK); + case 1: + if (search_string(a, "OK")) { + AT_DEBUG("<-\r\n%s\r\n", get_recv_buf(a)); + do_at_callbatk(a, i, cb, AT_RET_OK); //接收匹配 return true; } else if (search_string(a, "ERROR")) { + AT_DEBUG("<-\r\n%s\r\n", get_recv_buf(a)); if (++e->i >= 3) { do_at_callbatk(a, i, cb, AT_RET_ERROR); return true; } - e->state = 2; /**出错之后延时一段时间*/ - e->reset_timer(a); /**重置定时器*/ + e->state = 2; /*出错之后延时一段时间*/ + e->reset_timer(a); /*重置定时器*/ } else if (e->is_timeout(a, 3000 + e->i * 2000)) { if (++e->i >= 3) { do_at_callbatk(a, i, cb, AT_RET_TIMEOUT); return true; } - e->state = 0; /**返回上一状态*/ + e->state = 0; /*返回上一状态*/ } break; case 2: @@ -248,11 +245,12 @@ static int send_signlline_handler(at_obj_t *a) } return false; } -/******************************************************************************* + +/** * @brief 多行命令管理 - * @param[in] a - AT管理器 - * @return 0 - 保持工作,非0 - 结束工作 - ******************************************************************************/ + * @param[in] a - AT控制器 + * @return true - 结束作业, false - 保持作业, + */ static int send_multiline_handler(at_obj_t *a) { at_item_t *i = a->cursor; @@ -271,22 +269,28 @@ static int send_multiline_handler(at_obj_t *a) e->state++; break; case 1: - if (search_string(a, "OK")){ + if (search_string(a, "OK")) { e->state = 0; e->i++; - e->i = 0; + e->j = 0; + AT_DEBUG("<-\r\n%s\r\n", get_recv_buf(a)); } else if (search_string(a, "ERROR")) { + AT_DEBUG("<-\r\n%s\r\n", get_recv_buf(a)); if (++e->j >= 3) { do_at_callbatk(a, i, cb, AT_RET_ERROR); return true; } - e->state = 2; /**出错之后延时一段时间*/ - e->reset_timer(a); /**重置定时器*/ + e->state = 2; /*出错之后延时一段时间*/ + e->reset_timer(a); /*重置定时器*/ } else if (e->is_timeout(a, 3000)) { do_at_callbatk(a, i, cb, AT_RET_TIMEOUT); return true; } break; + case 2: + if (e->is_timeout(a, 500)) + e->state = 0; /**返回初始状态*/ + break; default: e->state = 0; } @@ -296,7 +300,7 @@ static int send_multiline_handler(at_obj_t *a) /** * @brief 发送行 * @param[in] fmt - 格式化输出 - * @param[in] args - 如变参数列表 + * @param[in] args - 可变参数列表 */ static void at_send_line(at_obj_t *at, const char *fmt, va_list args) { @@ -308,21 +312,29 @@ static void at_send_line(at_obj_t *at, const char *fmt, va_list args) recv_buf_clear(at); //清空接收缓存 send_data(at, buf, len); send_data(at, "\r\n", 2); + + AT_DEBUG("->\r\n%s\r\n", buf); } + /** - * @brief urc 处理总入口 - * @param[in] urc + * @brief urc(unsolicited code) 处理总入口 + * @param[in] urc - 接收缓冲区 + * @param[in] size - 缓冲区大小 * @return none */ static void urc_handler_entry(at_obj_t *at, char *urc, unsigned int size) { int i, n; utc_item_t *tbl = at->adap.utc_tbl; - for (i = 0; i < at->adap.urc_tbl_count; i++){ - n = strlen(tbl->prefix); - if (strncmp(urc, tbl->prefix, n) == 0) - tbl[i].handler(urc, size); + for (i = 0; i < at->adap.urc_tbl_count; i++) { + n = strlen(tbl->prefix); + if (strncmp(urc, tbl->prefix, n) == 0) { /* 匹配前缀 */ + tbl[i].handler(urc, size); /* 回调处理*/ + break; + } } + if (at->cursor == NULL) + AT_DEBUG("<=\r\n%s\r\n", urc); } /** @@ -335,22 +347,24 @@ static void urc_recv_process(at_obj_t *at, char *buf, unsigned int size) char *urc_buf; unsigned short urc_size; urc_buf = (char *)at->adap.urc_buf; - urc_size = at->adap.urc_bufsize; + urc_size = at->adap.urc_bufsize; + if (size == 0 && at->urc_cnt > 0) { - if (AT_IS_TIMEOUT(at->urc_timer, 2000)){ + if (AT_IS_TIMEOUT(at->urc_timer, 2000)) { /* 接收超时*/ urc_handler_entry(at, urc_buf, at->urc_cnt); at->recv_cnt = 0; + AT_DEBUG("Urc recv timeout.\r\n"); } - } else { - at->urc_timer = at_get_ms(); + } else if (urc_buf != NULL){ + at->urc_timer = AT_GET_TICK(); while (size--) { - if (*buf == '\n') { + if (*buf == '\n') { /*逐行处理*/ urc_buf[at->urc_cnt] = '\0'; urc_handler_entry(at, urc_buf, at->urc_cnt); } else { urc_buf[at->urc_cnt++] = *buf++; - if (at->urc_cnt >= urc_size) - at->urc_cnt = 0; + if (at->urc_cnt >= urc_size) /* 溢出处理 */ + at->urc_cnt = 0; } } } @@ -371,14 +385,46 @@ static void resp_recv_process(at_obj_t *at, const char *buf, unsigned int size) if (at->recv_cnt + size >= recv_size) //接收溢出处理 at->recv_cnt = 0; - memcpy(recv_buf + at->recv_cnt, buf, size); + memcpy(recv_buf + at->recv_cnt, buf, size); at->recv_cnt += size; recv_buf[at->recv_cnt] = '\0'; } /** - * @brief 执行AT作业 - * @param[in] a - AT管理器 + * @brief AT控制器初始化 + * @param[in] at - AT控制器 + * @param[in] adap - AT适配器 + */ +void at_obj_init(at_obj_t *at, const at_adapter_t *adap) +{ + int i; + at_env_t *e; + at->adap = *adap; + e = &at->env; + at->recv_cnt = 0; + + e->is_timeout = at_is_timeout; + e->printf = print; + e->recvbuf = get_recv_buf; + e->recvclr = recv_buf_clear; + e->recvlen = get_recv_count; + e->find = search_string; + e->abort = at_isabort; + e->reset_timer = at_reset_timer; + + /* 链表初始化*/ + INIT_LIST_HEAD(&at->ls_idle); + INIT_LIST_HEAD(&at->ls_ready); + + for (i = 0; i < sizeof(at->items) / sizeof(at_item_t); i++) + list_add_tail(&at->items[i].node, &at->ls_idle); + + while (adap->recv_buf == NULL) {} //确保缓冲区为非空 +} + +/** + * @brief 执行AT作业(自定义作业) + * @param[in] a - AT控制器 * @param[in] work - AT作业入口 * @param[in] params - */ @@ -389,7 +435,7 @@ bool at_do_work(at_obj_t *at, int (*work)(at_env_t *e), void *params) /** * @brief 执行AT指令 - * @param[in] a - AT管理器 + * @param[in] a - AT控制器 * @param[in] cmd - cmd命令 */ bool at_do_cmd(at_obj_t *at, void *params, const at_cmd_t *cmd) @@ -398,8 +444,8 @@ bool at_do_cmd(at_obj_t *at, void *params, const at_cmd_t *cmd) } /** - * @brief 发送单行AT命令 - * @param[in] at - AT管理器 + * @brief 发送单行AT命令(默认等待OK返回, 3s超时) + * @param[in] at - AT控制器 * @param[in] cb - 执行回调 * @param[in] singlline - 单行命令 * @note 在命令执行完毕之前,singlline必须始终有效 @@ -410,8 +456,8 @@ bool at_send_singlline(at_obj_t *at, at_callbatk_t cb, const char *singlline) } /** - * @brief 发送多行AT命令 - * @param[in] at - AT管理器 + * @brief 发送多行AT命令(多用于初始化模组, 默认等待OK返回, 3s超时) + * @param[in] at - AT控制器 * @param[in] cb - 执行回调 * @param[in] multiline - 单行命令 * @note 在命令执行完毕之前,multiline @@ -422,7 +468,7 @@ bool at_send_multiline(at_obj_t *at, at_callbatk_t cb, const char **multiline) } /** - * @brief 强行中止AT作业 + * @brief 强行中止AT作业 */ void at_item_abort(at_item_t *i) @@ -431,10 +477,10 @@ void at_item_abort(at_item_t *i) } /** - * @brief AT忙判断 - * @return true - 有AT指令或者任务正在执行中 + * @brief AT忙判断 + * @return true - 有AT指令或者任务正在执行中 */ -bool at_core_busy(at_obj_t *at) +bool at_obj_busy(at_obj_t *at) { return !list_empty(&at->ls_ready); } @@ -444,14 +490,13 @@ bool at_core_busy(at_obj_t *at) */ static void at_work_manager(at_obj_t *at) { - register at_item_t *cursor = at->cursor; at_env_t *e = &at->env; - /*通用工作处理者 ---------------------------------------------------------*/ + /*作业处理表 --------------------------------------------------------------*/ static int (*const work_handler_table[])(at_obj_t *) = { do_work_handler, do_cmd_handler, - send_signlline_handler, - send_multiline_handler + send_multiline_handler, + send_signlline_handler }; if (at->cursor == NULL) { if (list_empty(&at->ls_ready)) //就绪链为空 @@ -459,17 +504,18 @@ static void at_work_manager(at_obj_t *at) e->i = 0; e->j = 0; e->state = 0; - e->params = cursor->param; - e->recvclr(at); - e->reset_timer(at); at->cursor = list_first_entry(&at->ls_ready, at_item_t, node); + e->params = at->cursor->param; + e->recvclr(at); + e->reset_timer(at); } - /**工作执行完成,则将它放入到空闲工作链 ------------------------------------*/ - if (work_handler_table[cursor->type](at) || cursor->abort) { + /* 工作执行完成,则将它放入到空闲工作链 -------------------------------------*/ + if (work_handler_table[at->cursor->type](at) || at->cursor->abort) { list_move_tail(&at->cursor->node, &at->ls_idle); at->cursor = NULL; } } + /** * @brief AT轮询任务 */ diff --git a/at_chat.h b/at_chat.h index 7c688e9..0f6e397 100644 --- a/at_chat.h +++ b/at_chat.h @@ -1,24 +1,35 @@ /****************************************************************************** - * @brief AT指令通信 + * @brief AT指令通信管理 * - * Copyright (c) 2020, + * Copyright (c) 2020~2021, * * SPDX-License-Identifier: Apathe-2.0 * * Change Logs: * Date Author Notes * 2020-01-02 Morro 初版 + * 2021-01-20 Morro 增加debug调试接口, 解决链表未初始化导至段错误的问题 + * 调通单行命令、多行命令、自定义命令等接口 ******************************************************************************/ #ifndef _ATCHAT_H_ #define _ATCHAT_H_ -#include "at_util.h" #include #include + +/*最大AT命令长度 --------------------------------------------------------------*/ #define MAX_AT_CMD_LEN 128 +/* debug 打印接口 ------------------------------------------------------------*/ +#include +#define AT_DEBUG(...) printf("[AT]:");printf(__VA_ARGS__) /*do{}while(0)*/ + +/* 获取系统滴答(ms) -----------------------------------------------------------*/ +#include "platform.h" +#define AT_GET_TICK() get_tick() + struct at_obj; /*urc处理项 -----------------------------------------------------------------*/ @@ -81,24 +92,24 @@ typedef enum { /*AT作业项*/ typedef struct { - at_work_state state : 3; - unsigned char type : 3; - unsigned char abort : 1; - void *param; - void *info; - struct list_head node; + unsigned int state : 3; + unsigned int type : 3; /* 作业类型*/ + unsigned int abort : 1; + void *param; /* 通用参数*/ + void *info; /* 通用信息指针*/ + struct list_head node; /* 链表结点*/ }at_item_t; /*AT管理器 ------------------------------------------------------------------*/ typedef struct at_obj{ at_adapter_t adap; - at_env_t env; - at_item_t tbl[10]; - at_item_t *cursor; - struct list_head ls_ready, ls_idle; /*就绪,空闲作业链*/ - unsigned int resp_timer; - unsigned int urc_timer; - at_return ret; + at_env_t env; /* 作业运行环境*/ + at_item_t items[10]; /* 最大容纳10个作业*/ + at_item_t *cursor; /* 当前作业项*/ + struct list_head ls_ready, ls_idle; /* 就绪,空闲作业链*/ + unsigned int timer; + unsigned int urc_timer; /* urc接收计时器*/ + at_return ret; //urc接收计数, 命令响应接收计数器 unsigned short urc_cnt, recv_cnt; unsigned char suspend: 1;