diff --git a/README.md b/README.md index f2a115c..7c1971c 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,21 @@ Projet PlatformIO ESP32 pour recycler un téléphone RTC ancien (combiné, clavi ## Démarrage rapide 1. Ouvrir le dossier dans PlatformIO. +2. Compiler et flasher l'environnement `esp32-s3-devkitc-1` (par défaut). +3. Ouvrir le moniteur série à 115200 bauds. +4. Utiliser les commandes série (`h`, `r`, `o`, `d`, `c`) pour piloter la machine d'états. + +## Choix de cartes ESP32 +Voir `docs/solutions_rtc_phone_esp32.md` pour la shortlist des DevKit utilisables (ESP32-DevKitC, ESP32-S3-DevKitC-1, NodeMCU-32S, LOLIN32), les liens de référence web, et les solutions d’interface (direct combiné/clavier, SLIC/FXS, ATA externe), dont une variante AG1171S (Silvertel). + +## Plan projet (chef de projet) +Voir `docs/plan_chef_projet_esp32s3_ag1171s.md` pour le planning en phases, les risques, les critères d'acceptation et les livrables de la version ESP32-S3 + AG1171S. + +## Contenu +- `platformio.ini`: configuration multi-env (ESP32-S3 par défaut + ESP32 legacy). +- `src/main.cpp`: squelette firmware machine d'états pour intégration AG1171S. +- `docs/solutions_rtc_phone_esp32.md`: comparaison des architectures et recommandations. +- `docs/plan_chef_projet_esp32s3_ag1171s.md`: plan d'exécution projet version V0.1. 2. Compiler et flasher l'environnement `esp32dev`. 3. Ouvrir le moniteur série à 115200 bauds. diff --git a/docs/plan_chef_projet_esp32s3_ag1171s.md b/docs/plan_chef_projet_esp32s3_ag1171s.md new file mode 100644 index 0000000..1aebdcc --- /dev/null +++ b/docs/plan_chef_projet_esp32s3_ag1171s.md @@ -0,0 +1,51 @@ +# Plan chef de projet — ESP32-S3 + AG1171S (Silvertel) + +## 1) Objectif projet +Livrer un prototype fonctionnel "téléphone analogique ancien" piloté par ESP32-S3, avec interface 2 fils privée via AG1171S, sans connexion PSTN publique. + +## 2) Périmètre (version V0.1) +- Détection hook (on/off hook). +- Commande d'activation ligne (line enable). +- Commande de sonnerie (ring command/cadence côté analogique). +- Journal série + machine d'états téléphonie basique. +- Cible matérielle principale: **ESP32-S3-DevKitC-1**. + +## 3) Planning macro +### Phase A — Cadrage & schéma (Semaine 1) +- Valider broches AG1171S retenues (hook detect, ring control, line feed control). +- Produire schéma de câblage V0.1 (alims, masses, protections, découplage). +- Sortie: checklist sécurité + BOM V0.1. + +### Phase B — Firmware fondation (Semaine 2) +- Mettre en place environnement PlatformIO `esp32-s3-devkitc-1`. +- Implémenter machine d'états: `ON_HOOK`, `OFF_HOOK`, `DIALING`, `IN_CALL`, `RINGING`. +- Ajouter commandes série pour tests rapides (`r/o/d/c`). +- Sortie: build firmware de base + logs validés. + +### Phase C — Intégration hardware (Semaine 3) +- Câblage réel ESP32-S3 ↔ AG1171S. +- Test de robustesse hook (anti-rebond + stabilité). +- Test commande ring/line sans charge puis avec téléphone analogique. +- Sortie: matrice de tests V0.1 avec résultats. + +### Phase D — Validation système (Semaine 4) +- Campagne tests end-to-end: raccroché/décroché, sonnerie, transitions d'état. +- Vérifier alimentation et thermique. +- Corriger pinout/temporisations selon résultats. +- Sortie: release candidate V0.1. + +## 4) Risques & mitigation +- **Risque analogique (niveaux/impédance):** prévoir test progressif et instrumentation (oscillo, multimètre). +- **Risque sécurité téléphonie:** rester hors PSTN publique tant que conformité non traitée. +- **Risque planning:** découper firmware et hardware en jalons testables hebdomadaires. + +## 5) Critères d'acceptation V0.1 +- Boot stable sur ESP32-S3. +- Hook detect stable (> 100 transitions sans faux positif en test de banc). +- Commande `RINGING` active le signal de commande attendu. +- Retour `ON_HOOK` coupe ligne et ring command. + +## 6) Suite (V0.2+) +- Ajout décodage numérotation (DTMF/pulse). +- Ajout audio (codec I2S) et scénarios d'appel avancés. +- Option passerelle SIP locale. diff --git a/docs/solutions_rtc_phone_esp32.md b/docs/solutions_rtc_phone_esp32.md index c9e53a8..0b2efdc 100644 --- a/docs/solutions_rtc_phone_esp32.md +++ b/docs/solutions_rtc_phone_esp32.md @@ -41,6 +41,41 @@ Créer un projet PlatformIO sur ESP32 pour réutiliser un ancien téléphone ana - Design analogique + sécurité plus exigeants. - Debug plus long. +### Variante concrète: module **Silvertel AG1171S** +Si tu veux garder un ancien téléphone tel quel (2 fils TIP/RING) avec une carte ESP32, l'AG1171S est une piste concrète côté **FXS/SLIC**. + +#### Ce que ça apporte +- Génération de la boucle analogique pour alimenter un poste RTC ancien. +- Interface pensée pour créer une "ligne privée" locale (pas une connexion directe PSTN brute). +- Réduction de la complexité analogique par rapport à un design SLIC discret from-scratch. + +#### Comment l'intégrer proprement avec ESP32 +1. **AG1171S = étage ligne analogique** (alimentation de boucle, interface 2 fils). +2. **ESP32 = logique et signalisation** (états off-hook/on-hook, numérotation, scénarios). +3. **Chemin audio**: + - soit via codec audio externe (I2S) + adaptation vers l'étage ligne, + - soit via une architecture où l'audio analogique reste majoritairement côté téléphonie, et l'ESP32 pilote surtout la logique. +4. **Détection d'événements**: exposer vers GPIO les états utiles (hook, ring detect selon schéma d'application). + +#### Points d'attention (importants) +- Respecter strictement les notes d'application Silvertel (DC feed, protection, découplage, routage). +- Ne pas connecter à une ligne publique sans conformité réglementaire et schéma adapté. +- Prévoir protections (surintensité/surtension) et isolation selon l'usage final. +- Valider impédance et niveau audio pour éviter faible volume, saturation, écho/larsen. + +#### Recommandation projet +- **MVP rapide**: continuer Option A (combiné + clavier en hard) pour avancer sur firmware. +- **Version "vraie ligne 2 fils"**: passer en Option B avec AG1171S quand la logique applicative est stable. + + +### Proposition de mapping initial (ESP32-S3-DevKitC-1) +- `GPIO4` : Hook sense (entrée, `INPUT_PULLUP`, actif bas selon câblage). +- `GPIO5` : Ring command (sortie logique vers étage de commande sonnerie). +- `GPIO6` : Line enable (sortie logique vers activation ligne AG1171S). +- `GPIO48`: LED debug état firmware. + +> Ce mapping est un **point de départ firmware** et doit être validé/ajusté selon le schéma AG1171S final. + ## Option C — Passerelle hybride (ATA/FXS externe + ESP32 contrôle) ### Principe - L'audio et la boucle téléphonique sont gérés par un matériel externe (ATA/box FXS). @@ -101,6 +136,41 @@ Créer un projet PlatformIO sur ESP32 pour réutiliser un ancien téléphone ana - Ajouter journal série détaillé dès le début. - Écrire des tests de mapping clavier (table de correspondance). + +## Solutions existantes pour interfacer un ancien téléphone à un microcontrôleur + +Oui, il existe plusieurs familles de solutions déjà utilisées en pratique: + +1. **Interface combiné “en direct” (hook + clavier + audio séparé)** + - Tu n’utilises pas la ligne RJ11 d’origine: tu récupères seulement le crochet, le clavier, le micro et l’écouteur. + - C’est la méthode la plus simple pour ESP32 et la plus sûre pour un prototype. + - Très bien pour interphone, SIP local, Bluetooth, domotique vocale. + +2. **Interface FXS/SLIC (émuler une vraie ligne analogique privée)** + - Le microcontrôleur pilote un front-end téléphonique spécialisé qui fournit tension de ligne, courant de boucle et sonnerie. + - C’est la solution “propre téléphonie” si tu veux brancher un poste analogique sur 2 fils comme à l’époque. + - Plus complexe en électronique et en sécurité CEM/isolement. + +3. **Interface FXO/DAA (recevoir ou analyser une ligne analogique existante)** + - Utilisée quand on veut interfacer une ligne analogique côté “réseau”. + - Demande encore plus de prudence réglementaire/sécurité selon le pays. + +4. **Passerelle ATA externe (FXS déjà intégrée)** + - Exemple courant: un ATA SIP/FXS fait tout le travail téléphonique analogique. + - L’ESP32 ne gère que la logique (capteurs, scénarios, UI, automation). + - Super choix pour aller vite avec une bonne qualité audio. + +5. **Décodage DTMF / cadran impulsionnel dédié** + - Si ton téléphone est à cadran ou clavier ancien, tu peux ajouter un étage dédié: + - décodage DTMF matériel, + - ou capture d’impulsions du cadran via GPIO + anti-rebond/filtrage. + - Souvent combiné avec l’Option A. + +### Ce qui marche le mieux pour ton cas +- Vu ton besoin ("combiné + clavier en hard"), la meilleure approche reste: + - **MVP: interface directe (Option A)**, + - puis migration vers **ATA externe** ou **SLIC/FXS** si tu veux une expérience “ligne RTC” complète. + ## Sources web utiles - Espressif DevKitC: https://docs.espressif.com/projects/esp-dev-kits/en/latest/esp32/esp32-devkitc/index.html - Espressif S3 DevKitC-1: https://docs.espressif.com/projects/esp-dev-kits/en/latest/esp32s3/esp32-s3-devkitc-1/index.html @@ -109,6 +179,9 @@ Créer un projet PlatformIO sur ESP32 pour réutiliser un ancien téléphone ana - PlatformIO `nodemcu-32s`: https://docs.platformio.org/en/latest/boards/espressif32/nodemcu-32s.html - PlatformIO `lolin32`: https://docs.platformio.org/en/latest/boards/espressif32/lolin32.html - PlatformIO `esp32-c3-devkitc-02`: https://docs.platformio.org/en/latest/boards/espressif32/esp32-c3-devkitc-02.html +- Asterisk documentation (PBX/VoIP): https://docs.asterisk.org/ +- Exemple ATA FXS (Grandstream HT801): https://www.grandstream.com/products/gateways-and-atas/analog-telephone-adaptors/product/ht801 +- Silvertel (catalogue modules téléphonie): https://www.silvertel.com/ ## Décision proposée Pour ton besoin immédiat (PLIP / combiné + clavier en hard), la **meilleure balance risque/temps** est: diff --git a/platformio.ini b/platformio.ini index 163c888..bd79eb8 100644 --- a/platformio.ini +++ b/platformio.ini @@ -1,4 +1,8 @@ [platformio] +default_envs = esp32-s3-devkitc-1 + +[env] +platform = espressif32 default_envs = esp32dev [env:esp32dev] @@ -8,5 +12,11 @@ framework = arduino monitor_speed = 115200 build_flags = -DCORE_DEBUG_LEVEL=1 + +[env:esp32-s3-devkitc-1] +board = esp32-s3-devkitc-1 + +[env:esp32dev] +board = esp32dev lib_deps = bblanchon/ArduinoJson@^7.0.4 diff --git a/src/main.cpp b/src/main.cpp index bcc2da7..1b6ed2f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,5 +1,190 @@ #include +/* + RTC_BL_PHONE - ESP32-S3 + AG1171S control skeleton + + Goal: + - Provide a practical firmware base for a private analog line project. + - Keep telephony analog front-end on AG1171S side. + - Let ESP32 manage call-state logic and debug observability. + + Notes: + - Pin mapping must be validated against your AG1171S application schematic. + - Never connect to PSTN without compliant isolation/protection design. +*/ + +enum class PhoneState : uint8_t { + ON_HOOK, + OFF_HOOK, + DIALING, + IN_CALL, + RINGING +}; + +struct PhonePins { + uint8_t pinHookSense; + uint8_t pinRingCmd; + uint8_t pinLineEnable; + uint8_t pinLed; +}; + +#if CONFIG_IDF_TARGET_ESP32S3 +constexpr PhonePins PINS{ + .pinHookSense = 4, // AG1171S hook/off-hook indication input to ESP32-S3 + .pinRingCmd = 5, // ESP32-S3 output: request ring cadence generator/enable + .pinLineEnable = 6, // ESP32-S3 output: line feed enable (through safe driver) + .pinLed = 48 // ESP32-S3 DevKitC-1 RGB/Status-compatible GPIO +}; +#else +constexpr PhonePins PINS{ + .pinHookSense = 27, + .pinRingCmd = 26, + .pinLineEnable = 25, + .pinLed = 2 +}; +#endif + +constexpr uint32_t SERIAL_BAUD = 115200; +constexpr uint32_t DEBOUNCE_MS = 25; + +PhoneState g_state = PhoneState::ON_HOOK; +bool g_hookOffHook = false; +uint32_t g_lastHookEdgeMs = 0; + +const char* stateToString(PhoneState state) { + switch (state) { + case PhoneState::ON_HOOK: return "ON_HOOK"; + case PhoneState::OFF_HOOK: return "OFF_HOOK"; + case PhoneState::DIALING: return "DIALING"; + case PhoneState::IN_CALL: return "IN_CALL"; + case PhoneState::RINGING: return "RINGING"; + } + + return "UNKNOWN"; +} + +void setState(PhoneState newState) { + if (newState == g_state) { + return; + } + + g_state = newState; + Serial.printf("[RTC_PHONE] state=%s\n", stateToString(g_state)); + + switch (g_state) { + case PhoneState::ON_HOOK: + digitalWrite(PINS.pinLineEnable, LOW); + digitalWrite(PINS.pinRingCmd, LOW); + digitalWrite(PINS.pinLed, LOW); + break; + + case PhoneState::OFF_HOOK: + digitalWrite(PINS.pinLineEnable, HIGH); + digitalWrite(PINS.pinRingCmd, LOW); + digitalWrite(PINS.pinLed, HIGH); + break; + + case PhoneState::DIALING: + digitalWrite(PINS.pinLineEnable, HIGH); + digitalWrite(PINS.pinRingCmd, LOW); + digitalWrite(PINS.pinLed, HIGH); + break; + + case PhoneState::IN_CALL: + digitalWrite(PINS.pinLineEnable, HIGH); + digitalWrite(PINS.pinRingCmd, LOW); + digitalWrite(PINS.pinLed, HIGH); + break; + + case PhoneState::RINGING: + digitalWrite(PINS.pinLineEnable, HIGH); + digitalWrite(PINS.pinRingCmd, HIGH); + digitalWrite(PINS.pinLed, HIGH); + break; + } +} + +void printHelp() { + Serial.println("[RTC_PHONE] Commands:"); + Serial.println(" h -> help"); + Serial.println(" r -> enter RINGING"); + Serial.println(" o -> force ON_HOOK"); + Serial.println(" d -> force DIALING"); + Serial.println(" c -> force IN_CALL"); +} + +void handleSerialCommands() { + while (Serial.available() > 0) { + const char cmd = static_cast(Serial.read()); + + switch (cmd) { + case 'h': + printHelp(); + break; + case 'r': + setState(PhoneState::RINGING); + break; + case 'o': + setState(PhoneState::ON_HOOK); + break; + case 'd': + setState(PhoneState::DIALING); + break; + case 'c': + setState(PhoneState::IN_CALL); + break; + default: + break; + } + } +} + +void updateHookState() { + const bool rawOffHook = (digitalRead(PINS.pinHookSense) == LOW); + const uint32_t nowMs = millis(); + + if (rawOffHook != g_hookOffHook && (nowMs - g_lastHookEdgeMs) > DEBOUNCE_MS) { + g_lastHookEdgeMs = nowMs; + g_hookOffHook = rawOffHook; + + Serial.printf("[RTC_PHONE] hook=%s\n", g_hookOffHook ? "OFF_HOOK" : "ON_HOOK"); + + if (g_hookOffHook) { + setState(PhoneState::OFF_HOOK); + } else { + setState(PhoneState::ON_HOOK); + } + } +} + +void setup() { + Serial.begin(SERIAL_BAUD); + + pinMode(PINS.pinHookSense, INPUT_PULLUP); + pinMode(PINS.pinRingCmd, OUTPUT); + pinMode(PINS.pinLineEnable, OUTPUT); + pinMode(PINS.pinLed, OUTPUT); + + digitalWrite(PINS.pinRingCmd, LOW); + digitalWrite(PINS.pinLineEnable, LOW); + digitalWrite(PINS.pinLed, LOW); + + Serial.println("\n[RTC_PHONE] Boot OK"); +#if CONFIG_IDF_TARGET_ESP32S3 + Serial.println("[RTC_PHONE] Target: ESP32-S3"); +#else + Serial.println("[RTC_PHONE] Target: ESP32 (legacy mapping)"); +#endif + Serial.println("[RTC_PHONE] Profile: AG1171S control skeleton"); + printHelp(); + + setState(PhoneState::ON_HOOK); +} + +void loop() { + updateHookState(); + handleSerialCommands(); + delay(10); // Prototype minimal pour valider le câblage d'un téléphone RTC recyclé. // - Hook switch: détection décroché/raccroché // - Clavier: lecture en matrice (adaptateur nécessaire selon le modèle)