diff --git a/interpreter/src/main/java/org/intocps/maestro/interpreter/Fmi2Interpreter.java b/interpreter/src/main/java/org/intocps/maestro/interpreter/Fmi2Interpreter.java index c51f149bb..cdadb765f 100644 --- a/interpreter/src/main/java/org/intocps/maestro/interpreter/Fmi2Interpreter.java +++ b/interpreter/src/main/java/org/intocps/maestro/interpreter/Fmi2Interpreter.java @@ -79,7 +79,7 @@ public static String getString(Value value) { throw new InterpreterException("Value is not string"); } - public static void checkArgLength(List values, int size) { + public static void checkArgLength(List values, int size) { if (values == null) { throw new InterpreterException("No values passed"); } @@ -487,6 +487,111 @@ public static FmuComponentValue getFmuComponentValue(BufferedOutputStream fmuLog throw new InterpreterException("Invalid value"); + })); + + componentMembers.put("getSerializedFMUstateSize", new FunctionValue.ExternalFunctionValue(fcargs -> { + + checkArgLength(fcargs, 2); + + if (!(fcargs.get(1).isUpdatable())) { + throw new InterpreterException("size value not a reference value"); + } + + Value v = fcargs.get(0).deref(); + Value sizeValue = fcargs.get(1); + + if (v instanceof FmuComponentStateValue && sizeValue.deref().isNumeric()) { + try { + FmuComponentStateValue stateValue = (FmuComponentStateValue) v; + FmuResult res = component.getSerializedFMUstateSize(stateValue.getModule()); + if (res.status == Fmi2Status.OK) { + ((UpdatableValue) sizeValue).setValue(new LongValue(res.result)); + } + return new IntegerValue(res.status.value); + } catch (FmuInvocationException e) { + throw new InterpreterException(e); + } + } + + throw new InterpreterException("Invalid value"); + + + })); + + componentMembers.put("serializeFMUstate", new FunctionValue.ExternalFunctionValue(fcargs -> { + + checkArgLength(fcargs, 3); + + if (!(fcargs.get(2).isUpdatable())) { + throw new InterpreterException("bytes value not a reference value"); + } + + Value v = fcargs.get(0).deref(); + Value sizeValue = fcargs.get(1).deref(); + Value bytesValue = fcargs.get(2); + + if (v instanceof FmuComponentStateValue && sizeValue.isNumeric()) { + try { + FmuComponentStateValue stateValue = (FmuComponentStateValue) v; + NumericValue size = (NumericValue) sizeValue; + FmuResult res = component.serializeFMUstate(stateValue.getModule(), size.longValue()); + + if (res.status == Fmi2Status.OK) { + List byteValues = new Vector<>(); + for (byte b : res.result) { + byteValues.add(new ByteValue(b)); + } + + ((UpdatableValue) bytesValue).setValue(new ArrayValue<>(byteValues)); + } + return new IntegerValue(res.status.value); + } catch (FmuInvocationException e) { + throw new InterpreterException(e); + } + } + + throw new InterpreterException("Invalid value"); + + + })); + + componentMembers.put("deSerializeFMUstate", new FunctionValue.ExternalFunctionValue(fcargs -> { + + checkArgLength(fcargs, 3); + + if (!(fcargs.get(2).isUpdatable())) { + throw new InterpreterException("bytes value not a reference value"); + } + + Value bytesValue = fcargs.get(0).deref(); + Value sizeValue = fcargs.get(1).deref(); + Value stateValue = fcargs.get(2); + + if ( sizeValue.isNumeric()) { + try { + NumericValue size = (NumericValue) sizeValue; + ArrayValue byteArray = (ArrayValue) bytesValue; + byte[] bytes = new byte[byteArray.getValues().size()]; + for (int i = 0; i < bytes.length; i++) { + bytes[i] = (byte) byteArray.getValues().get(i).getValue(); + } + + FmuResult res = component.deSerializeFMUstate(bytes, size.longValue()); + + if (res.status == Fmi2Status.OK) { + UpdatableValue ref = (UpdatableValue) stateValue; + ref.setValue(new FmuComponentStateValue(res.result)); + } + + return new IntegerValue(res.status.value); + } catch (FmuInvocationException e) { + throw new InterpreterException(e); + } + } + + throw new InterpreterException("Invalid value"); + + })); componentMembers.put("getRealStatus", new FunctionValue.ExternalFunctionValue(fcargs -> { diff --git a/interpreter/src/main/java/org/intocps/maestro/interpreter/Interpreter.java b/interpreter/src/main/java/org/intocps/maestro/interpreter/Interpreter.java index cc6244ced..4b77b8144 100644 --- a/interpreter/src/main/java/org/intocps/maestro/interpreter/Interpreter.java +++ b/interpreter/src/main/java/org/intocps/maestro/interpreter/Interpreter.java @@ -202,7 +202,7 @@ public Value caseANotEqualBinaryExp(ANotEqualBinaryExp node, Context question) t public ArrayValue createArrayValue(List sizes, PType type, Context question) throws AnalysisException { List arrayValues = new ArrayList<>(); - for (int i = 0; i < ((NumericValue) sizes.get(0).apply(this, question)).intValue(); i++) { + for (int i = 0; i < ((NumericValue) sizes.get(0).apply(this, question).deref()).intValue(); i++) { if (sizes.size() > 1) { List nextSizes = sizes.subList(1, sizes.size()); // Call recursively diff --git a/interpreter/src/main/java/org/intocps/maestro/interpreter/values/IntegerValue.java b/interpreter/src/main/java/org/intocps/maestro/interpreter/values/IntegerValue.java index fe5f32991..f65674e8d 100644 --- a/interpreter/src/main/java/org/intocps/maestro/interpreter/values/IntegerValue.java +++ b/interpreter/src/main/java/org/intocps/maestro/interpreter/values/IntegerValue.java @@ -48,6 +48,10 @@ public int compareTo(Value other) { if (other instanceof IntegerValue || other instanceof ByteValue || other instanceof ShortValue) { NumericValue io = (NumericValue) other; return (value < io.intValue() ? -1 : (value == io.intValue() ? 0 : 1)); + }else if( other instanceof LongValue) + { + NumericValue io = (NumericValue) other; + return (value < io.longValue() ? -1 : (value == io.longValue() ? 0 : 1)); } return super.compareTo(other); diff --git a/maestro-webapi/src/main/java/org/intocps/maestro/webapi/services/EnvironmentFMUComponent.java b/maestro-webapi/src/main/java/org/intocps/maestro/webapi/services/EnvironmentFMUComponent.java index 4607a9cec..d17b8afe2 100644 --- a/maestro-webapi/src/main/java/org/intocps/maestro/webapi/services/EnvironmentFMUComponent.java +++ b/maestro-webapi/src/main/java/org/intocps/maestro/webapi/services/EnvironmentFMUComponent.java @@ -92,6 +92,21 @@ public void freeInstance() throws FmuInvocationException { } + @Override + public FmuResult getSerializedFMUstateSize(IFmiComponentState iFmiComponentState) throws FmuInvocationException { + return new FmuResult<>(Fmi2Status.Error, null); + } + + @Override + public FmuResult serializeFMUstate(IFmiComponentState iFmiComponentState, long l) throws FmuInvocationException { + return new FmuResult<>(Fmi2Status.Error, null); + } + + @Override + public FmuResult deSerializeFMUstate(byte[] bytes, long l) throws FmuInvocationException { + return new FmuResult<>(Fmi2Status.Error, null); + } + @Override public boolean isValid() { return false; diff --git a/maestro/src/test/java/org/intocps/maestro/FullSpecOnlineTest.java b/maestro/src/test/java/org/intocps/maestro/FullSpecOnlineTest.java index 3ab9e039e..bad207cff 100644 --- a/maestro/src/test/java/org/intocps/maestro/FullSpecOnlineTest.java +++ b/maestro/src/test/java/org/intocps/maestro/FullSpecOnlineTest.java @@ -26,6 +26,7 @@ private static Stream data() { @ParameterizedTest(name = "{index} \"{0}\"") @MethodSource("data") public void test(String name, File directory) throws Exception { + OnlineTestUtils.downloadJniFmuTestFmus(); for (INode spec : parse(getSpecificationFiles(directory))) { OnlineTestUtils.download(OnlineTestUtils.collectFmus(spec, false)); } diff --git a/maestro/src/test/java/org/intocps/maestro/OnlineTestUtils.java b/maestro/src/test/java/org/intocps/maestro/OnlineTestUtils.java index 07d319afd..dd89a4811 100644 --- a/maestro/src/test/java/org/intocps/maestro/OnlineTestUtils.java +++ b/maestro/src/test/java/org/intocps/maestro/OnlineTestUtils.java @@ -1,6 +1,7 @@ package org.intocps.maestro; import org.apache.commons.io.FileUtils; +import org.apache.commons.io.IOUtils; import org.intocps.maestro.ast.analysis.AnalysisException; import org.intocps.maestro.ast.analysis.DepthFirstAnalysisAdaptor; import org.intocps.maestro.ast.node.ALoadExp; @@ -9,11 +10,15 @@ import org.intocps.maestro.ast.node.PExp; import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import java.util.List; import java.util.Vector; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; public class OnlineTestUtils { @@ -26,9 +31,9 @@ public static void download(List urls) throws IOException { String file = url.getFile(); file = file.substring(file.lastIndexOf('/') + 1); File destination = new File("target/online-cache/" + file); - if (!destination.exists()) { + if (!destination.exists() && !destination.getName().endsWith("functiontest.fmu")) { - URL zipNameUrl =new URL( url.toString().replace(".fmu",".zip")); + URL zipNameUrl = new URL(url.toString().replace(".fmu", ".zip")); System.out.println("Downloading: " + zipNameUrl + " as: " + destination); FileUtils.copyURLToFile(zipNameUrl, destination); @@ -38,6 +43,39 @@ public static void download(List urls) throws IOException { } } + public static void downloadJniFmuTestFmus() throws IOException { + System.out.println("Downloading FMUs"); + URL url = new URL("https://github.com/INTO-CPS-Association/org.intocps.maestro.fmi/releases/download/Release%2F1.5.0/test-fmus.zip"); + String file = url.getFile(); + file = file.substring(file.lastIndexOf('/') + 1); + File destination = new File("target/online-cache/" + file); + if (!destination.exists()) { + +// URL zipNameUrl = new URL(url.toString().replace(".fmu", ".zip")); + + System.out.println("Downloading: " + url + " as: " + destination); + FileUtils.copyURLToFile(url, destination); + //lets unpack the fmus + if (destination.exists() && destination.isFile()) { + try (FileInputStream fis = new FileInputStream(destination); + ZipInputStream zis = new ZipInputStream(fis)) { + ZipEntry entry = zis.getNextEntry(); + while (entry != null) { + if (entry.getName().endsWith("functiontest.fmu")) { + IOUtils.copy(zis, new FileOutputStream("target/online-cache/" + new File(entry.getName()).getName())); + + } + zis.closeEntry(); + entry = zis.getNextEntry(); + } + } + } + } else { + System.out.println("Skipped - Downloading: " + url + " as: " + destination); + } + } + + public static List collectFmus(INode spec, boolean updatePath) throws AnalysisException { class FmuCollector extends DepthFirstAnalysisAdaptor { final List fmus = new Vector<>(); diff --git a/maestro/src/test/resources/specifications/online/serialize/serialize.mabl b/maestro/src/test/resources/specifications/online/serialize/serialize.mabl new file mode 100644 index 000000000..599a72372 --- /dev/null +++ b/maestro/src/test/resources/specifications/online/serialize/serialize.mabl @@ -0,0 +1,85 @@ +simulation +import Math; +import FMI2; +import DataWriter; +import Logger; +import FmiComponentState; +{ + Logger logger = load("Logger"); + FMI2 fmu = load("FMI2", "{12345678-9999-9999-9999-000000000000}", "target/online-cache/fmi2functiontest.fmu"); + FMI2Component comp = fmu.instantiate("crtlInstance", false, false); + int status=0; + status = comp.setupExperiment(false, 0.0, 0.0, true, 10.0); + logger.log(1, "Status setupExperiment: %d", status); + + status = comp.enterInitializationMode(); + logger.log(1, "Status enterInitializationMode: %d", status); + + FmiComponentState state0; + status = comp.getState(ref state0); + logger.log(1, "Status getState: %d", status); + + uint vr[1]={0}; + uint nvr=1; + real values[1]= {99.9}; + status = comp.setReal(vr,nvr,values); + logger.log(1, "Status setReal: %d", status); + + status = comp.exitInitializationMode(); + logger.log(1, "Status exitInitializationMode: %d", status); + + FmiComponentState state; + status = comp.getState(ref state); + logger.log(1, "Status getState: %d", status); + + int size=0; + status = comp.getSerializedFMUstateSize(state,ref size); + logger.log(1, "Status getSerializedFMUstateSize: %d", status); + logger.log(1, "State size: %d", size); + + byte bytes[size]; + status = comp.serializeFMUstate(state, size,ref bytes); + logger.log(1, "Status serializeFMUstate: %d", status); + int i = 0; + logger.log(1, "The state bytes:",""); + while(i11 11 2.17.1 - 1.4.1 + 1.5.0 1.0.10 1.7.21 2.13.12 @@ -418,7 +418,7 @@ commons-io commons-io - 2.10.0 + 2.15.1 compile diff --git a/typechecker/src/main/resources/org/intocps/maestro/typechecker/FMI2.mabl b/typechecker/src/main/resources/org/intocps/maestro/typechecker/FMI2.mabl index c30134406..aee6f9602 100644 --- a/typechecker/src/main/resources/org/intocps/maestro/typechecker/FMI2.mabl +++ b/typechecker/src/main/resources/org/intocps/maestro/typechecker/FMI2.mabl @@ -51,6 +51,10 @@ import FmiComponentState; int setState(FmiComponentState state); int freeState(out FmiComponentState state); + int getSerializedFMUstateSize(FmiComponentState state, out long size); + int serializeFMUstate(FmiComponentState state, long size, out byte[] bytes); + int deSerializeFMUstate(byte[] bytes, long size, out FmiComponentState state); + } module FmiComponentState {}