/*******************************************************************************
* NXP Semiconductors
* ALL RIGHTS RESERVED.
********************************************************************************
Services performed by NXP in this matter are performed AS IS and without 
any warranty. CUSTOMER retains the final decision relative to the total design 
and functionality of the end product. NXP neither guarantees nor will be 
held liable by CUSTOMER for the success of this project.
NXP DISCLAIMS ALL WARRANTIES, EXPRESSED, IMPLIED OR STATUTORY INCLUDING, 
BUT NOT LIMITED TO, IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR 
A PARTICULAR PURPOSE ON ANY HARDWARE, SOFTWARE OR ADVISE SUPPLIED TO THE PROJECT
BY NXP, AND OR NAY PRODUCT RESULTING FROM NXP SERVICES. IN NO EVENT
SHALL NXP BE LIABLE FOR INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF
THIS AGREEMENT.

CUSTOMER agrees to hold NXP harmless against any and all claims demands or
actions by anyone on account of any damage, or injury, whether commercial, 
contractual, or tortuous, rising directly or indirectly as a result of an advise
or assistance supplied CUSTOMER in connection with product, services or goods 
supplied under this Agreement.
********************************************************************************
* File      main.c
* Owner     NXA19261
* Version   1.0
* Date      Aug-17-2017
* Classification   General Business Information
* Brief     Bootloader code
********************************************************************************
* Detailed Description:
* Bootloader code displays menu and execute code per user selection
* 
********************************************************************************
Revision History:
Version  Date         Author    Description of Changes
1.0      Aug-17-2017  NXA19261  Initial version
*******************************************************************************/
#include "derivative.h" /* include peripheral declarations */
#include "Config.h"
#include "Bootloader.h"
#include "flash_S12Z.h"
#include "eeprom_S12Z.h"
#include "Srec.h"
#include "Errors.h"
#include "SCI.h"

/*******************************************************************************
 Function Name : EraseFlash
 Engineer      : NXA19261
 Date          : Aug-17-2017
 Parameters    : NONE
 Modifies      : NONE
 Returns       : NONE
 Notes         : Erase Flash for Application.
 Issues        : NONE
 *******************************************************************************/
#if BOOTLODER_REWRITABLE 
#pragma CODE_SEG DEFAULT_RAM
#endif /* BOOTLODER_REWRITABLE */
unsigned int EraseFlash(void)
{
  unsigned char Error = noErr;
  Error = (PFLASH_EraseSectorBySector(FLASH_START_ADD, APPLICATION_END_ADD));
  if (Error) return(FlashEraseError);
  return (noErr);
}
#if BOOTLODER_REWRITABLE 
#pragma CODE_SEG DEFAULT
#endif /* BOOTLODER_REWRITABLE */

#if WRITE_EEPROM
/*******************************************************************************
 Function Name : EraseEEPROM
 Engineer      : NXA19261
 Date          : Aug-17-2017
 Parameters    : NONE
 Modifies      : NONE
 Returns       : NONE
 Notes         : Erase EEPROM for Application.
 Issues        : NONE
 *******************************************************************************/
#if BOOTLODER_REWRITABLE 
#pragma CODE_SEG DEFAULT_RAM
#endif /* BOOTLODER_REWRITABLE */
unsigned int EraseEEPROM(void)
{
  unsigned char Error = noErr;
  Error = (EEPROM_EraseSectorBySector(EEPROM_START_ADD, EEPROM_END_ADD));
  if (Error) return(FlashEraseError);
  return (noErr);
}
#if BOOTLODER_REWRITABLE 
#pragma CODE_SEG DEFAULT
#endif /* BOOTLODER_REWRITABLE */

#endif /* WRITE_EEPROM */

/*******************************************************************************
 Function Name : ProgramFlash
 Engineer      : NXA19261
 Date          : Aug-17-2017
 Parameters    : NONE
 Modifies      : NONE
 Returns       : NONE
 Notes         : Program Application S record to the Flash.
 Issues        : NONE
 *******************************************************************************/  
#if BOOTLODER_REWRITABLE 
#pragma CODE_SEG DEFAULT_RAM
#endif /* BOOTLODER_REWRITABLE */
unsigned char ProgramFlash(void)
{
  SRecDataRec ProgSRec;
  unsigned char Error = noErr; 

  for(;;)
  {
    Error = RcvSRecord(&ProgSRec);
    if (Error != noErr)             //go get an S-Record, return if there was an error 
      break;
    
    if (ProgSRec.RecType == EndRec) // S7, S* or S9 record? 
      break;                        // yes. return 
      
    else if (ProgSRec.RecType == HeaderRec)       //S0 record?
      continue;                     //yes. just ignore it
      
    else                            //a data record was received 
    {
        
      if ((ProgSRec.LoadAddr & 0x0000001FUL) != 0) //S-Record address aligned?
        return(SRecOddError);       //yes. return
      if (ProgSRec.NumBytes != 32)  //S-Record constant length 32?
        return(SRecOddError);       //yes. return
      
      
      
      if (ProgSRec.LoadAddr == APPLICATION_RESET_VEC_SRC)
      {
        //Program reset vector to address 0xFFEFFD
        Error = PFLASH_Program((APPLICATION_RESET_VEC_ADD & 0xFFFFF8), (unsigned int *)&ProgSRec.Data[24]);
        if (Error) return(FlashProgramError);
      } 
      else 
      {
        
        //is the address within a physical flash?
        if ((ProgSRec.LoadAddr >= FLASH_START_ADD) && (ProgSRec.LoadAddr <= APPLICATION_END_ADD))
        {
          Error = PFLASH_Program(ProgSRec.LoadAddr, (unsigned int *)&ProgSRec.Data);
          if (Error) return(FlashProgramError);
          Error = PFLASH_Program(ProgSRec.LoadAddr+8, (unsigned int *)&ProgSRec.Data[8]);
          if (Error) return(FlashProgramError);
          Error = PFLASH_Program(ProgSRec.LoadAddr+16, (unsigned int *)&ProgSRec.Data[16]);
          if (Error) return(FlashProgramError);
          Error = PFLASH_Program(ProgSRec.LoadAddr+24, (unsigned int *)&ProgSRec.Data[24]);
          if (Error) return(FlashProgramError);
        }
#if WRITE_EEPROM
        else if (((ProgSRec.LoadAddr >= EEPROM_START_ADD) && (ProgSRec.LoadAddr <= EEPROM_END_ADD)))            
             {
               Error = EEPROM_Program(ProgSRec.LoadAddr, (unsigned int *)&ProgSRec.Data, 4);
               if (Error) return(FlashProgramError);
               Error = EEPROM_Program(ProgSRec.LoadAddr+8, (unsigned int *)&ProgSRec.Data[8], 4);
               if (Error) return(FlashProgramError);
               Error = EEPROM_Program(ProgSRec.LoadAddr+16, (unsigned int *)&ProgSRec.Data[16], 4);
               if (Error) return(FlashProgramError);
               Error = EEPROM_Program(ProgSRec.LoadAddr+24, (unsigned int *)&ProgSRec.Data[24], 4);
               if (Error) return(FlashProgramError);
             }
#endif /* WRITE_EEPROM */
        else return(SRecRangeError);
        
      }
    
    //feedback to serial port for each correctly programmed S-Record
    (void)putchar('*');
    
    }
  }
 
  return(Error);

}
#if BOOTLODER_REWRITABLE 
#pragma CODE_SEG DEFAULT
#endif /* BOOTLODER_REWRITABLE */

#if BOOTLODER_REWRITABLE
/*******************************************************************************
 Function Name : UnprotectBL
 Engineer      : NXA19261
 Date          : Aug-17-2017
 Parameters    : NONE
 Modifies      : NONE
 Returns       : NONE
 Notes         : Unprotect Flash and EEPROM.
 Issues        : NONE
 *******************************************************************************/  
#pragma CODE_SEG DEFAULT_RAM
unsigned int UnprotectBL(void)
{
  unsigned int key;
  unsigned char Error = noErr; 
  OutStr("\r\nEnter Protection Override key:\r\n");
  key = ((unsigned int) getchar()<<8);                        //get high byte
  key |= (unsigned int) getchar();                            //get low byte
  Error = PFLASH_Protection_Override(key, 0xFF, 0xFF, 0x01);  //update FPROT value to the 0xFF
  if (Error) return(BadHexData);
  return (noErr);
}
#pragma CODE_SEG DEFAULT

/*******************************************************************************
 Function Name : EraseBL
 Engineer      : NXA19261
 Date          : Aug-17-2017
 Parameters    : NONE
 Modifies      : NONE
 Returns       : NONE
 Notes         : Erase Bootloader.
 Issues        : NONE
 *******************************************************************************/ 
#pragma CODE_SEG DEFAULT_RAM
unsigned int EraseBL(void)
{
  unsigned char Error = noErr; 
  Error = PFLASH_EraseSectorBySector(BOOTLOADER_START_ADD, BOOTLOADER_END_ADD);
  if (Error) return(FlashEraseError);
  return (noErr);
}
#pragma CODE_SEG DEFAULT

/*******************************************************************************
 Function Name : ProgramBL
 Engineer      : NXA19261
 Date          : Aug-17-2017
 Parameters    : NONE
 Modifies      : NONE
 Returns       : NONE
 Notes         : Program Bootloader S record to the Flash.
 Issues        : NONE
 *******************************************************************************/ 
#pragma CODE_SEG DEFAULT_RAM
unsigned char ProgramBL(void)
{
  SRecDataRec ProgSRec;
  unsigned char Error = noErr; 

  for(;;)
  {
    Error = RcvSRecord(&ProgSRec);
    if (Error != noErr) //go get an S-Record, return if there was an error 
      break;
    
    if (ProgSRec.RecType == EndRec) // S7, S* or S9 record? 
      break;                        // yes. return 
      
    else if (ProgSRec.RecType == HeaderRec)       //S0 record?
      continue;                     //yes. just ignore it
      
    else                            //a data record was received 
    {
        
      if ((ProgSRec.LoadAddr & 0x0000001FUL) != 0) //S-Record address aligned?
        return(SRecOddError);       //yes. return
      if (ProgSRec.NumBytes != 32)  //S-Record constant length 32?
        return(SRecOddError);       //yes. return
      
       
      //is the address within a physical flash?
      if (!((ProgSRec.LoadAddr >= BOOTLOADER_START_ADD) && (ProgSRec.LoadAddr <= BOOTLOADER_END_ADD)))
            return(SRecRangeError);
        
      Error = PFLASH_Program(ProgSRec.LoadAddr, (unsigned int *)&ProgSRec.Data);
      if (Error) return(FlashProgramError);
      Error = PFLASH_Program(ProgSRec.LoadAddr+8, (unsigned int *)&ProgSRec.Data[8]);
      if (Error) return(FlashProgramError);
      Error = PFLASH_Program(ProgSRec.LoadAddr+16, (unsigned int *)&ProgSRec.Data[16]);
      if (Error) return(FlashProgramError);
      Error = PFLASH_Program(ProgSRec.LoadAddr+24, (unsigned int *)&ProgSRec.Data[24]);
      if (Error) return(FlashProgramError);
    
    
    //feedback to serial port for each correctly programmed S-Record
    (void)putchar('*');
    
    }
  }
 
  return(Error);

}
#pragma CODE_SEG DEFAULT

#endif /* BOOTLODER_REWRITABLE */ 

/*******************************************************************************
 Function Name : DisplayMenu
 Engineer      : NXA19261
 Date          : Aug-17-2017
 Parameters    : NONE
 Modifies      : NONE
 Returns       : NONE
 Notes         : Display menu through SCI.
 Issues        : NONE
/******************************************************************************/
#if BOOTLODER_REWRITABLE 
#pragma CODE_SEG DEFAULT_RAM
#endif /* BOOTLODER_REWRITABLE */
void DisplayMenu(void)
{
  char c;

  OutStr("\f\r\nS12Z Bootloader v1.0\r\n");    // sign-on

  for(;;)
  {
    //display menu
    OutStr("\r\na.) Erase Flash\r\n");
#if WRITE_EEPROM
    OutStr("b.) Program Flash/EEPROM\r\n");
#else
    OutStr("b.) Program Flash\r\n");
#endif /* WRITE_EEPROM */
    OutStr("c.) Set Baud Rate\r\n");
    OutStr("d.) Execute Application\r\n");
#if BOOTLODER_REWRITABLE 
    OutStr("e.) Unprotect Bootloader\r\n");
    OutStr("f.) Erase Bootloader\r\n");
    OutStr("g.) Program Bootloader\r\n");
#endif /* BOOTLODER_REWRITABLE */
#if WRITE_EEPROM 
    OutStr("h.) Erase EEPROM\r\n");
#endif /* WRITE_EEPROM */
   OutStr("? ");
    c = getchar();      //get choice
    (void)putchar(c);   //echo choice
    OutStr("\r\n");     //next line
    
    switch (c) {
    
    case 'a':
      c = EraseFlash();
      if (c != 0)    //go erase all the Flash (except the bootloader)
        OutStr(GetErrorString(c));    // and report an error if there was one
      else
        OutStr("\r\nErased successfully!\r\n");
      break;
    
    case 'b':
      c = ProgramFlash();
      if (c != 0)    //go program the Flash
        OutStr(GetErrorString(c));    //and report an error if there was one
      else
        OutStr("\r\nDownloaded successfully!\r\n");
      break;
    
    case 'c':
      SetBaud();     //go set the SCI baud rate
      break;
    
    case 'd':
      AppExecute();  //go execute the application
      break;

#if BOOTLODER_REWRITABLE      
    case 'e':
      c = UnprotectBL();
      if (c != 0)    //go unprotect all the Flash and EEPROM
        OutStr(GetErrorString(c));    // and report an error if there was one
      else
        OutStr("\r\nUnprotection successfully!\r\n");
      break;
      
    case 'f':
      c = EraseBL();
      if (c != 0)    //go erase the Bootloader
        OutStr(GetErrorString(c));    // and report an error if there was one
      else
        OutStr("\r\nErased successfully!\r\n");
      break;
      
    case 'g':
      c = ProgramBL();
      if (c != 0)    //go program the Bootloader
        OutStr(GetErrorString(c));    //and report an error if there was one
      else
        OutStr("\r\nBootloader downloaded successfully!\r\n");
      break;
#endif /* BOOTLODER_REWRITABLE */

#if WRITE_EEPROM      
    case 'h':
      c = EraseEEPROM();
      if (c != 0)    //go erase the Bootloader
        OutStr(GetErrorString(c));    // and report an error if there was one
      else
        OutStr("\r\nErased successfully!\r\n");
      break;
      
#endif /* WRITE_EEPROM */
      
    default:
      break;
     
    }
   
  }
}
#if BOOTLODER_REWRITABLE 
#pragma CODE_SEG DEFAULT
#endif /* BOOTLODER_REWRITABLE */

/*******************************************************************************
 Function Name : AppExecute
 Engineer      : NXA19261
 Date          : Aug-17-2017
 Parameters    : NONE
 Modifies      : NONE
 Returns       : NONE
 Notes         : Reset MCU through CPMU COP reset.
 Issues        : NONE
 *******************************************************************************/
#if BOOTLODER_REWRITABLE 
#pragma CODE_SEG DEFAULT_RAM
#endif /* BOOTLODER_REWRITABLE */
void AppExecute(void)
{
  CPMUCOP = 0x01;     //enable watchdog
  CPMUARMCOP = 0x00;
  //value written to ARMCOP register different from 0xAA or 0x55 will reset
  //the MCU immediately.
}
#if BOOTLODER_REWRITABLE 
#pragma CODE_SEG DEFAULT
#endif /* BOOTLODER_REWRITABLE */

