ergot_base/interface_manager/
mod.rs

1//! The Interface Manager
2//!
3//! The [`NetStack`] is generic over an "Interface Manager", which is
4//! responsible for handling any external interfaces of the current program
5//! or device.
6//!
7//! Different interface managers may support a various number of external
8//! interfaces. The simplest interface manager is a "Null Interface Manager",
9//! Which supports no external interfaces, meaning that messages may only be
10//! routed locally.
11//!
12//! The next simplest interface manager is one that only supports zero or one
13//! active interfaces, for example if a device is directly connected to a PC
14//! using USB. In this case, routing is again simple: if messages are not
15//! intended for the local device, they should be routed out of the one external
16//! interface. Similarly, if we support an interface, but it is not connected
17//! (e.g. the USB cable is unplugged), all packets with external destinations
18//! will fail to send.
19//!
20//! For more complex devices, an interface manager with multiple (bounded or
21//! unbounded) interfaces, and more complex routing capabilities, may be
22//! selected.
23//!
24//! Unlike Sockets, which might be various and diverse on all systems, a system
25//! is expected to have one statically-known interface manager, which may
26//! manage various and diverse interfaces. Therefore, the interface manager is
27//! a generic type (unlike sockets), while the interfaces owned by an interface
28//! manager use similar "trick"s like the socket list to handle different
29//! kinds of interfaces (for example, USB on one interface, and RS-485 on
30//! another).
31//!
32//! In general when sending a message, the [`NetStack`] will check if the
33//! message is definitively for the local device (e.g. Net ID = 0, Node ID = 0),
34//! and if not the NetStack will pass the message to the Interface Manager. If
35//! the interface manager can route this packet, it informs the NetStack it has
36//! done so. If the Interface Manager realizes that the packet is still for us
37//! (e.g. matching a Net ID and Node ID of the local device), it may bounce the
38//! message back to the NetStack to locally route.
39//!
40//! [`NetStack`]: crate::NetStack
41
42use crate::{Header, HeaderSeq, ProtocolError};
43use serde::Serialize;
44
45pub mod cobs_stream;
46pub mod framed_stream;
47pub mod null;
48
49#[cfg(feature = "embassy-usb-v0_4")]
50pub mod eusb_0_4_client;
51
52#[cfg(feature = "nusb-v0_1")]
53pub mod nusb_0_1_router;
54
55#[cfg(feature = "std")]
56pub mod std_tcp_client;
57#[cfg(feature = "std")]
58pub mod std_tcp_router;
59#[cfg(feature = "std")]
60pub mod std_utils;
61
62#[derive(Debug, PartialEq, Eq)]
63#[non_exhaustive]
64pub enum InterfaceSendError {
65    /// Refusing to send local destination remotely
66    DestinationLocal,
67    /// Interface Manager does not know how to route to requested destination
68    NoRouteToDest,
69    /// Interface Manager found a destination interface, but that interface
70    /// was full in space/slots
71    InterfaceFull,
72    /// TODO: Remove
73    PlaceholderOhNo,
74    /// Destination was an "any" port, but a key was not provided
75    AnyPortMissingKey,
76    /// TTL has reached the terminal value
77    TtlExpired,
78}
79
80pub trait ConstInit {
81    const INIT: Self;
82}
83
84// An interface send is very similar to a socket send, with the exception
85// that interface sends are ALWAYS a serializing operation (or requires
86// serialization has already been done), which means we don't need to
87// differentiate between "send owned" and "send borrowed". The exception
88// to this is "send raw", where serialization has already been done, e.g.
89// if we are routing a packet.
90pub trait InterfaceManager {
91    fn send<T: Serialize>(&mut self, hdr: &Header, data: &T) -> Result<(), InterfaceSendError>;
92    fn send_err(&mut self, hdr: &Header, err: ProtocolError) -> Result<(), InterfaceSendError>;
93    fn send_raw(&mut self, hdr: &Header, data: &[u8]) -> Result<(), InterfaceSendError>;
94}
95
96impl InterfaceSendError {
97    pub fn to_error(&self) -> ProtocolError {
98        match self {
99            InterfaceSendError::DestinationLocal => ProtocolError::ISE_DESTINATION_LOCAL,
100            InterfaceSendError::NoRouteToDest => ProtocolError::ISE_NO_ROUTE_TO_DEST,
101            InterfaceSendError::InterfaceFull => ProtocolError::ISE_INTERFACE_FULL,
102            InterfaceSendError::PlaceholderOhNo => ProtocolError::ISE_PLACEHOLDER_OH_NO,
103            InterfaceSendError::AnyPortMissingKey => ProtocolError::ISE_ANY_PORT_MISSING_KEY,
104            InterfaceSendError::TtlExpired => ProtocolError::ISE_TTL_EXPIRED,
105        }
106    }
107}
108
109pub mod wire_frames {
110    use log::warn;
111    use postcard::{Serializer, ser_flavors};
112    use serde::{Deserialize, Serialize};
113
114    use crate::{Address, FrameKind, HeaderSeq, Key, ProtocolError};
115
116    use super::BorrowedFrame;
117
118    #[derive(Serialize, Deserialize, Debug)]
119    pub struct CommonHeader {
120        pub src: u32,
121        pub dst: u32,
122        pub seq_no: u16,
123        pub kind: u8,
124        pub ttl: u8,
125    }
126
127    pub enum PartialDecodeTail<'a> {
128        Specific(&'a [u8]),
129        AnyAll { key: Key, body: &'a [u8] },
130        Err(ProtocolError),
131    }
132
133    pub struct PartialDecode<'a> {
134        pub hdr: CommonHeader,
135        pub tail: PartialDecodeTail<'a>,
136    }
137
138    pub(crate) fn decode_frame_partial(data: &[u8]) -> Option<PartialDecode<'_>> {
139        let (common, remain) = postcard::take_from_bytes::<CommonHeader>(data).ok()?;
140        let is_err = common.kind == FrameKind::PROTOCOL_ERROR.0;
141        let any_all = [0, 255].contains(&Address::from_word(common.dst).port_id);
142
143        match (is_err, any_all) {
144            // Not allowed: any/all AND is err
145            (true, true) => {
146                warn!("Rejecting any/all protocol error message");
147                None
148            }
149            (true, false) => {
150                // err
151                let (err, remain) = postcard::take_from_bytes::<ProtocolError>(remain).ok()?;
152                if !remain.is_empty() {
153                    warn!("Excess data, rejecting");
154                    return None;
155                }
156                Some(PartialDecode {
157                    hdr: common,
158                    tail: PartialDecodeTail::Err(err),
159                })
160            }
161            (false, true) => {
162                let (key, remain) = postcard::take_from_bytes::<Key>(remain).ok()?;
163                Some(PartialDecode {
164                    hdr: common,
165                    tail: PartialDecodeTail::AnyAll { key, body: remain },
166                })
167            }
168            (false, false) => Some(PartialDecode {
169                hdr: common,
170                tail: PartialDecodeTail::Specific(remain),
171            }),
172        }
173    }
174
175    // must not be error
176    // doesn't check if dest is actually any/all
177    pub(crate) fn encode_frame_ty<F, T>(
178        flav: F,
179        hdr: &CommonHeader,
180        key: Option<&Key>,
181        body: &T,
182    ) -> Result<F::Output, ()>
183    where
184        F: ser_flavors::Flavor,
185        T: Serialize,
186    {
187        let mut serializer = Serializer { output: flav };
188        hdr.serialize(&mut serializer).map_err(drop)?;
189
190        if let Some(key) = key {
191            serializer.output.try_extend(&key.0).map_err(drop)?;
192        }
193
194        body.serialize(&mut serializer).map_err(drop)?;
195        serializer.output.finalize().map_err(drop)
196    }
197
198    // must not be error
199    // doesn't check if dest is actually any/all
200    pub(crate) fn encode_frame_raw<F>(
201        flav: F,
202        hdr: &CommonHeader,
203        key: Option<&Key>,
204        body: &[u8],
205    ) -> Result<F::Output, ()>
206    where
207        F: ser_flavors::Flavor,
208    {
209        let mut serializer = Serializer { output: flav };
210        hdr.serialize(&mut serializer).map_err(drop)?;
211
212        if let Some(key) = key {
213            serializer.output.try_extend(&key.0).map_err(drop)?;
214        }
215
216        serializer.output.try_extend(body).map_err(drop)?;
217        serializer.output.finalize().map_err(drop)
218    }
219
220    pub(crate) fn encode_frame_err<F>(
221        flav: F,
222        hdr: &CommonHeader,
223        err: ProtocolError,
224    ) -> Result<F::Output, ()>
225    where
226        F: ser_flavors::Flavor,
227    {
228        let mut serializer = Serializer { output: flav };
229        hdr.serialize(&mut serializer).map_err(drop)?;
230        err.serialize(&mut serializer).map_err(drop)?;
231        serializer.output.finalize().map_err(drop)
232    }
233
234    #[allow(dead_code)]
235    pub(crate) fn de_frame(remain: &[u8]) -> Option<BorrowedFrame<'_>> {
236        let res = decode_frame_partial(remain)?;
237
238        let key;
239        let body = match res.tail {
240            PartialDecodeTail::Specific(body) => {
241                key = None;
242                Ok(body)
243            }
244            PartialDecodeTail::AnyAll { key: skey, body } => {
245                key = Some(skey);
246                Ok(body)
247            }
248            PartialDecodeTail::Err(protocol_error) => {
249                key = None;
250                Err(protocol_error)
251            }
252        };
253
254        let CommonHeader {
255            src,
256            dst,
257            seq_no,
258            kind,
259            ttl,
260        } = res.hdr;
261
262        Some(BorrowedFrame {
263            hdr: HeaderSeq {
264                src: Address::from_word(src),
265                dst: Address::from_word(dst),
266                seq_no,
267                key,
268                kind: FrameKind(kind),
269                ttl,
270            },
271            body,
272        })
273    }
274}
275
276#[allow(dead_code)]
277pub(crate) struct BorrowedFrame<'a> {
278    pub(crate) hdr: HeaderSeq,
279    pub(crate) body: Result<&'a [u8], ProtocolError>,
280}