FastLED 3.10.9
Loading...
Searching...
No Matches

◆ autoResearchLowMemorySetup()

void autoResearchLowMemorySetup ( )
inline

Definition at line 278 of file AutoResearchLowMemory.h.

278 {
279 fl::serial_begin(115200);
280
281 // Arm the watchdog so a hung sketch unbricks itself on crash.
283
284 // Emit a literal-only warning so the autoresearch harness can verify
285 // the FL_WARN log pipeline reaches the host.
286 FL_WARN_LIT("FL_WARN: low-memory bring-up OK");
287
288 // The C++ inline-ODR rule guarantees a single shared instance across
289 // every translation unit that calls this inline function, which is
290 // exactly what we want (one Remote bound to the singleton Serial
291 // transport). The included-once-per-sketch model of `.ino` builds
292 // also reduces to a single TU in practice.
294 remote.bind("echo", [](int v) -> int {
295 FL_WARN_LIT("FL_WARN: echo invoked");
296 return v;
297 });
298
299#if defined(FL_IS_ARM_LPC_845) && defined(FASTLED_AUTORESEARCH_FAULT_TEST)
300 remote.bind("trigger_oom", []() -> bool {
301 // Intentional #3302 fault input: ask the 16 KB SRAM target for
302 // far more RAM than exists. If the platform allocator returns null
303 // instead of trapping, dereference null to exercise HardFault emit.
304 volatile char* const p = new char[16UL * 1024UL * 1024UL]; // ok bare allocation
305 if (p == nullptr) {
306 triggerLowMemoryNullFault();
307 }
308 p[0] = 0x33;
309 triggerLowMemoryNullFault();
310 return false;
311 });
312 remote.bind("trigger_stackblow", []() -> bool {
313 (void)recurseLowMemoryStackBlow(0);
314 triggerLowMemoryNullFault();
315 return false;
316 });
317#endif // FL_IS_ARM_LPC_845 && FASTLED_AUTORESEARCH_FAULT_TEST
318
319#if defined(FL_IS_ESP8266) // ok platform specific - ESP8266 bring-up benches
320 autoresearch::esp8266::bindEsp8266Benches(remote);
321#endif
322
323#if defined(FASTLED_AUTORESEARCH_IEEE754_MODE)
324 remote.bind("ieee754CodecTest", [](const fl::json& args) -> fl::json {
325 (void)args;
326 const auto r = autoresearch::ieee754_check::run();
328 response.set("success", r.success);
329 response.set("tests_run", static_cast<int64_t>(r.tests_run));
330 response.set("tests_failed", static_cast<int64_t>(r.tests_failed));
331 response.set("first_failure", r.first_failure ? r.first_failure : "");
332 response.set("expected_bits", static_cast<int64_t>(r.expected_bits));
333 response.set("actual_bits", static_cast<int64_t>(r.actual_bits));
334 return response;
335 });
336#endif
337
338#if defined(FL_IS_ARM_LPC) && !defined(FASTLED_AUTORESEARCH_IEEE754_MODE) && \
339 !defined(FASTLED_AUTORESEARCH_FAULT_TEST)
340 // pinToggleRx (FastLED #3021 Phase 1) — bit-bang square wave on tx_pin
341 // and capture SCT edges on rx_pin. CSV stats out.
342#if !defined(FASTLED_AUTORESEARCH_LPC_DMA_LOOPBACK)
343 // Left out of the RX-DMA loopback builds (--ws2812-loopback/--pwm-dma-cl):
344 // with the DMA capture linked, the 64 KB LPC845 has no room for this
345 // unrelated ~1 KB diagnostic. --pin-toggle-rx builds keep it.
346 remote.bind("pinToggleRx",
347 [](int tx_pin, int rx_pin, int freq_hz, int duration_ms) -> fl::string {
348 if (tx_pin < 0 || rx_pin < 0 || freq_hz <= 0 || duration_ms <= 0) {
349 return fl::string("0,0,0,0,0,0,0");
350 }
351 const fl::u32 expected_edges =
352 2u * static_cast<fl::u32>(freq_hz) *
353 static_cast<fl::u32>(duration_ms) / 1000u;
354 // Keep both the RX vector and diagnostic copy buffer small on
355 // 16 KB SRAM LPC8xx parts. Larger static buffers regressed early
356 // init by leaving too little room for stack/heap (FastLED #3200),
357 // while stack buffers previously overflowed during this handler
358 // (FastLED #3125).
359 constexpr fl::u32 kLowMemEdgeBufSize = 64u;
360 fl::u32 cap = expected_edges + (expected_edges / 2u);
361 if (cap < 2u) cap = 2u;
362 if (cap > kLowMemEdgeBufSize) cap = kLowMemEdgeBufSize;
363
364 auto rx = fl::LpcSctRxChannel::create(rx_pin);
365 if (!rx) return fl::string("0,0,0,0,0,0,0");
366
367 fl::RxConfig cfg;
368 cfg.buffer_size = cap;
369 cfg.start_low = true;
370 if (!rx->begin(cfg)) return fl::string("0,0,0,0,0,0,0");
371
372 pinMode(tx_pin, OUTPUT);
373 digitalWrite(tx_pin, LOW);
374
375 const fl::u32 half_us = 500000u / static_cast<fl::u32>(freq_hz);
376 const fl::u32 cycles = static_cast<fl::u32>(freq_hz) *
377 static_cast<fl::u32>(duration_ms) / 1000u;
378
379 for (fl::u32 i = 0; i < cycles; ++i) {
380 digitalWrite(tx_pin, HIGH);
381 delayMicroseconds(half_us);
382 rx->pollOnce();
383 digitalWrite(tx_pin, LOW);
384 delayMicroseconds(half_us);
385 rx->pollOnce();
386 if ((i & 0x7Fu) == 0u) {
388 }
389 }
390 rx->wait(1);
391
392 // Static storage keeps this off the stack; the small fixed size
393 // keeps .bss below the LPC845-BRK early-init failure threshold.
394 fl::EdgeTime* edges_buf = autoresearch::low_memory::pinToggleState().edges;
395 const fl::size n_read = rx->getRawEdgeTimes(
396 fl::span<fl::EdgeTime>(edges_buf, sizeof(edges_buf) / sizeof(edges_buf[0])));
397
398 LowMemPinTogglePeriodStats stats = computeLowMemPeriodStats(edges_buf, n_read);
399
400 fl::sstream s;
401 const bool success = (stats.periods > 0);
402 s << (success ? 1 : 0) << ',' << static_cast<fl::u32>(n_read) << ','
403 << stats.periods << ',' << stats.mean_ns << ',' << stats.sigma_ns << ','
404 << stats.min_ns << ',' << stats.max_ns;
405 return s.str();
406 });
407#endif // !FASTLED_AUTORESEARCH_LPC_DMA_LOOPBACK
408
409#if defined(FASTLED_AUTORESEARCH_LPC_WS2812)
410 // ws2812SctTest (FastLED #3021 Phase 2) -- WS2812 byte-match loopback.
411 remote.bind("ws2812SctTest",
412 [](int test_case, int tx_pin, int rx_pin, int capture_ms) -> fl::string {
413 if (test_case < 0 || test_case > 4 ||
414 tx_pin < 0 || rx_pin < 0 || capture_ms <= 0) {
415 return fl::string("0,0,0,0,0,0,0,0");
416 }
417 int num_leds = 1;
418 switch (test_case) {
419 case 1: num_leds = 3; break;
420 case 4: num_leds = 100; break;
421 default: num_leds = 1; break;
422 }
423 autoresearch::low_memory::Ws2812State& ws_state =
424 autoresearch::low_memory::ws2812State();
425 CRGB* leds_buf = ws_state.leds;
426 for (int i = 0; i < num_leds; ++i) {
427 switch (test_case) {
428 case 0: leds_buf[i] = CRGB(0xFF, 0x00, 0x00); break;
429 case 1: {
430 if (i == 0) leds_buf[i] = CRGB(0xFF, 0x00, 0x00);
431 else if (i == 1) leds_buf[i] = CRGB(0x00, 0xFF, 0x00);
432 else leds_buf[i] = CRGB(0x00, 0x00, 0xFF);
433 break;
434 }
435 case 2: leds_buf[i] = CRGB(0x00, 0x00, 0x00); break;
436 case 3: leds_buf[i] = CRGB(0xFF, 0xFF, 0xFF); break;
437 case 4: {
438 const uint8_t r = (i % 3 == 0) ? 0xFFu : 0u;
439 const uint8_t g = (i % 3 == 1) ? 0xFFu : 0u;
440 const uint8_t b = (i % 3 == 2) ? 0xFFu : 0u;
441 leds_buf[i] = CRGB(r, g, b);
442 break;
443 }
444 }
445 }
446 const int expected_bytes = num_leds * 3;
447 uint8_t* expected_buf = ws_state.expected;
448 for (int i = 0; i < num_leds; ++i) {
449 expected_buf[i * 3 + 0] = leds_buf[i].g;
450 expected_buf[i * 3 + 1] = leds_buf[i].r;
451 expected_buf[i * 3 + 2] = leds_buf[i].b;
452 }
453 auto rx = fl::LpcSctRxChannel::create(rx_pin);
454 if (!rx) return fl::string("0,0,0,0,0,0,0,0");
455 fl::RxConfig cfg;
456 const fl::u32 expected_edges = (fl::u32)num_leds * 24u * 2u;
457 fl::u32 cap = expected_edges + (expected_edges / 2u);
458 // The low-memory sketch cannot afford the old 2048-edge reserve
459 // on a 16 KB SRAM LPC845. 192 edges covers the 1- and 3-LED
460 // sanity cases and fails the larger diagnostic cases without
461 // starving setup()/loop() stack.
462 constexpr fl::u32 kLowMemWs2812EdgeCapacity = 192u;
463 if (cap < 48u) cap = 48u;
464 if (cap > kLowMemWs2812EdgeCapacity) cap = kLowMemWs2812EdgeCapacity;
465 cfg.buffer_size = cap;
466 cfg.start_low = true;
467 if (!rx->begin(cfg)) return fl::string("0,0,0,0,0,0,0,0");
468
469 constexpr int kFixedTxPin = 10; // P0_10
470 if (tx_pin != kFixedTxPin) {
471 return fl::string("0,0,0,0,0,0,0,0");
472 }
473 if (!ws_state.fastled_initialized) {
474 FastLED.addLeds<WS2812, kFixedTxPin, GRB>(leds_buf, 100);
475 ws_state.fastled_initialized = true;
476 }
477 FastLED.show();
478 rx->wait(capture_ms);
479
480 uint8_t* decoded_buf = ws_state.decoded;
481 for (int i = 0; i < expected_bytes; ++i) decoded_buf[i] = 0;
482
486 /*reset_us=*/0u);
487
488 auto dec = rx->decode(timing, fl::span<u8>(decoded_buf, expected_bytes));
489 const fl::u32 decoded_bytes = dec.ok() ? dec.value() : 0u;
490
491 fl::u32 matched = 0;
492 fl::u32 mismatched = 0;
493 for (fl::u32 i = 0; i < decoded_bytes && i < (fl::u32)expected_bytes; ++i) {
494 if (decoded_buf[i] == expected_buf[i]) ++matched;
495 else ++mismatched;
496 }
497 const fl::u32 missing = (fl::u32)expected_bytes - decoded_bytes;
498 mismatched += missing;
499
500 // Diagnostic-only raw-edge sample. Keep this small in .bss; the
501 // decoder uses the RX channel's bounded capture vector above.
502 constexpr fl::size kLowMemWs2812ProbeSize = 64u;
503 fl::EdgeTime* probe = ws_state.probe;
504 const fl::size edges_captured = rx->getRawEdgeTimes(
505 fl::span<fl::EdgeTime>(probe, kLowMemWs2812ProbeSize));
506
507 const bool success = (mismatched == 0 && decoded_bytes == (fl::u32)expected_bytes);
508
509 fl::sstream s;
510 s << (success ? 1 : 0) << ',' << test_case << ',' << num_leds << ','
511 << expected_bytes << ',' << decoded_bytes << ','
512 << matched << ',' << mismatched << ','
513 << static_cast<fl::u32>(edges_captured);
514 return s.str();
515 });
516#endif // FASTLED_AUTORESEARCH_LPC_WS2812
517
518 // FastLED #3468: channels-API SCT+DMA clockless AutoResearch
519 // harness. Binds pwmDmaClFrameOnce / pwmDmaClFrameBurst /
520 // pwmDmaClCaptureSelf. Header self-gates on
521 // FL_IS_ARM_LPC_845 && FASTLED_LPC_PWM_DMA.
522#if defined(FL_IS_ARM_LPC_845) && defined(FASTLED_LPC_PWM_DMA)
523 autoresearch::pwm_dma_cl::bind(remote);
524#endif
525
526 // FastLED #3456: SPI+DMA async AutoResearch harness. Binds
527 // dmaSpiTransferOnce / dmaSpiTransferOverlap / dmaSpiMeasureSck.
528 // Header self-gates on FL_IS_ARM_LPC_845 && FASTLED_LPC_SPI_DMA.
529#if defined(FL_IS_ARM_LPC_845) && defined(FASTLED_LPC_SPI_DMA)
530 autoresearch::dma_spi::bind(remote);
531#endif
532
533 // #3453/#3611: UART DMA AutoResearch harness. Binds either the raw
534 // UART DMA stream bench or the clockless loopback verifier, depending
535 // on the build flags injected by `bash autoresearch`.
536#if defined(FL_IS_ARM_LPC_845) && FASTLED_AUTORESEARCH_LPC_UART_DMA
537 autoresearch::uart_dma::bind(remote);
538#endif
539
540#endif // FL_IS_ARM_LPC && !FASTLED_AUTORESEARCH_IEEE754_MODE
541}
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
JSON-RPC server with scheduling support.
Definition remote.h:42
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:864
string str() const FL_NO_EXCEPT
Definition strstream.h:43
constexpr EOrder GRB
Definition eorder.h:19
fl::CRGB CRGB
Definition crgb.h:25
#define FL_WARN_LIT(LITERAL)
Definition log.h:455
constexpr ChipsetTiming to_runtime_timing() FL_NO_EXCEPT
Convert enum-based timing type to runtime ChipsetTiming struct.
Definition led_timing.h:616
const dec_t dec
Definition ios.cpp.hpp:13
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:78
void serial_begin(u32 baudRate) FL_NO_EXCEPT
InputGamut g
Definition rgbw.h:125
void digitalWrite(int pin, PinValue val) FL_NO_EXCEPT
Write digital value to pin.
Definition pin.cpp.hpp:51
void pinMode(int pin, PinMode mode) FL_NO_EXCEPT
Set pin mode (input, output, pull-up, pull-down)
Definition pin.cpp.hpp:398
void delayMicroseconds(u32 us) FL_NO_EXCEPT
Delay for a given number of microseconds.
unsigned char uint8_t
Definition s16x16x4.h:209
4-phase RX timing thresholds for chipset detection
Definition rx.h:88
corkscrew_args args
Definition old.h:149
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

References args, fl::Watchdog::begin(), fl::RxConfig::buffer_size, FastLED, fl::Watchdog::feed(), FL_WARN_LIT, GRB, fl::Watchdog::instance(), fl::make4PhaseTiming(), fl::json::object(), autoresearch::low_memory::RemoteState::remote, remote, autoresearch::low_memory::remoteState(), autoresearch::ieee754_check::run(), fl::serial_begin(), fl::RxConfig::start_low, fl::sstream::str(), and fl::to_runtime_timing().

Referenced by setup().

+ Here is the call graph for this function:
+ Here is the caller graph for this function: