diag.c (primary)

/**
 *
 * @copyright © 2010 - 2018, 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   Diag 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"

#include "contactor.h"
#include "com.h"
#include "os.h"
#include "misc.h"
#include "nvramhandler.h"
#include "rtc.h"

/*================== 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;

// FIXME unused
// FIXME do you really want to have global variables?
DIAG_CODE_s diag_err;
DIAG_CODE_s diag_warn;
DIAG_OCCURRENCE_COUNTERS_s diag_occurrence_counters;

//uint32_t diag_error;

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);
static DIAG_RETURNTYPE_e DIAG_GeneralHandler(DIAG_CH_ID_e diag_ch_id, DIAG_EVENT_e event, uint32_t item_nr);
static DIAG_RETURNTYPE_e DIAG_ContHandler(DIAG_CH_ID_e eventID, uint32_t cont_nr, float* openingCur);

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

/**
 * @brief   DIAG_Reset resets/initalizes all needed strcutures/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, NULL));
    }
    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? */

    uint8_t buf[24] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};

    if(diag_entry_rdptr == diag_entry_wrptr)
    {
        DEBUG_PRINTF((const uint8_t * )"no new entries in DIAG");
        DEBUG_PRINTF((const uint8_t * )"\r\n");
    }
    else
    {
        DEBUG_PRINTF((const uint8_t * )"DIAG error entries:");
        DEBUG_PRINTF((const uint8_t * )"\r\n");
        DEBUG_PRINTF((const uint8_t * )"Date and Time:      Error Code/Item   Status     Description");
        DEBUG_PRINTF((const uint8_t * )"\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];
        }

        DEBUG_PRINTF(U8ToDecascii(buf, &diag_entry_rdptr->DD, 2));
        DEBUG_PRINTF((const uint8_t * )".");
        DEBUG_PRINTF(U8ToDecascii(buf, &diag_entry_rdptr->MM, 2));
        DEBUG_PRINTF((const uint8_t * )".");
        DEBUG_PRINTF(U8ToDecascii(buf, &diag_entry_rdptr->YY, 2));
        DEBUG_PRINTF((const uint8_t * )" - ");
        DEBUG_PRINTF(U8ToDecascii(buf, &diag_entry_rdptr->hh, 2));
        DEBUG_PRINTF((const uint8_t * )":");
        DEBUG_PRINTF(U8ToDecascii(buf, &diag_entry_rdptr->mm, 2));
        DEBUG_PRINTF((const uint8_t * )":");
        DEBUG_PRINTF(U8ToDecascii(buf, &diag_entry_rdptr->ss, 2));
        DEBUG_PRINTF((const uint8_t * )"     ");
        DEBUG_PRINTF(U8ToDecascii(buf, (uint8_t*)(&diag_entry_rdptr->event_id), 2));

        DEBUG_PRINTF((const uint8_t * )" / 0x");
        DEBUG_PRINTF(U32ToHexascii(buf, &diag_entry_rdptr->item));
        DEBUG_PRINTF((const uint8_t * )"      ");

        if(diag_entry_rdptr->event == DIAG_EVENT_OK)
            DEBUG_PRINTF((const uint8_t * )"cleared     ");
        else if(diag_entry_rdptr->event == DIAG_EVENT_NOK)
            DEBUG_PRINTF((const uint8_t * )"occurred    ");
        else
            DEBUG_PRINTF((const uint8_t * )"reset       ");

        for(uint8_t i = 0; i < 24; i++)
            buf[i] = diag_devptr->ch_cfg[diag.id2ch[diag_entry_rdptr->event_id]].description[i];

        DEBUG_PRINTF((const uint8_t *)buf);
        DEBUG_PRINTF((const uint8_t * )"\r\n");

        diag_entry_rdptr++;
        c++;

    }

    // More entries in diag buffer
    if(diag_entry_rdptr != diag_entry_wrptr)
        DEBUG_PRINTF((const uint8_t * )"Please repeat command. Additional error entries in DIAG buffer available!\r\n");

}

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? */

    uint8_t buf[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
    int32_t tmp = 0;
    DIAG_CONTACTOR_s diagContactor;

    NVM_Get_contactorcnt(&diagContactor);

    DEBUG_PRINTF((const uint8_t * )"Contactor switching entries:");
    DEBUG_PRINTF((const uint8_t * )"\r\n");

    for(uint8_t i = 0; i < BS_NR_OF_CONTACTORS; i++) {
        DEBUG_PRINTF((const uint8_t * )"Contactor ");
        DEBUG_PRINTF(U8ToDecascii(buf, &i, 2));
        DEBUG_PRINTF((const uint8_t * )"\r\nOpening switches: ");
        DEBUG_PRINTF(U16ToHexascii(buf, &diagContactor.cont_switch_opened[i]));
        DEBUG_PRINTF((const uint8_t * )"\r\nClosing switches: ");
        DEBUG_PRINTF(U16ToHexascii(buf, &diagContactor.cont_switch_closed[i]));
        DEBUG_PRINTF((const uint8_t * )"\r\nOpening switches hard at current: ");
        DEBUG_PRINTF(U16ToHexascii(buf, &diagContactor.cont_switch_opened_hard_at_current[i]));
        DEBUG_PRINTF((const uint8_t * )"\r\n\n");
        DEBUG_PRINTF((const uint8_t * )"\r\n");
    }

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



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

        DEBUG_PRINTF(U8ToDecascii(buf, &diagContactorError_entry_rdptr->DD, 2));
        DEBUG_PRINTF((const uint8_t * )".");
        DEBUG_PRINTF(U8ToDecascii(buf, &diagContactorError_entry_rdptr->MM, 2));
        DEBUG_PRINTF((const uint8_t * )".");
        DEBUG_PRINTF(U8ToDecascii(buf, &diagContactorError_entry_rdptr->YY, 2));
        DEBUG_PRINTF((const uint8_t * )" - ");
        DEBUG_PRINTF(U8ToDecascii(buf, &diagContactorError_entry_rdptr->hh, 2));
        DEBUG_PRINTF((const uint8_t * )":");
        DEBUG_PRINTF(U8ToDecascii(buf, &diagContactorError_entry_rdptr->mm, 2));
        DEBUG_PRINTF((const uint8_t * )":");
        DEBUG_PRINTF(U8ToDecascii(buf, &diagContactorError_entry_rdptr->ss, 2));
        DEBUG_PRINTF((const uint8_t * )"     ");

        DEBUG_PRINTF(U8ToDecascii(buf, (uint8_t*)(&diagContactorError_entry_rdptr->contactor), 2));
        DEBUG_PRINTF((const uint8_t * )"        ");
        tmp = (int32_t)diagContactorError_entry_rdptr->openingCurrent;
        DEBUG_PRINTF(I32ToDecascii(buf, &tmp));
        DEBUG_PRINTF((const uint8_t * )"mA\r\n");

        diagContactorError_entry_rdptr++;
    }

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

}


/**
 * @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;
    uint8_t buf[25] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; // max. description length = 24 + 1 to identify end of array

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

    if(diag.entry_event[eventID] == event)
        return ret_val;        // same event of same error type already recorded before -> ignore until event toggles
    if((diag.entry_event[eventID] == DIAG_EVENT_OK) && (event ==  DIAG_EVENT_RESET))
        return ret_val;     // 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

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

    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;
    DEBUG_PRINTF((const uint8_t * )"New Error entry! (");
    c = (uint8_t) diag.errcntreported;
    DEBUG_PRINTF(U8ToDecascii(buf, &c,3));
    DEBUG_PRINTF((const uint8_t * )"): Error Code/Item ");
    DEBUG_PRINTF(U8ToDecascii(buf, &eventID, 3));
    DEBUG_PRINTF((const uint8_t * )"/0x");
    DEBUG_PRINTF(U32ToHexascii(buf, &item_nr));
    DEBUG_PRINTF((const uint8_t * )" ");

    // Copy error description  in buffer, maximum description length = 24 characters
    for(uint8_t i = 0; i < 24; i++)
        buf[i] = diag_devptr->ch_cfg[diag.id2ch[eventID]].description[i];

    DEBUG_PRINTF((const uint8_t *)buf);

    if(event==DIAG_EVENT_OK)
        DEBUG_PRINTF((const uint8_t * )" cleared");
    else if (event==DIAG_EVENT_NOK)
        DEBUG_PRINTF((const uint8_t * )" occurred");
    else // DIAG_EVENT_RESET
        DEBUG_PRINTF((const uint8_t * )" reset");

    DEBUG_PRINTF((const uint8_t * )"\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, void* data) {

    DIAG_RETURNTYPE_e retVal = DIAG_HANDLER_RETURN_UNKNOWN;

    /* Get diagnosis type */
    DIAG_TYPE_e diagType = diag_dev.ch_cfg[diag.id2ch[diag_ch_id]].type;

    switch(diagType) {
    /* Call handler function depending on diagnosis type */

        case DIAG_GENERAL_TYPE:
            retVal = DIAG_GeneralHandler(diag_ch_id, event, item_nr);
            break;

        case DIAG_CELLMON_TYPE:
            break;

        case DIAG_COM_TYPE:
            break;

        case DIAG_ADC_TYPE:
            break;

        case DIAG_CONT_TYPE:
            // item_nr is contactor number
            retVal = DIAG_ContHandler(diag_ch_id, item_nr, (float*) data);
            break;

        default:
            break;

    }

    return retVal;
}


/**
 * @brief DIAG_GeneralHandler provides generic error handling, based on configuration.
 *
 * This function does all the handling based on the user defined configuration.
 * According to its return value further treatment is left to the calling module itself.
 * @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_STATE_UNINITIALIZED if diag module still uninitialized,\n
 *           DIAG_HANDLER_RETURN_WRONG_ID if invalid diag id,\n
 *           DIAG_HANDLER_INVALID_TYPE if diag id doesn't correspond to diag type,\n
 *           DIAG_HANDLER_RETURN_OK if error/warning occurred but no threshold reached or event = DIAG_EVENT_OK/DIAG_EVENT_RESET,\n
 *           DIAG_HANDLER_RETURN_ERR_OCCURRED if error threshold reached,\n
 *           DIAG_HANDLER_RETURN_WARNING_OCCURRED if warning threshold reached,\n
 */
static DIAG_RETURNTYPE_e DIAG_GeneralHandler(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
            }
        }
        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);
}


/**
 * @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
 */
static 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;
            uint8_t buf[9] = {0, 0, 0, 0, 0, 0, 0, 0, 0};

            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++;

            DEBUG_PRINTF((const uint8_t * )"new Contactor error entry! currently ");
            uint8_t tmp = (uint8_t)diagContactor.errcntreported;
            DEBUG_PRINTF(U8ToDecascii(buf, &tmp, 2));
            DEBUG_PRINTF((const uint8_t * )" error entrys");
            DEBUG_PRINTF((const uint8_t * )"\r\n");
        }
    }
    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 curren */
            NVRAM_setWriteRequest(NVRAM_BLOCK_ID_CONT_COUNTER);
        }
    }
    return retVal;
}


/**
 * @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, NULL);
                    }

                    if(diag_sysmon_ch_cfg[module_id].handlingtype == DIAG_SYSMON_HANDLING_SWITCHOFFCONTACTOR) {
                        // system not working trustfully, switch off contactors!
                        CONT_SwitchAllContactorsOff();
                    }
                    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, NULL);
#endif

    while (1) {
        ;
    }
}

diag.h (primary)

/**
 *
 * @copyright &copy; 2010 - 2018, 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   Diag driver header
 *
 */

#ifndef DIAG_H_
#define DIAG_H_

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

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

//FIXME Why is there no 1 in following enum?
/** diagnosis handler return types */
typedef enum {
    DIAG_HANDLER_RETURN_OK                  = 0,            /*!<  error not occured or occured but threshold not reached */
    DIAG_HANDLER_RETURN_ERR_OCCURED         = 2,            /*!<  error occured and enabled */
    DIAG_HANDLER_RETURN_WARNING_OCCURRED    = 3,            /*!<  warning occured (error occured but not enabled) */
    DIAG_HANDLER_RETURN_ERR_OCCURRED        = 4,            /*!<  error occured and enabled */
    DIAG_HANDLER_RETURN_WRONG_ID            = 5,            /*!<  wrong diagnosis id */
    DIAG_HANDLER_RETURN_UNKNOWN             = 6,            /*!<  unknown return type */
    DIAG_HANDLER_INVALID_TYPE               = 7,            /*!<  invalid diagnosis type, error in configuration */
    DIAG_HANDLER_INVALID_DATA               = 8,            /*!<  invalid data, dependent of the diagHandler */
    DIAG_HANDLER_RETURN_NOT_READY           = 0xFFFFFFFF,   /*!<  diagnosis handler not ready */
} DIAG_RETURNTYPE_e;

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

/**
 * Counters for error and warning thresholds
 */
typedef struct {
    uint8_t GENERALerrcnt[32];
    uint8_t CELLMONerrcnt[32];
    uint8_t COMerrcnt[32];
    uint8_t ADCerrcnt[32];
} DIAG_OCCURRENCE_COUNTERS_s;

/**
 * structure of failure code 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;

// FIXME doxygen comment missing, maybe even with explanation of struct member or use ///< comments
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;
// FIXME doxygen comment missing
//extern DIAG_s diag;

/*================== 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
 * @param   data:       pointer to data if DIAG_CONT_TYPE
 *
 * @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, void*  data);

/**
 * @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);

/**
 * @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);

/**
 * @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);

/**
 * @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.c (secondary)

/**
 *
 * @copyright &copy; 2010 - 2018, 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.c
 * @author  foxBMS Team
 * @date    09.11.2015 (date of creation)
 * @ingroup ENGINE
 * @prefix  DIAG
 *
 * @brief   Diag 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"

#include "com.h"
#include "misc.h"
#include "os.h"
#include "rtc.h"

/*================== 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;

// FIXME unused
// FIXME do you really want to have global variables?
DIAG_CODE_s diag_err;
DIAG_CODE_s diag_warn;
DIAG_OCCURRENCE_COUNTERS_s diag_occurrence_counters;

//uint32_t diag_error;

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);
static DIAG_RETURNTYPE_e DIAG_GeneralHandler(DIAG_CH_ID_e diag_ch_id, DIAG_EVENT_e event, uint32_t item_nr);

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

/**
 * @brief   DIAG_Reset resets/initalizes all needed strcutures/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, NULL));
    }
    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? */

    uint8_t buf[24] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};

    if(diag_entry_rdptr == diag_entry_wrptr)
    {
        DEBUG_PRINTF((const uint8_t * )"no new entries in DIAG");
        DEBUG_PRINTF((const uint8_t * )"\r\n");
    }
    else
    {
        DEBUG_PRINTF((const uint8_t * )"DIAG error entries:");
        DEBUG_PRINTF((const uint8_t * )"\r\n");
        DEBUG_PRINTF((const uint8_t * )"Date and Time:      Error Code/Item   Status     Description");
        DEBUG_PRINTF((const uint8_t * )"\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];
        }

        DEBUG_PRINTF(U8ToDecascii(buf, &diag_entry_rdptr->DD, 2));
        DEBUG_PRINTF((const uint8_t * )".");
        DEBUG_PRINTF(U8ToDecascii(buf, &diag_entry_rdptr->MM, 2));
        DEBUG_PRINTF((const uint8_t * )".");
        DEBUG_PRINTF(U8ToDecascii(buf, &diag_entry_rdptr->YY, 2));
        DEBUG_PRINTF((const uint8_t * )" - ");
        DEBUG_PRINTF(U8ToDecascii(buf, &diag_entry_rdptr->hh, 2));
        DEBUG_PRINTF((const uint8_t * )":");
        DEBUG_PRINTF(U8ToDecascii(buf, &diag_entry_rdptr->mm, 2));
        DEBUG_PRINTF((const uint8_t * )":");
        DEBUG_PRINTF(U8ToDecascii(buf, &diag_entry_rdptr->ss, 2));
        DEBUG_PRINTF((const uint8_t * )"     ");
        DEBUG_PRINTF(U8ToDecascii(buf, (uint8_t*)(&diag_entry_rdptr->event_id), 2));

        DEBUG_PRINTF((const uint8_t * )" / 0x");
        DEBUG_PRINTF(U32ToHexascii(buf, &diag_entry_rdptr->item));
        DEBUG_PRINTF((const uint8_t * )"      ");

        if(diag_entry_rdptr->event == DIAG_EVENT_OK)
            DEBUG_PRINTF((const uint8_t * )"cleared     ");
        else if(diag_entry_rdptr->event == DIAG_EVENT_NOK)
            DEBUG_PRINTF((const uint8_t * )"occurred    ");
        else
            DEBUG_PRINTF((const uint8_t * )"reset       ");

        for(uint8_t i = 0; i < 24; i++)
            buf[i] = diag_devptr->ch_cfg[diag.id2ch[diag_entry_rdptr->event_id]].description[i];

        DEBUG_PRINTF((const uint8_t *)buf);
        DEBUG_PRINTF((const uint8_t * )"\r\n");

        diag_entry_rdptr++;
        c++;

    }

    // More entries in diag buffer
    if(diag_entry_rdptr != diag_entry_wrptr)
        DEBUG_PRINTF((const uint8_t * )"Please repeat command. Additional error entries in DIAG buffer available!\r\n");

}


/**
 * @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;
    uint8_t buf[25] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; // max. description length = 24 + 1 to identify end of array

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

    if(diag.entry_event[eventID] == event)
        return ret_val;        // same event of same error type already recorded before -> ignore until event toggles
    if((diag.entry_event[eventID] == DIAG_EVENT_OK) && (event ==  DIAG_EVENT_RESET))
        return ret_val;     // 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

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

    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;
    DEBUG_PRINTF((const uint8_t * )"New Error entry! (");
    c = (uint8_t) diag.errcntreported;
    DEBUG_PRINTF(U8ToDecascii(buf, &c,3));
    DEBUG_PRINTF((const uint8_t * )"): Error Code/Item ");
    DEBUG_PRINTF(U8ToDecascii(buf, &eventID, 3));
    DEBUG_PRINTF((const uint8_t * )"/0x");
    DEBUG_PRINTF(U32ToHexascii(buf, &item_nr));
    DEBUG_PRINTF((const uint8_t * )" ");

    // Copy error description  in buffer, maximum description length = 24 characters
    for(uint8_t i = 0; i < 24; i++)
        buf[i] = diag_devptr->ch_cfg[diag.id2ch[eventID]].description[i];

    DEBUG_PRINTF((const uint8_t *)buf);

    if(event==DIAG_EVENT_OK)
        DEBUG_PRINTF((const uint8_t * )" cleared");
    else if (event==DIAG_EVENT_NOK)
        DEBUG_PRINTF((const uint8_t * )" occurred");
    else // DIAG_EVENT_RESET
        DEBUG_PRINTF((const uint8_t * )" reset");

    DEBUG_PRINTF((const uint8_t * )"\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, void* data) {

    DIAG_RETURNTYPE_e retVal = DIAG_HANDLER_RETURN_UNKNOWN;

    /* Get diagnosis type */
    DIAG_TYPE_e diagType = diag_dev.ch_cfg[diag.id2ch[diag_ch_id]].type;

    switch(diagType) {
    /* Call handler function depending on diagnosis type */

        case DIAG_GENERAL_TYPE:
            retVal = DIAG_GeneralHandler(diag_ch_id, event, item_nr);
            break;

        case DIAG_CELLMON_TYPE:
            break;

        case DIAG_COM_TYPE:
            break;

        case DIAG_ADC_TYPE:
            break;

        case DIAG_CONT_TYPE:
            break;

        default:
            break;

    }

    return retVal;
}


/**
 * @brief DIAG_GeneralHandler provides generic error handling, based on configuration.
 *
 * This function does all the handling based on the user defined configuration.
 * According to its return value further treatment is left to the calling module itself.
 * @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_STATE_UNINITIALIZED if diag module still uninitialized,\n
 *           DIAG_HANDLER_RETURN_WRONG_ID if invalid diag id,\n
 *           DIAG_HANDLER_INVALID_TYPE if diag id doesn't correspond to diag type,\n
 *           DIAG_HANDLER_RETURN_OK if error/warning occurred but no threshold reached or event = DIAG_EVENT_OK/DIAG_EVENT_RESET,\n
 *           DIAG_HANDLER_RETURN_ERR_OCCURRED if error threshold reached,\n
 *           DIAG_HANDLER_RETURN_WARNING_OCCURRED if warning threshold reached,\n
 */
static DIAG_RETURNTYPE_e DIAG_GeneralHandler(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
            }
        }
        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);
}

/**
 * @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, NULL);
                    }

                    if(diag_sysmon_ch_cfg[module_id].handlingtype == DIAG_SYSMON_HANDLING_SWITCHOFFCONTACTOR) {
                        // system not working trustfully, switch off contactors!
                        //BMS_SetStateRequest(BMS_STATE_ERROR_REQUEST);
                        //CONT_SwitchAllContactorsOff();
                    }
                    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, NULL);
#endif

    while (1) {
        ;
    }
}

diag.h (secondary)

/**
 *
 * @copyright &copy; 2010 - 2018, 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   Diag driver header
 *
 */

#ifndef DIAG_H_
#define DIAG_H_

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

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

//FIXME Why is there no 1 in following enum?
/** diagnosis handler return types */
typedef enum {
    DIAG_HANDLER_RETURN_OK                  = 0,            /*!<  error not occured or occured but threshold not reached */
    DIAG_HANDLER_RETURN_ERR_OCCURED         = 2,            /*!<  error occured and enabled */
    DIAG_HANDLER_RETURN_WARNING_OCCURRED    = 3,            /*!<  warning occured (error occured but not enabled) */
    DIAG_HANDLER_RETURN_ERR_OCCURRED        = 4,            /*!<  error occured and enabled */
    DIAG_HANDLER_RETURN_WRONG_ID            = 5,            /*!<  wrong diagnosis id */
    DIAG_HANDLER_RETURN_UNKNOWN             = 6,            /*!<  unknown return type */
    DIAG_HANDLER_INVALID_TYPE               = 7,            /*!<  invalid diagnosis type, error in configuration */
    DIAG_HANDLER_INVALID_DATA               = 8,            /*!<  invalid data, dependent of the diagHandler */
    DIAG_HANDLER_RETURN_NOT_READY           = 0xFFFFFFFF,   /*!<  diagnosis handler not ready */
} DIAG_RETURNTYPE_e;

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

/**
 * Counters for error and warning thresholds
 */
typedef struct {
    uint8_t GENERALerrcnt[32];
    uint8_t CELLMONerrcnt[32];
    uint8_t COMerrcnt[32];
    uint8_t ADCerrcnt[32];
} DIAG_OCCURRENCE_COUNTERS_s;

/**
 * structure of failure code 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 */
    uint16_t reserved[11];            /*!< 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;

// FIXME doxygen comment missing, maybe even with explanation of struct member or use ///< comments
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;
// FIXME doxygen comment missing
//extern DIAG_s diag;

/*================== 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
 * @param   data:       pointer to data if DIAG_CONT_TYPE
 *
 * @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, void*  data);

/**
 * @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);

/**
 * @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);

/**
 * @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 - 2018, 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 ===============================*/

/*================== 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,
};

/**
 * Callback function of diagnosis error events
 *
*/

static void dummyfu(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event);

static void DIAG_MSL_overvoltage(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event);
static void DIAG_RSL_overvoltage(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event);
static void DIAG_MOL_overvoltage(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event);

static void DIAG_MSL_undervoltage(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event);
static void DIAG_RSL_undervoltage(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event);
static void DIAG_MOL_undervoltage(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event);

static void DIAG_MSL_overtemperaturecharge(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event);
static void DIAG_RSL_overtemperaturecharge(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event);
static void DIAG_MOL_overtemperaturecharge(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event);

static void DIAG_MSL_overtemperaturedischarge(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event);
static void DIAG_RSL_overtemperaturedischarge(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event);
static void DIAG_MOL_overtemperaturedischarge(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event);

static void DIAG_MSL_undertemperaturecharge(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event);
static void DIAG_RSL_undertemperaturecharge(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event);
static void DIAG_MOL_undertemperaturecharge(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event);

static void DIAG_MSL_undertemperaturedischarge(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event);
static void DIAG_RSL_undertemperaturedischarge(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event);
static void DIAG_MOL_undertemperaturedischarge(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event);

static void DIAG_MSL_overcurrentcharge(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event);
static void DIAG_RSL_overcurrentcharge(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event);
static void DIAG_MOL_overcurrentcharge(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event);

static void DIAG_MSL_overcurrentdischarge(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event);
static void DIAG_RSL_overcurrentdischarge(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event);
static void DIAG_MOL_overcurrentdischarge(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event);

static void DIAG_error_cantiming(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event);
static void DIAG_error_cantiming_cc(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_error_ltcpec(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event);
static void DIAG_error_ltcmux(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event);
static void DIAG_error_ltcspi(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event);

static void DIAG_error_contactormainplus(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event);
static void DIAG_error_contactormainminus(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event);

static void DIAG_error_contactorprecharge(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event);
static void DIAG_error_contactorchargemainplus(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event);

static void DIAG_error_contactorchargemainminus(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event);
static void DIAG_error_contactorchargeprecharge(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 dummyfu2(DIAG_SYSMON_MODULE_ID_e ch_id);

void dummyfu(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event) {
    ;
}

void DIAG_MSL_overvoltage(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event) {
    DATA_BLOCK_MSL_FLAG_s msl_flags;
    DB_ReadBlock(&msl_flags, DATA_BLOCK_ID_MSL);
    if (event == DIAG_EVENT_RESET) {
        msl_flags.over_voltage = 0;
    }
    if (event == DIAG_EVENT_NOK) {
        msl_flags.over_voltage = 1;
    }
    DB_WriteBlock(&msl_flags, DATA_BLOCK_ID_ERRORSTATE);
}

void DIAG_RSL_overvoltage(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event) {
    DATA_BLOCK_RSL_FLAG_s rsl_flags;
    DB_ReadBlock(&rsl_flags, DATA_BLOCK_ID_RSL);
    if (event == DIAG_EVENT_RESET) {
        rsl_flags.over_voltage = 0;
    }
    if (event == DIAG_EVENT_NOK) {
        rsl_flags.over_voltage = 1;
    }
    DB_WriteBlock(&rsl_flags, DATA_BLOCK_ID_RSL);
}

void DIAG_MOL_overvoltage(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event) {
    DATA_BLOCK_MOL_FLAG_s mol_flags;
    DB_ReadBlock(&mol_flags, DATA_BLOCK_ID_MOL);
    if (event == DIAG_EVENT_RESET) {
        mol_flags.over_voltage = 0;
    }
    if (event == DIAG_EVENT_NOK) {
        mol_flags.over_voltage = 1;
    }
    DB_WriteBlock(&mol_flags, DATA_BLOCK_ID_MOL);
}

void DIAG_MSL_undervoltage(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event) {
    DATA_BLOCK_MSL_FLAG_s msl_flags;
    DB_ReadBlock(&msl_flags, DATA_BLOCK_ID_MSL);
    if (event == DIAG_EVENT_RESET) {
        msl_flags.under_voltage = 0;
    }
    if (event == DIAG_EVENT_NOK) {
        msl_flags.under_voltage = 1;
    }
    DB_WriteBlock(&msl_flags, DATA_BLOCK_ID_MSL);
}

void DIAG_RSL_undervoltage(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event) {
    DATA_BLOCK_RSL_FLAG_s rsl_flags;
    DB_ReadBlock(&rsl_flags, DATA_BLOCK_ID_RSL);
    if (event == DIAG_EVENT_RESET) {
        rsl_flags.under_voltage = 0;
    }
    if (event == DIAG_EVENT_NOK) {
        rsl_flags.under_voltage = 1;
    }
    DB_WriteBlock(&rsl_flags, DATA_BLOCK_ID_RSL);
}

void DIAG_MOL_undervoltage(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event) {
    DATA_BLOCK_MOL_FLAG_s mol_flags;
    DB_ReadBlock(&mol_flags, DATA_BLOCK_ID_MOL);
    if (event == DIAG_EVENT_RESET) {
        mol_flags.under_voltage = 0;
    }
    if (event == DIAG_EVENT_NOK) {
        mol_flags.under_voltage = 1;
    }
    DB_WriteBlock(&mol_flags, DATA_BLOCK_ID_MOL);
}

void DIAG_MSL_overtemperaturecharge(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event) {
    DATA_BLOCK_MSL_FLAG_s msl_flags;
    DB_ReadBlock(&msl_flags, DATA_BLOCK_ID_MSL);
    if (event == DIAG_EVENT_RESET) {
        msl_flags.over_temperature_charge = 0;
    }
    if (event == DIAG_EVENT_NOK) {
        msl_flags.over_temperature_charge = 1;
    }
    DB_WriteBlock(&msl_flags, DATA_BLOCK_ID_MSL);
}

void DIAG_RSL_overtemperaturecharge(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event) {
    DATA_BLOCK_RSL_FLAG_s rsl_flags;
    DB_ReadBlock(&rsl_flags, DATA_BLOCK_ID_RSL);
    if (event == DIAG_EVENT_RESET) {
        rsl_flags.over_temperature_charge = 0;
    }
    if (event == DIAG_EVENT_NOK) {
        rsl_flags.over_temperature_charge = 1;
    }
    DB_WriteBlock(&rsl_flags, DATA_BLOCK_ID_RSL);
}

void DIAG_MOL_overtemperaturecharge(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event) {
    DATA_BLOCK_MOL_FLAG_s mol_flags;
    DB_ReadBlock(&mol_flags, DATA_BLOCK_ID_MOL);
    if (event == DIAG_EVENT_RESET) {
        mol_flags.over_temperature_charge = 0;
    }
    if (event == DIAG_EVENT_NOK) {
        mol_flags.over_temperature_charge = 1;
    }
    DB_WriteBlock(&mol_flags, DATA_BLOCK_ID_MOL);
}

void DIAG_MSL_overtemperaturedischarge(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event) {
    DATA_BLOCK_MSL_FLAG_s msl_flags;
    DB_ReadBlock(&msl_flags, DATA_BLOCK_ID_MSL);
    if (event == DIAG_EVENT_RESET) {
        msl_flags.over_temperature_discharge = 0;
    }
    if (event == DIAG_EVENT_NOK) {
        msl_flags.over_temperature_discharge = 1;
    }
    DB_WriteBlock(&msl_flags, DATA_BLOCK_ID_MSL);
}

void DIAG_RSL_overtemperaturedischarge(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event) {
    DATA_BLOCK_RSL_FLAG_s rsl_flags;
    DB_ReadBlock(&rsl_flags, DATA_BLOCK_ID_RSL);
    if (event == DIAG_EVENT_RESET) {
        rsl_flags.over_temperature_discharge = 0;
    }
    if (event == DIAG_EVENT_NOK) {
        rsl_flags.over_temperature_discharge = 1;
    }
    DB_WriteBlock(&rsl_flags, DATA_BLOCK_ID_RSL);
}

void DIAG_MOL_overtemperaturedischarge(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event) {
    DATA_BLOCK_MOL_FLAG_s mol_flags;
    DB_ReadBlock(&mol_flags, DATA_BLOCK_ID_MOL);
    if (event == DIAG_EVENT_RESET) {
        mol_flags.over_temperature_discharge = 0;
    }
    if (event == DIAG_EVENT_NOK) {
        mol_flags.over_temperature_discharge = 1;
    }
    DB_WriteBlock(&mol_flags, DATA_BLOCK_ID_MOL);

}

void DIAG_MSL_undertemperaturecharge(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event) {
    DATA_BLOCK_MSL_FLAG_s msl_flags;
    DB_ReadBlock(&msl_flags, DATA_BLOCK_ID_MSL);
    if (event == DIAG_EVENT_RESET) {
        msl_flags.under_temperature_charge = 0;
    }
    if (event == DIAG_EVENT_NOK) {
        msl_flags.under_temperature_charge = 1;
    }
    DB_WriteBlock(&msl_flags, DATA_BLOCK_ID_MSL);
}

void DIAG_RSL_undertemperaturecharge(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event) {
    DATA_BLOCK_RSL_FLAG_s rsl_flags;
    DB_ReadBlock(&rsl_flags, DATA_BLOCK_ID_RSL);
    if (event == DIAG_EVENT_RESET) {
        rsl_flags.under_temperature_charge = 0;
    }
    if (event == DIAG_EVENT_NOK) {
        rsl_flags.under_temperature_charge = 1;
    }
    DB_WriteBlock(&rsl_flags, DATA_BLOCK_ID_RSL);
}

void DIAG_MOL_undertemperaturecharge(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event) {
    DATA_BLOCK_MOL_FLAG_s mol_flags;
    DB_ReadBlock(&mol_flags, DATA_BLOCK_ID_MOL);
    if (event == DIAG_EVENT_RESET) {
        mol_flags.under_temperature_charge = 0;
    }
    if (event == DIAG_EVENT_NOK) {
        mol_flags.under_temperature_charge = 1;
    }
    DB_WriteBlock(&mol_flags, DATA_BLOCK_ID_MOL);

}

void DIAG_MSL_undertemperaturedischarge(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event) {
    DATA_BLOCK_MSL_FLAG_s msl_flags;
    DB_ReadBlock(&msl_flags, DATA_BLOCK_ID_MSL);
    if (event == DIAG_EVENT_RESET) {
        msl_flags.under_temperature_discharge = 0;
    }
    if (event == DIAG_EVENT_NOK) {
        msl_flags.under_temperature_discharge = 1;
    }
    DB_WriteBlock(&msl_flags, DATA_BLOCK_ID_MSL);
}

void DIAG_RSL_undertemperaturedischarge(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event) {
    DATA_BLOCK_RSL_FLAG_s rsl_flags;
    DB_ReadBlock(&rsl_flags, DATA_BLOCK_ID_RSL);
    if (event == DIAG_EVENT_RESET) {
        rsl_flags.under_temperature_discharge = 0;
    }
    if (event == DIAG_EVENT_NOK) {
        rsl_flags.under_temperature_discharge = 1;
    }
    DB_WriteBlock(&rsl_flags, DATA_BLOCK_ID_RSL);
}

void DIAG_MOL_undertemperaturedischarge(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event) {
    DATA_BLOCK_MOL_FLAG_s mol_flags;
    DB_ReadBlock(&mol_flags, DATA_BLOCK_ID_MOL);
    if (event == DIAG_EVENT_RESET) {
        mol_flags.under_temperature_discharge = 0;
    }
    if (event == DIAG_EVENT_NOK) {
        mol_flags.under_temperature_discharge = 1;
    }
    DB_WriteBlock(&mol_flags, DATA_BLOCK_ID_MOL);
}

void DIAG_MSL_overcurrentcharge(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event) {
    DATA_BLOCK_MSL_FLAG_s msl_flags;
    DB_ReadBlock(&msl_flags, DATA_BLOCK_ID_MSL);
    if (event == DIAG_EVENT_RESET) {
        msl_flags.over_current_charge = 0;
    }
    if (event == DIAG_EVENT_NOK) {
        msl_flags.over_current_charge = 1;
    }
    DB_WriteBlock(&msl_flags, DATA_BLOCK_ID_MSL);
}

void DIAG_RSL_overcurrentcharge(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event) {
    DATA_BLOCK_RSL_FLAG_s rsl_flags;
    DB_ReadBlock(&rsl_flags, DATA_BLOCK_ID_RSL);
    if (event == DIAG_EVENT_RESET) {
        rsl_flags.over_current_charge = 0;
    }
    if (event == DIAG_EVENT_NOK) {
        rsl_flags.over_current_charge = 1;
    }
    DB_WriteBlock(&rsl_flags, DATA_BLOCK_ID_RSL);
}

void DIAG_MOL_overcurrentcharge(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event) {
    DATA_BLOCK_MOL_FLAG_s mol_flags;
    DB_ReadBlock(&mol_flags, DATA_BLOCK_ID_MOL);
    if (event == DIAG_EVENT_RESET) {
        mol_flags.over_current_charge = 0;
    }
    if (event == DIAG_EVENT_NOK) {
        mol_flags.over_current_charge = 1;
    }
    DB_WriteBlock(&mol_flags, DATA_BLOCK_ID_MOL);
}

void DIAG_MSL_overcurrentdischarge(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event) {
    DATA_BLOCK_MSL_FLAG_s msl_flags;
    DB_ReadBlock(&msl_flags, DATA_BLOCK_ID_MSL);
    if (event == DIAG_EVENT_RESET) {
        msl_flags.over_current_discharge = 0;
    }
    if (event == DIAG_EVENT_NOK) {
        msl_flags.over_current_discharge = 1;
    }
    DB_WriteBlock(&msl_flags, DATA_BLOCK_ID_MSL);
}

void DIAG_RSL_overcurrentdischarge(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event) {
    DATA_BLOCK_RSL_FLAG_s rsl_flags;
    DB_ReadBlock(&rsl_flags, DATA_BLOCK_ID_RSL);
    if (event == DIAG_EVENT_RESET) {
        rsl_flags.over_current_discharge = 0;
    }
    if (event == DIAG_EVENT_NOK) {
        rsl_flags.over_current_discharge = 1;
    }
    DB_WriteBlock(&rsl_flags, DATA_BLOCK_ID_RSL);
}

void DIAG_MOL_overcurrentdischarge(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event) {
    DATA_BLOCK_MOL_FLAG_s mol_flags;
    DB_ReadBlock(&mol_flags, DATA_BLOCK_ID_MOL);
    if (event == DIAG_EVENT_RESET) {
        mol_flags.over_current_discharge = 0;
    }
    if (event == DIAG_EVENT_NOK) {
        mol_flags.over_current_discharge = 1;
    }
    DB_WriteBlock(&mol_flags, DATA_BLOCK_ID_MOL);
}

void DIAG_error_cantiming(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event) {
    DATA_BLOCK_ERRORSTATE_s error_flags;
    DB_ReadBlock(&error_flags, DATA_BLOCK_ID_ERRORSTATE);
    if (event == DIAG_EVENT_RESET) {
        error_flags.can_timing = 0;
    }
    if (event == DIAG_EVENT_NOK) {
        error_flags.can_timing = 1;
    }
    DB_WriteBlock(&error_flags, DATA_BLOCK_ID_ERRORSTATE);
}

void DIAG_error_cantiming_cc(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event) {
    DATA_BLOCK_ERRORSTATE_s error_flags;
    DB_ReadBlock(&error_flags, DATA_BLOCK_ID_ERRORSTATE);
    if (event == DIAG_EVENT_RESET) {
        error_flags.can_timing_cc = 0;
    }
    if (event == DIAG_EVENT_NOK) {
        error_flags.can_timing_cc = 1;
    }
    DB_WriteBlock(&error_flags, DATA_BLOCK_ID_ERRORSTATE);
}

void DIAG_error_cancurrentsensor(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event) {
    DATA_BLOCK_ERRORSTATE_s error_flags;
    DB_ReadBlock(&error_flags, DATA_BLOCK_ID_ERRORSTATE);
    if (event == DIAG_EVENT_RESET) {
        error_flags.currentsensorresponding = 0;
    }
    if (event == DIAG_EVENT_NOK) {
        error_flags.currentsensorresponding = 1;
    }
    DB_WriteBlock(&error_flags, DATA_BLOCK_ID_ERRORSTATE);
}

void DIAG_error_ltcpec(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event) {
    DATA_BLOCK_ERRORSTATE_s error_flags;
    DB_ReadBlock(&error_flags, DATA_BLOCK_ID_ERRORSTATE);
    if (event == DIAG_EVENT_RESET) {
        error_flags.crc_error = 0;
    }
    if (event == DIAG_EVENT_NOK) {
        error_flags.crc_error = 1;
    }
    DB_WriteBlock(&error_flags, DATA_BLOCK_ID_ERRORSTATE);
}

void DIAG_error_ltcmux(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event) {
    DATA_BLOCK_ERRORSTATE_s error_flags;
    DB_ReadBlock(&error_flags, DATA_BLOCK_ID_ERRORSTATE);
    if (event == DIAG_EVENT_RESET) {
        error_flags.mux_error = 0;
    }
    if (event == DIAG_EVENT_NOK) {
        error_flags.mux_error = 1;
    }
    DB_WriteBlock(&error_flags, DATA_BLOCK_ID_ERRORSTATE);
}

void DIAG_error_ltcspi(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event) {
    DATA_BLOCK_ERRORSTATE_s error_flags;
    DB_ReadBlock(&error_flags, DATA_BLOCK_ID_ERRORSTATE);
    if (event == DIAG_EVENT_RESET) {
        error_flags.spi_error = 0;
    }
    if (event == DIAG_EVENT_NOK) {
        error_flags.spi_error = 1;
    }
    DB_WriteBlock(&error_flags, DATA_BLOCK_ID_ERRORSTATE);
}

void DIAG_error_contactormainplus(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event) {
    DATA_BLOCK_ERRORSTATE_s error_flags;
    DB_ReadBlock(&error_flags, DATA_BLOCK_ID_ERRORSTATE);
    if (event == DIAG_EVENT_RESET) {
        error_flags.main_plus = 0;
    }
    if (event == DIAG_EVENT_NOK) {
        error_flags.main_plus = 1;
    }
    DB_WriteBlock(&error_flags, DATA_BLOCK_ID_ERRORSTATE);
}

void DIAG_error_contactormainminus(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event) {
    DATA_BLOCK_ERRORSTATE_s error_flags;
    DB_ReadBlock(&error_flags, DATA_BLOCK_ID_ERRORSTATE);
    if (event == DIAG_EVENT_RESET) {
        error_flags.main_minus = 0;
    }
    if (event == DIAG_EVENT_NOK) {
        error_flags.main_minus = 1;
    }
    DB_WriteBlock(&error_flags, DATA_BLOCK_ID_ERRORSTATE);
}

void DIAG_error_contactorprecharge(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event) {
    DATA_BLOCK_ERRORSTATE_s error_flags;
    DB_ReadBlock(&error_flags, DATA_BLOCK_ID_ERRORSTATE);
    if (event == DIAG_EVENT_RESET) {
        error_flags.precharge = 0;
    }
    if (event == DIAG_EVENT_NOK) {
        error_flags.precharge = 1;
    }
    DB_WriteBlock(&error_flags, DATA_BLOCK_ID_ERRORSTATE);
}

void DIAG_error_contactorchargemainplus(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event) {
    DATA_BLOCK_ERRORSTATE_s error_flags;
    DB_ReadBlock(&error_flags, DATA_BLOCK_ID_ERRORSTATE);
    if (event == DIAG_EVENT_RESET) {
        error_flags.charge_main_plus = 0;
    }
    if (event == DIAG_EVENT_NOK) {
        error_flags.charge_main_plus = 1;
    }
    DB_WriteBlock(&error_flags, DATA_BLOCK_ID_ERRORSTATE);
}

void DIAG_error_contactorchargemainminus(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event) {
    DATA_BLOCK_ERRORSTATE_s error_flags;
    DB_ReadBlock(&error_flags, DATA_BLOCK_ID_ERRORSTATE);
    if (event == DIAG_EVENT_RESET) {
        error_flags.charge_main_minus = 0;
    }
    if (event == DIAG_EVENT_NOK) {
        error_flags.charge_main_minus = 1;
    }
    DB_WriteBlock(&error_flags, DATA_BLOCK_ID_ERRORSTATE);
}

void DIAG_error_contactorchargeprecharge(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event) {
    DATA_BLOCK_ERRORSTATE_s error_flags;
    DB_ReadBlock(&error_flags, DATA_BLOCK_ID_ERRORSTATE);
    if (event == DIAG_EVENT_RESET) {
        error_flags.charge_precharge = 0;
    }
    if (event == DIAG_EVENT_NOK) {
        error_flags.charge_precharge = 1;
    }
    DB_WriteBlock(&error_flags, DATA_BLOCK_ID_ERRORSTATE);
}

void DIAG_error_interlock(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event) {
    DATA_BLOCK_ERRORSTATE_s error_flags;
    DB_ReadBlock(&error_flags, DATA_BLOCK_ID_ERRORSTATE);
    if (event  ==  DIAG_EVENT_RESET) {
        error_flags.interlock = 0;
    }
    if (event==DIAG_EVENT_NOK) {
        error_flags.interlock = 1;
    }
    DB_WriteBlock(&error_flags, DATA_BLOCK_ID_ERRORSTATE);
}

/**
 * Callback function of system monitoring error events
 *
*/
void dummyfu2(DIAG_SYSMON_MODULE_ID_e ch_id) {
    ;
}


DIAG_CH_CFG_s  diag_ch_cfg[] = {

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

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

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


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

    {DIAG_CH_ISOMETER_TIM_ERROR,                        "ISOMETER_TIM_ERROR",                   DIAG_GENERAL_TYPE, DIAG_ERROR_SENSITIVITY_MID,               DIAG_RECORDING_ENABLED, DIAG_ENABLED, dummyfu},
    {DIAG_CH_ISOMETER_GROUNDERROR,                      "ISOMETER_GROUNDERROR",                 DIAG_GENERAL_TYPE, DIAG_ERROR_SENSITIVITY_HIGH,              DIAG_RECORDING_ENABLED, DIAG_ENABLED, dummyfu},
    {DIAG_CH_ISOMETER_ERROR,                            "ISOMETER_ERROR",                       DIAG_GENERAL_TYPE, DIAG_ERROR_SENSITIVITY_MID,               DIAG_RECORDING_ENABLED, DIAG_ENABLED, dummyfu},
    {DIAG_CH_ISOMETER_MEAS_INVALID,                     "ISOMETER_MEAS_INVALID",                DIAG_GENERAL_TYPE, DIAG_ERROR_SENSITIVITY_HIGH,              DIAG_RECORDING_ENABLED, DIAG_ENABLED, dummyfu},

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

    {DIAG_CH_CELLVOLTAGE_UNDERVOLTAGE_MSL,            "CELLVOLT_UNDERVOLT_MSL",           DIAG_GENERAL_TYPE, DIAG_ERROR_VOLTAGE_SENSITIVITY_MSL,           DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_MSL_undervoltage},
    {DIAG_CH_CELLVOLTAGE_UNDERVOLTAGE_RSL,            "CELLVOLT_UNDERVOLT_RSL",           DIAG_GENERAL_TYPE, DIAG_ERROR_VOLTAGE_SENSITIVITY_RSL,           DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_RSL_undervoltage},
    {DIAG_CH_CELLVOLTAGE_UNDERVOLTAGE_MOL,          "CELLVOLT_UNDERVOLT_MOL",             DIAG_GENERAL_TYPE, DIAG_ERROR_VOLTAGE_SENSITIVITY_MOL,         DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_MOL_undervoltage},

    {DIAG_CH_TEMP_OVERTEMPERATURE_CHARGE_MSL,         "OVERTEMP_CHARGE_MSL",             DIAG_GENERAL_TYPE, DIAG_ERROR_TEMPERATURE_SENSITIVITY_MSL,       DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_MSL_overtemperaturecharge},
    {DIAG_CH_TEMP_OVERTEMPERATURE_CHARGE_RSL,         "OVERTEMP_CHARGE_RSL",             DIAG_GENERAL_TYPE, DIAG_ERROR_TEMPERATURE_SENSITIVITY_RSL,       DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_RSL_overtemperaturecharge},
    {DIAG_CH_TEMP_OVERTEMPERATURE_CHARGE_MOL,       "OVERTEMP_CHARGE_MOL",               DIAG_GENERAL_TYPE, DIAG_ERROR_TEMPERATURE_SENSITIVITY_MOL,     DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_MOL_overtemperaturecharge},

    {DIAG_CH_TEMP_OVERTEMPERATURE_DISCHARGE_MSL,      "OVERTEMP_DISCHARGE_MSL",          DIAG_GENERAL_TYPE, DIAG_ERROR_TEMPERATURE_SENSITIVITY_MSL,       DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_MSL_overtemperaturedischarge},
    {DIAG_CH_TEMP_OVERTEMPERATURE_DISCHARGE_RSL,      "OVERTEMP_DISCHARGE_RSL",          DIAG_GENERAL_TYPE, DIAG_ERROR_TEMPERATURE_SENSITIVITY_MSL,       DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_RSL_overtemperaturedischarge},
    {DIAG_CH_TEMP_OVERTEMPERATURE_DISCHARGE_MOL,    "OVERTEMP_DISCHARGE_MOL",            DIAG_GENERAL_TYPE, DIAG_ERROR_TEMPERATURE_SENSITIVITY_MSL,       DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_MOL_overtemperaturedischarge},

    {DIAG_CH_TEMP_UNDERTEMPERATURE_CHARGE_MSL,        "UNDERTEMP_CHARGE_MSL",            DIAG_GENERAL_TYPE, DIAG_ERROR_TEMPERATURE_SENSITIVITY_MSL,       DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_MSL_undertemperaturecharge},
    {DIAG_CH_TEMP_UNDERTEMPERATURE_CHARGE_RSL,        "UNDERTEMP_CHARGE_RSL",            DIAG_GENERAL_TYPE, DIAG_ERROR_TEMPERATURE_SENSITIVITY_MSL,       DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_RSL_undertemperaturecharge},
    {DIAG_CH_TEMP_UNDERTEMPERATURE_CHARGE_MOL,      "UNDERTEMP_CHARGE_MOL",              DIAG_GENERAL_TYPE, DIAG_ERROR_TEMPERATURE_SENSITIVITY_MSL,       DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_MOL_undertemperaturecharge},

    {DIAG_CH_TEMP_UNDERTEMPERATURE_DISCHARGE_MSL,     "UNDERTEMP_DISCHARGE_MSL",         DIAG_GENERAL_TYPE, DIAG_ERROR_TEMPERATURE_SENSITIVITY_MSL,       DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_MSL_undertemperaturedischarge},
    {DIAG_CH_TEMP_UNDERTEMPERATURE_DISCHARGE_RSL,     "UNDERTEMP_DISCHARGE_RSL",         DIAG_GENERAL_TYPE, DIAG_ERROR_TEMPERATURE_SENSITIVITY_MSL,       DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_RSL_undertemperaturedischarge},
    {DIAG_CH_TEMP_UNDERTEMPERATURE_DISCHARGE_MOL,   "UNDERTEMP_DISCHARGE_MOL",           DIAG_GENERAL_TYPE, DIAG_ERROR_TEMPERATURE_SENSITIVITY_MSL,       DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_MOL_undertemperaturedischarge},

    {DIAG_CH_OVERCURRENT_CHARGE_MSL,                  "OVERCUR_CHARGE_MSL",                 DIAG_GENERAL_TYPE, DIAG_ERROR_CURRENT_SENSITIVITY_MSL,           DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_MSL_overcurrentcharge},
    {DIAG_CH_OVERCURRENT_CHARGE_RSL,                  "OVERCUR_CHARGE_RSL",                 DIAG_GENERAL_TYPE, DIAG_ERROR_CURRENT_SENSITIVITY_MSL,           DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_RSL_overcurrentcharge},
    {DIAG_CH_OVERCURRENT_CHARGE_MOL,                "OVERCUR_CHARGE_MOL",                   DIAG_GENERAL_TYPE, DIAG_ERROR_CURRENT_SENSITIVITY_MSL,           DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_MOL_overcurrentcharge},

    {DIAG_CH_OVERCURRENT_DISCHARGE_MSL,               "OVERCUR_DISCHARGE_MSL",              DIAG_GENERAL_TYPE, DIAG_ERROR_CURRENT_SENSITIVITY_MSL,           DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_MSL_overcurrentdischarge},
    {DIAG_CH_OVERCURRENT_DISCHARGE_RSL,               "OVERCUR_DISCHARGE_RSL",              DIAG_GENERAL_TYPE, DIAG_ERROR_CURRENT_SENSITIVITY_MSL,           DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_RSL_overcurrentdischarge},
    {DIAG_CH_OVERCURRENT_DISCHARGE_MOL,             "OVERCUR_DISCHARGE_MOL",                DIAG_GENERAL_TYPE, DIAG_ERROR_CURRENT_SENSITIVITY_MSL,           DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_MOL_overcurrentdischarge},

    {DIAG_CH_LTC_SPI,                                   "LTC_SPI",                              DIAG_GENERAL_TYPE, DIAG_ERROR_LTC_SPI_SENSITIVITY,           DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_error_ltcspi},
    {DIAG_CH_LTC_PEC,                                   "LTC_PEC",                              DIAG_GENERAL_TYPE, DIAG_ERROR_LTC_PEC_SENSITIVITY,           DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_error_ltcpec},
    {DIAG_CH_LTC_MUX,                                   "LTC_MUX",                              DIAG_GENERAL_TYPE, DIAG_ERROR_LTC_MUX_SENSITIVITY,           DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_error_ltcmux},

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

    /* Contactor Damage Error */
    {DIAG_CH_CONTACTOR_DAMAGED,                         "CONTACTOR_DAMAGED",                    DIAG_CONT_TYPE,     DIAG_ERROR_SENSITIVITY_HIGH,              DIAG_RECORDING_ENABLED, DIAG_ENABLED, dummyfu},
    {DIAG_CH_CONTACTOR_OPENING,                         "CONTACTOR_OPENING",                    DIAG_CONT_TYPE,     DIAG_ERROR_SENSITIVITY_HIGH,              DIAG_RECORDING_ENABLED, DIAG_ENABLED, dummyfu},
    {DIAG_CH_CONTACTOR_CLOSING,                         "CONTACTOR_CLOSING",                    DIAG_CONT_TYPE,     DIAG_ERROR_SENSITIVITY_HIGH,              DIAG_RECORDING_ENABLED, DIAG_ENABLED, dummyfu},

    /* Contactor Feedback Error */
    {DIAG_CH_CONTACTOR_MAIN_PLUS_FEEDBACK,              "CONT_MAIN_PLUS_FEED",         DIAG_GENERAL_TYPE,  DIAG_ERROR_MAIN_PLUS_SENSITIVITY,      DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_error_contactormainplus},
    {DIAG_CH_CONTACTOR_MAIN_MINUS_FEEDBACK,             "CONT_MAIN_MINUS_FEED",        DIAG_GENERAL_TYPE,  DIAG_ERROR_MAIN_MINUS_SENSITIVITY,     DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_error_contactormainminus},
    {DIAG_CH_CONTACTOR_PRECHARGE_FEEDBACK,              "CONT_PRECHARGE_FEED",         DIAG_GENERAL_TYPE,  DIAG_ERROR_PRECHARGE_SENSITIVITY,      DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_error_contactorprecharge},
    {DIAG_CH_CONTACTOR_CHARGE_MAIN_PLUS_FEEDBACK,       "CONT_CHRGE_MAIN_PLUS_FEED",  DIAG_GENERAL_TYPE,  DIAG_ERROR_MAIN_PLUS_SENSITIVITY,      DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_error_contactorchargemainplus},
    {DIAG_CH_CONTACTOR_CHARGE_MAIN_MINUS_FEEDBACK,      "CONT_CHRGE_MAIN_MINUS_FEED", DIAG_GENERAL_TYPE,  DIAG_ERROR_MAIN_MINUS_SENSITIVITY,     DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_error_contactorchargemainminus},
    {DIAG_CH_CONTACTOR_CHARGE_PRECHARGE_FEEDBACK,       "CONT_CHRGE_PRECHARGE_FEED",  DIAG_GENERAL_TYPE,  DIAG_ERROR_PRECHARGE_SENSITIVITY,      DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_error_contactorchargeprecharge},

    /* Interlock Feedback Error */
    {DIAG_CH_INTERLOCK_FEEDBACK,                        "INTERLOCK_FEEDBACK",                   DIAG_GENERAL_TYPE,  DIAG_ERROR_INTERLOCK_SENSITIVITY,       DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_error_interlock},

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

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

};


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},
    {DIAG_SYSMON_CONT_ID,           DIAG_SYSMON_CYCLICTASK,  20, DIAG_RECORDING_ENABLED, DIAG_SYSMON_HANDLING_SWITCHOFFCONTACTOR, DIAG_ENABLED, dummyfu2},
    {DIAG_SYSMON_ILCK_ID,           DIAG_SYSMON_CYCLICTASK,  20, DIAG_RECORDING_ENABLED, DIAG_SYSMON_HANDLING_SWITCHOFFCONTACTOR, DIAG_ENABLED, dummyfu2},
    {DIAG_SYSMON_LTC_ID,            DIAG_SYSMON_CYCLICTASK,   5, DIAG_RECORDING_ENABLED, DIAG_SYSMON_HANDLING_SWITCHOFFCONTACTOR, DIAG_ENABLED, dummyfu2},
    {DIAG_SYSMON_ISOGUARD_ID,       DIAG_SYSMON_CYCLICTASK, 400, DIAG_RECORDING_ENABLED, DIAG_SYSMON_HANDLING_SWITCHOFFCONTACTOR, DIAG_ENABLED, dummyfu2},
    {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],
};

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

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

diag_cfg.h (primary)

/**
 *
 * @copyright &copy; 2010 - 2018, 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"
#include "diag_id_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        (500)
#define DIAG_ERROR_MAIN_MINUS_SENSITIVITY       (500)
#define DIAG_ERROR_PRECHARGE_SENSITIVITY        (500)

#define DIAG_ERROR_INTERLOCK_SENSITIVITY        (10)

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

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

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


// FIXME simple doxygen comment for each define?
/* Initialization and startup events: 0-15 */
#define DIAG_CH_FLASHCHECKSUM                              DIAG_ID_5            //
#define DIAG_CH_BKPDIAG_FAILURE                            DIAG_ID_6            //
#define DIAG_CH_WATCHDOGRESET_FAILURE                      DIAG_ID_7            //
#define DIAG_CH_POSTOSINIT_FAILURE                         DIAG_ID_8            //
#define DIAG_CH_CALIB_EEPR_FAILURE                         DIAG_ID_9            //
#define DIAG_CH_CAN_INIT_FAILURE                           DIAG_ID_10           //
#define DIAG_CH_VIC_INIT_FAILURE                           DIAG_ID_11

/* HW-/SW-Runtime events: 16-31 */
#define DIAG_CH_DIV_BY_ZERO_FAILURE                        DIAG_ID_16            //
#define DIAG_CH_UNDEF_INSTRUCTION_FAILURE                  DIAG_ID_17            //
#define DIAG_CH_DATA_BUS_FAILURE                           DIAG_ID_18            //
#define DIAG_CH_INSTRUCTION_BUS_FAILURE                    DIAG_ID_19            //
#define DIAG_CH_HARDFAULT_NOTHANDLED                       DIAG_ID_20            //
#define DIAG_CH_RUNTIME_ERROR_RESERVED_1                   DIAG_ID_21            // reserved for future needs
#define DIAG_CH_RUNTIME_ERROR_RESERVED_2                   DIAG_ID_22            // reserved for future needs
#define DIAG_CH_RUNTIME_ERROR_RESERVED_3                   DIAG_ID_23            // reserved for future needs
#define DIAG_CH_CONFIGASSERT                               DIAG_ID_24            //
#define DIAG_CH_SYSTEMMONITORING_TIMEOUT                   DIAG_ID_25            //


/* Measurement events: 32-47 */
#define DIAG_CH_CANS_MAX_VALUE_VIOLATE                     DIAG_ID_32
#define DIAG_CH_CANS_MIN_VALUE_VIOLATE                     DIAG_ID_33
#define DIAG_CH_CANS_CAN_MOD_FAILURE                       DIAG_ID_34

/**
 * Measured frequency too low or no new value captured during last cycle
 */
#define DIAG_CH_ISOMETER_TIM_ERROR                         DIAG_ID_35

/**
 * Ground error detected
 */
#define DIAG_CH_ISOMETER_GROUNDERROR                       DIAG_ID_36

/**
 * Device error, invalid measurement result
 */
#define DIAG_CH_ISOMETER_ERROR                             DIAG_ID_37

 /**
  * Measurement trustworthy or not, hysteresis to ground error flag
  */
#define DIAG_CH_ISOMETER_MEAS_INVALID                      DIAG_ID_38

/**
 * Cell voltage limits violated
 */
#define DIAG_CH_CELLVOLTAGE_OVERVOLTAGE_MSL                DIAG_ID_39
#define DIAG_CH_CELLVOLTAGE_OVERVOLTAGE_RSL                DIAG_ID_40
#define DIAG_CH_CELLVOLTAGE_OVERVOLTAGE_MOL                DIAG_ID_41

#define DIAG_CH_CELLVOLTAGE_UNDERVOLTAGE_MSL               DIAG_ID_42
#define DIAG_CH_CELLVOLTAGE_UNDERVOLTAGE_RSL               DIAG_ID_43
#define DIAG_CH_CELLVOLTAGE_UNDERVOLTAGE_MOL               DIAG_ID_44

/**
 *  Temperature limits violated
 */
#define DIAG_CH_TEMP_OVERTEMPERATURE_CHARGE_MSL            DIAG_ID_45
#define DIAG_CH_TEMP_OVERTEMPERATURE_CHARGE_RSL            DIAG_ID_46
#define DIAG_CH_TEMP_OVERTEMPERATURE_CHARGE_MOL            DIAG_ID_47

#define DIAG_CH_TEMP_OVERTEMPERATURE_DISCHARGE_MSL         DIAG_ID_48
#define DIAG_CH_TEMP_OVERTEMPERATURE_DISCHARGE_RSL         DIAG_ID_49
#define DIAG_CH_TEMP_OVERTEMPERATURE_DISCHARGE_MOL         DIAG_ID_50

#define DIAG_CH_TEMP_UNDERTEMPERATURE_CHARGE_MSL           DIAG_ID_51
#define DIAG_CH_TEMP_UNDERTEMPERATURE_CHARGE_RSL           DIAG_ID_52
#define DIAG_CH_TEMP_UNDERTEMPERATURE_CHARGE_MOL           DIAG_ID_53

#define DIAG_CH_TEMP_UNDERTEMPERATURE_DISCHARGE_MSL        DIAG_ID_54
#define DIAG_CH_TEMP_UNDERTEMPERATURE_DISCHARGE_RSL        DIAG_ID_55
#define DIAG_CH_TEMP_UNDERTEMPERATURE_DISCHARGE_MOL        DIAG_ID_56

/**
 * Overcurrent
 */
#define DIAG_CH_OVERCURRENT_CHARGE_MSL                     DIAG_ID_57
#define DIAG_CH_OVERCURRENT_CHARGE_RSL                     DIAG_ID_58
#define DIAG_CH_OVERCURRENT_CHARGE_MOL                     DIAG_ID_59

#define DIAG_CH_OVERCURRENT_DISCHARGE_MSL                  DIAG_ID_60
#define DIAG_CH_OVERCURRENT_DISCHARGE_RSL                  DIAG_ID_61
#define DIAG_CH_OVERCURRENT_DISCHARGE_MOL                  DIAG_ID_62


/**
 * LTC
 */
#define DIAG_CH_LTC_SPI                                    DIAG_ID_63
#define DIAG_CH_LTC_PEC                                    DIAG_ID_64
#define DIAG_CH_LTC_MUX                                    DIAG_ID_65


/* Communication events: 50-63*/
/**
 *  CAN timing not coming
 */
#define DIAG_CH_CAN_TIMING                                 DIAG_ID_66
/**
 *  CAN C-C not coming
 */
#define DIAG_CH_CAN_CC_RESPONDING                          DIAG_ID_67
/**
 *  Current sensor not responding anymore
 */
#define DIAG_CH_CURRENT_SENSOR_RESPONDING                  DIAG_ID_68


/* Contactor events: 64-79*/
/**
 * @brief   Opening contactor at over current
 */
#define DIAG_CH_CONTACTOR_DAMAGED                          DIAG_ID_69

/**
 * @brief   counter for contactor opening
 */
#define DIAG_CH_CONTACTOR_OPENING                           DIAG_ID_70

/**
 * @brief   counter for contactor closing
 */
#define DIAG_CH_CONTACTOR_CLOSING                           DIAG_ID_71

/**
 * @brief   Contactor feedback error
 */
#define DIAG_CH_CONTACTOR_MAIN_PLUS_FEEDBACK                DIAG_ID_72
#define DIAG_CH_CONTACTOR_MAIN_MINUS_FEEDBACK               DIAG_ID_73
#define DIAG_CH_CONTACTOR_PRECHARGE_FEEDBACK                DIAG_ID_74
#define DIAG_CH_CONTACTOR_CHARGE_MAIN_PLUS_FEEDBACK         DIAG_ID_75
#define DIAG_CH_CONTACTOR_CHARGE_MAIN_MINUS_FEEDBACK        DIAG_ID_76
#define DIAG_CH_CONTACTOR_CHARGE_PRECHARGE_FEEDBACK         DIAG_ID_77

/**
 * @brief   Interlock feedback error
 */
#define DIAG_CH_INTERLOCK_FEEDBACK                          DIAG_ID_78



#define DIAG_CH_SLAVE_PCB_UNDERTEMPERATURE_MSL              DIAG_ID_79
#define DIAG_CH_SLAVE_PCB_UNDERTEMPERATURE_RSL              DIAG_ID_80
#define DIAG_CH_SLAVE_PCB_UNDERTEMPERATURE_MOL              DIAG_ID_81

#define DIAG_CH_SLAVE_PCB_OVERTEMPERATURE_MSL               DIAG_ID_82
#define DIAG_CH_SLAVE_PCB_OVERTEMPERATURE_RSL               DIAG_ID_83
#define DIAG_CH_SLAVE_PCB_OVERTEMPERATURE_MOL               DIAG_ID_84

/**
 * enable state of diagnosis entry
 */
typedef enum {
    DIAG_ENABLED  = 0,
    DIAG_DISABLED = 1,
} 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

// FIXME is it better to name it DIAG_GROUP_xxx instead of DIAG_xxx_TYPE and
/**
 * diagnosis groups
 * failure codes FC
 */
typedef enum {
    DIAG_GENERAL_TYPE   = 0x00,     /*!< FC 0x00 - 0x1F */
    DIAG_CELLMON_TYPE   = 0x01,     /*!< FC 0x20 - 0x3F */
    DIAG_COM_TYPE       = 0x02,     /*!< FC 0x40 - 0x5F */
    DIAG_ADC_TYPE       = 0x04,     /*!< FC 0x60 - 0x7F */
    // FIXME which failure codes for following group?
    DIAG_CONT_TYPE      = 0x08      /*!< FC             */
} DIAG_TYPE_e;

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

// FIXME duplicate comment with enum DIAG_TYPE_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  = 0x00,     /*!< */
    DIAG_SYSMON_RESERVED    = 0x01      /*!< */
} DIAG_SYSMON_TYPE_e;

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


/**
 * @brief   symbolic names for diagnosis
 */
typedef enum {
    DIAG_OK     = 0,    /*!< diagnosis event ok     */
    DIAG_NOT_OK = 1,    /*!< diagnosis event not ok */
    DIAG_BUSY   = 2     /*!< diagnosis event busy   */
} Diag_ReturnType;


/**
 * @brief listing of system-relevant tasks or functions which are checked by system monitoring
 *
 * diag_sysmon_ch_cfg[]=
 */
typedef enum {
    DIAG_SYSMON_DATABASE_ID         = 0,    /*!< diag entry for database                */
    DIAG_SYSMON_SYS_ID              = 1,    /*!< diag entry for sys              */
    DIAG_SYSMON_BMS_ID              = 2,    /*!< diag entry for bms              */
    DIAG_SYSMON_CONT_ID             = 3,    /*!< diag entry for contactors              */
    DIAG_SYSMON_ILCK_ID             = 4,    /*!< diag entry for contactors              */
    DIAG_SYSMON_LTC_ID              = 5,    /*!< diag entry for ltc                     */
    DIAG_SYSMON_ISOGUARD_ID         = 6,    /*!< diag entry for ioguard                 */
    DIAG_SYSMON_CANS_ID             = 7,    /*!< diag entry for can                     */
    DIAG_SYSMON_APPL_CYCLIC_1ms     = 8,    /*!< diag entry for application 10ms task   */
    DIAG_SYSMON_APPL_CYCLIC_10ms    = 9,    /*!< diag entry for application 10ms task   */
    DIAG_SYSMON_APPL_CYCLIC_100ms   = 10,    /*!< diag entry for application 100ms task  */
    DIAG_SYSMON_MODULE_ID_MAX       = 11     /*!< 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];
    DIAG_TYPE_e type;                       /*!< diagnosis group of diag event */
    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;

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

/**
 * 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;
/*================== Function Prototypes ==================================*/

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

#endif /* DIAG_CFG_H_ */

diag_id_cfg.h (primary)

/**
 *
 * @copyright &copy; 2010 - 2018, 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_id_cfg.h
 * @author  foxBMS Team
 * @date    13.11.2015 (date of creation)
 * @ingroup ENGINE
 * @prefix  DIAG
 *
 * @brief   This file contains basic definitions in order to use an abstracted diagnosis
 */

#ifndef DIAG_ID_CFG_H_
#define DIAG_ID_CFG_H_

/*================== Includes =============================================*/

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

/**
 * symbolic IDs for possible diagnosis entries
 */
typedef enum {
    DIAG_ID_0       = 0,
    DIAG_ID_1       = 1,
    DIAG_ID_2       = 2,
    DIAG_ID_3       = 3,
    DIAG_ID_4       = 4,
    DIAG_ID_5       = 5,
    DIAG_ID_6       = 6,
    DIAG_ID_7       = 7,
    DIAG_ID_8       = 8,
    DIAG_ID_9       = 9,
    DIAG_ID_10      = 10,
    DIAG_ID_11      = 11,
    DIAG_ID_12      = 12,
    DIAG_ID_13      = 13,
    DIAG_ID_14      = 14,
    DIAG_ID_15      = 15,

    DIAG_ID_16      = 16,
    DIAG_ID_17      = 17,
    DIAG_ID_18      = 18,
    DIAG_ID_19      = 19,
    DIAG_ID_20      = 20,
    DIAG_ID_21      = 21,
    DIAG_ID_22      = 22,
    DIAG_ID_23      = 23,
    DIAG_ID_24      = 24,
    DIAG_ID_25      = 25,
    DIAG_ID_26      = 26,
    DIAG_ID_27      = 27,
    DIAG_ID_28      = 28,
    DIAG_ID_29      = 29,
    DIAG_ID_30      = 30,
    DIAG_ID_31      = 31,

    DIAG_ID_32      = 32,
    DIAG_ID_33      = 33,
    DIAG_ID_34      = 34,
    DIAG_ID_35      = 35,
    DIAG_ID_36      = 36,
    DIAG_ID_37      = 37,
    DIAG_ID_38      = 38,
    DIAG_ID_39      = 39,
    DIAG_ID_40      = 40,
    DIAG_ID_41      = 41,
    DIAG_ID_42      = 42,
    DIAG_ID_43      = 43,
    DIAG_ID_44      = 44,
    DIAG_ID_45      = 45,
    DIAG_ID_46      = 46,
    DIAG_ID_47      = 47,

    DIAG_ID_48      = 48,
    DIAG_ID_49      = 49,
    DIAG_ID_50      = 50,
    DIAG_ID_51      = 51,
    DIAG_ID_52      = 52,
    DIAG_ID_53      = 53,
    DIAG_ID_54      = 54,
    DIAG_ID_55      = 55,
    DIAG_ID_56      = 56,
    DIAG_ID_57      = 57,
    DIAG_ID_58      = 58,
    DIAG_ID_59      = 59,
    DIAG_ID_60      = 60,
    DIAG_ID_61      = 61,
    DIAG_ID_62      = 62,
    DIAG_ID_63      = 63,

    DIAG_ID_64      = 64,
    DIAG_ID_65      = 65,
    DIAG_ID_66      = 66,
    DIAG_ID_67      = 67,
    DIAG_ID_68      = 68,
    DIAG_ID_69      = 69,
    DIAG_ID_70      = 70,
    DIAG_ID_71      = 71,
    DIAG_ID_72      = 72,
    DIAG_ID_73      = 73,
    DIAG_ID_74      = 74,
    DIAG_ID_75      = 75,
    DIAG_ID_76      = 76,
    DIAG_ID_77      = 77,
    DIAG_ID_78      = 78,
    DIAG_ID_79      = 79,

    DIAG_ID_80      = 80,
    DIAG_ID_81      = 81,
    DIAG_ID_82      = 82,
    DIAG_ID_83      = 83,
    DIAG_ID_84      = 84,
    DIAG_ID_85      = 85,
    DIAG_ID_86      = 86,
    DIAG_ID_87      = 87,
    DIAG_ID_88      = 88,
    DIAG_ID_89      = 89,
    DIAG_ID_90      = 90,
    DIAG_ID_91      = 91,
    DIAG_ID_92      = 92,
    DIAG_ID_93      = 93,
    DIAG_ID_94      = 94,
    DIAG_ID_95      = 95,

    DIAG_ID_96      = 96,
    DIAG_ID_97      = 97,
    DIAG_ID_98      = 98,
    DIAG_ID_99      = 99,
    DIAG_ID_100     = 100,
    DIAG_ID_101     = 101,
    DIAG_ID_102     = 102,
    DIAG_ID_103     = 103,
    DIAG_ID_104     = 104,
    DIAG_ID_105     = 105,
    DIAG_ID_106     = 106,
    DIAG_ID_107     = 107,
    DIAG_ID_108     = 108,
    DIAG_ID_109     = 109,
    DIAG_ID_110     = 110,
    DIAG_ID_111     = 111,

    DIAG_ID_MAX     = 112,

} DIAG_CH_ID_e;

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

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

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

#endif /* DIAG_ID_CFG_H_ */

diag_cfg.c (secondary)

/**
 *
 * @copyright &copy; 2010 - 2018, 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 ===============================*/

/*================== 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,
};

/**
 * Callback function of diagnosis error events
 *
*/

static void dummyfu(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event);

static void DIAG_MSL_overvoltage(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event);

static void DIAG_MSL_undervoltage(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event);

static void DIAG_MSL_overtemperaturecharge(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event);

static void DIAG_MSL_overtemperaturedischarge(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event);

static void DIAG_MSL_undertemperaturecharge(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event);

static void DIAG_MSL_undertemperaturedischarge(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event);

static void DIAG_MSL_overcurrentcharge(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event);

static void DIAG_MSL_overcurrentdischarge(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event);

static void DIAG_error_cantiming(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event);
static void DIAG_error_cantiming_cc(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_error_ltcpec(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event);
static void DIAG_error_ltcmux(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event);
static void DIAG_error_ltcspi(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event);

static void DIAG_error_contactormainplus(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event);
static void DIAG_error_contactormainminus(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event);

static void DIAG_error_contactorprecharge(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event);
static void DIAG_error_contactorchargemainplus(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event);

static void DIAG_error_contactorchargemainminus(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event);
static void DIAG_error_contactorchargeprecharge(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 dummyfu2(DIAG_SYSMON_MODULE_ID_e ch_id);

void dummyfu(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event) {
    ;
}

void DIAG_MSL_overvoltage(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event) {
    DATA_BLOCK_MSL_FLAG_s msl_flags;
    DB_ReadBlock(&msl_flags, DATA_BLOCK_ID_MSL);
    if (event == DIAG_EVENT_RESET) {
        msl_flags.over_voltage = 0;
    }
    if (event == DIAG_EVENT_NOK) {
        msl_flags.over_voltage = 1;
    }
    DB_WriteBlock(&msl_flags, DATA_BLOCK_ID_MSL);
}

void DIAG_MSL_undervoltage(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event) {
    DATA_BLOCK_MSL_FLAG_s msl_flags;
    DB_ReadBlock(&msl_flags, DATA_BLOCK_ID_MSL);
    if (event == DIAG_EVENT_RESET) {
        msl_flags.under_voltage = 0;
    }
    if (event == DIAG_EVENT_NOK) {
        msl_flags.under_voltage = 1;
    }
    DB_WriteBlock(&msl_flags, DATA_BLOCK_ID_MSL);
}

void DIAG_MSL_overtemperaturecharge(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event) {
    DATA_BLOCK_MSL_FLAG_s msl_flags;
    DB_ReadBlock(&msl_flags, DATA_BLOCK_ID_MSL);
    if (event == DIAG_EVENT_RESET) {
        msl_flags.over_temperature_charge = 0;
    }
    if (event == DIAG_EVENT_NOK) {
        msl_flags.over_temperature_charge = 1;
    }
    DB_WriteBlock(&msl_flags, DATA_BLOCK_ID_MSL);
}
void DIAG_MSL_overtemperaturedischarge(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event) {
    DATA_BLOCK_MSL_FLAG_s msl_flags;
    DB_ReadBlock(&msl_flags, DATA_BLOCK_ID_MSL);
    if (event == DIAG_EVENT_RESET) {
        msl_flags.over_temperature_discharge = 0;
    }
    if (event == DIAG_EVENT_NOK) {
        msl_flags.over_temperature_discharge = 1;
    }
    DB_WriteBlock(&msl_flags, DATA_BLOCK_ID_MSL);
}
void DIAG_MSL_undertemperaturecharge(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event) {
    DATA_BLOCK_MSL_FLAG_s msl_flags;
    DB_ReadBlock(&msl_flags, DATA_BLOCK_ID_MSL);
    if (event == DIAG_EVENT_RESET) {
        msl_flags.under_temperature_charge = 0;
    }
    if (event == DIAG_EVENT_NOK) {
        msl_flags.under_temperature_charge = 1;
    }
    DB_WriteBlock(&msl_flags, DATA_BLOCK_ID_MSL);
}
void DIAG_MSL_undertemperaturedischarge(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event) {
    DATA_BLOCK_MSL_FLAG_s msl_flags;
    DB_ReadBlock(&msl_flags, DATA_BLOCK_ID_MSL);
    if (event == DIAG_EVENT_RESET) {
        msl_flags.under_temperature_discharge = 0;
    }
    if (event == DIAG_EVENT_NOK) {
        msl_flags.under_temperature_discharge = 1;
    }
    DB_WriteBlock(&msl_flags, DATA_BLOCK_ID_MSL);
}
void DIAG_MSL_overcurrentcharge(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event) {
    DATA_BLOCK_MSL_FLAG_s msl_flags;
    DB_ReadBlock(&msl_flags, DATA_BLOCK_ID_MSL);
    if (event == DIAG_EVENT_RESET) {
        msl_flags.over_current_charge = 0;
    }
    if (event == DIAG_EVENT_NOK) {
        msl_flags.over_current_charge = 1;
    }
    DB_WriteBlock(&msl_flags, DATA_BLOCK_ID_MSL);
}
void DIAG_MSL_overcurrentdischarge(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event) {
    DATA_BLOCK_MSL_FLAG_s msl_flags;
    DB_ReadBlock(&msl_flags, DATA_BLOCK_ID_MSL);
    if (event == DIAG_EVENT_RESET) {
        msl_flags.over_current_discharge = 0;
    }
    if (event == DIAG_EVENT_NOK) {
        msl_flags.over_current_discharge = 1;
    }
    DB_WriteBlock(&msl_flags, DATA_BLOCK_ID_MSL);
}
void DIAG_error_cantiming(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event) {
    DATA_BLOCK_ERRORSTATE_s error_flags;
    DB_ReadBlock(&error_flags, DATA_BLOCK_ID_ERRORSTATE);
    if (event == DIAG_EVENT_RESET) {
        error_flags.can_timing = 0;
    }
    if (event == DIAG_EVENT_NOK) {
        error_flags.can_timing = 1;
    }
    DB_WriteBlock(&error_flags, DATA_BLOCK_ID_ERRORSTATE);
}

void DIAG_error_cantiming_cc(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event) {
    DATA_BLOCK_ERRORSTATE_s error_flags;
    DB_ReadBlock(&error_flags, DATA_BLOCK_ID_ERRORSTATE);
    if (event == DIAG_EVENT_RESET) {
        error_flags.can_timing_cc = 0;
    }
    if (event == DIAG_EVENT_NOK) {
        error_flags.can_timing_cc = 1;
    }
    DB_WriteBlock(&error_flags, DATA_BLOCK_ID_ERRORSTATE);
}

void DIAG_error_cancurrentsensor(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event) {
    DATA_BLOCK_ERRORSTATE_s error_flags;
    DB_ReadBlock(&error_flags, DATA_BLOCK_ID_ERRORSTATE);
    if (event == DIAG_EVENT_RESET) {
        error_flags.currentsensorresponding = 0;
    }
    if (event == DIAG_EVENT_NOK) {
        error_flags.currentsensorresponding = 1;
    }
    DB_WriteBlock(&error_flags, DATA_BLOCK_ID_ERRORSTATE);
}

void DIAG_error_ltcpec(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event) {
    DATA_BLOCK_ERRORSTATE_s error_flags;
    DB_ReadBlock(&error_flags, DATA_BLOCK_ID_ERRORSTATE);
    if (event == DIAG_EVENT_RESET) {
        error_flags.crc_error = 0;
    }
    if (event == DIAG_EVENT_NOK) {
        error_flags.crc_error = 1;
    }
    DB_WriteBlock(&error_flags, DATA_BLOCK_ID_ERRORSTATE);
}

void DIAG_error_ltcmux(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event) {
    DATA_BLOCK_ERRORSTATE_s error_flags;
    DB_ReadBlock(&error_flags, DATA_BLOCK_ID_ERRORSTATE);
    if (event == DIAG_EVENT_RESET) {
        error_flags.mux_error = 0;
    }
    if (event == DIAG_EVENT_NOK) {
        error_flags.mux_error = 1;
    }
    DB_WriteBlock(&error_flags, DATA_BLOCK_ID_ERRORSTATE);
}

void DIAG_error_ltcspi(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event) {
    DATA_BLOCK_ERRORSTATE_s error_flags;
    DB_ReadBlock(&error_flags, DATA_BLOCK_ID_ERRORSTATE);
    if (event == DIAG_EVENT_RESET) {
        error_flags.spi_error = 0;
    }
    if (event == DIAG_EVENT_NOK) {
        error_flags.spi_error = 1;
    }
    DB_WriteBlock(&error_flags, DATA_BLOCK_ID_ERRORSTATE);
}

void DIAG_error_contactormainplus(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event) {
    DATA_BLOCK_ERRORSTATE_s error_flags;
    DB_ReadBlock(&error_flags, DATA_BLOCK_ID_ERRORSTATE);
    if (event == DIAG_EVENT_RESET) {
        error_flags.main_plus = 0;
    }
    if (event == DIAG_EVENT_NOK) {
        error_flags.main_plus = 1;
    }
    DB_WriteBlock(&error_flags, DATA_BLOCK_ID_ERRORSTATE);
}

void DIAG_error_contactormainminus(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event) {
    DATA_BLOCK_ERRORSTATE_s error_flags;
    DB_ReadBlock(&error_flags, DATA_BLOCK_ID_ERRORSTATE);
    if (event == DIAG_EVENT_RESET) {
        error_flags.main_minus = 0;
    }
    if (event == DIAG_EVENT_NOK) {
        error_flags.main_minus = 1;
    }
    DB_WriteBlock(&error_flags, DATA_BLOCK_ID_ERRORSTATE);
}

void DIAG_error_contactorprecharge(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event) {
    DATA_BLOCK_ERRORSTATE_s error_flags;
    DB_ReadBlock(&error_flags, DATA_BLOCK_ID_ERRORSTATE);
    if (event == DIAG_EVENT_RESET) {
        error_flags.precharge = 0;
    }
    if (event == DIAG_EVENT_NOK) {
        error_flags.precharge = 1;
    }
    DB_WriteBlock(&error_flags, DATA_BLOCK_ID_ERRORSTATE);
}

void DIAG_error_contactorchargemainplus(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event) {
    DATA_BLOCK_ERRORSTATE_s error_flags;
    DB_ReadBlock(&error_flags, DATA_BLOCK_ID_ERRORSTATE);
    if (event == DIAG_EVENT_RESET) {
        error_flags.charge_main_plus = 0;
    }
    if (event == DIAG_EVENT_NOK) {
        error_flags.charge_main_plus = 1;
    }
    DB_WriteBlock(&error_flags, DATA_BLOCK_ID_ERRORSTATE);
}

void DIAG_error_contactorchargemainminus(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event) {
    DATA_BLOCK_ERRORSTATE_s error_flags;
    DB_ReadBlock(&error_flags, DATA_BLOCK_ID_ERRORSTATE);
    if (event == DIAG_EVENT_RESET) {
        error_flags.charge_main_minus = 0;
    }
    if (event == DIAG_EVENT_NOK) {
        error_flags.charge_main_minus = 1;
    }
    DB_WriteBlock(&error_flags, DATA_BLOCK_ID_ERRORSTATE);
}

void DIAG_error_contactorchargeprecharge(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event) {
    DATA_BLOCK_ERRORSTATE_s error_flags;
    DB_ReadBlock(&error_flags, DATA_BLOCK_ID_ERRORSTATE);
    if (event == DIAG_EVENT_RESET) {
        error_flags.charge_precharge = 0;
    }
    if (event == DIAG_EVENT_NOK) {
        error_flags.charge_precharge = 1;
    }
    DB_WriteBlock(&error_flags, DATA_BLOCK_ID_ERRORSTATE);
}

void DIAG_error_interlock(DIAG_CH_ID_e ch_id, DIAG_EVENT_e event) {
    DATA_BLOCK_ERRORSTATE_s error_flags;
    DB_ReadBlock(&error_flags, DATA_BLOCK_ID_ERRORSTATE);
    if (event  ==  DIAG_EVENT_RESET) {
        error_flags.interlock = 0;
    }
    if (event==DIAG_EVENT_NOK) {
        error_flags.interlock = 1;
    }
    DB_WriteBlock(&error_flags, DATA_BLOCK_ID_ERRORSTATE);
}

/**
 * Callback function of system monitoring error events
 *
*/
void dummyfu2(DIAG_SYSMON_MODULE_ID_e ch_id) {
    ;
}


DIAG_CH_CFG_s  diag_ch_cfg[] = {

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

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

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


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

    {DIAG_CH_ISOMETER_TIM_ERROR,                        "ISOMETER_TIM_ERROR",                   DIAG_GENERAL_TYPE, DIAG_ERROR_SENSITIVITY_MID,               DIAG_RECORDING_ENABLED, DIAG_ENABLED, dummyfu},
    {DIAG_CH_ISOMETER_GROUNDERROR,                      "ISOMETER_GROUNDERROR",                 DIAG_GENERAL_TYPE, DIAG_ERROR_SENSITIVITY_HIGH,              DIAG_RECORDING_ENABLED, DIAG_ENABLED, dummyfu},
    {DIAG_CH_ISOMETER_ERROR,                            "ISOMETER_ERROR",                       DIAG_GENERAL_TYPE, DIAG_ERROR_SENSITIVITY_MID,               DIAG_RECORDING_ENABLED, DIAG_ENABLED, dummyfu},
    {DIAG_CH_ISOMETER_MEAS_INVALID,                     "ISOMETER_MEAS_INVALID",                DIAG_GENERAL_TYPE, DIAG_ERROR_SENSITIVITY_HIGH,              DIAG_RECORDING_ENABLED, DIAG_ENABLED, dummyfu},

    /* Under and over temperature, voltage and current at cell level */
    {DIAG_CH_CELLVOLTAGE_OVERVOLTAGE_MSL,             "CELLVOLTAGE_OVERVOLTAGE_MSL",            DIAG_GENERAL_TYPE, DIAG_ERROR_VOLTAGE_SENSITIVITY_MSL,           DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_MSL_overvoltage},

    {DIAG_CH_CELLVOLTAGE_UNDERVOLTAGE_MSL,            "CELLVOLTAGE_UNDERVOLTAGE_MSL",           DIAG_GENERAL_TYPE, DIAG_ERROR_VOLTAGE_SENSITIVITY_MSL,           DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_MSL_undervoltage},

    {DIAG_CH_TEMP_OVERTEMPERATURE_CHARGE_MSL,         "OVERTEMPERATURE_CHARGE_MSL",             DIAG_GENERAL_TYPE, DIAG_ERROR_TEMPERATURE_SENSITIVITY_MSL,       DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_MSL_overtemperaturecharge},
    {DIAG_CH_TEMP_OVERTEMPERATURE_DISCHARGE_MSL,      "OVERTEMPERATURE_DISCHARGE_MSL",          DIAG_GENERAL_TYPE, DIAG_ERROR_TEMPERATURE_SENSITIVITY_MSL,       DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_MSL_overtemperaturedischarge},

    {DIAG_CH_TEMP_UNDERTEMPERATURE_CHARGE_MSL,        "UNDERTEMPERATURE_CHARGE_MSL",            DIAG_GENERAL_TYPE, DIAG_ERROR_TEMPERATURE_SENSITIVITY_MSL,       DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_MSL_undertemperaturecharge},

    {DIAG_CH_TEMP_UNDERTEMPERATURE_DISCHARGE_MSL,     "UNDERTEMPERATURE_DISCHARGE_MSL",         DIAG_GENERAL_TYPE, DIAG_ERROR_TEMPERATURE_SENSITIVITY_MSL,       DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_MSL_undertemperaturedischarge},

    {DIAG_CH_OVERCURRENT_CHARGE_MSL,                  "OVERCURRENT_CHARGE_MSL",                 DIAG_GENERAL_TYPE, DIAG_ERROR_CURRENT_SENSITIVITY_MSL,           DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_MSL_overcurrentcharge},

    {DIAG_CH_OVERCURRENT_DISCHARGE_MSL,               "OVERCURRENT_DISCHARGE_MSL",              DIAG_GENERAL_TYPE, DIAG_ERROR_CURRENT_SENSITIVITY_MSL,           DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_MSL_overcurrentdischarge},

    {DIAG_CH_LTC_SPI,                                   "LTC_SPI",                              DIAG_GENERAL_TYPE, DIAG_ERROR_LTC_SPI_SENSITIVITY,           DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_error_ltcspi},
    {DIAG_CH_LTC_PEC,                                   "LTC_PEC",                              DIAG_GENERAL_TYPE, DIAG_ERROR_LTC_PEC_SENSITIVITY,           DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_error_ltcpec},
    {DIAG_CH_LTC_MUX,                                   "LTC_MUX",                              DIAG_GENERAL_TYPE, DIAG_ERROR_LTC_MUX_SENSITIVITY,           DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_error_ltcmux},

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

    /* Contactor Damage Error */
    {DIAG_CH_CONTACTOR_DAMAGED,                         "CONTACTOR_DAMAGED",                    DIAG_CONT_TYPE,     DIAG_ERROR_SENSITIVITY_HIGH,              DIAG_RECORDING_ENABLED, DIAG_ENABLED, dummyfu},
    {DIAG_CH_CONTACTOR_OPENING,                         "CONTACTOR_OPENING",                    DIAG_CONT_TYPE,     DIAG_ERROR_SENSITIVITY_HIGH,              DIAG_RECORDING_ENABLED, DIAG_ENABLED, dummyfu},
    {DIAG_CH_CONTACTOR_CLOSING,                         "CONTACTOR_CLOSING",                    DIAG_CONT_TYPE,     DIAG_ERROR_SENSITIVITY_HIGH,              DIAG_RECORDING_ENABLED, DIAG_ENABLED, dummyfu},

    /* Contactor Feedback Error */
    {DIAG_CH_CONTACTOR_MAIN_PLUS_FEEDBACK,              "CONTACTOR_MAIN_PLUS_FEEDBACK",         DIAG_GENERAL_TYPE,  DIAG_ERROR_MAIN_PLUS_SENSITIVITY,      DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_error_contactormainplus},
    {DIAG_CH_CONTACTOR_MAIN_MINUS_FEEDBACK,             "CONTACTOR_MAIN_MINUS_FEEDBACK",        DIAG_GENERAL_TYPE,  DIAG_ERROR_MAIN_MINUS_SENSITIVITY,     DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_error_contactormainminus},
    {DIAG_CH_CONTACTOR_PRECHARGE_FEEDBACK,              "CONTACTOR_PRECHARGE_FEEDBACK",         DIAG_GENERAL_TYPE,  DIAG_ERROR_PRECHARGE_SENSITIVITY,      DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_error_contactorprecharge},
    {DIAG_CH_CONTACTOR_CHARGE_MAIN_PLUS_FEEDBACK,       "CONTACTOR_CHARGE_MAIN_PLUS_FEEDBACK",  DIAG_GENERAL_TYPE,  DIAG_ERROR_MAIN_PLUS_SENSITIVITY,      DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_error_contactorchargemainplus},
    {DIAG_CH_CONTACTOR_CHARGE_MAIN_MINUS_FEEDBACK,      "CONTACTOR_CHARGE_MAIN_MINUS_FEEDBACK", DIAG_GENERAL_TYPE,  DIAG_ERROR_MAIN_MINUS_SENSITIVITY,     DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_error_contactorchargemainminus},
    {DIAG_CH_CONTACTOR_CHARGE_PRECHARGE_FEEDBACK,       "CONTACTOR_CHARGE_PRECHARGE_FEEDBACK",  DIAG_GENERAL_TYPE,  DIAG_ERROR_PRECHARGE_SENSITIVITY,      DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_error_contactorchargeprecharge},

    /* Interlock Feedback Error */
    {DIAG_CH_INTERLOCK_FEEDBACK,                        "INTERLOCK_FEEDBACK",                   DIAG_GENERAL_TYPE,  DIAG_ERROR_INTERLOCK_SENSITIVITY,       DIAG_RECORDING_ENABLED, DIAG_ENABLED, DIAG_error_interlock},

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

    {DIAG_CH_SLAVE_PCB_OVERTEMPERATURE_MSL,           "SLAVE_PCB_OVERTEMPERATURE_MSL",      DIAG_GENERAL_TYPE,    DIAG_ERROR_SLAVE_TEMP_SENSITIVITY_MSL,   DIAG_RECORDING_ENABLED, DIAG_ENABLED, dummyfu},
};


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},
    {DIAG_SYSMON_ILCK_ID,        DIAG_SYSMON_CYCLICTASK,  20, DIAG_RECORDING_ENABLED, DIAG_SYSMON_HANDLING_SWITCHOFFCONTACTOR, DIAG_ENABLED, dummyfu2},
    {DIAG_SYSMON_LTC_ID,            DIAG_SYSMON_CYCLICTASK,   5, DIAG_RECORDING_ENABLED, DIAG_SYSMON_HANDLING_SWITCHOFFCONTACTOR, DIAG_ENABLED, dummyfu2},
    {DIAG_SYSMON_ISOGUARD_ID,       DIAG_SYSMON_CYCLICTASK, 400, DIAG_RECORDING_DISABLED, DIAG_SYSMON_HANDLING_SWITCHOFFCONTACTOR, DIAG_DISABLED, dummyfu2},
    {DIAG_SYSMON_CANS_ID,           DIAG_SYSMON_CYCLICTASK,  20, DIAG_RECORDING_DISABLED, DIAG_SYSMON_HANDLING_SWITCHOFFCONTACTOR, DIAG_DISABLED, 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],
};

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

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

diag_cfg.h (secondary)

/**
 *
 * @copyright &copy; 2010 - 2018, 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"
#include "diag_id_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        (500)
#define DIAG_ERROR_MAIN_MINUS_SENSITIVITY       (500)
#define DIAG_ERROR_PRECHARGE_SENSITIVITY        (500)

#define DIAG_ERROR_INTERLOCK_SENSITIVITY        (0)

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

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

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


// FIXME simple doxygen comment for each define?
/* Initialization and startup events: 0-15 */
#define DIAG_CH_FLASHCHECKSUM                              DIAG_ID_5            //
#define DIAG_CH_BKPDIAG_FAILURE                            DIAG_ID_6            //
#define DIAG_CH_WATCHDOGRESET_FAILURE                      DIAG_ID_7            //
#define DIAG_CH_POSTOSINIT_FAILURE                         DIAG_ID_8            //
#define DIAG_CH_CALIB_EEPR_FAILURE                         DIAG_ID_9            //
#define DIAG_CH_CAN_INIT_FAILURE                           DIAG_ID_10           //
#define DIAG_CH_VIC_INIT_FAILURE                           DIAG_ID_11

/* HW-/SW-Runtime events: 16-31 */
#define DIAG_CH_DIV_BY_ZERO_FAILURE                        DIAG_ID_16            //
#define DIAG_CH_UNDEF_INSTRUCTION_FAILURE                  DIAG_ID_17            //
#define DIAG_CH_DATA_BUS_FAILURE                           DIAG_ID_18            //
#define DIAG_CH_INSTRUCTION_BUS_FAILURE                    DIAG_ID_19            //
#define DIAG_CH_HARDFAULT_NOTHANDLED                       DIAG_ID_20            //
#define DIAG_CH_RUNTIME_ERROR_RESERVED_1                   DIAG_ID_21            // reserved for future needs
#define DIAG_CH_RUNTIME_ERROR_RESERVED_2                   DIAG_ID_22            // reserved for future needs
#define DIAG_CH_RUNTIME_ERROR_RESERVED_3                   DIAG_ID_23            // reserved for future needs
#define DIAG_CH_CONFIGASSERT                               DIAG_ID_24            //
#define DIAG_CH_SYSTEMMONITORING_TIMEOUT                   DIAG_ID_25            //


/* Measurement events: 32-47 */
#define DIAG_CH_CANS_MAX_VALUE_VIOLATE                     DIAG_ID_32
#define DIAG_CH_CANS_MIN_VALUE_VIOLATE                     DIAG_ID_33
#define DIAG_CH_CANS_CAN_MOD_FAILURE                       DIAG_ID_34

/**
 * Measured frequency too low or no new value captured during last cycle
 */
#define DIAG_CH_ISOMETER_TIM_ERROR                         DIAG_ID_35

/**
 * Ground error detected
 */
#define DIAG_CH_ISOMETER_GROUNDERROR                       DIAG_ID_36

/**
 * Device error, invalid measurement result
 */
#define DIAG_CH_ISOMETER_ERROR                             DIAG_ID_37

 /**
  * Measurement trustworthy or not, hysteresis to ground error flag
  */
#define DIAG_CH_ISOMETER_MEAS_INVALID                      DIAG_ID_38

/**
 * Cell voltage limits violated
 */
#define DIAG_CH_CELLVOLTAGE_OVERVOLTAGE_MSL                DIAG_ID_39

#define DIAG_CH_CELLVOLTAGE_UNDERVOLTAGE_MSL               DIAG_ID_42

/**
 *  Temperature limits violated
 */
#define DIAG_CH_TEMP_OVERTEMPERATURE_CHARGE_MSL            DIAG_ID_45

#define DIAG_CH_TEMP_OVERTEMPERATURE_DISCHARGE_MSL         DIAG_ID_48

#define DIAG_CH_TEMP_UNDERTEMPERATURE_CHARGE_MSL           DIAG_ID_51


#define DIAG_CH_TEMP_UNDERTEMPERATURE_DISCHARGE_MSL        DIAG_ID_54

/**
 * Overcurrent
 */
#define DIAG_CH_OVERCURRENT_CHARGE_MSL                     DIAG_ID_57
#define DIAG_CH_OVERCURRENT_DISCHARGE_MSL                  DIAG_ID_60




/**
 * LTC
 */
#define DIAG_CH_LTC_SPI                                    DIAG_ID_63
#define DIAG_CH_LTC_PEC                                    DIAG_ID_64
#define DIAG_CH_LTC_MUX                                    DIAG_ID_65


/* Communication events: 50-63*/
/**
 *  CAN timing not coming
 */
#define DIAG_CH_CAN_TIMING                                 DIAG_ID_66
/**
 *  CAN C-C not coming
 */
#define DIAG_CH_CAN_CC_RESPONDING                          DIAG_ID_67
/**
 *  Current sensor not responding anymore
 */
#define DIAG_CH_CURRENT_SENSOR_RESPONDING                  DIAG_ID_68


/* Contactor events: 64-79*/
/**
 * @brief   Opening contactor at over current
 */
#define DIAG_CH_CONTACTOR_DAMAGED                          DIAG_ID_69

/**
 * @brief   counter for contactor opening
 */
#define DIAG_CH_CONTACTOR_OPENING                           DIAG_ID_70

/**
 * @brief   counter for contactor closing
 */
#define DIAG_CH_CONTACTOR_CLOSING                           DIAG_ID_71

/**
 * @brief   Contactor feedback error
 */
#define DIAG_CH_CONTACTOR_MAIN_PLUS_FEEDBACK                DIAG_ID_72
#define DIAG_CH_CONTACTOR_MAIN_MINUS_FEEDBACK               DIAG_ID_73
#define DIAG_CH_CONTACTOR_PRECHARGE_FEEDBACK                DIAG_ID_74
#define DIAG_CH_CONTACTOR_CHARGE_MAIN_PLUS_FEEDBACK         DIAG_ID_75
#define DIAG_CH_CONTACTOR_CHARGE_MAIN_MINUS_FEEDBACK        DIAG_ID_76
#define DIAG_CH_CONTACTOR_CHARGE_PRECHARGE_FEEDBACK         DIAG_ID_77

/**
 * @brief   Interlock feedback error
 */
#define DIAG_CH_INTERLOCK_FEEDBACK                          DIAG_ID_78



#define DIAG_CH_SLAVE_PCB_UNDERTEMPERATURE_MSL              DIAG_ID_79

#define DIAG_CH_SLAVE_PCB_OVERTEMPERATURE_MSL               DIAG_ID_82

/**
 * enable state of diagnosis entry
 */
typedef enum {
    DIAG_ENABLED  = 0,
    DIAG_DISABLED = 1,
} 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

// FIXME is it better to name it DIAG_GROUP_xxx instead of DIAG_xxx_TYPE and
/**
 * diagnosis groups
 * failure codes FC
 */
typedef enum {
    DIAG_GENERAL_TYPE   = 0x00,     /*!< FC 0x00 - 0x1F */
    DIAG_CELLMON_TYPE   = 0x01,     /*!< FC 0x20 - 0x3F */
    DIAG_COM_TYPE       = 0x02,     /*!< FC 0x40 - 0x5F */
    DIAG_ADC_TYPE       = 0x04,     /*!< FC 0x60 - 0x7F */
    // FIXME which failure codes for following group?
    DIAG_CONT_TYPE      = 0x08      /*!< FC             */
} DIAG_TYPE_e;

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

// FIXME duplicate comment with enum DIAG_TYPE_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  = 0x00,     /*!< */
    DIAG_SYSMON_RESERVED    = 0x01      /*!< */
} DIAG_SYSMON_TYPE_e;

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


/**
 * @brief   symbolic names for diagnosis
 */
typedef enum {
    DIAG_OK     = 0,    /*!< diagnosis event ok     */
    DIAG_NOT_OK = 1,    /*!< diagnosis event not ok */
    DIAG_BUSY   = 2     /*!< diagnosis event busy   */
} Diag_ReturnType;


/**
 * @brief listing of system-relevant tasks or functions which are checked by system monitoring
 *
 * diag_sysmon_ch_cfg[]=
 */
typedef enum {
    DIAG_SYSMON_DATABASE_ID         = 0,    /*!< diag entry for database                */
    DIAG_SYSMON_SYS_ID              = 1,    /*!< diag entry for sys              */
    DIAG_SYSMON_BMS_ID              = 2,    /*!< diag entry for bms              */
    DIAG_SYSMON_ILCK_ID              = 2,    /*!< diag entry for bms              */
    DIAG_SYSMON_LTC_ID              = 3,    /*!< diag entry for ltc                     */
    DIAG_SYSMON_ISOGUARD_ID         = 4,    /*!< diag entry for ioguard                 */
    DIAG_SYSMON_CANS_ID             = 5,    /*!< diag entry for can                     */
    DIAG_SYSMON_APPL_CYCLIC_1ms     = 6,    /*!< diag entry for application 10ms task   */
    DIAG_SYSMON_APPL_CYCLIC_10ms    = 7,    /*!< diag entry for application 10ms task   */
    DIAG_SYSMON_APPL_CYCLIC_100ms   = 8,    /*!< diag entry for application 100ms task  */
    DIAG_SYSMON_MODULE_ID_MAX       = 9     /*!< 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];
    DIAG_TYPE_e type;                       /*!< diagnosis group of diag event */
    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;

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

/**
 * 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;
/*================== Function Prototypes ==================================*/

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

#endif /* DIAG_CFG_H_ */

diag_id_cfg.h (secondary)

/**
 *
 * @copyright &copy; 2010 - 2018, 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_id_cfg.h
 * @author  foxBMS Team
 * @date    13.11.2015 (date of creation)
 * @ingroup ENGINE
 * @prefix  DIAG
 *
 * @brief   This file contains basic definitions in order to use an abstracted diagnosis
 */

#ifndef DIAG_ID_CFG_H_
#define DIAG_ID_CFG_H_

/*================== Includes =============================================*/

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

/**
 * symbolic IDs for possible diagnosis entries
 */
typedef enum {
    DIAG_ID_0       = 0,
    DIAG_ID_1       = 1,
    DIAG_ID_2       = 2,
    DIAG_ID_3       = 3,
    DIAG_ID_4       = 4,
    DIAG_ID_5       = 5,
    DIAG_ID_6       = 6,
    DIAG_ID_7       = 7,
    DIAG_ID_8       = 8,
    DIAG_ID_9       = 9,
    DIAG_ID_10      = 10,
    DIAG_ID_11      = 11,
    DIAG_ID_12      = 12,
    DIAG_ID_13      = 13,
    DIAG_ID_14      = 14,
    DIAG_ID_15      = 15,

    DIAG_ID_16      = 16,
    DIAG_ID_17      = 17,
    DIAG_ID_18      = 18,
    DIAG_ID_19      = 19,
    DIAG_ID_20      = 20,
    DIAG_ID_21      = 21,
    DIAG_ID_22      = 22,
    DIAG_ID_23      = 23,
    DIAG_ID_24      = 24,
    DIAG_ID_25      = 25,
    DIAG_ID_26      = 26,
    DIAG_ID_27      = 27,
    DIAG_ID_28      = 28,
    DIAG_ID_29      = 29,
    DIAG_ID_30      = 30,
    DIAG_ID_31      = 31,

    DIAG_ID_32      = 32,
    DIAG_ID_33      = 33,
    DIAG_ID_34      = 34,
    DIAG_ID_35      = 35,
    DIAG_ID_36      = 36,
    DIAG_ID_37      = 37,
    DIAG_ID_38      = 38,
    DIAG_ID_39      = 39,
    DIAG_ID_40      = 40,
    DIAG_ID_41      = 41,
    DIAG_ID_42      = 42,
    DIAG_ID_43      = 43,
    DIAG_ID_44      = 44,
    DIAG_ID_45      = 45,
    DIAG_ID_46      = 46,
    DIAG_ID_47      = 47,

    DIAG_ID_48      = 48,
    DIAG_ID_49      = 49,
    DIAG_ID_50      = 50,
    DIAG_ID_51      = 51,
    DIAG_ID_52      = 52,
    DIAG_ID_53      = 53,
    DIAG_ID_54      = 54,
    DIAG_ID_55      = 55,
    DIAG_ID_56      = 56,
    DIAG_ID_57      = 57,
    DIAG_ID_58      = 58,
    DIAG_ID_59      = 59,
    DIAG_ID_60      = 60,
    DIAG_ID_61      = 61,
    DIAG_ID_62      = 62,
    DIAG_ID_63      = 63,

    DIAG_ID_64      = 64,
    DIAG_ID_65      = 65,
    DIAG_ID_66      = 66,
    DIAG_ID_67      = 67,
    DIAG_ID_68      = 68,
    DIAG_ID_69      = 69,
    DIAG_ID_70      = 70,
    DIAG_ID_71      = 71,
    DIAG_ID_72      = 72,
    DIAG_ID_73      = 73,
    DIAG_ID_74      = 74,
    DIAG_ID_75      = 75,
    DIAG_ID_76      = 76,
    DIAG_ID_77      = 77,
    DIAG_ID_78      = 78,
    DIAG_ID_79      = 79,

    DIAG_ID_80      = 80,
    DIAG_ID_81      = 81,
    DIAG_ID_82      = 82,
    DIAG_ID_83      = 83,
    DIAG_ID_84      = 84,
    DIAG_ID_85      = 85,
    DIAG_ID_86      = 86,
    DIAG_ID_87      = 87,
    DIAG_ID_88      = 88,
    DIAG_ID_89      = 89,
    DIAG_ID_90      = 90,
    DIAG_ID_91      = 91,
    DIAG_ID_92      = 92,
    DIAG_ID_93      = 93,
    DIAG_ID_94      = 94,
    DIAG_ID_95      = 95,

    DIAG_ID_96      = 96,
    DIAG_ID_97      = 97,
    DIAG_ID_98      = 98,
    DIAG_ID_99      = 99,
    DIAG_ID_100     = 100,
    DIAG_ID_101     = 101,
    DIAG_ID_102     = 102,
    DIAG_ID_103     = 103,
    DIAG_ID_104     = 104,
    DIAG_ID_105     = 105,
    DIAG_ID_106     = 106,
    DIAG_ID_107     = 107,
    DIAG_ID_108     = 108,
    DIAG_ID_109     = 109,
    DIAG_ID_110     = 110,
    DIAG_ID_111     = 111,

    DIAG_ID_MAX     = 112,

} DIAG_CH_ID_e;

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

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

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

#endif /* DIAG_ID_CFG_H_ */