foxBMS  1.4.0
The foxBMS Battery Management System API Documentation
contactor.c
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 contactor.c
44  * @author foxBMS Team
45  * @date 2020-02-11 (date of creation)
46  * @updated 2022-07-28 (date of last update)
47  * @version v1.4.0
48  * @ingroup DRIVERS
49  * @prefix CONT
50  *
51  * @brief Driver for the contactors.
52  *
53  */
54 
55 /*========== Includes =======================================================*/
56 #include "contactor.h"
57 
58 #include "mcu.h"
59 #include "sps.h"
60 
61 /*========== Macros and Definitions =========================================*/
62 
63 /*========== Static Constant and Variable Definitions =======================*/
64 
65 /*========== Extern Constant and Variable Definitions =======================*/
66 
67 /*========== Static Function Prototypes =====================================*/
68 /**
69  * @brief Resolves the contactor index from a contactor name
70  * @details Searches in the contactor index by iteration from front to back for
71  * the contactor name and returns the first hit.
72  * @param[in] name Name of the contactor
73  * @returns index number of the entry in the contactor array
74  */
76 
77 /**
78  * @brief Gets the contactor name from a contactor index
79  * @param[in] index index number of the contactor
80  * @returns Returns the name of the contactor
81  */
83 
84 /**
85  * @brief Returns the sps channel index from a contactor index
86  * @details Currently this implementation maps simply in ascending order
87  */
89 
90 /**
91  * @brief Sets SPS channels according to contactors
92  * @details Currently this implementation assumes simple ascending order.
93  * @param[in] contactor index of the contactor that should be set
94  */
95 static void CONT_SetSpsChannelFromContactor(const CONT_CONTACTOR_INDEX contactor);
96 
97 /** conducts an initialization test of the contactor registry and asserts at failure */
99 
100 /*========== Static Function Implementations ================================*/
102  CONT_CONTACTOR_INDEX contactor = 0u;
103  bool hit = false;
104  do {
105  if (name == cont_contactorStates[contactor].name) {
106  /* contactor found, therefore abort */
107  hit = true;
108  } else {
109  /* continue and increase contactor counter */
110  contactor++;
111  }
112  } while ((contactor < BS_NR_OF_CONTACTORS) && (true != hit));
113 
114  /* an unknown contactor may not exist */
115  FAS_ASSERT(hit == true);
116 
117  return contactor;
118 }
119 
122  return cont_contactorStates[index].name;
123 }
124 
126  FAS_ASSERT(contactor < BS_NR_OF_CONTACTORS);
127  return cont_contactorStates[contactor].spsChannel;
128 }
129 
131  FAS_ASSERT(contactor < BS_NR_OF_CONTACTORS);
132  switch (cont_contactorStates[contactor].currentSet) {
133  case CONT_SWITCH_UNDEF:
134  case CONT_SWITCH_OFF:
136  break;
137  case CONT_SWITCH_ON:
139  break;
140  default:
142  break;
143  }
144 }
145 
147  /* iterate over each contactor and compare found name with resolved name (if a name is used double this would
148  always return the first entry and we would have the second entry from iterating here) */
149  for (CONT_CONTACTOR_INDEX contactor = 0u; contactor < BS_NR_OF_CONTACTORS; contactor++) {
150  const CONT_CONTACTOR_INDEX resolvedContactor = CONT_ResolveContactorName(cont_contactorStates[contactor].name);
151  FAS_ASSERT(contactor == resolvedContactor);
152  const CONT_NAMES_e contactorName = CONT_GetContactorName(contactor);
153  FAS_ASSERT(cont_contactorStates[contactor].name == contactorName);
154 
155  /* convention at the moment: sps channel index has to be the same as contactor index; this may change in
156  future implementations */
157  FAS_ASSERT(contactor == cont_contactorStates[contactor].spsChannel);
158 
159  /* every contactor channel has to be affiliated with contactor */
160  const SPS_CHANNEL_AFFILIATION_e channelAffiliation =
161  SPS_GetChannelAffiliation(cont_contactorStates[contactor].spsChannel);
162  FAS_ASSERT(SPS_AFF_CONTACTOR == channelAffiliation);
163  }
164 }
165 
166 /*========== Extern Function Implementations ================================*/
168  CONT_CONTACTOR_INDEX contactorNumber = CONT_ResolveContactorName(name);
169  CONT_ELECTRICAL_STATE_TYPE_e contactorSetInformation = cont_contactorStates[contactorNumber].currentSet;
170  return contactorSetInformation;
171 }
172 
173 extern void CONT_GetContactorFeedback(void) {
174  for (CONT_CONTACTOR_INDEX contactor = 0; contactor < BS_NR_OF_CONTACTORS; contactor++) {
175  if (CONT_HAS_NO_FEEDBACK == cont_contactorStates[contactor].feedbackPinType) {
176  /* no feedback: assume set value is true */
178  } else if (CONT_FEEDBACK_THROUGH_CURRENT == cont_contactorStates[contactor].feedbackPinType) {
179  /* feedback from current: ask SPS driver for feedback */
180  cont_contactorStates[contactor].feedback =
182  } else if (CONT_FEEDBACK_NORMALLY_OPEN == cont_contactorStates[contactor].feedbackPinType) {
183  cont_contactorStates[contactor].feedback =
185  } else {
186  /* CONT_FEEDBACK_NORMALLY_CLOSED */
187  cont_contactorStates[contactor].feedback =
189  }
190  }
191 }
192 
194  const CONT_NAMES_e name,
195  CONT_ELECTRICAL_STATE_TYPE_e requestedContactorState) {
197  FAS_ASSERT(contactor < BS_NR_OF_CONTACTORS);
198  FAS_ASSERT(
199  (requestedContactorState == CONT_SWITCH_OFF) || (requestedContactorState == CONT_SWITCH_ON) ||
200  (requestedContactorState == CONT_SWITCH_UNDEF));
201 
202  STD_RETURN_TYPE_e retVal = STD_OK;
203 
204  if (requestedContactorState == CONT_SWITCH_ON) {
206  } else if (requestedContactorState == CONT_SWITCH_OFF) {
208  } else {
209  retVal = STD_NOT_OK;
210  }
211 
213 
214  return retVal;
215 }
216 
217 /**
218  * @brief checks the feedback of the contactors
219  *
220  * @details makes a DIAG entry for each contactor when the feedback does not match the set value
221  */
222 extern void CONT_CheckFeedback(void) {
224  /* TODO implement when contactor feedback is available */
225 }
226 
227 extern STD_RETURN_TYPE_e CONT_CloseString(uint8_t stringNumber) {
228  FAS_ASSERT(stringNumber < BS_NR_OF_STRINGS);
229  /* String contactors in the list start at index 0
230  * so string number corresponds to contactor index
231  */
233 }
234 
235 extern STD_RETURN_TYPE_e CONT_OpenString(uint8_t stringNumber) {
236  FAS_ASSERT(stringNumber < BS_NR_OF_STRINGS);
237  /* String contactors in the list start at index 0
238  * so string number corresponds to contactor index
239  */
240  /* TODO: implement current check and similar when opening */
242 }
243 
244 extern STD_RETURN_TYPE_e CONT_ClosePrecharge(uint8_t stringNumber) {
245  FAS_ASSERT(stringNumber < BS_NR_OF_STRINGS);
246  STD_RETURN_TYPE_e retVal = STD_NOT_OK;
247  uint8_t prechargeContactorNumber = 0u;
248  FAS_STATIC_ASSERT((BS_NR_OF_STRINGS <= (uint8_t)UINT8_MAX), "This code assumes BS_NR_OF_STRINGS fits into uint8_t");
249 
250  /* Precharge contactors in the list stay after string contactors
251  * so it has index (number of contactors)-1
252  */
253  if (bs_stringsWithPrecharge[stringNumber] == BS_STRING_WITH_PRECHARGE) {
254  /* Find contactor number corresponding to precharge of the requested string */
255  for (uint8_t stringPrechargeNumber = 0u; stringPrechargeNumber < BS_NR_OF_STRINGS; stringPrechargeNumber++) {
256  if (bs_stringsWithPrecharge[stringPrechargeNumber] == BS_STRING_WITH_PRECHARGE) {
257  if (stringPrechargeNumber == stringNumber) {
258  break;
259  }
260  prechargeContactorNumber++;
261  }
262  }
263  if ((BS_NR_OF_STRINGS + prechargeContactorNumber) < BS_NR_OF_CONTACTORS) {
264  retVal = CONT_SetContactorState(
265  CONT_GetContactorName(BS_NR_OF_STRINGS + prechargeContactorNumber), CONT_SWITCH_ON);
266  }
267  }
268  return retVal;
269 }
270 
271 extern STD_RETURN_TYPE_e CONT_OpenPrecharge(uint8_t stringNumber) {
272  FAS_ASSERT(stringNumber < BS_NR_OF_STRINGS);
273  STD_RETURN_TYPE_e retVal = STD_NOT_OK;
274  uint8_t prechargeContactorNumber = 0u;
275 
276  /* Precharge contactors in the list stay after string contactors
277  * so it has index (number of contactors)-1
278  */
279  if (bs_stringsWithPrecharge[stringNumber] == BS_STRING_WITH_PRECHARGE) {
280  /* Find contactor number corresponding to precharge of the requested string */
281  for (uint8_t stringPrechargeNumber = 0u; stringPrechargeNumber < BS_NR_OF_STRINGS; stringPrechargeNumber++) {
282  if (bs_stringsWithPrecharge[stringPrechargeNumber] == BS_STRING_WITH_PRECHARGE) {
283  if (stringPrechargeNumber == stringNumber) {
284  break;
285  }
286  prechargeContactorNumber++;
287  }
288  }
289  if ((BS_NR_OF_STRINGS + prechargeContactorNumber) < BS_NR_OF_CONTACTORS) {
290  retVal = CONT_SetContactorState(
291  CONT_GetContactorName(BS_NR_OF_STRINGS + prechargeContactorNumber), CONT_SWITCH_OFF);
292  }
293  }
294  return retVal;
295 }
296 
297 extern CONT_ELECTRICAL_STATE_TYPE_e CONT_GetState(uint8_t contactorNumber) {
298  FAS_ASSERT(contactorNumber < BS_NR_OF_CONTACTORS);
299  return (cont_contactorStates[contactorNumber].feedback);
300 }
301 
302 extern void CONT_Initialize(void) {
304 }
305 
306 /*========== Externalized Static Function Implementations (Unit Test) =======*/
307 #ifdef UNITY_UNIT_TEST
308 extern void TEST_CONT_InitializationCheckOfContactorRegistry() {
310 }
311 extern CONT_CONTACTOR_INDEX TEST_CONT_ResolveContactorName(const CONT_NAMES_e name) {
312  return CONT_ResolveContactorName(name);
313 }
314 #endif /* UNITY_UNIT_TEST */
BS_STRING_PRECHARGE_PRESENT_e bs_stringsWithPrecharge[BS_NR_OF_STRINGS]
#define BS_NR_OF_STRINGS
Number of parallel strings in the battery pack.
@ BS_STRING_WITH_PRECHARGE
#define BS_NR_OF_CONTACTORS
CONT_ELECTRICAL_STATE_TYPE_e CONT_GetState(uint8_t contactorNumber)
Gets the current state.
Definition: contactor.c:297
void CONT_CheckFeedback(void)
checks the feedback of the contactors
Definition: contactor.c:222
static void CONT_SetSpsChannelFromContactor(const CONT_CONTACTOR_INDEX contactor)
Sets SPS channels according to contactors.
Definition: contactor.c:130
static CONT_NAMES_e CONT_GetContactorName(const CONT_CONTACTOR_INDEX index)
Gets the contactor name from a contactor index.
Definition: contactor.c:120
static void CONT_InitializationCheckOfContactorRegistry(void)
Definition: contactor.c:146
STD_RETURN_TYPE_e CONT_OpenPrecharge(uint8_t stringNumber)
Opens precharge.
Definition: contactor.c:271
static SPS_CHANNEL_INDEX CONT_GetSpsChannelIndexFromContactor(const CONT_CONTACTOR_INDEX contactor)
Returns the sps channel index from a contactor index.
Definition: contactor.c:125
CONT_ELECTRICAL_STATE_TYPE_e CONT_GetContactorSetValue(const CONT_NAMES_e name)
Gets the latest value the contactors were set to.
Definition: contactor.c:167
STD_RETURN_TYPE_e CONT_SetContactorState(const CONT_NAMES_e name, CONT_ELECTRICAL_STATE_TYPE_e requestedContactorState)
Sets the contactor state to its requested state, if the contactor is at that time not in the requeste...
Definition: contactor.c:193
static CONT_CONTACTOR_INDEX CONT_ResolveContactorName(const CONT_NAMES_e name)
Resolves the contactor index from a contactor name.
Definition: contactor.c:101
STD_RETURN_TYPE_e CONT_CloseString(uint8_t stringNumber)
Closes the contactor of a string.
Definition: contactor.c:227
void CONT_GetContactorFeedback(void)
Reads the feedback pin of every contactor and returns its current value (CONT_SWITCH_OFF/CONT_SWITCH_...
Definition: contactor.c:173
STD_RETURN_TYPE_e CONT_ClosePrecharge(uint8_t stringNumber)
Closes precharge.
Definition: contactor.c:244
void CONT_Initialize(void)
initializes the contactor module
Definition: contactor.c:302
STD_RETURN_TYPE_e CONT_OpenString(uint8_t stringNumber)
Opens the contactor of a string.
Definition: contactor.c:235
Headers for the driver for the contactors.
CONT_CONTACTOR_STATE_s cont_contactorStates[BS_NR_OF_CONTACTORS]
Definition: contactor_cfg.c:63
@ CONT_HAS_NO_FEEDBACK
Definition: contactor_cfg.h:93
@ CONT_FEEDBACK_THROUGH_CURRENT
Definition: contactor_cfg.h:92
@ CONT_FEEDBACK_NORMALLY_OPEN
Definition: contactor_cfg.h:90
uint8_t CONT_CONTACTOR_INDEX
CONT_ELECTRICAL_STATE_TYPE_e
Definition: contactor_cfg.h:71
@ CONT_SWITCH_ON
Definition: contactor_cfg.h:73
@ CONT_SWITCH_OFF
Definition: contactor_cfg.h:72
@ CONT_SWITCH_UNDEF
Definition: contactor_cfg.h:74
CONT_NAMES_e
Definition: contactor_cfg.h:78
#define FAS_ASSERT(x)
Assertion macro that asserts that x is true.
Definition: fassert.h:252
#define FAS_TRAP
Define that evaluates to essential boolean false thus tripping an assert.
Definition: fassert.h:126
#define FAS_STATIC_ASSERT(cond, msg)
Definition: fassert.h:282
STD_RETURN_TYPE_e
Definition: fstd_types.h:81
@ STD_NOT_OK
Definition: fstd_types.h:83
@ STD_OK
Definition: fstd_types.h:82
Headers for the driver for the MCU module.
CONT_ELECTRICAL_STATE_TYPE_e SPS_GetChannelPexFeedback(const SPS_CHANNEL_INDEX channelIndex, bool normallyOpen)
Get the feedback state of a channel.
Definition: sps.c:625
SPS_CHANNEL_AFFILIATION_e SPS_GetChannelAffiliation(SPS_CHANNEL_INDEX channelIndex)
Returns the channel affiliation.
Definition: sps.c:648
CONT_ELECTRICAL_STATE_TYPE_e SPS_GetChannelCurrentFeedback(const SPS_CHANNEL_INDEX channelIndex)
Get feedback value.
Definition: sps.c:609
void SPS_RequestContactorState(SPS_CHANNEL_INDEX channelIndex, SPS_CHANNEL_FUNCTION_e channelFunction)
Request state of a contactor.
Definition: sps.c:597
Headers for the driver for the smart power switches.
@ SPS_CHANNEL_ON
Definition: sps_cfg.h:175
@ SPS_CHANNEL_OFF
Definition: sps_cfg.h:174
uint8_t SPS_CHANNEL_INDEX
Definition: sps_types.h:64
SPS_CHANNEL_AFFILIATION_e
affiliation type of a sps channel
Definition: sps_types.h:72
@ SPS_AFF_CONTACTOR
Definition: sps_types.h:73
CONT_ELECTRICAL_STATE_TYPE_e currentSet
Definition: contactor_cfg.h:98
CONT_ELECTRICAL_STATE_TYPE_e feedback
Definition: contactor_cfg.h:99
const CONT_NAMES_e name
const SPS_CHANNEL_INDEX spsChannel