Skip to main content

max485_async/
lib.rs

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