GCC Code Coverage Report


Directory: lib/fprime-samd/fprime-samd/Drv/UsartDriver/
File: UsartDriver.hpp
Date: 2026-10-20 16:49:03
Exec Total Coverage
Lines: 2 2 100.0%
Functions: 2 2 100.0%
Branches: 0 0 -%

Line Branch Exec Source
1 // ======================================================================
2 // \title UsartDriver.hpp
3 // \author tumbar
4 // \brief hpp file for UsartDriver component implementation class
5 // ======================================================================
6
7 #ifndef Samd21_UsartDriver_HPP
8 #define Samd21_UsartDriver_HPP
9
10 #include "Fw/DataStructures/FifoQueue.hpp"
11 #include "fprime-samd/Drv/Types/SercomKindEnumAc.hpp"
12 #include "fprime-samd/Drv/Types/ThinBuffer.hpp"
13 #include "fprime-samd/Drv/UsartDriver/UsartDriverComponentAc.hpp"
14 #include "samd-config/UsartDriverConfig.hpp"
15
16 namespace Samd21 {
17
18 class UsartDriver final : public UsartDriverComponentBase {
19 public:
20 // ----------------------------------------------------------------------
21 // Component construction and destruction
22 // ----------------------------------------------------------------------
23
24 //! Construct UsartDriver object
25 UsartDriver(const char* const compName //!< The component name
26 );
27
28 //! Destroy UsartDriver object
29 ~UsartDriver();
30
31 // ----------------------------------------------------------------------
32 // Component configuration
33 // ----------------------------------------------------------------------
34
35 enum class ClockMode : U8 {
36 EXTERNAL = 0x0, //!< Drive baud on the external XCK pad
37 INTERNAL = 0x1, //!< Drive the baud off a prescaled GCLK0
38 };
39
40 enum class CommunicationMode : U8 {
41 ASYNC = 0x0, //!< Asynchronous UART with TX/RX
42 SYNC = 0x1, //!< Synchronous UART with TX/RX, RTS/CTS
43 };
44
45 // These bits define the receive data (RxD) pin configuration.
46 enum class RxPinOut : U8 {
47 PAD0 = 0, //!< SERCOM PAD[0] is used for data reception
48 PAD1 = 1, //!< SERCOM PAD[1] is used for data reception
49 PAD2 = 2, //!< SERCOM PAD[2] is used for data reception
50 PAD3 = 3, //!< SERCOM PAD[3] is used for data reception
51 };
52
53 enum class TxPinOut : U8 {
54 PAD0 = 0, //!< TX: SERCOM PAD[0], XCK: SERCOM PAD[1]
55 PAD2_XCK_PAD3 = 1, //!< TX: SERCOM PAD[2], XCK: SERCOM PAD[3]
56 PAD0_RTS_PAD2_CTS_PAD3 = 2, //!< TX: SERCOM PAD[0], RTS: SERCOM PAD[2], CTS: SERCOM PAD[3]
57 };
58
59 enum class DataOrder : U8 {
60 MSB_FIRST = 0x0, //!< MSB is transmitted first
61 LSB_FIRST = 0x1, //!< LSB is transmitted first
62 };
63
64 enum class Parity : U8 {
65 NONE,
66 EVEN,
67 ODD,
68 };
69
70 enum class StopBits : U8 {
71 ONE = 0x0,
72 TWO = 0x1,
73 };
74
75 enum class DataBits : U8 {
76 BITS_8 = 0x0,
77 BITS_9 = 0x1,
78 BITS_5 = 0x5,
79 BITS_6 = 0x6,
80 BITS_7 = 0x7,
81 };
82
83 enum class BaudRate : U32 {
84 BAUD_9600 = 9600,
85 BAUD_19200 = 19200,
86 BAUD_38400 = 38400,
87 BAUD_57600 = 57600,
88 BAUD_115200 = 115200, //!< Modern default
89 BAUD_230400 = 230400,
90 BAUD_460800 = 460800,
91 BAUD_921600 = 921600,
92 };
93
94 void configure(SercomKind sercom,
95 RxPinOut rx,
96 TxPinOut tx,
97 ClockMode clock,
98 CommunicationMode mode,
99 BaudRate baud_rate,
100 DataOrder data_order,
101 DataBits data_bits,
102 StopBits stop_bits,
103 Parity parity);
104
105 private:
106 // ----------------------------------------------------------------------
107 // Handler implementations for typed input ports
108 // ----------------------------------------------------------------------
109
110 //! Service the UART driver:
111 //! 1. Return Tx buffers that finished DMA transmission.
112 //! 2. Detect IDLE Rx. Pull the in-progress DMA Rx and send it downstream
113 void schedIn_handler(FwIndexType portNum, U32 context) override;
114
115 //! Handler implementation for dmaReplyIn
116 //!
117 //! A signal from the DMAC that a request has finished.
118 //! This signal comes inside an ISR!
119 void dmaReplyIn_handler(FwIndexType portNum, //!< The port number
120 const Samd21::Dma::Reply& reply) override;
121
122 //! Handler implementation for recvReturnIn
123 //!
124 //! Port receiving back ownership of data sent out on $recv port
125 void recvReturnIn_handler(FwIndexType portNum, //!< The port number
126 Fw::Buffer& fwBuffer //!< The buffer
127 ) override;
128
129 //! Handler implementation for send
130 //!
131 //! Invoke this port to send data out the driver (asynchronous)
132 //! Status and ownership of the buffer are returned through the sendReturnOut callback
133 //! send buffer to the DMAC synchronously
134 void send_handler(FwIndexType portNum, //!< The port number
135 Fw::Buffer& fwBuffer //!< The buffer
136 ) override;
137
138 //! Handler for input port activeIn
139 //!
140 //! Returns true iff at least one signal was dequeued and processed this
141 //! tick (so the cycler should re-invoke us); false if idle (not configured
142 //! or the queue was empty).
143 bool activeIn_handler(FwIndexType portNum, //!< The port number
144 U32 context //!< The call order
145 ) override;
146
147 //! Handler for input port sendSync
148 Drv::ByteStreamStatus sendSync_handler(FwIndexType portNum, //!< The port number
149 Fw::Buffer& sendBuffer //!< Data to send
150 ) override;
151
152 // ----------------------------------------------------------------------
153 // Helper functions
154 // ----------------------------------------------------------------------
155
156 //! An enum tracking the
157 enum class RxDmaBufferID : U8 {
158 A,
159 B,
160 INVALID,
161 };
162
163 //! Handle a reply on the TX DMA channel
164 void dmaReplyTxIsr(const Samd21::Dma::Reply& reply);
165
166 //! Handle a reply on the RX DMA channel
167 void dmaReplyRxIsr(const Samd21::Dma::Reply& reply);
168
169 //! Send a buffer to the RX DMA channel
170 void dmaQueueRxSend(const ThinBuffer& buffer);
171
172 // ----------------------------------------------------------------------
173 // Member variables
174 // ----------------------------------------------------------------------
175
176 //! SERCOM peripheral this driver controls
177 SercomKind m_sercom;
178
179 //! Fifo tracking the queue of TX DMA transactions.
180 //! DMA replies should come back in the same order
181 Fw::FifoQueue<ThinBuffer, UsartDriverConfig::USART_TX_BUFFER_N> m_tx_queue;
182
183 struct RxBuffer {
184 U8 data[USART_RX_BUFFER_SIZE];
185 };
186
187 //! Rx buffers (A and B) for receiving data over the DMA
188 RxBuffer m_rx[2];
189 RxDmaBufferID m_active_rx;
190
191 //! Tracks whether configure() as been called or not
192 bool m_configured;
193
194 U16 m_active_processed;
195
196 //! m_rxOverflows: SERCOM STATUS.BUFOVF events (silent hardware RX drops).
197 U32 m_rxOverflows;
198
199 //! m_schedSkips: partial-read passes skipped by the high-RX watchdog.
200 U32 m_schedSkips;
201
202 //! High-RX watchdog. dmaReplyRxIsr bumps m_rx_activity on every RX
203 //! completion (ISR context); schedIn compares it against the value seen on
204 //! the previous tick. If it advanced, RX is actively moving full buffers, so
205 //! schedIn skips the partial read -- which would suspend the RX DMA channel
206 //! (see DmaChannel::readWriteback) and risk a BUFOVF drop. Full buffers are
207 //! delivered losslessly via RX_BUFFER_DONE, so skipping loses nothing; the
208 //! partial read only matters during genuine idle to extract a sub-buffer tail.
209 volatile U32 m_rx_activity;
210 U32 m_last_sched_activity;
211
212 U32 m_rxBytes;
213 U32 m_txBytes;
214
215 //! Signals sent to the internal queue for processing during schedIn
216 enum class SignalKind : U8 {
217 TX_BUFFER_OK, //!< A buffer has been TXed over the DMA successfully
218 RX_BUFFER_PARTIAL, //!< An RX buffer has been partially filled and is ready for processing
219 RX_BUFFER_DONE, //!< An RX buffer has been filled and is ready for processing
220 };
221
222 struct Signal {
223 SignalKind kind;
224 U16 rx_bytes;
225
226 117 Signal() : kind(SignalKind::TX_BUFFER_OK), rx_bytes(0) {}
227 8 explicit Signal(SignalKind kind_, U16 rx_bytes_) : kind(kind_), rx_bytes(rx_bytes_) {}
228 };
229
230 Fw::FifoQueue<Signal, UsartDriverConfig::USART_QUEUE_DEPTH> m_queue;
231 };
232
233 } // namespace Samd21
234
235 #endif
236