📄 bl_enet.c
字号:
for(lIdx = 2, lCount -= 4; lIdx < lCount; lIdx += 4)
{
*(unsigned long *)(uip_buf + lIdx) = HWREG(ETH_BASE + MAC_O_DATA);
}
//
// Read the final word from the FIFO, which contains part or all of the
// frame check sequence (which is ignored).
//
HWREG(ETH_BASE + MAC_O_DATA);
}
//*****************************************************************************
//
//! Writes a packet to the Ethernet controller.
//!
//! This function writes a packet from the uIP packet buffer into the Ethernet
//! controller and requests that the packet be transmitted. It will busy wait
//! until there is space in the transmit FIFO.
//!
//! This function is contained in <tt>bl_enet.c</tt>.
//!
//! \return None.
//
//*****************************************************************************
static void
EnetWritePacket(void)
{
long lIdx, lCount;
//
// Wait until there is space in the transmit FIFO.
//
while(HWREG(ETH_BASE + MAC_O_TR) & MAC_TR_NEWTX)
{
}
//
// Get the length of the packet.
//
lCount = uip_len;
//
// Write the first two bytes of the packet to the FIFO, along with the
// packet size.
//
HWREG(ETH_BASE + MAC_O_DATA) = ((*(unsigned short *)uip_buf << 16) |
(lCount - 14));
//
// Write the remaining bytes of the packet to the FIFO.
//
for(lIdx = 2; lIdx < lCount; lIdx += 4)
{
HWREG(ETH_BASE + MAC_O_DATA) = *(unsigned long *)(uip_buf + lIdx);
}
//
// Send the packet.
//
HWREG(ETH_BASE + MAC_O_TR) = MAC_TR_NEWTX;
}
//*****************************************************************************
//
//! Constructs and sends a BOOTP request packet.
//!
//! This function constructs a BOOTP request packet and sends it as a broadcast
//! message to the network.
//!
//! This function is contained in <tt>bl_enet.c</tt>.
//!
//! \return None.
//
//*****************************************************************************
static void
SendBOOTPRequest(void)
{
unsigned char *pucPacket = (unsigned char *)uip_appdata;
tBOOTPPacket *pBOOTP = (tBOOTPPacket *)uip_appdata;
unsigned long ulIdx;
//
// Zero fill the BOOTP request packet.
//
for(ulIdx = 0; ulIdx < sizeof(tBOOTPPacket); ulIdx++)
{
pucPacket[ulIdx] = 0;
}
//
// Construct a BOOTP request.
//
pBOOTP->ucOp = BOOTP_REQUEST;
//
// Set the hardware type to Ethernet.
//
pBOOTP->ucHType = 0x01;
//
// Set the hardware address length to 6.
//
pBOOTP->ucHLen = 0x06;
//
// Choose a random number for the transaction ID.
//
pBOOTP->ulXID = g_ulXID = RandomNumber();
//
// Set the number of seconds since we started.
//
pBOOTP->usSecs = HTONS(g_ulTicks / SYSTICKHZ);
//
// Fill in the Ethernet MAC address.
//
for(ulIdx = 0; ulIdx < 6; ulIdx++)
{
pBOOTP->pucCHAddr[ulIdx] = g_sMACAddr.addr[ulIdx];
}
//
// Set the server name if defined.
//
#ifdef ENET_BOOTP_SERVER
for(ulIdx = 0; (pBOOTP->pcSName[ulIdx] = ENET_BOOTP_SERVER[ulIdx]) != 0;
ulIdx++)
{
}
#endif
//
// Send the BOOTP request packet.
//
uip_udp_send(sizeof(tBOOTPPacket));
}
//*****************************************************************************
//
//! Parses a packet checking for a BOOTP reply message.
//!
//! This function parses a packet to determine if it is a BOOTP reply to our
//! currently outstanding BOOTP request. If a valid reply is found, the
//! appropriate information from the packet is extracted and saved.
//!
//! This function is contained in <tt>bl_enet.c</tt>.
//!
//! \return Returns 1 if a valid BOOTP reply message was found and 0 otherwise.
//
//*****************************************************************************
static unsigned long
ParseBOOTPReply(void)
{
tBOOTPPacket *pBOOTP = (tBOOTPPacket *)uip_appdata;
unsigned long ulIdx;
//
// See if this is a reply for our current BOOTP request.
//
if((pBOOTP->ucOp != BOOTP_REPLY) ||
(pBOOTP->ulXID != g_ulXID) ||
(*(unsigned long *)pBOOTP->pucCHAddr !=
*(unsigned long *)g_sMACAddr.addr) ||
(*(unsigned short *)(pBOOTP->pucCHAddr + 4) !=
*(unsigned short *)(g_sMACAddr.addr + 4)))
{
return(0);
}
//
// Extract our IP address from the response.
//
*((unsigned long *)(void *)(&uip_hostaddr)) = pBOOTP->ulYIAddr;
//
// Extract the server address from the response.
//
*((unsigned long *)(void *)(&g_sServerAddr)) = pBOOTP->ulSIAddr;
//
// Save the boot file name.
//
for(ulIdx = 0;
((g_pcFilename[ulIdx] = pBOOTP->pcFile[ulIdx]) != 0) &&
(ulIdx < (sizeof(g_pcFilename) - 1));
ulIdx++)
{
}
g_pcFilename[ulIdx] = 0;
//
// A valid BOOTP reply was found and decoded.
//
return(1);
}
//*****************************************************************************
//
//! Constructs and sends a TFTP read packet.
//!
//! This function constructs a TFTP read request packet (RRQ) and sends it to
//! the server.
//!
//! This function is contained in <tt>bl_enet.c</tt>.
//!
//! \return None.
//
//*****************************************************************************
static void
SendTFTPGet(void)
{
unsigned char *pucPacket = (unsigned char *)uip_appdata;
unsigned long ulIdx;
char *pcFilename;
//
// Set the TFTP packet opcode to RRQ.
//
pucPacket[0] = (TFTP_RRQ >> 8) & 0xff;
pucPacket[1] = TFTP_RRQ & 0xff;
//
// Copy the filename into the RRQ packet.
//
for(ulIdx = 2, pcFilename = g_pcFilename;
(pucPacket[ulIdx++] = *pcFilename++) != 0; )
{
}
//
// Set the transfer mode to binary.
//
for(pcFilename = "octet"; (pucPacket[ulIdx++] = *pcFilename++) != 0; )
{
}
//
// Send the TFTP read packet.
//
uip_udp_send(ulIdx);
}
//*****************************************************************************
//
//! Parses a packet checking for a TFTP data packet.
//!
//! This function parses a packet to determine if it is a TFTP data packet for
//! out current TFTP transfer. If a valid packet is found, the contents of the
//! packet are programmed into flash.
//!
//! This function is contained in <tt>bl_enet.c</tt>.
//!
//! \return Returns 1 if this packet was the last packet of the TFTP data
//! transfer and 0 otherwise.
//
//*****************************************************************************
static unsigned long
ParseTFTPData(void)
{
unsigned char *pucPacket = (unsigned char *)uip_appdata;
unsigned long ulIdx;
//
// See if this is a TFTP data packet.
//
if((pucPacket[0] != ((TFTP_DATA >> 8) && 0xff)) ||
(pucPacket[1] != (TFTP_DATA & 0xff)))
{
return(0);
}
//
// If the remote port on our connection is still the TFTP server port (i.e.
// this is the first data packet), then copy the transaction ID for the
// TFTP data connection into our connection. This will ensure that our
// response will be sent to the correct port.
//
if(g_pConn->rport == HTONS(TFTP_PORT))
{
g_pConn->rport =
((struct uip_udpip_hdr *)&uip_buf[UIP_LLH_LEN])->srcport;
}
//
// See if this is the correct data packet.
//
if((pucPacket[2] != ((g_ulTFTPBlock >> 8) & 0xff)) ||
(pucPacket[3] != (g_ulTFTPBlock & 0xff)))
{
//
// The wrong data packet was sent, so resend the ACK for the most
// recently received data packet (on the assumption that it was lost).
//
pucPacket[0] = (TFTP_ACK >> 8) & 0xff;
pucPacket[1] = TFTP_ACK & 0xff;
pucPacket[2] = (g_ulTFTPBlock >> 8) & 0xff;
pucPacket[3] = g_ulTFTPBlock & 0xff;
uip_udp_send(4);
//
// Ignore this packet.
//
return(0);
}
//
// Do not program this data into flash if it is beyond the end of flash.
//
if(((g_ulTFTPBlock - 1) * 512) < g_ulFlashEnd)
{
//
// If this is the first data packet and code protection is enabled,
// then erase the entire flash.
//
#ifdef FLASH_CODE_PROTECTION
if(g_ulTFTPBlock == 1)
{
//
// Loop through the pages in the flash, excluding the pages that
// contain the boot loader and the optional reserved space.
//
for(ulIdx = APP_START_ADDRESS; ulIdx < g_ulFlashEnd; ulIdx += 1024)
{
//
// Erase this block of the flash.
//
HWREG(FLASH_FMA) = ulIdx;
HWREG(FLASH_FMC) = FLASH_FMC_WRKEY | FLASH_FMC_ERASE;
//
// Wait until the flash has been erased.
//
while(HWREG(FLASH_FMC) & FLASH_FMC_ERASE)
{
}
}
}
#else
//
// Flash code protection is not enabled, so see if the data in this
// packet will be programmed to the beginning of a flash block.
//
if(g_ulTFTPBlock & 1)
{
//
// Erase this block of the flash.
//
HWREG(FLASH_FMA) = ((g_ulTFTPBlock - 1) * 512) + APP_START_ADDRESS;
HWREG(FLASH_FMC) = FLASH_FMC_WRKEY | FLASH_FMC_ERASE;
//
// Wait until the flash has been erased.
//
while(HWREG(FLASH_FMC) & FLASH_FMC_ERASE)
{
}
}
#endif
//
// Decrypt the data if required.
//
#ifdef ENABLE_DECRYPTION
DecryptData(pucPacket + 4, uip_len - 4);
#endif
//
// Loop through the data bytes in this packet.
//
for(ulIdx = 4; ulIdx < uip_len; ulIdx += 4)
{
//
// Program this word into flash.
//
HWREG(FLASH_FMA) = (((g_ulTFTPBlock - 1) * 512) +
APP_START_ADDRESS + ulIdx - 4);
HWREG(FLASH_FMD) = *(unsigned long *)(pucPacket + ulIdx);
HWREG(FLASH_FMC) = FLASH_FMC_WRKEY | FLASH_FMC_WRITE;
//
// Wait until the flash has been programmed.
//
while(HWREG(FLASH_FMC) & FLASH_FMC_WRITE)
{
}
}
}
//
// Increment to the next block.
//
g_ulTFTPBlock++;
//
// Save the packet length.
//
ulIdx = uip_len;
//
// Construct an ACK packet. The block number field is already correct, so
// it does not need to be set.
//
pucPacket[0] = (TFTP_ACK >> 8) & 0xff;
pucPacket[1] = TFTP_ACK & 0xff;
//
// Send the ACK packet to the TFTP server.
//
uip_udp_send(4);
//
// If the packet was shorter than 512 bytes then this was the last packet
// in the file.
//
if(ulIdx != 516)
{
return(1);
}
//
// There is more data to be read.
//
return(0);
}
//*****************************************************************************
//
//! Handles the BOOTP process.
//!
//! This function contains the proto-thread for handling the BOOTP process. It
//! first communicates with the BOOTP server to get its boot parameters (IP
//! address, server address, and filename), then it communicates with the TFTP
//! server on the specified server to read the firmware image file.
//!
//! This function is contained in <tt>bl_enet.c</tt>.
//!
//! \return None.
//
//*****************************************************************************
#ifdef DOXYGEN
char
BOOTPThread(void)
#else
PT_THREAD(BOOTPThread(void))
#endif
{
//
// Begin the proto-thread.
//
PT_BEGIN(&g_sThread);
//
// Set the initial delay between BOOTP requests to 1 second.
//
g_ulDelay = SYSTICKHZ;
//
// Loop forever. This loop is explicitly exited when a valid BOOTP reply
// is received.
//
while(1)
{
//
// Send a BOOTP request.
//
SendBOOTPRequest();
//
// Set the amount of time to wait for the BOOTP reply message.
//
g_ulTarget = g_ulTicks + g_ulDelay;
//
// Wait until a packet is received or the timeout has occurred.
//
PT_WAIT_UNTIL(&g_sThread, uip_newdata() || (g_ulTicks > g_ulTarget));
//
// See if a packet has been received.
//
if(uip_newdata())
{
//
// Clear the new data flag so that this packet will only be
// examined one time.
//
uip_flags &= ~(UIP_NEWDATA);
//
// See if this is a BOOTP reply.
//
if(ParseBOOTPReply() == 1)
{
break;
}
}
//
// If the delay between BOOTP requests is less than 60 seconds, double
// the delay time. This avoids constantly slamming the network with
// requests.
//
if(g_ulDelay < (60 * SYSTICKHZ))
{
g_ulDelay *= 2;
}
}
//
// Reconfigure the UDP socket to target the TFTP port on the server.
//
uip_ipaddr_copy(&g_pConn->ripaddr, g_sServerAddr);
uip_udp_bind(g_pConn, HTONS(13633));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -