embedded_morse/
lib.rs

1//! Morse output for embedded platforms
2//!
3//! # Limitations
4//!
5//! Only supports a-z
6#![no_std]
7
8use embedded_hal::{blocking::delay::DelayMs, digital::v2::OutputPin};
9
10/// 0 is dot, 1 is dash
11#[derive(Debug, Clone, Copy)]
12struct MorseChar {
13    length: u8,
14    pattern: u8,
15}
16
17const CHARS: [MorseChar; 26] = [
18    // A
19    MorseChar {
20        length: 2,
21        pattern: 0b10,
22    },
23    // B
24    MorseChar {
25        length: 4,
26        pattern: 0b0001,
27    },
28    // C
29    MorseChar {
30        length: 4,
31        pattern: 0b0101,
32    },
33    // D
34    MorseChar {
35        length: 3,
36        pattern: 0b001,
37    },
38    // E
39    MorseChar {
40        length: 1,
41        pattern: 0b0,
42    },
43    // F
44    MorseChar {
45        length: 4,
46        pattern: 0b0100,
47    },
48    // G
49    MorseChar {
50        length: 3,
51        pattern: 0b011,
52    },
53    // H
54    MorseChar {
55        length: 4,
56        pattern: 0b0000,
57    },
58    // I
59    MorseChar {
60        length: 2,
61        pattern: 0b00,
62    },
63    // J
64    MorseChar {
65        length: 4,
66        pattern: 0b1110,
67    },
68    // K
69    MorseChar {
70        length: 3,
71        pattern: 0b101,
72    },
73    // L
74    MorseChar {
75        length: 4,
76        pattern: 0b0010,
77    },
78    // M
79    MorseChar {
80        length: 2,
81        pattern: 0b11,
82    },
83    // N
84    MorseChar {
85        length: 2,
86        pattern: 0b01,
87    },
88    // O
89    MorseChar {
90        length: 3,
91        pattern: 0b111,
92    },
93    // P
94    MorseChar {
95        length: 4,
96        pattern: 0b0110,
97    },
98    // Q
99    MorseChar {
100        length: 4,
101        pattern: 0b1011,
102    },
103    // R
104    MorseChar {
105        length: 3,
106        pattern: 0b010,
107    },
108    // S
109    MorseChar {
110        length: 3,
111        pattern: 0b111,
112    },
113    // T
114    MorseChar {
115        length: 1,
116        pattern: 0b1,
117    },
118    // U
119    MorseChar {
120        length: 3,
121        pattern: 0b100,
122    },
123    // V
124    MorseChar {
125        length: 4,
126        pattern: 0b1000,
127    },
128    // W
129    MorseChar {
130        length: 3,
131        pattern: 0b110,
132    },
133    // X
134    MorseChar {
135        length: 4,
136        pattern: 0b1001,
137    },
138    // Y
139    MorseChar {
140        length: 4,
141        pattern: 0b1101,
142    },
143    // Z
144    MorseChar {
145        length: 4,
146        pattern: 0b0011,
147    },
148];
149
150pub struct Morse<DELAY, PIN> {
151    dot_length: u16,
152    dash_length: u16,
153    space_length: u16,
154    delay: DELAY,
155    pin: PIN,
156    invert: bool,
157}
158
159// TODO Invert output
160impl<ERR, DELAY: DelayMs<u16>, PIN: OutputPin<Error = ERR>> Morse<DELAY, PIN> {
161    pub fn new(delay: DELAY, pin: PIN, invert: bool, dot_length: u16) -> Self {
162        Self {
163            dot_length,
164            dash_length: dot_length * 3,
165            space_length: dot_length * 3,
166            delay,
167            pin,
168            invert,
169        }
170    }
171    pub fn new_default(delay: DELAY, pin: PIN, invert: bool) -> Self {
172        Self::new(delay, pin, invert, 300)
173    }
174
175    pub fn output_str(&mut self, output: &str) -> Result<(), ERR> {
176        for c in output.chars() {
177            let c = c.to_ascii_uppercase();
178            if c.is_ascii_uppercase() {
179                let morse_char = CHARS[c as usize - 0x41];
180                let mut pattern = morse_char.pattern;
181                for _ in 0..morse_char.length {
182                    if self.invert {
183                        self.pin.set_low()?;
184                    } else {
185                        self.pin.set_high()?;
186                    }
187                    self.delay.delay_ms(if pattern & 0b1 == 1 {
188                        self.dash_length
189                    } else {
190                        self.dot_length
191                    });
192                    if self.invert {
193                        self.pin.set_high()?;
194                    } else {
195                        self.pin.set_low()?;
196                    }
197                    pattern = pattern >> 1;
198                    self.delay.delay_ms(self.dot_length);
199                }
200                self.delay.delay_ms(self.space_length);
201            } else if c == ' ' {
202                self.delay.delay_ms(self.dot_length * 7);
203            }
204        }
205        Ok(())
206    }
207}