29 LinuxUART(
const char *dev_path,
unsigned int baudrate = 115200,
31 uint8_t stop_bits = 1, uint32_t tx_queue_size = 5,
size_t buffer_size = 512)
32 :
UART(&_read_port, &_write_port),
34 rx_buff_(
new uint8_t[buffer_size]),
35 tx_buff_(
new uint8_t[buffer_size]),
36 buff_size_(buffer_size),
37 _read_port(buffer_size),
38 _write_port(tx_queue_size, buffer_size)
40 ASSERT(buff_size_ > 0);
42 if (std::filesystem::exists(dev_path) ==
false)
44 XR_LOG_ERROR(
"Cannot find UART device: %s", dev_path);
48 device_path_ = GetByPathForTTY(dev_path);
50 fd_ = open(device_path_.c_str(), O_RDWR | O_NOCTTY);
53 XR_LOG_ERROR(
"Cannot open UART device: %s", device_path_.c_str());
58 XR_LOG_PASS(
"Open UART device: %s", device_path_.c_str());
61 config_ = {.baudrate = baudrate,
63 .data_bits = data_bits,
64 .stop_bits = stop_bits};
72 this, [](
LinuxUART *self) { self->RxLoop(); },
"rx_uart", 8192,
76 this, [](
LinuxUART *self) { self->TxLoop(); },
"tx_uart", 8192,
80 LinuxUART(
const std::string &vid,
const std::string &pid,
82 uint8_t data_bits = 8, uint8_t stop_bits = 1, uint32_t tx_queue_size = 5,
83 size_t buffer_size = 512)
84 :
UART(&_read_port, &_write_port),
86 rx_buff_(
new uint8_t[buffer_size]),
87 tx_buff_(
new uint8_t[buffer_size]),
88 buff_size_(buffer_size),
89 _read_port(buffer_size),
90 _write_port(tx_queue_size, buffer_size)
92 while (!FindUSBTTYByVidPid(vid, pid, device_path_))
94 XR_LOG_WARN(
"Cannot find USB TTY device with VID=%s PID=%s, retrying...",
95 vid.c_str(), pid.c_str());
99 XR_LOG_PASS(
"Found USB TTY: %s", device_path_.c_str());
101 if (std::filesystem::exists(device_path_) ==
false)
103 XR_LOG_ERROR(
"Cannot find UART device: %s", device_path_);
107 device_path_ = GetByPathForTTY(device_path_);
109 fd_ = open(device_path_.c_str(), O_RDWR | O_NOCTTY);
112 XR_LOG_ERROR(
"Cannot open UART device: %s", device_path_.c_str());
117 XR_LOG_PASS(
"Open UART device: %s", device_path_.c_str());
120 config_ = {.baudrate = baudrate,
122 .data_bits = data_bits,
123 .stop_bits = stop_bits};
131 this, [](
LinuxUART *self) { self->RxLoop(); },
"rx_uart", 8192,
135 this, [](
LinuxUART *self) { self->TxLoop(); },
"tx_uart", 8192,
139 std::string GetByPathForTTY(
const std::string &tty_name)
141 const std::string BASE =
"/dev/serial/by-path";
142 if (strncmp(tty_name.c_str(), BASE.c_str(), BASE.length()) == 0 ||
143 !std::filesystem::exists(BASE))
147 for (
const auto &entry : std::filesystem::directory_iterator(BASE))
149 std::string full = std::filesystem::canonical(entry.path());
150 if (full == tty_name)
158 static bool FindUSBTTYByVidPid(
const std::string &target_vid,
159 const std::string &target_pid, std::string &tty_path)
161 struct udev *udev = udev_new();
164 XR_LOG_ERROR(
"Cannot create udev context");
168 struct udev_enumerate *enumerate = udev_enumerate_new(udev);
169 udev_enumerate_add_match_subsystem(enumerate,
"tty");
170 udev_enumerate_scan_devices(enumerate);
172 struct udev_list_entry *devices = udev_enumerate_get_list_entry(enumerate);
173 struct udev_list_entry *entry;
176 udev_list_entry_foreach(entry, devices)
178 const char *path = udev_list_entry_get_name(entry);
179 struct udev_device *tty_dev = udev_device_new_from_syspath(udev, path);
180 if (!tty_dev)
continue;
182 struct udev_device *usb_dev =
183 udev_device_get_parent_with_subsystem_devtype(tty_dev,
"usb",
"usb_device");
187 const char *vid = udev_device_get_sysattr_value(usb_dev,
"idVendor");
188 const char *pid = udev_device_get_sysattr_value(usb_dev,
"idProduct");
190 if (vid && pid && target_vid == vid && target_pid == pid)
192 const char *devnode = udev_device_get_devnode(tty_dev);
197 udev_device_unref(tty_dev);
203 udev_device_unref(tty_dev);
206 udev_enumerate_unref(enumerate);
211 void SetLowLatency(
int fd)
213 struct serial_struct serinfo;
214 ioctl(fd, TIOCGSERIAL, &serinfo);
215 serinfo.flags |= ASYNC_LOW_LATENCY;
216 ioctl(fd, TIOCSSERIAL, &serinfo);
221 if (&config != &config_)
226 struct termios2 tio{};
227 if (ioctl(fd_, TCGETS2, &tio) != 0)
229 return ErrorCode::INIT_ERR;
233 tio.c_cflag &= ~CBAUD;
234 tio.c_cflag |= BOTHER;
239 tio.c_iflag &= ~(IXON | IXOFF | IXANY | ISTRIP | IGNCR | INLCR | ICRNL
246 tio.c_oflag &= ~(OPOST
262 tio.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
265 tio.c_cflag &= ~CSIZE;
281 return ErrorCode::ARG_ERR;
285 tio.c_cflag &= ~CSTOPB;
288 tio.c_cflag |= CSTOPB;
295 tio.c_cflag &= ~PARENB;
298 tio.c_cflag |= PARENB;
299 tio.c_cflag &= ~PARODD;
302 tio.c_cflag |= PARENB;
303 tio.c_cflag |= PARODD;
308 tio.c_cflag &= ~CRTSCTS;
311 tio.c_cflag |= (CLOCAL | CREAD);
318 if (ioctl(fd_, TCSETS2, &tio) != 0)
320 return ErrorCode::INIT_ERR;
325 tcflush(fd_, TCIOFLUSH);
327 return ErrorCode::OK;
332 static ErrorCode
WriteFun(WritePort &port)
334 auto uart = CONTAINER_OF(&port, LinuxUART, _write_port);
335 uart->write_sem_.Post();
336 return ErrorCode::OK;
347 fd_ = open(device_path_.c_str(), O_RDWR | O_NOCTTY);
351 XR_LOG_WARN(
"Cannot open UART device: %s", device_path_.c_str());
357 XR_LOG_PASS(
"Reopen UART device: %s", device_path_.c_str());
361 auto n = read(fd_, rx_buff_, buff_size_);
369 XR_LOG_WARN(
"Cannot read UART device: %s", device_path_.c_str());
386 if (write_sem_.
Wait() != ErrorCode::OK)
391 if (
write_port_->queue_info_->Pop(info) == ErrorCode::OK)
396 auto written = write(fd_, tx_buff_, info.data.size_);
399 XR_LOG_WARN(
"Cannot write UART device: %s", device_path_.c_str());
403 (written ==
static_cast<int>(info.data.size_))
411 info.op.UpdateStatus(
false, ErrorCode::FAILED);
418 bool connected_ =
true;
419 Configuration config_;
420 std::string device_path_;
423 uint8_t *rx_buff_ =
nullptr;
424 uint8_t *tx_buff_ =
nullptr;
425 size_t buff_size_ = 0;
426 Semaphore write_sem_;
430 WritePort _write_port;