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

◆ waitForCondition()

template<typename Condition>
bool fl::ChannelManager::waitForCondition ( Condition condition,
u32 timeoutMs = 1000 )
private

Wait until a condition is met, with check-pump-delay logic.

Parameters
conditionFunction that returns true when waiting should stop
timeoutMsOptional timeout in milliseconds (0 = no timeout)
Returns
true if condition was met, false if timeout occurred
Note
Runs async_run() on each iteration and delays intelligently to avoid busy-waiting

Definition at line 424 of file manager.cpp.hpp.

424 {
425 const u32 startTime = timeoutMs > 0 ? millis() : 0;
426
427 // Tier 1: instant non-blocking check (avoid micros() / millis() cost on
428 // the common already-ready path).
429 if (condition()) {
430 return true;
431 }
432
433 // Tier 2: bounded microsecond spin (#2818). Catches short DMA tails
434 // (APA102 small strips, WS2812B <=8 LEDs) without paying the >=1-tick
435 // floor of the cooperator yield below. Budget is runtime-tunable via
436 // FastLED.setWaitSpinBudgetUs(N); set to 0 to disable.
437 {
438 const u32 spinBudget = fl::detail::getWaitSpinBudgetUs();
439 if (spinBudget > 0) {
440 const u32 spinStart = fl::micros();
441 while ((fl::micros() - spinStart) < spinBudget) {
442 if (condition()) {
443 return true;
444 }
445 if (timeoutMs > 0 && (millis() - startTime) >= timeoutMs) {
446 FL_ERROR("ChannelManager: Timeout occurred while waiting for condition");
447 return false;
448 }
449 }
450 }
451 }
452
453 while (!condition()) {
454 // Check timeout if specified
455 if (timeoutMs > 0 && (millis() - startTime >= timeoutMs)) {
456 FL_ERROR("ChannelManager: Timeout occurred while waiting for condition");
457 return false; // Timeout occurred
458 }
459
460 const u32 sliceMs = pollNeededWaitSliceMs(startTime, timeoutMs);
461 if (sliceMs == 0) {
462 return false;
463 }
464 if (waitForPollNeededSignal(sliceMs)) {
465 continue;
466 }
467
468 // Adaptive yield (refs #2815, generalizes the #2493 ESP32-P4 carve-out):
469 //
470 // The 1-tick (>=1 ms at CONFIG_FREERTOS_HZ=1000) floor only exists to
471 // keep WiFi / lwIP / BT controller tasks alive while we are inside the
472 // channel wait loop (#2254). When no radio is actually up, that floor
473 // is pure timing drift -- visible as the regression reported in #2420
474 // and as the per-frame cost the #2493 ESP32-P4 carve-out was avoiding.
475 //
476 // NetworkDetector::isAnyNetworkActive() is the runtime version of the
477 // "is a radio up?" question. On non-ESP32 platforms and on ESP32-P4
478 // (no radio silicon) it folds to a constant `false`, so this is
479 // strictly a perf win for the common single-strip / no-WiFi case
480 // without losing the WiFi-friendly behavior when a radio is active.
482 // Radio active: keep WiFi/lwIP/BT alive with the deep yield.
484 } else {
485 // No radio: fast yield, no FreeRTOS tick floor.
487 }
488 }
489
490 return true; // Condition met
491}
bool waitForPollNeededSignal(u32 timeoutMs) FL_NOEXCEPT
u32 pollNeededWaitSliceMs(u32 startTime, u32 timeoutMs) const FL_NOEXCEPT
static bool isAnyNetworkActive() FL_NOEXCEPT
#define FL_ERROR(X)
Definition log.h:219
fl::u32 getWaitSpinBudgetUs() FL_NOEXCEPT
Get the current tiered-wait spin budget (microseconds).
void run(fl::u32 microseconds, ExecFlags flags)
Run selected task subsystems.
fl::u32 millis()
Universal millisecond timer - returns milliseconds since system startup.
fl::u32 micros()
Universal microsecond timer - returns microseconds since system startup.

References FL_ERROR, fl::detail::getWaitSpinBudgetUs(), fl::net::NetworkDetector::isAnyNetworkActive(), fl::micros(), fl::millis(), pollNeededWaitSliceMs(), fl::task::run(), fl::task::SYSTEM, and waitForPollNeededSignal().

Referenced by waitForReady(), and waitForReadyOrDraining().

+ Here is the call graph for this function:
+ Here is the caller graph for this function: