w5500_hl/
udp.rs

1use crate::{
2    io::{Read, Seek, SeekFrom, Write},
3    port_is_unique, Error, TcpReader,
4};
5use core::cmp::min;
6use w5500_ll::{
7    net::{Ipv4Addr, SocketAddrV4},
8    Protocol, Registers, Sn, SocketCommand, SocketMode, SocketStatus, TxPtrs,
9};
10
11/// W5500 UDP Header.
12#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
13#[cfg_attr(feature = "defmt", derive(defmt::Format))]
14pub struct UdpHeader {
15    /// Origin IP address and port.
16    pub origin: SocketAddrV4,
17    /// Length of the UDP packet in bytes.
18    ///
19    /// This may not be equal to the length of the data in the socket buffer if
20    /// the UDP packet was truncated.
21    pub len: u16,
22}
23
24impl UdpHeader {
25    // note: not your standard UDP datagram header
26    // For a UDP socket the W5500 UDP header contains:
27    // * 4 bytes origin IP
28    // * 2 bytes origin port
29    // * 2 bytes size
30    const LEN: u16 = 8;
31    const LEN_USIZE: usize = Self::LEN as usize;
32
33    /// Deserialize a UDP header.
34    fn deser(buf: [u8; Self::LEN_USIZE]) -> UdpHeader {
35        UdpHeader {
36            origin: SocketAddrV4::new(
37                Ipv4Addr::new(buf[0], buf[1], buf[2], buf[3]),
38                u16::from_be_bytes([buf[4], buf[5]]),
39            ),
40            len: u16::from_be_bytes([buf[6], buf[7]]),
41        }
42    }
43}
44
45/// Streaming reader for a UDP socket buffer.
46///
47/// This implements the [`Read`] and [`Seek`] traits.
48///
49/// Created with [`Udp::udp_reader`].
50///
51/// # Example
52///
53/// ```no_run
54/// # use ehm::eh1 as h;
55/// # let mut w5500 = w5500_ll::eh1::vdm::W5500::new(h::spi::Mock::new(&[]));
56/// use w5500_hl::{
57///     io::Read,
58///     ll::{Registers, Sn::Sn0},
59///     net::{Ipv4Addr, SocketAddrV4},
60///     Udp, UdpReader,
61/// };
62///
63/// const DEST: SocketAddrV4 = SocketAddrV4::new(Ipv4Addr::new(192, 0, 2, 1), 8081);
64///
65/// w5500.udp_bind(Sn0, 8080)?;
66///
67/// let mut reader: UdpReader<_> = w5500.udp_reader(Sn0)?;
68///
69/// let mut buf: [u8; 8] = [0; 8];
70/// reader.read_exact(&mut buf)?;
71///
72/// let mut other_buf: [u8; 16] = [0; 16];
73/// reader.read_exact(&mut buf)?;
74///
75/// // mark the datagram as done, removing it from the queue
76/// reader.done()?;
77/// # Ok::<(), w5500_hl::Error<_>>(())
78/// ```
79#[derive(Debug)]
80#[cfg_attr(feature = "defmt", derive(defmt::Format))]
81pub struct UdpReader<'w, W5500> {
82    inner: TcpReader<'w, W5500>,
83    header: UdpHeader,
84}
85
86impl<'w, W5500> Seek for UdpReader<'w, W5500> {
87    fn seek<E>(&mut self, pos: SeekFrom) -> Result<(), Error<E>> {
88        self.inner.seek(pos)
89    }
90
91    fn rewind(&mut self) {
92        self.inner.rewind()
93    }
94
95    fn stream_len(&self) -> u16 {
96        self.inner.stream_len()
97    }
98
99    fn stream_position(&self) -> u16 {
100        self.inner.stream_position()
101    }
102
103    fn remain(&self) -> u16 {
104        self.inner.remain()
105    }
106}
107
108impl<'w, W5500: Registers> Read<W5500::Error> for UdpReader<'w, W5500> {
109    fn read(&mut self, buf: &mut [u8]) -> Result<u16, W5500::Error> {
110        self.inner.read(buf)
111    }
112
113    fn read_exact(&mut self, buf: &mut [u8]) -> Result<(), Error<W5500::Error>> {
114        self.inner.read_exact(buf)
115    }
116
117    fn done(self) -> Result<(), W5500::Error> {
118        self.inner
119            .w5500
120            .set_sn_rx_rd(self.inner.sn, self.inner.tail_ptr)?;
121        self.inner
122            .w5500
123            .set_sn_cr(self.inner.sn, SocketCommand::Recv)?;
124        Ok(())
125    }
126}
127
128/// Streaming writer for a UDP socket buffer.
129///
130/// This implements the [`Seek`] traits.
131///
132/// Created with [`Udp::udp_writer`].
133///
134/// # Example
135///
136/// ```no_run
137/// # use ehm::eh1 as h;
138/// # let mut w5500 = w5500_ll::eh1::vdm::W5500::new(h::spi::Mock::new(&[]));
139/// use w5500_hl::{
140///     io::Write,
141///     ll::{Registers, Sn::Sn0},
142///     net::{Ipv4Addr, SocketAddrV4},
143///     Udp, UdpWriter,
144/// };
145///
146/// const DEST: SocketAddrV4 = SocketAddrV4::new(Ipv4Addr::new(192, 0, 2, 1), 8081);
147///
148/// w5500.udp_bind(Sn0, 8080)?;
149///
150/// let mut udp_writer: UdpWriter<_> = w5500.udp_writer(Sn0)?;
151///
152/// let data_header: [u8; 10] = [0; 10];
153/// let n_written: u16 = udp_writer.write(&data_header)?;
154/// assert_eq!(usize::from(n_written), data_header.len());
155///
156/// let data: [u8; 123] = [0; 123];
157/// let n_written: u16 = udp_writer.write(&data)?;
158/// assert_eq!(usize::from(n_written), data.len());
159///
160/// udp_writer.udp_send_to(&DEST)?;
161/// # Ok::<(), embedded_hal::spi::ErrorKind>(())
162/// ```
163#[derive(Debug, PartialEq, Eq)]
164#[cfg_attr(feature = "defmt", derive(defmt::Format))]
165pub struct UdpWriter<'w, W5500> {
166    pub(crate) w5500: &'w mut W5500,
167    pub(crate) sn: Sn,
168    pub(crate) head_ptr: u16,
169    pub(crate) tail_ptr: u16,
170    pub(crate) ptr: u16,
171}
172
173impl<'w, W5500> Seek for UdpWriter<'w, W5500> {
174    fn seek<E>(&mut self, pos: SeekFrom) -> Result<(), Error<E>> {
175        self.ptr = pos.new_ptr(self.ptr, self.head_ptr, self.tail_ptr)?;
176        Ok(())
177    }
178
179    fn rewind(&mut self) {
180        self.ptr = self.head_ptr
181    }
182
183    fn stream_len(&self) -> u16 {
184        self.tail_ptr.wrapping_sub(self.head_ptr)
185    }
186
187    fn stream_position(&self) -> u16 {
188        self.ptr.wrapping_sub(self.head_ptr)
189    }
190
191    fn remain(&self) -> u16 {
192        self.tail_ptr.wrapping_sub(self.ptr)
193    }
194}
195
196impl<'w, W5500: Registers> Write<W5500::Error> for UdpWriter<'w, W5500> {
197    fn write(&mut self, buf: &[u8]) -> Result<u16, W5500::Error> {
198        let write_size: u16 = min(self.remain(), buf.len().try_into().unwrap_or(u16::MAX));
199        if write_size != 0 {
200            self.w5500
201                .set_sn_tx_buf(self.sn, self.ptr, &buf[..usize::from(write_size)])?;
202            self.ptr = self.ptr.wrapping_add(write_size);
203
204            Ok(write_size)
205        } else {
206            Ok(0)
207        }
208    }
209
210    fn write_all(&mut self, buf: &[u8]) -> Result<(), Error<W5500::Error>> {
211        let buf_len: u16 = buf.len().try_into().unwrap_or(u16::MAX);
212        let write_size: u16 = min(self.remain(), buf_len);
213        if write_size != buf_len {
214            Err(Error::OutOfMemory)
215        } else {
216            self.w5500.set_sn_tx_buf(self.sn, self.ptr, buf)?;
217            self.ptr = self.ptr.wrapping_add(write_size);
218            Ok(())
219        }
220    }
221
222    fn send(self) -> Result<(), W5500::Error> {
223        self.w5500.set_sn_tx_wr(self.sn, self.ptr)?;
224        self.w5500.set_sn_cr(self.sn, SocketCommand::Send)?;
225        Ok(())
226    }
227}
228
229impl<'w, W5500: Registers> UdpWriter<'w, W5500> {
230    /// Send all data previously written with [`UdpWriter::write`] and
231    /// [`UdpWriter::write_all`] to the given address.
232    ///
233    /// # Panics
234    ///
235    /// * (debug) The socket must be opened as a UDP socket.
236    pub fn udp_send_to(self, addr: &SocketAddrV4) -> Result<(), W5500::Error> {
237        debug_assert_eq!(self.w5500.sn_sr(self.sn)?, Ok(SocketStatus::Udp));
238        self.w5500.set_sn_dest(self.sn, addr)?;
239        self.send()
240    }
241}
242
243impl<'a, W: Registers> UdpReader<'a, W> {
244    /// Get the UDP header.
245    ///
246    /// # Example
247    ///
248    /// ```no_run
249    /// # let mut w5500 = w5500_ll::eh1::vdm::W5500::new(ehm::eh1::spi::Mock::new(&[]));
250    /// use w5500_hl::{
251    ///     ll::{Registers, Sn::Sn0},
252    ///     net::{Ipv4Addr, SocketAddrV4},
253    ///     Udp, UdpHeader, UdpReader,
254    /// };
255    ///
256    /// const DEST: SocketAddrV4 = SocketAddrV4::new(Ipv4Addr::new(192, 0, 2, 1), 8081);
257    ///
258    /// w5500.udp_bind(Sn0, 8080)?;
259    ///
260    /// let reader: UdpReader<_> = w5500.udp_reader(Sn0)?;
261    /// let header: &UdpHeader = reader.header();
262    /// # Ok::<(), w5500_hl::Error<_>>(())
263    /// ```
264    #[inline]
265    pub fn header(&self) -> &UdpHeader {
266        &self.header
267    }
268}
269
270/// A W5500 UDP socket trait.
271///
272/// After creating a `UdpSocket` by [`bind`]ing it to a socket address,
273/// data can be [sent to] and [received from] any other socket address.
274///
275/// As stated in the User Datagram Protocol's specification in [IETF RFC 768],
276/// UDP is an unordered, unreliable protocol; refer to [`Tcp`] for the TCP trait.
277///
278/// # Comparison to [`std::net::UdpSocket`]
279///
280/// * Everything is non-blocking.
281/// * There is no socket struct, you must pass a socket number as the first
282///   argument to the methods.  This was simply the cleanest solution to the
283///   ownership problem after some experimentation; though it certainly is not
284///   the safest.
285///
286/// [`bind`]: Udp::udp_bind
287/// [IETF RFC 768]: https://tools.ietf.org/html/rfc768
288/// [received from]: Udp::udp_recv_from
289/// [sent to]: Udp::udp_send_to
290/// [`Tcp`]: crate::Tcp
291/// [`std::net::UdpSocket`]: https://doc.rust-lang.org/std/net/struct.UdpSocket.html
292pub trait Udp: Registers {
293    /// Binds the socket to the given port.
294    ///
295    /// This will close the socket, which will reset the RX and TX buffers.
296    ///
297    /// # Comparison to [`std::net::UdpSocket::bind`]
298    ///
299    /// This method accepts a port instead of a [`net::SocketAddrV4`], this is
300    /// because the IP address is global for the device, set by the
301    /// [source IP register], and cannot be set on a per-socket basis.
302    ///
303    /// Additionally you can only provide one port, instead of iterable
304    /// addresses to bind.
305    ///
306    /// # Panics
307    ///
308    /// * (debug) The port must not be in use by any other socket on the W5500.
309    ///
310    /// # Example
311    ///
312    /// Bind the first socket to port 8080.
313    ///
314    /// ```no_run
315    /// # let mut w5500 = w5500_ll::eh1::vdm::W5500::new(ehm::eh1::spi::Mock::new(&[]));
316    /// use w5500_hl::ll::{Registers, Sn::Sn0};
317    /// use w5500_hl::Udp;
318    ///
319    /// w5500.udp_bind(Sn0, 8080)?;
320    /// # Ok::<(), embedded_hal::spi::ErrorKind>(())
321    /// ```
322    ///
323    /// [`net::SocketAddrV4`]: [crate::net::SocketAddrV4]
324    /// [`std::net::UdpSocket::bind`]: https://doc.rust-lang.org/std/net/struct.UdpSocket.html#method.bind
325    /// [source IP register]: w5500_ll::Registers::sipr
326    fn udp_bind(&mut self, sn: Sn, port: u16) -> Result<(), Self::Error> {
327        debug_assert!(
328            port_is_unique(self, sn, port)?,
329            "Local port {port} is in use"
330        );
331
332        self.set_sn_cr(sn, SocketCommand::Close)?;
333        // This will not hang, the socket status will always change to closed
334        // after a close command.
335        // (unless you do somthing silly like holding the W5500 in reset)
336        while self.sn_sr(sn)? != Ok(SocketStatus::Closed) {}
337        self.set_sn_port(sn, port)?;
338        const MODE: SocketMode = SocketMode::DEFAULT.set_protocol(Protocol::Udp);
339        self.set_sn_mr(sn, MODE)?;
340        self.set_sn_cr(sn, SocketCommand::Open)?;
341        // This will not hang, the socket status will always change to Udp
342        // after a open command with SN_MR set to UDP.
343        // (unless you do somthing silly like holding the W5500 in reset)
344        while self.sn_sr(sn)? != Ok(SocketStatus::Udp) {}
345        Ok(())
346    }
347
348    /// Receives a single datagram message on the socket.
349    /// On success, returns the number of bytes read and the origin.
350    ///
351    /// The function must be called with valid byte array `buf` of sufficient
352    /// size to hold the message bytes.
353    /// If a message is too long to fit in the supplied buffer, excess bytes
354    /// will be discarded.
355    ///
356    /// # Comparison to [`std::net::UdpSocket::recv_from`]
357    ///
358    /// * This method will always discard excess bytes from the socket buffer.
359    /// * This method is non-blocking, use [`block`] to treat it as blocking.
360    ///
361    /// # Errors
362    ///
363    /// This method can only return:
364    ///
365    /// * [`Error::Other`]
366    /// * [`Error::WouldBlock`]
367    ///
368    /// # Panics
369    ///
370    /// * (debug) The socket must be opened as a UDP socket.
371    ///
372    /// # Example
373    ///
374    /// ```no_run
375    /// # let mut w5500 = w5500_ll::eh1::vdm::W5500::new(ehm::eh1::spi::Mock::new(&[]));
376    /// use w5500_hl::{
377    ///     block,
378    ///     ll::{Registers, Sn::Sn0},
379    ///     Udp,
380    /// };
381    ///
382    /// w5500.udp_bind(Sn0, 8080)?;
383    /// let mut buf = [0; 10];
384    /// let (number_of_bytes, src_addr) = block!(w5500.udp_recv_from(Sn0, &mut buf))?;
385    ///
386    /// // panics if bytes were discarded
387    /// assert!(
388    ///     usize::from(number_of_bytes) < buf.len(),
389    ///     "Buffer was too small to receive all data"
390    /// );
391    ///
392    /// let filled_buf = &mut buf[..number_of_bytes.into()];
393    /// # Ok::<(), w5500_hl::Error<_>>(())
394    /// ```
395    ///
396    /// [`std::net::UdpSocket::recv_from`]: https://doc.rust-lang.org/std/net/struct.UdpSocket.html#method.recv_from
397    /// [`block`]: crate::block
398    fn udp_recv_from(
399        &mut self,
400        sn: Sn,
401        buf: &mut [u8],
402    ) -> Result<(u16, SocketAddrV4), Error<Self::Error>> {
403        let rsr: u16 = match self.sn_rx_rsr(sn)?.checked_sub(UdpHeader::LEN) {
404            Some(rsr) => rsr,
405            // nothing to recieve
406            None => return Err(Error::WouldBlock),
407        };
408
409        debug_assert_eq!(self.sn_sr(sn)?, Ok(SocketStatus::Udp));
410
411        let mut ptr: u16 = self.sn_rx_rd(sn)?;
412        let mut header: [u8; UdpHeader::LEN_USIZE] = [0; UdpHeader::LEN_USIZE];
413        self.sn_rx_buf(sn, ptr, &mut header)?;
414        ptr = ptr.wrapping_add(UdpHeader::LEN);
415        let header: UdpHeader = UdpHeader::deser(header);
416
417        // not all data as indicated by the header has been buffered
418        if rsr < header.len {
419            return Err(Error::WouldBlock);
420        }
421
422        let read_size: u16 = min(header.len, buf.len().try_into().unwrap_or(u16::MAX));
423        if read_size != 0 {
424            self.sn_rx_buf(sn, ptr, &mut buf[..read_size.into()])?;
425        }
426        ptr = ptr.wrapping_add(header.len);
427        self.set_sn_rx_rd(sn, ptr)?;
428        self.set_sn_cr(sn, SocketCommand::Recv)?;
429        Ok((read_size, header.origin))
430    }
431
432    /// Receives a single datagram message on the socket, without removing it
433    /// from the queue.
434    /// On success, returns the number of bytes read and the UDP header.
435    ///
436    /// # Comparison to [`std::net::UdpSocket::peek_from`]
437    ///
438    /// * This method will never discard excess bytes from the socket buffer.
439    /// * This method is non-blocking, use [`block`] to treat it as blocking.
440    ///
441    /// # Errors
442    ///
443    /// This method can only return:
444    ///
445    /// * [`Error::Other`]
446    /// * [`Error::WouldBlock`]
447    ///
448    /// # Panics
449    ///
450    /// * (debug) The socket must be opened as a UDP socket.
451    ///
452    /// # Example
453    ///
454    /// ```no_run
455    /// # let mut w5500 = w5500_ll::eh1::vdm::W5500::new(ehm::eh1::spi::Mock::new(&[]));
456    /// use w5500_hl::{
457    ///     block,
458    ///     ll::{Registers, Sn::Sn0},
459    ///     Udp,
460    /// };
461    ///
462    /// w5500.udp_bind(Sn0, 8080)?;
463    /// let mut buf = [0; 10];
464    /// let (number_of_bytes, udp_header) = block!(w5500.udp_peek_from(Sn0, &mut buf))?;
465    ///
466    /// // panics if buffer was too small
467    /// assert!(
468    ///     usize::from(number_of_bytes) > buf.len(),
469    ///     "Buffer was of len {} too small to receive all data: {} / {} bytes read",
470    ///     buf.len(),
471    ///     number_of_bytes,
472    ///     udp_header.len
473    /// );
474    ///
475    /// let filled_buf = &mut buf[..number_of_bytes.into()];
476    /// # Ok::<(), w5500_hl::Error<_>>(())
477    /// ```
478    ///
479    /// [`std::net::UdpSocket::peek_from`]: https://doc.rust-lang.org/std/net/struct.UdpSocket.html#method.peek_from
480    /// [`block`]: crate::block
481    fn udp_peek_from(
482        &mut self,
483        sn: Sn,
484        buf: &mut [u8],
485    ) -> Result<(u16, UdpHeader), Error<Self::Error>> {
486        let rsr: u16 = match self.sn_rx_rsr(sn)?.checked_sub(UdpHeader::LEN) {
487            Some(rsr) => rsr,
488            // nothing to recieve
489            None => return Err(Error::WouldBlock),
490        };
491
492        debug_assert_eq!(self.sn_sr(sn)?, Ok(SocketStatus::Udp));
493
494        let mut ptr: u16 = self.sn_rx_rd(sn)?;
495        let mut header: [u8; UdpHeader::LEN_USIZE] = [0; UdpHeader::LEN_USIZE];
496        self.sn_rx_buf(sn, ptr, &mut header)?;
497        ptr = ptr.wrapping_add(UdpHeader::LEN);
498        let header: UdpHeader = UdpHeader::deser(header);
499
500        // not all data as indicated by the header has been buffered
501        if rsr < header.len {
502            return Err(Error::WouldBlock);
503        }
504
505        let read_size: u16 = min(header.len, buf.len().try_into().unwrap_or(u16::MAX));
506        if read_size != 0 {
507            self.sn_rx_buf(sn, ptr, &mut buf[..read_size.into()])?;
508        }
509
510        Ok((read_size, header))
511    }
512
513    /// Receives the origin and size of the next datagram available on the
514    /// socket, without removing it from the queue.
515    ///
516    /// There is no [`std::net`](https://doc.rust-lang.org/std/net) equivalent
517    /// for this method.
518    ///
519    /// # Errors
520    ///
521    /// This method can only return:
522    ///
523    /// * [`Error::Other`]
524    /// * [`Error::WouldBlock`]
525    ///
526    /// # Panics
527    ///
528    /// * (debug) The socket must be opened as a UDP socket.
529    ///
530    /// # Example
531    ///
532    /// ```no_run
533    /// # let mut w5500 = w5500_ll::eh1::vdm::W5500::new(ehm::eh1::spi::Mock::new(&[]));
534    /// use w5500_hl::{
535    ///     block,
536    ///     ll::{Registers, Sn::Sn0},
537    ///     Udp, UdpHeader,
538    /// };
539    /// // global_allocator is currently available on nightly for embedded rust
540    /// extern crate alloc;
541    /// use alloc::vec::{self, Vec};
542    ///
543    /// w5500.udp_bind(Sn0, 8080)?;
544    /// let udp_header: UdpHeader = block!(w5500.udp_peek_from_header(Sn0))?;
545    ///
546    /// let mut buf: Vec<u8> = vec![0; udp_header.len.into()];
547    /// let (number_of_bytes, source) = block!(w5500.udp_recv_from(Sn0, &mut buf))?;
548    /// // this can assert if the UDP datagram was truncated
549    /// // e.g. due to an insufficient socket buffer size
550    /// assert_eq!(udp_header.len, number_of_bytes);
551    /// # Ok::<(), w5500_hl::Error<_>>(())
552    /// ```
553    fn udp_peek_from_header(&mut self, sn: Sn) -> Result<UdpHeader, Error<Self::Error>> {
554        let rsr: u16 = self.sn_rx_rsr(sn)?;
555
556        // nothing to recieve
557        if rsr < UdpHeader::LEN {
558            return Err(Error::WouldBlock);
559        }
560
561        debug_assert_eq!(self.sn_sr(sn)?, Ok(SocketStatus::Udp));
562
563        let ptr: u16 = self.sn_rx_rd(sn)?;
564        let mut header: [u8; UdpHeader::LEN_USIZE] = [0; UdpHeader::LEN_USIZE];
565        self.sn_rx_buf(sn, ptr, &mut header)?;
566        Ok(UdpHeader::deser(header))
567    }
568
569    /// Sends data on the socket to the given address.
570    /// On success, returns the number of bytes written.
571    ///
572    /// # Comparison to [`std::net::UdpSocket::send_to`]
573    ///
574    /// * You cannot transmit more than `u16::MAX` bytes at once.
575    /// * You can only provide one destination.
576    ///
577    /// # Panics
578    ///
579    /// * (debug) The socket must be opened as a UDP socket.
580    ///
581    /// # Example
582    ///
583    /// ```no_run
584    /// # let mut w5500 = w5500_ll::eh1::vdm::W5500::new(ehm::eh1::spi::Mock::new(&[]));
585    /// use w5500_hl::{
586    ///     ll::{Registers, Sn::Sn0},
587    ///     net::{Ipv4Addr, SocketAddrV4},
588    ///     Udp,
589    /// };
590    ///
591    /// const DEST: SocketAddrV4 = SocketAddrV4::new(Ipv4Addr::new(192, 0, 2, 1), 8081);
592    ///
593    /// w5500.udp_bind(Sn0, 8080)?;
594    /// let buf: [u8; 10] = [0; 10];
595    /// let tx_bytes: u16 = w5500.udp_send_to(Sn0, &buf, &DEST)?;
596    /// assert_eq!(usize::from(tx_bytes), buf.len());
597    /// # Ok::<(), embedded_hal::spi::ErrorKind>(())
598    /// ```
599    ///
600    /// [`std::net::UdpSocket::send_to`]: https://doc.rust-lang.org/std/net/struct.UdpSocket.html#method.send_to
601    fn udp_send_to(&mut self, sn: Sn, buf: &[u8], addr: &SocketAddrV4) -> Result<u16, Self::Error> {
602        self.set_sn_dest(sn, addr)?;
603        self.udp_send(sn, buf)
604    }
605
606    /// Sends data on the socket to the given address.
607    /// On success, returns the number of bytes written.
608    ///
609    /// This will transmit only if there is enough free space in the W5500
610    /// transmit buffer.
611    ///
612    /// # Comparison to [`std::net::UdpSocket::send_to`]
613    ///
614    /// * You cannot transmit more than `u16::MAX` bytes at once.
615    /// * You can only provide one destination.
616    ///
617    /// # Panics
618    ///
619    /// * (debug) The socket must be opened as a UDP socket.
620    ///
621    /// # Example
622    ///
623    /// ```no_run
624    /// # let mut w5500 = w5500_ll::eh1::vdm::W5500::new(ehm::eh1::spi::Mock::new(&[]));
625    /// use w5500_hl::{
626    ///     ll::{Registers, Sn::Sn0},
627    ///     net::{Ipv4Addr, SocketAddrV4},
628    ///     Udp,
629    /// };
630    ///
631    /// const DEST: SocketAddrV4 = SocketAddrV4::new(Ipv4Addr::new(192, 0, 2, 1), 8081);
632    ///
633    /// w5500.udp_bind(Sn0, 8080)?;
634    /// let buf: [u8; 10] = [0; 10];
635    /// let tx_bytes: u16 = w5500.udp_send_to_if_free(Sn0, &buf, &DEST)?;
636    /// assert_eq!(usize::from(tx_bytes), buf.len());
637    /// # Ok::<(), embedded_hal::spi::ErrorKind>(())
638    /// ```
639    ///
640    /// [`std::net::UdpSocket::send_to`]: https://doc.rust-lang.org/std/net/struct.UdpSocket.html#method.send_to
641    fn udp_send_to_if_free(
642        &mut self,
643        sn: Sn,
644        buf: &[u8],
645        addr: &SocketAddrV4,
646    ) -> Result<u16, Self::Error> {
647        self.set_sn_dest(sn, addr)?;
648        self.udp_send_if_free(sn, buf)
649    }
650
651    /// Sends data to the currently configured destination.
652    /// On success, returns the number of bytes written.
653    ///
654    /// The destination is set by the last call to [`Registers::set_sn_dest`],
655    /// [`Udp::udp_send_to`], or [`UdpWriter::udp_send_to`].
656    ///
657    /// # Panics
658    ///
659    /// * (debug) The socket must be opened as a UDP socket.
660    ///
661    /// # Example
662    ///
663    /// ```no_run
664    /// # let mut w5500 = w5500_ll::eh1::vdm::W5500::new(ehm::eh1::spi::Mock::new(&[]));
665    /// use w5500_hl::{
666    ///     ll::{Registers, Sn::Sn0},
667    ///     net::{Ipv4Addr, SocketAddrV4},
668    ///     Udp,
669    /// };
670    ///
671    /// const DEST: SocketAddrV4 = SocketAddrV4::new(Ipv4Addr::new(192, 0, 2, 1), 8081);
672    ///
673    /// w5500.udp_bind(Sn0, 8080)?;
674    /// let buf: [u8; 10] = [0; 10];
675    /// let tx_bytes: u16 = w5500.udp_send_to(Sn0, &buf, &DEST)?;
676    /// assert_eq!(usize::from(tx_bytes), buf.len());
677    /// // send the same to the same destination
678    /// let tx_bytes: u16 = w5500.udp_send(Sn0, &buf)?;
679    /// assert_eq!(usize::from(tx_bytes), buf.len());
680    /// # Ok::<(), embedded_hal::spi::ErrorKind>(())
681    /// ```
682    ///
683    /// [`UdpWriter::udp_send_to`]: crate::UdpWriter::udp_send_to
684    fn udp_send(&mut self, sn: Sn, buf: &[u8]) -> Result<u16, Self::Error> {
685        debug_assert_eq!(self.sn_sr(sn)?, Ok(SocketStatus::Udp));
686
687        let data_len: u16 = u16::try_from(buf.len()).unwrap_or(u16::MAX);
688        let free_size: u16 = self.sn_tx_fsr(sn)?;
689        let tx_bytes: u16 = min(data_len, free_size);
690        if tx_bytes != 0 {
691            let ptr: u16 = self.sn_tx_wr(sn)?;
692            self.set_sn_tx_buf(sn, ptr, &buf[..tx_bytes.into()])?;
693            self.set_sn_tx_wr(sn, ptr.wrapping_add(tx_bytes))?;
694            self.set_sn_cr(sn, SocketCommand::Send)?;
695        }
696        Ok(tx_bytes)
697    }
698
699    /// Sends data to the currently configured destination.
700    /// On success, returns the number of bytes written.
701    ///
702    /// The destination is set by the last call to [`Registers::set_sn_dest`],
703    /// [`Udp::udp_send_to`], or [`UdpWriter::udp_send_to`].
704    ///
705    /// This will transmit only if there is enough free space in the W5500
706    /// transmit buffer.
707    ///
708    /// # Panics
709    ///
710    /// * (debug) The socket must be opened as a UDP socket.
711    ///
712    /// # Example
713    ///
714    /// ```no_run
715    /// # let mut w5500 = w5500_ll::eh1::vdm::W5500::new(ehm::eh1::spi::Mock::new(&[]));
716    /// use w5500_hl::{
717    ///     ll::{Registers, Sn::Sn0},
718    ///     net::{Ipv4Addr, SocketAddrV4},
719    ///     Udp,
720    /// };
721    ///
722    /// const DEST: SocketAddrV4 = SocketAddrV4::new(Ipv4Addr::new(192, 0, 2, 1), 8081);
723    ///
724    /// w5500.udp_bind(Sn0, 8080)?;
725    /// let buf: [u8; 10] = [0; 10];
726    /// let tx_bytes: u16 = w5500.udp_send_to_if_free(Sn0, &buf, &DEST)?;
727    /// assert_eq!(usize::from(tx_bytes), buf.len());
728    /// // send the same to the same destination
729    /// let tx_bytes: u16 = w5500.udp_send_if_free(Sn0, &buf)?;
730    /// assert_eq!(usize::from(tx_bytes), buf.len());
731    /// # Ok::<(), embedded_hal::spi::ErrorKind>(())
732    /// ```
733    ///
734    /// [`UdpWriter::udp_send_to`]: crate::UdpWriter::udp_send_to
735    fn udp_send_if_free(&mut self, sn: Sn, buf: &[u8]) -> Result<u16, Self::Error> {
736        debug_assert_eq!(self.sn_sr(sn)?, Ok(SocketStatus::Udp));
737
738        let data_len: u16 = match u16::try_from(buf.len()) {
739            Ok(l) => l,
740            Err(_) => return Ok(0),
741        };
742        let free_size: u16 = self.sn_tx_fsr(sn)?;
743        if data_len <= free_size {
744            let ptr: u16 = self.sn_tx_wr(sn)?;
745            self.set_sn_tx_buf(sn, ptr, buf)?;
746            self.set_sn_tx_wr(sn, ptr.wrapping_add(data_len))?;
747            self.set_sn_cr(sn, SocketCommand::Send)?;
748        }
749        Ok(data_len)
750    }
751
752    /// Create a UDP reader.
753    ///
754    /// This returns a [`UdpReader`] structure, which contains functions to
755    /// stream data from the W5500 socket buffers incrementally.
756    ///
757    /// This will return [`Error::WouldBlock`] if there is no data to read.
758    ///
759    /// # Errors
760    ///
761    /// This method can only return:
762    ///
763    /// * [`Error::Other`]
764    /// * [`Error::WouldBlock`]
765    ///
766    /// # Example
767    ///
768    /// See [`UdpReader`].
769    fn udp_reader(&mut self, sn: Sn) -> Result<UdpReader<Self>, Error<Self::Error>>
770    where
771        Self: Sized,
772    {
773        debug_assert_eq!(self.sn_sr(sn)?, Ok(SocketStatus::Udp));
774
775        let rsr: u16 = match self.sn_rx_rsr(sn)?.checked_sub(UdpHeader::LEN) {
776            Some(rsr) => rsr,
777            // nothing to recieve
778            None => return Err(Error::WouldBlock),
779        };
780
781        let sn_rx_rd: u16 = self.sn_rx_rd(sn)?;
782        let mut header: [u8; UdpHeader::LEN_USIZE] = [0; UdpHeader::LEN_USIZE];
783        self.sn_rx_buf(sn, sn_rx_rd, &mut header)?;
784        let header: UdpHeader = UdpHeader::deser(header);
785
786        // limit to the length of the first datagram if we have more than a
787        // single datagram enqueued
788        let rsr_or_datagram_len: u16 = min(header.len, rsr);
789
790        let head_ptr: u16 = sn_rx_rd.wrapping_add(UdpHeader::LEN);
791
792        Ok(UdpReader {
793            inner: TcpReader {
794                w5500: self,
795                sn,
796                head_ptr,
797                tail_ptr: head_ptr.wrapping_add(rsr_or_datagram_len),
798                ptr: head_ptr,
799            },
800            header,
801        })
802    }
803
804    /// Create a UDP writer.
805    ///
806    /// This returns a [`UdpWriter`] structure, which contains functions to
807    /// stream data to the W5500 socket buffers incrementally.
808    ///
809    /// # Example
810    ///
811    /// See [`UdpWriter`].
812    fn udp_writer(&mut self, sn: Sn) -> Result<UdpWriter<Self>, Self::Error>
813    where
814        Self: Sized,
815    {
816        let tx_ptrs: TxPtrs = self.sn_tx_ptrs(sn)?;
817
818        Ok(UdpWriter {
819            w5500: self,
820            sn,
821            head_ptr: tx_ptrs.wr,
822            tail_ptr: tx_ptrs.wr.wrapping_add(tx_ptrs.fsr),
823            ptr: tx_ptrs.wr,
824        })
825    }
826}
827
828/// Implement the UDP trait for any structure that implements [`w5500_ll::Registers`].
829impl<T> Udp for T where T: Registers {}