ergot_base/address.rs
1//! Addressing
2//!
3//! Addresses in Ergot have three main components:
4//!
5//! * A 16-bit **Network ID**
6//! * An 8-bit **Node ID**
7//! * An 8-bit **Socket ID**
8//!
9//! This addressing is similar in form to AppleTalk's addressing. This
10//! addressing is quite different to how TCP/IP IPv4 addressing works.
11//!
12//! ### Network IDs
13//!
14//! Network IDs represent a single "network segment", where all nodes of a
15//! network segment can hear all messages sent on that segment.
16//!
17//! For example, in a point-to-point link (e.g. UART, TCP, USB), that link will
18//! be a single Network ID, containing two nodes. In a bus-style link
19//! (e.g. RS-485, I2C), the bus will be a single Network ID, with one or more
20//! nodes residing on that link.
21//!
22//! The Network ID of "0" is reserved, and is generally used when sending
23//! messages within the local device, or used to mean "the current network
24//! segment" before an interface has discovered the Network ID of the Network
25//! Segment it resides on.
26//!
27//! The Network ID of "65535" is reserved.
28//!
29//! Network IDs are intended to be discovered/negotiated at runtime, and are
30//! not typically hardcoded. The general process of negotiating Network IDs,
31//! particularly across multiple network segment hops, is not yet defined.
32//!
33//! Networks that require more than 65534 network segments are not supported
34//! by Ergot. At that point, you should probably just use IPv4/v6.
35//!
36//! ### Node IDs
37//!
38//! Node IDs represent a single entity on a network segment.
39//!
40//! The Node ID of "0" is reserved, and is generally used when sending messages
41//! within the local device.
42//!
43//! The Node ID of "255" is reserved.
44//!
45//! Network segments that require more than 254 nodes are not supported by
46//! Ergot.
47//!
48//! Network IDs are intended to be discovered/negotiated at runtime, and are
49//! not typically hardcoded. One exception to this is for known point-to-point
50//! network segments that have a defined "controller" and "target" role, such
51//! as USB (where the "host" is the "controller", and the "device" is the
52//! "target"). In these cases, the "controller" typically hardcodes the Node ID
53//! of "1", and the "target" hardcodes the Node ID of "2". This is done to
54//! reduce complexity on these interface implementations.
55//!
56//! ### Socket IDs
57//!
58//! Socket IDs represent a single receiving socket within a [`NetStack`].
59//!
60//! The Socket ID of "0" is reserved, and is generally used as a "wildcard"
61//! when sending messages to a device.
62//!
63//! The Socket ID of "255" is reserved.
64//!
65//! Systems that require more than 254 active sockets are not supported by
66//! Ergot.
67//!
68//! Socket IDs are assigned dynamically by the [`NetStack`], and are never
69//! intended to be hardcoded. Socket IDs may be recycled over time.
70//!
71//! If a device has multiple interfaces, and therefore has multiple (Network ID,
72//! Node ID) tuples that refer to it, the same Socket ID is used on all
73//! interfaces.
74//!
75//! ### Form on the wire
76//!
77//! When serialized into a packet, addresses are encoded with Network ID as the
78//! most significant bytes, and the socket ID as the least significant bytes,
79//! and then varint encoded. This means that in many cases, where "0" is used
80//! for the Network or Node ID, or low numbers are used, Addresses can be
81//! encoded in fewer than 4 bytes on the wire.
82//!
83//! For this reason, when negotiating any ID, lower numbers should be preferred
84//! when possible. Addresses are only encoded as larger than 4 bytes when
85//! addressing a network ID >= 4096.
86//!
87//! [`NetStack`]: crate::NetStack
88
89/// The Ergot Address type
90#[derive(Clone, Copy, Debug, PartialEq)]
91pub struct Address {
92 pub network_id: u16,
93 pub node_id: u8,
94 pub port_id: u8,
95}
96
97// ---- impl Address ----
98
99impl Address {
100 pub const fn unknown() -> Self {
101 Self {
102 network_id: 0,
103 node_id: 0,
104 port_id: 0,
105 }
106 }
107
108 #[inline]
109 pub fn net_node_any(&self) -> bool {
110 self.network_id == 0 && self.node_id == 0
111 }
112
113 #[inline]
114 pub fn as_u32(&self) -> u32 {
115 ((self.network_id as u32) << 16) | ((self.node_id as u32) << 8) | (self.port_id as u32)
116 }
117
118 #[inline]
119 pub fn from_word(word: u32) -> Self {
120 Self {
121 network_id: (word >> 16) as u16,
122 node_id: (word >> 8) as u8,
123 port_id: word as u8,
124 }
125 }
126}