libxr  1.0
Want to be the best embedded framework
Loading...
Searching...
No Matches
LibXR::LinuxUART Class Reference

Linux UART 串口驱动实现 / Linux UART driver implementation. 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)
 通过设备路径构造 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
 
 LinuxUART (const std::string &vid, const std::string &pid, 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/序列号构造 UART / Construct UART by USB VID/PID/serial
 
std::string GetByPathForTTY (const std::string &tty_name)
 
void SetLowLatency (int fd)
 
ErrorCode SetConfig (UART::Configuration config) override
 设置 UART 配置 / Sets the UART configuration
 
- 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, const std::string &target_serial, std::string &tty_path)
 
static ErrorCode ReadFun (ReadPort &, bool)
 
static ErrorCode WriteFun (WritePort &port, bool)
 

Private Member Functions

void RxLoop ()
 
void TxLoop ()
 

Private Attributes

int fd_ = -1
 
bool connected_ = true
 
Configuration config_
 
std::string device_path_
 
Thread rx_thread_
 
Thread tx_thread_
 
uint8_t * rx_buff_ = nullptr
 
uint8_t * tx_buff_ = nullptr
 
size_t buff_size_ = 0
 
Semaphore write_sem_
 
Mutex read_mutex_
 
ReadPort _read_port
 
WritePort _write_port
 

Additional Inherited Members

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

Detailed Description

Linux UART 串口驱动实现 / Linux UART driver implementation.

支持按设备路径或 USB VID/PID(/serial) 自动发现并创建 UART 通道。 Supports UART creation by device path or USB VID/PID(/serial) auto discovery.

Definition at line 34 of file linux_uart.hpp.

Constructor & Destructor Documentation

◆ LinuxUART() [1/3]

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

通过设备路径构造 UART / Construct UART by device path

Definition at line 40 of file linux_uart.hpp.

44 : UART(&_read_port, &_write_port),
45 rx_buff_(new uint8_t[buffer_size]),
46 tx_buff_(new uint8_t[buffer_size]),
47 buff_size_(buffer_size),
48 _read_port(buffer_size),
49 _write_port(tx_queue_size, buffer_size)
50 {
51 ASSERT(buff_size_ > 0);
52
53 while (!std::filesystem::exists(dev_path))
54 {
55 XR_LOG_WARN("Cannot find UART device: %s, retrying...", dev_path);
56 Thread::Sleep(100);
57 }
58
59 device_path_ = GetByPathForTTY(dev_path);
60
61 fd_ = open(device_path_.c_str(), O_RDWR | O_NOCTTY);
62 if (fd_ < 0)
63 {
64 XR_LOG_ERROR("Cannot open UART device: %s", device_path_.c_str());
65 ASSERT(false);
66 }
67 else
68 {
69 XR_LOG_PASS("Open UART device: %s", device_path_.c_str());
70 }
71
72 config_ = {};
73 config_.baudrate = baudrate;
74 config_.parity = parity;
75 config_.data_bits = data_bits;
76 config_.stop_bits = stop_bits;
77
78 SetConfig(config_);
79
80 _read_port = ReadFun;
81 _write_port = WriteFun;
82
83 rx_thread_.Create<LinuxUART*>(
84 this, [](LinuxUART* self) { self->RxLoop(); }, "rx_uart", thread_stack_size,
86
87 tx_thread_.Create<LinuxUART*>(
88 this, [](LinuxUART* self) { self->TxLoop(); }, "tx_uart", thread_stack_size,
90 }
ErrorCode SetConfig(UART::Configuration config) override
设置 UART 配置 / Sets the UART configuration
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
@ REALTIME
实时优先级 Realtime priority
void Create(ArgType arg, void(*function)(ArgType arg), const char *name, size_t stack_depth, Thread::Priority priority)
创建新线程 Creates a new thread
Definition thread.hpp:68
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:66
ErrorCode(* ReadFun)(ReadPort &port, bool in_isr)
Function pointer type for read operations.
Definition libxr_rw.hpp:356
ErrorCode(* WriteFun)(WritePort &port, bool in_isr)
Function pointer type for write operations.
Definition libxr_rw.hpp:352
uint8_t stop_bits
停止位长度 / Number of stop bits
Definition uart.hpp:50
Parity parity
校验模式 / Parity mode
Definition uart.hpp:47
uint8_t data_bits
数据位长度 / Number of data bits
Definition uart.hpp:48
uint32_t baudrate
波特率 / Baud rate
Definition uart.hpp:45

◆ LinuxUART() [2/3]

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 构造 UART / Construct UART by USB VID/PID

Definition at line 95 of file linux_uart.hpp.

99 : LinuxUART(vid, pid, "", baudrate, parity, data_bits, stop_bits, tx_queue_size,
100 buffer_size, thread_stack_size)
101 {
102 }

◆ LinuxUART() [3/3]

LibXR::LinuxUART::LinuxUART ( const std::string & vid,
const std::string & pid,
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 VID/PID/序列号构造 UART / Construct UART by USB VID/PID/serial

Definition at line 107 of file linux_uart.hpp.

111 : UART(&_read_port, &_write_port),
112 rx_buff_(new uint8_t[buffer_size]),
113 tx_buff_(new uint8_t[buffer_size]),
114 buff_size_(buffer_size),
115 _read_port(buffer_size),
116 _write_port(tx_queue_size, buffer_size)
117 {
118 while (!FindUSBTTYByVidPid(vid, pid, serial, device_path_))
119 {
120 if (serial.empty())
121 {
122 XR_LOG_WARN("Cannot find USB TTY device with VID=%s PID=%s, retrying...",
123 vid.c_str(), pid.c_str());
124 }
125 else
126 {
127 XR_LOG_WARN("Cannot find USB TTY device with VID=%s PID=%s SERIAL=%s, retrying...",
128 vid.c_str(), pid.c_str(), serial.c_str());
129 }
130 Thread::Sleep(100);
131 }
132
133 XR_LOG_PASS("Found USB TTY: %s", device_path_.c_str());
134
135 if (std::filesystem::exists(device_path_) == false)
136 {
137 XR_LOG_ERROR("Cannot find UART device: %s", device_path_.c_str());
138 ASSERT(false);
139 return;
140 }
141
142 device_path_ = GetByPathForTTY(device_path_);
143
144 fd_ = open(device_path_.c_str(), O_RDWR | O_NOCTTY);
145 if (fd_ < 0)
146 {
147 XR_LOG_ERROR("Cannot open UART device: %s", device_path_.c_str());
148 ASSERT(false);
149 }
150 else
151 {
152 XR_LOG_PASS("Open UART device: %s", device_path_.c_str());
153 }
154
155 config_ = {};
156 config_.baudrate = baudrate;
157 config_.parity = parity;
158 config_.data_bits = data_bits;
159 config_.stop_bits = stop_bits;
160
161 SetConfig(config_);
162
163 _read_port = ReadFun;
164 _write_port = WriteFun;
165
166 rx_thread_.Create<LinuxUART*>(
167 this, [](LinuxUART* self) { self->RxLoop(); }, "rx_uart", thread_stack_size,
169
170 tx_thread_.Create<LinuxUART*>(
171 this, [](LinuxUART* self) { self->TxLoop(); }, "tx_uart", thread_stack_size,
173 }

Member Function Documentation

◆ FindUSBTTYByVidPid()

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

Definition at line 199 of file linux_uart.hpp.

202 {
203 struct udev* udev = udev_new();
204 if (!udev)
205 {
206 XR_LOG_ERROR("Cannot create udev context");
207 return false;
208 }
209
210 struct udev_enumerate* enumerate = udev_enumerate_new(udev);
211 udev_enumerate_add_match_subsystem(enumerate, "tty");
212 udev_enumerate_scan_devices(enumerate);
213
214 struct udev_list_entry* devices = udev_enumerate_get_list_entry(enumerate);
215 struct udev_list_entry* entry = nullptr;
216 std::vector<std::string> matches;
217
218 udev_list_entry_foreach(entry, devices)
219 {
220 const char* path = udev_list_entry_get_name(entry);
221 struct udev_device* tty_dev = udev_device_new_from_syspath(udev, path);
222 if (!tty_dev)
223 {
224 continue;
225 }
226
227 struct udev_device* usb_dev =
228 udev_device_get_parent_with_subsystem_devtype(tty_dev, "usb", "usb_device");
229
230 if (usb_dev)
231 {
232 const char* vid = udev_device_get_sysattr_value(usb_dev, "idVendor");
233 const char* pid = udev_device_get_sysattr_value(usb_dev, "idProduct");
234 const char* serial = udev_device_get_sysattr_value(usb_dev, "serial");
235
236 if (vid && pid && target_vid == vid && target_pid == pid &&
237 (target_serial.empty() || (serial && target_serial == serial)))
238 {
239 const char* devnode = udev_device_get_devnode(tty_dev);
240 if (devnode)
241 {
242 matches.emplace_back(devnode);
243 }
244 }
245 }
246
247 udev_device_unref(tty_dev);
248 }
249
250 udev_enumerate_unref(enumerate);
251 udev_unref(udev);
252 if (matches.empty())
253 {
254 return false;
255 }
256
257 std::sort(matches.begin(), matches.end());
258 tty_path = matches.front();
259
260 if (matches.size() > 1 && target_serial.empty())
261 {
262 XR_LOG_WARN(
263 "Multiple USB TTY devices found with VID=%s PID=%s, using %s. Specify serial to disambiguate.",
264 target_vid.c_str(), target_pid.c_str(), tty_path.c_str());
265 }
266
267 return true;
268 }

◆ GetByPathForTTY()

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

Definition at line 175 of file linux_uart.hpp.

176 {
177 const std::string BASE = "/dev/serial/by-path";
178 if (strncmp(tty_name.c_str(), BASE.c_str(), BASE.length()) == 0 ||
179 !std::filesystem::exists(BASE))
180 {
181 return tty_name;
182 }
183 for (const auto& entry : std::filesystem::directory_iterator(BASE))
184 {
185 std::error_code ec;
186 const auto full = std::filesystem::canonical(entry.path(), ec);
187 if (ec)
188 {
189 continue;
190 }
191 if (full == tty_name)
192 {
193 return entry.path().string(); // 返回符号链接路径
194 }
195 }
196 return tty_name; // 未命中 by-path 时保留原始 tty 路径
197 }

◆ ReadFun()

static ErrorCode LibXR::LinuxUART::ReadFun ( ReadPort & ,
bool  )
inlinestatic

Definition at line 389 of file linux_uart.hpp.

389{ return ErrorCode::EMPTY; }
@ EMPTY
为空 | Empty

◆ RxLoop()

void LibXR::LinuxUART::RxLoop ( )
inlineprivate

Definition at line 399 of file linux_uart.hpp.

400 {
401 while (true)
402 {
403 if (!connected_)
404 {
405 close(fd_);
406 fd_ = open(device_path_.c_str(), O_RDWR | O_NOCTTY);
407
408 if (fd_ < 0)
409 {
410 XR_LOG_WARN("Cannot open UART device: %s", device_path_.c_str());
411 Thread::Sleep(1000);
412 }
413 else
414 {
415 SetConfig(config_);
416 XR_LOG_PASS("Reopen UART device: %s", device_path_.c_str());
417 connected_ = true;
418 }
419 }
420 auto n = read(fd_, rx_buff_, buff_size_);
421 if (n > 0)
422 {
423 read_port_->queue_data_->PushBatch(rx_buff_, n);
425 }
426 else
427 {
428 XR_LOG_WARN("Cannot read UART device: %s", device_path_.c_str());
429 connected_ = false;
430 }
431 }
432 }
ErrorCode PushBatch(const Data *data, size_t size)
批量推入数据 / Pushes multiple elements into the queue
void ProcessPendingReads(bool in_isr)
Processes pending reads.
Definition libxr_rw.cpp:193
ReadPort * read_port_
读取端口 / Read port
Definition uart.hpp:53

◆ SetConfig()

ErrorCode LibXR::LinuxUART::SetConfig ( UART::Configuration config)
inlineoverridevirtual

设置 UART 配置 / Sets the UART configuration

Parameters
configUART 配置信息 / UART configuration settings
Returns
返回操作状态,成功时返回 ErrorCode::OK,否则返回相应错误码 / Returns the operation status, ErrorCode::OK if successful, otherwise an error code

该方法为纯虚函数,子类必须实现具体的 UART 配置逻辑。 This is a pure virtual function. Subclasses must implement the specific UART configuration logic.

Implements LibXR::UART.

Definition at line 278 of file linux_uart.hpp.

279 {
280 if (&config != &config_)
281 {
282 config_ = config;
283 }
284
285 struct termios2 tio{};
286 if (ioctl(fd_, TCGETS2, &tio) != 0)
287 {
288 return ErrorCode::INIT_ERR;
289 }
290
291 // 设置自定义波特率
292 tio.c_cflag &= ~CBAUD;
293 tio.c_cflag |= BOTHER;
294 tio.c_ispeed = config.baudrate;
295 tio.c_ospeed = config.baudrate;
296
297 // 输入模式:关闭软件流控、特殊字符处理
298 tio.c_iflag &= ~(IXON | IXOFF | IXANY | ISTRIP | IGNCR | INLCR | ICRNL
299#ifdef IUCLC
300 | IUCLC
301#endif
302 );
303
304 // 输出模式:关闭所有加工
305 tio.c_oflag &= ~(OPOST
306#ifdef ONLCR
307 | ONLCR
308#endif
309#ifdef OCRNL
310 | OCRNL
311#endif
312#ifdef ONOCR
313 | ONOCR
314#endif
315#ifdef ONLRET
316 | ONLRET
317#endif
318 );
319
320 // 本地模式:禁用行缓冲、回显、信号中断
321 tio.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
322
323 // 控制模式:设置数据位、校验、停止位、流控
324 tio.c_cflag &= ~CSIZE;
325 switch (config.data_bits)
326 {
327 case 5:
328 tio.c_cflag |= CS5;
329 break;
330 case 6:
331 tio.c_cflag |= CS6;
332 break;
333 case 7:
334 tio.c_cflag |= CS7;
335 break;
336 case 8:
337 tio.c_cflag |= CS8;
338 break;
339 default:
340 return ErrorCode::ARG_ERR;
341 }
342
343 // 停止位
344 tio.c_cflag &= ~CSTOPB;
345 if (config.stop_bits == 2)
346 {
347 tio.c_cflag |= CSTOPB;
348 }
349
350 // 奇偶校验
351 switch (config.parity)
352 {
354 tio.c_cflag &= ~PARENB;
355 break;
357 tio.c_cflag |= PARENB;
358 tio.c_cflag &= ~PARODD;
359 break;
361 tio.c_cflag |= PARENB;
362 tio.c_cflag |= PARODD;
363 break;
364 }
365
366 // 禁用硬件流控
367 tio.c_cflag &= ~CRTSCTS;
368
369 // 启用本地模式、读功能
370 tio.c_cflag |= (CLOCAL | CREAD);
371
372 // 控制字符配置:阻塞直到读到 1 字节
373 // for (int i = 0; i < NCCS; ++i) tio.c_cc[i] = 0;
374 tio.c_cc[VTIME] = 0;
375 tio.c_cc[VMIN] = 1;
376
377 if (ioctl(fd_, TCSETS2, &tio) != 0)
378 {
379 return ErrorCode::INIT_ERR;
380 }
381
382 SetLowLatency(fd_);
383
384 tcflush(fd_, TCIOFLUSH);
385
386 return ErrorCode::OK;
387 }
@ NO_PARITY
无校验 / No parity
@ ODD
奇校验 / Odd parity
@ EVEN
偶校验 / Even parity
@ INIT_ERR
初始化错误 | Initialization error
@ OK
操作成功 | Operation successful
@ ARG_ERR
参数错误 | Argument error

◆ SetLowLatency()

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

Definition at line 270 of file linux_uart.hpp.

271 {
272 struct serial_struct serinfo;
273 ioctl(fd, TIOCGSERIAL, &serinfo);
274 serinfo.flags |= ASYNC_LOW_LATENCY;
275 ioctl(fd, TIOCSSERIAL, &serinfo);
276 }

◆ TxLoop()

void LibXR::LinuxUART::TxLoop ( )
inlineprivate

Definition at line 434 of file linux_uart.hpp.

435 {
436 WriteInfoBlock info;
437 while (true)
438 {
439 if (!connected_)
440 {
441 Thread::Sleep(1);
442 continue;
443 }
444
445 if (write_sem_.Wait() != ErrorCode::OK)
446 {
447 continue;
448 }
449
450 if (write_port_->queue_info_->Pop(info) == ErrorCode::OK)
451 {
452 if (write_port_->queue_data_->PopBatch(tx_buff_, info.data.size_) ==
454 {
455 auto written = write(fd_, tx_buff_, info.data.size_);
456 if (written < 0)
457 {
458 XR_LOG_WARN("Cannot write UART device: %s", device_path_.c_str());
459 connected_ = false;
460 }
461 write_port_->Finish(false,
462 (written == static_cast<int>(info.data.size_))
465 info);
466 }
467 else
468 {
469 info.op.UpdateStatus(false, ErrorCode::FAILED);
470 }
471 }
472 }
473 }
ErrorCode PopBatch(Data *data, size_t size)
批量弹出数据 / Pops multiple elements from the queue
ErrorCode Wait(uint32_t timeout=UINT32_MAX)
等待(减少)信号量 Waits (decrements) the semaphore
Definition semaphore.cpp:53
WritePort * write_port_
写入端口 / Write port
Definition uart.hpp:54
void Finish(bool in_isr, ErrorCode ans, WriteInfoBlock &info)
更新写入操作的状态。 Updates the status of the write operation.
Definition libxr_rw.cpp:294
@ FAILED
操作失败 | Operation failed

◆ WriteFun()

static ErrorCode LibXR::LinuxUART::WriteFun ( WritePort & port,
bool  )
inlinestatic

Definition at line 391 of file linux_uart.hpp.

392 {
393 auto uart = CONTAINER_OF(&port, LinuxUART, _write_port);
394 uart->write_sem_.Post();
395 return ErrorCode::OK;
396 }

Field Documentation

◆ _read_port

ReadPort LibXR::LinuxUART::_read_port
private

Definition at line 487 of file linux_uart.hpp.

◆ _write_port

WritePort LibXR::LinuxUART::_write_port
private

Definition at line 488 of file linux_uart.hpp.

◆ buff_size_

size_t LibXR::LinuxUART::buff_size_ = 0
private

Definition at line 483 of file linux_uart.hpp.

◆ config_

Configuration LibXR::LinuxUART::config_
private

Definition at line 477 of file linux_uart.hpp.

◆ connected_

bool LibXR::LinuxUART::connected_ = true
private

Definition at line 476 of file linux_uart.hpp.

◆ device_path_

std::string LibXR::LinuxUART::device_path_
private

Definition at line 478 of file linux_uart.hpp.

◆ fd_

int LibXR::LinuxUART::fd_ = -1
private

Definition at line 475 of file linux_uart.hpp.

◆ read_mutex_

Mutex LibXR::LinuxUART::read_mutex_
private

Definition at line 485 of file linux_uart.hpp.

◆ rx_buff_

uint8_t* LibXR::LinuxUART::rx_buff_ = nullptr
private

Definition at line 481 of file linux_uart.hpp.

◆ rx_thread_

Thread LibXR::LinuxUART::rx_thread_
private

Definition at line 479 of file linux_uart.hpp.

◆ tx_buff_

uint8_t* LibXR::LinuxUART::tx_buff_ = nullptr
private

Definition at line 482 of file linux_uart.hpp.

◆ tx_thread_

Thread LibXR::LinuxUART::tx_thread_
private

Definition at line 480 of file linux_uart.hpp.

◆ write_sem_

Semaphore LibXR::LinuxUART::write_sem_
private

Definition at line 484 of file linux_uart.hpp.


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