Files
RTC_BL_PHONE/components/hook_monitor/hook_monitor.c
T
clement 8a2280edb0
Repo State / repo-state (push) Failing after 27s
feat(pwr): poll adaptatif des taches au repos
2026-06-20 00:33:10 +02:00

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; }