diff options
Diffstat (limited to 'sw/eval-clock-cw-tx/src/cw.rs')
-rw-r--r-- | sw/eval-clock-cw-tx/src/cw.rs | 200 |
1 files changed, 200 insertions, 0 deletions
diff --git a/sw/eval-clock-cw-tx/src/cw.rs b/sw/eval-clock-cw-tx/src/cw.rs new file mode 100644 index 0000000..045ef15 --- /dev/null +++ b/sw/eval-clock-cw-tx/src/cw.rs @@ -0,0 +1,200 @@ +//! CW output using PWM on PA8, TIM1 CH1 + +use stm32f1xx_hal::{ + prelude::*, + timer, + pac::TIM1, + gpio::gpioa::*, + gpio::{Alternate, PushPull}, + afio::MAPR, + pwm, +}; + +pub struct CWPWM { + channel : pwm::PwmChannel<TIM1, pwm::C1>, +} + +impl CWPWM { + pub fn new(pa8: PA8<Alternate<PushPull>>, tim1: timer::Timer<TIM1>, mapr: &mut MAPR) -> Self { + let pwm = tim1.pwm(pa8, mapr, 400.hz()); + let mut channel = pwm.split(); + channel.enable(); + channel.set_duty(0); + CWPWM { channel } + } + + pub fn on(&mut self) { + let max = self.channel.get_max_duty(); + self.channel.set_duty(max / 2); + } + + pub fn off(&mut self) { + self.channel.set_duty(0); + } +} + +#[derive(PartialEq, Eq, Clone, Copy)] +enum MorseSign { + Dot, + Dash +} + +impl MorseSign { + fn length(&self) -> u32 { + match self { + Self::Dot => 1, + Self::Dash => 3, + } + } + + fn other(&self) -> Self { + match self { + Self::Dot => Self::Dash, + Self::Dash => Self::Dot, + } + } +} + +fn other_pressed(sign: MorseSign, dot_pressed: bool, dash_pressed: bool) -> bool { + match sign { + MorseSign::Dot => dash_pressed, + MorseSign::Dash => dot_pressed, + } +} + +#[derive(Eq, Clone, Copy)] +enum KeyerState { + Idle, + Beep{current: MorseSign, next: Option<MorseSign>}, + Pause{current: MorseSign, next: Option<MorseSign>}, + LastPause{next: Option<MorseSign>}, +} + +impl PartialEq for KeyerState { + fn eq(&self, rhs: &Self) -> bool { + match (self, rhs) { + (Self::Idle, Self::Idle) => true, + (Self::Beep{current : c1, next : _}, Self::Beep{current : c2, next : _}) => c1 == c2, + (Self::Pause{current : c1, next : _}, Self::Pause{current : c2, next : _}) => c1 == c2, + (Self::LastPause{next : _}, Self::LastPause{next : _}) => true, + _ => false, + } + } +} + +pub struct Keyer { + // All durations are in ticks + dot_length : u32, + state : KeyerState, + time_last_state_change : u32, +} + +impl Keyer { + pub fn new(wpm : u32, ticks_per_s: u32) -> Keyer { + /* PARIS standard: 20 words per minute = dot length of 60 ms, inversely proportional: + * 1 wpm = 1200 ms, 2 wpm = 600 ms */ + + Keyer{ + dot_length : 1200 * ticks_per_s / (1000 * wpm), + state : KeyerState::Idle, + time_last_state_change : 0, + } + } + pub fn set_speed(&mut self, wpm : u32, ticks_per_s: u32) { self.dot_length = 1200 * ticks_per_s / (1000 * wpm) } + + pub fn tick(&mut self, ticks_now: u32, dot_pressed: bool, dash_pressed: bool) -> bool { + let mut transmit = false; + + let next_state = match self.state { + KeyerState::Idle => { + if dot_pressed { + transmit = true; + KeyerState::Beep{current: MorseSign::Dot, next: None} + } + else if dash_pressed { + transmit = true; + KeyerState::Beep{current: MorseSign::Dash, next: None} + } + else { + KeyerState::Idle + } + }, + KeyerState::Beep{current, next} => { + transmit = true; + + let next = if other_pressed(current, dot_pressed, dash_pressed) { + Some(current.other()) + } + else { + next + }; + + if self.time_last_state_change + self.dot_length * current.length() <= ticks_now { + KeyerState::Pause{current, next} + } + else { + KeyerState::Beep{current, next} + } + }, + KeyerState::Pause{current, next} => { + let next = if other_pressed(current, dot_pressed, dash_pressed) { + Some(current.other()) + } + else { + next + }; + + if self.time_last_state_change + self.dot_length <= ticks_now { + match next { + Some(state) => { + transmit = true; + KeyerState::Beep{current: state, next: None} + }, + None => KeyerState::LastPause{next: None} + } + } + else { + KeyerState::Pause{current, next} + } + }, + KeyerState::LastPause{next} => { + let next = if dot_pressed { + Some(MorseSign::Dot) + } + else if dash_pressed { + Some(MorseSign::Dash) + } + else { + next + }; + + if self.time_last_state_change + self.dot_length <= ticks_now { + KeyerState::LastPause{next} + } + else { + match next { + Some(MorseSign::Dot) => { + transmit = true; + KeyerState::Beep{current: MorseSign::Dot, next: None} + }, + Some(MorseSign::Dash) => { + transmit = true; + KeyerState::Beep{current: MorseSign::Dash, next: None} + }, + None => { + KeyerState::Idle + }, + } + } + }, + }; + + if next_state != self.state { + self.time_last_state_change = ticks_now; + } + self.state = next_state; + + transmit + } +} + |