From c7c5a733f9dc7aecaa1ff78f0a5eeaee4e767576 Mon Sep 17 00:00:00 2001 From: Astro Date: Tue, 12 Mar 2019 22:52:39 +0100 Subject: [PATCH] add net+server modules --- Cargo.toml | 1 - src/main.rs | 45 +++++++++++++++++++++------ src/net.rs | 84 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/server.rs | 82 +++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 201 insertions(+), 11 deletions(-) create mode 100644 src/net.rs create mode 100644 src/server.rs diff --git a/Cargo.toml b/Cargo.toml index 3e96f7c..153f07c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,7 +24,6 @@ panic-abort = "0.3.1" cortex-m = "0.5" cortex-m-rt = { version = "0.6", features = ["device"] } cortex-m-semihosting = "0.3" - stm32f4 = { version = "0.6", features = ["rt", "stm32f429"] } embedded-hal = "0.2" stm32f4xx-hal = { git = "https://github.com/stm32-rs/stm32f4xx-hal.git", features = ["rt", "stm32f429"] } diff --git a/src/main.rs b/src/main.rs index d05fd0d..780d02e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,7 @@ #![no_std] #![no_main] +// Enable returning `!` +#![feature(never_type)] #[allow(unused_extern_crates)] extern crate panic_abort; @@ -14,18 +16,25 @@ use stm32f4xx_hal::{ time::U32Ext, stm32::{CorePeripherals, Peripherals}, }; +use smoltcp::time::Instant; use core::fmt::Write; use cortex_m_semihosting::hio; mod adc_input; +mod net; +mod server; +use server::Server; #[entry] fn main() -> ! { let mut stdout = hio::hstdout().unwrap(); - writeln!(stdout, "Hello").unwrap(); + writeln!(stdout, "adc2tcp").unwrap(); let mut cp = CorePeripherals::take().unwrap(); + cp.SCB.enable_icache(); + cp.SCB.enable_dcache(&mut cp.CPUID); + let dp = Peripherals::take().unwrap(); stm32_eth::setup(&dp.RCC, &dp.SYSCFG); let _clocks = dp.RCC.constrain() @@ -45,19 +54,35 @@ fn main() -> ! { let gpioc = dp.GPIOC.split(); let gpiog = dp.GPIOG.split(); + writeln!(stdout, "ADC init").unwrap(); + adc_input::setup(&mut cp.NVIC, dp.ADC1, gpioa.pa3); + + writeln!(stdout, "Eth setup").unwrap(); stm32_eth::setup_pins( gpioa.pa1, gpioa.pa2, gpioa.pa7, gpiob.pb13, gpioc.pc1, gpioc.pc4, gpioc.pc5, gpiog.pg11, gpiog.pg13 ); + writeln!(stdout, "Net startup").unwrap(); + net::run(&mut cp.NVIC, dp.ETHERNET_MAC, dp.ETHERNET_DMA, |net| { + let mut server = Server::new(net); - adc_input::setup(&mut cp.NVIC, dp.ADC1, gpioa.pa3); + let mut t = 0; + loop { + t += 100; + let now = Instant::from_millis(t); + server.poll(now); - loop { - let adc_value = adc_input::read(); - adc_value.map(|adc_value| { - writeln!(stdout, "pa3: {}mV", adc_value).unwrap(); - }); - wd.feed(); - wfi(); - } + let adc_value = adc_input::read(); + adc_value.map(|adc_value| { + writeln!(server, "t={},pa3={}", t, adc_value).unwrap(); + }); + + // Update watchdog + wd.feed(); + // Wait for interrupts + // if net.is_pending() { + wfi(); + // } + } + }) } diff --git a/src/net.rs b/src/net.rs new file mode 100644 index 0000000..0397056 --- /dev/null +++ b/src/net.rs @@ -0,0 +1,84 @@ +//! As there is only one peripheral, supporting data structures are +//! declared once and globally. + +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 +static mut RX_RING: Option<[RingEntry; 8]> = None; +static mut TX_RING: Option<[RingEntry; 2]> = None; + +// TODO: generate one from device id +const SRC_MAC: [u8; 6] = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF]; + + +pub fn run(nvic: &mut NVIC, ethernet_mac: ETHERNET_MAC, ethernet_dma: ETHERNET_DMA, f: F) -> ! +where + F: FnOnce(&mut NetInterface) -> ! +{ + let rx_ring = unsafe { + RX_RING.get_or_insert(Default::default()) + }; + let tx_ring = unsafe { + TX_RING.get_or_insert(Default::default()) + }; + let mut eth_dev = Eth::new( + ethernet_mac, ethernet_dma, + &mut rx_ring[..], &mut tx_ring[..] + ); + eth_dev.enable_interrupt(nvic); + + let local_addr = IpAddress::v4(192, 168, 69, 3); + let mut ip_addrs = [IpCidr::new(local_addr, 24)]; + let mut neighbor_storage = [None; 16]; + let neighbor_cache = NeighborCache::new(&mut neighbor_storage[..]); + let ethernet_addr = EthernetAddress(SRC_MAC); + let iface = EthernetInterfaceBuilder::new(&mut eth_dev) + .ethernet_addr(ethernet_addr) + .ip_addrs(&mut ip_addrs[..]) + .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); +} + +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, +/// and TODO: set pending flag +#[interrupt] +fn ETH() { + let p = unsafe { Peripherals::steal() }; + stm32_eth::eth_interrupt_handler(&p.ETHERNET_DMA); +} diff --git a/src/server.rs b/src/server.rs new file mode 100644 index 0000000..991230b --- /dev/null +++ b/src/server.rs @@ -0,0 +1,82 @@ +use core::fmt; +use core::mem::uninitialized; +use smoltcp::{ + socket::{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; + +static mut SOCKET_BUFFERS: [u8; SOCKET_BUFFERS_LENGTH] = [0u8; SOCKET_BUFFERS_LENGTH]; + +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]) + } +} + +/// Contains a number of server sockets that get all sent the same +/// data (through `fmt::Write`). +pub struct Server<'a, 's> { + handles: [SocketHandle; SOCKET_COUNT], + net: &'s mut NetInterface<'a>, +} + +impl<'a, 's> Server<'a, 's> { + pub fn new(net: &'s mut NetInterface<'a>) -> Self { + let mut server = Server { + handles: unsafe { uninitialized() }, + 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 + } + + pub fn poll(&mut self, now: Instant) { + let activity = self.net.poll(now); + if ! activity { + return; + } + + for handle in &self.handles { + let mut socket = self.net.sockets().get::(*handle); + if ! socket.is_open() { + socket.listen(TCP_PORT) + .unwrap(); + } + } + } +} + +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::(*handle); + if socket.can_send() { + // Ignore errors, proceed with next client + let _ = socket.write_str(slice); + } + } + + Ok(()) + } +}