#![cfg_attr(not(feature = "simulator"), no_std)] #![cfg_attr(not(feature = "simulator"), no_main)] mod apps; mod config; mod display; mod energy; mod gui; mod keypad; mod state; mod strf; mod time; use energy::EnergyStatus; use state::*; use arrayvec::ArrayString; use core::fmt::Write; use embedded_graphics::{ mono_font::{ascii::FONT_10X20, ascii::FONT_6X10, ascii::FONT_9X15, MonoTextStyleBuilder}, pixelcolor::BinaryColor, prelude::*, primitives::{Line, PrimitiveStyle, PrimitiveStyleBuilder, Rectangle, StrokeAlignment}, text::{Alignment, Text}, }; #[cfg(not(feature = "simulator"))] use panic_halt as _; static mut STATE: State = State { energy: EnergyStatus { battery: 255, charging: false, }, hour: 0, minute: 0, mode: Mode::Clock { year: 0, month: 0, day: 0, week_day: 0, }, }; fn state() -> &'static State { unsafe { &STATE } } fn state_mut() -> &'static mut State { unsafe { &mut STATE } } #[cfg_attr(not(feature = "simulator"), cortex_m_rt::entry)] fn main() -> ! { let mut display = display::Display::new(); let mut keypad = keypad::Keypad::default(); let thin_stroke = PrimitiveStyle::with_stroke(BinaryColor::On, 1); let thick_stroke = PrimitiveStyle::with_stroke(BinaryColor::On, 3); let fill = PrimitiveStyle::with_fill(BinaryColor::On); let statusbar_text_style = MonoTextStyleBuilder::new() .font(&FONT_9X15) .text_color(BinaryColor::On) .background_color(BinaryColor::Off) .build(); let clock_text_style = MonoTextStyleBuilder::new() .font(&FONT_10X20) .text_color(BinaryColor::On) .background_color(BinaryColor::Off) .build(); Line::new(Point::new(0, 13), Point::new(199, 13)) .into_styled(thin_stroke) .draw(display.inner_mut()) .unwrap(); #[cfg(feature = "simulator")] display.update(); let mut update = true; let mut hm_change = true; loop { let energy_status = energy::get_energy_status(); if energy_status != state().energy { update = true; Text::with_alignment( unsafe { core::str::from_utf8_unchecked(&strf::fmt_energy(&energy_status)) }, Point::new(0, 9), statusbar_text_style, Alignment::Left, ) .draw(display.inner_mut()) .unwrap(); state_mut().energy = energy_status; } let now = time::now(); let hour = now.hour(); let minute = now.minute(); if (hour, minute) != (state().hour, state().minute) { update = true; hm_change = true; state_mut().hour = hour; state_mut().minute = minute; Text::with_alignment( unsafe { core::str::from_utf8_unchecked(&strf::fmt_time_hm(hour, minute)) }, Point::new(199, 9), statusbar_text_style, Alignment::Right, ) .draw(display.inner_mut()) .unwrap(); } let key_events = keypad.update(); match &mut state_mut().mode { Mode::Clock { year, month, day, week_day, } => { if hm_change { Text::with_alignment( unsafe { core::str::from_utf8_unchecked(&strf::fmt_time_hm(hour, minute)) }, display.inner().bounding_box().center() + Point::new(0, 10), clock_text_style, Alignment::Center, ) .draw(display.inner_mut()) .unwrap(); let year_ = now.year(); let month_ = now.month(); let day_ = now.month_day(); let week_day_ = now.week_day(); if (year_, month_, day_, week_day_) != (*year, *month, *day, *week_day) { *year = year_; *month = month_; *day = day_; *week_day = week_day_; Text::with_alignment( unsafe { core::str::from_utf8_unchecked(&strf::fmt_time_ymdw( year_, month_, day_, week_day_, )) }, display.inner().bounding_box().center() + Point::new(0, -20), clock_text_style, Alignment::Center, ) .draw(display.inner_mut()) .unwrap(); } } } } #[cfg(feature = "simulator")] { display.update(); std::thread::sleep(core::time::Duration::from_millis(50)); } #[cfg(not(feature = "simulator"))] if update { display.update(); } // TODO sleep on samd update = false; hm_change = false; } }