FastLED 3.10.8
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 460 of file manager.cpp.hpp.

460 {
461 const u32 startTime = timeoutMs > 0 ? millis() : 0;
462
463 // Tier 1: instant non-blocking check (avoid micros() / millis() cost on
464 // the common already-ready path).
465 if (condition()) {
466 return true;
467 }
468
469 // Tier 2: bounded microsecond spin (#2818). Catches short DMA tails
470 // (APA102 small strips, WS2812B <=8 LEDs) without paying the >=1-tick
471 // floor of the cooperator yield below. Budget is runtime-tunable via
472 // FastLED.setWaitSpinBudgetUs(N); set to 0 to disable.
473 {
474 const u32 spinBudget = fl::detail::getWaitSpinBudgetUs();
475 if (spinBudget > 0) {
476 const u32 spinStart = fl::micros();
477 while ((fl::micros() - spinStart) < spinBudget) {
478 if (condition()) {
479 return true;
480 }
481 if (timeoutMs > 0 && (millis() - startTime) >= timeoutMs) {
482 FL_ERROR("ChannelManager: Timeout occurred while waiting for condition");
483 return false;
484 }
485 }
486 }
487 }
488
489 while (!condition()) {
490 // Check timeout if specified
491 if (timeoutMs > 0 && (millis() - startTime >= timeoutMs)) {
492 FL_ERROR("ChannelManager: Timeout occurred while waiting for condition");
493 return false; // Timeout occurred
494 }
495
496 const u32 sliceMs = pollNeededWaitSliceMs(startTime, timeoutMs);
497 if (sliceMs == 0) {
498 return false;
499 }
500 if (waitForPollNeededSignal(sliceMs)) {
501 continue;
502 }
503
504 // Adaptive yield (refs #2815, generalizes the #2493 ESP32-P4 carve-out):
505 //
506 // The 1-tick (>=1 ms at CONFIG_FREERTOS_HZ=1000) floor only exists to
507 // keep WiFi / lwIP / BT controller tasks alive while we are inside the
508 // channel wait loop (#2254). When no radio is actually up, that floor
509 // is pure timing drift -- visible as the regression reported in #2420
510 // and as the per-frame cost the #2493 ESP32-P4 carve-out was avoiding.
511 //
512 // NetworkDetector::isAnyNetworkActive() is the runtime version of the
513 // "is a radio up?" question. On non-ESP32 platforms and on ESP32-P4
514 // (no radio silicon) it folds to a constant `false`, so this is
515 // strictly a perf win for the common single-strip / no-WiFi case
516 // without losing the WiFi-friendly behavior when a radio is active.
518 // Radio active: keep WiFi/lwIP/BT alive with the deep yield.
520 } else {
521 // No radio: fast yield, no FreeRTOS tick floor.
523 }
524 }
525
526 return true; // Condition met
527}
u32 pollNeededWaitSliceMs(u32 startTime, u32 timeoutMs) const FL_NO_EXCEPT
bool waitForPollNeededSignal(u32 timeoutMs) FL_NO_EXCEPT
static bool isAnyNetworkActive() FL_NO_EXCEPT
#define FL_ERROR(...)
Definition log.h:373
fl::u32 getWaitSpinBudgetUs() FL_NO_EXCEPT
Get the current tiered-wait spin budget (microseconds).
void yield_system(fl::u32 microseconds) FL_NO_EXCEPT
OS-level yield only: same behavior as run(us, ExecFlags::SYSTEM).
fl::u32 millis() FL_NO_EXCEPT
Universal millisecond timer - returns milliseconds since system startup.
fl::u32 micros() FL_NO_EXCEPT
Universal microsecond timer - returns microseconds since system startup.

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

Referenced by waitForReady(), and waitForReadyOrDraining().

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