diff --git a/docs/sidebar.md b/docs/sidebar.md index 2474fd8..fc586d3 100644 --- a/docs/sidebar.md +++ b/docs/sidebar.md @@ -1,6 +1,6 @@ -* [介绍](readme#简介) +* [介绍](README#简介) * [快速上手](quickStart#基础应用) * [高级教程](Expert#高级教程) * [平台移植](Porting#平台移植) \ No newline at end of file diff --git a/include/at_chat.h b/include/at_chat.h index 66a1ae9..0a5dbd8 100644 --- a/include/at_chat.h +++ b/include/at_chat.h @@ -8,11 +8,16 @@ * Change Logs: * Date Author Notes * 2020-01-02 roger.luo Initial version - * 2021-01-20 roger.luo Add debugging interface, and at the same time solve - * the problem of uninitialized linked list leading to - * segment fault. - * 2021-03-03 roger.luo Fix the problem of frequent print receive timeout caused by not clearing the URC counter. + * 2021-01-20 roger.luo Add debugging interface, and at the same time + * solve the problem of uninitialized linked list + * leading to segment fault. + * 2021-03-03 roger.luo Fix the problem of frequent print receive timeout + * caused by not clearing the URC counter. * 2022-10-01 roger.luo Redesign the entire AT framework and release V2.0. + * 2023-01-09 roger.luo Optimized the processing logic when multi-line + * command execution fails. + * 2023-01-10 roger.luo Resolve URC message containing ':' character + * causing parsing failure. ******************************************************************************/ #ifndef _AT_CHAT_H_ #define _AT_CHAT_H_ @@ -243,7 +248,7 @@ bool at_exec_cmd(at_obj_t *at, const at_attr_t *attr, const char *cmd, ...); bool at_exec_vcmd(at_obj_t *at, const at_attr_t *attr, const char *cmd, va_list va); -bool at_send_singlline(at_obj_t *at, at_callback_t cb, int timeout, int retry, const char *singlline); +bool at_send_singlline(at_obj_t *at, const at_attr_t *attr, const char *singlline); bool at_send_multiline(at_obj_t *at, const at_attr_t *attr, const char **multiline); diff --git a/src/at_chat.c b/src/at_chat.c index e6eb200..e3c77a7 100644 --- a/src/at_chat.c +++ b/src/at_chat.c @@ -8,11 +8,16 @@ * Change Logs: * Date Author Notes * 2020-01-02 roger.luo Initial version - * 2021-01-20 roger.luo Add debugging interface, and at the same time solve - * the problem of uninitialized linked list leading to - * segment fault. - * 2021-03-03 roger.luo Fix the problem of frequent print receive timeout caused by not clearing the URC counter. + * 2021-01-20 roger.luo Add debugging interface, and at the same time + * solve the problem of uninitialized linked list + * leading to segment fault. + * 2021-03-03 roger.luo Fix the problem of frequent print receive timeout + * caused by not clearing the URC counter. * 2022-10-01 roger.luo Redesign the entire AT framework and release V2.0. + * 2023-01-09 roger.luo Optimized the processing logic when multi-line + * command execution fails. + * 2023-01-10 roger.luo Resolve URC message containing ':' character + * causing parsing failure. ******************************************************************************/ #include "at_chat.h" #include "at_port.h" @@ -155,13 +160,7 @@ static inline at_info_t *obj_map(at_obj_t *at) { return (at_info_t *)at; } -/** - * @brief void * -> work_item_t * - */ -static inline work_item_t *work_item_map(void *work_obj) -{ - return (work_item_t *)work_obj; -} + static inline const at_adapter_t *__get_adapter(at_info_t *ai) { @@ -196,7 +195,7 @@ static void send_cmdline(at_info_t *at, const char *cmd) len = strlen(cmd); __get_adapter(at)->write(cmd, len); __get_adapter(at)->write("\r\n", 2); - AT_DEBUG(at,"=>:\r\n%s\r\n", cmd); + AT_DEBUG(at,"->\r\n%s\r\n", cmd); } /** @@ -268,10 +267,10 @@ static void at_next_wait(struct at_env *env, unsigned int ms) static void update_work_state(work_item_t *wi, at_work_state state, at_resp_code code) { - at_context_t *ctx = wi->attr.ctx; wi->state = state; wi->code = code; #if AT_WORK_CONTEXT_EN + at_context_t *ctx = wi->attr.ctx; if (ctx != NULL) { ctx->code = (at_resp_code)wi->code; ctx->work_state = (at_work_state)wi->state; @@ -294,8 +293,7 @@ static void at_finish(struct at_env *env, at_resp_code code) static void do_at_callback(at_info_t *ai, work_item_t *wi, at_resp_code code) { at_response_t r; - at_context_t *ctx; - AT_DEBUG(ai, "<=:\r\n%s\r\n", ai->recvbuf); + AT_DEBUG(ai, "<-\r\n%s\r\n", ai->recvbuf); //Exception notification if ((code == AT_RESP_ERROR || code == AT_RESP_TIMEOUT) && __get_adapter(ai)->error != NULL) { __get_adapter(ai)->error(&r); @@ -305,7 +303,7 @@ static void do_at_callback(at_info_t *ai, work_item_t *wi, at_resp_code code) ai->err_occur = 0; } #if AT_WORK_CONTEXT_EN - ctx = wi->attr.ctx; + at_context_t *ctx = wi->attr.ctx; if (ctx != NULL ) { if (ctx->respbuf != NULL/* && ctx->bufsize */) { ctx->resplen = ai->recv_cnt >= ctx->bufsize ? ctx->bufsize - 1 : ai->recv_cnt; @@ -412,10 +410,12 @@ static work_item_t *create_work_item(at_info_t *ai, int type, const at_attr_t *a it->attr = *attr; it->type = type; it->state = AT_WORK_STAT_READY; +#if AT_WORK_CONTEXT_EN if (attr->ctx) { attr->ctx->code = AT_RESP_OK; attr->ctx->work_state = AT_WORK_STAT_READY; } +#endif return it; } @@ -518,7 +518,7 @@ static int do_cmd_handler(at_info_t *ai) do_at_callback(ai, wi, AT_RESP_ERROR); return true; } - AT_DEBUG(ai, "<=\r\n%s\r\n", ai->recvbuf); + 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); } @@ -558,7 +558,7 @@ static int send_multiline_handler(at_info_t *ai) { case AT_STAT_SEND: if (cmds[env->i] == NULL) { /* All commands are sent.*/ - do_at_callback(ai, wi, AT_RESP_OK); + do_at_callback(ai, wi, env->params ? AT_RESP_OK : AT_RESP_ERROR); return true; } send_cmdline(ai, cmds[env->i]); @@ -572,23 +572,27 @@ static int send_multiline_handler(at_info_t *ai) env->state = 0; env->i++; env->j = 0; - AT_DEBUG(ai, "<-\r\n%s\r\n", ai->recvbuf); + env->params = (void *)true; /*Mark execution status*/ + AT_DEBUG(ai, "<-\r\n%s\r\n", ai->recvbuf); } else if (find_substr(env, AT_DEF_RESP_ERR)) { AT_DEBUG(ai, "<-\r\n%s\r\n", ai->recvbuf); - if (env->j++ >= attr->retry) { - do_at_callback(ai, wi, AT_RESP_ERROR); - return true; + env->j++; + AT_DEBUG(ai, "CMD:'%s' failed to executed, retry:%d\r\n", cmds[env->i], env->j); + if (env->j >= attr->retry) { + env->state = 0; + env->j = 0; + env->i++; + } else { + env->state = AT_STAT_RETRY; //After the command responds incorrect, try again after a period of time. + env->reset_timer(env); } - AT_DEBUG(ai, "<=\r\n%s\r\n", ai->recvbuf); - env->state = AT_STAT_RETRY; //After the command responds incorrect, try again after a period of time. - env->reset_timer(env); } else if (env->is_timeout(env, AT_DEF_TIMEOUT)) { do_at_callback(ai, wi, AT_RESP_TIMEOUT); return true; } break; case AT_STAT_RETRY: - if (env->is_timeout(env, 200)) + if (env->is_timeout(env, 100)) env->state = AT_STAT_SEND;/*Go back to the send state and resend.*/ break; default: @@ -663,11 +667,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->cursor == NULL && ai->urc_target == 0) - 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) { + 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); @@ -723,13 +729,16 @@ static void urc_recv_process(at_info_t *ai, char *buf, unsigned int size) continue; urc_buf[ai->urc_cnt] = '\0'; if (ai->urc_item == NULL) { //Find the corresponding URC handler - if (ai->urc_cnt < 3 || - (ai->urc_item = find_urc_item(ai, urc_buf, ai->urc_cnt)) == NULL) { - urc_reset(ai); - } + ai->urc_item = find_urc_item(ai, urc_buf, ai->urc_cnt); + if (ai->urc_item == NULL && ch == '\n') { + if (ai->urc_cnt > 2 && ai->cursor == NULL) //Unrecognized URC message + AT_DEBUG(ai, "%s\r\n", urc_buf); + urc_reset(ai); + continue; + } } if (ai->urc_item != NULL && ch == ai->urc_item->endmark) - urc_handler_entry(ai, URC_RECV_OK, urc_buf, ai->urc_cnt); + urc_handler_entry(ai, URC_RECV_OK, urc_buf, ai->urc_cnt); } } @@ -985,13 +994,9 @@ bool at_send_data(at_obj_t *at, const at_attr_t *attr, const void *databuf, unsi * @retval Indicates whether the asynchronous work was enqueued successfully. * @note Only the address is saved, so the 'singlline' can not be a local variable which will be destroyed. */ -bool at_send_singlline(at_obj_t *at, at_callback_t cb, int timeout, int retry, const char *singlline) +bool at_send_singlline(at_obj_t *at, const at_attr_t *attr, const char *singlline) { - at_attr_t attr = at_def_attr; - attr.cb = cb; - attr.timeout = timeout; - attr.retry = retry; - return add_work_item(obj_map(at), WORK_TYPE_SINGLLINE, &attr, singlline, 0) != NULL; + return add_work_item(obj_map(at), WORK_TYPE_SINGLLINE, attr, singlline, 0) != NULL; } /** @@ -1107,6 +1112,14 @@ static void at_core_free(void *ptr) #if AT_WORK_CONTEXT_EN +/** + * @brief void * -> work_item_t * + */ +static inline work_item_t *work_item_map(void *work_obj) +{ + return (work_item_t *)work_obj; +} + /** * @brief Indicates whether the AT work is valid. */