aboutsummaryrefslogtreecommitdiffstats
path: root/sw/picardy/src/cw.rs
diff options
context:
space:
mode:
Diffstat (limited to 'sw/picardy/src/cw.rs')
-rw-r--r--sw/picardy/src/cw.rs153
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
+ }
+}
+