Sys Module Sources


sys.c (primary)

/**
 *
 * @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    sys.c
 * @author  foxBMS Team
 * @date    21.09.2015 (date of creation)
 * @ingroup ENGINE
 * @prefix  SYS
 *
 * @brief   Sys driver implementation
 */


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

#include "bal.h"
#include "bms.h"
#include "cansignal.h"
#include "contactor.h"
#include "diag.h"
#include "interlock.h"
#include "isoguard.h"
#include "meas.h"
#include "rtc.h"
#include "sox.h"
#include "FreeRTOS.h"
#include "task.h"

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

/**
 * Saves the last state and the last substate
 */
#define SYS_SAVELASTSTATES()    sys_state.laststate = sys_state.state; \
                                sys_state.lastsubstate = sys_state.substate

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

/**
 * contains the state of the contactor state machine
 *
 */
static SYS_STATE_s sys_state = {
    .timer                  = 0,
    .statereq               = SYS_STATE_NO_REQUEST,
    .state                  = SYS_STATEMACH_UNINITIALIZED,
    .substate               = SYS_ENTRY,
    .laststate              = SYS_STATEMACH_UNINITIALIZED,
    .lastsubstate           = 0,
    .triggerentry           = 0,
    .ErrRequestCounter      = 0,
};

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

static SYS_RETURN_TYPE_e SYS_CheckStateRequest(SYS_STATE_REQUEST_e statereq);
static SYS_STATE_REQUEST_e SYS_GetStateRequest(void);
static SYS_STATE_REQUEST_e SYS_TransferStateRequest(void);
static uint8_t SYS_CheckReEntrance(void);

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

/**
 * @brief   re-entrance check of SYS state machine trigger function
 *
 * This function is not re-entrant and should only be called time- or event-triggered.
 * It increments the triggerentry counter from the state variable ltc_state.
 * It should never be called by two different processes, so if it is the case, triggerentry
 * should never be higher than 0 when this function is called.
 *
 *
 * @return  retval  0 if no further instance of the function is active, 0xff else
 *
 */
static uint8_t SYS_CheckReEntrance(void) {
    uint8_t retval = 0;

    taskENTER_CRITICAL();
    if (!sys_state.triggerentry) {
        sys_state.triggerentry++;
    } else {
        retval = 0xFF;  /* multiple calls of function */
    }
    taskEXIT_CRITICAL();

    return retval;
}




/**
 * @brief   gets the current state request.
 *
 * This function is used in the functioning of the SYS state machine.
 *
 * @return  retval  current state request, taken from SYS_STATE_REQUEST_e
 */
static SYS_STATE_REQUEST_e SYS_GetStateRequest(void) {
    SYS_STATE_REQUEST_e retval = SYS_STATE_NO_REQUEST;

    taskENTER_CRITICAL();
    retval    = sys_state.statereq;
    taskEXIT_CRITICAL();

    return (retval);
}


SYS_STATEMACH_e SYS_GetState(void) {
    return (sys_state.state);
}


/**
 * @brief   transfers the current state request to the state machine.
 *
 * This function takes the current state request from #sys_state and transfers it to the state machine.
 * It resets the value from #sys_state to #SYS_STATE_NO_REQUEST
 *
 * @return  retVal          current state request, taken from #SYS_STATE_REQUEST_e
 *
 */
static SYS_STATE_REQUEST_e SYS_TransferStateRequest(void) {
    SYS_STATE_REQUEST_e retval = SYS_STATE_NO_REQUEST;

    taskENTER_CRITICAL();
    retval    = sys_state.statereq;
    sys_state.statereq = SYS_STATE_NO_REQUEST;
    taskEXIT_CRITICAL();

    return (retval);
}



SYS_RETURN_TYPE_e SYS_SetStateRequest(SYS_STATE_REQUEST_e statereq) {
    SYS_RETURN_TYPE_e retVal = SYS_ILLEGAL_REQUEST;

    taskENTER_CRITICAL();
    retVal = SYS_CheckStateRequest(statereq);

    if (retVal == SYS_OK) {
            sys_state.statereq  = statereq;
        }
    taskEXIT_CRITICAL();

    return (retVal);
}



/**
 * @brief   checks the state requests that are made.
 *
 * This function checks the validity of the state requests.
 * The results of the checked is returned immediately.
 *
 * @param   statereq    state request to be checked
 *
 * @return              result of the state request that was made, taken from SYS_RETURN_TYPE_e
 */
static SYS_RETURN_TYPE_e SYS_CheckStateRequest(SYS_STATE_REQUEST_e statereq) {
    SYS_RETURN_TYPE_e retval = SYS_ILLEGAL_REQUEST;
    if (statereq == SYS_STATE_ERROR_REQUEST) {
        retval = SYS_OK;
    } else {
        if (sys_state.statereq == SYS_STATE_NO_REQUEST) {
            /* init only allowed from the uninitialized state */
            if (statereq == SYS_STATE_INIT_REQUEST) {
                if (sys_state.state == SYS_STATEMACH_UNINITIALIZED) {
                    retval = SYS_OK;
                } else {
                    retval = SYS_ALREADY_INITIALIZED;
                }
            } else {
                retval = SYS_ILLEGAL_REQUEST;
            }
        } else {
            retval = SYS_REQUEST_PENDING;
        }
    }
    return retval;
}


void SYS_Trigger(void) {
    /* STD_RETURN_TYPE_e retVal=E_OK; */
    SYS_STATE_REQUEST_e statereq = SYS_STATE_NO_REQUEST;
    ILCK_STATEMACH_e ilckstate = ILCK_STATEMACH_UNDEFINED;
    STD_RETURN_TYPE_e contstate = E_NOT_OK;
    STD_RETURN_TYPE_e balInitState = E_NOT_OK;
    STD_RETURN_TYPE_e bmsstate = E_NOT_OK;


    DIAG_SysMonNotify(DIAG_SYSMON_SYS_ID, 0);  /*  task is running, state = ok */
    /* Check re-entrance of function */
    if (SYS_CheckReEntrance()) {
        return;
    }

    if (sys_state.timer) {
        if (--sys_state.timer) {
            sys_state.triggerentry--;
            return;  /* handle state machine only if timer has elapsed */
        }
    }

    /****Happens every time the state machine is triggered**************/


    switch (sys_state.state) {
        /****************************UNINITIALIZED***********************************/
        case SYS_STATEMACH_UNINITIALIZED:
            /* waiting for Initialization Request */
            statereq = SYS_TransferStateRequest();
            if (statereq == SYS_STATE_INIT_REQUEST) {
                SYS_SAVELASTSTATES();
                sys_state.timer = SYS_STATEMACH_SHORTTIME_MS;
                sys_state.state = SYS_STATEMACH_INITIALIZATION;
                sys_state.substate = SYS_ENTRY;
            } else if (statereq == SYS_STATE_NO_REQUEST) {
                /* no actual request pending */
            } else {
                sys_state.ErrRequestCounter++;   /* illegal request pending */
            }
            break;
        /****************************INITIALIZATION**********************************/
        case SYS_STATEMACH_INITIALIZATION:

            SYS_SAVELASTSTATES();
            /* Initializations done here */

            /* Send CAN boot message directly on CAN */
            SYS_SendBootMessage(1);

            /* Check if undervoltage MSL violation was detected before reset */
            if (RTC_DEEP_DISCHARGE_DETECTED == 1) {
                /* Error detected */
                DIAG_Handler(DIAG_CH_DEEP_DISCHARGE_DETECTED, DIAG_EVENT_NOK, 0);
            } else {
                DIAG_Handler(DIAG_CH_DEEP_DISCHARGE_DETECTED, DIAG_EVENT_OK, 0);
            }

            sys_state.timer = SYS_STATEMACH_SHORTTIME_MS;
            sys_state.state = SYS_STATEMACH_INITIALIZED;
            sys_state.substate = SYS_ENTRY;
            break;

        /****************************INITIALIZED*************************************/
        case SYS_STATEMACH_INITIALIZED:
            SYS_SAVELASTSTATES();
            sys_state.timer = SYS_STATEMACH_SHORTTIME_MS;
#if BUILD_MODULE_ENABLE_ILCK == 1
            sys_state.state = SYS_STATEMACH_INITIALIZE_INTERLOCK;
#elif BUILD_MODULE_ENABLE_CONTACTOR == 1
            sys_state.state = SYS_STATEMACH_INITIALIZE_CONTACTORS;
#else
            sys_state.state = SYS_STATEMACH_INITIALIZE_BALANCING;
#endif
            sys_state.substate = SYS_ENTRY;
            break;

#if BUILD_MODULE_ENABLE_ILCK == 1
        /****************************INITIALIZE INTERLOCK*************************************/
        case SYS_STATEMACH_INITIALIZE_INTERLOCK:
            SYS_SAVELASTSTATES();

            if (sys_state.substate == SYS_ENTRY) {
                ILCK_SetStateRequest(ILCK_STATE_INIT_REQUEST);
                sys_state.timer = SYS_STATEMACH_SHORTTIME_MS;
                sys_state.substate = SYS_WAIT_INITIALIZATION_INTERLOCK;
                sys_state.InitCounter = 0;
                break;
            } else if (sys_state.substate == SYS_WAIT_INITIALIZATION_INTERLOCK) {
                ilckstate = ILCK_GetState();
                if (ilckstate == ILCK_STATEMACH_WAIT_FIRST_REQUEST) {
                    ILCK_SetStateRequest(ILCK_STATE_OPEN_REQUEST);
                    sys_state.timer = SYS_STATEMACH_SHORTTIME_MS;
#if BUILD_MODULE_ENABLE_CONTACTOR == 1
                    sys_state.state = SYS_STATEMACH_INITIALIZE_CONTACTORS;
#else
                    sys_state.state = SYS_STATEMACH_INITIALIZE_BALANCING;
#endif
                    sys_state.substate = SYS_ENTRY;
                    break;
                } else {
                    if (sys_state.InitCounter > (100/SYS_TASK_CYCLE_CONTEXT_MS)) {
                        sys_state.timer = SYS_STATEMACH_SHORTTIME_MS;
                        sys_state.state = SYS_STATEMACH_ERROR;
                        sys_state.substate = SYS_ILCK_INIT_ERROR;
                        break;
                    }
                    sys_state.timer = SYS_STATEMACH_SHORTTIME_MS;
                    sys_state.InitCounter++;
                    break;
                }
            }

            break;
#endif

#if BUILD_MODULE_ENABLE_CONTACTOR == 1
        /****************************INITIALIZE CONTACTORS*************************************/
        case SYS_STATEMACH_INITIALIZE_CONTACTORS:
            SYS_SAVELASTSTATES();

            if (sys_state.substate == SYS_ENTRY) {
                CONT_SetStateRequest(CONT_STATE_INIT_REQUEST);

                sys_state.timer = SYS_STATEMACH_SHORTTIME_MS;
                sys_state.substate = SYS_WAIT_INITIALIZATION_CONT;
                sys_state.InitCounter = 0;
                break;
            } else if (sys_state.substate == SYS_WAIT_INITIALIZATION_CONT) {
                contstate = CONT_GetInitializationState();
                if (contstate == E_OK) {
                    sys_state.timer = SYS_STATEMACH_SHORTTIME_MS;
                    sys_state.state = SYS_STATEMACH_INITIALIZE_BALANCING;
                    sys_state.substate = SYS_ENTRY;
                    break;
                } else {
                    if (sys_state.InitCounter > (100/SYS_TASK_CYCLE_CONTEXT_MS)) {
                        sys_state.timer = SYS_STATEMACH_SHORTTIME_MS;
                        sys_state.state = SYS_STATEMACH_ERROR;
                        sys_state.substate = SYS_CONT_INIT_ERROR;
                        break;
                    }
                    sys_state.timer = SYS_STATEMACH_SHORTTIME_MS;
                    sys_state.InitCounter++;
                    break;
                }
            }

            break;
#endif
            /****************************INITIALIZE BALANCING*************************************/
            case SYS_STATEMACH_INITIALIZE_BALANCING:
                SYS_SAVELASTSTATES();
                if (sys_state.substate == SYS_ENTRY) {
                    BAL_SetStateRequest(BAL_STATE_INIT_REQUEST);
                    sys_state.timer = SYS_STATEMACH_SHORTTIME_MS;
                    sys_state.substate = SYS_WAIT_INITIALIZATION_BAL;
                    sys_state.InitCounter = 0;
                    break;
                } else if (sys_state.substate == SYS_WAIT_INITIALIZATION_BAL) {
                    balInitState = BAL_GetInitializationState();
                    if (BALANCING_DEFAULT_INACTIVE == TRUE) {
                        BAL_SetStateRequest(BAL_STATE_GLOBAL_DISABLE_REQUEST);
                    } else {
                        BAL_SetStateRequest(BAL_STATE_GLOBAL_ENABLE_REQUEST);
                    }
                    if (balInitState == E_OK) {
                        sys_state.timer = SYS_STATEMACH_SHORTTIME_MS;
                        sys_state.state = SYS_STATEMACH_INITIALIZE_ISOGUARD;
                        sys_state.substate = SYS_ENTRY;
                        break;
                    } else {
                        if (sys_state.InitCounter > (100/SYS_TASK_CYCLE_CONTEXT_MS)) {
                            sys_state.timer = SYS_STATEMACH_SHORTTIME_MS;
                            sys_state.state = SYS_STATEMACH_ERROR;
                            sys_state.substate = SYS_BAL_INIT_ERROR;
                            break;
                        }
                        sys_state.timer = SYS_STATEMACH_SHORTTIME_MS;
                        sys_state.InitCounter++;
                        break;
                    }
                }

                break;

            /**************************** Initialize Isoguard **************************/
            case SYS_STATEMACH_INITIALIZE_ISOGUARD:

#if BUILD_MODULE_ENABLE_ISOGUARD == 1
                ISO_Init();
#endif
                sys_state.timer = SYS_STATEMACH_SHORTTIME_MS;
                sys_state.state = SYS_STATEMACH_FIRST_MEASUREMENT_CYCLE;
                sys_state.substate = SYS_ENTRY;
                break;

            /****************************START FIRST MEAS CYCLE**************************/
            case SYS_STATEMACH_FIRST_MEASUREMENT_CYCLE:
                SYS_SAVELASTSTATES();
                if (sys_state.substate == SYS_ENTRY) {
                    MEAS_StartMeasurement();
                    sys_state.InitCounter = 0;
                    sys_state.substate = SYS_WAIT_FIRST_MEASUREMENT_CYCLE;
                } else if (sys_state.substate == SYS_WAIT_FIRST_MEASUREMENT_CYCLE) {
                    if (MEAS_IsFirstMeasurementCycleFinished() == TRUE) {
                        MEAS_Request_OpenWireCheck();
                        sys_state.timer = SYS_STATEMACH_SHORTTIME_MS;
                        if (CURRENT_SENSOR_PRESENT == TRUE)
                            sys_state.state = SYS_STATEMACH_CHECK_CURRENT_SENSOR_PRESENCE;
                        else
                            sys_state.state = SYS_STATEMACH_INITIALIZE_MISC;
                        sys_state.substate = SYS_ENTRY;
                        break;
                    } else {
                        if (sys_state.InitCounter > (100/SYS_TASK_CYCLE_CONTEXT_MS)) {
                            sys_state.timer = SYS_STATEMACH_SHORTTIME_MS;
                            sys_state.state = SYS_STATEMACH_ERROR;
                            sys_state.substate = SYS_MEAS_INIT_ERROR;
                            break;
                        } else {
                            sys_state.timer = SYS_STATEMACH_MEDIUMTIME_MS;
                            sys_state.InitCounter++;
                            break;
                        }
                    }
                }
                break;

            /****************************CHECK CURRENT SENSOR PRESENCE*************************************/
            case SYS_STATEMACH_CHECK_CURRENT_SENSOR_PRESENCE:
                SYS_SAVELASTSTATES();

                if (sys_state.substate == SYS_ENTRY) {
                    sys_state.InitCounter = 0;
                    CANS_Enable_Periodic(TRUE);
#if CURRENT_SENSOR_ISABELLENHUETTE_TRIGGERED
                    /* If triggered mode is used, CAN trigger message needs to
                     * be transmitted and current sensor response has to be
                     * received afterwards. This may take some time, therefore
                     * delay has to be increased.
                     */
                    sys_state.timer = SYS_STATEMACH_LONGTIME_MS;
#else /* CURRENT_SENSOR_ISABELLENHUETTE_TRIGGERED */
                    sys_state.timer = SYS_STATEMACH_SHORTTIME_MS;
#endif /* CURRENT_SENSOR_ISABELLENHUETTE_TRIGGERED */
                    sys_state.substate = SYS_WAIT_CURRENT_SENSOR_PRESENCE;
                } else if (sys_state.substate == SYS_WAIT_CURRENT_SENSOR_PRESENCE) {
                    if (CANS_IsCurrentSensorPresent() == TRUE) {
                        SOF_Init();
                        if (CANS_IsCurrentSensorCCPresent() == TRUE) {
                            SOC_Init(TRUE);
                        } else {
                            SOC_Init(FALSE);
                        }
                        sys_state.timer = SYS_STATEMACH_SHORTTIME_MS;
                        sys_state.state = SYS_STATEMACH_INITIALIZE_MISC;
                        sys_state.substate = SYS_ENTRY;
                        break;
                    } else {
                        if (sys_state.InitCounter > (100/SYS_TASK_CYCLE_CONTEXT_MS)) {
                            sys_state.timer = SYS_STATEMACH_SHORTTIME_MS;
                            sys_state.state = SYS_STATEMACH_ERROR;
                            sys_state.substate = SYS_CURRENT_SENSOR_PRESENCE_ERROR;
                            break;
                        } else {
                            sys_state.timer = SYS_STATEMACH_MEDIUMTIME_MS;
                            sys_state.InitCounter++;
                            break;
                        }
                    }
                }
                break;

            /****************************INITIALIZED_MISC*************************************/
            case SYS_STATEMACH_INITIALIZE_MISC:
                SYS_SAVELASTSTATES();

                if (CURRENT_SENSOR_PRESENT == FALSE) {
                    CANS_Enable_Periodic(TRUE);
                    SOC_Init(FALSE);
                }

                sys_state.timer = SYS_STATEMACH_MEDIUMTIME_MS;
                sys_state.state = SYS_STATEMACH_INITIALIZE_BMS;
                sys_state.substate = SYS_ENTRY;
                break;

            /****************************INITIALIZE BMS*************************************/
            case SYS_STATEMACH_INITIALIZE_BMS:
                SYS_SAVELASTSTATES();

                if (sys_state.substate == SYS_ENTRY) {
                    BMS_SetStateRequest(BMS_STATE_INIT_REQUEST);
                    sys_state.timer = SYS_STATEMACH_SHORTTIME_MS;
                    sys_state.substate = SYS_WAIT_INITIALIZATION_BMS;
                    sys_state.InitCounter = 0;
                    break;
                } else if (sys_state.substate == SYS_WAIT_INITIALIZATION_BMS) {
                    bmsstate = BMS_GetInitializationState();
                    if (bmsstate == E_OK) {
                        sys_state.timer = SYS_STATEMACH_SHORTTIME_MS;
                        sys_state.state = SYS_STATEMACH_RUNNING;
                        sys_state.substate = SYS_ENTRY;
                        break;
                    } else {
                        if (sys_state.InitCounter > (100/SYS_TASK_CYCLE_CONTEXT_MS)) {
                            sys_state.timer = SYS_STATEMACH_SHORTTIME_MS;
                            sys_state.state = SYS_STATEMACH_ERROR;
                            sys_state.substate = SYS_BMS_INIT_ERROR;
                            break;
                        }
                        sys_state.timer = SYS_STATEMACH_SHORTTIME_MS;
                        sys_state.InitCounter++;
                        break;
                    }
                }
                break;

        /****************************RUNNNIG*************************************/
        case SYS_STATEMACH_RUNNING:
            SYS_SAVELASTSTATES();
            sys_state.timer = SYS_STATEMACH_LONGTIME_MS;
            break;

        /****************************ERROR*************************************/
        case SYS_STATEMACH_ERROR:
            SYS_SAVELASTSTATES();
            CANS_Enable_Periodic(TRUE);
            sys_state.timer = SYS_STATEMACH_LONGTIME_MS;
            break;
        /***************************DEFAULT CASE*************************************/
        default:
            /* This default case should never be entered.
             * If we actually enter this case, it means that an
             * unrecoverable error has occurred. Therefore the program
             * will trap.
             */
            configASSERT(0);
            break;
    }  /* end switch (sys_state.state) */
    sys_state.triggerentry--;
}

sys.h (primary)

/**
 *
 * @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    sys.h
 * @author  foxBMS Team
 * @date    21.09.2015 (date of creation)
 * @ingroup ENGINE
 * @prefix  SYS
 *
 * @brief   Sys driver header
 *
 *
 */

#ifndef SYS_H_
#define SYS_H_

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

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

/**
 * Symbolic names for busyness of the system
 */
typedef enum {
    SYS_CHECK_OK        = 0,    /*!< system ok      */
    SYS_CHECK_BUSY      = 1,    /*!< system busy    */
    SYS_CHECK_NOT_OK    = 2,    /*!< system not ok  */
} SYS_CHECK_e;



typedef enum {
  SYS_MODE_STARTUP_EVENT    = 0,    /*!< system startup                     */
/* SYS_MODE_EVENT_INIT      = 1,    !< todo                               */
  SYS_MODE_CYCLIC_EVENT     = 2,    /*!< for cyclic events                  */
  SYS_MODE_TRIGGERED_EVENT  = 3,    /*!< for triggered events               */
  SYS_MODE_ABNORMAL_EVENT   = 4,    /*!< for abnormal (error etc.) events   */
  SYS_MODE_EVENT_RESERVED   = 0xFF, /*!< do not use                         */
} SYS_TRIG_EVENT_e;


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

/**
 * States of the SYS state machine
 */
typedef enum {
    /* Init-Sequence */
    SYS_STATEMACH_UNINITIALIZED                             = 0,    /*!<    */
    SYS_STATEMACH_INITIALIZATION                            = 1,    /*!<    */
    SYS_STATEMACH_INITIALIZED                               = 2,    /*!<    */
    SYS_STATEMACH_INITIALIZE_INTERLOCK                      = 4,    /*!<    */
    SYS_STATEMACH_INITIALIZE_CONTACTORS                     = 5,    /*!<    */
    SYS_STATEMACH_INITIALIZE_BALANCING                      = 6,    /*!<    */
    SYS_STATEMACH_INITIALIZE_BMS                            = 7,    /*!<    */
    SYS_STATEMACH_RUNNING                                   = 8,    /*!<    */
    SYS_STATEMACH_FIRST_MEASUREMENT_CYCLE                   = 9,    /*!<    */
    SYS_STATEMACH_INITIALIZE_MISC                           = 10,   /*!<    */
    SYS_STATEMACH_CHECK_CURRENT_SENSOR_PRESENCE             = 11,   /*!<    */
    SYS_STATEMACH_INITIALIZE_ISOGUARD                       = 12,   /*!<    */
    SYS_STATEMACH_ERROR                                     = 0xF0, /*!< Error-State:       */
} SYS_STATEMACH_e;


/**
 * Substates of the SYS state machine
 */
typedef enum {
    SYS_ENTRY                           = 0,    /*!< Substate entry state       */
    SYS_CHECK_ERROR_FLAGS               = 1,    /*!< Substate check if any error flag set   */
    SYS_CHECK_STATE_REQUESTS            = 2,    /*!< Substate check if there is a state request   */
    SYS_WAIT_INITIALIZATION_INTERLOCK   = 3,    /*!< Substate to wait for initialization of the interlock state machine   */
    SYS_WAIT_INITIALIZATION_CONT        = 4,    /*!< Substate to wait for initialization of the contactor state machine   */
    SYS_WAIT_INITIALIZATION_BAL         = 5,    /*!< Substate to wait for initialization of the balancing state machine   */
    SYS_WAIT_INITIALIZATION_BMS         = 6,    /*!< Substate to wait for initialization of the bms state machine   */
    SYS_WAIT_FIRST_MEASUREMENT_CYCLE    = 7,    /*!< Substate to wait for first measurement cycle to complete   */
    SYS_WAIT_CURRENT_SENSOR_PRESENCE    = 8,    /*!< Substate to wait for first measurement cycle to complete   */
    SYS_CONT_INIT_ERROR                 = 9,    /*!< Substate error of contactor state machine initialization   */
    SYS_BAL_INIT_ERROR                  = 10,    /*!< Substate error of balancing state machine initialization   */
    SYS_ILCK_INIT_ERROR                 = 11,   /*!< Substate error of contactor state machine initialization   */
    SYS_BMS_INIT_ERROR                  = 12,   /*!< Substate error of bms state machine initialization   */
    SYS_MEAS_INIT_ERROR                 = 13,   /*!< Substate error if first measurement cycle does not complete   */
    SYS_CURRENT_SENSOR_PRESENCE_ERROR   = 14,   /*!< Substate error if first measurement cycle does not complete   */
} SYS_STATEMACH_SUB_e;


/**
 * State requests for the SYS statemachine
 */
typedef enum {
    SYS_STATE_INIT_REQUEST                = SYS_STATEMACH_INITIALIZATION,           /*!<    */
    SYS_STATE_ERROR_REQUEST               = SYS_STATEMACH_ERROR,                    /*!<    */
    SYS_STATE_NO_REQUEST,                                                           /*!<    */
} SYS_STATE_REQUEST_e;


/**
 * Possible return values when state requests are made to the SYS statemachine
 */
typedef enum {
    SYS_OK                                 = 0,    /*!< CONT --> ok                             */
    SYS_BUSY_OK                            = 1,    /*!< CONT under load --> ok                  */
    SYS_REQUEST_PENDING                    = 2,    /*!< requested to be executed               */
    SYS_ILLEGAL_REQUEST                    = 3,    /*!< Request can not be executed            */
    SYS_ALREADY_INITIALIZED                = 30,   /*!< Initialization of LTC already finished */
    SYS_ILLEGAL_TASK_TYPE                  = 99,   /*!< Illegal                                */
} SYS_RETURN_TYPE_e;



/**
 * This structure contains all the variables relevant for the CONT state machine.
 * The user can get the current state of the CONT state machine with this variable
 */
typedef struct {
    uint16_t timer;                         /*!< time in ms before the state machine processes the next state, e.g. in counts of 1ms    */
    SYS_STATE_REQUEST_e statereq;           /*!< current state request made to the state machine                                        */
    SYS_STATEMACH_e state;                  /*!< state of Driver State Machine                                                          */
    SYS_STATEMACH_SUB_e substate;                       /*!< current substate of the state machine                                                  */
    SYS_STATEMACH_e laststate;              /*!< previous state of the state machine                                                    */
    SYS_STATEMACH_SUB_e lastsubstate;                   /*!< previous substate of the state machine                                                 */
    uint32_t ErrRequestCounter;             /*!< counts the number of illegal requests to the SYS state machine */
    uint16_t InitCounter;                   /*!< Timeout to wait for initialization of state machine state machine */
    uint8_t triggerentry;                   /*!< counter for re-entrance protection (function running flag) */
} SYS_STATE_s;


/*================== Function Prototypes ==================================*/
/**
 * @brief   sets the current state request of the state variable sys_state.
 *
 * @details This function is used to make a state request to the state machine, e.g., start
 *          voltage measurement, read result of voltage measurement, re-initialization.
 *          It calls SYS_CheckStateRequest() to check if the request is valid. The state request
 *          is rejected if is not valid. The result of the check is returned immediately, so that
 *          the requester can act in case it made a non-valid state request.
 *
 * @param   statereq state requested to set
 *
 * @return  If the request was successfully set, it returns the SYS_OK, else the current state of
 *          requests (type SYS_STATE_REQUEST_e)
 */
extern SYS_RETURN_TYPE_e SYS_SetStateRequest(SYS_STATE_REQUEST_e statereq);

/**
 * @brief   gets the current state.
 *
 * @details This function is used in the functioning of the SYS state machine.
 *
 * @return  current state, taken from SYS_STATEMACH_e
 */
extern SYS_STATEMACH_e SYS_GetState(void);

/**
 * @brief   trigger function for the SYS driver state machine.
 *
 * @details This function contains the sequence of events in the SYS state machine. It must be
 *          called time-triggered, every 1ms.
 */
extern void SYS_Trigger(void);


#endif /* SYS_H_ */

sys.c (secondary)

/**
 *
 * @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    sys.c
 * @author  foxBMS Team
 * @date    21.09.2015 (date of creation)
 * @ingroup ENGINE
 * @prefix  SYS
 *
 * @brief   Sys driver implementation
 */


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

#include "bms.h"
#include "diag.h"
#include "meas.h"
#include "interlock.h"
#include "FreeRTOS.h"
#include "task.h"

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

/**
 * Saves the last state and the last substate
 */
#define SYS_SAVELASTSTATES()    sys_state.laststate = sys_state.state; \
                                sys_state.lastsubstate = sys_state.substate

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

/**
 * contains the state of the contactor state machine
 *
 */
static SYS_STATE_s sys_state = {
    .timer                  = 0,
    .statereq               = SYS_STATE_NO_REQUEST,
    .state                  = SYS_STATEMACH_UNINITIALIZED,
    .substate               = SYS_ENTRY,
    .laststate              = SYS_STATEMACH_UNINITIALIZED,
    .lastsubstate           = 0,
    .triggerentry           = 0,
    .ErrRequestCounter      = 0,
};

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

static SYS_RETURN_TYPE_e SYS_CheckStateRequest(SYS_STATE_REQUEST_e statereq);
static SYS_STATE_REQUEST_e SYS_GetStateRequest(void);
static SYS_STATE_REQUEST_e SYS_TransferStateRequest(void);
static uint8_t SYS_CheckReEntrance(void);

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

/**
 * @brief   re-entrance check of SYS state machine trigger function
 *
 * This function is not re-entrant and should only be called time- or event-triggered.
 * It increments the triggerentry counter from the state variable ltc_state.
 * It should never be called by two different processes, so if it is the case, triggerentry
 * should never be higher than 0 when this function is called.
 *
 *
 * @return  retval  0 if no further instance of the function is active, 0xff else
 *
 */
static uint8_t SYS_CheckReEntrance(void) {
    uint8_t retval = 0;

    taskENTER_CRITICAL();
    if (!sys_state.triggerentry) {
        sys_state.triggerentry++;
    } else {
        retval = 0xFF;  /* multiple calls of function */
    }
    taskEXIT_CRITICAL();

    return retval;
}




/**
 * @brief   gets the current state request.
 *
 * This function is used in the functioning of the SYS state machine.
 *
 * @return  retval  current state request, taken from SYS_STATE_REQUEST_e
 */
static SYS_STATE_REQUEST_e SYS_GetStateRequest(void) {
    SYS_STATE_REQUEST_e retval = SYS_STATE_NO_REQUEST;

    taskENTER_CRITICAL();
    retval    = sys_state.statereq;
    taskEXIT_CRITICAL();

    return (retval);
}


SYS_STATEMACH_e SYS_GetState(void) {
    return (sys_state.state);
}


/**
 * @brief   transfers the current state request to the state machine.
 *
 * This function takes the current state request from #sys_state and transfers it to the state machine.
 * It resets the value from #sys_state to #SYS_STATE_NO_REQUEST
 *
 * @return  retVal          current state request, taken from #SYS_STATE_REQUEST_e
 *
 */
static SYS_STATE_REQUEST_e SYS_TransferStateRequest(void) {
    SYS_STATE_REQUEST_e retval = SYS_STATE_NO_REQUEST;

    taskENTER_CRITICAL();
    retval    = sys_state.statereq;
    sys_state.statereq = SYS_STATE_NO_REQUEST;
    taskEXIT_CRITICAL();

    return (retval);
}



SYS_RETURN_TYPE_e SYS_SetStateRequest(SYS_STATE_REQUEST_e statereq) {
    SYS_RETURN_TYPE_e retVal = SYS_ILLEGAL_REQUEST;

    taskENTER_CRITICAL();
    retVal = SYS_CheckStateRequest(statereq);

    if (retVal == SYS_OK) {
            sys_state.statereq  = statereq;
        }
    taskEXIT_CRITICAL();

    return (retVal);
}



/**
 * @brief   checks the state requests that are made.
 *
 * This function checks the validity of the state requests.
 * The results of the checked is returned immediately.
 *
 * @param   statereq    state request to be checked
 *
 * @return              result of the state request that was made, taken from SYS_RETURN_TYPE_e
 */
static SYS_RETURN_TYPE_e SYS_CheckStateRequest(SYS_STATE_REQUEST_e statereq) {
    SYS_RETURN_TYPE_e retval = SYS_ILLEGAL_REQUEST;
    if (statereq == SYS_STATE_ERROR_REQUEST) {
        retval = SYS_OK;
    } else {
        if (sys_state.statereq == SYS_STATE_NO_REQUEST) {
            /* init only allowed from the uninitialized state */
            if (statereq == SYS_STATE_INIT_REQUEST) {
                if (sys_state.state == SYS_STATEMACH_UNINITIALIZED) {
                    retval = SYS_OK;
                } else {
                    retval = SYS_ALREADY_INITIALIZED;
                }
            } else {
                retval = SYS_ILLEGAL_REQUEST;
            }
        } else {
            retval = SYS_REQUEST_PENDING;
        }
    }
    return retval;
}


void SYS_Trigger(void) {
    /* STD_RETURN_TYPE_e retVal=E_OK; */
    SYS_STATE_REQUEST_e statereq = SYS_STATE_NO_REQUEST;
    ILCK_STATEMACH_e ilckstate = ILCK_STATEMACH_UNDEFINED;
    STD_RETURN_TYPE_e bmsstate = E_NOT_OK;


    DIAG_SysMonNotify(DIAG_SYSMON_SYS_ID, 0);  /*  task is running, state = ok */
    /* Check re-entrance of function */
    if (SYS_CheckReEntrance()) {
        return;
    }

    if (sys_state.timer) {
        if (--sys_state.timer) {
            sys_state.triggerentry--;
            return;  /* handle state machine only if timer has elapsed */
        }
    }

    /****Happens every time the state machine is triggered**************/


    switch (sys_state.state) {
        /****************************UNINITIALIZED***********************************/
        case SYS_STATEMACH_UNINITIALIZED:
            /* waiting for Initialization Request */
            statereq = SYS_TransferStateRequest();
            if (statereq == SYS_STATE_INIT_REQUEST) {
                SYS_SAVELASTSTATES();
                sys_state.timer = SYS_STATEMACH_SHORTTIME_MS;
                sys_state.state = SYS_STATEMACH_INITIALIZATION;
                sys_state.substate = SYS_ENTRY;
            } else if (statereq == SYS_STATE_NO_REQUEST) {
                /* no actual request pending */
            } else {
                sys_state.ErrRequestCounter++;   /* illegal request pending */
            }
            break;
        /****************************INITIALIZATION**********************************/
        case SYS_STATEMACH_INITIALIZATION:

            SYS_SAVELASTSTATES();
            /* Initializations done here */
            sys_state.timer = SYS_STATEMACH_SHORTTIME_MS;
            sys_state.state = SYS_STATEMACH_INITIALIZED;
            sys_state.substate = SYS_ENTRY;
            break;

        /****************************INITIALIZED*************************************/
        case SYS_STATEMACH_INITIALIZED:
            SYS_SAVELASTSTATES();
            MEAS_StartMeasurement();
            sys_state.timer = SYS_STATEMACH_SHORTTIME_MS;
            sys_state.state = SYS_STATEMACH_INITIALIZE_INTERLOCK;
            sys_state.substate = SYS_ENTRY;
            break;

        /****************************INITIALIZE INTERLOCK*************************************/
        case SYS_STATEMACH_INITIALIZE_INTERLOCK:
            SYS_SAVELASTSTATES();

            if (sys_state.substate == SYS_ENTRY) {
                ILCK_SetStateRequest(ILCK_STATE_INIT_REQUEST);
                sys_state.timer = SYS_STATEMACH_SHORTTIME_MS;
                sys_state.substate = SYS_WAIT_INITIALIZATION_INTERLOCK;
                sys_state.InitCounter = 0;
                break;
            } else if (sys_state.substate == SYS_WAIT_INITIALIZATION_INTERLOCK) {
                ilckstate = ILCK_GetState();
                if (ilckstate == ILCK_STATEMACH_WAIT_FIRST_REQUEST) {
                    ILCK_SetStateRequest(ILCK_STATE_CLOSE_REQUEST);
                    sys_state.timer = SYS_STATEMACH_SHORTTIME_MS;
                    sys_state.state = SYS_STATEMACH_INITIALIZE_MISC;
                    sys_state.substate = SYS_ENTRY;
                    break;
                } else {
                    if (sys_state.InitCounter > 1000) {
                        sys_state.timer = SYS_STATEMACH_SHORTTIME_MS;
                        sys_state.state = SYS_STATEMACH_ERROR;
                        sys_state.substate = SYS_ILCK_INIT_ERROR;
                        break;
                    }
                    sys_state.timer = SYS_STATEMACH_SHORTTIME_MS;
                    sys_state.InitCounter++;
                    break;
                }
            }

            break;


                /****************************INITIALIZED_MISC*************************************/
                case SYS_STATEMACH_INITIALIZE_MISC:
                    SYS_SAVELASTSTATES();


                    sys_state.timer = SYS_STATEMACH_MEDIUMTIME_MS;
                    sys_state.state = SYS_STATEMACH_INITIALIZE_BMS;
                    sys_state.substate = SYS_ENTRY;
                    break;

            /****************************INITIALIZE BMS*************************************/
            case SYS_STATEMACH_INITIALIZE_BMS:
                SYS_SAVELASTSTATES();

                if (sys_state.substate == SYS_ENTRY) {
                    BMS_SetStateRequest(BMS_STATE_INIT_REQUEST);
                    sys_state.timer = SYS_STATEMACH_SHORTTIME_MS;
                    sys_state.substate = SYS_WAIT_INITIALIZATION_BMS;
                    sys_state.InitCounter = 0;
                    break;
                } else if (sys_state.substate == SYS_WAIT_INITIALIZATION_BMS) {
                    bmsstate = BMS_GetInitializationState();
                    if (bmsstate == E_OK) {
                        sys_state.timer = SYS_STATEMACH_SHORTTIME_MS;
                        sys_state.state = SYS_STATEMACH_RUNNING;
                        sys_state.substate = SYS_ENTRY;
                        break;
                    } else {
                        if (sys_state.InitCounter > 1000) {
                            sys_state.timer = SYS_STATEMACH_SHORTTIME_MS;
                            sys_state.state = SYS_STATEMACH_ERROR;
                            sys_state.substate = SYS_BMS_INIT_ERROR;
                            break;
                        }
                        sys_state.timer = SYS_STATEMACH_SHORTTIME_MS;
                        sys_state.InitCounter++;
                        break;
                    }
                }
                break;

        /****************************RUNNNIG*************************************/
        case SYS_STATEMACH_RUNNING:
            SYS_SAVELASTSTATES();
            sys_state.timer = SYS_STATEMACH_LONGTIME_MS;
            break;

        /****************************ERROR*************************************/
        case SYS_STATEMACH_ERROR:
            SYS_SAVELASTSTATES();
            sys_state.timer = SYS_STATEMACH_LONGTIME_MS;
            break;
        /***************************DEFAULT CASE*************************************/
        default:
            /* This default case should never be entered.
             * If we actually enter this case, it means that an
             * unrecoverable error has occurred. Therefore the program
             * will trap.
             */
            configASSERT(0);
            break;
    }  /* end switch (sys_state.state) */
    sys_state.triggerentry--;
}

sys.h (secondary)

/**
 *
 * @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    sys.h
 * @author  foxBMS Team
 * @date    21.09.2015 (date of creation)
 * @ingroup ENGINE
 * @prefix  SYS
 *
 * @brief   Sys driver header
 *
 *
 */

#ifndef SYS_H_
#define SYS_H_

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

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

/**
 * Symbolic names for busyness of the system
 */
typedef enum {
    SYS_CHECK_OK        = 0,    /*!< system ok      */
    SYS_CHECK_BUSY      = 1,    /*!< system busy    */
    SYS_CHECK_NOT_OK    = 2,    /*!< system not ok  */
} SYS_CHECK_e;



typedef enum {
  SYS_MODE_STARTUP_EVENT    = 0,    /*!< system startup                     */
/* SYS_MODE_EVENT_INIT      = 1,    !< todo                               */
  SYS_MODE_CYCLIC_EVENT     = 2,    /*!< for cyclic events                  */
  SYS_MODE_TRIGGERED_EVENT  = 3,    /*!< for triggered events               */
  SYS_MODE_ABNORMAL_EVENT   = 4,    /*!< for abnormal (error etc.) events   */
  SYS_MODE_EVENT_RESERVED   = 0xFF, /*!< do not use                         */
} SYS_TRIG_EVENT_e;


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

/**
 * States of the SYS state machine
 */
typedef enum {
    /* Init-Sequence */
    SYS_STATEMACH_UNINITIALIZED                             = 0,    /*!<    */
    SYS_STATEMACH_INITIALIZATION                            = 1,    /*!<    */
    SYS_STATEMACH_INITIALIZED                               = 2,    /*!<    */
    SYS_STATEMACH_INITIALIZE_INTERLOCK                      = 4,    /*!<    */
    SYS_STATEMACH_INITIALIZE_CONTACTORS                     = 5,    /*!<    */
    SYS_STATEMACH_INITIALIZE_BALANCING                      = 6,    /*!<    */
    SYS_STATEMACH_INITIALIZE_BMS                            = 7,    /*!<    */
    SYS_STATEMACH_RUNNING                                   = 8,    /*!<    */
    SYS_STATEMACH_FIRST_MEASUREMENT_CYCLE                   = 9,    /*!<    */
    SYS_STATEMACH_INITIALIZE_MISC                           = 10,   /*!<    */
    SYS_STATEMACH_CHECK_CURRENT_SENSOR_PRESENCE             = 11,   /*!<    */
    SYS_STATEMACH_INITIALIZE_ISOGUARD                       = 12,   /*!<    */
    SYS_STATEMACH_ERROR                                     = 0xF0, /*!< Error-State:       */
} SYS_STATEMACH_e;


/**
 * Substates of the SYS state machine
 */
typedef enum {
    SYS_ENTRY                           = 0,    /*!< Substate entry state       */
    SYS_CHECK_ERROR_FLAGS               = 1,    /*!< Substate check if any error flag set   */
    SYS_CHECK_STATE_REQUESTS            = 2,    /*!< Substate check if there is a state request   */
    SYS_WAIT_INITIALIZATION_INTERLOCK   = 3,    /*!< Substate to wait for initialization of the interlock state machine   */
    SYS_WAIT_INITIALIZATION_CONT        = 4,    /*!< Substate to wait for initialization of the contactor state machine   */
    SYS_WAIT_INITIALIZATION_BAL         = 5,    /*!< Substate to wait for initialization of the balancing state machine   */
    SYS_WAIT_INITIALIZATION_BMS         = 6,    /*!< Substate to wait for initialization of the bms state machine   */
    SYS_WAIT_FIRST_MEASUREMENT_CYCLE    = 7,    /*!< Substate to wait for first measurement cycle to complete   */
    SYS_WAIT_CURRENT_SENSOR_PRESENCE    = 8,    /*!< Substate to wait for first measurement cycle to complete   */
    SYS_CONT_INIT_ERROR                 = 9,    /*!< Substate error of contactor state machine initialization   */
    SYS_ILCK_INIT_ERROR                 = 10,   /*!< Substate error of contactor state machine initialization   */
    SYS_BMS_INIT_ERROR                  = 11,   /*!< Substate error of bms state machine initialization   */
    SYS_MEAS_INIT_ERROR                 = 12,   /*!< Substate error if first measurement cycle does not complete   */
    SYS_CURRENT_SENSOR_PRESENCE_ERROR   = 13,   /*!< Substate error if first measurement cycle does not complete   */
} SYS_STATEMACH_SUB_e;


/**
 * State requests for the SYS statemachine
 */
typedef enum {
    SYS_STATE_INIT_REQUEST                = SYS_STATEMACH_INITIALIZATION,           /*!<    */
    SYS_STATE_ERROR_REQUEST               = SYS_STATEMACH_ERROR,                    /*!<    */
    SYS_STATE_NO_REQUEST,                                                           /*!<    */
} SYS_STATE_REQUEST_e;


/**
 * Possible return values when state requests are made to the SYS statemachine
 */
typedef enum {
    SYS_OK                                 = 0,    /*!< CONT --> ok                             */
    SYS_BUSY_OK                            = 1,    /*!< CONT under load --> ok                  */
    SYS_REQUEST_PENDING                    = 2,    /*!< requested to be executed               */
    SYS_ILLEGAL_REQUEST                    = 3,    /*!< Request can not be executed            */
    SYS_ALREADY_INITIALIZED                = 30,   /*!< Initialization of LTC already finished */
    SYS_ILLEGAL_TASK_TYPE                  = 99,   /*!< Illegal                                */
} SYS_RETURN_TYPE_e;



/**
 * This structure contains all the variables relevant for the CONT state machine.
 * The user can get the current state of the CONT state machine with this variable
 */
typedef struct {
    uint16_t timer;                         /*!< time in ms before the state machine processes the next state, e.g. in counts of 1ms    */
    SYS_STATE_REQUEST_e statereq;           /*!< current state request made to the state machine                                        */
    SYS_STATEMACH_e state;                  /*!< state of Driver State Machine                                                          */
    SYS_STATEMACH_SUB_e substate;                       /*!< current substate of the state machine                                                  */
    SYS_STATEMACH_e laststate;              /*!< previous state of the state machine                                                    */
    SYS_STATEMACH_SUB_e lastsubstate;                   /*!< previous substate of the state machine                                                 */
    uint32_t ErrRequestCounter;             /*!< counts the number of illegal requests to the SYS state machine */
    uint16_t InitCounter;                   /*!< Timeout to wait for initialization of state machine state machine */
    uint8_t triggerentry;                   /*!< counter for re-entrance protection (function running flag) */
} SYS_STATE_s;


/*================== Function Prototypes ==================================*/
/**
 * @brief   sets the current state request of the state variable sys_state.
 *
 * @details This function is used to make a state request to the state machine, e.g., start
 *          voltage measurement, read result of voltage measurement, re-initialization.
 *          It calls SYS_CheckStateRequest() to check if the request is valid. The state request
 *          is rejected if is not valid. The result of the check is returned immediately, so that
 *          the requester can act in case it made a non-valid state request.
 *
 * @param   statereq state requested to set
 *
 * @return  If the request was successfully set, it returns the SYS_OK, else the current state of
 *          requests (type SYS_STATE_REQUEST_e)
 */
extern SYS_RETURN_TYPE_e SYS_SetStateRequest(SYS_STATE_REQUEST_e statereq);

/**
 * @brief   gets the current state.
 *
 * @details This function is used in the functioning of the SYS state machine.
 *
 * @return  current state, taken from SYS_STATEMACH_e
 */
extern SYS_STATEMACH_e SYS_GetState(void);

/**
 * @brief   trigger function for the SYS driver state machine.
 *
 * @details This function contains the sequence of events in the SYS state machine. It must be
 *          called time-triggered, every 1ms.
 */
extern void SYS_Trigger(void);


#endif /* SYS_H_ */

sys_cfg.c (primary)

/**
 *
 * @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    sys_cfg.c
 * @author  foxBMS Team
 * @date    21.09.2015 (date of creation)
 * @ingroup ENGINE_CONF
 * @prefix  SYS
 *
 * @brief   Sys driver configuration
 */

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

#include "can.h"
#include "version.h"
#include "stdlib.h"

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

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

/*================== Function Implementations =============================*/
void SYS_SendBootMessage(uint8_t directTransmission) {
    /* Send CAN boot successful message */
    uint8_t data[8];
    data[0] = (uint8_t)atoi((char*)&ver_sw_validation.Version[0]);          /* SW-Version number: major */
    data[1] = (uint8_t)atoi((char*)&ver_sw_validation.Version[2]);          /* SW-Version number: minor */
    data[2] = (uint8_t)atoi((char*)&ver_sw_validation.Version[4]);          /* SW-Version number: bugfix */
    data[3] = 0;
    data[4] = 0xFF & ver_sw_validation.Checksum_u32;
    data[5] = 0xFF & (ver_sw_validation.Checksum_u32 >> 8);
    data[6] = 0xFF & (ver_sw_validation.Checksum_u32 >> 16);
    data[7] = 0xFF & (ver_sw_validation.Checksum_u32 >> 24);
    if (directTransmission == 0) {
        CAN_Send(CAN_NODE0, 0x101, &data[0], 8, 0);
    } else {
        CAN_TxMsg(CAN_NODE0, 0x101, &data[0], 8, 0);
    }
}

sys_cfg.h (primary)

/**
 *
 * @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    sys_cfg.h
 * @author  foxBMS Team
 * @date    21.09.2015 (date of creation)
 * @ingroup ENGINE_CONF
 * @prefix  SYS
 *
 * @brief   Sys driver configuration header
 */

#ifndef SYS_CFG_H_
#define SYS_CFG_H_

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

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

/**
 * This define MUST represent the cycle time of the task in which context the
 * functions run, e.g., if the SYS_Trigger() is running in the 10 ms task
 * then the define must be set to 10.
 *
 * This define also sets the minimum time.
 */

#define SYS_TASK_CYCLE_CONTEXT_MS (10)

/**
 * SYS statemachine short time definition in ms
 */

#define SYS_STATEMACH_SHORTTIME_MS      (SYS_TASK_CYCLE_CONTEXT_MS)

/**
 * SYS statemachine short time definition in ms
 */

#define SYS_STATEMACH_MEDIUMTIME_MS     (SYS_TASK_CYCLE_CONTEXT_MS)

/**
 * SYS statemachine long time definition in ms
 */

#define SYS_STATEMACH_LONGTIME_MS       ((10) * (SYS_TASK_CYCLE_CONTEXT_MS))


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

/**
 * Function to send out boot message with SW version
 */
extern void SYS_SendBootMessage(uint8_t directTransmission);

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

#endif /* SYS_CFG_H_ */

sys_cfg.c (secondary)

/**
 *
 * @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    sys_cfg.c
 * @author  foxBMS Team
 * @date    21.09.2015 (date of creation)
 * @ingroup ENGINE_CONF
 * @prefix  SYS
 *
 * @brief   Sys driver configuration
 */

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

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

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

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

sys_cfg.h (secondary)

/**
 *
 * @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    sys_cfg.h
 * @author  foxBMS Team
 * @date    21.09.2015 (date of creation)
 * @ingroup ENGINE_CONF
 * @prefix  SYS
 *
 * @brief   Sys driver configuration header
 */

#ifndef SYS_CFG_H_
#define SYS_CFG_H_

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

/*================== Macros and Definitions ===============================*/
/**
 * SYS statemachine short time definition in ms
 */

#define SYS_STATEMACH_SHORTTIME_MS     1

/**
 * SYS statemachine short time definition in ms
 */

#define SYS_STATEMACH_MEDIUMTIME_MS     10

/**
 * SYS statemachine long time definition in ms
 */

#define SYS_STATEMACH_LONGTIME_MS     100


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

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

#endif /* SYS_CFG_H_ */