278 {
280
281
283
284
285
287
288
289
290
291
292
294 remote.bind(
"echo", [](
int v) ->
int {
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
302
303
304 volatile char* const p = new char[16UL * 1024UL * 1024UL];
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
318
319#if defined(FL_IS_ESP8266)
320 autoresearch::esp8266::bindEsp8266Benches(
remote);
321#endif
322
323#if defined(FASTLED_AUTORESEARCH_IEEE754_MODE)
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));
335 });
336#endif
337
338#if defined(FL_IS_ARM_LPC) && !defined(FASTLED_AUTORESEARCH_IEEE754_MODE) && \
339 !defined(FASTLED_AUTORESEARCH_FAULT_TEST)
340
341
342#if !defined(FASTLED_AUTORESEARCH_LPC_DMA_LOOPBACK)
343
344
345
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) {
350 }
351 const fl::u32 expected_edges =
352 2u * static_cast<fl::u32>(freq_hz) *
353 static_cast<fl::u32>(duration_ms) / 1000u;
354
355
356
357
358
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);
366
370 if (!rx->begin(cfg))
return fl::string(
"0,0,0,0,0,0,0");
371
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) {
382 rx->pollOnce();
385 rx->pollOnce();
386 if ((i & 0x7Fu) == 0u) {
388 }
389 }
390 rx->wait(1);
391
392
393
394 fl::EdgeTime* edges_buf = autoresearch::low_memory::pinToggleState().edges;
395 const fl::size n_read = rx->getRawEdgeTimes(
397
398 LowMemPinTogglePeriodStats stats = computeLowMemPeriodStats(edges_buf, n_read);
399
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;
406 });
407#endif
408
409#if defined(FASTLED_AUTORESEARCH_LPC_WS2812)
410
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) {
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");
456 const fl::u32 expected_edges = (fl::u32)num_leds * 24u * 2u;
457 fl::u32 cap = expected_edges + (expected_edges / 2u);
458
459
460
461
462 constexpr fl::u32 kLowMemWs2812EdgeCapacity = 192u;
463 if (cap < 48u) cap = 48u;
464 if (cap > kLowMemWs2812EdgeCapacity) cap = kLowMemWs2812EdgeCapacity;
467 if (!rx->begin(cfg))
return fl::string(
"0,0,0,0,0,0,0,0");
468
469 constexpr int kFixedTxPin = 10;
470 if (tx_pin != kFixedTxPin) {
472 }
473 if (!ws_state.fastled_initialized) {
474 FastLED.addLeds<WS2812, kFixedTxPin,
GRB>(leds_buf, 100);
475 ws_state.fastled_initialized = true;
476 }
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 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
501
502 constexpr fl::size kLowMemWs2812ProbeSize = 64u;
504 const fl::size edges_captured = rx->getRawEdgeTimes(
506
507 const bool success = (mismatched == 0 && decoded_bytes == (fl::u32)expected_bytes);
508
510 s << (
success ? 1 : 0) <<
',' << test_case <<
',' << num_leds <<
','
511 << expected_bytes << ',' << decoded_bytes << ','
512 << matched << ',' << mismatched << ','
513 << static_cast<fl::u32>(edges_captured);
515 });
516#endif
517
518
519
520
521
522#if defined(FL_IS_ARM_LPC_845) && defined(FASTLED_LPC_PWM_DMA)
523 autoresearch::pwm_dma_cl::bind(
remote);
524#endif
525
526
527
528
529#if defined(FL_IS_ARM_LPC_845) && defined(FASTLED_LPC_SPI_DMA)
530 autoresearch::dma_spi::bind(
remote);
531#endif
532
533
534
535
536#if defined(FL_IS_ARM_LPC_845) && FASTLED_AUTORESEARCH_LPC_UART_DMA
537 autoresearch::uart_dma::bind(
remote);
538#endif
539
540#endif
541}
FL_DISABLE_WARNING_PUSH FL_DISABLE_WARNING_GLOBAL_CONSTRUCTORS CFastLED FastLED
Global LED strip management instance.
fl::unique_ptr< fl::Remote > remote
JSON-RPC server with scheduling support.
static Watchdog & instance() FL_NO_EXCEPT
void begin(fl::u32 timeout_ms) FL_NO_EXCEPT
static json object() FL_NO_EXCEPT
string str() const FL_NO_EXCEPT
#define FL_WARN_LIT(LITERAL)
RemoteState & remoteState()
constexpr ChipsetTiming to_runtime_timing() FL_NO_EXCEPT
Convert enum-based timing type to runtime ChipsetTiming struct.
ChipsetTiming4Phase make4PhaseTiming(const ChipsetTiming &timing_3phase, u32 tolerance_ns) FL_NO_EXCEPT
Create 4-phase RX timing from 3-phase chipset timing with tolerance.
void serial_begin(u32 baudRate) FL_NO_EXCEPT
void digitalWrite(int pin, PinValue val) FL_NO_EXCEPT
Write digital value to pin.
void pinMode(int pin, PinMode mode) FL_NO_EXCEPT
Set pin mode (input, output, pull-up, pull-down)
void delayMicroseconds(u32 us) FL_NO_EXCEPT
Delay for a given number of microseconds.
4-phase RX timing thresholds for chipset detection
Universal edge timing representation (platform-agnostic)
size_t buffer_size
Buffer size in symbols/edges (default: 512)
bool start_low
Pin idle state: true=LOW (WS2812B), false=HIGH (inverted)
Configuration for RX device initialization.