diff --git a/Cargo.lock b/Cargo.lock index 86401c7..f56d52d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -201,7 +201,7 @@ dependencies = [ [[package]] name = "derive_miniconf" version = "0.1.0" -source = "git+https://github.com/quartiq/miniconf.git?branch=develop#394d0634a9622e43a55850afc34eb4695ecababa" +source = "git+https://github.com/quartiq/miniconf.git?branch=develop#314fa5587d1aa28e1ad70106f19e30db646e9f28" dependencies = [ "proc-macro2", "quote", @@ -414,10 +414,10 @@ dependencies = [ [[package]] name = "miniconf" version = "0.1.0" -source = "git+https://github.com/quartiq/miniconf.git?branch=develop#394d0634a9622e43a55850afc34eb4695ecababa" +source = "git+https://github.com/quartiq/miniconf.git?branch=develop#314fa5587d1aa28e1ad70106f19e30db646e9f28" dependencies = [ "derive_miniconf", - "heapless 0.5.6", + "heapless 0.6.1", "minimq", "serde", "serde-json-core", @@ -426,13 +426,13 @@ dependencies = [ [[package]] name = "minimq" version = "0.2.0" -source = "git+https://github.com/quartiq/minimq.git?branch=master#a89a6f11d0d1f63114fb15f676022eb4fe904f56" +source = "git+https://github.com/quartiq/minimq.git#933687c2e4bc8a4d972de9a4d1508b0b554a8b38" dependencies = [ "bit_field", "embedded-nal", "enum-iterator", "generic-array 0.14.4", - "heapless 0.5.6", + "heapless 0.6.1", ] [[package]] @@ -697,8 +697,7 @@ dependencies = [ [[package]] name = "smoltcp" version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab527c390c7e107f687bd92a886a083fde61b8cdc700b37f3d7e4346ffd8fae1" +source = "git+https://github.com/ryan-summers/smoltcp.git?branch=feature/dhcp-lease-updates#e3954ebb8149341c52a4992e037d4b5109387910" dependencies = [ "bitflags", "byteorder", @@ -708,11 +707,10 @@ dependencies = [ [[package]] name = "smoltcp-nal" version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4e5aeb4818706fd74c35917692008d29a5314483c8180300a582253718ce57a" +source = "git+https://github.com/quartiq/smoltcp-nal.git?branch=main#56519012d7c6a382eaa0d7ecb26f2701771d9ce8" dependencies = [ "embedded-nal", - "heapless 0.5.6", + "heapless 0.6.1", "smoltcp", ] diff --git a/Cargo.toml b/Cargo.toml index 8626359..79124dd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -53,12 +53,19 @@ branch = "develop" [patch.crates-io.minimq] git = "https://github.com/quartiq/minimq.git" -branch = "master" + +[patch.crates-io.smoltcp-nal] +git = "https://github.com/quartiq/smoltcp-nal.git" +branch = "main" [patch.crates-io.serde-json-core] git = "https://github.com/rust-embedded-community/serde-json-core.git" branch = "master" +[patch.crates-io.smoltcp] +git = "https://github.com/ryan-summers/smoltcp.git" +branch = "feature/dhcp-lease-updates" + [dependencies.mcp23017] git = "https://github.com/mrd0ll4r/mcp23017.git" diff --git a/src/bin/dual-iir.rs b/src/bin/dual-iir.rs index 5d51632..4a27d48 100644 --- a/src/bin/dual-iir.rs +++ b/src/bin/dual-iir.rs @@ -144,16 +144,31 @@ const APP: () = { loop { let sleep = c.resources.mqtt_interface.lock(|interface| { - !interface.network_stack().poll(clock.current_ms()) + match interface.network_stack().poll(clock.current_ms()) { + Ok(updated) => !updated, + Err(err) => { + log::info!("Network error: {:?}", err); + false + } + } }); - if c.resources + match c + .resources .mqtt_interface - .lock(|interface| interface.update().unwrap()) + .lock(|interface| interface.update()) { - c.spawn.settings_update().unwrap() - } else if sleep { - cortex_m::asm::wfi(); + Ok(update) => { + if update { + c.spawn.settings_update().unwrap(); + } else if sleep { + cortex_m::asm::wfi(); + } + } + Err(miniconf::MqttError::Network( + smoltcp_nal::NetworkError::NoIpAddress, + )) => {} + Err(error) => log::info!("Unexpected error: {:?}", error), } } } diff --git a/src/bin/lockin-external.rs b/src/bin/lockin-external.rs index 306ae45..7d2db0e 100644 --- a/src/bin/lockin-external.rs +++ b/src/bin/lockin-external.rs @@ -208,16 +208,31 @@ const APP: () = { loop { let sleep = c.resources.mqtt_interface.lock(|interface| { - !interface.network_stack().poll(clock.current_ms()) + match interface.network_stack().poll(clock.current_ms()) { + Ok(updated) => !updated, + Err(err) => { + log::info!("Network error: {:?}", err); + false + } + } }); - if c.resources + match c + .resources .mqtt_interface - .lock(|interface| interface.update().unwrap()) + .lock(|interface| interface.update()) { - c.spawn.settings_update().unwrap() - } else if sleep { - cortex_m::asm::wfi(); + Ok(update) => { + if update { + c.spawn.settings_update().unwrap(); + } else if sleep { + cortex_m::asm::wfi(); + } + } + Err(miniconf::MqttError::Network( + smoltcp_nal::NetworkError::NoIpAddress, + )) => {} + Err(error) => log::info!("Unexpected error: {:?}", error), } } } diff --git a/src/hardware/configuration.rs b/src/hardware/configuration.rs index e8f3029..dfab1e0 100644 --- a/src/hardware/configuration.rs +++ b/src/hardware/configuration.rs @@ -19,13 +19,38 @@ use super::{ pub struct NetStorage { pub ip_addrs: [smoltcp::wire::IpCidr; 1], - pub sockets: [Option>; 1], + pub sockets: [Option>; 2], pub neighbor_cache: [Option<(smoltcp::wire::IpAddress, smoltcp::iface::Neighbor)>; 8], pub routes_cache: [Option<(smoltcp::wire::IpCidr, smoltcp::iface::Route)>; 8], pub tx_storage: [u8; 4096], pub rx_storage: [u8; 4096], + + pub dhcp_rx_metadata: [smoltcp::socket::RawPacketMetadata; 1], + pub dhcp_tx_metadata: [smoltcp::socket::RawPacketMetadata; 1], + pub dhcp_tx_storage: [u8; 600], + pub dhcp_rx_storage: [u8; 600], +} + +impl NetStorage { + pub fn new() -> Self { + NetStorage { + // Placeholder for the real IP address, which is initialized at runtime. + ip_addrs: [smoltcp::wire::IpCidr::Ipv6( + smoltcp::wire::Ipv6Cidr::SOLICITED_NODE_PREFIX, + )], + neighbor_cache: [None; 8], + routes_cache: [None; 8], + sockets: [None, None], + tx_storage: [0; 4096], + rx_storage: [0; 4096], + dhcp_tx_storage: [0; 600], + dhcp_rx_storage: [0; 600], + dhcp_rx_metadata: [smoltcp::socket::RawPacketMetadata::EMPTY; 1], + dhcp_tx_metadata: [smoltcp::socket::RawPacketMetadata::EMPTY; 1], + } + } } /// The available networking devices on Stabilizer. @@ -59,22 +84,6 @@ pub struct PounderDevices { /// Static storage for the ethernet DMA descriptor ring. static mut DES_RING: ethernet::DesRing = ethernet::DesRing::new(); -/// Static, global-scope network storage for the ethernet interface. -/// -/// This is a static singleton so that the network storage can be referenced from all contexts. -static mut NET_STORE: NetStorage = NetStorage { - // Placeholder for the real IP address, which is initialized at runtime. - ip_addrs: [smoltcp::wire::IpCidr::Ipv6( - smoltcp::wire::Ipv6Cidr::SOLICITED_NODE_PREFIX, - )], - neighbor_cache: [None; 8], - routes_cache: [None; 8], - sockets: [None; 1], - - tx_storage: [0; 4096], - rx_storage: [0; 4096], -}; - /// Configure the stabilizer hardware for operation. /// /// # Args @@ -516,17 +525,23 @@ pub fn setup( unsafe { ethernet::enable_interrupt() }; - let store = unsafe { &mut NET_STORE }; + // Note(unwrap): The hardware configuration function is only allowed to be called once. + // Unwrapping is intended to panic if called again to prevent re-use of global memory. + let store = + cortex_m::singleton!(: NetStorage = NetStorage::new()).unwrap(); store.ip_addrs[0] = smoltcp::wire::IpCidr::new( - smoltcp::wire::IpAddress::v4(10, 34, 16, 103), - 24, + smoltcp::wire::IpAddress::Ipv4( + smoltcp::wire::Ipv4Address::UNSPECIFIED, + ), + 0, ); - let default_v4_gw = smoltcp::wire::Ipv4Address::new(10, 34, 16, 1); let mut routes = smoltcp::iface::Routes::new(&mut store.routes_cache[..]); - routes.add_default_ipv4_route(default_v4_gw).unwrap(); + routes + .add_default_ipv4_route(smoltcp::wire::Ipv4Address::UNSPECIFIED) + .unwrap(); let neighbor_cache = smoltcp::iface::NeighborCache::new(&mut store.neighbor_cache[..]); @@ -538,36 +553,54 @@ pub fn setup( .routes(routes) .finalize(); - let sockets = { - // Note(unsafe): Configuration is only called once, so we only access the global - // storage a single time. - let socket_storage = unsafe { &mut NET_STORE.sockets[..] }; - let mut sockets = smoltcp::socket::SocketSet::new(socket_storage); + let (mut sockets, handles) = { + let mut sockets = + smoltcp::socket::SocketSet::new(&mut store.sockets[..]); let tcp_socket = { - let rx_buffer = { - // Note(unsafe): Configuration is only called once, so we only access the global - // storage a single time. - let storage = unsafe { &mut NET_STORE.rx_storage[..] }; - smoltcp::socket::TcpSocketBuffer::new(storage) - }; - - let tx_buffer = { - // Note(unsafe): Configuration is only called once, so we only access the global - // storage a single time. - let storage = unsafe { &mut NET_STORE.tx_storage[..] }; - smoltcp::socket::TcpSocketBuffer::new(storage) - }; + let rx_buffer = smoltcp::socket::TcpSocketBuffer::new( + &mut store.rx_storage[..], + ); + let tx_buffer = smoltcp::socket::TcpSocketBuffer::new( + &mut store.tx_storage[..], + ); smoltcp::socket::TcpSocket::new(rx_buffer, tx_buffer) }; - sockets.add(tcp_socket); - sockets + let handle = sockets.add(tcp_socket); + (sockets, [handle]) + }; + + let dhcp_client = { + let dhcp_rx_buffer = smoltcp::socket::RawSocketBuffer::new( + &mut store.dhcp_rx_metadata[..], + &mut store.dhcp_rx_storage[..], + ); + + let dhcp_tx_buffer = smoltcp::socket::RawSocketBuffer::new( + &mut store.dhcp_tx_metadata[..], + &mut store.dhcp_tx_storage[..], + ); + + smoltcp::dhcp::Dhcpv4Client::new( + &mut sockets, + dhcp_rx_buffer, + dhcp_tx_buffer, + // Smoltcp indicates that an instant with a negative time is indicative that time is + // not yet available. We can't get the current instant yet, so indicate an invalid + // time value. + smoltcp::time::Instant::from_millis(-1), + ) }; NetworkDevices { - stack: smoltcp_nal::NetworkStack::new(interface, sockets), + stack: smoltcp_nal::NetworkStack::new( + interface, + sockets, + &handles, + Some(dhcp_client), + ), phy: lan8742a, } };