FastLED 3.9.15
Loading...
Searching...
No Matches

◆ addDriver()

void fl::ChannelManager::addDriver ( int priority,
fl::shared_ptr< IChannelDriver > driver )

Add a driver with priority (higher priority = preferred)

Parameters
priorityDriver priority (higher values = higher priority)
driverShared driver implementation (allows caller to retain reference for testing)
Note
Platform-specific code calls this during static initialization
Drivers are automatically sorted by priority on each insertion
Driver name is obtained via driver->getName()
If driver->getName() returns empty string, driver is rejected (emits FL_WARN and returns)
If a driver with the same name already exists, it will be replaced:
  1. FL_WARN emitted about replacement
  2. All drivers polled until READY state (1 second timeout)
  3. Old driver removed (shared_ptr may trigger deletion)
  4. New driver added with specified priority

Definition at line 87 of file manager.cpp.hpp.

87 {
88 if (!driver) {
89 FL_WARN("ChannelManager::addDriver() - Null driver provided");
90 return;
91 }
92
93 // Get driver name from the driver itself
94 fl::string engineName = driver->getName();
95
96 // Reject drivers with empty names
97 if (engineName.empty()) {
98 FL_WARN("ChannelManager::addDriver() - Engine has empty name (driver->getName() returned empty string)");
99 return;
100 }
101
102 // Check if driver with this name already exists
103 bool replacing = false;
104 for (const auto& entry : mDrivers) {
105 if (entry.name == engineName) {
106 // True-duplicate fast path: same shared_ptr at same priority is
107 // a no-op (legacy clockless controllers may pre-bind the same
108 // driver singleton from many template instantiations). Skip the
109 // replace flow entirely so we don't waitForReady() or emit a
110 // spurious "Replacing" warning.
111 if (entry.driver == driver && entry.priority == priority) {
112 FL_DBG("ChannelManager::addDriver() - '" << engineName.c_str()
113 << "' already registered at priority " << priority
114 << " (idempotent no-op)");
115 return;
116 }
117 replacing = true;
118 FL_WARN("ChannelManager::addDriver() - Replacing existing driver '" << engineName.c_str() << "'");
119 break;
120 }
121 }
122
123 // If replacing, wait for all drivers to become READY
124 if (replacing) {
125 FL_DBG("ChannelManager: Waiting for all drivers to become READY before replacement");
126 waitForReady();
127
128 // Remove the old driver with matching name (shared_ptr may trigger deletion)
129 for (size_t i = 0; i < mDrivers.size(); ++i) {
130 if (mDrivers[i].name == engineName) {
131 FL_DBG("ChannelManager: Removing old driver '" << engineName.c_str() << "' (shared_ptr may delete)");
132 if (mDrivers[i].driver) {
133 mDrivers[i].driver->setPollNeededCallback(IChannelDriver::PollNeededCallback());
134 }
135 mDrivers.erase(mDrivers.begin() + i);
136 break;
137 }
138 }
139 }
140
141 // Respect exclusive driver mode: auto-disable if name doesn't match exclusive driver
142 bool enabled = true; // Default: enabled
143 if (!mExclusiveDriver.empty()) {
144 enabled = (engineName == mExclusiveDriver); // Only enable if matches exclusive driver
145 }
146
147 mDrivers.push_back({priority, driver, engineName, enabled});
148 driver->setPollNeededCallback(mPollNeededCallback);
149
150 // Build capability string for debug output. Gate the entire block behind
151 // FASTLED_HAS_DBG because the `capStr` exists ONLY to feed the FL_DBG
152 // line below. On release builds (FASTLED_HAS_DBG=0 — i.e. the default
153 // SKETCH_HAS_LARGE_MEMORY=0 path AND any -DFASTLED_LOG_VERBOSITY=0
154 // opt-in build via the gating in fl/log/log.h) the FL_DBG itself is a
155 // no-op, but without this guard the `fl::string capStr` allocation +
156 // two `if` branches still emitted code. See #2773 item 2.3 follow-up.
157#if FASTLED_HAS_DBG
158 IChannelDriver::Capabilities caps = driver->getCapabilities();
159 fl::string capStr;
160 if (caps.supportsClockless) {
161 capStr += "CLOCKLESS";
162 }
163 if (caps.supportsSpi) {
164 if (!capStr.empty()) capStr += "|";
165 capStr += "SPI";
166 }
167 if (capStr.empty()) {
168 capStr = "NONE";
169 }
170
171 FL_DBG("ChannelManager: Added driver '" << engineName.c_str() << "' (priority " << priority << ", caps: " << capStr.c_str() << ")");
172#endif
173
174 // Sort drivers by priority descending (higher values first) after each insertion
175 // Higher priority values = higher precedence (e.g., priority 50 selected over priority 10)
176 // Only 1-4 drivers expected — sort_small skips the quicksort_impl
177 // instantiation entirely (see #2907 for the bloat motivation).
178 fl::sort_small(mDrivers.begin(), mDrivers.end());
179}
IChannelDriver::PollNeededCallback mPollNeededCallback
Shared callback installed on drivers that can signal poll-needed events.
Definition manager.h:299
bool waitForReady(u32 timeoutMs=1000) FL_NOEXCEPT
Wait for all drivers to become READY.
fl::vector< EngineEntry > mDrivers
Shared drivers sorted by priority descending (higher values first)
Definition manager.h:287
fl::string mExclusiveDriver
Exclusive driver name (empty if no exclusive mode)
Definition manager.h:296
bool empty() const FL_NOEXCEPT
const char * c_str() const FL_NOEXCEPT
#define FL_WARN(X)
Definition log.h:276
#define FL_DBG
Definition log.h:388
void sort_small(Iterator first, Iterator last, Compare comp) FL_NOEXCEPT
Definition algorithm.h:612

References fl::basic_string::c_str(), fl::basic_string::empty(), FL_DBG, FL_WARN, mDrivers, mExclusiveDriver, mPollNeededCallback, fl::sort_small(), fl::IChannelDriver::Capabilities::supportsClockless, fl::IChannelDriver::Capabilities::supportsSpi, and waitForReady().

Referenced by setExclusiveDriver().

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