16 #if defined(MRPT_OS_LINUX) || defined(MRPT_OS_APPLE) 29 #include <sys/ioctl.h> 32 #ifdef HAVE_LINUX_SERIAL_H 33 #include <linux/serial.h> 38 #endif // Linux | Apple 40 #ifdef MRPT_OS_WINDOWS 54 : m_serialName(portName),
56 m_interBytesTimeout_ms(0),
57 #ifdef MRPT_OS_WINDOWS
70 m_interBytesTimeout_ms(0),
71 #ifdef MRPT_OS_WINDOWS
91 #ifdef MRPT_OS_WINDOWS 105 if (INVALID_HANDLE_VALUE ==
108 GENERIC_READ | GENERIC_WRITE, 0,
nullptr, OPEN_EXISTING, 0, 0)))
112 "Error trying to open serial port: %s",
m_serialName.c_str());
116 SetupComm(
hCOM, 4096, 4096);
132 "Error trying to open the serial port %s!!",
m_serialName.c_str());
135 fcntl(
hCOM, F_SETFL, 0);
140 termios port_settings;
141 bzero(&port_settings,
sizeof(port_settings));
147 port_settings.c_cflag |= CREAD | CLOCAL;
157 port_settings.c_cc[VMIN] = 0;
158 port_settings.c_cc[VTIME] = 0;
163 if (tcflush(
hCOM, TCIFLUSH) < 0)
169 if (tcsetattr(
hCOM, TCSANOW, &port_settings) < 0)
171 "Cannot set the new config to the serial port: %s",
175 fcntl(
hCOM, F_SETFL, FNDELAY);
187 #ifdef MRPT_OS_WINDOWS 188 return hCOM !=
nullptr;
198 int baudRate,
int parity,
int bits,
int nStopBits,
bool enableFlowControl)
201 #ifdef MRPT_OS_WINDOWS 204 dcb_conf.DCBlength =
sizeof(DCB);
209 if (!GetCommState(
hCOM, &dcb_conf))
255 dcb_conf.BaudRate = BR;
257 dcb_conf.ByteSize = (BYTE)bits;
258 dcb_conf.Parity = (BYTE)parity;
264 dcb_conf.StopBits = ONESTOPBIT;
267 dcb_conf.StopBits = TWOSTOPBITS;
274 dcb_conf.fBinary =
true;
275 dcb_conf.fParity = parity != 0;
277 dcb_conf.fRtsControl =
278 enableFlowControl ? RTS_CONTROL_HANDSHAKE : RTS_CONTROL_DISABLE;
279 dcb_conf.fOutxCtsFlow = enableFlowControl;
282 if (!SetCommState(
hCOM, &dcb_conf))
286 if (!GetCommState(
hCOM, &dcb_conf))
288 if (((
int)dcb_conf.BaudRate) != baudRate)
303 bool special_rate =
false;
397 #ifdef HAVE_LINUX_SERIAL_H 407 #ifdef HAVE_LINUX_SERIAL_H 408 struct serial_struct serial;
409 if (ioctl(
hCOM, TIOCGSERIAL, &serial) < 0)
412 serial.custom_divisor = serial.baud_base / baudRate;
413 if (!serial.custom_divisor) serial.custom_divisor = 1;
414 const int actual_rate = serial.baud_base / serial.custom_divisor;
416 serial.flags &= ~ASYNC_SPD_MASK;
417 serial.flags |= ASYNC_SPD_CUST;
419 if (ioctl(
hCOM, TIOCSSERIAL, &serial) < 0)
425 if (actual_rate != baudRate)
426 cout <<
"[CSerialPort::setConfig] Setting custom baud rate to " 427 << actual_rate <<
", the closer I can make to " << baudRate
430 THROW_EXCEPTION(
"Custom serial port baud rates require linux/serial.h");
448 termios port_settings;
449 if (tcgetattr(
hCOM, &port_settings) < 0)
451 "Cannot get the current settings: %s", strerror(errno));
453 if ((cfsetispeed(&port_settings, BR) < 0) ||
454 (cfsetospeed(&port_settings, BR) < 0))
456 "Cannot change baudRate in setting structure: %s", strerror(errno));
461 port_settings.c_cflag &= ~CSIZE;
465 port_settings.c_cflag |= CS5;
468 port_settings.c_cflag |= CS6;
471 port_settings.c_cflag |= CS7;
474 port_settings.c_cflag |= CS8;
485 port_settings.c_cflag |= PARENB;
486 port_settings.c_cflag &= ~PARODD;
487 port_settings.c_iflag |= INPCK;
490 port_settings.c_cflag |= (PARENB | PARODD);
491 port_settings.c_iflag |= INPCK;
494 port_settings.c_cflag &= ~(PARENB);
495 port_settings.c_iflag |= IGNPAR;
506 port_settings.c_cflag &= ~(CSTOPB);
509 port_settings.c_cflag |= CSTOPB;
519 if (enableFlowControl)
522 port_settings.c_cflag |= CRTSCTS;
527 port_settings.c_cflag &= ~(CRTSCTS);
532 if (tcsetattr(
hCOM, TCSANOW, &port_settings) < 0)
536 termios port_settings_verif;
537 if (tcgetattr(
hCOM, &port_settings_verif) < 0)
539 "Cannot get the settings to verify: %s", strerror(errno));
544 if (port_settings_verif.c_ispeed != port_settings.c_ispeed)
546 if (port_settings_verif.c_ospeed != port_settings.c_ospeed)
550 if (port_settings_verif.c_cflag != port_settings.c_cflag)
560 int ReadIntervalTimeout,
int ReadTotalTimeoutMultiplier,
561 int ReadTotalTimeoutConstant,
int WriteTotalTimeoutMultiplier,
562 int WriteTotalTimeoutConstant)
565 #ifdef MRPT_OS_WINDOWS 566 COMMTIMEOUTS timeouts;
572 timeouts.ReadIntervalTimeout =
574 timeouts.ReadTotalTimeoutMultiplier =
575 ReadTotalTimeoutMultiplier;
577 timeouts.ReadTotalTimeoutConstant =
578 ReadTotalTimeoutConstant;
580 timeouts.WriteTotalTimeoutMultiplier =
581 WriteTotalTimeoutMultiplier;
582 timeouts.WriteTotalTimeoutConstant =
583 WriteTotalTimeoutConstant;
585 if (!SetCommTimeouts(
hCOM, &timeouts))
599 termios port_settings;
600 if (tcgetattr(
hCOM, &port_settings) < 0)
602 "Cannot get the current settings: %s", strerror(errno));
606 port_settings.c_cc[VMIN] = 0;
607 port_settings.c_cc[VTIME] = max(1, ReadTotalTimeoutConstant / 100);
611 if (tcsetattr(
hCOM, TCSANOW, &port_settings) < 0)
623 #ifdef MRPT_OS_WINDOWS 627 if (
hCOM < 0)
return;
646 #ifdef MRPT_OS_WINDOWS 666 if (!Count)
return 0;
672 size_t alreadyRead = 0;
675 while (alreadyRead < Count && leftTime >= 0)
679 int waiting_bytes = 0;
680 if (ioctl(
hCOM, FIONREAD, &waiting_bytes) < 0)
693 if (waiting_bytes > 0)
695 int nToRead =
min((
size_t)waiting_bytes, Count - alreadyRead);
697 if ((nRead = ::read(
hCOM, ((
char*)Buffer) + alreadyRead, nToRead)) <
700 cerr <<
"[CSerialPort] Error reading from port..." << endl;
703 alreadyRead += nRead;
710 if (alreadyRead < Count)
713 std::this_thread::sleep_for(1ms);
732 const int total_timeout_ms,
bool* out_timeout,
const char* eol_chars)
743 if (out_timeout) *out_timeout =
false;
748 while (total_timeout_ms < 0 || (
m_timer.
Tac() * 1e3 < total_timeout_ms))
750 #ifdef MRPT_OS_WINDOWS 765 if (!strchr(eol_chars, buf[0]))
766 receivedStr.push_back(buf[0]);
773 std::this_thread::sleep_for(
778 int waiting_bytes = 0;
779 if (ioctl(
hCOM, FIONREAD, &waiting_bytes) < 0)
790 if (waiting_bytes > 0)
794 if ((nRead = ::read(
hCOM, buf, 1)) < 0)
796 cerr <<
"[CSerialPort] Error reading from port..." << endl;
800 if (!strchr(eol_chars, buf[0]))
801 receivedStr.push_back(buf[0]);
813 std::this_thread::sleep_for(
821 if (out_timeout) *out_timeout =
true;
832 #ifdef MRPT_OS_WINDOWS 833 DWORD actuallyWritten;
834 if (!WriteFile(
hCOM, Buffer, (DWORD)Count, &actuallyWritten,
nullptr))
836 return actuallyWritten;
843 int num_of_bytes_written = -1;
844 size_t total_bytes_written = 0;
847 gettimeofday(&
start,
nullptr);
848 num_of_bytes_written = write(
849 hCOM, reinterpret_cast<const char*>(Buffer) + total_bytes_written,
850 Count - total_bytes_written);
853 if (num_of_bytes_written > 0)
854 total_bytes_written += num_of_bytes_written;
856 if (num_of_bytes_written < (
int)Count)
866 gettimeofday(&
end,
nullptr);
867 usecs = (
end.tv_sec -
start.tv_sec) * 1000000 +
869 }
while (usecs < 60);
873 }
while ((total_bytes_written < Count) && (!errno || EAGAIN == errno));
875 if (num_of_bytes_written <
878 "Error writing data to the serial port: %s", strerror(errno));
885 return total_bytes_written;
898 #ifdef MRPT_OS_WINDOWS 901 PURGE_RXABORT | PURGE_RXCLEAR | PURGE_TXABORT | PURGE_TXCLEAR))
905 if (tcflush(
hCOM, TCIFLUSH) < 0)
size_t Write(const void *Buffer, size_t Count)
Implements the virtual method responsible for writing to the stream.
Classes for serialization, sockets, ini-file manipulation, streams, list of properties-values, timewatch, extensions to STL.
std::string ReadString(const int total_timeout_ms=-1, bool *out_timeout=nullptr, const char *eol_chars="\")
Reads one text line from the serial port in POSIX "canonical mode".
#define THROW_EXCEPTION(msg)
#define THROW_EXCEPTION_FMT(_FORMAT_STRING,...)
void open()
Open the port.
void setConfig(int baudRate, int parity=0, int bits=8, int nStopBits=1, bool enableFlowControl=false)
Changes the configuration of the port.
void Tic()
Starts the stopwatch.
mrpt::utils::CTicTac m_timer
Used only in ReadString.
int m_interBytesTimeout_ms
bool isOpen() const
Returns if port has been correctly open.
void purgeBuffers()
Purge tx and rx buffers.
GLsizei const GLchar ** string
void close()
Close the port.
void setTimeouts(int ReadIntervalTimeout, int ReadTotalTimeoutMultiplier, int ReadTotalTimeoutConstant, int WriteTotalTimeoutMultiplier, int WriteTotalTimeoutConstant)
Changes the timeouts of the port, in milliseconds.
This is the global namespace for all Mobile Robot Programming Toolkit (MRPT) libraries.
std::string m_serialName
The complete name of the serial port device (i.e.
double Tac()
Stops the stopwatch.
Serial and networking devices and utilities.
CSerialPort()
Default constructor: it does not open any port - later you must call "setSerialPortName" and then "op...
int hCOM
The file handle (-1: Not open)
size_t Read(void *Buffer, size_t Count)
Implements the virtual method responsible for reading from the stream - Unlike CStream::ReadBuffer, this method will not raise an exception on zero bytes read, as long as there is not any fatal error in the communications.
virtual ~CSerialPort()
Destructor.