Components

This section describes the fundamental VSlib interface of Component. This interface serves as a base to most of library’s classes that you, the user, interact with, such as filters, controllers, limits, etc.

General interface

The Component class is designed for you to extend and use whenever you need to have settable Parameters. All of the classes defined by you are intended to be derived from the Component interface. However, this is no the most baseline interface, as Component derives from IComponent. Another class derived from the IComponent is the VSlib-defined RootComponent, intended to serve as the base of the hierarchy of Components.

Component class defines a constructor that takes three parameters: the component’s type (std::string), the name of this instance (std::string, snake_case formatting is enforced), and a reference to parent of this Component. Every Component has a parent, ultimately a RootComponent, that is defined in the VSlib main function and passed to the user by reference.

Using std::string for types and names allows for semantic identification of Components and their Parameters, when the latter are registered in the ParameterRegistry. The definition of a parent, allows for a construction of logical hierarchy between the Components in your control workflow. Each Component in your code will derive either from your-defined class, which in turn derives from a RootComponent, or other Components defined in your code. For example, in the case of PID controller, the PID has a parent, while it itself is a parent to a LimitRange Component.

The interface implements all the logic for registering a Parameter to itself, a public-interface method registerParameter is called. The access to the container holding a vector of name-reference pairs of all Parameters registered to this Component is given by getParameters method. For interactions with the Parameters, there is also a method allowing to verify whether all Parameters of this Component have been initialized, a necessary step of the vloop startup procedure.

Component provides a method intended to be overriden in your code to define a custom Parameter values validation algorithm, the verifyParameters. If all your check pass, the method should return nothing, but in case there is an issue, it should be reported using the fgc4::utils::Warning object with all the information necessary to identify the issue.

Component contains the logic necessary to traverse the hierarchy of the components used in your control workflow and its serialization necessary for the linux - bare-metal communication of settable Parameters.

For more details regarding the API, see the API documentation for Component.

Usage examples

  1. Interactions of base-class Component:

#include "component.h"
#include "rootComponent.h"

using namespace vslib;

int main() {
    RootComponent root;

    const std::string child_type = "child_type"; // free string
    const std::string child_name = "child_name"; // needs to follow snake_case
    Component         child(child_type, child_name, root);

    auto name = child.getName();          // "child_name"
    auto full_name = child.getFullName(); // "root.child_name"

    auto parameters_size = child.getParameters().size();         // no parameters, 0
    auto parameters_initialized = child.parametersInitialized(); // no parameters, true

    auto serialized_component = parent.serialize(); // JSON containing all information needed by the parameter setting interface

    return 0;
}
  1. Deriving your own class and using it:

#include "component.h"
#include "parameter.h"
#include "rootComponent.h"

#include <array>

using namespace vslib;

enum class Enums
{
    option1,
    option2,
    option3
};

class Derived : public Component
{
    public:
        Derived(std::string_view name, IComponent& parent)
            : Component("Derived", name, parent),
            scalar_factor(*this, "scalar_factor", 0.0, 10.0), // min = 0.0, max = 10.0
            array_factor(*this, "array_factor"),
            enums(*this)
        {
        }

        Parameter<double> scalar_factor;  //! Scalar factor of type double
        Parameter<std::array<double, 3>> array_factor; //! Array of double-type factors of length 3
        Parameter<Enums> enums; //! Enumeration Parameter with user-defined options

        // if necessary, override the verifyParameters method to perform your custom validation
        std::optional<fgc4::utils::Warning> verifyParameters() override
        {
            // for example, the first element of the array must be larger than the last one:
            // To validate incoming values, you need to use 'toValidate' method to access the write-buffer values,
            // otherwise you would be checking the currently used valus in the read buffer.
            if (array_factor.toValidate()[0] < array_factor.toValidate()[2])
            {
                return fgc4::utils::Warning(
                    fmt::format("First element of the array_factor: {} is lower than the last element: {}.",
                                array_factor.toValidate()[0], array_factor.toValidate()[2]));
            }
            return {}; // checks passed, no need to return anything
        }

        // other methods, public and private, to interact with these Parameters
};

int main()
{
    RootComponent root;
    Derived derived("derived", root);

    // set your defined Parameters in the parameter setting GUI,
    // each time any Parameter is changed, the verifyParameters method is called.

    // when Parameters are set: use your derived class

    return 0;
}

Component array

ComponentArray is special type of Component allowing for creating a fixed-size array of Components of user’s choice, for example FIR filters. The class has two template parameters: the type of the Components it contains, and the number of objects it will store.

The constructor can be passed an arbitrary number of parameters. After the obligatory name and parent, the remaining parameters are passed to constructors of the relevant Component. The names of the array elements will follow the array-like pattern, by appending [n] to the name defined to this component, where n is the index of the Component in the array. Each stored Component is initialized with exactly the same parameters, except of the name.

The ComponentArray provides analogous interaction interface with stored Components to the std::array, namely it is possible to fetch a reference to the stored Component by overriden operator[], and also iterate over the ComponentArray in a for loop (see usage example below)

For more details regarding the API, see the API documentation for ComponentArray.

Usage example

Using Derived defined above.

#include "componentArray.h"
#include "parameter.h"
#include "rootComponent.h"

#include <array>

using namespace vslib;

void your_function(RootComponent& root)
{
    const std::string                     component_name = "array";
    constexpr size_t                      array_length   = 4;
    ComponentArray<Derived, array_length> array(component_name, root);

    // set all the Parameters of the Components in the array

    // now, you can access each Component, either by its index, like in a std::array:
    Derived& component = array[2]; // returns 3rd element of the array

    // you can also iterate over the array as if it is any other STL container
    for (const auto& element : array)   // tests begin() and end() operators
    {
        // you can now interact with the element object
        // each element is a Derived-type Component
    }
}