use crate::{
dcs::{self, InterfaceExt, SetAddressMode},
interface::Interface,
options::{self, ModelOptions, Rotation},
ConfigurationError,
};
use embedded_graphics_core::prelude::RgbColor;
use embedded_hal::delay::DelayNs;
mod gc9107;
mod gc9a01;
mod ili9225;
mod ili9341;
mod ili9342c;
mod ili934x;
mod ili9486;
mod ili9488;
mod ili948x;
mod rm67162;
mod st7735s;
mod st7789;
mod st7796;
pub use gc9107::*;
pub use gc9a01::*;
pub use ili9225::*;
pub use ili9341::*;
pub use ili9342c::*;
pub use ili9486::*;
pub use ili9488::*;
pub use rm67162::*;
pub use st7735s::*;
pub use st7789::*;
pub use st7796::*;
pub trait Model {
type ColorFormat: RgbColor;
const FRAMEBUFFER_SIZE: (u16, u16);
const RESET_DURATION: u32 = 10;
fn init<DELAY, DI>(
&mut self,
di: &mut DI,
delay: &mut DELAY,
options: &ModelOptions,
) -> Result<SetAddressMode, ModelInitError<DI::Error>>
where
DELAY: DelayNs,
DI: Interface;
fn update_address_window<DI>(
di: &mut DI,
_rotation: Rotation,
sx: u16,
sy: u16,
ex: u16,
ey: u16,
) -> Result<(), DI::Error>
where
DI: Interface,
{
di.write_command(dcs::SetColumnAddress::new(sx, ex))?;
di.write_command(dcs::SetPageAddress::new(sy, ey))
}
fn sleep<DI, DELAY>(di: &mut DI, delay: &mut DELAY) -> Result<(), DI::Error>
where
DI: Interface,
DELAY: DelayNs,
{
di.write_command(dcs::EnterSleepMode)?;
delay.delay_us(120_000);
Ok(())
}
fn wake<DI, DELAY>(di: &mut DI, delay: &mut DELAY) -> Result<(), DI::Error>
where
DI: Interface,
DELAY: DelayNs,
{
di.write_command(dcs::ExitSleepMode)?;
delay.delay_us(120_000);
Ok(())
}
fn write_memory_start<DI>(di: &mut DI) -> Result<(), DI::Error>
where
DI: Interface,
{
di.write_command(dcs::WriteMemoryStart)
}
fn software_reset<DI>(di: &mut DI) -> Result<(), DI::Error>
where
DI: Interface,
{
di.write_command(dcs::SoftReset)
}
fn update_options<DI>(&self, di: &mut DI, options: &ModelOptions) -> Result<(), DI::Error>
where
DI: Interface,
{
let madctl = SetAddressMode::from(options);
di.write_command(madctl)
}
fn set_tearing_effect<DI>(
di: &mut DI,
tearing_effect: options::TearingEffect,
_options: &ModelOptions,
) -> Result<(), DI::Error>
where
DI: Interface,
{
di.write_command(dcs::SetTearingEffect::new(tearing_effect))
}
fn set_vertical_scroll_region<DI>(
di: &mut DI,
top_fixed_area: u16,
bottom_fixed_area: u16,
) -> Result<(), DI::Error>
where
DI: Interface,
{
let rows = Self::FRAMEBUFFER_SIZE.1;
let vscrdef = if top_fixed_area + bottom_fixed_area > rows {
dcs::SetScrollArea::new(rows, 0, 0)
} else {
dcs::SetScrollArea::new(
top_fixed_area,
rows - top_fixed_area - bottom_fixed_area,
bottom_fixed_area,
)
};
di.write_command(vscrdef)
}
fn set_vertical_scroll_offset<DI>(di: &mut DI, offset: u16) -> Result<(), DI::Error>
where
DI: Interface,
{
let vscad = dcs::SetScrollStart::new(offset);
di.write_command(vscad)
}
}
#[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum ModelInitError<DiError> {
Interface(DiError),
InvalidConfiguration(ConfigurationError),
}
impl<DiError> From<DiError> for ModelInitError<DiError> {
fn from(value: DiError) -> Self {
Self::Interface(value)
}
}
#[cfg(test)]
mod tests {
use embedded_graphics::pixelcolor::Rgb565;
use crate::{
Builder,
_mock::{MockDelay, MockDisplayInterface},
dcs::SetAddressMode,
interface::InterfaceKind,
ConfigurationError, InitError,
};
use super::*;
struct OnlyOneKindModel(InterfaceKind);
impl Model for OnlyOneKindModel {
type ColorFormat = Rgb565;
const FRAMEBUFFER_SIZE: (u16, u16) = (16, 16);
fn init<DELAY, DI>(
&mut self,
_di: &mut DI,
_delay: &mut DELAY,
_options: &ModelOptions,
) -> Result<SetAddressMode, ModelInitError<DI::Error>>
where
DELAY: DelayNs,
DI: Interface,
{
if DI::KIND != self.0 {
return Err(ModelInitError::InvalidConfiguration(
ConfigurationError::UnsupportedInterface,
));
}
Ok(SetAddressMode::default())
}
}
#[test]
fn test_assert_interface_kind_serial() {
Builder::new(
OnlyOneKindModel(InterfaceKind::Serial4Line),
MockDisplayInterface,
)
.init(&mut MockDelay)
.unwrap();
}
#[test]
fn test_assert_interface_kind_parallel() {
assert!(matches!(
Builder::new(
OnlyOneKindModel(InterfaceKind::Parallel8Bit),
MockDisplayInterface,
)
.init(&mut MockDelay),
Err(InitError::InvalidConfiguration(
ConfigurationError::UnsupportedInterface
))
));
}
}