libxr
Embedded C++ framework for bare-metal, RTOS and Linux
Loading...
Searching...
No Matches
LibXR::LinuxUART Class Reference

使用单个 I/O 线程的 Linux 串口 / Linux UART with one I/O thread. More...

#include <linux_uart.hpp>

Inheritance diagram for LibXR::LinuxUART:
[legend]
Collaboration diagram for LibXR::LinuxUART:
[legend]

Public Member Functions

 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)
 通过设备路径构造串口 / Construct a 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 构造串口 / Construct a UART by USB VID/PID.
 
 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 控制接口名称构造串口 / Construct a UART by USB control interface.
 
 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 接口和序列号构造串口 / Construct a UART by USB interface and serial.
 
std::string GetByPathForTTY (const std::string &tty_name)
 查找设备的稳定路径 / Find a stable path for a TTY.
 
void SetLowLatency (int fd)
 尝试启用设备低延迟选项 / Try to enable the device low-latency option.
 
ErrorCode SetConfig (UART::Configuration config, bool=false) override
 提交串口配置请求 / Submit a UART configuration request.
 
- Public Member Functions inherited from LibXR::UART
template<typename ReadPortType = ReadPort, typename WritePortType = WritePort>
 UART (ReadPortType *read_port, WritePortType *write_port)
 UART 构造函数 / UART constructor.
 
template<typename OperationType , typename = std::enable_if_t<std::is_base_of_v< WriteOperation, std::decay_t<OperationType>>>>
ErrorCode Write (ConstRawData data, OperationType &&op, bool in_isr=false)
 
template<typename OperationType , typename = std::enable_if_t<std::is_base_of_v< ReadOperation, std::decay_t<OperationType>>>>
ErrorCode Read (RawData data, OperationType &&op, bool in_isr=false)
 

Static Public Member Functions

static bool FindUSBTTYByVidPid (const std::string &target_vid, const std::string &target_pid, std::string &tty_path)
 查找匹配的 USB 串口设备 / Find a matching USB TTY device.
 
static bool FindUSBTTYByVidPid (const std::string &target_vid, const std::string &target_pid, const std::string &target_control_interface_name, std::string &tty_path)
 查找匹配的 USB 串口设备 / Find a matching USB TTY device.
 
static bool FindUSBTTYByVidPid (const std::string &target_vid, const std::string &target_pid, const std::string &target_control_interface_name, const std::string &target_serial, std::string &tty_path)
 查找匹配的 USB 串口设备 / Find a matching USB TTY device.
 

Friends

class Detail::LinuxUARTReadPort
 

Additional Inherited Members

- Public Types inherited from LibXR::UART
enum class  Parity : uint8_t { NO_PARITY = 0 , EVEN = 1 , ODD = 2 }
 奇偶校验模式 / Parity mode More...
 
- Public Attributes inherited from LibXR::UART
ReadPort * read_port_
 读取端口 / Read port
 
WritePort * write_port_
 写入端口 / Write port
 

Detailed Description

使用单个 I/O 线程的 Linux 串口 / Linux UART with one I/O thread.

支持设备路径和 USB VID/PID、控制接口名称、序列号匹配。线程统一负责打开、关闭、 接收、发送、配置和重连,读写端口的通知只唤醒该线程。 Supports device paths or USB VID/PID, control-interface name, and serial matching. One thread handles open, close, RX, TX, configuration, and reconnect. Port callbacks only wake that thread.

Note
写完成表示数据已被 Linux 接收。短写保留剩余部分;部分发送后断线会以 FAILED 结束该请求,尚未发送的后续请求保留到重连。接收队列满时暂停读取设备。 Writes complete on kernel acceptance. Short writes retain the suffix; a disconnect after partial transmission fails that request and retains later requests for reconnect. Full RX queues pause device reads.
Precondition
读写操作遵守端口约定。对象用于长期运行,线程结束前须保持对象和端口有效。 Follow the port contracts. Keep this startup-lifetime object and its ports valid for the lifetime of the I/O thread.

Definition at line 73 of file linux_uart.hpp.

Constructor & Destructor Documentation

◆ LinuxUART() [1/4]

LibXR::LinuxUART::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 )
inline

通过设备路径构造串口 / Construct a UART by device path.

Parameters
dev_path设备路径 / Device path.
baudrate初始波特率,必须大于零 / Positive initial baud rate.
parity奇偶校验方式 / Parity mode.
data_bits数据位数,范围 5 至 8 / Data bits, from 5 to 8.
stop_bits停止位数,1 或 2 / Stop bits, 1 or 2.
tx_queue_size请求队列容量,必须大于零 / Positive TX request capacity.
buffer_size每个方向的字节队列容量,必须大于零 / Positive per-direction capacity.
thread_stack_sizeI/O 线程栈大小,单位为字节 / I/O thread stack size in bytes.
Note
路径不存在时等待;路径存在后等待线程首次尝试打开设备,失败由线程继续重连。 Waits for the path, then for the thread's first open attempt. Failure is recovered by the thread's reconnect loop.

Definition at line 101 of file linux_uart.hpp.

105 : UART(&_read_port, &_write_port),
106 rx_buff_(new uint8_t[buffer_size]),
107 buff_size_(buffer_size),
108 config_{baudrate, parity, data_bits, stop_bits},
109 _read_port(buffer_size, *this),
110 _write_port(tx_queue_size, buffer_size)
111 {
112 ASSERT(buff_size_ > 0);
113 ASSERT(tx_queue_size > 0);
114
115 while (!std::filesystem::exists(dev_path))
116 {
117 XR_LOG_WARN("Cannot find UART device: %s, retrying...", dev_path);
118 Thread::Sleep(100);
119 }
120
121 device_path_ = GetByPathForTTY(dev_path);
122
123 StartIoOwner(thread_stack_size);
124 }
std::string GetByPathForTTY(const std::string &tty_name)
查找设备的稳定路径 / Find a stable path for a TTY.
static void Sleep(uint32_t milliseconds)
让线程进入休眠状态 Puts the thread to sleep
Definition thread.cpp:15
UART(ReadPortType *read_port, WritePortType *write_port)
UART 构造函数 / UART constructor.
Definition uart.hpp:68

◆ LinuxUART() [2/4]

LibXR::LinuxUART::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 )
inline

通过 USB VID/PID 构造串口 / Construct a UART by USB VID/PID.

Parameters
vidUSB 厂商 ID 字符串 / USB vendor ID string.
pidUSB 产品 ID 字符串 / USB product ID string.
baudrate初始波特率,必须大于零 / Positive initial baud rate.
parity奇偶校验方式 / Parity mode.
data_bits数据位数,范围 5 至 8 / Data bits, from 5 to 8.
stop_bits停止位数,1 或 2 / Stop bits, 1 or 2.
tx_queue_size请求队列容量,必须大于零 / Positive TX request capacity.
buffer_size每个方向的字节队列容量,必须大于零 / Positive per-direction capacity.
thread_stack_sizeI/O 线程栈大小,单位为字节 / I/O thread stack size in bytes.

Definition at line 139 of file linux_uart.hpp.

143 : LinuxUART(vid, pid, "", "", baudrate, parity, data_bits, stop_bits, tx_queue_size,
144 buffer_size, thread_stack_size)
145 {
146 }
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)
通过设备路径构造串口 / Construct a UART by device path.

◆ LinuxUART() [3/4]

LibXR::LinuxUART::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 )
inline

按 USB 控制接口名称构造串口 / Construct a UART by USB control interface.

Parameters
vidUSB 厂商 ID 字符串 / USB vendor ID string.
pidUSB 产品 ID 字符串 / USB product ID string.
control_interface_name控制接口名称,空值不限制 / Control interface, empty for any.
baudrate初始波特率,必须大于零 / Positive initial baud rate.
parity奇偶校验方式 / Parity mode.
data_bits数据位数,范围 5 至 8 / Data bits, from 5 to 8.
stop_bits停止位数,1 或 2 / Stop bits, 1 or 2.
tx_queue_size请求队列容量,必须大于零 / Positive TX request capacity.
buffer_size每个方向的字节队列容量,必须大于零 / Positive per-direction capacity.
thread_stack_sizeI/O 线程栈大小,单位为字节 / I/O thread stack size in bytes.

Definition at line 163 of file linux_uart.hpp.

168 : LinuxUART(vid, pid, control_interface_name, "", baudrate, parity, data_bits,
169 stop_bits, tx_queue_size, buffer_size, thread_stack_size)
170 {
171 }

◆ LinuxUART() [4/4]

LibXR::LinuxUART::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 )
inline

按 USB 接口和序列号构造串口 / Construct a UART by USB interface and serial.

Parameters
vidUSB 厂商 ID 字符串 / USB vendor ID string.
pidUSB 产品 ID 字符串 / USB product ID string.
control_interface_name控制接口名称,空值不限制 / Control interface, empty for any.
serial设备序列号,空值不限制 / Device serial number, empty for any.
baudrate初始波特率,必须大于零 / Positive initial baud rate.
parity奇偶校验方式 / Parity mode.
data_bits数据位数,范围 5 至 8 / Data bits, from 5 to 8.
stop_bits停止位数,1 或 2 / Stop bits, 1 or 2.
tx_queue_size请求队列容量,必须大于零 / Positive TX request capacity.
buffer_size每个方向的字节队列容量,必须大于零 / Positive per-direction capacity.
thread_stack_sizeI/O 线程栈大小,单位为字节 / I/O thread stack size in bytes.
Note
等待匹配设备出现;多个匹配时按路径排序选择首项。CDC ACM 匹配控制接口名称。 Waits for a match; selects the first sorted path on ambiguity. CDC ACM matching uses the control-interface name.

Definition at line 192 of file linux_uart.hpp.

197 : UART(&_read_port, &_write_port),
198 rx_buff_(new uint8_t[buffer_size]),
199 buff_size_(buffer_size),
200 config_{baudrate, parity, data_bits, stop_bits},
201 _read_port(buffer_size, *this),
202 _write_port(tx_queue_size, buffer_size)
203 {
204 ASSERT(tx_queue_size > 0);
205 ASSERT(buff_size_ > 0);
206 while (!FindUSBTTYByVidPid(vid, pid, control_interface_name, serial, device_path_))
207 {
208 XR_LOG_WARN(
209 "Cannot find USB TTY device with VID=%s PID=%s SERIAL=%s CONTROL_INTERFACE=%s, "
210 "retrying...",
211 vid.c_str(), pid.c_str(), serial.empty() ? "*" : serial.c_str(),
212 control_interface_name.empty() ? "*" : control_interface_name.c_str());
213 Thread::Sleep(100);
214 }
215
216 XR_LOG_PASS("Found USB TTY: %s", device_path_.c_str());
217
218 if (std::filesystem::exists(device_path_) == false)
219 {
220 XR_LOG_ERROR("Cannot find UART device: %s", device_path_.c_str());
221 REQUIRE(false);
222 return;
223 }
224
225 device_path_ = GetByPathForTTY(device_path_);
226
227 StartIoOwner(thread_stack_size);
228 }
static bool FindUSBTTYByVidPid(const std::string &target_vid, const std::string &target_pid, std::string &tty_path)
查找匹配的 USB 串口设备 / Find a matching USB TTY device.

Member Function Documentation

◆ FindUSBTTYByVidPid() [1/3]

static bool LibXR::LinuxUART::FindUSBTTYByVidPid ( const std::string & target_vid,
const std::string & target_pid,
const std::string & target_control_interface_name,
const std::string & target_serial,
std::string & tty_path )
inlinestatic

查找匹配的 USB 串口设备 / Find a matching USB TTY device.

Returns
找到匹配路径时返回 true / True when a matching path is found.

Definition at line 287 of file linux_uart.hpp.

291 {
292 struct udev* udev = udev_new();
293 if (!udev)
294 {
295 XR_LOG_ERROR("Cannot create udev context");
296 return false;
297 }
298
299 struct udev_enumerate* enumerate = udev_enumerate_new(udev);
300 udev_enumerate_add_match_subsystem(enumerate, "tty");
301 udev_enumerate_scan_devices(enumerate);
302
303 struct udev_list_entry* devices = udev_enumerate_get_list_entry(enumerate);
304 struct udev_list_entry* entry = nullptr;
305 std::vector<std::string> matches;
306
307 udev_list_entry_foreach(entry, devices)
308 {
309 const char* path = udev_list_entry_get_name(entry);
310 struct udev_device* tty_dev = udev_device_new_from_syspath(udev, path);
311 if (!tty_dev)
312 {
313 continue;
314 }
315
316 struct udev_device* usb_dev =
317 udev_device_get_parent_with_subsystem_devtype(tty_dev, "usb", "usb_device");
318 struct udev_device* usb_interface =
319 udev_device_get_parent_with_subsystem_devtype(tty_dev, "usb", "usb_interface");
320
321 if (usb_dev)
322 {
323 const char* vid = udev_device_get_sysattr_value(usb_dev, "idVendor");
324 const char* pid = udev_device_get_sysattr_value(usb_dev, "idProduct");
325 const char* serial = udev_device_get_sysattr_value(usb_dev, "serial");
326 const char* control_interface_name = nullptr;
327 if (usb_interface)
328 {
329 // Linux cdc_acm 的 tty 父节点对应 CDC 控制接口。
330 // The parent of a Linux cdc_acm TTY is the CDC control interface.
331 control_interface_name =
332 udev_device_get_sysattr_value(usb_interface, "interface");
333 }
334
335 if (vid && pid && target_vid == vid && target_pid == pid &&
336 (target_serial.empty() || (serial && target_serial == serial)) &&
337 (target_control_interface_name.empty() ||
338 (control_interface_name &&
339 target_control_interface_name == control_interface_name)))
340 {
341 const char* devnode = udev_device_get_devnode(tty_dev);
342 if (devnode)
343 {
344 matches.emplace_back(devnode);
345 }
346 }
347 }
348
349 udev_device_unref(tty_dev);
350 }
351
352 udev_enumerate_unref(enumerate);
353 udev_unref(udev);
354 if (matches.empty())
355 {
356 return false;
357 }
358
359 std::sort(matches.begin(), matches.end());
360 tty_path = matches.front();
361
362 if (matches.size() > 1)
363 {
364 XR_LOG_WARN(
365 "Multiple USB TTY devices found with VID=%s PID=%s SERIAL=%s "
366 "CONTROL_INTERFACE=%s, using %s. Specify serial or control interface name to "
367 "disambiguate.",
368 target_vid.c_str(), target_pid.c_str(),
369 target_serial.empty() ? "*" : target_serial.c_str(),
370 target_control_interface_name.empty() ? "*"
371 : target_control_interface_name.c_str(),
372 tty_path.c_str());
373 }
374
375 return true;
376 }

◆ FindUSBTTYByVidPid() [2/3]

static bool LibXR::LinuxUART::FindUSBTTYByVidPid ( const std::string & target_vid,
const std::string & target_pid,
const std::string & target_control_interface_name,
std::string & tty_path )
inlinestatic

查找匹配的 USB 串口设备 / Find a matching USB TTY device.

Returns
找到匹配路径时返回 true / True when a matching path is found.

Definition at line 274 of file linux_uart.hpp.

278 {
279 return FindUSBTTYByVidPid(target_vid, target_pid, target_control_interface_name, "",
280 tty_path);
281 }

◆ FindUSBTTYByVidPid() [3/3]

static bool LibXR::LinuxUART::FindUSBTTYByVidPid ( const std::string & target_vid,
const std::string & target_pid,
std::string & tty_path )
inlinestatic

查找匹配的 USB 串口设备 / Find a matching USB TTY device.

Returns
找到匹配路径时返回 true / True when a matching path is found.

Definition at line 264 of file linux_uart.hpp.

266 {
267 return FindUSBTTYByVidPid(target_vid, target_pid, "", "", tty_path);
268 }

◆ GetByPathForTTY()

std::string LibXR::LinuxUART::GetByPathForTTY ( const std::string & tty_name)
inline

查找设备的稳定路径 / Find a stable path for a TTY.

Parameters
tty_name原始设备路径 / Original device path.
Returns
匹配的 by-path 链接,未找到时返回原路径 / Matching by-path link, or original path.

Definition at line 236 of file linux_uart.hpp.

237 {
238 const std::string BASE = "/dev/serial/by-path";
239 if (strncmp(tty_name.c_str(), BASE.c_str(), BASE.length()) == 0 ||
240 !std::filesystem::exists(BASE))
241 {
242 return tty_name;
243 }
244 for (const auto& entry : std::filesystem::directory_iterator(BASE))
245 {
246 std::error_code ec;
247 const auto full = std::filesystem::canonical(entry.path(), ec);
248 if (ec)
249 {
250 continue;
251 }
252 if (full == tty_name)
253 {
254 return entry.path().string(); // 返回稳定链接 / Return the stable link.
255 }
256 }
257 return tty_name; // 保留原路径 / Keep the original path.
258 }

◆ SetConfig()

ErrorCode LibXR::LinuxUART::SetConfig ( UART::Configuration config,
bool = false )
inlineoverridevirtual

提交串口配置请求 / Submit a UART configuration request.

Parameters
config目标配置 / Requested configuration.
Returns
接纳返回 OK,已有待处理配置返回 BUSY,参数无效返回 ARG_ERR。 OK on admission, BUSY for an occupied slot, ARG_ERR for invalid parameters.
Note
OK 不表示已经生效。线程等待当前部分写入结束及内核输出队列排空后应用。 断线时保留请求,重连时使用新配置;应用失败继续保留请求。 OK does not mean applied. The thread finishes the partial front and drains kernel output before applying. Pending configuration survives disconnect or application failure and is used on reopen.

Implements LibXR::UART.

Definition at line 406 of file linux_uart.hpp.

407 {
408 if (ValidateConfig(config) != ErrorCode::OK)
409 {
410 return ErrorCode::ARG_ERR;
411 }
412
413 uint8_t expected = static_cast<uint8_t>(ConfigState::EMPTY);
414 if (!config_state_.compare_exchange_strong(
415 expected, static_cast<uint8_t>(ConfigState::RESERVED),
416 std::memory_order_acq_rel, std::memory_order_acquire))
417 {
418 return ErrorCode::BUSY;
419 }
420
421 requested_config_ = config;
422 config_state_.store(static_cast<uint8_t>(ConfigState::PUBLISHED),
423 std::memory_order_release);
424 NotifyIoOwner();
425 return ErrorCode::OK;
426 }
@ BUSY
忙碌 / Busy
@ OK
操作成功 / Operation successful
@ ARG_ERR
参数错误 / Argument error

◆ SetLowLatency()

void LibXR::LinuxUART::SetLowLatency ( int fd)
inline

尝试启用设备低延迟选项 / Try to enable the device low-latency option.

Parameters
fd已打开的设备描述符 / Open device descriptor.
Note
仅在线程处理配置时调用,不支持该选项的设备直接跳过。 Called during owner-side configuration; skips unsupported devices.

Definition at line 384 of file linux_uart.hpp.

385 {
386 struct serial_struct serinfo{};
387 if (ioctl(fd, TIOCGSERIAL, &serinfo) != 0)
388 {
389 return;
390 }
391 serinfo.flags |= ASYNC_LOW_LATENCY;
392 ioctl(fd, TIOCSSERIAL, &serinfo);
393 }

Friends And Related Symbol Documentation

◆ Detail::LinuxUARTReadPort

friend class Detail::LinuxUARTReadPort
friend

Definition at line 75 of file linux_uart.hpp.


The documentation for this class was generated from the following file: