/*******************************************************************************
 * (c) Copyright 2009 Actel Corporation.  All rights reserved.
 *
 * Demo Application for loading and booting from external memories of
 * SmartFusion
 */

#include "mss_uart.h"
#include "mss_watchdog.h"
#include "spi_flash.h"

static void spi_flash_loader(void);

size_t
UART_Polled_Rx
(
   mss_uart_instance_t * this_uart,
   uint8_t * rx_buff,
   size_t buff_size
)
{
   size_t rx_size = 0U;
   while( rx_size < buff_size )
   {
       while ( this_uart->hw_reg_bit->LSR_DR != 0U  )
       {
          rx_buff[rx_size] = this_uart->hw_reg->RBR;
          ++rx_size;
       }
   }
   return rx_size;
}


/*==============================================================================
 * main function.
 */


int main()
{
   uint8_t rx_buff[1];
   /*--------------------------------------------------------------------------
    * Disable watchdog.
   */
   MSS_WD_disable();

   /* Initialize and configure UART0. */
   MSS_UART_init( &g_mss_uart0, 
   MSS_UART_57600_BAUD,
   MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT );

   /* Handshake */
   while(!(UART_Polled_Rx ( &g_mss_uart0, rx_buff, 1 )))
      ;
   if(rx_buff[0] == 'h')
      MSS_UART_polled_tx( &g_mss_uart0, (const uint8_t * )"a", 1 );
   while(!(UART_Polled_Rx ( &g_mss_uart0, rx_buff, 1 )))
      ;
   if(rx_buff[0] == 'n')
      MSS_UART_polled_tx( &g_mss_uart0, (const uint8_t * )"d", 1 );
   while(!(UART_Polled_Rx ( &g_mss_uart0, rx_buff, 1 )))
      ;
   if(rx_buff[0] == 's')
      MSS_UART_polled_tx( &g_mss_uart0, (const uint8_t * )"h", 1 );
   while(!(UART_Polled_Rx ( &g_mss_uart0, rx_buff, 1 )))
      ;
   if(rx_buff[0] == 'a')
      MSS_UART_polled_tx( &g_mss_uart0, (const uint8_t * )"k", 1 );
   while(!(UART_Polled_Rx ( &g_mss_uart0, rx_buff, 1 )))
      ;
   if(rx_buff[0] == 'e')
   {
      /* EMC or SPI Flash*/
      while( ! UART_Polled_Rx(&g_mss_uart0, rx_buff, 1))
         ;
      if(rx_buff[0] == 's')
      {
         spi_flash_loader();
      }
      else
      {
         MSS_UART_polled_tx( &g_mss_uart0, (const uint8_t * )"Selected Option is wrong, Please enter correct value", sizeof("Selected Option is wrong, Please enter correct value") );
      }
   }
   return 0;
}
static void spi_flash_loader(void)
{
   size_t rx_size;
   uint8_t img_buffer[1024];
   uint32_t  address, oriAddress;
   int32_t img_size,ii,length, oriSize;
   
   /* Read the file and burn into external flash */
   while( ! UART_Polled_Rx(&g_mss_uart0, (uint8_t *)&img_size, 4))
      ;
   spi_flash_init();
   spi_flash_control_hw(SPI_FLASH_GLOBAL_UNPROTECT,0,NULL);
   spi_flash_control_hw(SPI_FLASH_CHIP_ERASE,0,NULL);
   MSS_UART_polled_tx( &g_mss_uart0,(const uint8_t * )&img_size, 4 );
   oriSize = img_size;
   /* Read the file and burn into external flash */
   while( ! UART_Polled_Rx(&g_mss_uart0, (uint8_t *)&address, 4))
      ;
   MSS_UART_polled_tx( &g_mss_uart0,(const uint8_t * )&address, 4 );
   oriAddress = address;
   ii = 0;
   while(img_size > 0)
   {
      rx_size =0;
      if (img_size >=1024)
      {
         length = 1024;
      }
      else
      {
         length = img_size;
      }
      do
      {
         rx_size = UART_Polled_Rx(&g_mss_uart0, (uint8_t *)&img_buffer, length);
      }
      while(!rx_size);

      if(rx_size != length)
      {
         return;
      }
      img_size -= length;
      /* alligning to 32 bit */
      if ((length%4) != 0)
      {
         length += (4-(length%4));
      }
      spi_flash_write(address + ii, img_buffer, length);
      ii += length;
      MSS_UART_polled_tx(&g_mss_uart0,(const uint8_t * )"a",1);
   }
   /* Verify the last bytes */
   {
      uint8_t img_buffer2[1030];
      ii -= length;
      spi_flash_read(address + ii, img_buffer2, length);
      for(ii=0; ii<length; ii++)
      {
         if(img_buffer[ii] != img_buffer2[ii])
         {
            MSS_UART_polled_tx(&g_mss_uart0,(const uint8_t * )"z",1);
            return;
         }
                    
      }
      MSS_UART_polled_tx(&g_mss_uart0,(const uint8_t * )"y",1);
   }
   return;        
}
