7#include "platforms/shared/spi_manager.h"
8#include "platforms/shared/spi_hw_1.h"
9#include "platforms/shared/spi_hw_2.h"
10#include "platforms/shared/spi_hw_4.h"
23 FL_LOG_SPI(
"SPI Device: Created with clock=" << config.clock_pin <<
" data_pins.size()=" << config.data_pins.size());
29 FL_LOG_SPI(
"SPI Device: Calling end() from destructor");
33 FL_LOG_SPI(
"SPI Device: Checking owned hardware backend");
37 FL_LOG_SPI(
"SPI Device: Cleaning up owned hardware backend");
38 pImpl->hw_backend->end();
39 pImpl->hw_backend =
nullptr;
49 if (
pImpl->initialized) {
55 if (
pImpl->config.spi_mode > 3) {
56 FL_WARN(
"SPI Device: Invalid SPI mode " <<
pImpl->config.spi_mode <<
" (must be 0-3)");
62 if (
pImpl->config.spi_mode != 0) {
63 FL_WARN(
"SPI Device: SPI mode " <<
pImpl->config.spi_mode <<
" requested but hardware layer only supports mode 0 - ignoring");
67 SPIBusManager& mgr = getSPIBusManager();
68 int data_pin =
pImpl->config.data_pins.empty() ? -1 :
pImpl->config.data_pins[0];
69 pImpl->bus_handle = mgr.registerDevice(
70 pImpl->config.clock_pin,
72 pImpl->config.clock_speed_hz,
76 if (!
pImpl->bus_handle.is_valid) {
77 FL_WARN(
"SPI Device: Failed to register with bus manager");
82 if (!mgr.initialize()) {
83 FL_WARN(
"SPI Device: Bus initialization failed");
88 const SPIBusInfo* bus_info = mgr.getBusInfo(
pImpl->bus_handle.bus_id);
89 if (bus_info && bus_info->bus_type == SPIBusType::SINGLE_SPI && !bus_info->hw_controller) {
92 if (controllers.
empty()) {
93 FL_WARN(
"SPI Device: No SpiHw1 controllers available on this platform");
100 SpiHw1::Config hw_config;
101 hw_config.clock_pin =
pImpl->config.clock_pin;
102 hw_config.data_pin =
pImpl->config.data_pins.empty() ? -1 :
pImpl->config.data_pins[0];
103 hw_config.clock_speed_hz =
pImpl->config.clock_speed_hz;
104 hw_config.bus_num = 0;
106 if (!hw->begin(hw_config)) {
107 FL_WARN(
"SPI Device: Failed to initialize SpiHw1 controller");
111 pImpl->hw_backend = hw;
112 pImpl->owns_backend =
false;
113 FL_LOG_SPI(
"SPI Device: Created SpiHw1 controller for SINGLE_SPI mode");
116 pImpl->hw_backend = bus_info ? bus_info->hw_controller :
nullptr;
117 pImpl->owns_backend =
false;
120 pImpl->initialized =
true;
121 FL_LOG_SPI(
"SPI Device: Initialized successfully");
137 pImpl->hw_backend =
nullptr;
140 if (
pImpl->bus_handle.is_valid) {
141 SPIBusManager& mgr = getSPIBusManager();
142 mgr.unregisterDevice(
pImpl->bus_handle);
143 pImpl->bus_handle = SPIBusHandle();
146 pImpl->initialized =
false;
187 if (!data || size == 0) {
192 if (
pImpl->async_state.active) {
199 FL_WARN(
"SPI Device: Failed to acquire DMA buffer for async write");
205 if (buf_span.
size() < size) {
206 FL_WARN(
"SPI Device: Buffer size mismatch");
210 for (
size_t i = 0; i < size; i++) {
211 buf_span[i] = data[i];
217 FL_WARN(
"SPI Device: Failed to start async transmission");
222 pImpl->async_state.active =
true;
223 pImpl->async_state.tx_buffer = data;
224 pImpl->async_state.rx_buffer =
nullptr;
225 pImpl->async_state.size = size;
231 txn.
pImpl->completed =
false;
233 FL_LOG_SPI(
"SPI Device: Async write started (" << size <<
" bytes)");
259 return DMABuffer(SPIError::NOT_INITIALIZED);
263 if (!
pImpl->hw_backend) {
264 FL_WARN(
"SPI Device: No hardware controller available");
265 return DMABuffer(SPIError::NOT_INITIALIZED);
269 SpiHwBase* hw =
pImpl->hw_backend.get();
273 DMABuffer buffer = hw->acquireDMABuffer(size);
276 FL_WARN(
"SPI Device: Failed to acquire DMA buffer from hardware");
278 FL_LOG_SPI(
"SPI Device: Acquired DMA buffer (" << size <<
" bytes)");
294 if (!
pImpl->hw_backend) {
295 FL_WARN(
"SPI Device: No hardware controller available");
300 SpiHwBase* hw =
pImpl->hw_backend.get();
303 TransmitMode mode = async ? TransmitMode::ASYNC : TransmitMode::SYNC;
304 bool success = hw->transmit(mode);
307 FL_WARN(
"SPI Device: Transmission failed");
313 if (!hw->waitComplete()) {
314 FL_WARN(
"SPI Device: Wait for completion failed");
319 FL_LOG_SPI(
"SPI Device: Transmission started (" << ((async ?
"async" :
"blocking")) <<
")");
329 if (!
pImpl->hw_backend) {
330 FL_WARN(
"SPI Device: No hardware controller available");
335 SpiHwBase* hw =
pImpl->hw_backend.get();
337 return hw->waitComplete(timeout_ms);
346 if (!
pImpl->hw_backend) {
351 SpiHwBase* hw =
pImpl->hw_backend.get();
362 pImpl->config.clock_speed_hz = speed_hz;
368 if (
pImpl->initialized) {
369 FL_LOG_SPI(
"SPI Device: Clock speed updated to " << speed_hz <<
" Hz (will take effect on next begin())");
371 FL_LOG_SPI(
"SPI Device: Clock speed set to " << speed_hz <<
" Hz");
379 return pImpl->config;
393 if (
this != &other) {
402 if (!
pImpl->completed) {
413 if (
pImpl->completed) {
417 if (
pImpl->cancelled) {
418 pImpl->completed =
true;
423 if (!
pImpl->device) {
424 pImpl->completed =
true;
429 if (!
pImpl->device->isReady()) {
430 pImpl->completed =
true;
435#ifdef FASTLED_LOG_SPI_ENABLED
439 bool success =
pImpl->device->waitComplete(timeout_ms);
443 if (
pImpl->device->pImpl) {
444 pImpl->device->pImpl->async_state.active =
false;
446 pImpl->completed =
true;
449#ifdef FASTLED_LOG_SPI_ENABLED
450 FL_LOG_SPI(
"Transaction: Completed successfully (waited " << (
fl::millis() - start_time) <<
"ms)");
455 pImpl->completed =
true;
457 FL_WARN(
"Transaction: Timeout after " << timeout_ms <<
"ms");
479 pImpl->cancelled =
true;
480 pImpl->completed =
true;
485 pImpl->device->pImpl->async_state.active =
false;
496 return pImpl->result;
Multi-lane SPI interface for LED output Hardware (SPI_HW): 1-8 parallel data lanes Software (SPI_BITB...
FastLED chrono implementation - duration types for time measurements.
static expected failure(E err, const char *msg=nullptr) FL_NO_EXCEPT
Create error result.
static expected success(T value) FL_NO_EXCEPT
Create successful result.
const T * data() const FL_NO_EXCEPT
constexpr fl::size size() const FL_NO_EXCEPT
fl::optional< fl::task::Error > setClockSpeed(u32 speed_hz) FL_NO_EXCEPT
Update clock speed.
bool isBusy() const FL_NO_EXCEPT
Check if async operation is in progress.
const Config & getConfig() const FL_NO_EXCEPT
Get current configuration.
bool waitComplete(u32 timeout_ms=(fl::numeric_limits< u32 >::max)()) FL_NO_EXCEPT
Wait for pending async operation to complete.
bool isReady() const FL_NO_EXCEPT
Check if device is initialized and ready for use.
Device(const Config &config) FL_NO_EXCEPT
Construct SPI device with configuration.
~Device() FL_NO_EXCEPT
Destructor - releases hardware resources.
fl::unique_ptr< Impl > pImpl
Result< Transaction > writeAsync(const u8 *data, size_t size) FL_NO_EXCEPT
Begin asynchronous write operation (returns immediately)
void end() FL_NO_EXCEPT
Shutdown the SPI hardware and release resources.
DMABuffer acquireBuffer(size_t size) FL_NO_EXCEPT
Acquire DMA-capable buffer for zero-copy transmission.
fl::optional< fl::task::Error > begin() FL_NO_EXCEPT
Initialize the SPI hardware.
fl::optional< fl::task::Error > transmit(DMABuffer &buffer, bool async=true) FL_NO_EXCEPT
Transmit from previously acquired DMA buffer.
fl::unique_ptr< Impl > pImpl
bool isDone() const FL_NO_EXCEPT
Check if transaction is complete.
~Transaction()
Destructor - automatically waits for completion.
Transaction(Transaction &&other) FL_NO_EXCEPT
bool isPending() const FL_NO_EXCEPT
Check if transaction is still in progress.
fl::optional< fl::task::Error > getResult() const FL_NO_EXCEPT
Get result of completed transaction.
Transaction() FL_NO_EXCEPT
bool wait(u32 timeout_ms=(fl::numeric_limits< u32 >::max)()) FL_NO_EXCEPT
Wait for transaction to complete.
bool cancel() FL_NO_EXCEPT
Cancel pending transaction (if supported by platform)
Transaction & operator=(Transaction &&other) FL_NO_EXCEPT
bool empty() const FL_NO_EXCEPT
#define FL_LOG_SPI(...)
Serial Peripheral Interface (SPI) logging Logs SPI configuration, initialization, and transfers.
Private implementation details for fl::spi::Device.
Centralized logging categories for FastLED hardware interfaces and subsystems.
constexpr remove_reference< T >::type && move(T &&t) FL_NO_EXCEPT
fl::enable_if<!fl::is_array< T >::value, unique_ptr< T > >::type make_unique(Args &&... args) FL_NO_EXCEPT
fl::result< T, SPIError > Result
u8 u8 fract8 blur_amount FL_NO_EXCEPT
fl::u32 millis() FL_NO_EXCEPT
Universal millisecond timer - returns milliseconds since system startup.
constexpr nullopt_t nullopt
Base definition for an LED controller.