w5500_hl/
tcp.rs

1use crate::{
2    io::{Read, Seek, SeekFrom, Write},
3    port_is_unique, Error,
4};
5use core::cmp::min;
6use w5500_ll::{
7    net::SocketAddrV4, Protocol, Registers, Sn, SocketCommand, SocketMode, SocketStatus, TxPtrs,
8};
9
10/// Streaming reader for a TCP socket buffer.
11///
12/// This implements the [`Read`] and [`Seek`] traits.
13///
14/// Created with [`Tcp::tcp_reader`].
15///
16/// # Example
17///
18/// ```no_run
19/// # use ehm::eh1 as h;
20/// # let mut w5500 = w5500_ll::eh1::vdm::W5500::new(h::spi::Mock::new(&[]));
21/// use w5500_hl::{
22///     io::Read,
23///     ll::{Registers, Sn, SocketInterrupt},
24///     net::{Ipv4Addr, SocketAddrV4},
25///     Tcp, TcpReader,
26/// };
27///
28/// const MQTT_SOCKET: Sn = Sn::Sn0;
29/// const MQTT_SOURCE_PORT: u16 = 33650;
30/// const MQTT_SERVER: SocketAddrV4 = SocketAddrV4::new(Ipv4Addr::new(192, 168, 2, 10), 1883);
31///
32/// w5500.tcp_connect(MQTT_SOCKET, MQTT_SOURCE_PORT, &MQTT_SERVER)?;
33///
34/// // ... wait for a CON interrupt
35///
36/// const CONNECT: [u8; 14] = [
37///     0x10, 0x0C, 0x00, 0x04, b'M', b'Q', b'T', b'T', 0x04, 0x02, 0x0E, 0x10, 0x00, 0x00,
38/// ];
39/// let tx_bytes: u16 = w5500.tcp_write(MQTT_SOCKET, &CONNECT)?;
40/// assert_eq!(usize::from(tx_bytes), CONNECT.len());
41///
42/// // ... wait for a RECV interrupt
43///
44/// let mut reader: TcpReader<_> = w5500.tcp_reader(MQTT_SOCKET)?;
45/// let mut buf = [0; 2];
46///
47/// // read the first two bytes
48/// reader.read_exact(&mut buf)?;
49/// // ... do something with the data
50///
51/// // read another two bytes into the same buffer
52/// reader.read_exact(&mut buf)?;
53/// // ... do something with the data
54///
55/// // mark the data as read
56/// reader.done()?;
57/// # Ok::<(), w5500_hl::Error<_>>(())
58/// ```
59#[derive(Debug)]
60#[cfg_attr(feature = "defmt", derive(defmt::Format))]
61pub struct TcpReader<'w, W5500> {
62    pub(crate) w5500: &'w mut W5500,
63    pub(crate) sn: Sn,
64    pub(crate) head_ptr: u16,
65    pub(crate) tail_ptr: u16,
66    pub(crate) ptr: u16,
67}
68
69impl<'w, W5500> Seek for TcpReader<'w, W5500> {
70    fn seek<E>(&mut self, pos: SeekFrom) -> Result<(), Error<E>> {
71        self.ptr = pos.new_ptr(self.ptr, self.head_ptr, self.tail_ptr)?;
72        Ok(())
73    }
74
75    fn rewind(&mut self) {
76        self.ptr = self.head_ptr
77    }
78
79    fn stream_len(&self) -> u16 {
80        self.tail_ptr.wrapping_sub(self.head_ptr)
81    }
82
83    fn stream_position(&self) -> u16 {
84        self.ptr.wrapping_sub(self.head_ptr)
85    }
86
87    fn remain(&self) -> u16 {
88        self.tail_ptr.wrapping_sub(self.ptr)
89    }
90}
91
92impl<'a, W5500: Registers> Read<W5500::Error> for TcpReader<'a, W5500> {
93    fn read(&mut self, buf: &mut [u8]) -> Result<u16, W5500::Error> {
94        let read_size: u16 = min(self.remain(), buf.len().try_into().unwrap_or(u16::MAX));
95        if read_size != 0 {
96            self.w5500
97                .sn_rx_buf(self.sn, self.ptr, &mut buf[..usize::from(read_size)])?;
98            self.ptr = self.ptr.wrapping_add(read_size);
99
100            Ok(read_size)
101        } else {
102            Ok(0)
103        }
104    }
105
106    fn read_exact(&mut self, buf: &mut [u8]) -> Result<(), Error<W5500::Error>> {
107        let buf_len: u16 = buf.len().try_into().unwrap_or(u16::MAX);
108        let read_size: u16 = min(self.remain(), buf_len);
109        if read_size != buf_len {
110            Err(Error::UnexpectedEof)
111        } else {
112            self.w5500.sn_rx_buf(self.sn, self.ptr, buf)?;
113            self.ptr = self.ptr.wrapping_add(read_size);
114            Ok(())
115        }
116    }
117
118    fn done(self) -> Result<(), W5500::Error> {
119        self.w5500.set_sn_rx_rd(self.sn, self.ptr)?;
120        self.w5500.set_sn_cr(self.sn, SocketCommand::Recv)?;
121        Ok(())
122    }
123}
124
125/// Streaming writer for a TCP socket buffer.
126///
127/// This implements the [`Seek`] traits.
128///
129/// Created with [`Tcp::tcp_writer`](crate::Tcp::tcp_writer).
130///
131/// # Example
132///
133/// ```no_run
134/// # use ehm::eh1 as h;
135/// # let mut w5500 = w5500_ll::eh1::vdm::W5500::new(h::spi::Mock::new(&[]));
136/// use w5500_hl::{
137///     io::Write,
138///     ll::{Registers, Sn, SocketInterrupt},
139///     net::{Ipv4Addr, SocketAddrV4},
140///     Tcp, TcpWriter,
141/// };
142///
143/// const MQTT_SOCKET: Sn = Sn::Sn0;
144/// const MQTT_SOURCE_PORT: u16 = 33650;
145/// const MQTT_SERVER: SocketAddrV4 = SocketAddrV4::new(Ipv4Addr::new(192, 168, 2, 10), 1883);
146///
147/// w5500.tcp_connect(MQTT_SOCKET, MQTT_SOURCE_PORT, &MQTT_SERVER)?;
148///
149/// // ... wait for a CON interrupt
150///
151/// const CONNECT: [u8; 14] = [
152///     0x10, 0x0C, 0x00, 0x04, b'M', b'Q', b'T', b'T', 0x04, 0x02, 0x0E, 0x10, 0x00, 0x00,
153/// ];
154/// let mut writer: TcpWriter<_> = w5500.tcp_writer(MQTT_SOCKET)?;
155/// writer.write_all(&CONNECT)?;
156/// writer.send()?;
157/// # Ok::<(), w5500_hl::Error<_>>(())
158/// ```
159#[derive(Debug, PartialEq, Eq)]
160#[cfg_attr(feature = "defmt", derive(defmt::Format))]
161pub struct TcpWriter<'w, W5500> {
162    pub(crate) w5500: &'w mut W5500,
163    pub(crate) sn: Sn,
164    pub(crate) head_ptr: u16,
165    pub(crate) tail_ptr: u16,
166    pub(crate) ptr: u16,
167}
168
169impl<'w, W5500> Seek for TcpWriter<'w, W5500> {
170    fn seek<E>(&mut self, pos: SeekFrom) -> Result<(), Error<E>> {
171        self.ptr = pos.new_ptr(self.ptr, self.head_ptr, self.tail_ptr)?;
172        Ok(())
173    }
174
175    fn rewind(&mut self) {
176        self.ptr = self.head_ptr
177    }
178
179    fn stream_len(&self) -> u16 {
180        self.tail_ptr.wrapping_sub(self.head_ptr)
181    }
182
183    fn stream_position(&self) -> u16 {
184        self.ptr.wrapping_sub(self.head_ptr)
185    }
186
187    fn remain(&self) -> u16 {
188        self.tail_ptr.wrapping_sub(self.ptr)
189    }
190}
191
192impl<'w, W5500: Registers> Write<W5500::Error> for TcpWriter<'w, W5500> {
193    fn write(&mut self, buf: &[u8]) -> Result<u16, W5500::Error> {
194        let write_size: u16 = min(self.remain(), buf.len().try_into().unwrap_or(u16::MAX));
195        if write_size != 0 {
196            self.w5500
197                .set_sn_tx_buf(self.sn, self.ptr, &buf[..usize::from(write_size)])?;
198            self.ptr = self.ptr.wrapping_add(write_size);
199
200            Ok(write_size)
201        } else {
202            Ok(0)
203        }
204    }
205
206    fn write_all(&mut self, buf: &[u8]) -> Result<(), Error<W5500::Error>> {
207        let buf_len: u16 = buf.len().try_into().unwrap_or(u16::MAX);
208        let write_size: u16 = min(self.remain(), buf_len);
209        if write_size != buf_len {
210            Err(Error::OutOfMemory)
211        } else {
212            self.w5500.set_sn_tx_buf(self.sn, self.ptr, buf)?;
213            self.ptr = self.ptr.wrapping_add(write_size);
214            Ok(())
215        }
216    }
217
218    fn send(self) -> Result<(), W5500::Error> {
219        self.w5500.set_sn_tx_wr(self.sn, self.ptr)?;
220        self.w5500.set_sn_cr(self.sn, SocketCommand::Send)?;
221        Ok(())
222    }
223}
224
225/// A W5500 TCP trait.
226pub trait Tcp: Registers {
227    /// Starts the 3-way TCP handshake with the remote host.
228    ///
229    /// This method is used to create and interact with a TCP stream between
230    /// a local host and a remote socket.
231    ///
232    /// After initiating a connection with [`tcp_connect`] and receiving the
233    /// [`con`] interrupt data can be transmitting by using [`tcp_read`] and
234    /// [`tcp_write`].
235    ///
236    /// Calling this method **does not** mean the socket will be connected
237    /// afterwards, this simply starts the three way handshake.
238    ///
239    /// After calling this method you will eventually get one of 3 interrupts on
240    /// the socket:
241    ///
242    /// 1. [`con`](w5500_ll::SocketInterrupt::con_raised)
243    /// 2. [`discon`](w5500_ll::SocketInterrupt::discon_raised)
244    /// 3. [`timeout`](w5500_ll::SocketInterrupt::timeout_raised)
245    ///
246    /// # Arguments
247    ///
248    /// * `socket` - The socket number to use for this TCP stream.
249    /// * `port` - The local port to use for the TCP connection.
250    /// * `addr` - Address of the remote host to connect to.
251    ///
252    /// # Panics
253    ///
254    /// * (debug) The port must not be in use by any other socket on the W5500.
255    ///
256    /// # Example
257    ///
258    /// ```no_run
259    /// # let mut w5500 = w5500_ll::eh1::vdm::W5500::new(ehm::eh1::spi::Mock::new(&[]));
260    /// use w5500_hl::{
261    ///     ll::{Registers, Sn, SocketInterrupt},
262    ///     net::{Ipv4Addr, SocketAddrV4},
263    ///     Tcp,
264    /// };
265    ///
266    /// const MQTT_SOCKET: Sn = Sn::Sn0;
267    /// const MQTT_SOURCE_PORT: u16 = 33650;
268    /// const MQTT_SERVER: SocketAddrV4 = SocketAddrV4::new(Ipv4Addr::new(192, 168, 2, 10), 1883);
269    ///
270    /// w5500.tcp_connect(MQTT_SOCKET, MQTT_SOURCE_PORT, &MQTT_SERVER)?;
271    ///
272    /// // wait for a socket interrupt
273    /// // you should use the actual interrupt pin, polling is just for demonstration
274    /// loop {
275    ///     let sn_ir: SocketInterrupt = w5500.sn_ir(MQTT_SOCKET)?;
276    ///
277    ///     // in reality you will want to handle disconnections gracefully with retries
278    ///     assert!(!sn_ir.discon_raised());
279    ///     assert!(!sn_ir.timeout_raised());
280    ///
281    ///     // connection succeded
282    ///     if sn_ir.con_raised() {
283    ///         break;
284    ///     }
285    /// }
286    /// # Ok::<(), embedded_hal::spi::ErrorKind>(())
287    /// ```
288    ///
289    /// [`tcp_write`]: Tcp::tcp_write
290    /// [`tcp_read`]: Tcp::tcp_read
291    /// [`tcp_connect`]: Tcp::tcp_connect
292    /// [`con`]: w5500_ll::SocketInterrupt::con_raised
293    fn tcp_connect(&mut self, sn: Sn, port: u16, addr: &SocketAddrV4) -> Result<(), Self::Error> {
294        debug_assert!(
295            port_is_unique(self, sn, port)?,
296            "Local port {port} is in use"
297        );
298
299        self.set_sn_cr(sn, SocketCommand::Close)?;
300        // This will not hang, the socket status will always change to closed
301        // after a close command.
302        // (unless you do somthing silly like holding the W5500 in reset)
303        while self.sn_sr(sn)? != Ok(SocketStatus::Closed) {}
304
305        const MODE: SocketMode = SocketMode::DEFAULT.set_protocol(Protocol::Tcp);
306        self.set_sn_mr(sn, MODE)?;
307        self.set_sn_port(sn, port)?;
308        self.set_sn_cr(sn, SocketCommand::Open)?;
309        self.set_sn_dest(sn, addr)?;
310        // This will not hang, the socket status will always change to Init
311        // after a open command with SN_MR set to TCP.
312        // (unless you do somthing silly like holding the W5500 in reset)
313        while self.sn_sr(sn)? != Ok(SocketStatus::Init) {}
314
315        self.set_sn_cr(sn, SocketCommand::Connect)
316    }
317
318    /// Open a TCP listener on the given port.
319    ///
320    /// After opening a listener with [`tcp_listen`] and receiving the
321    /// [`con`] interrupt data can be transmitting by using [`tcp_read`] and
322    /// [`tcp_write`].
323    ///
324    /// # Arguments
325    ///
326    /// * `socket` - The socket number to use for this TCP listener.
327    /// * `port` - The local port to listen for remote connections on.
328    ///
329    /// # Panics
330    ///
331    /// * (debug) The port must not be in use by any other socket on the W5500.
332    ///
333    /// # Example
334    ///
335    /// Create an HTTP server.
336    ///
337    /// ```no_run
338    /// # let mut w5500 = w5500_ll::eh1::vdm::W5500::new(ehm::eh1::spi::Mock::new(&[]));
339    /// use w5500_hl::{
340    ///     ll::{Registers, Sn, SocketInterrupt},
341    ///     net::{Ipv4Addr, SocketAddrV4},
342    ///     Tcp,
343    /// };
344    /// // global_allocator is currently avaliable on nightly for embedded rust
345    /// extern crate alloc;
346    /// use alloc::vec::{self, Vec};
347    ///
348    /// const HTTP_SOCKET: Sn = Sn::Sn1;
349    /// const HTTP_PORT: u16 = 80;
350    ///
351    /// // start serving
352    /// w5500.tcp_listen(HTTP_SOCKET, HTTP_PORT)?;
353    ///
354    /// // wait for the RECV interrupt, indicating there is data to read from a client
355    /// loop {
356    ///     let sn_ir = w5500.sn_ir(HTTP_SOCKET).unwrap();
357    ///     if sn_ir.recv_raised() {
358    ///         w5500.set_sn_ir(HTTP_SOCKET, sn_ir).unwrap();
359    ///         break;
360    ///     }
361    ///     if sn_ir.discon_raised() | sn_ir.timeout_raised() {
362    ///         panic!("Socket disconnected while waiting for RECV");
363    ///     }
364    /// }
365    ///
366    /// let mut buf: Vec<u8> = vec![0; 256];
367    /// let rx_bytes: u16 = w5500.tcp_read(HTTP_SOCKET, &mut buf)?;
368    /// // Truncate the buffer to the number of bytes read
369    /// // Safety: BUF is only borrowed mutably in one location
370    /// let filled_buf: &[u8] = &buf[..rx_bytes.into()];
371    ///
372    /// // parse HTTP request here using filled_buf
373    /// # Ok::<(), embedded_hal::spi::ErrorKind>(())
374    /// ```
375    ///
376    /// [`tcp_write`]: Tcp::tcp_write
377    /// [`tcp_read`]: Tcp::tcp_read
378    /// [`tcp_listen`]: Tcp::tcp_listen
379    /// [`con`]: w5500_ll::SocketInterrupt::con_raised
380    fn tcp_listen(&mut self, sn: Sn, port: u16) -> Result<(), Self::Error> {
381        debug_assert!(
382            port_is_unique(self, sn, port)?,
383            "Local port {port} is in use"
384        );
385
386        self.set_sn_cr(sn, SocketCommand::Close)?;
387        // This will not hang, the socket status will always change to closed
388        // after a close command.
389        // (unless you do somthing silly like holding the W5500 in reset)
390        while self.sn_sr(sn)? != Ok(SocketStatus::Closed) {}
391        const MODE: SocketMode = SocketMode::DEFAULT.set_protocol(Protocol::Tcp);
392        self.set_sn_mr(sn, MODE)?;
393        self.set_sn_port(sn, port)?;
394        self.set_sn_cr(sn, SocketCommand::Open)?;
395        // This will not hang, the socket status will always change to Init
396        // after a open command with SN_MR set to TCP.
397        // (unless you do somthing silly like holding the W5500 in reset)
398        while self.sn_sr(sn)? != Ok(SocketStatus::Init) {}
399        self.set_sn_cr(sn, SocketCommand::Listen)
400    }
401
402    /// Read data from the remote host, returning the number of bytes read.
403    ///
404    /// You should wait for the socket [`recv`] interrupt before calling this method.
405    ///
406    /// # Panics
407    ///
408    /// * (debug) The socket must be an [`Established`] TCP socket.
409    ///
410    /// # Example
411    ///
412    /// Send a MQTT CONNECT packet and read a CONNACK.
413    ///
414    /// ```no_run
415    /// # let mut w5500 = w5500_ll::eh1::vdm::W5500::new(ehm::eh1::spi::Mock::new(&[]));
416    /// use w5500_hl::{
417    ///     ll::{Registers, Sn, SocketInterrupt},
418    ///     net::{Ipv4Addr, SocketAddrV4},
419    ///     Tcp,
420    /// };
421    ///
422    /// const MQTT_SOCKET: Sn = Sn::Sn0;
423    /// const MQTT_SOURCE_PORT: u16 = 33650;
424    /// const MQTT_SERVER: SocketAddrV4 = SocketAddrV4::new(Ipv4Addr::new(192, 168, 2, 10), 1883);
425    ///
426    /// w5500.tcp_connect(MQTT_SOCKET, MQTT_SOURCE_PORT, &MQTT_SERVER)?;
427    ///
428    /// // ... wait for a CON interrupt
429    ///
430    /// const CONNECT: [u8; 14] = [
431    ///     0x10, 0x0C, 0x00, 0x04, b'M', b'Q', b'T', b'T', 0x04, 0x02, 0x0E, 0x10, 0x00, 0x00,
432    /// ];
433    /// let tx_bytes: u16 = w5500.tcp_write(MQTT_SOCKET, &CONNECT)?;
434    /// assert_eq!(usize::from(tx_bytes), CONNECT.len());
435    ///
436    /// // ... wait for a RECV interrupt
437    ///
438    /// let mut buf = [0; 10];
439    /// let rx_bytes: u16 = w5500.tcp_read(MQTT_SOCKET, &mut buf)?;
440    /// let filled_buf = &buf[..rx_bytes.into()];
441    /// # Ok::<(), embedded_hal::spi::ErrorKind>(())
442    /// ```
443    ///
444    /// [`Established`]: w5500_ll::SocketStatus::Established
445    /// [`recv`]: w5500_ll::SocketInterrupt::recv_raised
446    fn tcp_read(&mut self, sn: Sn, buf: &mut [u8]) -> Result<u16, Self::Error> {
447        debug_assert!(!matches!(
448            self.sn_sr(sn)?,
449            Ok(SocketStatus::Udp) | Ok(SocketStatus::Init) | Ok(SocketStatus::Macraw)
450        ));
451
452        let rx_bytes: u16 = {
453            let rsr: u16 = self.sn_rx_rsr(sn)?;
454            min(rsr, u16::try_from(buf.len()).unwrap_or(u16::MAX))
455        };
456        if rx_bytes != 0 {
457            let ptr: u16 = self.sn_rx_rd(sn)?;
458            self.sn_rx_buf(sn, ptr, &mut buf[..usize::from(rx_bytes)])?;
459            self.set_sn_rx_rd(sn, ptr.wrapping_add(rx_bytes))?;
460            self.set_sn_cr(sn, SocketCommand::Recv)?;
461        }
462        Ok(rx_bytes)
463    }
464
465    /// Send data to the remote host, returning the number of bytes written.
466    ///
467    /// # Panics
468    ///
469    /// * (debug) The socket must be an [`Established`] TCP socket.
470    ///
471    /// # Example
472    ///
473    /// Send a MQTT CONNECT packet.
474    ///
475    /// ```no_run
476    /// # let mut w5500 = w5500_ll::eh1::vdm::W5500::new(ehm::eh1::spi::Mock::new(&[]));
477    /// use w5500_hl::{
478    ///     ll::{Registers, Sn, SocketInterrupt},
479    ///     net::{Ipv4Addr, SocketAddrV4},
480    ///     Tcp,
481    /// };
482    ///
483    /// const MQTT_SOCKET: Sn = Sn::Sn0;
484    /// const MQTT_SOURCE_PORT: u16 = 33650;
485    /// const MQTT_SERVER: SocketAddrV4 = SocketAddrV4::new(Ipv4Addr::new(192, 168, 2, 10), 1883);
486    ///
487    /// w5500.tcp_connect(MQTT_SOCKET, MQTT_SOURCE_PORT, &MQTT_SERVER)?;
488    ///
489    /// // ... wait for a CON interrupt
490    ///
491    /// const CONNECT: [u8; 14] = [
492    ///     0x10, 0x0C, 0x00, 0x04, b'M', b'Q', b'T', b'T', 0x04, 0x02, 0x0E, 0x10, 0x00, 0x00,
493    /// ];
494    /// let tx_bytes: u16 = w5500.tcp_write(MQTT_SOCKET, &CONNECT)?;
495    /// assert_eq!(usize::from(tx_bytes), CONNECT.len());
496    /// # Ok::<(), embedded_hal::spi::ErrorKind>(())
497    /// ```
498    ///
499    /// [`Established`]: w5500_ll::SocketStatus::Established
500    fn tcp_write(&mut self, sn: Sn, buf: &[u8]) -> Result<u16, Self::Error> {
501        debug_assert!(!matches!(
502            self.sn_sr(sn)?,
503            Ok(SocketStatus::Udp) | Ok(SocketStatus::Init) | Ok(SocketStatus::Macraw)
504        ));
505
506        let tx_bytes: u16 = {
507            let data_len: u16 = u16::try_from(buf.len()).unwrap_or(u16::MAX);
508            let free_size: u16 = self.sn_tx_fsr(sn)?;
509            min(data_len, free_size)
510        };
511        if tx_bytes != 0 {
512            let ptr: u16 = self.sn_tx_wr(sn)?;
513            self.set_sn_tx_buf(sn, ptr, &buf[..usize::from(tx_bytes)])?;
514            self.set_sn_tx_wr(sn, ptr.wrapping_add(tx_bytes))?;
515            self.set_sn_cr(sn, SocketCommand::Send)?;
516        }
517        Ok(tx_bytes)
518    }
519
520    /// Disconnect from the peer.
521    ///
522    /// If the disconnect is successful (FIN/ACK packet is received) the socket
523    /// status changes to [`Closed`], otherwise TCP<sub>TO</sub> occurs, the
524    /// [timeout interrupt] is raised, and the socket status changes to
525    /// [`Closed`].
526    ///
527    /// # Panics
528    ///
529    /// * (debug) The socket must be an [`Established`] TCP socket.
530    ///
531    /// # Example
532    ///
533    /// Connect and disconnect from a MQTT server.
534    ///
535    /// ```no_run
536    /// # let mut w5500 = w5500_ll::eh1::vdm::W5500::new(ehm::eh1::spi::Mock::new(&[]));
537    /// use w5500_hl::{
538    ///     ll::{Registers, Sn, SocketInterrupt},
539    ///     net::{Ipv4Addr, SocketAddrV4},
540    ///     Tcp,
541    /// };
542    ///
543    /// const MQTT_SOCKET: Sn = Sn::Sn0;
544    /// const MQTT_SOURCE_PORT: u16 = 33650;
545    /// const MQTT_SERVER: SocketAddrV4 = SocketAddrV4::new(Ipv4Addr::new(192, 168, 2, 10), 1883);
546    ///
547    /// w5500.tcp_connect(MQTT_SOCKET, MQTT_SOURCE_PORT, &MQTT_SERVER)?;
548    ///
549    /// // ... wait for a CON interrupt
550    ///
551    /// w5500.tcp_disconnect(MQTT_SOCKET)?;
552    /// # Ok::<(), embedded_hal::spi::ErrorKind>(())
553    /// ```
554    ///
555    /// [`Closed`]: w5500_ll::SocketStatus::Closed
556    /// [`Established`]: w5500_ll::SocketStatus::Established
557    /// [timeout interrupt]: w5500_ll::SocketInterrupt::timeout_raised
558    fn tcp_disconnect(&mut self, sn: Sn) -> Result<(), Self::Error> {
559        debug_assert!(!matches!(
560            self.sn_sr(sn)?,
561            Ok(SocketStatus::Udp) | Ok(SocketStatus::Init) | Ok(SocketStatus::Macraw)
562        ));
563        self.set_sn_cr(sn, SocketCommand::Disconnect)
564    }
565
566    /// Create a TCP reader.
567    ///
568    /// This returns a [`TcpReader`] structure, which contains functions to
569    /// stream data from the W5500 socket buffers incrementally.
570    ///
571    /// This will return [`Error::WouldBlock`] if there is no data to read.
572    ///
573    /// # Errors
574    ///
575    /// This method can only return:
576    ///
577    /// * [`Error::Other`]
578    /// * [`Error::WouldBlock`]
579    ///
580    /// # Example
581    ///
582    /// See [`TcpReader`].
583    fn tcp_reader(&mut self, sn: Sn) -> Result<TcpReader<Self>, Error<Self::Error>>
584    where
585        Self: Sized,
586    {
587        debug_assert!(!matches!(
588            self.sn_sr(sn)?,
589            Ok(SocketStatus::Udp) | Ok(SocketStatus::Init) | Ok(SocketStatus::Macraw)
590        ));
591
592        let sn_rx_rsr: u16 = self.sn_rx_rsr(sn)?;
593        if sn_rx_rsr == 0 {
594            return Err(Error::WouldBlock);
595        }
596
597        let sn_rx_rd: u16 = self.sn_rx_rd(sn)?;
598
599        Ok(TcpReader {
600            w5500: self,
601            sn,
602            head_ptr: sn_rx_rd,
603            tail_ptr: sn_rx_rd.wrapping_add(sn_rx_rsr),
604            ptr: sn_rx_rd,
605        })
606    }
607
608    /// Create a TCP writer.
609    ///
610    /// This returns a [`TcpWriter`] structure, which contains functions to
611    /// stream data to the W5500 socket buffers incrementally.
612    ///
613    /// # Example
614    ///
615    /// See [`TcpWriter`].
616    fn tcp_writer(&mut self, sn: Sn) -> Result<TcpWriter<Self>, Self::Error>
617    where
618        Self: Sized,
619    {
620        let tx_ptrs: TxPtrs = self.sn_tx_ptrs(sn)?;
621
622        Ok(TcpWriter {
623            w5500: self,
624            sn,
625            head_ptr: tx_ptrs.wr,
626            tail_ptr: tx_ptrs.wr.wrapping_add(tx_ptrs.fsr),
627            ptr: tx_ptrs.wr,
628        })
629    }
630}
631
632/// Implement the TCP trait for any structure that implements [`w5500_ll::Registers`].
633impl<T> Tcp for T where T: Registers {}