add net+server modules

This commit is contained in:
Astro 2019-03-12 22:52:39 +01:00
parent d4e8a131ca
commit c7c5a733f9
4 changed files with 201 additions and 11 deletions

View File

@ -24,7 +24,6 @@ panic-abort = "0.3.1"
cortex-m = "0.5" cortex-m = "0.5"
cortex-m-rt = { version = "0.6", features = ["device"] } cortex-m-rt = { version = "0.6", features = ["device"] }
cortex-m-semihosting = "0.3" cortex-m-semihosting = "0.3"
stm32f4 = { version = "0.6", features = ["rt", "stm32f429"] } stm32f4 = { version = "0.6", features = ["rt", "stm32f429"] }
embedded-hal = "0.2" embedded-hal = "0.2"
stm32f4xx-hal = { git = "https://github.com/stm32-rs/stm32f4xx-hal.git", features = ["rt", "stm32f429"] } stm32f4xx-hal = { git = "https://github.com/stm32-rs/stm32f4xx-hal.git", features = ["rt", "stm32f429"] }

View File

@ -1,5 +1,7 @@
#![no_std] #![no_std]
#![no_main] #![no_main]
// Enable returning `!`
#![feature(never_type)]
#[allow(unused_extern_crates)] #[allow(unused_extern_crates)]
extern crate panic_abort; extern crate panic_abort;
@ -14,18 +16,25 @@ use stm32f4xx_hal::{
time::U32Ext, time::U32Ext,
stm32::{CorePeripherals, Peripherals}, stm32::{CorePeripherals, Peripherals},
}; };
use smoltcp::time::Instant;
use core::fmt::Write; use core::fmt::Write;
use cortex_m_semihosting::hio; use cortex_m_semihosting::hio;
mod adc_input; mod adc_input;
mod net;
mod server;
use server::Server;
#[entry] #[entry]
fn main() -> ! { fn main() -> ! {
let mut stdout = hio::hstdout().unwrap(); let mut stdout = hio::hstdout().unwrap();
writeln!(stdout, "Hello").unwrap(); writeln!(stdout, "adc2tcp").unwrap();
let mut cp = CorePeripherals::take().unwrap(); let mut cp = CorePeripherals::take().unwrap();
cp.SCB.enable_icache();
cp.SCB.enable_dcache(&mut cp.CPUID);
let dp = Peripherals::take().unwrap(); let dp = Peripherals::take().unwrap();
stm32_eth::setup(&dp.RCC, &dp.SYSCFG); stm32_eth::setup(&dp.RCC, &dp.SYSCFG);
let _clocks = dp.RCC.constrain() let _clocks = dp.RCC.constrain()
@ -45,19 +54,35 @@ fn main() -> ! {
let gpioc = dp.GPIOC.split(); let gpioc = dp.GPIOC.split();
let gpiog = dp.GPIOG.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( stm32_eth::setup_pins(
gpioa.pa1, gpioa.pa2, gpioa.pa7, gpiob.pb13, gpioc.pc1, gpioa.pa1, gpioa.pa2, gpioa.pa7, gpiob.pb13, gpioc.pc1,
gpioc.pc4, gpioc.pc5, gpiog.pg11, gpiog.pg13 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();
let adc_value = adc_input::read(); adc_value.map(|adc_value| {
adc_value.map(|adc_value| { writeln!(server, "t={},pa3={}", t, adc_value).unwrap();
writeln!(stdout, "pa3: {}mV", adc_value).unwrap(); });
});
wd.feed(); // Update watchdog
wfi(); wd.feed();
} // Wait for interrupts
// if net.is_pending() {
wfi();
// }
}
})
} }

84
src/net.rs Normal file
View File

@ -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<RxDescriptor>; 8]> = None;
static mut TX_RING: Option<[RingEntry<TxDescriptor>; 2]> = None;
// TODO: generate one from device id
const SRC_MAC: [u8; 6] = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF];
pub fn run<F>(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);
}

82
src/server.rs Normal file
View File

@ -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::<TcpSocket>(*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::<TcpSocket>(*handle);
if socket.can_send() {
// Ignore errors, proceed with next client
let _ = socket.write_str(slice);
}
}
Ok(())
}
}