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)
103 if (INVALID_HANDLE_VALUE ==
106 GENERIC_READ | GENERIC_WRITE, 0,
nullptr, OPEN_EXISTING, 0, 0)))
110 "Error trying to open serial port: %s",
m_serialName.c_str());
114 SetupComm(
hCOM, 4096, 4096);
130 "Error trying to open the serial port %s!!",
m_serialName.c_str());
133 fcntl(
hCOM, F_SETFL, 0);
138 termios port_settings;
139 bzero(&port_settings,
sizeof(port_settings));
145 port_settings.c_cflag |= CREAD | CLOCAL;
155 port_settings.c_cc[VMIN] = 0;
156 port_settings.c_cc[VTIME] = 0;
161 if (tcflush(
hCOM, TCIFLUSH) < 0)
167 if (tcsetattr(
hCOM, TCSANOW, &port_settings) < 0)
169 "Cannot set the new config to the serial port: %s",
173 fcntl(
hCOM, F_SETFL, FNDELAY);
186 return hCOM !=
nullptr;
196 int baudRate,
int parity,
int bits,
int nStopBits,
bool enableFlowControl)
202 dcb_conf.DCBlength =
sizeof(DCB);
207 if (!GetCommState(
hCOM, &dcb_conf))
253 dcb_conf.BaudRate = BR;
255 dcb_conf.ByteSize = (BYTE)bits;
256 dcb_conf.Parity = (BYTE)parity;
262 dcb_conf.StopBits = ONESTOPBIT;
265 dcb_conf.StopBits = TWOSTOPBITS;
272 dcb_conf.fBinary =
true;
273 dcb_conf.fParity = parity != 0;
275 dcb_conf.fRtsControl =
276 enableFlowControl ? RTS_CONTROL_HANDSHAKE : RTS_CONTROL_DISABLE;
277 dcb_conf.fOutxCtsFlow = enableFlowControl;
280 if (!SetCommState(
hCOM, &dcb_conf))
284 if (!GetCommState(
hCOM, &dcb_conf))
286 if (((
int)dcb_conf.BaudRate) != baudRate)
301 bool special_rate =
false;
395 #ifdef HAVE_LINUX_SERIAL_H 405 #ifdef HAVE_LINUX_SERIAL_H 406 struct serial_struct serial;
407 if (ioctl(
hCOM, TIOCGSERIAL, &serial) < 0)
410 serial.custom_divisor = serial.baud_base / baudRate;
411 if (!serial.custom_divisor) serial.custom_divisor = 1;
412 const int actual_rate = serial.baud_base / serial.custom_divisor;
414 serial.flags &= ~ASYNC_SPD_MASK;
415 serial.flags |= ASYNC_SPD_CUST;
417 if (ioctl(
hCOM, TIOCSSERIAL, &serial) < 0)
423 if (actual_rate != baudRate)
424 cout <<
"[CSerialPort::setConfig] Setting custom baud rate to " 425 << actual_rate <<
", the closer I can make to " << baudRate
428 THROW_EXCEPTION(
"Custom serial port baud rates require linux/serial.h");
446 termios port_settings;
447 if (tcgetattr(
hCOM, &port_settings) < 0)
449 "Cannot get the current settings: %s", strerror(errno));
451 if ((cfsetispeed(&port_settings, BR) < 0) ||
452 (cfsetospeed(&port_settings, BR) < 0))
454 "Cannot change baudRate in setting structure: %s", strerror(errno));
459 port_settings.c_cflag &= ~CSIZE;
463 port_settings.c_cflag |= CS5;
466 port_settings.c_cflag |= CS6;
469 port_settings.c_cflag |= CS7;
472 port_settings.c_cflag |= CS8;
483 port_settings.c_cflag |= PARENB;
484 port_settings.c_cflag &= ~PARODD;
485 port_settings.c_iflag |= INPCK;
488 port_settings.c_cflag |= (PARENB | PARODD);
489 port_settings.c_iflag |= INPCK;
492 port_settings.c_cflag &= ~(PARENB);
493 port_settings.c_iflag |= IGNPAR;
504 port_settings.c_cflag &= ~(CSTOPB);
507 port_settings.c_cflag |= CSTOPB;
517 if (enableFlowControl)
520 port_settings.c_cflag |= CRTSCTS;
525 port_settings.c_cflag &= ~(CRTSCTS);
530 if (tcsetattr(
hCOM, TCSANOW, &port_settings) < 0)
534 termios port_settings_verif;
535 if (tcgetattr(
hCOM, &port_settings_verif) < 0)
537 "Cannot get the settings to verify: %s", strerror(errno));
542 if (port_settings_verif.c_ispeed != port_settings.c_ispeed)
544 if (port_settings_verif.c_ospeed != port_settings.c_ospeed)
548 if (port_settings_verif.c_cflag != port_settings.c_cflag)
558 int ReadIntervalTimeout,
int ReadTotalTimeoutMultiplier,
559 int ReadTotalTimeoutConstant,
int WriteTotalTimeoutMultiplier,
560 int WriteTotalTimeoutConstant)
564 COMMTIMEOUTS timeouts;
570 timeouts.ReadIntervalTimeout =
572 timeouts.ReadTotalTimeoutMultiplier =
573 ReadTotalTimeoutMultiplier;
575 timeouts.ReadTotalTimeoutConstant =
576 ReadTotalTimeoutConstant;
578 timeouts.WriteTotalTimeoutMultiplier =
579 WriteTotalTimeoutMultiplier;
580 timeouts.WriteTotalTimeoutConstant =
581 WriteTotalTimeoutConstant;
583 if (!SetCommTimeouts(
hCOM, &timeouts))
597 termios port_settings;
598 if (tcgetattr(
hCOM, &port_settings) < 0)
600 "Cannot get the current settings: %s", strerror(errno));
604 port_settings.c_cc[VMIN] = 0;
605 port_settings.c_cc[VTIME] = max(1, ReadTotalTimeoutConstant / 100);
609 if (tcsetattr(
hCOM, TCSANOW, &port_settings) < 0)
625 if (
hCOM < 0)
return;
664 if (!Count)
return 0;
670 size_t alreadyRead = 0;
673 while (alreadyRead < Count && leftTime >= 0)
677 int waiting_bytes = 0;
678 if (ioctl(
hCOM, FIONREAD, &waiting_bytes) < 0)
691 if (waiting_bytes > 0)
693 int nToRead =
min((
size_t)waiting_bytes, Count - alreadyRead);
695 if ((nRead = ::read(
hCOM, ((
char*)Buffer) + alreadyRead, nToRead)) <
698 cerr <<
"[CSerialPort] read() returned " << nRead
699 <<
", errno=" << errno << endl;
703 alreadyRead += nRead;
711 if (alreadyRead < Count)
714 std::this_thread::sleep_for(1ms);
733 const int total_timeout_ms,
bool* out_timeout,
const char* eol_chars)
744 if (out_timeout) *out_timeout =
false;
749 while (total_timeout_ms < 0 || (
m_timer.
Tac() * 1e3 < total_timeout_ms))
766 if (!strchr(eol_chars, buf[0]))
767 receivedStr.push_back(buf[0]);
774 std::this_thread::sleep_for(
779 int waiting_bytes = 0;
780 if (ioctl(
hCOM, FIONREAD, &waiting_bytes) < 0)
791 if (waiting_bytes > 0)
795 if ((nRead = ::read(
hCOM, buf, 1)) < 0)
797 cerr <<
"[CSerialPort] Error reading from port..." << endl;
801 if (!strchr(eol_chars, buf[0]))
802 receivedStr.push_back(buf[0]);
814 std::this_thread::sleep_for(
822 if (out_timeout) *out_timeout =
true;
834 DWORD actuallyWritten;
835 if (!WriteFile(
hCOM, Buffer, (DWORD)Count, &actuallyWritten,
nullptr))
837 return actuallyWritten;
844 int num_of_bytes_written = -1;
845 size_t total_bytes_written = 0;
848 gettimeofday(&
start,
nullptr);
849 num_of_bytes_written = write(
850 hCOM, reinterpret_cast<const char*>(Buffer) + total_bytes_written,
851 Count - total_bytes_written);
854 if (num_of_bytes_written > 0)
855 total_bytes_written += num_of_bytes_written;
857 if (num_of_bytes_written < (
int)Count)
867 gettimeofday(&
end,
nullptr);
868 usecs = (
end.tv_sec -
start.tv_sec) * 1000000 +
870 }
while (usecs < 60);
874 }
while ((total_bytes_written < Count) && (!errno || EAGAIN == errno));
876 if (num_of_bytes_written <
879 "Error writing data to the serial port: %s", strerror(errno));
886 return total_bytes_written;
902 PURGE_RXABORT | PURGE_RXCLEAR | PURGE_TXABORT | PURGE_TXCLEAR))
906 if (tcflush(
hCOM, TCIFLUSH) < 0)
919 "Method not applicable to serial communications port CStream!");
927 "Method not applicable to serial communications port CStream!");
935 "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.
#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
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.
unsigned __int64 uint64_t
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.
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...
#define MRPT_UNUSED_PARAM(a)
Determines whether this is an X86 or AMD64 platform.