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...