Example of the Config File#

A Config File contains a configuration of a system in a TOML-like structure.

[Configuration]
Version = 100

[[Component]]
Path = "module_example.sdv"
Class = "class_example"
Name = "object_name_example"
[Component.Parameters]
updatableValue = 13
Message = "It's me"
Id = 42
Pi = 3.1415926
Boolean = true
Array = [ 1, 2, 3 , 5 , 7, 11, 13, 17 ]
Table = { a = 77, b = 1.2, c = "das ist ein string" }
[Configuration]
Version = 100

[[Component]]
Path = "module_example.sdv"
Class = "class_example"
Name = "object_name_example"
[Component.Parameters]
updatableValue = 13
Message = "It's me"
Id = 42
Pi = 3.1415926
Boolean = true
Array = [ 1, 2, 3 , 5 , 7, 11, 13, 17 ]
Table = { a = 77, b = 1.2, c = "das ist ein string" }

A Config File must contain a version information.

[Configuration]
Version = 100

[[Component]]
Path = "module_example.sdv"
Class = "class_example"
Name = "object_name_example"
[Component.Parameters]
updatableValue = 13
Message = "It's me"
Id = 42
Pi = 3.1415926
Boolean = true
Array = [ 1, 2, 3 , 5 , 7, 11, 13, 17 ]
Table = { a = 77, b = 1.2, c = "das ist ein string" }

To load a VAPI Component the path/name to the binary file and the class name is required.

[Configuration]
Version = 100

[[Component]]
Path = "module_example.sdv"
Class = "class_example"
Name = "object_name_example"
[Component.Parameters]
updatableValue = 13
Message = "It's me"
Id = 42
Pi = 3.1415926
Boolean = true
Array = [ 1, 2, 3 , 5 , 7, 11, 13, 17 ]
Table = { a = 77, b = 1.2, c = "das ist ein string" }

The object name is optional. With that multiple VAPI Component s of the same class can be created.

[Configuration]
Version = 100

[[Component]]
Path = "module_example.sdv"
Class = "class_example"
Name = "object_name_example"
[Component.Parameters]
updatableValue = 13
Message = "It's me"
Id = 42
Pi = 3.1415926
Boolean = true
Array = [ 1, 2, 3 , 5 , 7, 11, 13, 17 ]
Table = { a = 77, b = 1.2, c = "das ist ein string" }

The component can have a parameter map. If the variable name fits the variable is directly updated and no parsing is required. Here the variable ‘updatableValue’ is updated, the other variable in the map is not touched.

[Configuration]
Version = 100

[[Component]]
Path = "module_example.sdv"
Class = "class_example"
Name = "object_name_example"
[Component.Parameters]
updatableValue = 13
Message = "It's me"
Id = 42
Pi = 3.1415926
Boolean = true
Array = [ 1, 2, 3 , 5 , 7, 11, 13, 17 ]
Table = { a = 77, b = 1.2, c = "das ist ein string" }

The rest are user defined variables of any type including arrays and further tables. With that any data could be in the configuration file

Setting one or more folders for the modules:

sdv::app::CAppControl appcontrol;
auto bResult = appcontrol.AddModuleSearchDir("../../tests/bin");
bResult &= appcontrol.AddModuleSearchDir("../../bin"); // even more can be added

Setting one or more folders for the config files:

appcontrol.SetConfigMode();
bResult &= appcontrol.AddConfigSearchDir("ApplicationConfigFiles");
bResult &= appcontrol.AddConfigSearchDir("ServiceConfigFiles"); // even more can be added

Following shows how to parse the configuration example above.

#include <iostream>
#include <support/component_impl.h>
#include <support/toml.h>

class DemoConfigurationComponent : public sdv::CSdvObject
{
public:
    DECLARE_OBJECT_CLASS_TYPE(sdv::EObjectType::device)
    DECLARE_OBJECT_CLASS_NAME("Configuration_Example")

    // Parameter map
    BEGIN_SDV_PARAM_MAP()
        SDV_PARAM_ENABLE_LOCKING()          //  optional, if the parameter should be updatable
        SDV_PARAM_ENTRY(m_InitializedValue, "initializedValue", 7, "km/h", "Description for an initialized parameter.")
        SDV_PARAM_ENTRY(m_UpdatableValue,   "updatableValue",   7, "m/s", "Description for an updatable parameter.")
    END_SDV_PARAM_MAP()

    /**
     * @brief Initialization event, called after object configuration was loaded. Overload of sdv::CSdvObject::OnInitialize.
     * @return Returns 'true' when the initialization was successful, 'false' when not.
     */
    virtual bool OnInitialize() override
    {
        try
        {
            sdv::toml::CTOMLParser config(GetObjectConfig());

            sdv::toml::CNode messageNode = config.GetDirect("Message");
            if (messageNode.GetType() == sdv::toml::ENodeType::node_string)
            {
                m_Message = static_cast<std::string>(messageNode.GetValue());
            }
            
            sdv::toml::CNode jsonNode = config.GetDirect("JSONConfig");
            if (jsonNode.GetType() == sdv::toml::ENodeType::node_string)
            {
                m_JSONConfig = static_cast<std::string>(jsonNode.GetValue());
            }
            
            sdv::toml::CNode idNode = config.GetDirect("Id");
            if (idNode.GetType() == sdv::toml::ENodeType::node_integer)
            {
                m_Id = static_cast<int32_t>(idNode.GetValue());
            }

            sdv::toml::CNode floatNode = config.GetDirect("Pi");
            if (floatNode.GetType() == sdv::toml::ENodeType::node_floating_point)
            {
                m_Pi = static_cast<float>(floatNode.GetValue());
            }

            sdv::toml::CNode boolNode = config.GetDirect("Boolean");
            if (boolNode.GetType() == sdv::toml::ENodeType::node_boolean)
            {
                m_IsValid = static_cast<bool>(boolNode.GetValue());
            }

            sdv::toml::CNodeCollection arrayNodes = config.GetDirect("Array");
            if (arrayNodes.GetType() == sdv::toml::ENodeType::node_array)
            {
                for (size_t nIndex = 0; nIndex < arrayNodes.GetCount(); nIndex++)
                {
                    sdv::toml::CNode node = arrayNodes[nIndex];
                    if (node.GetType() == sdv::toml::ENodeType::node_integer)
                    {
                        m_Counters.push_back(static_cast<uint32_t>(node.GetValue()));
                    }
                }
            }

            sdv::toml::CNodeCollection tableNodes = config.GetDirect("Table");
            if (tableNodes.GetType() == sdv::toml::ENodeType::node_table)
            {
                if (tableNodes.GetCount() >= 3)
                {
                    m_TableA = static_cast<uint32_t>(tableNodes[0].GetValue());
                    m_TableB = static_cast<float>(tableNodes[1].GetValue());
                    m_TableC = static_cast<std::string>(tableNodes[2].GetValue());
                }
            }

            auto table_a = config.GetDirect("Table.a");
            auto table_b = config.GetDirect("Table.b");
            auto table_c = config.GetDirect("Table.c");
            m_DirectTableA = static_cast<uint32_t>(table_a.GetValue());
            m_DirectTableB = static_cast<float>(table_b.GetValue());
            m_DirectTableC = static_cast<std::string>(table_c.GetValue());

        }
        catch (const sdv::toml::XTOMLParseException& e)
        {
            SDV_LOG_ERROR("Parsing error: ", e.what());

            return false;
        }

        PrintAllVariables();

        return true;
    };

    /**
     * @brief Shutdown the object. Overload of sdv::CSdvObject::OnShutdown.
     */
    virtual void OnShutdown() override
    {}

    /**
    * @brief Print all global variables to console
    */
    void PrintAllVariables()  const
    {
        std::cout << "\n----------\nValues from the parameter map:" << std::endl;        
        std::cout << "Expected 7, got " << "initialized value - not changed, not in configuration file: " << std::to_string(m_InitializedValue) << std::endl;          
        std::cout << "Expected 13, got " << "updated value - changed, found in configuration file: " << std::to_string(m_UpdatableValue) << std::endl;
        std::cout << "\n----------\nValues parsed during initialization:" << std::endl;
        std::cout << "Expected 'It's me', got " << "string: " << m_Message.c_str() << std::endl;
        std::cout << "multiline string: " << m_JSONConfig.c_str() << std::endl;
        std::cout << "Expected 42, got " << "integer: " << std::to_string(m_Id) << std::endl;
        std::cout << "Expected 3.141593, got " << "float: " << std::to_string(m_Pi) << std::endl;
        std::cout << "Expected 1, got " << "bool: " << std::to_string(m_IsValid) << std::endl;
        std::cout << "Expected 77, got " << "table column a: " << std::to_string(m_TableA) << "     " << std::to_string(m_DirectTableA) << std::endl;
        std::cout << "Expected 1.200000, got " << "table column b: " << std::to_string(m_TableB) << "     " << std::to_string(m_DirectTableB) << std::endl;
        std::cout << "Expected 'this is a string', got " << "table column c: " << m_TableC.c_str() << "     " << m_DirectTableC.c_str() << std::endl;
        for (auto counter : m_Counters)
        {
            std::cout << std::to_string(counter) << ", ";
        }
        std::cout << std::endl;
    }

  private:
    std::string           m_Message { "" };
    std::string           m_JSONConfig { "" };
    int32_t               m_Id { -1 };
    float                 m_Pi { 0.0 };
    bool                  m_IsValid { false };
    std::vector<uint32_t> m_Counters{};
    uint32_t              m_TableA { 0 };
    float                 m_TableB { 0.0 };
    std::string           m_TableC { "" };
    uint32_t              m_DirectTableA { 0 };
    float                 m_DirectTableB { 0.0 };
    std::string           m_DirectTableC { "" };
    uint32_t              m_InitializedValue { 0 };
    uint32_t              m_UpdatableValue { 0 }; 
};

DEFINE_SDV_OBJECT(DemoConfigurationComponent)
#include <iostream>
#include <support/component_impl.h>
#include <support/toml.h>

class DemoConfigurationComponent : public sdv::CSdvObject
{
public:
    DECLARE_OBJECT_CLASS_TYPE(sdv::EObjectType::device)
    DECLARE_OBJECT_CLASS_NAME("Configuration_Example")

    // Parameter map
    BEGIN_SDV_PARAM_MAP()
        SDV_PARAM_ENABLE_LOCKING()          //  optional, if the parameter should be updatable
        SDV_PARAM_ENTRY(m_InitializedValue, "initializedValue", 7, "km/h", "Description for an initialized parameter.")
        SDV_PARAM_ENTRY(m_UpdatableValue,   "updatableValue",   7, "m/s", "Description for an updatable parameter.")
    END_SDV_PARAM_MAP()

    /**
     * @brief Initialization event, called after object configuration was loaded. Overload of sdv::CSdvObject::OnInitialize.
     * @return Returns 'true' when the initialization was successful, 'false' when not.
     */
    virtual bool OnInitialize() override
    {
        try
        {
            sdv::toml::CTOMLParser config(GetObjectConfig());

            sdv::toml::CNode messageNode = config.GetDirect("Message");
            if (messageNode.GetType() == sdv::toml::ENodeType::node_string)
            {
                m_Message = static_cast<std::string>(messageNode.GetValue());
            }
            
            sdv::toml::CNode jsonNode = config.GetDirect("JSONConfig");
            if (jsonNode.GetType() == sdv::toml::ENodeType::node_string)
            {
                m_JSONConfig = static_cast<std::string>(jsonNode.GetValue());
            }
            
            sdv::toml::CNode idNode = config.GetDirect("Id");
            if (idNode.GetType() == sdv::toml::ENodeType::node_integer)
            {
                m_Id = static_cast<int32_t>(idNode.GetValue());
            }

            sdv::toml::CNode floatNode = config.GetDirect("Pi");
            if (floatNode.GetType() == sdv::toml::ENodeType::node_floating_point)
            {
                m_Pi = static_cast<float>(floatNode.GetValue());
            }

            sdv::toml::CNode boolNode = config.GetDirect("Boolean");
            if (boolNode.GetType() == sdv::toml::ENodeType::node_boolean)
            {
                m_IsValid = static_cast<bool>(boolNode.GetValue());
            }

            sdv::toml::CNodeCollection arrayNodes = config.GetDirect("Array");
            if (arrayNodes.GetType() == sdv::toml::ENodeType::node_array)
            {
                for (size_t nIndex = 0; nIndex < arrayNodes.GetCount(); nIndex++)
                {
                    sdv::toml::CNode node = arrayNodes[nIndex];
                    if (node.GetType() == sdv::toml::ENodeType::node_integer)
                    {
                        m_Counters.push_back(static_cast<uint32_t>(node.GetValue()));
                    }
                }
            }

            sdv::toml::CNodeCollection tableNodes = config.GetDirect("Table");
            if (tableNodes.GetType() == sdv::toml::ENodeType::node_table)
            {
                if (tableNodes.GetCount() >= 3)
                {
                    m_TableA = static_cast<uint32_t>(tableNodes[0].GetValue());
                    m_TableB = static_cast<float>(tableNodes[1].GetValue());
                    m_TableC = static_cast<std::string>(tableNodes[2].GetValue());
                }
            }

            auto table_a = config.GetDirect("Table.a");
            auto table_b = config.GetDirect("Table.b");
            auto table_c = config.GetDirect("Table.c");
            m_DirectTableA = static_cast<uint32_t>(table_a.GetValue());
            m_DirectTableB = static_cast<float>(table_b.GetValue());
            m_DirectTableC = static_cast<std::string>(table_c.GetValue());

        }
        catch (const sdv::toml::XTOMLParseException& e)
        {
            SDV_LOG_ERROR("Parsing error: ", e.what());

            return false;
        }

        PrintAllVariables();

        return true;
    };

    /**
     * @brief Shutdown the object. Overload of sdv::CSdvObject::OnShutdown.
     */
    virtual void OnShutdown() override
    {}

    /**
    * @brief Print all global variables to console
    */
    void PrintAllVariables()  const
    {
        std::cout << "\n----------\nValues from the parameter map:" << std::endl;        
        std::cout << "Expected 7, got " << "initialized value - not changed, not in configuration file: " << std::to_string(m_InitializedValue) << std::endl;          
        std::cout << "Expected 13, got " << "updated value - changed, found in configuration file: " << std::to_string(m_UpdatableValue) << std::endl;
        std::cout << "\n----------\nValues parsed during initialization:" << std::endl;
        std::cout << "Expected 'It's me', got " << "string: " << m_Message.c_str() << std::endl;
        std::cout << "multiline string: " << m_JSONConfig.c_str() << std::endl;
        std::cout << "Expected 42, got " << "integer: " << std::to_string(m_Id) << std::endl;
        std::cout << "Expected 3.141593, got " << "float: " << std::to_string(m_Pi) << std::endl;
        std::cout << "Expected 1, got " << "bool: " << std::to_string(m_IsValid) << std::endl;
        std::cout << "Expected 77, got " << "table column a: " << std::to_string(m_TableA) << "     " << std::to_string(m_DirectTableA) << std::endl;
        std::cout << "Expected 1.200000, got " << "table column b: " << std::to_string(m_TableB) << "     " << std::to_string(m_DirectTableB) << std::endl;
        std::cout << "Expected 'this is a string', got " << "table column c: " << m_TableC.c_str() << "     " << m_DirectTableC.c_str() << std::endl;
        for (auto counter : m_Counters)
        {
            std::cout << std::to_string(counter) << ", ";
        }
        std::cout << std::endl;
    }

  private:
    std::string           m_Message { "" };
    std::string           m_JSONConfig { "" };
    int32_t               m_Id { -1 };
    float                 m_Pi { 0.0 };
    bool                  m_IsValid { false };
    std::vector<uint32_t> m_Counters{};
    uint32_t              m_TableA { 0 };
    float                 m_TableB { 0.0 };
    std::string           m_TableC { "" };
    uint32_t              m_DirectTableA { 0 };
    float                 m_DirectTableB { 0.0 };
    std::string           m_DirectTableC { "" };
    uint32_t              m_InitializedValue { 0 };
    uint32_t              m_UpdatableValue { 0 }; 
};

DEFINE_SDV_OBJECT(DemoConfigurationComponent)

With a parameter map variables can already be defined. If allowed, then these variables can be automatically be updated, no parsing of the configuration file necessary.

#include <iostream>
#include <support/component_impl.h>
#include <support/toml.h>

class DemoConfigurationComponent : public sdv::CSdvObject
{
public:
    DECLARE_OBJECT_CLASS_TYPE(sdv::EObjectType::device)
    DECLARE_OBJECT_CLASS_NAME("Configuration_Example")

    // Parameter map
    BEGIN_SDV_PARAM_MAP()
        SDV_PARAM_ENABLE_LOCKING()          //  optional, if the parameter should be updatable
        SDV_PARAM_ENTRY(m_InitializedValue, "initializedValue", 7, "km/h", "Description for an initialized parameter.")
        SDV_PARAM_ENTRY(m_UpdatableValue,   "updatableValue",   7, "m/s", "Description for an updatable parameter.")
    END_SDV_PARAM_MAP()

    /**
     * @brief Initialization event, called after object configuration was loaded. Overload of sdv::CSdvObject::OnInitialize.
     * @return Returns 'true' when the initialization was successful, 'false' when not.
     */
    virtual bool OnInitialize() override
    {
        try
        {
            sdv::toml::CTOMLParser config(GetObjectConfig());

            sdv::toml::CNode messageNode = config.GetDirect("Message");
            if (messageNode.GetType() == sdv::toml::ENodeType::node_string)
            {
                m_Message = static_cast<std::string>(messageNode.GetValue());
            }
            
            sdv::toml::CNode jsonNode = config.GetDirect("JSONConfig");
            if (jsonNode.GetType() == sdv::toml::ENodeType::node_string)
            {
                m_JSONConfig = static_cast<std::string>(jsonNode.GetValue());
            }
            
            sdv::toml::CNode idNode = config.GetDirect("Id");
            if (idNode.GetType() == sdv::toml::ENodeType::node_integer)
            {
                m_Id = static_cast<int32_t>(idNode.GetValue());
            }

            sdv::toml::CNode floatNode = config.GetDirect("Pi");
            if (floatNode.GetType() == sdv::toml::ENodeType::node_floating_point)
            {
                m_Pi = static_cast<float>(floatNode.GetValue());
            }

            sdv::toml::CNode boolNode = config.GetDirect("Boolean");
            if (boolNode.GetType() == sdv::toml::ENodeType::node_boolean)
            {
                m_IsValid = static_cast<bool>(boolNode.GetValue());
            }

            sdv::toml::CNodeCollection arrayNodes = config.GetDirect("Array");
            if (arrayNodes.GetType() == sdv::toml::ENodeType::node_array)
            {
                for (size_t nIndex = 0; nIndex < arrayNodes.GetCount(); nIndex++)
                {
                    sdv::toml::CNode node = arrayNodes[nIndex];
                    if (node.GetType() == sdv::toml::ENodeType::node_integer)
                    {
                        m_Counters.push_back(static_cast<uint32_t>(node.GetValue()));
                    }
                }
            }

            sdv::toml::CNodeCollection tableNodes = config.GetDirect("Table");
            if (tableNodes.GetType() == sdv::toml::ENodeType::node_table)
            {
                if (tableNodes.GetCount() >= 3)
                {
                    m_TableA = static_cast<uint32_t>(tableNodes[0].GetValue());
                    m_TableB = static_cast<float>(tableNodes[1].GetValue());
                    m_TableC = static_cast<std::string>(tableNodes[2].GetValue());
                }
            }

            auto table_a = config.GetDirect("Table.a");
            auto table_b = config.GetDirect("Table.b");
            auto table_c = config.GetDirect("Table.c");
            m_DirectTableA = static_cast<uint32_t>(table_a.GetValue());
            m_DirectTableB = static_cast<float>(table_b.GetValue());
            m_DirectTableC = static_cast<std::string>(table_c.GetValue());

        }
        catch (const sdv::toml::XTOMLParseException& e)
        {
            SDV_LOG_ERROR("Parsing error: ", e.what());

            return false;
        }

        PrintAllVariables();

        return true;
    };

    /**
     * @brief Shutdown the object. Overload of sdv::CSdvObject::OnShutdown.
     */
    virtual void OnShutdown() override
    {}

    /**
    * @brief Print all global variables to console
    */
    void PrintAllVariables()  const
    {
        std::cout << "\n----------\nValues from the parameter map:" << std::endl;        
        std::cout << "Expected 7, got " << "initialized value - not changed, not in configuration file: " << std::to_string(m_InitializedValue) << std::endl;          
        std::cout << "Expected 13, got " << "updated value - changed, found in configuration file: " << std::to_string(m_UpdatableValue) << std::endl;
        std::cout << "\n----------\nValues parsed during initialization:" << std::endl;
        std::cout << "Expected 'It's me', got " << "string: " << m_Message.c_str() << std::endl;
        std::cout << "multiline string: " << m_JSONConfig.c_str() << std::endl;
        std::cout << "Expected 42, got " << "integer: " << std::to_string(m_Id) << std::endl;
        std::cout << "Expected 3.141593, got " << "float: " << std::to_string(m_Pi) << std::endl;
        std::cout << "Expected 1, got " << "bool: " << std::to_string(m_IsValid) << std::endl;
        std::cout << "Expected 77, got " << "table column a: " << std::to_string(m_TableA) << "     " << std::to_string(m_DirectTableA) << std::endl;
        std::cout << "Expected 1.200000, got " << "table column b: " << std::to_string(m_TableB) << "     " << std::to_string(m_DirectTableB) << std::endl;
        std::cout << "Expected 'this is a string', got " << "table column c: " << m_TableC.c_str() << "     " << m_DirectTableC.c_str() << std::endl;
        for (auto counter : m_Counters)
        {
            std::cout << std::to_string(counter) << ", ";
        }
        std::cout << std::endl;
    }

  private:
    std::string           m_Message { "" };
    std::string           m_JSONConfig { "" };
    int32_t               m_Id { -1 };
    float                 m_Pi { 0.0 };
    bool                  m_IsValid { false };
    std::vector<uint32_t> m_Counters{};
    uint32_t              m_TableA { 0 };
    float                 m_TableB { 0.0 };
    std::string           m_TableC { "" };
    uint32_t              m_DirectTableA { 0 };
    float                 m_DirectTableB { 0.0 };
    std::string           m_DirectTableC { "" };
    uint32_t              m_InitializedValue { 0 };
    uint32_t              m_UpdatableValue { 0 }; 
};

DEFINE_SDV_OBJECT(DemoConfigurationComponent)

The access to the variables is very easy with the sdv::toml::CTOMLParser. Just get direct access, validate the data type and get the value.

#include <iostream>
#include <support/component_impl.h>
#include <support/toml.h>

class DemoConfigurationComponent : public sdv::CSdvObject
{
public:
    DECLARE_OBJECT_CLASS_TYPE(sdv::EObjectType::device)
    DECLARE_OBJECT_CLASS_NAME("Configuration_Example")

    // Parameter map
    BEGIN_SDV_PARAM_MAP()
        SDV_PARAM_ENABLE_LOCKING()          //  optional, if the parameter should be updatable
        SDV_PARAM_ENTRY(m_InitializedValue, "initializedValue", 7, "km/h", "Description for an initialized parameter.")
        SDV_PARAM_ENTRY(m_UpdatableValue,   "updatableValue",   7, "m/s", "Description for an updatable parameter.")
    END_SDV_PARAM_MAP()

    /**
     * @brief Initialization event, called after object configuration was loaded. Overload of sdv::CSdvObject::OnInitialize.
     * @return Returns 'true' when the initialization was successful, 'false' when not.
     */
    virtual bool OnInitialize() override
    {
        try
        {
            sdv::toml::CTOMLParser config(GetObjectConfig());

            sdv::toml::CNode messageNode = config.GetDirect("Message");
            if (messageNode.GetType() == sdv::toml::ENodeType::node_string)
            {
                m_Message = static_cast<std::string>(messageNode.GetValue());
            }
            
            sdv::toml::CNode jsonNode = config.GetDirect("JSONConfig");
            if (jsonNode.GetType() == sdv::toml::ENodeType::node_string)
            {
                m_JSONConfig = static_cast<std::string>(jsonNode.GetValue());
            }
            
            sdv::toml::CNode idNode = config.GetDirect("Id");
            if (idNode.GetType() == sdv::toml::ENodeType::node_integer)
            {
                m_Id = static_cast<int32_t>(idNode.GetValue());
            }

            sdv::toml::CNode floatNode = config.GetDirect("Pi");
            if (floatNode.GetType() == sdv::toml::ENodeType::node_floating_point)
            {
                m_Pi = static_cast<float>(floatNode.GetValue());
            }

            sdv::toml::CNode boolNode = config.GetDirect("Boolean");
            if (boolNode.GetType() == sdv::toml::ENodeType::node_boolean)
            {
                m_IsValid = static_cast<bool>(boolNode.GetValue());
            }

            sdv::toml::CNodeCollection arrayNodes = config.GetDirect("Array");
            if (arrayNodes.GetType() == sdv::toml::ENodeType::node_array)
            {
                for (size_t nIndex = 0; nIndex < arrayNodes.GetCount(); nIndex++)
                {
                    sdv::toml::CNode node = arrayNodes[nIndex];
                    if (node.GetType() == sdv::toml::ENodeType::node_integer)
                    {
                        m_Counters.push_back(static_cast<uint32_t>(node.GetValue()));
                    }
                }
            }

            sdv::toml::CNodeCollection tableNodes = config.GetDirect("Table");
            if (tableNodes.GetType() == sdv::toml::ENodeType::node_table)
            {
                if (tableNodes.GetCount() >= 3)
                {
                    m_TableA = static_cast<uint32_t>(tableNodes[0].GetValue());
                    m_TableB = static_cast<float>(tableNodes[1].GetValue());
                    m_TableC = static_cast<std::string>(tableNodes[2].GetValue());
                }
            }

            auto table_a = config.GetDirect("Table.a");
            auto table_b = config.GetDirect("Table.b");
            auto table_c = config.GetDirect("Table.c");
            m_DirectTableA = static_cast<uint32_t>(table_a.GetValue());
            m_DirectTableB = static_cast<float>(table_b.GetValue());
            m_DirectTableC = static_cast<std::string>(table_c.GetValue());

        }
        catch (const sdv::toml::XTOMLParseException& e)
        {
            SDV_LOG_ERROR("Parsing error: ", e.what());

            return false;
        }

        PrintAllVariables();

        return true;
    };

    /**
     * @brief Shutdown the object. Overload of sdv::CSdvObject::OnShutdown.
     */
    virtual void OnShutdown() override
    {}

    /**
    * @brief Print all global variables to console
    */
    void PrintAllVariables()  const
    {
        std::cout << "\n----------\nValues from the parameter map:" << std::endl;        
        std::cout << "Expected 7, got " << "initialized value - not changed, not in configuration file: " << std::to_string(m_InitializedValue) << std::endl;          
        std::cout << "Expected 13, got " << "updated value - changed, found in configuration file: " << std::to_string(m_UpdatableValue) << std::endl;
        std::cout << "\n----------\nValues parsed during initialization:" << std::endl;
        std::cout << "Expected 'It's me', got " << "string: " << m_Message.c_str() << std::endl;
        std::cout << "multiline string: " << m_JSONConfig.c_str() << std::endl;
        std::cout << "Expected 42, got " << "integer: " << std::to_string(m_Id) << std::endl;
        std::cout << "Expected 3.141593, got " << "float: " << std::to_string(m_Pi) << std::endl;
        std::cout << "Expected 1, got " << "bool: " << std::to_string(m_IsValid) << std::endl;
        std::cout << "Expected 77, got " << "table column a: " << std::to_string(m_TableA) << "     " << std::to_string(m_DirectTableA) << std::endl;
        std::cout << "Expected 1.200000, got " << "table column b: " << std::to_string(m_TableB) << "     " << std::to_string(m_DirectTableB) << std::endl;
        std::cout << "Expected 'this is a string', got " << "table column c: " << m_TableC.c_str() << "     " << m_DirectTableC.c_str() << std::endl;
        for (auto counter : m_Counters)
        {
            std::cout << std::to_string(counter) << ", ";
        }
        std::cout << std::endl;
    }

  private:
    std::string           m_Message { "" };
    std::string           m_JSONConfig { "" };
    int32_t               m_Id { -1 };
    float                 m_Pi { 0.0 };
    bool                  m_IsValid { false };
    std::vector<uint32_t> m_Counters{};
    uint32_t              m_TableA { 0 };
    float                 m_TableB { 0.0 };
    std::string           m_TableC { "" };
    uint32_t              m_DirectTableA { 0 };
    float                 m_DirectTableB { 0.0 };
    std::string           m_DirectTableC { "" };
    uint32_t              m_InitializedValue { 0 };
    uint32_t              m_UpdatableValue { 0 }; 
};

DEFINE_SDV_OBJECT(DemoConfigurationComponent)

The configuration can include very complex data including tables. It’s not required to get from top to down, a direct access is also possible.

#include <iostream>
#include <support/component_impl.h>
#include <support/toml.h>

class DemoConfigurationComponent : public sdv::CSdvObject
{
public:
    DECLARE_OBJECT_CLASS_TYPE(sdv::EObjectType::device)
    DECLARE_OBJECT_CLASS_NAME("Configuration_Example")

    // Parameter map
    BEGIN_SDV_PARAM_MAP()
        SDV_PARAM_ENABLE_LOCKING()          //  optional, if the parameter should be updatable
        SDV_PARAM_ENTRY(m_InitializedValue, "initializedValue", 7, "km/h", "Description for an initialized parameter.")
        SDV_PARAM_ENTRY(m_UpdatableValue,   "updatableValue",   7, "m/s", "Description for an updatable parameter.")
    END_SDV_PARAM_MAP()

    /**
     * @brief Initialization event, called after object configuration was loaded. Overload of sdv::CSdvObject::OnInitialize.
     * @return Returns 'true' when the initialization was successful, 'false' when not.
     */
    virtual bool OnInitialize() override
    {
        try
        {
            sdv::toml::CTOMLParser config(GetObjectConfig());

            sdv::toml::CNode messageNode = config.GetDirect("Message");
            if (messageNode.GetType() == sdv::toml::ENodeType::node_string)
            {
                m_Message = static_cast<std::string>(messageNode.GetValue());
            }
            
            sdv::toml::CNode jsonNode = config.GetDirect("JSONConfig");
            if (jsonNode.GetType() == sdv::toml::ENodeType::node_string)
            {
                m_JSONConfig = static_cast<std::string>(jsonNode.GetValue());
            }
            
            sdv::toml::CNode idNode = config.GetDirect("Id");
            if (idNode.GetType() == sdv::toml::ENodeType::node_integer)
            {
                m_Id = static_cast<int32_t>(idNode.GetValue());
            }

            sdv::toml::CNode floatNode = config.GetDirect("Pi");
            if (floatNode.GetType() == sdv::toml::ENodeType::node_floating_point)
            {
                m_Pi = static_cast<float>(floatNode.GetValue());
            }

            sdv::toml::CNode boolNode = config.GetDirect("Boolean");
            if (boolNode.GetType() == sdv::toml::ENodeType::node_boolean)
            {
                m_IsValid = static_cast<bool>(boolNode.GetValue());
            }

            sdv::toml::CNodeCollection arrayNodes = config.GetDirect("Array");
            if (arrayNodes.GetType() == sdv::toml::ENodeType::node_array)
            {
                for (size_t nIndex = 0; nIndex < arrayNodes.GetCount(); nIndex++)
                {
                    sdv::toml::CNode node = arrayNodes[nIndex];
                    if (node.GetType() == sdv::toml::ENodeType::node_integer)
                    {
                        m_Counters.push_back(static_cast<uint32_t>(node.GetValue()));
                    }
                }
            }

            sdv::toml::CNodeCollection tableNodes = config.GetDirect("Table");
            if (tableNodes.GetType() == sdv::toml::ENodeType::node_table)
            {
                if (tableNodes.GetCount() >= 3)
                {
                    m_TableA = static_cast<uint32_t>(tableNodes[0].GetValue());
                    m_TableB = static_cast<float>(tableNodes[1].GetValue());
                    m_TableC = static_cast<std::string>(tableNodes[2].GetValue());
                }
            }

            auto table_a = config.GetDirect("Table.a");
            auto table_b = config.GetDirect("Table.b");
            auto table_c = config.GetDirect("Table.c");
            m_DirectTableA = static_cast<uint32_t>(table_a.GetValue());
            m_DirectTableB = static_cast<float>(table_b.GetValue());
            m_DirectTableC = static_cast<std::string>(table_c.GetValue());

        }
        catch (const sdv::toml::XTOMLParseException& e)
        {
            SDV_LOG_ERROR("Parsing error: ", e.what());

            return false;
        }

        PrintAllVariables();

        return true;
    };

    /**
     * @brief Shutdown the object. Overload of sdv::CSdvObject::OnShutdown.
     */
    virtual void OnShutdown() override
    {}

    /**
    * @brief Print all global variables to console
    */
    void PrintAllVariables()  const
    {
        std::cout << "\n----------\nValues from the parameter map:" << std::endl;        
        std::cout << "Expected 7, got " << "initialized value - not changed, not in configuration file: " << std::to_string(m_InitializedValue) << std::endl;          
        std::cout << "Expected 13, got " << "updated value - changed, found in configuration file: " << std::to_string(m_UpdatableValue) << std::endl;
        std::cout << "\n----------\nValues parsed during initialization:" << std::endl;
        std::cout << "Expected 'It's me', got " << "string: " << m_Message.c_str() << std::endl;
        std::cout << "multiline string: " << m_JSONConfig.c_str() << std::endl;
        std::cout << "Expected 42, got " << "integer: " << std::to_string(m_Id) << std::endl;
        std::cout << "Expected 3.141593, got " << "float: " << std::to_string(m_Pi) << std::endl;
        std::cout << "Expected 1, got " << "bool: " << std::to_string(m_IsValid) << std::endl;
        std::cout << "Expected 77, got " << "table column a: " << std::to_string(m_TableA) << "     " << std::to_string(m_DirectTableA) << std::endl;
        std::cout << "Expected 1.200000, got " << "table column b: " << std::to_string(m_TableB) << "     " << std::to_string(m_DirectTableB) << std::endl;
        std::cout << "Expected 'this is a string', got " << "table column c: " << m_TableC.c_str() << "     " << m_DirectTableC.c_str() << std::endl;
        for (auto counter : m_Counters)
        {
            std::cout << std::to_string(counter) << ", ";
        }
        std::cout << std::endl;
    }

  private:
    std::string           m_Message { "" };
    std::string           m_JSONConfig { "" };
    int32_t               m_Id { -1 };
    float                 m_Pi { 0.0 };
    bool                  m_IsValid { false };
    std::vector<uint32_t> m_Counters{};
    uint32_t              m_TableA { 0 };
    float                 m_TableB { 0.0 };
    std::string           m_TableC { "" };
    uint32_t              m_DirectTableA { 0 };
    float                 m_DirectTableB { 0.0 };
    std::string           m_DirectTableC { "" };
    uint32_t              m_InitializedValue { 0 };
    uint32_t              m_UpdatableValue { 0 }; 
};

DEFINE_SDV_OBJECT(DemoConfigurationComponent)

These are the variables required for the parsing of the example. The example can be found in the code examples.