From a77f5bba05e9087ced71d64015cffeaae1e73372 Mon Sep 17 00:00:00 2001 From: Levi Pearson Date: Tue, 1 Mar 2022 13:32:39 -0700 Subject: [PATCH] Break out UI code to a separate module --- src/hello_screen.rs | 99 +++++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 70 ++++++++++---------------------- 2 files changed, 121 insertions(+), 48 deletions(-) create mode 100644 src/hello_screen.rs diff --git a/src/hello_screen.rs b/src/hello_screen.rs new file mode 100644 index 0000000..9b137f5 --- /dev/null +++ b/src/hello_screen.rs @@ -0,0 +1,99 @@ +use arrayvec::ArrayString; + +use embedded_graphics::{ + draw_target::DrawTarget, + mono_font::{ascii::FONT_6X9, MonoTextStyle, MonoTextStyleBuilder}, + pixelcolor::BinaryColor, + prelude::*, + primitives::{Circle, PrimitiveStyle}, + text::{Baseline, Text}, +}; + +use core::fmt::Write; + +#[derive(Copy, Clone)] +pub enum HelloEvent { + Tick, + Knob(i32), + Button, +} + +#[derive(Clone)] +pub struct HelloDisplay { + circle_pos: (i32, i32), + counter: i32, + textbuf: ArrayString<15>, + text_style: MonoTextStyle<'static, BinaryColor>, + title: Text<'static, MonoTextStyle<'static, BinaryColor>>, +} + +impl HelloDisplay { + const C_RADIUS: i32 = 8; + + /// Construct a new HelloDisplay + pub fn new() -> Self { + let text_style = MonoTextStyleBuilder::new() + .font(&FONT_6X9) + .text_color(BinaryColor::On) + .build(); + let title = + Text::with_baseline("Hello Rust!", Point::new(20, 16), text_style, Baseline::Top); + Self { + circle_pos: (0, 0), + counter: 0, + textbuf: ArrayString::new(), + text_style, + title, + } + } + + /// Draw the current state of HelloDisplay onto the DrawTarget + pub fn draw(&mut self, target: &mut D) -> Result<(), D::Error> + where + D: DrawTarget, + { + let (cx, cy) = self.circle_pos; + let circle = Circle::new(Point::new(cx, cy), Self::C_RADIUS as u32) + .into_styled(PrimitiveStyle::with_fill(BinaryColor::On)); + + self.textbuf.clear(); + write!(&mut self.textbuf, "count: {}", self.counter).unwrap(); + let count = Text::with_baseline( + &self.textbuf, + Point::new(20, 36), + self.text_style, + Baseline::Top, + ); + + target.clear(BinaryColor::Off)?; + + self.title.draw(target)?; + circle.draw(target)?; + count.draw(target)?; + + Ok(()) + } + + /// Update the current state of HelloDisplay based on an event + pub fn event(&mut self, event: HelloEvent) { + match event { + HelloEvent::Tick => { + let (_, cy) = self.circle_pos; + let cx_next = self + .counter + .max(Self::C_RADIUS / 2) + .min(W - Self::C_RADIUS / 2); + let mut cy_next = cy + 1; + if cy_next > (H + Self::C_RADIUS) { + cy_next = -Self::C_RADIUS + }; + + self.circle_pos = (cx_next, cy_next); + } + HelloEvent::Knob(pos_delta) => { + self.counter = self.counter + pos_delta; + } + HelloEvent::Button => {} + } + } +} diff --git a/src/main.rs b/src/main.rs index f074351..626d70b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,8 +1,6 @@ #![no_std] #![cfg_attr(not(doc), no_main)] -use core::{cell::RefCell, fmt::Write}; - use panic_rtt_target as _; use rtt_target::{rprintln, rtt_init_print}; @@ -27,19 +25,14 @@ use switch_hal::{InputSwitch, IntoSwitch, OutputSwitch, ToggleableOutputSwitch}; use ssd1306::{prelude::*, I2CDisplayInterface, Ssd1306}; -use embedded_graphics::{ - mono_font::{ascii::FONT_6X9, MonoTextStyleBuilder}, - pixelcolor::BinaryColor, - prelude::*, - primitives::{Circle, PrimitiveStyle}, - text::{Baseline, Text}, -}; - -use arrayvec::ArrayString; +use core::cell::RefCell; mod rotary; use rotary::{Direction, Rotary}; +mod hello_screen; +use hello_screen::{HelloEvent, HelloDisplay}; + type ClkPin = PA8>; type DtPin = PA9>; @@ -47,6 +40,9 @@ static CLK_PIN: Mutex>> = Mutex::new(RefCell::new(None)); static DT_PIN: Mutex>> = Mutex::new(RefCell::new(None)); static COUNT: Mutex> = Mutex::new(RefCell::new(0)); +const DISPLAY_W: i32 = 128; +const DISPLAY_H: i32 = 64; + #[entry] fn main() -> ! { // Init buffers for debug printing @@ -141,58 +137,36 @@ fn main() -> ! { } NVIC::unpend(Interrupt::EXTI9_5); - // We will draw a fixed message on the screen and also a moving circle + rprintln!("Finished init, starting main loop"); - const C_RADIUS: i32 = 8; - const DISPLAY_W: i32 = 128; - const DISPLAY_H: i32 = 64; - - let mut cx = 20; - let mut cy = 20; - - let text_style = MonoTextStyleBuilder::new() - .font(&FONT_6X9) - .text_color(BinaryColor::On) - .build(); - let t = Text::with_baseline("Hello Rust!", Point::new(20, 16), text_style, Baseline::Top); + // Create the hello UI + let mut hello: HelloDisplay = HelloDisplay::new(); // Turn the LED on via the OutputPin trait led.on().unwrap(); - rprintln!("Finished init, starting main loop"); - let mut button_last = false; + let mut counter_last = 0; // Microcontroller programs never exit main, so we must loop! loop { + hello.draw(&mut display).unwrap(); + display.flush().unwrap(); + + hello.event(HelloEvent::Tick); + // Check our inputs let button = sw.is_active().unwrap(); - let counter = cortex_m::interrupt::free(|cs| *COUNT.borrow(cs).borrow()); if button_last && !button { led.toggle().unwrap(); + hello.event(HelloEvent::Button); } button_last = button; - let c = Circle::new(Point::new(cx, cy), C_RADIUS as u32) - .into_styled(PrimitiveStyle::with_fill(BinaryColor::On)); - - // Show the position of the knob and thus the ball - let mut textbuf = ArrayString::<15>::new(); - write!(&mut textbuf, "count: {}", counter).unwrap(); - let count = Text::with_baseline(&textbuf, Point::new(20, 36), text_style, Baseline::Top); - - display.clear(); - c.draw(&mut display).unwrap(); - t.draw(&mut display).unwrap(); - count.draw(&mut display).unwrap(); - display.flush().unwrap(); - - // Control the horizontal position with the knob - cx = counter.max(C_RADIUS / 2).min(DISPLAY_W - C_RADIUS / 2); - // Wrap the ball back to the top when it falls off the bottom - cy += 1; - if cy > (DISPLAY_H + C_RADIUS) { - cy = -C_RADIUS - }; + let counter = cortex_m::interrupt::free(|cs| *COUNT.borrow(cs).borrow()); + if counter_last != counter { + hello.event(HelloEvent::Knob(counter - counter_last)); + } + counter_last = counter; } }