Visual Servoing Platform  version 3.6.1 under development (2024-04-25)
vpSerial.cpp
1 /****************************************************************************
2  *
3  * ViSP, open source Visual Servoing Platform software.
4  * Copyright (C) 2005 - 2023 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 https://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 *****************************************************************************/
35 
36 #include <visp3/core/vpConfig.h>
37 
38 #if !defined(_WIN32)
39 
40 #include <errno.h>
41 #include <fcntl.h>
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #include <sys/ioctl.h>
46 #include <sys/stat.h>
47 #include <sys/types.h>
48 #include <termios.h>
49 #include <unistd.h>
50 
51 #include <visp3/core/vpException.h>
52 #include <visp3/core/vpSerial.h>
53 
54 #ifndef TIOCINQ
55 #ifdef FIONREAD
56 #define TIOCINQ FIONREAD
57 #else
58 #define TIOCINQ 0x541B
59 #endif
60 #endif
61 
97 vpSerial::vpSerial(const std::string &port, unsigned long baudrate, bytesize_t bytesize, parity_t parity,
98  stopbits_t stopbits, flowcontrol_t flowcontrol)
99  : m_port(port), m_fd(-1), m_is_open(false), m_xonxoff(false), m_rtscts(false), m_baudrate(baudrate), m_parity(parity),
100  m_bytesize(bytesize), m_stopbits(stopbits), m_flowcontrol(flowcontrol)
101 {
102  if (m_port.empty() == false)
103  open();
104 }
105 
110 
115 void vpSerial::setBaudrate(const unsigned long baudrate) { m_baudrate = baudrate; }
116 
121 void vpSerial::setBytesize(const bytesize_t &bytesize) { m_bytesize = bytesize; }
122 
127 void vpSerial::setFlowcontrol(const flowcontrol_t &flowcontrol) { m_flowcontrol = flowcontrol; }
128 
133 void vpSerial::setParity(const parity_t &parity) { m_parity = parity; }
134 
139 void vpSerial::setStopbits(const stopbits_t &stopbits) { m_stopbits = stopbits; }
140 
158 void vpSerial::setPort(const std::string &port) { m_port = port; }
159 
164 {
165  if (!m_is_open) {
166  return 0;
167  }
168  int count = 0;
169  if (-1 == ioctl(m_fd, TIOCINQ, &count)) {
170  throw(vpException(vpException::fatalError, "Cannot check is serial port data available"));
171  } else {
172  return count;
173  }
174 }
175 
181 {
182  if (m_is_open == true) {
183  if (m_fd != -1) {
184  int ret;
185  ret = ::close(m_fd);
186  if (ret == 0) {
187  m_fd = -1;
188  } else {
189  throw(vpException(vpException::fatalError, "Cannot close serial port"));
190  }
191  }
192  m_is_open = false;
193  }
194 }
195 
224 {
225  if (m_port.empty()) {
226  throw(vpException(vpException::fatalError, "Serial port empty"));
227  }
228  if (m_is_open == true) {
229  throw(vpException(vpException::fatalError, "Serial port already open"));
230  }
231 
232  m_fd = ::open(m_port.c_str(), O_RDWR | O_NOCTTY | O_NONBLOCK);
233 
234  if (m_fd == -1) {
235  switch (errno) {
236  case EINTR:
237  // Try again because this is a recoverable error.
238  open();
239  return;
240  case ENFILE:
241  case EMFILE:
242  throw(vpException(vpException::fatalError, "Serial port has to many handles open"));
243  default:
244  throw(vpException(vpException::fatalError, "Serial port opening error"));
245  }
246  }
247 
248  configure();
249  m_is_open = true;
250 }
251 
258 bool vpSerial::read(char *c, long timeout_s)
259 {
260  if (m_is_open == false) {
261  throw(vpException(vpException::fatalError, "Serial port not opened"));
262  }
263 
264  fd_set readfds; /* list of fds for select to listen to */
265  struct timeval timeout = {timeout_s, 0}; // seconde, micro-sec
266 
267  FD_ZERO(&readfds);
268  FD_SET(static_cast<unsigned int>(m_fd), &readfds);
269 
270  int ret = select(FD_SETSIZE, &readfds, (fd_set *)nullptr, (fd_set *)nullptr, &timeout);
271 
272  if (ret < 0) {
273  throw(vpException(vpException::fatalError, "Serial i/o exception"));
274  } else if (ret == 0) {
275  // Timeout occurred
276  return false;
277  } else {
278  ssize_t n = ::read(m_fd, c, 1); // read one character at a time
279  if (n != 1)
280  return false;
281  }
282  return true;
283 }
284 
290 std::string vpSerial::readline(const std::string &eol)
291 {
292  char c;
293  size_t eol_len = eol.length();
294  std::string line;
295 
296  while (true) {
297  size_t bytes_read = this->read(&c, 1);
298  if (bytes_read == 0) {
299  break; // Timeout occurred on reading 1 byte
300  }
301  line.append(&c, 1);
302  if (std::string(line, line.size() - eol_len, eol_len) == eol) {
303  break; // EOL found
304  }
305  }
306  return line;
307 }
308 
313 void vpSerial::write(const std::string &s)
314 {
315  if (m_is_open == false) {
316  throw(vpException(vpException::fatalError, "Serial port not opened"));
317  }
318 
319  ssize_t r = ::write(m_fd, s.c_str(), s.size());
320  if (r != (ssize_t)(s.size())) {
321  throw(vpException(vpException::fatalError, "Serial port write error"));
322  }
323 }
324 
325 void vpSerial::configure()
326 {
327  if (m_fd == -1) {
328  throw(vpException(vpException::fatalError, "Serial port not opened"));
329  }
330 
331  struct termios options;
332 
333  if (tcgetattr(m_fd, &options) == -1) {
334  ::close(m_fd);
335  throw vpException(vpException::fatalError, "Cannot get serial configuration");
336  }
337 
338  // set up raw mode / no echo / binary
339  options.c_cflag |= (tcflag_t)(CLOCAL | CREAD);
340  options.c_lflag &= (tcflag_t) ~(ICANON | ECHO | ECHOE | ECHOK | ECHONL | ISIG | IEXTEN); //|ECHOPRT
341 
342  options.c_oflag &= (tcflag_t) ~(OPOST);
343  options.c_iflag &= (tcflag_t) ~(INLCR | IGNCR | ICRNL | IGNBRK);
344 
345 #ifdef IUCLC
346  options.c_iflag &= (tcflag_t)~IUCLC;
347 #endif
348 #ifdef PARMRK
349  options.c_iflag &= (tcflag_t)~PARMRK;
350 #endif
351 
352  speed_t baudrate;
353  switch (m_baudrate) {
354 #ifdef B0
355  case 0:
356  baudrate = B0;
357  break;
358 #endif
359 #ifdef B50
360  case 50:
361  baudrate = B50;
362  break;
363 #endif
364 #ifdef B75
365  case 75:
366  baudrate = B75;
367  break;
368 #endif
369 #ifdef B110
370  case 110:
371  baudrate = B110;
372  break;
373 #endif
374 #ifdef B134
375  case 134:
376  baudrate = B134;
377  break;
378 #endif
379 #ifdef B150
380  case 150:
381  baudrate = B150;
382  break;
383 #endif
384 #ifdef B200
385  case 200:
386  baudrate = B200;
387  break;
388 #endif
389 #ifdef B300
390  case 300:
391  baudrate = B300;
392  break;
393 #endif
394 #ifdef B600
395  case 600:
396  baudrate = B600;
397  break;
398 #endif
399 #ifdef B1200
400  case 1200:
401  baudrate = B1200;
402  break;
403 #endif
404 #ifdef B1800
405  case 1800:
406  baudrate = B1800;
407  break;
408 #endif
409 #ifdef B2400
410  case 2400:
411  baudrate = B2400;
412  break;
413 #endif
414 #ifdef B4800
415  case 4800:
416  baudrate = B4800;
417  break;
418 #endif
419 #ifdef B9600
420  case 9600:
421  baudrate = B9600;
422  break;
423 #endif
424 #ifdef B14400
425  case 14400:
426  baudrate = B14400;
427  break;
428 #endif
429 #ifdef B19200
430  case 19200:
431  baudrate = B19200;
432  break;
433 #endif
434 #ifdef B38400
435  case 38400:
436  baudrate = B38400;
437  break;
438 #endif
439 #ifdef B57600
440  case 57600:
441  baudrate = B57600;
442  break;
443 #endif
444 #ifdef B115200
445  case 115200:
446  baudrate = B115200;
447  break;
448 #endif
449 #ifdef B230400
450  case 230400:
451  baudrate = B230400;
452  break;
453 #endif
454 #ifdef B460800
455  case 460800:
456  baudrate = B460800;
457  break;
458 #endif
459 #ifdef B500000
460  case 500000:
461  baudrate = B500000;
462  break;
463 #endif
464 #ifdef B576000
465  case 576000:
466  baudrate = B576000;
467  break;
468 #endif
469 #ifdef B921600
470  case 921600:
471  baudrate = B921600;
472  break;
473 #endif
474 #ifdef B1000000
475  case 1000000:
476  baudrate = B1000000;
477  break;
478 #endif
479 #ifdef B1152000
480  case 1152000:
481  baudrate = B1152000;
482  break;
483 #endif
484 #ifdef B1500000
485  case 1500000:
486  baudrate = B1500000;
487  break;
488 #endif
489 #ifdef B2000000
490  case 2000000:
491  baudrate = B2000000;
492  break;
493 #endif
494 #ifdef B2500000
495  case 2500000:
496  baudrate = B2500000;
497  break;
498 #endif
499 #ifdef B3000000
500  case 3000000:
501  baudrate = B3000000;
502  break;
503 #endif
504 #ifdef B3500000
505  case 3500000:
506  baudrate = B3500000;
507  break;
508 #endif
509 #ifdef B4000000
510  case 4000000:
511  baudrate = B4000000;
512  break;
513 #endif
514  default:
515  throw vpException(vpException::fatalError, "Cannot set serial baudrate to %ld", m_baudrate);
516  }
517 
518 #ifdef _BSD_SOURCE
519  ::cfsetspeed(&options, baudrate);
520 #else
521  ::cfsetispeed(&options, baudrate);
522  ::cfsetospeed(&options, baudrate);
523 #endif
524 
525  // setup char len
526  options.c_cflag &= (tcflag_t)~CSIZE;
527  switch (m_bytesize) {
528  case eightbits:
529  options.c_cflag |= CS8;
530  break;
531  case sevenbits:
532  options.c_cflag |= CS7;
533  break;
534  case sixbits:
535  options.c_cflag |= CS6;
536  break;
537  case fivebits:
538  options.c_cflag |= CS5;
539  break;
540  }
541 
542  switch (m_stopbits) {
543  case stopbits_one:
544  options.c_cflag &= (tcflag_t) ~(CSTOPB);
545  break;
546  case stopbits_two:
547  options.c_cflag |= (CSTOPB);
548  break;
549  }
550 
551  // setup parity
552  options.c_iflag &= (tcflag_t) ~(INPCK | ISTRIP);
553  switch (m_parity) {
554  case parity_none:
555  options.c_cflag &= (tcflag_t) ~(PARENB | PARODD);
556  break;
557  case parity_even:
558  options.c_cflag &= (tcflag_t) ~(PARODD);
559  options.c_cflag |= (PARENB);
560  break;
561  case parity_odd:
562  options.c_cflag |= (PARENB | PARODD);
563  break;
564  }
565 
566  // setup flow control
567  switch (m_flowcontrol) {
568  case flowcontrol_none:
569  m_xonxoff = false;
570  m_rtscts = false;
571  break;
573  m_xonxoff = true;
574  m_rtscts = false;
575  break;
577  m_xonxoff = false;
578  m_rtscts = true;
579  break;
580  }
581 
582  // xonxoff
583  if (m_xonxoff)
584  options.c_iflag |= (IXON | IXOFF);
585  else
586 #ifdef IXANY
587  options.c_iflag &= (tcflag_t) ~(IXON | IXOFF | IXANY);
588 #else
589  options.c_iflag &= (tcflag_t) ~(IXON | IXOFF);
590 #endif
591 
592  // rtscts
593 #ifdef CRTSCTS
594  if (m_rtscts)
595  options.c_cflag |= (CRTSCTS);
596  else
597  options.c_cflag &= (unsigned long)~(CRTSCTS);
598 #elif defined CNEW_RTSCTS
599  if (m_rtscts)
600  options.c_cflag |= (CNEW_RTSCTS);
601  else
602  options.c_cflag &= (unsigned long)~(CNEW_RTSCTS);
603 #else
604 #error "OS doesn't support serial rtscts"
605 #endif
606 
607  options.c_cc[VMIN] = 0;
608  options.c_cc[VTIME] = 0;
609 
610  // activate settings
611  ::tcsetattr(m_fd, TCSANOW, &options);
612 }
613 
614 #elif !defined(VISP_BUILD_SHARED_LIBS)
615 // Work around to avoid warning: libvisp_ar.a(vpAROgre.cpp.o) has no symbols
616 void dummy_vpSerial(){};
617 #endif
error that can be emitted by ViSP classes.
Definition: vpException.h:59
@ fatalError
Fatal error.
Definition: vpException.h:84
std::string readline(const std::string &eol)
Definition: vpSerial.cpp:290
flowcontrol_t
Definition: vpSerial.h:98
@ flowcontrol_software
Software flow control.
Definition: vpSerial.h:100
@ flowcontrol_none
No flow control.
Definition: vpSerial.h:99
@ flowcontrol_hardware
Hardware flow control.
Definition: vpSerial.h:101
void open()
Definition: vpSerial.cpp:223
void setParity(const parity_t &parity)
Definition: vpSerial.cpp:133
int available()
Definition: vpSerial.cpp:163
void setStopbits(const stopbits_t &stopbits)
Definition: vpSerial.cpp:139
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:97
@ parity_odd
Check for odd parity.
Definition: vpSerial.h:83
@ parity_none
No parity check.
Definition: vpSerial.h:82
@ parity_even
Check for even parity.
Definition: vpSerial.h:84
void close()
Definition: vpSerial.cpp:180
stopbits_t
Definition: vpSerial.h:90
@ stopbits_two
2 stop bits are used
Definition: vpSerial.h:92
@ stopbits_one
1 stop bit is used
Definition: vpSerial.h:91
void setFlowcontrol(const flowcontrol_t &flowcontrol)
Definition: vpSerial.cpp:127
bool read(char *c, long timeout_s)
Definition: vpSerial.cpp:258
void setBytesize(const bytesize_t &bytesize)
Definition: vpSerial.cpp:121
void write(const std::string &s)
Definition: vpSerial.cpp:313
virtual ~vpSerial()
Definition: vpSerial.cpp:109
void setPort(const std::string &port)
Definition: vpSerial.cpp:158
bytesize_t
Definition: vpSerial.h:71
@ eightbits
Data is encoded with 8 bits.
Definition: vpSerial.h:75
@ fivebits
Data is encoded with 5 bits.
Definition: vpSerial.h:72
@ sevenbits
Data is encoded with 7 bits.
Definition: vpSerial.h:74
@ sixbits
Data is encoded with 6 bits.
Definition: vpSerial.h:73
void setBaudrate(const unsigned long baudrate)
Definition: vpSerial.cpp:115