#include "tty_protocol_writer.h" #include #include #ifdef _WIN32 TtyProtocolWriter::TtyProtocolWriter(std::string path) : path_(std::move(path)) { throw std::runtime_error("tty output is supported only on Linux/POSIX"); } TtyProtocolWriter::~TtyProtocolWriter() = default; TtyProtocolWriter::TtyProtocolWriter(TtyProtocolWriter&& other) noexcept = default; TtyProtocolWriter& TtyProtocolWriter::operator=(TtyProtocolWriter&& other) noexcept = default; void TtyProtocolWriter::emit_packet_start() const {} void TtyProtocolWriter::emit_step(uint16_t index, int16_t ch1_avg, int16_t ch2_avg) const { (void) index; (void) ch1_avg; (void) ch2_avg; } const std::string& TtyProtocolWriter::path() const { return path_; } void TtyProtocolWriter::write_frame(uint16_t word0, uint16_t word1, uint16_t word2, uint16_t word3) const { (void) word0; (void) word1; (void) word2; (void) word3; } void TtyProtocolWriter::close_fd() noexcept {} #else #include #include #include #include #include #include namespace { std::string io_error(const std::string& action, const std::string& path) { std::ostringstream out; out << action << " '" << path << "': " << std::strerror(errno); return out.str(); } } // namespace TtyProtocolWriter::TtyProtocolWriter(std::string path) : path_(std::move(path)) { fd_ = ::open(path_.c_str(), O_WRONLY | O_NOCTTY); if (fd_ < 0) { throw std::runtime_error(io_error("Cannot open tty output", path_)); } } TtyProtocolWriter::~TtyProtocolWriter() { close_fd(); } TtyProtocolWriter::TtyProtocolWriter(TtyProtocolWriter&& other) noexcept : path_(std::move(other.path_)), fd_(other.fd_) { other.fd_ = -1; } TtyProtocolWriter& TtyProtocolWriter::operator=(TtyProtocolWriter&& other) noexcept { if (this != &other) { close_fd(); path_ = std::move(other.path_); fd_ = other.fd_; other.fd_ = -1; } return *this; } void TtyProtocolWriter::emit_packet_start() const { write_frame(0x000A, 0xFFFF, 0xFFFF, 0xFFFF); } void TtyProtocolWriter::emit_step(uint16_t index, int16_t ch1_avg, int16_t ch2_avg) const { write_frame(0x000A, index, static_cast(ch1_avg), static_cast(ch2_avg)); } const std::string& TtyProtocolWriter::path() const { return path_; } void TtyProtocolWriter::write_frame(uint16_t word0, uint16_t word1, uint16_t word2, uint16_t word3) const { const uint16_t frame[4] = {word0, word1, word2, word3}; const std::uint8_t* bytes = reinterpret_cast(frame); std::size_t remaining = sizeof(frame); while (remaining != 0U) { const ssize_t written = ::write(fd_, bytes, remaining); if (written < 0) { if (errno == EINTR) { continue; } throw std::runtime_error(io_error("Cannot write tty frame to", path_)); } if (written == 0) { throw std::runtime_error("tty write returned 0 bytes for '" + path_ + "'"); } bytes += static_cast(written); remaining -= static_cast(written); } } void TtyProtocolWriter::close_fd() noexcept { if (fd_ >= 0) { ::close(fd_); fd_ = -1; } } #endif