#![deny(missing_docs)]
#![deny(warnings)]
#![no_std]
extern crate byteorder;
extern crate cast;
extern crate embedded_hal as hal;
use core::mem;
use core::ptr;
use core::u16;
use byteorder::{ByteOrder, LE};
use cast::{u16, usize};
use hal::blocking;
use hal::blocking::delay::DelayMs;
use hal::digital::{InputPin, OutputPin};
use hal::spi::{Mode, Phase, Polarity};
use traits::U16Ext;
#[macro_use]
mod macros;
mod bank0;
mod bank1;
mod bank2;
mod bank3;
mod common;
mod phy;
mod traits;
pub const MODE: Mode = Mode {
phase: Phase::CaptureOnFirstTransition,
polarity: Polarity::IdleLow,
};
#[derive(Debug)]
pub enum Error<E> {
LateCollision,
Spi(E),
}
pub enum Event {
Pkt,
}
impl<E> From<E> for Error<E> {
fn from(e: E) -> Self {
Error::Spi(e)
}
}
pub struct Enc28j60<SPI, NCS, INT, RESET> {
int: INT,
ncs: NCS,
reset: RESET,
spi: SPI,
bank: Bank,
next_packet: u16,
rxnd: u16,
txnd: u16,
}
const NONE: u16 = u16::MAX;
const RXST: u16 = 0;
impl<E, SPI, NCS, INT, RESET> Enc28j60<SPI, NCS, INT, RESET>
where
SPI: blocking::spi::Transfer<u8, Error = E> + blocking::spi::Write<u8, Error = E>,
NCS: OutputPin,
INT: IntPin,
RESET: ResetPin,
{
const MAX_FRAME_LENGTH: u16 = 1518;
const CRC_SZ: u16 = 4;
pub fn new<D>(
spi: SPI,
ncs: NCS,
int: INT,
reset: RESET,
delay: &mut D,
mut rx_buf_sz: u16,
src: [u8; 6],
) -> Result<Self, E>
where
D: DelayMs<u8>,
RESET: ResetPin,
INT: IntPin,
{
const BUF_SZ: u16 = 8 * 1024;
if rx_buf_sz % 2 == 1 {
rx_buf_sz += 1;
}
assert!(rx_buf_sz <= BUF_SZ);
let mut enc28j60 = Enc28j60 {
bank: Bank::Bank0,
int,
ncs,
next_packet: NONE,
reset,
rxnd: NONE,
spi,
txnd: NONE,
};
if typeid!(RESET == Unconnected) {
enc28j60.soft_reset()?;
} else {
enc28j60.reset.reset();
}
delay.delay_ms(1);
enc28j60.write_control_register(bank3::Register::ECOCON, 0)?;
let rxnd = rx_buf_sz - 1;
enc28j60.rxnd = rxnd;
enc28j60.write_control_register(bank0::Register::ERXSTL, RXST.low())?;
enc28j60.write_control_register(bank0::Register::ERXSTH, RXST.high())?;
enc28j60.write_control_register(bank0::Register::ERXRDPTL, rxnd.low())?;
enc28j60.write_control_register(bank0::Register::ERXRDPTH, rxnd.high())?;
enc28j60.write_control_register(bank0::Register::ERXNDL, rxnd.low())?;
enc28j60.write_control_register(bank0::Register::ERXNDH, rxnd.high())?;
let txst = enc28j60.txst();
debug_assert_eq!(txst % 2, 0);
enc28j60.write_control_register(bank0::Register::ETXSTL, txst.low())?;
enc28j60.write_control_register(bank0::Register::ETXSTH, txst.high())?;
enc28j60.write_control_register(
bank2::Register::MACON1,
bank2::MACON1::default()
.marxen(1)
.passall(0)
.rxpaus(1)
.txpaus(1)
.bits(),
)?;
enc28j60.write_control_register(
bank2::Register::MACON3,
bank2::MACON3::default()
.frmlnen(1)
.txcrcen(1)
.padcfg(0b001)
.bits(),
)?;
enc28j60.write_control_register(bank2::Register::MAMXFLL, Self::MAX_FRAME_LENGTH.low())?;
enc28j60.write_control_register(bank2::Register::MAMXFLH, Self::MAX_FRAME_LENGTH.high())?;
enc28j60.write_control_register(bank2::Register::MABBIPG, 0x12)?;
enc28j60.write_control_register(bank2::Register::MAIPGL, 0x12)?;
enc28j60.write_control_register(bank3::Register::MAADR1, src[0])?;
enc28j60.write_control_register(bank3::Register::MAADR2, src[1])?;
enc28j60.write_control_register(bank3::Register::MAADR3, src[2])?;
enc28j60.write_control_register(bank3::Register::MAADR4, src[3])?;
enc28j60.write_control_register(bank3::Register::MAADR5, src[4])?;
enc28j60.write_control_register(bank3::Register::MAADR6, src[5])?;
enc28j60.write_phy_register(
phy::Register::PHCON2,
phy::PHCON2::default().hdldis(1).bits(),
)?;
if typeid!(INT != Unconnected) {
enc28j60.bit_field_set(common::Register::EIE, common::EIE::mask().intie())?;
}
enc28j60.write_buffer_memory(Some(txst), &[0])?;
enc28j60.bit_field_set(common::Register::ECON1, common::ECON1::mask().rxen())?;
Ok(enc28j60)
}
pub fn flush(&mut self) -> Result<(), Error<E>> {
if self.txnd != NONE {
while common::ECON1(self.read_control_register(common::Register::ECON1)?).txrts() == 1 {
}
let txnd = self.txnd;
unsafe { ptr::write_volatile(&mut self.txnd, NONE) }
let mut tx_stat = [0; 7];
self.read_buffer_memory(Some(txnd + 1), &mut tx_stat)?;
let stat = common::ESTAT(self.read_control_register(common::Register::ESTAT)?);
if stat.txabrt() == 1 {
if stat.latecol() == 1 || (tx_stat[2] & (1 << 5)) != 0 {
Err(Error::LateCollision)
} else {
unimplemented!()
}
} else {
Ok(())
}
} else {
Ok(())
}
}
pub fn receive(&mut self, buffer: &mut [u8]) -> Result<u16, E> {
loop {
let eir = common::EIR(self.read_control_register(common::Register::EIR)?);
debug_assert!(eir.rxerif() == 0);
if eir.pktif() == 1 {
break;
}
}
let curr_packet = if self.next_packet == NONE {
RXST
} else {
self.next_packet
};
let mut temp_buf: [u8; 6] = unsafe { mem::uninitialized() };
self.read_buffer_memory(Some(curr_packet), &mut temp_buf)?;
let next_packet = u16::from_parts(temp_buf[0], temp_buf[1]);
self.next_packet = next_packet;
let status = RxStatus(LE::read_u32(&temp_buf[2..]));
let n = status.byte_count() as u16;
let end = n - Self::CRC_SZ;
self.read_buffer_memory(None, &mut buffer[..usize(end)])?;
let rxrdpt = next_packet.checked_sub(1).unwrap_or(self.rxnd);
self.write_control_register(bank0::Register::ERXRDPTL, rxrdpt.low())?;
self.write_control_register(bank0::Register::ERXRDPTH, rxrdpt.high())?;
self.write_control_register(
common::Register::ECON2,
common::ECON2::default().pktdec(1).bits(),
)?;
Ok(end)
}
pub fn transmit(&mut self, bytes: &[u8]) -> Result<(), Error<E>> {
assert!(bytes.len() <= usize(Self::MAX_FRAME_LENGTH - Self::CRC_SZ));
self.flush()?;
let txst = self.txst();
self.bit_field_set(common::Register::ECON1, common::ECON1::mask().txrst())?;
self.bit_field_clear(common::Register::ECON1, common::ECON1::mask().txrst())?;
self.bit_field_clear(common::Register::EIR, {
let mask = common::EIR::mask();
mask.txerif() | mask.txif()
})?;
let wrpt = txst + 1;
self.write_buffer_memory(Some(wrpt), bytes)?;
let txnd = wrpt + u16(bytes.len()).unwrap() - 1;
self.write_control_register(bank0::Register::ETXNDL, txnd.low())?;
self.write_control_register(bank0::Register::ETXNDH, txnd.high())?;
self.bit_field_clear(common::Register::EIR, { common::EIR::mask().txif() })?;
self.bit_field_set(common::Register::ECON1, common::ECON1::mask().txrts())?;
unsafe { ptr::write_volatile(&mut self.txnd, txnd) }
Ok(())
}
pub fn free(self) -> (SPI, NCS, INT, RESET) {
(self.spi, self.ncs, self.int, self.reset)
}
pub fn pending_packets(&mut self) -> Result<u8, E> {
self.read_control_register(bank1::Register::EPKTCNT)
}
fn bit_field_clear<R>(&mut self, register: R, mask: u8) -> Result<(), E>
where
R: Into<Register>,
{
self._bit_field_clear(register.into(), mask)
}
fn _bit_field_clear(&mut self, register: Register, mask: u8) -> Result<(), E> {
assert!(register.is_eth_register());
self.change_bank(register)?;
self.ncs.set_low();
self.spi
.write(&[Instruction::BFC.opcode() | register.addr(), mask])?;
self.ncs.set_high();
Ok(())
}
fn bit_field_set<R>(&mut self, register: R, mask: u8) -> Result<(), E>
where
R: Into<Register>,
{
self._bit_field_set(register.into(), mask)
}
fn _bit_field_set(&mut self, register: Register, mask: u8) -> Result<(), E> {
assert!(register.is_eth_register());
self.change_bank(register)?;
self.ncs.set_low();
self.spi
.write(&[Instruction::BFS.opcode() | register.addr(), mask])?;
self.ncs.set_high();
Ok(())
}
fn modify_control_register<R, F>(&mut self, register: R, f: F) -> Result<(), E>
where
F: FnOnce(u8) -> u8,
R: Into<Register>,
{
self._modify_control_register(register.into(), f)
}
fn _modify_control_register<F>(&mut self, register: Register, f: F) -> Result<(), E>
where
F: FnOnce(u8) -> u8,
{
let r = self._read_control_register(register)?;
self._write_control_register(register, f(r))
}
fn read_control_register<R>(&mut self, register: R) -> Result<u8, E>
where
R: Into<Register>,
{
self._read_control_register(register.into())
}
fn _read_control_register(&mut self, register: Register) -> Result<u8, E> {
self.change_bank(register)?;
self.ncs.set_low();
let mut buffer = [Instruction::RCR.opcode() | register.addr(), 0];
self.spi.transfer(&mut buffer)?;
self.ncs.set_high();
Ok(buffer[1])
}
#[allow(dead_code)]
fn read_phy_register(&mut self, register: phy::Register) -> Result<u16, E> {
self.write_control_register(bank2::Register::MIREGADR, register.addr())?;
self.bit_field_set(bank2::Register::MICMD, bank2::MICMD::mask().miird())?;
while self.read_control_register(bank3::Register::MISTAT)? & 0b1 != 0 {}
self.bit_field_clear(bank2::Register::MICMD, bank2::MICMD::mask().miird())?;
Ok(
((self.read_control_register(bank2::Register::MIRDH)? as u16) << 8)
| (self.read_control_register(bank2::Register::MIRDL)? as u16),
)
}
fn read_buffer_memory(&mut self, addr: Option<u16>, buf: &mut [u8]) -> Result<(), E> {
if let Some(addr) = addr {
self.write_control_register(bank0::Register::ERDPTL, addr.low())?;
self.write_control_register(bank0::Register::ERDPTH, addr.high())?;
}
self.ncs.set_low();
self.spi.write(&[Instruction::RBM.opcode()])?;
self.spi.transfer(buf)?;
self.ncs.set_high();
Ok(())
}
fn write_buffer_memory(&mut self, addr: Option<u16>, buffer: &[u8]) -> Result<(), E> {
if let Some(addr) = addr {
self.write_control_register(bank0::Register::EWRPTL, addr.low())?;
self.write_control_register(bank0::Register::EWRPTH, addr.high())?;
}
self.ncs.set_low();
self.spi.write(&[Instruction::WBM.opcode()])?;
self.spi.write(buffer)?;
self.ncs.set_high();
Ok(())
}
fn write_control_register<R>(&mut self, register: R, value: u8) -> Result<(), E>
where
R: Into<Register>,
{
self._write_control_register(register.into(), value)
}
fn _write_control_register(&mut self, register: Register, value: u8) -> Result<(), E> {
self.change_bank(register)?;
self.ncs.set_low();
let buffer = [Instruction::WCR.opcode() | register.addr(), value];
self.spi.write(&buffer)?;
self.ncs.set_high();
Ok(())
}
fn write_phy_register(&mut self, register: phy::Register, value: u16) -> Result<(), E> {
self.write_control_register(bank2::Register::MIREGADR, register.addr())?;
self.write_control_register(bank2::Register::MIWRL, (value & 0xff) as u8)?;
self.write_control_register(bank2::Register::MIWRH, (value >> 8) as u8)?;
while self.read_control_register(bank3::Register::MISTAT)? & 0b1 != 0 {}
Ok(())
}
fn change_bank(&mut self, register: Register) -> Result<(), E> {
let bank = register.bank();
if let Some(bank) = bank {
if self.bank == bank {
return Ok(());
}
self.bank = bank;
match bank {
Bank::Bank0 => self.bit_field_clear(common::Register::ECON1, 0b11),
Bank::Bank1 => {
self.modify_control_register(common::Register::ECON1, |r| (r & !0b11) | 0b01)
}
Bank::Bank2 => {
self.modify_control_register(common::Register::ECON1, |r| (r & !0b11) | 0b10)
}
Bank::Bank3 => self.bit_field_set(common::Register::ECON1, 0b11),
}
} else {
Ok(())
}
}
fn soft_reset(&mut self) -> Result<(), E> {
self.ncs.set_low();
self.spi.transfer(&mut [Instruction::SRC.opcode()])?;
self.ncs.set_high();
Ok(())
}
fn txst(&self) -> u16 {
self.rxnd + 1
}
}
impl<E, SPI, NCS, INT, RESET> Enc28j60<SPI, NCS, INT, RESET>
where
SPI: blocking::spi::Transfer<u8, Error = E> + blocking::spi::Write<u8, Error = E>,
NCS: OutputPin,
INT: IntPin + InputPin,
RESET: ResetPin,
{
pub fn listen(&mut self, event: Event) -> Result<(), E> {
match event {
Event::Pkt => self.bit_field_set(common::Register::EIE, common::EIE::mask().pktie()),
}
}
pub fn interrupt_pending(&mut self) -> bool {
self.int.is_low()
}
pub fn unlisten(&mut self, event: Event) -> Result<(), E> {
match event {
Event::Pkt => self.bit_field_clear(common::Register::EIE, common::EIE::mask().pktie()),
}
}
}
pub struct Unconnected;
pub unsafe trait ResetPin: 'static {
#[doc(hidden)]
fn reset(&mut self);
}
unsafe impl ResetPin for Unconnected {
fn reset(&mut self) {}
}
unsafe impl<OP> ResetPin for OP
where
OP: OutputPin + 'static,
{
fn reset(&mut self) {
self.set_low();
self.set_high();
}
}
pub unsafe trait IntPin: 'static {}
unsafe impl IntPin for Unconnected {}
unsafe impl<IP> IntPin for IP where IP: InputPin + 'static {}
#[derive(Clone, Copy, PartialEq)]
enum Bank {
Bank0,
Bank1,
Bank2,
Bank3,
}
#[derive(Clone, Copy)]
enum Instruction {
RCR = 0b000_00000,
RBM = 0b001_11010,
WCR = 0b010_00000,
WBM = 0b011_11010,
BFS = 0b100_00000,
BFC = 0b101_00000,
SRC = 0b111_11111,
}
impl Instruction {
fn opcode(&self) -> u8 {
*self as u8
}
}
#[derive(Clone, Copy)]
enum Register {
Bank0(bank0::Register),
Bank1(bank1::Register),
Bank2(bank2::Register),
Bank3(bank3::Register),
Common(common::Register),
}
impl Register {
fn addr(&self) -> u8 {
match *self {
Register::Bank0(r) => r.addr(),
Register::Bank1(r) => r.addr(),
Register::Bank2(r) => r.addr(),
Register::Bank3(r) => r.addr(),
Register::Common(r) => r.addr(),
}
}
fn bank(&self) -> Option<Bank> {
Some(match *self {
Register::Bank0(_) => Bank::Bank0,
Register::Bank1(_) => Bank::Bank1,
Register::Bank2(_) => Bank::Bank2,
Register::Bank3(_) => Bank::Bank3,
Register::Common(_) => return None,
})
}
fn is_eth_register(&self) -> bool {
match *self {
Register::Bank0(r) => r.is_eth_register(),
Register::Bank1(r) => r.is_eth_register(),
Register::Bank2(r) => r.is_eth_register(),
Register::Bank3(r) => r.is_eth_register(),
Register::Common(r) => r.is_eth_register(),
}
}
}
register!(RxStatus, 0, u32, {
#[doc = "Indicates length of the received frame"]
byte_count @ 0..15,
#[doc = "Indicates a packet over 50,000 bit times occurred or that a packet was dropped since the last receive"]
long_event @ 16,
#[doc = "Indicates that at some time since the last receive, a carrier event was detected"]
carrier_event @ 18,
#[doc = "Indicates that frame CRC field value does not match the CRC calculated by the MAC"]
crc_error @ 20,
#[doc = "Indicates that frame length field value in the packet does not match the actual data byte length and specifies a valid length"]
length_check_error @ 21,
#[doc = "Indicates that frame type/length field was larger than 1500 bytes (type field)"]
length_out_of_range @ 22,
#[doc = "Indicates that at the packet had a valid CRC and no symbol errors"]
received_ok @ 23,
#[doc = "Indicates packet received had a valid Multicast address"]
multicast @ 24,
#[doc = "Indicates packet received had a valid Broadcast address."]
broadcast @ 25,
#[doc = "Indicates that after the end of this packet, an additional 1 to 7 bits were received"]
dribble_nibble @ 26,
#[doc = "Current frame was recognized as a control frame for having a valid type/length designating it as a control frame"]
receive_control_frame @ 27,
#[doc = "Current frame was recognized as a control frame containing a valid pause frame opcode and a valid destination address"]
receive_pause_control_frame @ 28,
#[doc = "Current frame was recognized as a control frame but it contained an unknown opcode"]
receive_unknown_opcode @ 29,
#[doc = "Current frame was recognized as a VLAN tagged frame"]
receive_vlan_type_detected @ 30,
});