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);
|
||||
|
||||
info!("Net startup");
|
||||
net::run(&mut cp.NVIC, dp.ETHERNET_MAC, dp.ETHERNET_DMA, |net| {
|
||||
let mut server = Server::new(net);
|
||||
net::run(&mut cp.NVIC, dp.ETHERNET_MAC, dp.ETHERNET_DMA, |iface| {
|
||||
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;
|
||||
loop {
|
||||
led_green.on();
|
||||
let now = timer::now().0;
|
||||
let instant = Instant::from_millis(now as i64);
|
||||
server.poll(instant);
|
||||
led_green.off();
|
||||
|
||||
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.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_red.off();
|
||||
}
|
||||
})
|
||||
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_red.off();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
unimplemented!()
|
||||
}
|
||||
|
|
42
src/net.rs
42
src/net.rs
|
@ -7,14 +7,15 @@ use bare_metal::CriticalSection;
|
|||
use stm32f4xx_hal::{
|
||||
stm32::{interrupt, Peripherals, NVIC, ETHERNET_MAC, ETHERNET_DMA},
|
||||
};
|
||||
use smoltcp::time::Instant;
|
||||
use smoltcp::wire::{EthernetAddress, IpAddress, IpCidr};
|
||||
use smoltcp::iface::{NeighborCache, EthernetInterfaceBuilder, EthernetInterface};
|
||||
use smoltcp::socket::SocketSet;
|
||||
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;
|
||||
/// 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;
|
||||
|
||||
// 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));
|
||||
|
||||
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
|
||||
F: FnOnce(&mut NetInterface) -> !
|
||||
F: FnOnce(EthernetInterface<&mut stm32_eth::Eth<'static, 'static>>),
|
||||
{
|
||||
let rx_ring = unsafe {
|
||||
RX_RING.get_or_insert(Default::default())
|
||||
|
@ -49,37 +50,10 @@ where
|
|||
.neighbor_cache(neighbor_cache)
|
||||
.finalize();
|
||||
|
||||
let mut sockets_storage = [None, None, None, None];
|
||||
let sockets = SocketSet::new(&mut sockets_storage[..]);
|
||||
|
||||
let mut net_iface = NetInterface {
|
||||
iface,
|
||||
sockets,
|
||||
};
|
||||
f(&mut net_iface);
|
||||
f(iface);
|
||||
}
|
||||
|
||||
pub struct NetInterface<'a> {
|
||||
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,
|
||||
/// Wake up from `wfi()`, clear interrupt flags,
|
||||
/// and TODO: set pending flag
|
||||
#[interrupt]
|
||||
fn ETH() {
|
||||
|
|
|
@ -1,63 +1,88 @@
|
|||
use core::fmt;
|
||||
use core::mem::uninitialized;
|
||||
use smoltcp::{
|
||||
socket::{SocketHandle, TcpSocket, TcpSocketBuffer},
|
||||
iface::EthernetInterface,
|
||||
socket::{SocketSet, SocketHandle, TcpSocket, TcpSocketBuffer},
|
||||
time::Instant,
|
||||
};
|
||||
|
||||
use crate::net::NetInterface;
|
||||
|
||||
const TCP_PORT: u16 = 23;
|
||||
const SOCKET_COUNT: usize = 4;
|
||||
const SOCKET_BUFFER_SIZE: usize = 2048;
|
||||
const SOCKET_BUFFERS_LENGTH: usize = 2 * SOCKET_COUNT * SOCKET_BUFFER_SIZE;
|
||||
const SOCKET_COUNT: usize = 8;
|
||||
|
||||
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]) {
|
||||
let offset1 = 2 * i * SOCKET_BUFFER_SIZE;
|
||||
let offset2 = offset1 + SOCKET_BUFFER_SIZE;
|
||||
let offset3 = offset2 + SOCKET_BUFFER_SIZE;
|
||||
unsafe {
|
||||
(&mut SOCKET_BUFFERS[offset1..offset2],
|
||||
&mut SOCKET_BUFFERS[offset2..offset3])
|
||||
}
|
||||
macro_rules! create_socket_storage {
|
||||
($rx_storage:ident, $tx_storage:ident) => (
|
||||
let mut $rx_storage = [0; TCP_RX_BUFFER_SIZE];
|
||||
let mut $tx_storage = [0; TCP_TX_BUFFER_SIZE];
|
||||
)
|
||||
}
|
||||
|
||||
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
|
||||
/// 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],
|
||||
net: &'s mut NetInterface<'a>,
|
||||
}
|
||||
|
||||
impl<'a, 's> Server<'a, 's> {
|
||||
pub fn new(net: &'s mut NetInterface<'a>) -> Self {
|
||||
impl<'a, 'b> Server<'a, 'b> {
|
||||
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 {
|
||||
handles: unsafe { uninitialized() },
|
||||
handles,
|
||||
sockets,
|
||||
net,
|
||||
};
|
||||
|
||||
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
|
||||
f(&mut server);
|
||||
}
|
||||
|
||||
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 {
|
||||
return;
|
||||
}
|
||||
|
||||
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() {
|
||||
socket.listen(TCP_PORT)
|
||||
.unwrap();
|
||||
|
@ -70,7 +95,7 @@ impl<'a, 's> fmt::Write for Server<'a, 's> {
|
|||
/// Write to all connected clients
|
||||
fn write_str(&mut self, slice: &str) -> fmt::Result {
|
||||
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() {
|
||||
// Ignore errors, proceed with next client
|
||||
let _ = socket.write_str(slice);
|
||||
|
|
Loading…
Reference in New Issue