#[non_exhaustive]pub enum Message {
Show 26 variants
InitializationComplete {
node_id: NodeId,
simple: bool,
},
VerifyNodeIdGlobal {
node_id: Option<NodeId>,
},
VerifyNodeIdAddressed {
dest: u16,
node_id: Option<NodeId>,
},
VerifiedNodeId {
node_id: NodeId,
simple: bool,
},
OptionalInteractionRejected {
dest: u16,
code: u16,
mti: Mti,
},
TerminateDueToError {
dest: u16,
code: u16,
mti: Mti,
},
ProtocolSupportInquiry {
dest: u16,
},
ProtocolSupportReply {
dest: u16,
flags: u32,
},
IdentifyConsumer(EventId),
ConsumerIdentified {
event: EventId,
state: EventState,
},
ConsumerRangeIdentified(EventId),
IdentifyProducer(EventId),
ProducerIdentified {
event: EventId,
state: EventState,
},
ProducerRangeIdentified(EventId),
IdentifyEventsGlobal,
IdentifyEventsAddressed {
dest: u16,
},
LearnEvent(EventId),
Pcer(EventId),
TractionCommand {
dest: u16,
payload: Vec<u8>,
},
TractionReply {
dest: u16,
payload: Vec<u8>,
},
SnipRequest {
dest: u16,
},
SnipReply {
dest: u16,
data: Vec<u8>,
},
Datagram {
dest: u16,
data: Vec<u8>,
},
DatagramReceivedOk {
dest: u16,
flags: u8,
},
DatagramRejected {
dest: u16,
code: u16,
},
Other {
mti: Mti,
dest: Option<u16>,
payload: Vec<u8>,
},
}Expand description
A decoded OpenLCB message. Addressed messages carry the 12-bit dest
alias of the node they are sent to.
The source of a message is not part of Message: when sending, it is
the alias of the sending Node; when receiving, it is in
the surrounding Received. Every variant maps to exactly one
Mti (see Message::mti); MTIs without a dedicated variant are
carried by Message::Other, so decoding never fails.
Traction payloads are kept as raw bytes; decode them with
traction::Command::decode and
traction::Reply::decode. SNIP data
decodes with NodeInfo::from_snip.
use rolcb::{EventId, EventState, Message, Mti};
let m = Message::ProducerIdentified { event: EventId(1), state: EventState::Valid };
assert_eq!(m.mti(), Mti::PRODUCER_IDENTIFIED_VALID);
assert_eq!(m.dest(), None);
assert_eq!(m.payload(), vec![0, 0, 0, 0, 0, 0, 0, 1]);
let q = Message::SnipRequest { dest: 0x6A1 };
assert_eq!(q.dest(), Some(0x6A1));The enum is #[non_exhaustive] so that new MTIs can get dedicated
variants without a breaking release: match it with a _ arm (which also
covers Message::Other).
Variants (Non-exhaustive)§
This enum is marked as non-exhaustive
InitializationComplete
Initialization Complete (MTI 0x0100/0x0101). The last step of a
node’s login; announces it is ready to communicate.
Fields
VerifyNodeIdGlobal
Verify Node ID Global (MTI 0x0490). Every node, or only the node
whose ID is given, replies with Message::VerifiedNodeId. Tools use
it to enumerate the network.
VerifyNodeIdAddressed
Verify Node ID Addressed (MTI 0x0488): ask one node to identify
itself, e.g. to confirm an alias is still mapped.
VerifiedNodeId
Verified Node ID (MTI 0x0170/0x0171): reply to Verify Node ID.
Fields
OptionalInteractionRejected
Optional Interaction Rejected (MTI 0x0068): the destination sent us
a request we do not support.
Fields
code: u16Error code, see crate::mti::error_code.
TerminateDueToError
Terminate Due To Error (MTI 0x00A8): an ongoing interaction failed.
Fields
code: u16Error code, see crate::mti::error_code.
ProtocolSupportInquiry
Protocol Support Inquiry (MTI 0x0828): “which protocols do you
support?” Node answers automatically.
ProtocolSupportReply
Protocol Support Reply (MTI 0x0668).
Fields
IdentifyConsumer(EventId)
Identify Consumer (MTI 0x08F4): nodes that consume this event reply
with Message::ConsumerIdentified.
ConsumerIdentified
Consumer Identified (MTI 0x04C4/0x04C5/0x04C7): the sender
consumes event, and reports its view of the event’s state.
ConsumerRangeIdentified(EventId)
Consumer Range Identified (MTI 0x04A4): the sender consumes a
range of events. The range is encoded in the ID itself: the
low-order bits that are all equal (all 1s or all 0s) are “don’t care”.
IdentifyProducer(EventId)
Identify Producer (MTI 0x0914): nodes that produce this event reply
with Message::ProducerIdentified. Also used for train search (see
traction::search).
ProducerIdentified
Producer Identified (MTI 0x0544/0x0545/0x0547): the sender
produces event, and reports whether it is currently valid.
ProducerRangeIdentified(EventId)
Producer Range Identified (MTI 0x0524): the sender produces a range
of events, encoded like Message::ConsumerRangeIdentified.
IdentifyEventsGlobal
Identify Events Global (MTI 0x0970): every node replies with
Producer/Consumer Identified for all its events.
IdentifyEventsAddressed
Identify Events Addressed (MTI 0x0968): one node lists all its events.
LearnEvent(EventId)
Learn Event (MTI 0x0594): teaching message. A node in “learn” mode
adopts this Event ID for the selected input or output.
Pcer(EventId)
Producer/Consumer Event Report: “this event happened”.
MTI 0x05B4. The core message of the Event Transport Standard:
a producer sends it, and every consumer of the Event ID acts on it.
TractionCommand
Traction Control Command (MTI 0x05EB), throttle → train. Build the
payload with traction::Command::encode.
TractionReply
Traction Control Reply (MTI 0x01E9), train → throttle. Decode the
payload with traction::Reply::decode.
SnipRequest
Simple Node Information Request (MTI 0x0DE8).
SnipReply
Simple Node Information Reply (MTI 0x0A08), usually several frames.
Fields
data: Vec<u8>Encoded SNIP strings, see NodeInfo::snip_payload.
Datagram
Datagram (MTI 0x1C48): an addressed, acknowledged block of up to 72
bytes (Datagram Transport Standard). The first byte identifies the
datagram protocol (e.g. 0x20 for Memory Configuration). The
receiver must answer with Message::DatagramReceivedOk or
Message::DatagramRejected.
Fields
data: Vec<u8>Datagram contents, at most 72 bytes (MAX_DATAGRAM). Enforced
by Message::try_to_frames, not by Message::to_frames.
DatagramReceivedOk
Datagram Received OK (MTI 0x0A28).
Fields
DatagramRejected
Datagram Rejected (MTI 0x0A48).
Fields
code: u16Error code, see crate::mti::error_code. Temporary errors
(0x2xxx) invite a resend.
Other
Anything not specifically decoded.
Also produced for a known MTI whose payload is too short to decode (for example a PCER with fewer than 8 bytes).
Implementations§
Source§impl Message
impl Message
Sourcepub fn dest(&self) -> Option<u16>
pub fn dest(&self) -> Option<u16>
Destination alias for addressed messages; None for global ones.
Sourcepub fn payload(&self) -> Vec<u8> ⓘ
pub fn payload(&self) -> Vec<u8> ⓘ
The message payload (for addressed messages, excluding the destination).
This is the byte sequence defined by the relevant standard: a Node ID, an Event ID, error code + MTI, and so on. The Protocol Support Reply is padded to six bytes.
Sourcepub fn from_parts(mti: Mti, dest: Option<u16>, p: Vec<u8>) -> Message
pub fn from_parts(mti: Mti, dest: Option<u16>, p: Vec<u8>) -> Message
Decode from MTI, destination and payload.
This is the inverse of Message::mti + Message::dest +
Message::payload. It never fails: unknown MTIs and payloads too
short for their MTI become Message::Other. dest should be
Some for addressed MTIs (a missing destination decodes as alias 0).
Usually fed from a RawMessage produced by an Assembler; the
From<RawMessage> impl does exactly that.
use rolcb::{EventId, Message, Mti};
let m = Message::from_parts(Mti::PCER, None, vec![5, 1, 1, 1, 0x22, 0, 0, 0x10]);
assert_eq!(m, Message::Pcer(EventId(0x0501_0101_2200_0010)));
// Too short to hold an Event ID: kept as Other.
let m = Message::from_parts(Mti::PCER, None, vec![1, 2]);
assert!(matches!(m, Message::Other { .. }));Sourcepub fn try_to_frames(
&self,
src_alias: u16,
) -> Result<Vec<CanFrame>, EncodeError>
pub fn try_to_frames( &self, src_alias: u16, ) -> Result<Vec<CanFrame>, EncodeError>
Encode as one or more CAN frames sent from src_alias, rejecting
messages that cannot be represented faithfully.
Framing is the same as Message::to_frames. The checks are:
| Problem | Error |
|---|---|
| global message with more than 8 payload bytes | EncodeError::GlobalPayloadTooLong |
addressed MTI with no dest (Message::Other only) | EncodeError::MissingDestination |
global MTI with a dest (Message::Other only) | EncodeError::UnexpectedDestination |
MTI with bit 12 or higher set, other than Mti::DATAGRAM | EncodeError::MtiTooWide |
| datagram over 72 bytes | EncodeError::DatagramTooLong |
§Errors
Returns the first EncodeError from the table above.
use rolcb::{EncodeError, Message, Mti};
let ok = Message::Datagram { dest: 0x456, data: vec![0x20; 72] };
assert_eq!(ok.try_to_frames(0x123)?.len(), 9);
let wide = Message::Other { mti: Mti(0x1F88), dest: Some(0x456), payload: vec![] };
assert!(matches!(wide.try_to_frames(0x123), Err(EncodeError::MtiTooWide { .. })));Sourcepub fn to_frames(&self, src_alias: u16) -> Vec<CanFrame>
pub fn to_frames(&self, src_alias: u16) -> Vec<CanFrame>
Encode as one or more CAN frames sent from src_alias.
- Global messages produce one frame (payload truncated to 8 bytes).
- Addressed messages produce one frame per 6 payload bytes (at least one), each starting with the framing flag and destination alias as described in the module docs.
- Datagrams produce one frame per 8 bytes using the datagram frame types.
This encoder is lenient and never fails. For a message that
Message::try_to_frames would reject it keeps its historical
behaviour: global payloads are truncated to 8 bytes, an addressed MTI
without a destination is sent as if it were global, a destination on
a global MTI is sent as addressed framing, bits 12-15 of the MTI are
dropped, and datagrams over 72 bytes are split into as many frames as
needed. In debug builds such a message trips a debug_assert!; use
try_to_frames when the message comes from untrusted input.
§Panics
In debug builds only, if try_to_frames would return an error.
use rolcb::{gridconnect, Message, NodeId};
let m = Message::VerifyNodeIdAddressed { dest: 0x456, node_id: None };
let f = m.to_frames(0x123);
assert_eq!(gridconnect::format(&f[0]), ":X19488123N0456;");
// A 20-byte datagram: frame types 3 (first), 4 (middle), 5 (final).
let d = Message::Datagram { dest: 0x456, data: (0..20).collect() };
let ids: Vec<u32> = d.to_frames(0x123).iter().map(|f| f.id).collect();
assert_eq!(ids, [0x1B45_6123, 0x1C45_6123, 0x1D45_6123]);Trait Implementations§
impl Eq for Message
Source§impl From<RawMessage> for Message
impl From<RawMessage> for Message
Source§fn from(raw: RawMessage) -> Message
fn from(raw: RawMessage) -> Message
Decode with Message::from_parts. The source alias is dropped.