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 size_t thread_stack_size = 65536)
33 :
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 while (!std::filesystem::exists(dev_path))
44 XR_LOG_WARN(
"Cannot find UART device: %s, retrying...", 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", thread_stack_size,
76 this, [](
LinuxUART *self) { self->TxLoop(); },
"tx_uart", thread_stack_size,
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,
size_t thread_stack_size = 65536)
84 :
UART(&_read_port, &_write_port),
85 rx_buff_(
new uint8_t[buffer_size]),
86 tx_buff_(
new uint8_t[buffer_size]),
87 buff_size_(buffer_size),
88 _read_port(buffer_size),
89 _write_port(tx_queue_size, buffer_size)
91 while (!FindUSBTTYByVidPid(vid, pid, device_path_))
93 XR_LOG_WARN(
"Cannot find USB TTY device with VID=%s PID=%s, retrying...",
94 vid.c_str(), pid.c_str());
98 XR_LOG_PASS(
"Found USB TTY: %s", device_path_.c_str());
100 if (std::filesystem::exists(device_path_) ==
false)
102 XR_LOG_ERROR(
"Cannot find UART device: %s", device_path_.c_str());
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", thread_stack_size,
135 this, [](
LinuxUART *self) { self->TxLoop(); },
"tx_uart", thread_stack_size,
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 =
nullptr;
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);
185 struct udev_device *usb_dev =
186 udev_device_get_parent_with_subsystem_devtype(tty_dev,
"usb",
"usb_device");
190 const char *vid = udev_device_get_sysattr_value(usb_dev,
"idVendor");
191 const char *pid = udev_device_get_sysattr_value(usb_dev,
"idProduct");
193 if (vid && pid && target_vid == vid && target_pid == pid)
195 const char *devnode = udev_device_get_devnode(tty_dev);
200 udev_device_unref(tty_dev);
206 udev_device_unref(tty_dev);
209 udev_enumerate_unref(enumerate);
214 void SetLowLatency(
int fd)
216 struct serial_struct serinfo;
217 ioctl(fd, TIOCGSERIAL, &serinfo);
218 serinfo.flags |= ASYNC_LOW_LATENCY;
219 ioctl(fd, TIOCSSERIAL, &serinfo);
224 if (&config != &config_)
232 if (ioctl(fd_, TCGETS2, &tio) != 0)
234 return ErrorCode::INIT_ERR;
238 tio.c_cflag &= ~CBAUD;
239 tio.c_cflag |= BOTHER;
244 tio.c_iflag &= ~(IXON | IXOFF | IXANY | ISTRIP | IGNCR | INLCR | ICRNL
251 tio.c_oflag &= ~(OPOST
267 tio.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
270 tio.c_cflag &= ~CSIZE;
286 return ErrorCode::ARG_ERR;
290 tio.c_cflag &= ~CSTOPB;
293 tio.c_cflag |= CSTOPB;
300 tio.c_cflag &= ~PARENB;
303 tio.c_cflag |= PARENB;
304 tio.c_cflag &= ~PARODD;
307 tio.c_cflag |= PARENB;
308 tio.c_cflag |= PARODD;
313 tio.c_cflag &= ~CRTSCTS;
316 tio.c_cflag |= (CLOCAL | CREAD);
323 if (ioctl(fd_, TCSETS2, &tio) != 0)
325 return ErrorCode::INIT_ERR;
330 tcflush(fd_, TCIOFLUSH);
332 return ErrorCode::OK;
337 static ErrorCode
WriteFun(WritePort &port)
339 auto uart = CONTAINER_OF(&port, LinuxUART, _write_port);
340 uart->write_sem_.Post();
341 return ErrorCode::OK;
352 fd_ = open(device_path_.c_str(), O_RDWR | O_NOCTTY);
356 XR_LOG_WARN(
"Cannot open UART device: %s", device_path_.c_str());
362 XR_LOG_PASS(
"Reopen UART device: %s", device_path_.c_str());
366 auto n = read(fd_, rx_buff_, buff_size_);
374 XR_LOG_WARN(
"Cannot read UART device: %s", device_path_.c_str());
391 if (write_sem_.
Wait() != ErrorCode::OK)
396 if (
write_port_->queue_info_->Pop(info) == ErrorCode::OK)
401 auto written = write(fd_, tx_buff_, info.data.size_);
404 XR_LOG_WARN(
"Cannot write UART device: %s", device_path_.c_str());
408 (written ==
static_cast<int>(info.data.size_))
415 info.op.UpdateStatus(
false, ErrorCode::FAILED);
422 bool connected_ =
true;
423 Configuration config_;
424 std::string device_path_;
427 uint8_t *rx_buff_ =
nullptr;
428 uint8_t *tx_buff_ =
nullptr;
429 size_t buff_size_ = 0;
430 Semaphore write_sem_;
434 WritePort _write_port;