GCC Code Coverage Report


Directory: lib/fprime-samd/fprime-samd/
File: Drv/UsartDriver/UsartDriver.cpp
Date: 2026-10-20 16:48:53
Exec Total Coverage
Lines: 158 168 94.0%
Functions: 12 12 100.0%
Branches: 135 247 54.7%

Line Branch Exec Source
1 // ======================================================================
2 // \title UsartDriver.cpp
3 // \author tumbar
4 // \brief cpp file for UsartDriver component implementation class
5 // ======================================================================
6
7 #include "fprime-samd/Drv/UsartDriver/UsartDriver.hpp"
8 #include "Drv/ByteStreamDriverModel/ByteStreamStatusEnumAc.hpp"
9 #include "Fw/Types/Assert.hpp"
10 #include "Fw/Types/SuccessEnumAc.hpp"
11 #include "config/FwAssertArgTypeAliasAc.h"
12 #include "config/FwIndexTypeAliasAc.h"
13 #include "fprime-samd/Drv/Types/CriticalSection.hpp"
14 #include "fprime-samd/Drv/Types/PriorityEnumAc.hpp"
15 #include "fprime-samd/Drv/Types/Sercom.hpp"
16 #include "fprime-samd/Drv/Types/ThinBuffer.hpp"
17 #include "fprime-samd/Drv/UsartDriver/UsartDriverHardware.hpp"
18 #include "fprime-samd/Drv/UsartDriver/UsartDriver_DmaChannelEnumAc.hpp"
19 #include "samd-config/UsartDriverConfig.hpp"
20
21 namespace Samd21 {
22
23 // ----------------------------------------------------------------------
24 // Component construction and destruction
25 // ----------------------------------------------------------------------
26
27 25 UsartDriver::UsartDriver(const char* const compName)
28 : UsartDriverComponentBase(compName),
29
1/2
✓ Branch 3 taken 25 times.
✗ Branch 4 not taken.
25 m_sercom(SercomKind::SERCOM_0),
30 25 m_active_rx(RxDmaBufferID::INVALID),
31 25 m_configured(false),
32 25 m_active_processed(0),
33 25 m_rxOverflows(0),
34 25 m_schedSkips(0),
35 25 m_rx_activity(0),
36 25 m_last_sched_activity(0),
37 25 m_rxBytes(0),
38
2/4
✓ Branch 10 taken 25 times.
✗ Branch 11 not taken.
✓ Branch 20 taken 25 times.
✗ Branch 21 not taken.
75 m_txBytes(0) {}
39
40 50 UsartDriver::~UsartDriver() = default;
41
42 22 void UsartDriver::configure(SercomKind sercom,
43 RxPinOut rx,
44 TxPinOut tx,
45 ClockMode clock,
46 CommunicationMode mode,
47 BaudRate baud_rate,
48 DataOrder data_order,
49 DataBits data_bits,
50 StopBits stop_bits,
51 Parity parity) {
52
2/6
✗ Branch 3 not taken.
✓ Branch 4 taken 22 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 22 times.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
22 FW_ASSERT(!this->m_configured, sercom.e);
53
54 // Store configuration
55 22 m_sercom = sercom;
56
57 // Configure and enable the SERCOM USART peripheral.
58
2/4
✓ Branch 2 taken 22 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 22 times.
✗ Branch 6 not taken.
22 UsartHardware::UsartHal::configure(sercom, rx, tx, clock, mode, baud_rate, data_order, data_bits, stop_bits,
59 parity);
60
61 // Initialize the RX state
62 22 this->m_active_rx = RxDmaBufferID::A;
63 22 this->m_active_processed = 0;
64
65 22 this->m_configured = true;
66
67
2/2
✓ Branch 5 taken 16 times.
✓ Branch 6 taken 6 times.
22 if (this->isConnected_ready_OutputPort(0)) {
68 16 this->ready_out(0);
69 }
70
71 // Queue the Rx buffer to get the DMA to start reading from the uart
72
1/2
✓ Branch 5 taken 22 times.
✗ Branch 6 not taken.
22 if (this->isConnected_dmaQueueOut_OutputPort(UsartDriver_DmaChannel::RX)) {
73 // Send these buffers to the DMA
74
2/4
✓ Branch 7 taken 22 times.
✗ Branch 8 not taken.
✓ Branch 11 taken 22 times.
✗ Branch 12 not taken.
22 this->dmaQueueRxSend(ThinBuffer(this->m_rx[0].data, USART_RX_BUFFER_SIZE));
75
2/4
✓ Branch 7 taken 22 times.
✗ Branch 8 not taken.
✓ Branch 11 taken 22 times.
✗ Branch 12 not taken.
22 this->dmaQueueRxSend(ThinBuffer(this->m_rx[1].data, USART_RX_BUFFER_SIZE));
76 22 this->dmaRxCircular_out(0);
77 }
78 22 }
79
80 // ----------------------------------------------------------------------
81 // Handler implementations for typed input ports
82 // ----------------------------------------------------------------------
83
84 8 void UsartDriver::schedIn_handler(FwIndexType portNum, U32 context) {
85
3/4
✗ Branch 3 not taken.
✓ Branch 4 taken 8 times.
✓ Branch 5 taken 7 times.
✓ Branch 6 taken 1 times.
8 if (this->m_configured) {
86 // Check the SERCOM RX hardware overflow flag. This is a plain register
87 // read (no channel suspend) and is safe to do at any RX rate; it tells us
88 // whether the peripheral silently dropped any bytes since the last tick.
89
4/6
✓ Branch 5 taken 7 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 7 times.
✗ Branch 9 not taken.
✓ Branch 13 taken 1 times.
✓ Branch 14 taken 6 times.
7 if (UsartHardware::UsartHal::checkAndClearRxOverflow(this->m_sercom)) {
90 1 this->m_rxOverflows++;
91 }
92
93 // High-RX watchdog. dmaReplyRxIsr bumps m_rx_activity on every full-buffer
94 // RX completion. If it advanced since the previous tick, RX is actively
95 // streaming and the partial read below
96 7 const U32 activity = this->m_rx_activity;
97 7 const bool rxBusy = (activity != this->m_last_sched_activity);
98 7 this->m_last_sched_activity = activity;
99
100
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 6 times.
7 if (rxBusy) {
101 1 this->m_schedSkips++;
102 } else {
103 // RX is idle -- safe to suspend and read the in-progress transfer.
104
1/2
✓ Branch 3 taken 6 times.
✗ Branch 4 not taken.
6 auto currentRx = this->dmaRxRead_out(0);
105
106 // Absolute count of bytes filled in the current DMA buffer so far
107 6 auto filled = static_cast<U16>(USART_RX_BUFFER_SIZE - currentRx.get_btcnt());
108
109 // Only notify if new data has arrived since we last processed this buffer.
110 // Signals carry the absolute high-water mark (not a delta) so that a PARTIAL and
111 // a concurrently-enqueued DONE/PARTIAL cannot double-count the same bytes.
112
2/2
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 2 times.
6 if (filled > this->m_active_processed) {
113 // Notify our queue of the current Rx status.
114 // m_queue is shared with the DMA ISR (dmaReplyIn), so the enqueue must be
115 // protected from a concurrent enqueue happening inside the ISR.
116
1/2
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
4 Fw::Success status;
117 {
118
1/2
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
4 CriticalSection cs;
119
2/4
✓ Branch 7 taken 4 times.
✗ Branch 8 not taken.
✓ Branch 12 taken 4 times.
✗ Branch 13 not taken.
4 status = this->m_queue.enqueue(Signal(SignalKind::RX_BUFFER_PARTIAL, filled));
120 4 }
121
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
4 FW_ASSERT(status == Fw::Success::SUCCESS, status);
122 4 }
123 6 }
124
125 // Emit diagnostics on the sched tick (no added TX load beyond telemetry).
126
1/2
✓ Branch 3 taken 7 times.
✗ Branch 4 not taken.
7 auto time = getTime();
127
2/4
✓ Branch 6 taken 7 times.
✗ Branch 7 not taken.
✓ Branch 13 taken 7 times.
✗ Branch 14 not taken.
7 this->tlmWrite_rxOverflows(this->m_rxOverflows, time);
128
2/4
✓ Branch 6 taken 7 times.
✗ Branch 7 not taken.
✓ Branch 13 taken 7 times.
✗ Branch 14 not taken.
7 this->tlmWrite_rxBytes(this->m_rxBytes, time);
129
2/4
✓ Branch 6 taken 7 times.
✗ Branch 7 not taken.
✓ Branch 13 taken 7 times.
✗ Branch 14 not taken.
7 this->tlmWrite_txBytes(this->m_txBytes, time);
130 7 }
131 8 }
132
133 10 bool UsartDriver::activeIn_handler(FwIndexType portNum, U32 context) {
134
3/4
✗ Branch 3 not taken.
✓ Branch 4 taken 10 times.
✓ Branch 5 taken 9 times.
✓ Branch 6 taken 1 times.
10 if (this->m_configured) {
135 // Tracks whether we actually dequeued (and processed) any signal this
136 // tick. Returned to the caller so the cycler knows whether to re-invoke
137 // us (work was done) or let it go idle (queue was empty).
138 9 bool didWork = false;
139
140 // Unload the queue
141 for (;;) {
142 17 Signal signal;
143
1/2
✓ Branch 2 taken 17 times.
✗ Branch 3 not taken.
17 Fw::Success status;
144
145 // Dequeue an item off the queue
146 {
147
1/2
✓ Branch 2 taken 17 times.
✗ Branch 3 not taken.
17 CriticalSection cs;
148
3/4
✓ Branch 6 taken 17 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 9 times.
✓ Branch 9 taken 8 times.
17 if (this->m_queue.isEmpty()) {
149 // No more items
150 9 break;
151 } else {
152
2/4
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
✓ Branch 9 taken 8 times.
✗ Branch 10 not taken.
8 status = this->m_queue.dequeue(signal);
153 }
154
2/2
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 9 times.
17 }
155
156
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 8 times.
8 FW_ASSERT(status == Fw::Success::SUCCESS, status);
157 8 didWork = true;
158
159
1/2
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
8 ThinBuffer thinBuffer;
160
1/2
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
8 Fw::Buffer thickBuffer;
161
1/2
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
8 Fw::Success bufferStatus;
162
163
2/3
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
8 switch (signal.kind) {
164 1 case SignalKind::TX_BUFFER_OK:
165
2/4
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 9 taken 1 times.
✗ Branch 10 not taken.
1 bufferStatus = this->m_tx_queue.dequeue(thinBuffer);
166
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
1 FW_ASSERT(bufferStatus == Fw::Success::SUCCESS);
167
2/4
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
1 thickBuffer = thinBuffer.getBuffer();
168
2/4
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 11 not taken.
1 this->sendReturnOut_out(0, thickBuffer, Drv::ByteStreamStatus::OP_OK);
169 1 break;
170 7 case SignalKind::RX_BUFFER_DONE:
171 case SignalKind::RX_BUFFER_PARTIAL: {
172
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 FW_ASSERT(signal.rx_bytes <= USART_RX_BUFFER_SIZE, this->m_sercom, signal.rx_bytes);
173
1/2
✗ Branch 4 not taken.
✓ Branch 5 taken 7 times.
7 FW_ASSERT(signal.rx_bytes >= this->m_active_processed, this->m_sercom, this->m_active_processed,
174 signal.rx_bytes);
175
176 7 U16 newBytes = signal.rx_bytes - this->m_active_processed;
177 // Wrap the newly received region of the current DMA buffer in a Fw::Buffer
178
2/3
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 2 times.
✗ Branch 6 not taken.
7 switch (this->m_active_rx) {
179 5 case RxDmaBufferID::A:
180
2/4
✓ Branch 9 taken 5 times.
✗ Branch 10 not taken.
✓ Branch 14 taken 5 times.
✗ Branch 15 not taken.
5 thickBuffer = Fw::Buffer(this->m_rx[0].data + this->m_active_processed, newBytes);
181 5 break;
182 2 case RxDmaBufferID::B:
183
2/4
✓ Branch 9 taken 2 times.
✗ Branch 10 not taken.
✓ Branch 14 taken 2 times.
✗ Branch 15 not taken.
2 thickBuffer = Fw::Buffer(this->m_rx[1].data + this->m_active_processed, newBytes);
184 2 break;
185 ✗ default:
186 ✗ FW_ASSERT(false, static_cast<FwAssertArgType>(this->m_active_rx));
187 }
188
189
2/3
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
7 switch (signal.kind) {
190 4 case SignalKind::RX_BUFFER_PARTIAL:
191 // We got part of a buffer, track the amount of data we received
192
1/2
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
4 this->m_active_processed += thickBuffer.getSize();
193 4 break;
194 3 case SignalKind::RX_BUFFER_DONE:
195 // We got the entire buffer, we need to tick the state machine
196
2/3
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
3 switch (this->m_active_rx) {
197 2 case RxDmaBufferID::A:
198 // Update all the states to represent the new overall state
199 2 this->m_active_rx = RxDmaBufferID::B;
200 2 this->m_active_processed = 0;
201 2 break;
202 1 case RxDmaBufferID::B:
203 // Update all the states to represent the new overall state
204 1 this->m_active_rx = RxDmaBufferID::A;
205 1 this->m_active_processed = 0;
206 1 break;
207 ✗ default:
208 ✗ FW_ASSERT(false, static_cast<FwAssertArgType>(this->m_active_rx));
209 }
210 3 break;
211 ✗ default:
212 ✗ FW_ASSERT(false); // unreachable
213 }
214
215 // Send the data we received to downstream uplink
216
2/4
✓ Branch 2 taken 7 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 7 times.
✗ Branch 5 not taken.
7 if (thickBuffer.getSize() > 0) {
217
1/2
✓ Branch 2 taken 7 times.
✗ Branch 3 not taken.
7 this->m_rxBytes += static_cast<U32>(thickBuffer.getSize());
218
2/4
✓ Branch 5 taken 7 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 7 times.
✗ Branch 8 not taken.
7 if (this->isConnected_recv_OutputPort(0)) {
219
2/4
✓ Branch 6 taken 7 times.
✗ Branch 7 not taken.
✓ Branch 10 taken 7 times.
✗ Branch 11 not taken.
7 this->recv_out(0, thickBuffer, Drv::ByteStreamStatus::OP_OK);
220 }
221 }
222
223 7 break;
224 }
225 ✗ default:
226 ✗ FW_ASSERT(false, static_cast<FwAssertArgType>(signal.kind));
227 }
228
2/2
✓ Branch 6 taken 8 times.
✓ Branch 7 taken 9 times.
25 }
229
230 9 return didWork;
231 }
232
233 // Not configured: nothing to do this tick.
234 1 return false;
235 }
236
237 4 void UsartDriver::dmaReplyIn_handler(FwIndexType portNum, const Samd21::Dma::Reply& reply) {
238
2/3
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
4 switch (portNum) {
239 1 case UsartDriver_DmaChannel::TX:
240 1 this->dmaReplyTxIsr(reply);
241 1 break;
242 3 case UsartDriver_DmaChannel::RX:
243 3 this->dmaReplyRxIsr(reply);
244 3 break;
245 ✗ default:
246 ✗ FW_ASSERT(false, static_cast<FwAssertArgType>(portNum));
247 }
248 4 }
249
250 1 void UsartDriver::recvReturnIn_handler(FwIndexType portNum, Fw::Buffer& fwBuffer) {
251 // The downstream process gave us our buffer back
252 // These buffers are always in the DMA, this is a no-op
253 // Do we need overrun detection here?
254 1 }
255
256 12 void UsartDriver::send_handler(FwIndexType portNum, Fw::Buffer& fwBuffer) {
257
2/4
✗ Branch 3 not taken.
✓ Branch 4 taken 12 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 12 times.
12 FW_ASSERT(this->m_configured);
258
259
2/4
✓ Branch 6 taken 12 times.
✗ Branch 7 not taken.
✓ Branch 10 taken 12 times.
✗ Branch 11 not taken.
12 auto status = this->m_tx_queue.enqueue(ThinBuffer(fwBuffer));
260
2/2
✓ Branch 2 taken 11 times.
✓ Branch 3 taken 1 times.
12 if (status == Fw::Success::SUCCESS) {
261
1/2
✓ Branch 4 taken 11 times.
✗ Branch 5 not taken.
11 this->m_txBytes += static_cast<U32>(fwBuffer.getSize());
262 // This job has been added to the queue, send it to the DMA
263 // Note: Use DATA.reg to get the actual register address, not the structure address
264
8/16
✓ Branch 6 taken 11 times.
✗ Branch 7 not taken.
✓ Branch 11 taken 11 times.
✗ Branch 12 not taken.
✓ Branch 16 taken 11 times.
✗ Branch 17 not taken.
✓ Branch 20 taken 11 times.
✗ Branch 21 not taken.
✓ Branch 23 taken 11 times.
✗ Branch 24 not taken.
✓ Branch 26 taken 11 times.
✗ Branch 27 not taken.
✓ Branch 31 taken 11 times.
✗ Branch 32 not taken.
✓ Branch 35 taken 11 times.
✗ Branch 36 not taken.
55 this->dmaQueueOut_out(
265
2/4
✓ Branch 6 taken 11 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 11 times.
✗ Branch 10 not taken.
22 UsartDriver_DmaChannel::TX, SercomUtil::txDmaTrigger(m_sercom), Dma::TransactionType::BEAT,
266
1/2
✓ Branch 4 taken 11 times.
✗ Branch 5 not taken.
11 Dma::Priority::PRIORITY_0, static_cast<U32>(reinterpret_cast<uintptr_t>(fwBuffer.getData())),
267
1/2
✓ Branch 4 taken 11 times.
✗ Branch 5 not taken.
11 UsartHardware::UsartHal::getDataRegisterAddress(m_sercom), fwBuffer.getSize(), Dma::BeatSize::BYTE,
268 /* increment source */ true,
269 /* incrementDestination */ false, Dma::AddressIncrementStepSize::SIZE_1, Dma::StepSelection::SOURCE);
270 } else {
271 // We could not add this buffer to the queue
272 // Reply back to the producer with a "retry"
273
2/4
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 11 not taken.
1 this->sendReturnOut_out(0, fwBuffer, Drv::ByteStreamStatus::SEND_RETRY);
274 }
275 24 }
276
277 1 Drv::ByteStreamStatus UsartDriver::sendSync_handler(FwIndexType portNum, Fw::Buffer& sendBuffer) {
278
2/4
✓ Branch 13 taken 1 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 1 times.
✗ Branch 17 not taken.
1 UsartHardware::UsartHal::sendSync(this->m_sercom, sendBuffer.getData(), sendBuffer.getSize());
279 1 return Drv::ByteStreamStatus::OP_OK;
280 }
281
282 44 void UsartDriver::dmaQueueRxSend(const ThinBuffer& buffer) {
283
8/16
✓ Branch 6 taken 44 times.
✗ Branch 7 not taken.
✓ Branch 11 taken 44 times.
✗ Branch 12 not taken.
✓ Branch 16 taken 44 times.
✗ Branch 17 not taken.
✓ Branch 20 taken 44 times.
✗ Branch 21 not taken.
✓ Branch 23 taken 44 times.
✗ Branch 24 not taken.
✓ Branch 27 taken 44 times.
✗ Branch 28 not taken.
✓ Branch 32 taken 44 times.
✗ Branch 33 not taken.
✓ Branch 36 taken 44 times.
✗ Branch 37 not taken.
176 this->dmaQueueOut_out(
284
2/4
✓ Branch 6 taken 44 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 44 times.
✗ Branch 10 not taken.
88 UsartDriver_DmaChannel::RX, SercomUtil::rxDmaTrigger(m_sercom), Dma::TransactionType::BEAT,
285 44 Dma::Priority::PRIORITY_0, UsartHardware::UsartHal::getDataRegisterAddress(m_sercom),
286
2/4
✓ Branch 2 taken 44 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 44 times.
✗ Branch 7 not taken.
44 static_cast<U32>(reinterpret_cast<uintptr_t>(buffer.getData())), buffer.getSize(), Dma::BeatSize::BYTE,
287 /* increment source */ false,
288 /* incrementDestination */ true, Dma::AddressIncrementStepSize::SIZE_1, Dma::StepSelection::DESTINATION);
289 44 }
290
291 1 void UsartDriver::dmaReplyTxIsr(const Samd21::Dma::Reply& reply) {
292
1/2
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
1 FW_ASSERT(reply.get_status() == Dma::Status::OK, this->m_sercom, static_cast<FwAssertArgType>(reply.get_status()));
293
1/2
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 Fw::Success status;
294
295 {
296
1/2
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 CriticalSection cs;
297
2/4
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
✓ Branch 12 taken 1 times.
✗ Branch 13 not taken.
1 status = this->m_queue.enqueue(Signal(SignalKind::TX_BUFFER_OK, 0));
298 1 }
299
300
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
1 FW_ASSERT(status == Fw::Success::SUCCESS, status);
301 2 }
302
303 3 void UsartDriver::dmaReplyRxIsr(const Samd21::Dma::Reply& reply) {
304
1/2
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
3 Fw::Success status;
305 // Make sure remaining bytes are consistent with our storage
306
1/2
✗ Branch 4 not taken.
✓ Branch 5 taken 3 times.
3 FW_ASSERT(reply.get_remainingBytes() <= USART_RX_BUFFER_SIZE, reply.get_remainingBytes());
307
1/2
✗ Branch 4 not taken.
✓ Branch 5 taken 3 times.
3 FW_ASSERT(reply.get_status() == Dma::Status::OK, static_cast<FwAssertArgType>(reply.get_status()));
308
309 // Signal the high-RX watchdog that a full buffer just completed. schedIn
310 // compares this across ticks to decide whether RX is busy (and thus
311 // whether the suspend-inducing partial read is safe to run).
312 3 this->m_rx_activity++;
313 {
314 // Carry the absolute count of bytes filled in the current buffer (high-water mark)
315 // rather than a delta against m_active_processed. m_active_processed is only mutated
316 // in activeIn_handler, so reading it here (in an ISR) would race; the absolute count
317 // is computed purely from DMA state and the delta is resolved at consume time.
318
1/2
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
3 CriticalSection cs;
319
1/2
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
12 status = this->m_queue.enqueue(
320 9 Signal(SignalKind::RX_BUFFER_DONE,
321
1/2
✓ Branch 7 taken 3 times.
✗ Branch 8 not taken.
6 static_cast<U16>(USART_RX_BUFFER_SIZE - static_cast<U16>(reply.get_remainingBytes()))));
322 3 }
323
324 // TODO(tumbar) If we are Rx-ing too fast, this will assert
325 // Maybe a better thing to do is to drop this buffer?
326
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
3 FW_ASSERT(status == Fw::Success::SUCCESS, status);
327 6 }
328
329 } // namespace Samd21
330