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