xref: /nrf52832-nimble/rt-thread/components/net/at/src/at_client.c (revision 104654410c56c573564690304ae786df310c91fc)
1 /*
2  * Copyright (c) 2006-2018, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  * 2018-03-30     chenyong     first version
9  * 2018-04-12     chenyong     add client implement
10  * 2018-08-17     chenyong     multiple client support
11  */
12 
13 #include <at.h>
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 
18 #define LOG_TAG              "at.clnt"
19 #include <at_log.h>
20 
21 #ifdef AT_USING_CLIENT
22 
23 #define AT_RESP_END_OK                 "OK"
24 #define AT_RESP_END_ERROR              "ERROR"
25 #define AT_RESP_END_FAIL               "FAIL"
26 #define AT_END_CR_LF                   "\r\n"
27 
28 static struct at_client at_client_table[AT_CLIENT_NUM_MAX] = { 0 };
29 
30 extern rt_size_t at_vprintfln(rt_device_t device, const char *format, va_list args);
31 extern void at_print_raw_cmd(const char *type, const char *cmd, rt_size_t size);
32 extern const char *at_get_last_cmd(rt_size_t *cmd_size);
33 
34 /**
35  * Create response object.
36  *
37  * @param buf_size the maximum response buffer size
38  * @param line_num the number of setting response lines
39  *         = 0: the response data will auto return when received 'OK' or 'ERROR'
40  *        != 0: the response data will return when received setting lines number data
41  * @param timeout the maximum response time
42  *
43  * @return != RT_NULL: response object
44  *          = RT_NULL: no memory
45  */
at_create_resp(rt_size_t buf_size,rt_size_t line_num,rt_int32_t timeout)46 at_response_t at_create_resp(rt_size_t buf_size, rt_size_t line_num, rt_int32_t timeout)
47 {
48     at_response_t resp = RT_NULL;
49 
50     resp = (at_response_t) rt_calloc(1, sizeof(struct at_response));
51     if (resp == RT_NULL)
52     {
53         LOG_E("AT create response object failed! No memory for response object!");
54         return RT_NULL;
55     }
56 
57     resp->buf = (char *) rt_calloc(1, buf_size);
58     if (resp->buf == RT_NULL)
59     {
60         LOG_E("AT create response object failed! No memory for response buffer!");
61         rt_free(resp);
62         return RT_NULL;
63     }
64 
65     resp->buf_size = buf_size;
66     resp->line_num = line_num;
67     resp->line_counts = 0;
68     resp->timeout = timeout;
69 
70     return resp;
71 }
72 
73 /**
74  * Delete and free response object.
75  *
76  * @param resp response object
77  */
at_delete_resp(at_response_t resp)78 void at_delete_resp(at_response_t resp)
79 {
80     if (resp && resp->buf)
81     {
82         rt_free(resp->buf);
83     }
84 
85     if (resp)
86     {
87         rt_free(resp);
88         resp = RT_NULL;
89     }
90 }
91 
92 /**
93  * Set response object information
94  *
95  * @param resp response object
96  * @param buf_size the maximum response buffer size
97  * @param line_num the number of setting response lines
98  *         = 0: the response data will auto return when received 'OK' or 'ERROR'
99  *        != 0: the response data will return when received setting lines number data
100  * @param timeout the maximum response time
101  *
102  * @return  != RT_NULL: response object
103  *           = RT_NULL: no memory
104  */
at_resp_set_info(at_response_t resp,rt_size_t buf_size,rt_size_t line_num,rt_int32_t timeout)105 at_response_t at_resp_set_info(at_response_t resp, rt_size_t buf_size, rt_size_t line_num, rt_int32_t timeout)
106 {
107     RT_ASSERT(resp);
108 
109     if (resp->buf_size != buf_size)
110     {
111         resp->buf_size = buf_size;
112 
113         resp->buf = (char *) rt_realloc(resp->buf, buf_size);
114         if (!resp->buf)
115         {
116             LOG_D("No memory for realloc response buffer size(%d).", buf_size);
117             return RT_NULL;
118         }
119     }
120 
121     resp->line_num = line_num;
122     resp->timeout = timeout;
123 
124     return resp;
125 }
126 
127 /**
128  * Get one line AT response buffer by line number.
129  *
130  * @param resp response object
131  * @param resp_line line number, start from '1'
132  *
133  * @return != RT_NULL: response line buffer
134  *          = RT_NULL: input response line error
135  */
at_resp_get_line(at_response_t resp,rt_size_t resp_line)136 const char *at_resp_get_line(at_response_t resp, rt_size_t resp_line)
137 {
138     char *resp_buf = resp->buf;
139     char *resp_line_buf = RT_NULL;
140     rt_size_t line_num = 1;
141 
142     RT_ASSERT(resp);
143 
144     if (resp_line > resp->line_counts || resp_line <= 0)
145     {
146         LOG_E("AT response get line failed! Input response line(%d) error!", resp_line);
147         return RT_NULL;
148     }
149 
150     for (line_num = 1; line_num <= resp->line_counts; line_num++)
151     {
152         if (resp_line == line_num)
153         {
154             resp_line_buf = resp_buf;
155 
156             return resp_line_buf;
157         }
158 
159         resp_buf += strlen(resp_buf) + 1;
160     }
161 
162     return RT_NULL;
163 }
164 
165 /**
166  * Get one line AT response buffer by keyword
167  *
168  * @param resp response object
169  * @param keyword query keyword
170  *
171  * @return != RT_NULL: response line buffer
172  *          = RT_NULL: no matching data
173  */
at_resp_get_line_by_kw(at_response_t resp,const char * keyword)174 const char *at_resp_get_line_by_kw(at_response_t resp, const char *keyword)
175 {
176     char *resp_buf = resp->buf;
177     char *resp_line_buf = RT_NULL;
178     rt_size_t line_num = 1;
179 
180     RT_ASSERT(resp);
181     RT_ASSERT(keyword);
182 
183     for (line_num = 1; line_num <= resp->line_counts; line_num++)
184     {
185         if (strstr(resp_buf, keyword))
186         {
187             resp_line_buf = resp_buf;
188 
189             return resp_line_buf;
190         }
191 
192         resp_buf += strlen(resp_buf) + 1;
193     }
194 
195     return RT_NULL;
196 }
197 
198 /**
199  * Get and parse AT response buffer arguments by line number.
200  *
201  * @param resp response object
202  * @param resp_line line number, start from '1'
203  * @param resp_expr response buffer expression
204  *
205  * @return -1 : input response line number error or get line buffer error
206  *          0 : parsed without match
207  *         >0 : the number of arguments successfully parsed
208  */
at_resp_parse_line_args(at_response_t resp,rt_size_t resp_line,const char * resp_expr,...)209 int at_resp_parse_line_args(at_response_t resp, rt_size_t resp_line, const char *resp_expr, ...)
210 {
211     va_list args;
212     int resp_args_num = 0;
213     const char *resp_line_buf = RT_NULL;
214 
215     RT_ASSERT(resp);
216     RT_ASSERT(resp_expr);
217 
218     if ((resp_line_buf = at_resp_get_line(resp, resp_line)) == RT_NULL)
219     {
220         return -1;
221     }
222 
223     va_start(args, resp_expr);
224 
225     resp_args_num = vsscanf(resp_line_buf, resp_expr, args);
226 
227     va_end(args);
228 
229     return resp_args_num;
230 }
231 
232 /**
233  * Get and parse AT response buffer arguments by keyword.
234  *
235  * @param resp response object
236  * @param keyword query keyword
237  * @param resp_expr response buffer expression
238  *
239  * @return -1 : input keyword error or get line buffer error
240  *          0 : parsed without match
241  *         >0 : the number of arguments successfully parsed
242  */
at_resp_parse_line_args_by_kw(at_response_t resp,const char * keyword,const char * resp_expr,...)243 int at_resp_parse_line_args_by_kw(at_response_t resp, const char *keyword, const char *resp_expr, ...)
244 {
245     va_list args;
246     int resp_args_num = 0;
247     const char *resp_line_buf = RT_NULL;
248 
249     RT_ASSERT(resp);
250     RT_ASSERT(resp_expr);
251 
252     if ((resp_line_buf = at_resp_get_line_by_kw(resp, keyword)) == RT_NULL)
253     {
254         return -1;
255     }
256 
257     va_start(args, resp_expr);
258 
259     resp_args_num = vsscanf(resp_line_buf, resp_expr, args);
260 
261     va_end(args);
262 
263     return resp_args_num;
264 }
265 
266 /**
267  * Send commands to AT server and wait response.
268  *
269  * @param client current AT client object
270  * @param resp AT response object, using RT_NULL when you don't care response
271  * @param cmd_expr AT commands expression
272  *
273  * @return 0 : success
274  *        -1 : response status error
275  *        -2 : wait timeout
276  */
at_obj_exec_cmd(at_client_t client,at_response_t resp,const char * cmd_expr,...)277 int at_obj_exec_cmd(at_client_t client, at_response_t resp, const char *cmd_expr, ...)
278 {
279     va_list args;
280     rt_size_t cmd_size = 0;
281     rt_err_t result = RT_EOK;
282     const char *cmd = RT_NULL;
283 
284     RT_ASSERT(cmd_expr);
285 
286     if (client == RT_NULL)
287     {
288         LOG_E("input AT Client object is NULL, please create or get AT Client object!");
289         return -RT_ERROR;
290     }
291 
292     rt_mutex_take(client->lock, RT_WAITING_FOREVER);
293 
294     client->resp_status = AT_RESP_OK;
295     client->resp = resp;
296 
297     va_start(args, cmd_expr);
298     at_vprintfln(client->device, cmd_expr, args);
299     va_end(args);
300 
301     if (resp != RT_NULL)
302     {
303         resp->line_counts = 0;
304         if (rt_sem_take(client->resp_notice, resp->timeout) != RT_EOK)
305         {
306             cmd = at_get_last_cmd(&cmd_size);
307             LOG_E("execute command (%.*s) timeout (%d ticks)!", cmd_size, cmd, resp->timeout);
308             client->resp_status = AT_RESP_TIMEOUT;
309             result = -RT_ETIMEOUT;
310             goto __exit;
311         }
312         if (client->resp_status != AT_RESP_OK)
313         {
314             cmd = at_get_last_cmd(&cmd_size);
315             LOG_E("execute command (%.*s) failed!", cmd_size, cmd);
316             result = -RT_ERROR;
317             goto __exit;
318         }
319     }
320 
321 __exit:
322     client->resp = RT_NULL;
323 
324     rt_mutex_release(client->lock);
325 
326     return result;
327 }
328 
329 /**
330  * Waiting for connection to external devices.
331  *
332  * @param client current AT client object
333  * @param timeout millisecond for timeout
334  *
335  * @return 0 : success
336  *        -2 : timeout
337  *        -5 : no memory
338  */
at_client_obj_wait_connect(at_client_t client,rt_uint32_t timeout)339 int at_client_obj_wait_connect(at_client_t client, rt_uint32_t timeout)
340 {
341     rt_err_t result = RT_EOK;
342     at_response_t resp = RT_NULL;
343     rt_tick_t start_time = 0;
344 
345     if (client == RT_NULL)
346     {
347         LOG_E("input AT Client object is NULL, please create or get AT Client object!");
348         return -RT_ERROR;
349     }
350 
351     resp = at_create_resp(16, 0, rt_tick_from_millisecond(500));
352     if (resp == RT_NULL)
353     {
354         LOG_E("No memory for response object!");
355         return -RT_ENOMEM;
356     }
357 
358     rt_mutex_take(client->lock, RT_WAITING_FOREVER);
359     client->resp = resp;
360 
361     start_time = rt_tick_get();
362 
363     while (1)
364     {
365         /* Check whether it is timeout */
366         if (rt_tick_get() - start_time > rt_tick_from_millisecond(timeout))
367         {
368             LOG_E("wait connect timeout (%d millisecond)!", timeout);
369             result = -RT_ETIMEOUT;
370             break;
371         }
372 
373         /* Check whether it is already connected */
374         resp->line_counts = 0;
375         rt_device_write(client->device, 0, "AT\r\n", 4);
376 
377         if (rt_sem_take(client->resp_notice, resp->timeout) != RT_EOK)
378             continue;
379         else
380             break;
381     }
382 
383     at_delete_resp(resp);
384 
385     client->resp = RT_NULL;
386 
387     rt_mutex_release(client->lock);
388 
389     return result;
390 }
391 
392 /**
393  * Send data to AT server, send data don't have end sign(eg: \r\n).
394  *
395  * @param client current AT client object
396  * @param buf   send data buffer
397  * @param size  send fixed data size
398  *
399  * @return >0: send data size
400  *         =0: send failed
401  */
at_client_obj_send(at_client_t client,const char * buf,rt_size_t size)402 rt_size_t at_client_obj_send(at_client_t client, const char *buf, rt_size_t size)
403 {
404     RT_ASSERT(buf);
405 
406     if (client == RT_NULL)
407     {
408         LOG_E("input AT Client object is NULL, please create or get AT Client object!");
409         return 0;
410     }
411 
412 #ifdef AT_PRINT_RAW_CMD
413     at_print_raw_cmd("send", buf, size);
414 #endif
415 
416     return rt_device_write(client->device, 0, buf, size);
417 }
418 
at_client_getchar(at_client_t client,char * ch,rt_int32_t timeout)419 static rt_err_t at_client_getchar(at_client_t client, char *ch, rt_int32_t timeout)
420 {
421     rt_err_t result = RT_EOK;
422 
423     while (rt_device_read(client->device, 0, ch, 1) == 0)
424     {
425         rt_sem_control(client->rx_notice, RT_IPC_CMD_RESET, RT_NULL);
426 
427         result = rt_sem_take(client->rx_notice, rt_tick_from_millisecond(timeout));
428         if (result != RT_EOK)
429         {
430             return result;
431         }
432     }
433 
434     return RT_EOK;
435 }
436 
437 /**
438  * AT client receive fixed-length data.
439  *
440  * @param client current AT client object
441  * @param buf   receive data buffer
442  * @param size  receive fixed data size
443  * @param timeout  receive data timeout (ms)
444  *
445  * @note this function can only be used in execution function of URC data
446  *
447  * @return >0: receive data size
448  *         =0: receive failed
449  */
at_client_obj_recv(at_client_t client,char * buf,rt_size_t size,rt_int32_t timeout)450 rt_size_t at_client_obj_recv(at_client_t client, char *buf, rt_size_t size, rt_int32_t timeout)
451 {
452     rt_size_t read_idx = 0;
453     rt_err_t result = RT_EOK;
454     char ch;
455 
456     RT_ASSERT(buf);
457 
458     if (client == RT_NULL)
459     {
460         LOG_E("input AT Client object is NULL, please create or get AT Client object!");
461         return 0;
462     }
463 
464     while (1)
465     {
466         if (read_idx < size)
467         {
468             result = at_client_getchar(client, &ch, timeout);
469             if (result != RT_EOK)
470             {
471                 LOG_E("AT Client receive failed, uart device get data error(%d)", result);
472                 return 0;
473             }
474 
475             buf[read_idx++] = ch;
476         }
477         else
478         {
479             break;
480         }
481     }
482 
483 #ifdef AT_PRINT_RAW_CMD
484     at_print_raw_cmd("urc_recv", buf, size);
485 #endif
486 
487     return read_idx;
488 }
489 
490 /**
491  *  AT client set end sign.
492  *
493  * @param client current AT client object
494  * @param ch the end sign, can not be used when it is '\0'
495  */
at_obj_set_end_sign(at_client_t client,char ch)496 void at_obj_set_end_sign(at_client_t client, char ch)
497 {
498     if (client == RT_NULL)
499     {
500         LOG_E("input AT Client object is NULL, please create or get AT Client object!");
501         return;
502     }
503 
504     client->end_sign = ch;
505 }
506 
507 /**
508  * set URC(Unsolicited Result Code) table
509  *
510  * @param client current AT client object
511  * @param table URC table
512  * @param size table size
513  */
at_obj_set_urc_table(at_client_t client,const struct at_urc * urc_table,rt_size_t table_sz)514 void at_obj_set_urc_table(at_client_t client, const struct at_urc *urc_table, rt_size_t table_sz)
515 {
516     rt_size_t idx;
517 
518     if (client == RT_NULL)
519     {
520         LOG_E("input AT Client object is NULL, please create or get AT Client object!");
521         return;
522     }
523 
524     for (idx = 0; idx < table_sz; idx++)
525     {
526         RT_ASSERT(urc_table[idx].cmd_prefix);
527         RT_ASSERT(urc_table[idx].cmd_suffix);
528     }
529 
530     client->urc_table = urc_table;
531     client->urc_table_size = table_sz;
532 }
533 
534 /**
535  * get AT client object by AT device name.
536  *
537  * @dev_name AT client device name
538  *
539  * @return AT client object
540  */
at_client_get(const char * dev_name)541 at_client_t at_client_get(const char *dev_name)
542 {
543     int idx = 0;
544 
545     RT_ASSERT(dev_name);
546 
547     for (idx = 0; idx < AT_CLIENT_NUM_MAX; idx++)
548     {
549         if (rt_strcmp(at_client_table[idx].device->parent.name, dev_name) == 0)
550         {
551             return &at_client_table[idx];
552         }
553     }
554 
555     return RT_NULL;
556 }
557 
558 /**
559  * get first AT client object in the table.
560  *
561  * @return AT client object
562  */
at_client_get_first(void)563 at_client_t at_client_get_first(void)
564 {
565     if (at_client_table[0].device == RT_NULL)
566     {
567         return RT_NULL;
568     }
569 
570     return &at_client_table[0];
571 }
572 
get_urc_obj(at_client_t client)573 static const struct at_urc *get_urc_obj(at_client_t client)
574 {
575     rt_size_t i, prefix_len, suffix_len;
576     rt_size_t buf_sz;
577     char *buffer = RT_NULL;
578 
579     if (client->urc_table == RT_NULL)
580     {
581         return RT_NULL;
582     }
583 
584     buffer = client->recv_buffer;
585     buf_sz = client->cur_recv_len;
586 
587     for (i = 0; i < client->urc_table_size; i++)
588     {
589         prefix_len = strlen(client->urc_table[i].cmd_prefix);
590         suffix_len = strlen(client->urc_table[i].cmd_suffix);
591         if (buf_sz < prefix_len + suffix_len)
592         {
593             continue;
594         }
595         if ((prefix_len ? !strncmp(buffer, client->urc_table[i].cmd_prefix, prefix_len) : 1)
596                 && (suffix_len ? !strncmp(buffer + buf_sz - suffix_len, client->urc_table[i].cmd_suffix, suffix_len) : 1))
597         {
598             return &client->urc_table[i];
599         }
600     }
601 
602     return RT_NULL;
603 }
604 
at_recv_readline(at_client_t client)605 static int at_recv_readline(at_client_t client)
606 {
607     rt_size_t read_len = 0;
608     char ch = 0, last_ch = 0;
609     rt_bool_t is_full = RT_FALSE;
610 
611     memset(client->recv_buffer, 0x00, client->recv_bufsz);
612     client->cur_recv_len = 0;
613 
614     while (1)
615     {
616         at_client_getchar(client, &ch, RT_WAITING_FOREVER);
617 
618         if (read_len < client->recv_bufsz)
619         {
620             client->recv_buffer[read_len++] = ch;
621             client->cur_recv_len = read_len;
622         }
623         else
624         {
625             is_full = RT_TRUE;
626         }
627 
628         /* is newline or URC data */
629         if ((ch == '\n' && last_ch == '\r') || (client->end_sign != 0 && ch == client->end_sign)
630                 || get_urc_obj(client))
631         {
632             if (is_full)
633             {
634                 LOG_E("read line failed. The line data length is out of buffer size(%d)!", client->recv_bufsz);
635                 memset(client->recv_buffer, 0x00, client->recv_bufsz);
636                 client->cur_recv_len = 0;
637                 return -RT_EFULL;
638             }
639             break;
640         }
641         last_ch = ch;
642     }
643 
644 #ifdef AT_PRINT_RAW_CMD
645     at_print_raw_cmd("recvline", client->recv_buffer, read_len);
646 #endif
647 
648     return read_len;
649 }
650 
client_parser(at_client_t client)651 static void client_parser(at_client_t client)
652 {
653     int resp_buf_len = 0;
654     const struct at_urc *urc;
655     rt_size_t line_counts = 0;
656 
657     while(1)
658     {
659         if (at_recv_readline(client) > 0)
660         {
661             if ((urc = get_urc_obj(client)) != RT_NULL)
662             {
663                 /* current receive is request, try to execute related operations */
664                 if (urc->func != RT_NULL)
665                 {
666                     urc->func(client->recv_buffer, client->cur_recv_len);
667                 }
668             }
669             else if (client->resp != RT_NULL)
670             {
671                 /* current receive is response */
672                 client->recv_buffer[client->cur_recv_len - 1] = '\0';
673                 if (resp_buf_len + client->cur_recv_len < client->resp->buf_size)
674                 {
675                     /* copy response lines, separated by '\0' */
676                     memcpy(client->resp->buf + resp_buf_len, client->recv_buffer, client->cur_recv_len);
677                     resp_buf_len += client->cur_recv_len;
678 
679                     line_counts++;
680                 }
681                 else
682                 {
683                     client->resp_status = AT_RESP_BUFF_FULL;
684                     LOG_E("Read response buffer failed. The Response buffer size is out of buffer size(%d)!", client->resp->buf_size);
685                 }
686                 /* check response result */
687                 if (memcmp(client->recv_buffer, AT_RESP_END_OK, strlen(AT_RESP_END_OK)) == 0
688                         && client->resp->line_num == 0)
689                 {
690                     /* get the end data by response result, return response state END_OK. */
691                     client->resp_status = AT_RESP_OK;
692                 }
693                 else if (strstr(client->recv_buffer, AT_RESP_END_ERROR)
694                         || (memcmp(client->recv_buffer, AT_RESP_END_FAIL, strlen(AT_RESP_END_FAIL)) == 0))
695                 {
696                     client->resp_status = AT_RESP_ERROR;
697                 }
698                 else if (line_counts == client->resp->line_num && client->resp->line_num)
699                 {
700                     /* get the end data by response line, return response state END_OK.*/
701                     client->resp_status = AT_RESP_OK;
702                 }
703                 else
704                 {
705                     continue;
706                 }
707                 client->resp->line_counts = line_counts;
708 
709                 client->resp = RT_NULL;
710                 rt_sem_release(client->resp_notice);
711                 resp_buf_len = 0, line_counts = 0;
712             }
713             else
714             {
715 //                log_d("unrecognized line: %.*s", client->cur_recv_len, client->recv_buffer);
716             }
717         }
718     }
719 }
720 
at_client_rx_ind(rt_device_t dev,rt_size_t size)721 static rt_err_t at_client_rx_ind(rt_device_t dev, rt_size_t size)
722 {
723     int idx = 0;
724 
725     for (idx = 0; idx < AT_CLIENT_NUM_MAX; idx++)
726     {
727         if (at_client_table[idx].device == dev && size > 0)
728         {
729             rt_sem_release(at_client_table[idx].rx_notice);
730         }
731     }
732 
733     return RT_EOK;
734 }
735 
736 /* initialize the client object parameters */
at_client_para_init(at_client_t client)737 static int at_client_para_init(at_client_t client)
738 {
739 #define AT_CLIENT_LOCK_NAME            "at_c"
740 #define AT_CLIENT_SEM_NAME             "at_cs"
741 #define AT_CLIENT_RESP_NAME            "at_cr"
742 #define AT_CLIENT_THREAD_NAME          "at_clnt"
743 
744     int result = RT_EOK;
745     static int at_client_num = 0;
746     char name[RT_NAME_MAX];
747 
748     client->status = AT_STATUS_UNINITIALIZED;
749 
750     client->cur_recv_len = 0;
751     client->recv_buffer = (char *) rt_calloc(1, client->recv_bufsz);
752     if (client->recv_buffer == RT_NULL)
753     {
754         LOG_E("AT client initialize failed! No memory for receive buffer.");
755         result = -RT_ENOMEM;
756         goto __exit;
757     }
758 
759     rt_snprintf(name, RT_NAME_MAX, "%s%d", AT_CLIENT_LOCK_NAME, at_client_num);
760     client->lock = rt_mutex_create(name, RT_IPC_FLAG_FIFO);
761     if (client->lock == RT_NULL)
762     {
763         LOG_E("AT client initialize failed! at_client_recv_lock create failed!");
764         result = -RT_ENOMEM;
765         goto __exit;
766     }
767 
768     rt_snprintf(name, RT_NAME_MAX, "%s%d", AT_CLIENT_SEM_NAME, at_client_num);
769     client->rx_notice = rt_sem_create(name, 0, RT_IPC_FLAG_FIFO);
770     if (client->rx_notice == RT_NULL)
771     {
772         LOG_E("AT client initialize failed! at_client_notice semaphore create failed!");
773         result = -RT_ENOMEM;
774         goto __exit;
775     }
776 
777     rt_snprintf(name, RT_NAME_MAX, "%s%d", AT_CLIENT_RESP_NAME, at_client_num);
778     client->resp_notice = rt_sem_create(name, 0, RT_IPC_FLAG_FIFO);
779     if (client->resp_notice == RT_NULL)
780     {
781         LOG_E("AT client initialize failed! at_client_resp semaphore create failed!");
782         result = -RT_ENOMEM;
783         goto __exit;
784     }
785 
786     client->urc_table = RT_NULL;
787     client->urc_table_size = 0;
788 
789     rt_snprintf(name, RT_NAME_MAX, "%s%d", AT_CLIENT_THREAD_NAME, at_client_num);
790     client->parser = rt_thread_create(name,
791                                      (void (*)(void *parameter))client_parser,
792                                      client,
793                                      1024 + 512,
794                                      RT_THREAD_PRIORITY_MAX / 3 - 1,
795                                      5);
796     if (client->parser == RT_NULL)
797     {
798         result = -RT_ENOMEM;
799         goto __exit;
800     }
801 
802 __exit:
803     if (result != RT_EOK)
804     {
805         if (client->lock)
806         {
807             rt_mutex_delete(client->lock);
808         }
809 
810         if (client->rx_notice)
811         {
812             rt_sem_delete(client->rx_notice);
813         }
814 
815         if (client->resp_notice)
816         {
817             rt_sem_delete(client->resp_notice);
818         }
819 
820         if (client->device)
821         {
822             rt_device_close(client->device);
823         }
824 
825         if (client->recv_buffer)
826         {
827             rt_free(client->recv_buffer);
828         }
829 
830         rt_memset(client, 0x00, sizeof(struct at_client));
831     }
832     else
833     {
834         at_client_num++;
835     }
836 
837     return result;
838 }
839 
840 /**
841  * AT client initialize.
842  *
843  * @param dev_name AT client device name
844  * @param recv_bufsz the maximum number of receive buffer length
845  *
846  * @return 0 : initialize success
847  *        -1 : initialize failed
848  *        -5 : no memory
849  */
at_client_init(const char * dev_name,rt_size_t recv_bufsz)850 int at_client_init(const char *dev_name,  rt_size_t recv_bufsz)
851 {
852     int idx = 0;
853     int result = RT_EOK;
854     rt_err_t open_result = RT_EOK;
855     at_client_t client = RT_NULL;
856 
857     RT_ASSERT(dev_name);
858     RT_ASSERT(recv_bufsz > 0);
859 
860     for (idx = 0; idx < AT_CLIENT_NUM_MAX && at_client_table[idx].device; idx++);
861 
862     if (idx >= AT_CLIENT_NUM_MAX)
863     {
864         LOG_E("AT client initialize failed! Check the maximum number(%d) of AT client.", AT_CLIENT_NUM_MAX);
865         result = -RT_EFULL;
866         goto __exit;
867     }
868 
869     client = &at_client_table[idx];
870     client->recv_bufsz = recv_bufsz;
871 
872     /* find and open command device */
873     client->device = rt_device_find(dev_name);
874     if (client->device)
875     {
876         RT_ASSERT(client->device->type == RT_Device_Class_Char);
877 
878         /* using DMA mode first */
879         open_result = rt_device_open(client->device, RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_DMA_RX);
880         /* using interrupt mode when DMA mode not supported */
881         if (open_result == -RT_EIO)
882         {
883             open_result = rt_device_open(client->device, RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_INT_RX);
884         }
885         RT_ASSERT(open_result == RT_EOK);
886 
887         rt_device_set_rx_indicate(client->device, at_client_rx_ind);
888     }
889     else
890     {
891         LOG_E("AT client initialize failed! Not find the device(%s).", dev_name);
892         result = -RT_ERROR;
893         goto __exit;
894     }
895 
896     result = at_client_para_init(client);
897     if (result != RT_EOK)
898     {
899         goto __exit;
900     }
901 
902 __exit:
903     if (result == RT_EOK)
904     {
905         client->status = AT_STATUS_INITIALIZED;
906 
907         rt_thread_startup(client->parser);
908 
909         LOG_I("AT client(V%s) on device %s initialize success.", AT_SW_VERSION, dev_name);
910     }
911     else
912     {
913         LOG_E("AT client(V%s) on device %s initialize failed(%d).", AT_SW_VERSION, dev_name, result);
914     }
915 
916     return result;
917 }
918 #endif /* AT_USING_CLIENT */
919