From e819eae5a50a28210595dd2991371cc7553abf74 Mon Sep 17 00:00:00 2001 From: electron-rare Date: Sun, 14 Jun 2026 21:55:02 +0200 Subject: [PATCH] feat(plip): dialer module + /debug/dial (digit accumulator) --- plip_voice/main/dialer.c | 73 ++++++++++++++++++++++++++++++++++++++++ plip_voice/main/dialer.h | 9 +++++ plip_voice/main/net.c | 36 ++++++++++++++++++-- 3 files changed, 116 insertions(+), 2 deletions(-) create mode 100644 plip_voice/main/dialer.c create mode 100644 plip_voice/main/dialer.h diff --git a/plip_voice/main/dialer.c b/plip_voice/main/dialer.c new file mode 100644 index 0000000..dda4c1a --- /dev/null +++ b/plip_voice/main/dialer.c @@ -0,0 +1,73 @@ +/* + * dialer.c — Digit accumulator for the PLIP telephone state machine. + * + * Digits are pushed from two sources: + * 1. HTTP /debug/dial?number=NNNN (net.c handler) + * 2. Rotary pulse detection (phone.c, CONFIG_PLIP_DIAL_PULSE) + * + * Thread-safety: all state is protected by atomic operations on s_last_us + * and simple writes to s_len / s_num (called from a single phone task or + * HTTP task at a time — no concurrent push expected). + */ + +#include "dialer.h" + +#include "esp_log.h" +#include "esp_timer.h" + +#include +#include + +#define TAG "dialer" + +#define MAX_DIGITS 8 + +static char s_num[MAX_DIGITS + 1]; +static int s_len; +static int64_t s_last_us; /* esp_timer_get_time() at last push */ + +void dialer_init(void) +{ + memset(s_num, 0, sizeof(s_num)); + s_len = 0; + s_last_us = 0; + ESP_LOGI(TAG, "dialer init"); +} + +void dialer_push_digit(int d) +{ + if (d < 0 || d > 9) return; + if (s_len >= MAX_DIGITS) return; /* silently discard overflow */ + + s_num[s_len++] = (char)('0' + d); + s_num[s_len] = '\0'; + s_last_us = esp_timer_get_time(); + + ESP_LOGI(TAG, "digit %d -> number so far: \"%s\"", d, s_num); +} + +void dialer_reset(void) +{ + memset(s_num, 0, sizeof(s_num)); + s_len = 0; + s_last_us = 0; + ESP_LOGI(TAG, "dialer reset"); +} + +const char *dialer_current(void) +{ + return s_num; +} + +bool dialer_idle(void) +{ + return s_len == 0; +} + +int dialer_ms_since_last(void) +{ + if (s_last_us == 0) return 0; + int64_t elapsed_us = esp_timer_get_time() - s_last_us; + int ms = (int)(elapsed_us / 1000); + return (ms < 0) ? 0 : ms; +} diff --git a/plip_voice/main/dialer.h b/plip_voice/main/dialer.h new file mode 100644 index 0000000..6483095 --- /dev/null +++ b/plip_voice/main/dialer.h @@ -0,0 +1,9 @@ +#pragma once +#include + +void dialer_init(void); +void dialer_push_digit(int d); +void dialer_reset(void); +const char *dialer_current(void); +bool dialer_idle(void); +int dialer_ms_since_last(void); diff --git a/plip_voice/main/net.c b/plip_voice/main/net.c index f91242c..c4d1dbb 100644 --- a/plip_voice/main/net.c +++ b/plip_voice/main/net.c @@ -15,6 +15,7 @@ */ #include "net.h" +#include "dialer.h" #include #include @@ -428,6 +429,32 @@ static esp_err_t handle_cmd_post(httpd_req_t *req) return send_json(req, "200 OK", "{\"ok\":true}"); } +/* ── GET /debug/dial?number=NNNN (push digits into the dialer) ───────────── */ + +static esp_err_t handle_debug_dial(httpd_req_t *req) +{ + char query[64] = {0}; + httpd_req_get_url_query_str(req, query, sizeof(query)); + char number[16] = {0}; + if (httpd_query_key_value(query, "number", number, sizeof(number)) != ESP_OK) { + return send_json(req, "400 Bad Request", "{\"error\":\"missing number param\"}"); + } + + int pushed = 0; + for (int i = 0; number[i] != '\0' && i < 8; i++) { + if (number[i] >= '0' && number[i] <= '9') { + dialer_push_digit(number[i] - '0'); + pushed++; + } + } + + char resp[64]; + snprintf(resp, sizeof(resp), "{\"ok\":true,\"pushed\":%d,\"number\":\"%s\"}", + pushed, dialer_current()); + ESP_LOGI(TAG, "debug/dial: pushed %d digits -> \"%s\"", pushed, dialer_current()); + return send_json(req, "200 OK", resp); +} + /* ── Public API ───────────────────────────────────────────────────────────── */ bool net_is_connected(void) @@ -500,7 +527,7 @@ esp_err_t net_init(void) /* Start HTTP server. */ httpd_config_t hcfg = HTTPD_DEFAULT_CONFIG(); hcfg.server_port = 80; - hcfg.max_uri_handlers = 12; + hcfg.max_uri_handlers = 14; hcfg.stack_size = 8192; esp_err_t ret = httpd_start(&s_httpd, &hcfg); @@ -533,13 +560,18 @@ esp_err_t net_init(void) .uri = "/debug/regs", .method = HTTP_GET, .handler = handle_debug_regs, .user_ctx = NULL, }; + static const httpd_uri_t uri_debug_dial = { + .uri = "/debug/dial", .method = HTTP_GET, + .handler = handle_debug_dial, .user_ctx = NULL, + }; httpd_register_uri_handler(s_httpd, &uri_status); httpd_register_uri_handler(s_httpd, &uri_scenario); httpd_register_uri_handler(s_httpd, &uri_file); httpd_register_uri_handler(s_httpd, &uri_cmd); httpd_register_uri_handler(s_httpd, &uri_capture); httpd_register_uri_handler(s_httpd, &uri_debug_regs); + httpd_register_uri_handler(s_httpd, &uri_debug_dial); - ESP_LOGI(TAG, "httpd up on :80 (GET /status, GET /debug/regs, POST /game/scenario, POST /game/file, POST /game/cmd, POST /voice/capture)"); + ESP_LOGI(TAG, "httpd up on :80 (GET /status, GET /debug/regs, GET /debug/dial, POST /game/scenario, POST /game/file, POST /game/cmd, POST /voice/capture)"); return ESP_OK; }