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