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!!!!
|
//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";
|
//"ESXISTEFuNFVIERTELZEHNKURZWXPNACHSVORTHALBTVEINSXJZWEIUDREIVIERYPHFuNFSECHSWYSIEBENACHTUNEUNZEHNELFZWoLFXUHRJT";
|
||||||
//115"ESHISTCKURZSIVORXZEHNMFuNFVIERTELVORNACHBALDHALBXEINSMEZEHNEUNZWEIELFuNFZWoLFSECHSIEBENXMDREIVIERVILRACHTSYUHR";
|
//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"
|
"ES_IST_ZEHNFuNFVIERTELVORNACHBALDHALB_ZWEINS___________ZEHNEUNACHTELFuNFZWoLFSECHSIEBEN__DREIVIER____PAUSE_UHR"
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,6 @@
|
||||||
|
|
||||||
#define AP_SSID_LENGHT 13
|
#define AP_SSID_LENGHT 13
|
||||||
#define AP_PASSWORD_LENGTH 17
|
#define AP_PASSWORD_LENGTH 17
|
||||||
#define MAXWORDS 3 // Anzahl Spezialwörter
|
|
||||||
|
|
||||||
// ════════════════════════════════════════════════════════════════
|
// ════════════════════════════════════════════════════════════════
|
||||||
// EEPROM ADRESSEN
|
// EEPROM ADRESSEN
|
||||||
|
|
@ -104,6 +103,6 @@
|
||||||
#define MINUTE_LEDS_MAGIC 0xEE
|
#define MINUTE_LEDS_MAGIC 0xEE
|
||||||
|
|
||||||
#define RUNNING_FLAG_MAGIC 0x42 // Magic Byte
|
#define RUNNING_FLAG_MAGIC 0x42 // Magic Byte
|
||||||
#define MAGIC_BYTE_INIT 0xAA
|
#define MAGIC_BYTE_INIT 0x55
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -17,8 +17,8 @@ int8_t isConfigured = 0xFF;
|
||||||
const unsigned long AP_TIMEOUT = 300000;
|
const unsigned long AP_TIMEOUT = 300000;
|
||||||
bool powerLossDetected = false; //Flag für Stromausfall
|
bool powerLossDetected = false; //Flag für Stromausfall
|
||||||
|
|
||||||
char AP_SSID[AP_SSID_LENGHT] = "CharGrap101\0";
|
char AP_SSID[AP_SSID_LENGHT] = "CharGraph\0";
|
||||||
char AP_PASSWORD[AP_PASSWORD_LENGTH] = "MeinPasswort101\0";
|
char AP_PASSWORD[AP_PASSWORD_LENGTH] = "CharGraph\0";
|
||||||
|
|
||||||
|
|
||||||
uint16_t bootCounter = 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)
|
// :20-:24 - ZWANZIG NACH or ZEHN VOR HALB (with fallback support)
|
||||||
static uint8_t rule_20_24(const RuleContext& ctx, const char** outWords) {
|
static uint8_t rule_20_24(const RuleContext& ctx, const char** outWords) {
|
||||||
if (ctx.fallbackLevel == 0 && ctx.hasZwanzig) {
|
if (ctx.fallbackLevel == 0 && ctx.hasZwanzig) {
|
||||||
// Primary: ZWANZIG NACH [h]
|
// Primary: ZWANZIG NACH [h] - uses current hour
|
||||||
outWords[0] = ZWANZIG;
|
outWords[0] = ZWANZIG;
|
||||||
outWords[1] = NACH;
|
outWords[1] = NACH;
|
||||||
outWords[2] = ctx.hourWord;
|
outWords[2] = ctx.hourWord;
|
||||||
return 3;
|
return 3;
|
||||||
}
|
}
|
||||||
// Fallback: ZEHN VOR HALB [h+1]
|
// Fallback: ZEHN VOR HALB [h+1] - must use NEXT hour
|
||||||
outWords[0] = ZEHN;
|
outWords[0] = ZEHN;
|
||||||
outWords[1] = VOR;
|
outWords[1] = VOR;
|
||||||
outWords[2] = HALB;
|
outWords[2] = HALB;
|
||||||
outWords[3] = ctx.hourWord;
|
outWords[3] = getHourWord((ctx.h12 + 1) % 12);
|
||||||
return 4;
|
return 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -88,9 +88,11 @@ uint8_t getWordsForTime(
|
||||||
hasUhrAtEnd = afterUhrEmpty;
|
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;
|
uint8_t h12 = hour % 12;
|
||||||
if (minute >= 20) {
|
if (minute >= 25) {
|
||||||
h12 = (h12 + 1) % 12;
|
h12 = (h12 + 1) % 12;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,15 +10,15 @@ CRGB specialColor = CRGB::Green;
|
||||||
CRGB leds[NUM_LEDS];
|
CRGB leds[NUM_LEDS];
|
||||||
uint8_t brightness = 80;
|
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;
|
bool customCharsoap = false;
|
||||||
|
|
||||||
// ── Konfiguration für Spezialanzeige ──
|
// ── Konfiguration für Spezialanzeige ──
|
||||||
// MAXWORDS ist in defines.inc definiert
|
// MAXWORDS ist in defines.inc definiert
|
||||||
// Platzhalter - werden dynamisch aus EEPROM oder Defaults geladen (siehe loadSpecialWords() in main.cpp)
|
// 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!
|
char SPECIAL_WORD[MAXWORDS][13] = {"DLZIAX\0", //max 11 Zeichen, \0 wird automatisch angefügt!
|
||||||
"",
|
"FACW\0",
|
||||||
"" }; //Text der ein- bzw. ausgeblendet werden soll
|
"\0" }; //Text der ein- bzw. ausgeblendet werden soll
|
||||||
const uint16_t SPECIAL_HOLD_MS = 5000; // Anzeigedauer des Spezialworts
|
const uint16_t SPECIAL_HOLD_MS = 5000; // Anzeigedauer des Spezialworts
|
||||||
|
|
||||||
const int hourpattern[][2] = {
|
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
|
// 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
|
// 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);
|
int pos = findWord(words[0], 0);
|
||||||
|
|
@ -404,24 +404,27 @@ int findWord(const char* word, int occurrence, bool searchBackward)
|
||||||
|
|
||||||
uint8_t testWords()
|
uint8_t testWords()
|
||||||
{
|
{
|
||||||
//return 0;
|
#if (defined(TEST_ALLTHETIME) && TEST_ALLTHETIME == false)
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
DEBUG_PRINT("╔════════════════════════╗\n");
|
DEBUG_PRINT("╔════════════════════════╗\n");
|
||||||
DEBUG_PRINT("║ Teste Wörter ... ║\n");
|
DEBUG_PRINT("║ Teste Wörter ... ║\n");
|
||||||
DEBUG_PRINT("╚════════════════════════╝\n")
|
DEBUG_PRINT("╚════════════════════════╝\n")
|
||||||
DEBUG_PRINTLN(DEFAULT_CHARSOAP);
|
DEBUG_PRINTLN(charsoap);
|
||||||
if(strlen(DEFAULT_CHARSOAP) != (COLS * (ROWS-1)))
|
if(strlen(charsoap) != (COLS * (ROWS-1)))
|
||||||
{
|
{
|
||||||
//return -1;
|
//return -1;
|
||||||
DEBUG_PRINT("\nLänge stimmt nicht: ");
|
DEBUG_PRINT("\nLänge stimmt nicht: ");
|
||||||
DEBUG_PRINTLN(strlen(DEFAULT_CHARSOAP));
|
DEBUG_PRINTLN(strlen(charsoap));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
DEBUG_PRINT("\nLänge stimmt: ");
|
DEBUG_PRINT("\nLänge stimmt: ");
|
||||||
DEBUG_PRINTLN(strlen(DEFAULT_CHARSOAP));
|
DEBUG_PRINTLN(strlen(charsoap));
|
||||||
}
|
}
|
||||||
uint8_t currentHour = 12;
|
uint8_t currentHour = 0;
|
||||||
uint8_t currentMinute = 29;
|
uint8_t currentMinute = 0;
|
||||||
//CharGraphTimeWords result;
|
//CharGraphTimeWords result;
|
||||||
while(true)
|
while(true)
|
||||||
{
|
{
|
||||||
|
|
@ -429,10 +432,10 @@ uint8_t testWords()
|
||||||
currentMinute++;
|
currentMinute++;
|
||||||
if(currentMinute == 60)
|
if(currentMinute == 60)
|
||||||
{
|
{
|
||||||
currentHour = 1;
|
currentHour += 1;
|
||||||
currentMinute = 0;
|
currentMinute = 0;
|
||||||
}
|
}
|
||||||
if(currentHour == 1 && currentMinute == 31)
|
if(currentHour == 23 && currentMinute == 59)
|
||||||
{
|
{
|
||||||
DEBUG_PRINT ("\n╔════════════════════════╗\n");
|
DEBUG_PRINT ("\n╔════════════════════════╗\n");
|
||||||
DEBUG_PRINT ( "║ Teste Wörter fertig. ║\n");
|
DEBUG_PRINT ( "║ Teste Wörter fertig. ║\n");
|
||||||
|
|
@ -449,9 +452,6 @@ uint8_t testWords()
|
||||||
DEBUG_PRINT(currentMinute);
|
DEBUG_PRINT(currentMinute);
|
||||||
DEBUG_PRINT("' -> ");
|
DEBUG_PRINT("' -> ");
|
||||||
//delay(1000);
|
//delay(1000);
|
||||||
|
|
||||||
//int8_t resultval = getCharGraphWords(DEFAULT_CHARSOAP, currentHour, currentMinute, result);
|
|
||||||
//if (resultval == 0)
|
|
||||||
{
|
{
|
||||||
// ===== Display current time =====
|
// ===== Display current time =====
|
||||||
displayTime(currentHour, currentMinute);
|
displayTime(currentHour, currentMinute);
|
||||||
|
|
@ -461,13 +461,13 @@ uint8_t testWords()
|
||||||
// DEBUG_PRINT("ERROR: "); DEBUG_PRINT(resultval); DEBUG_PRINTLN(" Pattern validation failed!");
|
// DEBUG_PRINT("ERROR: "); DEBUG_PRINT(resultval); DEBUG_PRINTLN(" Pattern validation failed!");
|
||||||
// delay(1000);
|
// delay(1000);
|
||||||
//}
|
//}
|
||||||
delay(500);
|
delay(50);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void checkPattern()
|
void checkPattern()
|
||||||
{
|
{
|
||||||
//testWords();
|
testWords();
|
||||||
|
|
||||||
FastLED.clear();
|
FastLED.clear();
|
||||||
uint8_t lengthPattern = strlen(testPattern);
|
uint8_t lengthPattern = strlen(testPattern);
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,8 @@
|
||||||
#define COLS 11
|
#define COLS 11
|
||||||
#define ROWS 11
|
#define ROWS 11
|
||||||
|
|
||||||
|
#define MAXWORDS 3 //Anzahl Spezialwörter
|
||||||
|
#define SPECIAL_WORD_LENGTH (COLS+2)
|
||||||
extern CRGB normalColor;
|
extern CRGB normalColor;
|
||||||
extern CRGB specialColor;
|
extern CRGB specialColor;
|
||||||
extern CRGB leds[NUM_LEDS];
|
extern CRGB leds[NUM_LEDS];
|
||||||
|
|
@ -20,9 +22,9 @@
|
||||||
extern int MINUTE_LEDS[4];
|
extern int MINUTE_LEDS[4];
|
||||||
extern char testPattern[];
|
extern char testPattern[];
|
||||||
extern bool customCharsoap;
|
extern bool customCharsoap;
|
||||||
extern char charsoap[COLS * ROWS * 2];
|
extern char charsoap[(COLS * ROWS * 2)+1];
|
||||||
extern const char DEFAULT_CHARSOAP[];
|
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 void showLEDs();
|
||||||
extern int bridgeLED(int pos);
|
extern int bridgeLED(int pos);
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,7 @@ build_flags =
|
||||||
-DUSE_RTC=false
|
-DUSE_RTC=false
|
||||||
-DTEST_RGB_ONLY=false
|
-DTEST_RGB_ONLY=false
|
||||||
-DTEST_RGB=false
|
-DTEST_RGB=false
|
||||||
|
-DTEST_ALLTHETIME=false
|
||||||
-DPOWERLOSSDETECT=false
|
-DPOWERLOSSDETECT=false
|
||||||
-DCHARGRAPH_DEBUG
|
-DCHARGRAPH_DEBUG
|
||||||
|
|
||||||
|
|
@ -63,7 +64,7 @@ platform = ${env.platform}
|
||||||
monitor_speed = ${common.monitor_speed}
|
monitor_speed = ${common.monitor_speed}
|
||||||
|
|
||||||
upload_speed = 115200 ; Langsam für Clone-Stabilität
|
upload_speed = 115200 ; Langsam für Clone-Stabilität
|
||||||
upload_port = COM13
|
;upload_port = COM13
|
||||||
|
|
||||||
; Flash-Einstellungen (sicher für alle Clones)
|
; Flash-Einstellungen (sicher für alle Clones)
|
||||||
board_build.flash_mode = dio ; Statt qio - kompatibler!
|
board_build.flash_mode = dio ; Statt qio - kompatibler!
|
||||||
|
|
@ -100,7 +101,7 @@ monitor_speed = ${common.monitor_speed}
|
||||||
;upload_speed = 921600
|
;upload_speed = 921600
|
||||||
upload_speed = 115200
|
upload_speed = 115200
|
||||||
;upload_port = COM13 ; Automatische Erkennung oder manuell anpassen
|
;upload_port = COM13 ; Automatische Erkennung oder manuell anpassen
|
||||||
upload_port = COM5
|
;upload_port = COM5
|
||||||
|
|
||||||
board_build.flash_mode = dio
|
board_build.flash_mode = dio
|
||||||
# CPU-Frequenz auf 160MHz erhöht
|
# 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
|
// 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 writePos = 0;
|
||||||
int readPos = 0;
|
int readPos = 0;
|
||||||
int sourceLen = strlen(DEFAULT_CHARSOAP);
|
int sourceLen = strlen(_charsoap);
|
||||||
|
|
||||||
while (readPos < sourceLen && writePos < (ROWS * COLS)) {
|
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
|
// UTF-8 Umlaute erkennen und zu lowercase konvertieren
|
||||||
if (c == 0xC3 && readPos + 1 < sourceLen) {
|
if (c == 0xC3 && readPos + 1 < sourceLen) {
|
||||||
unsigned char next = DEFAULT_CHARSOAP[readPos + 1];
|
unsigned char next = _charsoap[readPos + 1];
|
||||||
switch(next) {
|
switch(next) {
|
||||||
case 0x84: charsoap[writePos++] = 'a'; break; // Ä → a
|
case 0x84: temp[writePos++] = 'a'; break; // Ä → a
|
||||||
case 0x96: charsoap[writePos++] = 'o'; break; // Ö → o
|
case 0x96: temp[writePos++] = 'o'; break; // Ö → o
|
||||||
case 0x9C: charsoap[writePos++] = 'u'; break; // Ü → u
|
case 0x9C: temp[writePos++] = 'u'; break; // Ü → u
|
||||||
default:
|
default:
|
||||||
charsoap[writePos++] = c;
|
temp[writePos++] = c;
|
||||||
if (writePos < (ROWS * COLS)) charsoap[writePos++] = next;
|
if (writePos < (ROWS * COLS)) temp[writePos++] = next;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
readPos += 2;
|
readPos += 2;
|
||||||
} else {
|
} else {
|
||||||
charsoap[writePos++] = c;
|
temp[writePos++] = c;
|
||||||
readPos++;
|
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 initialisiert (Umlaute → lowercase)");
|
||||||
DEBUG_PRINTLN(charsoap);
|
DEBUG_PRINTLN(_charsoap);
|
||||||
}
|
}
|
||||||
|
|
||||||
void loadCharsoap() {
|
void loadCharsoap() {
|
||||||
|
|
@ -119,24 +124,20 @@ void loadCharsoap() {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
DEBUG_PRINTF("❌ Falsche Länge: %d\n", writePos);
|
DEBUG_PRINTF("❌ Falsche Länge: %d\n", writePos);
|
||||||
strcpy(charsoap, DEFAULT_CHARSOAP);
|
strcpy_P(charsoap, (const char*)DEFAULT_CHARSOAP);
|
||||||
initCharsoap(); // UTF-8 zu ASCII konvertieren!
|
initCharsoap(charsoap); // UTF-8 zu ASCII konvertieren!
|
||||||
customCharsoap = false;
|
customCharsoap = false;
|
||||||
DEBUG_PRINTLN("→ Verwende Default");
|
DEBUG_PRINTLN("→ Verwende Default");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
strcpy(charsoap, DEFAULT_CHARSOAP);
|
strcpy_P(charsoap, (const char*)DEFAULT_CHARSOAP);
|
||||||
initCharsoap(); // UTF-8 zu ASCII konvertieren!
|
initCharsoap(charsoap); // UTF-8 zu ASCII konvertieren!
|
||||||
DEBUG_PRINTLN("✓ Standard charsoap");
|
DEBUG_PRINTLN("✓ Standard charsoap");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void saveCharsoap(const char* newCharsoap) {
|
void saveCharsoap(const char* newCharsoap)
|
||||||
if (strlen(newCharsoap) != (ROWS * COLS)) {
|
{
|
||||||
DEBUG_PRINTF("❌ Länge: %d\n", strlen(newCharsoap));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
char cleaned[uint8_t (ROWS * COLS)+1];
|
char cleaned[uint8_t (ROWS * COLS)+1];
|
||||||
uint16_t writePos = 0;
|
uint16_t writePos = 0;
|
||||||
uint16_t readPos = 0;
|
uint16_t readPos = 0;
|
||||||
|
|
@ -184,8 +185,8 @@ void saveCharsoap(const char* newCharsoap) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void resetCharsoap() {
|
void resetCharsoap() {
|
||||||
strcpy(charsoap, DEFAULT_CHARSOAP);
|
strcpy_P(charsoap, (const char*)DEFAULT_CHARSOAP);
|
||||||
initCharsoap(); // UTF-8 zu ASCII konvertieren!
|
initCharsoap(charsoap); // UTF-8 zu ASCII konvertieren!
|
||||||
customCharsoap = false;
|
customCharsoap = false;
|
||||||
EEPROM.write(ADDR_CHARSOAP_SET, 0);
|
EEPROM.write(ADDR_CHARSOAP_SET, 0);
|
||||||
EEPROM.commit();
|
EEPROM.commit();
|
||||||
|
|
@ -220,8 +221,8 @@ void loadSpecialWords() {
|
||||||
// Erste Initialisierung: Default-Werte setzen
|
// Erste Initialisierung: Default-Werte setzen
|
||||||
DEBUG_PRINTLN("Setze Standard SPECIAL_WORD...");
|
DEBUG_PRINTLN("Setze Standard SPECIAL_WORD...");
|
||||||
const char DEFAULT_SPECIAL_WORD[MAXWORDS][12] = {
|
const char DEFAULT_SPECIAL_WORD[MAXWORDS][12] = {
|
||||||
"RWD",
|
"DLZIAX",
|
||||||
"",
|
"FACW",
|
||||||
""
|
""
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -439,8 +440,8 @@ void loadConfig() {
|
||||||
DEBUG_PRINTLN("╚════════════════════════════════════════════════════╝");
|
DEBUG_PRINTLN("╚════════════════════════════════════════════════════╝");
|
||||||
|
|
||||||
// DEFAULT_CHARSOAP vorbereiten (UTF-8 → ASCII)
|
// DEFAULT_CHARSOAP vorbereiten (UTF-8 → ASCII)
|
||||||
strcpy(charsoap, DEFAULT_CHARSOAP);
|
strcpy_P(charsoap, (const char*)DEFAULT_CHARSOAP);
|
||||||
initCharsoap();
|
initCharsoap(charsoap);
|
||||||
|
|
||||||
DEBUG_PRINTLN("→ Speichere DEFAULT_CHARSOAP ins EEPROM...");
|
DEBUG_PRINTLN("→ Speichere DEFAULT_CHARSOAP ins EEPROM...");
|
||||||
|
|
||||||
|
|
@ -827,7 +828,7 @@ void displayTime(int hours, int minutes)
|
||||||
yield();
|
yield();
|
||||||
|
|
||||||
CharGraphTimeWords result;
|
CharGraphTimeWords result;
|
||||||
int8_t resultval = getCharGraphWords(DEFAULT_CHARSOAP, testPattern, hours, minutes, result);
|
int8_t resultval = getCharGraphWords(charsoap, testPattern, hours, minutes, result);
|
||||||
|
|
||||||
if (resultval == 0)
|
if (resultval == 0)
|
||||||
{
|
{
|
||||||
|
|
@ -1361,6 +1362,7 @@ void handleSave() {
|
||||||
server.send(400, "text/plain", "Fehler");
|
server.send(400, "text/plain", "Fehler");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ════════════════════════════════════════════════════════════════
|
// ════════════════════════════════════════════════════════════════
|
||||||
// LED TEST HANDLER
|
// LED TEST HANDLER
|
||||||
// ════════════════════════════════════════════════════════════════
|
// ════════════════════════════════════════════════════════════════
|
||||||
|
|
@ -2395,7 +2397,7 @@ void setup()
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
while (!Serial) { }
|
while (!Serial) { }
|
||||||
Serial.setDebugOutput(true);
|
Serial.setDebugOutput(true);
|
||||||
delay(500);
|
delay(5000);
|
||||||
Serial.setDebugOutput(false);
|
Serial.setDebugOutput(false);
|
||||||
|
|
||||||
Serial.printf("Flash Chip ID: %08X\n", ESP.getFlashChipId());
|
Serial.printf("Flash Chip ID: %08X\n", ESP.getFlashChipId());
|
||||||
|
|
@ -2450,7 +2452,7 @@ void setup()
|
||||||
EEPROM.begin(EEPROM_SIZE);
|
EEPROM.begin(EEPROM_SIZE);
|
||||||
|
|
||||||
// Zuerst Default charsoap initialisieren
|
// Zuerst Default charsoap initialisieren
|
||||||
initCharsoap();
|
initCharsoap(charsoap);
|
||||||
|
|
||||||
loadCharsoap();
|
loadCharsoap();
|
||||||
loadSpecialWords();
|
loadSpecialWords();
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user