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 55 : m_serialName(portName)
67 catch (
const std::exception& e)
110 if (INVALID_HANDLE_VALUE ==
113 GENERIC_READ | GENERIC_WRITE, 0,
nullptr, OPEN_EXISTING, 0, 0)))
117 "Error trying to open serial port: %s",
m_serialName.c_str());
121 SetupComm(
hCOM, 4096, 4096);
137 "Error trying to open the serial port %s!!",
m_serialName.c_str());
140 fcntl(
hCOM, F_SETFL, 0);
145 termios port_settings;
146 bzero(&port_settings,
sizeof(port_settings));
152 port_settings.c_cflag |= CREAD | CLOCAL;
162 port_settings.c_cc[VMIN] = 0;
163 port_settings.c_cc[VTIME] = 0;
168 if (tcflush(
hCOM, TCIFLUSH) < 0)
174 if (tcsetattr(
hCOM, TCSANOW, &port_settings) < 0)
176 "Cannot set the new config to the serial port: %s",
180 fcntl(
hCOM, F_SETFL, FNDELAY);
193 return hCOM !=
nullptr;
203 int baudRate,
int parity,
int bits,
int nStopBits,
bool enableFlowControl)
209 dcb_conf.DCBlength =
sizeof(DCB);
214 if (!GetCommState(
hCOM, &dcb_conf))
260 dcb_conf.BaudRate = BR;
262 dcb_conf.ByteSize = (BYTE)bits;
263 dcb_conf.Parity = (BYTE)parity;
269 dcb_conf.StopBits = ONESTOPBIT;
272 dcb_conf.StopBits = TWOSTOPBITS;
279 dcb_conf.fBinary =
true;
280 dcb_conf.fParity = parity != 0;
282 dcb_conf.fRtsControl =
283 enableFlowControl ? RTS_CONTROL_HANDSHAKE : RTS_CONTROL_DISABLE;
284 dcb_conf.fOutxCtsFlow = enableFlowControl;
287 if (!SetCommState(
hCOM, &dcb_conf))
291 if (!GetCommState(
hCOM, &dcb_conf))
293 if (((
int)dcb_conf.BaudRate) != baudRate)
308 bool special_rate =
false;
402 #ifdef HAVE_LINUX_SERIAL_H 412 #ifdef HAVE_LINUX_SERIAL_H 413 struct serial_struct serial;
414 if (ioctl(
hCOM, TIOCGSERIAL, &serial) < 0)
417 serial.custom_divisor = serial.baud_base / baudRate;
418 if (!serial.custom_divisor) serial.custom_divisor = 1;
419 const int actual_rate = serial.baud_base / serial.custom_divisor;
421 serial.flags &= ~ASYNC_SPD_MASK;
422 serial.flags |= ASYNC_SPD_CUST;
424 if (ioctl(
hCOM, TIOCSSERIAL, &serial) < 0)
430 if (actual_rate != baudRate)
431 cout <<
"[CSerialPort::setConfig] Setting custom baud rate to " 432 << actual_rate <<
", the closer I can make to " << baudRate
435 THROW_EXCEPTION(
"Custom serial port baud rates require linux/serial.h");
453 termios port_settings;
454 if (tcgetattr(
hCOM, &port_settings) < 0)
456 "Cannot get the current settings: %s", strerror(errno));
458 if ((cfsetispeed(&port_settings, BR) < 0) ||
459 (cfsetospeed(&port_settings, BR) < 0))
461 "Cannot change baudRate in setting structure: %s", strerror(errno));
466 port_settings.c_cflag &= ~CSIZE;
470 port_settings.c_cflag |= CS5;
473 port_settings.c_cflag |= CS6;
476 port_settings.c_cflag |= CS7;
479 port_settings.c_cflag |= CS8;
490 port_settings.c_cflag |= PARENB;
491 port_settings.c_cflag &= ~PARODD;
492 port_settings.c_iflag |= INPCK;
495 port_settings.c_cflag |= (PARENB | PARODD);
496 port_settings.c_iflag |= INPCK;
499 port_settings.c_cflag &= ~(PARENB);
500 port_settings.c_iflag |= IGNPAR;
511 port_settings.c_cflag &= ~(CSTOPB);
514 port_settings.c_cflag |= CSTOPB;
524 if (enableFlowControl)
527 port_settings.c_cflag |= CRTSCTS;
532 port_settings.c_cflag &= ~(CRTSCTS);
537 if (tcsetattr(
hCOM, TCSANOW, &port_settings) < 0)
541 termios port_settings_verif;
542 if (tcgetattr(
hCOM, &port_settings_verif) < 0)
544 "Cannot get the settings to verify: %s", strerror(errno));
549 if (port_settings_verif.c_ispeed != port_settings.c_ispeed)
551 if (port_settings_verif.c_ospeed != port_settings.c_ospeed)
555 if (port_settings_verif.c_cflag != port_settings.c_cflag)
565 int ReadIntervalTimeout,
int ReadTotalTimeoutMultiplier,
566 int ReadTotalTimeoutConstant,
int WriteTotalTimeoutMultiplier,
567 int WriteTotalTimeoutConstant)
571 COMMTIMEOUTS timeouts;
577 timeouts.ReadIntervalTimeout =
579 timeouts.ReadTotalTimeoutMultiplier =
580 ReadTotalTimeoutMultiplier;
582 timeouts.ReadTotalTimeoutConstant =
583 ReadTotalTimeoutConstant;
585 timeouts.WriteTotalTimeoutMultiplier =
586 WriteTotalTimeoutMultiplier;
587 timeouts.WriteTotalTimeoutConstant =
588 WriteTotalTimeoutConstant;
590 if (!SetCommTimeouts(
hCOM, &timeouts))
604 termios port_settings;
605 if (tcgetattr(
hCOM, &port_settings) < 0)
607 "Cannot get the current settings: %s", strerror(errno));
611 port_settings.c_cc[VMIN] = 0;
612 port_settings.c_cc[VTIME] = max(1, ReadTotalTimeoutConstant / 100);
616 if (tcsetattr(
hCOM, TCSANOW, &port_settings) < 0)
632 if (
hCOM < 0)
return;
671 if (!Count)
return 0;
677 size_t alreadyRead = 0;
680 while (alreadyRead < Count && leftTime >= 0)
684 int waiting_bytes = 0;
685 if (ioctl(
hCOM, FIONREAD, &waiting_bytes) < 0)
698 if (waiting_bytes > 0)
700 int nToRead = min((
size_t)waiting_bytes, Count - alreadyRead);
702 if ((nRead = ::read(
hCOM, ((
char*)Buffer) + alreadyRead, nToRead)) <
705 cerr <<
"[CSerialPort] read() returned " << nRead
706 <<
", errno=" << errno << endl;
710 alreadyRead += nRead;
718 if (alreadyRead < Count)
721 std::this_thread::sleep_for(1ms);
740 const int total_timeout_ms,
bool* out_timeout,
const char* eol_chars)
751 if (out_timeout) *out_timeout =
false;
756 while (total_timeout_ms < 0 || (
m_timer.
Tac() * 1e3 < total_timeout_ms))
773 if (!strchr(eol_chars, buf[0]))
774 receivedStr.push_back(buf[0]);
781 std::this_thread::sleep_for(
786 int waiting_bytes = 0;
787 if (ioctl(
hCOM, FIONREAD, &waiting_bytes) < 0)
798 if (waiting_bytes > 0)
802 if ((nRead = ::read(
hCOM, buf, 1)) < 0)
804 cerr <<
"[CSerialPort] Error reading from port..." << endl;
808 if (!strchr(eol_chars, buf[0]))
809 receivedStr.push_back(buf[0]);
821 std::this_thread::sleep_for(
829 if (out_timeout) *out_timeout =
true;
841 DWORD actuallyWritten;
842 if (!WriteFile(
hCOM, Buffer, (DWORD)Count, &actuallyWritten,
nullptr))
844 return actuallyWritten;
850 struct timeval start = {0, 0},
end = {0, 0};
851 int num_of_bytes_written = -1;
852 size_t total_bytes_written = 0;
855 gettimeofday(&start,
nullptr);
856 num_of_bytes_written = write(
857 hCOM, reinterpret_cast<const char*>(Buffer) + total_bytes_written,
858 Count - total_bytes_written);
861 if (num_of_bytes_written > 0)
862 total_bytes_written += num_of_bytes_written;
864 if (num_of_bytes_written < (
int)Count)
874 gettimeofday(&
end,
nullptr);
875 usecs = (
end.tv_sec - start.tv_sec) * 1000000 +
876 (
end.tv_usec - start.tv_usec);
877 }
while (usecs < 60);
881 }
while ((total_bytes_written < Count) && (!errno || EAGAIN == errno));
883 if (num_of_bytes_written <
886 "Error writing data to the serial port: %s", strerror(errno));
893 return total_bytes_written;
909 PURGE_RXABORT | PURGE_RXCLEAR | PURGE_TXABORT | PURGE_TXCLEAR))
913 if (tcflush(
hCOM, TCIFLUSH) < 0)
921 [[maybe_unused]] int64_t Offset,
926 "Method not applicable to serial communications port CStream!");
934 "Method not applicable to serial communications port CStream!");
942 "Method not applicable to serial communications port CStream!");
TSeekOrigin
Used in CStream::Seek.
double Tac() noexcept
Stops the stopwatch.
size_t Read(void *Buffer, size_t Count) override
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.
#define MRPT_TRY_END
The end of a standard MRPT "try...catch()" block that allows tracing throw the call stack after an ex...
#define THROW_EXCEPTION(msg)
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".
void open()
Open the port.
uint64_t getTotalBytesCount() const override
not applicable in a serial port
void setConfig(int baudRate, int parity=0, int bits=8, int nStopBits=1, bool enableFlowControl=false)
Changes the configuration of the port.
void open(const std::string &COM_name)
Open the given serial port.
#define MRPT_TRY_START
The start of a standard MRPT "try...catch()" block that allows tracing throw the call stack after an ...
#define ASSERT_(f)
Defines an assertion mechanism.
int m_interBytesTimeout_ms
void setSerialPortName(const std::string &COM_name)
Sets the serial port to open (it is an error to try to change this while open yet).
bool isOpen() const
Returns if port has been correctly open.
size_t Write(const void *Buffer, size_t Count) override
Introduces a pure virtual method responsible for writing to the stream.
void purgeBuffers()
Purge tx and rx buffers.
mrpt::system::CTicTac m_timer
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.
const_iterator end() const
This is the global namespace for all Mobile Robot Programming Toolkit (MRPT) libraries.
~CSerialPort() override
Destructor.
std::string m_serialName
The complete name of the serial port device (i.e.
std::string exception_to_str(const std::exception &e)
Builds a nice textual representation of a nested exception, which if generated using MRPT macros (THR...
uint64_t Seek(int64_t off, CStream::TSeekOrigin o=sFromBeginning) override
not applicable in a serial port
Serial and networking devices and utilities.
void Tic() noexcept
Starts the stopwatch.
#define THROW_EXCEPTION_FMT(_FORMAT_STRING,...)
uint64_t getPosition() const override
not applicable in a serial port
CSerialPort()=default
Default constructor: it does not open any port - later you must call "setSerialPortName" and then "op...