Documentation

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


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");
}