some-serial 0.7.6

Unified serial driver collection for embedded and bare-metal environments
Documentation
use super::*;

pub(super) fn read_rx_sample(
    registers: &Pl011Registers,
    saved_status: &mut Pl011RxStatus,
) -> Option<RxSample> {
    if registers.uartfr.is_set(UARTFR::RXFE) {
        *saved_status |= Pl011RxStatus::from_rsr(registers.uartrsr_ecr.extract());
        return saved_status.take_status_sample();
    }

    let dr = registers.uartdr.extract();
    let data = dr.read(UARTDR::DATA) as u8;
    let status = Pl011RxStatus::from_data(dr);
    if !status.is_empty() {
        saved_status.remove(status);
    }

    Some(RxSample {
        byte: Some(data),
        flag: status.flag(),
        overrun: status.contains(Pl011RxStatus::OVERRUN),
    })
}

pub(super) fn rx_errors_from_sample(sample: RxSample) -> RxErrorFlags {
    let mut errors = match sample.flag {
        RxFlag::Normal => RxErrorFlags::empty(),
        RxFlag::Break => RxErrorFlags::BREAK,
        RxFlag::Parity => RxErrorFlags::PARITY,
        RxFlag::Framing => RxErrorFlags::FRAMING,
    };
    if sample.overrun {
        errors |= RxErrorFlags::OVERRUN;
    }
    errors
}

bitflags::bitflags! {
    #[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
    pub(super) struct Pl011RxStatus: u32 {
        const FRAMING = 1 << 0;
        const PARITY  = 1 << 1;
        const BREAK   = 1 << 2;
        const OVERRUN = 1 << 3;
    }
}

impl Pl011RxStatus {
    pub(super) fn to_irq_errors(self) -> RxErrorFlags {
        let mut errors = RxErrorFlags::empty();
        if self.contains(Self::BREAK) {
            errors |= RxErrorFlags::BREAK;
        }
        if self.contains(Self::PARITY) {
            errors |= RxErrorFlags::PARITY;
        }
        if self.contains(Self::FRAMING) {
            errors |= RxErrorFlags::FRAMING;
        }
        if self.contains(Self::OVERRUN) {
            errors |= RxErrorFlags::OVERRUN;
        }
        errors
    }

    fn from_data(dr: LocalRegisterCopy<u32, UARTDR::Register>) -> Self {
        let mut status = Self::empty();
        if dr.is_set(UARTDR::FE) {
            status |= Self::FRAMING;
        }
        if dr.is_set(UARTDR::PE) {
            status |= Self::PARITY;
        }
        if dr.is_set(UARTDR::BE) {
            status |= Self::BREAK;
        }
        if dr.is_set(UARTDR::OE) {
            status |= Self::OVERRUN;
        }
        status
    }

    pub(super) fn from_irq_status(mis: LocalRegisterCopy<u32, UARTIS::Register>) -> Self {
        let mut status = Self::empty();
        if mis.is_set(UARTIS::FE) {
            status |= Self::FRAMING;
        }
        if mis.is_set(UARTIS::PE) {
            status |= Self::PARITY;
        }
        if mis.is_set(UARTIS::BE) {
            status |= Self::BREAK;
        }
        if mis.is_set(UARTIS::OE) {
            status |= Self::OVERRUN;
        }
        status
    }

    pub(super) fn from_rsr(rsr: LocalRegisterCopy<u32, UARTRSR_ECR::Register>) -> Self {
        let mut status = Self::empty();
        if rsr.is_set(UARTRSR_ECR::FE) {
            status |= Self::FRAMING;
        }
        if rsr.is_set(UARTRSR_ECR::PE) {
            status |= Self::PARITY;
        }
        if rsr.is_set(UARTRSR_ECR::BE) {
            status |= Self::BREAK;
        }
        if rsr.is_set(UARTRSR_ECR::OE) {
            status |= Self::OVERRUN;
        }
        status
    }

    fn flag(self) -> RxFlag {
        if self.contains(Self::BREAK) {
            RxFlag::Break
        } else if self.contains(Self::PARITY) {
            RxFlag::Parity
        } else if self.contains(Self::FRAMING) {
            RxFlag::Framing
        } else {
            RxFlag::Normal
        }
    }

    fn take_status_sample(&mut self) -> Option<RxSample> {
        if self.is_empty() {
            return None;
        }

        let status = *self;
        *self = Self::empty();
        Some(RxSample {
            byte: None,
            flag: status.flag(),
            overrun: status.contains(Self::OVERRUN),
        })
    }
}