aboutsummaryrefslogtreecommitdiff
path: root/examples/rp235x/src/bin/ethernet_w5500_icmp.rs
diff options
context:
space:
mode:
Diffstat (limited to 'examples/rp235x/src/bin/ethernet_w5500_icmp.rs')
-rw-r--r--examples/rp235x/src/bin/ethernet_w5500_icmp.rs143
1 files changed, 143 insertions, 0 deletions
diff --git a/examples/rp235x/src/bin/ethernet_w5500_icmp.rs b/examples/rp235x/src/bin/ethernet_w5500_icmp.rs
new file mode 100644
index 000000000..f1abd311c
--- /dev/null
+++ b/examples/rp235x/src/bin/ethernet_w5500_icmp.rs
@@ -0,0 +1,143 @@
1//! This example implements an echo (ping) with an ICMP Socket and using defmt to report the results.
2//!
3//! Although there is a better way to execute pings using the child module ping of the icmp module,
4//! this example allows for other icmp messages like `Destination unreachable` to be sent aswell.
5//!
6//! Example written for the [`WIZnet W5500-EVB-Pico2`](https://docs.wiznet.io/Product/iEthernet/W5500/w5500-evb-pico2) board.
7
8#![no_std]
9#![no_main]
10
11use defmt::*;
12use embassy_executor::Spawner;
13use embassy_futures::yield_now;
14use embassy_net::icmp::{ChecksumCapabilities, IcmpEndpoint, IcmpSocket, Icmpv4Packet, Icmpv4Repr, PacketMetadata};
15use embassy_net::{Stack, StackResources};
16use embassy_net_wiznet::chip::W5500;
17use embassy_net_wiznet::*;
18use embassy_rp::clocks::RoscRng;
19use embassy_rp::gpio::{Input, Level, Output, Pull};
20use embassy_rp::peripherals::SPI0;
21use embassy_rp::spi::{Async, Config as SpiConfig, Spi};
22use embassy_time::{Delay, Instant, Timer};
23use embedded_hal_bus::spi::ExclusiveDevice;
24use static_cell::StaticCell;
25use {defmt_rtt as _, panic_probe as _};
26
27type ExclusiveSpiDevice = ExclusiveDevice<Spi<'static, SPI0, Async>, Output<'static>, Delay>;
28
29#[embassy_executor::task]
30async fn ethernet_task(runner: Runner<'static, W5500, ExclusiveSpiDevice, Input<'static>, Output<'static>>) -> ! {
31 runner.run().await
32}
33
34#[embassy_executor::task]
35async fn net_task(mut runner: embassy_net::Runner<'static, Device<'static>>) -> ! {
36 runner.run().await
37}
38
39#[embassy_executor::main]
40async fn main(spawner: Spawner) {
41 let p = embassy_rp::init(Default::default());
42 let mut rng = RoscRng;
43
44 let mut spi_cfg = SpiConfig::default();
45 spi_cfg.frequency = 50_000_000;
46 let (miso, mosi, clk) = (p.PIN_16, p.PIN_19, p.PIN_18);
47 let spi = Spi::new(p.SPI0, clk, mosi, miso, p.DMA_CH0, p.DMA_CH1, spi_cfg);
48 let cs = Output::new(p.PIN_17, Level::High);
49 let w5500_int = Input::new(p.PIN_21, Pull::Up);
50 let w5500_reset = Output::new(p.PIN_20, Level::High);
51
52 let mac_addr = [0x02, 0x00, 0x00, 0x00, 0x00, 0x00];
53 static STATE: StaticCell<State<8, 8>> = StaticCell::new();
54 let state = STATE.init(State::<8, 8>::new());
55 let (device, runner) = embassy_net_wiznet::new(
56 mac_addr,
57 state,
58 ExclusiveDevice::new(spi, cs, Delay),
59 w5500_int,
60 w5500_reset,
61 )
62 .await
63 .unwrap();
64 unwrap!(spawner.spawn(ethernet_task(runner)));
65
66 // Generate random seed
67 let seed = rng.next_u64();
68
69 // Init network stack
70 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
71 let (stack, runner) = embassy_net::new(
72 device,
73 embassy_net::Config::dhcpv4(Default::default()),
74 RESOURCES.init(StackResources::new()),
75 seed,
76 );
77
78 // Launch network task
79 unwrap!(spawner.spawn(net_task(runner)));
80
81 info!("Waiting for DHCP...");
82 let cfg = wait_for_config(stack).await;
83 let local_addr = cfg.address.address();
84 info!("IP address: {:?}", local_addr);
85
86 // Then we can use it!
87 let mut rx_buffer = [0; 256];
88 let mut tx_buffer = [0; 256];
89 let mut rx_meta = [PacketMetadata::EMPTY];
90 let mut tx_meta = [PacketMetadata::EMPTY];
91
92 // Identifier used for the ICMP socket
93 let ident = 42;
94
95 // Create and bind the socket
96 let mut socket = IcmpSocket::new(stack, &mut rx_meta, &mut rx_buffer, &mut tx_meta, &mut tx_buffer);
97 socket.bind(IcmpEndpoint::Ident(ident)).unwrap();
98
99 // Create the repr for the packet
100 let icmp_repr = Icmpv4Repr::EchoRequest {
101 ident,
102 seq_no: 0,
103 data: b"Hello, icmp!",
104 };
105
106 // Send the packet and store the starting instant to mesure latency later
107 let start = socket
108 .send_to_with(icmp_repr.buffer_len(), cfg.gateway.unwrap(), |buf| {
109 // Create and populate the packet buffer allocated by `send_to_with`
110 let mut icmp_packet = Icmpv4Packet::new_unchecked(buf);
111 icmp_repr.emit(&mut icmp_packet, &ChecksumCapabilities::default());
112 Instant::now() // Return the instant where the packet was sent
113 })
114 .await
115 .unwrap();
116
117 // Recieve and log the data of the reply
118 socket
119 .recv_from_with(|(buf, addr)| {
120 let packet = Icmpv4Packet::new_checked(buf).unwrap();
121 info!(
122 "Recieved {:?} from {} in {}ms",
123 packet.data(),
124 addr,
125 start.elapsed().as_millis()
126 );
127 })
128 .await
129 .unwrap();
130
131 loop {
132 Timer::after_secs(10).await;
133 }
134}
135
136async fn wait_for_config(stack: Stack<'static>) -> embassy_net::StaticConfigV4 {
137 loop {
138 if let Some(config) = stack.config_v4() {
139 return config.clone();
140 }
141 yield_now().await;
142 }
143}