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 {}