• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Copyright (c) 2016, The OpenThread Authors.
3  *  All rights reserved.
4  *
5  *  Redistribution and use in source and binary forms, with or without
6  *  modification, are permitted provided that the following conditions are met:
7  *  1. Redistributions of source code must retain the above copyright
8  *     notice, this list of conditions and the following disclaimer.
9  *  2. Redistributions in binary form must reproduce the above copyright
10  *     notice, this list of conditions and the following disclaimer in the
11  *     documentation and/or other materials provided with the distribution.
12  *  3. Neither the name of the copyright holder nor the
13  *     names of its contributors may be used to endorse or promote products
14  *     derived from this software without specific prior written permission.
15  *
16  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20  *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  *  POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include "platform-simulation.h"
30 
31 #include <assert.h>
32 #include <errno.h>
33 #include <fcntl.h>
34 #include <poll.h>
35 #include <signal.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <termios.h>
39 #include <unistd.h>
40 
41 #include <openthread/platform/debug_uart.h>
42 
43 #include "simul_utils.h"
44 #include "lib/platform/exit_code.h"
45 #include "utils/code_utils.h"
46 #include "utils/uart.h"
47 
48 #if OPENTHREAD_SIMULATION_VIRTUAL_TIME_UART == 0
49 
50 static uint8_t        s_receive_buffer[128];
51 static const uint8_t *s_write_buffer;
52 static uint16_t       s_write_length;
53 static int            s_in_fd;
54 static int            s_out_fd;
55 
56 static struct termios original_stdin_termios;
57 static struct termios original_stdout_termios;
58 
restore_stdin_termios(void)59 static void restore_stdin_termios(void) { tcsetattr(s_in_fd, TCSAFLUSH, &original_stdin_termios); }
60 
restore_stdout_termios(void)61 static void restore_stdout_termios(void) { tcsetattr(s_out_fd, TCSAFLUSH, &original_stdout_termios); }
62 
platformUartRestore(void)63 void platformUartRestore(void)
64 {
65     restore_stdin_termios();
66     restore_stdout_termios();
67     dup2(s_out_fd, STDOUT_FILENO);
68 }
69 
otPlatUartEnable(void)70 otError otPlatUartEnable(void)
71 {
72     otError        error = OT_ERROR_NONE;
73     struct termios termios;
74 
75     s_in_fd  = dup(STDIN_FILENO);
76     s_out_fd = dup(STDOUT_FILENO);
77     dup2(STDERR_FILENO, STDOUT_FILENO);
78 
79     // We need this signal to make sure that this
80     // process terminates properly.
81     signal(SIGPIPE, SIG_DFL);
82 
83     if (isatty(s_in_fd))
84     {
85         tcgetattr(s_in_fd, &original_stdin_termios);
86         atexit(&restore_stdin_termios);
87     }
88 
89     if (isatty(s_out_fd))
90     {
91         tcgetattr(s_out_fd, &original_stdout_termios);
92         atexit(&restore_stdout_termios);
93     }
94 
95     if (isatty(s_in_fd))
96     {
97         // get current configuration
98         otEXPECT_ACTION(tcgetattr(s_in_fd, &termios) == 0, perror("tcgetattr"); error = OT_ERROR_GENERIC);
99 
100         // Set up the termios settings for raw mode. This turns
101         // off input/output processing, line processing, and character processing.
102         cfmakeraw(&termios);
103 
104         // Set up our cflags for local use. Turn on hangup-on-close.
105         termios.c_cflag |= HUPCL | CREAD | CLOCAL;
106 
107         // "Minimum number of characters for noncanonical read"
108         termios.c_cc[VMIN] = 1;
109 
110         // "Timeout in deciseconds for noncanonical read"
111         termios.c_cc[VTIME] = 0;
112 
113         // configure baud rate
114         otEXPECT_ACTION(cfsetispeed(&termios, OPENTHREAD_SIMULATION_UART_BAUDRATE) == 0, perror("cfsetispeed");
115                         error = OT_ERROR_GENERIC);
116 
117         // set configuration
118         otEXPECT_ACTION(tcsetattr(s_in_fd, TCSANOW, &termios) == 0, perror("tcsetattr"); error = OT_ERROR_GENERIC);
119     }
120 
121     if (isatty(s_out_fd))
122     {
123         // get current configuration
124         otEXPECT_ACTION(tcgetattr(s_out_fd, &termios) == 0, perror("tcgetattr"); error = OT_ERROR_GENERIC);
125 
126         // Set up the termios settings for raw mode. This turns
127         // off input/output processing, line processing, and character processing.
128         cfmakeraw(&termios);
129 
130         // Absolutely obliterate all output processing.
131         termios.c_oflag = 0;
132 
133         // Set up our cflags for local use. Turn on hangup-on-close.
134         termios.c_cflag |= HUPCL | CREAD | CLOCAL;
135 
136         // configure baud rate
137         otEXPECT_ACTION(cfsetospeed(&termios, OPENTHREAD_SIMULATION_UART_BAUDRATE) == 0, perror("cfsetospeed");
138                         error = OT_ERROR_GENERIC);
139 
140         // set configuration
141         otEXPECT_ACTION(tcsetattr(s_out_fd, TCSANOW, &termios) == 0, perror("tcsetattr"); error = OT_ERROR_GENERIC);
142     }
143 
144     return error;
145 
146 exit:
147     close(s_in_fd);
148     close(s_out_fd);
149     return error;
150 }
151 
otPlatUartDisable(void)152 otError otPlatUartDisable(void)
153 {
154     otError error = OT_ERROR_NONE;
155 
156     close(s_in_fd);
157     close(s_out_fd);
158 
159     return error;
160 }
161 
otPlatUartSend(const uint8_t * aBuf,uint16_t aBufLength)162 otError otPlatUartSend(const uint8_t *aBuf, uint16_t aBufLength)
163 {
164     otError error = OT_ERROR_NONE;
165 
166     otEXPECT_ACTION(s_write_length == 0, error = OT_ERROR_BUSY);
167 
168     s_write_buffer = aBuf;
169     s_write_length = aBufLength;
170 
171 exit:
172     return error;
173 }
174 
platformUartUpdateFdSet(fd_set * aReadFdSet,fd_set * aWriteFdSet,fd_set * aErrorFdSet,int * aMaxFd)175 void platformUartUpdateFdSet(fd_set *aReadFdSet, fd_set *aWriteFdSet, fd_set *aErrorFdSet, int *aMaxFd)
176 {
177     utilsAddFdToFdSet(s_in_fd, aReadFdSet, aMaxFd);
178     utilsAddFdToFdSet(s_in_fd, aErrorFdSet, aMaxFd);
179 
180     if ((s_write_length > 0))
181     {
182         utilsAddFdToFdSet(s_out_fd, aWriteFdSet, aMaxFd);
183         utilsAddFdToFdSet(s_out_fd, aErrorFdSet, aMaxFd);
184     }
185 }
186 
otPlatUartFlush(void)187 otError otPlatUartFlush(void)
188 {
189     otError error = OT_ERROR_NONE;
190     ssize_t count;
191 
192     otEXPECT_ACTION(s_write_buffer != NULL && s_write_length > 0, error = OT_ERROR_INVALID_STATE);
193 
194     while ((count = write(s_out_fd, s_write_buffer, s_write_length)) > 0 && (s_write_length -= count) > 0)
195     {
196         s_write_buffer += count;
197     }
198 
199     if (count != -1)
200     {
201         assert(s_write_length == 0);
202         s_write_buffer = NULL;
203     }
204     else
205     {
206         perror("write(UART)");
207         DieNow(OT_EXIT_ERROR_ERRNO);
208     }
209 
210 exit:
211     return error;
212 }
213 
platformUartProcess(void)214 void platformUartProcess(void)
215 {
216     ssize_t       rval;
217     const int     error_flags = POLLERR | POLLNVAL | POLLHUP;
218     struct pollfd pollfd[]    = {
219            {s_in_fd, POLLIN | error_flags, 0},
220            {s_out_fd, POLLOUT | error_flags, 0},
221     };
222 
223     errno = 0;
224 
225     rval = poll(pollfd, sizeof(pollfd) / sizeof(*pollfd), 0);
226 
227     if (rval < 0)
228     {
229         perror("poll");
230         DieNow(OT_EXIT_ERROR_ERRNO);
231     }
232 
233     if (rval > 0)
234     {
235         if ((pollfd[0].revents & error_flags) != 0)
236         {
237             perror("s_in_fd");
238             DieNow(OT_EXIT_ERROR_ERRNO);
239         }
240 
241         if ((pollfd[1].revents & error_flags) != 0)
242         {
243             perror("s_out_fd");
244             DieNow(OT_EXIT_ERROR_ERRNO);
245         }
246 
247         if (pollfd[0].revents & POLLIN)
248         {
249             rval = read(s_in_fd, s_receive_buffer, sizeof(s_receive_buffer));
250 
251             if (rval <= 0)
252             {
253                 perror("read");
254                 DieNow(OT_EXIT_ERROR_ERRNO);
255             }
256 
257             otPlatUartReceived(s_receive_buffer, (uint16_t)rval);
258         }
259 
260         if ((s_write_length > 0) && (pollfd[1].revents & POLLOUT))
261         {
262             rval = write(s_out_fd, s_write_buffer, s_write_length);
263 
264             if (rval >= 0)
265             {
266                 s_write_buffer += (uint16_t)rval;
267                 s_write_length -= (uint16_t)rval;
268 
269                 if (s_write_length == 0)
270                 {
271                     otPlatUartSendDone();
272                 }
273             }
274             else if (errno != EINTR)
275             {
276                 perror("write");
277                 DieNow(OT_EXIT_ERROR_ERRNO);
278             }
279         }
280     }
281 }
282 #endif // OPENTHREAD_SIMULATION_VIRTUAL_TIME_UART == 0
283 
284 #if OPENTHREAD_CONFIG_ENABLE_DEBUG_UART && (OPENTHREAD_CONFIG_LOG_OUTPUT == OPENTHREAD_CONFIG_LOG_OUTPUT_DEBUG_UART)
285 
286 static FILE *posix_logfile;
287 
otPlatDebugUart_logfile(const char * filename)288 otError otPlatDebugUart_logfile(const char *filename)
289 {
290     posix_logfile = fopen(filename, "wt");
291 
292     return posix_logfile ? OT_ERROR_NONE : OT_ERROR_FAILED;
293 }
294 
otPlatDebugUart_putchar_raw(int c)295 void otPlatDebugUart_putchar_raw(int c)
296 {
297     FILE *fp;
298 
299     /* note: log file will have a mix of cr/lf and
300      * in some/many cases duplicate cr because in
301      * some cases the log function {ie: Mbed} already
302      * includes the CR or LF... but other log functions
303      * do not include cr/lf and expect it appended
304      */
305     fp = posix_logfile;
306 
307     if (fp != NULL)
308     {
309         /* log is lost ... until a file is setup */
310         fputc(c, fp);
311         /* we could "fflush" but will not */
312     }
313 }
314 
otPlatDebugUart_kbhit(void)315 int otPlatDebugUart_kbhit(void)
316 {
317     /* not supported */
318     return 0;
319 }
320 
otPlatDebugUart_getc(void)321 int otPlatDebugUart_getc(void)
322 {
323     /* not supported */
324     return -1;
325 }
326 
327 #endif
328