An additive fork of WLogicEngine32 — the RSeries Logic Engine firmware, originally written by Joymonkey (Paul Murphy) and updated and maintained by Rimim (Mimir Reynisson).
Almost everything in this repository is their work. This fork adds one small layer (about 700 lines across two headers plus a host test harness) so an external tool can drive the logic displays in time with music. Everything the firmware already did, it still does, unchanged.
reeltwo/WLogicEngine32 is the firmware for the WReactor32 board (ESP32 / Lolin D32 Pro) that runs the RSeries Logic Engine dome lighting kit — the front and rear logic displays on an astromech droid. It came out of the astromech.net parts runs, and it descends from Joymonkey's original logicengine project, which started this whole lineage.
If you use this fork, go star and support the original. Some specific things in it that are worth your attention:
-
It is built on Reeltwo (also by Rimim), which is a genuinely good piece of embedded C++: a whole device and animation framework with a clean renderer abstraction (
LogicEngineRenderer), a sequence system, Marcduino/JawaLite command dispatch, and a settings/menu stack. It is vendored here inlib/Reeltwo. -
The extension seam is why this fork is so small. Reeltwo exposes
CustomLogicEffectSelector: any sequence id at or above 100 is handed off to firmware-supplied effect functions. Rimim designed a hook for exactly this kind of addition years ago, so our whole render layer plugs in as effect id 106 without modifying a single line of the vendored library. That is good API design paying off later for a stranger, and it is the nicest thing in this fork. -
Firmware updates without a toolchain. Drop
LEngine.binon an SD card, power up, and the board flashes itself (or update over the air through the built-in web interface). The average builder never needs to install Arduino or PlatformIO to take an update. That is real thoughtfulness about the actual person holding the droid. -
Configuration on the board itself. Colours, brightness and pattern speeds are adjustable with the buttons and trimpot, no computer required.
The upstream project's own README is preserved here as README_UPSTREAM.md —
that is where the real firmware documentation lives (Marcduino commands, ~RTLE sequence codes,
WiFi setup, colour tables). Read that first. This README only covers what the fork adds.
No code in this fork has ever run on a real board. Not once.
Be precise about what is and is not verified, because the two are easy to blur:
What IS verified. It cross-compiles for the real microcontroller. pio run builds a complete
ESP32 firmware image with the real xtensa toolchain, and the real linker signs off on it:
1,132,213 B of flash (57.6%) and 63,324 B of SRAM (19.3%). Plus bash test/host/run.sh — 341
checks against the wire parser, beat clock and effect math, plus a type-check of the render layer
against a mock of the engine API, and it now finishes by doing that cross-compile itself.
This used to say the code had never been compiled for the ESP32 at all, and that was the honest
state. It is no longer. It is worth saying why it matters: the first real build immediately caught a
bug no mock could see — FastLED declares RGB as an enumerator of fl::EOrder, which name-hides a
struct RGB, and our shared contract core defined exactly that struct. It could never have compiled
on this board. The mock did not model EOrder, so the type-check passed happily for months.
What is NOT verified. Everything only a real board can tell you. A successful link is not a bench test. No bench flash, no scope, no LEDs, no droid. No timing, no brightness, no current draw has ever been observed. The code has never executed a single instruction outside a host test.
Both environments now build. wlogicengine32s3 (ESP32-S3) previously could not be built at all,
and an earlier revision of this README explained that with a claim that was simply wrong — it said
the platform pin was shared with the working ESP32 env, so recovering the S3 would drag that env's
toolchain along with it. It is not shared. platform = is declared per-environment (there is no
[env] section and [common] is empty), so the two are independent, coincidentally-identical lines.
The S3 could always have been re-pinned at zero risk. Correcting the record.
What was actually broken was two things, one hiding under the other:
platform-espressif32v5.2.0 makestoolchain-riscv32-espnon-optional for the S3 (it is the RISC-V ULP coprocessor toolchain) and pins it to8.4.0+2021r2-patch3— which the PlatformIO registry has since unpublished. Only that exact patch level was pruned;patch5is still served, so the env now pinspatch5viaplatform_packages, in the S3 env alone. The plain-ESP32 env never requests riscv32, which is exactly why it kept building. The ULP toolchain is inert here anyway: there is noulp/source and every object is compiled byxtensa-esp32s3-elf-g++.- Underneath that, the S3 env pulled FastLED from unpinned git master. It now uses the vendored
lib/FastLED3.5.0, same as the ESP32 env.
wlogicengine32 is provably unaffected: it still links at exactly 1,132,213 B, the same byte count as
before the change. The platform stays on v5.2.0 — no bump, no new toolchain, nothing to re-validate.
But a compile is not a run, and the S3 env has almost certainly never worked. It is a fork-local
hand-translation of upstream's make TARGET=ESP32S3 (upstream has no S3 PlatformIO env at all), and
it carries at least three hardware-config guesses a green build cannot catch: ARDUINO_USB_CDC_ON_BOOT
is not set, so with the board's ARDUINO_USB_MODE=1 the Serial console maps to UART0 rather than
the USB port — on a board whose only console is USB, this image would very likely just look silent;
BOARD_HAS_PSRAM is declared on a devkit profile that has none; and board = esp32-s3-devkitc-1 is a
generic devkit standing in for a WReactor32-2023. Treat the S3 target as "it compiles", nothing more.
Before this goes anywhere near a droid: bench it on a bare board with the display panels disconnected from anything you care about, and check current draw. The stock firmware from upstream is the safe, proven thing; this is not, yet.
A Driveable-Animation Contract: a small wire grammar so a host (Cantina Studio — a music analysis and dome lighting authoring tool) can drive the logic displays in time with a song.
!<cls><unit><verb>[:k=v,k=v,...]
cls L = logic displays P = PSI H = holoprojectors * = all
unit F = front R = rear T = top/HP * = all
verb A = animate (set the base look) P = pulse (a beat accent)
C = beat-clock seed B = brightness
L = level (energy 0-255) X = stop
M = mode (show / idle) Q = query
example: !LFA:i=comet,c=ff8800,s=200,m=64,am=1
front logics -> comet, orange, fast, beat-modulated
The ! prefix was chosen because every stock board parser already ignores it. That is the whole
trick, and it is what makes this layer additive rather than invasive.
What it buys:
- Arbitrary RGB (
c=ff8800), not just the palette indices the native commands take. - Beat-locked accents — the host seeds a beat clock (
!**C:bpm=,ph=,bpb=) once and the board stays in phase with the music on its own. - Autonomous section playback — the host pushes a compact "score" (looks scheduled at beat indices), then the board plays the whole song by itself with no further traffic.
- Six new parametric effects rendered along a per-board 1-D strand:
comet,chase,wipe,gradient,colorcycle,twinkle— alongsidesolid,flash,rainbow,scan,sparkle,meter, and anative:<code>escape hatch that hands a section straight back to an iconic stock sequence.
Every native command still works exactly as before. ~RTLE…, @nT…, #LE…, JawaLite, the web
interface, the SD-card updater, the menus — all untouched. This is backward-compatible and it is not
a rewrite. If you never send a ! command, this firmware behaves like the stock firmware.
Three layers, in the order they were written. The middle one matters: some of what is in this tree is neither upstream's nor part of the contract layer.
Theirs — the firmware itself, and the great majority of the code here:
src/main.cpp(1,415 lines — this is upstream'sWLogicEngine32.ino, relocated),WebPages.h,MarcduinoLogics.h,logic-sequences.h,pin-config.h,Screens.h,web-images.h,effects/,menus/,Makefile,platformio.ini— Joymonkey and Rimim, with contributions from IOIIOOO, Curiousmarc, Mowee, Flthymcnasty and others.lib/Reeltwo— Rimim.lib/FastLED,lib/Adafruit_NeoPixel— their respective authors.README_UPSTREAM.md— upstream's own README, preserved here.
A few of those files carry in-place edits made downstream (see the next block); the code in them is upstream's.
Earlier C2B5 droid customization (Travis Cook, pre-dating this fork) — downstream work that came with the tree this fork was seeded from. It is not upstream's:
| Path | What it is |
|---|---|
data/modern/ |
The C2B5 web UI — index.html and wifi.html, the only tracked files under data/. |
scripts/ |
PlatformIO build hooks, the HTML-to-header compressor that embeds that UI, and a JavaScript validator. |
visualizer/ |
A browser LED-matrix preview tool for the FLD/RLD displays ("author": "C2B5 Project"). Not firmware; not upstream. |
README_C2B5.md, docs/C2B5_CUSTOMIZATIONS.md, wapi_test_routes.h, wapi_debugging_guide.md, root package.json, .clang-tidy |
Notes, debug routes and tooling from the same work. |
| in-place edits | src/main.cpp (multi-network WiFi with priorities, RSeries.local mDNS, SSID URL-decoding, C2B5 debug output), WebPages.h, platformio.ini, and the two lib/Reeltwo/src/wifi/ headers (WifiAccess.h, WifiWebServer.h), which carry an LGPL-2.1 §2(b) modified-file notice at the top. |
None of that is upstream's, and none of it is part of the contract layer. It is described in README_C2B5.md and docs/C2B5_CUSTOMIZATIONS.md.
Ours (Travis Cook, 2026) — the fork layer this repository exists for:
| Path | What it is | Lines |
|---|---|---|
src/contract/contract_core.h |
Pure, dependency-free C++: wire parser, beat clock, effect math, score table. No Arduino, no FastLED, no Reeltwo. Byte-identical across the three DroidNet board forks. | 362 |
src/contract/ContractLogics.h |
The RSeries render layer: maps the contract onto this board's LED primitives, registers as custom effect id 106. | 337 |
test/host/* |
The host test harness (parser tests, engine mock, type-check). | 506 |
src/main.cpp |
Four added lines and one bounds-check fix. An #include, ContractRender appended to the custom-effect table, contractSetup() in setup(), contractTick() in mainLoop(). |
+7 / −2 |
DROIDNET_FORK.md, this README |
Fork docs. | — |
The bounds-check fix in main.cpp is a one-character change to a pre-existing off-by-one in the
custom-effect selector (selectSequence-100 <= SizeOfArray(...) read one slot past the array). It
was latent upstream because nothing ever selected the last id; adding effect 106 would have hit it.
That is the only line of upstream code this fork changes.
Run git diff 6bba8b1..HEAD --stat if you want the exact split (6bba8b1 is the baseline import):
13 files, 1,757 insertions, 183 deletions (the deletions are almost entirely the documentation
rewrite; only two are code, both in src/main.cpp). Nine of those files are code — the six new ones above, the
seven-line edit to src/main.cpp, and comment-only LGPL §2(b) notices on the two vendored Reeltwo
headers. The other four are documentation (this README, README_UPSTREAM.md, DROIDNET_FORK.md,
README_C2B5.md).
- Upstream:
reeltwo/WLogicEngine32, by Joymonkey and Rimim, on top of Rimim's Reeltwo library. LGPL-2.1. - A private working collection in which this firmware was customized for one specific droid
(call sign C2B5): better WiFi and AP-mode handling, multi-network support with priorities, an
RSeries.localmDNS hostname, SSID URL-decoding, and a modern web UI. Those changes are documented in README_C2B5.md and docs/C2B5_CUSTOMIZATIONS.md, and they are the reason two files underlib/Reeltwocarry a "modified from upstream" notice. That collection is private and stays private; it is not a repository you can visit, and nothing here depends on it. - This repository: that tree, plus the DroidNet contract layer. This is the first public distribution of any of it.
bash test/host/run.sh
# [1/4] contract_core parser unit tests -> OK 341/341 checks passed
# [2/4] ContractLogics.h firmware type-check -> OK
# [3/4] Marcduino command-buffer width guard -> OK
# [4/4] REAL cross-compile (ESP32) -> OK <- needs PlatformIO; skips cleanly without itStages 1-3 need no hardware and no toolchain. Stage 4 is the real cross-compile: it is what makes "it compiles" a claim about the firmware rather than a claim about our mock. If PlatformIO is not installed it skips cleanly and tells you what you did not check.
Firmware (PlatformIO): pio run builds both envs — wlogicengine32 (ESP32, 1,132,213 B / 57.6%)
and wlogicengine32s3 (ESP32-S3, 1,041,501 B / 53.0%). The S3 env used to be unbuildable; see the
warning above for what was wrong and for the hardware-config caveats that still apply to it.
See README_UPSTREAM.md for the real build and flashing instructions — they are
otherwise unchanged.
One fork-owned change to platformio.ini: build_src_filter gains -<test/>. src_dir is the repo
root here and that filter replaces PlatformIO's default, so the default's implicit -<test/> was
gone — meaning this fork's host suite (clang, C++17, its own main()) was being swept into the ESP32
firmware image.
The firmware, and the great majority of the code here:
- Joymonkey (Paul Murphy) — original Logic Engine and WLogicEngine32.
- Rimim (Mimir Reynisson) — WLogicEngine32 updates and maintenance, and the Reeltwo library.
- IOIIOOO, Curiousmarc, Mowee, Flthymcnasty, and others — named in upstream's own README as the source of portions of the code and inspiration.
- The astromech.net community and the RSeries Logic Engine parts runs.
- FastLED and Adafruit (Phil "Paint Your Dragon" Burgess and contributors) for the LED libraries vendored here.
The contract layer: Travis Cook, 2026.
LGPL-2.1. The upstream firmware and the vendored lib/Reeltwo are LGPL-2.1 (Joymonkey, Rimim);
the root LICENSE file is upstream's own, byte-identical. The DroidNet contract layer
(src/contract/*, test/host/*) is Copyright (c) 2026 Travis Cook, LGPL-2.1-only as distributed
here. Also vendored: lib/FastLED (MIT) and lib/Adafruit_NeoPixel (LGPL-3.0).