foxBMS - Unit Tests  1.5.0
The foxBMS Unit Tests API Documentation
fassert.h
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 fassert.h
44  * @author foxBMS Team
45  * @date 2020-03-20 (date of creation)
46  * @updated 2023-02-03 (date of last update)
47  * @version v1.5.0
48  * @ingroup ASSERT
49  * @prefix FAS
50  *
51  * @brief Assert macro implementation
52  *
53  * @details The default implementation accommodates three behaviors,
54  * based on FAS_ASSERT_LEVEL symbol:
55  *
56  * - When the FAS_ASSERT_LEVEL symbol is defined as
57  * FAS_ASSERT_LEVEL_INF_LOOP_AND_DISABLE_INTERRUPTS, the FAS_ASSERT
58  * macro is implemented as an infinite loop in which all interrupts
59  * are disabled. This will definitely trigger a watchdog reset.
60  *
61  * - When FAS_ASSERT_LEVEL symbol is defined as
62  * FAS_ASSERT_LEVEL_INF_LOOP_FOR_DEBUG, the validation performed by
63  * the FAS_ASSERT macro is enabled, and a failed validation triggers
64  * an infinite loop. This configuration is recommended for
65  * development environments, as it prevents further execution.
66  * Depending on the configuration this might lead to a watchdog
67  * reset. This mode is intended for investigation of problems by a
68  * developer.
69  *
70  * - When FAS_ASSERT_LEVEL symbol is defined as
71  * FAS_ASSERT_LEVEL_NO_OPERATION, the FAS_ASSERT macro is defined as
72  * empty and does nothing. It might be necessary to activate this
73  * mode in resource-constrained situations. Generally it is not
74  * recommended to use this option as it will not notice the
75  * undefined system-states that the assert should catch.
76  *
77  * Generally assertions should be used for asserting states and values
78  * that should occur when the program is executed correctly. Do *not*
79  * assert anything that *might* be false. As an example it is
80  * perfectly good practice to assert that the input to a function is
81  * not a null pointer if the function is not designed to accept null
82  * pointers, but it is not good to check if a communication error has
83  * occurred somewhere. Assertions should never trip in a bug-free
84  * program.
85  *
86  * Usage is FAS_ASSERT(condition that should be true).
87  */
88 
89 #ifndef FOXBMS__FASSERT_H_
90 #define FOXBMS__FASSERT_H_
91 
92 /*========== Includes =======================================================*/
93 #include <stdbool.h>
94 #include <stdint.h>
95 
96 /*========== Macros and Definitions =========================================*/
97 
98 /* AXIVION Disable Style MisraC2012Directive-1.1: 'pragma' required to tell the
99  * TI ARM CGT compiler, that this is an interrupt function
100  * (see SPNU151V-January1998-RevisedFebruary2020: 5.11.29 The SWI_ALIAS Pragma)
101  */
102 /* AXIVION Disable Style MisraC2012-1.2: Function is implemented in assembler
103  * and this is the way to tell it the TI compiler (see
104  * src\os\freertos\portable\ccs\arm_cortex-r5\portasm.asm::swiPortDisableInterrupts)
105  */
106 /* AXIVION Disable Style MisraC2012-8.6: Function definition is in assembler
107  * (see
108  * src\os\freertos\portable\ccs\arm_cortex-r5\portasm.asm::swiPortDisableInterrupts)
109  */
110 /**
111  * @brief Disable interrupts
112  * @details This alias is mapped to an ASM function and disables all interrupts
113  * by writing to the SPSR (Saved Program Status Register) register
114  * through the control field mask byte PSR[7:0] (privileged
115  * software execution)
116  */
117 #pragma SWI_ALIAS(FAS_DisableInterrupts, 5)
118 extern void FAS_DisableInterrupts(void);
119 /* AXIVION Enable Style MisraC2012-8.6: */
120 /* AXIVION Enable Style MisraC2012-1.2: */
121 /* AXIVION Enable Style MisraC2012Directive-1.1: */
122 
123 /**
124  * @brief Define that evaluates to essential boolean false thus tripping
125  * an assert.
126  * @details Call FAS_ASSERT() with this define in order to stop the code
127  * and trip an assertion.
128  */
129 #define FAS_TRAP (0u == 1u)
130 
131 /**
132  * @brief Struct for storing assert information
133  * @details This struct is intended for storing, information on the place
134  * in the code where an assert has been violated.
135  */
136 typedef struct {
137  uint32_t *pc; /*!< value of the program counter register */
138  uint32_t line; /*!< line number where an assert has triggered */
140 
141 /**
142  * @brief Copy the assert location into the assert struct.
143  * @details Takes the location of the last assertion and stores it into the
144  * static fas_assertLocation.
145  * This definition has to be at this position in order to be used by
146  * the macros below.
147  * If you get issues in a unit test with this being not defined, try
148  * to add this header to the unit tests includes explicitly.
149  * @param[in] pc address of the program counter where the assertion
150  * occurred
151  * @param[in] line line where the assertion occurred
152  */
153 extern void FAS_StoreAssertLocation(uint32_t *pc, uint32_t line);
154 
155 /**
156  * @def FAS_ASSERT_LEVEL_INF_LOOP_AND_DISABLE_INTERRUPTS
157  * @brief This assert level traps the complete program by going into an
158  * infinite loop and disabling all interrupts.
159  *
160  * @def FAS_ASSERT_LEVEL_INF_LOOP_FOR_DEBUG
161  * @brief This assert level traps the current task by going into an
162  * infinite loop.
163  *
164  * @def FAS_ASSERT_LEVEL_NO_OPERATION
165  * @brief This assert level does nothing (except for the standard recording
166  * of the assert location which does every level).
167  */
168 #define FAS_ASSERT_LEVEL_INF_LOOP_AND_DISABLE_INTERRUPTS (0u)
169 #define FAS_ASSERT_LEVEL_INF_LOOP_FOR_DEBUG (1u)
170 #define FAS_ASSERT_LEVEL_NO_OPERATION (2u)
171 
172 /**
173  * @def FAS_ASSERT_LEVEL
174  * @brief Set the assert level to a standard value if not set by the build.
175  */
176 #ifndef FAS_ASSERT_LEVEL
177 #define FAS_ASSERT_LEVEL FAS_ASSERT_LEVEL_INF_LOOP_AND_DISABLE_INTERRUPTS
178 #endif
179 
180 /*============= define how the assert shall behave =============*/
181 #if FAS_ASSERT_LEVEL == FAS_ASSERT_LEVEL_INF_LOOP_AND_DISABLE_INTERRUPTS
182 /** Assert macro will trigger a watchdog reset */
183 static inline void FAS_InfiniteLoop(void) {
184  /* disable IRQ interrupts */
186  /* AXIVION Next Codeline Style MisraC2012-2.2: an infinite loop is intended to stop further code execution */
187  while (true) { /* Stay here until watchdog reset happens */
188  }
189 }
190 #elif FAS_ASSERT_LEVEL == FAS_ASSERT_LEVEL_INF_LOOP_FOR_DEBUG
191 /** Assert macro will stay in infinite loop */
192 static inline void FAS_InfiniteLoop(void) {
193  while (true) {
194  /* Stay here to ease debugging */
195  }
196 }
197 #elif FAS_ASSERT_LEVEL == FAS_ASSERT_LEVEL_NO_OPERATION
198 static inline void FAS_InfiniteLoop(void) {
199 }
200 #else
201 #error "Invalid value for FAS_ASSERT_LEVEL"
202 #endif
203 
204 /*============= define the recording macro =============*/
205 #ifdef UNITY_UNIT_TEST
206 /**
207  * @def __curpc(x)
208  * @brief replaces in unit test the (platform-specific) function for the retrieval of the program counter
209  */
210 static inline uint32_t __curpc(void) {
211  return 0u;
212 }
213 #endif
214 
215 /**
216  * @brief Record the assert location
217  * @details Retrieves the program counter (with __curpc()) and line-number at
218  * the current location and passes it to #FAS_StoreAssertLocation().
219  *
220  * It is important that this is a macro in order to insert it directly
221  * at he assert location in the code
222  */
223 /* AXIVION Next Construct Style MisraC2012-11.5: The program counter needs to be casted to platform register width */
224 #define FAS_ASSERT_RECORD() \
225  do { \
226  uint32_t *pc = (uint32_t *)__curpc(); \
227  FAS_StoreAssertLocation(pc, __LINE__); \
228  } while (false)
229 
230 /*============= define the assertion-macro =============*/
231 /**
232  * @def FAS_ASSERT(x)
233  * @brief Assertion macro that asserts that x is true
234  * @details This macro asserts the taken argument x. If the assertion fails
235  * it calls #FAS_ASSERT_RECORD() and then #FAS_InfiniteLoop().
236  *
237  * In unit tests this is replace by an exception that is thrown in
238  * order to be able to test for a failed assertion.
239  *
240  * Use this macro if you want to assert. If the assertion fails
241  * the macro will take action based on the configuration of this module.
242  * See #FAS_ASSERT_LEVEL for reference.
243  *
244  * If the macro passes, it is just ignored. If you want to definitely
245  * fail, you can use the value #FAS_TRAP as an argument which is
246  * designed to fail in all cases.
247  */
248 #ifdef UNITY_UNIT_TEST
249 #include "CException.h"
250 #define FAS_ASSERT(x) \
251  if (!(x)) \
252  Throw(0)
253 #else
254 #define FAS_ASSERT(x) \
255  do { \
256  if (!(x)) { \
257  FAS_ASSERT_RECORD(); \
258  FAS_InfiniteLoop(); \
259  } \
260  } while (false)
261 #endif
262 
263 #if defined(__STDC_VERSION__) /* We have some newer compiler (C94 at least) */
264 #if __STDC_VERSION__ == 199409L
265 #warning "Ignoring static asserts in C94 mode (FAS_STATIC_ASSERT)."
266 #define FAS_STATIC_ASSERT(cond, msg)
267 #elif __STDC_VERSION__ == 199901L
268 #if defined(__TI_COMPILER_VERSION__)
269 /* The TI compiler seems to have hacks to enable static assert see include/sys/cdefs.h */
270 #define FAS_STATIC_ASSERT(cond, msg) _Static_assert(cond, msg)
271 #else /* for other compilers just ignore the static assert */
272 #warning "Ignoring static asserts in C99 mode (FAS_STATIC_ASSERT)."
273 #define FAS_STATIC_ASSERT(...)
274 #endif
275 #elif __STDC_VERSION__ == 201112L
276 #define FAS_STATIC_ASSERT(cond, msg) _Static_assert(cond, msg)
277 #elif __STDC_VERSION__ == 201710L
278 #define FAS_STATIC_ASSERT(cond, msg) _Static_assert(cond, msg)
279 #endif
280 #else
281 /* if __STDC_VERSION__ is not defined, we have some very old compiler and we
282  need to ignore static asserting */
283 #warning "Ignoring static asserts in C89/C90 mode (FAS_STATIC_ASSERT)."
284 #define FAS_STATIC_ASSERT(cond, msg)
285 #endif
286 
287 /*========== Extern Constant and Variable Declarations ======================*/
288 
289 /*========== Extern Function Prototypes =====================================*/
290 
291 /*========== Externalized Static Functions Prototypes (Unit Test) ===========*/
292 #ifdef UNITY_UNIT_TEST
293 #endif
294 
295 #endif /* FOXBMS__FASSERT_H_ */
static uint32_t __curpc(void)
Definition: fassert.h:210
void FAS_StoreAssertLocation(uint32_t *pc, uint32_t line)
Copy the assert location into the assert struct.
Definition: fassert.c:72
void FAS_DisableInterrupts(void)
Disable interrupts.
static void FAS_InfiniteLoop(void)
Definition: fassert.h:183
Struct for storing assert information.
Definition: fassert.h:136