OpenLCB Note: Using OpenLCB with DCC

OpenLCB needs to be able to interoperate with DCC systems in several ways. Initially, the two most important cases are:

DCC defines methods for operating accessory decoders. It should be possible to build an adapter that uses those commands to control OpenLCB-attached devices in a similar way.


It should be possible to build an adapter that takes OpenLCB Event Report messages and uses them to operate DCC accessory decoders. (This implies a dedicated DCC bus that the OpenLCB adapter would drive, not a general connection to the control bus of a DCC command station). This might be desirable, for example, to put a two-wire bus around the layout that just drives existing signals and turnouts, etc.


Adapters to DCC system control busses will also be wanted, e.g. to XpressNet or LocoNet. The only new complexity these add is “sensor” messages, inputs from the OpenLCB to the DCC control bus. These are conceptually similar to moving DCC accessory commands from OpenLCB to the DCC control bus, and similar methods should work. (See other notes)


Simple Prototocol

Packets in the DCC track signal are turned into OpenLCB event messages directory. The format of the resulting Event ID is

Byte 1


Byte 2


Byte 3

5 bits – reserved for connection number
3 bits – packet length

Byte 4-8 (optional)

Original DCC frame, without error.

Events: top two bytes are 1,238. The next byte is 5 high bits is “system ID”, for marking multiple DCC connections to OpenLCB. The low 3 bits in that byte are the length of the packet. The last 5 bytes are 0-5 bytes of DCC packet.


Simple configuration is needed, but we believe it's possible to build an adapter that doesn't require a computer tool for configuration.

A DCC-to-OpenLCB adapter could create events where the top bytes of the EventID are the adapter's Node ID, and the lower two bytes are the DCC accessory decoder address. OpenLCB consumers would then be configured in any of the usual ways to respond to those events.

For example, the Blue/Gold algorithm for configuring producer/consumer events with just two pushbuttons could be used. (In summary, the “blue” button makes a producer or consumer capture the next report OpenLCB EventID; the “gold” button has it emit a report with a new, guaranteed-unique EventID).

Going the other way is a little more complicated. The easiest method is to have a large table in the adapter that lists the (large number) of EventIDs recognized and the associated DCC accessory decoder address. In practice, perhaps only a few hundred are required, but that's still a lot of memory and configuration.

BobJ: Alternately, somebody might want to create a device that has a fixed map in the EventIDs it recognizes: It looks for a specific upper part, and the DCC accessory decoder address in the bottom part. This would require that the rest of the layout be configured to work with this device, not the other way around, and would not be generally as powerful as a fully configurable device. But there still might be a market for it, and there's no reason to forbid somebody from marketing it. At most, a standard might require that it be marked with a warning about “not fully configurable” or something like that.

See also the recent work on putting mapping LocoNet packets to and from OpenLCB EventIDs in a separate note.


DCC packets for multi-function (locomotive) packets are 1 or 2 bytes of address, 1 to 3 bytes of content, and 1 byte of error. Accessory packets are at most 5 bytes, including address. If this could fit in the basic datagram, that would be great. (“DCC address” is part of the packet, not part of the destination nodeID in this calculation, but it if was part of the destination node, that might allow some interesting routing, etc, for large layouts)

Consider whether DCC packets should be put in lower bytes of events, which makes them globally available. This will cause a lot of traffic if it includes refresh packets to e.g. locomotives, but might allow some other things to happen. Sort them?

Notes from test implementation

David Harris did a test implementation (Spring 2011) and wrote two notes:

shows that last DCC command:

Loco 0000 Speed 000

Loco 0000 Func 00 = 0

Acc 0000 State=0

Sig 0000 State=0


Blue: Idle --> Filters --> Speed --> Func --> Acc --> Sig --> idle

and Gold selects Rejecting or Accepting for each

Gold --> Idle --> Teach --> Idle

and Blue lets the next packet be accepted, when you get teh one you want, Gold sends a Learn-msg.

/*=== DCC to OpenLCB BridgeDCC to OpenLCB Bridge ===========================================================/


* Converts DCC packets to Events: (DCCPrefix.Segment.rawdata] (2+1+5 = 8 bytes)

* Filters on: speed, function, Acc, and Sig packets.


* Uses OpenDCC library:

* Raw packets converted to Events [DCCPrefic.RAW.d0,d1,d2,d3,d4] (filled with 0) 3+5=8

* Speed packets cobverted to Events [DCCprefix.SPEED.ForwardDir.Speed] (3+8+16+8+8) 3+1+2+1+1=8

* Function packets converted to Events: [DCCPrefix.FUNCTION.Addr.FuncNum.State] (3+8+16+8+8) 3+1+2+1+1=8

* DCCAccState packets converted to Events: [DCCprefix.ACC.Addr.State] (x+8+16+8+8)

* DCCSigState packets converted to Events: [DCCprefix.SIG.Addr.OutputIndex.State] (x+8+16+8+8) 3+1+2+1+1=8

* Speed packets cobverted to Events [DCCprefix. 1, dir] and [DCCprefix.2.speed]


/*=== Events =============================================/

* 0 - accept Speed-packets

* 1 - reject speed packets

* 2 - accept Func-packets

* 3 - reject Func-packets

* 4 - accept Acc-packets

* 5 - reject Acc-packets

* 6 - accept Sig-packets

* 7 - reject Sig-packets


/*=== User Interface ======================================/

* (blue)+ selects one of: Speed, Func, Acc, Sig, and

* (gold) sets its acceptance to true or false

* (gold) sets program mode, will display the last packet,

* (blue)+ allows another packet to be accepted, and

* (gold) sends Teach message


/*=== Resource use ==============================/

* DCC uses:

* DCC input: D2 (PD2)

* DCC Ack: D3 (PD3)

* Timer: timer2

* CAN uses:

* SPI: D10,11,12,13 (SS,MOSI,MISO,SCK)

* Int: D3 (PD3)

* LCD:

* d0-3: D3-6

* control: D8-9

* lcd(9, 8, 6, 5, 4, 3)


Site hosted by

This is SVN $Revision: 1349 $