Subversion Repositories HomeAutomation

Rev

Rev 363 | Blame | Compare with Previous | Last modification | View Log | SVN | RSS feed

  1. /*********************************************************************
  2.  *
  3.  *     MAC Module (Microchip ENC28J60) for Microchip TCP/IP Stack
  4.  *
  5.  *********************************************************************
  6.  * FileName:        ENC28J60.c
  7.  * Dependencies:    ENC28J60.h
  8.  *                  MAC.h
  9.  *                  string.h
  10.  *                  StackTsk.h
  11.  *                  Helpers.h
  12.  *                  Delay.h
  13.  * Processor:       PIC18, PIC24F, PIC24H, dsPIC30F, dsPIC33F
  14.  * Complier:        Microchip C18 v3.02 or higher
  15.  *                  Microchip C30 v2.01 or higher
  16.  * Company:         Microchip Technology, Inc.
  17.  *
  18.  * Software License Agreement
  19.  *
  20.  * This software is owned by Microchip Technology Inc. ("Microchip")
  21.  * and is supplied to you for use exclusively as described in the
  22.  * associated software agreement.  This software is protected by
  23.  * software and other intellectual property laws.  Any use in
  24.  * violation of the software license may subject the user to criminal
  25.  * sanctions as well as civil liability.  Copyright 2006 Microchip
  26.  * Technology Inc.  All rights reserved.
  27.  *
  28.  * This software is provided "AS IS."  MICROCHIP DISCLAIMS ALL
  29.  * WARRANTIES, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, NOT LIMITED
  30.  * TO MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND
  31.  * INFRINGEMENT.  Microchip shall in no event be liable for special,
  32.  * incidental, or consequential damages.
  33.  *
  34.  *
  35.  * Author               Date        Comment
  36.  *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  37.  * Howard Schlunder     6/28/04 Original
  38.  * Howard Schlunder     10/8/04 Cleanup
  39.  * Howard Schlunder     10/19/04 Small optimizations and more cleanup
  40.  * Howard Schlunder     11/29/04 Added Set/GetCLKOUT
  41.  * Howard Schlunder     12/23/05 Added B1 silicon errata workarounds
  42.  * Howard Schlunder     1/09/06 Added comments and minor mods
  43.  * Howard Schlunder     1/18/06 Added more silicon errata workarounds
  44.  * Howard Schlunder     6/16/06 Synchronized with PIC18F97J60 code
  45.  * Howard Schlunder     7/17/06 Updated TestMemory() for C30
  46.  * Howard Schlunder     8/07/06 Added SetRXHashTableEntry() function
  47. ********************************************************************/
  48. #define THIS_IS_MAC_LAYER
  49.  
  50. #include <string.h>
  51. #include "..\Include\StackTsk.h"
  52. #include "..\Include\Helpers.h"
  53. #include "..\Include\Delay.h"
  54. #include "..\Include\MAC.h"
  55. #include "..\Include\ENC28J60.h"
  56.  
  57.  
  58. #if defined(STACK_USE_SLIP)
  59. #error Unexpected module is detected.
  60. #error This file must be linked when SLIP module is not in use.
  61. #endif
  62.  
  63.  
  64. /** D E F I N I T I O N S ****************************************************/
  65. // IMPORTANT SPI NOTE: The code in this file expects that the SPI interrupt
  66. //      flag (ENC_SPI_IF) be clear at all times.  If the SPI is shared with
  67. //      other hardware, the other code should clear the ENC_SPI_IF when it is
  68. //      done using the SPI.
  69.  
  70. // Since the ENC28J60 doesn't support auto-negotiation, full-duplex mode is
  71. // not compatible with most switches/routers.  If a dedicated network is used
  72. // where the duplex of the remote node can be manually configured, you may
  73. // change this configuration.  Otherwise, half duplex should always be used.
  74. #define HALF_DUPLEX
  75. //#define FULL_DUPLEX
  76. //#define LEDB_DUPLEX
  77.  
  78. // Pseudo Functions
  79. #define LOW(a)                  (a & 0xFF)
  80. #define HIGH(a)                 ((a>>8) & 0xFF)
  81.  
  82. // NIC RAM definitions
  83. #define RAMSIZE 8192ul     
  84. #define TXSTART (RAMSIZE-(MAC_TX_BUFFER_COUNT * (MAC_TX_BUFFER_SIZE + 8ul)))
  85. #define RXSTART (0ul)                       // Should be an even memory address
  86. #define RXSTOP  ((TXSTART-2ul) | 0x0001ul)  // Odd for errata workaround
  87. #define RXSIZE  (RXSTOP-RXSTART+1ul)
  88.  
  89. // ENC28J60 Opcodes (to be ORed with a 5 bit address)
  90. #define WCR (0b010<<5)          // Write Control Register command
  91. #define BFS (0b100<<5)          // Bit Field Set command
  92. #define BFC (0b101<<5)          // Bit Field Clear command
  93. #define RCR (0b000<<5)          // Read Control Register command
  94. #define RBM ((0b001<<5) | 0x1A) // Read Buffer Memory command
  95. #define WBM ((0b011<<5) | 0x1A) // Write Buffer Memory command
  96. #define SR  ((0b111<<5) | 0x1F) // System Reset command does not use an address.  
  97.                                 //   It requires 0x1F, however.
  98.  
  99. #define ETHER_IP    (0x00u)
  100. #define ETHER_ARP   (0x06u)
  101.  
  102. #define MAXFRAMEC   (1500u+sizeof(ETHER_HEADER)+4u)
  103.  
  104. // A generic structure representing the Ethernet header starting all Ethernet
  105. // frames
  106. typedef struct _ETHER_HEADER
  107. {
  108.     MAC_ADDR        DestMACAddr;
  109.     MAC_ADDR        SourceMACAddr;
  110.     WORD_VAL        Type;
  111. } ETHER_HEADER;
  112.  
  113. // A header appended at the start of all RX frames by the hardware
  114. typedef struct _ENC_PREAMBLE
  115. {
  116.     WORD            NextPacketPointer;
  117.     RXSTATUS        StatusVector;
  118.  
  119.     MAC_ADDR        DestMACAddr;
  120.     MAC_ADDR        SourceMACAddr;
  121.     WORD_VAL        Type;
  122. } ENC_PREAMBLE;
  123.  
  124. typedef struct _DATA_BUFFER
  125. {
  126.     WORD_VAL StartAddress;
  127.     WORD_VAL EndAddress;
  128.     struct
  129.     {
  130.         unsigned char bFree : 1;
  131.         unsigned char bTransmitted : 1;
  132.     } Flags;
  133. } DATA_BUFFER;
  134.  
  135.  
  136. // Prototypes of functions intended for MAC layer use only.
  137. static void BankSel(WORD Register);
  138. static REG ReadETHReg(BYTE Address);
  139. static REG ReadMACReg(BYTE Address);
  140. static void WriteReg(BYTE Address, BYTE Data);
  141. static void BFCReg(BYTE Address, BYTE Data);
  142. static void BFSReg(BYTE Address, BYTE Data);
  143. static void SendSystemReset(void);
  144. //static void GetRegs(void);
  145. #ifdef MAC_POWER_ON_TEST
  146. static BOOL TestMemory(void);
  147. #endif
  148.  
  149. // Internal and externally used MAC level variables.
  150. #if MAC_TX_BUFFER_COUNT > 1
  151. static DATA_BUFFER TxBuffers[MAC_TX_BUFFER_COUNT];
  152. #endif
  153. BUFFER CurrentTxBuffer;
  154. BUFFER LastTXedBuffer;
  155.  
  156. // Internal MAC level variables and flags.
  157. WORD_VAL NextPacketLocation;
  158. WORD_VAL CurrentPacketLocation;
  159. BOOL WasDiscarded;
  160. BYTE ENCRevID;
  161.  
  162.  
  163. /******************************************************************************
  164.  * Function:        void MACInit(void)
  165.  *
  166.  * PreCondition:    None
  167.  *
  168.  * Input:           None
  169.  *
  170.  * Output:          None
  171.  *
  172.  * Side Effects:    None
  173.  *
  174.  * Overview:        MACInit sets up the PIC's SPI module and all the
  175.  *                  registers in the ENC28J60 so that normal operation can
  176.  *                  begin.
  177.  *
  178.  * Note:            None
  179.  *****************************************************************************/
  180. void MACInit(void)
  181. {
  182.     BYTE i;
  183.    
  184.     // Set up the SPI module on the PIC for communications with the ENC28J60
  185.     ENC_CS_IO = 1;
  186.     ENC_CS_TRIS = 0;        // Make the Chip Select pin an output
  187.     ENC_SCK_TRIS = 0;
  188.     ENC_SDO_TRIS = 0;
  189.     ENC_SDI_TRIS = 1;
  190.  
  191.     // Set up SPI
  192. #if defined(__18CXX)
  193.     ENC_SPICON1 = 0x20;         // SSPEN bit is set, SPI in master mode, FOSC/4,
  194.                             //   IDLE state is low level
  195.     ENC_SPI_IF = 0;
  196.     ENC_SPISTATbits.CKE = 1;    // Transmit data on rising edge of clock
  197.     ENC_SPISTATbits.SMP = 0;    // Input sampled at middle of data output time
  198. #else
  199.     ENC_SPISTAT = 0;        // clear SPI
  200. #if defined(__PIC24H__) || defined(__dsPIC33F__)
  201.     ENC_SPICON1 = 0x0F;     // 1:1 primary prescale, 5:1 secondary prescale (8MHz  @ 40MIPS)
  202. //    ENC_SPICON1 = 0x1E;   // 4:1 primary prescale, 1:1 secondary prescale (10MHz @ 40MIPS, Doesn't work.  CLKRDY is incorrectly reported as being clear.  Problem caused by dsPIC33/PIC24H ES silicon bug.)
  203. #elif defined(__PIC24F__)
  204. //    ENC_SPICON1 = 0x1F;   // 1:1 prescale broken on PIC24F ES silicon     (16MHz @ 16MIPS)
  205.     ENC_SPICON1 = 0x1B;     // 1:1 primary prescale, 2:1 secondary prescale (8MHz  @ 16MIPS)
  206. #else   // dsPIC30F
  207.     ENC_SPICON1 = 0x17;     // 1:1 primary prescale, 3:1 secondary prescale (10MHz @ 30MIPS)
  208. #endif
  209.     ENC_SPICON2 = 0;
  210.     ENC_SPICON1bits.CKE = 1;
  211.     ENC_SPICON1bits.MSTEN = 1;
  212.     ENC_SPISTATbits.SPIEN = 1;
  213. #endif
  214.  
  215.     // Wait for CLKRDY to become set.
  216.     // Bit 3 in ESTAT is an unimplemented bit.  If it reads out as '1' that
  217.     // means the part is in RESET or there is something wrong with the SPI
  218.     // connection.  This loop makes sure that we can communicate with the
  219.     // ENC28J60 before proceeding.
  220.     do
  221.     {
  222.         i = ReadETHReg(ESTAT).Val;
  223.     } while((i & 0x08) || (~i & ESTAT_CLKRDY));
  224.  
  225.  
  226. #ifdef MAC_POWER_ON_TEST
  227.     // Do the memory test and enter a while always trap if a hardware error
  228.     // occured.  The LEDA and LEDB pins will be configured to blink
  229.     // periodically in an abnormal manner to indicate to the user that the
  230.     // error occured.
  231.     if( !TestMemory() )
  232.     {
  233.         SetLEDConfig(0x0AA2);       // Set LEDs to blink periodically
  234.         while(1);          
  235.     }
  236. #endif
  237.  
  238.     // RESET the entire ENC28J60, clearing all registers
  239.     SendSystemReset(); 
  240.     DelayMs(1);
  241.  
  242. #if MAC_TX_BUFFER_COUNT > 1
  243.     // On Init, all transmit buffers are free.
  244.     for (i = 0; i < MAC_TX_BUFFER_COUNT; i++ )
  245.     {
  246.         TxBuffers[i].StartAddress.Val = TXSTART + ((WORD)i * (MAC_TX_BUFFER_SIZE+8));
  247.         TxBuffers[i].Flags.bFree = TRUE;
  248.     }
  249. #endif
  250.     CurrentTxBuffer = 0;
  251.    
  252.     // Start up in Bank 0 and configure the receive buffer boundary pointers
  253.     // and the buffer write protect pointer (receive buffer read pointer)
  254.     WasDiscarded = TRUE;
  255.     NextPacketLocation.Val = RXSTART;
  256.     WriteReg(ERXSTL, LOW(RXSTART));
  257.     WriteReg(ERXSTH, HIGH(RXSTART));
  258.     WriteReg(ERXRDPTL, LOW(RXSTOP));    // Write low byte first
  259.     WriteReg(ERXRDPTH, HIGH(RXSTOP));   // Write high byte last
  260. #if RXSTOP != 0x1FFF    // The RESET default ERXND is 0x1FFF
  261.     WriteReg(ERXNDL, LOW(RXSTOP));
  262.     WriteReg(ERXNDH, HIGH(RXSTOP));
  263. #endif
  264. #if TXSTART != 0        // The RESET default ETXST is 0
  265.     WriteReg(ETXSTL, LOW(TXSTART));
  266.     WriteReg(ETXSTH, HIGH(TXSTART));
  267. #endif
  268.  
  269.     // Enter Bank 1 and configure Receive Filters
  270.     // (No need to reconfigure - Unicast OR Broadcast with CRC checking is
  271.     // acceptable)
  272.     // Write ERXFCON_CRCEN only to ERXFCON to enter promiscuous mode
  273.     //BankSel(ERXFCON);
  274.     //WriteReg((BYTE)ERXFCON, ERXFCON_UCEN | ERXFCON_CRCEN | ERXFCON_BCEN | ERXFCON_HTEN);
  275.  
  276.     // Enter Bank 2 and configure the MAC
  277.     BankSel(MACON1);
  278.  
  279.     // Enable the receive portion of the MAC
  280.     WriteReg((BYTE)MACON1, MACON1_TXPAUS | MACON1_RXPAUS | MACON1_MARXEN);
  281.    
  282.     // Pad packets to 60 bytes, add CRC, and check Type/Length field.
  283.     WriteReg((BYTE)MACON3, MACON3_PADCFG0 | MACON3_TXCRCEN | MACON3_FRMLNEN);
  284.  
  285.     // Allow infinite deferals if the medium is continuously busy
  286.     // (do not time out a transmission if the half duplex medium is
  287.     // completely saturated with other people's data)
  288.     WriteReg((BYTE)MACON4, MACON4_DEFER);
  289.  
  290.     // Late collisions occur beyond 63+8 bytes (8 bytes for preamble/start of frame delimiter)
  291.     // 55 is all that is needed for IEEE 802.3, but ENC28J60 B5 errata for improper link pulse
  292.     // collisions will occur less often with a larger number.
  293.     WriteReg((BYTE)MACLCON2, 63);
  294.    
  295.     // Set non-back-to-back inter-packet gap to 9.6us.  The back-to-back
  296.     // inter-packet gap (MABBIPG) is set by MACSetDuplex() which is called
  297.     // later.
  298.     WriteReg((BYTE)MAIPGL, 0x12);
  299.     WriteReg((BYTE)MAIPGH, 0x0C);
  300.  
  301.     // Set the maximum packet size which the controller will accept
  302.     WriteReg((BYTE)MAMXFLL, LOW(MAXFRAMEC));   
  303.     WriteReg((BYTE)MAMXFLH, HIGH(MAXFRAMEC));
  304.    
  305.     // Enter Bank 3 and initialize physical MAC address registers
  306.     BankSel(MAADR1);
  307.     WriteReg((BYTE)MAADR1, AppConfig.MyMACAddr.v[0]);
  308.     WriteReg((BYTE)MAADR2, AppConfig.MyMACAddr.v[1]);
  309.     WriteReg((BYTE)MAADR3, AppConfig.MyMACAddr.v[2]);
  310.     WriteReg((BYTE)MAADR4, AppConfig.MyMACAddr.v[3]);
  311.     WriteReg((BYTE)MAADR5, AppConfig.MyMACAddr.v[4]);
  312.     WriteReg((BYTE)MAADR6, AppConfig.MyMACAddr.v[5]);
  313.  
  314.     // Get the Rev ID so that we can implement the correct errata workarounds
  315.     ENCRevID = ReadETHReg((BYTE)EREVID).Val;
  316.  
  317.     // Disable half duplex loopback in PHY.  Bank bits changed to Bank 2 as a
  318.     // side effect.
  319.     WritePHYReg(PHCON2, PHCON2_HDLDIS);
  320.  
  321.     // Configure LEDA to display LINK status, LEDB to display TX/RX activity
  322.     SetLEDConfig(0x0472);
  323.    
  324.     // Set the MAC and PHY into the proper duplex state
  325. #if defined(FULL_DUPLEX)
  326.     MACSetDuplex(FULL);     // Function exits with Bank 2 selected
  327. #elif defined(HALF_DUPLEX)
  328.     MACSetDuplex(HALF);     // Function exits with Bank 2 selected
  329. #else
  330.     // Use the external LEDB polarity to determine weather full or half duplex
  331.     // communication mode should be set.  
  332.     MACSetDuplex(USE_PHY);  // Function exits with Bank 2 selected
  333. #endif
  334.  
  335.     // Enable packet reception
  336.     BFSReg(ECON1, ECON1_RXEN);
  337. }//end MACInit
  338.  
  339.  
  340. /******************************************************************************
  341.  * Function:        BOOL MACIsLinked(void)
  342.  *
  343.  * PreCondition:    None
  344.  *
  345.  * Input:           None
  346.  *
  347.  * Output:          TRUE: If the PHY reports that a link partner is present
  348.  *                        and the link has been up continuously since the last
  349.  *                        call to MACIsLinked()
  350.  *                  FALSE: If the PHY reports no link partner, or the link went
  351.  *                         down momentarily since the last call to MACIsLinked()
  352.  *
  353.  * Side Effects:    None
  354.  *
  355.  * Overview:        Returns the PHSTAT1.LLSTAT bit.
  356.  *
  357.  * Note:            None
  358.  *****************************************************************************/
  359. BOOL MACIsLinked(void)
  360. {
  361.     // LLSTAT is a latching low link status bit.  Therefore, if the link
  362.     // goes down and comes back up before a higher level stack program calls
  363.     // MACIsLinked(), MACIsLinked() will still return FALSE.  The next
  364.     // call to MACIsLinked() will return TRUE (unless the link goes down
  365.     // again).
  366.     return ReadPHYReg(PHSTAT1).PHSTAT1bits.LLSTAT;
  367. }
  368.  
  369.  
  370. /******************************************************************************
  371.  * Function:        BOOL MACIsTxReady(BOOL HighPriority)
  372.  *
  373.  * PreCondition:    None
  374.  *
  375.  * Input:           HighPriority: TRUE: Check the hardware ECON1.TXRTS bit
  376.  *                                FALSE: Check if a TX buffer is free
  377.  *
  378.  * Output:          TRUE: If no Ethernet transmission is in progress
  379.  *                  FALSE: If a previous transmission was started, and it has
  380.  *                         not completed yet.  While FALSE, the data in the
  381.  *                         transmit buffer and the TXST/TXND pointers must not
  382.  *                         be changed.
  383.  *
  384.  * Side Effects:    None
  385.  *
  386.  * Overview:        Returns the ECON1.TXRTS bit
  387.  *
  388.  * Note:            None
  389.  *****************************************************************************/
  390. BOOL MACIsTxReady(BOOL HighPriority)
  391. {
  392. #if MAC_TX_BUFFER_COUNT > 1
  393.     BUFFER i;
  394.  
  395.     if(HighPriority)
  396. #endif
  397.     {
  398.         return !ReadETHReg(ECON1).ECON1bits.TXRTS;
  399.     }
  400.  
  401. #if MAC_TX_BUFFER_COUNT > 1
  402.  
  403.     // Check if the current buffer can be modified.  It cannot be modified if
  404.     // the TX hardware is currently transmitting it.
  405.     if(CurrentTxBuffer == LastTXedBuffer)
  406.     {
  407.         return !ReadETHReg(ECON1).ECON1bits.TXRTS;
  408.     }
  409.  
  410.     // Check if a buffer is available for a new packet
  411.     for(i = 1; i < MAC_TX_BUFFER_COUNT; i++)
  412.     {
  413.         if(TxBuffers[i].Flags.bFree)
  414.         {
  415.             return TRUE;
  416.         }
  417.     }
  418.  
  419.     return FALSE;
  420. #endif
  421. }
  422.  
  423.  
  424. BUFFER MACGetTxBuffer(BOOL HighPriority)
  425. {
  426. #if MAC_TX_BUFFER_COUNT > 1
  427.     BUFFER i;
  428.  
  429.     if(HighPriority)
  430. #endif
  431.     {
  432.         return !ReadETHReg(ECON1).ECON1bits.TXRTS ? 0 : INVALID_BUFFER;
  433.     }
  434.    
  435. #if MAC_TX_BUFFER_COUNT > 1
  436.     // Find a free buffer.  Do not use buffer 0, it is reserved for
  437.     // high priority messages that don't need to be acknowledged
  438.     // before being discarded (TCP control packets, all ICMP
  439.     // packets, all UDP packets, etc.)
  440.     for(i = 1; i < MAC_TX_BUFFER_COUNT; i++)
  441.     {
  442.         // If this buffer is free, then mark it as used and return with it
  443.         if(TxBuffers[i].Flags.bFree)
  444.         {
  445.             TxBuffers[i].Flags.bFree = FALSE;
  446.             TxBuffers[i].Flags.bTransmitted = FALSE;
  447.             return i;
  448.         }
  449.     }
  450.  
  451.     return INVALID_BUFFER;
  452. #endif
  453. }
  454.  
  455.  
  456. void MACDiscardTx(BUFFER buffer)
  457. {
  458. #if MAC_TX_BUFFER_COUNT > 1
  459.     if(buffer < sizeof(TxBuffers)/sizeof(TxBuffers[0]))
  460.     {
  461.         TxBuffers[buffer].Flags.bFree = TRUE;
  462.         CurrentTxBuffer = buffer;
  463.     }
  464. #endif
  465. }
  466.  
  467.  
  468. /******************************************************************************
  469.  * Function:        void MACDiscardRx(void)
  470.  *
  471.  * PreCondition:    None
  472.  *
  473.  * Input:           None
  474.  *
  475.  * Output:          None
  476.  *
  477.  * Side Effects:    None
  478.  *
  479.  * Overview:        Marks the last received packet (obtained using
  480.  *                  MACGetHeader())as being processed and frees the buffer
  481.  *                  memory associated with it
  482.  *
  483.  * Note:            None
  484.  *****************************************************************************/
  485. void MACDiscardRx(void)
  486. {
  487.     WORD_VAL NewRXRDLocation;
  488.  
  489.     // Make sure the current packet was not already discarded
  490.     if( WasDiscarded )
  491.         return;
  492.     WasDiscarded = TRUE;
  493.    
  494.     // Decrement the next packet pointer before writing it into
  495.     // the ERXRDPT registers.  This is a silicon errata workaround.
  496.     // RX buffer wrapping must be taken into account if the
  497.     // NextPacketLocation is precisely RXSTART.
  498.     NewRXRDLocation.Val = NextPacketLocation.Val - 1;
  499. #if RXSTART == 0
  500.     if(NewRXRDLocation.Val > RXSTOP)
  501. #else
  502.     if(NewRXRDLocation.Val < RXSTART || NewRXRDLocation.Val > RXSTOP)
  503. #endif
  504.     {
  505.         NewRXRDLocation.Val = RXSTOP;
  506.     }
  507.  
  508.     // Decrement the RX packet counter register, EPKTCNT
  509.     BFSReg(ECON2, ECON2_PKTDEC);
  510.  
  511.     // Move the receive read pointer to unwrite-protect the memory used by the
  512.     // last packet.  The writing order is important: set the low byte first,
  513.     // high byte last.
  514.     BankSel(ERXRDPTL);
  515.     WriteReg(ERXRDPTL, NewRXRDLocation.v[0]);
  516.     WriteReg(ERXRDPTH, NewRXRDLocation.v[1]);
  517. }
  518.  
  519.  
  520. /******************************************************************************
  521.  * Function:        WORD MACGetFreeRxSize(void)
  522.  *
  523.  * PreCondition:    None
  524.  *
  525.  * Input:           None
  526.  *
  527.  * Output:          A WORD estimate of how much RX buffer space is free at
  528.  *                  the present time.
  529.  *
  530.  * Side Effects:    None
  531.  *
  532.  * Overview:        None
  533.  *
  534.  * Note:            None
  535.  *****************************************************************************/
  536. WORD MACGetFreeRxSize(void)
  537. {
  538.     WORD_VAL ReadPT, WritePT;
  539.  
  540.     // Read the Ethernet hardware buffer write pointer.  Because packets can be
  541.     // received at any time, it can change between reading the low and high
  542.     // bytes.  A loop is necessary to make certain a proper low/high byte pair
  543.     // is read.
  544.     BankSel(EPKTCNT);
  545.     do {
  546.         // Save EPKTCNT in a temporary location
  547.         ReadPT.v[0] = ReadETHReg((BYTE)EPKTCNT).Val;
  548.    
  549.         BankSel(ERXWRPTL);
  550.         WritePT.v[0] = ReadETHReg(ERXWRPTL).Val;
  551.         WritePT.v[1] = ReadETHReg(ERXWRPTH).Val;
  552.    
  553.         BankSel(EPKTCNT);
  554.     } while(ReadETHReg((BYTE)EPKTCNT).Val != ReadPT.v[0]);
  555.    
  556.     // Determine where the write protection pointer is
  557.     BankSel(ERXRDPTL);
  558.     ReadPT.v[0] = ReadETHReg(ERXRDPTL).Val;
  559.     ReadPT.v[1] = ReadETHReg(ERXRDPTH).Val;
  560.    
  561.     // Calculate the difference between the pointers, taking care to account
  562.     // for buffer wrapping conditions
  563.     if ( WritePT.Val > ReadPT.Val )
  564.     {
  565.         return (RXSTOP - RXSTART) - (WritePT.Val - ReadPT.Val);
  566.     }
  567.     else if ( WritePT.Val == ReadPT.Val )
  568.     {
  569.         return RXSIZE - 1;
  570.     }
  571.     else
  572.     {
  573.         return ReadPT.Val - WritePT.Val - 1;
  574.     }
  575. }
  576.  
  577. /******************************************************************************
  578.  * Function:        BOOL MACGetHeader(MAC_ADDR *remote, BYTE* type)
  579.  *
  580.  * PreCondition:    None
  581.  *
  582.  * Input:           *remote: Location to store the Source MAC address of the
  583.  *                           received frame.
  584.  *                  *type: Location of a BYTE to store the constant
  585.  *                         MAC_UNKNOWN, ETHER_IP, or ETHER_ARP, representing
  586.  *                         the contents of the Ethernet type field.
  587.  *
  588.  * Output:          TRUE: If a packet was waiting in the RX buffer.  The
  589.  *                        remote, and type values are updated.
  590.  *                  FALSE: If a packet was not pending.  remote and type are
  591.  *                         not changed.
  592.  *
  593.  * Side Effects:    Last packet is discarded if MACDiscardRx() hasn't already
  594.  *                  been called.
  595.  *
  596.  * Overview:        None
  597.  *
  598.  * Note:            None
  599.  *****************************************************************************/
  600. BOOL MACGetHeader(MAC_ADDR *remote, BYTE* type)
  601. {
  602.     ENC_PREAMBLE header;
  603.  
  604.     // Test if at least one packet has been received and is waiting
  605.     BankSel(EPKTCNT);
  606.     if(ReadETHReg((BYTE)EPKTCNT).Val == 0)
  607.         return FALSE;  
  608.  
  609.     // Make absolutely certain that any previous packet was discarded
  610.     if(WasDiscarded == FALSE)
  611.     {
  612.         MACDiscardRx();
  613.         return FALSE;
  614.     }
  615.  
  616.     // Save the location of this packet
  617.     CurrentPacketLocation.Val = NextPacketLocation.Val;
  618.  
  619.     // Set the SPI read pointer to the beginning of the next unprocessed packet
  620.     BankSel(ERDPTL);
  621.     WriteReg(ERDPTL, NextPacketLocation.v[0]);
  622.     WriteReg(ERDPTH, NextPacketLocation.v[1]);
  623.  
  624.     // Obtain the MAC header from the Ethernet buffer
  625.     MACGetArray((BYTE*)&header, sizeof(header));
  626.  
  627.     // The EtherType field, like most items transmitted on the Ethernet medium
  628.     // are in big endian.
  629.     header.Type.Val = swaps(header.Type.Val);
  630.  
  631.     // Validate the data returned from the ENC28J60.  Random data corruption,
  632.     // such as if a single SPI bit error occurs while communicating or a
  633.     // momentary power glitch could cause this to occur in rare circumstances.
  634.     if(header.NextPacketPointer > RXSTOP || ((BYTE_VAL*)(&header.NextPacketPointer))->bits.b0 ||
  635.        header.StatusVector.bits.Zero ||
  636.        header.StatusVector.bits.CRCError ||
  637.        header.StatusVector.bits.ByteCount > 1518 ||
  638.        !header.StatusVector.bits.ReceiveOk)
  639.     {
  640.         Reset();
  641.     }
  642.  
  643.     // Save the location where the hardware will write the next packet to
  644.     NextPacketLocation.Val = header.NextPacketPointer;
  645.  
  646.     // Return the Ethernet frame's Source MAC address field to the caller
  647.     // This parameter is useful for replying to requests without requiring an
  648.     // ARP cycle.
  649.     memcpy((void*)remote->v, (void*)header.SourceMACAddr.v, sizeof(*remote));
  650.  
  651.     // Return a simplified version of the EtherType field to the caller
  652.     *type = MAC_UNKNOWN;
  653.     if( (header.Type.v[1] == 0x08u) &&
  654.         ((header.Type.v[0] == ETHER_IP) || (header.Type.v[0] == ETHER_ARP)) )
  655.     {
  656.         *type = header.Type.v[0];
  657.     }
  658.  
  659.     // Mark this packet as discardable
  660.     WasDiscarded = FALSE;  
  661.     return TRUE;
  662. }
  663.  
  664.  
  665. /******************************************************************************
  666.  * Function:        void    MACPutHeader(MAC_ADDR *remote,
  667.  *                                       BYTE type,
  668.  *                                       WORD dataLen)
  669.  *
  670.  * PreCondition:    MACIsTxReady() must return TRUE.
  671.  *
  672.  * Input:           *remote: Pointer to memory which contains the destination
  673.  *                           MAC address (6 bytes)
  674.  *                  type: The constant ETHER_ARP or ETHER_IP, defining which
  675.  *                        value to write into the Ethernet header's type field.
  676.  *                  dataLen: Length of the Ethernet data payload
  677.  *
  678.  * Output:          None
  679.  *
  680.  * Side Effects:    None
  681.  *
  682.  * Overview:        None
  683.  *
  684.  * Note:            Because of the dataLen parameter, it is probably
  685.  *                  advantagous to call this function immediately before
  686.  *                  transmitting a packet rather than initially when the
  687.  *                  packet is first created.  The order in which the packet
  688.  *                  is constructed (header first or data first) is not
  689.  *                  important.
  690.  *****************************************************************************/
  691. void    MACPutHeader(MAC_ADDR *remote,
  692.                      BYTE type,
  693.                      WORD dataLen)
  694. {
  695.  
  696.     BankSel(EWRPTL);
  697.  
  698. #if MAC_TX_BUFFER_COUNT > 1
  699.     // Set the SPI write pointer to the beginning of the transmit buffer
  700.     WriteReg(EWRPTL, TxBuffers[CurrentTxBuffer].StartAddress.v[0]);
  701.     WriteReg(EWRPTH, TxBuffers[CurrentTxBuffer].StartAddress.v[1]);
  702.  
  703.     // Calculate where to put the TXND pointer
  704.     dataLen += (WORD)sizeof(ETHER_HEADER) + TxBuffers[CurrentTxBuffer].StartAddress.Val;
  705.     TxBuffers[CurrentTxBuffer].EndAddress.Val = dataLen;
  706. #else
  707.     // Set the SPI write pointer to the beginning of the transmit buffer
  708.     WriteReg(EWRPTL, LOW(TXSTART));
  709.     WriteReg(EWRPTH, HIGH(TXSTART));
  710.  
  711.     // Calculate where to put the TXND pointer
  712.     dataLen += (WORD)sizeof(ETHER_HEADER) + TXSTART;
  713.  
  714.     // Write the TXND pointer into the registers, given the dataLen given
  715.     WriteReg(ETXNDL, ((WORD_VAL*)&dataLen)->v[0]);
  716.     WriteReg(ETXNDH, ((WORD_VAL*)&dataLen)->v[1]);
  717. #endif
  718.  
  719.  
  720.     // Set the per-packet control byte and write the Ethernet destination
  721.     // address
  722.     MACPut(0x00);   // Use default control configuration
  723.     MACPutArray((BYTE*)remote, sizeof(*remote));
  724.  
  725.     // Write our MAC address in the Ethernet source field
  726.     MACPutArray((BYTE*)&AppConfig.MyMACAddr, sizeof(AppConfig.MyMACAddr));
  727.  
  728.     // Write the appropriate Ethernet Type WORD for the protocol being used
  729.     MACPut(0x08);
  730.     MACPut((type == MAC_IP) ? ETHER_IP : ETHER_ARP);
  731. }
  732.  
  733. /******************************************************************************
  734.  * Function:        void MACFlush(void)
  735.  *
  736.  * PreCondition:    A packet has been created by calling MACPut() and
  737.  *                  MACPutHeader().
  738.  *
  739.  * Input:           None
  740.  *
  741.  * Output:          None
  742.  *
  743.  * Side Effects:    None
  744.  *
  745.  * Overview:        MACFlush causes the current TX packet to be sent out on
  746.  *                  the Ethernet medium.  The hardware MAC will take control
  747.  *                  and handle CRC generation, collision retransmission and
  748.  *                  other details.
  749.  *
  750.  * Note:            After transmission completes (MACIsTxReady() returns TRUE),
  751.  *                  the packet can be modified and transmitted again by calling
  752.  *                  MACFlush() again.  Until MACPutHeader() or MACPut() is
  753.  *                  called (in the TX data area), the data in the TX buffer
  754.  *                  will not be corrupted.
  755.  *****************************************************************************/
  756. void MACFlush(void)
  757. {
  758. #if MAC_TX_BUFFER_COUNT > 1
  759.     // Set the packet start and end address pointers
  760.     BankSel(ETXSTL);
  761.     WriteReg(ETXSTL, TxBuffers[CurrentTxBuffer].StartAddress.v[0]);
  762.     WriteReg(ETXSTH, TxBuffers[CurrentTxBuffer].StartAddress.v[1]);
  763.     WriteReg(ETXNDL, TxBuffers[CurrentTxBuffer].EndAddress.v[0]);
  764.     WriteReg(ETXNDH, TxBuffers[CurrentTxBuffer].EndAddress.v[1]);
  765.     LastTXedBuffer = CurrentTxBuffer;
  766.     TxBuffers[CurrentTxBuffer].Flags.bTransmitted = TRUE;
  767. #endif
  768.  
  769.     // Reset transmit logic if a TX Error has previously occured
  770.     // This is a silicon errata workaround
  771.     if(ReadETHReg(EIR).EIRbits.TXERIF)
  772.     {
  773.         BFSReg(ECON1, ECON1_TXRST);
  774.         BFCReg(ECON1, ECON1_TXRST);
  775.     }
  776.     BFCReg(EIR, EIR_TXERIF | EIR_TXIF);
  777.  
  778.     // Start the transmission
  779.     // After transmission completes (MACIsTxReady() returns TRUE), the packet
  780.     // can be modified and transmitted again by calling MACFlush() again.
  781.     // Until MACPutHeader() is called, the data in the TX buffer will not be
  782.     // corrupted.
  783.     BFSReg(ECON1, ECON1_TXRTS);
  784.  
  785.     // Revision B5 silicon errata workaround
  786.     if(ENCRevID == 0x05)
  787.     {
  788.         while(!(ReadETHReg(EIR).Val & (EIR_TXERIF | EIR_TXIF)));
  789.         if(ReadETHReg(EIR).EIRbits.TXERIF)
  790.         {
  791.             WORD_VAL ReadPtrSave;
  792.             WORD_VAL TXEnd;
  793.             TXSTATUS TXStatus;
  794.             BYTE i;
  795.            
  796.             // Cancel the previous transmission if it has become stuck set
  797.             BFCReg(ECON1, ECON1_TXRTS);
  798.  
  799.             // Save the current read pointer (controlled by application)
  800.             BankSel(ERDPTL);
  801.             ReadPtrSave.v[0] = ReadETHReg(ERDPTL).Val;
  802.             ReadPtrSave.v[1] = ReadETHReg(ERDPTH).Val;
  803.  
  804.             // Get the location of the transmit status vector
  805.             TXEnd.v[0] = ReadETHReg(ETXNDL).Val;
  806.             TXEnd.v[1] = ReadETHReg(ETXNDH).Val;
  807.             TXEnd.Val++;
  808.            
  809.             // Read the transmit status vector
  810.             WriteReg(ERDPTL, TXEnd.v[0]);
  811.             WriteReg(ERDPTH, TXEnd.v[1]);
  812.             MACGetArray((BYTE*)&TXStatus, sizeof(TXStatus));
  813.  
  814.             // Implement retransmission if a late collision occured (this can
  815.             // happen on B5 when certain link pulses arrive at the same time
  816.             // as the transmission)
  817.             for(i = 0; i < 16; i++)
  818.             {
  819.                 if(ReadETHReg(EIR).EIRbits.TXERIF && TXStatus.bits.LateCollision)
  820.                 {
  821.                     // Reset the TX logic
  822.                     BFSReg(ECON1, ECON1_TXRST);
  823.                     BFCReg(ECON1, ECON1_TXRST);
  824.                     BFCReg(EIR, EIR_TXERIF | EIR_TXIF);
  825.  
  826.                     // Transmit the packet again
  827.                     BFSReg(ECON1, ECON1_TXRTS);
  828.                     while(!(ReadETHReg(EIR).Val & (EIR_TXERIF | EIR_TXIF)));
  829.  
  830.                     // Cancel the previous transmission if it has become stuck set
  831.                     BFCReg(ECON1, ECON1_TXRTS);
  832.  
  833.                     // Read transmit status vector
  834.                     WriteReg(ERDPTL, TXEnd.v[0]);
  835.                     WriteReg(ERDPTH, TXEnd.v[1]);
  836.                     MACGetArray((BYTE*)&TXStatus, sizeof(TXStatus));
  837.                 }
  838.                 else
  839.                 {
  840.                     break;
  841.                 }
  842.             }
  843.  
  844.             // Restore the current read pointer
  845.             WriteReg(ERDPTL, ReadPtrSave.v[0]);
  846.             WriteReg(ERDPTH, ReadPtrSave.v[1]);
  847.         }
  848.     }
  849. }
  850.  
  851.  
  852. /******************************************************************************
  853.  * Function:        void MACSetRxBuffer(WORD offset)
  854.  *
  855.  * PreCondition:    A packet has been obtained by calling MACGetHeader() and
  856.  *                  getting a TRUE result.
  857.  *
  858.  * Input:           offset: WORD specifying how many bytes beyond the Ethernet
  859.  *                          header's type field to relocate the SPI read and
  860.  *                          write pointers.
  861.  *
  862.  * Output:          None
  863.  *
  864.  * Side Effects:    None
  865.  *
  866.  * Overview:        SPI read and write pointers are updated.  All calls to
  867.  *                  MACGet(), MACPut(), MACGetArray(), and MACPutArray(),
  868.  *                  and various other functions will use these new values.
  869.  *
  870.  * Note:            RXSTOP must be statically defined as being > RXSTART for
  871.  *                  this function to work correctly.  In other words, do not
  872.  *                  define an RX buffer which spans the 0x1FFF->0x0000 memory
  873.  *                  boundary.
  874.  *****************************************************************************/
  875. void MACSetRxBuffer(WORD offset)
  876. {
  877.     WORD_VAL ReadPT;
  878.  
  879.     // Determine the address of the beginning of the entire packet
  880.     // and adjust the address to the desired location
  881.     ReadPT.Val = CurrentPacketLocation.Val + sizeof(ENC_PREAMBLE) + offset;
  882.    
  883.     // Since the receive buffer is circular, adjust if a wraparound is needed
  884.     if ( ReadPT.Val > RXSTOP )
  885.         ReadPT.Val -= RXSIZE;
  886.    
  887.     // Set the SPI read and write pointers to the new calculated value
  888.     BankSel(ERDPTL);
  889.     WriteReg(ERDPTL, ReadPT.v[0]);
  890.     WriteReg(ERDPTH, ReadPT.v[1]);
  891.     WriteReg(EWRPTL, ReadPT.v[0]);
  892.     WriteReg(EWRPTH, ReadPT.v[1]);
  893. }
  894.  
  895.  
  896. /******************************************************************************
  897.  * Function:        void MACSetTxBuffer(BUFFER buffer, WORD offset)
  898.  *
  899.  * PreCondition:    None
  900.  *
  901.  * Input:           buffer: BYTE specifying which transmit buffer to seek
  902.  *                          within.  If MAC_TX_BUFFER_COUNT <= 1, this
  903.  *                          parameter is not used.
  904.  *                  offset: WORD specifying how many bytes beyond the Ethernet
  905.  *                          header's type field to relocate the SPI read and
  906.  *                          write pointers.
  907.  *
  908.  * Output:          None
  909.  *
  910.  * Side Effects:    None
  911.  *
  912.  * Overview:        SPI read and write pointers are updated.  All calls to
  913.  *                  MACGet(), MACPut(), MACGetArray(), and MACPutArray(),
  914.  *                  and various other functions will use these new values.
  915.  *
  916.  * Note:            None
  917.  *****************************************************************************/
  918. void MACSetTxBuffer(BUFFER buffer, WORD offset)
  919. {
  920.     CurrentTxBuffer = buffer;
  921.  
  922.     // Calculate the proper address.  Since the TX memory area is not circular,
  923.     // no wrapparound checks are necessary. +1 adjustment is needed because of
  924.     // the per packet control byte which preceeds the packet in the TX memory
  925.     // area.
  926. #if MAC_TX_BUFFER_COUNT > 1
  927.     offset += TxBuffers[buffer].StartAddress.Val + 1 + sizeof(ETHER_HEADER);
  928. #else
  929.     offset += TXSTART + 1 + sizeof(ETHER_HEADER);
  930. #endif
  931.  
  932.     // Set the SPI read and write pointers to the new calculated value
  933.     BankSel(EWRPTL);
  934.     WriteReg(ERDPTL, ((WORD_VAL*)&offset)->v[0]);
  935.     WriteReg(ERDPTH, ((WORD_VAL*)&offset)->v[1]);
  936.     WriteReg(EWRPTL, ((WORD_VAL*)&offset)->v[0]);
  937.     WriteReg(EWRPTH, ((WORD_VAL*)&offset)->v[1]);
  938. }
  939.  
  940.  
  941. // MACCalcRxChecksum() and MACCalcTxChecksum() use the DMA module to calculate
  942. // checksums.  These two functions have been tested.
  943. /******************************************************************************
  944.  * Function:        WORD MACCalcRxChecksum(WORD offset, WORD len)
  945.  *
  946.  * PreCondition:    None
  947.  *
  948.  * Input:           offset  - Number of bytes beyond the beginning of the
  949.  *                          Ethernet data (first byte after the type field)
  950.  *                          where the checksum should begin
  951.  *                  len     - Total number of bytes to include in the checksum
  952.  *
  953.  * Output:          16-bit checksum as defined by rfc 793.
  954.  *
  955.  * Side Effects:    None
  956.  *
  957.  * Overview:        This function performs a checksum calculation in the MAC
  958.  *                  buffer itself using the hardware DMA module
  959.  *
  960.  * Note:            None
  961.  *****************************************************************************/
  962. WORD MACCalcRxChecksum(WORD offset, WORD len)
  963. {
  964.     WORD_VAL temp;
  965.  
  966.     // Add the offset requested by firmware plus the Ethernet header
  967.     temp.Val = CurrentPacketLocation.Val + sizeof(ENC_PREAMBLE) + offset;
  968.     if ( temp.Val > RXSTOP )        // Adjust value if a wrap is needed
  969.     {
  970.         temp.Val -= RXSIZE;
  971.     }
  972.     // Program the start address of the DMA
  973.     BankSel(EDMASTL);
  974.     WriteReg(EDMASTL, temp.v[0]);
  975.     WriteReg(EDMASTH, temp.v[1]);
  976.  
  977.     // Calculate the end address, given the start address and len
  978.     temp.Val += len-1;
  979.     if ( temp.Val > RXSTOP )        // Adjust value if a wrap is needed
  980.     {
  981.         temp.Val -= RXSIZE;
  982.     }
  983.     // Program the end address of the DMA
  984.     WriteReg(EDMANDL, temp.v[0]);
  985.     WriteReg(EDMANDH, temp.v[1]);
  986.    
  987.     // Calculate the checksum using the DMA device
  988.     BFSReg(ECON1, ECON1_DMAST | ECON1_CSUMEN);
  989.     while(ReadETHReg(ECON1).ECON1bits.DMAST);
  990.  
  991.     // Swap endianness and return
  992.     temp.v[1] = ReadETHReg(EDMACSL).Val;
  993.     temp.v[0] = ReadETHReg(EDMACSH).Val;
  994.  
  995.     return temp.Val;
  996. }
  997.  
  998.  
  999. /******************************************************************************
  1000.  * Function:        WORD MACCalcTxChecksum(WORD offset, WORD len)
  1001.  *
  1002.  * PreCondition:    None
  1003.  *
  1004.  * Input:           offset  - Number of bytes beyond the beginning of the
  1005.  *                          Ethernet data (first byte after the type field)
  1006.  *                          where the checksum should begin
  1007.  *                  len     - Total number of bytes to include in the checksum
  1008.  *
  1009.  * Output:          16-bit checksum as defined by rfc 793.
  1010.  *
  1011.  * Side Effects:    None
  1012.  *
  1013.  * Overview:        This function performs a checksum calculation in the MAC
  1014.  *                  buffer itself using the hardware DMA module
  1015.  *
  1016.  * Note:            None
  1017.  *****************************************************************************/
  1018. WORD MACCalcTxChecksum(WORD offset, WORD len)
  1019. {
  1020.     WORD_VAL temp;
  1021.  
  1022.     // Program the start address of the DMA, after adjusting for the Ethernet
  1023.     // header
  1024. #if MAC_TX_BUFFER_COUNT > 1
  1025.     temp.Val = TxBuffers[CurrentTxBuffer].StartAddress.Val + sizeof(ETHER_HEADER)
  1026.                 + offset + 1;   // +1 needed to account for per packet control byte
  1027. #else
  1028.     temp.Val = TXSTART + sizeof(ETHER_HEADER)
  1029.                 + offset + 1;   // +1 needed to account for per packet control byte
  1030. #endif
  1031.     BankSel(EDMASTL);
  1032.     WriteReg(EDMASTL, temp.v[0]);
  1033.     WriteReg(EDMASTH, temp.v[1]);
  1034.    
  1035.     // Program the end address of the DMA.
  1036.     temp.Val += len-1;
  1037.     WriteReg(EDMANDL, temp.v[0]);
  1038.     WriteReg(EDMANDH, temp.v[1]);
  1039.    
  1040.     // Calcualte the checksum using the DMA device
  1041.     BFSReg(ECON1, ECON1_DMAST | ECON1_CSUMEN);
  1042.     while(ReadETHReg(ECON1).ECON1bits.DMAST);
  1043.  
  1044.     // Swap endianness and return
  1045.     temp.v[1] = ReadETHReg(EDMACSL).Val;
  1046.     temp.v[0] = ReadETHReg(EDMACSH).Val;
  1047.  
  1048.     return temp.Val;
  1049. }
  1050.  
  1051.  
  1052. /******************************************************************************
  1053.  * Function:        WORD CalcIPBufferChecksum(WORD len)
  1054.  *
  1055.  * PreCondition:    Read buffer pointer set to starting of checksum data
  1056.  *
  1057.  * Input:           len: Total number of bytes to calculate the checksum over.
  1058.  *                       The first byte included in the checksum is the byte
  1059.  *                       pointed to by ERDPT, which is updated by calls to
  1060.  *                       MACGet(), MACSetRxBuffer(), MACSetTxBuffer(), etc.
  1061.  *
  1062.  * Output:          16-bit checksum as defined by rfc 793.
  1063.  *
  1064.  * Side Effects:    None
  1065.  *
  1066.  * Overview:        This function performs a checksum calculation in the MAC
  1067.  *                  buffer itself.  The ENC28J60 has a hardware DMA module
  1068.  *                  which can calculate the checksum faster than software, so
  1069.  *                  this function replaces the CaclIPBufferChecksum() function
  1070.  *                  defined in the helpers.c file.  Through the use of
  1071.  *                  preprocessor defines, this replacement is automatic.
  1072.  *
  1073.  * Note:            This function works either in the RX buffer area or the TX
  1074.  *                  buffer area.  No validation is done on the len parameter.
  1075.  *****************************************************************************/
  1076. WORD CalcIPBufferChecksum(WORD len)
  1077. {
  1078.     WORD_VAL temp;
  1079.  
  1080.     // Take care of special cases which the DMA cannot be used for
  1081.     if(len == 0u)
  1082.     {
  1083.         return 0xFFFF;
  1084.     }
  1085.     else if(len == 1u)
  1086.     {
  1087.         return ~(((WORD)MACGet())<<8);
  1088.     }
  1089.        
  1090.  
  1091.     // Set the DMA starting address to the SPI read pointer value
  1092.     BankSel(ERDPTL);
  1093.     temp.v[0] = ReadETHReg(ERDPTL).Val;
  1094.     temp.v[1] = ReadETHReg(ERDPTH).Val;
  1095.     WriteReg(EDMASTL, temp.v[0]);
  1096.     WriteReg(EDMASTH, temp.v[1]);
  1097.    
  1098.     // See if we are calculating a checksum within the RX buffer (where
  1099.     // wrapping rules apply) or TX/unused area (where wrapping rules are
  1100.     // not applied)
  1101. #if RXSTART == 0
  1102.     if(temp.Val <= RXSTOP)
  1103. #else
  1104.     if(temp.Val >= RXSTART && temp.Val <= RXSTOP)
  1105. #endif
  1106.     {
  1107.         // Calculate the DMA ending address given the starting address and len
  1108.         // parameter.  The DMA will follow the receive buffer wrapping boundary.
  1109.         temp.Val += len-1;
  1110.         if(temp.Val > RXSTOP)
  1111.         {
  1112.             temp.Val -= RXSIZE;
  1113.         }
  1114.     }
  1115.     else
  1116.     {
  1117.         temp.Val += len-1;
  1118.     }  
  1119.  
  1120.     // Write the DMA end address
  1121.     WriteReg(EDMANDL, temp.v[0]);
  1122.     WriteReg(EDMANDH, temp.v[1]);
  1123.    
  1124.     // Begin the DMA checksum calculation and wait until it is finished
  1125.     BFSReg(ECON1, ECON1_DMAST | ECON1_CSUMEN);
  1126.     while(ReadETHReg(ECON1).ECON1bits.DMAST);
  1127.  
  1128.     // Return the resulting good stuff
  1129.     temp.v[0] = ReadETHReg(EDMACSL).Val;
  1130.     temp.v[1] = ReadETHReg(EDMACSH).Val;
  1131.     return temp.Val;
  1132. }
  1133.  
  1134.  
  1135. /******************************************************************************
  1136.  * Function:        void MACCopyRxToTx(WORD RxOffset, WORD TxOffset, WORD len)
  1137.  *
  1138.  * PreCondition:    None
  1139.  *
  1140.  * Input:           RxOffset: Offset in the RX buffer (0=first byte of
  1141.  *                            destination MAC address) to copy from.
  1142.  *                  TxOffset: Offset in the TX buffer (0=first byte of
  1143.  *                            destination MAC address) to copy to.
  1144.  *                  len:      Number of bytes to copy
  1145.  *
  1146.  * Output:          None
  1147.  *
  1148.  * Side Effects:    None
  1149.  *
  1150.  * Overview:        If the TX logic is transmitting a packet (ECON1.TXRTS is
  1151.  *                  set), the hardware will wait until it is finished.  Then,
  1152.  *                  the DMA module will copy the data from the receive buffer
  1153.  *                  to the transmit buffer.
  1154.  *
  1155.  * Note:            None
  1156.  *****************************************************************************/
  1157. // Remove this line if your application needs to use this
  1158. // function.  This code has NOT been tested.
  1159. #if 0
  1160. void MACCopyRxToTx(WORD RxOffset, WORD TxOffset, WORD len)
  1161. {
  1162.     WORD_VAL temp;
  1163.  
  1164.     temp.Val = CurrentPacketLocation.Val + RxOffset + sizeof(ENC_PREAMBLE);
  1165.     if ( temp.Val > RXSTOP )        // Adjust value if a wrap is needed
  1166.         temp.Val -= RXSIZE;
  1167.  
  1168.     BankSel(EDMASTL);
  1169.     WriteReg(EDMASTL, temp.v[0]);
  1170.     WriteReg(EDMASTH, temp.v[1]);
  1171.  
  1172.     temp.Val += len-1;
  1173.     if ( temp.Val > RXSTOP )        // Adjust value if a wrap is needed
  1174.         temp.Val -= RXSIZE;
  1175.  
  1176.     WriteReg(EDMANDL, temp.v[0]);
  1177.     WriteReg(EDMANDH, temp.v[1]);
  1178.    
  1179.     TxOffset += TXSTART+1;
  1180.     WriteReg(EDMADSTL, ((WORD_VAL*)&TxOffset)->v[0]);
  1181.     WriteReg(EDMADSTH, ((WORD_VAL*)&TxOffset)->v[1]);
  1182.    
  1183.     // Do the DMA Copy.  The DMA module will wait for TXRTS to become clear
  1184.     // before starting the copy.
  1185.     BFCReg(ECON1, ECON1_CSUMEN);
  1186.     BFSReg(ECON1, ECON1_DMAST);
  1187.     while(ReadETHReg(ECON1).ECON1bits.DMAST);
  1188. }
  1189. #endif
  1190.  
  1191.  
  1192. #if defined(MAC_FILTER_BROADCASTS)
  1193. // NOTE: This code has NOT been tested.  See StackTsk.h's explanation
  1194. // of MAC_FILTER_BROADCASTS.
  1195. /******************************************************************************
  1196.  * Function:        void MACSetPMFilter(BYTE *Pattern,
  1197.  *                                      BYTE *PatternMask,
  1198.  *                                      WORD PatternOffset)
  1199.  *
  1200.  * PreCondition:    SPI bus must be initialized (done in MACInit()).
  1201.  *                  MACIsTxReady() must return TRUE
  1202.  *
  1203.  * Input:           *Pattern: Pointer to an intial pattern to compare against
  1204.  *                  *PatternMask: Pointer to an 8 byte pattern mask which
  1205.  *                                defines which bytes of the pattern are
  1206.  *                                important.  At least one bit must be set.
  1207.  *                  PatternOffset: Offset from the beginning of the Ethernet
  1208.  *                                 frame (1st byte of destination address), to
  1209.  *                                 begin comparing with the given pattern.
  1210.  *
  1211.  * Output:          None
  1212.  *
  1213.  * Side Effects:    Contents of the TX buffer space are overwritten
  1214.  *
  1215.  * Overview:        MACSetPMFilter sets the hardware receive filters for:
  1216.  *                  CRC AND (Unicast OR Pattern Match).  As a result, only a
  1217.  *                  subset of the broadcast packets which are normally
  1218.  *                  received will be received.
  1219.  *
  1220.  * Note:            None
  1221.  *****************************************************************************/
  1222. void MACSetPMFilter(BYTE *Pattern,
  1223.                     BYTE *PatternMask,
  1224.                     WORD PatternOffset)
  1225. {
  1226.     WORD_VAL i;
  1227.     BYTE *MaskPtr;
  1228.     BYTE UnmaskedPatternLen;
  1229.    
  1230.     // Set the SPI write pointer and DMA startting address to the beginning of
  1231.     // the transmit buffer
  1232.     BankSel(EWRPTL);
  1233.     WriteReg(EWRPTL, LOW(TXSTART));
  1234.     WriteReg(EWRPTH, HIGH(TXSTART));
  1235.     WriteReg(EDMASTL, LOW(TXSTART));
  1236.     WriteReg(EDMASTH, HIGH(TXSTART));
  1237.  
  1238.     // Fill the transmit buffer with the pattern to match against.  Only the
  1239.     // bytes which have a mask bit of 1 are written into the buffer and will
  1240.     // subsequently be used for checksum computation.  
  1241.     MaskPtr = PatternMask;
  1242.     for(i.Val = 0x0100; i.v[0] < 64; i.v[0]++)
  1243.     {
  1244.         if( *MaskPtr & i.v[1] )
  1245.         {
  1246.             MACPut(*Pattern);
  1247.             UnmaskedPatternLen++;
  1248.         }
  1249.         Pattern++;
  1250.        
  1251.         i.v[1] <<= 1;
  1252.         if( i.v[1] == 0u )
  1253.         {
  1254.             i.v[1] = 0x01;
  1255.             MaskPtr++;
  1256.         }
  1257.     }
  1258.  
  1259.     // Calculate and set the DMA end address
  1260.     i.Val = TXSTART + (WORD)UnmaskedPatternLen - 1;
  1261.     WriteReg(EDMANDL, i.v[0]);
  1262.     WriteReg(EDMANDH, i.v[1]);
  1263.  
  1264.     // Calculate the checksum on the given pattern using the DMA module
  1265.     BFSReg(ECON1, ECON1_DMAST | ECON1_CSUMEN);
  1266.     while(ReadETHReg(ECON1).ECON1bits.DMAST);
  1267.  
  1268.     // Make certain that the PM filter isn't enabled while it is
  1269.     // being reconfigured.
  1270.     BankSel(ERXFCON);
  1271.     WriteReg(ERXFCON, ERXFCON_UCEN | ERXFCON_CRCEN | ERXFCON_BCEN);
  1272.  
  1273.     // Get the calculated DMA checksum and store it in the PM
  1274.     // checksum registers
  1275.     i.v[0] == ReadETHReg(EDMACSL).Val;
  1276.     i.v[1] == ReadETHReg(EDMACSH).Val;
  1277.     WriteReg(EPMCSL, i.v[0]);
  1278.     WriteReg(EPMCSH, i.v[0]);
  1279.  
  1280.     // Set the Pattern Match offset and 8 byte mask
  1281.     WriteReg(EPMOL, ((WORD_VAL*)&PatternOffset)->v[0]);
  1282.     WriteReg(EPMOH, ((WORD_VAL*)&PatternOffset)->v[1]);
  1283.     for(i.Val = EPMM0; i.Val <= EPMM7 ; i.Val++)
  1284.     {
  1285.         WriteReg(i.Val, *PatternMask++);
  1286.     }
  1287.  
  1288.     // Begin using the new Pattern Match filter instead of the
  1289.     // broadcast filter
  1290.     WriteReg(ERXFCON, ERXFCON_UCEN | ERXFCON_CRCEN | ERXFCON_PMEN);
  1291. }//end MACSetPMFilter
  1292.  
  1293.  
  1294. /******************************************************************************
  1295.  * Function:        void MACDisablePMFilter(void)
  1296.  *
  1297.  * PreCondition:    SPI bus must be initialized (done in MACInit()).
  1298.  *
  1299.  * Input:           None
  1300.  *
  1301.  * Output:          None
  1302.  *
  1303.  * Side Effects:    None
  1304.  *
  1305.  * Overview:        MACDisablePMFilter disables the Pattern Match receive
  1306.  *                  filter (if enabled) and returns to the default filter
  1307.  *                  configuration of: CRC AND (Unicast OR Broadcast).
  1308.  *
  1309.  * Note:            None
  1310.  *****************************************************************************/
  1311. void MACDisablePMFilter(void)
  1312. {
  1313.     BankSel(ERXFCON);
  1314.     WriteReg(ERXFCON, ERXFCON_UCEN | ERXFCON_CRCEN | ERXFCON_BCEN);
  1315.     return;
  1316. }//end MACDisablePMFilter
  1317. #endif // end of MAC_FILTER_BROADCASTS specific code
  1318.  
  1319.  
  1320. /******************************************************************************
  1321.  * Function:        BYTE MACGet()
  1322.  *
  1323.  * PreCondition:    SPI bus must be initialized (done in MACInit()).
  1324.  *                  ERDPT must point to the place to read from.
  1325.  *
  1326.  * Input:           None
  1327.  *
  1328.  * Output:          Byte read from the ENC28J60's RAM
  1329.  *
  1330.  * Side Effects:    None
  1331.  *
  1332.  * Overview:        MACGet returns the byte pointed to by ERDPT and
  1333.  *                  increments ERDPT so MACGet() can be called again.  The
  1334.  *                  increment will follow the receive buffer wrapping boundary.
  1335.  *
  1336.  * Note:            None
  1337.  *****************************************************************************/
  1338. BYTE MACGet()
  1339. {
  1340.     BYTE Result;
  1341.  
  1342.     ENC_CS_IO = 0;
  1343.     ENC_SPI_IF = 0;
  1344.     ENC_SSPBUF = RBM;
  1345.     while(!ENC_SPI_IF);     // Wait until opcode/address is transmitted.
  1346.     Result = ENC_SSPBUF;
  1347.     ENC_SPI_IF = 0;
  1348.     ENC_SSPBUF = 0;             // Send a dummy byte to receive the register
  1349.                             //   contents.
  1350.     while(!ENC_SPI_IF);     // Wait until register is received.
  1351.     Result = ENC_SSPBUF;
  1352.     ENC_SPI_IF = 0;
  1353.     ENC_CS_IO = 1;
  1354.  
  1355.     return Result;
  1356. }//end MACGet
  1357.  
  1358.  
  1359. /******************************************************************************
  1360.  * Function:        WORD MACGetArray(BYTE *val, WORD len)
  1361.  *
  1362.  * PreCondition:    SPI bus must be initialized (done in MACInit()).
  1363.  *                  ERDPT must point to the place to read from.
  1364.  *
  1365.  * Input:           *val: Pointer to storage location
  1366.  *                  len:  Number of bytes to read from the data buffer.
  1367.  *
  1368.  * Output:          Byte(s) of data read from the data buffer.
  1369.  *
  1370.  * Side Effects:    None
  1371.  *
  1372.  * Overview:        Burst reads several sequential bytes from the data buffer
  1373.  *                  and places them into local memory.  With SPI burst support,
  1374.  *                  it performs much faster than multiple MACGet() calls.
  1375.  *                  ERDPT is incremented after each byte, following the same
  1376.  *                  rules as MACGet().
  1377.  *
  1378.  * Note:            None
  1379.  *****************************************************************************/
  1380. WORD MACGetArray(BYTE *val, WORD len)
  1381. {
  1382.     WORD i;
  1383.     BYTE Dummy;
  1384.  
  1385.     // Start the burst operation
  1386.     ENC_CS_IO = 0;
  1387.     ENC_SPI_IF = 0;
  1388.     ENC_SSPBUF = RBM;           // Send the Read Buffer Memory opcode.
  1389.     i = 0;     
  1390.     val--;
  1391.     while(!ENC_SPI_IF);     // Wait until opcode/address is transmitted.
  1392.     Dummy = ENC_SSPBUF;
  1393.     ENC_SPI_IF = 0;
  1394.  
  1395.     // Read the data
  1396.     while(i<len)
  1397.     {
  1398.         ENC_SSPBUF = 0;         // Send a dummy byte to receive a byte
  1399.         i++;
  1400.         val++;
  1401.         while(!ENC_SPI_IF); // Wait until byte is received.
  1402.         *val = ENC_SSPBUF;
  1403.         ENC_SPI_IF = 0;
  1404.     };
  1405.  
  1406.     // Terminate the burst operation
  1407.     ENC_CS_IO = 1;
  1408.  
  1409.     return i;
  1410. }//end MACGetArray
  1411.  
  1412.  
  1413. /******************************************************************************
  1414.  * Function:        void MACPut(BYTE val)
  1415.  *
  1416.  * PreCondition:    SPI bus must be initialized (done in MACInit()).
  1417.  *                  EWRPT must point to the location to begin writing.
  1418.  *
  1419.  * Input:           Byte to write into the ENC28J60 buffer memory
  1420.  *
  1421.  * Output:          None
  1422.  *
  1423.  * Side Effects:    None
  1424.  *
  1425.  * Overview:        MACPut outputs the Write Buffer Memory opcode/constant
  1426.  *                  (8 bits) and data to write (8 bits) over the SPI.  
  1427.  *                  EWRPT is incremented after the write.
  1428.  *
  1429.  * Note:            None
  1430.  *****************************************************************************/
  1431. void MACPut(BYTE val)
  1432. {
  1433.     BYTE Dummy;
  1434.  
  1435.     ENC_CS_IO = 0;
  1436.     ENC_SPI_IF = 0;
  1437.     ENC_SSPBUF = WBM;           // Send the opcode and constant.
  1438.     while(!ENC_SPI_IF);     // Wait until opcode/constant is transmitted.
  1439.     Dummy = ENC_SSPBUF;
  1440.     ENC_SPI_IF = 0;
  1441.     ENC_SSPBUF = val;           // Send the byte to be writen.
  1442.     while(!ENC_SPI_IF);     // Wait until byte is transmitted.
  1443.     Dummy = ENC_SSPBUF;
  1444.     ENC_SPI_IF = 0;
  1445.     ENC_CS_IO = 1;
  1446. }//end MACPut
  1447.  
  1448.  
  1449. /******************************************************************************
  1450.  * Function:        void MACPutArray(BYTE *val, WORD len)
  1451.  *
  1452.  * PreCondition:    SPI bus must be initialized (done in MACInit()).
  1453.  *                  EWRPT must point to the location to begin writing.
  1454.  *
  1455.  * Input:           *val: Pointer to source of bytes to copy.
  1456.  *                  len:  Number of bytes to write to the data buffer.
  1457.  *
  1458.  * Output:          None
  1459.  *
  1460.  * Side Effects:    None
  1461.  *
  1462.  * Overview:        MACPutArray writes several sequential bytes to the
  1463.  *                  ENC28J60 RAM.  It performs faster than multiple MACPut()
  1464.  *                  calls.  EWRPT is incremented by len.
  1465.  *
  1466.  * Note:            None
  1467.  *****************************************************************************/
  1468. void MACPutArray(BYTE *val, WORD len)
  1469. {
  1470.     BYTE Dummy;
  1471.  
  1472.     // Select the chip and send the proper opcode
  1473.     ENC_CS_IO = 0;
  1474.     ENC_SPI_IF = 0;
  1475.     ENC_SSPBUF = WBM;           // Send the Write Buffer Memory opcode
  1476.     while(!ENC_SPI_IF);     // Wait until opcode/constant is transmitted.
  1477.     Dummy = ENC_SSPBUF;
  1478.     ENC_SPI_IF = 0;
  1479.  
  1480.     // Send the data
  1481.     while(len)
  1482.     {
  1483.         ENC_SSPBUF = *val;      // Start sending the byte
  1484.         val++;              // Increment after writing to ENC_SSPBUF to increase speed
  1485.         len--;              // Decrement after writing to ENC_SSPBUF to increase speed
  1486.         while(!ENC_SPI_IF); // Wait until byte is transmitted
  1487.         Dummy = ENC_SSPBUF;
  1488.         ENC_SPI_IF = 0;
  1489.     };
  1490.  
  1491.     // Terminate the burst operation
  1492.     ENC_CS_IO = 1;
  1493. }//end MACPutArray
  1494.  
  1495.  
  1496. /******************************************************************************
  1497.  * Function:        static void SendSystemReset(void)
  1498.  *
  1499.  * PreCondition:    SPI bus must be initialized (done in MACInit()).
  1500.  *
  1501.  * Input:           None
  1502.  *
  1503.  * Output:          None
  1504.  *
  1505.  * Side Effects:    None
  1506.  *
  1507.  * Overview:        SendSystemReset sends the System Reset SPI command to
  1508.  *                  the Ethernet controller.  It resets all register contents
  1509.  *                  (except for ECOCON) and returns the device to the power
  1510.  *                  on default state.
  1511.  *
  1512.  * Note:            None
  1513.  *****************************************************************************/
  1514. static void SendSystemReset(void)
  1515. {
  1516.     BYTE Dummy;
  1517.  
  1518.     ENC_CS_IO = 0;
  1519.     ENC_SPI_IF = 0;
  1520.     ENC_SSPBUF = SR;
  1521.     while(!ENC_SPI_IF);     // Wait until the command is transmitted.
  1522.     Dummy = ENC_SSPBUF;
  1523.     ENC_SPI_IF = 0;
  1524.     ENC_CS_IO = 1;
  1525. }//end SendSystemReset
  1526.  
  1527.  
  1528. /******************************************************************************
  1529.  * Function:        REG ReadETHReg(BYTE Address)
  1530.  *
  1531.  * PreCondition:    SPI bus must be initialized (done in MACInit()).
  1532.  *                  Bank select bits must be set corresponding to the register
  1533.  *                  to read from.
  1534.  *
  1535.  * Input:           5 bit address of the ETH control register to read from.
  1536.  *                    The top 3 bits must be 0.
  1537.  *
  1538.  * Output:          Byte read from the Ethernet controller's ETH register.
  1539.  *
  1540.  * Side Effects:    None
  1541.  *
  1542.  * Overview:        ReadETHReg sends the 8 bit RCR opcode/Address byte over
  1543.  *                  the SPI and then retrives the register contents in the
  1544.  *                  next 8 SPI clocks.
  1545.  *
  1546.  * Note:            This routine cannot be used to access MAC/MII or PHY
  1547.  *                  registers.  Use ReadMACReg() or ReadPHYReg() for that
  1548.  *                  purpose.  
  1549.  *****************************************************************************/
  1550. static REG ReadETHReg(BYTE Address)
  1551. {
  1552.     REG r;
  1553.  
  1554.     // Select the chip and send the Read Control Register opcode/address
  1555.     ENC_CS_IO = 0;
  1556.     ENC_SPI_IF = 0;
  1557.     ENC_SSPBUF = RCR | Address;
  1558.        
  1559.     while(!ENC_SPI_IF);     // Wait until the opcode/address is transmitted
  1560.     r.Val = ENC_SSPBUF;
  1561.     ENC_SPI_IF = 0;
  1562.     ENC_SSPBUF = 0;             // Send a dummy byte to receive the register
  1563.                             //   contents
  1564.     while(!ENC_SPI_IF);     // Wait until the register is received
  1565.     r.Val = ENC_SSPBUF;
  1566.     ENC_SPI_IF = 0;
  1567.     ENC_CS_IO = 1;
  1568.  
  1569.     return r;
  1570. }//end ReadETHReg
  1571.  
  1572.  
  1573. /******************************************************************************
  1574.  * Function:        REG ReadMACReg(BYTE Address)
  1575.  *
  1576.  * PreCondition:    SPI bus must be initialized (done in MACInit()).
  1577.  *                  Bank select bits must be set corresponding to the register
  1578.  *                  to read from.
  1579.  *
  1580.  * Input:           5 bit address of the MAC or MII register to read from.
  1581.  *                    The top 3 bits must be 0.
  1582.  *
  1583.  * Output:          Byte read from the Ethernet controller's MAC/MII register.
  1584.  *
  1585.  * Side Effects:    None
  1586.  *
  1587.  * Overview:        ReadMACReg sends the 8 bit RCR opcode/Address byte as well
  1588.  *                  as a dummy byte over the SPI and then retrives the
  1589.  *                  register contents in the last 8 SPI clocks.
  1590.  *
  1591.  * Note:            This routine cannot be used to access ETH or PHY
  1592.  *                  registers.  Use ReadETHReg() or ReadPHYReg() for that
  1593.  *                  purpose.  
  1594.  *****************************************************************************/
  1595. static REG ReadMACReg(BYTE Address)
  1596. {
  1597.     REG r;
  1598.  
  1599.     ENC_CS_IO = 0;
  1600.     ENC_SPI_IF = 0;
  1601.     ENC_SSPBUF = RCR | Address; // Send the Read Control Register opcode and
  1602.                             //   address.
  1603.     while(!ENC_SPI_IF);     // Wait until opcode/address is transmitted.
  1604.     r.Val = ENC_SSPBUF;
  1605.     ENC_SPI_IF = 0;
  1606.     ENC_SSPBUF = 0;             // Send a dummy byte
  1607.     while(!ENC_SPI_IF);     // Wait for the dummy byte to be transmitted
  1608.     r.Val = ENC_SSPBUF;
  1609.     ENC_SPI_IF = 0;
  1610.     ENC_SSPBUF = 0;             // Send another dummy byte to receive the register
  1611.                             //   contents.
  1612.     while(!ENC_SPI_IF);     // Wait until register is received.
  1613.     r.Val = ENC_SSPBUF;
  1614.     ENC_SPI_IF = 0;
  1615.     ENC_CS_IO = 1;
  1616.    
  1617.     return r;
  1618. }//end ReadMACReg
  1619.  
  1620.  
  1621. /******************************************************************************
  1622.  * Function:        ReadPHYReg
  1623.  *
  1624.  * PreCondition:    SPI bus must be initialized (done in MACInit()).
  1625.  *
  1626.  * Input:           Address of the PHY register to read from.
  1627.  *
  1628.  * Output:          16 bits of data read from the PHY register.
  1629.  *
  1630.  * Side Effects:    Alters bank bits to point to Bank 2
  1631.  *
  1632.  * Overview:        ReadPHYReg performs an MII read operation.  While in
  1633.  *                  progress, it simply polls the MII BUSY bit wasting time
  1634.  *                  (10.24us).
  1635.  *
  1636.  * Note:            None
  1637.  *****************************************************************************/
  1638. PHYREG ReadPHYReg(BYTE Register)
  1639. {
  1640.     PHYREG Result;
  1641.  
  1642.     // Set the right address and start the register read operation
  1643.     BankSel(MIREGADR);
  1644.     WriteReg((BYTE)MIREGADR, Register);
  1645.     WriteReg((BYTE)MICMD, MICMD_MIIRD);
  1646.  
  1647.     // Loop to wait until the PHY register has been read through the MII
  1648.     // This requires 10.24us
  1649.     BankSel(MISTAT);
  1650.     while(ReadMACReg((BYTE)MISTAT).MISTATbits.BUSY);
  1651.  
  1652.     // Stop reading
  1653.     BankSel(MIREGADR);
  1654.     WriteReg((BYTE)MICMD, 0x00);   
  1655.    
  1656.     // Obtain results and return
  1657.     Result.VAL.v[0] = ReadMACReg((BYTE)MIRDL).Val;
  1658.     Result.VAL.v[1] = ReadMACReg((BYTE)MIRDH).Val;
  1659.  
  1660.     return Result;
  1661. }//end ReadPHYReg
  1662.  
  1663.  
  1664. /******************************************************************************
  1665.  * Function:        void WriteReg(BYTE Address, BYTE Data)
  1666.  *
  1667.  * PreCondition:    SPI bus must be initialized (done in MACInit()).
  1668.  *                  Bank select bits must be set corresponding to the register
  1669.  *                  to modify.
  1670.  *
  1671.  * Input:           5 bit address of the ETH, MAC, or MII register to modify.  
  1672.  *                    The top 3 bits must be 0.  
  1673.  *                  Byte to be written into the register.
  1674.  *
  1675.  * Output:          None
  1676.  *
  1677.  * Side Effects:    None
  1678.  *
  1679.  * Overview:        WriteReg sends the 8 bit WCR opcode/Address byte over the
  1680.  *                  SPI and then sends the data to write in the next 8 SPI
  1681.  *                  clocks.
  1682.  *
  1683.  * Note:            This routine is almost identical to the BFCReg() and
  1684.  *                  BFSReg() functions.  It is seperate to maximize speed.  
  1685.  *                  Unlike the ReadETHReg/ReadMACReg functions, WriteReg()
  1686.  *                  can write to any ETH or MAC register.  Writing to PHY
  1687.  *                  registers must be accomplished with WritePHYReg().
  1688.  *****************************************************************************/
  1689. static void WriteReg(BYTE Address, BYTE Data)
  1690. {      
  1691.     BYTE Dummy;
  1692.  
  1693.     ENC_CS_IO = 0;
  1694.     ENC_SPI_IF = 0;
  1695.     ENC_SSPBUF = WCR | Address; // Send the opcode and address.
  1696.     while(!ENC_SPI_IF);     // Wait until opcode/address is transmitted.
  1697.     Dummy = ENC_SSPBUF;
  1698.     ENC_SPI_IF = 0;
  1699.     ENC_SSPBUF = Data;          // Send the byte to be writen.
  1700.     while(!ENC_SPI_IF);     // Wait until register is written.
  1701.     Dummy = ENC_SSPBUF;
  1702.     ENC_SPI_IF = 0;
  1703.     ENC_CS_IO = 1;
  1704. }//end WriteReg
  1705.  
  1706.  
  1707. /******************************************************************************
  1708.  * Function:        void BFCReg(BYTE Address, BYTE Data)
  1709.  *
  1710.  * PreCondition:    SPI bus must be initialized (done in MACInit()).
  1711.  *                  Bank select bits must be set corresponding to the register
  1712.  *                    to modify.
  1713.  *
  1714.  * Input:           5 bit address of the register to modify.  The top 3 bits
  1715.  *                    must be 0.  
  1716.  *                  Byte to be used with the Bit Field Clear operation.
  1717.  *
  1718.  * Output:          None
  1719.  *
  1720.  * Side Effects:    None
  1721.  *
  1722.  * Overview:        BFCReg sends the 8 bit BFC opcode/Address byte over the
  1723.  *                  SPI and then sends the data in the next 8 SPI clocks.
  1724.  *
  1725.  * Note:            This routine is almost identical to the WriteReg() and
  1726.  *                  BFSReg() functions.  It is separate to maximize speed.  
  1727.  *                  BFCReg() must only be used on ETH registers.
  1728.  *****************************************************************************/
  1729. static void BFCReg(BYTE Address, BYTE Data)
  1730. {
  1731.     BYTE Dummy;
  1732.  
  1733.     ENC_CS_IO = 0;
  1734.     ENC_SPI_IF = 0;
  1735.     ENC_SSPBUF = BFC | Address; // Send the opcode and address.
  1736.     while(!ENC_SPI_IF);     // Wait until opcode/address is transmitted.
  1737.     Dummy = ENC_SSPBUF;
  1738.     ENC_SPI_IF = 0;
  1739.     ENC_SSPBUF = Data;          // Send the byte to be writen.
  1740.     while(!ENC_SPI_IF);     // Wait until register is written.
  1741.     Dummy = ENC_SSPBUF;
  1742.     ENC_SPI_IF = 0;
  1743.     ENC_CS_IO = 1;
  1744. }//end BFCReg
  1745.  
  1746.  
  1747. /******************************************************************************
  1748.  * Function:        void BFSReg(BYTE Address, BYTE Data)
  1749.  *
  1750.  * PreCondition:    SPI bus must be initialized (done in MACInit()).
  1751.  *                  Bank select bits must be set corresponding to the register
  1752.  *                  to modify.
  1753.  *
  1754.  * Input:           5 bit address of the register to modify.  The top 3 bits
  1755.  *                    must be 0.  
  1756.  *                  Byte to be used with the Bit Field Set operation.
  1757.  *
  1758.  * Output:          None
  1759.  *
  1760.  * Side Effects:    None
  1761.  *
  1762.  * Overview:        BFSReg sends the 8 bit BFC opcode/Address byte over the
  1763.  *                  SPI and then sends the data in the next 8 SPI clocks.
  1764.  *
  1765.  * Note:            This routine is almost identical to the WriteReg() and
  1766.  *                  BFCReg() functions.  It is separate to maximize speed.
  1767.  *                  BFSReg() must only be used on ETH registers.
  1768.  *****************************************************************************/
  1769. static void BFSReg(BYTE Address, BYTE Data)
  1770. {
  1771.     BYTE Dummy;
  1772.  
  1773.     ENC_CS_IO = 0;
  1774.     ENC_SPI_IF = 0;
  1775.     ENC_SSPBUF = BFS | Address; // Send the opcode and address.
  1776.     while(!ENC_SPI_IF);     // Wait until opcode/address is transmitted.
  1777.     Dummy = ENC_SSPBUF;
  1778.     ENC_SPI_IF = 0;
  1779.     ENC_SSPBUF = Data;          // Send the byte to be writen.
  1780.     while(!ENC_SPI_IF);     // Wait until register is written.
  1781.     Dummy = ENC_SSPBUF;
  1782.     ENC_SPI_IF = 0;
  1783.     ENC_CS_IO = 1;
  1784. }//end BFSReg
  1785.  
  1786.  
  1787. /******************************************************************************
  1788.  * Function:        WritePHYReg
  1789.  *
  1790.  * PreCondition:    SPI bus must be initialized (done in MACInit()).
  1791.  *
  1792.  * Input:           Address of the PHY register to write to.
  1793.  *                  16 bits of data to write to PHY register.
  1794.  *
  1795.  * Output:          None
  1796.  *
  1797.  * Side Effects:    Alters bank bits to point to Bank 3
  1798.  *
  1799.  * Overview:        WritePHYReg performs an MII write operation.  While in
  1800.  *                  progress, it simply polls the MII BUSY bit wasting time.
  1801.  *
  1802.  * Note:            None
  1803.  *****************************************************************************/
  1804. void WritePHYReg(BYTE Register, WORD Data)
  1805. {
  1806.     // Write the register address
  1807.     BankSel(MIREGADR);
  1808.     WriteReg((BYTE)MIREGADR, Register);
  1809.    
  1810.     // Write the data
  1811.     // Order is important: write low byte first, high byte last
  1812.     WriteReg((BYTE)MIWRL, ((WORD_VAL*)&Data)->v[0]);   
  1813.     WriteReg((BYTE)MIWRH, ((WORD_VAL*)&Data)->v[1]);
  1814.  
  1815.     // Wait until the PHY register has been written
  1816.     BankSel(MISTAT);
  1817.     while(ReadMACReg((BYTE)MISTAT).MISTATbits.BUSY);
  1818. }//end WritePHYReg
  1819.  
  1820.  
  1821. /******************************************************************************
  1822.  * Function:        BankSel
  1823.  *
  1824.  * PreCondition:    SPI bus must be initialized (done in MACInit()).
  1825.  *
  1826.  * Input:           Register address with the high byte containing the 2 bank
  1827.  *                    select 2 bits.
  1828.  *
  1829.  * Output:          None
  1830.  *
  1831.  * Side Effects:    None
  1832.  *
  1833.  * Overview:        BankSel takes the high byte of a register address and
  1834.  *                  changes the bank select bits in ETHCON1 to match.
  1835.  *
  1836.  * Note:            None
  1837.  *****************************************************************************/
  1838. static void BankSel(WORD Register)
  1839. {
  1840.     BFCReg(ECON1, ECON1_BSEL1 | ECON1_BSEL0);
  1841.     BFSReg(ECON1, ((WORD_VAL*)&Register)->v[1]);
  1842. }//end BankSel
  1843.  
  1844.  
  1845. /******************************************************************************
  1846.  * Function:        static BOOL TestMemory(void)
  1847.  *
  1848.  * PreCondition:    SPI bus must be initialized (done in MACInit()).
  1849.  *
  1850.  * Input:           None
  1851.  *
  1852.  * Output:          TRUE if the memory tests have passed
  1853.  *                  FALSE if the BIST has detected a hardware fault
  1854.  *
  1855.  * Side Effects:    Alters the state of numerous control registers and all
  1856.  *                  RAM bytes.
  1857.  *
  1858.  * Overview:        The internal BIST and DMA modules are used to fill the
  1859.  *                  entire dual port memory and calculate a checksum of the
  1860.  *                  data stored within.  Address and Random fill modes are
  1861.  *                  used.
  1862.  *
  1863.  * Note:            For the Random Fill mode, the random number generator is
  1864.  *                  seeded by the contents of the TMR0L PIC SFR.  If the timer
  1865.  *                  is running, additional confidence that the memory is
  1866.  *                  working can be obtained by calling TestMemory multiple
  1867.  *                  times.
  1868.  *****************************************************************************/
  1869. #if defined(MAC_POWER_ON_TEST)
  1870. static BOOL TestMemory(void)
  1871. {
  1872.     #define RANDOM_FILL     0b0000
  1873.     #define ADDRESS_FILL    0b0100
  1874.     #define PATTERN_SHIFT   0b1000
  1875.    
  1876.     WORD_VAL DMAChecksum, BISTChecksum;
  1877.    
  1878.    
  1879.     // Select Bank 0 and disable anything that could have been in progress
  1880.     WriteReg(ECON1, 0x00);
  1881.    
  1882.     // Set up necessary pointers for the DMA to calculate over the entire
  1883.     // memory
  1884.     WriteReg(EDMASTL, 0x00);
  1885.     WriteReg(EDMASTH, 0x00);
  1886.     WriteReg(EDMANDL, LOW(RAMSIZE-1u));
  1887.     WriteReg(EDMANDH, HIGH(RAMSIZE-1u));
  1888.     WriteReg(ERXNDL, LOW(RAMSIZE-1u));
  1889.     WriteReg(ERXNDH, HIGH(RAMSIZE-1u));
  1890.  
  1891.     // Enable Test Mode and do an Address Fill
  1892.     BankSel(EBSTCON);
  1893.     WriteReg((BYTE)EBSTCON, EBSTCON_TME |
  1894.                          EBSTCON_BISTST |
  1895.                          ADDRESS_FILL);
  1896.    
  1897.    
  1898.     // Wait for the BIST to complete and disable test mode before
  1899.     // starting any DMA operations.
  1900.     while(ReadETHReg((BYTE)EBSTCON).EBSTCONbits.BISTST);
  1901.     BFCReg((BYTE)EBSTCON, EBSTCON_TME);
  1902.  
  1903.  
  1904.     // Begin reading the memory and calculating a checksum over it
  1905.     // Block until the checksum is generated
  1906.     BFSReg(ECON1, ECON1_DMAST | ECON1_CSUMEN);
  1907.     BankSel(EDMACSL);
  1908.     while(ReadETHReg(ECON1).ECON1bits.DMAST);
  1909.  
  1910.     // Obtain the resulting DMA checksum and the expected BIST checksum
  1911.     DMAChecksum.v[0] = ReadETHReg(EDMACSL).Val;
  1912.     DMAChecksum.v[1] = ReadETHReg(EDMACSH).Val;
  1913.     BankSel(EBSTCSL);
  1914.     BISTChecksum.v[0] = ReadETHReg((BYTE)EBSTCSL).Val;
  1915.     BISTChecksum.v[1] = ReadETHReg((BYTE)EBSTCSH).Val;
  1916.     BFCReg((BYTE)EBSTCON, EBSTCON_TME);
  1917.    
  1918.     // Compare the results
  1919.     // 0xF807 should always be generated in Address fill mode
  1920.     if( (DMAChecksum.Val != BISTChecksum.Val) || (DMAChecksum.Val != 0xF807) )
  1921.         return FALSE;
  1922.    
  1923.     // Seed the random number generator and begin another Random Fill test
  1924.     // with the DMA and BIST memory access ports swapped.
  1925. #ifdef __C30__
  1926.     WriteReg((BYTE)EBSTSD, TMR1);
  1927. #else
  1928.     WriteReg((BYTE)EBSTSD, TMR0L);
  1929. #endif
  1930.     WriteReg((BYTE)EBSTCON, EBSTCON_TME |
  1931.                       EBSTCON_PSEL |
  1932.                       EBSTCON_BISTST |
  1933.                       RANDOM_FILL);
  1934.                          
  1935.                          
  1936.     // Wait for the BIST to complete and disable test mode since
  1937.     // we won't be needing it anymore
  1938.     while(ReadETHReg((BYTE)EBSTCON).EBSTCONbits.BISTST);
  1939.     BFCReg((BYTE)EBSTCON, EBSTCON_TME);
  1940.    
  1941.    
  1942.     // Begin reading the memory and calculating a checksum over it
  1943.     // Block until the checksum is generated
  1944.     BFSReg(ECON1, ECON1_DMAST | ECON1_CSUMEN);
  1945.     BankSel(EDMACSL);
  1946.     while(ReadETHReg(ECON1).ECON1bits.DMAST);
  1947.  
  1948.     // Obtain the resulting DMA checksum and the expected BIST checksum
  1949.     DMAChecksum.v[0] = ReadETHReg(EDMACSL).Val;
  1950.     DMAChecksum.v[1] = ReadETHReg(EDMACSH).Val;
  1951.     BankSel(EBSTCSL);
  1952.     BISTChecksum.v[0] = ReadETHReg((BYTE)EBSTCSL).Val;
  1953.     BISTChecksum.v[1] = ReadETHReg((BYTE)EBSTCSH).Val;
  1954.    
  1955.     return (DMAChecksum.Val == BISTChecksum.Val);
  1956. }//end TestMemory
  1957. #endif
  1958.  
  1959.  
  1960. /******************************************************************************
  1961.  * Function:        void MACSetDuplex(DUPLEX DuplexState)
  1962.  *
  1963.  * PreCondition:    SPI bus must be initialized (done in MACInit()).
  1964.  *
  1965.  * Input:           Member of DUPLEX enum:
  1966.  *                      FULL: Set full duplex mode
  1967.  *                      HALF: Set half duplex mode
  1968.  *                      USE_PHY: Set the MAC to match the PHYDPLXMODE bit in
  1969.  *                               PHYCON.  This is controlled by LEDB on RESET.
  1970.  *
  1971.  * Output:          None
  1972.  *
  1973.  * Side Effects:    Changes bank bits to Bank 2.
  1974.  *
  1975.  * Overview:        Disables RX, TX logic, sets MAC up for full duplex
  1976.  *                  operation, sets PHY up for full duplex operation, and
  1977.  *                  reenables RX logic.  The back-to-back inter-packet gap
  1978.  *                  register (MACBBIPG) is updated to maintain a 9.6us gap.
  1979.  *
  1980.  * Note:            If a packet is being transmitted or received while this
  1981.  *                  function is called, it will be aborted.
  1982.  *****************************************************************************/
  1983. void MACSetDuplex(DUPLEX DuplexState)
  1984. {
  1985.     REG Register;
  1986.     PHYREG PhyReg;
  1987.    
  1988.     // Disable receive logic and abort any packets currently being transmitted
  1989.     BFCReg(ECON1, ECON1_TXRTS | ECON1_RXEN);
  1990.    
  1991.     // Set the PHY to the proper duplex mode
  1992.     PhyReg = ReadPHYReg(PHCON1);
  1993.     if(DuplexState == USE_PHY)
  1994.     {
  1995.         DuplexState = PhyReg.PHCON1bits.PDPXMD;
  1996.     }
  1997.     else
  1998.     {
  1999.         PhyReg.PHCON1bits.PDPXMD = DuplexState;
  2000.         WritePHYReg(PHCON1, PhyReg.Val);
  2001.     }
  2002.  
  2003.     // Set the MAC to the proper duplex mode
  2004.     BankSel(MACON3);
  2005.     Register = ReadMACReg((BYTE)MACON3);
  2006.     Register.MACON3bits.FULDPX = DuplexState;
  2007.     WriteReg((BYTE)MACON3, Register.Val);
  2008.  
  2009.     // Set the back-to-back inter-packet gap time to IEEE specified
  2010.     // requirements.  The meaning of the MABBIPG value changes with the duplex
  2011.     // state, so it must be updated in this function.
  2012.     // In full duplex, 0x15 represents 9.6us; 0x12 is 9.6us in half duplex
  2013.     WriteReg((BYTE)MABBIPG, DuplexState ? 0x15 : 0x12);
  2014.    
  2015.     // Reenable receive logic
  2016.     BFSReg(ECON1, ECON1_RXEN);
  2017. }//end MACSetDuplex
  2018.  
  2019.  
  2020. /******************************************************************************
  2021.  * Function:        void MACPowerDown(void)
  2022.  *
  2023.  * PreCondition:    SPI bus must be initialized (done in MACInit()).
  2024.  *
  2025.  * Input:           None
  2026.  *
  2027.  * Output:          None
  2028.  *
  2029.  * Side Effects:    None
  2030.  *
  2031.  * Overview:        MACPowerDown puts the ENC28J60 in low power sleep mode. In
  2032.  *                  sleep mode, no packets can be transmitted or received.  
  2033.  *                  All MAC and PHY registers should not be accessed.
  2034.  *
  2035.  * Note:            If a packet is being transmitted while this function is
  2036.  *                  called, this function will block until it is it complete.
  2037.  *                  If anything is being received, it will be completed.
  2038.  *****************************************************************************/
  2039. void MACPowerDown(void)
  2040. {
  2041.     // Disable packet reception
  2042.     BFCReg(ECON1, ECON1_RXEN);
  2043.  
  2044.     // Make sure any last packet which was in-progress when RXEN was cleared
  2045.     // is completed
  2046.     while(ReadETHReg(ESTAT).ESTATbits.RXBUSY);
  2047.  
  2048.     // If a packet is being transmitted, wait for it to finish
  2049.     while(ReadETHReg(ECON1).ECON1bits.TXRTS);
  2050.    
  2051.     // Enter sleep mode
  2052.     BFSReg(ECON2, ECON2_PWRSV);
  2053. }//end MACPowerDown
  2054.  
  2055.  
  2056. /******************************************************************************
  2057.  * Function:        void MACPowerUp(void)
  2058.  *
  2059.  * PreCondition:    SPI bus must be initialized (done in MACInit()).
  2060.  *
  2061.  * Input:           None
  2062.  *
  2063.  * Output:          None
  2064.  *
  2065.  * Side Effects:    None
  2066.  *
  2067.  * Overview:        MACPowerUp returns the ENC28J60 back to normal operation
  2068.  *                  after a previous call to MACPowerDown().  Calling this
  2069.  *                  function when already powered up will have no effect.
  2070.  *
  2071.  * Note:            If a link partner is present, it will take 10s of
  2072.  *                  milliseconds before a new link will be established after
  2073.  *                  waking up.  While not linked, packets which are
  2074.  *                  transmitted will most likely be lost.  MACIsLinked() can
  2075.  *                  be called to determine if a link is established.
  2076.  *****************************************************************************/
  2077. void MACPowerUp(void)
  2078. {  
  2079.     // Leave power down mode
  2080.     BFCReg(ECON2, ECON2_PWRSV);
  2081.  
  2082.     // Wait for the 300us Oscillator Startup Timer (OST) to time out.  This
  2083.     // delay is required for the PHY module to return to an operational state.
  2084.     while(!ReadETHReg(ESTAT).ESTATbits.CLKRDY);
  2085.    
  2086.     // Enable packet reception
  2087.     BFSReg(ECON1, ECON1_RXEN);
  2088. }//end MACPowerUp
  2089.  
  2090.  
  2091. /******************************************************************************
  2092.  * Function:        void SetCLKOUT(BYTE NewConfig)
  2093.  *
  2094.  * PreCondition:    SPI bus must be initialized (done in MACInit()).
  2095.  *
  2096.  * Input:           NewConfig - 0x00: CLKOUT disabled (pin driven low)
  2097.  *                              0x01: Divide by 1 (25 MHz)
  2098.  *                              0x02: Divide by 2 (12.5 MHz)
  2099.  *                              0x03: Divide by 3 (8.333333 MHz)
  2100.  *                              0x04: Divide by 4 (6.25 MHz, POR default)
  2101.  *                              0x05: Divide by 8 (3.125 MHz)
  2102.  *
  2103.  * Output:          None
  2104.  *
  2105.  * Side Effects:    None
  2106.  *
  2107.  * Overview:        Writes the value of NewConfig into the ECOCON register.  
  2108.  *                  The CLKOUT pin will beginning outputting the new frequency
  2109.  *                  immediately.
  2110.  *
  2111.  * Note:            
  2112.  *****************************************************************************/
  2113. void SetCLKOUT(BYTE NewConfig)
  2114. {  
  2115.     BankSel(ECOCON);
  2116.     WriteReg((BYTE)ECOCON, NewConfig);
  2117. }//end SetCLKOUT
  2118.  
  2119.  
  2120. /******************************************************************************
  2121.  * Function:        BYTE GetCLKOUT(void)
  2122.  *
  2123.  * PreCondition:    SPI bus must be initialized (done in MACInit()).
  2124.  *
  2125.  * Input:           None
  2126.  *
  2127.  * Output:          BYTE - 0x00: CLKOUT disabled (pin driven low)
  2128.  *                         0x01: Divide by 1 (25 MHz)
  2129.  *                         0x02: Divide by 2 (12.5 MHz)
  2130.  *                         0x03: Divide by 3 (8.333333 MHz)
  2131.  *                         0x04: Divide by 4 (6.25 MHz, POR default)
  2132.  *                         0x05: Divide by 8 (3.125 MHz)
  2133.  *                         0x06: Reserved
  2134.  *                         0x07: Reserved
  2135.  *
  2136.  * Side Effects:    None
  2137.  *
  2138.  * Overview:        Returns the current value of the ECOCON register.
  2139.  *
  2140.  * Note:            None
  2141.  *****************************************************************************/
  2142. BYTE GetCLKOUT(void)
  2143. {  
  2144.     BankSel(ECOCON);
  2145.     return ReadETHReg((BYTE)ECOCON).Val;
  2146. }//end GetCLKOUT
  2147.  
  2148.  
  2149. /******************************************************************************
  2150.  * Function:        void SetRXHashTableEntry(MAC_ADDR DestMACAddr)
  2151.  *
  2152.  * PreCondition:    SPI bus must be initialized (done in MACInit()).
  2153.  *
  2154.  * Input:           DestMACAddr: 6 byte group destination MAC address to allow
  2155.  *                               through the Hash Table Filter
  2156.  *
  2157.  * Output:          Sets the appropriate bit in the EHT* registers to allow
  2158.  *                  packets sent to DestMACAddr to be received if the Hash
  2159.  *                  Table receive filter is enabled
  2160.  *
  2161.  * Side Effects:    None
  2162.  *
  2163.  * Overview:        Calculates a CRC-32 using polynomial 0x4C11DB7 and then,
  2164.  *                  using bits 28:23 of the CRC, sets the appropriate bit in
  2165.  *                  the EHT* registers
  2166.  *
  2167.  * Note:            This code is commented out to save code space on systems
  2168.  *                  that do not need this function.  Change the "#if 0" line
  2169.  *                  to "#if 1" to uncomment it.
  2170.  *****************************************************************************/
  2171. #if 0
  2172. void SetRXHashTableEntry(MAC_ADDR DestMACAddr)
  2173. {
  2174.     DWORD_VAL CRC = {0xFFFFFFFF};
  2175.     BYTE HTRegister;
  2176.     BYTE i, j;
  2177.  
  2178.     // Calculate a CRC-32 over the 6 byte MAC address
  2179.     // using polynomial 0x4C11DB7
  2180.     for(i = 0; i < sizeof(MAC_ADDR); i++)
  2181.     {
  2182.         BYTE  crcnext;
  2183.    
  2184.         // shift in 8 bits
  2185.         for(j = 0; j < 8; j++)
  2186.         {
  2187.             crcnext = 0;
  2188.             if(((BYTE_VAL*)&(CRC.v[3]))->bits.b7)
  2189.                 crcnext = 1;
  2190.             crcnext ^= (((BYTE_VAL*)&DestMACAddr.v[i])->bits.b0);
  2191.    
  2192.             CRC.Val <<= 1;
  2193.             if(crcnext)
  2194.                 CRC.Val ^= 0x4C11DB7;
  2195.             // next bit
  2196.             DestMACAddr.v[i] >>= 1;
  2197.         }
  2198.     }
  2199.    
  2200.     // CRC-32 calculated, now extract bits 28:23
  2201.     // Bits 25:23 define where within the Hash Table byte the bit needs to be set
  2202.     // Bits 28:26 define which of the 8 Hash Table bytes that bits 25:23 apply to
  2203.     i = CRC.v[3] & 0x1F;
  2204.     HTRegister = (i >> 2) + (BYTE)EHT0;
  2205.     i = (i << 1) & 0x06;
  2206.     ((BYTE_VAL*)&i)->bits.b0 = ((BYTE_VAL*)&CRC.v[2])->bits.b7;
  2207.    
  2208.     // Set the proper bit in the Hash Table
  2209.     BankSel(EHT0);
  2210.     BFSReg(HTRegister, 1<<i);
  2211. }
  2212. #endif
  2213.  
  2214. //// GetRegs is a function for debugging purposes only.  It will read all
  2215. //// registers and store them in the PIC's RAM so they can be viewed with
  2216. //// the ICD2.
  2217. //static REG Regs[4][32];
  2218. //static void GetRegs(void)
  2219. //{
  2220. //  BYTE i;
  2221. // 
  2222. //  BankSel(0x000);
  2223. //  for(i=0; i<0x1A; i++)
  2224. //      Regs[0][i] = ReadETHReg(i);
  2225. //  for(i=0x1B; i<32; i++)
  2226. //      Regs[0][i] = ReadETHReg(i);
  2227. //
  2228. //  BankSel(0x100);
  2229. //  for(i=0; i<0x1A; i++)
  2230. //      Regs[1][i] = ReadETHReg(i);
  2231. //  for(i=0x1B; i<32; i++)
  2232. //      Regs[1][i] = ReadETHReg(i);
  2233. //
  2234. //  BankSel(0x200);
  2235. //  for(i=0; i<5; i++)
  2236. //      Regs[2][i] = ReadMACReg(i);
  2237. //  Regs[2][5] = ReadETHReg(i);
  2238. //  for(i=6; i<0x0F; i++)
  2239. //      Regs[2][i] = ReadMACReg(i);
  2240. //  Regs[2][0x0F] = ReadETHReg(i);
  2241. //  for(i=0x10; i<0x13; i++)
  2242. //      Regs[2][i] = ReadMACReg(i);
  2243. //  Regs[2][0x13] = ReadETHReg(i);
  2244. //  for(i=0x14; i<0x1A; i++)
  2245. //      Regs[2][i] = ReadMACReg(i);
  2246. //  for(i=0x1B; i<32; i++)
  2247. //      Regs[2][i] = ReadETHReg(i);
  2248. //
  2249. //  BankSel(0x300);
  2250. //  for(i=0; i<0x06; i++)
  2251. //      Regs[3][i] = ReadMACReg(i);
  2252. //  for(i=6; i<0x0A; i++)
  2253. //      Regs[3][i] = ReadETHReg(i);
  2254. //  Regs[3][0x0A] = ReadMACReg(i);
  2255. //  for(i=0x0B; i<0x1A; i++)
  2256. //      Regs[3][i] = ReadETHReg(i);
  2257. //  for(i=0x1B; i<32; i++)
  2258. //      Regs[3][i] = ReadETHReg(i);
  2259. //
  2260. //  Regs[0][0x1A].Val = 0;
  2261. //  Regs[1][0x1A].Val = 0;
  2262. //  Regs[2][0x1A].Val = 0;
  2263. //  Regs[3][0x1A].Val = 0;
  2264. //
  2265. //  return;
  2266. //}
  2267.