From bf7e191ef3ab2b7ce8326647ac6570d3522310ee Mon Sep 17 00:00:00 2001 From: Adam Dunkels Date: Tue, 3 Jun 2014 22:40:55 +0200 Subject: [PATCH] ENC28j60 Ethernet driver code --- dev/enc28j60/enc28j60.c | 644 ++++++++++++++++++++++++++++++++++++++++ dev/enc28j60/enc28j60.h | 51 ++++ 2 files changed, 695 insertions(+) create mode 100644 dev/enc28j60/enc28j60.c create mode 100644 dev/enc28j60/enc28j60.h diff --git a/dev/enc28j60/enc28j60.c b/dev/enc28j60/enc28j60.c new file mode 100644 index 000000000..dd00dddeb --- /dev/null +++ b/dev/enc28j60/enc28j60.c @@ -0,0 +1,644 @@ +/* + * Copyright (c) 2012-2013, Thingsquare, http://www.thingsquare.com/. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "contiki.h" +#include "enc28j60.h" +#include +#include + +#define DEBUG 0 +#if DEBUG +#define PRINTF(...) printf(__VA_ARGS__) +#else +#define PRINTF(...) +#endif + +#define EIE 0x1b +#define EIR 0x1c +#define ESTAT 0x1d +#define ECON2 0x1e +#define ECON1 0x1f + +#define ESTAT_CLKRDY 0x01 +#define ESTAT_TXABRT 0x02 + +#define ECON1_RXEN 0x04 +#define ECON1_TXRTS 0x08 + +#define ECON2_AUTOINC 0x80 +#define ECON2_PKTDEC 0x40 + +#define EIR_TXIF 0x08 + +#define ERXTX_BANK 0x00 + +#define ERDPTL 0x00 +#define ERDPTH 0x01 +#define EWRPTL 0x02 +#define EWRPTH 0x03 +#define ETXSTL 0x04 +#define ETXSTH 0x05 +#define ETXNDL 0x06 +#define ETXNDH 0x07 +#define ERXSTL 0x08 +#define ERXSTH 0x09 +#define ERXNDL 0x0a +#define ERXNDH 0x0b +#define ERXRDPTL 0x0c +#define ERXRDPTH 0x0d + +#define RX_BUF_START 0x0000 +#define RX_BUF_END 0x0fff + +#define TX_BUF_START 0x1200 + +/* MACONx registers are in bank 2 */ +#define MACONX_BANK 0x02 + +#define MACON1 0x00 +#define MACON2 0x01 +#define MACON3 0x02 +#define MACON4 0x03 +#define MABBIPG 0x04 +#define MAIPGL 0x06 +#define MAIPGH 0x07 +#define MAMXFLL 0x0a +#define MAMXFLH 0x0b + +#define MACON1_TXPAUS 0x08 +#define MACON1_RXPAUS 0x04 +#define MACON1_MARXEN 0x01 + +#define MACON2_MARST 0x80 + +#define MACON3_PADCFG_FULL 0xe0 +#define MACON3_TXCRCEN 0x10 +#define MACON3_FRMLNEN 0x02 +#define MACON3_FULDPX 0x01 + +#define MAX_MAC_LENGTH 1518 + +#define MAADRX_BANK 0x03 +#define MAADR1 0x04 /* MAADR<47:40> */ +#define MAADR2 0x05 /* MAADR<39:32> */ +#define MAADR3 0x02 /* MAADR<31:24> */ +#define MAADR4 0x03 /* MAADR<23:16> */ +#define MAADR5 0x00 /* MAADR<15:8> */ +#define MAADR6 0x01 /* MAADR<7:0> */ + +#define EPKTCNT_BANK 0x01 +#define ERXFCON 0x18 +#define EPKTCNT 0x19 + +#define ERXFCON_UCEN 0x80 +#define ERXFCON_ANDOR 0x40 +#define ERXFCON_CRCEN 0x20 +#define ERXFCON_MCEN 0x02 +#define ERXFCON_BCEN 0x01 + + +PROCESS(enc_watchdog_process, "Enc28j60 watchdog"); + +static uint8_t initialized = 0; +static uint8_t enc_mac_addr[6]; +static int received_packets = 0; +static int sent_packets = 0; + +/*---------------------------------------------------------------------------*/ +static uint8_t +readreg(uint8_t reg) +{ + uint8_t r; + enc28j60_arch_spi_select(); + enc28j60_arch_spi_write(0x00 | (reg & 0x1f)); + r = enc28j60_arch_spi_read(); + enc28j60_arch_spi_deselect(); + return r; +} +/*---------------------------------------------------------------------------*/ +static void +writereg(uint8_t reg, uint8_t data) +{ + enc28j60_arch_spi_select(); + enc28j60_arch_spi_write(0x40 | (reg & 0x1f)); + enc28j60_arch_spi_write(data); + enc28j60_arch_spi_deselect(); +} +/*---------------------------------------------------------------------------*/ +static void +setregbank(uint8_t bank) +{ + writereg(ECON1, (readreg(ECON1) & 0xfc) | (bank & 0x03)); +} +/*---------------------------------------------------------------------------*/ +static void +writedatabyte(uint8_t byte) +{ + enc28j60_arch_spi_select(); + /* The Write Buffer Memory (WBM) command is 0 1 1 1 1 0 1 0 */ + enc28j60_arch_spi_write(0x7a); + enc28j60_arch_spi_write(byte); + enc28j60_arch_spi_deselect(); +} +/*---------------------------------------------------------------------------*/ +static void +writedata(uint8_t *data, int datalen) +{ + int i; + enc28j60_arch_spi_select(); + /* The Write Buffer Memory (WBM) command is 0 1 1 1 1 0 1 0 */ + enc28j60_arch_spi_write(0x7a); + for(i = 0; i < datalen; i++) { + enc28j60_arch_spi_write(data[i]); + } + enc28j60_arch_spi_deselect(); +} +/*---------------------------------------------------------------------------*/ +static uint8_t +readdatabyte(void) +{ + uint8_t r; + enc28j60_arch_spi_select(); + /* THe Read Buffer Memory (RBM) command is 0 0 1 1 1 0 1 0 */ + enc28j60_arch_spi_write(0x3a); + r = enc28j60_arch_spi_read(); + enc28j60_arch_spi_deselect(); + return r; +} +/*---------------------------------------------------------------------------*/ +static int +readdata(uint8_t *buf, int len) +{ + int i; + enc28j60_arch_spi_select(); + /* THe Read Buffer Memory (RBM) command is 0 0 1 1 1 0 1 0 */ + enc28j60_arch_spi_write(0x3a); + for(i = 0; i < len; i++) { + buf[i] = enc28j60_arch_spi_read(); + } + enc28j60_arch_spi_deselect(); + return i; +} +/*---------------------------------------------------------------------------*/ +static void +softreset(void) +{ + enc28j60_arch_spi_select(); + /* The System Command (soft reset) is 1 1 1 1 1 1 1 1 */ + enc28j60_arch_spi_write(0xff); + enc28j60_arch_spi_deselect(); +} +/*---------------------------------------------------------------------------*/ +static void +reset(void) +{ + PRINTF("enc28j60: resetting chip\n"); + + enc28j60_arch_spi_init(); + + /* + 6.0 INITIALIZATION + + Before the ENC28J60 can be used to transmit and receive packets, + certain device settings must be initialized. Depending on the + application, some configuration options may need to be + changed. Normally, these tasks may be accomplished once after + Reset and do not need to be changed thereafter. + + 6.1 Receive Buffer + + Before receiving any packets, the receive buffer must be + initialized by programming the ERXST and ERXND pointers. All + memory between and including the ERXST and ERXND addresses will be + dedicated to the receive hardware. It is recommended that the + ERXST pointer be programmed with an even address. + + Applications expecting large amounts of data and frequent packet + delivery may wish to allocate most of the memory as the receive + buffer. Applications that may need to save older packets or have + several packets ready for transmission should allocate less + memory. + + When programming the ERXST pointer, the ERXWRPT registers will + automatically be updated with the same values. The address in + ERXWRPT will be used as the starting location when the receive + hardware begins writing received data. For tracking purposes, the + ERXRDPT registers should additionally be programmed with the same + value. To program ERXRDPT, the host controller must write to + ERXRDPTL first, followed by ERXRDPTH. See Section 7.2.4 “Freeing + Receive Buffer Space for more information + + 6.2 Transmission Buffer + + All memory which is not used by the receive buffer is considered + the transmission buffer. Data which is to be transmitted should be + written into any unused space. After a packet is transmitted, + however, the hardware will write a seven-byte status vector into + memory after the last byte in the packet. Therefore, the host + controller should leave at least seven bytes between each packet + and the beginning of the receive buffer. No explicit action is + required to initialize the transmission buffer. + + 6.3 Receive Filters + + The appropriate receive filters should be enabled or disabled by + writing to the ERXFCON register. See Section 8.0 “Receive Filters + for information on how to configure it. + + 6.4 Waiting For OST + + If the initialization procedure is being executed immediately + following a Power-on Reset, the ESTAT.CLKRDY bit should be polled + to make certain that enough time has elapsed before proceeding to + modify the MAC and PHY registers. For more information on the OST, + see Section 2.2 “Oscillator Start-up Timer. + */ + + /* Wait for OST */ + while((readreg(ESTAT) & ESTAT_CLKRDY) == 0); + + softreset(); + + setregbank(ERXTX_BANK); + /* Set up receive buffer */ + writereg(ERXSTL, RX_BUF_START & 0xff); + writereg(ERXSTH, RX_BUF_START >> 8); + writereg(ERXNDL, RX_BUF_END & 0xff); + writereg(ERXNDH, RX_BUF_END >> 8); + writereg(ERDPTL, RX_BUF_START & 0xff); + writereg(ERDPTH, RX_BUF_START >> 8); + writereg(ERXRDPTL, RX_BUF_START & 0xff); + writereg(ERXRDPTH, RX_BUF_START >> 8); + + /* Receive filters */ + setregbank(EPKTCNT_BANK); + /* writereg(ERXFCON, ERXFCON_UCEN | ERXFCON_CRCEN | + ERXFCON_MCEN | ERXFCON_BCEN);*/ + /* XXX: can't seem to get the unicast filter to work right now, + using promiscous mode for now. */ + writereg(ERXFCON, 0); + + /* + 6.5 MAC Initialization Settings + + Several of the MAC registers require configuration during + initialization. This only needs to be done once; the order of + programming is unimportant. + + 1. Clear the MARST bit in MACON2 to pull the MAC out of Reset. + + 2. Set the MARXEN bit in MACON1 to enable the MAC to receive + frames. If using full duplex, most applications should also set + TXPAUS and RXPAUS to allow IEEE defined flow control to function. + + 3. Configure the PADCFG, TXCRCEN and FULDPX bits of MACON3. Most + applications should enable automatic padding to at least 60 bytes + and always append a valid CRC. For convenience, many applications + may wish to set the FRMLNEN bit as well to enable frame length + status reporting. The FULDPX bit should be set if the application + will be connected to a full-duplex configured remote node; + otherwise, it should be left clear. + + 4. Configure the bits in MACON4. Many applications may not need to + modify the Reset default. + + 5. Program the MAMXFL registers with the maximum frame length to + be permitted to be received or transmitted. Normal network nodes + are designed to handle packets that are 1518 bytes or less. + + 6. Configure the Back-to-Back Inter-Packet Gap register, + MABBIPG. Most applications will program this register with 15h + when Full-Duplex mode is used and 12h when Half-Duplex mode is + used. + + 7. Configure the Non-Back-to-Back Inter-Packet Gap register low + byte, MAIPGL. Most applications will program this register with + 12h. + + 8. If half duplex is used, the Non-Back-to-Back Inter-Packet Gap + register high byte, MAIPGH, should be programmed. Most + applications will program this register to 0Ch. + + 9. If Half-Duplex mode is used, program the Retransmission and + Collision Window registers, MACLCON1 and MACLCON2. Most + applications will not need to change the default Reset values. If + the network is spread over exceptionally long cables, the default + value of MACLCON2 may need to be increased. + + 10. Program the local MAC address into the + MAADR0:MAADR5 registers. + */ + + setregbank(MACONX_BANK); + + /* Pull MAC out of reset */ + writereg(MACON2, 0);//readreg(MACON2) & (~MACON2_MARST)); + + /* Turn on reception and IEEE-defined flow control */ + writereg(MACON1, readreg(MACON1) | (MACON1_MARXEN + MACON1_TXPAUS + + MACON1_RXPAUS)); + + /* Set padding, crc, full duplex */ + writereg(MACON3, readreg(MACON3) | (MACON3_PADCFG_FULL + MACON3_TXCRCEN + + MACON3_FULDPX + MACON3_FRMLNEN)); + + /* Don't modify MACON4 */ + + /* Set maximum frame length in MAMXFL */ + writereg(MAMXFLL, MAX_MAC_LENGTH & 0xff); + writereg(MAMXFLH, MAX_MAC_LENGTH >> 8); + + /* Set back-to-back inter packet gap */ + writereg(MABBIPG, 0x15); + + /* Set non-back-to-back packet gap */ + writereg(MAIPGL, 0x12); + writereg(MAIPGH, 0x0c); + + /* Set MAC address */ + setregbank(MAADRX_BANK); + writereg(MAADR6, enc_mac_addr[5]); + writereg(MAADR5, enc_mac_addr[4]); + writereg(MAADR4, enc_mac_addr[3]); + writereg(MAADR3, enc_mac_addr[2]); + writereg(MAADR2, enc_mac_addr[1]); + writereg(MAADR1, enc_mac_addr[0]); + + /* Receive filters */ + setregbank(EPKTCNT_BANK); + writereg(ERXFCON, ERXFCON_UCEN | ERXFCON_CRCEN | ERXFCON_BCEN); + + /* + 6.6 PHY Initialization Settings + + Depending on the application, bits in three of the PHY module’s + registers may also require configuration. The PHCON1.PDPXMD bit + partially controls the device’s half/full-duplex + configuration. Normally, this bit is initialized correctly by the + external circuitry (see Section 2.6 “LED Configuration). If the + external circuitry is not present or incorrect, however, the host + controller must program the bit properly. Alternatively, for an + externally configurable system, the PDPXMD bit may be read and the + FULDPX bit be programmed to match. + + For proper duplex operation, the PHCON1.PDPXMD bit must also match + the value of the MACON3.FULDPX bit. + + If using half duplex, the host controller may wish to set the + PHCON2.HDLDIS bit to prevent automatic loopback of the data which + is transmitted. The PHY register, PHLCON, controls the outputs of + LEDA and LEDB. If an application requires a LED configuration + other than the default, PHLCON must be altered to match the new + requirements. The settings for LED operation are discussed in + Section 2.6 “LED Configuration. The PHLCON register is shown in + Register 2-2 (page 9). + */ + + /* Don't worry about PHY configuration for now */ + + /* Turn on autoincrement for buffer access */ + writereg(ECON2, readreg(ECON2) | ECON2_AUTOINC); + + /* Turn on reception */ + writereg(ECON1, ECON1_RXEN); +} +/*---------------------------------------------------------------------------*/ +void +enc28j60_init(uint8_t *mac_addr) +{ + if(initialized) { + return; + } + + memcpy(enc_mac_addr, mac_addr, 6); + + /* Start watchdog process */ + process_start(&enc_watchdog_process, NULL); + + reset(); + + initialized = 1; +} +/*---------------------------------------------------------------------------*/ +int +enc28j60_send(uint8_t *data, uint16_t datalen) +{ + int padding = 0; + + if(!initialized) { + return -1; + } + + /* + 1. Appropriately program the ETXST pointer to point to an unused + location in memory. It will point to the per packet control + byte. In the example, it would be programmed to 0120h. It is + recommended that an even address be used for ETXST. + + 2. Use the WBM SPI command to write the per packet control byte, + the destination address, the source MAC address, the + type/length and the data payload. + + 3. Appropriately program the ETXND pointer. It should point to the + last byte in the data payload. In the example, it would be + programmed to 0156h. + + 4. Clear EIR.TXIF, set EIE.TXIE and set EIE.INTIE to enable an + interrupt when done (if desired). + + 5. Start the transmission process by setting + ECON1.TXRTS. + */ + + setregbank(ERXTX_BANK); + /* Set up the transmit buffer pointer */ + writereg(ETXSTL, TX_BUF_START & 0xff); + writereg(ETXSTH, TX_BUF_START >> 8); + writereg(EWRPTL, TX_BUF_START & 0xff); + writereg(EWRPTH, TX_BUF_START >> 8); + + /* Write the transmission control register as the first byte of the + output packet. We write 0x00 to indicate that the default + configuration (the values in MACON3) will be used. */ +#define WITH_MANUAL_PADDING 1 +#if WITH_MANUAL_PADDING +#define PADDING_MIN_SIZE 60 + writedatabyte(0x0B); /* POVERRIDE, PCRCEN, PHUGEEN. Not PPADEN */ + if(datalen < PADDING_MIN_SIZE) { + padding = PADDING_MIN_SIZE - datalen; + } else { + padding = 0; + } +#else /* WITH_MANUAL_PADDING */ + writedatabyte(0x00); /* MACON3 */ + padding = 0; +#endif /* WITH_MANUAL_PADDING */ + + /* Write a pointer to the last data byte. */ + writereg(ETXNDL, (TX_BUF_START + datalen + 0 + padding) & 0xff); + writereg(ETXNDH, (TX_BUF_START + datalen + 0 + padding) >> 8); + + writedata(data, datalen); + if(padding > 0) { + uint8_t padding_buf[60]; + memset(padding_buf, 0, padding); + writedata(padding_buf, padding); + } + + /* Clear EIR.TXIF */ + writereg(EIR, readreg(EIR) & (~EIR_TXIF)); + + /* Don't care about interrupts for now */ + + /* Send the packet */ + writereg(ECON1, readreg(ECON1) | ECON1_TXRTS); + while((readreg(ECON1) & ECON1_TXRTS) > 0); + + if((readreg(ESTAT) & ESTAT_TXABRT) != 0) { + PRINTF("enc28j60: tx err: %d: %02x:%02x:%02x:%02x:%02x:%02x\n", datalen, + 0xff & data[0], 0xff & data[1], 0xff & data[2], + 0xff & data[3], 0xff & data[4], 0xff & data[5]); + } else { + PRINTF("enc28j60: tx: %d: %02x:%02x:%02x:%02x:%02x:%02x\n", datalen, + 0xff & data[0], 0xff & data[1], 0xff & data[2], + 0xff & data[3], 0xff & data[4], 0xff & data[5]); + } + sent_packets++; + PRINTF("enc28j60: sent_packets %d\n", sent_packets); + return datalen; +} +/*---------------------------------------------------------------------------*/ +int +enc28j60_read(uint8_t *buffer, uint16_t bufsize) +{ + int n, len, next, err; + + uint8_t nxtpkt[2]; + uint8_t status[2]; + uint8_t length[2]; + + err = 0; + + setregbank(EPKTCNT_BANK); + n = readreg(EPKTCNT); + + if(n == 0) { + return 0; + } + + PRINTF("enc28j60: EPKTCNT 0x%02x\n", n); + + setregbank(ERXTX_BANK); + /* Read the next packet pointer */ + nxtpkt[0] = readdatabyte(); + nxtpkt[1] = readdatabyte(); + + PRINTF("enc28j60: nxtpkt 0x%02x%02x\n", nxtpkt[1], nxtpkt[0]); + + length[0] = readdatabyte(); + length[1] = readdatabyte(); + + PRINTF("enc28j60: length 0x%02x%02x\n", length[1], length[0]); + + status[0] = readdatabyte(); + status[1] = readdatabyte(); + + /* This statement is just to avoid a compiler warning: */ + status[0] = status[0]; + PRINTF("enc28j60: status 0x%02x%02x\n", status[1], status[0]); + + len = (length[1] << 8) + length[0]; + if(bufsize >= len) { + readdata(buffer, len); + } else { + uint16_t i; + + err = 1; + + /* flush rx fifo */ + for(i = 0; i < len; i++) { + readdatabyte(); + } + } + + /* Read an additional byte at odd lengths, to avoid FIFO corruption */ + if((len % 2) != 0) { + readdatabyte(); + } + + /* Errata #14 */ + next = (nxtpkt[1] << 8) + nxtpkt[0]; + if(next == RX_BUF_START) { + next = RX_BUF_END; + } else { + next = next - 1; + } + writereg(ERXRDPTL, next & 0xff); + writereg(ERXRDPTH, next >> 8); + + writereg(ECON2, readreg(ECON2) | ECON2_PKTDEC); + + if(err) { + PRINTF("enc28j60: rx err: flushed %d\n", len); + return 0; + } + PRINTF("enc28j60: rx: %d: %02x:%02x:%02x:%02x:%02x:%02x\n", len, + 0xff & buffer[0], 0xff & buffer[1], 0xff & buffer[2], + 0xff & buffer[3], 0xff & buffer[4], 0xff & buffer[5]); + + received_packets++; + PRINTF("enc28j60: received_packets %d\n", received_packets); + return len; +} +/*---------------------------------------------------------------------------*/ +PROCESS_THREAD(enc_watchdog_process, ev, data) +{ + static struct etimer et; + + PROCESS_BEGIN(); + + while(1) { +#define RESET_PERIOD (30 * CLOCK_SECOND) + etimer_set(&et, RESET_PERIOD); + PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&et)); + + PRINTF("enc28j60: test received_packet %d > sent_packets %d\n", received_packets, sent_packets); + if(received_packets <= sent_packets) { + PRINTF("enc28j60: resetting chip\n"); + reset(); + } + received_packets = 0; + sent_packets = 0; + } + + PROCESS_END(); +} +/*---------------------------------------------------------------------------*/ diff --git a/dev/enc28j60/enc28j60.h b/dev/enc28j60/enc28j60.h new file mode 100644 index 000000000..059528816 --- /dev/null +++ b/dev/enc28j60/enc28j60.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2012-2013, Thingsquare, http://www.thingsquare.com/. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef ENC28J60_H +#define ENC28J60_H + +void enc28j60_init(uint8_t *mac_addr); + +int enc28j60_send(uint8_t *data, uint16_t datalen); + +int enc28j60_read(uint8_t *buffer, uint16_t bufsize); + +/* ENC28J60 architecture-specific SPI functions that are called by the + enc28j60 driver and must be implemented by the platform code */ + +void enc28j60_arch_spi_init(void); +uint8_t enc28j60_arch_spi_write(uint8_t data); +uint8_t enc28j60_arch_spi_read(void); +void enc28j60_arch_spi_select(void); +void enc28j60_arch_spi_deselect(void); + + +#endif /* ENC28J60_H */