Documentation

This page hosts the documentation of the SmartCGMS software architecture and all of its components.

The documentation is being updated to acommodate the recent improvements. Please, be patient, we are working on it...


Execution

Once you have the configuration saved in a file, you can use either the console or GUI application to execute it. The console application is intended for batch processing, to execute the experimental setups with no user input while conserving system resources.

The most important class in the SDK regarding the execution is the scgms::SFilter_Executor class. This implements the scgms::IFilter_Executor interface and offers an additional method to ease the workflow:

  • Execute (from scgms::SFilter_Executor) - executes a device event passes as a scgms::UDevice_Event instance on the configured chain, i.e.; passes the wrapped event to the Execute method of the first filter in chain
  • Execute (from scgms::IFilter_Executor) - same as above, but uses the scgms::IDevice_Event pointer and thus can be potentially unsafe in a given context
  • Terminate (from scgms::IFilter_Executor) - terminates the executor operation, effectively releasing filters from memory; optionally, you can wait for the Shut_Down event to be passed through the chain (and captured by the terminal filter)

Besides the above methods, one important part of the executor is the constructor. It retains the following parameters:

  1. configuration instance (scgms::SPersistent_Filter_Chain_Configuration, see the SDK configuration page) as a first parameter
  2. filter creation callback (scgms::TOn_Filter_Created)
  3. data-type-agnostic pointer (void*) to a data, passed as a parameter to the filter creation callback function
  4. error list (refcnt::Swstr_list)
  5. terminal (output) filter instance pointer (scgms::IFilter*); when passing nullptr (default value), the default terminal filter is used

To load the configuration and execute it programatically, follow this example:

const std::wstring config_filepath = L"my_example_config.ini"; // path to your config

scgms::SPersistent_Filter_Chain_Configuration configuration;
refcnt::Swstr_list errors;

HRESULT rc = E_FAIL;            // assume the worst
if (configuration) {            // and check whether we have constructed the main config container
    rc = configuration->Load_From_File(config_filepath, errors.get());  // and load it if we did
}

errors.for_each([](auto str) {
    std::wcerr << str << std::endl;
});

if (Succeeded(rc)) {
    if (rc == S_FALSE)
        std::wcerr << L"Warning: some filters were not loaded!" << std::endl;

        scgms::SFilter_Executor gFilter_Executor = scgms::SFilter_Executor{ configuration.get(), nullptr, nullptr, errors };

        errors.for_each([](auto str) {
            std::wcerr << str << std::endl;
        });

        if (!gFilter_Executor) {
            std::wcerr << L"Could not execute the filters!" << std::endl;
            return __LINE__;
        }

        // wait for filters to finish, or user to close the app
        gFilter_Executor->Terminate(TRUE);

        if (save_config) {
            std::wcout << L"Saving configuration...";
            errors = refcnt::Swstr_list{};
            const HRESULT rc = configuration->Save_To_File(nullptr, errors.get());

            errors.for_each([](auto str) {
                std::wcerr << str << std::endl;
        });
    
        if (!Succeeded(S_OK)) {
            std::wcerr << std::endl << L"Failed to save the configruation!" << std::endl;
            return __LINE__;
        }
        else
            std::wcout << L" saved." << std::endl;
    }
}
else
    std::wcerr << L"Cannot load the configuration file " << config_filepath << std::endl << L"Error code: " << rc << std::endl;	
 

Note that in scgms::SFilter_Executor construction, you may pass the second parameter, which is a callable function called whenever the filter gets created. This is convenient when creating a filter with an extended context, such as the database reader/writer filters. Such filters need to have a database driver injected during construction. As the used database drivers may be released under incompatible license, we need to inject them externally. To use the drivers, that are supplied with the SmartCGMS SDK, you may want to pass Setup_Filter_DB_Access SDK function as a second parameter to the constructor.

This mechanism is also highly convenient, when creating filters that implement a selected inspection interface. For more information, see the inspection interface documentation.