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