FastLED 3.10.8
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 300 of file multi_lane_device.cpp.hpp.

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

References fl::span< T, Extent >::data(), fl::expected< T, E >::failure(), FL_DBG, fl::FL_NO_EXCEPT, 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=().

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