4#include "platforms/is_platform.h"
37 if (
auto* p = options.mWhiteCfg.ptr<
Rgbww>()) {
39 }
else if (
auto* p = options.mWhiteCfg.ptr<
Rgbw>()) {
43 ctrl.clearWhiteChannel();
67 const XYMap* addressing,
76 u16 numLeds = pixels.
size();
82 if (expectedLeds != numLeds) {
84 <<
"=" << expectedLeds <<
") don't match LED count (" << numLeds
85 <<
"). Addressing transformation may produce unexpected results.");
97 for (u16 physicalIdx = 0; physicalIdx < numLeds; physicalIdx++) {
98 u16
x = physicalIdx %
width;
99 u16
y = physicalIdx /
width;
101 buffer[physicalIdx] = (sourceIdx < numLeds) ? pixelArray[sourceIdx] :
CRGB::Black;
134 if (!exclusive.empty()) {
135 FL_ERROR(
"Channel '" << channelName <<
"': bound driver '" << driverName
136 <<
"' is currently DISABLED by exclusive-driver selection '"
137 << exclusive <<
"'. Frame will be silently dropped. "
138 <<
"Resolve with: FastLED.enableDrivers<fl::Bus::"
139 << driverName <<
">() or FastLED.enableAllDrivers().");
141 FL_ERROR(
"Channel '" << channelName <<
"': bound driver '" << driverName
142 <<
"' is currently DISABLED. Frame will be silently dropped. "
143 <<
"Resolve with: FastLED.enableDrivers<fl::Bus::"
144 << driverName <<
">() or FastLED.enableAllDrivers().");
151i32 Channel::nextId() {
158 return configName.
value();
166#if FASTLED_LOG_RUNTIME_ENABLED
184 events.onChannelCreated(*channel);
188int Channel::getPin()
const {
246 applyWhiteCfg(*
this, options);
276 applyWhiteCfg(*
this, options);
284 events.onChannelBeginDestroy(*
this);
289 if (config.
mName.has_value()) {
299 applyWhiteCfg(*
this, config.
options);
301 events.onChannelConfigured(*
this, config);
304int Channel::getClockPin()
const {
306 return spi->clockPin;
345 u8 rgb_currents[3] = {current.
r, current.
g, current.
b};
346 u8 pos0 = (
static_cast<int>(rgbOrder) >> 6) & 0x3;
347 u8 pos1 = (
static_cast<int>(rgbOrder) >> 3) & 0x3;
348 u8 pos2 = (
static_cast<int>(rgbOrder) >> 0) & 0x3;
350 rgb_currents[pos0], rgb_currents[pos1], rgb_currents[pos2], current.
w);
357 size_t num_leds = pixelIterator.
size();
366 FL_WARN_ONCE(
"UCS7604 cannot carry 5-channel RGBWW — this chipset "
367 "always emits 4-channel RGBW. The warm/cool white "
368 "channels in your Rgbww config will be dropped. "
369 "Set ChannelOptions.mWhiteCfg = Rgbw{...} instead to "
370 "silence this warning.");
375 mode, wire_current, is_rgbw, gamma8.
get());
392#if defined(FASTLED_DISABLE_DYNAMIC_DRIVER) && FASTLED_DISABLE_DYNAMIC_DRIVER
414#if FASTLED_LOG_RUNTIME_ENABLED
416 (!driver || driver->getName() != busKey)) {
422 <<
"' wasn't instantiated. Resolve with: "
423 <<
"(1) fl::enableDrivers<fl::Bus::" << busKey <<
">() "
424 <<
"(links only this driver), "
425 <<
"(2) FastLED.enableAllDrivers() (links every driver), or "
426 <<
"(3) FastLED.addLeds<..., fl::Bus::" << busKey <<
">(...) "
427 <<
"(legacy API; pins Bus + triggers linker keep-alive). "
428 <<
"Defaulting to AUTO/priority dispatch.");
432 <<
"' is registered but cannot handle this channel's chipset "
433 <<
"(bus/chipset mismatch). Defaulting to AUTO/priority dispatch.");
438 FL_ERROR(
"Channel '" <<
mName <<
"': No compatible driver found - cannot transmit");
454 FL_WARN(
"Channel '" <<
mName <<
"': showPixels() called while mChannelData is in use by driver, attempting to wait");
457 FL_ERROR(
"Channel '" <<
mName <<
"': No driver bound yet the mChannelData is in use - cannot transmit");
461 bool ok = driver->waitForReady();
463 FL_ERROR(
"Channel '" <<
mName <<
"': Timeout occurred while waiting for driver to become READY");
466 FL_WARN(
"Channel '" <<
mName <<
"': Engine became READY after waiting");
492#if !defined(FASTLED_DISABLE_DYNAMIC_DRIVER) || !FASTLED_DISABLE_DYNAMIC_DRIVER
530#if !defined(FASTLED_DISABLE_UCS7604) || !FASTLED_DISABLE_UCS7604
543 writeUCS7604(&data, pixelIterator, clockless->
encoder,
548#if !defined(FASTLED_DISABLE_SPI_CHIPSETS) || !FASTLED_DISABLE_SPI_CHIPSETS
569 switch (config.chipset) {
643#if FASTLED_LOG_RUNTIME_ENABLED
645 emitDisabledDriverError(
660#if FASTLED_LOG_RUNTIME_ENABLED
672 events.onChannelEnqueued(*
this, driver->getName());
675void Channel::init() {
685 virtual
bool canHandle(const ChannelDataPtr& data)
const override {
690 virtual void enqueue(ChannelDataPtr )
override {
692 static bool warned =
false;
694 FL_DBG(
"StubChannelEngine: No-op enqueue (use for testing or unsupported platforms)");
719 static StubChannelEngine instance;
724void Channel::addToDrawList() {
726 FL_WARN(
"Channel '" <<
mName <<
"': Skipping addToDrawList() - already in draw list");
732 events.onChannelAdded(*
this);
735void Channel::removeFromDrawList() {
737 FL_WARN(
"Channel '" <<
mName <<
"': Skipping removeFromDrawList() - not in draw list");
743 events.onChannelRemoved(*
this);
749int Channel::size()
const {
757bool Channel::isInDrawList()
const {
773CRGB Channel::getTemperature() {
777u8 Channel::getDither() {
798 return driver->getName();
805 if (diameter <= 0.0f) {
836bool Channel::hasScreenMap()
const {
fl::UISlider brightness("Brightness", BRIGHTNESS, 0, 255)
ESP32-P4 Parallel IO (PARLIO) LED channel.
CPixelLEDController(RegistrationMode mode)
T fetch_add(T value) FL_NOEXCEPT
CLEDController & setCorrection(CRGB correction) FL_NOEXCEPT
The color corrction to use for this controller, expressed as a CRGB object.
VIRTUAL_IF_NOT_AVR void showLeds(fl::u8 brightness) FL_NOEXCEPT
fl::u8 getDither() FL_NOEXCEPT
Get the dithering option currently set for this controller.
void removeFromDrawList() FL_NOEXCEPT
Remove this controller from the draw list.
RegistrationMode
Registration mode for constructor.
@ DeferRegister
Defer registration until addToList() is called.
bool isInList() const FL_NOEXCEPT
Check if this controller is in the linked list.
CLEDController & setLeds(CRGB *data, int nLeds) FL_NOEXCEPT
Set the default array of LEDs to be used by this controller.
CLEDController & setDither(fl::u8 ditherMode=BINARY_DITHER) FL_NOEXCEPT
Set the dithering mode for this controller to use.
CRGB * leds() FL_NOEXCEPT
Pointer to the CRGB array for this controller.
void addToList() FL_NOEXCEPT
Add this controller to the linked list.
Rgbw getRgbw() const FL_NOEXCEPT
virtual int size() const FL_NOEXCEPT
How many LEDs does this controller manage?
CRGB getCorrection() FL_NOEXCEPT
Get the correction value used by this controller.
CLEDController & setTemperature(CRGB temperature) FL_NOEXCEPT
Set the color temperature, aka white point, for this controller.
CRGB getTemperature() FL_NOEXCEPT
Get the color temperature, aka white point, for this controller.
FL_NO_INLINE fl::shared_ptr< IChannelDriver > resolveDynamicDriver()
Cold slow-path helper for showPixels() when the driver was NOT pre-bound via setDriver().
static fl::string makeName(i32 id, const fl::optional< fl::string > &configName=fl::optional< fl::string >())
fl::span< CRGB > leds()
Get the LED array as a span (non-const)
CLEDController * asController()
Get pointer to base CLEDController for linked list traversal.
ChannelDataPtr mChannelData
Channel(const ChipsetVariant &chipset, EOrder rgbOrder, RegistrationMode mode)
Protected constructor for template subclasses (e.g., ClocklessIdf5)
bool mDisabledDriverWarned
fl::weak_ptr< IChannelDriver > mDriver
Channel & setScreenMap(const fl::XYMap &map, float diameter=-1.f)
Set screen map for JS canvas visualization from XYMap.
static ChannelDataPtr create(const ChipsetVariant &chipset, fl::vector_psram< u8 > &&encodedData=fl::vector_psram< u8 >()) FL_NOEXCEPT
Create channel transmission data (modern variant-based API)
fl::shared_ptr< IChannelDriver > selectDriverForChannel(const ChannelDataPtr &data, const fl::string &affinity) FL_NOEXCEPT
Select best driver for channel data (used by Channel::showPixels)
fl::shared_ptr< IChannelDriver > findDriverByName(const fl::string &name) const FL_NOEXCEPT
Silent counterpart to getDriverByName().
@ STATUS_ENABLED
Driver is registered and enabled.
@ STATUS_DISABLED
Driver is registered but disabled.
static ChannelManager & instance() FL_NOEXCEPT
Get the global singleton instance.
DriverStatus driverStatus(const fl::string &name) const FL_NOEXCEPT
Look up a driver's registration status without logging on miss.
static void onCanvasUiSet(CLEDController *strip, const ScreenMap &xymap) FL_NOEXCEPT
static fl::shared_ptr< const Gamma8 > getOrCreate(float gamma) FL_NOEXCEPT
IChannelDriver() FL_NOEXCEPT=default
Minimal interface for LED channel transmission drivers.
bool has_value() const FL_NOEXCEPT
void writeHD108(CONTAINER_UIN8_T *out) FL_NOEXCEPT
Encode pixels in HD108 format (zero allocation)
void writeAPA102(CONTAINER_UIN8_T *out, bool hd_gamma=false) FL_NOEXCEPT
Encode pixels in APA102/DOTSTAR format (zero allocation)
void writeP9813(CONTAINER_UIN8_T *out) FL_NOEXCEPT
Encode pixels in P9813 format (zero allocation)
void writeWS2801(CONTAINER_UIN8_T *out) FL_NOEXCEPT
Encode pixels in WS2801 format (zero allocation)
void writeSM16716(CONTAINER_UIN8_T *out) FL_NOEXCEPT
Encode pixels in SM16716 format (zero allocation)
void writeLPD6803(CONTAINER_UIN8_T *out) FL_NOEXCEPT
Encode pixels in LPD6803 format (zero allocation)
void writeWS2812(CONTAINER_UIN8_T *out) FL_NOEXCEPT
void writeSK9822(CONTAINER_UIN8_T *out, bool hd_gamma=false) FL_NOEXCEPT
Encode pixels in SK9822 format (zero allocation)
Rgbw get_rgbw() const FL_NOEXCEPT
Rgbww get_rgbww() const FL_NOEXCEPT
void writeWS2803(CONTAINER_UIN8_T *out) FL_NOEXCEPT
Encode pixels in WS2803 format (zero allocation)
void writeLPD8806(CONTAINER_UIN8_T *out) FL_NOEXCEPT
Encode pixels in LPD8806 format (zero allocation)
Adapter class that creates a PixelIterator from any color order.
u16 mapToIndex(const u16 &x, const u16 &y) const FL_NOEXCEPT
u16 getWidth() const FL_NOEXCEPT
u16 getHeight() const FL_NOEXCEPT
static XYMap fromXMap(const XMap &xmap) FL_NOEXCEPT
Create an XYMap from an XMap (treats 1D as 2D with height=1)
static XYMap constructRectangularGrid(u16 width, u16 height, u16 offset=0) FL_NOEXCEPT
PixelIteratorAny mPixelIterator
PixelIterator & get()
Get the constructed pixel iterator.
const PixelIterator & get() const
ReorderingPixelIteratorAny(PixelController< RGB, 1, 0xFFFFFFFF > &pixels, const XYMap *addressing, EOrder rgbOrder, Rgbw rgbw, Rgbww rgbww, const fl::string &channelName)
Construct pixel iterator with optional addressing transformation.
static fl::vector< CRGB > & getReorderBufferTLS()
Get thread-local buffer for addressing transformation.
fl::optional< PixelController< RGB, 1, 0xFFFFFFFF > > mAddressedController
virtual Capabilities getCapabilities() const override
Get driver capabilities (clockless, SPI, or both)
virtual bool canHandle(const ChannelDataPtr &data) const override
Check if this driver can handle the given channel data.
virtual DriverState poll() override
Query driver state and perform maintenance.
virtual void show() override
Trigger transmission of enqueued data.
virtual fl::string getName() const override
Get the driver name for affinity binding.
virtual void enqueue(ChannelDataPtr) override
Enqueue channel data for transmission.
virtual ~StubChannelEngine() FL_NOEXCEPT=default
T * get() const FL_NOEXCEPT
static string from_literal(const char *literal) FL_NOEXCEPT
fl::size size() const FL_NOEXCEPT
void resize(fl::size n) FL_NOEXCEPT
Channel transmission data - lightweight DTO for driver transmission.
#define DISABLE_DITHER
Disable dithering.
UCS7604 LED chipset encoder implementation.
Centralized logging categories for FastLED hardware interfaces and subsystems.
Unified manager for channel drivers with priority-based fallback.
void applyWhiteCfg(CLEDController &ctrl, const ChannelOptions &options) FL_NOEXCEPT
Apply the white-channel selection from ChannelOptions to a CLEDController.
static FL_NO_INLINE void emitDisabledDriverError(const fl::string &channelName, const fl::string &driverName, const fl::string &exclusive) FL_NOEXCEPT
Out-of-line cold-path emitter for the #2517 silent-drop DISABLED-driver diagnostic in Channel::showPi...
void writeUCS7604(fl::vector_psram< u8 > *data, PixelIterator &pixelIterator, ClocklessEncoder encoder, const ChannelOptions &settings, EOrder rgbOrder)
Encode UCS7604 pixel data into the channel data buffer.
CurrentControl brightness()
Get current global UCS7604 brightness value.
string to_string(T value) FL_NOEXCEPT
ClocklessEncoder
Identifies which encoder to use for clockless chipsets in the Channel API.
@ CLOCKLESS_ENCODER_UCS7604_8BIT
UCS7604 8-bit 800KHz.
@ CLOCKLESS_ENCODER_UCS7604_16BIT
UCS7604 16-bit 800KHz.
@ CLOCKLESS_ENCODER_UCS7604_16BIT_1600
UCS7604 16-bit 1600KHz.
@ CLOCKLESS_ENCODER_WS2812
Default, no preamble (WS2812 and compatible)
IChannelDriver * getStubChannelEngine()
Get stub channel driver for testing or unsupported platforms.
MapRedBlackTree< Key, T, Compare, fl::allocator_slab< char > > map
back_insert_iterator< Container > back_inserter(Container &c) FL_NOEXCEPT
Helper function to create a back_insert_iterator.
const char * busName(Bus b) FL_NOEXCEPT
Canonical driver-name string for a Bus value.
fl::variant< ClocklessChipset, SpiChipsetConfig > ChipsetVariant
Bus
Driver identifier for compile-time bus selection.
@ AUTO
Sentinel: defer to DefaultBus<Chipset>::value.
shared_ptr< T > make_shared(Args &&... args) FL_NOEXCEPT
UCS7604Mode
UCS7604 protocol configuration modes.
@ UCS7604_MODE_8BIT_800KHZ
@ UCS7604_MODE_16BIT_1600KHZ
@ UCS7604_MODE_16BIT_800KHZ
EOrder
RGB color channel orderings, used when instantiating controllers to determine what order the controll...
@ RGB
Red, Green, Blue (0012)
constexpr u32 gamma(float g) FL_NOEXCEPT
@ SM16716
SM16716 LED chipset.
@ LPD6803
LPD6803 LED chipset.
@ APA102HD
APA102 LED chipset with 5-bit gamma correction.
@ HD107
Same as APA102, but in turbo 40-mhz mode.
@ DOTSTARHD
APA102HD LED chipset alias.
@ SK9822HD
SK9822 LED chipset with 5-bit gamma correction.
@ SK9822
SK9822 LED chipset.
@ DOTSTAR
APA102 LED chipset alias.
@ P9813
P9813 LED chipset.
@ APA102
APA102 LED chipset.
@ HD108
16-bit variant of HD107, always gamma corrected. No SD (standard definition) option available - all H...
@ LPD8806
LPD8806 LED chipset.
@ WS2803
WS2803 LED chipset.
@ WS2801
WS2801 LED chipset.
@ HD107HD
Same as APA102HD, but in turbo 40-mhz mode.
void encodeUCS7604(PixelIterator &pixel_iter, size_t num_leds, OutputIterator out, UCS7604Mode mode, const UCS7604CurrentControl ¤t, bool is_rgbw, const Gamma8 *gamma=nullptr)
Encode complete UCS7604 frame (preamble + padding + pixel data)
Base definition for an LED controller.
Low level pixel data writing class.
FASTLED_FORCE_INLINE int size() const
Get the length of the LED strip.
ColorAdjustment mColorAdjustment
const fl::u8 * mData
pointer to the underlying LED data
@ Black
<div style='background:#000000;width:4em;height:4em;'></div>
Representation of an 8-bit RGB pixel (Red, Green, Blue)
fl::optional< fl::string > mName
Optional user-specified name (if not set, Channel generates one automatically)
ChannelOptions options
Optional channel settings (correction, temperature, dither, rgbw, affinity)
fl::span< CRGB > mLeds
LED data array.
ChipsetVariant chipset
Chipset configuration (clockless or SPI)
EOrder rgb_order
RGB channel ordering.
Configuration for a single LED channel.
static ChannelEvents & instance()
fl::optional< float > mGamma
Optional channel configuration parameters All fields have sensible defaults and can be overridden as ...
Runtime bit-period timing for a clockless chipset.
ClocklessEncoder encoder
Byte-level encoding pipeline (default: WS2812)
Clockless chipset configuration (single data pin)
Driver state with optional error message.
FASTLED_FORCE_INLINE bool active() const FL_NOEXCEPT
FASTLED_FORCE_INLINE bool active() const FL_NOEXCEPT
Per-strip RGBWW configuration.
SPI chipset configuration (data + clock pins)
SPI encoder configuration for LED protocols.
u8 g
Green channel current (0x0-0xF)
u8 b
Blue channel current (0x0-0xF)
u8 w
White channel current (0x0-0xF)
u8 r
Red channel current (0x0-0xF)
UCS7604 current control structure with 4-bit fields for each channel.
UCS7604 LED chipset controller implementation for FastLED.