/* ******************************************************************************* * INCLUDE ******************************************************************************* */ #include "SerialPort.h" #include #include #include #include #include #include namespace Hardware { /* ******************************************************************************* * CLASS DEFINE ******************************************************************************* */ SerialPort::SerialPort(): _fd(-1) { } SerialPort::~SerialPort() { if (isOpen()) close(); } void SerialPort::open() { if (isOpen()) return; if (_path.empty()) throw Poco::InvalidArgumentException("Empty path"); struct termios options = {0}; options.c_cflag |= CLOCAL | getBaudRateFlag(_baudRate); switch (_dataBits) { case 5: options.c_cflag |= CS5; break; case 6: options.c_cflag |= CS6; break; case 7: options.c_cflag |= CS7; break; case 8: options.c_cflag |= CS8; break; default: throw Poco::InvalidArgumentException(Poco::format("Invalid data bits: %d", _dataBits)); } switch (_stopBits) { case 1: options.c_cflag &= ~CSTOPB; break; case 2: options.c_cflag |= CSTOPB; break; default: case 3: case 4: throw Poco::InvalidArgumentException(Poco::format("Invalid stop bits: %d", _stopBits)); } switch (_parity) { default: case Parity::NONE: options.c_cflag &= ~PARENB; options.c_iflag &= ~INPCK; break; case Parity::ODD: options.c_cflag |= PARENB; options.c_cflag |= PARODD; options.c_iflag |= INPCK; options.c_iflag |= ISTRIP; break; case Parity::EVEN: options.c_cflag |= PARENB; options.c_cflag &= ~PARODD; options.c_iflag |= INPCK; options.c_iflag |= ISTRIP; break; } options.c_cflag |= CREAD; switch (_flowControl) { default: case FlowControl::NONE: options.c_cflag &= ~CRTSCTS; break; case FlowControl::RTSCTS: options.c_cflag |= CRTSCTS; break; } _fd = ::open(_path.c_str(), O_RDWR | O_NOCTTY | O_NONBLOCK); if (_fd < 0) throw Poco::InvalidAccessException(Poco::format("Open '%s' FAIL: %d", _path, _fd)); tcflush(_fd, TCIOFLUSH); cfmakeraw(&options); tcsetattr(_fd, TCSANOW, &options); } void SerialPort::close() { if (!isOpen()) return; ::close(_fd); _fd = -1; } bool SerialPort::isOpen() { return _fd != -1; } int SerialPort::write(const void* pData, uint32_t size) { if (!isOpen()) return 0; return ::write(_fd, pData, size); } int SerialPort::read(void* pBuffer, uint32_t length, uint32_t timeout) { if (!isOpen()) return 0; struct timeval tm; tm.tv_sec = timeout / 1000; tm.tv_usec = (timeout % 1000) * 1000; fd_set reads; FD_ZERO(&reads); FD_SET(_fd, &reads); int rc = ::select(_fd + 1, &reads, NULL, NULL, &tm); if (rc < 0) return 0; if (FD_ISSET(_fd, &reads)) return ::read(_fd, pBuffer, length); return 0; } SerialPort& SerialPort::setPath(const std::string& path) { _path = path; return *this; } SerialPort& SerialPort::setBaudRate(uint32_t baudRate) { _baudRate = baudRate; return *this; } SerialPort& SerialPort::setParity(Parity parity) { _parity = parity; return *this; } SerialPort& SerialPort::setDataBits(uint32_t bits) { _dataBits = bits; return *this; } SerialPort& SerialPort::setStopBits(uint32_t bits) { _stopBits = bits; return *this; } SerialPort& SerialPort::setFlowControl(FlowControl flowControl) { _flowControl = flowControl; return *this; } uint32_t SerialPort::getBaudRateFlag(uint32_t br) { uint32_t flag; switch (br) { case 0: flag = B0; break; case 50: flag = B50; break; case 75: flag = B75; break; case 110: flag = B110; break; case 134: flag = B134; break; case 150: flag = B150; break; case 200: flag = B200; break; case 300: flag = B300; break; case 600: flag = B600; break; case 1200: flag = B1200; break; case 1800: flag = B1800; break; case 2400: flag = B2400; break; case 4800: flag = B4800; break; case 9600: flag = B9600; break; case 19200: flag = B19200; break; case 38400: flag = B38400; break; case 57600: flag = B57600; break; case 115200: flag = B115200; break; case 230400: flag = B230400; break; case 460800: flag = B460800; break; case 500000: flag = B500000; break; case 576000: flag = B576000; break; case 921600: flag = B921600; break; case 1000000: flag = B1000000; break; case 1152000: flag = B1152000; break; case 1500000: flag = B1500000; break; case 2000000: flag = B2000000; break; case 2500000: flag = B2500000; break; case 3000000: flag = B3000000; break; case 3500000: flag = B3500000; break; case 4000000: flag = B4000000; break; default: flag = B9600; break; } return flag; } }