use core::convert::Infallible;
pub mod regs;
#[cfg(feature = "vor1x")]
use crate::InterruptConfig;
use crate::{
FunctionSelect,
gpio::{DynPinId, IoPeriphPin},
pins::AnyPin,
sealed::Sealed,
};
use arbitrary_int::{prelude::*, u6, u18};
use regs::{ClockScale, Control, Data, Enable, FifoClear, InterruptClear, MmioUart};
use crate::{PeripheralSelect, enable_nvic_interrupt, enable_peripheral_clock, time::Hertz};
use embedded_hal_nb::serial::Read;
pub use regs::{Bank, Stopbits, WordSize};
#[cfg(feature = "vor1x")]
mod pins_vor1x;
#[cfg(feature = "vor4x")]
mod pins_vor4x;
#[cfg(feature = "vor4x")]
use crate::clock::Clocks;
#[cfg(feature = "vor1x")]
use va108xx as pac;
#[cfg(feature = "vor4x")]
use va416xx as pac;
pub mod tx_async;
pub use tx_async::*;
pub mod rx_async;
pub use rx_async::*;
pub trait TxPin0: AnyPin {
const BANK: Bank = Bank::Uart0;
const FUNC_SEL: FunctionSelect;
}
pub trait RxPin0: AnyPin {
const BANK: Bank = Bank::Uart0;
const FUNC_SEL: FunctionSelect;
}
pub trait TxPin1: AnyPin {
const BANK: Bank = Bank::Uart1;
const FUNC_SEL: FunctionSelect;
}
pub trait RxPin1: AnyPin {
const BANK: Bank = Bank::Uart1;
const FUNC_SEL: FunctionSelect;
}
#[cfg(feature = "vor4x")]
pub trait TxPin2: AnyPin {
const BANK: Bank = Bank::Uart2;
const FUNC_SEL: FunctionSelect;
}
#[cfg(feature = "vor4x")]
pub trait RxPin2: AnyPin {
const BANK: Bank = Bank::Uart2;
const FUNC_SEL: FunctionSelect;
}
#[derive(Debug, PartialEq, Eq, thiserror::Error)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[error("no interrupt ID was set")]
pub struct NoInterruptIdWasSet;
#[derive(Debug, PartialEq, Eq, thiserror::Error)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[error("transer is pending")]
pub struct TransferPendingError;
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Event {
RxFifoHalfFull,
RxError,
RxTimeout,
TxFifoHalfFull,
TxError,
TxEmpty,
TxCts,
}
#[derive(Debug, Default, Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum BaudMode {
#[default]
_16 = 0,
_8 = 1,
}
impl BaudMode {
pub const fn multiplier(&self) -> u32 {
match self {
BaudMode::_16 => 16,
BaudMode::_8 => 8,
}
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Parity {
None,
Odd,
Even,
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct ClockConfig {
pub div: u18,
pub frac: u6,
pub baud_mode: BaudMode,
}
impl ClockConfig {
pub const fn calculate(ref_clk: Hertz, baudrate: Hertz, baud_mode: BaudMode) -> Self {
let multiplier = baud_mode.multiplier();
let frac = ((ref_clk.to_raw() % (baudrate.to_raw() * multiplier)) * 64
+ (baudrate.to_raw() * (multiplier / 2)))
/ (baudrate.to_raw() * multiplier);
let integer_div = ref_clk.to_raw() / (baudrate.to_raw() * multiplier);
Self {
frac: u6::new(frac as u8),
div: u18::new(integer_div),
baud_mode,
}
}
#[cfg(feature = "vor4x")]
pub fn calculate_with_clocks(
uart_id: Bank,
clks: &Clocks,
baudrate: Hertz,
baud_mode: BaudMode,
) -> Self {
let clk = if uart_id == Bank::Uart2 {
clks.apb1()
} else {
clks.apb2()
};
Self::calculate(clk, baudrate, baud_mode)
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct Config {
pub clock_config: ClockConfig,
pub parity: Parity,
pub stopbits: Stopbits,
pub wordsize: WordSize,
pub enable_tx: bool,
pub enable_rx: bool,
}
impl Config {
pub fn new_with_clock_config(clock_config: ClockConfig) -> Self {
Config {
clock_config,
parity: Parity::None,
stopbits: Stopbits::One,
wordsize: WordSize::Eight,
enable_tx: true,
enable_rx: true,
}
}
pub fn with_clock_config(mut self, clock_config: ClockConfig) -> Self {
self.clock_config = clock_config;
self
}
pub fn with_parity_none(mut self) -> Self {
self.parity = Parity::None;
self
}
pub fn with_parity_even(mut self) -> Self {
self.parity = Parity::Even;
self
}
pub fn with_parity_odd(mut self) -> Self {
self.parity = Parity::Odd;
self
}
pub fn with_stopbits(mut self, stopbits: Stopbits) -> Self {
self.stopbits = stopbits;
self
}
pub fn with_wordsize(mut self, wordsize: WordSize) -> Self {
self.wordsize = wordsize;
self
}
}
#[derive(Debug, Copy, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct InterruptContextTimeoutOrMaxSize {
rx_idx: usize,
mode: InterruptReceptionMode,
pub max_len: usize,
}
impl InterruptContextTimeoutOrMaxSize {
pub fn new(max_len: usize) -> Self {
InterruptContextTimeoutOrMaxSize {
rx_idx: 0,
max_len,
mode: InterruptReceptionMode::Idle,
}
}
}
impl InterruptContextTimeoutOrMaxSize {
pub fn reset(&mut self) {
self.rx_idx = 0;
self.mode = InterruptReceptionMode::Idle;
}
}
#[derive(Debug, Default)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct InterruptResult {
pub bytes_read: usize,
pub errors: Option<UartErrors>,
}
#[derive(Debug, Default)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct InterruptResultMaxSizeOrTimeout {
complete: bool,
timeout: bool,
pub errors: Option<UartErrors>,
pub bytes_read: usize,
}
impl InterruptResultMaxSizeOrTimeout {
pub fn new() -> Self {
InterruptResultMaxSizeOrTimeout {
complete: false,
timeout: false,
errors: None,
bytes_read: 0,
}
}
}
impl InterruptResultMaxSizeOrTimeout {
#[inline]
pub fn has_errors(&self) -> bool {
self.errors.is_some()
}
#[inline]
pub fn overflow_error(&self) -> bool {
self.errors.is_some_and(|e| e.overflow)
}
#[inline]
pub fn framing_error(&self) -> bool {
self.errors.is_some_and(|e| e.framing)
}
#[inline]
pub fn parity_error(&self) -> bool {
self.errors.is_some_and(|e| e.parity)
}
#[inline]
pub fn timeout(&self) -> bool {
self.timeout
}
#[inline]
pub fn complete(&self) -> bool {
self.complete
}
}
#[derive(Debug, PartialEq, Copy, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
enum InterruptReceptionMode {
Idle,
Pending,
}
#[derive(Default, Debug, Copy, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct UartErrors {
overflow: bool,
framing: bool,
parity: bool,
other: bool,
}
impl UartErrors {
#[inline(always)]
pub fn overflow(&self) -> bool {
self.overflow
}
#[inline(always)]
pub fn framing(&self) -> bool {
self.framing
}
#[inline(always)]
pub fn parity(&self) -> bool {
self.parity
}
#[inline(always)]
pub fn other(&self) -> bool {
self.other
}
}
impl UartErrors {
#[inline(always)]
pub fn error(&self) -> bool {
self.overflow || self.framing || self.parity || self.other
}
}
#[derive(Debug, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct BufferTooShortError {
found: usize,
expected: usize,
}
pub trait Uart0Instance: Sealed {
const ID: Bank = Bank::Uart0;
const PERIPH_SEL: PeripheralSelect;
}
pub trait Uart1Instance: Sealed {
const ID: Bank = Bank::Uart1;
const PERIPH_SEL: PeripheralSelect;
}
#[cfg(feature = "vor4x")]
pub trait Uart2Instance: Sealed {
const ID: Bank = Bank::Uart2;
const PERIPH_SEL: PeripheralSelect;
}
#[cfg(feature = "vor1x")]
pub type Uart0 = pac::Uarta;
#[cfg(feature = "vor4x")]
pub type Uart0 = pac::Uart0;
impl Uart0Instance for Uart0 {
const ID: Bank = Bank::Uart0;
const PERIPH_SEL: PeripheralSelect = PeripheralSelect::Uart0;
}
impl Sealed for Uart0 {}
#[cfg(feature = "vor1x")]
pub type Uart1 = pac::Uartb;
#[cfg(feature = "vor4x")]
pub type Uart1 = pac::Uart1;
impl Uart1Instance for Uart1 {
const ID: Bank = Bank::Uart1;
const PERIPH_SEL: PeripheralSelect = PeripheralSelect::Uart1;
}
impl Sealed for Uart1 {}
#[cfg(feature = "vor4x")]
impl Uart2Instance for pac::Uart2 {
const ID: Bank = Bank::Uart2;
const PERIPH_SEL: PeripheralSelect = PeripheralSelect::Uart2;
}
#[cfg(feature = "vor4x")]
impl Sealed for pac::Uart2 {}
pub struct Uart {
tx: Tx,
rx: Rx,
}
impl Uart {
cfg_if::cfg_if! {
if #[cfg(feature = "vor1x")] {
pub fn new_with_interrupt_uart0<Uart: Uart0Instance, Tx: TxPin0, Rx: RxPin0>(
uart: Uart,
tx_pin: Tx,
rx_pin: Rx,
config: Config,
irq_cfg: InterruptConfig,
) -> Self {
Self::new_for_uart0(uart, tx_pin, rx_pin, config, Some(irq_cfg))
}
pub fn new_with_interrupt_uart1<Uart: Uart1Instance, Tx: TxPin1, Rx: RxPin1>(
uart: Uart,
tx_pin: Tx,
rx_pin: Rx,
config: Config,
irq_cfg: InterruptConfig,
) -> Self {
Self::new_for_uart1(uart, tx_pin, rx_pin, config, Some(irq_cfg))
}
pub fn new_without_interrupt_uart0<Uart: Uart0Instance, Tx: TxPin0, Rx: RxPin0>(
uart: Uart,
tx_pin: Tx,
rx_pin: Rx,
config: Config,
) -> Self {
Self::new_for_uart0(uart, tx_pin, rx_pin, config, None)
}
pub fn new_without_interrupt_uart1<Uart: Uart1Instance, Tx: TxPin1, Rx: RxPin1>(
uart: Uart,
tx_pin: Tx,
rx_pin: Rx,
config: Config,
) -> Self {
Self::new_for_uart1(uart, tx_pin, rx_pin, config, None)
}
pub fn new_for_uart0<Uart: Uart0Instance, Tx: TxPin0, Rx: RxPin0>(
_uart: Uart,
_tx_pin: Tx,
_rx_pin: Rx,
config: Config,
opt_irq_cfg: Option<InterruptConfig>,
) -> Self {
Self::new_internal(
Uart::PERIPH_SEL,
Uart::ID,
Tx::ID,
Tx::FUNC_SEL,
Rx::ID,
Rx::FUNC_SEL,
config,
opt_irq_cfg
)
}
pub fn new_for_uart1<Uart: Uart1Instance, Tx: TxPin1, Rx: RxPin1>(
_uart: Uart,
_tx_pin: Tx,
_rx_pin: Rx,
config: Config,
opt_irq_cfg: Option<InterruptConfig>,
) -> Self {
Self::new_internal(
Uart::PERIPH_SEL,
Uart::ID,
Tx::ID,
Tx::FUNC_SEL,
Rx::ID,
Rx::FUNC_SEL,
config,
opt_irq_cfg
)
}
} else if #[cfg(feature = "vor4x")] {
pub fn new_for_uart0<Uart: Uart0Instance, Tx: TxPin0, Rx: RxPin0>(
_uart: Uart,
_tx_pin: Tx,
_rx_pin: Rx,
config: Config,
) -> Self {
Self::new_internal(
Uart::PERIPH_SEL,
Uart::ID,
Tx::ID,
Tx::FUNC_SEL,
Rx::ID,
Rx::FUNC_SEL,
config
)
}
pub fn new_for_uart1<Uart: Uart1Instance, Tx: TxPin1, Rx: RxPin1>(
_uart: Uart,
_tx_pin: Tx,
_rx_pin: Rx,
config: Config,
) -> Self {
Self::new_internal(
Uart::PERIPH_SEL,
Uart::ID,
Tx::ID,
Tx::FUNC_SEL,
Rx::ID,
Rx::FUNC_SEL,
config
)
}
pub fn new_for_uart2<Uart: Uart2Instance, Tx: TxPin2, Rx: RxPin2>(
_uart: Uart,
_tx_pin: Tx,
_rx_pin: Rx,
config: Config,
) -> Self {
Self::new_internal(
Uart::PERIPH_SEL,
Uart::ID,
Tx::ID,
Tx::FUNC_SEL,
Rx::ID,
Rx::FUNC_SEL,
config
)
}
pub fn new_with_ref_clk_uart0<Uart: Uart0Instance, Tx: TxPin0, Rx: RxPin0>(
_uart: Uart,
_tx_pin: Tx,
_rx_pin: Rx,
config: Config,
) -> Self {
Self::new_internal(
Uart::PERIPH_SEL,
Uart::ID,
Tx::ID,
Tx::FUNC_SEL,
Rx::ID,
Rx::FUNC_SEL,
config
)
}
pub fn new_with_ref_clk_uart1<Uart: Uart1Instance, Tx: TxPin1, Rx: RxPin1>(
_uart: Uart,
_tx_pin: Tx,
_rx_pin: Rx,
config: Config,
) -> Self {
Self::new_internal(
Uart::PERIPH_SEL,
Uart::ID,
Tx::ID,
Tx::FUNC_SEL,
Rx::ID,
Rx::FUNC_SEL,
config
)
}
pub fn new_with_ref_clk_uart2<Uart: Uart2Instance, Tx: TxPin2, Rx: RxPin2>(
_uart: Uart,
_tx_pin: Tx,
_rx_pin: Rx,
config: Config,
) -> Self {
Self::new_internal(
Uart::PERIPH_SEL,
Uart::ID,
Tx::ID,
Tx::FUNC_SEL,
Rx::ID,
Rx::FUNC_SEL,
config
)
}
}
}
#[allow(clippy::too_many_arguments)]
fn new_internal(
periph_sel: PeripheralSelect,
uart_bank: Bank,
tx_pin_id: DynPinId,
tx_func_sel: FunctionSelect,
rx_pin_id: DynPinId,
rx_func_sel: FunctionSelect,
config: Config,
#[cfg(feature = "vor1x")] opt_irq_cfg: Option<InterruptConfig>,
) -> Self {
IoPeriphPin::new(tx_pin_id, tx_func_sel, None);
IoPeriphPin::new(rx_pin_id, rx_func_sel, None);
enable_peripheral_clock(periph_sel);
let mut reg_block = regs::Uart::new_mmio(uart_bank);
reg_block.write_clkscale(
ClockScale::builder()
.with_int(config.clock_config.div)
.with_frac(config.clock_config.frac)
.build(),
);
let (paren, pareven) = match config.parity {
Parity::None => (false, false),
Parity::Odd => (true, false),
Parity::Even => (true, true),
};
reg_block.write_ctrl(
Control::builder()
.with_baud8(config.clock_config.baud_mode == BaudMode::_8)
.with_auto_rts(false)
.with_def_rts(false)
.with_auto_cts(false)
.with_loopback_block(false)
.with_loopback(false)
.with_wordsize(config.wordsize)
.with_stopbits(config.stopbits)
.with_parity_manual(false)
.with_parity_even(pareven)
.with_parity_enable(paren)
.build(),
);
reg_block.write_fifo_clr(FifoClear::builder().with_tx(true).with_rx(true).build());
reg_block.write_enable(
Enable::builder()
.with_tx(config.enable_tx)
.with_rx(config.enable_rx)
.build(),
);
#[cfg(feature = "vor1x")]
if let Some(irq_cfg) = opt_irq_cfg {
if irq_cfg.route {
enable_peripheral_clock(PeripheralSelect::Irqsel);
unsafe { va108xx::Irqsel::steal() }
.uart(uart_bank as usize)
.write(|w| unsafe { w.bits(irq_cfg.id as u32) });
}
if irq_cfg.enable_in_nvic {
unsafe { enable_nvic_interrupt(irq_cfg.id) };
}
}
Uart {
tx: Tx::new(uart_bank),
rx: Rx::new(uart_bank),
}
}
#[inline]
pub fn peripheral_id(&self) -> u32 {
self.tx.perid()
}
#[inline]
pub fn enable_rx(&mut self) {
self.rx.enable();
}
#[inline]
pub fn disable_rx(&mut self) {
self.rx.disable();
}
#[inline]
pub fn enable_tx(&mut self) {
self.tx.enable();
}
#[inline]
pub fn disable_tx(&mut self) {
self.tx.disable();
}
#[inline]
pub fn clear_rx_fifo(&mut self) {
self.rx.clear_fifo();
}
#[inline]
pub fn clear_tx_fifo(&mut self) {
self.tx.clear_fifo();
}
pub fn listen(&mut self, event: Event) {
self.tx.regs.modify_irq_enabled(|mut value| {
match event {
Event::RxError => value.set_rx_status(true),
Event::RxFifoHalfFull => value.set_rx(true),
Event::RxTimeout => value.set_rx_timeout(true),
Event::TxEmpty => value.set_tx_empty(true),
Event::TxError => value.set_tx_status(true),
Event::TxFifoHalfFull => value.set_tx(true),
Event::TxCts => value.set_tx_cts(true),
}
value
});
}
pub fn unlisten(&mut self, event: Event) {
self.tx.regs.modify_irq_enabled(|mut value| {
match event {
Event::RxError => value.set_rx_status(false),
Event::RxFifoHalfFull => value.set_rx(false),
Event::RxTimeout => value.set_rx_timeout(false),
Event::TxEmpty => value.set_tx_empty(false),
Event::TxError => value.set_tx_status(false),
Event::TxFifoHalfFull => value.set_tx(false),
Event::TxCts => value.set_tx_cts(false),
}
value
});
}
pub fn poll_rx_errors(&self) -> Option<UartErrors> {
self.rx.poll_errors()
}
pub fn split(self) -> (Tx, Rx) {
(self.tx, self.rx)
}
}
impl embedded_io::ErrorType for Uart {
type Error = Infallible;
}
impl embedded_hal_nb::serial::ErrorType for Uart {
type Error = Infallible;
}
impl embedded_hal_nb::serial::Read<u8> for Uart {
fn read(&mut self) -> nb::Result<u8, Self::Error> {
self.rx.read()
}
}
impl embedded_hal_nb::serial::Write<u8> for Uart {
fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> {
self.tx.write(word).map_err(|e| {
if let nb::Error::Other(_) = e {
unreachable!()
}
nb::Error::WouldBlock
})
}
fn flush(&mut self) -> nb::Result<(), Self::Error> {
self.tx.flush().map_err(|e| {
if let nb::Error::Other(_) = e {
unreachable!()
}
nb::Error::WouldBlock
})
}
}
#[inline(always)]
pub fn enable_rx(uart: &mut MmioUart<'static>) {
uart.modify_enable(|mut value| {
value.set_rx(true);
value
});
}
#[inline(always)]
pub fn disable_rx(uart: &mut MmioUart<'static>) {
uart.modify_enable(|mut value| {
value.set_rx(false);
value
});
}
#[inline(always)]
pub fn enable_rx_interrupts(uart: &mut MmioUart<'static>, timeout: bool) {
uart.modify_irq_enabled(|mut value| {
value.set_rx_status(true);
value.set_rx(true);
if timeout {
value.set_rx_timeout(true);
}
value
});
}
#[inline(always)]
pub fn disable_rx_interrupts(uart: &mut MmioUart<'static>) {
uart.modify_irq_enabled(|mut value| {
value.set_rx_status(false);
value.set_rx(false);
value.set_rx_timeout(false);
value
});
}
pub struct Rx {
id: Bank,
regs: regs::MmioUart<'static>,
}
impl Rx {
#[inline(always)]
pub unsafe fn steal(id: Bank) -> Self {
Self::new(id)
}
#[inline(always)]
fn new(id: Bank) -> Self {
Self {
id,
regs: regs::Uart::new_mmio(id),
}
}
pub fn poll_errors(&self) -> Option<UartErrors> {
let mut errors = UartErrors::default();
let status = self.regs.read_rx_status();
if status.overrun_error() {
errors.overflow = true;
} else if status.framing_error() {
errors.framing = true;
} else if status.parity_error() {
errors.parity = true;
} else {
return None;
};
Some(errors)
}
#[inline]
pub fn perid(&self) -> u32 {
self.regs.read_perid()
}
#[inline]
pub fn clear_fifo(&mut self) {
self.regs
.write_fifo_clr(FifoClear::builder().with_tx(false).with_rx(true).build());
}
#[inline]
pub fn disable_interrupts(&mut self) {
disable_rx_interrupts(&mut self.regs);
}
#[inline]
pub fn enable_interrupts(
&mut self,
#[cfg(feature = "vor4x")] enable_in_nvic: bool,
timeout: bool,
) {
#[cfg(feature = "vor4x")]
if enable_in_nvic {
unsafe {
enable_nvic_interrupt(self.id.interrupt_id_rx());
}
}
enable_rx_interrupts(&mut self.regs, timeout);
}
#[inline]
pub fn enable(&mut self) {
enable_rx(&mut self.regs);
}
#[inline]
pub fn disable(&mut self) {
disable_rx(&mut self.regs);
}
#[inline(always)]
pub fn read_fifo(&mut self) -> nb::Result<u32, Infallible> {
if !self.regs.read_rx_status().data_available() {
return Err(nb::Error::WouldBlock);
}
Ok(self.read_fifo_unchecked())
}
#[inline(always)]
pub fn read_fifo_unchecked(&mut self) -> u32 {
self.regs.read_data().raw_value()
}
pub fn into_rx_with_irq(self) -> RxWithInterrupt {
RxWithInterrupt::new(self)
}
}
impl embedded_io::ErrorType for Rx {
type Error = Infallible;
}
impl embedded_hal_nb::serial::ErrorType for Rx {
type Error = Infallible;
}
impl embedded_hal_nb::serial::Read<u8> for Rx {
fn read(&mut self) -> nb::Result<u8, Self::Error> {
self.read_fifo().map(|val| (val & 0xff) as u8).map_err(|e| {
if let nb::Error::Other(_) = e {
unreachable!()
}
nb::Error::WouldBlock
})
}
}
impl embedded_io::Read for Rx {
fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
if buf.is_empty() {
return Ok(0);
}
let mut read = 0;
loop {
if self.regs.read_rx_status().data_available() {
break;
}
}
for byte in buf.iter_mut() {
match <Self as embedded_hal_nb::serial::Read<u8>>::read(self) {
Ok(w) => {
*byte = w;
read += 1;
}
Err(nb::Error::WouldBlock) => break,
}
}
Ok(read)
}
}
#[inline(always)]
pub fn enable_tx(uart: &mut MmioUart<'static>) {
uart.modify_enable(|mut value| {
value.set_tx(true);
value
});
}
#[inline(always)]
pub fn disable_tx(uart: &mut MmioUart<'static>) {
uart.modify_enable(|mut value| {
value.set_tx(false);
value
});
}
#[inline(always)]
pub fn enable_tx_interrupts(uart: &mut MmioUart<'static>) {
uart.modify_irq_enabled(|mut value| {
value.set_tx(true);
value.set_tx_empty(true);
value.set_tx_status(true);
value
});
}
#[inline(always)]
pub fn disable_tx_interrupts(uart: &mut MmioUart<'static>) {
uart.modify_irq_enabled(|mut value| {
value.set_tx(false);
value.set_tx_empty(false);
value.set_tx_status(false);
value
});
}
pub struct Tx {
id: Bank,
regs: regs::MmioUart<'static>,
}
impl Tx {
#[inline(always)]
pub unsafe fn steal(id: Bank) -> Self {
Self::new(id)
}
#[inline(always)]
fn new(id: Bank) -> Self {
Self {
id,
regs: regs::Uart::new_mmio(id),
}
}
#[inline]
pub fn perid(&self) -> u32 {
self.regs.read_perid()
}
#[inline]
pub fn clear_fifo(&mut self) {
self.regs
.write_fifo_clr(FifoClear::builder().with_tx(true).with_rx(false).build());
}
#[inline]
pub fn enable(&mut self) {
self.regs.modify_enable(|mut value| {
value.set_tx(true);
value
});
}
#[inline]
pub fn disable(&mut self) {
self.regs.modify_enable(|mut value| {
value.set_tx(false);
value
});
}
#[inline]
pub fn enable_interrupts(&mut self, #[cfg(feature = "vor4x")] enable_in_nvic: bool) {
#[cfg(feature = "vor4x")]
if enable_in_nvic {
unsafe { enable_nvic_interrupt(self.id.interrupt_id_tx()) };
}
enable_tx_interrupts(&mut self.regs);
}
#[inline]
pub fn disable_interrupts(&mut self) {
disable_tx_interrupts(&mut self.regs);
}
#[inline(always)]
pub fn write_fifo(&mut self, data: u32) -> nb::Result<(), Infallible> {
if !self.regs.read_tx_status().ready() {
return Err(nb::Error::WouldBlock);
}
self.write_fifo_unchecked(data);
Ok(())
}
#[inline(always)]
pub fn write_fifo_unchecked(&mut self, data: u32) {
self.regs.write_data(Data::new_with_raw_value(data));
}
pub fn into_async(self) -> TxAsync {
TxAsync::new(self)
}
}
impl embedded_io::ErrorType for Tx {
type Error = Infallible;
}
impl embedded_hal_nb::serial::ErrorType for Tx {
type Error = Infallible;
}
impl embedded_hal_nb::serial::Write<u8> for Tx {
fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> {
self.write_fifo(word as u32)
}
fn flush(&mut self) -> nb::Result<(), Self::Error> {
if self.regs.read_tx_status().write_busy() {
return Err(nb::Error::WouldBlock);
}
Ok(())
}
}
impl embedded_io::Write for Tx {
fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
if buf.is_empty() {
return Ok(0);
}
loop {
if self.regs.read_tx_status().ready() {
break;
}
}
let mut written = 0;
for byte in buf.iter() {
match <Self as embedded_hal_nb::serial::Write<u8>>::write(self, *byte) {
Ok(_) => written += 1,
Err(nb::Error::WouldBlock) => return Ok(written),
}
}
Ok(written)
}
fn flush(&mut self) -> Result<(), Self::Error> {
nb::block!(<Self as embedded_hal_nb::serial::Write<u8>>::flush(self))
}
}
pub struct RxWithInterrupt(Rx);
impl RxWithInterrupt {
pub fn new(rx: Rx) -> Self {
Self(rx)
}
pub unsafe fn steal(id: Bank) -> Self {
Self(unsafe { Rx::steal(id) })
}
pub fn start(&mut self) {
#[cfg(feature = "vor4x")]
self.enable_interrupts(true, true);
#[cfg(feature = "vor1x")]
self.enable_interrupts(true);
self.0.enable();
}
#[inline(always)]
pub fn rx(&self) -> &Rx {
&self.0
}
pub fn read_fixed_len_or_timeout_based_using_irq(
&mut self,
context: &mut InterruptContextTimeoutOrMaxSize,
) -> Result<(), TransferPendingError> {
if context.mode != InterruptReceptionMode::Idle {
return Err(TransferPendingError);
}
context.mode = InterruptReceptionMode::Pending;
context.rx_idx = 0;
self.start();
Ok(())
}
#[inline]
fn enable_interrupts(&mut self, #[cfg(feature = "vor4x")] enable_in_nvic: bool, timeout: bool) {
#[cfg(feature = "vor4x")]
self.0.enable_interrupts(enable_in_nvic, timeout);
#[cfg(feature = "vor1x")]
self.0.enable_interrupts(timeout);
}
#[inline]
fn disable_interrupts(&mut self) {
self.0.disable_interrupts();
}
pub fn cancel_transfer(&mut self) {
self.disable_interrupts();
self.0.clear_fifo();
}
pub fn on_interrupt(&mut self, buf: &mut [u8; 16]) -> InterruptResult {
let mut result = InterruptResult::default();
let irq_status = self.0.regs.read_irq_status();
let irq_enabled = self.0.regs.read_irq_enabled();
let rx_enabled = irq_enabled.rx();
if irq_status.rx() {
let available_bytes = self.0.regs.read_rx_fifo_trigger().level().as_usize();
for _ in 0..available_bytes {
buf[result.bytes_read] = (self.0.read_fifo_unchecked() & 0xff) as u8;
result.bytes_read += 1;
}
}
if irq_status.rx_timeout() {
while let Ok(byte) = self.0.read_fifo() {
buf[result.bytes_read] = byte as u8;
result.bytes_read += 1;
}
}
if rx_enabled {
self.check_for_errors(&mut result.errors);
}
self.0.regs.write_irq_clr(
InterruptClear::builder()
.with_rx_overrun(true)
.with_tx_overrun(false)
.build(),
);
result
}
pub fn on_interrupt_max_size_or_timeout_based(
&mut self,
context: &mut InterruptContextTimeoutOrMaxSize,
buf: &mut [u8],
) -> Result<InterruptResultMaxSizeOrTimeout, BufferTooShortError> {
if buf.len() < context.max_len {
return Err(BufferTooShortError {
found: buf.len(),
expected: context.max_len,
});
}
let mut result = InterruptResultMaxSizeOrTimeout::default();
let irq_status = self.0.regs.read_irq_status();
let rx_enabled = self.0.regs.read_enable().rx();
if irq_status.rx() {
let available_bytes = self.0.regs.read_rx_fifo_trigger().level().as_usize();
let bytes_to_read = core::cmp::min(
available_bytes.saturating_sub(1),
context.max_len - context.rx_idx,
);
for _ in 0..bytes_to_read {
buf[context.rx_idx] = (self.0.read_fifo_unchecked() & 0xff) as u8;
context.rx_idx += 1;
}
}
if irq_status.rx_timeout() {
loop {
if context.rx_idx == context.max_len {
break;
}
match self.0.read() {
Ok(byte) => {
buf[context.rx_idx] = byte;
context.rx_idx += 1;
}
Err(_) => break,
}
}
self.irq_completion_handler_max_size_timeout(&mut result, context);
return Ok(result);
}
if (context.rx_idx < context.max_len) && rx_enabled {
self.check_for_errors(&mut result.errors);
}
self.0.regs.write_irq_clr(
InterruptClear::builder()
.with_rx_overrun(true)
.with_tx_overrun(false)
.build(),
);
Ok(result)
}
fn check_for_errors(&self, errors: &mut Option<UartErrors>) {
let rx_status = self.0.regs.read_rx_status();
if rx_status.overrun_error() || rx_status.framing_error() || rx_status.parity_error() {
let err = errors.get_or_insert(UartErrors::default());
if rx_status.overrun_error() {
err.overflow = true;
}
if rx_status.framing_error() {
err.framing = true;
}
if rx_status.parity_error() {
err.parity = true;
}
}
}
fn irq_completion_handler_max_size_timeout(
&mut self,
res: &mut InterruptResultMaxSizeOrTimeout,
context: &mut InterruptContextTimeoutOrMaxSize,
) {
self.disable_interrupts();
self.0.disable();
res.bytes_read = context.rx_idx;
res.complete = true;
context.mode = InterruptReceptionMode::Idle;
context.rx_idx = 0;
}
pub unsafe fn release(mut self) -> Rx {
self.disable_interrupts();
self.0
}
}