xref: /nrf52832-nimble/rt-thread/components/net/at/src/at_cli.c (revision 042d53a763ad75cb1465103098bb88c245d95138)
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-04-02     armink       first version
9  */
10 
11 #include <at.h>
12 #include <stdio.h>
13 #include <string.h>
14 
15 #include <rtthread.h>
16 #include <rtdevice.h>
17 #include <rthw.h>
18 
19 #ifdef AT_USING_CLI
20 
21 #define AT_CLI_FIFO_SIZE                      256
22 
23 static struct rt_semaphore console_rx_notice;
24 static struct rt_ringbuffer *console_rx_fifo = RT_NULL;
25 static rt_err_t (*odev_rx_ind)(rt_device_t dev, rt_size_t size) = RT_NULL;
26 
27 #ifdef AT_USING_CLIENT
28 static struct rt_semaphore client_rx_notice;
29 static struct rt_ringbuffer *client_rx_fifo = RT_NULL;
30 #endif
31 
32 static char console_getchar(void)
33 {
34     char ch;
35 
36     rt_sem_take(&console_rx_notice, RT_WAITING_FOREVER);
37     rt_ringbuffer_getchar(console_rx_fifo, (rt_uint8_t *)&ch);
38 
39     return ch;
40 }
41 
42 static rt_err_t console_getchar_rx_ind(rt_device_t dev, rt_size_t size)
43 {
44     uint8_t ch;
45     rt_size_t i;
46 
47     for (i = 0; i < size; i++)
48     {
49         /* read a char */
50         if (rt_device_read(dev, 0, &ch, 1))
51         {
52             rt_ringbuffer_put_force(console_rx_fifo, &ch, 1);
53             rt_sem_release(&console_rx_notice);
54         }
55     }
56 
57     return RT_EOK;
58 }
59 
60 void at_cli_init(void)
61 {
62     rt_base_t int_lvl;
63     rt_device_t console;
64 
65     rt_sem_init(&console_rx_notice, "cli_c", 0, RT_IPC_FLAG_FIFO);
66 
67     /* create RX FIFO */
68     console_rx_fifo = rt_ringbuffer_create(AT_CLI_FIFO_SIZE);
69     /* created must success */
70     RT_ASSERT(console_rx_fifo);
71 
72     int_lvl = rt_hw_interrupt_disable();
73     console = rt_console_get_device();
74     if (console)
75     {
76         /* backup RX indicate */
77         odev_rx_ind = console->rx_indicate;
78         rt_device_set_rx_indicate(console, console_getchar_rx_ind);
79     }
80 
81     rt_hw_interrupt_enable(int_lvl);
82 }
83 
84 void at_cli_deinit(void)
85 {
86     rt_base_t int_lvl;
87     rt_device_t console;
88 
89     int_lvl = rt_hw_interrupt_disable();
90     console = rt_console_get_device();
91     if (console && odev_rx_ind)
92     {
93         /* restore RX indicate */
94         rt_device_set_rx_indicate(console, odev_rx_ind);
95     }
96     rt_hw_interrupt_enable(int_lvl);
97 
98     rt_sem_detach(&console_rx_notice);
99     rt_ringbuffer_destroy(console_rx_fifo);
100 }
101 
102 #ifdef AT_USING_SERVER
103 static void server_cli_parser(void)
104 {
105     extern at_server_t at_get_server(void);
106 
107     at_server_t server = at_get_server();
108     rt_base_t int_lvl;
109     static rt_device_t device_bak;
110     static char (*getchar_bak)(void);
111     static char endmark_back[AT_END_MARK_LEN];
112 
113     /* backup server device and getchar function */
114     {
115         int_lvl = rt_hw_interrupt_disable();
116 
117         device_bak = server->device;
118         getchar_bak = server->get_char;
119 
120         memset(endmark_back, 0x00, AT_END_MARK_LEN);
121         memcpy(endmark_back, server->end_mark, strlen(server->end_mark));
122 
123         /* setup server device as console device */
124         server->device = rt_console_get_device();
125         server->get_char = console_getchar;
126 
127         memset(server->end_mark, 0x00, AT_END_MARK_LEN);
128         server->end_mark[0] = '\r';
129 
130         rt_hw_interrupt_enable(int_lvl);
131     }
132 
133     if (server)
134     {
135         rt_kprintf("======== Welcome to using RT-Thread AT command server cli ========\n");
136         rt_kprintf("Input your at command for test server. Press 'ESC' to exit.\n");
137         server->parser_entry(server);
138     }
139     else
140     {
141         rt_kprintf("AT client not initialized\n");
142     }
143 
144     /* restore server device and getchar function */
145     {
146         int_lvl = rt_hw_interrupt_disable();
147 
148         server->device = device_bak;
149         server->get_char = getchar_bak;
150 
151         memset(server->end_mark, 0x00, AT_END_MARK_LEN);
152         memcpy(server->end_mark, endmark_back, strlen(endmark_back));
153 
154         rt_hw_interrupt_enable(int_lvl);
155     }
156 }
157 #endif /* AT_USING_SERVER */
158 
159 #ifdef AT_USING_CLIENT
160 static char client_getchar(void)
161 {
162     char ch;
163 
164     rt_sem_take(&client_rx_notice, RT_WAITING_FOREVER);
165     rt_ringbuffer_getchar(client_rx_fifo, (rt_uint8_t *)&ch);
166 
167     return ch;
168 }
169 
170 static void at_client_entry(void *param)
171 {
172     char ch;
173 
174     while(1)
175     {
176         ch = client_getchar();
177         rt_kprintf("%c", ch);
178     }
179 }
180 
181 static rt_err_t client_getchar_rx_ind(rt_device_t dev, rt_size_t size)
182 {
183     uint8_t ch;
184     rt_size_t i;
185 
186     for (i = 0; i < size; i++)
187     {
188         /* read a char */
189         if (rt_device_read(dev, 0, &ch, 1))
190         {
191             rt_ringbuffer_put_force(client_rx_fifo, &ch, 1);
192             rt_sem_release(&client_rx_notice);
193         }
194     }
195 
196     return RT_EOK;
197 }
198 static void client_cli_parser(at_client_t  client)
199 {
200 #define ESC_KEY                 0x1B
201 #define BACKSPACE_KEY           0x08
202 #define DELECT_KEY              0x7F
203 
204     char ch;
205     char cur_line[FINSH_CMD_SIZE] = { 0 };
206     rt_size_t cur_line_len = 0;
207     static rt_err_t (*client_odev_rx_ind)(rt_device_t dev, rt_size_t size) = RT_NULL;
208     rt_base_t int_lvl;
209     rt_thread_t at_client;
210 
211     if (client)
212     {
213         /* backup client device RX indicate */
214         {
215             int_lvl = rt_hw_interrupt_disable();
216             client_odev_rx_ind = client->device->rx_indicate;
217             rt_device_set_rx_indicate(client->device, client_getchar_rx_ind);
218             rt_hw_interrupt_enable(int_lvl);
219         }
220 
221         rt_sem_init(&client_rx_notice, "cli_r", 0, RT_IPC_FLAG_FIFO);
222         client_rx_fifo = rt_ringbuffer_create(AT_CLI_FIFO_SIZE);
223 
224         at_client = rt_thread_create("at_cli", at_client_entry, RT_NULL, 512, 8, 8);
225         if (client_rx_fifo && at_client)
226         {
227             rt_kprintf("======== Welcome to using RT-Thread AT command client cli ========\n");
228             rt_kprintf("Cli will forward your command to server port(%s). Press 'ESC' to exit.\n", client->device->parent.name);
229             rt_thread_startup(at_client);
230             /* process user input */
231             while (ESC_KEY != (ch = console_getchar()))
232             {
233                 if (ch == BACKSPACE_KEY || ch == DELECT_KEY)
234                 {
235                     if (cur_line_len)
236                     {
237                         cur_line[--cur_line_len] = 0;
238                         rt_kprintf("\b \b");
239                     }
240                     continue;
241                 }
242                 else if (ch == '\r' || ch == '\n')
243                 {
244                     /* execute a AT request */
245                     if (cur_line_len)
246                     {
247                         rt_kprintf("\n");
248                         at_obj_exec_cmd(client, RT_NULL, "%.*s", cur_line_len, cur_line);
249                     }
250                     cur_line_len = 0;
251                 }
252                 else
253                 {
254                     rt_kprintf("%c", ch);
255                     cur_line[cur_line_len++] = ch;
256                 }
257             }
258 
259             /* restore client device RX indicate */
260             {
261                 int_lvl = rt_hw_interrupt_disable();
262                 rt_device_set_rx_indicate(client->device, client_odev_rx_ind);
263                 rt_hw_interrupt_enable(int_lvl);
264             }
265 
266             rt_thread_delete(at_client);
267             rt_sem_detach(&client_rx_notice);
268             rt_ringbuffer_destroy(client_rx_fifo);
269         }
270         else
271         {
272             rt_kprintf("No mem for AT cli client\n");
273         }
274     }
275     else
276     {
277         rt_kprintf("AT client not initialized\n");
278     }
279 }
280 #endif /* AT_USING_CLIENT */
281 
282 static void at(int argc, char **argv)
283 {
284 
285     if (argc != 2 && argc != 3)
286     {
287         rt_kprintf("Please input '<server|client [dev_name]>' \n");
288         return;
289     }
290 
291     at_cli_init();
292 
293     if (!strcmp(argv[1], "server"))
294     {
295 #ifdef AT_USING_SERVER
296         server_cli_parser();
297 #else
298         rt_kprintf("Not support AT server, please check your configure!\n");
299 #endif /* AT_USING_SERVER */
300     }
301     else if (!strcmp(argv[1], "client"))
302     {
303 #ifdef AT_USING_CLIENT
304         at_client_t client = RT_NULL;
305 
306         if (argc == 2)
307         {
308             client_cli_parser(at_client_get_first());
309         }
310         else if (argc == 3)
311         {
312             client = at_client_get(argv[2]);
313             if (client == RT_NULL)
314             {
315                 rt_kprintf("input AT client device name(%s) error.\n", argv[2]);
316             }
317             else
318             {
319                 client_cli_parser(client);
320             }
321         }
322 #else
323         rt_kprintf("Not support AT client, please check your configure!\n");
324 #endif /* AT_USING_CLIENT */
325     }
326     else
327     {
328         rt_kprintf("Please input '<server|client [dev_name]>' \n");
329     }
330 
331     at_cli_deinit();
332 }
333 MSH_CMD_EXPORT(at, RT-Thread AT component cli: at <server|client [dev_name]>);
334 
335 #endif /* AT_USING_CLI */
336