libxr  1.0
Want to be the best embedded framework
Loading...
Searching...
No Matches
libxr_rw.hpp
1#pragma once
2
3#include <atomic>
4#include <cstdarg>
5#include <cstddef>
6#include <cstdint>
7#include <cstdio>
8#include <utility>
9
10#include "libxr_cb.hpp"
11#include "libxr_def.hpp"
12#include "libxr_mem.hpp"
13#include "libxr_type.hpp"
14#include "lockfree_queue.hpp"
15#include "mutex.hpp"
16#include "semaphore.hpp"
17
18namespace LibXR
19{
20
28template <typename Args>
30{
31 public:
33
36 enum class OperationType : uint8_t
37 {
38 CALLBACK,
39 BLOCK,
40 POLLING,
41 NONE
42 };
43
46 enum class OperationPollingStatus : uint8_t
47 {
48 READY,
49 RUNNING,
50 DONE,
51 ERROR
52 };
53
56 Operation() : type(OperationType::NONE) { Memory::FastSet(&data, 0, sizeof(data)); }
57
69 Operation(Semaphore& sem, uint32_t timeout = UINT32_MAX) : type(OperationType::BLOCK)
70 {
71 data.sem_info.sem = &sem;
72 data.sem_info.timeout = timeout;
73 }
74
80 Operation(Callback& callback) : type(OperationType::CALLBACK)
81 {
82 data.callback = &callback;
83 }
84
91 {
92 data.status = &status;
93 }
94
102 {
103 if (this != &op)
104 {
105 type = op.type;
106 switch (type)
107 {
108 case OperationType::CALLBACK:
109 data.callback = op.data.callback;
110 break;
111 case OperationType::BLOCK:
112 data.sem_info.sem = op.data.sem_info.sem;
113 data.sem_info.timeout = op.data.sem_info.timeout;
114 break;
115 case OperationType::POLLING:
116 data.status = op.data.status;
117 break;
118 case OperationType::NONE:
119 break;
120 }
121 }
122 return *this;
123 }
124
132 {
133 if (this != &op)
134 {
135 type = op.type;
136 switch (type)
137 {
138 case OperationType::CALLBACK:
139 data.callback = op.data.callback;
140 break;
141 case OperationType::BLOCK:
142 data.sem_info.sem = op.data.sem_info.sem;
143 data.sem_info.timeout = op.data.sem_info.timeout;
144 break;
145 case OperationType::POLLING:
146 data.status = op.data.status;
147 break;
148 case OperationType::NONE:
149 break;
150 }
151 }
152 return *this;
153 }
154
163 template <
164 typename InitOperation,
165 typename = std::enable_if_t<std::is_same_v<std::decay_t<InitOperation>, Operation>>>
166 Operation(InitOperation&& op)
167 {
168 *this = std::forward<InitOperation>(op);
169 }
170
177 template <typename Status>
178 void UpdateStatus(bool in_isr, Status&& status)
179 {
180 switch (type)
181 {
182 case OperationType::CALLBACK:
183 data.callback->Run(in_isr, std::forward<Status>(status));
184 break;
185 case OperationType::BLOCK:
186 // BLOCK waits are signaled by semaphore only; the owning port keeps the
187 // final ErrorCode in its block_result_ handoff state.
188 // BLOCK 只通过信号量唤醒;最终 ErrorCode 由端口侧 block_result_ 交接。
189 data.sem_info.sem->PostFromCallback(in_isr);
190 break;
191 case OperationType::POLLING:
192 *data.status = (status == ErrorCode::OK) ? OperationPollingStatus::DONE
193 : OperationPollingStatus::ERROR;
194 break;
195 case OperationType::NONE:
196 break;
197 }
198 }
199
214 {
215 if (type == OperationType::POLLING)
216 {
217 *data.status = OperationPollingStatus::RUNNING;
218 }
219 }
220
223 union
224 {
225 Callback* callback;
226 struct
227 {
228 Semaphore* sem;
229 uint32_t timeout;
230 } sem_info;
232 // TODO: state
234
238};
239
247{
248 public:
249 // Keep the waiter state 32-bit wide so STM32 builds stay within the
250 // project-wide atomic shim boundary.
251 enum class State : uint32_t
252 {
253 IDLE = 0,
254 PENDING = 1,
255 CLAIMED = 2,
256 DETACHED = 3,
257 };
258
259 void Start(Semaphore& sem)
260 {
261 sem_ = &sem;
262 result_ = ErrorCode::OK;
263 state_.store(State::PENDING, std::memory_order_release);
264 }
265
266 void Cancel() { state_.store(State::IDLE, std::memory_order_release); }
267
268 ErrorCode Wait(uint32_t timeout)
269 {
270 ASSERT(sem_ != nullptr);
271 auto wait_ans = sem_->Wait(timeout);
272 if (wait_ans == ErrorCode::OK)
273 {
274#ifdef LIBXR_DEBUG_BUILD
275 ASSERT(state_.load(std::memory_order_acquire) == State::CLAIMED);
276#endif
277 state_.store(State::IDLE, std::memory_order_release);
278 return result_;
279 }
280
281 State expected = State::PENDING;
282 if (state_.compare_exchange_strong(expected, State::DETACHED,
283 std::memory_order_acq_rel,
284 std::memory_order_acquire))
285 {
286 return ErrorCode::TIMEOUT;
287 }
288
289 ASSERT(expected == State::CLAIMED || expected == State::DETACHED ||
290 expected == State::IDLE);
291 if (expected == State::DETACHED)
292 {
293 state_.store(State::IDLE, std::memory_order_release);
294 return ErrorCode::TIMEOUT;
295 }
296 if (expected == State::IDLE)
297 {
298 return ErrorCode::TIMEOUT;
299 }
300
301 auto finish_wait_ans = sem_->Wait(UINT32_MAX);
302 UNUSED(finish_wait_ans);
303 ASSERT(finish_wait_ans == ErrorCode::OK);
304 state_.store(State::IDLE, std::memory_order_release);
305 return result_;
306 }
307
308 bool TryPost(bool in_isr, ErrorCode ec)
309 {
310 ASSERT(sem_ != nullptr);
311
312 State expected = State::PENDING;
313 if (!state_.compare_exchange_strong(expected, State::CLAIMED,
314 std::memory_order_acq_rel,
315 std::memory_order_acquire))
316 {
317 ASSERT(expected == State::DETACHED || expected == State::IDLE);
318 if (expected == State::DETACHED)
319 {
320 expected = State::DETACHED;
321 (void)state_.compare_exchange_strong(expected, State::IDLE,
322 std::memory_order_acq_rel,
323 std::memory_order_acquire);
324 }
325 return false;
326 }
327
328 result_ = ec;
329 sem_->PostFromCallback(in_isr);
330 return true;
331 }
332
333 private:
334 Semaphore* sem_ = nullptr;
335 std::atomic<State> state_{State::IDLE};
336 ErrorCode result_ = ErrorCode::OK;
337};
338
339class ReadPort;
340class WritePort;
341
345
349
352typedef ErrorCode (*WriteFun)(WritePort& port, bool in_isr);
353
356typedef ErrorCode (*ReadFun)(ReadPort& port, bool in_isr);
357
367
373
379{
380 public:
381 // Read BLOCK states:
382 // PENDING = waiting for queue-fed completion
383 // BLOCK_CLAIMED = wakeup now belongs to the waiter
384 // BLOCK_DETACHED = timeout/reset detached the waiter
385 // The same semaphore may be reused only after the previous BLOCK call
386 // returns and the port goes back to IDLE.
387 // 读 BLOCK 状态:
388 // PENDING = 等待队列侧完成
389 // BLOCK_CLAIMED = 唤醒已经归当前 waiter 所有
390 // BLOCK_DETACHED = timeout/reset 已把 waiter 分离
391 // 同一个信号量只能在上一次 BLOCK 调用返回、端口回到 IDLE 后复用。
392 enum class BusyState : uint32_t
393 {
394 IDLE = 0,
395 PENDING = 1,
397 BLOCK_CLAIMED = 2,
399 BLOCK_DETACHED = 3,
401 EVENT = UINT32_MAX
403 };
404
405 ReadFun read_fun_ = nullptr;
406 LockFreeQueue<uint8_t>* queue_data_ = nullptr;
407 ReadInfoBlock info_;
408 std::atomic<BusyState> busy_{BusyState::IDLE};
410
420 ReadPort(size_t buffer_size = 128);
421
432 size_t EmptySize();
433
444 size_t Size();
445
448 bool Readable();
449
464
476 void Finish(bool in_isr, ErrorCode ans, ReadInfoBlock& info);
477
488 void MarkAsRunning(ReadInfoBlock& info);
489
508 ErrorCode operator()(RawData data, ReadOperation& op, bool in_isr = false);
509
517 virtual void OnRxDequeue(bool) {}
518
526 void ProcessPendingReads(bool in_isr);
527
530 void Reset();
531};
532
538{
539 public:
540 // Write BLOCK states:
541 // LOCKED = submit path owns queue mutation
542 // BLOCK_WAITING = waiter armed, completion not claimed yet
543 // BLOCK_CLAIMED = final wakeup belongs to the waiter
544 // BLOCK_DETACHED = timeout/reset detached the waiter
545 // The same semaphore may be reused only after the previous BLOCK call
546 // returns and the port goes back to IDLE.
547 // 写 BLOCK 状态:
548 // LOCKED = 提交路径占有队列修改权
549 // BLOCK_WAITING = waiter 已挂起,完成尚未 claim
550 // BLOCK_CLAIMED = 最终唤醒已经归 waiter 所有
551 // BLOCK_DETACHED = timeout/reset 已把 waiter 分离
552 // 同一个信号量只能在上一次 BLOCK 调用返回、端口回到 IDLE 后复用。
553 enum class BusyState : uint32_t
554 {
555 LOCKED =
556 0,
557 BLOCK_WAITING = 1,
560 2,
561 BLOCK_DETACHED = 3,
563 IDLE = UINT32_MAX
565 };
566
567 WriteFun write_fun_ = nullptr;
569 LockFreeQueue<uint8_t>* queue_data_;
570 std::atomic<BusyState> busy_{BusyState::IDLE};
572
584 class Stream
585 {
586 public:
594
600 ~Stream();
601
608 Stream& operator<<(const ConstRawData& data);
609
623
624 private:
627 size_t cap_;
628 size_t size_ = 0;
629 bool locked_ = false;
630 };
631
648 WritePort(size_t queue_size = 3, size_t buffer_size = 128);
649
657 size_t EmptySize();
658
666 size_t Size();
667
675 bool Writable();
676
691
707 void Finish(bool in_isr, ErrorCode ans, WriteInfoBlock& info);
708
720
739 ErrorCode operator()(ConstRawData data, WriteOperation& op, bool in_isr = false);
740
743 void Reset();
744
759 ErrorCode CommitWrite(ConstRawData data, WriteOperation& op, bool pushed = false,
760 bool in_isr = false);
761};
762
767class STDIO
768{
769 public:
770 // NOLINTBEGIN
771 static inline ReadPort* read_ = nullptr;
772 static inline WritePort* write_ = nullptr;
773 static inline LibXR::Mutex* write_mutex_ =
774 nullptr;
775 static inline LibXR::WritePort::Stream* write_stream_ = nullptr;
776#if LIBXR_PRINTF_BUFFER_SIZE > 0
777 static inline char
778 printf_buff_[LIBXR_PRINTF_BUFFER_SIZE];
779#endif
780 // NOLINTEND
781
791 static int Printf(const char* fmt, ...); // NOLINT
792};
793} // namespace LibXR
Shared BLOCK waiter handoff for synchronous driver operations.
Definition libxr_rw.hpp:247
通用回调包装,支持动态参数传递 / Generic callback wrapper supporting dynamic argument passing
Definition libxr_cb.hpp:142
常量原始数据封装类。 A class for encapsulating constant raw data.
无锁队列实现 / Lock-free queue implementation
static void FastSet(void *dst, uint8_t value, size_t size)
快速内存填充 / Fast memory fill
互斥锁类,提供线程同步机制 (Mutex class providing thread synchronization mechanisms).
Definition mutex.hpp:18
Defines an operation with different execution modes.
Definition libxr_rw.hpp:30
Operation & operator=(const Operation &op)
Copy assignment operator.
Definition libxr_rw.hpp:101
Operation(Semaphore &sem, uint32_t timeout=UINT32_MAX)
Constructs a blocking operation with a semaphore and timeout.
Definition libxr_rw.hpp:69
Operation & operator=(Operation &&op) noexcept
Move assignment operator.
Definition libxr_rw.hpp:131
Operation(Callback &callback)
Constructs a callback-based operation.
Definition libxr_rw.hpp:80
union LibXR::Operation::@5 data
Operation()
Default constructor, initializes with NONE type.
Definition libxr_rw.hpp:56
void UpdateStatus(bool in_isr, Status &&status)
Updates operation status based on type.
Definition libxr_rw.hpp:178
void MarkAsRunning()
标记操作为运行状态。 Marks the operation as running.
Definition libxr_rw.hpp:213
OperationType type
Definition libxr_rw.hpp:237
Operation(OperationPollingStatus &status)
Constructs a polling operation.
Definition libxr_rw.hpp:90
Operation(InitOperation &&op)
构造一个新的 Operation 对象(初始化操作)。 Constructs a new Operation object (initialization operation).
Definition libxr_rw.hpp:166
原始数据封装类。 A class for encapsulating raw data.
ReadPort class for handling read operations.
Definition libxr_rw.hpp:379
bool Readable()
Checks if read operations are supported.
Definition libxr_rw.cpp:30
void Finish(bool in_isr, ErrorCode ans, ReadInfoBlock &info)
更新读取操作的状态。 Updates the status of the read operation.
Definition libxr_rw.cpp:38
ReadPort(size_t buffer_size=128)
Constructs a ReadPort with queue sizes.
Definition libxr_rw.cpp:11
void Reset()
Resets the ReadPort.
Definition libxr_rw.cpp:235
ErrorCode block_result_
Final status for the current BLOCK read.
Definition libxr_rw.hpp:409
@ IDLE
No active waiter and no pending completion. 无等待者、无挂起完成。
size_t EmptySize()
获取队列的剩余可用空间。 Gets the remaining available space in the queue.
Definition libxr_rw.cpp:18
ErrorCode operator()(RawData data, ReadOperation &op, bool in_isr=false)
读取操作符重载,用于执行读取操作。 Overloaded function call operator to perform a read operation.
Definition libxr_rw.cpp:68
void ProcessPendingReads(bool in_isr)
Processes pending reads.
Definition libxr_rw.cpp:193
ReadPort & operator=(ReadFun fun)
赋值运算符重载,用于设置读取函数。 Overloaded assignment operator to set the read function.
Definition libxr_rw.cpp:32
size_t Size()
获取当前队列的已使用大小。 Gets the currently used size of the queue.
Definition libxr_rw.cpp:24
virtual void OnRxDequeue(bool)
RX 数据从软件队列成功出队后的通知。 Notification after bytes are popped from RX data queue.
Definition libxr_rw.hpp:517
void MarkAsRunning(ReadInfoBlock &info)
标记读取操作为运行中。 Marks the read operation as running.
Definition libxr_rw.cpp:66
STDIO interface for read/write ports.
Definition libxr_rw.hpp:768
static int Printf(const char *fmt,...)
Prints a formatted string to the write port (like printf).
Definition libxr_rw.cpp:603
static LibXR::Mutex * write_mutex_
Write port mutex. 写入端口互斥锁。
Definition libxr_rw.hpp:773
static ReadPort * read_
Read port instance. 读取端口。
Definition libxr_rw.hpp:771
static WritePort * write_
Write port instance. 写入端口。
Definition libxr_rw.hpp:772
信号量类,实现线程同步机制 Semaphore class implementing thread synchronization
Definition semaphore.hpp:23
void PostFromCallback(bool in_isr)
从中断回调中释放(增加)信号量 Releases (increments) the semaphore from an ISR (Interrupt Service Routine)
ErrorCode Wait(uint32_t timeout=UINT32_MAX)
等待(减少)信号量 Waits (decrements) the semaphore
Definition semaphore.cpp:53
WritePort 的流式写入操作器,支持链式 << 操作和批量提交。
Definition libxr_rw.hpp:585
bool locked_
是否持有写锁 Whether write lock is held
Definition libxr_rw.hpp:629
size_t size_
当前已写入但未提交的字节数 Bytes written but not yet committed
Definition libxr_rw.hpp:628
ErrorCode Commit()
手动提交已写入的数据到队列,并释放当前锁。
Definition libxr_rw.cpp:572
size_t cap_
当前队列容量 Current queue capacity
Definition libxr_rw.hpp:627
LibXR::WritePort * port_
写端口指针 Pointer to the WritePort
Definition libxr_rw.hpp:625
LibXR::WriteOperation op_
写操作对象 Write operation object
Definition libxr_rw.hpp:626
~Stream()
析构时自动提交已累积的数据并释放锁。
Definition libxr_rw.cpp:519
Stream(LibXR::WritePort *port, LibXR::WriteOperation op)
构造流写入对象,并尝试锁定端口。
Definition libxr_rw.cpp:498
Stream & operator<<(const ConstRawData &data)
追加写入数据,支持链式调用。
Definition libxr_rw.cpp:540
WritePort class for handling write operations.
Definition libxr_rw.hpp:538
size_t EmptySize()
获取数据队列的剩余可用空间。 Gets the remaining available space in the data queue.
Definition libxr_rw.cpp:274
size_t Size()
获取当前数据队列的已使用大小。 Gets the used size of the current data queue.
Definition libxr_rw.cpp:280
void Finish(bool in_isr, ErrorCode ans, WriteInfoBlock &info)
更新写入操作的状态。 Updates the status of the write operation.
Definition libxr_rw.cpp:294
ErrorCode block_result_
Final status for the current BLOCK write.
Definition libxr_rw.hpp:571
WritePort(size_t queue_size=3, size_t buffer_size=128)
构造一个新的 WritePort 对象。 Constructs a new WritePort object.
Definition libxr_rw.cpp:265
WritePort & operator=(WriteFun fun)
赋值运算符重载,用于设置写入函数。 Overloaded assignment operator to set the write function.
Definition libxr_rw.cpp:288
@ BLOCK_CLAIMED
Final wakeup belongs to the current waiter. 最终唤醒已归当前等待者所有。
@ LOCKED
Submission path owns queue mutation. 提交路径占有写队列/元数据修改权。
bool Writable()
判断端口是否可写。 Checks whether the port is writable.
Definition libxr_rw.cpp:286
ErrorCode CommitWrite(ConstRawData data, WriteOperation &op, bool pushed=false, bool in_isr=false)
提交写入操作。 Commits a write operation.
Definition libxr_rw.cpp:356
void MarkAsRunning(WriteOperation &op)
标记写入操作为运行中。 Marks the write operation as running.
Definition libxr_rw.cpp:325
void Reset()
Resets the WritePort.
Definition libxr_rw.cpp:467
ErrorCode operator()(ConstRawData data, WriteOperation &op, bool in_isr=false)
执行写入操作。 Performs a write operation.
Definition libxr_rw.cpp:327
LibXR 命名空间
Definition ch32_can.hpp:14
ErrorCode
定义错误码枚举
@ TIMEOUT
超时 | Timeout
@ PENDING
等待中 | Pending
@ OK
操作成功 | Operation successful
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
Operation< ErrorCode > ReadOperation
Read operation type.
Definition libxr_rw.hpp:344
Operation< ErrorCode > WriteOperation
Write operation type.
Definition libxr_rw.hpp:348
Read information block structure.
Definition libxr_rw.hpp:363
RawData data
Data buffer. 数据缓冲区。
Definition libxr_rw.hpp:364
ReadOperation op
Read operation instance. 读取操作实例。
Definition libxr_rw.hpp:365
ConstRawData data
Data buffer. 数据缓冲区。
Definition libxr_rw.hpp:370
WriteOperation op
Write operation instance. 写入操作实例。
Definition libxr_rw.hpp:371