/**
 ******************************************************************************
 *
 * @file        MG32_ADC_MID.c
 *
 * @brief       This file provides firmware functions to manage the following 
 *              functionalities of the ADC peripheral:
 *
 * @par         Project
 *              MG32
 * @version     V1.00
 * @date        2018/02/12
 * @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_ADC_MID.h"


/**
 * @name	Initial/Deinitial TM with TM_HandleTypeDef
 *   		
 */ 
///@{ 
/**
 *******************************************************************************
 * @brief       Initial ADC with ADC_HandleTypeDef.
 * @param[in]   hadc : pointer to a ADC_HandleTypeDef
 * @return		MID_StatusTypeDef
 * @note 
 * @par         Example
 * @code
    ADC_HandleTypeDef hadc;
 
    MID_ADC_Init(&hadc);
 * @endcode
 *******************************************************************************
 */
MID_StatusTypeDef MID_ADC_Init(ADC_HandleTypeDef *hadc)
{
    if(hadc->State == MID_ADC_STATE_RESET)
    {
        /* Allocate lock resource and initialize it */
        hadc->Lock = MID_UnLocked;

        /* Init the low level hardware : GPIO, CLOCK, NVIC and DMA */
        //    MID_ADC_PWM_MspInit(hadc);
    }

    /* Set the ADC state */
    hadc->State= MID_ADC_STATE_BUSY;

    /* Init the ADC Clock/Resolution/Justified */
    ADC_Base_Init(hadc->Instance, &hadc->Init);

    /* Enable ADC */
    ADC_Cmd(hadc->Instance, ENABLE);

    /* Initialize the TM state */
    hadc->State= MID_ADC_STATE_READY;
    
    return MID_Success;
}

/**
 *******************************************************************************
 * @brief       Fills each ADC_HandleTypeDef member with its default value.
 * @param[in]   hadc : pointer to a ADC_HandleTypeDef
 * @return		MID_StatusTypeDef
 * @note 
 * @par         Example
 * @code
    ADC_HandleTypeDef TM_Handle;
 
    MID_ADC_DeInit(&TM_Handle);
 * @endcode
 *******************************************************************************
 */
MID_StatusTypeDef MID_ADC_DeInit(ADC_HandleTypeDef *hadc)
{
    
    hadc->State = MID_ADC_STATE_BUSY;

    /* Disable the ADC Peripheral */
    ADC_Cmd(hadc->Instance, DISABLE);

    /* DeInit the low level hardware: GPIO, CLOCK, NVIC and DMA */
    // Use define this function call
//    MID_ADC_PWM_MspDeInit(hadc);

    /* Change ADC state */
    hadc->State = MID_ADC_STATE_RESET;

    /* Release Lock */
    __MID_UNLOCK(hadc);

    /* Return function status */
    return MID_Success;
}
///@}



/**
 * @name	Initial/Deinitial TM with TM_HandleTypeDef
 *   		
 */ 
///@{ 
/**
 *******************************************************************************
 * @brief       Initial ADC Window detect function.
 * @param[in]   hadc : pointer to a ADC_HandleTypeDef
 * @param[in]   ADCWinDet : pointer to a ADC_WindowDetectTypeDef
 * @return		MID_StatusTypeDef
 * @note 
 * @par         Example
 * @code
    ADC_HandleTypeDef hadc;
    ADC_WindowDetectTypeDef ADCWinDet;
 
    // modify parameter for you 
    MID_ADC_WindowDetect_Init(&hadc, &ADCWinDet);
 * @endcode
 *******************************************************************************
 */
MID_StatusTypeDef MID_ADC_WindowDetect_Init(ADC_HandleTypeDef *hadc, ADC_WindowDetectTypeDef *ADCWinDet)
{
    /* set window high threshold value */
    ADC_SetHigherThreshold(hadc->Instance, ADCWinDet->WindowHighThreshold);

    /* set window low threshold value */
    ADC_SetLowerThreshold(hadc->Instance, ADCWinDet->WindowLowThreshold);
    
    if(ADCWinDet->ApplyMode == ADC_WINDSingle)
    {
        /* set window detect for single channel */        
        ADC_WindowDetectRange_Select(hadc->Instance, ADC_WINDSingle);
        
        /* specify the channel */        
        ADC_ExternalChannel_Select(hadc->Instance, ADCWinDet->SingleChannel);
    }
    else if(ADCWinDet->ApplyMode == ADC_WINDAll)
    {
        /* set window detect for all channel */        
        ADC_WindowDetectRange_Select(hadc->Instance, ADC_WINDAll);
    }
    else
        return MID_Failure;
    
    /* Return function status */
    return MID_Success;
    
}

/**
 *******************************************************************************
 * @brief       Enable ADC window detect function.
 * @param[in]   hadc : pointer to a ADC_HandleTypeDef
 * @return		MID_StatusTypeDef
 * @note 
 * @par         Example
 * @code
    MID_ADC_WindowDetect_Start(&hadc);
 * @endcode
 *******************************************************************************
 */
MID_StatusTypeDef MID_ADC_WindowDetect_Start(ADC_HandleTypeDef *hadc)
{
    /* Enable the ADC Window Detect function */
    ADC_WindowDetect_Cmd(hadc->Instance, ENABLE);

    /* Return function status */
    return MID_Success;
}

/**
 *******************************************************************************
 * @brief       Disable ADC window detect function.
 * @param[in]   hadc : pointer to a ADC_HandleTypeDef
 * @return		MID_StatusTypeDef
 * @note 
 * @par         Example
 * @code
    MID_ADC_WindowDetect_Start(&hadc);
 * @endcode
 *******************************************************************************
 */
MID_StatusTypeDef MID_ADC_WindowDetect_Stop(ADC_HandleTypeDef *hadc)
{
    /* Disable the ADC Window Detect function */
    ADC_WindowDetect_Cmd(hadc->Instance, DISABLE);

    /* Return function status */
    return MID_Success;
}

/**
 *******************************************************************************
 * @brief       Enable ADC window detect event interrupt.
 * @param[in]   hadc : pointer to a ADC_HandleTypeDef
 * @param[in] 	ADC_ITSrc: interrupt source 
 *  @arg\b	    ADC_WDH_IE : ADC0 voltage window detect outside high event interrupt enable 
 *  @arg\b	    ADC_WDI_IE : ADC0 voltage window detect inside event interrupt enable 
 *  @arg\b	    ADC_WDL_IE : ADC0 voltage window detect outside low event interrupt enabl 
 * @return		MID_StatusTypeDef
 * @note 
 * @par         Example
 * @code
    MID_ADC_WindowDetect_Start(&hadc, );
 * @endcode
 *******************************************************************************
 */
MID_StatusTypeDef MID_ADC_WindowDetectIT_Start(ADC_HandleTypeDef *hadc, uint32_t ADC_ITSrc)
{
    /* Enable the ADC Window Detect event interrupt */
    ADC_IT_Config(hadc->Instance, ADC_ITSrc, ENABLE);
    
    /* Enable the ADC interrupt */
    ADC_ITEA_Cmd(hadc->Instance, ENABLE);
//    NVIC_ClearPendingIRQ(ADC_IRQn);
//    NVIC_EnableIRQ(ADC_IRQn);

    /* Return function status */
    return MID_Success;
}

/**
 *******************************************************************************
 * @brief       Disable ADC window detect event interrupt.
 * @param[in]   hadc : pointer to a ADC_HandleTypeDef
 * @return		MID_StatusTypeDef
 * @note 
 * @par         Example
 * @code
    MID_ADC_WindowDetect_Start(&hadc);
 * @endcode
 *******************************************************************************
 */
MID_StatusTypeDef MID_ADC_WindowDetectIT_Stop(ADC_HandleTypeDef *hadc, uint32_t ADC_ITSrc)
{
    /* Disable the ADC Window Detect event interrupt */
    ADC_IT_Config(hadc->Instance, ADC_ITSrc, DISABLE);

    ADC_ITEA_Cmd(hadc->Instance, DISABLE);
//    NVIC_DisableIRQ(ADC_IRQn);
    
    /* Return function status */
    return MID_Success;
}
///@}



/**
 * @name	Initial/Deinitial TM with TM_HandleTypeDef
 *   		
 */ 
///@{
/**
 *******************************************************************************
 * @brief       Config ADC conversion 
 * @param[in]   hadc : pointer to a ADC_HandleTypeDef
 * @param[in] 	ADCConMOD: pointer to a ADC_ConversionDef 
 * @return		MID_StatusTypeDef
 * @note 
 * @par         Example
 * @code
    MID_ADC_WindowDetect_Start(&hadc, );
 * @endcode
 *******************************************************************************
 */
MID_StatusTypeDef MID_ADC_Conversion_Init(ADC_HandleTypeDef *hadc, ADC_ConversionDef *ADCConMOD)
{
    
    /* Set ADC conversion type to ADC_SingleMode or ADC_DifferentMode */
    ADC_SingleDifferentMode_Select(hadc->Instance, ADCConMOD->ADCTypeMDS);
    
    /* Set extend of 'sample and hold' time */
    ADC_SetExtendSampling(hadc->Instance, ADCConMOD->ExtendSampling);
    
    /* Set scan/loop channels */
    ADC_ScanLoopChannel_Enable(hadc->Instance, ADCConMOD->ScanChannelMSK, ENABLE);
    
    /* Active PGA */
    if(ADCConMOD->ActivePGA == ENABLE)
    {   
        // check parameter
        if(ADCConMOD->PGAGain > 3)
            return MID_Failure;
        
        // check parameter
        if(ADCConMOD->PGAoffset > 63)
            return MID_Failure;
        
        /* Set PGA gain (x1~x3) */
        ADC_SetPGAGain(hadc->Instance, ADCConMOD->PGAGain);
        
        /* Set PGA offset (0~63) */
        ADC_SetPGAOffset(hadc->Instance, ADCConMOD->PGAoffset);
        
        /* Enable PGA unit */
        ADC_PGA_Cmd(hadc->Instance, ENABLE);
    }
    
    /* Active Calibration */
    if(ADCConMOD->CalibrationState != MID_ADC_Calibrated)
    {
        if(ADCConMOD->ActivePGA == ENABLE)
        {
            // 1. Calibration procedure : PGA calibration
            ADC_PGAOffsetCalibration_Cmd(hadc->Instance, ENABLE);
        }
        
        // 2. Calibration procedure : ADC calibration
        ADC_StartCalibration(hadc->Instance, ENABLE);
        
        /* Initialize the ADC calibration state*/
        ADCConMOD->CalibrationState = MID_ADC_Calibrated;
    }
    
    /* ADC select eternal channel */
    ADC_ChannelMUX_Select(hadc->Instance, ADC_ExternalChannel);
    
    /* declare ADC trigger source (except Loop mode) */
    ADC_TriggerSource_Select(hadc->Instance, ADCConMOD->TriggerSrcSel);
    
    /* switch ADC conversion mode */
    ADC_ConversionMode_Select(hadc->Instance, ADCConMOD->ADCConversioMDS);
    
    /* Return function status */
    return MID_Success;
}

///@}

