]> gerrit.simantics Code Review - simantics/fmil.git/blob - org.simantics.fmil.core/native/FMUSimulator/src/fmu_control.cpp
285be84e42627582224722227a789c39fd9436a5
[simantics/fmil.git] / org.simantics.fmil.core / native / FMUSimulator / src / fmu_control.cpp
1 /* ------------------------------------------------------------------------- 
2  * fmu_control.c
3  * Simulation controls for fmus
4  *
5  * Free libraries and tools used to implement this simulator:
6  *  - header files from the FMU specification
7  *  - eXpat 2.0.1 XML parser, see http://expat.sourceforge.net
8  *  - 7z.exe 4.57 zip and unzip tool, see http://www.7-zip.org <---------- Replace with zlib
9  * Author: Teemu Lempinen
10  * Copyright 2012 Semantum Oy
11  * -------------------------------------------------------------------------
12  */
13
14 #include <stdlib.h>
15 #include <stdio.h>
16 #include <string.h>
17 #include <map>
18 #include <string>
19 #include <vector>
20 #include <iostream>
21 #include <regex>
22
23 #include <org_simantics_fmil_FMILJNI.h>
24
25 extern "C" {
26         #include "fmi_me.h"
27         #include "sim_support.h"
28 }
29
30 #include "fmi1_cs.h"
31
32 #define PRINT(fmt,args) { FILE *fp = fopen("R:\\Simantics\\Sysdyn\\log.txt", "ab"); fprintf(fp, fmt, args); fclose(fp); }
33
34 using namespace std;
35
36 struct FMI1 {
37
38         void *fmu;
39
40         vector<string> variables;
41         vector<string> descriptions;
42         vector<string> declaredTypes;
43         vector<int> valueReferences;
44         vector<int> types;
45         vector<int> variabilities;
46         vector<int> causalities;
47
48         vector<string> declaredTypeNames;
49         vector<string> typeDescriptions;
50         vector<string> quantities;
51         vector<string> units;
52
53         vector<int> subscription;
54         double currentTime;
55         double timeStep;
56
57         int version;
58
59 };
60
61 struct FMUControlStruct {
62         double step;                                    // simulation step length
63         fmiReal currentTime;                    // current simulation time
64
65         fmiComponent c;                                 // instance of the fmu 
66         ScalarVariable** vars;                  // model variables
67
68         fmiEventInfo eventInfo;         // updated by calls to initialize and eventUpdate
69         const char* guid;               // global unique id of the fmu
70         fmiCallbackFunctions callbacks; // called by the model during simulation
71         fmiStatus fmiFlag;              // return code of the fmu functions
72
73         map<string,int> indexes;                // indexes for variable names in vars-table
74         map<string,int>::iterator it;
75
76         int nx;                                                 // number of state variables
77         double *x;                                              // continuous states
78         double *xdot;                                   // the crresponding derivatives in same order
79         int nz;                         // number of state event indicators
80         double *z;                                              // state event indicators
81         double *prez;                                   // previous values of state event indicators
82         
83         bool initialized;                               // has the fmu been initialized
84
85         vector<fmiValueReference> subscription;         // result subscriptions
86         vector<string> allVariables;    // all variables in an initialized model
87         vector<fmiValueReference> fmiValueReferences;           // all value references
88
89         string lastErrorMessage;
90
91         FMU fmu;
92 };
93
94 vector<FMI1> fmus;
95
96 //map<string,FMUControlStruct> fmus;            // indexes for variable names in vars-table
97
98 int throwFMILException(JNIEnv *env, string message) {
99         jclass newExcCls;
100     newExcCls = env->FindClass("org/simantics/fmil/core/FMILException");
101     if (newExcCls == NULL) {
102             newExcCls = env->FindClass("java/lang/Exception");
103     }
104     if (newExcCls == NULL) {
105         /* Unable to find the exception class, give up. */
106         return 1;
107     }
108         env->ThrowNew(newExcCls, message.c_str());
109         return 1;
110 }
111
112 int throwException(JNIEnv *env, string message) {
113         return throwFMILException(env, message);
114 }
115
116 bool isEmpty(const char *c) {
117         if (c == NULL) {
118                 return true;
119         }
120         if (c[0] == '\0') {
121                 return true;
122         }
123         return false;
124 }
125
126 /*
127 bool exists(string id) {
128         map<string,FMUControlStruct>::iterator it = fmus.find(id);
129         if(it != fmus.end()) {
130                 return true;
131         } else {
132                 return false;
133         }
134 }
135 */
136
137
138
139 JNIEXPORT jint JNICALL Java_org_simantics_fmil_core_FMIL_loadFMUFile_1 
140         (JNIEnv *env, jobject obj, jstring path, jstring tempDir) {
141
142         FMI1 fmi1;
143         FMIL_Variable *vars;
144         FMIL_DeclaredType *types;
145
146         int returnValue;
147
148         int variableCount = 0;
149         int typeCount = 0;
150
151         int fmuVersion = 0;
152         const char *error = "";
153
154     const char *fmuPath = env->GetStringUTFChars(path, 0);
155         const char *fmuTempDir = env->GetStringUTFChars(tempDir, 0);
156
157         fmi1.currentTime = 0;
158         fmi1.timeStep = 0.1;
159         returnValue = FMI_CS_LOAD(fmuPath, fmuTempDir, &fmi1.fmu, &fmuVersion, &error);
160
161         if (returnValue != 0) {
162                 string message = "Could not load FMU: ";
163                 return throwFMILException(env, message += error);
164         }
165         if(!fmi1.fmu) {
166                 string message = "No FMU loaded: ";
167                 return throwFMILException(env, message += error);
168         }
169
170         fmi1.version = fmuVersion;
171         if (fmi1.version == 1) {
172                 vars = FMI1_CS_GET_VARIABLES(fmi1.fmu, &variableCount, &error);
173         } else if (fmi1.version == 2) {
174                 vars = FMI2_CS_GET_VARIABLES(fmi1.fmu, &variableCount, &error);
175         }
176         if (!isEmpty(error)) {
177                 string message = "Could not get variables ";
178                 return throwFMILException(env, message += error);
179         }
180
181    for(int i=0;i<variableCount;i++) {
182            fmi1.variables.push_back(string(vars[i].name));
183            if(vars[i].description)
184                         fmi1.descriptions.push_back(string(vars[i].description));
185            else
186                         fmi1.descriptions.push_back(string(""));
187            if(vars[i].declaredType)
188                         fmi1.declaredTypes.push_back(string(vars[i].declaredType));
189            else
190                         fmi1.declaredTypes.push_back(string(""));
191            fmi1.types.push_back(vars[i].type);
192            fmi1.causalities.push_back(vars[i].causality);
193            fmi1.variabilities.push_back(vars[i].variability);
194            fmi1.valueReferences.push_back(vars[i].vr);
195    }
196
197    if (fmi1.version == 1) {
198            types = FMI1_CS_GET_DECLARED_TYPES(fmi1.fmu, &typeCount, &error);
199    } else if (fmi1.version == 2) {
200            types = FMI2_CS_GET_DECLARED_TYPES(fmi1.fmu, &typeCount, &error);
201    }
202    if (!isEmpty(error)) {
203                 string message = "Could not get declared types ";
204                 return throwFMILException(env, message += error);
205         }
206
207    for(int i=0;i<typeCount;i++) {
208            fmi1.declaredTypeNames.push_back(string(types[i].name));
209            if(types[i].description)
210                         fmi1.typeDescriptions.push_back(string(types[i].description));
211            else
212                         fmi1.typeDescriptions.push_back(string(""));
213            if(types[i].quantity)
214                         fmi1.quantities.push_back(string(types[i].quantity));
215            else
216                         fmi1.quantities.push_back(string(""));
217            if(types[i].unit)
218                         fmi1.units.push_back(string(types[i].unit));
219            else
220                         fmi1.units.push_back(string(""));
221    }
222
223
224    fmus.push_back(fmi1);
225
226         env->ReleaseStringUTFChars(path, fmuPath);
227         env->ReleaseStringUTFChars(tempDir, fmuTempDir);
228
229         return fmus.size() - 1;
230
231 }
232
233 JNIEXPORT jint JNICALL Java_org_simantics_fmil_core_FMIL_setStepLength_1 
234         (JNIEnv *env, jobject obj, jint id, jdouble stepLength) {
235         fmus[id].timeStep = stepLength;
236         return 0;
237 }
238
239 JNIEXPORT jint JNICALL Java_org_simantics_fmil_core_FMIL_subscribe_1
240   (JNIEnv *env, jobject obj, jint id, jintArray vrs) {
241
242         jboolean isCopy;
243         jint* elements = env -> GetIntArrayElements(vrs, &isCopy);
244         jsize n = env -> GetArrayLength(vrs);
245
246         int i;
247         for (i = 0; i < n; i++) {
248                 fmus[id].subscription.push_back(elements[i]);
249         } 
250           
251         if (isCopy == JNI_TRUE) {
252                 env -> ReleaseIntArrayElements(vrs, elements, 0);
253         }
254
255         return 0;
256
257 }
258
259 bool referenceExists(FMUControlStruct fmuStruct, string variable) {
260         map<string,int>::iterator it = fmuStruct.indexes.find(variable);
261         if(it != fmuStruct.indexes.end()) {
262                 return true;
263         } else {
264                 return false;
265         }
266 }
267
268 // Remember to check if reference exists
269 fmiValueReference getReference(FMUControlStruct fmuStruct, string variable) {
270         return fmuStruct.fmiValueReferences[fmuStruct.indexes[variable]];
271 }
272
273 // Get string representation of a scalar variable type
274 string getTypeString(ScalarVariable* sv) {
275         switch (sv->typeSpec->type){
276                 case elm_Integer:
277                         return "Integer";
278                 case elm_Enumeration:
279                         return "Enumeration";
280                 case elm_Real:
281                         return "Real";
282                 case elm_Boolean:
283                         return "Boolean";
284                 default:
285                         return "No type";
286         }
287 }
288
289 JNIEXPORT jint JNICALL Java_org_simantics_fmil_core_FMIL_setRealValue_1
290   (JNIEnv *env, jobject obj, jint id, jint vr, jdouble value) {
291
292           const char *error = "";
293           FMI1 fmi = fmus[id];
294           if (fmi.version == 1) {
295                 FMI1_CS_SET_REAL(fmi.fmu, vr, value, &error);
296           } else if (fmi.version == 2) {
297                   FMI2_CS_SET_REAL(fmi.fmu, vr, value, &error);
298           }
299           if (!isEmpty(error)) {
300                   string message = "Could not set real value ";
301                   return throwFMILException(env, message += error);
302       }
303           return 0;
304 }
305
306 JNIEXPORT jint JNICALL Java_org_simantics_fmil_core_FMIL_setIntegerValue_1
307   (JNIEnv *env, jobject obj, jstring id, jstring parameter, jint value) {
308           /*
309         const char *fmuId = env->GetStringUTFChars(id, 0);
310         if(exists(fmuId)) {
311                 FMUControlStruct& fmuStruct = fmus[fmuId];
312                 const char *name = env->GetStringUTFChars(parameter, 0);
313                 string nameString = name;
314                 string modelId = fmuId;
315                 if(!referenceExists(fmuStruct, name)) {
316                         string errorMessage = "setIntegerValue: Model (id " + modelId + ") does not contain variable: " + nameString;
317                         env->ReleaseStringUTFChars(parameter, name);
318                         env->ReleaseStringUTFChars(id, fmuId);
319                         return throwException(env, errorMessage);
320                 } else {
321                         // Check variable type
322                         ScalarVariable* sv = fmuStruct.vars[fmuStruct.indexes[name]];
323                         switch (sv->typeSpec->type){
324                                 case elm_Integer:
325                                         break; // ok
326                                 default: {
327                                         string errorMessage = "setIntegerValue: " + nameString + " is not of type Integer. (type: + " + getTypeString(sv) + ")";
328                                         env->ReleaseStringUTFChars(parameter, name);
329                                         env->ReleaseStringUTFChars(id, fmuId);
330                                         return throwException(env, errorMessage);
331                                 }
332                         }
333
334                         // Change value
335                         fmiValueReference vr = getReference(fmuStruct, name);
336                         const int intValue = (int) value;
337                         fmuStruct.fmu.setInteger(fmuStruct.c, &vr, 1, &intValue);
338                         env->ReleaseStringUTFChars(parameter, name);
339                         env->ReleaseStringUTFChars(id, fmuId);
340                         return 1;
341                 }
342         }  else {
343                 string message = fmuId;
344                 env->ReleaseStringUTFChars(id, fmuId);
345                 return throwException(env, "setIntegerValue: Model id " + message + " not found");
346         }
347         */
348           return 1;
349 }
350
351 JNIEXPORT jint JNICALL Java_org_simantics_fmil_core_FMIL_setBooleanValue_1
352   (JNIEnv *env, jobject obj, jstring id, jstring parameter, jboolean value) {
353           /*
354         const char *fmuId = env->GetStringUTFChars(id, 0);
355         if(exists(fmuId)) {
356                 FMUControlStruct& fmuStruct = fmus[fmuId];
357                 const char *name = env->GetStringUTFChars(parameter, 0);
358                 string nameString = name;
359                 string modelId = fmuId;
360                 if(!referenceExists(fmuStruct, name)) {
361                         string errorMessage = "setBooleanValue: Model (id " + modelId + ") does not contain variable: " + nameString;
362                         env->ReleaseStringUTFChars(parameter, name);
363                         env->ReleaseStringUTFChars(id, fmuId);
364                         return throwException(env, errorMessage);
365                 } else {
366                         // Check variable type
367                         ScalarVariable* sv = fmuStruct.vars[fmuStruct.indexes[name]];
368                         switch (sv->typeSpec->type){
369                                 case elm_Boolean:
370                                         break; // ok
371                                 default: {
372                                         string errorMessage = "setBooleanValue: " + nameString + " is not of type Boolean. (type: + " + getTypeString(sv) + ")";
373                                         env->ReleaseStringUTFChars(parameter, name);
374                                         env->ReleaseStringUTFChars(id, fmuId);
375                                         return throwException(env, errorMessage);
376                                 }
377                         }
378
379                         // Change value
380                         fmiValueReference vr = getReference(fmuStruct, name);
381                         fmiBoolean result = 1;
382                         if(value == 0)
383                                 result = 0;
384                         fmuStruct.fmu.setBoolean(fmuStruct.c, &vr, 1, &result);
385                         env->ReleaseStringUTFChars(parameter, name);
386                         env->ReleaseStringUTFChars(id, fmuId);
387                         return 1;
388                 }
389         }  else {
390                 string message = fmuId;
391                 env->ReleaseStringUTFChars(id, fmuId);
392                 return throwException(env, "setBooleanValue: Model id " + message + " not found");
393         }*/
394           return 1;
395 }
396
397 JNIEXPORT jboolean JNICALL Java_org_simantics_fmil_core_FMIL_isInitialized_1
398   (JNIEnv *env, jobject obj, jstring id) {
399           /*
400         const char *fmuId = env->GetStringUTFChars(id, 0);
401         if(exists(fmuId)) {
402                 FMUControlStruct& fmuStruct = fmus[fmuId];
403                 env->ReleaseStringUTFChars(id, fmuId);
404                 return fmuStruct.initialized;
405         } else {
406                 env->ReleaseStringUTFChars(id, fmuId);
407                 return false;
408         }
409         */
410           return 1;
411 }
412
413
414 JNIEXPORT jdouble JNICALL Java_org_simantics_fmil_core_FMIL_getTime_1
415   (JNIEnv *env, jobject obj, jint id) {
416           return fmus[id].currentTime;
417 }
418
419 double getRealValue(FMUControlStruct fmuStruct, int index) {
420         ScalarVariable *sv = fmuStruct.vars[index];
421         fmiValueReference vr = fmuStruct.fmiValueReferences[index];
422         double real;
423         fmiInteger integer;
424         fmiBoolean fmibool;
425
426         switch (sv->typeSpec->type){
427         case elm_Real:
428                         fmuStruct.fmu.getReal(fmuStruct.c, &vr, 1, &real);
429             break;
430         case elm_Integer:
431         case elm_Enumeration:
432             fmuStruct.fmu.getInteger(fmuStruct.c, &vr, 1, &integer);
433                         real = (double)integer;
434             break;
435         case elm_Boolean:
436             fmuStruct.fmu.getBoolean(fmuStruct.c, &vr, 1, &fmibool);
437                         if(fmibool == fmiTrue)
438                                 real = 1.0;
439                         else
440                                 real = 0.0;
441             break;
442         }
443         return real;
444 }
445
446 JNIEXPORT jdoubleArray JNICALL Java_org_simantics_fmil_core_FMIL_getSubscribedResults_1
447   (JNIEnv *env, jobject obj, jint id, jdoubleArray result) {
448
449         jboolean isCopy;
450         jdouble* resultElements = env -> GetDoubleArrayElements(result, &isCopy);
451         jsize n = env -> GetArrayLength(result);
452         int *vrs;
453         const char *error = "";
454
455         FMI1 fmi = fmus[id];
456         if(n > 0) {
457                 vrs = &(fmus[id].subscription[0]);
458                 if (fmi.version == 1) {
459                         FMI1_CS_GET_REALS(fmi.fmu, vrs, resultElements, n, &error);
460                 } else if (fmi.version == 2) {
461                         FMI2_CS_GET_REALS(fmi.fmu, vrs, resultElements, n, &error);
462                 }
463         }
464         if (isCopy == JNI_TRUE) {
465                 env -> ReleaseDoubleArrayElements(result, resultElements, 0);
466         }
467
468         return result;
469         
470 }
471
472 JNIEXPORT jint JNICALL Java_org_simantics_fmil_core_FMIL_instantiateSimulation_1
473   (JNIEnv *env, jobject obj, jint id) {
474
475           int returnValue;
476           const char *error = "";
477
478           FMI1 &fmi = fmus[id];
479           if (fmi.version == 1) {
480                 returnValue = FMI1_CS_INSTANTIATE(fmi.fmu, "", &error);
481           } else if (fmi.version == 2) {
482                   returnValue = FMI2_CS_INSTANTIATE(fmi.fmu, "", &error);
483           }
484           if(returnValue != 0) {
485                 string message = "No FMU loaded: ";
486                 return throwFMILException(env, message += error);
487           }
488           return 0;
489 }
490
491 JNIEXPORT jint JNICALL Java_org_simantics_fmil_core_FMIL_initializeSimulation_1
492   (JNIEnv *env, jobject obj, jint id) {
493         
494         const char *error = "";
495         int returnValue;
496         FMI1 fmi = fmus[id];
497         if (fmi.version == 1) {
498                 returnValue = FMI1_CS_INITIALIZE(fmi.fmu, &error);
499         } else if (fmi.version == 2) {
500                 returnValue = FMI2_CS_INITIALIZE(fmi.fmu, &error);
501         }
502         if(returnValue != 0) {
503                 string message = "Could not initialize simulation: ";
504                 return throwFMILException(env, message += error);
505         }
506
507         return 0;
508
509 }
510
511 JNIEXPORT jint JNICALL Java_org_simantics_fmil_core_FMIL_setTime_1
512   (JNIEnv *env, jobject obj, jstring id, jdouble time) {
513           return 0;
514 }
515
516 JNIEXPORT jobjectArray JNICALL Java_org_simantics_fmil_core_FMIL_getAllVariables_1
517   (JNIEnv *env, jobject obj, jint id) {
518
519         jobjectArray ret= (jobjectArray)env->NewObjectArray(fmus[id].variables.size(),  
520                         env->FindClass("java/lang/String"),  
521                         env->NewStringUTF(""));  
522    
523         for(unsigned int i=0;i<fmus[id].variables.size();i++) {  
524                 env->SetObjectArrayElement(ret,i,env->NewStringUTF(fmus[id].variables[i].c_str()));  
525         }  
526
527         return ret;  
528
529 }
530
531 JNIEXPORT jobjectArray JNICALL Java_org_simantics_fmil_core_FMIL_getAllVariableDescriptions_1
532   (JNIEnv *env, jobject obj, jint id) {
533
534         jobjectArray ret= (jobjectArray)env->NewObjectArray(fmus[id].descriptions.size(),  
535                         env->FindClass("java/lang/String"),  
536                         env->NewStringUTF(""));  
537    
538         for(unsigned int i=0;i<fmus[id].descriptions.size();i++) {  
539                 env->SetObjectArrayElement(ret,i,env->NewStringUTF(fmus[id].descriptions[i].c_str()));  
540         }  
541
542         return ret;  
543
544 }
545
546 JNIEXPORT jobjectArray JNICALL Java_org_simantics_fmil_core_FMIL_getAllVariableDeclaredTypes_1
547   (JNIEnv *env, jobject obj, jint id) {
548
549         jobjectArray ret= (jobjectArray)env->NewObjectArray(fmus[id].declaredTypes.size(),  
550                         env->FindClass("java/lang/String"),  
551                         env->NewStringUTF(""));
552    
553         for(unsigned int i=0;i<fmus[id].declaredTypes.size();i++) {  
554                 env->SetObjectArrayElement(ret,i,env->NewStringUTF(fmus[id].declaredTypes[i].c_str()));  
555         }  
556
557         return ret;  
558
559 }
560
561 JNIEXPORT jintArray JNICALL Java_org_simantics_fmil_core_FMIL_getAllVariableReferences_1
562   (JNIEnv *env, jobject obj, jint id, jintArray result) {
563
564         jboolean isCopy;
565         jint* resultElements = env -> GetIntArrayElements(result, &isCopy);
566         jsize n = env -> GetArrayLength(result);
567
568         int i;
569         for (i = 0; i < n; i++) {
570                 resultElements[i] = fmus[id].valueReferences[i];
571         } 
572           
573         if (isCopy == JNI_TRUE) {
574                 env -> ReleaseIntArrayElements(result, resultElements, 0);
575         }
576
577         return result;
578
579 }
580
581 JNIEXPORT jintArray JNICALL Java_org_simantics_fmil_core_FMIL_getAllVariableTypes_1
582   (JNIEnv *env, jobject obj, jint id, jintArray result) {
583
584         jboolean isCopy;
585         jint* resultElements = env -> GetIntArrayElements(result, &isCopy);
586         jsize n = env -> GetArrayLength(result);
587
588         int i;
589         for (i = 0; i < n; i++) {
590                 resultElements[i] = fmus[id].types[i];
591         } 
592           
593         if (isCopy == JNI_TRUE) {
594                 env -> ReleaseIntArrayElements(result, resultElements, 0);
595         }
596
597         return result;
598
599 }
600
601 JNIEXPORT jintArray JNICALL Java_org_simantics_fmil_core_FMIL_getAllVariableVariabilities_1
602   (JNIEnv *env, jobject obj, jint id, jintArray result) {
603
604         jboolean isCopy;
605         jint* resultElements = env -> GetIntArrayElements(result, &isCopy);
606         jsize n = env -> GetArrayLength(result);
607
608         for (jsize i = 0; i < n; i++) {
609                 resultElements[i] = fmus[id].variabilities[i];
610         } 
611           
612         if (isCopy == JNI_TRUE) {
613                 env -> ReleaseIntArrayElements(result, resultElements, 0);
614         }
615
616         return result;
617
618 }
619
620 JNIEXPORT jintArray JNICALL Java_org_simantics_fmil_core_FMIL_getAllVariableCausalities_1
621   (JNIEnv *env, jobject obj, jint id, jintArray result) {
622
623         jboolean isCopy;
624         jint* resultElements = env -> GetIntArrayElements(result, &isCopy);
625         jsize n = env -> GetArrayLength(result);
626
627         for (jsize i = 0; i < n; i++) {
628                 resultElements[i] = fmus[id].causalities[i];
629         } 
630           
631         if (isCopy == JNI_TRUE) {
632                 env -> ReleaseIntArrayElements(result, resultElements, 0);
633         }
634
635         return result;
636
637 }
638
639 JNIEXPORT jobjectArray JNICALL Java_org_simantics_fmil_core_FMIL_getAllDeclaredTypes_1
640   (JNIEnv *env, jobject obj, jint id) {
641
642         jobjectArray ret= (jobjectArray)env->NewObjectArray(fmus[id].declaredTypeNames.size(),  
643                         env->FindClass("java/lang/String"),  
644                         env->NewStringUTF(""));
645    
646         for(unsigned int i=0;i<fmus[id].declaredTypeNames.size();i++) {  
647                 env->SetObjectArrayElement(ret,i,env->NewStringUTF(fmus[id].declaredTypeNames[i].c_str()));  
648         }  
649
650         return ret;  
651
652 }
653
654 JNIEXPORT jobjectArray JNICALL Java_org_simantics_fmil_core_FMIL_getAllDeclaredTypeDescriptions_1
655   (JNIEnv *env, jobject obj, jint id) {
656
657         jobjectArray ret= (jobjectArray)env->NewObjectArray(fmus[id].typeDescriptions.size(),  
658                         env->FindClass("java/lang/String"),  
659                         env->NewStringUTF(""));
660    
661         for(unsigned int i=0;i<fmus[id].typeDescriptions.size();i++) {  
662                 env->SetObjectArrayElement(ret,i,env->NewStringUTF(fmus[id].typeDescriptions[i].c_str()));  
663         }  
664
665         return ret;  
666
667 }
668
669 JNIEXPORT jobjectArray JNICALL Java_org_simantics_fmil_core_FMIL_getAllDeclaredTypeQuantities_1
670   (JNIEnv *env, jobject obj, jint id) {
671
672         jobjectArray ret= (jobjectArray)env->NewObjectArray(fmus[id].quantities.size(),  
673                         env->FindClass("java/lang/String"),  
674                         env->NewStringUTF(""));
675    
676         for(unsigned int i=0;i<fmus[id].quantities.size();i++) {  
677                 env->SetObjectArrayElement(ret,i,env->NewStringUTF(fmus[id].quantities[i].c_str()));  
678         }  
679
680         return ret;  
681
682 }
683
684 JNIEXPORT jobjectArray JNICALL Java_org_simantics_fmil_core_FMIL_getAllDeclaredTypeUnits_1
685   (JNIEnv *env, jobject obj, jint id) {
686
687         jobjectArray ret= (jobjectArray)env->NewObjectArray(fmus[id].units.size(),  
688                         env->FindClass("java/lang/String"),  
689                         env->NewStringUTF(""));
690    
691         for(unsigned int i=0;i<fmus[id].units.size();i++) {  
692                 env->SetObjectArrayElement(ret,i,env->NewStringUTF(fmus[id].units[i].c_str()));  
693         }  
694
695         return ret;  
696
697 }
698
699 /*
700 JNIEXPORT jobjectArray JNICALL Java_org_simantics_fmil_core_FMIL_filterVariables_1
701   (JNIEnv *env, jobject obj, jstring id, jstring regexp) {
702          const char *rx = env->GetStringUTFChars(regexp, 0);
703          jobjectArray result = filterVariables(env, obj, id, rx);
704          env->ReleaseStringUTFChars(regexp, rx);
705          return result;
706 }
707 */
708
709 JNIEXPORT jint JNICALL Java_org_simantics_fmil_core_FMIL_simulateStep_1
710   (JNIEnv *env, jobject obj, jint id) {
711
712           int returnValue;
713           const char *error = "";
714
715           FMI1 &fmi = fmus[id];
716           if (fmi.version == 1) {
717                   returnValue = FMI1_CS_STEP(fmi.fmu, fmi.currentTime, fmi.timeStep, &error);
718           } else if (fmi.version == 2) {
719                   returnValue = FMI2_CS_STEP(fmi.fmu, fmi.currentTime, fmi.timeStep, &error);
720           }
721           if(returnValue != 0) {
722                   string message = "Could not simulate step: ";
723                   return throwException(env,  message += error);
724           }
725
726           fmi.currentTime += fmi.timeStep;
727
728           return 0;
729
730           /*
731         const char *fmuId = env->GetStringUTFChars(id, 0);
732         if(exists(fmuId)) {
733                 FMUControlStruct& fmuStruct = fmus[fmuId];
734                 env->ReleaseStringUTFChars(id, fmuId);
735
736                 if(&fmuStruct.fmu == NULL || fmuStruct.fmu.modelDescription == NULL || &fmuStruct.vars == NULL) {
737                         return throwException(env, "Simulate step failed - fmu not loaded");
738                 }
739
740                 if(fmuStruct.x == NULL) {
741                         return throwException(env, "Simulate step failed - fmu not instantiated");
742                 }
743
744                 if(fmuStruct.initialized == false) {
745                         fmiBoolean toleranceControlled = fmiFalse;
746                         fmuStruct.fmiFlag =  fmuStruct.fmu.initialize(fmuStruct.c, toleranceControlled, fmuStruct.currentTime, &(fmuStruct.eventInfo));
747                         if (fmuStruct.fmiFlag > fmiWarning)  return throwException(env, "could not initialize model");
748                         fmuStruct.initialized = true;
749                 }
750
751                 FMU& fmu = fmuStruct.fmu;
752                 int debug = 0; // DEBUG ON = 1, OFF = 0
753
754                 int i;
755                 double dt, tPre, tEnd = fmuStruct.currentTime + fmuStruct.step;
756
757                 fmiBoolean timeEvent, stateEvent, stepEvent;
758                 fmiStatus fmiFlag;                      // return code of the fmu functions
759                 fmiValueReference vr;
760
761
762                 */
763                 /* Simulate the duration of one step. The simulation may be done in 
764                  * multiple parts if events occur
765                  */ /*
766                 while (fmuStruct.currentTime < tEnd) {
767                         // get current state and derivatives
768                         fmiFlag = fmu.getContinuousStates(fmuStruct.c, fmuStruct.x, fmuStruct.nx);
769                         if (fmiFlag > fmiWarning) 
770                                 return throwException(env, "could not retrieve states");
771
772                         fmiFlag = fmu.getDerivatives(fmuStruct.c, fmuStruct.xdot, fmuStruct.nx);
773                         if (fmiFlag > fmiWarning) 
774                                 return throwException(env, "could not retrieve derivatives");
775
776                          // advance time
777                         tPre = fmuStruct.currentTime;
778                         fmuStruct.currentTime = min(fmuStruct.currentTime+fmuStruct.step, tEnd);
779                         timeEvent = fmuStruct.eventInfo.upcomingTimeEvent && fmuStruct.eventInfo.nextEventTime < fmuStruct.currentTime;  
780                 
781                         if (timeEvent) fmuStruct.currentTime = fmuStruct.eventInfo.nextEventTime;
782                         dt = fmuStruct.currentTime - tPre; 
783                         fmiFlag = fmu.setTime(fmuStruct.c, fmuStruct.currentTime);
784                         if (fmiFlag > fmiWarning) throwException(env, "could not set time");
785
786                         if(referenceExists(fmuStruct, "time")) {
787                                 vr = getReference(fmuStruct, "time");
788                                 if(vr != NULL) {
789                                         fmu.setReal(fmuStruct.c, &vr, 1, &(fmuStruct.currentTime));
790                                 }
791                         }
792
793                         if(debug)
794                                 printf("Actual time: %lf\n", fmuStruct.currentTime);
795
796                         if (fmiFlag > fmiWarning) 
797                                 return throwException(env, "could not set time");
798
799                         // perform one step
800                         for (i=0; i<fmuStruct.nx; i++) 
801                                 fmuStruct.x[i] += dt*fmuStruct.xdot[i]; // forward Euler method
802
803                         fmiFlag = fmu.setContinuousStates(fmuStruct.c, fmuStruct.x, fmuStruct.nx);
804                         if (fmiFlag > fmiWarning) 
805                                 return throwException(env, "could not set states");
806
807                         // Check for step event, e.g. dynamic state selection
808                         fmiFlag = fmu.completedIntegratorStep(fmuStruct.c, &stepEvent);
809                         if (fmiFlag > fmiWarning) return throwException(env, "could not complete intgrator step");
810                         */
811 /*                      for (i=0; i<fmuStruct.nz; i++) fmuStruct.prez[i] = fmuStruct.z[i]; 
812                         fmiFlag = fmu.getEventIndicators(fmuStruct.c, fmuStruct.z, fmuStruct.nz);
813                         if (fmiFlag > fmiWarning) return throwException(env, "could not retrieve event indicators");
814                         stateEvent = FALSE;
815                         for (i=0; i<fmuStruct.nz; i++) 
816                                 stateEvent = stateEvent || (fmuStruct.prez[i] * fmuStruct.z[i] < 0);  
817      
818
819                         stepEvent = fmiTrue;
820                         // handle events
821                         if (timeEvent || stateEvent || stepEvent) {
822         
823                                 // event iteration in one step, ignoring intermediate results
824                                 fmiFlag = fmu.eventUpdate(fmuStruct.c, fmiFalse, &(fmuStruct.eventInfo));
825                                 if (fmiFlag > fmiWarning) return throwException(env, "could not perform event update");
826       
827                         } // if event
828                         */
829         
830 /*              }
831
832                 fflush(stdout);
833                 return 1;
834
835         } else {
836                 string message = fmuId;
837                 env->ReleaseStringUTFChars(id, fmuId);
838                 return throwException(env, "simulateStep: Model id " + message + " not found");
839         }*/
840         return 1;
841 }
842
843 JNIEXPORT jint JNICALL Java_org_simantics_fmil_core_FMIL_unloadFMU_1
844   (JNIEnv *env, jobject obj, jint id) {
845
846           int returnValue;
847           const char *error = "";
848
849           FMI1 fmi = fmus[id];
850           if (fmi.version == 1) {
851                   returnValue = FMI1_CS_UNLOAD(fmi.fmu, &error);
852           } else if (fmi.version == 2) {
853                   returnValue = FMI2_CS_UNLOAD(fmi.fmu, &error);
854           }
855           if(returnValue != 0) {
856                 string message = "Could not unload FMU: ";
857                 return throwException(env, message += error);
858           }
859           return returnValue;
860 }
861
862 JNIEXPORT jdouble JNICALL Java_org_simantics_fmil_core_FMIL_getRealValue_1
863   (JNIEnv *env, jobject obj, jint id, jint vr) {
864
865           double value;
866           const char *error = "";
867
868           FMI1 fmi = fmus[id];
869           if (fmi.version == 1) {
870                   value = FMI1_CS_GET_REAL(fmi.fmu, vr, &error);
871           } else if (fmi.version == 2) {
872                   value = FMI2_CS_GET_REAL(fmi.fmu, vr, &error);
873           }
874           if (!isEmpty(error)) {
875                   string message = "Could not get real value: ";
876                   return throwFMILException(env, message += error);
877           }
878           return value;
879 }
880
881 JNIEXPORT jint JNICALL Java_org_simantics_fmil_core_FMIL_getIntegerValue_1
882   (JNIEnv *env, jobject obj, jstring id, jstring variable) {
883           /*
884         const char *fmuId = env->GetStringUTFChars(id, 0);
885         if(exists(fmuId)) {
886                 FMUControlStruct fmuStruct = fmus[fmuId];
887                 env->ReleaseStringUTFChars(id, fmuId);
888                 const char *name = env->GetStringUTFChars(variable, 0);
889
890                 if(referenceExists(fmuStruct, name)) {
891                         fmiValueReference vr = getReference(fmuStruct, name);
892                         int result;
893                         fmuStruct.fmu.getInteger(fmuStruct.c, &vr, 1, &result);
894                         env->ReleaseStringUTFChars(variable, name);
895                         return result;
896
897                 } else {
898                          string nameString = name;
899                          string message = "Variable " + nameString + " not found";
900                          env->ReleaseStringUTFChars(variable, name);
901                          return throwException(env, message);
902                 }
903
904         } else {
905                 string message = fmuId;
906                 env->ReleaseStringUTFChars(id, fmuId);
907                 return throwException(env, "unloadFMU: Model id " + message + " not found");
908         }
909         */
910           return 1;
911
912 }
913
914 JNIEXPORT jboolean JNICALL Java_org_simantics_fmil_core_FMIL_getBooleanValue_1
915   (JNIEnv *env, jobject obj, jstring id, jstring variable) {
916           /*
917         const char *fmuId = env->GetStringUTFChars(id, 0);
918         if(exists(fmuId)) {
919                 FMUControlStruct fmuStruct = fmus[fmuId];
920                 env->ReleaseStringUTFChars(id, fmuId);
921                 const char *name = env->GetStringUTFChars(variable, 0);
922
923                 if(referenceExists(fmuStruct, name)) {
924                         fmiValueReference vr = getReference(fmuStruct, name);
925                         fmiBoolean result;
926                         fmuStruct.fmu.getBoolean(fmuStruct.c, &vr, 1, &result);
927                         env->ReleaseStringUTFChars(variable, name);
928                         return result;
929
930                 } else {
931                          string nameString = name;
932                          string message = "Variable " + nameString + " not found";
933                          env->ReleaseStringUTFChars(variable, name);
934                          return throwException(env, message);
935                 }
936
937         } else {
938                 string message = fmuId;
939                 env->ReleaseStringUTFChars(id, fmuId);
940                 return throwException(env, "unloadFMU: Model id " + message + " not found");
941         }*/
942           return 1;
943
944 }
945
946 JNIEXPORT jstring JNICALL Java_org_simantics_fmil_core_FMIL_getStringValue_1
947   (JNIEnv *env, jobject obj, jstring id, jstring variable) {
948           /*
949         const char *fmuId = env->GetStringUTFChars(id, 0);
950         if(exists(fmuId)) {
951                 FMUControlStruct fmuStruct = fmus[fmuId];
952                 env->ReleaseStringUTFChars(id, fmuId);
953                 const char *name = env->GetStringUTFChars(variable, 0);
954
955                 if(referenceExists(fmuStruct, name)) {
956                         fmiValueReference vr = getReference(fmuStruct, name);
957                         fmiString result;
958                         fmuStruct.fmu.getString(fmuStruct.c, &vr, 1, &result);
959                         env->ReleaseStringUTFChars(variable, name);
960                         return env->NewStringUTF(result);
961
962                 } else {
963                          string nameString = name;
964                          string message = "Variable " + nameString + " not found";
965                          env->ReleaseStringUTFChars(variable, name);
966                          return 0; //throwException(env, message);
967                 }
968
969         } else {
970                 string message = fmuId;
971                 env->ReleaseStringUTFChars(id, fmuId);
972                 return 0; //throwException(env, "unloadFMU: Model id " + message + " not found");
973         }
974         */
975           return 0;
976
977 }