/**
 ******************************************************************************
 *
 * @file        MG32_IEC60730_Manager.c
 *
 * @brief       This is the C code format driver head file.
 *
 * @par         Project
 *              MG32
 * @version     V1.03
 * @date        2022/12/19
 * @author      Megawin Software Center
 * @copyright   Copyright (c) 2018 MegaWin Technology Co., Ltd.
 *              All rights reserved.
 *
 ******************************************************************************
 * @par     Disclaimer 
 *    The Demo software is provided "AS IS"  without any warranty, either 
 *    expressed or implied, including, but not limited to, the implied warranties 
 *    of merchantability and fitness for a particular purpose.  The author will 
 *    not be liable for any special, incidental, consequential or indirect 
 *    damages due to loss of data or any other reason. 
 *    These statements agree with the world wide and local dictated laws about 
 *    authorship and violence against these laws. 
 ******************************************************************************
 ******************************************************************************
 */ 




/* Includes ------------------------------------------------------------------*/
#include "MG32_IEC60730_Common.h"
#include <stdio.h>

/* Wizard menu ---------------------------------------------------------------*/
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Counter for verifying correct program execution at start */
#if defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) /* ARM Compiler V6 */
    #pragma clang diagnostic push
    #pragma clang diagnostic ignored "-Wmissing-variable-declarations"
        uint32_t CtrlFlowCnt __attribute__((section(".bss.CLASS_B_RAM")));
        uint32_t CtrlFlowCntInv __attribute__((section(".bss.CLASS_B_RAM_REV")));
    #pragma clang diagnostic pop
#else
    uint32_t CtrlFlowCnt __attribute__((section(".bss.CLASS_B_RAM")));
    uint32_t CtrlFlowCntInv __attribute__((section(".bss.CLASS_B_RAM_REV")));
#endif
#if DisplayInformation==1    
static PIN_InitTypeDef  PINX_InitStruct;
static URT_BRG_TypeDef  URT_BRG;
static URT_Data_TypeDef DataDef;
#endif

/* Private function prototypes -----------------------------------------------*/
void IEC60730_DisplayInformation_Init(void);
__weak int fputc(int ch, FILE *f __attribute__((unused)));
__weak void FailSafePOR(void);
void MG32_IEC60730_MANAGER(void);
void FailSafePOR(void) __attribute__ ((__noreturn__));

/* Exported variables --------------------------------------------------------*/
/* Exported functions --------------------------------------------------------*/
/* External vairables --------------------------------------------------------*/
extern void ReInitial_Stack(void);
extern uint8_t IEC60730_IntFreqResult;
extern uint8_t IEC60730_IntFreqTRG;

// printf_mg function : in Sample_Retraget.c file.
extern void printf_mg( const char *format,...);



#if DisplayInformation==1    
/**
 *******************************************************************************
 * @brief       replace fputc for printf sub routine
 * @param[in]   ch : specified the data transfer to UART
 * @param[in]   f : no used
 * @return      ch
 *******************************************************************************
 */
__weak int fputc(int ch, FILE *f __attribute__((unused)))
{ 
    URT_SetTXData(URT0, 1, (uint32_t) ch);
    while(URT_GetITSingleFlagStatus(URT0, URT_IT_TC) == DRV_UnHappened);   
    URT_ClearITFlag(URT0, URT_IT_TC);

    return ch;
}
#endif

/**
 *******************************************************************************
 * @brief     Contains the Fail Safe routine executed in case of
 *              failure detected during one of self-test routines
 * @details     
 * @return      
 * @exception   No
 * @note
 * @par         Example
 * @code
 * @endcode
 *******************************************************************************
 */
__weak void FailSafePOR(void)
{

    #if DisplayInformation==1    
        #if defined (__ARMCC_VERSION) || defined(__ARMCC_VERSION)
            printf(" >>>>>>>>>> POR FailSafe Mode <<<<<<<<<<\n");
        #elif defined ( __GNUC__ )
            printf_mg(" >>>>>>>>>> POR FailSafe Mode <<<<<<<<<<\n");
        #endif
    #endif
    
    while(1)
    {
        // to do ... (User code)
    }
}


/**
 *******************************************************************************
 * @brief     Contains the very first test routines executed right after
 *              the reset
 * @details     
 * @return      
 * @exception   No
 * @note
 * @par         Example
 * @code
 * @endcode
 *******************************************************************************
 */
void MG32_IEC60730_MANAGER(void)
{
    #if UseIEC60730==1
    
    #if defined(MG32_3RD) || defined(MG32_4TH)
        // Set FWAIT for MG32F02A128/U128/A064/U064/MG32F02V032 flash issue.
        UnProtectModuleReg(MEMprotect);
        MEM->CR0.MBIT.FWAIT = 1;            // set FWAIT to 1
        ProtectModuleReg(MEMprotect);
    #endif

    // ------------------------------------------------------------------------
    // Config IEC60730 in 48MHz (by CSC control)
    // require:
    //  1. Enable Peripheral clock: PortA, PortB, ADC, 
    //  2. Config ADC & URT clock source (CK_PROC)
    // ------------------------------------------------------------------------
    UnProtectModuleReg(CSCprotect);
  
    // Enable Peripheral clock & Clock Source
    CSC_PeriphOnModeClock_Config(CSC_ON_PortA, ENABLE);       // Enable GPIOA Periph clock 
    CSC_PeriphOnModeClock_Config(CSC_ON_GPL, ENABLE);         // Enable ADC Periph clock 
    #if DisplayInformation==1    
        CSC_PeriphOnModeClock_Config(CSC_ON_PortB, ENABLE);   // Enable GPIOB Periph clock 
        CSC_PeriphOnModeClock_Config(CSC_ON_UART0, ENABLE);   // Enable UART0 Periph clock 
        CSC_PeriphProcessClockSource_Config(CSC_UART0_CKS, CK_APB);
    #endif
    #if IEC60730_ADC_Option == 1
        CSC_PeriphOnModeClock_Config(CSC_ON_ADC0, ENABLE);    // Enable ADC Periph clock 
        CSC_PeriphProcessClockSource_Config(CSC_ADC0_CKS, CK_APB);
    #endif
    #if IEC60730_Flash_Option == 1
        #if !(defined(MG32_1ST) || defined(MG32_2ND))
        CSC_PeriphOnModeClock_Config(CSC_ON_DMA, ENABLE);     // Enable ADC Periph clock 
        #endif
    #endif
    
    ProtectModuleReg(CSCprotect);
    
    // ------------------------------------------------------------------------
    // Display module initial
    // ------------------------------------------------------------------------
    #if DisplayInformation==1
        IEC60730_DisplayInformation_Init();
    #endif 

    // ------------------------------------------------------------------------
    // CPU registers and Flags Self Test 
    // ------------------------------------------------------------------------
    /* WARNING: all registers destroyed when exiting this function (including
       preserved registers R4 to R11) and excluding stack point R13) */
    /* Initializes counter for control flow monitoring */
    #if IEC60730_CPURegister_Option == 1
        if (IEC60730_CPURegister_StartUp() == IEC60730_TEST_FAILURE)
        {
            #if DisplayInformation==1
                #if defined (__ARMCC_VERSION) || defined(__ARMCC_VERSION)
                    printf(" >>>>>>>>>> IEC60730 <<<<<<<<<<\n");
                    printf("Start-up CPU Register Failure\n");
                #elif defined ( __GNUC__ )
                    printf_mg(" >>>>>>>>>> IEC60730 <<<<<<<<<<\n");
                    printf_mg("Start-up CPU Register Failure\n");
                #endif
            #endif 
            
            // User Handler Code here.
            FailSafePOR();        
        }
        else
        {
            #if DisplayInformation==1
                #if defined (__ARMCC_VERSION) || defined(__ARMCC_VERSION)
                    printf(" >>>>>>>>>> IEC60730 <<<<<<<<<<\n");
                    printf("Start-up CPU Register Pass\n");
                #elif defined ( __GNUC__ )
                    printf_mg(" >>>>>>>>>> IEC60730 <<<<<<<<<<\n");
                    printf_mg("Start-up CPU Register Pass\n");
                #endif
            #endif 
        }
    #endif
        
    // ------------------------------------------------------------------------
    // CPU PC Self Test  
    // ------------------------------------------------------------------------
    #if IEC60730_CPU_PC_Option == 1
        if (IEC60730_CPU_PC() == IEC60730_TEST_FAILURE)
        {
            #if DisplayInformation==1
                #if defined (__ARMCC_VERSION) || defined(__ARMCC_VERSION)
                    printf("Start-up CPU PC Test Failure\n");
                #elif defined ( __GNUC__ )
                    printf_mg("Start-up CPU PC Test Failure\n");
                #endif
            #endif 
            
            // User Handler Code here.
            FailSafePOR();        
        }
        else
        {
            #if DisplayInformation==1
                #if defined (__ARMCC_VERSION) || defined(__ARMCC_VERSION)
                    printf("Start-up CPU PC Test Pass\n");
                #elif defined ( __GNUC__ )
                    printf_mg("Start-up CPU PC Test Pass\n");
                #endif
            #endif 
        }
    #endif
    
    // ------------------------------------------------------------------------
    // Variable memory functional test (RAM)
    // ------------------------------------------------------------------------
    /* WARNING: Stack is zero-initialized when exiting from this routine */
    #if IEC60730_RAM_FullTest_Option == 1
        if (IEC60730_RAM_Full_ASM() == IEC60730_TEST_FAILURE)
        {
            #if DisplayInformation==1
                #if defined (__ARMCC_VERSION) || defined(__ARMCC_VERSION)
                    printf("Start-up RAM Test Failure\n");
                #elif defined ( __GNUC__ )
                    printf_mg("Start-up RAM Test Failure\n");
                #endif
            #endif 
            
            // User Handler Code here.
            FailSafePOR();        
        }
        else
        {
            #if DisplayInformation==1
                #if defined (__ARMCC_VERSION) || defined(__ARMCC_VERSION)
                    printf("Start-up RAM Test Pass\n");
                #elif defined ( __GNUC__ )
                    printf_mg("Start-up RAM Test Pass\n");
                #endif
            #endif 
        }
    #endif

    // ------------------------------------------------------------------------
    // Interrupt test init
    // ------------------------------------------------------------------------
    /* WARNING: Interrupt test needs some time to verify function */
    /* WARNING: Interrupt test needs 2 interrupt resouce (TM00 & TM10) */
    #if IEC60730_Interrupt_Option == 1
        MG32_TestInterrupt_Init();
    #endif
        
    // ------------------------------------------------------------------------
    // Clock Source Control test
    // ------------------------------------------------------------------------
    #if IEC60730_Clock_Option == 1
        if (IEC60730_Clock_Test() == IEC60730_TEST_FAILURE)
        {
            #if DisplayInformation==1
                #if defined (__ARMCC_VERSION) || defined(__ARMCC_VERSION)
                    printf("Start-up Clock Test Failure\n");
                #elif defined ( __GNUC__ )
                    printf_mg("Start-up Clock Test Failure\n");
                #endif
            #endif 
            
            // User Handler Code here.
            FailSafePOR();        
        }
        else
        {
            #if DisplayInformation==1
                #if defined (__ARMCC_VERSION) || defined(__ARMCC_VERSION)
                    printf("Start-up Clock Test Pass\n");
                #elif defined ( __GNUC__ )
                    printf_mg("Start-up Clock Test Pass\n");
                #endif
            #endif 
        }
    #endif
               
    // ------------------------------------------------------------------------
    // Program memory functional test (AP)
    // ------------------------------------------------------------------------
    #if IEC60730_Flash_Option == 1
        IEC60730_Flash_Initial();
        if (IEC60730_Flash_StartUp() == IEC60730_TEST_FAILURE)
        {
            #if DisplayInformation==1
                #if defined (__ARMCC_VERSION) || defined(__ARMCC_VERSION)
                    printf("Start-up Flash (Starup) Test Failure\n");
                #elif defined ( __GNUC__ )
                    printf_mg("Start-up Flash (Starup) Test Failure\n");
                #endif
            #endif 
            
            // User Handler Code here.
            FailSafePOR();        
        }
        else
        {
            #if DisplayInformation==1
                #if defined (__ARMCC_VERSION) || defined(__ARMCC_VERSION)
                    printf("Start-up Flash (Starup) Test Pass\n");
                #elif defined ( __GNUC__ )
                    printf_mg("Start-up Flash (Starup) Test Pass\n");
                #endif
            #endif 
        }
    #endif
            
    // ------------------------------------------------------------------------
    // ADC function test
    // ------------------------------------------------------------------------
    /* WARNING: Vref pin must supply voltage (Default voltage is 5V */
    #if IEC60730_ADC_Option == 1
        if (IEC60730_ADC((ADC_ResolutionDef) IEC60730_ADC_Resolution, IEC60730_ADC_ChannelSelection, 
            IEC60730_ADC_Hthreshold, IEC60730_ADC_Lthreshold) == IEC60730_TEST_FAILURE)
        {
            #if DisplayInformation==1
                #if defined (__ARMCC_VERSION) || defined(__ARMCC_VERSION)
                    printf("Start-up ADC Test Failure\n");
                #elif defined ( __GNUC__ )
                    printf_mg("Start-up ADC Test Failure\n");
                #endif
            #endif 
            
            // User Handler Code here.
            FailSafePOR();        
        }
        else
        {
            #if DisplayInformation==1
                #if defined (__ARMCC_VERSION) || defined(__ARMCC_VERSION)
                    printf("Start-up ADC Test Pass\n");
                #elif defined ( __GNUC__ )
                    printf_mg("Start-up ADC Test Pass\n");
                #endif
            #endif 
        }
    #endif
        
    // ------------------------------------------------------------------------
    // IWDT function test
    // ------------------------------------------------------------------------
    #if IEC60730_IWDT_Option == 1
        if(IEC60730_IWDT_Test() == IEC60730_TEST_FAILURE)
        {
            #if DisplayInformation==1
                #if defined (__ARMCC_VERSION) || defined(__ARMCC_VERSION)
                    printf("Start-up IWDT Test Failure\n");
                #elif defined ( __GNUC__ )
                    printf_mg("Start-up IWDT Test Failure\n");
                #endif
            #endif 
            
            // User Handler Code here.
            FailSafePOR();        
        }
        else
        {
            #if DisplayInformation==1
                #if defined (__ARMCC_VERSION) || defined(__ARMCC_VERSION)
                    printf("Start-up IWDT Test Pass\n");
                #elif defined ( __GNUC__ )
                    printf_mg("Start-up IWDT Test Pass\n");
                #endif
            #endif 
        }
    #endif 
        
    // ------------------------------------------------------------------------
    // GPIO test
    //
    // Example:  
    // 1. Please config PA0, PB0 (PPO) for Output test (MG32_GPIO_Init.h)
    //    Please config PC0, PD0 (DIN+Pull-up resistor) for Input test (MG32_GPIO_Init.h)
    //   
    // 2. Please config MG32_IEC60730_GPIO.h test pin
    // ------------------------------------------------------------------------
    #if IEC60730_GPIO_Option == 1
        if (IEC60730_TestGPIO() == IEC60730_TEST_FAILURE)
        {
            #if DisplayInformation==1
                #if defined (__ARMCC_VERSION) || defined(__ARMCC_VERSION)
                    printf("Start-up GPIO Test Failure\n");
                #elif defined ( __GNUC__ )
                    printf_mg("Start-up GPIO Test Failure\n");
                #endif
            #endif 
            
            // User Handler Code here.
            FailSafePOR();        
        }
        else
        {
            #if DisplayInformation==1
                #if defined (__ARMCC_VERSION) || defined(__ARMCC_VERSION)
                    printf("Start-up GPIO Test Pass\n");
                #elif defined ( __GNUC__ )
                    printf_mg("Start-up GPIO Test Pass\n");
                #endif
            #endif 
        }
    #endif
        
    // ------------------------------------------------------------------------
    // Verify Interrupt test result
    // ------------------------------------------------------------------------
    #if IEC60730_Interrupt_Option == 1
        if ((IEC60730_IntFreqResult != IEC60370_IntFreq_Success) || (IEC60730_IntFreqTRG != Int_Freq_End))
        {
            #if DisplayInformation==1
                #if defined (__ARMCC_VERSION) || defined(__ARMCC_VERSION)
                    printf("Start-up Interrupt Test Failure\n");
                #elif defined ( __GNUC__ )
                    printf_mg("Start-up Interrupt Test Failure\n");
                #endif
            #endif 
            
            // User Handler Code here.
            FailSafePOR();        
        }
        else
        {
            #if DisplayInformation==1
                #if defined (__ARMCC_VERSION) || defined(__ARMCC_VERSION)
                    printf("Start-up Interrupt Test Pass\n");
                #elif defined ( __GNUC__ )
                    printf_mg("Start-up Interrupt Test Pass\n");
                #endif
            #endif 
        }
    #endif
        
        
        
        
          
    // ------------------------------------------------------------------------        
    // restore CSC & GPIO parameters
    // ------------------------------------------------------------------------    
    #if DisplayInformation==1  
        // restore GPIOB.8
        PINX_InitStruct.PINX_Mode       = PINX_Mode_Analog_IO;
        PINX_InitStruct.PINX_Alternate_Function = 0;
        
        GPIO_PinMode_Config(PINB(8),&PINX_InitStruct);
        
        // Disable UART peripheral
        URT_TX_Cmd(URT0, DISABLE);  
        URT_Cmd(URT0, DISABLE);
    #endif
        
        
    // ------------------------------------------------------------------------
    UnProtectModuleReg(CSCprotect);
  
    // Enable Peripheral clock & Clock Source
    CSC_PeriphOnModeClock_Config(CSC_ON_PortA, DISABLE);        // Enable GPIOA Periph clock 
    #if DisplayInformation==1    
        CSC_PeriphOnModeClock_Config(CSC_ON_PortB, DISABLE);    // Enable GPIOB Periph clock 
        CSC_PeriphOnModeClock_Config(CSC_ON_UART0, DISABLE);    // Enable UART0 Periph clock 
        CSC_PeriphProcessClockSource_Config(CSC_UART0_CKS, CK_APB);
    #endif
    #if IEC60730_ADC_Option == 1
        CSC_PeriphOnModeClock_Config(CSC_ON_ADC0, DISABLE);     // Enable ADC Periph clock 
        CSC_PeriphProcessClockSource_Config(CSC_ADC0_CKS, CK_APB);
    #endif
    
    ProtectModuleReg(CSCprotect);
        
    #endif
  
    // ------------------------------------------------------------------------        
    // Go to Reset Handler routine
    // ------------------------------------------------------------------------    
    ReInitial_Stack();
        
    
}

/**
 *******************************************************************************
 * @brief     Display information through by UART0
 * @details     
 * @return      
 * @exception   No
 * @note
 * @par         Example
 * @code
 * @endcode
 *******************************************************************************
 */

void IEC60730_DisplayInformation_Init(void)
{
    
#if DisplayInformation==1

    // ------------------------------------------------------------------------
    // GPIO initial (Push pull input) on GPIOB.8 (AFS=URT0_TX)
    // ------------------------------------------------------------------------
    PINX_InitStruct.PINX_Mode               = PINX_Mode_PushPull_O;
    PINX_InitStruct.PINX_PUResistant        = PINX_PUResistant_Disable;
    PINX_InitStruct.PINX_Speed              = PINX_Speed_High;
    PINX_InitStruct.PINX_OUTDrive           = PINX_OUTDrive_Level0;
    PINX_InitStruct.PINX_FilterDivider      = PINX_FilterDivider_Bypass;
    PINX_InitStruct.PINX_Inverse            = PINX_Inverse_Disable;
    PINX_InitStruct.PINX_Alternate_Function = 3;
    
    GPIO_PinMode_Config(PINB(8),&PINX_InitStruct);
    
    // ------------------------------------------------------------------------
    // UART initial (115200 bps N-8-1 @12MHz)
    // ------------------------------------------------------------------------
    URT_BRG.URT_InternalClockSource = URT_BDClock_PROC;
    URT_BRG.URT_BaudRateMode = URT_BDMode_Separated;
    URT_BRG.URT_PrescalerCounterReload = 1;                     //Set PSR (for 12M Hz)
    URT_BRG.URT_BaudRateCounterReload = 3;                      //Set RLR (for 12M Hz)
    URT_BaudRateGenerator_Config(URT0, &URT_BRG);               //BR115200 = f(CK_URTx)/(PSR+1)/(RLR+1)/(OS_NUM+1)
    URT_BaudRateGenerator_Cmd(URT0, ENABLE);                    //Enable BaudRateGenerator
    
    //---TX/RX Clock---//
    URT_TXClockSource_Select(URT0, URT_TXClock_Internal);       //URT_TX use BaudRateGenerator
    URT_RXClockSource_Select(URT0, URT_RXClock_Internal);       //URT_RX use BaudRateGenerator
    URT_TXOverSamplingSampleNumber_Select(URT0, 12);            //Set TX OS_NUM (for 25M Hz)
    URT_TX_Cmd(URT0, ENABLE);                                   //Enable TX

    //=====Set Mode=====//
    //---Set Data character config---//
    DataDef.URT_TX_DataLength  = URT_DataLength_8;
    DataDef.URT_TX_DataOrder   = URT_DataTyped_LSB;
    DataDef.URT_TX_Parity      = URT_Parity_No;
    DataDef.URT_TX_StopBits    = URT_StopBits_1_0;
    DataDef.URT_TX_DataInverse = DISABLE;
    DataDef.URT_RX_DataInverse = DISABLE;
    URT_DataCharacter_Config(URT0, &DataDef);
    
    //---Set Mode Select---//
    URT_Mode_Select(URT0, URT_URT_mode);
    //---Set DataLine Select---//
    URT_DataLine_Select(URT0, URT_DataLine_2);

    URT_ClearTXData(URT0);                                      //

    URT_Cmd(URT0, ENABLE);
#endif

}


