xref: /nrf52832-nimble/rt-thread/components/net/at/src/at_server.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-14     chenyong     modify parse arguments
10  */
11 
12 #include <at.h>
13 #include <stdlib.h>
14 #include <stdio.h>
15 #include <string.h>
16 
17 #include <rthw.h>
18 
19 #define LOG_TAG              "at.svr"
20 #include <at_log.h>
21 
22 #ifdef AT_USING_SERVER
23 
24 #define AT_CMD_CHAR_0                  '0'
25 #define AT_CMD_CHAR_9                  '9'
26 #define AT_CMD_QUESTION_MARK           '?'
27 #define AT_CMD_EQUAL_MARK              '='
28 #define AT_CMD_L_SQ_BRACKET            '['
29 #define AT_CMD_R_SQ_BRACKET            ']'
30 #define AT_CMD_L_ANGLE_BRACKET         '<'
31 #define AT_CMD_R_ANGLE_BRACKET         '>'
32 #define AT_CMD_COMMA_MARK              ','
33 #define AT_CMD_SEMICOLON               ';'
34 #define AT_CMD_CR                      '\r'
35 #define AT_CMD_LF                      '\n'
36 
37 static at_server_t at_server_local = RT_NULL;
38 static at_cmd_t cmd_table = RT_NULL;
39 static rt_size_t cmd_num;
40 
41 extern void at_vprintf(rt_device_t device, const char *format, va_list args);
42 extern void at_vprintfln(rt_device_t device, const char *format, va_list args);
43 
44 /**
45  * AT server send data to AT device
46  *
47  * @param format the input format
48  */
at_server_printf(const char * format,...)49 void at_server_printf(const char *format, ...)
50 {
51     va_list args;
52 
53     va_start(args, format);
54 
55     at_vprintf(at_server_local->device, format, args);
56 
57     va_end(args);
58 }
59 
60 /**
61  * AT server send data and newline to AT device
62  *
63  * @param format the input format
64  */
at_server_printfln(const char * format,...)65 void at_server_printfln(const char *format, ...)
66 {
67     va_list args;
68 
69     va_start(args, format);
70 
71     at_vprintfln(at_server_local->device, format, args);
72 
73     va_end(args);
74 }
75 
76 
77 /**
78  * AT server request arguments parse arguments
79  *
80  * @param req_args request arguments
81  * @param req_expr request expression
82  *
83  * @return  -1 : parse arguments failed
84  *           0 : parse without match
85  *          >0 : The number of arguments successfully parsed
86  */
at_req_parse_args(const char * req_args,const char * req_expr,...)87 int at_req_parse_args(const char *req_args, const char *req_expr, ...)
88 {
89     va_list args;
90     int req_args_num = 0;
91 
92     RT_ASSERT(req_args);
93     RT_ASSERT(req_expr);
94 
95     va_start(args, req_expr);
96 
97     req_args_num = vsscanf(req_args, req_expr, args);
98 
99     va_end(args);
100 
101     return req_args_num;
102 }
103 
104 /**
105  * AT server send command execute result to AT device
106  *
107  * @param result AT command execute result
108  */
at_server_print_result(at_result_t result)109 void at_server_print_result(at_result_t result)
110 {
111     switch (result)
112     {
113     case AT_RESULT_OK:
114         at_server_printfln("");
115         at_server_printfln("OK");
116         break;
117 
118     case AT_RESULT_FAILE:
119         at_server_printfln("");
120         at_server_printfln("ERROR");
121         break;
122 
123     case AT_RESULT_NULL:
124         break;
125 
126     case AT_RESULT_CMD_ERR:
127         at_server_printfln("ERR CMD MATCH FAILED!");
128         at_server_print_result(AT_RESULT_FAILE);
129         break;
130 
131     case AT_RESULT_CHECK_FAILE:
132         at_server_printfln("ERR CHECK ARGS FORMAT FAILED!");
133         at_server_print_result(AT_RESULT_FAILE);
134         break;
135 
136     case AT_RESULT_PARSE_FAILE:
137         at_server_printfln("ERR PARSE ARGS FAILED!");
138         at_server_print_result(AT_RESULT_FAILE);
139         break;
140 
141     default:
142         break;
143     }
144 }
145 
146 /**
147  *  AT server print all commands to AT device
148  */
rt_at_server_print_all_cmd(void)149 void rt_at_server_print_all_cmd(void)
150 {
151     rt_size_t i = 0;
152 
153     at_server_printfln("Commands list : ");
154 
155     for (i = 0; i < cmd_num; i++)
156     {
157         at_server_printf("%s", cmd_table[i].name);
158 
159         if (cmd_table[i].args_expr)
160         {
161             at_server_printfln("%s", cmd_table[i].args_expr);
162         }
163         else
164         {
165             at_server_printf("%c%c", AT_CMD_CR, AT_CMD_LF);
166         }
167     }
168 }
169 
at_get_server(void)170 at_server_t at_get_server(void)
171 {
172     RT_ASSERT(at_server_local);
173     RT_ASSERT(at_server_local->status != AT_STATUS_UNINITIALIZED);
174 
175     return at_server_local;
176 }
177 
at_check_args(const char * args,const char * args_format)178 static rt_err_t at_check_args(const char *args, const char *args_format)
179 {
180     rt_size_t left_sq_bracket_num = 0, right_sq_bracket_num = 0;
181     rt_size_t left_angle_bracket_num = 0, right_angle_bracket_num = 0;
182     rt_size_t comma_mark_num = 0;
183     rt_size_t i = 0;
184 
185     RT_ASSERT(args);
186     RT_ASSERT(args_format);
187 
188     for (i = 0; i < strlen(args_format); i++)
189     {
190         switch (args_format[i])
191         {
192         case AT_CMD_L_SQ_BRACKET:
193             left_sq_bracket_num++;
194             break;
195 
196         case AT_CMD_R_SQ_BRACKET:
197             right_sq_bracket_num++;
198             break;
199 
200         case AT_CMD_L_ANGLE_BRACKET:
201             left_angle_bracket_num++;
202             break;
203 
204         case AT_CMD_R_ANGLE_BRACKET:
205             right_angle_bracket_num++;
206             break;
207 
208         default:
209             break;
210         }
211     }
212 
213     if (left_sq_bracket_num != right_sq_bracket_num || left_angle_bracket_num != right_angle_bracket_num
214             || left_sq_bracket_num > left_angle_bracket_num)
215     {
216         return -RT_ERROR;
217     }
218 
219     for (i = 0; i < strlen(args); i++)
220     {
221         if (args[i] == AT_CMD_COMMA_MARK)
222         {
223             comma_mark_num++;
224         }
225     }
226 
227     if ((comma_mark_num + 1 < left_angle_bracket_num - left_sq_bracket_num)
228             || comma_mark_num + 1 > left_angle_bracket_num)
229     {
230         return -RT_ERROR;
231     }
232 
233     return RT_EOK;
234 }
235 
at_cmd_process(at_cmd_t cmd,const char * cmd_args)236 static rt_err_t at_cmd_process(at_cmd_t cmd, const char *cmd_args)
237 {
238     at_result_t result = AT_RESULT_OK;
239 
240     RT_ASSERT(cmd);
241     RT_ASSERT(cmd_args);
242 
243     if (cmd_args[0] == AT_CMD_EQUAL_MARK && cmd_args[1] == AT_CMD_QUESTION_MARK && cmd_args[2] == AT_CMD_CR)
244     {
245         if (cmd->test == RT_NULL)
246         {
247             at_server_print_result(AT_RESULT_CMD_ERR);
248             return -RT_ERROR;
249         }
250 
251         result = cmd->test();
252         at_server_print_result(result);
253     }
254     else if (cmd_args[0] == AT_CMD_QUESTION_MARK && cmd_args[1] == AT_CMD_CR)
255     {
256         if (cmd->query == RT_NULL)
257         {
258             at_server_print_result(AT_RESULT_CMD_ERR);
259             return -RT_ERROR;
260         }
261 
262         result = cmd->query();
263         at_server_print_result(result);
264     }
265     else if (cmd_args[0] == AT_CMD_EQUAL_MARK
266             || (cmd_args[0] >= AT_CMD_CHAR_0 && cmd_args[0] <= AT_CMD_CHAR_9 && cmd_args[1] == AT_CMD_CR))
267     {
268         if (cmd->setup == RT_NULL)
269         {
270             at_server_print_result(AT_RESULT_CMD_ERR);
271             return -RT_ERROR;
272         }
273 
274         if(at_check_args(cmd_args, cmd->args_expr) < 0)
275         {
276             at_server_print_result(AT_RESULT_CHECK_FAILE);
277             return -RT_ERROR;
278         }
279 
280         result = cmd->setup(cmd_args);
281         at_server_print_result(result);
282     }
283     else if (cmd_args[0] == AT_CMD_CR)
284     {
285         if (cmd->exec == RT_NULL)
286         {
287             at_server_print_result(AT_RESULT_CMD_ERR);
288             return -RT_ERROR;
289         }
290 
291         result = cmd->exec();
292         at_server_print_result(result);
293     }
294     else
295     {
296         return -RT_ERROR;
297     }
298 
299     return RT_EOK;
300 }
301 
at_find_cmd(const char * cmd)302 static at_cmd_t at_find_cmd(const char *cmd)
303 {
304     rt_size_t i = 0;
305 
306     RT_ASSERT(cmd_table);
307 
308     for (i = 0; i < cmd_num; i++)
309     {
310         if (!strcasecmp(cmd, cmd_table[i].name))
311         {
312             return &cmd_table[i];
313         }
314     }
315     return RT_NULL;
316 }
317 
at_cmd_get_name(const char * cmd_buffer,char * cmd_name)318 static rt_err_t at_cmd_get_name(const char *cmd_buffer, char *cmd_name)
319 {
320     rt_size_t cmd_name_len = 0, i = 0;
321 
322     RT_ASSERT(cmd_name);
323     RT_ASSERT(cmd_buffer);
324 
325     for (i = 0; i < strlen(cmd_buffer) + 1; i++)
326     {
327         if (*(cmd_buffer + i) == AT_CMD_QUESTION_MARK || *(cmd_buffer + i) == AT_CMD_EQUAL_MARK
328                 || *(cmd_buffer + i) == AT_CMD_CR
329                 || (*(cmd_buffer + i) >= AT_CMD_CHAR_0 && *(cmd_buffer + i) <= AT_CMD_CHAR_9))
330         {
331             cmd_name_len = i;
332             memcpy(cmd_name, cmd_buffer, cmd_name_len);
333             *(cmd_name + cmd_name_len) = '\0';
334 
335             return RT_EOK;
336         }
337     }
338 
339     return -RT_ERROR;
340 }
341 
at_server_gerchar(void)342 static char at_server_gerchar(void)
343 {
344     char ch;
345 
346     while (rt_device_read(at_server_local->device, 0, &ch, 1) == 0)
347     {
348         rt_sem_control(at_server_local->rx_notice, RT_IPC_CMD_RESET, RT_NULL);
349         rt_sem_take(at_server_local->rx_notice, RT_WAITING_FOREVER);
350     }
351 
352     return ch;
353 }
354 
server_parser(at_server_t server)355 static void server_parser(at_server_t server)
356 {
357 #define ESC_KEY                 0x1B
358 #define BACKSPACE_KEY           0x08
359 #define DELECT_KEY              0x7F
360 
361     char cur_cmd_name[AT_CMD_NAME_LEN] = { 0 };
362     at_cmd_t cur_cmd = RT_NULL;
363     char *cur_cmd_args = RT_NULL, ch, last_ch;
364 
365     RT_ASSERT(server);
366     RT_ASSERT(server->status != AT_STATUS_UNINITIALIZED);
367 
368     while (ESC_KEY != (ch = server->get_char()))
369     {
370         if (server->echo_mode)
371         {
372             if (ch == AT_CMD_CR || (ch == AT_CMD_LF && last_ch != AT_CMD_CR))
373             {
374                 at_server_printf("%c%c", AT_CMD_CR, AT_CMD_LF);
375             }
376             else if (ch == BACKSPACE_KEY || ch == DELECT_KEY)
377             {
378                 if (server->cur_recv_len)
379                 {
380                     server->recv_buffer[--server->cur_recv_len] = 0;
381                     at_server_printf("\b \b");
382                 }
383 
384                 continue;
385             }
386             else
387             {
388                 at_server_printf("%c", ch);
389             }
390         }
391 
392         server->recv_buffer[server->cur_recv_len++] = ch;
393         last_ch = ch;
394 
395         if(!strstr(server->recv_buffer, server->end_mark))
396         {
397             continue;
398         }
399 
400         if (at_cmd_get_name(server->recv_buffer, cur_cmd_name) < 0)
401         {
402             at_server_print_result(AT_RESULT_CMD_ERR);
403             goto __retry;
404         }
405 
406         cur_cmd = at_find_cmd(cur_cmd_name);
407         if (!cur_cmd)
408         {
409             at_server_print_result(AT_RESULT_CMD_ERR);
410             goto __retry;
411         }
412 
413         cur_cmd_args = server->recv_buffer + strlen(cur_cmd_name);
414         if (at_cmd_process(cur_cmd, cur_cmd_args) < 0)
415         {
416             goto __retry;
417         }
418 
419 __retry:
420         memset(server->recv_buffer, 0x00, AT_SERVER_RECV_BUFF_LEN);
421         server->cur_recv_len = 0;
422     }
423 }
424 
at_rx_ind(rt_device_t dev,rt_size_t size)425 static rt_err_t at_rx_ind(rt_device_t dev, rt_size_t size)
426 {
427     if (size > 0)
428     {
429         rt_sem_release(at_server_local->rx_notice);
430     }
431 
432     return RT_EOK;
433 }
434 
435 #if defined(__ICCARM__) || defined(__ICCRX__)               /* for IAR compiler */
436 #pragma section="RtAtCmdTab"
437 #endif
438 
at_server_init(void)439 int at_server_init(void)
440 {
441     rt_err_t result = RT_EOK;
442     rt_err_t open_result = RT_EOK;
443 
444     if (at_server_local)
445     {
446         return result;
447     }
448 
449     /* initialize the AT commands table.*/
450 #if defined(__CC_ARM)                                 /* ARM C Compiler */
451     extern const int RtAtCmdTab$$Base;
452     extern const int RtAtCmdTab$$Limit;
453     cmd_table = (at_cmd_t)&RtAtCmdTab$$Base;
454     cmd_num = (at_cmd_t)&RtAtCmdTab$$Limit - cmd_table;
455 #elif defined (__ICCARM__) || defined(__ICCRX__)      /* for IAR Compiler */
456     cmd_table = (at_cmd_t)__section_begin("RtAtCmdTab");
457     cmd_num = (at_cmd_t)__section_end("RtAtCmdTab") - cmd_table;
458 #elif defined (__GNUC__)                             /* for GCC Compiler */
459     extern const int __rtatcmdtab_start;
460     extern const int __rtatcmdtab_end;
461     cmd_table = (at_cmd_t)&__rtatcmdtab_start;
462     cmd_num = (at_cmd_t) &__rtatcmdtab_end - cmd_table;
463 #endif /* defined(__CC_ARM) */
464 
465     at_server_local = (at_server_t) rt_calloc(1, sizeof(struct at_server));
466     if (!at_server_local)
467     {
468         result = -RT_ENOMEM;
469         LOG_E("AT server session initialize failed! No memory for at_server structure !");
470         goto __exit;
471     }
472 
473     at_server_local->echo_mode = 1;
474     at_server_local->status = AT_STATUS_UNINITIALIZED;
475 
476     memset(at_server_local->recv_buffer, 0x00, AT_SERVER_RECV_BUFF_LEN);
477     at_server_local->cur_recv_len = 0;
478 
479     at_server_local->rx_notice = rt_sem_create("at_svr", 0, RT_IPC_FLAG_FIFO);
480     if (!at_server_local->rx_notice)
481     {
482         LOG_E("AT server session initialize failed! at_rx_notice semaphore create failed!");
483         result = -RT_ENOMEM;
484         goto __exit;
485     }
486 
487     /* Find and open command device */
488     at_server_local->device = rt_device_find(AT_SERVER_DEVICE);
489     if (at_server_local->device)
490     {
491         RT_ASSERT(at_server_local->device->type == RT_Device_Class_Char);
492 
493         /* using DMA mode first */
494         open_result = rt_device_open(at_server_local->device, RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_DMA_RX);
495         /* using interrupt mode when DMA mode not supported */
496         if (open_result == -RT_EIO)
497         {
498             open_result = rt_device_open(at_server_local->device, RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_INT_RX);
499         }
500         RT_ASSERT(open_result == RT_EOK);
501 
502         rt_device_set_rx_indicate(at_server_local->device, at_rx_ind);
503     }
504     else
505     {
506         LOG_E("AT device initialize failed! Not find the device : %s.", AT_SERVER_DEVICE);
507         result = -RT_ERROR;
508         goto __exit;
509     }
510 
511     at_server_local->get_char = at_server_gerchar;
512     memcpy(at_server_local->end_mark, AT_CMD_END_MARK, sizeof(AT_CMD_END_MARK));
513 
514     at_server_local->parser_entry = server_parser;
515     at_server_local->parser = rt_thread_create("at_svr",
516                                          (void (*)(void *parameter))server_parser,
517                                          at_server_local,
518                                          2 * 1024,
519                                          RT_THREAD_PRIORITY_MAX / 3 - 1,
520                                          5);
521     if (at_server_local->parser == RT_NULL)
522     {
523         result = -RT_ENOMEM;
524         goto __exit;
525     }
526 
527 __exit:
528     if (!result)
529     {
530         at_server_local->status = AT_STATUS_INITIALIZED;
531 
532         rt_thread_startup(at_server_local->parser);
533 
534         LOG_I("RT-Thread AT server (V%s) initialize success.", AT_SW_VERSION);
535     }
536     else
537     {
538         if (at_server_local)
539         {
540             rt_free(at_server_local);
541         }
542 
543         LOG_E("RT-Thread AT server (V%s) initialize failed(%d).", AT_SW_VERSION, result);
544     }
545 
546     return result;
547 }
548 INIT_COMPONENT_EXPORT(at_server_init);
549 
at_port_reset(void)550 RT_WEAK void at_port_reset(void)
551 {
552     LOG_E("The reset for AT server is not implement.");
553 }
554 
at_port_factory_reset(void)555 RT_WEAK void at_port_factory_reset(void)
556 {
557     LOG_E("The factory reset for AT server is not implement.");
558 }
559 
560 #endif /* AT_USING_SERVER */
561