clock_generator/firmware/src/screen.rs
finga 698965fcf7
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
firmware: Remove the c attempt of the firmware
2023-06-07 22:17:01 +02:00

210 lines
5.5 KiB
Rust

use atmega_hal::{
pac::{EEPROM, TC0},
port::{mode::Output, Pin, PB0, PB1, PD5},
Eeprom, Spi,
};
use si5351::{ClockOutput, Si5351, Si5351Device, PLL};
mod channel;
mod home;
mod setup;
mod splash;
use crate::{
assets::{OFF, ON, PLL_A, PLL_B},
lcd::Lcd,
I2c, Input, BACKLIGHT, CONTRAST,
};
pub use channel::Channel;
pub use home::Home;
pub use setup::Setup;
pub use splash::Splash;
// TODO: Only update changes instead of whole screen
pub enum Event {
Screen(Screens),
Backlight(u8),
Contrast(u8),
Channel(ClockChannel),
None,
}
#[derive(Clone, Copy)]
pub struct ClockChannel {
output: ClockOutput,
freq: u32,
enabled: bool,
pll: PLL,
}
impl ClockChannel {
fn print(&self, lcd: &mut Lcd, page: u8) {
lcd.print_freq(25, page, self.freq);
lcd.print_icon(91, page, if self.enabled { &ON } else { &OFF });
lcd.print_icon(
94,
page + 1,
match self.pll {
PLL::A => &PLL_A,
PLL::B => &PLL_B,
},
);
}
fn update(&self, si5351: &mut Si5351Device<I2c>) {
si5351
.set_frequency(self.pll, self.output, self.freq)
.unwrap();
si5351.set_clock_enabled(self.output, self.enabled);
si5351.flush_output_enabled().unwrap();
}
}
pub enum Screens {
Splash(Splash),
Home(Home),
Setup(Setup),
Channel(Channel),
}
impl Screens {
pub fn input(&mut self, input: &Input, channels: [ClockChannel; 3]) -> Event {
match self {
Screens::Splash(_) => Event::None,
Screens::Home(home) => home.input(input, channels),
Screens::Setup(setup) => setup.input(input),
Screens::Channel(channel) => channel.input(input),
}
}
}
pub struct Screen {
lcd: Lcd,
tc0: TC0,
eeprom: Eeprom,
pwm: Pin<Output, PD5>,
screen: Screens,
si5351: Si5351Device<I2c>,
channels: [ClockChannel; 3],
}
impl Screen {
pub fn new(
tc0: TC0,
eeprom: EEPROM,
spi: Spi,
pwm: Pin<Output, PD5>,
cd: Pin<Output, PB0>,
rst: Pin<Output, PB1>,
i2c: I2c,
) -> Self {
Self {
lcd: Lcd::new(spi, cd, rst),
tc0,
eeprom: Eeprom::new(eeprom),
pwm,
screen: Screens::Splash(Splash),
si5351: Si5351Device::new_adafruit_module(i2c),
channels: [
ClockChannel {
output: ClockOutput::Clk0,
freq: 1_000_000,
enabled: false,
pll: PLL::A,
},
ClockChannel {
output: ClockOutput::Clk1,
freq: 1_000_000,
enabled: false,
pll: PLL::A,
},
ClockChannel {
output: ClockOutput::Clk2,
freq: 1_000_000,
enabled: false,
pll: PLL::A,
},
],
}
}
pub fn init(&mut self) {
// Init display backlight
self.tc0.ocr0a.write(|w| w.bits(255));
self.tc0.tccr0a.write(|w| {
w.wgm0().pwm_fast();
w.com0b().match_clear()
});
self.set_backlight(self.eeprom.read_byte(&BACKLIGHT as *const _ as u16));
// Init lcd display controller
self.lcd
.init(self.eeprom.read_byte(&CONTRAST as *const _ as u16));
self.draw();
// Init Si5351
self.si5351.init_adafruit_module().unwrap();
}
fn set_backlight(&mut self, backlight: u8) {
match backlight {
0 => {
self.tc0.tccr0b.write(|w| w.cs0().no_clock());
self.pwm.set_low();
}
1..=5 => {
self.tc0.tccr0b.write(|w| {
w.wgm02().set_bit();
w.cs0().prescale_256()
});
self.tc0.ocr0b.write(|w| w.bits(backlight - 1));
}
_ => {
self.tc0.tccr0b.write(|w| {
w.wgm02().set_bit();
w.cs0().prescale_64()
});
self.tc0.ocr0b.write(|w| w.bits(backlight - 6));
}
}
}
pub fn draw(&mut self) {
self.lcd.fill_area(0, 0, 102, 8, 0x00);
match &self.screen {
Screens::Splash(splash) => splash.draw(&mut self.lcd),
Screens::Home(home) => home.draw(&mut self.lcd, self.channels),
Screens::Setup(setup) => setup.draw(&mut self.lcd),
Screens::Channel(channel) => channel.draw(&mut self.lcd),
}
}
pub fn input(&mut self, input: &Input) {
match self.screen.input(input, self.channels) {
Event::Screen(screen) => self.screen = screen,
Event::Backlight(backlight) => self.set_backlight(backlight),
Event::Contrast(contrast) => self.lcd.set_contrast(contrast),
Event::Channel(channel) => {
match channel.output {
ClockOutput::Clk0 => self.channels[0] = channel,
ClockOutput::Clk1 => self.channels[1] = channel,
ClockOutput::Clk2 => self.channels[2] = channel,
_ => unimplemented!(),
}
channel.update(&mut self.si5351);
}
Event::None => {}
}
self.draw();
}
pub fn change(&mut self, screen: Screens) {
self.screen = screen;
self.draw();
}
}