forked from M-Labs/thermostat
add net+server modules
This commit is contained in:
parent
d4e8a131ca
commit
c7c5a733f9
|
@ -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"] }
|
||||
|
|
45
src/main.rs
45
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();
|
||||
// }
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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(())
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue