1use embedded_hal::{delay::*, digital::*, spi::SpiDevice};
53
54use crate::interface::DisplayInterface;
55use crate::traits::{InternalWiAdditions, QuickRefresh, RefreshLut, WaveshareDisplay};
56
57mod constants;
59use crate::epd4in2::constants::*;
60
61pub const WIDTH: u32 = 400;
63pub const HEIGHT: u32 = 300;
65pub const DEFAULT_BACKGROUND_COLOR: Color = Color::White;
67const IS_BUSY_LOW: bool = true;
68const SINGLE_BYTE_WRITE: bool = true;
69
70use crate::color::Color;
71
72pub(crate) mod command;
73use self::command::Command;
74use crate::buffer_len;
75
76#[cfg(feature = "graphics")]
78pub type Display4in2 = crate::graphics::Display<
79 WIDTH,
80 HEIGHT,
81 false,
82 { buffer_len(WIDTH as usize, HEIGHT as usize) },
83 Color,
84>;
85
86pub struct Epd4in2<SPI, BUSY, DC, RST, DELAY> {
89 interface: DisplayInterface<SPI, BUSY, DC, RST, DELAY, SINGLE_BYTE_WRITE>,
91 color: Color,
93 refresh: RefreshLut,
95}
96
97impl<SPI, BUSY, DC, RST, DELAY> InternalWiAdditions<SPI, BUSY, DC, RST, DELAY>
98 for Epd4in2<SPI, BUSY, DC, RST, DELAY>
99where
100 SPI: SpiDevice,
101 BUSY: InputPin,
102 DC: OutputPin,
103 RST: OutputPin,
104 DELAY: DelayNs,
105{
106 fn init(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> {
107 self.interface.reset(delay, 10_000, 10_000);
109
110 self.interface.cmd_with_data(
112 spi,
113 Command::PowerSetting,
114 &[0x03, 0x00, 0x2b, 0x2b, 0xff],
115 )?;
116
117 self.interface
119 .cmd_with_data(spi, Command::BoosterSoftStart, &[0x17, 0x17, 0x17])?;
120
121 self.command(spi, Command::PowerOn)?;
123 delay.delay_us(5000);
124 self.wait_until_idle(spi, delay)?;
125
126 self.cmd_with_data(spi, Command::PanelSetting, &[0x3F])?;
128
129 self.cmd_with_data(spi, Command::PllControl, &[0x3A])?;
134
135 self.send_resolution(spi)?;
136
137 self.interface
138 .cmd_with_data(spi, Command::VcmDcSetting, &[0x12])?;
139
140 self.interface
142 .cmd_with_data(spi, Command::VcomAndDataIntervalSetting, &[0x97])?;
143
144 self.set_lut(spi, delay, None)?;
145
146 self.wait_until_idle(spi, delay)?;
147 Ok(())
148 }
149}
150
151impl<SPI, BUSY, DC, RST, DELAY> WaveshareDisplay<SPI, BUSY, DC, RST, DELAY>
152 for Epd4in2<SPI, BUSY, DC, RST, DELAY>
153where
154 SPI: SpiDevice,
155 BUSY: InputPin,
156 DC: OutputPin,
157 RST: OutputPin,
158 DELAY: DelayNs,
159{
160 type DisplayColor = Color;
161 fn new(
162 spi: &mut SPI,
163 busy: BUSY,
164 dc: DC,
165 rst: RST,
166 delay: &mut DELAY,
167 delay_us: Option<u32>,
168 ) -> Result<Self, SPI::Error> {
169 let interface = DisplayInterface::new(busy, dc, rst, delay_us);
170 let color = DEFAULT_BACKGROUND_COLOR;
171
172 let mut epd = Epd4in2 {
173 interface,
174 color,
175 refresh: RefreshLut::Full,
176 };
177
178 epd.init(spi, delay)?;
179
180 Ok(epd)
181 }
182
183 fn sleep(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> {
184 self.wait_until_idle(spi, delay)?;
185 self.interface
186 .cmd_with_data(spi, Command::VcomAndDataIntervalSetting, &[0x17])?; self.command(spi, Command::VcmDcSetting)?; self.command(spi, Command::PanelSetting)?;
189
190 self.command(spi, Command::PowerSetting)?; for _ in 0..4 {
192 self.send_data(spi, &[0x00])?;
193 }
194
195 self.command(spi, Command::PowerOff)?;
196 self.wait_until_idle(spi, delay)?;
197 self.interface
198 .cmd_with_data(spi, Command::DeepSleep, &[0xA5])?;
199 Ok(())
200 }
201
202 fn wake_up(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> {
203 self.init(spi, delay)
204 }
205
206 fn set_background_color(&mut self, color: Color) {
207 self.color = color;
208 }
209
210 fn background_color(&self) -> &Color {
211 &self.color
212 }
213
214 fn width(&self) -> u32 {
215 WIDTH
216 }
217
218 fn height(&self) -> u32 {
219 HEIGHT
220 }
221
222 fn update_frame(
223 &mut self,
224 spi: &mut SPI,
225 buffer: &[u8],
226 delay: &mut DELAY,
227 ) -> Result<(), SPI::Error> {
228 self.wait_until_idle(spi, delay)?;
229 let color_value = self.color.get_byte_value();
230
231 self.interface.cmd(spi, Command::DataStartTransmission1)?;
232 self.interface
233 .data_x_times(spi, color_value, WIDTH / 8 * HEIGHT)?;
234
235 self.interface
236 .cmd_with_data(spi, Command::DataStartTransmission2, buffer)?;
237 Ok(())
238 }
239
240 fn update_partial_frame(
241 &mut self,
242 spi: &mut SPI,
243 delay: &mut DELAY,
244 buffer: &[u8],
245 x: u32,
246 y: u32,
247 width: u32,
248 height: u32,
249 ) -> Result<(), SPI::Error> {
250 self.wait_until_idle(spi, delay)?;
251 if buffer.len() as u32 != width / 8 * height {
252 }
255
256 self.command(spi, Command::PartialIn)?;
257 self.command(spi, Command::PartialWindow)?;
258 self.send_data(spi, &[(x >> 8) as u8])?;
259 let tmp = x & 0xf8;
260 self.send_data(spi, &[tmp as u8])?; let tmp = tmp + width - 1;
262 self.send_data(spi, &[(tmp >> 8) as u8])?;
263 self.send_data(spi, &[(tmp | 0x07) as u8])?;
264
265 self.send_data(spi, &[(y >> 8) as u8])?;
266 self.send_data(spi, &[y as u8])?;
267
268 self.send_data(spi, &[((y + height - 1) >> 8) as u8])?;
269 self.send_data(spi, &[(y + height - 1) as u8])?;
270
271 self.send_data(spi, &[0x01])?; let is_dtm1 = false;
275 if is_dtm1 {
276 self.command(spi, Command::DataStartTransmission1)? } else {
278 self.command(spi, Command::DataStartTransmission2)?
279 }
280
281 self.send_data(spi, buffer)?;
282
283 self.command(spi, Command::PartialOut)?;
284 Ok(())
285 }
286
287 fn display_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> {
288 self.wait_until_idle(spi, delay)?;
289 self.command(spi, Command::DisplayRefresh)?;
290 Ok(())
291 }
292
293 fn update_and_display_frame(
294 &mut self,
295 spi: &mut SPI,
296 buffer: &[u8],
297 delay: &mut DELAY,
298 ) -> Result<(), SPI::Error> {
299 self.update_frame(spi, buffer, delay)?;
300 self.command(spi, Command::DisplayRefresh)?;
301 Ok(())
302 }
303
304 fn clear_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> {
305 self.wait_until_idle(spi, delay)?;
306 self.send_resolution(spi)?;
307
308 let color_value = self.color.get_byte_value();
309
310 self.interface.cmd(spi, Command::DataStartTransmission1)?;
311 self.interface
312 .data_x_times(spi, color_value, WIDTH / 8 * HEIGHT)?;
313
314 self.interface.cmd(spi, Command::DataStartTransmission2)?;
315 self.interface
316 .data_x_times(spi, color_value, WIDTH / 8 * HEIGHT)?;
317 Ok(())
318 }
319
320 fn set_lut(
321 &mut self,
322 spi: &mut SPI,
323 delay: &mut DELAY,
324 refresh_rate: Option<RefreshLut>,
325 ) -> Result<(), SPI::Error> {
326 if let Some(refresh_lut) = refresh_rate {
327 self.refresh = refresh_lut;
328 }
329 match self.refresh {
330 RefreshLut::Full => {
331 self.set_lut_helper(spi, delay, &LUT_VCOM0, &LUT_WW, &LUT_BW, &LUT_WB, &LUT_BB)
332 }
333 RefreshLut::Quick => self.set_lut_helper(
334 spi,
335 delay,
336 &LUT_VCOM0_QUICK,
337 &LUT_WW_QUICK,
338 &LUT_BW_QUICK,
339 &LUT_WB_QUICK,
340 &LUT_BB_QUICK,
341 ),
342 }
343 }
344
345 fn wait_until_idle(&mut self, _spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> {
346 self.interface.wait_until_idle(delay, IS_BUSY_LOW);
347 Ok(())
348 }
349}
350
351impl<SPI, BUSY, DC, RST, DELAY> Epd4in2<SPI, BUSY, DC, RST, DELAY>
352where
353 SPI: SpiDevice,
354 BUSY: InputPin,
355 DC: OutputPin,
356 RST: OutputPin,
357 DELAY: DelayNs,
358{
359 fn command(&mut self, spi: &mut SPI, command: Command) -> Result<(), SPI::Error> {
360 self.interface.cmd(spi, command)
361 }
362
363 fn send_data(&mut self, spi: &mut SPI, data: &[u8]) -> Result<(), SPI::Error> {
364 self.interface.data(spi, data)
365 }
366
367 fn cmd_with_data(
368 &mut self,
369 spi: &mut SPI,
370 command: Command,
371 data: &[u8],
372 ) -> Result<(), SPI::Error> {
373 self.interface.cmd_with_data(spi, command, data)
374 }
375
376 fn send_resolution(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> {
377 let w = self.width();
378 let h = self.height();
379
380 self.command(spi, Command::ResolutionSetting)?;
381 self.send_data(spi, &[(w >> 8) as u8])?;
382 self.send_data(spi, &[w as u8])?;
383 self.send_data(spi, &[(h >> 8) as u8])?;
384 self.send_data(spi, &[h as u8])
385 }
386
387 #[allow(clippy::too_many_arguments)]
388 fn set_lut_helper(
389 &mut self,
390 spi: &mut SPI,
391 delay: &mut DELAY,
392 lut_vcom: &[u8],
393 lut_ww: &[u8],
394 lut_bw: &[u8],
395 lut_wb: &[u8],
396 lut_bb: &[u8],
397 ) -> Result<(), SPI::Error> {
398 self.wait_until_idle(spi, delay)?;
399 self.cmd_with_data(spi, Command::LutForVcom, lut_vcom)?;
401
402 self.cmd_with_data(spi, Command::LutWhiteToWhite, lut_ww)?;
404
405 self.cmd_with_data(spi, Command::LutBlackToWhite, lut_bw)?;
407
408 self.cmd_with_data(spi, Command::LutWhiteToBlack, lut_wb)?;
410
411 self.cmd_with_data(spi, Command::LutBlackToBlack, lut_bb)?;
413 Ok(())
414 }
415
416 pub fn shift_display(
419 &mut self,
420 spi: &mut SPI,
421 x: u32,
422 y: u32,
423 width: u32,
424 height: u32,
425 ) -> Result<(), SPI::Error> {
426 self.send_data(spi, &[(x >> 8) as u8])?;
427 let tmp = x & 0xf8;
428 self.send_data(spi, &[tmp as u8])?; let tmp = tmp + width - 1;
430 self.send_data(spi, &[(tmp >> 8) as u8])?;
431 self.send_data(spi, &[(tmp | 0x07) as u8])?;
432
433 self.send_data(spi, &[(y >> 8) as u8])?;
434 self.send_data(spi, &[y as u8])?;
435
436 self.send_data(spi, &[((y + height - 1) >> 8) as u8])?;
437 self.send_data(spi, &[(y + height - 1) as u8])?;
438
439 self.send_data(spi, &[0x01])?; Ok(())
442 }
443}
444
445impl<SPI, BUSY, DC, RST, DELAY> QuickRefresh<SPI, BUSY, DC, RST, DELAY>
446 for Epd4in2<SPI, BUSY, DC, RST, DELAY>
447where
448 SPI: SpiDevice,
449 BUSY: InputPin,
450 DC: OutputPin,
451 RST: OutputPin,
452 DELAY: DelayNs,
453{
454 fn update_old_frame(
456 &mut self,
457 spi: &mut SPI,
458 buffer: &[u8],
459 delay: &mut DELAY,
460 ) -> Result<(), SPI::Error> {
461 self.wait_until_idle(spi, delay)?;
462
463 self.interface.cmd(spi, Command::DataStartTransmission1)?;
464
465 self.interface.data(spi, buffer)?;
466
467 Ok(())
468 }
469
470 fn update_new_frame(
472 &mut self,
473 spi: &mut SPI,
474 buffer: &[u8],
475 delay: &mut DELAY,
476 ) -> Result<(), SPI::Error> {
477 self.wait_until_idle(spi, delay)?;
478 self.interface.cmd(spi, Command::DataStartTransmission2)?;
481
482 self.interface.data(spi, buffer)?;
483
484 Ok(())
485 }
486
487 fn display_new_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> {
490 self.display_frame(spi, delay)
491 }
492
493 fn update_and_display_new_frame(
498 &mut self,
499 spi: &mut SPI,
500 buffer: &[u8],
501 delay: &mut DELAY,
502 ) -> Result<(), SPI::Error> {
503 self.update_new_frame(spi, buffer, delay)?;
504 self.display_frame(spi, delay)
505 }
506
507 fn update_partial_old_frame(
508 &mut self,
509 spi: &mut SPI,
510 delay: &mut DELAY,
511 buffer: &[u8],
512 x: u32,
513 y: u32,
514 width: u32,
515 height: u32,
516 ) -> Result<(), SPI::Error> {
517 self.wait_until_idle(spi, delay)?;
518
519 if buffer.len() as u32 != width / 8 * height {
520 }
523
524 self.interface.cmd(spi, Command::PartialIn)?;
525 self.interface.cmd(spi, Command::PartialWindow)?;
526
527 self.shift_display(spi, x, y, width, height)?;
528
529 self.interface.cmd(spi, Command::DataStartTransmission1)?;
530
531 self.interface.data(spi, buffer)?;
532
533 Ok(())
534 }
535
536 fn update_partial_new_frame(
539 &mut self,
540 spi: &mut SPI,
541 delay: &mut DELAY,
542 buffer: &[u8],
543 x: u32,
544 y: u32,
545 width: u32,
546 height: u32,
547 ) -> Result<(), SPI::Error> {
548 self.wait_until_idle(spi, delay)?;
549 if buffer.len() as u32 != width / 8 * height {
550 }
553
554 self.shift_display(spi, x, y, width, height)?;
555
556 self.interface.cmd(spi, Command::DataStartTransmission2)?;
557
558 self.interface.data(spi, buffer)?;
559
560 self.interface.cmd(spi, Command::PartialOut)?;
561 Ok(())
562 }
563
564 fn clear_partial_frame(
565 &mut self,
566 spi: &mut SPI,
567 delay: &mut DELAY,
568 x: u32,
569 y: u32,
570 width: u32,
571 height: u32,
572 ) -> Result<(), SPI::Error> {
573 self.wait_until_idle(spi, delay)?;
574 self.send_resolution(spi)?;
575
576 let color_value = self.color.get_byte_value();
577
578 self.interface.cmd(spi, Command::PartialIn)?;
579 self.interface.cmd(spi, Command::PartialWindow)?;
580
581 self.shift_display(spi, x, y, width, height)?;
582
583 self.interface.cmd(spi, Command::DataStartTransmission1)?;
584 self.interface
585 .data_x_times(spi, color_value, width / 8 * height)?;
586
587 self.interface.cmd(spi, Command::DataStartTransmission2)?;
588 self.interface
589 .data_x_times(spi, color_value, width / 8 * height)?;
590
591 self.interface.cmd(spi, Command::PartialOut)?;
592 Ok(())
593 }
594}
595
596#[cfg(test)]
597mod tests {
598 use super::*;
599
600 #[test]
601 fn epd_size() {
602 assert_eq!(WIDTH, 400);
603 assert_eq!(HEIGHT, 300);
604 assert_eq!(DEFAULT_BACKGROUND_COLOR, Color::White);
605 }
606}