Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding support for FMI2 serialize commands #425

Merged
merged 3 commits into from
Aug 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading