Paparazzi UAS  v5.18.0_stable
Paparazzi is a free software Unmanned Aircraft System.
serial_port.c
Go to the documentation of this file.
1 #include "serial_port.h"
2 
3 #include <sys/types.h>
4 #include <sys/stat.h>
5 #include <fcntl.h>
6 #include <errno.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <unistd.h>
11 
16 // for definition of baud rates
17 #if !USE_ARBITRARY_BAUDRATE
18 #include <termios.h>
19 #else
20 #include <linux/termios.h>
21 #endif
22 
23 // strange speed for SBUS
24 #ifndef B100000
25 #define B100000 100000
26 #endif
27 
28 // for conversion between linux baud rate definition and actual speed
29 static inline int uart_speed(int def)
30 {
31  switch (def) {
32  case B1200: return 1200;
33  case B2400: return 2400;
34  case B4800: return 4800;
35  case B9600: return 9600;
36  case B19200: return 19200;
37  case B38400: return 38400;
38  case B57600: return 57600;
39  case B100000: return 100000;
40  case B115200: return 115200;
41  case B230400: return 230400;
42 #ifdef B921600
43  case B921600: return 921600;
44 #endif
45  default: return 9600;
46  }
47 }
48 
49 #define UBITS_7 7
50 #define UBITS_8 8
51 
52 #define USTOP_1 1
53 #define USTOP_2 2
54 
55 #define UPARITY_NO 0
56 #define UPARITY_ODD 1
57 #define UPARITY_EVEN 2
58 
60 
61 
62 
63 
64 // IUCLC flag translates upper case to lower case (actually needed here?)
65 // but is not in POSIX and OSX
66 #ifndef IUCLC
67 #define IUCLC 0
68 #endif
69 
70 //#define TRACE(type,fmt,args...) fprintf(stderr, fmt, args)
71 #define TRACE(type,fmt,args...)
72 #define TRACE_ERROR 1
73 
75 {
76  struct SerialPort *me = malloc(sizeof(struct SerialPort));
77  return me;
78 }
79 
80 void serial_port_free(struct SerialPort *me)
81 {
82  free(me);
83 }
84 
85 
86 #if !USE_ARBITRARY_BAUDRATE
87 // classic set baud function
88 
89 void serial_port_flush(struct SerialPort *me)
90 {
91  /*
92  * flush any input that might be on the port so we start fresh.
93  */
94  if (tcflush(me->fd, TCIFLUSH)) {
95  TRACE(TRACE_ERROR, "%s, set term attr failed: %s (%d)\n", "", strerror(errno), errno);
96  fprintf(stderr, "flush (%d) failed: %s (%d)\n", me->fd, strerror(errno), errno);
97  }
98 }
99 
101 {
102  /*
103  * flush any input that might be on the port so we start fresh.
104  */
105  if (tcflush(me->fd, TCOFLUSH)) {
106  TRACE(TRACE_ERROR, "%s, set term attr failed: %s (%d)\n", "", strerror(errno), errno);
107  fprintf(stderr, "flush (%d) failed: %s (%d)\n", me->fd, strerror(errno), errno);
108  }
109 }
110 
111 int serial_port_open_raw(struct SerialPort *me, const char *device, speed_t speed)
112 {
113  if ((me->fd = open(device, O_RDWR | O_NONBLOCK | O_NOCTTY)) < 0) {
114  TRACE(TRACE_ERROR, "%s, open failed: %s (%d)\n", device, strerror(errno), errno);
115  return -1;
116  }
117  if (tcgetattr(me->fd, &me->orig_termios) < 0) {
118  TRACE(TRACE_ERROR, "%s, get term settings failed: %s (%d)\n", device, strerror(errno), errno);
119  close(me->fd);
120  return -1;
121  }
122  me->cur_termios = me->orig_termios;
123  /* input modes */
124  me->cur_termios.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | INPCK | ISTRIP | INLCR | IGNCR
125  | ICRNL | IUCLC | IXON | IXANY | IXOFF | IMAXBEL);
126  me->cur_termios.c_iflag |= IGNPAR;
127  /* control modes*/
128  me->cur_termios.c_cflag &= ~(CSIZE | PARENB | CRTSCTS | PARODD | HUPCL | CSTOPB);
129  me->cur_termios.c_cflag |= CREAD | CS8 | CLOCAL;
130  /* local modes */
131  me->cur_termios.c_lflag &= ~(ISIG | ICANON | IEXTEN | ECHO | FLUSHO | PENDIN);
132  me->cur_termios.c_lflag |= NOFLSH;
133  /* output modes */
134  me->cur_termios.c_oflag &=~(OPOST|ONLCR|OCRNL|ONOCR|ONLRET);
135  /* no buffering */
136  me->cur_termios.c_cc[VTIME] = 0;
137  me->cur_termios.c_cc[VMIN] = 0;
138 
139  if (cfsetispeed(&me->cur_termios, speed)) {
140  TRACE(TRACE_ERROR, "%s, set term speed failed: %s (%d)\n", device, strerror(errno), errno);
141  close(me->fd);
142  return -1;
143  }
144  if (tcsetattr(me->fd, TCSADRAIN, &me->cur_termios)) {
145  TRACE(TRACE_ERROR, "%s, set term attr failed: %s (%d)\n", device, strerror(errno), errno);
146  close(me->fd);
147  return -1;
148  }
149  serial_port_flush(me);
150  return 0;
151 }
152 
153 int serial_port_open(struct SerialPort *me, const char *device,
154  void(*term_conf_callback)(struct termios *, speed_t *))
155 {
156 
157  speed_t speed;
158  if ((me->fd = open(device, O_RDWR | O_NONBLOCK)) < 0) {
159  TRACE(TRACE_ERROR, "%s, open failed: %s (%d)\n", device, strerror(errno), errno);
160  return -1;
161  }
162  if (tcgetattr(me->fd, &me->orig_termios) < 0) {
163  TRACE(TRACE_ERROR, "%s, get term settings failed: %s (%d)\n", device, strerror(errno), errno);
164  close(me->fd);
165  return -1;
166  }
167  me->cur_termios = me->orig_termios;
168  term_conf_callback(&me->cur_termios, &speed);
169  if (cfsetispeed(&me->cur_termios, speed)) {
170  TRACE(TRACE_ERROR, "%s, set term speed failed: %s (%d)\n", device, strerror(errno), errno);
171  close(me->fd);
172  return -1;
173  }
174  if (tcsetattr(me->fd, TCSADRAIN, &me->cur_termios)) {
175  TRACE(TRACE_ERROR, "%s, set term attr failed: %s (%d)\n", device, strerror(errno), errno);
176  close(me->fd);
177  return -1;
178  }
179  serial_port_flush(me);
180  return 0;
181 
182 }
183 
185 {
186 
187  /* if null pointer or file descriptor indicates error just bail */
188  if (!me || me->fd < 0) {
189  return;
190  }
191  if (tcflush(me->fd, TCIOFLUSH)) {
192  TRACE(TRACE_ERROR, "flushing (%s) (%d)\n", strerror(errno), errno);
193  close(me->fd);
194  return;
195  }
196  if (tcsetattr(me->fd, TCSADRAIN, &me->orig_termios)) { // Restore modes.
197  TRACE(TRACE_ERROR, "restoring term attributes (%s) (%d)\n", strerror(errno), errno);
198  close(me->fd);
199  return;
200  }
201  if (close(me->fd)) {
202  TRACE(TRACE_ERROR, "closing %s (%d)\n", strerror(errno), errno);
203  return;
204  }
205  return;
206 
207 
208 }
209 
210 int serial_port_set_baudrate(struct SerialPort *me, speed_t speed)
211 {
212  /* if null pointer or file descriptor indicates error just bail */
213  if (!me || me->fd < 0) {
214  return -1;
215  }
216  if (cfsetispeed(&me->cur_termios, speed)) {
217  TRACE(TRACE_ERROR, "%s, set term speed failed: %s (%d)\n", device, strerror(errno), errno);
218  close(me->fd);
219  return -1;
220  }
221  return 0;
222 }
223 
224 int serial_port_set_bits_stop_parity(struct SerialPort *me, const int bits, const int stop, const int parity)
225 {
226  /* if null pointer or file descriptor indicates error just bail */
227  if (!me || me->fd < 0) {
228  return -1;
229  }
230  // clear data bits
231  me->cur_termios.c_cflag &= ~CSIZE;
232  if (bits == UBITS_7) {
233  me->cur_termios.c_cflag |= CS7;
234  } else {
235  me->cur_termios.c_cflag |= CS8;
236  }
237  // set stops
238  if (stop == USTOP_1) {
239  me->cur_termios.c_cflag &= ~CSTOPB;
240  } else {
241  me->cur_termios.c_cflag |= CSTOPB;
242  }
243  // set parity
244  if (parity == UPARITY_EVEN) {
245  me->cur_termios.c_cflag |= PARENB;
246  me->cur_termios.c_cflag &= ~PARODD;
247  } else if (parity == UPARITY_ODD) {
248  me->cur_termios.c_cflag |= PARENB;
249  me->cur_termios.c_cflag |= PARODD;
250  } else {
251  me->cur_termios.c_cflag &= ~PARENB;
252  }
253  // set new parameters
254  if (tcsetattr(me->fd, TCSADRAIN, &me->cur_termios)) {
255  TRACE(TRACE_ERROR, "setting term attributes (%s) (%d)\n", strerror(errno), errno);
256  return -2;
257  }
258  return 0;
259 }
260 
261 #else // USE_ARBITRARY_BAUDRATE
262 // use termios2 interface
263 // needed to set arbitrary speed
264 // it is the case for the SBUS RC input
265 
266 int ioctl(int d, int request, ...); // avoid warning
267 int tcflush (int __fd, int __queue_selector); // avoid warning
268 
269 void serial_port_flush(struct SerialPort *me)
270 {
271  /*
272  * flush any input that might be on the port so we start fresh.
273  */
274  if (tcflush(me->fd, TCIFLUSH)) {
275  TRACE(TRACE_ERROR, "%s, set term attr failed: %s (%d)\n", "", strerror(errno), errno);
276  fprintf(stderr, "flush (%d) failed: %s (%d)\n", me->fd, strerror(errno), errno);
277  }
278 }
279 
280 void serial_port_flush_output(struct SerialPort *me)
281 {
282  /*
283  * flush any input that might be on the port so we start fresh.
284  */
285  if (tcflush(me->fd, TCOFLUSH)) {
286  TRACE(TRACE_ERROR, "%s, set term attr failed: %s (%d)\n", "", strerror(errno), errno);
287  fprintf(stderr, "flush (%d) failed: %s (%d)\n", me->fd, strerror(errno), errno);
288  }
289 }
290 
291 int serial_port_open_raw(struct SerialPort *me, const char *device, speed_t speed)
292 {
293  if ((me->fd = open(device, O_RDWR | O_NONBLOCK | O_NOCTTY)) < 0) {
294  TRACE(TRACE_ERROR, "%s, open failed: %s (%d)\n", device, strerror(errno), errno);
295  return -1;
296  }
297 
298  if (ioctl(me->fd, TCGETS2, &me->orig_termios)) {
299  perror("TCGETS2");
300  close(me->fd);
301  return -1;
302  }
303 
304  me->cur_termios = me->orig_termios;
305  /* input modes */
306  me->cur_termios.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | INPCK | ISTRIP | INLCR | IGNCR
307  | ICRNL | IUCLC | IXON | IXANY | IXOFF | IMAXBEL);
308  me->cur_termios.c_iflag |= IGNPAR;
309  /* control modes*/
310  me->cur_termios.c_cflag &= ~(CSIZE | PARENB | CRTSCTS | PARODD | HUPCL | CSTOPB);
311  me->cur_termios.c_cflag |= CREAD | CS8 | CLOCAL;
312  /* local modes */
313  me->cur_termios.c_lflag &= ~(ISIG | ICANON | IEXTEN | ECHO | FLUSHO | PENDIN);
314  me->cur_termios.c_lflag |= NOFLSH;
315  /* output modes */
316  me->cur_termios.c_oflag &=~(OPOST|ONLCR|OCRNL|ONOCR|ONLRET);
317  /* no buffering */
318  me->cur_termios.c_cc[VTIME] = 0;
319  me->cur_termios.c_cc[VMIN] = 0;
320 
321  me->cur_termios.c_cflag &= ~CBAUD;
322  me->cur_termios.c_cflag |= BOTHER;
323  me->cur_termios.c_ispeed = uart_speed(speed); // set real speed
324  me->cur_termios.c_ospeed = uart_speed(speed); // set real speed
325 
326  if (ioctl(me->fd, TCSETS2, &me->cur_termios)) {
327  perror("TCSETS2");
328  close(me->fd);
329  return -1;
330  }
331 
332  serial_port_flush(me);
333 
334  if (ioctl(me->fd, TCGETS2, &me->cur_termios))
335  {
336  perror("TCGETS2");
337  return 5;
338  }
339 
340  return 0;
341 }
342 
343 int serial_port_open(struct SerialPort *me, const char *device,
344  void(*term_conf_callback)(struct termios *, speed_t *))
345 {
346  (void)me;
347  (void)device;
348  (void)term_conf_callback;
349  return 0;
350 }
351 
352 void serial_port_close(struct SerialPort *me)
353 {
354 
355  /* if null pointer or file descriptor indicates error just bail */
356  if (!me || me->fd < 0) {
357  return;
358  }
359  if (tcflush(me->fd, TCIOFLUSH)) {
360  TRACE(TRACE_ERROR, "flushing (%s) (%d)\n", strerror(errno), errno);
361  close(me->fd);
362  return;
363  }
364  if (ioctl(me->fd, TCSETS2, &me->orig_termios)) { // Restore modes.
365  TRACE(TRACE_ERROR, "restoring term attributes (%s) (%d)\n", strerror(errno), errno);
366  perror("TCSETS2");
367  close(me->fd);
368  return;
369  }
370  if (close(me->fd)) {
371  TRACE(TRACE_ERROR, "closing %s (%d)\n", strerror(errno), errno);
372  return;
373  }
374  return;
375 
376 }
377 
378 int serial_port_set_baudrate(struct SerialPort *me, speed_t speed)
379 {
380  /* if null pointer or file descriptor indicates error just bail */
381  if (!me || me->fd < 0) {
382  return -1;
383  }
384 
385  me->cur_termios.c_cflag &= ~CBAUD;
386  me->cur_termios.c_cflag |= BOTHER;
387  me->cur_termios.c_ispeed = uart_speed(speed); // set real speed
388  me->cur_termios.c_ospeed = uart_speed(speed); // set real speed
389 
390  // set new parameters
391  if (ioctl(me->fd, TCSETS2, &me->cur_termios)) {
392  perror("TCSETS2");
393  close(me->fd);
394  return -1;
395  }
396  return 0;
397 }
398 
399 
400 int serial_port_set_bits_stop_parity(struct SerialPort *me, const int bits, const int stop, const int parity)
401 {
402  /* if null pointer or file descriptor indicates error just bail */
403  if (!me || me->fd < 0) {
404  return -1;
405  }
406  // clear data bits
407  me->cur_termios.c_cflag &= ~CSIZE;
408  if (bits == UBITS_7) {
409  me->cur_termios.c_cflag |= CS7;
410  } else {
411  me->cur_termios.c_cflag |= CS8;
412  }
413  // set stops
414  if (stop == USTOP_1) {
415  me->cur_termios.c_cflag &= ~CSTOPB;
416  } else {
417  me->cur_termios.c_cflag |= CSTOPB;
418  }
419  // set parity
420  if (parity == UPARITY_EVEN) {
421  me->cur_termios.c_cflag |= PARENB;
422  me->cur_termios.c_cflag &= ~PARODD;
423  me->cur_termios.c_iflag |= INPCK;
424  } else if (parity == UPARITY_ODD) {
425  me->cur_termios.c_cflag |= PARENB;
426  me->cur_termios.c_cflag |= PARODD;
427  me->cur_termios.c_iflag |= INPCK;
428  } else {
429  me->cur_termios.c_cflag &= ~PARENB;
430  me->cur_termios.c_iflag &= ~INPCK;
431  }
432  // set new parameters
433  if (ioctl(me->fd, TCSETS2, &me->cur_termios)) {
434  perror("TCSETS2");
435  close(me->fd);
436  return -1;
437  }
438  return 0;
439 }
440 
441 #endif
442 
B19200
#define B19200
Definition: uart_arch.h:44
SerialPort::fd
int fd
Definition: serial_port.h:30
serial_port.h
serial_port_flush
void serial_port_flush(struct SerialPort *me)
Definition: serial_port.c:89
UPARITY_EVEN
#define UPARITY_EVEN
Definition: serial_port.c:57
UPARITY_ODD
#define UPARITY_ODD
Definition: serial_port.c:56
B230400
#define B230400
Definition: uart_arch.h:49
serial_port_open_raw
int serial_port_open_raw(struct SerialPort *me, const char *device, speed_t speed)
Definition: serial_port.c:111
serial_port_set_bits_stop_parity
int serial_port_set_bits_stop_parity(struct SerialPort *me, const int bits, const int stop, const int parity)
Definition: serial_port.c:224
B921600
#define B921600
Definition: uart_arch.h:50
serial_port_flush_output
void serial_port_flush_output(struct SerialPort *me)
Definition: serial_port.c:100
B4800
#define B4800
Definition: uart_arch.h:42
SerialPort::cur_termios
struct termios cur_termios
Definition: serial_port.h:32
serial_port_open
int serial_port_open(struct SerialPort *me, const char *device, void(*term_conf_callback)(struct termios *, speed_t *))
Definition: serial_port.c:153
serial_port_set_baudrate
int serial_port_set_baudrate(struct SerialPort *me, speed_t speed)
Definition: serial_port.c:210
IUCLC
#define IUCLC
Definition: serial_port.c:67
serial_port_close
void serial_port_close(struct SerialPort *me)
Definition: serial_port.c:184
TRACE_ERROR
#define TRACE_ERROR
Definition: serial_port.c:72
serial_port_new
struct SerialPort * serial_port_new(void)
Definition: serial_port.c:74
B2400
#define B2400
Definition: uart_arch.h:41
UBITS_7
#define UBITS_7
Definition: serial_port.c:49
B57600
#define B57600
Definition: uart_arch.h:46
B1200
#define B1200
Definition: uart_arch.h:40
uart_speed
static int uart_speed(int def)
Definition: serial_port.c:29
B9600
#define B9600
Definition: uart_arch.h:43
B38400
#define B38400
Definition: uart_arch.h:45
SerialPort::orig_termios
struct termios orig_termios
Definition: serial_port.h:31
USTOP_1
#define USTOP_1
Definition: serial_port.c:52
TRACE
#define TRACE(type, fmt, args...)
Definition: serial_port.c:71
B100000
#define B100000
some definitions from PPRZ uart driver as we can't include it directly
Definition: serial_port.c:25
SerialPort
Definition: serial_port.h:29
serial_port_free
void serial_port_free(struct SerialPort *me)
Definition: serial_port.c:80
B115200
#define B115200
Definition: uart_arch.h:48