| 299 | } |
| 300 | |
| 301 | Result<void> MultiLaneDevice::flush() { |
| 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()) { |
nothing calls this directly
no test coverage detected