Algorithm Module Sources


algo.c

/**
 *
 * @copyright © 2010 - 2021, Fraunhofer-Gesellschaft zur Foerderung der
 *  angewandten Forschung e.V. All rights reserved.
 *
 * BSD 3-Clause License
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 * 1.  Redistributions of source code must retain the above copyright notice,
 *     this list of conditions and the following disclaimer.
 * 2.  Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 * 3.  Neither the name of the copyright holder nor the names of its
 *     contributors may be used to endorse or promote products derived from
 *     this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * We kindly request you to use one or more of the following phrases to refer
 * to foxBMS in your hardware, software, documentation or advertising
 * materials:
 *
 * ″This product uses parts of foxBMS®″
 *
 * ″This product includes parts of foxBMS®″
 *
 * ″This product is derived from foxBMS®″
 *
 */

/**
 * @file    algo.c
 * @author  foxBMS Team
 * @date    18.12.2017 (date of creation)
 * @ingroup DRIVERS
 * @prefix  ALGO
 *
 * @brief   Main module to handle the execution of algorithms
 *
 *
 */


/*================== Includes =============================================*/
#include "algo.h"

#include "os.h"

/*================== Macros and Definitions ===============================*/

/*================== Constant and Variable Definitions ====================*/

/*================== Function Prototypes ==================================*/

/*================== Function Implementations =============================*/
void ALGO_Init(void) {
    /* Currently nothing to initialize */

    return;
}


void ALGO_MainFunction(void) {
    static uint32_t counter_ticks = 0;

    for (uint16_t i = 0; i < algo_length; i++) {
        if (counter_ticks % algo_algorithms[i].cycleTime_ms == 0) {
            /* Cycle time elapsed -> call function */
            if (algo_algorithms[i].state == ALGO_READY) {
                /* Set state to running -> reset to READY before leaving algo function */
                algo_algorithms[i].state = ALGO_RUNNING;
                algo_algorithms[i].startTime = OS_getOSSysTick();
                algo_algorithms[i].func(i);
            } else if (algo_algorithms[i].state == ALGO_WAIT_FOR_OTHER) {
                algo_algorithms[i].state = ALGO_RDY_BUT_WAITING;
            } else {
                /* TODO: explain why empty else */
            }
        } else if (algo_algorithms[i].state == ALGO_EXECUTE_ASAP) {
            /* Waited for other algo to finish -> can now be executed */
            /* Set state to running -> reset to READY before leaving algo function */
            algo_algorithms[i].state = ALGO_RUNNING;
            algo_algorithms[i].startTime = OS_getOSSysTick();
            algo_algorithms[i].func(i);
        }
    }

    counter_ticks += ALGO_TICK_MS;
}


void ALGO_MonitorExecutionTime(void) {
    uint32_t timestamp = OS_getOSSysTick();

    for (uint16_t i = 0; i < algo_length; i++) {
        if ((algo_algorithms[i].startTime != 0) && algo_algorithms[i].state == ALGO_RUNNING &&
                ((algo_algorithms[i].startTime + algo_algorithms[i].maxCalcDuration_ms) < timestamp)) {
            /* Block task from further execution because of runtime violation, but task will finish its execution */
            algo_algorithms[i].state = ALGO_BLOCKED;

            /* TODO: Add diag call to notify error in algorithm module */
        }
    }
}

algo.h

/**
 *
 * @copyright &copy; 2010 - 2021, Fraunhofer-Gesellschaft zur Foerderung der
 *  angewandten Forschung e.V. All rights reserved.
 *
 * BSD 3-Clause License
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 * 1.  Redistributions of source code must retain the above copyright notice,
 *     this list of conditions and the following disclaimer.
 * 2.  Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 * 3.  Neither the name of the copyright holder nor the names of its
 *     contributors may be used to endorse or promote products derived from
 *     this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * We kindly request you to use one or more of the following phrases to refer
 * to foxBMS in your hardware, software, documentation or advertising
 * materials:
 *
 * &Prime;This product uses parts of foxBMS&reg;&Prime;
 *
 * &Prime;This product includes parts of foxBMS&reg;&Prime;
 *
 * &Prime;This product is derived from foxBMS&reg;&Prime;
 *
 */

/**
 * @file    algo.h
 * @author  foxBMS Team
 * @date    18.12.2017 (date of creation)
 * @ingroup DRIVERS
 * @prefix  ALGO
 *
 * @brief   Headers for the driver for the storage in the EEPROM memory
 *
 * Header file driver of external EEPROM device
 *
 */

#ifndef ALGO_H_
#define ALGO_H_


/*================== Includes =============================================*/
#include "algo_cfg.h"

/*================== Macros and Definitions ===============================*/

/*================== Constant and Variable Definitions ====================*/

/*================== Function Prototypes ==================================*/
/**
 * @brief    initializes local variables and module internals needed to use the algorithm module.
 *           Until now no initialization is needed and thus the function does nothing.
 */
extern void ALGO_Init(void);

/**
 * @brief    handles the call of different algorithm functions when cycle time has expired.
 */
extern void ALGO_MainFunction(void);

/**
 * @brief    monitors the calculation duration of the different algorithms.
 */
extern void ALGO_MonitorExecutionTime(void);


/*================== Function Implementations =============================*/

#endif /* ALGO_H_ */

algo_cfg.c

/**
 *
 * @copyright &copy; 2010 - 2021, Fraunhofer-Gesellschaft zur Foerderung der
 *  angewandten Forschung e.V. All rights reserved.
 *
 * BSD 3-Clause License
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 * 1.  Redistributions of source code must retain the above copyright notice,
 *     this list of conditions and the following disclaimer.
 * 2.  Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 * 3.  Neither the name of the copyright holder nor the names of its
 *     contributors may be used to endorse or promote products derived from
 *     this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * We kindly request you to use one or more of the following phrases to refer
 * to foxBMS in your hardware, software, documentation or advertising
 * materials:
 *
 * &Prime;This product uses parts of foxBMS&reg;&Prime;
 *
 * &Prime;This product includes parts of foxBMS&reg;&Prime;
 *
 * &Prime;This product is derived from foxBMS&reg;&Prime;
 *
 */

/**
 * @file    algo_cfg.c
 * @author  foxBMS Team
 * @date    18.12.2017 (date of creation)
 * @ingroup DRIVERS_CONF
 * @prefix  ALGO
 *
 * @brief   Configuration for the algorithm module
 *
 */

/*================== Includes =============================================*/
#include "algo_cfg.h"

#include "database.h"

/*================== Macros and Definitions ===============================*/
#if ALGO_TICK_MS > ISA_CURRENT_CYCLE_TIME_MS
#define NMBR_AVERAGES_CUR_1s           1000/ALGO_TICK_MS
#define NMBR_AVERAGES_CUR_5s           5000/ALGO_TICK_MS
#define NMBR_AVERAGES_CUR_10s          10000/ALGO_TICK_MS
#define NMBR_AVERAGES_CUR_30s          30000/ALGO_TICK_MS
#define NMBR_AVERAGES_CUR_60s          60000/ALGO_TICK_MS
#define NMBR_AVERAGES_CUR_cfg          MOVING_AVERAGE_DURATION_CURRENT_CONFIG_MS/ALGO_TICK_MS
#else
#define NMBR_AVERAGES_CUR_1s           1000/ISA_CURRENT_CYCLE_TIME_MS
#define NMBR_AVERAGES_CUR_5s           5000/ISA_CURRENT_CYCLE_TIME_MS
#define NMBR_AVERAGES_CUR_10s          10000/ISA_CURRENT_CYCLE_TIME_MS
#define NMBR_AVERAGES_CUR_30s          30000/ISA_CURRENT_CYCLE_TIME_MS
#define NMBR_AVERAGES_CUR_60s          60000/ISA_CURRENT_CYCLE_TIME_MS
#define NMBR_AVERAGES_CUR_cfg          MOVING_AVERAGE_DURATION_CURRENT_CONFIG_MS/ISA_CURRENT_CYCLE_TIME_MS
#endif

#if ALGO_TICK_MS > ISA_POWER_CYCLE_TIME_MS
#define NMBR_AVERAGES_POW_1s           1000/ALGO_TICK_MS
#define NMBR_AVERAGES_POW_5s           5000/ALGO_TICK_MS
#define NMBR_AVERAGES_POW_10s          10000/ALGO_TICK_MS
#define NMBR_AVERAGES_POW_30s          30000/ALGO_TICK_MS
#define NMBR_AVERAGES_POW_60s          60000/ALGO_TICK_MS
#define NMBR_AVERAGES_POW_cfg          MOVING_AVERAGE_DURATION_POWER_CONFIG_MS/ALGO_TICK_MS
#else
#define NMBR_AVERAGES_POW_1s           1000/ISA_POWER_CYCLE_TIME_MS
#define NMBR_AVERAGES_POW_5s           5000/ISA_POWER_CYCLE_TIME_MS
#define NMBR_AVERAGES_POW_10s          10000/ISA_POWER_CYCLE_TIME_MS
#define NMBR_AVERAGES_POW_30s          30000/ISA_POWER_CYCLE_TIME_MS
#define NMBR_AVERAGES_POW_60s          60000/ISA_POWER_CYCLE_TIME_MS
#define NMBR_AVERAGES_POW_cfg          MOVING_AVERAGE_DURATION_POWER_CONFIG_MS/ISA_POWER_CYCLE_TIME_MS
#endif

/*================== Constant and Variable Definitions ====================*/

/* Arrays in extern SDRAM to calculate moving mean current and power */

/* Check if minimum algo cycle time > current sensor sample time */
#if ALGO_TICK_MS > ISA_CURRENT_CYCLE_TIME_MS
#if MOVING_AVERAGE_DURATION_CURRENT_CONFIG_MS/ALGO_TICK_MS > 60000/ALGO_TICK_MS
/* If array length of configured time > 60s array take this array size */
static float MEM_EXT_SDRAM curValues[(MOVING_AVERAGE_DURATION_CURRENT_CONFIG_MS/ALGO_TICK_MS)+1] = {};
static uint32_t movMeanCurLength = (MOVING_AVERAGE_DURATION_CURRENT_CONFIG_MS/ALGO_TICK_MS)+1;
#else
/* Take array size of 60s moving average */
static float MEM_EXT_SDRAM curValues[(60000/ALGO_TICK_MS)+1] = {};
static uint32_t movMeanCurLength = (60000/ALGO_TICK_MS)+1;
#endif
#else
/* If array length of configured time > 60s array take this array size */
#if MOVING_AVERAGE_DURATION_CURRENT_CONFIG_MS/ISA_CURRENT_CYCLE_TIME_MS > 60000/ISA_CURRENT_CYCLE_TIME_MS
static float MEM_EXT_SDRAM curValues[(MOVING_AVERAGE_DURATION_CURRENT_CONFIG_MS/ISA_CURRENT_CYCLE_TIME_MS)+1] = {};
static uint32_t movMeanCurLength = (MOVING_AVERAGE_DURATION_CURRENT_CONFIG_MS/ISA_CURRENT_CYCLE_TIME_MS)+1;
#else
/* Take array size of 60s moving average */
static float MEM_EXT_SDRAM curValues[(60000/ISA_CURRENT_CYCLE_TIME_MS)+1] = {};
static uint32_t movMeanCurLength = (60000/ISA_CURRENT_CYCLE_TIME_MS)+1;
#endif
#endif

/* Check if minimum algo cycle time > current sensor sample time */
#if ALGO_TICK_MS > ISA_POWER_CYCLE_TIME_MS
#if MOVING_AVERAGE_DURATION_POWER_CONFIG_MS/ALGO_TICK_MS > 60000/ALGO_TICK_MS
/* If array length of configured time > 60s array take this array size */
static float MEM_EXT_SDRAM powValues[(MOVING_AVERAGE_DURATION_POWER_CONFIG_MS/ALGO_TICK_MS)+1] = {};
static uint32_t movMeanPowLength = (MOVING_AVERAGE_DURATION_POWER_CONFIG_MS/ALGO_TICK_MS)+1;
#else
/* Take array size of 60s moving average */
static float MEM_EXT_SDRAM powValues[(60000/ALGO_TICK_MS)+1] = {};
static uint32_t movMeanPowLength = (60000/ALGO_TICK_MS)+1;
#endif
#else
#if MOVING_AVERAGE_DURATION_POWER_CONFIG_MS/ISA_POWER_CYCLE_TIME_MS > 60000/ISA_POWER_CYCLE_TIME_MS
/* If array length of configured time > 60s array take this array size */
static float MEM_EXT_SDRAM powValues[(MOVING_AVERAGE_DURATION_POWER_CONFIG_MS/ISA_POWER_CYCLE_TIME_MS)+1] = {};
static uint32_t movMeanPowLength = (MOVING_AVERAGE_DURATION_POWER_CONFIG_MS/ISA_POWER_CYCLE_TIME_MS)+1;
#else
/* Take array size of 60s moving average */
static float MEM_EXT_SDRAM powValues[(60000/ISA_POWER_CYCLE_TIME_MS)+1] = {};
static uint32_t movMeanPowLength = (60000/ISA_POWER_CYCLE_TIME_MS)+1;
#endif
#endif


/* Pointer for current moving mean calculation */
static float *ptrMovMeanCur_new = &curValues[0];
static float *ptrMovMeanCur_1s = &curValues[0];
static float *ptrMovMeanCur_5s = &curValues[0];
static float *ptrMovMeanCur_10s = &curValues[0];
static float *ptrMovMeanCur_30s = &curValues[0];
static float *ptrMovMeanCur_60s = &curValues[0];
static float *ptrMovMeanCur_cfg = &curValues[0];

/* Pointer for power moving mean calculation */
static float *ptrMovMeanPow_new = &powValues[0];
static float *ptrMovMeanPow_1s = &powValues[0];
static float *ptrMovMeanPow_5s = &powValues[0];
static float *ptrMovMeanPow_10s = &powValues[0];
static float *ptrMovMeanPow_30s = &powValues[0];
static float *ptrMovMeanPow_60s = &powValues[0];
static float *ptrMovMeanPow_cfg = &powValues[0];

/*================== Function Prototypes ==================================*/
static void algo_movAverage(uint32_t algoIdx);

/*================== Function Implementations =============================*/

ALGO_TASKS_s algo_algorithms[] = {
    {ALGO_READY, 100, 1000, 0, &algo_movAverage },
};

const uint16_t algo_length = sizeof(algo_algorithms)/sizeof(algo_algorithms[0]);


static void algo_movAverage(uint32_t algoIdx) {
    static uint8_t curCounter = 0;
    static uint8_t powCounter = 0;
    static DATA_BLOCK_CURRENT_SENSOR_s curPow_tab;
    static DATA_BLOCK_MOVING_AVERAGE_s movMean_tab;
    static uint8_t curInit = 0;     /* bit0: 1s, bit1: 5s, bit2: 10s, bit3: 30s, bit4: 60s, bit5: cfg */
    static uint8_t powInit = 0;     /* bit0: 1s, bit1: 5s, bit2: 10s, bit3: 30s, bit4: 60s, bit5: cfg */
    static uint8_t newValues = 0;
    float divider = 0;

    DB_ReadBlock(&curPow_tab, DATA_BLOCK_ID_CURRENT_SENSOR);
    DB_ReadBlock(&movMean_tab, DATA_BLOCK_ID_MOV_AVERAGE);

    /* Check if new current value */
    if (curCounter != curPow_tab.newCurrent) {
        curCounter = curPow_tab.newCurrent;

        /* Check if valid value */
        if (curPow_tab.state_current == 0) {
            /* new Values -> Save later in database */
            newValues = 1;

            /* Add value to array and calculate new moving mean values */
            *ptrMovMeanCur_new = curPow_tab.current;

            /* Calculate new moving means - first add new value */
            divider = NMBR_AVERAGES_CUR_1s;
            movMean_tab.movAverage_current_1s += (*ptrMovMeanCur_new)/divider;
            divider = NMBR_AVERAGES_CUR_5s;
            movMean_tab.movAverage_current_5s += (*ptrMovMeanCur_new)/divider;
            divider = NMBR_AVERAGES_CUR_10s;
            movMean_tab.movAverage_current_10s += (*ptrMovMeanCur_new)/divider;
            divider = NMBR_AVERAGES_CUR_30s;
            movMean_tab.movAverage_current_30s += (*ptrMovMeanCur_new)/divider;
            divider = NMBR_AVERAGES_CUR_60s;
            movMean_tab.movAverage_current_60s += (*ptrMovMeanCur_new)/divider;
            divider = NMBR_AVERAGES_CUR_cfg;
            movMean_tab.movAverage_current_config += (*ptrMovMeanCur_new)/divider;

            /* Then, increment pointer and substract oldest value when respective window is filled with data */
            ptrMovMeanCur_new++;
            if ((curInit & 0x01) == 0x01) {
                divider = NMBR_AVERAGES_CUR_1s;
                movMean_tab.movAverage_current_1s -= ((*ptrMovMeanCur_1s)/divider);
                ptrMovMeanCur_1s++;
            } else {
                if (ptrMovMeanCur_new == &curValues[NMBR_AVERAGES_CUR_1s])
                    curInit |= 0x01;
            }
            if ((curInit & 0x02) == 0x02) {
                divider = NMBR_AVERAGES_CUR_5s;
                movMean_tab.movAverage_current_5s -= (*ptrMovMeanCur_5s)/divider;
                ptrMovMeanCur_5s++;
            } else {
                if (ptrMovMeanCur_new == &curValues[NMBR_AVERAGES_CUR_5s])
                    curInit |= 0x02;
            }
            if ((curInit & 0x04) == 0x04) {
                divider = NMBR_AVERAGES_CUR_10s;
                movMean_tab.movAverage_current_10s -= (*ptrMovMeanCur_10s)/divider;
                ptrMovMeanCur_10s++;
            } else {
                if (ptrMovMeanCur_new == &curValues[NMBR_AVERAGES_CUR_10s])
                    curInit |= 0x04;
            }
            if ((curInit & 0x08) == 0x08) {
                divider = NMBR_AVERAGES_CUR_30s;
                movMean_tab.movAverage_current_30s -= (*ptrMovMeanCur_30s)/divider;
                ptrMovMeanCur_30s++;
            } else {
                if (ptrMovMeanCur_new == &curValues[NMBR_AVERAGES_CUR_30s])
                    curInit |= 0x08;
            }
            if ((curInit & 0x10) == 0x10) {
                divider = NMBR_AVERAGES_CUR_60s;
                movMean_tab.movAverage_current_60s -= (*ptrMovMeanCur_60s)/divider;
                ptrMovMeanCur_60s++;
            } else {
                if (ptrMovMeanCur_new == &curValues[NMBR_AVERAGES_CUR_60s])
                    curInit |= 0x10;
            }
            if ((curInit & 0x20) == 0x20) {
                divider = NMBR_AVERAGES_CUR_cfg;
                movMean_tab.movAverage_current_config -= (*ptrMovMeanCur_cfg)/divider;
                ptrMovMeanCur_cfg++;
            } else {
                if (ptrMovMeanCur_new == &curValues[NMBR_AVERAGES_CUR_cfg])
                    curInit |= 0x20;
            }

            /* Check pointer for buffer overflow */
            if (ptrMovMeanCur_new > &curValues[movMeanCurLength-1])
                ptrMovMeanCur_new = &curValues[0];
            if (ptrMovMeanCur_1s > &curValues[movMeanCurLength-1])
                ptrMovMeanCur_1s = &curValues[0];
            if (ptrMovMeanCur_5s > &curValues[movMeanCurLength-1])
                ptrMovMeanCur_5s = &curValues[0];
            if (ptrMovMeanCur_10s > &curValues[movMeanCurLength-1])
                ptrMovMeanCur_10s = &curValues[0];
            if (ptrMovMeanCur_30s > &curValues[movMeanCurLength-1])
                ptrMovMeanCur_30s = &curValues[0];
            if (ptrMovMeanCur_60s > &curValues[movMeanCurLength-1])
                ptrMovMeanCur_60s = &curValues[0];
            if (ptrMovMeanCur_cfg > &curValues[movMeanCurLength-1])
                ptrMovMeanCur_cfg = &curValues[0];
        }
    }

    /* Check if new power value */
    if (powCounter != curPow_tab.newPower) {
        powCounter = curPow_tab.newPower;

        /* Check if valid value */
        if (curPow_tab.state_power == 0) {
            newValues = 1;

            /* Add value to array and calculate new moving mean values */
            *ptrMovMeanPow_new = curPow_tab.power;

            /* Calculate new moving means - first add new value */
            divider = NMBR_AVERAGES_POW_1s;
            movMean_tab.movAverage_power_1s += (*ptrMovMeanPow_new)/divider;
            divider = NMBR_AVERAGES_POW_5s;
            movMean_tab.movAverage_power_5s += (*ptrMovMeanPow_new)/divider;
            divider = NMBR_AVERAGES_POW_10s;
            movMean_tab.movAverage_power_10s += (*ptrMovMeanPow_new)/divider;
            divider = NMBR_AVERAGES_POW_30s;
            movMean_tab.movAverage_power_30s += (*ptrMovMeanPow_new)/divider;
            divider = NMBR_AVERAGES_POW_60s;
            movMean_tab.movAverage_power_60s += (*ptrMovMeanPow_new)/divider;
            divider = NMBR_AVERAGES_POW_cfg;
            movMean_tab.movAverage_power_config += (*ptrMovMeanPow_new)/divider;

            /* Then, increment pointer and substract oldest value when respective window is filled with data */
            ptrMovMeanPow_new++;
            if ((powInit & 0x01) == 0x01) {
                divider = NMBR_AVERAGES_POW_1s;
                movMean_tab.movAverage_power_1s -= ((*ptrMovMeanPow_1s)/divider);
                ptrMovMeanPow_1s++;
            } else {
                if (ptrMovMeanPow_new == &powValues[NMBR_AVERAGES_POW_1s])
                    powInit |= 0x01;
            }
            if ((powInit & 0x02) == 0x02) {
                divider = NMBR_AVERAGES_POW_5s;
                movMean_tab.movAverage_power_5s -= ((*ptrMovMeanPow_5s)/divider);
                ptrMovMeanPow_5s++;
            } else {
                if (ptrMovMeanPow_new == &powValues[NMBR_AVERAGES_POW_5s])
                    powInit |= 0x02;
            }
            if ((powInit & 0x04) == 0x04) {
                divider = NMBR_AVERAGES_POW_10s;
                movMean_tab.movAverage_power_10s -= ((*ptrMovMeanPow_10s)/divider);
                ptrMovMeanPow_10s++;
            } else {
                if (ptrMovMeanPow_new == &powValues[NMBR_AVERAGES_POW_10s])
                    powInit |= 0x04;
            }
            if ((powInit & 0x08) == 0x08) {
                divider = NMBR_AVERAGES_POW_30s;
                movMean_tab.movAverage_power_30s -= ((*ptrMovMeanPow_30s)/divider);
                ptrMovMeanPow_30s++;
            } else {
                if (ptrMovMeanPow_new == &powValues[NMBR_AVERAGES_POW_30s])
                    powInit |= 0x08;
            }
            if ((powInit & 0x10) == 0x10) {
                divider = NMBR_AVERAGES_POW_60s;
                movMean_tab.movAverage_power_60s -= ((*ptrMovMeanPow_60s)/divider);
                ptrMovMeanPow_60s++;
            } else {
                if (ptrMovMeanPow_new == &powValues[NMBR_AVERAGES_POW_60s])
                    powInit |= 0x10;
            }
            if ((powInit & 0x20) == 0x20) {
                divider = NMBR_AVERAGES_POW_cfg;
                movMean_tab.movAverage_power_config -= ((*ptrMovMeanPow_cfg)/divider);
                ptrMovMeanPow_cfg++;
            } else {
                if (ptrMovMeanPow_new == &powValues[NMBR_AVERAGES_POW_cfg])
                    powInit |= 0x20;
            }

            /* Check pointer for buffer overflow */
            if (ptrMovMeanPow_new > &powValues[movMeanPowLength-1])
                ptrMovMeanPow_new = &powValues[0];
            if (ptrMovMeanPow_1s > &powValues[movMeanPowLength-1])
                ptrMovMeanPow_1s = &powValues[0];
            if (ptrMovMeanPow_5s > &powValues[movMeanPowLength-1])
                ptrMovMeanPow_5s = &powValues[0];
            if (ptrMovMeanPow_10s > &powValues[movMeanPowLength-1])
                ptrMovMeanPow_10s = &powValues[0];
            if (ptrMovMeanPow_30s > &powValues[movMeanPowLength-1])
                ptrMovMeanPow_30s = &powValues[0];
            if (ptrMovMeanPow_60s > &powValues[movMeanPowLength-1])
                ptrMovMeanPow_60s = &powValues[0];
            if (ptrMovMeanPow_cfg > &powValues[movMeanPowLength-1])
                ptrMovMeanPow_cfg = &powValues[0];
        }
    }

    if (newValues == 1) {
        newValues = 0;

        DB_WriteBlock(&movMean_tab, DATA_BLOCK_ID_MOV_AVERAGE);
    }

    /* Only set task to ready state if it isn't blocked by the monitoring unit because of a runtime violation */
    if (algo_algorithms[algoIdx].state != ALGO_BLOCKED) {
        algo_algorithms[algoIdx].state = ALGO_READY;
    }
    return;
}

algo_cfg.h

/**
 *
 * @copyright &copy; 2010 - 2021, Fraunhofer-Gesellschaft zur Foerderung der
 *  angewandten Forschung e.V. All rights reserved.
 *
 * BSD 3-Clause License
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 * 1.  Redistributions of source code must retain the above copyright notice,
 *     this list of conditions and the following disclaimer.
 * 2.  Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 * 3.  Neither the name of the copyright holder nor the names of its
 *     contributors may be used to endorse or promote products derived from
 *     this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * We kindly request you to use one or more of the following phrases to refer
 * to foxBMS in your hardware, software, documentation or advertising
 * materials:
 *
 * &Prime;This product uses parts of foxBMS&reg;&Prime;
 *
 * &Prime;This product includes parts of foxBMS&reg;&Prime;
 *
 * &Prime;This product is derived from foxBMS&reg;&Prime;
 *
 */

/**
 * @file    algo_cfg.h
 * @author  foxBMS Team
 * @date    18.12.2017 (date of creation)
 * @ingroup DRIVERS_CONF
 * @prefix  ALGO
 *
 * @brief   Headers for the configuration of the algorithm module
 *
 */

#ifndef ALGO_CFG_H_
#define ALGO_CFG_H_

/*================== Includes =============================================*/
#include "general.h"

/*================== Macros and Definitions ===============================*/

#define MOVING_AVERAGE_DURATION_CURRENT_CONFIG_MS       3000
#define MOVING_AVERAGE_DURATION_POWER_CONFIG_MS         3000

#define ISA_CURRENT_CYCLE_TIME_MS                       20
#define ISA_POWER_CYCLE_TIME_MS                         20

/**
 * @ingroup CONFIG_ALGO
 * task timeslot where the ALGO main function is called. Repetition time of algorithm cycle time must be multiple of this
 * \par Type:
 * select(3)
 * \par Default:
 * 2
*/
/* #define ALGO_TICK_MS 1 */
/* #define ALGO_TICK_MS 10 */
#define ALGO_TICK_MS 100


typedef enum ALGO_STATE {
    ALGO_READY           = 0,
    ALGO_RUNNING         = 1,
    ALGO_WAIT_FOR_OTHER  = 2,
    ALGO_RDY_BUT_WAITING = 3,
    ALGO_EXECUTE_ASAP    = 4,
    ALGO_BLOCKED         = 5,
} ALGO_STATE_e;

typedef struct ALGO_TASKS {
    ALGO_STATE_e state;              /* !< current execution state */
    uint32_t cycleTime_ms;           /* !< cycle time of algorithm */
    uint32_t maxCalcDuration_ms;     /* !< maximum allowed calculation duration for task */
    uint32_t startTime;              /* !< start time when executing algorithm */
    void (*func)(uint32_t algoIdx);  /*!< callback function */
} ALGO_TASKS_s;

/*================== Constant and Variable Definitions ====================*/

/*
 * Array with pointer to the different algorithms
 */
extern ALGO_TASKS_s algo_algorithms[];

/**
 * number of executed algorithms
 */
extern const uint16_t algo_length;

/*================== Function Prototypes ==================================*/

/*================== Function Implementations =============================*/

#endif /* ALGO_CFG_H_ */