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