Add State-system

This commit is contained in:
Sofia 2026-05-16 22:03:34 +03:00
parent d03b00e3f0
commit 3546cf62c6
4 changed files with 152 additions and 20 deletions

View File

@ -3,7 +3,7 @@ use core::ops::{Add, Mul};
use embedded_hal::{delay::DelayNs, spi::SpiBus}; use embedded_hal::{delay::DelayNs, spi::SpiBus};
use esp_hal::{DriverMode, gpio::Output, spi::master::Spi}; use esp_hal::{DriverMode, gpio::Output, spi::master::Spi};
#[derive(Clone, Copy)] #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct Rgb565(pub u8, pub u8, pub u8); pub struct Rgb565(pub u8, pub u8, pub u8);
impl Rgb565 { impl Rgb565 {
@ -72,7 +72,7 @@ impl Add<Rgb565> for Rgb565 {
} }
} }
#[derive(Default, Clone, Copy, Debug)] #[derive(Default, Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct Position { pub struct Position {
pub x: i16, pub x: i16,
pub y: i16, pub y: i16,
@ -84,7 +84,7 @@ impl Position {
} }
} }
#[derive(Default, Clone, Copy)] #[derive(Default, Clone, Copy, PartialEq, Eq)]
pub struct Color { pub struct Color {
pub bytes: [u8; 2], pub bytes: [u8; 2],
} }
@ -371,4 +371,8 @@ impl<'d, DM: DriverMode, T: DelayNs> Display<'d, DM, T> {
self.write(Writeable::Data(&color.bytes)); self.write(Writeable::Data(&color.bytes));
} }
} }
pub fn clear(&mut self, color: Color) {
self.draw_rect(Position::new(0, 0), Position::new(240, 240), color);
}
} }

View File

@ -10,12 +10,14 @@ use crate::display::{self, Color, Display, Position, Rgb565};
static OPEN_SANS: &'static [u8] = include_bytes!("./OpenSans_Condensed-Regular.ttf"); static OPEN_SANS: &'static [u8] = include_bytes!("./OpenSans_Condensed-Regular.ttf");
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
pub enum HorizontalAlignment { pub enum HorizontalAlignment {
RightToLeft, RightToLeft,
Center, Center,
LeftToRight, LeftToRight,
} }
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
pub enum VerticalAlignment { pub enum VerticalAlignment {
TopToBottom, TopToBottom,
Center, Center,

View File

@ -9,7 +9,7 @@
use core::fmt::Write; use core::fmt::Write;
use alloc::{borrow::ToOwned, str}; use alloc::{borrow::ToOwned, boxed::Box, str};
use embedded_hal::delay::DelayNs; use embedded_hal::delay::DelayNs;
use esp_alloc::export::enumset::EnumSet; use esp_alloc::export::enumset::EnumSet;
use esp_hal::{ use esp_hal::{
@ -28,6 +28,7 @@ use crate::{
at_commands::ATCommands, at_commands::ATCommands,
display::{Display, Position, Rgb565, SetAddressMode}, display::{Display, Position, Rgb565, SetAddressMode},
font::{FontRenderer, HorizontalAlignment, VerticalAlignment}, font::{FontRenderer, HorizontalAlignment, VerticalAlignment},
state::{HelloState, StateManager},
}; };
extern crate alloc; extern crate alloc;
@ -35,6 +36,7 @@ extern crate alloc;
mod at_commands; mod at_commands;
mod display; mod display;
mod font; mod font;
mod state;
// This creates a default app-descriptor required by the esp-idf bootloader. // This creates a default app-descriptor required by the esp-idf bootloader.
// For more information see: <https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/system/app_image_format.html#application-description> // For more information see: <https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/system/app_image_format.html#application-description>
@ -156,13 +158,18 @@ fn main() -> ! {
); );
}; };
at_commands.init(); // at_commands.init();
render_response(at_commands.raw_command("ATI".to_owned())); // render_response(at_commands.raw_command("ATI".to_owned()));
render_response(at_commands.raw_command("AT+CMGF?".to_owned())); // render_response(at_commands.raw_command("AT+CMGF?".to_owned()));
render_response(at_commands.raw_command("AT+CPIN=1234".to_owned())); // render_response(at_commands.raw_command("AT+CPIN=1234".to_owned()));
render_response(at_commands.raw_command("AT+CPIN?".to_owned())); // render_response(at_commands.raw_command("AT+CPIN?".to_owned()));
render_response(at_commands.raw_command("AT+CMGF=1".to_owned())); // render_response(at_commands.raw_command("AT+CMGF=1".to_owned()));
render_response(at_commands.raw_command("AT+CSCS=?".to_owned())); // render_response(at_commands.raw_command("AT+CSCS=?".to_owned()));
let mut state_mgr = StateManager {
data: state::StateData::from(display, at_commands),
curr_state: Box::new(HelloState),
};
// render_response( // render_response(
// at_commands.raw_two_part_command("AT+CMGS=\"number\"".to_owned(), "hello".to_owned()), // at_commands.raw_two_part_command("AT+CMGS=\"number\"".to_owned(), "hello".to_owned()),
// ); // );
@ -187,15 +194,8 @@ fn main() -> ! {
let mut test_delay = Delay::new(); let mut test_delay = Delay::new();
loop { loop {
// log::info!("Input 1: {}", input_1.is_high()); state_mgr.update();
// log::info!("Input 2: {}", input_2.is_high()); state_mgr.draw();
// log::info!("Input 3: {}", input_3.is_high());
// log::info!("Input 4: {}", input_4.is_high());
// log::info!("Input 5: {}", input_5.is_high());
// log::info!("Input 6: {}", input_6.is_high());
// log::info!("Input 7: {}", input_7.is_high());
// input_7.toggle();
test_delay.delay_millis(100);
} }
// for inspiration have a look at the examples at https://github.com/esp-rs/esp-hal/tree/esp-hal-v1.1.0/examples // for inspiration have a look at the examples at https://github.com/esp-rs/esp-hal/tree/esp-hal-v1.1.0/examples

126
src/state.rs Normal file
View File

@ -0,0 +1,126 @@
use alloc::{boxed::Box, string::String, vec::Vec};
use esp_hal::{Blocking, delay::Delay};
use crate::{
at_commands::ATCommands,
display::{Color, Display, Position, Rgb565},
font::{FontRenderer, HorizontalAlignment, VerticalAlignment},
};
#[derive(PartialEq, Eq, Clone)]
pub struct TextSettings {
h_align: HorizontalAlignment,
v_align: VerticalAlignment,
fg: Rgb565,
bg: Rgb565,
}
impl Default for TextSettings {
fn default() -> Self {
Self {
h_align: HorizontalAlignment::LeftToRight,
v_align: VerticalAlignment::TopToBottom,
fg: Rgb565::white(),
bg: Rgb565::black(),
}
}
}
#[derive(PartialEq, Eq, Clone)]
pub enum DrawCommands {
Clear(Color),
DrawText(String, Position, TextSettings),
}
pub struct StateData<'a> {
display: Display<'a, Blocking, Delay>,
at_commands: ATCommands<'a, 'a>,
font_renderer: FontRenderer<'a>,
pub delay: Delay,
prev_commands: Vec<DrawCommands>,
commands: Vec<DrawCommands>,
}
impl<'a> StateData<'a> {
pub fn from(
display: Display<'a, Blocking, Delay>,
at_commands: ATCommands<'a, 'a>,
) -> StateData<'a> {
StateData {
display,
at_commands,
font_renderer: FontRenderer::create(30),
delay: Delay::new(),
prev_commands: Vec::new(),
commands: Vec::new(),
}
}
pub fn clear_screen(&mut self, color: Color) {
self.commands.push(DrawCommands::Clear(color));
}
pub fn draw_text<T: Into<String>>(&mut self, text: T, pos: Position, settings: TextSettings) {
self.commands
.push(DrawCommands::DrawText(text.into(), pos, settings));
}
}
pub trait State {
fn update(&self, data: &mut StateData) -> Option<Box<dyn State>>;
fn draw(&self, data: &mut StateData);
}
pub struct StateManager<'a> {
pub data: StateData<'a>,
pub curr_state: Box<dyn State>,
}
impl<'a> StateManager<'a> {
pub fn update(&mut self) {
match self.curr_state.update(&mut self.data) {
Some(next_state) => self.curr_state = next_state,
None => {}
}
}
pub fn draw(&mut self) {
self.data.commands.clear();
self.curr_state.draw(&mut self.data);
if self.data.commands != self.data.prev_commands {
self.data.prev_commands = self.data.commands.clone();
for command in &self.data.commands {
match command {
DrawCommands::Clear(color) => self.data.display.clear(*color),
DrawCommands::DrawText(text, position, text_settings) => {
self.data.font_renderer.render(
&mut self.data.display,
text,
*position,
text_settings.h_align,
text_settings.v_align,
text_settings.bg,
text_settings.fg,
)
}
}
}
}
}
}
pub struct HelloState;
impl State for HelloState {
fn update(&self, data: &mut StateData) -> Option<Box<dyn State>> {
data.delay.delay_millis(100);
None
}
fn draw(&self, data: &mut StateData) {
data.clear_screen(Rgb565::black().as_color());
data.draw_text("Hello World", Position::new(0, 0), TextSettings::default());
}
}