34#include "libserial/SerialPort.h"
46#include <linux/serial.h>
75 const BaudRate& baudRate,
76 const CharacterSize& characterSize,
77 const FlowControl& flowControlType,
78 const Parity& parityType,
79 const StopBits& stopBits) ;
114 void Open(const std::
string& fileName,
115 const std::ios_base::openmode& openMode) ;
199 void SetParity(const Parity& parityType) ;
223 void SetVMin(const
short vmin) ;
248 void SetDTR(const
bool dtrState) ;
260 void SetRTS(const
bool rtsState) ;
298 std::vector<std::string> GetAvailableSerialPorts()
const ;
316 void Read(DataBuffer& dataBuffer,
317 size_t numberOfBytes = 0,
318 size_t msTimeout = 0) ;
333 void Read(std::string& dataString,
334 size_t numberOfBytes = 0,
335 size_t msTimeout = 0) ;
346 template <
typename ByteType,
347 typename = std::enable_if_t<(
sizeof(ByteType) == 1)>>
349 size_t msTimeout = 0) ;
365 void ReadLine(std::string& dataString,
366 char lineTerminator =
'\n',
367 size_t msTimeout = 0) ;
373 void Write(
const DataBuffer& dataBuffer) ;
379 void Write(
const std::string& dataString) ;
391 void WriteByte(
unsigned char charBuffer) ;
431 int GetBitRate(
const BaudRate& baudRate)
const ;
436 void SetDefaultLinuxSpecificModes() ;
441 void SetDefaultInputModes() ;
446 void SetDefaultOutputModes() ;
451 void SetDefaultControlModes() ;
456 void SetDefaultLocalModes() ;
461 int mFileDescriptor = -1 ;
467 int mByteArrivalTimeDelta = 1 ;
474 termios mOldPortSettings {} ;
484 const BaudRate& baudRate,
485 const CharacterSize& characterSize,
486 const FlowControl& flowControlType,
487 const Parity& parityType,
488 const StopBits& stopBits)
500 mImpl(std::move(otherSerialPort.mImpl))
507 mImpl = std::move(otherSerialPort.mImpl);
515 const std::ios_base::openmode& openMode)
517 mImpl->
Open(fileName,
530 mImpl->DrainWriteBuffer() ;
536 mImpl->FlushInputBuffer() ;
542 mImpl->FlushOutputBuffer() ;
548 mImpl->FlushIOBuffers() ;
554 return mImpl->IsDataAvailable() ;
560 return mImpl->IsOpen() ;
566 mImpl->SetDefaultSerialPortParameters() ;
572 mImpl->SetBaudRate(baudRate) ;
578 return mImpl->GetBaudRate() ;
584 mImpl->SetCharacterSize(characterSize) ;
590 return mImpl->GetCharacterSize() ;
596 mImpl->SetFlowControl(flowControlType) ;
602 return mImpl->GetFlowControl() ;
608 mImpl->SetParity(parityType) ;
614 return mImpl->GetParity() ;
620 mImpl->SetStopBits(stopBits) ;
626 return mImpl->GetStopBits() ;
632 mImpl->SetVMin(vmin) ;
638 return mImpl->GetVMin() ;
644 mImpl->SetVTime(vtime) ;
650 return mImpl->GetVTime() ;
656 mImpl->SetDTR(dtrState) ;
662 return mImpl->GetDTR() ;
668 mImpl->SetRTS(rtsState) ;
674 return mImpl->GetRTS() ;
680 return mImpl->GetCTS() ;
686 return mImpl->GetDSR() ;
692 return mImpl->GetFileDescriptor() ;
698 return mImpl->GetNumberOfBytesAvailable() ;
702 std::vector<std::string>
703 SerialPort::GetAvailableSerialPorts()
const
705 return mImpl->GetAvailableSerialPorts() ;
711 const size_t numberOfBytes,
712 const size_t msTimeout)
714 mImpl->Read(dataBuffer,
721 const size_t numberOfBytes,
722 const size_t msTimeout)
724 mImpl->Read(dataString,
731 const size_t msTimeout)
733 mImpl->ReadByte(charBuffer,
739 const size_t msTimeout)
741 mImpl->ReadByte(charBuffer,
747 const char lineTerminator,
748 const size_t msTimeout)
750 mImpl->ReadLine(dataString,
758 mImpl->Write(dataBuffer) ;
764 mImpl->Write(dataString) ;
770 mImpl->WriteByte(charBuffer) ;
776 mImpl->WriteByte(charBuffer) ;
782 mImpl->SetSerialPortBlockingStatus(blockingStatus) ;
788 return mImpl->GetSerialPortBlockingStatus() ;
793 const bool lineState)
795 mImpl->SetModemControlLine(modemLine, lineState) ;
801 return mImpl->GetModemControlLine(modemLine) ;
808 const BaudRate& baudRate,
809 const CharacterSize& characterSize,
810 const FlowControl& flowControlType,
811 const Parity& parityType,
812 const StopBits& stopBits)
814 this->
Open(fileName, std::ios_base::in | std::ios_base::out) ;
846 const std::ios_base::openmode& openMode)
858 int flags = (O_NOCTTY | O_NONBLOCK) ;
860 if (openMode == (std::ios_base::in | std::ios_base::out))
864 else if (openMode == std::ios_base::in)
868 else if (openMode == std::ios_base::out)
874 throw OpenFailed {
"Invalid or unsupported open mode"} ;
879 mFileDescriptor = call_with_retry(open, fileName.c_str(), flags) ;
881 if (this->mFileDescriptor < 0)
888 if (call_with_retry(ioctl,
889 this->mFileDescriptor,
892 throw std::runtime_error(std::strerror(errno)) ;
897 if (tcgetattr(this->mFileDescriptor,
898 &mOldPortSettings) < 0)
917 throw NotOpen(ERR_MSG_PORT_NOT_OPEN) ;
930 std::string err_msg {} ;
931 if (tcsetattr(this->mFileDescriptor,
933 &mOldPortSettings) < 0)
935 err_msg = std::strerror(errno) ;
940 bool is_failed = false ;
941 if (call_with_retry(close, this->mFileDescriptor) < 0)
945 err_msg += std::strerror(errno) ;
949 mFileDescriptor = -1 ;
956 throw std::runtime_error(err_msg) ;
967 throw NotOpen(ERR_MSG_PORT_NOT_OPEN) ;
970 if (call_with_retry(tcdrain, this->mFileDescriptor) < 0)
972 throw std::runtime_error(std::strerror(errno)) ;
983 throw NotOpen(ERR_MSG_PORT_NOT_OPEN) ;
986 if (tcflush(this->mFileDescriptor, TCIFLUSH) < 0)
988 throw std::runtime_error(std::strerror(errno)) ;
999 throw NotOpen(ERR_MSG_PORT_NOT_OPEN) ;
1002 if (tcflush(this->mFileDescriptor, TCOFLUSH) < 0)
1004 throw std::runtime_error(std::strerror(errno)) ;
1015 throw NotOpen(ERR_MSG_PORT_NOT_OPEN) ;
1018 if (tcflush(this->mFileDescriptor, TCIOFLUSH) < 0)
1020 throw std::runtime_error(std::strerror(errno)) ;
1028 return (this->mFileDescriptor != -1) ;
1038 throw NotOpen(ERR_MSG_PORT_NOT_OPEN) ;
1041 int number_of_bytes_available = 0 ;
1042 bool is_data_available = false ;
1045 const auto ioctl_result = call_with_retry(ioctl,
1046 this->mFileDescriptor,
1048 &number_of_bytes_available) ;
1050 if ((ioctl_result >= 0) and
1051 (number_of_bytes_available > 0))
1053 is_data_available = true ;
1056 return is_data_available ;
1066 throw NotOpen(ERR_MSG_PORT_NOT_OPEN) ;
1070 SetDefaultLinuxSpecificModes() ;
1073 SetDefaultInputModes() ;
1074 SetDefaultOutputModes() ;
1075 SetDefaultControlModes() ;
1076 SetDefaultLocalModes() ;
1094 throw NotOpen(ERR_MSG_PORT_NOT_OPEN) ;
1098 termios port_settings {} ;
1099 std::memset(&port_settings, 0,
sizeof(port_settings)) ;
1101 if (tcgetattr(this->mFileDescriptor,
1102 &port_settings) < 0)
1104 throw std::runtime_error(std::strerror(errno)) ;
1108 if (0 != cfsetspeed(&port_settings,
static_cast<speed_t
>(baudRate)))
1111 throw std::runtime_error(ERR_MSG_INVALID_BAUD_RATE) ;
1115 if (tcsetattr(this->mFileDescriptor,
1117 &port_settings) < 0)
1120 throw std::runtime_error(std::strerror(errno)) ;
1124 mByteArrivalTimeDelta = (BITS_PER_BYTE * MICROSECONDS_PER_SEC) / GetBitRate(baudRate) ;
1134 throw NotOpen(ERR_MSG_PORT_NOT_OPEN) ;
1138 termios port_settings {} ;
1139 std::memset(&port_settings, 0,
sizeof(port_settings)) ;
1141 if (tcgetattr(this->mFileDescriptor,
1142 &port_settings) < 0)
1144 throw std::runtime_error(std::strerror(errno)) ;
1148 const auto input_baud = cfgetispeed(&port_settings) ;
1149 const auto output_baud = cfgetospeed(&port_settings) ;
1153 if (input_baud != output_baud)
1155 throw std::runtime_error(ERR_MSG_INVALID_BAUD_RATE) ;
1160 return BaudRate(input_baud) ;
1165 SerialPort::Implementation::GetBitRate(
const BaudRate& baudRate)
const
1167 int baud_rate_as_int = 1 ;
1171 case BaudRate::BAUD_50:
1172 baud_rate_as_int = 50 ;
1175 case BaudRate::BAUD_75:
1176 baud_rate_as_int = 75 ;
1179 case BaudRate::BAUD_110:
1180 baud_rate_as_int = 110 ;
1183 case BaudRate::BAUD_134:
1184 baud_rate_as_int = 134 ;
1187 case BaudRate::BAUD_150:
1188 baud_rate_as_int = 150 ;
1191 case BaudRate::BAUD_200:
1192 baud_rate_as_int = 200 ;
1195 case BaudRate::BAUD_300:
1196 baud_rate_as_int = 300 ;
1199 case BaudRate::BAUD_600:
1200 baud_rate_as_int = 600 ;
1203 case BaudRate::BAUD_1200:
1204 baud_rate_as_int = 1200 ;
1207 case BaudRate::BAUD_1800:
1208 baud_rate_as_int = 1800 ;
1211 case BaudRate::BAUD_2400:
1212 baud_rate_as_int = 2400 ;
1215 case BaudRate::BAUD_4800:
1216 baud_rate_as_int = 4800 ;
1219 case BaudRate::BAUD_9600:
1220 baud_rate_as_int = 9600 ;
1223 case BaudRate::BAUD_19200:
1224 baud_rate_as_int = 19200 ;
1227 case BaudRate::BAUD_38400:
1228 baud_rate_as_int = 38400 ;
1231 case BaudRate::BAUD_57600:
1232 baud_rate_as_int = 57600 ;
1235 case BaudRate::BAUD_115200:
1236 baud_rate_as_int = 115200 ;
1239 case BaudRate::BAUD_230400:
1240 baud_rate_as_int = 230400 ;
1245 case BaudRate::BAUD_460800:
1246 baud_rate_as_int = 460800 ;
1249 case BaudRate::BAUD_500000:
1250 baud_rate_as_int = 500000 ;
1253 case BaudRate::BAUD_576000:
1254 baud_rate_as_int = 576000 ;
1257 case BaudRate::BAUD_921600:
1258 baud_rate_as_int = 921600 ;
1261 case BaudRate::BAUD_1000000:
1262 baud_rate_as_int = 1000000 ;
1265 case BaudRate::BAUD_1152000:
1266 baud_rate_as_int = 1152000 ;
1269 case BaudRate::BAUD_1500000:
1270 baud_rate_as_int = 1500000 ;
1273#if __MAX_BAUD > B2000000
1274 case BaudRate::BAUD_2000000:
1275 baud_rate_as_int = 2000000 ;
1278 case BaudRate::BAUD_2500000:
1279 baud_rate_as_int = 2500000 ;
1282 case BaudRate::BAUD_3000000:
1283 baud_rate_as_int = 3000000 ;
1286 case BaudRate::BAUD_3500000:
1287 baud_rate_as_int = 3500000 ;
1290 case BaudRate::BAUD_4000000:
1291 baud_rate_as_int = 4000000 ;
1297 throw std::runtime_error(ERR_MSG_INVALID_BAUD_RATE) ;
1300 return baud_rate_as_int ;
1310 throw NotOpen(ERR_MSG_PORT_NOT_OPEN) ;
1314 termios port_settings {} ;
1315 std::memset(&port_settings, 0,
sizeof(port_settings)) ;
1317 if (tcgetattr(this->mFileDescriptor,
1318 &port_settings) < 0)
1320 throw std::runtime_error(ERR_MSG_INVALID_CHARACTER_SIZE) ;
1331 if (characterSize == CharacterSize::CHAR_SIZE_8)
1334 port_settings.c_iflag &= ~ISTRIP ;
1338 port_settings.c_iflag |= ISTRIP ;
1343 port_settings.c_cflag &= ~CSIZE ;
1344 port_settings.c_cflag |=
static_cast<tcflag_t
>(characterSize) ;
1347 if (tcsetattr(this->mFileDescriptor,
1349 &port_settings) < 0)
1351 throw std::runtime_error(std::strerror(errno)) ;
1362 throw NotOpen(ERR_MSG_PORT_NOT_OPEN) ;
1366 termios port_settings {} ;
1367 std::memset(&port_settings, 0,
sizeof(port_settings)) ;
1369 if (tcgetattr(this->mFileDescriptor,
1370 &port_settings) < 0)
1372 throw std::runtime_error(std::strerror(errno)) ;
1377 return CharacterSize(port_settings.c_cflag & CSIZE) ;
1387 throw NotOpen(ERR_MSG_PORT_NOT_OPEN) ;
1391 if (tcflush(this->mFileDescriptor,
1394 throw std::runtime_error(std::strerror(errno)) ;
1398 termios port_settings {} ;
1399 std::memset(&port_settings, 0,
sizeof(port_settings)) ;
1401 if (tcgetattr(this->mFileDescriptor,
1402 &port_settings) < 0)
1404 throw std::runtime_error(ERR_MSG_INVALID_FLOW_CONTROL) ;
1410 switch(flowControlType)
1412 case FlowControl::FLOW_CONTROL_HARDWARE:
1413 port_settings.c_iflag &= ~ (IXON|IXOFF) ;
1414 port_settings.c_cflag |= CRTSCTS ;
1415 port_settings.c_cc[VSTART] = _POSIX_VDISABLE ;
1416 port_settings.c_cc[VSTOP] = _POSIX_VDISABLE ;
1418 case FlowControl::FLOW_CONTROL_SOFTWARE:
1419 port_settings.c_iflag |= IXON|IXOFF ;
1420 port_settings.c_cflag &= ~CRTSCTS ;
1421 port_settings.c_cc[VSTART] = CTRL_Q ;
1422 port_settings.c_cc[VSTOP] = CTRL_S ;
1424 case FlowControl::FLOW_CONTROL_NONE:
1425 port_settings.c_iflag &= ~(IXON|IXOFF) ;
1426 port_settings.c_cflag &= ~CRTSCTS ;
1429 throw std::invalid_argument(ERR_MSG_INVALID_FLOW_CONTROL) ;
1434 if (tcsetattr(this->mFileDescriptor,
1436 &port_settings) < 0)
1438 throw std::runtime_error(std::strerror(errno)) ;
1449 throw NotOpen(ERR_MSG_PORT_NOT_OPEN) ;
1453 termios port_settings {} ;
1454 std::memset(&port_settings, 0,
sizeof(port_settings)) ;
1456 if (tcgetattr(this->mFileDescriptor,
1457 &port_settings) < 0)
1459 throw std::runtime_error(std::strerror(errno)) ;
1465 if ((port_settings.c_iflag & IXON) and
1466 (port_settings.c_iflag & IXOFF) and
1467 (CTRL_Q == port_settings.c_cc[VSTART]) and
1468 (CTRL_S == port_settings.c_cc[VSTOP]))
1470 return FlowControl::FLOW_CONTROL_SOFTWARE ;
1473 if (not ((port_settings.c_iflag & IXON) or
1474 (port_settings.c_iflag & IXOFF)))
1476 if (0 != (port_settings.c_cflag & CRTSCTS))
1480 return FlowControl::FLOW_CONTROL_HARDWARE ;
1482 return FlowControl::FLOW_CONTROL_NONE ;
1487 return FlowControl::FLOW_CONTROL_INVALID ;
1497 throw NotOpen(ERR_MSG_PORT_NOT_OPEN) ;
1501 termios port_settings {} ;
1502 std::memset(&port_settings, 0,
sizeof(port_settings)) ;
1504 if (tcgetattr(this->mFileDescriptor,
1505 &port_settings) < 0)
1507 throw std::runtime_error(std::strerror(errno)) ;
1513 case Parity::PARITY_EVEN:
1514 port_settings.c_cflag |= PARENB ;
1515 port_settings.c_cflag &= ~PARODD ;
1516 port_settings.c_iflag |= INPCK ;
1518 case Parity::PARITY_ODD:
1519 port_settings.c_cflag |= PARENB ;
1520 port_settings.c_cflag |= PARODD ;
1521 port_settings.c_iflag |= INPCK ;
1523 case Parity::PARITY_NONE:
1524 port_settings.c_cflag &= ~PARENB ;
1525 port_settings.c_iflag |= IGNPAR ;
1528 throw std::invalid_argument(ERR_MSG_INVALID_PARITY) ;
1533 if (tcsetattr(this->mFileDescriptor,
1535 &port_settings) < 0)
1537 throw std::runtime_error(std::strerror(errno)) ;
1548 throw NotOpen(ERR_MSG_PORT_NOT_OPEN) ;
1552 termios port_settings {} ;
1553 std::memset(&port_settings, 0,
sizeof(port_settings)) ;
1555 if (tcgetattr(this->mFileDescriptor,
1556 &port_settings) < 0)
1558 throw std::runtime_error(std::strerror(errno)) ;
1562 if (0 != (port_settings.c_cflag & PARENB))
1565 if (port_settings.c_cflag & PARODD)
1567 return Parity::PARITY_ODD ;
1569 return Parity::PARITY_EVEN ;
1571 return Parity::PARITY_NONE ;
1581 throw NotOpen(ERR_MSG_PORT_NOT_OPEN) ;
1585 termios port_settings {} ;
1586 std::memset(&port_settings, 0,
sizeof(port_settings)) ;
1588 if (tcgetattr(this->mFileDescriptor,
1589 &port_settings) < 0)
1591 throw std::runtime_error(std::strerror(errno)) ;
1597 case StopBits::STOP_BITS_1:
1598 port_settings.c_cflag &= ~CSTOPB ;
1600 case StopBits::STOP_BITS_2:
1601 port_settings.c_cflag |= CSTOPB ;
1604 throw std::invalid_argument(ERR_MSG_INVALID_STOP_BITS) ;
1609 if (tcsetattr(this->mFileDescriptor,
1611 &port_settings) < 0)
1613 throw std::runtime_error(std::strerror(errno)) ;
1624 throw NotOpen(ERR_MSG_PORT_NOT_OPEN) ;
1628 termios port_settings {} ;
1629 std::memset(&port_settings, 0,
sizeof(port_settings)) ;
1631 if (tcgetattr(this->mFileDescriptor,
1632 &port_settings) < 0)
1634 throw std::runtime_error(std::strerror(errno)) ;
1639 if (port_settings.c_cflag & CSTOPB)
1641 return StopBits::STOP_BITS_2 ;
1643 return StopBits::STOP_BITS_1 ;
1653 throw NotOpen(ERR_MSG_PORT_NOT_OPEN) ;
1656 if (vmin < 0 || vmin > 255)
1658 std::stringstream error_message ;
1659 error_message <<
"Invalid vmin value: " << vmin <<
". " ;
1660 error_message <<
"Vmin must be in the range [0, 255]." ;
1661 throw std::invalid_argument {error_message.str()} ;
1665 termios port_settings {} ;
1666 std::memset(&port_settings, 0,
sizeof(port_settings)) ;
1668 if (tcgetattr(this->mFileDescriptor,
1669 &port_settings) < 0)
1671 throw std::runtime_error(std::strerror(errno)) ;
1674 port_settings.c_cc[VMIN] =
static_cast<cc_t
>(vmin) ;
1677 if (tcsetattr(this->mFileDescriptor,
1679 &port_settings) < 0)
1681 throw std::runtime_error(std::strerror(errno)) ;
1692 throw NotOpen(ERR_MSG_PORT_NOT_OPEN) ;
1696 termios port_settings {} ;
1697 std::memset(&port_settings, 0,
sizeof(port_settings)) ;
1699 if (tcgetattr(this->mFileDescriptor,
1700 &port_settings) < 0)
1702 throw std::runtime_error(std::strerror(errno)) ;
1705 return port_settings.c_cc[VMIN] ;
1715 throw NotOpen(ERR_MSG_PORT_NOT_OPEN) ;
1718 if (vtime < 0 || vtime > 255)
1720 std::stringstream error_message ;
1721 error_message <<
"Invalid vtime value: " << vtime <<
". " ;
1722 error_message <<
"Vtime must be in the range [0, 255]." ;
1723 throw std::invalid_argument {error_message.str()} ;
1727 termios port_settings {} ;
1728 std::memset(&port_settings, 0,
sizeof(port_settings)) ;
1730 if (tcgetattr(this->mFileDescriptor,
1731 &port_settings) < 0)
1733 throw std::runtime_error(std::strerror(errno)) ;
1736 port_settings.c_cc[VTIME] =
static_cast<cc_t
>(vtime) ;
1739 if (tcsetattr(this->mFileDescriptor,
1741 &port_settings) < 0)
1743 throw std::runtime_error(std::strerror(errno)) ;
1754 throw NotOpen(ERR_MSG_PORT_NOT_OPEN) ;
1758 termios port_settings {} ;
1759 std::memset(&port_settings, 0,
sizeof(port_settings)) ;
1761 if (tcgetattr(this->mFileDescriptor,
1762 &port_settings) < 0)
1764 throw std::runtime_error(std::strerror(errno)) ;
1767 return port_settings.c_cc[VTIME] ;
1777 throw NotOpen(ERR_MSG_PORT_NOT_OPEN) ;
1791 throw NotOpen(ERR_MSG_PORT_NOT_OPEN) ;
1804 throw NotOpen(ERR_MSG_PORT_NOT_OPEN) ;
1818 throw NotOpen(ERR_MSG_PORT_NOT_OPEN) ;
1831 throw NotOpen(ERR_MSG_PORT_NOT_OPEN) ;
1844 throw NotOpen(ERR_MSG_PORT_NOT_OPEN) ;
1857 throw NotOpen(ERR_MSG_PORT_NOT_OPEN) ;
1860 return this->mFileDescriptor ;
1870 throw NotOpen(ERR_MSG_PORT_NOT_OPEN) ;
1873 int number_of_bytes_available = 0 ;
1876 if (call_with_retry(ioctl,
1877 this->mFileDescriptor,
1879 &number_of_bytes_available) < 0)
1881 throw std::runtime_error(std::strerror(errno)) ;
1884 return number_of_bytes_available ;
1889 std::vector<std::string>
1890 SerialPort::Implementation::GetAvailableSerialPorts()
const
1892 constexpr int array_size = 3 ;
1893 constexpr size_t max_port_number = 128 ;
1895 std::string serial_ports[array_size] = {
"/dev/ttyS",
1899 std::vector<std::string> serial_port_names {} ;
1900 for (
const auto& port_prefix: serial_ports)
1902 for (
size_t j = 0 ;j < max_port_number;j++)
1904 const auto file_name = port_prefix + std::to_string(j) ;
1907 const auto file_desc = call_with_retry(open,
1909 O_RDWR | O_NOCTTY | O_NONBLOCK) ;
1913 serial_struct serial_port_info {} ;
1915 if (call_with_retry(ioctl,
1918 &serial_port_info) == -1)
1920 throw std::runtime_error(std::strerror(errno)) ;
1923 serial_port_names.push_back(file_name) ;
1930 return serial_port_names ;
1937 const bool lineState)
1942 throw NotOpen(ERR_MSG_PORT_NOT_OPEN) ;
1945 if (modemLine != TIOCM_LE &&
1946 modemLine != TIOCM_DTR &&
1947 modemLine != TIOCM_RTS &&
1948 modemLine != TIOCM_ST &&
1949 modemLine != TIOCM_SR &&
1950 modemLine != TIOCM_CTS &&
1951 modemLine != TIOCM_CAR &&
1952 modemLine != TIOCM_CD &&
1953 modemLine != TIOCM_RNG &&
1954 modemLine != TIOCM_RI &&
1955 modemLine != TIOCM_DSR)
1957 throw std::invalid_argument {ERR_MSG_INVALID_MODEM_LINE} ;
1961 int ioctl_result = -1 ;
1965 int set_line_mask = modemLine ;
1967 ioctl_result = call_with_retry(ioctl,
1968 this->mFileDescriptor,
1974 int reset_line_mask = modemLine ;
1976 ioctl_result = call_with_retry(ioctl,
1977 this->mFileDescriptor,
1983 if (ioctl_result < 0)
1985 throw std::runtime_error(std::strerror(errno)) ;
1996 throw NotOpen(ERR_MSG_PORT_NOT_OPEN) ;
1999 if (modemLine != TIOCM_LE &&
2000 modemLine != TIOCM_DTR &&
2001 modemLine != TIOCM_RTS &&
2002 modemLine != TIOCM_ST &&
2003 modemLine != TIOCM_SR &&
2004 modemLine != TIOCM_CTS &&
2005 modemLine != TIOCM_CAR &&
2006 modemLine != TIOCM_CD &&
2007 modemLine != TIOCM_RNG &&
2008 modemLine != TIOCM_RI &&
2009 modemLine != TIOCM_DSR)
2011 throw std::invalid_argument {ERR_MSG_INVALID_MODEM_LINE} ;
2015 int serial_port_state = 0 ;
2018 if (call_with_retry(ioctl,
2019 this->mFileDescriptor,
2021 &serial_port_state) < 0)
2023 throw std::runtime_error(std::strerror(errno)) ;
2026 return (0 != (serial_port_state & modemLine)) ;
2036 throw NotOpen(ERR_MSG_PORT_NOT_OPEN) ;
2039 int flags = fcntl(this->mFileDescriptor, F_GETFL, 0) ;
2044 if (fcntl(this->mFileDescriptor,
2046 flags &~ O_NONBLOCK) < 0)
2048 throw std::runtime_error(std::strerror(errno)) ;
2054 if (fcntl(this->mFileDescriptor,
2056 flags | O_NONBLOCK) < 0)
2058 throw std::runtime_error(std::strerror(errno)) ;
2070 throw NotOpen(ERR_MSG_PORT_NOT_OPEN) ;
2073 bool blocking_status = false ;
2075 const int flags = fcntl(this->mFileDescriptor, F_GETFL, 0) ;
2079 throw std::runtime_error(std::strerror(errno)) ;
2082 if (flags == (flags | O_NONBLOCK))
2084 blocking_status = true ;
2087 return blocking_status ;
2092 SerialPort::Implementation::SetDefaultLinuxSpecificModes()
2097 throw NotOpen(ERR_MSG_PORT_NOT_OPEN) ;
2101 termios port_settings {} ;
2102 std::memset(&port_settings, 0,
sizeof(port_settings)) ;
2104 if (tcgetattr(this->mFileDescriptor,
2105 &port_settings) < 0)
2107 throw std::runtime_error(std::strerror(errno)) ;
2113 port_settings.c_line =
'\0' ;
2117 if (tcsetattr(this->mFileDescriptor,
2119 &port_settings) < 0)
2121 throw std::runtime_error(std::strerror(errno)) ;
2127 SerialPort::Implementation::SetDefaultInputModes()
2132 throw NotOpen(ERR_MSG_PORT_NOT_OPEN) ;
2136 termios port_settings {} ;
2137 std::memset(&port_settings, 0,
sizeof(port_settings)) ;
2139 if (tcgetattr(this->mFileDescriptor,
2140 &port_settings) < 0)
2142 throw std::runtime_error(std::strerror(errno)) ;
2146 port_settings.c_iflag = IGNBRK ;
2149 if (tcsetattr(this->mFileDescriptor,
2151 &port_settings) < 0)
2153 throw std::runtime_error(std::strerror(errno)) ;
2159 SerialPort::Implementation::SetDefaultOutputModes()
2164 throw NotOpen(ERR_MSG_PORT_NOT_OPEN) ;
2168 termios port_settings {} ;
2169 std::memset(&port_settings, 0,
sizeof(port_settings)) ;
2171 if (tcgetattr(this->mFileDescriptor,
2172 &port_settings) < 0)
2174 throw std::runtime_error(std::strerror(errno)) ;
2177 port_settings.c_oflag = 0 ;
2180 if (tcsetattr(this->mFileDescriptor,
2182 &port_settings) < 0)
2184 throw std::runtime_error(std::strerror(errno)) ;
2190 SerialPort::Implementation::SetDefaultControlModes()
2195 throw NotOpen(ERR_MSG_PORT_NOT_OPEN) ;
2199 termios port_settings {} ;
2200 std::memset(&port_settings, 0,
sizeof(port_settings)) ;
2202 if (tcgetattr(this->mFileDescriptor,
2203 &port_settings) < 0)
2205 throw std::runtime_error(std::strerror(errno)) ;
2209 port_settings.c_cflag |= CREAD | CLOCAL ;
2212 if (tcsetattr(this->mFileDescriptor,
2214 &port_settings) < 0)
2216 throw std::runtime_error(std::strerror(errno)) ;
2222 SerialPort::Implementation::SetDefaultLocalModes()
2227 throw NotOpen(ERR_MSG_PORT_NOT_OPEN) ;
2231 termios port_settings {} ;
2232 std::memset(&port_settings, 0,
sizeof(port_settings)) ;
2234 if (tcgetattr(this->mFileDescriptor,
2235 &port_settings) < 0)
2237 throw std::runtime_error(std::strerror(errno)) ;
2240 port_settings.c_lflag = 0 ;
2243 if (tcsetattr(this->mFileDescriptor,
2245 &port_settings) < 0)
2247 throw std::runtime_error(std::strerror(errno)) ;
2254 const size_t numberOfBytes,
2255 const size_t msTimeout)
2260 throw NotOpen(ERR_MSG_PORT_NOT_OPEN) ;
2263 if ((numberOfBytes == 0) and
2270 size_t number_of_bytes_read = 0 ;
2271 size_t number_of_bytes_remaining = std::max(numberOfBytes,
static_cast<size_t>(1)) ;
2272 size_t maximum_number_of_bytes = dataBuffer.max_size() ;
2275 dataBuffer.clear() ;
2276 dataBuffer.resize(number_of_bytes_remaining) ;
2279 const auto entry_time = std::chrono::high_resolution_clock::now().time_since_epoch() ;
2281 while (number_of_bytes_remaining > 0)
2284 if (number_of_bytes_remaining >= maximum_number_of_bytes - number_of_bytes_read)
2289 if (numberOfBytes == 0)
2292 dataBuffer.resize(number_of_bytes_read + 1) ;
2295 const auto read_result = call_with_retry(read,
2296 this->mFileDescriptor,
2297 &dataBuffer[number_of_bytes_read],
2298 number_of_bytes_remaining) ;
2300 if (read_result > 0)
2302 number_of_bytes_read += read_result ;
2304 if (numberOfBytes != 0)
2306 number_of_bytes_remaining = numberOfBytes - number_of_bytes_read ;
2308 if (number_of_bytes_remaining == 0)
2314 else if ((read_result <= 0) and
2315 (errno != EWOULDBLOCK))
2317 throw std::runtime_error(std::strerror(errno)) ;
2321 const auto current_time = std::chrono::high_resolution_clock::now().time_since_epoch() ;
2324 const auto elapsed_time = current_time - entry_time ;
2327 const auto elapsed_ms = std::chrono::duration_cast<std::chrono::milliseconds>(elapsed_time).count() ;
2331 if ((msTimeout > 0) and
2332 (
static_cast<size_t>(elapsed_ms) > msTimeout))
2335 dataBuffer.resize(number_of_bytes_read) ;
2341 usleep(mByteArrivalTimeDelta) ;
2348 const size_t numberOfBytes,
2349 const size_t msTimeout)
2354 throw NotOpen(ERR_MSG_PORT_NOT_OPEN) ;
2357 if ((numberOfBytes == 0) and
2364 size_t number_of_bytes_read = 0 ;
2365 size_t number_of_bytes_remaining = std::max(numberOfBytes,
static_cast<size_t>(1)) ;
2366 size_t maximum_number_of_bytes = dataString.max_size() ;
2369 dataString.clear() ;
2370 dataString.resize(number_of_bytes_remaining) ;
2373 const auto entry_time = std::chrono::high_resolution_clock::now().time_since_epoch() ;
2375 while (number_of_bytes_remaining > 0)
2378 if (number_of_bytes_remaining >= maximum_number_of_bytes - number_of_bytes_read)
2383 if (numberOfBytes == 0)
2386 dataString.resize(number_of_bytes_read + 1) ;
2389 const auto read_result = call_with_retry(read,
2390 this->mFileDescriptor,
2391 &dataString[number_of_bytes_read],
2392 number_of_bytes_remaining) ;
2394 if (read_result > 0)
2396 number_of_bytes_read += read_result ;
2398 if (numberOfBytes != 0)
2400 number_of_bytes_remaining = numberOfBytes - number_of_bytes_read ;
2402 if (number_of_bytes_remaining == 0)
2408 else if (read_result <= 0 &&
2409 errno != EWOULDBLOCK)
2411 throw std::runtime_error(std::strerror(errno)) ;
2415 const auto current_time = std::chrono::high_resolution_clock::now().time_since_epoch() ;
2418 const auto elapsed_time = current_time - entry_time ;
2421 const auto elapsed_ms = std::chrono::duration_cast<std::chrono::milliseconds>(elapsed_time).count() ;
2425 if ((msTimeout > 0) and
2426 (
static_cast<size_t>(elapsed_ms) > msTimeout))
2429 dataString.resize(number_of_bytes_read) ;
2435 usleep(mByteArrivalTimeDelta) ;
2439 template <
typename ByteType,
typename >
2443 const size_t msTimeout)
2446 static_assert(
sizeof(ByteType) == 1,
2447 "ByteType must have a size of exactly one byte.") ;
2452 throw NotOpen(ERR_MSG_PORT_NOT_OPEN) ;
2456 const auto entry_time = std::chrono::high_resolution_clock::now().time_since_epoch() ;
2460 ssize_t read_result = 0 ;
2461 while (read_result < 1)
2463 read_result = call_with_retry(read,
2464 this->mFileDescriptor,
2469 if (read_result ==
sizeof(ByteType))
2474 if ((read_result <= 0) and
2475 (errno != EWOULDBLOCK))
2477 throw std::runtime_error(std::strerror(errno)) ;
2481 const auto current_time = std::chrono::high_resolution_clock::now().time_since_epoch() ;
2484 const auto elapsed_time = current_time - entry_time ;
2487 const auto elapsed_ms = std::chrono::duration_cast<std::chrono::milliseconds>(elapsed_time).count() ;
2491 if ((msTimeout > 0) and
2492 (
static_cast<size_t>(elapsed_ms) > msTimeout))
2498 usleep(mByteArrivalTimeDelta) ;
2505 const char lineTerminator,
2506 const size_t msTimeout)
2511 throw NotOpen(ERR_MSG_PORT_NOT_OPEN) ;
2515 dataString.clear() ;
2517 unsigned char next_char = 0 ;
2519 size_t elapsed_ms = 0 ;
2521 ssize_t remaining_ms = 0 ;
2523 std::chrono::high_resolution_clock::duration entry_time ;
2524 std::chrono::high_resolution_clock::duration current_time ;
2525 std::chrono::high_resolution_clock::duration elapsed_time ;
2528 entry_time = std::chrono::high_resolution_clock::now().time_since_epoch() ;
2530 while (next_char != lineTerminator)
2533 current_time = std::chrono::high_resolution_clock::now().time_since_epoch() ;
2536 elapsed_time = current_time - entry_time ;
2539 elapsed_ms = std::chrono::duration_cast<std::chrono::milliseconds>(elapsed_time).count() ;
2543 if (msTimeout > 0 &&
2544 elapsed_ms > msTimeout)
2549 remaining_ms = msTimeout - elapsed_ms ;
2554 dataString += next_char ;
2565 throw NotOpen(ERR_MSG_PORT_NOT_OPEN) ;
2568 size_t number_of_bytes = dataBuffer.size() ;
2571 if (number_of_bytes <= 0)
2577 size_t number_of_bytes_written = 0 ;
2578 size_t number_of_bytes_remaining = number_of_bytes ;
2582 ssize_t write_result = 0 ;
2584 while (number_of_bytes_remaining > 0)
2586 write_result = call_with_retry(write,
2587 this->mFileDescriptor,
2588 &dataBuffer[number_of_bytes_written],
2589 number_of_bytes_remaining) ;
2591 if (write_result >= 0)
2593 number_of_bytes_written += write_result ;
2594 number_of_bytes_remaining = number_of_bytes - number_of_bytes_written ;
2596 if (number_of_bytes_remaining == 0)
2601 else if (write_result <= 0 &&
2602 errno != EWOULDBLOCK)
2604 throw std::runtime_error(std::strerror(errno)) ;
2616 throw NotOpen(ERR_MSG_PORT_NOT_OPEN) ;
2619 size_t number_of_bytes = dataString.size() ;
2622 if (number_of_bytes <= 0)
2628 size_t number_of_bytes_written = 0 ;
2629 size_t number_of_bytes_remaining = number_of_bytes ;
2633 ssize_t write_result = 0 ;
2635 while (number_of_bytes_remaining > 0)
2637 write_result = call_with_retry(write,
2638 this->mFileDescriptor,
2639 &dataString[number_of_bytes_written],
2640 number_of_bytes_remaining) ;
2642 if (write_result >= 0)
2644 number_of_bytes_written += write_result ;
2645 number_of_bytes_remaining = number_of_bytes - number_of_bytes_written ;
2647 if (number_of_bytes_remaining == 0)
2652 else if (write_result <= 0 &&
2653 errno != EWOULDBLOCK)
2655 throw std::runtime_error(std::strerror(errno)) ;
2667 throw NotOpen(ERR_MSG_PORT_NOT_OPEN) ;
2672 ssize_t write_result = 0 ;
2674 while (write_result <= 0)
2676 write_result = call_with_retry(write,
2677 this->mFileDescriptor,
2681 if (write_result == 1)
2686 if ((write_result <= 0) and
2687 (errno != EWOULDBLOCK))
2689 throw std::runtime_error(std::strerror(errno)) ;
2701 throw NotOpen(ERR_MSG_PORT_NOT_OPEN) ;
2706 ssize_t write_result = 0 ;
2708 while (write_result <= 0)
2710 write_result = call_with_retry(write,
2711 this->mFileDescriptor,
2715 if (write_result == 1)
2720 if ((write_result <= 0) and
2721 (errno != EWOULDBLOCK))
2723 throw std::runtime_error(std::strerror(errno)) ;
Exception error thrown when the serial port is already open.
Exception error thrown when the serial port is not open.
Exception error thrown when the serial port could not be opened.
Exception error thrown when data could not be read from the serial port before the timeout had been e...
SerialPort::Implementation is the SerialPort implementation class.
void SetCharacterSize(const CharacterSize &characterSize)
Sets the character size for the serial port.
void SetSerialPortBlockingStatus(bool blockingStatus)
Sets the current state of the serial port blocking status.
~Implementation() noexcept
Default Destructor for a SerialPort object. Closes the serial port associated with mFileDescriptor if...
bool GetDTR()
Gets the serial port DTR line status.
void SetVMin(const short vmin)
Sets the minimum number of characters for non-canonical reads.
void WriteByte(char charBuffer)
Writes a single byte to the serial port.
void ReadLine(std::string &dataString, char lineTerminator='\n', size_t msTimeout=0)
Reads a line of characters from the serial port. The method will timeout if no data is received in th...
void SetDefaultSerialPortParameters()
Sets all serial port paramters to their default values.
void Close()
Closes the serial port. All settings of the serial port will be lost and no more I/O can be performed...
CharacterSize GetCharacterSize() const
Gets the character size being used for serial communication.
int GetFileDescriptor() const
Gets the serial port file descriptor.
bool GetCTS()
Gets the serial port CTS line status.
void DrainWriteBuffer()
Waits until the write buffer is drained and then returns.
void SetVTime(const short vtime)
Sets character buffer timeout for non-canonical reads in deciseconds.
Parity GetParity() const
Gets the parity type for the serial port.
bool GetSerialPortBlockingStatus() const
Gets the current state of the serial port blocking status.
FlowControl GetFlowControl() const
Get the current flow control setting.
bool GetRTS()
Gets the serial port RTS line status.
void SetParity(const Parity &parityType)
Sets the parity type for the serial port.
bool IsOpen() const
Determines if the serial port is open for I/O.
void SetStopBits(const StopBits &stopBits)
Sets the number of stop bits to be used with the serial port.
void Write(const DataBuffer &dataBuffer)
Writes a DataBuffer to the serial port.
StopBits GetStopBits() const
Gets the number of stop bits currently being used by the serial.
void SetBaudRate(const BaudRate &baudRate)
Sets the baud rate for the serial port to the specified value.
bool GetModemControlLine(int modemLine)
Get the current state of the specified modem control line.
void FlushOutputBuffer()
Flushes the serial port output buffer.
void SetRTS(const bool rtsState)
Sets the serial port RTS line status.
BaudRate GetBaudRate() const
Gets the current baud rate for the serial port.
void SetModemControlLine(int modemLine, bool lineState)
Set the specified modem control line to the specified value.
void Open(const std::string &fileName, const std::ios_base::openmode &openMode)
Opens the serial port associated with the specified file name and the specified mode.
bool IsDataAvailable()
Determines if data is available at the serial port.
void FlushInputBuffer()
Flushes the serial port input buffer.
void SetDTR(const bool dtrState)
Sets the serial port DTR line status.
void ReadByte(ByteType &charBuffer, size_t msTimeout=0)
Reads a single byte from the serial port. If no data is available within the specified number of mill...
short GetVTime() const
Gets the current timeout value for non-canonical reads in deciseconds.
void Read(DataBuffer &dataBuffer, size_t numberOfBytes=0, size_t msTimeout=0)
Reads the specified number of bytes from the serial port. The method will timeout if no data is recei...
void SetFlowControl(const FlowControl &flowControlType)
Sets flow control for the serial port.
void FlushIOBuffers()
Flushes the serial port input and output buffers.
Implementation()=default
Default Constructor.
int GetNumberOfBytesAvailable()
Gets the number of bytes available in the read buffer.
short GetVMin() const
Gets the VMIN value for the device, which represents the minimum number of characters for non-canonic...
bool GetDSR()
Gets the serial port DSR line status.
SerialPort allows an object oriented approach to serial port communication. A serial port object can ...
void SetBaudRate(const BaudRate &baudRate)
Sets the baud rate for the serial port to the specified value.
void SetModemControlLine(int modemLine, bool lineState)
Set the specified modem control line to the specified value.
void SetParity(const Parity &parityType)
Sets the parity type for the serial port.
void Open(const std::string &fileName, const std::ios_base::openmode &openMode=std::ios_base::in|std::ios_base::out)
Opens the serial port associated with the specified file name and the specified mode.
bool GetCTS()
Get the status of the CTS line.
bool GetSerialPortBlockingStatus() const
Gets the current state of the serial port blocking status.
void WriteByte(char charbuffer)
Writes a single byte to the serial port.
void FlushInputBuffer()
Flushes the serial port input buffer.
void SetFlowControl(const FlowControl &flowControlType)
Sets flow control for the serial port.
void SetDefaultSerialPortParameters()
Sets all serial port paramters to their default values.
SerialPort()
Default Constructor.
FlowControl GetFlowControl() const
Gets the current flow control setting.
CharacterSize GetCharacterSize() const
Gets the character size being used for serial communication.
void Write(const DataBuffer &dataBuffer)
Writes a DataBuffer to the serial port.
bool GetDTR() const
Gets the status of the DTR line.
void SetRTS(const bool rtsState=true)
Set the RTS line to the specified value.
void SetVMin(const short vmin)
Sets the minimum number of characters for non-canonical reads.
virtual ~SerialPort() noexcept
Default Destructor for a SerialPort object. Closes the serial port associated with mFileDescriptor if...
StopBits GetStopBits() const
Gets the number of stop bits currently being used by the serial.
bool GetRTS() const
Get the status of the RTS line.
void Close()
Closes the serial port. All settings of the serial port will be lost and no more I/O can be performed...
SerialPort & operator=(const SerialPort &otherSerialPort)=delete
Copy assignment is disallowed.
void SetCharacterSize(const CharacterSize &characterSize)
Sets the character size for the serial port.
bool IsDataAvailable()
Checks if data is available at the input of the serial port.
BaudRate GetBaudRate() const
Gets the current baud rate for the serial port.
void SetVTime(const short vtime)
Sets character buffer timeout for non-canonical reads in deciseconds.
void FlushIOBuffers()
Flushes the serial port input and output buffers.
void FlushOutputBuffer()
Flushes the serial port output buffer.
Parity GetParity() const
Gets the parity type for the serial port.
short GetVMin() const
Gets the VMIN value for the device, which represents the minimum number of characters for non-canonic...
bool GetModemControlLine(int modemLine)
Get the current state of the specified modem control line.
short GetVTime() const
Gets the current timeout value for non-canonical reads in deciseconds.
void Read(DataBuffer &dataBuffer, size_t numberOfBytes=0, size_t msTimeout=0)
Reads the specified number of bytes from the serial port. The method will timeout if no data is recei...
bool GetDSR()
Get the status of the DSR line.
void ReadByte(char &charBuffer, size_t msTimeout=0)
Reads a single byte from the serial port. If no data is available within the specified number of mill...
int GetNumberOfBytesAvailable()
Gets the number of bytes available in the read buffer.
int GetFileDescriptor() const
Gets the serial port file descriptor.
void SetDTR(const bool dtrState=true)
Sets the DTR line to the specified value.
void ReadLine(std::string &dataString, char lineTerminator='\n', size_t msTimeout=0)
Reads a line of characters from the serial port. The method will timeout if no data is received in th...
void DrainWriteBuffer()
Waits until the write buffer is drained and then returns.
bool IsOpen() const
Determines if the serial port is open for I/O.
void SetSerialPortBlockingStatus(bool blockingStatus)
Sets the current state of the serial port blocking status.
void SetStopBits(const StopBits &stopBits)
Sets the number of stop bits to be used with the serial port.