FastLED 3.10.9
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)
19#include "fl/system/delay.h" // for delayMicroseconds
20#include "fl/system/yield.h" // for fl::yield
22#if SKETCH_HAS_LARGE_MEMORY
23#include "fl/task/executor.h"
24#include "fl/net/network_detector.h" // adaptive yield gate in the refresh throttle (#3762)
25#endif
26#include "fl/log/log.h" // for FL_WARN
27#include "fl/stl/assert.h" // for FL_ASSERT
28#include "fl/audio/audio_manager.h" // for AudioManager
29#include "fl/ui/audio.h" // for UIAudio (CFastLED::add(UIAudio&))
30#include "hsv2rgb.h" // for CRGB
31#include "fl/stl/int.h" // for u32, u16
32#include "fl/stl/type_traits.h" // for conditional_t
33#include "platforms/init.h" // IWYU pragma: keep
34#include "fl/channels/config.h" // for ChannelConfig
35#include "fl/stl/singleton.h" // for fl::Singleton
36#include "platforms/is_platform.h"
37#include "fl/stl/noexcept.h"
38
41
42#ifndef MAX_CLED_CONTROLLERS
43#ifdef FL_IS_AVR
44// Uno/Nano-class (328P family) parts keep 8 slots to save RAM, as in 3.10.3;
45// larger ATmegas allow 16. Define MAX_CLED_CONTROLLERS to override (#4788).
46#if defined(FL_IS_AVR_ATMEGA) && !defined(FL_IS_AVR_ATMEGA_328P)
47#define MAX_CLED_CONTROLLERS 16
48#else
49#define MAX_CLED_CONTROLLERS 8
50#endif
51#else
52#define MAX_CLED_CONTROLLERS 64
53#endif // FL_IS_AVR
54#endif // MAX_CLED_CONTROLLERS
55
56#if defined(FL_IS_SAM)
57volatile fl::u32 fuckit;
58#endif
59
60
61#ifndef FASTLED_NO_ATEXIT
62#define FASTLED_NO_ATEXIT 0
63#endif
64
65#if !FASTLED_NO_ATEXIT
66extern "C" FL_LINK_WEAK int atexit(void (* /*func*/ )()) { return 0; }
67#endif
68
69#ifdef FASTLED_NEEDS_YIELD
70extern "C" void yield(void) { }
71#endif
72
73// Implementation of cled_contoller_size() moved to src/fl/fastled_internal.cpp
74
76
77#if !FL_PLATFORM_HAS_TINY_MEMORY
78// FL_LINT_ALLOW_GLOBAL(shared dither phase is required once per logical frame)
80
84#endif
85
88// FL_LINT_ALLOW_GLOBAL(extern ABI: smartmatrix_t3.h declares `extern SmartMatrix *pSmartMatrix`)
89void *pSmartMatrix = nullptr;
90
93
94CFastLED FastLED; // global constructor allowed in this case.
95
97
99static fl::u32 lastshow = 0;
100
101namespace fl {
104// FL_LINT_ALLOW_GLOBAL(mutable counter written by the driver via extern)
106
108// FL_LINT_ALLOW_GLOBAL(mutable counter written by the driver via extern)
110} // namespace fl
111
112// uint32_t CRGB::Squant = ((uint32_t)((__TIME__[4]-'0') * 28))<<16 | ((__TIME__[6]-'0')*50)<<8 | ((__TIME__[7]-'0')*28);
113
115 // clear out the array of led controllers
116 // m_nControllers = 0;
117 mScale = 255;
118 mNFPS = 0;
119 mPPowerFunc = nullptr;
120 mNPowerData = 0xFFFFFFFF;
122 mLastShownScale = 255;
123 mMaxRefreshHz = 0;
124}
125
126#if FL_COLOR_PIPELINE_SHARED
127const fl::FramePowerDispatch*& fl::activeFramePowerDispatch() FL_NO_EXCEPT {
128 static const FramePowerDispatch* dispatch = nullptr;
129 return dispatch;
130}
131#endif
132
134 // Call platform-specific initialization once
135 // Uses the trampoline pattern: platforms/init.h dispatches to platform-specific headers
136 // FL_RUN_ONCE ensures this is only called once, even if init() is called multiple times
137 FL_RUN_ONCE(fl::platforms::init());
138}
139
141 return (*this)[0].size();
142}
143
145 return (*this)[0].leds();
146}
147
149 CRGB *data,
150 int nLedsOrOffset, int nLedsIfOffset) FL_NO_EXCEPT {
151 int nOffset = (nLedsIfOffset > 0) ? nLedsOrOffset : 0;
152 int nLeds = (nLedsIfOffset > 0) ? nLedsIfOffset : nLedsOrOffset;
153
154 pLed->init();
155 pLed->setLeds(data + nOffset, nLeds);
156 FastLED.setMaxRefreshRate(pLed->getMaxRefreshRate(),true);
157 fl::EngineEvents::onStripAdded(pLed, nLedsOrOffset - nOffset);
158 return *pLed;
159}
160
164
165#if FL_COLOR_PIPELINE_SHARED
166fl::shared_ptr<fl::StreamingPipelineQ16> fl::channelColorPipeline(
168 const fl::Channel* channel = controller.asChannel();
169 return channel != nullptr ? channel->colorPipeline()
171}
172#endif
173
176 PowerCodecPolicy policy;
178 for (fl::size i = 0; i < registered.size(); ++i) {
179 const fl::Channel* channel = registered[i].get();
180 if (channel != &controller) continue;
181 policy.kind = PowerCodecKind::Byte;
183 channel->getChipset().ptr<fl::SpiChipsetConfig>();
184 if (spi == nullptr) return policy;
185 switch (spi->timing.chipset) {
188 break;
191 break;
197 const fl::EmitterProfile* profile = channel->emitterProfile();
199 spi->timing.chipset, profile != nullptr
200 ? profile->five_bit_semantics
203 semantics, fl::detail::hdFieldFloor());
204 break;
205 }
206 default:
207 break;
208 }
209 return policy;
210 }
211 // A custom managed controller has no known wire encoding. Charging full
212 // code for every lit emitter is conservative, never a silent guess.
213 return policy;
214}
215
216void CFastLED::add(fl::ChannelPtr channel) FL_NO_EXCEPT {
217 if (!channel) {
218 return;
219 }
220 auto& chnls = channels();
221 // Protect against double-add
222 if (chnls.has(channel)) {
223 return;
224 }
225 chnls.push_back(channel);
226 // Add channel to the CLEDController linked list
227 // fl::Channel uses DeferRegister mode, so explicit addToDrawList() call is required
228 // Note: addToDrawList() now fires onChannelAdded event
229 channel->addToDrawList();
230}
231
232void CFastLED::remove(fl::ChannelPtr channel) FL_NO_EXCEPT {
233 if (!channel) {
234 return;
235 }
236 // Note: removeFromDrawList() now fires onChannelRemoved event
237 channel->removeFromDrawList();
238 // Remove from internal storage (safe if not found - erase is a no-op)
239 channels().erase(channel);
240}
241
243 // Lambda to check if flag is set, clear it, and return true if it was set
244 auto clearFlag = [&flags](ClearFlags flag) -> bool {
245 if ((flags & flag) != ClearFlags::NONE) {
246 flags = static_cast<ClearFlags>(static_cast<fl::u32>(flags) & ~static_cast<fl::u32>(flag));
247 return true;
248 }
249 return false;
250 };
251
252
253 // Reset POWER_SETTINGS - reset power management to defaults
254 if (clearFlag(ClearFlags::POWER_SETTINGS)) {
255 FastLED.mPPowerFunc = nullptr; // No power limiting function
256 FastLED.mNPowerData = 0xFFFFFFFF; // No power limit (max value)
257 FastLED.mLastRequestedScale = 255;
258 FastLED.mLastShownScale = 255;
259 }
260
261 // Reset BRIGHTNESS - reset global brightness to 255 (full brightness)
262 if (clearFlag(ClearFlags::BRIGHTNESS)) {
263 FastLED.mScale = 255;
264 }
265
266 // Reset REFRESH_RATE - reset refresh rate limiting to unlimited
267 if (clearFlag(ClearFlags::REFRESH_RATE)) {
268 FastLED.mMaxRefreshHz = 0; // No minimum delay between frames
269 }
270
271 // Reset FPS_COUNTER - reset FPS tracking counter to 0
272 if (clearFlag(ClearFlags::FPS_COUNTER)) {
273 FastLED.mNFPS = 0;
274 }
275
276 // Reset CHANNELS - remove all channels from controller list
277 if (clearFlag(ClearFlags::CHANNELS)) {
278 // Wait for engines to complete, with 2s timeout to prevent infinite hang
279 // if an engine is permanently stalled (e.g. PARLIO on ESP32-C6 hw bug)
280 FastLED.wait(2000);
281
282 // Remove all channels by iterating through a copy of the vector
283 // (we make a copy because remove() modifies channels())
284 fl::vector<fl::ChannelPtr> channelsCopy = channels();
285 for (auto& channel : channelsCopy) {
286 remove(channel);
287 }
288
289 // Reset bus manager state (clear enqueued and transmitting channels)
291 manager.reset();
292
293 // Clear the internal storage (should already be empty, but ensure it)
294 channels().clear();
295 }
296
297 // Reset CHANNEL_ENGINES - clear all registered channel drivers
298 if (clearFlag(ClearFlags::CHANNEL_ENGINES)) {
299 // Always wait for all channel bus transmissions to complete first
300 FastLED.wait();
302 manager.clearAllDrivers();
303 }
304
305 // Ensure all flags were handled - catches typos or missing implementations
306 FL_ASSERT(flags == ClearFlags::NONE, "Unhandled flags in FastLED.clear()");
307}
308
309// This is bad code. But it produces the smallest binaries for reasons
310// beyond mortal comprehensions.
311// Instead of iterating through the link list for onBeginFrame(), beginShowLeds()
312// and endShowLeds(): store the pointers in an array and iterate through that.
313//
314// static uninitialized gControllersData produces the smallest binary on attiny85.
315// FL_LINT_ALLOW_GLOBAL(intentional ATtiny85 code-size optimization — moving to Singleton<T> reverses the size win documented above)
317
318// Refresh-rate throttle shared by show() and showColor().
319//
320// This mirrors the tiered wait already shipped in
321// IChannelDriver::waitForCondition (refs #2818 for the spin tier, #2815/#2817
322// for the adaptive yield). show() was the last call site still taking an
323// UNCONDITIONAL deep yield, which is the root cause of FastLED#2994.
324//
325// Why it matters: fl::task::run(<non-zero>, SYSTEM) routes to
326// pumpCoroutines(), which on ESP32 floors at one FreeRTOS tick
327// (coroutine_esp32.impl.hpp, the `if (ticks == 0) ticks = 1` branch added for
328// the #2254 websocket-starvation fix). That is >=1 ms at
329// CONFIG_FREERTOS_HZ=1000 and >=10 ms at the 100 Hz default. With
330// setMaxRefreshRate(800) the throttle only needs 1250 us, so every frame
331// overshot to a tick boundary -- ~500 shows per sequence x sub-ms jitter is
332// the 63-300 ms drift reported in #2994, against a rock-steady 2495 ms on
333// 3.10.3 (which used a plain busy-wait).
334//
335// Two tiers:
336// - No radio up: taskYIELD() only. Equal-priority tasks still run, and there
337// is no tick floor, so the wait stays microsecond-accurate.
338// - Radio up: keep the deep yield -- WiFi/lwIP/BT genuinely need the CPU --
339// but stop taking it once less than the spin budget remains, so the final
340// stretch is spun out instead of overshooting past our deadline.
341static void throttleToMaxRefreshRate(fl::u32 minMicros) FL_NO_EXCEPT {
342 if (!minMicros) {
343 return;
344 }
345#if SKETCH_HAS_LARGE_MEMORY
346 const fl::u32 spinBudget = fl::detail::getWaitSpinBudgetUs();
347#endif
348 while (true) {
349 const fl::u32 elapsed = fl::micros() - lastshow;
350 if (elapsed >= minMicros) {
351 return;
352 }
353#if SKETCH_HAS_LARGE_MEMORY
354 const fl::u32 remaining = minMicros - elapsed;
355 // Deep yield only while a radio is up AND there is more than the spin
356 // budget left to burn. Once inside the budget we spin, because a deep
357 // yield costs a whole tick and would overshoot the deadline.
358 if (remaining > spinBudget && fl::NetworkDetector::isAnyNetworkActive()) {
360 } else {
361 // taskYIELD()-equivalent: equal-priority tasks still get CPU, but
362 // there is no FreeRTOS tick floor, so this stays sub-microsecond.
364 }
365#endif
366 }
367}
368
372
376
379 onBeginFrame();
382
384 // If we have a function for computing power, use it!
385 if(mPPowerFunc) {
386 scale = (*mPPowerFunc)(scale, mNPowerData);
387 }
389
390
391 // A byte index saves bookkeeping on 16-bit-int targets; retain wider limits.
392 using ControllerIndex = fl::conditional_t<
394 ControllerIndex length = 0;
396
397 while(pCur && length < MAX_CLED_CONTROLLERS) {
398 if (pCur->getEnabled()) {
399 gControllersData[length] = pCur->beginShowLeds(pCur->size());
400 } else {
401 gControllersData[length] = nullptr;
402 }
403 length++;
405 pCur = pCur->next();
406 }
407
408 pCur = CLEDController::head();
409 for (length = 0; length < MAX_CLED_CONTROLLERS && pCur; length++) {
410 if (pCur->getEnabled()) {
411 pCur->showLedsInternal(scale);
412 }
413 pCur = pCur->next();
414
415 }
416
417 length = 0; // Reset length to 0 and iterate again.
418 pCur = CLEDController::head();
419 while(pCur && length < MAX_CLED_CONTROLLERS) {
420 if (pCur->getEnabled()) {
422 }
423 length++;
424 pCur = pCur->next();
425 }
426 countFPS();
427 onEndFrame();
429}
430
434
436 int x = 0;
438 while( pCur) {
439 ++x;
440 pCur = pCur->next();
441 }
442 return x;
443}
444
447 while(x-- && pCur) {
448 pCur = pCur->next();
449 }
450 if(pCur == nullptr) {
451 return *(CLEDController::head());
452 } else {
453 return *pCur;
454 }
455}
456
458 onBeginFrame();
461
463 // If we have a function for computing power, use it!
464 if(mPPowerFunc) {
465 // showColor() encodes a constant, not controller source pixels; the
466 // source-frame managed prepass cannot model it.
467#if FL_COLOR_PIPELINE_SHARED
468 const fl::FramePowerDispatch* dispatch = fl::activeFramePowerDispatch();
469 scale = dispatch ? dispatch->showColorBrightness(scale, mNPowerData)
470 : (*mPPowerFunc)(scale, mNPowerData);
471#else
472 scale = (*mPPowerFunc)(scale, mNPowerData);
473#endif
474 }
476
477 int length = 0;
479 while(pCur && length < MAX_CLED_CONTROLLERS) {
480 if (pCur->getEnabled()) {
481 gControllersData[length] = pCur->beginShowLeds(pCur->size());
482 } else {
483 gControllersData[length] = nullptr;
484 }
485 length++;
486 pCur = pCur->next();
487 }
488
489 pCur = CLEDController::head();
490 while(pCur && length < MAX_CLED_CONTROLLERS) {
492 if (pCur->getEnabled()) {
493 pCur->showColorInternal(color, scale);
494 }
495 pCur = pCur->next();
496 }
497
498 pCur = CLEDController::head();
499 length = 0; // Reset length to 0 and iterate again.
500 while(pCur && length < MAX_CLED_CONTROLLERS) {
501 if (pCur->getEnabled()) {
503 }
504 length++;
505 pCur = pCur->next();
506 }
507 countFPS();
508 onEndFrame();
510}
511
512void CFastLED::clear(bool writeData) FL_NO_EXCEPT {
513 if(writeData) {
514 showColor(CRGB(0,0,0), 0);
515 }
516 clearData();
517}
518
521 while(pCur) {
522 pCur->clearLedDataInternal();
523 pCur = pCur->next();
524 }
525}
526
527void CFastLED::delay(unsigned long ms) FL_NO_EXCEPT {
528 unsigned long start = fl::millis();
529 do {
530#ifndef FASTLED_ACCURATE_CLOCK
531 // make sure to allow at least one ms to pass to ensure the clock moves
532 // forward
533 fl::delay(1);
534#endif
535 show();
536 fl::yield();
537 }
538 while((fl::millis()-start) < ms);
539}
540
543 while(pCur) {
544 pCur->setTemperature(temp);
545 pCur = pCur->next();
546 }
547}
548
549void CFastLED::setCorrection(const CRGB & correction) FL_NO_EXCEPT {
551 while(pCur) {
552 pCur->setCorrection(correction);
553 pCur = pCur->next();
554 }
555}
556
559 while(pCur) {
560 pCur->setDither(ditherMode);
561 pCur = pCur->next();
562 }
563}
564
567 min_field < 1 ? 1 : (min_field > 31 ? 31 : min_field);
568}
569
573
574fl::u32 CFastLED::getEstimatedPowerInMilliWatts(bool apply_limiter) const FL_NO_EXCEPT {
575#if FL_COLOR_PIPELINE_SHARED
576 if (apply_limiter && mPPowerFunc && fl::activeFramePowerDispatch()) {
577 bool managed = false;
578 for (CLEDController* p = CLEDController::head(); p; p = p->next()) {
579 if (p->getEnabled() && fl::channelColorPipeline(*p)) {
580 managed = true;
581 break;
582 }
583 }
584 if (managed) {
585 const fl::FramePowerPlan plan =
586 fl::activeFramePowerDispatch()->calculate(mScale, mNPowerData);
587 if (plan.modeled_mW == 0xFFFFFFFFu) return plan.modeled_mW;
588 const fl::u32 mcu_mW = plan.mcu_mW;
589 return plan.modeled_mW > mcu_mW ? plan.modeled_mW - mcu_mW : 0;
590 }
591 }
592#endif
593 fl::u32 fixed_power_mW = 0;
594 fl::u32 controllable_power_mW = 0;
595 fl::u32 dither_reserve_power_mW = 0;
596
597 // Sum unscaled power from all LED controllers using visitor pattern.
598 // The dark-current baseline is kept apart from the part brightness scales,
599 // because it is drawn at every brightness including zero (#4156 R4).
600 const fl::u32 dark_mW_per_led = get_power_model().dark_mW;
602 if (!leds.empty()) {
603 // The controller's own estimate: its RGBW setting, so an RGBW strip
604 // is charged for the diode it actually lights, and for a bound
605 // colour profile the solved drives rather than the source (#4344).
606 const fl::u32 unscaled_mW = controller_unscaled_power_mW(*controller);
607 const fl::u32 dark_mW = dark_mW_per_led * static_cast<fl::u32>(leds.size());
608 fixed_power_mW += dark_mW;
609 controllable_power_mW += unscaled_mW > dark_mW ? unscaled_mW - dark_mW : 0;
610 // What dithering can add on top, at any non-zero brightness (#4342).
611 // Not on TINY, where the bound costs more flash than the tier has
612 // to spare (#4478); controller_dither_reserve_mW is 0 there.
613#if !FL_PLATFORM_HAS_TINY_MEMORY
614 dither_reserve_power_mW += controller_dither_reserve_mW(*controller);
615#endif
616 }
617 });
618
619 // Determine effective brightness
620 fl::u8 effective_brightness = mScale;
621
622 if (apply_limiter && mPPowerFunc) {
623 // Power limiting is enabled and user wants limited power - calculate brightness after limiting
624 // This calls calculate_max_brightness_for_power_mW(mScale, mNPowerData)
625 effective_brightness = (*mPPowerFunc)(mScale, mNPowerData);
626 }
627
628 // Scale only the emitter share by the configured power-brightness response
629 // and add the baseline back, so the estimate matches what the limiter now
630 // budgets against.
631 // Note: MCU power consumption is NOT included - caller should add platform-specific MCU power if needed
632 // The dither reserve only at a non-zero brightness: nothing dithers at 0,
633 // the same as the limiter, whose answer of 0 needs no reserve either.
634 if (effective_brightness != 0) {
635 fixed_power_mW += dither_reserve_power_mW;
636 }
637 return fixed_power_mW +
638 scale_power_for_brightness(controllable_power_mW, effective_brightness);
639}
640
641//
642// template<int m, int n> void transpose8(unsigned char A[8], unsigned char B[8]) {
643// uint32_t x, y, t;
644//
645// // Load the array and pack it into x and y.
646// y = *(unsigned int*)(A);
647// x = *(unsigned int*)(A+4);
648//
649// // x = (A[0]<<24) | (A[m]<<16) | (A[2*m]<<8) | A[3*m];
650// // y = (A[4*m]<<24) | (A[5*m]<<16) | (A[6*m]<<8) | A[7*m];
651//
652 // // pre-transform x
653 // t = (x ^ (x >> 7)) & 0x00AA00AA; x = x ^ t ^ (t << 7);
654 // t = (x ^ (x >>14)) & 0x0000CCCC; x = x ^ t ^ (t <<14);
655 //
656 // // pre-transform y
657 // t = (y ^ (y >> 7)) & 0x00AA00AA; y = y ^ t ^ (t << 7);
658 // t = (y ^ (y >>14)) & 0x0000CCCC; y = y ^ t ^ (t <<14);
659 //
660 // // final transform
661 // t = (x & 0xF0F0F0F0) | ((y >> 4) & 0x0F0F0F0F);
662 // y = ((x << 4) & 0xF0F0F0F0) | (y & 0x0F0F0F0F);
663 // x = t;
664//
665// B[7*n] = y; y >>= 8;
666// B[6*n] = y; y >>= 8;
667// B[5*n] = y; y >>= 8;
668// B[4*n] = y;
669//
670// B[3*n] = x; x >>= 8;
671// B[2*n] = x; x >>= 8;
672// B[n] = x; x >>= 8;
673// B[0] = x;
674// // B[0]=x>>24; B[n]=x>>16; B[2*n]=x>>8; B[3*n]=x>>0;
675// // B[4*n]=y>>24; B[5*n]=y>>16; B[6*n]=y>>8; B[7*n]=y>>0;
676// }
677//
678// void transposeLines(Lines & out, Lines & in) {
679// transpose8<1,2>(in.bytes, out.bytes);
680// transpose8<1,2>(in.bytes + 8, out.bytes + 1);
681// }
682
683
686extern int noise_min;
687
690extern int noise_max;
691
693 static int br = 0;
694#if SKETCH_HAS_LARGE_MEMORY
695 typedef fl::u32 frame_ms_t;
696#else
697 // Wrapping 16-bit millis saves 2 B RAM; nFrames frames must take < 65 s (#4788).
698 typedef fl::u16 frame_ms_t;
699#endif
700 static frame_ms_t lastframe = 0; // fl::millis();
701
702 if(br++ >= nFrames) {
703 const frame_ms_t sample = static_cast<frame_ms_t>(fl::millis());
704 frame_ms_t now = static_cast<frame_ms_t>(sample - lastframe);
705 if(now == 0) {
706 now = 1; // prevent division by zero below
707 }
708 mNFPS = static_cast<fl::u16>((static_cast<fl::u32>(br) * 1000) / now);
709 br = 0;
710 lastframe = sample;
711 }
712}
713
714void CFastLED::setMaxRefreshRate(fl::u16 refresh, bool constrain) FL_NO_EXCEPT {
715 if(constrain) {
716 // When constraining we may only slow things down: keep the lower cap.
717 if(refresh > 0 && (mMaxRefreshHz == 0 || refresh < mMaxRefreshHz)) {
718 mMaxRefreshHz = refresh;
719 }
720 } else {
721 mMaxRefreshHz = refresh; // 0 = unlimited
722 }
723}
724
725
727 return FastLED.getBrightness();
728}
729
730// ============================================================================
731// Deprecated Power Management Wrapper Functions
732// ============================================================================
733// These functions wrap the CFastLED singleton methods for backward compatibility.
734// They were originally in power_mgt.cpp but have been moved here to avoid
735// circular dependencies (power_mgt.cpp should not include FastLED.h).
736
737void set_max_power_in_volts_and_milliamps(fl::u8 volts, fl::u32 milliamps)
739 FastLED.setMaxPowerInVoltsAndMilliamps(volts, milliamps);
740}
741
742void set_max_power_in_milliwatts(fl::u32 powerInmW)
744 FastLED.setMaxPowerInMilliWatts(powerInmW);
745}
746
749 // power management usage is now in FastLED.show, no need for this function
750 FastLED.show();
751}
752
755 FastLED.delay(ms);
756}
757
758// ============================================================================
759// Channel Bus Manager Controls
760// ============================================================================
761
765
766void CFastLED::setDriverEnabled(const char* name, bool enabled) FL_NO_EXCEPT {
768 manager.setDriverEnabled(name, enabled);
769}
770
773 return manager.setExclusiveDriver(bus, which);
774}
775
776bool CFastLED::isDriverEnabled(const char* name) const FL_NO_EXCEPT {
778 return manager.isDriverEnabled(name);
779}
780
783 return manager.getDriverCount();
784}
785
790
791// ============================================================================
792// Wait for channel bus transmissions
793// ============================================================================
794
796 // A zero timeout means wait indefinitely. The void API cannot report a
797 // timeout, so returning early would violate its completion contract.
798 // Dispatch only to consumers already in use; do not construct a manager
799 // in legacy-only sketches just to wait for their direct driver.
801}
802
803bool CFastLED::wait(fl::u32 timeout_ms) FL_NO_EXCEPT {
804 return fl::detail::waitForDriverCompletion(timeout_ms);
805}
806
807// Tiered-wait spin-budget shims (#2818). Storage in
808// src/fl/channels/detail/wait_spin_budget.cpp.hpp.
812
816
817// ============================================================================
818// Runtime Channel API Implementation
819// ============================================================================
820
821fl::ChannelPtr CFastLED::add(const fl::ChannelConfig& config) FL_NO_EXCEPT {
822 // Issue #2459: the non-template `FastLED.add(cfg)` path is the runtime-
823 // selection mode. To make sure `cfg.options.mBus` (or priority dispatch
824 // when `mBus == Bus::AUTO`) can actually find the requested driver at
825 // runtime, we eagerly enroll every driver available on this platform.
826 // That trades binary size for ergonomics — the user wanted runtime
827 // selection, so they get runtime selection.
828 //
829 // For minimum binary size, callers should use the compile-time path:
830 // FastLED.addLeds<CHIPSET, PIN, ORDER, fl::Bus::X>(leds, n);
831 // which ODR-uses only `BusTraits<X>::instancePtr()` and lets
832 // `--gc-sections` drop every other driver TU.
833 //
834 // The warning fires at most once per process (FL_WARN_ONCE) and can be
835 // disabled with `-DFASTLED_SUPPRESS_RUNTIME_DRIVER_WARNING`.
836 #ifndef FASTLED_SUPPRESS_RUNTIME_DRIVER_WARNING
837 FL_WARN_ONCE("FastLED.add(cfg): runtime-selection mode — enrolling every "
838 "available driver via fl::enableAllDrivers(). For minimum "
839 "binary size, prefer FastLED.addLeds<CHIPSET, PIN, ORDER, "
840 "fl::Bus::X>(leds, n) which links only the named driver. "
841 "Suppress this warning with -DFASTLED_SUPPRESS_RUNTIME_DRIVER_WARNING.");
842 #endif
844
846 FL_ASSERT(manager.getDriverCount() > 0,
847 "No channel drivers available - channel API requires at least one registered driver");
848 auto channel = fl::Channel::create(config);
849 add(channel);
850 return channel;
851}
852
855 channels.reserve(configs.size());
856
857 for (const auto& config : configs) {
858 channels.push_back(add(config));
859 }
860
861 return channels;
862}
863
864fl::vector<fl::ChannelPtr> CFastLED::add(fl::initializer_list<fl::ChannelConfig> configs) FL_NO_EXCEPT {
866 channels.reserve(configs.size());
867
868 for (const auto& config : configs) {
869 channels.push_back(add(config));
870 }
871
872 return channels;
873}
874
877 channels.reserve(multiConfig.mChannels.size());
878
879 for (const auto& configPtr : multiConfig.mChannels) {
880 if (configPtr) {
881 channels.push_back(add(*configPtr));
882 }
883 }
884
885 return channels;
886}
887
888fl::RxChannelPtr CFastLED::addRx(const fl::RxChannelConfig& config) FL_NO_EXCEPT {
889 return fl::RxChannel::create(config);
890}
891
892// ============================================================================
893
894#ifdef NEED_CXX_BITS
895namespace __cxxabiv1
896{
897 #if !defined(FL_IS_ESP8266) && !defined(FL_IS_ESP32) && !defined(ARDUINO)
898 extern "C" void __cxa_pure_virtual (void) {}
899 #endif
900
901 /* guard variables */
902
903 /* The ABI requires a 64-bit type. */
904 __extension__ typedef int __guard __attribute__((mode(__DI__)));
905
906 extern "C" int __cxa_guard_acquire (__guard *) FL_LINK_WEAK;
907 extern "C" void __cxa_guard_release (__guard *) FL_LINK_WEAK;
908 extern "C" void __cxa_guard_abort (__guard *) FL_LINK_WEAK;
909
910 extern "C" int __cxa_guard_acquire (__guard *g)
911 {
912 return !*(char *)(g);
913 }
914
915 extern "C" void __cxa_guard_release (__guard *g)
916 {
917 *(char *)g = 1;
918 }
919
920 extern "C" void __cxa_guard_abort (__guard *)
921 {
922
923 }
924}
925#endif
926
927
931
932
934 #if FASTLED_HAS_ENGINE_EVENTS
936 #endif
937}
938
942
946
947// ============================================================================
948// CFastLED audio method implementations - thin trampolines to AudioManager
949// ============================================================================
950
955
960
965
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
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
int noise_min
Unused value.
ClearFlags
Flags for FastLED.clear() to control what state gets cleared/reset.
Definition FastLED.h:661
@ CHANNELS
Remove all channels from controller list.
Definition FastLED.h:663
@ BRIGHTNESS
Reset global brightness to 255.
Definition FastLED.h:665
@ CHANNEL_ENGINES
Clear all channel drivers from ChannelManager.
Definition FastLED.h:668
@ POWER_SETTINGS
Reset power management (setMaxPowerInMilliWatts)
Definition FastLED.h:664
@ FPS_COUNTER
Reset FPS tracking counter to 0.
Definition FastLED.h:667
@ NONE
Clear nothing (no-op)
Definition FastLED.h:662
@ REFRESH_RATE
Reset refresh rate limiting to unlimited.
Definition FastLED.h:666
#define FL_DITHER_ENABLE_MIN_REFRESH_HZ
High level controller interface for FastLED.
Definition FastLED.h:712
CFastLED FastLED
Global LED strip management instance.
central include file for FastLED, defines the CFastLED class/object
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:726
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:1645
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:1906
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:722
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:725
fl::u16 mNFPS
tracking for current frames per second (FPS) value
Definition FastLED.h:723
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:728
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:727
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:724
and refresh rates, and provides access functions for driving led data to controllers via the show() /...
Definition FastLED.h:718
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.
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
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.
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.
bool waitForDriverCompletion(u32 timeoutMs) FL_NO_EXCEPT
Wait for installed consumers using one deadline (zero means indefinitely).
unsigned char u8
Definition s16x16x4.h:132
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.
u32 _retry_cnt
Frame retry counter for ESP8266 clockless drivers (FASTLED_DEBUG_COUNT_FRAME_RETRIES).
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
u32 _frame_cnt
Frame counter for ESP8266 clockless drivers (FASTLED_DEBUG_COUNT_FRAME_RETRIES).
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...
Base definition for an LED controller.
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_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_NO_EXCEPT
#define FL_MAYBE_UNUSED
#define FL_LINK_WEAK
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.