Skip to content

Commit

Permalink
Merge pull request #55 from LechevSpace/chore/socket-and-other-docs
Browse files Browse the repository at this point in the history
Chore: Improve API and add docs
  • Loading branch information
ryan-summers authored Jul 25, 2023
2 parents f3f0f3e + 02063d1 commit 3da66e6
Show file tree
Hide file tree
Showing 4 changed files with 257 additions and 6 deletions.
8 changes: 7 additions & 1 deletion src/device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ use crate::socket::Socket;
use crate::uninitialized_device::UninitializedDevice;
use crate::{register, MacAddress};

#[derive(Debug, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum ResetError<E> {
SocketsNotReleased,
Other(E),
Expand All @@ -21,7 +23,7 @@ impl<E> From<E> for ResetError<E> {

#[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub(crate) struct DeviceState<HostImpl: Host> {
pub struct DeviceState<HostImpl: Host> {
host: HostImpl,
sockets: [u8; 1],
}
Expand All @@ -42,6 +44,10 @@ impl<SpiBus: Bus, HostImpl: Host> Device<SpiBus, HostImpl> {
}
}

pub fn get_state(&self) -> &DeviceState<HostImpl> {
&self.state
}

pub fn reset(mut self) -> Result<UninitializedDevice<SpiBus>, ResetError<SpiBus::Error>> {
if self.state.sockets != [0b11111111] {
Err(ResetError::SocketsNotReleased)
Expand Down
161 changes: 157 additions & 4 deletions src/register.rs
Original file line number Diff line number Diff line change
Expand Up @@ -156,41 +156,111 @@ pub const SOCKET7_BUFFER_RX: u8 = 0b000_11111;
pub mod socketn {
use derive_try_from_primitive::TryFromPrimitive;

/// The Protocol mode
pub const MODE: u16 = 0x00;

/// The protocol modes that can be used with the `w5500`
#[repr(u8)]
pub enum Protocol {
Closed = 0b00,
Tcp = 0b01,
Udp = 0b10,
MacRaw = 0b100,
}

/// Socket n Command Register
///
/// `Sn_CR`
pub const COMMAND: u16 = 0x01;

/// Socket n Commands
///
/// `Sn_CR` register
#[repr(u8)]
pub enum Command {
Open = 0x01,
/// [Datasheet page 46](https://docs.wiznet.io/img/products/w5500/W5500_ds_v110e.pdf):
///
/// > This is valid only in TCP mode (Sn_MR(P3:P0) = Sn_MR_TCP). In this
/// > mode, Socket n operates as a ‘TCP server’ and waits for connection-
/// > request (SYN packet) from any ‘TCP client
Listen = 0x02,
Connect = 0x04,
Discon = 0x08,
Close = 0x10,
Send = 0x20,

/// [Datasheet page 48](https://docs.wiznet.io/img/products/w5500/W5500_ds_v110e.pdf):
///
/// > RECV completes the processing of the received data in Socket n RX
/// > Buffer by using a RX read pointer register (Sn_RX_RD).
/// > For more details, refer to Socket n RX Received Size Register
/// > (Sn_RX_RSR), Socket n RX Write Pointer Register (Sn_RX_WR), and
/// > Socket n RX Read Pointer Register (Sn_RX_RD).
Receive = 0x40,
}

pub const INTERRUPT: u16 = 0x02;
/// | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
/// | Reserved | Reserved | Reserved | SEND_OK | TIMEOUT | RECV | DISCON | CON |
///
/// | Bit | Symbol | Description |
/// | 7~5 | Reserved | Reserved |
/// | 4 | SENDOK | Sn_IR(SENDOK) | Interrupt Mask |
/// | 3 | TIMEOUT | Sn_IR(TIMEOUT) | Interrupt Mask |
/// | 2 | RECV | Sn_IR(RECV) | Interrupt Mask |
/// | 1 | DISCON | Sn_IR(DISCON) | Interrupt Mask |
/// | 0 | CON | Sn_IR(CON) | Interrupt Mask |
#[repr(u8)]
pub enum Interrupt {
All = 0b11111111u8,
SendOk = 0b010000u8,
Timeout = 0b01000u8,
Receive = 0b00100u8,
SendOk = 0b10000u8,
Timeout = 0b1000u8,

/// Receive data
///
/// bit 2, symbol `RECV`, `Sn_IR(RECV) Interrupt Mask`
Receive = 0b100u8,

/// Disconnect
///
/// bit 1, symbol `DISCON`, `Sn_IR(DISCON) Interrupt Mask`
Disconnect = 0b10u8,

/// Connect
///
/// bit 0, symbol `CON`, `Sn_IR(CON) Interrupt Mask`
Connect = 0b1u8,
}

pub const STATUS: u16 = 0x03;

/// Socket status register
///
/// `W5500 Datasheet Version 1.1.0` page 49:
///
/// > Sn_SR (Socket n Status Register) [R] [0x0003] [0x00]
///
/// - 0x18 SOCK_FIN_WAIT
/// - 0x1A SOCK_CLOSING
/// - 0X1B SOCK_TIME_WAIT
/// > These indicate Socket n is closing.
/// > These are shown in disconnect-process such as active-close
/// > and passive-close.
/// > When Disconnect-process is successfully completed, or
/// > when timeout occurs, these change to SOCK_CLOSED.
///
#[derive(TryFromPrimitive, Debug, Copy, Clone, PartialEq, Eq)]
#[repr(u8)]
#[derive(TryFromPrimitive)]
pub enum Status {
Closed = 0x00,
Init = 0x13,

/// [Datasheet page 49](https://docs.wiznet.io/img/products/w5500/W5500_ds_v110e.pdf):
///
/// > This indicates Socket n is operating as ‘TCP server’ mode and
/// > waiting for connection-request (SYN packet) from a peer
/// > (‘TCP client’).
Listen = 0x14,
Established = 0x17,
CloseWait = 0x1c,
Expand All @@ -206,6 +276,19 @@ pub mod socketn {
LastAck = 0x1d,
}

#[cfg(feature = "defmt")]
impl defmt::Format for Status {
fn format(&self, fmt: defmt::Formatter) {
// Format as hexadecimal.
defmt::write!(
fmt,
"Status::{} ({=u8:#x})",
defmt::Debug2Format(self),
*self as u8
);
}
}

pub const SOURCE_PORT: u16 = 0x04;

pub const DESTINATION_IP: u16 = 0x0C;
Expand All @@ -214,17 +297,87 @@ pub mod socketn {

pub const RXBUF_SIZE: u16 = 0x1E;

/// Socket n TX Buffer Size Register
///
/// `Sn_TXBUF_SIZE`
///
/// From datasheet:
///
/// > .. can be configured with 1,2,4,8, and 16 Kbytes.
/// >
/// > Although Socket n TX Buffer Block size is initially configured to 2Kbytes, user can
/// > be re-configure its size using Sn_TXBUF_SIZE. The total sum of Sn_TXBUF_SIZE
/// > cannot be exceed 16Kbytes. When exceeded, the data transmission error is
/// > occurred.
pub const TXBUF_SIZE: u16 = 0x1F;

/// TX Free Size Register
///
/// `Sn_TX_FSR`
///
/// Socket n TX Free Size
///
/// offset (register)
/// 0x0020 (Sn_TX_FSR0)
/// 0x0021 (Sn_TX_FSR1)
pub const TX_FREE_SIZE: u16 = 0x20;

/// Socket n TX Read Pointer
///
/// offset (register)
/// 0x0022 (Sn_TX_RD0)
/// 0x0023 (Sn_TX_RD1)
pub const TX_DATA_READ_POINTER: u16 = 0x22;

/// Socket n TX Write Pointer
///
/// offset (register)
/// 0x0024 (Sn_TX_WR0)
/// 0x0025 (Sn_TX_WR1)
///
/// [Datasheet page 54](https://docs.wiznet.io/img/products/w5500/W5500_ds_v110e.pdf):
///
/// > Sn_TX_WR (Socket n TX Write Pointer Register) [R/W] [0x0024-0x0025] [0x0000]
/// >
/// > Sn_TX_WR is initialized by OPEN command. However, if Sn_MR(P[3:0]) is TCP
/// > mode(‘0001’), it is re-initialized while connecting with TCP.
/// > It should be read or to be updated like as follows.
/// > 1. Read the starting address for saving the transmitting data.
/// > 2. Save the transmitting data from the starting address of Socket n TX
/// > buffer.
/// > 3. After saving the transmitting data, update Sn_TX_WR to the
/// > increased value as many as transmitting data size. If the increment value
/// > exceeds the maximum value 0xFFFF(greater than 0x10000 and the carry
/// > bit occurs), then the carry bit is ignored and will automatically update
/// > with the lower 16bits value.
/// > 4. Transmit the saved data in Socket n TX Buffer by using SEND/SEND
/// command
pub const TX_DATA_WRITE_POINTER: u16 = 0x24;

/// Socket n Received Size Register
///
/// `Sn_RX_RSR`
pub const RECEIVED_SIZE: u16 = 0x26;

pub const RX_DATA_READ_POINTER: u16 = 0x28;

/// Socket n Interrupt Mask
///
/// offset (register)
/// 0x002C (Sn_IMR)
pub const INTERRUPT_MASK: u16 = 0x2C;

#[cfg(test)]
mod tests {
use core::convert::TryFrom;

use super::Status;

#[test]
fn test_status_from_byte() {
let udp = 0x22_u8;
let status = Status::try_from(udp).expect("Should parse to Status");
assert_eq!(status, Status::Udp);
}
}
}
91 changes: 90 additions & 1 deletion src/socket.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ pub struct Socket {
}

impl Socket {
/// 8 sockets available on the w5500
pub fn new(index: u8) -> Self {
/*
* Socket 0 is at address 0x01
Expand Down Expand Up @@ -75,6 +76,7 @@ impl Socket {
) -> Result<bool, SpiBus::Error> {
let mut data = [0u8];
bus.read_frame(self.register(), socketn::INTERRUPT, &mut data)?;

Ok(data[0] & code as u8 != 0)
}

Expand Down Expand Up @@ -179,9 +181,11 @@ impl Socket {
Ok(())
}

/// Get the received bytes size of the socket's RX buffer.
///
/// Section 4.2 of datasheet, Sn_TX_FSR address docs indicate that read must be repeated until two sequential reads are stable
pub fn get_receive_size<SpiBus: Bus>(&self, bus: &mut SpiBus) -> Result<u16, SpiBus::Error> {
loop {
// Section 4.2 of datasheet, Sn_TX_FSR address docs indicate that read must be repeated until two sequential reads are stable
let mut sample_0 = [0u8; 2];
bus.read_frame(self.register(), socketn::RECEIVED_SIZE, &mut sample_0)?;
let mut sample_1 = [0u8; 2];
Expand All @@ -192,9 +196,94 @@ impl Socket {
}
}

/// Get the free TX buffer size still available for this socket.
///
/// It's cleared once we `SEND` the buffer over the socket.
pub fn get_tx_free_size<SpiBus: Bus>(&self, bus: &mut SpiBus) -> Result<u16, SpiBus::Error> {
let mut data = [0; 2];
bus.read_frame(self.register(), socketn::TX_FREE_SIZE, &mut data)?;
Ok(u16::from_be_bytes(data))
}
}

#[cfg(test)]
mod test {
use crate::register::*;

use super::*;

#[test]
fn test_socket_registers() {
// Socket 0
{
let socket_0 = Socket::new(0);

assert_eq!(socket_0.register, SOCKET0);
assert_eq!(socket_0.tx_buffer, SOCKET0_BUFFER_TX);
assert_eq!(socket_0.rx_buffer, SOCKET0_BUFFER_RX);
}

// Socket 1
{
let socket_1 = Socket::new(1);

assert_eq!(socket_1.register, SOCKET1);
assert_eq!(socket_1.tx_buffer, SOCKET1_BUFFER_TX);
assert_eq!(socket_1.rx_buffer, SOCKET1_BUFFER_RX);
}

// Socket 2
{
let socket_2 = Socket::new(2);

assert_eq!(socket_2.register, SOCKET2);
assert_eq!(socket_2.tx_buffer, SOCKET2_BUFFER_TX);
assert_eq!(socket_2.rx_buffer, SOCKET2_BUFFER_RX);
}

// Socket 3
{
let socket_3 = Socket::new(3);

assert_eq!(socket_3.register, SOCKET3);
assert_eq!(socket_3.tx_buffer, SOCKET3_BUFFER_TX);
assert_eq!(socket_3.rx_buffer, SOCKET3_BUFFER_RX);
}

// Socket 4
{
let socket_4 = Socket::new(4);

assert_eq!(socket_4.register, SOCKET4);
assert_eq!(socket_4.tx_buffer, SOCKET4_BUFFER_TX);
assert_eq!(socket_4.rx_buffer, SOCKET4_BUFFER_RX);
}

// Socket 5
{
let socket_5 = Socket::new(5);

assert_eq!(socket_5.register, SOCKET5);
assert_eq!(socket_5.tx_buffer, SOCKET5_BUFFER_TX);
assert_eq!(socket_5.rx_buffer, SOCKET5_BUFFER_RX);
}

// Socket 6
{
let socket_6 = Socket::new(6);

assert_eq!(socket_6.register, SOCKET6);
assert_eq!(socket_6.tx_buffer, SOCKET6_BUFFER_TX);
assert_eq!(socket_6.rx_buffer, SOCKET6_BUFFER_RX);
}

// Socket 7
{
let socket_7 = Socket::new(7);

assert_eq!(socket_7.register, SOCKET7);
assert_eq!(socket_7.tx_buffer, SOCKET7_BUFFER_TX);
assert_eq!(socket_7.rx_buffer, SOCKET7_BUFFER_RX);
}
}
}
3 changes: 3 additions & 0 deletions src/uninitialized_device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ impl<SpiBus: Bus> UninitializedDevice<SpiBus> {
self.initialize_with_host(host, mode_options)
}

/// The gateway overrides the passed `ip` ([`Ip4Addr`]) to end with `.1`.
///
/// E.g. `let ip = "192.168.0.201".parse::<Ip4Addr>()` will become a device with a gateway `192.168.0.1`.
pub fn initialize_manual(
self,
mac: MacAddress,
Expand Down

0 comments on commit 3da66e6

Please sign in to comment.