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}