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, 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 = "embassy-usb-v0_5")]
53pub mod eusb_0_5_client;
54
55#[cfg(feature = "nusb-v0_1")]
56pub mod nusb_0_1_router;
57
58#[cfg(feature = "std")]
59pub mod std_tcp_client;
60#[cfg(feature = "std")]
61pub mod std_tcp_router;
62#[cfg(feature = "std")]
63pub mod std_utils;
64
65#[derive(Debug, PartialEq, Eq)]
66#[non_exhaustive]
67pub enum InterfaceSendError {
68    /// Refusing to send local destination remotely
69    DestinationLocal,
70    /// Interface Manager does not know how to route to requested destination
71    NoRouteToDest,
72    /// Interface Manager found a destination interface, but that interface
73    /// was full in space/slots
74    InterfaceFull,
75    /// TODO: Remove
76    PlaceholderOhNo,
77    /// Destination was an "any" port, but a key was not provided
78    AnyPortMissingKey,
79    /// TTL has reached the terminal value
80    TtlExpired,
81}
82
83pub trait ConstInit {
84    const INIT: Self;
85}
86
87// An interface send is very similar to a socket send, with the exception
88// that interface sends are ALWAYS a serializing operation (or requires
89// serialization has already been done), which means we don't need to
90// differentiate between "send owned" and "send borrowed". The exception
91// to this is "send raw", where serialization has already been done, e.g.
92// if we are routing a packet.
93pub trait InterfaceManager {
94    fn send<T: Serialize>(&mut self, hdr: &Header, data: &T) -> Result<(), InterfaceSendError>;
95    fn send_err(&mut self, hdr: &Header, err: ProtocolError) -> Result<(), InterfaceSendError>;
96    fn send_raw(
97        &mut self,
98        hdr: &Header,
99        hdr_raw: &[u8],
100        data: &[u8],
101    ) -> Result<(), InterfaceSendError>;
102}
103
104impl InterfaceSendError {
105    pub fn to_error(&self) -> ProtocolError {
106        match self {
107            InterfaceSendError::DestinationLocal => ProtocolError::ISE_DESTINATION_LOCAL,
108            InterfaceSendError::NoRouteToDest => ProtocolError::ISE_NO_ROUTE_TO_DEST,
109            InterfaceSendError::InterfaceFull => ProtocolError::ISE_INTERFACE_FULL,
110            InterfaceSendError::PlaceholderOhNo => ProtocolError::ISE_PLACEHOLDER_OH_NO,
111            InterfaceSendError::AnyPortMissingKey => ProtocolError::ISE_ANY_PORT_MISSING_KEY,
112            InterfaceSendError::TtlExpired => ProtocolError::ISE_TTL_EXPIRED,
113        }
114    }
115}