/**************************************************************************//**
 * @file     main.c
 * @version  V1.00
 * $Date: 14/11/20 9:22a $
 * @brief    Use SD card on SD port 0 as back end storage media to simulate a
 *           USB pen drive.
 *
 * @note
 * SPDX-License-Identifier: Apache-2.0
 * @copyright (C) 2020 Nuvoton Technology Corp. All rights reserved.
 ******************************************************************************/
#include <stdio.h>
#include <string.h>
#include "NUC505Series.h"
#include "massstorage.h"

extern DISK_DATA_T SD_DiskInfo0;

#if defined (__ICCARM__)
void USBD_IRQHandler_SRAM(void);
#endif

/******************************************************************************
 *--- Initial SD0 multi-function GPIO pin
 *
 * NUC505 support 3 groups of GPIO pins and SD sockets for same one SD port.
 * Please select ONLY ONE configuration from them.
 * 1. SD-A socket on daughter board + default SD0_Init(). (Default)
 * 2. SD-B socket on main board + short JP3 and JP4
 *    + define compile flag "SDH_GPIO_GB" in SD0_Init().
 *    (Note: this configuration conflict with UART1)
 * 3. SD-C socket on main board + short JP3 and JP2
 *    + define compile flag "SDH_GPIO_GA" in SD0_Init()
 *    (Note: this configuration conflict with UART0)
 ******************************************************************************/
void SD0_Init(void)
{
#ifdef SDH_GPIO_GA
    /* The group A are GPA10~11, GPA13~15, GPB0~1 */
    /* Conflict with UART0 */
//     printf("SD_Open(): Configure GPIO group A as SDH pins.\n");
    SYS->GPA_MFPH &= (~0x77707700);
    SYS->GPA_MFPH |=   0x44404400;
    SYS->GPA_MFPH &= (~0x00000077);
    SYS->GPB_MFPL |=   0x00000044;

#elif defined SDH_GPIO_GB
    /* The group B are GPB2~3, GPB5~9 */
    /* Conflict with UART1 */
//     printf("SD_Open(): Configure GPIO group B as SDH pins.\n");
    SYS->GPB_MFPL &= (~0x77707700);
    SYS->GPB_MFPL |=   0x44404400;
    SYS->GPB_MFPH &= (~0x00000077);
    SYS->GPB_MFPH |=   0x00000044;

#elif defined SDH_GPIO_G_48PIN
    /* The group 48PIN are GPB0~3, GPB5~7 for NUC505 48PIN chip */
    /* Conflict with both UART0 and UART1 */
//     printf("SD_Open(): Configure special GPIO as SDH pins for 48 pins NUC505 chip.\n");
    SYS->GPB_MFPL &= (~0x77707777);
    SYS->GPB_MFPL |=   0x44404444;

#else   /* default for defined SDH_GPIO_GC */
    /* The group C are GPC0~2, GPC4~7 */
//     printf("SD_Open(): Configure GPIO group C as SDH pins.\n");
    SYS->GPC_MFPL &= (~0x77770777);
    SYS->GPC_MFPL |=   0x11110111;
#endif
}


void SYS_Init(void)
{
    /*---------------------------------------------------------------------------------------------------------*/
    /* Init System Clock                                                                                       */
    /*---------------------------------------------------------------------------------------------------------*/

    /* Enable  XTAL */
    CLK->PWRCTL |= CLK_PWRCTL_HXTEN_Msk;

    CLK_SetCoreClock(96000000);

    /* Set PCLK divider */
    CLK_SetModuleClock(PCLK_MODULE, (uint32_t)NULL, 1);

    /* Update System Core Clock */
    SystemCoreClockUpdate();

    /* Enable IP clock */
    CLK_EnableModuleClock(UART0_MODULE);

    /* Select IP clock source */
    CLK_SetModuleClock(UART0_MODULE, CLK_UART0_SRC_EXT, 0);

    /* Enable USB IP clock */
    CLK_EnableModuleClock(USBD_MODULE);

    /* Select USB IP clock source */
    CLK_SetModuleClock(USBD_MODULE, CLK_USBD_SRC_EXT, 0);

    /*---------------------------------------------------------------------------------------------------------*/
    /* Init I/O Multi-function                                                                                 */
    /*---------------------------------------------------------------------------------------------------------*/
    /* Configure multi-function pins for UART0 RXD and TXD */
    SYS->GPB_MFPL  = (SYS->GPB_MFPL & (~SYS_GPB_MFPL_PB0MFP_Msk) ) | SYS_GPB_MFPL_PB0MFP_UART0_TXD;
    SYS->GPB_MFPL  = (SYS->GPB_MFPL & (~SYS_GPB_MFPL_PB1MFP_Msk) ) | SYS_GPB_MFPL_PB1MFP_UART0_RXD;
}


void UART0_Init()
{
    /*---------------------------------------------------------------------------------------------------------*/
    /* Init UART                                                                                               */
    /*---------------------------------------------------------------------------------------------------------*/
    /* Reset UART module */
    SYS_ResetModule(UART0_RST);

    /* Configure UART0 and set UART0 baud rate */
    UART_Open(UART0, 115200);
}


/*---------------------------------------------------------------------------------------------------------*/
/*  Main Function                                                                                          */
/*---------------------------------------------------------------------------------------------------------*/
int32_t main (void)
{
    /* Init System, IP clock and multi-function I/O
       In the end of SYS_Init() will issue SYS_LockReg()
       to lock protected register. If user want to write
       protected register, please issue SYS_UnlockReg()
       to unlock protected register if necessary */
    SYS_Init();

    /* Init UART to 115200-8n1 for print message */
    UART0_Init();

#if defined (__ICCARM__)
#pragma section = "VECTOR2"

    extern uint32_t __Vectors[];
    extern uint32_t __Vectors_Size[];
    uint32_t* pu32Src;
    uint32_t* pu32Dst;

    pu32Src = (uint32_t *)&USBD_IRQHandler_SRAM;
//         printf("Relocate vector table in SRAM (0x%08X) for fast interrupt handling.\n", __section_begin("VECTOR2"));
    memcpy((void *) __section_begin("VECTOR2"), (void *) __Vectors, (unsigned int) __Vectors_Size);
    SCB->VTOR = (uint32_t) __section_begin("VECTOR2");

    /* Change USBD vector to interrupt handler in SRAM */
    /* IAR compiler doesn't following initial configuration file to relocate USBD IRQHandler() */
    pu32Dst = (uint32_t*) ((uint32_t)__section_begin("VECTOR2")+0x64);
    *pu32Dst = (uint32_t)pu32Src;
#endif
    printf("NUC505 USB Mass Storage for SD Card\n");

    /* --- open SD port 0 and choose GPIO card detect pin. */
    SD0_Init();

    /* --- open SD port 0 and choose GPIO card detect pin. */
    SD_Open(SD_PORT0 | CardDetect_From_GPIO);

    /* --- probe SD card on port 0 */
    SD_Probe(SD_PORT0);     /* the global variables SD0 is initial here. */

    USBD_Open(&gsInfo, MSC_ClassRequest, NULL);

    /* Endpoint configuration */
    MSC_Init();

    /* Enable USBD interrupt */
    NVIC_EnableIRQ(USBD_IRQn);

    /* Start transaction */
    while(1)
    {
        if (USBD_IS_ATTACHED())
        {
            USBD_Start();
            break;
        }
    }

    while(1)
    {

        if (g_usbd_Configured)
        {
            MSC_ProcessCmd();
        }
    }
}

/*** (C) COPYRIGHT 2014 Nuvoton Technology Corp. ***/
