dRonin  adbada4
dRonin firmware
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
morsel.c
Go to the documentation of this file.
1 // Routines to expand morse code for error pattern blinking, etc.
2 // MorseL (morse library)
3 //
4 // Copyright (c) 2016, dRonin
5 // All rights reserved.
6 //
7 // Redistribution and use in source and binary forms, with or without
8 // modification, are permitted provided that the following conditions are met:
9 //
10 // 1. Redistributions of source code must retain the above copyright notice, this
11 // list of conditions and the following disclaimer.
12 // 2. Redistributions in binary form must reproduce the above copyright notice,
13 // this list of conditions and the following disclaimer in the documentation
14 // and/or other materials provided with the distribution.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
20 // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 
27 #include <morsel.h>
28 
29 /* Morse stuff is between 1 and 6 elements.
30  * First 2 bits == 11 (punctuation), next 6 bits are character
31  * First 3 bits == 000, 001, 010, 011, 100 for 1 to 5 elements,
32  * following 5 bits are character.
33  *
34  * 101 reserved / unused
35  *
36  * 0 is dit, 1 is dah
37  */
38 
39 static const uint8_t morse_table[] = {
40  /* **** ASCII, '(' to '@' **** (0..24) vs 40..64 */
41  0B10010110,
42  /* -.--. ( */
43  0B11101101,
44  /* -.--.- ) */
45  0B11011010,
46  /* .--.-. @ (should be *) */
47  0B10001010,
48  /* .-.-. + */
49  0B11110011,
50  /* --..-- , */
51  0B11100001,
52  /* -....- - */
53  0B11010101,
54  /* .-.-.- . */
55  0B10010010,
56  /* -..-. / */
57  0B10011111,
58  /* ----- 0 */
59  0B10001111,
60  /* .---- 1 */
61  0B10000111,
62  /* ..--- 2 */
63  0B10000011,
64  /* ...-- 3 */
65  0B10000001,
66  /* ....- 4 */
67  0B10000000,
68  /* ..... 5 */
69  0B10010000,
70  /* -.... 6 */
71  0B10011000,
72  /* --... 7 */
73  0B10011100,
74  /* ---.. 8 */
75  0B10011110,
76  /* ----. 9 */
77  0B11111000,
78  /* ---... : */
79  0B11101010,
80  /* -.-.-. ; */
81  0B10010110,
82  /* -.--. [ (should be <) */
83  0B10010001,
84  /* -...- = */
85  0B11101101,
86  /* -.--.- ] (should be >) */
87  0B11001100,
88  /* ..--.. ? */
89  0B11011010,
90  /* .--.-. @ (should be *) */
91 
92  /* **** ASCII, A to Z **** (25..50) vs 65..90 and 97..122 */
93  0B00101000,
94  /* .- A */
95  0B01110000,
96  /* -... B */
97  0B01110100,
98  /* -.-. C */
99  0B01010000,
100  /* -.. D */
101  0B00000000,
102  /* . E */
103  0B01100100,
104  /* ..-. F */
105  0B01011000,
106  /* --. G */
107  0B01100000,
108  /* .... H */
109  0B00100000,
110  /* .. I */
111  0B01101110,
112  /* .--- J */
113  0B01010100,
114  /* -.- K */
115  0B01101000,
116  /* .-.. L */
117  0B00111000,
118  /* -- M */
119  0B00110000,
120  /* -. N */
121  0B01011100,
122  /* --- O */
123  0B01101100,
124  /* .--. P */
125  0B01111010,
126  /* --.- Q */
127  0B01001000,
128  /* .-. R */
129  0B01000000,
130  /* ... S */
131  0B00010000,
132  /* - T */
133  0B01000100,
134  /* ..- U */
135  0B01100010,
136  /* ...- V SHORT SHORT SHORT LONG */
137  0B01001100,
138  /* .-- W */
139  0B01110010,
140  /* -..- X */
141  0B01110110,
142  /* -.-- Y */
143  0B01111000,
144  /* --.. Z */
145 };
146 
147 static uint8_t morse_expand(uint8_t raw, uint8_t *len)
148 {
149  /* Special 6 punctuation signifier */
150  if ((raw & 0B11000000) == 0B11000000) {
151  *len = 6;
152  return raw << 2;
153  }
154 
155  *len = (raw >> 5) + 1;
156 
157  return raw << 3;
158 }
159 
160 static uint8_t morse_lookup(char c, uint8_t *len)
161 {
162  *len = 0;
163 
164  if (c < 40) {
165  /* Space is included in here, in which case we return a 0 len,
166  * and there's a total of 6 time units of silence */
167  return 0;
168  }
169 
170  if (c <= 90) { /* 40..90 */
171  return morse_expand(morse_table[c - 40], len);
172  }
173 
174  if (c < 97) { /* 91..96 */
175  return 0;
176  }
177 
178  if (c < 122) { /* 97..122 */
179  return morse_expand(morse_table[c - 97 + 25], len);
180  }
181 
182  return 0;
183 }
184 
185 enum __attribute__ ((__packed__)) character_state {
186  STATE_NEXTCHAR = 0, // 1 time of nil, prime next character -> NEXTSYM/SPACEWAIT
187  STATE_SPACEWAIT, // 1 time of nil -> STATE_SPACEWAIT_B
188  STATE_SPACEWAIT_B, // 1 time of nil -> STATE_SPACEWAIT_C
189  STATE_SPACEWAIT_C, // 1 time of nil -> STATE_NEXTCHAR
190  STATE_NEXTSYM, // Prime next symbol, 1 time of nil -> NEXTCHAR/DOT/DASH
191  STATE_DOT, // Send a dot -> NEXTSYM
192  STATE_DASH, // Send a dash -> DASH_B
193  STATE_DASH_B, // Send a dash -> DASH_C
194  STATE_DASH_C // Send a dash -> NEXTSYM
195 };
196 
198  uint32_t raw_state;
199  struct {
200  uint8_t len;
201  uint8_t data;
202  enum character_state char_state;
203  } fields;
204 };
205 
206 #define DONT_BUILD_IF(COND,MSG) typedef char static_assertion_##MSG[(COND)?-1:1]
207 
208 DONT_BUILD_IF(sizeof(union morsel_packed_state) > sizeof(uint32_t),
209  packedStateRep);
210 
211 /* Returns 0 for off, 1 for on, -1 for completed */
212 int morse_send(const char **c, uint32_t *state)
213 {
214  union morsel_packed_state *m_s = (void *) state;
215 
216  switch (m_s->fields.char_state) {
217  case STATE_NEXTCHAR:
218  if (!**c) {
219  return -1;
220  }
221 
222  m_s->fields.data = morse_lookup(**c, &m_s->fields.len);
223  (*c)++;
224 
225  if (m_s->fields.len) {
226  m_s->fields.char_state = STATE_NEXTSYM;
227  } else {
228  m_s->fields.char_state = STATE_SPACEWAIT;
229  }
230 
231  return 0;
232 
233  case STATE_SPACEWAIT:
234  m_s->fields.char_state = STATE_SPACEWAIT_B;
235 
236  return 0;
237 
238  case STATE_SPACEWAIT_B:
239  m_s->fields.char_state = STATE_SPACEWAIT_C;
240 
241  return 0;
242 
243  case STATE_SPACEWAIT_C:
244  m_s->fields.char_state = STATE_NEXTCHAR;
245 
246  return 0;
247 
248  case STATE_NEXTSYM:
249  if (!m_s->fields.len) {
250  m_s->fields.char_state = STATE_NEXTCHAR;
251 
252  return 0;
253  }
254 
255  if (m_s->fields.data & 0B10000000) {
256  m_s->fields.char_state = STATE_DASH;
257  } else {
258  m_s->fields.char_state = STATE_DOT;
259  }
260 
261  m_s->fields.data <<= 1;
262 
263  m_s->fields.len--;
264 
265  return 0;
266 
267  case STATE_DASH:
268  m_s->fields.char_state = STATE_DASH_B;
269  return 1;
270 
271  case STATE_DASH_B:
272  m_s->fields.char_state = STATE_DASH_C;
273  return 1;
274 
275  case STATE_DOT:
276  case STATE_DASH_C:
277  m_s->fields.char_state = STATE_NEXTSYM;
278  return 1;
279 
280  default: /* illegal state */
281  return 1;
282  }
283 }
enum character_state char_state
Definition: morsel.c:202
uint32_t raw_state
Definition: morsel.c:198
int morse_send(const char **c, uint32_t *state)
Definition: morsel.c:212
static uint8_t morse_expand(uint8_t raw, uint8_t *len)
Definition: morsel.c:147
enum __attribute__((__packed__))
Definition: morsel.c:185
static const uint8_t morse_table[]
Definition: morsel.c:39
struct morsel_packed_state::@1 fields
static uint8_t morse_lookup(char c, uint8_t *len)
Definition: morsel.c:160
#define DONT_BUILD_IF(COND, MSG)
Definition: morsel.c:206
enum arena_state state