Visual Servoing Platform  version 3.5.1 under development (2023-03-14)
vpSerial.cpp
1 /****************************************************************************
2  *
3  * ViSP, open source Visual Servoing Platform software.
4  * Copyright (C) 2005 - 2019 by Inria. All rights reserved.
5  *
6  * This software is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  * See the file LICENSE.txt at the root directory of this source
11  * distribution for additional information about the GNU GPL.
12  *
13  * For using ViSP with software that can not be combined with the GNU
14  * GPL, please contact Inria about acquiring a ViSP Professional
15  * Edition License.
16  *
17  * See http://visp.inria.fr for more information.
18  *
19  * This software was developed at:
20  * Inria Rennes - Bretagne Atlantique
21  * Campus Universitaire de Beaulieu
22  * 35042 Rennes Cedex
23  * France
24  *
25  * If you have questions regarding the use of this file, please contact
26  * Inria at visp@inria.fr
27  *
28  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
29  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
30  *
31  * Description:
32  * Serial communication.
33  *
34  * Authors:
35  * Fabien Spindler
36  *
37  *****************************************************************************/
38 
39 #include <visp3/core/vpConfig.h>
40 
41 #if !defined(_WIN32)
42 
43 #include <errno.h>
44 #include <fcntl.h>
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #include <sys/ioctl.h>
49 #include <sys/stat.h>
50 #include <sys/types.h>
51 #include <termios.h>
52 #include <unistd.h>
53 
54 #include <visp3/core/vpException.h>
55 #include <visp3/core/vpSerial.h>
56 
57 #ifndef TIOCINQ
58 #ifdef FIONREAD
59 #define TIOCINQ FIONREAD
60 #else
61 #define TIOCINQ 0x541B
62 #endif
63 #endif
64 
100 vpSerial::vpSerial(const std::string &port, unsigned long baudrate, bytesize_t bytesize, parity_t parity,
101  stopbits_t stopbits, flowcontrol_t flowcontrol)
102  : m_port(port), m_fd(-1), m_is_open(false), m_xonxoff(false), m_rtscts(false), m_baudrate(baudrate), m_parity(parity),
103  m_bytesize(bytesize), m_stopbits(stopbits), m_flowcontrol(flowcontrol)
104 {
105  if (m_port.empty() == false)
106  open();
107 }
108 
113 
118 void vpSerial::setBaudrate(const unsigned long baudrate) { m_baudrate = baudrate; }
119 
124 void vpSerial::setBytesize(const bytesize_t &bytesize) { m_bytesize = bytesize; }
125 
130 void vpSerial::setFlowcontrol(const flowcontrol_t &flowcontrol) { m_flowcontrol = flowcontrol; }
131 
136 void vpSerial::setParity(const parity_t &parity) { m_parity = parity; }
137 
142 void vpSerial::setStopbits(const stopbits_t &stopbits) { m_stopbits = stopbits; }
143 
161 void vpSerial::setPort(const std::string &port) { m_port = port; }
162 
167 {
168  if (!m_is_open) {
169  return 0;
170  }
171  int count = 0;
172  if (-1 == ioctl(m_fd, TIOCINQ, &count)) {
173  throw(vpException(vpException::fatalError, "Cannot check is serial port data available"));
174  } else {
175  return count;
176  }
177 }
178 
184 {
185  if (m_is_open == true) {
186  if (m_fd != -1) {
187  int ret;
188  ret = ::close(m_fd);
189  if (ret == 0) {
190  m_fd = -1;
191  } else {
192  throw(vpException(vpException::fatalError, "Cannot close serial port"));
193  }
194  }
195  m_is_open = false;
196  }
197 }
198 
227 {
228  if (m_port.empty()) {
229  throw(vpException(vpException::fatalError, "Serial port empty"));
230  }
231  if (m_is_open == true) {
232  throw(vpException(vpException::fatalError, "Serial port already open"));
233  }
234 
235  m_fd = ::open(m_port.c_str(), O_RDWR | O_NOCTTY | O_NONBLOCK);
236 
237  if (m_fd == -1) {
238  switch (errno) {
239  case EINTR:
240  // Try again because this is a recoverable error.
241  open();
242  return;
243  case ENFILE:
244  case EMFILE:
245  throw(vpException(vpException::fatalError, "Serial port has to many handles open"));
246  default:
247  throw(vpException(vpException::fatalError, "Serial port opening error"));
248  }
249  }
250 
251  configure();
252  m_is_open = true;
253 }
254 
261 bool vpSerial::read(char *c, long timeout_s)
262 {
263  if (m_is_open == false) {
264  throw(vpException(vpException::fatalError, "Serial port not opened"));
265  }
266 
267  fd_set readfds; /* list of fds for select to listen to */
268  struct timeval timeout = {timeout_s, 0}; // seconde, micro-sec
269 
270  FD_ZERO(&readfds);
271  FD_SET(static_cast<unsigned int>(m_fd), &readfds);
272 
273  int ret = select(FD_SETSIZE, &readfds, (fd_set *)NULL, (fd_set *)NULL, &timeout);
274 
275  if (ret < 0) {
276  throw(vpException(vpException::fatalError, "Serial i/o exception"));
277  } else if (ret == 0) {
278  // Timeout occured
279  return false;
280  } else {
281  ssize_t n = ::read(m_fd, c, 1); // read one character at a time
282  if (n != 1)
283  return false;
284  }
285  return true;
286 }
287 
293 std::string vpSerial::readline(const std::string &eol)
294 {
295  char c;
296  size_t eol_len = eol.length();
297  std::string line;
298 
299  while (true) {
300  size_t bytes_read = this->read(&c, 1);
301  if (bytes_read == 0) {
302  break; // Timeout occured on reading 1 byte
303  }
304  line.append(&c, 1);
305  if (std::string(line, line.size() - eol_len, eol_len) == eol) {
306  break; // EOL found
307  }
308  }
309  return line;
310 }
311 
316 void vpSerial::write(const std::string &s)
317 {
318  if (m_is_open == false) {
319  throw(vpException(vpException::fatalError, "Serial port not opened"));
320  }
321 
322  ssize_t r = ::write(m_fd, s.c_str(), s.size());
323  if (r != (ssize_t)(s.size())) {
324  throw(vpException(vpException::fatalError, "Serial port write error"));
325  }
326 }
327 
328 void vpSerial::configure()
329 {
330  if (m_fd == -1) {
331  throw(vpException(vpException::fatalError, "Serial port not opened"));
332  }
333 
334  struct termios options;
335 
336  if (tcgetattr(m_fd, &options) == -1) {
337  ::close(m_fd);
338  throw vpException(vpException::fatalError, "Cannot get serial configuration");
339  }
340 
341  // set up raw mode / no echo / binary
342  options.c_cflag |= (tcflag_t)(CLOCAL | CREAD);
343  options.c_lflag &= (tcflag_t) ~(ICANON | ECHO | ECHOE | ECHOK | ECHONL | ISIG | IEXTEN); //|ECHOPRT
344 
345  options.c_oflag &= (tcflag_t) ~(OPOST);
346  options.c_iflag &= (tcflag_t) ~(INLCR | IGNCR | ICRNL | IGNBRK);
347 
348 #ifdef IUCLC
349  options.c_iflag &= (tcflag_t)~IUCLC;
350 #endif
351 #ifdef PARMRK
352  options.c_iflag &= (tcflag_t)~PARMRK;
353 #endif
354 
355  speed_t baudrate;
356  switch (m_baudrate) {
357 #ifdef B0
358  case 0:
359  baudrate = B0;
360  break;
361 #endif
362 #ifdef B50
363  case 50:
364  baudrate = B50;
365  break;
366 #endif
367 #ifdef B75
368  case 75:
369  baudrate = B75;
370  break;
371 #endif
372 #ifdef B110
373  case 110:
374  baudrate = B110;
375  break;
376 #endif
377 #ifdef B134
378  case 134:
379  baudrate = B134;
380  break;
381 #endif
382 #ifdef B150
383  case 150:
384  baudrate = B150;
385  break;
386 #endif
387 #ifdef B200
388  case 200:
389  baudrate = B200;
390  break;
391 #endif
392 #ifdef B300
393  case 300:
394  baudrate = B300;
395  break;
396 #endif
397 #ifdef B600
398  case 600:
399  baudrate = B600;
400  break;
401 #endif
402 #ifdef B1200
403  case 1200:
404  baudrate = B1200;
405  break;
406 #endif
407 #ifdef B1800
408  case 1800:
409  baudrate = B1800;
410  break;
411 #endif
412 #ifdef B2400
413  case 2400:
414  baudrate = B2400;
415  break;
416 #endif
417 #ifdef B4800
418  case 4800:
419  baudrate = B4800;
420  break;
421 #endif
422 #ifdef B9600
423  case 9600:
424  baudrate = B9600;
425  break;
426 #endif
427 #ifdef B14400
428  case 14400:
429  baudrate = B14400;
430  break;
431 #endif
432 #ifdef B19200
433  case 19200:
434  baudrate = B19200;
435  break;
436 #endif
437 #ifdef B38400
438  case 38400:
439  baudrate = B38400;
440  break;
441 #endif
442 #ifdef B57600
443  case 57600:
444  baudrate = B57600;
445  break;
446 #endif
447 #ifdef B115200
448  case 115200:
449  baudrate = B115200;
450  break;
451 #endif
452 #ifdef B230400
453  case 230400:
454  baudrate = B230400;
455  break;
456 #endif
457 #ifdef B460800
458  case 460800:
459  baudrate = B460800;
460  break;
461 #endif
462 #ifdef B500000
463  case 500000:
464  baudrate = B500000;
465  break;
466 #endif
467 #ifdef B576000
468  case 576000:
469  baudrate = B576000;
470  break;
471 #endif
472 #ifdef B921600
473  case 921600:
474  baudrate = B921600;
475  break;
476 #endif
477 #ifdef B1000000
478  case 1000000:
479  baudrate = B1000000;
480  break;
481 #endif
482 #ifdef B1152000
483  case 1152000:
484  baudrate = B1152000;
485  break;
486 #endif
487 #ifdef B1500000
488  case 1500000:
489  baudrate = B1500000;
490  break;
491 #endif
492 #ifdef B2000000
493  case 2000000:
494  baudrate = B2000000;
495  break;
496 #endif
497 #ifdef B2500000
498  case 2500000:
499  baudrate = B2500000;
500  break;
501 #endif
502 #ifdef B3000000
503  case 3000000:
504  baudrate = B3000000;
505  break;
506 #endif
507 #ifdef B3500000
508  case 3500000:
509  baudrate = B3500000;
510  break;
511 #endif
512 #ifdef B4000000
513  case 4000000:
514  baudrate = B4000000;
515  break;
516 #endif
517  default:
518  throw vpException(vpException::fatalError, "Cannot set serial baudrate to %ld", m_baudrate);
519  }
520 
521 #ifdef _BSD_SOURCE
522  ::cfsetspeed(&options, baudrate);
523 #else
524  ::cfsetispeed(&options, baudrate);
525  ::cfsetospeed(&options, baudrate);
526 #endif
527 
528  // setup char len
529  options.c_cflag &= (tcflag_t)~CSIZE;
530  switch (m_bytesize) {
531  case eightbits:
532  options.c_cflag |= CS8;
533  break;
534  case sevenbits:
535  options.c_cflag |= CS7;
536  break;
537  case sixbits:
538  options.c_cflag |= CS6;
539  break;
540  case fivebits:
541  options.c_cflag |= CS5;
542  break;
543  }
544 
545  switch (m_stopbits) {
546  case stopbits_one:
547  options.c_cflag &= (tcflag_t) ~(CSTOPB);
548  break;
549  case stopbits_two:
550  options.c_cflag |= (CSTOPB);
551  break;
552  }
553 
554  // setup parity
555  options.c_iflag &= (tcflag_t) ~(INPCK | ISTRIP);
556  switch (m_parity) {
557  case parity_none:
558  options.c_cflag &= (tcflag_t) ~(PARENB | PARODD);
559  break;
560  case parity_even:
561  options.c_cflag &= (tcflag_t) ~(PARODD);
562  options.c_cflag |= (PARENB);
563  break;
564  case parity_odd:
565  options.c_cflag |= (PARENB | PARODD);
566  break;
567  }
568 
569  // setup flow control
570  switch (m_flowcontrol) {
571  case flowcontrol_none:
572  m_xonxoff = false;
573  m_rtscts = false;
574  break;
576  m_xonxoff = true;
577  m_rtscts = false;
578  break;
580  m_xonxoff = false;
581  m_rtscts = true;
582  break;
583  }
584 
585  // xonxoff
586  if (m_xonxoff)
587  options.c_iflag |= (IXON | IXOFF);
588  else
589 #ifdef IXANY
590  options.c_iflag &= (tcflag_t) ~(IXON | IXOFF | IXANY);
591 #else
592  options.c_iflag &= (tcflag_t) ~(IXON | IXOFF);
593 #endif
594 
595  // rtscts
596 #ifdef CRTSCTS
597  if (m_rtscts)
598  options.c_cflag |= (CRTSCTS);
599  else
600  options.c_cflag &= (unsigned long)~(CRTSCTS);
601 #elif defined CNEW_RTSCTS
602  if (m_rtscts)
603  options.c_cflag |= (CNEW_RTSCTS);
604  else
605  options.c_cflag &= (unsigned long)~(CNEW_RTSCTS);
606 #else
607 #error "OS doesn't support serial rtscts"
608 #endif
609 
610  options.c_cc[VMIN] = 0;
611  options.c_cc[VTIME] = 0;
612 
613  // activate settings
614  ::tcsetattr(m_fd, TCSANOW, &options);
615 }
616 
617 #elif !defined(VISP_BUILD_SHARED_LIBS)
618 // Work around to avoid warning: libvisp_ar.a(vpAROgre.cpp.o) has no symbols
619 void dummy_vpSerial(){};
620 #endif
error that can be emited by ViSP classes.
Definition: vpException.h:72
@ fatalError
Fatal error.
Definition: vpException.h:96
std::string readline(const std::string &eol)
Definition: vpSerial.cpp:293
flowcontrol_t
Definition: vpSerial.h:103
@ flowcontrol_software
Software flow control.
Definition: vpSerial.h:105
@ flowcontrol_none
No flow control.
Definition: vpSerial.h:104
@ flowcontrol_hardware
Hardware flow control.
Definition: vpSerial.h:106
void open()
Definition: vpSerial.cpp:226
void setParity(const parity_t &parity)
Definition: vpSerial.cpp:136
int available()
Definition: vpSerial.cpp:166
void setStopbits(const stopbits_t &stopbits)
Definition: vpSerial.cpp:142
vpSerial(const std::string &port="", unsigned long baudrate=9600, bytesize_t bytesize=eightbits, parity_t parity=parity_none, stopbits_t stopbits=stopbits_one, flowcontrol_t flowcontrol=flowcontrol_none)
Definition: vpSerial.cpp:100
@ parity_odd
Check for odd parity.
Definition: vpSerial.h:88
@ parity_none
No parity check.
Definition: vpSerial.h:87
@ parity_even
Check for even parity.
Definition: vpSerial.h:89
void close()
Definition: vpSerial.cpp:183
stopbits_t
Definition: vpSerial.h:95
@ stopbits_two
2 stop bits are used
Definition: vpSerial.h:97
@ stopbits_one
1 stop bit is used
Definition: vpSerial.h:96
void setFlowcontrol(const flowcontrol_t &flowcontrol)
Definition: vpSerial.cpp:130
bool read(char *c, long timeout_s)
Definition: vpSerial.cpp:261
void setBytesize(const bytesize_t &bytesize)
Definition: vpSerial.cpp:124
void write(const std::string &s)
Definition: vpSerial.cpp:316
virtual ~vpSerial()
Definition: vpSerial.cpp:112
void setPort(const std::string &port)
Definition: vpSerial.cpp:161
bytesize_t
Definition: vpSerial.h:76
@ eightbits
Data is encoded with 8 bits.
Definition: vpSerial.h:80
@ fivebits
Data is encoded with 5 bits.
Definition: vpSerial.h:77
@ sevenbits
Data is encoded with 7 bits.
Definition: vpSerial.h:79
@ sixbits
Data is encoded with 6 bits.
Definition: vpSerial.h:78
void setBaudrate(const unsigned long baudrate)
Definition: vpSerial.cpp:118