RS41ng/src/codecs/morse/morse.c

266 wiersze
6.8 KiB
C

#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include "morse.h"
// Morse code definitions adapted from code by Mark Jessop VK5QI and OK1TE, also based on
// https://github.com/Paradoxis/Arduino-morse-code-translator/blob/master/main.ino
#define MORSE_UNITS_DOT 1
#define MORSE_UNITS_DASH 3
#define MORSE_UNITS_GAP 3
#define MORSE_UNITS_SPACE 7
const char MORSE_DOT = '.';
const char MORSE_DASH = '-';
const char MORSE_SPACE = ' ';
const char *const morse_letters[] = {
".-", // A
"-...", // B
"-.-.", // C
"-..", // D
".", // E
"..-.", // F
"--.", // G
"....", // H
"..", // I
".---", // J
"-.-", // K
".-..", // L
"--", // M
"-.", // N
"---", // O
".--.", // P
"--.-", // Q
".-.", // R
"...", // S
"-", // T
"..-", // U
"...-", // V
".--", // W
"-..-", // X
"-.--", // Y
"--.." // Z
};
const char *const morse_numbers[] = {
"-----", // 0
".----", // 1
"..---", // 2
"...--", // 3
"....-", // 4
".....", // 5
"-....", // 6
"--...", // 7
"---..", // 8
"----." // 9
};
const char morse_stroke[] = "-..-.";
const char morse_equal[] = "-...-";
const char morse_full_stop[] = ".-.-.-";
const char morse_comma[] = "--..--";
const char morse_question_mark[] = "..--..";
const char morse_plus[] = ".-.-.";
const char morse_at_sign[] = ".--.-.";
const char morse_space[] = " ";
static const char *morse_get_sequence(char c)
{
if (c >= 'A' && c <= 'Z') { // Uppercase letters
return morse_letters[c - 'A'];
} else if (c >= 'a' && c <= 'z') { // Lowercase letters
return morse_letters[c - 'a'];
} else if (c >= '0' && c <= '9') { // Numbers
return morse_numbers[c - '0'];
}
switch (c) {
case '/':
return morse_stroke;
case '=':
return morse_equal;
case '.':
return morse_full_stop;
case ',':
return morse_comma;
case '?':
return morse_question_mark;
case '+':
return morse_plus;
case '@':
return morse_at_sign;
default:
// Treat all other characters as a space
return morse_space;
}
}
typedef struct _morse_encoder {
uint32_t symbol_rate;
uint16_t data_length;
uint8_t *data;
uint16_t current_byte_index;
const char *current_sequence;
uint8_t current_sequence_index;
bool tone_active;
uint8_t units_left;
bool start;
fsk_tone tones[2];
} morse_encoder;
void morse_encoder_new(fsk_encoder *encoder, uint32_t symbol_rate)
{
encoder->priv = malloc(sizeof(morse_encoder));
memset(encoder->priv, 0, sizeof(morse_encoder));
morse_encoder *morse = (morse_encoder *) encoder->priv;
morse->symbol_rate = symbol_rate;
for (int i = 0; i < 2; i++) {
morse->tones[i].index = (int8_t) i;
morse->tones[i].frequency_hz_100 = i;
}
}
void morse_encoder_destroy(fsk_encoder *encoder)
{
if (encoder->priv != NULL) {
free(encoder->priv);
encoder->priv = NULL;
}
}
void morse_encoder_set_data(fsk_encoder *encoder, uint16_t data_length, uint8_t *data)
{
morse_encoder *morse = (morse_encoder *) encoder->priv;
morse->data = data;
morse->data_length = data_length;
morse->current_byte_index = 0;
morse->current_sequence = morse_get_sequence((char) data[0]);
morse->current_sequence_index = 0;
morse->tone_active = false;
morse->units_left = 0;
morse->start = true;
}
void morse_encoder_get_tones(fsk_encoder *encoder, int8_t *tone_count, fsk_tone **tones)
{
morse_encoder *morse = (morse_encoder *) encoder->priv;
*tone_count = 2;
*tones = morse->tones;
}
uint32_t morse_encoder_get_tone_spacing(fsk_encoder *encoder)
{
return 0;
}
uint32_t morse_encoder_get_symbol_rate(fsk_encoder *encoder)
{
morse_encoder *morse = (morse_encoder *) encoder->priv;
return morse->symbol_rate;
}
uint32_t morse_encoder_get_symbol_delay(fsk_encoder *encoder)
{
return 0;
}
int8_t morse_encoder_next_tone(fsk_encoder *encoder)
{
morse_encoder *morse = (morse_encoder *) encoder->priv;
if (morse->current_byte_index >= morse->data_length) {
return -1;
}
if (!morse->start && morse->units_left == 0) {
char next_element = morse->current_sequence[morse->current_sequence_index + 1];
if (morse->tone_active) {
if (next_element == 0) {
bool char_gap = true;
if (morse->current_byte_index + 1 < morse->data_length) {
const char *next_byte_sequence = morse_get_sequence((char) morse->data[morse->current_byte_index + 1]);
if (next_byte_sequence[0] == MORSE_SPACE) {
char_gap = false;
}
} else {
char_gap = false;
}
if (char_gap) {
// Char gap
morse->tone_active = false;
morse->units_left = MORSE_UNITS_GAP - 1;
return 0;
}
} else {
// Unit gap
morse->tone_active = false;
return 0;
}
}
morse->current_sequence_index++;
if (next_element == 0) {
morse->current_byte_index++;
if (morse->current_byte_index >= morse->data_length) {
return -1;
}
morse->current_sequence = morse_get_sequence((char) morse->data[morse->current_byte_index]);
morse->current_sequence_index = 0;
morse->tone_active = false;
}
}
morse->start = false;
char element = morse->current_sequence[morse->current_sequence_index];
if (morse->units_left > 0) {
morse->units_left--;
return morse->tone_active ? 1 : 0;
}
if (element == MORSE_DOT) {
morse->units_left = MORSE_UNITS_DOT;
morse->tone_active = true;
} else if (element == MORSE_DASH) {
morse->units_left = MORSE_UNITS_DASH;
morse->tone_active = true;
} else {
morse->units_left = MORSE_UNITS_SPACE;
morse->tone_active = false;
}
morse->units_left--;
return morse->tone_active ? 1 : 0;
}
fsk_encoder_api morse_fsk_encoder_api = {
.get_tones = morse_encoder_get_tones,
.get_tone_spacing = morse_encoder_get_tone_spacing,
.get_symbol_rate = morse_encoder_get_symbol_rate,
.get_symbol_delay = morse_encoder_get_symbol_delay,
.set_data = morse_encoder_set_data,
.next_tone = morse_encoder_next_tone,
};