From a6aa6140887d30a6c71dda067ae33ac71818611a Mon Sep 17 00:00:00 2001 From: "roger.luo" Date: Fri, 27 Oct 2023 21:47:51 +0800 Subject: [PATCH] 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. --- README.md | 5 +- include/at_chat.h | 73 ++++++++++++++++++-- include/at_port.h | 4 ++ samples/none_os/user/platform.c | 8 +-- src/at_chat.c | 114 ++++++++++++++++++++++++++++---- 5 files changed, 181 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index 6a52771..ba576d8 100644 --- a/README.md +++ b/README.md @@ -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 //接收缓冲区大小(按实际情况填写) }; diff --git a/include/at_chat.h b/include/at_chat.h index 0a5dbd8..9543266 100644 --- a/include/at_chat.h +++ b/include/at_chat.h @@ -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. @@ -223,7 +272,10 @@ typedef struct { *@brief AT object. */ typedef struct at_obj { - const at_adapter_t *adap; + 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_ diff --git a/include/at_port.h b/include/at_port.h index 802c32d..2e13587 100644 --- a/include/at_port.h +++ b/include/at_port.h @@ -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); diff --git a/samples/none_os/user/platform.c b/samples/none_os/user/platform.c index 16b33ed..1b1eee6 100644 --- a/samples/none_os/user/platform.c +++ b/samples/none_os/user/platform.c @@ -43,10 +43,10 @@ int fputc(int c, FILE *f) */ static void bsp_init(void) { - NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); - tty.init(115200); - SystemCoreClockUpdate(); - SysTick_Config(SystemCoreClock / (1000 / SYS_TICK_INTERVAL)); //配置系统时钟 + NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); + tty.init(115200); + SystemCoreClockUpdate(); + SysTick_Config(SystemCoreClock / (1000 / SYS_TICK_INTERVAL)); //配置系统时钟 NVIC_SetPriority(SysTick_IRQn, 0); }system_init("bsp", bsp_init); diff --git a/src/at_chat.c b/src/at_chat.c index e3c77a7..95f3bdb 100644 --- a/src/at_chat.c +++ b/src/at_chat.c @@ -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" @@ -118,17 +122,20 @@ typedef struct { unsigned short urc_bufsize; 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_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); + env->state = AT_STAT_SEND; } 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}; + 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)) { - if (ai->urc_target > 0) - AT_DEBUG(ai, "<=\r\n%.5s..\r\n", urc); - else - AT_DEBUG(ai, "<=\r\n%s\r\n", urc); 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); + 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);