2021-05-06 18:33:07 +08:00
|
|
|
///! Network Stack Sharing Utilities
|
|
|
|
///!
|
|
|
|
///! # Design
|
|
|
|
///! This module provides a mechanism for sharing a single network stack safely between drivers
|
|
|
|
///that may or may not execute in multiple contexts. The design copies that of `shared-bus`.
|
|
|
|
///!
|
|
|
|
///! Specifically, the network stack is stored in a global static singleton and proxies to the
|
|
|
|
///! underlying stack are handed out. The proxies provide an identical API for the
|
|
|
|
///! `embedded_nal::TcpStack` stack trait, so they can be provided direclty to drivers that require
|
|
|
|
///! a network stack.
|
|
|
|
///!
|
|
|
|
///! In order to ensure that pre-emption does not occur while accessing the same network stack from
|
|
|
|
///! multiple interrupt contexts, the proxy uses an atomic boolean check - if the flag indicates the
|
|
|
|
///! stack is in use, the proxy will generate a panic. The actual synchronization mechanism (mutex)
|
|
|
|
///! leverages RTIC resource allocation. All devices that use the underlying network stack must be
|
|
|
|
///! placed in a single RTIC resource, which will cause RTIC to prevent contention for the
|
|
|
|
///! underlying network stack.
|
2021-05-05 01:52:41 +08:00
|
|
|
use minimq::embedded_nal;
|
2021-05-05 21:39:33 +08:00
|
|
|
use shared_bus::{AtomicCheckMutex, BusMutex};
|
2021-05-05 01:52:41 +08:00
|
|
|
|
|
|
|
use crate::hardware::NetworkStack;
|
|
|
|
|
2021-05-06 18:33:07 +08:00
|
|
|
/// A manager for a shared network stack.
|
|
|
|
pub struct NetworkManager {
|
|
|
|
mutex: AtomicCheckMutex<NetworkStack>,
|
|
|
|
}
|
|
|
|
|
|
|
|
/// A basic proxy that references a shared network stack.
|
2021-05-05 01:52:41 +08:00
|
|
|
pub struct NetworkStackProxy<'a, S> {
|
2021-05-05 21:39:33 +08:00
|
|
|
mutex: &'a AtomicCheckMutex<S>,
|
2021-05-05 01:52:41 +08:00
|
|
|
}
|
|
|
|
|
2021-05-05 21:39:33 +08:00
|
|
|
impl<'a, S> NetworkStackProxy<'a, S> {
|
2021-05-06 18:33:07 +08:00
|
|
|
/// Using the proxy, access the underlying network stack directly.
|
|
|
|
///
|
|
|
|
/// # Args
|
|
|
|
/// * `f` - A closure which will be provided the network stack as an argument.
|
|
|
|
///
|
|
|
|
/// # Returns
|
|
|
|
/// Any value returned by the provided closure
|
2021-05-05 21:39:33 +08:00
|
|
|
pub fn lock<R, F: FnOnce(&mut S) -> R>(&mut self, f: F) -> R {
|
|
|
|
self.mutex.lock(|stack| f(stack))
|
2021-05-05 01:52:41 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-06 18:33:07 +08:00
|
|
|
// A simple forwarding macro taken from the `embedded-nal` to forward the embedded-nal API into the
|
|
|
|
// proxy structure.
|
2021-05-05 01:52:41 +08:00
|
|
|
macro_rules! forward {
|
|
|
|
($func:ident($($v:ident: $IT:ty),*) -> $T:ty) => {
|
2021-05-27 19:42:52 +08:00
|
|
|
fn $func(&mut self, $($v: $IT),*) -> $T {
|
2021-05-05 01:52:41 +08:00
|
|
|
self.mutex.lock(|stack| stack.$func($($v),*))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-06 18:33:07 +08:00
|
|
|
// Implement a TCP stack for the proxy if the underlying network stack implements it.
|
2021-05-27 19:42:52 +08:00
|
|
|
impl<'a, S> embedded_nal::TcpClientStack for NetworkStackProxy<'a, S>
|
2021-05-05 01:52:41 +08:00
|
|
|
where
|
2021-05-27 19:42:52 +08:00
|
|
|
S: embedded_nal::TcpClientStack,
|
2021-05-05 01:52:41 +08:00
|
|
|
{
|
|
|
|
type TcpSocket = S::TcpSocket;
|
|
|
|
type Error = S::Error;
|
|
|
|
|
2021-05-27 19:42:52 +08:00
|
|
|
forward! {socket() -> Result<S::TcpSocket, S::Error>}
|
|
|
|
forward! {connect(socket: &mut S::TcpSocket, remote: embedded_nal::SocketAddr) -> embedded_nal::nb::Result<(), S::Error>}
|
2021-05-05 01:52:41 +08:00
|
|
|
forward! {is_connected(socket: &S::TcpSocket) -> Result<bool, S::Error>}
|
2021-05-27 19:42:52 +08:00
|
|
|
forward! {send(socket: &mut S::TcpSocket, buffer: &[u8]) -> embedded_nal::nb::Result<usize, S::Error>}
|
|
|
|
forward! {receive(socket: &mut S::TcpSocket, buffer: &mut [u8]) -> embedded_nal::nb::Result<usize, S::Error>}
|
2021-05-05 01:52:41 +08:00
|
|
|
forward! {close(socket: S::TcpSocket) -> Result<(), S::Error>}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl NetworkManager {
|
2021-05-06 18:33:07 +08:00
|
|
|
/// Construct a new manager for a shared network stack
|
|
|
|
///
|
|
|
|
/// # Args
|
|
|
|
/// * `stack` - The network stack that is being shared.
|
2021-05-05 01:52:41 +08:00
|
|
|
pub fn new(stack: NetworkStack) -> Self {
|
2021-05-05 21:39:33 +08:00
|
|
|
Self {
|
|
|
|
mutex: AtomicCheckMutex::create(stack),
|
|
|
|
}
|
2021-05-05 01:52:41 +08:00
|
|
|
}
|
|
|
|
|
2021-05-06 18:33:07 +08:00
|
|
|
/// Acquire a proxy to the shared network stack.
|
|
|
|
///
|
|
|
|
/// # Returns
|
|
|
|
/// A proxy that can be used in place of the network stack. Note the requirements of
|
|
|
|
/// concurrency listed in the description of this file for usage.
|
2021-05-06 22:23:41 +08:00
|
|
|
pub fn acquire_stack(&'_ self) -> NetworkStackProxy<'_, NetworkStack> {
|
2021-05-05 21:39:33 +08:00
|
|
|
NetworkStackProxy { mutex: &self.mutex }
|
2021-05-05 01:52:41 +08:00
|
|
|
}
|
|
|
|
}
|