diff options
Diffstat (limited to 'sw/picardy/src/cw.rs')
-rw-r--r-- | sw/picardy/src/cw.rs | 153 |
1 files changed, 153 insertions, 0 deletions
diff --git a/sw/picardy/src/cw.rs b/sw/picardy/src/cw.rs index ce99e39..4ebebf9 100644 --- a/sw/picardy/src/cw.rs +++ b/sw/picardy/src/cw.rs @@ -33,3 +33,156 @@ impl CWPWM { } } +#[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(PartialEq, Eq, Clone, Copy)] +enum KeyerState { + Idle, + Beep{current: MorseSign, next: Option<MorseSign>}, + Pause{current: MorseSign, next: Option<MorseSign>}, + LastPause{next: Option<MorseSign>}, +} + +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 + } +} + |