FastLED 3.10.8
Loading...
Searching...
No Matches
FastLED.cpp.hpp
Go to the documentation of this file.
1#define FASTLED_INTERNAL
2// IWYU pragma: begin_keep
3#include <stdint.h>
4// IWYU pragma: end_keep // for u8, u32, u16
5#include "FastLED.h" // ok include: this file implements CFastLED, declared in FastLED.h
12#include "fl/channels/manager.h"
15#include "fl/system/trace.h"
16#include "fl/channels/driver.h" // for IChannelDriver
17#include "fl/channels/detail/wait_spin_budget.h" // for tiered-wait spin-budget setters (#2818)
18#include "fl/system/delay.h" // for delayMicroseconds
19#include "fl/system/yield.h" // for fl::yield
21#if SKETCH_HAS_LARGE_MEMORY
22#include "fl/task/executor.h"
23#include "fl/net/network_detector.h" // adaptive yield gate in the refresh throttle (#3762)
24#endif
25#include "fl/log/log.h" // for FL_WARN
26#include "fl/stl/assert.h" // for FL_ASSERT
27#include "fl/audio/audio_manager.h" // for AudioManager
28#include "fl/ui/audio.h" // for UIAudio (CFastLED::add(UIAudio&))
29#include "hsv2rgb.h" // for CRGB
30#include "fl/stl/int.h" // for u32, u16
31#include "fl/stl/type_traits.h" // for conditional_t
32#include "platforms/init.h" // IWYU pragma: keep
33#include "fl/channels/config.h" // for ChannelConfig
34#include "fl/stl/singleton.h" // for fl::Singleton
35#include "platforms/is_platform.h"
36#include "fl/stl/noexcept.h"
37
40
41#ifndef MAX_CLED_CONTROLLERS
42#ifdef FL_IS_AVR
43// Uno/Nano-class (328P family) parts keep 8 slots to save RAM, as in 3.10.3;
44// larger ATmegas allow 16. Define MAX_CLED_CONTROLLERS to override (#4788).
45#if defined(FL_IS_AVR_ATMEGA) && !defined(FL_IS_AVR_ATMEGA_328P)
46#define MAX_CLED_CONTROLLERS 16
47#else
48#define MAX_CLED_CONTROLLERS 8
49#endif
50#else
51#define MAX_CLED_CONTROLLERS 64
52#endif // FL_IS_AVR
53#endif // MAX_CLED_CONTROLLERS
54
55#if defined(FL_IS_SAM)
56volatile fl::u32 fuckit;
57#endif
58
59
60#ifndef FASTLED_NO_ATEXIT
61#define FASTLED_NO_ATEXIT 0
62#endif
63
64#if !FASTLED_NO_ATEXIT
65extern "C" FL_LINK_WEAK int atexit(void (* /*func*/ )()) { return 0; }
66#endif
67
68#ifdef FASTLED_NEEDS_YIELD
69extern "C" void yield(void) { }
70#endif
71
72// Implementation of cled_contoller_size() moved to src/fl/fastled_internal.cpp
73
75
76#if !FL_PLATFORM_HAS_TINY_MEMORY
77// FL_LINT_ALLOW_GLOBAL(shared dither phase is required once per logical frame)
79
83#endif
84
87// FL_LINT_ALLOW_GLOBAL(extern ABI: smartmatrix_t3.h declares `extern SmartMatrix *pSmartMatrix`)
88void *pSmartMatrix = nullptr;
89
92
93CFastLED FastLED; // global constructor allowed in this case.
94
96
98static fl::u32 lastshow = 0;
99
102fl::u32 _frame_cnt=0;
103
106fl::u32 _retry_cnt=0;
107
108// uint32_t CRGB::Squant = ((uint32_t)((__TIME__[4]-'0') * 28))<<16 | ((__TIME__[6]-'0')*50)<<8 | ((__TIME__[7]-'0')*28);
109
111 // clear out the array of led controllers
112 // m_nControllers = 0;
113 mScale = 255;
114 mNFPS = 0;
115 mPPowerFunc = nullptr;
116 mNPowerData = 0xFFFFFFFF;
118 mLastShownScale = 255;
119 mMaxRefreshHz = 0;
120}
121
122#if FL_COLOR_PIPELINE_SHARED
123const fl::FramePowerDispatch*& fl::activeFramePowerDispatch() FL_NO_EXCEPT {
124 static const FramePowerDispatch* dispatch = nullptr;
125 return dispatch;
126}
127#endif
128
130 // Call platform-specific initialization once
131 // Uses the trampoline pattern: platforms/init.h dispatches to platform-specific headers
132 // FL_RUN_ONCE ensures this is only called once, even if init() is called multiple times
133 FL_RUN_ONCE(fl::platforms::init());
134}
135
137 return (*this)[0].size();
138}
139
141 return (*this)[0].leds();
142}
143
145 CRGB *data,
146 int nLedsOrOffset, int nLedsIfOffset) FL_NO_EXCEPT {
147 int nOffset = (nLedsIfOffset > 0) ? nLedsOrOffset : 0;
148 int nLeds = (nLedsIfOffset > 0) ? nLedsIfOffset : nLedsOrOffset;
149
150 pLed->init();
151 pLed->setLeds(data + nOffset, nLeds);
152 FastLED.setMaxRefreshRate(pLed->getMaxRefreshRate(),true);
153 fl::EngineEvents::onStripAdded(pLed, nLedsOrOffset - nOffset);
154 return *pLed;
155}
156
160
161#if FL_COLOR_PIPELINE_SHARED
162fl::shared_ptr<fl::StreamingPipelineQ16> fl::channelColorPipeline(
164 const fl::Channel* channel = controller.asChannel();
165 return channel != nullptr ? channel->colorPipeline()
167}
168#endif
169
172 PowerCodecPolicy policy;
174 for (fl::size i = 0; i < registered.size(); ++i) {
175 const fl::Channel* channel = registered[i].get();
176 if (channel != &controller) continue;
177 policy.kind = PowerCodecKind::Byte;
179 channel->getChipset().ptr<fl::SpiChipsetConfig>();
180 if (spi == nullptr) return policy;
181 switch (spi->timing.chipset) {
184 break;
187 break;
193 const fl::EmitterProfile* profile = channel->emitterProfile();
195 spi->timing.chipset, profile != nullptr
196 ? profile->five_bit_semantics
199 semantics, fl::detail::hdFieldFloor());
200 break;
201 }
202 default:
203 break;
204 }
205 return policy;
206 }
207 // A custom managed controller has no known wire encoding. Charging full
208 // code for every lit emitter is conservative, never a silent guess.
209 return policy;
210}
211
212void CFastLED::add(fl::ChannelPtr channel) FL_NO_EXCEPT {
213 if (!channel) {
214 return;
215 }
216 auto& chnls = channels();
217 // Protect against double-add
218 if (chnls.has(channel)) {
219 return;
220 }
221 chnls.push_back(channel);
222 // Add channel to the CLEDController linked list
223 // fl::Channel uses DeferRegister mode, so explicit addToDrawList() call is required
224 // Note: addToDrawList() now fires onChannelAdded event
225 channel->addToDrawList();
226}
227
228void CFastLED::remove(fl::ChannelPtr channel) FL_NO_EXCEPT {
229 if (!channel) {
230 return;
231 }
232 // Note: removeFromDrawList() now fires onChannelRemoved event
233 channel->removeFromDrawList();
234 // Remove from internal storage (safe if not found - erase is a no-op)
235 channels().erase(channel);
236}
237
239 // Lambda to check if flag is set, clear it, and return true if it was set
240 auto clearFlag = [&flags](ClearFlags flag) -> bool {
241 if ((flags & flag) != ClearFlags::NONE) {
242 flags = static_cast<ClearFlags>(static_cast<fl::u32>(flags) & ~static_cast<fl::u32>(flag));
243 return true;
244 }
245 return false;
246 };
247
248
249 // Reset POWER_SETTINGS - reset power management to defaults
250 if (clearFlag(ClearFlags::POWER_SETTINGS)) {
251 FastLED.mPPowerFunc = nullptr; // No power limiting function
252 FastLED.mNPowerData = 0xFFFFFFFF; // No power limit (max value)
253 FastLED.mLastRequestedScale = 255;
254 FastLED.mLastShownScale = 255;
255 }
256
257 // Reset BRIGHTNESS - reset global brightness to 255 (full brightness)
258 if (clearFlag(ClearFlags::BRIGHTNESS)) {
259 FastLED.mScale = 255;
260 }
261
262 // Reset REFRESH_RATE - reset refresh rate limiting to unlimited
263 if (clearFlag(ClearFlags::REFRESH_RATE)) {
264 FastLED.mMaxRefreshHz = 0; // No minimum delay between frames
265 }
266
267 // Reset FPS_COUNTER - reset FPS tracking counter to 0
268 if (clearFlag(ClearFlags::FPS_COUNTER)) {
269 FastLED.mNFPS = 0;
270 }
271
272 // Reset CHANNELS - remove all channels from controller list
273 if (clearFlag(ClearFlags::CHANNELS)) {
274 // Wait for engines to complete, with 2s timeout to prevent infinite hang
275 // if an engine is permanently stalled (e.g. PARLIO on ESP32-C6 hw bug)
276 FastLED.wait(2000);
277
278 // Remove all channels by iterating through a copy of the vector
279 // (we make a copy because remove() modifies channels())
280 fl::vector<fl::ChannelPtr> channelsCopy = channels();
281 for (auto& channel : channelsCopy) {
282 remove(channel);
283 }
284
285 // Reset bus manager state (clear enqueued and transmitting channels)
287 manager.reset();
288
289 // Clear the internal storage (should already be empty, but ensure it)
290 channels().clear();
291 }
292
293 // Reset CHANNEL_ENGINES - clear all registered channel drivers
294 if (clearFlag(ClearFlags::CHANNEL_ENGINES)) {
295 // Always wait for all channel bus transmissions to complete first
296 FastLED.wait();
298 manager.clearAllDrivers();
299 }
300
301 // Ensure all flags were handled - catches typos or missing implementations
302 FL_ASSERT(flags == ClearFlags::NONE, "Unhandled flags in FastLED.clear()");
303}
304
305// This is bad code. But it produces the smallest binaries for reasons
306// beyond mortal comprehensions.
307// Instead of iterating through the link list for onBeginFrame(), beginShowLeds()
308// and endShowLeds(): store the pointers in an array and iterate through that.
309//
310// static uninitialized gControllersData produces the smallest binary on attiny85.
311// FL_LINT_ALLOW_GLOBAL(intentional ATtiny85 code-size optimization — moving to Singleton<T> reverses the size win documented above)
313
314// Refresh-rate throttle shared by show() and showColor().
315//
316// This mirrors the tiered wait already shipped in
317// IChannelDriver::waitForCondition (refs #2818 for the spin tier, #2815/#2817
318// for the adaptive yield). show() was the last call site still taking an
319// UNCONDITIONAL deep yield, which is the root cause of FastLED#2994.
320//
321// Why it matters: fl::task::run(<non-zero>, SYSTEM) routes to
322// pumpCoroutines(), which on ESP32 floors at one FreeRTOS tick
323// (coroutine_esp32.impl.hpp, the `if (ticks == 0) ticks = 1` branch added for
324// the #2254 websocket-starvation fix). That is >=1 ms at
325// CONFIG_FREERTOS_HZ=1000 and >=10 ms at the 100 Hz default. With
326// setMaxRefreshRate(800) the throttle only needs 1250 us, so every frame
327// overshot to a tick boundary -- ~500 shows per sequence x sub-ms jitter is
328// the 63-300 ms drift reported in #2994, against a rock-steady 2495 ms on
329// 3.10.3 (which used a plain busy-wait).
330//
331// Two tiers:
332// - No radio up: taskYIELD() only. Equal-priority tasks still run, and there
333// is no tick floor, so the wait stays microsecond-accurate.
334// - Radio up: keep the deep yield -- WiFi/lwIP/BT genuinely need the CPU --
335// but stop taking it once less than the spin budget remains, so the final
336// stretch is spun out instead of overshooting past our deadline.
337static void throttleToMaxRefreshRate(fl::u32 minMicros) FL_NO_EXCEPT {
338 if (!minMicros) {
339 return;
340 }
341#if SKETCH_HAS_LARGE_MEMORY
342 const fl::u32 spinBudget = fl::detail::getWaitSpinBudgetUs();
343#endif
344 while (true) {
345 const fl::u32 elapsed = fl::micros() - lastshow;
346 if (elapsed >= minMicros) {
347 return;
348 }
349#if SKETCH_HAS_LARGE_MEMORY
350 const fl::u32 remaining = minMicros - elapsed;
351 // Deep yield only while a radio is up AND there is more than the spin
352 // budget left to burn. Once inside the budget we spin, because a deep
353 // yield costs a whole tick and would overshoot the deadline.
354 if (remaining > spinBudget && fl::NetworkDetector::isAnyNetworkActive()) {
356 } else {
357 // taskYIELD()-equivalent: equal-priority tasks still get CPU, but
358 // there is no FreeRTOS tick floor, so this stays sub-microsecond.
360 }
361#endif
362 }
363}
364
368
372
375 onBeginFrame();
378
380 // If we have a function for computing power, use it!
381 if(mPPowerFunc) {
382 scale = (*mPPowerFunc)(scale, mNPowerData);
383 }
385
386
387 // A byte index saves bookkeeping on 16-bit-int targets; retain wider limits.
388 using ControllerIndex = fl::conditional_t<
390 ControllerIndex length = 0;
392
393 while(pCur && length < MAX_CLED_CONTROLLERS) {
394 if (pCur->getEnabled()) {
395 gControllersData[length] = pCur->beginShowLeds(pCur->size());
396 } else {
397 gControllersData[length] = nullptr;
398 }
399 length++;
401 pCur = pCur->next();
402 }
403
404 pCur = CLEDController::head();
405 for (length = 0; length < MAX_CLED_CONTROLLERS && pCur; length++) {
406 if (pCur->getEnabled()) {
407 pCur->showLedsInternal(scale);
408 }
409 pCur = pCur->next();
410
411 }
412
413 length = 0; // Reset length to 0 and iterate again.
414 pCur = CLEDController::head();
415 while(pCur && length < MAX_CLED_CONTROLLERS) {
416 if (pCur->getEnabled()) {
418 }
419 length++;
420 pCur = pCur->next();
421 }
422 countFPS();
423 onEndFrame();
425}
426
430
432 int x = 0;
434 while( pCur) {
435 ++x;
436 pCur = pCur->next();
437 }
438 return x;
439}
440
443 while(x-- && pCur) {
444 pCur = pCur->next();
445 }
446 if(pCur == nullptr) {
447 return *(CLEDController::head());
448 } else {
449 return *pCur;
450 }
451}
452
454 onBeginFrame();
457
459 // If we have a function for computing power, use it!
460 if(mPPowerFunc) {
461 // showColor() encodes a constant, not controller source pixels; the
462 // source-frame managed prepass cannot model it.
463#if FL_COLOR_PIPELINE_SHARED
464 const fl::FramePowerDispatch* dispatch = fl::activeFramePowerDispatch();
465 scale = dispatch ? dispatch->showColorBrightness(scale, mNPowerData)
466 : (*mPPowerFunc)(scale, mNPowerData);
467#else
468 scale = (*mPPowerFunc)(scale, mNPowerData);
469#endif
470 }
472
473 int length = 0;
475 while(pCur && length < MAX_CLED_CONTROLLERS) {
476 if (pCur->getEnabled()) {
477 gControllersData[length] = pCur->beginShowLeds(pCur->size());
478 } else {
479 gControllersData[length] = nullptr;
480 }
481 length++;
482 pCur = pCur->next();
483 }
484
485 pCur = CLEDController::head();
486 while(pCur && length < MAX_CLED_CONTROLLERS) {
488 if (pCur->getEnabled()) {
489 pCur->showColorInternal(color, scale);
490 }
491 pCur = pCur->next();
492 }
493
494 pCur = CLEDController::head();
495 length = 0; // Reset length to 0 and iterate again.
496 while(pCur && length < MAX_CLED_CONTROLLERS) {
497 if (pCur->getEnabled()) {
499 }
500 length++;
501 pCur = pCur->next();
502 }
503 countFPS();
504 onEndFrame();
506}
507
508void CFastLED::clear(bool writeData) FL_NO_EXCEPT {
509 if(writeData) {
510 showColor(CRGB(0,0,0), 0);
511 }
512 clearData();
513}
514
517 while(pCur) {
518 pCur->clearLedDataInternal();
519 pCur = pCur->next();
520 }
521}
522
523void CFastLED::delay(unsigned long ms) FL_NO_EXCEPT {
524 unsigned long start = fl::millis();
525 do {
526#ifndef FASTLED_ACCURATE_CLOCK
527 // make sure to allow at least one ms to pass to ensure the clock moves
528 // forward
529 fl::delay(1);
530#endif
531 show();
532 fl::yield();
533 }
534 while((fl::millis()-start) < ms);
535}
536
539 while(pCur) {
540 pCur->setTemperature(temp);
541 pCur = pCur->next();
542 }
543}
544
545void CFastLED::setCorrection(const CRGB & correction) FL_NO_EXCEPT {
547 while(pCur) {
548 pCur->setCorrection(correction);
549 pCur = pCur->next();
550 }
551}
552
555 while(pCur) {
556 pCur->setDither(ditherMode);
557 pCur = pCur->next();
558 }
559}
560
563 min_field < 1 ? 1 : (min_field > 31 ? 31 : min_field);
564}
565
569
570fl::u32 CFastLED::getEstimatedPowerInMilliWatts(bool apply_limiter) const FL_NO_EXCEPT {
571#if FL_COLOR_PIPELINE_SHARED
572 if (apply_limiter && mPPowerFunc && fl::activeFramePowerDispatch()) {
573 bool managed = false;
574 for (CLEDController* p = CLEDController::head(); p; p = p->next()) {
575 if (p->getEnabled() && fl::channelColorPipeline(*p)) {
576 managed = true;
577 break;
578 }
579 }
580 if (managed) {
581 const fl::FramePowerPlan plan =
582 fl::activeFramePowerDispatch()->calculate(mScale, mNPowerData);
583 if (plan.modeled_mW == 0xFFFFFFFFu) return plan.modeled_mW;
584 const fl::u32 mcu_mW = plan.mcu_mW;
585 return plan.modeled_mW > mcu_mW ? plan.modeled_mW - mcu_mW : 0;
586 }
587 }
588#endif
589 fl::u32 fixed_power_mW = 0;
590 fl::u32 controllable_power_mW = 0;
591 fl::u32 dither_reserve_power_mW = 0;
592
593 // Sum unscaled power from all LED controllers using visitor pattern.
594 // The dark-current baseline is kept apart from the part brightness scales,
595 // because it is drawn at every brightness including zero (#4156 R4).
596 const fl::u32 dark_mW_per_led = get_power_model().dark_mW;
598 if (!leds.empty()) {
599 // The controller's own estimate: its RGBW setting, so an RGBW strip
600 // is charged for the diode it actually lights, and for a bound
601 // colour profile the solved drives rather than the source (#4344).
602 const fl::u32 unscaled_mW = controller_unscaled_power_mW(*controller);
603 const fl::u32 dark_mW = dark_mW_per_led * static_cast<fl::u32>(leds.size());
604 fixed_power_mW += dark_mW;
605 controllable_power_mW += unscaled_mW > dark_mW ? unscaled_mW - dark_mW : 0;
606 // What dithering can add on top, at any non-zero brightness (#4342).
607 // Not on TINY, where the bound costs more flash than the tier has
608 // to spare (#4478); controller_dither_reserve_mW is 0 there.
609#if !FL_PLATFORM_HAS_TINY_MEMORY
610 dither_reserve_power_mW += controller_dither_reserve_mW(*controller);
611#endif
612 }
613 });
614
615 // Determine effective brightness
616 fl::u8 effective_brightness = mScale;
617
618 if (apply_limiter && mPPowerFunc) {
619 // Power limiting is enabled and user wants limited power - calculate brightness after limiting
620 // This calls calculate_max_brightness_for_power_mW(mScale, mNPowerData)
621 effective_brightness = (*mPPowerFunc)(mScale, mNPowerData);
622 }
623
624 // Scale only the emitter share by the configured power-brightness response
625 // and add the baseline back, so the estimate matches what the limiter now
626 // budgets against.
627 // Note: MCU power consumption is NOT included - caller should add platform-specific MCU power if needed
628 // The dither reserve only at a non-zero brightness: nothing dithers at 0,
629 // the same as the limiter, whose answer of 0 needs no reserve either.
630 if (effective_brightness != 0) {
631 fixed_power_mW += dither_reserve_power_mW;
632 }
633 return fixed_power_mW +
634 scale_power_for_brightness(controllable_power_mW, effective_brightness);
635}
636
637//
638// template<int m, int n> void transpose8(unsigned char A[8], unsigned char B[8]) {
639// uint32_t x, y, t;
640//
641// // Load the array and pack it into x and y.
642// y = *(unsigned int*)(A);
643// x = *(unsigned int*)(A+4);
644//
645// // x = (A[0]<<24) | (A[m]<<16) | (A[2*m]<<8) | A[3*m];
646// // y = (A[4*m]<<24) | (A[5*m]<<16) | (A[6*m]<<8) | A[7*m];
647//
648 // // pre-transform x
649 // t = (x ^ (x >> 7)) & 0x00AA00AA; x = x ^ t ^ (t << 7);
650 // t = (x ^ (x >>14)) & 0x0000CCCC; x = x ^ t ^ (t <<14);
651 //
652 // // pre-transform y
653 // t = (y ^ (y >> 7)) & 0x00AA00AA; y = y ^ t ^ (t << 7);
654 // t = (y ^ (y >>14)) & 0x0000CCCC; y = y ^ t ^ (t <<14);
655 //
656 // // final transform
657 // t = (x & 0xF0F0F0F0) | ((y >> 4) & 0x0F0F0F0F);
658 // y = ((x << 4) & 0xF0F0F0F0) | (y & 0x0F0F0F0F);
659 // x = t;
660//
661// B[7*n] = y; y >>= 8;
662// B[6*n] = y; y >>= 8;
663// B[5*n] = y; y >>= 8;
664// B[4*n] = y;
665//
666// B[3*n] = x; x >>= 8;
667// B[2*n] = x; x >>= 8;
668// B[n] = x; x >>= 8;
669// B[0] = x;
670// // B[0]=x>>24; B[n]=x>>16; B[2*n]=x>>8; B[3*n]=x>>0;
671// // B[4*n]=y>>24; B[5*n]=y>>16; B[6*n]=y>>8; B[7*n]=y>>0;
672// }
673//
674// void transposeLines(Lines & out, Lines & in) {
675// transpose8<1,2>(in.bytes, out.bytes);
676// transpose8<1,2>(in.bytes + 8, out.bytes + 1);
677// }
678
679
682extern int noise_min;
683
686extern int noise_max;
687
689 static int br = 0;
690#if SKETCH_HAS_LARGE_MEMORY
691 typedef fl::u32 frame_ms_t;
692#else
693 // Wrapping 16-bit millis saves 2 B RAM; nFrames frames must take < 65 s (#4788).
694 typedef fl::u16 frame_ms_t;
695#endif
696 static frame_ms_t lastframe = 0; // fl::millis();
697
698 if(br++ >= nFrames) {
699 const frame_ms_t sample = static_cast<frame_ms_t>(fl::millis());
700 frame_ms_t now = static_cast<frame_ms_t>(sample - lastframe);
701 if(now == 0) {
702 now = 1; // prevent division by zero below
703 }
704 mNFPS = static_cast<fl::u16>((static_cast<fl::u32>(br) * 1000) / now);
705 br = 0;
706 lastframe = sample;
707 }
708}
709
710void CFastLED::setMaxRefreshRate(fl::u16 refresh, bool constrain) FL_NO_EXCEPT {
711 if(constrain) {
712 // When constraining we may only slow things down: keep the lower cap.
713 if(refresh > 0 && (mMaxRefreshHz == 0 || refresh < mMaxRefreshHz)) {
714 mMaxRefreshHz = refresh;
715 }
716 } else {
717 mMaxRefreshHz = refresh; // 0 = unlimited
718 }
719}
720
721
723 return FastLED.getBrightness();
724}
725
726// ============================================================================
727// Deprecated Power Management Wrapper Functions
728// ============================================================================
729// These functions wrap the CFastLED singleton methods for backward compatibility.
730// They were originally in power_mgt.cpp but have been moved here to avoid
731// circular dependencies (power_mgt.cpp should not include FastLED.h).
732
733void set_max_power_in_volts_and_milliamps(fl::u8 volts, fl::u32 milliamps)
735 FastLED.setMaxPowerInVoltsAndMilliamps(volts, milliamps);
736}
737
738void set_max_power_in_milliwatts(fl::u32 powerInmW)
740 FastLED.setMaxPowerInMilliWatts(powerInmW);
741}
742
745 // power management usage is now in FastLED.show, no need for this function
746 FastLED.show();
747}
748
751 FastLED.delay(ms);
752}
753
754// ============================================================================
755// Channel Bus Manager Controls
756// ============================================================================
757
761
762void CFastLED::setDriverEnabled(const char* name, bool enabled) FL_NO_EXCEPT {
764 manager.setDriverEnabled(name, enabled);
765}
766
769 return manager.setExclusiveDriver(bus, which);
770}
771
772bool CFastLED::isDriverEnabled(const char* name) const FL_NO_EXCEPT {
774 return manager.isDriverEnabled(name);
775}
776
779 return manager.getDriverCount();
780}
781
786
787// ============================================================================
788// Wait for channel bus transmissions
789// ============================================================================
790
793 // A zero timeout means wait indefinitely. The void API cannot report a
794 // timeout, so returning early would violate its completion contract.
795 manager.waitForReady(0);
796}
797
798bool CFastLED::wait(fl::u32 timeout_ms) FL_NO_EXCEPT {
800 return manager.waitForReady(timeout_ms);
801}
802
803// Tiered-wait spin-budget shims (#2818). Storage in
804// src/fl/channels/detail/wait_spin_budget.cpp.hpp.
808
812
813// ============================================================================
814// Runtime Channel API Implementation
815// ============================================================================
816
817fl::ChannelPtr CFastLED::add(const fl::ChannelConfig& config) FL_NO_EXCEPT {
818 // Issue #2459: the non-template `FastLED.add(cfg)` path is the runtime-
819 // selection mode. To make sure `cfg.options.mBus` (or priority dispatch
820 // when `mBus == Bus::AUTO`) can actually find the requested driver at
821 // runtime, we eagerly enroll every driver available on this platform.
822 // That trades binary size for ergonomics — the user wanted runtime
823 // selection, so they get runtime selection.
824 //
825 // For minimum binary size, callers should use the compile-time path:
826 // FastLED.addLeds<CHIPSET, PIN, ORDER, fl::Bus::X>(leds, n);
827 // which ODR-uses only `BusTraits<X>::instancePtr()` and lets
828 // `--gc-sections` drop every other driver TU.
829 //
830 // The warning fires at most once per process (FL_WARN_ONCE) and can be
831 // disabled with `-DFASTLED_SUPPRESS_RUNTIME_DRIVER_WARNING`.
832 #ifndef FASTLED_SUPPRESS_RUNTIME_DRIVER_WARNING
833 FL_WARN_ONCE("FastLED.add(cfg): runtime-selection mode — enrolling every "
834 "available driver via fl::enableAllDrivers(). For minimum "
835 "binary size, prefer FastLED.addLeds<CHIPSET, PIN, ORDER, "
836 "fl::Bus::X>(leds, n) which links only the named driver. "
837 "Suppress this warning with -DFASTLED_SUPPRESS_RUNTIME_DRIVER_WARNING.");
838 #endif
840
842 FL_ASSERT(manager.getDriverCount() > 0,
843 "No channel drivers available - channel API requires at least one registered driver");
844 auto channel = fl::Channel::create(config);
845 add(channel);
846 return channel;
847}
848
851 channels.reserve(configs.size());
852
853 for (const auto& config : configs) {
854 channels.push_back(add(config));
855 }
856
857 return channels;
858}
859
860fl::vector<fl::ChannelPtr> CFastLED::add(fl::initializer_list<fl::ChannelConfig> configs) FL_NO_EXCEPT {
862 channels.reserve(configs.size());
863
864 for (const auto& config : configs) {
865 channels.push_back(add(config));
866 }
867
868 return channels;
869}
870
873 channels.reserve(multiConfig.mChannels.size());
874
875 for (const auto& configPtr : multiConfig.mChannels) {
876 if (configPtr) {
877 channels.push_back(add(*configPtr));
878 }
879 }
880
881 return channels;
882}
883
884fl::RxChannelPtr CFastLED::addRx(const fl::RxChannelConfig& config) FL_NO_EXCEPT {
885 return fl::RxChannel::create(config);
886}
887
888// ============================================================================
889
890#ifdef NEED_CXX_BITS
891namespace __cxxabiv1
892{
893 #if !defined(FL_IS_ESP8266) && !defined(FL_IS_ESP32) && !defined(ARDUINO)
894 extern "C" void __cxa_pure_virtual (void) {}
895 #endif
896
897 /* guard variables */
898
899 /* The ABI requires a 64-bit type. */
900 __extension__ typedef int __guard __attribute__((mode(__DI__)));
901
902 extern "C" int __cxa_guard_acquire (__guard *) FL_LINK_WEAK;
903 extern "C" void __cxa_guard_release (__guard *) FL_LINK_WEAK;
904 extern "C" void __cxa_guard_abort (__guard *) FL_LINK_WEAK;
905
906 extern "C" int __cxa_guard_acquire (__guard *g)
907 {
908 return !*(char *)(g);
909 }
910
911 extern "C" void __cxa_guard_release (__guard *g)
912 {
913 *(char *)g = 1;
914 }
915
916 extern "C" void __cxa_guard_abort (__guard *)
917 {
918
919 }
920}
921#endif
922
923
927
928
930 #if FASTLED_HAS_ENGINE_EVENTS
932 #endif
933}
934
938
942
943// ============================================================================
944// CFastLED audio method implementations - thin trampolines to AudioManager
945// ============================================================================
946
951
956
961
int x
Definition simple.h:92
FastLED show()
#define MAX_CLED_CONTROLLERS
FL_LINK_WEAK int atexit(void(*)())
void * pSmartMatrix
Pointer to the matrix object when using the Smart Matrix Library.
fl::u8 get_brightness() FL_NO_EXCEPT
static fl::u32 lastshow
fl::u32 _retry_cnt
Global frame retry counter, used for debugging ESP implementations.
static void * gControllersData[MAX_CLED_CONTROLLERS]
FL_DISABLE_WARNING_PUSH FL_DISABLE_WARNING_GLOBAL_CONSTRUCTORS CFastLED FastLED
Global LED strip management instance.
int noise_max
Unused value.
static void throttleToMaxRefreshRate(fl::u32 minMicros) FL_NO_EXCEPT
fl::u32 _frame_cnt
Global frame counter, used for debugging ESP implementations.
int noise_min
Unused value.
CLEDController * controller
fl::UISlider scale("Scale", 4,.1, 4,.1)
Declaration of fl::enableAllDrivers() — enrolls every channel driver available on the current platfor...
#define FL_ASSERT(x, MSG)
Definition assert.h:6
ESP32-P4 Parallel IO (PARLIO) LED channel.
void clear(bool writeData=false) FL_NO_EXCEPT
Clear the leds, wiping the local array of data.
power_func mPPowerFunc
function for overriding brightness when using FastLED.show();
Definition FastLED.h:731
fl::u8 getHdFieldFloor() const FL_NO_EXCEPT
void setExclusiveDriver() FL_NO_EXCEPT
Register a single driver at a priority above the platform default (compile-time TU-linking variant).
Definition FastLED.h:1633
void setCorrection(const CRGB &correction) FL_NO_EXCEPT
Set a global color correction.
static void _setWaitSpinBudgetUs(fl::u32 budget_us) FL_NO_EXCEPT
static void add(fl::ChannelPtr channel) FL_NO_EXCEPT
Add a Channel-based LED controller (from ChannelPtr)
void show() FL_NO_EXCEPT
Update all our controllers with the current led colors.
Definition FastLED.h:1894
void setDriverEnabled(const char *name, bool enabled) FL_NO_EXCEPT
Enable or disable a channel driver by name at runtime.
CFastLED() FL_NO_EXCEPT
static fl::ChannelEvents & channelEvents() FL_NO_EXCEPT
Access the channel event system.
void countFPS(int nFrames=25) FL_NO_EXCEPT
For debugging, this will keep track of time between calls to countFPS().
void onEndShowLeds() FL_NO_EXCEPT
Manually trigger the end show LEDs event.
static fl::u32 _getWaitSpinBudgetUs() FL_NO_EXCEPT
static fl::Watchdog & watchdog() FL_NO_EXCEPT
Access the unified cross-platform watchdog timer.
static void remove(fl::ChannelPtr channel) FL_NO_EXCEPT
Remove a channel from the LED controller list.
int size() FL_NO_EXCEPT
Get the number of leds in the first controller.
void clearData() FL_NO_EXCEPT
Clear out the local data array.
void setDither(fl::u8 ditherMode=BINARY_DITHER) FL_NO_EXCEPT
Set the dithering mode.
fl::u8 getLastShowBrightness() const FL_NO_EXCEPT
Brightness the most recent show() / showColor() actually applied, after the power limiter set by setM...
static fl::vector< fl::ChannelPtr > & channels() FL_NO_EXCEPT
stored ChannelPtrs to keep them alive
void onBeginFrame() FL_NO_EXCEPT
Manually trigger the begin frame event.
void showColor(const CRGB &color, fl::u8 scale) FL_NO_EXCEPT
Set all leds on all controllers to the given color/scale.
void wait() FL_NO_EXCEPT
Wait for all channel bus transmissions to complete.
fl::u8 mScale
the current global brightness scale setting
Definition FastLED.h:727
void onEndFrame() FL_NO_EXCEPT
bool isPowerLimited() const FL_NO_EXCEPT
True if the power limiter lowered the brightness of the most recent show() / showColor() below what i...
CRGB * leds() FL_NO_EXCEPT
Get a pointer to led data for the first controller.
void delay(unsigned long ms) FL_NO_EXCEPT
Delay for the given number of milliseconds.
static fl::RxChannelPtr addRx(const fl::RxChannelConfig &config) FL_NO_EXCEPT
Add an RX channel with runtime configuration.
fl::u32 mNPowerData
max power use parameter
Definition FastLED.h:730
fl::u16 mNFPS
tracking for current frames per second (FPS) value
Definition FastLED.h:728
void setMaxRefreshRate(fl::u16 refresh, bool constrain=false) FL_NO_EXCEPT
Set the maximum refresh rate.
void init() FL_NO_EXCEPT
Initialize platform-specific subsystems.
fl::u8 mLastShownScale
brightness the last show()/showColor() applied, after the power limiter
Definition FastLED.h:733
void setTemperature(const CRGB &temp) FL_NO_EXCEPT
Set a global color temperature.
int count() FL_NO_EXCEPT
Get how many controllers have been registered.
fl::u8 mLastRequestedScale
brightness the last show()/showColor() was asked for
Definition FastLED.h:732
CLEDController & operator[](int x) FL_NO_EXCEPT
Get a reference to a registered controller.
::CLEDController & addLeds(::CLEDController *pLed, CRGB *data, int nLedsOrOffset, int nLedsIfOffset=0) FL_NO_EXCEPT
Add a CLEDController instance to the world.
fl::span< const fl::DriverInfo > getDriverInfos() const FL_NO_EXCEPT
Get full state of all registered channel drivers.
bool isDriverEnabled(const char *name) const FL_NO_EXCEPT
Check if a driver is enabled by name.
fl::u32 getEstimatedPowerInMilliWatts(bool apply_limiter=true) const FL_NO_EXCEPT
Get estimated power consumption in milliwatts.
void setHdFieldFloor(fl::u8 min_field) FL_NO_EXCEPT
Lowest 5-bit current field the colour-managed APA102-HD path may use (B1's flicker floor,...
fl::size getDriverCount() const FL_NO_EXCEPT
Get count of registered channel drivers.
static void enableAllDrivers() FL_NO_EXCEPT
Enroll every channel driver available on this platform with ChannelManager.
fl::u16 mMaxRefreshHz
frame-rate cap in Hz, 0 = unlimited (u16 saves 2 B over micros, #4788)
Definition FastLED.h:729
and refresh rates, and provides access functions for driving led data to controllers via the show() /...
Definition FastLED.h:723
void showColorInternal(const CRGB &data, int nLeds, fl::u8 brightness) FL_NO_EXCEPT
void showLedsInternal(fl::u8 brightness) FL_NO_EXCEPT
Write the data to the LEDs managed by this controller.
static void visitControllers(Visitor &&visitor) FL_NO_EXCEPT
Visit all controllers in the linked list with a visitor The visitor must be a callable that accepts (...
CLEDController & setTemperature(CRGB temperature) FL_NO_EXCEPT
Set the color temperature, aka white point, for this controller.
void clearLedDataInternal(int nLeds=-1) FL_NO_EXCEPT
Zero out the LED data managed by this controller.
static CLEDController * head() FL_NO_EXCEPT
Get the first LED controller in the linked list of controllers.
bool getEnabled() FL_NO_EXCEPT
VIRTUAL_IF_NOT_AVR void * beginShowLeds(int size) FL_NO_EXCEPT
VIRTUAL_IF_NOT_AVR int size() const FL_NO_EXCEPT
How many LEDs does this controller manage?
VIRTUAL_IF_NOT_AVR void endShowLeds(void *data) FL_NO_EXCEPT
CLEDController & setDither(fl::u8 ditherMode=BINARY_DITHER) FL_NO_EXCEPT
Set the dithering mode for this controller to use.
static CLEDController * mPHead
pointer to the first LED controller in the linked list
CLEDController * next() FL_NO_EXCEPT
Get the next controller in the linked list after this one.
CLEDController & setCorrection(CRGB correction) FL_NO_EXCEPT
The color corrction to use for this controller, expressed as a CRGB object.
void removeFromDrawList() FL_NO_EXCEPT
Remove this channel from the global controller draw list.
const EmitterProfile * emitterProfile() const FL_NO_EXCEPT
Definition channel.h:233
void addToDrawList() FL_NO_EXCEPT
Add this channel to the global controller draw list.
const ChipsetVariant & getChipset() const FL_NO_EXCEPT
Get the chipset configuration variant.
Definition channel.h:136
LED channel for parallel output, pretty much a CPixelLEDController but with timing and pin informatio...
Definition channel.h:60
void setDriverEnabled(const char *name, bool enabled) FL_NO_EXCEPT
Enable or disable a driver by name at runtime.
void reset() FL_NO_EXCEPT
Reset bus manager state, clearing all enqueued and transmitting channels.
fl::size getDriverCount() const FL_NO_EXCEPT
Get count of registered drivers (including unnamed ones)
void clearAllDrivers() FL_NO_EXCEPT
Remove all drivers from the manager.
void setExclusiveDriver() FL_NO_EXCEPT
Register a single driver at a priority above the platform default and disable all others (compile-tim...
Definition manager.h:362
bool isDriverEnabled(const char *name) const FL_NO_EXCEPT
Check if a driver is enabled by name.
bool waitForReady(u32 timeoutMs=1000) FL_NO_EXCEPT
Wait for all drivers to become READY.
fl::span< const DriverInfo > getDriverInfos() const FL_NO_EXCEPT
Get full state of all registered drivers.
Unified channel manager with priority-based driver selection.
Definition manager.h:51
static void onBeginFrame() FL_NO_EXCEPT
static void onStripAdded(CLEDController *strip, fl::u32 num_leds) FL_NO_EXCEPT
static void onEndShowLeds() FL_NO_EXCEPT
static void onEndFrame() FL_NO_EXCEPT
static RxChannelPtr create(const RxChannelConfig &config) FL_NO_EXCEPT
static Watchdog & instance() FL_NO_EXCEPT
Unified cross-platform watchdog interface.
Definition watchdog.h:123
void remove(shared_ptr< Processor > processor) FL_NO_EXCEPT
static AudioManager & instance() FL_NO_EXCEPT
shared_ptr< Processor > add(const Config &config) FL_NO_EXCEPT
static bool isAnyNetworkActive() FL_NO_EXCEPT
fl::size size() const FL_NO_EXCEPT
fl::CLEDController CLEDController
#define FL_DISABLE_WARNING_GLOBAL_CONSTRUCTORS
#define FL_DISABLE_WARNING_PUSH
#define FL_KEEP_ALIVE
#define FL_RUN_ONCE(code)
#define FL_DISABLE_WARNING_POP
#define FL_MAYBE_UNUSED
#define FL_LINK_WEAK
Delay utilities for FastLED Includes nanosecond-precision delays, cycle counting, and microsecond del...
fl::UISlider length("Length", 1.0f, 0.0f, 1.0f, 0.01f)
Task executor — runs registered task runners and manages the run loop.
ClearFlags
Flags for FastLED.clear() to control what state gets cleared/reset.
Definition FastLED.h:666
@ CHANNELS
Remove all channels from controller list.
Definition FastLED.h:668
@ BRIGHTNESS
Reset global brightness to 255.
Definition FastLED.h:670
@ CHANNEL_ENGINES
Clear all channel drivers from ChannelManager.
Definition FastLED.h:673
@ POWER_SETTINGS
Reset power management (setMaxPowerInMilliWatts)
Definition FastLED.h:669
@ FPS_COUNTER
Reset FPS tracking counter to 0.
Definition FastLED.h:672
@ NONE
Clear nothing (no-op)
Definition FastLED.h:667
@ REFRESH_RATE
Reset refresh rate limiting to unlimited.
Definition FastLED.h:671
#define FL_DITHER_ENABLE_MIN_REFRESH_HZ
High level controller interface for FastLED.
Definition FastLED.h:717
CFastLED FastLED
Global LED strip management instance.
central include file for FastLED, defines the CFastLED class/object
fl::CRGB CRGB
Definition crgb.h:25
fl::u32 scale_power_for_brightness(fl::u32 total_mW, fl::u8 brightness) FL_NO_EXCEPT
Applies the configured power-scaling response to a total power value.
void delay_at_max_brightness_for_power(fl::u16 ms) FL_NO_EXCEPT
Similar to CFastLED::delay(), but pre-adjusts brightness to keep below the power threshold.
void set_max_power_in_milliwatts(fl::u32 powerInmW) FL_NO_EXCEPT
Set the maximum power used in watts.
fl::u32 controller_dither_reserve_mW(const fl::CLEDController &controller) FL_NO_EXCEPT
dither_reserve_mW() for a controller that dithers, and zero for one that does not: a mode other than ...
fl::u32 controller_unscaled_power_mW(const fl::CLEDController &controller) FL_NO_EXCEPT
One controller's demand at full brightness, in mW, including idle draw – the quantity the limiter sum...
void set_max_power_in_volts_and_milliamps(fl::u8 volts, fl::u32 milliamps) FL_NO_EXCEPT
Set the maximum power used in milliamps for a given voltage.
void show_at_max_brightness_for_power() FL_NO_EXCEPT
Similar to CFastLED::show(), but pre-adjusts brightness to keep below the power threshold.
PowerModelRGB get_power_model() FL_NO_EXCEPT
Get current RGB power model.
Functions to convert from the HSV colorspace to the RGB colorspace.
#define FL_WARN_ONCE(...)
Definition log.h:439
Centralized logging categories for FastLED hardware interfaces and subsystems.
Unified manager for channel drivers with priority-based fallback.
constexpr remove_reference< T >::type && move(T &&t) FL_NO_EXCEPT
Definition move.h:30
u8 & hdFieldFloor() FL_NO_EXCEPT
Backing store for CFastLED::setHdFieldFloor().
void setWaitSpinBudgetUs(fl::u32 budget_us) FL_NO_EXCEPT
Set the tiered-wait spin budget (microseconds).
fl::u32 getWaitSpinBudgetUs() FL_NO_EXCEPT
Get the current tiered-wait spin budget (microseconds).
u8 ditherFrame() FL_NO_EXCEPT
Return the temporal-dither phase shared by all controllers in this frame.
void yield_system(fl::u32 microseconds) FL_NO_EXCEPT
OS-level yield only: same behavior as run(us, ExecFlags::SYSTEM).
unsigned char u8
Definition stdint.h:131
void enableAllDrivers() FL_NO_EXCEPT
Register every channel driver available on this platform with ChannelManager, restoring 3....
u8 u8 fract8 blur_amount FL_NO_EXCEPT
Definition blur.h:186
typename conditional< B, T, F >::type conditional_t
void delay(u32 ms, bool run_async=true) FL_NO_EXCEPT
Public delay wrapper that keeps bare Arduino delay() preferred after using fl::delay; while still all...
Definition delay.h:98
ChannelManager & channelManager() FL_NO_EXCEPT
Get the global ChannelManager singleton instance.
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.
FiveBitSemantics
u8 hdMinimumField(FiveBitSemantics semantics, u8 floor_setting) FL_NO_EXCEPT
The lowest field the managed HD path may choose: the configured flicker floor for a secondary slow-PW...
Bus
Portable public bus selector.
Definition bus.h:27
void yield() FL_NO_EXCEPT
Yield to the platform scheduler.
Definition yield.cpp.hpp:32
PowerCodecPolicy powerChannelCodecPolicy(const CLEDController &controller) FL_NO_EXCEPT
Identify the channel's final current/quantization choice without adding a virtual slot or storage to ...
@ LPD6803
LPD6803 LED chipset.
@ APA102HD
APA102 LED chipset with 5-bit gamma correction.
@ DOTSTARHD
APA102HD LED chipset alias.
@ SK9822HD
SK9822 LED chipset with 5-bit gamma correction.
@ LPD8806
LPD8806 LED chipset.
@ HD107HD
Same as APA102HD, but in turbo 40-mhz mode.
FiveBitSemantics fiveBitSemanticsFor(SpiChipset chip, FiveBitSemantics profile) FL_NO_EXCEPT
The 5-bit semantics for chip, with profile overriding the chip's default when it is not NotApplicable...
PowerCodecKind kind
Result of the shared frame-budget prepass on large-memory managed output.
Cross-platform facade for runtime network activity detection.
static fl::u32 fixed_power_mW(fl::u32 led_count) FL_NO_EXCEPT
#define FL_NO_EXCEPT
fl::u8 dark_mW
Dark LED baseline power consumption, in milliwatts.
Definition power_mgt.h:34
Configuration for a single LED channel.
Definition config.h:167
static ChannelEvents & instance() FL_NO_EXCEPT
Singleton event router for Channel lifecycle events.
SPI chipset configuration (data + clock pins)
Definition config.h:103
#define FL_SCOPED_TRACE
Definition trace.h:128
Runtime-tunable microsecond spin budget for the channel-manager and driver wait loops (Phase 1 of #28...
Platform-aware cooperative yield for FastLED.