use crate::{
bus::DisplayBus,
color::ColorFormat,
panel::{Orientation, Panel, PanelSetBrightness},
Area, DisplayDriver, DisplayError, FrameControl,
};
use delegate::delegate;
use embedded_graphics::framebuffer::Framebuffer;
use embedded_graphics_core::{
draw_target::DrawTarget, geometry::OriginDimensions, geometry::Size, pixelcolor::PixelColor,
Pixel,
};
use embedded_hal_async::delay::DelayNs;
pub struct FrameBufferedDisplayDriver<
'a,
B,
P,
C,
R,
BO,
const W: usize,
const H: usize,
const N: usize,
> where
B: DisplayBus,
P: Panel<B>,
C: PixelColor<Raw = R>,
{
pub driver: DisplayDriver<B, P>,
area: Area,
framebuffer: &'a mut Framebuffer<C, R, BO, W, H, N>,
}
impl<'a, B, P, C, R, BO, const W: usize, const H: usize, const N: usize>
FrameBufferedDisplayDriver<'a, B, P, C, R, BO, W, H, N>
where
B: DisplayBus,
P: Panel<B>,
C: PixelColor<Raw = R>,
{
pub fn new(
driver: DisplayDriver<B, P>,
framebuffer: &'a mut Framebuffer<C, R, BO, W, H, N>,
) -> Self {
Self {
driver,
area: Area::from_origin(W as u16, H as u16),
framebuffer,
}
}
pub fn new_partial(
driver: DisplayDriver<B, P>,
area: Area,
framebuffer: &'a mut Framebuffer<C, R, BO, W, H, N>,
) -> Result<Self, DisplayError<B::Error>> {
if area.w as usize != W || area.h as usize != H {
return Err(DisplayError::InvalidArgs);
}
Ok(Self {
driver,
area,
framebuffer,
})
}
pub fn set_area(&mut self, area: Area) -> Result<(), DisplayError<B::Error>> {
if area.w as usize != W || area.h as usize != H {
return Err(DisplayError::InvalidArgs);
}
self.area = area;
Ok(())
}
pub fn area(&self) -> Area {
self.area
}
pub fn framebuffer(&self) -> &Framebuffer<C, R, BO, W, H, N> {
self.framebuffer
}
pub fn framebuffer_mut(&mut self) -> &mut Framebuffer<C, R, BO, W, H, N> {
self.framebuffer
}
pub async fn flush(&mut self) -> Result<(), DisplayError<B::Error>> {
self.flush_with_frame_control(FrameControl::new_standalone())
.await
}
pub async fn flush_with_frame_control(
&mut self,
frame_control: FrameControl,
) -> Result<(), DisplayError<B::Error>> {
self.driver
.write_pixels(self.area, frame_control, self.framebuffer.data())
.await
}
pub async fn flush_lines(
&mut self,
y_start: u16,
y_end: u16,
) -> Result<(), DisplayError<B::Error>> {
self.flush_lines_with_frame_control(y_start, y_end, FrameControl::new_standalone())
.await
}
pub async fn flush_lines_with_frame_control(
&mut self,
y_start: u16,
y_end: u16,
frame_control: FrameControl,
) -> Result<(), DisplayError<B::Error>> {
if y_start > y_end || y_end >= H as u16 {
return Err(DisplayError::InvalidArgs);
}
let bpp = core::mem::size_of::<R>();
let start_idx = (y_start as usize * W) * bpp;
let end_idx = ((y_end as usize + 1) * W) * bpp;
let data = self.framebuffer.data();
let slice = &data[start_idx..end_idx];
let area = Area::new(
self.area.x,
self.area.y + y_start,
W as u16,
y_end - y_start + 1,
);
self.driver.write_pixels(area, frame_control, slice).await
}
pub fn into_inner(self) -> DisplayDriver<B, P> {
self.driver
}
delegate! {
to self.driver {
pub async fn init(&mut self, delay: &mut impl DelayNs) -> Result<(), DisplayError<B::Error>>;
pub async fn set_color_format(&mut self, color_format: ColorFormat) -> Result<(), DisplayError<B::Error>>;
pub async fn set_orientation(&mut self, orientation: Orientation) -> Result<(), DisplayError<B::Error>>;
}
}
}
impl<'a, B, P, C, R, BO, const W: usize, const H: usize, const N: usize>
FrameBufferedDisplayDriver<'a, B, P, C, R, BO, W, H, N>
where
B: DisplayBus,
P: Panel<B> + PanelSetBrightness<B>,
C: PixelColor<Raw = R>,
{
delegate! {
to self.driver {
pub async fn set_brightness(&mut self, brightness: u8) -> Result<(), DisplayError<B::Error>>;
}
}
}
impl<'a, B, P, C, R, BO, const W: usize, const H: usize, const N: usize> OriginDimensions
for FrameBufferedDisplayDriver<'a, B, P, C, R, BO, W, H, N>
where
B: DisplayBus,
P: Panel<B>,
C: PixelColor<Raw = R>,
{
fn size(&self) -> Size {
self.framebuffer.size()
}
}
impl<'a, B, P, C, R, BO, const W: usize, const H: usize, const N: usize> DrawTarget
for FrameBufferedDisplayDriver<'a, B, P, C, R, BO, W, H, N>
where
B: DisplayBus,
P: Panel<B>,
C: PixelColor<Raw = R>,
Framebuffer<C, R, BO, W, H, N>: DrawTarget<Color = C>,
{
type Color = C;
type Error = <Framebuffer<C, R, BO, W, H, N> as DrawTarget>::Error;
fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error>
where
I: IntoIterator<Item = Pixel<Self::Color>>,
{
self.framebuffer.draw_iter(pixels)
}
fn fill_contiguous<I>(
&mut self,
area: &embedded_graphics_core::primitives::Rectangle,
colors: I,
) -> Result<(), Self::Error>
where
I: IntoIterator<Item = Self::Color>,
{
self.framebuffer.fill_contiguous(area, colors)
}
fn fill_solid(
&mut self,
area: &embedded_graphics_core::primitives::Rectangle,
color: Self::Color,
) -> Result<(), Self::Error> {
self.framebuffer.fill_solid(area, color)
}
fn clear(&mut self, color: Self::Color) -> Result<(), Self::Error> {
self.framebuffer.clear(color)
}
}