• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2023 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 
15 #pragma once
16 
17 #include <cstddef>
18 #include <cstdint>
19 #include <optional>
20 
21 #include "pw_assert/assert.h"
22 #include "pw_bytes/span.h"
23 #include "pw_chrono/system_clock.h"
24 #include "pw_function/function.h"
25 #include "pw_status/status.h"
26 #include "pw_status/status_with_size.h"
27 
28 namespace pw::uart {
29 
30 /// Represents an abstract UART interface.
31 ///
32 /// The `Uart` interface provides a basic set of methods for performing UART
33 /// communication. It defines the interface that concrete UART implementations
34 /// must adhere to.
35 
36 /// @defgroup pw_uart
37 /// @{
38 class Uart {
39  public:
40   virtual ~Uart() = default;
41 
42   /// Initializes the UART module on the microcontroller, sets it into the
43   /// default state as determined by the concrete UART implementation. This
44   /// function should be a no-op if the UART module is in an enabled state.
45   ///
46   /// This may change the power state of the UART module, configure the
47   /// interface parameters, enable the associated pins, setup the internal
48   /// TX and RX buffers, etc...
49   ///
50   /// @returns @rst
51   ///
52   /// .. pw-status-codes::
53   ///
54   ///    OK: The UART module has been successfully initialized.
55   ///
56   ///    INTERNAL: Internal errors within the hardware abstraction layer.
57   ///
58   /// @endrst
Enable()59   Status Enable() { return DoEnable(true); }
60 
61   /// Disables the UART module on the microcontroller. Disabling the UART
62   /// shuts down communication and prevents the microcontroller from
63   /// sending or receiving data through the UART port.
64   ///
65   /// This is usually done to save power. Interrupt handlers should also be
66   /// disabled.
67   ///
68   /// @returns @rst
69   ///
70   /// .. pw-status-codes::
71   ///
72   ///    OK: The UART module has been successfully initialized.
73   ///
74   ///    INTERNAL: Internal errors  within the hardware abstraction layer.
75   ///
76   /// @endrst
Disable()77   Status Disable() { return DoEnable(false); }
78 
79   /// Configures the UART communication baud rate.
80   ///
81   /// This function sets the communication speed (baud rate) for the UART.
82   /// Whether the baud rate can be changed while the UART is enabled depends on
83   /// the specific implementation.
84   ///
85   /// @returns @rst
86   ///
87   /// .. pw-status-codes::
88   ///
89   ///    OK: The UART has been successfully initialized.
90   ///
91   ///    FAILED_PRECONDITION: The device is enabled and does not support
92   ///    changing settings on the fly.
93   ///
94   ///    INTERNAL: Internal errors  within the hardware abstraction layer.
95   ///
96   /// @endrst
SetBaudRate(uint32_t baud_rate)97   Status SetBaudRate(uint32_t baud_rate) { return DoSetBaudRate(baud_rate); }
98 
99   /// Reads data from the UART into a provided buffer.
100   ///
101   /// This function blocks until the entirety of `rx_buffer` is filled with
102   /// data.
103   ///
104   /// @param rx_buffer  The buffer to read data into.
105   ///
106   /// @returns @rst
107   ///
108   /// .. pw-status-codes::
109   ///
110   ///    OK: The operation was successful.
111   ///
112   /// May return other implementation-specific status codes.
113   ///
114   /// @endrst
Read(ByteSpan rx_buffer)115   Status Read(ByteSpan rx_buffer) {
116     return DoTryReadFor(rx_buffer, std::nullopt).status();
117   }
118 
119   /// Reads data from the UART into a provided buffer.
120   ///
121   /// This function blocks until either the entire buffer has been filled with
122   /// data or the specified timeout has elapsed, whichever occurs first.
123   ///
124   /// @param rx_buffer  The buffer to read data into.
125   /// @param timeout    The maximum time to wait for data to be read. If zero,
126   ///                   the function will immediately return with at least one
127   ///                   hardware read operation attempt.
128   ///
129   /// @returns @rst
130   ///
131   /// .. pw-status-codes::
132   ///
133   ///    OK: The operation was successful and the entire buffer has been filled
134   ///    with data.
135   ///
136   ///    DEADLINE_EXCEEDED: The operation timed out before the entire buffer
137   ///    could be filled.
138   ///
139   /// May return other implementation-specific status codes.
140   ///
141   /// @endrst
TryReadFor(ByteSpan rx_buffer,chrono::SystemClock::duration timeout)142   StatusWithSize TryReadFor(ByteSpan rx_buffer,
143                             chrono::SystemClock::duration timeout) {
144     return DoTryReadFor(rx_buffer, timeout);
145   }
146 
147   /// Writes data from the provided buffer to the UART. The function blocks
148   /// until the entire buffer has been written.
149   ///
150   /// @param tx_buffer - The buffer to write data from.
151   ///
152   /// @returns @rst
153   ///
154   /// .. pw-status-codes::
155   ///
156   ///    OK: The operation was successful.
157   ///
158   /// May return other implementation-specific status codes.
159   ///
160   /// @endrst
Write(ConstByteSpan tx_buffer)161   Status Write(ConstByteSpan tx_buffer) {
162     return DoTryWriteFor(tx_buffer, std::nullopt).status();
163   }
164 
165   /// Writes data from the provided buffer to the UART. The function blocks
166   /// until either the entire buffer has been written or the specified timeout
167   /// has elapsed, whichever occurs first.
168   ///
169   /// @param tx_buffer  The buffer to write data from.
170   /// @param timeout    The maximum time to wait for data to be written.
171   ///                   If zero, the function will immediately return with at
172   ///                   least one hardware write operation attempt.
173   ///
174   /// @returns @rst
175   ///
176   /// .. pw-status-codes::
177   ///
178   ///    OK: The operation was successful and the entire buffer has been
179   ///    written.
180   ///
181   ///    DEADLINE_EXCEEDED: The operation timed out before the entire buffer
182   ///    could be written.
183   ///
184   /// May return other implementation-specific status codes.
185   ///
186   /// @endrst
TryWriteFor(ConstByteSpan tx_buffer,chrono::SystemClock::duration timeout)187   StatusWithSize TryWriteFor(ConstByteSpan tx_buffer,
188                              chrono::SystemClock::duration timeout) {
189     return DoTryWriteFor(tx_buffer, timeout);
190   }
191 
192   /// Returns the number of bytes currently available for reading.
193   ///
194   /// This function checks the receive buffer to determine how many bytes of
195   /// data are ready to be read.
196   ///
197   /// @returns The number of bytes available for reading. When no data is
198   /// available or in case of an error this function returns 0.
ConservativeReadAvailable()199   size_t ConservativeReadAvailable() { return DoConservativeReadAvailable(); }
200 
201   /// Blocks until all queued data in the UART  has been transmitted and the
202   /// FIFO is empty.
203   ///
204   /// This function ensures that all data enqueued before calling this function
205   /// has been transmitted. Any data enqueued after calling this function will
206   /// be transmitted immediately.
207   ///
208   /// @returns @rst
209   ///
210   /// .. pw-status-codes::
211   ///
212   ///    OK: The operation was successful.
213   ///
214   /// May return other implementation-specific status codes.
215   ///
216   /// @endrst
FlushOutput()217   Status FlushOutput() { return DoFlushOutput(); }
218 
219   /// Empties the UART's receive buffer and discards any unread data.
220   ///
221   /// This function removes all data from the receive buffer, resetting the
222   /// buffer to an empty state. This is useful for situations where you want to
223   /// disregard any previously received data and resynchronize.
224   ///
225   /// @returns @rst
226   ///
227   /// .. pw-status-codes::
228   ///
229   ///    OK: The operation was successful.
230   ///
231   /// May return other implementation-specific status codes.
232   ///
233   /// @endrst
ClearPendingReceiveBytes()234   Status ClearPendingReceiveBytes() { return DoClearPendingReceiveBytes(); }
235 
236  private:
237   virtual Status DoEnable(bool enable) = 0;
238   virtual Status DoSetBaudRate(uint32_t baud_rate) = 0;
239 
240   /// Reads data from the UART into a provided buffer with an optional timeout
241   /// provided.
242   ///
243   /// This virtual function attempts to read data into the provided byte buffer
244   /// (`rx_buffer`). The operation will continue until either the buffer is
245   /// full, an error occurs, or the optional timeout duration expires.
246   ///
247   /// @param rx_buffer  The buffer to read data into.
248   /// @param timeout    An optional timeout duration. If specified, the function
249   ///                   will block for no longer than this duration. If zero,
250   ///                   the function will immediately return with at least one
251   ///                   hardware read operation attempt. If not specified, the
252   ///                   function blocks untill the buffer is full.
253   ///
254   /// @returns @rst
255   ///
256   /// .. pw-status-codes::
257   ///
258   ///    OK: The operation was successful and the entire buffer has been
259   ///    filled with data.
260   ///
261   ///    DEADLINE_EXCEEDED: The operation timed out before the entire buffer
262   ///    could be filled.
263   ///
264   /// May return other implementation-specific status codes.
265   ///
266   /// @endrst
267   virtual StatusWithSize DoTryReadFor(
268       ByteSpan rx_buffer,
269       std::optional<chrono::SystemClock::duration> timeout) = 0;
270 
271   /// @brief Writes data from a provided buffer to the UART with an optional
272   /// timeout.
273   ///
274   /// This virtual function attempts to write data from the provided byte buffer
275   /// (`tx_buffer`) to the UART. The operation will continue until either the
276   /// buffer is empty, an error occurs, or the optional timeout duration
277   /// expires.
278   ///
279   /// @param tx_buffer  The buffer containing data to be written.
280   /// @param timeout    An optional timeout duration. If specified, the function
281   ///                   will block for no longer than this duration. If zero,
282   ///                   the function will immediately return after at least one
283   ///                   hardware write operation attempt. If not specified, the
284   ///                   function blocks until the buffer is empty.
285   ///
286   /// @returns @rst
287   ///
288   /// .. pw-status-codes::
289   ///
290   ///    OK: The operation was successful and the entire buffer has been
291   ///    written.
292   ///
293   ///    DEADLINE_EXCEEDED: The operation timed out before the entire buffer
294   ///    could be written.
295   ///
296   /// May return other implementation-specific status codes.
297   ///
298   /// @endrst
299   virtual StatusWithSize DoTryWriteFor(
300       ConstByteSpan tx_buffer,
301       std::optional<chrono::SystemClock::duration> timeout) = 0;
302   virtual size_t DoConservativeReadAvailable() = 0;
303   virtual Status DoFlushOutput() = 0;
304   virtual Status DoClearPendingReceiveBytes() = 0;
305 };
306 
307 /// @}
308 
309 }  // namespace pw::uart
310