Wählen funktioniert

This commit is contained in:
2026-09-02 22:11:30 +02:00
parent 5d4bd8bfd9
commit 965ac81f1f
3 changed files with 125 additions and 97 deletions
+1 -1
View File
@@ -1 +1 @@
c1b704a06958664cdd86ed07b79b2a04332e2c72 ee4a55eacb7a28959a3c3df9f700b6996855c849
+1 -1
View File
@@ -1,5 +1,5 @@
[env:esp32dev] [env:esp32dev]
platform = espressif32 platform = espressif32 @ 6.5.0
board = esp32dev board = esp32dev
framework = arduino framework = arduino
monitor_speed = 115200 monitor_speed = 115200
+123 -95
View File
@@ -2,162 +2,190 @@
#include <BleKeyboard.h> #include <BleKeyboard.h>
// --- Pin-Definitionen --- // --- Pin-Definitionen ---
#define PIN_HOOK 18 // GRÜN: HIGH = Hörer abgehoben, LOW = aufgelegt #define PIN_NSA 18 // Nummernschalter-Arbeitskontakt (HIGH wenn Scheibe gedreht)
#define PIN_DIAL 19 // WEISS: HIGH bei Drehung, fallende Flanken = Impulse #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 NSI_DEBOUNCE_MS 15 // Entprellung für die Impulse
#define DEBOUNCE_MS 30 // Entprellzeit für Impulse (ms) #define COMPLETE_DIAL_TIMEOUT 2500 // 2,5 Sekunden Pause nach letzter Ziffer bis zum Enter
#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)
// --- BLE Keyboard Instanz --- BleKeyboard bleKeyboard("FeTAp 791", "Deutsche Bundespost", 100);
BleKeyboard bleKeyboard("FeTAp 791 Telefon", "Deutsche Bundespost", 100);
// --- Interrupt-Variablen (müssen volatile sein!) --- // --- Status-Variablen ---
volatile int pulseCount = 0;
volatile unsigned long lastPulseTime = 0;
volatile bool isDialing = false;
// --- Hauptprogramm-Variablen ---
bool bleConnectedLastState = false; 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 = ""; String dialedNumber = "";
unsigned long lastDigitCompletedTime = 0; unsigned long lastDigitCompletedTime = 0;
bool waitingForCompleteNumber = false; 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() { void setup() {
Serial.begin(115200); Serial.begin(115200);
delay(1000); delay(1000);
Serial.println("\n=======================================================");
Serial.println("FeTAp 791 - ESC bei jedem Auflegen aktiv");
Serial.println("=======================================================");
Serial.println("\n========================================="); pinMode(PIN_NSA, INPUT_PULLDOWN);
Serial.println("FeTAp 791 - ESP32 mit Hardware-Interrupt"); pinMode(PIN_NSI, INPUT_PULLDOWN);
Serial.println("=========================================");
pinMode(PIN_HOOK, 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(); bleKeyboard.begin();
Serial.println("[BLE] Warte auf Verbindung zum iPhone...");
} }
void triggerIphoneShortcut(String number) { void triggerShortcut() {
if (!bleKeyboard.isConnected()) { if (!bleKeyboard.isConnected()) {
Serial.println("[BLE] Nicht verbunden – Kurzbefehl kann nicht gesendet werden!"); Serial.println("[BLE] Nicht verbunden - Shortcut kann nicht gesendet werden.");
return; return;
} }
Serial.printf("[Kurzbefehl] Starte Aktion für Rufnummer: %s\n", number.c_str()); Serial.println("[Shortcut] Sende Option + Command + C an iPhone...");
// Nummer eintippen und mit 'Enter' bestätigen bleKeyboard.press(KEY_LEFT_ALT);
bleKeyboard.print(number); bleKeyboard.press(KEY_LEFT_GUI);
bleKeyboard.press('c');
delay(100); 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; char digitChar;
if (pulses == 10) { if (rawPulses == 10) digitChar = '0';
digitChar = '0'; else if (rawPulses >= 1 && rawPulses <= 9) digitChar = '0' + rawPulses;
} else if (pulses >= 1 && pulses <= 9) { else {
digitChar = '0' + pulses; Serial.printf("[Fehler] Ungültige Pulsanzahl: %d\n", rawPulses);
} else {
Serial.printf("[Wahl] Ungültige Impulsanzahl (%d) ignoriert.\n", pulses);
return; return;
} }
dialedNumber += digitChar; 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(); lastDigitCompletedTime = millis();
waitingForCompleteNumber = true; waitingForCompleteNumber = true;
Serial.printf("[Wahl] Ziffer: %c | Aktuelle Nummer: %s\n", digitChar, dialedNumber.c_str());
} }
void loop() { void loop() {
unsigned long currentMillis = millis(); unsigned long currentMillis = millis();
// 1. Bluetooth-Verbindungsstatus // 1. Bluetooth Status überwachen
bool isConnectedNow = bleKeyboard.isConnected(); bool isConnectedNow = bleKeyboard.isConnected();
if (isConnectedNow && !bleConnectedLastState) { if (isConnectedNow != bleConnectedLastState) {
Serial.println("\n[BLE] >>> iPhone erfolgreich VERBUNDEN! <<<"); bleConnectedLastState = isConnectedNow;
bleConnectedLastState = true; Serial.println(isConnectedNow ? "\n[BLE] iPhone VERBUNDEN!" : "\n[BLE] Verbindung VERLOREN!");
} else if (!isConnectedNow && bleConnectedLastState) {
Serial.println("\n[BLE] >>> Verbindung zum iPhone VERLOREN! <<<");
bleConnectedLastState = false;
} }
// 2. Gabelumschalter (Hook) // 2. Gabelumschalter (Hook) auf PIN 21 auswerten
bool currentHookState = digitalRead(PIN_HOOK); bool currentHookState = digitalRead(PIN_HOOK);
if (currentHookState != hookLastState) { if (currentHookState != hookLastState) {
delay(20); // Entprellen der Gabel if ((currentMillis - hookDebounceTime) > 50) {
currentHookState = digitalRead(PIN_HOOK);
if (currentHookState != hookLastState) {
hookLastState = currentHookState; hookLastState = currentHookState;
hookDebounceTime = currentMillis;
if (currentHookState == HIGH) { if (hookLastState == HIGH) {
Serial.println("\n[Hörer] ABGEHOBEN"); Serial.println("\n[Hörer] ABGEHOBEN");
dialedNumber = ""; dialedNumber = "";
waitingForCompleteNumber = false; waitingForCompleteNumber = false;
// Interrupt aktivieren / Zähler nullen // Shortcut beim Abheben ausführen
pulseCount = 0; triggerShortcut();
isDialing = false;
} else { } else {
Serial.println("\n[Hörer] AUFGELEGT"); 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 = ""; dialedNumber = "";
waitingForCompleteNumber = false; 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) { if (hookLastState == HIGH) {
// A) Ist die Ziffern-Drehung beendet? (Timeout seit letztem Interrupt-Impuls) // A) NSA auswerten (Das "Fenster" für eine Ziffer)
if (isDialing && (currentMillis - lastPulseTime > DIGIT_TIMEOUT_MS)) { bool currentNsaState = digitalRead(PIN_NSA);
if (currentNsaState != lastNsaState) {
// Für die sichere Übergabe aus der ISR kurz Interrupts pausieren oder Wert kopieren delay(15); // Kurzes Entprellen des Arbeitskontakts
noInterrupts(); if (digitalRead(PIN_NSA) == currentNsaState) {
int currentPulses = pulseCount; lastNsaState = currentNsaState;
pulseCount = 0;
isDialing = false;
interrupts();
if (currentPulses > 0) { if (currentNsaState == HIGH) {
processDialedDigit(currentPulses); 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) // B) NSI auswerten (Impulse zählen während NSA = HIGH)
if (waitingForCompleteNumber && (currentMillis - lastDigitCompletedTime > COMPLETE_DIAL_TIMEOUT)) { if (lastNsaState == HIGH) {
waitingForCompleteNumber = false; bool currentNsiState = digitalRead(PIN_NSI);
Serial.printf("\n[Wahl abgeschlossen] Vollständige Nummer: %s\n", dialedNumber.c_str());
if (currentNsiState != lastNsiState) {
// Kurzbefehl am iPhone ausführen lastNsiDebounceTime = millis();
triggerIphoneShortcut(dialedNumber); }
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 = "";
}
} }
} }
} }