finga
c36581e703
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
In order to make the Si5351 configurable add some needed assets, create the ability to print the frequency with selected digits and add a channel screen.
207 lines
5.4 KiB
Rust
207 lines
5.4 KiB
Rust
use atmega_hal::{
|
|
pac::TC0,
|
|
port::{mode::Output, Pin, PB0, PB1, PD5},
|
|
Spi,
|
|
};
|
|
use si5351::{ClockOutput, Si5351, Si5351Device, PLL};
|
|
|
|
mod channel;
|
|
mod home;
|
|
mod setup;
|
|
mod splash;
|
|
|
|
use crate::{
|
|
assets::{OFF, ON, PLL_A, PLL_B},
|
|
eeprom,
|
|
lcd::Lcd,
|
|
I2c, Input, BACKLIGHT,
|
|
};
|
|
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,
|
|
pwm: Pin<Output, PD5>,
|
|
screen: Screens,
|
|
si5351: Si5351Device<I2c>,
|
|
channels: [ClockChannel; 3],
|
|
}
|
|
|
|
impl Screen {
|
|
pub fn new(
|
|
tc0: TC0,
|
|
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,
|
|
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| unsafe { w.bits(255) });
|
|
self.tc0.tccr0a.write(|w| {
|
|
w.wgm0().pwm_fast();
|
|
w.com0b().match_clear()
|
|
});
|
|
self.set_backlight(nb::block!(eeprom::read_byte(&BACKLIGHT)).unwrap());
|
|
|
|
// Init lcd display
|
|
self.lcd.init();
|
|
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| unsafe { w.bits(backlight - 1) });
|
|
}
|
|
_ => {
|
|
self.tc0.tccr0b.write(|w| {
|
|
w.wgm02().set_bit();
|
|
w.cs0().prescale_64()
|
|
});
|
|
self.tc0.ocr0b.write(|w| unsafe { 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();
|
|
}
|
|
}
|