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),
33 rx_buff_(
new uint8_t[buffer_size]),
34 tx_buff_(
new uint8_t[buffer_size]),
35 buff_size_(buffer_size),
36 _read_port(buffer_size),
37 _write_port(tx_queue_size, buffer_size)
39 ASSERT(buff_size_ > 0);
41 if (std::filesystem::exists(dev_path) ==
false)
43 XR_LOG_ERROR(
"Cannot find UART device: %s", dev_path);
47 device_path_ = GetByPathForTTY(dev_path);
49 fd_ = open(device_path_.c_str(), O_RDWR | O_NOCTTY);
52 XR_LOG_ERROR(
"Cannot open UART device: %s", device_path_.c_str());
57 XR_LOG_PASS(
"Open UART device: %s", device_path_.c_str());
60 config_ = {.baudrate = baudrate,
62 .data_bits = data_bits,
63 .stop_bits = stop_bits};
71 this, [](
LinuxUART *self) { self->RxLoop(); },
"rx_uart", 8192,
75 this, [](
LinuxUART *self) { self->TxLoop(); },
"tx_uart", 8192,
79 LinuxUART(
const std::string &vid,
const std::string &pid,
81 uint8_t data_bits = 8, uint8_t stop_bits = 1, uint32_t tx_queue_size = 5,
82 size_t buffer_size = 512)
83 :
UART(&_read_port, &_write_port),
84 rx_buff_(
new uint8_t[buffer_size]),
85 tx_buff_(
new uint8_t[buffer_size]),
86 buff_size_(buffer_size),
87 _read_port(buffer_size),
88 _write_port(tx_queue_size, buffer_size)
90 while (!FindUSBTTYByVidPid(vid, pid, device_path_))
92 XR_LOG_WARN(
"Cannot find USB TTY device with VID=%s PID=%s, retrying...",
93 vid.c_str(), pid.c_str());
97 XR_LOG_PASS(
"Found USB TTY: %s", device_path_.c_str());
99 if (std::filesystem::exists(device_path_) ==
false)
101 XR_LOG_ERROR(
"Cannot find UART device: %s", device_path_.c_str());
106 device_path_ = GetByPathForTTY(device_path_);
108 fd_ = open(device_path_.c_str(), O_RDWR | O_NOCTTY);
111 XR_LOG_ERROR(
"Cannot open UART device: %s", device_path_.c_str());
116 XR_LOG_PASS(
"Open UART device: %s", device_path_.c_str());
119 config_ = {.baudrate = baudrate,
121 .data_bits = data_bits,
122 .stop_bits = stop_bits};
130 this, [](
LinuxUART *self) { self->RxLoop(); },
"rx_uart", 8192,
134 this, [](
LinuxUART *self) { self->TxLoop(); },
"tx_uart", 8192,
138 std::string GetByPathForTTY(
const std::string &tty_name)
140 const std::string BASE =
"/dev/serial/by-path";
141 if (strncmp(tty_name.c_str(), BASE.c_str(), BASE.length()) == 0 ||
142 !std::filesystem::exists(BASE))
146 for (
const auto &entry : std::filesystem::directory_iterator(BASE))
148 std::string full = std::filesystem::canonical(entry.path());
149 if (full == tty_name)
157 static bool FindUSBTTYByVidPid(
const std::string &target_vid,
158 const std::string &target_pid, std::string &tty_path)
160 struct udev *udev = udev_new();
163 XR_LOG_ERROR(
"Cannot create udev context");
167 struct udev_enumerate *enumerate = udev_enumerate_new(udev);
168 udev_enumerate_add_match_subsystem(enumerate,
"tty");
169 udev_enumerate_scan_devices(enumerate);
171 struct udev_list_entry *devices = udev_enumerate_get_list_entry(enumerate);
172 struct udev_list_entry *entry;
175 udev_list_entry_foreach(entry, devices)
177 const char *path = udev_list_entry_get_name(entry);
178 struct udev_device *tty_dev = udev_device_new_from_syspath(udev, path);
179 if (!tty_dev)
continue;
181 struct udev_device *usb_dev =
182 udev_device_get_parent_with_subsystem_devtype(tty_dev,
"usb",
"usb_device");
186 const char *vid = udev_device_get_sysattr_value(usb_dev,
"idVendor");
187 const char *pid = udev_device_get_sysattr_value(usb_dev,
"idProduct");
189 if (vid && pid && target_vid == vid && target_pid == pid)
191 const char *devnode = udev_device_get_devnode(tty_dev);
196 udev_device_unref(tty_dev);
202 udev_device_unref(tty_dev);
205 udev_enumerate_unref(enumerate);
210 void SetLowLatency(
int fd)
212 struct serial_struct serinfo;
213 ioctl(fd, TIOCGSERIAL, &serinfo);
214 serinfo.flags |= ASYNC_LOW_LATENCY;
215 ioctl(fd, TIOCSSERIAL, &serinfo);
220 if (&config != &config_)
228 if (ioctl(fd_, TCGETS2, &tio) != 0)
230 return ErrorCode::INIT_ERR;
234 tio.c_cflag &= ~CBAUD;
235 tio.c_cflag |= BOTHER;
240 tio.c_iflag &= ~(IXON | IXOFF | IXANY | ISTRIP | IGNCR | INLCR | ICRNL
247 tio.c_oflag &= ~(OPOST
263 tio.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
266 tio.c_cflag &= ~CSIZE;
282 return ErrorCode::ARG_ERR;
286 tio.c_cflag &= ~CSTOPB;
289 tio.c_cflag |= CSTOPB;
296 tio.c_cflag &= ~PARENB;
299 tio.c_cflag |= PARENB;
300 tio.c_cflag &= ~PARODD;
303 tio.c_cflag |= PARENB;
304 tio.c_cflag |= PARODD;
309 tio.c_cflag &= ~CRTSCTS;
312 tio.c_cflag |= (CLOCAL | CREAD);
319 if (ioctl(fd_, TCSETS2, &tio) != 0)
321 return ErrorCode::INIT_ERR;
326 tcflush(fd_, TCIOFLUSH);
328 return ErrorCode::OK;
333 static ErrorCode
WriteFun(WritePort &port)
335 auto uart = CONTAINER_OF(&port, LinuxUART, _write_port);
336 uart->write_sem_.Post();
337 return ErrorCode::OK;
348 fd_ = open(device_path_.c_str(), O_RDWR | O_NOCTTY);
352 XR_LOG_WARN(
"Cannot open UART device: %s", device_path_.c_str());
358 XR_LOG_PASS(
"Reopen UART device: %s", device_path_.c_str());
362 auto n = read(fd_, rx_buff_, buff_size_);
370 XR_LOG_WARN(
"Cannot read UART device: %s", device_path_.c_str());
387 if (write_sem_.
Wait() != ErrorCode::OK)
392 if (
write_port_->queue_info_->Pop(info) == ErrorCode::OK)
397 auto written = write(fd_, tx_buff_, info.data.size_);
400 XR_LOG_WARN(
"Cannot write UART device: %s", device_path_.c_str());
404 (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;