#![no_std]
#![allow(clippy::type_complexity)]
#![warn(missing_docs)]
use dcs::SetAddressMode;
pub mod interface;
use embedded_hal::digital::OutputPin;
use embedded_hal_async::delay::DelayNs;
pub mod options;
use options::MemoryMapping;
mod builder;
pub use builder::*;
pub mod dcs;
pub mod models;
pub mod raw_framebuf;
use models::Model;
mod graphics;
mod test_image;
pub use test_image::TestImage;
pub mod _troubleshooting;
pub struct Display<DI, MODEL, RST>
where
DI: interface::Interface,
MODEL: Model,
RST: OutputPin,
{
di: DI,
model: MODEL,
rst: Option<RST>,
options: options::ModelOptions,
#[allow(dead_code)]
madctl: SetAddressMode,
sleeping: bool,
}
impl<DI, M, RST> Display<DI, M, RST>
where
DI: interface::Interface,
M: Model,
RST: OutputPin,
{
pub fn orientation(&self) -> options::Orientation {
self.options.orientation
}
pub async fn set_orientation(
&mut self,
orientation: options::Orientation,
) -> Result<(), DI::Error> {
self.options.orientation = orientation;
self.model.update_options(&mut self.di, &self.options).await
}
pub async fn show_raw_data<DW>(
&mut self,
x: u16,
y: u16,
width: u16,
height: u16,
pixel_data: &[DW],
) -> Result<(), DI::Error>
where
DI: interface::Interface<Word = DW>,
DW: Copy,
{
let ex = x + width - 1;
let ey = y + height - 1;
self.set_address_window(x, y, ex, ey).await?;
M::write_memory_start(&mut self.di).await?;
self.di.send_data_slice(pixel_data).await
}
pub async fn set_vertical_scroll_region(
&mut self,
top_fixed_area: u16,
bottom_fixed_area: u16,
) -> Result<(), DI::Error> {
M::set_vertical_scroll_region(&mut self.di, top_fixed_area, bottom_fixed_area).await
}
pub async fn set_vertical_scroll_offset(&mut self, offset: u16) -> Result<(), DI::Error> {
M::set_vertical_scroll_offset(&mut self.di, offset).await
}
pub fn release(self) -> (DI, M, Option<RST>) {
(self.di, self.model, self.rst)
}
async fn set_address_window(
&mut self,
sx: u16,
sy: u16,
ex: u16,
ey: u16,
) -> Result<(), DI::Error> {
let mut offset = self.options.display_offset;
let mapping = MemoryMapping::from(self.options.orientation);
if mapping.reverse_columns {
offset.0 = M::FRAMEBUFFER_SIZE.0 - (self.options.display_size.0 + offset.0);
}
if mapping.reverse_rows {
offset.1 = M::FRAMEBUFFER_SIZE.1 - (self.options.display_size.1 + offset.1);
}
if mapping.swap_rows_and_columns {
offset = (offset.1, offset.0);
}
let (sx, sy, ex, ey) = (sx + offset.0, sy + offset.1, ex + offset.0, ey + offset.1);
M::update_address_window(
&mut self.di,
self.options.orientation.rotation,
sx,
sy,
ex,
ey,
)
.await
}
pub async fn set_tearing_effect(
&mut self,
tearing_effect: options::TearingEffect,
) -> Result<(), DI::Error> {
M::set_tearing_effect(&mut self.di, tearing_effect, &self.options).await
}
pub fn is_sleeping(&self) -> bool {
self.sleeping
}
pub async fn sleep<D: DelayNs>(&mut self, delay: &mut D) -> Result<(), DI::Error> {
M::sleep(&mut self.di, delay).await?;
self.sleeping = true;
Ok(())
}
pub async fn wake<D: DelayNs>(&mut self, delay: &mut D) -> Result<(), DI::Error> {
M::wake(&mut self.di, delay).await?;
self.sleeping = false;
Ok(())
}
pub unsafe fn dcs(&mut self) -> &mut DI {
&mut self.di
}
}
#[doc(hidden)]
pub mod _mock {
use core::convert::Infallible;
use embedded_hal::{digital, spi};
use embedded_hal_async::delay::DelayNs;
use crate::{
interface::{Interface, InterfaceKind},
models::ILI9341Rgb565,
Builder, Display, NoResetPin,
};
pub async fn new_mock_display() -> Display<MockDisplayInterface, ILI9341Rgb565, NoResetPin> {
Builder::new(ILI9341Rgb565, MockDisplayInterface)
.init(&mut MockDelay)
.await
.unwrap()
}
pub struct MockOutputPin;
impl digital::OutputPin for MockOutputPin {
fn set_low(&mut self) -> Result<(), Self::Error> {
Ok(())
}
fn set_high(&mut self) -> Result<(), Self::Error> {
Ok(())
}
}
impl digital::ErrorType for MockOutputPin {
type Error = core::convert::Infallible;
}
pub struct MockSpi;
impl spi::SpiDevice for MockSpi {
fn transaction(
&mut self,
_operations: &mut [spi::Operation<'_, u8>],
) -> Result<(), Self::Error> {
Ok(())
}
}
impl spi::ErrorType for MockSpi {
type Error = core::convert::Infallible;
}
pub struct MockDelay;
impl DelayNs for MockDelay {
async fn delay_ns(&mut self, _ns: u32) {}
}
pub struct MockDisplayInterface;
impl Interface for MockDisplayInterface {
type Word = u8;
type Error = Infallible;
const KIND: InterfaceKind = InterfaceKind::Serial4Line;
async fn send_command(&mut self, _command: u8, _args: &[u8]) -> Result<(), Self::Error> {
Ok(())
}
async fn send_data_slice(&mut self, _data: &[Self::Word]) -> Result<(), Self::Error> {
Ok(())
}
}
}