Skip to content

Commit 4bf88e1

Browse files
authored
feat(firmware): gate LED gamma viz behind CONFIG_LED_GAMMA_VIZ (ADR-183 follow-up) (ruvnet#1129)
The 40 Hz gamma flicker is now Kconfig-gated (default y, unchanged behaviour). Set CONFIG_LED_GAMMA_VIZ=n for a dark, lower-power boot (the LED is simply cleared) — important for photosensitive deployments, no source edit needed. The colormap saturation point is now operator-tunable via CONFIG_LED_MOTION_FULLSCALE_MILLI (default 250 = 0.25). Build + flash confirmed on ESP32-S3 N16R8 (COM8): default y still arms the gamma timer, CSI flows. ADR-183 updated (gate moved from follow-up to done).
1 parent a4c2935 commit 4bf88e1

3 files changed

Lines changed: 50 additions & 10 deletions

File tree

docs/adr/ADR-183-onboard-led-gamma-stimulus-csi-colormap.md

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -74,11 +74,13 @@ therefore provably `ruv-neural-viz`'s, and the motion is provably real.
7474
- Confirms #962's GPIO-48 fix visually (the LED lights on N16R8).
7575

7676
**Negative / risks**
77-
- Changes *default* firmware behaviour: the onboard LED now animates instead of staying
78-
off (minor power + a visible flicker some may not want). Gate behind a Kconfig
79-
(`CONFIG_LED_GAMMA_VIZ`) if a dark default is preferred — follow-up.
80-
- A 40 Hz flicker can be an issue for photosensitive users; document on the enclosure.
81-
- `LED_MOTION_FULLSCALE` (0.25) is hand-tuned, not calibrated per-environment.
77+
- Changes the *default* firmware behaviour: the onboard LED animates instead of staying
78+
off. Now **gated by `CONFIG_LED_GAMMA_VIZ`** (default `y`); set it `n` for a dark,
79+
lower-power boot (the LED is just cleared) — no source change needed.
80+
- A 40 Hz flicker can be an issue for photosensitive users; document on the enclosure
81+
and disable `CONFIG_LED_GAMMA_VIZ` in those deployments.
82+
- The saturation point is now `CONFIG_LED_MOTION_FULLSCALE_MILLI` (default 250 = 0.25),
83+
operator-tunable; still not auto-calibrated per-environment.
8284
- The colour uses a baked LUT, not the live Rust `ColorMap` (FFI path deferred — needs
8385
the ESP Rust/xtensa toolchain, not yet in CI).
8486

firmware/esp32-csi-node/main/Kconfig.projbuild

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -468,3 +468,29 @@ menu "Mock CSI (QEMU Testing)"
468468
depends on CSI_MOCK_ENABLED
469469
default n
470470
endmenu
471+
472+
menu "Onboard LED (ADR-183)"
473+
474+
config LED_GAMMA_VIZ
475+
bool "Onboard WS2812: 40 Hz gamma flicker + CSI-motion colour"
476+
default y
477+
help
478+
Drive the onboard WS2812 as a GENUS-style 40 Hz gamma square wave
479+
(12.5 ms on / 12.5 ms off, 50% duty). The ON-phase colour is live
480+
CSI motion (edge motion_energy) mapped through the ruv-neural-viz
481+
viridis colormap (still=purple, moving=yellow).
482+
483+
Disable to leave the LED off at boot — lower power, no flicker.
484+
NOTE: a 40 Hz flicker can affect photosensitive users; disable or
485+
shield the LED in those environments. Not a medical device.
486+
487+
config LED_MOTION_FULLSCALE_MILLI
488+
int "Motion value (x1000) that saturates the colormap to yellow"
489+
depends on LED_GAMMA_VIZ
490+
default 250
491+
range 1 100000
492+
help
493+
edge motion_energy that maps to the top (yellow) of the viridis
494+
colormap, in milli-units (250 = 0.25). Lower = more sensitive
495+
(reaches yellow with less motion).
496+
endmenu

firmware/esp32-csi-node/main/main.c

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ static void wifi_init_sta(void)
144144
}
145145
}
146146

147+
#if CONFIG_LED_GAMMA_VIZ
147148
/* Viridis colormap (60 steps), generated from ruv-neural-viz::ColorMap::viridis()
148149
* — the rUv-Neural brain-topology colormap, now no_std (ruvnet/ruv-neural#3 /
149150
* RuView#1126). Used as the ON-phase colour of the 40 Hz gamma flicker below:
@@ -164,8 +165,8 @@ static const uint8_t VIRIDIS_LUT[60][3] = {
164165
};
165166
static led_strip_handle_t s_viz_led;
166167

167-
/* motion_energy that saturates the colormap to yellow (tunable). */
168-
#define LED_MOTION_FULLSCALE 0.25f
168+
/* motion_energy that saturates the colormap to yellow (CONFIG, milli-units). */
169+
#define LED_MOTION_FULLSCALE ((float)CONFIG_LED_MOTION_FULLSCALE_MILLI / 1000.0f)
169170

170171
/* GENUS-style 40 Hz gamma flicker: full on/off square wave, 50% duty (toggled
171172
* every 12.5 ms → 40 Hz). The ON colour is live CSI motion (edge motion_energy)
@@ -189,6 +190,7 @@ static void led_gamma_40hz_cb(void *arg)
189190
}
190191
led_strip_refresh(s_viz_led);
191192
}
193+
#endif /* CONFIG_LED_GAMMA_VIZ */
192194

193195
void app_main(void)
194196
{
@@ -219,10 +221,11 @@ void app_main(void)
219221
ESP_LOGI(TAG, "%s CSI Node (ADR-018 / ADR-110) — v%s — Node ID: %d",
220222
target_name, app_desc->version, g_nvs_config.node_id);
221223

222-
/* Onboard WS2812: sweep the ruv-neural-viz viridis colormap at 40 Hz.
223-
* C6 dev boards wire the LED to GPIO 8; S3 boards to GPIO 38 (DevKitC-1 v1.0)
224+
/* Onboard WS2812. C6 wires the LED to GPIO 8; S3 to GPIO 38 (DevKitC-1 v1.0)
224225
* or GPIO 48 (DevKitC-1 v1.1 / N16R8 — see #962). On S3 we drive 48 (the
225-
* common module). On C6, GPIO 38/48 don't exist (only 0-30) — gate by target. */
226+
* common module). On C6, GPIO 38/48 don't exist (only 0-30) — gate by target.
227+
* Behaviour is set by CONFIG_LED_GAMMA_VIZ (ADR-183): on = 40 Hz gamma flicker
228+
* coloured by CSI motion; off = clear the LED at boot. */
226229
#if defined(CONFIG_IDF_TARGET_ESP32C6)
227230
const int led_gpio = 8;
228231
#else
@@ -239,6 +242,7 @@ void app_main(void)
239242
.resolution_hz = 10 * 1000 * 1000, // 10MHz
240243
.flags.with_dma = false,
241244
};
245+
#if CONFIG_LED_GAMMA_VIZ
242246
if (led_strip_new_rmt_device(&strip_config, &rmt_config, &s_viz_led) == ESP_OK) {
243247
const esp_timer_create_args_t viz_args = {
244248
.callback = &led_gamma_40hz_cb,
@@ -250,6 +254,14 @@ void app_main(void)
250254
ESP_LOGI(TAG, "Onboard WS2812: 40 Hz gamma flicker (GENUS), colour=CSI motion via ruv-neural-viz, GPIO %d", led_gpio);
251255
}
252256
}
257+
#else
258+
/* Viz disabled — clear the onboard LED at boot and release the RMT channel. */
259+
led_strip_handle_t led_strip;
260+
if (led_strip_new_rmt_device(&strip_config, &rmt_config, &led_strip) == ESP_OK) {
261+
led_strip_clear(led_strip);
262+
led_strip_del(led_strip);
263+
}
264+
#endif /* CONFIG_LED_GAMMA_VIZ */
253265

254266
/* ADR-110 P4: 802.15.4 mesh time-sync (C6 only).
255267
* Initialized BEFORE WiFi so it's available even when WiFi STA can't

0 commit comments

Comments
 (0)