Skip to content

Hive Rail Node Board

Timo Sariwating edited this page Oct 31, 2026 · 22 revisions

Status: concept (scope widened 2026-10-31); schematic draft and parts list: hardware/board-v2/ in the repository; plan: phases B0 to B8 (13). The board is a full DCC-EX command station with the Hive-Rail extras (LocoNet, multiMAUS, the Hive-Rail node), usable at home and at a FREMO meeting (1, 2). Board v2 has two ESP32s: one runs stock DCC-EX, the other the Hive-Rail lite node (4). Built so far, on the single-ESP32 v1 prototype (the 2021 "ESP32 LocoNet Command Station"): stock DCC-EX 5.6.6 with a Hive-Rail add-on (OLED, LEDs, buttons, LocoNet buffer), and the DCC-EX driver in Hive-Rail (DCC-EX Adapter).

Contents

  1. Goal and scope
  2. Five ways to use the board
  3. Features
  4. Board v2: two ESP32s
  5. Who does what
  6. Throttles
  7. Stop and go buttons
  8. Status LEDs, OLED and link heartbeat
  9. District transfer relays and sensor
  10. Firmware
  11. v1 prototype: the 2021 board
  12. Existing projects and parts sources
  13. Phases
  14. Open questions

1. Goal and scope

One board that is a complete command station on its own, and a Hive-Rail node when it joins a meeting.

  • Command station: stock DCC-EX (EX-CommandStation) with main and programming track outputs. It is useful without any other Hive-Rail part, at home on a layout of any size that one command station can run.
  • Hive-Rail extras on the same board:
    • LocoNet (LocoNet-T for throttles and module devices, LocoNet-B with RailSync for boosters);
    • multiMAUS support over XpressNet, and Roco's Z21 app and wlanMAUS over Wi-Fi (6);
    • the Hive-Rail lite node: the district's part of the Hive-Rail mesh, without a Pi.
  • Cheap and easy to install: one board per district, powered from the district's track supply, with optional wired Ethernet.

Must-haves on every board:

Connection Why
Main track output The district's own track, or the part of it the board powers itself
Programming track output Reading and writing decoder CVs at home and at the meeting
LocoNet-T 12 V for throttles (FREDs) and module devices
LocoNet-B RailSync with DCC for LocoNet boosters, such as Digitrax or Uhlenbrock Power
CDE booster output DCC for CDE boosters (Lenz, Tams, Uhlenbrock and others), with the booster's short-circuit line back (E)

Larger districts get their power from external boosters on LocoNet-B or CDE; the board's own main output serves a small district or the station area.

Why two ESP32s: DCC-EX supports only the original ESP32 (ESP32-WROOM, ESP32-D0WD), which generates DCC with its RMT hardware. Putting the Hive-Rail extras on a second ESP32 keeps DCC-EX completely stock and updatable, keeps DCC timing apart from networking, and lets the node chip be chosen freely (4).

This widens Hive-Rail's scope: it was a set of nodes for FREMO meetings, with a board to make one district cheap. Now the board is also a product of its own, for home layouts, and the meeting use is one of its modes.

2. Five ways to use the board

Mode Where What runs Who drives
1. Command station Home DCC-EX, and the node chip as LocoNet and throttle interface. No PC needed multiMAUS, FREDs and LocoNet throttles, the Z21 app or wlanMAUS, WiThrottle apps (Engine Driver)
2. With Rocrail or JMRI Home As 1, with a PC program on the network Rocrail over RocNet (UDP), or Rocrail or JMRI over LocoNet over TCP or DCC-EX's own protocol. Throttles as in 1
3. Lite node FREMO meeting The node chip joins the Hive-Rail mesh itself (zenoh-pico): district power, loco register, train tracking, transfer zone, boundary signal Throttles as in 1, under Hive-Rail's one-controller rule; the dispatcher sees the district
4. Full node FREMO meeting A Raspberry Pi (or PC) runs the full Hive-Rail node; the board is its command station and its LocoNet and XpressNet interface As 3, plus everything only a full node has: web view, dispatcher, layout tools, LocoNet over TCP clients
5. Booster Home The board is a booster behind another command station, such as a Z21 or an Intellibox: DCC-EX in booster mode amplifies the master's DCC from the booster input, and reports a short back on the input's short line The master's throttles; the board adds track power, nothing else

Rules across the modes

  • One command station per district. In every mode, DCC-EX on the board is the district's only command station; Hive-Rail never adds a second one.
  • The one-controller rule applies at meetings (3, 4): one throttle at a time per loco. DCC-EX's own WiThrottle server bypasses it and is switched off there; WiThrottle apps then connect through the node, like every other throttle.
  • A meeting needs at least one full node, better two (open, NB-Q12). Lite nodes run their districts, but the shared roles (throttle number allocator, fast clock master), the dispatcher's web view and the layout tools need a full node. Two full nodes keep the shared roles alive if one fails, in line with "keeps working until the last mesh node dies". Whether lite nodes may take a shared role when no full node is left is still to be decided.
  • Several boards at home (one per booster district): either one Pi as a full node with the boards as lite nodes, or lite nodes meshing among themselves (if zenoh-pico's peer mode is good enough, NB-Q13).
  • Booster mode (5): for someone who already has a Z21 or an Intellibox at home and wants more track power. Details below.

Lite servers

A lite node (the board's node chip, or the M5StickC test device) reaches the mesh through a lite server: a full node or the dispatcher started with --lite-server, which runs Zenoh as a router. Lite nodes find lite servers by Zenoh scouting (routers only), so no addresses are configured; with two or more on the mesh they fail over to another when theirs stops (tested 2026-10-31, without a missed heartbeat). At a meeting: the dispatcher's computer, a dedicated Raspberry Pi, or both. A lite server with --layout also hands lite nodes their district's part of the layout. Later: load balancing, with each lite server publishing how many lite nodes it carries.

Booster mode and the DCC-to-LocoNet bridge

Z21 / Intellibox ──DCC──> [optocoupler] ──┬──> DCC-EX chip ──> track outputs (booster)
                                          └──> node chip: decodes DCC
                                                 accessory packets ──> LocoNet OPC_SW_REQ ──> LocoNet accessory decoders
DCC-EX chip: overload ──> [optocoupler] ──> short line back to the master (B-BUS pin 4, CDE E)
  • The master's DCC comes in on the booster input: the Z21's B-BUS, or an Intellibox's CDE or LocoNet-B output. A fast optocoupler keeps the two systems apart.
  • DCC-EX passes it through in hardware: with BOOSTER_INPUT set, a track in BOOST mode gets the input pin routed to its driver inside the ESP32's GPIO matrix (DCC-EX TrackManager.cpp), with no software in the path. EX-RAIL's ONRAILSYNCON switches the tracks to BOOST when the signal appears. DCC-EX keeps measuring current and cuts its own outputs on a short. DCC-EX's booster mode on the ESP32 is still beta (DCC-EX 5.4).
  • The short line back: EX-RAIL's ONOVERLOAD sets an output that pulls the master's short line through an optocoupler, so the Z21 or Intellibox sees the booster's short as from any of its own boosters.
  • The DCC-to-LocoNet bridge: the node chip also gets the master's DCC (one extra trace), decodes the accessory packets and sends them as OPC_SW_REQ on the board's LocoNet. Turnouts, lights and signals on LocoNet accessory decoders then follow the Z21's multiMAUS or app. The plain Z21 (white) and the z21start have no LocoNet, so for them the board is a booster and a LocoNet bridge in one.
    • One message per change: the master repeats each packet; the node sends one LocoNet message per real change.
    • Address offset: Roco, the Intellibox and the NMRA count accessory addresses differently (Roco by 4 for the same decoder); the offset is a setting.
    • Off when the master already has LocoNet on the same bus (an Intellibox, a black Z21): every command would arrive twice. On by default only on a separate LocoNet.
    • One way only: DCC has no replies; feedback from LocoNet does not reach the master this way.
    • Signal aspects: DCC's extended accessory packets have no direct LocoNet equivalent; basic accessory packets (turnouts, lights, simple signals) first, an aspect mapping later.
  • Later: the same decoder sees the master's loco packets (address, speed, functions). A district at a meeting that runs a Z21 or an Intellibox, with the board as booster and bridge, could put its locos into Hive-Rail's loco register from what it sees on the track: Hive-Rail with any DCC central. DCC-EX's own sniffer already decodes loco and accessory packets from the booster input (DCCDecoder.cpp), which is worth comparing with the node's.

3. Features

Feature Chip Notes
DCC-EX, main and programming track (must) DCC-EX ESP32 Stock, unchanged. Current sensing per output
LocoNet-T and LocoNet-B (must) Node ESP32, RailSync from DCC-EX T: 12 V for throttles and devices. B: RailSync carries DCC for boosters
CDE booster output (must) DCC-EX ESP32 C and D: the DCC signal for the boosters. E: a booster pulls it on a short; the board turns that into a district short (power off and report)
Z21 B-BUS (open) – Roco's booster bus. Only if its electrical spec is available (NB-Q16)
multiMAUS over XpressNet Node ESP32 RS-485 port; the node is the XpressNet master (6)
Z21 app and wlanMAUS Node ESP32 Roco's Z21 LAN protocol over Wi-Fi (6)
Hive-Rail lite node Node ESP32 Modes 3 and 1 to 2 at home with several boards
RocNet to Rocrail Node ESP32 Mode 2
Wired Ethernet (optional) Node ESP32 W5500; recommended at meetings
District transfer relays and sensor Node ESP32 For the Transition Zone (9)
Stop and go buttons DCC-EX ESP32 Work even when the node chip is down (7)
Status LEDs and OLED Node ESP32 Power, link, layout; fast clock and district on the screen (8)
Booster input DCC-EX ESP32 Booster mode (2, mode 5): DCC in through a fast optocoupler, short line back to the master through a second optocoupler

4. Board v2: two ESP32s

flowchart LR
    subgraph board["Hive-Rail board v2"]
        subgraph cs["ESP32-WROOM-32E: DCC-EX (stock)"]
            DCC["DCC generation (RMT)"]
        end
        subgraph node["Node ESP32 (S3 or C6): Hive-Rail lite node"]
            LN["LocoNet"]
            XN["XpressNet master"]
            NET["Wi-Fi, Ethernet (W5500)<br/>RocNet, Z21, zenoh-pico"]
            IO["Relays, LEDs, OLED"]
        end
        node <-->|"UART: DCC-EX commands<br/>+ reset and boot lines"| cs
        DRV["2× DRV8874<br/>main + programming"]
        RS["TC4427<br/>LocoNet-B RailSync"]
        cs --> DRV
        cs -->|"DCC signal"| RS
        CDE["CDE driver<br/>C, D out, E in"]
        cs <-->|"DCC signal, short"| CDE
        BTN["Stop and go buttons"] --> cs
    end
    TRACK["Track"] --- DRV
    LNB["LocoNet-B (boosters)"] --- RS
    BOOST["CDE boosters"] --- CDE
    LNT["LocoNet-T (throttles, devices)"] --- LN
    MAUS["multiMAUS"] --- XN
    PI["Pi (mode 4), Rocrail or JMRI (mode 2)"] --- NET
    MESH["Hive-Rail mesh (modes 3, 4)"] --- NET
Loading

Build style: through-hole first (decision 2026-10-31). Every part can be soldered by hand: the ESP32s, the regulators, Ethernet and the OLED are plug-in modules on pin headers, the track driver is an Arduino Uno motor shield (optional), and the interface chips sit in DIP sockets, so whatever blows is swapped in seconds. Everything else is through-hole, as on the 2021 board. A machine-assembled SMD variant can follow for batches. The full draft, with a first review, PCB current and track-width rules and the parts list, is in hardware/board-v2/.

Parts, by block. Taken from three designs that work: the EX-CSB1 (DCC-EX's own ESP32 board, 2025), positron96's LocoNet command station (2021, CERN-OHL) and our own 2021 board. We use their component choices, not their layouts.

Block Choice From
DCC-EX chip ESP32-DevKitC (ESP32-WROOM-32E) in a socket EX-CSB1 (the chip DCC-EX supports)
Track outputs Arduino Uno R3 shield headers, wired as DCC-EX's ESP32 shield definitions expect: the owner plugs in an EX-MotorShield8874 (2× DRV8874, 5 A) or an Arduino Motor Shield R3 (L298P, 2 A), swapped in seconds if blown. Optional: a district powered only by boosters needs no shield. A header for an IBT-2 module on the main track; a third DCC-EX track (no driver) feeds the booster buses, so they switch off with the district DCC-EX shields; EX-CSB1 also has Uno headers
Booster input (mode 5) DCC in through a 6N137 fast optocoupler with a constant-current input (any level from 5 to 24 V, C and D or one DCC wire and ground); short line out through a PC817 to the master's E or overload input. Screw terminals plus the Roco 4-pole B-BUS socket (NB-Q16) 6N137 instead of EX-CSB1's SMD TLP2361
Node chip ESP32-S3-DevKitC-1 in a socket: the node needs three UARTs (LocoNet, XpressNet, the DCC-EX link); the ESP32-C6 has two plus a limited low-power one (NB-Q10) New
LocoNet LM393 comparator receiver, 2N3904 transmitter, pull-up jumper, 2 to 3 RJ12 jacks (T and B) positron96 and our 2021 board (same circuit, IO16/IO17 on v1)
LocoNet-B RailSync TC4427 driver (DIP) fed by DCC-EX's booster-bus track, 150 Ω and a polyfuse per pin Our 2021 board; current limit from positron96's v2 goals
CDE booster output Driver for C and D from DCC-EX's DCC signal; E through an optocoupler to a DCC-EX input, which an EX-RAIL handler turns into power off. Screw terminals New; levels from Lenz's booster documents (NB-Q16)
XpressNet (optional) 3.3 V RS-485 transceiver with direction control, connector to match the multiMAUS (NB-Q14) New
Ethernet (optional) Socket for the common blue W5500 module (about a quarter of a WIZ850io's price) Our 2021 board
Link between the chips UART: DCC-EX's SERIAL2_COMMANDS takes commands on GPIO16/17 next to USB. The node can reset DCC-EX New
USB On the development boards: each has its own USB port, USB-serial chip and auto-reset. No USB circuit on the board –
Power 5 A fuse, P-MOSFET reverse-polarity protection, TVS, 12 V and 5 V switching regulators in a 3-pin 7805 footprint (36 V input). VIN 15 to 22 V Review 2026-10-31
Transfer relay driver Two coil drivers per double-pole changeover latching relay (9) Transition Zone
Buttons, LEDs, display Stop and go buttons, RGB status LEDs, 128x64 OLED, STEMMA QT I²C Our 2021 board, EX-CSB1

Isolation and protection

Rule: isolate where a device with its own power supply and its own ground connects; protect, without isolating, where a bus shares the board's ground by design.

Connection Isolate? How
Booster input (mode 5) Yes DCC in: fast optocoupler (TLP2361 or 6N137). A slow PC817 takes several microseconds to switch and skews DCC's 58 µs half-bits. Short line out: optocoupler transistor
E line from CDE boosters, overload line from B-BUS boosters Yes The booster has its own supply. A PC817 is fast enough
CDE and B-BUS DCC outputs to boosters Not on our side Boosters have an optocoupler at their input; we drive it through a current-limiting resistor, protected against shorts
Sensors under the module (transfer zone, anything that touches track voltage) Yes Optocoupler input. Dry contacts (reed, IR modules on our 5 V): RC filter, protection diode, Schmitt trigger
LocoNet-T and LocoNet-B No: LocoNet needs a common ground for all devices Series resistors, a TVS diode on the data line, the LM393 input divider, current-limited RailSync and 12 V, so a miswired cable cannot reach the ESP32
XpressNet (multiMAUS) No: the board powers the multiMAUS RS-485 TVS (for example SM712), fail-safe biasing, the 12 V pin current-limited
Transfer relays The relay isolates Flyback diodes on the coils
Ethernet Already isolated The magnetics of the jack or the W5500 module
USB No ESD protection (USBLC6). USB joins the laptop's ground to the board's: a laptop on two boards in different districts joins their grounds. At meetings the boards talk over Ethernet; debug one board at a time over USB, or use a USB isolator
Power input – Reverse-polarity MOSFET, TVS, fuse or polyfuse
Between the two ESP32s No Same board, same ground

The optocouplers, TVS diodes and USB protection cost a few euros in all.

5. Who does what

Rule: the chips do everything timing-critical; the decisions are made by the node, the lite node on the node ESP32 or the full node on the Pi.

DCC-EX ESP32 Node ESP32 Pi (mode 4)
DCC generation, programming track, overload and short detection, booster short line (E) LocoNet bit timing and collisions; XpressNet polling Full Hive-Rail node: mesh, web view, dispatcher, layout tools
Stop and go buttons (power off and on without anything else) Relay pulse timing, sensor debounce, LEDs, OLED Transition zone state machine and handoff (in mode 3: the node ESP32)
Booster mode (booster input, mode 5) Modes 1 to 3: slot master, loco register, throttles, RocNet, Z21, lite node Slot master, loco register, routing to other districts

6. Throttles

Throttle How it connects Notes
FRED, Fredi and other LocoNet throttles LocoNet-T The node is the only slot master on the board's LocoNet; a FRED keeps its loco across modules (FRED design)
multiMAUS (Roco, Fleischmann) on a cable XpressNet on RS-485 See below
wlanMAUS, Z21 app Wi-Fi, Roco's Z21 LAN protocol (UDP) Roco publishes the protocol. Software only: can be built on the Pi node first, without new hardware
WiThrottle apps (Engine Driver) Wi-Fi At home DCC-EX's own server; at meetings through the node (2)

The multiMAUS speaks XpressNet (Roco's X-BUS). XpressNet is RS-485 at 62.5 kbit/s with 9-bit characters. The command station is the bus master and polls each handheld in turn by its bus address; a handheld only speaks when asked. With Roco's own amplifier a "master" multiMAUS is the command station itself; on another central it is an ordinary handheld, as on this board.

  • The multiMAUS keeps its own loco library (name and address) and selects the loco address itself; nothing assigns it, unlike a FRED. Every XpressNet command carries the loco address directly; there are no slots.
  • It fits the loco register, which is also keyed by address. The node passes the multiMAUS's commands to the register, tells it when another controller has the loco (XpressNet has a message for that), and forwards commands to another district when the loco has moved there, as it does for LocoNet throttles.
  • 9-bit characters on the ESP32: its UART has no native 9-bit mode. The usual way is to set the parity per byte so that the parity bit is the ninth bit (NB-Q14).

7. Stop and go buttons

  • Stop (red): district power off directly in DCC-EX, so it works even when the node chip, the Pi or the network is down.
  • Go (green): district power on (MAIN only), also directly in DCC-EX.
  • Implemented on v1 as an EX-RAIL script, firmware/node-board/myAutomation.h: ONBUTTON(15) POWEROFF and ONBUTTON(13) POWERON. Tested on the 2021 board on USB power: each press switches DCC-EX, the OLED follows, Hive-Rail shows the district as reported by DCC-EX and sends OPC_GPON/OPC_GPOFF to its LocoNet clients. On v2 the buttons stay on the DCC-EX chip.
  • DCC-EX broadcasts the power change; the node follows power changes it did not request, reports them to every node and tells its LocoNet clients.
  • Long press on stop: a global emergency stop. The node turns it into the global stop (halt on rn/cs/all), because it must reach the other districts.

8. Status LEDs, OLED and link heartbeat

Proposal for three RGB LEDs:

LED Shows Source
1 Power green on, dark off, yellow emergency stop, red blinking short DCC-EX state
2 Hive-Rail link green connected, red blinking link lost The node's heartbeat
3 Layout green all neighbours fine, yellow a neighbour stale or without power, red global stop The mesh

Link lost: if the node is lost (on v1: Hive-Rail on the Pi; on v2: also the node chip, NB-Q2), the board puts the district in a safe state (emergency stop, value to be decided) and shows it on LED 2. LocoNet throttles need the node as slot master, so they stop working without it anyway.

On v1 (implemented 2026-10-29): LED 1 in myHiveRail.cpp, not yet seen lit (the WS2812s run on the board's +5 V rail, which needs the 12 V supply): dim green MAIN on, dim red off, orange blinking short, at about 10 % brightness, read from DCC-EX's track manager every 50 ms, driven on RMT channel 6 (DCC-EX uses 0 to 3).

OLED screen (implemented on v1, 2026-10-29)

▓Hive-Rail        RN101 ★▓   title bar: module name (HIVE_RAIL_NAME), RocNet ID, ★ = allocator and clock master
 06:42            ON         large: fast clock, district power (ON / OFF / STOP / SHORT, SHORT blinks)
 fast x4        district
 ─────────────────────────
 Mesh 4 nodes     locos ok   or blinking LOCOS !! when the loco registers differ
 Loco 1234 ▶ 40        F0    last loco driven on this module (or locos and slots taken)
 IP 192.168.4.1

Before Hive-Rail connects (Waiting for Hive-Rail) and after the link is lost (blinking HIVE-RAIL LINK LOST), the bottom lines show the WiFi name and, every 3 s in turn, the password and the IP address.

How it works on v1, without changing DCC-EX's files:

  • A HAL device (halSetup(), DCC-EX's myHal.cpp hook) gets _loop() calls from DCC-EX's main loop. The screen, the status LEDs and the reads of DCC-EX's track state run there. One changed 128-byte page is sent per call, about 3 ms at 400 kHz.
  • myFilter() sees every command. It answers <U 0> with <u 1> (the add-on and its protocol), takes Hive-Rail's status line, and copies the fast clock from <JC minutes rate>.
  • Status line from Hive-Rail, once a second: <U 1 rocnet nodes locos slots flags address speed dirf>. DCC-EX accepts at most 9 parameters, so dirf packs F0 to F4 (bits 0 to 4) and forward (bit 7); flags are allocator (1), loco register in sync (2), emergency stop (4), register compared (8). Hive-Rail only sends it after the board answered <U 0>; a stock DCC-EX answers <X> once and gets nothing more. The status line is also the link heartbeat: without it for 3 s the screen and LED 2 show the link as lost.
  • Our own 5x7 font and SSD1306 driver; HIVE_RAIL_OLED_SH1106 selects the 2-column offset of an SH1106 display.

On v2 the screen and the LEDs move to the node chip, which has all of this information itself, and DCC-EX needs no add-on.

9. District transfer relays and sensor

  • One double-pole changeover latching relay per transfer block: it switches both rails, so two districts never share a conductor, and a changeover contact always breaks before it makes. DCC currents (2 to 5 A at 14 to 22 V) are well within a small relay's rating.
  • The relay pulse is timed on the board (node chip), never over the network.
  • The entry and clear sensors are read on the board.
  • The state machine runs in the node: on the node chip in mode 3, on the Pi in mode 4 (Transition Zone Specification).

10. Firmware

Chip Firmware
DCC-EX ESP32 Stock EX-CommandStation, with only the user files DCC-EX provides for configuration: config.h (board definition) and myAutomation.h (stop and go buttons). Updated the normal DCC-EX way, or by the node chip through its reset and boot lines
Node ESP32 Hive-Rail lite node: LocoNet, XpressNet, Z21, RocNet, zenoh-pico, relays, LEDs, OLED, the modes of 2. Language and framework to be decided (NB-Q10): Rust (esp-hal, sharing no_std protocol crates with the Pi node) or C/C++ on ESP-IDF

v1: one ESP32 with a DCC-EX add-on (prototype, built)

Decision (2026-10-29): LocoNet is not ported into DCC-EX. On the single-ESP32 prototype, a LocoNet buffer runs next to stock DCC-EX: one firmware image, two independent services that do not know about each other.

Link DCC-EX LocoNet buffer
WiFi or Ethernet TCP 2560 (--dccex host:2560, works now) TCP 1234, LbServer (standard LocoNet over TCP)
USB The board's USB serial port (works now) A second USB-serial chip on another ESP32 UART

Implemented (2026-10-29), not yet tested on a powered bus: myHiveRailLocoNet.cpp runs the LocoNet buffer in its own ESP32 task: UART2 at 16 666 baud (RX IO16 not inverted, TX IO17 inverted for the 2N3904, both configurable), waiting for a quiet bus (carrier detect plus priority delay), comparing the echo byte by byte and sending a break on a collision, and an LbServer on TCP 1234 (SEND → RECEIVE echo to all clients and SENT OK, or SENT ERROR no LocoNet power / bus busy). The OLED shows LN n (clients) or LN off when the bus line stays low (no LocoNet power, the board's 12 V). On the Hive-Rail side, --loconet-connect <board>[:1234] is an LbServer client that reconnects by itself and drops the echo of its own messages; the bus's slots belong to the node by default (--loconet-connect-slots node), for FREDs.

  • The board is the LbServer server, because it sits on the bus; Hive-Rail connects as a client, as JMRI or Rocrail would. The reverse would loop: Hive-Rail echoes each message to its sender, and a bus bridge would put it back on the bus.
  • Fallback if only one serial link is available: tunnel LocoNet through DCC-EX's command hook (myFilter) as <U …>/<u …> frames.

Firmware options considered for v1 (NB-Q8):

Option Strength Weakness
A. DCC-EX + LocoNet buffer next to it Works today, large community, mature DCC on the ESP32, DCC-EX unchanged Two services on one chip; text protocol not made as a machine interface (shorts only as diagnostics, no reply without tracks, no acknowledgements, <c> crash); its own WiThrottle controllers bypass the one-controller rule; does not run the fast clock
B. positron96 LocoNetControlStation (MIT) LocoNet-first, same LocoNet circuit, LocoNet over TCP built in Its own slot server conflicts with Hive-Rail as slot master; small one-person project
C. Own firmware in Rust (esp-rs) Exactly the board's needs; reuses Hive-Rail's code Most work: DCC timing, programming track, overload handling of our own

Board v2 answers most of A's weaknesses without option C: DCC-EX stays stock on its own chip, and everything else moves to the node chip.

Build and flash v1 (the add-on lives in the Hive-Rail repo under firmware/node-board/; DCC-EX is an unmodified checkout next to it):

git clone https://github.com/DCC-EX/CommandStation-EX.git ../CommandStation-EX
pip3 install --user platformio
firmware/node-board/build.sh                                    # build
firmware/node-board/build.sh --upload /dev/cu.usbserial-0001    # build and flash

Step 1 result (2026-10-29), DCC-EX 5.6.6 on an ESP32 DevKit with OLED: 15 % RAM, 69 % flash. DCC-EX reports HIVERAIL_ESP32 with tracks A MAIN and B PROG, the add-on starts and runs its own task on core 0. With tracks defined, <1>/<0> answer <p1>/<p0>, the OLED shows PWR On/PWR Off, and Hive-Rail shows the district power as confirmed by DCC-EX.

Board definition in DCC-EX's config.h for v1:

// A = MAIN: DCC to LocoNet-B RailSync via MIC4426, no current sense (boosters measure)
// B = PROG: L6202, second input through a 74HC04, no usable sense
#define HIVE_RAIL_TEST_BOARD F("HIVERAIL_ESP32"), \
  new MotorDriver(32, 25, UNUSED_PIN, UNUSED_PIN, UNUSED_PIN, 1.0, 5000, UNUSED_PIN), \
  new MotorDriver(33, 26, UNUSED_PIN, UNUSED_PIN, UNUSED_PIN, 1.0, 250, UNUSED_PIN)
#define MOTOR_SHIELD_TYPE HIVE_RAIL_TEST_BOARD

A negative enable pin (-32) makes the enable active-low; which polarity switches the RailSync DCC off on <0> is tested on the board.

11. v1 prototype: the 2021 board

"ESP32 LocoNet Command Station" (Eagle 9.6.2, January 2021): ESP32 DevKit V1, LocoNet-T and LocoNet-B sockets, LM393 LocoNet receiver, MIC4426 RailSync driver, L6202 programming track, W5500 Ethernet, OLED, three WS2812 LEDs, red and green buttons. CAN is on the board but not needed.

Function GPIO
LocoNet RX / TX IO16 / IO17
DCC main signal / enable (MIC4426) IO25 / IO32
Programming track signal / enable / sense (L6202) IO26 / IO33 / IO39
OLED SDA / SCL IO21 / IO22
W5500 MOSI / MISO / SCK / CS / reset IO23 / IO19 / IO18 / IO5 / IO34
Red / green button IO15 / IO13
WS2812 LEDs IO4

IO34 and IO35 are input-only on the ESP32, so the W5500 reset on IO34 cannot be driven by firmware.

12. Existing projects and parts sources

Project Relation
EX-CSB1 (KiCad files) DCC-EX's own ESP32 command station and booster. Source of the DCC-EX side's parts: ESP32-WROOM-32E, DRV8874, TLP2361 RailSync input, USB-C with CH340C and USBLC6, AO4407C and TPS54302 power. The repository has no licence file; we use its part choices only
positron96/LocoNetControlStation (firmware MIT, PCB CERN-OHL) ESP32 LocoNet command station with its own DCC. Same LocoNet circuit (LM393, 2N3904, LM317L-limited RailSync, RJ12, pull-up jumper); v2 plans a socketed DevKitC, USB-PD, a switching regulator, a DIN-rail case and spare headers
IoTT RedHat++ shield and IoTT Stick Adds LocoNet to a DCC-EX Arduino with a second ESP32: the same two-chip idea
DCC-EX itself No LocoNet or XpressNet support

13. Phases

Each phase ends with something that works and can be used. Mode 1 (a command station at home) comes first: it is useful on its own, and everything later builds on it.

Phase Goal Done when
B0. Specs and measurements (zenoh-pico test passed 2026-10-31) Close the open hardware questions before the PCB: CDE and B-BUS levels and connectors (NB-Q16), the X-BUS cable and the 9-bit trick (NB-Q14), LocoNet-T supply and bus pull-up current, the node chip (NB-Q10) Measurements on a Z21, a multiMAUS, a Lenz or Digikeijs booster and an Intellibox are in this page; a zenoh-pico heartbeat from the chosen node chip shows as a district on the dispatcher
B1. Breadboard prototype Both chips on development boards: an ESP32 DevKit with DRV8874 breakouts on EX-CSB1's pins running stock DCC-EX, an ESP32-S3 DevKit as the node with the LocoNet circuit of the 2021 board. Lite node firmware skeleton: the DCC-EX link (SERIAL2_COMMANDS), LocoNet buffer, OLED A loco runs on main, CVs read on programming, a FRED drives through the node as slot master
B2. Schematic and PCB rev A KiCad schematic and layout from the draft, reviewed; five boards assembled at JLCPCB Boards delivered
B3. Bring-up: mode 1 Every block of rev A tested: power, both tracks, LocoNet-T and -B, CDE and B-BUS out with a real booster, stop and go, LEDs, OLED, USB flashing of both chips The board runs a home layout as its only command station
B4. Throttles Z21 LAN protocol (Z21 app, wlanMAUS), then the multiMAUS on XpressNet, both into the loco register with the one-controller rule A multiMAUS and the Z21 app drive locos next to a FRED
B5. Booster mode and the bridge: mode 5 Booster input with the short line back; DCC-to-LocoNet bridge for accessory packets The board boosts a Z21 and an Intellibox; a Z21 switches a LocoNet turnout decoder; a booster short shows on the master
B6. Home with a PC: mode 2 RocNet to Rocrail, LocoNet over TCP for Rocrail and JMRI, from the node chip Rocrail and JMRI each run a home layout through the board
B7. Meetings: modes 3 and 4 Lite node on the mesh (zenoh-pico): district power, loco register, transfer relays and sensors, boundary signal. Full node with a Pi using the board as command station and interface Two boards and a Pi run a bench layout across a district border, with a train handed over
B8. Rev B and builders' documents Fixes from B3 to B7 in a second PCB revision; assembly and setup guides for module owners A small batch for a FREMO trial

The software phases of the Hive-Rail roadmap (README) run alongside: train tracking (Phase T) and the transfer zone are needed for B7; the Z21 protocol (8.10) can start on the Pi node before B4.

14. Open questions

# Question How it will be answered
NB-Q1 Is the stop button power off or emergency stop? Decide with FREMO operators
NB-Q2 What does the board do when the node (Pi or node chip) is lost: emergency stop, power off, or keep running? Decide; start with emergency stop
NB-Q3 Do the LocoNet buffer and its TCP server run reliably next to DCC-EX on one chip (v1)? Prototype on the 2021 board
NB-Q4 Ethernet: W5500 on the node chip only, or also for DCC-EX? v2: the node chip has the network; DCC-EX needs none
NB-Q5 Pi separate, or mounted on the board (header for a Pi Zero 2 W)? Decide when the PCB is designed
NB-Q6 How are the mode, module name, district and RocNet ID set without a laptop? Web page on the node chip, or OLED and buttons
NB-Q7 Heartbeat and LED message format between node and board Decide with the v2 firmware
NB-Q8 v1 firmware: DCC-EX with an add-on, or own Rust firmware? Answered for v2 by the second chip (10)
NB-Q9 Does a FRED get slot replies fast enough through the node? Measure with a real FRED (README roadmap 8.5)
NB-Q10 Node chip: ESP32-S3 (two cores, PSRAM, three UARTs; Rust needs Espressif's compiler fork) or ESP32-C6 (RISC-V, standard Rust, but two UARTs plus a low-power one)? Rust or C/C++? The draft uses the S3 for its three UARTs. B0 test passed (2026-10-31), now our test device: Node-Lite on the M5StickC on an original ESP32 (M5StickC) with zenoh-pico 1.10.1 in C++ (Arduino): it joins the mesh as a district, about 210 KB heap free, 1.2 MB flash (results). Rust is still open
NB-Q11 Which serial port does DCC-EX on the ESP32 take commands on, next to USB? Answered (2026-10-31): SERIAL2_COMMANDS opens Serial2 on GPIO16/17 at 115 200 baud (DCC-EX SerialManager.cpp) –
NB-Q12 Must a meeting have a full node (Pi), or may lite nodes take the shared roles when none is left? Shown to matter (2026-10-31): in the B0 test the ESP32 became allocator and clock master, because the roles go to the lowest id. Implemented (2026-10-31): the heartbeat flag lite, and full nodes leave lite nodes out of the shared roles. Still to decide: may lite nodes take them when no full node is left?
NB-Q13 Is zenoh-pico's peer mode good enough for lite nodes to mesh without a Pi (several boards at home)? Test
NB-Q14 multiMAUS: connector and pinout, bus address handling, loco library size; 9-bit characters on the node chip (parity trick) Read Roco's and Lenz's XpressNet documents; test with a multiMAUS
NB-Q15 Is booster mode worth the parts on every board? Decided (2026-10-31): yes, for home users with a Z21 or an Intellibox who use the board as a booster (mode 5). About a euro in parts –
NB-Q16 Booster outputs: CDE signal levels and the E line's behaviour (Lenz's booster documents); is Roco's B-BUS documented, and does a Märklin 6017-style booster output matter for 3-rail districts? Read the documents; ask FREMO and 3-rail users which boosters they bring
NB-Q17 Booster mode: does DCC-EX pass the signal in hardware? Who drives the short line back? Answered (2026-10-31): hardware (GPIO matrix, TrackManager.cpp); the short line from EX-RAIL's ONOVERLOAD. To test in B5

Clone this wiki locally