1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334
// Licensed under the Apache License, Version 2.0 or the MIT License.
// SPDX-License-Identifier: Apache-2.0 OR MIT
// Copyright Tock Contributors 2022.
//! Hardware interface layer (HIL) traits for UART communication.
//!
//!
use crate::ErrorCode;
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum StopBits {
One = 1,
Two = 2,
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum Parity {
None = 0,
Odd = 1,
Even = 2,
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum Width {
Six = 6,
Seven = 7,
Eight = 8,
}
#[derive(Copy, Clone, Debug)]
pub struct Parameters {
pub baud_rate: u32, // baud rate in bit/s
pub width: Width,
pub parity: Parity,
pub stop_bits: StopBits,
pub hw_flow_control: bool,
}
/// The type of error encountered during UART transaction.
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum Error {
/// No error occurred and the command completed successfully
None,
/// Parity error during receive
ParityError,
/// Framing error during receive
FramingError,
/// Overrun error during receive
OverrunError,
/// Repeat call of transmit or receive before initial command complete
RepeatCallError,
/// UART hardware was reset
ResetError,
/// UART hardware was disconnected
BreakError,
/// Read or write was aborted early
Aborted,
}
pub trait Uart<'a>: Configure + Transmit<'a> + Receive<'a> {}
pub trait UartData<'a>: Transmit<'a> + Receive<'a> {}
pub trait UartAdvanced<'a>: Configure + Transmit<'a> + ReceiveAdvanced<'a> {}
pub trait Client: ReceiveClient + TransmitClient {}
// Provide blanket implementations for all trait groups
impl<'a, T: Configure + Transmit<'a> + Receive<'a>> Uart<'a> for T {}
impl<'a, T: Transmit<'a> + Receive<'a>> UartData<'a> for T {}
impl<'a, T: Configure + Transmit<'a> + ReceiveAdvanced<'a>> UartAdvanced<'a> for T {}
impl<T: ReceiveClient + TransmitClient> Client for T {}
/// Trait for configuring a UART.
pub trait Configure {
/// Returns Ok(()), or
/// - OFF: The underlying hardware is currently not available, perhaps
/// because it has not been initialized or in the case of a shared
/// hardware USART controller because it is set up for SPI.
/// - INVAL: Impossible parameters (e.g. a `baud_rate` of 0)
/// - ENOSUPPORT: The underlying UART cannot satisfy this configuration.
fn configure(&self, params: Parameters) -> Result<(), ErrorCode>;
}
pub trait Transmit<'a> {
/// Set the transmit client, which will be called when transmissions
/// complete.
fn set_transmit_client(&self, client: &'a dyn TransmitClient);
/// Transmit a buffer of data. On completion, `transmitted_buffer`
/// in the `TransmitClient` will be called. If the `Result<(), ErrorCode>`
/// returned by `transmit` is an `Ok(())`, the struct will issue a `transmitted_buffer`
/// callback in the future. If the value of the `Result<(), ErrorCode>` is
/// `Err(), then the `tx_buffer` argument is returned in the
/// `Err()`, along with the `ErrorCode`.
/// Valid `ErrorCode` values are:
/// - OFF: The underlying hardware is not available, perhaps because
/// it has not been initialized or in the case of a shared
/// hardware USART controller because it is set up for SPI.
/// - BUSY: the UART is already transmitting and has not made a
/// transmission callback yet.
/// - SIZE : `tx_len` is larger than the passed slice.
/// - FAIL: some other error.
///
/// Each byte in `tx_buffer` is a UART transfer word of 8 or fewer
/// bits. The word width is determined by the UART configuration,
/// truncating any more significant bits. E.g., 0x18f transmitted in
/// 8N1 will be sent as 0x8f and in 7N1 will be sent as 0x0f. Clients
/// that need to transfer 9-bit words should use `transmit_word`.
///
/// Calling `transmit_buffer` while there is an outstanding
/// `transmit_buffer` or `transmit_word` operation will return BUSY.
fn transmit_buffer(
&self,
tx_buffer: &'static mut [u8],
tx_len: usize,
) -> Result<(), (ErrorCode, &'static mut [u8])>;
/// Transmit a single word of data asynchronously. The word length is
/// determined by the UART configuration: it can be 6, 7, 8, or 9 bits long.
/// If the `Result<(), ErrorCode>` is Ok(()), on completion,
/// `transmitted_word` will be called on the `TransmitClient`.
/// Other valid `Result<(), ErrorCode>` values are:
/// - OFF: The underlying hardware is not available, perhaps because
/// it has not been initialized or in the case of a shared
/// hardware USART controller because it is set up for SPI.
/// - BUSY: the UART is already transmitting and has not made a
/// transmission callback yet.
/// - FAIL: not supported, or some other error.
/// If the `Result<(), ErrorCode>` is not Ok(()), no callback will be made.
/// Calling `transmit_word` while there is an outstanding
/// `transmit_buffer` or `transmit_word` operation will return
/// BUSY.
fn transmit_word(&self, word: u32) -> Result<(), ErrorCode>;
/// Abort an outstanding call to `transmit_word` or `transmit_buffer`.
/// The return code indicates whether the call has fully terminated or
/// there will be a callback. Cancelled calls to `transmit_buffer` MUST
/// always make a callback, to return the passed buffer back to the caller.
///
/// If abort_transmit returns Ok(()), there will be no future
/// callback and the client may retransmit immediately. If
/// abort_transmit returns any other `Result<(), ErrorCode>` there will be a
/// callback. This means that if there is no outstanding call to
/// `transmit_word` or `transmit_buffer` then a call to
/// `abort_transmit` returns Ok(()). If there was a `transmit`
/// outstanding and is cancelled successfully then `BUSY` will
/// be returned and there will be a callback with a `Result<(), ErrorCode>`
/// of `CANCEL`. If there was a reception outstanding, which is
/// not cancelled successfully, then `FAIL` will be returned and
/// there will be a later callback.
///
/// Returns Ok(()) or
/// - FAIL if the outstanding call to either transmit operation could
/// not be synchronously cancelled. A callback will be made on the
/// client indicating whether the call was successfully cancelled.
fn transmit_abort(&self) -> Result<(), ErrorCode>;
}
pub trait Receive<'a> {
/// Set the receive client, which will he called when reads complete.
fn set_receive_client(&self, client: &'a dyn ReceiveClient);
/// Receive `rx_len` bytes into `rx_buffer`, making a callback to
/// the `ReceiveClient` when complete. If the `Result<(), ErrorCode>` of
/// `receive_buffer`'s return is `Ok(())`, the struct will issue a `received_buffer`
/// callback in the future. If the value of the `Result<(), ErrorCode>` is
/// `Err()`, then the `rx_buffer` argument is returned in the
/// `Err()`. Valid `ErrorCode` values are:
/// - OFF: The underlying hardware is not available, perhaps because
/// it has not been initialized or in the case of a shared
/// hardware USART controller because it is set up for SPI.
/// - BUSY: the UART is already receiving and has not made a
/// reception `complete` callback yet.
/// - SIZE : `rx_len` is larger than the passed slice.
/// Each byte in `rx_buffer` is a UART transfer word of 8 or fewer
/// bits. The width is determined by the UART
/// configuration. Clients that need to transfer 9-bit words
/// should use `receive_word`. Calling `receive_buffer` while
/// there is an outstanding `receive_buffer` or `receive_word`
/// operation will return `Err(BUSY, rx_buffer)`.
fn receive_buffer(
&self,
rx_buffer: &'static mut [u8],
rx_len: usize,
) -> Result<(), (ErrorCode, &'static mut [u8])>;
/// Receive a single word of data. The word length is determined
/// by the UART configuration: it can be 6, 7, 8, or 9 bits long.
/// If the `Result<(), ErrorCode>` is Ok(()), on completion,
/// `received_word` will be called on the `ReceiveClient`.
/// Other valid `ErrorCode` values are:
/// - OFF: The underlying hardware is not available, perhaps because
/// it has not been initialized or in the case of a shared
/// hardware USART controller because it is set up for SPI.
/// - BUSY: the UART is already receiving and has not made a
/// reception callback yet.
/// - FAIL: not supported or some other error.
/// Calling `receive_word` while there is an outstanding
/// `receive_buffer` or `receive_word` operation will return
/// `Err(BUSY).
fn receive_word(&self) -> Result<(), ErrorCode>;
/// Abort any ongoing receive transfers and return what is in the
/// receive buffer with the `receive_complete` callback. If
/// Ok(()) is returned, there will be no callback (no call to
/// `receive` was outstanding). If there was a `receive`
/// outstanding, which is cancelled successfully then `BUSY` will
/// be returned and there will be a callback with a `Result<(), ErrorCode>`
/// of `CANCEL`. If there was a reception outstanding, which is
/// not cancelled successfully, then `FAIL` will be returned and
/// there will be a later callback.
fn receive_abort(&self) -> Result<(), ErrorCode>;
}
/// Trait implemented by a UART transmitter to receive callbacks when
/// operations complete.
pub trait TransmitClient {
/// A call to `Transmit::transmit_word` completed. The `Result<(), ErrorCode>`
/// indicates whether the word was successfully transmitted. A call
/// to `transmit_word` or `transmit_buffer` made within this callback
/// SHOULD NOT return BUSY: when this callback is made the UART should
/// be ready to receive another call.
///
/// `rval` is Ok(()) if the word was successfully transmitted, or
/// - CANCEL if the call to `transmit_word` was cancelled and
/// the word was not transmitted.
/// - FAIL if the transmission failed in some way.
fn transmitted_word(&self, _rval: Result<(), ErrorCode>) {}
/// A call to `Transmit::transmit_buffer` completed. The `Result<(), ErrorCode>`
/// indicates whether the buffer was successfully transmitted. A call
/// to `transmit_word` or `transmit_buffer` made within this callback
/// SHOULD NOT return BUSY: when this callback is made the UART should
/// be ready to receive another call.
///
/// The `tx_len` argument specifies how many words were transmitted.
/// An `rval` of Ok(()) indicates that every requested word was
/// transmitted: `tx_len` in the callback should be the same as
/// `tx_len` in the initiating call.
///
/// `rval` is Ok(()) if the full buffer was successfully transmitted, or
/// - CANCEL if the call to `transmit_buffer` was cancelled and
/// the buffer was not fully transmitted. `tx_len` contains
/// how many words were transmitted.
/// - SIZE if the buffer could only be partially transmitted. `tx_len`
/// contains how many words were transmitted.
/// - FAIL if the transmission failed in some way.
fn transmitted_buffer(
&self,
tx_buffer: &'static mut [u8],
tx_len: usize,
rval: Result<(), ErrorCode>,
);
}
pub trait ReceiveClient {
/// A call to `Receive::receive_word` completed. The `Result<(), ErrorCode>`
/// indicates whether the word was successfully received. A call
/// to `receive_word` or `receive_buffer` made within this callback
/// SHOULD NOT return BUSY: when this callback is made the UART should
/// be ready to receive another call.
///
/// `rval` Ok(()) if the word was successfully received, or
/// - CANCEL if the call to `receive_word` was cancelled and
/// the word was not received: `word` should be ignored.
/// - FAIL if the reception failed in some way and `word`
/// should be ignored. `error` may contain further information
/// on the sort of error.
fn received_word(&self, _word: u32, _rval: Result<(), ErrorCode>, _error: Error) {}
/// A call to `Receive::receive_buffer` completed. The `Result<(), ErrorCode>`
/// indicates whether the buffer was successfully received. A call
/// to `receive_word` or `receive_buffer` made within this callback
/// SHOULD NOT return BUSY: when this callback is made the UART should
/// be ready to receive another call.
///
/// The `rx_len` argument specifies how many words were received.
/// An `rval` of Ok(()) indicates that every requested word was
/// received: `rx_len` in the callback should be the same as
/// `rx_len` in the initiating call.
///
/// `rval` is Ok(()) if the full buffer was successfully received, or
/// - CANCEL if the call to `received_buffer` was cancelled and
/// the buffer was not fully received. `rx_len` contains
/// how many words were received.
/// - SIZE if the buffer could only be partially received. `rx_len`
/// contains how many words were received.
/// - FAIL if reception failed in some way: `error` may contain further
/// information.
fn received_buffer(
&self,
rx_buffer: &'static mut [u8],
rx_len: usize,
rval: Result<(), ErrorCode>,
error: Error,
);
}
/// Trait that isn't required for basic UART operation, but provides useful
/// abstractions that capsules may want to be able to leverage.
///
/// The interfaces are included here because some hardware platforms may be able
/// to directly implement them, while others platforms may need to emulate them
/// in software. The ones that can implement them in hardware should be able to
/// leverage that efficiency, and by placing the interfaces here in the HIL they
/// can do that.
///
/// Other interface ideas that have been discussed, but are not included due to
/// the lack of a clear use case, but are noted here in case they might help
/// someone in the future:
/// - `receive_until_terminator`: This would read in bytes until a specified
/// byte is received (or the buffer is full) and then return to the client.
/// - `receive_len_then_message`: This would do a one byte read to get a length
/// byte and then read that many more bytes from UART before returning to the
/// client.
pub trait ReceiveAdvanced<'a>: Receive<'a> {
/// Receive data until `interbyte_timeout` bit periods have passed since the
/// last byte or buffer is full. Does not timeout until at least one byte
/// has been received.
///
/// * `interbyte_timeout`: number of bit periods since last data received.
fn receive_automatic(
&self,
rx_buffer: &'static mut [u8],
rx_len: usize,
interbyte_timeout: u8,
) -> Result<(), (ErrorCode, &'static mut [u8])>;
}