Common, platform‑agnostic components used by multiple targets (data export, UI, SPI drivers).
active_strip_data/: Zero‑copy strip data export and screenmap tracking across frames. Seeactive_strip_data.hforActiveStripDatamanager and JSON helpers.ui/: JSON‑driven UI system.ui/json/containsJsonUiManager, components (Slider, Button, Checkbox, Dropdown, NumberField, Audio, Title, Description), and integration guide (readme.md).
Shared platform code includes multi-lane SPI transposer infrastructure supporting 1/2/4/8 parallel data lanes:
NEW: Unified bit-interleaving driver for all parallel SPI widths. Transposes sequential pixel data into parallel bitstreams for simultaneous multi-strip output.
Supported Widths:
- 1-lane (single-SPI)
- 2-lane (dual-SPI) via
transpose2() - 4-lane (quad-SPI) via
transpose4() - 8-lane (octo-SPI) via
transpose8()✨
Key Features:
- Single unified API: All transpose operations in
SPITransposerclass - Consistent naming:
transpose2(),transpose4(),transpose8()methods - Optimized algorithms: Width-specific interleaving for each configuration
- Platform-agnostic: Used by both hardware and software implementations
- Zero-copy operation: Efficient memory handling
Legacy Compatibility:
spi_transposer_dual.*- Deprecated wrappers for 2-lane (callstranspose2())spi_transposer_quad.*- Deprecated wrappers for 4-lane/8-lane (callstranspose4()/transpose8())
Platform-independent SPI configuration APIs organized by lane count:
Interfaces:
spi_hw_1.h- Single-lane SPI (SpiHw1)spi_hw_2.h- Dual-lane SPI (SpiHw2)spi_hw_4.h- 4-lane SPI (SpiHw4)spi_hw_8.h- 8-lane SPI (SpiHw8) ✨ NEW
Example Configuration:
namespace fl {
struct SpiHw8 {
struct Config {
uint8_t data0, data1, data2, data3; // First 4 data pins
uint8_t data4, data5, data6, data7; // Next 4 data pins (8-lane)
uint8_t clock; // Shared clock pin
// ... other config
};
};
}Configuration supports:
- Explicit lane count per interface (no ambiguity)
- Clock pin assignment
- Hardware vs software fallback selection
- Per-platform capabilities detection
The transposer and interfaces are used by both:
- Hardware SPI (ESP32-P4 octal, ESP32 quad): DMA-accelerated, ~40× faster
- Software SPI (bitbang ISR/blocking): Platform-agnostic fallback for all platforms
See platform-specific READMEs for implementation details:
src/platforms/esp/32/README.md- ESP32 hardware multi-lane SPIsrc/platforms/shared/spi_bitbang/README.md- Software multi-width SPI
ActiveStripDatalistens toEngineEventsto clear and publish per‑frame data; exposes legacy and new JSON creators and parsing helpers, plus on‑demand screenmap updates.- The UI system uses weak pointers for safe component lifecycle, and a manager that batches outbound JSON and applies inbound updates on frame boundaries.
- During
show(), the driver renders pixels. When the frame completes,EngineEvents::onEndShowLedsfires. ActiveStripDatalistens and clears per‑frame accumulators, then snapshots strip/screenmap data for export.- The platform bridge pulls JSON or raw buffers (depending on target) and forwards them to the UI/consumer.
- After UI updates arrive,
EngineEvents::onEndFrameapplies any pending control changes via the UI manager.
Bridge stub outline:
// Pseudocode for a host bridge loop
void pump() {
if (auto json = ActiveStripData::createLegacyJson(/*alloc*/)) {
platform_send_json(json.ptr);
ActiveStripData::freeJson(json.ptr);
}
if (auto incoming = platform_recv_ui_json()) {
JsonUiManager::instance().updateUiComponents(incoming);
}
}