1 /*
2  * Copyright (c) 2006-2021, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  */
9 
10 #include <stdio.h>
11 #include <rthw.h>
12 #include <rtdevice.h>
13 #include <rtthread.h>
14 #include <rtdevice.h>
15 
16 /* uart driver */
17 struct console_uart
18 {
19     int rx_ready;
20 
21     struct rt_ringbuffer rb;
22     rt_uint8_t rx_buffer[256];
23 } _console_uart;
24 static struct rt_serial_device _serial;
25 
26 #define SAVEKEY(key)  do { char ch = key; rt_ringbuffer_put_force(&(_console_uart.rb), &ch, 1); } while (0)
27 
28 #ifdef _WIN32
29 #include  <windows.h>
30 #include  <mmsystem.h>
31 #include  <conio.h>
32 extern int getch(void);
33 
34 /*
35  * Handler for OSKey Thread
36  */
37 static HANDLE       OSKey_Thread;
38 static DWORD        OSKey_ThreadID;
39 
40 static DWORD WINAPI ThreadforKeyGet(LPVOID lpParam);
console_lowlevel_init(void)41 void console_lowlevel_init(void)
42 {
43     /*
44      * create serial thread that receive key input from keyboard
45      */
46 
47     OSKey_Thread = CreateThread(NULL,
48                                 0,
49                                 (LPTHREAD_START_ROUTINE)ThreadforKeyGet,
50                                 0,
51                                 CREATE_SUSPENDED,
52                                 &OSKey_ThreadID);
53     if (OSKey_Thread == NULL)
54     {
55         //Display Error Message
56         return;
57     }
58 
59     SetThreadPriority(OSKey_Thread,
60                       THREAD_PRIORITY_NORMAL);
61     SetThreadPriorityBoost(OSKey_Thread,
62                            TRUE);
63     SetThreadAffinityMask(OSKey_Thread,
64                           0x01);
65     /*
66      * Start OS get key Thread
67      */
68     ResumeThread(OSKey_Thread);
69 }
70 
ThreadforKeyGet(LPVOID lpParam)71 static DWORD WINAPI ThreadforKeyGet(LPVOID lpParam)
72 #else /* POSIX version */
73 
74 #include <pthread.h>
75 #include <semaphore.h>
76 #include <stdlib.h>
77 #include <signal.h>
78 #include <termios.h> /* for tcxxxattr, ECHO, etc */
79 #include <unistd.h> /* for STDIN_FILENO */
80 
81 static void * ThreadforKeyGet(void * lpParam);
82 static pthread_t OSKey_Thread;
83 
84 void console_lowlevel_init(void)
85 {
86     int res;
87 
88     res = pthread_create(&OSKey_Thread, NULL, &ThreadforKeyGet, NULL);
89     if (res)
90     {
91         printf("pthread create faild, <%d>\n", res);
92         exit(EXIT_FAILURE);
93     }
94 }
95 
96 static struct termios oldt, newt;
97 /*simulate windows' getch(), it works!!*/
98 static void set_stty(void)
99 {
100     /* get terminal input's attribute */
101     tcgetattr(STDIN_FILENO, &oldt);
102     newt = oldt;
103 
104     /* set termios' local mode */
105     newt.c_lflag &= ~(ECHO|ICANON);
106     tcsetattr(STDIN_FILENO, TCSANOW, &newt);
107 }
108 
109 void restore_stty(void)
110 {
111    /* recover terminal's attribute */
112    tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
113 }
114 
115 #define getch  getchar
116 static void * ThreadforKeyGet(void * lpParam)
117 #endif /* not _WIN32*/
118 {
119  /*
120  * left  key(左): 0xe04b
121  * up    key(上): 0xe048
122  * right key(右): 0xe04d
123  * down  key(下): 0xe050
124  */
125     unsigned char key;
126 
127 #ifndef _WIN32
128     sigset_t  sigmask, oldmask;
129     /* set the getchar without buffer */
130     sigfillset(&sigmask);
131     pthread_sigmask(SIG_BLOCK, &sigmask, &oldmask);
132     set_stty();
133 #endif
134 
135     (void)lpParam;              //prevent compiler warnings
136 
137     for (;;)
138     {
139         key = getch();
140 #ifdef _WIN32
141         if (key == 0xE0)
142         {
143             key = getch();
144 
145             if (key == 0x48) //up key , 0x1b 0x5b 0x41
146             {
147                 SAVEKEY(0x1b);
148                 SAVEKEY(0x5b);
149                 SAVEKEY(0x41);
150             }
151             else if (key == 0x50)//0x1b 0x5b 0x42
152             {
153                 SAVEKEY(0x1b);
154                 SAVEKEY(0x5b);
155                 SAVEKEY(0x42);
156             }
157             else if (key == 0x4b)//<- 0x1b 0x5b 0x44
158             {
159                 SAVEKEY(0x1b);
160                 SAVEKEY(0x5b);
161                 SAVEKEY(0x44);
162             }
163             else if (key == 0x4d)//<- 0x1b 0x5b 0x43
164             {
165                 SAVEKEY(0x1b);
166                 SAVEKEY(0x5b);
167                 SAVEKEY(0x43);
168             }
169 
170             continue;
171         }
172 #endif
173         SAVEKEY(key);
174 
175         /* Notfiy serial ISR */
176         rt_hw_serial_isr(&_serial, RT_SERIAL_EVENT_RX_IND);
177     }
178     return RT_NULL;
179 } /*** ThreadforKeyGet ***/
180 
console_configure(struct rt_serial_device * serial,struct serial_configure * cfg)181 static rt_err_t console_configure(struct rt_serial_device *serial, struct serial_configure *cfg)
182 {
183     /* no baudrate, nothing */
184 
185     return RT_EOK;
186 }
187 
console_control(struct rt_serial_device * serial,int cmd,void * arg)188 static rt_err_t console_control(struct rt_serial_device *serial, int cmd, void *arg)
189 {
190     struct console_uart* uart;
191 
192     RT_ASSERT(serial != RT_NULL);
193     uart = (struct console_uart *)serial->parent.user_data;
194 
195     switch (cmd)
196     {
197     case RT_DEVICE_CTRL_CLR_INT:
198         uart->rx_ready = 0;
199         break;
200     case RT_DEVICE_CTRL_SET_INT:
201         uart->rx_ready = 1;
202         break;
203     }
204 
205     return RT_EOK;
206 }
207 
console_putc(struct rt_serial_device * serial,char c)208 static int console_putc(struct rt_serial_device *serial, char c)
209 {
210     int level;
211     RT_ASSERT(serial != RT_NULL);
212 
213 #if 0 /* Enable it if you want to save the console log */
214     {
215         static FILE* fp = NULL;
216 
217         if (fp == NULL)
218             fp = fopen("log.txt", "wb+");
219 
220         if (fp != NULL)
221             fwrite(buffer, size, 1, fp);
222     }
223 #endif
224 
225     level = rt_hw_interrupt_disable();
226     fwrite(&c, 1, 1, stdout);
227     fflush(stdout);
228     rt_hw_interrupt_enable(level);
229     return 1;
230 }
231 
console_getc(struct rt_serial_device * serial)232 static int console_getc(struct rt_serial_device *serial)
233 {
234     char ch;
235     struct console_uart* uart;
236 
237     RT_ASSERT(serial != RT_NULL);
238     uart = (struct console_uart *)serial->parent.user_data;
239 
240     if (rt_ringbuffer_getchar(&(uart->rb), &ch)) return ch;
241 
242     return -1;
243 }
244 
245 static const struct rt_uart_ops console_uart_ops =
246 {
247     console_configure,
248     console_control,
249     console_putc,
250     console_getc,
251 };
252 
uart_console_init(void)253 int uart_console_init(void)
254 {
255     struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT;
256     struct console_uart* uart;
257     struct rt_serial_device* serial;
258 
259     uart = &_console_uart;
260     serial = &_serial;
261 
262     uart->rx_ready = 0;
263 
264     serial->ops    = &console_uart_ops;
265     serial->config = config;
266     /* initialize ring buffer */
267     rt_ringbuffer_init(&uart->rb, uart->rx_buffer, sizeof(uart->rx_buffer));
268 
269     /* register UART device */
270     rt_hw_serial_register(serial, "console",
271                           RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX,
272                           uart);
273 
274     console_lowlevel_init();
275 
276     return 0;
277 }
278