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>
22 char* fmi_construct_dll_dir_name(jm_callbacks* callbacks, const char* fmu_unzipped_path) {
26 assert( fmu_unzipped_path && callbacks);
29 strlen(fmu_unzipped_path) + strlen(FMI_FILE_SEP)
30 + strlen(FMI_BINARIES) + strlen(FMI_FILE_SEP)
31 + strlen(FMI_PLATFORM) + strlen(FMI_FILE_SEP) + 1;
33 dir_path = (char*)callbacks->malloc(len);
34 if (dir_path == NULL) {
35 jm_log_fatal(callbacks, "FMIUT", "Failed to allocate memory.");
39 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 */
44 char* fmi_construct_dll_file_name(jm_callbacks* callbacks, const char* dll_dir_name, const char* model_identifier) {
47 assert(callbacks && model_identifier);
49 strlen(dll_dir_name) +
50 strlen(model_identifier)
51 + strlen(FMI_DLL_EXT) + 1;
52 fname = (char*)callbacks->malloc(len);
54 jm_log_fatal(callbacks, "FMIUT", "Failed to allocate memory.");
57 sprintf(fname, "%s%s%s", dll_dir_name, model_identifier, FMI_DLL_EXT);/*safe */
108 __declspec(dllexport) int FMI_CS_LOAD(const char *zipFilePath, const char *unzipFolder, void **fmuPointer, int *fmuVersion, const char **error);
110 __declspec(dllexport) int FMI1_CS_UNLOAD(void* fmu, const char **error);
111 __declspec(dllexport) FMIL_Variable *FMI1_CS_GET_VARIABLES(void* fmu, int *count, const char **error);
112 __declspec(dllexport) FMIL_DeclaredType *FMI1_CS_GET_DECLARED_TYPES(void* fmu, int *count, const char **error);
113 __declspec(dllexport) int FMI1_CS_INSTANTIATE(void* fmu, const char *instanceName, const char **error);
114 __declspec(dllexport) int FMI1_CS_INITIALIZE(void* fmu, const char **error);
115 __declspec(dllexport) int FMI1_CS_STEP(void* fmu, double masterTime, double stepSize, const char **error);
116 __declspec(dllexport) int FMI1_CS_SET_REAL(void* fmu, int vr, double value, const char **error);
117 __declspec(dllexport) double FMI1_CS_GET_REAL(void* fmu, int vr, const char **error);
118 __declspec(dllexport) int FMI1_CS_GET_REALS(void* fmu, int *vrs, double *values, int count, const char **error);
120 __declspec(dllexport) int FMI2_CS_UNLOAD(void* fmu, const char **error);
121 __declspec(dllexport) FMIL_Variable *FMI2_CS_GET_VARIABLES(void* fmu, int *count, const char **error);
122 __declspec(dllexport) FMIL_DeclaredType *FMI2_CS_GET_DECLARED_TYPES(void* fmu, int *count, const char **error);
123 __declspec(dllexport) int FMI2_CS_INSTANTIATE(void* fmu, const char *instanceName, const char **error);
124 __declspec(dllexport) int FMI2_CS_INITIALIZE(void* fmu, const char **error);
125 __declspec(dllexport) int FMI2_CS_STEP(void* fmu, double masterTime, double stepSize, const char **error);
126 __declspec(dllexport) int FMI2_CS_SET_REAL(void* fmu, int vr, double value, const char **error);
127 __declspec(dllexport) double FMI2_CS_GET_REAL(void* fmu, int vr, const char **error);
128 __declspec(dllexport) int FMI2_CS_GET_REALS(void* fmu, int *vrs, double *values, int count, const char **error);
136 /* Logger function used by the C-API */
137 void importlogger(jm_callbacks* c, jm_string module, jm_log_level_enu_t log_level, jm_string message)
139 printf("module = %s, log level = %d: %s\n", module, log_level, message);
142 /* Logger function used by the FMU internally */
143 void fmilogger(fmi1_component_t c, fmi1_string_t instanceName, fmi1_status_t status, fmi1_string_t category, fmi1_string_t message, ...)
148 va_start(argp, message);
149 /*len=jm_vsnprintf(msg, BUFFER, message, argp);
150 printf("fmiStatus = %d; %s (%s): %s\n", status, instanceName, category, msg);
152 printf("Warning: message was trancated");
156 int FMI_CS_LOAD(char *zipFilePath, char *unzipFolder, void **fmuPointer, int *fmuVersion, const char **error) {
158 fmi1_callback_functions_t callBackFunctions;
159 fmi2_callback_functions_t callBackFunctions2;
160 fmi_import_context_t* context;
161 fmi_version_enu_t version;
162 jm_status_enu_t status;
165 jm_callbacks* callbacks;
167 callbacks = (jm_callbacks *)calloc(1, sizeof(jm_callbacks));
169 callbacks->malloc = malloc;
170 callbacks->calloc = calloc;
171 callbacks->realloc = realloc;
172 callbacks->free = free;
173 callbacks->logger = importlogger;
174 callbacks->log_level = jm_log_level_debug;
175 callbacks->context = 0;
177 context = fmi_import_allocate_context(callbacks);
179 version = fmi_import_get_fmi_version(context, zipFilePath, unzipFolder);
181 if (version == fmi_version_1_enu ) {
182 fmu = fmi1_import_parse_xml(context, unzipFolder);
183 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) {
184 *error = "Provided FMU is version 1 but wrong type me (Model Exchange) when it should be cs (Co-Simulation)";
185 return 2; // wrong type, should be co-simulation
188 callBackFunctions.logger = fmilogger;
189 callBackFunctions.allocateMemory = calloc;
190 callBackFunctions.freeMemory = free;
192 status = fmi1_import_create_dllfmu(fmu, callBackFunctions, 0);
193 if (status == jm_status_error) {
194 *error = fmi1_import_get_last_error(fmu);
200 } else if (version == fmi_version_2_0_enu) {
201 fmu2 = fmi2_import_parse_xml(context, unzipFolder, 0);
203 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) {
204 *error = "Provided FMU is version 2.0 but wrong type me (Model Exchange) when it should be cs (Co-Simulation)";
205 return 2; // wrong type, should be co-simulation
208 callBackFunctions2.logger = fmi2_log_forwarding;
209 callBackFunctions2.allocateMemory = calloc;
210 callBackFunctions2.freeMemory = free;
211 callBackFunctions2.componentEnvironment = fmu2;
213 status = fmi2_import_create_dllfmu(fmu2, fmi2_fmu_kind_cs, &callBackFunctions2);
214 if (status == jm_status_error) {
215 *error = fmi2_import_get_last_error(fmu2);
223 fmi_import_free_context(context);
228 int FMI1_CS_UNLOAD(void *fmu_, const char **error) {
229 fmi1_import_t *fmu = (fmi1_import_t *)fmu_;
230 fmi1_import_destroy_dllfmu(fmu);
231 fmi1_import_free(fmu);
235 int FMI2_CS_UNLOAD(void *fmu_, const char **error) {
236 fmi2_import_t *fmu = (fmi2_import_t *)fmu_;
237 fmi2_import_destroy_dllfmu(fmu);
238 fmi2_import_free(fmu);
244 printf("No type definition\n");
248 quan = fmi1_import_get_type_quantity(vt);
250 printf("Type %s\n description: %s\n", fmi1_import_get_type_name(vt), fmi1_import_get_type_description(vt));
252 printf("Base type: %s\n", fmi1_base_type_to_string(fmi1_import_get_base_type(vt)));
255 printf("Quantity: %s\n", quan);
257 switch(fmi1_import_get_base_type(vt)) {
258 case fmi1_base_type_real: {
259 fmi1_import_real_typedef_t* rt = fmi1_import_get_type_as_real(vt);
260 fmi1_real_t min = fmi1_import_get_real_type_min(rt);
261 fmi1_real_t max = fmi1_import_get_real_type_max(rt);
262 fmi1_real_t nom = fmi1_import_get_real_type_nominal(rt);
263 fmi1_import_unit_t* u = fmi1_import_get_real_type_unit(rt);
264 fmi1_import_display_unit_t* du = fmi1_import_get_type_display_unit(rt);
266 printf("Min %g, max %g, nominal %g\n", min, max, nom);
269 printf("Unit: %s\n", fmi1_import_get_unit_name(u));
272 printf("Display unit: %s, gain: %g, offset: %g, is relative: %s",
273 fmi1_import_get_display_unit_name(du),
274 fmi1_import_get_display_unit_gain(du),
275 fmi1_import_get_display_unit_offset(du),
276 fmi1_import_get_real_type_is_relative_quantity(rt)?"yes":"no"
282 case fmi1_base_type_int:{
283 fmi1_import_integer_typedef_t* it = fmi1_import_get_type_as_int(vt);
284 int min = fmi1_import_get_integer_type_min(it);
285 int max = fmi1_import_get_integer_type_max(it);
286 printf("Min %d, max %d\n", min, max);
289 case fmi1_base_type_bool:{
292 case fmi1_base_type_str:{
295 case fmi1_base_type_enum:{
296 fmi1_import_enumeration_typedef_t* et = fmi1_import_get_type_as_enum(vt);
297 int min = fmi1_import_get_enum_type_min(et);
298 int max = fmi1_import_get_enum_type_max(et);
299 printf("Min %d, max %d\n", min, max);
303 ni = fmi1_import_get_enum_type_size(et);
306 printf("There are %u items \n",(unsigned)ni);
307 for(i = 0; i < ni; i++) {
308 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));
314 printf("Error in fmiGetBaseType()\n");
319 FMIL_Variable *FMI1_CS_GET_VARIABLES(void *fmu, int *count, const char **error) {
322 FMIL_Variable *result;
323 fmi1_import_variable_list_t* vl = fmi1_import_get_variable_list((fmi1_import_t *)fmu);
324 fmi1_import_variable_typedef_t* type;
326 count[0] = fmi1_import_get_variable_list_size(vl);
328 result = (FMIL_Variable *)malloc(count[0]*sizeof(FMIL_Variable));
330 for(i = 0; i < count[0]; i++) {
332 fmi1_import_variable_t* var = fmi1_import_get_variable(vl, i);
335 printf("Something wrong with variable %d \n",i);
340 result[i].name = fmi1_import_get_variable_name(var);
341 result[i].description = fmi1_import_get_variable_description(var);
343 switch (fmi1_import_get_variability(var)) {
344 case fmi1_variability_enu_constant:
345 result[i].variability = 0;
347 case fmi1_variability_enu_parameter:
348 result[i].variability = 1;
350 case fmi1_variability_enu_discrete:
351 result[i].variability = 2;
353 case fmi1_variability_enu_continuous:
354 result[i].variability = 3;
356 case fmi1_variability_enu_unknown:
357 result[i].variability = 4;
361 switch (fmi1_import_get_causality(var)) {
362 case fmi1_causality_enu_input:
363 result[i].causality = 0;
365 case fmi1_causality_enu_output:
366 result[i].causality = 1;
368 case fmi1_causality_enu_internal:
369 result[i].causality = 2;
371 case fmi1_causality_enu_none:
372 result[i].causality = 3;
374 case fmi1_causality_enu_unknown:
375 result[i].causality = 4;
379 switch (fmi1_import_get_variable_base_type(var)) {
380 case fmi1_base_type_real:
383 case fmi1_base_type_int:
386 case fmi1_base_type_bool:
389 case fmi1_base_type_str:
392 case fmi1_base_type_enum:
397 result[i].vr = fmi1_import_get_variable_vr(var);
399 type = fmi1_import_get_variable_declared_type(var);
401 result[i].declaredType = fmi1_import_get_type_name(type);
403 result[i].declaredType = 0;
410 fmi1_import_free_variable_list(vl);
416 FMIL_Variable *FMI2_CS_GET_VARIABLES(void *fmu, int *count, const char **error) {
419 FMIL_Variable *result;
420 fmi2_import_variable_list_t* vl = fmi2_import_get_variable_list((fmi2_import_t *)fmu, 0);
421 fmi2_import_variable_typedef_t* type;
423 count[0] = fmi2_import_get_variable_list_size(vl);
425 result = (FMIL_Variable *)malloc(count[0]*sizeof(FMIL_Variable));
427 for(i = 0; i < count[0]; i++) {
429 fmi2_import_variable_t* var = fmi2_import_get_variable(vl, i);
432 printf("Something wrong with variable %d \n",i);
437 result[i].name = fmi2_import_get_variable_name(var);
438 result[i].description = fmi2_import_get_variable_description(var);
440 switch (fmi2_import_get_variability(var)) {
441 case fmi2_variability_enu_constant:
442 result[i].variability = 0;
444 case fmi2_variability_enu_fixed:
445 case fmi2_variability_enu_tunable:
446 result[i].variability = 1;
448 case fmi2_variability_enu_discrete:
449 result[i].variability = 2;
451 case fmi2_variability_enu_continuous:
452 result[i].variability = 3;
454 case fmi2_variability_enu_unknown:
455 result[i].variability = 4;
459 switch (fmi2_import_get_causality(var)) {
460 case fmi2_causality_enu_input:
461 result[i].causality = 0;
463 case fmi2_causality_enu_output:
464 result[i].causality = 1;
466 case fmi2_causality_enu_local:
467 result[i].causality = 2;
469 case fmi2_causality_enu_independent:
470 result[i].causality = 3;
472 case fmi2_causality_enu_unknown:
473 result[i].causality = 4;
477 switch (fmi2_import_get_variable_base_type(var)) {
478 case fmi2_base_type_real:
481 case fmi2_base_type_int:
484 case fmi2_base_type_bool:
487 case fmi2_base_type_str:
490 case fmi2_base_type_enum:
495 result[i].vr = fmi2_import_get_variable_vr(var);
497 type = fmi2_import_get_variable_declared_type(var);
499 result[i].declaredType = fmi2_import_get_type_name(type);
501 result[i].declaredType = 0;
508 fmi2_import_free_variable_list(vl);
514 FMIL_DeclaredType *FMI1_CS_GET_DECLARED_TYPES(void *fmu, int *count, const char **error) {
516 FMIL_DeclaredType *result;
517 fmi1_import_type_definitions_t* td = fmi1_import_get_type_definitions((fmi1_import_t *)fmu);
518 fmi1_import_variable_typedef_t* type;
519 unsigned i, ntd = (unsigned)fmi1_import_get_type_definition_number(td);
523 result = (FMIL_DeclaredType *)malloc(count[0]*sizeof(FMIL_DeclaredType));
525 for(i = 0; i < ntd; i++) {
526 type = fmi1_import_get_typedef(td, i);
527 result[i].name = fmi1_import_get_type_name(type);
528 result[i].description = fmi1_import_get_type_description(type);
529 result[i].quantity = fmi1_import_get_type_quantity(type);
532 switch(fmi1_import_get_base_type(type)) {
533 case fmi1_base_type_real: {
534 fmi1_import_real_typedef_t* rt = fmi1_import_get_type_as_real(type);
535 fmi1_import_unit_t* u = fmi1_import_get_real_type_unit(rt);
536 if(u) result[i].unit = fmi1_import_get_unit_name(u);
546 FMIL_DeclaredType *FMI2_CS_GET_DECLARED_TYPES(void *fmu, int *count, const char **error) {
548 FMIL_DeclaredType *result;
549 fmi2_import_type_definitions_t* td = fmi2_import_get_type_definitions((fmi2_import_t *)fmu);
550 fmi2_import_variable_typedef_t* type;
551 unsigned i, ntd = (unsigned)fmi2_import_get_type_definition_number(td);
555 result = (FMIL_DeclaredType *)malloc(count[0]*sizeof(FMIL_DeclaredType));
557 for(i = 0; i < ntd; i++) {
558 type = fmi2_import_get_typedef(td, i);
559 result[i].name = fmi2_import_get_type_name(type);
560 result[i].description = fmi2_import_get_type_description(type);
561 result[i].quantity = fmi2_import_get_type_quantity(type);
564 switch(fmi2_import_get_base_type(type)) {
565 case fmi2_base_type_real: {
566 fmi2_import_real_typedef_t* rt = fmi2_import_get_type_as_real(type);
567 fmi2_import_unit_t* u = fmi2_import_get_real_type_unit(rt);
568 if(u) result[i].unit = fmi2_import_get_unit_name(u);
578 int FMI1_CS_INSTANTIATE(void *fmu, const char *instanceName, const char **error) {
580 fmi1_string_t fmuLocation;
581 fmi1_string_t mimeType;
583 fmi1_boolean_t visible;
584 fmi1_boolean_t interactive;
585 fmi1_boolean_t loggingOn;
587 jm_status_enu_t jmstatus;
592 visible = fmi1_false;
593 interactive = fmi1_false;
594 loggingOn = fmi1_true;
596 jmstatus = fmi1_import_instantiate_slave((fmi1_import_t*)fmu, instanceName, NULL, NULL, timeout, fmi1_false, fmi1_false);
597 if (jmstatus == jm_status_error) {
598 *error = fmi1_import_get_last_error((fmi1_import_t*)fmu);
604 int FMI2_CS_INSTANTIATE(void *fmu, const char *instanceName, const char **error) {
606 fmi2_string_t fmuLocation;
607 fmi2_string_t mimeType;
609 fmi2_boolean_t visible;
610 fmi2_boolean_t interactive;
611 fmi2_boolean_t loggingOn;
612 jm_status_enu_t jmstatus;
617 visible = fmi2_false;
618 jmstatus = fmi2_import_instantiate((fmi2_import_t*)fmu, instanceName, fmi2_cosimulation, NULL, visible);
619 if (jmstatus == jm_status_error) {
620 *error = fmi2_import_get_last_error((fmi2_import_t*)fmu);
626 int FMI1_CS_INITIALIZE(void *fmu, const char **error) {
628 fmi1_status_t status;
631 fmi1_boolean_t StopTimeDefined;
635 StopTimeDefined = fmi1_false;
637 status = fmi1_import_initialize_slave((fmi1_import_t *)fmu, tStart, StopTimeDefined, tStop);
638 if (status == fmi1_status_error || status == fmi1_status_fatal) {
639 printf("fmi1_capi_initialize_slave: Failed\n");
642 printf("fmi1_capi_initialize_slave: Success\n");
648 int FMI2_CS_INITIALIZE(void *fmu, const char **error) {
652 fmi2_boolean_t StopTimeDefined;
653 fmi2_real_t relativeTol = 1e-4;
655 fmi2_status_t fmistatus;
659 StopTimeDefined = fmi1_false;
661 fmistatus = fmi2_import_setup_experiment((fmi2_import_t*)fmu, fmi2_true, relativeTol, tStart, StopTimeDefined, tStop);
662 if(fmistatus != fmi2_status_ok) {
663 *error = ("fmi2_import_setup_experiment failed\n");
667 fmistatus = fmi2_import_enter_initialization_mode((fmi2_import_t*)fmu);
668 if(fmistatus != fmi2_status_ok) {
669 *error = ("fmi2_import_enter_initialization_mode failed\n");
673 fmistatus = fmi2_import_exit_initialization_mode((fmi2_import_t*)fmu);
674 if(fmistatus != fmi2_status_ok) {
675 *error = ("fmi2_import_exit_initialization_mode failed\n");
682 int FMI1_CS_STEP(void *fmu, double masterTime, double stepSize, const char **error) {
684 fmi1_status_t status;
686 status = fmi1_import_do_step((fmi1_import_t *)fmu, (fmi1_real_t)masterTime, (fmi1_real_t)stepSize, fmi1_true);
687 if (status == fmi1_status_error || status == fmi1_status_fatal) {
688 *error = "Error happened during stepping!";
694 int FMI2_CS_STEP(void *fmu, double masterTime, double stepSize, const char **error) {
696 fmi2_status_t status;
698 status = fmi2_import_do_step((fmi2_import_t *)fmu, (fmi2_real_t)masterTime, (fmi2_real_t)stepSize, fmi2_true);
699 if (status == fmi2_status_error || status == fmi2_status_fatal) {
700 *error = "Error happened during stepping!";
706 int FMI1_CS_SET_REAL(void *fmu, long valueId, double value, const char **error) {
708 fmi1_status_t status;
710 fmi1_value_reference_t vr = valueId;
711 status = fmi1_import_set_real((fmi1_import_t *)fmu, &vr, 1, &value);
712 if (status == fmi1_status_error || status == fmi1_status_fatal) {
713 *error = "Error happened during setting real value!";
719 int FMI2_CS_SET_REAL(void *fmu, long valueId, double value, const char **error) {
721 fmi2_status_t status;
723 fmi2_value_reference_t vr = valueId;
724 status = fmi2_import_set_real((fmi2_import_t *)fmu, &vr, 1, &value);
725 if (status == fmi2_status_error || status == fmi2_status_fatal) {
726 *error = "Error happened during setting real value!";
732 double FMI1_CS_GET_REAL(void *fmu, int valueReference, const char **error) {
734 fmi1_value_reference_t vr = valueReference;
737 fmi1_status_t status;
739 status = fmi1_import_get_real((fmi1_import_t *)fmu, &vr, 1, &value);
740 if (status == fmi1_status_error || status == fmi1_status_fatal) {
741 *error = "Error happened during getting real value!";
746 double FMI2_CS_GET_REAL(void *fmu, int valueReference, const char **error) {
748 fmi2_value_reference_t vr = valueReference;
751 fmi2_status_t status;
753 status = fmi2_import_get_real((fmi2_import_t *)fmu, &vr, 1, &value);
754 if (status == fmi2_status_error || status == fmi2_status_fatal) {
755 *error = "Error happened during setting real value!";
760 int FMI1_CS_GET_REALS(void *fmu, int *valueReferences, double *result, int count, const char **error) {
762 fmi1_value_reference_t *vrs = valueReferences;
765 fmi1_status_t status;
767 status = fmi1_import_get_real((fmi1_import_t *)fmu, vrs, count, result);
768 if (status == fmi1_status_error || status == fmi1_status_fatal) {
769 *error = "Error happened during getting reals value!";
774 int FMI2_CS_GET_REALS(void *fmu, int *valueReferences, double *result, int count, const char **error) {
776 fmi2_value_reference_t *vrs = valueReferences;
779 fmi2_status_t status;
781 status = fmi2_import_get_real((fmi2_import_t *)fmu, vrs, count, result);
782 if (status == fmi2_status_error || status == fmi2_status_fatal) {
783 *error = "Error happened during getting reals value!";