pub struct Node { /* private fields */ }Expand description
A virtual OpenLCB node.
Node is a pure state machine: it owns no socket or timer. See the
module documentation for the lifecycle, the replies it sends on
its own, and a complete login example. A node is cheap; an application
such as a throttle typically runs exactly one.
Event registration (add_producer,
add_consumer) only affects identification
replies. Node does not filter PCERs: every received PCER is returned
from receive and the application decides what to do.
Implementations§
Source§impl Node
impl Node
Sourcepub fn new(node_id: NodeId, info: NodeInfo) -> Self
pub fn new(node_id: NodeId, info: NodeInfo) -> Self
Create an inhibited (offline) node. Call Node::start to log in.
The node initially advertises
EVENT_EXCHANGE | SNIP;
change that with Node::set_protocols.
Sourcepub fn alias(&self) -> Option<u16>
pub fn alias(&self) -> Option<u16>
Our alias, once it has been successfully reserved.
None while inhibited or reserving. The alias can change at runtime
if a collision forces a new reservation, so do not cache it for long.
Sourcepub fn is_permitted(&self) -> bool
pub fn is_permitted(&self) -> bool
True once the alias is reserved and the node may send messages (the CAN “Permitted” state).
Sourcepub fn duplicate_node_id_detected(&self) -> bool
pub fn duplicate_node_id_detected(&self) -> bool
True if another node on the bus announced our Node ID (in an AMD, Initialization Complete or Verified Node ID). The user must configure a different Node ID.
The first detection also sends a PCER for
EventId::DUPLICATE_NODE_ID (held until login if necessary). The
flag stays set until the node is recreated.
Sourcepub fn set_protocols(&mut self, flags: u32)
pub fn set_protocols(&mut self, flags: u32)
Set the Protocol Support Inquiry reply flags (see protocol).
Setting protocol::TRACTION_CONTROL also stops the node from
auto-rejecting Traction Control Commands, so a train implementation
can handle them itself.
Sourcepub fn protocols(&self) -> u32
pub fn protocols(&self) -> u32
The Protocol Support Inquiry reply flags (see Node::set_protocols).
Sourcepub fn set_info(&mut self, info: NodeInfo)
pub fn set_info(&mut self, info: NodeInfo)
Replace the Simple Node Information. Takes effect with the next SNIP request; nothing is sent by itself.
Sourcepub fn start(&mut self, now_ms: u64)
pub fn start(&mut self, now_ms: u64)
Begin (or restart) alias reservation.
Picks the next candidate alias, queues the four CID frames and arms the
200 ms timer. Call Node::poll at or after
Node::next_deadline to finish the login.
CID frames of an earlier reservation that are still in the outbox are dropped, so a restart never puts two sets on the wire.
Calling start while permitted gives up the current alias: an
AMR frame for it is queued first, then the node reserves a new alias
as above. It does not send a second Initialization Complete (use
Node::reset first for a full re-login).
Sourcepub fn reset(&mut self)
pub fn reset(&mut self)
Go offline (e.g. the link dropped). Call Node::start to rejoin.
Clears the outbox, partial messages and the alias table, and
re-arms Initialization Complete for the next login. Registered events
and messages queued with Node::send are kept.
Sourcepub fn next_deadline(&self) -> Option<u64>
pub fn next_deadline(&self) -> Option<u64>
The next time Node::poll has work to do, if any.
Only Some while an alias reservation is in progress.
Sourcepub fn poll(&mut self, now_ms: u64)
pub fn poll(&mut self, now_ms: u64)
Advance timers.
When the reservation timer expires this queues RID and AMD, then (on
the first login only) Initialization Complete and Identified messages
for every registered event, and finally any messages queued by
Node::send before login. Cheap to call often.
Sourcepub fn send(&mut self, msg: Message)
pub fn send(&mut self, msg: Message)
Queue a message for transmission. Messages sent before login completes are held and sent as soon as the alias is reserved.
At most MAX_PENDING (512) messages are held while offline;
further ones are silently dropped (use Node::try_send to find
out). Once permitted, the message is immediately encoded into frames;
collect them with Node::take_outgoing.
Encoding uses the lenient rules of Message::to_frames (without
its debug assertion); validate untrusted messages with
Message::try_to_frames first.
Sourcepub fn try_send(&mut self, msg: Message) -> bool
pub fn try_send(&mut self, msg: Message) -> bool
Like Node::send, but returns false if the message was dropped
because MAX_PENDING messages are already waiting for login.
Sourcepub fn take_outgoing(&mut self) -> Vec<CanFrame>
pub fn take_outgoing(&mut self) -> Vec<CanFrame>
Drain frames waiting to be transmitted.
Frames are returned in the order they must be sent. Write each to the
bus (for example with gridconnect::format).
Sourcepub fn pop_outgoing(&mut self) -> Option<CanFrame>
pub fn pop_outgoing(&mut self) -> Option<CanFrame>
Remove and return the next frame to transmit, without allocating.
Useful with a CAN driver that has a small transmit queue: pop a frame, try to send it, and keep it for later if the driver is full.
use rolcb::{Node, NodeId, NodeInfo};
let mut node = Node::new(NodeId::new(0x0501_0101_2299), NodeInfo::default());
node.start(0);
let mut n = 0;
while let Some(_frame) = node.pop_outgoing() {
n += 1; // write _frame to the driver
}
assert_eq!(n, 4); // the CID framesSourcepub fn add_producer(&mut self, event: EventId, state: EventState)
pub fn add_producer(&mut self, event: EventId, state: EventState)
Register an event we produce (we send PCERs for it).
If the node is already permitted and the event is new, a Producer Identified message is sent right away. Registering again with a different state just updates the state.
Sourcepub fn add_consumer(&mut self, event: EventId, state: EventState)
pub fn add_consumer(&mut self, event: EventId, state: EventState)
Register an event we consume (we act on PCERs for it).
Announced with Consumer Identified, like
add_producer. Registering a consumer tells
producers and tools that someone listens; it does not filter what
receive returns.
Sourcepub fn set_producer_state(&mut self, event: EventId, state: EventState)
pub fn set_producer_state(&mut self, event: EventId, state: EventState)
Update the state reported for a registered produced event. Ignored for
unregistered events. Does not send anything by itself; send a
Message::Pcer if the event just happened.
Sourcepub fn set_consumer_state(&mut self, event: EventId, state: EventState)
pub fn set_consumer_state(&mut self, event: EventId, state: EventState)
Update the state reported for a registered consumed event. Ignored for unregistered events.
Sourcepub fn clear_events(&mut self)
pub fn clear_events(&mut self)
Forget all registered producers and consumers.
Sourcepub fn alias_of(&self, node: NodeId) -> Option<u16>
pub fn alias_of(&self, node: NodeId) -> Option<u16>
Look up the alias of a node (from AMD / Init Complete / Verified Node ID).
Returns None if the mapping has not been seen yet or was reset by an
AMR.
Sourcepub fn node_of(&self, alias: u16) -> Option<NodeId>
pub fn node_of(&self, alias: u16) -> Option<NodeId>
Look up the node behind an alias, if known.
Sourcepub fn receive(&mut self, frame: &CanFrame, now_ms: u64) -> Option<Received>
pub fn receive(&mut self, frame: &CanFrame, now_ms: u64) -> Option<Received>
Process a frame from the bus. Returns the decoded message, if the frame completed one. Standard replies are queued automatically.
Pass every frame read from the bus, including ones addressed to other
nodes. Control frames update alias state and return None; the first
frames of multi-frame messages also return None. now_ms is used
when an alias collision forces a new reservation and to expire
incomplete multi-frame messages (see Assembler::accept_at).
Never feed the node its own transmitted frames (for example from
a CAN driver or hub that echoes transmissions back). A frame carrying
our own alias is, by definition, an alias collision: the node would
release its alias with AMR and log in again, over and over. Filter
out local echo before calling receive.
use rolcb::node::ALIAS_RESERVE_MS;
use rolcb::{EventId, Message, Node, NodeId, NodeInfo};
let mut node = Node::new(NodeId::new(0x0501_0101_2299), NodeInfo::default());
node.start(0);
node.poll(ALIAS_RESERVE_MS);
let _ = node.take_outgoing();
// A PCER from some other node (alias 0x333):
let frame = Message::Pcer(EventId(5)).to_frames(0x333)[0];
let rx = node.receive(&frame, 300).unwrap();
assert_eq!(rx.src_alias, 0x333);
assert_eq!(rx.src_node, None); // we never saw its AMD
assert_eq!(rx.msg, Message::Pcer(EventId(5)));