This document has been superseded by the Traction Control protocol Working Note, Technical Note, and Standard. Reference them instead of this one. This only remains for historical interest. Move along, nothing to see here.
This document defines a protocol for the control of model trains.
Trains are to be treated as independent OpenLCB Nodes.
Train control must be independent of the underlying train control system.
Train control must be independent of train's scale, and other contextual factors.
Train control must avoid deliberately exposing the end user to unnecessary technical details; similarly, any model on any control system must be usable "out of the box", with no explicit configuration on the part of the user.
All communication should take advantage of the Datagram protocol.
Nevertheless, because currently technology requires that trains be represented by OpenLCB proxies, it should be possible to split the responsibilities of a proxy across several physical or virtual Nodes, to ease implementation. Therefore, the protocol should depend on little (preferably no) state information as context for the proper processing of commands. That is, each command should be atomic or self-contained.
Trains will be addressed using a well-known addressing scheme. See TODO
All communications will be point-to-point, between a controller and a train.
A controller is any OpenLCB Node that might need to control a train; controllers includes hand-held cabs, computer control systems, or decentralized control units (such as auto-reversers for automated operation, or ATC systems).
A train is any model that runs on rails (i.e. is not steerable; thus, a train might include vehicles using the Faller or Tomix car systems). A train might be a single locomotive, a locomotive with carriages (e.g. passenger cars with interior lighting or markerlights that can be digitally controlled), a consist of multiple locomotives, a multiple unit, etc. Take, for example a model of the Usui Pass in Japan, ca. 1970. Electric multiple units that wished to traverse the pass (either up or down) needed to be assisted by a matched pair of EF63 electric locomotives. In this scenario, there are several potential train objects: The EMU by itself (being permanently consisted, the individual carriages would not count as trains in the sense being used here), each individual EF63, the EF63s in a paired consist, and the entire EF63+EF63+EMU consist are all train objects.
The head of a train is the node with control. In the case of a single locomotive, that train is its own head. In the case of a consist of multiple trains, the train at the very front in the forward direction of travel is the head.
Train Command Stations designed to act as a bridge between an OpenLCB network and a train control network, and hence that provides proxy OpenLCB Nodes to stand in for Trains unable to represent themselves, should adhere to the following schema for generating OpenLCB NodeIDs, as existing trains are unable to generate or provide these addresses for themselves. See OpenLCB Standard "OpenLCB Unique Identifiers", §5.5 for additional details.
byte 1 |
byte 2 |
byte 3 |
byte 4 |
byte 5 |
byte 6 |
||
0x06 |
[TCS ID] |
[DCS ID1] |
[DCS ID2] |
[Train ID1] |
[Train ID2] |
Where:
[TCS ID] is determined as:
0x00 |
DC operated train |
0x01 |
DCC operated train |
0x02 |
TMCC operated train |
0x03 |
Marklin/Motorola operated train |
0x04 |
MTH DCS operated train |
0x05 |
C/MRI operated train |
0x06 |
DC + Tomix CL operated train |
(This specification supercedes the allocation specified in OpenLCB Standard "OpenLCB Unique Identifiers", §5.5.)
[DCS IDx] is an identifier, unique on an OpenLCB network, indicating which Train Command Station has control of the train. Notice that this portion of the NodeID can and will change as the train roams from command station to command station. If only one command station is present, both [DCS IDx] will default to 0x00.
[Train IDx] is the identifier for the train as used by the train command station, with [Train ID1] the MSW and [Train ID2] the LSW. Thus, for DCC short addresses, [Train ID1] will be 0x00 and [Train ID2] will be the DCC short address. For DCC long addresses (which are 14 bits), [Train ID1] will be contain the most significant 6 bits of the DCC address, and pTrain ID2] will contain the 8 least significant bits.
All communications via the Train Control Protocol use the Datagram transport method. Each datagram consists of an PTI (protocol type identifier) byte, which is 0x30 for the Train Control Protocol, a command identifier byte, and zero or more bytes of command-specific data:
Command |
Command Identifier Byte |
Arguments |
|
---|---|---|---|
Emergency Stop |
0x00 |
||
Set Train Speed |
0x01 |
direction and speed (16-bit float) |
|
Inquire Train Speed |
0x03 |
kind of speed (8-bit flags) |
|
Report Train Speed |
0x02 |
kind of speed (8-bit flags) |
direction and speed (16-bit float) |
Set Train FX |
0x11 |
FX address (16-bit uint) FX setting (16-bit uint) |
|
Inquire Train FX |
0x13 |
FX address (16-bit uint) |
|
Report Train FX |
0x12 |
FX address (16-bit uint) FX setting (16-bit uint) |
|
Request Attach to Train |
0x21 |
||
Attach Permitted |
0x22 |
||
Attach Denied |
0x24 |
||
Train Release |
0x23 |
||
Controller Dropped |
0x26 |
||
Create Consist |
TODO |
TODO |
|
Add to Consist |
TODO |
TODO |
|
Set Consist Head |
TODO |
TODO |
|
Remove from Consist |
TODO |
TODO |
|
Destroy Consist |
TODO |
TODO |
Summary: Commands for controlling the movement of trains.
Notes on the table columns:
Direction: Some messages are issued by a controller ('C') for a train ('T'), and some are issued by a train for a controller. Notice that the least-significant bit of the CIB flags the directionality, with 0x01 indicating that the command is to a train, and 0x00 indicating that the command is from a train.
Controlled?: Controlled messages require the permission of a secure train prior to transmission (see below).
Command |
Direction |
Controlled? |
Protocol Identifier Byte |
Command Identifier Byte |
Arguments |
||
---|---|---|---|---|---|---|---|
Byte 1 |
Byte 2 |
Byte 3 |
Byte 4 |
Byte 5 |
|||
Emergency Stop |
C→T |
yes |
0x30 |
0x00 |
|||
Set Train Speed |
C→T |
yes |
0x30 |
0x01 |
direction and speed (float16) |
||
Inquire Train Speed |
C→T |
no |
0x30 |
0x03 |
kind of speed (8-bit flags) |
||
Report Train Speed |
T→C |
n/a |
0x30 |
0x02 |
kind of speed (8-bit flags) |
direction and speed (float16) |
Bring the train to an immediate halt, without regard to any physical simulation of momentum. Notice that this command is supplementary to the more general OpenLCB commands TODO, with the difference being primarily one of scope.
The speed and direction to set is encoded as a half-precision floating point number (aka 'float16'), with positive numbers indicating forward direction, negative indicating reverse, and zero indicating full (non-emergency) stop. The value specifies a speed in scale meters per second (scale-m/s).
Rationale: The use of a 16-bit floating point permits relatively precise speed commands, especially at lower speeds; such fine granulatity ensures not just fine-grained control over the locomotive, but helps avoid aliasing issue that arise during the conversion to lower resolution system-specific speed commands (i.e. DCC's 14 or 28-step commands).
The use of meters per second is somewhat arbitrary, and reflects standard velocity units used throughout the metric-speaking world. By standardizing on m/s, we avoid any future unit conversion issues.
The use of scale meters per second has two distinct advantages. First, it permits us to transmit speed commands in a scale-independent way. Second, and because of this, it reduces the number of parameters that must be estimated when controlling a locomotive that has not yet been speed-calibrated (which, for new users using existing digital control systems, will be all of their models). For example, on a DCC system, if I issue a command to proceed at 30mph, the command station must convert the value in the speed command from 30mph to an interger in the range [0-26] (for 28-speed-step control). The command station need only estimate what a reasonable top speed for a locomotive might be: Let us say, 100mph. Thus, the command station could reasonably estimate that 30mph translates to speed step 8.
The alternative possibilities considered to date are absolute speed using real units (as opposed to scale units), and relative speed units. The difficulty with relative speed units (i.e., percentage of full throttle), is that TODO. The difficulty with using real (as opposed to scale) units is that it requires the estimation of an additional parameter for uncalibrated locomotives, specifically the train's scale. If I issue a command to a DCC locomotive to proceed at 0.1 (real)m/s, the command station must not only understand what a reasonable top speed for a train is, but how to scale the speed appropriately, as 0.1 m/s might be quite fast for Z scale, but quite slow for G. As there is really no reasonable scale to use as a default, users must configure their digital command station to set the scale for either the entire layout, or on a per-model basis—an additional configuration step that is easily avoided by the mechanism for scale units described above.
This is a request for a train to report its speed. Any OpenLCB node may make inquiries about a train's state without requesting permission first (see Security Commands below), although the train is under no particular obligation to respond. This command takes no additional arguments.
Of course, a request for a train's speed is itself ambiguous. The controller might be interested in knowing any of a number of possible measures: What speed the train has been commanded to take; what speed the train is attempting to reach; what speed the train is actually travelling at. Thus, a speed inquiry requires a parameter to indicate the interests of the controller:
Speed Kind |
command argument |
|
Commanded speed |
0x00 |
|
Intended speed |
0x01 |
|
Actual speed |
0x03 |
This is a response to the Inquire Train Speed command, and combines the arguments to the Set Speed and Inquire Speed commands, returning both the kind of speed being reported using the same flags as above, and the speed itself as a float16.
Summary: Commands for controlling a train's special effects, including lighting and sound.
Notes on the table columns:
Direction: Some messages are issued by a controller ('C') for a train ('T'), and some are issued by a train for a controller. Notice that the least-significant bit of the CIB flags the directionality, with 0x01 indicating that the command is to a train, and 0x00 indicating that the command is from a train.
Controlled?: Controlled messages require the permission of a secure train prior to transmission (see below).
Command |
Direction |
Controlled? |
Protocol Identifier Byte |
Command Identifier Byte |
Arguments |
|||
---|---|---|---|---|---|---|---|---|
Byte 1 |
Byte 2 |
Byte 3 |
Byte 4 |
Byte 5 |
Byte 6 |
|||
Set Train FX |
C→T |
yes |
0x30 |
0x11 |
FX address (uint_16) |
FX value (uint_16) |
||
Inquire Train FX |
C→T |
no |
0x30 |
0x13 |
FX address (uint_16) |
|||
Report Train FX |
T→C |
n/a |
0x30 |
0x12 |
FX address (uint_16) |
FX value (uint_16) |
Many trains offer independent control of various special effects (FX, sometimes called "functions") such as lighting or sound. This command permits a controller to control these effects directly. The first argument is the address of the FX to control as a 16-bit unsigned integer. This protocol does not define a semantics for FX addresses; that is, there is no particular address that is singled out as represenging headlights or the airhorn. Instead, the addresses are deliberately abstract, permitting the user to decide how to map addresses to FX for each train.
Additionally, each FX can take a 16-bit value. Current technology only permits binary FX; thus 0x00 should be interpreted as "off" for a binary FX, and any non-zero value as "on". Analog (non-binary) FX should treat the 16-bit value as an unsigned integer.
Rationale: Most digital systems offer multiple FX, each of which is numbered. Although currently most DCC throttles only permit access to 12 or 29 functions, DCC (TODO to my knowledge!) technically permits as many as 32796* different binary FX (see RP-9.2.1: Function Group One Instruction, Function Group Two Instruction, and Feature Expansion Command Instruction especially the Binary State Control Subcommand). For this reason, it seems prudent to go ahead and use a 16-bit value.
Likewise, although current DCC decoders only permit binary FX, some (for example SoundTraxx Tsunami sound decoders) actually permit a kind of analog control of FX by combining multiple DCC Functions. Thus, it seems likewise prudent to permit a wide range of values, and not simply a binary on and off.
One problem that faces the decision to use a single command with a numerical FX addressing system is that any kind of standardized assignment of FX addresses to particular FX is impossible in practice. DCC, for example, makes no such prescription, although by convention function F0 controls direction-sensitive headlights. Beyond this lies only manufacturers' conventions. Thus, any kind of mapping is best handled on a per-train basis, by configuring the mapping between particular FX (e.g. headlights, airhorn) to FX addresses for each train.
One way to mitigate this problem is to not make fixed FX address assignments, but to map them directly onto the addressing scheme used by the various control systems, that is, to leave each address in the OpenLCB FX addres space uninterpreted. In this way, the default behavior of each address will map directly onto the default behavior of the decoder in the train, giving some degree of predictability to the system, and permitting a digital command station the make reasonable guesses about the possible address-to-FX mappings. Nevertheless, users will often need to be exposed to this implementational detail, which is deeply unfortunate, but necessary given the ultimate flexibility of current train control systems.
Thus, it is recommended that the FX address space be mapped directly to the particular control system's address space; thus DCC F0 becomes FX address 0x0000, F1 becomes 0x0001, etc. The DCC Binary State addresses should be mapped to 0x8000 to 0xFFFF (i.e., to the 15-bit range beginning with 0b1000.0000.0000.0000). Other systems should be handled analogously.
*RP-9.2.1 defines the following:
Function Group One: 5
(F0-F4)
Function Group Two: 8 (F5-F12)
Binary State Control:
32767 (15bits) (note: different address space!)
Feature Expansion
Command 11110: 8 (F13-F20)
Feature Expansion Command 11111: 8
(F21-F28)
And in the future, perhaps even more. Possibly a lot
more. There are just under 20bit of address space available in the
Feature Expansion Comman Instruction for the potential manipulation
of Binary State Controls.
Any node may inquire the state of a train's FX. The only argument is the address of the FX to query.
Notice that, because the semantics for the FX address space may vary from train to train, this command does not provide a useful way to query the state of a particular FX, e.g. the headlights.
This command is for trains to report the state of a particular FX in response to an Inquire FX command. The format of the parameters is the same as for the Set Train FX command.
TODO Create Consist Add To Consist Remove From Consist Destroy Consist Consisting Acknowledged Consisting Denied
Optional. Trains may restrict communications from controllers using the following packet kinds.
TODO Attach Request Attach Acknowledged Attach Denied Command Denied?
Oh, I did want to mention that I think we decided, at least tentatively, that functions would be handled via men config protocol, andthat for nodes with addresses in the well-known DCC range, we could use a convention where writes and reads to a pair of memoryspaces were to be interpreted as CV read/writes (in one space) and function updates (in the other). Did we talk about that, or wasthat all in my head?
We did talk about that for functions, and I really like the idea, but I wasn't sure we agreed on it.
For CVs, is the idea that we'd have a memory space that maps straight to the decoder CV space?
In both cases, that would allow decoder-specific CDI (if that was available) to customize what's presented. Like DecoderPro, the user wouldn't have to deal with CV 111, but rather with "Motor multisnarb angle offset" or whatever the user-fiendish manufacturer decides to provide as options.
There are two remaining issues. First, is handling "indexed" CVs. (Ones where you write 12 to CV 51, then 8 to CV52, and then CV54 is the value you want to read/write). QSI is the only extensive user of these, but they're starting to appear in other places too.
There are a couple ways to handle it. First, we could just map it as is: The configuring node would have to explicitly do those reads and writes. But that's a mess, well outside the OpenLCB model, and I've spent way to much time debugging weird failures with that.
A better approach, I think, is to use the large address space. E.g. CV 59 is found at 0x00 00 00 3B, while the one I mentioned above is found at 0x01 00 0C 08. (The 0x01 tells how to decode the address space, e.g. which CV the 2nd byte is written to, which the 3rd byte is written to. We'd have to extend CDI to carry that info, but it's within reason.
The other issue is packed CVs, e.g. mapping parts of one or more CVs to a single "variable". This could be just a single bit in one CV, or something more complicated split across two (like long addresses). I'm not sure how to map those as a general case. For bits, I'd suggest another mapping trick, where some other part of the space is actually bit mapped:
0xFF 00 53 3C
is the middle bits (the 3C mask) of CV 53, and the 0xFF is just an arbitrary key for this. That doesn't work with noncontiguous splits across generic CVs, though, as that takes a lot to configure.
(And don't get me started on CV1/CV29 sequencing; I think we just ignore that entirely at the CDI level & build it into the gateway to DCC)
In the end, these legacy pains can't really be avoided. We have to croft the OpenLCB protocols to do a reasonable job with them, but I don't think we have to go nearly as far into the weird special cases as e.g. DecoderPro does.
With a two-byte field for DCC address, one can use the NMRA coding to separate short, long, basic, etc.
http://nmra.org/standards/DCC/standards_rps/RP-921%202006%20Aug%2021.pdf
See section A on page 1.