/***********************************************************************************************
* Company: Microsemi Corporation
*
* File: main.c
* File history:
*      Revision: 1.1 Date: May 7, 2013
*
* Description:
*
*	Program to do the Code Shadowing from SPI Flash to DDR memory. This program interfaces
*	with the GUI running on the Host PC through MMUART_0.
*	UartMsgHandler()   - 	handles the commands received from the GUI
*	spi_flash_loader() -    Programs the SPI Flash with the image received from GUI through
*							the MMUART_0
*	spi_flash_bootloader()- copies the code from SPI Flash to DDR and boots the application
*							image from DDR memory
*
* Author: Corporate Applications Engineering
*
************************************************************************************************/
#include "drivers/mss_uart/mss_uart.h"
#include "BSP/spi_flash_driver/winbondflash.h"

static void spi_flash_loader(void);

/*
 * Application receive handler called when UART0 receives data.
 */
void uart1_rx_handler( mss_uart_instance_t * this_uart );
static void UartMsgHandler(void);

uint8_t   key;
uint8_t rx_buff[1];
uint32_t MDDR_status=0;

void UartMsgHandler(){

      switch(key)
      {
				 case 'i':
      					   if((MDDR_status&0x2) == 0x2)
      						   MSS_UART_polled_tx( &g_mss_uart1, (const uint8_t *)"s", 1 );
      					   else
      						   MSS_UART_polled_tx( &g_mss_uart1, (const uint8_t *)"d", 1 );
      					   break;
                 case 'P':
						   MSS_UART_disable_irq(&g_mss_uart1,MSS_UART_RBF_IRQ );
      					   spi_flash_loader();				//program SPI Flash
      					   MSS_UART_enable_irq(&g_mss_uart1,MSS_UART_RBF_IRQ );
      					   break;
        }
}

void uart1_rx_handler( mss_uart_instance_t * this_uart )
{
	size_t rx_size = 0U;
	rx_size = MSS_UART_get_rx( &g_mss_uart1, &key, 1);

      if(rx_size==1)
      {
    	  UartMsgHandler();
          rx_size  = 0;
          key=0;
      }
}

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->LSR) & 0x1) != 0U  )
       {
           rx_buff[rx_size] = this_uart->hw_reg->RBR;
           ++rx_size;
       }
    }

    return rx_size;
}


/*==============================================================================
 * main function.
 */
int main()
{

   /* Initialize and configure UART0. */
    MSS_UART_init( &g_mss_uart1,
                  MSS_UART_115200_BAUD,
                  MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT );
    MDDR_status = SYSREG->MDDR_CR;
    MSS_UART_set_rx_handler( &g_mss_uart1,
                             uart1_rx_handler,
                             MSS_UART_FIFO_SINGLE_BYTE );
    FLASH_init();

  while(1)
  {

  }
   return 0;
}

static void spi_flash_loader(void)
{
    size_t rx_size;
    uint8_t img_buffer[1024];
    uint8_t img_buffer2[1030];
    uint32_t address, oriAddress;
    uint32_t img_size = 0,ii = 0,length = 0, oriSize = 0;
    ii     = 0;
    length = 0;
//    spi_flash_status_t spi_status;

    uint32_t erase_count = 0,erase_address =0;

    /**************handshaking with MMUART***********************/

    while(!(UART_Polled_Rx ( &g_mss_uart1, rx_buff, 1 )))
         ;
    if(rx_buff[0] == 'h')
        MSS_UART_polled_tx( &g_mss_uart1, (const uint8_t *)"a", 1 );

    while(!(UART_Polled_Rx ( &g_mss_uart1, rx_buff, 1 )))
         ;

    if(rx_buff[0] == 'n')
        MSS_UART_polled_tx( &g_mss_uart1, (const uint8_t *)"d", 1 );

    while(!(UART_Polled_Rx ( &g_mss_uart1, rx_buff, 1 )))
         ;

    if(rx_buff[0] == 's')
        MSS_UART_polled_tx( &g_mss_uart1, (const uint8_t *)"h", 1 );

    while(!(UART_Polled_Rx ( &g_mss_uart1, rx_buff, 1 )))
         ;

    if(rx_buff[0] == 'a')
        MSS_UART_polled_tx( &g_mss_uart1, (const uint8_t *)"k", 1 );


    /* Read the image size */
    while( ! UART_Polled_Rx(&g_mss_uart1, (uint8_t *)&img_size, 4));

    MSS_UART_polled_tx( &g_mss_uart1,(const uint8_t *)&img_size, 4 );

    oriSize = img_size;

    /* Read the address */
    while( ! UART_Polled_Rx(&g_mss_uart1, (uint8_t *)&address, 4))
        ;

    MSS_UART_polled_tx( &g_mss_uart1,(const uint8_t *)&address, 4 );
    oriAddress = address;



    /*********** Read the file and burn into external flash *****************/

    /* Erasing SPI flash*/

    FLASH_global_unprotect();
	for(erase_count = 0;erase_count<=4;erase_count++)  //4 * 64K erase
	{
		FLASH_erase_64k_block(erase_address);
		erase_address+=0x10000;

	}

    MSS_UART_polled_tx( &g_mss_uart1, (const uint8_t *)"c", 1 );


    while(img_size > 0)
    {
        rx_size =0;
        if (img_size >=256)
        {
            length = 256;
        }
        else
        {
            length = img_size;
        }

        do
        {
            rx_size = UART_Polled_Rx(&g_mss_uart1, (uint8_t *)&img_buffer, length);
        }
        while(!rx_size);

        if(rx_size != length)
        {
            return;
        }
        img_size -= length;
          /* aligning to 32 bit */
        if ((length%4) != 0)
        {
            length += (4-(length%4));
        }
        FLASH_program(address + ii, img_buffer, length);


        		ii += length;

        MSS_UART_polled_tx(&g_mss_uart1,(const uint8_t *)"p",1);


    }
           /* Verify the last bytes */

        ii -= length;
        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_uart1,(const uint8_t *)"v",1);
                return;
            }
        }
        MSS_UART_polled_tx(&g_mss_uart1,(const uint8_t *)"y",1);
        //exit_4byte_address_mode();
    return;
}

