1use core::marker::PhantomData;
4use embedded_hal::{delay::DelayNs, digital::InputPin, digital::OutputPin, spi::SpiDevice};
5
6use crate::DisplayBuffer;
7
8enum Command {
9 Psr = 0x00,
10 PowerOff = 0x02,
11 PowerOn = 0x04,
12 BufferBlack = 0x10,
13 Refresh = 0x12,
14 BufferRed = 0x13,
15 ActiveTemperature = 0xe0,
16 InputTemperature = 0xe5,
17}
18
19const REG_DATA_SOFT_RESET: &[u8] = &[0x0e];
21const REG_DATA_INPUT_TEMP: &[u8] = &[0x19];
22const REG_DATA_ACTIVE_TEMP: &[u8] = &[0x02];
23const REG_DATA_PSR: &[u8] = &[0xcf, 0x8d];
24
25const TIMEOUT_MS: i32 = 60_000;
27
28#[cfg(feature = "std")]
31#[derive(thiserror::Error, Debug)]
32pub enum Error<SpiError, DcError, RstError> {
33 #[error("SPI error: {0}")]
34 Spi(#[source] SpiError),
35 #[error("Error with GPIO 'DC': {0}")]
36 GpioDc(#[source] DcError),
37 #[error("Error with GPIO 'RESET': {0}")]
38 GpioRst(#[source] RstError),
39 #[error("Timeout while waiting for busy signal")]
40 Timeout,
41}
42
43#[cfg(not(feature = "std"))]
44#[derive(Debug)]
45pub enum Error<SpiError, DcError, RstError> {
46 Spi(SpiError),
47 GpioDc(DcError),
48 GpioRst(RstError),
49 Timeout,
50}
51
52type EpdError<SPI, DC, RST> = Error<
53 <SPI as embedded_hal::spi::ErrorType>::Error,
54 <DC as embedded_hal::digital::ErrorType>::Error,
55 <RST as embedded_hal::digital::ErrorType>::Error,
56>;
57
58type EpdResult<STATE, SPI, BUSY, DC, RST, DELAY> =
59 Result<Epd<STATE, SPI, BUSY, DC, RST, DELAY>, EpdError<SPI, DC, RST>>;
60
61pub struct Epd<STATE: EpdState, SPI, BUSY, DC, RST, DELAY> {
63 busy: BUSY,
65 dc: DC,
67 rst: RST,
69 spi_chunk_size: usize,
71 spi: PhantomData<SPI>,
72 delay: PhantomData<DELAY>,
73 state: PhantomData<STATE>,
74}
75
76pub struct Active; pub struct Inactive; pub trait EpdState {}
80impl EpdState for Active {}
81impl EpdState for Inactive {}
82
83impl<SPI, BUSY, DC, RST, DELAY> Epd<Inactive, SPI, BUSY, DC, RST, DELAY>
84where
85 SPI: SpiDevice,
86 BUSY: InputPin,
87 DC: OutputPin,
88 RST: OutputPin,
89 DELAY: DelayNs,
90{
91 pub fn new(
95 _spi: &mut SPI,
96 busy: BUSY,
97 dc: DC,
98 rst: RST,
99 _delay: &mut DELAY,
100 spi_chunk_size: usize,
101 ) -> Self {
102 Self {
103 busy,
104 dc,
105 rst,
106 spi_chunk_size,
107 spi: PhantomData,
108 delay: PhantomData,
109 state: PhantomData::<Inactive>,
110 }
111 }
112
113 pub fn init(
122 mut self,
123 spi: &mut SPI,
124 delay: &mut DELAY,
125 ) -> EpdResult<Active, SPI, BUSY, DC, RST, DELAY> {
126 self.dc.set_high().map_err(Error::GpioDc)?;
127 self.reset(delay)?;
128 self.soft_reset(spi, delay)?;
129 self.send_data(spi, Command::InputTemperature, REG_DATA_INPUT_TEMP)?;
130 self.send_data(spi, Command::ActiveTemperature, REG_DATA_ACTIVE_TEMP)?;
131 self.send_data(spi, Command::Psr, REG_DATA_PSR)?;
132 Ok(Epd {
133 busy: self.busy,
134 dc: self.dc,
135 rst: self.rst,
136 spi_chunk_size: self.spi_chunk_size,
137 spi: PhantomData,
138 delay: PhantomData,
139 state: PhantomData::<Active>,
140 })
141 }
142}
143
144impl<SPI, BUSY, DC, RST, DELAY> Epd<Active, SPI, BUSY, DC, RST, DELAY>
145where
146 SPI: SpiDevice,
147 BUSY: InputPin,
148 DC: OutputPin,
149 RST: OutputPin,
150 DELAY: DelayNs,
151{
152 pub fn update(
160 &mut self,
161 display: &impl DisplayBuffer,
162 spi: &mut SPI,
163 delay: &mut DELAY,
164 ) -> Result<(), EpdError<SPI, DC, RST>> {
165 self.send_data(spi, Command::BufferBlack, display.get_buffer_black())?;
166 self.send_data(spi, Command::BufferRed, display.get_buffer_red())?;
167 self.power_on(spi, delay)?;
168 self.display_refresh(spi, delay)?;
169 Ok(())
170 }
171
172 pub fn power_off(
182 mut self,
183 spi: &mut SPI,
184 delay: &mut DELAY,
185 ) -> EpdResult<Inactive, SPI, BUSY, DC, RST, DELAY> {
186 self.send_data(spi, Command::PowerOff, &[0x0])?;
187 self.wait_busy(delay)?;
188 self.dc.set_low().map_err(Error::GpioDc)?;
189 delay.delay_ms(150);
190 self.rst.set_low().map_err(Error::GpioRst)?;
191 Ok(Epd {
192 busy: self.busy,
193 dc: self.dc,
194 rst: self.rst,
195 spi_chunk_size: self.spi_chunk_size,
196 spi: PhantomData,
197 delay: PhantomData,
198 state: PhantomData::<Inactive>,
199 })
200 }
201}
202
203impl<STATE, SPI, BUSY, DC, RST, DELAY> Epd<STATE, SPI, BUSY, DC, RST, DELAY>
204where
205 STATE: EpdState,
206 SPI: SpiDevice,
207 BUSY: InputPin,
208 DC: OutputPin,
209 RST: OutputPin,
210 DELAY: DelayNs,
211{
212 fn reset(&mut self, delay: &mut DELAY) -> Result<(), EpdError<SPI, DC, RST>> {
213 delay.delay_ms(1);
214 self.rst.set_high().map_err(Error::GpioRst)?;
215 delay.delay_ms(5);
216 self.rst.set_low().map_err(Error::GpioRst)?;
217 delay.delay_ms(10);
218 self.rst.set_high().map_err(Error::GpioRst)?;
219 delay.delay_ms(5);
220 Ok(())
221 }
222
223 fn power_on(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), EpdError<SPI, DC, RST>> {
224 self.send_data(spi, Command::PowerOn, &[0x0])?;
225 self.wait_busy(delay)?;
226 Ok(())
227 }
228
229 fn send_data(
230 &mut self,
231 spi: &mut SPI,
232 cmd: Command,
233 data: &[u8],
234 ) -> Result<(), EpdError<SPI, DC, RST>> {
235 self.dc.set_low().map_err(Error::GpioDc)?;
236 self.write(spi, &[cmd as u8])?;
237 self.dc.set_high().map_err(Error::GpioDc)?;
238 self.write(spi, data)?;
239 Ok(())
240 }
241
242 fn write(&mut self, spi: &mut SPI, data: &[u8]) -> Result<(), EpdError<SPI, DC, RST>> {
243 if self.spi_chunk_size > 0 {
244 for chunk in data.chunks(self.spi_chunk_size) {
245 spi.write(chunk).map_err(Error::Spi)?;
246 }
247 } else {
248 spi.write(data).map_err(Error::Spi)?;
249 }
250 Ok(())
251 }
252
253 fn soft_reset(
254 &mut self,
255 spi: &mut SPI,
256 delay: &mut DELAY,
257 ) -> Result<(), EpdError<SPI, DC, RST>> {
258 self.send_data(spi, Command::Psr, REG_DATA_SOFT_RESET)?;
259 self.wait_busy(delay)?;
260 Ok(())
261 }
262
263 fn display_refresh(
264 &mut self,
265 spi: &mut SPI,
266 delay: &mut DELAY,
267 ) -> Result<(), EpdError<SPI, DC, RST>> {
268 self.send_data(spi, Command::Refresh, &[0x0])?;
269 self.wait_busy(delay)?;
270 Ok(())
271 }
272
273 fn wait_busy(&mut self, delay: &mut DELAY) -> Result<(), EpdError<SPI, DC, RST>> {
274 let delay_ms = 1;
275 let mut timeout = TIMEOUT_MS;
276 while self.busy.is_low().unwrap() && timeout > 0 {
277 delay.delay_ms(delay_ms);
278 timeout -= i32::try_from(delay_ms).unwrap();
279 }
280 if timeout <= 0 {
281 Err(Error::Timeout)
282 } else {
283 Ok(())
284 }
285 }
286}
287
288pub const SPI_MODE: embedded_hal::spi::Mode = embedded_hal::spi::Mode {
291 phase: embedded_hal::spi::Phase::CaptureOnFirstTransition,
292 polarity: embedded_hal::spi::Polarity::IdleLow,
293};