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