libxr  1.0
Want to be the best embedded framework
Loading...
Searching...
No Matches
LibXR::UartDmaTxModel< Backend > Class Template Reference

UART 单次 DMA 发送执行模型 / UART one-shot DMA TX execution model. More...

#include <uart_dma_tx_model.hpp>

Collaboration diagram for LibXR::UartDmaTxModel< Backend >:
[legend]

Data Structures

struct  SubmitContext
 

Public Member Functions

 UartDmaTxModel (Backend &backend, WritePort &port, RawData storage)
 绑定平台后端、写端口和 DMA 双缓冲区 / Bind the backend, write port, and DMA double buffer
 
ErrorCode Submit (bool in_isr)
 发布 WRITE 事件并推进队首请求 / Publish WRITE and advance the head request
 
void OnTransferDone (bool in_isr)
 发布正常完成事件 / Publish a normal completion event
 
void OnTransferError (bool in_isr)
 在平台恢复旧 DMA 后发布错误终止事件 / Publish an error terminal event after platform recovery
 
void RequestConfig (bool in_isr)
 发布最高优先级配置事件 / Publish the highest-priority configuration event
 
bool IsBusy () const
 查询 DMA 是否持有 active 请求 / Check whether DMA owns an active request
 
uint8_t * Buffer (int block) const
 
size_t BufferSize () const
 

Private Types

enum class  TxEvent : uint32_t { WRITE = 1U << 0U , COMPLETE = 1U << 1U , ERROR = 1U << 2U , CONFIG = 1U << 3U }
 

Private Member Functions

void ServiceTx (uint32_t events, bool in_isr, SubmitContext *submit) noexcept
 
bool PopPayload (uint8_t *destination, size_t size)
 
bool DiscardPayload (size_t size)
 
bool PopActiveInfo (WriteInfoBlock &info)
 
bool StagePending (const WriteInfoBlock &info)
 
bool StageNextPending (bool in_isr)
 
bool PromotePending (WriteInfoBlock &info)
 
bool StartActive ()
 
bool ReleaseActive ()
 
bool PromoteAndStartPending (bool in_isr)
 
void StartQueuedActive (bool in_isr, SubmitContext *submit)
 
bool ApplyConfig (bool in_isr)
 
void FailPublishedQueued (bool in_isr, size_t count)
 
void ClearActive ()
 

Static Private Member Functions

static constexpr uint32_t EventMask (TxEvent event)
 
static constexpr bool HasEvent (uint32_t events, TxEvent event)
 

Private Attributes

Backend & backend_
 
WritePortport_
 
DoubleBuffer buffers_
 
SerializedService service_ {}
 
size_t active_length_ = 0U
 
size_t config_prefix_count_ = 0U
 
bool busy_ = false
 
bool pending_valid_ = false
 
bool config_boundary_valid_ = false
 

Detailed Description

template<typename Backend>
class LibXR::UartDmaTxModel< Backend >

UART 单次 DMA 发送执行模型 / UART one-shot DMA TX execution model.

Submit()、正常完成和错误恢复入口只发布可合并事件。SerializedService 选出的 唯一 owner 负责 active/pending buffer、WritePort 出队、DMA 启动以及 Operation 完成,避免提交线程与完成 ISR 并发推进双缓冲状态。 Submit(), normal completion, and recovered-error entries only publish coalesced events. The sole owner selected by SerializedService controls active/pending buffers, WritePort dequeue, DMA start, and Operation completion, preventing submitters and completion ISRs from advancing the double-buffer state concurrently.

Template Parameters
Backend静态绑定的平台后端类型 / Statically bound platform backend type

Definition at line 28 of file uart_dma_tx_model.hpp.

Member Enumeration Documentation

◆ TxEvent

template<typename Backend >
enum class LibXR::UartDmaTxModel::TxEvent : uint32_t
strongprivate

Definition at line 111 of file uart_dma_tx_model.hpp.

112 {
113 WRITE = 1U << 0U,
114 COMPLETE = 1U << 1U,
115 ERROR = 1U << 2U,
116 CONFIG = 1U << 3U,
117 };

Constructor & Destructor Documentation

◆ UartDmaTxModel()

template<typename Backend >
LibXR::UartDmaTxModel< Backend >::UartDmaTxModel ( Backend & backend,
WritePort & port,
RawData storage )
inline

绑定平台后端、写端口和 DMA 双缓冲区 / Bind the backend, write port, and DMA double buffer

Definition at line 35 of file uart_dma_tx_model.hpp.

36 : backend_(backend), port_(port), buffers_(storage)
37 {
38 }

Member Function Documentation

◆ ApplyConfig()

template<typename Backend >
bool LibXR::UartDmaTxModel< Backend >::ApplyConfig ( bool in_isr)
inlineprivate

Definition at line 373 of file uart_dma_tx_model.hpp.

374 {
375 // Metadata is the operation publication boundary. Fix the old prefix before any
376 // Finish callback can append another request. Payload without metadata belongs to
377 // an in-progress producer and is intentionally left for its later WRITE event.
378 // metadata 是操作发布边界。在任何 Finish callback 可能追加新请求前固定旧前缀;
379 // 只有 payload、尚无 metadata 的生产者仍在发布中,留给其后续 WRITE 事件处理。
380 if (!config_boundary_valid_)
381 {
382 config_prefix_count_ = port_.queue_info_->Size();
383 config_boundary_valid_ = true;
384 }
385
386 if (!backend_.ApplyPendingConfig(in_isr))
387 {
388 return false;
389 }
390
391 size_t remaining = config_prefix_count_;
392 config_prefix_count_ = 0U;
393 config_boundary_valid_ = false;
394
395 (void)ReleaseActive();
396
397 if (pending_valid_)
398 {
399 ASSERT(remaining > 0U);
400 pending_valid_ = false;
401 WriteInfoBlock info{};
402 if (!PopActiveInfo(info))
403 {
404 ASSERT(false);
405 return false;
406 }
407 --remaining;
408 port_.Finish(in_isr, ErrorCode::FAILED, info);
409 }
410
411 FailPublishedQueued(in_isr, remaining);
412 return backend_.OnConfigApplied(in_isr);
413 }
void Finish(bool in_isr, ErrorCode ans, WriteInfoBlock &info)
更新写入操作的状态。 Updates the status of the write operation.
SPSCQueue< WriteInfoBlock > * queue_info_
Metadata queue for pending write batches. 挂起写批次的元数据队列。
@ FAILED
操作失败 | Operation failed

◆ Buffer()

template<typename Backend >
uint8_t * LibXR::UartDmaTxModel< Backend >::Buffer ( int block) const
inlinenodiscard

Definition at line 106 of file uart_dma_tx_model.hpp.

106{ return buffers_.Buffer(block); }
uint8_t * Buffer(int block) const
获取指定编号缓冲区的指针 Returns the pointer of the specified block

◆ BufferSize()

template<typename Backend >
size_t LibXR::UartDmaTxModel< Backend >::BufferSize ( ) const
inlinenodiscard

Definition at line 108 of file uart_dma_tx_model.hpp.

108{ return buffers_.Size(); }
size_t Size() const
获取每个缓冲区的大小(单位:字节) Gets the size of each buffer in bytes

◆ ClearActive()

template<typename Backend >
void LibXR::UartDmaTxModel< Backend >::ClearActive ( )
inlineprivate

Definition at line 434 of file uart_dma_tx_model.hpp.

434{ active_length_ = 0U; }

◆ DiscardPayload()

template<typename Backend >
bool LibXR::UartDmaTxModel< Backend >::DiscardPayload ( size_t size)
inlineprivate

Definition at line 189 of file uart_dma_tx_model.hpp.

190 {
191 while (size > 0U)
192 {
193 const size_t chunk = size > buffers_.Size() ? buffers_.Size() : size;
194 if (!PopPayload(buffers_.ActiveBuffer(), chunk))
195 {
196 return false;
197 }
198 size -= chunk;
199 }
200 return true;
201 }
uint8_t * ActiveBuffer() const
获取当前正在使用的缓冲区指针 Returns the currently active buffer

◆ EventMask()

template<typename Backend >
static constexpr uint32_t LibXR::UartDmaTxModel< Backend >::EventMask ( TxEvent event)
inlinestaticconstexprprivate

Definition at line 124 of file uart_dma_tx_model.hpp.

125 {
126 return static_cast<uint32_t>(event);
127 }

◆ FailPublishedQueued()

template<typename Backend >
void LibXR::UartDmaTxModel< Backend >::FailPublishedQueued ( bool in_isr,
size_t count )
inlineprivate

Definition at line 415 of file uart_dma_tx_model.hpp.

416 {
417 for (size_t index = 0U; index < count; ++index)
418 {
419 WriteInfoBlock info{};
420 if (port_.queue_info_->Peek(info) != ErrorCode::OK)
421 {
422 ASSERT(false);
423 return;
424 }
425 if (!DiscardPayload(info.data.size_) || !PopActiveInfo(info))
426 {
427 ASSERT(false);
428 return;
429 }
430 port_.Finish(in_isr, ErrorCode::FAILED, info);
431 }
432 }
@ OK
操作成功 | Operation successful

◆ HasEvent()

template<typename Backend >
static constexpr bool LibXR::UartDmaTxModel< Backend >::HasEvent ( uint32_t events,
TxEvent event )
inlinestaticconstexprprivate

Definition at line 129 of file uart_dma_tx_model.hpp.

130 {
131 return (events & EventMask(event)) != 0U;
132 }

◆ IsBusy()

template<typename Backend >
bool LibXR::UartDmaTxModel< Backend >::IsBusy ( ) const
inlinenodiscard

查询 DMA 是否持有 active 请求 / Check whether DMA owns an active request

Warning
调用方必须与 TX service 串行化。The caller must serialize this query against the TX service.

Definition at line 104 of file uart_dma_tx_model.hpp.

104{ return busy_; }

◆ OnTransferDone()

template<typename Backend >
void LibXR::UartDmaTxModel< Backend >::OnTransferDone ( bool in_isr)
inline

发布正常完成事件 / Publish a normal completion event

Parameters
in_isr当前调用是否位于 ISR / Whether the current caller is in an ISR

Definition at line 60 of file uart_dma_tx_model.hpp.

61 {
62 (void)service_.Invoke(EventMask(TxEvent::COMPLETE),
63 [this, in_isr](uint32_t events) noexcept
64 { ServiceTx(events, in_isr, nullptr); });
65 }
bool Invoke(uint32_t events, Handler &&handler) noexcept
发布事件并尝试执行服务 / Publish events and try to run the service

◆ OnTransferError()

template<typename Backend >
void LibXR::UartDmaTxModel< Backend >::OnTransferError ( bool in_isr)
inline

在平台恢复旧 DMA 后发布错误终止事件 / Publish an error terminal event after platform recovery

Parameters
in_isr当前调用是否位于 ISR / Whether the current caller is in an ISR
Note
平台必须先停止/复位旧 DMA 并清除其迟到完成源,再调用本接口。The platform must stop/reset the old DMA and clear its stale completion source before this call.

Definition at line 74 of file uart_dma_tx_model.hpp.

75 {
76 (void)service_.Invoke(EventMask(TxEvent::ERROR),
77 [this, in_isr](uint32_t events) noexcept
78 { ServiceTx(events, in_isr, nullptr); });
79 }

◆ PopActiveInfo()

template<typename Backend >
bool LibXR::UartDmaTxModel< Backend >::PopActiveInfo ( WriteInfoBlock & info)
inlineprivate

Definition at line 203 of file uart_dma_tx_model.hpp.

204 {
205 const ErrorCode result = port_.queue_info_->Pop(info);
206 ASSERT(result == ErrorCode::OK);
207 return result == ErrorCode::OK;
208 }
ErrorCode
定义错误码枚举

◆ PopPayload()

template<typename Backend >
bool LibXR::UartDmaTxModel< Backend >::PopPayload ( uint8_t * destination,
size_t size )
inlineprivate

Definition at line 182 of file uart_dma_tx_model.hpp.

183 {
184 const ErrorCode result = port_.queue_data_->PopBatch(destination, size);
185 ASSERT(result == ErrorCode::OK);
186 return result == ErrorCode::OK;
187 }
ErrorCode PopBatch(Data *data, size_t size)
批量弹出多个 payload。
SPSCQueue< uint8_t > * queue_data_
Payload queue for pending write bytes. 挂起写入字节的数据队列。

◆ PromoteAndStartPending()

template<typename Backend >
bool LibXR::UartDmaTxModel< Backend >::PromoteAndStartPending ( bool in_isr)
inlineprivate

Definition at line 291 of file uart_dma_tx_model.hpp.

292 {
293 WriteInfoBlock info{};
294 if (!PromotePending(info))
295 {
296 return false;
297 }
298
299 const bool started = StartActive();
300 if (!started)
301 {
302 ClearActive();
303 }
304 port_.Finish(in_isr, started ? ErrorCode::OK : ErrorCode::FAILED, info);
305
306 if (!started)
307 {
308 RequestConfig(in_isr);
309 return true;
310 }
311
312 (void)StageNextPending(in_isr);
313 return true;
314 }
void RequestConfig(bool in_isr)
发布最高优先级配置事件 / Publish the highest-priority configuration event

◆ PromotePending()

template<typename Backend >
bool LibXR::UartDmaTxModel< Backend >::PromotePending ( WriteInfoBlock & info)
inlineprivate

Definition at line 247 of file uart_dma_tx_model.hpp.

248 {
249 if (!pending_valid_)
250 {
251 return false;
252 }
253
254 pending_valid_ = false;
255 buffers_.FlipActiveBlock();
256 if (!PopActiveInfo(info))
257 {
258 return false;
259 }
260
261 active_length_ = info.data.size_;
262 return true;
263 }
void FlipActiveBlock()
翻转当前活动缓冲区编号 Flips the current active block index

◆ ReleaseActive()

template<typename Backend >
bool LibXR::UartDmaTxModel< Backend >::ReleaseActive ( )
inlineprivate

Definition at line 279 of file uart_dma_tx_model.hpp.

280 {
281 if (!busy_)
282 {
283 return false;
284 }
285
286 busy_ = false;
287 ClearActive();
288 return true;
289 }

◆ RequestConfig()

template<typename Backend >
void LibXR::UartDmaTxModel< Backend >::RequestConfig ( bool in_isr)
inline

发布最高优先级配置事件 / Publish the highest-priority configuration event

Parameters
in_isr当前调用是否位于 ISR / Whether the current caller is in an ISR

平台后端负责保存最新配置 payload。本入口只发布可合并事件;CONFIG owner 会停止并 重配硬件、终止旧 TX 前缀,然后让 CONFIG 期间追加的请求在后续轮次继续推进。 The platform backend owns the latest configuration payload. This entry only publishes the coalesced event; the CONFIG owner reconfigures hardware, aborts the old TX prefix, and leaves requests appended during CONFIG for later service rounds.

Definition at line 91 of file uart_dma_tx_model.hpp.

92 {
93 backend_.OnConfigRequested();
94 (void)service_.Invoke(EventMask(TxEvent::CONFIG),
95 [this, in_isr](uint32_t events) noexcept
96 { ServiceTx(events, in_isr, nullptr); });
97 }

◆ ServiceTx()

template<typename Backend >
void LibXR::UartDmaTxModel< Backend >::ServiceTx ( uint32_t events,
bool in_isr,
SubmitContext * submit )
inlineprivatenoexcept

Definition at line 134 of file uart_dma_tx_model.hpp.

135 {
136 if (HasEvent(events, TxEvent::CONFIG))
137 {
138 const bool resume_tx = ApplyConfig(in_isr);
139 if (!config_boundary_valid_ && resume_tx)
140 {
141 (void)service_.Invoke(EventMask(TxEvent::WRITE),
142 [this, in_isr](uint32_t pending_events) noexcept
143 { ServiceTx(pending_events, in_isr, nullptr); });
144 }
145 return;
146 }
147
148 // A CONFIG request may be waiting for RX hardware ownership. Keep later WRITE and
149 // terminal notifications coalesced in their level-triggered facts, but do not let
150 // them move the fixed old-prefix boundary before CONFIG is retried.
151 if (config_boundary_valid_)
152 {
153 return;
154 }
155
156 bool terminal = false;
157 if (HasEvent(events, TxEvent::ERROR))
158 {
159 terminal = ReleaseActive();
160 }
161 else if (HasEvent(events, TxEvent::COMPLETE))
162 {
163 terminal = ReleaseActive();
164 }
165
166 if (terminal && PromoteAndStartPending(in_isr))
167 {
168 return;
169 }
170
171 if (!busy_ && (active_length_ == 0U))
172 {
173 StartQueuedActive(in_isr, submit);
174 }
175
176 if (busy_)
177 {
178 (void)StageNextPending(in_isr);
179 }
180 }

◆ StageNextPending()

template<typename Backend >
bool LibXR::UartDmaTxModel< Backend >::StageNextPending ( bool in_isr)
inlineprivate

Definition at line 221 of file uart_dma_tx_model.hpp.

222 {
223 while (!pending_valid_)
224 {
225 WriteInfoBlock info{};
226 if (port_.queue_info_->Peek(info) != ErrorCode::OK)
227 {
228 return false;
229 }
230
231 if (info.data.size_ > buffers_.Size())
232 {
233 if (!DiscardPayload(info.data.size_) || !PopActiveInfo(info))
234 {
235 ASSERT(false);
236 return false;
237 }
238 port_.Finish(in_isr, ErrorCode::FAILED, info);
239 continue;
240 }
241
242 return StagePending(info);
243 }
244 return false;
245 }

◆ StagePending()

template<typename Backend >
bool LibXR::UartDmaTxModel< Backend >::StagePending ( const WriteInfoBlock & info)
inlineprivate

Definition at line 210 of file uart_dma_tx_model.hpp.

211 {
212 if (pending_valid_ || !PopPayload(buffers_.PendingBuffer(), info.data.size_))
213 {
214 return false;
215 }
216
217 pending_valid_ = true;
218 return true;
219 }
uint8_t * PendingBuffer() const
获取备用缓冲区的指针 Returns the pending (inactive) buffer

◆ StartActive()

template<typename Backend >
bool LibXR::UartDmaTxModel< Backend >::StartActive ( )
inlineprivate

Definition at line 265 of file uart_dma_tx_model.hpp.

266 {
267 ASSERT(active_length_ > 0U);
268 busy_ = true;
269 if (backend_.StartDmaTx(buffers_.ActiveBuffer(), active_length_,
270 buffers_.ActiveBlock()))
271 {
272 return true;
273 }
274
275 busy_ = false;
276 return false;
277 }
int ActiveBlock() const
获取当前活动缓冲区编号 Returns the current active block index

◆ StartQueuedActive()

template<typename Backend >
void LibXR::UartDmaTxModel< Backend >::StartQueuedActive ( bool in_isr,
SubmitContext * submit )
inlineprivate

Definition at line 316 of file uart_dma_tx_model.hpp.

317 {
318 WriteInfoBlock info{};
319 if (port_.queue_info_->Peek(info) != ErrorCode::OK)
320 {
321 return;
322 }
323
324 if (info.data.size_ > buffers_.Size())
325 {
326 if (!DiscardPayload(info.data.size_) || !PopActiveInfo(info))
327 {
328 ASSERT(false);
329 return;
330 }
331 if (submit != nullptr)
332 {
333 submit->result = ErrorCode::FAILED;
334 }
335 else
336 {
337 port_.Finish(in_isr, ErrorCode::FAILED, info);
338 }
339 return;
340 }
341
342 if (!PopPayload(buffers_.ActiveBuffer(), info.data.size_) || !PopActiveInfo(info))
343 {
344 ASSERT(false);
345 if (submit != nullptr)
346 {
347 submit->result = ErrorCode::FAILED;
348 }
349 return;
350 }
351
352 active_length_ = info.data.size_;
353 const bool started = StartActive();
354 if (!started)
355 {
356 ClearActive();
357 }
358
359 if (submit != nullptr)
360 {
361 submit->result = started ? ErrorCode::OK : ErrorCode::FAILED;
362 }
363 else
364 {
365 port_.Finish(in_isr, started ? ErrorCode::OK : ErrorCode::FAILED, info);
366 if (!started)
367 {
368 RequestConfig(in_isr);
369 }
370 }
371 }

◆ Submit()

template<typename Backend >
ErrorCode LibXR::UartDmaTxModel< Backend >::Submit ( bool in_isr)
inline

发布 WRITE 事件并推进队首请求 / Publish WRITE and advance the head request

Parameters
in_isr当前调用是否位于 ISR / Whether the current caller is in an ISR
Returns
当前请求同步启动时返回 OK,留在流水中时返回 PENDING,同步启动失败 时返回错误 / OK for a synchronous start, PENDING while retained by the pipeline, or an error for a synchronous start failure

Definition at line 47 of file uart_dma_tx_model.hpp.

48 {
49 SubmitContext context{};
50 (void)service_.Invoke(EventMask(TxEvent::WRITE),
51 [this, in_isr, &context](uint32_t events) noexcept
52 { ServiceTx(events, in_isr, &context); });
53 return context.result;
54 }

Field Documentation

◆ active_length_

template<typename Backend >
size_t LibXR::UartDmaTxModel< Backend >::active_length_ = 0U
private

Definition at line 440 of file uart_dma_tx_model.hpp.

◆ backend_

template<typename Backend >
Backend& LibXR::UartDmaTxModel< Backend >::backend_
private

Definition at line 436 of file uart_dma_tx_model.hpp.

◆ buffers_

template<typename Backend >
DoubleBuffer LibXR::UartDmaTxModel< Backend >::buffers_
private

Definition at line 438 of file uart_dma_tx_model.hpp.

◆ busy_

template<typename Backend >
bool LibXR::UartDmaTxModel< Backend >::busy_ = false
private

Definition at line 442 of file uart_dma_tx_model.hpp.

◆ config_boundary_valid_

template<typename Backend >
bool LibXR::UartDmaTxModel< Backend >::config_boundary_valid_ = false
private

Definition at line 444 of file uart_dma_tx_model.hpp.

◆ config_prefix_count_

template<typename Backend >
size_t LibXR::UartDmaTxModel< Backend >::config_prefix_count_ = 0U
private

Definition at line 441 of file uart_dma_tx_model.hpp.

◆ pending_valid_

template<typename Backend >
bool LibXR::UartDmaTxModel< Backend >::pending_valid_ = false
private

Definition at line 443 of file uart_dma_tx_model.hpp.

◆ port_

template<typename Backend >
WritePort& LibXR::UartDmaTxModel< Backend >::port_
private

Definition at line 437 of file uart_dma_tx_model.hpp.

◆ service_

template<typename Backend >
SerializedService LibXR::UartDmaTxModel< Backend >::service_ {}
private

Definition at line 439 of file uart_dma_tx_model.hpp.

439{};

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