add more smoltcp code
All checks were successful
Rust/sat-rs/pipeline/head This commit looks good

This commit is contained in:
Robin Müller 2024-05-20 20:38:07 +02:00
parent 6ecd55ef25
commit 25521b3772
Signed by: muellerr
GPG Key ID: A649FB78196E3849
2 changed files with 84 additions and 9 deletions

View File

@ -25,7 +25,7 @@ stm32h7xx-hal = { version="0.16", features= ["stm32h743v", "ethernet"] }
[dependencies.smoltcp] [dependencies.smoltcp]
version = "0.11.0" version = "0.11.0"
default-features = false default-features = false
features = ["medium-ethernet", "proto-ipv4", "socket-raw"] features = ["medium-ethernet", "proto-ipv4", "socket-raw", "socket-dhcpv4"]
[dependencies.rtic] [dependencies.rtic]
version = "2" version = "2"

View File

@ -1,10 +1,15 @@
#![no_main] #![no_main]
#![no_std] #![no_std]
use core::mem::MaybeUninit;
use rtic::app; use rtic::app;
use rtic_monotonics::systick::Systick;
use rtic_monotonics::Monotonic;
use satrs_stm32h7_nucleo_rtic as _; // global logger + panicking-behavior + memory layout use satrs_stm32h7_nucleo_rtic as _; // global logger + panicking-behavior + memory layout
use core::mem::MaybeUninit;
use smoltcp::iface::{Config, Interface, SocketSet, SocketStorage};
use smoltcp::time::Instant;
use smoltcp::wire::{HardwareAddress, IpAddress, IpCidr};
use stm32h7xx_hal::ethernet; use stm32h7xx_hal::ethernet;
const DEFAULT_BLINK_FREQ_MS: u32 = 1000; const DEFAULT_BLINK_FREQ_MS: u32 = 1000;
@ -13,11 +18,61 @@ const DEFAULT_BLINK_FREQ_MS: u32 = 1000;
#[link_section = ".sram3.eth"] #[link_section = ".sram3.eth"]
static mut DES_RING: MaybeUninit<ethernet::DesRing<4, 4>> = MaybeUninit::uninit(); static mut DES_RING: MaybeUninit<ethernet::DesRing<4, 4>> = MaybeUninit::uninit();
// This data will be held by Net through a mutable reference
pub struct NetStorageStatic<'a> {
socket_storage: [SocketStorage<'a>; 8],
}
// MaybeUninit allows us write code that is correct even if STORE is not
// initialised by the runtime
static mut STORE: MaybeUninit<NetStorageStatic> = MaybeUninit::uninit();
/// Locally administered MAC address /// Locally administered MAC address
const MAC_ADDRESS: [u8; 6] = [0x02, 0x00, 0x11, 0x22, 0x33, 0x44]; const MAC_ADDRESS: [u8; 6] = [0x02, 0x00, 0x11, 0x22, 0x33, 0x44];
pub struct Net<'a> {
iface: Interface,
ethdev: ethernet::EthernetDMA<4, 4>,
sockets: SocketSet<'a>,
}
impl<'a> Net<'a> {
pub fn new(
store: &'a mut NetStorageStatic<'a>,
mut ethdev: ethernet::EthernetDMA<4, 4>,
ethernet_addr: HardwareAddress,
now: Instant,
) -> Self {
let config = Config::new(ethernet_addr);
let mut iface = Interface::new(config, &mut ethdev, now);
// Set IP address
iface.update_ip_addrs(|addrs| {
let _ = addrs.push(IpCidr::new(IpAddress::v4(192, 168, 1, 99), 0));
});
let sockets = SocketSet::new(&mut store.socket_storage[..]);
Net::<'a> {
iface,
ethdev,
sockets,
}
}
/// Polls on the ethernet interface. You should refer to the smoltcp
/// documentation for poll() to understand how to call poll efficiently
pub fn poll(&mut self) -> bool {
let uptime = Systick::now() - Systick::ZERO;
let timestamp = smoltcp::time::Instant::from_millis(uptime.to_millis());
self.iface
.poll(timestamp, &mut self.ethdev, &mut self.sockets)
}
}
#[app(device = stm32h7xx_hal::stm32, peripherals = true)] #[app(device = stm32h7xx_hal::stm32, peripherals = true)]
mod app { mod app {
use core::ptr::addr_of_mut;
use super::*; use super::*;
use rtic_monotonics::systick::fugit::MillisDurationU32; use rtic_monotonics::systick::fugit::MillisDurationU32;
use rtic_monotonics::systick::Systick; use rtic_monotonics::systick::Systick;
@ -40,6 +95,7 @@ mod app {
struct Local { struct Local {
leds: BlinkyLeds, leds: BlinkyLeds,
link_led: Pin<'B', 0, Output>, link_led: Pin<'B', 0, Output>,
net: Net<'static>,
phy: ethernet::phy::LAN8742A<EthernetMAC>, phy: ethernet::phy::LAN8742A<EthernetMAC>,
} }
@ -72,7 +128,8 @@ mod app {
systick_mono_token, systick_mono_token,
); );
// Those are used in the example, I am not fully sure what they are good for. // Those are used in the smoltcp of the stm32h7xx-hal , I am not fully sure what they are
// good for.
cx.core.SCB.enable_icache(); cx.core.SCB.enable_icache();
cx.core.DWT.enable_cycle_counter(); cx.core.DWT.enable_cycle_counter();
@ -101,7 +158,7 @@ mod app {
let rmii_txd1 = gpiob.pb13.into_alternate::<11>(); let rmii_txd1 = gpiob.pb13.into_alternate::<11>();
let mac_addr = smoltcp::wire::EthernetAddress::from_bytes(&MAC_ADDRESS); let mac_addr = smoltcp::wire::EthernetAddress::from_bytes(&MAC_ADDRESS);
let (_eth_dma, eth_mac) = ethernet::new( let (eth_dma, eth_mac) = ethernet::new(
cx.device.ETHERNET_MAC, cx.device.ETHERNET_MAC,
cx.device.ETHERNET_MTL, cx.device.ETHERNET_MTL,
cx.device.ETHERNET_DMA, cx.device.ETHERNET_DMA,
@ -116,8 +173,8 @@ mod app {
rmii_txd0, rmii_txd0,
rmii_txd1, rmii_txd1,
), ),
// SAFETY: We do not move the returned DMA struct anymore, so this should be safe // SAFETY: We do not move the returned DMA struct across thread boundaries, so this
// according to the docs. // should be safe according to the docs.
unsafe { DES_RING.assume_init_mut() }, unsafe { DES_RING.assume_init_mut() },
mac_addr, mac_addr,
ccdr.peripheral.ETH1MAC, ccdr.peripheral.ETH1MAC,
@ -134,6 +191,22 @@ mod app {
cortex_m::peripheral::NVIC::unmask(Interrupt::ETH); cortex_m::peripheral::NVIC::unmask(Interrupt::ETH);
} }
// unsafe: mutable reference to static storage, we only do this once
let store = unsafe {
let store_ptr = STORE.as_mut_ptr();
// Initialise the socket_storage field. Using `write` instead of
// assignment via `=` to not call `drop` on the old, uninitialised
// value
addr_of_mut!((*store_ptr).socket_storage).write([SocketStorage::EMPTY; 8]);
// Now that all fields are initialised we can safely use
// assume_init_mut to return a mutable reference to STORE
STORE.assume_init_mut()
};
let net = Net::new(store, eth_dma, mac_addr.into(), Instant::ZERO);
eth_link_check::spawn().expect("eth link check failed"); eth_link_check::spawn().expect("eth link check failed");
blink::spawn().expect("spawning blink task failed"); blink::spawn().expect("spawning blink task failed");
( (
@ -144,6 +217,7 @@ mod app {
Local { Local {
link_led, link_led,
leds, leds,
net,
phy: lan8742a, phy: lan8742a,
}, },
) )
@ -181,11 +255,12 @@ mod app {
} }
} }
#[task(binds=ETH)] #[task(binds=ETH, local=[net])]
fn eth_isr(_: eth_isr::Context) { fn eth_isr(cx: eth_isr::Context) {
// SAFETY: We do not write the register mentioned inside the docs anywhere else. // SAFETY: We do not write the register mentioned inside the docs anywhere else.
unsafe { unsafe {
ethernet::interrupt_handler(); ethernet::interrupt_handler();
} }
cx.local.net.poll();
} }
} }