witness+opt: ADR-110 §A0.6 — IDF v5.4 soft-AP HE gap, swarm warnings

Iter 1 finding from /loop 5m SOTA sprint: two C6 boards now mesh through
the c6_softap_he soft-AP (COM12 hosts ruview-c6-twt, COM9 associates), but
COM9 lands at phymode(0x3, 11bgn), he:0 — the soft-AP doesn't advertise
HE. Confirmed by full grep of components/esp_wifi/include/esp_wifi*.h:
the public API exposes ONLY STA-side iTWT/bTWT. There is no
esp_wifi_ap_set_he_config, no wifi_he_ap_config_t, no wifi_config_t.ap.he_*
field — soft-AP HE/TWT-Responder advertise is not user-controllable on
ESP32-C6 in IDF v5.4.

Consequence: B1/B2 cannot be measured via the two-C6 path on this IDF
release. The c6_softap_he module ships as the in-place hook for any
future IDF release that exposes the API; until then a real 11ax router
or phone hotspot remains the path. Sharpens the open question from "do
we need an 11ax AP?" to "we need either a future IDF AP-side HE config
API, or an external 11ax AP".

WITNESS-LOG-110 §A0.6 records the parallel boot logs from both boards
plus the IDF surface grep evidence.

c6_softap_he.c gains an ESP_LOGW at AP-up time so operators understand
exactly why STAs land at 11bgn (avoids confusion with the v0.6.6 §A8
graceful-TWT-NACK story).

While here: cleared the three -Wunused-variable warnings in swarm_bridge.c
that fired on every build (fw_ver, free_heap, presence in heartbeat block).
fw_ver now feeds an ESP_LOGI so the boot log names the build; free_heap +
heartbeat-presence were dead anyway. Pure ultra-opt: smaller .o files, zero
warning noise.

Co-Authored-By: claude-flow <ruv@ruv.net>
This commit is contained in:
ruv
2026-05-23 11:36:09 -04:00
parent 83f20f7c61
commit f9aad75413
3 changed files with 22 additions and 14 deletions
+15 -9
View File
@@ -143,19 +143,25 @@ esp_err_t c6_softap_he_start(uint8_t *out_channel)
return err;
}
/* On IDF v5.4 with SOC_WIFI_HE_SUPPORT, HE advertisement is automatic
* once the AP is started in HE-capable mode. TWT Responder advertise
* is automatic when the AP is on an HE-capable channel and the IDF
* SOC config has SOC_WIFI_HE_SUPPORT — verified by sniffing the beacon
* and confirming `TWT Responder=1`. If a future IDF exposes
* `esp_wifi_ap_set_he_config()` or similar, hook it here.
/* IDF v5.4 LIMIT (verified empirically 2026-05-23 — WITNESS-LOG-110 §A0.6):
* the public API exposes ONLY STA-side iTWT/bTWT (esp_wifi_sta_itwt_*,
* esp_wifi_sta_btwt_*). There is NO esp_wifi_ap_set_he_config(), NO
* wifi_he_ap_config_t, and NO wifi_config_t.ap.he_* field. A second C6
* associating against this soft-AP currently lands at phymode 11bgn
* (he:0, vht:0, ht:1) — the AP doesn't advertise HE because there's no
* way to ask it to. A future IDF release that exposes AP-side HE config
* (or a patched WiFi blob) is required to make this AP iTWT-capable.
*
* Empirically against IDF v5.4 / C6 silicon: the beacon advertises
* HE capability when the band is 2.4 GHz and the AP is on an
* 11ax-capable channel, and TWT Responder follows. */
* Until then, this module still gives you a working WPA2 soft-AP on a
* controlled channel for AP+STA bench experiments and ESP-NOW peer
* discovery — just not iTWT validation. The c6_twt module on the STA
* side will return ESP_ERR_INVALID_ARG against this AP (no TWT Responder
* in the beacon), exactly as it does against any other 11n-only AP. */
ESP_LOGI(TAG, "soft-AP starting: ssid=\"%s\" channel=%u auth=%s",
ssid, s_channel,
ap_cfg.ap.authmode == WIFI_AUTH_OPEN ? "open" : "wpa2-psk");
ESP_LOGW(TAG, "IDF v5.4 soft-AP does NOT advertise HE — STAs will associate at 11bgn. "
"iTWT validation requires an external 11ax AP. See WITNESS-LOG-110 §A0.6.");
/* Don't call esp_wifi_start() here — main.c brings the WiFi up once
* for both AP and STA. We just configured the AP iface so it joins
+6 -5
View File
@@ -230,9 +230,13 @@ static void swarm_task(void *arg)
ESP_LOGI(TAG, "Bearer token configured for Seed auth");
}
/* Get firmware version string. */
/* Firmware version + IP captured locally so logs name the build; both
* intentionally unused in the JSON payloads — the seed extracts them
* from the register/heartbeat IDs. Keep as side-effect probes. */
const esp_app_desc_t *app = esp_app_get_description();
const char *fw_ver = app ? app->version : "unknown";
if (app) {
ESP_LOGI(TAG, "swarm bridge fw=%s", app->version);
}
/* Get local IP. */
char ip_str[16];
@@ -278,15 +282,12 @@ static void swarm_task(void *arg)
xSemaphoreGive(s_mutex);
uint32_t uptime_s = (uint32_t)(esp_timer_get_time() / 1000000ULL);
uint32_t free_heap = esp_get_free_heap_size();
uint32_t ts = (uint32_t)(esp_timer_get_time() / 1000ULL);
/* ---- Heartbeat ---- */
if ((now - last_heartbeat) >= pdMS_TO_TICKS(s_cfg.heartbeat_sec * 1000U)) {
last_heartbeat = now;
bool presence = vit_valid && (vit.flags & 0x01);
/* Heartbeat ID: node_id * 1000000 + 100000 + ts_sec */
uint32_t hb_id = (uint32_t)s_node_id * 1000000U + 100000U + (uptime_s % 100000U);
char json[SWARM_JSON_BUF];