mirror of
https://gitee.com/moluo-tech/AT-Command
synced 2025-08-12 05:02:52 +00:00
1、解决数据类型不匹配导致编译错误问题。
2、更新使用描述。
This commit is contained in:
parent
c6c8b8561d
commit
e7c891ba14
63
README.md
63
README.md
@ -4,9 +4,13 @@
|
||||
一种AT命令通信解析模块,支持裸机(at_chat)和OS版本(at)。适用于modem、WIFI模块、蓝牙通信。
|
||||
|
||||
#### 软件架构
|
||||
软件架构说明
|
||||
at_chat.c at_chat.h用于无OS版本,使用链式队列及异步回调方式处理AT命令收发,支持URC处理。
|
||||
at_core.c at_core.h用于OS版本
|
||||
|
||||
- at_chat.c at_chat.h list.h
|
||||
|
||||
用于无OS版本,使用链式队列及异步回调方式处理AT命令收发,支持URC处理。
|
||||
- at.c at.h at_util.h
|
||||
|
||||
用于OS版本, 使用前需要根据at_util.h规定的操作系统相关的接口进行移植,如提供信号量操作、任务延时等操作。
|
||||
#### 使用说明
|
||||
|
||||
##### at_chat 模块(无OS)
|
||||
@ -14,22 +18,28 @@ at_core.c at_core.h用于OS版本
|
||||
|
||||
```
|
||||
|
||||
static at_core_t at; //定义AT管理器
|
||||
static at_obj_t at; //定义AT控制器
|
||||
|
||||
const at_core_conf_t conf = { //AT管理器配置参数
|
||||
|
||||
const at_adapter_t adap = { //AT适配器接口
|
||||
//适配GPRS模块的串口读写接口
|
||||
.write = uart_write,
|
||||
.read = uart_read
|
||||
...
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
|
||||
3. 初始化AT控制器
|
||||
|
||||
```
|
||||
|
||||
at_obj_init(&at, &adap);
|
||||
|
||||
```
|
||||
|
||||
|
||||
3. 初始化AT管理器
|
||||
|
||||
```
|
||||
at_core_init(&at, &conf);
|
||||
```
|
||||
|
||||
|
||||
4. 将AT管理器放入任务中轮询
|
||||
4. 将AT控制器放入任务中轮询
|
||||
|
||||
```
|
||||
void main(void)
|
||||
@ -49,6 +59,9 @@ void main(void)
|
||||
|
||||
|
||||
```
|
||||
/**
|
||||
* @brief AT执行回调处理程序
|
||||
*/
|
||||
static void read_csq_callback(at_response_t *r)
|
||||
{
|
||||
/*...*/
|
||||
@ -61,15 +74,15 @@ at_send_singlline(&at, read_csq_callback, "AT+CSQ");
|
||||
|
||||
```
|
||||
|
||||
static at_obj_t at; //定义AT管理器
|
||||
static at_obj_t at; //定义AT控制器
|
||||
|
||||
char urc_buf[128]; //URC主动上报缓冲区
|
||||
static char urc_buf[128]; //URC主动上报缓冲区
|
||||
|
||||
utc_item_t utc_tbl[] = { //定义URC表
|
||||
"+CSQ: ", csq_updated_handler
|
||||
}
|
||||
|
||||
const at_conf_t conf = { //AT管理器配置参数
|
||||
const at_adapter_t adap = { //AT适配器接口
|
||||
.urc_buf = urc_buf,
|
||||
.urc_bufsize = sizeof(urc_buf),
|
||||
.utc_tbl = utc_tbl,
|
||||
@ -79,16 +92,17 @@ const at_conf_t conf = { //AT管理器配置参数
|
||||
.write = uart_write,
|
||||
.read = uart_read
|
||||
};
|
||||
```
|
||||
|
||||
3. 初始化AT管理器并创建AT线程
|
||||
|
||||
```
|
||||
|
||||
3. 初始化AT控制器并创建AT线程
|
||||
|
||||
```
|
||||
|
||||
void at_thread(void)
|
||||
{
|
||||
at_obj_create(&at, &conf);
|
||||
while (1) {
|
||||
/*do something ...*/
|
||||
at_obj_create(&at, &adap);
|
||||
while (1) {
|
||||
at_thread(&at);
|
||||
}
|
||||
}
|
||||
@ -102,6 +116,7 @@ void at_thread(void)
|
||||
|
||||
<= +CSQ: 24, 0
|
||||
<= OK
|
||||
|
||||
```
|
||||
/*
|
||||
* @brief 获取csq值
|
||||
@ -115,7 +130,7 @@ bool read_csq_value(at_obj_t *at, int *rssi, int *error_rate)
|
||||
//
|
||||
if (at_do_cmd(at, &r, "AT+CSQ") != AT_RET_OK)
|
||||
return false;
|
||||
//解析响应响应
|
||||
//提取出响应数据
|
||||
return (sscanf(recv, "%*[^+]+CSQ: %d,%d", rssi, error_rate) == 2);
|
||||
|
||||
}
|
||||
|
73
at.c
73
at.c
@ -26,7 +26,7 @@ static LIST_HEAD(atlist); /*
|
||||
static void put_string(at_obj_t *at, const char *s)
|
||||
{
|
||||
while (*s != '\0')
|
||||
at->cfg.write(s++, 1);
|
||||
at->adap.write(s++, 1);
|
||||
}
|
||||
|
||||
|
||||
@ -37,7 +37,7 @@ 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);
|
||||
at->adap.debug("->\r\n%s\r\n", s);
|
||||
}
|
||||
|
||||
//打印输出
|
||||
@ -67,8 +67,8 @@ static at_return wait_resp(at_obj_t *at, at_respond_t *r)
|
||||
at->resp_timer = at_get_ms();
|
||||
recvbuf_clr(at); //清空接收缓存
|
||||
at->wait = 1;
|
||||
at_sem_wait(&at->completed, r->timeout);
|
||||
at->cfg.debug("<-\r\n%s\r\n", r->recvbuf);
|
||||
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;
|
||||
@ -87,7 +87,7 @@ at_return wait_resp_sync(struct at_obj *at, const char *resp,
|
||||
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);
|
||||
len = at->adap.read(buf, sizeof(buf) - cnt);
|
||||
cnt += len;
|
||||
buf[cnt] = '\0';
|
||||
if (strstr(buf, resp)) {
|
||||
@ -99,7 +99,7 @@ at_return wait_resp_sync(struct at_obj *at, const char *resp,
|
||||
}
|
||||
at_delay(10);
|
||||
}
|
||||
at->cfg.debug("%s", buf);
|
||||
at->adap.debug("%s\r\n", buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -107,24 +107,23 @@ at_return wait_resp_sync(struct at_obj *at, const char *resp,
|
||||
/*
|
||||
* @brief AT内核配置
|
||||
*/
|
||||
void at_obj_create(at_obj_t *at, const at_conf_t cfg)
|
||||
void at_obj_create(at_obj_t *at, const at_adapter_t *adap)
|
||||
{
|
||||
at_work_env_t *e;
|
||||
at->cfg = cfg;
|
||||
at->adap = *adap;
|
||||
at->rcv_cnt = 0;
|
||||
|
||||
at_sem_init(&at->cmd_lock, 1);
|
||||
at_sem_init(&at->completed, 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 = cfg.read;
|
||||
e->write = cfg.write;
|
||||
e->read = adap->read;
|
||||
e->write = adap->write;
|
||||
e->wait_resp = wait_resp_sync;
|
||||
|
||||
list_add_tail(&at->node, &atlist);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
@ -149,7 +148,7 @@ at_return at_do_cmd(at_obj_t *at, at_respond_t *r, const char *cmd)
|
||||
if (r == NULL) {
|
||||
r = &default_resp; //默认响应
|
||||
}
|
||||
if (!at_sem_wait(&at->cmd_lock, r->timeout)) {
|
||||
if (!at_sem_wait(at->cmd_lock, r->timeout)) {
|
||||
return AT_RET_TIMEOUT;
|
||||
}
|
||||
while (at->urc_cnt) {
|
||||
@ -157,7 +156,7 @@ at_return at_do_cmd(at_obj_t *at, at_respond_t *r, const char *cmd)
|
||||
}
|
||||
put_line(at, cmd);
|
||||
ret = wait_resp(at, r);
|
||||
at_sem_post(&at->cmd_lock);
|
||||
at_sem_post(at->cmd_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -166,27 +165,31 @@ at_return at_do_cmd(at_obj_t *at, at_respond_t *r, const char *cmd)
|
||||
* @param[in] urc
|
||||
* @return none
|
||||
*/
|
||||
int at_do_work(at_obj_t *at, at_work work, void *params)
|
||||
at_return 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_return ret;
|
||||
if (!at_sem_wait(at->cmd_lock, 150 * 1000)) {
|
||||
return AT_RET_TIMEOUT;
|
||||
}
|
||||
while (at->urc_cnt) {
|
||||
at_delay(1);
|
||||
}
|
||||
at->env.params = params;
|
||||
at->dowork = true;
|
||||
ret = work(&at->env);
|
||||
at->dowork = false;
|
||||
at_sem_post(&at->cmd_lock);
|
||||
at_sem_post(at->cmd_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief 分割响应行
|
||||
* @param[in] recvbuf - 接收缓冲区
|
||||
* @param[out] lines - 响应行数组
|
||||
* @param[in] recvbuf - 接收缓冲区
|
||||
* @param[out] lines - 响应行数组
|
||||
* @param[in] separator- 分割符(, \n)
|
||||
* @return 行数
|
||||
*/
|
||||
int at_split_respond_lines(char *recvbuf, char *lines[], int count)
|
||||
int at_split_respond_lines(char *recvbuf, char *lines[], int count, char separator)
|
||||
{
|
||||
char *s = recvbuf;
|
||||
size_t i = 0;
|
||||
@ -212,20 +215,20 @@ int at_split_respond_lines(char *recvbuf, char *lines[], int count)
|
||||
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;
|
||||
utc_item_t *tbl = at->adap.utc_tbl;
|
||||
|
||||
for (i = 0; i < at->cfg.urc_tbl_count; i++){
|
||||
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);
|
||||
at->cfg.debug("<=\r\n%s\r\n", urcline);
|
||||
at->adap.debug("<=\r\n%s\r\n", urcline);
|
||||
return;
|
||||
}
|
||||
tbl++;
|
||||
}
|
||||
|
||||
if (size >= 2 && !at->wait) //自动输出
|
||||
at->cfg.debug("%s\r\n", urcline);
|
||||
at->adap.debug("%s\r\n", urcline);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -238,13 +241,13 @@ 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;
|
||||
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超时
|
||||
urc_buf[at->urc_cnt] = '\0';
|
||||
at->urc_cnt = 0;
|
||||
at->cfg.debug("urc recv timeout=>%s\r\n", urc_buf);
|
||||
at->adap.debug("urc recv timeout=>%s\r\n", urc_buf);
|
||||
}
|
||||
} else {
|
||||
at->urc_timer = at_get_ms();
|
||||
@ -284,7 +287,7 @@ static void resp_recv_process(at_obj_t *at, const char *buf, unsigned int size)
|
||||
|
||||
if (at->rcv_cnt + size >= rcv_size) { //接收溢出
|
||||
at->rcv_cnt = 0;
|
||||
at->cfg.debug("Receive overflow:%s", rcv_buf);
|
||||
at->adap.debug("Receive overflow:%s", rcv_buf);
|
||||
}
|
||||
/*将接收到的数据放至rcv_buf中 ---------------------------------------------*/
|
||||
memcpy(rcv_buf + at->rcv_cnt, buf, size);
|
||||
@ -305,7 +308,7 @@ static void resp_recv_process(at_obj_t *at, const char *buf, unsigned int size)
|
||||
else
|
||||
return;
|
||||
|
||||
at_sem_post(&at->completed);
|
||||
at_sem_post(at->completed);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -350,8 +353,8 @@ void at_thread(void)
|
||||
list_for_each_safe(list, n, &atlist) {
|
||||
at = list_entry(list, at_obj_t, node);
|
||||
if (!at->dowork) {
|
||||
#warning "读取优化(readline) ..."
|
||||
len = at->cfg.read(buf, sizeof(buf));
|
||||
//#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);
|
||||
|
32
at.h
32
at.h
@ -9,7 +9,7 @@
|
||||
* Date Author Notes
|
||||
* 2020-01-02 Morro Initial version.
|
||||
******************************************************************************/
|
||||
|
||||
|
||||
#ifndef _AT_H_
|
||||
#define _AT_H_
|
||||
|
||||
@ -17,7 +17,7 @@
|
||||
#include "list.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
#define MAX_AT_CMD_LEN 64
|
||||
#define MAX_AT_CMD_LEN 128
|
||||
|
||||
struct at_obj; /*AT对象*/
|
||||
|
||||
@ -27,17 +27,17 @@ typedef struct {
|
||||
void (*handler)(char *recvbuf, int size);
|
||||
}utc_item_t;
|
||||
|
||||
/*AT配置项 -------------------------------------------------------------------*/
|
||||
/*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;
|
||||
unsigned short urc_bufsize; /*urc缓冲区大小*/
|
||||
}at_conf_t;
|
||||
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 {
|
||||
@ -52,11 +52,11 @@ typedef struct {
|
||||
const char *matcher; /*接收匹配串*/
|
||||
char *recvbuf; /*接收缓冲区*/
|
||||
unsigned short bufsize; /*最大接收长度*/
|
||||
unsigned int timeout; /*最大超时时间 */
|
||||
unsigned int timeout; /*最大超时时间 */
|
||||
}at_respond_t;
|
||||
|
||||
/*AT作业 ---------------------------------------------------------------------*/
|
||||
typedef struct at_work_env{
|
||||
typedef struct at_work_env {
|
||||
struct at_obj *at;
|
||||
void *params;
|
||||
unsigned int (*write)(const void *buf, unsigned int len);
|
||||
@ -70,7 +70,7 @@ typedef struct at_work_env{
|
||||
/*AT对象 ---------------------------------------------------------------------*/
|
||||
typedef struct at_obj {
|
||||
struct list_head node;
|
||||
at_conf_t cfg;
|
||||
at_adapter_t adap;
|
||||
at_work_env_t env;
|
||||
at_sem_t cmd_lock; /*命令锁*/
|
||||
at_sem_t completed; /*命令处理完成*/
|
||||
@ -85,9 +85,9 @@ typedef struct at_obj {
|
||||
unsigned char dowork : 1;
|
||||
}at_obj_t;
|
||||
|
||||
typedef int (*at_work)(at_work_env_t *);
|
||||
typedef at_return (*at_work)(at_work_env_t *);
|
||||
|
||||
void at_obj_create(at_obj_t *at, const at_conf_t cfg); /*AT初始化*/
|
||||
void at_obj_create(at_obj_t *at, const at_adapter_t *adap); /*AT初始化*/
|
||||
|
||||
void at_obj_destroy(at_obj_t *at);
|
||||
|
||||
@ -99,9 +99,9 @@ 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);
|
||||
int at_split_respond_lines(char *recvbuf, char *lines[], int count, char separator);
|
||||
|
||||
int 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线程*/
|
||||
|
||||
|
155
at_chat.c
155
at_chat.c
@ -18,34 +18,34 @@
|
||||
//超时判断
|
||||
#define AT_IS_TIMEOUT(start, time) (at_get_ms() - (start) > (time))
|
||||
|
||||
/*ATCOMM work type -----------------------------------------------------------*/
|
||||
#define AT_TYPE_WORK 0 /*工作 --------------*/
|
||||
#define AT_TYPE_CMD 1 /*标准命令 ----------*/
|
||||
#define AT_TYPE_MULTILINE 3 /*多行命令 ----------*/
|
||||
#define AT_TYPE_SINGLLINE 4 /*单行命令 ----------*/
|
||||
/**AT作业类型(实际是4种类型的状态机轮询程序) -----------------------------------*/
|
||||
#define AT_TYPE_WORK 0 /* 普通作业 ----------*/
|
||||
#define AT_TYPE_CMD 1 /* 标准命令 ----------*/
|
||||
#define AT_TYPE_MULTILINE 3 /* 多行命令 ----------*/
|
||||
#define AT_TYPE_SINGLLINE 4 /* 单行命令 ----------*/
|
||||
|
||||
typedef int (*base_work)(at_obj_t *at, ...);
|
||||
|
||||
static void at_send_line(at_obj_t *at, const char *fmt, va_list args);
|
||||
|
||||
static const inline at_core_conf_t *__get_adapter(at_obj_t *at)
|
||||
static const inline at_adapter_t *__get_adapter(at_obj_t *at)
|
||||
{
|
||||
return &at->cfg;
|
||||
return &at->adap;
|
||||
}
|
||||
|
||||
static bool is_timeout(at_obj_t *at, unsigned int ms)
|
||||
{
|
||||
return AT_IS_TIMEOUT(at->resp_timer, ms);
|
||||
}
|
||||
/*
|
||||
/**
|
||||
* @brief 发送数据
|
||||
*/
|
||||
static void send_data(at_obj_t *at, const void *buf, unsigned int len)
|
||||
{
|
||||
at->cfg.write(buf, len);
|
||||
at->adap.write(buf, len);
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* @brief 格式化打印
|
||||
*/
|
||||
static void print(at_obj_t *at, const char *cmd, ...)
|
||||
@ -55,49 +55,52 @@ static void print(at_obj_t *at, const char *cmd, ...)
|
||||
at_send_line(at, cmd, args);
|
||||
va_end(args);
|
||||
}
|
||||
/*
|
||||
/**
|
||||
* @brief 获取当前数据接收长度
|
||||
*/
|
||||
static unsigned int get_recv_count(at_obj_t *at)
|
||||
{
|
||||
return at->rcv_cnt;
|
||||
return at->recv_cnt;
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* @brief 获取数据缓冲区
|
||||
*/
|
||||
static char *get_recv_buf(at_obj_t *at)
|
||||
{
|
||||
return (char *)at->cfg.rcv_buf;
|
||||
return (char *)at->adap.recv_buf;
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* @brief 清除数据缓冲区
|
||||
*/
|
||||
static void recv_buf_clear(at_obj_t *at)
|
||||
{
|
||||
at->rcv_cnt = 0;
|
||||
at->recv_cnt = 0;
|
||||
}
|
||||
|
||||
/*前向查找字串*/
|
||||
/**前向查找字串*/
|
||||
static char *search_string(at_obj_t *at, const char *str)
|
||||
{
|
||||
return strstr(get_recv_buf(at), str);
|
||||
}
|
||||
|
||||
/*前向查找字串*/
|
||||
/**前向查找字串*/
|
||||
static bool at_isabort(at_obj_t *at)
|
||||
{
|
||||
return at->cursor ? at->cursor->abort : 1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
/**
|
||||
* @brief AT执行回调
|
||||
*/
|
||||
static void do_at_callbatk(at_obj_t *a, at_item_t *i, at_callbatk_t cb, at_return ret)
|
||||
{
|
||||
at_response_t r;
|
||||
if ((ret == AT_RET_ERROR || ret == AT_RET_TIMEOUT) && a->adap.error != NULL)
|
||||
a->adap.error();
|
||||
|
||||
if (cb) {
|
||||
r.param = i->param;
|
||||
r.recvbuf = get_recv_buf(a);
|
||||
@ -107,16 +110,16 @@ static void do_at_callbatk(at_obj_t *a, at_item_t *i, at_callbatk_t cb, at_retur
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief AT配置
|
||||
/**
|
||||
* @brief AT控制器初始化
|
||||
* @param[in] cfg - AT响应
|
||||
*/
|
||||
void at_core_init(at_obj_t *at, const at_core_conf_t cfg)
|
||||
void at_core_init(at_obj_t *at, const at_adapter_t *adap)
|
||||
{
|
||||
at_env_t *e;
|
||||
at->cfg = cfg;
|
||||
at->adap = *adap;
|
||||
e = &at->env;
|
||||
at->rcv_cnt = 0;
|
||||
at->recv_cnt = 0;
|
||||
|
||||
e->is_timeout = is_timeout;
|
||||
e->printf = print;
|
||||
@ -126,7 +129,8 @@ void at_core_init(at_obj_t *at, const at_core_conf_t cfg)
|
||||
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;
|
||||
@ -142,8 +146,8 @@ static bool add_work(at_obj_t *at, void *params, void *info, int type)
|
||||
return i != 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief 执行任务
|
||||
/**
|
||||
* @brief 执行作业
|
||||
*/
|
||||
static int do_work_handler(at_obj_t *at)
|
||||
{
|
||||
@ -160,7 +164,7 @@ static int do_cmd_handler(at_obj_t *a)
|
||||
{
|
||||
at_item_t *i = a->cursor;
|
||||
at_env_t *e = &a->env;
|
||||
const at_respond_t *c = (at_respond_t *)i->info;
|
||||
const at_cmd_t *c = (at_cmd_t *)i->info;
|
||||
switch(e->state) {
|
||||
case 0: /*发送状态 ------------------------------------------------------*/
|
||||
c->sender(e);
|
||||
@ -168,7 +172,7 @@ static int do_cmd_handler(at_obj_t *a)
|
||||
e->reset_timer(a);
|
||||
e->recvclr(a);
|
||||
break;
|
||||
case 1: /*接收状态 ------------------------------------------------------*/
|
||||
case 1: /*接收状态 -----------------------------------0-------------------*/
|
||||
if (search_string(a, c->matcher)) {
|
||||
do_at_callbatk(a, i, c->cb, AT_RET_OK);
|
||||
return true;
|
||||
@ -177,19 +181,19 @@ static int do_cmd_handler(at_obj_t *a)
|
||||
do_at_callbatk(a, i, c->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, 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;
|
||||
@ -198,7 +202,7 @@ static int do_cmd_handler(at_obj_t *a)
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* @brief 单行命令
|
||||
* @brief 单行命令处理
|
||||
* @param[in] a - AT管理器
|
||||
* @return 0 - 保持工作,非0 - 结束工作
|
||||
******************************************************************************/
|
||||
@ -216,7 +220,7 @@ static int send_signlline_handler(at_obj_t *a)
|
||||
e->reset_timer(a);
|
||||
e->recvclr(a);
|
||||
break;
|
||||
case 1: /*接收状态 ------------------------------------------------------*/
|
||||
case 1: /*接收状态 -------------------------------------------------------*/
|
||||
if (search_string(a, "OK")) {
|
||||
do_at_callbatk(a, i, cb, AT_RET_OK);
|
||||
return true;
|
||||
@ -225,19 +229,19 @@ static int send_signlline_handler(at_obj_t *a)
|
||||
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:
|
||||
if (e->is_timeout(a, 500))
|
||||
e->state = 0; /*返回初始状态*/
|
||||
e->state = 0; /**返回初始状态*/
|
||||
break;
|
||||
default:
|
||||
e->state = 0;
|
||||
@ -257,12 +261,12 @@ static int send_multiline_handler(at_obj_t *a)
|
||||
at_callbatk_t cb = (at_callbatk_t)i->info;
|
||||
switch(e->state) {
|
||||
case 0:
|
||||
if (cmds[e->i] == NULL) { /*命令执行完毕*/
|
||||
if (cmds[e->i] == NULL) { /**命令执行完毕*/
|
||||
do_at_callbatk(a, i, cb, AT_RET_OK);
|
||||
return true;
|
||||
}
|
||||
e->printf(a, "%s\r\n", cmds[e->i]);
|
||||
e->recvclr(a); /*清除接收*/
|
||||
e->recvclr(a); /**清除接收*/
|
||||
e->reset_timer(a);
|
||||
e->state++;
|
||||
break;
|
||||
@ -276,8 +280,8 @@ static int send_multiline_handler(at_obj_t *a)
|
||||
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;
|
||||
@ -289,7 +293,7 @@ static int send_multiline_handler(at_obj_t *a)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* @brief 发送行
|
||||
* @param[in] fmt - 格式化输出
|
||||
* @param[in] args - 如变参数列表
|
||||
@ -298,14 +302,14 @@ static void at_send_line(at_obj_t *at, const char *fmt, va_list args)
|
||||
{
|
||||
char buf[MAX_AT_CMD_LEN];
|
||||
int len;
|
||||
const at_core_conf_t *adt = __get_adapter(at);
|
||||
const at_adapter_t *adt = __get_adapter(at);
|
||||
len = vsnprintf(buf, sizeof(buf), fmt, args);
|
||||
|
||||
recv_buf_clear(at); //清空接收缓存
|
||||
send_data(at, buf, len);
|
||||
send_data(at, "\r\n", 2);
|
||||
}
|
||||
/*
|
||||
/**
|
||||
* @brief urc 处理总入口
|
||||
* @param[in] urc
|
||||
* @return none
|
||||
@ -313,15 +317,15 @@ static void at_send_line(at_obj_t *at, const char *fmt, va_list args)
|
||||
static void urc_handler_entry(at_obj_t *at, char *urc, unsigned int size)
|
||||
{
|
||||
int i, n;
|
||||
utc_item_t *tbl = at->cfg.utc_tbl;
|
||||
for (i = 0; i < at->cfg.urc_tbl_count; i++){
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* @brief urc 接收处理
|
||||
* @param[in] buf - 数据缓冲区
|
||||
* @return none
|
||||
@ -330,12 +334,12 @@ 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->cfg.urc_buf;
|
||||
urc_size = at->cfg.urc_bufsize;
|
||||
urc_buf = (char *)at->adap.urc_buf;
|
||||
urc_size = at->adap.urc_bufsize;
|
||||
if (size == 0 && at->urc_cnt > 0) {
|
||||
if (AT_IS_TIMEOUT(at->urc_timer, 2000)){
|
||||
urc_handler_entry(at, urc_buf, at->urc_cnt);
|
||||
at->rcv_cnt = 0;
|
||||
at->recv_cnt = 0;
|
||||
}
|
||||
} else {
|
||||
at->urc_timer = at_get_ms();
|
||||
@ -352,29 +356,27 @@ static void urc_recv_process(at_obj_t *at, char *buf, unsigned int size)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* @brief 指令响应接收处理
|
||||
* @param[in] buf -
|
||||
* @return none
|
||||
*/
|
||||
static void resp_recv_process(at_obj_t *at, const char *buf, unsigned int size)
|
||||
{
|
||||
char *rcv_buf;
|
||||
unsigned short rcv_size;
|
||||
char *recv_buf;
|
||||
unsigned short recv_size;
|
||||
|
||||
rcv_buf = (char *)at->cfg.rcv_buf;
|
||||
rcv_size = at->cfg.rcv_bufsize;
|
||||
recv_buf = (char *)at->adap.recv_buf;
|
||||
recv_size = at->adap.recv_bufsize;
|
||||
|
||||
if (at->rcv_cnt + size >= rcv_size) //接收溢出
|
||||
at->rcv_cnt = 0;
|
||||
if (at->recv_cnt + size >= recv_size) //接收溢出处理
|
||||
at->recv_cnt = 0;
|
||||
|
||||
memcpy(rcv_buf + rcv_cnt, buf, size);
|
||||
at->rcv_cnt += size;
|
||||
rcv_buf[at->rcv_cnt] = '\0';
|
||||
|
||||
memcpy(recv_buf + at->recv_cnt, buf, size);
|
||||
at->recv_cnt += size;
|
||||
recv_buf[at->recv_cnt] = '\0';
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* @brief 执行AT作业
|
||||
* @param[in] a - AT管理器
|
||||
* @param[in] work - AT作业入口
|
||||
@ -385,17 +387,17 @@ bool at_do_work(at_obj_t *at, int (*work)(at_env_t *e), void *params)
|
||||
return add_work(at, params, (void *)work, AT_TYPE_WORK);
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* @brief 执行AT指令
|
||||
* @param[in] a - AT管理器
|
||||
* @param[in] cmd - cmd命令
|
||||
*/
|
||||
bool at_do_cmd(at_obj_t *at, void *params, const at_respond_t *cmd)
|
||||
bool at_do_cmd(at_obj_t *at, void *params, const at_cmd_t *cmd)
|
||||
{
|
||||
return add_work(at, params, (void *)cmd, AT_TYPE_CMD);
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* @brief 发送单行AT命令
|
||||
* @param[in] at - AT管理器
|
||||
* @param[in] cb - 执行回调
|
||||
@ -407,7 +409,7 @@ bool at_send_singlline(at_obj_t *at, at_callbatk_t cb, const char *singlline)
|
||||
return add_work(at, (void *)singlline, (void *)cb, AT_TYPE_SINGLLINE);
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* @brief 发送多行AT命令
|
||||
* @param[in] at - AT管理器
|
||||
* @param[in] cb - 执行回调
|
||||
@ -419,7 +421,7 @@ bool at_send_multiline(at_obj_t *at, at_callbatk_t cb, const char **multiline)
|
||||
return add_work(at, multiline, (void *)cb, AT_TYPE_MULTILINE);
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* @brief 强行中止AT作业
|
||||
*/
|
||||
|
||||
@ -428,7 +430,7 @@ void at_item_abort(at_item_t *i)
|
||||
i->abort = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* @brief AT忙判断
|
||||
* @return true - 有AT指令或者任务正在执行中
|
||||
*/
|
||||
@ -437,9 +439,9 @@ bool at_core_busy(at_obj_t *at)
|
||||
return !list_empty(&at->ls_ready);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
/**
|
||||
* @brief AT作业管理
|
||||
******************************************************************************/
|
||||
*/
|
||||
static void at_work_manager(at_obj_t *at)
|
||||
{
|
||||
register at_item_t *cursor = at->cursor;
|
||||
@ -462,14 +464,13 @@ static void at_work_manager(at_obj_t *at)
|
||||
e->reset_timer(at);
|
||||
at->cursor = list_first_entry(&at->ls_ready, at_item_t, node);
|
||||
}
|
||||
/*工作执行完成,则将它放入到空闲工作链 ------------------------------------*/
|
||||
/**工作执行完成,则将它放入到空闲工作链 ------------------------------------*/
|
||||
if (work_handler_table[cursor->type](at) || cursor->abort) {
|
||||
list_move_tail(&at->cursor->node, &at->ls_idle);
|
||||
at->cursor = NULL;
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
/**
|
||||
* @brief AT轮询任务
|
||||
*/
|
||||
void at_poll_task(at_obj_t *at)
|
||||
@ -481,5 +482,3 @@ void at_poll_task(at_obj_t *at)
|
||||
resp_recv_process(at, rbuf, read_size);
|
||||
at_work_manager(at);
|
||||
}
|
||||
|
||||
|
||||
|
77
at_chat.h
77
at_chat.h
@ -27,58 +27,56 @@ typedef struct {
|
||||
void (*handler)(char *recvbuf, int size);
|
||||
}utc_item_t;
|
||||
|
||||
/*AT接口适配器 ---------------------------------------------------------------*/
|
||||
typedef struct {
|
||||
unsigned int (*write)(const void *buf, unsigned int len); /*发送接口*/
|
||||
unsigned int (*read)(void *buf, unsigned int len); /*接收接口*/
|
||||
/*Events -----------------------------------------------------------------*/
|
||||
void (*before_at)(void); /*开始执行AT*/
|
||||
void (*after_at)(void);
|
||||
void (*error)(void);
|
||||
utc_item_t *utc_tbl; /*utc 表*/
|
||||
unsigned char *urc_buf; /*urc接收缓冲区*/
|
||||
unsigned char *rcv_buf;
|
||||
unsigned short urc_tbl_count;
|
||||
unsigned short urc_bufsize; /*urc缓冲区大小*/
|
||||
unsigned short rcv_bufsize; /*接收缓冲区*/
|
||||
}at_obj_conf_t;
|
||||
unsigned int (*write)(const void *buf, unsigned int len); /* 发送接口*/
|
||||
unsigned int (*read)(void *buf, unsigned int len); /* 接收接口*/
|
||||
void (*error)(void); /* AT执行异常事件*/
|
||||
utc_item_t *utc_tbl; /* urc 表*/
|
||||
unsigned char *urc_buf; /* urc接收缓冲区*/
|
||||
unsigned char *recv_buf; /* 数据缓冲区*/
|
||||
unsigned short urc_tbl_count; /* urc表项个数*/
|
||||
unsigned short urc_bufsize; /* urc缓冲区大小*/
|
||||
unsigned short recv_bufsize; /* 接收缓冲区大小*/
|
||||
}at_adapter_t;
|
||||
|
||||
/*AT作业运行环境*/
|
||||
typedef struct {
|
||||
int i,j,state;
|
||||
int i,j,state;
|
||||
void *params;
|
||||
void (*reset_timer)(struct at_obj *at);
|
||||
void (*reset_timer)(struct at_obj *at);
|
||||
bool (*is_timeout)(struct at_obj *at, unsigned int ms); /*时间跨度判断*/
|
||||
void (*printf)(struct at_obj *at, const char *fmt, ...);
|
||||
char * (*find)(struct at_obj *at, const char *expect);
|
||||
char * (*recvbuf)(struct at_obj *at); /*指向接收缓冲区*/
|
||||
unsigned int(*recvlen)(struct at_obj *at); /*缓冲区总长度*/
|
||||
void (*recvclr)(struct at_obj *at); /*清空接收缓冲区*/
|
||||
bool (*abort)(struct at_obj *at); /*终止执行*/
|
||||
char * (*recvbuf)(struct at_obj *at); /* 指向接收缓冲区*/
|
||||
unsigned int(*recvlen)(struct at_obj *at); /* 缓冲区总长度*/
|
||||
void (*recvclr)(struct at_obj *at); /* 清空接收缓冲区*/
|
||||
bool (*abort)(struct at_obj *at); /* 终止执行*/
|
||||
}at_env_t;
|
||||
|
||||
/*AT命令响应码*/
|
||||
typedef enum {
|
||||
AT_RET_OK = 0, /*执行成功*/
|
||||
AT_RET_ERROR, /*执行错误*/
|
||||
AT_RET_TIMEOUT, /*响应超时*/
|
||||
AT_RET_ABORT, /*强行中止*/
|
||||
AT_RET_OK = 0, /* 执行成功*/
|
||||
AT_RET_ERROR, /* 执行错误*/
|
||||
AT_RET_TIMEOUT, /* 响应超时*/
|
||||
AT_RET_ABORT, /* 强行中止*/
|
||||
}at_return;
|
||||
|
||||
/*AT响应 */
|
||||
typedef struct {
|
||||
void *param;
|
||||
char *recvbuf;
|
||||
unsigned short recvcnt;
|
||||
at_return ret;
|
||||
void *param;
|
||||
char *recvbuf; /* 接收缓冲区*/
|
||||
unsigned short recvcnt; /* 接收数据长度*/
|
||||
at_return ret; /* AT执行结果*/
|
||||
}at_response_t;
|
||||
|
||||
typedef void (*at_callbatk_t)(at_response_t *r);
|
||||
|
||||
/*AT状态 */
|
||||
typedef void (*at_callbatk_t)(at_response_t *r); /* AT 执行回调*/
|
||||
|
||||
/*AT状态 (当前版本未用) ------------------------------------------------------*/
|
||||
typedef enum {
|
||||
AT_STATE_IDLE, /*空闲状态*/
|
||||
AT_STATE_WAIT, /*等待执行*/
|
||||
AT_STATE_EXEC, /*正在执行*/
|
||||
AT_STATE_IDLE, /* 空闲状态*/
|
||||
AT_STATE_WAIT, /* 等待执行*/
|
||||
AT_STATE_EXEC, /* 正在执行*/
|
||||
}at_work_state;
|
||||
|
||||
/*AT作业项*/
|
||||
@ -93,7 +91,7 @@ typedef struct {
|
||||
|
||||
/*AT管理器 ------------------------------------------------------------------*/
|
||||
typedef struct at_obj{
|
||||
at_obj_conf_t cfg;
|
||||
at_adapter_t adap;
|
||||
at_env_t env;
|
||||
at_item_t tbl[10];
|
||||
at_item_t *cursor;
|
||||
@ -102,7 +100,7 @@ typedef struct at_obj{
|
||||
unsigned int urc_timer;
|
||||
at_return ret;
|
||||
//urc接收计数, 命令响应接收计数器
|
||||
unsigned short urc_cnt, rcv_cnt;
|
||||
unsigned short urc_cnt, recv_cnt;
|
||||
unsigned char suspend: 1;
|
||||
}at_obj_t;
|
||||
|
||||
@ -114,15 +112,14 @@ typedef struct {
|
||||
unsigned short timeout; /*最大超时时间 */
|
||||
}at_cmd_t;
|
||||
|
||||
void at_obj_init(at_obj_t *at, const at_obj_conf_t cfg);
|
||||
void at_obj_init(at_obj_t *at, const at_adapter_t *);
|
||||
|
||||
/*发送单行AT命令*/
|
||||
bool at_send_singlline(at_obj_t *at, at_callbatk_t cb, const char *singlline);
|
||||
/*发送多行AT命令*/
|
||||
|
||||
bool at_send_multiline(at_obj_t *at, at_callbatk_t cb, const char **multiline);
|
||||
/*执行AT命令*/
|
||||
|
||||
bool at_do_cmd(at_obj_t *at, void *params, const at_cmd_t *cmd);
|
||||
/*自定义AT作业*/
|
||||
|
||||
bool at_do_work(at_obj_t *at, int (*work)(at_env_t *e), void *params);
|
||||
|
||||
void at_item_abort(at_item_t *it); /*终止当前作业*/
|
||||
|
36
at_util.h
36
at_util.h
@ -13,18 +13,19 @@
|
||||
#ifndef _ATUTIL_H_
|
||||
#define _ATUTIL_H_
|
||||
|
||||
#include "os.h"
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
typedef struct os_semaphore at_sem_t; /*信号量*/
|
||||
typedef void *at_sem_t; /*信号量*/
|
||||
|
||||
/*
|
||||
* @brief 获取当前系统毫秒数
|
||||
*/
|
||||
static inline unsigned int at_get_ms(void)
|
||||
{
|
||||
return ril_get_ms();
|
||||
/*Add here...*/
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
* @brief 超时判断
|
||||
@ -41,32 +42,41 @@ static inline bool at_istimeout(unsigned int start_time, unsigned int timeout)
|
||||
*/
|
||||
static inline void at_delay(uint32_t ms)
|
||||
{
|
||||
os_delay(ms);
|
||||
|
||||
}
|
||||
/*
|
||||
* @brief 初始化信号量
|
||||
* @brief 创建信号
|
||||
* @retval none
|
||||
*/
|
||||
static inline void at_sem_init(at_sem_t *s, int value)
|
||||
static inline at_sem_t at_sem_new(int value)
|
||||
{
|
||||
os_sem_init(s, value);
|
||||
return NULL;
|
||||
}
|
||||
/*
|
||||
* @brief 获取信号量
|
||||
* @brief 等待信号
|
||||
* @retval none
|
||||
*/
|
||||
static inline bool at_sem_wait(at_sem_t *s, uint32_t timeout)
|
||||
static inline bool at_sem_wait(at_sem_t s, uint32_t timeout)
|
||||
{
|
||||
return os_sem_wait(s, timeout);
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief 释放信号量
|
||||
* @brief 释放信号
|
||||
* @retval none
|
||||
*/
|
||||
static inline void at_sem_post(at_sem_t *s)
|
||||
static inline void at_sem_post(at_sem_t s)
|
||||
{
|
||||
os_sem_post(s);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief 销毁的信号
|
||||
* @retval none
|
||||
*/
|
||||
static inline void at_sem_free(at_sem_t s)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
#endif
|
18
list.h
18
list.h
@ -1,9 +1,14 @@
|
||||
|
||||
#ifndef _LINUX_LIST_H_
|
||||
#define _LINUX_LIST_H_
|
||||
#ifndef _LINUX_LIST_H
|
||||
#define _LINUX_LIST_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#define typeof (struct list_head)
|
||||
|
||||
|
||||
#undef offsetof
|
||||
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
|
||||
|
||||
/**
|
||||
* container_of - cast a member of a structure out to the containing structure
|
||||
* @ptr: the pointer to the member.
|
||||
@ -11,9 +16,16 @@
|
||||
* @member: the name of the member within the struct.
|
||||
*
|
||||
*/
|
||||
#if defined(__ICCARM__) || defined(__CC_ARM)
|
||||
#define container_of(ptr, type, member) ( \
|
||||
(type *)( (char *)(ptr) - offsetof(type,member) ))
|
||||
#else
|
||||
#define container_of(ptr, type, member) ({ \
|
||||
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
|
||||
(type *)( (char *)__mptr - offsetof(type,member) );})
|
||||
#endif
|
||||
|
||||
/* copy from <linux/poison.h>, */
|
||||
/*
|
||||
* used to verify that nobody uses non-initialized list entries.
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user