Skip to main content

Node

Struct Node 

Source
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

Source

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.

Source

pub fn node_id(&self) -> NodeId

This node’s 48-bit Node ID.

Source

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.

Source

pub fn is_permitted(&self) -> bool

True once the alias is reserved and the node may send messages (the CAN “Permitted” state).

Source

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.

Source

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.

Source

pub fn protocols(&self) -> u32

The Protocol Support Inquiry reply flags (see Node::set_protocols).

Source

pub fn info(&self) -> &NodeInfo

The Simple Node Information this node reports.

Source

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.

Source

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).

Source

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.

Source

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.

Source

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.

Source

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.

Source

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.

Source

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).

Source

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 frames
Source

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.

Source

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.

Source

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.

Source

pub fn set_consumer_state(&mut self, event: EventId, state: EventState)

Update the state reported for a registered consumed event. Ignored for unregistered events.

Source

pub fn clear_events(&mut self)

Forget all registered producers and consumers.

Source

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.

Source

pub fn node_of(&self, alias: u16) -> Option<NodeId>

Look up the node behind an alias, if known.

Source

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)));

Trait Implementations§

Source§

impl Debug for Node

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl Freeze for Node

§

impl RefUnwindSafe for Node

§

impl Send for Node

§

impl Sync for Node

§

impl Unpin for Node

§

impl UnsafeUnpin for Node

§

impl UnwindSafe for Node

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.