Skip to content

Commit

Permalink
smoltcp_nal_stack: add independent stack controller for polling
Browse files Browse the repository at this point in the history
  • Loading branch information
HarryMakes committed Jun 16, 2021
1 parent b505d6f commit 0c01e2d
Show file tree
Hide file tree
Showing 3 changed files with 174 additions and 3 deletions.
73 changes: 73 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ usb-device = "0.2.6"
postcard = "0.5.1"
crc-any = { version = "2.3.5", default-features = false }
smoltcp-nal = { version = "0.1.0", optional = true }
embedded-time = { version = "0.12.0", optional = true }

[dependencies.minimq]
git = "https://github.com/quartiq/minimq"
Expand Down Expand Up @@ -72,7 +73,7 @@ path = "tca9548"

[features]
unstable = []
phy_enc424j600 = [ "enc424j600", "smoltcp-nal" ]
phy_enc424j600 = [ "enc424j600", "smoltcp-nal", "embedded-time" ]
phy_w5500 = [ "w5500" ]
default = [ "phy_w5500" ]

Expand Down
101 changes: 99 additions & 2 deletions src/smoltcp_nal_stack.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,23 @@
use crate::{
mutex::{AtomicCheckMutex, BusProxy},
mutex_lock_forward,
mutex_lock_forward, EthernetProxy,
};
use cortex_m::peripheral::DWT;
use embedded_time::{clock, duration::*, Instant};
use shared_bus::BusMutex;
use smoltcp_nal::embedded_nal;
use smoltcp_nal::{embedded_nal, NetworkError};

#[derive(Debug)]
pub enum Error {
TimeFault,
SmoltcpNal(NetworkError),
}

impl From<NetworkError> for Error {
fn from(e: NetworkError) -> Self {
Error::SmoltcpNal(e)
}
}

/// Proxy for accessing a smoltcp_nal::NetworkStack from different contexts
/// within the same RTIC structure.
Expand Down Expand Up @@ -80,3 +94,86 @@ macro_rules! new_network_stack_manager {
m
}};
}

/// Simple struct for implementing embedded_time::Clock
pub struct SmoltcpNalEpochClock<const CPUFREQ: u32> {
/// Epoch time in milliseconds to store a greater value
epoch_time_ms: Milliseconds<u32>,
/// Epoch time in ticks to store a temporary value
epoch_time_ticks: Instant<Self>,
}

impl<const CPUFREQ: u32> SmoltcpNalEpochClock<CPUFREQ> {
pub fn new() -> Self {
Self {
epoch_time_ms: Milliseconds::<u32>::new(0),
epoch_time_ticks: Instant::<Self>::new(0),
}
}

/// Update the valid epoch time in milliseconds, and returns the value.
///
/// Safe to call after RTIC #[init]. Returns Err() if DWT CYCCNT returns a
/// smaller value than the last recorded time.
pub fn now(&mut self) -> Result<u32, Error> {
use clock::Clock;
use core::convert::TryInto;

let now = match self.try_now() {
Ok(now) => now,
Err(_) => return Err(Error::TimeFault),
};
let elapsed: Milliseconds<u32> = match now.checked_duration_since(&self.epoch_time_ticks) {
Some(elapsed) => elapsed.try_into().map_err(|_| Error::TimeFault)?,
None => return Err(Error::TimeFault),
};
self.epoch_time_ticks = now;
self.epoch_time_ms = self.epoch_time_ms + elapsed;
Ok(self.epoch_time_ms.integer())
}
}

/// Implement a simple embedded_time::clock::Clock at the given CPU clock frequency
/// based on DWT CYCCNT.
///
/// This leverages "const generics" introduced in 1.51.
impl<const CPUFREQ: u32> clock::Clock for SmoltcpNalEpochClock<CPUFREQ> {
type T = u32;

const SCALING_FACTOR: Fraction = Fraction::new(1, CPUFREQ);

/// Returns directly from DWT CYCCNT. Not guaranteed to be valid.
fn try_now(&self) -> Result<Instant<Self>, clock::Error> {
Ok(Instant::new(DWT::get_cycle_count()))
}
}

/// Independent controller of a smoltcp_nal::NetworkStack, for the intended use
/// with the global smoltcp_nal::NetworkStack type
pub struct SmoltcpNalStackController<const CPUFREQ: u32> {
stack: EthernetProxy,
epoch_clock: SmoltcpNalEpochClock<CPUFREQ>,
}

impl<const CPUFREQ: u32> SmoltcpNalStackController<CPUFREQ> {
/// Constructor for safe use in any context of the RTIC structure
pub fn new(stack: EthernetProxy, epoch_clock: SmoltcpNalEpochClock<CPUFREQ>) -> Self {
Self { stack, epoch_clock }
}

/// Update the NAL stack
pub fn update(&mut self) {
let now = match self.epoch_clock.now() {
Ok(now) => now,
Err(e) => {
error!("Network poll error: {:?}", e);
return;
}
};

// Note: smoltcp-nal 0.1.0 ONLY returns boolean, and does NOT
// raise errors from smoltcp.
// TODO: Bump smoltcp-nal
self.stack.lock(|stack| stack.poll(now));
}
}

0 comments on commit 0c01e2d

Please sign in to comment.