SELKIELogger  1.0.0
serial.c
1 /*
2  * Copyright (C) 2023 Swansea University
3  *
4  * This file is part of the SELKIELogger suite of tools.
5  *
6  * SELKIELogger is free software: you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License as published by the Free
8  * Software Foundation, either version 3 of the License, or (at your option)
9  * any later version.
10  *
11  * SELKIELogger is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14  * more details.
15  *
16  * You should have received a copy of the GNU General Public License along
17  * with this SELKIELogger product.
18  * If not, see <http://www.gnu.org/licenses/>.
19 */
20 
21 #include <errno.h>
22 #include <fcntl.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <termios.h>
26 #include <unistd.h>
27 
28 #include "serial.h"
29 
44 int openSerialConnection(const char *port, const int baudRate) {
45  errno = 0;
46  int handle = open(port, O_RDWR | O_NOCTTY | O_DSYNC | O_NDELAY);
47  if (handle < 0) {
48  fprintf(stderr, "Unexpected error while reading from serial port (Device: %s)\n", port);
49  fprintf(stderr, "open() returned \"%s\"\n", strerror(errno));
50  return -1;
51  }
52 
53  fcntl(handle, F_SETFL, FNDELAY); // Make read() return 0 if no data
54 
55  struct termios options;
56  // Get options, adjust baud and enable local control (cf. NoCTTY) and push to
57  // interface
58  tcgetattr(handle, &options);
59 
60  speed_t rate = baud_to_flag(baudRate);
61  if (rate == (speed_t)-1) {
62  fprintf(stderr, "Unsupported baud rate requested: %d\n", baudRate);
63  return -1;
64  }
65 
66  cfsetispeed(&options, rate);
67  cfsetospeed(&options, rate);
68  options.c_oflag &= ~OPOST; // Disable any post processing
69  options.c_cflag &= ~(PARENB | CSTOPB | CSIZE);
70  options.c_cflag |= (CLOCAL | CREAD);
71  options.c_cflag |= CS8;
72  options.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON);
73  options.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
74  options.c_cc[VTIME] = 1;
75  options.c_cc[VMIN] = 0;
76  if (tcsetattr(handle, TCSANOW, &options)) { fprintf(stderr, "tcsetattr() failed!\n"); }
77  tcdrain(handle);
78  {
79  struct termios check;
80  tcgetattr(handle, &check);
81  if (cfgetispeed(&check) != rate) {
82  fprintf(stderr, "Unable to set target baud. Wanted %d, got %d\n", baudRate,
83  flag_to_baud(cfgetispeed(&check)));
84  /*close(handle); // Don't leave file descriptor dangling
85  return -1; */
86  }
87  }
88 
89  return handle;
90 }
91 
100 int baud_to_flag(const int rate) {
101  switch (rate) {
102  case 0:
103  return B0;
104  case 1200:
105  return B1200;
106  case 2400:
107  return B2400;
108  case 4800:
109  return B4800;
110  case 9600:
111  return B9600;
112  case 19200:
113  return B19200;
114  case 38400:
115  return B38400;
116  case 57600:
117  return B57600;
118  case 115200:
119  return B115200;
120  case 230400:
121  return B230400;
122  case 460800:
123  return B460800;
124  case 500000:
125  return B500000;
126  case 576000:
127  return B576000;
128  case 921600:
129  return B921600;
130  case 1000000:
131  return B1000000;
132  case 1152000:
133  return B1152000;
134  case 1500000:
135  return B1500000;
136  case 2000000:
137  return B2000000;
138 #ifdef B2500000
139  case 2500000:
140  return B2500000;
141 #endif
142 #ifdef B3000000
143  case 3000000:
144  return B3000000;
145 #endif
146 #ifdef B3500000
147  case 3500000:
148  return B3500000;
149 #endif
150 #ifdef B4000000
151  case 4000000:
152  return B4000000;
153 #endif
154  default:
155  return -1;
156  }
157 }
158 
166 int flag_to_baud(const int flag) {
167  switch (flag) {
168  case B0:
169  return 0;
170  case B1200:
171  return 1200;
172  case B2400:
173  return 2400;
174  case B4800:
175  return 4800;
176  case B9600:
177  return 9600;
178  case B19200:
179  return 19200;
180  case B38400:
181  return 38400;
182  case B57600:
183  return 57600;
184  case B115200:
185  return 115200;
186  case B230400:
187  return 230400;
188  case B460800:
189  return 460800;
190  case B500000:
191  return 500000;
192  case B576000:
193  return 576000;
194  case B921600:
195  return 921600;
196  case B1000000:
197  return 1000000;
198  case B1152000:
199  return 1152000;
200  case B1500000:
201  return 1500000;
202  case B2000000:
203  return 2000000;
204 #ifdef B2500000
205  case B2500000:
206  return 2500000;
207 #endif
208 #ifdef B3000000
209  case B3000000:
210  return 3000000;
211 #endif
212 #ifdef B3500000
213  case B3500000:
214  return 3500000;
215 #endif
216 #ifdef B4000000
217  case B4000000:
218  return 4000000;
219 #endif
220  default:
221  return -1;
222  }
223 }
int openSerialConnection(const char *port, const int baudRate)
Open a serial connection at a given baud rate.
Definition: serial.c:44
int baud_to_flag(const int rate)
Convert a numerical baud rate to termios flag.
Definition: serial.c:100
int flag_to_baud(const int flag)
Convert a termios baud rate flag to a numerical value.
Definition: serial.c:166