/***********************************************************************
*
*  FILE        : rx65n_fit_test.c
*  DATE        : 2018-08-01
*  DESCRIPTION : Main Program
*
*  NOTE:THIS IS A TYPICAL EXAMPLE.
*
***********************************************************************/
#include "r_smc_entry.h"
#include "r_cg_userdefine.h"
#include "r_usb_pmsc_apl.h"
#include "r_flash_rx_if.h"
#include "r_ram_disk.h"

void main(void);
void R_USB_PinSet_USB0_PERI(void);
extern volatile uint32_t g_1ms_count; // incremented every 1ms, defined Config_CMT0_user.c

static	void	userapl_jump_to_user_application( void );
static	void	userapl_reset_to_user_application( void );
static	void	userapl_ErrorEnd( void );
static	void	userapl_StartExecution( PDIRENT );

static usb_descriptor_t usb_descriptor =
{
    g_apl_device,
    g_apl_configuration,
    USB_NULL,
    USB_NULL,
    g_apl_string_table,
    NUM_STRING_DESCRIPTOR
};

void main(void)
{
    usb_ctrl_t  ctrl;
    usb_cfg_t   cfg;
	static PDIRENT		pdeFileInfo;

	if( SYSTEM.RSTSR2.BIT.SWRF == 1 ) // in case of software reset
	{
		userapl_jump_to_user_application();
	}

	if( SYSTEM.RSTSR1.BIT.CWSF == 0 ) // in case of cold start
	{
	    SYSTEM.PRCR.WORD = 0xA50BU;
		SYSTEM.RSTSR1.BIT.CWSF = 1; // set warm start from reset terminal
	    SYSTEM.PRCR.WORD = 0xA500U;
		userapl_jump_to_user_application();
	}


	R_Config_CMT0_Start();

    R_USB_PinSet_USB0_PERI();

	if(USB.DPUSR0R.BIT.DVBSTS0 == 0) // in case of no connection with VBUS
	{
		userapl_jump_to_user_application();
	}

    R_USB_media_initialize(&g_ram_mediadriver); /* Register the media device driver. */
    R_USB_media_open();                         /* Start up the  media device hardware. */

    ctrl.module     = USE_USBIP;
    ctrl.type       = USB_PMSC;
    cfg.usb_speed   = USB_SUPPORT_SPEED;
    cfg.usb_mode    = USB_PERI;
    cfg.p_usb_reg     = &usb_descriptor;
    R_USB_Open(&ctrl, &cfg); /* Initializes the USB module */

    while (1)
    {
        switch (R_USB_GetEvent(&ctrl))
        {
            case USB_STS_SUSPEND :
            case USB_STS_DETACH :
#if defined(USE_LPW)
                 low_power_mcu();
#endif /* defined(USE_LPW) */
            break;
            default :
            	pdeFileInfo = fatfs_FindUserApplicationFileInfo();
    			if(  pdeFileInfo != NULL )
    			{
    				if (g_1ms_count > 3000){
    					USB0.SYSCFG.WORD &= ~(0x0010u); // Clear DPRPU to detach
    				    R_USB_Close(&ctrl);
        			    userapl_StartExecution(pdeFileInfo);
    				}
    			} else {
    				g_1ms_count = 0;
    				if( (USB0.INTSTS0.WORD & 0x0070) == 0 ) // in case of no connection with PC
    				{
    					userapl_jump_to_user_application();
    				}
    			}
            break;
        }
    }
}

static void userapl_jump_to_user_application( void )
{
	#define	JUMP(_addr_)		((void(*)())_addr_)()

	JUMP( USBC_PMSC_USER_APPLICATION_ADDR );
}

void userapl_ErrorEnd( void )
{
	g_1ms_count = 0;
	LED0 = 0;
	LED1 = 0;

	R_Config_CMT0_Start();
	while(1){
		if(g_1ms_count > 100){
			LED0 = !LED0;
			LED1 = !LED1;
			g_1ms_count = 0;
		}
	}
}

static void userapl_reset_to_user_application( void )
{
	SYSTEM.PRCR.WORD	= 0xA503;
	SYSTEM.SWRR			= 0xA501;	// software reset
}

/******************************************************************************
* Function Name	:	userapl_StartExecution()
* Description	:	Start user application
* Argument		:	none
* Return		:	none (not return)
******************************************************************************/
static void userapl_StartExecution( PDIRENT pdeFileInfo )
{
	static uint16_t		nClusNo;
	static uint32_t		nLeftSize, addrWrite;
	static uint8_t	pbBuffer[FATFS_CLUSTER_SIZE];
	static flash_err_t 	err;


	// LEDを消灯
	LED0 = 0;
	LED1 = 0;

	//
	//	ファイル情報から○○○.binファイルを検索
	//
#if 0
	pdeFileInfo = fatfs_FindUserApplicationFileInfo();
	if( pdeFileInfo == NULL )
	{
		userapl_ErrorEnd();
	}
	if( pdeFileInfo->nFileSize == 0 )
	{
		userapl_ErrorEnd();
	}
#endif
	//
	//	ユーザーAPL領域を全て消去する
	//
	LED0 = 1;
	LED1 = 0;
	for( addrWrite = USBC_PMSC_USER_APPLICATION_ADDR;
		 addrWrite <= USBC_PMSC_USER_APPLICATION_END; ){

		R_BSP_InterruptsDisable();
		R_FLASH_Erase(addrWrite, 1);
		if (FLASH_SUCCESS != err)
		{
    		userapl_ErrorEnd();
		}
		R_BSP_InterruptsEnable();
		addrWrite += USBC_PMSC_STORAGE_FLASH_BLOCKSIZE;
		LED0 = !LED0;
		LED1 = !LED1;
	}

	//
	//	○○○.binのデータをユーザーAPL領域へコピーする
	//
	nClusNo		= pdeFileInfo->nClusNo;
	nLeftSize	= pdeFileInfo->nFileSize;
	addrWrite	= USBC_PMSC_USER_APPLICATION_ADDR;

	while( (nLeftSize > 0) && (nClusNo != (uint16_t)-1) )
	{
		void*	pStorageData;

		//
		//	書き込みデータの準備
		//
		pStorageData = fatfs_GetClusterData( nClusNo );
		if( nLeftSize >= FATFS_CLUSTER_SIZE )
		{
			memcpy( pbBuffer, pStorageData, FATFS_CLUSTER_SIZE );
			nLeftSize -= FATFS_CLUSTER_SIZE;
		}
		else
		{
			memcpy( pbBuffer, pStorageData, nLeftSize );
			memset( pbBuffer + nLeftSize, 0, (FATFS_CLUSTER_SIZE-nLeftSize) );	// Wipe invalid area
			nLeftSize = 0;
		}

		//
		//	データを書き込み
		//
    	err = R_FLASH_Write(pbBuffer, addrWrite, FATFS_CLUSTER_SIZE);
    	if (FLASH_SUCCESS != err)
    	{
    		userapl_ErrorEnd();
    	}

		//
		//	次のクラスタ番号を取得する
		//
		nClusNo = fatfs_GetNextClusterNo( nClusNo );

		addrWrite += FATFS_CLUSTER_SIZE;
		LED0 = !LED0;
		LED1 = !LED1;


	} //end of while( (nLeftSize > 0) && (nClusNo != (uint16_t)-1) )

	//
	//	ユーザーAPL領域へジャンプする
	//
	userapl_reset_to_user_application();
}
/******************************************************************************
End of function
******************************************************************************/

#pragma	section	_UserApplicationArea
void userapl_DummyCode( void )
{
	userapl_ErrorEnd();
}
