ublox_sockets/
lib.rs

1#![cfg_attr(not(test), no_std)]
2
3// This mod MUST go first, so that the others see its macros.
4pub(crate) mod fmt;
5
6mod meta;
7mod ref_;
8mod ring_buffer;
9mod set;
10pub mod tcp;
11pub mod tcp_listener;
12pub mod udp;
13pub mod udp_listener;
14
15pub(crate) use self::meta::Meta as SocketMeta;
16pub use self::ring_buffer::RingBuffer;
17
18#[cfg(feature = "socket-tcp")]
19pub use tcp::{State as TcpState, TcpSocket};
20
21#[cfg(feature = "socket-udp")]
22pub use udp::{State as UdpState, UdpSocket};
23
24pub use self::set::{Handle as SocketHandle, Set as SocketSet};
25
26pub use self::ref_::Ref as SocketRef;
27
28/// The error type for the networking stack.
29#[non_exhaustive]
30#[derive(Debug, Clone, Copy, PartialEq, Eq)]
31#[cfg_attr(feature = "defmt", derive(defmt::Format))]
32pub enum Error {
33    /// An operation cannot proceed because a buffer is empty or full.
34    Exhausted,
35    /// An operation is not permitted in the current state.
36    Illegal,
37    /// An endpoint or address of a remote host could not be translated to a lower level address.
38    /// E.g. there was no an Ethernet address corresponding to an IPv4 address in the ARP cache,
39    /// or a TCP connection attempt was made to an unspecified endpoint.
40    Unaddressable,
41
42    Timer,
43    Timeout,
44
45    SocketClosed,
46    BadLength,
47
48    NotBound,
49
50    ListenerError,
51
52    SocketSetFull,
53    InvalidSocket,
54    DuplicateSocket,
55}
56
57type Result<T> = core::result::Result<T, Error>;
58pub type Instant<const TIMER_HZ: u32> = fugit::TimerInstantU32<TIMER_HZ>;
59
60/// A network socket.
61///
62/// This enumeration abstracts the various types of sockets based on the IP protocol.
63/// To downcast a `Socket` value to a concrete socket, use the [AnySocket] trait,
64/// e.g. to get `UdpSocket`, call `UdpSocket::downcast(socket)`.
65///
66/// It is usually more convenient to use [SocketSet::get] instead.
67///
68/// [AnySocket]: trait.AnySocket.html
69/// [SocketSet::get]: struct.SocketSet.html#method.get
70#[non_exhaustive]
71#[derive(Debug)]
72pub enum Socket<const TIMER_HZ: u32, const L: usize> {
73    #[cfg(feature = "socket-udp")]
74    Udp(UdpSocket<TIMER_HZ, L>),
75    #[cfg(feature = "socket-tcp")]
76    Tcp(TcpSocket<TIMER_HZ, L>),
77}
78
79#[non_exhaustive]
80#[derive(Debug, Clone, Copy, PartialEq, Eq)]
81#[cfg_attr(feature = "defmt", derive(defmt::Format))]
82pub enum SocketType {
83    Udp,
84    Tcp,
85}
86
87impl<const TIMER_HZ: u32, const L: usize> Socket<TIMER_HZ, L> {
88    /// Return the socket handle.
89    #[inline]
90    pub fn handle(&self) -> SocketHandle {
91        self.meta().handle
92    }
93
94    pub(crate) fn meta(&self) -> &SocketMeta {
95        match self {
96            #[cfg(feature = "socket-udp")]
97            Socket::Udp(ref socket) => &socket.meta,
98            #[cfg(feature = "socket-tcp")]
99            Socket::Tcp(ref socket) => &socket.meta,
100        }
101    }
102
103    pub fn get_type(&self) -> SocketType {
104        match self {
105            Socket::Tcp(_) => SocketType::Tcp,
106            Socket::Udp(_) => SocketType::Udp,
107        }
108    }
109
110    pub fn should_update_available_data(&mut self, ts: Instant<TIMER_HZ>) -> bool {
111        match self {
112            Socket::Tcp(s) => s.should_update_available_data(ts),
113            Socket::Udp(s) => s.should_update_available_data(ts),
114        }
115    }
116
117    pub fn available_data(&self) -> usize {
118        match self {
119            Socket::Tcp(s) => s.get_available_data(),
120            Socket::Udp(s) => s.get_available_data(),
121        }
122    }
123
124    pub fn recycle(&self, ts: Instant<TIMER_HZ>) -> bool {
125        match self {
126            Socket::Tcp(s) => s.recycle(ts),
127            Socket::Udp(s) => s.recycle(ts),
128        }
129    }
130
131    pub fn closed_by_remote(&mut self, ts: Instant<TIMER_HZ>) {
132        match self {
133            Socket::Tcp(s) => s.closed_by_remote(ts),
134            Socket::Udp(s) => s.closed_by_remote(ts),
135        }
136    }
137
138    pub fn set_available_data(&mut self, available_data: usize) {
139        match self {
140            Socket::Tcp(s) => s.set_available_data(available_data),
141            Socket::Udp(s) => s.set_available_data(available_data),
142        }
143    }
144
145    pub fn rx_enqueue_slice(&mut self, data: &[u8]) -> usize {
146        match self {
147            Socket::Tcp(s) => s.rx_enqueue_slice(data),
148            Socket::Udp(s) => s.rx_enqueue_slice(data),
149        }
150    }
151
152    pub fn rx_window(&self) -> usize {
153        match self {
154            Socket::Tcp(s) => s.rx_window(),
155            Socket::Udp(s) => s.rx_window(),
156        }
157    }
158
159    pub fn can_recv(&self) -> bool {
160        match self {
161            Socket::Tcp(s) => s.can_recv(),
162            Socket::Udp(s) => s.can_recv(),
163        }
164    }
165}
166
167/// A conversion trait for network sockets.
168pub trait AnySocket<const TIMER_HZ: u32, const L: usize>: Sized {
169    fn downcast(socket_ref: SocketRef<'_, Socket<TIMER_HZ, L>>) -> Result<SocketRef<'_, Self>>;
170}
171
172#[cfg(feature = "socket-tcp")]
173impl<const TIMER_HZ: u32, const L: usize> AnySocket<TIMER_HZ, L> for TcpSocket<TIMER_HZ, L> {
174    fn downcast(ref_: SocketRef<'_, Socket<TIMER_HZ, L>>) -> Result<SocketRef<'_, Self>> {
175        match SocketRef::into_inner(ref_) {
176            Socket::Tcp(ref mut socket) => Ok(SocketRef::new(socket)),
177            _ => Err(Error::Illegal),
178        }
179    }
180}
181
182#[cfg(feature = "socket-udp")]
183impl<const TIMER_HZ: u32, const L: usize> AnySocket<TIMER_HZ, L> for UdpSocket<TIMER_HZ, L> {
184    fn downcast(ref_: SocketRef<'_, Socket<TIMER_HZ, L>>) -> Result<SocketRef<'_, Self>> {
185        match SocketRef::into_inner(ref_) {
186            Socket::Udp(ref mut socket) => Ok(SocketRef::new(socket)),
187            _ => Err(Error::Illegal),
188        }
189    }
190}
191
192#[cfg(test)]
193#[cfg(feature = "defmt")]
194mod test_helpers {
195    use core::ptr::NonNull;
196
197    #[defmt::global_logger]
198    struct Logger;
199    impl defmt::Write for Logger {
200        fn write(&mut self, _bytes: &[u8]) {}
201    }
202
203    unsafe impl defmt::Logger for Logger {
204        fn acquire() -> Option<NonNull<dyn defmt::Write>> {
205            Some(NonNull::from(&Logger as &dyn defmt::Write))
206        }
207
208        unsafe fn release(_: NonNull<dyn defmt::Write>) {}
209    }
210
211    defmt::timestamp!("");
212
213    #[export_name = "_defmt_panic"]
214    fn panic() -> ! {
215        panic!()
216    }
217}