@brief On FL_IS_STUB: register a one-shot async task that drives autoresearch On the stub (native/host) platform, this registers an async task that: 1. Discovers available drivers 2. Tests each driver with autoResearchChipsetTiming() 3. Collects results and exits 0 (all passed) or 1 (failure/no tests) On all other platforms (ESP32, etc.), this is a no-op. @param remote Reference to RemoteContro
| 51 | /// @param remote Reference to RemoteControl singleton (unused on non-stub) |
| 52 | /// @param state Shared autoresearch state (contains driver list, pins, RX channel) |
| 53 | inline void maybeRegisterStubAutorun( |
| 54 | AutoResearchRemoteControl& /*remote*/, |
| 55 | fl::shared_ptr<AutoResearchState> state) { |
| 56 | #ifdef FL_IS_STUB |
| 57 | // Register a task that runs on the next async_run() cycle (during loop()) |
| 58 | // Note: every_ms(0) fires immediately; after_frame() requires frame-task |
| 59 | // dispatch which isn't wired up in the stub example runner. |
| 60 | fl::task::every_ms(0, FL_TRACE).then([state]() { |
| 61 | if (!state || state->drivers_available.empty()) { |
| 62 | FL_ERROR("[STUB CLIENT] No drivers discovered — autoresearch cannot run"); |
| 63 | exit(1); |
| 64 | } |
| 65 | |
| 66 | FL_PRINT("\n[STUB CLIENT] ============================================"); |
| 67 | FL_PRINT("[STUB CLIENT] Simulated host client — running autoresearch"); |
| 68 | FL_PRINT("[STUB CLIENT] Drivers: " << state->drivers_available.size()); |
| 69 | FL_PRINT("[STUB CLIENT] ============================================"); |
| 70 | |
| 71 | // WS2812B-V5 timing (same as the Python client default) |
| 72 | fl::NamedTimingConfig timing_cfg( |
| 73 | fl::makeTimingConfig<fl::TIMING_WS2812B_V5>(), "WS2812B-V5"); |
| 74 | |
| 75 | // Static LED storage — span must remain valid for the entire call |
| 76 | static CRGB stub_leds[10]; |
| 77 | const int num_leds = 10; |
| 78 | |
| 79 | // ChannelConfig stores timing by value internally, so passing a local ref is fine |
| 80 | fl::ChannelConfig stub_tx_cfg( |
| 81 | state->pin_tx, |
| 82 | timing_cfg.timing, |
| 83 | fl::span<CRGB>(stub_leds, num_leds), |
| 84 | RGB); |
| 85 | |
| 86 | int grand_total = 0, grand_passed = 0; |
| 87 | |
| 88 | for (fl::size di = 0; di < state->drivers_available.size(); di++) { |
| 89 | const auto& drv = state->drivers_available[di]; |
| 90 | |
| 91 | // BIT_BANG is the cycle-counted GPIO fallback. On the stub/host |
| 92 | // platform there is no actual GPIO toggling, so its TX output |
| 93 | // can't be captured by the loopback RX path the stub uses for |
| 94 | // self-verification. Skip it in the stub autorun (#2469) — it's |
| 95 | // still available for explicit selection by name on real hardware. |
| 96 | if (drv.name == "BIT_BANG") { |
| 97 | FL_PRINT("\n[STUB CLIENT] Driver: " << drv.name.c_str() << " (skipped — no loopback in host stub)"); |
| 98 | continue; |
| 99 | } |
| 100 | |
| 101 | FL_PRINT("\n[STUB CLIENT] Driver: " << drv.name.c_str()); |
| 102 | |
| 103 | if (!autoResearchSetExclusiveDriverByName(drv.name.c_str())) { |
| 104 | FL_ERROR("[STUB CLIENT] Failed to activate driver: " << drv.name.c_str()); |
| 105 | grand_total++; // count as a failure |
| 106 | continue; |
| 107 | } |
| 108 | |
| 109 | // AutoResearchConfig holds timing by reference — timing_cfg is in scope |
| 110 | fl::AutoResearchConfig vcfg( |
nothing calls this directly
no test coverage detected