313 lines
5.7 KiB
C++
313 lines
5.7 KiB
C++
/*
|
|
*******************************************************************************
|
|
* INCLUDE
|
|
*******************************************************************************
|
|
*/
|
|
#include "SerialPort.h"
|
|
#include <fcntl.h>
|
|
#include <termios.h>
|
|
#include <stdio.h>
|
|
#include <unistd.h>
|
|
#include <Poco/Exception.h>
|
|
#include <Poco/Format.h>
|
|
|
|
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;
|
|
}
|
|
}
|