foxBMS  1.2.0
The foxBMS Battery Management System API Documentation
database.c
Go to the documentation of this file.
1 /**
2  *
3  * @copyright © 2010 - 2021, 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 database.c
44  * @author foxBMS Team
45  * @date 2015-08-18 (date of creation)
46  * @updated 2021-07-23 (date of last update)
47  * @ingroup ENGINE
48  * @prefix DATA
49  *
50  * @brief Database module implementation
51  *
52  * @details Implementation of database module
53  */
54 
55 /*========== Includes =======================================================*/
56 #include "database.h"
57 
58 #include "FreeRTOS.h"
59 #include "queue.h"
60 
61 #include "ftask.h"
62 
63 #include <string.h>
64 
65 /*========== Macros and Definitions =========================================*/
66 /**
67  * Maximum queue timeout time in milliseconds
68  */
69 #define DATA_QUEUE_TIMEOUT_MS ((TickType_t)10u)
70 
71 /**
72  * configuration struct of database device
73  */
74 typedef struct DATA_BASE_HEADER {
75  uint8_t nrDatabaseEntries; /*!< number of database entries */
76  DATA_BASE_s *pDatabase; /*!< pointer to the array with the database entries */
78 
79 /*========== Static Constant and Variable Definitions =======================*/
80 
81 /**
82  * @brief device configuration of database
83  * @details all attributes of device configuration are listed here (pointer to
84  * channel list, number of channels)
85  */
87  .nrDatabaseEntries = sizeof(data_database) / sizeof(DATA_BASE_s), /**< number of blocks (and block headers) */
88  .pDatabase = &data_database[0],
89 };
90 
91 /**
92  * @brief uniqueId to respective database entry selector
93  * @details This array is the link between the uniqueId of a database entry and
94  * the actual position of the database entry in data_database[]
95  */
97 
98 /*========== Extern Constant and Variable Definitions =======================*/
99 
100 /*========== Static Function Prototypes =====================================*/
101 
102 /*========== Static Function Implementations ================================*/
103 
104 /*========== Extern Function Implementations ================================*/
106  STD_RETURN_TYPE_e retval = STD_OK;
107  /* Check that database queue has been created */
109 
110  static_assert((sizeof(data_database) != 0u), "No database defined");
111  /* make sure that no basic assumptions are broken -- since data_database is
112  declared with length DATA_BLOCK_ID_MAX, this assert should never fail */
114  ((sizeof(data_database) / sizeof(DATA_BASE_s)) == (DATA_BLOCK_ID_MAX)), "Database array length error");
115 
116  /* Iterate over database and set respective read/write pointer for each database entry */
117  for (uint16_t i = 0u; i < data_baseHeader.nrDatabaseEntries; i++) {
118  /* Initialize database entry with 0, set write pointer to start of database entry */
119  uint8_t *pStartDatabaseEntryWR = (uint8_t *)data_baseHeader.pDatabase[i].pDatabaseEntry;
120 
121  /* Start after uniqueId entry. Set j'th byte to zero in database entry */
122  for (uint32_t j = 0u; j < (data_baseHeader.pDatabase + i)->datalength; j++) {
123  if (j >= sizeof(DATA_BLOCK_ID_e)) {
124  *pStartDatabaseEntryWR = 0;
125  }
126  pStartDatabaseEntryWR++;
127  }
128  }
129 
130  /* Configure link between uniqueId and database entry array position */
131  for (uint16_t databaseEntry = 0u; databaseEntry < data_baseHeader.nrDatabaseEntries; databaseEntry++) {
132  /* Get pointer to database header entry */
134  /* make sure that the database entry is not a null pointer (which would happen if an entry is missing
135  despite the ID existing) */
136  FAS_ASSERT(pHeader != NULL_PTR);
137  /* Get uniqueId */
138  DATA_BLOCK_ID_e blockId = pHeader->uniqueId;
139  if ((blockId < DATA_BLOCK_ID_MAX) && (databaseEntry < DATA_BLOCK_ID_MAX)) {
140  uniqueIdToDatabaseEntry[blockId] =
141  databaseEntry; /* e.g. uniqueIdToDatabaseEntry[<some id>] = configured database entry index */
142  } else {
143  /* Configuration error -> set retval to #STD_NOT_OK */
144  retval = STD_NOT_OK;
145  }
146  }
147 
148  if (ftsk_databaseQueue == NULL_PTR) {
149  /* Failed to create the queue */
150  retval = STD_NOT_OK;
151  }
152  return retval;
153 }
154 
155 void DATA_Task(void) {
156  DATA_QUEUE_MESSAGE_s receiveMessage;
157 
158  if (ftsk_databaseQueue != NULL_PTR) {
159  if (xQueueReceive(ftsk_databaseQueue, (&receiveMessage), (TickType_t)1) >
160  0) { /* scan queue and wait for a message up to a maximum amount of 1ms (block time) */
161  /* plausibility check, error if first pointer NULL_PTR */
162  FAS_ASSERT(receiveMessage.pDatabaseEntry[0] != NULL_PTR);
163  /* Iterate over pointer array and handle all access operations if pointer != NULL_PTR */
164  for (uint8_t queueEntry = 0u; queueEntry < DATA_MAX_ENTRIES_PER_ACCESS; queueEntry++) {
165  if (receiveMessage.pDatabaseEntry[queueEntry] != NULL_PTR) {
166  /* pointer to passed database struct */
167  void *pPassedDataStruct = receiveMessage.pDatabaseEntry[queueEntry];
168  /* Get access type (read or write) of passed data struct */
169  DATA_BLOCK_ACCESS_TYPE_e accesstype = receiveMessage.accesstype;
170 
171  /* Get pointer to database header entry */
172  DATA_BLOCK_HEADER_s *pHeader1 = (DATA_BLOCK_HEADER_s *)receiveMessage.pDatabaseEntry[queueEntry];
173  uint16_t entryIndex = uniqueIdToDatabaseEntry[(uint16_t)pHeader1->uniqueId];
174  /* Pointer to database struct representation of passed struct */
175  void *pDatabaseStruct = (void *)data_baseHeader.pDatabase[entryIndex].pDatabaseEntry;
176  /* Get datalength of database entry */
177  uint32_t datalength = data_baseHeader.pDatabase[entryIndex].datalength;
178 
179  /* Copy data either into database or passed database struct */
180  if (accesstype == DATA_WRITE_ACCESS) {
181  /* Pointer on datablock header of passed struct */
182  DATA_BLOCK_HEADER_s *pHeader = (DATA_BLOCK_HEADER_s *)pPassedDataStruct;
183  /* Update timestamps in passed database struct and then copy this struct into database */
184  pHeader->previousTimestamp = pHeader->timestamp;
185  pHeader->timestamp = OS_GetTickCount();
186  /* Copy passed struct in database struct */
187  /* memcpy has no return value therefore there is nothing to check: casting to void */
188  (void)memcpy(pDatabaseStruct, pPassedDataStruct, datalength);
189  } else if (accesstype == DATA_READ_ACCESS) {
190  /* Copy database entry in passed struct */
191  /* memcpy has no return value therefore there is nothing to check: casting to void */
192  (void)memcpy(pPassedDataStruct, pDatabaseStruct, datalength);
193  } else {
194  /* invalid database operation */
196  }
197  }
198  }
199  }
200  }
201 }
202 
203 void DATA_DummyFunction(void) {
204 }
205 
206 STD_RETURN_TYPE_e DATA_Read_1_DataBlock(void *pDataToReceiver0) {
207  /* Call write function with maximum number of database entries to prevent duplicated code */
208  return DATA_Read_4_DataBlocks(pDataToReceiver0, NULL_PTR, NULL_PTR, NULL_PTR);
209 }
210 
211 STD_RETURN_TYPE_e DATA_Read_2_DataBlocks(void *pDataToReceiver0, void *pDataToReceiver1) {
212  /* Call write function with maximum number of database entries to prevent duplicated code */
213  return DATA_Read_4_DataBlocks(pDataToReceiver0, pDataToReceiver1, NULL_PTR, NULL_PTR);
214 }
215 
216 STD_RETURN_TYPE_e DATA_Read_3_DataBlocks(void *pDataToReceiver0, void *pDataToReceiver1, void *pDataToReceiver2) {
217  /* Call write function with maximum number of database entries to prevent duplicated code */
218  return DATA_Read_4_DataBlocks(pDataToReceiver0, pDataToReceiver1, pDataToReceiver2, NULL_PTR);
219 }
220 
222  void *pDataToReceiver0,
223  void *pDataToReceiver1,
224  void *pDataToReceiver2,
225  void *pDataToReceiver3) {
226  STD_RETURN_TYPE_e retval = STD_NOT_OK;
227  DATA_QUEUE_MESSAGE_s data_send_msg;
228  TickType_t queuetimeout;
229 
230  queuetimeout = DATA_QUEUE_TIMEOUT_MS / portTICK_RATE_MS;
231  if (queuetimeout == 0) {
232  queuetimeout = 1;
233  }
234 
235  /* prepare send message with attributes of data block */
236  data_send_msg.pDatabaseEntry[0] = pDataToReceiver0;
237  data_send_msg.pDatabaseEntry[1] = pDataToReceiver1;
238  data_send_msg.pDatabaseEntry[2] = pDataToReceiver2;
239  data_send_msg.pDatabaseEntry[3] = pDataToReceiver3;
240  data_send_msg.accesstype = DATA_READ_ACCESS;
241 
242  /* Send a pointer to a message object and */
243  /* maximum block time: queuetimeout */
244  if (pdPASS == xQueueSend(ftsk_databaseQueue, (void *)&data_send_msg, queuetimeout)) {
245  retval = STD_OK;
246  }
247  return retval;
248 }
249 
250 STD_RETURN_TYPE_e DATA_Write_1_DataBlock(void *pDataFromSender0) {
251  /* Call write function with maximum number of database entries to prevent duplicated code */
252  return DATA_Write_4_DataBlocks(pDataFromSender0, NULL_PTR, NULL_PTR, NULL_PTR);
253 }
254 
255 STD_RETURN_TYPE_e DATA_Write_2_DataBlocks(void *pDataFromSender0, void *pDataFromSender1) {
256  /* Call write function with maximum number of database entries to prevent duplicated code */
257  return DATA_Write_4_DataBlocks(pDataFromSender0, pDataFromSender1, NULL_PTR, NULL_PTR);
258 }
259 
260 STD_RETURN_TYPE_e DATA_Write_3_DataBlocks(void *pDataFromSender0, void *pDataFromSender1, void *pDataFromSender2) {
261  /* Call write function with maximum number of database entries to prevent duplicated code */
262  return DATA_Write_4_DataBlocks(pDataFromSender0, pDataFromSender1, pDataFromSender2, NULL_PTR);
263 }
264 
266  void *pDataFromSender0,
267  void *pDataFromSender1,
268  void *pDataFromSender2,
269  void *pDataFromSender3) {
270  STD_RETURN_TYPE_e retval = STD_NOT_OK;
271  DATA_QUEUE_MESSAGE_s data_send_msg;
272  TickType_t queuetimeout;
273 
274  queuetimeout = DATA_QUEUE_TIMEOUT_MS / portTICK_RATE_MS;
275  if (queuetimeout == (TickType_t)0) {
276  queuetimeout = 1;
277  }
278 
279  /* prepare send message with attributes of data block */
280  data_send_msg.pDatabaseEntry[0] = pDataFromSender0;
281  data_send_msg.pDatabaseEntry[1] = pDataFromSender1;
282  data_send_msg.pDatabaseEntry[2] = pDataFromSender2;
283  data_send_msg.pDatabaseEntry[3] = pDataFromSender3;
284 
285  data_send_msg.accesstype = DATA_WRITE_ACCESS;
286  /* Send a pointer to a message object and
287  maximum block time: queuetimeout */
288  if (pdPASS == xQueueSend(ftsk_databaseQueue, (void *)&data_send_msg, queuetimeout)) {
289  retval = STD_OK;
290  }
291  return retval;
292 }
293 
294 extern void DATA_ExecuteDataBIST(void) {
295  /* compile database entry */
297  dummyWriteTable.member1 = UINT8_MAX;
299 
300  /* write entry */
301  STD_RETURN_TYPE_e writeReturnValue = DATA_WRITE_DATA(&dummyWriteTable);
302  FAS_ASSERT(writeReturnValue == STD_OK);
303 
305 
306  /* read entry into new variable */
307  STD_RETURN_TYPE_e readReturnValue = DATA_READ_DATA(&dummyReadTable);
308  FAS_ASSERT(readReturnValue == STD_OK);
309 
310  FAS_ASSERT(dummyReadTable.member1 == dummyWriteTable.member1);
311  FAS_ASSERT(dummyReadTable.member2 == dummyWriteTable.member2);
312 }
313 
314 /*========== Externalized Static Function Implementations (Unit Test) =======*/
STD_RETURN_TYPE_e DATA_Write_4_DataBlocks(void *pDataFromSender0, void *pDataFromSender1, void *pDataFromSender2, void *pDataFromSender3)
Stores a datablock in database.
Definition: database.c:265
void DATA_Task(void)
trigger of database manager
Definition: database.c:155
struct DATA_BASE_HEADER DATA_BASE_HEADER_s
void DATA_DummyFunction(void)
Dummy void function of the database module.
Definition: database.c:203
STD_RETURN_TYPE_e DATA_Read_1_DataBlock(void *pDataToReceiver0)
Reads a datablock in database by value.
Definition: database.c:206
STD_RETURN_TYPE_e DATA_Read_3_DataBlocks(void *pDataToReceiver0, void *pDataToReceiver1, void *pDataToReceiver2)
Reads a datablock in database by value.
Definition: database.c:216
static uint16_t uniqueIdToDatabaseEntry[DATA_BLOCK_ID_MAX]
uniqueId to respective database entry selector
Definition: database.c:96
static const DATA_BASE_HEADER_s data_baseHeader
device configuration of database
Definition: database.c:86
STD_RETURN_TYPE_e DATA_Write_1_DataBlock(void *pDataFromSender0)
Stores a datablock in database.
Definition: database.c:250
void DATA_ExecuteDataBIST(void)
Executes a built-in self-test for the database module.
Definition: database.c:294
STD_RETURN_TYPE_e DATA_Read_2_DataBlocks(void *pDataToReceiver0, void *pDataToReceiver1)
Reads a datablock in database by value.
Definition: database.c:211
#define DATA_QUEUE_TIMEOUT_MS
Definition: database.c:69
STD_RETURN_TYPE_e DATA_Write_3_DataBlocks(void *pDataFromSender0, void *pDataFromSender1, void *pDataFromSender2)
Stores a datablock in database.
Definition: database.c:260
STD_RETURN_TYPE_e DATA_Init(void)
Initialization of database manager.
Definition: database.c:105
STD_RETURN_TYPE_e DATA_Write_2_DataBlocks(void *pDataFromSender0, void *pDataFromSender1)
Stores a datablock in database.
Definition: database.c:255
STD_RETURN_TYPE_e DATA_Read_4_DataBlocks(void *pDataToReceiver0, void *pDataToReceiver1, void *pDataToReceiver2, void *pDataToReceiver3)
Reads a datablock in database by value.
Definition: database.c:221
Database module header.
enum DATA_BLOCK_ACCESS_TYPE DATA_BLOCK_ACCESS_TYPE_e
data block access types (read or write)
@ DATA_READ_ACCESS
Definition: database.h:101
@ DATA_WRITE_ACCESS
Definition: database.h:100
#define DATA_MAX_ENTRIES_PER_ACCESS
Definition: database.h:71
#define DATA_DUMMY_VALUE_UINT8_T_ALTERNATING_BIT_PATTERN
Definition: database.h:105
#define DATA_READ_DATA(...)
Definition: database.h:76
#define DATA_WRITE_DATA(...)
Definition: database.h:86
DATA_BASE_s data_database[]
channel configuration of database (data blocks)
Definition: database_cfg.c:176
enum DATA_BLOCK_ID DATA_BLOCK_ID_e
@ DATA_BLOCK_ID_DUMMY_FOR_SELF_TEST
Definition: database_cfg.h:105
@ DATA_BLOCK_ID_MAX
Definition: database_cfg.h:106
#define FAS_ASSERT(x)
Assertion macro that asserts that x is true.
Definition: fassert.h:237
#define static_assert(cond, msg)
static assertion macro
Definition: fassert.h:252
#define FAS_TRAP
Define that evaluates to essential boolean false thus tripping an assert.
Definition: fassert.h:108
@ STD_NOT_OK
Definition: fstd_types.h:73
@ STD_OK
Definition: fstd_types.h:72
#define NULL_PTR
Null pointer.
Definition: fstd_types.h:66
enum STD_RETURN_TYPE STD_RETURN_TYPE_e
volatile bool ftsk_allQueuesCreated
Definition: ftask.c:166
QueueHandle_t ftsk_databaseQueue
Definition: ftask.c:168
Header of task driver implementation.
uint32_t OS_GetTickCount(void)
Returns OS based system tick value.
Definition: os.c:182
uint8_t nrDatabaseEntries
Definition: database.c:75
DATA_BASE_s * pDatabase
Definition: database.c:76
void * pDatabaseEntry
Definition: database_cfg.h:67
uint32_t datalength
Definition: database_cfg.h:68
DATA_BLOCK_ID_e uniqueId
Definition: database_cfg.h:111
uint32_t timestamp
Definition: database_cfg.h:112
uint32_t previousTimestamp
Definition: database_cfg.h:113
DATA_BLOCK_HEADER_s header
Definition: database_cfg.h:575
DATA_BLOCK_ACCESS_TYPE_e accesstype
Definition: database.h:111
void * pDatabaseEntry[DATA_MAX_ENTRIES_PER_ACCESS]
Definition: database.h:112