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