2022-11-02 17:18:33 +08:00
|
|
|
// Modified by Wong Tat Hang (aw@m-labs.hk), with original source from
|
|
|
|
// https://github.com/stm32-rs/stm32-eth/blob/master/examples/rtic-echo.rs
|
|
|
|
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
|
|
|
|
|
|
|
use log::{info, warn};
|
|
|
|
use smoltcp::{
|
|
|
|
iface::{
|
|
|
|
Interface, InterfaceBuilder, Neighbor, NeighborCache, Route, SocketHandle, SocketStorage,
|
|
|
|
},
|
|
|
|
socket::{TcpSocket, TcpSocketBuffer, TcpState},
|
|
|
|
wire::{EthernetAddress, IpAddress, IpCidr, Ipv4Address, Ipv4Cidr},
|
|
|
|
};
|
2022-11-01 11:16:55 +08:00
|
|
|
use stm32_eth::stm32::{ETHERNET_DMA, ETHERNET_MAC, ETHERNET_MMC};
|
|
|
|
use stm32_eth::*;
|
2022-11-02 17:18:33 +08:00
|
|
|
use stm32f4xx_hal::{
|
|
|
|
gpio::{gpioa::*, gpiob::*, gpioc::*, Alternate, Input},
|
|
|
|
rcc::Clocks,
|
2022-11-01 11:16:55 +08:00
|
|
|
};
|
|
|
|
|
2022-11-02 17:18:33 +08:00
|
|
|
use crate::app::monotonics;
|
2022-11-01 11:16:55 +08:00
|
|
|
|
|
|
|
pub type EthernetPins =
|
|
|
|
EthPins<PA1<Input>, PA7<Input>, PB11<Input>, PB12<Input>, PB13<Input>, PC4<Input>, PC5<Input>>;
|
|
|
|
|
|
|
|
pub type EthInterface = Interface<'static, &'static mut EthernetDMA<'static, 'static>>;
|
|
|
|
|
|
|
|
const IPV4_ADDR: (u8, u8, u8, u8) = (192, 168, 1, 132);
|
2022-11-02 17:18:33 +08:00
|
|
|
const ADDRESS: (IpAddress, u16) = (
|
|
|
|
IpAddress::Ipv4(Ipv4Address::new(
|
|
|
|
IPV4_ADDR.0,
|
|
|
|
IPV4_ADDR.1,
|
|
|
|
IPV4_ADDR.2,
|
|
|
|
IPV4_ADDR.3,
|
|
|
|
)),
|
|
|
|
1337,
|
|
|
|
);
|
|
|
|
const MAC: [u8; 6] = [0x02, 0x5f, 0x25, 0x37, 0x93, 0x0e];
|
2022-11-01 11:16:55 +08:00
|
|
|
pub struct EthernetPeripherals {
|
|
|
|
pub dma: ETHERNET_DMA,
|
|
|
|
pub mac: ETHERNET_MAC,
|
|
|
|
pub mmc: ETHERNET_MMC,
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct ServerHandle {
|
|
|
|
// storage: &'static mut ServerStorage,
|
2022-11-02 17:18:33 +08:00
|
|
|
socket_handle: SocketHandle,
|
|
|
|
iface: EthInterface,
|
2022-11-01 11:16:55 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
pub struct ServerStorage {
|
|
|
|
rx_ring: [RxRingEntry; 8],
|
|
|
|
tx_ring: [TxRingEntry; 2],
|
|
|
|
storage: NetworkStorage,
|
|
|
|
dma: core::mem::MaybeUninit<EthernetDMA<'static, 'static>>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ServerStorage {
|
|
|
|
pub const fn new() -> Self {
|
2022-11-02 17:18:33 +08:00
|
|
|
ServerStorage {
|
|
|
|
rx_ring: [
|
|
|
|
RxRingEntry::new(),
|
|
|
|
RxRingEntry::new(),
|
|
|
|
RxRingEntry::new(),
|
|
|
|
RxRingEntry::new(),
|
|
|
|
RxRingEntry::new(),
|
|
|
|
RxRingEntry::new(),
|
|
|
|
RxRingEntry::new(),
|
|
|
|
RxRingEntry::new(),
|
|
|
|
],
|
|
|
|
tx_ring: [TxRingEntry::new(), TxRingEntry::new()],
|
2022-11-01 11:16:55 +08:00
|
|
|
storage: NetworkStorage::new(),
|
2022-11-02 17:18:33 +08:00
|
|
|
dma: core::mem::MaybeUninit::uninit(),
|
2022-11-01 11:16:55 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// All storage required for networking
|
|
|
|
pub struct NetworkStorage {
|
|
|
|
pub ip_addrs: [IpCidr; 1],
|
|
|
|
pub sockets: [SocketStorage<'static>; 1],
|
|
|
|
pub tcp_socket_storage: TcpSocketStorage,
|
|
|
|
pub neighbor_cache: [Option<(IpAddress, Neighbor)>; 8],
|
|
|
|
pub routes_cache: [Option<(IpCidr, Route)>; 8],
|
|
|
|
}
|
|
|
|
|
|
|
|
impl NetworkStorage {
|
2022-11-02 17:18:33 +08:00
|
|
|
const IP_INIT: IpCidr = IpCidr::Ipv4(Ipv4Cidr::new(
|
|
|
|
Ipv4Address::new(IPV4_ADDR.0, IPV4_ADDR.1, IPV4_ADDR.2, IPV4_ADDR.3),
|
|
|
|
24,
|
|
|
|
));
|
2022-11-01 11:16:55 +08:00
|
|
|
|
|
|
|
pub const fn new() -> Self {
|
|
|
|
NetworkStorage {
|
|
|
|
ip_addrs: [Self::IP_INIT],
|
|
|
|
neighbor_cache: [None; 8],
|
|
|
|
routes_cache: [None; 8],
|
|
|
|
sockets: [SocketStorage::EMPTY; 1],
|
|
|
|
tcp_socket_storage: TcpSocketStorage::new(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Storage of TCP sockets
|
|
|
|
#[derive(Copy, Clone)]
|
|
|
|
pub struct TcpSocketStorage {
|
|
|
|
rx_storage: [u8; 2048],
|
|
|
|
tx_storage: [u8; 2048],
|
|
|
|
}
|
|
|
|
|
|
|
|
impl TcpSocketStorage {
|
|
|
|
const fn new() -> Self {
|
|
|
|
Self {
|
|
|
|
rx_storage: [0; 2048],
|
|
|
|
tx_storage: [0; 2048],
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn now_fn() -> smoltcp::time::Instant {
|
|
|
|
let time = monotonics::now().duration_since_epoch().to_millis();
|
|
|
|
smoltcp::time::Instant::from_millis(time as i64)
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ServerHandle {
|
|
|
|
pub fn new(
|
2022-11-02 17:18:33 +08:00
|
|
|
eth_pins: EthernetPins,
|
|
|
|
ethernet: EthernetPeripherals,
|
|
|
|
clocks: Clocks,
|
2022-11-01 11:16:55 +08:00
|
|
|
storage: &'static mut ServerStorage,
|
|
|
|
mdio: stm32f4xx_hal::gpio::PA2<Alternate<11>>,
|
2022-11-02 17:18:33 +08:00
|
|
|
mdc: stm32f4xx_hal::gpio::PC1<Alternate<11>>,
|
2022-11-01 11:16:55 +08:00
|
|
|
) -> ServerHandle {
|
|
|
|
let (dma, mac) = stm32_eth::new_with_mii(
|
|
|
|
ethernet.mac,
|
|
|
|
ethernet.mmc,
|
|
|
|
ethernet.dma,
|
|
|
|
&mut storage.rx_ring[..],
|
|
|
|
&mut storage.tx_ring[..],
|
|
|
|
clocks,
|
|
|
|
eth_pins,
|
|
|
|
mdio,
|
2022-11-02 17:18:33 +08:00
|
|
|
mdc,
|
2022-11-01 11:16:55 +08:00
|
|
|
)
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
let mut routes = smoltcp::iface::Routes::new(&mut storage.storage.routes_cache[..]);
|
|
|
|
routes
|
|
|
|
.add_default_ipv4_route(Ipv4Address::new(192, 168, 1, 1))
|
|
|
|
.ok();
|
|
|
|
|
|
|
|
let dma = storage.dma.write(dma);
|
|
|
|
dma.enable_interrupt();
|
2022-11-02 17:18:33 +08:00
|
|
|
|
|
|
|
let rx_buffer =
|
|
|
|
TcpSocketBuffer::new(&mut storage.storage.tcp_socket_storage.rx_storage[..]);
|
|
|
|
let tx_buffer =
|
|
|
|
TcpSocketBuffer::new(&mut storage.storage.tcp_socket_storage.tx_storage[..]);
|
2022-11-01 11:16:55 +08:00
|
|
|
let socket = TcpSocket::new(rx_buffer, tx_buffer);
|
|
|
|
|
|
|
|
let mut iface = InterfaceBuilder::new(dma, &mut storage.storage.sockets[..])
|
|
|
|
.hardware_addr(EthernetAddress(MAC).into())
|
|
|
|
.ip_addrs(&mut storage.storage.ip_addrs[..])
|
|
|
|
.neighbor_cache(NeighborCache::new(&mut storage.storage.neighbor_cache[..]))
|
|
|
|
.routes(routes)
|
|
|
|
.finalize();
|
|
|
|
let mut server = ServerHandle {
|
|
|
|
socket_handle: iface.add_socket(socket),
|
2022-11-02 17:18:33 +08:00
|
|
|
iface: iface,
|
2022-11-01 11:16:55 +08:00
|
|
|
};
|
|
|
|
let socket = server.iface.get_socket::<TcpSocket>(server.socket_handle);
|
|
|
|
socket.listen(ADDRESS).ok();
|
2022-11-02 17:18:33 +08:00
|
|
|
server.iface.poll(now_fn()).ok();
|
2022-11-01 11:16:55 +08:00
|
|
|
if let Ok(mut phy) = EthernetPhy::from_miim(mac, 0) {
|
|
|
|
info!(
|
|
|
|
"Resetting PHY as an extra step. Type: {}",
|
|
|
|
phy.ident_string()
|
|
|
|
);
|
|
|
|
|
|
|
|
phy.phy_init();
|
|
|
|
} else {
|
|
|
|
info!("Not resetting unsupported PHY.");
|
|
|
|
}
|
|
|
|
|
|
|
|
server
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn poll(&mut self, buffer: &mut [u8]) {
|
|
|
|
self.iface.poll(now_fn()).ok();
|
|
|
|
|
|
|
|
let socket = self.iface.get_socket::<TcpSocket>(self.socket_handle);
|
|
|
|
if let Ok(recv_bytes) = socket.recv_slice(buffer) {
|
|
|
|
if recv_bytes > 0 {
|
|
|
|
socket.send_slice(&buffer[..recv_bytes]).ok();
|
|
|
|
info!("Echoed {} bytes.", recv_bytes);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if !socket.is_listening() && !socket.is_open() || socket.state() == TcpState::CloseWait {
|
|
|
|
socket.abort();
|
|
|
|
socket.listen(ADDRESS).ok();
|
|
|
|
warn!("Disconnected... Reopening listening socket.");
|
|
|
|
}
|
|
|
|
|
|
|
|
self.iface.poll(now_fn()).ok();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
use ieee802_3_miim::{
|
|
|
|
phy::{
|
|
|
|
lan87xxa::{LAN8720A, LAN8742A},
|
|
|
|
BarePhy, KSZ8081R,
|
|
|
|
},
|
|
|
|
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, ()> {
|
|
|
|
let mut bare = BarePhy::new(miim, phy_addr, Pause::NoPause);
|
|
|
|
let phy_ident = bare.phy_ident().ok_or(())?;
|
|
|
|
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(()),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// 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());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-11-02 17:18:33 +08:00
|
|
|
}
|