From 965ac81f1fdbdbf875826817dc9ee9189ccf9ff5 Mon Sep 17 00:00:00 2001 From: Daniel Date: Wed, 2 Sep 2026 22:11:30 +0200 Subject: [PATCH] =?UTF-8?q?W=C3=A4hlen=20funktioniert?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .pio/build/project.checksum | 2 +- platformio.ini | 2 +- src/main.cpp | 218 ++++++++++++++++++++---------------- 3 files changed, 125 insertions(+), 97 deletions(-) diff --git a/.pio/build/project.checksum b/.pio/build/project.checksum index 632145f..d7cefc2 100644 --- a/.pio/build/project.checksum +++ b/.pio/build/project.checksum @@ -1 +1 @@ -c1b704a06958664cdd86ed07b79b2a04332e2c72 \ No newline at end of file +ee4a55eacb7a28959a3c3df9f700b6996855c849 \ No newline at end of file diff --git a/platformio.ini b/platformio.ini index 46c1854..13a69bc 100644 --- a/platformio.ini +++ b/platformio.ini @@ -1,5 +1,5 @@ [env:esp32dev] -platform = espressif32 +platform = espressif32 @ 6.5.0 board = esp32dev framework = arduino monitor_speed = 115200 diff --git a/src/main.cpp b/src/main.cpp index df7ca0e..0f026f0 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2,162 +2,190 @@ #include // --- Pin-Definitionen --- -#define PIN_HOOK 18 // GRÜN: HIGH = Hörer abgehoben, LOW = aufgelegt -#define PIN_DIAL 19 // WEISS: HIGH bei Drehung, fallende Flanken = Impulse +#define PIN_NSA 18 // Nummernschalter-Arbeitskontakt (HIGH wenn Scheibe gedreht) +#define PIN_NSI 19 // Nummernschalter-Impulskontakt (Pulst während des Ablaufs) +#define PIN_HOOK 21 // Gabelumschalter (HIGH = Hörer abgehoben, LOW = aufgelegt) -// --- Hardware & Timing-Konstanten --- -#define DEBOUNCE_MS 30 // Entprellzeit für Impulse (ms) -#define DIGIT_TIMEOUT_MS 350 // Pause nach Drehung, bis Ziffer erkannt ist (ms) -#define COMPLETE_DIAL_TIMEOUT 2500 // Pause nach letzter Ziffer, bis Rufnummer komplett ist (ms) +#define NSI_DEBOUNCE_MS 15 // Entprellung für die Impulse +#define COMPLETE_DIAL_TIMEOUT 2500 // 2,5 Sekunden Pause nach letzter Ziffer bis zum Enter -// --- BLE Keyboard Instanz --- -BleKeyboard bleKeyboard("FeTAp 791 Telefon", "Deutsche Bundespost", 100); +BleKeyboard bleKeyboard("FeTAp 791", "Deutsche Bundespost", 100); -// --- Interrupt-Variablen (müssen volatile sein!) --- -volatile int pulseCount = 0; -volatile unsigned long lastPulseTime = 0; -volatile bool isDialing = false; - -// --- Hauptprogramm-Variablen --- +// --- Status-Variablen --- bool bleConnectedLastState = false; -bool hookLastState = false; +bool hookLastState = LOW; +unsigned long hookDebounceTime = 0; +// NSA (Arbeitskontakt) +bool lastNsaState = LOW; + +// NSI (Impulskontakt) +bool lastNsiState = LOW; +bool stableNsiState = LOW; +unsigned long lastNsiDebounceTime = 0; + +int pulseCount = 0; String dialedNumber = ""; unsigned long lastDigitCompletedTime = 0; bool waitingForCompleteNumber = false; -// ------------------------------------------------------------------- -// Interrupt Service Routine (ISR) für die fallende Flanke -// ------------------------------------------------------------------- -// 'IRAM_ATTR' sorgt dafür, dass dieser Code im schnellen RAM des ESP32 liegt -void IRAM_ATTR handleDialPulse() { - unsigned long currentMillis = millis(); - - // Entprellung direkt im Interrupt: - // Nur zählen, wenn der letzte Impuls länger als DEBOUNCE_MS her ist - if ((currentMillis - lastPulseTime) > DEBOUNCE_MS) { - pulseCount++; - isDialing = true; - lastPulseTime = currentMillis; - } -} - void setup() { Serial.begin(115200); delay(1000); + Serial.println("\n======================================================="); + Serial.println("FeTAp 791 - ESC bei jedem Auflegen aktiv"); + Serial.println("======================================================="); - Serial.println("\n========================================="); - Serial.println("FeTAp 791 - ESP32 mit Hardware-Interrupt"); - Serial.println("========================================="); - + pinMode(PIN_NSA, INPUT_PULLDOWN); + pinMode(PIN_NSI, INPUT_PULLDOWN); pinMode(PIN_HOOK, INPUT_PULLDOWN); - pinMode(PIN_DIAL, INPUT_PULLDOWN); - - // --- Hardware-Interrupt konfigurieren --- - // Löst 'handleDialPulse()' EXAKT beim Übergang von HIGH nach LOW aus! - attachInterrupt(digitalPinToInterrupt(PIN_DIAL), handleDialPulse, FALLING); - + bleKeyboard.begin(); - Serial.println("[BLE] Warte auf Verbindung zum iPhone..."); } -void triggerIphoneShortcut(String number) { +void triggerShortcut() { if (!bleKeyboard.isConnected()) { - Serial.println("[BLE] Nicht verbunden – Kurzbefehl kann nicht gesendet werden!"); + Serial.println("[BLE] Nicht verbunden - Shortcut kann nicht gesendet werden."); return; } - Serial.printf("[Kurzbefehl] Starte Aktion für Rufnummer: %s\n", number.c_str()); - - // Nummer eintippen und mit 'Enter' bestätigen - bleKeyboard.print(number); + Serial.println("[Shortcut] Sende Option + Command + C an iPhone..."); + + bleKeyboard.press(KEY_LEFT_ALT); + bleKeyboard.press(KEY_LEFT_GUI); + bleKeyboard.press('c'); delay(100); - bleKeyboard.write(KEY_RETURN); + bleKeyboard.releaseAll(); } -void processDialedDigit(int pulses) { +void sendCancel() { + if (!bleKeyboard.isConnected()) return; + + Serial.println("[Abbruch] Sende ESC (Cancel) an iPhone..."); + bleKeyboard.write(KEY_ESC); +} + +void processDigit(int rawPulses) { char digitChar; - if (pulses == 10) { - digitChar = '0'; - } else if (pulses >= 1 && pulses <= 9) { - digitChar = '0' + pulses; - } else { - Serial.printf("[Wahl] Ungültige Impulsanzahl (%d) ignoriert.\n", pulses); + if (rawPulses == 10) digitChar = '0'; + else if (rawPulses >= 1 && rawPulses <= 9) digitChar = '0' + rawPulses; + else { + Serial.printf("[Fehler] Ungültige Pulsanzahl: %d\n", rawPulses); return; } dialedNumber += digitChar; + + // Ziffer sofort ans iPhone senden + if (bleKeyboard.isConnected()) { + Serial.printf("[Wahl] Ziffer %c erkannt und sofort an iPhone gesendet.\n", digitChar); + bleKeyboard.print(digitChar); + } else { + Serial.printf("[Wahl] Ziffer %c erkannt, aber nicht verbunden.\n", digitChar); + } + + // Timer für das abschließende Enter starten lastDigitCompletedTime = millis(); waitingForCompleteNumber = true; - - Serial.printf("[Wahl] Ziffer: %c | Aktuelle Nummer: %s\n", digitChar, dialedNumber.c_str()); } void loop() { unsigned long currentMillis = millis(); - // 1. Bluetooth-Verbindungsstatus + // 1. Bluetooth Status überwachen bool isConnectedNow = bleKeyboard.isConnected(); - if (isConnectedNow && !bleConnectedLastState) { - Serial.println("\n[BLE] >>> iPhone erfolgreich VERBUNDEN! <<<"); - bleConnectedLastState = true; - } else if (!isConnectedNow && bleConnectedLastState) { - Serial.println("\n[BLE] >>> Verbindung zum iPhone VERLOREN! <<<"); - bleConnectedLastState = false; + if (isConnectedNow != bleConnectedLastState) { + bleConnectedLastState = isConnectedNow; + Serial.println(isConnectedNow ? "\n[BLE] iPhone VERBUNDEN!" : "\n[BLE] Verbindung VERLOREN!"); } - // 2. Gabelumschalter (Hook) + // 2. Gabelumschalter (Hook) auf PIN 21 auswerten bool currentHookState = digitalRead(PIN_HOOK); if (currentHookState != hookLastState) { - delay(20); // Entprellen der Gabel - currentHookState = digitalRead(PIN_HOOK); - - if (currentHookState != hookLastState) { + if ((currentMillis - hookDebounceTime) > 50) { hookLastState = currentHookState; + hookDebounceTime = currentMillis; - if (currentHookState == HIGH) { + if (hookLastState == HIGH) { Serial.println("\n[Hörer] ABGEHOBEN"); dialedNumber = ""; waitingForCompleteNumber = false; - // Interrupt aktivieren / Zähler nullen - pulseCount = 0; - isDialing = false; + // Shortcut beim Abheben ausführen + triggerShortcut(); } else { Serial.println("\n[Hörer] AUFGELEGT"); + + // Bei jedem Auflegen ESC senden, um das Eingabefenster (egal ob leer oder teilgewählt) zu schließen + sendCancel(); + dialedNumber = ""; waitingForCompleteNumber = false; - pulseCount = 0; - isDialing = false; } } } - // 3. Auswertung der Ziffern & Rufnummer (nur bei abgehobenem Hörer) + // 3. Wählscheibe NUR auswerten, wenn der Hörer abgehoben ist if (hookLastState == HIGH) { - // A) Ist die Ziffern-Drehung beendet? (Timeout seit letztem Interrupt-Impuls) - if (isDialing && (currentMillis - lastPulseTime > DIGIT_TIMEOUT_MS)) { - - // Für die sichere Übergabe aus der ISR kurz Interrupts pausieren oder Wert kopieren - noInterrupts(); - int currentPulses = pulseCount; - pulseCount = 0; - isDialing = false; - interrupts(); + // A) NSA auswerten (Das "Fenster" für eine Ziffer) + bool currentNsaState = digitalRead(PIN_NSA); + if (currentNsaState != lastNsaState) { + delay(15); // Kurzes Entprellen des Arbeitskontakts + if (digitalRead(PIN_NSA) == currentNsaState) { + lastNsaState = currentNsaState; - if (currentPulses > 0) { - processDialedDigit(currentPulses); + if (currentNsaState == HIGH) { + Serial.println("\n[NSA] Scheibe aufgezogen - beginne Messung..."); + pulseCount = 0; + } else { + Serial.println("[NSA] Scheibe steht - werte Impulse aus..."); + if (pulseCount > 0) { + processDigit(pulseCount); + pulseCount = 0; + } + } } } - // B) Ist die komplette Rufnummer fertig gewählt? (Pause nach letzter Ziffer) - if (waitingForCompleteNumber && (currentMillis - lastDigitCompletedTime > COMPLETE_DIAL_TIMEOUT)) { - waitingForCompleteNumber = false; - Serial.printf("\n[Wahl abgeschlossen] Vollständige Nummer: %s\n", dialedNumber.c_str()); - - // Kurzbefehl am iPhone ausführen - triggerIphoneShortcut(dialedNumber); + // B) NSI auswerten (Impulse zählen während NSA = HIGH) + if (lastNsaState == HIGH) { + bool currentNsiState = digitalRead(PIN_NSI); + + if (currentNsiState != lastNsiState) { + lastNsiDebounceTime = millis(); + } + lastNsiState = currentNsiState; + + if ((millis() - lastNsiDebounceTime) > NSI_DEBOUNCE_MS) { + if (currentNsiState != stableNsiState) { + stableNsiState = currentNsiState; + + if (stableNsiState == LOW) { + pulseCount++; + Serial.printf(" --> Puls %d registriert\n", pulseCount); + } + } + } + } + + // C) Enter nach 2,5 Sekunden Inaktivität senden + if (waitingForCompleteNumber) { + unsigned long elapsed = millis() - lastDigitCompletedTime; + + if (elapsed > COMPLETE_DIAL_TIMEOUT) { + waitingForCompleteNumber = false; + + if (bleKeyboard.isConnected() && dialedNumber.length() > 0) { + Serial.printf("\n[Wahl abgeschlossen] Sende Enter (KEY_RETURN) für Nummer: %s\n", dialedNumber.c_str()); + bleKeyboard.write(KEY_RETURN); + } else { + Serial.println("\n[Fehler] Entweder nicht verbunden oder Puffer leer."); + } + + // Puffer für die nächste Wahl leeren + dialedNumber = ""; + } } } } \ No newline at end of file