Tool/software:
Hi Team,
I trying to do firmware upgrade using ethernet bootloader code (boot_demo_emac_rom)(TM4C1294NCPDT),
The firmware upgrade is working fine using LM Flash in Ethernet,
But my requirement is to encrypt the HEX file using 128 bit ECB AES encryption,
The problem is I could not extract the payload that is Hex File DATA in the boot_demo_emac_rom code (swupdate.c file)
Can you please help me to get the payload data from which function, variable in this boot_demo_emac_rom and explain how this project will work
can You please help me to highlight which function, variable from where I need extract the TFTP Hex file data
I also attached my custom swupdate.c and boot_demo_emac_rom.c file for your reference
//*****************************************************************************
//
// swupdate.c - A module wrapping the Ethernet bootloader software update
// functionality.
//
// Copyright (c) 2008-2020 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.2.0.295 of the Tiva Utility Library.
//
//*****************************************************************************
#include <stdbool.h>
#include <stdint.h>
#include "inc/hw_aes.h"
#include "inc/hw_memmap.h"
#include "inc/hw_nvic.h"
#include "inc/hw_ints.h"
#include "inc/hw_sysctl.h"
#include "driverlib/debug.h"
#include "driverlib/gpio.h"
#include "driverlib/fpu.h"
#include "driverlib/interrupt.h"
#include "driverlib/pin_map.h"
#include "inc/hw_types.h"
#include "driverlib/flash.h"
#include "driverlib/rom.h"
#include "driverlib/sysctl.h"
#include "driverlib/systick.h"
#include "utils/lwiplib.h"
#include "utils/swupdate.h"
#include "driverlib/pin_map.h"
#include "driverlib/aes.h"
#include "driverlib/sysctl.h"
#include "driverlib/uart.h"
#include "driverlib/udma.h"
#include "driverlib/rom_map.h"
#include "utils/uartstdio.h"
int Binarydecryption(int8_t *pi8Datapayload, int8_t *pui8PlainText);
//*****************************************************************************
//
// Configuration defines.
//
//*****************************************************************************
#define CCM_LOOP_TIMEOUT 500000
//*****************************************************************************
//
// Sample plaintext, ciphertext, and key from the NIST SP 800-38A document.
//
//*****************************************************************************
uint32_t *g_pui32AES128Key = "aesEncryptionKey";
//*****************************************************************************
//
//! \addtogroup swupdate_api
//! @{
//
//*****************************************************************************
//*****************************************************************************
//
// The UDP port used to send the remote firmware update request signal. This
// is the well-known port associated with "discard" function and is also used
// by some Wake-On-LAN implementations.
//
//*****************************************************************************
#define MPACKET_PORT 9
//*****************************************************************************
//
// The length of the various parts of the remote firmware update request magic
// packet and its total length. This contains a 6 byte header followed by 4
// copies of the target MAC address.
//
//*****************************************************************************
#define MPACKET_HEADER_LEN 6
#define MPACKET_MAC_REP 4
#define MPACKET_MAC_LEN 6
#define MPACKET_LEN (MPACKET_HEADER_LEN + \
(MPACKET_MAC_REP * MPACKET_MAC_LEN))
//*****************************************************************************
//
// The marker byte used at the start of the magic packet. This is repeated
// MPACKET_HEADER_LEN times.
//
//*****************************************************************************
#define MPACKET_MARKER 0xAA
//*****************************************************************************
//
// The callback function which is used to determine whether or not the
// application wants to allow a remotely-requested firmware update.
//
//*****************************************************************************
tSoftwareUpdateRequested g_pfnUpdateCallback = NULL;
//*****************************************************************************
//
// A pointer to the remote firmware update signal PCB data structure.
//
//*****************************************************************************
static struct udp_pcb *g_psMagicPacketPCB = NULL;
//*****************************************************************************
//
// The MAC address for this board.
//
//*****************************************************************************
static uint8_t g_pui8MACAddr[6];
//*****************************************************************************
//
// Round up length to nearest 16 byte boundary. This is needed because all
// four data registers must be written at once. This is handled in the AES
// driver, but if using uDMA, the length must rounded up.
//
//*****************************************************************************
uint32_t
LengthRoundUp(uint32_t ui32Length)
{
uint32_t ui32Remainder;
ui32Remainder = ui32Length % 16;
if(ui32Remainder == 0)
{
return(ui32Length);
}
else
{
return(ui32Length + (16 - ui32Remainder));
}
}
//*****************************************************************************
//
// The AES interrupt handler and interrupt flags.
//
//*****************************************************************************
static volatile bool g_bContextInIntFlag;
static volatile bool g_bDataInIntFlag;
static volatile bool g_bContextOutIntFlag;
static volatile bool g_bDataOutIntFlag;
//*****************************************************************************
//
// Configure the UART and its pins. This must be called before UARTprintf().
//
//*****************************************************************************
void
ConfigureUART(void)
{
//
// Enable the GPIO Peripheral used by the UART.
//
MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
//
// Enable UART0
//
MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);
//
// Configure GPIO Pins for UART mode.
//
MAP_GPIOPinConfigure(GPIO_PA0_U0RX);
MAP_GPIOPinConfigure(GPIO_PA1_U0TX);
MAP_GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);
//
// Use the internal 16MHz oscillator as the UART clock source.
//
MAP_UARTClockSourceSet(UART0_BASE, UART_CLOCK_PIOSC);
//
// Initialize the UART for console I/O.
//
UARTStdioConfig(0, 115200, 16000000);
}
void
AESIntHandler(void)
{
uint32_t ui32IntStatus;
//
// Read the AES masked interrupt status.
//
ui32IntStatus = MAP_AESIntStatus(AES_BASE, true);
//
// Print a different message depending on the interrupt source.
//
if(ui32IntStatus & AES_INT_CONTEXT_IN)
{
MAP_AESIntDisable(AES_BASE, AES_INT_CONTEXT_IN);
g_bContextInIntFlag = true;
UARTprintf(" Context input registers are ready.\n");
}
if(ui32IntStatus & AES_INT_DATA_IN)
{
MAP_AESIntDisable(AES_BASE, AES_INT_DATA_IN);
g_bDataInIntFlag = true;
UARTprintf(" Data FIFO is ready to receive data.\n");
}
if(ui32IntStatus & AES_INT_CONTEXT_OUT)
{
MAP_AESIntDisable(AES_BASE, AES_INT_CONTEXT_OUT);
g_bContextOutIntFlag = true;
UARTprintf(" Context output registers are ready.\n");
}
if(ui32IntStatus & AES_INT_DATA_OUT)
{
MAP_AESIntDisable(AES_BASE, AES_INT_DATA_OUT);
g_bDataOutIntFlag = true;
UARTprintf(" Data FIFO is ready to provide data.\n");
}
}
//*****************************************************************************
//
// Perform an decryption operation.
//
//*****************************************************************************
bool
AESECBDecrypt(uint32_t ui32Keysize, uint32_t *pui32Src, uint32_t *pui32Dst,
uint32_t *pui32Key, uint32_t ui32Length, bool bUseDMA)
{
//
// Perform a soft reset.
//
MAP_AESReset(AES_BASE);
//
// Clear the interrupt flags.
//
g_bContextInIntFlag = false;
g_bDataInIntFlag = false;
g_bContextOutIntFlag = false;
g_bDataOutIntFlag = false;
//
// Enable all interrupts.
//
MAP_AESIntEnable(AES_BASE, (AES_INT_CONTEXT_IN | AES_INT_CONTEXT_OUT |
AES_INT_DATA_IN | AES_INT_DATA_OUT));
//
// Configure the AES module.
//
MAP_AESConfigSet(AES_BASE, (ui32Keysize | AES_CFG_DIR_DECRYPT |
AES_CFG_MODE_ECB));
//
// Write the key.
//
MAP_AESKey1Set(AES_BASE, pui32Key, ui32Keysize);
//
// Depending on the argument, perform the decryption
// with or without uDMA.
//
//
// Perform the decryption.
//
MAP_AESDataProcess(AES_BASE, pui32Src, pui32Dst, ui32Length);
return(true);
}
//*****************************************************************************
//
// Receives a UDP port 9 packet from lwIP.
//
// \param arg is not used in this implementation.
// \param pcb is the pointer to the UDB control structure.
// \param p is the pointer to the PBUF structure containing the packet data.
// \param addr is the source (remote) IP address for this packet.
// \param port is the source (remote) port for this packet.
//
// This function is called when the lwIP TCP/IP stack has an incoming
// UDP packet to be processed on the remote firmware update signal port.
//
// \return None.
//
//*****************************************************************************
static void
SoftwareUpdateUDPReceive(void *arg, struct udp_pcb *pcb, struct pbuf *p,
struct ip_addr *addr, u16_t port)
{
int8_t *encryptedpi8Data = NULL;//p->payload;
int8_t *pi8Data = p->payload;
int8_t *pi8payload = p->payload;
uint32_t ui32Loop, ui32MACLoop;
uint32_t ui32NewIPAddress;
int i=0;
//Binarydecryption(encryptedpi8Data,pi8Data);
ui32NewIPAddress = lwIPLocalIPAddrGet();
UARTprintf("IP Address: ");
DisplayIPAddress(ui32NewIPAddress);
UARTprintf("\n");
for(i=0;i< 512;i++)
{
UARTprintf("%x\t",*pi8Data & 0x000000FF);
pi8Data++;
if((i % 16) == 0)
{
UARTprintf("\n");
}
}
//
// Check that the packet length is what we expect. If not, ignore the
// packet.
//
if(p->len == MPACKET_LEN)
{
//
// The length matches so now look for the 6 byte header
//
for(ui32Loop = 0; ui32Loop < MPACKET_HEADER_LEN; ui32Loop++)
{
//
// Does this header byte match the expected marker?
//
if((*pi8Data & 0x000000FF)!= MPACKET_MARKER)
{
//
// No - free the buffer and return - this is not a packet
// we are interested in.
//
pbuf_free(p);
return;
}
else
{
//
// Byte matched so move on to the next one.
//
pi8Data++;
}
}
}
else
{
//
// No - free the buffer and return - this is not a packet
// we are interested in.
//
pbuf_free(p);
return;
}
//
// If we get here, the packet length and header markers indicate
// that this is a remote firmware update request. Now check that it
// is for us and that it contains the required number of copies of
// the MAC address.
//
UARTprintf("\n");
//
// Loop through each of the expected MAC address copies.
//
for(ui32Loop = 0; ui32Loop < MPACKET_MAC_REP; ui32Loop++)
{
//
// Loop through each byte of the MAC address in this
// copy.
//
for(ui32MACLoop = 0; ui32MACLoop < MPACKET_MAC_LEN; ui32MACLoop++)
{
//
// Does the payload MAC address byte match what we expect?
//
if((*pi8Data & 0x000000FF) != g_pui8MACAddr[ui32MACLoop])
{
//
// No match - free the packet and return.
//
pbuf_free(p);
return;
}
else
{
//
// Byte matched so move on to the next one.
//
pi8Data++;
}
}
}
//
// Free the pbuf since we are finished with it now.
//
pbuf_free(p);
//
// If we get this far, we've received a valid remote firmare update
// request targetted at this board. Signal this to the application
// if we have a valid callback pointer.
//
if(g_pfnUpdateCallback)
{
g_pfnUpdateCallback();
}
}
//*****************************************************************************
//
// Initialize the AES and CCM modules.
//
//*****************************************************************************
bool
AESInit(void)
{
uint32_t ui32Loop;
//
// Check that the CCM peripheral is present.
//
if(!MAP_SysCtlPeripheralPresent(SYSCTL_PERIPH_CCM0))
{
UARTprintf("No CCM peripheral found!\n");
//
// Return failure.
//
return(false);
}
//
// The hardware is available, enable it.
//
MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_CCM0);
//
// Wait for the peripheral to be ready.
//
ui32Loop = 0;
while(!MAP_SysCtlPeripheralReady(SYSCTL_PERIPH_CCM0))
{
//
// Increment our poll counter.
//
ui32Loop++;
if(ui32Loop > CCM_LOOP_TIMEOUT)
{
//
// Timed out, notify and spin.
//
UARTprintf("Time out on CCM ready after enable.\n");
//
// Return failure.
//
return(false);
}
}
//
// Reset the peripheral to ensure we are starting from a known condition.
//
MAP_SysCtlPeripheralReset(SYSCTL_PERIPH_CCM0);
//
// Wait for the peripheral to be ready again.
//
ui32Loop = 0;
while(!MAP_SysCtlPeripheralReady(SYSCTL_PERIPH_CCM0))
{
//
// Increment our poll counter.
//
ui32Loop++;
if(ui32Loop > CCM_LOOP_TIMEOUT)
{
//
// Timed out, spin.
//
UARTprintf("Time out on CCM ready after reset.\n");
//
// Return failure.
//
return(false);
}
}
//
// Return initialization success.
//
return(true);
}
int Binarydecryption(int8_t *pi8Datapayload, int8_t *pui8PlainText)
{
int8_t ui32Errors;
uint32_t ui32Keysize;
uint8_t ui8Loop;
//
// Initialize local variables.
//
ui32Errors = 0;
//
// Enable stacking for interrupt handlers. This allows floating-point
// instructions to be used within interrupt handlers, but at the expense of
// extra stack usage.
//
MAP_FPUStackingEnable();
//
// Configure the system clock to run off the internal 16MHz oscillator.
//
// MAP_SysCtlClockFreqSet(SYSCTL_OSC_INT | SYSCTL_USE_OSC, 16000000);
//
// Enable AES interrupts.
//
MAP_IntEnable(INT_AES0);
//
// Enable debug output on UART0 and print a welcome message.
//
UARTprintf("Starting AES ECB decryption demo.\n");
//
// Initialize the CCM and AES modules.
//
if(!AESInit())
{
UARTprintf("Initialization of the AES module failed.\n");
ui32Errors |= 0x00000001;
}
//
// Perform the same operation with 128bit key first, then 256bit key.
//
ui8Loop = 0;
ui32Keysize = (ui8Loop == 0)?AES_CFG_KEY_SIZE_128BIT:
AES_CFG_KEY_SIZE_256BIT;
UARTprintf("\nKey Size: %sbit\n", ((ui8Loop == 0)?"128":"256"));
//
// Clear the array containing the plaintext.
//
/*for(ui32Idx = 0; ui32Idx < 16; ui32Idx++)
{
pui32PlainText[ui32Idx] = 0;
}*/
//
// Perform the decryption without uDMA.
//
UARTprintf("Performing decryption without uDMA.\n");
/* AESECBDecrypt(ui32Keysize,
pi8Datapayload,
pui8PlainText,
g_pui32AES128Key,
64, false);*/
//
// Check the result.
//
/*for(ui32Idx = 0; ui32Idx < 16; ui32Idx++)
{
if(pui32PlainText[ui32Idx] != g_pui32AESPlainText[ui32Idx])
{
UARTprintf("Plaintext mismatch on word %d. Exp: 0x%x, Act: 0x%x\n",
ui32Idx, g_pui32AESPlainText[ui32Idx],
pui32PlainText[ui32Idx]);
ui32Errors |= (ui32Idx << 16) | 0x00000002;
}
}*/
//
// Clear the array containing the plaintext.
//
/*for(ui32Idx = 0; ui32Idx < 16; ui32Idx++)
{
pui32PlainText[ui32Idx] = 0;
}*/
//
// Finished.
//
if(ui32Errors)
{
UARTprintf("Demo failed with error code 0x%x.\n", ui32Errors);
}
else
{
UARTprintf("Demo completed successfully.\n");
}
}
//*****************************************************************************
//
//! Initializes the remote Ethernet software update notification feature.
//!
//! \param pfnCallback is a pointer to a function which will be called whenever
//! a remote firmware update request is received. If the application wishes
//! to allow the update to go ahead, it must call SoftwareUpdateBegin() from
//! non-interrupt context after the callback is received. Note that the
//! callback will most likely be made in interrupt context so it is not safe
//! to call SoftwareUpdateBegin() from within the callback itself.
//!
//! This function may be used on Ethernet-enabled parts to support
//! remotely-signaled firmware updates over Ethernet. The LM Flash Programmer
//! (LMFlash.exe) application sends a magic packet to UDP port 9 whenever the
//! user requests an Ethernet-based firmware update. This packet consists of
//! 6 bytes of 0xAA followed by the target MAC address repeated 4 times.
//! This function starts listening on UDP port 9 and, if a magic packet
//! matching the MAC address of this board is received, makes a call to the
//! provided callback function to indicate that an update has been requested.
//!
//! The callback function provided here will typically be called in the context
//! of the lwIP Ethernet interrupt handler. It is not safe to call
//! SoftwareUpdateBegin() in this context so the application should use the
//! callback to signal code running in a non-interrupt context to perform the
//! update if it is to be allowed.
//!
//! UDP port 9 is chosen for this function since this is the well-known port
//! associated with ``discard'' operation. In other words, any other system
//! receiving the magic packet will simply ignore it. The actual magic packet
//! used is modeled on Wake-On-LAN which uses a similar structure (6 bytes of
//! 0xFF followed by 16 repetitions of the target MAC address). Some
//! Wake-On-LAN implementations also use UDP port 9 for their signaling.
//!
//! \note Applications using this function must initialize the lwIP stack prior
//! to making this call and must ensure that the lwIPTimer() function is called
//! periodically. lwIP UDP must be enabled in lwipopts.h to ensure that the
//! magic packets can be received.
//!
//! \return None.
//
//*****************************************************************************
void
SoftwareUpdateInit(tSoftwareUpdateRequested pfnCallback)
{
uint32_t ui32User0, ui32User1;
//
// Remember the callback function pointer we have been given.
//
g_pfnUpdateCallback = pfnCallback;
//
// Get the MAC address from the user registers in NV ram.
//
FlashUserGet(&ui32User0, &ui32User1);
//
// Convert the 24/24 split MAC address from NV ram into a MAC address
// array.
//
g_pui8MACAddr[0] = ui32User0 & 0xff;
g_pui8MACAddr[1] = (ui32User0 >> 8) & 0xff;
g_pui8MACAddr[2] = (ui32User0 >> 16) & 0xff;
g_pui8MACAddr[3] = ui32User1 & 0xff;
g_pui8MACAddr[4] = (ui32User1 >> 8) & 0xff;
g_pui8MACAddr[5] = (ui32User1 >> 16) & 0xff;
//
// Set up a UDP PCB to allow us to receive the magic packets sent from
// LMFlash. These may be sent to port 9 from any port on the source
// machine so we do not call udp_connect here (since this causes lwIP to
// filter any packet that did not originate from port 9 too).
//
g_psMagicPacketPCB = udp_new();
udp_recv(g_psMagicPacketPCB, SoftwareUpdateUDPReceive, NULL);
udp_bind(g_psMagicPacketPCB, IP_ADDR_ANY, MPACKET_PORT);
}
//*****************************************************************************
//
//! Passes control to the bootloader and initiates a remote software update
//! over Ethernet.
//!
//! This function passes control to the bootloader and initiates an update of
//! the main application firmware image via BOOTP across Ethernet. This
//! function may only be used on parts supporting Ethernet and in cases where
//! the Ethernet boot loader is in use alongside the main application image.
//! It must not be called in interrupt context.
//!
//! Applications wishing to make use of this function must be built to
//! operate with the bootloader. If this function is called on a system
//! which does not include the bootloader, the results are unpredictable.
//!
//! \note It is not safe to call this function from within the callback
//! provided on the initial call to SoftwareUpdateInit(). The application
//! must use the callback to signal a pending update (assuming the update is to
//! be permitted) to some other code running in a non-interrupt context.
//!
//! \return Never returns.
//
//*****************************************************************************
void
SoftwareUpdateBegin(uint32_t ui32SysClock)
{
//
// Disable all processor interrupts. Instead of disabling them
// one at a time (and possibly missing an interrupt if new sources
// are added), a direct write to NVIC is done to disable all
// peripheral interrupts.
//
HWREG(NVIC_DIS0) = 0xffffffff;
HWREG(NVIC_DIS1) = 0xffffffff;
HWREG(NVIC_DIS2) = 0xffffffff;
HWREG(NVIC_DIS3) = 0xffffffff;
HWREG(NVIC_DIS4) = 0xffffffff;
//
// Also disable the SysTick interrupt.
//
SysTickIntDisable();
SysTickDisable();
//
// Return control to the boot loader. This is a call to the SVC
// handler in the flashed-based boot loader, or to the ROM if configured.
//
#if ((defined ROM_UpdateEMAC) && !(defined USE_FLASH_BOOT_LOADER))
ROM_UpdateEMAC(ui32SysClock);
#else
(*((void (*)(void))(*(uint32_t *)0x2c)))();
#endif
}
//*****************************************************************************
//
// Close the Doxygen group.
//! @}
//
//*****************************************************************************
//*****************************************************************************
//
// boot_demo_emac_rom.c - Example demonstrating the use of the ROM Ethernet
// boot loader.
//
// Copyright (c) 2008-2020 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.2.0.295 of the EK-TM4C1294XL Firmware Package.
//
//*****************************************************************************
#include <stdbool.h>
#include <stdint.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/debug.h"
#include "driverlib/flash.h"
#include "driverlib/gpio.h"
#include "driverlib/interrupt.h"
#include "driverlib/pin_map.h"
#include "driverlib/rom.h"
#include "driverlib/rom_map.h"
#include "driverlib/sysctl.h"
#include "driverlib/uart.h"
#include "utils/lwiplib.h"
#include "utils/swupdate.h"
#include "utils/ustdlib.h"
#include "utils/uartstdio.h"
#include "drivers/pinout.h"
//*****************************************************************************
//
//! \addtogroup example_list
//! <h1>ROM Boot Loader Ethernet Demo (boot_demo_emac_rom)</h1>
//!
//! An example to demonstrate the use of remote update signaling with the
//! ROM-based Ethernet boot loader. This application configures the Ethernet
//! controller and acquires an IP address. It then listens for a
//! ``magic packet'' telling it that a firmware upgrade request is being made
//! and, when this packet is received, transfers control to the ROM boot loader
//! to perform the upgrade.
//
//*****************************************************************************
//*****************************************************************************
//
// The number of SysTick ticks per second.
//
//*****************************************************************************
#define TICKS_PER_SECOND 100
//****************************************************************************
//
// The variable g_ui32SysClock contains the system clock frequency in Hz.
//
//****************************************************************************
uint32_t g_ui32SysClock;
//*****************************************************************************
//
// A global flag used to indicate if a remote firmware update request has been
// received.
//
//*****************************************************************************
static volatile bool g_bFirmwareUpdate = false;
//*****************************************************************************
//
// Buffers used to hold the Ethernet MAC and IP addresses for the board.
//
//*****************************************************************************
#define SIZE_MAC_ADDR_BUFFER 32
#define SIZE_IP_ADDR_BUFFER 32
char g_pcMACAddr[SIZE_MAC_ADDR_BUFFER];
char g_pcIPAddr[SIZE_IP_ADDR_BUFFER];
//*****************************************************************************
//
// The error routine that is called if the driver library encounters an error.
//
//*****************************************************************************
#ifdef DEBUG
void
__error__(char *pcFilename, uint32_t ui32Line)
{
}
#endif
//*****************************************************************************
//
// This is the handler for this SysTick interrupt. We use this to provide the
// required timer call to the lwIP stack.
//
//*****************************************************************************
void
SysTickIntHandler(void)
{
//
// Call the lwIP timer.
//
//
lwIPTimer(1000 / TICKS_PER_SECOND);
}
//*****************************************************************************
//
// This function is called by the software update module whenever a remote
// host requests to update the firmware on this board. We set a flag that
// will cause the main loop to exit and transfer control to the boot loader.
//
// IMPORTANT:
// Note that this callback is made in interrupt context and, since it is not
// permitted to transfer control to the boot loader from within an interrupt,
// we can't just call SoftwareUpdateBegin() here.
//
//*****************************************************************************
void
SoftwareUpdateRequestCallback(void)
{
g_bFirmwareUpdate = true;
}
void
DisplayIPAddress(uint32_t ui32Addr)
{
char pcBuf[16];
//
// Convert the IP Address into a string.
//
usprintf(pcBuf, "%d.%d.%d.%d", ui32Addr & 0xff, (ui32Addr >> 8) & 0xff,
(ui32Addr >> 16) & 0xff, (ui32Addr >> 24) & 0xff);
//
// Display the string.
//
UARTprintf(pcBuf);
}
//*****************************************************************************
//
// Perform the initialization steps required to start up the Ethernet controller
// and lwIP stack.
//
//*****************************************************************************
void
SetupForEthernet(void)
{
uint32_t ui32User0, ui32User1;
uint8_t pui8MACAddr[6];
//
// Configure SysTick for a 100Hz interrupt.
//
MAP_SysTickPeriodSet(g_ui32SysClock / TICKS_PER_SECOND);
MAP_SysTickEnable();
MAP_SysTickIntEnable();
//
// Get the MAC address from the UART0 and UART1 registers in NV ram.
//
MAP_FlashUserGet(&ui32User0, &ui32User1);
//
// Convert the 24/24 split MAC address from NV ram into a MAC address
// array.
//
pui8MACAddr[0] = ui32User0 & 0xff;
pui8MACAddr[1] = (ui32User0 >> 8) & 0xff;
pui8MACAddr[2] = (ui32User0 >> 16) & 0xff;
pui8MACAddr[3] = ui32User1 & 0xff;
pui8MACAddr[4] = (ui32User1 >> 8) & 0xff;
pui8MACAddr[5] = (ui32User1 >> 16) & 0xff;
//
// Format this address into the string used by the relevant widget.
//
usnprintf(g_pcMACAddr, SIZE_MAC_ADDR_BUFFER,
"MAC: %02X-%02X-%02X-%02X-%02X-%02X",
pui8MACAddr[0], pui8MACAddr[1], pui8MACAddr[2], pui8MACAddr[3],
pui8MACAddr[4], pui8MACAddr[5]);
//
// Remember that we don't have an IP address yet.
//
usnprintf(g_pcIPAddr, SIZE_IP_ADDR_BUFFER, "IP: Not assigned");
//
// Initialize the lwIP TCP/IP stack.
//
lwIPInit(g_ui32SysClock, pui8MACAddr, 0, 0xFFFFFF00, 0, IPADDR_USE_DHCP);
//
// Start the remote software update module.
//
SoftwareUpdateInit(SoftwareUpdateRequestCallback);
}
//*****************************************************************************
//
// A simple application demonstrating use of the boot loader.
//
//*****************************************************************************
int
main(void)
{
//
// Enable lazy stacking for interrupt handlers. This allows floating-point
// instructions to be used within interrupt handlers, but at the expense of
// extra stack usage.
//
MAP_FPULazyStackingEnable();
//
// Run from the PLL at 120 MHz.
// Note: SYSCTL_CFG_VCO_240 is a new setting provided in TivaWare 2.2.x and
// later to better reflect the actual VCO speed due to SYSCTL#22.
//
g_ui32SysClock = MAP_SysCtlClockFreqSet((SYSCTL_XTAL_25MHZ |
SYSCTL_OSC_MAIN |
SYSCTL_USE_PLL |
SYSCTL_CFG_VCO_240), 120000000);
//
// Configure the device pins.
//
PinoutSet(true, false);
//
// Configure debug port for internal use.
//
UARTStdioConfig(0, 115200, g_ui32SysClock);
//
// Clear the terminal and print a banner.
//
UARTprintf("\033[2J\033[H");
UARTprintf("Ethernet Boot-loader\n\n");
//
// Initialize the peripherals for the Ethernet boot loader.
//
SetupForEthernet();
//
// Configure Port N pin 1 as output.
//
MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPION);
while(!(MAP_SysCtlPeripheralReady(SYSCTL_PERIPH_GPION)));
MAP_GPIOPinTypeGPIOOutput(GPIO_PORTN_BASE, GPIO_PIN_1);
//
// If the Switch SW1 is not pressed then blink the LED D1 at 1 Hz rate.
// On switch SW1 press detection exit the blinking program and jump to
// the flash boot loader.
//
while(!g_bFirmwareUpdate)
{
MAP_GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_1, 0x0);
MAP_SysCtlDelay(g_ui32SysClock / 6);
MAP_GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_1, GPIO_PIN_1);
MAP_SysCtlDelay(g_ui32SysClock / 6);
}
//
// Before passing control make sure that the LED is turned OFF.
//
MAP_GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_1, 0x0);
//
// Pass control to whichever flavor of boot loader the board is configured
// with.
//
SoftwareUpdateBegin(g_ui32SysClock);
//
// The previous function never returns but we need to stick in a return
// code here to keep the compiler from generating a warning.
//
return(0);
}
And I also have a doubt is there any link between boot_demo_emac_rom and boot_emac_flash projects and
bl_emac.c file
//*****************************************************************************
//
// bl_emac.c - Functions to update via Ethernet.
//
// Copyright (c) 2013-2020 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.2.0.295 of the Tiva Firmware Development Package.
//
//*****************************************************************************
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#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
//
// Define ROM_EMACInit for the bootloader of Snowflake RA0. This function is
// deprecated in RA0 ROM, as it does not disable some interrupts that are not
// cleared by ***_EMACIntClear(). But that is not a problem for the bootloader
// as we are not enabling any interrupts.
//
#if defined(TARGET_IS_TM4C129_RA0)
#define ROM_EMACInit \
((void (*)(uint32_t ui32Base, \
uint32_t ui32SysClk, \
uint32_t ui32BusConfig, \
uint32_t ui32RxBurst, \
uint32_t ui32TxBurst, \
uint32_t ui32DescSkipSize))ROM_EMACTABLE[8])
#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
//! a 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
Please help to sort this issue ASAP