mirror of
https://github.com/ruvnet/RuView
synced 2026-08-01 19:01:42 +00:00
ADR-110: ESP32-C6 firmware extension (#764)
Closes the firmware-side ADR-110 design at v0.7.0-esp32 after a 38-iter /loop SOTA sprint. Headline (bench, COM9+COM12 ESP32-C6): - 99.56% cross-board RX, 104.1 µs smoothed offset stdev (≤100 µs §2.4 target met) - 3.95× EMA suppression, 1.4 ppm crystal skew preserved 4 firmware releases: v0.6.7 / v0.6.8 / v0.6.9 / v0.7.0-esp32. 42 ADR-110 unit tests, 1761 v2 workspace tests, full Firmware CI + QEMU green.
This commit is contained in:
@@ -33,6 +33,11 @@
|
||||
#include "swarm_bridge.h"
|
||||
#include "rv_radio_ops.h" /* ADR-081 Layer 1 — Radio Abstraction Layer. */
|
||||
#include "adaptive_controller.h" /* ADR-081 Layer 2 — Adaptive controller. */
|
||||
#include "c6_twt.h" /* ADR-110: TWT (no-op stub on S3) */
|
||||
#include "c6_timesync.h" /* ADR-110: 802.15.4 mesh time-sync (no-op on S3) */
|
||||
#include "c6_lp_core.h" /* ADR-110: LP-core hibernation (no-op on S3) */
|
||||
#include "c6_sync_espnow.h" /* ADR-110 D1 workaround: ESP-NOW sync */
|
||||
#include "c6_softap_he.h" /* ADR-110 B1/B2: HE/TWT soft-AP (no-op when disabled) */
|
||||
#ifdef CONFIG_CSI_MOCK_ENABLED
|
||||
#include "mock_csi.h"
|
||||
#endif
|
||||
@@ -112,6 +117,17 @@ static void wifi_init_sta(void)
|
||||
|
||||
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
|
||||
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config));
|
||||
|
||||
#if defined(CONFIG_IDF_TARGET_ESP32C6) && defined(CONFIG_C6_SOFTAP_HE_ENABLE)
|
||||
/* ADR-110 B1/B2 cheap-unblock: bring up a soft-AP that advertises HE +
|
||||
* TWT Responder=1 so a second C6 board can negotiate iTWT against
|
||||
* this node. c6_softap_he_start() switches the mode to AP+STA. */
|
||||
uint8_t softap_chan = 0;
|
||||
if (c6_softap_he_start(&softap_chan) == ESP_OK) {
|
||||
ESP_LOGI(TAG, "C6 soft-AP HE armed on channel %u (ADR-110 B1/B2)", softap_chan);
|
||||
}
|
||||
#endif
|
||||
|
||||
ESP_ERROR_CHECK(esp_wifi_start());
|
||||
|
||||
ESP_LOGI(TAG, "WiFi STA initialized, connecting to SSID: %s", g_nvs_config.wifi_ssid);
|
||||
@@ -147,13 +163,27 @@ void app_main(void)
|
||||
csi_collector_set_node_id(g_nvs_config.node_id);
|
||||
|
||||
const esp_app_desc_t *app_desc = esp_app_get_description();
|
||||
ESP_LOGI(TAG, "ESP32-S3 CSI Node (ADR-018) — v%s — Node ID: %d",
|
||||
app_desc->version, g_nvs_config.node_id);
|
||||
#if defined(CONFIG_IDF_TARGET_ESP32C6)
|
||||
const char *target_name = "ESP32-C6";
|
||||
#elif defined(CONFIG_IDF_TARGET_ESP32S3)
|
||||
const char *target_name = "ESP32-S3";
|
||||
#else
|
||||
const char *target_name = "ESP32";
|
||||
#endif
|
||||
ESP_LOGI(TAG, "%s CSI Node (ADR-018 / ADR-110) — v%s — Node ID: %d",
|
||||
target_name, app_desc->version, g_nvs_config.node_id);
|
||||
|
||||
/* Turn off onboard WS2812 LED on GPIO 38 */
|
||||
/* Turn off onboard WS2812 LED.
|
||||
* S3 dev boards put the LED on GPIO 38; C6 dev boards on GPIO 8.
|
||||
* On C6, GPIO 38 doesn't exist (only 0-30) — gate the init by target. */
|
||||
#if defined(CONFIG_IDF_TARGET_ESP32C6)
|
||||
const int led_gpio = 8;
|
||||
#else
|
||||
const int led_gpio = 38;
|
||||
#endif
|
||||
led_strip_handle_t led_strip;
|
||||
led_strip_config_t strip_config = {
|
||||
.strip_gpio_num = 38,
|
||||
.strip_gpio_num = led_gpio,
|
||||
.max_leds = 1,
|
||||
.led_model = LED_MODEL_WS2812,
|
||||
.color_component_format = LED_STRIP_COLOR_COMPONENT_FMT_GRB,
|
||||
@@ -167,6 +197,27 @@ void app_main(void)
|
||||
led_strip_clear(led_strip);
|
||||
}
|
||||
|
||||
/* ADR-110 P4: 802.15.4 mesh time-sync (C6 only).
|
||||
* Initialized BEFORE WiFi so it's available even when WiFi STA can't
|
||||
* connect — the radios are physically independent on the C6.
|
||||
* No-op on S3 (the helper compiles to an empty inline stub). */
|
||||
#if defined(CONFIG_IDF_TARGET_ESP32C6) && defined(CONFIG_C6_TIMESYNC_ENABLE)
|
||||
esp_err_t ts_ret = c6_timesync_init(CONFIG_C6_TIMESYNC_CHANNEL);
|
||||
if (ts_ret != ESP_OK) {
|
||||
ESP_LOGW(TAG, "c6_timesync_init failed: %s (continuing without 15.4 sync)",
|
||||
esp_err_to_name(ts_ret));
|
||||
}
|
||||
#endif
|
||||
|
||||
/* ADR-110 P5: Optionally arm LP-core wake-on-motion (C6 only, opt-in).
|
||||
* Default off — only nodes flashed for battery-powered seed duty enable
|
||||
* this in menuconfig. */
|
||||
#if defined(CONFIG_IDF_TARGET_ESP32C6) && defined(CONFIG_C6_LP_CORE_ENABLE)
|
||||
if (c6_lp_core_was_motion_wake()) {
|
||||
ESP_LOGI(TAG, "boot cause: LP-core motion wake (running CSI burst)");
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Initialize WiFi STA (skip entirely under QEMU mock — no RF hardware) */
|
||||
#ifndef CONFIG_CSI_MOCK_SKIP_WIFI_CONNECT
|
||||
wifi_init_sta();
|
||||
@@ -208,6 +259,26 @@ void app_main(void)
|
||||
}
|
||||
#endif
|
||||
|
||||
/* ADR-110 P3: Request TWT from the AP for deterministic CSI cadence.
|
||||
* No-op on S3 (the helper compiles to an empty inline stub). On C6
|
||||
* the AP may NACK — the helper logs and falls back to opportunistic.
|
||||
* Called only after WiFi STA connect (wifi_init_sta blocks until then). */
|
||||
#if defined(CONFIG_IDF_TARGET_ESP32C6) && defined(CONFIG_C6_TWT_ENABLE)
|
||||
c6_twt_setup_default();
|
||||
#endif
|
||||
|
||||
/* ADR-110 D1 workaround: ESP-NOW cross-node sync. Initialized after
|
||||
* WiFi STA connects (ESP-NOW needs the WiFi driver up). Works on
|
||||
* both S3 and C6 — replaces the broken 802.15.4 RX path in c6_timesync.
|
||||
* Skip on QEMU mock (no real WiFi → no ESP-NOW). */
|
||||
#ifndef CONFIG_CSI_MOCK_SKIP_WIFI_CONNECT
|
||||
esp_err_t espnow_ret = c6_sync_espnow_init();
|
||||
if (espnow_ret != ESP_OK) {
|
||||
ESP_LOGW(TAG, "c6_sync_espnow_init failed: %s (continuing without ESP-NOW sync)",
|
||||
esp_err_to_name(espnow_ret));
|
||||
}
|
||||
#endif
|
||||
|
||||
/* ADR-039: Initialize edge processing pipeline. */
|
||||
edge_config_t edge_cfg = {
|
||||
.tier = g_nvs_config.edge_tier,
|
||||
|
||||
Reference in New Issue
Block a user