From 2f1722c73a054adc1df1fcd07a61c82ad96b2063 Mon Sep 17 00:00:00 2001 From: jsimomaa Date: Thu, 24 Mar 2016 09:23:47 +0000 Subject: [PATCH] refs #6290 Compiled 64-bit FMI Library and necessary changes git-svn-id: https://www.simantics.org/svn/simantics/fmi/trunk@32613 ac1ea38d-2e2b-0410-8846-a27921b304fc --- org.simantics.fmil.feature/feature.xml | 9 +- .../native/FMUSimulator/FMUSimulator.vcxproj | 4 +- .../native/FMUSimulator/fmi_util.c.txt | 133 +++++++++++++++++- ...{fmilib_shared.lib => fmilib_shared32.lib} | Bin .../native/FMUSimulator/fmilib_shared64.lib | Bin 0 -> 119190 bytes .../src/org/simantics/fmil/FMIL.java | 2 +- .../src/org/simantics/fmil/FMILException.java | 4 + 7 files changed, 142 insertions(+), 10 deletions(-) rename org.simantics.fmil/native/FMUSimulator/{fmilib_shared.lib => fmilib_shared32.lib} (100%) create mode 100644 org.simantics.fmil/native/FMUSimulator/fmilib_shared64.lib diff --git a/org.simantics.fmil.feature/feature.xml b/org.simantics.fmil.feature/feature.xml index ea3a462..6eef9de 100644 --- a/org.simantics.fmil.feature/feature.xml +++ b/org.simantics.fmil.feature/feature.xml @@ -31,7 +31,14 @@ download-size="0" install-size="0" version="0.0.0" + fragment="true"/> + + + unpack="false"/> diff --git a/org.simantics.fmil/native/FMUSimulator/FMUSimulator.vcxproj b/org.simantics.fmil/native/FMUSimulator/FMUSimulator.vcxproj index 726cd7b..ac623b2 100644 --- a/org.simantics.fmil/native/FMUSimulator/FMUSimulator.vcxproj +++ b/org.simantics.fmil/native/FMUSimulator/FMUSimulator.vcxproj @@ -136,7 +136,7 @@ true true true - fmilib_shared.lib;%(AdditionalDependencies) + fmilib_shared32.lib;%(AdditionalDependencies) @@ -157,7 +157,7 @@ true true true - $(OutDir)zlibwapi.lib;$(OutDir)miniunz.lib;%(AdditionalDependencies) + fmilib_shared64.lib;%(AdditionalDependencies) diff --git a/org.simantics.fmil/native/FMUSimulator/fmi_util.c.txt b/org.simantics.fmil/native/FMUSimulator/fmi_util.c.txt index caab8ac..ab87846 100644 --- a/org.simantics.fmil/native/FMUSimulator/fmi_util.c.txt +++ b/org.simantics.fmil/native/FMUSimulator/fmi_util.c.txt @@ -77,6 +77,7 @@ extern "C" { typedef struct { char *name; char *description; + char *declaredType; long vr; // 0 = real // 1 = integer @@ -98,9 +99,17 @@ typedef struct { int causality; } FMIL_Variable; +typedef struct { + char *name; + char *description; + char *quantity; + char *unit; +} FMIL_DeclaredType; + __declspec(dllexport) void* FMI1_CS_LOAD(const char *zipFilePath, const char *unzipFolder); __declspec(dllexport) int FMI1_CS_UNLOAD(void* fmu); __declspec(dllexport) FMIL_Variable *FMI1_CS_GET_VARIABLES(void* fmu, int *count); +__declspec(dllexport) FMIL_DeclaredType *FMI1_CS_GET_DECLARED_TYPES(void* fmu, int *count); __declspec(dllexport) int FMI1_CS_INSTANTIATE(void* fmu); __declspec(dllexport) int FMI1_CS_INITIALIZE(void* fmu); __declspec(dllexport) int FMI1_CS_STEP(void* fmu, double masterTime, double stepSize); @@ -184,12 +193,89 @@ int FMI1_CS_UNLOAD(void *fmu_) { } +/* + 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) { 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); @@ -264,6 +350,13 @@ FMIL_Variable *FMI1_CS_GET_VARIABLES(void *fmu, int *count) { 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; + } + } } @@ -274,6 +367,38 @@ FMIL_Variable *FMI1_CS_GET_VARIABLES(void *fmu, int *count) { } +FMIL_DeclaredType *FMI1_CS_GET_DECLARED_TYPES(void *fmu, int *count) { + + 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; + +} + #define INSTANCE_NAME "kekkeli" int FMI1_CS_INSTANTIATE(void *fmu) { @@ -330,14 +455,10 @@ int FMI1_CS_STEP(void *fmu, double masterTime, double stepSize) { 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) { - printf("fmi1_capi_do_step: Failed\n"); - return 0; + return 1; } else { - printf("fmi1_capi_do_step: Success\n"); + return 0; } - - return 0; - } int FMI1_CS_SET_REAL(void *fmu, long valueId, double value) { diff --git a/org.simantics.fmil/native/FMUSimulator/fmilib_shared.lib b/org.simantics.fmil/native/FMUSimulator/fmilib_shared32.lib similarity index 100% rename from org.simantics.fmil/native/FMUSimulator/fmilib_shared.lib rename to org.simantics.fmil/native/FMUSimulator/fmilib_shared32.lib diff --git a/org.simantics.fmil/native/FMUSimulator/fmilib_shared64.lib b/org.simantics.fmil/native/FMUSimulator/fmilib_shared64.lib new file mode 100644 index 0000000000000000000000000000000000000000..191166a4115096dcb3de3e5252efb298bca7b159 GIT binary patch literal 119190 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