feat: Add STATUS counters, WiFi reconnect events, SCANRATE/PROBERATE commands

- Promote CSI packet counter to global, add csi_count= to STATUS
- Add uptime_s= (raw seconds) to STATUS for programmatic parsing
- Emit EVENT on WiFi reconnect with rssi and ip fields
- Add SCANRATE command (5-300s) to tune BLE scan restart interval
- Add PROBERATE command (1-300s) to tune probe dedup cooldown
This commit is contained in:
user
2026-02-04 19:26:09 +01:00
parent a69fe8d696
commit 60264d83ae

View File

@@ -89,6 +89,8 @@ static volatile led_mode_t s_led_mode = LED_OFF;
static volatile int64_t s_last_csi_time = 0;
static volatile int64_t s_identify_end_time = 0;
static volatile bool s_ota_in_progress = false;
static volatile uint32_t s_csi_count = 0;
static volatile bool s_wifi_connected = false;
/* Adaptive sampling */
#define WANDER_WINDOW 50
@@ -105,9 +107,11 @@ static uint32_t s_energy_buf[WANDER_WINDOW];
static uint32_t s_energy_idx = 0;
/* BLE scanning */
#define BLE_SCAN_RESTART_US 30000000LL /* restart scan every 30s to refresh duplicate filter */
#define BLE_SCAN_RESTART_DEFAULT_US 30000000LL /* restart scan every 30s to refresh duplicate filter */
static int64_t s_ble_scan_interval_us = BLE_SCAN_RESTART_DEFAULT_US;
static bool s_ble_enabled = false;
static uint8_t s_ble_own_addr_type;
static esp_timer_handle_t s_ble_timer = NULL;
/* Chip temperature sensor */
#if SOC_TEMP_SENSOR_SUPPORTED
@@ -295,7 +299,6 @@ static void wifi_csi_rx_cb(void *ctx, wifi_csi_info_t *info)
s_last_csi_time = esp_timer_get_time();
const wifi_pkt_rx_ctrl_t *rx_ctrl = &info->rx_ctrl;
static int s_count = 0;
float compensate_gain = 1.0f;
static uint8_t agc_gain = 0;
static int8_t fft_gain = 0;
@@ -303,9 +306,9 @@ static void wifi_csi_rx_cb(void *ctx, wifi_csi_info_t *info)
static uint8_t agc_gain_baseline = 0;
static int8_t fft_gain_baseline = 0;
esp_csi_gain_ctrl_get_rx_gain(rx_ctrl, &agc_gain, &fft_gain);
if (s_count < 100) {
if (s_csi_count < 100) {
esp_csi_gain_ctrl_record_rx_gain(agc_gain, fft_gain);
} else if (s_count == 100) {
} else if (s_csi_count == 100) {
esp_csi_gain_ctrl_get_rx_gain_baseline(&agc_gain_baseline, &fft_gain_baseline);
#if CONFIG_FORCE_GAIN
esp_csi_gain_ctrl_set_rx_force_gain(agc_gain_baseline, fft_gain_baseline);
@@ -320,21 +323,21 @@ static void wifi_csi_rx_cb(void *ctx, wifi_csi_info_t *info)
int pos = 0;
#if CONFIG_IDF_TARGET_ESP32C5 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32C61
if (!s_count) {
if (!s_csi_count) {
ESP_LOGI(TAG, "================ CSI RECV (UDP) ================");
}
pos = snprintf(s_udp_buffer, sizeof(s_udp_buffer),
"CSI_DATA,%s,%d," MACSTR ",%d,%d,%d,%d,%d,%d,%d,%d,%d",
s_hostname, s_count, MAC2STR(info->mac), rx_ctrl->rssi, rx_ctrl->rate,
"CSI_DATA,%s,%lu," MACSTR ",%d,%d,%d,%d,%d,%d,%d,%d,%d",
s_hostname, (unsigned long)s_csi_count, MAC2STR(info->mac), rx_ctrl->rssi, rx_ctrl->rate,
rx_ctrl->noise_floor, fft_gain, agc_gain, rx_ctrl->channel,
rx_ctrl->timestamp, rx_ctrl->sig_len, rx_ctrl->rx_state);
#else
if (!s_count) {
if (!s_csi_count) {
ESP_LOGI(TAG, "================ CSI RECV (UDP) ================");
}
pos = snprintf(s_udp_buffer, sizeof(s_udp_buffer),
"CSI_DATA,%s,%d," MACSTR ",%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d",
s_hostname, s_count, MAC2STR(info->mac), rx_ctrl->rssi, rx_ctrl->rate, rx_ctrl->sig_mode,
"CSI_DATA,%s,%lu," MACSTR ",%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d",
s_hostname, (unsigned long)s_csi_count, MAC2STR(info->mac), rx_ctrl->rssi, rx_ctrl->rate, rx_ctrl->sig_mode,
rx_ctrl->mcs, rx_ctrl->cwb, rx_ctrl->smoothing, rx_ctrl->not_sounding,
rx_ctrl->aggregation, rx_ctrl->stbc, rx_ctrl->fec_coding, rx_ctrl->sgi,
rx_ctrl->noise_floor, rx_ctrl->ampdu_cnt, rx_ctrl->channel, rx_ctrl->secondary_channel,
@@ -373,7 +376,7 @@ static void wifi_csi_rx_cb(void *ctx, wifi_csi_info_t *info)
s_energy_idx++;
}
s_count++;
s_csi_count++;
}
static void wifi_csi_init()
@@ -700,9 +703,10 @@ typedef struct {
uint16_t seq_ctrl;
} __attribute__((packed)) wifi_ieee80211_mac_hdr_t;
/* Probe request deduplication: report each MAC at most once per 10 seconds */
/* Probe request deduplication: report each MAC at most once per N seconds */
#define PROBE_DEDUP_SIZE 32
#define PROBE_DEDUP_US 10000000LL
#define PROBE_DEDUP_DEFAULT_US 10000000LL
static int64_t s_probe_dedup_us = PROBE_DEDUP_DEFAULT_US;
static struct {
uint8_t mac[6];
@@ -717,7 +721,7 @@ static bool probe_dedup_check(const uint8_t *mac)
for (int i = 0; i < PROBE_DEDUP_SIZE; i++) {
if (memcmp(s_probe_seen[i].mac, mac, 6) == 0) {
if (now - s_probe_seen[i].ts < PROBE_DEDUP_US) {
if (now - s_probe_seen[i].ts < s_probe_dedup_us) {
return true; /* seen recently, skip */
}
s_probe_seen[i].ts = now;
@@ -879,12 +883,12 @@ static int cmd_handle(const char *cmd, char *reply, size_t reply_size)
}
snprintf(reply, reply_size,
"OK STATUS uptime=%s heap=%lu rssi=%d tx_power=%d rate=%d hostname=%s version=%s adaptive=%s motion=%d ble=%s target=%s:%d temp=%.1f",
uptime_str, (unsigned long)heap, rssi, (int)s_tx_power_dbm,
"OK STATUS uptime=%s uptime_s=%lld heap=%lu rssi=%d tx_power=%d rate=%d hostname=%s version=%s adaptive=%s motion=%d ble=%s target=%s:%d temp=%.1f csi_count=%lu",
uptime_str, (long long)up, (unsigned long)heap, rssi, (int)s_tx_power_dbm,
s_send_frequency, s_hostname, app_desc->version,
s_adaptive ? "on" : "off", s_motion_detected ? 1 : 0,
s_ble_enabled ? "on" : "off", s_target_ip, s_target_port,
chip_temp);
chip_temp, (unsigned long)s_csi_count);
return strlen(reply);
}
@@ -1024,6 +1028,34 @@ static int cmd_handle(const char *cmd, char *reply, size_t reply_size)
return strlen(reply);
}
/* SCANRATE <5-300> */
if (strncmp(cmd, "SCANRATE ", 9) == 0) {
int val = atoi(cmd + 9);
if (val < 5 || val > 300) {
snprintf(reply, reply_size, "ERR SCANRATE range 5-300 seconds");
return strlen(reply);
}
s_ble_scan_interval_us = (int64_t)val * 1000000LL;
if (s_ble_timer) {
esp_timer_stop(s_ble_timer);
esp_timer_start_periodic(s_ble_timer, s_ble_scan_interval_us);
}
snprintf(reply, reply_size, "OK SCANRATE %ds", val);
return strlen(reply);
}
/* PROBERATE <1-300> */
if (strncmp(cmd, "PROBERATE ", 10) == 0) {
int val = atoi(cmd + 10);
if (val < 1 || val > 300) {
snprintf(reply, reply_size, "ERR PROBERATE range 1-300 seconds");
return strlen(reply);
}
s_probe_dedup_us = (int64_t)val * 1000000LL;
snprintf(reply, reply_size, "OK PROBERATE %ds", val);
return strlen(reply);
}
/* PROFILE */
if (strcmp(cmd, "PROFILE") == 0) {
int pos = 0;
@@ -1154,6 +1186,37 @@ static void cmd_task(void *arg)
}
}
/* --- WiFi event handler --- */
static void wifi_event_handler(void *arg, esp_event_base_t event_base,
int32_t event_id, void *event_data)
{
if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
s_wifi_connected = false;
ESP_LOGW(TAG, "WiFi disconnected");
}
if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
bool was_disconnected = !s_wifi_connected;
s_wifi_connected = true;
if (was_disconnected && s_udp_socket >= 0) {
ip_event_got_ip_t *event = (ip_event_got_ip_t *)event_data;
wifi_ap_record_t ap;
int rssi = 0;
if (esp_wifi_sta_get_ap_info(&ap) == ESP_OK) {
rssi = ap.rssi;
}
char evt[128];
int len = snprintf(evt, sizeof(evt),
"EVENT,%s,wifi=reconnected rssi=%d ip=" IPSTR "\n",
s_hostname, rssi, IP2STR(&event->ip_info.ip));
sendto(s_udp_socket, evt, len, 0,
(struct sockaddr *)&s_dest_addr, sizeof(s_dest_addr));
ESP_LOGI(TAG, "WiFi reconnected, event sent");
}
}
}
/* --- Main --- */
void app_main()
@@ -1167,12 +1230,19 @@ void app_main()
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
/* Register WiFi event handler for reconnect notifications */
ESP_ERROR_CHECK(esp_event_handler_instance_register(
WIFI_EVENT, WIFI_EVENT_STA_DISCONNECTED, wifi_event_handler, NULL, NULL));
ESP_ERROR_CHECK(esp_event_handler_instance_register(
IP_EVENT, IP_EVENT_STA_GOT_IP, wifi_event_handler, NULL, NULL));
/**
* @brief This helper function configures Wi-Fi, as selected in menuconfig.
* Read "Establishing Wi-Fi Connection" section in esp-idf/examples/protocols/README.md
* for more information about this function.
*/
ESP_ERROR_CHECK(example_connect());
s_wifi_connected = true;
/* Apply saved TX power after WiFi is up */
esp_wifi_set_max_tx_power(s_tx_power_dbm * 4);
@@ -1217,9 +1287,8 @@ void app_main()
.callback = ble_scan_restart_timer_cb,
.name = "ble_scan",
};
esp_timer_handle_t ble_timer;
esp_timer_create(&ble_timer_args, &ble_timer);
esp_timer_start_periodic(ble_timer, BLE_SCAN_RESTART_US);
esp_timer_create(&ble_timer_args, &s_ble_timer);
esp_timer_start_periodic(s_ble_timer, s_ble_scan_interval_us);
ESP_LOGI(TAG, "BLE: NimBLE initialized, scan=%s", s_ble_enabled ? "on" : "off");