max485_async/
lib.rs

1#![no_std]
2
3use core::fmt::{self, Debug, Display};
4use embedded_hal::digital::OutputPin;
5use embedded_hal_async::delay::DelayNs;
6use embedded_io_async::{ErrorType, Read, ReadReady, Write, WriteReady};
7
8/// Asynchronous driver for MAX485 RS-485 transceivers. Requires a serial port,
9/// a RE/DE pin, and a delay provider.
10pub struct Max485<RIDO, REDE, DELAY>
11where
12    RIDO: Read + Write,
13    REDE: OutputPin,
14{
15    serial: RIDO,
16    pin: REDE,
17    delay: DELAY,
18    begun_transmission: bool,
19}
20
21impl<RIDO, REDE, DELAY> Max485<RIDO, REDE, DELAY>
22where
23    RIDO: Read + Write,
24    REDE: OutputPin,
25{
26    pub fn new(serial: RIDO, pin: REDE, delay: DELAY) -> Self {
27        Self {
28            serial,
29            pin,
30            delay,
31            begun_transmission: false,
32        }
33    }
34
35    pub fn into_parts(self) -> (RIDO, REDE, DELAY) {
36        (self.serial, self.pin, self.delay)
37    }
38
39    pub fn inner_mut(&mut self) -> &mut RIDO {
40        &mut self.serial
41    }
42
43    /// Begin the transmission by setting the RE/DE pin high. This is called
44    /// automatically before any write operation.
45    pub async fn begin_transmission(&mut self) -> Result<(), <Self as ErrorType>::Error> {
46        if !self.begun_transmission {
47            self.pin.set_high().map_err(Error::Pin)?;
48            self.begun_transmission = true;
49        }
50        Ok(())
51    }
52
53    async fn end_transmission_inner(&mut self) -> Result<(), <Self as ErrorType>::Error>
54    where
55        DELAY: DelayNs,
56    {
57        if self.begun_transmission {
58            self.delay.delay_us(50).await;
59            self.pin.set_low().map_err(Error::Pin)?;
60            self.begun_transmission = false;
61        }
62        Ok(())
63    }
64
65    /// End the transmission by flushing the serial port and setting the RE/DE
66    /// pin low.
67    pub async fn end_transmission(&mut self) -> Result<(), <Self as ErrorType>::Error>
68    where
69        DELAY: DelayNs,
70    {
71        self.serial.flush().await.map_err(Error::Serial)?;
72        self.end_transmission_inner().await
73    }
74}
75
76impl<RIDO, REDE, DELAY> ErrorType for Max485<RIDO, REDE, DELAY>
77where
78    RIDO: Read + Write,
79    REDE: OutputPin,
80{
81    type Error = crate::Error<RIDO::Error, REDE::Error>;
82}
83
84impl<RIDO, REDE, DELAY> Write for Max485<RIDO, REDE, DELAY>
85where
86    RIDO: Read + Write,
87    REDE: OutputPin,
88    DELAY: DelayNs,
89{
90    async fn write(&mut self, bytes: &[u8]) -> Result<usize, Self::Error> {
91        self.begin_transmission().await?;
92        self.serial.write(bytes).await.map_err(Error::Serial)
93    }
94
95    async fn flush(&mut self) -> Result<(), Self::Error> {
96        self.begin_transmission().await?;
97        self.serial.flush().await.map_err(Error::Serial)?;
98        self.end_transmission_inner().await
99    }
100}
101
102impl<RIDO, REDE, DELAY> Read for Max485<RIDO, REDE, DELAY>
103where
104    RIDO: Read + Write,
105    REDE: OutputPin,
106    DELAY: DelayNs,
107{
108    async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
109        self.end_transmission_inner().await?;
110        self.serial.read(buf).await.map_err(Error::Serial)
111    }
112}
113
114impl<RIDO, REDE, DELAY> ReadReady for Max485<RIDO, REDE, DELAY>
115where
116    RIDO: Read + Write + ReadReady,
117    REDE: OutputPin,
118{
119    fn read_ready(&mut self) -> Result<bool, Self::Error> {
120        Ok(self.serial.read_ready().map_err(Error::Serial)? && !self.begun_transmission)
121    }
122}
123
124impl<RIDO, REDE, DELAY> WriteReady for Max485<RIDO, REDE, DELAY>
125where
126    RIDO: Read + Write + WriteReady,
127    REDE: OutputPin,
128{
129    fn write_ready(&mut self) -> Result<bool, Self::Error> {
130        self.serial.write_ready().map_err(Error::Serial)
131    }
132}
133
134/// Custom Error type
135#[derive(Debug)]
136pub enum Error<S, P> {
137    Serial(S),
138    Pin(P),
139}
140
141impl<S, P> Display for Error<S, P>
142where
143    S: Display,
144    P: Debug, // embedded_hal::digital::Error only implements Debug
145{
146    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
147        match self {
148            Error::Serial(s) => write!(f, "serial error: {s}"),
149            Error::Pin(p) => write!(f, "pin error: {p:?}"),
150        }
151    }
152}
153
154impl<S, P> core::error::Error for Error<S, P>
155where
156    S: core::error::Error,
157    P: Debug,
158{
159}
160
161impl<S, P> embedded_io_async::Error for Error<S, P>
162where
163    S: embedded_io_async::Error,
164    P: Debug,
165{
166    fn kind(&self) -> embedded_io_async::ErrorKind {
167        match self {
168            Error::Serial(s) => s.kind(),
169            Error::Pin(_) => embedded_io_async::ErrorKind::Other,
170        }
171    }
172}