KEK/comm_posix_tty.cpp
2024-05-17 19:23:04 +02:00

126 lines
2.9 KiB
C++

// (C) 2024 by Folkert van Heusden
// Released under MIT license
#include "gen.h"
#include <cstring>
#include <errno.h>
#include <fcntl.h>
#include <string>
#include <termios.h>
#include <thread>
#include <unistd.h>
#if defined(_WIN32)
#include <ws2tcpip.h>
#include <winsock2.h>
#else
#include <poll.h>
#endif
#include "comm_posix_tty.h"
#include "log.h"
comm_posix_tty::comm_posix_tty(const std::string & device, const int bitrate)
{
fd = open(device.c_str(), O_RDWR);
if (fd == -1) {
DOLOG(warning, false, "com_posix_tty failed to access %s: %s", device.c_str(), strerror(errno));
return; // TODO error handling
}
// from https://stackoverflow.com/questions/6947413/how-to-open-read-and-write-from-serial-port-in-c
termios tty { };
if (tcgetattr(fd, &tty) == -1) {
DOLOG(warning, false, "com_posix_tty tcgetattr failed: %s", strerror(errno));
close(fd);
fd = -1;
return;
}
cfsetospeed(&tty, bitrate);
cfsetispeed(&tty, bitrate);
tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8; // 8-bit chars
// disable IGNBRK for mismatched speed tests; otherwise receive break
// as \000 chars
tty.c_iflag &= ~IGNBRK; // disable break processing
tty.c_lflag = 0; // no signaling chars, no echo,
// no canonical processing
tty.c_oflag = 0; // no remapping, no delays
tty.c_cc[VMIN] = 0; // read doesn't block
tty.c_cc[VTIME] = 5; // 0.5 seconds read timeout
tty.c_iflag &= ~(IXON | IXOFF | IXANY); // shut off xon/xoff ctrl
tty.c_cflag |= (CLOCAL | CREAD);// ignore modem controls,
// enable reading
tty.c_cflag &= ~(PARENB | PARODD); // shut off parity
tty.c_cflag &= ~CSTOPB;
tty.c_cflag &= ~CRTSCTS;
if (tcsetattr(fd, TCSANOW, &tty) == -1) {
DOLOG(warning, false, "com_posix_tty tcsetattr failed: %s", strerror(errno));
close(fd);
fd = -1;
return;
}
}
comm_posix_tty::~comm_posix_tty()
{
if (fd != -1)
close(fd);
}
bool comm_posix_tty::is_connected()
{
return fd != -1;
}
bool comm_posix_tty::has_data()
{
if (fd == -1)
return false;
#if defined(_WIN32)
WSAPOLLFD fds[] { { fd, POLLIN, 0 } };
int rc = WSAPoll(fds, 1, 0);
#else
pollfd fds[] { { fd, POLLIN, 0 } };
int rc = poll(fds, 1, 0);
#endif
return rc == 1;
}
uint8_t comm_posix_tty::get_byte()
{
uint8_t c = 0;
if (read(fd, &c, 1) <= 0) {
DOLOG(warning, false, "com_posix_tty cannot read");
close(fd);
fd = -1;
}
return c;
}
void comm_posix_tty::send_data(const uint8_t *const in, const size_t n)
{
const uint8_t *p = in;
size_t len = n;
while(len > 0) {
int rc = write(fd, p, len);
if (rc <= 0) { // TODO error checking
DOLOG(warning, false, "com_posix_tty cannot write");
close(fd);
fd = -1;
break;
}
p += rc;
len -= rc;
}
}