2026-08-04 16:09:17 +04:00

118 lines
2.6 KiB
C++

#ifndef SERIAL_PORT_H
#define SERIAL_PORT_H
#include <termios.h>
#include <sys/select.h>
#include <string>
#include <string.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/serial.h>
#include <unistd.h>
#include <iostream>
#include <memory>
#include <chrono>
#include <queue>
#include <array> // recv_buf below is a std::array; without this, any TU that doesn't
// pull <array> in transitively (e.g. via Eigen) fails to compile.
class SerialPort
{
public:
using SharedPtr = std::shared_ptr<SerialPort>;
SerialPort(std::string port, speed_t baudrate, int timeout_ms = 2)
{
set_timeout(timeout_ms);
Init(port, baudrate);
}
~SerialPort()
{
close(fd_);
}
ssize_t send(const uint8_t* data, size_t len)
{
ssize_t ret = ::write(fd_, data, len);
return ret;
}
ssize_t recv(uint8_t* data, size_t len)
{
FD_ZERO(&rSet_);
FD_SET(fd_, &rSet_);
ssize_t recv_len = 0;
timeval tv = timeout_; // local copy: select() mutates the timeval, keep timeout_ intact
switch (select(fd_ + 1, &rSet_, NULL, NULL, &tv))
{
case -1: // error
// std::cout << "communication error" << std::endl;
break;
case 0: // timeout
// std::cout << "timeout" << std::endl;
break;
default:
recv_len = ::read(fd_, data, len);
break;
}
return recv_len;
}
void set_timeout(int timeout_ms)
{
timeout_.tv_sec = timeout_ms / 1000;
timeout_.tv_usec = (timeout_ms % 1000) * 1000;
}
void flush() { tcflush(fd_, TCIFLUSH); } // discard buffered/echoed input
private:
void Init(std::string port, speed_t baudrate)
{
int ret;
// Open serial port
fd_ = open(port.c_str(), O_RDWR | O_NOCTTY);
if (fd_ < 0)
{
printf("Open serial port %s failed\n", port.c_str());
exit(-1);
}
// Set attributes
struct termios option;
memset(&option, 0, sizeof(option));
ret = tcgetattr(fd_, &option);
option.c_oflag = 0;
option.c_lflag = 0;
option.c_iflag = 0;
cfsetispeed(&option, baudrate);
cfsetospeed(&option, baudrate);
option.c_cflag &= ~CSIZE;
option.c_cflag |= CS8; // 8
option.c_cflag &= ~PARENB; // no parity
option.c_iflag &= ~INPCK; // no parity
option.c_cflag &= ~CSTOPB; // 1 stop bit
option.c_cc[VTIME] = 0;
option.c_cc[VMIN] = 0;
option.c_lflag |= CBAUDEX;
ret = tcflush(fd_, TCIFLUSH);
ret = tcsetattr(fd_, TCSANOW, &option);
}
int fd_;
fd_set rSet_;
timeval timeout_;
std::queue<uint8_t> recv_queue;
std::array<uint8_t, 1024> recv_buf;
};
#endif // SERIAL_PORT_H