/*******************************************************************************
 * (c) Copyright 2011 Microsemi Corporation.  All rights reserved.
 *
 *  Sample Bootloader for SmartFusion
 *
 *
 * Author : Corporate Application Team
 * Rev    : 2.0
 *
 *******************************************************************************/

/**************************************************************************/
/* Standard Includes */
/**************************************************************************/

#include <stdio.h>
#include <stdlib.h>

/**************************************************************************/
/* Firmware Includes */
/**************************************************************************/

#include "a2fxxxm3.h"
#include "mss_uart.h"
#include "./drivers/mss_watchdog/mss_watchdog.h"
#include "./drivers/mss_timer/mss_timer.h"
#include "boot_config.h"

/**************************************************************************/
/* RTOS Includes */
/**************************************************************************/

/**************************************************************************/
/*Extern Declarations*/
/**************************************************************************/

void bx_user_code_esram(void);
void bx_3rd_eNVM_Image(void);

#define VECTOR_TABLE_ADDR_3RD_IMAGE 0x00020000
#define VECTOR_TABLE_ADDR_2ND_IMAGE 0x20000000

uint32_t boot_time_out;

void copy_esram_image()
{
    unsigned int ii=0;
    unsigned long *exeDestAddr, *exeSrcAddr;

    exeDestAddr = (unsigned long *)0x20000000;
    exeSrcAddr = (unsigned long *)0x60010000;
    /* 60 K B = 61440/4 ptr increments by 4bytes*/
    for (ii=0; ii<15360; ii++ )
    {
    	*exeDestAddr++ = *exeSrcAddr++;
    }

}

size_t
UART_Polled_Rx
(
    mss_uart_instance_t * this_uart,
    uint8_t * rx_buff,
    size_t buff_size
)
{
    size_t rx_size = 0U;

//    ASSERT( (this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1) );
    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;
       }
       if(boot_time_out)
       {
    	   break;
       }

    }

    return rx_size;
}
/****************************************************************/
/* Entry to Main form user bootcode                             */
/****************************************************************/

void Timer1_IRQHandler(void)
{
	boot_time_out = 1;
	MSS_TIM1_clear_irq();
	MSS_TIM1_disable_irq();

}

int main()
{
    uint8_t rx_buff[1];
    uint32_t ii;
    /* Disable the Watch Dog Timer */
    MSS_WD_disable( );


	/* Initialization all necessary hardware components */
    MSS_UART_init( &g_mss_uart0,MSS_UART_57600_BAUD,MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT );
  	MSS_UART_polled_tx(&g_mss_uart0,(uint8_t *)"#### SmartFusion Bootloader Example ####\n\r",sizeof("#### SmartFusion Bootloader Example ####\n\r"));


  	MSS_TIM1_init(MSS_TIMER_ONE_SHOT_MODE);
  	MSS_TIM1_load_immediate( (uint32_t)BOOT_DELAY_TIMER_VAL );
  	MSS_TIM1_enable_irq();

  	while(1)
  	{
  	    MSS_UART_polled_tx(&g_mss_uart0,(uint8_t *)"Pls Select the Following option with in 30 Secs \n\r",sizeof("Pls Select the Following option  with in 30 Secs \n\r"));
  	    MSS_UART_polled_tx(&g_mss_uart0,(uint8_t *)"1. IAP Programmer (Region 2)\n\r",sizeof("1. IAP Programmer (Region 2)\n\r"));
  	    MSS_UART_polled_tx(&g_mss_uart0,(uint8_t *)"2. Application (Region 3)-> Default bootImage \n\r",sizeof("2. Application (Region 3)-> Default bootImage  \n\r"));

  	    MSS_TIM1_start();
  		while( (!(UART_Polled_Rx ( &g_mss_uart0, rx_buff, 1 ))) && (!boot_time_out))
			;
  	    MSS_TIM1_stop();

  		if(boot_time_out == 1)
  		{
  	  	    MSS_UART_polled_tx(&g_mss_uart0,(uint8_t *)"Timeout occurred Booting application (3rd Image)\n\r",sizeof("Timeout occurred Booting application (3rd Image) \n\r"));
  	  	    rx_buff[0] = '2';
  	  	    /* Delay loop */
  	  	    for(ii =0; ii<0xFFFF; ii++)
  	  	    {
  	  	    	;
  	  	    }
  		}
	    if(rx_buff[0] == '1')
	    {
	  	    MSS_UART_polled_tx(&g_mss_uart0,(uint8_t *)"Disconnect this Hyperteminal /putty \n\r",sizeof("Disconnect this Hyperteminal /putty \n\r"));
	  	    MSS_UART_polled_tx(&g_mss_uart0,(uint8_t *)"and Start the host tool to do IAP\n\r",sizeof("and Start the host tool to do IAP\n\r"));

	    	copy_esram_image();

            bx_user_code_esram();
	    }
	    else if(rx_buff[0] == '2')
	    {
		    bx_3rd_eNVM_Image();
	    }
	    else
	    {
	  	    MSS_UART_polled_tx(&g_mss_uart0,(uint8_t *)"Incorrect option\n\r",sizeof("Incorrect option"));
	    }
  	}
    return 0;
}
