]> gerrit.simantics Code Review - simantics/fmil.git/blob - org.simantics.fmil.core/native/FMILibrary/src/CAPI/src/FMI1/fmi1_capi.c
Add FMILibrary-2.0.3 to org.simantics.fmil.core\native.
[simantics/fmil.git] / org.simantics.fmil.core / native / FMILibrary / src / CAPI / src / FMI1 / fmi1_capi.c
1 /*
2     Copyright (C) 2012 Modelon AB
3
4     This program is free software: you can redistribute it and/or modify
5     it under the terms of the BSD style license.
6
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.
11
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>.
14 */
15
16 #ifdef __cplusplus 
17 extern "C" {
18 #endif
19
20 #include <stdio.h>
21 #include <stdarg.h>
22 #include <string.h>
23 #include <assert.h>
24
25 #include <JM/jm_types.h>
26 #include <JM/jm_portability.h>
27
28 #include <FMI1/fmi1_capi_impl.h>
29
30 #define FUNCTION_NAME_LENGTH_MAX 2048                   /* Maximum length of FMI function name. Used in the load DLL function. */
31 #define STRINGIFY(str) #str
32
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)
35 {
36         char fname[FUNCTION_NAME_LENGTH_MAX];
37     int len;
38         
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;
42         }       
43
44         len = jm_snprintf(fname,FUNCTION_NAME_LENGTH_MAX,"%s_%s",fmu->modelIdentifier, function_name);
45
46         return jm_portability_load_dll_function(fmu->dllHandle, fname, dll_function_ptrptr);
47 }
48
49
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; \
54 }
55
56
57 /* Load FMI 1.0 Co-Simulation functions */
58 static jm_status_enu_t fmi1_capi_load_cs_fcn(fmi1_capi_t* fmu)
59 {
60         jm_status_enu_t jm_status = jm_status_success;
61
62         jm_log_verbose(fmu->callbacks, FMI_CAPI_MODULE_NAME, "Loading functions for the co-simulation interface"); 
63
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;
71                 }
72         }
73
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);
88
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);
99         return jm_status; 
100 }
101
102 /* Load FMI 1.0 Model Exchange functions */
103 static jm_status_enu_t fmi1_capi_load_me_fcn(fmi1_capi_t* fmu)
104 {
105         jm_status_enu_t jm_status = jm_status_success;
106
107         jm_log_verbose(fmu->callbacks, FMI_CAPI_MODULE_NAME, "Loading functions for the model exchange interface"); 
108
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);
123
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);
134
135         return jm_status; 
136 }
137
138 void fmi1_capi_destroy_dllfmu(fmi1_capi_t* fmu)
139 {
140         if (fmu == NULL) {
141                 return;
142         }
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);
148 }
149
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)
151 {
152         fmi1_capi_t* fmu = NULL;
153
154         jm_log_debug(cb, FMI_CAPI_MODULE_NAME, "Initializing data stuctures for FMICAPI.");
155
156         /* Minor check for the callbacks */
157         if (cb == NULL) {
158                 assert(0);
159                 return NULL;
160         }
161
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.");
166                 return NULL;
167         }
168
169         /* Set the import package callback functions */
170         fmu->callbacks = cb;
171
172         /* Set the FMI callback functions */
173         fmu->callBackFunctions = callBackFunctions;
174
175         /* Set FMI standard to load */
176         fmu->standard = standard;
177
178         /* Set all memory alloated pointers to NULL */
179         fmu->dllPath = NULL;
180         fmu->modelIdentifier = NULL;
181
182         /* Copy DLL path */
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);
187                 return NULL;
188         }
189         strcpy((char*)fmu->dllPath, dllPath);
190
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);
196                 return NULL;
197         }
198         strcpy((char*)fmu->modelIdentifier, modelIdentifier);
199
200         jm_log_debug(cb, FMI_CAPI_MODULE_NAME, "Successfully initialized data stuctures for FMICAPI.");
201
202         /* Everything was succesfull */
203         return fmu;
204 }
205
206 jm_status_enu_t fmi1_capi_load_fcn(fmi1_capi_t* fmu)
207 {
208         assert(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);
215         } else {
216                 return jm_status_error;
217         }
218 }
219
220 jm_status_enu_t fmi1_capi_load_dll(fmi1_capi_t* fmu)
221 {
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;
227         } else {
228                 jm_log_verbose(fmu->callbacks, FMI_CAPI_MODULE_NAME, "Loaded FMU binary from %s", fmu->dllPath);
229                 return jm_status_success;
230         }
231 }
232
233 void fmi1_capi_set_debug_mode(fmi1_capi_t* fmu, int mode) {
234         if(fmu)
235                 fmu->debugMode = mode;
236 }
237 \r
238 int fmi1_capi_get_debug_mode(fmi1_capi_t* fmu) {
239         if(fmu) return fmu->debugMode;
240         return 0;
241 }
242
243 jm_status_enu_t fmi1_capi_free_dll(fmi1_capi_t* fmu)
244 {
245         if (fmu == NULL) {              
246                 return jm_status_error; /* Return without writing any log message */
247         }
248
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 */ 
253                 jm_status_success:
254                 jm_portability_free_dll_handle(fmu->dllHandle);
255                 fmu->dllHandle = 0;
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;
259                 } else {
260                         jm_log_verbose(fmu->callbacks, FMI_CAPI_MODULE_NAME, "Successfully unloaded FMU binary");
261                         return jm_status_success;
262                 }
263         }
264         return jm_status_success;
265 }
266
267 /* Common FMI 1.0 functions */
268
269 const char* fmi1_capi_get_version(fmi1_capi_t* fmu)
270 {
271         assert(fmu);
272         return fmu->fmiGetVersion();
273 }
274
275 fmi1_status_t fmi1_capi_set_debug_logging(fmi1_capi_t* fmu, fmi1_boolean_t loggingOn)
276 {
277         return fmu->fmiSetDebugLogging(fmu->c, loggingOn);
278 }
279
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[])      \
283 { \
284         return fmu->FNAME2(fmu->c, vr, nvr, value); \
285 }
286
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[]) \
290 { \
291         return fmu->FNAME2(fmu->c, vr, nvr, value); \
292 }
293
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)
298
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)
303
304 #ifdef __cplusplus
305 }
306 #endif