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 = "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"] }
|
||||||
|
|
45
src/main.rs
45
src/main.rs
|
@ -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();
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -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