Wählen funktioniert
This commit is contained in:
@@ -1 +1 @@
|
|||||||
c1b704a06958664cdd86ed07b79b2a04332e2c72
|
ee4a55eacb7a28959a3c3df9f700b6996855c849
|
||||||
+1
-1
@@ -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
@@ -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 = "";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user