1.Added a temporary disable interface for URC to solve the problem of URC matching exception when receiving binary data from the modem.

2.Added the function of transparent data transmission.
This commit is contained in:
roger.luo 2023-10-27 21:47:51 +08:00
parent ea068791df
commit a6aa614088
5 changed files with 181 additions and 23 deletions

View File

@ -14,6 +14,7 @@ AT command(V2) 一款管理AT命令通信交互组件 适用于Modem、WIFI
- 支持多个AT设备通信管理。
- 支持内存使用监视与限制。
- 支持命令请求的生命周期管理,实时监视命令执行状态。
- 支持命令透传
## 系统要求
@ -42,8 +43,8 @@ V1版本分成了两个模块"at"模块仅适用于在OS环境下运行
static const at_adapter_t at_adapter = {
.lock = at_mutex_lock //多任务上锁(非OS下填NULL)
.unlock = at_mutex_unlock //多任务解锁(非OS下填NULL)
.write = at_device_write //数据写接口(非阻塞式)
.read = at_device_read //数据读接口(非阻塞式)
.write = at_device_write //串口数据写接口(非阻塞式)
.read = at_device_read //串口数据读接口(非阻塞式)
.debug = at_debug //调试打印接口(不需要则填NULL)
.recv_bufsize = 256 //接收缓冲区大小(按实际情况填写)
};

View File

@ -18,6 +18,10 @@
* command execution fails.
* 2023-01-10 roger.luo Resolve URC message containing ':' character
* causing parsing failure.
* 2023-02-23 roger.luo Added a temporary disable interface for URC to
* solve the problem of URC matching exception when
* receiving binary data from the modem.
* 2023-10-27 roger.luo Added the function of transparent data transmission.
******************************************************************************/
#ifndef _AT_CHAT_H_
#define _AT_CHAT_H_
@ -112,6 +116,36 @@ typedef struct {
char *suffix;
} at_response_t;
/**
* @brief The configuration for transparent transmission mode.
*/
typedef struct {
/**
* @brief Exit command(Example:AT+TRANS=0). When this command is matched through the
* read interface, the on_exit event is generated.
*/
const char *exit_cmd;
/**
* @brief Exit event, triggered when the exit command is currently matched. At this time,
* you can invoke 'at_raw_transport_exit' to exit the transparent transport mode.
*/
void (*on_exit)(void);
/**
* @brief Writting interface for transparent data transmission
* @param buf Data buffer
* @param len data length
* @return Indicates the length of the written data
*/
unsigned int (*write)(const void *buf, unsigned int len);
/**
* @brief Reading interface for transparent data transmission
* @param buf Data buffer
* @param len data length
* @return The length of the data actually read
*/
unsigned int (*read) (void *buf, unsigned int len);
} at_raw_trans_conf_t;
/**
* @brief AT interface adapter
*/
@ -120,13 +154,28 @@ typedef struct {
void (*lock)(void);
//Unlock, used in OS environment, fill in NULL if not required.
void (*unlock)(void);
//Data write operation (non-blocking)
/**
* @brief Data write operation (non-blocking)
* @param buf Data buffer
* @param len data length
* @return Indicates the length of the written data
*/
unsigned int (*write)(const void *buf, unsigned int len);
//Data read operation (non-blocking)
/**
* @brief Data read operation (non-blocking)
* @param buf Data buffer
* @param len data length
* @return The length of the data actually read
*/
unsigned int (*read)(void *buf, unsigned int len);
//AT error event ( if not required, fill in NULL)
/**
* @brief AT error event ( if not required, fill in NULL)
*/
void (*error)(at_response_t *);
//Log output interface, which can print the complete AT interaction process, fill in NULL if not required.
/**
* @brief Log output interface, which can print the complete AT interaction
* process, fill in NULL if not required.
*/
void (*debug)(const char *fmt, ...);
#if AT_URC_WARCH_EN
//URC buffer size, set according to the actual maximum URC frame when used.
@ -224,6 +273,9 @@ typedef struct {
*/
typedef struct at_obj {
const at_adapter_t *adap;
#if AT_RAW_TRANSPARENT_EN
const at_raw_trans_conf_t *raw_conf;
#endif
void *user_data;
} at_obj_t;
@ -238,6 +290,11 @@ void at_obj_set_user_data(at_obj_t *at, void *user_data);
void *at_obj_get_user_data(at_obj_t *at);
#if AT_URC_WARCH_EN
void at_obj_set_urc(at_obj_t *at, const urc_item_t *tbl, int count);
int at_obj_get_urcbuf_count(at_obj_t *at);
void at_obj_urc_set_enable(at_obj_t *at, int enable, unsigned short timeout);
#endif
void at_obj_process(at_obj_t *at);
@ -280,5 +337,11 @@ at_resp_code at_work_get_result(at_context_t *ctx);
#endif //End of AT_WORK_CONTEXT_EN
#if AT_RAW_TRANSPARENT_EN
void at_raw_transport_enter(at_obj_t *obj, const at_raw_trans_conf_t *conf);
void at_raw_transport_exit(at_obj_t *obj);
#endif //End of //End of
#endif //End of _AT_CHAT_H_

View File

@ -66,6 +66,10 @@
*/
#define AT_WORK_CONTEXT_EN 1u
/**
* @brief Supports raw data transparent transmission
*/
#define AT_RAW_TRANSPARENT_EN 1u
void *at_malloc(unsigned int nbytes);

View File

@ -18,6 +18,10 @@
* command execution fails.
* 2023-01-10 roger.luo Resolve URC message containing ':' character
* causing parsing failure.
* 2023-02-23 roger.luo Added a temporary disable interface for URC to
* solve the problem of URC matching exception when
* receiving binary data from the modem.
* 2023-10-27 roger.luo Added the function of transparent data transmission.
******************************************************************************/
#include "at_chat.h"
#include "at_port.h"
@ -119,16 +123,19 @@ typedef struct {
unsigned short urc_cnt;
unsigned short urc_target; /* The target data length of the current URC frame*/
unsigned short urc_tbl_size;
unsigned short urc_disable_time;
#endif
unsigned short list_cnt;
unsigned short recv_bufsize;
unsigned short recv_cnt; /* Command response receives counter*/
unsigned short match_len; /* Response information matching length*/
unsigned char match_mask; /* Response information matching mask*/
unsigned urc_enable: 1;
unsigned urc_match : 1;
unsigned enable : 1; /* Enable the work */
unsigned disposing : 1;
unsigned err_occur : 1;
unsigned raw_trans : 1;
} at_info_t;
/**
@ -514,11 +521,12 @@ static int do_cmd_handler(at_info_t *ai)
ai->match_mask |= strstr(ai->recvbuf, AT_DEF_RESP_ERR) ? MATCH_MASK_ERROR : 0x00;
}
if (ai->match_mask & MATCH_MASK_ERROR) {
AT_DEBUG(ai, "<-\r\n%s\r\n", ai->recvbuf);
if (env->i++ >= attr->retry) {
do_at_callback(ai, wi, AT_RESP_ERROR);
return true;
}
AT_DEBUG(ai, "<-\r\n%s\r\n", ai->recvbuf);
env->state = AT_STAT_RETRY; //If the command responds incorrectly, it will wait for a while and try again.
env->reset_timer(env);
}
@ -526,12 +534,12 @@ static int do_cmd_handler(at_info_t *ai)
do_at_callback(ai, wi, AT_RESP_OK);
return true;
} else if (env->is_timeout(env, attr->timeout)) {
AT_DEBUG(ai, "Command response timeout, retry:%d\r\n", env->i);
if (env->i++ >= attr->retry) {
do_at_callback(ai, wi, AT_RESP_TIMEOUT);
return true;
}
env->state = AT_STAT_SEND;
AT_DEBUG(ai, "Command response timeout, retry:%d\r\n", env->i);
}
break;
case AT_STAT_RETRY:
@ -667,13 +675,13 @@ static void urc_handler_entry(at_info_t *ai, urc_recv_status status, char *urc,
{
int remain;
at_urc_info_t ctx = {status, urc, size};
/* Send URC event notification. */
remain = ai->urc_item ? ai->urc_item->handler(&ctx) : 0;
if (remain == 0 && (ai->urc_item || ai->cursor == NULL)) {
if (ai->urc_target > 0)
AT_DEBUG(ai, "<=\r\n%.5s..\r\n", urc);
else
AT_DEBUG(ai, "<=\r\n%s\r\n", urc);
/* Send URC event notification. */
remain = ai->urc_item ? ai->urc_item->handler(&ctx) : 0;
if (remain == 0 && (ai->urc_item || ai->cursor == NULL)) {
urc_reset(ai);
} else {
AT_DEBUG(ai,"URC receives %d bytes remaining.\r\n", remain);
@ -688,8 +696,8 @@ static void urc_timeout_process(at_info_t *ai)
if (ai->urc_cnt > 0 && AT_IS_TIMEOUT(ai->urc_timer, AT_URC_TIMEOUT)) {
if (ai->urc_cnt > 2 && ai->urc_item != NULL) {
ai->urcbuf[ai->urc_cnt] = '\0';
urc_handler_entry(ai, URC_RECV_TIMEOUT, ai->urcbuf, ai->urc_cnt);
AT_DEBUG(ai,"urc recv timeout=>%s\r\n", ai->urcbuf);
urc_handler_entry(ai, URC_RECV_TIMEOUT, ai->urcbuf, ai->urc_cnt);
}
urc_reset(ai);
}
@ -710,6 +718,12 @@ static void urc_recv_process(at_info_t *ai, char *buf, unsigned int size)
urc_timeout_process(ai);
return;
}
if (!ai->urc_enable) {
if (!AT_IS_TIMEOUT(ai->urc_timer, ai->urc_disable_time))
return;
ai->urc_enable = 1;
AT_DEBUG(ai, "Enable the URC match handler\r\n");
}
urc_buf = ai->urcbuf;
while (size--) {
ch = *buf++;
@ -749,6 +763,8 @@ static void urc_recv_process(at_info_t *ai, char *buf, unsigned int size)
*/
static void resp_recv_process(at_info_t *ai, const char *buf, unsigned int size)
{
if (size == 0)
return;
if (ai->recv_cnt + size >= ai->recv_bufsize) //Receive overflow, clear directly.
ai->recv_cnt = 0;
@ -843,6 +859,8 @@ at_obj_t *at_obj_create(const at_adapter_t *adap)
#endif
e = &ai->env;
ai->recv_cnt = 0;
ai->urc_enable = 1;
ai->enable = 1;
//Initialization of public work environment.
e->is_timeout = at_is_timeout;
e->println = println;
@ -885,11 +903,12 @@ void at_obj_destroy(at_obj_t *obj)
*/
bool at_obj_busy(at_obj_t *at)
{
return !list_empty(&obj_map(at)->hlist) || !list_empty(&obj_map(at)->llist);
return !list_empty(&obj_map(at)->hlist) || !list_empty(&obj_map(at)->llist)
|| obj_map(at)->urc_cnt != 0;
}
/**
* @brief Suspend all AT work items
* @brief Enable/Disable the AT work
*/
void at_obj_set_enable(at_obj_t *at, int enable)
{
@ -1187,6 +1206,71 @@ at_resp_code at_work_get_result(at_context_t *ctx)
#endif
#if AT_RAW_TRANSPARENT_EN
/**
* @brief Data transparent transmission processing.
*/
static void at_raw_trans_process(at_obj_t *obj)
{
unsigned char rbuf[32];
int size;
int i;
at_info_t *ai = obj_map(obj);
if (obj->raw_conf == NULL)
return;
size = obj->adap->read(rbuf, sizeof(rbuf));
if (size > 0 ){
obj->raw_conf->write(rbuf, size);
}
size = obj->raw_conf->read(rbuf, sizeof(rbuf));
if (size > 0) {
obj->adap->write(rbuf, size);
}
//Exit command detection
if (obj->raw_conf->exit_cmd != NULL) {
for (i = 0; i < size; i++) {
if (ai->recv_cnt >= ai->recv_bufsize)
ai->recv_cnt = 0;
ai->recvbuf[ai->recv_cnt] = rbuf[i];
if (rbuf[i] == '\r' || rbuf[i] == 'n') {
ai->recvbuf[ai->recv_cnt] = '\0';
ai->recv_cnt = 0;
if (strcasecmp(obj->raw_conf->exit_cmd, ai->recvbuf) != 0) {
continue;
}
if (obj->raw_conf->on_exit) {
obj->raw_conf->on_exit();
}
} else {
ai->recv_cnt++;
}
}
}
}
/**
* @brief Enter transparent transmission mode.
* @param conf The configuration for transparent transmission mode.
*/
void at_raw_transport_enter(at_obj_t *obj, const at_raw_trans_conf_t *conf)
{
at_info_t *ai = obj_map(obj);
obj->raw_conf = conf;
ai->raw_trans = 1;
ai->recv_cnt = 0;
}
/**
* @brief Exit transparent transmission mode.
*/
void at_raw_transport_exit(at_obj_t *obj)
{
at_info_t *ai = obj_map(obj);
ai->raw_trans = 0;
}
#endif
/**
* @brief AT work polling processing.
*/
@ -1195,6 +1279,12 @@ void at_obj_process(at_obj_t *at)
char rbuf[64];
int read_size;
register at_info_t *ai = obj_map(at);
#if AT_RAW_TRANSPARENT_EN
if (ai->raw_trans) {
at_raw_trans_process(at);
return;
}
#endif
read_size = __get_adapter(ai)->read(rbuf, sizeof(rbuf));
#if AT_URC_WARCH_EN
urc_recv_process(ai, rbuf, read_size);