fw-rust: Make Si5351 useable
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
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.
This commit is contained in:
parent
7f14974146
commit
c36581e703
5 changed files with 430 additions and 119 deletions
|
@ -146,6 +146,12 @@ const SYM_E: [&[u8]; 2] = [
|
|||
&[0x3F, 0x3F, 0x31, 0x31, 0x30, 0x30],
|
||||
];
|
||||
|
||||
// TODO: Use https://github.com/rust-lang/rust/issues/85077 when stabilized
|
||||
const SYM_F: [&[u8]; 2] = [
|
||||
&[0xFC, 0xFC, 0x8C, 0x8C, 0x0C, 0x0C],
|
||||
&[0x3F, 0x3F, 0x01, 0x01, 0x00, 0x00],
|
||||
];
|
||||
|
||||
// TODO: Use https://github.com/rust-lang/rust/issues/85077 when stabilized
|
||||
const SYM_G: [&[u8]; 2] = [
|
||||
&[0xF8, 0xFC, 0x0C, 0x0C, 0x3C, 0x38],
|
||||
|
@ -191,6 +197,12 @@ const SYM_P: [&[u8]; 2] = [
|
|||
&[0x3F, 0x3F, 0x01, 0x01, 0x01, 0x00],
|
||||
];
|
||||
|
||||
// TODO: Use https://github.com/rust-lang/rust/issues/85077 when stabilized
|
||||
const SYM_Q: [&[u8]; 2] = [
|
||||
&[0xF8, 0xFC, 0x0C, 0x0C, 0xFC, 0xF8],
|
||||
&[0x1F, 0x3F, 0x30, 0x38, 0x7F, 0x6F],
|
||||
];
|
||||
|
||||
// TODO: Use https://github.com/rust-lang/rust/issues/85077 when stabilized
|
||||
const SYM_R: [&[u8]; 2] = [
|
||||
&[0xFC, 0xFC, 0x8C, 0x8C, 0xFC, 0xF8],
|
||||
|
@ -215,6 +227,12 @@ const SYM_U: [&[u8]; 2] = [
|
|||
&[0x1F, 0x3F, 0x30, 0x30, 0x3F, 0x1F],
|
||||
];
|
||||
|
||||
// TODO: Use https://github.com/rust-lang/rust/issues/85077 when stabilized
|
||||
const SYM_UNDERSCORE: [&[u8]; 2] = [
|
||||
&[0x00, 0x00, 0x00, 0x00, 0x00],
|
||||
&[0x30, 0x30, 0x30, 0x30, 0x30],
|
||||
];
|
||||
|
||||
// TODO: Use https://github.com/rust-lang/rust/issues/85077 when stabilized
|
||||
const SYM_INVALID: [&[u8]; 2] = [
|
||||
&[0x80, 0xE0, 0x98, 0xCC, 0x4C, 0x18, 0xE0, 0x80],
|
||||
|
@ -223,54 +241,54 @@ const SYM_INVALID: [&[u8]; 2] = [
|
|||
|
||||
// TODO: Use https://github.com/rust-lang/rust/issues/85077 when stabilized
|
||||
pub const SYMBOL_TABLE: [&[&[u8]; 2]; 50] = [
|
||||
&SYM_DOT, // '.'
|
||||
&SYM_INVALID, // '/'
|
||||
&SYM_0, // '0'
|
||||
&SYM_1, // '1'
|
||||
&SYM_2, // '2'
|
||||
&SYM_3, // '3'
|
||||
&SYM_4, // '4'
|
||||
&SYM_5, // '5'
|
||||
&SYM_6, // '6'
|
||||
&SYM_7, // '7'
|
||||
&SYM_8, // '8'
|
||||
&SYM_9, // '9'
|
||||
&SYM_COLON, // ':'
|
||||
&SYM_INVALID, // ';'
|
||||
&SYM_INVALID, // '<'
|
||||
&SYM_INVALID, // '='
|
||||
&SYM_INVALID, // '>'
|
||||
&SYM_INVALID, // '?'
|
||||
&SYM_INVALID, // '@'
|
||||
&SYM_A, // 'A'
|
||||
&SYM_B, // 'B'
|
||||
&SYM_C, // 'C'
|
||||
&SYM_INVALID, // 'D'
|
||||
&SYM_E, // 'E'
|
||||
&SYM_INVALID, // 'F'
|
||||
&SYM_G, // 'G'
|
||||
&SYM_H, // 'H'
|
||||
&SYM_I, // 'I'
|
||||
&SYM_INVALID, // 'J'
|
||||
&SYM_K, // 'K'
|
||||
&SYM_L, // 'L'
|
||||
&SYM_INVALID, // 'M'
|
||||
&SYM_N, // 'N'
|
||||
&SYM_O, // 'O'
|
||||
&SYM_P, // 'P'
|
||||
&SYM_INVALID, // 'Q'
|
||||
&SYM_R, // 'R'
|
||||
&SYM_S, // 'S'
|
||||
&SYM_T, // 'T'
|
||||
&SYM_U, // 'U'
|
||||
&SYM_INVALID, // 'V'
|
||||
&SYM_INVALID, // 'W'
|
||||
&SYM_INVALID, // 'X'
|
||||
&SYM_INVALID, // 'Y'
|
||||
&SYM_INVALID, // 'Z'
|
||||
&SYM_INVALID, // '['
|
||||
&SYM_INVALID, // '\'
|
||||
&SYM_INVALID, // ']'
|
||||
&SYM_INVALID, // '^'
|
||||
&SYM_INVALID, // '_'
|
||||
&SYM_DOT, // '.'
|
||||
&SYM_INVALID, // '/'
|
||||
&SYM_0, // '0'
|
||||
&SYM_1, // '1'
|
||||
&SYM_2, // '2'
|
||||
&SYM_3, // '3'
|
||||
&SYM_4, // '4'
|
||||
&SYM_5, // '5'
|
||||
&SYM_6, // '6'
|
||||
&SYM_7, // '7'
|
||||
&SYM_8, // '8'
|
||||
&SYM_9, // '9'
|
||||
&SYM_COLON, // ':'
|
||||
&SYM_INVALID, // ';'
|
||||
&SYM_INVALID, // '<'
|
||||
&SYM_INVALID, // '='
|
||||
&SYM_INVALID, // '>'
|
||||
&SYM_INVALID, // '?'
|
||||
&SYM_INVALID, // '@'
|
||||
&SYM_A, // 'A'
|
||||
&SYM_B, // 'B'
|
||||
&SYM_C, // 'C'
|
||||
&SYM_INVALID, // 'D'
|
||||
&SYM_E, // 'E'
|
||||
&SYM_F, // 'F'
|
||||
&SYM_G, // 'G'
|
||||
&SYM_H, // 'H'
|
||||
&SYM_I, // 'I'
|
||||
&SYM_INVALID, // 'J'
|
||||
&SYM_K, // 'K'
|
||||
&SYM_L, // 'L'
|
||||
&SYM_INVALID, // 'M'
|
||||
&SYM_N, // 'N'
|
||||
&SYM_O, // 'O'
|
||||
&SYM_P, // 'P'
|
||||
&SYM_Q, // 'Q'
|
||||
&SYM_R, // 'R'
|
||||
&SYM_S, // 'S'
|
||||
&SYM_T, // 'T'
|
||||
&SYM_U, // 'U'
|
||||
&SYM_INVALID, // 'V'
|
||||
&SYM_INVALID, // 'W'
|
||||
&SYM_INVALID, // 'X'
|
||||
&SYM_INVALID, // 'Y'
|
||||
&SYM_INVALID, // 'Z'
|
||||
&SYM_INVALID, // '['
|
||||
&SYM_INVALID, // '\'
|
||||
&SYM_INVALID, // ']'
|
||||
&SYM_INVALID, // '^'
|
||||
&SYM_UNDERSCORE, // '_'
|
||||
];
|
||||
|
|
|
@ -268,6 +268,79 @@ impl Lcd {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn print_freq_digit(&mut self, segment: u8, page: u8, data: u32, digit: u8) {
|
||||
let mut delay = Delay::<MHz8>::new();
|
||||
|
||||
let mut array = [0usize; 9];
|
||||
for (i, item) in array.iter_mut().enumerate() {
|
||||
*item = (((data / 10_u32.pow(i.try_into().unwrap())) % 10) + 2)
|
||||
.try_into()
|
||||
.unwrap();
|
||||
}
|
||||
array.reverse();
|
||||
let digit = 8 - digit;
|
||||
|
||||
for i in 0..2 {
|
||||
self.move_cursor(segment, page + i);
|
||||
|
||||
// TODO: This delay fixes issues, try find a better solution
|
||||
delay.delay_ms(1_u8);
|
||||
self.cd.set_high();
|
||||
|
||||
block!(self.spi.send(0x00)).unwrap();
|
||||
block!(self.spi.send(0x00)).unwrap();
|
||||
for j in 0..3 {
|
||||
if j == digit {
|
||||
for segment in SYMBOL_TABLE[array[j as usize]][i as usize] {
|
||||
block!(self.spi.send(!*segment)).unwrap();
|
||||
}
|
||||
} else {
|
||||
for segment in SYMBOL_TABLE[array[j as usize]][i as usize] {
|
||||
block!(self.spi.send(*segment)).unwrap();
|
||||
}
|
||||
}
|
||||
block!(self.spi.send(0x00)).unwrap();
|
||||
}
|
||||
for segment in SYMBOL_TABLE[0][i as usize] {
|
||||
block!(self.spi.send(*segment)).unwrap();
|
||||
}
|
||||
block!(self.spi.send(0x00)).unwrap();
|
||||
for j in 3..6 {
|
||||
if j == digit {
|
||||
for segment in SYMBOL_TABLE[array[j as usize]][i as usize] {
|
||||
block!(self.spi.send(!*segment)).unwrap();
|
||||
}
|
||||
} else {
|
||||
for segment in SYMBOL_TABLE[array[j as usize]][i as usize] {
|
||||
block!(self.spi.send(*segment)).unwrap();
|
||||
}
|
||||
}
|
||||
block!(self.spi.send(0x00)).unwrap();
|
||||
}
|
||||
for segment in SYMBOL_TABLE[0][i as usize] {
|
||||
block!(self.spi.send(*segment)).unwrap();
|
||||
}
|
||||
block!(self.spi.send(0x00)).unwrap();
|
||||
for j in 6..9 {
|
||||
if j == digit {
|
||||
for segment in SYMBOL_TABLE[array[j as usize]][i as usize] {
|
||||
block!(self.spi.send(!*segment)).unwrap();
|
||||
}
|
||||
} else {
|
||||
for segment in SYMBOL_TABLE[array[j as usize]][i as usize] {
|
||||
block!(self.spi.send(*segment)).unwrap();
|
||||
}
|
||||
}
|
||||
block!(self.spi.send(0x00)).unwrap();
|
||||
}
|
||||
block!(self.spi.send(0x00)).unwrap();
|
||||
|
||||
// TODO: This delay fixes issues, try find a better solution
|
||||
delay.delay_ms(1_u8);
|
||||
self.cd.set_low();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn print_icon(&mut self, segment: u8, page: u8, symbol: &[u8]) {
|
||||
let mut delay = Delay::<MHz8>::new();
|
||||
self.move_cursor(segment, page);
|
||||
|
|
191
firmware/rust/src/screen/channel.rs
Normal file
191
firmware/rust/src/screen/channel.rs
Normal file
|
@ -0,0 +1,191 @@
|
|||
use super::{ClockChannel, Event, Home, Screens};
|
||||
use crate::{lcd::Lcd, Input};
|
||||
use si5351::{ClockOutput, PLL};
|
||||
|
||||
enum Selection {
|
||||
Frequency,
|
||||
FrequencyDigit(u8),
|
||||
Digit(u8),
|
||||
Enabled,
|
||||
Pll,
|
||||
Back,
|
||||
}
|
||||
|
||||
pub struct Channel {
|
||||
active: Selection,
|
||||
channel: ClockChannel,
|
||||
}
|
||||
|
||||
impl Channel {
|
||||
pub fn new(channel: ClockChannel) -> Self {
|
||||
Self {
|
||||
active: Selection::Frequency,
|
||||
channel,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn input(&mut self, input: &Input) -> Event {
|
||||
self.active = match self.active {
|
||||
Selection::Frequency => match input {
|
||||
Input::Next => Selection::Enabled,
|
||||
Input::Previous => Selection::Back,
|
||||
Input::Select => Selection::FrequencyDigit(8),
|
||||
Input::Back => return Event::Screen(Screens::Home(Home::new())),
|
||||
},
|
||||
Selection::FrequencyDigit(digit) => match input {
|
||||
Input::Next => {
|
||||
if digit == u8::MIN {
|
||||
Selection::FrequencyDigit(8)
|
||||
} else {
|
||||
Selection::FrequencyDigit(digit - 1)
|
||||
}
|
||||
}
|
||||
Input::Previous => {
|
||||
if digit >= 8 {
|
||||
Selection::FrequencyDigit(u8::MIN)
|
||||
} else {
|
||||
Selection::FrequencyDigit(digit + 1)
|
||||
}
|
||||
}
|
||||
Input::Select => Selection::Digit(digit),
|
||||
Input::Back => Selection::Frequency,
|
||||
},
|
||||
Selection::Digit(digit) => match input {
|
||||
Input::Next => {
|
||||
let new_freq = self.channel.freq + 10_u32.pow(digit.into());
|
||||
if new_freq < 162_000_000 {
|
||||
self.channel.freq = new_freq;
|
||||
} else {
|
||||
self.channel.freq = 162_000_000
|
||||
}
|
||||
return Event::Channel(self.channel);
|
||||
}
|
||||
Input::Previous => {
|
||||
let difference = 10_u32.pow(digit.into());
|
||||
if self.channel.freq > difference {
|
||||
let new_freq = self.channel.freq - difference;
|
||||
if new_freq > 15_000 {
|
||||
self.channel.freq = new_freq;
|
||||
} else {
|
||||
self.channel.freq = 15_000;
|
||||
}
|
||||
} else {
|
||||
self.channel.freq = 15_000;
|
||||
}
|
||||
return Event::Channel(self.channel);
|
||||
}
|
||||
Input::Select => Selection::Frequency,
|
||||
Input::Back => Selection::FrequencyDigit(digit),
|
||||
},
|
||||
Selection::Enabled => match input {
|
||||
Input::Next => Selection::Pll,
|
||||
Input::Previous => Selection::Frequency,
|
||||
Input::Select => {
|
||||
self.channel.enabled = !self.channel.enabled;
|
||||
return Event::Channel(self.channel);
|
||||
}
|
||||
Input::Back => return Event::Screen(Screens::Home(Home::new())),
|
||||
},
|
||||
Selection::Pll => match input {
|
||||
Input::Next => Selection::Back,
|
||||
Input::Previous => Selection::Enabled,
|
||||
Input::Select => {
|
||||
self.channel.pll = match self.channel.pll {
|
||||
PLL::A => PLL::B,
|
||||
PLL::B => PLL::A,
|
||||
};
|
||||
return Event::Channel(self.channel);
|
||||
}
|
||||
Input::Back => return Event::Screen(Screens::Home(Home::new())),
|
||||
},
|
||||
Selection::Back => match input {
|
||||
Input::Next => Selection::Frequency,
|
||||
Input::Previous => Selection::Pll,
|
||||
_ => return Event::Screen(Screens::Home(Home::new())),
|
||||
},
|
||||
};
|
||||
|
||||
Event::None
|
||||
}
|
||||
|
||||
fn draw_enabled(&self, lcd: &mut Lcd, inverted: bool) {
|
||||
if inverted {
|
||||
match self.channel.enabled {
|
||||
false => lcd.print_inverted(13, 4, "OFF"),
|
||||
true => lcd.print_inverted(16, 4, "ON"),
|
||||
}
|
||||
} else {
|
||||
match self.channel.enabled {
|
||||
false => lcd.print(13, 4, "OFF"),
|
||||
true => lcd.print(16, 4, "ON"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn draw(&self, lcd: &mut Lcd) {
|
||||
lcd.fill_area(0, 0, 19, 2, 0xFF);
|
||||
match self.channel.output {
|
||||
ClockOutput::Clk0 => lcd.print_inverted(19, 0, "CHANNEL_1"),
|
||||
ClockOutput::Clk1 => lcd.print_inverted(19, 0, "CHANNEL_2"),
|
||||
ClockOutput::Clk2 => lcd.print_inverted(19, 0, "CHANNEL_3"),
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
lcd.fill_area(83, 0, 19, 2, 0xFF);
|
||||
|
||||
match &self.active {
|
||||
Selection::Frequency => {
|
||||
lcd.print_inverted(0, 2, "FREQ:");
|
||||
lcd.print_freq(39, 2, self.channel.freq);
|
||||
self.draw_enabled(lcd, false);
|
||||
match self.channel.pll {
|
||||
PLL::A => lcd.print(59, 4, "PLL_A"),
|
||||
PLL::B => lcd.print(59, 4, "PLL_B"),
|
||||
}
|
||||
lcd.print(36, 6, "BACK");
|
||||
}
|
||||
Selection::FrequencyDigit(digit) | Selection::Digit(digit) => {
|
||||
lcd.print(0, 2, "FREQ:");
|
||||
lcd.print_freq_digit(39, 2, self.channel.freq, *digit);
|
||||
self.draw_enabled(lcd, false);
|
||||
match self.channel.pll {
|
||||
PLL::A => lcd.print(59, 4, "PLL_A"),
|
||||
PLL::B => lcd.print(59, 4, "PLL_B"),
|
||||
}
|
||||
lcd.print(36, 6, "BACK");
|
||||
}
|
||||
Selection::Enabled => {
|
||||
lcd.print(0, 2, "FREQ:");
|
||||
lcd.print_freq(39, 2, self.channel.freq);
|
||||
self.draw_enabled(lcd, true);
|
||||
match self.channel.pll {
|
||||
PLL::A => lcd.print(59, 4, "PLL_A"),
|
||||
PLL::B => lcd.print(59, 4, "PLL_B"),
|
||||
}
|
||||
lcd.print(36, 6, "BACK");
|
||||
}
|
||||
Selection::Pll => {
|
||||
lcd.print(0, 2, "FREQ:");
|
||||
lcd.print_freq(39, 2, self.channel.freq);
|
||||
self.draw_enabled(lcd, false);
|
||||
match self.channel.pll {
|
||||
PLL::A => lcd.print_inverted(59, 4, "PLL_A"),
|
||||
PLL::B => lcd.print_inverted(59, 4, "PLL_B"),
|
||||
}
|
||||
lcd.print(36, 6, "BACK");
|
||||
}
|
||||
Selection::Back => {
|
||||
lcd.print(0, 2, "FREQ:");
|
||||
lcd.print_freq(39, 2, self.channel.freq);
|
||||
match self.channel.enabled {
|
||||
false => lcd.print(13, 4, "OFF"),
|
||||
true => lcd.print(16, 4, "ON"),
|
||||
}
|
||||
match self.channel.pll {
|
||||
PLL::A => lcd.print(59, 4, "PLL_A"),
|
||||
PLL::B => lcd.print(59, 4, "PLL_B"),
|
||||
}
|
||||
lcd.print_inverted(36, 6, "BACK");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,10 +1,5 @@
|
|||
use super::{Event, Screens, Setup, Splash};
|
||||
use crate::{
|
||||
assets::{OFF, ON, PLL_A, PLL_B},
|
||||
lcd::Lcd,
|
||||
Input,
|
||||
};
|
||||
use si5351::PLL;
|
||||
use super::{Channel, Event, Screens, Setup};
|
||||
use crate::{lcd::Lcd, screen::ClockChannel, Input};
|
||||
|
||||
enum Selection {
|
||||
Ch1,
|
||||
|
@ -13,74 +8,35 @@ enum Selection {
|
|||
Setup,
|
||||
}
|
||||
|
||||
struct Channel {
|
||||
freq: u32,
|
||||
enabled: bool,
|
||||
pll: PLL,
|
||||
}
|
||||
|
||||
impl Channel {
|
||||
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,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Home {
|
||||
active: Selection,
|
||||
channels: [Channel; 3],
|
||||
}
|
||||
|
||||
impl Home {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
active: Selection::Ch1,
|
||||
channels: [
|
||||
Channel {
|
||||
freq: 0,
|
||||
enabled: false,
|
||||
pll: PLL::A,
|
||||
},
|
||||
Channel {
|
||||
freq: 0,
|
||||
enabled: false,
|
||||
pll: PLL::A,
|
||||
},
|
||||
Channel {
|
||||
freq: 0,
|
||||
enabled: false,
|
||||
pll: PLL::A,
|
||||
},
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn input(&mut self, input: &Input) -> Event {
|
||||
pub fn input(&mut self, input: &Input, channels: [ClockChannel; 3]) -> Event {
|
||||
self.active = match self.active {
|
||||
Selection::Ch1 => match input {
|
||||
Input::Next => Selection::Ch2,
|
||||
Input::Previous => Selection::Setup,
|
||||
Input::Select => return Event::Screen(Screens::Splash(Splash)),
|
||||
Input::Select => return Event::Screen(Screens::Channel(Channel::new(channels[0]))),
|
||||
Input::Back => Selection::Ch1,
|
||||
},
|
||||
Selection::Ch2 => match input {
|
||||
Input::Next => Selection::Ch3,
|
||||
Input::Previous => Selection::Ch1,
|
||||
Input::Select => return Event::Screen(Screens::Splash(Splash)),
|
||||
Input::Select => return Event::Screen(Screens::Channel(Channel::new(channels[1]))),
|
||||
Input::Back => Selection::Ch2,
|
||||
},
|
||||
Selection::Ch3 => match input {
|
||||
Input::Next => Selection::Setup,
|
||||
Input::Previous => Selection::Ch2,
|
||||
Input::Select => return Event::Screen(Screens::Splash(Splash)),
|
||||
Input::Select => return Event::Screen(Screens::Channel(Channel::new(channels[2]))),
|
||||
Input::Back => Selection::Ch3,
|
||||
},
|
||||
Selection::Setup => match input {
|
||||
|
@ -94,42 +50,42 @@ impl Home {
|
|||
Event::None
|
||||
}
|
||||
|
||||
pub fn draw(&self, lcd: &mut Lcd) {
|
||||
pub fn draw(&self, lcd: &mut Lcd, channels: [ClockChannel; 3]) {
|
||||
match &self.active {
|
||||
Selection::Ch1 => {
|
||||
lcd.print_inverted(0, 0, "CH1");
|
||||
self.channels[0].print(lcd, 0);
|
||||
channels[0].print(lcd, 0);
|
||||
lcd.print(0, 2, "CH2");
|
||||
self.channels[1].print(lcd, 2);
|
||||
channels[1].print(lcd, 2);
|
||||
lcd.print(0, 4, "CH3");
|
||||
self.channels[2].print(lcd, 4);
|
||||
channels[2].print(lcd, 4);
|
||||
lcd.print(33, 6, "SETUP");
|
||||
}
|
||||
Selection::Ch2 => {
|
||||
lcd.print(0, 0, "CH1");
|
||||
self.channels[0].print(lcd, 0);
|
||||
channels[0].print(lcd, 0);
|
||||
lcd.print_inverted(0, 2, "CH2");
|
||||
self.channels[1].print(lcd, 2);
|
||||
channels[1].print(lcd, 2);
|
||||
lcd.print(0, 4, "CH3");
|
||||
self.channels[2].print(lcd, 4);
|
||||
channels[2].print(lcd, 4);
|
||||
lcd.print(33, 6, "SETUP");
|
||||
}
|
||||
Selection::Ch3 => {
|
||||
lcd.print(0, 0, "CH1");
|
||||
self.channels[0].print(lcd, 0);
|
||||
channels[0].print(lcd, 0);
|
||||
lcd.print(0, 2, "CH2");
|
||||
self.channels[1].print(lcd, 2);
|
||||
channels[1].print(lcd, 2);
|
||||
lcd.print_inverted(0, 4, "CH3");
|
||||
self.channels[2].print(lcd, 4);
|
||||
channels[2].print(lcd, 4);
|
||||
lcd.print(33, 6, "SETUP");
|
||||
}
|
||||
Selection::Setup => {
|
||||
lcd.print(0, 0, "CH1");
|
||||
self.channels[0].print(lcd, 0);
|
||||
channels[0].print(lcd, 0);
|
||||
lcd.print(0, 2, "CH2");
|
||||
self.channels[1].print(lcd, 2);
|
||||
channels[1].print(lcd, 2);
|
||||
lcd.print(0, 4, "CH3");
|
||||
self.channels[2].print(lcd, 4);
|
||||
channels[2].print(lcd, 4);
|
||||
lcd.print_inverted(33, 6, "SETUP");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,13 +3,20 @@ use atmega_hal::{
|
|||
port::{mode::Output, Pin, PB0, PB1, PD5},
|
||||
Spi,
|
||||
};
|
||||
use si5351::{Si5351, Si5351Device};
|
||||
use si5351::{ClockOutput, Si5351, Si5351Device, PLL};
|
||||
|
||||
mod channel;
|
||||
mod home;
|
||||
mod setup;
|
||||
mod splash;
|
||||
|
||||
use crate::{eeprom, lcd::Lcd, I2c, Input, BACKLIGHT};
|
||||
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;
|
||||
|
@ -20,21 +27,55 @@ 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) -> Event {
|
||||
pub fn input(&mut self, input: &Input, channels: [ClockChannel; 3]) -> Event {
|
||||
match self {
|
||||
Screens::Splash(_) => Event::None,
|
||||
Screens::Home(home) => home.input(input),
|
||||
Screens::Home(home) => home.input(input, channels),
|
||||
Screens::Setup(setup) => setup.input(input),
|
||||
Screens::Channel(channel) => channel.input(input),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -45,6 +86,7 @@ pub struct Screen {
|
|||
pwm: Pin<Output, PD5>,
|
||||
screen: Screens,
|
||||
si5351: Si5351Device<I2c>,
|
||||
channels: [ClockChannel; 3],
|
||||
}
|
||||
|
||||
impl Screen {
|
||||
|
@ -62,6 +104,26 @@ impl Screen {
|
|||
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,
|
||||
},
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -110,16 +172,27 @@ impl Screen {
|
|||
|
||||
match &self.screen {
|
||||
Screens::Splash(splash) => splash.draw(&mut self.lcd),
|
||||
Screens::Home(home) => home.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) {
|
||||
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 => {}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue