compress morse code

This commit is contained in:
Kizarm 2024-01-19 13:04:24 +01:00
parent 9f6d05a9e4
commit f6db62d0cf
5 changed files with 98 additions and 41 deletions

2
.gitignore vendored
View file

@ -9,3 +9,5 @@ bld/*
*.map
*.bin
*.elf
tabgen
table.cpp

View file

@ -48,10 +48,14 @@ $(BLD)%.o: %.cpp
@$(CXX) $(VFLAGS) -c $(CFLAGS) $< -o $@
$(BLD):
mkdir $(BLD)
tabgen: tabgen.cpp
$(CXX) -Oz tabgen.cpp -o tabgen
table.cpp: tabgen
./tabgen
# MODULES #
main.o: main.cpp morse.pcm
morse.o: morse.cpp io.pcm sys.pcm
morse.pcm: morse.cpp io.pcm sys.pcm
morse.o: morse.cpp table.cpp io.pcm sys.pcm
morse.pcm: morse.cpp table.cpp io.pcm sys.pcm
%.o: %.cpp
-@echo [CXM $(TARGET)] $@
@$(CXX) $(VFLAGS) -c $(MFLAGS) $< -o $@
@ -60,5 +64,5 @@ morse.pcm: morse.cpp io.pcm sys.pcm
@$(CXX) $(VFLAGS) -x $(PFLAGS) $< --precompile -o $@
# vycisti
clean:
rm -f $(BLD)* *.o *.lst *.bin *.elf *.map *.pcm *~
rm -f $(BLD)* *.o *.lst *.bin *.elf *.map *.pcm *~ table.cpp tabgen
.PHONY: all clean

View file

@ -9,7 +9,7 @@ a nepochopitelný, ale funguje to. Zjevně je to hodně experimentální.
Moduly mohou mít hierarchickou strukturu a opravdu nejsou potřeba
něco jako hlavičky. Ovšem distribuovat takto knihovny jednoduše
nejde. Prostě musí k tomu být zdrojáky a ty je potřeba přeložit
specifickým (a dost komlikovaným) způsobem. Negeneruje to žádný
specifickým (a dost komplikovaným) způsobem. Negeneruje to žádný
overhead, alespoň v tomto jednoduchém příkladu.
Připadá mi to složité a k ničemu, ale to je právě důvod, proč by

View file

@ -3,27 +3,26 @@ import sys;
import io;
export module morse;
static const char * const morse_code [] = { /* nedefinované znaky nahrazeny mezrou */
" ", /* */ " ", /*!*/ ".-..-.", /*"*/ " ", /*#*/ " ", /*$*/
" ", /*%*/ " ", /*&*/ ".----.", /*'*/ "-.--.", /*(*/ "-.--.-", /*)*/
" ", /***/ ".-.-.", /*+*/ "--..--", /*,*/ "-....-", /*-*/ ".-.-.-", /*.*/ "-..-." , /*/*/
"-----", /*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 unsigned slen (const char * str) {
unsigned n = 0;
while (*str++) n++;
return n;
}
union morse_byte {
struct {
unsigned char bits : 5;
unsigned char mlen : 3;
};
unsigned char byte;
explicit constexpr morse_byte () noexcept : byte (0u) {}
};
/* Použijeme vygenerovanou tabulku,
* je naprosto nečitelná, ale z čitelného kódu.
*
* Jsme v bare metal, tak ušetříme každý byte,
* to stojí co chce (je to cca 500 bytů).
*/
#include "table.cpp"
export class Morse {
const unsigned unit;
const io::GpioClass led;
@ -34,28 +33,24 @@ export class Morse {
}
void operator<< (const char * text) const;
protected:
void out (const char * text) const;
void out (const morse_byte mb) const;
};
void Morse::operator<< (const char * text) const {
const unsigned len = slen (text);
for (unsigned n=0; n<len; n++) {
const char c = text [n];
const char * mp = nullptr;
morse_byte mb;
if (c < '\x20') {
mp = morse_code [0];
} else if (c < '`') {
const int i = c - '\x20';
mp = morse_code [i];
mb.byte = compressed_table [i];
} else if (c == '`') {
mp = morse_code [0];
} else if (c <= 'z') {
const int i = c - '\x40';
mp = morse_code [i];
mb.byte = compressed_table [i];
} else {
mp = morse_code [0];
}
if (!mp) return;
out (mp);
out (mb);
}
sys::delay (10 * unit);
}
@ -65,21 +60,22 @@ void Morse::operator<< (const char * text) const {
* mezera mezi znaky => 3 x unit
* mezera mezi slovy => 7 x unit
* */
void Morse::out (const char * text) const {
const unsigned len = slen(text);
void Morse::out (const morse_byte mb) const {
/* 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) { sys::delay (4 * unit); return; }
for (unsigned n=0; n<len; n++) {
led << false;
sys::delay (unit);
const char c = text [n];
if (c == '.') {
led << true;
sys::delay (1 * unit);
} else if (c == '-') {
led << true;
sys::delay (3 * unit);
} else {
sys::delay (4 * unit);
}
const unsigned v = (1u << n) & mb.bits;
const unsigned d = v ? 3u : 1u;
led << true;
sys::delay (d * unit);
led << false;
}
sys::delay (3 * unit);

55
tabgen.cpp Normal file
View file

@ -0,0 +1,55 @@
#include <cstdio>
#include <cstring>
#if __BYTE_ORDER__ != 1234
#error "BAD ENDIAN"
#endif
static const char * oname = "table.cpp";
static const char * const morse_code [] = { /* nedefinované znaky nahrazeny mezrou */
" ", /* */ " ", /*!*/ ".-..-.", /*"*/ " ", /*#*/ " ", /*$*/
" ", /*%*/ " ", /*&*/ ".----.", /*'*/ "-.--.", /*(*/ "-.--.-", /*)*/
" ", /***/ ".-.-.", /*+*/ "--..--", /*,*/ "-....-", /*-*/ ".-.-.-", /*.*/ "-..-." , /*/*/
"-----", /*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*/ " ", " ", " ", " ", "..--.-", /*_*/
};
union morse_byte {
struct {
unsigned char bits : 5; // Jednotlivé bity.
unsigned char mlen : 3; // A jejich délka - max 6.
}; // Pokud je 6 nebo 7, pak je nejnižší bit zároveň součástí bitů
unsigned char byte;
explicit constexpr morse_byte () noexcept : byte (0u) {}
};
static morse_byte compress (const unsigned n) {
const char * const ptr = morse_code [n];
const unsigned len = strlen (ptr);
morse_byte mb;
if (ptr [0] == ' ') return mb;
mb.mlen = len;
for (unsigned n=0; n<len; n++) {
if (ptr [n] == '-') mb.byte |= (1u << n);
}
return mb;
}
/* Generátor komprimované tabulky morse kódů */
int main () {
FILE * out = fopen(oname, "w");
if (!out) return 1;
unsigned n = 0u;
fprintf(out, "static const unsigned char compressed_table [] = {");
for (auto & e: morse_code) {
if ((n & 0xf) == 0u) fprintf(out, "\n");
fprintf(out, " 0x%02x,", compress(n).byte);
n += 1u;
}
fprintf(out, "\n};\n");
fclose (out);
return 0;
}