Using the Variable Database API
The Variable Database API allows user applications to define variables that are exposed to MaxRT tools and servers.
Variable Databases
The Variable Database library supports up to 64 independent databases, each identified by a unique name.
- Each database has a directory tree structure starting with a root directory.
- The size of each directory is independent, and directories can contain other directories and variables.
- Variables within a parent directory must have unique names.
- The data size of a variable can't exceed 8 bytes.
Special Variables
The library defines two special variables:
- Directory: Points to a sub-directory that needs to be opened. It can't be opened or closed using the variable API. To close the sub-directory, you must end the application that created it.
- Buffer:
- Buffer variables can have a variable length. Instead of receiving a pointer from the database library, the user application provides a pointer to the buffer.
- Buffer should not be stored on the stack or destroyed without being deleted first. This will cause an access violation.
- Always check the validity of the database before accessing buffer variable data.
- Buffer variables are only accessible from real-time programs because Windows does not allow sharing pointers between applications. However, they are visible to Windows applications for passing them to the data logger.
Variable Database Lifetime
The Variable Database library does not manage the lifetime of databases. The user application that creates the database and directories is responsible for keeping them open if they are valid. Any directory that is closed by all applications will lose its content (including all sub-directories and variables).
Data Logger
To enable synchronized logging, real-time applications that create databases must call the background and cyclic process functions to enable the data logging engine.
Client and Database Server Responsibilities
- Client Applications: Trigger the log function to initiate data logging. See RTVDB_TRIGGER_TYPE.
- Database Servers:
- Initialize and release the logging engine using RtvdbLogBackgroundProcess.
- Collect data for logging using RtvdbLogCyclicProcess.
Access Control for Variable Database
RtvdbBrowseDatabases allows applications to browse the list of available databases. This function returns the names and status of each database.
Database Monitoring
Applications that monitor variables, such as the Scope tool, should follow these guidelines:
- Closing Databases: Close a database if the Invalidate flag is set to TRUE.
- Re-browsing Databases: Re-browse the list of databases using RtvdbBrowseDatabases if the TimeStamp has changed. This ensures applications are working with the latest database information.
Handle Management
- The database library maintains individual handle counts for each variable.
- Directories also track the total number of opened variables within them.
Database Locking
- Each database uses a lock to prevent concurrent manipulation during operations like open, close, create, and delete.
- The delete function checks for any open handles on the variable, directory, or its sub-objects before allowing deletion.
- If the object is in use, the Invalidate flag is set, and the delete call waits for all handles to be closed before proceeding.
Examples
Create Variables
INT Succeeded = ERROR_SUCCESS;
RTVDB_DATABASE Database = NULL;
RTVDB_DIRECTORY Root = NULL;
RTVDB_DIRECTORY Directory = NULL;
RTVDB_VARIABLE_DESCRIPTION VarDesc = { 0 };
RTVDB_VARIABLE_CONTROL Variable = { 0 };
RTVDB_VARIABLE_CONTROL Buffer = { 0 };
byte BufferData[8] = { 0 };
// Create database and variables
Succeeded = RtvdbInitialize();
Succeeded = RtvdbCreateDatabase(&Database, &Root, L"MyDb", 10);
wcscpy(VarDesc.Name, L"MyVar");
VarDesc.DataType = VarBool;
Succeeded = RtvdbCreateVariable(Root, &Variable, VarDesc);
Succeeded = RtvdbCreateBuffer(Root, &Buffer, L"MyBuffer", BufferData, 8);
// Map to local variables
BOOL* BoolVariable = (BOOL*)Variable.pValue;
byte* BufferVariable = (byte*)Buffer.pValue;
// Use variables
*BoolVariable = TRUE;
BufferVariable[0] = 1;
BufferVariable[2] = 2;
BufferVariable[4] = 3;
BufferVariable[7] = 4;
// Delete database
Succeeded = RtvdbDeleteDatabase(Database, TRUE, FALSE, 0);
Succeeded = RtvdbRelease(TRUE);
Monitor Variables
INT Succeeded = ERROR_SUCCESS;
RTVDB_DATABASE Database = NULL;
RTVDB_DIRECTORY Root = NULL;
RTVDB_DIRECTORY Directory = NULL;
RTVDB_VARIABLE_CONTROL Variable = { 0 };
RTVDB_VARIABLE_CONTROL Buffer = { 0 };
ULONG Count = 0;
ULONG Size = 0;
// Browse database
Succeeded = RtvdbInitialize();
// Get database count
Succeeded = RtvdbBrowseDatabases(0, &Count, NULL);
RTVDB_DATABASE_DESCRIPTION* pDatabases = (RTVDB_DATABASE_DESCRIPTION*)malloc(Count * sizeof(RTVDB_DATABASE_DESCRIPTION));
// Get database list
Succeeded = RtvdbBrowseDatabases(Count, &Count, pDatabases);
// Open first database
Succeeded = RtvdbOpenDatabase(&Database, &Root, pDatabases[0].Name, &Size);
free(pDatabases);
// Get root variables count
Succeeded = RtvdbBrowseDirectory(Root, 0, &Count, NULL);
RTVDB_VARIABLE_DESCRIPTION* pVariables = (RTVDB_VARIABLE_DESCRIPTION*)malloc(Count * sizeof(RTVDB_VARIABLE_DESCRIPTION));
// Get tool variables list
Succeeded = RtvdbBrowseDirectory(Root, Count, &Count, pVariables);
// Open variables
Succeeded = RtvdbOpenVariable(Root, &Variable, pVariables[0]);
Succeeded = RtvdbOpenVariable(Root, &Buffer, pVariables[1]);
// Access variables
BOOL* BoolVariable = (BOOL*)Variable.pValue;
byte* BufferVariable = (byte*)Buffer.pValue;
// Close database
Succeeded = RtvdbCloseDatabase(Database, TRUE);
Succeeded = RtvdbRelease(TRUE);
Log Data
INT Succeeded = ERROR_SUCCESS;
RTVDB_DATABASE Database = NULL;
RTVDB_DIRECTORY Root = NULL;
RTVDB_DIRECTORY Directory = NULL;
RTVDB_VARIABLE_CONTROL Variable = { 0 };
RTVDB_VARIABLE_CONTROL Buffer = { 0 };
ULONG Count = 0;
ULONG Size = 0;
// Browse database
Succeeded = RtvdbInitialize();
// Get database count
Succeeded = RtvdbBrowseDatabases(0, &Count, NULL);
RTVDB_DATABASE_DESCRIPTION* pDatabases = (RTVDB_DATABASE_DESCRIPTION*)malloc(Count * sizeof(RTVDB_DATABASE_DESCRIPTION));
// Get database list
Succeeded = RtvdbBrowseDatabases(Count, &Count, pDatabases);
// Open first database
Succeeded = RtvdbOpenDatabase(&Database, &Root, pDatabases[0].Name, &Size);
free(pDatabases);
// Get root variables count
Succeeded = RtvdbBrowseDirectory(Root, 0, &Count, NULL);
RTVDB_VARIABLE_DESCRIPTION* pVariables = (RTVDB_VARIABLE_DESCRIPTION*)malloc(Count * sizeof(RTVDB_VARIABLE_DESCRIPTION));
// Get tool variables list
Succeeded = RtvdbBrowseDirectory(Root, Count, &Count, pVariables);
// Open variables
Succeeded = RtvdbOpenVariable(Root, &Variable, pVariables[0]);
Succeeded = RtvdbOpenVariable(Root, &Buffer, pVariables[1]);
// Log variables
RTVDB_CHANNEL Channels[2] = { 0 };
Channels[0].Variable = Variable.Variable;
Channels[1].Variable = Buffer.Variable;
Channels[1].DataType = VarInt32;
Channels[1].Offset = 1;
RTVDB_TRIGGER Trigger = { 0, LogImmediately, 0 };
Succeeded = RtvdbStartLog(2, Channels, Trigger, 0.1, 0);
// Wait for log to finish
Sleep(200);
// Check Status
RTVDB_LOG_STATUS LogStatus;
ULONG LogSize = 0;
ULONG LogIndex = 0;
Succeeded = RtvdbGetLogStatus(&LogStatus, &LogSize, &LogIndex);
// Read log data
RTVDB_POINT Points[100] = { 0 };
ULONG ReadLength = 0;
LONGLONG FirstPointTimeStamp = 0;
ULONG PeriodUs = 0;
Succeeded = RtvdbGetLogData(100, Points, 0, &ReadLength, &FirstPointTimeStamp, &PeriodUs);
// Close database
Succeeded = RtvdbCloseDatabase(Database, TRUE);
Succeeded = RtvdbRelease(TRUE);