Skip to main content

Module message

Module message 

Source
Expand description

High-level OpenLCB messages and their encoding onto CAN frames.

A Message is one OpenLCB message as defined by the Message Network Standard and the protocol standards built on it (Event Transport, Traction Control, Simple Node Information, Datagram Transport). This module converts between messages and CAN frames, following the CAN Frame Transfer Standard:

Node wires these together (and resolves aliases into Node IDs for Received), but they are usable on their own, for example in a bus monitor.

§Global, addressed and datagram framing

Global messages (no destination, e.g. PCER) have at most 8 payload bytes and always fit in one frame, with the CAN-MTI in the header.

Addressed messages (MTI bit 3 set, e.g. Traction Control) start each frame’s data with two bytes holding a 4-bit framing flag and the 12-bit destination alias, leaving 6 payload bytes per frame:

 data[0] = FFFF DDDD   FFFF = framing flag, DDDD = dest alias bits 11-8
 data[1] = DDDD DDDD   dest alias bits 7-0
 data[2..8]            up to 6 payload bytes

 flag 0x0_ : only frame        flag 0x1_ : first frame
 flag 0x3_ : middle frame      flag 0x2_ : last frame

So a 9-byte Assign Controller command becomes two frames, the first flagged 0x1_ with 6 bytes and the second flagged 0x2_ with 3.

Datagrams carry the destination in the header instead, so each frame holds a full 8 bytes, and the framing is expressed by the frame type (only / first / middle / final, see MessageFrameType).

Multi-frame messages from different senders, or to different destinations, may interleave on the bus; the Assembler keys partial messages by (source, destination, MTI).

§Example

use rolcb::message::{Assembler, Message};
use rolcb::{gridconnect, EventId};

// A global message: one frame.
let pcer = Message::Pcer(EventId(0x0501_0101_2200_0010));
let frames = pcer.to_frames(0x123);
assert_eq!(gridconnect::format(&frames[0]), ":X195B4123N0501010122000010;");

// An addressed message with a 15-byte payload: three frames.
let reply = Message::TractionReply { dest: 0xABC, payload: (0..15).collect() };
let frames = reply.to_frames(0x123);
assert_eq!(frames.len(), 3);
assert_eq!(frames[0].data()[0], 0x1A); // first frame, dest bits 11-8 = 0xA
assert_eq!(frames[1].data()[0], 0x3A); // middle
assert_eq!(frames[2].data()[0], 0x2A); // last

// Reassemble and decode.
let mut asm = Assembler::new();
let raw = frames.iter().find_map(|f| asm.accept(f)).unwrap();
assert_eq!(raw.src_alias, 0x123);
assert_eq!(Message::from(raw), reply);

Modules§

protocol
Protocol Support Inquiry flag bits (first three bytes of the reply, with byte 0 in bits 23-16).

Structs§

Assembler
Reassembles multi-frame addressed messages and datagrams.
RawMessage
A complete message reassembled from frames, before decoding.
Received
A message received from the bus, with its source.

Enums§

EncodeError
Why Message::try_to_frames refused to encode a message.
Message
A decoded OpenLCB message. Addressed messages carry the 12-bit dest alias of the node they are sent to.

Constants§

MAX_DATAGRAM
The largest datagram the Datagram Transport Standard allows (72 bytes).
PARTIAL_TIMEOUT_MS
How long Assembler::accept_at keeps a partial multi-frame message that receives no further frames (3 s).