Diagnosis Module Sources


diag.c

/**
 *
 * @copyright © 2010 - 2020, 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    diag.c
 * @author  foxBMS Team
 * @date    09.11.2015 (date of creation)
 * @ingroup ENGINE
 * @prefix  DIAG
 *
 * @brief   Diagnosis driver implementation
 *
 * This diagnose module is responsible for error handling and reporting.
 * Reported errors are logged into the global database and can be reviewed
 * on user request.
 */

/*================== Includes =============================================*/
#include "diag.h"
#if BUILD_MODULE_ENABLE_CONTACTOR == 1
#include "contactor.h"
#endif
#include "com.h"
#include "os.h"
#if BUILD_MODULE_ENABLE_NVRAM == 1
#include "nvramhandler.h"
#endif
#include "rtc.h"
#include "stdio.h"

extern int _write(int fd, char *ptr, int len);

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

/*================== Constant and Variable Definitions ====================*/
static DIAG_s diag;
static DIAG_DEV_s  *diag_devptr;
static uint32_t diagsysmonTimestamp = 0;
static uint8_t diag_locked = 0;

DIAG_SYSMON_NOTIFICATION_s diag_sysmon[DIAG_SYSMON_MODULE_ID_MAX];
DIAG_SYSMON_NOTIFICATION_s diag_sysmon_last[DIAG_SYSMON_MODULE_ID_MAX];

uint32_t diag_sysmon_cnt[DIAG_SYSMON_MODULE_ID_MAX];

DIAG_ERROR_ENTRY_s MEM_BKP_SRAM diag_memory[DIAG_FAIL_ENTRY_LENGTH];
DIAG_ERROR_ENTRY_s MEM_BKP_SRAM *diag_entry_wrptr;
DIAG_ERROR_ENTRY_s MEM_BKP_SRAM *diag_entry_rdptr;

DIAG_CONTACTOR_ERROR_ENTRY_s MEM_BKP_SRAM diagContactorErrorMemory[DIAG_FAIL_ENTRY_CONTACTOR_LENGTH];
DIAG_CONTACTOR_ERROR_ENTRY_s MEM_BKP_SRAM *diagContactorError_entry_wrptr;
DIAG_CONTACTOR_ERROR_ENTRY_s MEM_BKP_SRAM *diagContactorError_entry_rdptr;

DIAG_FAILURECODE_s diag_fc;

/*================== Function Prototypes ==================================*/
static void DIAG_Reset(void);
static uint8_t DIAG_EntryWrite(uint8_t eventID, DIAG_EVENT_e event, uint32_t item_nr);

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

/**
 * @brief   DIAG_Reset resets/initializes all needed structures/buffers.
 *
 * This function gets called during initialization of the diagnose module.
 * It clears memory and counters used by diag later on.
 */

static void DIAG_Reset(void) {
    uint32_t i;
    uint32_t *u32ptr = (uint32_t*)(&diag_memory[0]);

    diag_locked = 1;

    /* Delete memory */
    for (i = 0; i < (sizeof(diag_memory))/4; i++) {
        *u32ptr++ = 0;
    }

    /* Reset counter */
    for (i = 0; i < sizeof(diag.entry_cnt); i++) {
        diag.entry_cnt[i] = 0;
    }

    /* Set pointer to beginning of buffer */
    diag_entry_wrptr = diag_entry_rdptr = &diag_memory[0];
    diag.errcnttotal = 0;

    /* Set pointer to beginning of buffer */
    u32ptr = (uint32_t*)(&diagContactorErrorMemory[0]);

    /* Delete memory */
    for (i = 0; i < (sizeof(diagContactorErrorMemory))/4; i++) {
        *u32ptr++ = 0;
    }

    /* Set pointer to beginning of buffer */
    diagContactorError_entry_wrptr = diagContactorError_entry_rdptr = &diagContactorErrorMemory[0];
    diag_locked = 0;
}


STD_RETURN_TYPE_e DIAG_Init(DIAG_DEV_s *diag_dev_pointer, STD_RETURN_TYPE_e bkpramValid) {
    STD_RETURN_TYPE_e retval = E_OK;
    uint8_t c = 0;
    uint8_t id_nr = DIAG_ID_MAX;
    uint32_t tmperr_Check[(DIAG_ID_MAX+31)/32];

    diag_devptr = diag_dev_pointer;

    diag.state = DIAG_STATE_UNINITIALIZED;
    uint16_t checkfail = 0;

    if ((diag_entry_rdptr < &diag_memory[0]) || (diag_entry_rdptr >= &diag_memory[DIAG_FAIL_ENTRY_LENGTH])) {
        checkfail |= 0x01;
    }

    if ((diag_entry_wrptr < &diag_memory[0]) || (diag_entry_wrptr >= &diag_memory[DIAG_FAIL_ENTRY_LENGTH])) {
        checkfail |= 0x02;
    }

    if (bkpramValid == E_NOT_OK) {
        checkfail |= 0x04;
    }

    if ((diagContactorError_entry_rdptr < &diagContactorErrorMemory[0]) ||
            (diagContactorError_entry_rdptr >= &diagContactorErrorMemory[DIAG_FAIL_ENTRY_CONTACTOR_LENGTH])) {
        checkfail |= 0x08;
    }

    if ((diagContactorError_entry_wrptr < &diagContactorErrorMemory[0]) ||
            (diagContactorError_entry_wrptr >= &diagContactorErrorMemory[DIAG_FAIL_ENTRY_CONTACTOR_LENGTH])) {
        checkfail |= 0x10;
    }


    if (checkfail) {
        DIAG_Reset();
    }

    /* Fill lookup table id2ch */
    for (c = 0; c < diag_dev_pointer->nr_of_ch; c++) {
        id_nr = diag_dev_pointer->ch_cfg[c].id;
        if (id_nr < DIAG_ID_MAX) {
            diag.id2ch[id_nr] = c;      /* e.g. diag.id2ch[DIAG_ID_90] = configured channel index */
        } else {
            /* Configuration error -> set retval to E_NOT_OK */
            checkfail |= 0x20;
            retval = E_NOT_OK;
        }
    }

    for (int i = 0; i < (DIAG_ID_MAX+31)/32; i++) {
        tmperr_Check[i] = 0;
    }

    /* Fill enable array err_enableflag */
    for (int i = 0; i < diag_dev_pointer->nr_of_ch; i++) {
        if (diag_dev_pointer->ch_cfg[i].state == DIAG_DISABLED) {
            /* Disable diagnosis entry */
            tmperr_Check[diag_dev_pointer->ch_cfg[i].id/32] |= 1 << (diag_dev_pointer->ch_cfg[i].id % 32);
        }
    }

    /* take over configured error enable masks*/
    for (c = 0; c < (DIAG_ID_MAX+31)/32; c++) {
        diag.err_enableflag[c] = ~tmperr_Check[c];
    }

    diag.state = DIAG_STATE_INITIALIZED;

    if (checkfail) {
        /* make first entry after DIAG_Reset() */
        (void)(DIAG_Handler(DIAG_CH_BKPDIAG_FAILURE, DIAG_EVENT_NOK, checkfail));
    }
    return retval;
}


void DIAG_PrintErrors(void) {
    /* FIXME if read once, rdptr is on writeptr, therefore in the next call the errors aren't
     * printed again. Maybe tmp save rdptr and set again at end of function. But when is the
     * diag memory cleared then? */

    if (diag_entry_rdptr == diag_entry_wrptr) {
        printf("no new entries in DIAG\r\n");
    } else {
        printf("DIAG error entries:\r\n");
        printf("Date and Time:      Error Code/Item   Status     Description\r\n");
    }
    uint8_t c = 0;
    while (diag_entry_rdptr != diag_entry_wrptr && c < 7) {
        if (diag_entry_rdptr >= &diag_memory[DIAG_FAIL_ENTRY_LENGTH]) {
            diag_entry_rdptr = &diag_memory[0];
        }


        printf("%02d.%02d.20%02d - %02d:%02d:%02d     ", diag_entry_rdptr->DD, diag_entry_rdptr->MM, diag_entry_rdptr->YY,
          diag_entry_rdptr->hh, diag_entry_rdptr->mm, diag_entry_rdptr->ss);

        printf("%02d / 0x%08x      ", diag_entry_rdptr->event_id, diag_entry_rdptr->event_id);

        if (diag_entry_rdptr->event == DIAG_EVENT_OK)
            printf("cleared     ");
        else if (diag_entry_rdptr->event == DIAG_EVENT_NOK)
            printf("occurred    ");
        else
            printf("reset       ");


        printf("%s\r\n", diag_devptr->ch_cfg[diag.id2ch[diag_entry_rdptr->event_id]].description);

        diag_entry_rdptr++;
        c++;
    }
    /* More entries in diag buffer */
    if (diag_entry_rdptr != diag_entry_wrptr)
        printf("Please repeat command. Additional error entries in DIAG buffer available!\r\n");
}

#if BUILD_MODULE_ENABLE_CONTACTOR == 1
void DIAG_PrintContactorInfo(void) {
    /* FIXME if read once, rdptr is on writeptr, therefore in the next call the errors aren't
     * printed again. Maybe tmp save rdptr and set again at end of function. But when is the
     * diag memory cleared then? */

    DIAG_CONTACTOR_s diagContactor;

    NVM_Get_contactorcnt(&diagContactor);

    printf("Contactor switching entries:");
    printf("\r\n");

    for (uint8_t i = 0; i < BS_NR_OF_CONTACTORS; i++) {
        printf("Contactor %02d\r\n", i);
        printf("Opening switches: %04x\r\n", diagContactor.cont_switch_opened[i]);
        printf("Closing switches: %04x\r\n", diagContactor.cont_switch_closed[i]);
        printf("Opening switches hard at current: %04x\r\n", diagContactor.cont_switch_opened_hard_at_current[i]);
        printf("\r\n\n");
        printf("\r\n");
    }

    printf("\r\n");
    if (diagContactorError_entry_rdptr == diagContactorError_entry_wrptr) {
        printf("no entries in Contactor");
        printf("\r\n");
    } else {
        printf("Contactor error entries:");
        printf("\r\n");
        printf("Date and Time       Contactor     Opening current");
        printf("\r\n");
    }



    while (diagContactorError_entry_rdptr != diagContactorError_entry_wrptr) {
        if (diagContactorError_entry_rdptr >= &diagContactorErrorMemory[DIAG_FAIL_ENTRY_CONTACTOR_LENGTH]) {
            diagContactorError_entry_rdptr = &diagContactorErrorMemory[0];
        }
        printf("%02d.%02d.%02d - %02d:%02d:%02d     ", diagContactorError_entry_rdptr->DD, diagContactorError_entry_rdptr->MM,
          diagContactorError_entry_rdptr->YY, diagContactorError_entry_rdptr->hh, diagContactorError_entry_rdptr->mm,
          diagContactorError_entry_rdptr->ss);

        printf("%02d        ", diagContactorError_entry_rdptr->contactor);
        printf("%fmA\r\n", (double)diagContactorError_entry_rdptr->openingCurrent);

        diagContactorError_entry_rdptr++;
    }

    /* Reset counter for open errors */
    diagContactor.errcntreported = 0;
}
#endif

/**
 * @brief DIAG_EntryWrite adds an error entry.
 *
 * This function adds an entry to the error buffer.
 * It provides some functionality to prevent duplicates from being logged.
 * Multiple occurring error doesn't get logged anymore after they reached a
 * pre-defined error count.
 *
 * @param  eventID:   ID of entry
 * @param  event:     OK, NOK or RESET
 * @param  item_nr:   item number of event
 *
 * @return 0xFF if event is logged, otherwise 0
 */
static uint8_t DIAG_EntryWrite(uint8_t eventID, DIAG_EVENT_e event, uint32_t item_nr) {
    uint8_t ret_val = 0;
    uint8_t c;
    RTC_Time_s currTime;
    RTC_Date_s currDate;

    if (diag_locked) {
        return ret_val;    /* only locked when clearing the diagnosis memory */
    }

    if (diag.entry_event[eventID] == event) {
        /* same event of same error type already recorded before -> ignore until event toggles */
        return ret_val;
    }
    if ((diag.entry_event[eventID] == DIAG_EVENT_OK) && (event ==  DIAG_EVENT_RESET)) {
        /* do record DIAG_EVENT_RESET-event only if last event was an error (re-initialization) */
        /* meaning: DIAG_EVENT_RESET-event at first time call or after DIAG_EVENT_OK-event will not be recorded */
        return ret_val;
    }

    if (++diag.entry_cnt[eventID] > DIAG_MAX_ENTRIES_OF_ERROR) {
        /* this type of error has been recorded too many times -> ignore to avoid filling buffer with same failurecodes */
        diag.entry_cnt[eventID] = DIAG_MAX_ENTRIES_OF_ERROR;
        return ret_val;
    }

    if (diag_entry_wrptr >= &diag_memory[DIAG_FAIL_ENTRY_LENGTH]) {
        diag_entry_wrptr = &diag_memory[0];
    }

    /* now record failurecode */
    ret_val = 0xFF;
    RTC_getTime(&currTime);
    RTC_getDate(&currDate);

    diag_entry_wrptr->YY = currDate.Year;
    diag_entry_wrptr->MM = currDate.Month;
    diag_entry_wrptr->DD = currDate.Date;
    diag_entry_wrptr->hh = currTime.Hours;
    diag_entry_wrptr->mm = currTime.Minutes;
    diag_entry_wrptr->ss = currTime.Seconds;

    diag_entry_wrptr->event_id = eventID;        /* Error Code 0... 4x32-1 */
    diag_entry_wrptr->item    = item_nr;         /*  */
    diag_entry_wrptr->event   = (uint8_t)event;  /* DIAG_EVENT_OK, DIAG_EVENT_NOK, DIAG_EVENT_RESET */

    diag_entry_wrptr->Val0 = diag_fc.Val0;
    diag_entry_wrptr->Val1 = diag_fc.Val1;
    diag_entry_wrptr->Val2 = diag_fc.Val2;
    diag_entry_wrptr->Val3 = diag_fc.Val3;
    ++diag_entry_wrptr;

    ++diag.errcntreported;         /* counts of (new) diagnosis entry records which is still not been read by external Tool */
                                   /* which will reset this value to 0 after having read all new entries which means <acknowledged by user> */
    ++diag.errcnttotal;            /* total counts of diagnosis entry records */

    diag.entry_event[eventID] = event;
    c = (uint8_t) diag.errcntreported;

    fprintf(stderr, "New Error entry! (%03d): Error Code/Item %03d/0x%08x ", c, eventID, (unsigned int)item_nr);

    fprintf(stderr, "%s", diag_devptr->ch_cfg[diag.id2ch[eventID]].description);

    if (event == DIAG_EVENT_OK) {
        fprintf(stderr, " cleared\r\n");
    } else if (event == DIAG_EVENT_NOK) {
        fprintf(stderr, " occured\r\n");
    } else {
        /* DIAG_EVENT_RESET */
        fprintf(stderr, " reset\r\n");
    }

    return ret_val;
}

DIAG_RETURNTYPE_e DIAG_Handler(DIAG_CH_ID_e diag_ch_id, DIAG_EVENT_e event, uint32_t item_nr) {
    uint32_t ret_val = DIAG_HANDLER_RETURN_UNKNOWN;
    uint32_t *u32ptr_errCodemsk, *u32ptr_warnCodemsk;
    uint16_t  *u16ptr_threshcounter;
    uint16_t cfg_threshold;
    uint16_t err_enable_idx;
    uint32_t err_enable_bitmask;

    DIAG_TYPE_RECORDING_e recordingenabled;

    if (diag.state == DIAG_STATE_UNINITIALIZED) {
        return (DIAG_HANDLER_RETURN_NOT_READY);
    }

    if (diag_ch_id >= DIAG_ID_MAX) {
        return (DIAG_HANDLER_RETURN_WRONG_ID);
    }

    if ((diag_ch_id == DIAG_CH_CONTACTOR_DAMAGED) || (diag_ch_id == DIAG_CH_CONTACTOR_OPENING) ||
            (diag_ch_id == DIAG_CH_CONTACTOR_CLOSING)) {
        return (DIAG_HANDLER_INVALID_TYPE);
    }
    err_enable_idx      = diag_ch_id/32;        /* array index of diag.err_enableflag[..] */
    err_enable_bitmask  = 1 << (diag_ch_id%32);   /* bit number (mask) of diag.err_enableflag[idx] */


    u32ptr_errCodemsk   = &diag.errflag[err_enable_idx];
    u32ptr_warnCodemsk  = &diag.warnflag[err_enable_idx];
    u16ptr_threshcounter = &diag.occurrence_cnt[diag_ch_id];
    cfg_threshold       = diag_devptr->ch_cfg[diag.id2ch[diag_ch_id]].thresholds;
    recordingenabled    = diag_devptr->ch_cfg[diag.id2ch[diag_ch_id]].enablerecording;

    if (event == DIAG_EVENT_OK) {
        if (diag.err_enableflag[err_enable_idx] & err_enable_bitmask) {
            /* if (((*u16ptr_threshcounter) == 0) && (*u32ptr_errCodemsk == 0)) */
            if (((*u16ptr_threshcounter) == 0)) {
                /* everything ok, nothing to be handled */
            } else if ((*u16ptr_threshcounter) > 1) {
                (*u16ptr_threshcounter)--;   /* Error did not occur, decrement Error-Counter */
            } else if ((*u16ptr_threshcounter) == 1) {
                /* else if ((*u16ptr_threshcounter) <= 1) */
                /* Error did not occur, now decrement to zero and clear Error- or Warning-Flag and make recording if enabled */
                *u32ptr_errCodemsk &= ~err_enable_bitmask;      /* ERROR:   clear corresponding bit in errflag[idx] */
                *u32ptr_warnCodemsk &= ~err_enable_bitmask;     /* WARNING: clear corresponding bit in warnflag[idx] */
                (*u16ptr_threshcounter) = 0;
                /* Make entry in error-memory (error disappeared) */
                if (recordingenabled == DIAG_RECORDING_ENABLED)
                    DIAG_EntryWrite(diag_ch_id, event, item_nr);

                /* Call callback function and reset error */
                diag_ch_cfg[diag.id2ch[diag_ch_id]].callbackfunc(diag_ch_id, DIAG_EVENT_RESET);
            }
        }
        ret_val = DIAG_HANDLER_RETURN_OK; /* Function does not return an error-message! */
    } else if (event == DIAG_EVENT_NOK) {
        if (diag.err_enableflag[err_enable_idx] & err_enable_bitmask) {
            if ((*u16ptr_threshcounter) < cfg_threshold) {
                (*u16ptr_threshcounter)++;   /* error-threshold not exceeded yet, increment Error-Counter */
                ret_val = DIAG_HANDLER_RETURN_OK; /* Function does not return an error-message! */
            } else if ((*u16ptr_threshcounter) == cfg_threshold) {
                /* Error occured AND error-threshold exceeded */
                (*u16ptr_threshcounter)++;
                *u32ptr_errCodemsk |= err_enable_bitmask;      /* ERROR:   set corresponding bit in errflag[idx] */
                *u32ptr_warnCodemsk &= ~err_enable_bitmask;    /* WARNING: clear corresponding bit in warnflag[idx] */

                /* Make entry in error-memory (error occurred) */
                if (recordingenabled == DIAG_RECORDING_ENABLED) {
                    DIAG_EntryWrite(diag_ch_id, event, item_nr);
                }

                /* Call callback function and set error */
                diag_ch_cfg[diag.id2ch[diag_ch_id]].callbackfunc(diag_ch_id, DIAG_EVENT_NOK);
                /* Function returns an error-message! */
                ret_val = DIAG_HANDLER_RETURN_ERR_OCCURRED;
            } else if (((*u16ptr_threshcounter) > cfg_threshold)) {
                /* error-threshold already exceeded, nothing to be handled */
                ret_val = DIAG_HANDLER_RETURN_ERR_OCCURRED;
            }
        } else {
            /* Error occured BUT NOT enabled by mask */
            *u32ptr_errCodemsk &= ~err_enable_bitmask;        /* ERROR:   clear corresponding bit in errflag[idx] */
            *u32ptr_warnCodemsk |= err_enable_bitmask;        /* WARNING: set corresponding bit in warnflag[idx] */
            ret_val = DIAG_HANDLER_RETURN_WARNING_OCCURRED;   /* Function returns an error-message! */
        }
    } else if (event == DIAG_EVENT_RESET) {
        if (diag.err_enableflag[err_enable_idx] & err_enable_bitmask) {
            /* clear counter, Error-, Warning-Flag and make recording if enabled */
            *u32ptr_errCodemsk &= ~err_enable_bitmask;      /* ERROR:   clear corresponding bit in errflag[idx] */
            *u32ptr_warnCodemsk &= ~err_enable_bitmask;     /* WARNING: clear corresponding bit in warnflag[idx] */
            (*u16ptr_threshcounter) = 0;
            if (recordingenabled == DIAG_RECORDING_ENABLED)
                DIAG_EntryWrite(diag_ch_id, event, item_nr);      /* Make entry in error-memory (error disappeared) if error was recorded before */
        }
        ret_val = DIAG_HANDLER_RETURN_OK; /* Function does not return an error-message! */
    }


    return (ret_val);
}


STD_RETURN_TYPE_e DIAG_checkEvent(STD_RETURN_TYPE_e cond,
                                  DIAG_CH_ID_e diag_ch_id,
                                  uint32_t item_nr) {
    STD_RETURN_TYPE_e retVal = E_NOT_OK;

    if (cond == E_OK) {
        DIAG_Handler(diag_ch_id, DIAG_EVENT_OK, item_nr);
    } else {
        DIAG_Handler(diag_ch_id, DIAG_EVENT_NOK, item_nr);
    }

    return retVal;
}

#if BUILD_MODULE_ENABLE_CONTACTOR == 1
/**
 * @brief DIAG_ContHandler provides generic contactor switching handling, based on configuration.
 *
 * This function does all the handling based on the user defined configuration.
 * It needs to get called in every occurrence where a contactor is either opened or closed.
 * According to its return value further treatment is left to the calling module itself.
 *
 * @param eventID     switching event that occurred
 * @param cont_nr     contactor that switches
 * @param openingCur  current flow during contactor opening
 *
 * @return  DIAG_HANDLER_RETURN_ERR_OCCURRED if hard opening threshold is reached,\n
 *          DIAG_HANDLER_RETURN_OK if normal opening/closing of contactor occurred or threshold not reached,\n
 *          DIAG_HANDLER_INVALID_TYPE if called with wrong eventID,\n
 *          DIAG_HANDLER_INVALID_DATA if no opening current is passed in case of hard opening
 */
DIAG_RETURNTYPE_e DIAG_ContHandler(DIAG_CH_ID_e eventID, uint32_t cont_nr, float* openingCur) {
    DIAG_RETURNTYPE_e retVal = DIAG_HANDLER_RETURN_UNKNOWN;
    uint8_t updateNVRAM = 0;

    if (diag_locked)
        return retVal;    /*  only locked when clearing the diagnosis memory */
    DIAG_CONTACTOR_s diagContactor;
    NVM_Get_contactorcnt(&diagContactor);
    if (eventID == DIAG_CH_CONTACTOR_OPENING) {
        diagContactor.cont_switch_opened[cont_nr]++;
        retVal = DIAG_HANDLER_RETURN_OK;
    } else if (eventID == DIAG_CH_CONTACTOR_CLOSING) {
        diagContactor.cont_switch_closed[cont_nr]++;
        retVal = DIAG_HANDLER_RETURN_OK;
    } else if (eventID == DIAG_CH_CONTACTOR_DAMAGED) {
        if (NULL_PTR == openingCur) {
            retVal = DIAG_HANDLER_INVALID_DATA;
        } else {
            RTC_Time_s currTime;
            RTC_Date_s currDate;

            updateNVRAM = 1;

            diagContactor.cont_switch_opened_hard_at_current[cont_nr]++;

            if (diagContactor.cont_switch_opened_hard_at_current[cont_nr] >= CONT_NUMBER_OF_BAD_COUNTINGS)
                retVal = DIAG_HANDLER_RETURN_ERR_OCCURRED;
            else
                retVal = DIAG_HANDLER_RETURN_OK;

            if (diagContactorError_entry_wrptr >= &diagContactorErrorMemory[DIAG_FAIL_ENTRY_CONTACTOR_LENGTH]) {
                diagContactorError_entry_wrptr = &diagContactorErrorMemory[0];
            }

            /* Write error entry */

            /* Get time and date */
            RTC_getTime(&currTime);
            RTC_getDate(&currDate);

            /* Set time and date */
            diagContactorError_entry_wrptr->YY = currDate.Year;
            diagContactorError_entry_wrptr->MM = currDate.Month;
            diagContactorError_entry_wrptr->DD = currDate.Date;
            diagContactorError_entry_wrptr->hh = currTime.Hours;
            diagContactorError_entry_wrptr->mm = currTime.Minutes;
            diagContactorError_entry_wrptr->ss = currTime.Seconds;

            diagContactorError_entry_wrptr->contactor = (uint8_t)cont_nr;
            diagContactorError_entry_wrptr->openingCurrent =  *openingCur;

            diagContactorError_entry_wrptr++;

            printf("new Contactor error entry! currently %02d error entrys\r\n", diagContactor.errcntreported);
        }
    } else {
        retVal = DIAG_HANDLER_INVALID_TYPE;
    }
    if ((DIAG_HANDLER_RETURN_ERR_OCCURRED == retVal) || (DIAG_HANDLER_RETURN_OK == retVal)) {
        /* Write new value in nvram buffer */
        NVM_Set_contactorcnt(&diagContactor);
        if (updateNVRAM == 1) {
            /* Update NVRAM only if contactor opened hard at current */
            NVRAM_setWriteRequest(NVRAM_BLOCK_ID_CONT_COUNTER);
        }
    }
    return retVal;
}
#endif

/**
 * @brief overall system monitoring
 *
 * checks notifications (state and timestamps) of all system-relevant tasks or functions
 * all checks should be customized corresponding to its timing and state requirements
 */
void DIAG_SysMon(void) {
    DIAG_SYSMON_MODULE_ID_e module_id;
    uint32_t localTimer = OS_getOSSysTick();
    if (diagsysmonTimestamp == localTimer) {
        return;
    }
    diagsysmonTimestamp = localTimer;

    /* check modules */
    for (module_id = 0; module_id < DIAG_SYSMON_MODULE_ID_MAX; module_id++) {
        if ((diag_sysmon_ch_cfg[module_id].type == DIAG_SYSMON_CYCLICTASK) &&
           (diag_sysmon_ch_cfg[module_id].state == DIAG_ENABLED)) {
            if (diag_sysmon[module_id].timestamp -  diag_sysmon_last[module_id].timestamp <  1) {
                /* module not running */
                if (++diag_sysmon_cnt[module_id] >= diag_sysmon_ch_cfg[module_id].threshold) {
                    /* @todo configurable timeouts ! */
                    if (diag_sysmon_ch_cfg[module_id].enablerecording == DIAG_RECORDING_ENABLED) {
                        DIAG_Handler(DIAG_CH_SYSTEMMONITORING_TIMEOUT, DIAG_EVENT_NOK, module_id);
                    }
#if BUILD_MODULE_ENABLE_CONTACTOR == 1
                    if (diag_sysmon_ch_cfg[module_id].handlingtype == DIAG_SYSMON_HANDLING_SWITCHOFFCONTACTOR) {
                        /* system not working trustfully, switch off contactors! */
                        CONT_SwitchAllContactorsOff();
                    }
#endif
                    diag_sysmon_cnt[module_id] = 0;

                    /* @todo: call callback function if error occurred */
                    diag_sysmon_ch_cfg[module_id].callbackfunc(module_id);
                }
            } else {
                /* module running */
                diag_sysmon_cnt[module_id] = 0;

                if (diag_sysmon[module_id].state != 0) {
                    /* check state of module */
                    /* @todo: do something now! */
                }
            }
        } else {
            /* if Sysmon type != cyclic task (not used at the moment) */
        }
        diag_sysmon_last[module_id] = diag_sysmon[module_id];      /*save last values for next check*/
    }
}


void DIAG_SysMonNotify(DIAG_SYSMON_MODULE_ID_e module_id, uint32_t state) {
    if (module_id < DIAG_SYSMON_MODULE_ID_MAX) {
        taskENTER_CRITICAL();
        diag_sysmon[module_id].timestamp = OS_getOSSysTick();
        diag_sysmon[module_id].state = state;
        taskEXIT_CRITICAL();
    }
}


void DIAG_configASSERT(void) {
#ifdef STM32F4
    uint32_t lr_register;
    uint32_t sp_register;
    __ASM volatile("mov %0, r14" : "=r" (lr_register));
    __ASM volatile("mov %0, r13" : "=r" (sp_register));

    lr_register = lr_register & 0xFFFFFFFE;     /* mask out LSB as this only is indicates thumb instruction */
    diag_fc.Val0 = sp_register;                 /* actual stack pointer */
    diag_fc.Val1 = lr_register;                 /* report instruction address where this function has been called */
    diag_fc.Val2 = *(uint32_t*)(sp_register + 0x1C);        /* return address of callers context (one above caller) */
    DIAG_Handler(DIAG_CH_CONFIGASSERT, DIAG_EVENT_NOK, 0);
#endif

    while (1) {
        /* TODO: explain why infinite loop */
    }
}

diag.h

/**
 *
 * @copyright &copy; 2010 - 2020, 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    diag.h
 * @author  foxBMS Team
 * @date    09.11.2015 (date of creation)
 * @ingroup ENGINE
 * @prefix  DIAG
 *
 * @brief   Diagnosis driver header
 *
 */

#ifndef DIAG_H_
#define DIAG_H_

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

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

/** diagnosis handler return types */
typedef enum {
    DIAG_HANDLER_RETURN_OK,               /*!<  error not occurred or occurred but threshold not reached */
    DIAG_HANDLER_RETURN_ERR_OCCURRED,     /*!<  error occurred and enabled */
    DIAG_HANDLER_RETURN_WARNING_OCCURRED, /*!<  warning occurred (error occurred but not enabled) */
    DIAG_HANDLER_RETURN_WRONG_ID,         /*!<  wrong diagnosis id */
    DIAG_HANDLER_RETURN_UNKNOWN,          /*!<  unknown return type */
    DIAG_HANDLER_INVALID_TYPE,            /*!<  invalid diagnosis type, error in configuration */
    DIAG_HANDLER_INVALID_DATA,            /*!<  invalid data, dependent of the diagHandler */
    DIAG_HANDLER_RETURN_NOT_READY,        /*!<  diagnosis handler not ready */
} DIAG_RETURNTYPE_e;

/**
 * state of diagnosis module
 */
typedef enum {
    DIAG_STATE_UNINITIALIZED,   /*!< diagnosis module not initialized              */
    DIAG_STATE_INITIALIZED,   /*!< diagnosis module initialized (ready for use)  */
} DIAG_STATE_e;

/**
 * structure of failure entry record
 */
typedef struct {
    uint8_t YY;
    uint8_t MM;
    uint8_t DD;
    uint8_t hh;
    uint8_t mm;
    uint8_t ss;
    DIAG_EVENT_e event;
    DIAG_CH_ID_e event_id;
    uint32_t item;
    uint32_t dummy1;
    uint32_t Val0;
    uint32_t Val1;
    uint32_t Val2;
    uint32_t Val3;
} DIAG_ERROR_ENTRY_s;

/* FIXME maybe short explanation why there is separate Error entry for contactor in a few words */
/**
 * structure of failure code entry record for contactor
 */
typedef struct {
    uint8_t YY;
    uint8_t MM;
    uint8_t DD;
    uint8_t hh;
    uint8_t mm;
    uint8_t ss;
/*     DIAG_EVENT_e event; */
/*     DIAG_CH_ID_e event_id; */
    uint8_t contactor;
    float openingCurrent;
} DIAG_CONTACTOR_ERROR_ENTRY_s;

/**
 * structure contains number of switching actions for each contactor
 */
typedef struct {
    uint16_t cont_switch_closed[BS_NR_OF_CONTACTORS];
    uint16_t cont_switch_opened[BS_NR_OF_CONTACTORS];
    uint16_t cont_switch_opened_hard_at_current[BS_NR_OF_CONTACTORS];
    uint16_t errcntreported;          /*!<  number of hard switches occurred since last call of DIAG_PrintContactorInfo */
    /*            sizeof(struct) - (memory of contactors) - errcntreported - chksum */
    uint8_t reserved[0x40 - (3*BS_NR_OF_CONTACTORS*2) - 2 - 4];            /*!< reserved for future use */
} DIAG_CONTACTOR_s;

/* FIXME doxygen comment missing */
typedef struct {
    uint32_t Val0;
    uint32_t Val1;
    uint32_t Val2;
    uint32_t Val3;
} DIAG_FAILURECODE_s;

typedef struct {
    DIAG_STATE_e state;                            /*!< actual state of diagnosis module */
    uint16_t errcnttotal;                          /*!< total counts of diagnosis entry records*/
    uint16_t errcntreported;                       /*!< reported error counts to external tool*/
    uint32_t entry_event[DIAG_ID_MAX];             /*!< last detected entry event*/
    uint8_t entry_cnt[DIAG_ID_MAX];                /*!< reported event counter used for limitation  */
    uint16_t occurrence_cnt[DIAG_ID_MAX];          /*!< */
    uint8_t id2ch[DIAG_ID_MAX];                    /*!< diagnosis-id to configuration channel selector*/
    uint8_t nr_of_ch;                              /*!< number of configured channels*/
    uint32_t errflag[(DIAG_ID_MAX+31)/32];         /*!< detected error   flags (bit_nr = diag_id) */
    uint32_t warnflag[(DIAG_ID_MAX+31)/32];        /*!< detected warning flags (bit_nr = diag_id) */
    uint32_t err_enableflag[(DIAG_ID_MAX+31)/32];   /*!< enabled error flags (bit_nr = diag_id)    */
} DIAG_s;

/*================== Constant and Variable Definitions ====================*/
/* FIXME doxygen comment missing */
extern DIAG_FAILURECODE_s diag_fc;

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

/**
 * @brief   DIAG_Handler provides generic error handling, based on diagnosis group.
   @ingroup API_DIAG

 * This function calls the handler functions depending on the diagnosis group of call.
 * It needs to get called in every function which wants to apply some kind of diagnosis handling.
 * According to its return value further treatment is either left to the calling module itself, or
 * can be done in the callback function defined in diag_cfg.c
 *
 *
 * @param   diag_ch_id: event ID of the event that has occurred
 * @param   event:      event that occurred (OK, NOK, RESET)
 * @param   item_nr:    item nr of event, to distinguish between different calling locations of the event
 *
 * @return  DIAG_HANDLER_RETURN_UNKNOWN if invalid DIAG_TYPE_e, otherwise return value of
 *          DIAG_GeneralHandler or DIAG_ContHandler
 */
extern DIAG_RETURNTYPE_e DIAG_Handler(DIAG_CH_ID_e diag_ch_id,
                                      DIAG_EVENT_e event,
                                      uint32_t item_nr);


/**
 * @brief   DIAG_checkEvent provides a simple interface to check an event for E_OK
 *
 * @details DIAG_checkEvent is a wrapper function for DIAG_Handler. In simple cases where a return value
 *          that is not E_OK (or a 0 casted to E_OK) should increase the error counter in a diagnosis
 *          channel, this function should be used instead of directly calling the DIAG_Handler().
 *
 * @param   cond:       condition
 * @param   diag_ch_id: event ID of the event that has occurred
 * @param   item_nr:    item nr of event, to distinguish between different calling locations of the event
 *
 * @return  E_OK if ok, E_NOK if not ok
 */
extern STD_RETURN_TYPE_e DIAG_checkEvent(STD_RETURN_TYPE_e cond, DIAG_CH_ID_e diag_ch_id, uint32_t item_nr);


/**
 * @brief   DIAG_Init initializes all needed structures/buffers.
 *
 * This function provides initialization of the diagnose module.
 * In case of miss behaviour it calls Reset and adds an entry into database
 * to ensure data validity/report back malfunction
 *
 * @param   diag_dev_pointer
 */
extern STD_RETURN_TYPE_e DIAG_Init(DIAG_DEV_s *diag_dev_pointer, STD_RETURN_TYPE_e bkpramValid);

#if BUILD_MODULE_ENABLE_CONTACTOR == 1
DIAG_RETURNTYPE_e DIAG_ContHandler(DIAG_CH_ID_e eventID, uint32_t cont_nr, float* openingCur);
#endif
/**
 * @brief   trap of configuration errors derived by FreeRTOS configASSERT
 */
extern void DIAG_configASSERT(void);

/**
 * @brief   overall system monitoring
 *
 * checks notifications (state and timestamps) of all system-relevant tasks or functions
 * all checks should be customized corresponding to its timing and state requirements
 */
extern void DIAG_SysMon(void);

/**
 * @brief   DIAG_PrintErrors prints contents of the error buffer on user request.
 *
 * This function prints out complete error buffer using the UART interface.
 */
extern void DIAG_PrintErrors(void);

#if BUILD_MODULE_ENABLE_CONTACTOR == 1
/**
 * @brief   DIAG_PrintContactorInfo prints contents of the contactor switching buffer on user request.
 *
 * This function prints out complete contactor information using the UART interface.
 */
extern void DIAG_PrintContactorInfo(void);
#endif


/**
 * @brief   DIAG_SysMonNotify has to be called in every function using the system monitoring.
 *
 * @param   module_id:  module id to notify system monitoring
 * @param   state:      state of module
 */
extern void DIAG_SysMonNotify(DIAG_SYSMON_MODULE_ID_e module_id, uint32_t state);

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

#endif /* DIAG_H_ */

diag_cfg.c (primary)

/**
 *
 * @copyright &copy; 2010 - 2020, 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    diag_cfg.c
 * @author  foxBMS Team
 * @date    09.11.2015 (date of creation)
 * @ingroup ENGINE_CONF
 * @prefix  DIAG
 *
 * @brief   Diagnostic module configuration
 *
 * The configuration of the different diagnosis events defined in diag_cfg.h is set in the array
 * diag_ch_cfg[], e.g. initialization errors or runtime errors.
 *
 * Every entry of the diag_ch_cfg[] array consists of
 *  - name of the diagnosis event (defined in diag_cfg.h)
 *  - type of diagnosis event
 *  - diagnosis sensitivity (after how many occurrences event is counted as error)
 *  - enabling of the recording for diagnosis event
 *  - enabling of the diagnosis event
 *  - callback function for diagnosis event if wished, otherwise dummyfu
 *
 * The system monitoring configuration defined in diag_cfg.h is set in the array
 * diag_sysmon_ch_cfg[]. The system monitoring is at the moment only used for
 * supervising the cyclic/periodic tasks.
 *
 * Every entry of the diag_sysmon_ch_cfg[] consists of
 *  - enum of monitored object
 *  - type of monitored object (at the moment only DIAG_SYSMON_CYCLICTASK is supported)
 *  - maximum delay in [ms] in which the object needs to call the DIAG_SysMonNotify function defined in diag.c
 *  - enabling of the recording for system monitoring
 *  - enabling of the system monitoring for the monitored object
 *  - callback function if system monitoring notices an error if wished, otherwise dummyfu2
 */

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

#include "database.h"
#include "rtc.h"

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

/*================== Static Constant and Variable Definitions ===============*/
static DATA_BLOCK_ERRORSTATE_s error_flags = { 0 };
static DATA_BLOCK_MOL_FLAG_s mol_flags = { 0 };
static DATA_BLOCK_RSL_FLAG_s rsl_flags = { 0 };
static DATA_BLOCK_MSL_FLAG_s msl_flags = { 0 };

/*================== Static Function Prototypes =============================*/
/* dummy functions */
static void dummyfu(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event);
static void dummyfu2(DIAG_SYSMON_MODULE_ID_e ch_id);

/* functions for SOA related events */
static void DIAG_overvoltage(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event);
static void DIAG_undervoltage(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event);
static void DIAG_overtemperature_charge(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event);
static void DIAG_overtemperature_discharge(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event);
static void DIAG_undertemperature_charge(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event);
static void DIAG_undertemperature_discharge(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event);
static void DIAG_overcurrent_charge(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event);
static void DIAG_overcurrent_discharge(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event);

/* functions for system related events */
static void DIAG_error_cantiming(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event);
static void DIAG_error_ltc(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event);
static void DIAG_error_cancurrentsensor(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event);
static void DIAG_cont_feedback(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event);
static void DIAG_error_fuseState(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event);
static void DIAG_error_interlock(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event);
static void DIAG_error_insulation(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event);
static void DIAG_error_openWire(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event);
static void DIAG_error_deep_discharge_detected(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event);
static void DIAG_error_MCUdieTemperature(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event);
static void DIAG_error_coinCellVoltage(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event);

/* functions for plausibility related events */
static void DIAG_error_plausibility_check(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event);

/*================== Extern Constant and Variable Definitions ===============*/
/**
 * Enable and Disable of Error Checks for Testing Purposes
 *
 * Each Bit enables or disables the diagnosis (checking of) the corresponding failure code
 * FIXME struct isn't used anywhere in the code at the moment.
 * FIXME delete if not needed
*/
DIAG_CODE_s diag_mask = {
        .GENERALmsk = 0xFFFFFFFF,
        .CELLMONmsk = 0xFFFFFFFF,
        .COMmsk = 0xFFFFFFFF,
        .ADCmsk = 0xFFFFFFFF,
};

DIAG_CH_CFG_s  diag_ch_cfg[] = {
    /* OS-Framework and startup events */
    {DIAG_CH_FLASHCHECKSUM,                             "FLASHCHECKSUM",                        DIAG_ERROR_SENSITIVITY_HIGH,              DIAG_RECORDING_ENABLED, DIAG_ENABLED, dummyfu},
    {DIAG_CH_BKPDIAG_FAILURE,                           "BKPDIAG",                              DIAG_ERROR_SENSITIVITY_HIGH,              DIAG_RECORDING_ENABLED, DIAG_ENABLED, dummyfu},
    {DIAG_CH_WATCHDOGRESET_FAILURE,                     "WATCHDOGRESET",                        DIAG_ERROR_SENSITIVITY_HIGH,              DIAG_RECORDING_ENABLED, DIAG_ENABLED, dummyfu},
    {DIAG_CH_POSTOSINIT_FAILURE,                        "POSTOSINIT",                           DIAG_ERROR_SENSITIVITY_HIGH,              DIAG_RECORDING_ENABLED, DIAG_ENABLED, dummyfu},
    {DIAG_CH_CALIB_EEPR_FAILURE,                        "CALIB_EEPR",                           DIAG_ERROR_SENSITIVITY_HIGH,              DIAG_RECORDING_ENABLED, DIAG_ENABLED, dummyfu},
    {DIAG_CH_CAN_INIT_FAILURE,                          "CAN_INIT",                             DIAG_ERROR_SENSITIVITY_HIGH,              DIAG_RECORDING_ENABLED, DIAG_ENABLED, dummyfu},
    {DIAG_CH_VIC_INIT_FAILURE,                          "VIC_INIT",                             DIAG_ERROR_SENSITIVITY_HIGH,              DIAG_RECORDING_ENABLED, DIAG_ENABLED, dummyfu},

    /* HW-/SW-Runtime events */
    {DIAG_CH_DIV_BY_ZERO_FAILURE,                       "DIV_BY_ZERO",                          DIAG_ERROR_SENSITIVITY_HIGH,              DIAG_RECORDING_ENABLED, DIAG_ENABLED, dummyfu},
    {DIAG_CH_UNDEF_INSTRUCTION_FAILURE,                 "UNDEF_INSTRUCTION",                    DIAG_ERROR_SENSITIVITY_HIGH,              DIAG_RECORDING_ENABLED, DIAG_ENABLED, dummyfu},
    {DIAG_CH_DATA_BUS_FAILURE,                          "DATA_BUS_FAILURE",                     DIAG_ERROR_SENSITIVITY_HIGH,              DIAG_RECORDING_ENABLED, DIAG_ENABLED, dummyfu},
    {DIAG_CH_INSTRUCTION_BUS_FAILURE,                   "INSTRUCTION_BUS",                      DIAG_ERROR_SENSITIVITY_HIGH,              DIAG_RECORDING_ENABLED, DIAG_ENABLED, dummyfu},
    {DIAG_CH_HARDFAULT_NOTHANDLED,                      "HARDFAULT_NOTHANDLED",                 DIAG_ERROR_SENSITIVITY_HIGH,              DIAG_RECORDING_ENABLED, DIAG_ENABLED, dummyfu},

    {DIAG_CH_CONFIGASSERT,                              "CONFIGASSERT",                         DIAG_ERROR_SENSITIVITY_HIGH,              DIAG_RECORDING_ENABLED, DIAG_ENABLED, dummyfu},
    {DIAG_CH_SYSTEMMONITORING_TIMEOUT,                  "SYSTEMMONITORING_TIMEOUT",             DIAG_ERROR_SENSITIVITY_HIGH,              DIAG_RECORDING_ENABLED, DIAG_ENABLED, dummyfu},


    /* Measurement events */
    {DIAG_CH_CANS_MAX_VALUE_VIOLATE,                    "CANS_MAX_VALUE_VIOLATE",               DIAG_ERROR_SENSITIVITY_HIGH,              DIAG_RECORDING_ENABLED, DIAG_ENABLED, dummyfu},
    {DIAG_CH_CANS_MIN_VALUE_VIOLATE,                    "CANS_MIN_VALUE_VIOLATE",               DIAG_ERROR_SENSITIVITY_HIGH,              DIAG_RECORDING_ENABLED, DIAG_ENABLED, dummyfu},
    {DIAG_CH_CANS_CAN_MOD_FAILURE,                      "CANS_CAN_MOD_FAILURE",                 DIAG_ERROR_SENSITIVITY_HIGH,              DIAG_RECORDING_ENABLED, DIAG_ENABLED, dummyfu},

#if BUILD_MODULE_ENABLE_ISOGUARD == 1
    {DIAG_CH_ISOMETER_TIM_ERROR,                        "ISOMETER_TIM_ERROR",                   DIAG_ERROR_SENSITIVITY_MID,               DIAG_RECORDING_ENABLED, DIAG_ENABLED, dummyfu},
    {DIAG_CH_ISOMETER_GROUNDERROR,                      "ISOMETER_GROUNDERROR",                 DIAG_ERROR_SENSITIVITY_HIGH,              DIAG_RECORDING_ENABLED, DIAG_ENABLED, dummyfu},
    {DIAG_CH_ISOMETER_ERROR,                            "ISOMETER_ERROR",                       DIAG_ERROR_SENSITIVITY_MID,               DIAG_RECORDING_ENABLED, DIAG_ENABLED, dummyfu},
    {DIAG_CH_ISOMETER_MEAS_INVALID,                     "ISOMETER_MEAS_INVALID",                DIAG_ERROR_SENSITIVITY_HIGH,              DIAG_RECORDING_ENABLED, DIAG_ENABLED, dummyfu},
    {DIAG_CH_INSULATION_ERROR,                          "INSULATION_ERROR",                     DIAG_ERROR_INSULATION_SENSITIVITY,        DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_error_insulation},
#else
    {DIAG_CH_ISOMETER_TIM_ERROR,                        "ISOMETER_TIM_ERROR",                   DIAG_ERROR_SENSITIVITY_MID,               DIAG_RECORDING_DISABLED, DIAG_DISABLED, dummyfu},
    {DIAG_CH_ISOMETER_GROUNDERROR,                      "ISOMETER_GROUNDERROR",                 DIAG_ERROR_SENSITIVITY_HIGH,              DIAG_RECORDING_DISABLED, DIAG_DISABLED, dummyfu},
    {DIAG_CH_ISOMETER_ERROR,                            "ISOMETER_ERROR",                       DIAG_ERROR_SENSITIVITY_MID,               DIAG_RECORDING_DISABLED, DIAG_DISABLED, dummyfu},
    {DIAG_CH_ISOMETER_MEAS_INVALID,                     "ISOMETER_MEAS_INVALID",                DIAG_ERROR_SENSITIVITY_HIGH,              DIAG_RECORDING_DISABLED, DIAG_DISABLED, dummyfu},
    {DIAG_CH_INSULATION_ERROR,                          "INSULATION_ERROR",                     DIAG_ERROR_INSULATION_SENSITIVITY,        DIAG_RECORDING_DISABLED, DIAG_DISABLED, dummyfu},
#endif

    /* Under and over temperature, voltage and current at cell level */
    {DIAG_CH_CELLVOLTAGE_OVERVOLTAGE_MSL,             "CELLVOLT_OVERVOLT_MSL",            DIAG_ERROR_VOLTAGE_SENSITIVITY_MSL,          DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_overvoltage},
    {DIAG_CH_CELLVOLTAGE_OVERVOLTAGE_RSL,             "CELLVOLT_OVERVOLT_RSL",            DIAG_ERROR_VOLTAGE_SENSITIVITY_RSL,          DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_overvoltage},
    {DIAG_CH_CELLVOLTAGE_OVERVOLTAGE_MOL,           "CELLVOLT_OVERVOLT_MOL",              DIAG_ERROR_VOLTAGE_SENSITIVITY_MOL,          DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_overvoltage},

    {DIAG_CH_CELLVOLTAGE_UNDERVOLTAGE_MSL,            "CELLVOLT_UNDERVOLT_MSL",           DIAG_ERROR_VOLTAGE_SENSITIVITY_MSL,          DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_undervoltage},
    {DIAG_CH_CELLVOLTAGE_UNDERVOLTAGE_RSL,            "CELLVOLT_UNDERVOLT_RSL",           DIAG_ERROR_VOLTAGE_SENSITIVITY_RSL,          DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_undervoltage},
    {DIAG_CH_CELLVOLTAGE_UNDERVOLTAGE_MOL,          "CELLVOLT_UNDERVOLT_MOL",             DIAG_ERROR_VOLTAGE_SENSITIVITY_MOL,          DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_undervoltage},

    {DIAG_CH_TEMP_OVERTEMPERATURE_CHARGE_MSL,         "OVERTEMP_CHARGE_MSL",             DIAG_ERROR_TEMPERATURE_SENSITIVITY_MSL,       DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_overtemperature_charge},
    {DIAG_CH_TEMP_OVERTEMPERATURE_CHARGE_RSL,         "OVERTEMP_CHARGE_RSL",             DIAG_ERROR_TEMPERATURE_SENSITIVITY_RSL,       DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_overtemperature_charge},
    {DIAG_CH_TEMP_OVERTEMPERATURE_CHARGE_MOL,       "OVERTEMP_CHARGE_MOL",               DIAG_ERROR_TEMPERATURE_SENSITIVITY_MOL,       DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_overtemperature_charge},

    {DIAG_CH_TEMP_OVERTEMPERATURE_DISCHARGE_MSL,      "OVERTEMP_DISCHARGE_MSL",          DIAG_ERROR_TEMPERATURE_SENSITIVITY_MSL,       DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_overtemperature_discharge},
    {DIAG_CH_TEMP_OVERTEMPERATURE_DISCHARGE_RSL,      "OVERTEMP_DISCHARGE_RSL",          DIAG_ERROR_TEMPERATURE_SENSITIVITY_MSL,       DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_overtemperature_discharge},
    {DIAG_CH_TEMP_OVERTEMPERATURE_DISCHARGE_MOL,    "OVERTEMP_DISCHARGE_MOL",            DIAG_ERROR_TEMPERATURE_SENSITIVITY_MSL,       DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_overtemperature_discharge},

    {DIAG_CH_TEMP_UNDERTEMPERATURE_CHARGE_MSL,        "UNDERTEMP_CHARGE_MSL",            DIAG_ERROR_TEMPERATURE_SENSITIVITY_MSL,       DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_undertemperature_charge},
    {DIAG_CH_TEMP_UNDERTEMPERATURE_CHARGE_RSL,        "UNDERTEMP_CHARGE_RSL",            DIAG_ERROR_TEMPERATURE_SENSITIVITY_MSL,       DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_undertemperature_charge},
    {DIAG_CH_TEMP_UNDERTEMPERATURE_CHARGE_MOL,      "UNDERTEMP_CHARGE_MOL",              DIAG_ERROR_TEMPERATURE_SENSITIVITY_MSL,       DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_undertemperature_charge},

    {DIAG_CH_TEMP_UNDERTEMPERATURE_DISCHARGE_MSL,     "UNDERTEMP_DISCHARGE_MSL",         DIAG_ERROR_TEMPERATURE_SENSITIVITY_MSL,       DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_undertemperature_discharge},
    {DIAG_CH_TEMP_UNDERTEMPERATURE_DISCHARGE_RSL,     "UNDERTEMP_DISCHARGE_RSL",         DIAG_ERROR_TEMPERATURE_SENSITIVITY_MSL,       DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_undertemperature_discharge},
    {DIAG_CH_TEMP_UNDERTEMPERATURE_DISCHARGE_MOL,   "UNDERTEMP_DISCHARGE_MOL",           DIAG_ERROR_TEMPERATURE_SENSITIVITY_MSL,       DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_undertemperature_discharge},

    {DIAG_CH_OVERCURRENT_PL_NONE,             "OVERCUR_NO_POWERLINE",      DIAG_ERROR_CURRENT_SENSITIVITY_MSL,   DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_overcurrent_charge},

    {DIAG_CH_OVERCURRENT_CHARGE_CELL_MSL,     "OVERCUR_CHRG_CELL_MSL",     DIAG_ERROR_CURRENT_SENSITIVITY_MSL,   DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_overcurrent_charge},
    {DIAG_CH_OVERCURRENT_CHARGE_CELL_RSL,     "OVERCUR_CHRG_CELL_RSL",     DIAG_ERROR_CURRENT_SENSITIVITY_RSL,   DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_overcurrent_charge},
    {DIAG_CH_OVERCURRENT_CHARGE_CELL_MOL,     "OVERCUR_CHRG_CELL_MOL",     DIAG_ERROR_CURRENT_SENSITIVITY_MOL,   DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_overcurrent_charge},

    {DIAG_CH_OVERCURRENT_DISCHARGE_CELL_MSL,  "OVERCUR_DCHRG_CELL_MSL",    DIAG_ERROR_CURRENT_SENSITIVITY_MSL,   DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_overcurrent_discharge},
    {DIAG_CH_OVERCURRENT_DISCHARGE_CELL_RSL,  "OVERCUR_DCHRG_CELL_RSL",    DIAG_ERROR_CURRENT_SENSITIVITY_RSL,   DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_overcurrent_discharge},
    {DIAG_CH_OVERCURRENT_DISCHARGE_CELL_MOL,  "OVERCUR_DCHRG_CELL_MOL",    DIAG_ERROR_CURRENT_SENSITIVITY_MOL,   DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_overcurrent_discharge},

    {DIAG_CH_OVERCURRENT_CHARGE_PL0_MSL,       "OVERCUR_CHRG_PL0_MSL",     DIAG_ERROR_CURRENT_SENSITIVITY_MSL,   DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_overcurrent_charge},
    {DIAG_CH_OVERCURRENT_CHARGE_PL0_RSL,       "OVERCUR_CHRG_PL0_RSL",     DIAG_ERROR_CURRENT_SENSITIVITY_RSL,   DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_overcurrent_charge},
    {DIAG_CH_OVERCURRENT_CHARGE_PL0_MOL,       "OVERCUR_CHRG_PL0_MOL",     DIAG_ERROR_CURRENT_SENSITIVITY_MOL,   DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_overcurrent_charge},

    {DIAG_CH_OVERCURRENT_DISCHARGE_PL0_MSL,    "OVERCUR_DCHRG_PL0_MSL",    DIAG_ERROR_CURRENT_SENSITIVITY_MSL,   DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_overcurrent_discharge},
    {DIAG_CH_OVERCURRENT_DISCHARGE_PL0_RSL,    "OVERCUR_DCHRG_PL0_RSL",    DIAG_ERROR_CURRENT_SENSITIVITY_RSL,   DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_overcurrent_discharge},
    {DIAG_CH_OVERCURRENT_DISCHARGE_PL0_MOL,    "OVERCUR_DCHRG_PL0_MOL",    DIAG_ERROR_CURRENT_SENSITIVITY_MOL,   DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_overcurrent_discharge},

    {DIAG_CH_OVERCURRENT_CHARGE_PL1_MSL,       "OVERCUR_CHRG_PL1_MSL",     DIAG_ERROR_CURRENT_SENSITIVITY_MSL,   DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_overcurrent_charge},
    {DIAG_CH_OVERCURRENT_CHARGE_PL1_RSL,       "OVERCUR_CHRG_PL1_RSL",     DIAG_ERROR_CURRENT_SENSITIVITY_RSL,   DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_overcurrent_charge},
    {DIAG_CH_OVERCURRENT_CHARGE_PL1_MOL,       "OVERCUR_CHRG_PL1_MOL",     DIAG_ERROR_CURRENT_SENSITIVITY_MOL,   DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_overcurrent_charge},

    {DIAG_CH_OVERCURRENT_DISCHARGE_PL1_MSL,    "OVERCUR_DCHRG_PL1_MSL",    DIAG_ERROR_CURRENT_SENSITIVITY_MSL,   DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_overcurrent_discharge},
    {DIAG_CH_OVERCURRENT_DISCHARGE_PL1_RSL,    "OVERCUR_DCHRG_PL1_RSL",    DIAG_ERROR_CURRENT_SENSITIVITY_RSL,   DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_overcurrent_discharge},
    {DIAG_CH_OVERCURRENT_DISCHARGE_PL1_MOL,    "OVERCUR_DCHRG_PL1_MOL",    DIAG_ERROR_CURRENT_SENSITIVITY_MOL,   DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_overcurrent_discharge},

    {DIAG_CH_LTC_SPI,                                   "LTC_SPI",                              DIAG_ERROR_LTC_SPI_SENSITIVITY,           DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_error_ltc},
    {DIAG_CH_LTC_PEC,                                   "LTC_PEC",                              DIAG_ERROR_LTC_PEC_SENSITIVITY,           DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_error_ltc},
    {DIAG_CH_LTC_MUX,                                   "LTC_MUX",                              DIAG_ERROR_LTC_MUX_SENSITIVITY,           DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_error_ltc},
    {DIAG_CH_LTC_CONFIG,                                "LTC_CONFIG",                           DIAG_ERROR_SENSITIVITY_HIGH,              DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_error_ltc},

    /* Communication events */
    {DIAG_CH_CAN_TIMING,                                "CAN_TIMING",                           DIAG_ERROR_CAN_TIMING_SENSITIVITY,        DIAG_RECORDING_ENABLED, DIAG_CAN_TIMING, DIAG_error_cantiming},
    {DIAG_CH_CAN_CC_RESPONDING,                         "CAN_CC_RESPONDING",                    DIAG_ERROR_CAN_TIMING_CC_SENSITIVITY,     DIAG_RECORDING_ENABLED, DIAG_CAN_SENSOR_PRESENT, DIAG_error_cantiming},
    {DIAG_CH_CURRENT_SENSOR_RESPONDING,                 "CURRENT_SENSOR_RESPONDING",            DIAG_ERROR_CAN_SENSOR_SENSITIVITY,        DIAG_RECORDING_ENABLED, DIAG_CAN_SENSOR_PRESENT, DIAG_error_cancurrentsensor},

#if BUILD_MODULE_ENABLE_CONTACTOR == 1
    /* Contactor Damage Error */
    {DIAG_CH_CONTACTOR_DAMAGED,                         "CONTACTOR_DAMAGED",                    DIAG_ERROR_SENSITIVITY_HIGH,              DIAG_RECORDING_ENABLED, DIAG_ENABLED, dummyfu},
    {DIAG_CH_CONTACTOR_OPENING,                         "CONTACTOR_OPENING",                    DIAG_ERROR_SENSITIVITY_HIGH,              DIAG_RECORDING_ENABLED, DIAG_ENABLED, dummyfu},
    {DIAG_CH_CONTACTOR_CLOSING,                         "CONTACTOR_CLOSING",                    DIAG_ERROR_SENSITIVITY_HIGH,              DIAG_RECORDING_ENABLED, DIAG_ENABLED, dummyfu},

    /* Contactor Feedback Error */
    {DIAG_CH_CONTACTOR_MAIN_PLUS_FEEDBACK,              "CONT_MAIN_PLUS_FEED",          DIAG_ERROR_MAIN_PLUS_SENSITIVITY,      DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_cont_feedback },
    {DIAG_CH_CONTACTOR_MAIN_MINUS_FEEDBACK,             "CONT_MAIN_MINUS_FEED",         DIAG_ERROR_MAIN_MINUS_SENSITIVITY,     DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_cont_feedback },
    {DIAG_CH_CONTACTOR_PRECHARGE_FEEDBACK,              "CONT_PRECHARGE_FEED",          DIAG_ERROR_PRECHARGE_SENSITIVITY,      DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_cont_feedback },
    {DIAG_CH_CONTACTOR_CHARGE_MAIN_PLUS_FEEDBACK,       "CONT_CHRGE_MAIN_PLUS_FEED",    DIAG_ERROR_MAIN_PLUS_SENSITIVITY,      DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_cont_feedback },
    {DIAG_CH_CONTACTOR_CHARGE_MAIN_MINUS_FEEDBACK,      "CONT_CHRGE_MAIN_MINUS_FEED",   DIAG_ERROR_MAIN_MINUS_SENSITIVITY,     DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_cont_feedback },
    {DIAG_CH_CONTACTOR_CHARGE_PRECHARGE_FEEDBACK,       "CONT_CHRGE_PRECHARGE_FEED",    DIAG_ERROR_PRECHARGE_SENSITIVITY,      DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_cont_feedback },

    /* Fuse state */
    {DIAG_CH_FUSE_STATE_NORMAL,                         "FUSE_STATE_NORMAL",          DIAG_ERROR_SENSITIVITY_LOW,            DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_error_fuseState },
    {DIAG_CH_FUSE_STATE_CHARGE,                         "FUSE_STATE_CHARGE",          DIAG_ERROR_SENSITIVITY_LOW,            DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_error_fuseState },
#else
    /* Contactor Damage Error */
    {DIAG_CH_CONTACTOR_DAMAGED,                         "CONTACTOR_DAMAGED",                    DIAG_ERROR_SENSITIVITY_HIGH,              DIAG_RECORDING_DISABLED, DIAG_DISABLED, dummyfu},
    {DIAG_CH_CONTACTOR_OPENING,                         "CONTACTOR_OPENING",                    DIAG_ERROR_SENSITIVITY_HIGH,              DIAG_RECORDING_DISABLED, DIAG_DISABLED, dummyfu},
    {DIAG_CH_CONTACTOR_CLOSING,                         "CONTACTOR_CLOSING",                    DIAG_ERROR_SENSITIVITY_HIGH,              DIAG_RECORDING_DISABLED, DIAG_DISABLED, dummyfu},

    /* Contactor Feedback Error */
    {DIAG_CH_CONTACTOR_MAIN_PLUS_FEEDBACK,              "CONT_MAIN_PLUS_FEED",          DIAG_ERROR_MAIN_PLUS_SENSITIVITY,      DIAG_RECORDING_DISABLED, DIAG_DISABLED, DIAG_cont_feedback},
    {DIAG_CH_CONTACTOR_MAIN_MINUS_FEEDBACK,             "CONT_MAIN_MINUS_FEED",         DIAG_ERROR_MAIN_MINUS_SENSITIVITY,     DIAG_RECORDING_DISABLED, DIAG_DISABLED, DIAG_cont_feedback},
    {DIAG_CH_CONTACTOR_PRECHARGE_FEEDBACK,              "CONT_PRECHARGE_FEED",          DIAG_ERROR_PRECHARGE_SENSITIVITY,      DIAG_RECORDING_DISABLED, DIAG_DISABLED, DIAG_cont_feedback},
    {DIAG_CH_CONTACTOR_CHARGE_MAIN_PLUS_FEEDBACK,       "CONT_CHRGE_MAIN_PLUS_FEED",   DIAG_ERROR_MAIN_PLUS_SENSITIVITY,      DIAG_RECORDING_DISABLED, DIAG_DISABLED, DIAG_cont_feedback},
    {DIAG_CH_CONTACTOR_CHARGE_MAIN_MINUS_FEEDBACK,      "CONT_CHRGE_MAIN_MINUS_FEED",  DIAG_ERROR_MAIN_MINUS_SENSITIVITY,     DIAG_RECORDING_DISABLED, DIAG_DISABLED, DIAG_cont_feedback},
    {DIAG_CH_CONTACTOR_CHARGE_PRECHARGE_FEEDBACK,       "CONT_CHRGE_PRECHARGE_FEED",   DIAG_ERROR_PRECHARGE_SENSITIVITY,      DIAG_RECORDING_DISABLED, DIAG_DISABLED, DIAG_cont_feedback},

    /* Fuse state */
    {DIAG_CH_FUSE_STATE_NORMAL,                         "FUSE_STATE_NORMAL",        DIAG_ERROR_SENSITIVITY_LOW,            DIAG_RECORDING_DISABLED, DIAG_DISABLED, DIAG_error_fuseState},
    {DIAG_CH_FUSE_STATE_CHARGE,                         "FUSE_STATE_CHARGE",        DIAG_ERROR_SENSITIVITY_LOW,            DIAG_RECORDING_DISABLED, DIAG_DISABLED, DIAG_error_fuseState},

#endif

#if BUILD_MODULE_ENABLE_ILCK == 1
    /* Interlock Feedback Error */
    {DIAG_CH_INTERLOCK_FEEDBACK,                        "INTERLOCK_FEEDBACK",                    DIAG_ERROR_INTERLOCK_SENSITIVITY,       DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_error_interlock},
#else
    {DIAG_CH_INTERLOCK_FEEDBACK,                        "INTERLOCK_FEEDBACK",                    DIAG_ERROR_INTERLOCK_SENSITIVITY,       DIAG_RECORDING_DISABLED, DIAG_DISABLED, DIAG_error_interlock},
#endif

    /* Slave PCB temperature errors for under and over temperature */
    {DIAG_CH_SLAVE_PCB_UNDERTEMPERATURE_MSL,          "SLAVE_PCB_UNDERTEMP_MSL",        DIAG_ERROR_SLAVE_TEMP_SENSITIVITY_MSL,   DIAG_RECORDING_ENABLED, DIAG_ENABLED, dummyfu},
    {DIAG_CH_SLAVE_PCB_UNDERTEMPERATURE_RSL,          "SLAVE_PCB_UNDERTEMP_RSL",        DIAG_ERROR_SLAVE_TEMP_SENSITIVITY_RSL,   DIAG_RECORDING_ENABLED, DIAG_ENABLED, dummyfu},
    {DIAG_CH_SLAVE_PCB_UNDERTEMPERATURE_MOL,        "SLAVE_PCB_UNDERTEMP_MOL",        DIAG_ERROR_SLAVE_TEMP_SENSITIVITY_MOL, DIAG_RECORDING_ENABLED, DIAG_ENABLED, dummyfu},

    {DIAG_CH_SLAVE_PCB_OVERTEMPERATURE_MSL,           "SLAVE_PCB_OVERTEMP_MSL",         DIAG_ERROR_SLAVE_TEMP_SENSITIVITY_MSL,   DIAG_RECORDING_ENABLED, DIAG_ENABLED, dummyfu},
    {DIAG_CH_SLAVE_PCB_OVERTEMPERATURE_RSL,           "SLAVE_PCB_OVERTEMP_RSL",         DIAG_ERROR_SLAVE_TEMP_SENSITIVITY_RSL,   DIAG_RECORDING_ENABLED, DIAG_ENABLED, dummyfu},
    {DIAG_CH_SLAVE_PCB_OVERTEMPERATURE_MOL,         "SLAVE_PCB_OVERTEMP_MOL",         DIAG_ERROR_SLAVE_TEMP_SENSITIVITY_MOL, DIAG_RECORDING_ENABLED, DIAG_ENABLED, dummyfu},

    {DIAG_CH_ERROR_MCU_DIE_TEMPERATURE,     "MCU_DIE_TEMPERATURE",      DIAG_ERROR_SENSITIVITY_LOW, DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_error_MCUdieTemperature},
    {DIAG_CH_LOW_COIN_CELL_VOLTAGE,         "COIN_CELL_VOLT_LOW",       DIAG_ERROR_SENSITIVITY_LOW, DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_error_coinCellVoltage},
    {DIAG_CH_CRIT_LOW_COIN_CELL_VOLTAGE,    "COIN_CELL_VOLT_CRITICAL",  DIAG_ERROR_SENSITIVITY_LOW, DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_error_coinCellVoltage},

    {DIAG_CH_OPEN_WIRE,       "OPEN_WIRE",         DIAG_ERROR_SENSITIVITY_HIGH, DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_error_openWire},
    {DIAG_CH_DEEP_DISCHARGE_DETECTED,    "DEEP-DISCHARGE detected", DIAG_ERROR_SENSITIVITY_HIGH, DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_error_deep_discharge_detected},

    /* Plausibility checks */
    {DIAG_CH_PLAUSIBILITY_CELL_VOLTAGE,    "PL_CELL_VOLT",    DIAG_ERROR_SENSITIVITY_HIGH, DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_error_plausibility_check},
    {DIAG_CH_PLAUSIBILITY_CELL_TEMP,       "PL_CELL_TEMP",    DIAG_ERROR_SENSITIVITY_HIGH, DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_error_plausibility_check},
    {DIAG_CH_PLAUSIBILITY_PACK_VOLTAGE,    "PL_PACK_VOLT",    DIAG_ERROR_PLAUSIBILITY_PACK_SENSITIVITY, DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_error_plausibility_check},
};


DIAG_SYSMON_CH_CFG_s diag_sysmon_ch_cfg[] = {
    {DIAG_SYSMON_DATABASE_ID,       DIAG_SYSMON_CYCLICTASK,  10, DIAG_RECORDING_ENABLED, DIAG_SYSMON_HANDLING_SWITCHOFFCONTACTOR, DIAG_ENABLED, dummyfu2},
    {DIAG_SYSMON_SYS_ID,            DIAG_SYSMON_CYCLICTASK,  20, DIAG_RECORDING_ENABLED, DIAG_SYSMON_HANDLING_SWITCHOFFCONTACTOR, DIAG_ENABLED, dummyfu2},
    {DIAG_SYSMON_BMS_ID,            DIAG_SYSMON_CYCLICTASK,  20, DIAG_RECORDING_ENABLED, DIAG_SYSMON_HANDLING_SWITCHOFFCONTACTOR, DIAG_ENABLED, dummyfu2},

#if BUILD_MODULE_ENABLE_CONTACTOR == 1
    {DIAG_SYSMON_CONT_ID,           DIAG_SYSMON_CYCLICTASK,  20, DIAG_RECORDING_ENABLED, DIAG_SYSMON_HANDLING_SWITCHOFFCONTACTOR, DIAG_ENABLED, dummyfu2},
#else
    {DIAG_SYSMON_CONT_ID,           DIAG_SYSMON_CYCLICTASK,  20, DIAG_RECORDING_DISABLED, DIAG_SYSMON_HANDLING_SWITCHOFFCONTACTOR, DIAG_DISABLED, dummyfu2},
#endif

#if BUILD_MODULE_ENABLE_ILCK == 1
    {DIAG_SYSMON_ILCK_ID,           DIAG_SYSMON_CYCLICTASK,  20, DIAG_RECORDING_ENABLED, DIAG_SYSMON_HANDLING_SWITCHOFFCONTACTOR, DIAG_ENABLED, dummyfu2},
#else
    {DIAG_SYSMON_ILCK_ID,           DIAG_SYSMON_CYCLICTASK,  20, DIAG_RECORDING_DISABLED, DIAG_SYSMON_HANDLING_SWITCHOFFCONTACTOR, DIAG_DISABLED, dummyfu2},
#endif
    {DIAG_SYSMON_LTC_ID,            DIAG_SYSMON_CYCLICTASK,   5, DIAG_RECORDING_ENABLED, DIAG_SYSMON_HANDLING_SWITCHOFFCONTACTOR, DIAG_ENABLED, dummyfu2},

#if BUILD_MODULE_ENABLE_ISOGUARD == 1
    {DIAG_SYSMON_ISOGUARD_ID,       DIAG_SYSMON_CYCLICTASK, 400, DIAG_RECORDING_ENABLED, DIAG_SYSMON_HANDLING_SWITCHOFFCONTACTOR, DIAG_ENABLED, dummyfu2},
#else
    {DIAG_SYSMON_ISOGUARD_ID,       DIAG_SYSMON_CYCLICTASK, 400, DIAG_RECORDING_DISABLED, DIAG_SYSMON_HANDLING_SWITCHOFFCONTACTOR, DIAG_DISABLED, dummyfu2},
#endif

    {DIAG_SYSMON_CANS_ID,           DIAG_SYSMON_CYCLICTASK,  20, DIAG_RECORDING_ENABLED, DIAG_SYSMON_HANDLING_SWITCHOFFCONTACTOR, DIAG_ENABLED, dummyfu2},
    {DIAG_SYSMON_APPL_CYCLIC_1ms,   DIAG_SYSMON_CYCLICTASK,  20, DIAG_RECORDING_ENABLED, DIAG_SYSMON_HANDLING_SWITCHOFFCONTACTOR, DIAG_ENABLED, dummyfu2},
    {DIAG_SYSMON_APPL_CYCLIC_10ms,  DIAG_SYSMON_CYCLICTASK,  20, DIAG_RECORDING_ENABLED, DIAG_SYSMON_HANDLING_SWITCHOFFCONTACTOR, DIAG_ENABLED, dummyfu2},
    {DIAG_SYSMON_APPL_CYCLIC_100ms, DIAG_SYSMON_CYCLICTASK, 200, DIAG_RECORDING_ENABLED, DIAG_SYSMON_HANDLING_SWITCHOFFCONTACTOR, DIAG_ENABLED, dummyfu2},
};


DIAG_DEV_s  diag_dev = {
    .nr_of_ch   = sizeof(diag_ch_cfg)/sizeof(DIAG_CH_CFG_s),
    .ch_cfg     = &diag_ch_cfg[0],
};

/*================== Static Function Implementations ========================*/
/**
 * @brief  dummy callback function of diagnosis events
 */
void dummyfu(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event) {
    /* Dummy function -> empty */
}

/**
 * @brief  dummy callback function of system monitoring error events
 */
void dummyfu2(DIAG_SYSMON_MODULE_ID_e ch_id) {
    /* Dummy function -> empty */
}

/**
 * @brief  diagnosis callback function for overvoltage events
 */
static void DIAG_overvoltage(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event) {
    if (ch_id == DIAG_CH_CELLVOLTAGE_OVERVOLTAGE_MSL) {
        if (event == DIAG_EVENT_RESET) {
            msl_flags.over_voltage = 0;
        }
        if (event == DIAG_EVENT_NOK) {
            msl_flags.over_voltage = 1;
        }
    } else if (ch_id == DIAG_CH_CELLVOLTAGE_OVERVOLTAGE_RSL) {
        if (event == DIAG_EVENT_RESET) {
            rsl_flags.over_voltage = 0;
        }
        if (event == DIAG_EVENT_NOK) {
            rsl_flags.over_voltage = 1;
        }
    } else if (ch_id == DIAG_CH_CELLVOLTAGE_OVERVOLTAGE_MOL) {
        if (event == DIAG_EVENT_RESET) {
            mol_flags.over_voltage = 0;
        }
        if (event == DIAG_EVENT_NOK) {
            mol_flags.over_voltage = 1;
        }
    }
}

/**
 * @brief  diagnosis callback function for undervoltage events
 */
static void DIAG_undervoltage(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event) {
    if (ch_id == DIAG_CH_CELLVOLTAGE_UNDERVOLTAGE_MSL) {
        if (event == DIAG_EVENT_RESET) {
            msl_flags.under_voltage = 0;
        }
        if (event == DIAG_EVENT_NOK) {
            msl_flags.under_voltage = 1;
        }
    } else if (ch_id == DIAG_CH_CELLVOLTAGE_UNDERVOLTAGE_RSL) {
        if (event == DIAG_EVENT_RESET) {
            rsl_flags.under_voltage = 0;
        }
        if (event == DIAG_EVENT_NOK) {
            rsl_flags.under_voltage = 1;
        }
    } else if (ch_id == DIAG_CH_CELLVOLTAGE_UNDERVOLTAGE_MOL) {
        if (event == DIAG_EVENT_RESET) {
            mol_flags.under_voltage = 0;
        }
        if (event == DIAG_EVENT_NOK) {
            mol_flags.under_voltage = 1;
        }
    }
}

/**
 * @brief  diagnosis callback function for overtemperature charge events
 */
static void DIAG_overtemperature_charge(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event) {
    if (ch_id == DIAG_CH_TEMP_OVERTEMPERATURE_CHARGE_MSL) {
        if (event == DIAG_EVENT_RESET) {
            msl_flags.over_temperature_charge = 0;
        }
        if (event == DIAG_EVENT_NOK) {
            msl_flags.over_temperature_charge = 1;
        }
    } else if (ch_id == DIAG_CH_TEMP_OVERTEMPERATURE_CHARGE_RSL) {
        if (event == DIAG_EVENT_RESET) {
            rsl_flags.over_temperature_charge = 0;
        }
        if (event == DIAG_EVENT_NOK) {
            rsl_flags.over_temperature_charge = 1;
        }
    } else if (ch_id == DIAG_CH_TEMP_OVERTEMPERATURE_CHARGE_MOL) {
        if (event == DIAG_EVENT_RESET) {
            mol_flags.over_temperature_charge = 0;
        }
        if (event == DIAG_EVENT_NOK) {
            mol_flags.over_temperature_charge = 1;
        }
    }
}

/**
 * @brief  diagnosis callback function for overtemperature discharge events
 */
static void DIAG_overtemperature_discharge(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event) {
    if (ch_id == DIAG_CH_TEMP_OVERTEMPERATURE_DISCHARGE_MSL) {
        if (event == DIAG_EVENT_RESET) {
            msl_flags.over_temperature_discharge = 0;
        }
        if (event == DIAG_EVENT_NOK) {
            msl_flags.over_temperature_discharge = 1;
        }
    } else if (ch_id == DIAG_CH_TEMP_OVERTEMPERATURE_DISCHARGE_RSL) {
        if (event == DIAG_EVENT_RESET) {
            rsl_flags.over_temperature_discharge = 0;
        }
        if (event == DIAG_EVENT_NOK) {
            rsl_flags.over_temperature_discharge = 1;
        }
    } else if (ch_id == DIAG_CH_TEMP_OVERTEMPERATURE_DISCHARGE_MOL) {
        if (event == DIAG_EVENT_RESET) {
            mol_flags.over_temperature_discharge = 0;
        }
        if (event == DIAG_EVENT_NOK) {
            mol_flags.over_temperature_discharge = 1;
        }
    }
}

/**
 * @brief  diagnosis callback function for undertemperature charge events
 */
static void DIAG_undertemperature_charge(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event) {
    if (ch_id == DIAG_CH_TEMP_UNDERTEMPERATURE_CHARGE_MSL) {
        if (event == DIAG_EVENT_RESET) {
            msl_flags.under_temperature_charge = 0;
        }
        if (event == DIAG_EVENT_NOK) {
            msl_flags.under_temperature_charge = 1;
        }
    } else if (ch_id == DIAG_CH_TEMP_UNDERTEMPERATURE_CHARGE_RSL) {
        if (event == DIAG_EVENT_RESET) {
            rsl_flags.under_temperature_charge = 0;
        }
        if (event == DIAG_EVENT_NOK) {
            rsl_flags.under_temperature_charge = 1;
        }
    } else if (ch_id == DIAG_CH_TEMP_UNDERTEMPERATURE_CHARGE_MOL) {
        if (event == DIAG_EVENT_RESET) {
            mol_flags.under_temperature_charge = 0;
        }
        if (event == DIAG_EVENT_NOK) {
            mol_flags.under_temperature_charge = 1;
        }
    }
}

/**
 * @brief  diagnosis callback function for undertemperature discharge events
 */
static void DIAG_undertemperature_discharge(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event) {
    if (ch_id == DIAG_CH_TEMP_UNDERTEMPERATURE_DISCHARGE_MSL) {
        if (event == DIAG_EVENT_RESET) {
            msl_flags.under_temperature_discharge = 0;
        }
        if (event == DIAG_EVENT_NOK) {
            msl_flags.under_temperature_discharge = 1;
        }
    } else if (ch_id == DIAG_CH_TEMP_UNDERTEMPERATURE_DISCHARGE_RSL) {
        if (event == DIAG_EVENT_RESET) {
            rsl_flags.under_temperature_discharge = 0;
        }
        if (event == DIAG_EVENT_NOK) {
            rsl_flags.under_temperature_discharge = 1;
        }
    } else if (ch_id == DIAG_CH_TEMP_UNDERTEMPERATURE_DISCHARGE_MOL) {
        if (event == DIAG_EVENT_RESET) {
            mol_flags.under_temperature_discharge = 0;
        }
        if (event == DIAG_EVENT_NOK) {
            mol_flags.under_temperature_discharge = 1;
        }
    }
}

/**
 * @brief  diagnosis callback function for overcurrent charge events
 */
static void DIAG_overcurrent_charge(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event) {
    switch (ch_id) {
    case DIAG_CH_OVERCURRENT_CHARGE_CELL_MSL:
        if (event == DIAG_EVENT_RESET) {
            msl_flags.over_current_charge_cell = 0;
        } else if (event == DIAG_EVENT_NOK) {
            msl_flags.over_current_charge_cell = 1;
        } else {
            /* no relevant event, do nothing */
        }
        break;
    case DIAG_CH_OVERCURRENT_CHARGE_CELL_RSL:
        if (event == DIAG_EVENT_RESET) {
            rsl_flags.over_current_charge_cell = 0;
        } else if (event == DIAG_EVENT_NOK) {
            rsl_flags.over_current_charge_cell = 1;
        } else {
            /* no relevant event, do nothing */
        }
        break;
    case DIAG_CH_OVERCURRENT_CHARGE_CELL_MOL:
        if (event == DIAG_EVENT_RESET) {
            mol_flags.over_current_charge_cell = 0;
        } else if (event == DIAG_EVENT_NOK) {
            mol_flags.over_current_charge_cell = 1;
        } else {
            /* no relevant event, do nothing */
        }
        break;
    case DIAG_CH_OVERCURRENT_CHARGE_PL0_MSL:
        if (event == DIAG_EVENT_RESET) {
            msl_flags.over_current_charge_pl0 = 0;
        } else if (event == DIAG_EVENT_NOK) {
            msl_flags.over_current_charge_pl0 = 1;
        } else {
            /* no relevant event, do nothing */
        }
        break;
    case DIAG_CH_OVERCURRENT_CHARGE_PL0_RSL:
        if (event == DIAG_EVENT_RESET) {
            rsl_flags.over_current_charge_pl0 = 0;
        } else if (event == DIAG_EVENT_NOK) {
            rsl_flags.over_current_charge_pl0 = 1;
        } else {
            /* no relevant event, do nothing */
        }
        break;
    case DIAG_CH_OVERCURRENT_CHARGE_PL0_MOL:
        if (event == DIAG_EVENT_RESET) {
            mol_flags.over_current_charge_pl0 = 0;
        } else if (event == DIAG_EVENT_NOK) {
            mol_flags.over_current_charge_pl0 = 1;
        } else {
            /* no relevant event, do nothing */
        }
        break;
    case DIAG_CH_OVERCURRENT_CHARGE_PL1_MSL:
        if (event == DIAG_EVENT_RESET) {
            msl_flags.over_current_charge_pl1 = 0;
        } else if (event == DIAG_EVENT_NOK) {
            msl_flags.over_current_charge_pl1 = 1;
        } else {
            /* no relevant event, do nothing */
        }
        break;
    case DIAG_CH_OVERCURRENT_CHARGE_PL1_RSL:
        if (event == DIAG_EVENT_RESET) {
            rsl_flags.over_current_charge_pl1 = 0;
        } else if (event == DIAG_EVENT_NOK) {
            rsl_flags.over_current_charge_pl1 = 1;
        } else {
            /* no relevant event, do nothing */
        }
        break;
    case DIAG_CH_OVERCURRENT_CHARGE_PL1_MOL:
        if (event == DIAG_EVENT_RESET) {
            mol_flags.over_current_charge_pl1 = 0;
        } else if (event == DIAG_EVENT_NOK) {
            mol_flags.over_current_charge_pl1 = 1;
        } else {
            /* no relevant event, do nothing */
        }
        break;
    case DIAG_CH_OVERCURRENT_PL_NONE:
        if (event == DIAG_EVENT_RESET) {
            error_flags.currentOnOpenPowerline = 0;
        } else if (event == DIAG_EVENT_NOK) {
            error_flags.currentOnOpenPowerline = 1;
        } else {
            /* no relevant event, do nothing */
        }
        break;
    default:
        /* no relevant channel, do nothing */
        break;
    }
}

/**
 * @brief  diagnosis callback function for overcurrent discharge events
 */
static void DIAG_overcurrent_discharge(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event) {
    switch (ch_id) {
    case DIAG_CH_OVERCURRENT_DISCHARGE_CELL_MSL:
        if (event == DIAG_EVENT_RESET) {
            msl_flags.over_current_discharge_cell = 0;
        } else if (event == DIAG_EVENT_NOK) {
            msl_flags.over_current_discharge_cell = 1;
        } else {
            /* no relevant event, do nothing */
        }
        break;
    case DIAG_CH_OVERCURRENT_DISCHARGE_CELL_RSL:
        if (event == DIAG_EVENT_RESET) {
            rsl_flags.over_current_discharge_cell = 0;
        } else if (event == DIAG_EVENT_NOK) {
            rsl_flags.over_current_discharge_cell = 1;
        } else {
            /* no relevant event, do nothing */
        }
        break;
    case DIAG_CH_OVERCURRENT_DISCHARGE_CELL_MOL:
        if (event == DIAG_EVENT_RESET) {
            mol_flags.over_current_discharge_cell = 0;
        } else if (event == DIAG_EVENT_NOK) {
            mol_flags.over_current_discharge_cell = 1;
        } else {
            /* no relevant event, do nothing */
        }
        break;
    case DIAG_CH_OVERCURRENT_DISCHARGE_PL0_MSL:
        if (event == DIAG_EVENT_RESET) {
            msl_flags.over_current_discharge_pl0 = 0;
        } else if (event == DIAG_EVENT_NOK) {
            msl_flags.over_current_discharge_pl0 = 1;
        } else {
            /* no relevant event, do nothing */
        }
        break;
    case DIAG_CH_OVERCURRENT_DISCHARGE_PL0_RSL:
        if (event == DIAG_EVENT_RESET) {
            rsl_flags.over_current_discharge_pl0 = 0;
        } else if (event == DIAG_EVENT_NOK) {
            rsl_flags.over_current_discharge_pl0 = 1;
        } else {
            /* no relevant event, do nothing */
        }
        break;
    case DIAG_CH_OVERCURRENT_DISCHARGE_PL0_MOL:
        if (event == DIAG_EVENT_RESET) {
            mol_flags.over_current_discharge_pl0 = 0;
        } else if (event == DIAG_EVENT_NOK) {
            mol_flags.over_current_discharge_pl0 = 1;
        } else {
            /* no relevant event, do nothing */
        }
        break;
    case DIAG_CH_OVERCURRENT_DISCHARGE_PL1_MSL:
        if (event == DIAG_EVENT_RESET) {
            msl_flags.over_current_discharge_pl1 = 0;
        } else if (event == DIAG_EVENT_NOK) {
            msl_flags.over_current_discharge_pl1 = 1;
        } else {
            /* no relevant event, do nothing */
        }
        break;
    case DIAG_CH_OVERCURRENT_DISCHARGE_PL1_RSL:
        if (event == DIAG_EVENT_RESET) {
            rsl_flags.over_current_discharge_pl1 = 0;
        } else if (event == DIAG_EVENT_NOK) {
            rsl_flags.over_current_discharge_pl1 = 1;
        } else {
            /* no relevant event, do nothing */
        }
        break;
    case DIAG_CH_OVERCURRENT_DISCHARGE_PL1_MOL:
        if (event == DIAG_EVENT_RESET) {
            mol_flags.over_current_discharge_pl1 = 0;
        } else if (event == DIAG_EVENT_NOK) {
            mol_flags.over_current_discharge_pl1 = 1;
        } else {
            /* no relevant event, do nothing */
        }
        break;
    default:
        /* no relevant channel, do nothing */
        break;
    }
}

/**
 * @brief  diagnosis callback function for can related events
 */
void DIAG_error_cantiming(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event) {
    if (ch_id == DIAG_CH_CAN_TIMING) {
        if (event == DIAG_EVENT_RESET) {
            error_flags.can_timing = 0;
        }
        if (event == DIAG_EVENT_NOK) {
            error_flags.can_timing = 1;
        }
    } else if (ch_id == DIAG_CH_CAN_CC_RESPONDING) {
        if (event == DIAG_EVENT_RESET) {
            error_flags.can_timing_cc = 0;
        }
        if (event == DIAG_EVENT_NOK) {
            error_flags.can_timing_cc = 1;
        }
    }
}

/**
 * @brief  diagnosis callback function for current sensor related events
 */
void DIAG_error_cancurrentsensor(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event) {
    if (ch_id == DIAG_CH_CURRENT_SENSOR_RESPONDING) {
        if (event == DIAG_EVENT_RESET) {
            error_flags.currentsensorresponding = 0;
        }
        if (event == DIAG_EVENT_NOK) {
            error_flags.currentsensorresponding = 1;
        }
    }
}

/**
 * @brief  diagnosis callback function for LTC module related events
 */
static void DIAG_error_ltc(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event) {
    if (ch_id == DIAG_CH_LTC_SPI) {
        if (event == DIAG_EVENT_RESET) {
            error_flags.spi_error = 0;
        }
        if (event == DIAG_EVENT_NOK) {
            error_flags.spi_error = 1;
        }
    } else if (ch_id == DIAG_CH_LTC_PEC) {
        if (event == DIAG_EVENT_RESET) {
            error_flags.crc_error = 0;
        }
        if (event == DIAG_EVENT_NOK) {
            error_flags.crc_error = 1;
        }
    } else if (ch_id == DIAG_CH_LTC_MUX) {
        if (event == DIAG_EVENT_RESET) {
            error_flags.mux_error = 0;
        }
        if (event == DIAG_EVENT_NOK) {
            error_flags.mux_error = 1;
        }
    }  else if (ch_id == DIAG_CH_LTC_CONFIG) {
        if (event == DIAG_EVENT_RESET) {
            error_flags.ltc_config_error = 0;
        }
        if (event == DIAG_EVENT_NOK) {
            error_flags.ltc_config_error = 1;
        }
    }
}

/**
 * @brief  diagnosis callback function for contactor feedback events
 */
void DIAG_cont_feedback(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event) {
    if (ch_id == DIAG_CH_CONTACTOR_MAIN_PLUS_FEEDBACK) {
        if (event == DIAG_EVENT_RESET) {
            error_flags.main_plus = 0;
        }
        if (event == DIAG_EVENT_NOK) {
            error_flags.main_plus = 1;
        }
    } else if (ch_id == DIAG_CH_CONTACTOR_MAIN_MINUS_FEEDBACK) {
        if (event == DIAG_EVENT_RESET) {
            error_flags.main_minus = 0;
        }
        if (event == DIAG_EVENT_NOK) {
            error_flags.main_minus = 1;
        }
    } else if (ch_id == DIAG_CH_CONTACTOR_PRECHARGE_FEEDBACK) {
        if (event == DIAG_EVENT_RESET) {
            error_flags.precharge = 0;
        }
        if (event == DIAG_EVENT_NOK) {
            error_flags.precharge = 1;
        }
    } else if (ch_id == DIAG_CH_CONTACTOR_CHARGE_MAIN_PLUS_FEEDBACK) {
        if (event == DIAG_EVENT_RESET) {
            error_flags.charge_main_plus = 0;
        }
        if (event == DIAG_EVENT_NOK) {
            error_flags.charge_main_plus = 1;
        }
    } else if (ch_id == DIAG_CH_CONTACTOR_CHARGE_MAIN_MINUS_FEEDBACK) {
        if (event == DIAG_EVENT_RESET) {
            error_flags.charge_main_minus = 0;
        }
        if (event == DIAG_EVENT_NOK) {
            error_flags.charge_main_minus = 1;
        }
    } else if (ch_id == DIAG_CH_CONTACTOR_CHARGE_PRECHARGE_FEEDBACK) {
        if (event == DIAG_EVENT_RESET) {
            error_flags.charge_precharge = 0;
        }
        if (event == DIAG_EVENT_NOK) {
            error_flags.charge_precharge = 1;
        }
    }
}

/**
 * @brief  diagnosis callback function for fuse related events
 */
void DIAG_error_fuseState(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event) {
    if (ch_id == DIAG_CH_FUSE_STATE_NORMAL) {
        if (event == DIAG_EVENT_RESET) {
            error_flags.fuse_state_normal = 0;
        }
        if (event == DIAG_EVENT_NOK) {
            error_flags.fuse_state_normal = 1;
        }
    } else if (ch_id == DIAG_CH_FUSE_STATE_CHARGE) {
        if (event == DIAG_EVENT_RESET) {
            error_flags.fuse_state_charge = 0;
        }
        if (event == DIAG_EVENT_NOK) {
            error_flags.fuse_state_charge = 1;
        }
    }
}

/**
 * @brief  diagnosis callback function for interlock events
 */
void DIAG_error_interlock(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event) {
    if (ch_id == DIAG_CH_INTERLOCK_FEEDBACK) {
        if (event == DIAG_EVENT_RESET) {
            error_flags.interlock = 0;
        }
        if (event == DIAG_EVENT_NOK) {
            error_flags.interlock = 1;
        }
    }
}

/**
 * @brief  diagnosis callback function for insulation events
 */
void DIAG_error_insulation(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event) {
    if (ch_id == DIAG_CH_INSULATION_ERROR) {
        if (event == DIAG_EVENT_RESET) {
            error_flags.insulation_error = 0;
        }
        if (event == DIAG_EVENT_NOK) {
            error_flags.insulation_error = 1;
        }
    }
}

/**
 * @brief  diagnosis callback function for MCU die temperature events
 */
void DIAG_error_MCUdieTemperature(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event) {
    if (ch_id == DIAG_CH_ERROR_MCU_DIE_TEMPERATURE) {
        if (event == DIAG_EVENT_RESET) {
            error_flags.mcuDieTemperature = 0;
        }
        if (event == DIAG_EVENT_NOK) {
            error_flags.mcuDieTemperature = 1;
        }
    }
}

/**
 * @brief  diagnosis callback function for coin cell voltage events
 */
void DIAG_error_coinCellVoltage(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event) {
    if (ch_id == DIAG_CH_LOW_COIN_CELL_VOLTAGE) {
        if (event  ==  DIAG_EVENT_RESET) {
            error_flags.coinCellVoltage &= 0xFE;
        }
        if (event == DIAG_EVENT_NOK) {
            error_flags.coinCellVoltage |= 0x01;
        }
    } else if (ch_id == DIAG_CH_CRIT_LOW_COIN_CELL_VOLTAGE) {
        if (event  ==  DIAG_EVENT_RESET) {
            error_flags.coinCellVoltage &= 0xFD;
        }
        if (event == DIAG_EVENT_NOK) {
            error_flags.coinCellVoltage |= 0x02;
        }
    }
}

/**
 * @brief  diagnosis callback function for plausibility events
 */
void DIAG_error_plausibility_check(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event) {
    if (ch_id == DIAG_CH_PLAUSIBILITY_CELL_VOLTAGE) {
        if (event  ==  DIAG_EVENT_RESET) {
            error_flags.plausibilityCheck &= 0xFE;
        }
        if (event == DIAG_EVENT_NOK) {
            error_flags.plausibilityCheck |= 0x01;
        }
    } else if (ch_id == DIAG_CH_PLAUSIBILITY_CELL_TEMP) {
        if (event  ==  DIAG_EVENT_RESET) {
            error_flags.plausibilityCheck &= 0xFD;
        }
        if (event == DIAG_EVENT_NOK) {
            error_flags.plausibilityCheck |= 0x02;
        }
    } else if (ch_id == DIAG_CH_PLAUSIBILITY_PACK_VOLTAGE) {
        if (event  ==  DIAG_EVENT_RESET) {
            error_flags.plausibilityCheck &= 0xFB;
        }
        if (event == DIAG_EVENT_NOK) {
            error_flags.plausibilityCheck |= 0x04;
        }
    }
}

/**
 * @brief  diagnosis callback function for open-wire events
 */
void DIAG_error_openWire(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event) {
    if (ch_id == DIAG_CH_OPEN_WIRE) {
        if (event  ==  DIAG_EVENT_RESET) {
            error_flags.open_wire = 0;
        }
        if (event == DIAG_EVENT_NOK) {
            error_flags.open_wire = 1;
        }
    }
}

/**
 * @brief  diagnosis callback function for deep-discharge related events
 */
void DIAG_error_deep_discharge_detected(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event) {
    if (ch_id == DIAG_CH_DEEP_DISCHARGE_DETECTED) {
        if (event == DIAG_EVENT_RESET) {
            error_flags.deepDischargeDetected = 0;
            RTC_DEEP_DISCHARGE_DETECTED = 0;
        }
        if (event == DIAG_EVENT_NOK) {
            error_flags.deepDischargeDetected = 1;
            RTC_DEEP_DISCHARGE_DETECTED = 1;
        }
    }
}

/*================== Extern Function Implementations ========================*/
void DIAG_updateFlags(void) {
    DB_WriteBlock(&error_flags, DATA_BLOCK_ID_ERRORSTATE);
    DB_WriteBlock(&msl_flags, DATA_BLOCK_ID_MSL);
    DB_WriteBlock(&rsl_flags, DATA_BLOCK_ID_RSL);
    DB_WriteBlock(&mol_flags, DATA_BLOCK_ID_MOL);
}

diag_cfg.h (primary)

/**
 *
 * @copyright &copy; 2010 - 2020, 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    diag_cfg.h
 * @author  foxBMS Team
 * @date    09.11.2015 (date of creation)
 * @ingroup ENGINE_CONF
 * @prefix  DIAG
 *
 * @brief   Diagnostic module configuration header
 *
 * In this header filer are the different diagnosis channel
 * defines assigned to different diagnosis IDs.
 *
 * Furthermore are the diagnosis error log settings be configured here..
 */

#ifndef DIAG_CFG_H_
#define DIAG_CFG_H_

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

#include "batterysystem_cfg.h"

/*================== Macros and Definitions =================================*/
#define DIAG_ERROR_SENSITIVITY_HIGH         (0)    /* logging at first event */
#define DIAG_ERROR_SENSITIVITY_MID          (5)    /* logging at fifth event */
#define DIAG_ERROR_SENSITIVITY_LOW          (10)   /* logging at tenth event */

#define DIAG_ERROR_VOLTAGE_SENSITIVITY_MSL      (500)   /*!< MSL level for event occurrence if over/under voltage event   */
#define DIAG_ERROR_VOLTAGE_SENSITIVITY_RSL      (500)   /*!< RSL level for event occurrence if over/under voltage event   */
#define DIAG_ERROR_VOLTAGE_SENSITIVITY_MOL      (500)   /*!< MOL level for event occurrence if over/under voltage event   */

#define DIAG_ERROR_TEMPERATURE_SENSITIVITY_MSL  (500)   /*!< MSL level for event occurrence if over/under temperature event    */
#define DIAG_ERROR_TEMPERATURE_SENSITIVITY_RSL  (500)   /*!< RSL level for event occurrence if over/under temperature event    */
#define DIAG_ERROR_TEMPERATURE_SENSITIVITY_MOL  (500)   /*!< MOL level for event occurrence if over/under temperature event    */

#define DIAG_ERROR_CURRENT_SENSITIVITY_MSL      (500)   /*!< MSL level for event occurrence if over/under current event        */
#define DIAG_ERROR_CURRENT_SENSITIVITY_RSL      (500)   /*!< RSL level for event occurrence if over/under current event        */
#define DIAG_ERROR_CURRENT_SENSITIVITY_MOL      (500)   /*!< MOL level for event occurrence if over/under current event        */

#define DIAG_ERROR_SLAVE_TEMP_SENSITIVITY_MSL   (500)   /*!< MSL level for event occurrence if slave PCB temperature event     */
#define DIAG_ERROR_SLAVE_TEMP_SENSITIVITY_RSL   (500)   /*!< RSL level for event occurrence if slave PCB temperature event     */
#define DIAG_ERROR_SLAVE_TEMP_SENSITIVITY_MOL   (500)   /*!< MOL level for event occurrence if slave PCB temperature event     */

#define DIAG_ERROR_LTC_PEC_SENSITIVITY          (5)
#define DIAG_ERROR_LTC_MUX_SENSITIVITY          (5)
#define DIAG_ERROR_LTC_SPI_SENSITIVITY          (5)

#define DIAG_ERROR_CAN_TIMING_SENSITIVITY       (100)
#define DIAG_ERROR_CAN_TIMING_CC_SENSITIVITY    (100)
#define DIAG_ERROR_CAN_SENSOR_SENSITIVITY       (100)

#define DIAG_ERROR_MAIN_PLUS_SENSITIVITY        (50)
#define DIAG_ERROR_MAIN_MINUS_SENSITIVITY       (50)
#define DIAG_ERROR_PRECHARGE_SENSITIVITY        (50)

#define DIAG_ERROR_INTERLOCK_SENSITIVITY        (10)

#define DIAG_ERROR_INSULATION_SENSITIVITY       (30)

#define DIAG_ERROR_PLAUSIBILITY_PACK_SENSITIVITY    (100)

/** Number of errors that can be logged */
#define DIAG_FAIL_ENTRY_LENGTH              (50)

/** Maximum number of the same errors that are logged */
#define DIAG_MAX_ENTRIES_OF_ERROR           (5)

/** Number of contactor errors that are logged */
#define DIAG_FAIL_ENTRY_CONTACTOR_LENGTH    (50)


typedef enum {
    DIAG_CH_FLASHCHECKSUM,                          /*  */
    DIAG_CH_BKPDIAG_FAILURE,                        /*  */
    DIAG_CH_WATCHDOGRESET_FAILURE,                  /*  */
    DIAG_CH_POSTOSINIT_FAILURE,                     /*  */
    DIAG_CH_CALIB_EEPR_FAILURE,                     /*  */
    DIAG_CH_CAN_INIT_FAILURE,                       /*  */
    DIAG_CH_VIC_INIT_FAILURE,
    /* HW-/SW-Runtime events: 16-31 */
    DIAG_CH_DIV_BY_ZERO_FAILURE,                    /*  */
    DIAG_CH_UNDEF_INSTRUCTION_FAILURE,              /*  */
    DIAG_CH_DATA_BUS_FAILURE,                       /*  */
    DIAG_CH_INSTRUCTION_BUS_FAILURE,                /*  */
    DIAG_CH_HARDFAULT_NOTHANDLED,                   /*  */
    DIAG_CH_RUNTIME_ERROR_RESERVED_1,               /*  reserved for future needs */
    DIAG_CH_RUNTIME_ERROR_RESERVED_2,               /*  reserved for future needs */
    DIAG_CH_RUNTIME_ERROR_RESERVED_3,               /*  reserved for future needs */
    DIAG_CH_CONFIGASSERT,                           /*  */
    DIAG_CH_SYSTEMMONITORING_TIMEOUT,               /*  */
    /* Measurement events: 32-47 */
    DIAG_CH_CANS_MAX_VALUE_VIOLATE,
    DIAG_CH_CANS_MIN_VALUE_VIOLATE,
    DIAG_CH_CANS_CAN_MOD_FAILURE,
    DIAG_CH_ISOMETER_TIM_ERROR,                     /* Measured frequency too low or no new value captured during last cycle */
    DIAG_CH_ISOMETER_GROUNDERROR,                   /* Ground error detected */
    DIAG_CH_ISOMETER_ERROR,                         /* Device error, invalid measurement result */
    DIAG_CH_ISOMETER_MEAS_INVALID,                  /* Measurement trustworthy or not, hysteresis to ground error flag */
    DIAG_CH_CELLVOLTAGE_OVERVOLTAGE_MSL,            /* Cell voltage limits violated */
    DIAG_CH_CELLVOLTAGE_OVERVOLTAGE_RSL,            /* Cell voltage limits violated */
    DIAG_CH_CELLVOLTAGE_OVERVOLTAGE_MOL,            /* Cell voltage limits violated */
    DIAG_CH_CELLVOLTAGE_UNDERVOLTAGE_MSL,           /* Cell voltage limits violated */
    DIAG_CH_CELLVOLTAGE_UNDERVOLTAGE_RSL,           /* Cell voltage limits violated */
    DIAG_CH_CELLVOLTAGE_UNDERVOLTAGE_MOL,           /* Cell voltage limits violated */
    DIAG_CH_TEMP_OVERTEMPERATURE_CHARGE_MSL,        /* Temperature limits violated */
    DIAG_CH_TEMP_OVERTEMPERATURE_CHARGE_RSL,        /* Temperature limits violated */
    DIAG_CH_TEMP_OVERTEMPERATURE_CHARGE_MOL,        /* Temperature limits violated */
    DIAG_CH_TEMP_OVERTEMPERATURE_DISCHARGE_MSL,     /* Temperature limits violated */
    DIAG_CH_TEMP_OVERTEMPERATURE_DISCHARGE_RSL,     /* Temperature limits violated */
    DIAG_CH_TEMP_OVERTEMPERATURE_DISCHARGE_MOL,     /* Temperature limits violated */
    DIAG_CH_TEMP_UNDERTEMPERATURE_CHARGE_MSL,       /* Temperature limits violated */
    DIAG_CH_TEMP_UNDERTEMPERATURE_CHARGE_RSL,       /* Temperature limits violated */
    DIAG_CH_TEMP_UNDERTEMPERATURE_CHARGE_MOL,       /* Temperature limits violated */
    DIAG_CH_TEMP_UNDERTEMPERATURE_DISCHARGE_MSL,    /* Temperature limits violated */
    DIAG_CH_TEMP_UNDERTEMPERATURE_DISCHARGE_RSL,    /* Temperature limits violated */
    DIAG_CH_TEMP_UNDERTEMPERATURE_DISCHARGE_MOL,    /* Temperature limits violated */
    DIAG_CH_OVERCURRENT_CHARGE_CELL_MSL,            /* Overcurrent */
    DIAG_CH_OVERCURRENT_CHARGE_CELL_RSL,            /* Overcurrent */
    DIAG_CH_OVERCURRENT_CHARGE_CELL_MOL,            /* Overcurrent */
    DIAG_CH_OVERCURRENT_DISCHARGE_CELL_MSL,         /* Overcurrent */
    DIAG_CH_OVERCURRENT_DISCHARGE_CELL_RSL,         /* Overcurrent */
    DIAG_CH_OVERCURRENT_DISCHARGE_CELL_MOL,         /* Overcurrent */
    DIAG_CH_OVERCURRENT_CHARGE_PL0_MSL,             /* Overcurrent */
    DIAG_CH_OVERCURRENT_CHARGE_PL0_RSL,             /* Overcurrent */
    DIAG_CH_OVERCURRENT_CHARGE_PL0_MOL,             /* Overcurrent */
    DIAG_CH_OVERCURRENT_CHARGE_PL1_MSL,             /* Overcurrent */
    DIAG_CH_OVERCURRENT_CHARGE_PL1_RSL,             /* Overcurrent */
    DIAG_CH_OVERCURRENT_CHARGE_PL1_MOL,             /* Overcurrent */
    DIAG_CH_OVERCURRENT_DISCHARGE_PL0_MSL,          /* Overcurrent */
    DIAG_CH_OVERCURRENT_DISCHARGE_PL0_RSL,          /* Overcurrent */
    DIAG_CH_OVERCURRENT_DISCHARGE_PL0_MOL,          /* Overcurrent */
    DIAG_CH_OVERCURRENT_DISCHARGE_PL1_MSL,          /* Overcurrent */
    DIAG_CH_OVERCURRENT_DISCHARGE_PL1_RSL,          /* Overcurrent */
    DIAG_CH_OVERCURRENT_DISCHARGE_PL1_MOL,          /* Overcurrent */
    DIAG_CH_OVERCURRENT_PL_NONE,
    DIAG_CH_LTC_SPI,                                /* LTC */
    DIAG_CH_LTC_PEC,                                /* LTC */
    DIAG_CH_LTC_MUX,                                /* LTC */
    DIAG_CH_LTC_CONFIG,                             /* LTC */

    /* Communication events: 50-63*/
    DIAG_CH_CAN_TIMING,  /* error in CAN timing */
    DIAG_CH_CAN_CC_RESPONDING, /* CAN C-C */
    DIAG_CH_CURRENT_SENSOR_RESPONDING, /* Current sensor not responding anymore */
    /* Contactor events: 69-77*/
    DIAG_CH_CONTACTOR_DAMAGED, /* Opening contactor at over current */
    DIAG_CH_CONTACTOR_OPENING, /* counter for contactor opening */
    DIAG_CH_CONTACTOR_CLOSING, /* counter for contactor closing */
    DIAG_CH_CONTACTOR_MAIN_PLUS_FEEDBACK, /* Contactor feedback error */
    DIAG_CH_CONTACTOR_MAIN_MINUS_FEEDBACK, /* Contactor feedback error */
    DIAG_CH_CONTACTOR_PRECHARGE_FEEDBACK, /* Contactor feedback error */
    DIAG_CH_CONTACTOR_CHARGE_MAIN_PLUS_FEEDBACK, /* Contactor feedback error */
    DIAG_CH_CONTACTOR_CHARGE_MAIN_MINUS_FEEDBACK, /* Contactor feedback error */
    DIAG_CH_CONTACTOR_CHARGE_PRECHARGE_FEEDBACK, /* Contactor feedback error */
    DIAG_CH_INTERLOCK_FEEDBACK, /* Interlock feedback error */
    DIAG_CH_SLAVE_PCB_UNDERTEMPERATURE_MSL,
    DIAG_CH_SLAVE_PCB_UNDERTEMPERATURE_RSL,
    DIAG_CH_SLAVE_PCB_UNDERTEMPERATURE_MOL,
    DIAG_CH_SLAVE_PCB_OVERTEMPERATURE_MSL,
    DIAG_CH_SLAVE_PCB_OVERTEMPERATURE_RSL,
    DIAG_CH_SLAVE_PCB_OVERTEMPERATURE_MOL,
    DIAG_CH_INSULATION_ERROR, /* Insulation error: measured insulation < threshold */
    DIAG_CH_FUSE_STATE_NORMAL, /* Fuse tripped */
    DIAG_CH_FUSE_STATE_CHARGE, /* Fuse tripped */
    DIAG_CH_ERROR_MCU_DIE_TEMPERATURE, /* MCU die temperature */
    DIAG_CH_LOW_COIN_CELL_VOLTAGE, /* coin cell voltage */
    DIAG_CH_CRIT_LOW_COIN_CELL_VOLTAGE, /* coin cell voltage */
    DIAG_CH_OPEN_WIRE, /* open-wire check */
    DIAG_CH_PLAUSIBILITY_CELL_VOLTAGE, /* plausibility checks */
    DIAG_CH_PLAUSIBILITY_CELL_TEMP, /* plausibility checks */
    DIAG_CH_PLAUSIBILITY_PACK_VOLTAGE, /* plausibility checks */
    DIAG_CH_DEEP_DISCHARGE_DETECTED, /* DoD was detected */
    DIAG_ID_MAX, /* MAX indicator - do not change */
} DIAG_CH_ID_e;

/** diagnosis check result (event) */
typedef enum {
    DIAG_EVENT_OK, /*!< diag channel event OK */
    DIAG_EVENT_NOK, /*!< diag channel event NOK */
    DIAG_EVENT_RESET, /*!< reset diag channel eventcounter to 0 */
} DIAG_EVENT_e;

/**
 * enable state of diagnosis entry
 */
typedef enum {
    DIAG_ENABLED,
    DIAG_DISABLED,
} DIAG_ENABLE_STATE_e;


#if CHECK_CAN_TIMING == TRUE
    #define DIAG_CAN_TIMING DIAG_ENABLED
#else
    #define DIAG_CAN_TIMING DIAG_DISABLED
#endif

#if CURRENT_SENSOR_PRESENT == TRUE
    #define DIAG_CAN_SENSOR_PRESENT DIAG_ENABLED
#else
    #define DIAG_CAN_SENSOR_PRESENT DIAG_DISABLED
#endif

/**
 * diagnosis recording activation
 */
typedef enum {
    DIAG_RECORDING_ENABLED,     /*!< enable diagnosis event recording   */
    DIAG_RECORDING_DISABLED,    /*!< disable diagnosis event recording  */
} DIAG_TYPE_RECORDING_e;

/*  FIXME some enums are typedefed with DIAG...TYPE_e, some with DIAG_TYPE..._e! Reconsider this */
/**
 * diagnosis types for system monitoring
 */
typedef enum {
    DIAG_SYSMON_CYCLICTASK, /*!< */
    DIAG_SYSMON_RESERVED,   /*!< */
} DIAG_SYSMON_TYPE_e;

/**
 * diagnosis handling type for system monitoring
 */
typedef enum {
    DIAG_SYSMON_HANDLING_DONOTHING,             /*!< */
    DIAG_SYSMON_HANDLING_SWITCHOFFCONTACTOR,    /*!< */
} DIAG_SYSMON_HANDLING_TYPE_e;


/**
 * @brief listing of system-relevant tasks or functions which are checked by system monitoring
 *
 * diag_sysmon_ch_cfg[]=
 */
typedef enum {
    DIAG_SYSMON_DATABASE_ID,        /*!< diag entry for database               */
    DIAG_SYSMON_SYS_ID,             /*!< diag entry for sys                    */
    DIAG_SYSMON_BMS_ID,             /*!< diag entry for bms                    */
    DIAG_SYSMON_CONT_ID,            /*!< diag entry for contactors             */
    DIAG_SYSMON_ILCK_ID,            /*!< diag entry for contactors             */
    DIAG_SYSMON_LTC_ID,             /*!< diag entry for ltc                    */
    DIAG_SYSMON_ISOGUARD_ID,        /*!< diag entry for isoguard               */
    DIAG_SYSMON_CANS_ID,            /*!< diag entry for can                    */
    DIAG_SYSMON_APPL_CYCLIC_1ms,    /*!< diag entry for application 10ms task  */
    DIAG_SYSMON_APPL_CYCLIC_10ms,   /*!< diag entry for application 10ms task  */
    DIAG_SYSMON_APPL_CYCLIC_100ms,  /*!< diag entry for application 100ms task */
    DIAG_SYSMON_MODULE_ID_MAX,      /*!< end marker do not delete              */
} DIAG_SYSMON_MODULE_ID_e;

/*  FIXME doxygen comment */
/*  FIXME is DIAG_CODE_s an appropriate name for this? */
typedef struct {
    uint32_t GENERALmsk;
    uint32_t CELLMONmsk;
    uint32_t COMmsk;
    uint32_t ADCmsk;
} DIAG_CODE_s;


/**
 * Channel configuration of one diag channel
*/
typedef struct {
    DIAG_CH_ID_e id;                        /*!< diagnosis event id diag_id */
    uint8_t description[40];
    uint16_t thresholds;                     /*!< threshold for number of events which will be tolerated before generating a notification in both direction (OK or NOT OK)
                                             *   threshold = 0: reports the value at first occurence, threshold = 1:reports the value at second occurence*/
    DIAG_TYPE_RECORDING_e enablerecording;  /*!< if enabled recording in diag_memory will be activated */
    DIAG_ENABLE_STATE_e state;              /*!< if enabled diagnosis event will be evaluated */
    void (*callbackfunc)(DIAG_CH_ID_e, DIAG_EVENT_e);     /*!< will be called if number of events exceeds threshold (in both direction) with parameter DIAG_EVENT_e */
} DIAG_CH_CFG_s;


/**
 * struct for device Configuration of diag module
 */
typedef struct {
    uint8_t nr_of_ch;       /*!< number of entries in DIAG_CH_CFG_s */
    DIAG_CH_CFG_s *ch_cfg;  /*!< pointer to diag channel config struct */
} DIAG_DEV_s;

/**
 * state (in summary) used for task or function notification
 */
typedef struct {
    uint32_t state;     /*!< state              */
    uint32_t timestamp; /*!< timestamp of state */
} DIAG_SYSMON_NOTIFICATION_s;


/**
 * Channel configuration of one system monitoring channel
 */
typedef struct {
    DIAG_SYSMON_MODULE_ID_e id;                     /*!< the diag type by its symbolic name            */
    DIAG_SYSMON_TYPE_e type;                        /*!< system monitoring types: cyclic or special    */
    uint16_t threshold;                             /*!< max. delay time in ms                         */
    DIAG_TYPE_RECORDING_e enablerecording;          /*!< enabled if set to DIAG_RECORDING_ENABLED      */
    DIAG_SYSMON_HANDLING_TYPE_e handlingtype;       /*!< type of handling of system monitoring errors  */
    DIAG_ENABLE_STATE_e state;                      /*!< enable or disable system monitoring           */
    void (*callbackfunc)(DIAG_SYSMON_MODULE_ID_e);  /*!< */
} DIAG_SYSMON_CH_CFG_s;

/*================== Extern Constant and Variable Declarations ==============*/
/**
 * diag device configuration struct
 */
extern DIAG_DEV_s diag_dev;

/**
 * diag system monitoring struct
 */
extern DIAG_SYSMON_CH_CFG_s diag_sysmon_ch_cfg[];
extern DIAG_CH_CFG_s  diag_ch_cfg[];

/*  FIXME why is it in header at all? and why is it in code at all? not used */
extern DIAG_CODE_s diag_mask;

/*================== Extern Function Prototypes =============================*/
/**
 * @brief update function for diagnosis flags (errors, MOL/RSL/MSL violations)
 */
extern void DIAG_updateFlags(void);

#endif /* DIAG_CFG_H_ */

diag_cfg.c (secondary)

/**
 *
 * @copyright &copy; 2010 - 2020, 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    diag_cfg.c
 * @author  foxBMS Team
 * @date    09.11.2015 (date of creation)
 * @ingroup ENGINE_CONF
 * @prefix  DIAG
 *
 * @brief   Diagnostic module configuration
 *
 * The configuration of the different diagnosis events defined in diag_cfg.h is set in the array
 * diag_ch_cfg[], e.g. initialization errors or runtime errors.
 *
 * Every entry of the diag_ch_cfg[] array consists of
 *  - name of the diagnosis event (defined in diag_cfg.h)
 *  - type of diagnosis event
 *  - diagnosis sensitivity (after how many occurrences event is counted as error)
 *  - enabling of the recording for diagnosis event
 *  - enabling of the diagnosis event
 *  - callback function for diagnosis event if wished, otherwise dummyfu
 *
 * The system monitoring configuration defined in diag_cfg.h is set in the array
 * diag_sysmon_ch_cfg[]. The system monitoring is at the moment only used for
 * supervising the cyclic/periodic tasks.
 *
 * Every entry of the diag_sysmon_ch_cfg[] consists of
 *  - enum of monitored object
 *  - type of monitored object (at the moment only DIAG_SYSMON_CYCLICTASK is supported)
 *  - maximum delay in [ms] in which the object needs to call the DIAG_SysMonNotify function defined in diag.c
 *  - enabling of the recording for system monitoring
 *  - enabling of the system monitoring for the monitored object
 *  - callback function if system monitoring notices an error if wished, otherwise dummyfu2
 */

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

#include "database.h"

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

/*================== Static Constant and Variable Definitions ===============*/
static DATA_BLOCK_ERRORSTATE_s error_flags = { 0 };
static DATA_BLOCK_MSL_FLAG_s msl_flags = { 0 };

/*================== Static Function Prototypes =============================*/
/* dummy functions */
static void dummyfu(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event);
static void dummyfu2(DIAG_SYSMON_MODULE_ID_e ch_id);

/* functions for SOA related events */
static void DIAG_overvoltage(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event);
static void DIAG_undervoltage(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event);
static void DIAG_overtemperature_charge(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event);
static void DIAG_overtemperature_discharge(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event);
static void DIAG_undertemperature_charge(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event);
static void DIAG_undertemperature_discharge(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event);

/* functions for system related events */
static void DIAG_error_ltc(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event);
static void DIAG_error_interlock(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event);
static void DIAG_error_MCUdieTemperature(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event);
static void DIAG_error_coinCellVoltage(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event);

/* functions for plausibility related events */
static void DIAG_error_plausibility_check(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event);

/*================== Extern Constant and Variable Definitions ===============*/
/**
 * Enable and Disable of Error Checks for Testing Purposes
 *
 * Each Bit enables or disables the diagnosis (checking of) the corresponding failure code
 * FIXME struct isn't used anywhere in the code at the moment.
 * FIXME delete if not needed
*/
DIAG_CODE_s diag_mask = {
        .GENERALmsk = 0xFFFFFFFF,
        .CELLMONmsk = 0xFFFFFFFF,
        .COMmsk = 0xFFFFFFFF,
        .ADCmsk = 0xFFFFFFFF,
};

DIAG_CH_CFG_s  diag_ch_cfg[] = {
    /* OS-Framework and startup events */
    {DIAG_CH_FLASHCHECKSUM,                             "FLASHCHECKSUM",                        DIAG_ERROR_SENSITIVITY_HIGH,              DIAG_RECORDING_ENABLED, DIAG_ENABLED, dummyfu},
    {DIAG_CH_BKPDIAG_FAILURE,                           "BKPDIAG",                              DIAG_ERROR_SENSITIVITY_HIGH,              DIAG_RECORDING_ENABLED, DIAG_ENABLED, dummyfu},
    {DIAG_CH_WATCHDOGRESET_FAILURE,                     "WATCHDOGRESET",                        DIAG_ERROR_SENSITIVITY_HIGH,              DIAG_RECORDING_ENABLED, DIAG_ENABLED, dummyfu},
    {DIAG_CH_POSTOSINIT_FAILURE,                        "POSTOSINIT",                           DIAG_ERROR_SENSITIVITY_HIGH,              DIAG_RECORDING_ENABLED, DIAG_ENABLED, dummyfu},
    {DIAG_CH_CALIB_EEPR_FAILURE,                        "CALIB_EEPR",                           DIAG_ERROR_SENSITIVITY_HIGH,              DIAG_RECORDING_ENABLED, DIAG_ENABLED, dummyfu},
    {DIAG_CH_CAN_INIT_FAILURE,                          "CAN_INIT",                             DIAG_ERROR_SENSITIVITY_HIGH,              DIAG_RECORDING_ENABLED, DIAG_ENABLED, dummyfu},
    {DIAG_CH_VIC_INIT_FAILURE,                          "VIC_INIT",                             DIAG_ERROR_SENSITIVITY_HIGH,              DIAG_RECORDING_ENABLED, DIAG_ENABLED, dummyfu},

    /* HW-/SW-Runtime events */
    {DIAG_CH_DIV_BY_ZERO_FAILURE,                       "DIV_BY_ZERO",                          DIAG_ERROR_SENSITIVITY_HIGH,              DIAG_RECORDING_ENABLED, DIAG_ENABLED, dummyfu},
    {DIAG_CH_UNDEF_INSTRUCTION_FAILURE,                 "UNDEF_INSTRUCTION",                    DIAG_ERROR_SENSITIVITY_HIGH,              DIAG_RECORDING_ENABLED, DIAG_ENABLED, dummyfu},
    {DIAG_CH_DATA_BUS_FAILURE,                          "DATA_BUS_FAILURE",                     DIAG_ERROR_SENSITIVITY_HIGH,              DIAG_RECORDING_ENABLED, DIAG_ENABLED, dummyfu},
    {DIAG_CH_INSTRUCTION_BUS_FAILURE,                   "INSTRUCTION_BUS",                      DIAG_ERROR_SENSITIVITY_HIGH,              DIAG_RECORDING_ENABLED, DIAG_ENABLED, dummyfu},
    {DIAG_CH_HARDFAULT_NOTHANDLED,                      "HARDFAULT_NOTHANDLED",                 DIAG_ERROR_SENSITIVITY_HIGH,              DIAG_RECORDING_ENABLED, DIAG_ENABLED, dummyfu},

    {DIAG_CH_CONFIGASSERT,                              "CONFIGASSERT",                         DIAG_ERROR_SENSITIVITY_HIGH,              DIAG_RECORDING_ENABLED, DIAG_ENABLED, dummyfu},
    {DIAG_CH_SYSTEMMONITORING_TIMEOUT,                  "SYSTEMMONITORING_TIMEOUT",             DIAG_ERROR_SENSITIVITY_HIGH,              DIAG_RECORDING_ENABLED, DIAG_ENABLED, dummyfu},


    /* Measurement events */
    {DIAG_CH_CANS_MAX_VALUE_VIOLATE,                    "CANS_MAX_VALUE_VIOLATE",               DIAG_ERROR_SENSITIVITY_HIGH,              DIAG_RECORDING_ENABLED, DIAG_ENABLED, dummyfu},
    {DIAG_CH_CANS_MIN_VALUE_VIOLATE,                    "CANS_MIN_VALUE_VIOLATE",               DIAG_ERROR_SENSITIVITY_HIGH,              DIAG_RECORDING_ENABLED, DIAG_ENABLED, dummyfu},
    {DIAG_CH_CANS_CAN_MOD_FAILURE,                      "CANS_CAN_MOD_FAILURE",                 DIAG_ERROR_SENSITIVITY_HIGH,              DIAG_RECORDING_ENABLED, DIAG_ENABLED, dummyfu},

#if BUILD_MODULE_ENABLE_ISOGUARD == 1
    {DIAG_CH_ISOMETER_TIM_ERROR,                        "ISOMETER_TIM_ERROR",                   DIAG_ERROR_SENSITIVITY_MID,               DIAG_RECORDING_ENABLED, DIAG_ENABLED, dummyfu},
    {DIAG_CH_ISOMETER_GROUNDERROR,                      "ISOMETER_GROUNDERROR",                 DIAG_ERROR_SENSITIVITY_HIGH,              DIAG_RECORDING_ENABLED, DIAG_ENABLED, dummyfu},
    {DIAG_CH_ISOMETER_ERROR,                            "ISOMETER_ERROR",                       DIAG_ERROR_SENSITIVITY_MID,               DIAG_RECORDING_ENABLED, DIAG_ENABLED, dummyfu},
    {DIAG_CH_ISOMETER_MEAS_INVALID,                     "ISOMETER_MEAS_INVALID",                DIAG_ERROR_SENSITIVITY_HIGH,              DIAG_RECORDING_ENABLED, DIAG_ENABLED, dummyfu},
#else
    {DIAG_CH_ISOMETER_TIM_ERROR,                        "ISOMETER_TIM_ERROR",                   DIAG_ERROR_SENSITIVITY_MID,               DIAG_RECORDING_DISABLED, DIAG_DISABLED, dummyfu},
    {DIAG_CH_ISOMETER_GROUNDERROR,                      "ISOMETER_GROUNDERROR",                 DIAG_ERROR_SENSITIVITY_HIGH,              DIAG_RECORDING_DISABLED, DIAG_DISABLED, dummyfu},
    {DIAG_CH_ISOMETER_ERROR,                            "ISOMETER_ERROR",                       DIAG_ERROR_SENSITIVITY_MID,               DIAG_RECORDING_DISABLED, DIAG_DISABLED, dummyfu},
    {DIAG_CH_ISOMETER_MEAS_INVALID,                     "ISOMETER_MEAS_INVALID",                DIAG_ERROR_SENSITIVITY_HIGH,              DIAG_RECORDING_DISABLED, DIAG_DISABLED, dummyfu},
#endif

    /* Under and over temperature, voltage and current at cell level */
    {DIAG_CH_CELLVOLTAGE_OVERVOLTAGE_MSL,             "CELLVOLT_OVERVOLT_MSL",            DIAG_ERROR_VOLTAGE_SENSITIVITY_MSL,          DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_overvoltage},
    {DIAG_CH_CELLVOLTAGE_UNDERVOLTAGE_MSL,            "CELLVOLT_UNDERVOLT_MSL",           DIAG_ERROR_VOLTAGE_SENSITIVITY_MSL,          DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_undervoltage},
    {DIAG_CH_TEMP_OVERTEMPERATURE_CHARGE_MSL,         "OVERTEMP_CHARGE_MSL",             DIAG_ERROR_TEMPERATURE_SENSITIVITY_MSL,       DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_overtemperature_charge},
    {DIAG_CH_TEMP_OVERTEMPERATURE_DISCHARGE_MSL,      "OVERTEMP_DISCHARGE_MSL",          DIAG_ERROR_TEMPERATURE_SENSITIVITY_MSL,       DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_overtemperature_discharge},
    {DIAG_CH_TEMP_UNDERTEMPERATURE_CHARGE_MSL,        "UNDERTEMP_CHARGE_MSL",            DIAG_ERROR_TEMPERATURE_SENSITIVITY_MSL,       DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_undertemperature_charge},
    {DIAG_CH_TEMP_UNDERTEMPERATURE_DISCHARGE_MSL,     "UNDERTEMP_DISCHARGE_MSL",         DIAG_ERROR_TEMPERATURE_SENSITIVITY_MSL,       DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_undertemperature_discharge},

    {DIAG_CH_LTC_SPI,                                   "LTC_SPI",                              DIAG_ERROR_LTC_SPI_SENSITIVITY,           DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_error_ltc},
    {DIAG_CH_LTC_PEC,                                   "LTC_PEC",                              DIAG_ERROR_LTC_PEC_SENSITIVITY,           DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_error_ltc},
    {DIAG_CH_LTC_MUX,                                   "LTC_MUX",                              DIAG_ERROR_LTC_MUX_SENSITIVITY,           DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_error_ltc},
    {DIAG_CH_LTC_CONFIG,                                "LTC_CONFIG",                           DIAG_ERROR_SENSITIVITY_HIGH,              DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_error_ltc},

#if BUILD_MODULE_ENABLE_ILCK == 1
    /* Interlock Feedback Error */
    {DIAG_CH_INTERLOCK_FEEDBACK,                        "INTERLOCK_FEEDBACK",                    DIAG_ERROR_INTERLOCK_SENSITIVITY,       DIAG_RECORDING_DISABLED, DIAG_DISABLED, DIAG_error_interlock},
#else
    {DIAG_CH_INTERLOCK_FEEDBACK,                        "INTERLOCK_FEEDBACK",                    DIAG_ERROR_INTERLOCK_SENSITIVITY,       DIAG_RECORDING_DISABLED, DIAG_DISABLED, DIAG_error_interlock},
#endif

    /* Slave PCB temperature errors for under and over temperature */
    {DIAG_CH_SLAVE_PCB_UNDERTEMPERATURE_MSL,          "SLAVE_PCB_UNDERTEMP_MSL",        DIAG_ERROR_SLAVE_TEMP_SENSITIVITY_MSL,   DIAG_RECORDING_ENABLED, DIAG_ENABLED, dummyfu},

    {DIAG_CH_SLAVE_PCB_OVERTEMPERATURE_MSL,           "SLAVE_PCB_OVERTEMP_MSL",         DIAG_ERROR_SLAVE_TEMP_SENSITIVITY_MSL,   DIAG_RECORDING_ENABLED, DIAG_ENABLED, dummyfu},
    {DIAG_CH_ERROR_MCU_DIE_TEMPERATURE,     "MCU_DIE_TEMPERATURE",      DIAG_ERROR_SENSITIVITY_LOW, DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_error_MCUdieTemperature},
    {DIAG_CH_LOW_COIN_CELL_VOLTAGE,         "COIN_CELL_VOLT_LOW",       DIAG_ERROR_SENSITIVITY_LOW, DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_error_coinCellVoltage},
    {DIAG_CH_CRIT_LOW_COIN_CELL_VOLTAGE,    "COIN_CELL_VOLT_CRITICAL",  DIAG_ERROR_SENSITIVITY_LOW, DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_error_coinCellVoltage},

    /* Plausibility checks */
    {DIAG_CH_PLAUSIBILITY_CELL_VOLTAGE,    "PL_CELL_VOLT",    DIAG_ERROR_SENSITIVITY_HIGH, DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_error_plausibility_check},
    {DIAG_CH_PLAUSIBILITY_CELL_TEMP,       "PL_CELL_TEMP",    DIAG_ERROR_SENSITIVITY_HIGH, DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_error_plausibility_check},
};


DIAG_SYSMON_CH_CFG_s diag_sysmon_ch_cfg[] = {
    {DIAG_SYSMON_DATABASE_ID,       DIAG_SYSMON_CYCLICTASK,  10, DIAG_RECORDING_ENABLED, DIAG_SYSMON_HANDLING_SWITCHOFFCONTACTOR, DIAG_ENABLED, dummyfu2},
    {DIAG_SYSMON_SYS_ID,        DIAG_SYSMON_CYCLICTASK,  20, DIAG_RECORDING_ENABLED, DIAG_SYSMON_HANDLING_SWITCHOFFCONTACTOR, DIAG_ENABLED, dummyfu2},
    {DIAG_SYSMON_BMS_ID,        DIAG_SYSMON_CYCLICTASK,  20, DIAG_RECORDING_ENABLED, DIAG_SYSMON_HANDLING_SWITCHOFFCONTACTOR, DIAG_ENABLED, dummyfu2},
#if BUILD_MODULE_ENABLE_ILCK == 1
    {DIAG_SYSMON_ILCK_ID,           DIAG_SYSMON_CYCLICTASK,  20, DIAG_RECORDING_ENABLED, DIAG_SYSMON_HANDLING_SWITCHOFFCONTACTOR, DIAG_ENABLED, dummyfu2},
#else
    {DIAG_SYSMON_ILCK_ID,           DIAG_SYSMON_CYCLICTASK,  20, DIAG_RECORDING_DISABLED, DIAG_SYSMON_HANDLING_SWITCHOFFCONTACTOR, DIAG_DISABLED, dummyfu2},
#endif
    {DIAG_SYSMON_LTC_ID,            DIAG_SYSMON_CYCLICTASK,   5, DIAG_RECORDING_ENABLED, DIAG_SYSMON_HANDLING_SWITCHOFFCONTACTOR, DIAG_ENABLED, dummyfu2},
    {DIAG_SYSMON_APPL_CYCLIC_1ms,   DIAG_SYSMON_CYCLICTASK,   2, DIAG_RECORDING_ENABLED, DIAG_SYSMON_HANDLING_SWITCHOFFCONTACTOR, DIAG_ENABLED, dummyfu2},
    {DIAG_SYSMON_APPL_CYCLIC_10ms,  DIAG_SYSMON_CYCLICTASK,  20, DIAG_RECORDING_ENABLED, DIAG_SYSMON_HANDLING_SWITCHOFFCONTACTOR, DIAG_ENABLED, dummyfu2},
    {DIAG_SYSMON_APPL_CYCLIC_100ms, DIAG_SYSMON_CYCLICTASK, 200, DIAG_RECORDING_ENABLED, DIAG_SYSMON_HANDLING_SWITCHOFFCONTACTOR, DIAG_ENABLED, dummyfu2},
};


DIAG_DEV_s  diag_dev = {
    .nr_of_ch   = sizeof(diag_ch_cfg)/sizeof(DIAG_CH_CFG_s),
    .ch_cfg     = &diag_ch_cfg[0],
};

/*================== Static Function Implementations ========================*/
/**
 * @brief  dummy callback function of diagnosis events
 */
void dummyfu(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event) {
    /* Dummy function -> empty */
}

/**
 * @brief  dummy callback function of system monitoring error events
 */
void dummyfu2(DIAG_SYSMON_MODULE_ID_e ch_id) {
    /* Dummy function -> empty */
}

/**
 * @brief  diagnosis callback function for overvoltage events
 */
static void DIAG_overvoltage(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event) {
    if (ch_id == DIAG_CH_CELLVOLTAGE_OVERVOLTAGE_MSL) {
        if (event == DIAG_EVENT_RESET) {
            msl_flags.over_voltage = 0;
        }
        if (event == DIAG_EVENT_NOK) {
            msl_flags.over_voltage = 1;
        }
    }
}

/**
 * @brief  diagnosis callback function for undervoltage events
 */
static void DIAG_undervoltage(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event) {
    if (ch_id == DIAG_CH_CELLVOLTAGE_UNDERVOLTAGE_MSL) {
        if (event == DIAG_EVENT_RESET) {
            msl_flags.under_voltage = 0;
        }
        if (event == DIAG_EVENT_NOK) {
            msl_flags.under_voltage = 1;
        }
    }
}

/**
 * @brief  diagnosis callback function for overtemperature charge events
 */
static void DIAG_overtemperature_charge(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event) {
    if (ch_id == DIAG_CH_TEMP_OVERTEMPERATURE_CHARGE_MSL) {
        if (event == DIAG_EVENT_RESET) {
            msl_flags.over_temperature_charge = 0;
        }
        if (event == DIAG_EVENT_NOK) {
            msl_flags.over_temperature_charge = 1;
        }
    }
}

/**
 * @brief  diagnosis callback function for overtemperature discharge events
 */
static void DIAG_overtemperature_discharge(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event) {
    if (ch_id == DIAG_CH_TEMP_OVERTEMPERATURE_DISCHARGE_MSL) {
        if (event == DIAG_EVENT_RESET) {
            msl_flags.over_temperature_discharge = 0;
        }
        if (event == DIAG_EVENT_NOK) {
            msl_flags.over_temperature_discharge = 1;
        }
    }
}

/**
 * @brief  diagnosis callback function for undertemperature charge events
 */
static void DIAG_undertemperature_charge(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event) {
    if (ch_id == DIAG_CH_TEMP_UNDERTEMPERATURE_CHARGE_MSL) {
        if (event == DIAG_EVENT_RESET) {
            msl_flags.under_temperature_charge = 0;
        }
        if (event == DIAG_EVENT_NOK) {
            msl_flags.under_temperature_charge = 1;
        }
    }
}

/**
 * @brief  diagnosis callback function for undertemperature discharge events
 */
static void DIAG_undertemperature_discharge(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event) {
    if (ch_id == DIAG_CH_TEMP_UNDERTEMPERATURE_DISCHARGE_MSL) {
        if (event == DIAG_EVENT_RESET) {
            msl_flags.under_temperature_discharge = 0;
        }
        if (event == DIAG_EVENT_NOK) {
            msl_flags.under_temperature_discharge = 1;
        }
    }
}

/**
 * @brief  diagnosis callback function for LTC module related events
 */
static void DIAG_error_ltc(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event) {
    if (ch_id == DIAG_CH_LTC_SPI) {
        if (event == DIAG_EVENT_RESET) {
            error_flags.spi_error = 0;
        }
        if (event == DIAG_EVENT_NOK) {
            error_flags.spi_error = 1;
        }
    } else if (ch_id == DIAG_CH_LTC_PEC) {
        if (event == DIAG_EVENT_RESET) {
            error_flags.crc_error = 0;
        }
        if (event == DIAG_EVENT_NOK) {
            error_flags.crc_error = 1;
        }
    } else if (ch_id == DIAG_CH_LTC_MUX) {
        if (event == DIAG_EVENT_RESET) {
            error_flags.mux_error = 0;
        }
        if (event == DIAG_EVENT_NOK) {
            error_flags.mux_error = 1;
        }
    } else if (ch_id == DIAG_CH_LTC_CONFIG) {
        if (event == DIAG_EVENT_RESET) {
            error_flags.ltc_config_error = 0;
        }
        if (event == DIAG_EVENT_NOK) {
            error_flags.ltc_config_error = 1;
        }
    }
}

/**
 * @brief  diagnosis callback function for interlock events
 */
void DIAG_error_interlock(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event) {
    if (ch_id == DIAG_CH_INTERLOCK_FEEDBACK) {
        if (event == DIAG_EVENT_RESET) {
            error_flags.interlock = 0;
        }
        if (event == DIAG_EVENT_NOK) {
            error_flags.interlock = 1;
        }
    }
}

/**
 * @brief  diagnosis callback function for MCU die temperature events
 */
void DIAG_error_MCUdieTemperature(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event) {
    if (ch_id == DIAG_CH_ERROR_MCU_DIE_TEMPERATURE) {
        if (event == DIAG_EVENT_RESET) {
            error_flags.mcuDieTemperature = 0;
        }
        if (event == DIAG_EVENT_NOK) {
            error_flags.mcuDieTemperature = 1;
        }
    }
}

/**
 * @brief  diagnosis callback function for coin cell voltage events
 */
void DIAG_error_coinCellVoltage(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event) {
    if (ch_id == DIAG_CH_LOW_COIN_CELL_VOLTAGE) {
        if (event  ==  DIAG_EVENT_RESET) {
            error_flags.coinCellVoltage &= 0xFE;
        }
        if (event == DIAG_EVENT_NOK) {
            error_flags.coinCellVoltage |= 0x01;
        }
    } else if (ch_id == DIAG_CH_CRIT_LOW_COIN_CELL_VOLTAGE) {
        if (event  ==  DIAG_EVENT_RESET) {
            error_flags.coinCellVoltage &= 0xFD;
        }
        if (event == DIAG_EVENT_NOK) {
            error_flags.coinCellVoltage |= 0x02;
        }
    }
}

/**
 * @brief  diagnosis callback function for plausibility events
 */
void DIAG_error_plausibility_check(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event) {
    if (ch_id == DIAG_CH_PLAUSIBILITY_CELL_VOLTAGE) {
        if (event  ==  DIAG_EVENT_RESET) {
            error_flags.plausibilityCheck &= 0xFE;
        }
        if (event == DIAG_EVENT_NOK) {
            error_flags.plausibilityCheck |= 0x01;
        }
    } else if (ch_id == DIAG_CH_PLAUSIBILITY_CELL_TEMP) {
        if (event  ==  DIAG_EVENT_RESET) {
            error_flags.plausibilityCheck &= 0xFD;
        }
        if (event == DIAG_EVENT_NOK) {
            error_flags.plausibilityCheck |= 0x02;
        }
    }
}
/*================== Extern Function Implementations ========================*/
void DIAG_updateFlags(void) {
    DB_WriteBlock(&error_flags, DATA_BLOCK_ID_ERRORSTATE);
    DB_WriteBlock(&msl_flags, DATA_BLOCK_ID_MSL);
}

diag_cfg.h (secondary)

/**
 *
 * @copyright &copy; 2010 - 2020, 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    diag_cfg.h
 * @author  foxBMS Team
 * @date    09.11.2015 (date of creation)
 * @ingroup ENGINE_CONF
 * @prefix  DIAG
 *
 * @brief   Diagnostic module configuration header
 *
 * In this header filer are the different diagnosis channel
 * defines assigned to different diagnosis IDs.
 *
 * Furthermore are the diagnosis error log settings be configured here..
 */

#ifndef DIAG_CFG_H_
#define DIAG_CFG_H_

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

#include "batterysystem_cfg.h"

/*================== Macros and Definitions =================================*/
#define DIAG_ERROR_SENSITIVITY_HIGH         (0)    /* logging at first event */
#define DIAG_ERROR_SENSITIVITY_MID          (5)    /* logging at fifth event */
#define DIAG_ERROR_SENSITIVITY_LOW          (10)   /* logging at tenth event */

#define DIAG_ERROR_VOLTAGE_SENSITIVITY_MSL      (500)   /*!< MSL level for event occurrence if over/under voltage event   */
#define DIAG_ERROR_TEMPERATURE_SENSITIVITY_MSL  (500)   /*!< MSL level for event occurrence if over/under temperature event    */
#define DIAG_ERROR_CURRENT_SENSITIVITY_MSL      (500)   /*!< MSL level for event occurrence if over/under current event        */

#define DIAG_ERROR_SLAVE_TEMP_SENSITIVITY_MSL   (500)   /*!< MSL level for event occurrence if slave PCB temperature event     */

#define DIAG_ERROR_LTC_PEC_SENSITIVITY          (5)
#define DIAG_ERROR_LTC_MUX_SENSITIVITY          (5)
#define DIAG_ERROR_LTC_SPI_SENSITIVITY          (5)

#define DIAG_ERROR_CAN_TIMING_SENSITIVITY       (100)
#define DIAG_ERROR_CAN_TIMING_CC_SENSITIVITY    (100)
#define DIAG_ERROR_CAN_SENSOR_SENSITIVITY       (100)

#define DIAG_ERROR_MAIN_PLUS_SENSITIVITY        (50)
#define DIAG_ERROR_MAIN_MINUS_SENSITIVITY       (50)
#define DIAG_ERROR_PRECHARGE_SENSITIVITY        (50)

#define DIAG_ERROR_INTERLOCK_SENSITIVITY        (10)

/** Number of errors that can be logged */
#define DIAG_FAIL_ENTRY_LENGTH              (50)

/** Maximum number of the same errors that are logged */
#define DIAG_MAX_ENTRIES_OF_ERROR           (5)

/** Number of contactor errors that are logged */
#define DIAG_FAIL_ENTRY_CONTACTOR_LENGTH    (50)


typedef enum {
    DIAG_CH_FLASHCHECKSUM,                          /*  */
    DIAG_CH_BKPDIAG_FAILURE,                        /*  */
    DIAG_CH_WATCHDOGRESET_FAILURE,                  /*  */
    DIAG_CH_POSTOSINIT_FAILURE,                     /*  */
    DIAG_CH_CALIB_EEPR_FAILURE,                     /*  */
    DIAG_CH_CAN_INIT_FAILURE,                       /*  */
    DIAG_CH_VIC_INIT_FAILURE,
    /* HW-/SW-Runtime events: 16-31 */
    DIAG_CH_DIV_BY_ZERO_FAILURE,                    /*  */
    DIAG_CH_UNDEF_INSTRUCTION_FAILURE,              /*  */
    DIAG_CH_DATA_BUS_FAILURE,                       /*  */
    DIAG_CH_INSTRUCTION_BUS_FAILURE,                /*  */
    DIAG_CH_HARDFAULT_NOTHANDLED,                   /*  */
    DIAG_CH_RUNTIME_ERROR_RESERVED_1,               /*  reserved for future needs */
    DIAG_CH_RUNTIME_ERROR_RESERVED_2,               /*  reserved for future needs */
    DIAG_CH_RUNTIME_ERROR_RESERVED_3,               /*  reserved for future needs */
    DIAG_CH_CONFIGASSERT,                           /*  */
    DIAG_CH_SYSTEMMONITORING_TIMEOUT,               /*  */
    /* Measurement events: 32-47 */
    DIAG_CH_CANS_MAX_VALUE_VIOLATE,
    DIAG_CH_CANS_MIN_VALUE_VIOLATE,
    DIAG_CH_CANS_CAN_MOD_FAILURE,
    DIAG_CH_ISOMETER_TIM_ERROR,                     /* Measured frequency too low or no new value captured during last cycle */
    DIAG_CH_ISOMETER_GROUNDERROR,                   /* Ground error detected */
    DIAG_CH_ISOMETER_ERROR,                         /* Device error, invalid measurement result */
    DIAG_CH_ISOMETER_MEAS_INVALID,                  /* Measurement trustworthy or not, hysteresis to ground error flag */
    DIAG_CH_CELLVOLTAGE_OVERVOLTAGE_MSL,            /* Cell voltage limits violated */
    DIAG_CH_CELLVOLTAGE_UNDERVOLTAGE_MSL,           /* Cell voltage limits violated */
    DIAG_CH_TEMP_OVERTEMPERATURE_CHARGE_MSL,        /* Temperature limits violated */
    DIAG_CH_TEMP_OVERTEMPERATURE_DISCHARGE_MSL,     /* Temperature limits violated */
    DIAG_CH_TEMP_UNDERTEMPERATURE_CHARGE_MSL,       /* Temperature limits violated */
    DIAG_CH_TEMP_UNDERTEMPERATURE_DISCHARGE_MSL,    /* Temperature limits violated */
    DIAG_CH_LTC_SPI,                                /* LTC */
    DIAG_CH_LTC_PEC,                                /* LTC */
    DIAG_CH_LTC_MUX,                                /* LTC */
    DIAG_CH_LTC_CONFIG,                             /* LTC */

/* Contactor events: 64-79 */
    DIAG_CH_CONTACTOR_DAMAGED, /* Opening contactor at over current */
    DIAG_CH_CONTACTOR_OPENING, /* counter for contactor opening */
    DIAG_CH_CONTACTOR_CLOSING, /* counter for contactor closing */
    DIAG_CH_INTERLOCK_FEEDBACK, /* Interlock feedback error */
    DIAG_CH_SLAVE_PCB_UNDERTEMPERATURE_MSL,
    DIAG_CH_SLAVE_PCB_OVERTEMPERATURE_MSL,
    DIAG_CH_ERROR_MCU_DIE_TEMPERATURE, /* MCU die temperature */
    DIAG_CH_LOW_COIN_CELL_VOLTAGE, /* coin cell voltage */
    DIAG_CH_CRIT_LOW_COIN_CELL_VOLTAGE, /* coin cell voltage */
    DIAG_CH_PLAUSIBILITY_CELL_VOLTAGE, /* plausibility checks */
    DIAG_CH_PLAUSIBILITY_CELL_TEMP, /* plausibility checks */
    DIAG_ID_MAX, /* MAX indicator - do not change */
} DIAG_CH_ID_e;

/** diagnosis check result (event) */
typedef enum {
    DIAG_EVENT_OK, /*!< diag channel event OK */
    DIAG_EVENT_NOK, /*!< diag channel event NOK */
    DIAG_EVENT_RESET, /*!< reset diag channel eventcounter to 0 */
} DIAG_EVENT_e;

/**
 * enable state of diagnosis entry
 */
typedef enum {
    DIAG_ENABLED,
    DIAG_DISABLED,
} DIAG_ENABLE_STATE_e;


/**
 * diagnosis recording activation
 */
typedef enum {
    DIAG_RECORDING_ENABLED,    /*!< enable diagnosis event recording   */
    DIAG_RECORDING_DISABLED,    /*!< disable diagnosis event recording  */
} DIAG_TYPE_RECORDING_e;

/*  FIXME some enums are typedefed with DIAG...TYPE_e, some with DIAG_TYPE..._e! Reconsider this */
/**
 * diagnosis types for system monitoring
 */
typedef enum {
    DIAG_SYSMON_CYCLICTASK, /*!< */
    DIAG_SYSMON_RESERVED,   /*!< */
} DIAG_SYSMON_TYPE_e;

/**
 * diagnosis handling type for system monitoring
 */
typedef enum {
    DIAG_SYSMON_HANDLING_DONOTHING,             /*!< */
    DIAG_SYSMON_HANDLING_SWITCHOFFCONTACTOR,    /*!< */
} DIAG_SYSMON_HANDLING_TYPE_e;


/**
 * @brief listing of system-relevant tasks or functions which are checked by system monitoring
 *
 * diag_sysmon_ch_cfg[]=
 */
typedef enum {
    DIAG_SYSMON_DATABASE_ID,        /*!< diag entry for database                */
    DIAG_SYSMON_SYS_ID,             /*!< diag entry for sys              */
    DIAG_SYSMON_BMS_ID,             /*!< diag entry for bms              */
    DIAG_SYSMON_ILCK_ID,            /*!< diag entry for bms              */
    DIAG_SYSMON_LTC_ID,             /*!< diag entry for ltc                     */
    DIAG_SYSMON_APPL_CYCLIC_1ms,    /*!< diag entry for application 10ms task   */
    DIAG_SYSMON_APPL_CYCLIC_10ms,   /*!< diag entry for application 10ms task   */
    DIAG_SYSMON_APPL_CYCLIC_100ms,  /*!< diag entry for application 100ms task  */
    DIAG_SYSMON_MODULE_ID_MAX,      /*!< end marker do not delete               */
} DIAG_SYSMON_MODULE_ID_e;

/*  FIXME doxygen comment */
/*  FIXME is DIAG_CODE_s an appropriate name for this? */
typedef struct {
    uint32_t GENERALmsk;
    uint32_t CELLMONmsk;
    uint32_t COMmsk;
    uint32_t ADCmsk;
} DIAG_CODE_s;


/**
 * Channel configuration of one diag channel
*/
typedef struct {
    DIAG_CH_ID_e id;                        /*!< diagnosis event id diag_id */
    uint8_t description[40];
    uint16_t thresholds;                     /*!< threshold for number of events which will be tolerated before generating a notification in both direction (OK or NOT OK)
                                             *   threshold = 0: reports the value at first occurence, threshold = 1:reports the value at second occurence*/
    DIAG_TYPE_RECORDING_e enablerecording;  /*!< if enabled recording in diag_memory will be activated */
    DIAG_ENABLE_STATE_e state;              /*!< if enabled diagnosis event will be evaluated */
    void (*callbackfunc)(DIAG_CH_ID_e, DIAG_EVENT_e);     /*!< will be called if number of events exceeds threshold (in both direction) with parameter DIAG_EVENT_e */
} DIAG_CH_CFG_s;


/**
 * struct for device Configuration of diag module
 */
typedef struct {
    uint8_t nr_of_ch;       /*!< number of entries in DIAG_CH_CFG_s */
    DIAG_CH_CFG_s *ch_cfg;  /*!< pointer to diag channel config struct */
} DIAG_DEV_s;

/**
 * state (in summary) used for task or function notification
 */
typedef struct {
    uint32_t state;     /*!< state              */
    uint32_t timestamp; /*!< timestamp of state */
} DIAG_SYSMON_NOTIFICATION_s;


/**
 * Channel configuration of one system monitoring channel
 */
typedef struct {
    DIAG_SYSMON_MODULE_ID_e id;                     /*!< the diag type by its symbolic name            */
    DIAG_SYSMON_TYPE_e type;                        /*!< system monitoring types: cyclic or special    */
    uint16_t threshold;                             /*!< max. delay time in ms                         */
    DIAG_TYPE_RECORDING_e enablerecording;          /*!< enabled if set to DIAG_RECORDING_ENABLED      */
    DIAG_SYSMON_HANDLING_TYPE_e handlingtype;       /*!< type of handling of system monitoring errors  */
    DIAG_ENABLE_STATE_e state;                      /*!< enable or disable system monitoring           */
    void (*callbackfunc)(DIAG_SYSMON_MODULE_ID_e);  /*!< */
} DIAG_SYSMON_CH_CFG_s;

/*================== Extern Constant and Variable Declarations ==============*/
/**
 * diag device configuration struct
 */
extern DIAG_DEV_s diag_dev;

/**
 * diag system monitoring struct
 */
extern DIAG_SYSMON_CH_CFG_s diag_sysmon_ch_cfg[];
extern DIAG_CH_CFG_s  diag_ch_cfg[];

/*  FIXME why is it in header at all? and why is it in code at all? not used */
extern DIAG_CODE_s diag_mask;

/*================== Extern Function Prototypes =============================*/
/**
 * @brief update function for diagnosis flags (errors, MOL/RSL/MSL violations)
 */
extern void DIAG_updateFlags(void);

#endif /* DIAG_CFG_H_ */