/* 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 . */ #include #include #include #include #include char* fmi_construct_dll_dir_name(jm_callbacks* callbacks, const char* fmu_unzipped_path) { char* dir_path; size_t len; assert( fmu_unzipped_path && callbacks); len = strlen(fmu_unzipped_path) + strlen(FMI_FILE_SEP) + strlen(FMI_BINARIES) + strlen(FMI_FILE_SEP) + strlen(FMI_PLATFORM) + strlen(FMI_FILE_SEP) + 1; dir_path = (char*)callbacks->malloc(len); if (dir_path == NULL) { jm_log_fatal(callbacks, "FMIUT", "Failed to allocate memory."); return NULL; } 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 */ return dir_path; } char* fmi_construct_dll_file_name(jm_callbacks* callbacks, const char* dll_dir_name, const char* model_identifier) { char* fname; size_t len; assert(callbacks && model_identifier); len = strlen(dll_dir_name) + strlen(model_identifier) + strlen(FMI_DLL_EXT) + 1; fname = (char*)callbacks->malloc(len); if (fname == NULL) { jm_log_fatal(callbacks, "FMIUT", "Failed to allocate memory."); return NULL; } sprintf(fname, "%s%s%s", dll_dir_name, model_identifier, FMI_DLL_EXT);/*safe */ return fname; } #include #include #include #include #include #include #ifdef __cplusplus extern "C" { #endif typedef struct { char *name; char *description; char *declaredType; long vr; /* 0 = real // 1 = integer // 2 = boolean // 3 = string // 4 = enumeration */ int type; /* 0 = constant // 1 = parameter // 2 = discrete // 3 = continuous // 4 = unknown */ int variability; /* 0 = input // 1 = output // 2 = internal // 3 = none // 4 = unknown */ int causality; } FMIL_Variable; typedef struct { char *name; char *description; char *quantity; char *unit; } FMIL_DeclaredType; #ifdef _MSC_VER #define DLLEXPORT __declspec(dllexport) #elif __GNUC__ #define DLLEXPORT __attribute__((visibility("default"))) #pragma warning Using GNUC default visibility #else #define DLLEXPORT #pragma warning Empty dynamic link EXPORT defined #endif DLLEXPORT int FMI_CS_LOAD(const char *zipFilePath, const char *unzipFolder, void **fmuPointer, int *fmuVersion, const char **error); DLLEXPORT int FMI1_CS_UNLOAD(void* fmu, const char **error); DLLEXPORT FMIL_Variable *FMI1_CS_GET_VARIABLES(void* fmu, int *count, const char **error); DLLEXPORT FMIL_DeclaredType *FMI1_CS_GET_DECLARED_TYPES(void* fmu, int *count, const char **error); DLLEXPORT int FMI1_CS_INSTANTIATE(void* fmu, const char *instanceName, const char **error); DLLEXPORT int FMI1_CS_INITIALIZE(void* fmu, const char **error); DLLEXPORT int FMI1_CS_STEP(void* fmu, double masterTime, double stepSize, const char **error); DLLEXPORT int FMI1_CS_SET_REAL(void* fmu, int vr, double value, const char **error); DLLEXPORT double FMI1_CS_GET_REAL(void* fmu, int vr, const char **error); DLLEXPORT int FMI1_CS_GET_REALS(void* fmu, int *vrs, double *values, int count, const char **error); DLLEXPORT int FMI2_CS_UNLOAD(void* fmu, const char **error); DLLEXPORT FMIL_Variable *FMI2_CS_GET_VARIABLES(void* fmu, int *count, const char **error); DLLEXPORT FMIL_DeclaredType *FMI2_CS_GET_DECLARED_TYPES(void* fmu, int *count, const char **error); DLLEXPORT int FMI2_CS_INSTANTIATE(void* fmu, const char *instanceName, const char **error); DLLEXPORT int FMI2_CS_INITIALIZE(void* fmu, const char **error); DLLEXPORT int FMI2_CS_STEP(void* fmu, double masterTime, double stepSize, const char **error); DLLEXPORT int FMI2_CS_SET_REAL(void* fmu, int vr, double value, const char **error); DLLEXPORT double FMI2_CS_GET_REAL(void* fmu, int vr, const char **error); DLLEXPORT int FMI2_CS_GET_REALS(void* fmu, int *vrs, double *values, int count, const char **error); #ifdef __cplusplus } #endif #define BUFFER 4096 /* Logger function used by the C-API */ void importlogger(jm_callbacks* c, jm_string module, jm_log_level_enu_t log_level, jm_string message) { printf("module = %s, log level = %d: %s\n", module, log_level, message); } /* Logger function used by the FMU internally */ void fmilogger(fmi1_component_t c, fmi1_string_t instanceName, fmi1_status_t status, fmi1_string_t category, fmi1_string_t message, ...) { char msg[BUFFER]; int len; va_list argp; va_start(argp, message); /*len=jm_vsnprintf(msg, BUFFER, message, argp); printf("fmiStatus = %d; %s (%s): %s\n", status, instanceName, category, msg); if(len > BUFFER) { printf("Warning: message was trancated"); }*/ } int FMI_CS_LOAD(const char *zipFilePath, const char *unzipFolder, void **fmuPointer, int *fmuVersion, const char **error) { fmi1_callback_functions_t callBackFunctions; fmi2_callback_functions_t callBackFunctions2; fmi_import_context_t* context; fmi_version_enu_t version; jm_status_enu_t status; fmi1_import_t *fmu; fmi2_import_t *fmu2; jm_callbacks* callbacks; callbacks = (jm_callbacks *)calloc(1, sizeof(jm_callbacks)); callbacks->malloc = malloc; callbacks->calloc = calloc; callbacks->realloc = realloc; callbacks->free = free; callbacks->logger = importlogger; #ifdef _DEBUG callbacks->log_level = jm_log_level_debug; #else callbacks->log_level = jm_log_level_warning; #endif callbacks->context = 0; context = fmi_import_allocate_context(callbacks); version = fmi_import_get_fmi_version(context, zipFilePath, unzipFolder); if (version == fmi_version_1_enu ) { fmu = fmi1_import_parse_xml(context, unzipFolder); 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) { *error = "Provided FMU is version 1 but wrong type me (Model Exchange) when it should be cs (Co-Simulation)"; return 2; /* wrong type, should be co-simulation */ } callBackFunctions.logger = fmilogger; callBackFunctions.allocateMemory = calloc; callBackFunctions.freeMemory = free; status = fmi1_import_create_dllfmu(fmu, callBackFunctions, 0); if (status == jm_status_error) { *error = fmi1_import_get_last_error(fmu); return 3; } *fmuPointer = fmu; *fmuVersion = 1; } else if (version == fmi_version_2_0_enu) { fmu2 = fmi2_import_parse_xml(context, unzipFolder, 0); 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) { *error = "Provided FMU is version 2.0 but wrong type me (Model Exchange) when it should be cs (Co-Simulation)"; return 2; /* wrong type, should be co-simulation */ } callBackFunctions2.logger = fmi2_log_forwarding; callBackFunctions2.allocateMemory = calloc; callBackFunctions2.freeMemory = free; callBackFunctions2.componentEnvironment = fmu2; status = fmi2_import_create_dllfmu(fmu2, fmi2_fmu_kind_cs, &callBackFunctions2); if (status == jm_status_error) { *error = fmi2_import_get_last_error(fmu2); return 3; } *fmuPointer = fmu2; *fmuVersion = 2; } fmi_import_free_context(context); return 0; /* success */ } int FMI1_CS_UNLOAD(void *fmu_, const char **error) { fmi1_import_t *fmu = (fmi1_import_t *)fmu_; fmi1_import_destroy_dllfmu(fmu); fmi1_import_free(fmu); return 0; } int FMI2_CS_UNLOAD(void *fmu_, const char **error) { fmi2_import_t *fmu = (fmi2_import_t *)fmu_; fmi2_import_destroy_dllfmu(fmu); fmi2_import_free(fmu); return 0; } /* if(!vt) { printf("No type definition\n"); return; } quan = fmi1_import_get_type_quantity(vt); printf("Type %s\n description: %s\n", fmi1_import_get_type_name(vt), fmi1_import_get_type_description(vt)); printf("Base type: %s\n", fmi1_base_type_to_string(fmi1_import_get_base_type(vt))); if(quan) { printf("Quantity: %s\n", quan); } switch(fmi1_import_get_base_type(vt)) { case fmi1_base_type_real: { fmi1_import_real_typedef_t* rt = fmi1_import_get_type_as_real(vt); fmi1_real_t min = fmi1_import_get_real_type_min(rt); fmi1_real_t max = fmi1_import_get_real_type_max(rt); fmi1_real_t nom = fmi1_import_get_real_type_nominal(rt); fmi1_import_unit_t* u = fmi1_import_get_real_type_unit(rt); fmi1_import_display_unit_t* du = fmi1_import_get_type_display_unit(rt); printf("Min %g, max %g, nominal %g\n", min, max, nom); if(u) { printf("Unit: %s\n", fmi1_import_get_unit_name(u)); } if(du) { printf("Display unit: %s, gain: %g, offset: %g, is relative: %s", fmi1_import_get_display_unit_name(du), fmi1_import_get_display_unit_gain(du), fmi1_import_get_display_unit_offset(du), fmi1_import_get_real_type_is_relative_quantity(rt)?"yes":"no" ); } break; } case fmi1_base_type_int:{ fmi1_import_integer_typedef_t* it = fmi1_import_get_type_as_int(vt); int min = fmi1_import_get_integer_type_min(it); int max = fmi1_import_get_integer_type_max(it); printf("Min %d, max %d\n", min, max); break; } case fmi1_base_type_bool:{ break; } case fmi1_base_type_str:{ break; } case fmi1_base_type_enum:{ fmi1_import_enumeration_typedef_t* et = fmi1_import_get_type_as_enum(vt); int min = fmi1_import_get_enum_type_min(et); int max = fmi1_import_get_enum_type_max(et); printf("Min %d, max %d\n", min, max); { size_t ni; unsigned i; ni = fmi1_import_get_enum_type_size(et); i = (unsigned)(ni); assert( i == ni); printf("There are %u items \n",(unsigned)ni); for(i = 0; i < ni; i++) { 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)); } } break; } default: printf("Error in fmiGetBaseType()\n"); } */ FMIL_Variable *FMI1_CS_GET_VARIABLES(void *fmu, int *count, const char **error) { int i; FMIL_Variable *result; fmi1_import_variable_list_t* vl = fmi1_import_get_variable_list((fmi1_import_t *)fmu); fmi1_import_variable_typedef_t* type; count[0] = fmi1_import_get_variable_list_size(vl); result = (FMIL_Variable *)malloc(count[0]*sizeof(FMIL_Variable)); for(i = 0; i < count[0]; i++) { fmi1_import_variable_t* var = fmi1_import_get_variable(vl, i); if(!var) { printf("Something wrong with variable %d \n",i); return 0; } else { result[i].name = fmi1_import_get_variable_name(var); result[i].description = fmi1_import_get_variable_description(var); switch (fmi1_import_get_variability(var)) { case fmi1_variability_enu_constant: result[i].variability = 0; break; case fmi1_variability_enu_parameter: result[i].variability = 1; break; case fmi1_variability_enu_discrete: result[i].variability = 2; break; case fmi1_variability_enu_continuous: result[i].variability = 3; break; case fmi1_variability_enu_unknown: result[i].variability = 4; break; } switch (fmi1_import_get_causality(var)) { case fmi1_causality_enu_input: result[i].causality = 0; break; case fmi1_causality_enu_output: result[i].causality = 1; break; case fmi1_causality_enu_internal: result[i].causality = 2; break; case fmi1_causality_enu_none: result[i].causality = 3; break; case fmi1_causality_enu_unknown: result[i].causality = 4; break; } switch (fmi1_import_get_variable_base_type(var)) { case fmi1_base_type_real: result[i].type = 0; break; case fmi1_base_type_int: result[i].type = 1; break; case fmi1_base_type_bool: result[i].type = 2; break; case fmi1_base_type_str: result[i].type = 3; break; case fmi1_base_type_enum: result[i].type = 4; break; } result[i].vr = fmi1_import_get_variable_vr(var); type = fmi1_import_get_variable_declared_type(var); if(type) { result[i].declaredType = fmi1_import_get_type_name(type); } else { result[i].declaredType = 0; } } } fmi1_import_free_variable_list(vl); return result; } FMIL_Variable *FMI2_CS_GET_VARIABLES(void *fmu, int *count, const char **error) { int i; FMIL_Variable *result; fmi2_import_variable_list_t* vl = fmi2_import_get_variable_list((fmi2_import_t *)fmu, 0); fmi2_import_variable_typedef_t* type; count[0] = fmi2_import_get_variable_list_size(vl); result = (FMIL_Variable *)malloc(count[0]*sizeof(FMIL_Variable)); for(i = 0; i < count[0]; i++) { fmi2_import_variable_t* var = fmi2_import_get_variable(vl, i); if(!var) { printf("Something wrong with variable %d \n",i); return 0; } else { result[i].name = fmi2_import_get_variable_name(var); result[i].description = fmi2_import_get_variable_description(var); switch (fmi2_import_get_variability(var)) { case fmi2_variability_enu_constant: result[i].variability = 0; break; case fmi2_variability_enu_fixed: case fmi2_variability_enu_tunable: result[i].variability = 1; break; case fmi2_variability_enu_discrete: result[i].variability = 2; break; case fmi2_variability_enu_continuous: result[i].variability = 3; break; case fmi2_variability_enu_unknown: result[i].variability = 4; break; } switch (fmi2_import_get_causality(var)) { case fmi2_causality_enu_input: result[i].causality = 0; break; case fmi2_causality_enu_output: result[i].causality = 1; break; case fmi2_causality_enu_local: result[i].causality = 2; break; case fmi2_causality_enu_independent: result[i].causality = 3; break; case fmi2_causality_enu_unknown: result[i].causality = 4; break; } switch (fmi2_import_get_variable_base_type(var)) { case fmi2_base_type_real: result[i].type = 0; break; case fmi2_base_type_int: result[i].type = 1; break; case fmi2_base_type_bool: result[i].type = 2; break; case fmi2_base_type_str: result[i].type = 3; break; case fmi2_base_type_enum: result[i].type = 4; break; } result[i].vr = fmi2_import_get_variable_vr(var); type = fmi2_import_get_variable_declared_type(var); if(type) { result[i].declaredType = fmi2_import_get_type_name(type); } else { result[i].declaredType = 0; } } } fmi2_import_free_variable_list(vl); return result; } FMIL_DeclaredType *FMI1_CS_GET_DECLARED_TYPES(void *fmu, int *count, const char **error) { FMIL_DeclaredType *result; fmi1_import_type_definitions_t* td = fmi1_import_get_type_definitions((fmi1_import_t *)fmu); fmi1_import_variable_typedef_t* type; unsigned i, ntd = (unsigned)fmi1_import_get_type_definition_number(td); count[0] = ntd; result = (FMIL_DeclaredType *)malloc(count[0]*sizeof(FMIL_DeclaredType)); for(i = 0; i < ntd; i++) { type = fmi1_import_get_typedef(td, i); result[i].name = fmi1_import_get_type_name(type); result[i].description = fmi1_import_get_type_description(type); result[i].quantity = fmi1_import_get_type_quantity(type); result[i].unit = 0; switch(fmi1_import_get_base_type(type)) { case fmi1_base_type_real: { fmi1_import_real_typedef_t* rt = fmi1_import_get_type_as_real(type); fmi1_import_unit_t* u = fmi1_import_get_real_type_unit(rt); if(u) result[i].unit = fmi1_import_get_unit_name(u); } } } return result; } FMIL_DeclaredType *FMI2_CS_GET_DECLARED_TYPES(void *fmu, int *count, const char **error) { FMIL_DeclaredType *result; fmi2_import_type_definitions_t* td = fmi2_import_get_type_definitions((fmi2_import_t *)fmu); fmi2_import_variable_typedef_t* type; unsigned i, ntd = (unsigned)fmi2_import_get_type_definition_number(td); count[0] = ntd; result = (FMIL_DeclaredType *)malloc(count[0]*sizeof(FMIL_DeclaredType)); for(i = 0; i < ntd; i++) { type = fmi2_import_get_typedef(td, i); result[i].name = fmi2_import_get_type_name(type); result[i].description = fmi2_import_get_type_description(type); result[i].quantity = fmi2_import_get_type_quantity(type); result[i].unit = 0; switch(fmi2_import_get_base_type(type)) { case fmi2_base_type_real: { fmi2_import_real_typedef_t* rt = fmi2_import_get_type_as_real(type); fmi2_import_unit_t* u = fmi2_import_get_real_type_unit(rt); if(u) result[i].unit = fmi2_import_get_unit_name(u); } } } return result; } int FMI1_CS_INSTANTIATE(void *fmu, const char *instanceName, const char **error) { fmi1_string_t fmuLocation; fmi1_string_t mimeType; fmi1_real_t timeout; fmi1_boolean_t visible; fmi1_boolean_t interactive; fmi1_boolean_t loggingOn; jm_status_enu_t jmstatus; fmuLocation = ""; mimeType = ""; timeout = 0; visible = fmi1_false; interactive = fmi1_false; loggingOn = fmi1_true; jmstatus = fmi1_import_instantiate_slave((fmi1_import_t*)fmu, instanceName, NULL, NULL, timeout, fmi1_false, fmi1_false); if (jmstatus == jm_status_error) { *error = fmi1_import_get_last_error((fmi1_import_t*)fmu); return 1; } return 0; } int FMI2_CS_INSTANTIATE(void *fmu, const char *instanceName, const char **error) { fmi2_string_t fmuLocation; fmi2_string_t mimeType; fmi2_real_t timeout; fmi2_boolean_t visible; fmi2_boolean_t interactive; fmi2_boolean_t loggingOn; jm_status_enu_t jmstatus; fmuLocation = ""; mimeType = ""; timeout = 0; visible = fmi2_false; jmstatus = fmi2_import_instantiate((fmi2_import_t*)fmu, instanceName, fmi2_cosimulation, NULL, visible); if (jmstatus == jm_status_error) { *error = fmi2_import_get_last_error((fmi2_import_t*)fmu); return 1; } return 0; } int FMI1_CS_INITIALIZE(void *fmu, const char **error) { fmi1_status_t status; fmi1_real_t tStart; fmi1_real_t tStop; fmi1_boolean_t StopTimeDefined; tStart = 0; tStop = 10; StopTimeDefined = fmi1_false; status = fmi1_import_initialize_slave((fmi1_import_t *)fmu, tStart, StopTimeDefined, tStop); if (status == fmi1_status_error || status == fmi1_status_fatal) { printf("fmi1_capi_initialize_slave: Failed\n"); return 0; } else { printf("fmi1_capi_initialize_slave: Success\n"); } return 0; } int FMI2_CS_INITIALIZE(void *fmu, const char **error) { fmi2_real_t tStart; fmi2_real_t tStop; fmi2_boolean_t StopTimeDefined; fmi2_real_t relativeTol = 1e-4; fmi2_status_t fmistatus; tStart = 0; tStop = 10; StopTimeDefined = fmi1_false; fmistatus = fmi2_import_setup_experiment((fmi2_import_t*)fmu, fmi2_true, relativeTol, tStart, StopTimeDefined, tStop); if(fmistatus != fmi2_status_ok) { *error = ("fmi2_import_setup_experiment failed\n"); return 1; } fmistatus = fmi2_import_enter_initialization_mode((fmi2_import_t*)fmu); if(fmistatus != fmi2_status_ok) { *error = ("fmi2_import_enter_initialization_mode failed\n"); return 1; } fmistatus = fmi2_import_exit_initialization_mode((fmi2_import_t*)fmu); if(fmistatus != fmi2_status_ok) { *error = ("fmi2_import_exit_initialization_mode failed\n"); return 1; } return 0; } int FMI1_CS_STEP(void *fmu, double masterTime, double stepSize, const char **error) { fmi1_status_t status; status = fmi1_import_do_step((fmi1_import_t *)fmu, (fmi1_real_t)masterTime, (fmi1_real_t)stepSize, fmi1_true); if (status == fmi1_status_error || status == fmi1_status_fatal) { *error = "Error happened during stepping!"; return 1; } return 0; } int FMI2_CS_STEP(void *fmu, double masterTime, double stepSize, const char **error) { fmi2_status_t status; status = fmi2_import_do_step((fmi2_import_t *)fmu, (fmi2_real_t)masterTime, (fmi2_real_t)stepSize, fmi2_true); if (status == fmi2_status_error || status == fmi2_status_fatal) { *error = "Error happened during stepping!"; return 1; } return 0; } int FMI1_CS_SET_REAL(void *fmu, int valueId, double value, const char **error) { fmi1_status_t status; fmi1_value_reference_t vr = valueId; status = fmi1_import_set_real((fmi1_import_t *)fmu, &vr, 1, &value); if (status == fmi1_status_error || status == fmi1_status_fatal) { *error = "Error happened during setting real value!"; return 1; } return 0; } int FMI2_CS_SET_REAL(void *fmu, int valueId, double value, const char **error) { fmi2_status_t status; fmi2_value_reference_t vr = valueId; status = fmi2_import_set_real((fmi2_import_t *)fmu, &vr, 1, &value); if (status == fmi2_status_error || status == fmi2_status_fatal) { *error = "Error happened during setting real value!"; return 1; } return 0; } double FMI1_CS_GET_REAL(void *fmu, int valueReference, const char **error) { fmi1_value_reference_t vr = valueReference; fmi1_real_t value; fmi1_status_t status; status = fmi1_import_get_real((fmi1_import_t *)fmu, &vr, 1, &value); if (status == fmi1_status_error || status == fmi1_status_fatal) { *error = "Error happened during getting real value!"; } return value; } double FMI2_CS_GET_REAL(void *fmu, int valueReference, const char **error) { fmi2_value_reference_t vr = valueReference; fmi2_real_t value; fmi2_status_t status; status = fmi2_import_get_real((fmi2_import_t *)fmu, &vr, 1, &value); if (status == fmi2_status_error || status == fmi2_status_fatal) { *error = "Error happened during setting real value!"; } return value; } int FMI1_CS_GET_REALS(void *fmu, int *valueReferences, double *result, int count, const char **error) { fmi1_value_reference_t *vrs = (fmi1_value_reference_t*) valueReferences; fmi1_real_t value; fmi1_status_t status; status = fmi1_import_get_real((fmi1_import_t *)fmu, vrs, count, result); if (status == fmi1_status_error || status == fmi1_status_fatal) { *error = "Error happened during getting reals value!"; } return 0; } int FMI2_CS_GET_REALS(void *fmu, int *valueReferences, double *result, int count, const char **error) { fmi2_value_reference_t *vrs = (fmi2_value_reference_t*) valueReferences; fmi2_real_t value; fmi2_status_t status; status = fmi2_import_get_real((fmi2_import_t *)fmu, vrs, count, result); if (status == fmi2_status_error || status == fmi2_status_fatal) { *error = "Error happened during getting reals value!"; } return 0; }