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

/*! \brief Contains public interface to various functions related
 *         to the Averaging with sliding window (AVERAGE) 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 _AverageType_
{
    bool     isInitial; /*!< Internal variable: Flag to indicate initial state */
    _iq     *pBuffer;   /*!< Internal variable: The pointer to the buffer */
    uint16_t winSize;   /*!< Internal variable: window length */
    uint16_t index;     /*!< Internal variable: index of the value ready to pop */
    _iq      sum;       /*!< Internal variable: the sum of all the values in buffer */

    _iq output; /*!< Output: The output value */
} AverageType;

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

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

/*! \brief Initialize the AVERAGE object
 *
 * This function initializes the average instance.
 *
 * \param[in] obj : pointer to Average instance
 * \param[in] buffer : filter buffer
 * \param[in] bufferSize : size of buffer
 */
static inline void Average_Init(AverageType *obj, _iq buffer[], uint16_t bufferSize)
{
    obj->pBuffer = &buffer[0];
    obj->winSize = bufferSize;

    for(obj->index = 0; obj->index < obj->winSize; obj->index++)
    {
        obj->pBuffer[obj->index] = 0;
    }

    obj->index     = 0;
    obj->isInitial = true;
    obj->sum       = 0;
    obj->output    = 0;
}

/*! \brief Push input to the filter
 *
 * This function pushes input to the filter.
 *
 * \param[in] obj : pointer to Average instance
 * \param[in] input : input value to be filter
 */
static inline void Average_PushInput(AverageType *obj, _iq input)
{
    if(obj->isInitial)
    {
        obj->output    = input;
        obj->isInitial = false;
    }
    else
    {
        obj->sum                 = obj->sum - obj->pBuffer[obj->index] + input;
        obj->pBuffer[obj->index] = input;
        obj->index++;
        if(obj->index > obj->winSize - 1)
        {
            obj->index = 0;
        }
        obj->output = obj->sum / obj->winSize;
    }
}

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

/*! \brief Reset the filter
 *
 * This function resets the filter to the initial state.
 *
 * \param[in] obj : pointer to Average instance
 */
static inline void Average_Reset(AverageType *obj)
{
    for(obj->index = 0; obj->index < obj->winSize; obj->index++)
    {
        obj->pBuffer[obj->index] = 0;
    }

    obj->index     = 0;
    obj->isInitial = true;
    obj->output    = 0;
}

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

#endif /* _AVERAGE_H_ */
