浏览代码

[component][net][at] at_client增加deInit接口 (#10598)

* [component][net][at] at_client增加deInit接口

* [component][net][at] at_client优化serial_v2适配
RyanCW 3 周之前
父节点
当前提交
a1a8bc5422
共有 2 个文件被更改,包括 254 次插入269 次删除
  1. 4 6
      components/net/at/include/at.h
  2. 250 263
      components/net/at/src/at_client.c

+ 4 - 6
components/net/at/include/at.h

@@ -169,14 +169,10 @@ struct at_client
     /* The maximum supported receive data length */
     rt_size_t recv_bufsz;
 
-#if (!defined(RT_USING_SERIAL_V2))
-    rt_sem_t rx_notice;
-#endif
-
-    rt_mutex_t lock;
+    struct rt_event event;
+    struct rt_mutex lock;
 
     at_response_t resp;
-    rt_sem_t resp_notice;
     at_resp_status_t resp_status;
 
     struct at_urc_table *urc_table;
@@ -184,6 +180,7 @@ struct at_client
     const struct at_urc *urc;
 
     rt_thread_t parser;
+    rt_slist_t  list;
 };
 typedef struct at_client *at_client_t;
 #endif /* AT_USING_CLIENT */
@@ -207,6 +204,7 @@ int at_req_parse_args(const char *req_args, const char *req_expr, ...);
 
 /* AT client initialize and start*/
 int at_client_init(const char *dev_name, rt_size_t recv_bufsz, rt_size_t send_bufsz);
+int at_client_deInit(const char *dev_name);
 
 /* ========================== multiple AT client function ============================ */
 

+ 250 - 263
components/net/at/src/at_client.c

@@ -12,6 +12,7 @@
  * 2021-07-14     Sszl         fix a buf of leaking memory
  * 2025-01-02     dongly       support SERIAL_V2
  * 2025-04-18     RyanCw       support New SERIAL_V2
+ * 2025-08-11     RyanCw       add client deInit
  */
 
 #include <at.h>
@@ -19,19 +20,24 @@
 #include <stdlib.h>
 #include <string.h>
 
-#define LOG_TAG              "at.clnt"
+#define LOG_TAG "at.clnt"
 #include <at_log.h>
 #ifdef AT_USING_CLIENT
 
-#define AT_RESP_END_OK                 "OK"
-#define AT_RESP_END_ERROR              "ERROR"
-#define AT_RESP_END_FAIL               "FAIL"
-#define AT_END_CR_LF                   "\r\n"
-#define AT_END_CR                      "\r"
-#define AT_END_LF                      "\n"
-#define AT_END_RAW                     ""
+#define AT_RESP_END_OK    "OK"
+#define AT_RESP_END_ERROR "ERROR"
+#define AT_RESP_END_FAIL  "FAIL"
+#define AT_END_CR_LF      "\r\n"
+#define AT_END_CR         "\r"
+#define AT_END_LF         "\n"
+#define AT_END_RAW        ""
 
-static struct at_client at_client_table[AT_CLIENT_NUM_MAX] = { 0 };
+#define at_client_rx_notice_event   (1 << 0)
+#define at_client_resp_notice_event (1 << 1)
+#define at_client_deInit_event      (1 << 2)
+#define at_client_deInit_over_event (1 << 3)
+
+static rt_slist_t g_at_client_list = RT_SLIST_OBJECT_INIT(g_at_client_list);
 
 extern rt_size_t at_utils_send(rt_device_t dev,
                                rt_off_t    pos,
@@ -41,7 +47,7 @@ extern rt_size_t at_vprintfln(rt_device_t device, char *send_buf, rt_size_t buf_
 extern rt_size_t at_vprintf(rt_device_t device, char *send_buf, rt_size_t buf_size, const char *format, va_list args);
 extern rt_size_t at_vprintfcr(rt_device_t device, char *send_buf, rt_size_t buf_size, const char *format, va_list args);
 extern rt_size_t at_vprintflf(rt_device_t device, char *send_buf, rt_size_t buf_size, const char *format, va_list args);
-extern void at_print_raw_cmd(const char *type, const char *cmd, rt_size_t size);
+extern void      at_print_raw_cmd(const char *type, const char *cmd, rt_size_t size);
 
 /**
  * Create response object.
@@ -59,14 +65,14 @@ at_response_t at_create_resp(rt_size_t buf_size, rt_size_t line_num, rt_int32_t
 {
     at_response_t resp = RT_NULL;
 
-    resp = (at_response_t) rt_calloc(1, sizeof(struct at_response));
+    resp = (at_response_t)rt_calloc(1, sizeof(struct at_response));
     if (resp == RT_NULL)
     {
         LOG_E("AT create response object failed! No memory for response object!");
         return RT_NULL;
     }
 
-    resp->buf = (char *) rt_calloc(1, buf_size);
+    resp->buf = (char *)rt_calloc(1, buf_size);
     if (resp->buf == RT_NULL)
     {
         LOG_E("AT create response object failed! No memory for response buffer!");
@@ -74,10 +80,10 @@ at_response_t at_create_resp(rt_size_t buf_size, rt_size_t line_num, rt_int32_t
         return RT_NULL;
     }
 
-    resp->buf_size = buf_size;
-    resp->line_num = line_num;
+    resp->buf_size    = buf_size;
+    resp->line_num    = line_num;
     resp->line_counts = 0;
-    resp->timeout = timeout;
+    resp->timeout     = timeout;
 
     return resp;
 }
@@ -123,7 +129,7 @@ at_response_t at_resp_set_info(at_response_t resp, rt_size_t buf_size, rt_size_t
     {
         resp->buf_size = buf_size;
 
-        p_temp = (char *) rt_realloc(resp->buf, buf_size);
+        p_temp = (char *)rt_realloc(resp->buf, buf_size);
         if (p_temp == RT_NULL)
         {
             LOG_D("No memory for realloc response buffer size(%d).", buf_size);
@@ -136,7 +142,7 @@ at_response_t at_resp_set_info(at_response_t resp, rt_size_t buf_size, rt_size_t
     }
 
     resp->line_num = line_num;
-    resp->timeout = timeout;
+    resp->timeout  = timeout;
 
     return resp;
 }
@@ -152,7 +158,7 @@ at_response_t at_resp_set_info(at_response_t resp, rt_size_t buf_size, rt_size_t
  */
 const char *at_resp_get_line(at_response_t resp, rt_size_t resp_line)
 {
-    char *resp_buf = resp->buf;
+    char     *resp_buf = resp->buf;
     rt_size_t line_num = 1;
 
     RT_ASSERT(resp);
@@ -187,7 +193,7 @@ const char *at_resp_get_line(at_response_t resp, rt_size_t resp_line)
  */
 const char *at_resp_get_line_by_kw(at_response_t resp, const char *keyword)
 {
-    char *resp_buf = resp->buf;
+    char     *resp_buf = resp->buf;
     rt_size_t line_num = 1;
 
     RT_ASSERT(resp);
@@ -219,8 +225,8 @@ const char *at_resp_get_line_by_kw(at_response_t resp, const char *keyword)
  */
 int at_resp_parse_line_args(at_response_t resp, rt_size_t resp_line, const char *resp_expr, ...)
 {
-    va_list args;
-    int resp_args_num = 0;
+    va_list     args;
+    int         resp_args_num = 0;
     const char *resp_line_buf = RT_NULL;
 
     RT_ASSERT(resp);
@@ -254,8 +260,8 @@ int at_resp_parse_line_args(at_response_t resp, rt_size_t resp_line, const char
  */
 int at_resp_parse_line_args_by_kw(at_response_t resp, const char *keyword, const char *resp_expr, ...)
 {
-    va_list args;
-    int resp_args_num = 0;
+    va_list     args;
+    int         resp_args_num = 0;
     const char *resp_line_buf = RT_NULL;
 
     RT_ASSERT(resp);
@@ -290,7 +296,7 @@ int at_resp_parse_line_args_by_kw(at_response_t resp, const char *keyword, const
  */
 int at_obj_exec_cmd(at_client_t client, at_response_t resp, const char *cmd_expr, ...)
 {
-    va_list args;
+    va_list  args;
     rt_err_t result = RT_EOK;
 
     RT_ASSERT(cmd_expr);
@@ -307,18 +313,18 @@ int at_obj_exec_cmd(at_client_t client, at_response_t resp, const char *cmd_expr
         return -RT_EBUSY;
     }
 
-    rt_mutex_take(client->lock, RT_WAITING_FOREVER);
+    rt_mutex_take(&client->lock, RT_WAITING_FOREVER);
 
     client->resp_status = AT_RESP_OK;
 
     if (resp != RT_NULL)
     {
-        resp->buf_len = 0;
+        resp->buf_len     = 0;
         resp->line_counts = 0;
     }
 
     client->resp = resp;
-    rt_sem_control(client->resp_notice, RT_IPC_CMD_RESET, RT_NULL);
+    rt_event_recv(&client->event, at_client_resp_notice_event, RT_EVENT_FLAG_AND | RT_EVENT_FLAG_CLEAR, 0, NULL);
 
     va_start(args, cmd_expr);
     client->last_cmd_len = at_vprintfln(client->device, client->send_buf, client->send_bufsz, cmd_expr, args);
@@ -330,11 +336,11 @@ int at_obj_exec_cmd(at_client_t client, at_response_t resp, const char *cmd_expr
 
     if (resp != RT_NULL)
     {
-        if (rt_sem_take(client->resp_notice, resp->timeout) != RT_EOK)
+        if (rt_event_recv(&client->event, at_client_resp_notice_event, RT_EVENT_FLAG_AND | RT_EVENT_FLAG_CLEAR, resp->timeout, NULL) != RT_EOK)
         {
             LOG_W("execute command (%.*s) timeout (%d ticks)!", client->last_cmd_len, client->send_buf, resp->timeout);
             client->resp_status = AT_RESP_TIMEOUT;
-            result = -RT_ETIMEOUT;
+            result              = -RT_ETIMEOUT;
         }
         else if (client->resp_status != AT_RESP_OK)
         {
@@ -345,7 +351,7 @@ int at_obj_exec_cmd(at_client_t client, at_response_t resp, const char *cmd_expr
 
     client->resp = RT_NULL;
 
-    rt_mutex_release(client->lock);
+    rt_mutex_release(&client->lock);
 
     return result;
 }
@@ -366,9 +372,9 @@ int at_obj_exec_cmd(at_client_t client, at_response_t resp, const char *cmd_expr
  *        -2 : wait timeout
  *        -7 : enter AT CLI mode
  */
-int at_obj_exec_cmd_format(at_client_t client, at_response_t resp, const char* format, const char *cmd_expr, ...)
+int at_obj_exec_cmd_format(at_client_t client, at_response_t resp, const char *format, const char *cmd_expr, ...)
 {
-    va_list args;
+    va_list  args;
     rt_err_t result = RT_EOK;
 
     RT_ASSERT(cmd_expr);
@@ -385,18 +391,18 @@ int at_obj_exec_cmd_format(at_client_t client, at_response_t resp, const char* f
         return -RT_EBUSY;
     }
 
-    rt_mutex_take(client->lock, RT_WAITING_FOREVER);
+    rt_mutex_take(&client->lock, RT_WAITING_FOREVER);
 
     client->resp_status = AT_RESP_OK;
 
     if (resp != RT_NULL)
     {
-        resp->buf_len = 0;
+        resp->buf_len     = 0;
         resp->line_counts = 0;
     }
 
     client->resp = resp;
-    rt_sem_control(client->resp_notice, RT_IPC_CMD_RESET, RT_NULL);
+    rt_event_recv(&client->event, at_client_resp_notice_event, RT_EVENT_FLAG_AND | RT_EVENT_FLAG_CLEAR, 0, NULL);
 
     va_start(args, cmd_expr);
 
@@ -421,11 +427,11 @@ int at_obj_exec_cmd_format(at_client_t client, at_response_t resp, const char* f
 
     if (resp != RT_NULL)
     {
-        if (rt_sem_take(client->resp_notice, resp->timeout) != RT_EOK)
+        if (rt_event_recv(&client->event, at_client_resp_notice_event, RT_EVENT_FLAG_AND | RT_EVENT_FLAG_CLEAR, resp->timeout, NULL) != RT_EOK)
         {
             LOG_W("execute command (%.*s) timeout (%d ticks)!", client->last_cmd_len, client->send_buf, resp->timeout);
             client->resp_status = AT_RESP_TIMEOUT;
-            result = -RT_ETIMEOUT;
+            result              = -RT_ETIMEOUT;
         }
         else if (client->resp_status != AT_RESP_OK)
         {
@@ -436,7 +442,7 @@ int at_obj_exec_cmd_format(at_client_t client, at_response_t resp, const char* f
 
     client->resp = RT_NULL;
 
-    rt_mutex_release(client->lock);
+    rt_mutex_release(&client->lock);
 
     return result;
 }
@@ -453,10 +459,9 @@ int at_obj_exec_cmd_format(at_client_t client, at_response_t resp, const char* f
  */
 int at_client_obj_wait_connect(at_client_t client, rt_uint32_t timeout)
 {
-    rt_err_t result = RT_EOK;
-    at_response_t resp = RT_NULL;
-    rt_tick_t start_time = 0;
-    char *client_name = client->device->parent.name;
+    rt_err_t      result     = RT_EOK;
+    at_response_t resp       = RT_NULL;
+    rt_tick_t     start_time = 0;
 
     if (client == RT_NULL)
     {
@@ -467,14 +472,10 @@ int at_client_obj_wait_connect(at_client_t client, rt_uint32_t timeout)
     resp = at_create_resp(64, 0, rt_tick_from_millisecond(300));
     if (resp == RT_NULL)
     {
-        LOG_E("no memory for AT client(%s) response object.", client_name);
+        LOG_E("no memory for AT client(%s) response object.", client->device->parent.name);
         return -RT_ENOMEM;
     }
 
-    rt_mutex_take(client->lock, RT_WAITING_FOREVER);
-    client->resp = resp;
-    rt_sem_control(client->resp_notice, RT_IPC_CMD_RESET, RT_NULL);
-
     start_time = rt_tick_get();
 
     while (1)
@@ -482,26 +483,18 @@ int at_client_obj_wait_connect(at_client_t client, rt_uint32_t timeout)
         /* Check whether it is timeout */
         if (rt_tick_get() - start_time > rt_tick_from_millisecond(timeout))
         {
-            LOG_E("wait AT client(%s) connect timeout(%d tick).", client_name, timeout);
+            LOG_E("wait AT client(%s) connect timeout(%d tick).", client->device->parent.name, timeout);
             result = -RT_ETIMEOUT;
             break;
         }
 
-        /* Check whether it is already connected */
-        resp->buf_len = 0;
-        resp->line_counts = 0;
-        at_utils_send(client->device, 0, "AT\r\n", 4);
-
-        if (rt_sem_take(client->resp_notice, resp->timeout) == RT_EOK)
+        if (at_obj_exec_cmd(client, resp, "AT") == RT_EOK)
+        {
             break;
+        }
     }
 
     at_delete_resp(resp);
-
-    client->resp = RT_NULL;
-
-    rt_mutex_release(client->lock);
-
     return result;
 }
 
@@ -531,45 +524,15 @@ rt_size_t at_client_obj_send(at_client_t client, const char *buf, rt_size_t size
     at_print_raw_cmd("sendline", buf, size);
 #endif
 
-    rt_mutex_take(client->lock, RT_WAITING_FOREVER);
+    rt_mutex_take(&client->lock, RT_WAITING_FOREVER);
 
     len = at_utils_send(client->device, 0, buf, size);
 
-    rt_mutex_release(client->lock);
+    rt_mutex_release(&client->lock);
 
     return len;
 }
 
-static rt_err_t at_client_getchar(at_client_t client, char *ch, rt_int32_t timeout)
-{
-    rt_err_t result = RT_EOK;
-
-#if (!defined(RT_USING_SERIAL_V2))
-    while (rt_device_read(client->device, 0, ch, 1) == 0)
-    {
-        result = rt_sem_take(client->rx_notice, rt_tick_from_millisecond(timeout));
-        if (result != RT_EOK)
-        {
-            return result;
-        }
-
-        rt_sem_control(client->rx_notice, RT_IPC_CMD_RESET, RT_NULL);
-    }
-#else
-    rt_int32_t rx_timeout = rt_tick_from_millisecond(timeout);
-    rt_device_control(client->device, RT_SERIAL_CTRL_SET_RX_TIMEOUT, (void *)&rx_timeout);
-    result = rt_device_read(client->device, 0, ch, 1);
-    if(result <= 0)
-    {
-        result = -RT_ERROR;
-    }
-    rx_timeout = RT_WAITING_FOREVER;
-    rt_device_control(client->device, RT_SERIAL_CTRL_SET_RX_TIMEOUT, (void*)&rx_timeout);
-#endif
-
-    return result;
-}
-
 /**
  * AT client receive fixed-length data.
  *
@@ -595,31 +558,31 @@ rt_size_t at_client_obj_recv(at_client_t client, char *buf, rt_size_t size, rt_i
         return 0;
     }
 
-#if (!defined(RT_USING_SERIAL_V2))
+#ifndef RT_USING_SERIAL_V2
     while (size)
     {
         rt_size_t read_len;
 
-        rt_sem_control(client->rx_notice, RT_IPC_CMD_RESET, RT_NULL);
+        rt_event_recv(&client->event, at_client_rx_notice_event, RT_EVENT_FLAG_AND | RT_EVENT_FLAG_CLEAR, 0, NULL);
 
         read_len = rt_device_read(client->device, 0, buf + read_idx, size);
         if (read_len > 0)
         {
             read_idx += read_len;
-            size -= read_len;
+            size     -= read_len;
         }
         else
         {
-            if (rt_sem_take(client->rx_notice, rt_tick_from_millisecond(timeout)) != RT_EOK)
+            if (rt_event_recv(&client->event, at_client_rx_notice_event, RT_EVENT_FLAG_AND | RT_EVENT_FLAG_CLEAR, rt_tick_from_millisecond(timeout), NULL) != RT_EOK)
                 break;
         }
     }
 #else
     rt_int32_t rx_timeout = rt_tick_from_millisecond(timeout);
     rt_device_control(client->device, RT_SERIAL_CTRL_SET_RX_TIMEOUT, (void *)&rx_timeout);
-    read_idx = rt_device_read(client->device, 0, buf, size);
-    rx_timeout = RT_WAITING_FOREVER;
-    rt_device_control(client->device, RT_SERIAL_CTRL_SET_RX_TIMEOUT, (void*)&rx_timeout);
+    read_idx   = rt_device_read(client->device, 0, buf, size);
+    rx_timeout = RT_WAITING_NO;
+    rt_device_control(client->device, RT_SERIAL_CTRL_SET_RX_TIMEOUT, (void *)&rx_timeout);
 #endif
 
 #ifdef AT_PRINT_RAW_CMD
@@ -671,13 +634,13 @@ int at_obj_set_urc_table(at_client_t client, const struct at_urc *urc_table, rt_
 
     if (client->urc_table_size == 0)
     {
-        client->urc_table = (struct at_urc_table *) rt_calloc(1, sizeof(struct at_urc_table));
+        client->urc_table = (struct at_urc_table *)rt_calloc(1, sizeof(struct at_urc_table));
         if (client->urc_table == RT_NULL)
         {
             return -RT_ENOMEM;
         }
 
-        client->urc_table[0].urc = urc_table;
+        client->urc_table[0].urc      = urc_table;
         client->urc_table[0].urc_size = table_sz;
         client->urc_table_size++;
     }
@@ -686,16 +649,15 @@ int at_obj_set_urc_table(at_client_t client, const struct at_urc *urc_table, rt_
         struct at_urc_table *new_urc_table = RT_NULL;
 
         /* realloc urc table space */
-        new_urc_table = (struct at_urc_table *) rt_realloc(client->urc_table,client->urc_table_size * sizeof(struct at_urc_table) + sizeof(struct at_urc_table));
+        new_urc_table = (struct at_urc_table *)rt_realloc(client->urc_table, client->urc_table_size * sizeof(struct at_urc_table) + sizeof(struct at_urc_table));
         if (new_urc_table == RT_NULL)
         {
             return -RT_ENOMEM;
         }
-        client->urc_table = new_urc_table;
-        client->urc_table[client->urc_table_size].urc = urc_table;
+        client->urc_table                                  = new_urc_table;
+        client->urc_table[client->urc_table_size].urc      = urc_table;
         client->urc_table[client->urc_table_size].urc_size = table_sz;
         client->urc_table_size++;
-
     }
 
     return RT_EOK;
@@ -710,18 +672,22 @@ int at_obj_set_urc_table(at_client_t client, const struct at_urc *urc_table, rt_
  */
 at_client_t at_client_get(const char *dev_name)
 {
-    int idx = 0;
-
     RT_ASSERT(dev_name);
 
-    for (idx = 0; idx < AT_CLIENT_NUM_MAX; idx++)
+    rt_slist_t *node;
+    at_client_t client;
+
+    rt_base_t level = rt_hw_interrupt_disable();
+    rt_slist_for_each(node, &g_at_client_list)
     {
-        if (at_client_table[idx].device &&
-        (rt_strcmp(at_client_table[idx].device->parent.name, dev_name) == 0))
+        client = rt_slist_entry(node, struct at_client, list);
+        if (rt_strcmp(client->device->parent.name, dev_name) == 0)
         {
-            return &at_client_table[idx];
+            rt_hw_interrupt_enable(level);
+            return client;
         }
     }
+    rt_hw_interrupt_enable(level);
 
     return RT_NULL;
 }
@@ -733,20 +699,24 @@ at_client_t at_client_get(const char *dev_name)
  */
 at_client_t at_client_get_first(void)
 {
-    if (at_client_table[0].device == RT_NULL)
+    at_client_t client = RT_NULL;
+
+    rt_base_t level = rt_hw_interrupt_disable();
+    if (!rt_slist_isempty(&g_at_client_list))
     {
-        return RT_NULL;
+        client = rt_slist_first_entry(&g_at_client_list, struct at_client, list);
     }
+    rt_hw_interrupt_enable(level);
 
-    return &at_client_table[0];
+    return client;
 }
 
 static const struct at_urc *get_urc_obj(at_client_t client)
 {
-    rt_size_t i, j, prefix_len, suffix_len;
-    rt_size_t bufsz;
-    char *buffer = RT_NULL;
-    const struct at_urc *urc = RT_NULL;
+    rt_size_t            i, j, prefix_len, suffix_len;
+    rt_size_t            bufsz;
+    char                *buffer    = RT_NULL;
+    const struct at_urc *urc       = RT_NULL;
     struct at_urc_table *urc_table = RT_NULL;
 
     if (client->urc_table == RT_NULL)
@@ -755,14 +725,14 @@ static const struct at_urc *get_urc_obj(at_client_t client)
     }
 
     buffer = client->recv_line_buf;
-    bufsz = client->recv_line_len;
+    bufsz  = client->recv_line_len;
 
     for (i = 0; i < client->urc_table_size; i++)
     {
         for (j = 0; j < client->urc_table[i].urc_size; j++)
         {
             urc_table = client->urc_table + i;
-            urc = urc_table->urc + j;
+            urc       = urc_table->urc + j;
 
             prefix_len = rt_strlen(urc->cmd_prefix);
             suffix_len = rt_strlen(urc->cmd_suffix);
@@ -771,7 +741,7 @@ static const struct at_urc *get_urc_obj(at_client_t client)
                 continue;
             }
             if ((prefix_len ? !rt_strncmp(buffer, urc->cmd_prefix, prefix_len) : 1)
-                    && (suffix_len ? !rt_strncmp(buffer + bufsz - suffix_len, urc->cmd_suffix, suffix_len) : 1))
+                && (suffix_len ? !rt_strncmp(buffer + bufsz - suffix_len, urc->cmd_suffix, suffix_len) : 1))
             {
                 return urc;
             }
@@ -781,44 +751,85 @@ static const struct at_urc *get_urc_obj(at_client_t client)
     return RT_NULL;
 }
 
+static rt_err_t at_client_getchar(at_client_t client, char *ch)
+{
+    rt_err_t   result  = RT_EOK;
+    rt_ssize_t recvLen = 0;
+/* Temporarily retain the distinction */
+#ifndef RT_USING_SERIAL_V2
+    recvLen = rt_device_read(client->device, 0, ch, 1);
+    if (recvLen <= 0)
+    {
+        result = -RT_ERROR;
+    }
+#else
+    recvLen = rt_device_read(client->device, 0, ch, 1);
+    if (recvLen != 1)
+    {
+        result = -RT_ERROR;
+    }
+#endif
+
+    return result;
+}
+
 static int at_recv_readline(at_client_t client)
 {
-    char ch = 0, last_ch = 0;
-    rt_bool_t is_full = RT_FALSE;
+    char        ch = 0, last_ch = 0;
+    rt_bool_t   is_full = RT_FALSE;
+    rt_uint32_t event;
 
     rt_memset(client->recv_line_buf, 0x00, client->recv_bufsz);
     client->recv_line_len = 0;
 
     while (1)
     {
-        at_client_getchar(client, &ch, RT_WAITING_FOREVER);
+        event = 0;
+        rt_event_recv(&client->event, at_client_rx_notice_event | at_client_deInit_event,
+                      RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR, RT_WAITING_FOREVER, &event);
 
-        if (client->recv_line_len < client->recv_bufsz)
-        {
-            client->recv_line_buf[client->recv_line_len++] = ch;
-        }
-        else
+        if (event & at_client_deInit_event)
         {
-            is_full = RT_TRUE;
+            rt_event_send(&client->event, at_client_deInit_over_event);
+            rt_thread_delete(rt_thread_self());
         }
 
-        /* is newline or URC data */
-        client->urc = get_urc_obj(client);
-        if (client->urc != RT_NULL || (ch == '\n' && last_ch == '\r')
-                || (client->end_sign != 0 && ch == client->end_sign))
+        if (event & at_client_rx_notice_event)
         {
-            if (is_full)
+            while (RT_EOK == at_client_getchar(client, &ch))
             {
-                LOG_E("read line failed. The line data length is out of buffer size(%d)!", client->recv_bufsz);
-                rt_memset(client->recv_line_buf, 0x00, client->recv_bufsz);
-                client->recv_line_len = 0;
-                return -RT_EFULL;
+                if (client->recv_line_len < client->recv_bufsz)
+                {
+                    client->recv_line_buf[client->recv_line_len++] = ch;
+                }
+                else
+                {
+                    is_full = RT_TRUE;
+                }
+
+                /* is newline or URC data */
+                client->urc = get_urc_obj(client);
+                if (client->urc != RT_NULL || (ch == '\n' && last_ch == '\r')
+                    || (client->end_sign != 0 && ch == client->end_sign))
+                {
+                    if (is_full)
+                    {
+                        LOG_E("read line failed. The line data length is out of buffer size(%d)!", client->recv_bufsz);
+                        rt_memset(client->recv_line_buf, 0x00, client->recv_bufsz);
+                        client->recv_line_len = 0;
+                        return -RT_EFULL;
+                    }
+
+                    /* Since the buffer state is uncertain, we proactively clear it; the overhead is negligible. */
+                    rt_event_send(&client->event, at_client_rx_notice_event);
+                    goto __next;
+                }
+                last_ch = ch;
             }
-            break;
         }
-        last_ch = ch;
     }
 
+__next:
 #ifdef AT_PRINT_RAW_CMD
     at_print_raw_cmd("recvline", client->recv_line_buf, client->recv_line_len);
 #endif
@@ -828,7 +839,7 @@ static int at_recv_readline(at_client_t client)
 
 static void client_parser(at_client_t client)
 {
-    while(1)
+    while (1)
     {
         if (at_recv_readline(client) > 0)
         {
@@ -870,13 +881,13 @@ static void client_parser(at_client_t client)
                     client->resp_status = AT_RESP_OK;
                 }
                 else if (rt_memcmp(client->recv_line_buf, AT_RESP_END_OK, rt_strlen(AT_RESP_END_OK)) == 0
-                        && resp->line_num == 0)
+                         && resp->line_num == 0)
                 {
                     /* get the end data by response result, return response state END_OK. */
                     client->resp_status = AT_RESP_OK;
                 }
                 else if (rt_strstr(client->recv_line_buf, AT_RESP_END_ERROR)
-                        || (rt_memcmp(client->recv_line_buf, AT_RESP_END_FAIL, rt_strlen(AT_RESP_END_FAIL)) == 0))
+                         || (rt_memcmp(client->recv_line_buf, AT_RESP_END_FAIL, rt_strlen(AT_RESP_END_FAIL)) == 0))
                 {
                     client->resp_status = AT_RESP_ERROR;
                 }
@@ -891,146 +902,76 @@ static void client_parser(at_client_t client)
                 }
 
                 client->resp = RT_NULL;
-                rt_sem_release(client->resp_notice);
+                rt_event_send(&client->event, at_client_resp_notice_event);
             }
             else
             {
-/*                log_d("unrecognized line: %.*s", client->recv_line_len, client->recv_line_buf);*/
+                LOG_D("unrecognized line: %.*s", client->recv_line_len, client->recv_line_buf);
             }
         }
     }
 }
 
-#if (!defined(RT_USING_SERIAL_V2))
 static rt_err_t at_client_rx_ind(rt_device_t dev, rt_size_t size)
 {
-    int idx = 0;
+    rt_slist_t *node;
+    at_client_t client;
+
+    if (size <= 0)
+    {
+        return RT_EOK;
+    }
 
-    for (idx = 0; idx < AT_CLIENT_NUM_MAX; idx++)
+    rt_base_t level = rt_hw_interrupt_disable();
+    rt_slist_for_each(node, &g_at_client_list)
     {
-        if (at_client_table[idx].device == dev && size > 0)
+        client = rt_slist_entry(node, struct at_client, list);
+        if (client->device == dev)
         {
-            rt_sem_release(at_client_table[idx].rx_notice);
+            rt_event_send(&client->event, at_client_rx_notice_event);
+            break;
         }
     }
+    rt_hw_interrupt_enable(level);
 
     return RT_EOK;
 }
-#endif
+
 
 /* initialize the client object parameters */
 static int at_client_para_init(at_client_t client)
 {
-#define AT_CLIENT_LOCK_NAME            "at_c"
-#define AT_CLIENT_SEM_NAME             "at_cs"
-#define AT_CLIENT_RESP_NAME            "at_cr"
-#define AT_CLIENT_THREAD_NAME          "at_clnt"
+#define AT_CLIENT_LOCK_NAME   "at_c"
+#define AT_CLIENT_EVENT_NAME  "at_ce"
+#define AT_CLIENT_THREAD_NAME "at_clnt"
 
-    int result = RT_EOK;
-    static int at_client_num = 0;
+    int  result = RT_EOK;
     char name[RT_NAME_MAX];
 
-    client->status = AT_STATUS_UNINITIALIZED;
-
-    client->recv_line_len = 0;
-    client->recv_line_buf = (char *) rt_calloc(1, client->recv_bufsz);
-    if (client->recv_line_buf == RT_NULL)
-    {
-        LOG_E("AT client initialize failed! No memory for receive buffer.");
-        result = -RT_ENOMEM;
-        goto __exit;
-    }
-
-    client->last_cmd_len = 0;
-    client->send_buf = (char *) rt_calloc(1, client->send_bufsz);
-    if (client->send_buf == RT_NULL)
-    {
-        LOG_E("AT client initialize failed! No memory for send buffer.");
-        result = -RT_ENOMEM;
-        goto __exit;
-    }
-
-    rt_snprintf(name, RT_NAME_MAX, "%s%d", AT_CLIENT_LOCK_NAME, at_client_num);
-    client->lock = rt_mutex_create(name, RT_IPC_FLAG_PRIO);
-    if (client->lock == RT_NULL)
-    {
-        LOG_E("AT client initialize failed! at_client_recv_lock create failed!");
-        result = -RT_ENOMEM;
-        goto __exit;
-    }
-
-#if (!defined(RT_USING_SERIAL_V2))
-    rt_snprintf(name, RT_NAME_MAX, "%s%d", AT_CLIENT_SEM_NAME, at_client_num);
-    client->rx_notice = rt_sem_create(name, 0, RT_IPC_FLAG_FIFO);
-    if (client->rx_notice == RT_NULL)
-    {
-        LOG_E("AT client initialize failed! at_client_notice semaphore create failed!");
-        result = -RT_ENOMEM;
-        goto __exit;
-    }
-#endif
-
-    rt_snprintf(name, RT_NAME_MAX, "%s%d", AT_CLIENT_RESP_NAME, at_client_num);
-    client->resp_notice = rt_sem_create(name, 0, RT_IPC_FLAG_FIFO);
-    if (client->resp_notice == RT_NULL)
-    {
-        LOG_E("AT client initialize failed! at_client_resp semaphore create failed!");
-        result = -RT_ENOMEM;
-        goto __exit;
-    }
-
-    client->urc_table = RT_NULL;
-    client->urc_table_size = 0;
+    rt_base_t    level         = rt_hw_interrupt_disable();
+    unsigned int at_client_num = rt_slist_len(&g_at_client_list);
+    rt_hw_interrupt_enable(level);
 
     rt_snprintf(name, RT_NAME_MAX, "%s%d", AT_CLIENT_THREAD_NAME, at_client_num);
     client->parser = rt_thread_create(name,
-                                     (void (*)(void *parameter))client_parser,
-                                     client,
-                                     1024 + 512,
-                                     RT_THREAD_PRIORITY_MAX / 3 - 1,
-                                     5);
+                                      (void (*)(void *parameter))client_parser,
+                                      client,
+                                      1024 + 512,
+                                      RT_THREAD_PRIORITY_MAX / 3 - 1,
+                                      5);
     if (client->parser == RT_NULL)
     {
         result = -RT_ENOMEM;
+        goto __exit;
     }
 
-__exit:
-    if (result != RT_EOK)
-    {
-        if (client->lock)
-        {
-            rt_mutex_delete(client->lock);
-        }
-
-#if (!defined(RT_USING_SERIAL_V2))
-        if (client->rx_notice)
-        {
-            rt_sem_delete(client->rx_notice);
-        }
-#endif
-
-        if (client->resp_notice)
-        {
-            rt_sem_delete(client->resp_notice);
-        }
-
-        if (client->recv_line_buf)
-        {
-            rt_free(client->recv_line_buf);
-        }
-
-        if (client->send_buf)
-        {
-            rt_free(client->send_buf);
-        }
+    rt_snprintf(name, RT_NAME_MAX, "%s%d", AT_CLIENT_LOCK_NAME, at_client_num);
+    rt_mutex_init(&client->lock, name, RT_IPC_FLAG_PRIO);
 
-        rt_memset(client, 0x00, sizeof(struct at_client));
-    }
-    else
-    {
-        at_client_num++;
-    }
+    rt_snprintf(name, RT_NAME_MAX, "%s%d", AT_CLIENT_EVENT_NAME, at_client_num);
+    rt_event_init(&client->event, name, RT_IPC_FLAG_FIFO);
 
+__exit:
     return result;
 }
 
@@ -1047,10 +988,9 @@ __exit:
  */
 int at_client_init(const char *dev_name, rt_size_t recv_bufsz, rt_size_t send_bufsz)
 {
-    int idx = 0;
-    int result = RT_EOK;
-    rt_err_t open_result = RT_EOK;
-    at_client_t client = RT_NULL;
+    int         result      = RT_EOK;
+    rt_err_t    open_result = RT_EOK;
+    at_client_t client      = RT_NULL;
 
     RT_ASSERT(dev_name);
     RT_ASSERT(recv_bufsz > 0);
@@ -1061,18 +1001,20 @@ int at_client_init(const char *dev_name, rt_size_t recv_bufsz, rt_size_t send_bu
         return result;
     }
 
-    for (idx = 0; idx < AT_CLIENT_NUM_MAX && at_client_table[idx].device; idx++);
-
-    if (idx >= AT_CLIENT_NUM_MAX)
+    client = rt_malloc(sizeof(struct at_client) + recv_bufsz + send_bufsz);
+    if (client == RT_NULL)
     {
-        LOG_E("AT client initialize failed! Check the maximum number(%d) of AT client.", AT_CLIENT_NUM_MAX);
-        result = -RT_EFULL;
+        result = -RT_ENOMEM;
         goto __exit;
     }
+    rt_memset(client, 0, sizeof(struct at_client) + recv_bufsz + send_bufsz);
+    client->status = AT_STATUS_UNINITIALIZED;
+
+    client->recv_bufsz    = recv_bufsz;
+    client->recv_line_buf = ((char *)client) + sizeof(struct at_client);
 
-    client = &at_client_table[idx];
-    client->recv_bufsz = recv_bufsz;
     client->send_bufsz = send_bufsz;
+    client->send_buf   = ((char *)client) + sizeof(struct at_client) + client->recv_bufsz;
 
     result = at_client_para_init(client);
     if (result != RT_EOK)
@@ -1085,8 +1027,7 @@ int at_client_init(const char *dev_name, rt_size_t recv_bufsz, rt_size_t send_bu
     if (client->device)
     {
         RT_ASSERT(client->device->type == RT_Device_Class_Char);
-#if (!defined(RT_USING_SERIAL_V2))
-        rt_device_set_rx_indicate(client->device, at_client_rx_ind);
+#ifndef RT_USING_SERIAL_V2
         /* using DMA mode first */
         open_result = rt_device_open(client->device, RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_DMA_RX);
         /* using interrupt mode when DMA mode not supported */
@@ -1098,6 +1039,8 @@ int at_client_init(const char *dev_name, rt_size_t recv_bufsz, rt_size_t send_bu
 #else
         open_result = rt_device_open(client->device, RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_RX_BLOCKING | RT_DEVICE_FLAG_TX_BLOCKING);
         RT_ASSERT(open_result == RT_EOK);
+        rt_int32_t rx_timeout = RT_WAITING_NO;
+        rt_device_control(client->device, RT_SERIAL_CTRL_SET_RX_TIMEOUT, (void *)&rx_timeout);
 #endif
     }
     else
@@ -1109,17 +1052,61 @@ int at_client_init(const char *dev_name, rt_size_t recv_bufsz, rt_size_t send_bu
 __exit:
     if (result == RT_EOK)
     {
-        client->status = AT_STATUS_INITIALIZED;
+        rt_slist_init(&client->list);
+        rt_base_t level = rt_hw_interrupt_disable();
+        rt_slist_append(&g_at_client_list, &client->list);
+        rt_hw_interrupt_enable(level);
+
+        rt_device_set_rx_indicate(client->device, at_client_rx_ind);
 
+        client->status = AT_STATUS_INITIALIZED;
         rt_thread_startup(client->parser);
 
         LOG_I("AT client(V%s) on device %s initialize success.", AT_SW_VERSION, dev_name);
     }
     else
     {
+        if (RT_NULL != client->parser)
+        {
+            rt_thread_delete(client->parser);
+        }
+
+        if (RT_NULL != client)
+        {
+            rt_free(client);
+        }
         LOG_E("AT client(V%s) on device %s initialize failed(%d).", AT_SW_VERSION, dev_name, result);
     }
 
     return result;
 }
-#endif /* AT_USING_CLIENT */
+
+int at_client_deInit(const char *dev_name)
+{
+    int         result = RT_EOK;
+    at_client_t client = RT_NULL;
+
+    RT_ASSERT(dev_name);
+
+    client = at_client_get(dev_name);
+    if (client == RT_NULL)
+    {
+        return RT_EOK;
+    }
+
+    rt_base_t level = rt_hw_interrupt_disable();
+    rt_slist_remove(&g_at_client_list, &client->list);
+    rt_hw_interrupt_enable(level);
+
+    rt_event_send(&client->event, at_client_deInit_event);
+    rt_event_recv(&client->event, at_client_deInit_over_event, RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR, RT_WAITING_FOREVER, NULL);
+
+    rt_event_detach(&client->event);
+    rt_mutex_detach(&client->lock);
+
+    result = rt_device_close(client->device);
+
+    rt_free(client);
+    return result;
+}
+#endif /* AT_USING_CLIENT */