10#include "platforms/shared/spi_hw_1.h"
21 const char* adapterName
24 if (hwControllers.empty()) {
25 FL_WARN(
"SpiChannelEngineAdapter::create: No controllers provided");
29 if (hwControllers.size() != priorities.
size() || hwControllers.size() != names.
size()) {
30 FL_WARN(
"SpiChannelEngineAdapter::create: Size mismatch in arguments");
34 if (!adapterName || adapterName[0] ==
'\0') {
35 FL_WARN(
"SpiChannelEngineAdapter::create: Empty adapter name");
43 for (
size_t i = 0; i < hwControllers.size(); i++) {
44 if (!hwControllers[i]) {
45 FL_WARN(
"SpiChannelEngineAdapter: Null controller at index " << i);
49 adapter->mControllers.emplace_back(hwControllers[i], priorities[i], names[i]);
51 FL_DBG(
"SpiChannelEngineAdapter: Registered controller '" << names[i]
52 <<
"' (priority " << priorities[i]
53 <<
", lanes: " <<
static_cast<int>(hwControllers[i]->getLaneCount()) <<
")");
56 if (adapter->mControllers.empty()) {
57 FL_WARN(
"SpiChannelEngineAdapter: No valid controllers registered");
71 FL_DBG(
"SpiChannelEngineAdapter: Destructor for '" <<
mName <<
"'");
78 while (
poll() != DriverState::READY) {
85 if (ctrl.controller && ctrl.controller->isInitialized()) {
86 ctrl.controller->end();
94 if (ctrl.priority > maxPriority) {
95 maxPriority = ctrl.priority;
104 if (assignment.clockPin == clockPin) {
105 return assignment.controllerIndex;
111 int bestPriority = -1;
125 if (bestIndex >= 0) {
142 if (assignedPin == clockPin) {
157 if (pin == clockPin) {
161 FL_WARN(
"SpiChannelEngineAdapter: Controller " << ctrl.
name
162 <<
" already initialized with different clock pin");
170 SpiHw1::Config config;
172 config.clock_pin = clockPin;
173 config.data_pin = dataPin;
174 config.clock_speed_hz = 20000000;
175 config.max_transfer_sz = 65536;
178 FL_WARN(
"SpiChannelEngineAdapter: Failed to initialize " << ctrl.
name);
183 FL_WARN(
"SpiChannelEngineAdapter: Multi-lane init not yet implemented");
190 FL_DBG(
"SpiChannelEngineAdapter: Initialized " << ctrl.
name
191 <<
" with clock pin " << clockPin);
210 return data->isSpi();
215 FL_WARN(
"SpiChannelEngineAdapter: Null channel data passed to enqueue()");
221 FL_WARN(
"SpiChannelEngineAdapter: Cannot handle non-SPI channel data (chipset mismatch)");
244 FL_DBG(
"SpiChannelEngineAdapter: Grouped into " << groups.size() <<
" clock pin groups");
247 for (
size_t i = 0; i < groups.size(); i++) {
250 FL_DBG(
"SpiChannelEngineAdapter: Transmitting group with clock pin "
254 FL_WARN(
"SpiChannelEngineAdapter: Failed to transmit batch for clock pin " << group.
clockPin);
259 FL_DBG(
"SpiChannelEngineAdapter: show() complete");
264 bool anyBusy =
false;
266 if (ctrl.controller && ctrl.controller->isBusy()) {
273 return DriverState::BUSY;
279 <<
" completed channels");
283 channel->setInUse(
false);
291 return DriverState::DRAINING;
294 return DriverState::READY;
302 for (
const auto& channel :
channels) {
308 const auto& chipset = channel->getChipset();
310 FL_WARN(
"SpiChannelEngineAdapter: Non-SPI chipset in groupByClockPin");
319 for (
size_t i = 0; i < groups.
size(); i++) {
320 if (groups[i].clockPin == clockPin) {
321 existingGroup = &groups[i];
346 const auto& chipset =
channels[0]->getChipset();
348 FL_WARN(
"SpiChannelEngineAdapter: Non-SPI chipset in transmitBatch");
354 int dataPin =
channels[0]->getPin();
358 if (controllerIndex < 0) {
359 FL_WARN(
"SpiChannelEngineAdapter: No available controller for clock pin " << clockPin);
371 for (
const auto& channel :
channels) {
377 channel->setInUse(
true);
380 const auto& data = channel->getData();
382 FL_WARN(
"SpiChannelEngineAdapter: Empty channel data");
383 channel->setInUse(
false);
387 FL_DBG(
"SpiChannelEngineAdapter: Transmitting channel via " << ctrl.
name
388 <<
" (pin " << channel->getPin() <<
", " << data.
size() <<
" bytes)");
391 DMABuffer dmaBuffer = ctrl.
controller->acquireDMABuffer(data.size());
392 if (!dmaBuffer.ok()) {
393 FL_WARN(
"SpiChannelEngineAdapter: Failed to acquire DMA buffer (error "
394 <<
static_cast<int>(dmaBuffer.error()) <<
")");
395 channel->setInUse(
false);
401 if (buffer.
size() < data.size()) {
402 FL_WARN(
"SpiChannelEngineAdapter: DMA buffer too small ("
403 << buffer.
size() <<
" < " << data.size() <<
")");
404 channel->setInUse(
false);
411 if (!ctrl.
controller->transmit(TransmitMode::ASYNC)) {
412 FL_WARN(
"SpiChannelEngineAdapter: Transmission failed");
413 channel->setInUse(
false);
417 FL_DBG(
"SpiChannelEngineAdapter: Transmission queued successfully");
423 FL_WARN(
"SpiChannelEngineAdapter: Transmission timeout");
427 FL_DBG(
"SpiChannelEngineAdapter: Batch transmission complete");
int getPriority() const
Get maximum priority among all controllers.
SpiChannelEngineAdapter(const char *name)
Private constructor - use create() factory method.
fl::string mName
Engine name for debugging.
~SpiChannelEngineAdapter() FL_NOEXCEPT override
Destructor.
fl::vector< ControllerInfo > mControllers
All managed controllers.
void show() override
Trigger transmission of enqueued data.
fl::vector< ClockPinGroup > groupByClockPin(fl::span< const ChannelDataPtr > channels)
Group channels by clock pin for efficient transmission.
DriverState poll() override
Query driver state and perform maintenance.
void enqueue(ChannelDataPtr channelData) override
Enqueue channel data for transmission.
bool initializeControllerIfNeeded(ControllerInfo &ctrl, int clockPin, int dataPin)
Initialize controller if needed for this clock pin.
fl::vector< ChannelDataPtr > mEnqueuedChannels
Channels waiting for show()
int selectControllerForClockPin(int clockPin)
Select best controller for a given clock pin.
static fl::shared_ptr< SpiChannelEngineAdapter > create(fl::vector< fl::shared_ptr< SpiHwBase > > hwControllers, fl::vector< int > priorities, fl::vector< const char * > names, const char *adapterName)
Create unified adapter managing multiple controllers.
bool transmitBatch(fl::span< const ChannelDataPtr > channels)
Transmit a batch of channels (all same clock pin)
bool canControllerHandleClockPin(const ControllerInfo &ctrl, int clockPin) const
Check if controller can handle this clock pin.
fl::vector< ClockPinAssignment > mClockPinAssignments
Clock pin → controller mapping.
fl::vector< ChannelDataPtr > mTransmittingChannels
Channels currently transmitting.
bool canHandle(const ChannelDataPtr &data) const override
Check if adapter can handle channel data.
fl::vector< ChannelDataPtr > channels
Group data structure for channels with same clock pin.
fl::size size() const FL_NOEXCEPT
const T * data() const FL_NOEXCEPT
constexpr fl::size size() const FL_NOEXCEPT
fl::size size() const FL_NOEXCEPT
void push_back(const T &value) FL_NOEXCEPT
Centralized logging categories for FastLED hardware interfaces and subsystems.
constexpr remove_reference< T >::type && move(T &&t) FL_NOEXCEPT
void * memcpy(void *dest, const void *src, size_t n) FL_NOEXCEPT
shared_ptr< T > make_shared(Args &&... args) FL_NOEXCEPT
Base definition for an LED controller.
Adapter that wraps HW SPI controllers for ChannelManager.
Driver state with optional error message.
fl::shared_ptr< SpiHwBase > controller
Hardware instance.
fl::vector< int > assignedClockPins
Clock pins assigned to this controller.
fl::string name
Name (e.g., "SPI2", "SPI3", "I2S0")
bool isInitialized
Whether begin() has been called.
Information about a registered SPI hardware controller.
int clockPin
GPIO clock pin (SCK)
SPI chipset configuration (data + clock pins)