Compare commits
4 Commits
232a08f110
...
6d17703e6b
Author | SHA1 | Date |
---|---|---|
Harry Ho | 6d17703e6b | |
Harry Ho | 78e4d82660 | |
Harry Ho | b9b28f0725 | |
Harry Ho | 3529fcd192 |
|
@ -17,8 +17,7 @@ use stm32f4xx_hal::{
|
||||||
spi::Spi,
|
spi::Spi,
|
||||||
time::Hertz
|
time::Hertz
|
||||||
};
|
};
|
||||||
use enc424j600;
|
use enc424j600::smoltcp_phy;
|
||||||
use enc424j600::{smoltcp_phy, EthController};
|
|
||||||
|
|
||||||
use smoltcp::wire::{
|
use smoltcp::wire::{
|
||||||
EthernetAddress, IpAddress, IpCidr, Ipv6Cidr
|
EthernetAddress, IpAddress, IpCidr, Ipv6Cidr
|
||||||
|
@ -78,7 +77,7 @@ use stm32f4xx_hal::{
|
||||||
Alternate, AF5, Output, PushPull
|
Alternate, AF5, Output, PushPull
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
type BoosterSpiEth = enc424j600::SpiEth<
|
type SpiEth = enc424j600::Enc424j600<
|
||||||
Spi<SPI1, (PA5<Alternate<AF5>>, PA6<Alternate<AF5>>, PA7<Alternate<AF5>>)>,
|
Spi<SPI1, (PA5<Alternate<AF5>>, PA6<Alternate<AF5>>, PA7<Alternate<AF5>>)>,
|
||||||
PA4<Output<PushPull>>,
|
PA4<Output<PushPull>>,
|
||||||
fn(u32) -> ()
|
fn(u32) -> ()
|
||||||
|
@ -102,7 +101,7 @@ const APP: () = {
|
||||||
struct Resources {
|
struct Resources {
|
||||||
eth_iface: EthernetInterface<
|
eth_iface: EthernetInterface<
|
||||||
'static,
|
'static,
|
||||||
smoltcp_phy::SmoltcpDevice<BoosterSpiEth>>,
|
smoltcp_phy::SmoltcpDevice<SpiEth>>,
|
||||||
itm: ITM
|
itm: ITM
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -157,11 +156,11 @@ const APP: () = {
|
||||||
let delay_ns_fp: fn(u32) -> () = |time_ns| {
|
let delay_ns_fp: fn(u32) -> () = |time_ns| {
|
||||||
cortex_m::asm::delay((time_ns*21)/125 + 1)
|
cortex_m::asm::delay((time_ns*21)/125 + 1)
|
||||||
};
|
};
|
||||||
enc424j600::SpiEth::new(spi_eth_port, spi1_nss, delay_ns_fp)
|
SpiEth::new(spi_eth_port, spi1_nss, delay_ns_fp)
|
||||||
};
|
};
|
||||||
|
|
||||||
// Init controller
|
// Init controller
|
||||||
match spi_eth.init_dev() {
|
match spi_eth.reset() {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
iprintln!(stim0, "Initializing Ethernet...")
|
iprintln!(stim0, "Initializing Ethernet...")
|
||||||
}
|
}
|
||||||
|
@ -172,7 +171,7 @@ const APP: () = {
|
||||||
|
|
||||||
// Read MAC
|
// Read MAC
|
||||||
let mut eth_mac_addr: [u8; 6] = [0; 6];
|
let mut eth_mac_addr: [u8; 6] = [0; 6];
|
||||||
spi_eth.read_from_mac(&mut eth_mac_addr);
|
spi_eth.read_mac_addr(&mut eth_mac_addr);
|
||||||
for i in 0..6 {
|
for i in 0..6 {
|
||||||
let byte = eth_mac_addr[i];
|
let byte = eth_mac_addr[i];
|
||||||
match i {
|
match i {
|
||||||
|
|
|
@ -17,8 +17,7 @@ use stm32f4xx_hal::{
|
||||||
spi::Spi,
|
spi::Spi,
|
||||||
time::Hertz
|
time::Hertz
|
||||||
};
|
};
|
||||||
use enc424j600;
|
use enc424j600::EthPhy;
|
||||||
use enc424j600::EthController;
|
|
||||||
|
|
||||||
///
|
///
|
||||||
use stm32f4xx_hal::{
|
use stm32f4xx_hal::{
|
||||||
|
@ -28,15 +27,16 @@ use stm32f4xx_hal::{
|
||||||
Alternate, AF5, Output, PushPull
|
Alternate, AF5, Output, PushPull
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
type BoosterSpiEth = enc424j600::SpiEth<
|
type SpiEth = enc424j600::Enc424j600<
|
||||||
Spi<SPI1, (PA5<Alternate<AF5>>, PA6<Alternate<AF5>>, PA7<Alternate<AF5>>)>,
|
Spi<SPI1, (PA5<Alternate<AF5>>, PA6<Alternate<AF5>>, PA7<Alternate<AF5>>)>,
|
||||||
PA4<Output<PushPull>>,
|
PA4<Output<PushPull>>,
|
||||||
fn(u32)>;
|
fn(u32) -> ()
|
||||||
|
>;
|
||||||
|
|
||||||
#[rtic::app(device = stm32f4xx_hal::stm32, peripherals = true, monotonic = rtic::cyccnt::CYCCNT)]
|
#[rtic::app(device = stm32f4xx_hal::stm32, peripherals = true, monotonic = rtic::cyccnt::CYCCNT)]
|
||||||
const APP: () = {
|
const APP: () = {
|
||||||
struct Resources {
|
struct Resources {
|
||||||
spi_eth: BoosterSpiEth,
|
spi_eth: SpiEth,
|
||||||
delay: Delay,
|
delay: Delay,
|
||||||
itm: ITM,
|
itm: ITM,
|
||||||
}
|
}
|
||||||
|
@ -87,11 +87,11 @@ const APP: () = {
|
||||||
let delay_ns: fn(u32) -> () = |time_ns| {
|
let delay_ns: fn(u32) -> () = |time_ns| {
|
||||||
cortex_m::asm::delay((time_ns*21)/125 + 1)
|
cortex_m::asm::delay((time_ns*21)/125 + 1)
|
||||||
};
|
};
|
||||||
enc424j600::SpiEth::new(spi_eth_port, spi1_nss, delay_ns)
|
SpiEth::new(spi_eth_port, spi1_nss, delay_ns)
|
||||||
};
|
};
|
||||||
|
|
||||||
// Init
|
// Init
|
||||||
match spi_eth.init_dev() {
|
match spi_eth.reset() {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
iprintln!(stim0, "Initializing Ethernet...")
|
iprintln!(stim0, "Initializing Ethernet...")
|
||||||
}
|
}
|
||||||
|
@ -102,7 +102,7 @@ const APP: () = {
|
||||||
|
|
||||||
// Read MAC
|
// Read MAC
|
||||||
let mut eth_mac_addr: [u8; 6] = [0; 6];
|
let mut eth_mac_addr: [u8; 6] = [0; 6];
|
||||||
spi_eth.read_from_mac(&mut eth_mac_addr);
|
spi_eth.read_mac_addr(&mut eth_mac_addr);
|
||||||
for i in 0..6 {
|
for i in 0..6 {
|
||||||
let byte = eth_mac_addr[i];
|
let byte = eth_mac_addr[i];
|
||||||
match i {
|
match i {
|
||||||
|
@ -157,7 +157,7 @@ const APP: () = {
|
||||||
_ => ()
|
_ => ()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
c.resources.spi_eth.send_raw_packet(ð_tx_packet);
|
c.resources.spi_eth.send_packet(ð_tx_packet);
|
||||||
iprintln!(stim0, "Packet sent");
|
iprintln!(stim0, "Packet sent");
|
||||||
c.resources.delay.delay_ms(100_u32);
|
c.resources.delay.delay_ms(100_u32);
|
||||||
}
|
}
|
||||||
|
|
128
src/lib.rs
128
src/lib.rs
|
@ -20,36 +20,31 @@ pub mod nal;
|
||||||
/// Max raw frame array size
|
/// Max raw frame array size
|
||||||
pub const RAW_FRAME_LENGTH_MAX: usize = 1518;
|
pub const RAW_FRAME_LENGTH_MAX: usize = 1518;
|
||||||
|
|
||||||
pub trait EthController {
|
/// Trait representing PHY layer of ENC424J600
|
||||||
fn init_dev(&mut self) -> Result<(), EthControllerError>;
|
pub trait EthPhy {
|
||||||
fn init_rxbuf(&mut self) -> Result<(), EthControllerError>;
|
fn recv_packet(&mut self, is_poll: bool) -> Result<rx::RxPacket, Error>;
|
||||||
fn init_txbuf(&mut self) -> Result<(), EthControllerError>;
|
fn send_packet(&mut self, packet: &tx::TxPacket) -> Result<(), Error>;
|
||||||
fn receive_next(&mut self, is_poll: bool) -> Result<rx::RxPacket, EthControllerError>;
|
|
||||||
fn send_raw_packet(&mut self, packet: &tx::TxPacket) -> Result<(), EthControllerError>;
|
|
||||||
fn set_promiscuous(&mut self) -> Result<(), EthControllerError>;
|
|
||||||
fn read_from_mac(&mut self, mac: &mut [u8]) -> Result<(), EthControllerError>;
|
|
||||||
fn write_mac_address(&mut self, mac: &[u8]) -> Result<(), EthControllerError>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// TODO: Improve these error types
|
/// TODO: Improve these error types
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum EthControllerError {
|
pub enum Error {
|
||||||
SpiPortError,
|
SpiPortError,
|
||||||
GeneralError,
|
RegisterError,
|
||||||
// TODO: Better name?
|
// TODO: Better name?
|
||||||
NoRxPacketError
|
NoRxPacketError
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<spi::SpiPortError> for EthControllerError {
|
impl From<spi::Error> for Error {
|
||||||
fn from(_: spi::SpiPortError) -> EthControllerError {
|
fn from(_: spi::Error) -> Error {
|
||||||
EthControllerError::SpiPortError
|
Error::SpiPortError
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Ethernet controller using SPI interface
|
/// ENC424J600 controller in SPI mode
|
||||||
pub struct SpiEth<SPI: Transfer<u8>,
|
pub struct Enc424j600<SPI: Transfer<u8>,
|
||||||
NSS: OutputPin,
|
NSS: OutputPin,
|
||||||
F: FnMut(u32) -> ()> {
|
F: FnMut(u32) -> ()> {
|
||||||
spi_port: spi::SpiPort<SPI, NSS, F>,
|
spi_port: spi::SpiPort<SPI, NSS, F>,
|
||||||
rx_buf: rx::RxBuffer,
|
rx_buf: rx::RxBuffer,
|
||||||
tx_buf: tx::TxBuffer
|
tx_buf: tx::TxBuffer
|
||||||
|
@ -57,26 +52,29 @@ pub struct SpiEth<SPI: Transfer<u8>,
|
||||||
|
|
||||||
impl <SPI: Transfer<u8>,
|
impl <SPI: Transfer<u8>,
|
||||||
NSS: OutputPin,
|
NSS: OutputPin,
|
||||||
F: FnMut(u32) -> ()> SpiEth<SPI, NSS, F> {
|
F: FnMut(u32) -> ()> Enc424j600<SPI, NSS, F> {
|
||||||
pub fn new(spi: SPI, nss: NSS, delay_ns: F) -> Self {
|
pub fn new(spi: SPI, nss: NSS, delay_ns: F) -> Self {
|
||||||
SpiEth {
|
Enc424j600 {
|
||||||
spi_port: spi::SpiPort::new(spi, nss, delay_ns),
|
spi_port: spi::SpiPort::new(spi, nss, delay_ns),
|
||||||
rx_buf: rx::RxBuffer::new(),
|
rx_buf: rx::RxBuffer::new(),
|
||||||
tx_buf: tx::TxBuffer::new()
|
tx_buf: tx::TxBuffer::new()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl <SPI: Transfer<u8>,
|
pub fn init(&mut self) -> Result<(), Error> {
|
||||||
NSS: OutputPin,
|
self.reset()?;
|
||||||
F: FnMut(u32) -> ()> EthController for SpiEth<SPI, NSS, F> {
|
self.init_rxbuf()?;
|
||||||
fn init_dev(&mut self) -> Result<(), EthControllerError> {
|
self.init_txbuf()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn reset(&mut self) -> Result<(), Error> {
|
||||||
// Write 0x1234 to EUDAST
|
// Write 0x1234 to EUDAST
|
||||||
self.spi_port.write_reg_16b(spi::addrs::EUDAST, 0x1234)?;
|
self.spi_port.write_reg_16b(spi::addrs::EUDAST, 0x1234)?;
|
||||||
// Verify that EUDAST is 0x1234
|
// Verify that EUDAST is 0x1234
|
||||||
let mut eudast = self.spi_port.read_reg_16b(spi::addrs::EUDAST)?;
|
let mut eudast = self.spi_port.read_reg_16b(spi::addrs::EUDAST)?;
|
||||||
if eudast != 0x1234 {
|
if eudast != 0x1234 {
|
||||||
return Err(EthControllerError::GeneralError)
|
return Err(Error::RegisterError)
|
||||||
}
|
}
|
||||||
// Poll CLKRDY (ESTAT<12>) to check if it is set
|
// Poll CLKRDY (ESTAT<12>) to check if it is set
|
||||||
loop {
|
loop {
|
||||||
|
@ -90,13 +88,13 @@ impl <SPI: Transfer<u8>,
|
||||||
// Verify that EUDAST is 0x0000
|
// Verify that EUDAST is 0x0000
|
||||||
eudast = self.spi_port.read_reg_16b(spi::addrs::EUDAST)?;
|
eudast = self.spi_port.read_reg_16b(spi::addrs::EUDAST)?;
|
||||||
if eudast != 0x0000 {
|
if eudast != 0x0000 {
|
||||||
return Err(EthControllerError::GeneralError)
|
return Err(Error::RegisterError)
|
||||||
}
|
}
|
||||||
self.spi_port.delay_us(256);
|
self.spi_port.delay_us(256);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn init_rxbuf(&mut self) -> Result<(), EthControllerError> {
|
pub fn init_rxbuf(&mut self) -> Result<(), Error> {
|
||||||
// Set ERXST pointer
|
// Set ERXST pointer
|
||||||
self.spi_port.write_reg_16b(spi::addrs::ERXST, self.rx_buf.get_wrap_addr())?;
|
self.spi_port.write_reg_16b(spi::addrs::ERXST, self.rx_buf.get_wrap_addr())?;
|
||||||
// Set ERXTAIL pointer
|
// Set ERXTAIL pointer
|
||||||
|
@ -109,22 +107,57 @@ impl <SPI: Transfer<u8>,
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn init_txbuf(&mut self) -> Result<(), EthControllerError> {
|
pub fn init_txbuf(&mut self) -> Result<(), Error> {
|
||||||
// Set EGPWRPT pointer
|
// Set EGPWRPT pointer
|
||||||
self.spi_port.write_reg_16b(spi::addrs::EGPWRPT, 0x0000)?;
|
self.spi_port.write_reg_16b(spi::addrs::EGPWRPT, 0x0000)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set controller to Promiscuous Mode
|
||||||
|
pub fn set_promiscuous(&mut self) -> Result<(), Error> {
|
||||||
|
// From Section 10.12, ENC424J600 Data Sheet:
|
||||||
|
// "To accept all incoming frames regardless of content (Promiscuous mode),
|
||||||
|
// set the CRCEN, RUNTEN, UCEN, NOTMEEN and MCEN bits."
|
||||||
|
let erxfcon_lo = self.spi_port.read_reg_8b(spi::addrs::ERXFCON)?;
|
||||||
|
self.spi_port.write_reg_8b(spi::addrs::ERXFCON, 0b0101_1110 | (erxfcon_lo & 0b1010_0001))?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Read MAC to [u8; 6]
|
||||||
|
pub fn read_mac_addr(&mut self, mac: &mut [u8]) -> Result<(), Error> {
|
||||||
|
mac[0] = self.spi_port.read_reg_8b(spi::addrs::MAADR1)?;
|
||||||
|
mac[1] = self.spi_port.read_reg_8b(spi::addrs::MAADR1 + 1)?;
|
||||||
|
mac[2] = self.spi_port.read_reg_8b(spi::addrs::MAADR2)?;
|
||||||
|
mac[3] = self.spi_port.read_reg_8b(spi::addrs::MAADR2 + 1)?;
|
||||||
|
mac[4] = self.spi_port.read_reg_8b(spi::addrs::MAADR3)?;
|
||||||
|
mac[5] = self.spi_port.read_reg_8b(spi::addrs::MAADR3 + 1)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write_mac_addr(&mut self, mac: &[u8]) -> Result<(), Error> {
|
||||||
|
self.spi_port.write_reg_8b(spi::addrs::MAADR1, mac[0])?;
|
||||||
|
self.spi_port.write_reg_8b(spi::addrs::MAADR1 + 1, mac[1])?;
|
||||||
|
self.spi_port.write_reg_8b(spi::addrs::MAADR2, mac[2])?;
|
||||||
|
self.spi_port.write_reg_8b(spi::addrs::MAADR2 + 1, mac[3])?;
|
||||||
|
self.spi_port.write_reg_8b(spi::addrs::MAADR3, mac[4])?;
|
||||||
|
self.spi_port.write_reg_8b(spi::addrs::MAADR3 + 1, mac[5])?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl <SPI: Transfer<u8>,
|
||||||
|
NSS: OutputPin,
|
||||||
|
F: FnMut(u32) -> ()> EthPhy for Enc424j600<SPI, NSS, F> {
|
||||||
/// Receive the next packet and return it
|
/// Receive the next packet and return it
|
||||||
/// Set is_poll to true for returning until PKTIF is set;
|
/// Set is_poll to true for returning until PKTIF is set;
|
||||||
/// Set is_poll to false for returning Err when PKTIF is not set
|
/// Set is_poll to false for returning Err when PKTIF is not set
|
||||||
fn receive_next(&mut self, is_poll: bool) -> Result<rx::RxPacket, EthControllerError> {
|
fn recv_packet(&mut self, is_poll: bool) -> Result<rx::RxPacket, Error> {
|
||||||
// Poll PKTIF (EIR<4>) to check if it is set
|
// Poll PKTIF (EIR<4>) to check if it is set
|
||||||
loop {
|
loop {
|
||||||
let eir = self.spi_port.read_reg_16b(spi::addrs::EIR)?;
|
let eir = self.spi_port.read_reg_16b(spi::addrs::EIR)?;
|
||||||
if eir & 0x40 == 0x40 { break }
|
if eir & 0x40 == 0x40 { break }
|
||||||
if !is_poll {
|
if !is_poll {
|
||||||
return Err(EthControllerError::NoRxPacketError)
|
return Err(Error::NoRxPacketError)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Set ERXRDPT pointer to next_addr
|
// Set ERXRDPT pointer to next_addr
|
||||||
|
@ -160,7 +193,7 @@ impl <SPI: Transfer<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Send an established packet
|
/// Send an established packet
|
||||||
fn send_raw_packet(&mut self, packet: &tx::TxPacket) -> Result<(), EthControllerError> {
|
fn send_packet(&mut self, packet: &tx::TxPacket) -> Result<(), Error> {
|
||||||
// Set EGPWRPT pointer to next_addr
|
// Set EGPWRPT pointer to next_addr
|
||||||
self.spi_port.write_reg_16b(spi::addrs::EGPWRPT, self.tx_buf.get_next_addr())?;
|
self.spi_port.write_reg_16b(spi::addrs::EGPWRPT, self.tx_buf.get_next_addr())?;
|
||||||
// Copy packet data to SRAM Buffer
|
// Copy packet data to SRAM Buffer
|
||||||
|
@ -187,35 +220,4 @@ impl <SPI: Transfer<u8>,
|
||||||
tx::GPBUFEN_DEFAULT);
|
tx::GPBUFEN_DEFAULT);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set controller to Promiscuous Mode
|
|
||||||
fn set_promiscuous(&mut self) -> Result<(), EthControllerError> {
|
|
||||||
// From Section 10.12, ENC424J600 Data Sheet:
|
|
||||||
// "To accept all incoming frames regardless of content (Promiscuous mode),
|
|
||||||
// set the CRCEN, RUNTEN, UCEN, NOTMEEN and MCEN bits."
|
|
||||||
let erxfcon_lo = self.spi_port.read_reg_8b(spi::addrs::ERXFCON)?;
|
|
||||||
self.spi_port.write_reg_8b(spi::addrs::ERXFCON, 0b0101_1110 | (erxfcon_lo & 0b1010_0001))?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Read MAC to [u8; 6]
|
|
||||||
fn read_from_mac(&mut self, mac: &mut [u8]) -> Result<(), EthControllerError> {
|
|
||||||
mac[0] = self.spi_port.read_reg_8b(spi::addrs::MAADR1)?;
|
|
||||||
mac[1] = self.spi_port.read_reg_8b(spi::addrs::MAADR1 + 1)?;
|
|
||||||
mac[2] = self.spi_port.read_reg_8b(spi::addrs::MAADR2)?;
|
|
||||||
mac[3] = self.spi_port.read_reg_8b(spi::addrs::MAADR2 + 1)?;
|
|
||||||
mac[4] = self.spi_port.read_reg_8b(spi::addrs::MAADR3)?;
|
|
||||||
mac[5] = self.spi_port.read_reg_8b(spi::addrs::MAADR3 + 1)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write_mac_address(&mut self, mac: &[u8]) -> Result<(), EthControllerError> {
|
|
||||||
self.spi_port.write_reg_8b(spi::addrs::MAADR1, mac[0])?;
|
|
||||||
self.spi_port.write_reg_8b(spi::addrs::MAADR1 + 1, mac[1])?;
|
|
||||||
self.spi_port.write_reg_8b(spi::addrs::MAADR2, mac[2])?;
|
|
||||||
self.spi_port.write_reg_8b(spi::addrs::MAADR2 + 1, mac[3])?;
|
|
||||||
self.spi_port.write_reg_8b(spi::addrs::MAADR3, mac[4])?;
|
|
||||||
self.spi_port.write_reg_8b(spi::addrs::MAADR3 + 1, mac[5])?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,7 @@ pub enum NetworkError {
|
||||||
pub type NetworkInterface<SPI, NSS> = net::iface::EthernetInterface<
|
pub type NetworkInterface<SPI, NSS> = net::iface::EthernetInterface<
|
||||||
'static,
|
'static,
|
||||||
crate::smoltcp_phy::SmoltcpDevice<
|
crate::smoltcp_phy::SmoltcpDevice<
|
||||||
crate::SpiEth<SPI, NSS, fn(u32)>
|
crate::Enc424j600<SPI, NSS, fn(u32)>
|
||||||
>,
|
>,
|
||||||
>;
|
>;
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
EthController, tx, RAW_FRAME_LENGTH_MAX
|
EthPhy, tx, RAW_FRAME_LENGTH_MAX
|
||||||
};
|
};
|
||||||
use core::cell;
|
use core::cell;
|
||||||
use smoltcp::{
|
use smoltcp::{
|
||||||
|
@ -8,25 +8,25 @@ use smoltcp::{
|
||||||
Error
|
Error
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct SmoltcpDevice<EC: EthController> {
|
pub struct SmoltcpDevice<E: EthPhy> {
|
||||||
pub eth_controller: cell::RefCell<EC>,
|
pub eth_phy: cell::RefCell<E>,
|
||||||
rx_packet_buf: [u8; RAW_FRAME_LENGTH_MAX],
|
rx_packet_buf: [u8; RAW_FRAME_LENGTH_MAX],
|
||||||
tx_packet_buf: [u8; RAW_FRAME_LENGTH_MAX]
|
tx_packet_buf: [u8; RAW_FRAME_LENGTH_MAX]
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<EC: EthController> SmoltcpDevice<EC> {
|
impl<E: EthPhy> SmoltcpDevice<E> {
|
||||||
pub fn new(eth_controller: EC) -> Self {
|
pub fn new(eth_phy: E) -> Self {
|
||||||
SmoltcpDevice {
|
SmoltcpDevice {
|
||||||
eth_controller: cell::RefCell::new(eth_controller),
|
eth_phy: cell::RefCell::new(eth_phy),
|
||||||
rx_packet_buf: [0; RAW_FRAME_LENGTH_MAX],
|
rx_packet_buf: [0; RAW_FRAME_LENGTH_MAX],
|
||||||
tx_packet_buf: [0; RAW_FRAME_LENGTH_MAX]
|
tx_packet_buf: [0; RAW_FRAME_LENGTH_MAX]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, EC: 'a + EthController> Device<'a> for SmoltcpDevice<EC> {
|
impl<'a, E: 'a + EthPhy> Device<'a> for SmoltcpDevice<E> {
|
||||||
type RxToken = EthRxToken<'a>;
|
type RxToken = EthRxToken<'a>;
|
||||||
type TxToken = EthTxToken<'a, EC>;
|
type TxToken = EthTxToken<'a, E>;
|
||||||
|
|
||||||
fn capabilities(&self) -> DeviceCapabilities {
|
fn capabilities(&self) -> DeviceCapabilities {
|
||||||
let mut caps = DeviceCapabilities::default();
|
let mut caps = DeviceCapabilities::default();
|
||||||
|
@ -35,8 +35,8 @@ impl<'a, EC: 'a + EthController> Device<'a> for SmoltcpDevice<EC> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn receive(&'a mut self) -> Option<(Self::RxToken, Self::TxToken)> {
|
fn receive(&'a mut self) -> Option<(Self::RxToken, Self::TxToken)> {
|
||||||
let self_p = (&mut *self) as *mut SmoltcpDevice<EC>;
|
let self_p = (&mut *self) as *mut SmoltcpDevice<E>;
|
||||||
match self.eth_controller.borrow_mut().receive_next(false) {
|
match self.eth_phy.borrow_mut().recv_packet(false) {
|
||||||
Ok(rx_packet) => {
|
Ok(rx_packet) => {
|
||||||
// Write received packet to RX packet buffer
|
// Write received packet to RX packet buffer
|
||||||
rx_packet.write_frame_to(&mut self.rx_packet_buf);
|
rx_packet.write_frame_to(&mut self.rx_packet_buf);
|
||||||
|
@ -57,7 +57,7 @@ impl<'a, EC: 'a + EthController> Device<'a> for SmoltcpDevice<EC> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn transmit(&'a mut self) -> Option<Self::TxToken> {
|
fn transmit(&'a mut self) -> Option<Self::TxToken> {
|
||||||
let self_p = (&mut *self) as *mut SmoltcpDevice<EC>;
|
let self_p = (&mut *self) as *mut SmoltcpDevice<E>;
|
||||||
// Construct a blank TxToken
|
// Construct a blank TxToken
|
||||||
let tx_token = EthTxToken {
|
let tx_token = EthTxToken {
|
||||||
buf: &mut self.tx_packet_buf,
|
buf: &mut self.tx_packet_buf,
|
||||||
|
@ -81,12 +81,12 @@ impl<'a> RxToken for EthRxToken<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct EthTxToken<'a, EC: EthController> {
|
pub struct EthTxToken<'a, E: EthPhy> {
|
||||||
buf: &'a mut [u8],
|
buf: &'a mut [u8],
|
||||||
dev: *mut SmoltcpDevice<EC>
|
dev: *mut SmoltcpDevice<E>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, EC: 'a + EthController> TxToken for EthTxToken<'a, EC> {
|
impl<'a, E: 'a + EthPhy> TxToken for EthTxToken<'a, E> {
|
||||||
fn consume<R, F>(self, _timestamp: Instant, len: usize, f: F) -> Result<R, Error>
|
fn consume<R, F>(self, _timestamp: Instant, len: usize, f: F) -> Result<R, Error>
|
||||||
where
|
where
|
||||||
F: FnOnce(&mut [u8]) -> Result<R, Error>,
|
F: FnOnce(&mut [u8]) -> Result<R, Error>,
|
||||||
|
@ -97,10 +97,10 @@ impl<'a, EC: 'a + EthController> TxToken for EthTxToken<'a, EC> {
|
||||||
// Update frame length and write frame bytes
|
// Update frame length and write frame bytes
|
||||||
tx_packet.update_frame(&mut self.buf[..len], len);
|
tx_packet.update_frame(&mut self.buf[..len], len);
|
||||||
// Send the packet as raw
|
// Send the packet as raw
|
||||||
let eth_controller = unsafe {
|
let eth_phy = unsafe {
|
||||||
&mut (*self.dev).eth_controller
|
&mut (*self.dev).eth_phy
|
||||||
};
|
};
|
||||||
match eth_controller.borrow_mut().send_raw_packet(&tx_packet) {
|
match eth_phy.borrow_mut().send_packet(&tx_packet) {
|
||||||
Ok(_) => { result },
|
Ok(_) => { result },
|
||||||
Err(_) => Err(Error::Exhausted)
|
Err(_) => Err(Error::Exhausted)
|
||||||
}
|
}
|
||||||
|
|
28
src/spi.rs
28
src/spi.rs
|
@ -59,7 +59,7 @@ pub struct SpiPort<SPI: Transfer<u8>,
|
||||||
delay_ns: F,
|
delay_ns: F,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum SpiPortError {
|
pub enum Error {
|
||||||
TransferError
|
TransferError
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,13 +78,13 @@ impl <SPI: Transfer<u8>,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read_reg_8b(&mut self, addr: u8) -> Result<u8, SpiPortError> {
|
pub fn read_reg_8b(&mut self, addr: u8) -> Result<u8, Error> {
|
||||||
// Using RCRU instruction to read using unbanked (full) address
|
// Using RCRU instruction to read using unbanked (full) address
|
||||||
let r_data = self.rw_addr_u8(opcodes::RCRU, addr, 0)?;
|
let r_data = self.rw_addr_u8(opcodes::RCRU, addr, 0)?;
|
||||||
Ok(r_data)
|
Ok(r_data)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read_reg_16b(&mut self, lo_addr: u8) -> Result<u16, SpiPortError> {
|
pub fn read_reg_16b(&mut self, lo_addr: u8) -> Result<u16, Error> {
|
||||||
let r_data_lo = self.read_reg_8b(lo_addr)?;
|
let r_data_lo = self.read_reg_8b(lo_addr)?;
|
||||||
let r_data_hi = self.read_reg_8b(lo_addr + 1)?;
|
let r_data_hi = self.read_reg_8b(lo_addr + 1)?;
|
||||||
// Combine top and bottom 8-bit to return 16-bit
|
// Combine top and bottom 8-bit to return 16-bit
|
||||||
|
@ -93,7 +93,7 @@ impl <SPI: Transfer<u8>,
|
||||||
|
|
||||||
// Currently requires manual slicing (buf[1..]) for the data read back
|
// Currently requires manual slicing (buf[1..]) for the data read back
|
||||||
pub fn read_rxdat<'a>(&mut self, buf: &'a mut [u8], data_length: usize)
|
pub fn read_rxdat<'a>(&mut self, buf: &'a mut [u8], data_length: usize)
|
||||||
-> Result<(), SpiPortError> {
|
-> Result<(), Error> {
|
||||||
let r_valid = self.r_n(buf, opcodes::RERXDATA, data_length)?;
|
let r_valid = self.r_n(buf, opcodes::RERXDATA, data_length)?;
|
||||||
Ok(r_valid)
|
Ok(r_valid)
|
||||||
}
|
}
|
||||||
|
@ -101,19 +101,19 @@ impl <SPI: Transfer<u8>,
|
||||||
// Currenly requires actual data to be stored in buf[1..] instead of buf[0..]
|
// Currenly requires actual data to be stored in buf[1..] instead of buf[0..]
|
||||||
// TODO: Maybe better naming?
|
// TODO: Maybe better naming?
|
||||||
pub fn write_txdat<'a>(&mut self, buf: &'a mut [u8], data_length: usize)
|
pub fn write_txdat<'a>(&mut self, buf: &'a mut [u8], data_length: usize)
|
||||||
-> Result<(), SpiPortError> {
|
-> Result<(), Error> {
|
||||||
let w_valid = self.w_n(buf, opcodes::WEGPDATA, data_length)?;
|
let w_valid = self.w_n(buf, opcodes::WEGPDATA, data_length)?;
|
||||||
Ok(w_valid)
|
Ok(w_valid)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn write_reg_8b(&mut self, addr: u8, data: u8) -> Result<(), SpiPortError> {
|
pub fn write_reg_8b(&mut self, addr: u8, data: u8) -> Result<(), Error> {
|
||||||
// TODO: addr should be separated from w_data
|
// TODO: addr should be separated from w_data
|
||||||
// Using WCRU instruction to write using unbanked (full) address
|
// Using WCRU instruction to write using unbanked (full) address
|
||||||
self.rw_addr_u8(opcodes::WCRU, addr, data)?;
|
self.rw_addr_u8(opcodes::WCRU, addr, data)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn write_reg_16b(&mut self, lo_addr: u8, data: u16) -> Result<(), SpiPortError> {
|
pub fn write_reg_16b(&mut self, lo_addr: u8, data: u16) -> Result<(), Error> {
|
||||||
self.write_reg_8b(lo_addr, (data & 0xff) as u8)?;
|
self.write_reg_8b(lo_addr, (data & 0xff) as u8)?;
|
||||||
self.write_reg_8b(lo_addr + 1, ((data & 0xff00) >> 8) as u8)?;
|
self.write_reg_8b(lo_addr + 1, ((data & 0xff00) >> 8) as u8)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -127,7 +127,7 @@ impl <SPI: Transfer<u8>,
|
||||||
// TODO: (Make data read/write as reference to array)
|
// TODO: (Make data read/write as reference to array)
|
||||||
// Currently requires 1-byte addr, read/write data is only 1-byte
|
// Currently requires 1-byte addr, read/write data is only 1-byte
|
||||||
fn rw_addr_u8(&mut self, opcode: u8, addr: u8, data: u8)
|
fn rw_addr_u8(&mut self, opcode: u8, addr: u8, data: u8)
|
||||||
-> Result<u8, SpiPortError> {
|
-> Result<u8, Error> {
|
||||||
// Enable chip select
|
// Enable chip select
|
||||||
self.nss.set_low();
|
self.nss.set_low();
|
||||||
// Start writing to SLAVE
|
// Start writing to SLAVE
|
||||||
|
@ -150,7 +150,7 @@ impl <SPI: Transfer<u8>,
|
||||||
(self.delay_ns)(60);
|
(self.delay_ns)(60);
|
||||||
self.nss.set_high();
|
self.nss.set_high();
|
||||||
(self.delay_ns)(30);
|
(self.delay_ns)(30);
|
||||||
Err(SpiPortError::TransferError)
|
Err(Error::TransferError)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -161,7 +161,7 @@ impl <SPI: Transfer<u8>,
|
||||||
// Note: buf must be at least (data_length + 1)-byte long
|
// Note: buf must be at least (data_length + 1)-byte long
|
||||||
// TODO: Check and raise error for array size < (data_length + 1)
|
// TODO: Check and raise error for array size < (data_length + 1)
|
||||||
fn r_n<'a>(&mut self, buf: &'a mut [u8], opcode: u8, data_length: usize)
|
fn r_n<'a>(&mut self, buf: &'a mut [u8], opcode: u8, data_length: usize)
|
||||||
-> Result<(), SpiPortError> {
|
-> Result<(), Error> {
|
||||||
// Enable chip select
|
// Enable chip select
|
||||||
self.nss.set_low();
|
self.nss.set_low();
|
||||||
// Start writing to SLAVE
|
// Start writing to SLAVE
|
||||||
|
@ -176,7 +176,7 @@ impl <SPI: Transfer<u8>,
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
// Disable chip select
|
// Disable chip select
|
||||||
self.nss.set_high();
|
self.nss.set_high();
|
||||||
Err(SpiPortError::TransferError)
|
Err(Error::TransferError)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -184,7 +184,7 @@ impl <SPI: Transfer<u8>,
|
||||||
// Note: buf[0] is currently reserved for opcode to overwrite
|
// Note: buf[0] is currently reserved for opcode to overwrite
|
||||||
// TODO: Actual data should start from buf[0], not buf[1]
|
// TODO: Actual data should start from buf[0], not buf[1]
|
||||||
fn w_n<'a>(&mut self, buf: &'a mut [u8], opcode: u8, data_length: usize)
|
fn w_n<'a>(&mut self, buf: &'a mut [u8], opcode: u8, data_length: usize)
|
||||||
-> Result<(), SpiPortError> {
|
-> Result<(), Error> {
|
||||||
// Enable chip select
|
// Enable chip select
|
||||||
self.nss.set_low();
|
self.nss.set_low();
|
||||||
// Start writing to SLAVE
|
// Start writing to SLAVE
|
||||||
|
@ -200,8 +200,8 @@ impl <SPI: Transfer<u8>,
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
// Disable chip select
|
// Disable chip select
|
||||||
self.nss.set_high();
|
self.nss.set_high();
|
||||||
Err(SpiPortError::TransferError)
|
Err(Error::TransferError)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue