diff --git a/RetroCall.cpp b/RetroCall.cpp new file mode 100644 index 0000000..650cc28 --- /dev/null +++ b/RetroCall.cpp @@ -0,0 +1,125 @@ +#include +#include + +// --- Pin-Konfiguration --- +const int PIN_HOOK = 25; // Gabelumschalter (Hörer abgenommen) +const int PIN_NSA = 26; // Wählscheibe dreht sich (Arbeitskontakt) +const int PIN_NSI = 27; // Wählscheibe Impulse + +// --- BLE Keyboard --- +BleKeyboard bleKeyboard("Retro Phone", "Custom", 100); + +// --- Variablen --- +String phoneNumber = ""; +int pulseCount = 0; +bool isDialing = false; +bool lastNsiState = HIGH; +unsigned long lastDebounceTime = 0; +const unsigned long debounceDelay = 20; // 20ms Entprellung für alte Mechanik + +// Timer für den automatischen Anruf nach Eingabe der letzten Ziffer +unsigned long lastDigitTime = 0; +const unsigned long dialTimeout = 4000; // 4 Sekunden warten nach der letzten Ziffer +bool callPending = false; + +void setup() { + Serial.begin(115200); + + // Interne Pull-Ups aktivieren. (Bei stark oxidierten Kontakten des + // alten Telefons externe 10k Widerstände gegen 3.3V verwenden!) + pinMode(PIN_HOOK, INPUT_PULLUP); + pinMode(PIN_NSA, INPUT_PULLUP); + pinMode(PIN_NSI, INPUT_PULLUP); + + Serial.println("Starte BLE Keyboard..."); + bleKeyboard.begin(); +} + +void triggerShortcutAndCall(String number) { + if (!bleKeyboard.isConnected()) { + Serial.println("Fehler: iPhone nicht über BLE verbunden."); + return; + } + + Serial.println("Wähle Nummer: " + number); + + // 1. Kurzbefehl auslösen (Beispiel: Option + Command + C) + // Passe diese Kombination an das an, was du im iPhone eingestellt hast. + bleKeyboard.press(KEY_LEFT_ALT); // Option + bleKeyboard.press(KEY_LEFT_GUI); // Command + bleKeyboard.press('c'); + delay(100); + bleKeyboard.releaseAll(); + + // 2. Warten, bis das iOS-Eingabefeld des Kurzbefehls erscheint + delay(1000); + + // 3. Nummer eintippen + bleKeyboard.print(number); + + // 4. Mit Enter bestätigen, um den Anruf zu starten + delay(200); + bleKeyboard.write(KEY_RETURN); +} + +void loop() { + bool hookState = digitalRead(PIN_HOOK); // LOW = Hörer abgenommen (je nach Verdrahtung) + bool nsaState = digitalRead(PIN_NSA); // LOW = Scheibe dreht + bool nsiState = digitalRead(PIN_NSI); // Wechselt LOW/HIGH bei Impulsen + + // Nur aktiv, wenn der Hörer abgenommen ist + if (hookState == LOW) { + + // Wählscheibe wird gerade gedreht + if (nsaState == LOW) { + isDialing = true; + callPending = false; // Anruf-Timer abbrechen, solange gewählt wird + + // Impulse zählen (Entprellt) + if (nsiState != lastNsiState) { + if (millis() - lastDebounceTime > debounceDelay) { + lastDebounceTime = millis(); + if (nsiState == LOW) { // Flanke je nach Schalterart anpassen + pulseCount++; + } + } + } + } + // Wählscheibe ist in Ruheposition zurückgekehrt + else if (isDialing) { + isDialing = false; + + // 10 Impulse bedeuten die Ziffer 0 + int digit = (pulseCount == 10) ? 0 : pulseCount; + phoneNumber += String(digit); + + Serial.print("Erkannte Ziffer: "); + Serial.println(digit); + + pulseCount = 0; + lastDigitTime = millis(); + callPending = true; // Timer für automatischen Anruf starten + } + + // Wenn 4 Sekunden nach der letzten Ziffer nichts passiert ist -> Anrufen + if (callPending && (millis() - lastDigitTime > dialTimeout)) { + if (phoneNumber.length() > 0) { + triggerShortcutAndCall(phoneNumber); + phoneNumber = ""; // Nummernspeicher leeren + callPending = false; + } + } + + } else { + // Hörer ist aufgelegt -> Alles zurücksetzen + if (phoneNumber.length() > 0 || callPending) { + Serial.println("Hörer aufgelegt, setze zurück."); + } + phoneNumber = ""; + pulseCount = 0; + isDialing = false; + callPending = false; + } + + lastNsiState = nsiState; +} \ No newline at end of file diff --git a/new.cpp b/new.cpp new file mode 100644 index 0000000..df7ca0e --- /dev/null +++ b/new.cpp @@ -0,0 +1,163 @@ +#include +#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 + +// --- 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) + +// --- BLE Keyboard Instanz --- +BleKeyboard bleKeyboard("FeTAp 791 Telefon", "Deutsche Bundespost", 100); + +// --- Interrupt-Variablen (müssen volatile sein!) --- +volatile int pulseCount = 0; +volatile unsigned long lastPulseTime = 0; +volatile bool isDialing = false; + +// --- Hauptprogramm-Variablen --- +bool bleConnectedLastState = false; +bool hookLastState = false; + +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 - ESP32 mit Hardware-Interrupt"); + Serial.println("========================================="); + + 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) { + if (!bleKeyboard.isConnected()) { + Serial.println("[BLE] Nicht verbunden – Kurzbefehl 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); + delay(100); + bleKeyboard.write(KEY_RETURN); +} + +void processDialedDigit(int pulses) { + 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); + return; + } + + dialedNumber += digitChar; + 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 + 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; + } + + // 2. Gabelumschalter (Hook) + bool currentHookState = digitalRead(PIN_HOOK); + if (currentHookState != hookLastState) { + delay(20); // Entprellen der Gabel + currentHookState = digitalRead(PIN_HOOK); + + if (currentHookState != hookLastState) { + hookLastState = currentHookState; + + if (currentHookState == HIGH) { + Serial.println("\n[Hörer] ABGEHOBEN"); + dialedNumber = ""; + waitingForCompleteNumber = false; + + // Interrupt aktivieren / Zähler nullen + pulseCount = 0; + isDialing = false; + } else { + Serial.println("\n[Hörer] AUFGELEGT"); + dialedNumber = ""; + waitingForCompleteNumber = false; + pulseCount = 0; + isDialing = false; + } + } + } + + // 3. Auswertung der Ziffern & Rufnummer (nur bei abgehobenem Hörer) + 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(); + + if (currentPulses > 0) { + processDialedDigit(currentPulses); + } + } + + // 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); + } + } +} \ No newline at end of file diff --git a/platform.ini b/platform.ini new file mode 100644 index 0000000..46c1854 --- /dev/null +++ b/platform.ini @@ -0,0 +1,7 @@ +[env:esp32dev] +platform = espressif32 +board = esp32dev +framework = arduino +monitor_speed = 115200 +lib_deps = + t-vk/ESP32 BLE Keyboard @ ^0.3.2 \ No newline at end of file