//*****************************************************************************
//
// bl_sdcard.c : Functions to transfer data via the UART port.
//
//*****************************************************************************

#include "hw_sci.h"
#include "bl_config.h"
#include "sci_common.h"
#include "sys_common.h"
#include "sd_card.h"
#include "ff.h"
#include "uartstdioBiolase.h"
#include "Types.h"
#include <string.h>

extern char file_name[FILE_NAME_LENGTH];
extern long Size;
extern uint32_t flashAddress;

//*****************************************************************************
//
// Defines the size of the buffers that hold the path, or temporary data from
// the SD card.  There are two buffers allocated of this size.  The buffer size
// must be large enough to hold the longest expected full path name, including
// the file name, and a trailing null character.
//
//*****************************************************************************
#define SDCARD_PATH_BUF_SIZE           80

//*****************************************************************************
//
// This buffer holds the full path to the current working directory.  Initially
// it is root ("/").
//
//*****************************************************************************
static char g_cwdBuf[SDCARD_PATH_BUF_SIZE] = "/";

//*****************************************************************************
//
// A temporary data buffer used when manipulating file paths, or reading data
// from the SD card.
//
//*****************************************************************************
static char g_tmpBuf[SDCARD_PATH_BUF_SIZE];


//*****************************************************************************
//
// The following are data structures used by FatFs.
//
//*****************************************************************************
static FIL g_fileObject;


extern void get_software_Version(void);
extern void get_hardware_Info(void);

extern Fapi_StatusType bootloader_FlashApplicationRegion(void);
extern Fapi_StatusType bootloader_FlashEraseApplication(void);
extern Fapi_StatusType Fapi_doBlankCheck(
uint32_t* pu32StartAddress,
uint32_t u32Length,
Fapi_FlashStatusWordType* poFlashStatusWord
);


void raptorBootloaderUpdater(void);

uint32_t JumpSDCardAddress;


//*****************************************************************************
//
//! This function performs the update on the selected port.
//!
//! This function is called directly by the boot loader or it is called as a
//! result of an update request from the application.
//!
//! \return Never returns.
//
//*****************************************************************************
void UpdaterSDCard(void)
{
	  char key = 0;

	  /* Upload user application from the Flash */
	  bootloader_FlashApplicationRegion();

      JumpSDCardAddress = (uint32_t)APP_START_ADDRESS;
      ((void (*)(void))JumpSDCardAddress)();

#if 0
	  while (1)
	  {
		    UART_putString(UART, "\r\n\r\n");
			UART_putString(UART, "\r================== Main Menu ==========================\r\n");
			UART_putString(UART, "  1. Download Application Image Over SDCARD/SPI2 To the Internal Flash \r\n");
			UART_putString(UART, "  2. Execute The Application Code \r\n");
			UART_putString(UART, "  3. Get Bootloader Version \r\n");
			UART_putString(UART, "  4. Get Device Information \r\n");
			UART_putString(UART, "  5. SDCard FS - List Directory Contents Test\r\n");
			UART_putString(UART, "  6. SDCard FS - Print Working Directory Test\r\n");
			UART_putString(UART, "  7. Auto-Raptor Bootloader and Application Start \r\n");
			UART_putString(UART,   "=======================================================\r\n");

			key = UART_getKey(UART);

			if (key == 0x31)
			{
		      /* Upload user application from the Flash */
		      bootloader_FlashApplicationRegion();
		    }
			else if (key == 0x32)
			{
		        JumpSDCardAddress = (uint32_t)APP_START_ADDRESS;
		        ((void (*)(void))JumpSDCardAddress)();
			}
			else if (key == 0x33)
			{
				get_software_Version();
			}
			else if (key == 0x34)
			{
				get_hardware_Info();
			}
			else if (key == 0x35)
			{
				lsUnitTest();
			}
			else if (key == 0x36)
			{
				pwdUnitTest();
			}
			else if (key == 0x37)
			{
			  raptorBootloaderUpdater();
			}
			else
			{
				UART_putString(UART, "Invalid Number !! \r");
			}
	  }

#endif
}

void raptorBootloaderUpdater(void)
{
    FRESULT iFResult;
    Fapi_StatusType FapiStatus    = Fapi_Error_Fail;
    char newFileName[9] = "updb.bin";
    char defaultFileName[9] = "facb.bin";
    char *file;
    uint8_t reflashApplication = 0;
    Fapi_FlashStatusWordType  oFlashStatusWord;
    TCHAR* fileToDelete;

    file = &newFileName[0];
    //
    // First, check to make sure that the current path (CWD), plus the file
    // name, plus a separator and trailing null, will all fit in the temporary
    // buffer that will be used to hold the file name.  The file name must be
    // fully specified, with path, to FatFs.
    //
    if(strlen(g_cwdBuf) + strlen(file) + 1 + 1 > sizeof(g_tmpBuf))
    {
        UARTprintf("Error: Resulting path name is too long\r\n");
    }

    //
    // Copy the current path to the temporary buffer so it can be manipulated.
    //
    strcpy(g_tmpBuf, g_cwdBuf);

    //
    // If not already at the root level, then append a separator.
    //
    if(strcmp("/", g_cwdBuf))
    {
        strcat(g_tmpBuf, "/");
    }

    //
    // Now finally, append the file name to result in a fully specified file.
    //
    strcat(g_tmpBuf, file);

    fileToDelete = &g_tmpBuf[0];

    //
    // Open the file for reading.
    //
    iFResult = f_open(&g_fileObject, g_tmpBuf, FA_READ);

    //
    // If there was some problem opening the file, then check if need to install factory version.
    //
    if(iFResult != FR_OK)
    {
      /* Check if Flash erased and if new software needs to be programmed */
      FapiStatus = Fapi_doBlankCheck( (uint32_t *)(flashAddress), 0x7FFF, &oFlashStatusWord);
      if (FapiStatus != Fapi_Status_Success)
      {
        UARTprintf("\r\n Application software already in Flash, starting application ...... \r\n");
    	//start new application software
        JumpSDCardAddress = (uint32_t)APP_START_ADDRESS;
        ((void (*)(void))JumpSDCardAddress)();
      }
      else
      {
    	UARTprintf("\r\n No software in flash, loading factory version in flash ...... \r\n");
  	    f_close(&g_fileObject);

  	    file = &defaultFileName[0];
  	    reflashApplication = 1;
      }
    }
	else
	{
	  f_close(&g_fileObject);

	  UARTprintf("\r\n New Application Software Detected on SDCard ...... \r\n");
	  UARTprintf("\r\n Erasing Flash ...... \r\n");

      // Erase Application Flash Region
  	  FapiStatus = bootloader_FlashEraseApplication();

      if ( FapiStatus == Fapi_Status_Success )
      {
    	//Program new Application File Into Flash
    	reflashApplication = 2;
      }
      else
      {
    	UARTprintf("\r\n ERROR Erasing Flash ......!!! \r\n");
      }
    }

    UARTprintf("\r\n Programming application binary onto Flash ...... \r\n");

    //Program new Application File Into Flash
    iFResult = (FRESULT) sdCardCatFlash((char *)file);

    if (reflashApplication == 2)
    {
      //delete new file from sdcard
      iFResult =  f_unlink(fileToDelete);
      //
      // If there was some problem deleting the file
      //
      if(iFResult != FR_OK)
      {
    	  UARTprintf("\r\n ERROR Deleting newb.bin ......!!! \r\n");
      }
      else
      {
    	  UARTprintf("\r\n OK Deleting newb.bin. \r\n");
      }
    }

    switch (iFResult)
    {
      case -1:
    	UART_putString(UART, "\n\rThe image size is larger than the allowed space memory!\n\r");
    	break;

      case -3:
    	UART_putString(UART, "\n\rError: The flash programming failed!\n\r");
    	break;

      case -4:
    	UART_putString(UART, "\r\n Error: Invalid Filename.\n\r");
    	break;

      default:
    	UART_putString(UART, "\r\n The application image has been programmed successfully!");
   	    //start new application software
        JumpSDCardAddress = (uint32_t)APP_START_ADDRESS;
        ((void (*)(void))JumpSDCardAddress)();
  	    break;
    }
}
