mirror of
https://gitee.com/moluo-tech/AT-Command
synced 2025-06-17 16:07:52 +00:00
1.支持URC回调中接收数据.
2.修改struct at_obj,去除链表管理机制,使用单独任务接收处理每个at_obj.
This commit is contained in:
parent
e95ea83470
commit
ea3dccb6b6
@ -95,7 +95,12 @@ static int wifi_reset_work(at_env_t *e)
|
||||
break;
|
||||
case 2:
|
||||
wifi_open(); //重启启动wifi
|
||||
e->state++;
|
||||
break;
|
||||
case 3:
|
||||
if (e->is_timeout(a, 2000)) //延时等待2s
|
||||
return true;
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -146,7 +151,8 @@ void wifi_init(void)
|
||||
wifi_uart_init(115200);
|
||||
at_obj_init(&at, &at_adapter);
|
||||
|
||||
wifi_open();
|
||||
//启动WIFI
|
||||
at_do_work(&at, wifi_reset_work, &at);
|
||||
|
||||
//初始化wifi
|
||||
at_send_multiline(&at, at_init_callbatk, wifi_init_cmds);
|
||||
|
31
README.md
31
README.md
@ -1,5 +1,6 @@
|
||||
# AT Command
|
||||
|
||||
|
||||
## 介绍
|
||||
一种AT命令通信解析模块,支持裸机(at_chat)和OS版本(at)。适用于modem、WIFI模块、蓝牙通信。
|
||||
|
||||
@ -22,7 +23,7 @@
|
||||
|
||||
at_chat 模块使用链式队列进行管理,包含2条链表,空闲链表和就绪链表。它们的每一个基本工作单元称为一个作业项,对于将要执行的命令都会放到就绪链表中,命令执行完成之后由空闲链表来进行回收,作业项的定义如下:
|
||||
|
||||
```
|
||||
```c
|
||||
|
||||
/*AT作业项*/
|
||||
typedef struct {
|
||||
@ -51,7 +52,7 @@ typedef struct {
|
||||
详细使用可以参考Demo程序wifi_task.c模块
|
||||
|
||||

|
||||
```
|
||||
```c
|
||||
|
||||
/*
|
||||
* @brief 定义AT控制器
|
||||
@ -70,7 +71,7 @@ const at_adapter_t adap = { //AT适配器接口
|
||||
|
||||
3. 初始化AT控制器
|
||||
|
||||
```
|
||||
```c
|
||||
|
||||
at_obj_init(&at, &adap);
|
||||
|
||||
@ -79,7 +80,7 @@ at_obj_init(&at, &adap);
|
||||
|
||||
4. 将AT控制器放入任务中轮询(考虑到处理实时性,建议20ms以下)
|
||||
|
||||
```
|
||||
```c
|
||||
/*
|
||||
* @brief wifi任务(10ms 轮询1次)
|
||||
*/
|
||||
@ -99,7 +100,7 @@ void wifi_task(void)
|
||||
|
||||
<= OK\r\n
|
||||
|
||||
```
|
||||
```c
|
||||
|
||||
/**
|
||||
* @brief AT执行回调处理程序
|
||||
@ -124,12 +125,12 @@ at_send_singlline(&at, test_gpio_callback, "AT+GPIO_TEST_EN=1");
|
||||
|
||||
- at_do_cmd,执行AT命令,可以通过这个接口进一步封装出一常用的单行命令、多行命令。
|
||||
- at_split_respond_lines,命令响应分割器。
|
||||
- at_do_work,如果发送的数据比较复杂,如GPRS模组发送短信或者发送socket数据需要等待"<"提示符,可以通过这个接口自定义收发。
|
||||
- at_do_work,适用于发送组合命令,如GPRS模组发送短信或者发送socket数据需要等待"<"或者"CONNECT"提示符,可以通过这个接口自定义收发。
|
||||
|
||||
##### 使用演示(后续会提供一个无线GPRS模块演示程序出来)
|
||||
```
|
||||
```c
|
||||
|
||||
static at_obj_t at; //定义AT控制器
|
||||
static at_obj_t at; //定义AT控制器对象
|
||||
|
||||
static char urc_buf[128]; //URC主动上报缓冲区
|
||||
|
||||
@ -142,7 +143,8 @@ const at_adapter_t adap = { //AT适配器接口
|
||||
.urc_bufsize = sizeof(urc_buf),
|
||||
.utc_tbl = utc_tbl,
|
||||
.urc_tbl_count = sizeof(utc_tbl) / sizeof(utc_item_t),
|
||||
|
||||
//debug调试接口
|
||||
.debug = at_debug,
|
||||
//适配GPRS模块的串口读写接口
|
||||
.write = uart_write,
|
||||
.read = uart_read
|
||||
@ -150,15 +152,15 @@ const at_adapter_t adap = { //AT适配器接口
|
||||
|
||||
```
|
||||
|
||||
3. 初始化AT控制器并创建AT线程
|
||||
3. 初始化AT控制器并创建AT接收处理线程
|
||||
|
||||
```
|
||||
```c
|
||||
|
||||
void at_thread(void)
|
||||
{
|
||||
at_obj_create(&at, &adap);
|
||||
while (1) {
|
||||
at_thread(&at);
|
||||
at_process(&at);
|
||||
}
|
||||
}
|
||||
|
||||
@ -172,7 +174,7 @@ void at_thread(void)
|
||||
<= +CSQ: 24, 0
|
||||
<= OK
|
||||
|
||||
```
|
||||
```c
|
||||
/*
|
||||
* @brief 获取csq值
|
||||
*/
|
||||
@ -191,4 +193,7 @@ bool read_csq_value(at_obj_t *at, int *rssi, int *error_rate)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
```
|
||||
|
226
at.c
226
at.c
@ -8,17 +8,33 @@
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2020-01-02 Morro Initial version.
|
||||
* 2021-02-01 Morro 支持URC回调中接收数据.
|
||||
* 2021-02-05 Morro 1.修改struct at_obj,去除链表管理机制
|
||||
* 2.删除 at_obj_destroy接口
|
||||
******************************************************************************/
|
||||
|
||||
#include "at.h"
|
||||
#include "at/at.h"
|
||||
#include "misc/comdef.h"
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stddef.h>
|
||||
|
||||
//超时判断
|
||||
#define AT_IS_TIMEOUT(start, time) (at_get_ms() - (start) > (time))
|
||||
|
||||
static LIST_HEAD(atlist); /*链表头结点 ----------------*/
|
||||
/*
|
||||
* @brief 默认调试接口
|
||||
*/
|
||||
static void nop_dbg(const char *fmt, ...){}
|
||||
|
||||
/*
|
||||
* @brief 获取at控制器
|
||||
*/
|
||||
at_obj_t *get_at_obj(struct at_work_ctx *e)
|
||||
{
|
||||
return container_of(e, at_obj_t, ctx);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* @brief 输出字符串
|
||||
@ -41,22 +57,22 @@ static void put_line(at_obj_t *at, const char *s)
|
||||
}
|
||||
|
||||
//打印输出
|
||||
static void at_print(at_obj_t *at, const char *cmd, ...)
|
||||
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(at, buf);
|
||||
put_line(get_at_obj(e), buf);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief 清除数据缓冲区
|
||||
*/
|
||||
static void recvbuf_clr(at_obj_t *at)
|
||||
static void recvbuf_clr(struct at_work_ctx *e)
|
||||
{
|
||||
at->rcv_cnt = 0;
|
||||
get_at_obj(e)->rcv_cnt = 0;
|
||||
}
|
||||
|
||||
//等待AT命令响应
|
||||
@ -65,12 +81,10 @@ 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); //清空接收缓存
|
||||
at->wait = 1;
|
||||
at->rcv_cnt = 0; //清空接收缓存
|
||||
at_sem_wait(at->completed, r->timeout);
|
||||
at->adap.debug("<-\r\n%s\r\n", r->recvbuf);
|
||||
at->resp = NULL;
|
||||
at->wait = 0;
|
||||
return at->ret;
|
||||
}
|
||||
|
||||
@ -79,11 +93,13 @@ static at_return wait_resp(at_obj_t *at, at_respond_t *r)
|
||||
* @param[in] resp - 等待接收串(如"OK",">")
|
||||
* @param[in] timeout - 等待超时时间
|
||||
*/
|
||||
at_return wait_resp_sync(struct at_obj *at, const char *resp,
|
||||
at_return wait_resp_sync(struct at_work_ctx *e, const char *resp,
|
||||
unsigned int timeout)
|
||||
{
|
||||
char buf[64];
|
||||
int cnt = 0, len;
|
||||
at_obj_t *at = get_at_obj(e);
|
||||
|
||||
at_return ret = AT_RET_TIMEOUT;
|
||||
unsigned int timer = at_get_ms();
|
||||
while (at_get_ms() - timer < timeout) {
|
||||
@ -105,58 +121,54 @@ at_return wait_resp_sync(struct at_obj *at, const char *resp,
|
||||
|
||||
|
||||
/*
|
||||
* @brief AT内核配置
|
||||
* @brief 创建AT控制器
|
||||
*/
|
||||
void at_obj_create(at_obj_t *at, const at_adapter_t *adap)
|
||||
{
|
||||
at_work_env_t *e;
|
||||
at_work_ctx_t *ctx;
|
||||
at->adap = *adap;
|
||||
at->rcv_cnt = 0;
|
||||
|
||||
at->cmd_lock = at_sem_new(1);
|
||||
at->completed = at_sem_new(0);
|
||||
e = &at->env;
|
||||
e->at = at;
|
||||
e->printf = at_print;
|
||||
e->recvclr = recvbuf_clr;
|
||||
e->read = adap->read;
|
||||
e->write = adap->write;
|
||||
e->wait_resp = wait_resp_sync;
|
||||
at->cmd_lock = ril_sem_new(1);
|
||||
at->completed = ril_sem_new(0);
|
||||
ctx = &at->ctx;
|
||||
ctx->printf = at_print;
|
||||
ctx->recvclr = recvbuf_clr;
|
||||
ctx->read = adap->read;
|
||||
ctx->write = adap->write;
|
||||
ctx->wait_resp = wait_resp_sync;
|
||||
|
||||
list_add_tail(&at->node, &atlist);
|
||||
}
|
||||
if (at->adap.debug == NULL)
|
||||
at->adap.debug = nop_dbg;
|
||||
|
||||
/*
|
||||
* @brief 销毁AT
|
||||
*/
|
||||
void at_obj_destroy(at_obj_t *at)
|
||||
{
|
||||
list_del(&at->node);
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief 执行命令
|
||||
* @param[in] fmt - 格式化输出
|
||||
* @param[in] r - 响应参数,如果填NULL, 默认返回OK表示成功,等待3s
|
||||
* @param[in] r - 响应参数,如果填NULL, 默认返回OK表示成功,等待5s
|
||||
* @param[in] args - 如变参数列表
|
||||
*/
|
||||
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};
|
||||
at_respond_t default_resp = {"OK", defbuf, sizeof(defbuf), 5000};
|
||||
if (r == NULL) {
|
||||
r = &default_resp; //默认响应
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
@ -171,14 +183,17 @@ at_return at_do_work(at_obj_t *at, at_work work, void *params)
|
||||
if (!at_sem_wait(at->cmd_lock, 150 * 1000)) {
|
||||
return AT_RET_TIMEOUT;
|
||||
}
|
||||
while (at->urc_cnt) {
|
||||
at->busy = true;
|
||||
while (at->urc_cnt) { //等待URC处理完成
|
||||
at_delay(1);
|
||||
}
|
||||
at->env.params = params;
|
||||
at->ctx.params = params;
|
||||
at->dowork = true;
|
||||
ret = work(&at->env);
|
||||
at->rcv_cnt = 0;
|
||||
ret = work(&at->ctx);
|
||||
at->dowork = false;
|
||||
at_sem_post(at->cmd_lock);
|
||||
at->busy = false;
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -210,61 +225,86 @@ int at_split_respond_lines(char *recvbuf, char *lines[], int count, char separat
|
||||
/*
|
||||
* @brief urc 处理总入口
|
||||
* @param[in] urcline - URC行
|
||||
* @return none
|
||||
* @return true - 正常识别并处理, false - 未识别URC
|
||||
*/
|
||||
static void urc_handler_entry(at_obj_t *at, char *urcline, unsigned int size)
|
||||
static bool urc_handler_entry(at_obj_t *at, char *urcline, unsigned int size)
|
||||
{
|
||||
int i, n;
|
||||
utc_item_t *tbl = at->adap.utc_tbl;
|
||||
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++) {
|
||||
n = strlen(tbl->prefix);
|
||||
if (n > 0 && strncmp(urcline, tbl->prefix, n) == 0) {
|
||||
tbl->handler(urcline, size);
|
||||
if (strstr(urcline, tbl->prefix)) { /* 匹配前缀*/
|
||||
|
||||
if (tbl->end_mark) { /* 匹配结束标记*/
|
||||
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);
|
||||
return;
|
||||
|
||||
tbl->handler(&context); /* 递交到上层处理 */
|
||||
return true;
|
||||
}
|
||||
tbl++;
|
||||
}
|
||||
|
||||
if (size >= 2 && !at->wait) //自动输出
|
||||
at->adap.debug("%s\r\n", urcline);
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief urc 接收处理
|
||||
* @param[in] buf - 接收缓存
|
||||
* @param[in] ch - 接收字符
|
||||
* @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->adap.urc_buf;
|
||||
urc_size = at->adap.urc_bufsize;
|
||||
if (at->urc_cnt > 0 && size == 0) {
|
||||
if (AT_IS_TIMEOUT(at->urc_timer, 100)) { //100ms超时
|
||||
register char *urc_buf;
|
||||
int ch;
|
||||
urc_buf = at->adap.urc_buf;
|
||||
|
||||
//接收超时处理,默认MAX_URC_RECV_TIMEOUT
|
||||
if (at->urc_cnt > 0 && AT_IS_TIMEOUT(at->urc_timer, MAX_URC_RECV_TIMEOUT)) {
|
||||
urc_buf[at->urc_cnt] = '\0';
|
||||
at->urc_cnt = 0;
|
||||
at->adap.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') { //收到1行
|
||||
at->urc_timer = at_get_ms();
|
||||
ch = *buf++;
|
||||
urc_buf[at->urc_cnt++] = ch;
|
||||
|
||||
if (strchr(SPEC_URC_END_MARKS, ch) || ch == '\0') { //结束标记
|
||||
urc_buf[at->urc_cnt] = '\0';
|
||||
if (at->urc_cnt > 2)
|
||||
urc_handler_entry(at, urc_buf, at->urc_cnt);
|
||||
|
||||
if (ch == '\r' || ch == '\n'|| ch == '\0') { //检测到1行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); //未识别到的URC
|
||||
}
|
||||
at->urc_cnt = 0;
|
||||
} else {
|
||||
urc_buf[at->urc_cnt++] = c;
|
||||
if (at->urc_cnt >= urc_size) //溢出处理
|
||||
} else if (urc_handler_entry(at, urc_buf, at->urc_cnt)) {
|
||||
at->urc_cnt = 0;
|
||||
}
|
||||
} else if (at->urc_cnt >= at->adap.urc_bufsize) //溢出处理
|
||||
at->urc_cnt = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief 命令响应通知
|
||||
* @return none
|
||||
*/
|
||||
static void resp_notification(at_obj_t *at, at_return ret)
|
||||
{
|
||||
at->ret = ret;
|
||||
at_sem_post(at->completed);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -279,9 +319,10 @@ static void resp_recv_process(at_obj_t *at, const char *buf, unsigned int size)
|
||||
unsigned short rcv_size;
|
||||
at_respond_t *resp = at->resp;
|
||||
|
||||
if (resp == NULL || size == 0)
|
||||
if (resp == NULL) //无命令请求
|
||||
return;
|
||||
|
||||
if (size) {
|
||||
rcv_buf = (char *)resp->recvbuf;
|
||||
rcv_size = resp->bufsize;
|
||||
|
||||
@ -294,21 +335,18 @@ static void resp_recv_process(at_obj_t *at, const char *buf, unsigned int size)
|
||||
at->rcv_cnt += size;
|
||||
rcv_buf[at->rcv_cnt] = '\0';
|
||||
|
||||
|
||||
if (!at->wait)
|
||||
return;
|
||||
if (strstr(rcv_buf, resp->matcher)) { //接收匹配
|
||||
at->ret = AT_RET_OK;
|
||||
resp_notification(at, 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) //强制终止
|
||||
at->ret = AT_RET_ABORT;
|
||||
else
|
||||
return;
|
||||
resp_notification(at, AT_RET_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
if (AT_IS_TIMEOUT(at->resp_timer, resp->timeout)) //接收超时
|
||||
resp_notification(at, AT_RET_TIMEOUT);
|
||||
else if (at->suspend) //强制终止
|
||||
resp_notification(at, AT_RET_ABORT);
|
||||
|
||||
at_sem_post(at->completed);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -317,7 +355,7 @@ static void resp_recv_process(at_obj_t *at, const char *buf, unsigned int size)
|
||||
*/
|
||||
bool at_obj_busy(at_obj_t *at)
|
||||
{
|
||||
return at->wait == 0 && AT_IS_TIMEOUT(at->urc_timer, 2000);
|
||||
return !at->busy && AT_IS_TIMEOUT(at->urc_timer, 2000);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -339,28 +377,18 @@ void at_resume(at_obj_t *at)
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief AT轮询线程
|
||||
* @brief AT处理
|
||||
* @return none
|
||||
*/
|
||||
void at_thread(void)
|
||||
void at_process(at_obj_t *at)
|
||||
{
|
||||
at_obj_t *at;
|
||||
struct list_head *list ,*n = NULL;
|
||||
int len;
|
||||
char buf[32];
|
||||
while (1) {
|
||||
/*遍历所有at_obj结点*/
|
||||
list_for_each_safe(list, n, &atlist) {
|
||||
at = list_entry(list, at_obj_t, node);
|
||||
if (!at->dowork) {
|
||||
//#warning "读取待优化(readline) ..."
|
||||
len = at->adap.read(buf, sizeof(buf));
|
||||
urc_recv_process(at, (char *)buf, len);
|
||||
if (len > 0) {
|
||||
resp_recv_process(at, buf, len);
|
||||
}
|
||||
}
|
||||
}
|
||||
at_delay(1);
|
||||
}
|
||||
char c;
|
||||
unsigned int len;
|
||||
if (at->dowork) /* 自定义命令处理 */
|
||||
return;
|
||||
do {
|
||||
len = at->adap.read(&c, 1);
|
||||
urc_recv_process(at, &c,len);
|
||||
resp_recv_process(at, &c, len);
|
||||
} while (len);
|
||||
}
|
||||
|
127
at.h
127
at.h
@ -8,37 +8,28 @@
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2020-01-02 Morro Initial version.
|
||||
* 2021-02-01 Morro 支持URC回调中接收数据.
|
||||
* 2021-02-05 Morro 1.修改struct at_obj,去除链表管理机制
|
||||
* 2.删除 at_obj_destroy接口
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef _AT_H_
|
||||
#define _AT_H_
|
||||
|
||||
#include "at_util.h"
|
||||
#include "list.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
/* 单行最大命令长度 */
|
||||
#define MAX_AT_CMD_LEN 128
|
||||
|
||||
/* 单行urc接收超时时间*/
|
||||
#define MAX_URC_RECV_TIMEOUT 300
|
||||
|
||||
/* 指定的URC 结束标记列表 */
|
||||
#define SPEC_URC_END_MARKS ",\r\n"
|
||||
|
||||
struct at_obj; /* AT对象*/
|
||||
|
||||
/*urc处理项 -----------------------------------------------------------------*/
|
||||
typedef struct {
|
||||
const char *prefix; //URC前缀
|
||||
void (*handler)(char *recvbuf, int size);
|
||||
}utc_item_t;
|
||||
|
||||
/*AT接口适配器 ---------------------------------------------------------------*/
|
||||
typedef struct {
|
||||
/*数据读写接口 -----------------------------------------------------------*/
|
||||
unsigned int (*read)(void *buf, unsigned int len);
|
||||
unsigned int (*write)(const void *buf, unsigned int len);
|
||||
void (*debug)(const char *fmt, ...);
|
||||
utc_item_t *utc_tbl; /* utc 表*/
|
||||
char *urc_buf; /* urc接收缓冲区*/
|
||||
unsigned short urc_tbl_count; /* urc表项个数*/
|
||||
unsigned short urc_bufsize; /* urc缓冲区大小*/
|
||||
}at_adapter_t;
|
||||
|
||||
/*AT命令响应码 ---------------------------------------------------------------*/
|
||||
typedef enum {
|
||||
AT_RET_OK = 0, /* 执行成功*/
|
||||
@ -47,45 +38,102 @@ typedef enum {
|
||||
AT_RET_ABORT, /* 未知错误*/
|
||||
}at_return;
|
||||
|
||||
/**
|
||||
* @brief URC 上下文(Context) 定义
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* @brief 数据读取接口
|
||||
* @params buf - 缓冲区
|
||||
* @params len - 缓冲区大小
|
||||
*/
|
||||
unsigned int (*read)(void *buf, unsigned int len);
|
||||
char *buf; /* 数据缓冲区 */
|
||||
int bufsize; /* 缓冲区大小 */
|
||||
int recvlen; /* 已接收数据长度*/
|
||||
} at_urc_ctx_t;
|
||||
|
||||
/*(Unsolicited Result Codes (URCs))处理项 ------------------------------------*/
|
||||
typedef struct {
|
||||
/**
|
||||
* @brief urc 前缀(如"+CSQ: ")
|
||||
*/
|
||||
const char *prefix;
|
||||
/**
|
||||
* @brief urc 指定结束字符标记(参考DEF_URC_END_MARKS列表,如果不指定则默认"\n")
|
||||
* @note
|
||||
*/
|
||||
const char *end_mark;
|
||||
/**
|
||||
* @brief urc处理程序
|
||||
* @params ctx - URC 上下文
|
||||
*/
|
||||
void (*handler)(at_urc_ctx_t *ctx);
|
||||
}utc_item_t;
|
||||
|
||||
/**AT接口适配器 --------------------------------------------------------------*/
|
||||
typedef struct {
|
||||
//数据写操作
|
||||
unsigned int (*write)(const void *buf, unsigned int len);
|
||||
//数据读操作
|
||||
unsigned int (*read)(void *buf, unsigned int len);
|
||||
//调试打印输出,如果不需要则填NULL
|
||||
void (*debug)(const char *fmt, ...);
|
||||
//utc 处理函数表,如果不需要则填NULL
|
||||
utc_item_t *utc_tbl;
|
||||
//urc接收缓冲区,如果不需要则填NULL
|
||||
char *urc_buf;
|
||||
//urc表项个数,如果不需要则填0
|
||||
unsigned short urc_tbl_count;
|
||||
//urc缓冲区大小,如果不需要则填0
|
||||
unsigned short urc_bufsize;
|
||||
}at_adapter_t;
|
||||
|
||||
/*AT响应参数 -----------------------------------------------------------------*/
|
||||
typedef struct {
|
||||
const char *matcher; /* 接收匹配串 */
|
||||
char *recvbuf; /* 接收缓冲区 */
|
||||
unsigned short bufsize; /*最大接收长度*/
|
||||
unsigned short bufsize; /* 缓冲区长度 */
|
||||
unsigned int timeout; /* 最大超时时间 */
|
||||
}at_respond_t;
|
||||
|
||||
/*AT作业 ---------------------------------------------------------------------*/
|
||||
typedef struct at_work_env {
|
||||
struct at_obj *at;
|
||||
/** work context ------------------------------------------------------------*/
|
||||
/**
|
||||
* @brief AT作业上下文(Work Context) 定义
|
||||
*/
|
||||
typedef struct at_work_ctx {
|
||||
//作业参数,由at_do_work接口传入
|
||||
void *params;
|
||||
unsigned int (*write)(const void *buf, unsigned int len);
|
||||
unsigned int (*read)(void *buf, unsigned int len);
|
||||
|
||||
void (*printf)(struct at_obj *at, const char *frm, ...);
|
||||
at_return (*wait_resp)(struct at_obj *at, const char *resp, unsigned int timeout);
|
||||
void (*recvclr)(struct at_obj *at); /*清空接收缓冲区*/
|
||||
}at_work_env_t;
|
||||
//打印输出
|
||||
void (*printf)(struct at_work_ctx *self, const char *fmt, ...);
|
||||
//响应等待
|
||||
at_return (*wait_resp)(struct at_work_ctx *self, const char *prefix,
|
||||
unsigned int timeout);
|
||||
//清除接收缓存
|
||||
void (*recvclr)(struct at_work_ctx *self);
|
||||
}at_work_ctx_t;
|
||||
|
||||
/*AT对象 ---------------------------------------------------------------------*/
|
||||
typedef struct at_obj {
|
||||
struct list_head node;
|
||||
at_adapter_t adap;
|
||||
at_work_env_t env;
|
||||
at_adapter_t adap; /* 接口适配器*/
|
||||
at_work_ctx_t ctx; /* work context*/
|
||||
at_sem_t cmd_lock; /* 命令锁*/
|
||||
at_sem_t completed; /*命令处理完成*/
|
||||
at_respond_t *resp;
|
||||
unsigned int resp_timer;
|
||||
unsigned int urc_timer;
|
||||
at_return ret;
|
||||
at_sem_t completed; /* 命令完成信号*/
|
||||
at_respond_t *resp; /* AT应答信息*/
|
||||
unsigned int resp_timer; /* 响应接收定时器*/
|
||||
unsigned int urc_timer; /* URC定时器 */
|
||||
at_return ret; /* 命令执行结果*/
|
||||
//urc接收计数, 命令响应接收计数器
|
||||
unsigned short urc_cnt, rcv_cnt;
|
||||
unsigned char wait : 1;
|
||||
unsigned char busy : 1;
|
||||
unsigned char suspend: 1;
|
||||
unsigned char dowork : 1;
|
||||
}at_obj_t;
|
||||
|
||||
typedef at_return (*at_work)(at_work_env_t *);
|
||||
typedef at_return (*at_work)(at_work_ctx_t *);
|
||||
|
||||
void at_obj_create(at_obj_t *at, const at_adapter_t *adap); /* AT初始化*/
|
||||
|
||||
@ -99,10 +147,11 @@ void at_resume(at_obj_t *at); /*
|
||||
|
||||
at_return at_do_cmd(at_obj_t *at, at_respond_t *r, const char *cmd);
|
||||
|
||||
//响应行分割处理
|
||||
int at_split_respond_lines(char *recvbuf, char *lines[], int count, char separator);
|
||||
|
||||
at_return at_do_work(at_obj_t *at, at_work work, void *params);/*执行AT作业*/
|
||||
at_return at_do_work(at_obj_t *at, at_work work, void *params);/* 自定义AT作业*/
|
||||
|
||||
void at_thread(void); /*AT线程*/
|
||||
void at_process(at_obj_t *at); /* AT接收处理*/
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user