serial_port.cpp
Go to the documentation of this file.
1 /*********************************************************************
2 *
3 * Software License Agreement (BSD License)
4 *
5 * Copyright (c) 2010, ISR University of Coimbra.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * * Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * * Redistributions in binary form must reproduce the above
15 * copyright notice, this list of conditions and the following
16 * disclaimer in the documentation and/or other materials provided
17 * with the distribution.
18 * * Neither the name of the ISR University of Coimbra nor the names of its
19 * contributors may be used to endorse or promote products derived
20 * from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
30 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 * POSSIBILITY OF SUCH DAMAGE.
34 *
35 * Author: Gonçalo Cabrita on 01/10/2010
36 *********************************************************************/
37 
38 #include <errno.h>
39 #include <fcntl.h>
40 #include <math.h>
41 #include <poll.h>
42 #include <signal.h>
43 #include <stdio.h>
44 #include <string.h>
45 #include <termios.h>
46 #include <unistd.h>
47 #include <fstream>
48 #include <iostream>
49 #include <stdexcept>
50 #include <string>
51 
52 #include "kvh/serial_port.h"
53 
55 #define SERIAL_EXCEPT(except, msg, ...) \
56  { \
57  char buf[1000]; \
58  snprintf(buf, sizeof(buf), msg " (in SerialPort::%s)", ##__VA_ARGS__, __FUNCTION__); \
59  throw except(buf); \
60  }
61 
63 {
64  stream_thread_ = NULL;
65 }
66 
68 {
69  if (portOpen())
70  close();
71 }
72 
73 void SerialPort::open(const char* port_name, int baud_rate)
74 {
75  if (portOpen())
76  close();
77 
78  // Make IO non blocking. This way there are no race conditions that
79  // cause blocking when a badly behaving process does a read at the same
80  // time as us. Will need to switch to blocking for writes or errors
81  // occur just after a replug event.
82  fd_ = ::open(port_name, O_RDWR | O_NONBLOCK | O_NOCTTY);
83 
84  if (fd_ == -1)
85  {
86  const char* extra_msg = "";
87  switch (errno)
88  {
89  case EACCES:
90  extra_msg = "You probably don't have premission to open the port for reading and writing.";
91  break;
92 
93  case ENOENT:
94  extra_msg = "The requested port does not exist. Is the device connected? Was the port name misspelled?";
95  break;
96  }
97  SERIAL_EXCEPT(SerialException, "Failed to open port: %s. %s (errno = %d). %s", port_name, strerror(errno), errno,
98  extra_msg);
99  }
100 
101  try
102  {
103  struct flock fl;
104  fl.l_type = F_WRLCK;
105  fl.l_whence = SEEK_SET;
106  fl.l_start = 0;
107  fl.l_len = 0;
108  fl.l_pid = getpid();
109 
110  if (fcntl(fd_, F_SETLK, &fl) != 0)
111  SERIAL_EXCEPT(SerialException, "Device %s is already locked. Try 'lsof | grep %s' to find other processes that "
112  "currently have the port open.",
113  port_name, port_name);
114 
115  // Settings for USB?
116  struct termios newtio;
117  tcgetattr(fd_, &newtio);
118  memset(&newtio.c_cc, 0, sizeof(newtio.c_cc));
119  newtio.c_cflag = CS8 | CLOCAL | CREAD;
120  newtio.c_iflag = IGNPAR;
121  newtio.c_oflag = 0;
122  newtio.c_lflag = 0;
123  cfsetspeed(&newtio, baud_rate);
124  baud_ = baud_rate;
125 
126  // Activate new settings
127  tcflush(fd_, TCIFLUSH);
128  if (tcsetattr(fd_, TCSANOW, &newtio) < 0)
130  "Unable to set serial port attributes. The port you specified (%s) may not be a serial port.",
131  port_name);
132  usleep(200000);
134  }
135  catch (SerialException& e)
136  {
137  // These exceptions mean something failed on open and we should close
138  if (fd_ != -1)
139  ::close(fd_);
140  fd_ = -1;
141  throw e;
142  }
143 }
144 
146 {
147  int retval = 0;
148 
149  retval = ::close(fd_);
150 
151  fd_ = -1;
152 
153  if (retval != 0)
154  SERIAL_EXCEPT(SerialException, "Failed to close port properly -- error = %d: %s\n", errno, strerror(errno));
155 }
156 
157 int SerialPort::write(const char* data, int length)
158 {
159  int len = length == -1 ? strlen(data) : length;
160 
161  // IO is currently non-blocking. This is what we want for the more cerealon read case.
162  int origflags = fcntl(fd_, F_GETFL, 0);
163  fcntl(fd_, F_SETFL, origflags & ~O_NONBLOCK);
164  int retval = ::write(fd_, data, len);
165  fcntl(fd_, F_SETFL, origflags | O_NONBLOCK);
166 
167  if (retval == len)
168  return retval;
169  else
170  SERIAL_EXCEPT(SerialException, "write failed");
171 }
172 
173 int SerialPort::read(char* buffer, int max_length, int timeout)
174 {
175  int ret;
176 
177  struct pollfd ufd[1];
178  int retval;
179  ufd[0].fd = fd_;
180  ufd[0].events = POLLIN;
181 
182  if (timeout == 0)
183  timeout = -1; // For compatibility with former behavior, 0 means no timeout. For poll, negative means no timeout.
184 
185  if ((retval = poll(ufd, 1, timeout)) < 0)
186  SERIAL_EXCEPT(SerialException, "poll failed -- error = %d: %s", errno, strerror(errno));
187 
188  if (retval == 0)
189  SERIAL_EXCEPT(SerialTimeoutException, "timeout reached");
190 
191  if (ufd[0].revents & POLLERR)
192  SERIAL_EXCEPT(SerialException, "error on socket, possibly unplugged");
193 
194  ret = ::read(fd_, buffer, max_length);
195 
196  if (ret == -1 && errno != EAGAIN && errno != EWOULDBLOCK)
197  SERIAL_EXCEPT(SerialException, "read failed");
198 
199  return ret;
200 }
201 
202 int SerialPort::readBytes(char* buffer, int length, int timeout)
203 {
204  int ret;
205  int current = 0;
206 
207  struct pollfd ufd[1];
208  int retval;
209  ufd[0].fd = fd_;
210  ufd[0].events = POLLIN;
211 
212  if (timeout == 0)
213  timeout = -1; // For compatibility with former behavior, 0 means no timeout. For poll, negative means no timeout.
214 
215  while (current < length)
216  {
217  if ((retval = poll(ufd, 1, timeout)) < 0)
218  SERIAL_EXCEPT(SerialException, "poll failed -- error = %d: %s", errno, strerror(errno));
219 
220  if (retval == 0)
221  SERIAL_EXCEPT(SerialTimeoutException, "timeout reached");
222 
223  if (ufd[0].revents & POLLERR)
224  SERIAL_EXCEPT(SerialException, "error on socket, possibly unplugged");
225 
226  ret = ::read(fd_, &buffer[current], length - current);
227 
228  if (ret == -1 && errno != EAGAIN && errno != EWOULDBLOCK)
229  SERIAL_EXCEPT(SerialException, "read failed");
230 
231  current += ret;
232  }
233  return current;
234 }
235 
236 int SerialPort::readLine(char* buffer, int length, int timeout)
237 {
238  int ret;
239  int current = 0;
240 
241  struct pollfd ufd[1];
242  int retval;
243  ufd[0].fd = fd_;
244  ufd[0].events = POLLIN;
245 
246  if (timeout == 0)
247  timeout = -1; // For compatibility with former behavior, 0 means no timeout. For poll, negative means no timeout.
248 
249  while (current < length - 1)
250  {
251  if (current > 0)
252  if (buffer[current - 1] == '\n')
253  return current;
254 
255  if ((retval = poll(ufd, 1, timeout)) < 0)
256  SERIAL_EXCEPT(SerialException, "poll failed -- error = %d: %s", errno, strerror(errno));
257 
258  if (retval == 0)
259  SERIAL_EXCEPT(SerialTimeoutException, "timeout reached");
260 
261  if (ufd[0].revents & POLLERR)
262  SERIAL_EXCEPT(SerialException, "error on socket, possibly unplugged");
263 
264  ret = ::read(fd_, &buffer[current], length - current);
265 
266  if (ret == -1 && errno != EAGAIN && errno != EWOULDBLOCK)
267  SERIAL_EXCEPT(SerialException, "read failed");
268 
269  current += ret;
270  }
271  SERIAL_EXCEPT(SerialException, "buffer filled without end of line being found");
272 }
273 
274 bool SerialPort::readLine(std::string* buffer, int timeout)
275 {
276  int ret;
277 
278  struct pollfd ufd[1];
279  int retval;
280  ufd[0].fd = fd_;
281  ufd[0].events = POLLIN;
282 
283  if (timeout == 0)
284  timeout = -1; // For compatibility with former behavior, 0 means no timeout. For poll, negative means no timeout.
285 
286  buffer->clear();
287  while (buffer->size() < buffer->max_size() / 2)
288  {
289  // Look for the end char
290  ret = buffer->find_first_of('\n');
291  if (ret > 0)
292  {
293  // If it is there clear everything after it and return
294  buffer->erase(ret + 1, buffer->size() - ret - 1);
295  return true;
296  }
297 
298  if ((retval = poll(ufd, 1, timeout)) < 0)
299  SERIAL_EXCEPT(SerialException, "poll failed -- error = %d: %s", errno, strerror(errno));
300 
301  if (retval == 0)
302  SERIAL_EXCEPT(SerialTimeoutException, "timeout reached");
303 
304  if (ufd[0].revents & POLLERR)
305  SERIAL_EXCEPT(SerialException, "error on socket, possibly unplugged");
306 
307  char temp_buffer[128];
308  ret = ::read(fd_, temp_buffer, 128);
309 
310  if (ret == -1 && errno != EAGAIN && errno != EWOULDBLOCK)
311  SERIAL_EXCEPT(SerialException, "read failed");
312 
313  // Append the new data to the buffer
314  try
315  {
316  buffer->append(temp_buffer, ret);
317  }
318  catch (std::length_error& le)
319  {
320  SERIAL_EXCEPT(SerialException, "buffer filled without reaching end of data stream");
321  }
322  }
323  SERIAL_EXCEPT(SerialException, "buffer filled without end of line being found");
324 }
325 
326 bool SerialPort::readBetween(std::string* buffer, char start, char end, int timeout)
327 {
328  int ret;
329 
330  struct pollfd ufd[1];
331  static std::string erased;
332  int retval;
333  ufd[0].fd = fd_;
334  ufd[0].events = POLLIN;
335 
336  if (timeout == 0)
337  timeout = -1; // For compatibility with former behavior, 0 means no timeout. For poll, negative means no timeout.
338 
339  // Clear the buffer before we start
340  buffer->clear();
341  while (buffer->size() < buffer->max_size() / 2)
342  {
343  if ((retval = poll(ufd, 1, timeout)) < 0)
344  SERIAL_EXCEPT(SerialException, "poll failed -- error = %d: %s", errno, strerror(errno));
345 
346  if (retval == 0)
347  SERIAL_EXCEPT(SerialTimeoutException, "timeout reached");
348 
349  if (ufd[0].revents & POLLERR)
350  SERIAL_EXCEPT(SerialException, "error on socket, possibly unplugged");
351 
352  // Append erased characters in last iteration
353  if (!erased.empty())
354  {
355  try
356  {
357  buffer->append(erased);
358  erased.clear();
359  }
360  catch (std::length_error& le)
361  {
362  SERIAL_EXCEPT(SerialException, "failed to append erased to buffer");
363  }
364  }
365 
366  char temp_buffer[3];
367  ret = ::read(fd_, temp_buffer, 3);
368 
369  if (ret == -1 && errno != EAGAIN && errno != EWOULDBLOCK)
370  SERIAL_EXCEPT(SerialException, "read failed");
371 
372  // Append the new data to the buffer
373  try
374  {
375  buffer->append(temp_buffer, ret);
376  }
377  catch (std::length_error& le)
378  {
379  SERIAL_EXCEPT(SerialException, "buffer filled without reaching end of data stream");
380  }
381 
382  // Look for the start char
383  ret = buffer->find_first_of(start);
384  // If it is not on the buffer, clear it
385  if (ret == -1)
386  buffer->clear();
387  // If it is there, but not on the first position clear everything behind it
388  else if (ret > 0)
389  buffer->erase(0, ret);
390 
391  // Look for the end char
392  ret = buffer->find_first_of(end);
393  if (ret > 0)
394  {
395  // If it is there clear everything after it and return
396  erased = buffer->substr(ret + 1, buffer->size() - ret - 1);
397  // std::cout << "sobra |" << erased << "|\n";
398  buffer->erase(ret + 1, buffer->size() - ret - 1);
399  return true;
400  }
401  }
402  SERIAL_EXCEPT(SerialException, "buffer filled without reaching end of data stream");
403 }
404 
406 {
407  int retval = tcflush(fd_, TCIOFLUSH);
408  if (retval != 0)
409  SERIAL_EXCEPT(SerialException, "tcflush failed");
410 
411  return retval;
412 }
413 
414 bool SerialPort::startReadStream(std::function<void(char*, int)> f)
415 {
416  if (stream_thread_ != NULL)
417  return false;
418 
419  stream_stopped_ = false;
420  stream_paused_ = false;
421 
422  readCallback = f;
423 
424  stream_thread_ = new std::thread([this]() { this->readThread(); }); // NOLINT(whitespace/braces)
425  return true;
426 }
427 
429 {
430  char data[128];
431  int ret;
432 
433  struct pollfd ufd[1];
434  ufd[0].fd = fd_;
435  ufd[0].events = POLLIN;
436 
437  while (!stream_stopped_)
438  {
439  if (!stream_paused_)
440  {
441  if (poll(ufd, 1, 10) > 0)
442  {
443  if (!(ufd[0].revents & POLLERR))
444  {
445  ret = ::read(fd_, data, sizeof(data));
446  if (ret > 0)
447  {
448  readCallback(data, ret);
449  }
450  }
451  }
452  }
453  }
454 }
455 
456 bool SerialPort::startReadLineStream(std::function<void(std::string*)> f)
457 {
458  if (stream_thread_ != NULL)
459  return false;
460 
461  stream_stopped_ = false;
462  stream_paused_ = false;
463 
465 
466  stream_thread_ = new std::thread([this]() { this->readLineThread(); }); // NOLINT(whitespace/braces)
467  return true;
468 }
469 
471 {
472  std::string data;
473  bool error = false;
474 
475  while (!stream_stopped_)
476  {
477  if (!stream_paused_)
478  {
479  error = false;
480  try
481  {
482  readLine(&data, 100);
483  }
484  catch (SerialException& e)
485  {
486  error = true;
487  }
488 
489  if (!error && data.size() > 0)
490  readLineCallback(&data);
491  }
492  }
493 }
494 
495 bool SerialPort::startReadBetweenStream(std::function<void(std::string*)> f, char start, char end)
496 {
497  if (stream_thread_ != NULL)
498  return false;
499 
500  stream_stopped_ = false;
501  stream_paused_ = false;
502 
504 
506  new std::thread([this, start, end]() { this->readBetweenThread(start, end); }); // NOLINT(whitespace/braces)s
507  return true;
508 }
509 
510 void SerialPort::readBetweenThread(char start, char end)
511 {
512  std::string data;
513  bool error = false;
514 
515  while (!stream_stopped_)
516  {
517  if (!stream_paused_)
518  {
519  error = false;
520  try
521  {
522  readBetween(&data, start, end, 100);
523  }
524  catch (SerialException& e)
525  {
526  error = true;
527  }
528 
529  if (!error && data.size() > 0)
530  readBetweenCallback(&data);
531  }
532  }
533 }
534 
536 {
537  stream_stopped_ = true;
538  stream_thread_->join();
539 
540  delete stream_thread_;
541  stream_thread_ = NULL;
542 }
543 
545 {
546  stream_paused_ = true;
547 }
548 
550 {
551  stream_paused_ = false;
552 }
553 
554 // EOF
bool startReadStream(std::function< void(char *, int)> f)
Start a stream of read()
f
void close()
Close the serial port.
bool startReadLineStream(std::function< void(std::string *)> f)
Start a stream of readLine(std::string*, int)
std::function< void(std::string *)> readBetweenCallback
Stream readBetween callback boost function.
Definition: serial_port.h:281
SerialPort()
Constructor.
Definition: serial_port.cpp:62
int write(const char *data, int length=-1)
Write to the port.
bool stream_paused_
Whether streaming is paused or not.
Definition: serial_port.h:284
void readThread()
Thread for a stream of read()
~SerialPort()
Destructor.
Definition: serial_port.cpp:67
std::thread * stream_thread_
Stream thread.
Definition: serial_port.h:274
void pauseStream()
Pause streaming.
void open(const char *port_name, int baud_rate=115200)
Open the serial port.
Definition: serial_port.cpp:73
void resumeStream()
Resume streaming.
void readLineThread()
Thread for a stream of readLine(std::string*, int)
int fd_
File descriptor.
Definition: serial_port.h:245
void stopStream()
Stop streaming.
bool stream_stopped_
Whether streaming is stopped or not.
Definition: serial_port.h:286
int readBytes(char *data, int length, int timeout=-1)
Read a fixed number of bytes from the serial port.
bool portOpen()
Check whether the port is open or not.
Definition: serial_port.h:105
int flush()
Wrapper around tcflush.
void readBetweenThread(char start, char end)
Thread for a stream of readBetween()
bool startReadBetweenStream(std::function< void(std::string *)> f, char start, char end)
Start a stream of readBetween()
std::function< void(std::string *)> readLineCallback
Stream readLine callback boost function.
Definition: serial_port.h:279
#define SERIAL_EXCEPT(except, msg,...)
Macro for throwing an exception with a message, passing args.
Definition: serial_port.cpp:55
std::function< void(char *, int)> readCallback
Stream read callback boost function.
Definition: serial_port.h:277
int read(char *data, int max_length, int timeout=-1)
Read from the port.
bool readBetween(std::string *data, char start, char end, int timeout=-1)
Read from the serial port between a start char and an end char.
int baud_
Baud rate.
Definition: serial_port.h:247
int readLine(char *data, int length, int timeout=-1)
Read a line from the serial port.


kvh_drivers
Author(s): Jeff Schmidt, Geoffrey Viola
autogenerated on Mon Jun 10 2019 13:45:24