add morse code

This commit is contained in:
Kizarm 2024-01-18 11:42:56 +01:00
parent bcf1030226
commit 9f6d05a9e4
5 changed files with 158 additions and 66 deletions

View file

@ -16,12 +16,13 @@ CFLAGS = -Wall $(TGT) -Oz -gdwarf-3 -I./$(TARGET) -ffunction-sections -fdata-sec
LFLAGS = -nostart-files --gc-sections -Map=example.map LFLAGS = -nostart-files --gc-sections -Map=example.map
MFLAGS = $(CFLAGS) -fmodules -fprebuilt-module-path=. MFLAGS = $(CFLAGS) -fmodules -fprebuilt-module-path=.
VFLAGS = -std=c++20 -fno-rtti VFLAGS = -std=c++20 -fno-rtti
PFLAGS = c++-module $(TGT) -I./$(TARGET) -fprebuilt-module-path=. -fno-exceptions
VPATH = . ./$(TARGET) VPATH = . ./$(TARGET)
# zdrojaky -> objekty # zdrojaky -> objekty
OBJS = STM32L4x2_startup.o system.o OBJS = STM32L4x2_startup.o system.o
MOBJS = main.o io.o sys.o MOBJS = morse.o io.o sys.o main.o
BOBJS = $(addprefix $(BLD),$(OBJS)) BOBJS = $(addprefix $(BLD),$(OBJS))
@ -30,7 +31,7 @@ all: $(BLD) $(PRJ).elf
# -include $(BLD)*.d # -include $(BLD)*.d
# linker # linker
$(PRJ).elf: $(BOBJS) $(MOBJS) $(PRJ).elf: $(BOBJS) $(MOBJS)
-@echo [LD $(TARGET)] $@ -@echo [LLD $(TARGET)] $@
@$(LD) $(LFLAGS) -o $(PRJ).elf $(BOBJS) $(MOBJS) $(LDLIBS) @$(LD) $(LFLAGS) -o $(PRJ).elf $(BOBJS) $(MOBJS) $(LDLIBS)
-@echo "size:" -@echo "size:"
@$(SIZE) $(PRJ).elf @$(SIZE) $(PRJ).elf
@ -40,7 +41,7 @@ $(PRJ).elf: $(BOBJS) $(MOBJS)
-@echo "OK." -@echo "OK."
# preloz co je potreba # preloz co je potreba
$(BLD)%.o: %.c $(BLD)%.o: %.c
-@echo [CC $(TARGET)] $@ -@echo [CCC $(TARGET)] $@
@$(CC) -c $(CFLAGS) $< -o $@ @$(CC) -c $(CFLAGS) $< -o $@
$(BLD)%.o: %.cpp $(BLD)%.o: %.cpp
-@echo [CXX $(TARGET)] $@ -@echo [CXX $(TARGET)] $@
@ -48,13 +49,15 @@ $(BLD)%.o: %.cpp
$(BLD): $(BLD):
mkdir $(BLD) mkdir $(BLD)
# MODULES # # MODULES #
main.o: main.cpp io.pcm sys.pcm main.o: main.cpp morse.pcm
morse.o: morse.cpp io.pcm sys.pcm
morse.pcm: morse.cpp io.pcm sys.pcm
%.o: %.cpp %.o: %.cpp
-@echo [CXM $(TARGET)] $@ -@echo [CXM $(TARGET)] $@
@$(CXX) $(VFLAGS) -c $(MFLAGS) $< -o $@ @$(CXX) $(VFLAGS) -c $(MFLAGS) $< -o $@
%.pcm: %.cpp %.pcm: %.cpp
-@echo [PRE $(TARGET)] $@ -@echo [PRE $(TARGET)] $@
@$(CXX) $(VFLAGS) -x c++-module $(TGT) -I./$(TARGET) -fno-exceptions $< --precompile -o $@ @$(CXX) $(VFLAGS) -x $(PFLAGS) $< --precompile -o $@
# vycisti # vycisti
clean: clean:
rm -f $(BLD)* *.o *.lst *.bin *.elf *.map *.pcm *~ rm -f $(BLD)* *.o *.lst *.bin *.elf *.map *.pcm *~

View file

@ -6,5 +6,11 @@ použít C++ moduly i v bare metal. Sice se to musí kompilovat
clang ve verzi 18. (a asi i vyšší), postup je poměrně komplikovaný clang ve verzi 18. (a asi i vyšší), postup je poměrně komplikovaný
a nepochopitelný, ale funguje to. Zjevně je to hodně experimentální. 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ý
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 Připadá mi to složité a k ničemu, ale to je právě důvod, proč by
se to mohlo ujmout. se to mohlo ujmout. Třeba v Arduinu.

32
io.cpp
View file

@ -8,57 +8,57 @@ struct GpioAssocPort {
uint32_t clkMask; uint32_t clkMask;
}; };
namespace io {
/** /**
* @brief GPIO Configuration Mode enumeration * @brief GPIO Configuration Mode enumeration
*/ */
typedef enum { enum GPIOMode_TypeDef {
GPIO_Mode_IN = 0x00, /*!< GPIO Input Mode */ GPIO_Mode_IN = 0x00, /*!< GPIO Input Mode */
GPIO_Mode_OUT = 0x01, /*!< GPIO Output Mode */ GPIO_Mode_OUT = 0x01, /*!< GPIO Output Mode */
GPIO_Mode_AF = 0x02, /*!< GPIO Alternate function Mode */ GPIO_Mode_AF = 0x02, /*!< GPIO Alternate function Mode */
GPIO_Mode_AN = 0x03 /*!< GPIO Analog Mode */ GPIO_Mode_AN = 0x03 /*!< GPIO Analog Mode */
}GPIOMode_TypeDef; };
/** /**
* @brief GPIO Output type enumeration * @brief GPIO Output type enumeration
*/ */
typedef enum { enum GPIOOType_TypeDef {
GPIO_OType_PP = 0x00, GPIO_OType_PP = 0x00,
GPIO_OType_OD = 0x01 GPIO_OType_OD = 0x01
}GPIOOType_TypeDef; };
/** /**
* @brief GPIO Output Maximum frequency enumeration * @brief GPIO Output Maximum frequency enumeration
*/ */
typedef enum { enum GPIOSpeed_TypeDef {
GPIO_Speed_LS = 0x00, /*!< Low speed */ GPIO_Speed_LS = 0x00, /*!< Low speed */
GPIO_Speed_MS = 0x01, /*!< Medium speed */ GPIO_Speed_MS = 0x01, /*!< Medium speed */
GPIO_Speed_FS = 0x02, /*!< Fast speed */ GPIO_Speed_FS = 0x02, /*!< Fast speed */
GPIO_Speed_HS = 0x03 /*!< Very High speed */ GPIO_Speed_HS = 0x03 /*!< Very High speed */
}GPIOSpeed_TypeDef; };
/** /**
* @brief GPIO Configuration PullUp PullDown enumeration * @brief GPIO Configuration PullUp PullDown enumeration
*/ */
typedef enum { enum GPIOPuPd_TypeDef {
GPIO_PuPd_NOPULL = 0x00, GPIO_PuPd_NOPULL = 0x00,
GPIO_PuPd_UP = 0x01, GPIO_PuPd_UP = 0x01,
GPIO_PuPd_DOWN = 0x02 GPIO_PuPd_DOWN = 0x02
}GPIOPuPd_TypeDef; };
/** Vstupní parametry metod */ /** Vstupní parametry metod */
typedef enum { enum GPIODir_TypeDef {
GPIO_Dir_Mode_IN = 0x00, /*!< GPIO Input Mode */ GPIO_Dir_Mode_IN = 0x00, /*!< GPIO Input Mode */
GPIO_Dir_Mode_OUT = 0x01, /*!< GPIO Output Mode */ GPIO_Dir_Mode_OUT = 0x01, /*!< GPIO Output Mode */
} GPIODir_TypeDef; };
/// Enum pro PortNumber /// Enum pro PortNumber
typedef enum { enum GpioPortNum {
GpioPortA, GpioPortA = 0,
GpioPortB, GpioPortB,
GpioPortC, GpioPortC,
GpioPortD, GpioPortD,
GpioPortE, GpioPortE,
GpioPortH, GpioPortH,
} GpioPortNum; };
namespace io {
/** @file /** @file
* @brief Obecný GPIO pin. * @brief Obecný GPIO pin.
* *
@ -76,8 +76,8 @@ namespace io {
GpioClass (GpioPortNum const port, const uint32_t no, const GPIOMode_TypeDef type = GPIO_Mode_OUT); GpioClass (GpioPortNum const port, const uint32_t no, const GPIOMode_TypeDef type = GPIO_Mode_OUT);
/// Nastav pin @param b na tuto hodnotu /// Nastav pin @param b na tuto hodnotu
const GpioClass& operator<< (const bool b) const { const GpioClass& operator<< (const bool b) const {
if (b) io->BSRR.R = (uint32_t) pos; const uint32_t sh = b ? pos : pos << 16;
else io->BSRR.R = (uint32_t) pos << 16; io->BSRR.R = sh;
return *this; return *this;
} }
/// Nastav pin na log. H /// Nastav pin na log. H

View file

@ -1,14 +1,10 @@
/* SIMPLE EXAMPLE: LED blinking */ /* SIMPLE EXAMPLE: LED blinking */
import io; // use module !!! import morse; // use module !!!
import sys;
////////////////////////////////////// //////////////////////////////////////
static io::GpioClass led (GpioPortA, 10);
int main () { int main () {
sys::init (); Morse morse (330);
for (;;) { for (;;) {
~led; // change status - unary ~ morse << "Hello world";
sys::delay ();
} }
return 0; return 0;
} }

87
morse.cpp Normal file
View file

@ -0,0 +1,87 @@
module;
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;
}
export class Morse {
const unsigned unit;
const io::GpioClass led;
public:
explicit Morse (const unsigned ms = 100) noexcept : unit (ms), led (io::GpioPortA, 10) {
sys::init ();
}
void operator<< (const char * text) const;
protected:
void out (const char * text) 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;
if (c < '\x20') {
mp = morse_code [0];
} else if (c < '`') {
const int i = c - '\x20';
mp = morse_code [i];
} else if (c == '`') {
mp = morse_code [0];
} else if (c <= 'z') {
const int i = c - '\x40';
mp = morse_code [i];
} else {
mp = morse_code [0];
}
if (!mp) return;
out (mp);
}
sys::delay (10 * unit);
}
/* . => 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 char * text) const {
const unsigned len = slen(text);
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);
}
led << false;
}
sys::delay (3 * unit);
}