/**
 ******************************************************************************
 *
 * @file        MG32_IEC60730_CSC.c
 *
 * @brief       This file provides firmware functions to manage the following 
 *              functionalities of the ADC peripheral:
 *
 * @par         Project
 *              MG32
 * @version     V1.12
 * @date        2018/12/17
 * @author      Megawin Software Center
 * @copyright   Copyright (c) 2016 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. 
 ******************************************************************************
 ******************************************************************************
 */ 
 
#include "MG32_DRV.h"
#include "MG32_IEC60730_Common.h"

#define IHRCO0_MaxLimit 610 /* When ILRCO 32.768KHz - 40%, TM26 count in IHRCO0 */
#define IHRCO0_MinLimit 261 /* When ILRCO 32.768KHz + 40%, TM26 count in IHRCO0 */
#define IHRCO1_MaxLimit 562 /* When ILRCO 32.768KHz - 40%, TM26 count in IHRCO1 */
#define IHRCO1_MinLimit 241 /* When ILRCO 32.768KHz + 40%, TM26 count in IHRCO1 */
#define IHRCOx_MaxRatio 
#define IHRCOx_MinRatio 


typedef enum 
{
    TRM_IHRCO = TRGI_IN0,
    TRM_ILRCO = TRGI_ITR,
}TRM_IxRCO_TypeDef; 


void MG32_TM26_IC0_32bit_MiddleFirmware(TRM_IxRCO_TypeDef TRG_Source);
IEC60730_Ret IEC60730_Clock_Test (void);


/**
 *******************************************************************************
 * @brief       
 * @details  
 * @param[in]    
 * @return      
 * @exception      
 * @note        
 *******************************************************************************
 */
void MG32_TM26_IC0_32bit_MiddleFirmware(TRM_IxRCO_TypeDef TRG_Source)   // Not confirm 
{
    TM_TimeBaseInitTypeDef TM_TimeBase_InitStruct;
    
                
    TM_DeInit(TM26);
    
    // TimeBase initial
    TM_TimeBaseStruct_Init(&TM_TimeBase_InitStruct);
    
    // modify parameter & config it
    TM_TimeBase_InitStruct.TM_MainClockDirection =TM_UpCount;
    TM_TimeBase_InitStruct.TM_Period = 65535; 
    TM_TimeBase_InitStruct.TM_Prescaler = 65535;
    TM_TimeBase_InitStruct.TM_CounterMode = Full_Counter;
    
    TM_TimeBase_Init(TM26, &TM_TimeBase_InitStruct);
   
    // internal clock config
    TM_InternalClockSource_Select(TM26, TM_PROC);

    // overwrite test
    TM_IC0OverWritten_Cmd(TM26, TM_Keep);
    
    // TM26 channel 0 function config
    TM_CH0Function_Config(TM26, TM_InputCapture);
//    TM_IN0TriggerEvent_Select(TM26, (TM_ICxTrgDef) IC_FallingEdge); /*???*/
    
    if(TRG_Source == TRM_IHRCO)                             // for IHRCO 
    {
        TM_IN0Source_Select(TM26, IC0);                     // Input capture TM26_IC0
        
        TM_TriggerSource_Select(TM26, TRGI_IN0);            // TRGI config
        TM_TRGICounter_Select(TM26,TRGI_StartupRising);     // Configure trigger rising edge start falling edge stop
        TM_TRGIPrescaler_Select(TM26,TRGI_StartupRising);
        TM_IN0TriggerEvent_Select(TM26, IC_FallingEdge);
        
        TM_ClearFlag(TM26, TMx_CF0A | TMx_CF0B);            // clear all flag
        while(PB0);                                         // wait PB0 = 0
    }
    
    if(TRG_Source == TRM_ILRCO)                             // for ILRCO
    {
        UnProtectModuleReg(CSCprotect);                     // ICKO_INT =  CK_LS /1
        CSC_ICKO_ClockSource_Select(ICKO_CK_LS);
        CSC_ICKO_Divider_Select(ICKO_DIV_1);
        ProtectModuleReg(CSCprotect);
        
        APB_ITR7_Select(ITR7_ICKO_INT);                     // ITR7 = ICKO_INT
        TM_ITRx_Select(TM26, ITR7);                         // Trigger source ITR7
        
        TM_IN0Source_Select(TM26, IC1);                     // Input capture TM26_ITR
        TM_TriggerSource_Select(TM26, TRGI_ITR);            // TRGI config
        
        TM_TRGICounter_Select(TM26,TRGI_StartupFalling);    // Configure trigger falling edge start falling edge stop
        TM_TRGIPrescaler_Select(TM26,TRGI_StartupFalling);
        TM_IN0TriggerEvent_Select(TM26, IC_FallingEdge);
        
        TM_ClearFlag(TM26, TMx_CF0A | TMx_CF0B);            // clear all flag
    }
          
    // Timer enable
    TM_Timer_Cmd(TM26,ENABLE);
    
    return;
}



/**
 *******************************************************************************
 * @brief       
 * @details  
 * @param[in]    
 * @return      
 * @exception      
 * @note        
 *******************************************************************************
 */
IEC60730_Ret IEC60730_Clock_Test (void)
{
    uint8_t  FailFlag;                                                  // 0x01 IHRCO0 check fail
                                                                        // 0x02 IHRCO1 check fail
    uint32_t IHRCO0_Freq;
    uint32_t IHRCO1_Freq;

    
    FailFlag = 0;
    UnProtectModuleReg(CSCprotect);                                     // Setting flash wait state
    if(CSC->CR0.MBIT.HS_SEL != 0)                                       // When CK_HS not IHRCOx 
    {
        if(CSC->CR0.MBIT.IHRCO_EN != 0)                                 // When IHRCOx not enable  
        {
            CSC_IHRCO_Cmd(ENABLE);                                      // Enable IHRCOx
            while(CSC_GetSingleFlagStatus(CSC_IHRCOF) == DRV_UnHappened);
            CSC_ClearFlag(CSC_IHRCOF);
        }
        CSC_CK_HS_Select(HS_CK_IHRCO);                                  // CK_HS = IHRCOx
    }
        
    CSC_IHRCO_Select(IHRCO_12MHz);                                      // IHRCO = 12MHz
    CSC_CK_MAIN_Select(MAIN_CK_HS);                                     // CK_MAIN = CK_HS
    CSC_CK_APB_Divider_Select(APB_DIV_1);                               // CK_APB = CK_MAIN /1
    CSC_CK_AHB_Divider_Select(AHB_DIV_1);                               // CK_AHB = CK_APB /1
    CSC_PeriphOnModeClock_Config(CSC_ON_TM26, ENABLE);                  // Enable TM26 clock
    CSC_PeriphProcessClockSource_Config(CSC_TM26_CKS, CK_APB);          // TM26 clock source CK_APB
    ProtectModuleReg(CSCprotect);                                       // Setting flash wait state

    

    /* Check IHRCO0 frequency */
    MG32_TM26_IC0_32bit_MiddleFirmware(TRM_ILRCO);                  // Init 
    while(TM_GetSingleFlagStatus(TM26,TMx_CF0A) == DRV_UnHappened);     // wait for Capture event
    IHRCO0_Freq = TM_GetIC0Value(TM26);                                 // Get IC0 capture data (32-bits)
    TM_ClearFlag(TM26, TMx_CF0A | TMx_CF0B);                            // clear TM26 flag
    // Check IHRCO0 is in range
    if(IHRCO0_Freq > IHRCO0_MaxLimit)                                   // When ILRCO -40%
        FailFlag |= 0x01;
    if(IHRCO0_Freq < IHRCO0_MinLimit)                                   // When ILRCO +40%
        FailFlag |= 0x01;
    
    
    /* Check IHRCO1 frequcncy */
    UnProtectModuleReg(CSCprotect);
    CSC_IHRCO_Select(IHRCO_11M0592Hz);                                  // IHRCO = 11M0592Hz
    ProtectModuleReg(CSCprotect);
    MG32_TM26_IC0_32bit_MiddleFirmware(TRM_ILRCO);                  // Init 
    while(TM_GetSingleFlagStatus(TM26,TMx_CF0A) == DRV_UnHappened);     // wait for Capture event
    IHRCO1_Freq = TM_GetIC0Value(TM26);                                 // Get IC0 capture data (32-bits)
    TM_ClearFlag(TM26, TMx_CF0A | TMx_CF0B);                            // clear TM26 flag
    
    UnProtectModuleReg(CSCprotect);
    CSC_IHRCO_Select(IHRCO_12MHz);                                      // IHRCO = 12MHz
    ProtectModuleReg(CSCprotect);
    
    // Check IHRCO1 is in range
    if(IHRCO1_Freq > IHRCO1_MaxLimit)                                   // When ILRCO -40%
        FailFlag |= 0x02;
    if(IHRCO1_Freq < IHRCO1_MinLimit)                                   // When ILRCO +40%
        FailFlag |= 0x02;

    // Check IHRCO0 <= IHRCO1
    if(IHRCO0_Freq <= IHRCO1_Freq)
        FailFlag |= 0x04;
    
    if(FailFlag == 0)                                                   // When IHRCOx or ILRCO success
        return IEC60730_TEST_SUCCESS;
    else                                                                // When IHRCOx or ILRCO failure
        return IEC60730_TEST_FAILURE;                                   
}







