feat: Add POWERTEST command, update roadmap with v2.0 FTM milestone

Add 7-phase power profiling command (POWERTEST) that cycles through
idle, CSI 10/100 Hz, BLE-only, combined, tx_low/tx_high with EVENT
markers for external power meter correlation. Saves/restores all
settings on completion.

Update roadmap: mark v1.4 done, add v2.0 hardware upgrade milestone
for ESP32-S3/C6 with WiFi FTM / 802.11mc inter-sensor ranging.
This commit is contained in:
user
2026-02-04 21:47:28 +01:00
parent 84f2b33dac
commit 8c79d20cd8
2 changed files with 156 additions and 4 deletions

View File

@@ -162,6 +162,9 @@ static struct { int64_t ts; } s_deauth_ring[FLOOD_RING_SIZE];
static int s_deauth_ring_head = 0;
static int s_deauth_ring_count = 0;
/* Power test */
static volatile bool s_powertest_running = false;
/* --- NVS helpers --- */
static void config_load_nvs(void)
@@ -1071,6 +1074,117 @@ static void reboot_after_delay(void *arg)
esp_restart();
}
/* --- Power test --- */
static void send_powertest_event(const char *phase, int dwell_s)
{
char buf[128];
int len = snprintf(buf, sizeof(buf), "EVENT,%s,powertest,%s,%d\n",
s_hostname, phase, dwell_s);
if (s_udp_socket >= 0) {
sendto(s_udp_socket, buf, len, 0,
(struct sockaddr *)&s_dest_addr, sizeof(s_dest_addr));
}
}
static void powertest_task(void *arg)
{
int dwell_s = (int)(intptr_t)arg;
/* Save current settings */
int saved_freq = s_send_frequency;
bool saved_adaptive = s_adaptive;
bool saved_ble = s_ble_enabled;
int8_t saved_tx_power = s_tx_power_dbm;
led_mode_t saved_led = s_led_mode;
/* Disable adaptive during test */
s_adaptive = false;
s_motion_detected = false;
typedef struct {
const char *name;
int rate; /* 0 = stop ping */
bool ble;
int8_t tx_dbm; /* 0 = no change */
bool led;
} phase_t;
static const phase_t phases[] = {
{ "idle", 0, false, 0, false },
{ "csi_10", 10, false, 0, true },
{ "csi_100", 100, false, 0, true },
{ "ble_only", 0, true, 0, true },
{ "all", 100, true, 0, true },
{ "tx_low", 100, false, 2, true },
{ "tx_high", 100, false, 20, true },
};
int n_phases = sizeof(phases) / sizeof(phases[0]);
ESP_LOGI(TAG, "POWERTEST: starting %d phases, dwell=%ds", n_phases, dwell_s);
for (int i = 0; i < n_phases; i++) {
const phase_t *p = &phases[i];
send_powertest_event(p->name, dwell_s);
ESP_LOGI(TAG, "POWERTEST: phase %s (rate=%d ble=%d tx=%d)", p->name, p->rate, p->ble, p->tx_dbm);
/* LED */
s_led_mode = p->led ? LED_FAST_BLINK : LED_OFF;
/* BLE */
if (p->ble && !s_ble_enabled) {
s_ble_enabled = true;
ble_scan_start();
} else if (!p->ble && s_ble_enabled) {
s_ble_enabled = false;
ble_gap_disc_cancel();
}
/* TX power */
if (p->tx_dbm > 0) {
s_tx_power_dbm = p->tx_dbm;
esp_wifi_set_max_tx_power(s_tx_power_dbm * 4);
}
/* Ping rate */
if (p->rate > 0) {
s_send_frequency = p->rate;
wifi_ping_router_start();
} else {
if (s_ping_handle) {
esp_ping_stop(s_ping_handle);
esp_ping_delete_session(s_ping_handle);
s_ping_handle = NULL;
}
}
vTaskDelay(pdMS_TO_TICKS(dwell_s * 1000));
}
/* Restore settings */
s_adaptive = saved_adaptive;
s_ble_enabled = saved_ble;
s_tx_power_dbm = saved_tx_power;
esp_wifi_set_max_tx_power(s_tx_power_dbm * 4);
s_led_mode = saved_led;
s_send_frequency = saved_freq;
if (saved_ble) {
ble_scan_start();
} else {
ble_gap_disc_cancel();
}
wifi_ping_router_start();
int total_s = dwell_s * n_phases;
send_powertest_event("done", total_s);
ESP_LOGI(TAG, "POWERTEST: done total=%ds", total_s);
s_powertest_running = false;
vTaskDelete(NULL);
}
static int cmd_handle(const char *cmd, char *reply, size_t reply_size)
{
/* REBOOT */
@@ -1469,6 +1583,26 @@ static int cmd_handle(const char *cmd, char *reply, size_t reply_size)
return strlen(reply);
}
/* POWERTEST [dwell_s] */
if (strncmp(cmd, "POWERTEST", 9) == 0) {
if (s_powertest_running) {
snprintf(reply, reply_size, "ERR POWERTEST already running");
return strlen(reply);
}
int dwell = 15;
if (cmd[9] == ' ') {
dwell = atoi(cmd + 10);
if (dwell < 5 || dwell > 60) {
snprintf(reply, reply_size, "ERR POWERTEST dwell range 5-60");
return strlen(reply);
}
}
s_powertest_running = true;
xTaskCreate(powertest_task, "powertest", 4096, (void *)(intptr_t)dwell, 3, NULL);
snprintf(reply, reply_size, "OK POWERTEST started dwell=%ds phases=7 total=~%ds", dwell, dwell * 7);
return strlen(reply);
}
snprintf(reply, reply_size, "ERR UNKNOWN");
return strlen(reply);
}