stm32f1-hal 0.12.3

HAL for the STM32F1 family
Documentation
//! UART interrupt implementation

use super::*;
use crate::common::{
    embedded_io::{BufRead, ErrorType, Read, ReadReady, Write, WriteReady},
    os_trait::Duration,
    ringbuf::*,
};

// TX -------------------------------------------------------------------------

pub struct UartInterruptTx<U, OS: OsInterface> {
    uart: U,
    timeout: MicrosDurationU32,
    flush_timeout: MicrosDurationU32,
    w: Producer<u8>,
    waiter: OS::NotifyWaiter,
}

impl<U, OS> UartInterruptTx<U, OS>
where
    U: UartPeriph,
    OS: OsInterface,
{
    pub fn new(
        uart: [U; 2],
        buf_size: usize,
        baudrate: u32,
        timeout: MicrosDurationU32,
    ) -> (Self, UartInterruptTxHandler<U, OS>) {
        let (notifier, waiter) = OS::notify();
        let [uart, u2] = uart;
        let (w, r) = RingBuffer::<u8>::new(buf_size);
        (
            Self {
                uart,
                timeout,
                flush_timeout: calculate_timeout(baudrate, buf_size + 10),
                w,
                waiter,
            },
            UartInterruptTxHandler::new(u2, r, notifier),
        )
    }
}

impl<U: UartPeriph, OS: OsInterface> ErrorType for UartInterruptTx<U, OS> {
    type Error = Error;
}

impl<U, OS> Write for UartInterruptTx<U, OS>
where
    U: UartPeriph,
    OS: OsInterface,
{
    fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
        if buf.is_empty() {
            return Err(Error::Other);
        }

        self.waiter
            .wait_with(&Duration::<OS>::micros(self.timeout.ticks()), 1, || {
                if let n @ 1.. = self.w.push_slice(buf) {
                    self.uart.set_interrupt(Event::TxEmpty, true);
                    return Some(n);
                } else if !self.uart.is_interrupt_enable(Event::TxEmpty) {
                    self.uart.set_interrupt(Event::TxEmpty, true);
                }
                None
            })
            .ok_or(Error::Busy)
    }

    fn flush(&mut self) -> Result<(), Self::Error> {
        self.waiter
            .wait_with(
                &Duration::<OS>::micros(self.flush_timeout.ticks()),
                1,
                || {
                    if self.uart.is_tx_complete() && self.w.is_empty() {
                        return Some(());
                    } else if !self.uart.is_interrupt_enable(Event::TxEmpty) {
                        self.uart.set_interrupt(Event::TxEmpty, true);
                    }
                    None
                },
            )
            .ok_or(Error::Other)
    }
}

impl<U, OS> WriteReady for UartInterruptTx<U, OS>
where
    U: UartPeriph,
    OS: OsInterface,
{
    fn write_ready(&mut self) -> Result<bool, Self::Error> {
        Ok(!self.w.is_full())
    }
}

// TX interrupt -----------------

pub struct UartInterruptTxHandler<U, OS: OsInterface> {
    uart: U,
    r: Consumer<u8>,
    notifier: OS::Notifier,
}

impl<U, OS> UartInterruptTxHandler<U, OS>
where
    U: UartPeriph,
    OS: OsInterface,
{
    pub fn new(uart: U, r: Consumer<u8>, notifier: OS::Notifier) -> Self {
        Self { uart, r, notifier }
    }
}

impl<U, OS> UartInterruptTxHandler<U, OS>
where
    U: UartPeriph,
    OS: OsInterface,
{
    pub fn handler(&mut self) {
        if let Some(wrote_data) = self.uart.write_with(|| {
            let data = self.r.pop();
            data.map_or(None, |d| Some(d as u16))
        }) {
            if wrote_data {
                if self.r.buffer().capacity() - self.r.slots() < 4 {
                    self.notifier.notify();
                }
            } else {
                self.uart.set_interrupt(Event::TxEmpty, false);
            }
        }
    }
}

// RX -------------------------------------------------------------------------

pub struct UartInterruptRx<U, OS: OsInterface> {
    uart: U,
    timeout: MicrosDurationU32,
    r: Consumer<u8>,
    waiter: OS::NotifyWaiter,
}

impl<U, OS> UartInterruptRx<U, OS>
where
    U: UartPeriph,
    OS: OsInterface,
{
    pub fn new(
        uart: [U; 2],
        buf_size: usize,
        timeout: MicrosDurationU32,
    ) -> (Self, UartInterruptRxHandler<U, OS>) {
        let (notifier, waiter) = OS::notify();
        let [uart, u2] = uart;
        let (w, r) = RingBuffer::<u8>::new(buf_size);
        (
            Self {
                uart,
                timeout,
                r,
                waiter,
            },
            UartInterruptRxHandler::new(u2, w, notifier),
        )
    }
}

impl<U: UartPeriph, OS: OsInterface> ErrorType for UartInterruptRx<U, OS> {
    type Error = Error;
}

impl<U, OS> Read for UartInterruptRx<U, OS>
where
    U: UartPeriph,
    OS: OsInterface,
{
    fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
        if buf.is_empty() {
            return Err(Error::Other);
        }

        self.waiter
            .wait_with(&Duration::<OS>::micros(self.timeout.ticks()), 1, || {
                if let n @ 1.. = self.r.pop_slice(buf) {
                    return Some(n);
                } else if !self.uart.is_interrupt_enable(Event::RxNotEmpty) {
                    self.uart.set_interrupt(Event::RxNotEmpty, true);
                }
                None
            })
            .ok_or(Error::Other)
    }
}

impl<U, OS> BufRead for UartInterruptRx<U, OS>
where
    U: UartPeriph,
    OS: OsInterface,
{
    fn fill_buf(&mut self) -> Result<&[u8], Self::Error> {
        self.waiter
            .wait_with(&Duration::<OS>::micros(self.timeout.ticks()), 1, || {
                if let Some(chunk) = self.r.get_read_chunk() {
                    let buf = chunk.get_slice();
                    let p = buf.as_ptr();
                    return unsafe { Some(core::slice::from_raw_parts(p, buf.len())) };
                } else if !self.uart.is_interrupt_enable(Event::RxNotEmpty) {
                    self.uart.set_interrupt(Event::RxNotEmpty, true);
                }
                None
            })
            .ok_or(Error::Other)
    }

    fn consume(&mut self, amt: usize) {
        let chunk = self.r.get_read_chunk().unwrap();
        chunk.commit(amt);
    }
}

impl<U, OS> ReadReady for UartInterruptRx<U, OS>
where
    U: UartPeriph,
    OS: OsInterface,
{
    fn read_ready(&mut self) -> Result<bool, Self::Error> {
        Ok(self.r.peek().is_ok())
    }
}

// RX interrupt -----------------

pub struct UartInterruptRxHandler<U, OS: OsInterface> {
    uart: U,
    w: Producer<u8>,
    notifier: OS::Notifier,
    // count: [u32; 10],
}

impl<U, OS> UartInterruptRxHandler<U, OS>
where
    U: UartPeriph,
    OS: OsInterface,
{
    pub fn new(mut uart: U, w: Producer<u8>, notifier: OS::Notifier) -> Self {
        uart.set_interrupt(Event::RxNotEmpty, true);
        Self {
            uart,
            w,
            notifier,
            // count: [0; 10],
        }
    }

    pub fn handler(&mut self) {
        if let Ok(data) = self.uart.read() {
            self.w.push(data as u8).ok();
            if self.w.buffer().capacity() - self.w.slots() < 4 {
                self.notifier.notify();
            }
        }

        // match self.uart.read() {
        //     Ok(data) => match self.w.push(data as u8) {
        //         Ok(()) => self.count[0] = self.count[0].saturating_add(1),
        //         Err(_) => self.count[1] = self.count[1].saturating_add(1),
        //     },
        //     Err(nb::Error::WouldBlock) => self.count[2] = self.count[2].saturating_add(1),
        //     Err(nb::Error::Other(e)) => match e {
        //         Error::Overrun => self.count[3] = self.count[3].saturating_add(1),
        //         Error::Other => self.count[4] = self.count[4].saturating_add(1),
        //         Error::Noise => self.count[5] = self.count[5].saturating_add(1),
        //         Error::FrameFormat => self.count[6] = self.count[6].saturating_add(1),
        //         Error::Parity => self.count[7] = self.count[7].saturating_add(1),
        //         Error::Busy => self.count[8] = self.count[8].saturating_add(1),
        //     },
        // }
    }
}