Format, clean
This commit is contained in:
parent
62e56052cf
commit
bbd50619a4
21 changed files with 1942 additions and 2121 deletions
13
.github/dependabot.yml
vendored
13
.github/dependabot.yml
vendored
|
|
@ -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
|
|
||||||
70
.github/workflows/rust.yml
vendored
70
.github/workflows/rust.yml
vendored
|
|
@ -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
2
.gitignore
vendored
|
|
@ -1,4 +1,2 @@
|
||||||
*.iml
|
|
||||||
/target
|
/target
|
||||||
**/*.rs.bk
|
|
||||||
Cargo.lock
|
Cargo.lock
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ keywords = ["embedded", "w5100", "embedded-hal-driver"]
|
||||||
categories = ["embedded", "hardware-support", "no-std", "network-programming"]
|
categories = ["embedded", "hardware-support", "no-std", "network-programming"]
|
||||||
license = "AGPL-3.0-only"
|
license = "AGPL-3.0-only"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
|
|
||||||
|
|
|
||||||
79
README.md
79
README.md
|
|
@ -1,87 +1,12 @@
|
||||||
# W5100 Driver
|
# W5100 Driver
|
||||||
|
|
||||||
|
Rust driver for the WIZnet W5100 Ethernet controler using SPI.
|
||||||
|
|
||||||
**Fork status**:
|
**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.
|
* 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.
|
* What works: receive and send UDP packets.
|
||||||
* Tested on Arduino Uno with Arduino Ethernet Shield.
|
* 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.
|
|
||||||
|
|
||||||
|
|
||||||
[](https://github.com/kellerkindt/w5500/actions?query=workflow%3ARust)
|
|
||||||
[](https://github.com/kellerkindt/w5500)
|
|
||||||
[](https://crates.io/crates/w5500)
|
|
||||||
[](https://docs.rs/w5500)
|
|
||||||
[](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
|
## License
|
||||||
|
|
||||||
[Support me via LiberaPay](https://liberapay.com/tuxmain/donate)
|
[Support me via LiberaPay](https://liberapay.com/tuxmain/donate)
|
||||||
|
|
|
||||||
9
rustfmt.toml
Normal file
9
rustfmt.toml
Normal 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
|
||||||
|
|
@ -12,44 +12,44 @@ const OPMODE_WRITE: u8 = 0xf0;
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
pub struct FourWire<SPI> {
|
pub struct FourWire<SPI> {
|
||||||
spi: SPI,
|
spi: SPI,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<SPI> FourWire<SPI> {
|
impl<SPI> FourWire<SPI> {
|
||||||
pub fn new(spi: SPI) -> Self {
|
pub fn new(spi: SPI) -> Self {
|
||||||
Self { spi }
|
Self { spi }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn release(self) -> SPI {
|
pub fn release(self) -> SPI {
|
||||||
self.spi
|
self.spi
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<SPI: SpiDevice> Bus for FourWire<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> {
|
fn read_frame(&mut self, address: u16, data: &mut [u8]) -> Result<(), SPI::Error> {
|
||||||
let address_phase = address.to_be_bytes();
|
let address_phase = address.to_be_bytes();
|
||||||
for (i, byte) in data.iter_mut().enumerate() {
|
for (i, byte) in data.iter_mut().enumerate() {
|
||||||
self.spi.transaction(&mut [
|
self.spi.transaction(&mut [
|
||||||
Operation::Write(&[OPMODE_READ]),
|
Operation::Write(&[OPMODE_READ]),
|
||||||
Operation::Write(&(address+i as u16).to_be_bytes()),
|
Operation::Write(&(address + i as u16).to_be_bytes()),
|
||||||
Operation::TransferInPlace(core::array::from_mut(byte)),
|
Operation::TransferInPlace(core::array::from_mut(byte)),
|
||||||
])?;
|
])?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_frame(&mut self, address: u16, data: &[u8]) -> Result<(), SPI::Error> {
|
fn write_frame(&mut self, address: u16, data: &[u8]) -> Result<(), SPI::Error> {
|
||||||
for (i, byte) in data.iter().enumerate() {
|
for (i, byte) in data.iter().enumerate() {
|
||||||
self.spi.transaction(&mut [
|
self.spi.transaction(&mut [
|
||||||
Operation::Write(&[OPMODE_WRITE]),
|
Operation::Write(&[OPMODE_WRITE]),
|
||||||
Operation::Write(&(address+i as u16).to_be_bytes()),
|
Operation::Write(&(address + i as u16).to_be_bytes()),
|
||||||
Operation::Write(&[*byte]),
|
Operation::Write(&[*byte]),
|
||||||
])?;
|
])?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,9 @@ mod four_wire;
|
||||||
pub use self::four_wire::FourWire;
|
pub use self::four_wire::FourWire;
|
||||||
|
|
||||||
pub trait Bus {
|
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>;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
188
src/cursor.rs
188
src/cursor.rs
|
|
@ -1,126 +1,122 @@
|
||||||
use crate::bus::Bus;
|
use crate::{bus::Bus, register::socketn::Command, socket::Socket};
|
||||||
use crate::register::socketn::Command;
|
|
||||||
use crate::socket::Socket;
|
|
||||||
|
|
||||||
pub(crate) struct RxCursor<'a, SpiBus>
|
pub(crate) struct RxCursor<'a, SpiBus>
|
||||||
where
|
where
|
||||||
SpiBus: Bus,
|
SpiBus: Bus,
|
||||||
{
|
{
|
||||||
sock: &'a Socket,
|
sock: &'a Socket,
|
||||||
bus: &'a mut SpiBus,
|
bus: &'a mut SpiBus,
|
||||||
ptr: u16,
|
ptr: u16,
|
||||||
size: u16,
|
size: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, SpiBus> RxCursor<'a, SpiBus>
|
impl<'a, SpiBus> RxCursor<'a, SpiBus>
|
||||||
where
|
where
|
||||||
SpiBus: Bus,
|
SpiBus: Bus,
|
||||||
{
|
{
|
||||||
pub fn new(sock: &'a Socket, bus: &'a mut SpiBus) -> Result<Self, SpiBus::Error> {
|
pub fn new(sock: &'a Socket, bus: &'a mut SpiBus) -> Result<Self, SpiBus::Error> {
|
||||||
let size = sock.get_receive_size(bus)?;
|
let size = sock.get_receive_size(bus)?;
|
||||||
let ptr = sock.get_rx_read_pointer(bus)?;
|
let ptr = sock.get_rx_read_pointer(bus)?;
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
sock,
|
sock,
|
||||||
bus,
|
bus,
|
||||||
ptr,
|
ptr,
|
||||||
size,
|
size,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn available(&self) -> u16 {
|
pub fn available(&self) -> u16 {
|
||||||
self.size
|
self.size
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Read up to `buf.len()` bytes. The actual number of bytes read is bounded by `available()`.
|
/// 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> {
|
pub fn read(&mut self, buf: &mut [u8]) -> Result<u16, SpiBus::Error> {
|
||||||
if buf.is_empty() {
|
if buf.is_empty() {
|
||||||
return Ok(0);
|
return Ok(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
let count = self.available().min(buf.len() as u16);
|
let count = self.available().min(buf.len() as u16);
|
||||||
self.bus
|
self.bus.read_frame(self.ptr, &mut buf[..count as _])?;
|
||||||
.read_frame(self.ptr, &mut buf[..count as _])?;
|
Ok(self.skip(count))
|
||||||
Ok(self.skip(count))
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// Read up to `max` bytes. The actual number of bytes read is bounded by buf.len() and available().
|
/// 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> {
|
pub fn read_upto(&mut self, buf: &mut [u8], max: u16) -> Result<u16, SpiBus::Error> {
|
||||||
let bounded_buf = if buf.len() > max as usize {
|
let bounded_buf = if buf.len() > max as usize {
|
||||||
&mut buf[..max as _]
|
&mut buf[..max as _]
|
||||||
} else {
|
} else {
|
||||||
buf
|
buf
|
||||||
};
|
};
|
||||||
self.read(bounded_buf)
|
self.read(bounded_buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Skip up to count bytes. The actual number of bytes skipped is bounded by available().
|
/// Skip up to count bytes. The actual number of bytes skipped is bounded by available().
|
||||||
pub fn skip(&mut self, count: u16) -> u16 {
|
pub fn skip(&mut self, count: u16) -> u16 {
|
||||||
let bounded_count = self.available().min(count);
|
let bounded_count = self.available().min(count);
|
||||||
self.ptr = self.ptr.wrapping_add(bounded_count);
|
self.ptr = self.ptr.wrapping_add(bounded_count);
|
||||||
self.size -= bounded_count;
|
self.size -= bounded_count;
|
||||||
bounded_count
|
bounded_count
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return ownership of the portion of the RX buffer that has already been read back to the
|
/// Return ownership of the portion of the RX buffer that has already been read back to the
|
||||||
/// chip and issue the next receive command.
|
/// chip and issue the next receive command.
|
||||||
pub fn commit(mut self) -> Result<(), SpiBus::Error> {
|
pub fn commit(mut self) -> Result<(), SpiBus::Error> {
|
||||||
self.sock.set_rx_read_pointer(self.bus, self.ptr)?;
|
self.sock.set_rx_read_pointer(self.bus, self.ptr)?;
|
||||||
self.sock.command(self.bus, Command::Receive)?;
|
self.sock.command(self.bus, Command::Receive)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct TxCursor<'a, SpiBus>
|
pub(crate) struct TxCursor<'a, SpiBus>
|
||||||
where
|
where
|
||||||
SpiBus: Bus,
|
SpiBus: Bus,
|
||||||
{
|
{
|
||||||
sock: &'a Socket,
|
sock: &'a Socket,
|
||||||
bus: &'a mut SpiBus,
|
bus: &'a mut SpiBus,
|
||||||
ptr: u16,
|
ptr: u16,
|
||||||
size: u16,
|
size: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, SpiBus> TxCursor<'a, SpiBus>
|
impl<'a, SpiBus> TxCursor<'a, SpiBus>
|
||||||
where
|
where
|
||||||
SpiBus: Bus,
|
SpiBus: Bus,
|
||||||
{
|
{
|
||||||
pub fn new(sock: &'a Socket, bus: &'a mut SpiBus) -> Result<Self, SpiBus::Error> {
|
pub fn new(sock: &'a Socket, bus: &'a mut SpiBus) -> Result<Self, SpiBus::Error> {
|
||||||
let size = sock.get_tx_free_size(bus)?;
|
let size = sock.get_tx_free_size(bus)?;
|
||||||
let ptr = sock.get_tx_write_pointer(bus)?;
|
let ptr = sock.get_tx_write_pointer(bus)?;
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
sock,
|
sock,
|
||||||
bus,
|
bus,
|
||||||
ptr,
|
ptr,
|
||||||
size,
|
size,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn available(&self) -> u16 {
|
pub fn available(&self) -> u16 {
|
||||||
self.size
|
self.size
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Write all bytes in buf to the current TX buffer position and update the cursor position
|
/// Write all bytes in buf to the current TX buffer position and update the cursor position
|
||||||
/// and remaining size on success.
|
/// and remaining size on success.
|
||||||
pub fn write(&mut self, buf: &[u8]) -> Result<u16, SpiBus::Error> {
|
pub fn write(&mut self, buf: &[u8]) -> Result<u16, SpiBus::Error> {
|
||||||
if buf.is_empty() || buf.len() > self.available() as _ {
|
if buf.is_empty() || buf.len() > self.available() as _ {
|
||||||
return Ok(0);
|
return Ok(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
let count = buf.len() as u16;
|
let count = buf.len() as u16;
|
||||||
self.bus
|
self.bus.write_frame(self.ptr, &buf[..count as _])?;
|
||||||
.write_frame(self.ptr, &buf[..count as _])?;
|
self.ptr = self.ptr.wrapping_add(count);
|
||||||
self.ptr = self.ptr.wrapping_add(count);
|
self.size -= count;
|
||||||
self.size -= count;
|
Ok(count)
|
||||||
Ok(count)
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// Pass ownership of the portion of the TX buffer that has already been written back to the
|
/// Pass ownership of the portion of the TX buffer that has already been written back to the
|
||||||
/// chip and issue the next send command.
|
/// chip and issue the next send command.
|
||||||
pub fn commit(mut self) -> Result<(), SpiBus::Error> {
|
pub fn commit(mut self) -> Result<(), SpiBus::Error> {
|
||||||
self.sock.set_tx_write_pointer(self.bus, self.ptr)?;
|
self.sock.set_tx_write_pointer(self.bus, self.ptr)?;
|
||||||
self.sock.command(self.bus, Command::Send)?;
|
self.sock.command(self.bus, Command::Send)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
475
src/device.rs
475
src/device.rs
|
|
@ -1,304 +1,293 @@
|
||||||
use bit_field::BitField;
|
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::{
|
use crate::{
|
||||||
register::{self, common::RetryTime},
|
bus::{Bus, FourWire},
|
||||||
MacAddress, Mode,
|
host::Host,
|
||||||
|
net::Ipv4Addr,
|
||||||
|
register::{self, common::RetryTime},
|
||||||
|
socket::Socket,
|
||||||
|
uninitialized_device::UninitializedDevice,
|
||||||
|
MacAddress, Mode,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
pub enum ResetError<E> {
|
pub enum ResetError<E> {
|
||||||
SocketsNotReleased,
|
SocketsNotReleased,
|
||||||
Other(E),
|
Other(E),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E> From<E> for ResetError<E> {
|
impl<E> From<E> for ResetError<E> {
|
||||||
fn from(error: E) -> ResetError<E> {
|
fn from(error: E) -> ResetError<E> {
|
||||||
ResetError::Other(error)
|
ResetError::Other(error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mod private {
|
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 {
|
pub trait State: private::Sealed {
|
||||||
fn socket(&mut self) -> Option<Socket>;
|
fn socket(&mut self) -> Option<Socket>;
|
||||||
fn release_socket(&mut self, socket: Socket);
|
fn release_socket(&mut self, socket: Socket);
|
||||||
fn any_allocated(&self) -> bool;
|
fn any_allocated(&self) -> bool;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
pub struct DeviceState<HostImpl: Host> {
|
pub struct DeviceState<HostImpl: Host> {
|
||||||
host: HostImpl,
|
host: HostImpl,
|
||||||
sockets: u8,
|
sockets: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<HostImpl: Host> DeviceState<HostImpl> {
|
impl<HostImpl: Host> DeviceState<HostImpl> {
|
||||||
pub fn new(host: HostImpl) -> Self {
|
pub fn new(host: HostImpl) -> Self {
|
||||||
Self {
|
Self {
|
||||||
sockets: 0xFF,
|
sockets: 0xFF,
|
||||||
host,
|
host,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<HostImpl: Host> private::Sealed for DeviceState<HostImpl> {}
|
impl<HostImpl: Host> private::Sealed for DeviceState<HostImpl> {}
|
||||||
|
|
||||||
impl<HostImpl: Host> State for DeviceState<HostImpl> {
|
impl<HostImpl: Host> State for DeviceState<HostImpl> {
|
||||||
fn socket(&mut self) -> Option<Socket> {
|
fn socket(&mut self) -> Option<Socket> {
|
||||||
for index in 0..8 {
|
for index in 0..8 {
|
||||||
if self.sockets.get_bit(index) {
|
if self.sockets.get_bit(index) {
|
||||||
self.sockets.set_bit(index, false);
|
self.sockets.set_bit(index, false);
|
||||||
return Some(Socket::new(index as u8));
|
return Some(Socket::new(index as u8));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
fn release_socket(&mut self, socket: Socket) {
|
fn release_socket(&mut self, socket: Socket) {
|
||||||
self.sockets.set_bit(socket.index.into(), true);
|
self.sockets.set_bit(socket.index.into(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn any_allocated(&self) -> bool {
|
fn any_allocated(&self) -> bool {
|
||||||
self.sockets != 0xFF
|
self.sockets != 0xFF
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: State> State for &'_ mut T {
|
impl<T: State> State for &'_ mut T {
|
||||||
fn socket(&mut self) -> Option<Socket> {
|
fn socket(&mut self) -> Option<Socket> {
|
||||||
T::socket(self)
|
T::socket(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn release_socket(&mut self, socket: Socket) {
|
fn release_socket(&mut self, socket: Socket) {
|
||||||
T::release_socket(self, socket)
|
T::release_socket(self, socket)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn any_allocated(&self) -> bool {
|
fn any_allocated(&self) -> bool {
|
||||||
T::any_allocated(self)
|
T::any_allocated(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Device<SpiBus: Bus, StateImpl: State> {
|
pub struct Device<SpiBus: Bus, StateImpl: State> {
|
||||||
pub(crate) bus: SpiBus,
|
pub(crate) bus: SpiBus,
|
||||||
state: StateImpl,
|
state: StateImpl,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<SpiBus: Bus, StateImpl: State> Device<SpiBus, StateImpl> {
|
impl<SpiBus: Bus, StateImpl: State> Device<SpiBus, StateImpl> {
|
||||||
pub(crate) fn new(bus: SpiBus, state: StateImpl) -> Self {
|
pub(crate) fn new(bus: SpiBus, state: StateImpl) -> Self {
|
||||||
Device { bus, state }
|
Device { bus, state }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_state(&self) -> &StateImpl {
|
pub fn get_state(&self) -> &StateImpl {
|
||||||
&self.state
|
&self.state
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn reset(mut self) -> Result<UninitializedDevice<SpiBus>, ResetError<SpiBus::Error>> {
|
pub fn reset(mut self) -> Result<UninitializedDevice<SpiBus>, ResetError<SpiBus::Error>> {
|
||||||
if self.state.any_allocated() {
|
if self.state.any_allocated() {
|
||||||
Err(ResetError::SocketsNotReleased)
|
Err(ResetError::SocketsNotReleased)
|
||||||
} else {
|
} else {
|
||||||
self.reset_device()?;
|
self.reset_device()?;
|
||||||
Ok(UninitializedDevice::new(self.bus))
|
Ok(UninitializedDevice::new(self.bus))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn release(self) -> (SpiBus, StateImpl) {
|
pub fn release(self) -> (SpiBus, StateImpl) {
|
||||||
(self.bus, self.state)
|
(self.bus, self.state)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn take_socket(&mut self) -> Option<Socket> {
|
pub fn take_socket(&mut self) -> Option<Socket> {
|
||||||
// TODO maybe return Future that resolves when release_socket invoked
|
// TODO maybe return Future that resolves when release_socket invoked
|
||||||
self.state.socket()
|
self.state.socket()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn release_socket(&mut self, socket: Socket) {
|
pub fn release_socket(&mut self, socket: Socket) {
|
||||||
self.state.release_socket(socket)
|
self.state.release_socket(socket)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn gateway(&mut self) -> Result<Ipv4Addr, SpiBus::Error> {
|
pub fn gateway(&mut self) -> Result<Ipv4Addr, SpiBus::Error> {
|
||||||
let mut octets = [0u8; 4];
|
let mut octets = [0u8; 4];
|
||||||
self.bus
|
self.bus
|
||||||
.read_frame(register::COMMON + register::common::GATEWAY, &mut octets)?;
|
.read_frame(register::COMMON + register::common::GATEWAY, &mut octets)?;
|
||||||
Ok(Ipv4Addr::from(octets))
|
Ok(Ipv4Addr::from(octets))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn subnet_mask(&mut self) -> Result<Ipv4Addr, SpiBus::Error> {
|
pub fn subnet_mask(&mut self) -> Result<Ipv4Addr, SpiBus::Error> {
|
||||||
let mut octets = [0u8; 4];
|
let mut octets = [0u8; 4];
|
||||||
self.bus
|
self.bus.read_frame(
|
||||||
.read_frame(register::COMMON + register::common::SUBNET_MASK, &mut octets)?;
|
register::COMMON + register::common::SUBNET_MASK,
|
||||||
Ok(Ipv4Addr::from(octets))
|
&mut octets,
|
||||||
}
|
)?;
|
||||||
|
Ok(Ipv4Addr::from(octets))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn mac(&mut self) -> Result<MacAddress, SpiBus::Error> {
|
pub fn mac(&mut self) -> Result<MacAddress, SpiBus::Error> {
|
||||||
let mut mac = MacAddress::default();
|
let mut mac = MacAddress::default();
|
||||||
self.bus
|
self.bus
|
||||||
.read_frame(register::COMMON + register::common::MAC, &mut mac.octets)?;
|
.read_frame(register::COMMON + register::common::MAC, &mut mac.octets)?;
|
||||||
Ok(mac)
|
Ok(mac)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ip(&mut self) -> Result<Ipv4Addr, SpiBus::Error> {
|
pub fn ip(&mut self) -> Result<Ipv4Addr, SpiBus::Error> {
|
||||||
let mut octets = [0u8; 4];
|
let mut octets = [0u8; 4];
|
||||||
self.bus
|
self.bus
|
||||||
.read_frame(register::COMMON + register::common::IP, &mut octets)?;
|
.read_frame(register::COMMON + register::common::IP, &mut octets)?;
|
||||||
Ok(Ipv4Addr::from(octets))
|
Ok(Ipv4Addr::from(octets))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn reset_device(&mut self) -> Result<(), SpiBus::Error> {
|
pub fn reset_device(&mut self) -> Result<(), SpiBus::Error> {
|
||||||
// Set RST common register of the w5500
|
// Set RST common register of the w5500
|
||||||
let mode = [0b10000000];
|
let mode = [0b10000000];
|
||||||
self.bus
|
self.bus
|
||||||
.write_frame(register::COMMON + register::common::MODE, &mode)
|
.write_frame(register::COMMON + register::common::MODE, &mode)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_mode(&mut self, mode_options: Mode) -> Result<(), SpiBus::Error> {
|
pub fn set_mode(&mut self, mode_options: Mode) -> Result<(), SpiBus::Error> {
|
||||||
self.bus.write_frame(
|
self.bus.write_frame(
|
||||||
register::COMMON +
|
register::COMMON + register::common::MODE,
|
||||||
register::common::MODE,
|
&mode_options.to_register(),
|
||||||
&mode_options.to_register(),
|
)
|
||||||
)
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_rx_memory_size(&mut self, val: u8) -> Result<(), SpiBus::Error> {
|
pub fn set_rx_memory_size(&mut self, val: u8) -> Result<(), SpiBus::Error> {
|
||||||
self.bus.write_frame(
|
self.bus
|
||||||
register::COMMON +
|
.write_frame(register::COMMON + register::common::RX_MEMORY_SIZE, &[val])
|
||||||
register::common::RX_MEMORY_SIZE,
|
}
|
||||||
&[val],
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_tx_memory_size(&mut self, val: u8) -> Result<(), SpiBus::Error> {
|
pub fn set_tx_memory_size(&mut self, val: u8) -> Result<(), SpiBus::Error> {
|
||||||
self.bus.write_frame(
|
self.bus
|
||||||
register::COMMON +
|
.write_frame(register::COMMON + register::common::TX_MEMORY_SIZE, &[val])
|
||||||
register::common::TX_MEMORY_SIZE,
|
}
|
||||||
&[val],
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_rx_memory_size(&mut self) -> Result<u8, SpiBus::Error> {
|
pub fn get_rx_memory_size(&mut self) -> Result<u8, SpiBus::Error> {
|
||||||
let mut val = [0];
|
let mut val = [0];
|
||||||
self.bus.read_frame(
|
self.bus.read_frame(
|
||||||
register::COMMON +
|
register::COMMON + register::common::RX_MEMORY_SIZE,
|
||||||
register::common::RX_MEMORY_SIZE,
|
&mut val,
|
||||||
&mut val,
|
)?;
|
||||||
)?;
|
Ok(val[0])
|
||||||
Ok(val[0])
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_tx_memory_size(&mut self) -> Result<u8, SpiBus::Error> {
|
pub fn get_tx_memory_size(&mut self) -> Result<u8, SpiBus::Error> {
|
||||||
let mut val = [0];
|
let mut val = [0];
|
||||||
self.bus.read_frame(
|
self.bus.read_frame(
|
||||||
register::COMMON +
|
register::COMMON + register::common::TX_MEMORY_SIZE,
|
||||||
register::common::TX_MEMORY_SIZE,
|
&mut val,
|
||||||
&mut val,
|
)?;
|
||||||
)?;
|
Ok(val[0])
|
||||||
Ok(val[0])
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// Set a new value for the Retry Time-value Register.
|
/// Set a new value for the Retry Time-value Register.
|
||||||
///
|
///
|
||||||
/// RTR (Retry Time-value Register) [R/W] [0x0019 – 0x001A] [0x07D0]
|
/// RTR (Retry Time-value Register) [R/W] [0x0019 – 0x001A] [0x07D0]
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use w5500::register::common::RetryTime;
|
/// use w5500::register::common::RetryTime;
|
||||||
///
|
///
|
||||||
/// let default = RetryTime::from_millis(200);
|
/// let default = RetryTime::from_millis(200);
|
||||||
/// assert_eq!(RetryTime::default(), default);
|
/// assert_eq!(RetryTime::default(), default);
|
||||||
///
|
///
|
||||||
/// // E.g. 4000 (register) = 400ms
|
/// // E.g. 4000 (register) = 400ms
|
||||||
/// let four_hundred_ms = RetryTime::from_millis(400);
|
/// let four_hundred_ms = RetryTime::from_millis(400);
|
||||||
/// assert_eq!(four_hundred_ms.to_u16(), 4000);
|
/// assert_eq!(four_hundred_ms.to_u16(), 4000);
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_retry_timeout(&mut self, retry_time_value: RetryTime) -> Result<(), SpiBus::Error> {
|
pub fn set_retry_timeout(&mut self, retry_time_value: RetryTime) -> Result<(), SpiBus::Error> {
|
||||||
self.bus.write_frame(
|
self.bus.write_frame(
|
||||||
register::COMMON +
|
register::COMMON + register::common::RETRY_TIME,
|
||||||
register::common::RETRY_TIME,
|
&retry_time_value.to_register(),
|
||||||
&retry_time_value.to_register(),
|
)?;
|
||||||
)?;
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the currently set Retry Time-value Register.
|
/// Get the currently set Retry Time-value Register.
|
||||||
///
|
///
|
||||||
/// RTR (Retry Time-value Register) [R/W] [0x0019 – 0x001A] [0x07D0]
|
/// RTR (Retry Time-value Register) [R/W] [0x0019 – 0x001A] [0x07D0]
|
||||||
///
|
///
|
||||||
/// E.g. 4000 = 400ms
|
/// E.g. 4000 = 400ms
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn current_retry_timeout(&mut self) -> Result<RetryTime, SpiBus::Error> {
|
pub fn current_retry_timeout(&mut self) -> Result<RetryTime, SpiBus::Error> {
|
||||||
let mut retry_time_register: [u8; 2] = [0, 0];
|
let mut retry_time_register: [u8; 2] = [0, 0];
|
||||||
self.bus.read_frame(
|
self.bus.read_frame(
|
||||||
register::COMMON+
|
register::COMMON + register::common::RETRY_TIME,
|
||||||
register::common::RETRY_TIME,
|
&mut retry_time_register,
|
||||||
&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.
|
/// Set a new value for the Retry Count register.
|
||||||
///
|
///
|
||||||
/// RCR (Retry Count Register) [R/W] [0x001B] [0x08]
|
/// RCR (Retry Count Register) [R/W] [0x001B] [0x08]
|
||||||
///
|
///
|
||||||
/// For more details check out the rest of the datasheet documentation on the Retry count.
|
/// For more details check out the rest of the datasheet documentation on the Retry count.
|
||||||
///
|
///
|
||||||
/// From datasheet:
|
/// From datasheet:
|
||||||
///
|
///
|
||||||
/// RCR configures the number of time of retransmission. When retransmission occurs
|
/// RCR configures the number of time of retransmission. When retransmission occurs
|
||||||
/// as many as ‘RCR+1’, Timeout interrupt is issued (Sn_IR[TIMEOUT] = ‘1’).
|
/// 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
|
/// 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.
|
/// timeout such as Address Resolution Protocol (ARP) and TCP retransmission.
|
||||||
///
|
///
|
||||||
/// E.g. In case of errors it will retry for 7 times:
|
/// E.g. In case of errors it will retry for 7 times:
|
||||||
/// `RCR = 0x0007`
|
/// `RCR = 0x0007`
|
||||||
pub fn set_retry_count(&mut self, retry_count: u8) -> Result<(), SpiBus::Error> {
|
pub fn set_retry_count(&mut self, retry_count: u8) -> Result<(), SpiBus::Error> {
|
||||||
self.bus.write_frame(
|
self.bus.write_frame(
|
||||||
register::COMMON+
|
register::COMMON + register::common::RETRY_COUNT,
|
||||||
register::common::RETRY_COUNT,
|
&[retry_count],
|
||||||
&[retry_count],
|
)?;
|
||||||
)?;
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the current Retry Count value
|
/// Get the current Retry Count value
|
||||||
///
|
///
|
||||||
/// RCR (Retry Count Register) [R/W] [0x001B] [0x08]
|
/// RCR (Retry Count Register) [R/W] [0x001B] [0x08]
|
||||||
///
|
///
|
||||||
/// E.g. In case of errors it will retry for 7 times:
|
/// E.g. In case of errors it will retry for 7 times:
|
||||||
/// `RCR = 0x0007`
|
/// `RCR = 0x0007`
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn current_retry_count(&mut self) -> Result<u8, SpiBus::Error> {
|
pub fn current_retry_count(&mut self) -> Result<u8, SpiBus::Error> {
|
||||||
let mut retry_count_register: [u8; 1] = [0];
|
let mut retry_count_register: [u8; 1] = [0];
|
||||||
self.bus.read_frame(
|
self.bus.read_frame(
|
||||||
register::COMMON+
|
register::COMMON + register::common::RETRY_COUNT,
|
||||||
register::common::RETRY_COUNT,
|
&mut retry_count_register,
|
||||||
&mut retry_count_register,
|
)?;
|
||||||
)?;
|
|
||||||
|
|
||||||
Ok(retry_count_register[0])
|
Ok(retry_count_register[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deactivate(self) -> (SpiBus, InactiveDevice<StateImpl>) {
|
pub fn deactivate(self) -> (SpiBus, InactiveDevice<StateImpl>) {
|
||||||
(self.bus, InactiveDevice(self.state))
|
(self.bus, InactiveDevice(self.state))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|
@ -306,15 +295,15 @@ impl<SpiBus: Bus, StateImpl: State> Device<SpiBus, StateImpl> {
|
||||||
pub struct InactiveDevice<StateImpl: State>(StateImpl);
|
pub struct InactiveDevice<StateImpl: State>(StateImpl);
|
||||||
|
|
||||||
impl<StateImpl: State> InactiveDevice<StateImpl> {
|
impl<StateImpl: State> InactiveDevice<StateImpl> {
|
||||||
/// Activates the device by taking ownership
|
/// Activates the device by taking ownership
|
||||||
pub fn activate<SpiBus: Bus>(self, bus: SpiBus) -> Device<SpiBus, StateImpl> {
|
pub fn activate<SpiBus: Bus>(self, bus: SpiBus) -> Device<SpiBus, StateImpl> {
|
||||||
Device { bus, state: self.0 }
|
Device { bus, state: self.0 }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn activate_ref<SpiBus: Bus>(&mut self, bus: SpiBus) -> Device<SpiBus, &mut StateImpl> {
|
pub fn activate_ref<SpiBus: Bus>(&mut self, bus: SpiBus) -> Device<SpiBus, &mut StateImpl> {
|
||||||
Device {
|
Device {
|
||||||
bus,
|
bus,
|
||||||
state: &mut self.0,
|
state: &mut self.0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,32 +1,30 @@
|
||||||
use crate::bus::Bus;
|
use crate::{bus::Bus, host::Host, MacAddress};
|
||||||
use crate::host::Host;
|
|
||||||
use crate::MacAddress;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
pub struct Dhcp {
|
pub struct Dhcp {
|
||||||
// settings: HostConfig,
|
// settings: HostConfig,
|
||||||
// current: HostConfig,
|
// current: HostConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Dhcp {
|
impl Dhcp {
|
||||||
pub fn new(_mac: MacAddress) -> Self {
|
pub fn new(_mac: MacAddress) -> Self {
|
||||||
// let settings = HostConfig {
|
// let settings = HostConfig {
|
||||||
// mac,
|
// mac,
|
||||||
// ..HostConfig::default()
|
// ..HostConfig::default()
|
||||||
// };
|
// };
|
||||||
Self {
|
Self {
|
||||||
// settings,
|
// settings,
|
||||||
// current: HostConfig::default(),
|
// current: HostConfig::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Host for Dhcp {
|
impl Host for Dhcp {
|
||||||
/// Gets (if necessary) and sets the host settings on the chip
|
/// Gets (if necessary) and sets the host settings on the chip
|
||||||
fn refresh<SpiBus: Bus>(&mut self, _bus: &mut SpiBus) -> Result<(), SpiBus::Error> {
|
fn refresh<SpiBus: Bus>(&mut self, _bus: &mut SpiBus) -> Result<(), SpiBus::Error> {
|
||||||
// TODO actually negotiate settings from DHCP
|
// TODO actually negotiate settings from DHCP
|
||||||
// TODO figure out how should receive socket for DHCP negotiations
|
// TODO figure out how should receive socket for DHCP negotiations
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,39 +1,41 @@
|
||||||
use core::net::Ipv4Addr;
|
use core::net::Ipv4Addr;
|
||||||
|
|
||||||
use crate::bus::Bus;
|
use crate::{
|
||||||
use crate::host::{Host, HostConfig};
|
bus::Bus,
|
||||||
use crate::MacAddress;
|
host::{Host, HostConfig},
|
||||||
|
MacAddress,
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
pub struct Manual {
|
pub struct Manual {
|
||||||
is_setup: bool,
|
is_setup: bool,
|
||||||
settings: HostConfig,
|
settings: HostConfig,
|
||||||
current: HostConfig,
|
current: HostConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Manual {
|
impl Manual {
|
||||||
pub fn new(mac: MacAddress, ip: Ipv4Addr, gateway: Ipv4Addr, subnet: Ipv4Addr) -> Self {
|
pub fn new(mac: MacAddress, ip: Ipv4Addr, gateway: Ipv4Addr, subnet: Ipv4Addr) -> Self {
|
||||||
Self {
|
Self {
|
||||||
is_setup: false,
|
is_setup: false,
|
||||||
settings: HostConfig {
|
settings: HostConfig {
|
||||||
mac,
|
mac,
|
||||||
ip,
|
ip,
|
||||||
gateway,
|
gateway,
|
||||||
subnet,
|
subnet,
|
||||||
},
|
},
|
||||||
current: HostConfig::default(),
|
current: HostConfig::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Host for Manual {
|
impl Host for Manual {
|
||||||
/// Gets (if necessary) and sets the host settings on the chip
|
/// Gets (if necessary) and sets the host settings on the chip
|
||||||
fn refresh<SpiBus: Bus>(&mut self, bus: &mut SpiBus) -> Result<(), SpiBus::Error> {
|
fn refresh<SpiBus: Bus>(&mut self, bus: &mut SpiBus) -> Result<(), SpiBus::Error> {
|
||||||
if !self.is_setup {
|
if !self.is_setup {
|
||||||
Self::write_settings(bus, &mut self.current, &self.settings)?;
|
Self::write_settings(bus, &mut self.current, &self.settings)?;
|
||||||
self.is_setup = true;
|
self.is_setup = true;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
103
src/host/mod.rs
103
src/host/mod.rs
|
|
@ -3,68 +3,65 @@ use core::net::Ipv4Addr;
|
||||||
mod dhcp;
|
mod dhcp;
|
||||||
mod manual;
|
mod manual;
|
||||||
|
|
||||||
pub use self::dhcp::Dhcp;
|
pub use self::{dhcp::Dhcp, manual::Manual};
|
||||||
pub use self::manual::Manual;
|
use crate::{bus::Bus, register, MacAddress};
|
||||||
use crate::bus::Bus;
|
|
||||||
use crate::register;
|
|
||||||
use crate::MacAddress;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
pub struct HostConfig {
|
pub struct HostConfig {
|
||||||
mac: MacAddress,
|
mac: MacAddress,
|
||||||
#[cfg_attr(feature = "defmt", defmt(Display2Format))]
|
#[cfg_attr(feature = "defmt", defmt(Display2Format))]
|
||||||
ip: Ipv4Addr,
|
ip: Ipv4Addr,
|
||||||
#[cfg_attr(feature = "defmt", defmt(Display2Format))]
|
#[cfg_attr(feature = "defmt", defmt(Display2Format))]
|
||||||
gateway: Ipv4Addr,
|
gateway: Ipv4Addr,
|
||||||
#[cfg_attr(feature = "defmt", defmt(Display2Format))]
|
#[cfg_attr(feature = "defmt", defmt(Display2Format))]
|
||||||
subnet: Ipv4Addr,
|
subnet: Ipv4Addr,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for HostConfig {
|
impl Default for HostConfig {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
mac: MacAddress::default(),
|
mac: MacAddress::default(),
|
||||||
ip: Ipv4Addr::UNSPECIFIED,
|
ip: Ipv4Addr::UNSPECIFIED,
|
||||||
gateway: Ipv4Addr::UNSPECIFIED,
|
gateway: Ipv4Addr::UNSPECIFIED,
|
||||||
subnet: Ipv4Addr::UNSPECIFIED,
|
subnet: Ipv4Addr::UNSPECIFIED,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Host {
|
pub trait Host {
|
||||||
/// Gets (if necessary) and sets the host settings on the chip
|
/// Gets (if necessary) and sets the host settings on the chip
|
||||||
fn refresh<SpiBus: Bus>(&mut self, bus: &mut SpiBus) -> Result<(), SpiBus::Error>;
|
fn refresh<SpiBus: Bus>(&mut self, bus: &mut SpiBus) -> Result<(), SpiBus::Error>;
|
||||||
|
|
||||||
/// Write changed settings to chip
|
/// Write changed settings to chip
|
||||||
///
|
///
|
||||||
/// Will check all settings and write any new ones to the chip. Will update the settings returned by `current`
|
/// Will check all settings and write any new ones to the chip. Will update the settings returned by `current`
|
||||||
/// with any changes.
|
/// with any changes.
|
||||||
fn write_settings<SpiBus: Bus>(
|
fn write_settings<SpiBus: Bus>(
|
||||||
bus: &mut SpiBus,
|
bus: &mut SpiBus,
|
||||||
current: &mut HostConfig,
|
current: &mut HostConfig,
|
||||||
settings: &HostConfig,
|
settings: &HostConfig,
|
||||||
) -> Result<(), SpiBus::Error> {
|
) -> Result<(), SpiBus::Error> {
|
||||||
if settings.gateway != current.gateway {
|
if settings.gateway != current.gateway {
|
||||||
let address = settings.gateway.octets();
|
let address = settings.gateway.octets();
|
||||||
bus.write_frame(register::COMMON + register::common::GATEWAY, &address)?;
|
bus.write_frame(register::COMMON + register::common::GATEWAY, &address)?;
|
||||||
current.gateway = settings.gateway;
|
current.gateway = settings.gateway;
|
||||||
}
|
}
|
||||||
if settings.subnet != current.subnet {
|
if settings.subnet != current.subnet {
|
||||||
let address = settings.subnet.octets();
|
let address = settings.subnet.octets();
|
||||||
bus.write_frame(register::COMMON + register::common::SUBNET_MASK, &address)?;
|
bus.write_frame(register::COMMON + register::common::SUBNET_MASK, &address)?;
|
||||||
current.subnet = settings.subnet;
|
current.subnet = settings.subnet;
|
||||||
}
|
}
|
||||||
if settings.mac != current.mac {
|
if settings.mac != current.mac {
|
||||||
let address = settings.mac.octets;
|
let address = settings.mac.octets;
|
||||||
bus.write_frame(register::COMMON + register::common::MAC, &address)?;
|
bus.write_frame(register::COMMON + register::common::MAC, &address)?;
|
||||||
current.mac = settings.mac;
|
current.mac = settings.mac;
|
||||||
}
|
}
|
||||||
if settings.ip != current.ip {
|
if settings.ip != current.ip {
|
||||||
let address = settings.ip.octets();
|
let address = settings.ip.octets();
|
||||||
bus.write_frame(register::COMMON + register::common::IP, &address)?;
|
bus.write_frame(register::COMMON + register::common::IP, &address)?;
|
||||||
current.ip = settings.ip;
|
current.ip = settings.ip;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
118
src/lib.rs
118
src/lib.rs
|
|
@ -17,10 +17,10 @@ mod uninitialized_device;
|
||||||
|
|
||||||
#[doc(inline)]
|
#[doc(inline)]
|
||||||
pub use self::{
|
pub use self::{
|
||||||
device::{Device, DeviceState},
|
device::{Device, DeviceState},
|
||||||
host::{Dhcp, Host, HostConfig, Manual},
|
host::{Dhcp, Host, HostConfig, Manual},
|
||||||
net::MacAddress,
|
net::MacAddress,
|
||||||
uninitialized_device::{InitializeError, UninitializedDevice},
|
uninitialized_device::{InitializeError, UninitializedDevice},
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO add better docs to all public items, add unit tests.
|
// 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)]
|
#[derive(Copy, Clone, Debug, PartialOrd, PartialEq, Eq)]
|
||||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
pub enum OnPingRequest {
|
pub enum OnPingRequest {
|
||||||
/// 0: Disable Ping block
|
/// 0: Disable Ping block
|
||||||
Respond = 0b00000000,
|
Respond = 0b00000000,
|
||||||
/// 1 : Enable Ping block
|
/// 1 : Enable Ping block
|
||||||
///
|
///
|
||||||
/// If the bit is ‘1’, it blocks the response to a ping request.
|
/// If the bit is ‘1’, it blocks the response to a ping request.
|
||||||
Ignore = 0b00010000,
|
Ignore = 0b00010000,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Use [ConnectionType::PPoE] when talking
|
/// Use [ConnectionType::PPoE] when talking
|
||||||
|
|
@ -46,72 +46,72 @@ pub enum OnPingRequest {
|
||||||
#[derive(Copy, Clone, Debug, PartialOrd, PartialEq, Eq)]
|
#[derive(Copy, Clone, Debug, PartialOrd, PartialEq, Eq)]
|
||||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
pub enum ConnectionType {
|
pub enum ConnectionType {
|
||||||
PPoE = 0b00001000,
|
PPoE = 0b00001000,
|
||||||
Ethernet = 0b00000000,
|
Ethernet = 0b00000000,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
pub struct Mode {
|
pub struct Mode {
|
||||||
pub on_ping_request: OnPingRequest,
|
pub on_ping_request: OnPingRequest,
|
||||||
pub connection_type: ConnectionType,
|
pub connection_type: ConnectionType,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Mode {
|
impl Mode {
|
||||||
pub fn to_register(self) -> [u8; 1] {
|
pub fn to_register(self) -> [u8; 1] {
|
||||||
[self.to_u8()]
|
[self.to_u8()]
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_u8(self) -> u8 {
|
pub fn to_u8(self) -> u8 {
|
||||||
let mut register = 0;
|
let mut register = 0;
|
||||||
register |= self.on_ping_request as u8;
|
register |= self.on_ping_request as u8;
|
||||||
register |= self.connection_type as u8;
|
register |= self.connection_type as u8;
|
||||||
|
|
||||||
register
|
register
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Mode {
|
impl Default for Mode {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
on_ping_request: OnPingRequest::Respond,
|
on_ping_request: OnPingRequest::Respond,
|
||||||
connection_type: ConnectionType::Ethernet,
|
connection_type: ConnectionType::Ethernet,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use crate::Mode;
|
use crate::Mode;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_mode_register() {
|
fn test_mode_register() {
|
||||||
let ping_respond_and_force_arp = Mode {
|
let ping_respond_and_force_arp = Mode {
|
||||||
// Bit: 7 Reset (RST) should be 0
|
// Bit: 7 Reset (RST) should be 0
|
||||||
// Bit: 6 reserved
|
// Bit: 6 reserved
|
||||||
// Bit: 5 reserved
|
// Bit: 5 reserved
|
||||||
// Bit: 4 should be 0 - Disable Ping Block Mode
|
// Bit: 4 should be 0 - Disable Ping Block Mode
|
||||||
on_ping_request: crate::OnPingRequest::Respond,
|
on_ping_request: crate::OnPingRequest::Respond,
|
||||||
// Bit: 3 should be 0 - PPoE disabled
|
// Bit: 3 should be 0 - PPoE disabled
|
||||||
connection_type: crate::ConnectionType::Ethernet,
|
connection_type: crate::ConnectionType::Ethernet,
|
||||||
// Bit: 2 reserved
|
// Bit: 2 reserved
|
||||||
// Bit: 1 address auto-increment should be 0
|
// Bit: 1 address auto-increment should be 0
|
||||||
// Bit: 0 indirect bus I/F mode should be 0
|
// Bit: 0 indirect bus I/F mode should be 0
|
||||||
};
|
};
|
||||||
assert_eq!(0b0000_0000, ping_respond_and_force_arp.to_u8());
|
assert_eq!(0b0000_0000, ping_respond_and_force_arp.to_u8());
|
||||||
|
|
||||||
let all_enabled = Mode {
|
let all_enabled = Mode {
|
||||||
// Bit: 7 Reset (RST) should be 0
|
// Bit: 7 Reset (RST) should be 0
|
||||||
// Bit: 6 reserved
|
// Bit: 6 reserved
|
||||||
// Bit: 5 reserved
|
// Bit: 5 reserved
|
||||||
// Bit: 4 should be 0 - Disable Ping Block Mode
|
// Bit: 4 should be 0 - Disable Ping Block Mode
|
||||||
on_ping_request: crate::OnPingRequest::Respond,
|
on_ping_request: crate::OnPingRequest::Respond,
|
||||||
// Bit: 3 should be 1 - PPoE enable
|
// Bit: 3 should be 1 - PPoE enable
|
||||||
connection_type: crate::ConnectionType::PPoE,
|
connection_type: crate::ConnectionType::PPoE,
|
||||||
// Bit: 2 reserved
|
// Bit: 2 reserved
|
||||||
// Bit: 1 address auto-increment should be 0
|
// Bit: 1 address auto-increment should be 0
|
||||||
// Bit: 0 indirect bus I/F mode should be 0
|
// Bit: 0 indirect bus I/F mode should be 0
|
||||||
};
|
};
|
||||||
assert_eq!(0b0000_1000, all_enabled.to_u8());
|
assert_eq!(0b0000_1000, all_enabled.to_u8());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
160
src/net.rs
160
src/net.rs
|
|
@ -20,95 +20,95 @@ pub use core::net::Ipv4Addr;
|
||||||
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Hash, Default)]
|
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Hash, Default)]
|
||||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
pub struct MacAddress {
|
pub struct MacAddress {
|
||||||
/// Octets of the MAC address.
|
/// Octets of the MAC address.
|
||||||
pub octets: [u8; 6],
|
pub octets: [u8; 6],
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MacAddress {
|
impl MacAddress {
|
||||||
/// Creates a new EUI-48 MAC address from six eight-bit octets.
|
/// Creates a new EUI-48 MAC address from six eight-bit octets.
|
||||||
///
|
///
|
||||||
/// The result will represent the EUI-48 MAC address
|
/// The result will represent the EUI-48 MAC address
|
||||||
/// `a`:`b`:`c`:`d`:`e`:`f`.
|
/// `a`:`b`:`c`:`d`:`e`:`f`.
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use w5500::MacAddress;
|
/// use w5500::MacAddress;
|
||||||
///
|
///
|
||||||
/// let addr = MacAddress::new(0x00, 0x00, 0x5E, 0x00, 0x00, 0x00);
|
/// let addr = MacAddress::new(0x00, 0x00, 0x5E, 0x00, 0x00, 0x00);
|
||||||
/// ```
|
/// ```
|
||||||
#[allow(clippy::many_single_char_names)]
|
#[allow(clippy::many_single_char_names)]
|
||||||
pub const fn new(a: u8, b: u8, c: u8, d: u8, e: u8, f: u8) -> MacAddress {
|
pub const fn new(a: u8, b: u8, c: u8, d: u8, e: u8, f: u8) -> MacAddress {
|
||||||
MacAddress {
|
MacAddress {
|
||||||
octets: [a, b, c, d, e, f],
|
octets: [a, b, c, d, e, f],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the six eight-bit integers that make up this address.
|
/// Returns the six eight-bit integers that make up this address.
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use w5500::MacAddress;
|
/// use w5500::MacAddress;
|
||||||
///
|
///
|
||||||
/// let addr = MacAddress::new(13, 12, 11, 10, 15, 14);
|
/// let addr = MacAddress::new(13, 12, 11, 10, 15, 14);
|
||||||
/// assert_eq!([13u8, 12u8, 11u8, 10u8, 15u8, 14u8], addr.octets());
|
/// assert_eq!([13u8, 12u8, 11u8, 10u8, 15u8, 14u8], addr.octets());
|
||||||
/// ```
|
/// ```
|
||||||
pub const fn octets(&self) -> [u8; 6] {
|
pub const fn octets(&self) -> [u8; 6] {
|
||||||
[
|
[
|
||||||
self.octets[0],
|
self.octets[0],
|
||||||
self.octets[1],
|
self.octets[1],
|
||||||
self.octets[2],
|
self.octets[2],
|
||||||
self.octets[3],
|
self.octets[3],
|
||||||
self.octets[4],
|
self.octets[4],
|
||||||
self.octets[5],
|
self.octets[5],
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An EUI-48 MAC address representing an unspecified address:
|
/// An EUI-48 MAC address representing an unspecified address:
|
||||||
/// 00:00:00:00:00:00
|
/// 00:00:00:00:00:00
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use w5500::MacAddress;
|
/// use w5500::MacAddress;
|
||||||
///
|
///
|
||||||
/// let addr = MacAddress::UNSPECIFIED;
|
/// let addr = MacAddress::UNSPECIFIED;
|
||||||
/// assert_eq!(addr, MacAddress::new(0x00, 0x00, 0x00, 0x00, 0x00, 0x00));
|
/// assert_eq!(addr, MacAddress::new(0x00, 0x00, 0x00, 0x00, 0x00, 0x00));
|
||||||
/// ```
|
/// ```
|
||||||
pub const UNSPECIFIED: Self = MacAddress::new(0, 0, 0, 0, 0, 0);
|
pub const UNSPECIFIED: Self = MacAddress::new(0, 0, 0, 0, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<[u8; 6]> for MacAddress {
|
impl From<[u8; 6]> for MacAddress {
|
||||||
/// Creates an `Ipv4Addr` from a six element byte array.
|
/// Creates an `Ipv4Addr` from a six element byte array.
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use w5500::MacAddress;
|
/// use w5500::MacAddress;
|
||||||
///
|
///
|
||||||
/// let addr = MacAddress::from([13u8, 12u8, 11u8, 10u8, 15u8, 14u8]);
|
/// let addr = MacAddress::from([13u8, 12u8, 11u8, 10u8, 15u8, 14u8]);
|
||||||
/// assert_eq!(MacAddress::new(13, 12, 11, 10, 15, 14), addr);
|
/// assert_eq!(MacAddress::new(13, 12, 11, 10, 15, 14), addr);
|
||||||
/// ```
|
/// ```
|
||||||
fn from(octets: [u8; 6]) -> MacAddress {
|
fn from(octets: [u8; 6]) -> MacAddress {
|
||||||
MacAddress::new(
|
MacAddress::new(
|
||||||
octets[0], octets[1], octets[2], octets[3], octets[4], octets[5],
|
octets[0], octets[1], octets[2], octets[3], octets[4], octets[5],
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ::core::fmt::Display for MacAddress {
|
impl ::core::fmt::Display for MacAddress {
|
||||||
/// String formatter for MacAddress addresses.
|
/// String formatter for MacAddress addresses.
|
||||||
fn fmt(&self, fmt: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
|
fn fmt(&self, fmt: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
|
||||||
write!(
|
write!(
|
||||||
fmt,
|
fmt,
|
||||||
"{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}",
|
"{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}",
|
||||||
self.octets[0],
|
self.octets[0],
|
||||||
self.octets[1],
|
self.octets[1],
|
||||||
self.octets[2],
|
self.octets[2],
|
||||||
self.octets[3],
|
self.octets[3],
|
||||||
self.octets[4],
|
self.octets[4],
|
||||||
self.octets[5],
|
self.octets[5],
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,121 +4,114 @@ use crate::{bus::Bus, register, socket::Socket, uninitialized_device::Initialize
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
pub struct RawDevice<SpiBus: Bus> {
|
pub struct RawDevice<SpiBus: Bus> {
|
||||||
bus: SpiBus,
|
bus: SpiBus,
|
||||||
raw_socket: Socket,
|
raw_socket: Socket,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<SpiBus: Bus> RawDevice<SpiBus> {
|
impl<SpiBus: Bus> RawDevice<SpiBus> {
|
||||||
/// Create the raw device.
|
/// Create the raw device.
|
||||||
///
|
///
|
||||||
/// # Note
|
/// # Note
|
||||||
/// The device is configured with MAC filtering enabled.
|
/// The device is configured with MAC filtering enabled.
|
||||||
///
|
///
|
||||||
/// # Args
|
/// # Args
|
||||||
/// * `bus` - The bus to communicate with the device.
|
/// * `bus` - The bus to communicate with the device.
|
||||||
pub(crate) fn new(mut bus: SpiBus) -> Result<Self, InitializeError<SpiBus::Error>> {
|
pub(crate) fn new(mut bus: SpiBus) -> Result<Self, InitializeError<SpiBus::Error>> {
|
||||||
// Set the raw socket to 16KB RX/TX buffer space.
|
// Set the raw socket to 16KB RX/TX buffer space.
|
||||||
let raw_socket = Socket::new(0);
|
let raw_socket = Socket::new(0);
|
||||||
|
|
||||||
// Configure the chip in MACRAW mode with MAC filtering.
|
// Configure the chip in MACRAW mode with MAC filtering.
|
||||||
let mode: u8 = (1 << 6) | // MAC address filtering
|
let mode: u8 = (1 << 6) | // MAC address filtering
|
||||||
(register::socketn::Protocol::MacRaw as u8);
|
(register::socketn::Protocol::MacRaw as u8);
|
||||||
|
|
||||||
bus.write_frame(raw_socket.register() + register::socketn::MODE, &[mode])?;
|
bus.write_frame(raw_socket.register() + register::socketn::MODE, &[mode])?;
|
||||||
raw_socket.command(&mut bus, register::socketn::Command::Open)?;
|
raw_socket.command(&mut bus, register::socketn::Command::Open)?;
|
||||||
|
|
||||||
Ok(Self { bus, raw_socket })
|
Ok(Self { bus, raw_socket })
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Enable one or more interrupts
|
/// Enable one or more interrupts
|
||||||
pub fn enable_interrupts(&mut self) -> Result<(), SpiBus::Error> {
|
pub fn enable_interrupts(&mut self) -> Result<(), SpiBus::Error> {
|
||||||
self.bus.write_frame(
|
self.bus
|
||||||
register::COMMON +
|
.write_frame(register::COMMON + register::common::INTERRUPT_MASK, &[1])?;
|
||||||
register::common::INTERRUPT_MASK,
|
Ok(())
|
||||||
&[1],
|
}
|
||||||
)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Clear pending interrupts
|
/// Clear pending interrupts
|
||||||
///
|
///
|
||||||
/// If using RTIC or similar, this should be called from the
|
/// If using RTIC or similar, this should be called from the
|
||||||
/// interrupt handler. If not (i.e., if there's concern that this
|
/// 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
|
/// use of the SPI bus will clobber someone else's use), then you
|
||||||
/// can mask the interrupt *at microcontroller level* in the
|
/// can mask the interrupt *at microcontroller level* in the
|
||||||
/// interrupt handler, then call this from thread mode before
|
/// interrupt handler, then call this from thread mode before
|
||||||
/// unmasking again.
|
/// unmasking again.
|
||||||
pub fn clear_interrupts(&mut self) -> Result<(), SpiBus::Error> {
|
pub fn clear_interrupts(&mut self) -> Result<(), SpiBus::Error> {
|
||||||
self.raw_socket
|
self.raw_socket
|
||||||
.reset_interrupt(&mut self.bus, register::socketn::Interrupt::All)
|
.reset_interrupt(&mut self.bus, register::socketn::Interrupt::All)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Disable all interrupts
|
/// Disable all interrupts
|
||||||
///
|
pub fn disable_interrupts(&mut self) -> Result<(), SpiBus::Error> {
|
||||||
pub fn disable_interrupts(&mut self) -> Result<(), SpiBus::Error> {
|
self.bus
|
||||||
self.bus.write_frame(
|
.write_frame(register::COMMON + register::common::INTERRUPT_MASK, &[0])?;
|
||||||
register::COMMON +
|
Ok(())
|
||||||
register::common::INTERRUPT_MASK,
|
}
|
||||||
&[0],
|
|
||||||
)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Read an ethernet frame from the device.
|
/// Read an ethernet frame from the device.
|
||||||
///
|
///
|
||||||
/// # Args
|
/// # Args
|
||||||
/// * `frame` - The location to store the received frame
|
/// * `frame` - The location to store the received frame
|
||||||
///
|
///
|
||||||
/// # Returns
|
/// # Returns
|
||||||
/// The number of bytes read into the provided frame buffer.
|
/// The number of bytes read into the provided frame buffer.
|
||||||
pub fn read_frame(&mut self, frame: &mut [u8]) -> Result<usize, SpiBus::Error> {
|
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)?;
|
let mut rx_cursor = crate::cursor::RxCursor::new(&self.raw_socket, &mut self.bus)?;
|
||||||
|
|
||||||
// Check if there is anything to receive.
|
// Check if there is anything to receive.
|
||||||
if rx_cursor.available() == 0 {
|
if rx_cursor.available() == 0 {
|
||||||
return Ok(0);
|
return Ok(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// The W5500 specifies the size of the received ethernet frame in the first two bytes.
|
// 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.
|
// Refer to https://forum.wiznet.io/t/topic/979/2 for more information.
|
||||||
let expected_frame_size = {
|
let expected_frame_size = {
|
||||||
let mut frame_bytes = [0u8; 2];
|
let mut frame_bytes = [0u8; 2];
|
||||||
assert!(rx_cursor.read(&mut frame_bytes[..])? == 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)?;
|
let received_frame_size = rx_cursor.read_upto(frame, expected_frame_size)?;
|
||||||
if received_frame_size < expected_frame_size {
|
if received_frame_size < expected_frame_size {
|
||||||
rx_cursor.skip(expected_frame_size - received_frame_size);
|
rx_cursor.skip(expected_frame_size - received_frame_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
rx_cursor.commit()?;
|
rx_cursor.commit()?;
|
||||||
Ok(received_frame_size as _)
|
Ok(received_frame_size as _)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Write an ethernet frame to the device.
|
/// Write an ethernet frame to the device.
|
||||||
///
|
///
|
||||||
/// # Args
|
/// # Args
|
||||||
/// * `frame` - The ethernet frame to transmit.
|
/// * `frame` - The ethernet frame to transmit.
|
||||||
///
|
///
|
||||||
/// # Returns
|
/// # Returns
|
||||||
/// The number of bytes successfully transmitted from the provided buffer.
|
/// The number of bytes successfully transmitted from the provided buffer.
|
||||||
pub fn write_frame(&mut self, frame: &[u8]) -> Result<usize, SpiBus::Error> {
|
pub fn write_frame(&mut self, frame: &[u8]) -> Result<usize, SpiBus::Error> {
|
||||||
// Reset the transmission complete flag, we'll wait on it later.
|
// Reset the transmission complete flag, we'll wait on it later.
|
||||||
self.raw_socket
|
self.raw_socket
|
||||||
.reset_interrupt(&mut self.bus, register::socketn::Interrupt::SendOk)?;
|
.reset_interrupt(&mut self.bus, register::socketn::Interrupt::SendOk)?;
|
||||||
|
|
||||||
let mut tx_cursor = crate::cursor::TxCursor::new(&self.raw_socket, &mut self.bus)?;
|
let mut tx_cursor = crate::cursor::TxCursor::new(&self.raw_socket, &mut self.bus)?;
|
||||||
let count = tx_cursor.write(frame)?;
|
let count = tx_cursor.write(frame)?;
|
||||||
tx_cursor.commit()?;
|
tx_cursor.commit()?;
|
||||||
|
|
||||||
// Wait for the socket transmission to complete.
|
// Wait for the socket transmission to complete.
|
||||||
while !self
|
while !self
|
||||||
.raw_socket
|
.raw_socket
|
||||||
.has_interrupt(&mut self.bus, register::socketn::Interrupt::SendOk)?
|
.has_interrupt(&mut self.bus, register::socketn::Interrupt::SendOk)?
|
||||||
{}
|
{}
|
||||||
|
|
||||||
Ok(count as _)
|
Ok(count as _)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
499
src/register.rs
499
src/register.rs
|
|
@ -3,299 +3,298 @@
|
||||||
// TODO change from u8 to a custom struct implementing a trait.
|
// TODO change from u8 to a custom struct implementing a trait.
|
||||||
pub const COMMON: u16 = 0;
|
pub const COMMON: u16 = 0;
|
||||||
pub mod common {
|
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]
|
/// Register: GAR (Gateway IP Address Register) [R/W] [0x0001 – 0x0004] [0x00]
|
||||||
pub const GATEWAY: u16 = 0x01;
|
pub const GATEWAY: u16 = 0x01;
|
||||||
|
|
||||||
/// Register: SUBR (Subnet Mask Register) [R/W] [0x0005 – 0x0008] [0x00]
|
/// Register: SUBR (Subnet Mask Register) [R/W] [0x0005 – 0x0008] [0x00]
|
||||||
pub const SUBNET_MASK: u16 = 0x05;
|
pub const SUBNET_MASK: u16 = 0x05;
|
||||||
|
|
||||||
/// Register: SHAR (Source Hardware Address Register) [R/W] [0x0009 – 0x000E] [0x00]
|
/// Register: SHAR (Source Hardware Address Register) [R/W] [0x0009 – 0x000E] [0x00]
|
||||||
pub const MAC: u16 = 0x09;
|
pub const MAC: u16 = 0x09;
|
||||||
|
|
||||||
/// Register: SIPR (Source IP Address Register) [R/W] [0x000F – 0x0012] [0x00]
|
/// Register: SIPR (Source IP Address Register) [R/W] [0x000F – 0x0012] [0x00]
|
||||||
pub const IP: u16 = 0x0F;
|
pub const IP: u16 = 0x0F;
|
||||||
|
|
||||||
/// Register: IMR (Interrupt Mask Register) [R/W] [0x0016 – 0x001A] [0x07D0]
|
/// Register: IMR (Interrupt Mask Register) [R/W] [0x0016 – 0x001A] [0x07D0]
|
||||||
pub const INTERRUPT_MASK: u16 = 0x16;
|
pub const INTERRUPT_MASK: u16 = 0x16;
|
||||||
|
|
||||||
/// Register: RTR (Retry Time-value Register) [R/W] [0x0019 – 0x001A] [0x07D0]
|
/// Register: RTR (Retry Time-value Register) [R/W] [0x0019 – 0x001A] [0x07D0]
|
||||||
pub const RETRY_TIME: u16 = 0x17;
|
pub const RETRY_TIME: u16 = 0x17;
|
||||||
|
|
||||||
/// Register: RCR (Retry Count Register) [R/W] [0x001B] [0x08]
|
/// Register: RCR (Retry Count Register) [R/W] [0x001B] [0x08]
|
||||||
pub const RETRY_COUNT: u16 = 0x19;
|
pub const RETRY_COUNT: u16 = 0x19;
|
||||||
|
|
||||||
/// Register: RCR (Retry Count Register) [R/W] [0x001B] [0x08]
|
/// Register: RCR (Retry Count Register) [R/W] [0x001B] [0x08]
|
||||||
pub const RX_MEMORY_SIZE: u16 = 0x1A;
|
pub const RX_MEMORY_SIZE: u16 = 0x1A;
|
||||||
|
|
||||||
/// Register: RCR (Retry Count Register) [R/W] [0x001B] [0x08]
|
/// Register: RCR (Retry Count Register) [R/W] [0x001B] [0x08]
|
||||||
pub const TX_MEMORY_SIZE: u16 = 0x1B;
|
pub const TX_MEMORY_SIZE: u16 = 0x1B;
|
||||||
|
|
||||||
/// A Retry Time-value
|
/// A Retry Time-value
|
||||||
///
|
///
|
||||||
/// RTR (Retry Time-value Register) [R/W] [0x0019 – 0x001A] [0x07D0]
|
/// RTR (Retry Time-value Register) [R/W] [0x0019 – 0x001A] [0x07D0]
|
||||||
///
|
///
|
||||||
/// From datasheet:
|
/// From datasheet:
|
||||||
///
|
///
|
||||||
/// RTR configures the retransmission timeout period. The unit of timeout period is
|
/// 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
|
/// 100us and the default of RTR is ‘0x07D0’ or ‘2000’. And so the default timeout period
|
||||||
/// is 200ms(100us X 2000).
|
/// is 200ms(100us X 2000).
|
||||||
/// During the time configured by RTR, W5500 waits for the peer response to the packet
|
/// 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
|
/// 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
|
/// command). If the peer does not respond within the RTR time, W5500 retransmits the
|
||||||
/// packet or issues timeout.
|
/// packet or issues timeout.
|
||||||
///
|
///
|
||||||
///
|
///
|
||||||
/// > Ex) When timeout-period is set as 400ms, RTR = (400ms / 1ms) X 10 = 4000(0x0FA0)
|
/// > Ex) When timeout-period is set as 400ms, RTR = (400ms / 1ms) X 10 = 4000(0x0FA0)
|
||||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
|
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
|
||||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
pub struct RetryTime(pub(crate) u16);
|
pub struct RetryTime(pub(crate) u16);
|
||||||
|
|
||||||
impl RetryTime {
|
impl RetryTime {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn to_u16(&self) -> u16 {
|
pub fn to_u16(&self) -> u16 {
|
||||||
self.0
|
self.0
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn to_register(&self) -> [u8; 2] {
|
pub fn to_register(&self) -> [u8; 2] {
|
||||||
self.0.to_be_bytes()
|
self.0.to_be_bytes()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn from_register(register: [u8; 2]) -> Self {
|
pub fn from_register(register: [u8; 2]) -> Self {
|
||||||
Self(u16::from_be_bytes(register))
|
Self(u16::from_be_bytes(register))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn from_millis(milliseconds: u16) -> Self {
|
pub fn from_millis(milliseconds: u16) -> Self {
|
||||||
Self(milliseconds * 10)
|
Self(milliseconds * 10)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn to_millis(&self) -> u16 {
|
pub fn to_millis(&self) -> u16 {
|
||||||
self.0 / 10
|
self.0 / 10
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for RetryTime {
|
impl Default for RetryTime {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self::from_millis(200)
|
Self::from_millis(200)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod socketn {
|
pub mod socketn {
|
||||||
use derive_try_from_primitive::TryFromPrimitive;
|
use derive_try_from_primitive::TryFromPrimitive;
|
||||||
|
|
||||||
/// The Protocol mode
|
/// The Protocol mode
|
||||||
pub const MODE: u16 = 0x00;
|
pub const MODE: u16 = 0x00;
|
||||||
|
|
||||||
/// The protocol modes that can be used with the `w5500`
|
/// The protocol modes that can be used with the `w5500`
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
pub enum Protocol {
|
pub enum Protocol {
|
||||||
Closed = 0b00,
|
Closed = 0b00,
|
||||||
Tcp = 0b01,
|
Tcp = 0b01,
|
||||||
Udp = 0b10,
|
Udp = 0b10,
|
||||||
IpRaw = 0b11,
|
IpRaw = 0b11,
|
||||||
MacRaw = 0b100,
|
MacRaw = 0b100,
|
||||||
PPoE = 0b101,
|
PPoE = 0b101,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Socket n Command Register
|
/// Socket n Command Register
|
||||||
///
|
///
|
||||||
/// `Sn_CR`
|
/// `Sn_CR`
|
||||||
pub const COMMAND: u16 = 0x01;
|
pub const COMMAND: u16 = 0x01;
|
||||||
|
|
||||||
/// Socket n Commands
|
/// Socket n Commands
|
||||||
///
|
///
|
||||||
/// `Sn_CR` register
|
/// `Sn_CR` register
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
pub enum Command {
|
pub enum Command {
|
||||||
Open = 0x01,
|
Open = 0x01,
|
||||||
/// [Datasheet page 46](https://docs.wiznet.io/img/products/w5500/W5500_ds_v110e.pdf):
|
/// [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
|
/// > 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-
|
/// > mode, Socket n operates as a ‘TCP server’ and waits for connection-
|
||||||
/// > request (SYN packet) from any ‘TCP client
|
/// > request (SYN packet) from any ‘TCP client
|
||||||
Listen = 0x02,
|
Listen = 0x02,
|
||||||
Connect = 0x04,
|
Connect = 0x04,
|
||||||
Discon = 0x08,
|
Discon = 0x08,
|
||||||
Close = 0x10,
|
Close = 0x10,
|
||||||
Send = 0x20,
|
Send = 0x20,
|
||||||
|
|
||||||
/// [Datasheet page 48](https://docs.wiznet.io/img/products/w5500/W5500_ds_v110e.pdf):
|
/// [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
|
/// > RECV completes the processing of the received data in Socket n RX
|
||||||
/// > Buffer by using a RX read pointer register (Sn_RX_RD).
|
/// > Buffer by using a RX read pointer register (Sn_RX_RD).
|
||||||
/// > For more details, refer to Socket n RX Received Size Register
|
/// > For more details, refer to Socket n RX Received Size Register
|
||||||
/// > (Sn_RX_RSR), Socket n RX Write Pointer Register (Sn_RX_WR), and
|
/// > (Sn_RX_RSR), Socket n RX Write Pointer Register (Sn_RX_WR), and
|
||||||
/// > Socket n RX Read Pointer Register (Sn_RX_RD).
|
/// > Socket n RX Read Pointer Register (Sn_RX_RD).
|
||||||
Receive = 0x40,
|
Receive = 0x40,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const INTERRUPT: u16 = 0x02;
|
pub const INTERRUPT: u16 = 0x02;
|
||||||
/// | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|
/// | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|
||||||
/// | Reserved | Reserved | Reserved | SEND_OK | TIMEOUT | RECV | DISCON | CON |
|
/// | Reserved | Reserved | Reserved | SEND_OK | TIMEOUT | RECV | DISCON | CON |
|
||||||
///
|
///
|
||||||
/// | Bit | Symbol | Description |
|
/// | Bit | Symbol | Description |
|
||||||
/// | 7~5 | Reserved | Reserved |
|
/// | 7~5 | Reserved | Reserved |
|
||||||
/// | 4 | SENDOK | Sn_IR(SENDOK) | Interrupt Mask |
|
/// | 4 | SENDOK | Sn_IR(SENDOK) | Interrupt Mask |
|
||||||
/// | 3 | TIMEOUT | Sn_IR(TIMEOUT) | Interrupt Mask |
|
/// | 3 | TIMEOUT | Sn_IR(TIMEOUT) | Interrupt Mask |
|
||||||
/// | 2 | RECV | Sn_IR(RECV) | Interrupt Mask |
|
/// | 2 | RECV | Sn_IR(RECV) | Interrupt Mask |
|
||||||
/// | 1 | DISCON | Sn_IR(DISCON) | Interrupt Mask |
|
/// | 1 | DISCON | Sn_IR(DISCON) | Interrupt Mask |
|
||||||
/// | 0 | CON | Sn_IR(CON) | Interrupt Mask |
|
/// | 0 | CON | Sn_IR(CON) | Interrupt Mask |
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
pub enum Interrupt {
|
pub enum Interrupt {
|
||||||
All = 0b11111u8,
|
All = 0b11111u8,
|
||||||
SendOk = 0b10000u8,
|
SendOk = 0b10000u8,
|
||||||
Timeout = 0b1000u8,
|
Timeout = 0b1000u8,
|
||||||
|
|
||||||
/// Receive data
|
/// Receive data
|
||||||
///
|
///
|
||||||
/// bit 2, symbol `RECV`, `Sn_IR(RECV) Interrupt Mask`
|
/// bit 2, symbol `RECV`, `Sn_IR(RECV) Interrupt Mask`
|
||||||
Receive = 0b100u8,
|
Receive = 0b100u8,
|
||||||
|
|
||||||
/// Disconnect
|
/// Disconnect
|
||||||
///
|
///
|
||||||
/// bit 1, symbol `DISCON`, `Sn_IR(DISCON) Interrupt Mask`
|
/// bit 1, symbol `DISCON`, `Sn_IR(DISCON) Interrupt Mask`
|
||||||
Disconnect = 0b10u8,
|
Disconnect = 0b10u8,
|
||||||
|
|
||||||
/// Connect
|
/// Connect
|
||||||
///
|
///
|
||||||
/// bit 0, symbol `CON`, `Sn_IR(CON) Interrupt Mask`
|
/// bit 0, symbol `CON`, `Sn_IR(CON) Interrupt Mask`
|
||||||
Connect = 0b1u8,
|
Connect = 0b1u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const STATUS: u16 = 0x03;
|
pub const STATUS: u16 = 0x03;
|
||||||
|
|
||||||
/// Socket status register
|
/// Socket status register
|
||||||
///
|
///
|
||||||
/// `W5500 Datasheet Version 1.1.0` page 49:
|
/// `W5500 Datasheet Version 1.1.0` page 49:
|
||||||
///
|
///
|
||||||
/// > Sn_SR (Socket n Status Register) [R] [0x0003] [0x00]
|
/// > Sn_SR (Socket n Status Register) [R] [0x0003] [0x00]
|
||||||
///
|
///
|
||||||
/// - 0x18 SOCK_FIN_WAIT
|
/// - 0x18 SOCK_FIN_WAIT
|
||||||
/// - 0x1A SOCK_CLOSING
|
/// - 0x1A SOCK_CLOSING
|
||||||
/// - 0X1B SOCK_TIME_WAIT
|
/// - 0X1B SOCK_TIME_WAIT
|
||||||
/// > These indicate Socket n is closing.
|
/// > These indicate Socket n is closing.
|
||||||
/// > These are shown in disconnect-process such as active-close
|
/// > These are shown in disconnect-process such as active-close
|
||||||
/// > and passive-close.
|
/// > and passive-close.
|
||||||
/// > When Disconnect-process is successfully completed, or
|
/// > When Disconnect-process is successfully completed, or
|
||||||
/// > when timeout occurs, these change to SOCK_CLOSED.
|
/// > when timeout occurs, these change to SOCK_CLOSED.
|
||||||
///
|
#[derive(TryFromPrimitive, Debug, Copy, Clone, PartialEq, Eq)]
|
||||||
#[derive(TryFromPrimitive, Debug, Copy, Clone, PartialEq, Eq)]
|
#[repr(u8)]
|
||||||
#[repr(u8)]
|
pub enum Status {
|
||||||
pub enum Status {
|
Closed = 0x00,
|
||||||
Closed = 0x00,
|
Init = 0x13,
|
||||||
Init = 0x13,
|
|
||||||
|
|
||||||
/// [Datasheet page 49](https://docs.wiznet.io/img/products/w5500/W5500_ds_v110e.pdf):
|
/// [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
|
/// > This indicates Socket n is operating as ‘TCP server’ mode and
|
||||||
/// > waiting for connection-request (SYN packet) from a peer
|
/// > waiting for connection-request (SYN packet) from a peer
|
||||||
/// > (‘TCP client’).
|
/// > (‘TCP client’).
|
||||||
Listen = 0x14,
|
Listen = 0x14,
|
||||||
Established = 0x17,
|
Established = 0x17,
|
||||||
CloseWait = 0x1c,
|
CloseWait = 0x1c,
|
||||||
Udp = 0x22,
|
Udp = 0x22,
|
||||||
IpRaw = 0x32,
|
IpRaw = 0x32,
|
||||||
MacRaw = 0x42,
|
MacRaw = 0x42,
|
||||||
PPoE = 0x5f,
|
PPoE = 0x5f,
|
||||||
|
|
||||||
// Transient states.
|
// Transient states.
|
||||||
SynSent = 0x15,
|
SynSent = 0x15,
|
||||||
SynRecv = 0x16,
|
SynRecv = 0x16,
|
||||||
FinWait = 0x18,
|
FinWait = 0x18,
|
||||||
Closing = 0x1a,
|
Closing = 0x1a,
|
||||||
TimeWait = 0x1b,
|
TimeWait = 0x1b,
|
||||||
LastAck = 0x1d,
|
LastAck = 0x1d,
|
||||||
Arp = 0x01,
|
Arp = 0x01,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "defmt")]
|
#[cfg(feature = "defmt")]
|
||||||
impl defmt::Format for Status {
|
impl defmt::Format for Status {
|
||||||
fn format(&self, fmt: defmt::Formatter) {
|
fn format(&self, fmt: defmt::Formatter) {
|
||||||
// Format as hexadecimal.
|
// Format as hexadecimal.
|
||||||
defmt::write!(
|
defmt::write!(
|
||||||
fmt,
|
fmt,
|
||||||
"Status::{} ({=u8:#x})",
|
"Status::{} ({=u8:#x})",
|
||||||
defmt::Debug2Format(self),
|
defmt::Debug2Format(self),
|
||||||
*self as u8
|
*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
|
/// TX Free Size Register
|
||||||
///
|
///
|
||||||
/// `Sn_TX_FSR`
|
/// `Sn_TX_FSR`
|
||||||
///
|
///
|
||||||
/// Socket n TX Free Size
|
/// Socket n TX Free Size
|
||||||
///
|
///
|
||||||
/// offset (register)
|
/// offset (register)
|
||||||
/// 0x0020 (Sn_TX_FSR0)
|
/// 0x0020 (Sn_TX_FSR0)
|
||||||
/// 0x0021 (Sn_TX_FSR1)
|
/// 0x0021 (Sn_TX_FSR1)
|
||||||
pub const TX_FREE_SIZE: u16 = 0x20;
|
pub const TX_FREE_SIZE: u16 = 0x20;
|
||||||
|
|
||||||
/// Socket n TX Read Pointer
|
/// Socket n TX Read Pointer
|
||||||
///
|
///
|
||||||
/// offset (register)
|
/// offset (register)
|
||||||
/// 0x0022 (Sn_TX_RD0)
|
/// 0x0022 (Sn_TX_RD0)
|
||||||
/// 0x0023 (Sn_TX_RD1)
|
/// 0x0023 (Sn_TX_RD1)
|
||||||
pub const TX_DATA_READ_POINTER: u16 = 0x22;
|
pub const TX_DATA_READ_POINTER: u16 = 0x22;
|
||||||
|
|
||||||
/// Socket n TX Write Pointer
|
/// Socket n TX Write Pointer
|
||||||
///
|
///
|
||||||
/// offset (register)
|
/// offset (register)
|
||||||
/// 0x0024 (Sn_TX_WR0)
|
/// 0x0024 (Sn_TX_WR0)
|
||||||
/// 0x0025 (Sn_TX_WR1)
|
/// 0x0025 (Sn_TX_WR1)
|
||||||
///
|
///
|
||||||
/// [Datasheet page 54](https://docs.wiznet.io/img/products/w5500/W5500_ds_v110e.pdf):
|
/// [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 (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
|
/// > 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.
|
/// > mode(‘0001’), it is re-initialized while connecting with TCP.
|
||||||
/// > It should be read or to be updated like as follows.
|
/// > It should be read or to be updated like as follows.
|
||||||
/// > 1. Read the starting address for saving the transmitting data.
|
/// > 1. Read the starting address for saving the transmitting data.
|
||||||
/// > 2. Save the transmitting data from the starting address of Socket n TX
|
/// > 2. Save the transmitting data from the starting address of Socket n TX
|
||||||
/// > buffer.
|
/// > buffer.
|
||||||
/// > 3. After saving the transmitting data, update Sn_TX_WR to the
|
/// > 3. After saving the transmitting data, update Sn_TX_WR to the
|
||||||
/// > increased value as many as transmitting data size. If the increment value
|
/// > increased value as many as transmitting data size. If the increment value
|
||||||
/// > exceeds the maximum value 0xFFFF(greater than 0x10000 and the carry
|
/// > exceeds the maximum value 0xFFFF(greater than 0x10000 and the carry
|
||||||
/// > bit occurs), then the carry bit is ignored and will automatically update
|
/// > bit occurs), then the carry bit is ignored and will automatically update
|
||||||
/// > with the lower 16bits value.
|
/// > with the lower 16bits value.
|
||||||
/// > 4. Transmit the saved data in Socket n TX Buffer by using SEND/SEND
|
/// > 4. Transmit the saved data in Socket n TX Buffer by using SEND/SEND
|
||||||
/// > command
|
/// > command
|
||||||
pub const TX_DATA_WRITE_POINTER: u16 = 0x24;
|
pub const TX_DATA_WRITE_POINTER: u16 = 0x24;
|
||||||
|
|
||||||
/// Socket n Received Size Register
|
/// Socket n Received Size Register
|
||||||
///
|
///
|
||||||
/// `Sn_RX_RSR`
|
/// `Sn_RX_RSR`
|
||||||
pub const RECEIVED_SIZE: u16 = 0x26;
|
pub const RECEIVED_SIZE: u16 = 0x26;
|
||||||
|
|
||||||
pub const RX_DATA_READ_POINTER: u16 = 0x28;
|
pub const RX_DATA_READ_POINTER: u16 = 0x28;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use core::convert::TryFrom;
|
use core::convert::TryFrom;
|
||||||
|
|
||||||
use super::Status;
|
use super::Status;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_status_from_byte() {
|
fn test_status_from_byte() {
|
||||||
let udp = 0x22_u8;
|
let udp = 0x22_u8;
|
||||||
let status = Status::try_from(udp).expect("Should parse to Status");
|
let status = Status::try_from(udp).expect("Should parse to Status");
|
||||||
assert_eq!(status, Status::Udp);
|
assert_eq!(status, Status::Udp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
363
src/socket.rs
363
src/socket.rs
|
|
@ -1,216 +1,209 @@
|
||||||
use core::convert::TryFrom;
|
use core::{convert::TryFrom, net::Ipv4Addr};
|
||||||
use core::net::Ipv4Addr;
|
|
||||||
|
|
||||||
use crate::bus::Bus;
|
use crate::{
|
||||||
use crate::register::{self, socketn};
|
bus::Bus,
|
||||||
|
register::{self, socketn},
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
pub struct Socket {
|
pub struct Socket {
|
||||||
pub index: u8,
|
pub index: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Socket {
|
impl Socket {
|
||||||
/// 4 sockets available on the w5100
|
/// 4 sockets available on the w5100
|
||||||
pub fn new(index: u8) -> Self {
|
pub fn new(index: u8) -> Self {
|
||||||
Socket {
|
Socket { index }
|
||||||
index,
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn register(&self) -> u16 {
|
pub fn register(&self) -> u16 {
|
||||||
self.index as u16 * 0x100 + 0x400
|
self.index as u16 * 0x100 + 0x400
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_mode<SpiBus: Bus>(
|
pub fn set_mode<SpiBus: Bus>(
|
||||||
&self,
|
&self,
|
||||||
bus: &mut SpiBus,
|
bus: &mut SpiBus,
|
||||||
mode: socketn::Protocol,
|
mode: socketn::Protocol,
|
||||||
) -> Result<(), SpiBus::Error> {
|
) -> Result<(), SpiBus::Error> {
|
||||||
let mode = [mode as u8];
|
let mode = [mode as u8];
|
||||||
bus.write_frame(self.register() + socketn::MODE, &mode)?;
|
bus.write_frame(self.register() + socketn::MODE, &mode)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_mode<SpiBus: Bus>(
|
pub fn get_mode<SpiBus: Bus>(&self, bus: &mut SpiBus) -> Result<u8, SpiBus::Error> {
|
||||||
&self,
|
let mut mode = [0];
|
||||||
bus: &mut SpiBus,
|
bus.write_frame(self.register() + socketn::MODE, &mode)?;
|
||||||
) -> Result<u8, SpiBus::Error> {
|
Ok(mode[0])
|
||||||
let mut mode = [0];
|
}
|
||||||
bus.write_frame(self.register() + socketn::MODE, &mut mode)?;
|
|
||||||
Ok(mode[0])
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_status<SpiBus: Bus>(&self, bus: &mut SpiBus) -> Result<u8, SpiBus::Error> {
|
pub fn get_status<SpiBus: Bus>(&self, bus: &mut SpiBus) -> Result<u8, SpiBus::Error> {
|
||||||
let mut data = [0u8];
|
let mut data = [0u8];
|
||||||
bus.read_frame(self.register() + socketn::STATUS, &mut data)?;
|
bus.read_frame(self.register() + socketn::STATUS, &mut data)?;
|
||||||
Ok(data[0])
|
Ok(data[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn reset_interrupt<SpiBus: Bus>(
|
pub fn reset_interrupt<SpiBus: Bus>(
|
||||||
&self,
|
&self,
|
||||||
bus: &mut SpiBus,
|
bus: &mut SpiBus,
|
||||||
code: socketn::Interrupt,
|
code: socketn::Interrupt,
|
||||||
) -> Result<(), SpiBus::Error> {
|
) -> Result<(), SpiBus::Error> {
|
||||||
let data = [code as u8];
|
let data = [code as u8];
|
||||||
bus.write_frame(self.register() + socketn::INTERRUPT, &data)?;
|
bus.write_frame(self.register() + socketn::INTERRUPT, &data)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn has_interrupt<SpiBus: Bus>(
|
pub fn has_interrupt<SpiBus: Bus>(
|
||||||
&self,
|
&self,
|
||||||
bus: &mut SpiBus,
|
bus: &mut SpiBus,
|
||||||
code: socketn::Interrupt,
|
code: socketn::Interrupt,
|
||||||
) -> Result<bool, SpiBus::Error> {
|
) -> Result<bool, SpiBus::Error> {
|
||||||
let mut data = [0u8];
|
let mut data = [0u8];
|
||||||
bus.read_frame(self.register() + socketn::INTERRUPT, &mut data)?;
|
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>(
|
pub fn set_source_port<SpiBus: Bus>(
|
||||||
&self,
|
&self,
|
||||||
bus: &mut SpiBus,
|
bus: &mut SpiBus,
|
||||||
port: u16,
|
port: u16,
|
||||||
) -> Result<(), SpiBus::Error> {
|
) -> Result<(), SpiBus::Error> {
|
||||||
let data = port.to_be_bytes();
|
let data = port.to_be_bytes();
|
||||||
bus.write_frame(self.register() + socketn::SOURCE_PORT, &data)?;
|
bus.write_frame(self.register() + socketn::SOURCE_PORT, &data)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_source_port<SpiBus: Bus>(
|
pub fn get_source_port<SpiBus: Bus>(&self, bus: &mut SpiBus) -> Result<u16, SpiBus::Error> {
|
||||||
&self,
|
let mut data = [0; 2];
|
||||||
bus: &mut SpiBus,
|
bus.read_frame(self.register() + socketn::SOURCE_PORT, &mut data)?;
|
||||||
) -> Result<u16, SpiBus::Error> {
|
Ok(u16::from_be_bytes(data))
|
||||||
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>(
|
pub fn set_destination_ip<SpiBus: Bus>(
|
||||||
&self,
|
&self,
|
||||||
bus: &mut SpiBus,
|
bus: &mut SpiBus,
|
||||||
ip: Ipv4Addr,
|
ip: Ipv4Addr,
|
||||||
) -> Result<(), SpiBus::Error> {
|
) -> Result<(), SpiBus::Error> {
|
||||||
let data = ip.octets();
|
let data = ip.octets();
|
||||||
bus.write_frame(self.register() + socketn::DESTINATION_IP, &data)?;
|
bus.write_frame(self.register() + socketn::DESTINATION_IP, &data)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_destination_port<SpiBus: Bus>(
|
pub fn set_destination_port<SpiBus: Bus>(
|
||||||
&self,
|
&self,
|
||||||
bus: &mut SpiBus,
|
bus: &mut SpiBus,
|
||||||
port: u16,
|
port: u16,
|
||||||
) -> Result<(), SpiBus::Error> {
|
) -> Result<(), SpiBus::Error> {
|
||||||
let data = port.to_be_bytes();
|
let data = port.to_be_bytes();
|
||||||
bus.write_frame(self.register() + socketn::DESTINATION_PORT, &data)?;
|
bus.write_frame(self.register() + socketn::DESTINATION_PORT, &data)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_tx_read_pointer<SpiBus: Bus>(&self, bus: &mut SpiBus) -> Result<u16, SpiBus::Error> {
|
pub fn get_tx_read_pointer<SpiBus: Bus>(&self, bus: &mut SpiBus) -> Result<u16, SpiBus::Error> {
|
||||||
let mut data = [0u8; 2];
|
let mut data = [0u8; 2];
|
||||||
bus.read_frame(self.register() + socketn::TX_DATA_READ_POINTER, &mut data)?;
|
bus.read_frame(self.register() + socketn::TX_DATA_READ_POINTER, &mut data)?;
|
||||||
Ok(u16::from_be_bytes(data))
|
Ok(u16::from_be_bytes(data))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_tx_read_pointer<SpiBus: Bus>(
|
pub fn set_tx_read_pointer<SpiBus: Bus>(
|
||||||
&self,
|
&self,
|
||||||
bus: &mut SpiBus,
|
bus: &mut SpiBus,
|
||||||
pointer: u16,
|
pointer: u16,
|
||||||
) -> Result<(), SpiBus::Error> {
|
) -> Result<(), SpiBus::Error> {
|
||||||
let data = pointer.to_be_bytes();
|
let data = pointer.to_be_bytes();
|
||||||
bus.write_frame(self.register() + socketn::TX_DATA_READ_POINTER, &data)?;
|
bus.write_frame(self.register() + socketn::TX_DATA_READ_POINTER, &data)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_tx_write_pointer<SpiBus: Bus>(
|
pub fn get_tx_write_pointer<SpiBus: Bus>(
|
||||||
&self,
|
&self,
|
||||||
bus: &mut SpiBus,
|
bus: &mut SpiBus,
|
||||||
) -> Result<u16, SpiBus::Error> {
|
) -> Result<u16, SpiBus::Error> {
|
||||||
let mut data = [0u8; 2];
|
let mut data = [0u8; 2];
|
||||||
bus.read_frame(self.register() + socketn::TX_DATA_WRITE_POINTER, &mut data)?;
|
bus.read_frame(self.register() + socketn::TX_DATA_WRITE_POINTER, &mut data)?;
|
||||||
Ok(u16::from_be_bytes(data))
|
Ok(u16::from_be_bytes(data))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_tx_write_pointer<SpiBus: Bus>(
|
pub fn set_tx_write_pointer<SpiBus: Bus>(
|
||||||
&self,
|
&self,
|
||||||
bus: &mut SpiBus,
|
bus: &mut SpiBus,
|
||||||
pointer: u16,
|
pointer: u16,
|
||||||
) -> Result<(), SpiBus::Error> {
|
) -> Result<(), SpiBus::Error> {
|
||||||
let data = pointer.to_be_bytes();
|
let data = pointer.to_be_bytes();
|
||||||
bus.write_frame(self.register() + socketn::TX_DATA_WRITE_POINTER, &data)?;
|
bus.write_frame(self.register() + socketn::TX_DATA_WRITE_POINTER, &data)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_rx_read_pointer<SpiBus: Bus>(&self, bus: &mut SpiBus) -> Result<u16, SpiBus::Error> {
|
pub fn get_rx_read_pointer<SpiBus: Bus>(&self, bus: &mut SpiBus) -> Result<u16, SpiBus::Error> {
|
||||||
let mut data = [0u8; 2];
|
let mut data = [0u8; 2];
|
||||||
bus.read_frame(self.register() + socketn::RX_DATA_READ_POINTER, &mut data)?;
|
bus.read_frame(self.register() + socketn::RX_DATA_READ_POINTER, &mut data)?;
|
||||||
Ok(u16::from_be_bytes(data))
|
Ok(u16::from_be_bytes(data))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_rx_read_pointer<SpiBus: Bus>(
|
pub fn set_rx_read_pointer<SpiBus: Bus>(
|
||||||
&self,
|
&self,
|
||||||
bus: &mut SpiBus,
|
bus: &mut SpiBus,
|
||||||
pointer: u16,
|
pointer: u16,
|
||||||
) -> Result<(), SpiBus::Error> {
|
) -> Result<(), SpiBus::Error> {
|
||||||
let data = pointer.to_be_bytes();
|
let data = pointer.to_be_bytes();
|
||||||
bus.write_frame(self.register() + socketn::RX_DATA_READ_POINTER, &data)?;
|
bus.write_frame(self.register() + socketn::RX_DATA_READ_POINTER, &data)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn enable_interrupts<SpiBus: Bus>(
|
pub fn enable_interrupts<SpiBus: Bus>(&self, bus: &mut SpiBus) -> Result<(), SpiBus::Error> {
|
||||||
&self,
|
let mut data = [0];
|
||||||
bus: &mut SpiBus,
|
bus.read_frame(
|
||||||
) -> Result<(), SpiBus::Error> {
|
register::COMMON + register::common::INTERRUPT_MASK,
|
||||||
let mut data = [0];
|
&mut data,
|
||||||
bus.read_frame(register::COMMON + register::common::INTERRUPT_MASK, &mut data)?;
|
)?;
|
||||||
data[0] |= 1 << self.index;
|
data[0] |= 1 << self.index;
|
||||||
bus.write_frame(register::COMMON + register::common::INTERRUPT_MASK, &data)?;
|
bus.write_frame(register::COMMON + register::common::INTERRUPT_MASK, &data)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn disable_interrupts<SpiBus: Bus>(
|
pub fn disable_interrupts<SpiBus: Bus>(&self, bus: &mut SpiBus) -> Result<(), SpiBus::Error> {
|
||||||
&self,
|
let mut data = [0];
|
||||||
bus: &mut SpiBus,
|
bus.read_frame(
|
||||||
) -> Result<(), SpiBus::Error> {
|
register::COMMON + register::common::INTERRUPT_MASK,
|
||||||
let mut data = [0];
|
&mut data,
|
||||||
bus.read_frame(register::COMMON + register::common::INTERRUPT_MASK, &mut data)?;
|
)?;
|
||||||
data[0] &= !(1 << self.index);
|
data[0] &= !(1 << self.index);
|
||||||
bus.write_frame(register::COMMON + register::common::INTERRUPT_MASK, &data)?;
|
bus.write_frame(register::COMMON + register::common::INTERRUPT_MASK, &data)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn command<SpiBus: Bus>(
|
pub fn command<SpiBus: Bus>(
|
||||||
&self,
|
&self,
|
||||||
bus: &mut SpiBus,
|
bus: &mut SpiBus,
|
||||||
command: socketn::Command,
|
command: socketn::Command,
|
||||||
) -> Result<(), SpiBus::Error> {
|
) -> Result<(), SpiBus::Error> {
|
||||||
let data = [command as u8];
|
let data = [command as u8];
|
||||||
bus.write_frame(self.register() + socketn::COMMAND, &data)?;
|
bus.write_frame(self.register() + socketn::COMMAND, &data)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the received bytes size of the socket's RX buffer.
|
/// 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
|
/// 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> {
|
pub fn get_receive_size<SpiBus: Bus>(&self, bus: &mut SpiBus) -> Result<u16, SpiBus::Error> {
|
||||||
loop {
|
loop {
|
||||||
let mut sample_0 = [0u8; 2];
|
let mut sample_0 = [0u8; 2];
|
||||||
bus.read_frame(self.register() + socketn::RECEIVED_SIZE, &mut sample_0)?;
|
bus.read_frame(self.register() + socketn::RECEIVED_SIZE, &mut sample_0)?;
|
||||||
let mut sample_1 = [0u8; 2];
|
let mut sample_1 = [0u8; 2];
|
||||||
bus.read_frame(self.register() + socketn::RECEIVED_SIZE, &mut sample_1)?;
|
bus.read_frame(self.register() + socketn::RECEIVED_SIZE, &mut sample_1)?;
|
||||||
if sample_0 == sample_1 {
|
if sample_0 == sample_1 {
|
||||||
break Ok(u16::from_be_bytes(sample_0));
|
break Ok(u16::from_be_bytes(sample_0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the free TX buffer size still available for this socket.
|
/// Get the free TX buffer size still available for this socket.
|
||||||
///
|
///
|
||||||
/// It's cleared once we `SEND` the buffer over the 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> {
|
pub fn get_tx_free_size<SpiBus: Bus>(&self, bus: &mut SpiBus) -> Result<u16, SpiBus::Error> {
|
||||||
let mut data = [0; 2];
|
let mut data = [0; 2];
|
||||||
bus.read_frame(self.register() + socketn::TX_FREE_SIZE, &mut data)?;
|
bus.read_frame(self.register() + socketn::TX_FREE_SIZE, &mut data)?;
|
||||||
Ok(u16::from_be_bytes(data))
|
Ok(u16::from_be_bytes(data))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
394
src/tcp.rs
394
src/tcp.rs
|
|
@ -1,260 +1,260 @@
|
||||||
use core::{
|
use core::{
|
||||||
convert::TryFrom,
|
convert::TryFrom,
|
||||||
net::{IpAddr, Ipv4Addr, SocketAddr, SocketAddrV4},
|
net::{IpAddr, Ipv4Addr, SocketAddr, SocketAddrV4},
|
||||||
};
|
};
|
||||||
|
|
||||||
use embedded_nal::{nb, TcpClientStack, TcpError, TcpErrorKind};
|
use embedded_nal::{nb, TcpClientStack, TcpError, TcpErrorKind};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
bus::Bus,
|
bus::Bus,
|
||||||
device::{Device, State},
|
device::{Device, State},
|
||||||
register::socketn,
|
register::socketn,
|
||||||
socket::Socket,
|
socket::Socket,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
pub enum TcpSocketError<E: core::fmt::Debug> {
|
pub enum TcpSocketError<E: core::fmt::Debug> {
|
||||||
NoMoreSockets,
|
NoMoreSockets,
|
||||||
NotConnected,
|
NotConnected,
|
||||||
UnsupportedAddress,
|
UnsupportedAddress,
|
||||||
Other(#[cfg_attr(feature = "defmt", defmt(Debug2Format))] E),
|
Other(#[cfg_attr(feature = "defmt", defmt(Debug2Format))] E),
|
||||||
UnsupportedMode,
|
UnsupportedMode,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E: core::fmt::Debug> TcpError for TcpSocketError<E> {
|
impl<E: core::fmt::Debug> TcpError for TcpSocketError<E> {
|
||||||
fn kind(&self) -> TcpErrorKind {
|
fn kind(&self) -> TcpErrorKind {
|
||||||
match self {
|
match self {
|
||||||
TcpSocketError::NotConnected => TcpErrorKind::PipeClosed,
|
TcpSocketError::NotConnected => TcpErrorKind::PipeClosed,
|
||||||
_ => TcpErrorKind::Other,
|
_ => TcpErrorKind::Other,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E: core::fmt::Debug> From<E> for TcpSocketError<E> {
|
impl<E: core::fmt::Debug> From<E> for TcpSocketError<E> {
|
||||||
fn from(e: E) -> Self {
|
fn from(e: E) -> Self {
|
||||||
TcpSocketError::Other(e)
|
TcpSocketError::Other(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
pub struct TcpSocket {
|
pub struct TcpSocket {
|
||||||
socket: Socket,
|
socket: Socket,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TcpSocket {
|
impl TcpSocket {
|
||||||
fn reopen<B: Bus>(&mut self, bus: &mut B) -> Result<(), TcpSocketError<B::Error>> {
|
fn reopen<B: Bus>(&mut self, bus: &mut B) -> Result<(), TcpSocketError<B::Error>> {
|
||||||
self.socket.command(bus, socketn::Command::Close)?;
|
self.socket.command(bus, socketn::Command::Close)?;
|
||||||
self.socket.reset_interrupt(bus, socketn::Interrupt::All)?;
|
self.socket.reset_interrupt(bus, socketn::Interrupt::All)?;
|
||||||
self.socket.set_mode(bus, socketn::Protocol::Tcp)?;
|
self.socket.set_mode(bus, socketn::Protocol::Tcp)?;
|
||||||
self.socket.enable_interrupts(bus)?;
|
self.socket.enable_interrupts(bus)?;
|
||||||
|
|
||||||
self.socket.command(bus, socketn::Command::Open)?;
|
self.socket.command(bus, socketn::Command::Open)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
fn open<B: Bus>(
|
fn open<B: Bus>(
|
||||||
&mut self,
|
&mut self,
|
||||||
bus: &mut B,
|
bus: &mut B,
|
||||||
local_port: u16,
|
local_port: u16,
|
||||||
) -> Result<(), TcpSocketError<B::Error>> {
|
) -> Result<(), TcpSocketError<B::Error>> {
|
||||||
self.socket.command(bus, socketn::Command::Close)?;
|
self.socket.command(bus, socketn::Command::Close)?;
|
||||||
self.socket.reset_interrupt(bus, socketn::Interrupt::All)?;
|
self.socket.reset_interrupt(bus, socketn::Interrupt::All)?;
|
||||||
self.socket.set_source_port(bus, local_port)?;
|
self.socket.set_source_port(bus, local_port)?;
|
||||||
self.socket.set_mode(bus, socketn::Protocol::Tcp)?;
|
self.socket.set_mode(bus, socketn::Protocol::Tcp)?;
|
||||||
self.socket.enable_interrupts(bus)?;
|
self.socket.enable_interrupts(bus)?;
|
||||||
|
|
||||||
self.socket.command(bus, socketn::Command::Open)?;
|
self.socket.command(bus, socketn::Command::Open)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn socket_close<B: Bus>(&self, bus: &mut B) -> Result<(), TcpSocketError<B::Error>> {
|
fn socket_close<B: Bus>(&self, bus: &mut B) -> Result<(), TcpSocketError<B::Error>> {
|
||||||
self.socket.set_mode(bus, socketn::Protocol::Closed)?;
|
self.socket.set_mode(bus, socketn::Protocol::Closed)?;
|
||||||
self.socket.command(bus, socketn::Command::Close)?;
|
self.socket.command(bus, socketn::Command::Close)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn socket_connect<B: Bus>(
|
fn socket_connect<B: Bus>(
|
||||||
&mut self,
|
&mut self,
|
||||||
bus: &mut B,
|
bus: &mut B,
|
||||||
remote: SocketAddrV4,
|
remote: SocketAddrV4,
|
||||||
) -> Result<(), TcpSocketError<B::Error>> {
|
) -> Result<(), TcpSocketError<B::Error>> {
|
||||||
// Ensure the socket is open and ready before we attempt to connect it.
|
// Ensure the socket is open and ready before we attempt to connect it.
|
||||||
match socketn::Status::try_from(self.socket.get_status(bus)?) {
|
match socketn::Status::try_from(self.socket.get_status(bus)?) {
|
||||||
// Happy case: Nothing to do.
|
// Happy case: Nothing to do.
|
||||||
Ok(socketn::Status::Init) => {}
|
Ok(socketn::Status::Init) => {}
|
||||||
|
|
||||||
// If the socket is in the wrong mode, we can't use it. The user needs to re-open it.
|
// 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) => {
|
Err(_) | Ok(socketn::Status::MacRaw) | Ok(socketn::Status::Udp) => {
|
||||||
return Err(TcpSocketError::UnsupportedMode)
|
return Err(TcpSocketError::UnsupportedMode)
|
||||||
}
|
}
|
||||||
|
|
||||||
// All other cases are transient TCP states. For these, we need to reset the TCP
|
// All other cases are transient TCP states. For these, we need to reset the TCP
|
||||||
// machinery to return to the INIT state.
|
// machinery to return to the INIT state.
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
self.socket_close(bus)?;
|
self.socket_close(bus)?;
|
||||||
self.reopen(bus)?;
|
self.reopen(bus)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write the remote port and IP
|
// Write the remote port and IP
|
||||||
self.socket.set_destination_ip(bus, *remote.ip())?;
|
self.socket.set_destination_ip(bus, *remote.ip())?;
|
||||||
self.socket.set_destination_port(bus, remote.port())?;
|
self.socket.set_destination_port(bus, remote.port())?;
|
||||||
|
|
||||||
// Connect the socket.
|
// Connect the socket.
|
||||||
self.socket.command(bus, socketn::Command::Connect)?;
|
self.socket.command(bus, socketn::Command::Connect)?;
|
||||||
|
|
||||||
// Wait for the socket to connect or encounter an error.
|
// Wait for the socket to connect or encounter an error.
|
||||||
loop {
|
loop {
|
||||||
match socketn::Status::try_from(self.socket.get_status(bus)?) {
|
match socketn::Status::try_from(self.socket.get_status(bus)?) {
|
||||||
Ok(socketn::Status::Established) => return Ok(()),
|
Ok(socketn::Status::Established) => return Ok(()),
|
||||||
|
|
||||||
// The socket is closed if a timeout (ARP or SYN-ACK) or if the TCP socket receives
|
// 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.
|
// 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
|
// 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 (since we cannot inform the user of the connection failure). The returned
|
||||||
// socket will not actually be connected.
|
// socket will not actually be connected.
|
||||||
Ok(socketn::Status::Closed) => {
|
Ok(socketn::Status::Closed) => {
|
||||||
// For now, always return an open socket so that the user can re-connect with
|
// For now, always return an open socket so that the user can re-connect with
|
||||||
// it in the future.
|
// it in the future.
|
||||||
self.socket_close(bus)?;
|
self.socket_close(bus)?;
|
||||||
return self.reopen(bus);
|
return self.reopen(bus);
|
||||||
}
|
}
|
||||||
|
|
||||||
// The socket is still in some transient state. Wait for it to connect or for the
|
// The socket is still in some transient state. Wait for it to connect or for the
|
||||||
// connection to fail.
|
// connection to fail.
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn socket_is_connected<B: Bus>(&self, bus: &mut B) -> Result<bool, TcpSocketError<B::Error>> {
|
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)
|
Ok(self.socket.get_status(bus)? == socketn::Status::Established as u8)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn socket_send<B: Bus>(
|
fn socket_send<B: Bus>(
|
||||||
&mut self,
|
&mut self,
|
||||||
bus: &mut B,
|
bus: &mut B,
|
||||||
data: &[u8],
|
data: &[u8],
|
||||||
) -> Result<usize, TcpSocketError<B::Error>> {
|
) -> Result<usize, TcpSocketError<B::Error>> {
|
||||||
if !self.socket_is_connected(bus)? {
|
if !self.socket_is_connected(bus)? {
|
||||||
return Err(TcpSocketError::NotConnected);
|
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 {
|
let write_data = if data.len() < max_size {
|
||||||
data
|
data
|
||||||
} else {
|
} else {
|
||||||
&data[..max_size]
|
&data[..max_size]
|
||||||
};
|
};
|
||||||
|
|
||||||
// Append the data to the write buffer after the current write pointer.
|
// Append the data to the write buffer after the current write pointer.
|
||||||
let write_pointer = self.socket.get_tx_write_pointer(bus)?;
|
let write_pointer = self.socket.get_tx_write_pointer(bus)?;
|
||||||
|
|
||||||
// Write data into the buffer and update the writer pointer.
|
// Write data into the buffer and update the writer pointer.
|
||||||
bus.write_frame(write_pointer, write_data)?;
|
bus.write_frame(write_pointer, write_data)?;
|
||||||
self.socket
|
self.socket
|
||||||
.set_tx_write_pointer(bus, write_pointer.wrapping_add(write_data.len() as u16))?;
|
.set_tx_write_pointer(bus, write_pointer.wrapping_add(write_data.len() as u16))?;
|
||||||
|
|
||||||
// Send the data.
|
// Send the data.
|
||||||
self.socket.command(bus, socketn::Command::Send)?;
|
self.socket.command(bus, socketn::Command::Send)?;
|
||||||
|
|
||||||
// Wait until the send command completes.
|
// Wait until the send command completes.
|
||||||
while !self.socket.has_interrupt(bus, socketn::Interrupt::SendOk)? {}
|
while !self.socket.has_interrupt(bus, socketn::Interrupt::SendOk)? {}
|
||||||
self.socket
|
self.socket
|
||||||
.reset_interrupt(bus, socketn::Interrupt::SendOk)?;
|
.reset_interrupt(bus, socketn::Interrupt::SendOk)?;
|
||||||
|
|
||||||
Ok(write_data.len())
|
Ok(write_data.len())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn socket_receive<B: Bus>(
|
fn socket_receive<B: Bus>(
|
||||||
&mut self,
|
&mut self,
|
||||||
bus: &mut B,
|
bus: &mut B,
|
||||||
data: &mut [u8],
|
data: &mut [u8],
|
||||||
) -> Result<usize, TcpSocketError<B::Error>> {
|
) -> Result<usize, TcpSocketError<B::Error>> {
|
||||||
if !self.socket_is_connected(bus)? {
|
if !self.socket_is_connected(bus)? {
|
||||||
return Err(TcpSocketError::NotConnected);
|
return Err(TcpSocketError::NotConnected);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if we've received data.
|
// Check if we've received data.
|
||||||
if !self
|
if !self
|
||||||
.socket
|
.socket
|
||||||
.has_interrupt(bus, socketn::Interrupt::Receive)?
|
.has_interrupt(bus, socketn::Interrupt::Receive)?
|
||||||
{
|
{
|
||||||
return Ok(0);
|
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() {
|
let read_buffer = if rx_size > data.len() {
|
||||||
data
|
data
|
||||||
} else {
|
} else {
|
||||||
&mut data[..rx_size]
|
&mut data[..rx_size]
|
||||||
};
|
};
|
||||||
|
|
||||||
// Read from the RX ring buffer.
|
// Read from the RX ring buffer.
|
||||||
let read_pointer = self.socket.get_rx_read_pointer(bus)?;
|
let read_pointer = self.socket.get_rx_read_pointer(bus)?;
|
||||||
bus.read_frame(read_pointer, read_buffer)?;
|
bus.read_frame(read_pointer, read_buffer)?;
|
||||||
self.socket
|
self.socket
|
||||||
.set_rx_read_pointer(bus, read_pointer.wrapping_add(read_buffer.len() as u16))?;
|
.set_rx_read_pointer(bus, read_pointer.wrapping_add(read_buffer.len() as u16))?;
|
||||||
|
|
||||||
// Register the reception as complete.
|
// Register the reception as complete.
|
||||||
self.socket.command(bus, socketn::Command::Receive)?;
|
self.socket.command(bus, socketn::Command::Receive)?;
|
||||||
self.socket
|
self.socket
|
||||||
.reset_interrupt(bus, socketn::Interrupt::Receive)?;
|
.reset_interrupt(bus, socketn::Interrupt::Receive)?;
|
||||||
|
|
||||||
Ok(read_buffer.len())
|
Ok(read_buffer.len())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<SpiBus: Bus, StateImpl: State> TcpClientStack for Device<SpiBus, StateImpl> {
|
impl<SpiBus: Bus, StateImpl: State> TcpClientStack for Device<SpiBus, StateImpl> {
|
||||||
type TcpSocket = TcpSocket;
|
type TcpSocket = TcpSocket;
|
||||||
type Error = TcpSocketError<SpiBus::Error>;
|
type Error = TcpSocketError<SpiBus::Error>;
|
||||||
|
|
||||||
fn socket(&mut self) -> Result<TcpSocket, Self::Error> {
|
fn socket(&mut self) -> Result<TcpSocket, Self::Error> {
|
||||||
match self.take_socket() {
|
match self.take_socket() {
|
||||||
Some(socket) => Ok(TcpSocket { socket }),
|
Some(socket) => Ok(TcpSocket { socket }),
|
||||||
None => Err(TcpSocketError::NoMoreSockets),
|
None => Err(TcpSocketError::NoMoreSockets),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn connect(
|
fn connect(
|
||||||
&mut self,
|
&mut self,
|
||||||
socket: &mut Self::TcpSocket,
|
socket: &mut Self::TcpSocket,
|
||||||
remote: SocketAddr,
|
remote: SocketAddr,
|
||||||
) -> nb::Result<(), Self::Error> {
|
) -> nb::Result<(), Self::Error> {
|
||||||
let SocketAddr::V4(remote) = remote else {
|
let SocketAddr::V4(remote) = remote else {
|
||||||
return Err(nb::Error::Other(Self::Error::UnsupportedAddress));
|
return Err(nb::Error::Other(Self::Error::UnsupportedAddress));
|
||||||
};
|
};
|
||||||
// TODO dynamically select a random port
|
// TODO dynamically select a random port
|
||||||
socket.open(&mut self.bus, 49849 + u16::from(socket.socket.index))?; // chosen by fair dice roll.
|
socket.open(&mut self.bus, 49849 + u16::from(socket.socket.index))?; // chosen by fair dice roll.
|
||||||
socket.socket_connect(&mut self.bus, remote)?;
|
socket.socket_connect(&mut self.bus, remote)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send(
|
fn send(
|
||||||
&mut self,
|
&mut self,
|
||||||
socket: &mut Self::TcpSocket,
|
socket: &mut Self::TcpSocket,
|
||||||
buffer: &[u8],
|
buffer: &[u8],
|
||||||
) -> nb::Result<usize, Self::Error> {
|
) -> nb::Result<usize, Self::Error> {
|
||||||
let len = socket.socket_send(&mut self.bus, buffer)?;
|
let len = socket.socket_send(&mut self.bus, buffer)?;
|
||||||
Ok(len)
|
Ok(len)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn receive(
|
fn receive(
|
||||||
&mut self,
|
&mut self,
|
||||||
socket: &mut Self::TcpSocket,
|
socket: &mut Self::TcpSocket,
|
||||||
buffer: &mut [u8],
|
buffer: &mut [u8],
|
||||||
) -> nb::Result<usize, Self::Error> {
|
) -> nb::Result<usize, Self::Error> {
|
||||||
Ok(socket.socket_receive(&mut self.bus, buffer)?)
|
Ok(socket.socket_receive(&mut self.bus, buffer)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn close(&mut self, socket: Self::TcpSocket) -> Result<(), Self::Error> {
|
fn close(&mut self, socket: Self::TcpSocket) -> Result<(), Self::Error> {
|
||||||
socket.socket_close(&mut self.bus)?;
|
socket.socket_close(&mut self.bus)?;
|
||||||
self.release_socket(socket.socket);
|
self.release_socket(socket.socket);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
889
src/udp.rs
889
src/udp.rs
File diff suppressed because it is too large
Load diff
|
|
@ -2,217 +2,211 @@ use core::net::Ipv4Addr;
|
||||||
|
|
||||||
use embedded_hal::spi::SpiDevice;
|
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::{
|
use crate::{
|
||||||
register::{self, common::RetryTime},
|
bus::{Bus, FourWire},
|
||||||
MacAddress, Mode,
|
device::{Device, DeviceState},
|
||||||
|
host::{Dhcp, Host, Manual},
|
||||||
|
raw_device::RawDevice,
|
||||||
|
register::{self, common::RetryTime},
|
||||||
|
MacAddress, Mode,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
pub struct UninitializedDevice<SpiBus: Bus> {
|
pub struct UninitializedDevice<SpiBus: Bus> {
|
||||||
bus: SpiBus,
|
bus: SpiBus,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
pub enum InitializeError<SpiError> {
|
pub enum InitializeError<SpiError> {
|
||||||
SpiError(SpiError),
|
SpiError(SpiError),
|
||||||
ChipNotConnected,
|
ChipNotConnected,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<SpiError> From<SpiError> for InitializeError<SpiError> {
|
impl<SpiError> From<SpiError> for InitializeError<SpiError> {
|
||||||
fn from(error: SpiError) -> InitializeError<SpiError> {
|
fn from(error: SpiError) -> InitializeError<SpiError> {
|
||||||
InitializeError::SpiError(error)
|
InitializeError::SpiError(error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<SpiBus: Bus> UninitializedDevice<SpiBus> {
|
impl<SpiBus: Bus> UninitializedDevice<SpiBus> {
|
||||||
pub fn new(bus: SpiBus) -> UninitializedDevice<SpiBus> {
|
pub fn new(bus: SpiBus) -> UninitializedDevice<SpiBus> {
|
||||||
UninitializedDevice { bus }
|
UninitializedDevice { bus }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Initialize the device with a MAC address and mode settings.
|
/// Initialize the device with a MAC address and mode settings.
|
||||||
///
|
///
|
||||||
/// Consider using freely available private/locally administered mac
|
/// Consider using freely available private/locally administered mac
|
||||||
/// addresses that match the following hex pattern:
|
/// addresses that match the following hex pattern:
|
||||||
///
|
///
|
||||||
/// ```code
|
/// ```code
|
||||||
/// x2-xx-xx-xx-xx-xx
|
/// x2-xx-xx-xx-xx-xx
|
||||||
/// x6-xx-xx-xx-xx-xx
|
/// x6-xx-xx-xx-xx-xx
|
||||||
/// xA-xx-xx-xx-xx-xx
|
/// xA-xx-xx-xx-xx-xx
|
||||||
/// xE-xx-xx-xx-xx-xx
|
/// xE-xx-xx-xx-xx-xx
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// "Universally administered and locally administered addresses are
|
/// "Universally administered and locally administered addresses are
|
||||||
/// distinguished by setting the second-least-significant bit of the first
|
/// distinguished by setting the second-least-significant bit of the first
|
||||||
/// octet of the address"
|
/// octet of the address"
|
||||||
/// [Wikipedia](https://en.wikipedia.org/wiki/MAC_address#Universal_vs._local)
|
/// [Wikipedia](https://en.wikipedia.org/wiki/MAC_address#Universal_vs._local)
|
||||||
pub fn initialize(
|
pub fn initialize(
|
||||||
self,
|
self,
|
||||||
mac: MacAddress,
|
mac: MacAddress,
|
||||||
mode_options: Mode,
|
mode_options: Mode,
|
||||||
) -> Result<Device<SpiBus, DeviceState<Dhcp>>, InitializeError<SpiBus::Error>> {
|
) -> Result<Device<SpiBus, DeviceState<Dhcp>>, InitializeError<SpiBus::Error>> {
|
||||||
let host = Dhcp::new(mac);
|
let host = Dhcp::new(mac);
|
||||||
self.initialize_with_host(host, mode_options)
|
self.initialize_with_host(host, mode_options)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The gateway overrides the passed `ip` ([`Ip4Addr`]) to end with `.1`.
|
/// 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`.
|
/// 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(
|
pub fn initialize_manual(
|
||||||
self,
|
self,
|
||||||
mac: MacAddress,
|
mac: MacAddress,
|
||||||
ip: Ipv4Addr,
|
ip: Ipv4Addr,
|
||||||
mode_options: Mode,
|
mode_options: Mode,
|
||||||
) -> Result<Device<SpiBus, DeviceState<Manual>>, InitializeError<SpiBus::Error>> {
|
) -> Result<Device<SpiBus, DeviceState<Manual>>, InitializeError<SpiBus::Error>> {
|
||||||
let mut ip_bytes = ip.octets();
|
let mut ip_bytes = ip.octets();
|
||||||
ip_bytes[3] = 1;
|
ip_bytes[3] = 1;
|
||||||
let gateway = Ipv4Addr::from(ip_bytes);
|
let gateway = Ipv4Addr::from(ip_bytes);
|
||||||
let subnet = Ipv4Addr::new(255, 255, 255, 0);
|
let subnet = Ipv4Addr::new(255, 255, 255, 0);
|
||||||
self.initialize_advanced(mac, ip, gateway, subnet, mode_options)
|
self.initialize_advanced(mac, ip, gateway, subnet, mode_options)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn initialize_advanced(
|
pub fn initialize_advanced(
|
||||||
self,
|
self,
|
||||||
mac: MacAddress,
|
mac: MacAddress,
|
||||||
ip: Ipv4Addr,
|
ip: Ipv4Addr,
|
||||||
gateway: Ipv4Addr,
|
gateway: Ipv4Addr,
|
||||||
subnet: Ipv4Addr,
|
subnet: Ipv4Addr,
|
||||||
mode_options: Mode,
|
mode_options: Mode,
|
||||||
) -> Result<Device<SpiBus, DeviceState<Manual>>, InitializeError<SpiBus::Error>> {
|
) -> Result<Device<SpiBus, DeviceState<Manual>>, InitializeError<SpiBus::Error>> {
|
||||||
let host = Manual::new(mac, ip, gateway, subnet);
|
let host = Manual::new(mac, ip, gateway, subnet);
|
||||||
self.initialize_with_host(host, mode_options)
|
self.initialize_with_host(host, mode_options)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn initialize_with_host<HostImpl: Host>(
|
fn initialize_with_host<HostImpl: Host>(
|
||||||
mut self,
|
mut self,
|
||||||
mut host: HostImpl,
|
mut host: HostImpl,
|
||||||
mode_options: Mode,
|
mode_options: Mode,
|
||||||
) -> Result<Device<SpiBus, DeviceState<HostImpl>>, InitializeError<SpiBus::Error>> {
|
) -> Result<Device<SpiBus, DeviceState<HostImpl>>, InitializeError<SpiBus::Error>> {
|
||||||
|
// RESET
|
||||||
|
self.reset()?;
|
||||||
|
|
||||||
// RESET
|
self.set_mode(mode_options)?;
|
||||||
self.reset()?;
|
host.refresh(&mut self.bus)?;
|
||||||
|
Ok(Device::new(self.bus, DeviceState::new(host)))
|
||||||
|
}
|
||||||
|
|
||||||
self.set_mode(mode_options)?;
|
pub fn initialize_macraw(
|
||||||
host.refresh(&mut self.bus)?;
|
mut self,
|
||||||
Ok(Device::new(self.bus, DeviceState::new(host)))
|
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(
|
self.bus
|
||||||
mut self,
|
.write_frame(register::COMMON + register::common::MAC, &mac.octets)?;
|
||||||
mac: MacAddress,
|
|
||||||
) -> Result<RawDevice<SpiBus>, InitializeError<SpiBus::Error>> {
|
|
||||||
// Reset the device.
|
|
||||||
self.bus
|
|
||||||
.write_frame(register::COMMON + register::common::MODE, &[0x80])?;
|
|
||||||
|
|
||||||
self.bus
|
RawDevice::new(self.bus)
|
||||||
.write_frame(register::COMMON + register::common::MAC, &mac.octets)?;
|
}
|
||||||
|
|
||||||
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
|
/// RTR (Retry Time-value Register) [R/W] [0x0019 – 0x001A] [0x07D0]
|
||||||
#[inline]
|
///
|
||||||
pub fn reset(&mut self) -> Result<(), SpiBus::Error> {
|
/// # Example
|
||||||
// Set RST common register of the w5500
|
///
|
||||||
let mode = [0b10000000];
|
/// ```
|
||||||
self.bus
|
/// use w5500::register::common::RetryTime;
|
||||||
.write_frame(register::COMMON + register::common::MODE, &mode)
|
///
|
||||||
}
|
/// let default = RetryTime::from_millis(200);
|
||||||
#[inline]
|
/// assert_eq!(RetryTime::default(), default);
|
||||||
pub fn set_mode(&mut self, mode_options: Mode) -> Result<(), SpiBus::Error> {
|
///
|
||||||
self.bus.write_frame(
|
/// // E.g. 4000 (register) = 400ms
|
||||||
register::COMMON +
|
/// let four_hundred_ms = RetryTime::from_millis(400);
|
||||||
register::common::MODE,
|
/// assert_eq!(four_hundred_ms.to_u16(), 4000);
|
||||||
&mode_options.to_register(),
|
/// ```
|
||||||
)
|
#[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]
|
Ok(())
|
||||||
///
|
}
|
||||||
/// # 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(())
|
/// 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]
|
Ok(RetryTime::from_register(retry_time_register))
|
||||||
///
|
}
|
||||||
/// 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))
|
/// 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.
|
Ok(())
|
||||||
///
|
}
|
||||||
/// 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(())
|
/// 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
|
Ok(retry_count_register[0])
|
||||||
/// 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])
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue