@brief Run the PARLIO streaming functional test. @param base_tx_pin First PARLIO TX pin; lanes occupy [base_tx_pin .. base_tx_pin+num_lanes-1] @param num_lanes Number of PARLIO lanes (1-16). Use 16 to exercise BF1+pipe4. @param num_leds LEDs per lane. @param iterations Number of back-to-back show()+wait() cycles (capped at kMaxIterations). @param timeout_ms Per-iteration timeout. Test
| 92 | /// @param timeout_ms Per-iteration timeout. Test fails if any iter exceeds this. |
| 93 | /// @param tx_pins Optional explicit per-lane pins. If null, uses contiguous base_tx_pin+lane. |
| 94 | inline ValidateResult validateParlioStreaming(int base_tx_pin, |
| 95 | int num_lanes, |
| 96 | int num_leds, |
| 97 | int iterations, |
| 98 | uint32_t timeout_ms, |
| 99 | const int* tx_pins = nullptr) { |
| 100 | ValidateResult r{}; |
| 101 | r.channels_ok = false; |
| 102 | r.completed = false; |
| 103 | r.explicit_tx_pins = tx_pins != nullptr; |
| 104 | r.base_tx_pin = base_tx_pin; |
| 105 | r.lanes = num_lanes; |
| 106 | r.leds_per_lane = num_leds; |
| 107 | r.iterations = iterations; |
| 108 | r.timeout_ms = timeout_ms; |
| 109 | r.failed_iter = -1; |
| 110 | for (int lane = 0; lane < kMaxLanes; ++lane) { |
| 111 | r.tx_pins[lane] = -1; |
| 112 | } |
| 113 | |
| 114 | if (iterations < 1) iterations = 1; |
| 115 | if (iterations > kMaxIterations) iterations = kMaxIterations; |
| 116 | r.iterations = iterations; |
| 117 | if (!tx_pins && base_tx_pin < 0) return r; |
| 118 | if (num_lanes < 1 || num_lanes > 16) return r; |
| 119 | if (num_leds < 1) return r; |
| 120 | if (tx_pins) { |
| 121 | base_tx_pin = tx_pins[0]; |
| 122 | r.base_tx_pin = base_tx_pin; |
| 123 | for (int lane = 0; lane < num_lanes; ++lane) { |
| 124 | if (tx_pins[lane] < 0) return r; |
| 125 | } |
| 126 | } |
| 127 | |
| 128 | #if defined(ARDUINO_ARCH_ESP32) || defined(ESP_PLATFORM) |
| 129 | // Reuse a single static heap-resident LED buffer sized for the canonical |
| 130 | // worst case (16 lanes × 256 LEDs). Test callers must stay within these |
| 131 | // bounds. Static to avoid repeated allocation across RPC calls. |
| 132 | constexpr int kMaxLEDs = 256; |
| 133 | if (num_leds > kMaxLEDs) return r; |
| 134 | static CRGB leds[kMaxLanes][kMaxLEDs]; |
| 135 | for (int lane = 0; lane < num_lanes; ++lane) { |
| 136 | for (int i = 0; i < num_leds; ++i) { |
| 137 | leds[lane][i] = CRGB(0xF0, 0x0F, 0xAA); // Pattern A (mixed bits) |
| 138 | } |
| 139 | } |
| 140 | |
| 141 | fl::ChipsetTimingConfig timing = |
| 142 | fl::makeTimingConfig<fl::TIMING_WS2812B_V5>(); |
| 143 | |
| 144 | fl::ChannelOptions parlio_opts; |
| 145 | parlio_opts.mBus = fl::Bus::PARLIO; |
| 146 | |
| 147 | FastLED.clear(ClearFlags::CHANNELS); |
| 148 | |
| 149 | fl::vector<fl::shared_ptr<fl::Channel>> channels; |
| 150 | for (int lane = 0; lane < num_lanes; ++lane) { |
| 151 | const int tx_pin = tx_pins ? tx_pins[lane] : (base_tx_pin + lane); |
no test coverage detected