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

◆ flush()

Result< void > fl::spi::MultiLaneDevice::flush ( )

Flush all lanes (transpose and transmit)

Returns
Result indicating success or error (Result<void>)
Note
Transposes all lane buffers and transmits via hardware DMA
Clears all lane buffers after transmission starts
All non-empty lanes MUST have identical sizes - operation fails with error if sizes differ
Zero-padding is NOT performed - size validation prevents unreliable chipset-specific padding issues
Transaction API not yet implemented - call waitComplete() manually after flush()

Definition at line 301 of file multi_lane_device.cpp.hpp.

301 {
302 if (!isReady()) {
303 return Result<void>::failure(SPIError::NOT_INITIALIZED,
304 "Device not initialized");
305 }
306
307 // Find lane sizes and validate all non-empty lanes have the same size
308 size_t expected_size = 0;
309 bool found_first = false;
310
311 for (size_t i = 0; i < pImpl->lanes.size(); i++) {
312 size_t lane_size = pImpl->lanes[i].bufferSize();
313
314 if (lane_size > 0) {
315 if (!found_first) {
316 // First non-empty lane sets the expected size
317 expected_size = lane_size;
318 found_first = true;
319 } else if (lane_size != expected_size) {
320 // Size mismatch detected
321 FL_WARN("MultiLaneDevice: Lane size mismatch - expected " << expected_size
322 << " bytes (lane 0), but lane " << i << " has " << lane_size << " bytes");
323 return Result<void>::failure(SPIError::INVALID_PARAMETER,
324 "Lane size mismatch: all lanes must have identical sizes");
325 }
326 }
327 }
328
329 if (expected_size == 0) {
330 FL_WARN("MultiLaneDevice: No data to flush (all lanes empty)");
331 return Result<void>::failure(SPIError::ALLOCATION_FAILED,
332 "No data to transmit");
333 }
334
335 // Use expected_size for DMA buffer allocation (all lanes now guaranteed same size)
336 size_t max_size = expected_size;
337
338 // Acquire DMA buffer from hardware backend - use polymorphic interface
339 DMABuffer dma_buffer = pImpl->backend->acquireDMABuffer(max_size);
340
341 if (!dma_buffer.ok()) {
342 FL_WARN("MultiLaneDevice: Failed to acquire DMA buffer");
343 return Result<void>::failure(dma_buffer.error(),
344 "Failed to acquire DMA buffer");
345 }
346
347 // Transpose lanes into DMA buffer (or copy for single lane)
348 const char* error = nullptr;
349 bool transpose_ok = false;
350
351 if (pImpl->backend_type == 1) {
352 // Single lane - no transposition needed, just copy data directly
353 if (pImpl->lanes.size() > 0) {
354 fl::span<const u8> lane_data = pImpl->lanes[0].data();
355 fl::span<u8> dma_data = dma_buffer.data();
356
357 // Verify sizes match (DMA buffer should be exactly the size we requested)
358 if (lane_data.size() != dma_data.size()) {
359 FL_WARN("MultiLaneDevice: DMA buffer size mismatch - expected " << lane_data.size()
360 << " bytes, got " << dma_data.size() << " bytes");
361 error = "DMA buffer size mismatch";
362 transpose_ok = false;
363 } else {
364 // Copy lane data to DMA buffer
365 for (size_t i = 0; i < lane_data.size(); i++) {
366 dma_data[i] = lane_data[i];
367 }
368 transpose_ok = true;
369 }
370 } else {
371 error = "No lanes configured";
372 transpose_ok = false;
373 }
374
375 } else if (pImpl->backend_type == 2) {
376 // Dual-SPI transposition
378 if (pImpl->lanes.size() > 0) {
379 lane0 = SPITransposer::LaneData{
380 pImpl->lanes[0].data(),
381 fl::span<const u8>() // No padding
382 };
383 }
384 if (pImpl->lanes.size() > 1) {
385 lane1 = SPITransposer::LaneData{
386 pImpl->lanes[1].data(),
387 fl::span<const u8>() // No padding
388 };
389 }
390
391 transpose_ok = SPITransposer::transpose2(lane0, lane1, dma_buffer.data(), &error);
392
393 } else if (pImpl->backend_type == 4) {
394 // Quad-SPI transposition
396 for (size_t i = 0; i < pImpl->lanes.size() && i < 4; i++) {
397 lanes[i] = SPITransposer::LaneData{
398 pImpl->lanes[i].data(),
399 fl::span<const u8>() // No padding
400 };
401 }
402
403 transpose_ok = SPITransposer::transpose4(lanes[0], lanes[1], lanes[2], lanes[3],
404 dma_buffer.data(), &error);
405
406 } else if (pImpl->backend_type == 8) {
407 // Octal-SPI transposition
409 for (size_t i = 0; i < pImpl->lanes.size() && i < 8; i++) {
410 lanes[i] = SPITransposer::LaneData{
411 pImpl->lanes[i].data(),
412 fl::span<const u8>() // No padding
413 };
414 }
415
416 transpose_ok = SPITransposer::transpose8(lanes, dma_buffer.data(), &error);
417 }
418
419 if (!transpose_ok) {
420 FL_WARN("MultiLaneDevice: Transposition failed - " << (error ? error : "unknown error"));
421 return Result<void>::failure(SPIError::ALLOCATION_FAILED,
422 error ? error : "Transposition failed");
423 }
424
425 // Transmit via hardware backend - use polymorphic interface
426 bool transmit_ok = pImpl->backend->transmit(TransmitMode::ASYNC);
427
428 if (!transmit_ok) {
429 FL_WARN("MultiLaneDevice: Hardware transmit failed");
430 return Result<void>::failure(SPIError::BUSY,
431 "Hardware transmit failed");
432 }
433
434 // Clear lane buffers after starting transmission
435 for (auto& lane : pImpl->lanes) {
436 lane.clear();
437 }
438
439 FL_DBG("MultiLaneDevice: Flushed " << pImpl->lanes.size() << " lanes ("
440 << max_size << " bytes per lane)");
441
442 // Success - transmission started asynchronously
443 // User must call waitComplete() manually to block until transmission completes
444 return Result<void>::success();
445}
static bool transpose8(const fl::optional< LaneData > lanes[8], fl::span< u8 > output, const char **error=nullptr) FL_NOEXCEPT
Transpose 8 lanes of data into interleaved octal-SPI format.
static bool transpose4(const fl::optional< LaneData > &lane0, const fl::optional< LaneData > &lane1, const fl::optional< LaneData > &lane2, const fl::optional< LaneData > &lane3, fl::span< u8 > output, const char **error=nullptr) FL_NOEXCEPT
Transpose 4 lanes of data into interleaved quad-SPI format.
static bool transpose2(const fl::optional< LaneData > &lane0, const fl::optional< LaneData > &lane1, fl::span< u8 > output, const char **error=nullptr) FL_NOEXCEPT
Transpose 2 lanes of data into interleaved dual-SPI format.
static expected failure(E err, const char *msg=nullptr) FL_NOEXCEPT
Create error result.
Definition expected.h:115
static expected success(T value) FL_NOEXCEPT
Create successful result.
Definition expected.h:108
constexpr fl::size size() const FL_NOEXCEPT
Definition span.h:458
bool isReady() const
Check if device is initialized.
Lane & lane(size_t lane_id)
Get access to a specific lane.
fl::unique_ptr< Impl > pImpl
#define FL_WARN(X)
Definition log.h:276
#define FL_DBG
Definition log.h:388
Optional< T > optional
Definition optional.h:16

References fl::span< T, Extent >::data(), fl::expected< T, E >::failure(), FL_DBG, FL_WARN, isReady(), lane(), pImpl, fl::span< T, Extent >::size(), fl::expected< T, E >::success(), fl::SPITransposer::transpose2(), fl::SPITransposer::transpose4(), and fl::SPITransposer::transpose8().

Referenced by operator=(), and writeImpl().

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