text: //*****************************************************************************
  //
  // bl_can.c - Functions to transfer data via the CAN port.
  //
  // Copyright (c) 2008-2015 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.2.111 of the Tiva Firmware Development Package.
  //
  //*****************************************************************************
  
  #include <stdint.h>
  #include "inc/hw_can.h"
  #include "inc/hw_gpio.h"
  #include "inc/hw_memmap.h"
  #include "inc/hw_nvic.h"
  #include "inc/hw_flash.h"
  #include "inc/hw_sysctl.h"
  #include "inc/hw_types.h"
  #include "inc/hw_uart.h"
  #include "bl_config.h"
  #include "boot_loader/bl_can.h"
  #include "boot_loader/bl_can_timing.h"
  #include "boot_loader/bl_check.h"
  #include "boot_loader/bl_crystal.h"
  #include "boot_loader/bl_flash.h"
  #include "boot_loader/bl_hooks.h"
  #include "boot_loader/bl_uart.h"
  
  //*****************************************************************************
  //
  //! \addtogroup bl_can_api
  //! @{
  //
  //*****************************************************************************
  #if defined(CAN_ENABLE_UPDATE) || defined(DOXYGEN)
  
  //*****************************************************************************
  //
  // The results that can be returned by the CAN APIs.
  //
  //*****************************************************************************
  #define CAN_CMD_SUCCESS         0x00
  #define CAN_CMD_FAIL            0x01
  
  //*****************************************************************************
  //
  // Macros used to generate correct pin definitions.
  //
  //*****************************************************************************
  #define CAN_RX_PIN_M            (1 << CAN_RX_PIN)
  #define CAN_TX_PIN_M            (1 << CAN_TX_PIN)
  #define CAN_RX_PIN_PCTL_M       (CAN_RX_PIN_PCTL << (CAN_RX_PIN*4))
  #define CAN_TX_PIN_PCTL_M       (CAN_TX_PIN_PCTL << (CAN_TX_PIN*4))
  
  //*****************************************************************************
  //
  // Convenience macros for accessing CAN registers.
  //
  //*****************************************************************************
  #define CANRegWrite(ui32Address, ui32Value)                                   \
                                  HWREG(ui32Address) = ui32Value
  
  #define CANRegRead(ui32Address)                                               \
                                  HWREG(ui32Address)
  
  //*****************************************************************************
  //
  // The message object number and index to the local message object memory to
  // use when accessing the messages.
  //
  //*****************************************************************************
  #define MSG_OBJ_BCAST_RX_ID     1
  #define MSG_OBJ_BCAST_TX_ID     2
  
  //*****************************************************************************
  //
  // A prototype for the function (in the startup code) for calling the
  // application.
  //
  //*****************************************************************************
  extern void StartApplication(void);
  
  //*****************************************************************************
  //
  // A prototype for the function (in the startup code) for a predictable length
  // delay.
  //
  //*****************************************************************************
  extern void Delay(uint32_t ui32Count);
  
  //*****************************************************************************
  //
  // Holds the current address to write to when data is received via the Send
  // Data Command.
  //
  //*****************************************************************************
  static uint32_t g_ui32TransferAddress;
  
  //*****************************************************************************
  //
  // Holds the remaining bytes expected to be received.
  //
  //*****************************************************************************
  static uint32_t g_ui32TransferSize;
  
  //*****************************************************************************
  //
  // The buffer used to receive data from the update.
  //
  //*****************************************************************************
  static uint8_t g_pui8CommandBuffer[8];
  
  //*****************************************************************************
  //
  // These globals are used to store the first two words to prevent a partial
  // image from being booted.
  //
  //*****************************************************************************
  static uint32_t g_ui32StartValues[2];
  static uint32_t g_ui32StartSize;
  static uint32_t g_ui32StartAddress;
  
  //*****************************************************************************
  //
  // The active interface when the UART bridge is enabled.
  //
  //*****************************************************************************
  #ifdef CAN_UART_BRIDGE
  static uint32_t g_ui32Interface;
  #define IFACE_UNKNOWN           0
  #define IFACE_CAN               1
  #define IFACE_UART              2
  #endif
  
  //*****************************************************************************
  //
  //! Initializes the CAN controller after reset.
  //!
  //! After reset, the CAN controller is left in the disabled state.  However,
  //! the memory used for message objects contains undefined values and must be
  //! cleared prior to enabling the CAN controller the first time.  This prevents
  //! unwanted transmission or reception of data before the message objects are
  //! configured.  This function must be called before enabling the controller
  //! the first time.
  //!
  //! \return None.
  //
  //*****************************************************************************
  static void
  CANInit(void)
  {
      int iMsg;
  
      //
      // Place CAN controller in init state, regardless of previous state.  This
      // will put the controller in idle, and allow the message object RAM to be
      // programmed.
      //
      CANRegWrite(CAN0_BASE + CAN_O_CTL, CAN_CTL_INIT | CAN_CTL_CCE);
  
      //
      // Loop through to program all 32 message objects
      //
      for(iMsg = 1; iMsg <= 32; iMsg++)
      {
          //
          // Wait for busy bit to clear.
          //
          while(CANRegRead(CAN0_BASE + CAN_O_IF1CRQ) & CAN_IF1CRQ_BUSY)
          {
          }
  
          //
          // Clear the message value bit in the arbitration register.  This
          // indicates the message is not valid and is a "safe" condition to
          // leave the message object.
          //
          CANRegWrite(CAN0_BASE + CAN_O_IF1CMSK,
                      CAN_IF1CMSK_WRNRD | CAN_IF1CMSK_ARB | CAN_IF1CMSK_CONTROL);
          CANRegWrite(CAN0_BASE + CAN_O_IF1ARB2, 0);
          CANRegWrite(CAN0_BASE + CAN_O_IF1MCTL, 0);
  
          //
          // Initiate programming of the message object
          //
          CANRegWrite(CAN0_BASE + CAN_O_IF1CRQ, iMsg);
      }
  
      //
      // Acknowledge any pending status interrupts.
      //
      CANRegRead(CAN0_BASE + CAN_O_STS);
  }
  
  //*****************************************************************************
  //
  //! This function configures the message object used to receive commands.
  //!
  //! This function configures the message object used to receive all firmware
  //! update messages.  This will not actually read the data from the message it
  //! is used to prepare the message object to receive the data when it is sent.
  //!
  //! \return None.
  //
  //*****************************************************************************
  static void
  CANMessageSetRx(void)
  {
      uint16_t ui16CmdMaskReg;
      uint16_t ui16MaskReg[2];
      uint16_t ui16ArbReg[2];
      uint16_t ui16MsgCtrl;
  
      //
      // Wait for busy bit to clear
      //
      while(CANRegRead(CAN0_BASE + CAN_O_IF1CRQ) & CAN_IF1CRQ_BUSY)
      {
      }
  
      //
      // This is always a write to the Message object as this call is setting a
      // message object.  This call will also always set all size bits so it sets
      // both data bits.  The call will use the CONTROL register to set control
      // bits so this bit needs to be set as well.
      //
      // Set the MASK bit so that this gets transferred to the Message Object.
      // Set the Arb bit so that this gets transferred to the Message object.
      //
      ui16CmdMaskReg = (CAN_IF1CMSK_WRNRD | CAN_IF1CMSK_DATAA |
                        CAN_IF1CMSK_DATAB | CAN_IF1CMSK_CONTROL |
                        CAN_IF1CMSK_MASK | CAN_IF1CMSK_ARB);
  
      //
      // Set the UMASK bit to enable using the mask register.
      // Set the data length since this is set for all transfers.  This is also a
      // single transfer and not a FIFO transfer so set EOB bit.
      //
      ui16MsgCtrl = CAN_IF1MCTL_UMASK | CAN_IF1MCTL_EOB;
  
      //
      // Configure the Mask Registers.
      //
      //
      // Set the 29 bits of Identifier mask that were requested.
      //
      ui16MaskReg[0] = (uint16_t)LM_API_UPD;
  
      //
      // If the caller wants to filter on the extended ID bit then set it.
      //
      ui16MaskReg[1] =
          (uint16_t)(CAN_IF1MSK2_MXTD | (LM_API_UPD >> 16));
  
      //
      // Set the 29 bit version of the Identifier for this message object.
      // Mark the message as valid and set the extended ID bit.
      //
      ui16ArbReg[0] = LM_API_UPD & CAN_IF1ARB1_ID_M;
      ui16ArbReg[1] = (((LM_API_UPD >> 16) & CAN_IF1ARB2_ID_M) |
                       (CAN_IF1ARB2_MSGVAL | CAN_IF1ARB2_XTD));
  
      //
      // Write out the registers to program the message object.
      //
      CANRegWrite(CAN0_BASE + CAN_O_IF1CMSK, ui16CmdMaskReg);
      CANRegWrite(CAN0_BASE + CAN_O_IF1MSK1, ui16MaskReg[0]);
      CANRegWrite(CAN0_BASE + CAN_O_IF1MSK2, ui16MaskReg[1]);
      CANRegWrite(CAN0_BASE + CAN_O_IF1ARB1, ui16ArbReg[0]);
      CANRegWrite(CAN0_BASE + CAN_O_IF1ARB2, ui16ArbReg[1]);
      CANRegWrite(CAN0_BASE + CAN_O_IF1MCTL, ui16MsgCtrl);
  
      //
      // Transfer the message object to the message object specific by
      // MSG_OBJ_BCAST_RX_ID.
      //
      CANRegWrite(CAN0_BASE + CAN_O_IF1CRQ,
                  MSG_OBJ_BCAST_RX_ID & CAN_IF1CRQ_MNUM_M);
  }
  
  //*****************************************************************************
  //
  //! This function reads data from the receive message object.
  //!
  //! \param pui8Data is a pointer to the buffer to store the data read from the
  //! CAN controller.
  //! \param pui32MsgID is a pointer to the ID that was received with the data.
  //!
  //! This function will reads and acknowledges the data read from the message
  //! object used to receive all CAN firmware update messages.  It will also
  //! return the message identifier as this holds the API number that was
  //! attached to the data.  This message identifier should be one of the
  //! LM_API_UPD_* definitions.
  //!
  //! \return The number of valid bytes returned in the \e pui8Data buffer or
  //! 0xffffffff if data was overwritten in the buffer.
  //
  //*****************************************************************************
  static uint32_t
  CANMessageGetRx(uint8_t *pui8Data, uint32_t *pui32MsgID)
  {
      uint16_t ui16CmdMaskReg;
      uint16_t ui16ArbReg0, ui16ArbReg1;
      uint16_t ui16MsgCtrl;
      uint32_t ui32Bytes;
      uint16_t *pui16Data;
  
      //
      // This is always a read to the Message object as this call is setting a
      // message object.
      // Clear a pending interrupt and new data in a message object.
      //
      ui16CmdMaskReg = (CAN_IF2CMSK_DATAA | CAN_IF2CMSK_DATAB |
                        CAN_IF1CMSK_CONTROL | CAN_IF2CMSK_CLRINTPND |
                        CAN_IF2CMSK_ARB);
  
      //
      // Set up the request for data from the message object.
      //
      CANRegWrite(CAN0_BASE + CAN_O_IF2CMSK, ui16CmdMaskReg);
  
      //
      // Transfer the message object to the message object specific by
      // MSG_OBJ_BCAST_RX_ID.
      //
      CANRegWrite(CAN0_BASE + CAN_O_IF2CRQ,
                  MSG_OBJ_BCAST_RX_ID & CAN_IF1CRQ_MNUM_M);
  
      //
      // Wait for busy bit to clear
      //
      while(CANRegRead(CAN0_BASE + CAN_O_IF2CRQ) & CAN_IF1CRQ_BUSY)
      {
      }
  
      //
      // Read out the IF Registers.
      //
      ui16ArbReg0 = CANRegRead(CAN0_BASE + CAN_O_IF2ARB1);
      ui16ArbReg1 = CANRegRead(CAN0_BASE + CAN_O_IF2ARB2);
      ui16MsgCtrl = CANRegRead(CAN0_BASE + CAN_O_IF2MCTL);
  
      //
      // Set the 29 bit version of the Identifier for this message object.
      //
      *pui32MsgID = ((ui16ArbReg1 & CAN_IF1ARB2_ID_M) << 16) | ui16ArbReg0;
  
      //
      // See if there is new data available.
      //
      if((ui16MsgCtrl & (CAN_IF1MCTL_NEWDAT | CAN_IF1MCTL_MSGLST)) ==
         CAN_IF1MCTL_NEWDAT)
      {
          //
          // Get the amount of data needed to be read.
          //
          ui32Bytes = ui16MsgCtrl & CAN_IF1MCTL_DLC_M;
  
          //
          // Read out the data from the CAN registers 16 bits at a time.
          //
          pui16Data = (uint16_t *)pui8Data;
  
          pui16Data[0] = CANRegRead(CAN0_BASE + CAN_O_IF2DA1);
          pui16Data[1] = CANRegRead(CAN0_BASE + CAN_O_IF2DA2);
          pui16Data[2] = CANRegRead(CAN0_BASE + CAN_O_IF2DB1);
          pui16Data[3] = CANRegRead(CAN0_BASE + CAN_O_IF2DB2);
  
          //
          // Now clear out the new data flag.
          //
          CANRegWrite(CAN0_BASE + CAN_O_IF2CMSK, CAN_IF1CMSK_NEWDAT);
  
          //
          // Transfer the message object to the message object specific by
          // MSG_OBJ_BCAST_RX_ID.
          //
          CANRegWrite(CAN0_BASE + CAN_O_IF2CRQ, MSG_OBJ_BCAST_RX_ID);
  
          //
          // Wait for busy bit to clear
          //
          while(CANRegRead(CAN0_BASE + CAN_O_IF2CRQ) & CAN_IF2CRQ_BUSY)
          {
          }
      }
      else
      {
          //
          // Data was lost so inform the caller.
          //
          ui32Bytes = 0xffffffff;
      }
      return(ui32Bytes);
  }
  
  //*****************************************************************************
  //
  //! This function sends data using the transmit message object.
  //!
  //! \param ui32Id is the ID to use with this message.
  //! \param pui8Data is a pointer to the buffer with the data to be sent.
  //! \param ui32Size is the number of bytes to send and should not be more than
  //! 8 bytes.
  //!
  //! This function will reads and acknowledges the data read from the message
  //! object used to receive all CAN firmware update messages.  It will also
  //! return the message identifier as this holds the API number that was
  //! attached to the data.  This message identifier should be one of the
  //! LM_API_UPD_* definitions.
  //!
  //! \return None.
  //
  //*****************************************************************************
  static void
  CANMessageSetTx(uint32_t ui32Id, const uint8_t *pui8Data, uint32_t ui32Size)
  {
      uint16_t ui16CmdMaskReg;
      uint16_t ui16ArbReg0, ui16ArbReg1;
      uint16_t ui16MsgCtrl;
      uint16_t *pui16Data;
  
      //
      // Wait for busy bit to clear
      //
      while(CANRegRead(CAN0_BASE + CAN_O_IF1CRQ) & CAN_IF1CRQ_BUSY)
      {
      }
  
      //
      // This is always a write to the Message object as this call is setting a
      // message object.  This call will also always set all size bits so it sets
      // both data bits.  The call will use the CONTROL register to set control
      // bits so this bit needs to be set as well.
      //
      ui16CmdMaskReg = (CAN_IF1CMSK_WRNRD | CAN_IF1CMSK_DATAA |
                        CAN_IF1CMSK_DATAB | CAN_IF1CMSK_CONTROL |
                        CAN_IF1CMSK_ARB);
  
      //
      // Set the 29 bit version of the Identifier for this message object.
      //
      ui16ArbReg0 = ui32Id & CAN_IF1ARB1_ID_M;
  
      //
      // Mark the message as valid and set the extended ID bit.
      //
      ui16ArbReg1 = (((ui32Id >> 16) & CAN_IF1ARB2_ID_M) |
                     (CAN_IF1ARB2_DIR | CAN_IF1ARB2_MSGVAL | CAN_IF1ARB2_XTD));
  
      //
      // Set the TXRQST bit and the reset the rest of the register.
      // Set the data length since this is set for all transfers.  This is also a
      // single transfer and not a FIFO transfer so set EOB bit.
      //
      //
      ui16MsgCtrl = (CAN_IF1MCTL_TXRQST | CAN_IF1MCTL_EOB |
                     (ui32Size & CAN_IF1MCTL_DLC_M));
  
      pui16Data = (uint16_t *)pui8Data;
  
      //
      // Write the data out to the CAN Data registers if needed.
      //
      CANRegWrite(CAN0_BASE + CAN_O_IF1DA1, pui16Data[0]);
      CANRegWrite(CAN0_BASE + CAN_O_IF1DA2, pui16Data[1]);
      CANRegWrite(CAN0_BASE + CAN_O_IF1DB1, pui16Data[2]);
      CANRegWrite(CAN0_BASE + CAN_O_IF1DB2, pui16Data[3]);
  
      //
      // Write out the registers to program the message object.
      //
      CANRegWrite(CAN0_BASE + CAN_O_IF1CMSK, ui16CmdMaskReg);
      CANRegWrite(CAN0_BASE + CAN_O_IF1ARB1, ui16ArbReg0);
      CANRegWrite(CAN0_BASE + CAN_O_IF1ARB2, ui16ArbReg1);
      CANRegWrite(CAN0_BASE + CAN_O_IF1MCTL, ui16MsgCtrl);
  
      //
      // Transfer the message object to the message object specifiec by
      // MSG_OBJ_BCAST_RX_ID.
      //
      CANRegWrite(CAN0_BASE + CAN_O_IF1CRQ,
                  (MSG_OBJ_BCAST_TX_ID) & CAN_IF1CRQ_MNUM_M);
  }
  
  //*****************************************************************************
  //
  //! Configures the CAN interface.
  //!
  //! \param ui32SetTiming determines if the CAN bit timing should be configured.
  //!
  //! This function configures the CAN controller, preparing it for use by
  //! the boot loader.   If the \e ui32SetTiming parameter is 0, the bit timing
  //! for the CAN bus will be left alone.  This occurs when the boot loader was
  //! entered from a running application that already has configured the timing
  //! for the system.  When \e ui32SetTiming is non-zero the bit timing will be
  //! set to the defaults defined in the <tt>bl_config.h</tt> file in the
  //! project.
  //!
  //! \return None.
  //
  //*****************************************************************************
  static void
  ConfigureCANInterface(uint32_t ui32SetTiming)
  {
      //
      // Reset the state of all the message object and the state of the CAN
      // module to a known state.
      //
      CANInit();
  
      //
      // If a device identifier was specified then this was due to an update from
      // a running CAN application so don't change the CAN bit timing.
      //
      if(ui32SetTiming != 0)
      {
          //
          // Set the bit fields of the bit timing register according to the
          // parms.
          //
          CANRegWrite(CAN0_BASE + CAN_O_BIT, CAN_BIT_TIMING);
  
          //
          // Set the divider upper bits in the extension register.
          //
          CANRegWrite(CAN0_BASE + CAN_O_BRPE, 0);
      }
  
      //
      // Take the CAN0 device out of INIT state.
      //
      CANRegWrite(CAN0_BASE + CAN_O_CTL, 0);
  
      //
      // Configure the broadcast receive message object.
      //
      CANMessageSetRx();
  }
  
  //*****************************************************************************
  //
  // Reads the next packet that is sent to the boot loader.
  //
  //*****************************************************************************
  static uint32_t
  PacketRead(uint8_t *pui8Data, uint32_t *pui32Size)
  {
      uint32_t ui32MsgID;
  
  #ifdef CAN_UART_BRIDGE
      uint32_t ui32Size, ui32Length, ui32Mode, ui32Char;
      uint8_t pui8Buffer[12];
  
      //
      // Initialize the size and length of the packet.
      //
      ui32Length = 0;
      ui32Size = 0;
  
      //
      // If no interface has been determined then wait for either CAN or UART
      // data until either responds.
      //
      if(g_ui32Interface == IFACE_UNKNOWN)
      {
          //
          // Wait for CAN or UART data.
          //
          while((CANRegRead(CAN0_BASE + CAN_O_NWDA1) == 0) &&
                ((HWREG(UART0_BASE + UART_O_FR) & UART_FR_RXFE) == UART_FR_RXFE))
          {
          }
  
          //
          // If the UART FIFO was empty then the loop exited due to a CAN
          // message.
          //
          if((HWREG(UART0_BASE + UART_O_FR) & UART_FR_RXFE) == UART_FR_RXFE)
          {
              g_ui32Interface = IFACE_CAN;
          }
          else
          {
              //
              // The UART FIFO was not empty so the UART interface was used.
              //
              g_ui32Interface = IFACE_UART;
          }
      }
  
      //
      // Read a data packet from the CAN controller.
      //
      if(g_ui32Interface == IFACE_CAN)
      {
  #endif
          //
          // Wait until a packet has been received.
          //
          while(CANRegRead(CAN0_BASE + CAN_O_NWDA1) == 0)
          {
          }
  
          //
          // Read the packet.
          //
          *pui32Size = CANMessageGetRx(pui8Data, &ui32MsgID);
  #ifdef CAN_UART_BRIDGE
      }
      else
      {
          //
          // Read a data packet from the UART controller.
          //
          ui32Mode = 0;
  
          while(1)
          {
              //
              // Wait until a char is available.
              //
              while(HWREG(UART0_BASE + UART_O_FR) & UART_FR_RXFE)
              {
              }
  
              //
              // Now get the char.
              //
              ui32Char = HWREG(UART0_BASE + UART_O_DR);
  
              if(ui32Char == 0xff)
              {
                  ui32Mode = 1;
                  ui32Length = 0;
              }
              else if(ui32Mode == 1)
              {
                  if(ui32Char > 12)
                  {
                      ui32Mode = 0;
                  }
                  else
                  {
                      ui32Size = ui32Char;
                      ui32Mode = 2;
                  }
              }
              else if(ui32Mode == 3)
              {
                  if(ui32Char == 0xfe)
                  {
                      pui8Buffer[ui32Length++] = 0xff;
                      ui32Mode = 2;
                  }
                  else if(ui32Char == 0xfd)
                  {
                      pui8Buffer[ui32Length++] = 0xfe;
                      ui32Mode = 2;
                  }
                  else
                  {
                      ui32Mode = 0;
                  }
              }
              else if(ui32Mode == 2)
              {
                  if(ui32Char == 0xfe)
                  {
                      ui32Mode = 3;
                  }
                  else
                  {
                      pui8Buffer[ui32Length++] = ui32Char;
                  }
              }
  
              if((ui32Length == ui32Size) && (ui32Mode == 2))
              {
                  ui32MsgID = *(uint32_t *)pui8Buffer;
  
                  if((ui32MsgID & (CAN_MSGID_MFR_M | CAN_MSGID_DTYPE_M)) ==
                     LM_API_UPD)
                  {
                      *(uint32_t *)pui8Data =
                          *(uint32_t *)(pui8Buffer + 4);
                      *(uint32_t *)(pui8Data + 4) =
                          *(uint32_t *)(pui8Buffer + 8);
                      *pui32Size = ui32Size - 4;
                      break;
                  }
              }
          }
      }
  #endif
  
      //
      // Return the message ID of the packet that was received.
      //
      return(ui32MsgID);
  }
  
  //*****************************************************************************
  //
  // This function writes out an individual character over the UART and
  // handles sending out special sequences for handling 0xff and 0xfe values.
  //
  //*****************************************************************************
  #ifdef CAN_UART_BRIDGE
  static void
  UARTBridgeWrite(uint32_t ui32Char)
  {
      //
      // See if the character being sent is 0xff.
      //
      if(ui32Char == 0xff)
      {
          //
          // Send 0xfe 0xfe, the escaped version of 0xff.  A sign extended
          // version of 0xfe is used to avoid the check below for 0xfe, thereby
          // avoiding an infinite loop.  Only the lower 8 bits are actually sent,
          // so 0xfe is what is actually transmitted.
          //
          UARTBridgeWrite(0xfffffffe);
          UARTBridgeWrite(0xfffffffe);
      }
  
      //
      // Otherwise, see if the character being sent is 0xfe.
      //
      else if(ui32Char == 0xfe)
      {
          //
          // Send 0xfe 0xfd, the escaped version of 0xfe.  A sign extended
          // version of 0xfe is used to avoid the check above for 0xfe, thereby
          // avoiding an infinite loop.  Only the lower 8 bits are actually sent,
          // so 0xfe is what is actually transmitted.
          //
          UARTBridgeWrite(0xfffffffe);
          UARTBridgeWrite(0xfd);
      }
  
      //
      // Otherwise, simply send this character.
      //
      else
      {
          //
          // Wait until space is available in the UART transmit FIFO.
          //
          while(HWREG(UART0_BASE + UART_O_FR) & UART_FR_TXFF)
          {
          }
  
          //
          // Send the char.
          //
          HWREG(UART0_BASE + UART_O_DR) = ui32Char & 0xff;
      }
  }
  #endif
  
  //*****************************************************************************
  //
  // Sends a packet to the controller that is communicating with the boot loader.
  //
  //*****************************************************************************
  static void
  PacketWrite(uint32_t ui32Id, const uint8_t *pui8Data, uint32_t ui32Size)
  {
      uint32_t ui32Idx;
  
  #ifdef CAN_UART_BRIDGE
      //
      // Check if the boot loader is in CAN mode.
      //
      if(g_ui32Interface == IFACE_CAN)
      {
  #endif
          //
          // Wait until the previous packet has been sent, providing a time out so
          // that the boot loader does not hang here.
          //
          for(ui32Idx = 1000;
              (ui32Idx != 0) && (CANRegRead(CAN0_BASE + CAN_O_TXRQ1) != 0);
              ui32Idx--)
          {
          }
  
          //
          // If the previous packet was sent, then send this packet.
          //
          if(ui32Idx != 0)
          {
              CANMessageSetTx(ui32Id, pui8Data, ui32Size);
          }
  #ifdef CAN_UART_BRIDGE
      }
      else
      {
          //
          // The boot loader is in UART modes so write the packet using the UART
          // functions.  Write the start pattern followed by the size, and the ID.
          //
          UARTBridgeWrite(0xffffffff);
          UARTBridgeWrite(ui32Size + 4);
          UARTBridgeWrite(ui32Id & 0xff);
          UARTBridgeWrite((ui32Id >> 8) & 0xff);
          UARTBridgeWrite((ui32Id >> 16) & 0xff);
          UARTBridgeWrite((ui32Id >> 24) & 0xff);
  
          //
          // Now write out the remaining data bytes.
          //
          while(ui32Size--)
          {
              UARTBridgeWrite(*pui8Data++);
          }
      }
  #endif
  }
  
  //*****************************************************************************
  //
  //! This is the main routine for handling updating over CAN.
  //!
  //! This function accepts boot loader commands over CAN to perform a firmware
  //! update over the CAN bus.  This function assumes that the CAN bus timing
  //! and message objects have been configured elsewhere.
  //!
  //! \return None.
  //
  //*****************************************************************************
  void
  UpdaterCAN(void)
  {
      uint32_t ui32Bytes;
      uint32_t ui32Cmd;
      uint32_t ui32FlashSize;
      uint32_t ui32Temp;
      uint8_t ui8Status;
  
  #ifdef ENABLE_UPDATE_CHECK
      //
      // Check the application is valid and check the pin to see if an update is
      // being requested.
      //
      if(g_ui32Forced == 1)
      {
          //
          // Send out the CAN request.
          //
  #ifdef CAN_UART_BRIDGE
          g_ui32Interface = IFACE_CAN;
  #endif
          PacketWrite(LM_API_UPD_REQUEST, 0, 0);
  
          //
          // Send out the UART request.
          //
  #ifdef CAN_UART_BRIDGE
          g_ui32Interface = IFACE_UART;
          PacketWrite(LM_API_UPD_REQUEST, 0, 0);
          g_ui32Interface = IFACE_UNKNOWN;
  #endif
  
          //
          // Wait only 50ms for the response and move on otherwise.
          //
          Delay(CRYSTAL_FREQ / 20);
  
          //
          // Wait until a packet has been received.
          //
  #ifdef CAN_UART_BRIDGE
          if((CANRegRead(CAN0_BASE + CAN_O_NWDA1) == 0) &&
             ((HWREG(UART0_BASE + UART_O_FR) & UART_FR_RXFE) == UART_FR_RXFE))
  #else
          if(CANRegRead(CAN0_BASE + CAN_O_NWDA1) == 0)
  #endif
          {
              //
              // Call the application.
              //
              StartApplication();
          }
      }
  #endif
  
      //
      // Loop forever processing packets.
      //
      while(1)
      {
          //
          // Read the next packet.
          //
          ui32Bytes = 0;
          ui32Cmd = PacketRead(g_pui8CommandBuffer, &ui32Bytes);
  
          //
          // Handle this packet.
          //
          ui8Status = CAN_CMD_SUCCESS;
          switch(ui32Cmd)
          {
              //
              // This is an update request packet.
              //
              case LM_API_UPD_REQUEST:
              {
                  //
                  // This packet is ignored (other than generating an ACK).
                  //
                  break;
              }
  
              //
              // This is a ping packet.
              //
              case LM_API_UPD_PING:
              {
                  //
                  // This packet is ignored (other than generating an ACK).
                  //
                  break;
              }
  
              //
              // This is a reset packet.
              //
              case LM_API_UPD_RESET:
              {
                  //
                  // 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)
                  {
                  }
              }
  
              //
              // This is a data packet.
              //
              case LM_API_UPD_SEND_DATA:
              {
                  //
                  // If this is overwriting the boot loader then the application
                  // has already been erased so now erase the boot loader.
                  //
                  if(g_ui32TransferAddress == 0)
                  {
                      //
                      // Clear the flash access interrupt.
                      //
                      BL_FLASH_CL_ERR_FN_HOOK();
  
                      //
                      // Erase the application before the boot loader.
                      //
                      for(ui32Temp = 0; ui32Temp < APP_START_ADDRESS;
                          ui32Temp += FLASH_PAGE_SIZE)
                      {
                          //
                          // Erase this block.
                          //
                          BL_FLASH_ERASE_FN_HOOK(ui32Temp);
                      }
  
                      //
                      // Return an error if an access violation occurred.
                      //
                      if(BL_FLASH_ERROR_FN_HOOK())
                      {
                          //
                          // Setting g_ui32TransferSize to zero makes
                          // COMMAND_SEND_DATA fail to accept any more data.
                          //
                          g_ui32TransferSize = 0;
  
                          //
                          // Indicate that the flash erase failed.
                          //
                          ui8Status = CAN_CMD_FAIL;
                      }
                  }
  
                  //
                  // Check if there are any more bytes to receive.
                  //
                  if(g_ui32TransferSize >= ui32Bytes)
                  {
                      //
                      // Decrypt the data if required.
                      //
  #ifdef BL_DECRYPT_FN_HOOK
                      BL_DECRYPT_FN_HOOK(g_pui8CommandBuffer, ui32Bytes);
  #endif
  
                      //
                      // Clear the flash access interrupt.
                      //
                      BL_FLASH_CL_ERR_FN_HOOK();
  
                      //
                      // Skip the first transfer.
                      //
                      if(g_ui32StartSize == g_ui32TransferSize)
                      {
                          g_ui32StartValues[0] =
                              *((uint32_t *)&g_pui8CommandBuffer[0]);
                          g_ui32StartValues[1] =
                              *((uint32_t *)&g_pui8CommandBuffer[4]);
                      }
                      else
                      {
                          //
                          // Loop over the words to program.
                          //
                          BL_FLASH_PROGRAM_FN_HOOK(g_ui32TransferAddress,
                                                   g_pui8CommandBuffer,
                                                   ui32Bytes);
                      }
  
                      //
                      // Return an error if an access violation occurred.
                      //
                      if(BL_FLASH_ERROR_FN_HOOK())
                      {
                          //
                          // Indicate that the flash programming failed.
                          //
                          ui8Status = CAN_CMD_FAIL;
                      }
                      else
                      {
                          //
                          // Now update the address to program.
                          //
                          g_ui32TransferSize -= ui32Bytes;
                          g_ui32TransferAddress += ui32Bytes;
  
                          //
                          // If a progress hook function has been provided, call
                          // it here.
                          //
  #ifdef BL_PROGRESS_FN_HOOK
                          BL_PROGRESS_FN_HOOK(g_ui32StartSize -
                                              g_ui32TransferSize,
                                              g_ui32StartSize);
  #endif
                      }
                  }
                  else
                  {
                      //
                      // This indicates that too much data is being sent to the
                      // device.
                      //
                      ui8Status = CAN_CMD_FAIL;
                  }
  
                  //
                  // If the last expected bytes were received then write out the
                  // first two words of the image to allow it to boot.
                  //
                  if(g_ui32TransferSize == 0)
                  {
                      //
                      // Loop over the words to program.
                      //
                      BL_FLASH_PROGRAM_FN_HOOK(g_ui32StartAddress,
                                               (uint8_t *)&g_ui32StartValues,
                                               8);
  
                      //
                      // If an end signal hook function has been provided, call
                      // it here since we have finished a download.
                      //
  #ifdef BL_END_FN_HOOK
                      BL_END_FN_HOOK();
  #endif
                  }
                  break;
              }
  
              //
              // This is a start download packet.
              //
              case LM_API_UPD_DOWNLOAD:
              {
                  //
                  // Get the application address and size from the packet data.
                  //
                  g_ui32TransferAddress =
                      *((uint32_t *)&g_pui8CommandBuffer[0]);
                  g_ui32TransferSize = *((uint32_t *)&g_pui8CommandBuffer[4]);
                  g_ui32StartSize = g_ui32TransferSize;
                  g_ui32StartAddress = g_ui32TransferAddress;
  
                  //
                  // Check for a valid starting address and image size.
                  //
                  if(!BL_FLASH_AD_CHECK_FN_HOOK(g_ui32TransferAddress,
                                                g_ui32TransferSize))
                  {
                      //
                      // Set the code to an error to indicate that the last
                      // command failed.  This informs the updater program
                      // that the download command failed.
                      //
                      ui8Status = CAN_CMD_FAIL;
  
                      //
                      // This packet has been handled.
                      //
                      break;
                  }
  
                  //
                  // Only erase the space that we need if we are not protecting
                  // the code, otherwise erase the entire flash.
                  //
  #ifdef FLASH_CODE_PROTECTION
                  ui32FlashSize = BL_FLASH_SIZE_FN_HOOK();
  #ifdef FLASH_RSVD_SPACE
                  if((ui32FlashSize - FLASH_RSVD_SPACE) != g_ui32TransferAddress)
                  {
                      ui32FlashSize -= FLASH_RSVD_SPACE;
                  }
  #endif
  #else
                  ui32FlashSize = g_ui32TransferAddress + g_ui32TransferSize;
  #endif
  
                  //
                  // Clear the flash access interrupt.
                  //
                  BL_FLASH_CL_ERR_FN_HOOK();
  
                  //
                  // Leave the boot loader present until we start getting an
                  // image.
                  //
                  for(ui32Temp = g_ui32TransferAddress; ui32Temp < ui32FlashSize;
                      ui32Temp += FLASH_PAGE_SIZE)
                  {
                      //
                      // Erase this block.
                      //
                      BL_FLASH_ERASE_FN_HOOK(ui32Temp);
                  }
  
                  //
                  // Return an error if an access violation occurred.
                  //
                  if(BL_FLASH_ERROR_FN_HOOK())
                  {
                      ui8Status = CAN_CMD_FAIL;
                  }
  
                  //
                  // See if the command was successful.
                  //
                  if(ui8Status != CAN_CMD_SUCCESS)
                  {
                      //
                      // Setting g_ui32TransferSize to zero makes
                      // COMMAND_SEND_DATA fail to accept any data.
                      //
                      g_ui32TransferSize = 0;
                  }
  #ifdef BL_START_FN_HOOK
                  else
                  {
                      //
                      // If a start signal hook function has been provided, call
                      // it here since we are about to start a new download.
                      //
                      BL_START_FN_HOOK();
                  }
  #endif
  
                  break;
              }
  
              //
              // This is an unknown packet.
              //
              default:
              {
                  //
                  // Set the status to indicate a failure.
                  //
                  ui8Status = CAN_CMD_FAIL;
                  break;
              }
          }
  
          //
          // Send an ACK packet in response to indicate that the packet was
          // received.  The status in the ACK data indicates if the command was
          // successfully processed.
          //
          PacketWrite(LM_API_UPD_ACK, &ui8Status, 1);
      }
  }
  
  //*****************************************************************************
  //
  // Configures the UART used for CAN traffic bridging.
  //
  //*****************************************************************************
  #ifdef CAN_UART_BRIDGE
  void
  ConfigureBridge(void)
  {
      //
      // Enable the GPIO module if necessary.
      //
  #if (CAN_RX_PERIPH != SYSCTL_RCGCGPIO_R0) && \
      (CAN_TX_PERIPH != SYSCTL_RCGCGPIO_R0)
      HWREG(SYSCTL_RCGCGPIO) |= SYSCTL_RCGCGPIO_R0;
  #endif
  
      //
      // Enable the UART module.
      //
      HWREG(SYSCTL_RCGCUART) |= SYSCTL_RCGCUART_R0;
  
      //
      // Enable the GPIO pins used for the UART.
      //
      HWREG(GPIO_PORTA_BASE + GPIO_O_DEN)  |= UART_PINS;
      HWREG(GPIO_PORTA_BASE + GPIO_O_PCTL) |= UART_PINS_PCTL;
      HWREG(GPIO_PORTA_BASE + GPIO_O_DEN)  |= UART_PINS;
  
      //
      // Configure the UART.
      //
      HWREG(UART0_BASE + UART_O_IBRD) = UART_BAUD_RATIO(115200) >> 6;
      HWREG(UART0_BASE + UART_O_FBRD) = (UART_BAUD_RATIO(115200) &
                                         UART_FBRD_DIVFRAC_M);
      HWREG(UART0_BASE + UART_O_LCRH) = UART_LCRH_WLEN_8 | UART_LCRH_FEN;
      HWREG(UART0_BASE + UART_O_CTL) = (UART_CTL_UARTEN | UART_CTL_TXE |
                                        UART_CTL_RXE);
  }
  #endif
  
  //*****************************************************************************
  //
  //! This is the application entry point to the CAN updater.
  //!
  //! This function should only be entered from a running application and not
  //! when running the boot loader with no application present.
  //!
  //! \return None.
  //
  //*****************************************************************************
  void
  AppUpdaterCAN(void)
  {
      //
      // If the boot loader is being called from the application the UART needs
      // to be configured.
      //
  #ifdef CAN_UART_BRIDGE
      ConfigureBridge();
  #endif
  
      //
      // Configure the CAN controller but don't change the bit timing.
      //
      ConfigureCANInterface(0);
  
      //
      // Call the main update routine.
      //
      UpdaterCAN();
  }
  
  //*****************************************************************************
  //
  //! Generic configuration is handled in this function.
  //!
  //! This function is called by the start up code to perform any configuration
  //! necessary before calling the update routine.
  //!
  //! \return None.
  //
  //*****************************************************************************
  void
  ConfigureCAN(void)
  {
  #ifdef CRYSTAL_FREQ
  #if defined(TARGET_IS_TM4C129_RA0) ||                                         \
  	defined(TARGET_IS_TM4C129_RA1) ||                                         \
      defined(TARGET_IS_TM4C129_RA2)
  
      //
      // Since the crystal frequency was specified, enable the main oscillator
      // and clock the processor from it. Check for whether the Oscillator range
      // has to be set and wait states need to be updated
      //
      if(CRYSTAL_FREQ >= 10000000)
      {
          HWREG(SYSCTL_MOSCCTL) |= (SYSCTL_MOSCCTL_OSCRNG);
          HWREG(SYSCTL_MOSCCTL) &= ~(SYSCTL_MOSCCTL_PWRDN | SYSCTL_MOSCCTL_NOXTAL);
      }
      else
      {
          HWREG(SYSCTL_MOSCCTL) &= ~(SYSCTL_MOSCCTL_PWRDN | SYSCTL_MOSCCTL_NOXTAL);
      }
  
      //
      // Wait for the Oscillator to Stabilize
      //
      Delay(524288);
  
      if(CRYSTAL_FREQ > 16000000)
      {
      	HWREG(SYSCTL_MEMTIM0)  = (SYSCTL_MEMTIM0_FBCHT_1_5 | (1 << SYSCTL_MEMTIM0_FWS_S) |
                  				  SYSCTL_MEMTIM0_EBCHT_1_5 | (1 << SYSCTL_MEMTIM0_EWS_S) |
                  				  SYSCTL_MEMTIM0_MB1);
      	HWREG(SYSCTL_RSCLKCFG) = (SYSCTL_RSCLKCFG_MEMTIMU | SYSCTL_RSCLKCFG_OSCSRC_MOSC);
      }
      else
      {
      	HWREG(SYSCTL_RSCLKCFG) = (SYSCTL_RSCLKCFG_OSCSRC_MOSC);
      }
  #else
      //
      // Since the crystal frequency was specified, enable the main oscillator
      // and clock the processor from it.
      //
      HWREG(SYSCTL_RCC) &= ~(SYSCTL_RCC_MOSCDIS);
  
      //
      // Delay while the main oscillator starts up.
      //
      Delay(524288);
  
      //
      // Set the crystal frequency and switch to the main oscillator.
      //
      HWREG(SYSCTL_RCC) = ((HWREG(SYSCTL_RCC) &
                            ~(SYSCTL_RCC_XTAL_M | SYSCTL_RCC_OSCSRC_M)) |
                           XTAL_VALUE | SYSCTL_RCC_OSCSRC_MAIN);
  #endif
  #endif
  
      //
      // Enable the CAN controller.
      //
      HWREG(SYSCTL_RCGCCAN) |= SYSCTL_RCGCCAN_R0;
  
  #if CAN_RX_PERIPH == CAN_TX_PERIPH
      //
      // Enable the GPIO associated with CAN0
      //
      HWREG(SYSCTL_RCGCGPIO) |= CAN_RX_PERIPH;
  
      //
      // Wait a while before accessing the peripheral.
      //
      Delay(3);
  
      //
      // Set the alternate function selects.
      //
      HWREG(CAN_RX_PORT + GPIO_O_AFSEL) |= CAN_RX_PIN_M | CAN_TX_PIN_M;
  
      //
      // Set the port control selects.
      //
      HWREG(CAN_RX_PORT + GPIO_O_PCTL) |= CAN_RX_PIN_PCTL_M | CAN_TX_PIN_PCTL_M;
  
      //
      // Set the pin type to it's digital function.
      //
      HWREG(CAN_RX_PORT + GPIO_O_DEN) |= CAN_RX_PIN_M | CAN_TX_PIN_M;
  
  #else
      //
      // Enable the GPIO associated with CAN0
      //
      HWREG(SYSCTL_RCGCGPIO) |= CAN_RX_PERIPH | CAN_TX_PERIPH;
  
      //
      // Wait a while before accessing the peripheral.
      //
      Delay(3);
  
      //
      // Set the alternate function selects.
      //
      HWREG(CAN_RX_PORT + GPIO_O_AFSEL) |= CAN_RX_PIN_M;
      HWREG(CAN_TX_PORT + GPIO_O_AFSEL) |= CAN_TX_PIN_M;
  
      //
      // Set the port control selects.
      //
      HWREG(CAN_RX_PORT + GPIO_O_PCTL) |= CAN_RX_PIN_PCTL_M;
      HWREG(CAN_TX_PORT + GPIO_O_PCTL) |= CAN_TX_PIN_PCTL_M;
  
      //
      // Set the pin type to it's digital function.
      //
      HWREG(CAN_RX_PORT + GPIO_O_DEN) |= CAN_RX_PIN_M;
      HWREG(CAN_TX_PORT + GPIO_O_DEN) |= CAN_TX_PIN_M;
  #endif
  
      //
      // Configure the UART used for bridging.
      //
  #ifdef CAN_UART_BRIDGE
      ConfigureBridge();
  #endif
  
      //
      // Configure the CAN interface.
      //
      ConfigureCANInterface(1);
  }
  
  //*****************************************************************************
  //
  // Close the Doxygen group.
  //! @}
  //
  //*****************************************************************************
  #endif
  