Repository navigation
Architecture
0.9.4 stable note: the final architecture keeps BLE wire formats stable, delegates optional sound to the standalone WLED Buzzer Usermod, and uses board-specific PSRAM media policies on Waveshare and MatrixPortal S3. The final release also hardens Schedule multipart publication and Alarm persistence without changing the qualified media protocol.
The Usermod is designed as a compatibility layer, not as an alternative WLED display driver.
iDotMatrix app / BLE
↓
BLEServer receive queue
↓
FA02 logical-packet assembler
↓
protocol parser
↓
feature-specific transaction
(Bulk / Graffiti / automation / Carousel / Preset)
↓
renderer / media state
↓
logical RGB canvas
↓
iDotMatrix WLED effect
↓
WLED 2D pixel model
↓
physical LED/HUB75 backend
-
IDotMatrixBLEServer— GATT services, advertising, bounded receive queue and dispatch. -
IDotMatrixFA02Assembler— ATT-fragment to logical-FA02 reassembly, maximum 8192 bytes. -
IDotMatrixProtocol— command decoding, ACK generation, Clock/timer state and Graffiti multipart transaction. -
IDotMatrixBulkTransfer— normal 16-byte Bulk transport and CRC32 state. -
IDotMatrixRenderer— logical canvas, effects, TEXT, Clock, timers and raw-image staging. -
IDotMatrixMedia/IDotMatrixCompactGif— image/GIF decoding paths. -
IDotMatrixGifSourceStage— ownership, guards, reuse cache, one-item prefetch and telemetry for whole-file GIF sources staged in PSRAM on eligible targets.
gifStage peak is the largest source image that has actually become active for AnimatedGIF since boot, including persistent/prefetched cache hits. This preserves gifStage peak >= gifStage bytes without conflating normal stage counters with cache activation. MatrixPortal uses a 256 KiB transient stage maximum, 1 MiB reserve, 384 KiB persistent cache, 256 KiB per-entry limit and 8 metadata entries; Waveshare uses the larger qualified 2 MiB stage / 4 MiB reserve / 1 MiB cache policy.
-
IDotMatrixCarousel— persistent Device Assets bank. -
IDotMatrixPreset— volatile staged/active Preset playlist. -
IDotMatrixAutomation— alarms and programs/schedules. -
IDotMatrixAudioSource— optional WLED AudioReactive bridge. -
IDotMatrixWLEDAdapter— WLED state/ownership integration. -
usermod_idotmatrix.cpp— Usermod lifecycle, configuration and diagnostics.
The 0.9.3 line removes the internal buzzer engine and all electrical/timing ownership from iDotMatrix. IDotMatrixAutomation publishes only logical Alarm and Program/Schedule sound intent; the top-level Usermod also collects Countdown completion, BLE connection and BLE disconnection events.
iDotMatrix does not include WLEDBuzzerService.h. IDotMatrixBuzzerBridge.h weak-links the RC7 extern "C" service ABI, so a firmware containing only iDotMatrix remains buildable even if the Buzzer repository exists beside WLED. When the bridge is present and ready, Alarm requests looping triple_beep, Program/Schedule requests notification, Countdown requests triple_beep, BLE connection requests connect, and BLE disconnection requests disconnect. When the bridge is absent, iDotMatrix continues normally with its Buzzer Enable control disabled.
The standalone Buzzer Usermod is the sole owner of GPIO allocation, Active/Passive hardware, polarity, LEDC, volume, sound definitions and playback scheduling.
BLE fragmentation and application multipart are separate. The FA02 assembler first produces one complete logical packet. Feature-specific code can then combine multiple complete FA02 packets into one object.
The 0.9.1 Graffiti path is the clearest example:
ATT writes -> 4105-byte FA02 packet -> 4096 RGB bytes
ATT writes -> 4105-byte FA02 packet -> 4096 RGB bytes
ATT writes -> 4105-byte FA02 packet -> 4096 RGB bytes
↓
12288-byte raster
The renderer receives those chunks through raw-image staging, so the protocol layer does not need a second 12288-byte full-raster buffer.
WLED and the iDotMatrix compatibility layer share one physical display. Selecting native WLED content releases iDotMatrix display ownership. A later supported iDotMatrix content command reclaims the iDotMatrix effect.
Live content suspends autonomous Carousel/Preset playback when appropriate. Live TEXT from the app suspends both players; TEXT rendered internally by Preset/Carousel uses the same parser without self-suspending.
LittleFS is shared with WLED, but iDotMatrix cleanup is namespace-scoped. Carousel, Preset, automation and caches manage only their own files. Hardware validation confirmed that unrelated WLED/PixelForge images survive Carousel/Preset operations and iDotMatrix reset. See Media Storage.
For IDOT_WAVESHARE_S3_RGB_MATRIX, direct AnimatedGIF playback can copy an eligible GIF source into PSRAM before the decoder opens it. IDotMatrixGifSourceStage owns the active staged byte image, safety guards/counters and the bounded persistent reuse cache for durable Carousel GIFs. The normal stage maximum remains 2 MiB and every new source allocation must preserve a 4 MiB free-PSRAM reserve. Files are copied in 4096-byte chunks with scheduler yields; the existing AnimatedGIF callbacks then resolve reads and seeks against the active PSRAM image.
The non-owning one-item look-ahead path runs after the current Carousel item becomes visible. After approximately 250 ms, the Carousel offers only the immediately following playable GIF to IDotMatrixGifSourceStage::prefetch(). Prefetch never releases or replaces the active decoder source; it allocates a separate future-source buffer and admits it to the same LRU cache. The active entry remains protected from eviction. A following TEXT item stops look-ahead for the current dwell, and any prefetch failure is advisory only: normal playback staging/reuse remains authoritative.
The persistent cache is separately bounded to 1 MiB total, 512 KiB per admitted source and 12 metadata entries, with LRU eviction. A source too large for persistent admission may still use the normal one-play stage. App-upload/transient /idot_play.gif remains outside persistent reuse.
The filesystem is authoritative. Full Carousel reset/reconfiguration clears resident sources and committed slot replacement invalidates the corresponding path, including same-size replacements. If an entry is invalidated while active, retirement is deferred until AnimatedGIF closes. Under PSRAM pressure, resident LRU entries are expendable and are retired before the normal staging path gives up its reserve/allocation check.
This remains source-level I/O optimization only: decoded frames are not retained on the Waveshare direct path, GIF timing is unchanged, and Carousel order/dwell ownership is unchanged. The no-PSRAM filesystem frame-cache backend remains separate. Dev.10 adds gifSourceCache=... hit/miss/store/eviction/invalidation telemetry; cache hits intentionally do not increment gifStage attempts/ok.
- FA02 has bounded permanent inline storage plus temporary expansion up to 8192 bytes.
- Large TEXT is dynamically allocated only during transfer/playback and prefers PSRAM on ESP32-S3.
- Graffiti full-raster chunks stream directly into raw-image staging.
- GIF backend selection depends on profile and memory; low-memory targets can use LittleFS frame caching.
- The C3 OTA layout reserves flash for two application slots; it does not materially change the runtime DRAM model.
The iDotMatrix logical profile is independent from the physical WLED matrix. Supported 16x16/32x32/64x64 combinations use nearest-neighbour upscale and box-average downscale as needed. WLED remains responsible for physical wiring, serpentine mapping, panel layout, rotation and mirroring. On the native Waveshare and MatrixPortal S3 HUB75 profiles this automatic output scaling is the only scaling control exposed to the user; the legacy low-memory rescale storage mode is compile-time disabled.
Structural changes such as enabling/disabling the Usermod are restart-required rather than attempting hot teardown/reinitialization of BLE and dependent state.
The optional consumer bridge intentionally exposes only the operations currently required by iDotMatrix: readiness, playing state, named-sound playback, stop and current sound ID. playRepeat, raw beep and raw tone are not required by the current event mapping because Alarm repeat uses the loop flag of named-sound playback.
iDotMatrix WLED Usermod 0.9.4 — stable release
- Home
- Release 0.9.4
- Release 0.9.3
- Release 0.9.2
- Release 0.9.1
- Release 0.9.0
- Getting Started
- Hardware
- Implementation
- Build / Validation