Zoltan Hudak / RawEthernet

Dependents:   RawEthernet_Hello

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers RawEthernet.cpp Source File

RawEthernet.cpp

00001 //------------------------------------------------------------------------------
00002 // Functions for using an ENC28J60 ethernet controller, optimized for 
00003 // communication speed.
00004 //
00005 // Written by Rogier Schouten http://www.rogiershikes.tk
00006 // Based on code by Guido Socher http://www.tuxgraphics.org
00007 // Idea modified and further updated by Guido Socher
00008 // Ported to MBED by Zoltan Hudak hudakz@outlook.com
00009 // License: GPL V2
00010 //
00011 // Enables to read sensor data or control IO-ports with less than a millisecond delay. 
00012 // The trick is in removing the TCP/IP overhead and use raw Ethernet frames. 
00013 // A Linux application using raw network sockets is controlling this slave device.
00014 //
00015 // Assumptions:
00016 // - Max. payload data: 255 bytes per packet
00017 // - The network consists of a master PC and one or more slave devices. 
00018 //   Only plain hubs and switches are allowed between PC and ethernet device.
00019 //   Note that some wlan routers have internal switches which switch only
00020 //   IP packets. They will discard plain ethernet frames. A normal 100Mbit 
00021 //   office/workgroup switch will however work.
00022 // 
00023 // Based on these assumptions, we can optimize the protocol for faster communication:
00024 // - Master and slave send unicast packets.
00025 // - We use raw ethernet and no higher-level protocol such as UDP or TCP/IP
00026 // - We use the EtherType field of a packet as a length field. Actually, we only
00027 //   use one byte of it since we have max 255 length packets.
00028 //  
00029 // Furthermore, there are a few code optimizations:
00030 // - Minimize communication between ENC and MCU.
00031 // - No unnecessary memory bank checks
00032 // 
00033 #include "RawEthernet.h"
00034 
00035 // ENC28J60 Control Registers
00036 
00037 // Control register definitions are a combination of address,
00038 // bank number, and Ethernet/MAC/PHY indicator bits.
00039 // - Register address       (bits 0-4)
00040 // - Bank number            (bits 5-6)
00041 // - MAC/PHY indicator      (bit 7)
00042 #define ADDR_MASK   0x1F
00043 #define BANK_MASK   0x60
00044 #define SPRD_MASK   0x80
00045 // All-bank registers
00046 #define EIE     0x1B
00047 #define EIR     0x1C
00048 #define ESTAT   0x1D
00049 #define ECON2   0x1E
00050 #define ECON1   0x1F
00051 // Bank 0 registers
00052 #define ERDPTL      (0x00 | 0x00)
00053 #define ERDPTH      (0x01 | 0x00)
00054 #define EWRPTL      (0x02 | 0x00)
00055 #define EWRPTH      (0x03 | 0x00)
00056 #define ETXSTL      (0x04 | 0x00)
00057 #define ETXSTH      (0x05 | 0x00)
00058 #define ETXNDL      (0x06 | 0x00)
00059 #define ETXNDH      (0x07 | 0x00)
00060 #define ERXSTL      (0x08 | 0x00)
00061 #define ERXSTH      (0x09 | 0x00)
00062 #define ERXNDL      (0x0A | 0x00)
00063 #define ERXNDH      (0x0B | 0x00)
00064 #define ERXRDPTL    (0x0C | 0x00)
00065 #define ERXRDPTH    (0x0D | 0x00)
00066 #define ERXWRPTL    (0x0E | 0x00)
00067 #define ERXWRPTH    (0x0F | 0x00)
00068 #define EDMASTL     (0x10 | 0x00)
00069 #define EDMASTH     (0x11 | 0x00)
00070 #define EDMANDL     (0x12 | 0x00)
00071 #define EDMANDH     (0x13 | 0x00)
00072 #define EDMADSTL    (0x14 | 0x00)
00073 #define EDMADSTH    (0x15 | 0x00)
00074 #define EDMACSL     (0x16 | 0x00)
00075 #define EDMACSH     (0x17 | 0x00)
00076 // Bank 1 registers
00077 #define EHT0    (0x00 | 0x20)
00078 #define EHT1    (0x01 | 0x20)
00079 #define EHT2    (0x02 | 0x20)
00080 #define EHT3    (0x03 | 0x20)
00081 #define EHT4    (0x04 | 0x20)
00082 #define EHT5    (0x05 | 0x20)
00083 #define EHT6    (0x06 | 0x20)
00084 #define EHT7    (0x07 | 0x20)
00085 #define EPMM0   (0x08 | 0x20)
00086 #define EPMM1   (0x09 | 0x20)
00087 #define EPMM2   (0x0A | 0x20)
00088 #define EPMM3   (0x0B | 0x20)
00089 #define EPMM4   (0x0C | 0x20)
00090 #define EPMM5   (0x0D | 0x20)
00091 #define EPMM6   (0x0E | 0x20)
00092 #define EPMM7   (0x0F | 0x20)
00093 #define EPMCSL  (0x10 | 0x20)
00094 #define EPMCSH  (0x11 | 0x20)
00095 #define EPMOL   (0x14 | 0x20)
00096 #define EPMOH   (0x15 | 0x20)
00097 #define EWOLIE  (0x16 | 0x20)
00098 #define EWOLIR  (0x17 | 0x20)
00099 #define ERXFCON (0x18 | 0x20)
00100 #define EPKTCNT (0x19 | 0x20)
00101 // Bank 2 registers
00102 #define MACON1      (0x00 | 0x40 | 0x80)
00103 #define MACON2      (0x01 | 0x40 | 0x80)
00104 #define MACON3      (0x02 | 0x40 | 0x80)
00105 #define MACON4      (0x03 | 0x40 | 0x80)
00106 #define MABBIPG     (0x04 | 0x40 | 0x80)
00107 #define MAIPGL      (0x06 | 0x40 | 0x80)
00108 #define MAIPGH      (0x07 | 0x40 | 0x80)
00109 #define MACLCON1    (0x08 | 0x40 | 0x80)
00110 #define MACLCON2    (0x09 | 0x40 | 0x80)
00111 #define MAMXFLL     (0x0A | 0x40 | 0x80)
00112 #define MAMXFLH     (0x0B | 0x40 | 0x80)
00113 #define MAPHSUP     (0x0D | 0x40 | 0x80)
00114 #define MICON       (0x11 | 0x40 | 0x80)
00115 #define MICMD       (0x12 | 0x40 | 0x80)
00116 #define MIREGADR    (0x14 | 0x40 | 0x80)
00117 #define MIWRL       (0x16 | 0x40 | 0x80)
00118 #define MIWRH       (0x17 | 0x40 | 0x80)
00119 #define MIRDL       (0x18 | 0x40 | 0x80)
00120 #define MIRDH       (0x19 | 0x40 | 0x80)
00121 // Bank 3 registers
00122 #define MAADR1  (0x00 | 0x60 | 0x80)
00123 #define MAADR0  (0x01 | 0x60 | 0x80)
00124 #define MAADR3  (0x02 | 0x60 | 0x80)
00125 #define MAADR2  (0x03 | 0x60 | 0x80)
00126 #define MAADR5  (0x04 | 0x60 | 0x80)
00127 #define MAADR4  (0x05 | 0x60 | 0x80)
00128 #define EBSTSD  (0x06 | 0x60)
00129 #define EBSTCON (0x07 | 0x60)
00130 #define EBSTCSL (0x08 | 0x60)
00131 #define EBSTCSH (0x09 | 0x60)
00132 #define MISTAT  (0x0A | 0x60 | 0x80)
00133 #define EREVID  (0x12 | 0x60)
00134 #define ECOCON  (0x15 | 0x60)
00135 #define EFLOCON (0x17 | 0x60)
00136 #define EPAUSL  (0x18 | 0x60)
00137 #define EPAUSH  (0x19 | 0x60)
00138 // PHY registers
00139 #define PHCON1  0x00
00140 #define PHSTAT1 0x01
00141 #define PHHID1  0x02
00142 #define PHHID2  0x03
00143 #define PHCON2  0x10
00144 #define PHSTAT2 0x11
00145 #define PHIE    0x12
00146 #define PHIR    0x13
00147 #define PHLCON  0x14
00148 // ENC28J60 ERXFCON Register Bit Definitions
00149 #define ERXFCON_UCEN    0x80
00150 #define ERXFCON_ANDOR   0x40
00151 #define ERXFCON_CRCEN   0x20
00152 #define ERXFCON_PMEN    0x10
00153 #define ERXFCON_MPEN    0x08
00154 #define ERXFCON_HTEN    0x04
00155 #define ERXFCON_MCEN    0x02
00156 #define ERXFCON_BCEN    0x01
00157 // ENC28J60 EIE Register Bit Definitions
00158 #define EIE_INTIE   0x80
00159 #define EIE_PKTIE   0x40
00160 #define EIE_DMAIE   0x20
00161 #define EIE_LINKIE  0x10
00162 #define EIE_TXIE    0x08
00163 #define EIE_WOLIE   0x04
00164 #define EIE_TXERIE  0x02
00165 #define EIE_RXERIE  0x01
00166 // ENC28J60 EIR Register Bit Definitions
00167 #define EIR_PKTIF   0x40
00168 #define EIR_DMAIF   0x20
00169 #define EIR_LINKIF  0x10
00170 #define EIR_TXIF    0x08
00171 #define EIR_WOLIF   0x04
00172 #define EIR_TXERIF  0x02
00173 #define EIR_RXERIF  0x01
00174 // ENC28J60 ESTAT Register Bit Definitions
00175 #define ESTAT_INT       0x80
00176 #define ESTAT_LATECOL   0x10
00177 #define ESTAT_RXBUSY    0x04
00178 #define ESTAT_TXABRT    0x02
00179 #define ESTAT_CLKRDY    0x01
00180 // ENC28J60 ECON2 Register Bit Definitions
00181 #define ECON2_AUTOINC   0x80
00182 #define ECON2_PKTDEC    0x40
00183 #define ECON2_PWRSV     0x20
00184 #define ECON2_VRPS      0x08
00185 // ENC28J60 ECON1 Register Bit Definitions
00186 #define ECON1_TXRST     0x80
00187 #define ECON1_RXRST     0x40
00188 #define ECON1_DMAST     0x20
00189 #define ECON1_CSUMEN    0x10
00190 #define ECON1_TXRTS     0x08
00191 #define ECON1_RXEN      0x04
00192 #define ECON1_BSEL1     0x02
00193 #define ECON1_BSEL0     0x01
00194 // ENC28J60 MACON1 Register Bit Definitions
00195 #define MACON1_LOOPBK   0x10
00196 #define MACON1_TXPAUS   0x08
00197 #define MACON1_RXPAUS   0x04
00198 #define MACON1_PASSALL  0x02
00199 #define MACON1_MARXEN   0x01
00200 // ENC28J60 MACON2 Register Bit Definitions
00201 #define MACON2_MARST    0x80
00202 #define MACON2_RNDRST   0x40
00203 #define MACON2_MARXRST  0x08
00204 #define MACON2_RFUNRST  0x04
00205 #define MACON2_MATXRST  0x02
00206 #define MACON2_TFUNRST  0x01
00207 // ENC28J60 MACON3 Register Bit Definitions
00208 #define MACON3_PADCFG2  0x80
00209 #define MACON3_PADCFG1  0x40
00210 #define MACON3_PADCFG0  0x20
00211 #define MACON3_TXCRCEN  0x10
00212 #define MACON3_PHDRLEN  0x08
00213 #define MACON3_HFRMLEN  0x04
00214 #define MACON3_FRMLNEN  0x02
00215 #define MACON3_FULDPX   0x01
00216 // ENC28J60 MACON4 Register Bit Definitions
00217 #define MACON4_DEFER    0x40
00218 #define MACON4_BPEN     0x20
00219 #define MACON4_NOBKOFF  0x10
00220 // ENC28J60 MICMD Register Bit Definitions
00221 #define MICMD_MIISCAN   0x02
00222 #define MICMD_MIIRD     0x01
00223 // ENC28J60 MISTAT Register Bit Definitions
00224 #define MISTAT_NVALID   0x04
00225 #define MISTAT_SCAN     0x02
00226 #define MISTAT_BUSY     0x01
00227 // ENC28J60 PHY PHCON1 Register Bit Definitions
00228 #define PHCON1_PRST     0x8000
00229 #define PHCON1_PLOOPBK  0x4000
00230 #define PHCON1_PPWRSV   0x0800
00231 #define PHCON1_PDPXMD   0x0100
00232 // ENC28J60 PHY PHSTAT1 Register Bit Definitions
00233 #define PHSTAT1_PFDPX   0x1000
00234 #define PHSTAT1_PHDPX   0x0800
00235 #define PHSTAT1_LLSTAT  0x0004
00236 #define PHSTAT1_JBSTAT  0x0002
00237 // ENC28J60 PHY PHSTAT2H Register Bit Definitions
00238 #define PHSTAT2H_LSTAT  0x04
00239 // ENC28J60 PHY PHCON2 Register Bit Definitions
00240 #define PHCON2_FRCLINK  0x4000
00241 #define PHCON2_TXDIS    0x2000
00242 #define PHCON2_JABBER   0x0400
00243 #define PHCON2_HDLDIS   0x0100
00244 // ENC28J60 Packet Control Byte Bit Definitions
00245 #define PKTCTRL_PHUGEEN     0x08
00246 #define PKTCTRL_PPADEN      0x04
00247 #define PKTCTRL_PCRCEN      0x02
00248 #define PKTCTRL_POVERRIDE   0x01
00249 // SPI operation codes
00250 #define ENC28J60_READ_CTRL_REG  0x00
00251 #define ENC28J60_READ_BUF_MEM   0x3A
00252 #define ENC28J60_WRITE_CTRL_REG 0x40
00253 #define ENC28J60_WRITE_BUF_MEM  0x7A
00254 #define ENC28J60_BIT_FIELD_SET  0x80
00255 #define ENC28J60_BIT_FIELD_CLR  0xA0
00256 #define ENC28J60_SOFT_RESET     0xFF
00257 // Buffer memory allocation within controlller.
00258 // Assuming the controller is slower than the network, we allocate one transmit
00259 // packet and leave the rest for receiving.
00260 // The RXSTART_INIT should be zero. See Rev. B4 Silicon Errata
00261 #define RXSTART_INIT    0x0
00262 #define RXSTOP_INIT     (0x1FFF - 0x0600 - 2)   // note: MUST be odd (see errata point 13)
00263 #define TXSTART_INIT    (0x1FFF - 0x0600)
00264 // Maximum packet length: this software has a limit of 255 payload data bytes
00265 // and then there is some ethernet overhead (srd, dst, len, fcs)
00266 #define ENC28J60_MAX_PACKET_LEN ((uint16_t) 273)
00267 // field or packet lengths
00268 #define ETH_HEADER_LEN      14
00269 #define ETH_CHECKSUM_LEN    4
00270 #define ETH_ENVELOPE_LEN    (ETH_HEADER_LEN + ETH_CHECKSUM_LEN)
00271 #define ETH_PAYLOAD_MIN     46
00272 #define ETH_PAYLOAD_MAX     1500
00273 #define ETH_PACKET_MIN      64
00274 #define ETH_PACKET_MAX      1518
00275 // field locations in ethernet packet
00276 #define ETH_DST_MAC_P   0
00277 #define ETH_SRC_MAC_P   6
00278 #define ETH_TYPE_H_P    12
00279 #define ETH_TYPE_L_P    13
00280 #define ENC28J60_HAS_PENDING_TRANSMIT_ON_TRANSMIT
00281 
00282 /* Static member initialization */
00283 char RawEthernet::_arpReqHdr[10] = { 8, 6, 0, 1, 8, 0, 6, 4, 0, 1 };
00284 
00285 /**
00286   * @brief   Constructor
00287   * @note
00288   * @param   mosi SPI master-out slave-in pin #
00289   * @param   miso SPI master-in slave-out pin #
00290   * @param   sclk SPI serial clock pin #
00291   * @param   cs SPI chip select pin #
00292   * @retval
00293   */
00294 RawEthernet::RawEthernet(PinName mosi, PinName miso, PinName sclk, PinName cs, uint8_t myMac[6], uint8_t myIp[4]) :
00295     _spi(mosi, miso, sclk),
00296     _cs(cs)
00297 {
00298     int i;
00299 
00300     for (i = 0; i < 6; i++)
00301         _mac[i] = myMac[i];
00302 
00303     for (i = 0; i < 4; i++)
00304         _ip[i] = myIp[i];
00305 }
00306 
00307 /**
00308   * @brief   Read operation
00309   * @note    Reads from ENC28J60 register
00310   * @param   op operation code
00311   * @param   address register address
00312   * @retval  Register value
00313   */
00314 uint8_t RawEthernet::readOp(uint8_t op, uint8_t address)
00315 {
00316     uint8_t result;
00317 
00318     _cs = 0;
00319 
00320     // issue read command
00321     _spi.write(op | (address & ADDR_MASK));
00322 
00323     // read data
00324     result = _spi.write(0x00);
00325 
00326     // do dummy read if needed (for mac and mii, see datasheet page 29)
00327     if (address & 0x80)
00328         result = _spi.write(0x00);
00329 
00330     // release CS
00331     _cs = 1;
00332     return(result);
00333 }
00334 
00335 /**
00336  * @brief   Write operation
00337  * @note    Writes to ENC28J60 register
00338  * @param   op operation code
00339  * @param   address register address
00340  * @retval  data data to be written
00341  */
00342 void RawEthernet::writeOp(uint8_t op, uint8_t address, uint8_t data)
00343 {
00344     _cs = 0;
00345 
00346     // issue write command
00347     _spi.write(op | (address & ADDR_MASK));
00348 
00349     // write data
00350     _spi.write(data);
00351     _cs = 1;
00352 }
00353 
00354 /**
00355  * @brief
00356  * @note
00357  * @param
00358  * @retval
00359  */
00360 void RawEthernet::setBank(uint8_t address)
00361 {
00362     // set the bank (if needed)
00363     if ((address & BANK_MASK) != _bank) {
00364         // set the bank
00365         writeOp(ENC28J60_BIT_FIELD_CLR, ECON1, (ECON1_BSEL1 | ECON1_BSEL0));
00366         writeOp(ENC28J60_BIT_FIELD_SET, ECON1, (address & BANK_MASK) >> 5);
00367         _bank = (address & BANK_MASK);
00368     }
00369 }
00370 
00371 /**
00372  * @brief
00373  * @note
00374  * @param
00375  * @retval
00376  */
00377 uint8_t RawEthernet::readReg(uint8_t address)
00378 {
00379     setBank(address);
00380     readOp(ENC28J60_READ_CTRL_REG, address);
00381 }
00382 
00383 /**
00384  * @brief
00385  * @note
00386  * @param
00387  * @retval
00388  */
00389 void RawEthernet::writeReg(uint8_t address, uint8_t data)
00390 {
00391     setBank(address);
00392     writeOp(ENC28J60_WRITE_CTRL_REG, address, data);
00393 }
00394 
00395 /**
00396  * @brief
00397  * @note
00398  * @param
00399  * @retval
00400  */
00401 void RawEthernet::readBuffer(uint16_t len, uint8_t* data)
00402 {
00403     _cs = 0;
00404 
00405     // issue read command
00406     _spi.write(ENC28J60_READ_BUF_MEM);
00407     while (len) {
00408         len--;
00409 
00410         // read data
00411         *data = _spi.write(0x00);
00412         data++;
00413     }
00414 
00415     //*data = '\0';
00416     _cs = 1;
00417 }
00418 
00419 /**
00420  * @brief
00421  * @note
00422  * @param
00423  * @retval
00424  */
00425 void RawEthernet::writeBuffer(uint16_t len, uint8_t* data)
00426 {
00427     _cs = 0;
00428 
00429     // issue write command
00430     _spi.write(ENC28J60_WRITE_BUF_MEM);
00431     while (len) {
00432         len--;
00433 
00434         // write data
00435         _spi.write(*data);
00436         data++;
00437     }
00438 
00439     _cs = 1;
00440 }
00441 
00442 /**
00443  * @brief
00444  * @note
00445  * @param
00446  * @retval
00447  */
00448 uint16_t RawEthernet::phyReadH(uint8_t address)
00449 {
00450     // set the right address and start the register read operation
00451     writeReg(MIREGADR, address);
00452     writeReg(MICMD, MICMD_MIIRD);
00453     wait_us(15);
00454 
00455     // wait until the PHY read completes
00456     while (readReg(MISTAT) & MISTAT_BUSY);
00457 
00458     // reset reading bit
00459     setBank(2);
00460     writeReg(MICMD, 0x00);
00461 
00462     return(readReg(MIRDH));
00463 }
00464 
00465 /**
00466  * @brief
00467  * @note
00468  * @param
00469  * @retval
00470  */
00471 void RawEthernet::phyWrite(uint8_t address, uint16_t data)
00472 {
00473     setBank(2);
00474 
00475     // set the PHY register address
00476     writeReg(MIREGADR, address);
00477 
00478     // write the PHY data
00479     writeReg(MIWRL, data);
00480     writeReg(MIWRH, data >> 8);
00481 
00482     // wait until the PHY write completes
00483     setBank(3);
00484     while (readReg(MISTAT) & MISTAT_BUSY) {
00485         wait_us(15);
00486     }
00487 }
00488 
00489 /**
00490  * @brief
00491  * @note
00492  * @param
00493  * @retval
00494  */
00495 void RawEthernet::linkTo(uint8_t remoteMac[6])
00496 {
00497     for (int i = 0; i < 6; i++)
00498         _remoteMac[i] = remoteMac[i];
00499 
00500     _spi.format(8, 0);          // 8bit, mode 0
00501     _spi.frequency(7000000);    // 7MHz
00502     wait(1);                    // 1 second for stable state
00503     // initialize I/O
00504     _cs = 1;
00505     // perform system reset
00506     writeOp(ENC28J60_SOFT_RESET, 0, ENC28J60_SOFT_RESET);
00507     wait_ms(50);
00508     // The CLKRDY does not work. See Rev. B4 Silicon Errata point. Just wait.
00509     //while(!(read(ESTAT) & ESTAT_CLKRDY));
00510     // do bank 0 stuff
00511     // initialize receive buffer
00512     // 16-bit transfers, must write low byte first
00513     // set receive buffer start address
00514     _nextPacketPtr = RXSTART_INIT;
00515 
00516     // Rx start
00517     writeReg(ERXSTL, RXSTART_INIT & 0xFF);
00518     writeReg(ERXSTH, RXSTART_INIT >> 8);
00519 
00520     // set receive pointer address
00521     writeReg(ERXRDPTL, RXSTART_INIT & 0xFF);
00522     writeReg(ERXRDPTH, RXSTART_INIT >> 8);
00523 
00524     // RX end
00525     writeReg(ERXNDL, RXSTOP_INIT & 0xFF);
00526     writeReg(ERXNDH, RXSTOP_INIT >> 8);
00527 
00528     // TX start
00529     writeReg(ETXSTL, TXSTART_INIT & 0xFF);
00530     writeReg(ETXSTH, TXSTART_INIT >> 8);
00531 
00532     // TX end (initialize for a packet with a payload of 1 byte)
00533     uint16_t    address = (TXSTART_INIT + ETH_HEADER_LEN + 1);
00534     writeReg(ETXNDL, address & 0xFF);
00535     writeReg(ETXNDH, address >> 8);
00536 
00537     // prepare the parts of the transmit packet that never change
00538     // write per-packet control byte (0x00 means use macon3 settings)
00539     writeReg(EWRPTL, (TXSTART_INIT) & 0xFF);
00540     writeReg(EWRPTH, (TXSTART_INIT) >> 8);
00541     writeOp(ENC28J60_WRITE_BUF_MEM, 0, 0x00);
00542 
00543     // write broadcast address as DST MAC
00544     uint8_t i = 0;
00545     while (i < 6) {
00546         writeOp(ENC28J60_WRITE_BUF_MEM, 0, 0xFF);
00547         i++;
00548     }
00549 
00550     // set our MAC address as the SRC MAC into the transmit buffer
00551     // set the write pointer to start of transmit buffer area
00552     writeBuffer(6, const_cast<uint8_t*>(_mac));
00553     // First EtherType/length byte is always 0, initialize second byte to 1
00554     writeOp(ENC28J60_WRITE_BUF_MEM, 0, 0x00);
00555     writeOp(ENC28J60_WRITE_BUF_MEM, 0, 0x01);
00556 
00557     // do bank 1 stuff, packet filter:
00558     setBank(1);
00559     // only allow unicast packets destined for us and that have a correct CRC
00560     writeReg(ERXFCON, ERXFCON_UCEN | ERXFCON_CRCEN);
00561 
00562     // do bank 2 stuff
00563     setBank(2);
00564     // enable MAC receive, disable flow control (only needed in full-duplex)
00565     writeReg(MACON1, MACON1_MARXEN);
00566     // bring MAC out of reset
00567     writeReg(MACON2, 0x00);
00568     // enable automatic padding to 60bytes and CRC operations
00569     // also, force half-duplex operation
00570     writeReg(MACON3, MACON3_PADCFG0 | MACON3_TXCRCEN | MACON3_FRMLNEN);
00571     // half-duplex only: back-off settings
00572     writeReg(MACON4, MACON4_DEFER | MACON4_BPEN | MACON4_NOBKOFF);
00573     // set the maximum packet size which the controller will accept
00574     // do not send packets longer than MAX_FRAMELEN:
00575     writeReg(MAMXFLL, ENC28J60_MAX_PACKET_LEN & 0xFF);
00576     writeReg(MAMXFLH, ENC28J60_MAX_PACKET_LEN >> 8);
00577     // set inter-frame gap (non-back-to-back)
00578     writeReg(MAIPGL, 0x12);
00579     writeReg(MAIPGH, 0x0C);
00580     // set inter-frame gap (back-to-back)
00581     writeReg(MABBIPG, 0x12);
00582 
00583     // do bank 3 stuff
00584     // write MAC address
00585     // NOTE: MAC address in ENC28J60 is byte-backward
00586     writeReg(MAADR5, _mac[0]);
00587     writeReg(MAADR4, _mac[1]);
00588     writeReg(MAADR3, _mac[2]);
00589     writeReg(MAADR2, _mac[3]);
00590     writeReg(MAADR1, _mac[4]);
00591     writeReg(MAADR0, _mac[5]);
00592 
00593     // no loopback of transmitted frames
00594     phyWrite(PHCON2, PHCON2_HDLDIS);
00595 
00596     // switch to bank 0
00597     setBank(ECON1);
00598 
00599     // enable interrutps
00600     writeOp(ENC28J60_BIT_FIELD_SET, EIE, EIE_INTIE | EIE_PKTIE);
00601 
00602     // enable packet reception
00603     writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_RXEN);
00604 
00605     // change clkout from 6.25MHz to 12.5MHz
00606     writeReg(ECOCON, 2 & 0x7);
00607     wait_us(60);
00608 
00609     /* magjack leds configuration, see enc28j60 datasheet, page 11 */
00610     // LEDA=green,        LEDB=yellow,
00611     // LEDA=links status, LEDB=receive/transmit
00612     // phyWrite(PHLCON,0b0000 0100 0111 0110);
00613     phyWrite(PHLCON, 0x476);
00614 
00615     // wait until the link is up, then send a gratuitous ARP request
00616     // to inform any conected switch about my existence
00617     while (!isLinkUp());
00618     wait_ms(50);
00619     // send gratuitous ARP request
00620     gratuitousArp();
00621 }
00622 
00623 /**
00624  * @brief
00625  * @note
00626  * @param
00627  * @retval
00628  */
00629 bool RawEthernet::isLinkUp(void)
00630 {
00631     return(phyReadH(PHSTAT2) & PHSTAT2H_LSTAT);
00632 }
00633 
00634 /**
00635  * @brief
00636  * @note
00637  * @param
00638  * @retval
00639  */
00640 uint8_t RawEthernet::receive(uint8_t* buf, uint8_t maxlen)
00641 {
00642     uint16_t    len;
00643     uint16_t    currentPacketPtr = _nextPacketPtr;
00644     uint16_t    address;
00645     uint16_t    framelen;
00646 
00647     // check if a packet has been received and buffered
00648     setBank(1);
00649     if (readReg(EPKTCNT) == 0)
00650         return(0);
00651 
00652     setBank(0);
00653 
00654     // Somehow, the read pointer is NOT already at the start of the next packet
00655     // even though we leave it in that state
00656     writeReg(ERDPTL, (_nextPacketPtr & 0xff));
00657     writeReg(ERDPTH, (_nextPacketPtr) >> 8);
00658     // Read the next packet pointer 
00659     _nextPacketPtr = readOp(ENC28J60_READ_BUF_MEM, 0);
00660     _nextPacketPtr |= readOp(ENC28J60_READ_BUF_MEM, 0) << 8;
00661     // read the frame length
00662     framelen = readOp(ENC28J60_READ_BUF_MEM, 0);
00663     framelen |= readOp(ENC28J60_READ_BUF_MEM, 0) << 8;
00664     if (maxlen > framelen - 14) {
00665         // subtract eth source, dest and length fields
00666         maxlen = framelen - 14;
00667     }
00668 
00669     // Read EtherType (we use this as a length field) (note +6 for receive vectors)
00670     // Set read pointer (taking care of wrap-around)
00671     address = currentPacketPtr + ETH_TYPE_H_P + 6;
00672     if (address > RXSTOP_INIT) {
00673         address -= (RXSTOP_INIT - RXSTART_INIT + 1);
00674     }
00675 
00676     writeReg(ERDPTL, (address & 0xff));
00677     writeReg(ERDPTH, (address) >> 8);
00678     readBuffer(6, _remoteMac);
00679 
00680     // A value of less than 0x05dc in the EtherType has to be interpreted as length.
00681     // This is what we do here.
00682     // The length is 16 bit. The upper 8 bits must be zero
00683     // otherwise it is not our packet.
00684     len = readOp(ENC28J60_READ_BUF_MEM, 0);
00685     if (len == 0) {
00686         // read the lower byte of the length field
00687         len = readOp(ENC28J60_READ_BUF_MEM, 0);
00688         // limit retrieve length to maxlen, ignoring anything else
00689         if (len > maxlen) {
00690             len = maxlen;
00691         }
00692 
00693         // copy payload data from the receive buffer
00694         readBuffer(len, buf);
00695     }
00696     else
00697         len = 0;
00698 
00699     // Move the RX read pointer to the start of the next received packet
00700     // This frees the memory we just read out.
00701     // However, compensate for the errata point 13, rev B4: enver write an even address!
00702     if ((_nextPacketPtr - 1 < RXSTART_INIT) || (_nextPacketPtr - 1 > RXSTOP_INIT)) {
00703         writeReg(ERXRDPTL, (RXSTOP_INIT) & 0xFF);
00704         writeReg(ERXRDPTH, (RXSTOP_INIT) >> 8);
00705     }
00706     else {
00707         writeReg(ERXRDPTL, (_nextPacketPtr - 1) & 0xFF);
00708         writeReg(ERXRDPTH, (_nextPacketPtr - 1) >> 8);
00709     }
00710 
00711     // Decrement the packet counter indicate we are done with this packet
00712     writeOp(ENC28J60_BIT_FIELD_SET, ECON2, ECON2_PKTDEC);
00713     return(len);
00714 }
00715 
00716 // sends gratuitous ARP request (spontaneous arp request) to teach
00717 
00718 // switches what our mac is.
00719 void RawEthernet::gratuitousArp()
00720 {
00721     uint8_t     i = 0;
00722     uint16_t    address;
00723     setBank(0);
00724 
00725     // (control byte, and SRC MAC have already been set during init)
00726 #ifdef ENC28J60_HAS_PENDING_TRANSMIT_ON_TRANSMIT
00727     // Check no transmit in progress
00728 
00729     while (readOp(ENC28J60_READ_CTRL_REG, ECON1) & ECON1_TXRTS) {
00730         // Reset the transmit logic problem. See Rev. B4 Silicon Errata point 12.
00731         if ((readReg(EIR) & EIR_TXERIF)) {
00732             writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_TXRST);
00733             writeOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_TXRST);
00734         }
00735     }
00736 
00737 #else
00738     // Reset the transmit logic problem. See Rev. B4 Silicon Errata point 12.
00739 
00740     if ((readReg(EIR) & EIR_TXERIF)) {
00741         writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_TXRST);
00742         writeOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_TXRST);
00743     }
00744 #endif
00745     // Set the write pointer to start of transmit buffer area
00746 
00747     // +1 to skip the per packet control byte and write directly the mac
00748     // The control byte was set to zero during initialisation and remains like that.
00749     writeReg(EWRPTL, (TXSTART_INIT + 1) & 0xFF);
00750     writeReg(EWRPTH, (TXSTART_INIT + 1) >> 8);
00751     // write a broadcase destination mac (all ff):
00752     while (i < 6) {
00753         writeOp(ENC28J60_WRITE_BUF_MEM, 0, 0xFF);
00754         i++;
00755     }
00756 
00757     // The mac in the ethernet field does not need to be changed.
00758     // Set the write pointer to the first byte of the EtherType field
00759     address = TXSTART_INIT + 1 + ETH_TYPE_H_P;
00760     writeReg(EWRPTL, address & 0xFF);
00761     writeReg(EWRPTH, address >> 8);
00762     // there are 10 fixed bytes in the arp request
00763     i = 0;
00764     while (i < 10) {
00765         writeOp(ENC28J60_WRITE_BUF_MEM, 0, (_arpReqHdr[i]));
00766         i++;
00767     }
00768 
00769     i = 0;
00770     while (i < 6) {
00771         writeOp(ENC28J60_WRITE_BUF_MEM, 0, _mac[i]);
00772         i++;
00773     }
00774 
00775     i = 0;
00776     while (i < 4) {
00777         writeOp(ENC28J60_WRITE_BUF_MEM, 0, _ip[i]);
00778         i++;
00779     }
00780 
00781     // target data:
00782     i = 0;
00783     while (i < 6) {
00784         writeOp(ENC28J60_WRITE_BUF_MEM, 0, 0xff);
00785         i++;
00786     }
00787 
00788     // to self, for gratuitous arp:
00789     i = 0;
00790     while (i < 4) {
00791         writeOp(ENC28J60_WRITE_BUF_MEM, 0, _ip[i]);
00792         i++;
00793     }
00794 
00795     // Set the TXND pointer to correspond to the payload size given
00796     address = (TXSTART_INIT + 42);
00797     writeReg(ETXNDL, address & 0xFF);
00798     writeReg(ETXNDH, address >> 8);
00799 
00800     // Send the contents of the transmit buffer onto the network
00801     writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_TXRTS);
00802 }
00803 
00804 /**
00805  * @brief
00806  * @note
00807  * @param
00808  * @retval
00809  */
00810 void RawEthernet::send(uint8_t* buf, uint8_t len)
00811 {
00812     uint16_t    address;
00813     setBank(0);
00814 
00815     // (control byte, and SRC MAC have already been set during init)
00816 #ifdef ENC28J60_HAS_PENDING_TRANSMIT_ON_TRANSMIT
00817     // Check no transmit in progress
00818 
00819     while (readOp(ENC28J60_READ_CTRL_REG, ECON1) & ECON1_TXRTS) {
00820         // Reset the transmit logic problem. See Rev. B4 Silicon Errata point 12.
00821         if ((readReg(EIR) & EIR_TXERIF)) {
00822             writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_TXRST);
00823             writeOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_TXRST);
00824         }
00825     }
00826 
00827 #else
00828     // Reset the transmit logic problem. See Rev. B4 Silicon Errata point 12.
00829 
00830     if ((readReg(EIR) & EIR_TXERIF)) {
00831         writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_TXRST);
00832         writeOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_TXRST);
00833     }
00834 #endif
00835     // Set the write pointer to start of transmit buffer area
00836 
00837     // +1 to skip the per packet control byte and write directly the mac
00838     // The control byte was set to zero during initialisation and remains like that.
00839     writeReg(EWRPTL, (TXSTART_INIT + 1) & 0xFF);
00840     writeReg(EWRPTH, (TXSTART_INIT + 1) >> 8);
00841     writeBuffer(6, _remoteMac);
00842 
00843     // Set the write pointer to the first byte of the EtherType field
00844     // (field after the mac address). This is the 802.3 length field.
00845     address = TXSTART_INIT + 1 + ETH_TYPE_H_P;
00846     writeReg(EWRPTL, address & 0xFF);
00847     writeReg(EWRPTH, address >> 8);
00848     // write the length of the data in the ethernet type field.
00849     // The type field to be interpreted by the receiver as ieee802.3 length if
00850     // the value is less than 0x05dc (see e.g. http://www.cavebear.com/archive/cavebear/Ethernet/type.html ):
00851     writeOp(ENC28J60_WRITE_BUF_MEM, 0, 0);
00852     writeOp(ENC28J60_WRITE_BUF_MEM, 0, len);
00853     // Copy the payload into the transmit buffer
00854     writeBuffer(len, buf);  // remove dest mac and write the rest
00855     // Set the TXND pointer to correspond to the payload size given
00856     address = (TXSTART_INIT + ETH_HEADER_LEN + len);
00857     writeReg(ETXNDL, address & 0xFF);
00858     writeReg(ETXNDH, address >> 8);
00859 
00860     // Send the contents of the transmit buffer onto the network
00861     writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_TXRTS);
00862 }
00863 
00864 /**
00865  * @brief
00866  * @note
00867  * @param
00868  * @retval
00869  */
00870 uint8_t RawEthernet::getRev(void)
00871 {
00872     uint8_t rev;
00873 
00874     rev = readReg(EREVID);
00875 
00876     // microchip forgott to step the number on the silcon when they
00877     // released the revision B7. 6 is now rev B7. We still have
00878     // to see what they do when they release B8. At the moment
00879     // there is no B8 out yet
00880     if (rev > 5)
00881         rev++;
00882     return(rev);
00883 }
00884