General ASAM MDF library.
The MDF reader simply read and parse a Measurement Data File (MDF). The file format is specified by the ASAM standard organisation and an overview of the file format can be found here: ASAM MDF Wiki.
The reader object handles all versions of MDF. The object is either created through the MDFFactory class or simply by declaring the reader. Example of usage below:
#include <mdf/mdfreader.h>
#include <mdf/ichannelgroup.h>
#include <mdf/idatagroup.h>
using namespace mdf;
int main() {
MdfReader reader("c:/mdf/example.mf4"); // Note the file is now open.
// Read all blocks but not the raw data and attachments.
// This reads in the block information into memory.
reader.ReadEverythingButData();
const auto* mdf_file = reader.GetFile(); // Get the file interface.
DataGroupList dg_list; // Get all measurements.
mdf_file->DataGroups(dg_list);
// In this example, we read in all sample data and fetch all values.
for (auto* dg4 : dg_list) {
// Subscribers holds the sample data for a channel.
// You should normally only subscribe on some channels.
// We need a list to hold them.
ChannelObserverList subscriber_list;
const auto cg_list = dg4->ChannelGroups();
for (const auto* cg4 : cg_list ) {
const auto cn_list = cg4->Channels();
for (const auto* cn4 : cn_list) {
// Create a subscriber and add it to the temporary list
auto sub = CreateChannelObserver(*dg4, *cg4, *cn4);
subscriber_list.emplace_back(std::move(sub));
}
}
// Now it is time to read in all samples
reader.ReadData(*dg4); // Read raw data from file
double channel_value = 0.0; // Channel value (no scaling)
double eng_value = 0.0; // Engineering value
for (auto& obs : subscriber_list) {
for (size_t sample = 0; sample < obs->NofSamples(); ++sample) {
const auto channel_valid = obs->GetChannelValue(sample, channel_value);
const auto eng_valid = obs->GetEngValue(sample, eng_value);
// You should do something with data here
}
}
// Not needed in this example as we delete the subscribers,
// but it is good practise to remove samples data from memory
// when it is no longer needed.
dg4->ClearData();
}
reader.Close(); // Close the file
}
When the reader object is created, the file is open and normally the application should do an initial read. Reading from disc may take some time. Therefor the user may choose from 3 types of initial reads.
After the initial read the file may be closed and opened later when reading sample or attachment data.
Embedded attachment data can be extracted by the ExportAttachmentData(). Supply the attachment object and a destination file name.
After the initial read, the channels configuration should be available. Before reading the samples, the user needs to define which channels that should be read. This is done by creating a list of channel subscriptions (ISampleObserver). The subscriber objects are responsible to hold all sample values.
After the subscribers are created, the user normally calls the ReadData(). This call fills the subscriber with sample values. This call may take some time and consume memory.
Reading all samples may take very long time but if the files starts to be bigger than 1 GB, the physical memory for the read may cause out of memory conditions. To solve that problem, only partial read can be performed.
The ReadPartialData() is similar to the ReadData() function but the user needs to supply a min and max sample index. Note that this function still uses the subscribers but just fills the requested samples. This function is much faster that to read all samples with the ReadData() function.
If the user wants to read the sample reduction (SR) data fast without reading the sample data, the ReadSrData() function shall be used.
Big data files typically stores big data arrays of variable length. Typical are bus, video and picture data. These files are typical so large that primary memory cannot store all samples. The ReadVlsdData() solves this problem. It is similar to reading partial data but it operates on VLSD data.
The user must first read in a sample to VLSD offset list. This is done by first setting the channels ReadVlsdData property to false and then read all samples. The channels data now holds the offset into the VLSD byte array. Using the offset list and call the ReadVlsdData() function. Note that user needs the supply callback function that is called for each sample.