/*
 * 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 _IIR_FO_H_
#define _IIR_FO_H_

/*! \brief  Contains public interface to various functions related
 *         to the 1st-Order IIR (IirFo) low-pass filter object
 */

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

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

#ifdef __cplusplus
extern "C" {
#endif

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

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

typedef struct _IirFoType_
{
    _iq  output;      /*!< the output value */
    bool isInitial;   /*!< the flag to indicate whether the instance is initialized */
    _iq  filterCoeff; /*!< 1st order IIR, y[n] = y[n-1] + coeff*(x[n]-y[n-1]) */

} IirFoType;

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

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

/*! \brief Initialize the IirFo object
 *
 * This function initializes the 1st-order IIR filter instance
 *
 * \param[in] obj : pointer to IirFo instance
 * \param[in] filterCoeff : the coefficient of the filter
 */
static inline void IirFo_Init(IirFoType *obj, _iq filterCoeff)
{
    obj->isInitial = true;
    obj->output    = 0;
    if(filterCoeff > 0 && filterCoeff < _IQ(1.0))
    {
        obj->filterCoeff = filterCoeff;
    }
    else
    {
        obj->filterCoeff = _IQ(1.0); /* Just for protection, normally we don't want this */
    }
}

/*! \brief Theoretically initialize the IirFo object with detailed parameters
 *
 * This function initialize the IirFo object in the theoretical way using the unit rad/s
 *
 * \note The Wc_rps is the cutoff frequency in the unit of rad/s
 *
 * \param[in] obj : pointer to IirFo instance
 * \param[in] Wc_rps : the cut-off frequency in rad/s
 * \param[in] runFreq_kHz : the calculation frequency of the filter
 */
static inline void IirFo_InitTheo(IirFoType *obj, float Wc_rps, float runFreq_kHz)
{
    obj->isInitial  = true;
    obj->output     = 0;
    _iq filterCoeff = _IQ(Wc_rps / runFreq_kHz * 0.001);
    if(filterCoeff > 0 && filterCoeff < _IQ(1.0))
    {
        obj->filterCoeff = filterCoeff;
    }
    else
    {
        obj->filterCoeff = _IQ(1.0); /* Just for protection, normally we don't want this */
    }
}

/*! \brief Theoretically initialize the IirFo object with detailed parameters, 2nd interface
 *
 * This function initialize the IirFo object in the theoretical way using the unit Hz
 *
 * \note The fc_Hz is the cutoff frequency in the unit of Hz
 *
 * \param[in] obj : pointer to IirFo instance
 * \param[in] fc_Hz : the cut-off frequency in Hz
 * \param[in] runFreq_kHz : the calculation frequency of the filter
 */
static inline void IirFo_InitTheo2(IirFoType *obj, float fc_Hz, float runFreq_kHz)
{
    obj->isInitial  = true;
    obj->output     = 0;
    _iq filterCoeff = _IQ(MATH_2PI * fc_Hz / runFreq_kHz * 0.001);
    if(filterCoeff > 0 && filterCoeff < _IQ(1.0))
    {
        obj->filterCoeff = filterCoeff;
    }
    else
    {
        obj->filterCoeff = _IQ(1.0); /* Just for protection, normally we don't want this */
    }
}

/*! \brief Push input to the filter
 *
 * This function push data into the filter
 *
 * \param[in] obj : pointer to IirFo instance
 * \param[in] input : the input data
 */
static inline void IirFo_PushInput(IirFoType *obj, _iq input)
{
    if(obj->isInitial)
    {
        obj->output    = input;
        obj->isInitial = false;
    }
    else
    {
        obj->output = obj->output + _IQmpy(input - obj->output, obj->filterCoeff);
    }
}

/*! \brief Get the output value
 *
 * This function gets the output value.
 *
 * \param[in] obj : pointer to IirFo instance
 * \return the filter result of the filter in IQ format.
 */
static inline _iq IirFo_GetOutput(const IirFoType *obj)
{
    return obj->output;
}

/*! \brief Reset the filter
 *
 * This function reset the filter to the initial state.
 *
 * \param[in] obj : pointer to IirFo instance
 */
static inline void IirFo_Reset(IirFoType *obj)
{
    obj->isInitial = true;
    obj->output    = 0;
}

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

#endif /* _IIR_FO_H_ */
