]> gerrit.simantics Code Review - simantics/fmil.git/blobdiff - org.simantics.fmil.core/native/FMUSimulator/src/fmu_control.cpp
Pending status can be returns from FMU to Native C to Java
[simantics/fmil.git] / org.simantics.fmil.core / native / FMUSimulator / src / fmu_control.cpp
index c5c99412d644fc8752d99d039043115d982a8e1a..28e75f74c2b3a4c7dde14119cea95a1be1885902 100644 (file)
-/* ------------------------------------------------------------------------- \r
- * fmu_control.c\r
- * Simulation controls for fmus\r
- *\r
- * Free libraries and tools used to implement this simulator:\r
- *  - header files from the FMU specification\r
- *  - eXpat 2.0.1 XML parser, see http://expat.sourceforge.net\r
- *  - 7z.exe 4.57 zip and unzip tool, see http://www.7-zip.org <---------- Replace with zlib\r
- * Author: Teemu Lempinen\r
- * Copyright 2012 Semantum Oy\r
- * -------------------------------------------------------------------------\r
- */\r
-\r
-#include <stdlib.h>\r
-#include <stdio.h>\r
-#include <string.h>\r
-#include <map>\r
-#include <string>\r
-#include <vector>\r
-#include <iostream>\r
-#include <regex>\r
-\r
-#include <org_simantics_fmil_FMILJNI.h>\r
-\r
-extern "C" {\r
-       #include "fmi_me.h"\r
-       #include "sim_support.h"\r
-}\r
-\r
-#include "fmi1_cs.h"\r
-\r
-#define PRINT(fmt,args) { FILE *fp = fopen("R:\\Simantics\\Sysdyn\\log.txt", "ab"); fprintf(fp, fmt, args); fclose(fp); }\r
-\r
-#include <direct.h>\r
-#define GetCurrentDir _getcwd\r
-\r
-using namespace std;\r
-\r
-struct FMI1 {\r
-\r
-       void *fmu;\r
-\r
-       vector<string> variables;\r
-       vector<string> descriptions;\r
-       vector<string> declaredTypes;\r
-       vector<int> valueReferences;\r
-       vector<int> types;\r
-       vector<int> variabilities;\r
-       vector<int> causalities;\r
-\r
-       vector<string> declaredTypeNames;\r
-       vector<string> typeDescriptions;\r
-       vector<string> quantities;\r
-       vector<string> units;\r
-\r
-       vector<int> subscription;\r
-       double currentTime;\r
-       double timeStep;\r
-\r
-};\r
-\r
-struct FMUControlStruct {\r
-       double step;                                    // simulation step length\r
-       fmiReal currentTime;                    // current simulation time\r
-\r
-       fmiComponent c;                                 // instance of the fmu \r
-       ScalarVariable** vars;                  // model variables\r
-\r
-       fmiEventInfo eventInfo;         // updated by calls to initialize and eventUpdate\r
-       const char* guid;               // global unique id of the fmu\r
-       fmiCallbackFunctions callbacks; // called by the model during simulation\r
-       fmiStatus fmiFlag;              // return code of the fmu functions\r
-\r
-       map<string,int> indexes;                // indexes for variable names in vars-table\r
-       map<string,int>::iterator it;\r
-\r
-       int nx;                                                 // number of state variables\r
-       double *x;                                              // continuous states\r
-       double *xdot;                                   // the crresponding derivatives in same order\r
-       int nz;                         // number of state event indicators\r
-       double *z;                                              // state event indicators\r
-       double *prez;                                   // previous values of state event indicators\r
-       \r
-       bool initialized;                               // has the fmu been initialized\r
-\r
-       vector<fmiValueReference> subscription;         // result subscriptions\r
-       vector<string> allVariables;    // all variables in an initialized model\r
-       vector<fmiValueReference> fmiValueReferences;           // all value references\r
-\r
-       string lastErrorMessage;\r
-\r
-       FMU fmu;\r
-};\r
-\r
-vector<FMI1> fmus;\r
-\r
-//map<string,FMUControlStruct> fmus;           // indexes for variable names in vars-table\r
-\r
-int throwException(JNIEnv *env, string message) {\r
-       jclass newExcCls;\r
-    newExcCls = env->FindClass("java/lang/Exception");\r
-    if (newExcCls == NULL) {\r
-        /* Unable to find the exception class, give up. */\r
-        return 0;\r
-    }\r
-       env->ThrowNew(newExcCls, message.c_str());\r
-       return 0;\r
-}\r
-\r
-/*\r
-bool exists(string id) {\r
-       map<string,FMUControlStruct>::iterator it = fmus.find(id);\r
-       if(it != fmus.end()) {\r
-               return true;\r
-       } else {\r
-               return false;\r
-       }\r
-}\r
-*/\r
-\r
-\r
-\r
-JNIEXPORT jint JNICALL Java_org_simantics_fmil_FMIL_loadFMUFile_1 \r
-       (JNIEnv *env, jobject obj, jstring path, jstring tempDir) {\r
-\r
-       HMODULE module = NULL;\r
-       FMI1 fmi1;\r
-       FMIL_Variable *vars;\r
-       FMIL_DeclaredType *types;\r
-       int variableCount = 0;\r
-       int typeCount = 0;\r
-\r
-    const char *fmuPath = env->GetStringUTFChars(path, 0);\r
-       const char *fmuTempDir = env->GetStringUTFChars(tempDir, 0);\r
-\r
-       fmi1.currentTime = 0;\r
-       fmi1.timeStep = 0.1;\r
-       fmi1.fmu = FMI1_CS_LOAD(fmuPath, fmuTempDir);\r
-       if(!fmi1.fmu)\r
-         return throwException(env, "No FMU loaded");\r
-\r
-   vars = FMI1_CS_GET_VARIABLES(fmi1.fmu, &variableCount);\r
-   for(int i=0;i<variableCount;i++) {\r
-          fmi1.variables.push_back(string(vars[i].name));\r
-          if(vars[i].description)\r
-                       fmi1.descriptions.push_back(string(vars[i].description));\r
-          else\r
-                       fmi1.descriptions.push_back(string(""));\r
-          if(vars[i].declaredType)\r
-                       fmi1.declaredTypes.push_back(string(vars[i].declaredType));\r
-          else\r
-                       fmi1.declaredTypes.push_back(string(""));\r
-          fmi1.types.push_back(vars[i].type);\r
-          fmi1.causalities.push_back(vars[i].causality);\r
-          fmi1.variabilities.push_back(vars[i].variability);\r
-          fmi1.valueReferences.push_back(vars[i].vr);\r
-   }\r
-\r
-   types = FMI1_CS_GET_DECLARED_TYPES(fmi1.fmu, &typeCount);\r
-   for(int i=0;i<typeCount;i++) {\r
-          fmi1.declaredTypeNames.push_back(string(types[i].name));\r
-          if(types[i].description)\r
-                       fmi1.typeDescriptions.push_back(string(types[i].description));\r
-          else\r
-                       fmi1.typeDescriptions.push_back(string(""));\r
-          if(types[i].quantity)\r
-                       fmi1.quantities.push_back(string(types[i].quantity));\r
-          else\r
-                       fmi1.quantities.push_back(string(""));\r
-          if(types[i].unit)\r
-                       fmi1.units.push_back(string(types[i].unit));\r
-          else\r
-                       fmi1.units.push_back(string(""));\r
-   }\r
-\r
-\r
-   fmus.push_back(fmi1);\r
-\r
-       env->ReleaseStringUTFChars(path, fmuPath);\r
-       env->ReleaseStringUTFChars(tempDir, fmuTempDir);\r
-\r
-       return fmus.size() - 1;\r
-\r
-}\r
-\r
-JNIEXPORT jint JNICALL Java_org_simantics_fmil_FMIL_setStepLength_1 \r
-       (JNIEnv *env, jobject obj, jint id, jdouble stepLength) {\r
-       fmus[id].timeStep = stepLength;\r
-       return 1;\r
-}\r
-\r
-JNIEXPORT jint JNICALL Java_org_simantics_fmil_FMIL_subscribe_1\r
-  (JNIEnv *env, jobject obj, jint id, jintArray vrs) {\r
-\r
-       jboolean isCopy;\r
-       jint* elements = env -> GetIntArrayElements(vrs, &isCopy);\r
-       jsize n = env -> GetArrayLength(vrs);\r
-\r
-       int i;\r
-       for (i = 0; i < n; i++) {\r
-               fmus[id].subscription.push_back(elements[i]);\r
-       } \r
-         \r
-       if (isCopy == JNI_TRUE) {\r
-               env -> ReleaseIntArrayElements(vrs, elements, 0);\r
-       }\r
-\r
-       return 1;\r
-\r
-}\r
-\r
-bool referenceExists(FMUControlStruct fmuStruct, string variable) {\r
-       map<string,int>::iterator it = fmuStruct.indexes.find(variable);\r
-       if(it != fmuStruct.indexes.end()) {\r
-               return true;\r
-       } else {\r
-               return false;\r
-       }\r
-}\r
-\r
-// Remember to check if reference exists\r
-fmiValueReference getReference(FMUControlStruct fmuStruct, string variable) {\r
-       return fmuStruct.fmiValueReferences[fmuStruct.indexes[variable]];\r
-}\r
-\r
-// Get string representation of a scalar variable type\r
-string getTypeString(ScalarVariable* sv) {\r
-       switch (sv->typeSpec->type){\r
-               case elm_Integer:\r
-                       return "Integer";\r
-               case elm_Enumeration:\r
-                       return "Enumeration";\r
-               case elm_Real:\r
-                       return "Real";\r
-               case elm_Boolean:\r
-                       return "Boolean";\r
-               default:\r
-                       return "No type";\r
-       }\r
-}\r
-\r
-JNIEXPORT jint JNICALL Java_org_simantics_fmil_FMIL_setRealValue_1\r
-  (JNIEnv *env, jobject obj, jint id, jint vr, jdouble value) {\r
-\r
-         FMI1_CS_SET_REAL(fmus[id].fmu, vr, value);\r
-         return 1;\r
-\r
-}\r
-\r
-JNIEXPORT jint JNICALL Java_org_simantics_fmil_FMIL_setIntegerValue_1\r
-  (JNIEnv *env, jobject obj, jstring id, jstring parameter, jint value) {\r
-         /*\r
-       const char *fmuId = env->GetStringUTFChars(id, 0);\r
-       if(exists(fmuId)) {\r
-               FMUControlStruct& fmuStruct = fmus[fmuId];\r
-               const char *name = env->GetStringUTFChars(parameter, 0);\r
-               string nameString = name;\r
-               string modelId = fmuId;\r
-               if(!referenceExists(fmuStruct, name)) {\r
-                       string errorMessage = "setIntegerValue: Model (id " + modelId + ") does not contain variable: " + nameString;\r
-                       env->ReleaseStringUTFChars(parameter, name);\r
-                       env->ReleaseStringUTFChars(id, fmuId);\r
-                       return throwException(env, errorMessage);\r
-               } else {\r
-                       // Check variable type\r
-                       ScalarVariable* sv = fmuStruct.vars[fmuStruct.indexes[name]];\r
-                       switch (sv->typeSpec->type){\r
-                               case elm_Integer:\r
-                                       break; // ok\r
-                               default: {\r
-                                       string errorMessage = "setIntegerValue: " + nameString + " is not of type Integer. (type: + " + getTypeString(sv) + ")";\r
-                                       env->ReleaseStringUTFChars(parameter, name);\r
-                                       env->ReleaseStringUTFChars(id, fmuId);\r
-                                       return throwException(env, errorMessage);\r
-                               }\r
-                       }\r
-\r
-                       // Change value\r
-                       fmiValueReference vr = getReference(fmuStruct, name);\r
-                       const int intValue = (int) value;\r
-                       fmuStruct.fmu.setInteger(fmuStruct.c, &vr, 1, &intValue);\r
-                       env->ReleaseStringUTFChars(parameter, name);\r
-                       env->ReleaseStringUTFChars(id, fmuId);\r
-                       return 1;\r
-               }\r
-       }  else {\r
-               string message = fmuId;\r
-               env->ReleaseStringUTFChars(id, fmuId);\r
-               return throwException(env, "setIntegerValue: Model id " + message + " not found");\r
-       }\r
-       */\r
-         return 1;\r
-}\r
-\r
-JNIEXPORT jint JNICALL Java_org_simantics_fmil_FMIL_setBooleanValue_1\r
-  (JNIEnv *env, jobject obj, jstring id, jstring parameter, jboolean value) {\r
-         /*\r
-       const char *fmuId = env->GetStringUTFChars(id, 0);\r
-       if(exists(fmuId)) {\r
-               FMUControlStruct& fmuStruct = fmus[fmuId];\r
-               const char *name = env->GetStringUTFChars(parameter, 0);\r
-               string nameString = name;\r
-               string modelId = fmuId;\r
-               if(!referenceExists(fmuStruct, name)) {\r
-                       string errorMessage = "setBooleanValue: Model (id " + modelId + ") does not contain variable: " + nameString;\r
-                       env->ReleaseStringUTFChars(parameter, name);\r
-                       env->ReleaseStringUTFChars(id, fmuId);\r
-                       return throwException(env, errorMessage);\r
-               } else {\r
-                       // Check variable type\r
-                       ScalarVariable* sv = fmuStruct.vars[fmuStruct.indexes[name]];\r
-                       switch (sv->typeSpec->type){\r
-                               case elm_Boolean:\r
-                                       break; // ok\r
-                               default: {\r
-                                       string errorMessage = "setBooleanValue: " + nameString + " is not of type Boolean. (type: + " + getTypeString(sv) + ")";\r
-                                       env->ReleaseStringUTFChars(parameter, name);\r
-                                       env->ReleaseStringUTFChars(id, fmuId);\r
-                                       return throwException(env, errorMessage);\r
-                               }\r
-                       }\r
-\r
-                       // Change value\r
-                       fmiValueReference vr = getReference(fmuStruct, name);\r
-                       fmiBoolean result = 1;\r
-                       if(value == 0)\r
-                               result = 0;\r
-                       fmuStruct.fmu.setBoolean(fmuStruct.c, &vr, 1, &result);\r
-                       env->ReleaseStringUTFChars(parameter, name);\r
-                       env->ReleaseStringUTFChars(id, fmuId);\r
-                       return 1;\r
-               }\r
-       }  else {\r
-               string message = fmuId;\r
-               env->ReleaseStringUTFChars(id, fmuId);\r
-               return throwException(env, "setBooleanValue: Model id " + message + " not found");\r
-       }*/\r
-         return 1;\r
-}\r
-\r
-JNIEXPORT jboolean JNICALL Java_org_simantics_fmil_FMIL_isInitialized_1\r
-  (JNIEnv *env, jobject obj, jstring id) {\r
-         /*\r
-       const char *fmuId = env->GetStringUTFChars(id, 0);\r
-       if(exists(fmuId)) {\r
-               FMUControlStruct& fmuStruct = fmus[fmuId];\r
-               env->ReleaseStringUTFChars(id, fmuId);\r
-               return fmuStruct.initialized;\r
-       } else {\r
-               env->ReleaseStringUTFChars(id, fmuId);\r
-               return false;\r
-       }\r
-       */\r
-         return 1;\r
-}\r
-\r
-\r
-JNIEXPORT jdouble JNICALL Java_org_simantics_fmil_FMIL_getTime_1\r
-  (JNIEnv *env, jobject obj, jint id) {\r
-         return fmus[id].currentTime;\r
-}\r
-\r
-double getRealValue(FMUControlStruct fmuStruct, int index) {\r
-       ScalarVariable *sv = fmuStruct.vars[index];\r
-       fmiValueReference vr = fmuStruct.fmiValueReferences[index];\r
-       double real;\r
-       fmiInteger integer;\r
-       fmiBoolean fmibool;\r
-\r
-       switch (sv->typeSpec->type){\r
-        case elm_Real:\r
-                       fmuStruct.fmu.getReal(fmuStruct.c, &vr, 1, &real);\r
-            break;\r
-        case elm_Integer:\r
-        case elm_Enumeration:\r
-            fmuStruct.fmu.getInteger(fmuStruct.c, &vr, 1, &integer);\r
-                       real = (double)integer;\r
-            break;\r
-        case elm_Boolean:\r
-            fmuStruct.fmu.getBoolean(fmuStruct.c, &vr, 1, &fmibool);\r
-                       if(fmibool == fmiTrue)\r
-                               real = 1.0;\r
-                       else\r
-                               real = 0.0;\r
-            break;\r
-       }\r
-       return real;\r
-}\r
-\r
-JNIEXPORT jdoubleArray JNICALL Java_org_simantics_fmil_FMIL_getSubscribedResults_1\r
-  (JNIEnv *env, jobject obj, jint id, jdoubleArray result) {\r
-\r
-       jboolean isCopy;\r
-       jdouble* resultElements = env -> GetDoubleArrayElements(result, &isCopy);\r
-       jsize n = env -> GetArrayLength(result);\r
-       int *vrs;\r
-       if(n > 0) {\r
-               vrs = &(fmus[id].subscription[0]);\r
-               FMI1_CS_GET_REALS(fmus[id].fmu, vrs, resultElements, n);\r
-       }\r
-       if (isCopy == JNI_TRUE) {\r
-               env -> ReleaseDoubleArrayElements(result, resultElements, 0);\r
-       }\r
-\r
-       return result;\r
-       \r
-}\r
-\r
-JNIEXPORT jint JNICALL Java_org_simantics_fmil_FMIL_instantiateSimulation_1\r
-  (JNIEnv *env, jobject obj, jint id) {\r
-\r
-         int asd = FMI1_CS_INSTANTIATE(fmus[id].fmu);\r
-         if(asd != 0)\r
-               return throwException(env, "No FMU loaded");\r
-\r
-         return 1;\r
-\r
-}\r
-\r
-JNIEXPORT jint JNICALL Java_org_simantics_fmil_FMIL_initializeSimulation_1\r
-  (JNIEnv *env, jobject obj, jint id) {\r
-\r
-         int asd = FMI1_CS_INITIALIZE(fmus[id].fmu);\r
-         if(asd != 0)\r
-               return throwException(env, "No FMU loaded");\r
-\r
-         return 1;\r
-\r
-}\r
-\r
-JNIEXPORT jint JNICALL Java_org_simantics_fmil_FMIL_setTime_1\r
-  (JNIEnv *env, jobject obj, jstring id, jdouble time) {\r
-         return 1;\r
-}\r
-\r
-JNIEXPORT jobjectArray JNICALL Java_org_simantics_fmil_FMIL_getAllVariables_1\r
-  (JNIEnv *env, jobject obj, jint id) {\r
-\r
-       jobjectArray ret= (jobjectArray)env->NewObjectArray(fmus[id].variables.size(),  \r
-                       env->FindClass("java/lang/String"),  \r
-                       env->NewStringUTF(""));  \r
-   \r
-       for(int i=0;i<fmus[id].variables.size();i++) {  \r
-               env->SetObjectArrayElement(ret,i,env->NewStringUTF(fmus[id].variables[i].c_str()));  \r
-       }  \r
-\r
-       return ret;  \r
-\r
-}\r
-\r
-JNIEXPORT jobjectArray JNICALL Java_org_simantics_fmil_FMIL_getAllVariableDescriptions_1\r
-  (JNIEnv *env, jobject obj, jint id) {\r
-\r
-       jobjectArray ret= (jobjectArray)env->NewObjectArray(fmus[id].descriptions.size(),  \r
-                       env->FindClass("java/lang/String"),  \r
-                       env->NewStringUTF(""));  \r
-   \r
-       for(int i=0;i<fmus[id].descriptions.size();i++) {  \r
-               env->SetObjectArrayElement(ret,i,env->NewStringUTF(fmus[id].descriptions[i].c_str()));  \r
-       }  \r
-\r
-       return ret;  \r
-\r
-}\r
-\r
-JNIEXPORT jobjectArray JNICALL Java_org_simantics_fmil_FMIL_getAllVariableDeclaredTypes_1\r
-  (JNIEnv *env, jobject obj, jint id) {\r
-\r
-       jobjectArray ret= (jobjectArray)env->NewObjectArray(fmus[id].declaredTypes.size(),  \r
-                       env->FindClass("java/lang/String"),  \r
-                       env->NewStringUTF(""));\r
-   \r
-       for(int i=0;i<fmus[id].declaredTypes.size();i++) {  \r
-               env->SetObjectArrayElement(ret,i,env->NewStringUTF(fmus[id].declaredTypes[i].c_str()));  \r
-       }  \r
-\r
-       return ret;  \r
-\r
-}\r
-\r
-JNIEXPORT jintArray JNICALL Java_org_simantics_fmil_FMIL_getAllVariableReferences_1\r
-  (JNIEnv *env, jobject obj, jint id, jintArray result) {\r
-\r
-       jboolean isCopy;\r
-       jint* resultElements = env -> GetIntArrayElements(result, &isCopy);\r
-       jsize n = env -> GetArrayLength(result);\r
-\r
-       int i;\r
-       for (i = 0; i < n; i++) {\r
-               resultElements[i] = fmus[id].valueReferences[i];\r
-       } \r
-         \r
-       if (isCopy == JNI_TRUE) {\r
-               env -> ReleaseIntArrayElements(result, resultElements, 0);\r
-       }\r
-\r
-       return result;\r
-\r
-}\r
-\r
-JNIEXPORT jintArray JNICALL Java_org_simantics_fmil_FMIL_getAllVariableTypes_1\r
-  (JNIEnv *env, jobject obj, jint id, jintArray result) {\r
-\r
-       jboolean isCopy;\r
-       jint* resultElements = env -> GetIntArrayElements(result, &isCopy);\r
-       jsize n = env -> GetArrayLength(result);\r
-\r
-       int i;\r
-       for (i = 0; i < n; i++) {\r
-               resultElements[i] = fmus[id].types[i];\r
-       } \r
-         \r
-       if (isCopy == JNI_TRUE) {\r
-               env -> ReleaseIntArrayElements(result, resultElements, 0);\r
-       }\r
-\r
-       return result;\r
-\r
-}\r
-\r
-JNIEXPORT jintArray JNICALL Java_org_simantics_fmil_FMIL_getAllVariableVariabilities_1\r
-  (JNIEnv *env, jobject obj, jint id, jintArray result) {\r
-\r
-       jboolean isCopy;\r
-       jint* resultElements = env -> GetIntArrayElements(result, &isCopy);\r
-       jsize n = env -> GetArrayLength(result);\r
-\r
-       int i;\r
-       for (i = 0; i < n; i++) {\r
-               resultElements[i] = fmus[id].variabilities[i];\r
-       } \r
-         \r
-       if (isCopy == JNI_TRUE) {\r
-               env -> ReleaseIntArrayElements(result, resultElements, 0);\r
-       }\r
-\r
-       return result;\r
-\r
-}\r
-\r
-JNIEXPORT jintArray JNICALL Java_org_simantics_fmil_FMIL_getAllVariableCausalities_1\r
-  (JNIEnv *env, jobject obj, jint id, jintArray result) {\r
-\r
-       jboolean isCopy;\r
-       jint* resultElements = env -> GetIntArrayElements(result, &isCopy);\r
-       jsize n = env -> GetArrayLength(result);\r
-\r
-       int i;\r
-       for (i = 0; i < n; i++) {\r
-               resultElements[i] = fmus[id].causalities[i];\r
-       } \r
-         \r
-       if (isCopy == JNI_TRUE) {\r
-               env -> ReleaseIntArrayElements(result, resultElements, 0);\r
-       }\r
-\r
-       return result;\r
-\r
-}\r
-\r
-JNIEXPORT jobjectArray JNICALL Java_org_simantics_fmil_FMIL_getAllDeclaredTypes_1\r
-  (JNIEnv *env, jobject obj, jint id) {\r
-\r
-       jobjectArray ret= (jobjectArray)env->NewObjectArray(fmus[id].declaredTypeNames.size(),  \r
-                       env->FindClass("java/lang/String"),  \r
-                       env->NewStringUTF(""));\r
-   \r
-       for(int i=0;i<fmus[id].declaredTypeNames.size();i++) {  \r
-               env->SetObjectArrayElement(ret,i,env->NewStringUTF(fmus[id].declaredTypeNames[i].c_str()));  \r
-       }  \r
-\r
-       return ret;  \r
-\r
-}\r
-\r
-JNIEXPORT jobjectArray JNICALL Java_org_simantics_fmil_FMIL_getAllDeclaredTypeDescriptions_1\r
-  (JNIEnv *env, jobject obj, jint id) {\r
-\r
-       jobjectArray ret= (jobjectArray)env->NewObjectArray(fmus[id].typeDescriptions.size(),  \r
-                       env->FindClass("java/lang/String"),  \r
-                       env->NewStringUTF(""));\r
-   \r
-       for(int i=0;i<fmus[id].typeDescriptions.size();i++) {  \r
-               env->SetObjectArrayElement(ret,i,env->NewStringUTF(fmus[id].typeDescriptions[i].c_str()));  \r
-       }  \r
-\r
-       return ret;  \r
-\r
-}\r
-\r
-JNIEXPORT jobjectArray JNICALL Java_org_simantics_fmil_FMIL_getAllDeclaredTypeQuantities_1\r
-  (JNIEnv *env, jobject obj, jint id) {\r
-\r
-       jobjectArray ret= (jobjectArray)env->NewObjectArray(fmus[id].quantities.size(),  \r
-                       env->FindClass("java/lang/String"),  \r
-                       env->NewStringUTF(""));\r
-   \r
-       for(int i=0;i<fmus[id].quantities.size();i++) {  \r
-               env->SetObjectArrayElement(ret,i,env->NewStringUTF(fmus[id].quantities[i].c_str()));  \r
-       }  \r
-\r
-       return ret;  \r
-\r
-}\r
-\r
-JNIEXPORT jobjectArray JNICALL Java_org_simantics_fmil_FMIL_getAllDeclaredTypeUnits_1\r
-  (JNIEnv *env, jobject obj, jint id) {\r
-\r
-       jobjectArray ret= (jobjectArray)env->NewObjectArray(fmus[id].units.size(),  \r
-                       env->FindClass("java/lang/String"),  \r
-                       env->NewStringUTF(""));\r
-   \r
-       for(int i=0;i<fmus[id].units.size();i++) {  \r
-               env->SetObjectArrayElement(ret,i,env->NewStringUTF(fmus[id].units[i].c_str()));  \r
-       }  \r
-\r
-       return ret;  \r
-\r
-}\r
-\r
-/*\r
-JNIEXPORT jobjectArray JNICALL Java_org_simantics_fmil_FMIL_filterVariables_1\r
-  (JNIEnv *env, jobject obj, jstring id, jstring regexp) {\r
-        const char *rx = env->GetStringUTFChars(regexp, 0);\r
-        jobjectArray result = filterVariables(env, obj, id, rx);\r
-        env->ReleaseStringUTFChars(regexp, rx);\r
-        return result;\r
-}\r
-*/\r
-\r
-JNIEXPORT jint JNICALL Java_org_simantics_fmil_FMIL_simulateStep_1\r
-  (JNIEnv *env, jobject obj, jint id) {\r
-\r
-         int asd = FMI1_CS_STEP(fmus[id].fmu, fmus[id].currentTime, fmus[id].timeStep);\r
-         if(asd != 0)\r
-               return throwException(env, "No FMU loaded");\r
-\r
-         fmus[id].currentTime += fmus[id].timeStep;\r
-\r
-         return 1;\r
-\r
-         /*\r
-       const char *fmuId = env->GetStringUTFChars(id, 0);\r
-       if(exists(fmuId)) {\r
-               FMUControlStruct& fmuStruct = fmus[fmuId];\r
-               env->ReleaseStringUTFChars(id, fmuId);\r
-\r
-               if(&fmuStruct.fmu == NULL || fmuStruct.fmu.modelDescription == NULL || &fmuStruct.vars == NULL) {\r
-                       return throwException(env, "Simulate step failed - fmu not loaded");\r
-               }\r
-\r
-               if(fmuStruct.x == NULL) {\r
-                       return throwException(env, "Simulate step failed - fmu not instantiated");\r
-               }\r
-\r
-               if(fmuStruct.initialized == false) {\r
-                       fmiBoolean toleranceControlled = fmiFalse;\r
-                       fmuStruct.fmiFlag =  fmuStruct.fmu.initialize(fmuStruct.c, toleranceControlled, fmuStruct.currentTime, &(fmuStruct.eventInfo));\r
-                       if (fmuStruct.fmiFlag > fmiWarning)  return throwException(env, "could not initialize model");\r
-                       fmuStruct.initialized = true;\r
-               }\r
-\r
-               FMU& fmu = fmuStruct.fmu;\r
-               int debug = 0; // DEBUG ON = 1, OFF = 0\r
-\r
-               int i;\r
-               double dt, tPre, tEnd = fmuStruct.currentTime + fmuStruct.step;\r
-\r
-               fmiBoolean timeEvent, stateEvent, stepEvent;\r
-               fmiStatus fmiFlag;                      // return code of the fmu functions\r
-               fmiValueReference vr;\r
-\r
-\r
-               */\r
-               /* Simulate the duration of one step. The simulation may be done in \r
-                * multiple parts if events occur\r
-                */ /*\r
-               while (fmuStruct.currentTime < tEnd) {\r
-                       // get current state and derivatives\r
-                       fmiFlag = fmu.getContinuousStates(fmuStruct.c, fmuStruct.x, fmuStruct.nx);\r
-                       if (fmiFlag > fmiWarning) \r
-                               return throwException(env, "could not retrieve states");\r
-\r
-                       fmiFlag = fmu.getDerivatives(fmuStruct.c, fmuStruct.xdot, fmuStruct.nx);\r
-                       if (fmiFlag > fmiWarning) \r
-                               return throwException(env, "could not retrieve derivatives");\r
-\r
-                        // advance time\r
-                       tPre = fmuStruct.currentTime;\r
-                       fmuStruct.currentTime = min(fmuStruct.currentTime+fmuStruct.step, tEnd);\r
-                       timeEvent = fmuStruct.eventInfo.upcomingTimeEvent && fmuStruct.eventInfo.nextEventTime < fmuStruct.currentTime;  \r
-               \r
-                       if (timeEvent) fmuStruct.currentTime = fmuStruct.eventInfo.nextEventTime;\r
-                       dt = fmuStruct.currentTime - tPre; \r
-                       fmiFlag = fmu.setTime(fmuStruct.c, fmuStruct.currentTime);\r
-                       if (fmiFlag > fmiWarning) throwException(env, "could not set time");\r
-\r
-                       if(referenceExists(fmuStruct, "time")) {\r
-                               vr = getReference(fmuStruct, "time");\r
-                               if(vr != NULL) {\r
-                                       fmu.setReal(fmuStruct.c, &vr, 1, &(fmuStruct.currentTime));\r
-                               }\r
-                       }\r
-\r
-                       if(debug)\r
-                               printf("Actual time: %lf\n", fmuStruct.currentTime);\r
-\r
-                       if (fmiFlag > fmiWarning) \r
-                               return throwException(env, "could not set time");\r
-\r
-                       // perform one step\r
-                       for (i=0; i<fmuStruct.nx; i++) \r
-                               fmuStruct.x[i] += dt*fmuStruct.xdot[i]; // forward Euler method\r
-\r
-                       fmiFlag = fmu.setContinuousStates(fmuStruct.c, fmuStruct.x, fmuStruct.nx);\r
-                       if (fmiFlag > fmiWarning) \r
-                               return throwException(env, "could not set states");\r
-\r
-                       // Check for step event, e.g. dynamic state selection\r
-                       fmiFlag = fmu.completedIntegratorStep(fmuStruct.c, &stepEvent);\r
-                       if (fmiFlag > fmiWarning) return throwException(env, "could not complete intgrator step");\r
-                       */\r
-/*                     for (i=0; i<fmuStruct.nz; i++) fmuStruct.prez[i] = fmuStruct.z[i]; \r
-                       fmiFlag = fmu.getEventIndicators(fmuStruct.c, fmuStruct.z, fmuStruct.nz);\r
-                       if (fmiFlag > fmiWarning) return throwException(env, "could not retrieve event indicators");\r
-                       stateEvent = FALSE;\r
-                       for (i=0; i<fmuStruct.nz; i++) \r
-                               stateEvent = stateEvent || (fmuStruct.prez[i] * fmuStruct.z[i] < 0);  \r
-     \r
-\r
-                       stepEvent = fmiTrue;\r
-                       // handle events\r
-                       if (timeEvent || stateEvent || stepEvent) {\r
-        \r
-                               // event iteration in one step, ignoring intermediate results\r
-                               fmiFlag = fmu.eventUpdate(fmuStruct.c, fmiFalse, &(fmuStruct.eventInfo));\r
-                               if (fmiFlag > fmiWarning) return throwException(env, "could not perform event update");\r
-      \r
-                       } // if event\r
-                       */\r
-       \r
-/*             }\r
-\r
-               fflush(stdout);\r
-               return 1;\r
-\r
-       } else {\r
-               string message = fmuId;\r
-               env->ReleaseStringUTFChars(id, fmuId);\r
-               return throwException(env, "simulateStep: Model id " + message + " not found");\r
-       }*/\r
-       return 1;\r
-}\r
-\r
-JNIEXPORT jint JNICALL Java_org_simantics_fmil_FMIL_unloadFMU_1\r
-  (JNIEnv *env, jobject obj, jint id) {\r
-\r
-         int asd = FMI1_CS_UNLOAD(fmus[id].fmu);\r
-         return asd;\r
-\r
-}\r
-\r
-JNIEXPORT jstring JNICALL Java_org_simantics_fmil_FMIL_getLastErrorMessage_1\r
-  (JNIEnv *env, jobject obj, jstring id) {\r
-         return env->NewStringUTF("No errors");\r
-}\r
-\r
-JNIEXPORT jdouble JNICALL Java_org_simantics_fmil_FMIL_getRealValue_1\r
-  (JNIEnv *env, jobject obj, jint id, jint vr) {\r
-         return FMI1_CS_GET_REAL(fmus[id].fmu, vr);\r
-}\r
-\r
-JNIEXPORT jint JNICALL Java_org_simantics_fmil_FMIL_getIntegerValue_1\r
-  (JNIEnv *env, jobject obj, jstring id, jstring variable) {\r
-         /*\r
-       const char *fmuId = env->GetStringUTFChars(id, 0);\r
-       if(exists(fmuId)) {\r
-               FMUControlStruct fmuStruct = fmus[fmuId];\r
-               env->ReleaseStringUTFChars(id, fmuId);\r
-               const char *name = env->GetStringUTFChars(variable, 0);\r
-\r
-               if(referenceExists(fmuStruct, name)) {\r
-                       fmiValueReference vr = getReference(fmuStruct, name);\r
-                       int result;\r
-                       fmuStruct.fmu.getInteger(fmuStruct.c, &vr, 1, &result);\r
-                       env->ReleaseStringUTFChars(variable, name);\r
-                       return result;\r
-\r
-               } else {\r
-                        string nameString = name;\r
-                        string message = "Variable " + nameString + " not found";\r
-                        env->ReleaseStringUTFChars(variable, name);\r
-                        return throwException(env, message);\r
-               }\r
-\r
-       } else {\r
-               string message = fmuId;\r
-               env->ReleaseStringUTFChars(id, fmuId);\r
-               return throwException(env, "unloadFMU: Model id " + message + " not found");\r
-       }\r
-       */\r
-         return 1;\r
-\r
-}\r
-\r
-JNIEXPORT jboolean JNICALL Java_org_simantics_fmil_FMIL_getBooleanValue_1\r
-  (JNIEnv *env, jobject obj, jstring id, jstring variable) {\r
-         /*\r
-       const char *fmuId = env->GetStringUTFChars(id, 0);\r
-       if(exists(fmuId)) {\r
-               FMUControlStruct fmuStruct = fmus[fmuId];\r
-               env->ReleaseStringUTFChars(id, fmuId);\r
-               const char *name = env->GetStringUTFChars(variable, 0);\r
-\r
-               if(referenceExists(fmuStruct, name)) {\r
-                       fmiValueReference vr = getReference(fmuStruct, name);\r
-                       fmiBoolean result;\r
-                       fmuStruct.fmu.getBoolean(fmuStruct.c, &vr, 1, &result);\r
-                       env->ReleaseStringUTFChars(variable, name);\r
-                       return result;\r
-\r
-               } else {\r
-                        string nameString = name;\r
-                        string message = "Variable " + nameString + " not found";\r
-                        env->ReleaseStringUTFChars(variable, name);\r
-                        return throwException(env, message);\r
-               }\r
-\r
-       } else {\r
-               string message = fmuId;\r
-               env->ReleaseStringUTFChars(id, fmuId);\r
-               return throwException(env, "unloadFMU: Model id " + message + " not found");\r
-       }*/\r
-         return 1;\r
-\r
-}\r
-\r
-JNIEXPORT jstring JNICALL Java_org_simantics_fmil_FMIL_getStringValue_1\r
-  (JNIEnv *env, jobject obj, jstring id, jstring variable) {\r
-         /*\r
-       const char *fmuId = env->GetStringUTFChars(id, 0);\r
-       if(exists(fmuId)) {\r
-               FMUControlStruct fmuStruct = fmus[fmuId];\r
-               env->ReleaseStringUTFChars(id, fmuId);\r
-               const char *name = env->GetStringUTFChars(variable, 0);\r
-\r
-               if(referenceExists(fmuStruct, name)) {\r
-                       fmiValueReference vr = getReference(fmuStruct, name);\r
-                       fmiString result;\r
-                       fmuStruct.fmu.getString(fmuStruct.c, &vr, 1, &result);\r
-                       env->ReleaseStringUTFChars(variable, name);\r
-                       return env->NewStringUTF(result);\r
-\r
-               } else {\r
-                        string nameString = name;\r
-                        string message = "Variable " + nameString + " not found";\r
-                        env->ReleaseStringUTFChars(variable, name);\r
-                        return 0; //throwException(env, message);\r
-               }\r
-\r
-       } else {\r
-               string message = fmuId;\r
-               env->ReleaseStringUTFChars(id, fmuId);\r
-               return 0; //throwException(env, "unloadFMU: Model id " + message + " not found");\r
-       }\r
-       */\r
-         return 0;\r
-\r
-}
\ No newline at end of file
+/* ------------------------------------------------------------------------- 
+ * fmu_control.c
+ * Simulation controls for fmus
+ *
+ * Free libraries and tools used to implement this simulator:
+ *  - header files from the FMU specification
+ *  - eXpat 2.0.1 XML parser, see http://expat.sourceforge.net
+ *  - 7z.exe 4.57 zip and unzip tool, see http://www.7-zip.org <---------- Replace with zlib
+ * Author: Teemu Lempinen
+ * Copyright 2012 Semantum Oy
+ * -------------------------------------------------------------------------
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <map>
+#include <string>
+#include <vector>
+#include <iostream>
+#include <regex>
+#include <atomic>
+
+#include <org_simantics_fmil_FMILJNI.h>
+
+extern "C" {
+       #include "fmi_me.h"
+       #include "sim_support.h"
+}
+
+#include "fmi1_cs.h"
+
+#define PRINT(fmt,args) { FILE *fp = fopen("R:\\Simantics\\Sysdyn\\log.txt", "ab"); fprintf(fp, fmt, args); fclose(fp); }
+
+using namespace std;
+
+static std::atomic<int> instanceNameID;
+
+int create_id() {
+    return instanceNameID++;
+}
+
+struct FMI1 {
+
+       void *fmu;
+
+       vector<string> variables;
+       vector<string> descriptions;
+       vector<string> declaredTypes;
+       vector<int> valueReferences;
+       vector<int> types;
+       vector<int> variabilities;
+       vector<int> causalities;
+
+       vector<string> declaredTypeNames;
+       vector<string> typeDescriptions;
+       vector<string> quantities;
+       vector<string> units;
+
+       vector<int> subscription;
+       double currentTime;
+       double timeStep;
+
+       int version;
+
+};
+
+struct FMUControlStruct {
+       double step;                                    // simulation step length
+       fmiReal currentTime;                    // current simulation time
+
+       fmiComponent c;                                 // instance of the fmu 
+       ScalarVariable** vars;                  // model variables
+
+       fmiEventInfo eventInfo;         // updated by calls to initialize and eventUpdate
+       const char* guid;               // global unique id of the fmu
+       fmiCallbackFunctions callbacks; // called by the model during simulation
+       fmiStatus fmiFlag;              // return code of the fmu functions
+
+       map<string,int> indexes;                // indexes for variable names in vars-table
+       map<string,int>::iterator it;
+
+       int nx;                                                 // number of state variables
+       double *x;                                              // continuous states
+       double *xdot;                                   // the crresponding derivatives in same order
+       int nz;                         // number of state event indicators
+       double *z;                                              // state event indicators
+       double *prez;                                   // previous values of state event indicators
+       
+       bool initialized;                               // has the fmu been initialized
+
+       vector<fmiValueReference> subscription;         // result subscriptions
+       vector<string> allVariables;    // all variables in an initialized model
+       vector<fmiValueReference> fmiValueReferences;           // all value references
+
+       string lastErrorMessage;
+
+       FMU fmu;
+};
+
+vector<FMI1> fmus;
+
+//map<string,FMUControlStruct> fmus;           // indexes for variable names in vars-table
+
+int throwFMILException(JNIEnv *env, string message) {
+       jclass newExcCls;
+    newExcCls = env->FindClass("org/simantics/fmil/core/FMILException");
+    if (newExcCls == NULL) {
+           newExcCls = env->FindClass("java/lang/Exception");
+    }
+    if (newExcCls == NULL) {
+        /* Unable to find the exception class, give up. */
+        return 1;
+    }
+       env->ThrowNew(newExcCls, message.c_str());
+       return 1;
+}
+
+int throwException(JNIEnv *env, string message) {
+       return throwFMILException(env, message);
+}
+
+bool isEmpty(const char *c) {
+       if (c == NULL) {
+               return true;
+       }
+       if (c[0] == '\0') {
+               return true;
+       }
+       return false;
+}
+
+/*
+bool exists(string id) {
+       map<string,FMUControlStruct>::iterator it = fmus.find(id);
+       if(it != fmus.end()) {
+               return true;
+       } else {
+               return false;
+       }
+}
+*/
+
+
+
+JNIEXPORT jint JNICALL Java_org_simantics_fmil_core_FMIL_loadFMUFile_1 
+       (JNIEnv *env, jobject obj, jstring path, jstring tempDir) {
+
+       FMI1 fmi1;
+       FMIL_Variable *vars;
+       FMIL_DeclaredType *types;
+
+       int returnValue;
+
+       int variableCount = 0;
+       int typeCount = 0;
+
+       int fmuVersion = 0;
+       const char *error = "";
+
+    const char *fmuPath = env->GetStringUTFChars(path, 0);
+       const char *fmuTempDir = env->GetStringUTFChars(tempDir, 0);
+
+       fmi1.currentTime = 0;
+       fmi1.timeStep = 0.1;
+       returnValue = FMI_CS_LOAD(fmuPath, fmuTempDir, &fmi1.fmu, &fmuVersion, &error);
+
+       if (returnValue != 0) {
+               string message = "Could not load FMU: ";
+               return throwFMILException(env, message += error);
+       }
+       if(!fmi1.fmu) {
+               string message = "No FMU loaded: ";
+               return throwFMILException(env, message += error);
+       }
+
+       fmi1.version = fmuVersion;
+       if (fmi1.version == 1) {
+               vars = FMI1_CS_GET_VARIABLES(fmi1.fmu, &variableCount, &error);
+       } else if (fmi1.version == 2) {
+               vars = FMI2_CS_GET_VARIABLES(fmi1.fmu, &variableCount, &error);
+       }
+       if (!isEmpty(error)) {
+               string message = "Could not get variables ";
+               return throwFMILException(env, message += error);
+       }
+
+   for(int i=0;i<variableCount;i++) {
+          fmi1.variables.push_back(string(vars[i].name));
+          if(vars[i].description)
+                       fmi1.descriptions.push_back(string(vars[i].description));
+          else
+                       fmi1.descriptions.push_back(string(""));
+          if(vars[i].declaredType)
+                       fmi1.declaredTypes.push_back(string(vars[i].declaredType));
+          else
+                       fmi1.declaredTypes.push_back(string(""));
+          fmi1.types.push_back(vars[i].type);
+          fmi1.causalities.push_back(vars[i].causality);
+          fmi1.variabilities.push_back(vars[i].variability);
+          fmi1.valueReferences.push_back(vars[i].vr);
+   }
+
+   if (fmi1.version == 1) {
+          types = FMI1_CS_GET_DECLARED_TYPES(fmi1.fmu, &typeCount, &error);
+   } else if (fmi1.version == 2) {
+          types = FMI2_CS_GET_DECLARED_TYPES(fmi1.fmu, &typeCount, &error);
+   }
+   if (!isEmpty(error)) {
+               string message = "Could not get declared types ";
+               return throwFMILException(env, message += error);
+       }
+
+   for(int i=0;i<typeCount;i++) {
+          fmi1.declaredTypeNames.push_back(string(types[i].name));
+          if(types[i].description)
+                       fmi1.typeDescriptions.push_back(string(types[i].description));
+          else
+                       fmi1.typeDescriptions.push_back(string(""));
+          if(types[i].quantity)
+                       fmi1.quantities.push_back(string(types[i].quantity));
+          else
+                       fmi1.quantities.push_back(string(""));
+          if(types[i].unit)
+                       fmi1.units.push_back(string(types[i].unit));
+          else
+                       fmi1.units.push_back(string(""));
+   }
+
+
+   fmus.push_back(fmi1);
+
+       env->ReleaseStringUTFChars(path, fmuPath);
+       env->ReleaseStringUTFChars(tempDir, fmuTempDir);
+
+       return (jint)fmus.size() - 1;
+
+}
+
+JNIEXPORT jint JNICALL Java_org_simantics_fmil_core_FMIL_setStepLength_1 
+       (JNIEnv *env, jobject obj, jint id, jdouble stepLength) {
+       fmus[id].timeStep = stepLength;
+       return 0;
+}
+
+JNIEXPORT jint JNICALL Java_org_simantics_fmil_core_FMIL_subscribe_1
+  (JNIEnv *env, jobject obj, jint id, jintArray vrs) {
+
+       jboolean isCopy;
+       jint* elements = env -> GetIntArrayElements(vrs, &isCopy);
+       jsize n = env -> GetArrayLength(vrs);
+
+       int i;
+       for (i = 0; i < n; i++) {
+               fmus[id].subscription.push_back(elements[i]);
+       } 
+         
+       if (isCopy == JNI_TRUE) {
+               env -> ReleaseIntArrayElements(vrs, elements, 0);
+       }
+
+       return 0;
+
+}
+
+bool referenceExists(FMUControlStruct fmuStruct, string variable) {
+       map<string,int>::iterator it = fmuStruct.indexes.find(variable);
+       if(it != fmuStruct.indexes.end()) {
+               return true;
+       } else {
+               return false;
+       }
+}
+
+// Remember to check if reference exists
+fmiValueReference getReference(FMUControlStruct fmuStruct, string variable) {
+       return fmuStruct.fmiValueReferences[fmuStruct.indexes[variable]];
+}
+
+// Get string representation of a scalar variable type
+string getTypeString(ScalarVariable* sv) {
+       switch (sv->typeSpec->type){
+               case elm_Integer:
+                       return "Integer";
+               case elm_Enumeration:
+                       return "Enumeration";
+               case elm_Real:
+                       return "Real";
+               case elm_Boolean:
+                       return "Boolean";
+               default:
+                       return "No type";
+       }
+}
+
+JNIEXPORT jint JNICALL Java_org_simantics_fmil_core_FMIL_setRealValue_1
+  (JNIEnv *env, jobject obj, jint id, jint vr, jdouble value) {
+
+       const char *error = "";
+       FMI1 &fmi = fmus[id];
+       if (fmi.version == 1) {
+               FMI1_CS_SET_REAL(fmi.fmu, vr, value, &error);
+       }
+       else if (fmi.version == 2) {
+               FMI2_CS_SET_REAL(fmi.fmu, vr, value, &error);
+       }
+       if (!isEmpty(error)) {
+               string message = "Could not set real value: ";
+               return throwFMILException(env, message += error);
+    }
+       return 0;
+}
+
+JNIEXPORT jint JNICALL Java_org_simantics_fmil_core_FMIL_setIntegerValue_1
+  (JNIEnv *env, jobject obj, jint id, jint vr, jint value) {
+       
+       const char *error = "";
+       FMI1 fmi = fmus[id];
+       if (fmi.version == 1) {
+               FMI1_CS_SET_INTEGER(fmi.fmu, vr, value, &error);
+       }
+       else if (fmi.version == 2) {
+               FMI2_CS_SET_INTEGER(fmi.fmu, vr, value, &error);
+       }
+       if (!isEmpty(error)) {
+               string message = "Could not set integer value: ";
+               return throwFMILException(env, message += error);
+       }
+       return 0;
+}
+
+JNIEXPORT jint JNICALL Java_org_simantics_fmil_core_FMIL_setBooleanValue_1
+  (JNIEnv *env, jobject obj, jint id, jint vr, jboolean value) {
+
+       const char *error = "";
+       FMI1 fmi = fmus[id];
+       if (fmi.version == 1) {
+               FMI1_CS_SET_BOOLEAN(fmi.fmu, vr, value != 0, &error);
+       }
+       else if (fmi.version == 2) {
+               FMI2_CS_SET_BOOLEAN(fmi.fmu, vr, value != 0, &error);
+       }
+       if (!isEmpty(error)) {
+               string message = "Could not set boolean value: ";
+               return throwFMILException(env, message += error);
+       }
+       return 0;
+}
+
+JNIEXPORT jint JNICALL Java_org_simantics_fmil_core_FMIL_setStringValue_1
+(JNIEnv *env, jobject obj, jint id, jint vr, jstring value) {
+
+       const char *error = "";
+       const char *valueChars = env->GetStringUTFChars(value, 0);
+       FMI1 fmi = fmus[id];
+       if (fmi.version == 1) {
+               FMI1_CS_SET_STRING(fmi.fmu, vr, valueChars, &error);
+       }
+       else if (fmi.version == 2) {
+               FMI2_CS_SET_STRING(fmi.fmu, vr, valueChars, &error);
+       }
+       env->ReleaseStringUTFChars(value, valueChars);
+       if (!isEmpty(error)) {
+               string message = "Could not set string value: ";
+               return throwFMILException(env, message += error);
+       }
+       return 0;
+}
+
+JNIEXPORT jboolean JNICALL Java_org_simantics_fmil_core_FMIL_isInitialized_1
+  (JNIEnv *env, jobject obj, jstring id) {
+         /*
+       const char *fmuId = env->GetStringUTFChars(id, 0);
+       if(exists(fmuId)) {
+               FMUControlStruct& fmuStruct = fmus[fmuId];
+               env->ReleaseStringUTFChars(id, fmuId);
+               return fmuStruct.initialized;
+       } else {
+               env->ReleaseStringUTFChars(id, fmuId);
+               return false;
+       }
+       */
+         return 1;
+}
+
+
+JNIEXPORT jdouble JNICALL Java_org_simantics_fmil_core_FMIL_getTime_1
+  (JNIEnv *env, jobject obj, jint id) {
+         return fmus[id].currentTime;
+}
+
+double getRealValue(FMUControlStruct fmuStruct, int index) {
+       ScalarVariable *sv = fmuStruct.vars[index];
+       fmiValueReference vr = fmuStruct.fmiValueReferences[index];
+       double real;
+       fmiInteger integer;
+       fmiBoolean fmibool;
+
+       switch (sv->typeSpec->type){
+        case elm_Real:
+                       fmuStruct.fmu.getReal(fmuStruct.c, &vr, 1, &real);
+            break;
+        case elm_Integer:
+        case elm_Enumeration:
+            fmuStruct.fmu.getInteger(fmuStruct.c, &vr, 1, &integer);
+                       real = (double)integer;
+            break;
+        case elm_Boolean:
+            fmuStruct.fmu.getBoolean(fmuStruct.c, &vr, 1, &fmibool);
+                       if(fmibool == fmiTrue)
+                               real = 1.0;
+                       else
+                               real = 0.0;
+            break;
+       }
+       return real;
+}
+
+JNIEXPORT jdoubleArray JNICALL Java_org_simantics_fmil_core_FMIL_getSubscribedResults_1
+  (JNIEnv *env, jobject obj, jint id, jdoubleArray result) {
+
+       jboolean isCopy;
+       jdouble* resultElements = env -> GetDoubleArrayElements(result, &isCopy);
+       jsize n = env -> GetArrayLength(result);
+       int *vrs;
+       const char *error = "";
+
+       FMI1 fmi = fmus[id];
+       if(n > 0) {
+               vrs = &(fmus[id].subscription[0]);
+               if (fmi.version == 1) {
+                       FMI1_CS_GET_REALS(fmi.fmu, vrs, resultElements, n, &error);
+               } else if (fmi.version == 2) {
+                       FMI2_CS_GET_REALS(fmi.fmu, vrs, resultElements, n, &error);
+               }
+       }
+       if (isCopy == JNI_TRUE) {
+               env -> ReleaseDoubleArrayElements(result, resultElements, 0);
+       }
+
+       return result;
+       
+}
+
+JNIEXPORT jint JNICALL Java_org_simantics_fmil_core_FMIL_instantiateSimulation_1
+  (JNIEnv *env, jobject obj, jint id) {
+
+         int uniqueId = create_id();
+         std::string instanceName = std::to_string(uniqueId);
+         int returnValue;
+         const char *error = "";
+
+         FMI1 &fmi = fmus[id];
+         if (fmi.version == 1) {
+                 returnValue = FMI1_CS_INSTANTIATE(fmi.fmu, instanceName.c_str(), &error);
+         } else if (fmi.version == 2) {
+                 returnValue = FMI2_CS_INSTANTIATE(fmi.fmu, instanceName.c_str(), &error);
+         }
+         if(returnValue != 0) {
+               string message = "No FMU loaded: ";
+               return throwFMILException(env, message += error);
+         }
+         return 0;
+}
+
+JNIEXPORT jint JNICALL Java_org_simantics_fmil_core_FMIL_initializeSimulation_1
+  (JNIEnv *env, jobject obj, jint id) {
+       
+       const char *error = "";
+       int returnValue;
+       FMI1 fmi = fmus[id];
+       if (fmi.version == 1) {
+               returnValue = FMI1_CS_INITIALIZE(fmi.fmu, &error);
+       } else if (fmi.version == 2) {
+               returnValue = FMI2_CS_INITIALIZE(fmi.fmu, &error);
+       }
+       if(returnValue != 0) {
+               string message = "Could not initialize simulation: ";
+               return throwFMILException(env, message += error);
+       }
+
+       return 0;
+
+}
+
+JNIEXPORT jint JNICALL Java_org_simantics_fmil_core_FMIL_setTime_1
+  (JNIEnv *env, jobject obj, jstring id, jdouble time) {
+         return 0;
+}
+
+JNIEXPORT jobjectArray JNICALL Java_org_simantics_fmil_core_FMIL_getAllVariables_1
+  (JNIEnv *env, jobject obj, jint id) {
+
+       jobjectArray ret= (jobjectArray)env->NewObjectArray((jsize)fmus[id].variables.size(),  
+                       env->FindClass("java/lang/String"),  
+                       env->NewStringUTF(""));  
+   
+       for(unsigned int i=0;i<fmus[id].variables.size();i++) {  
+               env->SetObjectArrayElement(ret,i,env->NewStringUTF(fmus[id].variables[i].c_str()));  
+       }  
+
+       return ret;  
+
+}
+
+JNIEXPORT jobjectArray JNICALL Java_org_simantics_fmil_core_FMIL_getAllVariableDescriptions_1
+  (JNIEnv *env, jobject obj, jint id) {
+
+       jobjectArray ret= (jobjectArray)env->NewObjectArray((jsize)fmus[id].descriptions.size(),
+                       env->FindClass("java/lang/String"),  
+                       env->NewStringUTF(""));  
+   
+       for(unsigned int i=0;i<fmus[id].descriptions.size();i++) {  
+               env->SetObjectArrayElement(ret,i,env->NewStringUTF(fmus[id].descriptions[i].c_str()));  
+       }  
+
+       return ret;  
+
+}
+
+JNIEXPORT jobjectArray JNICALL Java_org_simantics_fmil_core_FMIL_getAllVariableDeclaredTypes_1
+  (JNIEnv *env, jobject obj, jint id) {
+
+       jobjectArray ret= (jobjectArray)env->NewObjectArray((jsize)fmus[id].declaredTypes.size(),
+                       env->FindClass("java/lang/String"),  
+                       env->NewStringUTF(""));
+   
+       for(unsigned int i=0;i<fmus[id].declaredTypes.size();i++) {  
+               env->SetObjectArrayElement(ret,i,env->NewStringUTF(fmus[id].declaredTypes[i].c_str()));  
+       }  
+
+       return ret;  
+
+}
+
+JNIEXPORT jintArray JNICALL Java_org_simantics_fmil_core_FMIL_getAllVariableReferences_1
+  (JNIEnv *env, jobject obj, jint id, jintArray result) {
+
+       jboolean isCopy;
+       jint* resultElements = env -> GetIntArrayElements(result, &isCopy);
+       jsize n = env -> GetArrayLength(result);
+
+       int i;
+       for (i = 0; i < n; i++) {
+               resultElements[i] = fmus[id].valueReferences[i];
+       } 
+         
+       if (isCopy == JNI_TRUE) {
+               env -> ReleaseIntArrayElements(result, resultElements, 0);
+       }
+
+       return result;
+
+}
+
+JNIEXPORT jintArray JNICALL Java_org_simantics_fmil_core_FMIL_getAllVariableTypes_1
+  (JNIEnv *env, jobject obj, jint id, jintArray result) {
+
+       jboolean isCopy;
+       jint* resultElements = env -> GetIntArrayElements(result, &isCopy);
+       jsize n = env -> GetArrayLength(result);
+
+       int i;
+       for (i = 0; i < n; i++) {
+               resultElements[i] = fmus[id].types[i];
+       } 
+         
+       if (isCopy == JNI_TRUE) {
+               env -> ReleaseIntArrayElements(result, resultElements, 0);
+       }
+
+       return result;
+
+}
+
+JNIEXPORT jintArray JNICALL Java_org_simantics_fmil_core_FMIL_getAllVariableVariabilities_1
+  (JNIEnv *env, jobject obj, jint id, jintArray result) {
+
+       jboolean isCopy;
+       jint* resultElements = env -> GetIntArrayElements(result, &isCopy);
+       jsize n = env -> GetArrayLength(result);
+
+       for (jsize i = 0; i < n; i++) {
+               resultElements[i] = fmus[id].variabilities[i];
+       } 
+         
+       if (isCopy == JNI_TRUE) {
+               env -> ReleaseIntArrayElements(result, resultElements, 0);
+       }
+
+       return result;
+
+}
+
+JNIEXPORT jintArray JNICALL Java_org_simantics_fmil_core_FMIL_getAllVariableCausalities_1
+  (JNIEnv *env, jobject obj, jint id, jintArray result) {
+
+       jboolean isCopy;
+       jint* resultElements = env -> GetIntArrayElements(result, &isCopy);
+       jsize n = env -> GetArrayLength(result);
+
+       for (jsize i = 0; i < n; i++) {
+               resultElements[i] = fmus[id].causalities[i];
+       } 
+         
+       if (isCopy == JNI_TRUE) {
+               env -> ReleaseIntArrayElements(result, resultElements, 0);
+       }
+
+       return result;
+
+}
+
+JNIEXPORT jobjectArray JNICALL Java_org_simantics_fmil_core_FMIL_getAllDeclaredTypes_1
+  (JNIEnv *env, jobject obj, jint id) {
+
+       jobjectArray ret= (jobjectArray)env->NewObjectArray((jsize)fmus[id].declaredTypeNames.size(),
+                       env->FindClass("java/lang/String"),  
+                       env->NewStringUTF(""));
+   
+       for(unsigned int i=0;i<fmus[id].declaredTypeNames.size();i++) {  
+               env->SetObjectArrayElement(ret,i,env->NewStringUTF(fmus[id].declaredTypeNames[i].c_str()));  
+       }  
+
+       return ret;  
+
+}
+
+JNIEXPORT jobjectArray JNICALL Java_org_simantics_fmil_core_FMIL_getAllDeclaredTypeDescriptions_1
+  (JNIEnv *env, jobject obj, jint id) {
+
+       jobjectArray ret= (jobjectArray)env->NewObjectArray((jsize)fmus[id].typeDescriptions.size(),
+                       env->FindClass("java/lang/String"),  
+                       env->NewStringUTF(""));
+   
+       for(unsigned int i=0;i<fmus[id].typeDescriptions.size();i++) {  
+               env->SetObjectArrayElement(ret,i,env->NewStringUTF(fmus[id].typeDescriptions[i].c_str()));  
+       }  
+
+       return ret;  
+
+}
+
+JNIEXPORT jobjectArray JNICALL Java_org_simantics_fmil_core_FMIL_getAllDeclaredTypeQuantities_1
+  (JNIEnv *env, jobject obj, jint id) {
+
+       jobjectArray ret= (jobjectArray)env->NewObjectArray((jsize)fmus[id].quantities.size(),
+                       env->FindClass("java/lang/String"),  
+                       env->NewStringUTF(""));
+   
+       for(unsigned int i=0;i<fmus[id].quantities.size();i++) {  
+               env->SetObjectArrayElement(ret,i,env->NewStringUTF(fmus[id].quantities[i].c_str()));  
+       }  
+
+       return ret;  
+
+}
+
+JNIEXPORT jobjectArray JNICALL Java_org_simantics_fmil_core_FMIL_getAllDeclaredTypeUnits_1
+  (JNIEnv *env, jobject obj, jint id) {
+
+       jobjectArray ret= (jobjectArray)env->NewObjectArray((jsize)fmus[id].units.size(),
+                       env->FindClass("java/lang/String"),  
+                       env->NewStringUTF(""));
+   
+       for(unsigned int i=0;i<fmus[id].units.size();i++) {  
+               env->SetObjectArrayElement(ret,i,env->NewStringUTF(fmus[id].units[i].c_str()));  
+       }  
+
+       return ret;  
+
+}
+
+/*
+JNIEXPORT jobjectArray JNICALL Java_org_simantics_fmil_core_FMIL_filterVariables_1
+  (JNIEnv *env, jobject obj, jstring id, jstring regexp) {
+        const char *rx = env->GetStringUTFChars(regexp, 0);
+        jobjectArray result = filterVariables(env, obj, id, rx);
+        env->ReleaseStringUTFChars(regexp, rx);
+        return result;
+}
+*/
+
+JNIEXPORT jint JNICALL Java_org_simantics_fmil_core_FMIL_simulateStep_1
+  (JNIEnv *env, jobject obj, jint id) {
+
+         int returnValue;
+         const char *error = "";
+
+         FMI1 &fmi = fmus[id];
+         if (fmi.version == 1) {
+                 returnValue = FMI1_CS_STEP(fmi.fmu, fmi.currentTime, fmi.timeStep, &error);
+         } else if (fmi.version == 2) {
+                 returnValue = FMI2_CS_STEP(fmi.fmu, fmi.currentTime, fmi.timeStep, &error);
+         }
+         if(returnValue == 1) {
+                 string message = "Could not simulate step: ";
+                 return throwException(env,  message += error);
+         }
+
+         fmi.currentTime += fmi.timeStep;
+
+         return returnValue; //Pass return value up. 0 is OK, 1 is error, 2 is pending
+
+         /*
+       const char *fmuId = env->GetStringUTFChars(id, 0);
+       if(exists(fmuId)) {
+               FMUControlStruct& fmuStruct = fmus[fmuId];
+               env->ReleaseStringUTFChars(id, fmuId);
+
+               if(&fmuStruct.fmu == NULL || fmuStruct.fmu.modelDescription == NULL || &fmuStruct.vars == NULL) {
+                       return throwException(env, "Simulate step failed - fmu not loaded");
+               }
+
+               if(fmuStruct.x == NULL) {
+                       return throwException(env, "Simulate step failed - fmu not instantiated");
+               }
+
+               if(fmuStruct.initialized == false) {
+                       fmiBoolean toleranceControlled = fmiFalse;
+                       fmuStruct.fmiFlag =  fmuStruct.fmu.initialize(fmuStruct.c, toleranceControlled, fmuStruct.currentTime, &(fmuStruct.eventInfo));
+                       if (fmuStruct.fmiFlag > fmiWarning)  return throwException(env, "could not initialize model");
+                       fmuStruct.initialized = true;
+               }
+
+               FMU& fmu = fmuStruct.fmu;
+               int debug = 0; // DEBUG ON = 1, OFF = 0
+
+               int i;
+               double dt, tPre, tEnd = fmuStruct.currentTime + fmuStruct.step;
+
+               fmiBoolean timeEvent, stateEvent, stepEvent;
+               fmiStatus fmiFlag;                      // return code of the fmu functions
+               fmiValueReference vr;
+
+
+               */
+               /* Simulate the duration of one step. The simulation may be done in 
+                * multiple parts if events occur
+                */ /*
+               while (fmuStruct.currentTime < tEnd) {
+                       // get current state and derivatives
+                       fmiFlag = fmu.getContinuousStates(fmuStruct.c, fmuStruct.x, fmuStruct.nx);
+                       if (fmiFlag > fmiWarning) 
+                               return throwException(env, "could not retrieve states");
+
+                       fmiFlag = fmu.getDerivatives(fmuStruct.c, fmuStruct.xdot, fmuStruct.nx);
+                       if (fmiFlag > fmiWarning) 
+                               return throwException(env, "could not retrieve derivatives");
+
+                        // advance time
+                       tPre = fmuStruct.currentTime;
+                       fmuStruct.currentTime = min(fmuStruct.currentTime+fmuStruct.step, tEnd);
+                       timeEvent = fmuStruct.eventInfo.upcomingTimeEvent && fmuStruct.eventInfo.nextEventTime < fmuStruct.currentTime;  
+               
+                       if (timeEvent) fmuStruct.currentTime = fmuStruct.eventInfo.nextEventTime;
+                       dt = fmuStruct.currentTime - tPre; 
+                       fmiFlag = fmu.setTime(fmuStruct.c, fmuStruct.currentTime);
+                       if (fmiFlag > fmiWarning) throwException(env, "could not set time");
+
+                       if(referenceExists(fmuStruct, "time")) {
+                               vr = getReference(fmuStruct, "time");
+                               if(vr != NULL) {
+                                       fmu.setReal(fmuStruct.c, &vr, 1, &(fmuStruct.currentTime));
+                               }
+                       }
+
+                       if(debug)
+                               printf("Actual time: %lf\n", fmuStruct.currentTime);
+
+                       if (fmiFlag > fmiWarning) 
+                               return throwException(env, "could not set time");
+
+                       // perform one step
+                       for (i=0; i<fmuStruct.nx; i++) 
+                               fmuStruct.x[i] += dt*fmuStruct.xdot[i]; // forward Euler method
+
+                       fmiFlag = fmu.setContinuousStates(fmuStruct.c, fmuStruct.x, fmuStruct.nx);
+                       if (fmiFlag > fmiWarning) 
+                               return throwException(env, "could not set states");
+
+                       // Check for step event, e.g. dynamic state selection
+                       fmiFlag = fmu.completedIntegratorStep(fmuStruct.c, &stepEvent);
+                       if (fmiFlag > fmiWarning) return throwException(env, "could not complete intgrator step");
+                       */
+/*                     for (i=0; i<fmuStruct.nz; i++) fmuStruct.prez[i] = fmuStruct.z[i]; 
+                       fmiFlag = fmu.getEventIndicators(fmuStruct.c, fmuStruct.z, fmuStruct.nz);
+                       if (fmiFlag > fmiWarning) return throwException(env, "could not retrieve event indicators");
+                       stateEvent = FALSE;
+                       for (i=0; i<fmuStruct.nz; i++) 
+                               stateEvent = stateEvent || (fmuStruct.prez[i] * fmuStruct.z[i] < 0);  
+     
+
+                       stepEvent = fmiTrue;
+                       // handle events
+                       if (timeEvent || stateEvent || stepEvent) {
+        
+                               // event iteration in one step, ignoring intermediate results
+                               fmiFlag = fmu.eventUpdate(fmuStruct.c, fmiFalse, &(fmuStruct.eventInfo));
+                               if (fmiFlag > fmiWarning) return throwException(env, "could not perform event update");
+      
+                       } // if event
+                       */
+       
+/*             }
+
+               fflush(stdout);
+               return 1;
+
+       } else {
+               string message = fmuId;
+               env->ReleaseStringUTFChars(id, fmuId);
+               return throwException(env, "simulateStep: Model id " + message + " not found");
+       }*/
+       return 1;
+}
+
+JNIEXPORT jint JNICALL Java_org_simantics_fmil_core_FMIL_unloadFMU_1
+  (JNIEnv *env, jobject obj, jint id) {
+
+         int returnValue;
+         const char *error = "";
+
+         FMI1 fmi = fmus[id];
+         if (fmi.version == 1) {
+                 returnValue = FMI1_CS_UNLOAD(fmi.fmu, &error);
+         } else if (fmi.version == 2) {
+                 returnValue = FMI2_CS_UNLOAD(fmi.fmu, &error);
+         }
+         if(returnValue != 0) {
+               string message = "Could not unload FMU: ";
+               return throwException(env, message += error);
+         }
+         return returnValue;
+}
+
+JNIEXPORT jdouble JNICALL Java_org_simantics_fmil_core_FMIL_getRealValue_1
+  (JNIEnv *env, jobject obj, jint id, jint vr) {
+
+         double value;
+         const char *error = "";
+
+         FMI1 fmi = fmus[id];
+         if (fmi.version == 1) {
+                 value = FMI1_CS_GET_REAL(fmi.fmu, vr, &error);
+         } else if (fmi.version == 2) {
+                 value = FMI2_CS_GET_REAL(fmi.fmu, vr, &error);
+         }
+         if (!isEmpty(error)) {
+                 string message = "Could not get real value: ";
+                 throwFMILException(env, message += error);
+                 return 0.0;
+         }
+         return value;
+}
+
+JNIEXPORT jint JNICALL Java_org_simantics_fmil_core_FMIL_getIntegerValue_1
+  (JNIEnv *env, jobject obj, jint id, jint vr) {
+
+       int value;
+       const char *error = "";
+
+       FMI1 fmi = fmus[id];
+       if (fmi.version == 1) {
+               value = FMI1_CS_GET_INTEGER(fmi.fmu, vr, &error);
+       }
+       else if (fmi.version == 2) {
+               value = FMI2_CS_GET_INTEGER(fmi.fmu, vr, &error);
+       }
+       if (!isEmpty(error)) {
+               string message = "Could not get integer value: ";
+               throwFMILException(env, message += error);
+               return 0;
+       }
+       return value;
+}
+
+JNIEXPORT jboolean JNICALL Java_org_simantics_fmil_core_FMIL_getBooleanValue_1
+  (JNIEnv *env, jobject obj, jint id, jint vr) {
+
+       int value;
+       const char *error = "";
+
+       FMI1 fmi = fmus[id];
+       if (fmi.version == 1) {
+               value = FMI1_CS_GET_BOOLEAN(fmi.fmu, vr, &error);
+       }
+       else if (fmi.version == 2) {
+               value = FMI2_CS_GET_BOOLEAN(fmi.fmu, vr, &error);
+       }
+       if (!isEmpty(error)) {
+               string message = "Could not get boolean value: ";
+               throwFMILException(env, message += error);
+               return 0;
+       }
+
+       return value != 0;
+}
+
+JNIEXPORT jstring JNICALL Java_org_simantics_fmil_core_FMIL_getStringValue_1
+  (JNIEnv *env, jobject obj, jint id, jint vr) {
+
+       const char *value;
+       const char *error = "";
+
+       FMI1 fmi = fmus[id];
+       if (fmi.version == 1) {
+               value = FMI1_CS_GET_STRING(fmi.fmu, vr, &error);
+       }
+       else if (fmi.version == 2) {
+               value = FMI2_CS_GET_STRING(fmi.fmu, vr, &error);
+       }
+       if (!isEmpty(error)) {
+               string message = "Could not get string value: ";
+               throwFMILException(env, message += error);
+               return nullptr;
+       }
+
+       return env->NewStringUTF(value);
+}