#![cfg_attr(not(feature = "simulator"), no_std)] #![cfg_attr(not(feature = "simulator"), no_main)] mod apps; mod config; mod display; mod energy; mod fs; mod gui; mod keypad; mod state; mod strf; mod time; use apps::App; use display::Display; use energy::EnergyStatus; use keypad::KeyEvents; 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 maduino_zero_4g::{ self as bsp, hal::{ clock::GenericClockController, delay::Delay, pac::{CorePeripherals, Peripherals}, prelude::*, }, }; #[cfg(not(feature = "simulator"))] use panic_halt as _; use tz::DateTime; #[cfg_attr(not(feature = "simulator"), bsp::entry)] fn main() -> ! { cfg_if::cfg_if! { if #[cfg(not(feature = "simulator"))] { let mut peripherals = Peripherals::take().unwrap(); let mut pins = maduino_zero_4g::Pins::new(peripherals.PORT); let core = CorePeripherals::take().unwrap(); let mut clocks = GenericClockController::with_external_32kosc( peripherals.GCLK, &mut peripherals.PM, &mut peripherals.SYSCTRL, &mut peripherals.NVMCTRL, ); let mut delay = Delay::new(core.SYST, &mut clocks); let mut fs = fs::Fs::new(atsamd_hal::sercom::spi::Config::new( &peripherals.PM, peripherals.SERCOM4, atsamd_hal::sercom::spi::Pads::default().data_in(pins.sd_miso).data_out(pins.sd_mosi).sclk(pins.sd_sck), 10_u32.mhz(), ).enable(), pins.d4.into_push_pull_output()); } } let mut state = State { energy: EnergyStatus { battery: 255, charging: false, }, hour: 0, minute: 0, }; let mut mode_state = ModeState::Clock(Default::default()); let mut 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(); 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 ctx = Context { display: &mut display, hm_change: true, key_events: Default::default(), now: DateTime::from_timespec(0, 0, tz::TimeZoneRef::utc()).unwrap(), update: true, state: &mut state, }; loop { let energy_status = energy::get_energy_status(); if energy_status != ctx.state.energy { ctx.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(ctx.display.inner_mut()) .unwrap(); ctx.state.energy = energy_status; } ctx.now = time::now(); let hour = ctx.now.hour(); let minute = ctx.now.minute(); if (hour, minute) != (ctx.state.hour, ctx.state.minute) { ctx.update = true; ctx.hm_change = true; ctx.state.hour = hour; ctx.state.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(ctx.display.inner_mut()) .unwrap(); } ctx.key_events = keypad.update(); if let Some(new_mode_state) = match &mut mode_state { ModeState::Clock(clock_state) => apps::clock::Clock::update(&mut ctx, clock_state), ModeState::Dial(dial_state) => apps::dial::Dial::update(&mut ctx, dial_state), } { mode_state = new_mode_state; } #[cfg(feature = "simulator")] { ctx.display.update(); std::thread::sleep(core::time::Duration::from_millis(50)); } #[cfg(not(feature = "simulator"))] if ctx.update { ctx.display.update(); } #[cfg(not(feature = "simulator"))] delay.delay_ms(50_u8); ctx.update = false; ctx.hm_change = false; } } pub struct Context<'a> { pub state: &'a mut State, pub display: &'a mut Display, pub hm_change: bool, pub now: DateTime, pub update: bool, pub key_events: KeyEvents, }