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
 
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, std::string &tty_path)
 
static ErrorCode ReadFun (ReadPort &)
 
static ErrorCode WriteFun (WritePort &port)
 

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 自动发现并创建 UART 通道。 Supports UART creation by device path or USB VID/PID auto discovery.

Definition at line 32 of file linux_uart.hpp.

Constructor & Destructor Documentation

◆ LinuxUART() [1/2]

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 38 of file linux_uart.hpp.

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)
48 {
49 ASSERT(buff_size_ > 0);
50
51 while (!std::filesystem::exists(dev_path))
52 {
53 XR_LOG_WARN("Cannot find UART device: %s, retrying...", dev_path);
54 Thread::Sleep(100);
55 }
56
57 device_path_ = GetByPathForTTY(dev_path);
58
59 fd_ = open(device_path_.c_str(), O_RDWR | O_NOCTTY);
60 if (fd_ < 0)
61 {
62 XR_LOG_ERROR("Cannot open UART device: %s", device_path_.c_str());
63 ASSERT(false);
64 }
65 else
66 {
67 XR_LOG_PASS("Open UART device: %s", device_path_.c_str());
68 }
69
70 config_ = {.baudrate = baudrate,
71 .parity = parity,
72 .data_bits = data_bits,
73 .stop_bits = stop_bits};
74
75 SetConfig(config_);
76
77 _read_port = ReadFun;
78 _write_port = WriteFun;
79
80 rx_thread_.Create<LinuxUART*>(
81 this, [](LinuxUART* self) { self->RxLoop(); }, "rx_uart", thread_stack_size,
83
84 tx_thread_.Create<LinuxUART*>(
85 this, [](LinuxUART* self) { self->TxLoop(); }, "tx_uart", thread_stack_size,
87 }
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:66
static void Sleep(uint32_t milliseconds)
让线程进入休眠状态 Puts the thread to sleep
Definition thread.cpp:16
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:249
ErrorCode(* WriteFun)(WritePort &port, bool in_isr)
Function pointer type for write operations.
Definition libxr_rw.hpp:245

◆ LinuxUART() [2/2]

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 92 of file linux_uart.hpp.

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)
102 {
103 while (!FindUSBTTYByVidPid(vid, pid, device_path_))
104 {
105 XR_LOG_WARN("Cannot find USB TTY device with VID=%s PID=%s, retrying...",
106 vid.c_str(), pid.c_str());
107 Thread::Sleep(100);
108 }
109
110 XR_LOG_PASS("Found USB TTY: %s", device_path_.c_str());
111
112 if (std::filesystem::exists(device_path_) == false)
113 {
114 XR_LOG_ERROR("Cannot find UART device: %s", device_path_.c_str());
115 ASSERT(false);
116 return;
117 }
118
119 device_path_ = GetByPathForTTY(device_path_);
120
121 fd_ = open(device_path_.c_str(), O_RDWR | O_NOCTTY);
122 if (fd_ < 0)
123 {
124 XR_LOG_ERROR("Cannot open UART device: %s", device_path_.c_str());
125 ASSERT(false);
126 }
127 else
128 {
129 XR_LOG_PASS("Open UART device: %s", device_path_.c_str());
130 }
131
132 config_ = {.baudrate = baudrate,
133 .parity = parity,
134 .data_bits = data_bits,
135 .stop_bits = stop_bits};
136
137 SetConfig(config_);
138
139 _read_port = ReadFun;
140 _write_port = WriteFun;
141
142 rx_thread_.Create<LinuxUART*>(
143 this, [](LinuxUART* self) { self->RxLoop(); }, "rx_uart", thread_stack_size,
145
146 tx_thread_.Create<LinuxUART*>(
147 this, [](LinuxUART* self) { self->TxLoop(); }, "tx_uart", thread_stack_size,
149 }

Member Function Documentation

◆ FindUSBTTYByVidPid()

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

Definition at line 170 of file linux_uart.hpp.

172 {
173 struct udev* udev = udev_new();
174 if (!udev)
175 {
176 XR_LOG_ERROR("Cannot create udev context");
177 return false;
178 }
179
180 struct udev_enumerate* enumerate = udev_enumerate_new(udev);
181 udev_enumerate_add_match_subsystem(enumerate, "tty");
182 udev_enumerate_scan_devices(enumerate);
183
184 struct udev_list_entry* devices = udev_enumerate_get_list_entry(enumerate);
185 struct udev_list_entry* entry = nullptr;
186 bool found = false;
187
188 udev_list_entry_foreach(entry, devices)
189 {
190 const char* path = udev_list_entry_get_name(entry);
191 struct udev_device* tty_dev = udev_device_new_from_syspath(udev, path);
192 if (!tty_dev)
193 {
194 continue;
195 }
196
197 struct udev_device* usb_dev =
198 udev_device_get_parent_with_subsystem_devtype(tty_dev, "usb", "usb_device");
199
200 if (usb_dev)
201 {
202 const char* vid = udev_device_get_sysattr_value(usb_dev, "idVendor");
203 const char* pid = udev_device_get_sysattr_value(usb_dev, "idProduct");
204
205 if (vid && pid && target_vid == vid && target_pid == pid)
206 {
207 const char* devnode = udev_device_get_devnode(tty_dev);
208 if (devnode)
209 {
210 tty_path = devnode;
211 found = true;
212 udev_device_unref(tty_dev);
213 break;
214 }
215 }
216 }
217
218 udev_device_unref(tty_dev);
219 }
220
221 udev_enumerate_unref(enumerate);
222 udev_unref(udev);
223 return found;
224 }

◆ GetByPathForTTY()

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

Definition at line 151 of file linux_uart.hpp.

152 {
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))
156 {
157 return tty_name;
158 }
159 for (const auto& entry : std::filesystem::directory_iterator(BASE))
160 {
161 std::string full = std::filesystem::canonical(entry.path());
162 if (full == tty_name)
163 {
164 return entry.path(); // 返回符号链接路径
165 }
166 }
167 return ""; // 没找到
168 }

◆ ReadFun()

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

Definition at line 345 of file linux_uart.hpp.

345{ return ErrorCode::EMPTY; }

◆ RxLoop()

void LibXR::LinuxUART::RxLoop ( )
inlineprivate

Definition at line 355 of file linux_uart.hpp.

356 {
357 while (true)
358 {
359 if (!connected_)
360 {
361 close(fd_);
362 fd_ = open(device_path_.c_str(), O_RDWR | O_NOCTTY);
363
364 if (fd_ < 0)
365 {
366 XR_LOG_WARN("Cannot open UART device: %s", device_path_.c_str());
367 Thread::Sleep(1000);
368 }
369 else
370 {
371 SetConfig(config_);
372 XR_LOG_PASS("Reopen UART device: %s", device_path_.c_str());
373 connected_ = true;
374 }
375 }
376 auto n = read(fd_, rx_buff_, buff_size_);
377 if (n > 0)
378 {
379 read_port_->queue_data_->PushBatch(rx_buff_, n);
381 }
382 else
383 {
384 XR_LOG_WARN("Cannot read UART device: %s", device_path_.c_str());
385 connected_ = false;
386 }
387 }
388 }
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:127
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 234 of file linux_uart.hpp.

235 {
236 if (&config != &config_)
237 {
238 config_ = config;
239 }
240
241 struct termios2 tio{};
242 if (ioctl(fd_, TCGETS2, &tio) != 0)
243 {
244 return ErrorCode::INIT_ERR;
245 }
246
247 // 设置自定义波特率
248 tio.c_cflag &= ~CBAUD;
249 tio.c_cflag |= BOTHER;
250 tio.c_ispeed = config.baudrate;
251 tio.c_ospeed = config.baudrate;
252
253 // 输入模式:关闭软件流控、特殊字符处理
254 tio.c_iflag &= ~(IXON | IXOFF | IXANY | ISTRIP | IGNCR | INLCR | ICRNL
255#ifdef IUCLC
256 | IUCLC
257#endif
258 );
259
260 // 输出模式:关闭所有加工
261 tio.c_oflag &= ~(OPOST
262#ifdef ONLCR
263 | ONLCR
264#endif
265#ifdef OCRNL
266 | OCRNL
267#endif
268#ifdef ONOCR
269 | ONOCR
270#endif
271#ifdef ONLRET
272 | ONLRET
273#endif
274 );
275
276 // 本地模式:禁用行缓冲、回显、信号中断
277 tio.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
278
279 // 控制模式:设置数据位、校验、停止位、流控
280 tio.c_cflag &= ~CSIZE;
281 switch (config.data_bits)
282 {
283 case 5:
284 tio.c_cflag |= CS5;
285 break;
286 case 6:
287 tio.c_cflag |= CS6;
288 break;
289 case 7:
290 tio.c_cflag |= CS7;
291 break;
292 case 8:
293 tio.c_cflag |= CS8;
294 break;
295 default:
296 return ErrorCode::ARG_ERR;
297 }
298
299 // 停止位
300 tio.c_cflag &= ~CSTOPB;
301 if (config.stop_bits == 2)
302 {
303 tio.c_cflag |= CSTOPB;
304 }
305
306 // 奇偶校验
307 switch (config.parity)
308 {
310 tio.c_cflag &= ~PARENB;
311 break;
313 tio.c_cflag |= PARENB;
314 tio.c_cflag &= ~PARODD;
315 break;
317 tio.c_cflag |= PARENB;
318 tio.c_cflag |= PARODD;
319 break;
320 }
321
322 // 禁用硬件流控
323 tio.c_cflag &= ~CRTSCTS;
324
325 // 启用本地模式、读功能
326 tio.c_cflag |= (CLOCAL | CREAD);
327
328 // 控制字符配置:阻塞直到读到 1 字节
329 // for (int i = 0; i < NCCS; ++i) tio.c_cc[i] = 0;
330 tio.c_cc[VTIME] = 0;
331 tio.c_cc[VMIN] = 1;
332
333 if (ioctl(fd_, TCSETS2, &tio) != 0)
334 {
335 return ErrorCode::INIT_ERR;
336 }
337
338 SetLowLatency(fd_);
339
340 tcflush(fd_, TCIOFLUSH);
341
342 return ErrorCode::OK;
343 }
@ NO_PARITY
无校验 / No parity
@ ODD
奇校验 / Odd parity
@ EVEN
偶校验 / Even parity

◆ SetLowLatency()

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

Definition at line 226 of file linux_uart.hpp.

227 {
228 struct serial_struct serinfo;
229 ioctl(fd, TIOCGSERIAL, &serinfo);
230 serinfo.flags |= ASYNC_LOW_LATENCY;
231 ioctl(fd, TIOCSSERIAL, &serinfo);
232 }

◆ TxLoop()

void LibXR::LinuxUART::TxLoop ( )
inlineprivate

Definition at line 390 of file linux_uart.hpp.

391 {
392 WriteInfoBlock info;
393 while (true)
394 {
395 if (!connected_)
396 {
397 Thread::Sleep(1);
398 continue;
399 }
400
401 if (write_sem_.Wait() != ErrorCode::OK)
402 {
403 continue;
404 }
405
406 if (write_port_->queue_info_->Pop(info) == ErrorCode::OK)
407 {
408 if (write_port_->queue_data_->PopBatch(tx_buff_, info.data.size_) ==
409 ErrorCode::OK)
410 {
411 auto written = write(fd_, tx_buff_, info.data.size_);
412 if (written < 0)
413 {
414 XR_LOG_WARN("Cannot write UART device: %s", device_path_.c_str());
415 connected_ = false;
416 }
417 write_port_->Finish(false,
418 (written == static_cast<int>(info.data.size_))
419 ? ErrorCode::OK
420 : ErrorCode::FAILED,
421 info, written);
422 }
423 else
424 {
425 info.op.UpdateStatus(false, ErrorCode::FAILED);
426 }
427 }
428 }
429 }
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:25
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:191

◆ WriteFun()

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

Definition at line 347 of file linux_uart.hpp.

348 {
349 auto uart = CONTAINER_OF(&port, LinuxUART, _write_port);
350 uart->write_sem_.Post();
351 return ErrorCode::OK;
352 }

Field Documentation

◆ _read_port

ReadPort LibXR::LinuxUART::_read_port
private

Definition at line 443 of file linux_uart.hpp.

◆ _write_port

WritePort LibXR::LinuxUART::_write_port
private

Definition at line 444 of file linux_uart.hpp.

◆ buff_size_

size_t LibXR::LinuxUART::buff_size_ = 0
private

Definition at line 439 of file linux_uart.hpp.

◆ config_

Configuration LibXR::LinuxUART::config_
private

Definition at line 433 of file linux_uart.hpp.

◆ connected_

bool LibXR::LinuxUART::connected_ = true
private

Definition at line 432 of file linux_uart.hpp.

◆ device_path_

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

Definition at line 434 of file linux_uart.hpp.

◆ fd_

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

Definition at line 431 of file linux_uart.hpp.

◆ read_mutex_

Mutex LibXR::LinuxUART::read_mutex_
private

Definition at line 441 of file linux_uart.hpp.

◆ rx_buff_

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

Definition at line 437 of file linux_uart.hpp.

◆ rx_thread_

Thread LibXR::LinuxUART::rx_thread_
private

Definition at line 435 of file linux_uart.hpp.

◆ tx_buff_

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

Definition at line 438 of file linux_uart.hpp.

◆ tx_thread_

Thread LibXR::LinuxUART::tx_thread_
private

Definition at line 436 of file linux_uart.hpp.

◆ write_sem_

Semaphore LibXR::LinuxUART::write_sem_
private

Definition at line 440 of file linux_uart.hpp.


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