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
- the configuration given by the parameter
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
- retains the opaque handler as the first parameter
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
- optionally, it may wait for the
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");
}