diff options
| author | Author Name <[email protected]> | 2023-07-07 12:20:59 +0930 |
|---|---|---|
| committer | David Rowe <[email protected]> | 2023-07-07 12:29:06 +0930 |
| commit | ac7c48b4dee99d4c772f133d70d8d1b38262fcd2 (patch) | |
| tree | a2d0ace57a9c0e2e5b611c4987f6fed1b38b81e7 /stm32/src/morse.c | |
shallow zip-file copy from codec2 e9d726bf20
Diffstat (limited to 'stm32/src/morse.c')
| -rw-r--r-- | stm32/src/morse.c | 175 |
1 files changed, 175 insertions, 0 deletions
diff --git a/stm32/src/morse.c b/stm32/src/morse.c new file mode 100644 index 0000000..2522993 --- /dev/null +++ b/stm32/src/morse.c @@ -0,0 +1,175 @@ +/*! + * Morse code library. + * + * This implements a state machine for playing back morse code messages. + * + * Author Stuart Longland <[email protected]> + * Copyright (C) 2015 FreeDV project. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License version 2.1, + * as published by the Free Software Foundation. This program is + * distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see + * <http://www.gnu.org/licenses/>. + */ + +#include <stdlib.h> +#include "morse.h" + +#include <stdio.h> + +/*! Symbol table element definition */ +struct morse_sym_table_t { + uint8_t code; uint8_t len; +}; + +/*! Symbol table: "digits" */ +static const struct morse_sym_table_t morse_digits[] = { + { .code = 0xf8, .len = 5 }, /* 0: ----- */ + { .code = 0x78, .len = 5 }, /* 1: .---- */ + { .code = 0x38, .len = 5 }, /* 2: ..--- */ + { .code = 0x18, .len = 5 }, /* 3: ...-- */ + { .code = 0x08, .len = 5 }, /* 4: ....- */ + { .code = 0x00, .len = 5 }, /* 5: ..... */ + { .code = 0x80, .len = 5 }, /* 6: -.... */ + { .code = 0xc0, .len = 5 }, /* 7: --... */ + { .code = 0xe0, .len = 5 }, /* 8: ---.. */ + { .code = 0xf0, .len = 5 }, /* 9: ----. */ +}; + +/*! Symbol table: "letters" */ +static const struct morse_sym_table_t morse_letters[] = { + { .code = 0x40, .len = 2 }, /* A: .- */ + { .code = 0x80, .len = 4 }, /* B: -... */ + { .code = 0xa0, .len = 4 }, /* C: -.-. */ + { .code = 0x80, .len = 3 }, /* D: -.. */ + { .code = 0x00, .len = 1 }, /* E: . */ + { .code = 0x20, .len = 4 }, /* F: ..-. */ + { .code = 0xc0, .len = 3 }, /* G: --. */ + { .code = 0x00, .len = 4 }, /* H: .... */ + { .code = 0x00, .len = 2 }, /* I: .. */ + { .code = 0x70, .len = 4 }, /* J: .--- */ + { .code = 0xa0, .len = 3 }, /* K: -.- */ + { .code = 0x40, .len = 4 }, /* L: .-.. */ + { .code = 0xc0, .len = 2 }, /* M: -- */ + { .code = 0x80, .len = 2 }, /* N: -. */ + { .code = 0xe0, .len = 3 }, /* O: --- */ + { .code = 0x60, .len = 4 }, /* P: .--. */ + { .code = 0xd0, .len = 4 }, /* Q: --.- */ + { .code = 0x40, .len = 3 }, /* R: .-. */ + { .code = 0x00, .len = 3 }, /* S: ... */ + { .code = 0x80, .len = 1 }, /* T: - */ + { .code = 0x20, .len = 3 }, /* U: ..- */ + { .code = 0x10, .len = 4 }, /* V: ...- */ + { .code = 0x60, .len = 3 }, /* W: .-- */ + { .code = 0x90, .len = 4 }, /* X: -..- */ + { .code = 0xb0, .len = 4 }, /* Y: -.-- */ + { .code = 0xc0, .len = 4 }, /* Z: --.. */ +}; + +static void morse_next_sym(struct morse_player_t* const morse_player) +{ + struct sfx_player_t* sfx_player = &(morse_player->sfx_player); + + if (!morse_player->msg) { + sfx_play(sfx_player, NULL); + return; + } + + uint8_t sym_rem = 0; + uint8_t sym_code = 0; + const struct morse_sym_table_t* sym = NULL; + const char* c = morse_player->msg; + + while(!sym) { + if ((*c >= 'A') && (*c <= 'Z')) + /* Play a letter. (capitals) */ + sym = &morse_letters[*c - 'A']; + else if ((*c >= 'a') && (*c <= 'z')) + /* Play a letter. (lowercase) */ + sym = &morse_letters[*c - 'a']; + else if ((*c >= '0') && (*c <= '9')) + /* Play a digit. */ + sym = &morse_digits[*c - '0']; + else if (*c == 0) { + morse_player->msg = NULL; + return; + } + c++; + } + morse_player->msg = c; + + struct sfx_note_t* note = morse_player->sym; + sym_rem = sym->len; + sym_code = sym->code; + + while(sym_rem) { + note->freq = morse_player->freq; + if (sym_code & 0x80) + /* Play a "dah" */ + note->duration = morse_player->dit_time*3; + else + /* Play a "dit" */ + note->duration = morse_player->dit_time; + note++; + sym_code <<= 1; + sym_rem--; + + /* A gap follows */ + note->freq = 0; + + if (sym_rem) { + /* More of the character */ + note->duration = morse_player->dit_time; + note++; + } + } + + /* What comes next? */ + if (*c == ' ') { + /* End of word */ + note->duration = morse_player->dit_time*7; + note++; + } else if (*c) { + /* End of character */ + note->duration = morse_player->dit_time*3; + note++; + } + + /* Terminate the sequence */ + note->freq = 0; + note->duration = 0; + + /* Set the player up */ + sfx_play(sfx_player, morse_player->sym); +} + +/*! + * Start playing a particular effect. + * @param sfx_player Effect player state machine + * @param effect Pointer to sound effect (NULL == stop) + */ +void morse_play(struct morse_player_t* const morse_player, + const char* msg) +{ + morse_player->msg = msg; + morse_next_sym(morse_player); +} + +/*! + * Retrieve the next sample to be played. + */ +int16_t morse_next(struct morse_player_t* const morse_player) +{ + if (!morse_player) + return(0); + if (!morse_player->sfx_player.note) + morse_next_sym(morse_player); + return sfx_next(&(morse_player->sfx_player)); +} |
