All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.javafmi.proxy.v1.FmuProxy Maven / Gradle / Ivy

Go to download

javaFMI is a Java Library for the functional mock-up interface (or FMI). FMI defines a standardized interface to be used in computer simulations. The FMI Standard has beed developed by a large number of software companies and research centers that have worked in a cooperation project under the name of MODELISAR. This library addresses the connection of a java application with a FMU (functional mock-up unit).

There is a newer version: 2.26.5
Show newest version
/*
 *  Copyright 2013-2016 SIANI - ULPGC
 *
 *  This File is part of JavaFMI Project
 *
 *  JavaFMI Project is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Lesser General Public License as published by
 *  the Free Software Foundation, either version 3 of the License.
 *
 *  JavaFMI Project is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 *  GNU Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public License
 *  along with JavaFMI. If not, see .
 */

package org.javafmi.proxy.v1;

import com.sun.jna.Function;
import com.sun.jna.Library;
import com.sun.jna.NativeLibrary;
import com.sun.jna.Pointer;
import org.javafmi.kernel.OS;
import org.javafmi.modeldescription.FmiVersion;
import org.javafmi.modeldescription.ScalarVariable;
import org.javafmi.modeldescription.v1.EnumerationType;
import org.javafmi.modeldescription.v1.ModelDescription;
import org.javafmi.proxy.*;

import java.io.File;
import java.nio.ByteBuffer;
import java.nio.DoubleBuffer;
import java.nio.IntBuffer;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

import static org.javafmi.proxy.Status.*;

public class FmuProxy implements FmiProxy {

	private static final String MIME_TYPE = "application/x-fmu-sharedlibrary";
	private static final long DEFAULT_TIMEOUT = 2000;
	private static final boolean DEFAULT_DOING_LOGGING = false;
	private static final boolean DEFAULT_VISIBLE = false;
	private static final boolean DEFAULT_INTERACTIVE = false;
	private static final boolean STOP_DEFINED = true;
	private static final String SET_DEBUG = "_fmiSetDebugLogging";
	private static final String GET_REAL = "_fmiGetReal";
	private static final String GET_INTEGER = "_fmiGetInteger";
	private static final String GET_BOOLEAN = "_fmiGetBoolean";
	private static final String GET_STRING = "_fmiGetString";
	private static final String SET_REAL = "_fmiSetReal";
	private static final String SET_INTEGER = "_fmiSetInteger";
	private static final String SET_BOOLEAN = "_fmiSetBoolean";
	private static final String SET_STRING = "_fmiSetString";
	private static final String INSTANTIATE = "_fmiInstantiateSlave";
	private static final String INITIALIZE = "_fmiInitializeSlave";
	private static final String TERMINATE = "_fmiTerminateSlave";
	private static final String FREE = "_fmiFreeSlaveInstance";
	private static final String RESET = "_fmiResetSlave";
	private static final String DO_STEP = "_fmiDoStep";
	private static final String CANCEL_STEP = "_fmiCancelStep";
	private final String libraryPath;
	private ModelDescription modelDescription;
	private NativeLibrary libraryInstance;
	private double startTime;
	private double stopTime;
	private Pointer component;
	private Map functions;
	private FmuProxyState fmuProxyState;
	private CallbackFunctions.ByValue callbacks;
	private Buffers buffers;

	public FmuProxy(String libraryPath, ModelDescription modelDescription) {
		this.libraryPath = libraryPath;
		this.modelDescription = modelDescription.build();
		this.callbacks = new CallbackFunctions.ByValue();
		this.libraryInstance = getInstance(libraryPath);
		this.functions = getFunctions();
		this.buffers = new Buffers();
	}

	private NativeLibrary getInstance(String libraryPath) {
		int RTLD_NOW = 0x00002, RTLD_DEEPBIND = 0x00008;
		Map options = new HashMap<>();
		if(OS.isLinux32() || OS.isLinux64()) options.put(Library.OPTION_OPEN_FLAGS,  RTLD_NOW | RTLD_DEEPBIND);
		return NativeLibrary.getInstance(libraryPath, options);
	}

	static String[] functionsSuffix() {
		return new String[]{SET_DEBUG, GET_REAL, GET_INTEGER, GET_BOOLEAN, GET_STRING, SET_REAL, SET_INTEGER, SET_BOOLEAN, SET_STRING, INSTANTIATE, INITIALIZE, TERMINATE, FREE, RESET, DO_STEP, CANCEL_STEP};
	}

	@Override
	public void instantiate(String resourcesPath) {
		component = (Pointer) functions.get(INSTANTIATE).invoke(Pointer.class, getParametersForInstantiate(libraryPath));
		if (component == Pointer.NULL)
			throw new MethodExecutionException("Instantiate: " + modelDescription.getModelIdentifier());
		fmuProxyState = FmuProxyState.INSTANTIATED;
	}

	public Map getFunctions() {
		LinkedHashMap functions = new LinkedHashMap<>();
		for (String suffix : functionsSuffix())
			functions.put(suffix, getFunction(suffix));
		return functions;
	}

	@Override
	public Status initialize(double startTime, double stopTime) {
		if (fmuProxyState.equals(FmuProxyState.INITED)) return WARNING;
		this.startTime = startTime;
		this.stopTime = Double.isNaN(stopTime) ? Double.MAX_VALUE : stopTime;
		if (translateStatus(functions.get(INITIALIZE).invokeInt(getParametersForInitialize())) != Status.OK)
			throw new RuntimeException("impossible to initialize");
		fmuProxyState = FmuProxyState.INITED;
		return OK;
	}

	@Override
	public Status terminate() {
		Status terminateStatus = translateStatus((Integer) functions.get(TERMINATE).invoke(Integer.class, new Object[]{component}));
		if (terminateStatus.equals(OK)) fmuProxyState = FmuProxyState.TERMINATED;
		else fmuProxyState = FmuProxyState.INITED;
		return terminateStatus;
	}

	@Override
	public Status reset() {
		Status resetStatus = translateStatus((Integer) functions.get(RESET).invoke(Integer.class, new Object[]{component}));
		if (resetStatus.equals(Status.OK)) {
			fmuProxyState = FmuProxyState.INSTANTIATED;
		}
		return resetStatus;
	}

	@Override
	public void freeInstance() {
		functions.get(FREE).invoke(new Object[]{component});
		libraryInstance.dispose();
	}

	@Override
	public Status doStep(double communicationPoint, double stepSize) {
		return translateStatus(functions.get(DO_STEP).invokeInt(getParametersForDoStep(stepSize, communicationPoint)));
	}

	@Override
	public Status cancelStep() {
		return translateStatus((Integer) functions.get(CANCEL_STEP).invoke(Integer.class, new Object[]{component}));
	}

	@Override
	public Object getEnumeration(ScalarVariable modelVariable) {
		EnumerationType enumeration = (EnumerationType) modelVariable.getType();
		Integer enumerationIndex;
		EnumerationType enumerationType = (EnumerationType) modelDescription.getTypeFromTypeDefinition(enumeration.getDeclaredType());
		if (modelVariable.getVariability().equalsIgnoreCase("constant")) {
			enumerationIndex = enumeration.getStart();
			return enumerationType.getItems().get(enumerationIndex - 1).getName();
		}
		enumerationIndex = getInteger(modelVariable.getValueReference())[0];
		return enumerationType.getItems().get(enumerationIndex - 1).getName();
	}

	@Override
	public double[] getReal(int... valueReferences) {
		DoubleBuffer buffer = buffers.forDouble(valueReferences.length);
		functions.get(GET_REAL).invokeInt(new Object[]{component, valueReferences, valueReferences.length, buffer});
		return buffer.array();
	}

	@Override
	public int[] getInteger(int... valueReference) {
		IntBuffer buffer = buffers.forInteger(valueReference.length);
		functions.get(GET_INTEGER).invoke(getParametersForFmuGetterSetter(valueReference, buffer));
		return buffer.array();
	}

	@Override
	public boolean[] getBoolean(int... valueReference) {
		ByteBuffer buffer = buffers.forBytes(valueReference.length);
		functions.get(GET_BOOLEAN).invoke(getParametersForFmuGetterSetter(valueReference, buffer));
		byte[] resultAsArray = buffer.array();
		boolean[] resultAsBoolean = new boolean[resultAsArray.length];
		for (int i = 0; i < resultAsArray.length; i++) {
			resultAsBoolean[i] = NativeBoolean.getBooleanFor(resultAsArray[i]);
		}
		return resultAsBoolean;
	}

	@Override
	public String[] getString(int... valueReference) {
		String[] buffer = new String[valueReference.length];
		functions.get(GET_STRING).invoke(getParametersForFmuGetterSetter(valueReference, buffer));
		return buffer;
	}

	@Override
	public Status setReal(int[] valueReferences, double[] values) {
		return translateStatus(functions.get(SET_REAL).invokeInt(new Object[]{component, valueReferences, valueReferences.length, values}));
	}

	@Override
	public Status setInteger(int[] valueReferences, int[] values) {
		return translateStatus(functions.get(SET_INTEGER).invokeInt(getParametersForFmuGetterSetter(valueReferences, values)));
	}

	@Override
	public Status setBoolean(int[] valueReference, boolean[] values) {
		return translateStatus(functions.get(SET_BOOLEAN).invokeInt(getParametersForFmuGetterSetter(valueReference, values)));
	}

	@Override
	public Status setString(int[] valueReference, String[] newValue) {
		return translateStatus(functions.get(SET_STRING).invokeInt(getParametersForFmuGetterSetter(valueReference, newValue)));
	}

	@SuppressWarnings("UnusedParameters")
	public Status setIsDoingLogging(boolean isDoingLogging) {
		return translateStatus(functions.get(SET_DEBUG).invokeInt(getParametersForSetDebugLogging()));
	}

	@Override
	public boolean isTerminated() {
		return fmuProxyState.equals(FmuProxyState.TERMINATED);
	}

	private Function getFunction(String suffix) {
		return libraryInstance.getFunction(modelDescription.getModelIdentifier() + suffix);
	}

	private Object[] getParametersForInstantiate(String libraryPath) {
		return new Object[]{modelDescription.getModelIdentifier(), modelDescription.getGuid(), rootFolderOf(libraryPath), MIME_TYPE, DEFAULT_TIMEOUT, NativeBoolean.getValueFor(DEFAULT_VISIBLE), NativeBoolean.getValueFor(DEFAULT_INTERACTIVE), callbacks, NativeBoolean.getValueFor(DEFAULT_DOING_LOGGING)};
	}

	private Object[] getParametersForInitialize() {
		return new Object[]{component, startTime, NativeBoolean.getValueFor(STOP_DEFINED), stopTime};
	}

	private Object[] getParametersForDoStep(double stepSize, double communicationPoint) {
		return new Object[]{component, communicationPoint, stepSize, (byte) 1};
	}

	private Object[] getParametersForSetDebugLogging() {
		return new Object[]{component, NativeBoolean.getValueFor(DEFAULT_DOING_LOGGING)};
	}

	public Object[] getParametersForFmuGetterSetter(int[] valueReference, Object buffer) {
		return new Object[]{component, valueReference, valueReference.length, buffer};
	}

	private String rootFolderOf(String libraryPath) {
		return new File(libraryPath).getParentFile().getParentFile().getParentFile().getAbsolutePath();
	}

	@Override
	public String getVersion() {
		return FmiVersion.One;
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy