morse.c 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  1. /*
  2. * Morse decoder
  3. *
  4. * Copyright (c) 2012 Michael Buesch <m@bues.ch>
  5. * Licensed under the terms of the GNU General Public License version 2.
  6. */
  7. #include "morse.h"
  8. #include "util.h"
  9. #define dit MORSE_DIT
  10. #define dah MORSE_DAH
  11. #define CHAR_SYM(charac, sym) [(charac) - MORSE_CHARS_START] = sym
  12. #define NUM_SYM(num, sym) [(num) - MORSE_NUMS_START] = sym
  13. #define SPEC_SYM(spec, sym) [(spec) - MORSE_SPEC_START] = sym
  14. #define SIG_SYM(sig, sym) [(sig) - MORSE_SIG_START] = sym
  15. static const morse_sym_t PROGMEM character_symbols[] = {
  16. CHAR_SYM(MORSE_A, MORSE_SYM_2(dit, dah)),
  17. CHAR_SYM(MORSE_B, MORSE_SYM_4(dah, dit, dit, dit)),
  18. CHAR_SYM(MORSE_C, MORSE_SYM_4(dah, dit, dah, dit)),
  19. CHAR_SYM(MORSE_D, MORSE_SYM_3(dah, dit, dit)),
  20. CHAR_SYM(MORSE_E, MORSE_SYM_1(dit)),
  21. CHAR_SYM(MORSE_F, MORSE_SYM_4(dit, dit, dah, dit)),
  22. CHAR_SYM(MORSE_G, MORSE_SYM_3(dah, dah, dit)),
  23. CHAR_SYM(MORSE_H, MORSE_SYM_4(dit, dit, dit, dit)),
  24. CHAR_SYM(MORSE_I, MORSE_SYM_2(dit, dit)),
  25. CHAR_SYM(MORSE_J, MORSE_SYM_4(dit, dah, dah, dah)),
  26. CHAR_SYM(MORSE_K, MORSE_SYM_3(dah, dit, dah)),
  27. CHAR_SYM(MORSE_L, MORSE_SYM_4(dit, dah, dit, dit)),
  28. CHAR_SYM(MORSE_M, MORSE_SYM_2(dah, dah)),
  29. CHAR_SYM(MORSE_N, MORSE_SYM_2(dah, dit)),
  30. CHAR_SYM(MORSE_O, MORSE_SYM_3(dah, dah, dah)),
  31. CHAR_SYM(MORSE_P, MORSE_SYM_4(dit, dah, dah, dit)),
  32. CHAR_SYM(MORSE_Q, MORSE_SYM_4(dah, dah, dit, dah)),
  33. CHAR_SYM(MORSE_R, MORSE_SYM_3(dit, dah, dit)),
  34. CHAR_SYM(MORSE_S, MORSE_SYM_3(dit, dit, dit)),
  35. CHAR_SYM(MORSE_T, MORSE_SYM_1(dah)),
  36. CHAR_SYM(MORSE_U, MORSE_SYM_3(dit, dit, dah)),
  37. CHAR_SYM(MORSE_V, MORSE_SYM_4(dit, dit, dit, dah)),
  38. CHAR_SYM(MORSE_W, MORSE_SYM_3(dit, dah, dah)),
  39. CHAR_SYM(MORSE_X, MORSE_SYM_4(dah, dit, dit, dah)),
  40. CHAR_SYM(MORSE_Y, MORSE_SYM_4(dah, dit, dah, dah)),
  41. CHAR_SYM(MORSE_Z, MORSE_SYM_4(dah, dah, dit, dit)),
  42. };
  43. static const morse_sym_t PROGMEM number_symbols[] = {
  44. NUM_SYM(MORSE_0, MORSE_SYM_5(dah, dah, dah, dah, dah)),
  45. NUM_SYM(MORSE_1, MORSE_SYM_5(dit, dah, dah, dah, dah)),
  46. NUM_SYM(MORSE_2, MORSE_SYM_5(dit, dit, dah, dah, dah)),
  47. NUM_SYM(MORSE_3, MORSE_SYM_5(dit, dit, dit, dah, dah)),
  48. NUM_SYM(MORSE_4, MORSE_SYM_5(dit, dit, dit, dit, dah)),
  49. NUM_SYM(MORSE_5, MORSE_SYM_5(dit, dit, dit, dit, dit)),
  50. NUM_SYM(MORSE_6, MORSE_SYM_5(dah, dit, dit, dit, dit)),
  51. NUM_SYM(MORSE_7, MORSE_SYM_5(dah, dah, dit, dit, dit)),
  52. NUM_SYM(MORSE_8, MORSE_SYM_5(dah, dah, dah, dit, dit)),
  53. NUM_SYM(MORSE_9, MORSE_SYM_5(dah, dah, dah, dah, dit)),
  54. };
  55. static const morse_sym_t PROGMEM special_symbols[] = {
  56. SPEC_SYM(MORSE_GACC_A, MORSE_SYM_5(dit, dah, dah, dit, dah)),
  57. SPEC_SYM(MORSE_AE, MORSE_SYM_4(dit, dah, dit, dah)),
  58. SPEC_SYM(MORSE_GACC_E, MORSE_SYM_5(dit, dah, dit, dit, dah)),
  59. SPEC_SYM(MORSE_AACC_E, MORSE_SYM_5(dit, dit, dah, dit, dit)),
  60. SPEC_SYM(MORSE_OE, MORSE_SYM_4(dah, dah, dah, dit)),
  61. SPEC_SYM(MORSE_UE, MORSE_SYM_4(dit, dit, dah, dah)),
  62. SPEC_SYM(MORSE_SZ, MORSE_SYM_6(dit, dit, dit, dah, dah, dit)),
  63. SPEC_SYM(MORSE_CH, MORSE_SYM_4(dah, dah, dah, dah)),
  64. SPEC_SYM(MORSE_TILDE_N, MORSE_SYM_5(dah, dah, dit, dah, dah)),
  65. SPEC_SYM(MORSE_PERIOD, MORSE_SYM_6(dit, dah, dit, dah, dit, dah)),
  66. SPEC_SYM(MORSE_COMMA, MORSE_SYM_6(dah, dah, dit, dit, dah, dah)),
  67. SPEC_SYM(MORSE_COLON, MORSE_SYM_6(dah, dah, dah, dit, dit, dit)),
  68. SPEC_SYM(MORSE_SEMICOLON, MORSE_SYM_6(dah, dit, dah, dit, dah, dit)),
  69. SPEC_SYM(MORSE_QUESTION, MORSE_SYM_6(dit, dit, dah, dah, dit, dit)),
  70. SPEC_SYM(MORSE_DASH, MORSE_SYM_6(dah, dit, dit, dit, dit, dah)),
  71. SPEC_SYM(MORSE_UNDERSCORE, MORSE_SYM_6(dit, dit, dah, dah, dit, dah)),
  72. SPEC_SYM(MORSE_PAREN_OPEN, MORSE_SYM_5(dah, dit, dah, dah, dit)),
  73. SPEC_SYM(MORSE_PAREN_CLOSE, MORSE_SYM_6(dah, dit, dah, dah, dit, dah)),
  74. SPEC_SYM(MORSE_TICK, MORSE_SYM_6(dit, dah, dah, dah, dah, dit)),
  75. SPEC_SYM(MORSE_EQUAL, MORSE_SYM_5(dah, dit, dit, dit, dah)),
  76. SPEC_SYM(MORSE_PLUS, MORSE_SYM_5(dit, dah, dit, dah, dit)),
  77. SPEC_SYM(MORSE_SLASH, MORSE_SYM_5(dah, dit, dit, dah, dit)),
  78. SPEC_SYM(MORSE_AT, MORSE_SYM_6(dit, dah, dah, dit, dah, dit)),
  79. SPEC_SYM(MORSE_SPACE, 0),
  80. };
  81. static const morse_sym_t PROGMEM signal_symbols[] = {
  82. SIG_SYM(MORSE_SIG_KA, MORSE_SYM_5(dah, dit, dah, dit, dah)),
  83. SIG_SYM(MORSE_SIG_BT, MORSE_SYM_5(dah, dit, dit, dit, dah)),
  84. SIG_SYM(MORSE_SIG_AR, MORSE_SYM_5(dit, dah, dit, dah, dit)),
  85. SIG_SYM(MORSE_SIG_VE, MORSE_SYM_5(dit, dit, dit, dah, dit)),
  86. SIG_SYM(MORSE_SIG_SK, MORSE_SYM_6(dit, dit, dit, dah, dit, dah)),
  87. SIG_SYM(MORSE_SIG_SOS, MORSE_SYM_9(dit, dit, dit, dah, dah, dah, dit, dit, dit)),
  88. SIG_SYM(MORSE_SIG_ERROR, MORSE_SYM_8(dit, dit, dit, dit, dit, dit, dit, dit)),
  89. };
  90. static morse_sym_t fetch_sym(const morse_sym_t * PROGPTR table,
  91. uint8_t offset)
  92. {
  93. return pgm_read_word(&table[offset]);
  94. }
  95. morse_sym_t morse_encode_character(enum morse_character c)
  96. {
  97. if (c >= MORSE_CHARS_START && c <= MORSE_CHARS_END)
  98. return fetch_sym(character_symbols, c - MORSE_CHARS_START);
  99. if (c >= MORSE_NUMS_START && c <= MORSE_NUMS_END)
  100. return fetch_sym(number_symbols, c - MORSE_NUMS_START);
  101. if (c >= MORSE_SPEC_START && c <= MORSE_SPEC_END)
  102. return fetch_sym(special_symbols, c - MORSE_SPEC_START);
  103. if (c >= MORSE_SIG_START && c <= MORSE_SIG_END)
  104. return fetch_sym(signal_symbols, c - MORSE_SIG_START);
  105. return fetch_sym(signal_symbols, MORSE_SIG_ERROR - MORSE_SIG_START);
  106. }
  107. enum morse_character morse_decode_symbol(morse_sym_t sym)
  108. {
  109. unsigned int i;
  110. #define check_decode_tab(table, startchar) \
  111. for (i = 0; i < ARRAY_SIZE(table); i++) { \
  112. if (fetch_sym(table, i) == sym) \
  113. return (enum morse_character)(i + startchar); \
  114. }
  115. check_decode_tab(character_symbols, MORSE_CHARS_START)
  116. check_decode_tab(number_symbols, MORSE_NUMS_START)
  117. check_decode_tab(special_symbols, MORSE_SPEC_START)
  118. check_decode_tab(signal_symbols, MORSE_SIG_START)
  119. #undef check_decode_tab
  120. return MORSE_INVALID;
  121. }
  122. int8_t morse_to_ascii(char *buf, uint8_t buf_size,
  123. enum morse_character mchar)
  124. {
  125. int8_t ret = 0;
  126. #define put_char(c) { \
  127. if (!buf_size--) \
  128. return -1; \
  129. *buf++ = (c); \
  130. ret++; \
  131. }
  132. if ((mchar >= MORSE_CHARS_START && mchar <= MORSE_CHARS_END) ||
  133. (mchar >= MORSE_NUMS_START && mchar <= MORSE_NUMS_END)) {
  134. put_char((char)mchar);
  135. } else {
  136. switch (mchar) {
  137. case MORSE_GACC_A:
  138. put_char('A');
  139. break;
  140. case MORSE_GACC_E:
  141. case MORSE_AACC_E:
  142. put_char('E');
  143. break;
  144. case MORSE_AE:
  145. put_char('A');
  146. put_char('E');
  147. break;
  148. case MORSE_OE:
  149. put_char('O');
  150. put_char('E');
  151. break;
  152. case MORSE_UE:
  153. put_char('U');
  154. put_char('E');
  155. break;
  156. case MORSE_SZ:
  157. put_char('S');
  158. put_char('S');
  159. break;
  160. case MORSE_CH:
  161. put_char('C');
  162. put_char('H');
  163. break;
  164. case MORSE_TILDE_N:
  165. put_char('N');
  166. break;
  167. case MORSE_PERIOD:
  168. put_char('.');
  169. break;
  170. case MORSE_COMMA:
  171. put_char(',');
  172. break;
  173. case MORSE_COLON:
  174. put_char(':');
  175. break;
  176. case MORSE_SEMICOLON:
  177. put_char(';');
  178. break;
  179. case MORSE_QUESTION:
  180. put_char('?');
  181. break;
  182. case MORSE_DASH:
  183. put_char('-');
  184. break;
  185. case MORSE_UNDERSCORE:
  186. put_char('_');
  187. break;
  188. case MORSE_PAREN_OPEN:
  189. put_char('(');
  190. break;
  191. case MORSE_PAREN_CLOSE:
  192. put_char(')');
  193. break;
  194. case MORSE_TICK:
  195. put_char('\'');
  196. break;
  197. case MORSE_EQUAL:
  198. put_char('=');
  199. break;
  200. case MORSE_PLUS:
  201. put_char('+');
  202. break;
  203. case MORSE_SLASH:
  204. put_char('/');
  205. break;
  206. case MORSE_AT:
  207. put_char('@');
  208. break;
  209. case MORSE_SPACE:
  210. put_char(' ');
  211. break;
  212. case MORSE_SIG_KA:
  213. case MORSE_SIG_BT:
  214. case MORSE_SIG_AR:
  215. case MORSE_SIG_VE:
  216. case MORSE_SIG_SK:
  217. put_char(' ');
  218. break;
  219. case MORSE_SIG_SOS:
  220. put_char('S');
  221. put_char('0');
  222. put_char('S');
  223. break;
  224. case MORSE_SIG_ERROR:
  225. put_char('-');
  226. put_char('E');
  227. put_char('R');
  228. put_char('R');
  229. put_char('O');
  230. put_char('R');
  231. put_char('-');
  232. break;
  233. default:
  234. return -1;
  235. }
  236. }
  237. #undef put_char
  238. return ret;
  239. }