foxBMS  1.0.0
The foxBMS Battery Management System API Documentation
diag.c
Go to the documentation of this file.
1 /**
2  *
3  * @copyright © 2010 - 2021, Fraunhofer-Gesellschaft zur Foerderung der
4  * angewandten Forschung e.V. All rights reserved.
5  *
6  * BSD 3-Clause License
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions are met:
9  * 1. Redistributions of source code must retain the above copyright notice,
10  * this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in the
13  * documentation and/or other materials provided with the distribution.
14  * 3. Neither the name of the copyright holder nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28  * POSSIBILITY OF SUCH DAMAGE.
29  *
30  * We kindly request you to use one or more of the following phrases to refer
31  * to foxBMS in your hardware, software, documentation or advertising
32  * materials:
33  *
34  * ″This product uses parts of foxBMS®″
35  *
36  * ″This product includes parts of foxBMS®″
37  *
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 2020-01-17 (date of last update)
47  * @ingroup ENGINE
48  * @prefix DIAG
49  *
50  * @brief Diagnosis driver implementation
51  *
52  * This diagnose module is responsible for error handling and reporting.
53  * Reported errors are logged into the global database and can be reviewed
54  * on user request.
55  */
56 
57 /*========== Includes =======================================================*/
58 #include "diag.h"
59 
60 #include "os.h"
61 
62 /*========== Macros and Definitions =========================================*/
63 
64 /*========== Static Constant and Variable Definitions =======================*/
65 /** state-variable of the diag module */
66 static DIAG_s diag;
67 
68 /** pointer to the device configuration of the diag module */
70 
71 /** superb implementation of a mutex for the diag module */
72 static uint8_t diag_locked = 0;
73 
74 /*========== Extern Constant and Variable Definitions =======================*/
75 
76 /*========== Static Function Prototypes =====================================*/
77 static void DIAG_Reset(void);
78 
79 /**
80  * @brief DIAG_EntryWrite adds an error entry.
81  * @details This function adds an entry to the error buffer. It provides some
82  * functionality to prevent duplicates from being logged. Multiple
83  * occurring error doesn't get logged anymore after they reached a
84  * pre-defined error count.
85  * @param eventID ID of entry
86  * @param event OK, NOK or RESET
87  * @param data individual information for #DIAG_ID_e e.g. string number,..
88  * @return 0xFF if event is logged, otherwise 0
89  */
90 static uint8_t DIAG_EntryWrite(uint8_t eventID, DIAG_EVENT_e event, uint32_t data);
91 
92 /*========== Static Function Implementations ================================*/
93 /**
94  * @brief DIAG_Reset resetsall needed structures
95  * @details This function gets called during initialization of the diagnose
96  * module. It clears memory and counters used by diag later on.
97  */
98 
99 static void DIAG_Reset(void) {
100  diag_locked = 1;
101 
102  /* Reset counter */
103  for (uint32_t i = 0u; i < sizeof(diag.entry_cnt); i++) {
104  diag.entry_cnt[i] = 0;
105  }
106  diag.errcnttotal = 0;
107  diag_locked = 0;
108 }
109 
110 /*========== Extern Function Implementations ================================*/
112  STD_RETURN_TYPE_e retval = STD_OK;
113  uint8_t id_nr = (uint8_t)DIAG_ID_MAX;
114  /* take assumptions on the value of DIAG_ID_MAX */
115  FAS_ASSERT((uint16_t)DIAG_ID_MAX < UINT8_MAX);
116  uint32_t tmperr_Check[((uint16_t)DIAG_ID_MAX + 31u) / 32u] = {0};
117 
118  diag_devptr = diag_dev_pointer;
119 
121  uint16_t checkfail = 0u;
122 
123  /* TODO this will always evaluate to true?! */
124  if (checkfail > 0u) {
125  DIAG_Reset();
126  }
127 
128  /* Fill lookup table id2ch */
129  for (uint8_t c = 0; c < diag_dev_pointer->nr_of_ch; c++) {
130  id_nr = diag_dev_pointer->ch_cfg[c].id;
131  if (id_nr < (uint16_t)DIAG_ID_MAX) {
132  diag.id2ch[id_nr] = c; /* e.g. diag.id2ch[DIAG_ID_90] = configured channel index */
133  } else {
134  /* Configuration error -> set retval to #STD_NOT_OK */
135  checkfail |= 0x20u;
136  retval = STD_NOT_OK;
137  }
138  }
139 
140  for (uint8_t i = 0; i < (uint8_t)(((uint16_t)DIAG_ID_MAX + 31u) / 32u); i++) {
141  tmperr_Check[i] = 0u;
142  }
143 
144  /* Fill enable array err_enableflag */
145  for (uint8_t i = 0; i < diag_dev_pointer->nr_of_ch; i++) {
146  if (diag_dev_pointer->ch_cfg[i].enable_evaluate == DIAG_EVALUATION_DISABLED) {
147  /* Disable diagnosis entry */
148  tmperr_Check[diag_dev_pointer->ch_cfg[i].id / 32] |= (1 << (diag_dev_pointer->ch_cfg[i].id % 32));
149  }
150  }
151 
152  /* take over configured error enable masks*/
153  for (uint8_t c = 0; c < (uint8_t)(((uint16_t)DIAG_ID_MAX + 31u) / 32u); c++) {
154  diag.err_enableflag[c] = ~tmperr_Check[c];
155  }
156 
158  return retval;
159 }
160 
161 void DIAG_PrintErrors(void) {
162 }
163 
164 static uint8_t DIAG_EntryWrite(uint8_t eventID, DIAG_EVENT_e event, uint32_t data) {
165  uint8_t ret_val = 0;
166  if (diag_locked > 0u) {
167  return ret_val; /* only locked when clearing the diagnosis memory */
168  }
169 
170  if (diag.entry_event[eventID] == event) {
171  /* same event of same error type already recorded before -> ignore until event toggles */
172  return ret_val;
173  }
174  if ((diag.entry_event[eventID] == DIAG_EVENT_OK) && (event == DIAG_EVENT_RESET)) {
175  /* do record DIAG_EVENT_RESET-event only if last event was an error (re-initialization) */
176  /* meaning: DIAG_EVENT_RESET-event at first time call or after DIAG_EVENT_OK-event will not be recorded */
177  return ret_val;
178  }
179 
180  if (++diag.entry_cnt[eventID] > DIAG_MAX_ENTRIES_OF_ERROR) {
181  /* this type of error has been recorded too many times -> ignore to avoid filling buffer with same failurecodes */
183  return ret_val;
184  }
185 
186  /* now record failurecode */
187  ret_val = 0xFF;
188 
189  /* counts of (new) diagnosis entry records which is still not been read by
190  * external Tool which will reset this value to 0 after having read all
191  * new entries which means <acknowledged by user> */
193  ++diag.errcnttotal; /* total counts of diagnosis entry records */
194  diag.entry_event[eventID] = event;
195 
196  return ret_val;
197 }
198 
201  uint32_t *u32ptr_errCodemsk = NULL;
202  uint32_t *u32ptr_warnCodemsk = NULL;
203  uint16_t *u16ptr_threshcounter = NULL;
204  uint16_t cfg_threshold = 0;
205  uint16_t err_enable_idx = 0;
206  uint32_t err_enable_bitmask = 0;
207 
208  DIAG_RECORDING_e recording_enabled;
209  DIAG_EVALUATE_e evaluate_enabled;
210 
213  }
214 
215  if (diag_id >= DIAG_ID_MAX) {
217  }
218 
219  if (!((impact == DIAG_SYSTEM) || (DIAG_STRING))) {
221  }
222 
223  if ((impact == DIAG_STRING) && (data >= BS_NR_OF_STRINGS)) {
225  }
226 
227  /* Determine a stringID, for impact level #DIAG_SYSTEM this is
228  always 0. This stringID is used to access the #DIAG_s::occurrenceCounter
229  2D-array.
230  */
231  uint8_t stringID = 0u;
232  if (impact == DIAG_STRING) {
233  stringID = data;
234  }
235 
236  err_enable_idx = diag_id / 32; /* array index of diag.err_enableflag[..] */
237  err_enable_bitmask = 1 << (diag_id % 32); /* bit number (mask) of diag.err_enableflag[idx] */
238 
239  u32ptr_errCodemsk = &diag.errflag[err_enable_idx];
240  u32ptr_warnCodemsk = &diag.warnflag[err_enable_idx];
241  u16ptr_threshcounter = &diag.occurrenceCounter[stringID][diag_id];
242  cfg_threshold = diag_devptr->ch_cfg[diag.id2ch[diag_id]].threshold;
243  recording_enabled = diag_devptr->ch_cfg[diag.id2ch[diag_id]].enable_recording;
244  evaluate_enabled = diag_devptr->ch_cfg[diag.id2ch[diag_id]].enable_evaluate;
245 
246  if (event == DIAG_EVENT_OK) {
247  if ((diag.err_enableflag[err_enable_idx] & err_enable_bitmask) > 0u) {
248  /* if (((*u16ptr_threshcounter) == 0) && (*u32ptr_errCodemsk == 0)) */
249  if (((*u16ptr_threshcounter) == 0)) {
250  /* everything ok, nothing to be handled */
251  } else if ((*u16ptr_threshcounter) > 1) {
252  (*u16ptr_threshcounter)--; /* Error did not occur, decrement Error-Counter */
253  } else if ((*u16ptr_threshcounter) == 1) {
254  /* else if ((*u16ptr_threshcounter) <= 1) */
255  /* Error did not occur, now decrement to zero and clear Error- or Warning-Flag and make recording if enabled */
256  *u32ptr_errCodemsk &= ~err_enable_bitmask; /* ERROR: clear corresponding bit in errflag[idx] */
257  *u32ptr_warnCodemsk &= ~err_enable_bitmask; /* WARNING: clear corresponding bit in warnflag[idx] */
258  (*u16ptr_threshcounter) = 0;
259  /* Make entry in error-memory (error disappeared) */
260  if (recording_enabled == DIAG_RECORDING_ENABLED) {
261  DIAG_EntryWrite(diag_id, event, data);
262  }
263 
264  if (evaluate_enabled == DIAG_EVALUATION_ENABLED) {
265  /* Call callback function and reset error */
267  }
268  }
269  }
270  ret_val = DIAG_HANDLER_RETURN_OK; /* Function does not return an error-message! */
271  } else if (event == DIAG_EVENT_NOT_OK) {
272  if ((diag.err_enableflag[err_enable_idx] & err_enable_bitmask) > 0u) {
273  if ((*u16ptr_threshcounter) < cfg_threshold) {
274  (*u16ptr_threshcounter)++; /* error-threshold not exceeded yet, increment Error-Counter */
275  ret_val = DIAG_HANDLER_RETURN_OK; /* Function does not return an error-message! */
276  } else if ((*u16ptr_threshcounter) == cfg_threshold) {
277  /* Error occured AND error-threshold exceeded */
278  (*u16ptr_threshcounter)++;
279  *u32ptr_errCodemsk |= err_enable_bitmask; /* ERROR: set corresponding bit in errflag[idx] */
280  *u32ptr_warnCodemsk &= ~err_enable_bitmask; /* WARNING: clear corresponding bit in warnflag[idx] */
281 
282  /* Make entry in error-memory (error occurred) */
283  if (recording_enabled == DIAG_RECORDING_ENABLED) {
284  DIAG_EntryWrite(diag_id, event, data);
285  }
286 
287  if (evaluate_enabled == DIAG_EVALUATION_ENABLED) {
288  /* Call callback function and set error */
290  }
291  /* Function returns an error-message! */
293  } else if (((*u16ptr_threshcounter) > cfg_threshold)) {
294  /* error-threshold already exceeded, nothing to be handled */
296  }
297  } else {
298  /* Error occured BUT NOT enabled by mask */
299  *u32ptr_errCodemsk &= ~err_enable_bitmask; /* ERROR: clear corresponding bit in errflag[idx] */
300  *u32ptr_warnCodemsk |= err_enable_bitmask; /* WARNING: set corresponding bit in warnflag[idx] */
301  ret_val = DIAG_HANDLER_RETURN_WARNING_OCCURRED; /* Function returns an error-message! */
302  }
303  } else if (event == DIAG_EVENT_RESET) {
304  if ((diag.err_enableflag[err_enable_idx] & err_enable_bitmask) > 0u) {
305  /* clear counter, Error-, Warning-Flag and make recording if enabled */
306  *u32ptr_errCodemsk &= ~err_enable_bitmask; /* ERROR: clear corresponding bit in errflag[idx] */
307  *u32ptr_warnCodemsk &= ~err_enable_bitmask; /* WARNING: clear corresponding bit in warnflag[idx] */
308  (*u16ptr_threshcounter) = 0;
309  if (recording_enabled == DIAG_RECORDING_ENABLED) {
311  diag_id,
312  event,
313  data); /* Make entry in error-memory (error disappeared) if error was recorded before */
314  }
315  if (evaluate_enabled == DIAG_EVALUATION_ENABLED) {
316  /* Call callback function and reset error */
318  }
319  }
320  ret_val = DIAG_HANDLER_RETURN_OK; /* Function does not return an error-message! */
321  }
322 
323  return ret_val;
324 }
325 
327  STD_RETURN_TYPE_e cond,
328  DIAG_ID_e diag_id,
329  DIAG_IMPACT_LEVEL_e impact,
330  uint32_t data) {
331  STD_RETURN_TYPE_e retVal = STD_NOT_OK;
332 
333  if (cond == STD_OK) {
334  DIAG_Handler(diag_id, DIAG_EVENT_OK, impact, data);
335  } else {
336  DIAG_Handler(diag_id, DIAG_EVENT_NOT_OK, impact, data);
337  }
338 
339  return retVal;
340 }
341 
342 /*========== Externalized Static Function Implementations (Unit Test) =======*/
os.h
Implementation of the tasks used by the system, headers.
DIAG_IMPACT_LEVEL_e
enum DIAG_IMPACT_LEVEL DIAG_IMPACT_LEVEL_e
diag_devptr
static DIAG_DEV_s * diag_devptr
Definition: diag.c:69
DIAG_HANDLER_RETURN_OK
@ DIAG_HANDLER_RETURN_OK
Definition: diag.h:64
DIAG_EVALUATION_ENABLED
@ DIAG_EVALUATION_ENABLED
Definition: diag_cfg.h:208
DIAG_STATE_INITIALIZED
@ DIAG_STATE_INITIALIZED
Definition: diag.h:80
STD_RETURN_TYPE_e
enum STD_RETURN_TYPE STD_RETURN_TYPE_e
DIAG::state
DIAG_STATE_e state
Definition: diag.h:85
DIAG
Definition: diag.h:84
DIAG_HANDLER_INVALID_ERR_IMPACT
@ DIAG_HANDLER_INVALID_ERR_IMPACT
Definition: diag.h:71
diag.h
Diagnosis driver header.
DIAG_Reset
static void DIAG_Reset(void)
DIAG_Reset resetsall needed structures.
Definition: diag.c:99
DIAG_CH_CFG::threshold
uint16_t threshold
Definition: diag_cfg.h:263
DIAG::err_enableflag
uint32_t err_enableflag[(DIAG_ID_MAX+31)/32]
Definition: diag.h:95
DIAG::id2ch
uint8_t id2ch[DIAG_ID_MAX]
Definition: diag.h:91
diag_kDatabaseShim
const DIAG_DATABASE_SHIM_s diag_kDatabaseShim
Definition: diag_cfg.c:99
DIAG_EVENT_OK
@ DIAG_EVENT_OK
Definition: diag_cfg.h:201
DIAG_Handler
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:199
DIAG_DEV::nr_of_ch
uint8_t nr_of_ch
Definition: diag_cfg.h:277
DIAG_EVENT_RESET
@ DIAG_EVENT_RESET
Definition: diag_cfg.h:203
DIAG_STATE_UNINITIALIZED
@ DIAG_STATE_UNINITIALIZED
Definition: diag.h:79
DIAG::warnflag
uint32_t warnflag[(DIAG_ID_MAX+31)/32]
Definition: diag.h:94
FAS_ASSERT
#define FAS_ASSERT(x)
Assertion macro that asserts that x is true.
Definition: fassert.h:237
DIAG_RECORDING_e
enum DIAG_RECORDING DIAG_RECORDING_e
DIAG_ID_e
enum DIAG_ID DIAG_ID_e
DIAG_HANDLER_RETURN_UNKNOWN
@ DIAG_HANDLER_RETURN_UNKNOWN
Definition: diag.h:68
DIAG::errflag
uint32_t errflag[(DIAG_ID_MAX+31)/32]
Definition: diag.h:93
DIAG_STRING
@ DIAG_STRING
Definition: diag_cfg.h:215
DIAG_Initialize
STD_RETURN_TYPE_e DIAG_Initialize(DIAG_DEV_s *diag_dev_pointer)
DIAG_Init initializes all needed structures/buffers.
Definition: diag.c:111
STD_OK
@ STD_OK
Definition: fstd_types.h:72
DIAG_SYSTEM
@ DIAG_SYSTEM
Definition: diag_cfg.h:214
DIAG_EntryWrite
static uint8_t DIAG_EntryWrite(uint8_t eventID, DIAG_EVENT_e event, uint32_t data)
DIAG_EntryWrite adds an error entry.
Definition: diag.c:164
DIAG_ID_cfg
DIAG_ID_CFG_s DIAG_ID_cfg[]
Definition: diag_cfg.c:110
DIAG_MAX_ENTRIES_OF_ERROR
#define DIAG_MAX_ENTRIES_OF_ERROR
Definition: diag_cfg.h:110
DIAG_RECORDING_ENABLED
@ DIAG_RECORDING_ENABLED
Definition: diag_cfg.h:242
DIAG::errcnttotal
uint16_t errcnttotal
Definition: diag.h:86
DIAG::entry_event
uint32_t entry_event[DIAG_ID_MAX]
Definition: diag.h:88
DIAG_CheckEvent
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:326
STD_NOT_OK
@ STD_NOT_OK
Definition: fstd_types.h:73
DIAG_EVALUATE_e
enum DIAG_EVALUATE DIAG_EVALUATE_e
DIAG_CH_CFG::enable_evaluate
DIAG_EVALUATE_e enable_evaluate
Definition: diag_cfg.h:268
DIAG_HANDLER_RETURN_NOT_READY
@ DIAG_HANDLER_RETURN_NOT_READY
Definition: diag.h:72
DIAG_PrintErrors
void DIAG_PrintErrors(void)
Prints contents of the error buffer on user request.
Definition: diag.c:161
DIAG_EVENT_NOT_OK
@ DIAG_EVENT_NOT_OK
Definition: diag_cfg.h:202
DIAG_EVENT_e
enum DIAG_EVENT DIAG_EVENT_e
DIAG_HANDLER_RETURN_ERR_OCCURRED
@ DIAG_HANDLER_RETURN_ERR_OCCURRED
Definition: diag.h:65
DIAG_RETURNTYPE_e
enum DIAG_RETURNTYPE DIAG_RETURNTYPE_e
DIAG_CH_CFG::enable_recording
DIAG_RECORDING_e enable_recording
Definition: diag_cfg.h:267
DIAG::entry_cnt
uint8_t entry_cnt[DIAG_ID_MAX]
Definition: diag.h:89
DIAG_DEV
Definition: diag_cfg.h:276
DIAG_CH_CFG::fpCallback
DIAG_CALLBACK_FUNCTION_f * fpCallback
Definition: diag_cfg.h:269
DIAG_HANDLER_RETURN_WRONG_ID
@ DIAG_HANDLER_RETURN_WRONG_ID
Definition: diag.h:67
DIAG::occurrenceCounter
uint16_t occurrenceCounter[BS_NR_OF_STRINGS][DIAG_ID_MAX]
Definition: diag.h:90
DIAG_EVALUATION_DISABLED
@ DIAG_EVALUATION_DISABLED
Definition: diag_cfg.h:209
diag_locked
static uint8_t diag_locked
Definition: diag.c:72
DIAG_DEV::ch_cfg
DIAG_ID_CFG_s * ch_cfg
Definition: diag_cfg.h:278
DIAG_CH_CFG::id
DIAG_ID_e id
Definition: diag_cfg.h:261
DIAG_HANDLER_RETURN_WARNING_OCCURRED
@ DIAG_HANDLER_RETURN_WARNING_OCCURRED
Definition: diag.h:66
BS_NR_OF_STRINGS
#define BS_NR_OF_STRINGS
Definition: battery_system_cfg.h:89
diag
static DIAG_s diag
Definition: diag.c:66
DIAG::errcntreported
uint16_t errcntreported
Definition: diag.h:87
DIAG_HANDLER_INVALID_DATA
@ DIAG_HANDLER_INVALID_DATA
Definition: diag.h:70
DIAG_ID_MAX
@ DIAG_ID_MAX
Definition: diag_cfg.h:196