36 : backend_(backend), port_(port), buffers_(storage)
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;
62 (void)service_.
Invoke(EventMask(TxEvent::COMPLETE),
63 [
this, in_isr](uint32_t events)
noexcept
64 { ServiceTx(events, in_isr,
nullptr); });
76 (void)service_.
Invoke(EventMask(TxEvent::ERROR),
77 [
this, in_isr](uint32_t events)
noexcept
78 { ServiceTx(events, in_isr,
nullptr); });
93 backend_.OnConfigRequested();
94 (void)service_.
Invoke(EventMask(TxEvent::CONFIG),
95 [
this, in_isr](uint32_t events)
noexcept
96 { ServiceTx(events, in_isr,
nullptr); });
104 [[nodiscard]]
bool IsBusy()
const {
return busy_; }
106 [[nodiscard]] uint8_t* Buffer(
int block)
const {
return buffers_.
Buffer(block); }
108 [[nodiscard]]
size_t BufferSize()
const {
return buffers_.
Size(); }
111 enum class TxEvent : uint32_t
124 static constexpr uint32_t EventMask(TxEvent event)
126 return static_cast<uint32_t
>(event);
129 static constexpr bool HasEvent(uint32_t events, TxEvent event)
131 return (events & EventMask(event)) != 0U;
134 void ServiceTx(uint32_t events,
bool in_isr, SubmitContext* submit)
noexcept
136 if (HasEvent(events, TxEvent::CONFIG))
138 const bool resume_tx = ApplyConfig(in_isr);
139 if (!config_boundary_valid_ && resume_tx)
141 (void)service_.
Invoke(EventMask(TxEvent::WRITE),
142 [
this, in_isr](uint32_t pending_events)
noexcept
143 { ServiceTx(pending_events, in_isr,
nullptr); });
151 if (config_boundary_valid_)
156 bool terminal =
false;
157 if (HasEvent(events, TxEvent::ERROR))
159 terminal = ReleaseActive();
161 else if (HasEvent(events, TxEvent::COMPLETE))
163 terminal = ReleaseActive();
166 if (terminal && PromoteAndStartPending(in_isr))
171 if (!busy_ && (active_length_ == 0U))
173 StartQueuedActive(in_isr, submit);
178 (void)StageNextPending(in_isr);
182 bool PopPayload(uint8_t* destination,
size_t size)
189 bool DiscardPayload(
size_t size)
193 const size_t chunk = size > buffers_.
Size() ? buffers_.
Size() : size;
203 bool PopActiveInfo(WriteInfoBlock& info)
210 bool StagePending(
const WriteInfoBlock& info)
212 if (pending_valid_ || !PopPayload(buffers_.
PendingBuffer(), info.data.size_))
217 pending_valid_ =
true;
221 bool StageNextPending(
bool in_isr)
223 while (!pending_valid_)
225 WriteInfoBlock info{};
231 if (info.data.size_ > buffers_.
Size())
233 if (!DiscardPayload(info.data.size_) || !PopActiveInfo(info))
242 return StagePending(info);
247 bool PromotePending(WriteInfoBlock& info)
254 pending_valid_ =
false;
256 if (!PopActiveInfo(info))
261 active_length_ = info.data.size_;
267 ASSERT(active_length_ > 0U);
269 if (backend_.StartDmaTx(buffers_.
ActiveBuffer(), active_length_,
291 bool PromoteAndStartPending(
bool in_isr)
293 WriteInfoBlock info{};
294 if (!PromotePending(info))
299 const bool started = StartActive();
312 (void)StageNextPending(in_isr);
316 void StartQueuedActive(
bool in_isr, SubmitContext* submit)
318 WriteInfoBlock info{};
324 if (info.data.size_ > buffers_.
Size())
326 if (!DiscardPayload(info.data.size_) || !PopActiveInfo(info))
331 if (submit !=
nullptr)
342 if (!PopPayload(buffers_.
ActiveBuffer(), info.data.size_) || !PopActiveInfo(info))
345 if (submit !=
nullptr)
352 active_length_ = info.data.size_;
353 const bool started = StartActive();
359 if (submit !=
nullptr)
373 bool ApplyConfig(
bool in_isr)
380 if (!config_boundary_valid_)
383 config_boundary_valid_ =
true;
386 if (!backend_.ApplyPendingConfig(in_isr))
391 size_t remaining = config_prefix_count_;
392 config_prefix_count_ = 0U;
393 config_boundary_valid_ =
false;
395 (void)ReleaseActive();
399 ASSERT(remaining > 0U);
400 pending_valid_ =
false;
401 WriteInfoBlock info{};
402 if (!PopActiveInfo(info))
411 FailPublishedQueued(in_isr, remaining);
412 return backend_.OnConfigApplied(in_isr);
415 void FailPublishedQueued(
bool in_isr,
size_t count)
417 for (
size_t index = 0U; index < count; ++index)
419 WriteInfoBlock info{};
425 if (!DiscardPayload(info.data.size_) || !PopActiveInfo(info))
434 void ClearActive() { active_length_ = 0U; }
438 DoubleBuffer buffers_;
439 SerializedService service_{};
440 size_t active_length_ = 0U;
441 size_t config_prefix_count_ = 0U;
443 bool pending_valid_ =
false;
444 bool config_boundary_valid_ =
false;