24 #include <system_error> 49 unsigned long baud_rate,
51 std::unique_ptr<UnixSyscalls> syscalls)
52 : device_(
std::move(device)), baud_rate_(baud_rate),
53 features_(features), syscalls_(
std::move(syscalls)), port_(-1)
66 syscalls_->close(port_);
78 const std::chrono::nanoseconds &timeout)
80 std::chrono::milliseconds timeout_ms =
81 std::chrono::duration_cast<std::chrono::milliseconds>(timeout);
82 struct pollfd fds = {port_, POLLIN, 0};
83 auto result = syscalls_->poll(
84 &fds, 1, static_cast<int>(timeout_ms.count()));
89 throw std::system_error(std::error_code(errno, std::system_category()));
95 if (fds.revents & POLLERR)
97 syscalls_->close(port_);
99 return std::vector<uint8_t>();
102 else if (fds.revents & POLLIN)
109 return std::vector<uint8_t>();
121 auto err = syscalls_->write(port_, data.data(), data.size());
126 throw std::system_error(std::error_code(errno, std::system_category()));
130 if (static_cast<size_t>(err) < data.size())
144 void UnixSerialPort::configure_port_(
150 if (syscalls_->tcgetattr(port_, &tty) < 0)
152 throw std::system_error(std::error_code(errno, std::system_category()));
156 speed_t speed = speed_constant_(baud_rate);
158 if (cfsetispeed(&tty, speed) < 0)
163 throw std::system_error(std::error_code(errno, std::system_category()));
167 if (cfsetospeed(&tty, speed) < 0)
172 throw std::system_error(std::error_code(errno, std::system_category()));
177 tty.c_cflag |=
static_cast<tcflag_t
>(CLOCAL | CREAD);
179 tty.c_cflag &=
static_cast<tcflag_t
>(~PARENB);
180 tty.c_cflag &=
static_cast<tcflag_t
>(~CSTOPB);
181 tty.c_cflag &=
static_cast<tcflag_t
>(~CSIZE);
182 tty.c_cflag |=
static_cast<tcflag_t
>(CS8);
187 tty.c_cflag |=
static_cast<tcflag_t
>(CRTSCTS);
191 tty.c_cflag &=
static_cast<tcflag_t
>(~CRTSCTS);
195 tty.c_lflag &=
static_cast<tcflag_t
>(~(ICANON | ECHO | ECHOE | ISIG));
196 tty.c_iflag &=
static_cast<tcflag_t
>(~(IGNBRK | BRKINT | PARMRK | ISTRIP));
197 tty.c_iflag &=
static_cast<tcflag_t
>(~(INLCR | IGNCR | ICRNL));
199 tty.c_iflag &=
static_cast<tcflag_t
>(~(IXON | IXOFF | IXANY));
201 tty.c_oflag &=
static_cast<tcflag_t
>(~OPOST);
208 if (syscalls_->tcsetattr(port_, TCSANOW, &tty) < 0)
210 throw std::system_error(std::error_code(errno, std::system_category()));
220 void UnixSerialPort::open_port_()
224 port_ = syscalls_->open(device_.c_str(), O_RDWR | O_NOCTTY | O_SYNC);
228 throw std::system_error(
229 std::error_code(errno, std::system_category()),
230 "Failed to open \"" + device_ +
"\".");
236 configure_port_(baud_rate_, features_);
240 syscalls_->close(port_);
254 std::vector<uint8_t> UnixSerialPort::read_()
256 std::vector<uint8_t> buffer;
258 auto size = syscalls_->read(port_, buffer.data(), buffer.size());
262 throw std::system_error(std::error_code(errno, std::system_category()));
265 buffer.resize(static_cast<size_t>(size));
278 speed_t UnixSerialPort::speed_constant_(
unsigned long baud_rate)
341 throw std::invalid_argument(
342 std::to_string(baud_rate) +
" bps is not a valid baud rate.");
362 os <<
"serial {" << std::endl;
363 os <<
" device " << device_ <<
";" << std::endl;
364 os <<
" baudrate " << std::to_string(baud_rate_) <<
";" << std::endl;
368 os <<
" flow_control yes;" << std::endl;
372 os <<
" flow_control no;" << std::endl;
virtual ~UnixSerialPort()
virtual void write(const std::vector< uint8_t > &data) final
virtual std::vector< uint8_t > read(const std::chrono::nanoseconds &timeout=std::chrono::nanoseconds::zero()) final
std::ostream & print_(std::ostream &os) const final
UnixSerialPort(std::string device, unsigned long baud_rate=9600, SerialPort::Feature features=SerialPort::DEFAULT, std::unique_ptr< UnixSyscalls > syscalls=std::make_unique< UnixSyscalls >())