X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;f=org.simantics.fmil.core%2Fsrc%2Forg%2Fsimantics%2Ffmil%2Fcore%2FFMIL.java;h=4b1eeaca132386d9e1071b4e6bac3569d25d8325;hb=f6f05cb36bc0b849af8090efac1d549779e2076f;hp=5c00607b9be349d4a03401a27397cb99cc97d9da;hpb=411f77604de585b8b00e76ce39dab96e530193e5;p=simantics%2Ffmil.git diff --git a/org.simantics.fmil.core/src/org/simantics/fmil/core/FMIL.java b/org.simantics.fmil.core/src/org/simantics/fmil/core/FMIL.java index 5c00607..4b1eeac 100644 --- a/org.simantics.fmil.core/src/org/simantics/fmil/core/FMIL.java +++ b/org.simantics.fmil.core/src/org/simantics/fmil/core/FMIL.java @@ -1,993 +1,1109 @@ -package org.simantics.fmil.core; - -import java.io.File; -import java.io.IOException; -import java.io.RandomAccessFile; -import java.nio.channels.FileChannel; -import java.nio.channels.FileLock; -import java.util.ArrayList; -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.Platform; -import org.osgi.framework.Bundle; -import org.simantics.Simantics; -import org.simantics.fmil.core.ExecEnvironment.ARCHType; -import org.simantics.fmil.core.ExecEnvironment.OSType; -import org.simantics.utils.FileUtils; - -import gnu.trove.list.array.TIntArrayList; -import gnu.trove.map.hash.TObjectIntHashMap; - - -public class FMIL { - - /** - * Static variables - */ - private static int ERROR = 0; - private static int OK = 1; - private static String UNSATISFIED_LINK = "Method not found. DLL might not be loaded properly."; - private static 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(); - - /** - * 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(); - } - } - - for(File library : libraries) { - if(library == null) { - System.err.println("FMU library not loaded. FMU simulation not working."); - continue; - } else if(!library.isFile()) { - System.err.println(library.getAbsolutePath() + " not found"); - } else { - try { - System.load(library.getAbsolutePath()); - } catch (Throwable t) { - System.err.println(t.getMessage()); - } - } - } - } - - /** - * Static: initialize fmu temp folder - */ - static { - File dir = Simantics.getTemporaryDirectory(TEMP_FMU_DIRECTORY_NAME); - TEMP_FMU_COMMON_DIRECTORY = dir.getAbsolutePath(); - } - - - private String fmuDir; - private int id; - - public String TEMP_FOLDER_1; - public String TEMP_FOLDER_2; - public String TEMP_FMU_DIRECTORY; - private String dirName; - - private String[] variableNames; - private String[] variableDescriptions; - private String[] variableDeclaredTypes; - private int[] variableReferences; - private int[] variableTypes; - private int[] variableCausalities; - private int[] variableVariabilities; - - private String[] declaredTypes; - private String[] declaredTypeDescriptions; - private String[] declaredTypeQuantities; - private String[] declaredTypeUnits; - - private TObjectIntHashMap variableMap = new TObjectIntHashMap(); - - private Set subscriptionSet = new HashSet(); - private TIntArrayList subscription = new TIntArrayList(); - private ArrayList subscribedNames = new ArrayList(); - - public List getSubscribedNames() { - return subscribedNames; - } - - 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; - } - - public FMIL() { - // Create a directory for this control - File tempDir = new File(TEMP_FMU_COMMON_DIRECTORY, UUID.randomUUID().toString()); - tempDir.mkdir(); - TEMP_FMU_DIRECTORY = tempDir.getAbsolutePath(); - - // Create two directories inside the temp directory for this control - dirName = UUID.randomUUID().toString(); - File fmuDir = new File(TEMP_FMU_DIRECTORY, dirName); - fmuDir.mkdir(); - - TEMP_FOLDER_1 = fmuDir.toString(); - TEMP_FOLDER_2 = fmuDir.toString() + "_2"; - - // Lock fmu directory in temp directory - lockFMUDirectory(); - } - - public int getModelIDNew() { - return id; - } - - public String getModelID() { - return dirName; - } - - public String getFmuDir() { - return fmuDir; - } - - /** - * Load fmu from a given file path. Releases the (possible) previously - * loaded fmu. - * - * @param path absolute file path for fmu file - * @throws FMILException - */ - private int fmuN = 0; - private boolean fmuLoaded = false; - public void loadFMUFile(String path) throws FMILException { - - synchronized(syncObject) { - - if(fmuN % 2 == 0) { - fmuDir = TEMP_FOLDER_1; - fmuN++; - } else { - fmuDir = TEMP_FOLDER_2; - fmuN = 0; - } - - File tempDir = new File(fmuDir); - if(tempDir.isDirectory()) { - try { - FileUtils.deleteAll(tempDir); - } catch (IOException e) { - throw new FMILException("Could not create temp folder for fmu"); - } - tempDir.mkdir(); - } else { - tempDir.mkdir(); - } - - - try { - String tmpPath = tempDir.getAbsolutePath(); - if(!tmpPath.endsWith("\\")) - tmpPath = tmpPath + "\\"; - id = loadFMUFile_(path, tmpPath); - - getAllVariables(); - getAllVariableReferences(); - - for(int i=0;i - * Make sure that an FMU is loaded first. - * @throws FMILException - */ - public void instantiateSimulation() throws FMILException { - synchronized(syncObject) { - - try { - - int ret = instantiateSimulation_(getModelIDNew()); - 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 instantiateSimulation_(int id); - - - /** - * Initializes a simulation. - *

- * Make sure that simulation is instantiated first! - * @throws FMILException - */ - public void initializeSimulation() throws FMILException { - synchronized(syncObject) { - - try { - - int ret = initializeSimulation_(getModelIDNew()); - 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 initializeSimulation_(int id); - - /** - * Subscribe a set of variables from a loaded simulation. - *

- * Make sure that an FMU is loaded first. - * @param variables Array of variables - * @throws FMILException - */ - public void subscribe(int[] variables) throws FMILException { - synchronized(syncObject) { - - try { - - int ret = subscribe_(getModelIDNew(), variables); - 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 subscribe_(int id, int[] variables); - - /** - * Set a new (Real, double) value for a variable. If the variable is a - * parameter, the change is effective immediately. - * - * @param name Variable - * @param value New (Real, double) value - * @throws FMILException - */ - public void setRealValue(String name, double value) throws FMILException { - - synchronized(syncObject) { - - try { - - int ret = setRealValue_(getModelIDNew(), variableMap.get(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()); - } - - } - - } - - public void setRealValue(int variableReference, double value) throws FMILException { - - synchronized(syncObject) { - - try { - - int ret = setRealValue_(getModelIDNew(), variableReference, 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 setRealValue_(int id, int variableReference, double value); - -// /** -// * 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); - - /** - * Simulate one step forward. The step length can be set with - * setStepLength() - * - * @throws FMILException - */ - public void simulateStep() throws FMILException { - synchronized(syncObject) { - - try { - - int ret = simulateStep_(getModelIDNew()); - 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 simulateStep_(int id); - - /** - * Get an array containing the current values for subscribed variables. The - * values are in the same order as in the subscription. - * - * @param results An array the size of subscribed results - * @return - */ - public double[] getSubscribedResults() throws FMILException { - synchronized(syncObject) { - - try { - - double[] results = new double[subscription.size()]; - return getSubscribedResults_(getModelIDNew(), results); - - } catch (UnsatisfiedLinkError err) { - throw new FMILException(UNSATISFIED_LINK); - } catch (Exception e) { - throw new FMILException(e.getMessage()); - } - } - } - - private native double[] getSubscribedResults_(int id, double[] results); - - - /** - * Unload FMU and the dll:s that it requires. - *

- * To be called after all FMU simulations are ended. - * If the fmu is loaded again / changed, call to loadFMUFile is sufficient. loadFMUFile - * releases the previous fmu.dll - * - * @throws FMILException - */ - public void unloadFMU() throws FMILException { - synchronized(syncObject) { - - try { - - unlockFMUDirectory(); - if(fmuLoaded) { - int ret = unloadFMU_(getModelIDNew()); - if(ret == ERROR) - throw new FMILException(getLastErrorMessage()); - } - removeFMUDirectoryContents(); - - } catch (UnsatisfiedLinkError err) { - throw new FMILException(UNSATISFIED_LINK); - } catch (Exception e) { - throw new FMILException(e.getMessage()); - } - } - } - private native int unloadFMU_(int id); - -// /** -// * Checks if fmu has been initialized -// * @return current simulation time -// */ -// public boolean isInitialized() throws FMILException { -// synchronized(syncObject) { -// try { -// return isInitialized_(getModelID()); -// } catch (UnsatisfiedLinkError err) { -// throw new FMILException(UNSATISFIED_LINK); -// } catch (Exception e) { -// throw new FMILException(e.getMessage()); -// } -// } -// } -// -// private native boolean isInitialized_(String id); -// - /** - * Get the current simulation time - * @return current simulation time - */ - public double getTime() throws FMILException { - synchronized(syncObject) { - - try { - - return getTime_(getModelIDNew()); - - } catch (UnsatisfiedLinkError err) { - throw new FMILException(UNSATISFIED_LINK); - } catch (Exception e) { - throw new FMILException(e.getMessage()); - } - } - } - - private native double getTime_(int id); - - /** - * Get all variables in a loaded model - * @return all variables in a loaded model - */ - public String[] getAllVariables() throws FMILException { - synchronized(syncObject) { - - try { - - if(variableNames == null) { - variableNames = getAllVariables_(getModelIDNew()); - } - return variableNames; - - } catch (UnsatisfiedLinkError err) { - throw new FMILException(UNSATISFIED_LINK); - } catch (Exception e) { - throw new FMILException(e.getMessage()); - } - } - } - - private native String[] getAllVariables_(int id); - - public String[] getAllVariableDescriptions() throws FMILException { - synchronized(syncObject) { - - try { - - if(variableDescriptions == null) { - variableDescriptions = getAllVariableDescriptions_(getModelIDNew()); - } - return variableDescriptions; - - } catch (UnsatisfiedLinkError err) { - throw new FMILException(UNSATISFIED_LINK); - } catch (Exception e) { - throw new FMILException(e.getMessage()); - } - } - } - - private native String[] getAllVariableDescriptions_(int id); - - public String[] getAllVariableDeclaredTypes() throws FMILException { - synchronized(syncObject) { - - try { - - if(variableDeclaredTypes == null) { - variableDeclaredTypes = getAllVariableDeclaredTypes_(getModelIDNew()); - } - return variableDeclaredTypes; - - } catch (UnsatisfiedLinkError err) { - throw new FMILException(UNSATISFIED_LINK); - } catch (Exception e) { - throw new FMILException(e.getMessage()); - } - } - } - - private native String[] getAllVariableDeclaredTypes_(int id); - - public int[] getAllVariableReferences() throws FMILException { - synchronized(syncObject) { - - try { - - if(variableReferences == null) { - variableReferences = getAllVariableReferences_(getModelIDNew(), new int[variableNames.length]); - } - return variableReferences; - - } catch (UnsatisfiedLinkError err) { - throw new FMILException(UNSATISFIED_LINK); - } catch (Exception e) { - throw new FMILException(e.getMessage()); - } - } - } - - private native int[] getAllVariableReferences_(int id, int[] array); - - public int[] getAllVariableTypes() throws FMILException { - synchronized(syncObject) { - - try { - - if(variableTypes == null) { - variableTypes = getAllVariableTypes_(getModelIDNew(), new int[variableNames.length]); - } - return variableTypes; - - } catch (UnsatisfiedLinkError err) { - throw new FMILException(UNSATISFIED_LINK); - } catch (Exception e) { - throw new FMILException(e.getMessage()); - } - } - } - - private native int[] getAllVariableTypes_(int id, int[] array); - - public int[] getAllVariableCausalities() throws FMILException { - synchronized(syncObject) { - - try { - - if(variableCausalities == null) { - variableCausalities = getAllVariableCausalities_(getModelIDNew(), new int[variableNames.length]); - } - return variableCausalities; - - } catch (UnsatisfiedLinkError err) { - throw new FMILException(UNSATISFIED_LINK); - } catch (Exception e) { - throw new FMILException(e.getMessage()); - } - } - } - - private native int[] getAllVariableCausalities_(int id, int[] array); - - public int[] getAllVariableVariabilities() throws FMILException { - synchronized(syncObject) { - - try { - - if(variableVariabilities == null) { - variableVariabilities = getAllVariableVariabilities_(getModelIDNew(), new int[variableNames.length]); - } - return variableVariabilities; - - } catch (UnsatisfiedLinkError err) { - throw new FMILException(UNSATISFIED_LINK); - } catch (Exception e) { - throw new FMILException(e.getMessage()); - } - } - } - - private native int[] getAllVariableVariabilities_(int id, int[] array); - - /** - * Get all variables in a loaded model - * @return all variables in a loaded model - */ - public String[] getAllDeclaredTypes() throws FMILException { - synchronized(syncObject) { - - try { - - if(declaredTypes == null) { - declaredTypes = getAllDeclaredTypes_(getModelIDNew()); - } - return declaredTypes; - - } catch (UnsatisfiedLinkError err) { - throw new FMILException(UNSATISFIED_LINK); - } catch (Exception e) { - throw new FMILException(e.getMessage()); - } - } - } - - private native String[] getAllDeclaredTypes_(int id); - - public String[] getAllDeclaredTypeDescriptions() throws FMILException { - synchronized(syncObject) { - - try { - - if(declaredTypeDescriptions == null) { - declaredTypeDescriptions = getAllDeclaredTypeDescriptions_(getModelIDNew()); - } - return declaredTypeDescriptions; - - } catch (UnsatisfiedLinkError err) { - throw new FMILException(UNSATISFIED_LINK); - } catch (Exception e) { - throw new FMILException(e.getMessage()); - } - } - } - - private native String[] getAllDeclaredTypeDescriptions_(int id); - - public String[] getAllDeclaredTypeQuantities() throws FMILException { - synchronized(syncObject) { - - try { - - if(declaredTypeQuantities == null) { - declaredTypeQuantities = getAllDeclaredTypeQuantities_(getModelIDNew()); - } - return declaredTypeQuantities; - - } catch (UnsatisfiedLinkError err) { - throw new FMILException(UNSATISFIED_LINK); - } catch (Exception e) { - throw new FMILException(e.getMessage()); - } - } - } - - private native String[] getAllDeclaredTypeQuantities_(int id); - - public String[] getAllDeclaredTypeUnits() throws FMILException { - synchronized(syncObject) { - - try { - - if(declaredTypeUnits == null) { - declaredTypeUnits = getAllDeclaredTypeUnits_(getModelIDNew()); - } - return declaredTypeUnits; - - } catch (UnsatisfiedLinkError err) { - throw new FMILException(UNSATISFIED_LINK); - } catch (Exception e) { - throw new FMILException(e.getMessage()); - } - } - } - - private native String[] getAllDeclaredTypeUnits_(int id); - - -// -// /** -// * Get all variables from model that match the filter (and time variable) -// * -// * @param regexp Regular expression filter -// * @return An array of variable names that match regexp filter (and time-variable) -// * @throws FMILException -// */ -// public String[] filterVariables(String regexp) throws FMILException { -// synchronized(syncObject) { -// try { -// -// return filterVariables_(getModelID(), regexp + "|time"); -// -// } catch (UnsatisfiedLinkError err) { -// throw new FMILException(UNSATISFIED_LINK); -// } catch (Exception e) { -// throw new FMILException(e.getMessage()); -// } -// } -// } -// -// private native String[] filterVariables_(String id, String regexp); -// - /** - * Get the last error message - * @return Last error message - */ - public String getLastErrorMessage() throws FMILException { - synchronized(syncObject) { - - try { - - return "err"; - //return getLastErrorMessage_(getModelID()); - - } catch (UnsatisfiedLinkError err) { - throw new FMILException(UNSATISFIED_LINK); - } catch (Exception e) { - throw new FMILException(e.getMessage()); - } - } - } -// -// private native String getLastErrorMessage_(String id); - - /** - * Get a real (double) value for variable - * @param name Name of the variable - * @return value - * @throws FMILException - */ - public double getRealValue(String name) 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; - } catch (UnsatisfiedLinkError err) { - throw new FMILException(UNSATISFIED_LINK); - } catch (Exception e) { - throw new FMILException(e.getMessage()); - } - } - } - - private native double getRealValue_(int id, int variableReference); - -// /** -// * 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); - - private FileChannel channel; - private FileLock lock; - - @SuppressWarnings("resource") - private boolean lockFMUDirectory() { - - try { - // Get a file channel for the lock file - File lockFile = new File(TEMP_FMU_DIRECTORY, LOCK_FILE_NAME); - if(!lockFile.isFile()) - lockFile.createNewFile(); - - channel = new RandomAccessFile(lockFile, "rw").getChannel(); - - // Use the file channel to create a lock on the file. - // This method blocks until it can retrieve the lock. - lock = channel.lock(); - - // // Try acquiring the lock without blocking. This method returns - // // null or throws an exception if the file is already locked. - // try { - // lock = channel.tryLock(); - // } catch (OverlappingFileLockException e) { - // // File is already locked in this thread or virtual machine - // } - } catch (IOException e) { - return false; - } - - return true; - } - - private boolean unlockFMUDirectory() { - try { - // Release the lock - if(lock != null) - lock.release(); - - // Close the file - if(channel != null) - channel.close(); - } catch (IOException e) { - return false; - } - return true; - } - - private boolean removeFMUDirectoryContents() { - // Remove contents - try { - File tempDir = new File(TEMP_FMU_DIRECTORY); - FileUtils.deleteAll(tempDir); - tempDir.delete(); - } catch (IOException e) { - return false; - } - return true; - } -} +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.OSType; +import org.simantics.utils.FileUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import gnu.trove.list.array.TIntArrayList; +import gnu.trove.map.hash.TObjectIntHashMap; + + +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; + public static String LOCK_FILE_NAME = "fmil.lock"; + + public static Object syncObject = new Object(); + + /** + * Static: load native libraries required for the FMU simulation to work. + */ + static { + + File[] libraries = new File[2]; + + ExecEnvironment env = ExecEnvironment.calculate(); + + 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) { + if(library == null) { + System.err.println("FMU library not loaded. FMU simulation not working."); + continue; + } else if(!library.isFile()) { + System.err.println(library.getAbsolutePath() + " not found"); + } else { + try { + System.load(library.getAbsolutePath()); + } catch (Throwable t) { + System.err.println(t.getMessage()); + } + } + } + } + + /** + * Static: initialize fmu temp folder from current working directory + */ + static { + TEMP_FMU_COMMON_DIRECTORY = Paths.get(".").toAbsolutePath().normalize().toString(); + } + + public static void setTempFMUCommonDir(File dir) { + TEMP_FMU_COMMON_DIRECTORY = dir.getAbsolutePath(); + } + + private String fmuDir; + private int id; + + public String TEMP_FOLDER_1; + public String TEMP_FOLDER_2; + public String TEMP_FMU_DIRECTORY; + private String dirName; + + private String[] variableNames; + private String[] variableDescriptions; + private String[] variableDeclaredTypes; + private int[] variableReferences; + private int[] variableTypes; + private int[] variableCausalities; + private int[] variableVariabilities; + + private String[] declaredTypes; + private String[] declaredTypeDescriptions; + private String[] declaredTypeQuantities; + private String[] declaredTypeUnits; + + private TObjectIntHashMap variableMap = new TObjectIntHashMap(); + + private Set subscriptionSet = new HashSet(); + private TIntArrayList subscription = new TIntArrayList(); + private ArrayList subscribedNames = new ArrayList(); + + public List getSubscribedNames() { + return subscribedNames; + } + + public boolean subscribe(String name) throws FMILException { + 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() { + // Create a directory for this control + File tempDir = new File(TEMP_FMU_COMMON_DIRECTORY, UUID.randomUUID().toString()); + tempDir.mkdir(); + TEMP_FMU_DIRECTORY = tempDir.getAbsolutePath(); + + // Create two directories inside the temp directory for this control + dirName = UUID.randomUUID().toString(); + File fmuDir = new File(TEMP_FMU_DIRECTORY, dirName); + fmuDir.mkdir(); + + TEMP_FOLDER_1 = fmuDir.toString(); + TEMP_FOLDER_2 = fmuDir.toString() + "_2"; + + // Lock fmu directory in temp directory + lockFMUDirectory(); + } + + public int getModelIDNew() { + return id; + } + + public String getModelID() { + return dirName; + } + + public String getFmuDir() { + return fmuDir; + } + + /** + * Load fmu from a given file path. Releases the (possible) previously + * loaded fmu. + * + * @param path absolute file path for fmu file + * @throws FMILException + */ + private int fmuN = 0; + 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) { + fmuDir = TEMP_FOLDER_1; + fmuN++; + } else { + fmuDir = TEMP_FOLDER_2; + fmuN = 0; + } + + java.nio.file.Path tempDir = Paths.get(fmuDir); + if(Files.exists(tempDir) && Files.isDirectory(tempDir)) { + try { + FileUtils.emptyDirectory(tempDir); + } catch (IOException e) { + throw new FMILException("Could not delete existing files from temp folder for fmu " + path, e); + } + } else { + try { + Files.createDirectory(tempDir); + } catch (IOException e) { + throw new FMILException("Could not create temp folder for fmu " + path, e); + } + } + + try { + String tmpPath = tempDir.toString(); + if(!tmpPath.endsWith("\\") && !tmpPath.endsWith("/")) + tmpPath = tmpPath + "/"; + id = loadFMUFile_(path, tmpPath); + + getAllVariables(); + getAllVariableReferences(); + + for(int i=0;i + * Make sure that an FMU is loaded first. + * @throws FMILException + */ + public void instantiateSimulation() throws FMILException { + synchronized(syncObject) { + + try { + + int ret = instantiateSimulation_(getModelIDNew()); + 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 instantiateSimulation_(int id) throws FMILException; + + + /** + * Initializes a simulation. + *

+ * Make sure that simulation is instantiated first! + * @throws FMILException + */ + public void initializeSimulation() throws FMILException { + synchronized(syncObject) { + + try { + + int ret = initializeSimulation_(getModelIDNew()); + 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 initializeSimulation_(int id) throws FMILException; + + /** + * Subscribe a set of variables from a loaded simulation. + *

+ * Make sure that an FMU is loaded first. + * @param variables Array of variables + * @throws FMILException + */ + public void subscribe(int[] variables) throws FMILException { + synchronized(syncObject) { + + try { + + int ret = subscribe_(getModelIDNew(), variables); + if(ret != OK) + LOGGER.warn("Function return value != OK, an exception should have been thrown from native code!"); + + } catch (UnsatisfiedLinkError err) { + throw new FMILException(UNSATISFIED_LINK); + } catch (Exception e) { + throw new FMILException(e.getMessage()); + } + } + } + + private native int subscribe_(int id, int[] variables); + + /** + * Set value of a real variable. If the variable is a + * parameter, the change is effective immediately. + * + * @param name Variable name + * @param value New value + * @throws FMILException + */ + public void setRealValue(String name, double value) throws FMILException { + 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(), 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 setRealValue_(int id, int variableReference, double value) throws FMILException; + + + /** + * 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); + } + + /** + * 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) { + throw new FMILException(UNSATISFIED_LINK); + } catch (Exception e) { + throw new FMILException(e.getMessage()); + } + } + } + + private native int setBooleanValue_(int id, int variableReference, boolean value) throws FMILException; + + + /** + * 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 + * setStepLength() + * + * @throws FMILException + */ + public void simulateStep() throws FMILException { + synchronized(syncObject) { + + try { + + 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) { + throw new FMILException(UNSATISFIED_LINK); + } catch (Exception e) { + throw new FMILException(e.getMessage()); + } + } + } + private native int simulateStep_(int id) throws FMILException; + + /** + * Get an array containing the current values for subscribed variables. The + * values are in the same order as in the subscription. + * + * @param results An array the size of subscribed results + * @return + */ + public double[] getSubscribedResults() throws FMILException { + synchronized(syncObject) { + + try { + + double[] results = new double[subscription.size()]; + Arrays.fill(results, Double.NaN); + + return getSubscribedResults_(getModelIDNew(), results); + } catch (UnsatisfiedLinkError err) { + throw new FMILException(UNSATISFIED_LINK); + } catch (Exception e) { + throw new FMILException(e.getMessage()); + } + } + } + + private native double[] getSubscribedResults_(int id, double[] results); + + + /** + * Unload FMU and the dll:s that it requires. + *

+ * To be called after all FMU simulations are ended. + * If the fmu is loaded again / changed, call to loadFMUFile is sufficient. loadFMUFile + * releases the previous fmu.dll + * + * @throws FMILException + */ + public void unloadFMU() throws FMILException { + synchronized(syncObject) { + + try { + + unlockFMUDirectory(); + if(fmuLoaded) { + int ret = unloadFMU_(getModelIDNew()); + if(ret != OK) + LOGGER.warn("Function return value != OK, an exception should have been thrown from native code!"); + fmuLoaded = false; + } + removeFMUDirectoryContents(); + + } catch (FMILException e) { + throw e; + } catch (UnsatisfiedLinkError err) { + throw new FMILException(UNSATISFIED_LINK); + } catch (Exception e) { + throw new FMILException(e.getMessage()); + } + } + } + private native int unloadFMU_(int id) throws FMILException; + +// /** +// * Checks if fmu has been initialized +// * @return current simulation time +// */ +// public boolean isInitialized() throws FMILException { +// synchronized(syncObject) { +// try { +// return isInitialized_(getModelID()); +// } catch (UnsatisfiedLinkError err) { +// throw new FMILException(UNSATISFIED_LINK); +// } catch (Exception e) { +// throw new FMILException(e.getMessage()); +// } +// } +// } +// +// private native boolean isInitialized_(String id); +// + /** + * Get the current simulation time + * @return current simulation time + */ + public double getTime() throws FMILException { + synchronized(syncObject) { + + try { + + return getTime_(getModelIDNew()); + + } catch (UnsatisfiedLinkError err) { + throw new FMILException(UNSATISFIED_LINK); + } catch (Exception e) { + throw new FMILException(e.getMessage()); + } + } + } + + private native double getTime_(int id); + + /** + * Get all variables in a loaded model + * @return all variables in a loaded model + */ + public String[] getAllVariables() throws FMILException { + synchronized(syncObject) { + + try { + + if(variableNames == null) { + variableNames = getAllVariables_(getModelIDNew()); + } + return variableNames; + + } catch (UnsatisfiedLinkError err) { + throw new FMILException(UNSATISFIED_LINK); + } catch (Exception e) { + throw new FMILException(e.getMessage()); + } + } + } + + private native String[] getAllVariables_(int id); + + public String[] getAllVariableDescriptions() throws FMILException { + synchronized(syncObject) { + + try { + + if(variableDescriptions == null) { + variableDescriptions = getAllVariableDescriptions_(getModelIDNew()); + } + return variableDescriptions; + + } catch (UnsatisfiedLinkError err) { + throw new FMILException(UNSATISFIED_LINK); + } catch (Exception e) { + throw new FMILException(e.getMessage()); + } + } + } + + private native String[] getAllVariableDescriptions_(int id); + + public String[] getAllVariableDeclaredTypes() throws FMILException { + synchronized(syncObject) { + + try { + + if(variableDeclaredTypes == null) { + variableDeclaredTypes = getAllVariableDeclaredTypes_(getModelIDNew()); + } + return variableDeclaredTypes; + + } catch (UnsatisfiedLinkError err) { + throw new FMILException(UNSATISFIED_LINK); + } catch (Exception e) { + throw new FMILException(e.getMessage()); + } + } + } + + private native String[] getAllVariableDeclaredTypes_(int id); + + public int[] getAllVariableReferences() throws FMILException { + synchronized(syncObject) { + + try { + + if(variableReferences == null) { + variableReferences = getAllVariableReferences_(getModelIDNew(), new int[variableNames.length]); + } + return variableReferences; + + } catch (UnsatisfiedLinkError err) { + throw new FMILException(UNSATISFIED_LINK); + } catch (Exception e) { + throw new FMILException(e.getMessage()); + } + } + } + + private native int[] getAllVariableReferences_(int id, int[] array); + + public int[] getAllVariableTypes() throws FMILException { + synchronized(syncObject) { + + try { + + if(variableTypes == null) { + variableTypes = getAllVariableTypes_(getModelIDNew(), new int[variableNames.length]); + } + return variableTypes; + + } catch (UnsatisfiedLinkError err) { + throw new FMILException(UNSATISFIED_LINK); + } catch (Exception e) { + throw new FMILException(e.getMessage()); + } + } + } + + private native int[] getAllVariableTypes_(int id, int[] array); + + public int[] getAllVariableCausalities() throws FMILException { + synchronized(syncObject) { + + try { + + if(variableCausalities == null) { + variableCausalities = getAllVariableCausalities_(getModelIDNew(), new int[variableNames.length]); + } + return variableCausalities; + + } catch (UnsatisfiedLinkError err) { + throw new FMILException(UNSATISFIED_LINK); + } catch (Exception e) { + throw new FMILException(e.getMessage()); + } + } + } + + private native int[] getAllVariableCausalities_(int id, int[] array); + + public int[] getAllVariableVariabilities() throws FMILException { + synchronized(syncObject) { + + try { + + if(variableVariabilities == null) { + variableVariabilities = getAllVariableVariabilities_(getModelIDNew(), new int[variableNames.length]); + } + return variableVariabilities; + + } catch (UnsatisfiedLinkError err) { + throw new FMILException(UNSATISFIED_LINK); + } catch (Exception e) { + throw new FMILException(e.getMessage()); + } + } + } + + private native int[] getAllVariableVariabilities_(int id, int[] array); + + /** + * Get all variables in a loaded model + * @return all variables in a loaded model + */ + public String[] getAllDeclaredTypes() throws FMILException { + synchronized(syncObject) { + + try { + + if(declaredTypes == null) { + declaredTypes = getAllDeclaredTypes_(getModelIDNew()); + } + return declaredTypes; + + } catch (UnsatisfiedLinkError err) { + throw new FMILException(UNSATISFIED_LINK); + } catch (Exception e) { + throw new FMILException(e.getMessage()); + } + } + } + + private native String[] getAllDeclaredTypes_(int id); + + public String[] getAllDeclaredTypeDescriptions() throws FMILException { + synchronized(syncObject) { + + try { + + if(declaredTypeDescriptions == null) { + declaredTypeDescriptions = getAllDeclaredTypeDescriptions_(getModelIDNew()); + } + return declaredTypeDescriptions; + + } catch (UnsatisfiedLinkError err) { + throw new FMILException(UNSATISFIED_LINK); + } catch (Exception e) { + throw new FMILException(e.getMessage()); + } + } + } + + private native String[] getAllDeclaredTypeDescriptions_(int id); + + public String[] getAllDeclaredTypeQuantities() throws FMILException { + synchronized(syncObject) { + + try { + + if(declaredTypeQuantities == null) { + declaredTypeQuantities = getAllDeclaredTypeQuantities_(getModelIDNew()); + } + return declaredTypeQuantities; + + } catch (UnsatisfiedLinkError err) { + throw new FMILException(UNSATISFIED_LINK); + } catch (Exception e) { + throw new FMILException(e.getMessage()); + } + } + } + + private native String[] getAllDeclaredTypeQuantities_(int id); + + public String[] getAllDeclaredTypeUnits() throws FMILException { + synchronized(syncObject) { + + try { + + if(declaredTypeUnits == null) { + declaredTypeUnits = getAllDeclaredTypeUnits_(getModelIDNew()); + } + return declaredTypeUnits; + + } catch (UnsatisfiedLinkError err) { + throw new FMILException(UNSATISFIED_LINK); + } catch (Exception e) { + throw new FMILException(e.getMessage()); + } + } + } + + private native String[] getAllDeclaredTypeUnits_(int id); + + +// +// /** +// * Get all variables from model that match the filter (and time variable) +// * +// * @param regexp Regular expression filter +// * @return An array of variable names that match regexp filter (and time-variable) +// * @throws FMILException +// */ +// public String[] filterVariables(String regexp) throws FMILException { +// synchronized(syncObject) { +// try { +// +// return filterVariables_(getModelID(), regexp + "|time"); +// +// } catch (UnsatisfiedLinkError err) { +// throw new FMILException(UNSATISFIED_LINK); +// } catch (Exception e) { +// throw new FMILException(e.getMessage()); +// } +// } +// } +// +// private native String[] filterVariables_(String id, String regexp); +//// +// /** +// * Get the last error message +// * @return Last error message +// */ +// public String getLastErrorMessage() throws FMILException { +// synchronized(syncObject) { +// +// try { +// +// return "err"; +// //return getLastErrorMessage_(getModelID()); +// +// } catch (UnsatisfiedLinkError err) { +// throw new FMILException(UNSATISFIED_LINK); +// } catch (Exception e) { +// throw new FMILException(e.getMessage()); +// } +// } +// } +// +// private native String getLastErrorMessage_(String id); + + /** + * 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 { + return getIntegerValue_(getModelIDNew(), variableReference); + } catch (UnsatisfiedLinkError err) { + throw new FMILException(UNSATISFIED_LINK); + } catch (Exception e) { + throw new FMILException(e.getMessage()); + } + } + } + + 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; + } + + /** + * 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 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; + + @SuppressWarnings("resource") + private boolean lockFMUDirectory() { + + try { + // Get a file channel for the lock file + File lockFile = new File(TEMP_FMU_DIRECTORY, LOCK_FILE_NAME); + if(!lockFile.isFile()) + lockFile.createNewFile(); + + channel = new RandomAccessFile(lockFile, "rw").getChannel(); + + // Use the file channel to create a lock on the file. + // This method blocks until it can retrieve the lock. + lock = channel.lock(); + + // // Try acquiring the lock without blocking. This method returns + // // null or throws an exception if the file is already locked. + // try { + // lock = channel.tryLock(); + // } catch (OverlappingFileLockException e) { + // // File is already locked in this thread or virtual machine + // } + } catch (IOException e) { + return false; + } + + return true; + } + + private boolean unlockFMUDirectory() { + try { + // Release the lock + if(lock != null) + lock.release(); + + // Close the file + if(channel != null) + channel.close(); + } catch (IOException e) { + return false; + } + return true; + } + + private boolean removeFMUDirectoryContents() { + // Remove contents + try { + File tempDir = new File(TEMP_FMU_DIRECTORY); + FileUtils.deleteAll(tempDir); + tempDir.delete(); + } catch (IOException e) { + return false; + } + return true; + } + + @Override + protected void finalize() throws Throwable { + try { + unloadFMU(); + } catch (Throwable t) { + LOGGER.error("Could not unload native FMU!", t); + } finally { + super.finalize(); + } + } +}