Format, clean

This commit is contained in:
Pascal Engélibert 2025-11-11 14:56:54 +01:00
commit bbd50619a4
21 changed files with 1942 additions and 2121 deletions

View file

@ -1,13 +0,0 @@
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
version: 2
updates:
- package-ecosystem: cargo
directory: "/"
schedule:
interval: daily
time: "07:00"
open-pull-requests-limit: 10

View file

@ -1,70 +0,0 @@
name: Rust
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
check:
name: Check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
override: true
- uses: actions-rs/cargo@v1
with:
command: check
args: --all-features
test:
name: Test Suite
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
override: true
- uses: actions-rs/cargo@v1
with:
command: test
args: --all-features
fmt:
name: Rustfmt
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
override: true
- run: rustup component add rustfmt
- uses: actions-rs/cargo@v1
with:
command: fmt
args: --all -- --check
clippy:
name: Clippy
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
override: true
- run: rustup component add clippy
- uses: actions-rs/cargo@v1
with:
command: clippy
args: -- -D warnings

2
.gitignore vendored
View file

@ -1,4 +1,2 @@
*.iml
/target
**/*.rs.bk
Cargo.lock

View file

@ -13,7 +13,7 @@ keywords = ["embedded", "w5100", "embedded-hal-driver"]
categories = ["embedded", "hardware-support", "no-std", "network-programming"]
license = "AGPL-3.0-only"
readme = "README.md"
edition = "2018"
edition = "2021"
[features]

View file

@ -1,87 +1,12 @@
# W5100 Driver
Rust driver for the WIZnet W5100 Ethernet controler using SPI.
**Fork status**:
* Work-in-progress fork of the crate [w5500](https://github.com/kellerkindt/w5500) for W5100. The two chips are different versions of the same design, very similar but not fully compatible. The older revision of the Arduino Ethernet Shield uses W5100, hence the need for this fork.
* What works: receive and send UDP packets.
* Tested on Arduino Uno with Arduino Ethernet Shield.
This crate is a driver for the WIZnet W5500 chip. The W5500 chip is a hardwired TCP/IP embedded Ethernet controller
that enables embedded systems using SPI (Serial Peripheral Interface) to access the LAN. It is one of the
more popular ethernet modules on Arduino platforms.
[![Build Status](https://github.com/kellerkindt/w5500/workflows/Rust/badge.svg)](https://github.com/kellerkindt/w5500/actions?query=workflow%3ARust)
[![License](https://img.shields.io/badge/license-MIT%2FApache--2.0-blue.svg)](https://github.com/kellerkindt/w5500)
[![Crates.io](https://img.shields.io/crates/v/w5500.svg)](https://crates.io/crates/w5500)
[![Documentation](https://docs.rs/w5500/badge.svg)](https://docs.rs/w5500)
[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://github.com/kellerkindt/w5500/issues/new)
## Embedded-HAL
The [`embedded-hal`](https://docs.rs/embedded-hal/latest/embedded_hal/index.html) is a standard set
of traits meant to permit communication between MCU implementations and hardware drivers like this
one. Any microcontroller that implements the
[`spi::SpiDevice`](https://docs.rs/embedded-hal/latest/embedded_hal/spi/trait.SpiDevice.html) or
[`spi::SpiBus`](https://docs.rs/embedded-hal/latest/embedded_hal/spi/trait.SpiBus.html) can use this
driver.
# Example Usage
Below is a basic example of sending UDP packets to a remote host. An important thing to confirm is the configuration
of the SPI implementation. It must be set up to work as the W5500 chip requires. That configuration is as follows:
* Data Order: Most significant bit first
* Clock Polarity: Idle low
* Clock Phase: Sample leading edge
* Clock speed: 33MHz maximum
```rust,no_run
use core::net::{IpAddr, Ipv4Addr, SocketAddr};
#
# struct Mock;
#
# impl embedded_hal::spi::ErrorType for Mock {
# type Error = core::convert::Infallible;
# }
#
# impl embedded_hal::spi::SpiDevice for Mock {
# fn transaction(&mut self, operations: &mut [embedded_hal::spi::Operation<'_, u8>]) -> Result<(), Self::Error> {
# Ok(())
# }
# }
use embedded_nal::UdpClientStack;
let mut spi = Mock;
let mut device = w5500::UninitializedDevice::new(w5500::bus::FourWire::new(spi))
.initialize_manual(
w5500::MacAddress::new(0, 1, 2, 3, 4, 5),
Ipv4Addr::new(192, 168, 86, 79),
w5500::Mode::default()
).unwrap();
// Allocate a UDP socket to send data with
let mut socket = device.socket().unwrap();
// Connect the socket to the IP address and port we want to send to.
device.connect(&mut socket,
SocketAddr::new(IpAddr::V4(Ipv4Addr::new(192, 168, 86, 38)), 8000),
).unwrap();
// Send the data
nb::block!(device.send(&mut socket, &[104, 101, 108, 108, 111, 10]));
// Optionally close the socket
device.close(socket);
```
## Todo
In no particular order, things to do to improve this driver.
* Add support for TCP server implementations
* Add support for DHCP
## License
[Support me via LiberaPay](https://liberapay.com/tuxmain/donate)

9
rustfmt.toml Normal file
View file

@ -0,0 +1,9 @@
hard_tabs = true
newline_style = "Unix"
imports_granularity = "Crate"
unstable_features = true
format_code_in_doc_comments = true
format_macro_bodies = true
format_macro_matchers = true
format_strings = true

View file

@ -12,44 +12,44 @@ const OPMODE_WRITE: u8 = 0xf0;
#[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct FourWire<SPI> {
spi: SPI,
spi: SPI,
}
impl<SPI> FourWire<SPI> {
pub fn new(spi: SPI) -> Self {
Self { spi }
}
pub fn new(spi: SPI) -> Self {
Self { spi }
}
pub fn release(self) -> SPI {
self.spi
}
pub fn release(self) -> SPI {
self.spi
}
}
impl<SPI: SpiDevice> Bus for FourWire<SPI> {
type Error = <SPI as ErrorType>::Error;
type Error = <SPI as ErrorType>::Error;
fn read_frame(&mut self, address: u16, data: &mut [u8]) -> Result<(), SPI::Error> {
let address_phase = address.to_be_bytes();
for (i, byte) in data.iter_mut().enumerate() {
self.spi.transaction(&mut [
Operation::Write(&[OPMODE_READ]),
Operation::Write(&(address+i as u16).to_be_bytes()),
Operation::TransferInPlace(core::array::from_mut(byte)),
])?;
}
fn read_frame(&mut self, address: u16, data: &mut [u8]) -> Result<(), SPI::Error> {
let address_phase = address.to_be_bytes();
for (i, byte) in data.iter_mut().enumerate() {
self.spi.transaction(&mut [
Operation::Write(&[OPMODE_READ]),
Operation::Write(&(address + i as u16).to_be_bytes()),
Operation::TransferInPlace(core::array::from_mut(byte)),
])?;
}
Ok(())
}
Ok(())
}
fn write_frame(&mut self, address: u16, data: &[u8]) -> Result<(), SPI::Error> {
for (i, byte) in data.iter().enumerate() {
self.spi.transaction(&mut [
Operation::Write(&[OPMODE_WRITE]),
Operation::Write(&(address+i as u16).to_be_bytes()),
Operation::Write(&[*byte]),
])?;
}
fn write_frame(&mut self, address: u16, data: &[u8]) -> Result<(), SPI::Error> {
for (i, byte) in data.iter().enumerate() {
self.spi.transaction(&mut [
Operation::Write(&[OPMODE_WRITE]),
Operation::Write(&(address + i as u16).to_be_bytes()),
Operation::Write(&[*byte]),
])?;
}
Ok(())
}
Ok(())
}
}

View file

@ -5,9 +5,9 @@ mod four_wire;
pub use self::four_wire::FourWire;
pub trait Bus {
type Error: Debug;
type Error: Debug;
fn read_frame(&mut self, address: u16, data: &mut [u8]) -> Result<(), Self::Error>;
fn read_frame(&mut self, address: u16, data: &mut [u8]) -> Result<(), Self::Error>;
fn write_frame(&mut self, address: u16, data: &[u8]) -> Result<(), Self::Error>;
fn write_frame(&mut self, address: u16, data: &[u8]) -> Result<(), Self::Error>;
}

View file

@ -1,126 +1,122 @@
use crate::bus::Bus;
use crate::register::socketn::Command;
use crate::socket::Socket;
use crate::{bus::Bus, register::socketn::Command, socket::Socket};
pub(crate) struct RxCursor<'a, SpiBus>
where
SpiBus: Bus,
SpiBus: Bus,
{
sock: &'a Socket,
bus: &'a mut SpiBus,
ptr: u16,
size: u16,
sock: &'a Socket,
bus: &'a mut SpiBus,
ptr: u16,
size: u16,
}
impl<'a, SpiBus> RxCursor<'a, SpiBus>
where
SpiBus: Bus,
SpiBus: Bus,
{
pub fn new(sock: &'a Socket, bus: &'a mut SpiBus) -> Result<Self, SpiBus::Error> {
let size = sock.get_receive_size(bus)?;
let ptr = sock.get_rx_read_pointer(bus)?;
Ok(Self {
sock,
bus,
ptr,
size,
})
}
pub fn new(sock: &'a Socket, bus: &'a mut SpiBus) -> Result<Self, SpiBus::Error> {
let size = sock.get_receive_size(bus)?;
let ptr = sock.get_rx_read_pointer(bus)?;
Ok(Self {
sock,
bus,
ptr,
size,
})
}
#[inline]
pub fn available(&self) -> u16 {
self.size
}
#[inline]
pub fn available(&self) -> u16 {
self.size
}
/// Read up to `buf.len()` bytes. The actual number of bytes read is bounded by `available()`.
pub fn read(&mut self, buf: &mut [u8]) -> Result<u16, SpiBus::Error> {
if buf.is_empty() {
return Ok(0);
}
/// Read up to `buf.len()` bytes. The actual number of bytes read is bounded by `available()`.
pub fn read(&mut self, buf: &mut [u8]) -> Result<u16, SpiBus::Error> {
if buf.is_empty() {
return Ok(0);
}
let count = self.available().min(buf.len() as u16);
self.bus
.read_frame(self.ptr, &mut buf[..count as _])?;
Ok(self.skip(count))
}
let count = self.available().min(buf.len() as u16);
self.bus.read_frame(self.ptr, &mut buf[..count as _])?;
Ok(self.skip(count))
}
/// Read up to `max` bytes. The actual number of bytes read is bounded by buf.len() and available().
pub fn read_upto(&mut self, buf: &mut [u8], max: u16) -> Result<u16, SpiBus::Error> {
let bounded_buf = if buf.len() > max as usize {
&mut buf[..max as _]
} else {
buf
};
self.read(bounded_buf)
}
/// Read up to `max` bytes. The actual number of bytes read is bounded by buf.len() and available().
pub fn read_upto(&mut self, buf: &mut [u8], max: u16) -> Result<u16, SpiBus::Error> {
let bounded_buf = if buf.len() > max as usize {
&mut buf[..max as _]
} else {
buf
};
self.read(bounded_buf)
}
/// Skip up to count bytes. The actual number of bytes skipped is bounded by available().
pub fn skip(&mut self, count: u16) -> u16 {
let bounded_count = self.available().min(count);
self.ptr = self.ptr.wrapping_add(bounded_count);
self.size -= bounded_count;
bounded_count
}
/// Skip up to count bytes. The actual number of bytes skipped is bounded by available().
pub fn skip(&mut self, count: u16) -> u16 {
let bounded_count = self.available().min(count);
self.ptr = self.ptr.wrapping_add(bounded_count);
self.size -= bounded_count;
bounded_count
}
/// Return ownership of the portion of the RX buffer that has already been read back to the
/// chip and issue the next receive command.
pub fn commit(mut self) -> Result<(), SpiBus::Error> {
self.sock.set_rx_read_pointer(self.bus, self.ptr)?;
self.sock.command(self.bus, Command::Receive)?;
Ok(())
}
/// Return ownership of the portion of the RX buffer that has already been read back to the
/// chip and issue the next receive command.
pub fn commit(mut self) -> Result<(), SpiBus::Error> {
self.sock.set_rx_read_pointer(self.bus, self.ptr)?;
self.sock.command(self.bus, Command::Receive)?;
Ok(())
}
}
pub(crate) struct TxCursor<'a, SpiBus>
where
SpiBus: Bus,
SpiBus: Bus,
{
sock: &'a Socket,
bus: &'a mut SpiBus,
ptr: u16,
size: u16,
sock: &'a Socket,
bus: &'a mut SpiBus,
ptr: u16,
size: u16,
}
impl<'a, SpiBus> TxCursor<'a, SpiBus>
where
SpiBus: Bus,
SpiBus: Bus,
{
pub fn new(sock: &'a Socket, bus: &'a mut SpiBus) -> Result<Self, SpiBus::Error> {
let size = sock.get_tx_free_size(bus)?;
let ptr = sock.get_tx_write_pointer(bus)?;
Ok(Self {
sock,
bus,
ptr,
size,
})
}
pub fn new(sock: &'a Socket, bus: &'a mut SpiBus) -> Result<Self, SpiBus::Error> {
let size = sock.get_tx_free_size(bus)?;
let ptr = sock.get_tx_write_pointer(bus)?;
Ok(Self {
sock,
bus,
ptr,
size,
})
}
#[inline]
pub fn available(&self) -> u16 {
self.size
}
#[inline]
pub fn available(&self) -> u16 {
self.size
}
/// Write all bytes in buf to the current TX buffer position and update the cursor position
/// and remaining size on success.
pub fn write(&mut self, buf: &[u8]) -> Result<u16, SpiBus::Error> {
if buf.is_empty() || buf.len() > self.available() as _ {
return Ok(0);
}
/// Write all bytes in buf to the current TX buffer position and update the cursor position
/// and remaining size on success.
pub fn write(&mut self, buf: &[u8]) -> Result<u16, SpiBus::Error> {
if buf.is_empty() || buf.len() > self.available() as _ {
return Ok(0);
}
let count = buf.len() as u16;
self.bus
.write_frame(self.ptr, &buf[..count as _])?;
self.ptr = self.ptr.wrapping_add(count);
self.size -= count;
Ok(count)
}
let count = buf.len() as u16;
self.bus.write_frame(self.ptr, &buf[..count as _])?;
self.ptr = self.ptr.wrapping_add(count);
self.size -= count;
Ok(count)
}
/// Pass ownership of the portion of the TX buffer that has already been written back to the
/// chip and issue the next send command.
pub fn commit(mut self) -> Result<(), SpiBus::Error> {
self.sock.set_tx_write_pointer(self.bus, self.ptr)?;
self.sock.command(self.bus, Command::Send)?;
Ok(())
}
/// Pass ownership of the portion of the TX buffer that has already been written back to the
/// chip and issue the next send command.
pub fn commit(mut self) -> Result<(), SpiBus::Error> {
self.sock.set_tx_write_pointer(self.bus, self.ptr)?;
self.sock.command(self.bus, Command::Send)?;
Ok(())
}
}

View file

@ -1,304 +1,293 @@
use bit_field::BitField;
use crate::bus::{Bus, FourWire};
use crate::host::Host;
use crate::net::Ipv4Addr;
use crate::socket::Socket;
use crate::uninitialized_device::UninitializedDevice;
use crate::{
register::{self, common::RetryTime},
MacAddress, Mode,
bus::{Bus, FourWire},
host::Host,
net::Ipv4Addr,
register::{self, common::RetryTime},
socket::Socket,
uninitialized_device::UninitializedDevice,
MacAddress, Mode,
};
#[derive(Debug, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum ResetError<E> {
SocketsNotReleased,
Other(E),
SocketsNotReleased,
Other(E),
}
impl<E> From<E> for ResetError<E> {
fn from(error: E) -> ResetError<E> {
ResetError::Other(error)
}
fn from(error: E) -> ResetError<E> {
ResetError::Other(error)
}
}
mod private {
pub trait Sealed {}
pub trait Sealed {}
impl<T: Sealed> Sealed for &'_ mut T {}
impl<T: Sealed> Sealed for &'_ mut T {}
}
pub trait State: private::Sealed {
fn socket(&mut self) -> Option<Socket>;
fn release_socket(&mut self, socket: Socket);
fn any_allocated(&self) -> bool;
fn socket(&mut self) -> Option<Socket>;
fn release_socket(&mut self, socket: Socket);
fn any_allocated(&self) -> bool;
}
#[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct DeviceState<HostImpl: Host> {
host: HostImpl,
sockets: u8,
host: HostImpl,
sockets: u8,
}
impl<HostImpl: Host> DeviceState<HostImpl> {
pub fn new(host: HostImpl) -> Self {
Self {
sockets: 0xFF,
host,
}
}
pub fn new(host: HostImpl) -> Self {
Self {
sockets: 0xFF,
host,
}
}
}
impl<HostImpl: Host> private::Sealed for DeviceState<HostImpl> {}
impl<HostImpl: Host> State for DeviceState<HostImpl> {
fn socket(&mut self) -> Option<Socket> {
for index in 0..8 {
if self.sockets.get_bit(index) {
self.sockets.set_bit(index, false);
return Some(Socket::new(index as u8));
}
}
None
}
fn socket(&mut self) -> Option<Socket> {
for index in 0..8 {
if self.sockets.get_bit(index) {
self.sockets.set_bit(index, false);
return Some(Socket::new(index as u8));
}
}
None
}
fn release_socket(&mut self, socket: Socket) {
self.sockets.set_bit(socket.index.into(), true);
}
fn release_socket(&mut self, socket: Socket) {
self.sockets.set_bit(socket.index.into(), true);
}
fn any_allocated(&self) -> bool {
self.sockets != 0xFF
}
fn any_allocated(&self) -> bool {
self.sockets != 0xFF
}
}
impl<T: State> State for &'_ mut T {
fn socket(&mut self) -> Option<Socket> {
T::socket(self)
}
fn socket(&mut self) -> Option<Socket> {
T::socket(self)
}
fn release_socket(&mut self, socket: Socket) {
T::release_socket(self, socket)
}
fn release_socket(&mut self, socket: Socket) {
T::release_socket(self, socket)
}
fn any_allocated(&self) -> bool {
T::any_allocated(self)
}
fn any_allocated(&self) -> bool {
T::any_allocated(self)
}
}
pub struct Device<SpiBus: Bus, StateImpl: State> {
pub(crate) bus: SpiBus,
state: StateImpl,
pub(crate) bus: SpiBus,
state: StateImpl,
}
impl<SpiBus: Bus, StateImpl: State> Device<SpiBus, StateImpl> {
pub(crate) fn new(bus: SpiBus, state: StateImpl) -> Self {
Device { bus, state }
}
pub(crate) fn new(bus: SpiBus, state: StateImpl) -> Self {
Device { bus, state }
}
pub fn get_state(&self) -> &StateImpl {
&self.state
}
pub fn get_state(&self) -> &StateImpl {
&self.state
}
pub fn reset(mut self) -> Result<UninitializedDevice<SpiBus>, ResetError<SpiBus::Error>> {
if self.state.any_allocated() {
Err(ResetError::SocketsNotReleased)
} else {
self.reset_device()?;
Ok(UninitializedDevice::new(self.bus))
}
}
pub fn reset(mut self) -> Result<UninitializedDevice<SpiBus>, ResetError<SpiBus::Error>> {
if self.state.any_allocated() {
Err(ResetError::SocketsNotReleased)
} else {
self.reset_device()?;
Ok(UninitializedDevice::new(self.bus))
}
}
pub fn release(self) -> (SpiBus, StateImpl) {
(self.bus, self.state)
}
pub fn release(self) -> (SpiBus, StateImpl) {
(self.bus, self.state)
}
pub fn take_socket(&mut self) -> Option<Socket> {
// TODO maybe return Future that resolves when release_socket invoked
self.state.socket()
}
pub fn take_socket(&mut self) -> Option<Socket> {
// TODO maybe return Future that resolves when release_socket invoked
self.state.socket()
}
pub fn release_socket(&mut self, socket: Socket) {
self.state.release_socket(socket)
}
pub fn release_socket(&mut self, socket: Socket) {
self.state.release_socket(socket)
}
pub fn gateway(&mut self) -> Result<Ipv4Addr, SpiBus::Error> {
let mut octets = [0u8; 4];
self.bus
.read_frame(register::COMMON + register::common::GATEWAY, &mut octets)?;
Ok(Ipv4Addr::from(octets))
}
pub fn gateway(&mut self) -> Result<Ipv4Addr, SpiBus::Error> {
let mut octets = [0u8; 4];
self.bus
.read_frame(register::COMMON + register::common::GATEWAY, &mut octets)?;
Ok(Ipv4Addr::from(octets))
}
pub fn subnet_mask(&mut self) -> Result<Ipv4Addr, SpiBus::Error> {
let mut octets = [0u8; 4];
self.bus
.read_frame(register::COMMON + register::common::SUBNET_MASK, &mut octets)?;
Ok(Ipv4Addr::from(octets))
}
pub fn subnet_mask(&mut self) -> Result<Ipv4Addr, SpiBus::Error> {
let mut octets = [0u8; 4];
self.bus.read_frame(
register::COMMON + register::common::SUBNET_MASK,
&mut octets,
)?;
Ok(Ipv4Addr::from(octets))
}
pub fn mac(&mut self) -> Result<MacAddress, SpiBus::Error> {
let mut mac = MacAddress::default();
self.bus
.read_frame(register::COMMON + register::common::MAC, &mut mac.octets)?;
Ok(mac)
}
pub fn mac(&mut self) -> Result<MacAddress, SpiBus::Error> {
let mut mac = MacAddress::default();
self.bus
.read_frame(register::COMMON + register::common::MAC, &mut mac.octets)?;
Ok(mac)
}
pub fn ip(&mut self) -> Result<Ipv4Addr, SpiBus::Error> {
let mut octets = [0u8; 4];
self.bus
.read_frame(register::COMMON + register::common::IP, &mut octets)?;
Ok(Ipv4Addr::from(octets))
}
pub fn ip(&mut self) -> Result<Ipv4Addr, SpiBus::Error> {
let mut octets = [0u8; 4];
self.bus
.read_frame(register::COMMON + register::common::IP, &mut octets)?;
Ok(Ipv4Addr::from(octets))
}
#[inline]
pub fn reset_device(&mut self) -> Result<(), SpiBus::Error> {
// Set RST common register of the w5500
let mode = [0b10000000];
self.bus
.write_frame(register::COMMON + register::common::MODE, &mode)
}
#[inline]
pub fn reset_device(&mut self) -> Result<(), SpiBus::Error> {
// Set RST common register of the w5500
let mode = [0b10000000];
self.bus
.write_frame(register::COMMON + register::common::MODE, &mode)
}
#[inline]
pub fn set_mode(&mut self, mode_options: Mode) -> Result<(), SpiBus::Error> {
self.bus.write_frame(
register::COMMON +
register::common::MODE,
&mode_options.to_register(),
)
}
#[inline]
pub fn set_mode(&mut self, mode_options: Mode) -> Result<(), SpiBus::Error> {
self.bus.write_frame(
register::COMMON + register::common::MODE,
&mode_options.to_register(),
)
}
#[inline]
pub fn set_rx_memory_size(&mut self, val: u8) -> Result<(), SpiBus::Error> {
self.bus.write_frame(
register::COMMON +
register::common::RX_MEMORY_SIZE,
&[val],
)
}
#[inline]
pub fn set_rx_memory_size(&mut self, val: u8) -> Result<(), SpiBus::Error> {
self.bus
.write_frame(register::COMMON + register::common::RX_MEMORY_SIZE, &[val])
}
#[inline]
pub fn set_tx_memory_size(&mut self, val: u8) -> Result<(), SpiBus::Error> {
self.bus.write_frame(
register::COMMON +
register::common::TX_MEMORY_SIZE,
&[val],
)
}
#[inline]
pub fn set_tx_memory_size(&mut self, val: u8) -> Result<(), SpiBus::Error> {
self.bus
.write_frame(register::COMMON + register::common::TX_MEMORY_SIZE, &[val])
}
#[inline]
pub fn get_rx_memory_size(&mut self) -> Result<u8, SpiBus::Error> {
let mut val = [0];
self.bus.read_frame(
register::COMMON +
register::common::RX_MEMORY_SIZE,
&mut val,
)?;
Ok(val[0])
}
#[inline]
pub fn get_rx_memory_size(&mut self) -> Result<u8, SpiBus::Error> {
let mut val = [0];
self.bus.read_frame(
register::COMMON + register::common::RX_MEMORY_SIZE,
&mut val,
)?;
Ok(val[0])
}
#[inline]
pub fn get_tx_memory_size(&mut self) -> Result<u8, SpiBus::Error> {
let mut val = [0];
self.bus.read_frame(
register::COMMON +
register::common::TX_MEMORY_SIZE,
&mut val,
)?;
Ok(val[0])
}
#[inline]
pub fn get_tx_memory_size(&mut self) -> Result<u8, SpiBus::Error> {
let mut val = [0];
self.bus.read_frame(
register::COMMON + register::common::TX_MEMORY_SIZE,
&mut val,
)?;
Ok(val[0])
}
/// Set a new value for the Retry Time-value Register.
///
/// RTR (Retry Time-value Register) [R/W] [0x0019 0x001A] [0x07D0]
///
/// # Example
///
/// ```
/// use w5500::register::common::RetryTime;
///
/// let default = RetryTime::from_millis(200);
/// assert_eq!(RetryTime::default(), default);
///
/// // E.g. 4000 (register) = 400ms
/// let four_hundred_ms = RetryTime::from_millis(400);
/// assert_eq!(four_hundred_ms.to_u16(), 4000);
/// ```
#[inline]
pub fn set_retry_timeout(&mut self, retry_time_value: RetryTime) -> Result<(), SpiBus::Error> {
self.bus.write_frame(
register::COMMON +
register::common::RETRY_TIME,
&retry_time_value.to_register(),
)?;
/// Set a new value for the Retry Time-value Register.
///
/// RTR (Retry Time-value Register) [R/W] [0x0019 0x001A] [0x07D0]
///
/// # Example
///
/// ```
/// use w5500::register::common::RetryTime;
///
/// let default = RetryTime::from_millis(200);
/// assert_eq!(RetryTime::default(), default);
///
/// // E.g. 4000 (register) = 400ms
/// let four_hundred_ms = RetryTime::from_millis(400);
/// assert_eq!(four_hundred_ms.to_u16(), 4000);
/// ```
#[inline]
pub fn set_retry_timeout(&mut self, retry_time_value: RetryTime) -> Result<(), SpiBus::Error> {
self.bus.write_frame(
register::COMMON + register::common::RETRY_TIME,
&retry_time_value.to_register(),
)?;
Ok(())
}
Ok(())
}
/// Get the currently set Retry Time-value Register.
///
/// RTR (Retry Time-value Register) [R/W] [0x0019 0x001A] [0x07D0]
///
/// E.g. 4000 = 400ms
#[inline]
pub fn current_retry_timeout(&mut self) -> Result<RetryTime, SpiBus::Error> {
let mut retry_time_register: [u8; 2] = [0, 0];
self.bus.read_frame(
register::COMMON+
register::common::RETRY_TIME,
&mut retry_time_register,
)?;
/// Get the currently set Retry Time-value Register.
///
/// RTR (Retry Time-value Register) [R/W] [0x0019 0x001A] [0x07D0]
///
/// E.g. 4000 = 400ms
#[inline]
pub fn current_retry_timeout(&mut self) -> Result<RetryTime, SpiBus::Error> {
let mut retry_time_register: [u8; 2] = [0, 0];
self.bus.read_frame(
register::COMMON + register::common::RETRY_TIME,
&mut retry_time_register,
)?;
Ok(RetryTime::from_register(retry_time_register))
}
Ok(RetryTime::from_register(retry_time_register))
}
/// Set a new value for the Retry Count register.
///
/// RCR (Retry Count Register) [R/W] [0x001B] [0x08]
///
/// For more details check out the rest of the datasheet documentation on the Retry count.
///
/// From datasheet:
///
/// RCR configures the number of time of retransmission. When retransmission occurs
/// as many as RCR+1, Timeout interrupt is issued (Sn_IR[TIMEOUT] = 1).
///
/// The timeout of W5500 can be configurable with RTR and RCR. W5500 has two kind
/// timeout such as Address Resolution Protocol (ARP) and TCP retransmission.
///
/// E.g. In case of errors it will retry for 7 times:
/// `RCR = 0x0007`
pub fn set_retry_count(&mut self, retry_count: u8) -> Result<(), SpiBus::Error> {
self.bus.write_frame(
register::COMMON+
register::common::RETRY_COUNT,
&[retry_count],
)?;
/// Set a new value for the Retry Count register.
///
/// RCR (Retry Count Register) [R/W] [0x001B] [0x08]
///
/// For more details check out the rest of the datasheet documentation on the Retry count.
///
/// From datasheet:
///
/// RCR configures the number of time of retransmission. When retransmission occurs
/// as many as RCR+1, Timeout interrupt is issued (Sn_IR[TIMEOUT] = 1).
///
/// The timeout of W5500 can be configurable with RTR and RCR. W5500 has two kind
/// timeout such as Address Resolution Protocol (ARP) and TCP retransmission.
///
/// E.g. In case of errors it will retry for 7 times:
/// `RCR = 0x0007`
pub fn set_retry_count(&mut self, retry_count: u8) -> Result<(), SpiBus::Error> {
self.bus.write_frame(
register::COMMON + register::common::RETRY_COUNT,
&[retry_count],
)?;
Ok(())
}
Ok(())
}
/// Get the current Retry Count value
///
/// RCR (Retry Count Register) [R/W] [0x001B] [0x08]
///
/// E.g. In case of errors it will retry for 7 times:
/// `RCR = 0x0007`
#[inline]
pub fn current_retry_count(&mut self) -> Result<u8, SpiBus::Error> {
let mut retry_count_register: [u8; 1] = [0];
self.bus.read_frame(
register::COMMON+
register::common::RETRY_COUNT,
&mut retry_count_register,
)?;
/// Get the current Retry Count value
///
/// RCR (Retry Count Register) [R/W] [0x001B] [0x08]
///
/// E.g. In case of errors it will retry for 7 times:
/// `RCR = 0x0007`
#[inline]
pub fn current_retry_count(&mut self) -> Result<u8, SpiBus::Error> {
let mut retry_count_register: [u8; 1] = [0];
self.bus.read_frame(
register::COMMON + register::common::RETRY_COUNT,
&mut retry_count_register,
)?;
Ok(retry_count_register[0])
}
Ok(retry_count_register[0])
}
pub fn deactivate(self) -> (SpiBus, InactiveDevice<StateImpl>) {
(self.bus, InactiveDevice(self.state))
}
pub fn deactivate(self) -> (SpiBus, InactiveDevice<StateImpl>) {
(self.bus, InactiveDevice(self.state))
}
}
#[derive(Debug)]
@ -306,15 +295,15 @@ impl<SpiBus: Bus, StateImpl: State> Device<SpiBus, StateImpl> {
pub struct InactiveDevice<StateImpl: State>(StateImpl);
impl<StateImpl: State> InactiveDevice<StateImpl> {
/// Activates the device by taking ownership
pub fn activate<SpiBus: Bus>(self, bus: SpiBus) -> Device<SpiBus, StateImpl> {
Device { bus, state: self.0 }
}
/// Activates the device by taking ownership
pub fn activate<SpiBus: Bus>(self, bus: SpiBus) -> Device<SpiBus, StateImpl> {
Device { bus, state: self.0 }
}
pub fn activate_ref<SpiBus: Bus>(&mut self, bus: SpiBus) -> Device<SpiBus, &mut StateImpl> {
Device {
bus,
state: &mut self.0,
}
}
pub fn activate_ref<SpiBus: Bus>(&mut self, bus: SpiBus) -> Device<SpiBus, &mut StateImpl> {
Device {
bus,
state: &mut self.0,
}
}
}

View file

@ -1,32 +1,30 @@
use crate::bus::Bus;
use crate::host::Host;
use crate::MacAddress;
use crate::{bus::Bus, host::Host, MacAddress};
#[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct Dhcp {
// settings: HostConfig,
// current: HostConfig,
// settings: HostConfig,
// current: HostConfig,
}
impl Dhcp {
pub fn new(_mac: MacAddress) -> Self {
// let settings = HostConfig {
// mac,
// ..HostConfig::default()
// };
Self {
// settings,
// current: HostConfig::default(),
}
}
pub fn new(_mac: MacAddress) -> Self {
// let settings = HostConfig {
// mac,
// ..HostConfig::default()
// };
Self {
// settings,
// current: HostConfig::default(),
}
}
}
impl Host for Dhcp {
/// Gets (if necessary) and sets the host settings on the chip
fn refresh<SpiBus: Bus>(&mut self, _bus: &mut SpiBus) -> Result<(), SpiBus::Error> {
// TODO actually negotiate settings from DHCP
// TODO figure out how should receive socket for DHCP negotiations
Ok(())
}
/// Gets (if necessary) and sets the host settings on the chip
fn refresh<SpiBus: Bus>(&mut self, _bus: &mut SpiBus) -> Result<(), SpiBus::Error> {
// TODO actually negotiate settings from DHCP
// TODO figure out how should receive socket for DHCP negotiations
Ok(())
}
}

View file

@ -1,39 +1,41 @@
use core::net::Ipv4Addr;
use crate::bus::Bus;
use crate::host::{Host, HostConfig};
use crate::MacAddress;
use crate::{
bus::Bus,
host::{Host, HostConfig},
MacAddress,
};
#[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct Manual {
is_setup: bool,
settings: HostConfig,
current: HostConfig,
is_setup: bool,
settings: HostConfig,
current: HostConfig,
}
impl Manual {
pub fn new(mac: MacAddress, ip: Ipv4Addr, gateway: Ipv4Addr, subnet: Ipv4Addr) -> Self {
Self {
is_setup: false,
settings: HostConfig {
mac,
ip,
gateway,
subnet,
},
current: HostConfig::default(),
}
}
pub fn new(mac: MacAddress, ip: Ipv4Addr, gateway: Ipv4Addr, subnet: Ipv4Addr) -> Self {
Self {
is_setup: false,
settings: HostConfig {
mac,
ip,
gateway,
subnet,
},
current: HostConfig::default(),
}
}
}
impl Host for Manual {
/// Gets (if necessary) and sets the host settings on the chip
fn refresh<SpiBus: Bus>(&mut self, bus: &mut SpiBus) -> Result<(), SpiBus::Error> {
if !self.is_setup {
Self::write_settings(bus, &mut self.current, &self.settings)?;
self.is_setup = true;
}
Ok(())
}
/// Gets (if necessary) and sets the host settings on the chip
fn refresh<SpiBus: Bus>(&mut self, bus: &mut SpiBus) -> Result<(), SpiBus::Error> {
if !self.is_setup {
Self::write_settings(bus, &mut self.current, &self.settings)?;
self.is_setup = true;
}
Ok(())
}
}

View file

@ -3,68 +3,65 @@ use core::net::Ipv4Addr;
mod dhcp;
mod manual;
pub use self::dhcp::Dhcp;
pub use self::manual::Manual;
use crate::bus::Bus;
use crate::register;
use crate::MacAddress;
pub use self::{dhcp::Dhcp, manual::Manual};
use crate::{bus::Bus, register, MacAddress};
#[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct HostConfig {
mac: MacAddress,
#[cfg_attr(feature = "defmt", defmt(Display2Format))]
ip: Ipv4Addr,
#[cfg_attr(feature = "defmt", defmt(Display2Format))]
gateway: Ipv4Addr,
#[cfg_attr(feature = "defmt", defmt(Display2Format))]
subnet: Ipv4Addr,
mac: MacAddress,
#[cfg_attr(feature = "defmt", defmt(Display2Format))]
ip: Ipv4Addr,
#[cfg_attr(feature = "defmt", defmt(Display2Format))]
gateway: Ipv4Addr,
#[cfg_attr(feature = "defmt", defmt(Display2Format))]
subnet: Ipv4Addr,
}
impl Default for HostConfig {
fn default() -> Self {
Self {
mac: MacAddress::default(),
ip: Ipv4Addr::UNSPECIFIED,
gateway: Ipv4Addr::UNSPECIFIED,
subnet: Ipv4Addr::UNSPECIFIED,
}
}
fn default() -> Self {
Self {
mac: MacAddress::default(),
ip: Ipv4Addr::UNSPECIFIED,
gateway: Ipv4Addr::UNSPECIFIED,
subnet: Ipv4Addr::UNSPECIFIED,
}
}
}
pub trait Host {
/// Gets (if necessary) and sets the host settings on the chip
fn refresh<SpiBus: Bus>(&mut self, bus: &mut SpiBus) -> Result<(), SpiBus::Error>;
/// Gets (if necessary) and sets the host settings on the chip
fn refresh<SpiBus: Bus>(&mut self, bus: &mut SpiBus) -> Result<(), SpiBus::Error>;
/// Write changed settings to chip
///
/// Will check all settings and write any new ones to the chip. Will update the settings returned by `current`
/// with any changes.
fn write_settings<SpiBus: Bus>(
bus: &mut SpiBus,
current: &mut HostConfig,
settings: &HostConfig,
) -> Result<(), SpiBus::Error> {
if settings.gateway != current.gateway {
let address = settings.gateway.octets();
bus.write_frame(register::COMMON + register::common::GATEWAY, &address)?;
current.gateway = settings.gateway;
}
if settings.subnet != current.subnet {
let address = settings.subnet.octets();
bus.write_frame(register::COMMON + register::common::SUBNET_MASK, &address)?;
current.subnet = settings.subnet;
}
if settings.mac != current.mac {
let address = settings.mac.octets;
bus.write_frame(register::COMMON + register::common::MAC, &address)?;
current.mac = settings.mac;
}
if settings.ip != current.ip {
let address = settings.ip.octets();
bus.write_frame(register::COMMON + register::common::IP, &address)?;
current.ip = settings.ip;
}
Ok(())
}
/// Write changed settings to chip
///
/// Will check all settings and write any new ones to the chip. Will update the settings returned by `current`
/// with any changes.
fn write_settings<SpiBus: Bus>(
bus: &mut SpiBus,
current: &mut HostConfig,
settings: &HostConfig,
) -> Result<(), SpiBus::Error> {
if settings.gateway != current.gateway {
let address = settings.gateway.octets();
bus.write_frame(register::COMMON + register::common::GATEWAY, &address)?;
current.gateway = settings.gateway;
}
if settings.subnet != current.subnet {
let address = settings.subnet.octets();
bus.write_frame(register::COMMON + register::common::SUBNET_MASK, &address)?;
current.subnet = settings.subnet;
}
if settings.mac != current.mac {
let address = settings.mac.octets;
bus.write_frame(register::COMMON + register::common::MAC, &address)?;
current.mac = settings.mac;
}
if settings.ip != current.ip {
let address = settings.ip.octets();
bus.write_frame(register::COMMON + register::common::IP, &address)?;
current.ip = settings.ip;
}
Ok(())
}
}

View file

@ -17,10 +17,10 @@ mod uninitialized_device;
#[doc(inline)]
pub use self::{
device::{Device, DeviceState},
host::{Dhcp, Host, HostConfig, Manual},
net::MacAddress,
uninitialized_device::{InitializeError, UninitializedDevice},
device::{Device, DeviceState},
host::{Dhcp, Host, HostConfig, Manual},
net::MacAddress,
uninitialized_device::{InitializeError, UninitializedDevice},
};
// TODO add better docs to all public items, add unit tests.
@ -32,12 +32,12 @@ pub use self::{
#[derive(Copy, Clone, Debug, PartialOrd, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum OnPingRequest {
/// 0: Disable Ping block
Respond = 0b00000000,
/// 1 : Enable Ping block
///
/// If the bit is 1, it blocks the response to a ping request.
Ignore = 0b00010000,
/// 0: Disable Ping block
Respond = 0b00000000,
/// 1 : Enable Ping block
///
/// If the bit is 1, it blocks the response to a ping request.
Ignore = 0b00010000,
}
/// Use [ConnectionType::PPoE] when talking
@ -46,72 +46,72 @@ pub enum OnPingRequest {
#[derive(Copy, Clone, Debug, PartialOrd, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum ConnectionType {
PPoE = 0b00001000,
Ethernet = 0b00000000,
PPoE = 0b00001000,
Ethernet = 0b00000000,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct Mode {
pub on_ping_request: OnPingRequest,
pub connection_type: ConnectionType,
pub on_ping_request: OnPingRequest,
pub connection_type: ConnectionType,
}
impl Mode {
pub fn to_register(self) -> [u8; 1] {
[self.to_u8()]
}
pub fn to_register(self) -> [u8; 1] {
[self.to_u8()]
}
pub fn to_u8(self) -> u8 {
let mut register = 0;
register |= self.on_ping_request as u8;
register |= self.connection_type as u8;
pub fn to_u8(self) -> u8 {
let mut register = 0;
register |= self.on_ping_request as u8;
register |= self.connection_type as u8;
register
}
register
}
}
impl Default for Mode {
fn default() -> Self {
Self {
on_ping_request: OnPingRequest::Respond,
connection_type: ConnectionType::Ethernet,
}
}
fn default() -> Self {
Self {
on_ping_request: OnPingRequest::Respond,
connection_type: ConnectionType::Ethernet,
}
}
}
#[cfg(test)]
mod test {
use crate::Mode;
use crate::Mode;
#[test]
fn test_mode_register() {
let ping_respond_and_force_arp = Mode {
// Bit: 7 Reset (RST) should be 0
// Bit: 6 reserved
// Bit: 5 reserved
// Bit: 4 should be 0 - Disable Ping Block Mode
on_ping_request: crate::OnPingRequest::Respond,
// Bit: 3 should be 0 - PPoE disabled
connection_type: crate::ConnectionType::Ethernet,
// Bit: 2 reserved
// Bit: 1 address auto-increment should be 0
// Bit: 0 indirect bus I/F mode should be 0
};
assert_eq!(0b0000_0000, ping_respond_and_force_arp.to_u8());
#[test]
fn test_mode_register() {
let ping_respond_and_force_arp = Mode {
// Bit: 7 Reset (RST) should be 0
// Bit: 6 reserved
// Bit: 5 reserved
// Bit: 4 should be 0 - Disable Ping Block Mode
on_ping_request: crate::OnPingRequest::Respond,
// Bit: 3 should be 0 - PPoE disabled
connection_type: crate::ConnectionType::Ethernet,
// Bit: 2 reserved
// Bit: 1 address auto-increment should be 0
// Bit: 0 indirect bus I/F mode should be 0
};
assert_eq!(0b0000_0000, ping_respond_and_force_arp.to_u8());
let all_enabled = Mode {
// Bit: 7 Reset (RST) should be 0
// Bit: 6 reserved
// Bit: 5 reserved
// Bit: 4 should be 0 - Disable Ping Block Mode
on_ping_request: crate::OnPingRequest::Respond,
// Bit: 3 should be 1 - PPoE enable
connection_type: crate::ConnectionType::PPoE,
// Bit: 2 reserved
// Bit: 1 address auto-increment should be 0
// Bit: 0 indirect bus I/F mode should be 0
};
assert_eq!(0b0000_1000, all_enabled.to_u8());
}
let all_enabled = Mode {
// Bit: 7 Reset (RST) should be 0
// Bit: 6 reserved
// Bit: 5 reserved
// Bit: 4 should be 0 - Disable Ping Block Mode
on_ping_request: crate::OnPingRequest::Respond,
// Bit: 3 should be 1 - PPoE enable
connection_type: crate::ConnectionType::PPoE,
// Bit: 2 reserved
// Bit: 1 address auto-increment should be 0
// Bit: 0 indirect bus I/F mode should be 0
};
assert_eq!(0b0000_1000, all_enabled.to_u8());
}
}

View file

@ -20,95 +20,95 @@ pub use core::net::Ipv4Addr;
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Hash, Default)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct MacAddress {
/// Octets of the MAC address.
pub octets: [u8; 6],
/// Octets of the MAC address.
pub octets: [u8; 6],
}
impl MacAddress {
/// Creates a new EUI-48 MAC address from six eight-bit octets.
///
/// The result will represent the EUI-48 MAC address
/// `a`:`b`:`c`:`d`:`e`:`f`.
///
/// # Examples
///
/// ```
/// use w5500::MacAddress;
///
/// let addr = MacAddress::new(0x00, 0x00, 0x5E, 0x00, 0x00, 0x00);
/// ```
#[allow(clippy::many_single_char_names)]
pub const fn new(a: u8, b: u8, c: u8, d: u8, e: u8, f: u8) -> MacAddress {
MacAddress {
octets: [a, b, c, d, e, f],
}
}
/// Creates a new EUI-48 MAC address from six eight-bit octets.
///
/// The result will represent the EUI-48 MAC address
/// `a`:`b`:`c`:`d`:`e`:`f`.
///
/// # Examples
///
/// ```
/// use w5500::MacAddress;
///
/// let addr = MacAddress::new(0x00, 0x00, 0x5E, 0x00, 0x00, 0x00);
/// ```
#[allow(clippy::many_single_char_names)]
pub const fn new(a: u8, b: u8, c: u8, d: u8, e: u8, f: u8) -> MacAddress {
MacAddress {
octets: [a, b, c, d, e, f],
}
}
/// Returns the six eight-bit integers that make up this address.
///
/// # Examples
///
/// ```
/// use w5500::MacAddress;
///
/// let addr = MacAddress::new(13, 12, 11, 10, 15, 14);
/// assert_eq!([13u8, 12u8, 11u8, 10u8, 15u8, 14u8], addr.octets());
/// ```
pub const fn octets(&self) -> [u8; 6] {
[
self.octets[0],
self.octets[1],
self.octets[2],
self.octets[3],
self.octets[4],
self.octets[5],
]
}
/// Returns the six eight-bit integers that make up this address.
///
/// # Examples
///
/// ```
/// use w5500::MacAddress;
///
/// let addr = MacAddress::new(13, 12, 11, 10, 15, 14);
/// assert_eq!([13u8, 12u8, 11u8, 10u8, 15u8, 14u8], addr.octets());
/// ```
pub const fn octets(&self) -> [u8; 6] {
[
self.octets[0],
self.octets[1],
self.octets[2],
self.octets[3],
self.octets[4],
self.octets[5],
]
}
/// An EUI-48 MAC address representing an unspecified address:
/// 00:00:00:00:00:00
///
/// # Examples
///
/// ```
/// use w5500::MacAddress;
///
/// let addr = MacAddress::UNSPECIFIED;
/// assert_eq!(addr, MacAddress::new(0x00, 0x00, 0x00, 0x00, 0x00, 0x00));
/// ```
pub const UNSPECIFIED: Self = MacAddress::new(0, 0, 0, 0, 0, 0);
/// An EUI-48 MAC address representing an unspecified address:
/// 00:00:00:00:00:00
///
/// # Examples
///
/// ```
/// use w5500::MacAddress;
///
/// let addr = MacAddress::UNSPECIFIED;
/// assert_eq!(addr, MacAddress::new(0x00, 0x00, 0x00, 0x00, 0x00, 0x00));
/// ```
pub const UNSPECIFIED: Self = MacAddress::new(0, 0, 0, 0, 0, 0);
}
impl From<[u8; 6]> for MacAddress {
/// Creates an `Ipv4Addr` from a six element byte array.
///
/// # Examples
///
/// ```
/// use w5500::MacAddress;
///
/// let addr = MacAddress::from([13u8, 12u8, 11u8, 10u8, 15u8, 14u8]);
/// assert_eq!(MacAddress::new(13, 12, 11, 10, 15, 14), addr);
/// ```
fn from(octets: [u8; 6]) -> MacAddress {
MacAddress::new(
octets[0], octets[1], octets[2], octets[3], octets[4], octets[5],
)
}
/// Creates an `Ipv4Addr` from a six element byte array.
///
/// # Examples
///
/// ```
/// use w5500::MacAddress;
///
/// let addr = MacAddress::from([13u8, 12u8, 11u8, 10u8, 15u8, 14u8]);
/// assert_eq!(MacAddress::new(13, 12, 11, 10, 15, 14), addr);
/// ```
fn from(octets: [u8; 6]) -> MacAddress {
MacAddress::new(
octets[0], octets[1], octets[2], octets[3], octets[4], octets[5],
)
}
}
impl ::core::fmt::Display for MacAddress {
/// String formatter for MacAddress addresses.
fn fmt(&self, fmt: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
write!(
fmt,
"{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}",
self.octets[0],
self.octets[1],
self.octets[2],
self.octets[3],
self.octets[4],
self.octets[5],
)
}
/// String formatter for MacAddress addresses.
fn fmt(&self, fmt: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
write!(
fmt,
"{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}",
self.octets[0],
self.octets[1],
self.octets[2],
self.octets[3],
self.octets[4],
self.octets[5],
)
}
}

View file

@ -4,121 +4,114 @@ use crate::{bus::Bus, register, socket::Socket, uninitialized_device::Initialize
#[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct RawDevice<SpiBus: Bus> {
bus: SpiBus,
raw_socket: Socket,
bus: SpiBus,
raw_socket: Socket,
}
impl<SpiBus: Bus> RawDevice<SpiBus> {
/// Create the raw device.
///
/// # Note
/// The device is configured with MAC filtering enabled.
///
/// # Args
/// * `bus` - The bus to communicate with the device.
pub(crate) fn new(mut bus: SpiBus) -> Result<Self, InitializeError<SpiBus::Error>> {
// Set the raw socket to 16KB RX/TX buffer space.
let raw_socket = Socket::new(0);
/// Create the raw device.
///
/// # Note
/// The device is configured with MAC filtering enabled.
///
/// # Args
/// * `bus` - The bus to communicate with the device.
pub(crate) fn new(mut bus: SpiBus) -> Result<Self, InitializeError<SpiBus::Error>> {
// Set the raw socket to 16KB RX/TX buffer space.
let raw_socket = Socket::new(0);
// Configure the chip in MACRAW mode with MAC filtering.
let mode: u8 = (1 << 6) | // MAC address filtering
(register::socketn::Protocol::MacRaw as u8);
// Configure the chip in MACRAW mode with MAC filtering.
let mode: u8 = (1 << 6) | // MAC address filtering
(register::socketn::Protocol::MacRaw as u8);
bus.write_frame(raw_socket.register() + register::socketn::MODE, &[mode])?;
raw_socket.command(&mut bus, register::socketn::Command::Open)?;
bus.write_frame(raw_socket.register() + register::socketn::MODE, &[mode])?;
raw_socket.command(&mut bus, register::socketn::Command::Open)?;
Ok(Self { bus, raw_socket })
}
Ok(Self { bus, raw_socket })
}
/// Enable one or more interrupts
pub fn enable_interrupts(&mut self) -> Result<(), SpiBus::Error> {
self.bus.write_frame(
register::COMMON +
register::common::INTERRUPT_MASK,
&[1],
)?;
Ok(())
}
/// Enable one or more interrupts
pub fn enable_interrupts(&mut self) -> Result<(), SpiBus::Error> {
self.bus
.write_frame(register::COMMON + register::common::INTERRUPT_MASK, &[1])?;
Ok(())
}
/// Clear pending interrupts
///
/// If using RTIC or similar, this should be called from the
/// interrupt handler. If not (i.e., if there's concern that this
/// use of the SPI bus will clobber someone else's use), then you
/// can mask the interrupt *at microcontroller level* in the
/// interrupt handler, then call this from thread mode before
/// unmasking again.
pub fn clear_interrupts(&mut self) -> Result<(), SpiBus::Error> {
self.raw_socket
.reset_interrupt(&mut self.bus, register::socketn::Interrupt::All)
}
/// Clear pending interrupts
///
/// If using RTIC or similar, this should be called from the
/// interrupt handler. If not (i.e., if there's concern that this
/// use of the SPI bus will clobber someone else's use), then you
/// can mask the interrupt *at microcontroller level* in the
/// interrupt handler, then call this from thread mode before
/// unmasking again.
pub fn clear_interrupts(&mut self) -> Result<(), SpiBus::Error> {
self.raw_socket
.reset_interrupt(&mut self.bus, register::socketn::Interrupt::All)
}
/// Disable all interrupts
///
pub fn disable_interrupts(&mut self) -> Result<(), SpiBus::Error> {
self.bus.write_frame(
register::COMMON +
register::common::INTERRUPT_MASK,
&[0],
)?;
Ok(())
}
/// Disable all interrupts
pub fn disable_interrupts(&mut self) -> Result<(), SpiBus::Error> {
self.bus
.write_frame(register::COMMON + register::common::INTERRUPT_MASK, &[0])?;
Ok(())
}
/// Read an ethernet frame from the device.
///
/// # Args
/// * `frame` - The location to store the received frame
///
/// # Returns
/// The number of bytes read into the provided frame buffer.
pub fn read_frame(&mut self, frame: &mut [u8]) -> Result<usize, SpiBus::Error> {
let mut rx_cursor = crate::cursor::RxCursor::new(&self.raw_socket, &mut self.bus)?;
/// Read an ethernet frame from the device.
///
/// # Args
/// * `frame` - The location to store the received frame
///
/// # Returns
/// The number of bytes read into the provided frame buffer.
pub fn read_frame(&mut self, frame: &mut [u8]) -> Result<usize, SpiBus::Error> {
let mut rx_cursor = crate::cursor::RxCursor::new(&self.raw_socket, &mut self.bus)?;
// Check if there is anything to receive.
if rx_cursor.available() == 0 {
return Ok(0);
}
// Check if there is anything to receive.
if rx_cursor.available() == 0 {
return Ok(0);
}
// The W5500 specifies the size of the received ethernet frame in the first two bytes.
// Refer to https://forum.wiznet.io/t/topic/979/2 for more information.
let expected_frame_size = {
let mut frame_bytes = [0u8; 2];
assert!(rx_cursor.read(&mut frame_bytes[..])? == 2);
// The W5500 specifies the size of the received ethernet frame in the first two bytes.
// Refer to https://forum.wiznet.io/t/topic/979/2 for more information.
let expected_frame_size = {
let mut frame_bytes = [0u8; 2];
assert!(rx_cursor.read(&mut frame_bytes[..])? == 2);
u16::from_be_bytes(frame_bytes).saturating_sub(2)
};
u16::from_be_bytes(frame_bytes).saturating_sub(2)
};
let received_frame_size = rx_cursor.read_upto(frame, expected_frame_size)?;
if received_frame_size < expected_frame_size {
rx_cursor.skip(expected_frame_size - received_frame_size);
}
let received_frame_size = rx_cursor.read_upto(frame, expected_frame_size)?;
if received_frame_size < expected_frame_size {
rx_cursor.skip(expected_frame_size - received_frame_size);
}
rx_cursor.commit()?;
Ok(received_frame_size as _)
}
rx_cursor.commit()?;
Ok(received_frame_size as _)
}
/// Write an ethernet frame to the device.
///
/// # Args
/// * `frame` - The ethernet frame to transmit.
///
/// # Returns
/// The number of bytes successfully transmitted from the provided buffer.
pub fn write_frame(&mut self, frame: &[u8]) -> Result<usize, SpiBus::Error> {
// Reset the transmission complete flag, we'll wait on it later.
self.raw_socket
.reset_interrupt(&mut self.bus, register::socketn::Interrupt::SendOk)?;
/// Write an ethernet frame to the device.
///
/// # Args
/// * `frame` - The ethernet frame to transmit.
///
/// # Returns
/// The number of bytes successfully transmitted from the provided buffer.
pub fn write_frame(&mut self, frame: &[u8]) -> Result<usize, SpiBus::Error> {
// Reset the transmission complete flag, we'll wait on it later.
self.raw_socket
.reset_interrupt(&mut self.bus, register::socketn::Interrupt::SendOk)?;
let mut tx_cursor = crate::cursor::TxCursor::new(&self.raw_socket, &mut self.bus)?;
let count = tx_cursor.write(frame)?;
tx_cursor.commit()?;
let mut tx_cursor = crate::cursor::TxCursor::new(&self.raw_socket, &mut self.bus)?;
let count = tx_cursor.write(frame)?;
tx_cursor.commit()?;
// Wait for the socket transmission to complete.
while !self
.raw_socket
.has_interrupt(&mut self.bus, register::socketn::Interrupt::SendOk)?
{}
// Wait for the socket transmission to complete.
while !self
.raw_socket
.has_interrupt(&mut self.bus, register::socketn::Interrupt::SendOk)?
{}
Ok(count as _)
}
Ok(count as _)
}
}

View file

@ -3,299 +3,298 @@
// TODO change from u8 to a custom struct implementing a trait.
pub const COMMON: u16 = 0;
pub mod common {
use bit_field::BitArray;
use bit_field::BitArray;
pub const MODE: u16 = 0x0;
pub const MODE: u16 = 0x0;
/// Register: GAR (Gateway IP Address Register) [R/W] [0x0001 0x0004] [0x00]
pub const GATEWAY: u16 = 0x01;
/// Register: GAR (Gateway IP Address Register) [R/W] [0x0001 0x0004] [0x00]
pub const GATEWAY: u16 = 0x01;
/// Register: SUBR (Subnet Mask Register) [R/W] [0x0005 0x0008] [0x00]
pub const SUBNET_MASK: u16 = 0x05;
/// Register: SUBR (Subnet Mask Register) [R/W] [0x0005 0x0008] [0x00]
pub const SUBNET_MASK: u16 = 0x05;
/// Register: SHAR (Source Hardware Address Register) [R/W] [0x0009 0x000E] [0x00]
pub const MAC: u16 = 0x09;
/// Register: SHAR (Source Hardware Address Register) [R/W] [0x0009 0x000E] [0x00]
pub const MAC: u16 = 0x09;
/// Register: SIPR (Source IP Address Register) [R/W] [0x000F 0x0012] [0x00]
pub const IP: u16 = 0x0F;
/// Register: SIPR (Source IP Address Register) [R/W] [0x000F 0x0012] [0x00]
pub const IP: u16 = 0x0F;
/// Register: IMR (Interrupt Mask Register) [R/W] [0x0016 0x001A] [0x07D0]
pub const INTERRUPT_MASK: u16 = 0x16;
/// Register: IMR (Interrupt Mask Register) [R/W] [0x0016 0x001A] [0x07D0]
pub const INTERRUPT_MASK: u16 = 0x16;
/// Register: RTR (Retry Time-value Register) [R/W] [0x0019 0x001A] [0x07D0]
pub const RETRY_TIME: u16 = 0x17;
/// Register: RTR (Retry Time-value Register) [R/W] [0x0019 0x001A] [0x07D0]
pub const RETRY_TIME: u16 = 0x17;
/// Register: RCR (Retry Count Register) [R/W] [0x001B] [0x08]
pub const RETRY_COUNT: u16 = 0x19;
/// Register: RCR (Retry Count Register) [R/W] [0x001B] [0x08]
pub const RETRY_COUNT: u16 = 0x19;
/// Register: RCR (Retry Count Register) [R/W] [0x001B] [0x08]
pub const RX_MEMORY_SIZE: u16 = 0x1A;
/// Register: RCR (Retry Count Register) [R/W] [0x001B] [0x08]
pub const RX_MEMORY_SIZE: u16 = 0x1A;
/// Register: RCR (Retry Count Register) [R/W] [0x001B] [0x08]
pub const TX_MEMORY_SIZE: u16 = 0x1B;
/// Register: RCR (Retry Count Register) [R/W] [0x001B] [0x08]
pub const TX_MEMORY_SIZE: u16 = 0x1B;
/// A Retry Time-value
///
/// RTR (Retry Time-value Register) [R/W] [0x0019 0x001A] [0x07D0]
///
/// From datasheet:
///
/// RTR configures the retransmission timeout period. The unit of timeout period is
/// 100us and the default of RTR is 0x07D0 or 2000. And so the default timeout period
/// is 200ms(100us X 2000).
/// During the time configured by RTR, W5500 waits for the peer response to the packet
/// that is transmitted by Sn_CR(CONNECT, DISCON, CLOSE, SEND, SEND_MAC, SEND_KEEP
/// command). If the peer does not respond within the RTR time, W5500 retransmits the
/// packet or issues timeout.
///
///
/// > Ex) When timeout-period is set as 400ms, RTR = (400ms / 1ms) X 10 = 4000(0x0FA0)
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct RetryTime(pub(crate) u16);
/// A Retry Time-value
///
/// RTR (Retry Time-value Register) [R/W] [0x0019 0x001A] [0x07D0]
///
/// From datasheet:
///
/// RTR configures the retransmission timeout period. The unit of timeout period is
/// 100us and the default of RTR is 0x07D0 or 2000. And so the default timeout period
/// is 200ms(100us X 2000).
/// During the time configured by RTR, W5500 waits for the peer response to the packet
/// that is transmitted by Sn_CR(CONNECT, DISCON, CLOSE, SEND, SEND_MAC, SEND_KEEP
/// command). If the peer does not respond within the RTR time, W5500 retransmits the
/// packet or issues timeout.
///
///
/// > Ex) When timeout-period is set as 400ms, RTR = (400ms / 1ms) X 10 = 4000(0x0FA0)
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct RetryTime(pub(crate) u16);
impl RetryTime {
#[inline]
pub fn to_u16(&self) -> u16 {
self.0
}
impl RetryTime {
#[inline]
pub fn to_u16(&self) -> u16 {
self.0
}
#[inline]
pub fn to_register(&self) -> [u8; 2] {
self.0.to_be_bytes()
}
#[inline]
pub fn to_register(&self) -> [u8; 2] {
self.0.to_be_bytes()
}
#[inline]
pub fn from_register(register: [u8; 2]) -> Self {
Self(u16::from_be_bytes(register))
}
#[inline]
pub fn from_register(register: [u8; 2]) -> Self {
Self(u16::from_be_bytes(register))
}
#[inline]
pub fn from_millis(milliseconds: u16) -> Self {
Self(milliseconds * 10)
}
#[inline]
pub fn from_millis(milliseconds: u16) -> Self {
Self(milliseconds * 10)
}
#[inline]
pub fn to_millis(&self) -> u16 {
self.0 / 10
}
}
#[inline]
pub fn to_millis(&self) -> u16 {
self.0 / 10
}
}
impl Default for RetryTime {
fn default() -> Self {
Self::from_millis(200)
}
}
impl Default for RetryTime {
fn default() -> Self {
Self::from_millis(200)
}
}
}
pub mod socketn {
use derive_try_from_primitive::TryFromPrimitive;
use derive_try_from_primitive::TryFromPrimitive;
/// The Protocol mode
pub const MODE: u16 = 0x00;
/// 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,
IpRaw = 0b11,
MacRaw = 0b100,
PPoE = 0b101,
}
/// The protocol modes that can be used with the `w5500`
#[repr(u8)]
pub enum Protocol {
Closed = 0b00,
Tcp = 0b01,
Udp = 0b10,
IpRaw = 0b11,
MacRaw = 0b100,
PPoE = 0b101,
}
/// Socket n Command Register
///
/// `Sn_CR`
pub const COMMAND: u16 = 0x01;
/// 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,
/// 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,
}
/// [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 = 0b11111u8,
SendOk = 0b10000u8,
Timeout = 0b1000u8,
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 = 0b11111u8,
SendOk = 0b10000u8,
Timeout = 0b1000u8,
/// Receive data
///
/// bit 2, symbol `RECV`, `Sn_IR(RECV) Interrupt Mask`
Receive = 0b100u8,
/// 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,
/// Disconnect
///
/// bit 1, symbol `DISCON`, `Sn_IR(DISCON) Interrupt Mask`
Disconnect = 0b10u8,
/// Connect
///
/// bit 0, symbol `CON`, `Sn_IR(CON) Interrupt Mask`
Connect = 0b1u8,
}
/// Connect
///
/// bit 0, symbol `CON`, `Sn_IR(CON) Interrupt Mask`
Connect = 0b1u8,
}
pub const STATUS: u16 = 0x03;
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)]
pub enum Status {
Closed = 0x00,
Init = 0x13,
/// 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)]
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,
Udp = 0x22,
IpRaw = 0x32,
MacRaw = 0x42,
PPoE = 0x5f,
/// [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,
Udp = 0x22,
IpRaw = 0x32,
MacRaw = 0x42,
PPoE = 0x5f,
// Transient states.
SynSent = 0x15,
SynRecv = 0x16,
FinWait = 0x18,
Closing = 0x1a,
TimeWait = 0x1b,
LastAck = 0x1d,
Arp = 0x01,
}
// Transient states.
SynSent = 0x15,
SynRecv = 0x16,
FinWait = 0x18,
Closing = 0x1a,
TimeWait = 0x1b,
LastAck = 0x1d,
Arp = 0x01,
}
#[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
);
}
}
#[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 SOURCE_PORT: u16 = 0x04;
pub const DESTINATION_IP: u16 = 0x0C;
pub const DESTINATION_IP: u16 = 0x0C;
pub const DESTINATION_PORT: u16 = 0x10;
pub const DESTINATION_PORT: u16 = 0x10;
/// 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;
/// 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 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 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;
/// Socket n Received Size Register
///
/// `Sn_RX_RSR`
pub const RECEIVED_SIZE: u16 = 0x26;
pub const RX_DATA_READ_POINTER: u16 = 0x28;
pub const RX_DATA_READ_POINTER: u16 = 0x28;
#[cfg(test)]
mod tests {
use core::convert::TryFrom;
#[cfg(test)]
mod tests {
use core::convert::TryFrom;
use super::Status;
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);
}
}
#[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);
}
}
}

View file

@ -1,216 +1,209 @@
use core::convert::TryFrom;
use core::net::Ipv4Addr;
use core::{convert::TryFrom, net::Ipv4Addr};
use crate::bus::Bus;
use crate::register::{self, socketn};
use crate::{
bus::Bus,
register::{self, socketn},
};
#[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct Socket {
pub index: u8,
pub index: u8,
}
impl Socket {
/// 4 sockets available on the w5100
pub fn new(index: u8) -> Self {
Socket {
index,
}
}
/// 4 sockets available on the w5100
pub fn new(index: u8) -> Self {
Socket { index }
}
pub fn register(&self) -> u16 {
self.index as u16 * 0x100 + 0x400
}
pub fn register(&self) -> u16 {
self.index as u16 * 0x100 + 0x400
}
pub fn set_mode<SpiBus: Bus>(
&self,
bus: &mut SpiBus,
mode: socketn::Protocol,
) -> Result<(), SpiBus::Error> {
let mode = [mode as u8];
bus.write_frame(self.register() + socketn::MODE, &mode)?;
Ok(())
}
pub fn set_mode<SpiBus: Bus>(
&self,
bus: &mut SpiBus,
mode: socketn::Protocol,
) -> Result<(), SpiBus::Error> {
let mode = [mode as u8];
bus.write_frame(self.register() + socketn::MODE, &mode)?;
Ok(())
}
pub fn get_mode<SpiBus: Bus>(
&self,
bus: &mut SpiBus,
) -> Result<u8, SpiBus::Error> {
let mut mode = [0];
bus.write_frame(self.register() + socketn::MODE, &mut mode)?;
Ok(mode[0])
}
pub fn get_mode<SpiBus: Bus>(&self, bus: &mut SpiBus) -> Result<u8, SpiBus::Error> {
let mut mode = [0];
bus.write_frame(self.register() + socketn::MODE, &mode)?;
Ok(mode[0])
}
pub fn get_status<SpiBus: Bus>(&self, bus: &mut SpiBus) -> Result<u8, SpiBus::Error> {
let mut data = [0u8];
bus.read_frame(self.register() + socketn::STATUS, &mut data)?;
Ok(data[0])
}
pub fn get_status<SpiBus: Bus>(&self, bus: &mut SpiBus) -> Result<u8, SpiBus::Error> {
let mut data = [0u8];
bus.read_frame(self.register() + socketn::STATUS, &mut data)?;
Ok(data[0])
}
pub fn reset_interrupt<SpiBus: Bus>(
&self,
bus: &mut SpiBus,
code: socketn::Interrupt,
) -> Result<(), SpiBus::Error> {
let data = [code as u8];
bus.write_frame(self.register() + socketn::INTERRUPT, &data)?;
Ok(())
}
pub fn reset_interrupt<SpiBus: Bus>(
&self,
bus: &mut SpiBus,
code: socketn::Interrupt,
) -> Result<(), SpiBus::Error> {
let data = [code as u8];
bus.write_frame(self.register() + socketn::INTERRUPT, &data)?;
Ok(())
}
pub fn has_interrupt<SpiBus: Bus>(
&self,
bus: &mut SpiBus,
code: socketn::Interrupt,
) -> Result<bool, SpiBus::Error> {
let mut data = [0u8];
bus.read_frame(self.register() + socketn::INTERRUPT, &mut data)?;
pub fn has_interrupt<SpiBus: Bus>(
&self,
bus: &mut SpiBus,
code: socketn::Interrupt,
) -> Result<bool, SpiBus::Error> {
let mut data = [0u8];
bus.read_frame(self.register() + socketn::INTERRUPT, &mut data)?;
Ok(data[0] & code as u8 != 0)
}
Ok(data[0] & code as u8 != 0)
}
pub fn set_source_port<SpiBus: Bus>(
&self,
bus: &mut SpiBus,
port: u16,
) -> Result<(), SpiBus::Error> {
let data = port.to_be_bytes();
bus.write_frame(self.register() + socketn::SOURCE_PORT, &data)?;
Ok(())
}
pub fn set_source_port<SpiBus: Bus>(
&self,
bus: &mut SpiBus,
port: u16,
) -> Result<(), SpiBus::Error> {
let data = port.to_be_bytes();
bus.write_frame(self.register() + socketn::SOURCE_PORT, &data)?;
Ok(())
}
pub fn get_source_port<SpiBus: Bus>(
&self,
bus: &mut SpiBus,
) -> Result<u16, SpiBus::Error> {
let mut data = [0; 2];
bus.read_frame(self.register() + socketn::SOURCE_PORT, &mut data)?;
Ok(u16::from_be_bytes(data))
}
pub fn get_source_port<SpiBus: Bus>(&self, bus: &mut SpiBus) -> Result<u16, SpiBus::Error> {
let mut data = [0; 2];
bus.read_frame(self.register() + socketn::SOURCE_PORT, &mut data)?;
Ok(u16::from_be_bytes(data))
}
pub fn set_destination_ip<SpiBus: Bus>(
&self,
bus: &mut SpiBus,
ip: Ipv4Addr,
) -> Result<(), SpiBus::Error> {
let data = ip.octets();
bus.write_frame(self.register() + socketn::DESTINATION_IP, &data)?;
Ok(())
}
pub fn set_destination_ip<SpiBus: Bus>(
&self,
bus: &mut SpiBus,
ip: Ipv4Addr,
) -> Result<(), SpiBus::Error> {
let data = ip.octets();
bus.write_frame(self.register() + socketn::DESTINATION_IP, &data)?;
Ok(())
}
pub fn set_destination_port<SpiBus: Bus>(
&self,
bus: &mut SpiBus,
port: u16,
) -> Result<(), SpiBus::Error> {
let data = port.to_be_bytes();
bus.write_frame(self.register() + socketn::DESTINATION_PORT, &data)?;
Ok(())
}
pub fn set_destination_port<SpiBus: Bus>(
&self,
bus: &mut SpiBus,
port: u16,
) -> Result<(), SpiBus::Error> {
let data = port.to_be_bytes();
bus.write_frame(self.register() + socketn::DESTINATION_PORT, &data)?;
Ok(())
}
pub fn get_tx_read_pointer<SpiBus: Bus>(&self, bus: &mut SpiBus) -> Result<u16, SpiBus::Error> {
let mut data = [0u8; 2];
bus.read_frame(self.register() + socketn::TX_DATA_READ_POINTER, &mut data)?;
Ok(u16::from_be_bytes(data))
}
pub fn get_tx_read_pointer<SpiBus: Bus>(&self, bus: &mut SpiBus) -> Result<u16, SpiBus::Error> {
let mut data = [0u8; 2];
bus.read_frame(self.register() + socketn::TX_DATA_READ_POINTER, &mut data)?;
Ok(u16::from_be_bytes(data))
}
pub fn set_tx_read_pointer<SpiBus: Bus>(
&self,
bus: &mut SpiBus,
pointer: u16,
) -> Result<(), SpiBus::Error> {
let data = pointer.to_be_bytes();
bus.write_frame(self.register() + socketn::TX_DATA_READ_POINTER, &data)?;
Ok(())
}
pub fn set_tx_read_pointer<SpiBus: Bus>(
&self,
bus: &mut SpiBus,
pointer: u16,
) -> Result<(), SpiBus::Error> {
let data = pointer.to_be_bytes();
bus.write_frame(self.register() + socketn::TX_DATA_READ_POINTER, &data)?;
Ok(())
}
pub fn get_tx_write_pointer<SpiBus: Bus>(
&self,
bus: &mut SpiBus,
) -> Result<u16, SpiBus::Error> {
let mut data = [0u8; 2];
bus.read_frame(self.register() + socketn::TX_DATA_WRITE_POINTER, &mut data)?;
Ok(u16::from_be_bytes(data))
}
pub fn get_tx_write_pointer<SpiBus: Bus>(
&self,
bus: &mut SpiBus,
) -> Result<u16, SpiBus::Error> {
let mut data = [0u8; 2];
bus.read_frame(self.register() + socketn::TX_DATA_WRITE_POINTER, &mut data)?;
Ok(u16::from_be_bytes(data))
}
pub fn set_tx_write_pointer<SpiBus: Bus>(
&self,
bus: &mut SpiBus,
pointer: u16,
) -> Result<(), SpiBus::Error> {
let data = pointer.to_be_bytes();
bus.write_frame(self.register() + socketn::TX_DATA_WRITE_POINTER, &data)?;
Ok(())
}
pub fn set_tx_write_pointer<SpiBus: Bus>(
&self,
bus: &mut SpiBus,
pointer: u16,
) -> Result<(), SpiBus::Error> {
let data = pointer.to_be_bytes();
bus.write_frame(self.register() + socketn::TX_DATA_WRITE_POINTER, &data)?;
Ok(())
}
pub fn get_rx_read_pointer<SpiBus: Bus>(&self, bus: &mut SpiBus) -> Result<u16, SpiBus::Error> {
let mut data = [0u8; 2];
bus.read_frame(self.register() + socketn::RX_DATA_READ_POINTER, &mut data)?;
Ok(u16::from_be_bytes(data))
}
pub fn get_rx_read_pointer<SpiBus: Bus>(&self, bus: &mut SpiBus) -> Result<u16, SpiBus::Error> {
let mut data = [0u8; 2];
bus.read_frame(self.register() + socketn::RX_DATA_READ_POINTER, &mut data)?;
Ok(u16::from_be_bytes(data))
}
pub fn set_rx_read_pointer<SpiBus: Bus>(
&self,
bus: &mut SpiBus,
pointer: u16,
) -> Result<(), SpiBus::Error> {
let data = pointer.to_be_bytes();
bus.write_frame(self.register() + socketn::RX_DATA_READ_POINTER, &data)?;
Ok(())
}
pub fn set_rx_read_pointer<SpiBus: Bus>(
&self,
bus: &mut SpiBus,
pointer: u16,
) -> Result<(), SpiBus::Error> {
let data = pointer.to_be_bytes();
bus.write_frame(self.register() + socketn::RX_DATA_READ_POINTER, &data)?;
Ok(())
}
pub fn enable_interrupts<SpiBus: Bus>(
&self,
bus: &mut SpiBus,
) -> Result<(), SpiBus::Error> {
let mut data = [0];
bus.read_frame(register::COMMON + register::common::INTERRUPT_MASK, &mut data)?;
data[0] |= 1 << self.index;
bus.write_frame(register::COMMON + register::common::INTERRUPT_MASK, &data)?;
Ok(())
}
pub fn enable_interrupts<SpiBus: Bus>(&self, bus: &mut SpiBus) -> Result<(), SpiBus::Error> {
let mut data = [0];
bus.read_frame(
register::COMMON + register::common::INTERRUPT_MASK,
&mut data,
)?;
data[0] |= 1 << self.index;
bus.write_frame(register::COMMON + register::common::INTERRUPT_MASK, &data)?;
Ok(())
}
pub fn disable_interrupts<SpiBus: Bus>(
&self,
bus: &mut SpiBus,
) -> Result<(), SpiBus::Error> {
let mut data = [0];
bus.read_frame(register::COMMON + register::common::INTERRUPT_MASK, &mut data)?;
data[0] &= !(1 << self.index);
bus.write_frame(register::COMMON + register::common::INTERRUPT_MASK, &data)?;
Ok(())
}
pub fn disable_interrupts<SpiBus: Bus>(&self, bus: &mut SpiBus) -> Result<(), SpiBus::Error> {
let mut data = [0];
bus.read_frame(
register::COMMON + register::common::INTERRUPT_MASK,
&mut data,
)?;
data[0] &= !(1 << self.index);
bus.write_frame(register::COMMON + register::common::INTERRUPT_MASK, &data)?;
Ok(())
}
pub fn command<SpiBus: Bus>(
&self,
bus: &mut SpiBus,
command: socketn::Command,
) -> Result<(), SpiBus::Error> {
let data = [command as u8];
bus.write_frame(self.register() + socketn::COMMAND, &data)?;
Ok(())
}
pub fn command<SpiBus: Bus>(
&self,
bus: &mut SpiBus,
command: socketn::Command,
) -> Result<(), SpiBus::Error> {
let data = [command as u8];
bus.write_frame(self.register() + socketn::COMMAND, &data)?;
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 {
let mut sample_0 = [0u8; 2];
bus.read_frame(self.register() + socketn::RECEIVED_SIZE, &mut sample_0)?;
let mut sample_1 = [0u8; 2];
bus.read_frame(self.register() + socketn::RECEIVED_SIZE, &mut sample_1)?;
if sample_0 == sample_1 {
break Ok(u16::from_be_bytes(sample_0));
}
}
}
/// 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 {
let mut sample_0 = [0u8; 2];
bus.read_frame(self.register() + socketn::RECEIVED_SIZE, &mut sample_0)?;
let mut sample_1 = [0u8; 2];
bus.read_frame(self.register() + socketn::RECEIVED_SIZE, &mut sample_1)?;
if sample_0 == sample_1 {
break Ok(u16::from_be_bytes(sample_0));
}
}
}
/// 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))
}
/// 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))
}
}

View file

@ -1,260 +1,260 @@
use core::{
convert::TryFrom,
net::{IpAddr, Ipv4Addr, SocketAddr, SocketAddrV4},
convert::TryFrom,
net::{IpAddr, Ipv4Addr, SocketAddr, SocketAddrV4},
};
use embedded_nal::{nb, TcpClientStack, TcpError, TcpErrorKind};
use crate::{
bus::Bus,
device::{Device, State},
register::socketn,
socket::Socket,
bus::Bus,
device::{Device, State},
register::socketn,
socket::Socket,
};
#[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum TcpSocketError<E: core::fmt::Debug> {
NoMoreSockets,
NotConnected,
UnsupportedAddress,
Other(#[cfg_attr(feature = "defmt", defmt(Debug2Format))] E),
UnsupportedMode,
NoMoreSockets,
NotConnected,
UnsupportedAddress,
Other(#[cfg_attr(feature = "defmt", defmt(Debug2Format))] E),
UnsupportedMode,
}
impl<E: core::fmt::Debug> TcpError for TcpSocketError<E> {
fn kind(&self) -> TcpErrorKind {
match self {
TcpSocketError::NotConnected => TcpErrorKind::PipeClosed,
_ => TcpErrorKind::Other,
}
}
fn kind(&self) -> TcpErrorKind {
match self {
TcpSocketError::NotConnected => TcpErrorKind::PipeClosed,
_ => TcpErrorKind::Other,
}
}
}
impl<E: core::fmt::Debug> From<E> for TcpSocketError<E> {
fn from(e: E) -> Self {
TcpSocketError::Other(e)
}
fn from(e: E) -> Self {
TcpSocketError::Other(e)
}
}
#[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct TcpSocket {
socket: Socket,
socket: Socket,
}
impl TcpSocket {
fn reopen<B: Bus>(&mut self, bus: &mut B) -> Result<(), TcpSocketError<B::Error>> {
self.socket.command(bus, socketn::Command::Close)?;
self.socket.reset_interrupt(bus, socketn::Interrupt::All)?;
self.socket.set_mode(bus, socketn::Protocol::Tcp)?;
self.socket.enable_interrupts(bus)?;
fn reopen<B: Bus>(&mut self, bus: &mut B) -> Result<(), TcpSocketError<B::Error>> {
self.socket.command(bus, socketn::Command::Close)?;
self.socket.reset_interrupt(bus, socketn::Interrupt::All)?;
self.socket.set_mode(bus, socketn::Protocol::Tcp)?;
self.socket.enable_interrupts(bus)?;
self.socket.command(bus, socketn::Command::Open)?;
Ok(())
}
fn open<B: Bus>(
&mut self,
bus: &mut B,
local_port: u16,
) -> Result<(), TcpSocketError<B::Error>> {
self.socket.command(bus, socketn::Command::Close)?;
self.socket.reset_interrupt(bus, socketn::Interrupt::All)?;
self.socket.set_source_port(bus, local_port)?;
self.socket.set_mode(bus, socketn::Protocol::Tcp)?;
self.socket.enable_interrupts(bus)?;
self.socket.command(bus, socketn::Command::Open)?;
Ok(())
}
fn open<B: Bus>(
&mut self,
bus: &mut B,
local_port: u16,
) -> Result<(), TcpSocketError<B::Error>> {
self.socket.command(bus, socketn::Command::Close)?;
self.socket.reset_interrupt(bus, socketn::Interrupt::All)?;
self.socket.set_source_port(bus, local_port)?;
self.socket.set_mode(bus, socketn::Protocol::Tcp)?;
self.socket.enable_interrupts(bus)?;
self.socket.command(bus, socketn::Command::Open)?;
Ok(())
}
self.socket.command(bus, socketn::Command::Open)?;
Ok(())
}
fn socket_close<B: Bus>(&self, bus: &mut B) -> Result<(), TcpSocketError<B::Error>> {
self.socket.set_mode(bus, socketn::Protocol::Closed)?;
self.socket.command(bus, socketn::Command::Close)?;
Ok(())
}
fn socket_close<B: Bus>(&self, bus: &mut B) -> Result<(), TcpSocketError<B::Error>> {
self.socket.set_mode(bus, socketn::Protocol::Closed)?;
self.socket.command(bus, socketn::Command::Close)?;
Ok(())
}
fn socket_connect<B: Bus>(
&mut self,
bus: &mut B,
remote: SocketAddrV4,
) -> Result<(), TcpSocketError<B::Error>> {
// Ensure the socket is open and ready before we attempt to connect it.
match socketn::Status::try_from(self.socket.get_status(bus)?) {
// Happy case: Nothing to do.
Ok(socketn::Status::Init) => {}
fn socket_connect<B: Bus>(
&mut self,
bus: &mut B,
remote: SocketAddrV4,
) -> Result<(), TcpSocketError<B::Error>> {
// Ensure the socket is open and ready before we attempt to connect it.
match socketn::Status::try_from(self.socket.get_status(bus)?) {
// Happy case: Nothing to do.
Ok(socketn::Status::Init) => {}
// If the socket is in the wrong mode, we can't use it. The user needs to re-open it.
Err(_) | Ok(socketn::Status::MacRaw) | Ok(socketn::Status::Udp) => {
return Err(TcpSocketError::UnsupportedMode)
}
// If the socket is in the wrong mode, we can't use it. The user needs to re-open it.
Err(_) | Ok(socketn::Status::MacRaw) | Ok(socketn::Status::Udp) => {
return Err(TcpSocketError::UnsupportedMode)
}
// All other cases are transient TCP states. For these, we need to reset the TCP
// machinery to return to the INIT state.
Ok(_) => {
self.socket_close(bus)?;
self.reopen(bus)?;
}
}
// All other cases are transient TCP states. For these, we need to reset the TCP
// machinery to return to the INIT state.
Ok(_) => {
self.socket_close(bus)?;
self.reopen(bus)?;
}
}
// Write the remote port and IP
self.socket.set_destination_ip(bus, *remote.ip())?;
self.socket.set_destination_port(bus, remote.port())?;
// Write the remote port and IP
self.socket.set_destination_ip(bus, *remote.ip())?;
self.socket.set_destination_port(bus, remote.port())?;
// Connect the socket.
self.socket.command(bus, socketn::Command::Connect)?;
// Connect the socket.
self.socket.command(bus, socketn::Command::Connect)?;
// Wait for the socket to connect or encounter an error.
loop {
match socketn::Status::try_from(self.socket.get_status(bus)?) {
Ok(socketn::Status::Established) => return Ok(()),
// Wait for the socket to connect or encounter an error.
loop {
match socketn::Status::try_from(self.socket.get_status(bus)?) {
Ok(socketn::Status::Established) => return Ok(()),
// The socket is closed if a timeout (ARP or SYN-ACK) or if the TCP socket receives
// a RST packet. In this case, the client will need to re-attempt to connect.
// The socket is closed if a timeout (ARP or SYN-ACK) or if the TCP socket receives
// a RST packet. In this case, the client will need to re-attempt to connect.
// TODO: Due to limitations of the embedded-nal, we currently still return the
// socket (since we cannot inform the user of the connection failure). The returned
// socket will not actually be connected.
Ok(socketn::Status::Closed) => {
// For now, always return an open socket so that the user can re-connect with
// it in the future.
self.socket_close(bus)?;
return self.reopen(bus);
}
// TODO: Due to limitations of the embedded-nal, we currently still return the
// socket (since we cannot inform the user of the connection failure). The returned
// socket will not actually be connected.
Ok(socketn::Status::Closed) => {
// For now, always return an open socket so that the user can re-connect with
// it in the future.
self.socket_close(bus)?;
return self.reopen(bus);
}
// The socket is still in some transient state. Wait for it to connect or for the
// connection to fail.
_ => {}
}
}
}
// The socket is still in some transient state. Wait for it to connect or for the
// connection to fail.
_ => {}
}
}
}
fn socket_is_connected<B: Bus>(&self, bus: &mut B) -> Result<bool, TcpSocketError<B::Error>> {
Ok(self.socket.get_status(bus)? == socketn::Status::Established as u8)
}
fn socket_is_connected<B: Bus>(&self, bus: &mut B) -> Result<bool, TcpSocketError<B::Error>> {
Ok(self.socket.get_status(bus)? == socketn::Status::Established as u8)
}
fn socket_send<B: Bus>(
&mut self,
bus: &mut B,
data: &[u8],
) -> Result<usize, TcpSocketError<B::Error>> {
if !self.socket_is_connected(bus)? {
return Err(TcpSocketError::NotConnected);
}
fn socket_send<B: Bus>(
&mut self,
bus: &mut B,
data: &[u8],
) -> Result<usize, TcpSocketError<B::Error>> {
if !self.socket_is_connected(bus)? {
return Err(TcpSocketError::NotConnected);
}
let max_size = self.socket.get_tx_free_size(bus)? as usize;
let max_size = self.socket.get_tx_free_size(bus)? as usize;
let write_data = if data.len() < max_size {
data
} else {
&data[..max_size]
};
let write_data = if data.len() < max_size {
data
} else {
&data[..max_size]
};
// Append the data to the write buffer after the current write pointer.
let write_pointer = self.socket.get_tx_write_pointer(bus)?;
// Append the data to the write buffer after the current write pointer.
let write_pointer = self.socket.get_tx_write_pointer(bus)?;
// Write data into the buffer and update the writer pointer.
bus.write_frame(write_pointer, write_data)?;
self.socket
.set_tx_write_pointer(bus, write_pointer.wrapping_add(write_data.len() as u16))?;
// Write data into the buffer and update the writer pointer.
bus.write_frame(write_pointer, write_data)?;
self.socket
.set_tx_write_pointer(bus, write_pointer.wrapping_add(write_data.len() as u16))?;
// Send the data.
self.socket.command(bus, socketn::Command::Send)?;
// Send the data.
self.socket.command(bus, socketn::Command::Send)?;
// Wait until the send command completes.
while !self.socket.has_interrupt(bus, socketn::Interrupt::SendOk)? {}
self.socket
.reset_interrupt(bus, socketn::Interrupt::SendOk)?;
// Wait until the send command completes.
while !self.socket.has_interrupt(bus, socketn::Interrupt::SendOk)? {}
self.socket
.reset_interrupt(bus, socketn::Interrupt::SendOk)?;
Ok(write_data.len())
}
Ok(write_data.len())
}
fn socket_receive<B: Bus>(
&mut self,
bus: &mut B,
data: &mut [u8],
) -> Result<usize, TcpSocketError<B::Error>> {
if !self.socket_is_connected(bus)? {
return Err(TcpSocketError::NotConnected);
}
fn socket_receive<B: Bus>(
&mut self,
bus: &mut B,
data: &mut [u8],
) -> Result<usize, TcpSocketError<B::Error>> {
if !self.socket_is_connected(bus)? {
return Err(TcpSocketError::NotConnected);
}
// Check if we've received data.
if !self
.socket
.has_interrupt(bus, socketn::Interrupt::Receive)?
{
return Ok(0);
}
// Check if we've received data.
if !self
.socket
.has_interrupt(bus, socketn::Interrupt::Receive)?
{
return Ok(0);
}
let rx_size = self.socket.get_receive_size(bus)? as usize;
let rx_size = self.socket.get_receive_size(bus)? as usize;
let read_buffer = if rx_size > data.len() {
data
} else {
&mut data[..rx_size]
};
let read_buffer = if rx_size > data.len() {
data
} else {
&mut data[..rx_size]
};
// Read from the RX ring buffer.
let read_pointer = self.socket.get_rx_read_pointer(bus)?;
bus.read_frame(read_pointer, read_buffer)?;
self.socket
.set_rx_read_pointer(bus, read_pointer.wrapping_add(read_buffer.len() as u16))?;
// Read from the RX ring buffer.
let read_pointer = self.socket.get_rx_read_pointer(bus)?;
bus.read_frame(read_pointer, read_buffer)?;
self.socket
.set_rx_read_pointer(bus, read_pointer.wrapping_add(read_buffer.len() as u16))?;
// Register the reception as complete.
self.socket.command(bus, socketn::Command::Receive)?;
self.socket
.reset_interrupt(bus, socketn::Interrupt::Receive)?;
// Register the reception as complete.
self.socket.command(bus, socketn::Command::Receive)?;
self.socket
.reset_interrupt(bus, socketn::Interrupt::Receive)?;
Ok(read_buffer.len())
}
Ok(read_buffer.len())
}
}
impl<SpiBus: Bus, StateImpl: State> TcpClientStack for Device<SpiBus, StateImpl> {
type TcpSocket = TcpSocket;
type Error = TcpSocketError<SpiBus::Error>;
type TcpSocket = TcpSocket;
type Error = TcpSocketError<SpiBus::Error>;
fn socket(&mut self) -> Result<TcpSocket, Self::Error> {
match self.take_socket() {
Some(socket) => Ok(TcpSocket { socket }),
None => Err(TcpSocketError::NoMoreSockets),
}
}
fn socket(&mut self) -> Result<TcpSocket, Self::Error> {
match self.take_socket() {
Some(socket) => Ok(TcpSocket { socket }),
None => Err(TcpSocketError::NoMoreSockets),
}
}
fn connect(
&mut self,
socket: &mut Self::TcpSocket,
remote: SocketAddr,
) -> nb::Result<(), Self::Error> {
let SocketAddr::V4(remote) = remote else {
return Err(nb::Error::Other(Self::Error::UnsupportedAddress));
};
// TODO dynamically select a random port
socket.open(&mut self.bus, 49849 + u16::from(socket.socket.index))?; // chosen by fair dice roll.
socket.socket_connect(&mut self.bus, remote)?;
fn connect(
&mut self,
socket: &mut Self::TcpSocket,
remote: SocketAddr,
) -> nb::Result<(), Self::Error> {
let SocketAddr::V4(remote) = remote else {
return Err(nb::Error::Other(Self::Error::UnsupportedAddress));
};
// TODO dynamically select a random port
socket.open(&mut self.bus, 49849 + u16::from(socket.socket.index))?; // chosen by fair dice roll.
socket.socket_connect(&mut self.bus, remote)?;
Ok(())
}
Ok(())
}
fn send(
&mut self,
socket: &mut Self::TcpSocket,
buffer: &[u8],
) -> nb::Result<usize, Self::Error> {
let len = socket.socket_send(&mut self.bus, buffer)?;
Ok(len)
}
fn send(
&mut self,
socket: &mut Self::TcpSocket,
buffer: &[u8],
) -> nb::Result<usize, Self::Error> {
let len = socket.socket_send(&mut self.bus, buffer)?;
Ok(len)
}
fn receive(
&mut self,
socket: &mut Self::TcpSocket,
buffer: &mut [u8],
) -> nb::Result<usize, Self::Error> {
Ok(socket.socket_receive(&mut self.bus, buffer)?)
}
fn receive(
&mut self,
socket: &mut Self::TcpSocket,
buffer: &mut [u8],
) -> nb::Result<usize, Self::Error> {
Ok(socket.socket_receive(&mut self.bus, buffer)?)
}
fn close(&mut self, socket: Self::TcpSocket) -> Result<(), Self::Error> {
socket.socket_close(&mut self.bus)?;
self.release_socket(socket.socket);
Ok(())
}
fn close(&mut self, socket: Self::TcpSocket) -> Result<(), Self::Error> {
socket.socket_close(&mut self.bus)?;
self.release_socket(socket.socket);
Ok(())
}
}

File diff suppressed because it is too large Load diff

View file

@ -2,217 +2,211 @@ use core::net::Ipv4Addr;
use embedded_hal::spi::SpiDevice;
use crate::bus::{Bus, FourWire};
use crate::device::{Device, DeviceState};
use crate::host::{Dhcp, Host, Manual};
use crate::raw_device::RawDevice;
use crate::{
register::{self, common::RetryTime},
MacAddress, Mode,
bus::{Bus, FourWire},
device::{Device, DeviceState},
host::{Dhcp, Host, Manual},
raw_device::RawDevice,
register::{self, common::RetryTime},
MacAddress, Mode,
};
#[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct UninitializedDevice<SpiBus: Bus> {
bus: SpiBus,
bus: SpiBus,
}
#[derive(Debug)]
#[repr(u8)]
pub enum InitializeError<SpiError> {
SpiError(SpiError),
ChipNotConnected,
SpiError(SpiError),
ChipNotConnected,
}
impl<SpiError> From<SpiError> for InitializeError<SpiError> {
fn from(error: SpiError) -> InitializeError<SpiError> {
InitializeError::SpiError(error)
}
fn from(error: SpiError) -> InitializeError<SpiError> {
InitializeError::SpiError(error)
}
}
impl<SpiBus: Bus> UninitializedDevice<SpiBus> {
pub fn new(bus: SpiBus) -> UninitializedDevice<SpiBus> {
UninitializedDevice { bus }
}
pub fn new(bus: SpiBus) -> UninitializedDevice<SpiBus> {
UninitializedDevice { bus }
}
/// Initialize the device with a MAC address and mode settings.
///
/// Consider using freely available private/locally administered mac
/// addresses that match the following hex pattern:
///
/// ```code
/// x2-xx-xx-xx-xx-xx
/// x6-xx-xx-xx-xx-xx
/// xA-xx-xx-xx-xx-xx
/// xE-xx-xx-xx-xx-xx
/// ```
///
/// "Universally administered and locally administered addresses are
/// distinguished by setting the second-least-significant bit of the first
/// octet of the address"
/// [Wikipedia](https://en.wikipedia.org/wiki/MAC_address#Universal_vs._local)
pub fn initialize(
self,
mac: MacAddress,
mode_options: Mode,
) -> Result<Device<SpiBus, DeviceState<Dhcp>>, InitializeError<SpiBus::Error>> {
let host = Dhcp::new(mac);
self.initialize_with_host(host, mode_options)
}
/// Initialize the device with a MAC address and mode settings.
///
/// Consider using freely available private/locally administered mac
/// addresses that match the following hex pattern:
///
/// ```code
/// x2-xx-xx-xx-xx-xx
/// x6-xx-xx-xx-xx-xx
/// xA-xx-xx-xx-xx-xx
/// xE-xx-xx-xx-xx-xx
/// ```
///
/// "Universally administered and locally administered addresses are
/// distinguished by setting the second-least-significant bit of the first
/// octet of the address"
/// [Wikipedia](https://en.wikipedia.org/wiki/MAC_address#Universal_vs._local)
pub fn initialize(
self,
mac: MacAddress,
mode_options: Mode,
) -> Result<Device<SpiBus, DeviceState<Dhcp>>, InitializeError<SpiBus::Error>> {
let host = Dhcp::new(mac);
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,
ip: Ipv4Addr,
mode_options: Mode,
) -> Result<Device<SpiBus, DeviceState<Manual>>, InitializeError<SpiBus::Error>> {
let mut ip_bytes = ip.octets();
ip_bytes[3] = 1;
let gateway = Ipv4Addr::from(ip_bytes);
let subnet = Ipv4Addr::new(255, 255, 255, 0);
self.initialize_advanced(mac, ip, gateway, subnet, 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,
ip: Ipv4Addr,
mode_options: Mode,
) -> Result<Device<SpiBus, DeviceState<Manual>>, InitializeError<SpiBus::Error>> {
let mut ip_bytes = ip.octets();
ip_bytes[3] = 1;
let gateway = Ipv4Addr::from(ip_bytes);
let subnet = Ipv4Addr::new(255, 255, 255, 0);
self.initialize_advanced(mac, ip, gateway, subnet, mode_options)
}
pub fn initialize_advanced(
self,
mac: MacAddress,
ip: Ipv4Addr,
gateway: Ipv4Addr,
subnet: Ipv4Addr,
mode_options: Mode,
) -> Result<Device<SpiBus, DeviceState<Manual>>, InitializeError<SpiBus::Error>> {
let host = Manual::new(mac, ip, gateway, subnet);
self.initialize_with_host(host, mode_options)
}
pub fn initialize_advanced(
self,
mac: MacAddress,
ip: Ipv4Addr,
gateway: Ipv4Addr,
subnet: Ipv4Addr,
mode_options: Mode,
) -> Result<Device<SpiBus, DeviceState<Manual>>, InitializeError<SpiBus::Error>> {
let host = Manual::new(mac, ip, gateway, subnet);
self.initialize_with_host(host, mode_options)
}
fn initialize_with_host<HostImpl: Host>(
mut self,
mut host: HostImpl,
mode_options: Mode,
) -> Result<Device<SpiBus, DeviceState<HostImpl>>, InitializeError<SpiBus::Error>> {
fn initialize_with_host<HostImpl: Host>(
mut self,
mut host: HostImpl,
mode_options: Mode,
) -> Result<Device<SpiBus, DeviceState<HostImpl>>, InitializeError<SpiBus::Error>> {
// RESET
self.reset()?;
// RESET
self.reset()?;
self.set_mode(mode_options)?;
host.refresh(&mut self.bus)?;
Ok(Device::new(self.bus, DeviceState::new(host)))
}
self.set_mode(mode_options)?;
host.refresh(&mut self.bus)?;
Ok(Device::new(self.bus, DeviceState::new(host)))
}
pub fn initialize_macraw(
mut self,
mac: MacAddress,
) -> Result<RawDevice<SpiBus>, InitializeError<SpiBus::Error>> {
// Reset the device.
self.bus
.write_frame(register::COMMON + register::common::MODE, &[0x80])?;
pub fn initialize_macraw(
mut self,
mac: MacAddress,
) -> Result<RawDevice<SpiBus>, InitializeError<SpiBus::Error>> {
// Reset the device.
self.bus
.write_frame(register::COMMON + register::common::MODE, &[0x80])?;
self.bus
.write_frame(register::COMMON + register::common::MAC, &mac.octets)?;
self.bus
.write_frame(register::COMMON + register::common::MAC, &mac.octets)?;
RawDevice::new(self.bus)
}
RawDevice::new(self.bus)
}
/// Reset the device
#[inline]
pub fn reset(&mut self) -> Result<(), SpiBus::Error> {
// Set RST common register of the w5500
let mode = [0b10000000];
self.bus
.write_frame(register::COMMON + register::common::MODE, &mode)
}
#[inline]
pub fn set_mode(&mut self, mode_options: Mode) -> Result<(), SpiBus::Error> {
self.bus.write_frame(
register::COMMON + register::common::MODE,
&mode_options.to_register(),
)
}
/// Reset the device
#[inline]
pub fn reset(&mut self) -> Result<(), SpiBus::Error> {
// Set RST common register of the w5500
let mode = [0b10000000];
self.bus
.write_frame(register::COMMON + register::common::MODE, &mode)
}
#[inline]
pub fn set_mode(&mut self, mode_options: Mode) -> Result<(), SpiBus::Error> {
self.bus.write_frame(
register::COMMON +
register::common::MODE,
&mode_options.to_register(),
)
}
/// RTR (Retry Time-value Register) [R/W] [0x0019 0x001A] [0x07D0]
///
/// # Example
///
/// ```
/// use w5500::register::common::RetryTime;
///
/// let default = RetryTime::from_millis(200);
/// assert_eq!(RetryTime::default(), default);
///
/// // E.g. 4000 (register) = 400ms
/// let four_hundred_ms = RetryTime::from_millis(400);
/// assert_eq!(four_hundred_ms.to_u16(), 4000);
/// ```
#[inline]
pub fn set_retry_timeout(&mut self, retry_time_value: RetryTime) -> Result<(), SpiBus::Error> {
self.bus.write_frame(
register::COMMON + register::common::RETRY_TIME,
&retry_time_value.to_register(),
)?;
/// RTR (Retry Time-value Register) [R/W] [0x0019 0x001A] [0x07D0]
///
/// # Example
///
/// ```
/// use w5500::register::common::RetryTime;
///
/// let default = RetryTime::from_millis(200);
/// assert_eq!(RetryTime::default(), default);
///
/// // E.g. 4000 (register) = 400ms
/// let four_hundred_ms = RetryTime::from_millis(400);
/// assert_eq!(four_hundred_ms.to_u16(), 4000);
/// ```
#[inline]
pub fn set_retry_timeout(&mut self, retry_time_value: RetryTime) -> Result<(), SpiBus::Error> {
self.bus.write_frame(
register::COMMON +
register::common::RETRY_TIME,
&retry_time_value.to_register(),
)?;
Ok(())
}
Ok(())
}
/// RTR (Retry Time-value Register) [R/W] [0x0019 0x001A] [0x07D0]
///
/// E.g. 4000 = 400ms
#[inline]
pub fn current_retry_timeout(&mut self) -> Result<RetryTime, SpiBus::Error> {
let mut retry_time_register: [u8; 2] = [0, 0];
self.bus.read_frame(
register::COMMON + register::common::RETRY_TIME,
&mut retry_time_register,
)?;
/// RTR (Retry Time-value Register) [R/W] [0x0019 0x001A] [0x07D0]
///
/// E.g. 4000 = 400ms
#[inline]
pub fn current_retry_timeout(&mut self) -> Result<RetryTime, SpiBus::Error> {
let mut retry_time_register: [u8; 2] = [0, 0];
self.bus.read_frame(
register::COMMON+
register::common::RETRY_TIME,
&mut retry_time_register,
)?;
Ok(RetryTime::from_register(retry_time_register))
}
Ok(RetryTime::from_register(retry_time_register))
}
/// Set a new value for the Retry Count register.
///
/// RCR (Retry Count Register) [R/W] [0x001B] [0x08]
///
/// For more details check out the rest of the datasheet documentation on the Retry count.
///
/// From datasheet:
///
/// RCR configures the number of time of retransmission. When retransmission occurs
/// as many as RCR+1, Timeout interrupt is issued (Sn_IR[TIMEOUT] = 1).
///
/// The timeout of W5500 can be configurable with RTR and RCR. W5500 has two kind
/// timeout such as Address Resolution Protocol (ARP) and TCP retransmission.
///
/// E.g. In case of errors it will retry for 7 times:
/// `RCR = 0x0007`
pub fn set_retry_count(&mut self, retry_count: u8) -> Result<(), SpiBus::Error> {
self.bus.write_frame(
register::COMMON + register::common::RETRY_COUNT,
&[retry_count],
)?;
/// Set a new value for the Retry Count register.
///
/// RCR (Retry Count Register) [R/W] [0x001B] [0x08]
///
/// For more details check out the rest of the datasheet documentation on the Retry count.
///
/// From datasheet:
///
/// RCR configures the number of time of retransmission. When retransmission occurs
/// as many as RCR+1, Timeout interrupt is issued (Sn_IR[TIMEOUT] = 1).
///
/// The timeout of W5500 can be configurable with RTR and RCR. W5500 has two kind
/// timeout such as Address Resolution Protocol (ARP) and TCP retransmission.
///
/// E.g. In case of errors it will retry for 7 times:
/// `RCR = 0x0007`
pub fn set_retry_count(&mut self, retry_count: u8) -> Result<(), SpiBus::Error> {
self.bus.write_frame(
register::COMMON+
register::common::RETRY_COUNT,
&[retry_count],
)?;
Ok(())
}
Ok(())
}
/// Get the current Retry Count value
/// RCR (Retry Count Register) [R/W] [0x001B] [0x08]
///
/// E.g. In case of errors it will retry for 7 times:
/// `RCR = 0x0007`
#[inline]
pub fn current_retry_count(&mut self) -> Result<u8, SpiBus::Error> {
let mut retry_count_register: [u8; 1] = [0];
self.bus.read_frame(
register::COMMON + register::common::RETRY_COUNT,
&mut retry_count_register,
)?;
/// Get the current Retry Count value
/// RCR (Retry Count Register) [R/W] [0x001B] [0x08]
///
/// E.g. In case of errors it will retry for 7 times:
/// `RCR = 0x0007`
#[inline]
pub fn current_retry_count(&mut self) -> Result<u8, SpiBus::Error> {
let mut retry_count_register: [u8; 1] = [0];
self.bus.read_frame(
register::COMMON+
register::common::RETRY_COUNT,
&mut retry_count_register,
)?;
Ok(retry_count_register[0])
}
Ok(retry_count_register[0])
}
}