]> gerrit.simantics Code Review - simantics/fmil.git/blobdiff - org.simantics.fmil.core/src/org/simantics/fmil/core/FMIL.java
Pending status can be returns from FMU to Native C to Java
[simantics/fmil.git] / org.simantics.fmil.core / src / org / simantics / fmil / core / FMIL.java
index 41ebf95522967d70ede8c7bc856f4e6f636ec2f7..4b1eeaca132386d9e1071b4e6bac3569d25d8325 100644 (file)
@@ -3,19 +3,22 @@ package org.simantics.fmil.core;
 import java.io.File;
 import java.io.IOException;
 import java.io.RandomAccessFile;
+import java.net.URL;
 import java.nio.channels.FileChannel;
 import java.nio.channels.FileLock;
+import java.nio.file.Files;
 import java.nio.file.Paths;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
 import java.util.UUID;
 
 import org.eclipse.core.runtime.FileLocator;
+import org.eclipse.core.runtime.Path;
 import org.eclipse.core.runtime.Platform;
 import org.osgi.framework.Bundle;
-import org.simantics.fmil.core.ExecEnvironment.ARCHType;
 import org.simantics.fmil.core.ExecEnvironment.OSType;
 import org.simantics.utils.FileUtils;
 import org.slf4j.Logger;
@@ -29,14 +32,17 @@ 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 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;  
+    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;
     public static String    LOCK_FILE_NAME      = "fmil.lock";
 
     public static Object syncObject = new Object();
@@ -45,35 +51,28 @@ public class FMIL {
      * Static: load native libraries required for the FMU simulation to work.
      */
     static {
-       
+
         File[] libraries = new File[2];
 
-        Bundle bundle = null;
-        
         ExecEnvironment env = ExecEnvironment.calculate();
-        if (env.os == OSType.WINDOWS) {
-            if (env.arch == ARCHType.X86) {
-                bundle = Platform.getBundle("org.simantics.fmil.win32");
-            } else if (env.arch == ARCHType.X86_64) {
-                bundle = Platform.getBundle("org.simantics.fmil.win64");
-            }
-        }
-        
-        if (bundle != null) {
-            try{
-                String root = FileLocator.getBundleFile(bundle).getAbsolutePath();
-//                if (env.arch == ARCHType.X86_64) {
-//                    File newFIle = new File(root, "libraries/libexpat.dll");
-//                    System.load(newFIle.getAbsolutePath());
-//                }
-//                libraries[0] = new File(root, "libraries/zlibwapi.dll");
-//                libraries[1] = new File(root, "libraries/miniunz.dll");
-                libraries[0] = new File(root, "libraries/fmilib_shared.dll");
-                libraries[1] = new File(root, "libraries/FMUSimulator.dll");
-            }
-            catch (Exception e) {
-                e.printStackTrace();
+
+        try {
+            URL sharedFMILIBUrl = null;
+            URL simulatorFMIUrl = null;
+            Bundle b = Platform.getBundle("org.simantics.fmil.core");
+
+            if (env.os == OSType.WINDOWS) {
+                sharedFMILIBUrl = FileLocator.find(b, new Path("libraries/fmilib_shared.dll"), null);
+                simulatorFMIUrl = FileLocator.find(b, new Path("libraries/FMUSimulator.dll"), null);
+            } else if(env.os == OSType.LINUX) {
+                sharedFMILIBUrl = FileLocator.find(b, new Path("libraries/libfmilib_shared.so"), null);
+                simulatorFMIUrl = FileLocator.find(b, new Path("libraries/libFMUSimulator.so"), null);
             }
+
+            libraries[0] = new File(FileLocator.toFileURL(sharedFMILIBUrl).getPath());
+            libraries[1] = new File(FileLocator.toFileURL(simulatorFMIUrl).getPath());
+        } catch (Exception e) {
+            LOGGER.error("Failed to resolve native FMU simulation library for execution environment {}.{}", env.os, env.arch, e);
         }
 
         for(File library : libraries) {
@@ -135,15 +134,16 @@ public class FMIL {
        }
        
        public boolean subscribe(String name) throws FMILException {
-               // Safety check
-               int vr = variableMap.get(name);
-               if(vr == 0) return false;
-               if(!subscriptionSet.add(name)) return false;
-               subscribedNames.add(name);
-               System.err.println("subscribed : " + name + " => " + subscribedNames.size());
-               subscription.add(vr);
-               subscribe(new int[] { vr });
-               return true;
+               synchronized(syncObject) {
+                       // Safety check
+                       int vr = variableMap.get(name);
+                       if(vr == 0) return false;
+                       if(!subscriptionSet.add(name)) return false;
+                       subscribedNames.add(name);
+                       subscription.add(vr);
+                       subscribe(new int[] { vr });
+                       return true;
+               }
        }
 
     public FMIL() {
@@ -187,6 +187,11 @@ public class FMIL {
     private boolean fmuLoaded = 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) {
@@ -197,23 +202,25 @@ public class FMIL {
                 fmuN = 0;
             }
 
-            File tempDir = new File(fmuDir);
-            if(tempDir.isDirectory()) {
+            java.nio.file.Path tempDir = Paths.get(fmuDir);
+            if(Files.exists(tempDir) && Files.isDirectory(tempDir)) {
                 try {
-                    FileUtils.deleteAll(tempDir);
+                       FileUtils.emptyDirectory(tempDir);
                 } catch (IOException e) {
-                    throw new FMILException("Could not create temp folder for fmu");
+                    throw new FMILException("Could not delete existing files from temp folder for fmu " + path, e);
                 }
-                tempDir.mkdir();
             } else {
-                tempDir.mkdir();
+                try {
+                       Files.createDirectory(tempDir);
+                } catch (IOException e) {
+                    throw new FMILException("Could not create temp folder for fmu " + path, e);
+                }
             }
 
-
             try {
-                String tmpPath = tempDir.getAbsolutePath();
-                if(!tmpPath.endsWith("\\"))
-                    tmpPath = tmpPath + "\\";
+                String tmpPath = tempDir.toString();
+                if(!tmpPath.endsWith("\\") && !tmpPath.endsWith("/"))
+                    tmpPath = tmpPath + "/";
                 id = loadFMUFile_(path, tmpPath);
                 
                 getAllVariables();
@@ -227,12 +234,13 @@ public class FMIL {
             } catch (UnsatisfiedLinkError err) {
                 throw new FMILException(UNSATISFIED_LINK, err);
             } catch (Exception e) {
+               LOGGER.error(e.getMessage());
                 throw new FMILException(e.getMessage());
             }
         }
     }
 
-    private native int loadFMUFile_(String path, String toDir);
+    private native int loadFMUFile_(String path, String toDir) throws FMILException;
 
     /**
      * Set a step length for simulation
@@ -340,23 +348,31 @@ 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) {
+       setRealValue(variableMap.get(name), 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 +380,77 @@ 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 {
+       setIntegerValue(variableMap.get(name), 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 {
+       setBooleanValue(variableMap.get(name), 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 +458,50 @@ 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 {
+       setStringValue(variableMap.get(name), 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 +514,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) {
@@ -500,10 +541,11 @@ public class FMIL {
         synchronized(syncObject) {
 
             try {
-
+               
                double[] results = new double[subscription.size()];
-                return getSubscribedResults_(getModelIDNew(), results);
-
+               Arrays.fill(results, Double.NaN);
+               
+               return getSubscribedResults_(getModelIDNew(), results);
             } catch (UnsatisfiedLinkError err) {
                 throw new FMILException(UNSATISFIED_LINK);
             } catch (Exception e) {
@@ -864,19 +906,60 @@ 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 {
+       double result = getRealValue(variableMap.get(name)); 
+       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 result = getIntegerValue(variableMap.get(name));
+       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) {
@@ -884,71 +967,75 @@ 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 {
+       boolean result = getBooleanValue(variableMap.get(name));
+       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 {
+       String result = getStringValue(variableMap.get(name));
+       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;