FastLED 3.10.8
Loading...
Searching...
No Matches
AutoResearchLowMemory.h
Go to the documentation of this file.
1#pragma once
2//
3// examples/AutoResearch/AutoResearchLowMemory.h
4//
5// Low-memory AutoResearch bring-up surface for parts whose flash budget
6// cannot fit the full ESP32 / Teensy LED-protocol matrix. Originally lived
7// as the standalone `examples/AutoResearchLpc/AutoResearchLpc.ino` sketch;
8// retired and folded in here per FastLED #3030 once the soft-FP cascade
9// from #3022 phase 2 freed up the budget on LPC8xx.
10//
11// Included from the main `AutoResearch.ino` when
12// `FL_PLATFORM_HAS_LARGE_MEMORY == 0` (Low + Tiny tiers per the FastLED
13// #3000 memory classification).
14//
15// Same JSON-RPC contract as the retired LPC sketch:
16// echo: [int] -> int
17// pinToggleRx: [tx_pin, rx_pin, freq_hz, duration_ms] -> CSV
18// ws2812SctTest: [test_case, tx_pin, rx_pin, capture_ms] -> CSV
19// See FastLED #3021 for the SCT-RX bring-up flags.
20//
21
22#include "platforms/arm/lpc/is_lpc.h" // ok platform headers - LPC RX driver gate
23
24// Gate FL_DBG to no-op. Without `RELEASE`, fl/log/log.h auto-sets
25// FASTLED_FORCE_DBG=1, which expands every FL_DBG call site (inside
26// fl::Remote etc.) through the fl::println formatting machinery and
27// blows ~4 KB of flash budget. fbuild's nxplpc orchestrator does not
28// yet propagate platformio.ini's `build_flags`, so it's defined here.
29#ifndef RELEASE
30#define RELEASE 1
31#endif
32
33// Dedicated #3039 codec-test builds keep the low-memory surface to echo +
34// IEEE754 only. The SCT/WS2812 handlers are useful diagnostics, but they are
35// unrelated to the codec and push LPC845 past its flash budget when combined.
36#if defined(FL_AUTORESEARCH_IEEE754) && FL_AUTORESEARCH_IEEE754
37#define FASTLED_AUTORESEARCH_IEEE754_MODE 1
38#endif
39
40#if !defined(FASTLED_AUTORESEARCH_LPC_UART_DMA)
41#define FASTLED_AUTORESEARCH_LPC_UART_DMA 0
42#endif
43
44// Opt in to the SCT input-capture RX backend (FastLED #3021). With this
45// flag set, `LpcSctRxChannel::begin()` programs the SCT for hardware
46// edge-capture; without it the driver is a no-op stub (host tests still
47// work via `injectEdges()`).
48#if !defined(FASTLED_AUTORESEARCH_IEEE754_MODE) && \
49 !defined(FASTLED_AUTORESEARCH_FAULT_TEST)
50#ifndef FASTLED_LPC_RX_SCT
51#define FASTLED_LPC_RX_SCT 1
52#endif
53#endif
54
55// The LPC845-BRK low-memory build fits FastLED + Remote + the WS2812 loopback
56// RPC in normal mode. The dedicated IEEE754 mode deliberately omits it.
57#if defined(FL_IS_ARM_LPC_845) && !defined(FASTLED_AUTORESEARCH_IEEE754_MODE) && \
58 !defined(FASTLED_AUTORESEARCH_FAULT_TEST) && !defined(FASTLED_LPC_SPI_DMA) && \
59 !defined(FASTLED_LPC_PWM_DMA) && !FASTLED_AUTORESEARCH_LPC_UART_DMA
60#define FASTLED_AUTORESEARCH_LPC_WS2812 1
61#endif
62
63// The WS2812 loopback uses the SCT->DMA RX capture path. The UART clockless
64// verifier uses USART RX-DMA instead, so keep SCT-DMA out of that build;
65// UM11029 Table 296 fixes USART1_RX/USART1_TX on DMA channels 2/3.
66#if defined(FASTLED_AUTORESEARCH_LPC_WS2812) && \
67 !defined(FASTLED_LPC_RX_SCT_DMA)
68#define FASTLED_LPC_RX_SCT_DMA 1
69#endif
70
71#include <Arduino.h>
72#include "fl/remote/remote.h"
75#include "fl/wdt/watchdog.h"
76#include "fl/log/log.h"
77#include "fl/stl/cstdio.h" // fl::serial_begin -- HWCDC-safe Serial.begin wrapper
78#include "fl/stl/singleton.h"
79
80#if defined(FASTLED_AUTORESEARCH_IEEE754_MODE)
81#include "AutoResearchIeee754.h"
82#endif
83
84// The host-stub example DLL build (`tests/shared/example_dll_wrapper_template.cpp`)
85// compiles this sketch on Linux to surface ABI breaks. The RX SCT driver
86// types are platform-gated behind `FL_IS_ARM_LPC` -- they only exist on
87// the real LPC build. So the include + every RX usage below must be gated
88// the same way.
89#if defined(FL_IS_ARM_LPC) && !defined(FASTLED_AUTORESEARCH_IEEE754_MODE) && \
90 !defined(FASTLED_AUTORESEARCH_FAULT_TEST)
92#include "fl/stl/strstream.h"
93#endif
94
95#if defined(FASTLED_AUTORESEARCH_LPC_WS2812)
96#include "FastLED.h"
98#endif
99
100// FastLED #3468: channels-API SCT+DMA clockless AutoResearch harness.
101// Opt-in via `-DFASTLED_LPC_PWM_DMA=1`; the header self-gates on
102// `FL_IS_ARM_LPC_845 && FASTLED_LPC_PWM_DMA` so unrelated builds are
103// unaffected. Note: exclusive with FASTLED_AUTORESEARCH_LPC_WS2812 —
104// both target the same SCT peripheral and would collide at runtime.
105// The host-side `bash autoresearch --pwm-dma-cl` wrapper enforces
106// mutual exclusion with `--dma-spi` and the legacy `ws2812SctTest`.
107#if defined(FL_IS_ARM_LPC_845) && defined(FASTLED_LPC_PWM_DMA)
109#endif
110
111// FastLED #3456: LPC845 SPI+DMA async AutoResearch harness (Phase 1 of
112// #3453 bench bring-up). Opt-in via `-DFASTLED_LPC_SPI_DMA=1`; the
113// header self-gates on `FL_IS_ARM_LPC_845 && FASTLED_LPC_SPI_DMA`.
114// LPC804 is NOT supported — silicon has no DMA peripheral. See
115// `agents/docs/peripheral-existence.md`. Mutually exclusive with
116// FASTLED_LPC_PWM_DMA (both claim DMA0 channels and the LowMemory
117// flash budget doesn't fit both). Enforced host-side by
118// `bash autoresearch` refusing `--dma-spi --pwm-dma-cl`.
119#if defined(FL_IS_ARM_LPC_845) && defined(FASTLED_LPC_SPI_DMA) && \
120 defined(FASTLED_LPC_PWM_DMA)
121#error "FASTLED_LPC_SPI_DMA and FASTLED_LPC_PWM_DMA are mutually exclusive on LPC845: both claim DMA0 channels and the LowMemory flash budget doesn't fit both. Pick one for the AutoResearch build."
122#endif
123#if defined(FL_IS_ARM_LPC_845) && defined(FASTLED_LPC_SPI_DMA)
124#include "AutoResearchSpiDma.h"
125#endif
126
127// #3453 follow-up: LPC845 async UART TX harness (DMA + ISR chunk chain) and
128// #3611 UART clockless loopback verifier. The UART DMA driver is now the
129// LPC845 library default, so the AutoResearch RPC harness has its own flag.
130#if defined(FL_IS_ARM_LPC_845) && FASTLED_AUTORESEARCH_LPC_UART_DMA && \
131 !FASTLED_LPC_UART_DMA
132#error "FASTLED_AUTORESEARCH_LPC_UART_DMA requires FASTLED_LPC_UART_DMA=1."
133#endif
134#if defined(FL_IS_ARM_LPC_845) && FASTLED_AUTORESEARCH_LPC_UART_DMA && \
135 (defined(FASTLED_LPC_SPI_DMA) || defined(FASTLED_LPC_PWM_DMA))
136#error "FASTLED_AUTORESEARCH_LPC_UART_DMA is mutually exclusive with the SPI/PWM DMA harnesses on LPC845: the LowMemory flash budget fits one bench at a time. Pick one for the AutoResearch build."
137#endif
138#if defined(FL_IS_ARM_LPC_845) && FASTLED_AUTORESEARCH_LPC_UART_DMA
139#include "AutoResearchUartDma.h"
140#endif
141
142namespace autoresearch {
143namespace low_memory {
144
147
149 : remote(fl::createSerialRequestSource(),
150 fl::createSerialResponseSink("REMOTE: ")) {}
151};
152
156
157#if defined(FL_IS_ARM_LPC) && !defined(FASTLED_AUTORESEARCH_IEEE754_MODE) && \
158 !defined(FASTLED_AUTORESEARCH_FAULT_TEST)
159struct PinToggleState {
160 fl::EdgeTime edges[64];
161};
162
163inline PinToggleState& pinToggleState() {
165}
166#endif
167
168#if defined(FASTLED_AUTORESEARCH_LPC_WS2812)
169struct Ws2812State {
170 CRGB leds[100];
171 uint8_t expected[300];
172 uint8_t decoded[300];
173 fl::EdgeTime probe[64];
174 bool fastled_initialized;
175
176 Ws2812State() : fastled_initialized(false) {}
177};
178
179inline Ws2812State& ws2812State() {
181}
182#endif
183
184} // namespace low_memory
185} // namespace autoresearch
186
187namespace {
188
189#if defined(FL_IS_ARM_LPC) && !defined(FASTLED_AUTORESEARCH_IEEE754_MODE) && \
190 !defined(FASTLED_AUTORESEARCH_FAULT_TEST)
191// Period-stat helpers for `pinToggleRx`. Mirrors the FlexIO RX benchmark
192// logic in `examples/AutoResearch/AutoResearchRemote.cpp::flexioRxBenchmark`
193// but inline so we don't pull in the AutoResearch ObjectFLED bus.
194struct LowMemPinTogglePeriodStats {
195 fl::u32 periods;
196 fl::u32 mean_ns;
197 fl::u32 sigma_ns;
198 fl::u32 min_ns;
199 fl::u32 max_ns;
200};
201
202inline LowMemPinTogglePeriodStats computeLowMemPeriodStats(
203 const fl::EdgeTime* edges, fl::size edge_count) FL_NO_EXCEPT {
204 LowMemPinTogglePeriodStats s{0, 0, 0, 0, 0};
205 fl::u64 sum = 0;
206 fl::u64 sum_sq = 0;
207 fl::u32 min_ns = 0xFFFFFFFFu;
208 fl::u32 max_ns = 0;
209 fl::u32 count = 0;
210 for (fl::size i = 0; i + 1 < edge_count; i += 2) {
211 const fl::u32 period_ns =
212 static_cast<fl::u32>(edges[i].ns) +
213 static_cast<fl::u32>(edges[i + 1].ns);
214 if (period_ns == 0) continue;
215 sum += period_ns;
216 sum_sq += static_cast<fl::u64>(period_ns) * static_cast<fl::u64>(period_ns);
217 if (period_ns < min_ns) min_ns = period_ns;
218 if (period_ns > max_ns) max_ns = period_ns;
219 ++count;
220 }
221 if (count == 0) return s;
222 const fl::u32 mean = static_cast<fl::u32>(sum / static_cast<fl::u64>(count));
223 const fl::u64 mean64 = static_cast<fl::u64>(mean);
224 const fl::u64 var = (sum_sq / static_cast<fl::u64>(count)) - (mean64 * mean64);
225 fl::u32 sig = 0;
226 while (static_cast<fl::u64>(sig + 1) * static_cast<fl::u64>(sig + 1) <= var) ++sig;
227 s.periods = count;
228 s.mean_ns = mean;
229 s.sigma_ns = sig;
230 s.min_ns = (min_ns == 0xFFFFFFFFu) ? 0u : min_ns;
231 s.max_ns = max_ns;
232 return s;
233}
234#endif // FL_IS_ARM_LPC && !FASTLED_AUTORESEARCH_IEEE754_MODE && !FAULT_TEST
235
236#if defined(FL_IS_ARM_LPC_845) && defined(FASTLED_AUTORESEARCH_FAULT_TEST)
237FL_NO_RETURN FL_NO_INLINE void triggerLowMemoryNullFault() FL_NO_EXCEPT {
238 volatile fl::u32* const p =
239 reinterpret_cast<volatile fl::u32*>(0u); // ok reinterpret cast - fault test
240 *p = 0x3302u;
241 while (true) {}
242}
243
245FL_DISABLE_WARNING(infinite-recursion)
246FL_NO_INLINE int recurseLowMemoryStackBlow(int depth) FL_NO_EXCEPT {
247 volatile fl::u8 pad[64] = {0};
248 pad[static_cast<fl::u8>(depth) & 0x3Fu] = static_cast<fl::u8>(depth);
249 // LPC845/M0+ has no stack-limit trap; unbounded recursion can corrupt the
250 // runtime before the HardFault handler can emit. Burn stack frames, then
251 // force the HardFault path while the diagnostic surface is still intact.
252 if (depth >= 32) {
253 triggerLowMemoryNullFault();
254 }
255 return recurseLowMemoryStackBlow(depth + 1) + pad[depth & 0x3F];
256}
258#endif // FL_IS_ARM_LPC_845 && FASTLED_AUTORESEARCH_FAULT_TEST
259
260} // namespace
261
263 fl::serial_begin(115200);
264
265 // Arm the watchdog so a hung sketch unbricks itself on crash.
267
268 // Emit a literal-only warning so the autoresearch harness can verify
269 // the FL_WARN log pipeline reaches the host.
270 FL_WARN_LIT("FL_WARN: low-memory bring-up OK");
271
272 // The C++ inline-ODR rule guarantees a single shared instance across
273 // every translation unit that calls this inline function, which is
274 // exactly what we want (one Remote bound to the singleton Serial
275 // transport). The included-once-per-sketch model of `.ino` builds
276 // also reduces to a single TU in practice.
278 remote.bind("echo", [](int v) -> int {
279 FL_WARN_LIT("FL_WARN: echo invoked");
280 return v;
281 });
282
283#if defined(FL_IS_ARM_LPC_845) && defined(FASTLED_AUTORESEARCH_FAULT_TEST)
284 remote.bind("trigger_oom", []() -> bool {
285 // Intentional #3302 fault input: ask the 16 KB SRAM target for
286 // far more RAM than exists. If the platform allocator returns null
287 // instead of trapping, dereference null to exercise HardFault emit.
288 volatile char* const p = new char[16UL * 1024UL * 1024UL]; // ok bare allocation
289 if (p == nullptr) {
290 triggerLowMemoryNullFault();
291 }
292 p[0] = 0x33;
293 triggerLowMemoryNullFault();
294 return false;
295 });
296 remote.bind("trigger_stackblow", []() -> bool {
297 (void)recurseLowMemoryStackBlow(0);
298 triggerLowMemoryNullFault();
299 return false;
300 });
301#endif // FL_IS_ARM_LPC_845 && FASTLED_AUTORESEARCH_FAULT_TEST
302
303#if defined(FASTLED_AUTORESEARCH_IEEE754_MODE)
304 remote.bind("ieee754CodecTest", [](const fl::json& args) -> fl::json {
305 (void)args;
306 const auto r = autoresearch::ieee754_check::run();
307 fl::json response = fl::json::object();
308 response.set("success", r.success);
309 response.set("tests_run", static_cast<int64_t>(r.tests_run));
310 response.set("tests_failed", static_cast<int64_t>(r.tests_failed));
311 response.set("first_failure", r.first_failure ? r.first_failure : "");
312 response.set("expected_bits", static_cast<int64_t>(r.expected_bits));
313 response.set("actual_bits", static_cast<int64_t>(r.actual_bits));
314 return response;
315 });
316#endif
317
318#if defined(FL_IS_ARM_LPC) && !defined(FASTLED_AUTORESEARCH_IEEE754_MODE) && \
319 !defined(FASTLED_AUTORESEARCH_FAULT_TEST)
320 // pinToggleRx (FastLED #3021 Phase 1) — bit-bang square wave on tx_pin
321 // and capture SCT edges on rx_pin. CSV stats out.
322#if !defined(FASTLED_AUTORESEARCH_LPC_DMA_LOOPBACK)
323 // Left out of the RX-DMA loopback builds (--ws2812-loopback/--pwm-dma-cl):
324 // with the DMA capture linked, the 64 KB LPC845 has no room for this
325 // unrelated ~1 KB diagnostic. --pin-toggle-rx builds keep it.
326 remote.bind("pinToggleRx",
327 [](int tx_pin, int rx_pin, int freq_hz, int duration_ms) -> fl::string {
328 if (tx_pin < 0 || rx_pin < 0 || freq_hz <= 0 || duration_ms <= 0) {
329 return fl::string("0,0,0,0,0,0,0");
330 }
331 const fl::u32 expected_edges =
332 2u * static_cast<fl::u32>(freq_hz) *
333 static_cast<fl::u32>(duration_ms) / 1000u;
334 // Keep both the RX vector and diagnostic copy buffer small on
335 // 16 KB SRAM LPC8xx parts. Larger static buffers regressed early
336 // init by leaving too little room for stack/heap (FastLED #3200),
337 // while stack buffers previously overflowed during this handler
338 // (FastLED #3125).
339 constexpr fl::u32 kLowMemEdgeBufSize = 64u;
340 fl::u32 cap = expected_edges + (expected_edges / 2u);
341 if (cap < 2u) cap = 2u;
342 if (cap > kLowMemEdgeBufSize) cap = kLowMemEdgeBufSize;
343
344 auto rx = fl::LpcSctRxChannel::create(rx_pin);
345 if (!rx) return fl::string("0,0,0,0,0,0,0");
346
347 fl::RxConfig cfg;
348 cfg.buffer_size = cap;
349 cfg.start_low = true;
350 if (!rx->begin(cfg)) return fl::string("0,0,0,0,0,0,0");
351
352 pinMode(tx_pin, OUTPUT);
353 digitalWrite(tx_pin, LOW);
354
355 const fl::u32 half_us = 500000u / static_cast<fl::u32>(freq_hz);
356 const fl::u32 cycles = static_cast<fl::u32>(freq_hz) *
357 static_cast<fl::u32>(duration_ms) / 1000u;
358
359 for (fl::u32 i = 0; i < cycles; ++i) {
360 digitalWrite(tx_pin, HIGH);
361 delayMicroseconds(half_us);
362 rx->pollOnce();
363 digitalWrite(tx_pin, LOW);
364 delayMicroseconds(half_us);
365 rx->pollOnce();
366 if ((i & 0x7Fu) == 0u) {
368 }
369 }
370 rx->wait(1);
371
372 // Static storage keeps this off the stack; the small fixed size
373 // keeps .bss below the LPC845-BRK early-init failure threshold.
374 fl::EdgeTime* edges_buf = autoresearch::low_memory::pinToggleState().edges;
375 const fl::size n_read = rx->getRawEdgeTimes(
376 fl::span<fl::EdgeTime>(edges_buf, sizeof(edges_buf) / sizeof(edges_buf[0])));
377
378 LowMemPinTogglePeriodStats stats = computeLowMemPeriodStats(edges_buf, n_read);
379
380 fl::sstream s;
381 const bool success = (stats.periods > 0);
382 s << (success ? 1 : 0) << ',' << static_cast<fl::u32>(n_read) << ','
383 << stats.periods << ',' << stats.mean_ns << ',' << stats.sigma_ns << ','
384 << stats.min_ns << ',' << stats.max_ns;
385 return s.str();
386 });
387#endif // !FASTLED_AUTORESEARCH_LPC_DMA_LOOPBACK
388
389#if defined(FASTLED_AUTORESEARCH_LPC_WS2812)
390 // ws2812SctTest (FastLED #3021 Phase 2) -- WS2812 byte-match loopback.
391 remote.bind("ws2812SctTest",
392 [](int test_case, int tx_pin, int rx_pin, int capture_ms) -> fl::string {
393 if (test_case < 0 || test_case > 4 ||
394 tx_pin < 0 || rx_pin < 0 || capture_ms <= 0) {
395 return fl::string("0,0,0,0,0,0,0,0");
396 }
397 int num_leds = 1;
398 switch (test_case) {
399 case 1: num_leds = 3; break;
400 case 4: num_leds = 100; break;
401 default: num_leds = 1; break;
402 }
403 autoresearch::low_memory::Ws2812State& ws_state =
404 autoresearch::low_memory::ws2812State();
405 CRGB* leds_buf = ws_state.leds;
406 for (int i = 0; i < num_leds; ++i) {
407 switch (test_case) {
408 case 0: leds_buf[i] = CRGB(0xFF, 0x00, 0x00); break;
409 case 1: {
410 if (i == 0) leds_buf[i] = CRGB(0xFF, 0x00, 0x00);
411 else if (i == 1) leds_buf[i] = CRGB(0x00, 0xFF, 0x00);
412 else leds_buf[i] = CRGB(0x00, 0x00, 0xFF);
413 break;
414 }
415 case 2: leds_buf[i] = CRGB(0x00, 0x00, 0x00); break;
416 case 3: leds_buf[i] = CRGB(0xFF, 0xFF, 0xFF); break;
417 case 4: {
418 const uint8_t r = (i % 3 == 0) ? 0xFFu : 0u;
419 const uint8_t g = (i % 3 == 1) ? 0xFFu : 0u;
420 const uint8_t b = (i % 3 == 2) ? 0xFFu : 0u;
421 leds_buf[i] = CRGB(r, g, b);
422 break;
423 }
424 }
425 }
426 const int expected_bytes = num_leds * 3;
427 uint8_t* expected_buf = ws_state.expected;
428 for (int i = 0; i < num_leds; ++i) {
429 expected_buf[i * 3 + 0] = leds_buf[i].g;
430 expected_buf[i * 3 + 1] = leds_buf[i].r;
431 expected_buf[i * 3 + 2] = leds_buf[i].b;
432 }
433 auto rx = fl::LpcSctRxChannel::create(rx_pin);
434 if (!rx) return fl::string("0,0,0,0,0,0,0,0");
435 fl::RxConfig cfg;
436 const fl::u32 expected_edges = (fl::u32)num_leds * 24u * 2u;
437 fl::u32 cap = expected_edges + (expected_edges / 2u);
438 // The low-memory sketch cannot afford the old 2048-edge reserve
439 // on a 16 KB SRAM LPC845. 192 edges covers the 1- and 3-LED
440 // sanity cases and fails the larger diagnostic cases without
441 // starving setup()/loop() stack.
442 constexpr fl::u32 kLowMemWs2812EdgeCapacity = 192u;
443 if (cap < 48u) cap = 48u;
444 if (cap > kLowMemWs2812EdgeCapacity) cap = kLowMemWs2812EdgeCapacity;
445 cfg.buffer_size = cap;
446 cfg.start_low = true;
447 if (!rx->begin(cfg)) return fl::string("0,0,0,0,0,0,0,0");
448
449 constexpr int kFixedTxPin = 10; // P0_10
450 if (tx_pin != kFixedTxPin) {
451 return fl::string("0,0,0,0,0,0,0,0");
452 }
453 if (!ws_state.fastled_initialized) {
454 FastLED.addLeds<WS2812, kFixedTxPin, GRB>(leds_buf, 100);
455 ws_state.fastled_initialized = true;
456 }
457 FastLED.show();
458 rx->wait(capture_ms);
459
460 uint8_t* decoded_buf = ws_state.decoded;
461 for (int i = 0; i < expected_bytes; ++i) decoded_buf[i] = 0;
462
466 /*reset_us=*/0u);
467
468 auto dec = rx->decode(timing, fl::span<u8>(decoded_buf, expected_bytes));
469 const fl::u32 decoded_bytes = dec.ok() ? dec.value() : 0u;
470
471 fl::u32 matched = 0;
472 fl::u32 mismatched = 0;
473 for (fl::u32 i = 0; i < decoded_bytes && i < (fl::u32)expected_bytes; ++i) {
474 if (decoded_buf[i] == expected_buf[i]) ++matched;
475 else ++mismatched;
476 }
477 const fl::u32 missing = (fl::u32)expected_bytes - decoded_bytes;
478 mismatched += missing;
479
480 // Diagnostic-only raw-edge sample. Keep this small in .bss; the
481 // decoder uses the RX channel's bounded capture vector above.
482 constexpr fl::size kLowMemWs2812ProbeSize = 64u;
483 fl::EdgeTime* probe = ws_state.probe;
484 const fl::size edges_captured = rx->getRawEdgeTimes(
485 fl::span<fl::EdgeTime>(probe, kLowMemWs2812ProbeSize));
486
487 const bool success = (mismatched == 0 && decoded_bytes == (fl::u32)expected_bytes);
488
489 fl::sstream s;
490 s << (success ? 1 : 0) << ',' << test_case << ',' << num_leds << ','
491 << expected_bytes << ',' << decoded_bytes << ','
492 << matched << ',' << mismatched << ','
493 << static_cast<fl::u32>(edges_captured);
494 return s.str();
495 });
496#endif // FASTLED_AUTORESEARCH_LPC_WS2812
497
498 // FastLED #3468: channels-API SCT+DMA clockless AutoResearch
499 // harness. Binds pwmDmaClFrameOnce / pwmDmaClFrameBurst /
500 // pwmDmaClCaptureSelf. Header self-gates on
501 // FL_IS_ARM_LPC_845 && FASTLED_LPC_PWM_DMA.
502#if defined(FL_IS_ARM_LPC_845) && defined(FASTLED_LPC_PWM_DMA)
503 autoresearch::pwm_dma_cl::bind(remote);
504#endif
505
506 // FastLED #3456: SPI+DMA async AutoResearch harness. Binds
507 // dmaSpiTransferOnce / dmaSpiTransferOverlap / dmaSpiMeasureSck.
508 // Header self-gates on FL_IS_ARM_LPC_845 && FASTLED_LPC_SPI_DMA.
509#if defined(FL_IS_ARM_LPC_845) && defined(FASTLED_LPC_SPI_DMA)
510 autoresearch::dma_spi::bind(remote);
511#endif
512
513 // #3453/#3611: UART DMA AutoResearch harness. Binds either the raw
514 // UART DMA stream bench or the clockless loopback verifier, depending
515 // on the build flags injected by `bash autoresearch`.
516#if defined(FL_IS_ARM_LPC_845) && FASTLED_AUTORESEARCH_LPC_UART_DMA
517 autoresearch::uart_dma::bind(remote);
518#endif
519
520#endif // FL_IS_ARM_LPC && !FASTLED_AUTORESEARCH_IEEE754_MODE
521}
522
CRGB leds[1]
On-device verification for the integer-only IEEE 754 decimal codec.
void autoResearchLowMemoryLoop()
void autoResearchLowMemorySetup()
FL_DISABLE_WARNING_PUSH FL_DISABLE_WARNING_GLOBAL_CONSTRUCTORS CFastLED FastLED
Global LED strip management instance.
fl::unique_ptr< fl::Remote > remote
Definition RpcClient.ino:43
size_t update(u32 currentTimeMs) FL_NO_EXCEPT
Main update: pull + tick + push (overrides Server::update)
JSON-RPC server with scheduling support.
Definition remote.h:42
static T & instance() FL_NO_EXCEPT
Definition singleton.h:81
static Watchdog & instance() FL_NO_EXCEPT
void begin(fl::u32 timeout_ms) FL_NO_EXCEPT
void feed() FL_NO_EXCEPT
static json object() FL_NO_EXCEPT
Definition json.h:857
string str() const FL_NO_EXCEPT
Definition strstream.h:43
#define FL_DISABLE_WARNING(warning)
#define FL_DISABLE_WARNING_PUSH
#define FL_NO_INLINE
#define FL_DISABLE_WARNING_POP
#define FL_NO_RETURN
constexpr EOrder GRB
Definition eorder.h:19
fl::CRGB CRGB
Definition crgb.h:25
#define FL_WARN_LIT(LITERAL)
Definition log.h:455
Centralized logging categories for FastLED hardware interfaces and subsystems.
unsigned char u8
Definition stdint.h:131
constexpr ChipsetTiming to_runtime_timing() FL_NO_EXCEPT
Convert enum-based timing type to runtime ChipsetTiming struct.
Definition led_timing.h:616
ChipsetTiming4Phase make4PhaseTiming(const ChipsetTiming &timing_3phase, u32 tolerance_ns) FL_NO_EXCEPT
Create 4-phase RX timing from 3-phase chipset timing with tolerance.
Definition rx.cpp.hpp:72
void serial_begin(u32 baudRate) FL_NO_EXCEPT
Base definition for an LED controller.
Definition crgb.hpp:179
4-phase RX timing thresholds for chipset detection
Definition rx.h:88
corkscrew_args args
Definition old.h:149
Public re-export of the LPC SCT-capture RX driver (FastLED#3015).
#define FL_NO_EXCEPT
unsigned char uint8_t
Definition stdint.h:208
u32 ns
Duration in nanoseconds (31 bits, max ~2.1s)
Definition rx.h:35
Universal edge timing representation (platform-agnostic)
Definition rx.h:34
size_t buffer_size
Buffer size in symbols/edges (default: 512)
Definition rx.h:225
bool start_low
Pin idle state: true=LOW (WS2812B), false=HIGH (inverted)
Definition rx.h:232
Configuration for RX device initialization.
Definition rx.h:223
Compile-time timing extraction from ChipsetTiming structs.
Unified cross-platform Watchdog Timer API for FastLED.