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