Skip to content

Commit

Permalink
Merge pull request #425 from INTO-CPS-Association/kel/fmi2-serialize
Browse files Browse the repository at this point in the history
Adding support for FMI2 serialize commands
  • Loading branch information
lausdahl authored Aug 15, 2024
2 parents dec864d + 35b3fbc commit 1aac687
Show file tree
Hide file tree
Showing 9 changed files with 258 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ public static String getString(Value value) {
throw new InterpreterException("Value is not string");
}

public static void checkArgLength(List<Value> values, int size) {
public static void checkArgLength(List<Value> values, int size) {
if (values == null) {
throw new InterpreterException("No values passed");
}
Expand Down Expand Up @@ -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<Long> 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<byte[]> res = component.serializeFMUstate(stateValue.getModule(), size.longValue());

if (res.status == Fmi2Status.OK) {
List<ByteValue> 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<ByteValue> byteArray = (ArrayValue<ByteValue>) 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<IFmiComponentState> 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 -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ public Value caseANotEqualBinaryExp(ANotEqualBinaryExp node, Context question) t

public ArrayValue createArrayValue(List<PExp> sizes, PType type, Context question) throws AnalysisException {
List<Value> 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<PExp> nextSizes = sizes.subList(1, sizes.size());
// Call recursively
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,21 @@ public void freeInstance() throws FmuInvocationException {

}

@Override
public FmuResult<Long> getSerializedFMUstateSize(IFmiComponentState iFmiComponentState) throws FmuInvocationException {
return new FmuResult<>(Fmi2Status.Error, null);
}

@Override
public FmuResult<byte[]> serializeFMUstate(IFmiComponentState iFmiComponentState, long l) throws FmuInvocationException {
return new FmuResult<>(Fmi2Status.Error, null);
}

@Override
public FmuResult<IFmiComponentState> deSerializeFMUstate(byte[] bytes, long l) throws FmuInvocationException {
return new FmuResult<>(Fmi2Status.Error, null);
}

@Override
public boolean isValid() {
return false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ private static Stream<Arguments> 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));
}
Expand Down
42 changes: 40 additions & 2 deletions maestro/src/test/java/org/intocps/maestro/OnlineTestUtils.java
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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 {

Expand All @@ -26,9 +31,9 @@ public static void download(List<URL> 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);
Expand All @@ -38,6 +43,39 @@ public static void download(List<URL> 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<URL> collectFmus(INode spec, boolean updatePath) throws AnalysisException {
class FmuCollector extends DepthFirstAnalysisAdaptor {
final List<URL> fmus = new Vector<>();
Expand Down
Original file line number Diff line number Diff line change
@@ -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(i<size)
{
logger.log(1, "%d", bytes[i]);
i = i +1;
}

FmiComponentState stateRestore;
status = comp.deSerializeFMUstate(bytes,size,ref stateRestore);
logger.log(1, "Status deSerializeFMUstate: %d", status);

status = comp.getReal(vr,nvr,values);
logger.log(1, "Status setReal: %d, value: %f", status,values[0]);


//lets try to check the initial state
logger.log(1, "Set base state", "");
status =comp.setState(state0);
logger.log(1, "Status setState: %d", status);

status = comp.getReal(vr,nvr,values);
logger.log(1, "Status setReal: %d, value: %f", status,values[0]);

//lets check the deserialized state
logger.log(1, "Set deserialized state", "");
status =comp.setState(stateRestore);
logger.log(1, "Status setState: %d", status);

status = comp.getReal(vr,nvr,values);
logger.log(1, "Status setReal: %d, value: %f", status,values[0]);

//clean up
comp.freeState(ref state0);
comp.freeState(ref state);
comp.freeState(ref stateRestore);


unload(logger);
fmu.freeInstance(comp);
unload(fmu);
}

4 changes: 2 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<log4j2.version>2.17.1</log4j2.version>
<fmu.api.version>1.4.1</fmu.api.version>
<fmu.api.version>1.5.0</fmu.api.version>
<maestro.v1.version>1.0.10</maestro.v1.version>
<kotlin.version>1.7.21</kotlin.version>
<scala.version>2.13.12</scala.version>
Expand Down Expand Up @@ -418,7 +418,7 @@
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.10.0</version>
<version>2.15.1</version>
<scope>compile</scope>
</dependency>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 {}
Expand Down

0 comments on commit 1aac687

Please sign in to comment.