foxBMS - Unit Tests  1.4.1
The foxBMS Unit Tests API Documentation
diag.c
Go to the documentation of this file.
1 /**
2  *
3  * @copyright © 2010 - 2022, 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 2022-10-27 (date of last update)
47  * @version v1.4.1
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 "os.h"
63 
64 /*========== Macros and Definitions =========================================*/
65 
66 /*========== Static Constant and Variable Definitions =======================*/
67 /** state-variable of the diag module */
69 
70 /** pointer to the device configuration of the diag module */
72 
73 /** superb implementation of a mutex for the diag module */
74 static uint8_t diag_locked = 0;
75 
76 /*========== Extern Constant and Variable Definitions =======================*/
77 
78 /*========== Static Function Prototypes =====================================*/
79 static void DIAG_Reset(void);
80 
81 /**
82  * @brief DIAG_EntryWrite adds an error entry.
83  * @details This function adds an entry to the error buffer. It provides some
84  * functionality to prevent duplicates from being logged. Multiple
85  * occurring error doesn't get logged anymore after they reached a
86  * pre-defined error count.
87  * @param eventID ID of entry
88  * @param event OK, NOK or RESET
89  * @param data individual information for #DIAG_ID_e e.g. string number,..
90  * @return 0xFF if event is logged, otherwise 0
91  */
92 static uint8_t DIAG_EntryWrite(uint8_t eventID, DIAG_EVENT_e event, uint32_t data);
93 
94 /*========== Static Function Implementations ================================*/
95 /**
96  * @brief DIAG_Reset resetsall needed structures
97  * @details This function gets called during initialization of the diagnose
98  * module. It clears memory and counters used by diag later on.
99  */
100 
101 static void DIAG_Reset(void) {
102  diag_locked = 1;
103 
104  /* Reset counter */
105  for (uint32_t i = 0u; i < sizeof(diag.entry_cnt); i++) {
106  diag.entry_cnt[i] = 0;
107  }
108  diag.errcnttotal = 0;
109  diag_locked = 0;
110 }
111 
112 /*========== Extern Function Implementations ================================*/
114  FAS_ASSERT(diag_dev_pointer != NULL_PTR);
115 
116  STD_RETURN_TYPE_e retval = STD_OK;
117  uint8_t id_nr = (uint8_t)DIAG_ID_MAX;
118  /* take assumptions on the value of DIAG_ID_MAX */
119  FAS_ASSERT((uint16_t)DIAG_ID_MAX < UINT8_MAX);
120  uint32_t tmperr_Check[((uint16_t)DIAG_ID_MAX + 31u) / 32u] = {0};
121 
122  diag_devptr = diag_dev_pointer;
123 
125  uint16_t checkfail = 0u;
126 
127  /* TODO this will always evaluate to true?! */
128  if (checkfail > 0u) {
129  DIAG_Reset();
130  }
131 
132  /* Fill lookup table id2ch */
133  for (uint8_t c = 0; c < diag_dev_pointer->nrOfConfiguredDiagnosisEntries; c++) {
134  id_nr = diag_dev_pointer->pConfigurationOfDiagnosisEntries[c].id;
135  if (id_nr < (uint16_t)DIAG_ID_MAX) {
136  diag.id2ch[id_nr] = c; /* e.g. diag.id2ch[DIAG_ID_90] = configured channel index */
137  } else {
138  /* Configuration error -> set retval to #STD_NOT_OK */
139  checkfail |= 0x20u;
140  retval = STD_NOT_OK;
141  }
142  }
143 
144  for (uint8_t i = 0; i < (uint8_t)(((uint16_t)DIAG_ID_MAX + 31u) / 32u); i++) {
145  tmperr_Check[i] = 0u;
146  }
147 
148  /* Fill enable array err_enableflag */
149  for (uint8_t i = 0; i < diag_dev_pointer->nrOfConfiguredDiagnosisEntries; i++) {
151  /* Disable diagnosis entry */
152  tmperr_Check[diag_dev_pointer->pConfigurationOfDiagnosisEntries[i].id / 32] |=
153  (1 << (diag_dev_pointer->pConfigurationOfDiagnosisEntries[i].id % 32));
154  }
155  }
156 
157  /* take over configured error enable masks*/
158  for (uint8_t c = 0; c < (uint8_t)(((uint16_t)DIAG_ID_MAX + 31u) / 32u); c++) {
159  diag.err_enableflag[c] = ~tmperr_Check[c];
160  }
161 
162  /* Reset counter in case init function is called multiple times */
163  diag_dev_pointer->numberOfFatalErrors = 0u;
164  /* Fill pointer array with links to all diagnosis entries with a fatal error */
165  for (uint16_t entry = 0u; entry < (uint16_t)DIAG_ID_MAX; entry++) {
166  if (diag_diagnosisIdConfiguration[entry].severity == DIAG_FATAL_ERROR) {
167  diag_dev_pointer->pFatalErrorLinkTable[diag_dev_pointer->numberOfFatalErrors] =
169  diag_dev_pointer->numberOfFatalErrors++;
170  }
171  }
172 
173  /** Iterate over #diag_diagnosisIdConfiguration and check that a meaningful
174  * state transition time is configured if a severity of #DIAG_FATAL_ERROR
175  * is configured. */
176  for (uint16_t diagnosisEntry = 0u; diagnosisEntry < diag_dev_pointer->nrOfConfiguredDiagnosisEntries;
177  diagnosisEntry++) {
178  bool fatalErrorDetected = (bool)(diag_diagnosisIdConfiguration[diagnosisEntry].severity == DIAG_FATAL_ERROR);
179  bool discardDelay = (bool)(diag_diagnosisIdConfiguration[diagnosisEntry].delay_ms == DIAG_DELAY_DISCARDED);
180  if (fatalErrorDetected && discardDelay) {
181  /* Configuration error. Fatal error configured but delay is discared.*/
183  }
184  }
186  return retval;
187 }
188 
190  STD_RETURN_TYPE_e retval = STD_OK;
191  const uint16_t errorThreshold =
192  diag_devptr->pConfigurationOfDiagnosisEntries[diag.id2ch[(uint16_t)diagnosisEntry]].threshold;
193 
194  /* Error if active if threshold counter is larger than configured error threshold */
195  for (uint8_t s = 0u; s < BS_NR_OF_STRINGS; s++) {
196  uint16_t thresholdCounter = diag.occurrenceCounter[s][(uint16_t)diagnosisEntry];
197  if (thresholdCounter > errorThreshold) {
198  /* error-threshold exceeded -> error is active */
199  retval = STD_NOT_OK;
200  }
201  }
202  return retval;
203 }
204 
205 void DIAG_PrintErrors(void) {
206 }
207 
208 static uint8_t DIAG_EntryWrite(uint8_t eventID, DIAG_EVENT_e event, uint32_t data) {
209  uint8_t ret_val = 0;
210  if (diag_locked > 0u) {
211  return ret_val; /* only locked when clearing the diagnosis memory */
212  }
213 
214  if (diag.entry_event[eventID] == event) {
215  /* same event of same error type already recorded before -> ignore until event toggles */
216  return ret_val;
217  }
218  if ((diag.entry_event[eventID] == DIAG_EVENT_OK) && (event == DIAG_EVENT_RESET)) {
219  /* do record DIAG_EVENT_RESET-event only if last event was an error (re-initialization) */
220  /* meaning: DIAG_EVENT_RESET-event at first time call or after DIAG_EVENT_OK-event will not be recorded */
221  return ret_val;
222  }
223 
224  if (++diag.entry_cnt[eventID] > DIAG_MAX_ENTRIES_OF_ERROR) {
225  /* this type of error has been recorded too many times -> ignore to avoid filling buffer with same failure codes */
227  return ret_val;
228  }
229 
230  /* now record failure code */
231  ret_val = 0xFF;
232 
233  /* counts of (new) diagnosis entry records which is still not been read by
234  * external Tool which will reset this value to 0 after having read all
235  * new entries which means <acknowledged by user> */
237  ++diag.errcnttotal; /* total counts of diagnosis entry records */
238  diag.entry_event[eventID] = event;
239 
240  return ret_val;
241 }
242 
245  uint32_t *u32ptr_errCodemsk = NULL_PTR;
246  uint32_t *u32ptr_warnCodemsk = NULL_PTR;
247  uint16_t *u16ptr_threshcounter = NULL_PTR;
248  uint16_t cfg_threshold = 0;
249  uint16_t err_enable_idx = 0;
250  uint32_t err_enable_bitmask = 0;
251 
252  DIAG_RECORDING_e recording_enabled;
253  DIAG_EVALUATE_e evaluate_enabled;
254 
257  }
258 
259  if (diagId >= DIAG_ID_MAX) {
261  }
262 
263  if (!((impact == DIAG_SYSTEM) || (DIAG_STRING))) {
265  }
266 
267  if ((impact == DIAG_STRING) && (data >= BS_NR_OF_STRINGS)) {
269  }
270 
271  /* Determine a stringID, for impact level #DIAG_SYSTEM this is
272  always 0. This stringID is used to access the #DIAG_DIAGNOSIS_STATE_s::occurrenceCounter
273  2D-array.
274  */
275  uint8_t stringID = 0u;
276  if (impact == DIAG_STRING) {
277  stringID = data;
278  }
279 
280  err_enable_idx = diagId / 32; /* array index of diag.err_enableflag[..] */
281  err_enable_bitmask = 1 << (diagId % 32); /* bit number (mask) of diag.err_enableflag[idx] */
282 
283  u32ptr_errCodemsk = &diag.errflag[err_enable_idx];
284  u32ptr_warnCodemsk = &diag.warnflag[err_enable_idx];
285  u16ptr_threshcounter = &diag.occurrenceCounter[stringID][diagId];
289 
290  if (event == DIAG_EVENT_OK) {
291  if ((diag.err_enableflag[err_enable_idx] & err_enable_bitmask) > 0u) {
292  /* if (((*u16ptr_threshcounter) == 0) && (*u32ptr_errCodemsk == 0)) */
293  if (((*u16ptr_threshcounter) == 0)) {
294  /* everything ok, nothing to be handled */
295  } else if ((*u16ptr_threshcounter) > 1) {
296  (*u16ptr_threshcounter)--; /* Error did not occur, decrement Error-Counter */
297  } else if ((*u16ptr_threshcounter) == 1) {
298  /* else if ((*u16ptr_threshcounter) <= 1) */
299  /* Error did not occur, now decrement to zero and clear Error- or Warning-Flag and make recording if enabled */
300  *u32ptr_errCodemsk &= ~err_enable_bitmask; /* ERROR: clear corresponding bit in errflag[idx] */
301  *u32ptr_warnCodemsk &= ~err_enable_bitmask; /* WARNING: clear corresponding bit in warnflag[idx] */
302  (*u16ptr_threshcounter) = 0;
303  /* Make entry in error-memory (error disappeared) */
304  if (recording_enabled == DIAG_RECORDING_ENABLED) {
305  DIAG_EntryWrite(diagId, event, data);
306  }
307 
308  if (evaluate_enabled == DIAG_EVALUATION_ENABLED) {
309  /* Call callback function and reset error */
311  diagId, DIAG_EVENT_RESET, &diag_kDatabaseShim, data);
312  }
313  }
314  }
315  ret_val = DIAG_HANDLER_RETURN_OK; /* Function does not return an error-message! */
316  } else if (event == DIAG_EVENT_NOT_OK) {
317  if ((diag.err_enableflag[err_enable_idx] & err_enable_bitmask) > 0u) {
318  if ((*u16ptr_threshcounter) < cfg_threshold) {
319  (*u16ptr_threshcounter)++; /* error-threshold not exceeded yet, increment Error-Counter */
320  ret_val = DIAG_HANDLER_RETURN_OK; /* Function does not return an error-message! */
321  } else if ((*u16ptr_threshcounter) == cfg_threshold) {
322  /* Error occured AND error-threshold exceeded */
323  (*u16ptr_threshcounter)++;
324  *u32ptr_errCodemsk |= err_enable_bitmask; /* ERROR: set corresponding bit in errflag[idx] */
325  *u32ptr_warnCodemsk &= ~err_enable_bitmask; /* WARNING: clear corresponding bit in warnflag[idx] */
326 
327  /* Make entry in error-memory (error occurred) */
328  if (recording_enabled == DIAG_RECORDING_ENABLED) {
329  DIAG_EntryWrite(diagId, event, data);
330  }
331 
332  if (evaluate_enabled == DIAG_EVALUATION_ENABLED) {
333  /* Call callback function and set error */
335  diagId, DIAG_EVENT_NOT_OK, &diag_kDatabaseShim, data);
336  }
337  /* Function returns an error-message! */
339  } else if (((*u16ptr_threshcounter) > cfg_threshold)) {
340  /* error-threshold already exceeded, nothing to be handled */
342  }
343  } else {
344  /* Error occurred BUT NOT enabled by mask */
345  *u32ptr_errCodemsk &= ~err_enable_bitmask; /* ERROR: clear corresponding bit in errflag[idx] */
346  *u32ptr_warnCodemsk |= err_enable_bitmask; /* WARNING: set corresponding bit in warnflag[idx] */
347  ret_val = DIAG_HANDLER_RETURN_WARNING_OCCURRED; /* Function returns an error-message! */
348  }
349  } else if (event == DIAG_EVENT_RESET) {
350  if ((diag.err_enableflag[err_enable_idx] & err_enable_bitmask) > 0u) {
351  /* clear counter, Error-, Warning-Flag and make recording if enabled */
352  *u32ptr_errCodemsk &= ~err_enable_bitmask; /* ERROR: clear corresponding bit in errflag[idx] */
353  *u32ptr_warnCodemsk &= ~err_enable_bitmask; /* WARNING: clear corresponding bit in warnflag[idx] */
354  (*u16ptr_threshcounter) = 0;
355  if (recording_enabled == DIAG_RECORDING_ENABLED) {
356  /* Make entry in error-memory (error disappeared) if error was recorded before */
357  DIAG_EntryWrite(diagId, event, data);
358  }
359  if (evaluate_enabled == DIAG_EVALUATION_ENABLED) {
360  /* Call callback function and reset error */
362  diagId, DIAG_EVENT_RESET, &diag_kDatabaseShim, data);
363  }
364  }
365  ret_val = DIAG_HANDLER_RETURN_OK; /* Function does not return an error-message! */
366  }
367 
368  return ret_val;
369 }
370 
372  STD_RETURN_TYPE_e retVal = STD_NOT_OK;
373 
374  if (cond == STD_OK) {
375  DIAG_Handler(diagId, DIAG_EVENT_OK, impact, data);
376  } else {
377  DIAG_Handler(diagId, DIAG_EVENT_NOT_OK, impact, data);
378  }
379 
380  return retVal;
381 }
382 
383 uint32_t DIAG_GetDelay(DIAG_ID_e diagnosisEntry) {
384  FAS_ASSERT(diagnosisEntry < DIAG_ID_MAX);
385  return diag_diagnosisIdConfiguration[diag.id2ch[(uint16_t)diagnosisEntry]].delay_ms;
386 }
387 
389  bool fatalErrorActive = false;
390  for (uint16_t entry = 0u; entry < diag_device.numberOfFatalErrors; entry++) {
391  const STD_RETURN_TYPE_e diagnosisState =
393  if (STD_NOT_OK == diagnosisState) {
394  fatalErrorActive = true;
395  }
396  }
397  return fatalErrorActive;
398 }
399 
400 /*========== Externalized Static Function Implementations (Unit Test) =======*/
#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:371
static DIAG_DEV_s * diag_devptr
Definition: diag.c:71
static uint8_t DIAG_EntryWrite(uint8_t eventID, DIAG_EVENT_e event, uint32_t data)
DIAG_EntryWrite adds an error entry.
Definition: diag.c:208
uint32_t DIAG_GetDelay(DIAG_ID_e diagnosisEntry)
Get configured delay of passed diagnosis entry.
Definition: diag.c:383
void DIAG_PrintErrors(void)
Prints contents of the error buffer on user request.
Definition: diag.c:205
STD_RETURN_TYPE_e DIAG_GetDiagnosisEntryState(DIAG_ID_e diagnosisEntry)
Checks if passed diagnosis entry has been triggered or not.
Definition: diag.c:189
bool DIAG_IsAnyFatalErrorSet(void)
Check if any fatal error is set.
Definition: diag.c:388
static DIAG_DIAGNOSIS_STATE_s diag
Definition: diag.c:68
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:243
static uint8_t diag_locked
Definition: diag.c:74
STD_RETURN_TYPE_e DIAG_Initialize(DIAG_DEV_s *diag_dev_pointer)
DIAG_Init initializes all needed structures/buffers.
Definition: diag.c:113
static void DIAG_Reset(void)
DIAG_Reset resetsall needed structures.
Definition: diag.c:101
Diagnosis driver header.
@ DIAG_STATE_UNINITIALIZED
Definition: diag.h:78
@ DIAG_STATE_INITIALIZED
Definition: diag.h:79
DIAG_RETURNTYPE_e
Definition: diag.h:64
@ DIAG_HANDLER_RETURN_NOT_READY
Definition: diag.h:73
@ DIAG_HANDLER_INVALID_DATA
Definition: diag.h:71
@ DIAG_HANDLER_RETURN_WRONG_ID
Definition: diag.h:68
@ DIAG_HANDLER_RETURN_WARNING_OCCURRED
Definition: diag.h:67
@ DIAG_HANDLER_RETURN_ERR_OCCURRED
Definition: diag.h:66
@ DIAG_HANDLER_INVALID_ERR_IMPACT
Definition: diag.h:72
@ DIAG_HANDLER_RETURN_OK
Definition: diag.h:65
@ DIAG_HANDLER_RETURN_UNKNOWN
Definition: diag.h:69
DIAG_ID_CFG_s diag_diagnosisIdConfiguration[]
Definition: diag_cfg.c:122
const DIAG_DATABASE_SHIM_s diag_kDatabaseShim
Definition: diag_cfg.c:111
DIAG_DEV_s diag_device
Definition: diag_cfg.c:227
DIAG_EVENT_e
Definition: diag_cfg.h:256
@ DIAG_EVENT_RESET
Definition: diag_cfg.h:259
@ DIAG_EVENT_NOT_OK
Definition: diag_cfg.h:258
@ DIAG_EVENT_OK
Definition: diag_cfg.h:257
DIAG_IMPACT_LEVEL_e
Definition: diag_cfg.h:269
@ DIAG_SYSTEM
Definition: diag_cfg.h:270
@ DIAG_STRING
Definition: diag_cfg.h:271
DIAG_EVALUATE_e
Definition: diag_cfg.h:263
@ DIAG_EVALUATION_ENABLED
Definition: diag_cfg.h:264
@ DIAG_EVALUATION_DISABLED
Definition: diag_cfg.h:265
@ DIAG_FATAL_ERROR
Definition: diag_cfg.h:298
DIAG_ID_e
Definition: diag_cfg.h:174
@ DIAG_ID_MAX
Definition: diag_cfg.h:252
#define DIAG_MAX_ENTRIES_OF_ERROR
Definition: diag_cfg.h:160
#define DIAG_DELAY_DISCARDED
Definition: diag_cfg.h:125
DIAG_RECORDING_e
Definition: diag_cfg.h:304
@ DIAG_RECORDING_ENABLED
Definition: diag_cfg.h:305
#define FAS_ASSERT(x)
Assertion macro that asserts that x is true.
Definition: fassert.h:248
#define FAS_TRAP
Define that evaluates to essential boolean false thus tripping an assert.
Definition: fassert.h:126
STD_RETURN_TYPE_e
Definition: fstd_types.h:81
@ STD_NOT_OK
Definition: fstd_types.h:83
@ STD_OK
Definition: fstd_types.h:82
#define NULL_PTR
Null pointer.
Definition: fstd_types.h:76
Declaration of the OS wrapper interface.
uint8_t nrOfConfiguredDiagnosisEntries
Definition: diag_cfg.h:343
DIAG_ID_CFG_s * pConfigurationOfDiagnosisEntries
Definition: diag_cfg.h:344
DIAG_ID_CFG_s * pFatalErrorLinkTable[DIAG_ID_MAX]
Definition: diag_cfg.h:347
uint16_t numberOfFatalErrors
Definition: diag_cfg.h:345
uint16_t errcnttotal
Definition: diag.h:85
uint16_t errcntreported
Definition: diag.h:86
uint32_t entry_event[DIAG_ID_MAX]
Definition: diag.h:87
uint32_t errflag[(DIAG_ID_MAX+31)/32]
Definition: diag.h:92
uint8_t entry_cnt[DIAG_ID_MAX]
Definition: diag.h:88
uint16_t occurrenceCounter[BS_NR_OF_STRINGS][DIAG_ID_MAX]
Definition: diag.h:89
DIAG_MODULE_STATE_e state
Definition: diag.h:84
uint32_t warnflag[(DIAG_ID_MAX+31)/32]
Definition: diag.h:93
uint8_t id2ch[DIAG_ID_MAX]
Definition: diag.h:90
uint32_t err_enableflag[(DIAG_ID_MAX+31)/32]
Definition: diag.h:94
DIAG_RECORDING_e enable_recording
Definition: diag_cfg.h:333
DIAG_CALLBACK_FUNCTION_f * fpCallback
Definition: diag_cfg.h:335
uint16_t threshold
Definition: diag_cfg.h:325
DIAG_EVALUATE_e enable_evaluate
Definition: diag_cfg.h:334
DIAG_ID_e id
Definition: diag_cfg.h:324