From e310a96db7039063e26e8c57e2c68f5689432816 Mon Sep 17 00:00:00 2001
From: Tim Uebelhoer <tim.uebelhoer@rwth-aachen.de>
Date: Mon, 18 Dec 2017 12:06:28 +0100
Subject: [PATCH] Finished the unmanaged interface and the Managed wrapper
 class

---
 ModeliRpc.capnp                               |   6 +-
 ModeliRpc/ModeliRpcCLR/ModeliRpc.cpp          | 127 +++++++++++++++---
 ModeliRpc/ModeliRpcCLR/ModeliRpc.h            |  23 ++++
 ModeliRpc/ModeliRpcCLR/ModeliRpcCLR.vcxproj   |   2 +
 .../ModeliRpcCLR/ModeliRpcCLR.vcxproj.filters |   6 +
 ModeliRpc/ModeliRpcCLR/NewValuesEventArgs.h   |   2 +-
 ModeliRpc/ModeliRpcCLR/RpcChannelLink.cpp     |   7 +
 ModeliRpc/ModeliRpcCLR/RpcChannelLink.h       |  14 ++
 ModeliRpc/ModeliRpcNative/CapnConverter.cpp   |   2 +-
 ModeliRpc/ModeliRpcNative/IRpcFrontend.h      |   6 +-
 ModeliRpc/ModeliRpcNative/ModeliRpc.capnp.c++ |  33 ++++-
 ModeliRpc/ModeliRpcNative/ModeliRpc.capnp.h   |  63 ++++++---
 ModeliRpc/ModeliRpcNative/RpcFrontend.cpp     |  16 ++-
 ModeliRpc/ModeliRpcNative/RpcFrontend.h       |   3 +-
 14 files changed, 255 insertions(+), 55 deletions(-)
 create mode 100644 ModeliRpc/ModeliRpcCLR/RpcChannelLink.cpp
 create mode 100644 ModeliRpc/ModeliRpcCLR/RpcChannelLink.h

diff --git a/ModeliRpc.capnp b/ModeliRpc.capnp
index 98df47b..c399418 100644
--- a/ModeliRpc.capnp
+++ b/ModeliRpc.capnp
@@ -8,7 +8,7 @@ interface ModeliBackend {
   # Start Simulation
   play @0 () -> (result : Int16);
   # Simulate as quick as possible
-  playFast @1 () -> (result : Int16);
+  playFast @1 (timeToPlay : Float64) -> (result : Int16);
   # Pause simulation
   pause @2 ();
   # Stop and reset simulation
@@ -54,8 +54,8 @@ struct Values {
   integerValues @2 : List(Int32);
   realValueRefs @3 : List(UInt32);
   realValues @4 : List(Float64);
-  boolValueRefs @5 : List(UInt32);
-  boolValues @6 : List(Bool);
+  boolValueRefs @5 : List(UInt32);  # fmi2Bool is an int (0 = false, 1 = true)
+  boolValues @6 : List(Int32);
   stringValueRefs @7 : List(UInt32);
   stringValues @8 : List(Text);
 }   
\ No newline at end of file
diff --git a/ModeliRpc/ModeliRpcCLR/ModeliRpc.cpp b/ModeliRpc/ModeliRpcCLR/ModeliRpc.cpp
index 883e035..5076e49 100644
--- a/ModeliRpc/ModeliRpcCLR/ModeliRpc.cpp
+++ b/ModeliRpc/ModeliRpcCLR/ModeliRpc.cpp
@@ -31,7 +31,6 @@ namespace ModeliRpc
             static_cast<LogCallback>(Marshal::GetFunctionPointerForDelegate(_log).ToPointer()));
         // Connect
         _rpcFrontend->connect(marshal_as<std::string>(address), port);
-
     }
 
     FrontendRpc::~FrontendRpc()
@@ -52,40 +51,136 @@ namespace ModeliRpc
         }
     }
 
+    int FrontendRpc::Play()
+    {
+        return _rpcFrontend->play();
+    }
+
+    int FrontendRpc::PlayFast(double timeToPlay)
+    {
+        return _rpcFrontend->playFast(timeToPlay);
+    }
+
+    void FrontendRpc::Pause()
+    {
+        _rpcFrontend->pause();
+    }
+
+    int FrontendRpc::Stop()
+    {
+        return _rpcFrontend->stop();
+    }
+
+    bool FrontendRpc::AddFmu(String ^ instanceName, array<Byte>^  fmuFileBuffer)
+    {
+        // Prevent GC from moving the memory
+        pin_ptr<unsigned char> pin = &fmuFileBuffer[0];
+        unsigned char* src = pin;
+        std::vector<unsigned char> buffer(src, src + fmuFileBuffer->Length);
+        return _rpcFrontend->addFmu(marshal_as<std::string>(instanceName), buffer);
+    }
+
+    bool FrontendRpc::RemoveFmu(String ^ instanceName)
+    {
+        return _rpcFrontend->removeFmu(marshal_as<std::string>(instanceName));
+    }
+
+    bool FrontendRpc::AddChannelLink(RpcChannelLink ^ channelLink)
+    {
+        // Native struct
+        ChannelLink nativeLink = {};
+        nativeLink.masterInstanceName = marshal_as<std::string>(channelLink->MasterInstanceName);
+        nativeLink.slaveInstanceName = marshal_as<std::string>(channelLink->SlaveInstanceName);
+        nativeLink.masterValueRef = channelLink->MasterValueRef;
+        nativeLink.slaveValueRef = channelLink->SlaveValueRef;
+        nativeLink.factor = channelLink->Factor;
+        nativeLink.offset = channelLink->Offset;
+        return _rpcFrontend->addChannelLink(nativeLink);
+    }
+
+    bool FrontendRpc::RemoveChannelLink(RpcChannelLink ^ channelLink)
+    {
+        // Native struct
+        ChannelLink nativeLink = {};
+        nativeLink.masterInstanceName = marshal_as<std::string>(channelLink->MasterInstanceName);
+        nativeLink.slaveInstanceName = marshal_as<std::string>(channelLink->SlaveInstanceName);
+        nativeLink.masterValueRef = channelLink->MasterValueRef;
+        nativeLink.slaveValueRef = channelLink->SlaveValueRef;
+        nativeLink.factor = channelLink->Factor;
+        nativeLink.offset = channelLink->Offset;
+        return _rpcFrontend->removeChannelink(nativeLink);
+    }
+
+    int FrontendRpc::SetValues(String^ instanceName, array<unsigned int>^ intVRs, array<int>^ intValues, array<unsigned int>^ realVRs, array<double>^ realValues, array<unsigned int>^ boolVRs, array<int>^ boolValues, array<unsigned int>^ stringVRs, array<String^>^ stringValues)
+    {
+        ValuesStruct values = {};
+        values.instanceName = marshal_as<std::string>(instanceName);
+        // Int
+        pin_ptr<uint32_t> pinIntVrs = &intVRs[0];
+        uint32_t* srcIntVrs = pinIntVrs;
+        values.integerValueRefs.assign(srcIntVrs, srcIntVrs + intVRs->Length);
+        pin_ptr<int32_t> pinIntValues = &intValues[0];
+        int32_t* srcIntValues = pinIntValues;
+        values.integerValues.assign(srcIntValues, srcIntValues + intValues->Length);
+        // Real
+        pin_ptr<uint32_t> pinRealVrs = &realVRs[0];
+        uint32_t* srcRealVrs = pinRealVrs;
+        values.realValueRefs.assign(srcRealVrs, srcRealVrs + realVRs->Length);
+        pin_ptr<double> pinRealValues = &realValues[0];
+        double* srcRealValues = pinRealValues;
+        values.realValues.assign(srcRealValues, srcRealValues + realValues->Length);
+        // Bool
+        pin_ptr<uint32_t> pinBoolVrs = &boolVRs[0];
+        uint32_t* srcBoolVrs = pinBoolVrs;
+        values.boolValueRefs.assign(srcBoolVrs, srcBoolVrs + boolVRs->Length);
+        pin_ptr<int32_t> pinBoolValues = &boolValues[0];
+        int32_t* srcBoolValues = pinBoolValues;
+        values.boolValues.assign(srcBoolValues, srcBoolValues + boolValues->Length);
+        // String
+        pin_ptr<uint32_t> pinStringVrs = &stringVRs[0];
+        uint32_t* srcStringVrs = pinStringVrs;
+        values.stringValueRefs.assign(srcStringVrs, srcStringVrs + stringVRs->Length);
+        for (int i = 0; i < stringValues->Length; i++)
+        {
+            auto temp = stringValues[i];    // I dont know why marshal_as doesnt take stringValues[i]
+            values.stringValues.push_back(marshal_as<std::string>(temp));
+        }
+        // RPC call
+        return _rpcFrontend->setValues(values);
+    }
+
     void FrontendRpc::onNewValues(double timestamp, ValuesStruct values)
     {
         // Copy data into the EventArgs
         auto args = gcnew NewValuesEventArgs();
         args->Timestamp = timestamp;
-        args->InstanceName = marshal_as<String^> (values.instanceName);
+        args->InstanceName = marshal_as<String^>(values.instanceName);
         // Int
-        args->IntegerValueRefs = gcnew array<unsigned int>(values.integerValueRefs.size());
+        args->IntegerValueRefs = gcnew array<unsigned int>(static_cast<int>(values.integerValueRefs.size()));
         pin_ptr<unsigned int> pinIntegerVrs = &args->IntegerValueRefs[0];
         memcpy_s(pinIntegerVrs, args->IntegerValueRefs->Length, values.integerValueRefs.data(), values.integerValueRefs.size());
-        args->IntegerValues = gcnew array<int>(values.integerValues.size());
+        args->IntegerValues = gcnew array<int>(static_cast<int>(values.integerValues.size()));
         pin_ptr<int> pinIntegerValues = &args->IntegerValues[0];
         memcpy_s(pinIntegerValues, args->IntegerValues->Length, values.integerValues.data(), values.integerValues.size());
         // Real
-        args->RealValueRefs = gcnew array<unsigned int>(values.realValueRefs.size());
+        args->RealValueRefs = gcnew array<unsigned int>(static_cast<int>(values.realValueRefs.size()));
         pin_ptr<unsigned int> pinRealVrs = &args->RealValueRefs[0];
         memcpy_s(pinRealVrs, args->RealValueRefs->Length, values.realValueRefs.data(), values.realValueRefs.size());
-        args->RealValues = gcnew array<double>(values.realValues.size());
+        args->RealValues = gcnew array<double>(static_cast<int>(values.realValues.size()));
         pin_ptr<double> pinRealValues = &args->RealValues[0];
         memcpy_s(pinIntegerValues, args->RealValues->Length, values.realValues.data(), values.realValues.size());
         // Bool
-        args->BoolValueRefs = gcnew array<unsigned int>(values.boolValueRefs.size());
+        args->BoolValueRefs = gcnew array<unsigned int>(static_cast<int>(values.boolValueRefs.size()));
         pin_ptr<unsigned int> pinBoolVrs = &args->BoolValueRefs[0];
         memcpy_s(pinBoolVrs, args->BoolValueRefs->Length, values.boolValueRefs.data(), values.boolValueRefs.size());
-        args->BoolValues = gcnew array<bool>(values.boolValues.size());
-        for (int i = 0; i < args->BoolValues->Length; i++)
-        {
-            args->BoolValues[i] = values.boolValues[i];
-        }
-        // String
-        args->StringValueRefs = gcnew array<unsigned int>(values.stringValueRefs.size());
+        args->BoolValues = gcnew array<int>(static_cast<int>(values.boolValues.size()));
+        pin_ptr<int> pinBoolValues = &args->BoolValues[0];
+        memcpy_s(pinBoolValues, args->BoolValueRefs->Length, values.boolValues.data(), values.boolValues.size());
+        // String no memcpy possible because each string needs to be marshalled
+        args->StringValueRefs = gcnew array<unsigned int>(static_cast<int>(values.stringValueRefs.size()));
         pin_ptr<unsigned int> pinStringVrs = &args->StringValueRefs[0];
         memcpy_s(pinStringVrs, args->StringValueRefs->Length, values.stringValueRefs.data(), values.stringValueRefs.size());
-        args->StringValues = gcnew array<String^>(values.stringValues.size());
+        args->StringValues = gcnew array<String^>(static_cast<int>(values.stringValues.size()));
         for (int i = 0; i < args->StringValues->Length; i++)
         {
             args->StringValues[i] = marshal_as<String^>(values.stringValues[i]);
@@ -93,7 +188,7 @@ namespace ModeliRpc
         // Fire!
         NewValuesArrived(this, args);
     }
-  
+
     void FrontendRpc::onLog(std::string instanceName, int status, std::string message)
     {
         auto args = gcnew LogEventArgs();
diff --git a/ModeliRpc/ModeliRpcCLR/ModeliRpc.h b/ModeliRpc/ModeliRpcCLR/ModeliRpc.h
index ce5677b..76fcddf 100644
--- a/ModeliRpc/ModeliRpcCLR/ModeliRpc.h
+++ b/ModeliRpc/ModeliRpcCLR/ModeliRpc.h
@@ -8,6 +8,7 @@
 #include <string>
 #include "NewValuesEventArgs.h"
 #include "LogEventArgs.h"
+#include "RpcChannelLink.h"
 
 using namespace System;
 
@@ -48,5 +49,27 @@ namespace ModeliRpc
         event EventHandler<NewValuesEventArgs^>^ NewValuesArrived;
         /// Gets fired when logging  messages arrive from the backend.
         event EventHandler<LogEventArgs^>^ LogArrived;
+        /// Play the simulation, returns a fmi2Status
+        int Play();
+        /// Fast forward the simulation, returns a fmi2Status
+        int PlayFast(double timeToPlay);
+        /// Pause the simulation without resetting it
+        void Pause();
+        /// Stop & reset the simulation, returns a fmi2Status
+        int Stop();
+        /// Add a fmu to the simulation, returns false on fail
+        bool AddFmu(String^ instanceName, array<Byte>^ fmuFileBuffer);
+        /// Remove a fmu to the simulation, returns false on fail
+        bool RemoveFmu(String^ instanceName);
+        /// Add a ChannelLink to the simulation, returns false on fail
+        bool AddChannelLink(RpcChannelLink^ channelLink);
+        /// Remove a ChannelLink from the simulation, returns false on fail
+        bool RemoveChannelLink(RpcChannelLink^ channelLink);
+        /// Set values in the simulation, retruns a fmi2Status
+        int SetValues(String^ instanceName,
+                      array<unsigned int>^ intVRs, array<int>^ intValues,
+                      array<unsigned int>^ realVRs, array<double>^ realValues,
+                      array<unsigned int>^ boolVRs, array<int>^ boolValues, // Fmi2Bool = int
+                      array<unsigned int>^ stringVRs, array<String^>^ stringValues);
     };
 }
\ No newline at end of file
diff --git a/ModeliRpc/ModeliRpcCLR/ModeliRpcCLR.vcxproj b/ModeliRpc/ModeliRpcCLR/ModeliRpcCLR.vcxproj
index 75e5902..3aff032 100644
--- a/ModeliRpc/ModeliRpcCLR/ModeliRpcCLR.vcxproj
+++ b/ModeliRpc/ModeliRpcCLR/ModeliRpcCLR.vcxproj
@@ -148,6 +148,7 @@
     <ClInclude Include="ModeliRpc.h" />
     <ClInclude Include="NewValuesEventArgs.h" />
     <ClInclude Include="resource.h" />
+    <ClInclude Include="RpcChannelLink.h" />
     <ClInclude Include="Stdafx.h" />
   </ItemGroup>
   <ItemGroup>
@@ -155,6 +156,7 @@
     <ClCompile Include="LogEventArgs.cpp" />
     <ClCompile Include="ModeliRpc.cpp" />
     <ClCompile Include="NewValuesEventArgs.cpp" />
+    <ClCompile Include="RpcChannelLink.cpp" />
     <ClCompile Include="Stdafx.cpp">
       <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
       <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
diff --git a/ModeliRpc/ModeliRpcCLR/ModeliRpcCLR.vcxproj.filters b/ModeliRpc/ModeliRpcCLR/ModeliRpcCLR.vcxproj.filters
index d71ba5a..9476f3c 100644
--- a/ModeliRpc/ModeliRpcCLR/ModeliRpcCLR.vcxproj.filters
+++ b/ModeliRpc/ModeliRpcCLR/ModeliRpcCLR.vcxproj.filters
@@ -30,6 +30,9 @@
     <ClInclude Include="LogEventArgs.h">
       <Filter>Header Files</Filter>
     </ClInclude>
+    <ClInclude Include="RpcChannelLink.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="AssemblyInfo.cpp">
@@ -47,6 +50,9 @@
     <ClCompile Include="LogEventArgs.cpp">
       <Filter>Source Files</Filter>
     </ClCompile>
+    <ClCompile Include="RpcChannelLink.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <Text Include="ReadMe.txt" />
diff --git a/ModeliRpc/ModeliRpcCLR/NewValuesEventArgs.h b/ModeliRpc/ModeliRpcCLR/NewValuesEventArgs.h
index cfe4f75..8472511 100644
--- a/ModeliRpc/ModeliRpcCLR/NewValuesEventArgs.h
+++ b/ModeliRpc/ModeliRpcCLR/NewValuesEventArgs.h
@@ -12,7 +12,7 @@ public:
     property array<unsigned int>^ RealValueRefs;
     property array<double>^ RealValues;
     property array<unsigned int>^ BoolValueRefs;
-    property array<bool>^ BoolValues;
+    property array<int>^ BoolValues;
     property array<unsigned int>^ StringValueRefs;
     property array<String^>^ StringValues;
 };
diff --git a/ModeliRpc/ModeliRpcCLR/RpcChannelLink.cpp b/ModeliRpc/ModeliRpcCLR/RpcChannelLink.cpp
new file mode 100644
index 0000000..3331ab8
--- /dev/null
+++ b/ModeliRpc/ModeliRpcCLR/RpcChannelLink.cpp
@@ -0,0 +1,7 @@
+#include "stdafx.h"
+#include "RpcChannelLink.h"
+
+
+RpcChannelLink::RpcChannelLink()
+{
+}
diff --git a/ModeliRpc/ModeliRpcCLR/RpcChannelLink.h b/ModeliRpc/ModeliRpcCLR/RpcChannelLink.h
new file mode 100644
index 0000000..a3354ea
--- /dev/null
+++ b/ModeliRpc/ModeliRpcCLR/RpcChannelLink.h
@@ -0,0 +1,14 @@
+#pragma once
+using namespace System;
+ref class RpcChannelLink
+{
+public:
+    RpcChannelLink();
+    property String^ MasterInstanceName;
+    property String^ SlaveInstanceName;
+    property unsigned int MasterValueRef;
+    property unsigned int SlaveValueRef;
+    property double Factor;
+    property double Offset;
+};
+
diff --git a/ModeliRpc/ModeliRpcNative/CapnConverter.cpp b/ModeliRpc/ModeliRpcNative/CapnConverter.cpp
index fa6ef93..4db9419 100644
--- a/ModeliRpc/ModeliRpcNative/CapnConverter.cpp
+++ b/ModeliRpc/ModeliRpcNative/CapnConverter.cpp
@@ -44,7 +44,7 @@ ValuesStruct CapnConverter::convertValues(Values::Reader reader)
     {
         boolVrs.push_back(element);
     }
-    std::vector<bool> boolValues;
+    std::vector<int32_t> boolValues;
     for (auto element : reader.getBoolValues())
     {
         boolValues.push_back(element);
diff --git a/ModeliRpc/ModeliRpcNative/IRpcFrontend.h b/ModeliRpc/ModeliRpcNative/IRpcFrontend.h
index adf9824..e859903 100644
--- a/ModeliRpc/ModeliRpcNative/IRpcFrontend.h
+++ b/ModeliRpc/ModeliRpcNative/IRpcFrontend.h
@@ -11,7 +11,7 @@ struct ValuesStruct
     std::vector<uint32_t> realValueRefs;
     std::vector<double> realValues;
     std::vector<uint32_t> boolValueRefs;
-    std::vector<bool> boolValues;
+    std::vector<int32_t> boolValues;
     std::vector<uint32_t> stringValueRefs;
     std::vector<std::string> stringValues;
 };
@@ -38,10 +38,12 @@ class IRpcFrontend
 {
 public:
     virtual void destroy() = 0;
-    virtual void connect(std::string address, int port) = 0;
+    virtual void connect(std::string address, unsigned int port) = 0;
     virtual void registerCallbacks(NewValuesCallback newValuesCallback, LogCallback logCallback) = 0;
     /// Returns fmi2Status
     virtual int play() = 0;
+    /// Returns fmi2Status
+    virtual int playFast(double timeToPlay) = 0;
     virtual void pause() = 0;
     /// Returns fmi2Status
     virtual int stop() = 0;
diff --git a/ModeliRpc/ModeliRpcNative/ModeliRpc.capnp.c++ b/ModeliRpc/ModeliRpcNative/ModeliRpc.capnp.c++
index d483ef7..7b9a27e 100644
--- a/ModeliRpc/ModeliRpcNative/ModeliRpc.capnp.c++
+++ b/ModeliRpc/ModeliRpcNative/ModeliRpc.capnp.c++
@@ -367,17 +367,17 @@ const ::capnp::_::RawSchema s_935c832cec2e072f = {
   0, 1, i_935c832cec2e072f, nullptr, nullptr, { &s_935c832cec2e072f, nullptr, nullptr, 0, 0, nullptr }
 };
 #endif  // !CAPNP_LITE
-static const ::capnp::_::AlignedData<18> b_92d58775d6d1f6fe = {
+static const ::capnp::_::AlignedData<35> b_92d58775d6d1f6fe = {
   {   0,   0,   0,   0,   5,   0,   6,   0,
     254, 246, 209, 214, 117, 135, 213, 146,
-     30,   0,   0,   0,   1,   0,   0,   0,
+     30,   0,   0,   0,   1,   0,   1,   0,
       0,   0,   0,   0,   0,   0,   0,   0,
       0,   0,   7,   0,   0,   0,   0,   0,
       0,   0,   0,   0,   0,   0,   0,   0,
      21,   0,   0,   0, 114,   1,   0,   0,
       0,   0,   0,   0,   0,   0,   0,   0,
       0,   0,   0,   0,   0,   0,   0,   0,
-      0,   0,   0,   0,   0,   0,   0,   0,
+     33,   0,   0,   0,  63,   0,   0,   0,
       0,   0,   0,   0,   0,   0,   0,   0,
       0,   0,   0,   0,   0,   0,   0,   0,
      77, 111, 100, 101, 108, 105,  82, 112,
@@ -385,13 +385,32 @@ static const ::capnp::_::AlignedData<18> b_92d58775d6d1f6fe = {
      77, 111, 100, 101, 108, 105,  66,  97,
      99, 107, 101, 110, 100,  46, 112, 108,
      97, 121,  70,  97, 115, 116,  36,  80,
-     97, 114,  97, 109, 115,   0,   0,   0, }
+     97, 114,  97, 109, 115,   0,   0,   0,
+      4,   0,   0,   0,   3,   0,   4,   0,
+      0,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,   1,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,   0,
+     13,   0,   0,   0,  90,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,   0,
+     12,   0,   0,   0,   3,   0,   1,   0,
+     24,   0,   0,   0,   2,   0,   1,   0,
+    116, 105, 109, 101,  84, 111,  80, 108,
+     97, 121,   0,   0,   0,   0,   0,   0,
+     11,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,   0,
+     11,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,   0, }
 };
 ::capnp::word const* const bp_92d58775d6d1f6fe = b_92d58775d6d1f6fe.words;
 #if !CAPNP_LITE
+static const uint16_t m_92d58775d6d1f6fe[] = {0};
+static const uint16_t i_92d58775d6d1f6fe[] = {0};
 const ::capnp::_::RawSchema s_92d58775d6d1f6fe = {
-  0x92d58775d6d1f6fe, b_92d58775d6d1f6fe.words, 18, nullptr, nullptr,
-  0, 0, nullptr, nullptr, nullptr, { &s_92d58775d6d1f6fe, nullptr, nullptr, 0, 0, nullptr }
+  0x92d58775d6d1f6fe, b_92d58775d6d1f6fe.words, 35, nullptr, m_92d58775d6d1f6fe,
+  0, 1, i_92d58775d6d1f6fe, nullptr, nullptr, { &s_92d58775d6d1f6fe, nullptr, nullptr, 0, 0, nullptr }
 };
 #endif  // !CAPNP_LITE
 static const ::capnp::_::AlignedData<34> b_dce78f15ea9b3d58 = {
@@ -1538,7 +1557,7 @@ static const ::capnp::_::AlignedData<194> b_a43101940a8689a5 = {
       0,   0,   0,   0,   0,   0,   0,   0,
       0,   0,   0,   0,   0,   0,   0,   0,
       0,   0,   0,   0,   3,   0,   1,   0,
-      1,   0,   0,   0,   0,   0,   0,   0,
+      4,   0,   0,   0,   0,   0,   0,   0,
       0,   0,   0,   0,   0,   0,   0,   0,
       0,   0,   0,   0,   0,   0,   0,   0,
       0,   0,   0,   0,   0,   0,   0,   0,
diff --git a/ModeliRpc/ModeliRpcNative/ModeliRpc.capnp.h b/ModeliRpc/ModeliRpcNative/ModeliRpc.capnp.h
index 5342c7c..1f36039 100644
--- a/ModeliRpc/ModeliRpcNative/ModeliRpc.capnp.h
+++ b/ModeliRpc/ModeliRpcNative/ModeliRpc.capnp.h
@@ -141,7 +141,7 @@ struct ModeliBackend::PlayFastParams {
   class Pipeline;
 
   struct _capnpPrivate {
-    CAPNP_DECLARE_STRUCT_HEADER(92d58775d6d1f6fe, 0, 0)
+    CAPNP_DECLARE_STRUCT_HEADER(92d58775d6d1f6fe, 1, 0)
     #if !CAPNP_LITE
     static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; }
     #endif  // !CAPNP_LITE
@@ -881,6 +881,8 @@ public:
   }
 #endif  // !CAPNP_LITE
 
+  inline double getTimeToPlay() const;
+
 private:
   ::capnp::_::StructReader _reader;
   template <typename, ::capnp::Kind>
@@ -909,6 +911,9 @@ public:
   inline ::kj::StringTree toString() const { return asReader().toString(); }
 #endif  // !CAPNP_LITE
 
+  inline double getTimeToPlay();
+  inline void setTimeToPlay(double value);
+
 private:
   ::capnp::_::StructBuilder _builder;
   template <typename, ::capnp::Kind>
@@ -2673,7 +2678,7 @@ public:
   inline  ::capnp::List< ::uint32_t>::Reader getBoolValueRefs() const;
 
   inline bool hasBoolValues() const;
-  inline  ::capnp::List<bool>::Reader getBoolValues() const;
+  inline  ::capnp::List< ::int32_t>::Reader getBoolValues() const;
 
   inline bool hasStringValueRefs() const;
   inline  ::capnp::List< ::uint32_t>::Reader getStringValueRefs() const;
@@ -2757,12 +2762,12 @@ public:
   inline ::capnp::Orphan< ::capnp::List< ::uint32_t>> disownBoolValueRefs();
 
   inline bool hasBoolValues();
-  inline  ::capnp::List<bool>::Builder getBoolValues();
-  inline void setBoolValues( ::capnp::List<bool>::Reader value);
-  inline void setBoolValues(::kj::ArrayPtr<const bool> value);
-  inline  ::capnp::List<bool>::Builder initBoolValues(unsigned int size);
-  inline void adoptBoolValues(::capnp::Orphan< ::capnp::List<bool>>&& value);
-  inline ::capnp::Orphan< ::capnp::List<bool>> disownBoolValues();
+  inline  ::capnp::List< ::int32_t>::Builder getBoolValues();
+  inline void setBoolValues( ::capnp::List< ::int32_t>::Reader value);
+  inline void setBoolValues(::kj::ArrayPtr<const  ::int32_t> value);
+  inline  ::capnp::List< ::int32_t>::Builder initBoolValues(unsigned int size);
+  inline void adoptBoolValues(::capnp::Orphan< ::capnp::List< ::int32_t>>&& value);
+  inline ::capnp::Orphan< ::capnp::List< ::int32_t>> disownBoolValues();
 
   inline bool hasStringValueRefs();
   inline  ::capnp::List< ::uint32_t>::Builder getStringValueRefs();
@@ -2970,6 +2975,20 @@ inline void ModeliBackend::PlayResults::Builder::setResult( ::int16_t value) {
       ::capnp::bounded<0>() * ::capnp::ELEMENTS, value);
 }
 
+inline double ModeliBackend::PlayFastParams::Reader::getTimeToPlay() const {
+  return _reader.getDataField<double>(
+      ::capnp::bounded<0>() * ::capnp::ELEMENTS);
+}
+
+inline double ModeliBackend::PlayFastParams::Builder::getTimeToPlay() {
+  return _builder.getDataField<double>(
+      ::capnp::bounded<0>() * ::capnp::ELEMENTS);
+}
+inline void ModeliBackend::PlayFastParams::Builder::setTimeToPlay(double value) {
+  _builder.setDataField<double>(
+      ::capnp::bounded<0>() * ::capnp::ELEMENTS, value);
+}
+
 inline  ::int16_t ModeliBackend::PlayFastResults::Reader::getResult() const {
   return _reader.getDataField< ::int16_t>(
       ::capnp::bounded<0>() * ::capnp::ELEMENTS);
@@ -3717,33 +3736,33 @@ inline bool Values::Builder::hasBoolValues() {
   return !_builder.getPointerField(
       ::capnp::bounded<6>() * ::capnp::POINTERS).isNull();
 }
-inline  ::capnp::List<bool>::Reader Values::Reader::getBoolValues() const {
-  return ::capnp::_::PointerHelpers< ::capnp::List<bool>>::get(_reader.getPointerField(
+inline  ::capnp::List< ::int32_t>::Reader Values::Reader::getBoolValues() const {
+  return ::capnp::_::PointerHelpers< ::capnp::List< ::int32_t>>::get(_reader.getPointerField(
       ::capnp::bounded<6>() * ::capnp::POINTERS));
 }
-inline  ::capnp::List<bool>::Builder Values::Builder::getBoolValues() {
-  return ::capnp::_::PointerHelpers< ::capnp::List<bool>>::get(_builder.getPointerField(
+inline  ::capnp::List< ::int32_t>::Builder Values::Builder::getBoolValues() {
+  return ::capnp::_::PointerHelpers< ::capnp::List< ::int32_t>>::get(_builder.getPointerField(
       ::capnp::bounded<6>() * ::capnp::POINTERS));
 }
-inline void Values::Builder::setBoolValues( ::capnp::List<bool>::Reader value) {
-  ::capnp::_::PointerHelpers< ::capnp::List<bool>>::set(_builder.getPointerField(
+inline void Values::Builder::setBoolValues( ::capnp::List< ::int32_t>::Reader value) {
+  ::capnp::_::PointerHelpers< ::capnp::List< ::int32_t>>::set(_builder.getPointerField(
       ::capnp::bounded<6>() * ::capnp::POINTERS), value);
 }
-inline void Values::Builder::setBoolValues(::kj::ArrayPtr<const bool> value) {
-  ::capnp::_::PointerHelpers< ::capnp::List<bool>>::set(_builder.getPointerField(
+inline void Values::Builder::setBoolValues(::kj::ArrayPtr<const  ::int32_t> value) {
+  ::capnp::_::PointerHelpers< ::capnp::List< ::int32_t>>::set(_builder.getPointerField(
       ::capnp::bounded<6>() * ::capnp::POINTERS), value);
 }
-inline  ::capnp::List<bool>::Builder Values::Builder::initBoolValues(unsigned int size) {
-  return ::capnp::_::PointerHelpers< ::capnp::List<bool>>::init(_builder.getPointerField(
+inline  ::capnp::List< ::int32_t>::Builder Values::Builder::initBoolValues(unsigned int size) {
+  return ::capnp::_::PointerHelpers< ::capnp::List< ::int32_t>>::init(_builder.getPointerField(
       ::capnp::bounded<6>() * ::capnp::POINTERS), size);
 }
 inline void Values::Builder::adoptBoolValues(
-    ::capnp::Orphan< ::capnp::List<bool>>&& value) {
-  ::capnp::_::PointerHelpers< ::capnp::List<bool>>::adopt(_builder.getPointerField(
+    ::capnp::Orphan< ::capnp::List< ::int32_t>>&& value) {
+  ::capnp::_::PointerHelpers< ::capnp::List< ::int32_t>>::adopt(_builder.getPointerField(
       ::capnp::bounded<6>() * ::capnp::POINTERS), kj::mv(value));
 }
-inline ::capnp::Orphan< ::capnp::List<bool>> Values::Builder::disownBoolValues() {
-  return ::capnp::_::PointerHelpers< ::capnp::List<bool>>::disown(_builder.getPointerField(
+inline ::capnp::Orphan< ::capnp::List< ::int32_t>> Values::Builder::disownBoolValues() {
+  return ::capnp::_::PointerHelpers< ::capnp::List< ::int32_t>>::disown(_builder.getPointerField(
       ::capnp::bounded<6>() * ::capnp::POINTERS));
 }
 
diff --git a/ModeliRpc/ModeliRpcNative/RpcFrontend.cpp b/ModeliRpc/ModeliRpcNative/RpcFrontend.cpp
index 0fc8546..f7d0021 100644
--- a/ModeliRpc/ModeliRpcNative/RpcFrontend.cpp
+++ b/ModeliRpc/ModeliRpcNative/RpcFrontend.cpp
@@ -18,7 +18,7 @@ void RpcFrontend::destroy()
     delete(this);
 }
 
-void RpcFrontend::connect(std::string address, int port)
+void RpcFrontend::connect(std::string address, unsigned int port)
 {
     _client = std::make_unique<capnp::EzRpcClient>(address, port);
 }
@@ -46,6 +46,18 @@ int RpcFrontend::play()
     return backend.playRequest().send().wait(_client->getWaitScope()).getResult();
 }
 
+int RpcFrontend::playFast(double timeToPlay)
+{
+    if (!_client)
+    {
+        return FMI2_ERROR;
+    }
+    auto backend = _client->getMain<ModeliBackend>();
+    auto request = backend.playFastRequest();
+    request.setTimeToPlay(timeToPlay);
+    request.send().wait(_client->getWaitScope()).getResult();
+}
+
 void RpcFrontend::pause()
 {
     if (!_client)
@@ -128,4 +140,4 @@ int RpcFrontend::setValues(ValuesStruct values)
     auto request = backend.setValuesRequest();
     request.setValues(CapnConverter::convertValues(values));
     return request.send().wait(_client->getWaitScope()).getResult();
-}
\ No newline at end of file
+}
diff --git a/ModeliRpc/ModeliRpcNative/RpcFrontend.h b/ModeliRpc/ModeliRpcNative/RpcFrontend.h
index e4e1e54..d81fe70 100644
--- a/ModeliRpc/ModeliRpcNative/RpcFrontend.h
+++ b/ModeliRpc/ModeliRpcNative/RpcFrontend.h
@@ -19,9 +19,10 @@ private:
 
     // Inherited via IModeliFrontend
     void destroy() override;
-    void connect(std::string address, int port) override;
+    void connect(std::string address, unsigned int port) override;
     void registerCallbacks(NewValuesCallback newValuesCallback, LogCallback logCallback) override;
     int play() override;
+    int playFast(double timeToPlay) override;
     void pause() override;
     int stop() override;
     bool addFmu(std::string instanceName, std::vector<unsigned char> fmuFile) override;
-- 
GitLab