Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Restructure and implement embedded-nal UDP traits #26

Merged
merged 58 commits into from
Mar 23, 2021
Merged
Changes from 1 commit
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
03e30ef
Began skeleton of new UninitializedW5500 struct and Bus trait/impls
jonahbron Aug 5, 2019
a43f86d
Added bus model and InactiveW5500 state
jonahbron Aug 7, 2019
16e813e
Implemented frame transfer for four-wire bus
jonahbron Aug 8, 2019
aa0c69b
Fixed some masking issues with FourWireBus, added implementation for …
jonahbron Aug 8, 2019
d47de54
Added state-machine diagram SVG
jonahbron Aug 8, 2019
3177bad
Restored chip mode settings/common type structs
jonahbron Aug 8, 2019
ce36644
Added module containing new register address representations, added c…
jonahbron Aug 8, 2019
7dd4c04
Renamed Settings to Mode since it only applies to network mode byte
jonahbron Aug 9, 2019
fd9e861
Added Network trait that keeps track of network settings and has DHCP…
jonahbron Aug 9, 2019
d2fb6b9
fmt
jonahbron Aug 9, 2019
e74f7f4
Fixed bug in bitmasking
jonahbron Aug 9, 2019
b30e4d0
Stubbed UdpSocket struct, added Socket structs
jonahbron Aug 14, 2019
e8c8e3c
Laid out concept for UdpSocket init
jonahbron Aug 14, 2019
bd78b82
Comment for checking socket at run-time
jonahbron Aug 14, 2019
715cdea
Changed UdpSocket to store a socket reference
jonahbron Aug 14, 2019
b82bb92
Added inactive UP socket state, added run-time socket ownership check…
jonahbron Sep 4, 2019
65a9552
Moved register addresses into register modules, fixed borrow error
jonahbron Sep 5, 2019
36df284
Finished UDP socket init
jonahbron Sep 6, 2019
95ca1be
Ran formatting
jonahbron Sep 6, 2019
d0f5792
Added Packet struct and beginnings of packet reading
jonahbron Sep 10, 2019
423d2f6
Fleshed out packet receipt
jonahbron Sep 11, 2019
332ab92
Moved more functionality into socket
jonahbron Sep 11, 2019
63890a5
Moved packet to incoming_packet, stubbed outgoing_packet
jonahbron Sep 11, 2019
b9f9166
Fleshed out packet sending
jonahbron Sep 14, 2019
b6a52cb
Removed socket ownership checking, giving up on that effort for now
jonahbron Sep 19, 2019
adc7005
Fixed representation of enum to be u8, fixed FourWire bus to set CS p…
jonahbron Oct 24, 2019
4ff4bc9
Added register_dump function to show the contents of a socket register
jonahd-g Jan 20, 2020
3dbb2d4
Made dump_register suppress any errors
jonahd-g Jan 20, 2020
074e01e
Removed nb from areas where it's not necessary
jonahbron Jul 27, 2020
41cd42e
added all
jonahbron Nov 6, 2020
8aa5656
Added timeout interrupt bit, fixed several bugs with Socket code, add…
jonahbron Nov 8, 2020
b1e83e3
Added TODOs for safer sending
jonahbron Nov 8, 2020
f546ff2
Re-wrote socket implementations to be more compatible with embedded-nal
jonahbron Nov 18, 2020
3cad9ca
Renamed W5500 -> Device, added an Interface struct that should implem…
jonahbron Nov 20, 2020
1d533b2
Added a way to consume the Interface object, and easy single-function…
jonahbron Nov 20, 2020
79b1f52
Ran cargo fmt
jonahbron Nov 20, 2020
6caeeae
Updated dependencies
jonahbron Nov 20, 2020
79dc9a4
Add method to read PHY configuration.
newAM Aug 12, 2020
cc4db22
Changed to depend on upstream version of embedded-nal after PR merge
jonahbron Nov 22, 2020
1cac758
Added self to authors list, fixed Clippy lint errors
jonahbron Nov 22, 2020
dcfa655
Renamed Network mod to Host, removed debugging function, communted ou…
jonahbron Nov 24, 2020
839367b
Different clippy lint allowed
jonahbron Nov 24, 2020
2b59081
Removed implementation description from README, updated example to wo…
jonahbron Nov 24, 2020
2f26a50
Implemented From trait for InitializeError
jonahbron Nov 25, 2020
90604fc
Implemented From trait for busses
jonahbron Nov 25, 2020
259da58
Recovered MAC address docs from previous driver code
jonahbron Dec 1, 2020
d3ca4a3
Removed unnecessary extern crate statements
jonahbron Dec 1, 2020
da2bcd4
Updated to released version of embedded-nal
jonahbron Dec 2, 2020
9a05719
Updated UDP impl to be compatible with embedded-nal 0.2.0
jonahbron Dec 2, 2020
d844a11
Updated to latest embedded-nal
jonahbron Jan 19, 2021
d6574b8
Removed refcell container from Interface
jonahbron Jan 20, 2021
5509732
Updated embedded-nal and removed (now-redundent) Interface struct
jonahbron Feb 16, 2021
ca8268a
Removed the active/inactive concept, and changed bus to use blocking …
jonahbron Feb 16, 2021
a3e0911
Minor typo fixes, clean-up of the public interface
jonahbron Feb 16, 2021
daa1c00
Minor typo fixes, clean-up of the public interface
jonahbron Feb 16, 2021
b49f41c
fmt
jonahbron Feb 16, 2021
dfa252f
Short-term net fix
jonahbron Feb 26, 2021
52f0d06
Updated dependencies, fixed port closing after receive
jonahbron Mar 23, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Removed the active/inactive concept, and changed bus to use blocking …
…traits to allow users to use shared-bus
  • Loading branch information
jonahbron committed Feb 19, 2021
commit ca8268ab31d67812c86933cc9c754c3589f98b78
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -33,8 +33,10 @@ of the SPI implementation. It must be set up to work as the W5500 chip requires
let mut spi = ...; // SPI interface to use
let mut cs : OutputPin = ...; // chip select

let interface = Interface::setup(spi, cs, MacAddress::new(0, 1, 2, 3, 4, 5), Ipv4Addr::new(192, 168, 86, 79)).unwrap();
let socket = interface.connect(
let device = UninitializedDevice::new(FourWire::new(spi, cs));
let device = device.initialize_manual(MacAddress::new(0, 1, 2, 3, 4, 5), Ipv4Addr::new(192, 168, 86, 79), Mode::default()).unwrap();
let socket = interface.socket();
socket.connect(
SocketAddr::new(IpAddr::V4(Ipv4Addr::new(192, 168, 86, 38)), 8000),
).unwrap();
block!(interface.send(&mut socket, &[104, 101, 108, 108, 111, 10]));
74 changes: 35 additions & 39 deletions src/bus/four_wire.rs
Original file line number Diff line number Diff line change
@@ -1,50 +1,43 @@
#![allow(clippy::inconsistent_digit_grouping, clippy::unusual_byte_groupings)]

use core::fmt;
use embedded_hal::blocking::spi::{Transfer, Write};
use embedded_hal::digital::v2::OutputPin;
use embedded_hal::spi::FullDuplex;

use crate::bus::{ActiveBus, Bus};
use crate::bus::Bus;

const WRITE_MODE_MASK: u8 = 0b00000_1_00;

pub struct FourWire<ChipSelect: OutputPin> {
pub struct FourWire<Spi: Transfer<u8> + Write<u8>, ChipSelect: OutputPin> {
cs: ChipSelect,
spi: Spi,
}

impl<ChipSelect: OutputPin> FourWire<ChipSelect> {
pub fn new(cs: ChipSelect) -> Self {
Self { cs }
}
pub fn release(self) -> ChipSelect {
self.cs
impl<Spi: Transfer<u8> + Write<u8>, ChipSelect: OutputPin> FourWire<Spi, ChipSelect> {
pub fn new(spi: Spi, cs: ChipSelect) -> Self {
Self { spi, cs }
}
}

impl<ChipSelect: OutputPin> Bus for FourWire<ChipSelect> {}

impl<ChipSelect: OutputPin> FourWire<ChipSelect> {
pub fn activate<Spi: FullDuplex<u8>>(self, spi: Spi) -> ActiveFourWire<Spi, ChipSelect> {
ActiveFourWire { cs: self.cs, spi }
pub fn release(self) -> (Spi, ChipSelect) {
(self.spi, self.cs)
}
}

pub struct ActiveFourWire<Spi: FullDuplex<u8>, ChipSelect: OutputPin> {
cs: ChipSelect,
spi: Spi,
}

impl<Spi: FullDuplex<u8>, ChipSelect: OutputPin> ActiveBus for ActiveFourWire<Spi, ChipSelect> {
type Error = FourWireError<Spi::Error, ChipSelect::Error>;
impl<Spi: Transfer<u8> + Write<u8>, ChipSelect: OutputPin> Bus for FourWire<Spi, ChipSelect> {
type Error =
FourWireError<<Spi as Transfer<u8>>::Error, <Spi as Write<u8>>::Error, ChipSelect::Error>;
fn read_frame(&mut self, block: u8, address: u16, data: &mut [u8]) -> Result<(), Self::Error> {
let address_phase = address.to_be_bytes();
let control_phase = block << 3;
let data_phase = data;
self.cs.set_low().map_err(FourWireError::ChipSelectError)?;
Self::write_bytes(&mut self.spi, &address_phase)
.and_then(|_| Self::transfer_byte(&mut self.spi, control_phase))
.and_then(|_| Self::read_bytes(&mut self.spi, data_phase))
.map_err(FourWireError::SpiError)?;
self.spi
.write(&address_phase)
.and_then(|_| self.spi.write(&[control_phase]))
.map_err(FourWireError::WriteError)?;
self.spi
.transfer(data_phase)
.map_err(FourWireError::TransferError)?;
self.cs.set_high().map_err(FourWireError::ChipSelectError)?;

Ok(())
@@ -54,37 +47,40 @@ impl<Spi: FullDuplex<u8>, ChipSelect: OutputPin> ActiveBus for ActiveFourWire<Sp
let control_phase = block << 3 | WRITE_MODE_MASK;
let data_phase = data;
self.cs.set_low().map_err(FourWireError::ChipSelectError)?;
Self::write_bytes(&mut self.spi, &address_phase)
.and_then(|_| Self::transfer_byte(&mut self.spi, control_phase))
.and_then(|_| Self::write_bytes(&mut self.spi, data_phase))
.map_err(FourWireError::SpiError)?;
self.spi
.write(&address_phase)
.and_then(|_| self.spi.write(&[control_phase]))
.and_then(|_| self.spi.write(data_phase))
.map_err(FourWireError::WriteError)?;
self.cs.set_high().map_err(FourWireError::ChipSelectError)?;

Ok(())
}
}
impl<Spi: FullDuplex<u8>, ChipSelect: OutputPin> ActiveFourWire<Spi, ChipSelect> {
pub fn deactivate(self) -> (FourWire<ChipSelect>, Spi) {
(FourWire::new(self.cs), self.spi)
}
}

// Must use map_err, ambiguity prevents From from being implemented
#[repr(u8)]
pub enum FourWireError<SpiError, ChipSelectError> {
SpiError(SpiError),
pub enum FourWireError<TransferError, WriteError, ChipSelectError> {
TransferError(TransferError),
WriteError(WriteError),
ChipSelectError(ChipSelectError),
}

impl<SpiError, ChipSelectError> fmt::Debug for FourWireError<SpiError, ChipSelectError> {
impl<TransferError, WriteError, ChipSelectError> fmt::Debug
for FourWireError<TransferError, WriteError, ChipSelectError>
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"FourWireError::{}",
match self {
Self::SpiError(_) => "SpiError",
Self::TransferError(_) => "TransferError",
Self::WriteError(_) => "WriteError",
Self::ChipSelectError(_) => "ChipSelectError",
}
)
}
}

// TODO Improved error rendering could be done with specialization.
// https://github.com/rust-lang/rust/issues/31844
25 changes: 1 addition & 24 deletions src/bus/mod.rs
Original file line number Diff line number Diff line change
@@ -1,38 +1,15 @@
use core::fmt::Debug;
use embedded_hal::spi::FullDuplex;

mod four_wire;
mod three_wire;

pub use self::four_wire::ActiveFourWire;
pub use self::four_wire::FourWire;
pub use self::three_wire::ActiveThreeWire;
pub use self::three_wire::ThreeWire;

pub trait Bus {}

pub trait ActiveBus {
pub trait Bus {
type Error: Debug;

fn read_frame(&mut self, block: u8, address: u16, data: &mut [u8]) -> Result<(), Self::Error>;

fn write_frame(&mut self, block: u8, address: u16, data: &[u8]) -> Result<(), Self::Error>;

fn read_bytes<Spi: FullDuplex<u8>>(spi: &mut Spi, bytes: &mut [u8]) -> Result<(), Spi::Error> {
for byte in bytes.iter_mut() {
*byte = Self::transfer_byte(spi, *byte)?;
}
Ok(())
}

fn write_bytes<Spi: FullDuplex<u8>>(spi: &mut Spi, bytes: &[u8]) -> Result<(), Spi::Error> {
for byte in bytes.iter() {
Self::transfer_byte(spi, *byte)?;
}
Ok(())
}

fn transfer_byte<Spi: FullDuplex<u8>>(spi: &mut Spi, byte: u8) -> Result<u8, Spi::Error> {
block!(spi.send(byte)).and_then(|_| block!(spi.read()))
}
}
83 changes: 31 additions & 52 deletions src/bus/three_wire.rs
Original file line number Diff line number Diff line change
@@ -1,44 +1,32 @@
#![allow(clippy::inconsistent_digit_grouping, clippy::unusual_byte_groupings)]

use core::fmt;
use embedded_hal::spi::FullDuplex;
use embedded_hal::blocking::spi::{Transfer, Write};

use crate::bus::{ActiveBus, Bus};
use crate::bus::Bus;

const WRITE_MODE_MASK: u8 = 0b00000_1_0;

const FIXED_DATA_LENGTH_MODE_1: u8 = 0b000000_01;
const FIXED_DATA_LENGTH_MODE_2: u8 = 0b000000_10;
const FIXED_DATA_LENGTH_MODE_4: u8 = 0b000000_11;

pub struct ThreeWire {}

impl ThreeWire {
pub fn new() -> Self {
Self {}
}
pub struct ThreeWire<Spi: Transfer<u8> + Write<u8>> {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What stands FDM for?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed length Data Mode (see screenshot of datasheet above).

spi: Spi,
}

impl Default for ThreeWire {
fn default() -> Self {
Self::new()
impl<Spi: Transfer<u8> + Write<u8>> ThreeWire<Spi> {
pub fn new(spi: Spi) -> Self {
Self { spi }
}
}

impl Bus for ThreeWire {}

impl ThreeWire {
pub fn activate<Spi: FullDuplex<u8>>(self, spi: Spi) -> ActiveThreeWire<Spi> {
ActiveThreeWire { spi }
pub fn release(self) -> Spi {
self.spi
}
}

pub struct ActiveThreeWire<Spi: FullDuplex<u8>> {
spi: Spi,
}

impl<Spi: FullDuplex<u8>> ActiveBus for ActiveThreeWire<Spi> {
type Error = ThreeWireError<Spi::Error>;
impl<Spi: Transfer<u8> + Write<u8>> Bus for ThreeWire<Spi> {
type Error = ThreeWireError<<Spi as Transfer<u8>>::Error, <Spi as Write<u8>>::Error>;

/// Transfers a frame with an arbitrary data length in FDM
///
@@ -74,20 +62,20 @@ impl<Spi: FullDuplex<u8>> ActiveBus for ActiveThreeWire<Spi> {
}

let address_phase = address.to_be_bytes();
Self::write_bytes(&mut self.spi, &address_phase)
.and_then(|_| Self::transfer_byte(&mut self.spi, control_phase))
.and_then(|_| {
Self::read_bytes(
&mut self.spi,
&mut data_phase[..last_length_written as usize],
)
})?;
self.spi
.write(&address_phase)
.and_then(|_| self.spi.write(&[control_phase]))
.map_err(ThreeWireError::WriteError)?;
self.spi
.transfer(&mut data_phase[..last_length_written as usize])
.map_err(ThreeWireError::TransferError)?;

address += last_length_written;
data_phase = &mut data_phase[last_length_written as usize..];
}
Ok(())
}

fn write_frame(&mut self, block: u8, mut address: u16, data: &[u8]) -> Result<(), Self::Error> {
let mut control_phase = block << 3 | WRITE_MODE_MASK;

@@ -106,11 +94,11 @@ impl<Spi: FullDuplex<u8>> ActiveBus for ActiveThreeWire<Spi> {
}

let address_phase = address.to_be_bytes();
Self::write_bytes(&mut self.spi, &address_phase)
.and_then(|_| Self::transfer_byte(&mut self.spi, control_phase))
.and_then(|_| {
Self::write_bytes(&mut self.spi, &data_phase[..last_length_written as usize])
})?;
self.spi
.write(&address_phase)
.and_then(|_| self.spi.write(&[control_phase]))
.and_then(|_| self.spi.write(&data_phase[..last_length_written as usize]))
.map_err(ThreeWireError::WriteError)?;

address += last_length_written;
data_phase = &data_phase[last_length_written as usize..];
@@ -119,29 +107,20 @@ impl<Spi: FullDuplex<u8>> ActiveBus for ActiveThreeWire<Spi> {
}
}

impl<Spi: FullDuplex<u8>> ActiveThreeWire<Spi> {
pub fn deactivate(self) -> (ThreeWire, Spi) {
(ThreeWire::new(), self.spi)
}
}

pub enum ThreeWireError<SpiError> {
SpiError(SpiError),
}

impl<SpiError> From<SpiError> for ThreeWireError<SpiError> {
fn from(error: SpiError) -> ThreeWireError<SpiError> {
ThreeWireError::SpiError(error)
}
// Must use map_err, ambiguity prevents From from being implemented
pub enum ThreeWireError<TransferError, WriteError> {
TransferError(TransferError),
WriteError(WriteError),
}

impl<SpiError> fmt::Debug for ThreeWireError<SpiError> {
impl<TransferError, WriteError> fmt::Debug for ThreeWireError<TransferError, WriteError> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"ThreeWireError::{}",
match self {
Self::SpiError(_) => "SpiError",
Self::TransferError(_) => "TransferError",
Self::WriteError(_) => "WriteError",
}
)
}
27 changes: 4 additions & 23 deletions src/device.rs
Original file line number Diff line number Diff line change
@@ -3,18 +3,14 @@ use crate::uninitialized_device::UninitializedDevice;
use bit_field::BitArray;
use bus::{ActiveBus, ActiveFourWire, ActiveThreeWire, FourWire, ThreeWire};
use embedded_hal::digital::v2::OutputPin;
use embedded_hal::spi::FullDuplex;

use interface::Interface;
use network::Network;
use crate::bus::{ActiveBus, ActiveFourWire, ActiveThreeWire, FourWire, ThreeWire};
use crate::bus::{Bus, FourWire, ThreeWire};
use crate::host::Host;
use crate::inactive_device::InactiveDevice;
use crate::register;
use crate::socket::Socket;
use crate::uninitialized_device::UninitializedDevice;

pub struct Device<SpiBus: ActiveBus, HostImpl: Host> {
pub struct Device<SpiBus: Bus, HostImpl: Host> {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldnt this be called something like W5500 instead of generically calling it Device?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I felt that was kind of repetitive, considering the crate is already called w5500. w5500::W5500. IMO, I'm willing to discuss renaming.

pub bus: SpiBus,
host: HostImpl,
sockets: [u8; 1],
@@ -31,7 +27,7 @@ impl<E> From<E> for ResetError<E> {
}
}

impl<SpiBus: ActiveBus, HostImpl: Host> Device<SpiBus, HostImpl> {
impl<SpiBus: Bus, HostImpl: Host> Device<SpiBus, HostImpl> {
pub fn new(bus: SpiBus, host: HostImpl) -> Self {
Device {
bus,
@@ -58,6 +54,7 @@ impl<SpiBus: ActiveBus, HostImpl: Host> Device<SpiBus, HostImpl> {
}

pub fn take_socket(&mut self) -> Option<Socket> {
// TODO maybe return Future that resolves when release_socket invoked
for index in 0..8 {
if self.sockets.get_bit(index) {
self.sockets.set_bit(index, false);
@@ -82,19 +79,3 @@ impl<SpiBus: ActiveBus, HostImpl: Host> Device<SpiBus, HostImpl> {
(self.bus, self.host)
}
}

impl<Spi: FullDuplex<u8>, ChipSelect: OutputPin, HostImpl: Host>
Device<ActiveFourWire<Spi, ChipSelect>, HostImpl>
{
pub fn deactivate(self) -> (InactiveDevice<FourWire<ChipSelect>, HostImpl>, Spi) {
let (bus, spi) = self.bus.deactivate();
(InactiveDevice::new(bus, self.host), spi)
}
}

impl<Spi: FullDuplex<u8>, HostImpl: Host> Device<ActiveThreeWire<Spi>, HostImpl> {
pub fn deactivate(self) -> (InactiveDevice<ThreeWire, HostImpl>, Spi) {
let (bus, spi) = self.bus.deactivate();
(InactiveDevice::new(bus, self.host), spi)
}
}
4 changes: 2 additions & 2 deletions src/host/dhcp.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::bus::ActiveBus;
use crate::bus::Bus;
use crate::host::Host;
use crate::MacAddress;

@@ -22,7 +22,7 @@ impl Dhcp {

impl Host for Dhcp {
/// Gets (if necessary) and sets the host settings on the chip
fn refresh<SpiBus: ActiveBus>(&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 figure out how should receive socket for DHCP negotiations
Ok(())
Loading