Expand description
Traction Control protocol payloads (MTI 0x05EB command / 0x01E9 reply) and the Train Search protocol.
In OpenLCB every locomotive (or consist) is a train node. For DCC locos the train node is usually virtual and lives in the command station, which turns traction commands into DCC packets. A throttle drives a train by sending addressed Traction Control Command messages to it and reading Traction Control Reply messages back, as defined by the Traction Control Standard.
This module only encodes and decodes the payload bytes. Wrap them in
Message::TractionCommand /
Message::TractionReply and send them
through a Node. The throttle guide
walks through a whole session.
§A throttle session
- Find the train. Send Identify Producer for a search event built from the DCC address. The train node (allocated by the command station if needed) answers with Producer Identified for the same event; its source alias is the train.
- Assign controller. Send
Command::AssignControllerwith our Node ID. The train answersReply::AssignControllerwith result 0 if accepted. Only the assigned controller should send speed commands. - Drive.
Command::SetSpeed,Command::SetFunction,Command::EmergencyStop. Query state withCommand::QuerySpeed/Command::QueryFunction. - Stay alive. A train may send
Reply::Heartbeatasking for any command withintimeout_sseconds; answer withCommand::Noopor the train will stop itself. - Release with
Command::ReleaseController.
§Controller handover
When a second throttle sends Assign Controller to a train that already
has a controller, the train asks the current controller first. It
sends the command Command::ControllerChangingNotify (20 04 flags NodeID, carrying the new controller’s Node ID) to the current
controller, which answers with the reply Reply::ControllerChanged
(20 04 result): result 0 accepts the handover, nonzero refuses it.
So a throttle receives a Traction Control Command in this one case,
even though it is not a train; Node delivers it
instead of rejecting it. On accepting, the throttle should stop sending
commands to that train and tell the user it lost control. The
throttle guide
shows the exchange.
§Command bytes
| Byte 0 | Byte 1 | Meaning | Rest |
|---|---|---|---|
0x00 | Set Speed | half-float speed (2 bytes) | |
0x01 | Set Function | 24-bit address, 16-bit value | |
0x02 | Emergency Stop | ||
0x10 | Query Speed | ||
0x11 | Query Function | 24-bit address | |
0x20 | 0x01 | Assign Controller | flags, Node ID (6) |
0x20 | 0x02 | Release Controller | flags, Node ID (6) |
0x20 | 0x03 | Query Controller | |
0x20 | 0x04 | Controller Changing Notify (train → current controller) | flags, new controller Node ID (6) |
0x30 | Consist (listener) config | ||
0x40 | 0x01 | Management: Reserve | |
0x40 | 0x02 | Management: Release | |
0x40 | 0x03 | Management: Noop / heartbeat |
Replies reuse the same command bytes; see Reply. Constants are in
cmd. Bit 7 of byte 0 (cmd::LISTENER_FLAG) marks a command
forwarded to a consist member and is ignored by Command::decode.
use rolcb::traction::{Command, Reply, Speed};
// 1.0 m/s forward is half-float 0x3C00.
assert_eq!(Command::SetSpeed(Speed::from_mps(1.0, false)).encode(), [0x00, 0x3C, 0x00]);
// Same speed in reverse: the sign bit is set.
assert_eq!(Command::SetSpeed(Speed::from_mps(1.0, true)).encode(), [0x00, 0xBC, 0x00]);
// F3 on.
assert_eq!(Command::SetFunction { addr: 3, value: 1 }.encode(), [0x01, 0, 0, 3, 0, 1]);
assert_eq!(Reply::decode(&[0x40, 0x03, 10]), Reply::Heartbeat { timeout_s: 10 });Modules§
- cmd
- Traction Control command and sub-command byte values.
- search
- Train Search protocol: find (or allocate) a train node by DCC address by emitting Identify Producer for a specially formed event ID. Matching train nodes answer with Producer Identified for the same event.
Structs§
- Speed
- A traction speed: IEEE half-float in scale m/s, sign bit = reverse.
Enums§
- Command
- A Traction Control Command (throttle → train).
- Reply
- A Traction Control Reply (train → throttle).
Functions§
- function_
value - Function number helpers: F0..F28 map directly to function addresses 0..28.