@brief Unified channel manager with priority-based driver selection This manager acts as a registry for concrete driver implementations (RMT, SPI, PARLIO). Channels select drivers via selectDriverForChannel() and bind directly to them via weak_ptr. Platform-specific code registers drivers during static initialization.
| 48 | /// |
| 49 | /// Platform-specific code registers drivers during static initialization. |
| 50 | class ChannelManager : public EngineEvents::Listener { |
| 51 | public: |
| 52 | /// @brief Get the global singleton instance |
| 53 | /// @return Reference to the singleton ChannelManager |
| 54 | /// @note Thread-safe singleton initialization |
| 55 | static ChannelManager& instance() FL_NOEXCEPT; |
| 56 | |
| 57 | /// @brief Constructor |
| 58 | ChannelManager() FL_NOEXCEPT; |
| 59 | |
| 60 | /// @brief Destructor - cleanup shared drivers (automatic via shared_ptr) |
| 61 | ~ChannelManager() FL_NOEXCEPT override; |
| 62 | |
| 63 | /// @brief Add a driver with priority (higher priority = preferred) |
| 64 | /// @param priority Driver priority (higher values = higher priority) |
| 65 | /// @param driver Shared driver implementation (allows caller to retain reference for testing) |
| 66 | /// @note Platform-specific code calls this during static initialization |
| 67 | /// @note Drivers are automatically sorted by priority on each insertion |
| 68 | /// @note Driver name is obtained via driver->getName() |
| 69 | /// @note If driver->getName() returns empty string, driver is rejected (emits FL_WARN and returns) |
| 70 | /// @note If a driver with the same name already exists, it will be replaced: |
| 71 | /// 1. FL_WARN emitted about replacement |
| 72 | /// 2. All drivers polled until READY state (1 second timeout) |
| 73 | /// 3. Old driver removed (shared_ptr may trigger deletion) |
| 74 | /// 4. New driver added with specified priority |
| 75 | void addDriver(int priority, fl::shared_ptr<IChannelDriver> driver) FL_NOEXCEPT; |
| 76 | |
| 77 | /// @brief Remove a driver from the manager |
| 78 | /// @param driver Shared pointer to the driver to remove |
| 79 | /// @return true if driver was found and removed, false if not found |
| 80 | /// @note Emits FL_WARN if driver is not found |
| 81 | /// @note Useful for test cleanup |
| 82 | bool removeDriver(fl::shared_ptr<IChannelDriver> driver) FL_NOEXCEPT; |
| 83 | |
| 84 | /// @brief Remove all drivers from the manager |
| 85 | /// @note Clears the entire driver registry |
| 86 | /// @note Useful for FastLED.reset() with CHANNEL_DRIVERS flag |
| 87 | /// @note Waits for all drivers to become READY before clearing (1 second timeout) |
| 88 | void clearAllDrivers() FL_NOEXCEPT; |
| 89 | |
| 90 | /// @brief Enable or disable a driver by name at runtime |
| 91 | /// @param name Driver name to control (case-sensitive, e.g., "RMT", "SPI", "PARLIO") |
| 92 | /// @param enabled true to enable, false to disable |
| 93 | /// @note Disabled drivers are skipped during selection |
| 94 | /// @note Changes take effect immediately on next enqueue() |
| 95 | /// @note If name is not found, this is a no-op (does not warn) |
| 96 | void setDriverEnabled(const char* name, bool enabled) FL_NOEXCEPT; |
| 97 | |
| 98 | /// @brief Register a single driver at a priority above the platform default |
| 99 | /// and disable all others (compile-time TU-linking variant). |
| 100 | /// |
| 101 | /// Post-#2428 the default build does NOT auto-register every driver -- |
| 102 | /// only the platform-default driver TU links (via the legacy clockless |
| 103 | /// controller's Phase 5b pre-bind). This template provides the opt-in |
| 104 | /// path to add another driver and have it win priority dispatch. |
| 105 | /// |
| 106 | /// Naming `BusTraits<B>::instancePtr()` here is the ODR-use that links |
| 107 | /// the driver TU; the registration with the manager happens at |