mirror of https://github.com/nealey/puzzle-box.git
121 lines
2.8 KiB
C++
121 lines
2.8 KiB
C++
|
#include "morse.h"
|
||
|
|
||
|
// Each morse dit/dah is stored as a nybble
|
||
|
|
||
|
#define dit 1
|
||
|
#define dah 3
|
||
|
|
||
|
#define Pack(a, b, c, d) ((a << 0) | (b << 2) | (c << 4) | (d << 6))
|
||
|
#define Unpack(m, pos) ((m >> (pos * 2)) & 0b11)
|
||
|
|
||
|
const uint8_t MorseLetters[] = {
|
||
|
Pack(dit, dah, 0, 0), // A
|
||
|
Pack(dah, dit, dit, dit), // B
|
||
|
Pack(dah, dit, dah, dit), // C
|
||
|
Pack(dah, dit, dit, 0), // D
|
||
|
Pack(dit, 0, 0, 0), // E
|
||
|
Pack(dit, dit, dah, dit), // F
|
||
|
Pack(dah, dah, dit, 0), // G
|
||
|
Pack(dit, dit, dit, dit), // H
|
||
|
Pack(dit, dit, 0, 0), // I
|
||
|
Pack(dit, dah, dah, dah), // J
|
||
|
Pack(dah, dit, dah, 0), // K
|
||
|
Pack(dit, dah, dit, dit), // L
|
||
|
Pack(dah, dah, 0, 0), // M
|
||
|
Pack(dah, dit, 0, 0), // N
|
||
|
Pack(dah, dah, dah, 0), // O
|
||
|
Pack(dit, dah, dah, dit), // P
|
||
|
Pack(dah, dah, dit, dah), // Q
|
||
|
Pack(dit, dah, dit, 0), // R
|
||
|
Pack(dit, dit, dit, 0), // S
|
||
|
Pack(dah, 0, 0, 0), // T
|
||
|
Pack(dit, dit, dah, 0), // U
|
||
|
Pack(dit, dit, dit, dah), // V
|
||
|
Pack(dit, dah, dah, 0), // W
|
||
|
Pack(dah, dit, dit, dah), // X
|
||
|
Pack(dah, dit, dah, dah), // Y
|
||
|
Pack(dah, dah, dit, dit), // Z
|
||
|
};
|
||
|
|
||
|
MorseEncoder::MorseEncoder() {
|
||
|
SetText("");
|
||
|
}
|
||
|
MorseEncoder::MorseEncoder(const char *s) {
|
||
|
SetText(s);
|
||
|
}
|
||
|
|
||
|
void MorseEncoder::SetText(const char *s) {
|
||
|
p = s;
|
||
|
crumb = 0;
|
||
|
ticksLeft = 0;
|
||
|
Transmitting = false;
|
||
|
}
|
||
|
|
||
|
void MorseEncoder::Quiet(int ticks) {
|
||
|
Transmitting = false;
|
||
|
ticksLeft = ticks;
|
||
|
}
|
||
|
|
||
|
bool MorseEncoder::Tick() {
|
||
|
--ticksLeft;
|
||
|
if (ticksLeft > 0) {
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
// We're out of ticks
|
||
|
|
||
|
if (!p || !*p) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
// If we were just transmitting, we have to stop for at least one dit
|
||
|
if (Transmitting) {
|
||
|
Transmitting = false;
|
||
|
ticksLeft = MORSE_DIT;
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
// If that was the end of the letter, we have to pause more
|
||
|
if (crumb == 4) {
|
||
|
crumb = 0;
|
||
|
++p;
|
||
|
ticksLeft = MORSE_PAUSE_LETTER - MORSE_DIT;
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
switch (*p) {
|
||
|
case '\0':
|
||
|
return false;
|
||
|
case 'a' ... 'z':
|
||
|
Transmitting = true;
|
||
|
ticksLeft = Unpack(MorseLetters[*p - 'a'], crumb++);
|
||
|
break;
|
||
|
case 'A' ... 'Z':
|
||
|
Transmitting = true;
|
||
|
ticksLeft = Unpack(MorseLetters[*p - 'A'], crumb++);
|
||
|
break;
|
||
|
case ' ':
|
||
|
crumb = 0;
|
||
|
++p;
|
||
|
Transmitting = false;
|
||
|
ticksLeft = MORSE_PAUSE_WORD - MORSE_DIT;
|
||
|
break;
|
||
|
default: // this should never happen! Transmit for a word pause to indicate weirdness.
|
||
|
crumb = 0;
|
||
|
++p;
|
||
|
Transmitting = true;
|
||
|
ticksLeft = MORSE_PAUSE_WORD;
|
||
|
break;
|
||
|
}
|
||
|
if (0 == ticksLeft) {
|
||
|
// Unpack can return 0 if there are fewer than 4 emissions for a letter.
|
||
|
// In that case, we 're done with the letter.
|
||
|
crumb = 0;
|
||
|
++p;
|
||
|
Transmitting = false;
|
||
|
ticksLeft = MORSE_PAUSE_LETTER - MORSE_DIT;
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|