Skip to content

Commit

Permalink
Merge branch 'pdh-dependencies'
Browse files Browse the repository at this point in the history
  • Loading branch information
pdh11 committed Jul 9, 2024
2 parents b21af6b + 03ab2af commit ef871f8
Show file tree
Hide file tree
Showing 13 changed files with 119 additions and 41 deletions.
9 changes: 5 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,11 @@ So far:
[![docs.rs](https://img.shields.io/docsrs/cotton-unique)](https://docs.rs/cotton-unique/latest/cotton_unique/): creating deterministic but per-device unique
identifiers such as MAC addresses.

- cotton-w5500: smoltcp driver for the Wiznet W5500 Ethernet
controller in MACRAW mode, including interrupt-driven mode. Not yet
on crates.io as it depends on a git prerelease of the w5500 crate,
but released here in case anyone needs example code.
- [cotton-w5500](https://crates.io/crates/cotton-w5500)
[![Crates.io](https://img.shields.io/crates/v/cotton-w5500)](https://crates.io/crates/cotton-w5500)
[![Crates.io](https://img.shields.io/crates/d/cotton-w5500)](https://crates.io/crates/cotton-w5500)
[![docs.rs](https://img.shields.io/docsrs/cotton-w5500)](https://docs.rs/cotton-w5500/latest/cotton_w5500/): smoltcp driver for the Wiznet W5500 Ethernet
controller in MACRAW mode, including interrupt-driven mode.

These crates are `no_std`-compatible, meaning that they can be used on
embedded systems. In fact, all pushes to my local (not Github)
Expand Down
4 changes: 3 additions & 1 deletion cotton-w5500/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ rust-version = "1.75"
all-features = true

[dependencies]
w5500 = { git = "https://github.com/kellerkindt/w5500", rev = "74ef8391", version = "0.4.1" }
w5500 = "0.5"
# defmt 0.3.7 has msrv too big
defmt = ">=0.3.2, <0.3.7"
smoltcp = { version = "0.11", default-features = false, features = [
Expand All @@ -24,6 +24,8 @@ smoltcp = { version = "0.11", default-features = false, features = [
], optional = true }
rp2040-hal = { version = "0.10", optional = true }
mockall = { version = "0.12.1", optional = true }
# embedded-hal-bus 0.2 assumes compare_exchange, which Cortex-M0 doesn't have
embedded-hal-bus = "0.1"

[features]
default = ["smoltcp", "std"]
Expand Down
31 changes: 31 additions & 0 deletions cotton-w5500/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
[![CI status](https://github.com/pdh11/cotton/actions/workflows/ci.yml/badge.svg)](https://github.com/pdh11/cotton/actions)
[![codecov](https://codecov.io/gh/pdh11/cotton/branch/main/graph/badge.svg?token=SMSZEPGRHA)](https://codecov.io/gh/pdh11/cotton)
[![dependency status](https://deps.rs/repo/github/pdh11/cotton/status.svg)](https://deps.rs/repo/github/pdh11/cotton)
[![Crates.io](https://img.shields.io/crates/v/cotton-w5500)](https://crates.io/crates/cotton-w5500)
[![Crates.io](https://img.shields.io/crates/d/cotton-w5500)](https://crates.io/crates/cotton-w5500)
[![docs.rs](https://img.shields.io/docsrs/cotton-w5500)](https://docs.rs/cotton-w5500/latest/cotton_w5500/)
[![License: CC0-1.0](https://img.shields.io/badge/License-CC0_1.0-lightgrey.svg)](http://creativecommons.org/publicdomain/zero/1.0/)

# cotton-w5500

Part of the [Cotton](https://github.com/pdh11/cotton) project.

## A Wiznet W5500 driver for smoltcp

This crate includes an implementation of `smoltcp::phy::Device` which
uses the [W5500](https://crates.io/crates/w5500) crate to target
[smoltcp](https://crates.io/crates/smoltcp) to the Wiznet W5500
SPI-to-Ethernet chip, as found on the
[W5500-EVB-Pico](https://thepihut.com/products/wiznet-w5100s-evb-pico-rp2040-board-with-ethernet)
board (and in many other places). The W5500 is operated in "MACRAW"
(raw packet) mode, which allows more flexible networking (via smoltcp)
than is possible using the W5500's onboard TCP/UDP mode -- for
instance, it enables IPv6 support, which would otherwise require the
somewhat rarer W6100 chip.

Although cotton-w5500 works well with cotton-unique, it is relatively
stand-alone: it does not depend on cotton-unique nor on any other part
of the Cotton project.

Library documentation is [on
docs.rs](https://docs.rs/cotton-w5500/latest/cotton_w5500/).
17 changes: 16 additions & 1 deletion cotton-w5500/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,19 @@
//! Helpers for using the W5500 SPI Ethernet controller
//! A Wiznet W5500 driver for smoltcp
//!
//! This crate includes an implementation of `smoltcp::phy::Device`
//! which uses the [W5500](https://crates.io/crates/w5500) crate to
//! target [smoltcp](https://crates.io/crates/smoltcp) to the Wiznet
//! W5500 SPI-to-Ethernet chip, as found on the
//! [W5500-EVB-Pico](https://thepihut.com/products/wiznet-w5100s-evb-pico-rp2040-board-with-ethernet)
//! board (and in many other places). The W5500 is operated in
//! "MACRAW" (raw packet) mode, which allows more flexible networking
//! (via smoltcp) than is possible using the W5500's onboard TCP/UDP
//! mode -- for instance, it enables IPv6 support, which would
//! otherwise require the somewhat rarer W6100 chip.
//!
//! Although cotton-w5500 works well with cotton-unique, it is
//! relatively stand-alone: it does not depend on cotton-unique nor on
//! any other part of the Cotton project.
#![cfg_attr(not(feature = "std"), no_std)]
#![warn(missing_docs)]
#![warn(rustdoc::missing_crate_level_docs)]
Expand Down
6 changes: 5 additions & 1 deletion cotton-w5500/src/smoltcp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,8 @@ pub mod w5500_evb_pico {
use rp2040_hal::gpio::PullNone;
use rp2040_hal::gpio::SioOutput;
use rp2040_hal::pac::SPI0;
use embedded_hal_bus::spi::ExclusiveDevice;
use embedded_hal_bus::spi::NoDelay;

type Spi0 = rp2040_hal::Spi<
rp2040_hal::spi::Enabled,
Expand All @@ -165,7 +167,9 @@ pub mod w5500_evb_pico {
type SpiChipSelect =
rp2040_hal::gpio::Pin<Gpio17, FunctionSio<SioOutput>, PullNone>;

type SpiBus = w5500::bus::FourWire<Spi0, SpiChipSelect>;
type SpiDevice = ExclusiveDevice<Spi0, SpiChipSelect, NoDelay>;

type SpiBus = w5500::bus::FourWire<SpiDevice>;

/// A W5500 driver specialised for the SPI setup on the W5500-EVB-Pico board
pub type Device = super::Device<SpiBus>;
Expand Down
2 changes: 1 addition & 1 deletion cross/rp2040-w5500/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ embedded-hal-bus = "0.1"
fugit = "0.3"
systick-monotonic = "1.0"

w5500 = { git = "https://github.com/kellerkindt/w5500", rev = "74ef8391", version = "0.4.1" }
w5500 = "0.5"
smoltcp = { version = "0.11", features = [
"medium-ethernet",
"proto-ipv4",
Expand Down
7 changes: 5 additions & 2 deletions cross/rp2040-w5500/src/bin/rp2040-w5500macraw-dhcp-rtic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,14 +128,17 @@ mod app {
(spi_mosi, spi_miso, spi_sclk),
);

let spi = spi.init(
let spi_bus = spi.init(
&mut resets,
clocks.peripheral_clock.freq(),
16u32.MHz(),
hal::spi::FrameFormat::MotorolaSpi(embedded_hal::spi::MODE_0),
);

let bus = w5500::bus::FourWire::new(spi, spi_ncs);
let spi_device =
embedded_hal_bus::spi::ExclusiveDevice::new_no_delay(spi_bus, spi_ncs);

let bus = w5500::bus::FourWire::new(spi_device);

let w5500_irq = pins.gpio21.into_pull_up_input();
w5500_irq.set_interrupt_enabled(EdgeLow, true);
Expand Down
9 changes: 6 additions & 3 deletions cross/rp2040-w5500/src/bin/rp2040-w5500macraw-ssdp-rtic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -186,14 +186,17 @@ mod app {
(spi_mosi, spi_miso, spi_sclk),
);

let spi = spi.init(
let spi_bus = spi.init(
&mut resets,
clocks.peripheral_clock.freq(),
16u32.MHz(),
hal::spi::FrameFormat::MotorolaSpi(embedded_hal::spi::MODE_0),
);

let bus = w5500::bus::FourWire::new(spi, spi_ncs);
let spi_device =
embedded_hal_bus::spi::ExclusiveDevice::new_no_delay(spi_bus, spi_ncs);

let bus = w5500::bus::FourWire::new(spi_device);

let w5500_irq = pins.gpio21.into_pull_up_input();
w5500_irq.set_interrupt_enabled(EdgeLow, true);
Expand Down Expand Up @@ -318,7 +321,7 @@ mod app {
&ws,
);

ssdp.subscribe("ssdp:all".to_string(), Listener {}, &ws);
ssdp.subscribe("cotton-test-server-rp2040".to_string(), Listener {}, &ws);

defmt::println!("Advertising!");
ssdp.advertise(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ mod app {
);
let ws = WrappedSocket::new(&mut udp_socket);
_ = ssdp.on_network_event(&ev, &wi, &ws);
ssdp.subscribe("ssdp:all".to_string(), Listener {}, &ws);
ssdp.subscribe("cotton-test-server-stm32f746".to_string(), Listener {}, &ws);

let uuid = alloc::format!(
"{:032x}",
Expand Down
36 changes: 26 additions & 10 deletions systemtests/tests/device/device_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,24 @@ struct DeviceTestInner {
errors: String,
}

impl DeviceTestInner {
fn poll(&mut self) {
let mut s = String::new();
self.stdout.read_available_to_string(&mut s).unwrap();
self.output.push_str(&s);
if !s.is_empty() {
eprintln!("{:?}: stdout {s}", Instant::now());
}

let mut s = String::new();
self.stderr.read_available_to_string(&mut s).unwrap();
self.errors.push_str(&s);
if !s.is_empty() {
eprintln!("{:?}: stderr {s}", Instant::now());
}
}
}

pub struct DeviceTest {
inner: Mutex<DeviceTestInner>,
}
Expand Down Expand Up @@ -60,14 +78,12 @@ impl DeviceTest {

pub fn expect(&self, needle: &str, timeout: Duration) {
let start = Instant::now();
eprintln!("{:?}: searching stdout for {needle}", Instant::now());

loop {
{
let mut inner = self.inner.lock().unwrap();
let mut s = String::new();
inner.stdout.read_available_to_string(&mut s).unwrap();
inner.output.push_str(&s);
print!("{s}");
inner.poll();
if let Some((_before, after)) = inner.output.split_once(needle)
{
eprintln!("OK: {needle}");
Expand All @@ -76,6 +92,7 @@ impl DeviceTest {
}

if start.elapsed() > timeout {
eprintln!("{:?}: stdout {}", Instant::now(), inner.output);
assert_contains!(inner.output, needle);
return;
}
Expand All @@ -86,22 +103,21 @@ impl DeviceTest {

pub fn expect_stderr(&self, needle: &str, timeout: Duration) {
let start = Instant::now();
eprintln!("{:?}: searching stderr for {needle}", Instant::now());

loop {
{
let mut inner = self.inner.lock().unwrap();
let mut s = String::new();
inner.stderr.read_available_to_string(&mut s).unwrap();
inner.errors.push_str(&s);
print!("{s}");
if let Some((_before, after)) = inner.output.split_once(needle)
inner.poll();
if let Some((_before, after)) = inner.errors.split_once(needle)
{
eprintln!("OK: {needle}");
inner.output = after.to_string();
inner.errors = after.to_string();
return;
}

if start.elapsed() > timeout {
eprintln!("{:?}: stderr {}", Instant::now(), inner.errors);
assert_contains!(inner.errors, needle);
return;
}
Expand Down
5 changes: 3 additions & 2 deletions systemtests/tests/device/rp2040_w5500.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ fn rp2040_test<F: FnOnce(DeviceTest) -> () + panic::UnwindSafe>(
#[test]
#[serial(rp2040_w5500)]
#[cfg_attr(miri, ignore)]
fn arm_rp2040_w5500_hello() {
fn arm_rp2040_w5500_0hello() {
rp2040_test(
"../cross/rp2040-w5500/target/thumbv6m-none-eabi/debug/hello",
|t| {
Expand Down Expand Up @@ -59,7 +59,8 @@ fn arm_rp2040_w5500macraw_ssdp_rtic() {
nt.expect_stderr("Finished in", Duration::from_secs(45));
nt.expect("DHCP config acquired!", Duration::from_secs(10));
ssdp_test(
Some("cotton-test-server-rp2040".to_string()),
"cotton-test-server-rp2040",
"rp2040-w5500-test",
|st| {
nt.expect("SSDP! cotton-test-server-rp2040",
Duration::from_secs(20));
Expand Down
25 changes: 13 additions & 12 deletions systemtests/tests/device/ssdp_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ impl SsdpTest {

pub fn expect_seen(&self, notification_type: &str, timeout: Duration) {
let start = Instant::now();
eprintln!("{:?}: Looking for {notification_type}", Instant::now());

loop {
{
Expand All @@ -28,6 +29,7 @@ impl SsdpTest {
return;
}
if start.elapsed() > timeout {
eprintln!("{:?}: Didn't find it", Instant::now());
assert_contains!(v, notification_type);
return;
}
Expand All @@ -39,7 +41,8 @@ impl SsdpTest {
}

pub fn ssdp_test<F: FnOnce(SsdpTest) -> () + panic::UnwindSafe>(
advertise: Option<String>,
my_service: &'static str,
device_service: &'static str,
f: F,
) {
let t = SsdpTest::new();
Expand All @@ -58,19 +61,17 @@ pub fn ssdp_test<F: FnOnce(SsdpTest) -> () + panic::UnwindSafe>(
Service::new(poll.registry(), (SSDP_TOKEN1, SSDP_TOKEN2))
.unwrap();

if let Some(nt) = advertise {
let uuid = uuid::Uuid::new_v4();
ssdp.advertise(
uuid.to_string(),
cotton_ssdp::Advertisement {
notification_type: nt.to_string(),
location: "http://127.0.0.1/test".to_string(),
},
);
}
let uuid = uuid::Uuid::new_v4();
ssdp.advertise(
uuid.to_string(),
cotton_ssdp::Advertisement {
notification_type: my_service.to_string(),
location: "http://127.0.0.1/test".to_string(),
},
);

ssdp.subscribe(
"ssdp:all",
device_service,
Box::new(move |r| {
println!("HOST GOT {r:?}");
if let cotton_ssdp::Notification::Alive {
Expand Down
7 changes: 4 additions & 3 deletions systemtests/tests/device/stm32f746_nucleo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ fn nucleo_test<F: FnOnce(DeviceTest) -> () + panic::UnwindSafe>(
#[test]
#[serial(stm32f746_nucleo)]
#[cfg_attr(miri, ignore)]
fn arm_stm32f746_nucleo_hello() {
fn arm_stm32f746_nucleo_0hello() {
nucleo_test(
"../cross/stm32f746-nucleo/target/thumbv7em-none-eabi/debug/stm32f746-nucleo-hello",
|t| {
Expand Down Expand Up @@ -51,12 +51,13 @@ fn arm_stm32f746_nucleo_ssdp() {
nt.expect_stderr("Finished in", Duration::from_secs(45));
nt.expect("DHCP config acquired!", Duration::from_secs(10));
ssdp_test(
Some("cotton-test-server-stm32f746".to_string()),
"cotton-test-server-stm32f746", // host service
"stm32f746-nucleo-test", // device service
|st| {
nt.expect("SSDP! cotton-test-server-stm32f746",
Duration::from_secs(20));
st.expect_seen("stm32f746-nucleo-test",
Duration::from_secs(10));
Duration::from_secs(20));
}
);
}
Expand Down

0 comments on commit ef871f8

Please sign in to comment.