42 LinuxUART(
const char* dev_path,
unsigned int baudrate = 115200,
44 uint8_t stop_bits = 1, uint32_t tx_queue_size = 5,
size_t buffer_size = 512,
45 size_t thread_stack_size = 65536)
46 :
UART(&_read_port, &_write_port),
47 rx_buff_(new uint8_t[buffer_size]),
48 tx_buff_(new uint8_t[buffer_size]),
49 buff_size_(buffer_size),
50 _read_port(buffer_size),
51 _write_port(tx_queue_size, buffer_size)
53 ASSERT(buff_size_ > 0);
55 while (!std::filesystem::exists(dev_path))
57 XR_LOG_WARN(
"Cannot find UART device: %s, retrying...", dev_path);
61 device_path_ = GetByPathForTTY(dev_path);
63 fd_ = open(device_path_.c_str(), O_RDWR | O_NOCTTY);
66 XR_LOG_ERROR(
"Cannot open UART device: %s", device_path_.c_str());
71 XR_LOG_PASS(
"Open UART device: %s", device_path_.c_str());
86 this, [](
LinuxUART* self) { self->RxLoop(); },
"rx_uart", thread_stack_size,
90 this, [](
LinuxUART* self) { self->TxLoop(); },
"tx_uart", thread_stack_size,
97 LinuxUART(
const std::string& vid,
const std::string& pid,
99 uint8_t data_bits = 8, uint8_t stop_bits = 1, uint32_t tx_queue_size = 5,
100 size_t buffer_size = 512,
size_t thread_stack_size = 65536)
101 :
LinuxUART(vid, pid,
"",
"", baudrate, parity, data_bits, stop_bits,
102 tx_queue_size, buffer_size, thread_stack_size)
116 LinuxUART(
const std::string& vid,
const std::string& pid,
117 const std::string& control_interface_name,
119 uint8_t data_bits = 8, uint8_t stop_bits = 1, uint32_t tx_queue_size = 5,
120 size_t buffer_size = 512,
size_t thread_stack_size = 65536)
121 :
LinuxUART(vid, pid, control_interface_name,
"", baudrate, parity, data_bits,
122 stop_bits, tx_queue_size, buffer_size, thread_stack_size)
136 LinuxUART(
const std::string& vid,
const std::string& pid,
137 const std::string& control_interface_name,
const std::string& serial,
139 uint8_t data_bits = 8, uint8_t stop_bits = 1, uint32_t tx_queue_size = 5,
140 size_t buffer_size = 512,
size_t thread_stack_size = 65536)
141 :
UART(&_read_port, &_write_port),
142 rx_buff_(new uint8_t[buffer_size]),
143 tx_buff_(new uint8_t[buffer_size]),
144 buff_size_(buffer_size),
145 _read_port(buffer_size),
146 _write_port(tx_queue_size, buffer_size)
148 while (!FindUSBTTYByVidPid(vid, pid, control_interface_name, serial, device_path_))
151 "Cannot find USB TTY device with VID=%s PID=%s SERIAL=%s CONTROL_INTERFACE=%s, retrying...",
152 vid.c_str(), pid.c_str(), serial.empty() ?
"*" : serial.c_str(),
153 control_interface_name.empty() ?
"*" : control_interface_name.c_str());
157 XR_LOG_PASS(
"Found USB TTY: %s", device_path_.c_str());
159 if (std::filesystem::exists(device_path_) ==
false)
161 XR_LOG_ERROR(
"Cannot find UART device: %s", device_path_.c_str());
166 device_path_ = GetByPathForTTY(device_path_);
168 fd_ = open(device_path_.c_str(), O_RDWR | O_NOCTTY);
171 XR_LOG_ERROR(
"Cannot open UART device: %s", device_path_.c_str());
176 XR_LOG_PASS(
"Open UART device: %s", device_path_.c_str());
191 this, [](
LinuxUART* self) { self->RxLoop(); },
"rx_uart", thread_stack_size,
195 this, [](
LinuxUART* self) { self->TxLoop(); },
"tx_uart", thread_stack_size,
199 std::string GetByPathForTTY(
const std::string& tty_name)
201 const std::string BASE =
"/dev/serial/by-path";
202 if (strncmp(tty_name.c_str(), BASE.c_str(), BASE.length()) == 0 ||
203 !std::filesystem::exists(BASE))
207 for (
const auto& entry : std::filesystem::directory_iterator(BASE))
210 const auto full = std::filesystem::canonical(entry.path(), ec);
215 if (full == tty_name)
217 return entry.path().string();
223 static bool FindUSBTTYByVidPid(
const std::string& target_vid,
224 const std::string& target_pid,
225 std::string& tty_path)
227 return FindUSBTTYByVidPid(target_vid, target_pid,
"",
"", tty_path);
230 static bool FindUSBTTYByVidPid(
const std::string& target_vid,
231 const std::string& target_pid,
232 const std::string& target_control_interface_name,
233 std::string& tty_path)
235 return FindUSBTTYByVidPid(target_vid, target_pid, target_control_interface_name,
"",
239 static bool FindUSBTTYByVidPid(
const std::string& target_vid,
240 const std::string& target_pid,
241 const std::string& target_control_interface_name,
242 const std::string& target_serial, std::string& tty_path)
244 struct udev* udev = udev_new();
247 XR_LOG_ERROR(
"Cannot create udev context");
251 struct udev_enumerate* enumerate = udev_enumerate_new(udev);
252 udev_enumerate_add_match_subsystem(enumerate,
"tty");
253 udev_enumerate_scan_devices(enumerate);
255 struct udev_list_entry* devices = udev_enumerate_get_list_entry(enumerate);
256 struct udev_list_entry* entry =
nullptr;
257 std::vector<std::string> matches;
259 udev_list_entry_foreach(entry, devices)
261 const char* path = udev_list_entry_get_name(entry);
262 struct udev_device* tty_dev = udev_device_new_from_syspath(udev, path);
268 struct udev_device* usb_dev =
269 udev_device_get_parent_with_subsystem_devtype(tty_dev,
"usb",
"usb_device");
270 struct udev_device* usb_interface = udev_device_get_parent_with_subsystem_devtype(
271 tty_dev,
"usb",
"usb_interface");
275 const char* vid = udev_device_get_sysattr_value(usb_dev,
"idVendor");
276 const char* pid = udev_device_get_sysattr_value(usb_dev,
"idProduct");
277 const char* serial = udev_device_get_sysattr_value(usb_dev,
"serial");
278 const char* control_interface_name =
nullptr;
283 control_interface_name =
284 udev_device_get_sysattr_value(usb_interface,
"interface");
287 if (vid && pid && target_vid == vid && target_pid == pid &&
288 (target_serial.empty() || (serial && target_serial == serial)) &&
289 (target_control_interface_name.empty() ||
290 (control_interface_name &&
291 target_control_interface_name == control_interface_name)))
293 const char* devnode = udev_device_get_devnode(tty_dev);
296 matches.emplace_back(devnode);
301 udev_device_unref(tty_dev);
304 udev_enumerate_unref(enumerate);
311 std::sort(matches.begin(), matches.end());
312 tty_path = matches.front();
314 if (matches.size() > 1)
317 "Multiple USB TTY devices found with VID=%s PID=%s SERIAL=%s CONTROL_INTERFACE=%s, using %s. Specify serial or control interface name to disambiguate.",
318 target_vid.c_str(), target_pid.c_str(),
319 target_serial.empty() ?
"*" : target_serial.c_str(),
320 target_control_interface_name.empty() ?
"*"
321 : target_control_interface_name.c_str(),
328 void SetLowLatency(
int fd)
330 struct serial_struct serinfo;
331 ioctl(fd, TIOCGSERIAL, &serinfo);
332 serinfo.flags |= ASYNC_LOW_LATENCY;
333 ioctl(fd, TIOCSSERIAL, &serinfo);
338 if (&config != &config_)
343 struct termios2 tio{};
344 if (ioctl(fd_, TCGETS2, &tio) != 0)
350 tio.c_cflag &= ~CBAUD;
351 tio.c_cflag |= BOTHER;
356 tio.c_iflag &= ~(IXON | IXOFF | IXANY | ISTRIP | IGNCR | INLCR | ICRNL
363 tio.c_oflag &= ~(OPOST
379 tio.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
382 tio.c_cflag &= ~CSIZE;
402 tio.c_cflag &= ~CSTOPB;
405 tio.c_cflag |= CSTOPB;
412 tio.c_cflag &= ~PARENB;
415 tio.c_cflag |= PARENB;
416 tio.c_cflag &= ~PARODD;
419 tio.c_cflag |= PARENB;
420 tio.c_cflag |= PARODD;
425 tio.c_cflag &= ~CRTSCTS;
428 tio.c_cflag |= (CLOCAL | CREAD);
435 if (ioctl(fd_, TCSETS2, &tio) != 0)
442 tcflush(fd_, TCIOFLUSH);
452 uart->write_sem_.Post();
464 fd_ = open(device_path_.c_str(), O_RDWR | O_NOCTTY);
468 XR_LOG_WARN(
"Cannot open UART device: %s", device_path_.c_str());
474 XR_LOG_PASS(
"Reopen UART device: %s", device_path_.c_str());
478 auto n = read(fd_, rx_buff_, buff_size_);
486 XR_LOG_WARN(
"Cannot read UART device: %s", device_path_.c_str());
513 auto written = write(fd_, tx_buff_, info.data.size_);
516 XR_LOG_WARN(
"Cannot write UART device: %s", device_path_.c_str());
520 (written ==
static_cast<int>(info.data.size_))
534 bool connected_ =
true;
535 Configuration config_;
536 std::string device_path_;
539 uint8_t* rx_buff_ =
nullptr;
540 uint8_t* tx_buff_ =
nullptr;
541 size_t buff_size_ = 0;
542 Semaphore write_sem_;
546 WritePort _write_port;
LinuxUART(const char *dev_path, unsigned int baudrate=115200, Parity parity=Parity::NO_PARITY, uint8_t data_bits=8, uint8_t stop_bits=1, uint32_t tx_queue_size=5, size_t buffer_size=512, size_t thread_stack_size=65536)
通过设备路径构造 UART / Construct UART by device path
LinuxUART(const std::string &vid, const std::string &pid, const std::string &control_interface_name, const std::string &serial, unsigned int baudrate=115200, Parity parity=Parity::NO_PARITY, uint8_t data_bits=8, uint8_t stop_bits=1, uint32_t tx_queue_size=5, size_t buffer_size=512, size_t thread_stack_size=65536)
通过 USB VID/PID/control interface name/serial 构造 UART Construct UART by USB VID/PID/control interface ...
LinuxUART(const std::string &vid, const std::string &pid, const std::string &control_interface_name, unsigned int baudrate=115200, Parity parity=Parity::NO_PARITY, uint8_t data_bits=8, uint8_t stop_bits=1, uint32_t tx_queue_size=5, size_t buffer_size=512, size_t thread_stack_size=65536)
通过 USB VID/PID/control interface name 构造 UART Construct UART by USB VID/PID/control interface name
LinuxUART(const std::string &vid, const std::string &pid, unsigned int baudrate=115200, Parity parity=Parity::NO_PARITY, uint8_t data_bits=8, uint8_t stop_bits=1, uint32_t tx_queue_size=5, size_t buffer_size=512, size_t thread_stack_size=65536)
通过 USB VID/PID 构造 UART / Construct UART by USB VID/PID