forked from M-Labs/thermostat
net, server: put tcp storage on stack
This commit is contained in:
parent
912bc2db24
commit
1832bd5884
70
src/main.rs
70
src/main.rs
|
@ -100,40 +100,42 @@ fn main() -> ! {
|
||||||
timer::setup(cp.SYST, clocks);
|
timer::setup(cp.SYST, clocks);
|
||||||
|
|
||||||
info!("Net startup");
|
info!("Net startup");
|
||||||
net::run(&mut cp.NVIC, dp.ETHERNET_MAC, dp.ETHERNET_DMA, |net| {
|
net::run(&mut cp.NVIC, dp.ETHERNET_MAC, dp.ETHERNET_DMA, |iface| {
|
||||||
let mut server = Server::new(net);
|
Server::run(iface, |server| {
|
||||||
|
let mut last_output = 0_u32;
|
||||||
|
loop {
|
||||||
|
led_green.on();
|
||||||
|
let now = timer::now().0;
|
||||||
|
let instant = Instant::from_millis(now as i64);
|
||||||
|
server.poll(instant);
|
||||||
|
led_green.off();
|
||||||
|
|
||||||
let mut last_output = 0_u32;
|
led_blue.on();
|
||||||
loop {
|
let now = timer::now().0;
|
||||||
led_green.on();
|
if now - last_output >= OUTPUT_INTERVAL {
|
||||||
let now = timer::now().0;
|
let adc_value = adc_input::read();
|
||||||
let instant = Instant::from_millis(now as i64);
|
adc_value.map(|adc_value| {
|
||||||
server.poll(instant);
|
write!(server, "t={},pa3={}\r\n", now, adc_value).unwrap();
|
||||||
led_green.off();
|
});
|
||||||
|
last_output = now;
|
||||||
led_blue.on();
|
|
||||||
let now = timer::now().0;
|
|
||||||
if now - last_output >= OUTPUT_INTERVAL {
|
|
||||||
let adc_value = adc_input::read();
|
|
||||||
adc_value.map(|adc_value| {
|
|
||||||
write!(server, "t={},pa3={}\r\n", now, adc_value).unwrap();
|
|
||||||
});
|
|
||||||
last_output = now;
|
|
||||||
}
|
|
||||||
led_blue.off();
|
|
||||||
|
|
||||||
// Update watchdog
|
|
||||||
wd.feed();
|
|
||||||
|
|
||||||
led_red.on();
|
|
||||||
cortex_m::interrupt::free(|cs| {
|
|
||||||
if !net::is_pending(cs) {
|
|
||||||
// Wait for interrupts
|
|
||||||
wfi();
|
|
||||||
net::clear_pending(cs);
|
|
||||||
}
|
}
|
||||||
});
|
led_blue.off();
|
||||||
led_red.off();
|
|
||||||
}
|
// Update watchdog
|
||||||
})
|
wd.feed();
|
||||||
|
|
||||||
|
led_red.on();
|
||||||
|
cortex_m::interrupt::free(|cs| {
|
||||||
|
if !net::is_pending(cs) {
|
||||||
|
// Wait for interrupts
|
||||||
|
wfi();
|
||||||
|
net::clear_pending(cs);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
led_red.off();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
|
42
src/net.rs
42
src/net.rs
|
@ -7,14 +7,15 @@ use bare_metal::CriticalSection;
|
||||||
use stm32f4xx_hal::{
|
use stm32f4xx_hal::{
|
||||||
stm32::{interrupt, Peripherals, NVIC, ETHERNET_MAC, ETHERNET_DMA},
|
stm32::{interrupt, Peripherals, NVIC, ETHERNET_MAC, ETHERNET_DMA},
|
||||||
};
|
};
|
||||||
use smoltcp::time::Instant;
|
|
||||||
use smoltcp::wire::{EthernetAddress, IpAddress, IpCidr};
|
use smoltcp::wire::{EthernetAddress, IpAddress, IpCidr};
|
||||||
use smoltcp::iface::{NeighborCache, EthernetInterfaceBuilder, EthernetInterface};
|
use smoltcp::iface::{NeighborCache, EthernetInterfaceBuilder, EthernetInterface};
|
||||||
use smoltcp::socket::SocketSet;
|
|
||||||
use stm32_eth::{Eth, RingEntry, RxDescriptor, TxDescriptor};
|
use stm32_eth::{Eth, RingEntry, RxDescriptor, TxDescriptor};
|
||||||
|
|
||||||
// TODO: ram regions
|
/// Not on the stack so that stack can be placed in CCMRAM (which the
|
||||||
|
/// ethernet peripheral cannot access)
|
||||||
static mut RX_RING: Option<[RingEntry<RxDescriptor>; 8]> = None;
|
static mut RX_RING: Option<[RingEntry<RxDescriptor>; 8]> = None;
|
||||||
|
/// Not on the stack so that stack can be placed in CCMRAM (which the
|
||||||
|
/// ethernet peripheral cannot access)
|
||||||
static mut TX_RING: Option<[RingEntry<TxDescriptor>; 2]> = None;
|
static mut TX_RING: Option<[RingEntry<TxDescriptor>; 2]> = None;
|
||||||
|
|
||||||
// TODO: generate one from device id
|
// TODO: generate one from device id
|
||||||
|
@ -22,9 +23,9 @@ const SRC_MAC: [u8; 6] = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF];
|
||||||
|
|
||||||
static NET_PENDING: Mutex<RefCell<bool>> = Mutex::new(RefCell::new(false));
|
static NET_PENDING: Mutex<RefCell<bool>> = Mutex::new(RefCell::new(false));
|
||||||
|
|
||||||
pub fn run<F>(nvic: &mut NVIC, ethernet_mac: ETHERNET_MAC, ethernet_dma: ETHERNET_DMA, f: F) -> !
|
pub fn run<F>(nvic: &mut NVIC, ethernet_mac: ETHERNET_MAC, ethernet_dma: ETHERNET_DMA, f: F)
|
||||||
where
|
where
|
||||||
F: FnOnce(&mut NetInterface) -> !
|
F: FnOnce(EthernetInterface<&mut stm32_eth::Eth<'static, 'static>>),
|
||||||
{
|
{
|
||||||
let rx_ring = unsafe {
|
let rx_ring = unsafe {
|
||||||
RX_RING.get_or_insert(Default::default())
|
RX_RING.get_or_insert(Default::default())
|
||||||
|
@ -49,37 +50,10 @@ where
|
||||||
.neighbor_cache(neighbor_cache)
|
.neighbor_cache(neighbor_cache)
|
||||||
.finalize();
|
.finalize();
|
||||||
|
|
||||||
let mut sockets_storage = [None, None, None, None];
|
f(iface);
|
||||||
let sockets = SocketSet::new(&mut sockets_storage[..]);
|
|
||||||
|
|
||||||
let mut net_iface = NetInterface {
|
|
||||||
iface,
|
|
||||||
sockets,
|
|
||||||
};
|
|
||||||
f(&mut net_iface);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct NetInterface<'a> {
|
/// Wake up from `wfi()`, clear interrupt flags,
|
||||||
iface: EthernetInterface<'a, 'a, 'a, &'a mut stm32_eth::Eth<'static, 'static>>,
|
|
||||||
sockets: SocketSet<'a, 'static, 'static>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> NetInterface<'a> {
|
|
||||||
/// Passes the boolean that indicates any sockets change.
|
|
||||||
pub fn poll(&mut self, now: Instant) -> bool {
|
|
||||||
// TODO: clear pending flag
|
|
||||||
|
|
||||||
self.iface.poll(&mut self.sockets, now)
|
|
||||||
.ok()
|
|
||||||
.unwrap_or(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn sockets(&mut self) -> &mut SocketSet<'a, 'static, 'static> {
|
|
||||||
&mut self.sockets
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Wwake up from `wfi()`, clear interrupt flags,
|
|
||||||
/// and TODO: set pending flag
|
/// and TODO: set pending flag
|
||||||
#[interrupt]
|
#[interrupt]
|
||||||
fn ETH() {
|
fn ETH() {
|
||||||
|
|
|
@ -1,63 +1,88 @@
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
use core::mem::uninitialized;
|
use core::mem::uninitialized;
|
||||||
use smoltcp::{
|
use smoltcp::{
|
||||||
socket::{SocketHandle, TcpSocket, TcpSocketBuffer},
|
iface::EthernetInterface,
|
||||||
|
socket::{SocketSet, SocketHandle, TcpSocket, TcpSocketBuffer},
|
||||||
time::Instant,
|
time::Instant,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::net::NetInterface;
|
|
||||||
|
|
||||||
const TCP_PORT: u16 = 23;
|
const TCP_PORT: u16 = 23;
|
||||||
const SOCKET_COUNT: usize = 4;
|
const SOCKET_COUNT: usize = 8;
|
||||||
const SOCKET_BUFFER_SIZE: usize = 2048;
|
|
||||||
const SOCKET_BUFFERS_LENGTH: usize = 2 * SOCKET_COUNT * SOCKET_BUFFER_SIZE;
|
|
||||||
|
|
||||||
static mut SOCKET_BUFFERS: [u8; SOCKET_BUFFERS_LENGTH] = [0u8; SOCKET_BUFFERS_LENGTH];
|
const TCP_RX_BUFFER_SIZE: usize = 2048;
|
||||||
|
const TCP_TX_BUFFER_SIZE: usize = 2048;
|
||||||
|
|
||||||
fn get_socket_buffers(i: usize) -> (&'static mut [u8], &'static mut [u8]) {
|
macro_rules! create_socket_storage {
|
||||||
let offset1 = 2 * i * SOCKET_BUFFER_SIZE;
|
($rx_storage:ident, $tx_storage:ident) => (
|
||||||
let offset2 = offset1 + SOCKET_BUFFER_SIZE;
|
let mut $rx_storage = [0; TCP_RX_BUFFER_SIZE];
|
||||||
let offset3 = offset2 + SOCKET_BUFFER_SIZE;
|
let mut $tx_storage = [0; TCP_TX_BUFFER_SIZE];
|
||||||
unsafe {
|
)
|
||||||
(&mut SOCKET_BUFFERS[offset1..offset2],
|
}
|
||||||
&mut SOCKET_BUFFERS[offset2..offset3])
|
|
||||||
}
|
macro_rules! create_socket {
|
||||||
|
($set:ident, $rx_storage:ident, $tx_storage:ident, $target:expr) => (
|
||||||
|
let tcp_rx_buffer = TcpSocketBuffer::new(&mut $rx_storage[..]);
|
||||||
|
let tcp_tx_buffer = TcpSocketBuffer::new(&mut $tx_storage[..]);
|
||||||
|
let tcp_socket = TcpSocket::new(tcp_rx_buffer, tcp_tx_buffer);
|
||||||
|
$target = $set.add(tcp_socket);
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Contains a number of server sockets that get all sent the same
|
/// Contains a number of server sockets that get all sent the same
|
||||||
/// data (through `fmt::Write`).
|
/// data (through `fmt::Write`).
|
||||||
pub struct Server<'a, 's> {
|
pub struct Server<'a, 'b> {
|
||||||
|
net: EthernetInterface<'a, 'a, 'a, &'a mut stm32_eth::Eth<'static, 'static>>,
|
||||||
|
sockets: SocketSet<'b, 'b, 'static>,
|
||||||
handles: [SocketHandle; SOCKET_COUNT],
|
handles: [SocketHandle; SOCKET_COUNT],
|
||||||
net: &'s mut NetInterface<'a>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 's> Server<'a, 's> {
|
impl<'a, 'b> Server<'a, 'b> {
|
||||||
pub fn new(net: &'s mut NetInterface<'a>) -> Self {
|
pub fn run<F>(net: EthernetInterface<'a, 'a, 'a, &'a mut stm32_eth::Eth<'static, 'static>>, f: F)
|
||||||
|
where
|
||||||
|
F: FnOnce(&mut Server<'a, '_>),
|
||||||
|
{
|
||||||
|
create_socket_storage!(tcp_rx_storage0, tcp_tx_storage0);
|
||||||
|
create_socket_storage!(tcp_rx_storage1, tcp_tx_storage1);
|
||||||
|
create_socket_storage!(tcp_rx_storage2, tcp_tx_storage2);
|
||||||
|
create_socket_storage!(tcp_rx_storage3, tcp_tx_storage3);
|
||||||
|
create_socket_storage!(tcp_rx_storage4, tcp_tx_storage4);
|
||||||
|
create_socket_storage!(tcp_rx_storage5, tcp_tx_storage5);
|
||||||
|
create_socket_storage!(tcp_rx_storage6, tcp_tx_storage6);
|
||||||
|
create_socket_storage!(tcp_rx_storage7, tcp_tx_storage7);
|
||||||
|
|
||||||
|
let mut sockets_storage = [
|
||||||
|
None, None, None, None,
|
||||||
|
None, None, None, None
|
||||||
|
];
|
||||||
|
let mut sockets = SocketSet::new(&mut sockets_storage[..]);
|
||||||
|
let mut handles: [SocketHandle; SOCKET_COUNT] = unsafe { uninitialized() };
|
||||||
|
create_socket!(sockets, tcp_rx_storage0, tcp_tx_storage0, handles[0]);
|
||||||
|
create_socket!(sockets, tcp_rx_storage1, tcp_tx_storage1, handles[1]);
|
||||||
|
create_socket!(sockets, tcp_rx_storage2, tcp_tx_storage2, handles[2]);
|
||||||
|
create_socket!(sockets, tcp_rx_storage3, tcp_tx_storage3, handles[3]);
|
||||||
|
create_socket!(sockets, tcp_rx_storage4, tcp_tx_storage4, handles[4]);
|
||||||
|
create_socket!(sockets, tcp_rx_storage5, tcp_tx_storage5, handles[5]);
|
||||||
|
create_socket!(sockets, tcp_rx_storage6, tcp_tx_storage6, handles[6]);
|
||||||
|
create_socket!(sockets, tcp_rx_storage7, tcp_tx_storage7, handles[7]);
|
||||||
|
|
||||||
let mut server = Server {
|
let mut server = Server {
|
||||||
handles: unsafe { uninitialized() },
|
handles,
|
||||||
|
sockets,
|
||||||
net,
|
net,
|
||||||
};
|
};
|
||||||
|
f(&mut server);
|
||||||
for i in 0..SOCKET_COUNT {
|
|
||||||
let buffers = get_socket_buffers(i);
|
|
||||||
let server_socket = TcpSocket::new(
|
|
||||||
TcpSocketBuffer::new(&mut buffers.0[..]),
|
|
||||||
TcpSocketBuffer::new(&mut buffers.1[..])
|
|
||||||
);
|
|
||||||
server.handles[i] = server.net.sockets().add(server_socket);
|
|
||||||
}
|
|
||||||
|
|
||||||
server
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn poll(&mut self, now: Instant) {
|
pub fn poll(&mut self, now: Instant) {
|
||||||
let activity = self.net.poll(now);
|
let activity = self.net.poll(&mut self.sockets, now)
|
||||||
|
.unwrap_or(true);
|
||||||
if ! activity {
|
if ! activity {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for handle in &self.handles {
|
for handle in &self.handles {
|
||||||
let mut socket = self.net.sockets().get::<TcpSocket>(*handle);
|
let mut socket = self.sockets.get::<TcpSocket>(*handle);
|
||||||
if ! socket.is_open() {
|
if ! socket.is_open() {
|
||||||
socket.listen(TCP_PORT)
|
socket.listen(TCP_PORT)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
@ -70,7 +95,7 @@ impl<'a, 's> fmt::Write for Server<'a, 's> {
|
||||||
/// Write to all connected clients
|
/// Write to all connected clients
|
||||||
fn write_str(&mut self, slice: &str) -> fmt::Result {
|
fn write_str(&mut self, slice: &str) -> fmt::Result {
|
||||||
for handle in &self.handles {
|
for handle in &self.handles {
|
||||||
let mut socket = self.net.sockets().get::<TcpSocket>(*handle);
|
let mut socket = self.sockets.get::<TcpSocket>(*handle);
|
||||||
if socket.can_send() {
|
if socket.can_send() {
|
||||||
// Ignore errors, proceed with next client
|
// Ignore errors, proceed with next client
|
||||||
let _ = socket.write_str(slice);
|
let _ = socket.write_str(slice);
|
||||||
|
|
Loading…
Reference in New Issue