enc28j60.c
来自「本附件为嵌入式Web的相关资料」· C语言 代码 · 共 1,923 行 · 第 1/4 页
C
1,923 行
*
* Overview: None
*
* Note: None
*****************************************************************************/
WORD MACGetFreeRxSize(void)
{
WORD_VAL ReadPT, WritePT;
// Read the Ethernet hardware buffer write pointer. Because packets can be
// received at any time, it can change between reading the low and high
// bytes. A loop is necessary to make certain a proper low/high byte pair
// is read.
BankSel(EPKTCNT);
do {
// Save EPKTCNT in a temporary location
ReadPT.v[0] = ReadETHReg((BYTE)EPKTCNT).Val;
BankSel(ERXWRPTL);
WritePT.v[0] = ReadETHReg(ERXWRPTL).Val;
WritePT.v[1] = ReadETHReg(ERXWRPTH).Val;
BankSel(EPKTCNT);
} while(ReadETHReg((BYTE)EPKTCNT).Val != ReadPT.v[0]);
// Determine where the write protection pointer is
BankSel(ERXRDPTL);
ReadPT.v[0] = ReadETHReg(ERXRDPTL).Val;
ReadPT.v[1] = ReadETHReg(ERXRDPTH).Val;
// Calculate the difference between the pointers, taking care to account
// for buffer wrapping conditions
if(WritePT.Val > ReadPT.Val)
{
return (RXSTOP - RXSTART) - (WritePT.Val - ReadPT.Val);
}
else if(WritePT.Val == ReadPT.Val)
{
return RXSIZE - 1;
}
else
{
return ReadPT.Val - WritePT.Val - 1;
}
}
/******************************************************************************
* Function: BOOL MACGetHeader(MAC_ADDR *remote, BYTE* type)
*
* PreCondition: None
*
* Input: *remote: Location to store the Source MAC address of the
* received frame.
* *type: Location of a BYTE to store the constant
* MAC_UNKNOWN, ETHER_IP, or ETHER_ARP, representing
* the contents of the Ethernet type field.
*
* Output: TRUE: If a packet was waiting in the RX buffer. The
* remote, and type values are updated.
* FALSE: If a packet was not pending. remote and type are
* not changed.
*
* Side Effects: Last packet is discarded if MACDiscardRx() hasn't already
* been called.
*
* Overview: None
*
* Note: None
*****************************************************************************/
BOOL MACGetHeader(MAC_ADDR *remote, BYTE* type)
{
ENC_PREAMBLE header;
BYTE PacketCount;
// Test if at least one packet has been received and is waiting
BankSel(EPKTCNT);
PacketCount = ReadETHReg((BYTE)EPKTCNT).Val;
BankSel(ERDPTL);
if(PacketCount == 0u)
return FALSE;
// Make absolutely certain that any previous packet was discarded
if(WasDiscarded == FALSE)
{
MACDiscardRx();
return FALSE;
}
// Set the SPI read pointer to the beginning of the next unprocessed packet
CurrentPacketLocation.Val = NextPacketLocation.Val;
WriteReg(ERDPTL, CurrentPacketLocation.v[0]);
WriteReg(ERDPTH, CurrentPacketLocation.v[1]);
// Obtain the MAC header from the Ethernet buffer
MACGetArray((BYTE*)&header, sizeof(header));
// The EtherType field, like most items transmitted on the Ethernet medium
// are in big endian.
header.Type.Val = swaps(header.Type.Val);
// Validate the data returned from the ENC28J60. Random data corruption,
// such as if a single SPI bit error occurs while communicating or a
// momentary power glitch could cause this to occur in rare circumstances.
if(header.NextPacketPointer > RXSTOP || ((BYTE_VAL*)(&header.NextPacketPointer))->bits.b0 ||
header.StatusVector.bits.Zero ||
header.StatusVector.bits.CRCError ||
header.StatusVector.bits.ByteCount > 1518u ||
!header.StatusVector.bits.ReceiveOk)
{
//***Reset();
MACInit();
return FALSE;
}
// Save the location where the hardware will write the next packet to
NextPacketLocation.Val = header.NextPacketPointer;
// Return the Ethernet frame's Source MAC address field to the caller
// This parameter is useful for replying to requests without requiring an
// ARP cycle.
memcpy((void*)remote->v, (void*)header.SourceMACAddr.v, sizeof(*remote));
// Return a simplified version of the EtherType field to the caller
*type = MAC_UNKNOWN;
if( (header.Type.v[1] == 0x08u) &&
((header.Type.v[0] == ETHER_IP) || (header.Type.v[0] == ETHER_ARP)) )
{
*type = header.Type.v[0];
}
// Mark this packet as discardable
WasDiscarded = FALSE;
return TRUE;
}
/******************************************************************************
* Function: void MACPutHeader(MAC_ADDR *remote, BYTE type, WORD dataLen)
*
* PreCondition: MACIsTxReady() must return TRUE.
*
* Input: *remote: Pointer to memory which contains the destination
* MAC address (6 bytes)
* type: The constant ETHER_ARP or ETHER_IP, defining which
* value to write into the Ethernet header's type field.
* dataLen: Length of the Ethernet data payload
*
* Output: None
*
* Side Effects: None
*
* Overview: None
*
* Note: Because of the dataLen parameter, it is probably
* advantagous to call this function immediately before
* transmitting a packet rather than initially when the
* packet is first created. The order in which the packet
* is constructed (header first or data first) is not
* important.
*****************************************************************************/
void MACPutHeader(MAC_ADDR *remote, BYTE type, WORD dataLen)
{
// Set the SPI write pointer to the beginning of the transmit buffer (post per packet control byte)
WriteReg(EWRPTL, LOW(TXSTART+1));
WriteReg(EWRPTH, HIGH(TXSTART+1));
// Calculate where to put the TXND pointer
dataLen += (WORD)sizeof(ETHER_HEADER) + TXSTART;
// Write the TXND pointer into the registers, given the dataLen given
WriteReg(ETXNDL, ((WORD_VAL*)&dataLen)->v[0]);
WriteReg(ETXNDH, ((WORD_VAL*)&dataLen)->v[1]);
// Set the per-packet control byte and write the Ethernet destination
// address
MACPutArray((BYTE*)remote, sizeof(*remote));
// Write our MAC address in the Ethernet source field
MACPutArray((BYTE*)&AppConfig.MyMACAddr, sizeof(AppConfig.MyMACAddr));
// Write the appropriate Ethernet Type WORD for the protocol being used
MACPut(0x08);
MACPut((type == MAC_IP) ? ETHER_IP : ETHER_ARP);
}
/******************************************************************************
* Function: void MACFlush(void)
*
* PreCondition: A packet has been created by calling MACPut() and
* MACPutHeader().
*
* Input: None
*
* Output: None
*
* Side Effects: None
*
* Overview: MACFlush causes the current TX packet to be sent out on
* the Ethernet medium. The hardware MAC will take control
* and handle CRC generation, collision retransmission and
* other details.
*
* Note: After transmission completes (MACIsTxReady() returns TRUE),
* the packet can be modified and transmitted again by calling
* MACFlush() again. Until MACPutHeader() or MACPut() is
* called (in the TX data area), the data in the TX buffer
* will not be corrupted.
*****************************************************************************/
void MACFlush(void)
{
// Reset transmit logic if a TX Error has previously occured
// This is a silicon errata workaround
if(ReadETHReg(EIR).EIRbits.TXERIF)
{
BFSReg(ECON1, ECON1_TXRST);
BFCReg(ECON1, ECON1_TXRST);
}
BFCReg(EIR, EIR_TXERIF | EIR_TXIF);
// Start the transmission
// After transmission completes (MACIsTxReady() returns TRUE), the packet
// can be modified and transmitted again by calling MACFlush() again.
// Until MACPutHeader() is called, the data in the TX buffer will not be
// corrupted.
BFSReg(ECON1, ECON1_TXRTS);
// Revision B5 and B7 silicon errata workaround
if(ENCRevID == 0x05u || ENCRevID == 0x06u)
{
while(!(ReadETHReg(EIR).Val & (EIR_TXERIF | EIR_TXIF)));
if(ReadETHReg(EIR).EIRbits.TXERIF)
{
WORD_VAL ReadPtrSave;
WORD_VAL TXEnd;
TXSTATUS TXStatus;
BYTE i;
// Cancel the previous transmission if it has become stuck set
BFCReg(ECON1, ECON1_TXRTS);
// Save the current read pointer (controlled by application)
ReadPtrSave.v[0] = ReadETHReg(ERDPTL).Val;
ReadPtrSave.v[1] = ReadETHReg(ERDPTH).Val;
// Get the location of the transmit status vector
TXEnd.v[0] = ReadETHReg(ETXNDL).Val;
TXEnd.v[1] = ReadETHReg(ETXNDH).Val;
TXEnd.Val++;
// Read the transmit status vector
WriteReg(ERDPTL, TXEnd.v[0]);
WriteReg(ERDPTH, TXEnd.v[1]);
MACGetArray((BYTE*)&TXStatus, sizeof(TXStatus));
// Implement retransmission if a late collision occured (this can
// happen on B5 when certain link pulses arrive at the same time
// as the transmission)
for(i = 0; i < 16u; i++)
{
if(ReadETHReg(EIR).EIRbits.TXERIF && TXStatus.bits.LateCollision)
{
// Reset the TX logic
BFSReg(ECON1, ECON1_TXRST);
BFCReg(ECON1, ECON1_TXRST);
BFCReg(EIR, EIR_TXERIF | EIR_TXIF);
// Transmit the packet again
BFSReg(ECON1, ECON1_TXRTS);
while(!(ReadETHReg(EIR).Val & (EIR_TXERIF | EIR_TXIF)));
// Cancel the previous transmission if it has become stuck set
BFCReg(ECON1, ECON1_TXRTS);
// Read transmit status vector
WriteReg(ERDPTL, TXEnd.v[0]);
WriteReg(ERDPTH, TXEnd.v[1]);
MACGetArray((BYTE*)&TXStatus, sizeof(TXStatus));
}
else
{
break;
}
}
// Restore the current read pointer
WriteReg(ERDPTL, ReadPtrSave.v[0]);
WriteReg(ERDPTH, ReadPtrSave.v[1]);
}
}
}
/******************************************************************************
* Function: void MACSetReadPtrInRx(WORD offset)
*
* PreCondition: A packet has been obtained by calling MACGetHeader() and
* getting a TRUE result.
*
* Input: offset: WORD specifying how many bytes beyond the Ethernet
* header's type field to relocate the SPI read
* pointer.
*
* Output: None
*
* Side Effects: None
*
* Overview: SPI read pointer are updated. All calls to
* MACGet() and MACGetArray() will use these new values.
*
* Note: RXSTOP must be statically defined as being > RXSTART for
* this function to work correctly. In other words, do not
* define an RX buffer which spans the 0x1FFF->0x0000 memory
* boundary.
*****************************************************************************/
void MACSetReadPtrInRx(WORD offset)
{
WORD_VAL ReadPT;
// Determine the address of the beginning of the entire packet
// and adjust the address to the desired location
ReadPT.Val = CurrentPacketLocation.Val + sizeof(ENC_PREAMBLE) + offset;
// Since the receive buffer is circular, adjust if a wraparound is needed
if(ReadPT.Val > RXSTOP)
ReadPT.Val -= RXSIZE;
// Set the SPI read pointer to the new calculated value
WriteReg(ERDPTL, ReadPT.v[0]);
WriteReg(ERDPTH, ReadPT.v[1]);
}
/******************************************************************************
* Function: WORD MACSetWritePtr(WORD Address)
*
* PreCondition: None
*
* Input: Address: Address to seek to
*
* Output: WORD: Old EWRPT location
*
* Side Effects: None
*
* Overview: SPI write pointer is updated. All calls to
* MACPut() and MACPutArray() will use this new value.
*
* Note: None
*****************************************************************************/
WORD MACSetWritePtr(WORD address)
{
WORD_VAL oldVal;
oldVal.v[0] = ReadETHReg(EWRPTL).Val;
oldVal.v[1] = ReadETHReg(EWRPTH).Val;
// Set the SPI write pointer to the new calculated value
WriteReg(EWRPTL, ((WORD_VAL*)&address)->v[0]);
WriteReg(EWRPTH, ((WORD_VAL*)&address)->v[1]);
return oldVal.Val;
}
/******************************************************************************
* Function: WORD MACSetReadPtr(WORD Address)
*
* PreCondition: None
*
* Input: Address: Address to seek to
*
* Output: WORD: Old ERDPT value
*
* Side Effects: None
*
* Overview: SPI write pointer is updated. All calls to
* MACPut() and MACPutArray() will use this new value.
*
* Note: None
*****************************************************************************/
WORD MACSetReadPtr(WORD address)
{
WORD_VAL oldVal;
oldVal.v[0] = ReadETHReg(ERDPTL).Val;
oldVal.v[1] = ReadETHReg(ERDPTH).Val;
// Set the SPI write pointer to the new calculated value
WriteReg(ERDPTL, ((WORD_VAL*)&address)->v[0]);
WriteReg(ERDPTH, ((WORD_VAL*)&address)->v[1]);
return oldVal.Val;
}
/******************************************************************************
* Function: WORD MACCalcRxChecksum(WORD offset, WORD len)
*
* PreCondition: None
*
* Input: offset - Number of bytes beyond the beginning of the
* Ethernet data (first byte after the type field)
* where the checksum should begin
* len - Total number of bytes to include in the checksum
*
* Output: 16-bit checksum as defined by RFC 793.
*
* Side Effects: None
*
* Overview: This function performs a checksum calculation in the MAC
* buffer itself
*
* Note: None
*****************************************************************************/
WORD MACCalcRxChecksum(WORD offset, WORD len)
{
WORD_VAL temp;
WORD_VAL RDSave;
// Add the offset requested by firmware plus the Ethernet header
temp.Val = CurrentPacketLocation.Val + sizeof(ENC_PREAMBLE) + offset;
if(temp.Val > RXSTOP) // Adjust value if a wrap is needed
{
temp.Val -= RXSIZE;
}
RDSave.v[0] = ReadETHReg(ERDPTL).Val;
RDSave.v[1] = ReadETHReg(ERDPTH).Val;
WriteReg(ERDPTL, temp.v[0]);
WriteReg(ERDPTH, temp.v[1]);
temp.Val = CalcIPBufferChecksum(len);
WriteReg(ERDPTL, RDSave.v[0]);
WriteReg(ERDPTH, RDSave.v[1]);
return temp.Val;
}
/******************************************************************************
* Function: WORD CalcIPBufferChecksum(WORD len)
*
* PreCondition: Read buffer pointer set to starting of checksum data
*
* Input: len: Total number of bytes to calculate the checksum over.
* The first byte included in the checksum is the byte
* pointed to by ERDPT, which is updated by calls to
* MACSetReadPtr(), MACGet(), MACGetArray(),
* MACGetHeader(), etc.
*
* Output: 16-bit checksum as defined by RFC 793
*
* Side Effects: None
*
* Overview: This function performs a checksum calculation in the MAC
* buffer itself. The ENC28J60 has a hardware DMA module
* which can calculate the checksum faster than software, so
* this function replaces the CaclIPBufferChecksum() function
* defined in the helpers.c file. Through the use of
* preprocessor defines, this replacement is automatic.
*
* Note: This function works either in the RX buffer area or the TX
* buffer area. No validation is done on the len parameter.
*****************************************************************************/
WORD CalcIPBufferChecksum(WORD len)
{
WORD_VAL Start;
DWORD_VAL Checksum = {0x00000000ul};
WORD ChunkLen;
BYTE DataBuffer[20]; // Must be an even size
WORD *DataPtr;
// Save the SPI read pointer starting address
Start.v[0] = ReadETHReg(ERDPTL).Val;
Start.v[1] = ReadETHReg(ERDPTH).Val;
while(len)
{
// Obtain a chunk of data (less SPI overhead compared
// to requesting one byte at a time)
ChunkLen = len > sizeof(DataBuffer) ? sizeof(DataBuffer) : len;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?