use embedded_hal::delay::DelayNs;
use embedded_hal::digital::{InputPin, OutputPin};
use embedded_hal::spi::SpiDevice;
use crate::bus::{EpdBusError, SpiBusWrapper};
use crate::traits::{ColorChannel, EpdController};
pub mod cmd {
pub const PSR: u8 = 0x00;
pub const POWER_OFF: u8 = 0x02;
pub const POWER_ON: u8 = 0x04;
pub const WRITE_BW_DATA: u8 = 0x10;
pub const DISPLAY_REFRESH: u8 = 0x12;
pub const WRITE_RED_DATA: u8 = 0x13;
pub const VCOM_INTERVAL: u8 = 0x50;
pub const ACTIVE_TEMP: u8 = 0xE0;
pub const INPUT_TEMP: u8 = 0xE5;
}
const REG_DATA_SOFT_RESET: &[u8] = &[0x0E];
const REG_DATA_ACTIVE_TEMP: &[u8] = &[0x02];
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum PervasiveRefreshMode {
#[default]
Normal,
Fast,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum PervasiveDriverVariant {
#[default]
DriverC,
DriverF,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct PervasiveBwController {
width: u32,
height: u32,
temperature_c: i8,
refresh_mode: PervasiveRefreshMode,
driver_variant: PervasiveDriverVariant,
psr: [u8; 2],
auto_clear_secondary: bool,
}
impl Default for PervasiveBwController {
fn default() -> Self {
Self {
width: 0,
height: 0,
temperature_c: 25,
refresh_mode: PervasiveRefreshMode::Normal,
driver_variant: PervasiveDriverVariant::DriverC,
psr: [0xCF, 0x8D],
auto_clear_secondary: true,
}
}
}
impl PervasiveBwController {
pub fn new(width: u32, height: u32) -> Self {
Self {
width,
height,
..Default::default()
}
}
pub fn with_temperature(mut self, temperature_c: i8) -> Self {
self.temperature_c = temperature_c;
self
}
pub fn set_temperature(&mut self, temperature_c: i8) {
self.temperature_c = temperature_c;
}
pub fn temperature(&self) -> i8 {
self.temperature_c
}
pub fn with_refresh_mode(mut self, mode: PervasiveRefreshMode) -> Self {
self.refresh_mode = mode;
self
}
pub fn set_refresh_mode(&mut self, mode: PervasiveRefreshMode) {
self.refresh_mode = mode;
}
pub fn refresh_mode(&self) -> PervasiveRefreshMode {
self.refresh_mode
}
pub fn with_driver_variant(mut self, variant: PervasiveDriverVariant) -> Self {
self.driver_variant = variant;
self
}
pub fn set_driver_variant(&mut self, variant: PervasiveDriverVariant) {
self.driver_variant = variant;
}
pub fn driver_variant(&self) -> PervasiveDriverVariant {
self.driver_variant
}
pub fn with_psr(mut self, psr: [u8; 2]) -> Self {
self.psr = psr;
self
}
pub fn with_auto_clear_secondary(mut self, auto_clear: bool) -> Self {
self.auto_clear_secondary = auto_clear;
self
}
#[allow(clippy::type_complexity)]
pub fn write_fast_frame<SPI, DC, RST, BUSY>(
&mut self,
bus: &mut SpiBusWrapper<SPI, DC, RST, BUSY>,
previous_frame: &[u8],
current_frame: &[u8],
) -> Result<(), EpdBusError<SPI::Error, DC::Error, RST::Error, BUSY::Error>>
where
SPI: SpiDevice,
DC: OutputPin,
RST: OutputPin,
BUSY: InputPin,
{
bus.send_command_with_data(cmd::VCOM_INTERVAL, &[0x27])?;
bus.send_command(cmd::WRITE_BW_DATA)?;
let mut buf = [0u8; 64];
for chunk in previous_frame.chunks(64) {
for (i, &b) in chunk.iter().enumerate() {
buf[i] = !b;
}
bus.send_data(&buf[..chunk.len()])?;
}
bus.send_command(cmd::WRITE_RED_DATA)?;
for chunk in current_frame.chunks(64) {
for (i, &b) in chunk.iter().enumerate() {
buf[i] = !b;
}
bus.send_data(&buf[..chunk.len()])?;
}
bus.send_command_with_data(cmd::VCOM_INTERVAL, &[0x07])?;
Ok(())
}
}
impl<SPI, DC, RST, BUSY> EpdController<SpiBusWrapper<SPI, DC, RST, BUSY>> for PervasiveBwController
where
SPI: SpiDevice,
DC: OutputPin,
RST: OutputPin,
BUSY: InputPin,
{
type Error = EpdBusError<SPI::Error, DC::Error, RST::Error, BUSY::Error>;
fn init_sequence<DELAY: DelayNs>(
&mut self,
bus: &mut SpiBusWrapper<SPI, DC, RST, BUSY>,
delay: &mut DELAY,
) -> Result<(), Self::Error> {
bus.hard_reset(delay, 10)?;
bus.wait_busy_with_delay(delay, false)?;
let (temp_val, psr_val) = match self.refresh_mode {
PervasiveRefreshMode::Normal => (self.temperature_c as u8, self.psr),
PervasiveRefreshMode::Fast => (
(self.temperature_c as u8) | 0x40,
[self.psr[0] | 0x10, self.psr[1] | 0x02],
),
};
bus.send_command_with_data(cmd::PSR, REG_DATA_SOFT_RESET)?;
bus.wait_busy_with_delay(delay, false)?;
bus.send_command_with_data(cmd::INPUT_TEMP, &[temp_val])?;
bus.send_command_with_data(cmd::ACTIVE_TEMP, REG_DATA_ACTIVE_TEMP)?;
match self.driver_variant {
PervasiveDriverVariant::DriverC => {
bus.send_command_with_data(cmd::PSR, &psr_val)?;
}
PervasiveDriverVariant::DriverF => {
bus.send_command_with_data(0x4D, &[0x55])?;
bus.send_command_with_data(0xE9, &[0x02])?;
}
}
if self.refresh_mode == PervasiveRefreshMode::Fast {
bus.send_command_with_data(cmd::VCOM_INTERVAL, &[0x07])?;
}
Ok(())
}
fn set_window(
&mut self,
_bus: &mut SpiBusWrapper<SPI, DC, RST, BUSY>,
_x_start: u32,
_y_start: u32,
_x_end: u32,
_y_end: u32,
) -> Result<(), Self::Error> {
Ok(())
}
fn set_cursor(
&mut self,
_bus: &mut SpiBusWrapper<SPI, DC, RST, BUSY>,
_x: u32,
_y: u32,
) -> Result<(), Self::Error> {
Ok(())
}
fn write_frame(
&mut self,
bus: &mut SpiBusWrapper<SPI, DC, RST, BUSY>,
channel: ColorChannel,
data: &[u8],
) -> Result<(), Self::Error> {
match channel {
ColorChannel::BlackWhite => {
bus.send_command(cmd::WRITE_BW_DATA)?;
let mut buf = [0u8; 64];
for chunk in data.chunks(64) {
for (i, &b) in chunk.iter().enumerate() {
buf[i] = !b;
}
bus.send_data(&buf[..chunk.len()])?;
}
if self.refresh_mode == PervasiveRefreshMode::Normal && self.auto_clear_secondary {
bus.send_command(cmd::WRITE_RED_DATA)?;
bus.send_data_repeated(0x00, data.len())?;
}
Ok(())
}
ColorChannel::RedYellow
| ColorChannel::Red
| ColorChannel::Yellow
| ColorChannel::Color7(_) => bus.send_command_with_data(cmd::WRITE_RED_DATA, data),
}
}
fn write_frame_pattern(
&mut self,
bus: &mut SpiBusWrapper<SPI, DC, RST, BUSY>,
channel: ColorChannel,
byte: u8,
count: usize,
) -> Result<(), Self::Error> {
let (cmd, byte) = match channel {
ColorChannel::BlackWhite => (cmd::WRITE_BW_DATA, !byte),
ColorChannel::RedYellow
| ColorChannel::Red
| ColorChannel::Yellow
| ColorChannel::Color7(_) => (cmd::WRITE_RED_DATA, byte),
};
bus.send_command(cmd)?;
bus.send_data_repeated(byte, count)
}
fn trigger_refresh<DELAY: DelayNs>(
&mut self,
bus: &mut SpiBusWrapper<SPI, DC, RST, BUSY>,
delay: &mut DELAY,
) -> Result<(), Self::Error> {
bus.wait_busy_with_delay(delay, false)?;
bus.send_command(cmd::POWER_ON)?;
bus.wait_busy_with_delay(delay, false)?;
bus.send_command(cmd::DISPLAY_REFRESH)?;
bus.wait_busy_with_delay(delay, false)
}
fn sleep<DELAY: DelayNs>(
&mut self,
bus: &mut SpiBusWrapper<SPI, DC, RST, BUSY>,
delay: &mut DELAY,
) -> Result<(), Self::Error> {
bus.send_command(cmd::POWER_OFF)?;
bus.wait_busy_with_delay(delay, false)
}
}