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
89use serde::{Deserialize, Serialize};
90
91/// The Ergot Address type
92#[cfg_attr(feature = "defmt-v1", derive(defmt::Format))]
93#[derive(Clone, Copy, Debug, PartialEq)]
94pub struct Address {
95 pub network_id: u16,
96 pub node_id: u8,
97 pub port_id: u8,
98}
99
100// ---- impl Address ----
101
102impl Address {
103 pub const fn unknown() -> Self {
104 Self {
105 network_id: 0,
106 node_id: 0,
107 port_id: 0,
108 }
109 }
110
111 #[inline]
112 pub fn net_node_any(&self) -> bool {
113 self.network_id == 0 && self.node_id == 0
114 }
115
116 #[inline]
117 pub fn as_u32(&self) -> u32 {
118 ((self.network_id as u32) << 16) | ((self.node_id as u32) << 8) | (self.port_id as u32)
119 }
120
121 #[inline]
122 pub fn from_word(word: u32) -> Self {
123 Self {
124 network_id: (word >> 16) as u16,
125 node_id: (word >> 8) as u8,
126 port_id: word as u8,
127 }
128 }
129}
130
131impl Serialize for Address {
132 #[inline]
133 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
134 where
135 S: serde::Serializer,
136 {
137 let val = self.as_u32();
138 val.serialize(serializer)
139 }
140}
141
142impl<'de> Deserialize<'de> for Address {
143 #[inline]
144 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
145 where
146 D: serde::Deserializer<'de>,
147 {
148 let val = u32::deserialize(deserializer)?;
149 Ok(Self::from_word(val))
150 }
151}
152
153#[cfg(feature = "postcard-schema-v0_2")]
154impl postcard_schema::Schema for Address {
155 const SCHEMA: &'static postcard_schema::schema::NamedType =
156 &postcard_schema::schema::NamedType {
157 name: "Address",
158 ty: u32::SCHEMA.ty,
159 };
160}