38 LinuxUART(
const char* dev_path,
unsigned int baudrate = 115200,
40 uint8_t stop_bits = 1, uint32_t tx_queue_size = 5,
size_t buffer_size = 512,
41 size_t thread_stack_size = 65536)
42 :
UART(&_read_port, &_write_port),
43 rx_buff_(new uint8_t[buffer_size]),
44 tx_buff_(new uint8_t[buffer_size]),
45 buff_size_(buffer_size),
46 _read_port(buffer_size),
47 _write_port(tx_queue_size, buffer_size)
49 ASSERT(buff_size_ > 0);
51 while (!std::filesystem::exists(dev_path))
53 XR_LOG_WARN(
"Cannot find UART device: %s, retrying...", dev_path);
57 device_path_ = GetByPathForTTY(dev_path);
59 fd_ = open(device_path_.c_str(), O_RDWR | O_NOCTTY);
62 XR_LOG_ERROR(
"Cannot open UART device: %s", device_path_.c_str());
67 XR_LOG_PASS(
"Open UART device: %s", device_path_.c_str());
70 config_ = {.baudrate = baudrate,
72 .data_bits = data_bits,
73 .stop_bits = stop_bits};
81 this, [](
LinuxUART* self) { self->RxLoop(); },
"rx_uart", thread_stack_size,
85 this, [](
LinuxUART* self) { self->TxLoop(); },
"tx_uart", thread_stack_size,
92 LinuxUART(
const std::string& vid,
const std::string& pid,
94 uint8_t data_bits = 8, uint8_t stop_bits = 1, uint32_t tx_queue_size = 5,
95 size_t buffer_size = 512,
size_t thread_stack_size = 65536)
96 :
UART(&_read_port, &_write_port),
97 rx_buff_(new uint8_t[buffer_size]),
98 tx_buff_(new uint8_t[buffer_size]),
99 buff_size_(buffer_size),
100 _read_port(buffer_size),
101 _write_port(tx_queue_size, buffer_size)
103 while (!FindUSBTTYByVidPid(vid, pid, device_path_))
105 XR_LOG_WARN(
"Cannot find USB TTY device with VID=%s PID=%s, retrying...",
106 vid.c_str(), pid.c_str());
110 XR_LOG_PASS(
"Found USB TTY: %s", device_path_.c_str());
112 if (std::filesystem::exists(device_path_) ==
false)
114 XR_LOG_ERROR(
"Cannot find UART device: %s", device_path_.c_str());
119 device_path_ = GetByPathForTTY(device_path_);
121 fd_ = open(device_path_.c_str(), O_RDWR | O_NOCTTY);
124 XR_LOG_ERROR(
"Cannot open UART device: %s", device_path_.c_str());
129 XR_LOG_PASS(
"Open UART device: %s", device_path_.c_str());
132 config_ = {.baudrate = baudrate,
134 .data_bits = data_bits,
135 .stop_bits = stop_bits};
143 this, [](
LinuxUART* self) { self->RxLoop(); },
"rx_uart", thread_stack_size,
147 this, [](
LinuxUART* self) { self->TxLoop(); },
"tx_uart", thread_stack_size,
151 std::string GetByPathForTTY(
const std::string& tty_name)
153 const std::string BASE =
"/dev/serial/by-path";
154 if (strncmp(tty_name.c_str(), BASE.c_str(), BASE.length()) == 0 ||
155 !std::filesystem::exists(BASE))
159 for (
const auto& entry : std::filesystem::directory_iterator(BASE))
161 std::string full = std::filesystem::canonical(entry.path());
162 if (full == tty_name)
170 static bool FindUSBTTYByVidPid(
const std::string& target_vid,
171 const std::string& target_pid, std::string& tty_path)
173 struct udev* udev = udev_new();
176 XR_LOG_ERROR(
"Cannot create udev context");
180 struct udev_enumerate* enumerate = udev_enumerate_new(udev);
181 udev_enumerate_add_match_subsystem(enumerate,
"tty");
182 udev_enumerate_scan_devices(enumerate);
184 struct udev_list_entry* devices = udev_enumerate_get_list_entry(enumerate);
185 struct udev_list_entry* entry =
nullptr;
188 udev_list_entry_foreach(entry, devices)
190 const char* path = udev_list_entry_get_name(entry);
191 struct udev_device* tty_dev = udev_device_new_from_syspath(udev, path);
197 struct udev_device* usb_dev =
198 udev_device_get_parent_with_subsystem_devtype(tty_dev,
"usb",
"usb_device");
202 const char* vid = udev_device_get_sysattr_value(usb_dev,
"idVendor");
203 const char* pid = udev_device_get_sysattr_value(usb_dev,
"idProduct");
205 if (vid && pid && target_vid == vid && target_pid == pid)
207 const char* devnode = udev_device_get_devnode(tty_dev);
212 udev_device_unref(tty_dev);
218 udev_device_unref(tty_dev);
221 udev_enumerate_unref(enumerate);
226 void SetLowLatency(
int fd)
228 struct serial_struct serinfo;
229 ioctl(fd, TIOCGSERIAL, &serinfo);
230 serinfo.flags |= ASYNC_LOW_LATENCY;
231 ioctl(fd, TIOCSSERIAL, &serinfo);
236 if (&config != &config_)
241 struct termios2 tio{};
242 if (ioctl(fd_, TCGETS2, &tio) != 0)
244 return ErrorCode::INIT_ERR;
248 tio.c_cflag &= ~CBAUD;
249 tio.c_cflag |= BOTHER;
254 tio.c_iflag &= ~(IXON | IXOFF | IXANY | ISTRIP | IGNCR | INLCR | ICRNL
261 tio.c_oflag &= ~(OPOST
277 tio.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
280 tio.c_cflag &= ~CSIZE;
296 return ErrorCode::ARG_ERR;
300 tio.c_cflag &= ~CSTOPB;
303 tio.c_cflag |= CSTOPB;
310 tio.c_cflag &= ~PARENB;
313 tio.c_cflag |= PARENB;
314 tio.c_cflag &= ~PARODD;
317 tio.c_cflag |= PARENB;
318 tio.c_cflag |= PARODD;
323 tio.c_cflag &= ~CRTSCTS;
326 tio.c_cflag |= (CLOCAL | CREAD);
333 if (ioctl(fd_, TCSETS2, &tio) != 0)
335 return ErrorCode::INIT_ERR;
340 tcflush(fd_, TCIOFLUSH);
342 return ErrorCode::OK;
347 static ErrorCode
WriteFun(WritePort& port)
349 auto uart = CONTAINER_OF(&port,
LinuxUART, _write_port);
350 uart->write_sem_.Post();
351 return ErrorCode::OK;
362 fd_ = open(device_path_.c_str(), O_RDWR | O_NOCTTY);
366 XR_LOG_WARN(
"Cannot open UART device: %s", device_path_.c_str());
372 XR_LOG_PASS(
"Reopen UART device: %s", device_path_.c_str());
376 auto n = read(fd_, rx_buff_, buff_size_);
384 XR_LOG_WARN(
"Cannot read UART device: %s", device_path_.c_str());
401 if (write_sem_.
Wait() != ErrorCode::OK)
406 if (
write_port_->queue_info_->Pop(info) == ErrorCode::OK)
411 auto written = write(fd_, tx_buff_, info.data.size_);
414 XR_LOG_WARN(
"Cannot write UART device: %s", device_path_.c_str());
418 (written ==
static_cast<int>(info.data.size_))
425 info.op.UpdateStatus(
false, ErrorCode::FAILED);
432 bool connected_ =
true;
433 Configuration config_;
434 std::string device_path_;
437 uint8_t* rx_buff_ =
nullptr;
438 uint8_t* tx_buff_ =
nullptr;
439 size_t buff_size_ = 0;
440 Semaphore write_sem_;
444 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, 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
void Create(ArgType arg, void(*function)(ArgType arg), const char *name, size_t stack_depth, Thread::Priority priority)
创建新线程 Creates a new thread