From 4085ae3ddfbbf10c8ccbd3dccd43452c40a1fe40 Mon Sep 17 00:00:00 2001 From: Yuval Adam Date: Fri, 13 Mar 2015 12:24:52 +0200 Subject: Add bootloader, nfclib and sensorlib --- boot_loader/bl_emac.c | 1914 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1914 insertions(+) create mode 100644 boot_loader/bl_emac.c (limited to 'boot_loader/bl_emac.c') diff --git a/boot_loader/bl_emac.c b/boot_loader/bl_emac.c new file mode 100644 index 0000000..c098da0 --- /dev/null +++ b/boot_loader/bl_emac.c @@ -0,0 +1,1914 @@ +//***************************************************************************** +// +// bl_emac.c - Functions to update via Ethernet. +// +// Copyright (c) 2013-2014 Texas Instruments Incorporated. All rights reserved. +// Software License Agreement +// +// Texas Instruments (TI) is supplying this software for use solely and +// exclusively on TI's microcontroller products. The software is owned by +// TI and/or its suppliers, and is protected under applicable copyright +// laws. You may not combine this software with "viral" open-source +// software in order to form a larger program. +// +// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS. +// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT +// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY +// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL +// DAMAGES, FOR ANY REASON WHATSOEVER. +// +// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package. +// +//***************************************************************************** + +#include +#include +#include +#include "bl_config.h" +#include "inc/hw_emac.h" +#include "inc/hw_flash.h" +#include "inc/hw_gpio.h" +#include "inc/hw_memmap.h" +#include "inc/hw_nvic.h" +#include "inc/hw_sysctl.h" +#include "inc/hw_types.h" +#include "driverlib/gpio.h" +#include "driverlib/pin_map.h" +#include "driverlib/emac.h" +#include "driverlib/sysctl.h" +#include "boot_loader/bl_decrypt.h" +#include "boot_loader/bl_flash.h" +#include "boot_loader/bl_hooks.h" +#include "driverlib/rom.h" +// +// Define ROM_SysCtlClockFreqSet() for snowflake RA0. Even though this function +// is deprecated in RA0 ROM, the function operates correctly when +// SYSCTL_MOSCCTL register is configured correctly prior to calling this +// function. +// +#if defined(TARGET_IS_TM4C129_RA0) +#define ROM_SysCtlClockFreqSet \ + ((uint32_t (*)(uint32_t ui32Config, \ + uint32_t ui32SysClock))ROM_SYSCTLTABLE[48]) +#endif + +// +// Define MAP_GPIOPadConfigSet() for the Boot Loader for Snowflake. +// This function fails in Snowflake for higher drive strengths, it will work +// properly for the instances where it is used here in the boot loader. +// +#if defined(TARGET_IS_TM4C129_RA0) || \ + defined(TARGET_IS_TM4C129_RA1) +#define ROM_GPIOPadConfigSet \ + ((void (*)(uint32_t ui32Port, \ + uint8_t ui8Pins, \ + uint32_t ui32Strength, \ + uint32_t ui32PadType))ROM_GPIOTABLE[5]) +#endif + +#include "driverlib/rom_map.h" + +//***************************************************************************** +// +//! \addtogroup bl_emac_api +//! @{ +// +//***************************************************************************** + +#if defined(ENET_ENABLE_UPDATE) || defined(DOXYGEN) +//***************************************************************************** +// +// Make sure that the crystal frequency is defined. +// +//***************************************************************************** +#if !defined(CRYSTAL_FREQ) +#error ERROR: CRYSTAL_FREQ must be defined for Ethernet update! +#endif + +//***************************************************************************** +// +// Make sure that boot loader update is not enabled (it is not supported via +// BOOTP given that there is no way to distinguish between a normal firmware +// image and a boot loader update image). +// +//***************************************************************************** +#if defined(ENABLE_BL_UPDATE) +#error ERROR: Updating the boot loader is not supported over Ethernet! +#endif + +//***************************************************************************** +// +// TFTP packets contain 512 bytes of data and a packet shorter than this +// indicates the end of the transfer. +// +//***************************************************************************** +#define TFTP_BLOCK_SIZE 512 + +//***************************************************************************** +// +// uIP uses memset, so a simple one is provided here. This is not as efficient +// as the one in the C library (from an execution time perspective), but it is +// much smaller. +// +//***************************************************************************** +void * +my_memset(void *pvDest, int iChar, size_t i32Length) +{ + int8_t *pi8Buf = (int8_t *)pvDest; + + // + // Fill the buffer with the given character. + // + while(i32Length--) + { + *pi8Buf++ = iChar; + } + + // + // Return a pointer to the beginning of the buffer. + // + return(pvDest); +} + +//***************************************************************************** +// +// uIP uses memcpy, so a simple one is provided here. This is not as efficient +// as the one in the C library (from an execution time perspective), but it is +// much smaller. +// +//***************************************************************************** +void * +my_memcpy(void *pvDest, const void *pvSrc, size_t i32Length) +{ + const int8_t *pi8Src = (const int8_t *)pvSrc; + int8_t *pi8Dest = (int8_t *)pvDest; + + // + // Copy bytes from the source buffer to the destination buffer. + // + while(i32Length--) + { + *pi8Dest++ = *pi8Src++; + } + + // + // Return a pointer to the beginning of the destination buffer. + // + return(pvDest); +} + +//***************************************************************************** +// +// Directly include the uIP code if using Ethernet for the update. This allows +// non-Ethernet boot loader builds to not have to supply the uip-conf.h file +// that would otherwise be required. +// +//***************************************************************************** +#define memcpy my_memcpy +#define memset my_memset +#undef htonl +#undef ntohl +#undef htons +#undef ntohs +#include "third_party/uip-1.0/uip/pt.h" +#include "third_party/uip-1.0/uip/uip_arp.c" +#undef BUF +#include "third_party/uip-1.0/uip/uip.c" + +//***************************************************************************** +// +// A prototype for the function (in the startup code) for a predictable length +// delay. +// +//***************************************************************************** +extern void Delay(uint32_t ui32Count); + +//***************************************************************************** +// +// Defines for setting up the system clock. +// +//***************************************************************************** +#define SYSTICKHZ 100 +#define SYSTICKMS (1000 / SYSTICKHZ) + +//***************************************************************************** +// +// UIP Timers (in ms) +// +//***************************************************************************** +#define UIP_PERIODIC_TIMER_MS 50 +#define UIP_ARP_TIMER_MS 10000 + +//***************************************************************************** +// +// This structure defines the fields in a BOOTP request/reply packet. +// +//***************************************************************************** +typedef struct +{ + // + // The operation; 1 is a request, 2 is a reply. + // + uint8_t ui8Op; + + // + // The hardware type; 1 is Ethernet. + // + uint8_t ui8HType; + + // + // The hardware address length; for Ethernet this will be 6, the length of + // the MAC address. + // + uint8_t ui8HLen; + + // + // Hop count, used by gateways for cross-gateway booting. + // + uint8_t ui8Hops; + + // + // The transaction ID. + // + uint32_t ui32XID; + + // + // The number of seconds elapsed since the client started trying to boot. + // + uint16_t ui16Secs; + + // + // The BOOTP flags. + // + uint16_t ui16Flags; + + // + // The client's IP address, if it knows it. + // + uint32_t ui32CIAddr; + + // + // The client's IP address, as assigned by the BOOTP server. + // + uint32_t ui32YIAddr; + + // + // The TFTP server's IP address. + // + uint32_t ui32SIAddr; + + // + // The gateway IP address, if booting cross-gateway. + // + uint32_t ui32GIAddr; + + // + // The hardware address; for Ethernet this is the MAC address. + // + uint8_t pui8CHAddr[16]; + + // + // The name, or nickname, of the server that should handle this BOOTP + // request. + // + char pcSName[64]; + + // + // The name of the boot file to be loaded via TFTP. + // + char pcFile[128]; + + // + // Optional vendor-specific area; not used for BOOTP. + // + uint8_t pui8Vend[64]; +} +tBOOTPPacket; + +//***************************************************************************** +// +// The BOOTP commands. +// +//***************************************************************************** +#define BOOTP_REQUEST 1 +#define BOOTP_REPLY 2 + +//***************************************************************************** +// +// The TFTP commands. +// +//***************************************************************************** +#define TFTP_RRQ 1 +#define TFTP_WRQ 2 +#define TFTP_DATA 3 +#define TFTP_ACK 4 +#define TFTP_ERROR 5 + +//***************************************************************************** +// +// The UDP ports used by the BOOTP protocol. +// +//***************************************************************************** +#define BOOTP_SERVER_PORT 67 +#define BOOTP_CLIENT_PORT 68 + +//***************************************************************************** +// +// The UDP port for the TFTP server. +// +//***************************************************************************** +#define TFTP_PORT 69 + +//***************************************************************************** +// +// The MAC address of the Ethernet interface. +// +//***************************************************************************** +#ifdef ENET_MAC_ADDR0 +static struct uip_eth_addr g_sMACAddr = +{ + { + ENET_MAC_ADDR0, + ENET_MAC_ADDR1, + ENET_MAC_ADDR2, + ENET_MAC_ADDR3, + ENET_MAC_ADDR4, + ENET_MAC_ADDR5 + } +}; +#else +static struct uip_eth_addr g_sMACAddr; +#endif + +//***************************************************************************** +// +// The number of SysTick interrupts since the start of the boot loader. +// +//***************************************************************************** +static uint32_t g_ui32Ticks; + +//***************************************************************************** +// +// The seed for the random number generator. +// +//***************************************************************************** +static uint32_t g_ui32RandomSeed; + +//***************************************************************************** +// +// The number of milliseconds since the last call to uip_udp_periodic(). +// +//***************************************************************************** +static volatile uint32_t g_ui32PeriodicTimer; + +//***************************************************************************** +// +// The number of milliseconds since the last call to uip_arp_timer(). +// +//***************************************************************************** +static volatile uint32_t g_ui32ARPTimer; + +//***************************************************************************** +// +// The transaction ID of the most recently sent out BOOTP request. +// +//***************************************************************************** +static uint32_t g_ui32XID; + +//***************************************************************************** +// +// The state for the proto-thread that handles the BOOTP process. +// +//***************************************************************************** +static struct pt g_sThread; + +//***************************************************************************** +// +// The amount of time to wait for a BOOTP reply before sending out a new BOOTP +// request. +// +//***************************************************************************** +static uint32_t g_ui32Delay; + +//***************************************************************************** +// +// The target time (relative to g_ui32Ticks) when the next timeout occurs. +// +//***************************************************************************** +static uint32_t g_ui32Target; + +//***************************************************************************** +// +// The IP address of the TFTP server. +// +//***************************************************************************** +static uip_ipaddr_t g_sServerAddr; + +//***************************************************************************** +// +// The name of the file to be read from the TFTP server. +// +//***************************************************************************** +static char g_pcFilename[128]; + +//***************************************************************************** +// +// The end of flash. If there is not a reserved block at the end of flash, +// this is the real end of flash. If there is a reserved block, this is the +// start of the reserved block (i.e. the virtual end of flash). +// +//***************************************************************************** +static uint32_t g_ui32FlashEnd; + +//***************************************************************************** +// +// The current block being read from the TFTP server. +// +//***************************************************************************** +static uint32_t g_ui32TFTPBlock; + +//***************************************************************************** +// +// The number of TFTP retries. +// +//***************************************************************************** +static uint32_t g_ui32TFTPRetries; + +//***************************************************************************** +// +// The UDP socket used to communicate with the BOOTP and TFTP servers (in +// sequence). +// +//***************************************************************************** +struct uip_udp_conn *g_pConn; + +//***************************************************************************** +// +// The current link status. +// +//***************************************************************************** +static uint32_t g_ui32Link; + +//***************************************************************************** +// +// Ethernet DMA descriptors. +// +// Although uIP uses a single buffer, the MAC hardware needs a minimum of +// 3 receive descriptors to operate. +// +//***************************************************************************** +#define NUM_TX_DESCRIPTORS 3 +#define NUM_RX_DESCRIPTORS 3 +tEMACDMADescriptor g_psRxDescriptor[NUM_TX_DESCRIPTORS]; +tEMACDMADescriptor g_psTxDescriptor[NUM_RX_DESCRIPTORS]; +uint32_t g_ui32RxDescIndex; +uint32_t g_ui32TxDescIndex; + +//***************************************************************************** +// +// Transmit and receive buffers. +// +//***************************************************************************** +#define RX_BUFFER_SIZE 1536 +#define TX_BUFFER_SIZE 1536 +uint8_t g_pui8RxBuffer[RX_BUFFER_SIZE]; +uint8_t g_pui8TxBuffer[TX_BUFFER_SIZE]; + +//***************************************************************************** +// +//! Handles the SysTick interrupt. +//! +//! This function is called when the SysTick interrupt occurs. It simply +//! keeps a running count of interrupts, used as a time basis for the BOOTP and +//! TFTP protocols. +//! +//! \return None. +// +//***************************************************************************** +void +SysTickIntHandler(void) +{ + // + // Increment the tick count. + // + g_ui32Ticks++; + g_ui32PeriodicTimer += SYSTICKMS; + g_ui32ARPTimer += SYSTICKMS; +} + +//***************************************************************************** +// +//! Computes a new random number. +//! +//! This function computes a new pseudo-random number, using a linear +//! congruence random number generator. Note that if the entire 32-bits of the +//! produced random number are not being used, the upper N bits should be used +//! instead of the lower N bits as they are much more random (for example, use +//! ``RandomNumber() >> 28'' instead of ``RandomNumber() & 15''). +//! +//! \return Returns a 32-bit pseudo-random number. +// +//***************************************************************************** +static uint32_t +RandomNumber(void) +{ + // + // Generate a new pseudo-random number with a linear congruence random + // number generator. This new random number becomes the seed for the next + // random number. + // + g_ui32RandomSeed = (g_ui32RandomSeed * 1664525) + 1013904223; + + // + // Return the new random number. + // + return(g_ui32RandomSeed); +} + +//***************************************************************************** +// +// Read a packet from the DMA receive buffer into the uIP packet buffer. +// +//***************************************************************************** +static int32_t +PacketReceive(uint8_t *pui8Buf, int32_t i32BufLen) +{ + int_fast32_t i32FrameLen, i32Loop; + + // + // By default, we assume we got a bad frame. + // + i32FrameLen = 0; + + // + // See if the receive descriptor contains a valid frame. Look for a + // descriptor error, indicating that the incoming packet was truncated or, + // if this is the last frame in a packet, the receive error bit. + // + if(!(g_psRxDescriptor[g_ui32RxDescIndex].ui32CtrlStatus & + DES0_RX_STAT_ERR)) + { + // + // We have a valid frame so copy the content to the supplied buffer. + // First check that the "last descriptor" flag is set. We sized the + // receive buffer such that it can always hold a valid frame so this + // flag should never be clear at this point but... + // + if(g_psRxDescriptor[g_ui32RxDescIndex].ui32CtrlStatus & + DES0_RX_STAT_LAST_DESC) + { + i32FrameLen = + ((g_psRxDescriptor[g_ui32RxDescIndex].ui32CtrlStatus & + DES0_RX_STAT_FRAME_LENGTH_M) >> + DES0_RX_STAT_FRAME_LENGTH_S); + + // + // Sanity check. This shouldn't be required since we sized the uIP + // buffer such that it's the same size as the DMA receive buffer + // but, just in case... + // + if(i32FrameLen > i32BufLen) + { + i32FrameLen = i32BufLen; + } + + // + // Copy the data from the DMA receive buffer into the provided + // frame buffer. + // + for(i32Loop = 0; i32Loop < i32FrameLen; i32Loop++) + { + pui8Buf[i32Loop] = g_pui8RxBuffer[i32Loop]; + } + } + } + + // + // Move on to the next descriptor in the chain. + // + g_ui32RxDescIndex++; + if(g_ui32RxDescIndex == NUM_RX_DESCRIPTORS) + { + g_ui32RxDescIndex = 0; + } + + // + // Mark the next descriptor in the ring as available for the receiver to + // write into. + // + g_psRxDescriptor[g_ui32RxDescIndex].ui32CtrlStatus = DES0_RX_CTRL_OWN; + + // + // Return the Frame Length + // + return(i32FrameLen); +} + +//***************************************************************************** +// +// Transmit a packet from the supplied buffer. +// +//***************************************************************************** +static int32_t +PacketTransmit(uint8_t *pui8Buf, int32_t i32BufLen) +{ + int_fast32_t i32Loop; + + // + // Wait for the previous packet to be transmitted. + // + while(g_psTxDescriptor[g_ui32TxDescIndex].ui32CtrlStatus & + DES0_TX_CTRL_OWN) + { + } + + // + // Check that we're not going to overflow the transmit buffer. This + // shouldn't be necessary since the uIP buffer is smaller than our DMA + // transmit buffer but, just in case... + // + if(i32BufLen > TX_BUFFER_SIZE) + { + i32BufLen = TX_BUFFER_SIZE; + } + + // + // Copy the packet data into the transmit buffer. + // + for(i32Loop = 0; i32Loop < i32BufLen; i32Loop++) + { + g_pui8TxBuffer[i32Loop] = pui8Buf[i32Loop]; + } + + // + // Move to the next descriptor. + // + g_ui32TxDescIndex++; + if(g_ui32TxDescIndex == NUM_TX_DESCRIPTORS) + { + g_ui32TxDescIndex = 0; + } + + // + // Fill in the packet size and tell the transmitter to start work. + // + g_psTxDescriptor[g_ui32TxDescIndex].ui32Count = (uint32_t)i32BufLen; + g_psTxDescriptor[g_ui32TxDescIndex].ui32CtrlStatus = + (DES0_TX_CTRL_LAST_SEG | DES0_TX_CTRL_FIRST_SEG | + DES0_TX_CTRL_INTERRUPT | DES0_TX_CTRL_IP_ALL_CKHSUMS | + DES0_TX_CTRL_CHAINED | DES0_TX_CTRL_OWN); + + // + // Tell the DMA to reacquire the descriptor now that we've filled it in. + // + ROM_EMACTxDMAPollDemand(EMAC0_BASE); + + // + // Return the number of bytes sent. + // + return(i32BufLen); +} + +//***************************************************************************** +// +//! Constructs and sends a BOOTP request packet. +//! +//! This function constructs a BOOTP request packet and sends it as a broadcast +//! message to the network. +//! +//! \return None. +// +//***************************************************************************** +static void +SendBOOTPRequest(void) +{ + uint8_t *pui8Packet = (uint8_t *)uip_appdata; + tBOOTPPacket *psBOOTP = (tBOOTPPacket *)uip_appdata; + uint32_t ui32Idx; + + // + // Zero fill the BOOTP request packet. + // + for(ui32Idx = 0; ui32Idx < sizeof(tBOOTPPacket); ui32Idx++) + { + pui8Packet[ui32Idx] = 0; + } + + // + // Construct a BOOTP request. + // + psBOOTP->ui8Op = BOOTP_REQUEST; + + // + // Set the hardware type to Ethernet. + // + psBOOTP->ui8HType = 0x01; + + // + // Set the hardware address length to 6. + // + psBOOTP->ui8HLen = 0x06; + + // + // Choose a random number for the transaction ID. + // + psBOOTP->ui32XID = g_ui32XID = RandomNumber(); + + // + // Set the number of seconds since we started. + // + psBOOTP->ui16Secs = HTONS(g_ui32Ticks / SYSTICKHZ); + + // + // Fill in the Ethernet MAC address. + // + for(ui32Idx = 0; ui32Idx < 6; ui32Idx++) + { + psBOOTP->pui8CHAddr[ui32Idx] = g_sMACAddr.addr[ui32Idx]; + } + + // + // Set the server name if defined. + // +#ifdef ENET_BOOTP_SERVER + for(ui32Idx = 0; + (psBOOTP->pcSName[ui32Idx] = ENET_BOOTP_SERVER[ui32Idx]) != 0; + ui32Idx++) + { + } +#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. +//! +//! \return Returns 1 if a valid BOOTP reply message was found and 0 otherwise. +// +//***************************************************************************** +static uint32_t +ParseBOOTPReply(void) +{ + tBOOTPPacket *psBOOTP = (tBOOTPPacket *)uip_appdata; + uint32_t ui32Idx; + + // + // See if this is a reply for our current BOOTP request. + // + if((psBOOTP->ui8Op != BOOTP_REPLY) || + (psBOOTP->ui32XID != g_ui32XID) || + (*(uint32_t *)psBOOTP->pui8CHAddr != *(uint32_t *)g_sMACAddr.addr) || + (*(uint16_t *)(psBOOTP->pui8CHAddr + 4) != + *(uint16_t *)(g_sMACAddr.addr + 4))) + { + return(0); + } + + // + // Extract our IP address from the response. + // + *((uint32_t *)(void *)(&uip_hostaddr)) = psBOOTP->ui32YIAddr; + + // + // Extract the server address from the response. + // + *((uint32_t *)(void *)(&g_sServerAddr)) = psBOOTP->ui32SIAddr; + + // + // Save the boot file name. + // + for(ui32Idx = 0; + ((g_pcFilename[ui32Idx] = psBOOTP->pcFile[ui32Idx]) != 0) && + (ui32Idx < (sizeof(g_pcFilename) - 1)); + ui32Idx++) + { + } + g_pcFilename[ui32Idx] = 0; + + // + // A valid BOOTP reply was found and decoded. + // + return(1); +} + + +//***************************************************************************** +// +//! Constructs and sends a TFTP error packet. +//! +//! This function constructs a TFTP read request packet (RRQ) and sends it to +//! the server. +//! +//! \return None. +// +//***************************************************************************** +static void +SendTFTPError(uint16_t ui16Error, char *pcString) +{ + uint8_t *pui8Packet = (uint8_t *)uip_appdata; + int32_t i32Len; + + pui8Packet[0] = (TFTP_ERROR >> 8) & 0xff; + pui8Packet[1] = TFTP_ERROR & 0xff; + pui8Packet[2] = (ui16Error >> 8) & 0xFF; + pui8Packet[3] = ui16Error & 0xFF; + + // + // Get ready to copy the error string. + // + i32Len = 4; + pui8Packet += 4; + + // + // Copy as much of the string as we can fit. + // + while((i32Len < (UIP_APPDATA_SIZE - 1)) && *pcString) + { + *pui8Packet++ = *pcString++; + i32Len++; + } + + // + // Write the terminating 0. + // + *pui8Packet = (uint8_t)0; + + // + // Send the error packet. + // + uip_udp_send(i32Len + 1); +} + +//***************************************************************************** +// +//! Constructs and sends a TFTP read packet. +//! +//! This function constructs a TFTP read request packet (RRQ) and sends it to +//! the server. +//! +//! \return None. +// +//***************************************************************************** +static void +SendTFTPGet(void) +{ + uint8_t *pui8Packet = (uint8_t *)uip_appdata; + uint32_t ui32Idx; + char *pcFilename; + + // + // The TFTP RRQ packet should be sent to the TFTP server port. + // + g_pConn->rport = HTONS(TFTP_PORT); + + // + // Set the TFTP packet opcode to RRQ. + // + pui8Packet[0] = (TFTP_RRQ >> 8) & 0xff; + pui8Packet[1] = TFTP_RRQ & 0xff; + + // + // Copy the file name into the RRQ packet. + // + for(ui32Idx = 2, pcFilename = g_pcFilename; + (pui8Packet[ui32Idx++] = *pcFilename++) != 0; ) + { + } + + // + // Set the transfer mode to binary. + // + for(pcFilename = "octet"; (pui8Packet[ui32Idx++] = *pcFilename++) != 0; ) + { + } + + // + // Send the TFTP read packet. + // + uip_udp_send(ui32Idx); +} + +//***************************************************************************** +// +//! 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. +//! +//! \return Returns 1 if this packet was the last packet of the TFTP data +//! transfer and 0 otherwise. +// +//***************************************************************************** +static uint32_t +ParseTFTPData(void) +{ + uint8_t *pui8Packet = (uint8_t *)uip_appdata; + uint32_t ui32FlashAddr; + uint32_t ui32Idx; + + // + // See if this is a TFTP data packet. + // + if((pui8Packet[0] != ((TFTP_DATA >> 8) && 0xff)) || + (pui8Packet[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((pui8Packet[2] != ((g_ui32TFTPBlock >> 8) & 0xff)) || + (pui8Packet[3] != (g_ui32TFTPBlock & 0xff))) + { + // + // Since the wrong data packet was sent, resend the ACK for it since + // we've already processed it. + // + pui8Packet[0] = (TFTP_ACK >> 8) & 0xff; + pui8Packet[1] = TFTP_ACK & 0xff; + uip_udp_send(4); + + // + // Ignore this packet. + // + return(0); + } + + // + // What address are we about to program to? + // + ui32FlashAddr = + ((g_ui32TFTPBlock - 1) * TFTP_BLOCK_SIZE) + APP_START_ADDRESS; + + // + // Do not program this data into flash if it is beyond the end of flash. + // + if(ui32FlashAddr < g_ui32FlashEnd) + { + // + // If this is the first block and we have been provided with a start + // hook function, call it here to indicate that we are about to begin + // flashing a new image. + // +#ifdef BL_START_FN_HOOK + if(g_ui32TFTPBlock == 1) + { + BL_START_FN_HOOK(); + } +#endif + + // + // Clear any flash error indicator. + // + BL_FLASH_CL_ERR_FN_HOOK(); + + // + // If this is the first data packet and code protection is enabled, + // then erase the entire flash. + // +#ifdef FLASH_CODE_PROTECTION + if(g_ui32TFTPBlock == 1) + { + // + // Loop through the pages in the flash, excluding the pages that + // contain the boot loader and the optional reserved space. + // + for(ui32Idx = APP_START_ADDRESS; ui32Idx < g_ui32FlashEnd; + ui32Idx += FLASH_PAGE_SIZE) + { + // + // Erase this block of the flash. + // + BL_FLASH_ERASE_FN_HOOK((ui32Idx); + } + } +#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. We + // assume that the flash block size is always a multiple of 1KB so, + // since each TFTP packet is 512 bytes and that the start must always + // be on a flash page boundary, we can be sure that we will hit the + // start of each page as we receive packets. + // + if(!(ui32FlashAddr & (FLASH_PAGE_SIZE - 1))) + { + // + // Erase this block of the flash. + // + BL_FLASH_ERASE_FN_HOOK(ui32FlashAddr); + } +#endif + + // + // Decrypt the data if required. + // +#ifdef BL_DECRYPT_FN_HOOK + BL_DECRYPT_FN_HOOK(pui8Packet + 4, uip_len - 4); +#endif + + // + // Program this block of data into flash. + // + BL_FLASH_PROGRAM_FN_HOOK(ui32FlashAddr, (pui8Packet + 4), + (uip_len - 4)); + + // + // If a progress reporting hook function has been provided, call it + // here. The TFTP protocol doesn't let us know how large the image is + // before it starts the transfer so we pass 0 as the ui32Total + // parameter to indicate this. + // +#ifdef BL_PROGRESS_FN_HOOK + BL_PROGRESS_FN_HOOK(((ui32FlashAddr - APP_START_ADDRESS) + + (uip_len - 4)), 0); +#endif + } + + // + // Increment to the next block. + // + g_ui32TFTPBlock++; + + // + // Save the packet length. + // + ui32Idx = uip_len; + + // + // Did we see any error? + // + if(BL_FLASH_ERROR_FN_HOOK()) + { + // + // Yes - send back an error packet. + // + SendTFTPError(2, "Error programming flash."); + } + else + { + // + // No errors reported so construct an ACK packet. The block number + // field is already correct, so it does not need to be set. + // + pui8Packet[0] = (TFTP_ACK >> 8) & 0xff; + pui8Packet[1] = TFTP_ACK & 0xff; + + // + // Send the ACK packet to the TFTP server. + // + uip_udp_send(4); + } + + // + // If the packet was shorter than TFTP_BLOCK_SIZE bytes then this was the + // last packet in the file. + // + if(ui32Idx != (TFTP_BLOCK_SIZE + 4)) + { + // + // If an end signal hook function has been provided, call it here. + // +#ifdef BL_END_FN_HOOK + BL_END_FN_HOOK(); +#endif + return(1); + } + // + // There is more data to be read. + // + return(0); +} + +uint16_t +LOCAL_EMACPHYRead(uint32_t ui32Base, uint8_t ui8PhyAddr, uint8_t ui8RegAddr) +{ + + // + // Make sure the MII is idle. + // + while(HWREG(ui32Base + EMAC_O_MIIADDR) & EMAC_MIIADDR_MIIB) + { + } + + // + // Tell the MAC to read the given PHY register. + // + HWREG(ui32Base + EMAC_O_MIIADDR) = + ((HWREG(ui32Base + EMAC_O_MIIADDR) & EMAC_MIIADDR_CR_M) | + (ui8RegAddr << EMAC_MIIADDR_MII_S) | + (ui8PhyAddr << EMAC_MIIADDR_PLA_S) | EMAC_MIIADDR_MIIB); + + // + // Wait for the read to complete. + // + while(HWREG(ui32Base + EMAC_O_MIIADDR) & EMAC_MIIADDR_MIIB) + { + } + + // + // Return the result. + // + return(HWREG(ui32Base + EMAC_O_MIIDATA) & EMAC_MIIDATA_DATA_M); +} + +//***************************************************************************** +// +//! 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 file name), then it communicates with the TFTP +//! server on the specified server to read the firmware image file. +//! +//! \return None. +// +//***************************************************************************** +#ifdef DOXYGEN +char +BOOTPThread(void) +#else +PT_THREAD(BOOTPThread(void)) +#endif +{ + // + // Begin the proto-thread. + // + PT_BEGIN(&g_sThread); + +wait_for_link: + PT_WAIT_UNTIL(&g_sThread, + (LOCAL_EMACPHYRead(EMAC0_BASE, 0, EPHY_BMSR) & + EPHY_BMSR_LINKSTAT) != 0); + + // + // Reset the host address. + // + *((uint32_t *)(void *)(&uip_hostaddr)) = 0; + + // + // Re-bind the UDP socket for sending requests to the BOOTP server. + // + uip_udp_remove(g_pConn); + *((uint32_t *)(void *)(&g_sServerAddr)) = 0xffffffff; + uip_udp_new(&g_sServerAddr, HTONS(BOOTP_SERVER_PORT)); + uip_udp_bind(g_pConn, HTONS(BOOTP_CLIENT_PORT)); + + // + // Set the initial delay between BOOTP requests to 1 second. + // + g_ui32Delay = 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_ui32Target = g_ui32Ticks + g_ui32Delay; + + // + // Wait until a packet is received or the timeout has occurred. + // +wait_for_bootp_reply: + PT_WAIT_UNTIL(&g_sThread, + ((g_ui32Link = (LOCAL_EMACPHYRead(EMAC0_BASE, 0, EPHY_BMSR) & + EPHY_BMSR_LINKSTAT)) == 0) || + uip_newdata() || (g_ui32Ticks > g_ui32Target)); + + // + // If the link has been lost, go back to waiting for a link. + // + if(g_ui32Link == 0) + { + goto wait_for_link; + } + + // + // 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; + } + + // + // This was not a BOOTP reply packet, so go back to waiting. + // + goto wait_for_bootp_reply; + } + + // + // 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_ui32Delay < (60 * SYSTICKHZ)) + { + g_ui32Delay *= 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)); + + // + // Send a TFTP read request. + // + SendTFTPGet(); + + // + // Since the first TFTP read request will result in an ARP request, delay + // for just a bit and then re-issue the TFTP read request. + // + PT_YIELD(&g_sThread); + + // + // Resend the TFTP read request. If the ARP request has already been + // answered, this will go out as is and avoid the two second timeout below. + // + SendTFTPGet(); + + // + // Start the TFTP transfer from block one. + // + g_ui32TFTPBlock = 1; + + // + // Set the number of TFTP retries to zero. + // + g_ui32TFTPRetries = 0; + + // + // Loop forever. This loop is explicitly exited when the TFTP transfer has + // completed. + // + while(1) + { + // + // Set the amount of time to wait for the TFTP data packet. + // + g_ui32Target = g_ui32Ticks + (SYSTICKHZ * 4); + + // + // Wait until a packet is received or the timeout has occurred. + // + PT_WAIT_UNTIL(&g_sThread, + ((g_ui32Link = (LOCAL_EMACPHYRead(EMAC0_BASE, 0, EPHY_BMSR) & + EPHY_BMSR_LINKSTAT)) == 0) || + uip_newdata() || (g_ui32Ticks > g_ui32Target)); + + // + // If the link has been lost, go back to waiting for a link. + // + if(g_ui32Link == 0) + { + goto wait_for_link; + } + + // + // 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 TFTP data packet. + // + if(ParseTFTPData() == 1) + { + break; + } + } + else if(g_ui32TFTPRetries < 3) + { + // + // The transfer timed out, so send a new TFTP read request. + // + SendTFTPGet(); + + // + // Start the TFTP transfer from block one. + // + g_ui32TFTPBlock = 1; + + // + // Increment the count of TFTP retries. + // + g_ui32TFTPRetries++; + } + else + { + // + // The TFTP transfer failed after three retries, so start over. + // + goto wait_for_link; + } + } + // + // Wait for the last packet to be transmitted. + // + while(g_psTxDescriptor[g_ui32TxDescIndex].ui32CtrlStatus & + DES0_TX_CTRL_OWN) + { + } + + // + // Wait for a bit to make sure that the final ACK packet is transmitted. + // + g_ui32Target = g_ui32Ticks + (SYSTICKHZ / 4); + while(g_ui32Ticks < g_ui32Target) + { + PT_YIELD(&g_sThread); + } + + // + // Perform a software reset request. This will cause the microcontroller + // to reset; no further code will be executed. + // + HWREG(NVIC_APINT) = NVIC_APINT_VECTKEY | NVIC_APINT_SYSRESETREQ; + + // + // The microcontroller should have reset, so this should never be reached. + // Just in case, loop forever. + // + while(1) + { + } + + // + // End the proto-thread. + // + PT_END(&g_sThread); +} + +static void +LOCAL_EMACPHYConfigSet(uint32_t ui32Base, uint32_t ui32Config) +{ + // + // Write the Ethernet PHY configuration to the peripheral configuration + // register. + // + HWREG(ui32Base + EMAC_O_PC) = ui32Config; + + // + // If using the internal PHY, reset it to ensure that new configuration is + // latched there. + // + if((ui32Config & EMAC_PHY_TYPE_MASK) == EMAC_PHY_TYPE_INTERNAL) + { + ROM_SysCtlPeripheralReset(SYSCTL_PERIPH_EPHY0); + while(!ROM_SysCtlPeripheralReady(SYSCTL_PERIPH_EPHY0)) + { + // + // Wait for the PHY reset to complete. + // + } + + // + // Delay a bit longer to ensure that the PHY reset has completed. + // + ROM_SysCtlDelay(1000); + } + + // + // If using an external RMII PHY, we must set 2 bits in the Ethernet MAC + // Clock Configuration Register. + // + if((ui32Config & EMAC_PHY_TYPE_MASK) == EMAC_PHY_TYPE_EXTERNAL_RMII) + { + // + // Select and enable the external clock from the RMII PHY. + // + HWREG(EMAC0_BASE + EMAC_O_CC) |= EMAC_CC_CLKEN; + } + else + { + // + // Disable the external clock. + // + HWREG(EMAC0_BASE + EMAC_O_CC) &= ~EMAC_CC_CLKEN; + } + + // + // Reset the MAC regardless of whether the PHY connection changed or not. + // + ROM_EMACReset(EMAC0_BASE); + + ROM_SysCtlDelay(1000); +} + +//***************************************************************************** +// +//! Reconfigures the Ethernet controller. +//! +//! \param ui32Clock is the system clock frequency. +//! +//! This function reconfigures the Ethernet controller, preparing it for use by +//! the boot loader. This performs the steps common between the direct +//! invocation of the boot loader and the application invocation of the boot +//! loader. +//! +//! \return None. +// +//***************************************************************************** +void +EnetReconfig(uint32_t ui32Clock) +{ + uip_ipaddr_t sAddr; + uint32_t ui32Loop; + uint32_t ui32User0, ui32User1; + + // + // Configure for use with the internal PHY. + // + LOCAL_EMACPHYConfigSet(EMAC0_BASE, + (EMAC_PHY_TYPE_INTERNAL | EMAC_PHY_INT_MDIX_EN | + EMAC_PHY_AN_100B_T_FULL_DUPLEX)); + + + // + // Reset the MAC. + // + ROM_EMACReset(EMAC0_BASE); + + // + // Initialize the MAC and set the DMA mode. + // + ROM_EMACInit(EMAC0_BASE, ui32Clock, + EMAC_BCONFIG_MIXED_BURST | EMAC_BCONFIG_PRIORITY_FIXED, 4, 4, 0); + + // + // Get the MAC address from the flash user registers. If it has not been + // programmed, then use the boot loader default MAC address. + // + ROM_FlashUserGet(&ui32User0, &ui32User1); + if((ui32User0 == 0xffffffff) || (ui32User1 == 0xffffffff)) + { + // + // MAC address has not been programmed, use default. + // + g_sMACAddr.addr[0] = 0x00; + g_sMACAddr.addr[1] = 0x1a; + g_sMACAddr.addr[2] = 0xb6; + g_sMACAddr.addr[3] = 0x00; + g_sMACAddr.addr[4] = 0x64; + g_sMACAddr.addr[5] = 0x00; + } + else + { + g_sMACAddr.addr[0] = ui32User0 & 0xff; + g_sMACAddr.addr[1] = (ui32User0 >> 8) & 0xff; + g_sMACAddr.addr[2] = (ui32User0 >> 16) & 0xff; + g_sMACAddr.addr[3] = ui32User1 & 0xff; + g_sMACAddr.addr[4] = (ui32User1 >> 8) & 0xff; + g_sMACAddr.addr[5] = (ui32User1 >> 16) & 0xff; + } + + // + // Set MAC configuration options. + // + ROM_EMACConfigSet(EMAC0_BASE, + (EMAC_CONFIG_FULL_DUPLEX | EMAC_CONFIG_CHECKSUM_OFFLOAD | + EMAC_CONFIG_7BYTE_PREAMBLE | EMAC_CONFIG_IF_GAP_96BITS | + EMAC_CONFIG_USE_MACADDR0 | EMAC_CONFIG_SA_FROM_DESCRIPTOR | + EMAC_CONFIG_BO_LIMIT_1024), + (EMAC_MODE_RX_STORE_FORWARD | EMAC_MODE_TX_STORE_FORWARD | + EMAC_MODE_TX_THRESHOLD_64_BYTES | + EMAC_MODE_RX_THRESHOLD_64_BYTES), 0); + + // + // Initialize each of the transmit descriptors. Note that we leave the OWN + // bit clear here since we have not set up any transmissions yet. + // + for(ui32Loop = 0; ui32Loop < NUM_TX_DESCRIPTORS; ui32Loop++) + { + g_psTxDescriptor[ui32Loop].ui32Count = + (DES1_TX_CTRL_SADDR_INSERT | + (TX_BUFFER_SIZE << DES1_TX_CTRL_BUFF1_SIZE_S)); + g_psTxDescriptor[ui32Loop].pvBuffer1 = g_pui8TxBuffer; + g_psTxDescriptor[ui32Loop].DES3.pLink = + (ui32Loop == (NUM_TX_DESCRIPTORS - 1)) ? + g_psTxDescriptor : &g_psTxDescriptor[ui32Loop + 1]; + g_psTxDescriptor[ui32Loop].ui32CtrlStatus = + (DES0_TX_CTRL_LAST_SEG | DES0_TX_CTRL_FIRST_SEG | + DES0_TX_CTRL_INTERRUPT | DES0_TX_CTRL_CHAINED | + DES0_TX_CTRL_IP_ALL_CKHSUMS); + } + + // + // Initialize each of the receive descriptors. We clear the OWN bit here + // to make sure that the receiver doesn't start writing anything + // immediately. + // + for(ui32Loop = 0; ui32Loop < NUM_RX_DESCRIPTORS; ui32Loop++) + { + g_psRxDescriptor[ui32Loop].ui32CtrlStatus = 0; + g_psRxDescriptor[ui32Loop].ui32Count = + (DES1_RX_CTRL_CHAINED | + (RX_BUFFER_SIZE << DES1_RX_CTRL_BUFF1_SIZE_S)); + g_psRxDescriptor[ui32Loop].pvBuffer1 = g_pui8RxBuffer; + g_psRxDescriptor[ui32Loop].DES3.pLink = + (ui32Loop == (NUM_RX_DESCRIPTORS - 1)) ? + g_psRxDescriptor : &g_psRxDescriptor[ui32Loop + 1]; + } + + // + // Set the descriptor pointers in the hardware. + // + ROM_EMACRxDMADescriptorListSet(EMAC0_BASE, g_psRxDescriptor); + ROM_EMACTxDMADescriptorListSet(EMAC0_BASE, g_psTxDescriptor); + + // + // Start from the beginning of both descriptor chains. We actually set + // the transmit descriptor index to the last descriptor in the chain + // since it will be incremented before use and this means the first + // transmission we perform will use the correct descriptor. + // + g_ui32RxDescIndex = 0; + g_ui32TxDescIndex = NUM_TX_DESCRIPTORS - 1; + + // + // Program the MAC address. + // + ROM_EMACAddrSet(EMAC0_BASE, 0, g_sMACAddr.addr); + + // + // Wait for the link to become active. + // + while((ROM_EMACPHYRead(EMAC0_BASE, 0, EPHY_BMSR) & + EPHY_BMSR_LINKSTAT) == 0) + { + } + + // + // Set MAC filtering options. We receive all broadcast and multicast + // packets along with those addressed specifically for us. + // + ROM_EMACFrameFilterSet(EMAC0_BASE, (EMAC_FRMFILTER_SADDR | + EMAC_FRMFILTER_PASS_MULTICAST | + EMAC_FRMFILTER_PASS_NO_CTRL)); + + // + // Seed the random number generator from the MAC address. + // + g_ui32RandomSeed = *(uint32_t *)(g_sMACAddr.addr + 2); + + // + // Initialize the uIP stack. + // + uip_init(); + uip_arp_init(); + + // + // Set the MAC address. + // + uip_setethaddr(g_sMACAddr); + + // + // Initialize the proto-thread used by the BOOTP protocol handler. + // + PT_INIT(&g_sThread); + + // + // Create a UDP socket for sending requests to the BOOTP server. After the + // BOOTP portion of the protocol has been handled, this socket will be + // reused to communicate with the TFTP server. + // + *((uint32_t *)(void *)(&sAddr)) = 0xffffffff; + g_pConn = uip_udp_new(&sAddr, HTONS(BOOTP_SERVER_PORT)); + uip_udp_bind(g_pConn, HTONS(BOOTP_CLIENT_PORT)); + + // + // Enable the Ethernet MAC transmitter and receiver. + // + ROM_EMACTxEnable(EMAC0_BASE); + ROM_EMACRxEnable(EMAC0_BASE); + + // + // Mark the first receive descriptor as available to the DMA to start + // the receive processing. + // + g_psRxDescriptor[g_ui32RxDescIndex].ui32CtrlStatus |= DES0_RX_CTRL_OWN; + + // + // Reset the counters that are incremented by SysTick. + // + g_ui32Ticks = 0; + g_ui32PeriodicTimer = 0; + g_ui32ARPTimer = 0; + + // + // Setup SysTick. + // + HWREG(NVIC_ST_RELOAD) = (ui32Clock / SYSTICKHZ) - 1; + HWREG(NVIC_ST_CTRL) = (NVIC_ST_CTRL_CLK_SRC | NVIC_ST_CTRL_INTEN | + NVIC_ST_CTRL_ENABLE); +} +//***************************************************************************** +// +//! Configures the Ethernet controller. +//! +//! This function configures the Ethernet controller, preparing it for use by +//! the boot loader. +//! +//! \return None. +// +//***************************************************************************** +void +ConfigureEnet(void) +{ + // + // Make sure the main oscillator is enabled because this is required by + // the PHY. The system must have a 25MHz crystal attached to the OSC + // pins. The SYSCTL_MOSC_HIGHFREQ parameter is used when the crystal + // frequency is 10MHz or higher. + // + HWREG(SYSCTL_MOSCCTL) = SYSCTL_MOSC_HIGHFREQ; + + // + // Delay while the main oscillator starts up. + // + Delay(5242880); + + MAP_SysCtlClockFreqSet((SYSCTL_XTAL_25MHZ | + SYSCTL_OSC_MAIN | + SYSCTL_USE_PLL | + SYSCTL_CFG_VCO_480), 120000000); + + +#ifdef ENET_ENABLE_LEDS + // + // PF1/PK4/PK6 are used for Ethernet LEDs. + // + ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF); + ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOK); + ROM_GPIOPinConfigure(GPIO_PF1_EN0LED2); + ROM_GPIOPinConfigure(GPIO_PK4_EN0LED0); + ROM_GPIOPinConfigure(GPIO_PK6_EN0LED1); + + // + // Make the pin(s) be peripheral controlled. + // + ROM_GPIODirModeSet(GPIO_PORTF_BASE, GPIO_PIN_1, GPIO_DIR_MODE_HW); + ROM_GPIODirModeSet(GPIO_PORTK_BASE, GPIO_PIN_4|GPIO_PIN_6, GPIO_DIR_MODE_HW); + + // + // Set the pad(s) for standard push-pull operation. + // + ROM_GPIOPadConfigSet(GPIO_PORTF_BASE, GPIO_PIN_1, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD); + ROM_GPIOPadConfigSet(GPIO_PORTK_BASE, GPIO_PIN_4|GPIO_PIN_6, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD); +#endif + + // + // Enable and reset the Ethernet modules. + // + ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_EMAC0); + ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_EPHY0); + ROM_SysCtlPeripheralReset(SYSCTL_PERIPH_EMAC0); + ROM_SysCtlPeripheralReset(SYSCTL_PERIPH_EPHY0); + + while(!ROM_SysCtlPeripheralReady(SYSCTL_PERIPH_EMAC0)) + { + } + +} + +//***************************************************************************** +// +//! Starts the update process via BOOTP. +//! +//! This function starts the Ethernet firmware update process. The BOOTP +//! (as defined by RFC951 at http://tools.ietf.org/html/rfc951) and TFTP (as +//! defined by RFC1350 at http://tools.ietf.org/html/rfc1350) protocols are +//! used to transfer the firmware image over Ethernet. +//! +//! \return Never returns. +// +//***************************************************************************** +void +UpdateBOOTP(void) +{ + // + // Get the size of flash. + // + g_ui32FlashEnd = ROM_SysCtlFlashSizeGet(); +#ifdef FLASH_RSVD_SPACE + g_ui32FlashEnd -= FLASH_RSVD_SPACE; +#endif + + // + // Perform the common Ethernet configuration. The frequency should + // match whatever the application sets the system clock. + // + EnetReconfig(120000000); + + // + // Main Application Loop. + // + while(1) + { + uint32_t ui32Temp; + + // + // See if there is a packet waiting to be read. + // + if(!(g_psRxDescriptor[g_ui32RxDescIndex].ui32CtrlStatus & + DES0_RX_CTRL_OWN)) + { + // + // Read the packet from the Ethernet controller. + // + uip_len = PacketReceive(uip_buf, UIP_CONF_BUFFER_SIZE); + + // + // See if this is an IP packet. + // + if((uip_len != 0) && + (((struct uip_eth_hdr *)&uip_buf[0])->type == + HTONS(UIP_ETHTYPE_IP))) + { + // + // Update the ARP tables based on this packet. + // + uip_arp_ipin(); + + // + // Process this packet. + // + uip_input(); + + // + // See if the processing of this packet resulted in a packet to be + // sent. + // + if(uip_len > 0) + { + // + // Update the ARP tables based on the packet to be sent. + // + uip_arp_out(); + + // + // Send the packet. + // + PacketTransmit(uip_buf, uip_len); + + // + // Indicate that the packet has been sent. + // + uip_len = 0; + } + } + + // + // See if this is an ARP packet. + // + else if((uip_len != 0) && + (((struct uip_eth_hdr *)&uip_buf[0])->type == + HTONS(UIP_ETHTYPE_ARP))) + { + // + // Process this packet. + // + uip_arp_arpin(); + + // + // See if the processing of this packet resulted in a packet to be + // sent. + // + if(uip_len > 0) + { + // + // Send the packet. + // + PacketTransmit(uip_buf, uip_len); + + // + // Indicate that the packet has been sent. + // + uip_len = 0; + } + } + } + + // + // See if the periodic timer has expired. + // + if(g_ui32PeriodicTimer > UIP_PERIODIC_TIMER_MS) + { + // + // Reset the periodic timer. + // + g_ui32PeriodicTimer = 0; + + // + // Loop through the UDP connections. + // + for(ui32Temp = 0; ui32Temp < UIP_UDP_CONNS; ui32Temp++) + { + // + // Perform the periodic processing on this UDP connection. + // + uip_udp_periodic(ui32Temp); + + // + // See if the periodic processing of this connection resulted in a + // packet to be sent. + // + if(uip_len > 0) + { + // + // Update the ARP tables based on the packet to be sent. + // + uip_arp_out(); + + // + // Send the packet. + // + PacketTransmit(uip_buf, uip_len); + + // + // Indicate that the packet has been sent. + // + uip_len = 0; + } + } + } + + // + // See if the ARP timer has expired. + // + if(g_ui32ARPTimer > UIP_ARP_TIMER_MS) + { + // + // Reset the ARP timer. + // + g_ui32ARPTimer = 0; + + // + // Perform periodic processing on the ARP table. + // + uip_arp_timer(); + } + } +} + +//***************************************************************************** +// +// Close the Doxygen group. +//! @} +// +//***************************************************************************** +#endif -- cgit v1.3.1