text: /***************************************************************************//**
   * @file     isp_user.c
   * @brief    ISP Command source file
   *
   * @copyright SPDX-License-Identifier: Apache-2.0
   * @copyright Copyright (C) 2020 Nuvoton Technology Corp. All rights reserved.
   ******************************************************************************/
  #include <stdio.h>
  #include <string.h>
  #include "isp_user.h"
  
  __attribute__((aligned(4))) uint8_t response_buff[64];
  __attribute__((aligned(4))) static uint8_t aprom_buf[FMC_FLASH_PAGE_SIZE];
  uint32_t g_apromSize, g_dataFlashAddr, g_dataFlashSize;
  
  static uint16_t Checksum(unsigned char *buf, int len)
  {
      int i;
      uint16_t c;
  
      for(c = 0, i = 0 ; i < len; i++)
      {
          c += buf[i];
      }
  
      return (c);
  }
  
  int ParseCmd(unsigned char *buffer, uint8_t len)
  {
      static uint32_t StartAddress, StartAddress_bak, TotalLen, TotalLen_bak, LastDataLen, g_packno = 1;
      uint8_t *response;
      uint16_t lcksum;
      uint32_t lcmd, srclen;
      unsigned char *pSrc;
      static uint32_t gcmd;
  
      response = response_buff;
      pSrc = buffer;
      srclen = len;
      lcmd = inpw((uint32_t)pSrc);
      outpw((uint32_t)(response + 4), 0);
      pSrc += 8;
      srclen -= 8;
      ReadData(Config0, Config0 + 16, (uint32_t *)((uint32_t)(response + 8))); //read config
  
      if(lcmd == CMD_SYNC_PACKNO)
      {
          g_packno = inpw((uint32_t)pSrc);
      }
  
      if((lcmd) && (lcmd != CMD_RESEND_PACKET))
      {
          gcmd = lcmd;
      }
  
      if(lcmd == CMD_GET_FWVER)
      {
          response[8] = FW_VERSION;
      }
      else if(lcmd == CMD_GET_DEVICEID)
      {
          outpw((uint32_t)(response + 8), SYS->PDID);
          goto out;
      }
      else if(lcmd == CMD_RUN_APROM)
      {
          FMC_SetVectorPageAddr(FMC_APROM_BASE);
          NVIC_SystemReset();
  
          /* Trap the CPU */
          while(1);
      }
      else if(lcmd == CMD_CONNECT)
      {
          g_packno = 1;
          outpw((uint32_t)(response + 8), g_apromSize);
          outpw((uint32_t)(response + 12), g_dataFlashAddr);
          goto out;
      }
      else if(lcmd == CMD_ERASE_ALL)
      {
          EraseAP(FMC_APROM_BASE, g_apromSize);
      }
  
      if((lcmd == CMD_UPDATE_APROM) || (lcmd == CMD_UPDATE_DATAFLASH))
      {
          if(lcmd == CMD_UPDATE_DATAFLASH)
          {
              StartAddress = g_dataFlashAddr;
  
              if(g_dataFlashSize)    //g_dataFlashAddr
              {
                  EraseAP(g_dataFlashAddr, g_dataFlashSize);
              }
              else
              {
                  goto out;
              }
          }
          else
          {
              StartAddress = inpw((uint32_t)pSrc);
              TotalLen = inpw((uint32_t)(pSrc + 4));
              EraseAP(StartAddress, TotalLen);
          }
  
          //StartAddress = inpw(pSrc);
          TotalLen = inpw((uint32_t)(pSrc + 4));
          pSrc += 8;
          srclen -= 8;
          StartAddress_bak = StartAddress;
          TotalLen_bak = TotalLen;
      }
      else if(lcmd == CMD_UPDATE_CONFIG)
      {
          UpdateConfig((uint32_t *)(uint32_t)pSrc, (uint32_t *)((uint32_t)(response + 8)));
          goto out;
      }
      else if(lcmd == CMD_RESEND_PACKET)      //for APROM&Data flash only
      {
          uint32_t PageAddress;
          StartAddress -= LastDataLen;
          TotalLen += LastDataLen;
          PageAddress = StartAddress & (0x100000 - FMC_FLASH_PAGE_SIZE);
  
          if(PageAddress >= Config0)
          {
              goto out;
          }
  
          ReadData(PageAddress, StartAddress, (uint32_t *)aprom_buf);
          FMC_Erase_User(PageAddress);
          WriteData(PageAddress, StartAddress, (uint32_t *)aprom_buf);
  
          if((StartAddress % FMC_FLASH_PAGE_SIZE) >= (FMC_FLASH_PAGE_SIZE - LastDataLen))
          {
              FMC_Erase_User(PageAddress + FMC_FLASH_PAGE_SIZE);
          }
  
          goto out;
      }
  
      if((gcmd == CMD_UPDATE_APROM) || (gcmd == CMD_UPDATE_DATAFLASH))
      {
          if(TotalLen < srclen)
          {
              srclen = TotalLen;//prevent last package from over writing
          }
  
          TotalLen -= srclen;
          WriteData(StartAddress, StartAddress + srclen, (uint32_t *)(uint32_t)pSrc);
          memset(pSrc, 0, srclen);
          ReadData(StartAddress, StartAddress + srclen, (uint32_t *)(uint32_t)pSrc);
          StartAddress += srclen;
          LastDataLen =  srclen;
      }
  
  out:
      lcksum = Checksum(buffer, len);
      outps((uint32_t)response, lcksum);
      ++g_packno;
      outpw((uint32_t)(response + 4), g_packno);
      g_packno++;
      return 0;
  }
  