⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 bl_enet.c

📁 ARM-CORTEX LM3S系列远程下载更新程序
💻 C
📖 第 1 页 / 共 3 页
字号:
    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 + -