/*
 * Copyright (c) 2022, Shenzhen CVA Innovation CO.,LTD
 * All rights reserved.
 *
 * Shenzhen CVA Innovation CO.,LTD (CVA chip) is supplying this file for use
 * exclusively with CVA's microcontroller products. This file can be freely
 * distributed within development tools that are supporting such microcontroller
 * products.
 *
 * THIS SOFTWARE IS PROVIDED "AS IS".  NO WARRANTIES, WHETHER EXPRESS, IMPLIED
 * OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.
 * CVA SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL,
 * OR CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
 */

#ifndef _TRIGGER_H_
#define _TRIGGER_H_

/*! \brief  Contains public interface to various functions related
 *          to the Trigger object
 */

/*******************************************************************************
 * the includes
 ******************************************************************************/

#include <stdint.h>
#include <stdbool.h>
#include "common/iqmath/iqmath.h"
#include "common/sort/compare.h"

#ifdef __cplusplus
extern "C" {
#endif

/*******************************************************************************
 * the defines
 ******************************************************************************/

/*******************************************************************************
 * the typedefs
 ******************************************************************************/

/*! \brief The definition of Compare mode
 */
typedef enum
{
    TRIGGER_COMPTYPE_OVER,
    TRIGGER_COMPTYPE_UNDER,
} Trigger_CompModeType;

/*! \brief The definition of parameters of Trigger class
 */
typedef struct _Trigger_ParamsType_
{
    Trigger_CompModeType compType;
    _iq                  threshold;
    _iq                  recoverValue;
    uint16_t             trigCntMax;
    uint16_t             recoverCntMax;
    bool                 isRecoverable;
} Trigger_ParamsType;

/*! \brief The definition of Trigger prototype
 */
typedef struct _TriggerType_
{
    _iq input; /*!< Input: The input for scan */

    _iq      threshold;     /*!< Parameter: The threshold for compare */
    _iq      recoverValue;  /*!< Parameter: The recover value that will reverse trigger */
    uint16_t trigCntMax;    /*!< Parameter: The max counts for the compare */
    uint16_t recoverCntMax; /*!< Parameter: The max counts for the recover */
    bool     isRecoverable; /*!< Parameter: Whether the trigger can be recovered */

    uint16_t trigCnt;          /*!< Internal Variable: The count for the compare */
    uint16_t recoverCnt;       /*!< Internal Variable: The count for the recover */
    bool (*comp)(_iq, _iq);    /*!< Internal Variable: The compare function pointer */
    bool (*recover)(_iq, _iq); /*!< Internal Variable: The recover function pointer */

    bool compSatisfied; /*!< Output: Whether compare satisfied without debounce */
    bool isTriggered;   /*!< Output: Whether it's triggered based on compare and debounce */
} TriggerType;

/*******************************************************************************
 * the globals
 ******************************************************************************/

/*******************************************************************************
 * the function prototypes
 ******************************************************************************/

/*! \brief The initialization of Trigger
 *
 * This function initializes the trigger instance
 *
 * \param[in] obj : pointer to Trigger instance
 * \param[in] pParams : pointer to the parameters
 */
static inline void Trigger_Init(TriggerType *obj, const Trigger_ParamsType *pParams)
{
    obj->trigCntMax    = pParams->trigCntMax;
    obj->recoverCntMax = pParams->recoverCntMax;
    obj->threshold     = pParams->threshold;
    obj->recoverValue  = pParams->recoverValue;
    obj->isRecoverable = pParams->isRecoverable;
    if(pParams->compType == TRIGGER_COMPTYPE_OVER)
    {
        obj->comp    = Compare_GreaterThan;
        obj->recover = Compare_SmallerThan;
    }
    else if(pParams->compType == TRIGGER_COMPTYPE_UNDER)
    {
        obj->comp    = Compare_SmallerThan;
        obj->recover = Compare_GreaterThan;
    }

    obj->trigCnt       = 0;
    obj->recoverCnt    = 0;
    obj->compSatisfied = false;
    obj->isTriggered   = false;
}

/*! \brief Run the trigger algorithm
 *
 * This function runs the trigger algorithm
 *
 * \param[in] obj : pointer to Trigger instance
 */
static inline void Trigger_Run(TriggerType *obj)
{
    if(obj->comp(obj->input, obj->threshold))
    {
        obj->compSatisfied = true;
        obj->recoverCnt    = 0;
        if(obj->trigCnt < obj->trigCntMax)
        {
            obj->trigCnt++;
        }
        if(obj->trigCnt >= obj->trigCntMax)
        {
            obj->isTriggered = true;
        }
    }
    else
    {
        obj->compSatisfied = false;
        obj->trigCnt       = 0;
        if(obj->isRecoverable)
        {
            if(obj->recover(obj->input, obj->recoverValue))
            {
                if(obj->recoverCnt < obj->recoverCntMax)
                {
                    obj->recoverCnt++;
                }
                if(obj->recoverCnt >= obj->recoverCntMax)
                {
                    obj->isTriggered = false;
                }
            }
            else
            {
                obj->recoverCnt = 0;
            }
        }
    }
}

/*! \brief Reset the trigger instance
 *
 * This function reset the trigger to the initial state
 *
 * \param[in] obj : pointer to Trigger instance
 */
static inline void Trigger_Reset(TriggerType *obj)
{
    obj->trigCnt       = 0;
    obj->recoverCnt    = 0;
    obj->compSatisfied = false;
    obj->isTriggered   = false;
}

#ifdef __cplusplus
}
#endif /* extern "C" */

#endif /* _TRIGGER_H_ */
