X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;ds=sidebyside;f=org.simantics.fmil.core%2Fnative%2FFMILibrary%2Fsrc%2FCAPI%2Fsrc%2FFMI1%2Ffmi1_capi.c;fp=org.simantics.fmil.core%2Fnative%2FFMILibrary%2Fsrc%2FCAPI%2Fsrc%2FFMI1%2Ffmi1_capi.c;h=a9eb3334ac39c57e44a307514efa60ea11c79f5f;hb=4bed8078f3f6d15b8539d7357b8815f8bfeec2c4;hp=0000000000000000000000000000000000000000;hpb=87cc423aefd98832c6c8d0979afc21551f8ceca3;p=simantics%2Ffmil.git diff --git a/org.simantics.fmil.core/native/FMILibrary/src/CAPI/src/FMI1/fmi1_capi.c b/org.simantics.fmil.core/native/FMILibrary/src/CAPI/src/FMI1/fmi1_capi.c new file mode 100644 index 0000000..a9eb333 --- /dev/null +++ b/org.simantics.fmil.core/native/FMILibrary/src/CAPI/src/FMI1/fmi1_capi.c @@ -0,0 +1,306 @@ +/* + Copyright (C) 2012 Modelon AB + + This program is free software: you can redistribute it and/or modify + it under the terms of the BSD style license. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + FMILIB_License.txt file for more details. + + You should have received a copy of the FMILIB_License.txt file + along with this program. If not, contact Modelon AB . +*/ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include +#include + +#include +#include + +#include + +#define FUNCTION_NAME_LENGTH_MAX 2048 /* Maximum length of FMI function name. Used in the load DLL function. */ +#define STRINGIFY(str) #str + +/* Loading shared library functions */ +static jm_status_enu_t fmi1_capi_get_fcn(fmi1_capi_t* fmu, const char* function_name, jm_dll_function_ptr* dll_function_ptrptr) +{ + char fname[FUNCTION_NAME_LENGTH_MAX]; + int len; + + if (strlen(fmu->modelIdentifier) + strlen(function_name) + 2 > FUNCTION_NAME_LENGTH_MAX) { + jm_log_fatal(fmu->callbacks, FMI_CAPI_MODULE_NAME, "DLL function name is too long. Max name length is set to %s.", STRINGIFY(FUNCTION_NAME_LENGTH_MAX)); + return jm_status_error; + } + + len = jm_snprintf(fname,FUNCTION_NAME_LENGTH_MAX,"%s_%s",fmu->modelIdentifier, function_name); + + return jm_portability_load_dll_function(fmu->dllHandle, fname, dll_function_ptrptr); +} + + +/* Load FMI functions from DLL macro */ +#define LOAD_DLL_FUNCTION(FMIFUNCTION) if (fmi1_capi_get_fcn(fmu, #FMIFUNCTION, (jm_dll_function_ptr*)&fmu->FMIFUNCTION) == jm_status_error) { \ + jm_log_error(fmu->callbacks, FMI_CAPI_MODULE_NAME, "Could not load the FMI function '"#FMIFUNCTION"'. %s", jm_portability_get_last_dll_error()); \ + jm_status = jm_status_error; \ +} + + +/* Load FMI 1.0 Co-Simulation functions */ +static jm_status_enu_t fmi1_capi_load_cs_fcn(fmi1_capi_t* fmu) +{ + jm_status_enu_t jm_status = jm_status_success; + + jm_log_verbose(fmu->callbacks, FMI_CAPI_MODULE_NAME, "Loading functions for the co-simulation interface"); + + /* Workaround for Dymola 2012 and SimulationX 3.x */ + if (fmi1_capi_get_fcn(fmu, "fmiGetTypesPlatform",(jm_dll_function_ptr*)&fmu->fmiGetTypesPlatform) == jm_status_error) { + jm_log_warning(fmu->callbacks, FMI_CAPI_MODULE_NAME, "Could not load the FMI function 'fmiGetTypesPlatform'. %s. Trying to load fmiGetModelTypesPlatform instead.", jm_portability_get_last_dll_error()); + jm_status = jm_status_warning; + if (fmi1_capi_get_fcn(fmu, "fmiGetModelTypesPlatform", (jm_dll_function_ptr*)&fmu->fmiGetTypesPlatform) == jm_status_error) { + jm_log_error(fmu->callbacks, FMI_CAPI_MODULE_NAME, "Could not load the FMI function 'fmiGetModelTypesPlatform'. %s", jm_portability_get_last_dll_error()); + jm_status = jm_status_error; + } + } + + LOAD_DLL_FUNCTION(fmiInstantiateSlave); + LOAD_DLL_FUNCTION(fmiInitializeSlave); + LOAD_DLL_FUNCTION(fmiTerminateSlave); + LOAD_DLL_FUNCTION(fmiResetSlave); + LOAD_DLL_FUNCTION(fmiFreeSlaveInstance); + LOAD_DLL_FUNCTION(fmiSetRealInputDerivatives); + LOAD_DLL_FUNCTION(fmiGetRealOutputDerivatives); + LOAD_DLL_FUNCTION(fmiCancelStep); + LOAD_DLL_FUNCTION(fmiDoStep); + LOAD_DLL_FUNCTION(fmiGetStatus); + LOAD_DLL_FUNCTION(fmiGetRealStatus); + LOAD_DLL_FUNCTION(fmiGetIntegerStatus); + LOAD_DLL_FUNCTION(fmiGetBooleanStatus); + LOAD_DLL_FUNCTION(fmiGetStringStatus); + + LOAD_DLL_FUNCTION(fmiGetVersion); + LOAD_DLL_FUNCTION(fmiSetDebugLogging); + LOAD_DLL_FUNCTION(fmiSetReal); + LOAD_DLL_FUNCTION(fmiSetInteger); + LOAD_DLL_FUNCTION(fmiSetBoolean); + LOAD_DLL_FUNCTION(fmiSetString); + LOAD_DLL_FUNCTION(fmiGetReal); + LOAD_DLL_FUNCTION(fmiGetInteger); + LOAD_DLL_FUNCTION(fmiGetBoolean); + LOAD_DLL_FUNCTION(fmiGetString); + return jm_status; +} + +/* Load FMI 1.0 Model Exchange functions */ +static jm_status_enu_t fmi1_capi_load_me_fcn(fmi1_capi_t* fmu) +{ + jm_status_enu_t jm_status = jm_status_success; + + jm_log_verbose(fmu->callbacks, FMI_CAPI_MODULE_NAME, "Loading functions for the model exchange interface"); + + LOAD_DLL_FUNCTION(fmiGetModelTypesPlatform); + LOAD_DLL_FUNCTION(fmiInstantiateModel); + LOAD_DLL_FUNCTION(fmiFreeModelInstance); + LOAD_DLL_FUNCTION(fmiSetTime); + LOAD_DLL_FUNCTION(fmiSetContinuousStates); + LOAD_DLL_FUNCTION(fmiCompletedIntegratorStep); + LOAD_DLL_FUNCTION(fmiInitialize); + LOAD_DLL_FUNCTION(fmiGetDerivatives); + LOAD_DLL_FUNCTION(fmiGetEventIndicators); + LOAD_DLL_FUNCTION(fmiEventUpdate); + LOAD_DLL_FUNCTION(fmiGetContinuousStates); + LOAD_DLL_FUNCTION(fmiGetNominalContinuousStates); + LOAD_DLL_FUNCTION(fmiGetStateValueReferences); + LOAD_DLL_FUNCTION(fmiTerminate); + + LOAD_DLL_FUNCTION(fmiGetVersion); + LOAD_DLL_FUNCTION(fmiSetDebugLogging); + LOAD_DLL_FUNCTION(fmiSetReal); + LOAD_DLL_FUNCTION(fmiSetInteger); + LOAD_DLL_FUNCTION(fmiSetBoolean); + LOAD_DLL_FUNCTION(fmiSetString); + LOAD_DLL_FUNCTION(fmiGetReal); + LOAD_DLL_FUNCTION(fmiGetInteger); + LOAD_DLL_FUNCTION(fmiGetBoolean); + LOAD_DLL_FUNCTION(fmiGetString); + + return jm_status; +} + +void fmi1_capi_destroy_dllfmu(fmi1_capi_t* fmu) +{ + if (fmu == NULL) { + return; + } + fmi1_capi_free_dll(fmu); + jm_log_debug(fmu->callbacks, FMI_CAPI_MODULE_NAME, "Releasing allocated memory"); + fmu->callbacks->free((void*)fmu->dllPath); + fmu->callbacks->free((void*)fmu->modelIdentifier); + fmu->callbacks->free((void*)fmu); +} + +fmi1_capi_t* fmi1_capi_create_dllfmu(jm_callbacks* cb, const char* dllPath, const char* modelIdentifier, fmi1_callback_functions_t callBackFunctions, fmi1_fmu_kind_enu_t standard) +{ + fmi1_capi_t* fmu = NULL; + + jm_log_debug(cb, FMI_CAPI_MODULE_NAME, "Initializing data stuctures for FMICAPI."); + + /* Minor check for the callbacks */ + if (cb == NULL) { + assert(0); + return NULL; + } + + /* Allocate memory for the FMU instance */ + fmu = (fmi1_capi_t*)cb->calloc(1, sizeof(fmi1_capi_t)); + if (fmu == NULL) { /* Could not allocate memory for the FMU struct */ + jm_log_fatal(cb, FMI_CAPI_MODULE_NAME, "Could not allocate memory for the FMU struct."); + return NULL; + } + + /* Set the import package callback functions */ + fmu->callbacks = cb; + + /* Set the FMI callback functions */ + fmu->callBackFunctions = callBackFunctions; + + /* Set FMI standard to load */ + fmu->standard = standard; + + /* Set all memory alloated pointers to NULL */ + fmu->dllPath = NULL; + fmu->modelIdentifier = NULL; + + /* Copy DLL path */ + fmu->dllPath = (char*)cb->calloc(sizeof(char), strlen(dllPath) + 1); + if (fmu->dllPath == NULL) { + jm_log_fatal(cb, FMI_CAPI_MODULE_NAME, "Could not allocate memory for the DLL path string."); + fmi1_capi_destroy_dllfmu(fmu); + return NULL; + } + strcpy((char*)fmu->dllPath, dllPath); + + /* Copy the modelIdentifier */ + fmu->modelIdentifier = (char*)cb->calloc(sizeof(char), strlen(modelIdentifier) + 1); + if (fmu->modelIdentifier == NULL) { + jm_log_fatal(cb, FMI_CAPI_MODULE_NAME, "Could not allocate memory for the modelIdentifier string."); + fmi1_capi_destroy_dllfmu(fmu); + return NULL; + } + strcpy((char*)fmu->modelIdentifier, modelIdentifier); + + jm_log_debug(cb, FMI_CAPI_MODULE_NAME, "Successfully initialized data stuctures for FMICAPI."); + + /* Everything was succesfull */ + return fmu; +} + +jm_status_enu_t fmi1_capi_load_fcn(fmi1_capi_t* fmu) +{ + assert(fmu); + /* Load ME functions */ + if (fmu->standard == fmi1_fmu_kind_enu_me) { + return fmi1_capi_load_me_fcn(fmu); + /* Load CS functions */ + } else if (fmu->standard == fmi1_fmu_kind_enu_cs_standalone || fmu->standard == fmi1_fmu_kind_enu_cs_tool) { + return fmi1_capi_load_cs_fcn(fmu); + } else { + return jm_status_error; + } +} + +jm_status_enu_t fmi1_capi_load_dll(fmi1_capi_t* fmu) +{ + assert(fmu && fmu->dllPath); + fmu->dllHandle = jm_portability_load_dll_handle(fmu->dllPath); /* Load the shared library */ + if (fmu->dllHandle == NULL) { + jm_log_fatal(fmu->callbacks, FMI_CAPI_MODULE_NAME, "Could not load the DLL: %s", jm_portability_get_last_dll_error()); + return jm_status_error; + } else { + jm_log_verbose(fmu->callbacks, FMI_CAPI_MODULE_NAME, "Loaded FMU binary from %s", fmu->dllPath); + return jm_status_success; + } +} + +void fmi1_capi_set_debug_mode(fmi1_capi_t* fmu, int mode) { + if(fmu) + fmu->debugMode = mode; +} + +int fmi1_capi_get_debug_mode(fmi1_capi_t* fmu) { + if(fmu) return fmu->debugMode; + return 0; +} + +jm_status_enu_t fmi1_capi_free_dll(fmi1_capi_t* fmu) +{ + if (fmu == NULL) { + return jm_status_error; /* Return without writing any log message */ + } + + if (fmu->dllHandle) { + jm_status_enu_t status = + (fmu->debugMode != 0) ? + /* When running valgrind this may be convenient to track mem leaks */ + jm_status_success: + jm_portability_free_dll_handle(fmu->dllHandle); + fmu->dllHandle = 0; + if (status == jm_status_error) { /* Free the library handle */ + jm_log(fmu->callbacks, FMI_CAPI_MODULE_NAME, jm_log_level_error, "Could not free the DLL: %s", jm_portability_get_last_dll_error()); + return jm_status_error; + } else { + jm_log_verbose(fmu->callbacks, FMI_CAPI_MODULE_NAME, "Successfully unloaded FMU binary"); + return jm_status_success; + } + } + return jm_status_success; +} + +/* Common FMI 1.0 functions */ + +const char* fmi1_capi_get_version(fmi1_capi_t* fmu) +{ + assert(fmu); + return fmu->fmiGetVersion(); +} + +fmi1_status_t fmi1_capi_set_debug_logging(fmi1_capi_t* fmu, fmi1_boolean_t loggingOn) +{ + return fmu->fmiSetDebugLogging(fmu->c, loggingOn); +} + +/* fmiSet* functions */ +#define FMISETX(FNAME1, FNAME2, FTYPE) \ +fmi1_status_t FNAME1(fmi1_capi_t* fmu, const fmi1_value_reference_t vr[], size_t nvr, const FTYPE value[]) \ +{ \ + return fmu->FNAME2(fmu->c, vr, nvr, value); \ +} + +/* fmiGet* functions */ +#define FMIGETX(FNAME1, FNAME2, FTYPE) \ +fmi1_status_t FNAME1(fmi1_capi_t* fmu, const fmi1_value_reference_t vr[], size_t nvr, FTYPE value[]) \ +{ \ + return fmu->FNAME2(fmu->c, vr, nvr, value); \ +} + +FMISETX(fmi1_capi_set_real, fmiSetReal, fmi1_real_t) +FMISETX(fmi1_capi_set_integer, fmiSetInteger, fmi1_integer_t) +FMISETX(fmi1_capi_set_boolean, fmiSetBoolean, fmi1_boolean_t) +FMISETX(fmi1_capi_set_string, fmiSetString, fmi1_string_t) + +FMIGETX(fmi1_capi_get_real, fmiGetReal, fmi1_real_t) +FMIGETX(fmi1_capi_get_integer, fmiGetInteger, fmi1_integer_t) +FMIGETX(fmi1_capi_get_boolean, fmiGetBoolean, fmi1_boolean_t) +FMIGETX(fmi1_capi_get_string, fmiGetString, fmi1_string_t) + +#ifdef __cplusplus +} +#endif