serial_port.cpp
Go to the documentation of this file.
1 // *****************************************************************************
2 //
3 // Copyright (c) 2014, Southwest Research Institute® (SwRI®)
4 // All rights reserved.
5 //
6 // Redistribution and use in source and binary forms, with or without
7 // modification, are permitted provided that the following conditions are met:
8 // * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above copyright
11 // notice, this list of conditions and the following disclaimer in the
12 // documentation and/or other materials provided with the distribution.
13 // * Neither the name of Southwest Research Institute® (SwRI®) nor the
14 // names of its contributors may be used to endorse or promote products
15 // derived from this software without specific prior written permission.
16 //
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 // ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
21 // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 //
28 // *****************************************************************************
29 
31 
32 #include <errno.h> // NOLINT
33 #include <sys/ioctl.h>
34 #include <fcntl.h>
35 #include <unistd.h>
36 #include <poll.h>
37 #include <termios.h>
38 #include <linux/serial.h>
39 #include <cstring>
40 
41 #include <boost/lexical_cast.hpp>
42 
43 namespace swri_serial_util
44 {
46  baud(B115200),
47  data_bits(8),
48  stop_bits(1),
49  parity(NO_PARITY),
50  flow_control(false),
51  low_latency_mode(false),
52  writable(false)
53  {
54  }
55 
57  int32_t baud,
58  int32_t data_bits,
59  int32_t stop_bits,
60  Parity parity,
61  bool flow_control,
62  bool low_latency_mode,
63  bool writable) :
64  baud(baud),
65  data_bits(data_bits),
66  stop_bits(stop_bits),
67  parity(parity),
68  flow_control(flow_control),
69  low_latency_mode(low_latency_mode),
70  writable(writable)
71  {
72  }
73 
75  fd_(-1),
76  error_msg_("")
77  {
78  }
79 
81  {
82  Close();
83  }
84 
86  {
87  if (fd_ < 0)
88  return;
89 
90  close(fd_);
91  fd_ = -1;
92  }
93 
94  bool SerialPort::Open(const std::string &device, SerialConfig config)
95  {
96  Close();
97 
98  int32_t baud = ParseBaudRate(config.baud);
99  if (baud == -1)
100  {
101  error_msg_ = "Invalid baud rate: " + boost::lexical_cast<std::string>(config.baud);
102  return false;
103  }
104 
105  if (config.stop_bits != 1 && config.stop_bits != 2)
106  {
107  error_msg_ = "Invalid stop bits: " + boost::lexical_cast<std::string>(config.stop_bits);
108  return false;
109  }
110 
111  if (config.data_bits != 7 && config.data_bits != 8)
112  {
113  error_msg_ = "Invalid data bits: " + boost::lexical_cast<std::string>(config.data_bits);
114  return false;
115  }
116 
117  if (config.parity != SerialConfig::NO_PARITY &&
118  config.parity != SerialConfig::EVEN_PARITY &&
120  {
121  error_msg_ = "Invalid parity mode.";
122  return false;
123  }
124 
125  fd_ = open(device.c_str(), config.writable ? O_RDWR : O_RDONLY);
126  if (fd_ == -1)
127  {
128  error_msg_ = "Error opening serial port <" + device + ">: " + strerror(errno);
129  return false;
130  }
131 
132  struct termios term;
133  if (tcgetattr(fd_, &term) < 0)
134  {
135  error_msg_ = "Unable to set serial attributes <" + device + ">: " + strerror(errno);
136  Close();
137  return false;
138  }
139 
140  cfmakeraw(&term);
141 
142  if (config.stop_bits == 2)
143  {
144  term.c_cflag |= CSTOPB;
145  }
146  else
147  {
148  term.c_cflag &= ~CSTOPB;
149  }
150 
151  if (config.parity == SerialConfig::EVEN_PARITY)
152  {
153  term.c_cflag |= PARENB;
154  term.c_cflag &= ~PARODD;
155  }
156  else if (config.parity == SerialConfig::ODD_PARITY)
157  {
158  term.c_cflag |= PARENB;
159  term.c_cflag |= PARODD;
160  }
161  else
162  {
163  term.c_cflag &= ~PARENB;
164  term.c_cflag &= ~PARODD;
165  }
166 
167  if (config.data_bits == 8)
168  {
169  term.c_cflag &= ~CSIZE;
170  term.c_cflag |= CS8;
171  }
172  else
173  {
174  term.c_cflag &= ~CSIZE;
175  term.c_cflag |= CS7;
176  }
177 
178  if (cfsetspeed(&term, config.baud) < 0)
179  {
180  error_msg_ = "Invalid baud rate: " + boost::lexical_cast<std::string>(config.baud);
181  Close();
182  return false;
183  }
184 
185  if (tcsetattr(fd_, TCSAFLUSH, &term) < 0)
186  {
187  error_msg_ = "Unable to set serial port attributes <" + device + ">: " + strerror(errno);
188  Close();
189  return false;
190  }
191 
192  if (config.low_latency_mode && !SetLowLatencyMode())
193  {
194  Close();
195  return false;
196  }
197 
198  return true;
199  }
200 
202  {
203  if (fd_ < 0)
204  {
205  error_msg_ = "Device not open.";
206  return false;
207  }
208 
209  struct serial_struct serial_info;
210 
211  if (ioctl(fd_, TIOCGSERIAL, &serial_info) < 0)
212  {
213  error_msg_ = "Failed to set low latency mode. Cannot get serial configuration: " + std::string(strerror(errno));
214  return false;
215  }
216 
217  serial_info.flags |= ASYNC_LOW_LATENCY;
218 
219  if (ioctl(fd_, TIOCSSERIAL, &serial_info) < 0)
220  {
221  error_msg_ = "Failed to set low latency mode. Cannot set serial configuration: " + std::string(strerror(errno));
222  return false;
223  }
224 
225  return true;
226  }
227 
228  int32_t SerialPort::ParseBaudRate(int32_t baud)
229  {
230  int32_t value = -1;
231 
232  if (baud == B50 || baud == 50)
233  {
234  value = B50;
235  }
236  else if (baud == B75 || baud == 75)
237  {
238  value = B75;
239  }
240  else if (baud == B110 || baud == 110)
241  {
242  value = B110;
243  }
244  else if (baud == B134 || baud == 134)
245  {
246  value = B134;
247  }
248  else if (baud == B150 || baud == 150)
249  {
250  value = B150;
251  }
252  else if (baud == B200 || baud == 200)
253  {
254  value = B200;
255  }
256  else if (baud == B300 || baud == 300)
257  {
258  value = B300;
259  }
260  else if (baud == B600 || baud == 600)
261  {
262  value = B600;
263  }
264  else if (baud == B1200 || baud == 1200)
265  {
266  value = B1200;
267  }
268  else if (baud == B1800 || baud == 1800)
269  {
270  value = B1800;
271  }
272  else if (baud == B2400 || baud == 2400)
273  {
274  value = B2400;
275  }
276  else if (baud == B4800 || baud == 4800)
277  {
278  value = B4800;
279  }
280  else if (baud == B9600 || baud == 9600)
281  {
282  value = B9600;
283  }
284  else if (baud == B19200 || baud == 19200)
285  {
286  value = B19200;
287  }
288  else if (baud == B38400 || baud == 38400)
289  {
290  value = B38400;
291  }
292  else if (baud == B57600 || baud == 57600)
293  {
294  value = B57600;
295  }
296  else if (baud == B115200 || baud == 115200)
297  {
298  value = B115200;
299  }
300  else if (baud == B230400 || baud == 230400)
301  {
302  value = B230400;
303  }
304  else if (baud == B460800 || baud == 460800)
305  {
306  value = B460800;
307  }
308  else if (baud == B576000 || baud == 576000)
309  {
310  value = B576000;
311  }
312  else if (baud == B921600 || baud == 921600)
313  {
314  value = B921600;
315  }
316  else if (baud == B1000000 || baud == 1000000)
317  {
318  value = B1000000;
319  }
320  else if (baud == B1152000 || baud == 1152000)
321  {
322  value = B1152000;
323  }
324  else if (baud == B1500000 || baud == 1500000)
325  {
326  value = B1500000;
327  }
328  else if (baud == B2000000 || baud == 2000000)
329  {
330  value = B2000000;
331  }
332  else if (baud == B2500000 || baud == 2500000)
333  {
334  value = B2500000;
335  }
336  else if (baud == B3000000 || baud == 3000000)
337  {
338  value = B3000000;
339  }
340  else if (baud == B3500000 || baud == 3500000)
341  {
342  value = B3500000;
343  }
344  else if (baud == B4000000 || baud == 4000000)
345  {
346  value = B4000000;
347  }
348 
349  return value;
350  }
351 
352  SerialPort::Result SerialPort::ReadBytes(std::vector<uint8_t>& output, size_t max_bytes, int32_t timeout)
353  {
354  if (fd_ < 0)
355  {
356  error_msg_ = "Device not open.";
357  return ERROR;
358  }
359 
360  struct pollfd fds[1];
361  fds[0].fd = fd_;
362  fds[0].events = POLLIN;
363 
364  int poll_return = poll(fds, 1, timeout);
365  if (poll_return == 0)
366  {
367  error_msg_ = "Timed out while waiting for data.";
368  return TIMEOUT;
369  }
370  else if (poll_return < 0)
371  {
372  int error_num = errno;
373  switch (error_num)
374  {
375  case EINTR:
376  return INTERRUPTED;
377  default:
378  error_msg_ = "Error polling serial port: " + std::string(strerror(errno));
379  return ERROR;
380  }
381  }
382 
383  size_t to_read = max_bytes;
384  if (to_read <= 0)
385  {
386  int bytes;
387  ioctl(fd_, FIONREAD, &bytes);
388  if (bytes < 0)
389  {
390  error_msg_ = "Error getting number of available bytes from serial port: " + std::string(strerror(errno));
391  return ERROR;
392  }
393  to_read = static_cast<size_t>(bytes);
394  }
395 
396  size_t output_size = output.size();
397  output.resize(output_size + to_read);
398 
399  int result = read(fd_, output.data() + output_size, to_read);
400 
401  if (result > 0)
402  {
403  output.resize(output_size + result);
404  }
405  else
406  {
407  output.resize(output_size);
408  }
409 
410  if (result > 0)
411  {
412  return SUCCESS;
413  }
414  else if (result == 0)
415  {
416  return INTERRUPTED;
417  }
418  else
419  {
420  int error_num = errno;
421  switch (error_num)
422  {
423  case EINTR:
424  return INTERRUPTED;
425  break;
426  default:
427  error_msg_ = "Error reading serial port: " + std::string(strerror(errno));
428  return ERROR;
429  }
430  }
431  }
432 
433  int32_t SerialPort::Write(const std::vector<uint8_t>& input)
434  {
435  return write(fd_, input.data(), input.size());
436  }
437 }
virtual bool Open(const std::string &device, SerialConfig config=SerialConfig())
Definition: serial_port.cpp:94
virtual int32_t Write(const std::vector< uint8_t > &input)
virtual Result ReadBytes(std::vector< uint8_t > &output, size_t max_bytes, int32_t timeout)
int32_t ParseBaudRate(int32_t baud)


swri_serial_util
Author(s): Marc Alban
autogenerated on Tue Apr 6 2021 02:50:43