16 #if defined(MRPT_OS_LINUX) || defined(__APPLE__)
29 #include <sys/ioctl.h>
32 #ifdef HAVE_LINUX_SERIAL_H
33 #include <linux/serial.h>
38 #endif // Linux | Apple
51 using namespace std::literals;
55 : m_serialName(portName),
57 m_interBytesTimeout_ms(0),
71 m_interBytesTimeout_ms(0),
123 if (INVALID_HANDLE_VALUE ==
126 GENERIC_READ | GENERIC_WRITE, 0,
nullptr, OPEN_EXISTING, 0, 0)))
130 "Error trying to open serial port: %s",
m_serialName.c_str());
134 SetupComm(
hCOM, 4096, 4096);
150 "Error trying to open the serial port %s!!",
m_serialName.c_str());
153 fcntl(
hCOM, F_SETFL, 0);
158 termios port_settings;
159 bzero(&port_settings,
sizeof(port_settings));
165 port_settings.c_cflag |= CREAD | CLOCAL;
175 port_settings.c_cc[VMIN] = 0;
176 port_settings.c_cc[VTIME] = 0;
181 if (tcflush(
hCOM, TCIFLUSH) < 0)
187 if (tcsetattr(
hCOM, TCSANOW, &port_settings) < 0)
189 "Cannot set the new config to the serial port: %s",
193 fcntl(
hCOM, F_SETFL, FNDELAY);
206 return hCOM !=
nullptr;
216 int baudRate,
int parity,
int bits,
int nStopBits,
bool enableFlowControl)
222 dcb_conf.DCBlength =
sizeof(DCB);
227 if (!GetCommState(
hCOM, &dcb_conf))
273 dcb_conf.BaudRate = BR;
275 dcb_conf.ByteSize = (BYTE)bits;
276 dcb_conf.Parity = (BYTE)parity;
282 dcb_conf.StopBits = ONESTOPBIT;
285 dcb_conf.StopBits = TWOSTOPBITS;
292 dcb_conf.fBinary =
true;
293 dcb_conf.fParity = parity != 0;
295 dcb_conf.fRtsControl =
296 enableFlowControl ? RTS_CONTROL_HANDSHAKE : RTS_CONTROL_DISABLE;
297 dcb_conf.fOutxCtsFlow = enableFlowControl;
300 if (!SetCommState(
hCOM, &dcb_conf))
304 if (!GetCommState(
hCOM, &dcb_conf))
306 if (((
int)dcb_conf.BaudRate) != baudRate)
321 bool special_rate =
false;
415 #ifdef HAVE_LINUX_SERIAL_H
425 #ifdef HAVE_LINUX_SERIAL_H
426 struct serial_struct serial;
427 if (ioctl(
hCOM, TIOCGSERIAL, &serial) < 0)
430 serial.custom_divisor = serial.baud_base / baudRate;
431 if (!serial.custom_divisor) serial.custom_divisor = 1;
432 const int actual_rate = serial.baud_base / serial.custom_divisor;
434 serial.flags &= ~ASYNC_SPD_MASK;
435 serial.flags |= ASYNC_SPD_CUST;
437 if (ioctl(
hCOM, TIOCSSERIAL, &serial) < 0)
443 if (actual_rate != baudRate)
444 cout <<
"[CSerialPort::setConfig] Setting custom baud rate to "
445 << actual_rate <<
", the closer I can make to " << baudRate
448 THROW_EXCEPTION(
"Custom serial port baud rates require linux/serial.h");
466 termios port_settings;
467 if (tcgetattr(
hCOM, &port_settings) < 0)
469 "Cannot get the current settings: %s", strerror(errno));
471 if ((cfsetispeed(&port_settings, BR) < 0) ||
472 (cfsetospeed(&port_settings, BR) < 0))
474 "Cannot change baudRate in setting structure: %s", strerror(errno));
479 port_settings.c_cflag &= ~CSIZE;
483 port_settings.c_cflag |= CS5;
486 port_settings.c_cflag |= CS6;
489 port_settings.c_cflag |= CS7;
492 port_settings.c_cflag |= CS8;
503 port_settings.c_cflag |= PARENB;
504 port_settings.c_cflag &= ~PARODD;
505 port_settings.c_iflag |= INPCK;
508 port_settings.c_cflag |= (PARENB | PARODD);
509 port_settings.c_iflag |= INPCK;
512 port_settings.c_cflag &= ~(PARENB);
513 port_settings.c_iflag |= IGNPAR;
524 port_settings.c_cflag &= ~(CSTOPB);
527 port_settings.c_cflag |= CSTOPB;
537 if (enableFlowControl)
540 port_settings.c_cflag |= CRTSCTS;
545 port_settings.c_cflag &= ~(CRTSCTS);
550 if (tcsetattr(
hCOM, TCSANOW, &port_settings) < 0)
554 termios port_settings_verif;
555 if (tcgetattr(
hCOM, &port_settings_verif) < 0)
557 "Cannot get the settings to verify: %s", strerror(errno));
562 if (port_settings_verif.c_ispeed != port_settings.c_ispeed)
564 if (port_settings_verif.c_ospeed != port_settings.c_ospeed)
568 if (port_settings_verif.c_cflag != port_settings.c_cflag)
578 int ReadIntervalTimeout,
int ReadTotalTimeoutMultiplier,
579 int ReadTotalTimeoutConstant,
int WriteTotalTimeoutMultiplier,
580 int WriteTotalTimeoutConstant)
584 COMMTIMEOUTS timeouts;
590 timeouts.ReadIntervalTimeout =
592 timeouts.ReadTotalTimeoutMultiplier =
593 ReadTotalTimeoutMultiplier;
595 timeouts.ReadTotalTimeoutConstant =
596 ReadTotalTimeoutConstant;
598 timeouts.WriteTotalTimeoutMultiplier =
599 WriteTotalTimeoutMultiplier;
600 timeouts.WriteTotalTimeoutConstant =
601 WriteTotalTimeoutConstant;
603 if (!SetCommTimeouts(
hCOM, &timeouts))
617 termios port_settings;
618 if (tcgetattr(
hCOM, &port_settings) < 0)
620 "Cannot get the current settings: %s", strerror(errno));
624 port_settings.c_cc[VMIN] = 0;
625 port_settings.c_cc[VTIME] = max(1, ReadTotalTimeoutConstant / 100);
629 if (tcsetattr(
hCOM, TCSANOW, &port_settings) < 0)
645 if (
hCOM < 0)
return;
684 if (!Count)
return 0;
690 size_t alreadyRead = 0;
693 while (alreadyRead < Count && leftTime >= 0)
697 int waiting_bytes = 0;
698 if (ioctl(
hCOM, FIONREAD, &waiting_bytes) < 0)
711 if (waiting_bytes > 0)
713 int nToRead =
min((
size_t)waiting_bytes, Count - alreadyRead);
715 if ((nRead = ::read(
hCOM, ((
char*)Buffer) + alreadyRead, nToRead)) <
718 cerr <<
"[CSerialPort] read() returned " << nRead
719 <<
", errno=" << errno << endl;
723 alreadyRead += nRead;
731 if (alreadyRead < Count)
734 std::this_thread::sleep_for(1ms);
753 const int total_timeout_ms,
bool* out_timeout,
const char* eol_chars)
764 if (out_timeout) *out_timeout =
false;
769 while (total_timeout_ms < 0 || (
m_timer.
Tac() * 1e3 < total_timeout_ms))
786 if (!strchr(eol_chars, buf[0]))
787 receivedStr.push_back(buf[0]);
794 std::this_thread::sleep_for(
799 int waiting_bytes = 0;
800 if (ioctl(
hCOM, FIONREAD, &waiting_bytes) < 0)
811 if (waiting_bytes > 0)
815 if ((nRead = ::read(
hCOM, buf, 1)) < 0)
817 cerr <<
"[CSerialPort] Error reading from port..." << endl;
821 if (!strchr(eol_chars, buf[0]))
822 receivedStr.push_back(buf[0]);
834 std::this_thread::sleep_for(
842 if (out_timeout) *out_timeout =
true;
854 DWORD actuallyWritten;
855 if (!WriteFile(
hCOM, Buffer, (DWORD)Count, &actuallyWritten,
nullptr))
857 return actuallyWritten;
864 int num_of_bytes_written = -1;
865 size_t total_bytes_written = 0;
868 gettimeofday(&
start,
nullptr);
869 num_of_bytes_written = write(
870 hCOM,
reinterpret_cast<const char*
>(Buffer) + total_bytes_written,
871 Count - total_bytes_written);
874 if (num_of_bytes_written > 0)
875 total_bytes_written += num_of_bytes_written;
877 if (num_of_bytes_written < (
int)Count)
887 gettimeofday(&
end,
nullptr);
888 usecs = (
end.tv_sec -
start.tv_sec) * 1000000 +
890 }
while (usecs < 60);
894 }
while ((total_bytes_written < Count) && (!errno || EAGAIN == errno));
896 if (num_of_bytes_written <
899 "Error writing data to the serial port: %s", strerror(errno));
906 return total_bytes_written;
922 PURGE_RXABORT | PURGE_RXCLEAR | PURGE_TXABORT | PURGE_TXCLEAR))
926 if (tcflush(
hCOM, TCIFLUSH) < 0)
939 "Method not applicable to serial communications port CStream!");
947 "Method not applicable to serial communications port CStream!");
955 "Method not applicable to serial communications port CStream!");