foxBMS  1.6.0
The foxBMS Battery Management System API Documentation
diag.c
Go to the documentation of this file.
1 /**
2  *
3  * @copyright © 2010 - 2023, Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V.
4  * All rights reserved.
5  *
6  * SPDX-License-Identifier: BSD-3-Clause
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright notice, this
12  * list of conditions and the following disclaimer.
13  *
14  * 2. Redistributions in binary form must reproduce the above copyright notice,
15  * this list of conditions and the following disclaimer in the documentation
16  * and/or other materials provided with the distribution.
17  *
18  * 3. Neither the name of the copyright holder nor the names of its
19  * contributors may be used to endorse or promote products derived from
20  * this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
28  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  *
33  * We kindly request you to use one or more of the following phrases to refer to
34  * foxBMS in your hardware, software, documentation or advertising materials:
35  *
36  * - ″This product uses parts of foxBMS®″
37  * - ″This product includes parts of foxBMS®″
38  * - ″This product is derived from foxBMS®″
39  *
40  */
41 
42 /**
43  * @file diag.c
44  * @author foxBMS Team
45  * @date 2019-11-28 (date of creation)
46  * @updated 2023-10-12 (date of last update)
47  * @version v1.6.0
48  * @ingroup ENGINE
49  * @prefix DIAG
50  *
51  * @brief Diagnosis driver implementation
52  *
53  * @details This diagnose module is responsible for error handling and
54  * reporting.
55  * Reported errors are logged into the global database and can be
56  * reviewed on user request.
57  */
58 
59 /*========== Includes =======================================================*/
60 #include "diag.h"
61 
62 #include "fstd_types.h"
63 #include "os.h"
64 
65 #include <stdint.h>
66 
67 /*========== Macros and Definitions =========================================*/
68 
69 /*========== Static Constant and Variable Definitions =======================*/
70 /** state-variable of the diag module */
72 
73 /** pointer to the device configuration of the diag module */
75 
76 /** superb implementation of a mutex for the diag module */
77 static uint8_t diag_locked = 0;
78 
79 /*========== Extern Constant and Variable Definitions =======================*/
80 
81 /*========== Static Function Prototypes =====================================*/
82 static void DIAG_Reset(void);
83 
84 /**
85  * @brief DIAG_EntryWrite adds an error entry.
86  * @details This function adds an entry to the error buffer. It provides some
87  * functionality to prevent duplicates from being logged. Multiple
88  * occurring error doesn't get logged anymore after they reached a
89  * pre-defined error count.
90  * @param eventID ID of entry
91  * @param event OK, NOK or RESET
92  * @param data individual information for #DIAG_ID_e e.g. string number,..
93  * @return 0xFF if event is logged, otherwise 0
94  */
95 static uint8_t DIAG_EntryWrite(uint8_t eventID, DIAG_EVENT_e event, uint32_t data);
96 
97 /*========== Static Function Implementations ================================*/
98 /**
99  * @brief DIAG_Reset resetsall needed structures
100  * @details This function gets called during initialization of the diagnose
101  * module. It clears memory and counters used by diag later on.
102  */
103 
104 static void DIAG_Reset(void) {
105  diag_locked = 1;
106 
107  /* Reset counter */
108  for (uint32_t i = 0u; i < sizeof(diag.entry_cnt); i++) {
109  diag.entry_cnt[i] = 0;
110  }
111  diag.errcnttotal = 0;
112  diag_locked = 0;
113 }
114 
115 /*========== Extern Function Implementations ================================*/
117  FAS_ASSERT(diag_dev_pointer != NULL_PTR);
118 
119  STD_RETURN_TYPE_e retval = STD_OK;
120  uint8_t id_nr = (uint8_t)DIAG_ID_MAX;
121  /* take assumptions on the value of DIAG_ID_MAX */
122  FAS_ASSERT((uint16_t)DIAG_ID_MAX < UINT8_MAX);
123  uint32_t tmperr_Check[((uint16_t)DIAG_ID_MAX + 31u) / 32u] = {0};
124 
125  diag_devptr = diag_dev_pointer;
126 
128  uint16_t checkfail = 0u;
129 
130  /* TODO this will always evaluate to true?! */
131  if (checkfail > 0u) {
132  DIAG_Reset();
133  }
134 
135  /* Fill lookup table id2ch */
136  for (uint8_t c = 0; c < diag_dev_pointer->nrOfConfiguredDiagnosisEntries; c++) {
137  id_nr = diag_dev_pointer->pConfigurationOfDiagnosisEntries[c].id;
138  if (id_nr < (uint16_t)DIAG_ID_MAX) {
139  diag.id2ch[id_nr] = c; /* e.g. diag.id2ch[DIAG_ID_90] = configured channel index */
140  } else {
141  /* Configuration error -> set retval to #STD_NOT_OK */
142  checkfail |= 0x20u;
143  retval = STD_NOT_OK;
144  }
145  }
146 
147  for (uint8_t i = 0; i < (uint8_t)(((uint16_t)DIAG_ID_MAX + 31u) / 32u); i++) {
148  tmperr_Check[i] = 0u;
149  }
150 
151  /* Fill enable array err_enableflag */
152  for (uint8_t i = 0; i < diag_dev_pointer->nrOfConfiguredDiagnosisEntries; i++) {
154  /* Disable diagnosis entry */
155  tmperr_Check[diag_dev_pointer->pConfigurationOfDiagnosisEntries[i].id / 32] |=
156  (1 << (diag_dev_pointer->pConfigurationOfDiagnosisEntries[i].id % 32));
157  }
158  }
159 
160  /* take over configured error enable masks*/
161  for (uint8_t c = 0; c < (uint8_t)(((uint16_t)DIAG_ID_MAX + 31u) / 32u); c++) {
162  diag.err_enableflag[c] = ~tmperr_Check[c];
163  }
164 
165  /* Reset counter in case init function is called multiple times */
166  diag_dev_pointer->numberOfFatalErrors = 0u;
167  /* Fill pointer array with links to all diagnosis entries with a fatal error */
168  for (uint16_t entry = 0u; entry < (uint16_t)DIAG_ID_MAX; entry++) {
169  if (diag_diagnosisIdConfiguration[entry].severity == DIAG_FATAL_ERROR) {
170  diag_dev_pointer->pFatalErrorLinkTable[diag_dev_pointer->numberOfFatalErrors] =
172  diag_dev_pointer->numberOfFatalErrors++;
173  }
174  }
175 
176  /** Iterate over #diag_diagnosisIdConfiguration and check that a meaningful
177  * state transition time is configured if a severity of #DIAG_FATAL_ERROR
178  * is configured. */
179  for (uint16_t diagnosisEntry = 0u; diagnosisEntry < diag_dev_pointer->nrOfConfiguredDiagnosisEntries;
180  diagnosisEntry++) {
181  bool fatalErrorDetected = (bool)(diag_diagnosisIdConfiguration[diagnosisEntry].severity == DIAG_FATAL_ERROR);
182  bool discardDelay = (bool)(diag_diagnosisIdConfiguration[diagnosisEntry].delay_ms == DIAG_DELAY_DISCARDED);
183  if (fatalErrorDetected && discardDelay) {
184  /* Configuration error. Fatal error configured but delay is discared.*/
186  }
187  }
189  return retval;
190 }
191 
193  STD_RETURN_TYPE_e retval = STD_OK;
194  const uint16_t errorThreshold =
195  diag_devptr->pConfigurationOfDiagnosisEntries[diag.id2ch[(uint16_t)diagnosisEntry]].threshold;
196 
197  /* Error if active if threshold counter is larger than configured error threshold */
198  for (uint8_t s = 0u; s < BS_NR_OF_STRINGS; s++) {
199  uint16_t thresholdCounter = diag.occurrenceCounter[s][(uint16_t)diagnosisEntry];
200  if (thresholdCounter > errorThreshold) {
201  /* error-threshold exceeded -> error is active */
202  retval = STD_NOT_OK;
203  }
204  }
205  return retval;
206 }
207 
208 void DIAG_PrintErrors(void) {
209 }
210 
211 static uint8_t DIAG_EntryWrite(uint8_t eventID, DIAG_EVENT_e event, uint32_t data) {
212  uint8_t ret_val = 0;
213  if (diag_locked > 0u) {
214  return ret_val; /* only locked when clearing the diagnosis memory */
215  }
216 
217  if (diag.entry_event[eventID] == event) {
218  /* same event of same error type already recorded before -> ignore until event toggles */
219  return ret_val;
220  }
221  if ((diag.entry_event[eventID] == DIAG_EVENT_OK) && (event == DIAG_EVENT_RESET)) {
222  /* do record DIAG_EVENT_RESET-event only if last event was an error (re-initialization) */
223  /* meaning: DIAG_EVENT_RESET-event at first time call or after DIAG_EVENT_OK-event will not be recorded */
224  return ret_val;
225  }
226 
227  if (++diag.entry_cnt[eventID] > DIAG_MAX_ENTRIES_OF_ERROR) {
228  /* this type of error has been recorded too many times -> ignore to avoid filling buffer with same failure codes */
230  return ret_val;
231  }
232 
233  /* now record failure code */
234  ret_val = 0xFF;
235 
236  /* counts of (new) diagnosis entry records which is still not been read by
237  * external Tool which will reset this value to 0 after having read all
238  * new entries which means <acknowledged by user> */
240  ++diag.errcnttotal; /* total counts of diagnosis entry records */
241  diag.entry_event[eventID] = event;
242 
243  return ret_val;
244 }
245 
248  uint32_t *u32ptr_errCodemsk = NULL_PTR;
249  uint32_t *u32ptr_warnCodemsk = NULL_PTR;
250  uint16_t *u16ptr_threshcounter = NULL_PTR;
251  uint16_t cfg_threshold = 0;
252  uint16_t err_enable_idx = 0;
253  uint32_t err_enable_bitmask = 0;
254 
255  DIAG_RECORDING_e recording_enabled;
256  DIAG_EVALUATE_e evaluate_enabled;
257 
260  }
261 
262  if (diagId >= DIAG_ID_MAX) {
264  }
265 
266  if (!((impact == DIAG_SYSTEM) || (DIAG_STRING))) {
268  }
269 
270  if ((impact == DIAG_STRING) && (data >= BS_NR_OF_STRINGS)) {
272  }
273 
274  /* Determine a stringID, for impact level #DIAG_SYSTEM this is
275  always 0. This stringID is used to access the #DIAG_DIAGNOSIS_STATE_s::occurrenceCounter
276  2D-array.
277  */
278  uint8_t stringID = 0u;
279  if (impact == DIAG_STRING) {
280  stringID = data;
281  }
282 
283  err_enable_idx = diagId / 32; /* array index of diag.err_enableflag[..] */
284  err_enable_bitmask = 1 << (diagId % 32); /* bit number (mask) of diag.err_enableflag[idx] */
285 
286  u32ptr_errCodemsk = &diag.errflag[err_enable_idx];
287  u32ptr_warnCodemsk = &diag.warnflag[err_enable_idx];
288  u16ptr_threshcounter = &diag.occurrenceCounter[stringID][diagId];
292 
293  if (event == DIAG_EVENT_OK) {
294  if ((diag.err_enableflag[err_enable_idx] & err_enable_bitmask) > 0u) {
295  /* if (((*u16ptr_threshcounter) == 0) && (*u32ptr_errCodemsk == 0)) */
296  if (((*u16ptr_threshcounter) == 0)) {
297  /* everything ok, nothing to be handled */
298  } else if ((*u16ptr_threshcounter) > 1) {
299  (*u16ptr_threshcounter)--; /* Error did not occur, decrement Error-Counter */
300  } else if ((*u16ptr_threshcounter) == 1) {
301  /* else if ((*u16ptr_threshcounter) <= 1) */
302  /* Error did not occur, now decrement to zero and clear Error- or Warning-Flag and make recording if enabled */
303  *u32ptr_errCodemsk &= ~err_enable_bitmask; /* ERROR: clear corresponding bit in errflag[idx] */
304  *u32ptr_warnCodemsk &= ~err_enable_bitmask; /* WARNING: clear corresponding bit in warnflag[idx] */
305  (*u16ptr_threshcounter) = 0;
306  /* Make entry in error-memory (error disappeared) */
307  if (recording_enabled == DIAG_RECORDING_ENABLED) {
308  DIAG_EntryWrite(diagId, event, data);
309  }
310 
311  if (evaluate_enabled == DIAG_EVALUATION_ENABLED) {
312  /* Call callback function and reset error */
314  diagId, DIAG_EVENT_RESET, &diag_kDatabaseShim, data);
315  }
316  }
317  }
318  ret_val = DIAG_HANDLER_RETURN_OK; /* Function does not return an error-message! */
319  } else if (event == DIAG_EVENT_NOT_OK) {
320  if ((diag.err_enableflag[err_enable_idx] & err_enable_bitmask) > 0u) {
321  if ((*u16ptr_threshcounter) < cfg_threshold) {
322  (*u16ptr_threshcounter)++; /* error-threshold not exceeded yet, increment Error-Counter */
323  ret_val = DIAG_HANDLER_RETURN_OK; /* Function does not return an error-message! */
324  } else if ((*u16ptr_threshcounter) == cfg_threshold) {
325  /* Error occured AND error-threshold exceeded */
326  (*u16ptr_threshcounter)++;
327  *u32ptr_errCodemsk |= err_enable_bitmask; /* ERROR: set corresponding bit in errflag[idx] */
328  *u32ptr_warnCodemsk &= ~err_enable_bitmask; /* WARNING: clear corresponding bit in warnflag[idx] */
329 
330  /* Make entry in error-memory (error occurred) */
331  if (recording_enabled == DIAG_RECORDING_ENABLED) {
332  DIAG_EntryWrite(diagId, event, data);
333  }
334 
335  if (evaluate_enabled == DIAG_EVALUATION_ENABLED) {
336  /* Call callback function and set error */
338  diagId, DIAG_EVENT_NOT_OK, &diag_kDatabaseShim, data);
339  }
340  /* Function returns an error-message! */
342  } else if (((*u16ptr_threshcounter) > cfg_threshold)) {
343  /* error-threshold already exceeded, nothing to be handled */
345  }
346  } else {
347  /* Error occurred BUT NOT enabled by mask */
348  *u32ptr_errCodemsk &= ~err_enable_bitmask; /* ERROR: clear corresponding bit in errflag[idx] */
349  *u32ptr_warnCodemsk |= err_enable_bitmask; /* WARNING: set corresponding bit in warnflag[idx] */
350  ret_val = DIAG_HANDLER_RETURN_WARNING_OCCURRED; /* Function returns an error-message! */
351  }
352  } else if (event == DIAG_EVENT_RESET) {
353  if ((diag.err_enableflag[err_enable_idx] & err_enable_bitmask) > 0u) {
354  /* clear counter, Error-, Warning-Flag and make recording if enabled */
355  *u32ptr_errCodemsk &= ~err_enable_bitmask; /* ERROR: clear corresponding bit in errflag[idx] */
356  *u32ptr_warnCodemsk &= ~err_enable_bitmask; /* WARNING: clear corresponding bit in warnflag[idx] */
357  (*u16ptr_threshcounter) = 0;
358  if (recording_enabled == DIAG_RECORDING_ENABLED) {
359  /* Make entry in error-memory (error disappeared) if error was recorded before */
360  DIAG_EntryWrite(diagId, event, data);
361  }
362  if (evaluate_enabled == DIAG_EVALUATION_ENABLED) {
363  /* Call callback function and reset error */
365  diagId, DIAG_EVENT_RESET, &diag_kDatabaseShim, data);
366  }
367  }
368  ret_val = DIAG_HANDLER_RETURN_OK; /* Function does not return an error-message! */
369  }
370 
371  return ret_val;
372 }
373 
375  STD_RETURN_TYPE_e retVal = STD_NOT_OK;
376 
377  if (cond == STD_OK) {
378  DIAG_Handler(diagId, DIAG_EVENT_OK, impact, data);
379  } else {
380  DIAG_Handler(diagId, DIAG_EVENT_NOT_OK, impact, data);
381  }
382 
383  return retVal;
384 }
385 
386 uint32_t DIAG_GetDelay(DIAG_ID_e diagnosisEntry) {
387  FAS_ASSERT(diagnosisEntry < DIAG_ID_MAX);
388  return diag_diagnosisIdConfiguration[diag.id2ch[(uint16_t)diagnosisEntry]].delay_ms;
389 }
390 
392  bool fatalErrorActive = false;
393  for (uint16_t entry = 0u; entry < diag_device.numberOfFatalErrors; entry++) {
394  const STD_RETURN_TYPE_e diagnosisState =
396  if (STD_NOT_OK == diagnosisState) {
397  fatalErrorActive = true;
398  }
399  }
400  return fatalErrorActive;
401 }
402 
403 /*========== Externalized Static Function Implementations (Unit Test) =======*/
404 #ifdef UNITY_UNIT_TEST
405 #endif
#define BS_NR_OF_STRINGS
Number of parallel strings in the battery pack.
STD_RETURN_TYPE_e DIAG_CheckEvent(STD_RETURN_TYPE_e cond, DIAG_ID_e diagId, DIAG_IMPACT_LEVEL_e impact, uint32_t data)
DIAG_CheckEvent provides a simple interface to check an event for STD_OK.
Definition: diag.c:374
static DIAG_DEV_s * diag_devptr
Definition: diag.c:74
static uint8_t DIAG_EntryWrite(uint8_t eventID, DIAG_EVENT_e event, uint32_t data)
DIAG_EntryWrite adds an error entry.
Definition: diag.c:211
uint32_t DIAG_GetDelay(DIAG_ID_e diagnosisEntry)
Get configured delay of passed diagnosis entry.
Definition: diag.c:386
void DIAG_PrintErrors(void)
Prints contents of the error buffer on user request.
Definition: diag.c:208
STD_RETURN_TYPE_e DIAG_GetDiagnosisEntryState(DIAG_ID_e diagnosisEntry)
Checks if passed diagnosis entry has been triggered or not.
Definition: diag.c:192
bool DIAG_IsAnyFatalErrorSet(void)
Check if any fatal error is set.
Definition: diag.c:391
static DIAG_DIAGNOSIS_STATE_s diag
Definition: diag.c:71
DIAG_RETURNTYPE_e DIAG_Handler(DIAG_ID_e diagId, DIAG_EVENT_e event, DIAG_IMPACT_LEVEL_e impact, uint32_t data)
DIAG_Handler provides generic error handling, based on diagnosis group.
Definition: diag.c:246
static uint8_t diag_locked
Definition: diag.c:77
STD_RETURN_TYPE_e DIAG_Initialize(DIAG_DEV_s *diag_dev_pointer)
DIAG_Init initializes all needed structures/buffers.
Definition: diag.c:116
static void DIAG_Reset(void)
DIAG_Reset resetsall needed structures.
Definition: diag.c:104
Diagnosis driver header.
@ DIAG_STATE_UNINITIALIZED
Definition: diag.h:82
@ DIAG_STATE_INITIALIZED
Definition: diag.h:83
DIAG_RETURNTYPE_e
Definition: diag.h:68
@ DIAG_HANDLER_RETURN_NOT_READY
Definition: diag.h:77
@ DIAG_HANDLER_INVALID_DATA
Definition: diag.h:75
@ DIAG_HANDLER_RETURN_WRONG_ID
Definition: diag.h:72
@ DIAG_HANDLER_RETURN_WARNING_OCCURRED
Definition: diag.h:71
@ DIAG_HANDLER_RETURN_ERR_OCCURRED
Definition: diag.h:70
@ DIAG_HANDLER_INVALID_ERR_IMPACT
Definition: diag.h:76
@ DIAG_HANDLER_RETURN_OK
Definition: diag.h:69
@ DIAG_HANDLER_RETURN_UNKNOWN
Definition: diag.h:73
DIAG_ID_CFG_s diag_diagnosisIdConfiguration[]
Definition: diag_cfg.c:124
const DIAG_DATABASE_SHIM_s diag_kDatabaseShim
Definition: diag_cfg.c:113
DIAG_DEV_s diag_device
Definition: diag_cfg.c:240
DIAG_EVENT_e
Definition: diag_cfg.h:266
@ DIAG_EVENT_RESET
Definition: diag_cfg.h:269
@ DIAG_EVENT_NOT_OK
Definition: diag_cfg.h:268
@ DIAG_EVENT_OK
Definition: diag_cfg.h:267
DIAG_IMPACT_LEVEL_e
Definition: diag_cfg.h:279
@ DIAG_SYSTEM
Definition: diag_cfg.h:280
@ DIAG_STRING
Definition: diag_cfg.h:281
DIAG_EVALUATE_e
Definition: diag_cfg.h:273
@ DIAG_EVALUATION_ENABLED
Definition: diag_cfg.h:274
@ DIAG_EVALUATION_DISABLED
Definition: diag_cfg.h:275
@ DIAG_FATAL_ERROR
Definition: diag_cfg.h:308
DIAG_ID_e
Definition: diag_cfg.h:176
@ DIAG_ID_MAX
Definition: diag_cfg.h:262
#define DIAG_MAX_ENTRIES_OF_ERROR
Definition: diag_cfg.h:162
#define DIAG_DELAY_DISCARDED
Definition: diag_cfg.h:127
DIAG_RECORDING_e
Definition: diag_cfg.h:314
@ DIAG_RECORDING_ENABLED
Definition: diag_cfg.h:315
#define FAS_ASSERT(x)
Assertion macro that asserts that x is true.
Definition: fassert.h:255
#define FAS_TRAP
Define that evaluates to essential boolean false thus tripping an assert.
Definition: fassert.h:129
Definition of foxBMS standard types.
STD_RETURN_TYPE_e
Definition: fstd_types.h:82
@ STD_NOT_OK
Definition: fstd_types.h:84
@ STD_OK
Definition: fstd_types.h:83
#define NULL_PTR
Null pointer.
Definition: fstd_types.h:77
Declaration of the OS wrapper interface.
uint8_t nrOfConfiguredDiagnosisEntries
Definition: diag_cfg.h:353
DIAG_ID_CFG_s * pConfigurationOfDiagnosisEntries
Definition: diag_cfg.h:354
DIAG_ID_CFG_s * pFatalErrorLinkTable[DIAG_ID_MAX]
Definition: diag_cfg.h:357
uint16_t numberOfFatalErrors
Definition: diag_cfg.h:355
uint16_t errcnttotal
Definition: diag.h:89
uint16_t errcntreported
Definition: diag.h:90
uint32_t entry_event[DIAG_ID_MAX]
Definition: diag.h:91
uint32_t errflag[(DIAG_ID_MAX+31)/32]
Definition: diag.h:96
uint8_t entry_cnt[DIAG_ID_MAX]
Definition: diag.h:92
uint16_t occurrenceCounter[BS_NR_OF_STRINGS][DIAG_ID_MAX]
Definition: diag.h:93
DIAG_MODULE_STATE_e state
Definition: diag.h:88
uint32_t warnflag[(DIAG_ID_MAX+31)/32]
Definition: diag.h:97
uint8_t id2ch[DIAG_ID_MAX]
Definition: diag.h:94
uint32_t err_enableflag[(DIAG_ID_MAX+31)/32]
Definition: diag.h:98
DIAG_RECORDING_e enable_recording
Definition: diag_cfg.h:343
DIAG_CALLBACK_FUNCTION_f * fpCallback
Definition: diag_cfg.h:345
uint16_t threshold
Definition: diag_cfg.h:335
DIAG_EVALUATE_e enable_evaluate
Definition: diag_cfg.h:344
DIAG_ID_e id
Definition: diag_cfg.h:334