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