116 lines
4.6 KiB
C
116 lines
4.6 KiB
C
/*
|
|
* hook_monitor.c — surveille le crochet (SHK via slic) et décode la
|
|
* numérotation par impulsions du cadran. Adapté de plip_voice/main/phone.c
|
|
* (logique de pulse/hangup) sans le couplage conversation/audio.
|
|
*
|
|
* Cadran à impulsions : pendant que le combiné est décroché, le cadran ouvre
|
|
* la boucle N fois pour le chiffre N (10 impulsions = 0). Un raccroché réel se
|
|
* distingue d'une impulsion par sa durée (> HANGUP_THRESHOLD_MS).
|
|
*/
|
|
#include "hook_monitor.h"
|
|
#include "slic.h"
|
|
#include "dialer.h"
|
|
|
|
#include "freertos/FreeRTOS.h"
|
|
#include "freertos/task.h"
|
|
#include "esp_timer.h"
|
|
#include "esp_log.h"
|
|
|
|
#define TAG "hook_monitor"
|
|
|
|
#define POLL_MS 10 /* décroché : résolution fine pour décoder les impulsions */
|
|
#define POLL_IDLE_MS 80 /* raccroché (repos) : poll lent -> CPU dort + DFS (éco batterie) */
|
|
#define DEBOUNCE_MS 30
|
|
#define PULSE_MIN_WIDTH_MS 20 /* filtre anti-glitch */
|
|
#define INTER_DIGIT_GAP_MS 200 /* fin d'un chiffre au cadran */
|
|
#define HANGUP_THRESHOLD_MS 2500 /* ouverture > seuil = vrai raccroché */
|
|
|
|
static hook_change_cb_t s_cb = NULL;
|
|
static volatile bool s_offhook = false;
|
|
static TaskHandle_t s_task = NULL;
|
|
|
|
/* slic_is_offhook() renvoie true si la boucle est fermée (combiné décroché,
|
|
* cadran au repos). Pendant une impulsion, la boucle s'ouvre brièvement →
|
|
* slic_is_offhook() repasse false un court instant. On distingue :
|
|
* - impulsion : ouverture courte (~60 ms) répétée, puis gap inter-chiffre
|
|
* - raccroché : ouverture longue (> HANGUP_THRESHOLD_MS) */
|
|
static void hook_task(void *arg)
|
|
{
|
|
(void)arg;
|
|
bool stable = slic_is_offhook();
|
|
s_offhook = stable;
|
|
if (s_cb) s_cb(stable);
|
|
|
|
int pulse_count = 0;
|
|
bool in_open = false;
|
|
int64_t open_start_us = 0;
|
|
int64_t last_close_us = esp_timer_get_time();
|
|
|
|
for (;;) {
|
|
bool raw = slic_is_offhook();
|
|
int64_t now = esp_timer_get_time();
|
|
|
|
if (!stable) {
|
|
/* Combiné raccroché : n'attendre qu'un décroché franc et débouncé. */
|
|
if (raw) {
|
|
vTaskDelay(pdMS_TO_TICKS(DEBOUNCE_MS));
|
|
if (slic_is_offhook()) {
|
|
stable = true; s_offhook = true;
|
|
pulse_count = 0; in_open = false;
|
|
last_close_us = esp_timer_get_time();
|
|
dialer_reset();
|
|
if (s_cb) s_cb(true);
|
|
ESP_LOGI(TAG, "décroché");
|
|
}
|
|
}
|
|
} else {
|
|
/* Combiné décroché : décoder impulsions + détecter raccroché. */
|
|
if (!raw && !in_open) {
|
|
in_open = true; open_start_us = now; /* début ouverture */
|
|
} else if (raw && in_open) {
|
|
in_open = false; /* fin ouverture */
|
|
int open_ms = (int)((now - open_start_us) / 1000);
|
|
if (open_ms >= PULSE_MIN_WIDTH_MS && open_ms < HANGUP_THRESHOLD_MS) {
|
|
pulse_count++; /* impulsion valide */
|
|
}
|
|
last_close_us = now;
|
|
} else if (!raw && in_open) {
|
|
/* ouverture en cours : vérifier un raccroché (ouverture longue) */
|
|
int open_ms = (int)((now - open_start_us) / 1000);
|
|
if (open_ms >= HANGUP_THRESHOLD_MS) {
|
|
stable = false; s_offhook = false;
|
|
in_open = false; pulse_count = 0;
|
|
if (s_cb) s_cb(false);
|
|
ESP_LOGI(TAG, "raccroché");
|
|
}
|
|
}
|
|
|
|
/* Fin d'un chiffre : gap inter-impulsions dépassé avec des pulses. */
|
|
if (!in_open && pulse_count > 0 &&
|
|
(int)((now - last_close_us) / 1000) >= INTER_DIGIT_GAP_MS) {
|
|
int digit = (pulse_count >= 10) ? 0 : pulse_count;
|
|
ESP_LOGI(TAG, "cadran: %d impulsions -> chiffre %d", pulse_count, digit);
|
|
dialer_push_digit(digit);
|
|
pulse_count = 0;
|
|
}
|
|
}
|
|
/* Poll adaptatif : 10 ms décroché (décodage impulsions), 80 ms raccroché
|
|
* (repos) -> le CPU dort plus longtemps, DFS/tickless idle s'engagent. */
|
|
vTaskDelay(pdMS_TO_TICKS(stable ? POLL_MS : POLL_IDLE_MS));
|
|
}
|
|
}
|
|
|
|
esp_err_t hook_monitor_start(hook_change_cb_t cb)
|
|
{
|
|
if (s_task != NULL) return ESP_ERR_INVALID_STATE;
|
|
s_cb = cb;
|
|
if (xTaskCreatePinnedToCore(hook_task, "hook", 4096, NULL, 6, &s_task, 1) != pdPASS) {
|
|
ESP_LOGE(TAG, "échec création tâche hook");
|
|
s_task = NULL;
|
|
return ESP_FAIL;
|
|
}
|
|
return ESP_OK;
|
|
}
|
|
|
|
bool hook_monitor_offhook(void) { return s_offhook; }
|