Paparazzi UAS  v5.12_stable-4-g9b43e9b
Paparazzi is a free software Unmanned Aircraft System.
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
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 
136  if (cfsetispeed(&me->cur_termios, speed)) {
137  TRACE(TRACE_ERROR, "%s, set term speed failed: %s (%d)\n", device, strerror(errno), errno);
138  close(me->fd);
139  return -1;
140  }
141  if (tcsetattr(me->fd, TCSADRAIN, &me->cur_termios)) {
142  TRACE(TRACE_ERROR, "%s, set term attr failed: %s (%d)\n", device, strerror(errno), errno);
143  close(me->fd);
144  return -1;
145  }
146  serial_port_flush(me);
147  return 0;
148 }
149 
150 int serial_port_open(struct SerialPort *me, const char *device,
151  void(*term_conf_callback)(struct termios *, speed_t *))
152 {
153 
154  speed_t speed;
155  if ((me->fd = open(device, O_RDWR | O_NONBLOCK)) < 0) {
156  TRACE(TRACE_ERROR, "%s, open failed: %s (%d)\n", device, strerror(errno), errno);
157  return -1;
158  }
159  if (tcgetattr(me->fd, &me->orig_termios) < 0) {
160  TRACE(TRACE_ERROR, "%s, get term settings failed: %s (%d)\n", device, strerror(errno), errno);
161  close(me->fd);
162  return -1;
163  }
164  me->cur_termios = me->orig_termios;
165  term_conf_callback(&me->cur_termios, &speed);
166  if (cfsetispeed(&me->cur_termios, speed)) {
167  TRACE(TRACE_ERROR, "%s, set term speed failed: %s (%d)\n", device, strerror(errno), errno);
168  close(me->fd);
169  return -1;
170  }
171  if (tcsetattr(me->fd, TCSADRAIN, &me->cur_termios)) {
172  TRACE(TRACE_ERROR, "%s, set term attr failed: %s (%d)\n", device, strerror(errno), errno);
173  close(me->fd);
174  return -1;
175  }
176  serial_port_flush(me);
177  return 0;
178 
179 }
180 
182 {
183 
184  /* if null pointer or file descriptor indicates error just bail */
185  if (!me || me->fd < 0) {
186  return;
187  }
188  if (tcflush(me->fd, TCIOFLUSH)) {
189  TRACE(TRACE_ERROR, "flushing (%s) (%d)\n", strerror(errno), errno);
190  close(me->fd);
191  return;
192  }
193  if (tcsetattr(me->fd, TCSADRAIN, &me->orig_termios)) { // Restore modes.
194  TRACE(TRACE_ERROR, "restoring term attributes (%s) (%d)\n", strerror(errno), errno);
195  close(me->fd);
196  return;
197  }
198  if (close(me->fd)) {
199  TRACE(TRACE_ERROR, "closing %s (%d)\n", strerror(errno), errno);
200  return;
201  }
202  return;
203 
204 
205 }
206 
207 int serial_port_set_baudrate(struct SerialPort *me, speed_t speed)
208 {
209  /* if null pointer or file descriptor indicates error just bail */
210  if (!me || me->fd < 0) {
211  return -1;
212  }
213  if (cfsetispeed(&me->cur_termios, speed)) {
214  TRACE(TRACE_ERROR, "%s, set term speed failed: %s (%d)\n", device, strerror(errno), errno);
215  close(me->fd);
216  return -1;
217  }
218  return 0;
219 }
220 
221 int serial_port_set_bits_stop_parity(struct SerialPort *me, const int bits, const int stop, const int parity)
222 {
223  /* if null pointer or file descriptor indicates error just bail */
224  if (!me || me->fd < 0) {
225  return -1;
226  }
227  // clear data bits
228  me->cur_termios.c_cflag &= ~CSIZE;
229  if (bits == UBITS_7) {
230  me->cur_termios.c_cflag |= CS7;
231  } else {
232  me->cur_termios.c_cflag |= CS8;
233  }
234  // set stops
235  if (stop == USTOP_1) {
236  me->cur_termios.c_cflag &= ~CSTOPB;
237  } else {
238  me->cur_termios.c_cflag |= CSTOPB;
239  }
240  // set parity
241  if (parity == UPARITY_EVEN) {
242  me->cur_termios.c_cflag |= PARENB;
243  me->cur_termios.c_cflag &= ~PARODD;
244  } else if (parity == UPARITY_ODD) {
245  me->cur_termios.c_cflag |= PARENB;
246  me->cur_termios.c_cflag |= PARODD;
247  } else {
248  me->cur_termios.c_cflag &= ~PARENB;
249  }
250  // set new parameters
251  if (tcsetattr(me->fd, TCSADRAIN, &me->cur_termios)) {
252  TRACE(TRACE_ERROR, "setting term attributes (%s) (%d)\n", strerror(errno), errno);
253  return -2;
254  }
255  return 0;
256 }
257 
258 #else // USE_ARBITRARY_BAUDRATE
259 // use termios2 interface
260 // needed to set arbitrary speed
261 // it is the case for the SBUS RC input
262 
263 int ioctl(int d, int request, ...); // avoid warning
264 int tcflush (int __fd, int __queue_selector); // avoid warning
265 
266 void serial_port_flush(struct SerialPort *me)
267 {
268  /*
269  * flush any input that might be on the port so we start fresh.
270  */
271  if (tcflush(me->fd, TCIFLUSH)) {
272  TRACE(TRACE_ERROR, "%s, set term attr failed: %s (%d)\n", "", strerror(errno), errno);
273  fprintf(stderr, "flush (%d) failed: %s (%d)\n", me->fd, strerror(errno), errno);
274  }
275 }
276 
277 void serial_port_flush_output(struct SerialPort *me)
278 {
279  /*
280  * flush any input that might be on the port so we start fresh.
281  */
282  if (tcflush(me->fd, TCOFLUSH)) {
283  TRACE(TRACE_ERROR, "%s, set term attr failed: %s (%d)\n", "", strerror(errno), errno);
284  fprintf(stderr, "flush (%d) failed: %s (%d)\n", me->fd, strerror(errno), errno);
285  }
286 }
287 
288 int serial_port_open_raw(struct SerialPort *me, const char *device, speed_t speed)
289 {
290  if ((me->fd = open(device, O_RDWR | O_NONBLOCK | O_NOCTTY)) < 0) {
291  TRACE(TRACE_ERROR, "%s, open failed: %s (%d)\n", device, strerror(errno), errno);
292  return -1;
293  }
294 
295  if (ioctl(me->fd, TCGETS2, &me->orig_termios)) {
296  perror("TCGETS2");
297  close(me->fd);
298  return -1;
299  }
300 
301  me->cur_termios = me->orig_termios;
302  /* input modes */
303  me->cur_termios.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | INPCK | ISTRIP | INLCR | IGNCR
304  | ICRNL | IUCLC | IXON | IXANY | IXOFF | IMAXBEL);
305  me->cur_termios.c_iflag |= IGNPAR;
306  /* control modes*/
307  me->cur_termios.c_cflag &= ~(CSIZE | PARENB | CRTSCTS | PARODD | HUPCL | CSTOPB);
308  me->cur_termios.c_cflag |= CREAD | CS8 | CLOCAL;
309  /* local modes */
310  me->cur_termios.c_lflag &= ~(ISIG | ICANON | IEXTEN | ECHO | FLUSHO | PENDIN);
311  me->cur_termios.c_lflag |= NOFLSH;
312  /* output modes */
313  me->cur_termios.c_oflag &=~(OPOST|ONLCR|OCRNL|ONOCR|ONLRET);
314 
315  me->cur_termios.c_cflag &= ~CBAUD;
316  me->cur_termios.c_cflag |= BOTHER;
317  me->cur_termios.c_ispeed = uart_speed(speed); // set real speed
318  me->cur_termios.c_ospeed = uart_speed(speed); // set real speed
319 
320  if (ioctl(me->fd, TCSETS2, &me->cur_termios)) {
321  perror("TCSETS2");
322  close(me->fd);
323  return -1;
324  }
325 
326  serial_port_flush(me);
327 
328  if (ioctl(me->fd, TCGETS2, &me->cur_termios))
329  {
330  perror("TCGETS2");
331  return 5;
332  }
333 
334  return 0;
335 }
336 
337 int serial_port_open(struct SerialPort *me, const char *device,
338  void(*term_conf_callback)(struct termios *, speed_t *))
339 {
340  (void)me;
341  (void)device;
342  (void)term_conf_callback;
343  return 0;
344 }
345 
346 void serial_port_close(struct SerialPort *me)
347 {
348 
349  /* if null pointer or file descriptor indicates error just bail */
350  if (!me || me->fd < 0) {
351  return;
352  }
353  if (tcflush(me->fd, TCIOFLUSH)) {
354  TRACE(TRACE_ERROR, "flushing (%s) (%d)\n", strerror(errno), errno);
355  close(me->fd);
356  return;
357  }
358  if (ioctl(me->fd, TCSETS2, &me->orig_termios)) { // Restore modes.
359  TRACE(TRACE_ERROR, "restoring term attributes (%s) (%d)\n", strerror(errno), errno);
360  perror("TCSETS2");
361  close(me->fd);
362  return;
363  }
364  if (close(me->fd)) {
365  TRACE(TRACE_ERROR, "closing %s (%d)\n", strerror(errno), errno);
366  return;
367  }
368  return;
369 
370 }
371 
372 int serial_port_set_baudrate(struct SerialPort *me, speed_t speed)
373 {
374  /* if null pointer or file descriptor indicates error just bail */
375  if (!me || me->fd < 0) {
376  return -1;
377  }
378 
379  me->cur_termios.c_cflag &= ~CBAUD;
380  me->cur_termios.c_cflag |= BOTHER;
381  me->cur_termios.c_ispeed = uart_speed(speed); // set real speed
382  me->cur_termios.c_ospeed = uart_speed(speed); // set real speed
383 
384  // set new parameters
385  if (ioctl(me->fd, TCSETS2, &me->cur_termios)) {
386  perror("TCSETS2");
387  close(me->fd);
388  return -1;
389  }
390  return 0;
391 }
392 
393 
394 int serial_port_set_bits_stop_parity(struct SerialPort *me, const int bits, const int stop, const int parity)
395 {
396  /* if null pointer or file descriptor indicates error just bail */
397  if (!me || me->fd < 0) {
398  return -1;
399  }
400  // clear data bits
401  me->cur_termios.c_cflag &= ~CSIZE;
402  if (bits == UBITS_7) {
403  me->cur_termios.c_cflag |= CS7;
404  } else {
405  me->cur_termios.c_cflag |= CS8;
406  }
407  // set stops
408  if (stop == USTOP_1) {
409  me->cur_termios.c_cflag &= ~CSTOPB;
410  } else {
411  me->cur_termios.c_cflag |= CSTOPB;
412  }
413  // set parity
414  if (parity == UPARITY_EVEN) {
415  me->cur_termios.c_cflag |= PARENB;
416  me->cur_termios.c_cflag &= ~PARODD;
417  me->cur_termios.c_iflag |= INPCK;
418  } else if (parity == UPARITY_ODD) {
419  me->cur_termios.c_cflag |= PARENB;
420  me->cur_termios.c_cflag |= PARODD;
421  me->cur_termios.c_iflag |= INPCK;
422  } else {
423  me->cur_termios.c_cflag &= ~PARENB;
424  me->cur_termios.c_iflag &= ~INPCK;
425  }
426  // set new parameters
427  if (ioctl(me->fd, TCSETS2, &me->cur_termios)) {
428  perror("TCSETS2");
429  close(me->fd);
430  return -1;
431  }
432  return 0;
433 }
434 
435 #endif
436 
#define B38400
Definition: uart_arch.h:45
#define USTOP_1
Definition: serial_port.c:52
#define UPARITY_EVEN
Definition: serial_port.c:57
int serial_port_set_bits_stop_parity(struct SerialPort *me, const int bits, const int stop, const int parity)
Definition: serial_port.c:221
void serial_port_flush_output(struct SerialPort *me)
Definition: serial_port.c:100
#define B115200
Definition: uart_arch.h:48
#define TRACE(type, fmt, args...)
Definition: serial_port.c:71
struct termios orig_termios
Definition: serial_port.h:31
#define IUCLC
Definition: serial_port.c:67
void serial_port_flush(struct SerialPort *me)
Definition: serial_port.c:89
#define B230400
Definition: uart_arch.h:49
void serial_port_free(struct SerialPort *me)
Definition: serial_port.c:80
#define B921600
Definition: uart_arch.h:50
#define B19200
Definition: uart_arch.h:44
#define UBITS_7
Definition: serial_port.c:49
#define B4800
Definition: uart_arch.h:42
#define B100000
some definitions from PPRZ uart driver as we can't include it directly
Definition: serial_port.c:25
#define B2400
Definition: uart_arch.h:41
#define B9600
Definition: uart_arch.h:43
#define UPARITY_ODD
Definition: serial_port.c:56
struct termios cur_termios
Definition: serial_port.h:32
struct SerialPort * serial_port_new(void)
Definition: serial_port.c:74
void serial_port_close(struct SerialPort *me)
Definition: serial_port.c:181
int serial_port_open_raw(struct SerialPort *me, const char *device, speed_t speed)
Definition: serial_port.c:111
int serial_port_open(struct SerialPort *me, const char *device, void(*term_conf_callback)(struct termios *, speed_t *))
Definition: serial_port.c:150
#define B1200
Definition: uart_arch.h:40
#define TRACE_ERROR
Definition: serial_port.c:72
int serial_port_set_baudrate(struct SerialPort *me, speed_t speed)
Definition: serial_port.c:207
#define B57600
Definition: uart_arch.h:46
static int uart_speed(int def)
Definition: serial_port.c:29