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>
40 #ifdef MRPT_OS_WINDOWS
50 using namespace std::literals;
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)
bool isOpen() const
Returns if port has been correctly open.
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.
std::string ReadString(const int total_timeout_ms=-1, bool *out_timeout=nullptr, const char *eol_chars="\r\n")
Reads one text line from the serial port in POSIX "canonical mode".
CSerialPort()
Default constructor: it does not open any port - later you must call "setSerialPortName" and then "op...
size_t Write(const void *Buffer, size_t Count)
Implements the virtual method responsible for writing to the stream.
size_t Read(void *Buffer, size_t Count)
Implements the virtual method responsible for reading from the stream - Unlike CStream::ReadBuffer,...
void purgeBuffers()
Purge tx and rx buffers.
mrpt::utils::CTicTac m_timer
Used only in ReadString.
void close()
Close the port.
std::string m_serialName
The complete name of the serial port device (i.e.
void setTimeouts(int ReadIntervalTimeout, int ReadTotalTimeoutMultiplier, int ReadTotalTimeoutConstant, int WriteTotalTimeoutMultiplier, int WriteTotalTimeoutConstant)
Changes the timeouts of the port, in milliseconds.
int m_interBytesTimeout_ms
virtual ~CSerialPort()
Destructor.
int hCOM
The file handle (-1: Not open)
double Tac()
Stops the stopwatch.
void Tic()
Starts the stopwatch.
GLsizei const GLchar ** string
#define THROW_EXCEPTION(msg)
#define THROW_EXCEPTION_FMT(_FORMAT_STRING,...)
Serial and networking devices and utilities.
Classes for serialization, sockets, ini-file manipulation, streams, list of properties-values,...
This is the global namespace for all Mobile Robot Programming Toolkit (MRPT) libraries.