foxBMS - Unit Tests  1.3.0
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-05-30 (date of last update)
47  * @version v1.3.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 ASSERT_LEVEL symbol:
55  *
56  * - When the ASSERT_LEVEL symbol is defined as
57  * 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 ASSERT_LEVEL symbol is defined as 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 ASSERT_LEVEL symbol is defined as 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 ressource-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 MisraC2012-1.2 MisraC2012Directive-4.1: Function is
96  * implemented in Assembler (see swiPortDisableInterrupts) and this is the way
97  * to tell it the TI compiler */
98 /**
99  * @brief Disable interrupts
100  * @details This alias is mapped to an ASM function and disables all interrupts
101  * by writing to the SPSR (Saved Program Status Register) register
102  * through the control field mask byte PSR[7:0] (privileged
103  * software execution)
104  */
105 #pragma SWI_ALIAS(FAS_DisableInterrupts, 5)
106 extern void FAS_DisableInterrupts(void);
107 /* AXIVION Enable Style MisraC2012-1.2 MisraC2012Directive-4.1: */
108 
109 /**
110  * @brief Define that evaluates to essential boolean false thus tripping
111  * an assert.
112  * @details Call FAS_ASSERT() with this define in order to stop the code
113  * and trip an assertion.
114  */
115 #define FAS_TRAP (0u == 1u)
116 
117 /**
118  * @brief Struct for storing assert information
119  * @details This struct is intended for storing, information on the place
120  * in the code where an assert has been violated.
121  */
122 typedef struct {
123  uint32_t *pc; /*!< value of the program counter register */
124  uint32_t line; /*!< line number where an assert has triggered */
126 
127 /**
128  * @brief Copy the assert location into the assert struct.
129  * @details Takes the location of the last assertion and stores it into the
130  * static fas_assertLocation.
131  * This definition has to be at this position in order to be used by
132  * the macros below.
133  * If you get issues in a unit test with this being not defined, try
134  * to add this header to the unit tests includes explicitely.
135  * @param[in] pc address of the program counter where the assertion
136  * occurred
137  * @param[in] line line where the assertion occurred
138  */
139 extern void FAS_StoreAssertLocation(uint32_t *pc, uint32_t line);
140 
141 /**
142  * @def ASSERT_LEVEL_INF_LOOP_AND_DISABLE_INTERRUPTS
143  * @brief This assert level traps the complete program by going into an
144  * infinite loop and disabling all interrupts.
145  *
146  * @def ASSERT_LEVEL_INF_LOOP_FOR_DEBUG
147  * @brief This assert level traps the current task by going into an
148  * infinite loop.
149  *
150  * @def ASSERT_LEVEL_NO_OPERATION
151  * @brief This assert level does nothing (except for the standard recording
152  * of the assert location which does every level).
153  */
154 #define ASSERT_LEVEL_INF_LOOP_AND_DISABLE_INTERRUPTS (0u)
155 #define ASSERT_LEVEL_INF_LOOP_FOR_DEBUG (1u)
156 #define ASSERT_LEVEL_NO_OPERATION (2u)
157 
158 /**
159  * @def ASSERT_LEVEL
160  * @brief Set the assert level to a standard value if not set by the build.
161  */
162 #ifndef ASSERT_LEVEL
163 #define ASSERT_LEVEL ASSERT_LEVEL_INF_LOOP_AND_DISABLE_INTERRUPTS
164 #endif
165 
166 /*============= define how the assert shall behave =============*/
167 #if ASSERT_LEVEL == ASSERT_LEVEL_INF_LOOP_AND_DISABLE_INTERRUPTS
168 /** Assert macro will trigger a watchdog reset */
169 static inline void FAS_InfiniteLoop(void) {
170  /* disable IRQ interrupts */
172  /* AXIVION Next Line Style MisraC2012-2.2: an infinite loop is intended to stop further code execution */
173  while (true) { /* Stay here until watchdog reset happens */
174  }
175 }
176 #elif ASSERT_LEVEL == ASSERT_LEVEL_INF_LOOP_FOR_DEBUG
177 /** Assert macro will stay in infinite loop */
178 static inline void FAS_InfiniteLoop(void) {
179  while (true) {
180  /* Stay here to ease debugging */
181  }
182 }
183 #elif ASSERT_LEVEL == ASSERT_LEVEL_NO_OPERATION
184 static inline void FAS_InfiniteLoop(void) {
185 }
186 #else
187 #error "Invalid value for ASSERT_LEVEL"
188 #endif
189 
190 /*============= define the recording macro =============*/
191 
192 #ifdef UNITY_UNIT_TEST
193 /**
194  * @def __curpc(x)
195  * @brief replaces in unit test the (platform-specific) function for the retrieval of the program counter
196  */
197 static inline uint32_t __curpc(void) {
198  return 0u;
199 }
200 #endif
201 
202 /**
203  * @brief Record the assert location
204  * @details Retrieves the program counter (with __curpc()) and line-number at
205  * the current location and passes it to #FAS_StoreAssertLocation().
206  *
207  * It is important that this is a macro in order to insert it directly
208  * at he assert location in the code
209  */
210 #define FAS_ASSERT_RECORD() \
211  do { \
212  /* AXIVION Next Line Style MisraC2012-11.5: The program counter needs to be casted to platform register
213  width */ \
214  uint32_t *pc = (uint32_t *)__curpc(); \
215  FAS_StoreAssertLocation(pc, __LINE__); \
216  } while (0)
217 
218 /*============= define the assertion-macro =============*/
219 /**
220  * @def FAS_ASSERT(x)
221  * @brief Assertion macro that asserts that x is true
222  * @details This macro asserts the taken argument x. If the assertion fails
223  * it calls #FAS_ASSERT_RECORD() and then #FAS_InfiniteLoop().
224  *
225  * In unit tests this is replace by an exception that is thrown in
226  * order to be able to test for a failed assertion.
227  *
228  * Use this macro if you want to assert. If the assertion fails
229  * the macro will take action based on the configuration of this module.
230  * See #ASSERT_LEVEL for reference.
231  *
232  * If the macro passes, it is just ignored. If you want to definitely
233  * fail, you can use the value #FAS_TRAP as an argument which is
234  * designed to fail in all cases.
235  */
236 #ifdef UNITY_UNIT_TEST
237 #include "CException.h"
238 #define FAS_ASSERT(x) \
239  if (!(x)) \
240  Throw(0)
241 #else
242 #define FAS_ASSERT(x) \
243  do { \
244  if (!(x)) { \
245  FAS_ASSERT_RECORD(); \
246  FAS_InfiniteLoop(); \
247  } \
248  } while (0)
249 #endif
250 
251 #if defined(__STDC_VERSION__) /* We have some newer compiler (C94 at least) */
252 #if __STDC_VERSION__ == 199409L
253 #warning "Ignoring static asserts in C94 mode (f_static_assert)."
254 #define f_static_assert(cond, msg)
255 #elif __STDC_VERSION__ == 199901L
256 #if defined(__TI_COMPILER_VERSION__)
257 /* The TI compiler seems to have hacks to enable static assert see include/sys/cdefs.h */
258 #define f_static_assert(cond, msg) _Static_assert(cond, msg)
259 #else /* for other compilers just ignore the static assert */
260 #warning "Ignoring static asserts in C99 mode (f_static_assert)."
261 #define f_static_assert(...)
262 #endif
263 #elif __STDC_VERSION__ == 201112L
264 #define f_static_assert(cond, msg) _Static_assert(cond, msg)
265 #elif __STDC_VERSION__ == 201710L
266 #define f_static_assert(cond, msg) _Static_assert(cond, msg)
267 #endif
268 #else
269 /* if __STDC_VERSION__ is not defined, we have some very old compiler and we
270  need to ignore static asserting */
271 #warning "Ignoring static asserts in C89/C90 mode (f_static_assert)."
272 #define f_static_assert(cond, msg)
273 #endif
274 
275 /*========== Extern Constant and Variable Declarations ======================*/
276 
277 /*========== Extern Function Prototypes =====================================*/
278 
279 /*========== Externalized Static Functions Prototypes (Unit Test) ===========*/
280 
281 #endif /* FOXBMS__FASSERT_H_ */
static uint32_t __curpc(void)
Definition: fassert.h:197
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:169
Struct for storing assert information.
Definition: fassert.h:122