
/******************************************************************************
*@file  : hal_comp.c
*@brief : COMP HAL module driver.
*@ver   : 1.0.0
*@date  : 2022.10.20
******************************************************************************/

#include "hal.h"

/******************************************************************************
*@brief : COMP MSP Initialization.such as module clock, IO share, ... 
*           COMP1 VinP: PA1, PB1, PB10
*           COMP1 VinM: PA4, PA0, DAC1, VREF_AVDD
*           COMP1 Vout: PA0(AF6), PA6(AF6), PA11(AF6), PB0(AF6), PB8(AF7), PB10(AF6)
*               
*           COMP2 VinP: PA7, PA3, PB11
*           COMP2 VinM: PA5, PA2, DAC2, VREF_AVDD
*           COMP2 Vout: PA2(AF6), PA7(AF6), PA12(AF6), PB5(AF6), PB9(AF7), PB11(AF6) 
*               
*           COMP3 VinP: PA0, PC1, PC3
*           COMP3 VinM: PF1, PC0, DAC1, VREF_AVDD
*           COMP3 Vout: PB7(AF7), PB15(AF6), PC2(AF7)
* 
*           COMP4 VinP: PB0, PE7, PE9
*           COMP4 VinM: PE8, PB2, DAC1, VREF_AVDD
*           COMP4 Vout: PB1(AF7), PB6(AF10), PB14(AF7)
*@param : hcomp: COMP handle
*@return: None
******************************************************************************/
__weak void HAL_COMP_MspInit(COMP_HandleTypeDef* hcomp)
{
    //Prevent unused argument(s) compilation warning
    UNUSED(hcomp);

    //NOTE : This function should not be modified. 
    //when the callback is needed,the HAL_COMP_MspInit could be implemented in the user file
}

/******************************************************************************
*@brief : COMP MSP De-Initialization.
*@param : hcomp: COMP handle
*@return: None
******************************************************************************/
__weak void HAL_COMP_MspDeInit(COMP_HandleTypeDef* hcomp)
{
    //Prevent unused argument(s) compilation warning
    UNUSED(hcomp);

    //NOTE : This function should not be modified. 
    //when the callback is needed,the HAL_COMP_MspDeInit could be implemented in the user file
}

/******************************************************************************
*@brief : Initialize the COMP. 
*@note  : If the selected comparator is locked, initialization can't be performed.
*         To unlock the configuration, perform a module reset.
*@param : hcomp: COMP handle
*@return: HAL status
******************************************************************************/
HAL_StatusTypeDef HAL_COMP_Init(COMP_HandleTypeDef* hcomp)
{    
    uint32_t tempReg;
    __IO uint32_t *pCRx;
    
    if(hcomp == NULL)
    {
        return HAL_ERROR;
    }

    assert_param(IS_COMP_INSTANCE(hcomp->Instance));
    assert_param(IS_COMP_COMPx(hcomp->Init.COMPx));
    
    //get the CR register of COMPx
    if(hcomp->Init.COMPx == COMP1)
    {
        pCRx = &hcomp->Instance->CR1;
    }
    else if(hcomp->Init.COMPx == COMP2)
    {
        pCRx = &hcomp->Instance->CR2;
    }    
    else if(hcomp->Init.COMPx == COMP3)
    {
        pCRx = &hcomp->Instance->CR3;
    }    
    else if(hcomp->Init.COMPx == COMP4)
    {
        pCRx = &hcomp->Instance->CR4;
    }
    else
    {
        return HAL_ERROR;
    }
    
    //check lock status
    if(*pCRx & COMP_CR_LOCK)
    {
        return HAL_ERROR;
    }

    tempReg = 0;
    
    assert_param(IS_COMP_WINOUT(hcomp->Init.WinOut));
    assert_param(IS_COMP_POLARITY(hcomp->Init.Polarity));      
    assert_param(IS_COMP_BLANKSEL(hcomp->Init.BlankSel));  
    assert_param(IS_COMP_HYS(hcomp->Init.HYS)); 
    tempReg |= ((hcomp->Init.WinOut & COMP_CR_WINOUT_Msk) | \
                (hcomp->Init.Polarity & COMP_CR_POLARITY_Msk) | \
                (hcomp->Init.BlankSel & COMP_CR_BLANKSEL_Msk) | \
                (hcomp->Init.HYS & COMP_CR_HYS_Msk));

    assert_param(IS_COMP_WINMODE(hcomp->Init.WinMode));
    tempReg |= hcomp->Init.WinMode & COMP_CR_WINMODE_Msk; 
    if(hcomp->Init.WinMode == COMP_WINMODE_SELF_INP)
    {
        assert_param(IS_COMP_INPSEL(hcomp->Init.InPSel));
        tempReg |= hcomp->Init.InPSel & COMP_CR_INPSEL_Msk;
    }    
    
    assert_param(IS_COMP_INMSEL(hcomp->Init.InMSel));
    tempReg |= hcomp->Init.InMSel & COMP_CR_INMSEL_Msk;
    if(hcomp->Init.InMSel == COMP_INMSEL_VREF_AVDD)
    {
        assert_param(IS_COMP_CRVSEL(hcomp->Init.CrvSel)); 
        assert_param(IS_COMP_CRVEN(hcomp->Init.CrvEn)); 
        tempReg |= ((hcomp->Init.CrvSel & COMP_CR_CRVSEL_Msk) | \
                    (hcomp->Init.CrvEn & COMP_CR_CRVEN_Msk));
        
        if(hcomp->Init.CrvEn == COMP_CRV_ENABLE)
        {
            assert_param(IS_COMP_CRVCFG(hcomp->Init.CrvCfg));
            tempReg |= hcomp->Init.CrvCfg << COMP_CR_CRVCFG_Pos;
        }
    }
    
    assert_param(IS_COMP_FLTEN(hcomp->Init.FltEn));
    tempReg |= hcomp->Init.FltEn & COMP_CR_FLTEN_Msk;
    if(hcomp->Init.FltEn == COMP_FLT_ENABLE)
    {
        assert_param(IS_COMP_FLTTIME(hcomp->Init.FltTime));
        tempReg |= hcomp->Init.FltTime & COMP_CR_FLTTIME_Msk;
    }
    
    CLEAR_BIT(*pCRx, COMP_CR_EN); //disable
    
    /* Init the low level hardware : GPIO, CLOCK */
    HAL_COMP_MspInit(hcomp);                

    //Write the COMP_CR register
    WRITE_REG(*pCRx,tempReg);

    return HAL_OK;
}

/******************************************************************************
*@brief : de-Initialize the COMP. 
*@note  : If the selected comparator is locked, de-initialization can't be performed.
*         To unlock the configuration, perform a module reset.
*@param : hcomp: COMP handle
*@return: HAL status
******************************************************************************/
HAL_StatusTypeDef HAL_COMP_DeInit(COMP_HandleTypeDef* hcomp)
{
    __IO uint32_t *pCRx;
    
    if(hcomp == NULL)
    {
        return HAL_ERROR;
    }

    assert_param(IS_COMP_INSTANCE(hcomp->Instance));
    assert_param(IS_COMP_COMPx(hcomp->Init.COMPx));
    
    if(hcomp->Init.COMPx == COMP1)
    {
        pCRx = &hcomp->Instance->CR1;
    }
    else if(hcomp->Init.COMPx == COMP2)
    {
        pCRx = &hcomp->Instance->CR2;
    }    
    else if(hcomp->Init.COMPx == COMP3)
    {
        pCRx = &hcomp->Instance->CR3;
    }    
    else if(hcomp->Init.COMPx == COMP4)
    {
        pCRx = &hcomp->Instance->CR4;
    }
    else
    {
        return HAL_ERROR;
    }
    
    //check lock status
    if(*pCRx & COMP_CR_LOCK)
    {
        return HAL_ERROR;
    }

    /* Set COMP_CSR register to reset value */
    WRITE_REG(*pCRx, 0x00000000UL);
    
    HAL_COMP_MspDeInit(hcomp);

    memset(&hcomp->Init, 0, sizeof(hcomp->Init));

    return HAL_OK;
}

/******************************************************************************
*@brief : Enable comparator.
*@param : hcomp: COMP handle
*@return: HAL status
******************************************************************************/
HAL_StatusTypeDef HAL_COMP_Enable(COMP_HandleTypeDef* hcomp)
{
    __IO uint32_t *pCRx;
    
    if(hcomp == NULL)
    {
        return HAL_ERROR;
    }

    assert_param(IS_COMP_INSTANCE(hcomp->Instance));
    assert_param(IS_COMP_COMPx(hcomp->Init.COMPx));
    
    if(hcomp->Init.COMPx == COMP1)
    {
        pCRx = &hcomp->Instance->CR1;
    }
    else if(hcomp->Init.COMPx == COMP2)
    {
        pCRx = &hcomp->Instance->CR2;
    }    
    else if(hcomp->Init.COMPx == COMP3)
    {
        pCRx = &hcomp->Instance->CR3;
    }    
    else if(hcomp->Init.COMPx == COMP4)
    {
        pCRx = &hcomp->Instance->CR4;
    }
    else
    {
        return HAL_ERROR;
    }
    
    //check lock status
    if(*pCRx & COMP_CR_LOCK)
    {
        return HAL_ERROR;
    }

    SET_BIT(*pCRx, COMP_CR_EN); //enable
    
    return HAL_OK;
}

/******************************************************************************
*@brief : disable comparator.
*@param : hcomp: COMP handle
*@return: HAL status
******************************************************************************/
HAL_StatusTypeDef HAL_COMP_Disable(COMP_HandleTypeDef* hcomp)
{
    __IO uint32_t *pCRx;
    
    if(hcomp == NULL)
    {
        return HAL_ERROR;
    }

    assert_param(IS_COMP_INSTANCE(hcomp->Instance));
    assert_param(IS_COMP_COMPx(hcomp->Init.COMPx));
    
    if(hcomp->Init.COMPx == COMP1)
    {
        pCRx = &hcomp->Instance->CR1;
    }
    else if(hcomp->Init.COMPx == COMP2)
    {
        pCRx = &hcomp->Instance->CR2;
    }    
    else if(hcomp->Init.COMPx == COMP3)
    {
        pCRx = &hcomp->Instance->CR3;
    }    
    else if(hcomp->Init.COMPx == COMP4)
    {
        pCRx = &hcomp->Instance->CR4;
    }
    else
    {
        return HAL_ERROR;
    }
    
    //check lock status
    if(*pCRx & COMP_CR_LOCK)
    {
        return HAL_ERROR;
    }

    CLEAR_BIT(*pCRx, COMP_CR_EN); //disable
    
    return HAL_OK;
}

/******************************************************************************
*@brief : Get the output level of the comparator. the value is stored in hcomp.
*@param : hcomp: COMP handle.
*@return: HAL status
******************************************************************************/
HAL_StatusTypeDef HAL_COMP_GetOutputLevel(COMP_HandleTypeDef* hcomp)
{
    __IO uint32_t *pCRx;
    
    if(hcomp == NULL)
    {
        return HAL_ERROR;
    }

    assert_param(IS_COMP_INSTANCE(hcomp->Instance));
    assert_param(IS_COMP_COMPx(hcomp->Init.COMPx));
    
    if(hcomp->Init.COMPx == COMP1)
    {
        hcomp->OutputLevelOrg = (hcomp->Instance->SR & COMP_SR_VCOUT1ORG) ? 1 : 0;
        hcomp->OutputLevel    = (hcomp->Instance->SR & COMP_SR_VCOUT1) ? 1 : 0;
    }
    else if(hcomp->Init.COMPx == COMP2)
    {
        hcomp->OutputLevelOrg = (hcomp->Instance->SR & COMP_SR_VCOUT2ORG) ? 1 : 0;
        hcomp->OutputLevel    = (hcomp->Instance->SR & COMP_SR_VCOUT2) ? 1 : 0;
    }    
    else if(hcomp->Init.COMPx == COMP3)
    {
        hcomp->OutputLevelOrg = (hcomp->Instance->SR & COMP_SR_VCOUT3ORG) ? 1 : 0;
        hcomp->OutputLevel    = (hcomp->Instance->SR & COMP_SR_VCOUT3) ? 1 : 0;
    }    
    else if(hcomp->Init.COMPx == COMP4)
    {
        hcomp->OutputLevelOrg = (hcomp->Instance->SR & COMP_SR_VCOUT4ORG) ? 1 : 0;
        hcomp->OutputLevel    = (hcomp->Instance->SR & COMP_SR_VCOUT4) ? 1 : 0;
    }
    else
    {
        return HAL_ERROR;
    }
 
    return HAL_OK;
}


/******************************************************************************
*@brief : start comparator.
*@param : hcomp: COMP handle
*@return: HAL status
******************************************************************************/
HAL_StatusTypeDef HAL_COMP_Start(COMP_HandleTypeDef *hcomp)
{
    return(HAL_COMP_Enable(hcomp));
}


/******************************************************************************
*@brief : stop comparator.
*@param : hcomp: COMP handle
*@return: HAL status
******************************************************************************/
HAL_StatusTypeDef HAL_COMP_Stop(COMP_HandleTypeDef *hcomp)
{
    return(HAL_COMP_Disable(hcomp));
}


/******************************************************************************
*@brief : lock comparator.
*@param : hcomp: COMP handle
*@return: HAL status
******************************************************************************/
HAL_StatusTypeDef HAL_COMP_Lock(COMP_HandleTypeDef* hcomp)
{
    __IO uint32_t *pCRx;
    
    if(hcomp == NULL)
    {
        return HAL_ERROR;
    }

    assert_param(IS_COMP_INSTANCE(hcomp->Instance));
    assert_param(IS_COMP_COMPx(hcomp->Init.COMPx));
    
    if(hcomp->Init.COMPx == COMP1)
    {
        pCRx = &hcomp->Instance->CR1;
    }
    else if(hcomp->Init.COMPx == COMP2)
    {
        pCRx = &hcomp->Instance->CR2;
    }    
    else if(hcomp->Init.COMPx == COMP3)
    {
        pCRx = &hcomp->Instance->CR3;
    }    
    else if(hcomp->Init.COMPx == COMP4)
    {
        pCRx = &hcomp->Instance->CR4;
    }
    else
    {
        return HAL_ERROR;
    }
    
    //check lock status
    if(*pCRx & COMP_CR_LOCK)
    {
        return HAL_OK;
    }
    
    SET_BIT(*pCRx, COMP_CR_LOCK); //lock

    return HAL_OK;
}

