205#if defined(FL_IS_ARM_LPC) && !defined(FASTLED_AUTORESEARCH_IEEE754_MODE) && \
206 !defined(FASTLED_AUTORESEARCH_FAULT_TEST)
210struct LowMemPinTogglePeriodStats {
218inline LowMemPinTogglePeriodStats computeLowMemPeriodStats(
220 LowMemPinTogglePeriodStats s{0, 0, 0, 0, 0};
223 fl::u32 min_ns = 0xFFFFFFFFu;
226 for (fl::size i = 0; i + 1 < edge_count; i += 2) {
227 const fl::u32 period_ns =
228 static_cast<fl::u32
>(edges[i].
ns) +
229 static_cast<fl::u32
>(edges[i + 1].ns);
230 if (period_ns == 0)
continue;
232 sum_sq +=
static_cast<fl::u64>(period_ns) *
static_cast<fl::u64>(period_ns);
233 if (period_ns < min_ns) min_ns = period_ns;
234 if (period_ns > max_ns) max_ns = period_ns;
237 if (count == 0)
return s;
238 const fl::u32 mean =
static_cast<fl::u32
>(sum /
static_cast<fl::u64>(count));
240 const fl::u64 var = (sum_sq /
static_cast<fl::u64>(count)) - (mean64 * mean64);
242 while (
static_cast<fl::u64>(sig + 1) *
static_cast<fl::u64>(sig + 1) <= var) ++sig;
246 s.min_ns = (min_ns == 0xFFFFFFFFu) ? 0u : min_ns;
252#if defined(FL_IS_ARM_LPC_845) && defined(FASTLED_AUTORESEARCH_FAULT_TEST)
254 volatile fl::u32*
const p =
255 reinterpret_cast<volatile fl::u32*
>(0u);
263 volatile fl::u8 pad[64] = {0};
264 pad[
static_cast<fl::u8>(depth) & 0x3Fu] =
static_cast<fl::u8>(depth);
269 triggerLowMemoryNullFault();
271 return recurseLowMemoryStackBlow(depth + 1) + pad[depth & 0x3F];
294 remote.bind(
"echo", [](
int v) ->
int {
299#if defined(FL_IS_ARM_LPC_845) && defined(FASTLED_AUTORESEARCH_FAULT_TEST)
300 remote.bind(
"trigger_oom", []() ->
bool {
304 volatile char*
const p =
new char[16UL * 1024UL * 1024UL];
306 triggerLowMemoryNullFault();
309 triggerLowMemoryNullFault();
312 remote.bind(
"trigger_stackblow", []() ->
bool {
313 (void)recurseLowMemoryStackBlow(0);
314 triggerLowMemoryNullFault();
319#if defined(FL_IS_ESP8266)
320 autoresearch::esp8266::bindEsp8266Benches(
remote);
323#if defined(FASTLED_AUTORESEARCH_IEEE754_MODE)
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));
338#if defined(FL_IS_ARM_LPC) && !defined(FASTLED_AUTORESEARCH_IEEE754_MODE) && \
339 !defined(FASTLED_AUTORESEARCH_FAULT_TEST)
342#if !defined(FASTLED_AUTORESEARCH_LPC_DMA_LOOPBACK)
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) {
351 const fl::u32 expected_edges =
352 2u *
static_cast<fl::u32
>(freq_hz) *
353 static_cast<fl::u32
>(duration_ms) / 1000u;
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;
364 auto rx = fl::LpcSctRxChannel::create(rx_pin);
370 if (!rx->begin(cfg))
return fl::string(
"0,0,0,0,0,0,0");
372 pinMode(tx_pin, OUTPUT);
373 digitalWrite(tx_pin, LOW);
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;
379 for (fl::u32 i = 0; i < cycles; ++i) {
380 digitalWrite(tx_pin, HIGH);
381 delayMicroseconds(half_us);
383 digitalWrite(tx_pin, LOW);
384 delayMicroseconds(half_us);
386 if ((i & 0x7Fu) == 0u) {
394 fl::EdgeTime* edges_buf = autoresearch::low_memory::pinToggleState().edges;
395 const fl::size n_read = rx->getRawEdgeTimes(
398 LowMemPinTogglePeriodStats stats = computeLowMemPeriodStats(edges_buf, n_read);
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;
409#if defined(FASTLED_AUTORESEARCH_LPC_WS2812)
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) {
419 case 1: num_leds = 3;
break;
420 case 4: num_leds = 100;
break;
421 default: num_leds = 1;
break;
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) {
428 case 0: leds_buf[i] =
CRGB(0xFF, 0x00, 0x00);
break;
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);
435 case 2: leds_buf[i] =
CRGB(0x00, 0x00, 0x00);
break;
436 case 3: leds_buf[i] =
CRGB(0xFF, 0xFF, 0xFF);
break;
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);
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;
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);
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");
469 constexpr int kFixedTxPin = 10;
470 if (tx_pin != kFixedTxPin) {
473 if (!ws_state.fastled_initialized) {
474 FastLED.addLeds<WS2812, kFixedTxPin,
GRB>(leds_buf, 100);
475 ws_state.fastled_initialized =
true;
478 rx->wait(capture_ms);
480 uint8_t* decoded_buf = ws_state.decoded;
481 for (
int i = 0; i < expected_bytes; ++i) decoded_buf[i] = 0;
488 auto dec = rx->decode(timing,
fl::span<u8>(decoded_buf, expected_bytes));
489 const fl::u32 decoded_bytes = dec.ok() ? dec.value() : 0u;
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;
497 const fl::u32 missing = (fl::u32)expected_bytes - decoded_bytes;
498 mismatched += missing;
502 constexpr fl::size kLowMemWs2812ProbeSize = 64u;
504 const fl::size edges_captured = rx->getRawEdgeTimes(
507 const bool success = (mismatched == 0 && decoded_bytes == (fl::u32)expected_bytes);
510 s << (success ? 1 : 0) <<
',' << test_case <<
',' << num_leds <<
','
511 << expected_bytes <<
',' << decoded_bytes <<
','
512 << matched <<
',' << mismatched <<
','
513 <<
static_cast<fl::u32
>(edges_captured);
522#if defined(FL_IS_ARM_LPC_845) && defined(FASTLED_LPC_PWM_DMA)
523 autoresearch::pwm_dma_cl::bind(
remote);
529#if defined(FL_IS_ARM_LPC_845) && defined(FASTLED_LPC_SPI_DMA)
530 autoresearch::dma_spi::bind(
remote);
536#if defined(FL_IS_ARM_LPC_845) && FASTLED_AUTORESEARCH_LPC_UART_DMA
537 autoresearch::uart_dma::bind(
remote);