/[H8]/trunk/docs/Microchip TCP_IP stack/TCPIP Stack/ETH97J60.c
ViewVC logotype

Annotation of /trunk/docs/Microchip TCP_IP stack/TCPIP Stack/ETH97J60.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 15 - (hide annotations) (download)
Thu Apr 19 09:01:15 2007 UTC (17 years, 2 months ago) by hedin
File MIME type: text/plain
File size: 40874 byte(s)
added the TCP/IP stack, source code.
1 hedin 15 /*********************************************************************
2     *
3     * Medium Access Control (MAC) Layer for Microchip PIC18F97J60 family
4     * Module for Microchip TCP/IP Stack
5     * -Provides access to PIC18F97J60 family Ethernet controller
6     * -Reference: PIC18F97J60 Family data sheet, IEEE 802.3 Standard
7     *
8     *********************************************************************
9     * FileName: ETH97J60.c
10     * Dependencies: ETH97J60.h
11     * MAC.h
12     * string.h
13     * StackTsk.h
14     * Helpers.h
15     * Delay.h
16     * Processor: PIC18F97J60 family device
17     * Complier: Microchip C18 v3.10 or higher
18     * HI-TECH PICC-18 v9.50PL3 or higher
19     * Company: Microchip Technology, Inc.
20     *
21     * Software License Agreement
22     *
23     * Copyright © 2002-2007 Microchip Technology Inc. All rights
24     * reserved.
25     *
26     * Microchip licenses to you the right to use, modify, copy, and
27     * distribute:
28     * (i) the Software when embedded on a Microchip microcontroller or
29     * digital signal controller product (“Device”) which is
30     * integrated into Licensee’s product; or
31     * (ii) ONLY the Software driver source files ENC28J60.c and
32     * ENC28J60.h ported to a non-Microchip device used in
33     * conjunction with a Microchip ethernet controller for the
34     * sole purpose of interfacing with the ethernet controller.
35     *
36     * You should refer to the license agreement accompanying this
37     * Software for additional information regarding your rights and
38     * obligations.
39     *
40     * THE SOFTWARE AND DOCUMENTATION ARE PROVIDED “AS IS” WITHOUT
41     * WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT
42     * LIMITATION, ANY WARRANTY OF MERCHANTABILITY, FITNESS FOR A
43     * PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL
44     * MICROCHIP BE LIABLE FOR ANY INCIDENTAL, SPECIAL, INDIRECT OR
45     * CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF
46     * PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY OR SERVICES, ANY CLAIMS
47     * BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE
48     * THEREOF), ANY CLAIMS FOR INDEMNITY OR CONTRIBUTION, OR OTHER
49     * SIMILAR COSTS, WHETHER ASSERTED ON THE BASIS OF CONTRACT, TORT
50     * (INCLUDING NEGLIGENCE), BREACH OF WARRANTY, OR OTHERWISE.
51     *
52     * Author Date Comment
53     *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
54     * Rawin Rojvanit 07/26/05 Stuff
55     * Howard Schlunder 11/17/05 Ported to PIC18F97J60
56     * Howard Schlunder 06/16/06 Synchronized with ENC28J60 code
57     ********************************************************************/
58     #define __ETH97J60_C
59    
60     #include "TCPIP Stack/TCPIP.h"
61    
62     // Make sure that this hardware profile has a PIC18F97J60 family device in it
63     #if (defined(__18F97J60) || defined(__18F96J65) || defined(__18F96J60) || defined(__18F87J60) || defined(__18F86J65) || defined(__18F86J60) || defined(__18F67J60) || defined(__18F66J65) || defined(__18F66J60) || \
64     defined(_18F97J60) || defined(_18F96J65) || defined(_18F96J60) || defined(_18F87J60) || defined(_18F86J65) || defined(_18F86J60) || defined(_18F67J60) || defined(_18F66J65) || defined(_18F66J60)) \
65     && !defined(STACK_USE_SLIP) && !defined(ENC_CS_TRIS)
66    
67    
68     /** D E F I N I T I O N S ****************************************************/
69     // Since the Ethernet PHY doesn't support auto-negotiation, full-duplex mode is
70     // not compatible with most switches/routers. If a dedicated network is used
71     // where the duplex of the remote node can be manually configured, you may
72     // change this configuration. Otherwise, half duplex should always be used.
73     #define HALF_DUPLEX
74     //#define FULL_DUPLEX
75    
76     // Pseudo Functions
77     #define LOW(a) (a & 0xFF)
78     #define HIGH(a) ((a>>8) & 0xFF)
79    
80     #define ETHER_IP (0x00u)
81     #define ETHER_ARP (0x06u)
82    
83     // A header appended at the start of all RX frames by the hardware
84     typedef struct _ENC_PREAMBLE
85     {
86     WORD NextPacketPointer;
87     RXSTATUS StatusVector;
88    
89     MAC_ADDR DestMACAddr;
90     MAC_ADDR SourceMACAddr;
91     WORD_VAL Type;
92     } ENC_PREAMBLE;
93    
94    
95     // Internal MAC level variables and flags.
96     static WORD_VAL NextPacketLocation;
97     static WORD_VAL CurrentPacketLocation;
98     static BOOL WasDiscarded;
99     #if defined(HI_TECH_C)
100     static BYTE ErrataTemp;
101     #endif
102    
103     /******************************************************************************
104     * Function: void MACInit(void)
105     *
106     * PreCondition: None
107     *
108     * Input: None
109     *
110     * Output: None
111     *
112     * Side Effects: None
113     *
114     * Overview: MACInit enables the Ethernet module, waits for the
115     * to become ready, and programs all registers for future
116     * TX/RX operations.
117     *
118     * Note: This function blocks for at least 1ms, waiting for the
119     * hardware to stabilize.
120     *****************************************************************************/
121     void MACInit(void)
122     {
123     BYTE i;
124    
125    
126     LATAbits.LATA0 = 0;
127     LATAbits.LATA1 = 0;
128     TRISAbits.TRISA0 = 0; // Set LED0 as output
129     TRISAbits.TRISA1 = 0; // Set LED1 as output
130     ECON2bits.ETHEN = 1; // Enable Ethernet!
131    
132     // Wait for PHYRDY to become set.
133     while(!ESTATbits.PHYRDY);
134    
135     // Configure the receive buffer boundary pointers
136     // and the buffer write protect pointer (receive buffer read pointer)
137     WasDiscarded = TRUE;
138     NextPacketLocation.Val = RXSTART;
139     ERXST = RXSTART;
140     ERXRDPTL = LOW(RXSTOP); // Write low byte first
141     ERXRDPTH = HIGH(RXSTOP);// Write high byte last
142     ERXND = RXSTOP;
143     ETXST = TXSTART;
144    
145     // Write a permanant per packet control byte of 0x00
146     EWRPT = TXSTART;
147     MACPut(0x00);
148    
149     // Configure Receive Filters
150     // (No need to reconfigure - Unicast OR Broadcast with CRC checking is
151     // acceptable)
152     //ERXFCON = ERXFCON_CRCEN; // Promiscious mode
153    
154     // Configure the MAC
155     // Enable the receive portion of the MAC
156     MACON1 = MACON1_TXPAUS | MACON1_RXPAUS | MACON1_MARXEN; Nop();
157    
158     // Pad packets to 60 bytes, add CRC, and check Type/Length field.
159     #if defined(FULL_DUPLEX)
160     MACON3 = MACON3_PADCFG0 | MACON3_TXCRCEN | MACON3_FRMLNEN | MACON3_FULDPX; Nop();
161     MABBIPG = 0x15; Nop();
162     #else
163     MACON3 = MACON3_PADCFG0 | MACON3_TXCRCEN | MACON3_FRMLNEN; Nop();
164     MABBIPG = 0x12; Nop();
165     #endif
166    
167     // Allow infinite deferals if the medium is continuously busy
168     // (do not time out a transmission if the half duplex medium is
169     // completely saturated with other people's data)
170     MACON4 = MACON4_DEFER; Nop();
171    
172     // Set non-back-to-back inter-packet gap to 9.6us. The back-to-back
173     // inter-packet gap (MABBIPG) is set by MACSetDuplex() which is called
174     // later.
175     MAIPGL = 0x12; Nop();
176     MAIPGH = 0x0C; Nop();
177    
178     // Set the maximum packet size which the controller will accept
179     MAMXFLL = LOW(6+6+2+1500+4); Nop();
180     MAMXFLH = HIGH(6+6+2+1500+4); Nop();
181    
182     // Initialize physical MAC address registers
183     MAADR1 = AppConfig.MyMACAddr.v[0]; Nop();
184     MAADR2 = AppConfig.MyMACAddr.v[1]; Nop();
185     MAADR3 = AppConfig.MyMACAddr.v[2]; Nop();
186     MAADR4 = AppConfig.MyMACAddr.v[3]; Nop();
187     MAADR5 = AppConfig.MyMACAddr.v[4]; Nop();
188     MAADR6 = AppConfig.MyMACAddr.v[5]; Nop();
189    
190     // Disable half duplex loopback in PHY and set RXAPDIS bit as per errata
191     WritePHYReg(PHCON2, PHCON2_HDLDIS | PHCON2_RXAPDIS);
192    
193     // Configure LEDA to display LINK status, LEDB to display TX/RX activity
194     SetLEDConfig(0x3472);
195    
196     // Set the PHY into the proper duplex state
197     #if defined(FULL_DUPLEX)
198     WritePHYReg(PHCON1, PHCON1_PDPXMD);
199     #else
200     WritePHYReg(PHCON1, 0x0000);
201     #endif
202    
203     // Enable packet reception
204     ECON1bits.RXEN = 1;
205     }//end MACInit
206    
207    
208     /******************************************************************************
209     * Function: BOOL MACIsLinked(void)
210     *
211     * PreCondition: None
212     *
213     * Input: None
214     *
215     * Output: TRUE: If the PHY reports that a link partner is present
216     * and the link has been up continuously since the last
217     * call to MACIsLinked()
218     * FALSE: If the PHY reports no link partner, or the link went
219     * down momentarily since the last call to MACIsLinked()
220     *
221     * Side Effects: None
222     *
223     * Overview: Returns the PHSTAT1.LLSTAT bit.
224     *
225     * Note: None
226     *****************************************************************************/
227     BOOL MACIsLinked(void)
228     {
229     // LLSTAT is a latching low link status bit. Therefore, if the link
230     // goes down and comes back up before a higher level stack program calls
231     // MACIsLinked(), MACIsLinked() will still return FALSE. The next
232     // call to MACIsLinked() will return TRUE (unless the link goes down
233     // again).
234     return ReadPHYReg(PHSTAT1).PHSTAT1bits.LLSTAT;
235     }
236    
237    
238     /******************************************************************************
239     * Function: BOOL MACIsTxReady(void)
240     *
241     * PreCondition: None
242     *
243     * Input: None
244     *
245     * Output: TRUE: If no Ethernet transmission is in progress
246     * FALSE: If a previous transmission was started, and it has
247     * not completed yet. While FALSE, the data in the
248     * transmit buffer and the TXST/TXND pointers must not
249     * be changed.
250     *
251     * Side Effects: None
252     *
253     * Overview: Returns the ECON1.TXRTS bit
254     *
255     * Note: None
256     *****************************************************************************/
257     BOOL MACIsTxReady(void)
258     {
259     return !ECON1bits.TXRTS;
260     }
261    
262    
263     /******************************************************************************
264     * Function: void MACDiscardRx(void)
265     *
266     * PreCondition: None
267     *
268     * Input: None
269     *
270     * Output: None
271     *
272     * Side Effects: None
273     *
274     * Overview: Marks the last received packet (obtained using
275     * MACGetHeader())as being processed and frees the buffer
276     * memory associated with it
277     *
278     * Note: None
279     *****************************************************************************/
280     void MACDiscardRx(void)
281     {
282     WORD_VAL NewRXRDLocation;
283    
284     // Make sure the current packet was not already discarded
285     if(WasDiscarded)
286     return;
287     WasDiscarded = TRUE;
288    
289     // Decrement the next packet pointer before writing it into
290     // the ERXRDPT registers. This is a silicon errata workaround.
291     // RX buffer wrapping must be taken into account if the
292     // NextPacketLocation is precisely RXSTART.
293     NewRXRDLocation.Val = NextPacketLocation.Val - 1;
294     #if RXSTART == 0
295     if(NewRXRDLocation.Val > RXSTOP)
296     #else
297     if(NewRXRDLocation.Val < RXSTART || NewRXRDLocation.Val > RXSTOP)
298     #endif
299     {
300     NewRXRDLocation.Val = RXSTOP;
301     }
302    
303     // Decrement the RX packet counter register, EPKTCNT
304     ECON2bits.PKTDEC = 1;
305    
306     // Move the receive read pointer to unwrite-protect the memory used by the
307     // last packet. The writing order is important: set the low byte first,
308     // high byte last.
309     ERXRDPTL = NewRXRDLocation.v[0];
310     ERXRDPTH = NewRXRDLocation.v[1];
311    
312     // The PKTIF flag should automatically be cleared by hardware, but
313     // early beta silicon requires that you manually clear it. This should be
314     // unneeded for production A0 silicon and later.
315     EIRbits.PKTIF = 0;
316     }
317    
318    
319     /******************************************************************************
320     * Function: WORD MACGetFreeRxSize(void)
321     *
322     * PreCondition: None
323     *
324     * Input: None
325     *
326     * Output: A WORD estimate of how much RX buffer space is free at
327     * the present time.
328     *
329     * Side Effects: None
330     *
331     * Overview: None
332     *
333     * Note: None
334     *****************************************************************************/
335     WORD MACGetFreeRxSize(void)
336     {
337     WORD_VAL ReadPT, WritePT;
338    
339     // Read the Ethernet hardware buffer write pointer. Because packets can be
340     // received at any time, it can change between reading the low and high
341     // bytes. A loop is necessary to make certain a proper low/high byte pair
342     // is read.
343     do {
344     // Save EPKTCNT in a temporary location
345     ReadPT.v[0] = EPKTCNT;
346    
347     WritePT.Val = ERXWRPT;
348     } while(EPKTCNT != ReadPT.v[0]);
349    
350     // Determine where the write protection pointer is
351     ReadPT.Val = ERXRDPT;
352    
353    
354     // Calculate the difference between the pointers, taking care to account
355     // for buffer wrapping conditions
356     if(WritePT.Val > ReadPT.Val)
357     {
358     return (RXSTOP - RXSTART) - (WritePT.Val - ReadPT.Val);
359     }
360     else if(WritePT.Val == ReadPT.Val)
361     {
362     return RXSIZE - 1;
363     }
364     else
365     {
366     return ReadPT.Val - WritePT.Val - 1;
367     }
368     }
369    
370     /******************************************************************************
371     * Function: BOOL MACGetHeader(MAC_ADDR *remote, BYTE* type)
372     *
373     * PreCondition: None
374     *
375     * Input: *remote: Location to store the Source MAC address of the
376     * received frame.
377     * *type: Location of a BYTE to store the constant
378     * MAC_UNKNOWN, ETHER_IP, or ETHER_ARP, representing
379     * the contents of the Ethernet type field.
380     *
381     * Output: TRUE: If a packet was waiting in the RX buffer. The
382     * remote, and type values are updated.
383     * FALSE: If a packet was not pending. remote and type are
384     * not changed.
385     *
386     * Side Effects: Last packet is discarded if MACDiscardRx() hasn't already
387     * been called.
388     *
389     * Overview: None
390     *
391     * Note: None
392     *****************************************************************************/
393     BOOL MACGetHeader(MAC_ADDR *remote, BYTE* type)
394     {
395     ENC_PREAMBLE header;
396    
397     // Test if at least one packet has been received and is waiting
398     if(EPKTCNT == 0u)
399     {
400     return FALSE;
401     }
402    
403     // Make absolutely certain that any previous packet was discarded
404     if(WasDiscarded == FALSE)
405     {
406     MACDiscardRx();
407     return FALSE;
408     }
409     // Save the location of this packet
410     CurrentPacketLocation.Val = NextPacketLocation.Val;
411    
412     // Set the read pointer to the beginning of the next unprocessed packet
413     ERDPT = CurrentPacketLocation.Val;
414    
415     // Obtain the MAC header from the Ethernet buffer
416     MACGetArray((BYTE*)&header, sizeof(header));
417    
418     // The EtherType field, like most items transmitted on the Ethernet medium
419     // are in big endian.
420     header.Type.Val = swaps(header.Type.Val);
421    
422     // Do a sanity check. There might be a bug in code someplace if this
423     // Reset() ever happens. Check for potential errors in array/pointer writing code.
424     if(header.NextPacketPointer > RXSTOP || ((BYTE_VAL*)(&header.NextPacketPointer))->bits.b0 ||
425     header.StatusVector.bits.Zero ||
426     header.StatusVector.bits.CRCError ||
427     header.StatusVector.bits.ByteCount > 1518u ||
428     !header.StatusVector.bits.ReceiveOk)
429     {
430     Reset();
431     }
432    
433     // Save the location where the hardware will write the next packet to
434     NextPacketLocation.Val = header.NextPacketPointer;
435    
436     // Return the Ethernet frame's Source MAC address field to the caller
437     // This parameter is useful for replying to requests without requiring an
438     // ARP cycle.
439     memcpy((void*)remote->v, (void*)header.SourceMACAddr.v, sizeof(*remote));
440    
441     // Return a simplified version of the EtherType field to the caller
442     *type = MAC_UNKNOWN;
443     if( (header.Type.v[1] == 0x08u) &&
444     ((header.Type.v[0] == ETHER_IP) || (header.Type.v[0] == ETHER_ARP)) )
445     {
446     *type = header.Type.v[0];
447     }
448    
449     // Mark this packet as discardable
450     WasDiscarded = FALSE;
451     return TRUE;
452     }
453    
454    
455     /******************************************************************************
456     * Function: void MACPutHeader(MAC_ADDR *remote, BYTE type, WORD dataLen)
457     *
458     * PreCondition: MACIsTxReady() must return TRUE.
459     *
460     * Input: *remote: Pointer to memory which contains the destination
461     * MAC address (6 bytes)
462     * type: The constant ETHER_ARP or ETHER_IP, defining which
463     * value to write into the Ethernet header's type field.
464     * dataLen: Length of the Ethernet data payload
465     *
466     * Output: None
467     *
468     * Side Effects: None
469     *
470     * Overview: None
471     *
472     * Note: Because of the dataLen parameter, it is probably
473     * advantagous to call this function immediately before
474     * transmitting a packet rather than initially when the
475     * packet is first created. The order in which the packet
476     * is constructed (header first or data first) is not
477     * important.
478     *****************************************************************************/
479     void MACPutHeader(MAC_ADDR *remote, BYTE type, WORD dataLen)
480     {
481     // Set the write pointer to the beginning of the transmit buffer
482     EWRPT = TXSTART + 1;
483    
484     // Calculate where to put the TXND pointer
485     dataLen += (WORD)sizeof(ETHER_HEADER) + TXSTART;
486    
487     // Write the TXND pointer into the registers, given the dataLen given
488     ETXND = dataLen;
489    
490     // Set the per-packet control byte and write the Ethernet destination
491     // address
492     MACPutArray((BYTE*)remote, sizeof(*remote));
493    
494     // Write our MAC address in the Ethernet source field
495     MACPutArray((BYTE*)&AppConfig.MyMACAddr, sizeof(AppConfig.MyMACAddr));
496    
497     // Write the appropriate Ethernet Type WORD for the protocol being used
498     MACPut(0x08);
499     MACPut((type == MAC_IP) ? ETHER_IP : ETHER_ARP);
500     }
501    
502     /******************************************************************************
503     * Function: void MACFlush(void)
504     *
505     * PreCondition: A packet has been created by calling MACPut() and
506     * MACPutHeader().
507     *
508     * Input: None
509     *
510     * Output: None
511     *
512     * Side Effects: None
513     *
514     * Overview: MACFlush causes the current TX packet to be sent out on
515     * the Ethernet medium. The hardware MAC will take control
516     * and handle CRC generation, collision retransmission and
517     * other details.
518     *
519     * Note: After transmission completes (MACIsTxReady() returns TRUE),
520     * the packet can be modified and transmitted again by calling
521     * MACFlush() again. Until MACPutHeader() or MACPut() is
522     * called (in the TX data area), the data in the TX buffer
523     * will not be corrupted.
524     *****************************************************************************/
525     void MACFlush(void)
526     {
527     // Start the transmission
528     // After transmission completes (MACIsTxReady() returns TRUE), the packet
529     // can be modified and transmitted again by calling MACFlush() again.
530     // Until MACPutHeader() is called, the data in the TX buffer will not be
531     // corrupted.
532     ECON1bits.TXRTS = 1;
533     }
534    
535    
536     /******************************************************************************
537     * Function: void MACSetReadPtrInRx(WORD offset)
538     *
539     * PreCondition: A packet has been obtained by calling MACGetHeader() and
540     * getting a TRUE result.
541     *
542     * Input: offset: WORD specifying how many bytes beyond the Ethernet
543     * header's type field to relocate the SPI read
544     * pointer.
545     *
546     * Output: None
547     *
548     * Side Effects: None
549     *
550     * Overview: SPI read pointer are updated. All calls to
551     * MACGet() and MACGetArray() will use these new values.
552     *
553     * Note: RXSTOP must be statically defined as being > RXSTART for
554     * this function to work correctly. In other words, do not
555     * define an RX buffer which spans the 0x1FFF->0x0000 memory
556     * boundary.
557     *****************************************************************************/
558     void MACSetReadPtrInRx(WORD offset)
559     {
560     WORD_VAL ReadPT;
561    
562     // Determine the address of the beginning of the entire packet
563     // and adjust the address to the desired location
564     ReadPT.Val = CurrentPacketLocation.Val + sizeof(ENC_PREAMBLE) + offset;
565    
566     // Since the receive buffer is circular, adjust if a wraparound is needed
567     if(ReadPT.Val > RXSTOP)
568     ReadPT.Val -= RXSIZE;
569    
570     // Set the read pointer to the new calculated value
571     ERDPTL = ReadPT.v[0];
572     ERDPTH = ReadPT.v[1];
573     }
574    
575    
576     /******************************************************************************
577     * Function: WORD MACSetWritePtr(WORD Address)
578     *
579     * PreCondition: None
580     *
581     * Input: Address: Address to seek to
582     *
583     * Output: WORD: Old EWRPT location
584     *
585     * Side Effects: None
586     *
587     * Overview: SPI write pointer is updated. All calls to
588     * MACPut() and MACPutArray() will use this new value.
589     *
590     * Note: None
591     *****************************************************************************/
592     WORD MACSetWritePtr(WORD address)
593     {
594     WORD oldVal;
595    
596     oldVal = EWRPT;
597     EWRPT = address;
598     return oldVal;
599     }
600    
601     /******************************************************************************
602     * Function: WORD MACSetReadPtr(WORD Address)
603     *
604     * PreCondition: None
605     *
606     * Input: Address: Address to seek to
607     *
608     * Output: WORD: Old ERDPT value
609     *
610     * Side Effects: None
611     *
612     * Overview: SPI write pointer is updated. All calls to
613     * MACPut() and MACPutArray() will use this new value.
614     *
615     * Note: None
616     *****************************************************************************/
617     WORD MACSetReadPtr(WORD address)
618     {
619     WORD oldVal;
620    
621     oldVal = ERDPT;
622     ERDPT = address;
623     return oldVal;
624     }
625    
626    
627     /******************************************************************************
628     * Function: WORD MACCalcRxChecksum(WORD offset, WORD len)
629     *
630     * PreCondition: None
631     *
632     * Input: offset - Number of bytes beyond the beginning of the
633     * Ethernet data (first byte after the type field)
634     * where the checksum should begin
635     * len - Total number of bytes to include in the checksum
636     *
637     * Output: 16-bit checksum as defined by RFC 793.
638     *
639     * Side Effects: None
640     *
641     * Overview: This function performs a checksum calculation in the MAC
642     * buffer itself
643     *
644     * Note: None
645     *****************************************************************************/
646     WORD MACCalcRxChecksum(WORD offset, WORD len)
647     {
648     WORD temp;
649     WORD RDSave;
650    
651     // Add the offset requested by firmware plus the Ethernet header
652     temp = CurrentPacketLocation.Val + sizeof(ENC_PREAMBLE) + offset;
653     if(temp > RXSTOP) // Adjust value if a wrap is needed
654     {
655     temp -= RXSIZE;
656     }
657    
658     RDSave = ERDPT;
659     ERDPT = temp;
660     temp = CalcIPBufferChecksum(len);
661     ERDPT = RDSave;
662    
663     return temp;
664     }
665    
666    
667     /******************************************************************************
668     * Function: WORD CalcIPBufferChecksum(WORD len)
669     *
670     * PreCondition: Read buffer pointer set to starting of checksum data
671     *
672     * Input: len: Total number of bytes to calculate the checksum over.
673     * The first byte included in the checksum is the byte
674     * pointed to by ERDPT, which is updated by calls to
675     * MACGet(), MACSetRxBuffer(), MACSetTxBuffer(), etc.
676     *
677     * Output: 16-bit checksum as defined by RFC 793
678     *
679     * Side Effects: None
680     *
681     * Overview: This function performs a checksum calculation in the MAC
682     * buffer itself. The MAC has a hardware DMA module
683     * which can calculate the checksum faster than software, so
684     * this function replaces the CaclIPBufferChecksum() function
685     * defined in the helpers.c file. Through the use of
686     * preprocessor defines, this replacement is automatic.
687     *
688     * Note: This function works either in the RX buffer area or the TX
689     * buffer area. No validation is done on the len parameter.
690     *****************************************************************************/
691     WORD CalcIPBufferChecksum(WORD len)
692     {
693     WORD_VAL temp;
694    
695     // Take care of special cases which the DMA cannot be used for
696     if(len == 0u)
697     {
698     return 0xFFFF;
699     }
700     else if(len == 1u)
701     {
702     return ~((WORD)MACGet());
703     }
704    
705    
706     // Set the DMA starting address to the RAM read pointer value
707     temp.Val = ERDPT;
708     EDMAST = temp.Val;
709    
710     // See if we are calculating a checksum within the RX buffer (where
711     // wrapping rules apply) or TX/unused area (where wrapping rules are
712     // not applied)
713     #if RXSTART == 0
714     if(temp.Val <= RXSTOP)
715     #else
716     if(temp.Val >= RXSTART && temp.Val <= RXSTOP)
717     #endif
718     {
719     // Calculate the DMA ending address given the starting address and len
720     // parameter. The DMA will follow the receive buffer wrapping boundary.
721     temp.Val += len-1;
722     if(temp.Val > RXSTOP)
723     {
724     temp.Val -= RXSIZE;
725     }
726     }
727     else
728     {
729     temp.Val += len-1;
730     }
731    
732     // Write the DMA end address
733     EDMAND = temp.Val;
734    
735     // Begin the DMA checksum calculation and wait until it is finished
736     ECON1bits.CSUMEN = 1;
737     ECON1bits.DMAST = 1;
738     while(ECON1bits.DMAST);
739    
740     // Return the resulting good stuff
741     return (((WORD)EDMACSL)<<8) | EDMACSH;
742     }
743    
744    
745     /******************************************************************************
746     * Function: WORD CalcIPBufferChecksum(WORD len)
747     *
748     * PreCondition: Read buffer pointer set to starting of checksum data
749     *
750     * Input: len: Total number of bytes to calculate the checksum over.
751     * The first byte included in the checksum is the byte
752     * pointed to by ERDPT, which is updated by calls to
753     * MACSetReadPtr(), MACGet(), MACGetArray(),
754     * MACGetHeader(), etc.
755     *
756     * Output: 16-bit checksum as defined by RFC 793
757     *
758     * Side Effects: None
759     *
760     * Overview: This function performs a checksum calculation in the MAC
761     * buffer itself
762     *
763     * Note: This function works either in the RX buffer area or the TX
764     * buffer area. No validation is done on the len parameter.
765     *****************************************************************************/
766     /*
767     WORD CalcIPBufferChecksum(WORD len)
768     {
769     WORD Start;
770     DWORD_VAL Checksum = {0x00000000ul};
771     WORD ChunkLen;
772     BYTE DataBuffer[20]; // Must be an even size
773     WORD *DataPtr;
774    
775     // Save the read pointer starting address
776     Start = ERDPT;
777    
778     while(len)
779     {
780     // Obtain a chunk of data (less SPI overhead compared
781     // to requesting one byte at a time)
782     ChunkLen = len > sizeof(DataBuffer) ? sizeof(DataBuffer) : len;
783     MACGetArray(DataBuffer, ChunkLen);
784    
785     len -= ChunkLen;
786    
787     // Take care of a last odd numbered data byte
788     if(((WORD_VAL*)&ChunkLen)->bits.b0)
789     {
790     DataBuffer[ChunkLen] = 0x00;
791     ChunkLen++;
792     }
793    
794     // Calculate the checksum over this chunk
795     DataPtr = (WORD*)&DataBuffer[0];
796     while(ChunkLen)
797     {
798     Checksum.Val += *DataPtr++;
799     ChunkLen -= 2;
800     }
801     }
802    
803     // Restore old read pointer location
804     ERDPT = Start;
805    
806     // Do an end-around carry (one's complement arrithmatic)
807     Checksum.Val = (DWORD)Checksum.w[0] + (DWORD)Checksum.w[1];
808    
809     // Do another end-around carry in case if the prior add
810     // caused a carry out
811     Checksum.w[0] += Checksum.w[1];
812    
813     // Return the resulting checksum
814     return ~Checksum.w[0];
815     }
816     */
817    
818     /******************************************************************************
819     * Function: void MACMemCopyAsync(WORD destAddr, WORD sourceAddr, WORD len)
820     *
821     * PreCondition: None
822     *
823     * Input: destAddr: Destination address in the Ethernet memory to
824     * copy to. If the MSb is set, the current EWRPT
825     * value will be used instead.
826     * sourceAddr: Source address to read from. If the MSb is
827     * set, the current ERDPT value will be used
828     * instead.
829     * len: Number of bytes to copy
830     *
831     * Output: Byte read from the ENC28J60's RAM
832     *
833     * Side Effects: None
834     *
835     * Overview: Bytes are asynchrnously transfered within the buffer. Call
836     * MACIsMemCopyDone() to see when the transfer is complete.
837     *
838     * Note: If a prior transfer is already in progress prior to
839     * calling this function, this function will block until it
840     * can start this transfer.
841     *****************************************************************************/
842     void MACMemCopyAsync(WORD destAddr, WORD sourceAddr, WORD len)
843     {
844     WORD_VAL ReadSave, WriteSave;
845     BOOL UpdateWritePointer = FALSE;
846     BOOL UpdateReadPointer = FALSE;
847    
848     if(((WORD_VAL*)&destAddr)->bits.b15)
849     {
850     UpdateWritePointer = TRUE;
851     destAddr = EWRPT;
852     }
853     if(((WORD_VAL*)&sourceAddr)->bits.b15)
854     {
855     UpdateReadPointer = TRUE;
856     sourceAddr = ERDPT;
857     }
858    
859     /*
860     ReadSave.Val = ERDPT;
861     WriteSave.Val = EWRPT;
862     ERDPT = sourceAddr;
863     EWRPT = destAddr;
864     while(len--)
865     MACPut(MACGet());
866     if(!UpdateReadPointer)
867     {
868     ERDPT = ReadSave.Val;
869     }
870     if(!UpdateWritePointer)
871     {
872     EWRPT = WriteSave.Val;
873     }
874     */
875    
876     // Handle special conditions where len == 0 or len == 1
877     // The DMA module is not capable of handling those corner cases
878     if(len <= 1u)
879     {
880     ReadSave.Val = ERDPT;
881     WriteSave.Val = EWRPT;
882     ERDPT = sourceAddr;
883     EWRPT = destAddr;
884     while(len--)
885     MACPut(MACGet());
886     if(!UpdateReadPointer)
887     {
888     ERDPT = ReadSave.Val;
889     }
890     if(!UpdateWritePointer)
891     {
892     EWRPT = WriteSave.Val;
893     }
894     }
895     else
896     {
897     if(UpdateWritePointer)
898     {
899     WriteSave.Val = destAddr + len;
900     EWRPT = WriteSave.Val;
901     }
902     len += sourceAddr - 1;
903     while(ECON1bits.DMAST);
904     EDMAST = sourceAddr;
905     EDMADST = destAddr;
906     if((sourceAddr <= RXSTOP) && (len > RXSTOP)) //&& (sourceAddr >= RXSTART))
907     len -= RXSIZE;
908     EDMAND = len;
909     ECON1bits.CSUMEN = 0;
910     ECON1bits.DMAST = 1;
911     if(UpdateReadPointer)
912     {
913     len++;
914     if((sourceAddr <= RXSTOP) && (len > RXSTOP)) //&& (sourceAddr >= RXSTART))
915     len -= RXSIZE;
916     ERDPT = len;
917     }
918     }
919     }
920    
921     BOOL MACIsMemCopyDone(void)
922     {
923     return !ECON1bits.DMAST;
924     }
925    
926     /******************************************************************************
927     * Function: BYTE MACGet()
928     *
929     * PreCondition: ERDPT must point to the place to read from.
930     *
931     * Input: None
932     *
933     * Output: Byte read from the Ethernet's buffer RAM
934     *
935     * Side Effects: None
936     *
937     * Overview: MACGet returns the byte pointed to by ERDPT and
938     * increments ERDPT so MACGet() can be called again. The
939     * increment will follow the receive buffer wrapping boundary.
940     *
941     * Note: For better performance, implement this function as a macro:
942     * #define MACGet() (EDATA)
943     *****************************************************************************/
944     BYTE MACGet()
945     {
946     return EDATA;
947     }//end MACGet
948    
949    
950     /******************************************************************************
951     * Function: WORD MACGetArray(BYTE *val, WORD len)
952     *
953     * PreCondition: ERDPT must point to the place to read from.
954     *
955     * Input: *val: Pointer to storage location
956     * len: Number of bytes to read from the data buffer.
957     *
958     * Output: Byte(s) of data read from the data buffer.
959     *
960     * Side Effects: None
961     *
962     * Overview: Reads several sequential bytes from the data buffer
963     * and places them into local memory. ERDPT is incremented
964     * after each byte, following the same rules as MACGet().
965     *
966     * Note: None
967     *****************************************************************************/
968     WORD MACGetArray(BYTE *val, WORD len)
969     {
970     WORD w = len;
971     BYTE i;
972    
973     if(val)
974     {
975     while(w--)
976     {
977     *val++ = EDATA;
978     }
979     }
980     else
981     {
982     while(w--)
983     {
984     i = EDATA;
985     }
986     }
987    
988     return len;
989     }//end MACGetArray
990    
991    
992     /******************************************************************************
993     * Function: void MACPut(BYTE val)
994     *
995     * PreCondition: EWRPT must point to the location to begin writing.
996     *
997     * Input: Byte to write into the Ethernet buffer memory
998     *
999     * Output: None
1000     *
1001     * Side Effects: None
1002     *
1003     * Overview: Writes to the EDATA register, which will indirectly
1004     * increment EWRPTH:EWRPTL.
1005     *
1006     * Note: For better performance, implement this function as a macro:
1007     * #define MACPut(a) EDATA = a
1008     *****************************************************************************/
1009     void MACPut(BYTE val)
1010     {
1011     // Note: Due to a PIC18F97J60 bug, you must use the MOVFF instruction to
1012     // write to EDATA or else the read pointer (ERDPT) will inadvertently
1013     // increment.
1014     #if defined(HI_TECH_C)
1015     ErrataTemp = val;
1016     asm("movff _ErrataTemp, _EDATA");
1017     #else
1018     _asm movff val, EDATA _endasm
1019     #endif
1020     }//end MACPut
1021    
1022    
1023     /******************************************************************************
1024     * Function: void MACPutArray(BYTE *val, WORD len)
1025     *
1026     * PreCondition: EWRPT must point to the location to begin writing.
1027     *
1028     * Input: *val: Pointer to source of bytes to copy.
1029     * len: Number of bytes to write to the data buffer.
1030     *
1031     * Output: None
1032     *
1033     * Side Effects: None
1034     *
1035     * Overview: MACPutArray writes several sequential bytes to the
1036     * Ethernet buffer RAM. It performs faster than multiple MACPut()
1037     * calls. EWRPT is incremented by len.
1038     *
1039     * Note: None
1040     *****************************************************************************/
1041     void MACPutArray(BYTE *val, WORD len)
1042     {
1043     while(len--)
1044     {
1045     // Note: Due to a PIC18F97J60 bug, you must use the MOVFF instruction to
1046     // write to EDATA or else the read pointer (ERDPT) will inadvertently
1047     // increment.
1048     #if defined(HI_TECH_C)
1049     ErrataTemp = *val++;
1050     asm("movff _ErrataTemp, _EDATA");
1051     #else
1052     BYTE i;
1053    
1054     i = *val++;
1055     _asm movff i, EDATA _endasm
1056     #endif
1057     }
1058     }//end MACPutArray
1059    
1060     void MACPutROMArray(ROM BYTE *val, WORD len)
1061     {
1062     while(len--)
1063     {
1064     // Note: Due to a PIC18F97J60 bug, you must use the MOVFF instruction to
1065     // write to EDATA or else the read pointer (ERDPT) will inadvertently
1066     // increment.
1067     #if defined(HI_TECH_C)
1068     ErrataTemp = *val++;
1069     asm("movff _ErrataTemp, _EDATA");
1070     #else
1071     BYTE i;
1072    
1073     i = *val++;
1074     _asm movff i, EDATA _endasm
1075     #endif
1076     }
1077     }//end MACPutArray
1078    
1079    
1080     /******************************************************************************
1081     * Function: ReadPHYReg
1082     *
1083     * PreCondition: Ethernet module must be enabled (ECON1.ETHEN = 1).
1084     *
1085     * Input: Address of the PHY register to read from.
1086     *
1087     * Output: 16 bits of data read from the PHY register.
1088     *
1089     * Side Effects: None
1090     *
1091     * Overview: ReadPHYReg performs an MII read operation. While in
1092     * progress, it simply polls the MII BUSY bit wasting time
1093     * (10.24us).
1094     *
1095     * Note: None
1096     *****************************************************************************/
1097     PHYREG ReadPHYReg(BYTE Register)
1098     {
1099     PHYREG Result;
1100    
1101     // Set the right address and start the register read operation
1102     MIREGADR = Register; Nop();
1103     MICMD = MICMD_MIIRD; Nop();
1104    
1105     // Loop to wait until the PHY register has been read through the MII
1106     // This requires 10.24us
1107     while(MISTATbits.BUSY);
1108    
1109     // Stop reading
1110     MICMD = 0x00; Nop();
1111    
1112     // Obtain results and return
1113     Result.VAL.v[0] = MIRDL;
1114     Nop();
1115     Result.VAL.v[1] = MIRDH;
1116    
1117     return Result;
1118     }//end ReadPHYReg
1119    
1120    
1121     /******************************************************************************
1122     * Function: WritePHYReg
1123     *
1124     * PreCondition: Ethernet module must be enabled (ECON1.ETHEN = 1).
1125     *
1126     * Input: Address of the PHY register to write to.
1127     * 16 bits of data to write to PHY register.
1128     *
1129     * Output: None
1130     *
1131     * Side Effects: None
1132     *
1133     * Overview: WritePHYReg performs an MII write operation. While in
1134     * progress, it simply polls the MII BUSY bit wasting time
1135     * (10.24us).
1136     *
1137     * Note: None
1138     *****************************************************************************/
1139     void WritePHYReg(BYTE Register, WORD Data)
1140     {
1141     // Write the register address
1142     MIREGADR = Register; Nop();
1143    
1144     // Write the data
1145     // Order is important: write low byte first, high byte last
1146     MIWRL = ((WORD_VAL*)&Data)->v[0]; Nop();
1147     MIWRH = ((WORD_VAL*)&Data)->v[1]; Nop();
1148    
1149     // Wait until the PHY register has been written
1150     // This operation requires 10.24us
1151     while(MISTATbits.BUSY);
1152     }//end WritePHYReg
1153    
1154    
1155     /******************************************************************************
1156     * Function: void MACPowerDown(void)
1157     *
1158     * PreCondition: None
1159     *
1160     * Input: None
1161     *
1162     * Output: None
1163     *
1164     * Side Effects: None
1165     *
1166     * Overview: MACPowerDown disables the Ethernet module.
1167     * All MAC and PHY registers should not be accessed.
1168     *
1169     * Note: Normally, this function would be called before putting the
1170     * PIC to sleep. If a packet is being transmitted while this
1171     * function is called, this function will block until it is
1172     * it complete. If anything is being received, it will be
1173     * completed.
1174     *
1175     * The Ethernet module will continue to draw significant
1176     * power in sleep mode if this function is not called first.
1177     *****************************************************************************/
1178     void MACPowerDown(void)
1179     {
1180     // Disable packet reception
1181     ECON1bits.RXEN = 0;
1182    
1183     // Make sure any last packet which was in-progress when RXEN was cleared
1184     // is completed
1185     while(ESTATbits.RXBUSY);
1186    
1187     // If a packet is being transmitted, wait for it to finish
1188     while(ECON1bits.TXRTS);
1189    
1190     // Disable the Ethernet module
1191     ECON2bits.ETHEN = 0;
1192     }//end MACPowerDown
1193    
1194     /******************************************************************************
1195     * Function: void MACPowerUp(void)
1196     *
1197     * PreCondition: None
1198     *
1199     * Input: None
1200     *
1201     * Output: None
1202     *
1203     * Side Effects: None
1204     *
1205     * Overview: MACPowerUp returns the Ethernet module back to normal operation
1206     * after a previous call to MACPowerDown(). Calling this
1207     * function when already powered up will have no effect.
1208     *
1209     * Note: If a link partner is present, it will take 10s of
1210     * milliseconds before a new link will be established after
1211     * waking up. While not linked, packets which are
1212     * transmitted will most likely be lost. MACIsLinked() can
1213     * be called to determine if a link is established.
1214     *****************************************************************************/
1215     void MACPowerUp(void)
1216     {
1217     // Power up the Ethernet module
1218     ECON2bits.ETHEN = 1;
1219    
1220     // Wait for PHY to become ready
1221     while(!ESTATbits.PHYRDY)
1222    
1223     // Enable packet reception
1224     ECON1bits.RXEN = 1;
1225     }//end MACPowerUp
1226    
1227    
1228    
1229     /******************************************************************************
1230     * Function: void SetRXHashTableEntry(MAC_ADDR DestMACAddr)
1231     *
1232     * PreCondition: SPI bus must be initialized (done in MACInit()).
1233     *
1234     * Input: DestMACAddr: 6 byte group destination MAC address to allow
1235     * through the Hash Table Filter
1236     *
1237     * Output: Sets the appropriate bit in the EHT* registers to allow
1238     * packets sent to DestMACAddr to be received if the Hash
1239     * Table receive filter is enabled
1240     *
1241     * Side Effects: None
1242     *
1243     * Overview: Calculates a CRC-32 using polynomial 0x4C11DB7 and then,
1244     * using bits 28:23 of the CRC, sets the appropriate bit in
1245     * the EHT* registers
1246     *
1247     * Note: This code is commented out to save code space on systems
1248     * that do not need this function. Change the "#if 0" line
1249     * to "#if 1" to uncomment it.
1250     *****************************************************************************/
1251     #if 0
1252     void SetRXHashTableEntry(MAC_ADDR DestMACAddr)
1253     {
1254     DWORD_VAL CRC = {0xFFFFFFFF};
1255     BYTE *HTRegister;
1256     BYTE i, j;
1257    
1258     // Calculate a CRC-32 over the 6 byte MAC address
1259     // using polynomial 0x4C11DB7
1260     for(i = 0; i < sizeof(MAC_ADDR); i++)
1261     {
1262     BYTE crcnext;
1263    
1264     // shift in 8 bits
1265     for(j = 0; j < 8; j++)
1266     {
1267     crcnext = 0;
1268     if(((BYTE_VAL*)&(CRC.v[3]))->bits.b7)
1269     crcnext = 1;
1270     crcnext ^= (((BYTE_VAL*)&DestMACAddr.v[i])->bits.b0);
1271    
1272     CRC.Val <<= 1;
1273     if(crcnext)
1274     CRC.Val ^= 0x4C11DB7;
1275     // next bit
1276     DestMACAddr.v[i] >>= 1;
1277     }
1278     }
1279    
1280     // CRC-32 calculated, now extract bits 28:23
1281     // Bits 25:23 define where within the Hash Table byte the bit needs to be set
1282     // Bits 28:26 define which of the 8 Hash Table bytes that bits 25:23 apply to
1283     i = CRC.v[3] & 0x1F;
1284     HTRegister = (i >> 2) + &EHT0;
1285     i = (i << 1) & 0x06;
1286     ((BYTE_VAL*)&i)->bits.b0 = ((BYTE_VAL*)&CRC.v[2])->bits.b7;
1287    
1288     // Set the proper bit in the Hash Table
1289     *HTRegister |= 1<<i;
1290     }
1291     #endif
1292    
1293    
1294    
1295     #endif //#if (defined(__18F97J60) || defined(__18F96J65) || defined(__18F96J60) || defined(__18F87J60) || defined(__18F86J65) || defined(__18F86J60) || defined(__18F67J60) || defined(__18F66J65) || defined(__18F66J60)) || defined(HI_TECH_C) && !defined(STACK_USE_SLIP)

  ViewVC Help
Powered by ViewVC 1.1.20