604 {
605
606
608
610 FL_WARN(
"\n[MULTI-LANE] Testing " << config.
tx_configs.
size() <<
" lanes, testing Lane 0 only (hardware limitation)");
611 }
612
613
614 for (size_t config_idx = 0; config_idx < channels_to_test; config_idx++) {
615 total++;
616
617
619 size_t num_leds =
leds.size();
620
625 test_name,
627 static_cast<int>(config_idx),
629 static_cast<int>(num_leds),
631 };
632
634 <<
", Pin " << config.
tx_configs[config_idx].getDataPin()
635 <<
", LEDs " << config.
tx_configs[config_idx].mLeds.
size() <<
"] ===");
636
637
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
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
660
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
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
684 size_t bytes_expected = num_leds * 3;
685
686
687 const size_t front_padding_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
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;
705 if (byte_offset + 2 >= bytes_captured) {
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
717
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) {
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}
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
fl::size size() const FL_NOEXCEPT
const char * toString(RxDeviceType type) FL_NOEXCEPT
Convert RxDeviceType to human-readable string.
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.