Skip to main content

msrt_uart/
backend.rs

1//! Passive UART backend for MCU/no-std use.
2
3use msrt::endpoint::{EndpointPoll, EngineConfig, PassiveEndpoint, PeerState};
4
5use crate::event::UartBackendEvent;
6use crate::traits::{UartError, UartIo, UartIoError, UartResult};
7
8const RX_BYTES: usize = 512;
9const TX_BYTES: usize = 256;
10
11/// Passive UART backend adapter.
12///
13/// This type does not require `std` or heap allocation. The caller provides
14/// time through `now_ms` arguments, usually from SysTick or an RTOS tick.
15#[derive(Debug)]
16pub struct UartBackend<T> {
17    io: T,
18    endpoint: PassiveEndpoint,
19    rx_buf: [u8; RX_BYTES],
20    tx_buf: [u8; TX_BYTES],
21}
22
23impl<T> UartBackend<T>
24where
25    T: UartIo,
26{
27    /// Creates a backend adapter using default MSRT config.
28    pub fn new(io: T) -> Self {
29        Self::with_config(io, EngineConfig::default())
30    }
31
32    /// Creates a backend adapter using `config`.
33    pub fn with_config(io: T, config: EngineConfig) -> Self {
34        Self {
35            io,
36            endpoint: PassiveEndpoint::new(config),
37            rx_buf: [0; RX_BYTES],
38            tx_buf: [0; TX_BYTES],
39        }
40    }
41
42    /// Returns the endpoint peer state.
43    pub fn peer_state(&self) -> PeerState {
44        self.endpoint.peer().state()
45    }
46
47    /// Returns a shared reference to the owned UART IO object.
48    pub const fn io(&self) -> &T {
49        &self.io
50    }
51
52    /// Returns a mutable reference to the owned UART IO object.
53    pub fn io_mut(&mut self) -> &mut T {
54        &mut self.io
55    }
56
57    /// Consumes the adapter and returns the UART IO object.
58    pub fn into_inner(self) -> T {
59        self.io
60    }
61
62    /// Drops the active backend session.
63    pub fn disconnect(&mut self) {
64        self.endpoint.disconnect();
65    }
66
67    /// Queues an application message.
68    pub fn send(&mut self, message: &[u8]) -> UartResult<bool, T::Error> {
69        self.endpoint
70            .send(message)
71            .map(|id| id.is_some())
72            .map_err(UartError::Protocol)
73    }
74
75    /// Reads currently available UART bytes and feeds them into MSRT.
76    pub fn receive_available(&mut self, now_ms: u64) -> UartResult<usize, T::Error> {
77        let mut total = 0;
78        loop {
79            match self.io.read(&mut self.rx_buf) {
80                Ok(0) => return Ok(total),
81                Ok(n) => {
82                    total += n;
83                    let _ = self.endpoint.receive(now_ms, &self.rx_buf[..n]);
84                    if n < self.rx_buf.len() {
85                        return Ok(total);
86                    }
87                }
88                Err(UartIoError::WouldBlock) => return Ok(total),
89                Err(UartIoError::Interrupted) => continue,
90                Err(error) => return Err(UartError::Io(error)),
91            }
92        }
93    }
94
95    /// Polls one backend event and writes pending UART bytes.
96    pub fn poll(&mut self, now_ms: u64) -> UartResult<UartBackendEvent, T::Error> {
97        loop {
98            match self
99                .endpoint
100                .poll(now_ms, &mut self.tx_buf)
101                .map_err(UartError::Protocol)?
102            {
103                EndpointPoll::Transmit { bytes, .. } => {
104                    self.io.write_all(bytes).map_err(UartError::Io)?;
105                }
106                EndpointPoll::Message(message) => return Ok(UartBackendEvent::Message(message)),
107                EndpointPoll::SendFailed(failed) => {
108                    return Ok(UartBackendEvent::SendFailed(failed));
109                }
110                EndpointPoll::Idle => return Ok(UartBackendEvent::Idle),
111            }
112        }
113    }
114
115    /// Runs `receive_available` followed by `poll`.
116    pub fn tick(&mut self, now_ms: u64) -> UartResult<UartBackendEvent, T::Error> {
117        let _ = self.receive_available(now_ms)?;
118        self.poll(now_ms)
119    }
120}