Major Rewrite

No more blinking :D
This commit is contained in:
CanadianBaconBoi 2025-05-10 22:37:10 +02:00
parent 66fdd992d5
commit 36484f1735
Signed by: CanadianBacon
GPG Key ID: 410B7F84E17E4424
11 changed files with 198 additions and 177 deletions

View File

@ -18,7 +18,11 @@ debug = true # Symbols are nice and they don't increase the size on Flash
opt-level = "z"
[features]
default = []
default = [
"mipidsi/heapless",
"embedded-graphics/defmt",
"embedded-hal/defmt-03",
]
experimental = ["esp-idf-svc/experimental"]
@ -29,6 +33,7 @@ mipidsi = "0.9.0"
anyhow = "1.0.98"
embedded-graphics = "0.8.1"
embedded-hal = "1.0.0"
defmt = "1.0.1"
[build-dependencies]
embuild = "0.33"

View File

@ -1,34 +1,30 @@
{
"version": 1,
"author": "Justin hei Eusebio",
"editor": "wokwi",
"author": "CanadianBaconBoi <bc.bacon.bits@gmail.com>",
"parts": [
{
"type": "board-esp32-devkit-c-v4",
"id": "esp",
"top": 0.59,
"left": 0.67,
"attrs": {
"flashSize": "16"
}
}
"top": -19.38,
"left": -158.63,
"attrs": {}
},
{ "type": "wokwi-ili9341", "id": "lcd1", "top": -81, "left": 88.1, "rotate": 90, "attrs": {} }
],
"connections": [
[
"esp:TX",
"$serialMonitor:RX",
"",
[]
],
[
"esp:RX",
"$serialMonitor:TX",
"",
[]
]
[ "esp:TX", "$serialMonitor:RX", "", [] ],
[ "esp:RX", "$serialMonitor:TX", "", [] ],
[ "lcd1:VCC", "esp:5V", "red", [ "h-17.2", "v-72.2", "h-174.8", "v225.8" ] ],
[ "lcd1:GND", "esp:GND.2", "black", [ "h-38.4", "v-28.8" ] ],
[ "lcd1:MOSI", "esp:19", "Yellow", [ "h-28.8", "v172.79", "h-182.4", "v-86.4" ] ],
[ "lcd1:RST", "esp:23", "Yellow", [ "h-28.8", "v172.79", "h-182.4", "v-86.4" ] ],
[ "lcd1:LED", "esp:4", "Yellow", [ "h-28.8", "v172.79", "h-182.4", "v-86.4" ] ],
[ "lcd1:MISO", "esp:21", "Yellow", [ "h-28.8", "v172.79", "h-182.4", "v-86.4" ] ],
[ "lcd1:SCK", "esp:18", "White", [ "h-19.2", "v172.79", "h-182.4", "v-86.4" ] ],
[ "lcd1:RST", "esp:23", "Blue", [ "h-48", "v-76.8", "h-163.2", "v96" ] ],
[ "lcd1:CS", "esp:5", "Orange", [ "h-28.8", "v-76.8", "h-172.8", "v76.8" ] ],
[ "lcd1:D/C", "esp:16", "green", [ "h-57.6", "v-134.4", "h-163.2", "v163.2" ] ]
],
"serialMonitor": {
"display": "terminal",
"convertEol": true
}
}
"dependencies": {}
}

View File

@ -2,5 +2,4 @@ pub mod base;
pub mod home;
pub mod success;
pub mod error;
pub mod macros;
mod prelude;
pub mod macros;

View File

@ -1,71 +1,61 @@
use embedded_graphics::draw_target::DrawTarget;
use embedded_graphics::framebuffer::Framebuffer;
use embedded_graphics::geometry::{Point, Size};
use embedded_graphics::pixelcolor::Rgb565;
use embedded_graphics::pixelcolor::{PixelColor, RgbColor};
use embedded_graphics::primitives::CornerRadii;
use embedded_hal::digital::OutputPin;
use mipidsi::interface::InterfacePixelFormat;
use crate::display::tools::DrawTools;
use crate::{W, H};
use crate::display::theme::MACCHIATO;
use crate::{H_I, W_I};
pub trait DisplayScreen<DI, M, RST>
pub trait DisplayScreen<C, BO, const WIDTH: usize, const HEIGHT: usize, const N: usize>
where
DI: mipidsi::interface::Interface,
M: mipidsi::models::Model<ColorFormat = Rgb565>,
M::ColorFormat: InterfacePixelFormat<DI::Word>,
RST: OutputPin,
C: RgbColor + From<embedded_graphics::pixelcolor::Rgb565> + Into<C>, Framebuffer<C, <C as PixelColor>::Raw, BO, WIDTH, HEIGHT, N>: DrawTarget
{
fn show(index: &mut usize, frame_counter: &mut usize, dirty: &mut bool, display: &mut mipidsi::Display<DI, M, RST>) -> anyhow::Result<(), DI::Error>;
fn input(button: ButtonPosition) -> anyhow::Result<(), DI::Error> {
fn show(index: &mut usize, frame_counter: &mut usize, dirty: &mut bool, display: &mut Framebuffer<C, <C as PixelColor>::Raw, BO, WIDTH, HEIGHT, N>) -> anyhow::Result<(), <Framebuffer<C, C::Raw, BO, WIDTH, HEIGHT, N> as DrawTarget>::Error>;
fn input(button: ButtonPosition) -> anyhow::Result<(), <Framebuffer<C, C::Raw, BO, WIDTH, HEIGHT, N> as embedded_graphics::draw_target::DrawTarget>::Error> {
Ok(())
}
}
pub struct StandardBase;
impl<DI, M, RST> DisplayScreen<DI, M, RST> for StandardBase
impl<C, BO, const WIDTH: usize, const HEIGHT: usize, const N: usize> DisplayScreen<C, BO, WIDTH, HEIGHT, N> for StandardBase
where
DI: mipidsi::interface::Interface,
M: mipidsi::models::Model<ColorFormat = Rgb565>,
M::ColorFormat: InterfacePixelFormat<DI::Word>,
RST: OutputPin,
C: RgbColor + From<embedded_graphics::pixelcolor::Rgb565> + Into<C>, Framebuffer<C, <C as PixelColor>::Raw, BO, WIDTH, HEIGHT, N>: DrawTarget<Color=C>
{
fn show(_index: &mut usize, _frame_counter: &mut usize, dirty: &mut bool, display: &mut mipidsi::Display<DI, M, RST>) -> anyhow::Result<(), DI::Error> {
fn show(index: &mut usize, frame_counter: &mut usize, dirty: &mut bool, display: &mut Framebuffer<C, <C as PixelColor>::Raw, BO, WIDTH, HEIGHT, N>) -> anyhow::Result<(), <Framebuffer<C, C::Raw, BO, WIDTH, HEIGHT, N> as DrawTarget>::Error>
{
if *dirty {
display.draw_rectangle_bounds(Point::new(0, 0), Point::new(W, H), MACCHIATO.crust)?;
display.draw_rounded_rectangle_bounds(Point::new(10, 10), Point::new(W -10, H -10), MACCHIATO.mantle, CornerRadii::new(Size::new(10, 10)))?;
display.draw_rectangle_bounds(Point::new(0, 0), Point::new(W_I, H_I), MACCHIATO.crust.into())?;
display.draw_rounded_rectangle_bounds(Point::new(10, 10), Point::new(W_I - 10, H_I - 10), MACCHIATO.mantle.into(), CornerRadii::new(Size::new(10, 10)))?;
}
Ok(())
}
}
pub struct ErrorBase;
impl<DI, M, RST> DisplayScreen<DI, M, RST> for ErrorBase
impl<C, BO, const WIDTH: usize, const HEIGHT: usize, const N: usize> DisplayScreen<C, BO, WIDTH, HEIGHT, N> for ErrorBase
where
DI: mipidsi::interface::Interface,
M: mipidsi::models::Model<ColorFormat = Rgb565>,
M::ColorFormat: InterfacePixelFormat<DI::Word>,
RST: OutputPin,
C: RgbColor + From<embedded_graphics::pixelcolor::Rgb565> + Into<C>, Framebuffer<C, <C as PixelColor>::Raw, BO, WIDTH, HEIGHT, N>: DrawTarget<Color=C>
{
fn show(_index: &mut usize, _frame_counter: &mut usize, dirty: &mut bool, display: &mut mipidsi::Display<DI, M, RST>) -> anyhow::Result<(), DI::Error> {
fn show(index: &mut usize, frame_counter: &mut usize, dirty: &mut bool, display: &mut Framebuffer<C, <C as PixelColor>::Raw, BO, WIDTH, HEIGHT, N>) -> anyhow::Result<(), <Framebuffer<C, C::Raw, BO, WIDTH, HEIGHT, N> as DrawTarget>::Error> {
if *dirty {
display.draw_rectangle_bounds(Point::new(0, 0), Point::new(W, H), MACCHIATO.maroon)?;
display.draw_rounded_rectangle_bounds(Point::new(10, 10), Point::new(W -10, H -10), MACCHIATO.mantle, CornerRadii::new(Size::new(10, 10)))?;
display.draw_rectangle_bounds(Point::new(0, 0), Point::new(W_I, H_I), MACCHIATO.maroon.into())?;
display.draw_rounded_rectangle_bounds(Point::new(10, 10), Point::new(W_I-10, H_I-10), MACCHIATO.mantle.into(), CornerRadii::new(Size::new(10, 10)))?;
}
Ok(())
}
}
pub struct SuccessBase;
impl<DI, M, RST> DisplayScreen<DI, M, RST> for SuccessBase
impl<C, BO, const WIDTH: usize, const HEIGHT: usize, const N: usize> DisplayScreen<C, BO, WIDTH, HEIGHT, N> for SuccessBase
where
DI: mipidsi::interface::Interface,
M: mipidsi::models::Model<ColorFormat = Rgb565>,
M::ColorFormat: InterfacePixelFormat<DI::Word>,
RST: OutputPin,
C: RgbColor + From<embedded_graphics::pixelcolor::Rgb565> + Into<C>, Framebuffer<C, <C as PixelColor>::Raw, BO, WIDTH, HEIGHT, N>: DrawTarget<Color=C>
{
fn show(_index: &mut usize, _frame_counter: &mut usize, dirty: &mut bool, display: &mut mipidsi::Display<DI, M, RST>) -> anyhow::Result<(), DI::Error> {
fn show(index: &mut usize, frame_counter: &mut usize, dirty: &mut bool, display: &mut Framebuffer<C, <C as PixelColor>::Raw, BO, WIDTH, HEIGHT, N>) -> anyhow::Result<(), <Framebuffer<C, C::Raw, BO, WIDTH, HEIGHT, N> as DrawTarget>::Error> {
if *dirty {
display.draw_rectangle_bounds(Point::new(0, 0), Point::new(W, H), MACCHIATO.green)?;
display.draw_rounded_rectangle_bounds(Point::new(10, 10), Point::new(W -10, H -10), MACCHIATO.mantle, CornerRadii::new(Size::new(10, 10)))?;
display.draw_rectangle_bounds(Point::new(0, 0), Point::new(W_I, H_I), MACCHIATO.green.into())?;
display.draw_rounded_rectangle_bounds(Point::new(10, 10), Point::new(W_I-10, H_I-10), MACCHIATO.mantle.into(), CornerRadii::new(Size::new(10, 10)))?;
}
Ok(())
}

View File

@ -1,16 +1,16 @@
use crate::{error_screen, FRAMERATE, H, W};
use crate::{error_screen, FRAMERATE, H_I, W_I};
use crate::display::screens::base::{ButtonPosition, ErrorBase};
use crate::DisplayScreen;
use mipidsi::models::Model;
use embedded_graphics::pixelcolor::Rgb565;
use embedded_graphics::prelude::Point;
use mipidsi::interface::InterfacePixelFormat;
use embedded_hal::digital::OutputPin;
use crate::display::tools::DrawTools;
use embedded_graphics::pixelcolor::PixelColor;
use embedded_graphics::draw_target::DrawTarget;
use embedded_graphics::framebuffer::Framebuffer;
use embedded_graphics::pixelcolor::RgbColor;
error_screen!(ErrorScreen, |index: &mut usize, frame_counter: &mut usize, dirty: &mut bool, display: &mut mipidsi::Display<_, _, _>|->anyhow::Result<(), _> {
error_screen!(ErrorScreen, |index: &mut usize, frame_counter: &mut usize, dirty: &mut bool, display: &mut Framebuffer<_, _, _, WIDTH, HEIGHT, N>|->anyhow::Result<(), _> {
if *dirty {
display.draw_text_centered(Point::new(W/2, H/2), "Error!")?;
display.draw_text_centered(Point::new(W_I/2, H_I/2), "Error!")?;
*dirty = false;
} else if *frame_counter % FRAMERATE*4 == 0 {
#[cfg(debug_assertions)]

View File

@ -1,16 +1,16 @@
use embedded_graphics::framebuffer::Framebuffer;
use embedded_graphics::geometry::Point;
use crate::{standard_screen, FRAMERATE, H, W};
use crate::{standard_screen, FRAMERATE, H_I, W_I};
use crate::display::screens::base::{ButtonPosition, StandardBase};
use crate::DisplayScreen;
use mipidsi::models::Model;
use embedded_graphics::pixelcolor::Rgb565;
use mipidsi::interface::InterfacePixelFormat;
use embedded_hal::digital::OutputPin;
use crate::display::tools::DrawTools;
use embedded_graphics::pixelcolor::PixelColor;
use embedded_graphics::draw_target::DrawTarget;
use embedded_graphics::pixelcolor::RgbColor;
standard_screen!(StandardScreen, |index: &mut usize, frame_counter: &mut usize, dirty: &mut bool, display: &mut mipidsi::Display<_, _, _>|->anyhow::Result<(), _> {
standard_screen!(StandardScreen, |index: &mut usize, frame_counter: &mut usize, dirty: &mut bool, display: &mut Framebuffer<_, _, _, WIDTH, HEIGHT, N>|->anyhow::Result<(), _> {
if *dirty {
display.draw_text_centered(Point::new(W/2, H/2), "Standard!")?;
display.draw_text_centered(Point::new(W_I/2, H_I/2), "Standard!")?;
*dirty = false;
} else if *frame_counter % FRAMERATE*4 == 0 {
#[cfg(debug_assertions)]

View File

@ -2,21 +2,18 @@
macro_rules! standard_screen {
( $name: ident, $show: expr, $input: expr ) => {
pub struct $name;
impl<DI, M, RST> DisplayScreen<DI, M, RST> for $name
where
DI: mipidsi::interface::Interface,
M: Model<ColorFormat = Rgb565>,
M::ColorFormat: InterfacePixelFormat<DI::Word>,
RST: OutputPin {
impl<C: RgbColor + From<embedded_graphics::pixelcolor::Rgb565> + Into<C>, BO, const WIDTH: usize, const HEIGHT: usize, const N: usize> DisplayScreen<C, BO, WIDTH, HEIGHT, N> for $name
where Framebuffer<C, <C as PixelColor>::Raw, BO, WIDTH, HEIGHT, N>: DrawTarget<Color = C>
{
#[inline]
fn show(idex: &mut usize, frame_counter: &mut usize, dirty: &mut bool, display: &mut mipidsi::Display<DI, M, RST>) -> anyhow::Result<(), DI::Error> {
fn show(idex: &mut usize, frame_counter: &mut usize, dirty: &mut bool, display: &mut embedded_graphics::framebuffer::Framebuffer<C, C::Raw, BO, WIDTH, HEIGHT, N>) -> anyhow::Result<(), <Framebuffer<C, C::Raw, BO, WIDTH, HEIGHT, N> as DrawTarget>::Error> {
StandardBase::show(idex, frame_counter, dirty, display)?;
$show(idex, frame_counter, dirty, display)
}
#[inline]
fn input(button: ButtonPosition) {
$input(button);
fn input(button: ButtonPosition) -> anyhow::Result<(), <Framebuffer<C, C::Raw, BO, WIDTH, HEIGHT, N> as DrawTarget>::Error> {
$input(button)
}
}
};
@ -26,21 +23,18 @@ macro_rules! standard_screen {
macro_rules! error_screen {
( $name: ident, $show: expr, $input: expr ) => {
pub struct $name;
impl<DI, M, RST> DisplayScreen<DI, M, RST> for $name
where
DI: mipidsi::interface::Interface,
M: Model<ColorFormat = Rgb565>,
M::ColorFormat: InterfacePixelFormat<DI::Word>,
RST: OutputPin {
impl<C: RgbColor + From<embedded_graphics::pixelcolor::Rgb565> + Into<C>, BO, const WIDTH: usize, const HEIGHT: usize, const N: usize> DisplayScreen<C, BO, WIDTH, HEIGHT, N> for $name
where Framebuffer<C, <C as PixelColor>::Raw, BO, WIDTH, HEIGHT, N>: DrawTarget<Color = C>
{
#[inline]
fn show(idex: &mut usize, frame_counter: &mut usize, dirty: &mut bool, display: &mut mipidsi::Display<DI, M, RST>) -> anyhow::Result<(), DI::Error> {
fn show(idex: &mut usize, frame_counter: &mut usize, dirty: &mut bool, display: &mut embedded_graphics::framebuffer::Framebuffer<C, C::Raw, BO, WIDTH, HEIGHT, N>) -> anyhow::Result<(), <Framebuffer<C, C::Raw, BO, WIDTH, HEIGHT, N> as DrawTarget>::Error> {
ErrorBase::show(idex, frame_counter, dirty, display)?;
$show(idex, frame_counter, dirty, display)
}
#[inline]
fn input(button: ButtonPosition) {
$input(button);
fn input(button: ButtonPosition) -> anyhow::Result<(), <Framebuffer<C, C::Raw, BO, WIDTH, HEIGHT, N> as DrawTarget>::Error> {
$input(button)
}
}
};
@ -50,21 +44,18 @@ macro_rules! error_screen {
macro_rules! success_screen {
( $name: ident, $show: expr, $input: expr ) => {
pub struct $name;
impl<DI, M, RST> DisplayScreen<DI, M, RST> for $name
where
DI: mipidsi::interface::Interface,
M: Model<ColorFormat = Rgb565>,
M::ColorFormat: InterfacePixelFormat<DI::Word>,
RST: OutputPin {
impl<C: RgbColor + From<embedded_graphics::pixelcolor::Rgb565> + Into<C>, BO, const WIDTH: usize, const HEIGHT: usize, const N: usize> DisplayScreen<C, BO, WIDTH, HEIGHT, N> for $name
where Framebuffer<C, <C as PixelColor>::Raw, BO, WIDTH, HEIGHT, N>: DrawTarget<Color = C>
{
#[inline]
fn show(idex: &mut usize, frame_counter: &mut usize, dirty: &mut bool, display: &mut mipidsi::Display<DI, M, RST>) -> anyhow::Result<(), DI::Error> {
fn show(idex: &mut usize, frame_counter: &mut usize, dirty: &mut bool, display: &mut embedded_graphics::framebuffer::Framebuffer<C, C::Raw, BO, WIDTH, HEIGHT, N>) -> anyhow::Result<(), <Framebuffer<C, C::Raw, BO, WIDTH, HEIGHT, N> as DrawTarget>::Error> {
SuccessBase::show(idex, frame_counter, dirty, display)?;
$show(idex, frame_counter, dirty, display)
}
#[inline]
fn input(button: ButtonPosition) {
$input(button);
fn input(button: ButtonPosition) -> anyhow::Result<(), <Framebuffer<C, C::Raw, BO, WIDTH, HEIGHT, N> as DrawTarget>::Error> {
$input(button)
}
}
};

View File

@ -1,9 +0,0 @@
use embedded_graphics::geometry::Point;
use crate::{success_screen, FRAMERATE, H, W};
use crate::display::screens::base::{ButtonPosition, SuccessBase};
use crate::DisplayScreen;
use mipidsi::models::Model;
use embedded_graphics::pixelcolor::Rgb565;
use mipidsi::interface::InterfacePixelFormat;
use embedded_hal::digital::OutputPin;
use crate::display::tools::DrawTools;

View File

@ -1,8 +1,16 @@
use crate::display::screens::prelude;
use embedded_graphics::framebuffer::{Framebuffer};
use crate::{success_screen, FRAMERATE, H_I, W_I};
use crate::display::screens::base::{ButtonPosition, SuccessBase};
use crate::DisplayScreen;
use embedded_graphics::pixelcolor::{PixelColor};
use embedded_graphics::prelude::Point;
use crate::display::tools::DrawTools;
use embedded_graphics::draw_target::DrawTarget;
use embedded_graphics::pixelcolor::RgbColor;
success_screen!(SuccessScreen, |index: &mut usize, frame_counter: &mut usize, dirty: &mut bool, display: &mut mipidsi::Display<_, _, _>|->anyhow::Result<(), _> {
success_screen!(SuccessScreen, |index: &mut usize, frame_counter: &mut usize, dirty: &mut bool, display: &mut Framebuffer<_, _, _, WIDTH, HEIGHT, N>|->anyhow::Result<(), _> {
if *dirty {
display.draw_text_centered(Point::new(W/2, H/2), "Success!")?;
display.draw_text_centered(Point::new(W_I/2, H_I/2), "Success!")?;
*dirty = false;
} else if *frame_counter % FRAMERATE*4 == 0 {
#[cfg(debug_assertions)]

View File

@ -1,72 +1,65 @@
use embedded_graphics::draw_target::DrawTarget;
use embedded_graphics::Drawable;
use embedded_graphics::framebuffer::Framebuffer;
use embedded_graphics::geometry::{Point, Size};
use embedded_graphics::mono_font::MonoTextStyle;
use embedded_graphics::pixelcolor::Rgb565;
use embedded_graphics::pixelcolor::{PixelColor, Rgb565};
use embedded_graphics::prelude::RgbColor;
use embedded_graphics::primitives::{CornerRadii, PrimitiveStyle, Rectangle, RoundedRectangle, StyledDrawable};
use embedded_graphics::text::Text;
use embedded_hal::digital::OutputPin;
use mipidsi::Display;
use mipidsi::interface::InterfacePixelFormat;
use crate::display::theme::MACCHIATO;
pub trait DrawTools<DI, M, RST>
pub trait DrawTools<C, BO, const WIDTH: usize, const HEIGHT: usize, const N: usize>
where
DI: mipidsi::interface::Interface,
M: mipidsi::models::Model<ColorFormat = Rgb565>,
M::ColorFormat: InterfacePixelFormat<DI::Word>,
RST: OutputPin,
C: RgbColor + From<embedded_graphics::pixelcolor::Rgb565> + Into<C>,
Framebuffer<C, <C as PixelColor>::Raw, BO, WIDTH, HEIGHT, N>: DrawTarget<Color = C>,
{
fn draw_rectangle_bounds(&mut self, top_left: Point, bottom_right: Point, color: M::ColorFormat) -> anyhow::Result<(), DI::Error>;
fn draw_rectangle_top_left(&mut self, top_left: Point, size: Size, color: M::ColorFormat) -> anyhow::Result<(), DI::Error>;
fn draw_rectangle_center(&mut self, center: Point, size: Size, color: M::ColorFormat) -> anyhow::Result<(), DI::Error>;
fn draw_rectangle_bounds(&mut self, top_left: Point, bottom_right: Point, color: C) -> anyhow::Result<(), <Framebuffer<C, C::Raw, BO, WIDTH, HEIGHT, N> as DrawTarget>::Error>;
fn draw_rectangle_top_left(&mut self, top_left: Point, size: Size, color: C) -> anyhow::Result<(), <Framebuffer<C, C::Raw, BO, WIDTH, HEIGHT, N> as DrawTarget>::Error>;
fn draw_rectangle_center(&mut self, center: Point, size: Size, color: C) -> anyhow::Result<(), <Framebuffer<C, C::Raw, BO, WIDTH, HEIGHT, N> as DrawTarget>::Error>;
fn draw_rounded_rectangle_bounds(&mut self, top_left: Point, bottom_right: Point, color: M::ColorFormat, corner_radii: CornerRadii) -> anyhow::Result<(), DI::Error>;
fn draw_rounded_rectangle_top_left(&mut self, top_left: Point, size: Size, color: M::ColorFormat, corner_radii: CornerRadii) -> anyhow::Result<(), DI::Error>;
fn draw_rounded_rectangle_center(&mut self, center: Point, size: Size, color: M::ColorFormat, corner_radii: CornerRadii) -> anyhow::Result<(), DI::Error>;
fn draw_rounded_rectangle_bounds(&mut self, top_left: Point, bottom_right: Point, color: C, corner_radii: CornerRadii) -> anyhow::Result<(), <Framebuffer<C, C::Raw, BO, WIDTH, HEIGHT, N> as DrawTarget>::Error>;
fn draw_rounded_rectangle_top_left(&mut self, top_left: Point, size: Size, color: C, corner_radii: CornerRadii) -> anyhow::Result<(), <Framebuffer<C, C::Raw, BO, WIDTH, HEIGHT, N> as DrawTarget>::Error>;
fn draw_rounded_rectangle_center(&mut self, center: Point, size: Size, color: C, corner_radii: CornerRadii) -> anyhow::Result<(), <Framebuffer<C, C::Raw, BO, WIDTH, HEIGHT, N> as DrawTarget>::Error>;
fn draw_text_centered(&mut self, center: Point, text: &str) -> anyhow::Result<(), DI::Error>;
fn draw_text_centered(&mut self, center: Point, text: &str) -> anyhow::Result<(), <Framebuffer<C, C::Raw, BO, WIDTH, HEIGHT, N> as DrawTarget>::Error>;
}
impl<DI, M, RST> DrawTools<DI, M, RST> for Display<DI, M, RST>
impl<C, BO, const WIDTH: usize, const HEIGHT: usize, const N: usize> DrawTools<C, BO, WIDTH, HEIGHT, N> for Framebuffer<C, C::Raw, BO, WIDTH, HEIGHT, N>
where
DI: mipidsi::interface::Interface,
M: mipidsi::models::Model<ColorFormat = Rgb565>,
M::ColorFormat: InterfacePixelFormat<DI::Word>,
RST: OutputPin,
C: RgbColor + From<Rgb565> + Into<C> + Copy,
Framebuffer<C, <C as PixelColor>::Raw, BO, WIDTH, HEIGHT, N>: DrawTarget<Color = C>,
{
fn draw_rectangle_bounds(&mut self, top_left: Point, bottom_right: Point, color: M::ColorFormat) -> anyhow::Result<(), DI::Error> {
fn draw_rectangle_bounds(&mut self, top_left: Point, bottom_right: Point, color: C) -> anyhow::Result<(), <Framebuffer<C, C::Raw, BO, WIDTH, HEIGHT, N> as DrawTarget>::Error> {
self.draw_rectangle_top_left(top_left, Size::new((bottom_right.x - top_left.x) as u32, (bottom_right.y - top_left.y) as u32), color)
}
fn draw_rectangle_top_left(&mut self, top_left: Point, size: Size, color: M::ColorFormat) -> anyhow::Result<(), DI::Error> {
fn draw_rectangle_top_left(&mut self, top_left: Point, size: Size, color: C) -> anyhow::Result<(), <Framebuffer<C, C::Raw, BO, WIDTH, HEIGHT, N> as DrawTarget>::Error> {
self.fill_solid(&Rectangle::new(top_left, size), color)
}
fn draw_rectangle_center(&mut self, center: Point, size: Size, color: M::ColorFormat) -> anyhow::Result<(), DI::Error> {
fn draw_rectangle_center(&mut self, center: Point, size: Size, color: C) -> anyhow::Result<(), <Framebuffer<C, C::Raw, BO, WIDTH, HEIGHT, N> as DrawTarget>::Error> {
self.draw_rectangle_top_left(center - Point::new((size.width / 2) as i32, (size.height / 2) as i32), size, color)
}
fn draw_rounded_rectangle_bounds(&mut self, top_left: Point, bottom_right: Point, color: M::ColorFormat, corner_radii: CornerRadii) -> anyhow::Result<(), DI::Error> {
fn draw_rounded_rectangle_bounds(&mut self, top_left: Point, bottom_right: Point, color: C, corner_radii: CornerRadii) -> anyhow::Result<(), <Framebuffer<C, C::Raw, BO, WIDTH, HEIGHT, N> as DrawTarget>::Error> {
self.draw_rounded_rectangle_top_left(top_left, Size::new((bottom_right.x - top_left.x) as u32, (bottom_right.y - top_left.y) as u32), color, corner_radii)
}
fn draw_rounded_rectangle_top_left(&mut self, top_left: Point, size: Size, color: M::ColorFormat, corner_radii: CornerRadii) -> anyhow::Result<(), DI::Error> {
fn draw_rounded_rectangle_top_left(&mut self, top_left: Point, size: Size, color: C, corner_radii: CornerRadii) -> anyhow::Result<(), <Framebuffer<C, C::Raw, BO, WIDTH, HEIGHT, N> as DrawTarget>::Error> {
let rectangle = Rectangle::new(top_left, size);
let rounded_rectangle = RoundedRectangle::new(rectangle, corner_radii);
rounded_rectangle.draw_styled(&PrimitiveStyle::with_fill(color), self)
}
fn draw_rounded_rectangle_center(&mut self, center: Point, size: Size, color: M::ColorFormat, corner_radii: CornerRadii) -> anyhow::Result<(), DI::Error> {
fn draw_rounded_rectangle_center(&mut self, center: Point, size: Size, color: C, corner_radii: CornerRadii) -> anyhow::Result<(), <Framebuffer<C, C::Raw, BO, WIDTH, HEIGHT, N> as DrawTarget>::Error> {
self.draw_rounded_rectangle_top_left(center - Point::new((size.width / 2) as i32, (size.height / 2) as i32), size, color, corner_radii)
}
fn draw_text_centered(&mut self, center: Point, text: &str) -> anyhow::Result<(), DI::Error> {
Text::new(text, center - Point::new((text.len()*5) as i32, -10), TEXT_STYLE).draw(self)?;
fn draw_text_centered(&mut self, center: Point, text: &str) -> anyhow::Result<(), <Framebuffer<C, C::Raw, BO, WIDTH, HEIGHT, N> as DrawTarget>::Error> {
let text_style: MonoTextStyle<C> = MonoTextStyle::new(&embedded_graphics::mono_font::ascii::FONT_10X20, MACCHIATO.text.into());
Text::new(text, center - Point::new((text.len()*5) as i32, -10), text_style).draw(self)?;
Ok(())
}
}
static TEXT_STYLE: MonoTextStyle<Rgb565> = MonoTextStyle::new(&embedded_graphics::mono_font::ascii::FONT_10X20, MACCHIATO.text);
}

View File

@ -1,32 +1,71 @@
///#region Imports
mod display;
use std::{
thread,
time::Duration
};
use embedded_graphics::{
framebuffer::{
buffer_size,
Framebuffer
},
pixelcolor::{
PixelColor,
Rgb565
}
};
use embedded_graphics::draw_target::DrawTarget;
use embedded_graphics::image::ImageDrawable;
use embedded_graphics::pixelcolor::raw::BigEndian;
use embedded_graphics::pixelcolor::RgbColor;
use esp_idf_svc::hal::{
delay::Ets,
gpio::{Gpio16, Gpio18, Gpio19, Gpio20, Gpio23, Gpio4, Gpio5, PinDriver},
gpio::{Gpio16, Gpio18, Gpio19, Gpio20, Gpio21, Gpio23, Gpio4, Gpio5, PinDriver},
peripherals::Peripherals,
spi::{config, SpiDeviceDriver, SpiDriverConfig},
spi::{
config,
SpiDeviceDriver,
SpiDriverConfig},
spi::config::MODE_3,
units::*
};
use mipidsi::{Builder, interface::SpiInterface, models::{ST7789}, options::{ColorInversion, Orientation}};
use mipidsi::options::{ColorOrder, Rotation};
use crate::display::screens::base::DisplayScreen;
use crate::display::screens::error::ErrorScreen;
use crate::display::screens::home::StandardScreen;
use crate::display::screens::success::SuccessScreen;
use mipidsi::{Builder, interface::SpiInterface, models::ST7789, options::{
Orientation,
ColorOrder,
Rotation,
ColorInversion
}};
use crate::display::screens::{
base::DisplayScreen,
error::ErrorScreen,
home::StandardScreen,
success::SuccessScreen
};
///#endregion
///#region Constants
// Display
const H: i32 = 135;
const H: usize = 135;
const H_I: i32 = 135;
const X_OFF: i32 = 52;
const W: i32 = 240;
const W: usize = 240;
const W_I: i32 = 240;
const Y_OFF: i32 = 40;
const FRAMERATE: usize = 30;
static mut BUFFER: [u8; (H * W) as usize] = [0u8; (H * W) as usize];
type ScreenHolder<C: RgbColor, BO, const W: usize, const H: usize, const N: usize, const X: usize> = [fn(index: &mut usize, frame_counter: &mut usize, dirty: &mut bool, display: &mut Framebuffer<C, C::Raw, BO, W, H, N>) -> anyhow::Result<(), <Framebuffer<C, C::Raw, BO, W, H, N> as DrawTarget>::Error>; X];
const SCREENS: ScreenHolder<Rgb565, BigEndian, W, H, {buffer_size::<Rgb565>(W, H)}, 3> = [
SuccessScreen::show,
StandardScreen::show,
ErrorScreen::show
];
static mut DISPLAYBUFFER: [u8; W*H] = [0; W*H];
static mut FRAMEBUFFER: Framebuffer<Rgb565, <Rgb565 as PixelColor>::Raw, BigEndian, {W}, {H}, { buffer_size::<Rgb565>(W, H) }> = Framebuffer::new();
//#endregion
fn main() -> anyhow::Result<()> {
let peripherals: Peripherals = Peripherals::take()?;
@ -35,16 +74,12 @@ fn main() -> anyhow::Result<()> {
let pin_bl: Gpio4 = peripherals.pins.gpio4;
let pin_sclk: Gpio18 = peripherals.pins.gpio18;
let pin_mosi: Gpio19 = peripherals.pins.gpio19;
#[cfg(debug_assertions)]
let pin_miso: Gpio21 = peripherals.pins.gpio21;
#[cfg(not(debug_assertions))]
let pin_miso: Gpio20 = peripherals.pins.gpio20;
let pin_cs: Gpio5 = peripherals.pins.gpio5;
let screens: Vec<fn(&mut usize, &mut usize, &mut bool, &mut mipidsi::Display<_, _, _>) -> anyhow::Result<(), _>> = vec!(
StandardScreen::show,
ErrorScreen::show,
SuccessScreen::show,
);
unsafe {
esp_idf_svc::sys::link_patches();
esp_idf_svc::log::EspLogger::initialize_default();
@ -72,8 +107,21 @@ fn main() -> anyhow::Result<()> {
)?;
// display interface abstraction from SPI and DC
let di = SpiInterface::new(device, PinDriver::output(pin_dc)?, &mut *&raw mut BUFFER);
let di = SpiInterface::new(device, PinDriver::output(pin_dc)?, &mut *&raw mut DISPLAYBUFFER);
#[cfg(debug_assertions)]
// create driver
let mut display = Builder::new(ST7789, di)
.display_size(H as u16, W as u16)
.orientation(Orientation::new().flip_horizontal().rotate(Rotation::Deg90))
.reset_pin(PinDriver::output(pin_rst)?)
.color_order(ColorOrder::Bgr)
.display_offset(X_OFF as u16, Y_OFF as u16)
.init(&mut delay)
.unwrap();
#[cfg(not(debug_assertions))]
// create driver
let mut display = Builder::new(ST7789, di)
.display_size(H as u16, W as u16)
@ -85,25 +133,25 @@ fn main() -> anyhow::Result<()> {
.init(&mut delay)
.unwrap();
// turn on the backlight
backlight.set_high()?;
let mut screen_index = 0;
let mut frame_counter = 0;
let mut dirty = true;
let mut screen_index: usize = 0;
let mut frame_counter: usize = 0;
let mut dirty: bool = true;
loop {
screens[screen_index](&mut screen_index, &mut frame_counter, &mut dirty, &mut display).unwrap();
SCREENS[screen_index](&mut screen_index, &mut frame_counter, &mut dirty, &mut FRAMEBUFFER)?;
if screen_index == screens.len() {
if screen_index == SCREENS.len() {
screen_index = 0;
} else if screen_index >= screens.len() + 1 {
screen_index = screens.len() - 1;
} else if screen_index >= SCREENS.len() + 1 {
screen_index = SCREENS.len() - 1;
}
#[cfg(debug_assertions)]
println!("Sleeping for {}", 1000/FRAMERATE);
FRAMEBUFFER.as_image().draw(&mut display).unwrap();
thread::sleep(Duration::from_millis((1000 / FRAMERATE) as u64));
frame_counter += 1;
}