From 990090a4cc9070837d31e66b58d40f0c3d038741 Mon Sep 17 00:00:00 2001 From: Yuval Adam Date: Sun, 16 Mar 2014 14:41:11 +0200 Subject: Add usblib and utils --- utils/swupdate.c | 355 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 355 insertions(+) create mode 100644 utils/swupdate.c (limited to 'utils/swupdate.c') diff --git a/utils/swupdate.c b/utils/swupdate.c new file mode 100644 index 0000000..edd523b --- /dev/null +++ b/utils/swupdate.c @@ -0,0 +1,355 @@ +//***************************************************************************** +// +// swupdate.c - A module wrapping the Ethernet bootloader software update +// functionality. +// +// Copyright (c) 2008-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 Utility Library. +// +//***************************************************************************** + +#include +#include +#include "inc/hw_nvic.h" +#include "inc/hw_sysctl.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" + +//***************************************************************************** +// +//! \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]; + +//***************************************************************************** +// +// 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 *pi8Data = p->payload; + uint32_t ui32Loop, ui32MACLoop; + + // + // 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. + // + + // + // 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(); + } +} + +//***************************************************************************** +// +//! 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_UpdateEthernet) && !(defined USE_FLASH_BOOT_LOADER)) + ROM_UpdateEMAC(ui32SysClock); +#else + (*((void (*)(void))(*(uint32_t *)0x2c)))(); +#endif +} + +//***************************************************************************** +// +// Close the Doxygen group. +//! @} +// +//***************************************************************************** -- cgit v1.3.1