15#include "platforms/init_channel_driver.h"
16#include "platforms/is_platform.h"
29 static bool sInitialized =
false;
32 platforms::initChannelDrivers();
40 FL_DBG(
"ChannelManager: Initializing");
47 FL_DBG(
"ChannelManager: Destructor called");
66 if (context ==
nullptr) {
77 constexpr u32 kPollNeededFallbackSliceMs = 1;
79 return kPollNeededFallbackSliceMs;
81 const u32 elapsed =
millis() - startTime;
82 if (elapsed >= timeoutMs) {
85 const u32 remaining = timeoutMs - elapsed;
86 return remaining < kPollNeededFallbackSliceMs ? remaining : kPollNeededFallbackSliceMs;
95 FL_WARN(
"ChannelManager::addDriver() - Null driver provided");
99 FL_WARN(
"ChannelManager::addDriver() - Engine has empty name (driver->getName() returned empty string)");
103 for (
const auto& entry :
mDrivers) {
104 if (entry.name == *engineName) {
110 if (entry.driver == driver && entry.priority == priority) {
111 FL_DBG(
"ChannelManager::addDriver() - '" << engineName->c_str() <<
"' already registered at priority " << priority <<
" (idempotent no-op)");
114 FL_WARN(
"ChannelManager::addDriver() - Replacing existing driver '" << engineName->c_str() <<
"'");
116 FL_DBG(
"ChannelManager: Waiting for all drivers to become READY before replacement");
121 for (
size_t i = 0; i <
mDrivers.size(); ++i) {
122 if (
mDrivers[i].name != *engineName) {
125 FL_DBG(
"ChannelManager: Removing old driver '" << engineName->c_str() <<
"' (shared_ptr may delete)");
148 if (engineName.
empty()) {
154 for (
const auto& entry :
mDrivers) {
155 if (entry.name == engineName) {
169 mDrivers.push_back({priority, driver, engineName, enabled});
183 capStr +=
"CLOCKLESS";
186 if (!capStr.
empty()) capStr +=
"|";
189 if (capStr.
empty()) {
193 FL_DBG(
"ChannelManager: Added driver '" << engineName.
c_str() <<
"' (priority " << priority <<
", caps: " << capStr.
c_str() <<
")");
205 FL_WARN(
"ChannelManager::removeDriver() - Null driver provided");
210 for (
size_t i = 0; i <
mDrivers.size(); ++i) {
212 FL_DBG(
"ChannelManager: Removing driver '" <<
mDrivers[i].name <<
"'");
223 FL_WARN(
"ChannelManager::removeDriver() - Engine " << driver.get() <<
" not found in registry");
228 FL_DBG(
"ChannelManager: Waiting for all drivers to become READY before clearing");
234 FL_DBG(
"ChannelManager: Clearing " <<
mDrivers.size() <<
" drivers");
254 FL_ERROR(
"ChannelManager::setDriverEnabled() - Null driver name provided");
260 if (entry.name == name) {
261 entry.enabled = enabled;
263 FL_DBG(
"ChannelManager: Driver '" << name <<
"' " << (enabled ?
"enabled" :
"disabled"));
268 FL_ERROR(
"ChannelManager::setDriverEnabled() - Driver '" << name <<
"' not found in registry");
278 if (!name || !name[0]) {
279 FL_ERROR(
"ChannelManager::setExclusiveDriverByName() - Null or empty driver name provided");
282 entry.enabled =
false;
294 entry.enabled = (entry.name == name);
295 found = found || entry.enabled;
299 FL_ERROR(
"ChannelManager::setExclusiveDriverByName() - Driver '" << name <<
"' not found in registry");
306 FL_ERROR(
"ChannelManager::setDriverPriority() - Empty driver name provided");
313 if (entry.name == name) {
314 entry.priority = priority;
316 FL_DBG(
"ChannelManager: Driver '" << name <<
"' priority changed to " << priority);
322 FL_ERROR(
"ChannelManager::setDriverPriority() - Driver '" << name <<
"' not found in registry");
330 FL_DBG(
"ChannelManager: Engine list re-sorted after priority change");
335 for (
const auto& entry :
mDrivers) {
336 if (entry.driver.get() == &driver) {
337 return entry.enabled;
346 FL_ERROR(
"ChannelManager::isDriverEnabled() - Null driver name provided");
350 for (
const auto& entry :
mDrivers) {
351 if (entry.name == name) {
352 return entry.enabled;
356 FL_ERROR(
"ChannelManager::isDriverEnabled() - Driver '" << name <<
"' not found in registry");
364 for (
const auto& entry :
mDrivers) {
365 if (entry.name == name) {
382 for (
const auto& entry :
mDrivers) {
398 for (
const auto& entry :
mDrivers) {
399 if (entry.enabled && entry.name == name) {
408 FL_ERROR(
"ChannelManager::getDriverByName() - Empty driver name provided");
413 FL_ERROR(
"ChannelManager::getDriverByName() - Driver '" << name.c_str() <<
"' not found or not enabled");
420 FL_ERROR(
"ChannelManager::selectDriverForChannel() - Null channel data");
431 if (affinity.empty()) {
438 if (!driver->canHandle(data)) {
439 FL_WARN_ONCE(
"ChannelManager: Affinity driver '" << affinity <<
"' cannot handle channel data (chipset/bus mismatch). Falling back to AUTO/priority dispatch.");
447 for (
const auto& entry :
mDrivers) {
448 if (!entry.enabled)
continue;
449 if (entry.driver->canHandle(data)) {
454 FL_ERROR(
"ChannelManager: No compatible driver found for channel data");
459template<
typename Condition>
461 const u32 startTime = timeoutMs > 0 ?
millis() : 0;
475 if (spinBudget > 0) {
477 while ((
fl::micros() - spinStart) < spinBudget) {
481 if (timeoutMs > 0 && (
millis() - startTime) >= timeoutMs) {
482 FL_ERROR(
"ChannelManager: Timeout occurred while waiting for condition");
489 while (!condition()) {
491 if (timeoutMs > 0 && (
millis() - startTime >= timeoutMs)) {
492 FL_ERROR(
"ChannelManager: Timeout occurred while waiting for condition");
532 bool anyBusy =
false;
533 bool anyDraining =
false;
545 firstError =
result.error;
550 if (!firstError.
empty()) {
568 FL_ERROR(
"ChannelManager: Timeout occurred while waiting for READY state");
576 bool draining_or_done = (
580 return draining_or_done;
583 FL_ERROR(
"ChannelManager: Timeout occurred while waiting for READY or DRAINING state");
599 entry.driver->show();
608 FL_DBG(
"ChannelManager: reset() - all drivers ready");
FastLED chrono implementation - duration types for time measurements.
void onEndFrame() FL_NO_EXCEPT override
Trigger transmission of batched channel data.
void setDriverEnabled(const char *name, bool enabled) FL_NO_EXCEPT
Enable or disable a driver by name at runtime.
bool waitForReadyOrDraining(u32 timeoutMs=1000) FL_NO_EXCEPT
bool setExclusiveDriverByName(const char *name) FL_NO_EXCEPT
Enable only one driver exclusively (disables all others) — by-name escape hatch.
u32 pollNeededWaitSliceMs(u32 startTime, u32 timeoutMs) const FL_NO_EXCEPT
void reset() FL_NO_EXCEPT
Reset bus manager state, clearing all enqueued and transmitting channels.
ChannelManager() FL_NO_EXCEPT
Constructor.
~ChannelManager() FL_NO_EXCEPT override
Destructor - cleanup shared drivers (automatic via shared_ptr)
void onBeginFrame() FL_NO_EXCEPT override
Poll drivers before frame starts to clear previous frame state.
static ChannelManager & registry() FL_NO_EXCEPT
Get the singleton WITHOUT registering platform default drivers.
fl::shared_ptr< IChannelDriver > findDriverByName(const fl::string &name) const FL_NO_EXCEPT
Silent counterpart to getDriverByName().
fl::size getDriverCount() const FL_NO_EXCEPT
Get count of registered drivers (including unnamed ones)
IChannelDriver::DriverState poll() FL_NO_EXCEPT
Poll all registered drivers and return aggregate state.
void clearAllDrivers() FL_NO_EXCEPT
Remove all drivers from the manager.
static ChannelManager & instance() FL_NO_EXCEPT
Get the global singleton instance.
IChannelDriver::PollNeededCallback mPollNeededCallback
Shared callback installed on drivers that can signal poll-needed events.
DriverStatus driverStatus(const fl::string &name) const FL_NO_EXCEPT
Look up a driver's registration status without logging on miss.
FL_NO_INLINE FL_COLD bool addDriverSlow(int priority, const fl::shared_ptr< IChannelDriver > &driver, const fl::string *engineName, AddDriverSlowReason reason) FL_NO_EXCEPT
Handle validation failures and the uncommon replacement flow outside the normal driver-registration p...
platforms::ChannelPollSignal mPollNeededSignal
Platform wait primitive owned by the manager.
fl::vector< DriverInfo > mCachedDriverInfo
Cached driver info for getDriverInfos() to avoid allocations.
DriverStatus
Registration status of a driver by name (silent lookup)
@ NOT_REGISTERED
No driver with that name is registered.
@ STATUS_ENABLED
Driver is registered and enabled.
@ STATUS_DISABLED
Driver is registered but disabled.
void setExclusiveDriver() FL_NO_EXCEPT
Register a single driver at a priority above the platform default and disable all others (compile-tim...
fl::shared_ptr< IChannelDriver > getDriverByName(const fl::string &name) const FL_NO_EXCEPT
Get driver by name for affinity binding.
bool waitForCondition(Condition condition, u32 timeoutMs=1000) FL_NO_EXCEPT
Wait until a condition is met, with check-pump-delay logic.
fl::shared_ptr< IChannelDriver > selectDriverForChannel(const ChannelDataPtr &data, const fl::string &affinity) FL_NO_EXCEPT
Select best driver for channel data (used by Channel::showPixels)
fl::vector< EngineEntry > mDrivers
Shared drivers sorted by priority descending (higher values first)
fl::string mExclusiveDriver
Exclusive driver name (empty if no exclusive mode)
static void notifyPollNeededThunk(void *context) FL_NO_EXCEPT
bool setDriverPriority(const fl::string &name, int priority) FL_NO_EXCEPT
Change the priority of a registered driver.
bool waitForPollNeededSignal(u32 timeoutMs) FL_NO_EXCEPT
void addDriver(int priority, fl::shared_ptr< IChannelDriver > driver) FL_NO_EXCEPT
Add a driver with priority (higher priority = preferred)
bool isDriverEnabled(const char *name) const FL_NO_EXCEPT
Check if a driver is enabled by name.
void notifyPollNeeded() FL_NO_EXCEPT
bool removeDriver(fl::shared_ptr< IChannelDriver > driver) FL_NO_EXCEPT
Remove a driver from the manager.
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.
static void removeListener(Listener *listener) FL_NO_EXCEPT
static void addListener(Listener *listener, int priority=0) FL_NO_EXCEPT
Minimal interface for LED channel transmission drivers.
static T & instance() FL_NO_EXCEPT
bool empty() const FL_NO_EXCEPT
const char * c_str() const FL_NO_EXCEPT
static bool isAnyNetworkActive() FL_NO_EXCEPT
Task executor — runs registered task runners and manages the run loop.
#define FL_WARN_ONCE(...)
Centralized logging categories for FastLED hardware interfaces and subsystems.
Unified manager for channel drivers with priority-based fallback.
void sort_small(Iterator first, Iterator last, Compare comp) FL_NO_EXCEPT
fl::u32 getWaitSpinBudgetUs() FL_NO_EXCEPT
Get the current tiered-wait spin budget (microseconds).
void yield_system(fl::u32 microseconds) FL_NO_EXCEPT
OS-level yield only: same behavior as run(us, ExecFlags::SYSTEM).
u8 u8 fract8 blur_amount FL_NO_EXCEPT
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.
const char * busDriverName(Bus b, fl::u8 which=0, bool spi=false) FL_NO_EXCEPT
Concrete ChannelManager driver name for a portable bus.
Bus
Portable public bus selector.
expected< T, E > result
Alias for expected (Rust-style naming)
Base definition for an LED controller.
Cross-platform facade for runtime network activity detection.
bool supportsClockless
Supports clockless protocols (WS2812, SK6812, etc.)
bool supportsSpi
Supports SPI protocols (APA102, SK9822, etc.)
@ READY
Hardware idle; ready to accept new transmissions.
@ DRAINING
All channels submitted; still transmitting.
@ ERROR
Driver encountered an error.
@ BUSY
Active: channels transmitting or queued.
Driver state with optional error message.
ISR-safe callback handle invoked when the manager should poll again.
Runtime-tunable microsecond spin budget for the channel-manager and driver wait loops (Phase 1 of #28...