morsec/
lib.rs

1#![cfg_attr(not(feature = "std"), no_std)]
2
3#[cfg(not(feature = "std"))]
4use core::{
5    clone::Clone, marker::Copy, slice::Iter, str::SplitWhitespace, time::Duration, unimplemented,
6};
7#[cfg(feature = "std")]
8pub use std::{slice::Iter, str::SplitWhitespace, time::Duration};
9
10mod conversion;
11use conversion::*;
12
13pub(crate) enum MorseChar {
14    Dit,
15    Dah,
16}
17
18impl Copy for MorseChar {}
19
20impl Clone for MorseChar {
21    fn clone(&self) -> Self {
22        *self
23    }
24}
25
26pub struct Morsec<'input, T: MorsecTransmitter> {
27    /// The message that is to be transmitted via Morse code, it is required
28    /// that the message be one of the 26 basic Latin characters or a space
29    message: SplitWhitespace<'input>,
30
31    /// User defined struct that implements the MorsecTransmitter trait
32    transmitter: T,
33}
34
35pub trait MorsecTransmitter {
36    /// The DIT_DURATION controls the time length that a dit will last for.
37    /// It is the fundamental time unit in Morse code, as all other times are
38    /// defined of this single value. A dah for example being 3 times longer
39    /// than a dit, the space between dits/dahs - which are part of the same
40    /// letter - lasts the same length of time as a dit and the space between
41    /// words is 7 times that of a dit.
42    ///
43    /// This value is optional as it has been defaulted to be 500ms. It is not
44    /// needed for a user to use this variable in their code as the Morsec
45    /// library will handle using this variable in the appropriate way
46    const DIT_DURATION: Duration = Duration::from_millis(500);
47
48    /// Morse code relies on the time delays to signal messages. As such the
49    /// user is required to provide a function which can cause execution to
50    /// sleep for the variable duration.
51    fn sleep(&mut self, duration: Duration);
52
53    /// As Morse code transmits messages through toggling on and off some
54    /// medium, the toggle function here provides a way to allow the Morsec
55    /// struct to cause the desired side effect
56    fn toggle(&mut self);
57}
58
59impl<'input, T: MorsecTransmitter> Morsec<'input, T> {
60    /// Creates a new Morsec struct from the input message and the toggle
61    /// function. The initial dit_duration is defaulted to be 0.5s
62    pub fn new(message: &'input str, transmitter: T) -> Self {
63        Self {
64            message: message.split_whitespace(),
65            transmitter,
66        }
67    }
68
69    /// Transmit will send the message that was given to the struct and in the
70    /// process consume the struct
71    pub fn transmit(mut self) {
72        for word in self.message {
73            for letter in word.chars() {
74                for symbol in Self::convert_char(letter) {
75                    self.transmitter.toggle();
76                    match symbol {
77                        MorseChar::Dit => self.transmitter.sleep(T::DIT_DURATION),
78                        MorseChar::Dah => self.transmitter.sleep(3 * T::DIT_DURATION),
79                    };
80                    self.transmitter.toggle();
81                    // Sleep between the encoded characters
82                    self.transmitter.sleep(T::DIT_DURATION);
83                }
84                // sleep between letters in the words cumulative needs to be 3x
85                // the dit duration
86                self.transmitter.sleep(2 * T::DIT_DURATION);
87            }
88            // Sleep so the time between words is cumulative 7x dit duration
89            self.transmitter.sleep(4 * T::DIT_DURATION);
90        }
91    }
92
93    fn convert_char(input: char) -> Iter<'static, MorseChar> {
94        match input {
95            'a' | 'A' => A.iter(),
96            'b' | 'B' => B.iter(),
97            'c' | 'C' => C.iter(),
98            'd' | 'D' => D.iter(),
99            'e' | 'E' => E.iter(),
100            'f' | 'F' => F.iter(),
101            'g' | 'G' => G.iter(),
102            'h' | 'H' => H.iter(),
103            'i' | 'I' => I.iter(),
104            'j' | 'J' => J.iter(),
105            'k' | 'K' => K.iter(),
106            'l' | 'L' => L.iter(),
107            'm' | 'M' => M.iter(),
108            'n' | 'N' => N.iter(),
109            'o' | 'O' => O.iter(),
110            'p' | 'P' => P.iter(),
111            'q' | 'Q' => Q.iter(),
112            'r' | 'R' => R.iter(),
113            's' | 'S' => S.iter(),
114            't' | 'T' => T.iter(),
115            'u' | 'U' => U.iter(),
116            'v' | 'V' => V.iter(),
117            'w' | 'W' => W.iter(),
118            'x' | 'X' => X.iter(),
119            'y' | 'Y' => Y.iter(),
120            'z' | 'Z' => Z.iter(),
121            _ => unimplemented!(),
122        }
123    }
124}