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>.
19 #include <FMI/fmi_util.h>
20 #include <FMI/fmi_zip_unzip.h>
23 char* fmi_construct_dll_dir_name(jm_callbacks* callbacks, const char* fmu_unzipped_path) {
27 assert( fmu_unzipped_path && callbacks);
30 strlen(fmu_unzipped_path) + strlen(FMI_FILE_SEP)
31 + strlen(FMI_BINARIES) + strlen(FMI_FILE_SEP)
32 + strlen(FMI_PLATFORM) + strlen(FMI_FILE_SEP) + 1;
34 dir_path = (char*)callbacks->malloc(len);
35 if (dir_path == NULL) {
36 jm_log_fatal(callbacks, "FMIUT", "Failed to allocate memory.");
40 sprintf(dir_path, "%s%s%s%s%s%s", fmu_unzipped_path, FMI_FILE_SEP, FMI_BINARIES, FMI_FILE_SEP, FMI_PLATFORM, FMI_FILE_SEP);/*safe */
45 char* fmi_construct_dll_file_name(jm_callbacks* callbacks, const char* dll_dir_name, const char* model_identifier) {
48 assert(callbacks && model_identifier);
50 strlen(dll_dir_name) +
51 strlen(model_identifier)
52 + strlen(FMI_DLL_EXT) + 1;
53 fname = (char*)callbacks->malloc(len);
55 jm_log_fatal(callbacks, "FMIUT", "Failed to allocate memory.");
58 sprintf(fname, "%s%s%s", dll_dir_name, model_identifier, FMI_DLL_EXT);/*safe */
108 #define DLLEXPORT __declspec(dllexport)
110 #define DLLEXPORT __attribute__((visibility("default")))
111 #pragma warning Using GNUC default visibility
114 #pragma warning Empty dynamic link EXPORT defined
117 DLLEXPORT int FMI_CS_LOAD(const char *zipFilePath, const char *unzipFolder, void **fmuPointer, int *fmuVersion, const char **error);
119 DLLEXPORT int FMI1_CS_UNLOAD(void* fmu, const char **error);
120 DLLEXPORT FMIL_Variable *FMI1_CS_GET_VARIABLES(void* fmu, int *count, const char **error);
121 DLLEXPORT FMIL_DeclaredType *FMI1_CS_GET_DECLARED_TYPES(void* fmu, int *count, const char **error);
122 DLLEXPORT int FMI1_CS_INSTANTIATE(void* fmu, const char *instanceName, const char **error);
123 DLLEXPORT int FMI1_CS_INITIALIZE(void* fmu, const char **error);
124 DLLEXPORT int FMI1_CS_STEP(void* fmu, double masterTime, double stepSize, const char **error);
125 DLLEXPORT int FMI1_CS_SET_REAL(void* fmu, int vr, double value, const char **error);
126 DLLEXPORT double FMI1_CS_GET_REAL(void* fmu, int vr, const char **error);
127 DLLEXPORT int FMI1_CS_GET_REALS(void* fmu, int *vrs, double *values, int count, const char **error);
129 DLLEXPORT int FMI2_CS_UNLOAD(void* fmu, const char **error);
130 DLLEXPORT FMIL_Variable *FMI2_CS_GET_VARIABLES(void* fmu, int *count, const char **error);
131 DLLEXPORT FMIL_DeclaredType *FMI2_CS_GET_DECLARED_TYPES(void* fmu, int *count, const char **error);
132 DLLEXPORT int FMI2_CS_INSTANTIATE(void* fmu, const char *instanceName, const char **error);
133 DLLEXPORT int FMI2_CS_INITIALIZE(void* fmu, const char **error);
134 DLLEXPORT int FMI2_CS_STEP(void* fmu, double masterTime, double stepSize, const char **error);
135 DLLEXPORT int FMI2_CS_SET_REAL(void* fmu, int vr, double value, const char **error);
136 DLLEXPORT double FMI2_CS_GET_REAL(void* fmu, int vr, const char **error);
137 DLLEXPORT int FMI2_CS_GET_REALS(void* fmu, int *vrs, double *values, int count, const char **error);
145 /* Logger function used by the C-API */
146 void importlogger(jm_callbacks* c, jm_string module, jm_log_level_enu_t log_level, jm_string message)
148 printf("module = %s, log level = %d: %s\n", module, log_level, message);
151 /* Logger function used by the FMU internally */
152 void fmilogger(fmi1_component_t c, fmi1_string_t instanceName, fmi1_status_t status, fmi1_string_t category, fmi1_string_t message, ...)
157 va_start(argp, message);
158 /*len=jm_vsnprintf(msg, BUFFER, message, argp);
159 printf("fmiStatus = %d; %s (%s): %s\n", status, instanceName, category, msg);
161 printf("Warning: message was trancated");
165 int FMI_CS_LOAD(const char *zipFilePath, const char *unzipFolder, void **fmuPointer, int *fmuVersion, const char **error) {
167 fmi1_callback_functions_t callBackFunctions;
168 fmi2_callback_functions_t callBackFunctions2;
169 fmi_import_context_t* context;
170 fmi_version_enu_t version;
171 jm_status_enu_t status;
174 jm_callbacks* callbacks;
176 callbacks = (jm_callbacks *)calloc(1, sizeof(jm_callbacks));
178 callbacks->malloc = malloc;
179 callbacks->calloc = calloc;
180 callbacks->realloc = realloc;
181 callbacks->free = free;
182 callbacks->logger = importlogger;
184 callbacks->log_level = jm_log_level_debug;
186 callbacks->log_level = jm_log_level_warning;
188 callbacks->context = 0;
190 context = fmi_import_allocate_context(callbacks);
192 version = fmi_import_get_fmi_version(context, zipFilePath, unzipFolder);
194 if (version == fmi_version_1_enu ) {
195 fmu = fmi1_import_parse_xml(context, unzipFolder);
196 if (fmi1_import_get_fmu_kind(fmu) != fmi1_fmu_kind_enu_cs_standalone && fmi1_import_get_fmu_kind(fmu) != fmi1_fmu_kind_enu_cs_tool) {
197 *error = "Provided FMU is version 1 but wrong type me (Model Exchange) when it should be cs (Co-Simulation)";
198 return 2; /* wrong type, should be co-simulation */
201 callBackFunctions.logger = fmilogger;
202 callBackFunctions.allocateMemory = calloc;
203 callBackFunctions.freeMemory = free;
205 status = fmi1_import_create_dllfmu(fmu, callBackFunctions, 0);
206 if (status == jm_status_error) {
207 *error = fmi1_import_get_last_error(fmu);
213 } else if (version == fmi_version_2_0_enu) {
214 fmu2 = fmi2_import_parse_xml(context, unzipFolder, 0);
216 if (fmi2_import_get_fmu_kind(fmu2) != fmi1_fmu_kind_enu_cs_standalone && fmi2_import_get_fmu_kind(fmu2) != fmi1_fmu_kind_enu_cs_tool) {
217 *error = "Provided FMU is version 2.0 but wrong type me (Model Exchange) when it should be cs (Co-Simulation)";
218 return 2; /* wrong type, should be co-simulation */
221 callBackFunctions2.logger = fmi2_log_forwarding;
222 callBackFunctions2.allocateMemory = calloc;
223 callBackFunctions2.freeMemory = free;
224 callBackFunctions2.componentEnvironment = fmu2;
226 status = fmi2_import_create_dllfmu(fmu2, fmi2_fmu_kind_cs, &callBackFunctions2);
227 if (status == jm_status_error) {
228 *error = fmi2_import_get_last_error(fmu2);
235 *error = "Couldn't find version of FMU - possibly incorrect file!";
239 fmi_import_free_context(context);
241 return 0; /* success */
244 int FMI1_CS_UNLOAD(void *fmu_, const char **error) {
245 fmi1_import_t *fmu = (fmi1_import_t *)fmu_;
246 fmi1_import_destroy_dllfmu(fmu);
247 fmi1_import_free(fmu);
251 int FMI2_CS_UNLOAD(void *fmu_, const char **error) {
252 fmi2_import_t *fmu = (fmi2_import_t *)fmu_;
253 fmi2_import_destroy_dllfmu(fmu);
254 fmi2_import_free(fmu);
260 printf("No type definition\n");
264 quan = fmi1_import_get_type_quantity(vt);
266 printf("Type %s\n description: %s\n", fmi1_import_get_type_name(vt), fmi1_import_get_type_description(vt));
268 printf("Base type: %s\n", fmi1_base_type_to_string(fmi1_import_get_base_type(vt)));
271 printf("Quantity: %s\n", quan);
273 switch(fmi1_import_get_base_type(vt)) {
274 case fmi1_base_type_real: {
275 fmi1_import_real_typedef_t* rt = fmi1_import_get_type_as_real(vt);
276 fmi1_real_t min = fmi1_import_get_real_type_min(rt);
277 fmi1_real_t max = fmi1_import_get_real_type_max(rt);
278 fmi1_real_t nom = fmi1_import_get_real_type_nominal(rt);
279 fmi1_import_unit_t* u = fmi1_import_get_real_type_unit(rt);
280 fmi1_import_display_unit_t* du = fmi1_import_get_type_display_unit(rt);
282 printf("Min %g, max %g, nominal %g\n", min, max, nom);
285 printf("Unit: %s\n", fmi1_import_get_unit_name(u));
288 printf("Display unit: %s, gain: %g, offset: %g, is relative: %s",
289 fmi1_import_get_display_unit_name(du),
290 fmi1_import_get_display_unit_gain(du),
291 fmi1_import_get_display_unit_offset(du),
292 fmi1_import_get_real_type_is_relative_quantity(rt)?"yes":"no"
298 case fmi1_base_type_int:{
299 fmi1_import_integer_typedef_t* it = fmi1_import_get_type_as_int(vt);
300 int min = fmi1_import_get_integer_type_min(it);
301 int max = fmi1_import_get_integer_type_max(it);
302 printf("Min %d, max %d\n", min, max);
305 case fmi1_base_type_bool:{
308 case fmi1_base_type_str:{
311 case fmi1_base_type_enum:{
312 fmi1_import_enumeration_typedef_t* et = fmi1_import_get_type_as_enum(vt);
313 int min = fmi1_import_get_enum_type_min(et);
314 int max = fmi1_import_get_enum_type_max(et);
315 printf("Min %d, max %d\n", min, max);
319 ni = fmi1_import_get_enum_type_size(et);
322 printf("There are %u items \n",(unsigned)ni);
323 for(i = 0; i < ni; i++) {
324 printf("[%u] %s (%s) \n", (unsigned)i+1, fmi1_import_get_enum_type_item_name(et, i), fmi1_import_get_enum_type_item_description(et, i));
330 printf("Error in fmiGetBaseType()\n");
335 FMIL_Variable *FMI1_CS_GET_VARIABLES(void *fmu, int *count, const char **error) {
338 FMIL_Variable *result;
339 fmi1_import_variable_list_t* vl = fmi1_import_get_variable_list((fmi1_import_t *)fmu);
340 fmi1_import_variable_typedef_t* type;
342 count[0] = fmi1_import_get_variable_list_size(vl);
344 result = (FMIL_Variable *)malloc(count[0]*sizeof(FMIL_Variable));
346 for(i = 0; i < count[0]; i++) {
348 fmi1_import_variable_t* var = fmi1_import_get_variable(vl, i);
351 printf("Something wrong with variable %d \n",i);
356 result[i].name = fmi1_import_get_variable_name(var);
357 result[i].description = fmi1_import_get_variable_description(var);
359 switch (fmi1_import_get_variability(var)) {
360 case fmi1_variability_enu_constant:
361 result[i].variability = 0;
363 case fmi1_variability_enu_parameter:
364 result[i].variability = 1;
366 case fmi1_variability_enu_discrete:
367 result[i].variability = 2;
369 case fmi1_variability_enu_continuous:
370 result[i].variability = 3;
372 case fmi1_variability_enu_unknown:
373 result[i].variability = 4;
377 switch (fmi1_import_get_causality(var)) {
378 case fmi1_causality_enu_input:
379 result[i].causality = 0;
381 case fmi1_causality_enu_output:
382 result[i].causality = 1;
384 case fmi1_causality_enu_internal:
385 result[i].causality = 2;
387 case fmi1_causality_enu_none:
388 result[i].causality = 3;
390 case fmi1_causality_enu_unknown:
391 result[i].causality = 4;
395 switch (fmi1_import_get_variable_base_type(var)) {
396 case fmi1_base_type_real:
399 case fmi1_base_type_int:
402 case fmi1_base_type_bool:
405 case fmi1_base_type_str:
408 case fmi1_base_type_enum:
413 result[i].vr = fmi1_import_get_variable_vr(var);
415 type = fmi1_import_get_variable_declared_type(var);
417 result[i].declaredType = fmi1_import_get_type_name(type);
419 result[i].declaredType = 0;
426 fmi1_import_free_variable_list(vl);
432 FMIL_Variable *FMI2_CS_GET_VARIABLES(void *fmu, int *count, const char **error) {
435 FMIL_Variable *result;
436 fmi2_import_variable_list_t* vl = fmi2_import_get_variable_list((fmi2_import_t *)fmu, 0);
437 fmi2_import_variable_typedef_t* type;
439 count[0] = fmi2_import_get_variable_list_size(vl);
441 result = (FMIL_Variable *)malloc(count[0]*sizeof(FMIL_Variable));
443 for(i = 0; i < count[0]; i++) {
445 fmi2_import_variable_t* var = fmi2_import_get_variable(vl, i);
448 printf("Something wrong with variable %d \n",i);
453 result[i].name = fmi2_import_get_variable_name(var);
454 result[i].description = fmi2_import_get_variable_description(var);
456 switch (fmi2_import_get_variability(var)) {
457 case fmi2_variability_enu_constant:
458 result[i].variability = 0;
460 case fmi2_variability_enu_fixed:
461 case fmi2_variability_enu_tunable:
462 result[i].variability = 1;
464 case fmi2_variability_enu_discrete:
465 result[i].variability = 2;
467 case fmi2_variability_enu_continuous:
468 result[i].variability = 3;
470 case fmi2_variability_enu_unknown:
471 result[i].variability = 4;
475 switch (fmi2_import_get_causality(var)) {
476 case fmi2_causality_enu_input:
477 result[i].causality = 0;
479 case fmi2_causality_enu_output:
480 result[i].causality = 1;
482 case fmi2_causality_enu_local:
483 result[i].causality = 2;
485 case fmi2_causality_enu_independent:
486 result[i].causality = 3;
488 case fmi2_causality_enu_unknown:
489 result[i].causality = 4;
493 switch (fmi2_import_get_variable_base_type(var)) {
494 case fmi2_base_type_real:
497 case fmi2_base_type_int:
500 case fmi2_base_type_bool:
503 case fmi2_base_type_str:
506 case fmi2_base_type_enum:
511 result[i].vr = fmi2_import_get_variable_vr(var);
513 type = fmi2_import_get_variable_declared_type(var);
515 result[i].declaredType = fmi2_import_get_type_name(type);
517 result[i].declaredType = 0;
524 fmi2_import_free_variable_list(vl);
530 FMIL_DeclaredType *FMI1_CS_GET_DECLARED_TYPES(void *fmu, int *count, const char **error) {
532 FMIL_DeclaredType *result;
533 fmi1_import_type_definitions_t* td = fmi1_import_get_type_definitions((fmi1_import_t *)fmu);
534 fmi1_import_variable_typedef_t* type;
535 unsigned i, ntd = (unsigned)fmi1_import_get_type_definition_number(td);
539 result = (FMIL_DeclaredType *)malloc(count[0]*sizeof(FMIL_DeclaredType));
541 for(i = 0; i < ntd; i++) {
542 type = fmi1_import_get_typedef(td, i);
543 result[i].name = fmi1_import_get_type_name(type);
544 result[i].description = fmi1_import_get_type_description(type);
545 result[i].quantity = fmi1_import_get_type_quantity(type);
548 switch(fmi1_import_get_base_type(type)) {
549 case fmi1_base_type_real: {
550 fmi1_import_real_typedef_t* rt = fmi1_import_get_type_as_real(type);
551 fmi1_import_unit_t* u = fmi1_import_get_real_type_unit(rt);
552 if(u) result[i].unit = fmi1_import_get_unit_name(u);
562 FMIL_DeclaredType *FMI2_CS_GET_DECLARED_TYPES(void *fmu, int *count, const char **error) {
564 FMIL_DeclaredType *result;
565 fmi2_import_type_definitions_t* td = fmi2_import_get_type_definitions((fmi2_import_t *)fmu);
566 fmi2_import_variable_typedef_t* type;
567 unsigned i, ntd = (unsigned)fmi2_import_get_type_definition_number(td);
571 result = (FMIL_DeclaredType *)malloc(count[0]*sizeof(FMIL_DeclaredType));
573 for(i = 0; i < ntd; i++) {
574 type = fmi2_import_get_typedef(td, i);
575 result[i].name = fmi2_import_get_type_name(type);
576 result[i].description = fmi2_import_get_type_description(type);
577 result[i].quantity = fmi2_import_get_type_quantity(type);
580 switch(fmi2_import_get_base_type(type)) {
581 case fmi2_base_type_real: {
582 fmi2_import_real_typedef_t* rt = fmi2_import_get_type_as_real(type);
583 fmi2_import_unit_t* u = fmi2_import_get_real_type_unit(rt);
584 if(u) result[i].unit = fmi2_import_get_unit_name(u);
594 int FMI1_CS_INSTANTIATE(void *fmu, const char *instanceName, const char **error) {
596 fmi1_string_t fmuLocation;
597 fmi1_string_t mimeType;
599 fmi1_boolean_t visible;
600 fmi1_boolean_t interactive;
601 fmi1_boolean_t loggingOn;
603 jm_status_enu_t jmstatus;
608 visible = fmi1_false;
609 interactive = fmi1_false;
610 loggingOn = fmi1_true;
612 jmstatus = fmi1_import_instantiate_slave((fmi1_import_t*)fmu, instanceName, NULL, NULL, timeout, fmi1_false, fmi1_false);
613 if (jmstatus == jm_status_error) {
614 *error = fmi1_import_get_last_error((fmi1_import_t*)fmu);
620 int FMI2_CS_INSTANTIATE(void *fmu, const char *instanceName, const char **error) {
622 fmi2_string_t fmuLocation;
623 fmi2_string_t mimeType;
625 fmi2_boolean_t visible;
626 fmi2_boolean_t interactive;
627 fmi2_boolean_t loggingOn;
628 jm_status_enu_t jmstatus;
633 visible = fmi2_false;
634 jmstatus = fmi2_import_instantiate((fmi2_import_t*)fmu, instanceName, fmi2_cosimulation, NULL, visible);
635 if (jmstatus == jm_status_error) {
636 *error = fmi2_import_get_last_error((fmi2_import_t*)fmu);
642 int FMI1_CS_INITIALIZE(void *fmu, const char **error) {
644 fmi1_status_t status;
647 fmi1_boolean_t StopTimeDefined;
651 StopTimeDefined = fmi1_false;
653 status = fmi1_import_initialize_slave((fmi1_import_t *)fmu, tStart, StopTimeDefined, tStop);
654 if (status == fmi1_status_error || status == fmi1_status_fatal) {
655 printf("fmi1_capi_initialize_slave: Failed\n");
658 printf("fmi1_capi_initialize_slave: Success\n");
664 int FMI2_CS_INITIALIZE(void *fmu, const char **error) {
668 fmi2_boolean_t StopTimeDefined;
669 fmi2_real_t relativeTol = 1e-4;
671 fmi2_status_t fmistatus;
675 StopTimeDefined = fmi1_false;
677 fmistatus = fmi2_import_setup_experiment((fmi2_import_t*)fmu, fmi2_true, relativeTol, tStart, StopTimeDefined, tStop);
678 if(fmistatus != fmi2_status_ok) {
679 *error = ("fmi2_import_setup_experiment failed\n");
683 fmistatus = fmi2_import_enter_initialization_mode((fmi2_import_t*)fmu);
684 if(fmistatus != fmi2_status_ok) {
685 *error = ("fmi2_import_enter_initialization_mode failed\n");
689 fmistatus = fmi2_import_exit_initialization_mode((fmi2_import_t*)fmu);
690 if(fmistatus != fmi2_status_ok) {
691 *error = ("fmi2_import_exit_initialization_mode failed\n");
698 int FMI1_CS_STEP(void *fmu, double masterTime, double stepSize, const char **error) {
700 fmi1_status_t status;
702 status = fmi1_import_do_step((fmi1_import_t *)fmu, (fmi1_real_t)masterTime, (fmi1_real_t)stepSize, fmi1_true);
703 if (status == fmi1_status_error || status == fmi1_status_fatal) {
704 *error = "Error happened during stepping!";
710 int FMI2_CS_STEP(void *fmu, double masterTime, double stepSize, const char **error) {
712 fmi2_status_t status;
714 status = fmi2_import_do_step((fmi2_import_t *)fmu, (fmi2_real_t)masterTime, (fmi2_real_t)stepSize, fmi2_true);
715 if (status == fmi2_status_error || status == fmi2_status_fatal) {
716 *error = "Error happened during stepping!";
722 int FMI1_CS_SET_REAL(void *fmu, int valueId, double value, const char **error) {
724 fmi1_status_t status;
726 fmi1_value_reference_t vr = valueId;
727 status = fmi1_import_set_real((fmi1_import_t *)fmu, &vr, 1, &value);
728 if (status == fmi1_status_error || status == fmi1_status_fatal) {
729 *error = "Error happened during setting real value!";
735 int FMI2_CS_SET_REAL(void *fmu, int valueId, double value, const char **error) {
737 fmi2_status_t status;
739 fmi2_value_reference_t vr = valueId;
740 status = fmi2_import_set_real((fmi2_import_t *)fmu, &vr, 1, &value);
741 if (status == fmi2_status_error || status == fmi2_status_fatal) {
742 *error = "Error happened during setting real value!";
748 double FMI1_CS_GET_REAL(void *fmu, int valueReference, const char **error) {
750 fmi1_value_reference_t vr = valueReference;
753 fmi1_status_t status;
755 status = fmi1_import_get_real((fmi1_import_t *)fmu, &vr, 1, &value);
756 if (status == fmi1_status_error || status == fmi1_status_fatal) {
757 *error = "Error happened during getting real value!";
762 double FMI2_CS_GET_REAL(void *fmu, int valueReference, const char **error) {
764 fmi2_value_reference_t vr = valueReference;
767 fmi2_status_t status;
769 status = fmi2_import_get_real((fmi2_import_t *)fmu, &vr, 1, &value);
770 if (status == fmi2_status_error || status == fmi2_status_fatal) {
771 *error = "Error happened during setting real value!";
776 int FMI1_CS_GET_REALS(void *fmu, int *valueReferences, double *result, int count, const char **error) {
778 fmi1_value_reference_t *vrs = (fmi1_value_reference_t*) valueReferences;
781 fmi1_status_t status;
783 status = fmi1_import_get_real((fmi1_import_t *)fmu, vrs, count, result);
784 if (status == fmi1_status_error || status == fmi1_status_fatal) {
785 *error = "Error happened during getting reals value!";
790 int FMI2_CS_GET_REALS(void *fmu, int *valueReferences, double *result, int count, const char **error) {
792 fmi2_value_reference_t *vrs = (fmi2_value_reference_t*) valueReferences;
795 fmi2_status_t status;
797 status = fmi2_import_get_real((fmi2_import_t *)fmu, vrs, count, result);
798 if (status == fmi2_status_error || status == fmi2_status_fatal) {
799 *error = "Error happened during getting reals value!";