From f37b18c20504e9d47a0311f0c7f427973e63610b Mon Sep 17 00:00:00 2001 From: LongHairedHacker Date: Wed, 23 Dec 2020 23:40:32 +0100 Subject: [PATCH] Started to split application into submodules --- src/application.rs | 451 --------------------------- src/application/confirm_profile.rs | 134 ++++++++ src/{ => application}/logo.bmp | Bin src/application/mod.rs | 80 +++++ src/application/profile_selection.rs | 121 +++++++ src/application/run_profile.rs | 83 +++++ src/application/setup.rs | 108 +++++++ src/application/splash.rs | 59 ++++ 8 files changed, 585 insertions(+), 451 deletions(-) delete mode 100644 src/application.rs create mode 100644 src/application/confirm_profile.rs rename src/{ => application}/logo.bmp (100%) create mode 100644 src/application/mod.rs create mode 100644 src/application/profile_selection.rs create mode 100644 src/application/run_profile.rs create mode 100644 src/application/setup.rs create mode 100644 src/application/splash.rs diff --git a/src/application.rs b/src/application.rs deleted file mode 100644 index 4359303..0000000 --- a/src/application.rs +++ /dev/null @@ -1,451 +0,0 @@ -use arrayvec::ArrayString; -use core::fmt::Write; -use cortex_m::asm; -use cortex_m_rt::{entry, exception}; -use embedded_graphics::{ - drawable::Drawable, fonts::Text, image::Image, pixelcolor::BinaryColor, pixelcolor::Rgb565, - prelude::*, primitives::rectangle::Rectangle, primitives::Line, style::PrimitiveStyleBuilder, - style::TextStyleBuilder, -}; - -use embedded_hal::digital::v2::{InputPin, OutputPin}; -use profont::{ProFont12Point, ProFont14Point, ProFont9Point}; -use rtt_target::{rprintln, rtt_init_print}; -use st7735_lcd::Orientation; -use stm32f1xx_hal::{ - delay::Delay, - gpio::{gpioa, gpiob, gpioc, Alternate, Floating, Input, Output, PushPull}, - pac, - prelude::*, - qei, rcc, - spi::{Mode, Phase, Polarity, Spi, Spi1NoRemap}, - stm32, - timer::{Tim3PartialRemap, Timer}, -}; -use tinybmp::Bmp; - -use crate::profiles; - -type AppSPI = Spi< - pac::SPI1, - Spi1NoRemap, - ( - gpioa::PA5>, - gpioa::PA6>, - gpioa::PA7>, - ), ->; - -type AppQEI = qei::Qei< - pac::TIM3, - Tim3PartialRemap, - (gpiob::PB4>, gpiob::PB5>), ->; - -pub struct App { - delay: Delay, - board_led: gpioc::PC13>, - spi: AppSPI, - disp_cs: gpioa::PA0>, - disp_dc: gpioa::PA4>, - disp_rst: gpioa::PA1>, - max_cs: gpioa::PA9>, - qei: AppQEI, - button: gpiob::PB3>, - - selected_profile: usize, -} - -pub fn setup(cp: cortex_m::peripheral::Peripherals, dp: stm32::Peripherals) -> App { - // Take ownership over the raw flash and rcc devices and convert them into the corresponding - // HAL structs - let mut flash = dp.FLASH.constrain(); - - let mut rcc = dp.RCC.constrain(); - - // Freeze the configuration of all the clocks in the system and store the frozen frequencies in - // `clocks` - let clocks = rcc - .cfgr - .use_hse(8.mhz()) - .sysclk(72.mhz()) - .pclk1(36.mhz()) - .freeze(&mut flash.acr); - - // Acquire the GPIOC peripheral - let mut gpioc = dp.GPIOC.split(&mut rcc.apb2); - let mut gpioa = dp.GPIOA.split(&mut rcc.apb2); - - // Configure gpio C pin 13 as a push-pull output. The `crh` register is passed to the function - // in order to configure the port. For pins 0-7, crl should be passed instead. - let led = gpioc.pc13.into_push_pull_output(&mut gpioc.crh); - - let delay = Delay::new(cp.SYST, clocks); - - let gpiob = dp.GPIOB.split(&mut rcc.apb2); - let mut afio = dp.AFIO.constrain(&mut rcc.apb2); - - let (_, pb3, pb4) = afio.mapr.disable_jtag(gpioa.pa15, gpiob.pb3, gpiob.pb4); - - let qei = Timer::tim3(dp.TIM3, &clocks, &mut rcc.apb1).qei( - (pb4, gpiob.pb5), - &mut afio.mapr, - qei::QeiOptions::default(), - ); - let button = pb3; - - // SPI1 - let sck = gpioa.pa5.into_alternate_push_pull(&mut gpioa.crl); - let miso = gpioa.pa6; - let mosi = gpioa.pa7.into_alternate_push_pull(&mut gpioa.crl); - - let disp_cs = gpioa.pa0.into_push_pull_output(&mut gpioa.crl); - let max_cs = gpioa.pa9.into_push_pull_output(&mut gpioa.crh); - - let rst = gpioa.pa1.into_push_pull_output(&mut gpioa.crl); - let dc = gpioa.pa4.into_push_pull_output(&mut gpioa.crl); - let mut disp_led = gpioa.pa8.into_push_pull_output(&mut gpioa.crh); - - disp_led.set_high().unwrap(); - - let spi = Spi::spi1( - dp.SPI1, - (sck, miso, mosi), - &mut afio.mapr, - Mode { - polarity: Polarity::IdleLow, - phase: Phase::CaptureOnFirstTransition, - }, - 16.mhz(), - clocks, - &mut rcc.apb2, - ); - - App { - delay: delay, - board_led: led, - spi: spi, - disp_cs: disp_cs, - disp_dc: dc, - disp_rst: rst, - max_cs: max_cs, - qei: qei, - button: button, - - selected_profile: 0, - } -} - -impl App { - pub fn run(mut self) -> ! { - self = self.splash_screen(); - loop { - self = self.profile_selection(); - let (confirmed, app) = self.confirm_profile(); - self = app; - if !confirmed { - continue; - } - self = self.run_profile(); - } - } - - fn splash_screen(mut self) -> App { - let mut disp = - st7735_lcd::ST7735::new(self.spi, self.disp_dc, self.disp_rst, true, false, 160, 128); - self.disp_cs.set_low().unwrap(); - - disp.init(&mut self.delay).unwrap(); - disp.set_orientation(&Orientation::LandscapeSwapped) - .unwrap(); - - let style_black = PrimitiveStyleBuilder::new() - .fill_color(Rgb565::BLACK) - .build(); - let rect = Rectangle::new(Point::new(0, 0), Point::new(160, 128)).into_styled(style_black); - - rect.draw(&mut disp).unwrap(); - - let bmp = Bmp::from_slice(include_bytes!("logo.bmp")).unwrap(); - let image = Image::new(&bmp, Point::new(16, 0)); - image.draw(&mut disp).unwrap(); - - self.delay.delay_ms(2000u16); - - let (spi, disp_dc, disp_rst) = disp.release(); - self.spi = spi; - self.disp_dc = disp_dc; - self.disp_rst = disp_rst; - - self - } - - fn profile_selection(mut self) -> App { - let mut disp = - st7735_lcd::ST7735::new(self.spi, self.disp_dc, self.disp_rst, true, false, 160, 128); - self.disp_cs.set_low().unwrap(); - - disp.init(&mut self.delay).unwrap(); - disp.set_orientation(&Orientation::LandscapeSwapped) - .unwrap(); - - let style_black = PrimitiveStyleBuilder::new() - .fill_color(Rgb565::BLACK) - .build(); - let rect = Rectangle::new(Point::new(0, 0), Point::new(160, 128)).into_styled(style_black); - - rect.draw(&mut disp).unwrap(); - - let text_lager = TextStyleBuilder::new(ProFont12Point) - .text_color(Rgb565::WHITE) - .build(); - - let profile_box = PrimitiveStyleBuilder::new() - .fill_color(Rgb565::BLACK) - .stroke_color(Rgb565::WHITE) - .stroke_width(1) - .build(); - - let selected_box = PrimitiveStyleBuilder::new() - .fill_color(Rgb565::BLUE) - .stroke_color(Rgb565::WHITE) - .stroke_width(1) - .build(); - - Text::new("Selected a profile", Point::new(4, 4)) - .into_styled(text_lager) - .draw(&mut disp) - .unwrap(); - - let encoder_start = self.qei.count(); - - let mut press_count = 0; - let mut needs_redraw = true; - while press_count < 5 { - if needs_redraw { - for i in 0..profiles::REFLOW_PROFILES.len() { - let style = if i == self.selected_profile { - selected_box - } else { - profile_box - }; - Rectangle::new( - Point::new(0, 20 + (i as i32) * 16), - Point::new(159, 20 + (i as i32) * 16 + 16), - ) - .into_styled(style) - .draw(&mut disp) - .unwrap(); - - Text::new( - profiles::REFLOW_PROFILES[i].get_name(), - Point::new(4, 21 + (i as i32) * 16), - ) - .into_styled(text_lager) - .draw(&mut disp) - .unwrap(); - } - needs_redraw = false; - } - - self.delay.delay_ms(10u16); - let new_selection = (((self.qei.count().wrapping_sub(encoder_start)) as usize) / 4) - % profiles::REFLOW_PROFILES.len(); - if new_selection != self.selected_profile { - self.selected_profile = new_selection; - needs_redraw = true; - } - - if !needs_redraw && self.button.is_low().unwrap() { - press_count += 1; - } else { - press_count = 0; - } - } - - // Make sure the button has been released, before continuing to the next stage - while !self.button.is_high().unwrap() { - self.delay.delay_ms(10u16); - } - - let (spi, disp_dc, disp_rst) = disp.release(); - self.spi = spi; - self.disp_dc = disp_dc; - self.disp_rst = disp_rst; - - self - } - - fn confirm_profile(mut self) -> (bool, App) { - let mut disp = - st7735_lcd::ST7735::new(self.spi, self.disp_dc, self.disp_rst, true, false, 160, 128); - self.disp_cs.set_low().unwrap(); - - disp.init(&mut self.delay).unwrap(); - disp.set_orientation(&Orientation::LandscapeSwapped) - .unwrap(); - - let style_black = PrimitiveStyleBuilder::new() - .fill_color(Rgb565::BLACK) - .build(); - let rect = Rectangle::new(Point::new(0, 0), Point::new(160, 128)).into_styled(style_black); - rect.draw(&mut disp).unwrap(); - - let text = TextStyleBuilder::new(ProFont12Point) - .text_color(Rgb565::WHITE) - .build(); - - let text_big = TextStyleBuilder::new(ProFont14Point) - .text_color(Rgb565::WHITE) - .build(); - - let text_big_black = TextStyleBuilder::new(ProFont14Point) - .text_color(Rgb565::BLACK) - .build(); - - let normal_box = PrimitiveStyleBuilder::new() - .fill_color(Rgb565::BLACK) - .stroke_color(Rgb565::WHITE) - .stroke_width(1) - .build(); - - let ok_box = PrimitiveStyleBuilder::new() - .fill_color(Rgb565::GREEN) - .stroke_color(Rgb565::WHITE) - .stroke_width(1) - .build(); - - let cancel_box = PrimitiveStyleBuilder::new() - .fill_color(Rgb565::RED) - .stroke_color(Rgb565::WHITE) - .stroke_width(1) - .build(); - - Text::new("Confirm profile", Point::new(4, 4)) - .into_styled(text) - .draw(&mut disp) - .unwrap(); - - Text::new( - profiles::REFLOW_PROFILES[self.selected_profile].get_name(), - Point::new(20, 50), - ) - .into_styled(text_big) - .draw(&mut disp) - .unwrap(); - - let mut press_count = 0; - let mut needs_redraw = true; - let mut confirmed = false; - let encoder_start = self.qei.count(); - - while press_count < 5 { - if needs_redraw { - let style = if confirmed { ok_box } else { normal_box }; - Rectangle::new(Point::new(4, 104), Point::new(70, 124)) - .into_styled(style) - .draw(&mut disp) - .unwrap(); - - let text_style = if confirmed { text_big_black } else { text_big }; - Text::new("Start", Point::new(12, 105)) - .into_styled(text_style) - .draw(&mut disp) - .unwrap(); - - let style = if !confirmed { cancel_box } else { normal_box }; - Rectangle::new(Point::new(90, 104), Point::new(155, 124)) - .into_styled(style) - .draw(&mut disp) - .unwrap(); - - let text_style = if !confirmed { text_big_black } else { text_big }; - Text::new("Cancel", Point::new(96, 105)) - .into_styled(text_style) - .draw(&mut disp) - .unwrap(); - - needs_redraw = false; - } - - self.delay.delay_ms(10u16); - let new_selection = - (((self.qei.count().wrapping_sub(encoder_start)) as usize) / 4) % 2 == 0; - if new_selection != confirmed { - needs_redraw = true; - confirmed = new_selection; - } - - if !needs_redraw && self.button.is_low().unwrap() { - press_count += 1; - } else { - press_count = 0; - } - } - - // Make sure the button has been released, before continuing to the next stage - while !self.button.is_high().unwrap() { - self.delay.delay_ms(10u16); - } - - let (spi, disp_dc, disp_rst) = disp.release(); - self.spi = spi; - self.disp_dc = disp_dc; - self.disp_rst = disp_rst; - - (confirmed, self) - } - - fn run_profile(mut self) -> App { - let mut disp = - st7735_lcd::ST7735::new(self.spi, self.disp_dc, self.disp_rst, true, false, 160, 128); - self.disp_cs.set_low().unwrap(); - - disp.init(&mut self.delay).unwrap(); - disp.set_orientation(&Orientation::LandscapeSwapped) - .unwrap(); - - let style_black = PrimitiveStyleBuilder::new() - .fill_color(Rgb565::BLACK) - .build(); - let rect = Rectangle::new(Point::new(0, 0), Point::new(160, 128)).into_styled(style_black); - rect.draw(&mut disp).unwrap(); - - let style_grid = PrimitiveStyleBuilder::new() - .stroke_color(Rgb565::new(4, 8, 4)) - .stroke_width(1) - .build(); - - for x in (0..160).step_by(30) { - Line::new(Point::new(x, 20), Point::new(x, 127)) - .into_styled(style_grid) - .draw(&mut disp) - .unwrap(); - } - - for y in (0..110).step_by(10) { - Line::new(Point::new(0, 127 - y), Point::new(195, 127 - y)) - .into_styled(style_grid) - .draw(&mut disp) - .unwrap(); - } - - for t in 0..320 { - let y = 148 - - (profiles::REFLOW_PROFILES[self.selected_profile].get_temp(t as f32) / 2.0) - as i32; - Pixel(Point::new((t / 2) as i32, y), Rgb565::new(24, 48, 24)) - .draw(&mut disp) - .unwrap(); - } - - let (spi, disp_dc, disp_rst) = disp.release(); - self.spi = spi; - self.disp_dc = disp_dc; - self.disp_rst = disp_rst; - - loop {} - - self - } -} diff --git a/src/application/confirm_profile.rs b/src/application/confirm_profile.rs new file mode 100644 index 0000000..85869cd --- /dev/null +++ b/src/application/confirm_profile.rs @@ -0,0 +1,134 @@ +use embedded_graphics::{ + drawable::Drawable, fonts::Text, pixelcolor::Rgb565, prelude::*, + primitives::rectangle::Rectangle, style::PrimitiveStyleBuilder, style::TextStyleBuilder, +}; + +use embedded_hal::digital::v2::{InputPin, OutputPin}; +use profont::{ProFont12Point, ProFont14Point}; +use st7735_lcd::Orientation; +use stm32f1xx_hal::prelude::*; + +use crate::application::App; +use crate::profiles; + +impl App { + pub fn confirm_profile(mut self) -> (bool, App) { + let mut disp = + st7735_lcd::ST7735::new(self.spi, self.disp_dc, self.disp_rst, true, false, 160, 128); + self.disp_cs.set_low().unwrap(); + + disp.init(&mut self.delay).unwrap(); + disp.set_orientation(&Orientation::LandscapeSwapped) + .unwrap(); + + let style_black = PrimitiveStyleBuilder::new() + .fill_color(Rgb565::BLACK) + .build(); + let rect = Rectangle::new(Point::new(0, 0), Point::new(160, 128)).into_styled(style_black); + rect.draw(&mut disp).unwrap(); + + let text = TextStyleBuilder::new(ProFont12Point) + .text_color(Rgb565::WHITE) + .build(); + + let text_big = TextStyleBuilder::new(ProFont14Point) + .text_color(Rgb565::WHITE) + .build(); + + let text_big_black = TextStyleBuilder::new(ProFont14Point) + .text_color(Rgb565::BLACK) + .build(); + + let normal_box = PrimitiveStyleBuilder::new() + .fill_color(Rgb565::BLACK) + .stroke_color(Rgb565::WHITE) + .stroke_width(1) + .build(); + + let ok_box = PrimitiveStyleBuilder::new() + .fill_color(Rgb565::GREEN) + .stroke_color(Rgb565::WHITE) + .stroke_width(1) + .build(); + + let cancel_box = PrimitiveStyleBuilder::new() + .fill_color(Rgb565::RED) + .stroke_color(Rgb565::WHITE) + .stroke_width(1) + .build(); + + Text::new("Confirm profile", Point::new(4, 4)) + .into_styled(text) + .draw(&mut disp) + .unwrap(); + + Text::new( + profiles::REFLOW_PROFILES[self.selected_profile].get_name(), + Point::new(20, 50), + ) + .into_styled(text_big) + .draw(&mut disp) + .unwrap(); + + let mut press_count = 0; + let mut needs_redraw = true; + let mut confirmed = false; + let encoder_start = self.qei.count(); + + while press_count < 5 { + if needs_redraw { + let style = if confirmed { ok_box } else { normal_box }; + Rectangle::new(Point::new(4, 104), Point::new(70, 124)) + .into_styled(style) + .draw(&mut disp) + .unwrap(); + + let text_style = if confirmed { text_big_black } else { text_big }; + Text::new("Start", Point::new(12, 105)) + .into_styled(text_style) + .draw(&mut disp) + .unwrap(); + + let style = if !confirmed { cancel_box } else { normal_box }; + Rectangle::new(Point::new(90, 104), Point::new(155, 124)) + .into_styled(style) + .draw(&mut disp) + .unwrap(); + + let text_style = if !confirmed { text_big_black } else { text_big }; + Text::new("Cancel", Point::new(96, 105)) + .into_styled(text_style) + .draw(&mut disp) + .unwrap(); + + needs_redraw = false; + } + + self.delay.delay_ms(10u16); + let new_selection = + (((self.qei.count().wrapping_sub(encoder_start)) as usize) / 4) % 2 == 0; + if new_selection != confirmed { + needs_redraw = true; + confirmed = new_selection; + } + + if !needs_redraw && self.button.is_low().unwrap() { + press_count += 1; + } else { + press_count = 0; + } + } + + // Make sure the button has been released, before continuing to the next stage + while !self.button.is_high().unwrap() { + self.delay.delay_ms(10u16); + } + + let (spi, disp_dc, disp_rst) = disp.release(); + self.spi = spi; + self.disp_dc = disp_dc; + self.disp_rst = disp_rst; + + (confirmed, self) + } +} diff --git a/src/logo.bmp b/src/application/logo.bmp similarity index 100% rename from src/logo.bmp rename to src/application/logo.bmp diff --git a/src/application/mod.rs b/src/application/mod.rs new file mode 100644 index 0000000..2a8af4e --- /dev/null +++ b/src/application/mod.rs @@ -0,0 +1,80 @@ +use arrayvec::ArrayString; +use core::fmt::Write; +use cortex_m::asm; +use cortex_m_rt::{entry, exception}; +use embedded_graphics::{ + drawable::Drawable, fonts::Text, image::Image, pixelcolor::BinaryColor, pixelcolor::Rgb565, + prelude::*, primitives::rectangle::Rectangle, primitives::Line, style::PrimitiveStyleBuilder, + style::TextStyleBuilder, +}; + +use embedded_hal::digital::v2::{InputPin, OutputPin}; +use profont::{ProFont12Point, ProFont14Point, ProFont9Point}; +use rtt_target::{rprintln, rtt_init_print}; +use st7735_lcd::Orientation; +use stm32f1xx_hal::{ + delay::Delay, + gpio::{gpioa, gpiob, gpioc, Alternate, Floating, Input, Output, PushPull}, + pac, + prelude::*, + qei, rcc, + spi::{Mode, Phase, Polarity, Spi, Spi1NoRemap}, + stm32, + timer::{Tim3PartialRemap, Timer}, +}; +use tinybmp::Bmp; + +use crate::profiles; + +mod confirm_profile; +mod profile_selection; +mod run_profile; +mod setup; +mod splash; + +pub use setup::setup; + +type AppSPI = Spi< + pac::SPI1, + Spi1NoRemap, + ( + gpioa::PA5>, + gpioa::PA6>, + gpioa::PA7>, + ), +>; + +type AppQEI = qei::Qei< + pac::TIM3, + Tim3PartialRemap, + (gpiob::PB4>, gpiob::PB5>), +>; + +pub struct App { + delay: Delay, + board_led: gpioc::PC13>, + spi: AppSPI, + disp_cs: gpioa::PA0>, + disp_dc: gpioa::PA4>, + disp_rst: gpioa::PA1>, + max_cs: gpioa::PA9>, + qei: AppQEI, + button: gpiob::PB3>, + + selected_profile: usize, +} + +impl App { + pub fn run(mut self) -> ! { + self = self.splash_screen(); + loop { + self = self.profile_selection(); + let (confirmed, app) = self.confirm_profile(); + self = app; + if !confirmed { + continue; + } + self = self.run_profile(); + } + } +} diff --git a/src/application/profile_selection.rs b/src/application/profile_selection.rs new file mode 100644 index 0000000..e0852a5 --- /dev/null +++ b/src/application/profile_selection.rs @@ -0,0 +1,121 @@ +use embedded_graphics::{ + drawable::Drawable, fonts::Text, pixelcolor::BinaryColor, pixelcolor::Rgb565, prelude::*, + primitives::rectangle::Rectangle, primitives::Line, style::PrimitiveStyleBuilder, + style::TextStyleBuilder, +}; + +use embedded_hal::digital::v2::{InputPin, OutputPin}; +use profont::ProFont12Point; + +use st7735_lcd::Orientation; +use stm32f1xx_hal::{ + delay::Delay, + gpio::{gpioa, gpiob, gpioc, Alternate, Floating, Input, Output, PushPull}, + pac, + prelude::*, + qei, rcc, + spi::{Mode, Phase, Polarity, Spi, Spi1NoRemap}, + stm32, + timer::{Tim3PartialRemap, Timer}, +}; + +use crate::application::App; +use crate::profiles; + +impl App { + pub fn profile_selection(mut self) -> App { + let mut disp = + st7735_lcd::ST7735::new(self.spi, self.disp_dc, self.disp_rst, true, false, 160, 128); + self.disp_cs.set_low().unwrap(); + + disp.init(&mut self.delay).unwrap(); + disp.set_orientation(&Orientation::LandscapeSwapped) + .unwrap(); + + let style_black = PrimitiveStyleBuilder::new() + .fill_color(Rgb565::BLACK) + .build(); + let rect = Rectangle::new(Point::new(0, 0), Point::new(160, 128)).into_styled(style_black); + + rect.draw(&mut disp).unwrap(); + + let text_lager = TextStyleBuilder::new(ProFont12Point) + .text_color(Rgb565::WHITE) + .build(); + + let profile_box = PrimitiveStyleBuilder::new() + .fill_color(Rgb565::BLACK) + .stroke_color(Rgb565::WHITE) + .stroke_width(1) + .build(); + + let selected_box = PrimitiveStyleBuilder::new() + .fill_color(Rgb565::BLUE) + .stroke_color(Rgb565::WHITE) + .stroke_width(1) + .build(); + + Text::new("Selected a profile", Point::new(4, 4)) + .into_styled(text_lager) + .draw(&mut disp) + .unwrap(); + + let encoder_start = self.qei.count(); + + let mut press_count = 0; + let mut needs_redraw = true; + while press_count < 5 { + if needs_redraw { + for i in 0..profiles::REFLOW_PROFILES.len() { + let style = if i == self.selected_profile { + selected_box + } else { + profile_box + }; + Rectangle::new( + Point::new(0, 20 + (i as i32) * 16), + Point::new(159, 20 + (i as i32) * 16 + 16), + ) + .into_styled(style) + .draw(&mut disp) + .unwrap(); + + Text::new( + profiles::REFLOW_PROFILES[i].get_name(), + Point::new(4, 21 + (i as i32) * 16), + ) + .into_styled(text_lager) + .draw(&mut disp) + .unwrap(); + } + needs_redraw = false; + } + + self.delay.delay_ms(10u16); + let new_selection = (((self.qei.count().wrapping_sub(encoder_start)) as usize) / 4) + % profiles::REFLOW_PROFILES.len(); + if new_selection != self.selected_profile { + self.selected_profile = new_selection; + needs_redraw = true; + } + + if !needs_redraw && self.button.is_low().unwrap() { + press_count += 1; + } else { + press_count = 0; + } + } + + // Make sure the button has been released, before continuing to the next stage + while !self.button.is_high().unwrap() { + self.delay.delay_ms(10u16); + } + + let (spi, disp_dc, disp_rst) = disp.release(); + self.spi = spi; + self.disp_dc = disp_dc; + self.disp_rst = disp_rst; + + self + } +} diff --git a/src/application/run_profile.rs b/src/application/run_profile.rs new file mode 100644 index 0000000..8a83e56 --- /dev/null +++ b/src/application/run_profile.rs @@ -0,0 +1,83 @@ +use arrayvec::ArrayString; +use core::fmt::Write; +use cortex_m::asm; +use cortex_m_rt::{entry, exception}; +use embedded_graphics::{ + drawable::Drawable, fonts::Text, image::Image, pixelcolor::BinaryColor, pixelcolor::Rgb565, + prelude::*, primitives::rectangle::Rectangle, primitives::Line, style::PrimitiveStyleBuilder, + style::TextStyleBuilder, +}; + +use embedded_hal::digital::v2::{InputPin, OutputPin}; +use profont::{ProFont12Point, ProFont14Point, ProFont9Point}; +use rtt_target::{rprintln, rtt_init_print}; +use st7735_lcd::Orientation; +use stm32f1xx_hal::{ + delay::Delay, + gpio::{gpioa, gpiob, gpioc, Alternate, Floating, Input, Output, PushPull}, + pac, + prelude::*, + qei, rcc, + spi::{Mode, Phase, Polarity, Spi, Spi1NoRemap}, + stm32, + timer::{Tim3PartialRemap, Timer}, +}; +use tinybmp::Bmp; + +use crate::application::App; +use crate::profiles; + +impl App { + pub fn run_profile(mut self) -> App { + let mut disp = + st7735_lcd::ST7735::new(self.spi, self.disp_dc, self.disp_rst, true, false, 160, 128); + self.disp_cs.set_low().unwrap(); + + disp.init(&mut self.delay).unwrap(); + disp.set_orientation(&Orientation::LandscapeSwapped) + .unwrap(); + + let style_black = PrimitiveStyleBuilder::new() + .fill_color(Rgb565::BLACK) + .build(); + let rect = Rectangle::new(Point::new(0, 0), Point::new(160, 128)).into_styled(style_black); + rect.draw(&mut disp).unwrap(); + + let style_grid = PrimitiveStyleBuilder::new() + .stroke_color(Rgb565::new(4, 8, 4)) + .stroke_width(1) + .build(); + + for x in (0..160).step_by(30) { + Line::new(Point::new(x, 20), Point::new(x, 127)) + .into_styled(style_grid) + .draw(&mut disp) + .unwrap(); + } + + for y in (0..110).step_by(10) { + Line::new(Point::new(0, 127 - y), Point::new(195, 127 - y)) + .into_styled(style_grid) + .draw(&mut disp) + .unwrap(); + } + + for t in 0..320 { + let y = 148 + - (profiles::REFLOW_PROFILES[self.selected_profile].get_temp(t as f32) / 2.0) + as i32; + Pixel(Point::new((t / 2) as i32, y), Rgb565::new(24, 48, 24)) + .draw(&mut disp) + .unwrap(); + } + + let (spi, disp_dc, disp_rst) = disp.release(); + self.spi = spi; + self.disp_dc = disp_dc; + self.disp_rst = disp_rst; + + loop {} + + self + } +} diff --git a/src/application/setup.rs b/src/application/setup.rs new file mode 100644 index 0000000..3d1d357 --- /dev/null +++ b/src/application/setup.rs @@ -0,0 +1,108 @@ +use arrayvec::ArrayString; +use core::fmt::Write; +use cortex_m::asm; +use cortex_m_rt::{entry, exception}; +use embedded_graphics::{ + drawable::Drawable, fonts::Text, image::Image, pixelcolor::BinaryColor, pixelcolor::Rgb565, + prelude::*, primitives::rectangle::Rectangle, primitives::Line, style::PrimitiveStyleBuilder, + style::TextStyleBuilder, +}; + +use embedded_hal::digital::v2::{InputPin, OutputPin}; +use profont::{ProFont12Point, ProFont14Point, ProFont9Point}; +use rtt_target::{rprintln, rtt_init_print}; +use st7735_lcd::Orientation; +use stm32f1xx_hal::{ + delay::Delay, + gpio::{gpioa, gpiob, gpioc, Alternate, Floating, Input, Output, PushPull}, + pac, + prelude::*, + qei, rcc, + spi::{Mode, Phase, Polarity, Spi, Spi1NoRemap}, + stm32, + timer::{Tim3PartialRemap, Timer}, +}; +use tinybmp::Bmp; + +use crate::application::App; +use crate::profiles; + +pub fn setup(cp: cortex_m::peripheral::Peripherals, dp: stm32::Peripherals) -> App { + // Take ownership over the raw flash and rcc devices and convert them into the corresponding + // HAL structs + let mut flash = dp.FLASH.constrain(); + + let mut rcc = dp.RCC.constrain(); + + // Freeze the configuration of all the clocks in the system and store the frozen frequencies in + // `clocks` + let clocks = rcc + .cfgr + .use_hse(8.mhz()) + .sysclk(72.mhz()) + .pclk1(36.mhz()) + .freeze(&mut flash.acr); + + // Acquire the GPIOC peripheral + let mut gpioc = dp.GPIOC.split(&mut rcc.apb2); + let mut gpioa = dp.GPIOA.split(&mut rcc.apb2); + + // Configure gpio C pin 13 as a push-pull output. The `crh` register is passed to the function + // in order to configure the port. For pins 0-7, crl should be passed instead. + let led = gpioc.pc13.into_push_pull_output(&mut gpioc.crh); + + let delay = Delay::new(cp.SYST, clocks); + + let gpiob = dp.GPIOB.split(&mut rcc.apb2); + let mut afio = dp.AFIO.constrain(&mut rcc.apb2); + + let (_, pb3, pb4) = afio.mapr.disable_jtag(gpioa.pa15, gpiob.pb3, gpiob.pb4); + + let qei = Timer::tim3(dp.TIM3, &clocks, &mut rcc.apb1).qei( + (pb4, gpiob.pb5), + &mut afio.mapr, + qei::QeiOptions::default(), + ); + let button = pb3; + + // SPI1 + let sck = gpioa.pa5.into_alternate_push_pull(&mut gpioa.crl); + let miso = gpioa.pa6; + let mosi = gpioa.pa7.into_alternate_push_pull(&mut gpioa.crl); + + let disp_cs = gpioa.pa0.into_push_pull_output(&mut gpioa.crl); + let max_cs = gpioa.pa9.into_push_pull_output(&mut gpioa.crh); + + let rst = gpioa.pa1.into_push_pull_output(&mut gpioa.crl); + let dc = gpioa.pa4.into_push_pull_output(&mut gpioa.crl); + let mut disp_led = gpioa.pa8.into_push_pull_output(&mut gpioa.crh); + + disp_led.set_high().unwrap(); + + let spi = Spi::spi1( + dp.SPI1, + (sck, miso, mosi), + &mut afio.mapr, + Mode { + polarity: Polarity::IdleLow, + phase: Phase::CaptureOnFirstTransition, + }, + 16.mhz(), + clocks, + &mut rcc.apb2, + ); + + App { + delay: delay, + board_led: led, + spi: spi, + disp_cs: disp_cs, + disp_dc: dc, + disp_rst: rst, + max_cs: max_cs, + qei: qei, + button: button, + + selected_profile: 0, + } +} diff --git a/src/application/splash.rs b/src/application/splash.rs new file mode 100644 index 0000000..e621f5b --- /dev/null +++ b/src/application/splash.rs @@ -0,0 +1,59 @@ +use arrayvec::ArrayString; +use core::fmt::Write; +use cortex_m::asm; +use cortex_m_rt::{entry, exception}; +use embedded_graphics::{ + drawable::Drawable, fonts::Text, image::Image, pixelcolor::BinaryColor, pixelcolor::Rgb565, + prelude::*, primitives::rectangle::Rectangle, primitives::Line, style::PrimitiveStyleBuilder, + style::TextStyleBuilder, +}; + +use embedded_hal::digital::v2::{InputPin, OutputPin}; +use profont::{ProFont12Point, ProFont14Point, ProFont9Point}; +use rtt_target::{rprintln, rtt_init_print}; +use st7735_lcd::Orientation; +use stm32f1xx_hal::{ + delay::Delay, + gpio::{gpioa, gpiob, gpioc, Alternate, Floating, Input, Output, PushPull}, + pac, + prelude::*, + qei, rcc, + spi::{Mode, Phase, Polarity, Spi, Spi1NoRemap}, + stm32, + timer::{Tim3PartialRemap, Timer}, +}; +use tinybmp::Bmp; + +use crate::application::App; + +impl App { + pub fn splash_screen(mut self) -> App { + let mut disp = + st7735_lcd::ST7735::new(self.spi, self.disp_dc, self.disp_rst, true, false, 160, 128); + self.disp_cs.set_low().unwrap(); + + disp.init(&mut self.delay).unwrap(); + disp.set_orientation(&Orientation::LandscapeSwapped) + .unwrap(); + + let style_black = PrimitiveStyleBuilder::new() + .fill_color(Rgb565::BLACK) + .build(); + let rect = Rectangle::new(Point::new(0, 0), Point::new(160, 128)).into_styled(style_black); + + rect.draw(&mut disp).unwrap(); + + let bmp = Bmp::from_slice(include_bytes!("logo.bmp")).unwrap(); + let image = Image::new(&bmp, Point::new(16, 0)); + image.draw(&mut disp).unwrap(); + + self.delay.delay_ms(2000u16); + + let (spi, disp_dc, disp_rst) = disp.release(); + self.spi = spi; + self.disp_dc = disp_dc; + self.disp_rst = disp_rst; + + self + } +}