8.1.3. How to Use the Database Module¶
This How-to shows how to add new entries to the database, and how to read and write database entries.
8.1.3.1. How to Add a Database Entry?¶
Four steps need to be undertaken to add an entry to the database.
First, an identification number (ID) for this database entry must be added to enum
DATA_BLOCK_ID_e
in file src/app/engine/config/database_cfg.h
. This enumeration
value respectively the identification number functions as uniqueId
for each
database entry to synchronize database entries with local copies during read
and write access to the database.
Note
The new ID must start with DATA_BLOCK_ID_
. Before any source is
compiled the build process checks that a database variable is
initialized with the matching ID from DATA_BLOCK_ID_e
. For the details
of the checker implementation see Checking Database Entries.
In this example the name of the new database entry is example, therefore the
corresponding ID must be the prefix and the name in uppercase, which
gives DATA_BLOCK_ID_EXAMPLE
.
1 2 3 4 5 6 7 8 9 | /** data block identification numbers */
typedef enum DATA_BLOCK_ID {
DATA_BLOCK_ID_EXAMPLE, /**< some example database entry */
/* ...
...
...
*/
DATA_BLOCK_ID_MAX, /**< DO NOT CHANGE, MUST BE THE LAST ENTRY */
} DATA_BLOCK_ID_e;
|
Second, a struct definition of the database entry has to be added in file
src/app/engine/config/database_cfg.h
. This structure needs to contain a variable
header
of type DATA_BLOCK_HEADER_s
at the beginning of the struct. This
header contains a uniqueID
for this database entry as well as timestamps. These
timestamps (timestamp
and previousTimestamp
) are automatically updated each
time new data is stored in this database entry. The remaining struct consists
of all the data needed for the entry.
Note
The new database entry must start with DATA_BLOCK_
. Before any source is
compiled the build process checks that a database variable is
initialized with the matching ID from DATA_BLOCK_ID_e
. For the details
of the checker implementation see Checking Database Entries.
Again, the name of the new database entry is example, therefore the
corresponding data block must be the prefix followed by the name in uppercase and
the _s
suffix as the typedef is a struct, which gives DATA_BLOCK_EXAMPLE_s
.
1 2 3 4 5 6 7 8 9 10 | /**
* data block struct of example
*/
typedef struct DATA_BLOCK_EXAMPLE {
/* This struct needs to be at the beginning of every database entry. During
* the initialization of a database struct, uniqueId must be set to the
* respective database entry representation in enum DATA_BLOCK_ID_e. */
DATA_BLOCK_HEADER_s header;
uint16_t dummyValue;
} DATA_BLOCK_EXAMPLE_s;
|
The database checker basically checks that if a database struct is found (something matching
DATA_BLOCK_(A_Z_0-9)_s
) that it is initialized with a corresponding ID name.
Examples:
Struct |
Id |
DATA_BLOCK_**EXAMPLE**_s |
DATA_BLOCK_ID_**EXAMPLE** |
DATA_BLOCK_**CELL_VOLTAGE**_s |
DATA_BLOCK_ID_**CELL_VOLTAGE** |
Third, in src/app/engine/config/database_cfg.c
, a static variable with
the structure type must be declared. In this declaration the uniqueId
of the
database header must be initialized with the identification number added in the
first step. This structure data_blockExample
contains the actual values of
this database entry during once the BMS is running.
1 | static DATA_BLOCK_EXAMPLE_s data_blockExample = {.header.uniqueId = DATA_BLOCK_ID_EXAMPLE};
|
Last, this declared struct must be linked to the actual database implementation
by adding an additional entry to the structure DATA_BASE_s data_database[]
in file src/app/engine/config/database_cfg.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | /**
* @brief channel configuration of database (data blocks)
* @details all data block managed by database are listed here (address, size,
* consistency type)
*/
DATA_BASE_s data_database[] = {
{
(void*)(&data_blockExample),
sizeof(DATA_BLOCK_EXAMPLE_s)
},
/* ...
...
...
*/
};
|
8.1.3.2. How to Read a Database Entry?¶
Data inside the database can not be accessed directly. The data from a database
entry has to be copied inside a local representation of the requested entry.
For the local structure of the database entry, the uniqueId
of the database
entry header has to be initialized with the identification number of the
requested database entry. Once this is done, a database entry can simply be
accessed by calling function DATA_READ_DATA()
and passing the pointer to
the local database entry structure.
1 2 3 4 | /* Create local structure of database entry */
DATA_BLOCK_EXAMPLE_s tableLocalExampleEntry = { .header.uniqueId = DATA_BLOCK_ID_EXAMPLE };
/* Read data from database entry and update local variable */
DATA_READ_DATA(&tableLocalExampleEntry);
|
Up to four database entries can be accessed on the same time with one call of
DATA_READ_DATA()
.
1 2 3 4 5 6 | DATA_BLOCK_EXAMPLE_0_s tableLocalExampleEntry0 = { .header.uniqueId = DATA_BLOCK_ID_EXAMPLE_0 };
DATA_BLOCK_EXAMPLE_1_s tableLocalExampleEntry1 = { .header.uniqueId = DATA_BLOCK_ID_EXAMPLE_1 };
DATA_BLOCK_EXAMPLE_2_s tableLocalExampleEntry2 = { .header.uniqueId = DATA_BLOCK_ID_EXAMPLE_2 };
DATA_BLOCK_EXAMPLE_3_s tableLocalExampleEntry3 = { .header.uniqueId = DATA_BLOCK_ID_EXAMPLE_3 };
/* Read data from 4 database entries and update local variables */
DATA_READ_DATA(&tableLocalExampleEntry0, &tableLocalExampleEntry1, &tableLocalExampleEntry2, &tableLocalExampleEntry3);
|
8.1.3.3. How to Write a Database Entry?¶
It is not possible to directly write data into a database entry. Only the
content of a local representation of the requested database entry can be copied
into the database. The uniqueId
of the database entry header has to be
initialized with the identification number of the requested database entry for
the local structure of the database entry. Once this is done, a database entry
can be written by calling function DATA_WRITE_DATA()
and passing the
pointer to the local database entry structure. Up to four database entries can
be written with one call of DATA_WRITE_DATA()
.
1 2 3 4 5 6 | /* Create local structure of database entry */
DATA_BLOCK_EXAMPLE_s tableLocalExampleEntry = { .header.uniqueId = DATA_BLOCK_ID_EXAMPLE };
/* Set dummy value to 100 */
tableLocalExampleEntry.dummyValue = 100;
/* Update database entry with changed dummy value */
DATA_WRITE_DATA(&tableLocalExampleEntry);
|
After a call of DATA_WRITE_DATA
the timestamp variables in the database
entry header are automatically updated database entry AND the local
database entry structure.
Up to four database entries can be written on the same time with one call of
DATA_WRITE_DATA()
.
1 2 3 4 5 6 7 8 9 10 11 | DATA_BLOCK_EXAMPLE_0_s tableLocalExampleEntry0 = { .header.uniqueId = DATA_BLOCK_ID_EXAMPLE_0 };
DATA_BLOCK_EXAMPLE_1_s tableLocalExampleEntry1 = { .header.uniqueId = DATA_BLOCK_ID_EXAMPLE_1 };
DATA_BLOCK_EXAMPLE_2_s tableLocalExampleEntry2 = { .header.uniqueId = DATA_BLOCK_ID_EXAMPLE_2 };
DATA_BLOCK_EXAMPLE_3_s tableLocalExampleEntry3 = { .header.uniqueId = DATA_BLOCK_ID_EXAMPLE_3 };
/* Set dummy values to 100 */
tableLocalExampleEntry0.dummyValue = 100;
tableLocalExampleEntry1.dummyValue = 100;
tableLocalExampleEntry2.dummyValue = 100;
tableLocalExampleEntry3.dummyValue = 100;
/* Update database entries with changed dummy values */
DATA_WRITE_DATA(&tableLocalExampleEntry0, &tableLocalExampleEntry1, &tableLocalExampleEntry2, &tableLocalExampleEntry3);
|
8.1.3.4. Further Reading¶
Implementation details of the database module are found in Database Module.