CharGraphs added
This commit is contained in:
parent
679cfab9e8
commit
520bcf7d7f
134
include/WordFinder.h
Normal file
134
include/WordFinder.h
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
/**
|
||||
* CharGraph - Unified Word Finder
|
||||
*
|
||||
* Central component for finding words in patterns
|
||||
* Handles both PROGMEM patterns (for validation) and regular strings (for display)
|
||||
* Shared between CharGraphTimeLogic and rgbPanel
|
||||
*/
|
||||
|
||||
#ifndef WORD_FINDER_H
|
||||
#define WORD_FINDER_H
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
// ============================================================================
|
||||
// PROGMEM WORD SEARCH (for validation)
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* Find word in PROGMEM pattern starting from position
|
||||
* Both pattern and word are in PROGMEM
|
||||
*
|
||||
* @param pattern_progmem Pattern string in PROGMEM
|
||||
* @param word_progmem Word pointer in PROGMEM
|
||||
* @param searchStart Start position for search (default 0)
|
||||
* @return Position of word, or -1 if not found
|
||||
*/
|
||||
inline int16_t findWordProgmem(const char* pattern_progmem, const char* word_progmem, uint16_t searchStart = 0) {
|
||||
if (!pattern_progmem || !word_progmem) return -1;
|
||||
|
||||
// Load word from PROGMEM into buffer (max 11 chars: DREIVIERTEL)
|
||||
char wordBuf[12]; // 11 chars + null terminator
|
||||
strcpy_P(wordBuf, word_progmem);
|
||||
uint8_t wordLen = strlen(wordBuf);
|
||||
|
||||
// Search through pattern_progmem byte by byte
|
||||
uint16_t pos = searchStart;
|
||||
while (true) {
|
||||
char patByte = pgm_read_byte(pattern_progmem + pos);
|
||||
if (patByte == '\0') break; // End of pattern
|
||||
|
||||
// Check if word matches at this position
|
||||
bool match = true;
|
||||
for (uint8_t i = 0; i < wordLen; i++) {
|
||||
char p = pgm_read_byte(pattern_progmem + pos + i);
|
||||
if (p != wordBuf[i]) {
|
||||
match = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (match) return pos;
|
||||
pos++;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// STRING WORD SEARCH (for display)
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* Find word in regular string with occurrence support
|
||||
*
|
||||
* @param text String to search in
|
||||
* @param word Word to find
|
||||
* @param occurrence Which occurrence to find (0 = first, 1 = second, etc.)
|
||||
* @param searchBackward Search backward from end
|
||||
* @return Position of word, or -1 if not found
|
||||
*/
|
||||
inline int findWordString(const char* text, const char* word, int occurrence = 0, bool searchBackward = false) {
|
||||
if (!text || !word) return -1;
|
||||
|
||||
const int wordLen = strlen(word);
|
||||
const int textLen = strlen(text);
|
||||
|
||||
if (searchBackward) {
|
||||
// Backward search: from end to beginning
|
||||
int foundCount = 0;
|
||||
for (int pos = textLen - wordLen; pos >= 0; --pos) {
|
||||
bool match = true;
|
||||
for (int j = 0; j < wordLen; ++j) {
|
||||
unsigned char c1 = text[pos + j];
|
||||
unsigned char c2 = word[j];
|
||||
|
||||
// Lowercase comparison (case-insensitive)
|
||||
if (c1 >= 'A' && c1 <= 'Z') c1 += ('a' - 'A');
|
||||
if (c2 >= 'A' && c2 <= 'Z') c2 += ('a' - 'A');
|
||||
|
||||
if (c1 != c2) {
|
||||
match = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (match) {
|
||||
if (foundCount == occurrence) {
|
||||
return pos;
|
||||
}
|
||||
foundCount++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Forward search: from beginning to end
|
||||
int foundCount = 0;
|
||||
for (int pos = 0; pos <= textLen - wordLen; ++pos) {
|
||||
bool match = true;
|
||||
for (int j = 0; j < wordLen; ++j) {
|
||||
unsigned char c1 = text[pos + j];
|
||||
unsigned char c2 = word[j];
|
||||
|
||||
// Lowercase comparison (case-insensitive)
|
||||
if (c1 >= 'A' && c1 <= 'Z') c1 += ('a' - 'A');
|
||||
if (c2 >= 'A' && c2 <= 'Z') c2 += ('a' - 'A');
|
||||
|
||||
if (c1 != c2) {
|
||||
match = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (match) {
|
||||
if (foundCount == occurrence) {
|
||||
return pos;
|
||||
}
|
||||
foundCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
#endif // WORD_FINDER_H
|
||||
|
|
@ -3,10 +3,30 @@
|
|||
|
||||
//Hier Umlaute wie Ö und Ü bereits durch o und u wegen UTF8 ersetzen!!!!
|
||||
|
||||
const char DEFAULT_CHARSOAP[] = "ESHISTRFASTKURZVIERTELFuNFZWANZIGAZEHNJNACHRVORWHALBKLBZWEINSECHSEELFVIERACHTFuNFSIEBENITDREIZWoLFZZEHNEUNLUHR"; //119
|
||||
const char DEFAULT_CHARSOAP[] PROGMEM = "ESPISTGZEHNFuNFVIERTELVORNACHBALDHALBGZWEINSWCDLZIAXMTVZEHNEUNACHTELFuNFZWoLFSECHSIEBENBGDREIVIERZECRPFACWLUHR";//DLZIAX
|
||||
//"ESYISTHZEHNFuNFVIERTELVORNACHBALDHALBUZWEINSDG6MSMARTINZEHNEUNACHTELFuNFZWoLFSECHSIEBENBXDREIVIERLUWRNFACWFUHR";//DG6MS
|
||||
//"ESYISTMZEHNFuNFVIERTELVORNACHBALDHALBDZWEINSNZUXHAUSEMZZEHNEUNACHTELFuNFZWoLFSECHSIEBENHXDREIVIERKNOTPAUSECUHR";//Böcker
|
||||
//"ESQISTFZEHNFuNFVIERTELVORNACHBALDHALBFYZWEITJEGARTNERVDELFuNFZWoLFZEHNEUNACHTXDREINSVIERSECHSIEBENCRWDSIMONUHR";//GARTNERSIMON
|
||||
//"ESQISTOZEHNFuNFVIERTLEVORNACHBALDHALBPJZWEIOVQGARTNERCAELFuNFZWoLFZEHNEUNACHTYDREINSVIERSECHSIEBENLRWDTZEITUHR";//GÄRTNER
|
||||
//"ESHISTQBALDVIERTELFuNFKURZEHNUVORVNACHTAHALBACHTZEHNEUNLIMONCIELLOXVIERIYZWEIELFZWoLFuNFDREINSIEBENSECHSRWDUHR";//LIMONCIELLO
|
||||
//"ESHISTQBALDVIERTELFuNFKURZEHNUVORVNACHTAHALBACHTZEHNEUNLIMONCIELLOXVIERIYZWEIELFZWoLFuNFDREINSIEBENSECHSRWDUHR";//Limonciello
|
||||
//"ESJISTSBALDVIERTELFuNFKURZEHNIVORINACHZOHALBGRDNEUSSOBHACHTZEHNEUNHVIERTBZWEIELFZWoLFuNFDREINSIEBENSECHSWCFUHR";//NEUSS
|
||||
//"ESHISTGFuNFZEHNVIERTELVORFASTNACHHALBALKZWEIFCAROLAZEITDREINSIEBENELFZWoLFuNFZEHNEUNACHTOSECHSVIERGFURWDUWEUHR";//Carola
|
||||
//"ESMISTKBALDFuNFASTZEHNVIERTELMVORKNACHPHALBDHANNESKBRAUZWoLFuNFHWADREIELFVIERSECHSIEBENARZWEINSJXLUZEHNEUNACHT";//Uwe Kleinhans
|
||||
//"ESOISTNZEHNFuNFVIERTELVORNACHBALDHALBEZWEINSONEAFAMILYAZEHNEUNACHTELFuNFZWoLFSECHSIEBENKFREIVIERTLYAMPAUSEIUHR"; //Breunig
|
||||
//"ESXISTXFASTBALDKURZEHNFuNFVIERTELVOROBNACHGEBGZPAULHALBDREINSZWEIJELFVIERFuNFZEHNEUNACHTOSECHSIEBENZWoLFRDWUHR";// LASKAI
|
||||
//"ESHISTCKURZSIVOTXZEHNMFuNFVIERTELVORNACHBALDHALBXEINSMEZEHNEUNZWEIELFuNFZWoLFSECHSIEBENXMDREIVIERVILRACHTSYUHR";//Harald Mück
|
||||
//"ESKISTHZEHNFuNFVIERTELVORNACHBALDHALBPZWEINSAXISIHTHEMZWATERMELONSELFuNFZWoLFSECHSIEBENTXDREIVIERECZEHNEUNACHT"; //ISI THE WATERMELON
|
||||
//"ESHISTPZEHNFuNFVIERTELVORNACHBALDHALBWZWEINSELFuNFZWoLFZEHNEUNACHTDREIVIERJIEJASMIN&LEVIRSECHSIEBENGPAUSERDUHR";//JASMIN&LEVI
|
||||
//"ESGISTKZEHNFuNFVIERTELVORNACHBALDHALBDZWEINSDREIVIERWLZZEHNEUNACHTPSECHSIEBENELFuNFZWoLFMAIKETOCVXIUHRU&FABIAN";//Maike&Fabian
|
||||
//"ESHISTPZEHNFuNFVIERTELVORNACHBALDHALBWZWEINSELFuNFZWoLFZEHNEUNACHTDREIVIERJIEJASMINKLEVIRSECHSIEBENGPAUSERDUHR";//JASMIN&LEVI
|
||||
//"ESHISTJZEHNFuNFVIERTELNACHFASTVORYHALBPBALDSQXBMICHLFPYDREINSIEBENELFZWoLFuNFPSECHSZVIERACHTZEHNEUNZWEIRWDUHRK";//Rouven Öttinger 12BM02
|
||||
//"ESOISTBZEHNFuNFVIERTELVORNACHBALDHALBCZWEINSULINAKLUCADIDREIVIEREFZEHNEUNACHTELFuNFZWoLFSECHSIEBENBPAUSEMBYUHR"; //Spiller
|
||||
//"ESHISTRFASTKURZVIERTELFuNFZWANZIGAZEHNJNACHRVORWHALBKLBZWEINSECHSEELFVIERACHTFuNFSIEBENITDREIZWoLFZZEHNEUNLUHR";
|
||||
//"ESHISTRFASTKURZVIERTELFuNFZWANZIGAZEHNJNACHRVORWHALBKLBZWEINSECHSEELFVIERACHTFuNFSIEBENITDREIZWoLFZZEHNEUNLUHR"; //119
|
||||
//"ESXISTEFuNFVIERTELZEHNKURZWXPNACHSVORTHALBTVEINSXJZWEIUDREIVIERYPHFuNFSECHSWYSIEBENACHTUNEUNZEHNELFZWoLFXUHRJT";
|
||||
//115"ESHISTCKURZSIVORXZEHNMFuNFVIERTELVORNACHBALDHALBXEINSMEZEHNEUNZWEIELFuNFZWoLFSECHSIEBENXMDREIVIERVILRACHTSYUHR";
|
||||
char testPattern[]="ES-IST-WIR-HABEN-BALD-FAST-KURZ-FuNF-ZEHN-DREIVIERTEL-VIERTEL-ZWANZIG-VOR-NACH-EIN-EINS-ZWEI-DREI-VIER-FuNF-SECHS-SIEBEN-ACHT-NEUN-ZEHN-ELF-ZWoLF-UHR-NACHT-PAUSE-ALARM-ZEIT-RWD-KKS-KARLKUEBEL-MINT\0";
|
||||
char testPattern[]="ES-IST-WIR-HABEN-BALD-FAST-KURZ-FuNF-ZEHN-DREIVIERTEL-VIERTEL-ZWANZIG-VOR-NACH-EIN-EINS-ZWEI-DREI-VIER-FuNF-SECHS-SIEBEN-ACHT-NEUN-ZEHN-ELF-ZWoLF-UHR-NACHT-PAUSE-ALARM-ZEIT-RWD-KKS-KARLKUEBEL-MINT-UWE\0";
|
||||
|
||||
/*
|
||||
"ES_IST_ZEHNFuNFVIERTELVORNACHBALDHALB_ZWEINS___________ZEHNEUNACHTELFuNFZWoLFSECHSIEBEN__DREIVIER____PAUSE_UHR"
|
||||
|
|
|
|||
|
|
@ -25,7 +25,6 @@
|
|||
|
||||
#define AP_SSID_LENGHT 13
|
||||
#define AP_PASSWORD_LENGTH 17
|
||||
#define MAXWORDS 3 // Anzahl Spezialwörter
|
||||
|
||||
// ════════════════════════════════════════════════════════════════
|
||||
// EEPROM ADRESSEN
|
||||
|
|
@ -104,6 +103,6 @@
|
|||
#define MINUTE_LEDS_MAGIC 0xEE
|
||||
|
||||
#define RUNNING_FLAG_MAGIC 0x42 // Magic Byte
|
||||
#define MAGIC_BYTE_INIT 0xAA
|
||||
#define MAGIC_BYTE_INIT 0x55
|
||||
|
||||
#endif
|
||||
|
|
@ -17,8 +17,8 @@ int8_t isConfigured = 0xFF;
|
|||
const unsigned long AP_TIMEOUT = 300000;
|
||||
bool powerLossDetected = false; //Flag für Stromausfall
|
||||
|
||||
char AP_SSID[AP_SSID_LENGHT] = "CharGrap101\0";
|
||||
char AP_PASSWORD[AP_PASSWORD_LENGTH] = "MeinPasswort101\0";
|
||||
char AP_SSID[AP_SSID_LENGHT] = "CharGraph\0";
|
||||
char AP_PASSWORD[AP_PASSWORD_LENGTH] = "CharGraph\0";
|
||||
|
||||
|
||||
uint16_t bootCounter = 0;
|
||||
|
|
|
|||
|
|
@ -129,17 +129,17 @@ static uint8_t rule_15_19(const RuleContext& ctx, const char** outWords) {
|
|||
// :20-:24 - ZWANZIG NACH or ZEHN VOR HALB (with fallback support)
|
||||
static uint8_t rule_20_24(const RuleContext& ctx, const char** outWords) {
|
||||
if (ctx.fallbackLevel == 0 && ctx.hasZwanzig) {
|
||||
// Primary: ZWANZIG NACH [h]
|
||||
// Primary: ZWANZIG NACH [h] - uses current hour
|
||||
outWords[0] = ZWANZIG;
|
||||
outWords[1] = NACH;
|
||||
outWords[2] = ctx.hourWord;
|
||||
return 3;
|
||||
}
|
||||
// Fallback: ZEHN VOR HALB [h+1]
|
||||
// Fallback: ZEHN VOR HALB [h+1] - must use NEXT hour
|
||||
outWords[0] = ZEHN;
|
||||
outWords[1] = VOR;
|
||||
outWords[2] = HALB;
|
||||
outWords[3] = ctx.hourWord;
|
||||
outWords[3] = getHourWord((ctx.h12 + 1) % 12);
|
||||
return 4;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -88,9 +88,11 @@ uint8_t getWordsForTime(
|
|||
hasUhrAtEnd = afterUhrEmpty;
|
||||
}
|
||||
|
||||
// ========== STEP 4: Calculate display hour (advance at mm >= 20) ==========
|
||||
// ========== STEP 4: Calculate display hour (advance at mm >= 25) ==========
|
||||
// :20-:24 ZWANZIG NACH uses current hour
|
||||
// :25-:59 other rules use next hour
|
||||
uint8_t h12 = hour % 12;
|
||||
if (minute >= 20) {
|
||||
if (minute >= 25) {
|
||||
h12 = (h12 + 1) % 12;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,15 +10,15 @@ CRGB specialColor = CRGB::Green;
|
|||
CRGB leds[NUM_LEDS];
|
||||
uint8_t brightness = 80;
|
||||
|
||||
char charsoap[COLS * ROWS * 2]; //Char * 2 to fit all in, cause UTF (maybe ÄÖÜ)
|
||||
char charsoap[(COLS * ROWS * 2) + 1] = {'\0'}; //Char * 2 to fit all in, cause UTF (maybe ÄÖÜ)
|
||||
bool customCharsoap = false;
|
||||
|
||||
// ── Konfiguration für Spezialanzeige ──
|
||||
// MAXWORDS ist in defines.inc definiert
|
||||
// Platzhalter - werden dynamisch aus EEPROM oder Defaults geladen (siehe loadSpecialWords() in main.cpp)
|
||||
char SPECIAL_WORD[MAXWORDS][12] = {"", //max 11 Zeichen, \0 wird automatisch angefügt!
|
||||
"",
|
||||
"" }; //Text der ein- bzw. ausgeblendet werden soll
|
||||
char SPECIAL_WORD[MAXWORDS][13] = {"DLZIAX\0", //max 11 Zeichen, \0 wird automatisch angefügt!
|
||||
"FACW\0",
|
||||
"\0" }; //Text der ein- bzw. ausgeblendet werden soll
|
||||
const uint16_t SPECIAL_HOLD_MS = 5000; // Anzeigedauer des Spezialworts
|
||||
|
||||
const int hourpattern[][2] = {
|
||||
|
|
@ -87,7 +87,7 @@ void fadeInCurrentFrame(uint8_t targetBrightness, uint8_t steps = MAX_STEPS, uin
|
|||
|
||||
// Zeigt ein Wort (falls vorhanden) mit sanftem Fade-In, hält es und blendet es wieder aus
|
||||
// OPTIMIERT: Schnellere Animation für bessere WiFi-Performance
|
||||
bool showSpecialWordSequence(const char words[][12], CRGB color, uint8_t steps = 20, uint16_t stepDelayMs = 15)
|
||||
bool showSpecialWordSequence(const char words[][SPECIAL_WORD_LENGTH], CRGB color, uint8_t steps = 20, uint16_t stepDelayMs = 15)
|
||||
{
|
||||
|
||||
int pos = findWord(words[0], 0);
|
||||
|
|
@ -404,24 +404,27 @@ int findWord(const char* word, int occurrence, bool searchBackward)
|
|||
|
||||
uint8_t testWords()
|
||||
{
|
||||
//return 0;
|
||||
#if (defined(TEST_ALLTHETIME) && TEST_ALLTHETIME == false)
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
DEBUG_PRINT("╔════════════════════════╗\n");
|
||||
DEBUG_PRINT("║ Teste Wörter ... ║\n");
|
||||
DEBUG_PRINT("╚════════════════════════╝\n")
|
||||
DEBUG_PRINTLN(DEFAULT_CHARSOAP);
|
||||
if(strlen(DEFAULT_CHARSOAP) != (COLS * (ROWS-1)))
|
||||
DEBUG_PRINTLN(charsoap);
|
||||
if(strlen(charsoap) != (COLS * (ROWS-1)))
|
||||
{
|
||||
//return -1;
|
||||
DEBUG_PRINT("\nLänge stimmt nicht: ");
|
||||
DEBUG_PRINTLN(strlen(DEFAULT_CHARSOAP));
|
||||
DEBUG_PRINTLN(strlen(charsoap));
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_PRINT("\nLänge stimmt: ");
|
||||
DEBUG_PRINTLN(strlen(DEFAULT_CHARSOAP));
|
||||
DEBUG_PRINTLN(strlen(charsoap));
|
||||
}
|
||||
uint8_t currentHour = 12;
|
||||
uint8_t currentMinute = 29;
|
||||
uint8_t currentHour = 0;
|
||||
uint8_t currentMinute = 0;
|
||||
//CharGraphTimeWords result;
|
||||
while(true)
|
||||
{
|
||||
|
|
@ -429,10 +432,10 @@ uint8_t testWords()
|
|||
currentMinute++;
|
||||
if(currentMinute == 60)
|
||||
{
|
||||
currentHour = 1;
|
||||
currentMinute = 0;
|
||||
currentHour += 1;
|
||||
currentMinute = 0;
|
||||
}
|
||||
if(currentHour == 1 && currentMinute == 31)
|
||||
if(currentHour == 23 && currentMinute == 59)
|
||||
{
|
||||
DEBUG_PRINT ("\n╔════════════════════════╗\n");
|
||||
DEBUG_PRINT ( "║ Teste Wörter fertig. ║\n");
|
||||
|
|
@ -449,9 +452,6 @@ uint8_t testWords()
|
|||
DEBUG_PRINT(currentMinute);
|
||||
DEBUG_PRINT("' -> ");
|
||||
//delay(1000);
|
||||
|
||||
//int8_t resultval = getCharGraphWords(DEFAULT_CHARSOAP, currentHour, currentMinute, result);
|
||||
//if (resultval == 0)
|
||||
{
|
||||
// ===== Display current time =====
|
||||
displayTime(currentHour, currentMinute);
|
||||
|
|
@ -461,13 +461,13 @@ uint8_t testWords()
|
|||
// DEBUG_PRINT("ERROR: "); DEBUG_PRINT(resultval); DEBUG_PRINTLN(" Pattern validation failed!");
|
||||
// delay(1000);
|
||||
//}
|
||||
delay(500);
|
||||
delay(50);
|
||||
}
|
||||
}
|
||||
|
||||
void checkPattern()
|
||||
{
|
||||
//testWords();
|
||||
testWords();
|
||||
|
||||
FastLED.clear();
|
||||
uint8_t lengthPattern = strlen(testPattern);
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@
|
|||
#define COLS 11
|
||||
#define ROWS 11
|
||||
|
||||
#define MAXWORDS 3 //Anzahl Spezialwörter
|
||||
#define SPECIAL_WORD_LENGTH (COLS+2)
|
||||
extern CRGB normalColor;
|
||||
extern CRGB specialColor;
|
||||
extern CRGB leds[NUM_LEDS];
|
||||
|
|
@ -20,9 +22,9 @@
|
|||
extern int MINUTE_LEDS[4];
|
||||
extern char testPattern[];
|
||||
extern bool customCharsoap;
|
||||
extern char charsoap[COLS * ROWS * 2];
|
||||
extern char charsoap[(COLS * ROWS * 2)+1];
|
||||
extern const char DEFAULT_CHARSOAP[];
|
||||
extern char SPECIAL_WORD[3][12]; // MAXWORDS = 3
|
||||
extern char SPECIAL_WORD[MAXWORDS][SPECIAL_WORD_LENGTH]; // MAXWORDS = 3
|
||||
|
||||
extern void showLEDs();
|
||||
extern int bridgeLED(int pos);
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ build_flags =
|
|||
-DUSE_RTC=false
|
||||
-DTEST_RGB_ONLY=false
|
||||
-DTEST_RGB=false
|
||||
-DTEST_ALLTHETIME=false
|
||||
-DPOWERLOSSDETECT=false
|
||||
-DCHARGRAPH_DEBUG
|
||||
|
||||
|
|
@ -63,7 +64,7 @@ platform = ${env.platform}
|
|||
monitor_speed = ${common.monitor_speed}
|
||||
|
||||
upload_speed = 115200 ; Langsam für Clone-Stabilität
|
||||
upload_port = COM13
|
||||
;upload_port = COM13
|
||||
|
||||
; Flash-Einstellungen (sicher für alle Clones)
|
||||
board_build.flash_mode = dio ; Statt qio - kompatibler!
|
||||
|
|
@ -100,7 +101,7 @@ monitor_speed = ${common.monitor_speed}
|
|||
;upload_speed = 921600
|
||||
upload_speed = 115200
|
||||
;upload_port = COM13 ; Automatische Erkennung oder manuell anpassen
|
||||
upload_port = COM5
|
||||
;upload_port = COM5
|
||||
|
||||
board_build.flash_mode = dio
|
||||
# CPU-Frequenz auf 160MHz erhöht
|
||||
|
|
|
|||
66
src/main.cpp
66
src/main.cpp
|
|
@ -15,37 +15,42 @@ const byte DNS_PORT = 53;
|
|||
// ════════════════════════════════════════════════════════════════
|
||||
// CHARSOAP / ZEICHENSATZ
|
||||
// ════════════════════════════════════════════════════════════════
|
||||
void initCharsoap() {
|
||||
void initCharsoap(char *_charsoap) {
|
||||
// Konvertiert UTF-8 Umlaute in charsoap zu ASCII in-place
|
||||
// charsoap muss bereits gefüllt sein (von strcpy_P)
|
||||
|
||||
char temp[COLS * ROWS * 2]; // Temporärer Buffer für Konvertierung
|
||||
int writePos = 0;
|
||||
int readPos = 0;
|
||||
int sourceLen = strlen(DEFAULT_CHARSOAP);
|
||||
int sourceLen = strlen(_charsoap);
|
||||
|
||||
while (readPos < sourceLen && writePos < (ROWS * COLS)) {
|
||||
unsigned char c = DEFAULT_CHARSOAP[readPos];
|
||||
unsigned char c = _charsoap[readPos];
|
||||
|
||||
// UTF-8 Umlaute erkennen und zu lowercase konvertieren
|
||||
if (c == 0xC3 && readPos + 1 < sourceLen) {
|
||||
unsigned char next = DEFAULT_CHARSOAP[readPos + 1];
|
||||
unsigned char next = _charsoap[readPos + 1];
|
||||
switch(next) {
|
||||
case 0x84: charsoap[writePos++] = 'a'; break; // Ä → a
|
||||
case 0x96: charsoap[writePos++] = 'o'; break; // Ö → o
|
||||
case 0x9C: charsoap[writePos++] = 'u'; break; // Ü → u
|
||||
case 0x84: temp[writePos++] = 'a'; break; // Ä → a
|
||||
case 0x96: temp[writePos++] = 'o'; break; // Ö → o
|
||||
case 0x9C: temp[writePos++] = 'u'; break; // Ü → u
|
||||
default:
|
||||
charsoap[writePos++] = c;
|
||||
if (writePos < (ROWS * COLS)) charsoap[writePos++] = next;
|
||||
temp[writePos++] = c;
|
||||
if (writePos < (ROWS * COLS)) temp[writePos++] = next;
|
||||
break;
|
||||
}
|
||||
readPos += 2;
|
||||
} else {
|
||||
charsoap[writePos++] = c;
|
||||
temp[writePos++] = c;
|
||||
readPos++;
|
||||
}
|
||||
}
|
||||
|
||||
charsoap[writePos] = '\0';
|
||||
temp[writePos] = '\0';
|
||||
strcpy(_charsoap, temp); // Konvertiertes Ergebnis zurück nach charsoap
|
||||
|
||||
DEBUG_PRINTLN("✓ Default charsoap initialisiert (Umlaute → lowercase)");
|
||||
DEBUG_PRINTLN(charsoap);
|
||||
DEBUG_PRINTLN("✓ charsoap initialisiert (Umlaute → lowercase)");
|
||||
DEBUG_PRINTLN(_charsoap);
|
||||
}
|
||||
|
||||
void loadCharsoap() {
|
||||
|
|
@ -119,24 +124,20 @@ void loadCharsoap() {
|
|||
}
|
||||
} else {
|
||||
DEBUG_PRINTF("❌ Falsche Länge: %d\n", writePos);
|
||||
strcpy(charsoap, DEFAULT_CHARSOAP);
|
||||
initCharsoap(); // UTF-8 zu ASCII konvertieren!
|
||||
strcpy_P(charsoap, (const char*)DEFAULT_CHARSOAP);
|
||||
initCharsoap(charsoap); // UTF-8 zu ASCII konvertieren!
|
||||
customCharsoap = false;
|
||||
DEBUG_PRINTLN("→ Verwende Default");
|
||||
}
|
||||
} else {
|
||||
strcpy(charsoap, DEFAULT_CHARSOAP);
|
||||
initCharsoap(); // UTF-8 zu ASCII konvertieren!
|
||||
strcpy_P(charsoap, (const char*)DEFAULT_CHARSOAP);
|
||||
initCharsoap(charsoap); // UTF-8 zu ASCII konvertieren!
|
||||
DEBUG_PRINTLN("✓ Standard charsoap");
|
||||
}
|
||||
}
|
||||
|
||||
void saveCharsoap(const char* newCharsoap) {
|
||||
if (strlen(newCharsoap) != (ROWS * COLS)) {
|
||||
DEBUG_PRINTF("❌ Länge: %d\n", strlen(newCharsoap));
|
||||
return;
|
||||
}
|
||||
|
||||
void saveCharsoap(const char* newCharsoap)
|
||||
{
|
||||
char cleaned[uint8_t (ROWS * COLS)+1];
|
||||
uint16_t writePos = 0;
|
||||
uint16_t readPos = 0;
|
||||
|
|
@ -184,8 +185,8 @@ void saveCharsoap(const char* newCharsoap) {
|
|||
}
|
||||
|
||||
void resetCharsoap() {
|
||||
strcpy(charsoap, DEFAULT_CHARSOAP);
|
||||
initCharsoap(); // UTF-8 zu ASCII konvertieren!
|
||||
strcpy_P(charsoap, (const char*)DEFAULT_CHARSOAP);
|
||||
initCharsoap(charsoap); // UTF-8 zu ASCII konvertieren!
|
||||
customCharsoap = false;
|
||||
EEPROM.write(ADDR_CHARSOAP_SET, 0);
|
||||
EEPROM.commit();
|
||||
|
|
@ -220,8 +221,8 @@ void loadSpecialWords() {
|
|||
// Erste Initialisierung: Default-Werte setzen
|
||||
DEBUG_PRINTLN("Setze Standard SPECIAL_WORD...");
|
||||
const char DEFAULT_SPECIAL_WORD[MAXWORDS][12] = {
|
||||
"RWD",
|
||||
"",
|
||||
"DLZIAX",
|
||||
"FACW",
|
||||
""
|
||||
};
|
||||
|
||||
|
|
@ -439,8 +440,8 @@ void loadConfig() {
|
|||
DEBUG_PRINTLN("╚════════════════════════════════════════════════════╝");
|
||||
|
||||
// DEFAULT_CHARSOAP vorbereiten (UTF-8 → ASCII)
|
||||
strcpy(charsoap, DEFAULT_CHARSOAP);
|
||||
initCharsoap();
|
||||
strcpy_P(charsoap, (const char*)DEFAULT_CHARSOAP);
|
||||
initCharsoap(charsoap);
|
||||
|
||||
DEBUG_PRINTLN("→ Speichere DEFAULT_CHARSOAP ins EEPROM...");
|
||||
|
||||
|
|
@ -827,7 +828,7 @@ void displayTime(int hours, int minutes)
|
|||
yield();
|
||||
|
||||
CharGraphTimeWords result;
|
||||
int8_t resultval = getCharGraphWords(DEFAULT_CHARSOAP, testPattern, hours, minutes, result);
|
||||
int8_t resultval = getCharGraphWords(charsoap, testPattern, hours, minutes, result);
|
||||
|
||||
if (resultval == 0)
|
||||
{
|
||||
|
|
@ -1361,6 +1362,7 @@ void handleSave() {
|
|||
server.send(400, "text/plain", "Fehler");
|
||||
}
|
||||
}
|
||||
|
||||
// ════════════════════════════════════════════════════════════════
|
||||
// LED TEST HANDLER
|
||||
// ════════════════════════════════════════════════════════════════
|
||||
|
|
@ -2395,7 +2397,7 @@ void setup()
|
|||
Serial.begin(115200);
|
||||
while (!Serial) { }
|
||||
Serial.setDebugOutput(true);
|
||||
delay(500);
|
||||
delay(5000);
|
||||
Serial.setDebugOutput(false);
|
||||
|
||||
Serial.printf("Flash Chip ID: %08X\n", ESP.getFlashChipId());
|
||||
|
|
@ -2450,7 +2452,7 @@ void setup()
|
|||
EEPROM.begin(EEPROM_SIZE);
|
||||
|
||||
// Zuerst Default charsoap initialisieren
|
||||
initCharsoap();
|
||||
initCharsoap(charsoap);
|
||||
|
||||
loadCharsoap();
|
||||
loadSpecialWords();
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user