use crate::basic_display::{BasicDisplay, DisplayUpdateMode, Rotation};
use crate::command::DisplayCommands;
use crate::config;
use crate::interface::DisplayInterface;
use core::usize;
use embedded_hal;
#[cfg(feature = "graphics")]
use embedded_graphics_core::{pixelcolor::BinaryColor, prelude::*};
#[cfg(feature = "defmt")]
use defmt::*;
pub struct Display<'a, I, SPI>
where
SPI: embedded_hal::spi::SpiDevice,
I: DisplayInterface + DisplayCommands<SPI>,
{
display: BasicDisplay<I, SPI>, bw_buffer: &'a mut [u8], }
impl<'a, I, SPI> Display<'a, I, SPI>
where
SPI: embedded_hal::spi::SpiDevice,
I: DisplayInterface + DisplayCommands<SPI>,
{
pub fn new(interface: I, bw_buffer: &'a mut [u8], config: config::Config) -> Self {
let d = BasicDisplay::new(interface, config);
Display::from_basic_display(d, bw_buffer)
}
pub fn from_basic_display(display: BasicDisplay<I, SPI>, bw_buffer: &'a mut [u8]) -> Self {
Display { display, bw_buffer }
}
pub fn update(
&mut self,
mode: DisplayUpdateMode,
) -> Result<(), <I as DisplayInterface>::Error> {
self.display.update(Some(self.bw_buffer), None, mode)
}
#[cfg(not(feature = "graphics"))]
pub fn clear(&mut self, fill_white: bool) {
let fill_value: u8 = match fill_white {
true => 0xFF,
false => 0x00,
};
for byte in &mut self.bw_buffer.as_mut().iter_mut() {
*byte = fill_value;
}
self.update(DisplayUpdateMode::Slow)
}
#[cfg(feature = "graphics")]
pub fn clear(&mut self, color: BinaryColor) -> Result<(), <I as DisplayInterface>::Error> {
let fill_value: u8 = match color {
BinaryColor::On => 0x00,
BinaryColor::Off => 0xFF,
};
for byte in &mut self.bw_buffer.as_mut().iter_mut() {
*byte = fill_value;
}
if self.display.config.auto_update {
self.update(DisplayUpdateMode::Slow)
} else {
Ok(())
}
}
pub fn set_pixel(&mut self, x: u32, y: u32, color: BinaryColor) {
#[cfg(feature = "defmt")]
trace!(
"Setting pixel on (x: {}, y: {}) to `{}` with rotation {}",
x,
y,
color,
self.rotation()
);
let (index, bit) = rotation(
x,
y,
self.cols() as u32,
self.rows() as u32,
self.rotation(),
);
let index = index as usize;
#[cfg(feature = "defmt")]
trace!("Setting pixel on index {} to {}", index, bit);
match color {
BinaryColor::On => {
self.bw_buffer.as_mut()[index] &= !bit;
}
BinaryColor::Off => {
self.bw_buffer.as_mut()[index] |= bit;
}
}
}
}
impl<'a, I, SPI> core::ops::Deref for Display<'a, I, SPI>
where
SPI: embedded_hal::spi::SpiDevice,
I: DisplayInterface + DisplayCommands<SPI>,
{
type Target = BasicDisplay<I, SPI>;
fn deref(&self) -> &BasicDisplay<I, SPI> {
&self.display
}
}
impl<'a, I, SPI> core::ops::DerefMut for Display<'a, I, SPI>
where
SPI: embedded_hal::spi::SpiDevice,
I: DisplayInterface + DisplayCommands<SPI>,
{
fn deref_mut(&mut self) -> &mut BasicDisplay<I, SPI> {
&mut self.display
}
}
fn rotation(x: u32, y: u32, width: u32, height: u32, rotation: Rotation) -> (u32, u8) {
let (px, py) = match rotation {
Rotation::Rotate0 => (x, y),
Rotation::Rotate90 => (y, height - 1 - x),
Rotation::Rotate180 => (width - 1 - x, height - 1 - y),
Rotation::Rotate270 => (width - 1 - y, x),
};
let phys_x = px;
let phys_y = height - 1 - py;
let bytes_per_row = width / 8;
let byte_index = phys_y * bytes_per_row + (phys_x / 8);
let bit_mask = 0x80 >> (phys_x % 8);
(byte_index, bit_mask)
}
#[cfg(feature = "graphics")]
impl<'a, I, SPI> DrawTarget for Display<'a, I, SPI>
where
SPI: embedded_hal::spi::SpiDevice,
I: DisplayInterface + DisplayCommands<SPI>,
{
type Color = BinaryColor;
type Error = core::convert::Infallible;
fn draw_iter<Iter>(&mut self, pixels: Iter) -> Result<(), Self::Error>
where
Iter: IntoIterator<Item = Pixel<Self::Color>>,
{
let size = self.size();
#[cfg(feature = "defmt")]
trace!("Drawing to the display");
for Pixel(Point { x, y }, color) in pixels {
let x = x as u32;
let y = y as u32;
if x < size.width && y < size.height {
self.set_pixel(x, y, color);
}
}
if self.config.auto_update {
let _ = self.update(DisplayUpdateMode::Fast);
}
Ok(())
}
}
#[cfg(feature = "graphics")]
impl<'a, I, SPI> OriginDimensions for Display<'a, I, SPI>
where
SPI: embedded_hal::spi::SpiDevice,
I: DisplayInterface + DisplayCommands<SPI>,
{
fn size(&self) -> Size {
match self.rotation() {
Rotation::Rotate0 | Rotation::Rotate180 => {
Size::new(self.cols().into(), self.rows().into())
}
Rotation::Rotate90 | Rotation::Rotate270 => {
Size::new(self.rows().into(), self.cols().into())
}
}
}
}