/******************************************************************************
 * $Revision: 423 $
 * $Date:: 2017-04-07 16:03:30 +0900#$
 *****************************************************************************/
/* __DISCLAIMER_START__                                                      */
/******************************************************************************
* (c)2017, Cypress Semiconductor Corporation
* or a subsidiary of Cypress Semiconductor Corporation. All rights
* reserved.
*
* This software, including source code, documentation and related
* materials ( "Software" ), is owned by Cypress Semiconductor
* Corporation or one of its subsidiaries ( "Cypress" ) and is protected by
* and subject to worldwide patent protection (United States and foreign),
* United States copyright laws and international treaty provisions.
* Therefore, you may use this Software only as provided in the license
* agreement accompanying the software package from which you
* obtained this Software ( "EULA" ).
*
* If no EULA applies, Cypress hereby grants you a personal, nonexclusive,
* non-transferable license to copy, modify, and compile the
* Software source code solely for use in connection with Cypress' s
* integrated circuit products. Any reproduction, modification, translation,
* compilation, or representation of this Software except as specified
* above is prohibited without the express written permission of Cypress.
*
* Disclaimer: THIS SOFTWARE IS PROVIDED AS-IS, WITH NO
* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING,
* BUT NOT LIMITED TO, NONINFRINGEMENT, IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE. Cypress reserves the right to make
* changes to the Software without notice. Cypress does not assume any
* liability arising out of the application or use of the Software or any
* product or circuit described in the Software. Cypress does not
* authorize its products for use in any products where a malfunction or
* failure of the Cypress product may reasonably be expected to result in
* significant property damage, injury or death ( "High Risk Product" ). By
* including Cypress' s product in a High Risk Product, the manufacturer
* of such system or application assumes all risk of such use and in doing
* so agrees to indemnify Cypress against all liability.
******************************************************************************/
/* __DISCLAIMER_END__                                                        */
/*****************************************************************************
 ** \file bt_rlt.c
 **
 ** A detailed description is available at
 ** @link RltGroup Reload Timer (RLT) description @endlink
 **
 ** History:
 ** - 2014-05-30  0.01  ST  First version
 *****************************************************************************/

/*****************************************************************************/
/* Include files                                                             */
/*****************************************************************************/

#include "common_include.h"
#include "bsp_bt_rlt.h"

/**
 *****************************************************************************
 ** \addtogroup RltGroup
 *****************************************************************************/
//@{

/*****************************************************************************/
/* Local pre-processor symbols/macros ('#define')                            */
/*****************************************************************************/
#define RLT_TMCR_CKS2_0       0x07   /* Bit mask for the CKS2-0 Bit */
#define RLT_TMCR2_CKS3        0x08   /* Bit mask for the CKS3 Bit   */

#define RLT_TMCR_CKS2_0_SHIFT 0x00   /* Shift value for the CKS2-0 Bit */
#define RLT_TMCR2_CKS3_SHIFT  0x03   /* Shift value for the CKS3 Bit   */


/*****************************************************************************/
/* Global variable definitions (declared in header file with 'extern')       */
/*****************************************************************************/


/*****************************************************************************/
/* Local type definitions ('typedef')                                        */
/*****************************************************************************/


/*****************************************************************************/
/* Local variable definitions ('static')                                     */
/*****************************************************************************/


/*****************************************************************************/
/* Local function prototypes ('static')                                      */
/*****************************************************************************/


/*****************************************************************************/
/* Function implementation - global ('extern') and local ('static')          */
/*****************************************************************************/


/**
 *****************************************************************************
 ** \brief ISR callback for Reload Timer
 **
 ** This callback is called by the global RLT ISR whenever a RLT triggers an
 ** interrupt. It in return calls the callback function that has been given
 ** during RLT initialization (see Rlt_Init() and #stc_rlt_config_t) and clears
 ** the interrupt flags of the RLT.
 **
 **
 ** \param [in] pstcRlt           RLT instance that caused the interrupt
 ** \param [in] pstcRltInternData Internal data associated with the RLT instance
 *****************************************************************************/
void BtRltIrqHandler( volatile stc_btn_rt_t* pstcRlt,
                           stc_rlt_intern_data_t* pstcRltInternData
                         )
{

    /* Check if a trigger interrupt is raised */
    if ( pstcRlt->unSTC.stcField.u1TGIR == 1 )
    {
        /* clear trigger flag of RLT */
        PDL_WRITE_REG_SYNC(pstcRlt->unSTCC.stcField.u1TGIRC, 1);

        /* Call RLT callback function */
        if ( pstcRltInternData->pfnTriggerCallback != NULL )
        {
            pstcRltInternData->pfnTriggerCallback() ;
        }
    } /* if ( pstcRlt->unSTC.stcField.u1TGIR == 1 ) */

    /* Check if a underflow interrupt is raised */
    if ( pstcRlt->unSTC.stcField.u1UDIR == 1 )
    {
        /* clear underflow flag of RLT */
        PDL_WRITE_REG_SYNC(pstcRlt->unSTCC.stcField.u1UDIRC, 1);

        /* Call RLT callback function */
        if ( pstcRltInternData->pfnUnderflowCallback != NULL )
        {
            pstcRltInternData->pfnUnderflowCallback() ;
        }
    } /* if ( pstcRlt->unSTC.stcField.u1UDIR == 1 ) */

} /* BtRltIrqHandler */


/**
 *****************************************************************************
 ** \brief Initialize a Reload Timer.
 **
 ** This function initializes the given RLT instance with the provided
 ** parameters.
 ** Before the RLT is configured the timer is disabled.
 ** The parameters are checked for plausibility. The given callback is
 ** stored internally.
 **
 ** \param [in] pstcRlt           RLT unit instance
 ** \param [in] pstcConfig        RLT configuration
 **
 ** \retval Ok                    RLT has been successfully initialized.
 ** \retval ErrorInvalidParameter If one of the following conditions are met:
 **          - one of the passed parameters is a NULL pointer
 **          - pstcRltInternData == NULL (pstcRlt is an invalid address)
 **            i.E. invalid or disabled RLT unit
 **
 *****************************************************************************/
en_result_t Bt_Rlt_Init( volatile stc_btn_rt_t* pstcRlt,
                      const stc_rlt_config_t* pstcConfig
                    )
{
    /* Pointer to the internal data structure */
    stc_rlt_intern_data_t* pstcInternData ;
    /* Local buffer to prepare the settings */
    stc_btn_rt_tmcr_field_t   stcTmcr  = { 0 } ;
    stc_btn_rt_stc_field_t    stcStc   = { 0 } ;
    stc_btn_rt_tmcr2_field_t  stcTmcr2 = { 0 } ;

    /* Check that parameters are valid pointers */
    if ( pstcRlt    == NULL ||
         pstcConfig == NULL
       )
    {
        return ErrorInvalidParameter ;
    }

    /* Get pointer to internal data ... */
    pstcInternData = BtRltGetInternDataPtr( pstcRlt ) ;
    /* ... and check for NULL pointer */
    if ( pstcInternData == NULL )
    {
        /* The pstcRlt that was passed is not available or not enabled */
        return ErrorInvalidParameter ;
    }

    /* Write STC register to reset value which also disables the RLT      */
    /* operation. u1TGIRC and u1UDIRC are set to 1 to clear the interrupt flag */
    PDL_WRITE_REG_SYNC(pstcRlt->unSTCC.stcField.u1TGIRC, 1);
    PDL_WRITE_REG_SYNC(pstcRlt->unSTCC.stcField.u1UDIRC, 1);

    /* Set the timer function */
    stcTmcr.u3FMD = 3;     /* Select 16/32-bit reload timer */

    /* Store the callback that shall be called within the interrupt routine in */
    /* the internal data structure. */
    pstcInternData->pfnTriggerCallback = pstcConfig->pfnTriggerCallback ;
    pstcInternData->pfnUnderflowCallback = pstcConfig->pfnUnderflowCallback ;

    /* Setup clock settings */
    stcTmcr.u3CKS2_0 = (pstcConfig->enPrescaler & RLT_TMCR_CKS2_0);
    stcTmcr2.u1CKS3  = (pstcConfig->enPrescaler & RLT_TMCR2_CKS3) >> RLT_TMCR2_CKS3_SHIFT;

    /* Set the operation mode of the reload timer */
    stcTmcr.u2EGS = pstcConfig->enOperationMode;

    /* configure rest of RLT */
    stcTmcr.u1T32  = (pstcConfig->b32bitTimerModeEnable    == TRUE) ? 1 : 0 ;
    stcTmcr.u1OSEL = (pstcConfig->bOutputPolarityInverse   == TRUE) ? 1 : 0 ;
    stcTmcr.u1MDSE = (pstcConfig->bOneshotEnable           == TRUE) ? 1 : 0 ;
    stcTmcr2.u1GATE = (pstcConfig->bGateInputEnable        == TRUE) ? 1 : 0 ;

    /* Write the prepared configuration to the real register */
    pstcRlt->unTMCR.stcField = stcTmcr ;
    pstcRlt->unSTC.stcField = stcStc ;
    pstcRlt->unTMCR2.stcField = stcTmcr2 ;

    return Ok ;
} /* Bt_Rlt_Init */


/**
 ***********************************************************************************
 ** \brief Start Reload Timer
 **
 ** This function enables (and optionally starts) the given RLT. If a callback
 ** was set by Bt_Rlt_Init(), the RLT interrupt is enabled and the internal ISR
 ** in turn calls the given callback.
 ** If the RLT is not triggered immediately (bTrigger == FALSE), the RLT is
 ** waiting for a trigger, which can be applied externally trigger.
 **
 ** The interrupt (and callback) is not enabled even if a callback was set
 ** by Bt_Rlt_Init().
 **
 ** Before the RLT is triggered, configure the parameters by calling Bt_Rlt_Init().
 ** If the RLT is triggered in 32-bit mode, set the instance of odd-numbered 
 ** channel to pstcRltOdd.
 **
 ** \param [in] pstcRlt           RLT unit instance
 ** \param [in] pstcRltOdd        RLT unit instance Odd channel (16bit mode is set to NULL)
 ** \param [in] u32ReloadValue    Initial reload value of the timer
 ** \param [in] bTrigger          Immediately apply software trigger
 **
 ** \retval Ok                    RLT has been started
 ** \retval ErrorInvalidParameter If one of the following conditions are met:
 **          - one of the passed parameters is a NULL pointer
 **          - pstcRltInternData == NULL (pstcRlt is an invalid address)
 **            i.E. invalid or disabled RLT unit
 **********************************************************************************/
en_result_t Bt_Rlt_Start( volatile stc_btn_rt_t* pstcRlt,
                       volatile stc_btn_rt_t* pstcRltOdd,
                       uint32_t u32ReloadValue,
                       boolean_t bTrigger
                     )
{
    /* Pointer to the internal data structure */
    stc_rlt_intern_data_t* pstcInternData ;

    /* Check that parameters are valid pointers */
    if ( pstcRlt == NULL )
    {
        return ErrorInvalidParameter ;
    }

    /* Get pointer to internal data ... */
    pstcInternData = BtRltGetInternDataPtr( pstcRlt ) ;
    /* ... and check for NULL pointer */
    if ( pstcInternData == NULL )
    {
        /* The pstcRlt that was passed is not available or not enabled */
        return ErrorInvalidParameter ;
    }

    /* If necessary register ISR */
    if ( pstcInternData->pfnTriggerCallback != NULL )
    {
        /* Enable interrupt */
        pstcRlt->unSTCS.stcField.u1TGIES = 1;
    }
    if ( pstcInternData->pfnUnderflowCallback != NULL )
    {
        /* Enable interrupt */
        pstcRlt->unSTCS.stcField.u1UDIES = 1;
    }

    /* Set initial counter value */
    /* If the instance of the odd-numbered channel is not NULL, */
    /* the RLT is work in 32bit mode. */
    if ( (pstcRltOdd != NULL) && (pstcRlt->unTMCR.stcField.u1T32 == 1) )
    {
        pstcRltOdd->unPCSR.u16Register = (uint16_t)(u32ReloadValue >> 16);
    }
    pstcRlt->unPCSR.u16Register = (uint16_t)u32ReloadValue ;

    /* Enable timer and wait for trigger */
    pstcRlt->unTMCR.stcField.u1CTEN = 1;

    /* Trigger timer if desired */
    if ( bTrigger == TRUE )
    {
        pstcRlt->unTMCR.stcField.u1STRG = 1;

    } /* if ( bTrigger == TRUE ) */


    return Ok ;
} /* Bt_Rlt_Start */


/**
 *****************************************************************************
 ** \brief Stop Reload Timer
 **
 ** This function stops and disables the given RLT. The RLT interrupt is
 ** disabled as well.
 **
 ** \param [in] pstcRlt           RLT unit instance
 **
 ** \retval Ok                    RLT has been stopped
 ** \retval ErrorInvalidParameter Parameter pstcRlt == NULL
 *****************************************************************************/
en_result_t Bt_Rlt_Stop( volatile stc_btn_rt_t* pstcRlt )
{

    /* Check that parameters are valid pointers */
    if ( pstcRlt    == NULL )
    {
        return ErrorInvalidParameter ;
    }

    /* disable timer before anything else is done */
    pstcRlt->unTMCR.stcField.u1CTEN = 0 ;
    
    /* disable interrupt */
    PDL_SAFELY_DISABLE_INTERRUPT(pstcRlt->unSTCC.stcField.u1TGIEC, 1)
    PDL_SAFELY_DISABLE_INTERRUPT(pstcRlt->unSTCC.stcField.u1UDIEC, 1)

    return Ok ;
} /* Bt_Rlt_Stop */


/*****************************************************************************/
/* EOF (not truncated)                                                       */
/*****************************************************************************/
