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 <cstddef>
5#include <cstdint>
6#include <cstring>
7#include <limits>
8#include <string_view>
9#include <tuple>
10#include <utility>
11
12#include "libxr_cb.hpp"
13#include "libxr_def.hpp"
14#include "libxr_mem.hpp"
15#include "print/print_api.hpp"
16#include "libxr_type.hpp"
17#include "lockfree_queue.hpp"
18#include "mutex.hpp"
19#include "semaphore.hpp"
20
21namespace LibXR
22{
23
31template <typename Args>
33{
34 public:
36
39 enum class OperationType : uint8_t
40 {
41 CALLBACK,
42 BLOCK,
43 POLLING,
44 NONE
45 };
46
49 enum class OperationPollingStatus : uint8_t
50 {
51 READY,
52 RUNNING,
53 DONE,
54 ERROR
55 };
56
59 Operation() : data{nullptr}, type(OperationType::NONE) {}
60
72 Operation(Semaphore& sem, uint32_t timeout = UINT32_MAX)
73 : data{.sem_info = {&sem, timeout}}, type(OperationType::BLOCK)
74 {}
75
82 : data{.callback = &callback}, type(OperationType::CALLBACK)
83 {}
84
91 : data{.status = &status}, type(OperationType::POLLING)
92 {}
93
94 Operation(const Operation& op) : data{nullptr}, type(OperationType::NONE)
95 {
96 *this = op;
97 }
98
99 Operation(Operation&& op) noexcept : data{nullptr}, type(OperationType::NONE)
100 {
101 *this = std::move(op);
102 }
103
111 {
112 if (this != &op)
113 {
114 type = op.type;
115 switch (type)
116 {
117 case OperationType::CALLBACK:
118 data.callback = op.data.callback;
119 break;
120 case OperationType::BLOCK:
121 data.sem_info.sem = op.data.sem_info.sem;
122 data.sem_info.timeout = op.data.sem_info.timeout;
123 break;
124 case OperationType::POLLING:
125 data.status = op.data.status;
126 break;
127 case OperationType::NONE:
128 data.callback = nullptr;
129 break;
130 }
131 }
132 return *this;
133 }
134
142 {
143 if (this != &op)
144 {
145 type = op.type;
146 switch (type)
147 {
148 case OperationType::CALLBACK:
149 data.callback = op.data.callback;
150 break;
151 case OperationType::BLOCK:
152 data.sem_info.sem = op.data.sem_info.sem;
153 data.sem_info.timeout = op.data.sem_info.timeout;
154 break;
155 case OperationType::POLLING:
156 data.status = op.data.status;
157 break;
158 case OperationType::NONE:
159 data.callback = nullptr;
160 break;
161 }
162 }
163 return *this;
164 }
165
172 template <typename Status>
173 void UpdateStatus(bool in_isr, Status&& status)
174 {
175 switch (type)
176 {
177 case OperationType::CALLBACK:
178 data.callback->Run(in_isr, std::forward<Status>(status));
179 break;
180 case OperationType::BLOCK:
181 // BLOCK waits are signaled by semaphore only; the owning port keeps the
182 // final ErrorCode in its block_result_ handoff state.
183 // BLOCK 只通过信号量唤醒;最终 ErrorCode 由端口侧 block_result_ 交接。
184 data.sem_info.sem->PostFromCallback(in_isr);
185 break;
186 case OperationType::POLLING:
187 *data.status = (status == ErrorCode::OK) ? OperationPollingStatus::DONE
188 : OperationPollingStatus::ERROR;
189 break;
190 case OperationType::NONE:
191 break;
192 }
193 }
194
209 {
210 if (type == OperationType::POLLING)
211 {
212 *data.status = OperationPollingStatus::RUNNING;
213 }
214 }
215
218 union
219 {
220 Callback* callback;
221 struct
222 {
223 Semaphore* sem;
224 uint32_t timeout;
225 } sem_info;
226 OperationPollingStatus* status;
227 } data;
228
232};
233
241{
242 public:
243 // Keep the waiter state 32-bit wide so STM32 builds stay within the
244 // project-wide atomic shim boundary.
245 enum class State : uint32_t
246 {
247 IDLE = 0,
248 PENDING = 1,
249 CLAIMED = 2,
250 DETACHED = 3,
251 };
252
253 void Start(Semaphore& sem)
254 {
255 sem_ = &sem;
256 result_ = ErrorCode::OK;
257 state_.store(State::PENDING, std::memory_order_release);
258 }
259
260 void Cancel() { state_.store(State::IDLE, std::memory_order_release); }
261
262 ErrorCode Wait(uint32_t timeout)
263 {
264 ASSERT(sem_ != nullptr);
265 auto wait_ans = sem_->Wait(timeout);
266 if (wait_ans == ErrorCode::OK)
267 {
268#ifdef LIBXR_DEBUG_BUILD
269 ASSERT(state_.load(std::memory_order_acquire) == State::CLAIMED);
270#endif
271 state_.store(State::IDLE, std::memory_order_release);
272 return result_;
273 }
274
275 State expected = State::PENDING;
276 if (state_.compare_exchange_strong(expected, State::DETACHED,
277 std::memory_order_acq_rel,
278 std::memory_order_acquire))
279 {
280 return ErrorCode::TIMEOUT;
281 }
282
283 ASSERT(expected == State::CLAIMED || expected == State::DETACHED ||
284 expected == State::IDLE);
285 if (expected == State::DETACHED)
286 {
287 state_.store(State::IDLE, std::memory_order_release);
288 return ErrorCode::TIMEOUT;
289 }
290 if (expected == State::IDLE)
291 {
292 return ErrorCode::TIMEOUT;
293 }
294
295 auto finish_wait_ans = sem_->Wait(UINT32_MAX);
296 UNUSED(finish_wait_ans);
297 ASSERT(finish_wait_ans == ErrorCode::OK);
298 state_.store(State::IDLE, std::memory_order_release);
299 return result_;
300 }
301
302 bool TryPost(bool in_isr, ErrorCode ec)
303 {
304 ASSERT(sem_ != nullptr);
305
306 State expected = State::PENDING;
307 if (!state_.compare_exchange_strong(expected, State::CLAIMED,
308 std::memory_order_acq_rel,
309 std::memory_order_acquire))
310 {
311 ASSERT(expected == State::DETACHED || expected == State::IDLE);
312 if (expected == State::DETACHED)
313 {
314 expected = State::DETACHED;
315 (void)state_.compare_exchange_strong(expected, State::IDLE,
316 std::memory_order_acq_rel,
317 std::memory_order_acquire);
318 }
319 return false;
320 }
321
322 result_ = ec;
323 sem_->PostFromCallback(in_isr);
324 return true;
325 }
326
327 private:
328 Semaphore* sem_ = nullptr;
329 std::atomic<State> state_{State::IDLE};
330 ErrorCode result_ = ErrorCode::OK;
331};
332
333class ReadPort;
334class WritePort;
335
339
343
354typedef ErrorCode (*WriteFun)(WritePort& port, bool in_isr);
355
365typedef ErrorCode (*ReadFun)(ReadPort& port, bool in_isr);
366
376
382
388{
389 public:
390 // Exposed low-level state and helpers for the read-path core. Some members stay public
391 // because low-level libxr tests and driver glue inspect them directly.
392 // 读路径核心的低层状态与辅助类型。部分成员保持 public,
393 // 是因为 libxr 的底层测试与驱动胶水层会直接检查它们。
394
395 // Read BLOCK states:
396 // PENDING = waiting for queue-fed completion after read_fun_ was notified
397 // BLOCK_CLAIMED = wakeup now belongs to the waiter
398 // BLOCK_DETACHED = timeout/reset detached the waiter
399 // The same semaphore may be reused only after the previous BLOCK call
400 // returns and the port goes back to IDLE.
401 // 读 BLOCK 状态:
402 // PENDING = 已通知 read_fun_,等待队列侧完成
403 // BLOCK_CLAIMED = 唤醒已经归当前 waiter 所有
404 // BLOCK_DETACHED = timeout/reset 已把 waiter 分离
405 // 同一个信号量只能在上一次 BLOCK 调用返回、端口回到 IDLE 后复用。
406 enum class BusyState : uint32_t
407 {
408 IDLE = 0,
409 PENDING = 1,
411 BLOCK_CLAIMED = 2,
413 BLOCK_DETACHED = 3,
415 EVENT = UINT32_MAX
417 };
418
419 ReadFun read_fun_ = nullptr;
420 LockFreeQueue<uint8_t>* queue_data_ = nullptr;
422 std::atomic<BusyState> busy_{BusyState::IDLE};
423 ErrorCode block_result_ = ErrorCode::OK;
424
434 ReadPort(size_t buffer_size = 128);
435
446 size_t EmptySize();
447
458 size_t Size();
459
462 bool Readable();
463
477 ReadPort& operator=(ReadFun fun);
478
490 void Finish(bool in_isr, ErrorCode ans, ReadInfoBlock& info);
491
502 void MarkAsRunning(ReadInfoBlock& info);
503
528 ErrorCode operator()(RawData data, ReadOperation& op, bool in_isr = false);
529
537 virtual void OnRxDequeue(bool) {}
538
546 void ProcessPendingReads(bool in_isr);
547
550 void Reset();
551};
552
558{
559 public:
560 // Exposed low-level state and helpers for the write-path core. Some members stay public
561 // because low-level libxr tests and backend glue inspect them directly. Keep the
562 // boundary explicit instead of introducing a fake private wall that tests cannot use.
563 // 写路径核心的低层状态与辅助类型。部分成员保持 public,
564 // 是因为 libxr 的底层测试与后端胶水层会直接检查它们。
565 // 这里保持显式边界即可,不做测试本身也用不上的“伪私有化”。
566
567 // Write BLOCK states:
568 // LOCKED = submit path owns queue mutation
569 // BLOCK_PUBLISHING = BLOCK submit path is publishing queue metadata
570 // BLOCK_WAITING = waiter armed, completion not claimed yet
571 // BLOCK_CLAIMED = final wakeup belongs to the waiter
572 // BLOCK_DETACHED = timeout/reset detached the waiter
573 // RESETTING = reset path owns queue mutation
574 // The same semaphore may be reused only after the previous BLOCK call
575 // returns and the port goes back to IDLE.
576 // 写 BLOCK 状态:
577 // LOCKED = 提交路径占有队列修改权
578 // BLOCK_PUBLISHING = BLOCK 提交路径正在发布队列元数据
579 // BLOCK_WAITING = waiter 已挂起,完成尚未 claim
580 // BLOCK_CLAIMED = 最终唤醒已经归 waiter 所有
581 // BLOCK_DETACHED = timeout/reset 已把 waiter 分离
582 // RESETTING = reset 路径占有队列修改权
583 // 同一个信号量只能在上一次 BLOCK 调用返回、端口回到 IDLE 后复用。
584 enum class BusyState : uint32_t
585 {
586 LOCKED =
587 0,
588 BLOCK_PUBLISHING = 1,
590 BLOCK_WAITING = 2,
592 BLOCK_CLAIMED =
593 3,
594 BLOCK_DETACHED = 4,
596 RESETTING = 5,
597 IDLE = UINT32_MAX
599 };
600
601 WriteFun write_fun_ = nullptr;
603 nullptr;
605 nullptr;
606 std::atomic<BusyState> busy_{BusyState::IDLE};
607 ErrorCode block_result_ = ErrorCode::OK;
608
609 // Stream batch facade.
610 // Stream 负责一次批次的累积写入与提交。
611 class Stream
612 {
613 public:
621
627 ~Stream();
628
642 [[nodiscard]] ErrorCode Write(ConstRawData data);
643
650 [[nodiscard]] ErrorCode Write(std::string_view text)
651 {
652 return Write(ConstRawData{text.data(), text.size()});
653 }
654
661 Stream& operator<<(const ConstRawData& data);
662
675 ErrorCode Commit();
676
681 void Discard();
682
688 [[nodiscard]] ErrorCode Acquire();
689
698 [[nodiscard]] size_t EmptySize() const
699 {
700 return owns_port_ ? (batch_capacity_ - buffered_size_) : 0;
701 }
702
703 private:
713 [[nodiscard]] ErrorCode SubmitBuffered();
714
719 void Release();
720
723 size_t batch_capacity_ = 0;
724 size_t buffered_size_ = 0;
725 bool owns_port_ = false;
726 };
727
728 // Direct WritePort operations and state-machine entrypoints.
729 // WritePort 本体的直接写接口与状态机入口。
746 WritePort(size_t queue_size = 3, size_t buffer_size = 128);
747
755 size_t EmptySize();
756
764 size_t Size();
765
773 bool Writable();
774
788 WritePort& operator=(WriteFun fun);
789
805 void Finish(bool in_isr, ErrorCode ans, WriteInfoBlock& info);
806
817 void MarkAsRunning(WriteOperation& op);
818
837 ErrorCode operator()(ConstRawData data, WriteOperation& op, bool in_isr = false);
838
841 void Reset();
842
857 ErrorCode CommitWrite(ConstRawData data, WriteOperation& op, bool pushed = false,
858 bool in_isr = false);
859};
860
865class STDIO
866{
867 public:
868 // Shared global stdio binding state.
869 // 共享的全局 stdio 绑定状态。
870 // NOLINTBEGIN
871 static inline ReadPort* read_ = nullptr;
872 static inline WritePort* write_ = nullptr;
873 static inline LibXR::Mutex* write_mutex_ =
874 nullptr;
875 static inline LibXR::WritePort::Stream* write_stream_ =
876 nullptr;
877 // NOLINTEND
878
879 private:
880 // Compiled-format bridge shared by the brace and printf frontends.
881 // brace 与 printf 两个前端共用的编译格式桥接层。
882
888 {
889 public:
894 explicit CompiledSink(WritePort::Stream& stream);
895
901 [[nodiscard]] ErrorCode Write(std::string_view chunk);
902
907 [[nodiscard]] size_t RetainedSize() const { return retained_size_; }
908
909 private:
911 size_t retained_size_ = 0;
912 bool saturated_ = false;
913 };
914
916 using CompiledWriteFun = ErrorCode (*)(void* context, CompiledSink& sink);
917
922 template <typename CompiledFormat, typename... Args>
924 {
925 const CompiledFormat& format;
926 std::tuple<Args&&...> args;
927
932 [[nodiscard]] static ErrorCode Write(void* context, CompiledSink& sink)
933 {
934 auto& compiled_call = *static_cast<CompiledCall*>(context);
935 return std::apply(
936 [&](auto&&... unpacked) -> ErrorCode
937 {
938 return Print::Write(sink, compiled_call.format,
939 std::forward<decltype(unpacked)>(unpacked)...);
940 },
941 compiled_call.args);
942 }
943 };
944
955 [[nodiscard]] static int WriteCompiledToStream(WritePort::Stream& stream,
956 void* context,
957 CompiledWriteFun write_fun);
958
969 [[nodiscard]] static int WriteCompiledSession(void* context, CompiledWriteFun write_fun);
970
981 template <typename Call>
982 [[nodiscard]] static int RunCompiledSession(Call& call)
983 {
984 if (!BeginWriteSession())
985 {
986 return -1;
987 }
988
989 return WriteCompiledSession(&call, &Call::Write);
990 }
991
997 template <typename CompiledFormat, typename... Args>
998 [[nodiscard]] static int RunCompiled(const CompiledFormat& format, Args&&... args)
999 {
1000 CompiledCall<CompiledFormat, Args...> call{
1001 format, std::forward_as_tuple(std::forward<Args>(args)...)};
1002 return RunCompiledSession(call);
1003 }
1004
1009 [[nodiscard]] static bool BeginWriteSession();
1010
1016 [[nodiscard]] static int FinishWriteSession(WritePort::Stream& stream,
1017 size_t retained_size,
1018 ErrorCode format_result);
1019
1020 public:
1021
1030 template <Print::Text Source, typename... Args>
1031 static int Print(Args&&... args)
1032 {
1033 constexpr LibXR::Format<Source> format{};
1034 return RunCompiled(format, std::forward<Args>(args)...);
1035 }
1036
1045 template <Print::Text Source, typename... Args>
1046 static int Printf(Args&&... args)
1047 {
1048 constexpr auto format = Print::Printf::Build<Source>();
1049 return RunCompiled(format, std::forward<Args>(args)...);
1050 }
1051};
1052} // namespace LibXR
Shared BLOCK waiter handoff for synchronous driver operations.
Definition libxr_rw.hpp:241
通用回调包装,支持动态参数传递 / Generic callback wrapper supporting dynamic argument passing
Definition libxr_cb.hpp:142
只读原始数据视图 / Immutable raw data view
无锁队列实现 / Lock-free queue implementation
互斥锁类,提供线程同步机制 (Mutex class providing thread synchronization mechanisms).
Definition mutex.hpp:18
Defines an operation with different execution modes.
Definition libxr_rw.hpp:33
Operation & operator=(const Operation &op)
Copy assignment operator.
Definition libxr_rw.hpp:110
Operation(Semaphore &sem, uint32_t timeout=UINT32_MAX)
Constructs a blocking operation with a semaphore and timeout.
Definition libxr_rw.hpp:72
Operation & operator=(Operation &&op) noexcept
Move assignment operator.
Definition libxr_rw.hpp:141
Operation(Callback &callback)
Constructs a callback-based operation.
Definition libxr_rw.hpp:81
union LibXR::Operation::@5 data
Operation()
Default constructor, initializes with NONE type.
Definition libxr_rw.hpp:59
void UpdateStatus(bool in_isr, Status &&status)
Updates operation status based on type.
Definition libxr_rw.hpp:173
void MarkAsRunning()
标记操作为运行状态。 Marks the operation as running.
Definition libxr_rw.hpp:208
OperationType type
Definition libxr_rw.hpp:231
Operation(OperationPollingStatus &status)
Constructs a polling operation.
Definition libxr_rw.hpp:90
可写原始数据视图 / Mutable raw data view
ReadPort class for handling read operations.
Definition libxr_rw.hpp:388
virtual void OnRxDequeue(bool)
RX 数据从软件队列成功出队后的通知。 Notification after bytes are popped from RX data queue.
Definition libxr_rw.hpp:537
STDIO 编译格式会话使用的流式截断输出端。
Definition libxr_rw.hpp:888
WritePort::Stream & stream_
Active stream session receiving retained bytes. 接收保留字节的活动流会话。
Definition libxr_rw.hpp:910
size_t RetainedSize() const
返回当前会话最终保留下来的字节数。
Definition libxr_rw.hpp:907
STDIO interface for read/write ports.
Definition libxr_rw.hpp:866
static int Printf(Args &&... args)
Prints one compile-time printf literal to the active STDIO output.
static int RunCompiledSession(Call &call)
执行一次模板已知的 STDIO 编译格式会话。
Definition libxr_rw.hpp:982
ErrorCode(*)(void *context, CompiledSink &sink) CompiledWriteFun
Type-erased bridge for one compiled STDIO call. / 一次编译格式 STDIO 调用的类型擦除桥接函数。
Definition libxr_rw.hpp:916
static int Print(Args &&... args)
Prints one compile-time brace literal to the active STDIO output.
static int RunCompiled(const CompiledFormat &format, Args &&... args)
用一份已编译格式和一组运行时参数执行一次完整的 STDIO 写会话。
Definition libxr_rw.hpp:998
信号量类,实现线程同步机制 Semaphore class implementing thread synchronization
Definition semaphore.hpp:23
size_t EmptySize() const
获取当前批次还可追加的剩余字节数。
Definition libxr_rw.hpp:698
LibXR::WritePort * port_
写端口指针 Pointer to the WritePort
Definition libxr_rw.hpp:721
LibXR::WriteOperation op_
写操作对象 Write operation object
Definition libxr_rw.hpp:722
ErrorCode Write(std::string_view text)
追加一个文本片段到当前流批次。
Definition libxr_rw.hpp:650
WritePort class for handling write operations.
Definition libxr_rw.hpp:558
LibXR 命名空间
Definition ch32_can.hpp:14
ErrorCode
定义错误码枚举
@ PENDING
等待中 | Pending
@ OK
操作成功 | Operation successful
ErrorCode(* ReadFun)(ReadPort &port, bool in_isr)
Function pointer type for read notifications.
Definition libxr_rw.hpp:365
ErrorCode(* WriteFun)(WritePort &port, bool in_isr)
Function pointer type for write operations.
Definition libxr_rw.hpp:354
Structural literal wrapper used as the NTTP source for printf formats.
Definition printf.hpp:17
Read information block structure.
Definition libxr_rw.hpp:372
RawData data
Data buffer. 数据缓冲区。
Definition libxr_rw.hpp:373
ReadOperation op
Read operation instance. 读取操作实例。
Definition libxr_rw.hpp:374
一次编译格式 STDIO 调用的模板上下文。
Definition libxr_rw.hpp:924
std::tuple< Args &&... > args
Forwarded runtime arguments. 转发保存的运行时参数。
Definition libxr_rw.hpp:926
static ErrorCode Write(void *context, CompiledSink &sink)
将当前模板上下文桥接到编译格式前端写入入口。
Definition libxr_rw.hpp:932
const CompiledFormat & format
Compile-time compiled format object. 编译期已编译的格式对象。
Definition libxr_rw.hpp:925
ConstRawData data
Data buffer. 数据缓冲区。
Definition libxr_rw.hpp:379
WriteOperation op
Write operation instance. 写入操作实例。
Definition libxr_rw.hpp:380