]> gerrit.simantics Code Review - simantics/fmil.git/blobdiff - org.simantics.fmil.core/src/org/simantics/fmil/core/FMIL.java
Switch to full JavaSE-11+ compatibility
[simantics/fmil.git] / org.simantics.fmil.core / src / org / simantics / fmil / core / FMIL.java
index f4c7ca4f2fbbf7d044be10c09a2b4f896b31fe0b..0e413afcef29ff63c1cd7c98ee01044d917d7b6d 100644 (file)
@@ -32,11 +32,14 @@ public class FMIL {
 
     private static final Logger LOGGER = LoggerFactory.getLogger(FMIL.class);
 
+       private static final boolean DEBUG = false;
+    
     /**
      * Static variables
      */
     private static int      OK                  = 0;
     private static int      ERROR               = 1;
+    private static int      PENDING                    = 2;
     private static String   UNSATISFIED_LINK    = "Method not found. DLL might not be loaded properly.";
     public static final String TEMP_FMU_DIRECTORY_NAME = "fmil";
     public static String    TEMP_FMU_COMMON_DIRECTORY;
@@ -120,7 +123,9 @@ public class FMIL {
        private String[] declaredTypeQuantities;
        private String[] declaredTypeUnits;
        
-       private TObjectIntHashMap<String> variableMap = new TObjectIntHashMap<String>();
+       private static int NO_VARIABLE_KEY = -1;
+       
+       private TObjectIntHashMap<String> variableMap = new TObjectIntHashMap<String>(10, 0.5f, NO_VARIABLE_KEY);
        
        private Set<String> subscriptionSet = new HashSet<String>();
        private TIntArrayList subscription = new TIntArrayList();
@@ -134,7 +139,7 @@ public class FMIL {
                synchronized(syncObject) {
                        // Safety check
                        int vr = variableMap.get(name);
-                       if(vr == 0) return false;
+                       if(vr == NO_VARIABLE_KEY) return false;
                        if(!subscriptionSet.add(name)) return false;
                        subscribedNames.add(name);
                        subscription.add(vr);
@@ -181,9 +186,14 @@ public class FMIL {
      * @throws FMILException
      */
     private int fmuN = 0;
-    private boolean fmuLoaded = false;
+    private boolean instantiated = false;
     public void loadFMUFile(String path) throws FMILException {
 
+        if (!Files.exists(Paths.get(path)))
+            throw new FMILException("File " + path + " does not exist");
+        if (!Files.isRegularFile(Paths.get(path)))
+            throw new FMILException("Path " + path + " is not a file");
+
         synchronized(syncObject) {
 
             if(fmuN % 2 == 0) {
@@ -221,8 +231,8 @@ public class FMIL {
                 for(int i=0;i<variableNames.length;i++) {
                        variableMap.put(variableNames[i], variableReferences[i]);
                 }
-
-                fmuLoaded = true;
+                
+                instantiated = false;
             } catch (UnsatisfiedLinkError err) {
                 throw new FMILException(UNSATISFIED_LINK, err);
             } catch (Exception e) {
@@ -232,7 +242,7 @@ public class FMIL {
         }
     }
 
-    private native int loadFMUFile_(String path, String toDir);
+    private native int loadFMUFile_(String path, String toDir) throws FMILException;
 
     /**
      * Set a step length for simulation
@@ -270,9 +280,11 @@ public class FMIL {
             try {
 
                 int ret = instantiateSimulation_(getModelIDNew()); 
-                if(ret != OK)
+                if(ret != OK) {
                     LOGGER.warn("Function return value != OK, an exception should have been thrown from native code!");
-
+                } else {
+                       instantiated = true;
+                }
             } catch (FMILException e) {
                 throw e;
             } catch (UnsatisfiedLinkError err) {
@@ -340,23 +352,34 @@ public class FMIL {
     private native int subscribe_(int id, int[] variables);
 
     /**
-     * Set a new (Real, double) value for a variable. If the variable is a 
+     * Set value of a real variable. If the variable is a 
      * parameter, the change is effective immediately.
      *  
-     * @param name Variable
-     * @param value New (Real, double) value
+     * @param name  Variable name
+     * @param value  New value
      * @throws FMILException
      */
     public void setRealValue(String name, double value) throws FMILException {
-       
-        synchronized(syncObject) {
+       int key = variableMap.get(name);
+       if(key == NO_VARIABLE_KEY)
+               throw new FMILException("No variable with name " + name);
+       setRealValue(key, value);
+    }
 
+    /**
+     * Set value of a real variable. If the variable is a 
+     * parameter, the change is effective immediately.
+     *  
+     * @param name  Variable id
+     * @param value  New value
+     * @throws FMILException
+     */
+    public void setRealValue(int variableReference, double value) throws FMILException {
+        synchronized(syncObject) {
             try {
-
-                int ret = setRealValue_(getModelIDNew(), variableMap.get(name), value); 
+                int ret = setRealValue_(getModelIDNew(), variableReference, value); 
                 if(ret != OK)
                     LOGGER.warn("Function return value != OK, an exception should have been thrown from native code!");
-
             } catch (FMILException e) {
                 throw e;
             } catch (UnsatisfiedLinkError err) {
@@ -364,21 +387,83 @@ public class FMIL {
             } catch (Exception e) {
                 throw new FMILException(e.getMessage());
             }
-            
         }
-        
     }
 
-    public void setRealValue(int variableReference, double value) throws FMILException {
-       
-        synchronized(syncObject) {
+    private native int setRealValue_(int id, int variableReference, double value) throws FMILException;
 
-            try {
+    
+    /**
+     * Set value of an integer variable. If the variable is a 
+     * parameter, the change is effective immediately.
+     *  
+     * @param name  Variable name
+     * @param value  New value
+     * @throws FMILException
+     */
+    public void setIntegerValue(String name, int value) throws FMILException {
+       int key = variableMap.get(name);
+       if(key == NO_VARIABLE_KEY)
+               throw new FMILException("No variable with name " + name);
+       setIntegerValue(key, value);
+    }
 
-                int ret = setRealValue_(getModelIDNew(), variableReference, value); 
+    /**
+     * Set value of an integer variable. If the variable is a 
+     * parameter, the change is effective immediately.
+     *  
+     * @param name  Variable id
+     * @param value  New value
+     * @throws FMILException
+     */
+    public void setIntegerValue(int variableReference, int value) throws FMILException {
+        synchronized(syncObject) {
+            try {
+                int ret = setIntegerValue_(getModelIDNew(), variableReference, value); 
                 if(ret != OK)
                     LOGGER.warn("Function return value != OK, an exception should have been thrown from native code!");
+            } catch (FMILException e) {
+                throw e;
+            } catch (UnsatisfiedLinkError err) {
+                throw new FMILException(UNSATISFIED_LINK);
+            } catch (Exception e) {
+                throw new FMILException(e.getMessage());
+            }
+        }
+    }
 
+    private native int setIntegerValue_(int id, int variableReference, int value) throws FMILException;
+
+    
+    /**
+     * Set value of a boolean variable. If the variable is a 
+     * parameter, the change is effective immediately.
+     *  
+     * @param name  Variable name
+     * @param value  New value
+     * @throws FMILException
+     */
+    public void setBooleanValue(String name, boolean value) throws FMILException {
+       int key = variableMap.get(name);
+       if(key == NO_VARIABLE_KEY)
+               throw new FMILException("No variable with name " + name);
+       setBooleanValue(key, value);
+    }
+
+    /**
+     * Set value of a boolean variable. If the variable is a 
+     * parameter, the change is effective immediately.
+     *  
+     * @param name  Variable id
+     * @param value  New value
+     * @throws FMILException
+     */
+    public void setBooleanValue(int variableReference, boolean value) throws FMILException {
+        synchronized(syncObject) {
+            try {
+                int ret = setBooleanValue_(getModelIDNew(), variableReference, value); 
+                if(ret != OK)
+                    LOGGER.warn("Function return value != OK, an exception should have been thrown from native code!");
             } catch (FMILException e) {
                 throw e;
             } catch (UnsatisfiedLinkError err) {
@@ -386,82 +471,53 @@ public class FMIL {
             } catch (Exception e) {
                 throw new FMILException(e.getMessage());
             }
-            
         }
-        
     }
 
-    private native int setRealValue_(int id, int variableReference, double value) throws FMILException;
+    private native int setBooleanValue_(int id, int variableReference, boolean value) throws FMILException;
 
-//    /**
-//     * Set a new (integer) value for a variable. If the variable is a 
-//     * parameter, the change is effective immediately.
-//     *  
-//     * @param name Variable
-//     * @param value New (integer) value
-//     * @throws FMILException
-//     */
-//    public void setIntegerValue(String name, int value) throws FMILException {
-//        synchronized(syncObject) {
-//
-//            try {
-//
-//                int ret = setIntegerValue_(getModelID(), name, value); 
-//                if(ret == ERROR)
-//                    throw new FMILException(getLastErrorMessage());
-//
-//            } catch (UnsatisfiedLinkError err) {
-//                throw new FMILException(UNSATISFIED_LINK);
-//            } catch (Exception e) {
-//                throw new FMILException(e.getMessage());
-//            }
-//        }
-//    }
-//    private native int setIntegerValue_(String id, String name, int value);
-//
-//    /**
-//     * Set a new (boolean) value for a variable. If the variable is a 
-//     * parameter, the change is effective immediately.
-//     *  
-//     * @param name Variable
-//     * @param value New (boolean) value
-//     * @throws FMILException
-//     */
-//    public void setBooleanValue(String name, boolean value) throws FMILException {
-//        synchronized(syncObject) {
-//
-//            try {
-//
-//                int ret = setBooleanValue_(getModelID(), name, value); 
-//                if(ret == ERROR)
-//                    throw new FMILException(getLastErrorMessage());
-//
-//            } catch (UnsatisfiedLinkError err) {
-//                throw new FMILException(UNSATISFIED_LINK);
-//            } catch (Exception e) {
-//                throw new FMILException(e.getMessage());
-//            }
-//        }
-//    }
-//    private native int setBooleanValue_(String id, String name, boolean value);
-//
-//    public void setTime(double time) throws FMILException {
-//        synchronized(syncObject) {
-//
-//            try {
-//
-//                int ret = setTime_(getModelID(), time); 
-//                if(ret == ERROR)
-//                    throw new FMILException(getLastErrorMessage());
-//
-//            } catch (UnsatisfiedLinkError err) {
-//                throw new FMILException(UNSATISFIED_LINK);
-//            } catch (Exception e) {
-//                throw new FMILException(e.getMessage());
-//            }
-//        }
-//    }
-//    private native int setTime_(String id, double time);
+    
+    /**
+     * Set value of a string variable. If the variable is a 
+     * parameter, the change is effective immediately.
+     *  
+     * @param name  Variable name
+     * @param value  New value
+     * @throws FMILException
+     */
+    public void setStringValue(String name, String value) throws FMILException {
+       int key = variableMap.get(name);
+       if(key == NO_VARIABLE_KEY)
+               throw new FMILException("No variable with name " + name);
+       setStringValue(key, value);
+    }
+
+    /**
+     * Set value of a string variable. If the variable is a 
+     * parameter, the change is effective immediately.
+     *  
+     * @param name  Variable id
+     * @param value  New value
+     * @throws FMILException
+     */
+    public void setStringValue(int variableReference, String value) throws FMILException {
+        synchronized(syncObject) {
+            try {
+                int ret = setStringValue_(getModelIDNew(), variableReference, value); 
+                if(ret != OK)
+                    LOGGER.warn("Function return value != OK, an exception should have been thrown from native code!");
+            } catch (FMILException e) {
+                throw e;
+            } catch (UnsatisfiedLinkError err) {
+                throw new FMILException(UNSATISFIED_LINK);
+            } catch (Exception e) {
+                throw new FMILException(e.getMessage());
+            }
+        }
+    }
+
+    private native int setStringValue_(int id, int variableReference, String value) throws FMILException;
+    
 
     /**
      * Simulate one step forward. The step length can be set with
@@ -474,10 +530,11 @@ public class FMIL {
 
             try {
 
-                int ret = simulateStep_(getModelIDNew()); 
-                if(ret != OK)
+                int ret = simulateStep_(getModelIDNew()); //0 is ok, 1 is error, 2 is pending
+                if(ret == PENDING)
+                    LOGGER.warn("Pending status return from FMU. This is not implemented in our Simulator yet!");
+                else if(ret != OK)
                     LOGGER.warn("Function return value != OK, an exception should have been thrown from native code!");
-
             } catch (FMILException e) {
                 throw e;
             } catch (UnsatisfiedLinkError err) {
@@ -531,11 +588,15 @@ public class FMIL {
             try {
 
                 unlockFMUDirectory();
-                if(fmuLoaded) {
+                
+                // Many FMUs will not correctly clean-up during unload if the simulation isn't instantiated
+                // Essentially we'd likely be passing an invalid pointer to the FMU to cleanup, causing native c-level crashes.
+                
+                if(instantiated) {
                     int ret = unloadFMU_(getModelIDNew()); 
                     if(ret != OK)
                         LOGGER.warn("Function return value != OK, an exception should have been thrown from native code!");
-                    fmuLoaded = false;
+                    instantiated = false;
                 }
                 removeFMUDirectoryContents();
 
@@ -865,19 +926,66 @@ public class FMIL {
 //    private native String getLastErrorMessage_(String id);
 
     /**
-     * Get a real (double) value for variable
+     * Get a value (double) for real variable
      * @param name Name of the variable
      * @return value
      * @throws FMILException
      */
     public double getRealValue(String name) throws FMILException {
+       int key = variableMap.get(name);
+       if(key == NO_VARIABLE_KEY)
+               throw new FMILException("No variable with name " + name);
+       double result = getRealValue(key); 
+       if (DEBUG) System.err.println("getRealValue " + name + " = " + result);
+       return result;
+    }
+
+    /**
+     * Get a value (double) for real variable
+     * @param variableReference  Numeric id of the variable
+     * @return value
+     * @throws FMILException
+     */
+    public double getRealValue(int variableReference) throws FMILException {
         synchronized(syncObject) {
+            try {
+                return getRealValue_(getModelIDNew(), variableReference);
+            } catch (UnsatisfiedLinkError err) {
+                throw new FMILException(UNSATISFIED_LINK);
+            } catch (Exception e) {
+                throw new FMILException(e.getMessage());
+            }
+        }
+    }
+    
+    private native double getRealValue_(int id, int variableReference) throws FMILException;
+
+
+    /**
+     * Get value of integer variable
+     * @param name Name of the variable
+     * @return value
+     * @throws FMILException
+     */
+    public int getIntegerValue(String name) throws FMILException {
+       int key = variableMap.get(name);
+       if(key == NO_VARIABLE_KEY)
+               throw new FMILException("No variable with name " + name);
+       int result = getIntegerValue(key);
+       if (DEBUG) System.err.println("getIntegerValue " + name + " = " + result);
+       return result;
+    }
 
+    /**
+     * Get a real (double) value for variable
+     * @param variableReference  Numeric id of the variable
+     * @return value
+     * @throws FMILException
+     */
+    public int getIntegerValue(int variableReference) throws FMILException {
+        synchronized(syncObject) {
             try {
-                // TODO: printtaa id ja name, jotta saadaan virheessä kiinni
-               double result = getRealValue_(getModelIDNew(), variableMap.get(name));
-               System.err.println("getRealValue " + name + " = " + result);
-                return  result;
+                return getIntegerValue_(getModelIDNew(), variableReference);
             } catch (UnsatisfiedLinkError err) {
                 throw new FMILException(UNSATISFIED_LINK);
             } catch (Exception e) {
@@ -885,71 +993,81 @@ public class FMIL {
             }
         }
     }
+    
+    private native int getIntegerValue_(int id, int variableReference) throws FMILException;
+    
+    
+    /**
+     * Get value of boolean variable
+     * @param name Name of the variable
+     * @return value
+     * @throws FMILException
+     */
+    public boolean getBooleanValue(String name) throws FMILException {
+       int key = variableMap.get(name);
+       if(key == NO_VARIABLE_KEY)
+               throw new FMILException("No variable with name " + name);
+       boolean result = getBooleanValue(key);
+       if (DEBUG) System.err.println("getBooleanValue " + name + " = " + result);
+       return result;
+    }
 
-    private native double getRealValue_(int id, int variableReference);
+    /**
+     * Get value of boolean variable
+     * @param variableReference  Numeric id of the variable
+     * @return value
+     * @throws FMILException
+     */
+    public boolean getBooleanValue(int variableReference) throws FMILException {
+        synchronized(syncObject) {
+            try {
+                return getBooleanValue_(getModelIDNew(), variableReference);
+            } catch (UnsatisfiedLinkError err) {
+                throw new FMILException(UNSATISFIED_LINK);
+            } catch (Exception e) {
+                throw new FMILException(e.getMessage());
+            }
+        }
+    }
+    
+    private native boolean getBooleanValue_(int id, int variableReference) throws FMILException;
+    
+    
+    /**
+     * Get value of string variable
+     * @param name Name of the variable
+     * @return value
+     * @throws FMILException
+     */
+    public String getStringValue(String name) throws FMILException {
+       int key = variableMap.get(name);
+       if(key == NO_VARIABLE_KEY)
+               throw new FMILException("No variable with name " + name);
+       String result = getStringValue(key);
+       if (DEBUG) System.err.println("getIntegerValue " + name + " = " + result);
+       return result;
+    }
 
-//    /**
-//     * Get a string value for variable
-//     * @param name Name of the variable
-//     * @return value
-//     * @throws FMILException
-//     */
-//    public String getStringValue(String name) throws FMILException {
-//        synchronized(syncObject) {
-//
-//            try {
-//                return getStringValue_(getModelID(), name); 
-//            } catch (UnsatisfiedLinkError err) {
-//                throw new FMILException(UNSATISFIED_LINK);
-//            } catch (Exception e) {
-//                throw new FMILException(e.getMessage());
-//            }
-//        }
-//    }
-//
-//    private native String getStringValue_(String id, String name);
-//
-//    /**
-//     * Get an integer value for variable
-//     * @param name Name of the variable
-//     * @return value
-//     * @throws FMILException
-//     */
-//    public int getIntegerValue(String name) throws FMILException {
-//        synchronized(syncObject) {
-//
-//            try {
-//                return getIntegerValue_(getModelID(), name); 
-//            } catch (UnsatisfiedLinkError err) {
-//                throw new FMILException(UNSATISFIED_LINK);
-//            } catch (Exception e) {
-//                throw new FMILException(e.getMessage());
-//            }
-//        }
-//    }
-//
-//    private native int getIntegerValue_(String id, String name);
-//
-//    /**
-//     * Get a real (double) value for variable
-//     * @param name Name of the variable
-//     * @return value
-//     * @throws FMILException
-//     */
-//    public boolean getBooleanValue(String name) throws FMILException {
-//        synchronized(syncObject) {
-//
-//            try {
-//                return getBooleanValue_(getModelID(), name); 
-//            } catch (UnsatisfiedLinkError err) {
-//                throw new FMILException(UNSATISFIED_LINK);
-//            } catch (Exception e) {
-//                throw new FMILException(e.getMessage());
-//            }
-//        }
-//    }
-//
-//    private native boolean getBooleanValue_(String id, String name);
+    /**
+     * Get value of string variable
+     * @param variableReference  Numeric id of the variable
+     * @return value
+     * @throws FMILException
+     */
+    public String getStringValue(int variableReference) throws FMILException {
+        synchronized(syncObject) {
+            try {
+                return getStringValue_(getModelIDNew(), variableReference);
+            } catch (UnsatisfiedLinkError err) {
+                throw new FMILException(UNSATISFIED_LINK);
+            } catch (Exception e) {
+                throw new FMILException(e.getMessage());
+            }
+        }
+    }
+    
+    private native String getStringValue_(int id, int variableReference) throws FMILException;
+    
 
     private FileChannel channel; 
     private FileLock lock;