mod uart_dma;
mod uart_it;
mod uart_poll;
pub use uart_dma::*;
pub use uart_it::*;
pub use uart_poll::*;
use crate::common::{
embedded_hal_nb as e_nb, embedded_io as e_io, fugit::MicrosDurationU32, prelude::*,
};
use core::fmt::Display;
pub struct UartIdleInterrupt<U: UartPeriph> {
uart: U,
}
impl<U: UartPeriph> UartIdleInterrupt<U> {
pub fn new(uart: U) -> Self {
Self { uart }
}
#[inline]
pub fn check_and_clear_interrupt(&mut self) -> bool {
self.uart.check_and_clear_interrupt(Event::Idle)
}
#[inline]
pub fn listen(&mut self) {
self.uart.set_interrupt(Event::Idle, true);
}
#[inline]
pub fn unlisten(&mut self) {
self.uart.set_interrupt(Event::Idle, false);
}
}
pub trait UartPeriph {
fn write(&mut self, word: u16) -> nb::Result<(), Error>;
fn write_with(&mut self, f: impl FnOnce() -> Option<u16>) -> Option<bool>;
fn is_tx_complete(&self) -> bool;
fn read(&mut self) -> nb::Result<u16, Error>;
fn set_interrupt(&mut self, event: Event, enable: bool);
fn is_interrupt_enable(&mut self, event: Event) -> bool;
fn check_and_clear_interrupt(&mut self, event: Event) -> bool;
fn clear_err_flag(&self);
}
pub trait UartPeriphWithDma: UartPeriph {
fn get_tx_data_reg_addr(&self) -> usize;
fn get_rx_data_reg_addr(&self) -> usize;
fn enable_dma_tx(&mut self, enable: bool);
fn enable_dma_rx(&mut self, enable: bool);
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Event {
TxEmpty,
RxNotEmpty,
Idle,
}
#[derive(Debug)]
#[non_exhaustive]
pub enum Error {
Overrun,
FrameFormat,
Parity,
Noise,
Busy,
Other,
}
impl Display for Error {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
Self::Overrun => write!(f, "UART overrun error"),
Self::FrameFormat => write!(f, "UART frame format error"),
Self::Parity => write!(f, "UART parity error"),
Self::Noise => write!(f, "UART noise error"),
Self::Busy => write!(f, "UART busy"),
Self::Other => write!(f, "UART other error"),
}
}
}
impl core::error::Error for Error {}
impl embedded_io::Error for Error {
#[inline]
fn kind(&self) -> e_io::ErrorKind {
match self {
Self::Overrun => e_io::ErrorKind::InvalidData,
Self::FrameFormat => e_io::ErrorKind::InvalidData,
Self::Parity => e_io::ErrorKind::InvalidData,
Self::Noise => e_io::ErrorKind::InvalidData,
Self::Busy => e_io::ErrorKind::WriteZero,
Self::Other => e_io::ErrorKind::Other,
}
}
}
impl e_nb::serial::Error for Error {
#[inline]
fn kind(&self) -> e_nb::serial::ErrorKind {
match self {
Self::Overrun => e_nb::serial::ErrorKind::Overrun,
Self::FrameFormat => e_nb::serial::ErrorKind::FrameFormat,
Self::Parity => e_nb::serial::ErrorKind::Parity,
Self::Noise => e_nb::serial::ErrorKind::Noise,
Self::Busy => e_nb::serial::ErrorKind::Other,
Self::Other => e_nb::serial::ErrorKind::Other,
}
}
}
pub enum WordLength {
Bits8,
Bits9,
}
pub enum Parity {
ParityNone,
ParityEven,
ParityOdd,
}
pub enum StopBits {
STOP1,
STOP0P5,
STOP2,
STOP1P5,
}
pub struct Config {
pub baudrate: u32,
pub word_length: WordLength,
pub parity: Parity,
pub stop_bits: StopBits,
}
impl Default for Config {
fn default() -> Config {
Config {
baudrate: 115_200,
word_length: WordLength::Bits8,
parity: Parity::ParityNone,
stop_bits: StopBits::STOP1,
}
}
}
impl Config {
pub fn baudrate(mut self, baudrate: u32) -> Self {
self.baudrate = baudrate;
self
}
pub fn word_length(mut self, wordlength: WordLength) -> Self {
self.word_length = wordlength;
self
}
pub fn word_length_8bits(mut self) -> Self {
self.word_length = WordLength::Bits8;
self
}
pub fn word_length_9bits(mut self) -> Self {
self.word_length = WordLength::Bits9;
self
}
pub fn parity(mut self, parity: Parity) -> Self {
self.parity = parity;
self
}
pub fn parity_none(mut self) -> Self {
self.parity = Parity::ParityNone;
self
}
pub fn parity_even(mut self) -> Self {
self.parity = Parity::ParityEven;
self
}
pub fn parity_odd(mut self) -> Self {
self.parity = Parity::ParityOdd;
self
}
pub fn stop_bits(mut self, stop_bits: StopBits) -> Self {
self.stop_bits = stop_bits;
self
}
}
#[inline]
const fn calculate_timeout(baudrate: u32, data_len: usize) -> MicrosDurationU32 {
let bytes_per_sec = baudrate / 12;
MicrosDurationU32::micros((data_len * 1_000_000) as u32 / bytes_per_sec)
}