diff --git a/components/net/at/include/at.h b/components/net/at/include/at.h index b94c0448cc1..5913a9cf26b 100644 --- a/components/net/at/include/at.h +++ b/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 ============================ */ diff --git a/components/net/at/src/at_client.c b/components/net/at/src/at_client.c index ed183f1eac8..4c83db6c22d 100644 --- a/components/net/at/src/at_client.c +++ b/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 @@ -19,19 +20,24 @@ #include #include -#define LOG_TAG "at.clnt" +#define LOG_TAG "at.clnt" #include #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 @@ static int at_client_para_init(at_client_t client) */ 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 */ \ No newline at end of file + +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 */