17 #if defined(MRPT_OS_LINUX) || defined(MRPT_OS_APPLE)
30 #include <sys/ioctl.h>
33 #ifdef HAVE_LINUX_SERIAL_H
34 #include <linux/serial.h>
41 #ifdef MRPT_OS_WINDOWS
51 CSerialPort::CSerialPort(
const string &portName,
bool openNow ) :
52 m_serialName(portName),
54 m_interBytesTimeout_ms(0),
55 #ifdef MRPT_OS_WINDOWS
68 m_interBytesTimeout_ms(0),
69 #ifdef MRPT_OS_WINDOWS
90 #ifdef MRPT_OS_WINDOWS
104 if (INVALID_HANDLE_VALUE == (
107 GENERIC_READ | GENERIC_WRITE,
119 SetupComm(
hCOM, 4096, 4096);
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 )
172 fcntl(
hCOM, F_SETFL, FNDELAY);
185 #ifdef MRPT_OS_WINDOWS
200 bool enableFlowControl )
203 #ifdef MRPT_OS_WINDOWS
206 dcb_conf.DCBlength =
sizeof(DCB);
219 case 300: BR = CBR_300;
break;
220 case 600: BR = CBR_600;
break;
221 case 1200: BR = CBR_1200;
break;
222 case 2400: BR = CBR_2400;
break;
223 case 4800: BR = CBR_4800;
break;
224 case 9600: BR = CBR_9600;
break;
225 case 19200: BR = CBR_19200;
break;
226 case 38400: BR = CBR_38400;
break;
227 case 57600: BR = CBR_57600;
break;
228 case 115200: BR = CBR_115200;
break;
235 dcb_conf.BaudRate = BR;
238 dcb_conf.ByteSize = (BYTE)bits;
239 dcb_conf.Parity = (BYTE)parity;
245 dcb_conf.StopBits = ONESTOPBIT;
248 dcb_conf.StopBits = TWOSTOPBITS;
255 dcb_conf.fBinary =
true;
256 dcb_conf.fParity = parity != 0;
258 dcb_conf.fRtsControl = enableFlowControl ? RTS_CONTROL_HANDSHAKE : RTS_CONTROL_DISABLE;
259 dcb_conf.fOutxCtsFlow = enableFlowControl;
262 if (!SetCommState(
hCOM, &dcb_conf))
266 if (!GetCommState(
hCOM, &dcb_conf))
268 if (((
int)dcb_conf.BaudRate) != baudRate)
283 bool special_rate =
false;
286 case 50: BR = B50;
break;
287 case 75: BR = B75;
break;
288 case 110: BR = B110;
break;
289 case 134: BR = B134;
break;
290 case 200: BR = B200;
break;
291 case 300: BR = B300;
break;
292 case 600: BR = B600;
break;
293 case 1200: BR = B1200;
break;
294 case 2400: BR = B2400;
break;
295 case 4800: BR = B4800;
break;
296 case 9600: BR = B9600;
break;
297 case 19200: BR = B19200;
break;
298 case 38400: BR = B38400;
break;
299 case 57600: BR = B57600;
break;
300 case 115200: BR = B115200;
break;
301 case 230400: BR = B230400;
break;
303 case 460800: BR = B460800;
break;
306 case 500000: BR = B500000;
break;
309 case 576000: BR = B576000;
break;
310 case 921600: BR = B921600;
break;
311 case 1000000: BR = B1000000;
break;
312 case 1152000: BR = B1152000;
break;
313 case 1500000: BR = B1500000;
break;
314 case 2000000: BR = B2000000;
break;
315 case 2500000: BR = B2500000;
break;
316 case 3000000: BR = B3000000;
break;
317 case 3500000: BR = B3500000;
break;
318 case 4000000: BR = B4000000;
break;
321 #ifdef HAVE_LINUX_SERIAL_H
331 #ifdef HAVE_LINUX_SERIAL_H
332 struct serial_struct serial;
333 if (ioctl(
hCOM, TIOCGSERIAL, &serial) < 0)
336 serial.custom_divisor = serial.baud_base / baudRate;
337 if (!serial.custom_divisor) serial.custom_divisor = 1;
338 const int actual_rate = serial.baud_base / serial.custom_divisor;
340 serial.flags &= ~ASYNC_SPD_MASK;
341 serial.flags |= ASYNC_SPD_CUST;
343 if (ioctl(
hCOM, TIOCSSERIAL, &serial) < 0)
348 if (actual_rate!=baudRate)
349 cout <<
"[CSerialPort::setConfig] Setting custom baud rate to " << actual_rate <<
", the closer I can make to " << baudRate << endl;
351 THROW_EXCEPTION(
"Custom serial port baud rates require linux/serial.h");
369 termios port_settings;
370 if ( tcgetattr(
hCOM, & port_settings ) < 0 )
373 if ( ( cfsetispeed( &port_settings,BR ) < 0 ) ||
374 ( cfsetospeed( &port_settings,BR) < 0 ) )
380 port_settings.c_cflag &= ~CSIZE ;
384 port_settings.c_cflag |= CS5;
387 port_settings.c_cflag |= CS6;
390 port_settings.c_cflag |= CS7;
393 port_settings.c_cflag |= CS8;
404 port_settings.c_cflag |= PARENB ;
405 port_settings.c_cflag &= ~PARODD ;
406 port_settings.c_iflag |= INPCK ;
409 port_settings.c_cflag |= ( PARENB | PARODD );
410 port_settings.c_iflag |= INPCK;
413 port_settings.c_cflag &= ~(PARENB);
414 port_settings.c_iflag |= IGNPAR;
425 port_settings.c_cflag &= ~(CSTOPB) ;
428 port_settings.c_cflag |= CSTOPB ;
438 if (enableFlowControl)
441 port_settings.c_cflag |= CRTSCTS ;
446 port_settings.c_cflag &= ~(CRTSCTS) ;
451 if ( tcsetattr(
hCOM,TCSANOW,&port_settings ) < 0 )
455 termios port_settings_verif;
456 if ( tcgetattr(
hCOM, & port_settings_verif) < 0 )
462 if (port_settings_verif.c_ispeed != port_settings.c_ispeed)
464 if (port_settings_verif.c_ospeed != port_settings.c_ospeed)
468 if (port_settings_verif.c_cflag != port_settings.c_cflag)
478 int ReadIntervalTimeout,
479 int ReadTotalTimeoutMultiplier,
480 int ReadTotalTimeoutConstant,
481 int WriteTotalTimeoutMultiplier,
482 int WriteTotalTimeoutConstant )
485 #ifdef MRPT_OS_WINDOWS
486 COMMTIMEOUTS timeouts;
493 timeouts.ReadIntervalTimeout = ReadIntervalTimeout;
494 timeouts.ReadTotalTimeoutMultiplier = ReadTotalTimeoutMultiplier;
495 timeouts.ReadTotalTimeoutConstant = ReadTotalTimeoutConstant;
496 timeouts.WriteTotalTimeoutMultiplier = WriteTotalTimeoutMultiplier;
497 timeouts.WriteTotalTimeoutConstant = WriteTotalTimeoutConstant;
499 if (!SetCommTimeouts(
hCOM, &timeouts))
513 termios port_settings;
514 if (tcgetattr(
hCOM, &port_settings) < 0)
519 port_settings.c_cc[VMIN] = 0;
520 port_settings.c_cc[VTIME] = max(1, ReadTotalTimeoutConstant / 100);
524 if (tcsetattr(
hCOM, TCSANOW, &port_settings) < 0)
536 #ifdef MRPT_OS_WINDOWS
559 #ifdef MRPT_OS_WINDOWS
580 if (!Count)
return 0;
586 size_t alreadyRead = 0;
589 while ( alreadyRead<Count && leftTime>=0 )
594 if ( ioctl(
hCOM, FIONREAD, &waiting_bytes) < 0)
609 int nToRead =
min( (
size_t)waiting_bytes, Count-alreadyRead );
611 if ( ( nRead=::read(
hCOM, ((
char*)Buffer)+alreadyRead, nToRead ) ) <0 )
613 cerr <<
"[CSerialPort] Error reading from port..." << endl;
623 if (alreadyRead<Count)
645 const int total_timeout_ms,
647 const char *eol_chars)
657 if (out_timeout) *out_timeout =
false;
662 while (total_timeout_ms<0 || (
m_timer.
Tac()*1e3 < total_timeout_ms))
664 #ifdef MRPT_OS_WINDOWS
679 if (!strchr(eol_chars, buf[0]))
680 receivedStr.push_back(buf[0]);
691 int waiting_bytes = 0;
692 if (ioctl(
hCOM, FIONREAD, &waiting_bytes) < 0)
707 if ((nRead = ::read(
hCOM, buf, 1)) <0)
709 cerr <<
"[CSerialPort] Error reading from port..." << endl;
713 if (!strchr(eol_chars, buf[0]))
714 receivedStr.push_back(buf[0]);
732 if (out_timeout) *out_timeout =
true;
743 #ifdef MRPT_OS_WINDOWS
744 DWORD actuallyWritten;
752 return actuallyWritten;
759 int num_of_bytes_written = -1 ;
760 size_t total_bytes_written = 0;
763 gettimeofday(&
start, NULL);
764 num_of_bytes_written = write(
hCOM,
reinterpret_cast<const char*
>(Buffer)+total_bytes_written, Count-total_bytes_written );
766 if (num_of_bytes_written>0)
767 total_bytes_written+=num_of_bytes_written;
769 if (num_of_bytes_written<(
int)Count)
778 gettimeofday(&
end, NULL);
779 usecs= (
end.tv_sec -
start.tv_sec)*1000000 +
781 }
while (usecs < 60);
785 while ( ( total_bytes_written<Count) &&
786 ( !errno || EAGAIN == errno ) ) ;
788 if ( num_of_bytes_written < 0 )
796 return total_bytes_written;
809 #ifdef MRPT_OS_WINDOWS
810 if (!PurgeComm(
hCOM, PURGE_RXABORT | PURGE_RXCLEAR | PURGE_TXABORT | PURGE_TXCLEAR))
814 if ( tcflush(
hCOM,TCIFLUSH ) < 0 )
bool isOpen() const
Returns if port has been correctly open.
void open()
Open the port.
std::string ReadString(const int total_timeout_ms=-1, bool *out_timeout=NULL, const char *eol_chars="\r\n")
Reads one text line from the serial port in POSIX "canonical mode".
void setConfig(int baudRate, int parity=0, int bits=8, int nStopBits=1, bool enableFlowControl=false)
Changes the configuration of the port.
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.
std::string m_serialName
The complete name of the serial port device (i.e.
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.
int hCOM
The file handle (-1: Not open)
mrpt::utils::CTicTac m_timer
Used only in ReadString.
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.
int m_interBytesTimeout_ms
virtual ~CSerialPort()
Destructor.
double Tac()
Stops the stopwatch.
void Tic()
Starts the stopwatch.
GLsizei const GLchar ** string
void BASE_IMPEXP sleep(int time_ms) MRPT_NO_THROWS
An OS-independent method for sending the current thread to "sleep" for a given period of time.
#define THROW_EXCEPTION(msg)
#define THROW_EXCEPTION_FMT(_FORMAT_STRING,...)
Contains classes for various device interfaces.
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.