FastLED 3.9.15
Loading...
Searching...
No Matches

◆ runTest()

void runTest ( const char * test_name,
fl::AutoResearchConfig & config,
int & total,
int & passed )

Definition at line 602 of file AutoResearchTest.cpp.

604 {
605 // Multi-lane limitation: Only test Lane 0 (first channel)
606 // Hardware constraint: Only one TX channel can be read from via RX loopback
607 size_t channels_to_test = config.tx_configs.size() > 1 ? 1 : config.tx_configs.size();
608
609 if (config.tx_configs.size() > 1) {
610 FL_WARN("\n[MULTI-LANE] Testing " << config.tx_configs.size() << " lanes, testing Lane 0 only (hardware limitation)");
611 }
612
613 // Test enabled configs (Lane 0 only for multi-lane)
614 for (size_t config_idx = 0; config_idx < channels_to_test; config_idx++) {
615 total++;
616
617 // Build test context for detailed error reporting
618 const auto& leds = config.tx_configs[config_idx].mLeds;
619 size_t num_leds = leds.size();
620
621 fl::TestContext ctx{
622 config.driver_name,
623 config.timing_name,
624 fl::toString(config.rx_type),
625 test_name,
626 static_cast<int>(config.tx_configs.size()),
627 static_cast<int>(config_idx),
628 config.base_strip_size,
629 static_cast<int>(num_leds),
630 config.tx_configs[config_idx].getDataPin()
631 };
632
633 FL_WARN("\n=== " << test_name << " [Lane " << config_idx << "/" << config.tx_configs.size()
634 << ", Pin " << config.tx_configs[config_idx].getDataPin()
635 << ", LEDs " << config.tx_configs[config_idx].mLeds.size() << "] ===");
636
637 // Use RX channel provided via config (created in .ino file, never created dynamically here)
638 if (!config.rx_channel) {
639 FL_ERROR("[" << ctx.driver_name << "/" << ctx.timing_name << "/" << ctx.pattern_name
640 << " | Lane " << ctx.lane_index << "/" << ctx.lane_count
641 << " (Pin " << ctx.pin_number << ", " << ctx.num_leds << " LEDs) | RX:" << ctx.rx_type_name << "] "
642 << "RX channel is null - must be created in .ino and passed via AutoResearchConfig");
643 FL_ERROR("Result: FAIL ✗ (RX channel not provided)");
644 continue;
645 }
646
647 size_t bytes_captured = capture(config.rx_channel, config.rx_buffer, config.timing, config.driver_name);
648
649 if (bytes_captured == 0) {
650 FL_ERROR("[" << ctx.driver_name << "/" << ctx.timing_name << "/" << ctx.pattern_name
651 << " | Lane " << ctx.lane_index << "/" << ctx.lane_count
652 << " (Pin " << ctx.pin_number << ", " << ctx.num_leds << " LEDs) | RX:" << ctx.rx_type_name << "] "
653 << "Result: FAIL ✗ (capture failed)");
654 continue;
655 }
656
657 int mismatches = 0;
658
659 if (isUCS7604(config.encoder)) {
660 // UCS7604: Compare full encoded frame (preamble + padding + pixel data) byte-for-byte
661 fl::vector<uint8_t> expected_encoded = buildExpectedUCS7604(
662 config.tx_configs[config_idx].mLeds, config.encoder);
663 size_t expected_len = expected_encoded.size();
664
665 FL_WARN("UCS7604 encoded comparison: expected " << expected_len << " bytes, captured " << bytes_captured);
666
667 size_t compare_len = (bytes_captured < expected_len) ? bytes_captured : expected_len;
668 for (size_t i = 0; i < compare_len; i++) {
669 if (expected_encoded[i] != config.rx_buffer[i]) {
670 mismatches++;
671 }
672 }
673 // Count any missing bytes as mismatches
674 if (bytes_captured < expected_len) {
675 mismatches += static_cast<int>(expected_len - bytes_captured);
676 }
677
678 FL_WARN("Bytes Captured: " << bytes_captured << " (expected: " << expected_len << ")");
679 int total_bytes = static_cast<int>(expected_len);
680 FL_WARN("Accuracy: " << (100.0 * (total_bytes - mismatches) / total_bytes) << "% ("
681 << (total_bytes - mismatches) << "/" << total_bytes << " bytes match)");
682 } else {
683 // WS2812: Compare raw RGB per-LED
684 size_t bytes_expected = num_leds * 3;
685
686 // NEVER EVER CHANGE THIS!!!!!
687 const size_t front_padding_bytes = 0; // No front padding: PARLIO FRONT_PAD_BYTES=0
688 const size_t rx_buffer_offset = front_padding_bytes;
689
690 if (bytes_captured > bytes_expected + front_padding_bytes) {
691 FL_WARN("Info: Captured " << bytes_captured << " bytes ("
692 << front_padding_bytes << " front pad + "
693 << bytes_expected << " LED data + "
694 << (bytes_captured - bytes_expected - front_padding_bytes) << " back pad/RESET)");
695 }
696
697 // Compare: byte-level comparison (COLOR_ORDER is RGB, so no reordering)
698 size_t bytes_to_check = (bytes_captured < bytes_expected + rx_buffer_offset) ?
699 (bytes_captured > rx_buffer_offset ? bytes_captured - rx_buffer_offset : 0) :
700 bytes_expected;
701 (void)bytes_to_check;
702
703 for (size_t i = 0; i < num_leds; i++) {
704 size_t byte_offset = rx_buffer_offset + i * 3; // Skip front padding
705 if (byte_offset + 2 >= bytes_captured) { // Check against total captured bytes
706 FL_ERROR("[" << ctx.driver_name << "/" << ctx.timing_name << "/" << ctx.pattern_name
707 << " | Lane " << ctx.lane_index << "/" << ctx.lane_count
708 << " (Pin " << ctx.pin_number << ", " << ctx.num_leds << " LEDs) | RX:" << ctx.rx_type_name << "] "
709 << "Incomplete data for LED[" << static_cast<int>(i)
710 << "] (only " << bytes_captured << " bytes captured)");
711 break;
712 }
713
714 uint8_t expected_r = leds[i].r;
715 uint8_t expected_g = leds[i].g;
716 uint8_t expected_b = leds[i].b;
717
718 uint8_t actual_r = config.rx_buffer[byte_offset + 0];
719 uint8_t actual_g = config.rx_buffer[byte_offset + 1];
720 uint8_t actual_b = config.rx_buffer[byte_offset + 2];
721
722 if (expected_r != actual_r || expected_g != actual_g || expected_b != actual_b) {
723 mismatches++;
724 }
725 }
726
727 FL_WARN("Bytes Captured: " << bytes_captured << " (expected: " << bytes_expected << ")");
728 FL_WARN("Accuracy: " << (100.0 * (num_leds - mismatches) / num_leds) << "% ("
729 << (num_leds - mismatches) << "/" << num_leds << " LEDs match)");
730 }
731
732 if (mismatches == 0) {
733 FL_WARN("Result: PASS ✓");
734 passed++;
735 } else {
736 FL_ERROR("[" << ctx.driver_name << "/" << ctx.timing_name << "/" << ctx.pattern_name
737 << " | Lane " << ctx.lane_index << "/" << ctx.lane_count
738 << " (Pin " << ctx.pin_number << ", " << ctx.num_leds << " LEDs) | RX:" << ctx.rx_type_name << "] "
739 << "Result: FAIL ✗");
740 }
741 }
742}
fl::CRGB leds[NUM_LEDS]
static bool isUCS7604(fl::ClocklessEncoder encoder)
Check if an encoder selector identifies a UCS7604 variant.
static fl::vector< uint8_t > buildExpectedUCS7604(fl::span< CRGB > leds, fl::ClocklessEncoder encoder)
Build expected UCS7604 encoded bytes from LED data.
size_t capture(fl::shared_ptr< fl::RxChannel > rx_channel, fl::span< uint8_t > rx_buffer, const fl::ChipsetTimingConfig &timing, const char *driver_name)
constexpr fl::size size() const FL_NOEXCEPT
Definition span.h:458
fl::size size() const FL_NOEXCEPT
#define FL_WARN(X)
Definition log.h:276
#define FL_ERROR(X)
Definition log.h:219
const char * toString(RxDeviceType type) FL_NOEXCEPT
Convert RxDeviceType to human-readable string.
Definition rx.h:177
unsigned char uint8_t
Definition s16x16x4.h:209
Test context for detailed error reporting Aggregates all test configuration parameters for error mess...
const fl::ChipsetTimingConfig & timing
Chipset timing configuration to test.
fl::RxDeviceType rx_type
RX device type (RMT or ISR)
const char * timing_name
Timing name for logging (e.g., "WS2812B-V5")
const char * driver_name
Driver name for logging (e.g., "RMT", "SPI", "PARLIO")
int base_strip_size
Base strip size (10 or 300 LEDs)
fl::span< fl::ChannelConfig > tx_configs
TX channel configurations to test (mutable for LED manipulation)
fl::ClocklessEncoder encoder
Encoder selector (peer of timing; see issue #2467)
fl::shared_ptr< fl::RxChannel > rx_channel
RX channel for loopback capture (created in .ino, passed in)
fl::span< uint8_t > rx_buffer
Buffer to store received bytes.

References fl::AutoResearchConfig::base_strip_size, buildExpectedUCS7604(), capture(), fl::AutoResearchConfig::driver_name, fl::AutoResearchConfig::encoder, FL_ERROR, FL_WARN, isUCS7604(), leds, fl::AutoResearchConfig::rx_buffer, fl::AutoResearchConfig::rx_channel, fl::AutoResearchConfig::rx_type, fl::span< T, Extent >::size(), fl::vector_basic::size(), fl::AutoResearchConfig::timing, fl::AutoResearchConfig::timing_name, fl::toString(), and fl::AutoResearchConfig::tx_configs.

+ Here is the call graph for this function: