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