88 lines
3.2 KiB
C++
88 lines
3.2 KiB
C++
|
#include "morse.h"
|
||
|
#include "utils.h"
|
||
|
// Spočteme číslo (pro 1kHz) jako (1000 << 32) / 24000 (24 kHz je samplerate).
|
||
|
static constexpr unsigned F0 = (1000ull << 32) / 24000u;
|
||
|
|
||
|
static constexpr const char * const morse_code [] = { /* nedefinované znaky nahrazeny mezerou */
|
||
|
" ", /* */ " ", /*!*/ ".-..-.", /*\"*/ " ", /*#*/ " ", /*$*/
|
||
|
" ", /*%*/ " ", /*&*/ ".----.", /*\'*/ "-.--.", /*(*/ "-.--.-", /*)*/
|
||
|
" ", /***/ ".-.-.", /*+*/ "--..--", /*,*/ "-....-", /*-*/ ".-.-.-", /*.*/ "-..-." , /*/*/
|
||
|
"-----", /*0*/ ".----", /*1*/ "..---", /*2*/ "...--", /*3*/ "....-", /*4*/
|
||
|
".....", /*5*/ "-....", /*6*/ "--...", /*7*/ "---..", /*8*/ "----.", /*9*/
|
||
|
"---...", /*:*/ "-.-.-.", /*;*/ " ", /*<*/ "-...-" , /*=*/ " ", /*>*/ "..--..", /*?*/
|
||
|
".--.-.", /*@*/
|
||
|
".-", /*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*/ " ", " ", " ", " ", "..--.-", /*_*/
|
||
|
};
|
||
|
static constexpr unsigned slen (const char * const str) {
|
||
|
unsigned n = 0;
|
||
|
while (str[n]) n++;
|
||
|
return n;
|
||
|
}
|
||
|
static const TABLE<unsigned char, array_size (morse_code)> compressed_table
|
||
|
([](const unsigned n) -> auto {
|
||
|
const char * const ptr = morse_code [n];
|
||
|
const unsigned len = slen (ptr);
|
||
|
unsigned char mb = 0u;
|
||
|
if (ptr [0] == ' ') return mb;
|
||
|
mb = (len & 7u) << 5;
|
||
|
for (unsigned n=0; n<len; n++) {
|
||
|
if (ptr [n] == '-') mb |= (1u << n);
|
||
|
}
|
||
|
return mb;
|
||
|
});
|
||
|
|
||
|
Morse::Morse(const GpioClass & pin, const unsigned int ms) noexcept : unit (ms), led (pin),
|
||
|
gen (F0), pwm () {
|
||
|
pwm.attach(gen);
|
||
|
}
|
||
|
const Morse & Morse::operator<< (const char * text) {
|
||
|
for (unsigned n=0; ; n++) {
|
||
|
const char c = text [n];
|
||
|
if (c == '\0') break;
|
||
|
morse_byte mb;
|
||
|
if (c < '\x20') {
|
||
|
} else if (c < '`') {
|
||
|
const int i = c - '\x20';
|
||
|
mb.byte = compressed_table [i];
|
||
|
} else if (c == '`') {
|
||
|
} else if (c <= 'z') {
|
||
|
const int i = c - '\x40';
|
||
|
mb.byte = compressed_table [i];
|
||
|
} else {
|
||
|
}
|
||
|
out (mb);
|
||
|
}
|
||
|
gen.delay (10 * unit);
|
||
|
return * this;
|
||
|
}
|
||
|
/* . => 1 x unit
|
||
|
* - => 3 x unit
|
||
|
* mezera mezi značkami => 1 x unit
|
||
|
* mezera mezi znaky => 3 x unit
|
||
|
* mezera mezi slovy => 7 x unit
|
||
|
* */
|
||
|
void Morse::out (const morse_byte mb) {
|
||
|
/* Finta je v tom, že i když se pole mlen a bits překrývají,
|
||
|
* nevadí to - maximální délka je 6, takže v nejnižším bitu
|
||
|
* mlen může být obsažen 1 bit 6.bitového znaku.
|
||
|
* Takhle napsáno to běhá jen na malém indiánu, přepisovat
|
||
|
* to do bitových posunů nebudu, i když by to bylo čistší.
|
||
|
* */
|
||
|
const unsigned len = mb.mlen > 6u ? 6u : mb.mlen;
|
||
|
if (!len) { gen.delay (4 * unit); return; }
|
||
|
for (unsigned n=0; n<len; n++) {
|
||
|
off ();
|
||
|
gen.delay (unit);
|
||
|
const unsigned v = (1u << n) & mb.bits;
|
||
|
const unsigned d = v ? 3u : 1u;
|
||
|
on ();
|
||
|
gen.delay (d * unit);
|
||
|
off ();
|
||
|
}
|
||
|
gen.delay (3 * unit);
|
||
|
}
|