foxBMS - Unit Tests  1.6.0
The foxBMS Unit Tests API Documentation
test_bms.c
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 test_bms.c
44  * @author foxBMS Team
45  * @date 2020-04-01 (date of creation)
46  * @updated 2023-10-12 (date of last update)
47  * @version v1.6.0
48  * @ingroup UNIT_TEST_IMPLEMENTATION
49  * @prefix TEST
50  *
51  * @brief Tests for the bms driver implementation
52  */
53 
54 /*========== Includes =======================================================*/
55 #include "unity.h"
56 #include "Mockafe.h"
57 #include "Mockbal.h"
58 #include "Mockbattery_system_cfg.h"
59 #include "Mockcontactor.h"
60 #include "Mockdatabase.h"
61 #include "Mockdiag.h"
62 #include "Mockfassert.h"
63 #include "Mockimd.h"
64 #include "Mockinterlock.h"
65 #include "Mockled.h"
66 #include "Mockmeas.h"
67 #include "Mockos.h"
68 #include "Mockplausibility.h"
69 #include "Mocksoa.h"
70 
71 #include "sps_cfg.h"
72 
73 #include "bms.h"
74 #include "foxmath.h"
75 #include "test_assert_helper.h"
76 
77 #include <stdbool.h>
78 
79 /*========== Unit Testing Framework Directives ==============================*/
80 TEST_INCLUDE_PATH("../../src/app/application/bal")
81 TEST_INCLUDE_PATH("../../src/app/application/bms")
82 TEST_INCLUDE_PATH("../../src/app/application/plausibility")
83 TEST_INCLUDE_PATH("../../src/app/application/soa")
84 TEST_INCLUDE_PATH("../../src/app/driver/afe/api")
85 TEST_INCLUDE_PATH("../../src/app/driver/config")
86 TEST_INCLUDE_PATH("../../src/app/driver/contactor")
87 TEST_INCLUDE_PATH("../../src/app/driver/foxmath")
88 TEST_INCLUDE_PATH("../../src/app/driver/imd")
89 TEST_INCLUDE_PATH("../../src/app/driver/interlock")
90 TEST_INCLUDE_PATH("../../src/app/driver/led")
91 TEST_INCLUDE_PATH("../../src/app/driver/meas")
92 TEST_INCLUDE_PATH("../../src/app/driver/sps")
93 TEST_INCLUDE_PATH("../../src/app/engine/diag")
94 TEST_INCLUDE_PATH("../../src/app/task/config")
95 
96 /*========== Definitions and Implementations for Unit Test ==================*/
97 
99 
102  .pConfigurationOfDiagnosisEntries = &diag_diagnosisIdConfiguration[0],
103  .numberOfFatalErrors = 0u,
104 };
105 
108 };
109 
111  /* String contactors configuration */
115  BS_STRING0,
116  CONT_PLUS,
122  BS_STRING0,
123  CONT_MINUS,
126  /* Precharge contactors configuration */
130  BS_STRING0,
134 };
135 
136 /*========== Setup and Teardown =============================================*/
137 void setUp(void) {
138 }
139 
140 void tearDown(void) {
141 }
142 
143 /*========== Test Cases =====================================================*/
144 #define NUM_PRECHARGE_TESTS 13
146 /*
147  * mock callback in order to provide custom values to current_tab
148  */
149 STD_RETURN_TYPE_e MockDATA_ReadBlock_Callback(void *pDataToReceiver, int num_calls) {
150  int32_t current = 0;
151  int32_t voltage_1 = 0;
152  int32_t voltage_2 = 0;
153 
154  /* determine a value depending on num_calls (has to be synchronized with test) */
155  switch (num_calls) {
156  case 0:
158  /* no current, no voltage difference --> expect OK */
159  current = 0;
160  voltage_1 = 0;
161  voltage_2 = 0;
162  break;
163  case 1:
165  /* INT32_MAX current, no voltage difference --> expect NOK */
166  current = INT32_MAX;
167  voltage_1 = 0;
168  voltage_2 = 0;
169  break;
170  case 2:
172  /* INT32_MIN current, no voltage difference --> expect NOK */
173  current = INT32_MIN;
174  voltage_1 = 0;
175  voltage_2 = 0;
176  break;
177  case 3:
179  /* no current, no voltage difference --> expect OK */
180  current = 0;
181  voltage_1 = INT32_MAX;
182  voltage_2 = INT32_MAX;
183  break;
184  case 4:
186  /* no current, no voltage difference --> expect OK */
187  current = 0;
188  voltage_1 = INT32_MIN;
189  voltage_2 = INT32_MIN;
190  break;
191  case 5:
193  /* no current, maximum voltage difference --> expect NOK */
194  current = 0;
195  voltage_1 = INT32_MAX;
196  voltage_2 = INT32_MIN;
197  break;
198  case 6:
200  /* no current, maximum voltage difference --> expect NOK */
201  current = 0;
202  voltage_1 = INT32_MIN;
203  voltage_2 = INT32_MAX;
204  break;
205  case 7:
207  /* current exactly at threshold, no voltage difference --> expect NOK */
209  voltage_1 = 0;
210  voltage_2 = 0;
211  break;
212  case 8:
214  /* no current, voltage difference exactly at threshold --> expect NOK */
215  current = 0;
217  voltage_2 = 0;
218  break;
219  case 9:
221  /* no current, voltage difference exactly at threshold --> expect NOK */
222  current = 0;
223  voltage_1 = 0;
225  break;
226  case 10:
228  /* current exactly 1 below threshold, no voltage difference --> expect OK */
230  voltage_1 = 0;
231  voltage_2 = 0;
232  break;
233  case 11:
235  /* no current, voltage difference exactly 1 below threshold --> expect OK */
236  current = 0;
237  voltage_1 = BMS_PRECHARGE_VOLTAGE_THRESHOLD_mV - 1;
238  voltage_2 = 0;
239  break;
240  case 12:
242  /* no current, voltage difference exactly 1 below threshold --> expect OK */
243  current = 0;
244  voltage_1 = 0;
245  voltage_2 = BMS_PRECHARGE_VOLTAGE_THRESHOLD_mV - 1;
246  break;
247  default:
248  TEST_FAIL_MESSAGE("DATA_ReadBlock_Callback was called too often");
249  }
250  /* ENTER HIGHEST CASE NUMBER IN EXPECT; checks whether all cases are used */
251  TEST_ASSERT_EQUAL_MESSAGE(12, (NUM_PRECHARGE_TESTS - 1), "Check code of stub. Something does not fit.");
252 
253  if (num_calls >= NUM_PRECHARGE_TESTS) {
254  TEST_FAIL_MESSAGE("This stub is fishy, prechargeExpectedResults is too short for the number of calls");
255  }
256 
257  /* cast to correct struct in order to properly write current and other values */
258  for (uint8_t s = 0; s < BS_NR_OF_STRINGS; s++) {
259  for (uint8_t testNumber = 0; testNumber < NUM_PRECHARGE_TESTS; testNumber++) {
260  prechargeExpectedResults[s][testNumber] = prechargeExpectedResults[0][testNumber];
261  }
262 
263  ((DATA_BLOCK_PACK_VALUES_s *)pDataToReceiver)->stringCurrent_mA[0] = current;
264  ((DATA_BLOCK_PACK_VALUES_s *)pDataToReceiver)->stringVoltage_mV[0] = voltage_1;
265  }
266  ((DATA_BLOCK_PACK_VALUES_s *)pDataToReceiver)->highVoltageBusVoltage_mV = voltage_2;
267 
268  return STD_OK;
269 }
270 
271 /**
272  * @brief Iterate over a callback that supplies various scenarios and check if they work as expected
273  * @details This function uses the callback #MockDATA_ReadBlock_Callback() in order to inject
274  * current tables and voltage tables into the returned database tables. The array
275  * #prechargeExpectedResults contains prepared return values against which the output
276  * of #TEST_BMS_CheckPrecharge() is compared.
277  */
279  /* tell CMock to use our callback */
280  DATA_Read1DataBlock_Stub(MockDATA_ReadBlock_Callback);
281 
283 
284  /* iterate until we have all covered cases from our stub processed */
285  for (uint8_t i = 0u; i < NUM_PRECHARGE_TESTS; i++) {
286  char buffer[30];
287  snprintf(buffer, 30, "Loop iteration %d.", i);
288  for (uint8_t s = 0; s < BS_NR_OF_STRINGS; s++) {
289  DIAG_Handler_IgnoreAndReturn(DIAG_HANDLER_RETURN_OK);
290  DIAG_Handler_IgnoreAndReturn(DIAG_HANDLER_RETURN_OK);
291  TEST_ASSERT_EQUAL_MESSAGE(
292  prechargeExpectedResults[s][i], TEST_BMS_CheckPrecharge(s, &tablePackValues), buffer);
293  }
294  }
295 }
296 
298  /*
299  WARNING: the function under test has code that is unaccessible
300  in order to solve this situation it has to be refactored
301  so that the branch in it does not always evaluate to true.
302 
303  However, the way it is implemented now, the unit test will be
304  always valid for the currently active defines.
305  */
306 
307 #if (BS_POSITIVE_DISCHARGE_CURRENT == true)
308  /* discharge is positive */
309 
310  /* maximum positive current has to be discharge */
311  TEST_ASSERT_EQUAL(BMS_DISCHARGING, BMS_GetCurrentFlowDirection(INT32_MAX));
312 
313  /* maximum negative current has to be charge */
314  TEST_ASSERT_EQUAL(BMS_CHARGING, BMS_GetCurrentFlowDirection(INT32_MIN));
315 #else
316  /* discharge is negative */
317 
318  /* maximum positive current has to be charge */
319  TEST_ASSERT_EQUAL(BMS_CHARGING, BMS_GetCurrentFlowDirection(INT32_MAX));
320 
321  /* maximum negative current has to be discharge */
322  TEST_ASSERT_EQUAL(BMS_DISCHARGING, BMS_GetCurrentFlowDirection(INT32_MIN));
323 #endif
324 
325  /* zero current has to be no charge */
326  TEST_ASSERT_EQUAL(BMS_AT_REST, BMS_GetCurrentFlowDirection(0));
327 
328  /* positive current below/equal to resting current is no current too */
329  TEST_ASSERT_EQUAL(BMS_AT_REST, BMS_GetCurrentFlowDirection(0 + BS_REST_CURRENT_mA - 1));
330 
331  /* negative current below/equal to resting current is no current too */
332  TEST_ASSERT_EQUAL(BMS_AT_REST, BMS_GetCurrentFlowDirection(0 - BS_REST_CURRENT_mA + 1));
333 
334  /* function should have same behavior for #BS_CS_THRESHOLD_NO_CURRENT_mA */
335  TEST_ASSERT_EQUAL(
338 }
339 
341  /* Set the current to 0 */
342  TEST_ASSERT_EQUAL(BMS_AT_REST, BMS_GetCurrentFlowDirection(0u));
343 
344  /* Set the current to #INT32_MAX */
345 #if (BS_POSITIVE_DISCHARGE_CURRENT == true)
346  TEST_ASSERT_EQUAL(BMS_DISCHARGING, BMS_GetCurrentFlowDirection(INT32_MAX));
347 #else
348  TEST_ASSERT_EQUAL(BMS_CHARGING, BMS_GetCurrentFlowDirection(INT32_MAX));
349 #endif
350 
351  /* Set the current to #INT32_MIN */
352 #if (BS_POSITIVE_DISCHARGE_CURRENT == true)
353  TEST_ASSERT_EQUAL(BMS_CHARGING, BMS_GetCurrentFlowDirection(INT32_MIN));
354 #else
355  TEST_ASSERT_EQUAL(BMS_DISCHARGING, BMS_GetCurrentFlowDirection(INT32_MIN));
356 #endif
357 }
358 
359 /** check that invalid values to BMS_CheckPrecharge trip an assertion
360  *
361  * invalid values are all those that do not fall into
362  * 0 <= stringNumber < #BS_NR_OF_STRINGS
363  */
366 
367  /* Invalid string number */
368  DIAG_Handler_IgnoreAndReturn(DIAG_HANDLER_RETURN_OK);
369  DIAG_Handler_IgnoreAndReturn(DIAG_HANDLER_RETURN_OK);
371 
372  /* Invalid string number */
373  DIAG_Handler_IgnoreAndReturn(DIAG_HANDLER_RETURN_OK);
374  DIAG_Handler_IgnoreAndReturn(DIAG_HANDLER_RETURN_OK);
376 
377  /* Invalid string number */
378  DIAG_Handler_IgnoreAndReturn(DIAG_HANDLER_RETURN_OK);
379  DIAG_Handler_IgnoreAndReturn(DIAG_HANDLER_RETURN_OK);
380  TEST_ASSERT_FAIL_ASSERT(TEST_BMS_CheckPrecharge(UINT8_MAX, &tablePackValues));
381 
382  /* Valid string number */
383  DIAG_Handler_IgnoreAndReturn(DIAG_HANDLER_RETURN_OK);
384  DIAG_Handler_IgnoreAndReturn(DIAG_HANDLER_RETURN_OK);
385  TEST_ASSERT_PASS_ASSERT(TEST_BMS_CheckPrecharge(0u, &tablePackValues));
386 }
#define BS_NR_OF_STRINGS
Number of parallel strings in the battery pack.
#define BS_REST_CURRENT_mA
current threshold for determining rest state of battery. If absolute current is below this limit valu...
BS_STRING_PRECHARGE_PRESENT_e
@ BS_STRING_WITH_PRECHARGE
@ BS_STRING0
#define BS_CS_THRESHOLD_NO_CURRENT_mA
current sensor threshold for 0 current in mA as the sensor has a jitter.
STD_RETURN_TYPE_e TEST_BMS_CheckPrecharge(uint8_t stringNumber, DATA_BLOCK_PACK_VALUES_s *pPackValues)
Definition: bms.c:1666
BMS_CURRENT_FLOW_STATE_e BMS_GetCurrentFlowDirection(int32_t current_mA)
Get current flow direction, current value as function parameter.
Definition: bms.c:1590
bms driver header
@ BMS_AT_REST
Definition: bms.h:76
@ BMS_DISCHARGING
Definition: bms.h:74
@ BMS_CHARGING
Definition: bms.h:73
#define BMS_PRECHARGE_VOLTAGE_THRESHOLD_mV
Definition: bms_cfg.h:169
#define BMS_PRECHARGE_CURRENT_THRESHOLD_mA
Definition: bms_cfg.h:172
@ CONT_HAS_NO_FEEDBACK
Definition: contactor_cfg.h:81
@ CONT_FEEDBACK_NORMALLY_OPEN
Definition: contactor_cfg.h:78
@ CONT_PRECHARGE
Definition: contactor_cfg.h:88
@ CONT_MINUS
Definition: contactor_cfg.h:87
@ CONT_PLUS
Definition: contactor_cfg.h:86
@ CONT_SWITCH_OFF
Definition: contactor_cfg.h:71
@ CONT_BIDIRECTIONAL
@ CONT_CHARGING_DIRECTION
@ CONT_DISCHARGING_DIRECTION
@ DATA_BLOCK_ID_PACK_VALUES
Definition: database_cfg.h:105
static DIAG_DIAGNOSIS_STATE_s diag
Definition: diag.c:71
@ DIAG_HANDLER_RETURN_OK
Definition: diag.h:69
math library for often used math functions
STD_RETURN_TYPE_e
Definition: fstd_types.h:82
@ STD_NOT_OK
Definition: fstd_types.h:84
@ STD_OK
Definition: fstd_types.h:83
Header for the configuration for the driver for the smart power switches.
#define SPS_CHANNEL_2
Definition: sps_cfg.h:90
#define SPS_CHANNEL_0
Definition: sps_cfg.h:88
#define SPS_CHANNEL_1
Definition: sps_cfg.h:89
DATA_BLOCK_ID_e uniqueId
Definition: database_cfg.h:125
DATA_BLOCK_HEADER_s header
Definition: database_cfg.h:195
uint8_t nrOfConfiguredDiagnosisEntries
Definition: diag_cfg.h:353
Helper for unit tests.
#define TEST_ASSERT_PASS_ASSERT(_code_under_test)
assert whether assert macro has passed
#define TEST_ASSERT_FAIL_ASSERT(_code_under_test)
assert whether assert macro has failed
BS_STRING_PRECHARGE_PRESENT_e bs_stringsWithPrecharge[BS_NR_OF_STRINGS]
Definition: test_bms.c:106
#define NUM_PRECHARGE_TESTS
Definition: test_bms.c:144
STD_RETURN_TYPE_e prechargeExpectedResults[BS_NR_OF_STRINGS][NUM_PRECHARGE_TESTS]
Definition: test_bms.c:145
void testBMS_CheckPrechargeInvalidStringNumber(void)
Definition: test_bms.c:364
CONT_CONTACTOR_STATE_s cont_contactorStates[]
Definition: test_bms.c:110
void testCheckPrechargeIterateStub(void)
Iterate over a callback that supplies various scenarios and check if they work as expected.
Definition: test_bms.c:278
void setUp(void)
Definition: test_bms.c:137
void tearDown(void)
Definition: test_bms.c:140
void testBMS_GetCurrentFlowDirectionWithTypicalValues(void)
Definition: test_bms.c:297
STD_RETURN_TYPE_e MockDATA_ReadBlock_Callback(void *pDataToReceiver, int num_calls)
Definition: test_bms.c:149
void testCheckCurrentValueDirectionWithCurrentZeroMaxAndMin(void)
Definition: test_bms.c:340
DIAG_ID_CFG_s diag_diagnosisIdConfiguration[]
Definition: test_bms.c:98
DIAG_DEV_s diag_device
Definition: test_bms.c:100