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...


Simple Interface

To enable interoperability with other than C++ languages, we provide a simple, C-style API - SimpleIface.h. Basically, it provides three functions to load, execute and free SmartCGMS configuration. An opaque handle represents the instantiated, live configuration.

The SmartCGMS main library (scgms.dll, libscgms.so, ...) exports three functions:

scgms_execution_t SimpleCalling Execute_SCGMS_Configuration(const char *config, TSCGMS_Execution_Callback callback, scgms::TOn_Filter_Created filterCreatedCallback);
BOOL SimpleCalling Inject_SCGMS_Event(const scgms_execution_t execution, const TSCGMS_Event_Data *simple_event);
void SimpleCalling Shutdown_SCGMS(const scgms_execution_t execution, BOOL wait_for_shutdown);

Here, SimpleCalling is an alias for __cdecl on Windows, or translates to an empty string on other systems.

  • Execute_SCGMS_Configuration - executes given configuration, registers an execution callback and returns the opaque handle
    • the configuration given by the parameter configuration is a null-terminated string containing the whole configuration (not the path)
    • the parameter callback points to a function, that gets invoked whenever there is an event leaving the filter chain at the terminal end
  • Inject_SCGMS_Event - injects an event to the filter chain
    • retains the opaque handler as the first parameter execution
    • note, that the event gets injected, and as a result, the registered callback may be invoked depending on configuration; when the same event triggers the callback, the call is done in the same thread
  • Shutdown_SCGMS - shuts down the SmartCGMS execution identified by the handle given as the first parameter
    • optionally, it may wait for the Shut_Down event before the chain gets terminated
    • this call blocks until the chain is destroyed

To substitute the compound device event structure, the simple interface defines a simplified, marshallable version of the device event called TSCGMS_Event_Data. The structure is as follows:

typedef struct _TSCGMS_Event_Data {
    uint8_t event_code;
    GUID device_id;
    GUID signal_id;

    double device_time;
    int64_t logical_time;

    uint64_t segment_id;

    double level;
    double *parameters;
    size_t count;

    wchar_t *str;
} TSCGMS_Event_Data;

The execution callback is a function pointer TSCGMS_Execution_Callback, which is an alias for the full definition:

typedef HRESULT(SimpleCalling *TSCGMS_Execution_Callback)(TSCGMS_Event_Data *event);

To obtain entry points to the API, we provide this example C++ code:

#include <utils/winapi_mapping.h>

TExecute_SCMGS_Configuration Execute_SCGMS_Configuration;
TInject_SCGMS_Event Inject_SCGMS_Event;
TShutdown_SCGMS Shutdown_SCGMS;

HMODULE scgms = NULL;

// platform-dependent choice for SCGMS library
#if defined(WIN32)
    const wchar_t* SCGMS_Library_File_Name = L"scgms.dll";
#elif defined(__APPLE__)
    const wchar_t* SCGMS_Library_File_Name = L"libscgms.dylib";
#else
    const wchar_t* SCGMS_Library_File_Name = L"libscgms.so";
#endif

int Load_SCGMS() {
    scgms = LoadLibraryW(SCGMS_Library_File_Name);
    if (scgms) {
        Execute_SCGMS_Configuration = (TExecute_SCMGS_Configuration) GetProcAddress(scgms, "Execute_SCGMS_Configuration");
        Inject_SCGMS_Event = (TInject_SCGMS_Event) GetProcAddress(scgms, "Inject_SCGMS_Event");
        Shutdown_SCGMS = (TShutdown_SCGMS) GetProcAddress(scgms, "Shutdown_SCGMS");

        if (!(Execute_SCGMS_Configuration && Inject_SCGMS_Event && Shutdown_SCGMS)) {
            Free_SCGMS();
        }
    }

    return scgms ? 1 : 0;
}

void Free_SCGMS() {
    if (scgms) {
        FreeLibrary(scgms);
        scgms = NULL;
    }
}

Using the code above, we prepared the environment for calling the simple interface. Now, we can write the simple main function:

HRESULT SimpleCalling SCGMS_Execution_Callback(TSCGMS_Event_Data *event) {
   
    do_what_ever_we_wish_with(event);

    return S_OK;
}

int MainCalling main(int argc, char **argv) {

    if (!Load_SCGMS()) {
        printf("Cannot load the SCGMS engine!\n"
               "Make sure that this executable is in the same directory the scgms dynamic library.\n");
        return -2;
    }

    executor = Execute_SCGMS_Configuration(configuration, SCGMS_Execution_Callback);
    if (executor) {

        // now we have the execution up and running. Let us inject e.g.; 50-gram CHO food
        const GUID signal_Carb_Intake = { 0x37aa6ac1, 0x6984, 0x4a06,{ 0x92, 0xcc, 0xa6, 0x60, 0x11, 0xd, 0xd, 0xc7 } };

        TSCGMS_Event_Data event;
        memset(&event, 0, sizeof(event));

        event.event_code = ec_level;	//Level
        event.level = 50.0;
        event.device_time = event.device_time;
        event.segment_id = 1;
        event.signal_id = signal_Carb_Intake;

        Inject_SCGMS_Event(executor, &event);

        // and wait for it to end
        Shutdown_SCGMS(executor, TRUE);
    } else {
        printf("Error: unable to execute the configuration!\n");
        Free_SCGMS();
        return -1;
    }

    // we are done - clean up
    Free_SCGMS();

    return 0;
}

To make sure, that the locale matches the SmartCGMS conventions, you may add the following code to the start of the main function:

setlocale(LC_ALL, "");
if (!getlocale(LC_ALL)) {
    setlocale(LC_ALL, "C.UTF-8");
}