| 43 | } |
| 44 | |
| 45 | fl::optional<fl::task::Error> Device::begin() { |
| 46 | if (!pImpl) { |
| 47 | return fl::task::Error("Device not initialized"); |
| 48 | } |
| 49 | |
| 50 | if (pImpl->initialized) { |
| 51 | // Already initialized - idempotent |
| 52 | return fl::nullopt; |
| 53 | } |
| 54 | |
| 55 | // Validate SPI mode (0-3 for CPOL/CPHA combinations) |
| 56 | if (pImpl->config.spi_mode > 3) { |
| 57 | FL_WARN("SPI Device: Invalid SPI mode " << pImpl->config.spi_mode << " (must be 0-3)"); |
| 58 | return fl::task::Error("Invalid SPI mode"); |
| 59 | } |
| 60 | |
| 61 | // Note: SPI mode configuration is not yet supported by the hardware layer |
| 62 | // All devices currently operate in mode 0 (CPOL=0, CPHA=0) |
| 63 | if (pImpl->config.spi_mode != 0) { |
| 64 | FL_WARN("SPI Device: SPI mode " << pImpl->config.spi_mode |
| 65 | << " requested but hardware layer only supports mode 0 - ignoring"); |
| 66 | } |
| 67 | |
| 68 | // Register with SPIBusManager |
| 69 | SPIBusManager& mgr = getSPIBusManager(); |
| 70 | int data_pin = pImpl->config.data_pins.empty() ? -1 : pImpl->config.data_pins[0]; |
| 71 | pImpl->bus_handle = mgr.registerDevice( |
| 72 | pImpl->config.clock_pin, |
| 73 | data_pin, |
| 74 | pImpl->config.clock_speed_hz, |
| 75 | this // controller pointer |
| 76 | ); |
| 77 | |
| 78 | if (!pImpl->bus_handle.is_valid) { |
| 79 | FL_WARN("SPI Device: Failed to register with bus manager"); |
| 80 | return fl::task::Error("Failed to register with bus manager"); |
| 81 | } |
| 82 | |
| 83 | // Initialize the bus |
| 84 | if (!mgr.initialize()) { |
| 85 | FL_WARN("SPI Device: Bus initialization failed"); |
| 86 | return fl::task::Error("Bus initialization failed"); |
| 87 | } |
| 88 | |
| 89 | // Check if we need to create our own SpiHw1 controller (SINGLE_SPI/passthrough mode) |
| 90 | const SPIBusInfo* bus_info = mgr.getBusInfo(pImpl->bus_handle.bus_id); |
| 91 | if (bus_info && bus_info->bus_type == SPIBusType::SINGLE_SPI && !bus_info->hw_controller) { |
| 92 | // Create and initialize a SpiHw1 controller |
| 93 | const fl::vector<fl::shared_ptr<SpiHw1>>& controllers = SpiHw1::getAll(); |
| 94 | if (controllers.empty()) { |
| 95 | FL_WARN("SPI Device: No SpiHw1 controllers available on this platform"); |
| 96 | return fl::task::Error("No SpiHw1 controllers available"); |
| 97 | } |
| 98 | |
| 99 | // Use the first available controller (could be improved with bus number selection) |
| 100 | fl::shared_ptr<SpiHw1> hw = controllers[0]; |
| 101 | |
| 102 | SpiHw1::Config hw_config; |