use core::iter::repeat; use alloc::{borrow::ToOwned, boxed::Box, format, string::String}; use esp_hal::time::{Duration, Instant}; use crate::{ async_io::ATPromise, at_commands::{ ATCommand, ATInformationCommand, CheckPinCommand, EnterPinCommand, SMSFormat, SelectSMSFormatCommand, SetTECharsetCommand, TECharset, }, display::{Position, Rgb565}, font::{HorizontalAlignment, VerticalAlignment}, state::{State, StateData, TextSettings}, }; #[derive(Clone)] pub struct ATCommandState { message: String, command: Cmd, dots: u8, prev_dots: Instant, promise: Option>, after_state: T, } impl ATCommandState { pub fn with(message: String, command: Cmd, after: T) -> ATCommandState { ATCommandState { message, command, dots: 0, prev_dots: Instant::now(), promise: None, after_state: after, } } } impl State for ATCommandState { fn init(&mut self, data: &mut StateData) { self.promise = Some(data.io.send_at_command(self.command.clone()).unwrap()); } fn update(&mut self, data: &mut StateData) -> Option> { // Update dots if self.prev_dots.elapsed() > Duration::from_millis(200) { self.dots = (self.dots + 1) % 3; self.prev_dots = Instant::now(); } if let Some(promise) = &self.promise { match promise.poll(&mut data.io) { Some(response) => match response { Some(response) => { log::info!("Response: {:?}", response); self.promise = None; } None => {} }, None => self.promise = None, } return None; } return Some(Box::new(self.after_state.clone())); } fn draw(&self, data: &mut StateData) { data.clear_screen(Rgb565::black().as_color()); let dots = repeat(".").take(self.dots as usize).collect::(); data.draw_text( format!("{}{}", self.message, dots), Position::new(0, 0), TextSettings::default(), ); } } pub struct InitATState; impl Default for InitATState { fn default() -> Self { Self {} } } impl State for InitATState { fn update(&mut self, _: &mut StateData) -> Option> { let state = ATCommandState::with( "Checking info".to_owned(), ATInformationCommand, ATCommandState::with( "Entering PIN".to_owned(), EnterPinCommand("1234".to_owned()), ATCommandState::with( "Checking PIN".to_owned(), CheckPinCommand, ATCommandState::with( "Selecting SMS\ncharset".to_owned(), SelectSMSFormatCommand(SMSFormat::TextMode), ATCommandState::with( "Setting\nTE charset".to_owned(), SetTECharsetCommand(TECharset::IRA), TextState { text: "All done!".to_owned(), }, ), ), ), ), ); Some(Box::new(state)) } fn draw(&self, _: &mut StateData) {} } #[derive(Clone)] pub struct TextState { text: String, } impl State for TextState { fn update(&mut self, data: &mut StateData) -> Option> { if data.io.button.get_presses() > 0 { Some(Box::new(ButtonTestState { presses: 0 })) } else { None } } fn draw(&self, data: &mut StateData) { data.clear_screen(Rgb565::black().as_color()); data.draw_text(&self.text, Position::new(0, 0), TextSettings::default()); data.draw_text( "OK", Position::new(120, 240), TextSettings { h_align: HorizontalAlignment::Center, v_align: VerticalAlignment::BottomToTop, ..Default::default() }, ); } } pub struct ButtonTestState { presses: u32, } impl State for ButtonTestState { fn update(&mut self, data: &mut StateData) -> Option> { self.presses += data.io.button.get_presses(); None } fn draw(&self, data: &mut StateData) { data.clear_screen(Rgb565::black().as_color()); data.draw_text( format!("Presses: {}", self.presses), Position::new(0, 0), TextSettings::default(), ); } }