/**
 ******************************************************************************
 *
 * @file        BSP_VariableResistor.c
 * @brief       This is Variable Resistor C file
 
 * @par         Project
 *              MG32F02N128
 * @version     V1.00
 * @date        2024/08/23
 * @author      Megawin Software Center
 * @copyright   Copyright (c) 2017 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 "BSP_VariableResistor.h"

/* Wizard menu ---------------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
//GPIO
#define VR1_PIN             PX_Pin_0
#define VR_PIN_MODE         PINX_Mode_Analog_IO
#define VR_PIN_AFS          0
#define VR_IOM              IOMA

//ADC
#define VR_ADC              ADC0

//Variable Resistor
#define ADC_VREF            3300                        /*!< ADC Vref voltage*/
#define VR_VCC              3300                        /*!< Variable register voltage*/
//#define VR_ADC_MAX          (4095*VR_VCC)/ADC_VREF    /*!< ADC conversion max value.*/
#define VR_ADC_MAX          3850
#define VR_ADC_DIFRANGE     50
#define VR_ADC_SMPTIME      5

/* Private typedef -----------------------------------------------------------*/

/*! @struct VRCTR_TypeDef
    @brief  VR control struct
*/ 
typedef struct __attribute__((packed))
{
    uint8_t  VR_Status;                 /*!< Get Variable resistor percentage (%) for variable resister.*/
    uint8_t  ADCCalibration_Complete;   /*!< 1 = Calibration complete. 
                                            0 = Calibration fail.
                                            If MCU get ADCCalibration_Complete=0 then check VREF pin status. Or change another MCU.
                                        */
    uint16_t VR_ADCData;                /*!< ADC conversion data for VR1, VR2.*/
    
}VRCTR_TypeDef;




/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
static VRCTR_TypeDef  VR_CTR;                /*!< Variable resistor control parameter.*/

static uint8_t        VR_ADC_SampleCount;    /*!< ADC sample time for average. The maximum value is 5.*/
static uint32_t       VR_ADC_SampleData;     /*!< ADC conversion data. ([0] for VR1, [1] for VR2).*/

/* Private function prototypes -----------------------------------------------*/
/* Exported variables --------------------------------------------------------*/
/* Exported functions --------------------------------------------------------*/
/* External variables --------------------------------------------------------*/

/**
 *******************************************************************************
 * @brief       Variable resistor initial. 
 * @details     
 * @return      
 * @exception   No
 * @note        No
 *******************************************************************************
 */
void BSP_VR_Init(void)
{
    PIN_InitTypeDef    VR_Pin;

    /*Initial GPIO*/
    VR_Pin.PINX_Pin                = ( VR1_PIN );
    VR_Pin.PINX_Mode               = VR_PIN_MODE;
    VR_Pin.PINX_PUResistant        = PINX_PUResistant_Disable;
    VR_Pin.PINX_Speed              = PINX_Speed_Low;
    VR_Pin.PINX_Inverse            = PINX_Inverse_Disable;
    VR_Pin.PINX_OUTDrive           = PINX_OUTDrive_Level0;
    VR_Pin.PINX_FilterDivider      = PINX_FilterDivider_Bypass;
    VR_Pin.PINX_Alternate_Function = VR_PIN_AFS;
    GPIO_PortMode_Config(VR_IOM, &VR_Pin);

    /*ADC Default Initial.*/
//    ADC_DeInit(VR_ADC);

//    ADC_Cmd(VR_ADC, ENABLE);

    //Configure ADC clock
//    ADC_ClockSource_Select(VR_ADC, ADC_CKADC);
//    ADC_SetInternalClockDivider(VR_ADC, ADC_IntDIV4);
    
//    ADC_DataResolution_Select(VR_ADC, ADC_12BitData);          // 12 bit resolution
//    ADC_WaitDataReadOut(VR_ADC, DISABLE);                      // No wait to convert next channel
//    ADC_DataOverrunMode_Select(VR_ADC, ADC_DataOverWritten);   // Over written the previous channel data
//    ADC_DataAlignment_Select(VR_ADC, ADC_RightJustified);      // Right justified

    //Disable PGA
//    ADC_PGA_Cmd(VR_ADC, DISABLE);
//    ADC_SetPGAGain(VR_ADC, 0);

//    ADC_TriggerSource_Select(VR_ADC, ADC_START);
//    ADC_TriggerEdge_Select(VR_ADC, ADC_DisableTrg);
//    ADC_ContinueMode_Cmd(VR_ADC, DISABLE);
//    ADC_MainConversionMode_Select(VR_ADC, ADC_OneShot);

//    ADC_SetExtendSampling(VR_ADC, 30);

//    ADC_SetConversionTime(VR_ADC, ADC_FastCONV);
//    ADC_SetOperationCurrent(VR_ADC, ADC_BIAS_LVL3);
//    ADC_SampleClockPhase_Select(VR_ADC, ADC_CK_PHASE2);

    //ADC calibration
//    ADC_StartCalibration(VR_ADC, ENABLE);

    // Conversion channel selection
    ADC_ChannelMUX_Select(VR_ADC, ADC_ExternalChannel);
    ADC_ExternalChannel_Select(VR_ADC, (ADC_ExtChannelDef)VR1_ADC_CHANNEL);

    // 1. clear ADC E1CNVF flag.
    // 2. Start ADC conversion.
    ADC_ClearFlag(VR_ADC, ADC_E1CNVF);

    /*Get VR1 first data.*/
    ADC_ExternalChannel_Select(VR_ADC, (ADC_ExtChannelDef)VR1_ADC_CHANNEL);
    ADC_ClearFlag(VR_ADC, ADC_E1CNVF);
    ADC_SoftwareConversion_Cmd(VR_ADC, ENABLE);
    while((ADC_GetAllFlagStatus(VR_ADC) & ADC_E1CNVF) == 0);
    VR_CTR.VR_ADCData = (uint16_t)ADC_GetDAT0Data(VR_ADC);

    /*Trigger next VR1 ADC data.*/
//    ADC_ClearFlag(VR_ADC,ADC_E1CNVF);
//    ADC_SoftwareConversion_Cmd(VR_ADC,ENABLE);

    /*Initial parameter*/
    VR_ADC_SampleCount = 0;
    VR_ADC_SampleData = 0;
    VR_CTR.VR_ADCData = 0;
}

/**
 *******************************************************************************
 * @brief       Trigger ADC conversion(external channel(Variable Resistor pin)) 
 * @details     
 * @return      
 * @exception   
 * @note        
 *******************************************************************************
 */
void BSP_VR_Trigger(void)
{
    ADC_ClearFlag(VR_ADC, ADC_E1CNVF);
    ADC_ChannelMUX_Select(VR_ADC, ADC_ExternalChannel);
    ADC_ExternalChannel_Select(VR_ADC,(ADC_ExtChannelDef)VR1_ADC_CHANNEL);
    ADC_SoftwareConversion_Cmd(VR_ADC, ENABLE);
}

/**
 *******************************************************************************
 * @brief       Trigger ADC conversion ( internal channel(VSSA)) 
 * @details     
 * @return      
 * @exception   No
 * @note        No
 *******************************************************************************
 */
void BSP_VR_DischargeTrigger(void)
{
    ADC_ClearFlag(VR_ADC, ADC_E1CNVF);
    ADC_ChannelMUX_Select(VR_ADC, ADC_InternalChannel);
    ADC_InternalChannel_Select(VR_ADC, ADC_INT_VSSA); 
    ADC_SoftwareConversion_Cmd(VR_ADC, ENABLE);
}

/**
 *******************************************************************************
 * @brief       Variable resistor handler flow. 
 * @details     
 * @return      
 * @exception   No
 * @note        No
 *******************************************************************************
 */
void BSP_VR_Handler(void)
{
    uint16_t BSP_VR_ADCDataTmp;
    uint16_t BSP_VR_ADCDataDif;
    uint32_t BSP_VR_DataTmp;
    uint32_t BSP_VR_MaxTmp;

    /*Check ADC conversion whether complete or not.*/
    if((ADC_GetAllFlagStatus(VR_ADC) & ADC_STA_E1CNVF_happened_w) == 0)
    {
        return;
    }

    /*Get ADC conversion data and check status whether change or not.*/
    if(VR_ADC_SampleCount == VR_ADC_SMPTIME)
    {
        //Get average result
        BSP_VR_ADCDataTmp = (uint16_t)(VR_ADC_SampleData / VR_ADC_SMPTIME);

        //Refresh counter and data
        VR_ADC_SampleCount = 0;
        VR_ADC_SampleData = 0;

        if( BSP_VR_ADCDataTmp > VR_CTR.VR_ADCData)
        {
            BSP_VR_ADCDataDif = BSP_VR_ADCDataTmp - VR_CTR.VR_ADCData;
        }
        else
        {
            BSP_VR_ADCDataDif = VR_CTR.VR_ADCData - BSP_VR_ADCDataTmp;
        }

        if( BSP_VR_ADCDataDif > VR_ADC_DIFRANGE)
        {
            VR_CTR.VR_ADCData = (uint16_t)BSP_VR_ADCDataTmp;

            /*Get Variable resistor percentage*/
            BSP_VR_DataTmp    = (uint32_t)(BSP_VR_ADCDataTmp * 100);
            BSP_VR_MaxTmp     = VR_ADC_MAX;
            VR_CTR.VR_Status  = (uint8_t)(BSP_VR_DataTmp / BSP_VR_MaxTmp);

            if(VR_CTR.VR_Status > 100)
            {
                VR_CTR.VR_Status = 100;
            }
            else if(BSP_VR_DataTmp<50)
            {
                VR_CTR.VR_Status = 0;
            }

            /*Variable resistor change*/
            BSP_VR_ChangeCallback();
        }
    }
    /*Accumulation ADC conversion data*/
    else
    {
        BSP_VR_ADCDataTmp = (uint16_t)ADC_GetDAT0Data(VR_ADC);
        VR_ADC_SampleData = VR_ADC_SampleData + BSP_VR_ADCDataTmp;

        VR_ADC_SampleCount = VR_ADC_SampleCount + 1;
    }

    ADC_ClearFlag(VR_ADC, ADC_E1CNVF);                     //Clear one-time conversion end flag
}

/**
 *******************************************************************************
 * @brief       Skip this ADC data.
 * @details     
 * @return      
 * @exception   No
 * @note        No
 *******************************************************************************
 */
void BSP_VR_SkipADCData(void)
{
    ADC_ClearFlag(VR_ADC, ADC_E1CNVF); 
}

/**
 *******************************************************************************
 * @brief       Get ADC data.
 * @details     
 * @return      
 * @exception   No
 * @note        No
 *******************************************************************************
 */
uint16_t BSP_VR_GetADCData(void)
{
    return(VR_CTR.VR_ADCData);
}

/**
 *******************************************************************************
 * @brief       Get Variable percentage.
 * @details     
 * @return      
 * @exception   No
 * @note        No
 *******************************************************************************
 */
uint8_t BSP_VR_GetPercentage(void)
{
    return(VR_CTR.VR_Status);
}

/**
 *******************************************************************************
 * @brief       Variable resistor status change call back function.
 * @details     
 * @return      
 * @exception   No
 * @note        No
 *******************************************************************************
 */
__WEAK void BSP_VR_ChangeCallback(void)
{
    //=========================================================
    //Note : This function should not be modified, when the callback
    //       is needed, the BSP_VR_ChangeCallback can
    //       be implemented in the user file.    
}

