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 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            // This delay probaby should be called, but the current combination
59            // of embassy-executor and esp-rtos panics if end_transmission is
60            // cancelled. Try again in a few months!
61            // self.delay.delay_us(100).await;
62            self.pin.set_low().map_err(Error::Pin)?;
63            self.begun_transmission = false;
64        }
65        Ok(())
66    }
67
68    /// End the transmission by flushing the serial port and setting the RE/DE
69    /// pin low.
70    pub async fn end_transmission(&mut self) -> Result<(), <Self as ErrorType>::Error>
71    where
72        DELAY: DelayNs,
73    {
74        self.serial.flush().await.map_err(Error::Serial)?;
75        self.end_transmission_inner().await
76    }
77}
78
79impl<RIDO, REDE, DELAY> ErrorType for Max485<RIDO, REDE, DELAY>
80where
81    RIDO: Read + Write,
82    REDE: OutputPin,
83{
84    type Error = crate::Error<RIDO::Error, REDE::Error>;
85}
86
87impl<RIDO, REDE, DELAY> Write for Max485<RIDO, REDE, DELAY>
88where
89    RIDO: Read + Write,
90    REDE: OutputPin,
91    DELAY: DelayNs,
92{
93    async fn write(&mut self, bytes: &[u8]) -> Result<usize, Self::Error> {
94        self.begin_transmission()?;
95        self.serial.write(bytes).await.map_err(Error::Serial)
96    }
97
98    async fn flush(&mut self) -> Result<(), Self::Error> {
99        self.begin_transmission()?;
100        self.serial.flush().await.map_err(Error::Serial)?;
101        self.end_transmission_inner().await
102    }
103}
104
105impl<RIDO, REDE, DELAY> Read for Max485<RIDO, REDE, DELAY>
106where
107    RIDO: Read + Write,
108    REDE: OutputPin,
109    DELAY: DelayNs,
110{
111    async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
112        self.end_transmission_inner().await?;
113        self.serial.read(buf).await.map_err(Error::Serial)
114    }
115}
116
117impl<RIDO, REDE, DELAY> ReadReady for Max485<RIDO, REDE, DELAY>
118where
119    RIDO: Read + Write + ReadReady,
120    REDE: OutputPin,
121{
122    fn read_ready(&mut self) -> Result<bool, Self::Error> {
123        Ok(self.serial.read_ready().map_err(Error::Serial)? && !self.begun_transmission)
124    }
125}
126
127impl<RIDO, REDE, DELAY> WriteReady for Max485<RIDO, REDE, DELAY>
128where
129    RIDO: Read + Write + WriteReady,
130    REDE: OutputPin,
131{
132    fn write_ready(&mut self) -> Result<bool, Self::Error> {
133        self.serial.write_ready().map_err(Error::Serial)
134    }
135}
136
137/// Custom Error type
138#[derive(Debug)]
139pub enum Error<S, P> {
140    Serial(S),
141    Pin(P),
142}
143
144impl<S, P> Display for Error<S, P>
145where
146    S: Display,
147    P: Debug, // embedded_hal::digital::Error only implements Debug
148{
149    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
150        match self {
151            Error::Serial(s) => write!(f, "serial error: {s}"),
152            Error::Pin(p) => write!(f, "pin error: {p:?}"),
153        }
154    }
155}
156
157impl<S, P> core::error::Error for Error<S, P>
158where
159    S: core::error::Error,
160    P: Debug,
161{
162}
163
164impl<S, P> embedded_io_async::Error for Error<S, P>
165where
166    S: embedded_io_async::Error,
167    P: Debug,
168{
169    fn kind(&self) -> embedded_io_async::ErrorKind {
170        match self {
171            Error::Serial(s) => s.kind(),
172            Error::Pin(_) => embedded_io_async::ErrorKind::Other,
173        }
174    }
175}