kirdy/src/net/net.rs

464 lines
15 KiB
Rust
Raw Normal View History

use crate::device::sys_timer;
use core::mem::{self, MaybeUninit};
use core::cell::RefCell;
use cortex_m::interrupt::{CriticalSection, Mutex};
2024-03-04 16:13:52 +08:00
use log::{debug, info};
use smoltcp::{
iface::{
self, Interface, SocketHandle, SocketSet, SocketStorage
}, socket::tcp::{Socket, SocketBuffer, State}, time::Instant, wire::{EthernetAddress, IpAddress, IpCidr, Ipv4Address, Ipv4Cidr}
};
use stm32_eth::{
Parts, EthPins, PartsIn,
mac::{Speed, EthernetMACWithMii},
dma::{
TxRingEntry, RxRingEntry, EthernetDMA
}};
use stm32f4xx_hal::{
gpio::{gpioa::*, gpiob::*, gpioc::*, Alternate, Input, Pin},
rcc::Clocks,
interrupt,
};
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, Deserialize, Serialize)]
pub struct IpSettings {
addr: [u8; 4],
port: u16,
prefix_len: u8,
2024-03-06 10:34:57 +08:00
gateway: [u8; 4],
}
impl Default for IpSettings {
fn default() -> Self {
IpSettings {
addr: [192, 168, 1, 128],
port: 1337,
prefix_len: 24,
2024-03-06 10:34:57 +08:00
gateway: [192, 168, 1, 1]
}
}
}
/// Interrupt pending flag: set by the `ETH` interrupt handler, should
/// be cleared before polling the interface.
static NET_PENDING: Mutex<RefCell<bool>> = Mutex::new(RefCell::new(false));
pub struct ServerHandle {
socket_handles: [SocketHandle; NUM_OF_SOCKETS],
socket_set: SocketSet<'static>,
socket_addr: (IpAddress, u16),
iface: EthInterface,
dma: EthernetDMA<'static, 'static>,
phy: EthernetPhy<EthernetMACWithMii<Pin<'A', 2, Alternate<11>>, Pin<'C', 1, Alternate<11>>>>,
link_was_up: bool,
}
pub type EthernetPins =
EthPins<PA1<Input>, PA7<Input>, PB11<Input>, PB12<Input>, PB13<Input>, PC4<Input>, PC5<Input>>;
pub struct EthernetMgmtPins {
pub mdio: PA2<Alternate<11>>,
pub mdc: PC1<Alternate<11>>,
}
pub type EthInterface = Interface;
pub const NUM_OF_SOCKETS : usize = 4;
const TCP_BUFFER_SIZE: usize = 2048;
static mut RX_RING: Option<[RxRingEntry; 8]> = None;
static mut TX_RING: Option<[TxRingEntry; 2]> = None;
static mut SOCKET_STORAGE: Option<[SocketStorage<'static>; NUM_OF_SOCKETS]> = None;
fn now_fn() -> smoltcp::time::Instant {
Instant::from_millis(i64::from(sys_timer::now()))
}
static mut SERVER_HANDLE : Option<ServerHandle> = None;
impl ServerHandle {
pub fn new (eth_pins: EthernetPins,
eth_mgmt_pins: EthernetMgmtPins,
ethernet_parts_in: PartsIn,
clocks: Clocks,
mac_addr: [u8; 6],
ip_settings: IpSettings,
) {
let rx_ring = unsafe { RX_RING.get_or_insert(Default::default()) };
let tx_ring = unsafe { TX_RING.get_or_insert(Default::default()) };
let socket_storage = unsafe { SOCKET_STORAGE.get_or_insert([SocketStorage::EMPTY; NUM_OF_SOCKETS]) };
let Parts {
mut dma,
mac,
#[cfg(feature = "ptp")]
..
} = stm32_eth::new_with_mii(
ethernet_parts_in,
&mut rx_ring[..],
&mut tx_ring[..],
clocks,
eth_pins,
eth_mgmt_pins.mdio,
eth_mgmt_pins.mdc
).unwrap();
let ip_init = IpCidr::Ipv4(Ipv4Cidr::new(
Ipv4Address::new(ip_settings.addr[0], ip_settings.addr[1], ip_settings.addr[2], ip_settings.addr[3]),
ip_settings.prefix_len,
));
let socket_addr: (IpAddress, u16) = (
IpAddress::Ipv4(Ipv4Address::new(
ip_settings.addr[0],
ip_settings.addr[1],
ip_settings.addr[2],
ip_settings.addr[3],
)),
ip_settings.port,
);
let mut routes = smoltcp::iface::Routes::new();
routes
2024-03-06 10:34:57 +08:00
.add_default_ipv4_route(Ipv4Address::new(ip_settings.gateway[0], ip_settings.gateway[1], ip_settings.gateway[2], ip_settings.gateway[3]))
.ok();
dma.enable_interrupt();
let config = iface::Config::new(EthernetAddress::from_bytes(&mac_addr).into());
let mut iface = Interface::new(config, &mut &mut dma, smoltcp::time::Instant::ZERO);
iface.set_hardware_addr(EthernetAddress(mac_addr).into());
debug!("MAC ADDRESS: {:02X?}", EthernetAddress(mac_addr));
debug!("IP Settings: {:?}", ip_settings);
iface.update_ip_addrs(|addr| {
addr.push(ip_init).unwrap();
});
let mut socket_set = SocketSet::new(&mut socket_storage[..]);
let tcp_handles = {
// Do not use NUM_OF_SOCKETS to define array size to
// remind developers to create/remove tcp_handles accordingly after changing NUM_OF_SOCKETS
let mut tcp_handles: [MaybeUninit<SocketHandle>; 4]= unsafe {
MaybeUninit::uninit().assume_init()
};
macro_rules! create_tcp_handle {
($rx_storage:ident, $tx_storage:ident, $handle:expr) => {
static mut $rx_storage : [u8; TCP_BUFFER_SIZE] = [0; TCP_BUFFER_SIZE];
static mut $tx_storage : [u8; TCP_BUFFER_SIZE] = [0; TCP_BUFFER_SIZE];
unsafe {
let rx_buffer = SocketBuffer::new(&mut $rx_storage[..]);
let tx_buffer = SocketBuffer::new(&mut $tx_storage[..]);
$handle.write(socket_set.add(Socket::new(rx_buffer, tx_buffer)));
}
}
}
create_tcp_handle!(RX_STORAGE0, TX_STORAGE0, tcp_handles[0]);
create_tcp_handle!(RX_STORAGE1, TX_STORAGE1, tcp_handles[1]);
create_tcp_handle!(RX_STORAGE2, TX_STORAGE2, tcp_handles[2]);
create_tcp_handle!(RX_STORAGE3, TX_STORAGE3, tcp_handles[3]);
unsafe { mem::transmute::<_, [SocketHandle; 4]>(tcp_handles) }
};
for i in 0..NUM_OF_SOCKETS {
let socket = socket_set.get_mut::<Socket>(tcp_handles[i]);
socket.listen(socket_addr).ok();
}
iface.poll(Instant::from_millis(i64::from(sys_timer::now())), &mut &mut dma, &mut socket_set);
if let Ok(mut phy) = EthernetPhy::from_miim(mac, 0) {
info!(
"Resetting PHY as an extra step. Type: {}",
phy.ident_string()
);
phy.phy_init();
let server = ServerHandle {
socket_handles: tcp_handles,
socket_set: socket_set,
socket_addr: socket_addr,
iface: iface,
dma: dma,
phy: phy,
link_was_up: false,
};
unsafe {
SERVER_HANDLE = Some(server);
}
} else {
panic!("Ethernet Phy is not supported");
}
}
pub fn update_link_speed(&mut self) {
if !self.link_was_up & self.phy.phy_link_up() {
if let Some(speed) = self.phy.speed().map(|s| match s {
PhySpeed::HalfDuplexBase10T => Speed::HalfDuplexBase10T,
PhySpeed::FullDuplexBase10T => Speed::FullDuplexBase10T,
PhySpeed::HalfDuplexBase100Tx => Speed::HalfDuplexBase100Tx,
PhySpeed::FullDuplexBase100Tx => Speed::FullDuplexBase100Tx,
}) {
info!("New eth link is up. Setting detected PhySpeed: {:?}", speed);
self.phy.get_miim().set_speed(speed);
} else {
debug!("Failed to detect link speed.");
}
}
self.link_was_up = self.phy.phy_link_up();
}
pub fn recv(&mut self, buffer: &mut [u8], socket_handles: SocketHandle)-> Result<usize, smoltcp::socket::tcp::RecvError> {
self.iface.poll(now_fn(), &mut &mut self.dma, &mut self.socket_set);
let socket = self.socket_set.get_mut::<Socket>(socket_handles);
socket.recv_slice(buffer)
}
pub fn send(&mut self, buffer: &mut [u8], num_bytes: usize, socket_handles: SocketHandle) {
let socket = self.socket_set.get_mut::<Socket>(socket_handles);
if num_bytes > 0 {
socket.send_slice(&buffer[..num_bytes]).ok();
info!("Sent {} bytes.", num_bytes);
}
// Send bytes out
self.iface.poll(now_fn(), &mut &mut self.dma, &mut self.socket_set);
}
pub fn is_socket_connected(&mut self, socket_handles: SocketHandle)->bool {
let socket = self.socket_set.get_mut::<Socket>(socket_handles);
socket.state() == State::Established
}
pub fn poll_socket_status(&mut self, socket_handles: SocketHandle)-> bool {
let socket = self.socket_set.get_mut::<Socket>(socket_handles);
if !socket.is_listening() && !socket.is_open() || socket.state() == State::CloseWait {
socket.abort();
socket.listen(self.socket_addr).ok();
info!("Disconnected... Reopening listening socket.");
return false;
} else if socket.state() == State::Closed || socket.state() == State::Closing {
return false;
}
return true;
}
pub fn close_socket(&mut self, socket_handles: SocketHandle) {
let socket = self.socket_set.get_mut::<Socket>(socket_handles);
socket.abort();
}
}
use ieee802_3_miim::{
phy::{
lan87xxa::{LAN8720A, LAN8742A},
BarePhy, KSZ8081R,
PhySpeed
},
Miim, Pause, Phy,
};
/// An ethernet PHY
pub enum EthernetPhy<M: Miim> {
/// LAN8720A
LAN8720A(LAN8720A<M>),
/// LAN8742A
LAN8742A(LAN8742A<M>),
/// KSZ8081R
KSZ8081R(KSZ8081R<M>),
}
impl<M: Miim> Phy<M> for EthernetPhy<M> {
fn best_supported_advertisement(&self) -> ieee802_3_miim::AutoNegotiationAdvertisement {
unimplemented!()
}
fn get_miim(&mut self) -> &mut M {
match self {
EthernetPhy::LAN8720A(phy) => phy.get_miim(),
EthernetPhy::LAN8742A(phy) => phy.get_miim(),
EthernetPhy::KSZ8081R(phy) => phy.get_miim(),
}
}
fn get_phy_addr(&self) -> u8 {
match self {
EthernetPhy::LAN8720A(phy) => phy.get_phy_addr(),
EthernetPhy::LAN8742A(phy) => phy.get_phy_addr(),
EthernetPhy::KSZ8081R(phy) => phy.get_phy_addr(),
}
}
}
impl<M: Miim> EthernetPhy<M> {
/// Attempt to create one of the known PHYs from the given
/// MIIM.
///
/// Returns an error if the PHY does not support the extended register
/// set, or if the PHY's identifier does not correspond to a known PHY.
pub fn from_miim(miim: M, phy_addr: u8) -> Result<Self, M> {
let mut bare = BarePhy::new(miim, phy_addr, Pause::NoPause);
let phy_ident = if let Some(id) = bare.phy_ident() {
id.raw_u32()
} else {
return Err(bare.release());
};
let miim = bare.release();
match phy_ident & 0xFFFFFFF0 {
0x0007C0F0 => Ok(Self::LAN8720A(LAN8720A::new(miim, phy_addr))),
0x0007C130 => Ok(Self::LAN8742A(LAN8742A::new(miim, phy_addr))),
0x00221560 => Ok(Self::KSZ8081R(KSZ8081R::new(miim, phy_addr))),
_ => Err(miim),
}
}
/// Get a string describing the type of PHY
pub const fn ident_string(&self) -> &'static str {
match self {
EthernetPhy::LAN8720A(_) => "LAN8720A",
EthernetPhy::LAN8742A(_) => "LAN8742A",
EthernetPhy::KSZ8081R(_) => "KSZ8081R",
}
}
/// Initialize the PHY
pub fn phy_init(&mut self) {
match self {
EthernetPhy::LAN8720A(phy) => phy.phy_init(),
EthernetPhy::LAN8742A(phy) => phy.phy_init(),
EthernetPhy::KSZ8081R(phy) => {
phy.set_autonegotiation_advertisement(phy.best_supported_advertisement());
}
}
}
#[allow(dead_code)]
pub fn speed(&mut self) -> Option<ieee802_3_miim::phy::PhySpeed> {
match self {
EthernetPhy::LAN8720A(phy) => phy.link_speed(),
EthernetPhy::LAN8742A(phy) => phy.link_speed(),
EthernetPhy::KSZ8081R(phy) => phy.link_speed(),
}
}
#[allow(dead_code)]
pub fn release(self) -> M {
match self {
EthernetPhy::LAN8720A(phy) => phy.release(),
EthernetPhy::LAN8742A(phy) => phy.release(),
EthernetPhy::KSZ8081R(phy) => phy.release(),
}
}
}
pub fn eth_poll_and_update_link_speed() {
unsafe {
if let Some(ref mut server_handle ) = SERVER_HANDLE {
server_handle.update_link_speed();
}
else {
panic!("eth_poll_and_update_link_speed is called before init");
}
}
}
pub fn eth_send(buffer: &mut [u8], num_bytes: usize, socket_handles: SocketHandle) {
unsafe {
if let Some(ref mut server_handle ) = SERVER_HANDLE {
server_handle.send(buffer, num_bytes, socket_handles);
}
else {
panic!("eth_send is called before init");
}
}
}
pub fn eth_recv(buffer: &mut [u8], socket_handles: SocketHandle)-> usize{
unsafe {
if let Some(ref mut server_handle ) = SERVER_HANDLE {
match server_handle.recv(buffer, socket_handles){
Ok(recv_bytes) => {return recv_bytes}
Err(err) => {
debug!("TCP Recv Error: {}", err);
return 0
}
};
}
else {
panic!("eth_send is called before init");
}
}
}
pub fn eth_is_socket_connected(socket_handles: SocketHandle) -> bool {
unsafe {
if let Some(ref mut server_handle ) = SERVER_HANDLE {
server_handle.is_socket_connected(socket_handles)
}
else {
panic!("eth_is_socket_connected is called before init");
}
}
}
pub fn eth_is_socket_active(socket_handles: SocketHandle) -> bool {
unsafe {
if let Some(ref mut server_handle ) = SERVER_HANDLE {
server_handle.poll_socket_status(socket_handles)
}
else {
panic!("eth_is_socket_active is called before init");
}
}
}
pub fn eth_close_socket(socket_handles: SocketHandle) {
unsafe {
if let Some(ref mut server_handle ) = SERVER_HANDLE {
server_handle.close_socket(socket_handles)
}
else {
panic!("eth_close_socket is called before init");
}
}
}
pub fn for_each<F: FnMut(SocketHandle, usize)>(mut callback: F) {
unsafe {
if let Some(ref mut server_handle ) = SERVER_HANDLE {
for i in 0..NUM_OF_SOCKETS {
callback(server_handle.socket_handles[i], i);
}
}
else {
panic!("eth_close_socket is called before init");
}
}
}
/// Potentially wake up from `wfi()`, set the interrupt pending flag,
/// clear interrupt flags.
#[interrupt]
fn ETH() {
let interrupt_reason = stm32_eth::eth_interrupt_handler();
cortex_m::interrupt::free(|cs| {
*NET_PENDING.borrow(cs)
.borrow_mut() = true;
});
debug!("Ethernet Interrupt{:?}", interrupt_reason);
}
/// Has an interrupt occurred since last call to `clear_pending()`?
pub fn is_pending(cs: &CriticalSection) -> bool {
*NET_PENDING.borrow(cs)
.borrow()
}
/// Clear the interrupt pending flag before polling the interface for
/// data.
pub fn clear_pending(cs: &CriticalSection) {
*NET_PENDING.borrow(cs)
.borrow_mut() = false;
}