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
(fromscgms::SFilter_Executor
) - executes a device event passes as ascgms::UDevice_Event
instance on the configured chain, i.e.; passes the wrapped event to theExecute
method of the first filter in chainExecute
(fromscgms::IFilter_Executor
) - same as above, but uses thescgms::IDevice_Event
pointer and thus can be potentially unsafe in a given contextTerminate
(fromscgms::IFilter_Executor
) - terminates the executor operation, effectively releasing filters from memory; optionally, you can wait for theShut_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:
- configuration instance (
scgms::SPersistent_Filter_Chain_Configuration
, see the SDK configuration page) as a first parameter - filter creation callback (
scgms::TOn_Filter_Created
) - data-type-agnostic pointer (
void*
) to a data, passed as a parameter to the filter creation callback function - error list (
refcnt::Swstr_list
) - terminal (output) filter instance pointer (
scgms::IFilter*
); when passingnullptr
(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.