340 {
341 if (channels.
empty()) {
342 return true;
343 }
344
345
346 const auto& chipset = channels[0]->getChipset();
347 if (!chipset.is<SpiChipsetConfig>()) {
348 FL_WARN(
"SpiChannelEngineAdapter: Non-SPI chipset in transmitBatch");
349 return false;
350 }
351
352 const SpiChipsetConfig& spiConfig = chipset.get<SpiChipsetConfig>();
353 int clockPin = spiConfig.clockPin;
354 int dataPin = channels[0]->getPin();
355
356
358 if (controllerIndex < 0) {
359 FL_WARN(
"SpiChannelEngineAdapter: No available controller for clock pin " << clockPin);
360 return false;
361 }
362
364
365
367 return false;
368 }
369
370
371 for (const auto& channel : channels) {
372 if (!channel) {
373 continue;
374 }
375
376
377 channel->setInUse(true);
378
379
380 const auto& data = channel->getData();
381 if (data.empty()) {
382 FL_WARN(
"SpiChannelEngineAdapter: Empty channel data");
383 channel->setInUse(false);
384 continue;
385 }
386
387 FL_DBG(
"SpiChannelEngineAdapter: Transmitting channel via " << ctrl.name
388 << " (pin " << channel->getPin() << ", " << data.size() << " bytes)");
389
390
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);
396 return false;
397 }
398
399
400 fl::span<u8> buffer = dmaBuffer.data();
401 if (buffer.
size() < data.size()) {
402 FL_WARN(
"SpiChannelEngineAdapter: DMA buffer too small ("
403 << buffer.
size() <<
" < " << data.size() <<
")");
404 channel->setInUse(false);
405 return false;
406 }
407
409
410
411 if (!ctrl.controller->transmit(TransmitMode::ASYNC)) {
412 FL_WARN(
"SpiChannelEngineAdapter: Transmission failed");
413 channel->setInUse(false);
414 return false;
415 }
416
417 FL_DBG(
"SpiChannelEngineAdapter: Transmission queued successfully");
418 }
419
420
421
422 if (!ctrl.controller->waitComplete(1000)) {
423 FL_WARN(
"SpiChannelEngineAdapter: Transmission timeout");
424 return false;
425 }
426
427 FL_DBG(
"SpiChannelEngineAdapter: Batch transmission complete");
428 return true;
429}
fl::vector< ControllerInfo > mControllers
All managed controllers.
bool initializeControllerIfNeeded(ControllerInfo &ctrl, int clockPin, int dataPin)
Initialize controller if needed for this clock pin.
int selectControllerForClockPin(int clockPin)
Select best controller for a given clock pin.
constexpr bool empty() const FL_NOEXCEPT
const T * data() const FL_NOEXCEPT
constexpr fl::size size() const FL_NOEXCEPT
void * memcpy(void *dest, const void *src, size_t n) FL_NOEXCEPT
Information about a registered SPI hardware controller.