Syrostan-MCU/src/ethernet.rs

202 lines
6.2 KiB
Rust

use enc424j600::smoltcp_phy;
use smoltcp::wire::{
EthernetAddress, IpAddress, IpCidr, Ipv6Cidr
};
use smoltcp::iface::{NeighborCache, EthernetInterfaceBuilder, EthernetInterface};
use smoltcp::socket::{SocketSet, TcpSocket, TcpSocketBuffer};
use core::str;
use core::fmt::Write;
use smoltcp::time::Instant;
use cortex_m_rt::exception;
///spi
use stm32f1xx_hal::{
time::U32Ext,
delay::Delay
};
/// Timer
use core::cell::RefCell;
use cortex_m::interrupt::Mutex;
use stm32f1xx_hal::{
time::MilliSeconds,
timer::{Timer, Event as TimerEvent},
rcc::Clocks,
stm32::SYST
};
/// Rate in Hz
const TIMER_RATE: u32 = 20;
/// Interval duration in milliseconds
const TIMER_DELTA: u32 = 1000 / TIMER_RATE;
/// Elapsed time in milliseconds
static TIMER_MS: Mutex<RefCell<u32>> = Mutex::new(RefCell::new(0));
/// Setup SysTick exception
fn timer_setup(syst: SYST, clocks: Clocks) {
let timer = Timer::syst(syst, &clocks);
timer.start_count_down(TIMER_RATE.hz()).listen(TimerEvent::Update);
}
/// SysTick exception (Timer)
#[exception]
fn SysTick() {
cortex_m::interrupt::free(|cs| {
*TIMER_MS.borrow(cs)
.borrow_mut() += TIMER_DELTA;
});
}
/// Obtain current time in milliseconds
pub fn timer_now() -> MilliSeconds {
let ms = cortex_m::interrupt::free(|cs| {
*TIMER_MS.borrow(cs)
.borrow()
});
ms.ms()
}
pub struct NetStorage {
ip_addrs: [IpCidr; 1],
neighbor_cache: [Option<(IpAddress, smoltcp::iface::Neighbor)>; 8],
}
static mut NET_STORE: NetStorage = NetStorage {
// Placeholder for the real IP address, which is initialized at runtime.
ip_addrs: [IpCidr::Ipv6(
Ipv6Cidr::SOLICITED_NODE_PREFIX,
)],
neighbor_cache: [None; 8],
};
pub fn ethernet_init<SpiEth> (
spi_eth: SpiEth,
delay: Delay,
clocks: &Clocks
)
// -> EthernetInterface<smoltcp_phy::SmoltcpDevice<SpiEth>>
{
// Init controller
match spi_eth.reset(&mut delay) {
Ok(_) => {
// serial_tx.write_fmt(format_args!("Initializing Ethernet...\n")).unwrap();
}
Err(_) => {
panic!("Ethernet initialization failed!")
}
}
// Read MAC
let mut eth_mac_addr: [u8; 6] = [0; 6];
spi_eth.read_mac_addr(&mut eth_mac_addr);
for i in 0..6 {
let byte = eth_mac_addr[i];
match i {
// 0 => {
// serial_tx.write_fmt(format_args!("MAC Address = {:02x}-", byte)).unwrap();
// },
// 1..=4 => {
// serial_tx.write_fmt(format_args!("{:02x}-", byte)).unwrap();
// },
// 5 => {
// serial_tx.write_fmt(format_args!("{:02x}\n", byte)).unwrap();
// },
_ => ()
};
}
// Init Rx/Tx buffers
spi_eth.init_rxbuf();
spi_eth.init_txbuf();
// serial_tx.write_fmt(format_args!("Ethernet controller initialized\n")).unwrap();
// Init smoltcp interface
let eth_iface = {
let device = smoltcp_phy::SmoltcpDevice::new(spi_eth);
let store = unsafe { &mut NET_STORE };
store.ip_addrs[0] = IpCidr::new(IpAddress::v4(192, 168, 1, 88), 24);
let neighbor_cache = NeighborCache::new(&mut store.neighbor_cache[..]);
EthernetInterfaceBuilder::new(device)
.ethernet_addr(EthernetAddress(eth_mac_addr))
.neighbor_cache(neighbor_cache)
.ip_addrs(&mut store.ip_addrs[..])
.finalize()
};
// serial_tx.write_fmt(format_args!("Ethernet interface initialized\n")).unwrap();
// Setup SysTick after releasing SYST from Delay
// Reference to stm32-eth:examples/ip.rs
timer_setup(delay.free(), *clocks);
// serial_tx.write_fmt(format_args!("Timer initialized\n")).unwrap();
// eth_iface
let iface = eth_iface;
let greet_socket = {
static mut TCP_SERVER_RX_DATA: [u8; 256] = [0; 256];
static mut TCP_SERVER_TX_DATA: [u8; 256] = [0; 256];
let tcp_rx_buffer = TcpSocketBuffer::new(unsafe { &mut TCP_SERVER_RX_DATA[..] });
let tcp_tx_buffer = TcpSocketBuffer::new(unsafe { &mut TCP_SERVER_TX_DATA[..] });
TcpSocket::new(tcp_rx_buffer, tcp_tx_buffer)
};
let mut socket_set_entries = [None, None];
let mut socket_set = SocketSet::new(&mut socket_set_entries[..]);
let greet_handle = socket_set.add(greet_socket);
{
let store = unsafe { &mut NET_STORE };
// serial_tx.write_fmt(format_args!("TCP sockets will listen at {}\n", store.ip_addrs[0].address())).unwrap();
}
// Copied / modified from:
// smoltcp:examples/loopback.rs, examples/server.rs;
// stm32-eth:examples/ip.rs,
// git.m-labs.hk/M-Labs/tnetplug
loop {
// Poll
let now = timer_now().0;
let instant = Instant::from_millis(now as i64);
match iface.poll(&mut socket_set, instant) {
Ok(_) => {
},
Err(e) => {
// serial_tx.write_fmt(format_args!("[{}] Poll error: {:?}\n", instant, e)).unwrap();
}
}
// Control the "greeting" socket (:4321)
{
let mut socket = socket_set.get::<TcpSocket>(greet_handle);
if !socket.is_open() {
// serial_tx.write_fmt(format_args!("[{}] Listening to port 4321 for greeting, please connect to the port\n", instant)).unwrap();
socket.listen(4321).unwrap();
// socket.set_timeout(Some(smoltcp::time::Duration::from_millis(10000)));
}
if socket.can_send() {
let greeting = "Welcome to the server demo for STM32F103!";
write!(socket, "{}\n", greeting).unwrap();
// serial_tx.write_fmt(format_args!("[{}] Greeting sent, socket closed\n", instant)).unwrap();
socket.close();
}
if socket.can_recv() {
// serial_tx.write_fmt(format_args!("[{}] Received packet: {:?}\n",
// instant, socket.recv(|buffer| {(buffer.len(), str::from_utf8(buffer).unwrap())}))).unwrap();
}
}
}
}
// pub fn ethernet_test<SpiEth>
// (mut iface: EthernetInterface<smoltcp_phy::SmoltcpDevice<SpiEth>>)
// {
// // Copied / modified from smoltcp:
// // examples/loopback.rs
// }