2 Copyright (C) 2012 Modelon AB
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the BSD style license.
7 This program is distributed in the hope that it will be useful,
8 but WITHOUT ANY WARRANTY; without even the implied warranty of
9 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 FMILIB_License.txt file for more details.
12 You should have received a copy of the FMILIB_License.txt file
13 along with this program. If not, contact Modelon AB <http://www.modelon.com>.
25 #include <JM/jm_types.h>
26 #include <JM/jm_portability.h>
28 #include <FMI1/fmi1_capi_impl.h>
30 #define FUNCTION_NAME_LENGTH_MAX 2048 /* Maximum length of FMI function name. Used in the load DLL function. */
31 #define STRINGIFY(str) #str
33 /* Loading shared library functions */
34 static jm_status_enu_t fmi1_capi_get_fcn(fmi1_capi_t* fmu, const char* function_name, jm_dll_function_ptr* dll_function_ptrptr)
36 char fname[FUNCTION_NAME_LENGTH_MAX];
39 if (strlen(fmu->modelIdentifier) + strlen(function_name) + 2 > FUNCTION_NAME_LENGTH_MAX) {
40 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));
41 return jm_status_error;
44 len = jm_snprintf(fname,FUNCTION_NAME_LENGTH_MAX,"%s_%s",fmu->modelIdentifier, function_name);
46 return jm_portability_load_dll_function(fmu->dllHandle, fname, dll_function_ptrptr);
50 /* Load FMI functions from DLL macro */
51 #define LOAD_DLL_FUNCTION(FMIFUNCTION) if (fmi1_capi_get_fcn(fmu, #FMIFUNCTION, (jm_dll_function_ptr*)&fmu->FMIFUNCTION) == jm_status_error) { \
52 jm_log_error(fmu->callbacks, FMI_CAPI_MODULE_NAME, "Could not load the FMI function '"#FMIFUNCTION"'. %s", jm_portability_get_last_dll_error()); \
53 jm_status = jm_status_error; \
57 /* Load FMI 1.0 Co-Simulation functions */
58 static jm_status_enu_t fmi1_capi_load_cs_fcn(fmi1_capi_t* fmu)
60 jm_status_enu_t jm_status = jm_status_success;
62 jm_log_verbose(fmu->callbacks, FMI_CAPI_MODULE_NAME, "Loading functions for the co-simulation interface");
64 /* Workaround for Dymola 2012 and SimulationX 3.x */
65 if (fmi1_capi_get_fcn(fmu, "fmiGetTypesPlatform",(jm_dll_function_ptr*)&fmu->fmiGetTypesPlatform) == jm_status_error) {
66 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());
67 jm_status = jm_status_warning;
68 if (fmi1_capi_get_fcn(fmu, "fmiGetModelTypesPlatform", (jm_dll_function_ptr*)&fmu->fmiGetTypesPlatform) == jm_status_error) {
69 jm_log_error(fmu->callbacks, FMI_CAPI_MODULE_NAME, "Could not load the FMI function 'fmiGetModelTypesPlatform'. %s", jm_portability_get_last_dll_error());
70 jm_status = jm_status_error;
74 LOAD_DLL_FUNCTION(fmiInstantiateSlave);
75 LOAD_DLL_FUNCTION(fmiInitializeSlave);
76 LOAD_DLL_FUNCTION(fmiTerminateSlave);
77 LOAD_DLL_FUNCTION(fmiResetSlave);
78 LOAD_DLL_FUNCTION(fmiFreeSlaveInstance);
79 LOAD_DLL_FUNCTION(fmiSetRealInputDerivatives);
80 LOAD_DLL_FUNCTION(fmiGetRealOutputDerivatives);
81 LOAD_DLL_FUNCTION(fmiCancelStep);
82 LOAD_DLL_FUNCTION(fmiDoStep);
83 LOAD_DLL_FUNCTION(fmiGetStatus);
84 LOAD_DLL_FUNCTION(fmiGetRealStatus);
85 LOAD_DLL_FUNCTION(fmiGetIntegerStatus);
86 LOAD_DLL_FUNCTION(fmiGetBooleanStatus);
87 LOAD_DLL_FUNCTION(fmiGetStringStatus);
89 LOAD_DLL_FUNCTION(fmiGetVersion);
90 LOAD_DLL_FUNCTION(fmiSetDebugLogging);
91 LOAD_DLL_FUNCTION(fmiSetReal);
92 LOAD_DLL_FUNCTION(fmiSetInteger);
93 LOAD_DLL_FUNCTION(fmiSetBoolean);
94 LOAD_DLL_FUNCTION(fmiSetString);
95 LOAD_DLL_FUNCTION(fmiGetReal);
96 LOAD_DLL_FUNCTION(fmiGetInteger);
97 LOAD_DLL_FUNCTION(fmiGetBoolean);
98 LOAD_DLL_FUNCTION(fmiGetString);
102 /* Load FMI 1.0 Model Exchange functions */
103 static jm_status_enu_t fmi1_capi_load_me_fcn(fmi1_capi_t* fmu)
105 jm_status_enu_t jm_status = jm_status_success;
107 jm_log_verbose(fmu->callbacks, FMI_CAPI_MODULE_NAME, "Loading functions for the model exchange interface");
109 LOAD_DLL_FUNCTION(fmiGetModelTypesPlatform);
110 LOAD_DLL_FUNCTION(fmiInstantiateModel);
111 LOAD_DLL_FUNCTION(fmiFreeModelInstance);
112 LOAD_DLL_FUNCTION(fmiSetTime);
113 LOAD_DLL_FUNCTION(fmiSetContinuousStates);
114 LOAD_DLL_FUNCTION(fmiCompletedIntegratorStep);
115 LOAD_DLL_FUNCTION(fmiInitialize);
116 LOAD_DLL_FUNCTION(fmiGetDerivatives);
117 LOAD_DLL_FUNCTION(fmiGetEventIndicators);
118 LOAD_DLL_FUNCTION(fmiEventUpdate);
119 LOAD_DLL_FUNCTION(fmiGetContinuousStates);
120 LOAD_DLL_FUNCTION(fmiGetNominalContinuousStates);
121 LOAD_DLL_FUNCTION(fmiGetStateValueReferences);
122 LOAD_DLL_FUNCTION(fmiTerminate);
124 LOAD_DLL_FUNCTION(fmiGetVersion);
125 LOAD_DLL_FUNCTION(fmiSetDebugLogging);
126 LOAD_DLL_FUNCTION(fmiSetReal);
127 LOAD_DLL_FUNCTION(fmiSetInteger);
128 LOAD_DLL_FUNCTION(fmiSetBoolean);
129 LOAD_DLL_FUNCTION(fmiSetString);
130 LOAD_DLL_FUNCTION(fmiGetReal);
131 LOAD_DLL_FUNCTION(fmiGetInteger);
132 LOAD_DLL_FUNCTION(fmiGetBoolean);
133 LOAD_DLL_FUNCTION(fmiGetString);
138 void fmi1_capi_destroy_dllfmu(fmi1_capi_t* fmu)
143 fmi1_capi_free_dll(fmu);
144 jm_log_debug(fmu->callbacks, FMI_CAPI_MODULE_NAME, "Releasing allocated memory");
145 fmu->callbacks->free((void*)fmu->dllPath);
146 fmu->callbacks->free((void*)fmu->modelIdentifier);
147 fmu->callbacks->free((void*)fmu);
150 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)
152 fmi1_capi_t* fmu = NULL;
154 jm_log_debug(cb, FMI_CAPI_MODULE_NAME, "Initializing data stuctures for FMICAPI.");
156 /* Minor check for the callbacks */
162 /* Allocate memory for the FMU instance */
163 fmu = (fmi1_capi_t*)cb->calloc(1, sizeof(fmi1_capi_t));
164 if (fmu == NULL) { /* Could not allocate memory for the FMU struct */
165 jm_log_fatal(cb, FMI_CAPI_MODULE_NAME, "Could not allocate memory for the FMU struct.");
169 /* Set the import package callback functions */
172 /* Set the FMI callback functions */
173 fmu->callBackFunctions = callBackFunctions;
175 /* Set FMI standard to load */
176 fmu->standard = standard;
178 /* Set all memory alloated pointers to NULL */
180 fmu->modelIdentifier = NULL;
183 fmu->dllPath = (char*)cb->calloc(sizeof(char), strlen(dllPath) + 1);
184 if (fmu->dllPath == NULL) {
185 jm_log_fatal(cb, FMI_CAPI_MODULE_NAME, "Could not allocate memory for the DLL path string.");
186 fmi1_capi_destroy_dllfmu(fmu);
189 strcpy((char*)fmu->dllPath, dllPath);
191 /* Copy the modelIdentifier */
192 fmu->modelIdentifier = (char*)cb->calloc(sizeof(char), strlen(modelIdentifier) + 1);
193 if (fmu->modelIdentifier == NULL) {
194 jm_log_fatal(cb, FMI_CAPI_MODULE_NAME, "Could not allocate memory for the modelIdentifier string.");
195 fmi1_capi_destroy_dllfmu(fmu);
198 strcpy((char*)fmu->modelIdentifier, modelIdentifier);
200 jm_log_debug(cb, FMI_CAPI_MODULE_NAME, "Successfully initialized data stuctures for FMICAPI.");
202 /* Everything was succesfull */
206 jm_status_enu_t fmi1_capi_load_fcn(fmi1_capi_t* fmu)
209 /* Load ME functions */
210 if (fmu->standard == fmi1_fmu_kind_enu_me) {
211 return fmi1_capi_load_me_fcn(fmu);
212 /* Load CS functions */
213 } else if (fmu->standard == fmi1_fmu_kind_enu_cs_standalone || fmu->standard == fmi1_fmu_kind_enu_cs_tool) {
214 return fmi1_capi_load_cs_fcn(fmu);
216 return jm_status_error;
220 jm_status_enu_t fmi1_capi_load_dll(fmi1_capi_t* fmu)
222 assert(fmu && fmu->dllPath);
223 fmu->dllHandle = jm_portability_load_dll_handle(fmu->dllPath); /* Load the shared library */
224 if (fmu->dllHandle == NULL) {
225 jm_log_fatal(fmu->callbacks, FMI_CAPI_MODULE_NAME, "Could not load the DLL: %s", jm_portability_get_last_dll_error());
226 return jm_status_error;
228 jm_log_verbose(fmu->callbacks, FMI_CAPI_MODULE_NAME, "Loaded FMU binary from %s", fmu->dllPath);
229 return jm_status_success;
233 void fmi1_capi_set_debug_mode(fmi1_capi_t* fmu, int mode) {
235 fmu->debugMode = mode;
238 int fmi1_capi_get_debug_mode(fmi1_capi_t* fmu) {
239 if(fmu) return fmu->debugMode;
243 jm_status_enu_t fmi1_capi_free_dll(fmi1_capi_t* fmu)
246 return jm_status_error; /* Return without writing any log message */
249 if (fmu->dllHandle) {
250 jm_status_enu_t status =
251 (fmu->debugMode != 0) ?
252 /* When running valgrind this may be convenient to track mem leaks */
254 jm_portability_free_dll_handle(fmu->dllHandle);
256 if (status == jm_status_error) { /* Free the library handle */
257 jm_log(fmu->callbacks, FMI_CAPI_MODULE_NAME, jm_log_level_error, "Could not free the DLL: %s", jm_portability_get_last_dll_error());
258 return jm_status_error;
260 jm_log_verbose(fmu->callbacks, FMI_CAPI_MODULE_NAME, "Successfully unloaded FMU binary");
261 return jm_status_success;
264 return jm_status_success;
267 /* Common FMI 1.0 functions */
269 const char* fmi1_capi_get_version(fmi1_capi_t* fmu)
272 return fmu->fmiGetVersion();
275 fmi1_status_t fmi1_capi_set_debug_logging(fmi1_capi_t* fmu, fmi1_boolean_t loggingOn)
277 return fmu->fmiSetDebugLogging(fmu->c, loggingOn);
280 /* fmiSet* functions */
281 #define FMISETX(FNAME1, FNAME2, FTYPE) \
282 fmi1_status_t FNAME1(fmi1_capi_t* fmu, const fmi1_value_reference_t vr[], size_t nvr, const FTYPE value[]) \
284 return fmu->FNAME2(fmu->c, vr, nvr, value); \
287 /* fmiGet* functions */
288 #define FMIGETX(FNAME1, FNAME2, FTYPE) \
289 fmi1_status_t FNAME1(fmi1_capi_t* fmu, const fmi1_value_reference_t vr[], size_t nvr, FTYPE value[]) \
291 return fmu->FNAME2(fmu->c, vr, nvr, value); \
294 FMISETX(fmi1_capi_set_real, fmiSetReal, fmi1_real_t)
295 FMISETX(fmi1_capi_set_integer, fmiSetInteger, fmi1_integer_t)
296 FMISETX(fmi1_capi_set_boolean, fmiSetBoolean, fmi1_boolean_t)
297 FMISETX(fmi1_capi_set_string, fmiSetString, fmi1_string_t)
299 FMIGETX(fmi1_capi_get_real, fmiGetReal, fmi1_real_t)
300 FMIGETX(fmi1_capi_get_integer, fmiGetInteger, fmi1_integer_t)
301 FMIGETX(fmi1_capi_get_boolean, fmiGetBoolean, fmi1_boolean_t)
302 FMIGETX(fmi1_capi_get_string, fmiGetString, fmi1_string_t)