From fa8dcbda41c7db503f999c670989b03ef3a2afbe Mon Sep 17 00:00:00 2001 From: Tim Uebelhoer <tim.uebelhoer@rwth-aachen.de> Date: Sun, 17 Dec 2017 13:58:23 +0100 Subject: [PATCH] Added events for callbacks --- ModeliRpc/ModeliRpcCLR/LogEventArgs.cpp | 7 ++ ModeliRpc/ModeliRpcCLR/LogEventArgs.h | 12 ++++ ModeliRpc/ModeliRpcCLR/ModeliRpc.cpp | 68 +++++++++++++++---- ModeliRpc/ModeliRpcCLR/ModeliRpc.h | 31 ++++++--- ModeliRpc/ModeliRpcCLR/ModeliRpcCLR.vcxproj | 11 ++- .../ModeliRpcCLR/ModeliRpcCLR.vcxproj.filters | 12 ++++ ModeliRpc/ModeliRpcCLR/NewValuesEventArgs.cpp | 7 ++ ModeliRpc/ModeliRpcCLR/NewValuesEventArgs.h | 19 ++++++ ModeliRpc/ModeliRpcNative/IRpcFrontend.h | 19 ++---- ModeliRpc/ModeliRpcNative/RpcFrontend.cpp | 18 ++--- ModeliRpc/ModeliRpcNative/RpcFrontend.h | 7 +- 11 files changed, 154 insertions(+), 57 deletions(-) create mode 100644 ModeliRpc/ModeliRpcCLR/LogEventArgs.cpp create mode 100644 ModeliRpc/ModeliRpcCLR/LogEventArgs.h create mode 100644 ModeliRpc/ModeliRpcCLR/NewValuesEventArgs.cpp create mode 100644 ModeliRpc/ModeliRpcCLR/NewValuesEventArgs.h diff --git a/ModeliRpc/ModeliRpcCLR/LogEventArgs.cpp b/ModeliRpc/ModeliRpcCLR/LogEventArgs.cpp new file mode 100644 index 0000000..176149a --- /dev/null +++ b/ModeliRpc/ModeliRpcCLR/LogEventArgs.cpp @@ -0,0 +1,7 @@ +#include "stdafx.h" +#include "LogEventArgs.h" + + +LogEventArgs::LogEventArgs() +{ +} diff --git a/ModeliRpc/ModeliRpcCLR/LogEventArgs.h b/ModeliRpc/ModeliRpcCLR/LogEventArgs.h new file mode 100644 index 0000000..1b53d33 --- /dev/null +++ b/ModeliRpc/ModeliRpcCLR/LogEventArgs.h @@ -0,0 +1,12 @@ +#pragma once +using namespace System; + +ref class LogEventArgs : public EventArgs +{ +public: + LogEventArgs(); + property String^ InstanceName; + property int Status; + property String^ Message; +}; + diff --git a/ModeliRpc/ModeliRpcCLR/ModeliRpc.cpp b/ModeliRpc/ModeliRpcCLR/ModeliRpc.cpp index c8329dd..883e035 100644 --- a/ModeliRpc/ModeliRpcCLR/ModeliRpc.cpp +++ b/ModeliRpc/ModeliRpcCLR/ModeliRpc.cpp @@ -5,13 +5,13 @@ using namespace msclr::interop; using namespace System::Runtime::InteropServices; -namespace ModeliRpcImpl +namespace ModeliRpc { - ModeliRpcImpl::ModeliRpcImpl(String^ address, int port) + FrontendRpc::FrontendRpc(String^ address, int port) { // Managed callbacks - _newValues = gcnew NewValuesDelegate(this, &ModeliRpcImpl::onNewValues); - _log = gcnew LogDelegate(this, &ModeliRpcImpl::onLog); + _newValues = gcnew NewValuesDelegate(this, &FrontendRpc::onNewValues); + _log = gcnew LogDelegate(this, &FrontendRpc::onLog); // Load the unmanged instance HINSTANCE _rpcDll = LoadLibrary("ModeliRpcNative.dll"); if (!_rpcDll) @@ -34,12 +34,12 @@ namespace ModeliRpcImpl } - ModeliRpcImpl::~ModeliRpcImpl() + FrontendRpc::~FrontendRpc() { // Call the finalizer - this->!ModeliRpcImpl(); + this->!FrontendRpc(); } - ModeliRpcImpl::!ModeliRpcImpl() + FrontendRpc::!FrontendRpc() { // Clear all unmanaged resources if (_rpcFrontend) @@ -52,16 +52,54 @@ namespace ModeliRpcImpl } } - void ModeliRpcImpl::onNewValues(double timestamp, ValuesStruct values) + void FrontendRpc::onNewValues(double timestamp, ValuesStruct values) { - throw gcnew System::NotImplementedException(); + // Copy data into the EventArgs + auto args = gcnew NewValuesEventArgs(); + args->Timestamp = timestamp; + args->InstanceName = marshal_as<String^> (values.instanceName); + // Int + args->IntegerValueRefs = gcnew array<unsigned 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()); + 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()); + 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()); + 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()); + 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()); + 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()); + for (int i = 0; i < args->StringValues->Length; i++) + { + args->StringValues[i] = marshal_as<String^>(values.stringValues[i]); + } + // Fire! + NewValuesArrived(this, args); } - - void ModeliRpcImpl::onLog(std::string instanceName, fmi2Status status, std::string message) + + void FrontendRpc::onLog(std::string instanceName, int status, std::string message) { - throw gcnew System::NotImplementedException(); + auto args = gcnew LogEventArgs(); + args->InstanceName = marshal_as<String^>(instanceName); + args->Status = status; + args->Message = marshal_as<String^>(message); + LogArrived(this, args); } - - - } \ No newline at end of file diff --git a/ModeliRpc/ModeliRpcCLR/ModeliRpc.h b/ModeliRpc/ModeliRpcCLR/ModeliRpc.h index c7a1f9d..ce5677b 100644 --- a/ModeliRpc/ModeliRpcCLR/ModeliRpc.h +++ b/ModeliRpc/ModeliRpcCLR/ModeliRpc.h @@ -1,10 +1,13 @@ #pragma once -#include"../ModeliRpcNative/IRpcFrontend.h" -#include <string> +// Faster build by not incuding all of windows #ifndef VC_EXTRALEAN #define VC_EXTRALEAN #endif -#include <windows.h> +#include <windows.h> // Always on top otherwise build fails (IServicProvider CLI issue) +#include "../ModeliRpcNative/IRpcFrontend.h" +#include <string> +#include "NewValuesEventArgs.h" +#include "LogEventArgs.h" using namespace System; @@ -15,29 +18,35 @@ namespace capnp class EzRpcClient; } -namespace ModeliRpcImpl +namespace ModeliRpc { - ref class ModeliRpcImpl + ref class FrontendRpc { private: // Unmanaged rpc interface - IRpcFrontend* _rpcFrontend; + IRpcFrontend * _rpcFrontend; // The native project exports a dll to hide the rpc framework HMODULE _rpcDll; // Delegates for callbacks delegate void NewValuesDelegate(double timestamp, ValuesStruct values); - delegate void LogDelegate(std::string instanceName, fmi2Status status, std::string message); + delegate void LogDelegate(std::string instanceName, int status, std::string message); NewValuesDelegate^ _newValues; LogDelegate^ _log; // Functions for the delegates void onNewValues(double timestamp, ValuesStruct values); - void onLog(std::string instanceName, fmi2Status status, std::string message); + void onLog(std::string instanceName, int status, std::string message); public: - ModeliRpcImpl(String^ address, int port); - ~ModeliRpcImpl(); // Destructor (IDisposable) - !ModeliRpcImpl(); // Finalizer + /// Create a new managed instance for RPCs to the ModeliBackend. + FrontendRpc(String^ address, int port); + ~FrontendRpc(); // Destructor (IDisposable) + !FrontendRpc(); // Finalizer + + /// Gets fired when new values arrived from the backend. + event EventHandler<NewValuesEventArgs^>^ NewValuesArrived; + /// Gets fired when logging messages arrive from the backend. + event EventHandler<LogEventArgs^>^ LogArrived; }; } \ No newline at end of file diff --git a/ModeliRpc/ModeliRpcCLR/ModeliRpcCLR.vcxproj b/ModeliRpc/ModeliRpcCLR/ModeliRpcCLR.vcxproj index ab51d94..75e5902 100644 --- a/ModeliRpc/ModeliRpcCLR/ModeliRpcCLR.vcxproj +++ b/ModeliRpc/ModeliRpcCLR/ModeliRpcCLR.vcxproj @@ -21,7 +21,7 @@ <PropertyGroup Label="Globals"> <VCProjectVersion>15.0</VCProjectVersion> <ProjectGuid>{A8187A41-1D24-438F-9B5D-0F7BF270130E}</ProjectGuid> - <TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion> + <TargetFrameworkVersion>v4.7</TargetFrameworkVersion> <Keyword>ManagedCProj</Keyword> <RootNamespace>ModeliRpcCLR</RootNamespace> <WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion> @@ -144,13 +144,17 @@ <Reference Include="System.Xml" /> </ItemGroup> <ItemGroup> + <ClInclude Include="LogEventArgs.h" /> <ClInclude Include="ModeliRpc.h" /> + <ClInclude Include="NewValuesEventArgs.h" /> <ClInclude Include="resource.h" /> <ClInclude Include="Stdafx.h" /> </ItemGroup> <ItemGroup> <ClCompile Include="AssemblyInfo.cpp" /> + <ClCompile Include="LogEventArgs.cpp" /> <ClCompile Include="ModeliRpc.cpp" /> + <ClCompile Include="NewValuesEventArgs.cpp" /> <ClCompile Include="Stdafx.cpp"> <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader> <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader> @@ -167,11 +171,6 @@ <ItemGroup> <Image Include="app.ico" /> </ItemGroup> - <ItemGroup> - <ProjectReference Include="..\ModeliRpcNative\ModeliRpcNative.vcxproj"> - <Project>{171ed599-c0c6-4342-8328-e7abe7f7feaa}</Project> - </ProjectReference> - </ItemGroup> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <ImportGroup Label="ExtensionTargets"> </ImportGroup> diff --git a/ModeliRpc/ModeliRpcCLR/ModeliRpcCLR.vcxproj.filters b/ModeliRpc/ModeliRpcCLR/ModeliRpcCLR.vcxproj.filters index 1a04e77..d71ba5a 100644 --- a/ModeliRpc/ModeliRpcCLR/ModeliRpcCLR.vcxproj.filters +++ b/ModeliRpc/ModeliRpcCLR/ModeliRpcCLR.vcxproj.filters @@ -24,6 +24,12 @@ <ClInclude Include="ModeliRpc.h"> <Filter>Header Files</Filter> </ClInclude> + <ClInclude Include="NewValuesEventArgs.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="LogEventArgs.h"> + <Filter>Header Files</Filter> + </ClInclude> </ItemGroup> <ItemGroup> <ClCompile Include="AssemblyInfo.cpp"> @@ -35,6 +41,12 @@ <ClCompile Include="ModeliRpc.cpp"> <Filter>Source Files</Filter> </ClCompile> + <ClCompile Include="NewValuesEventArgs.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="LogEventArgs.cpp"> + <Filter>Source Files</Filter> + </ClCompile> </ItemGroup> <ItemGroup> <Text Include="ReadMe.txt" /> diff --git a/ModeliRpc/ModeliRpcCLR/NewValuesEventArgs.cpp b/ModeliRpc/ModeliRpcCLR/NewValuesEventArgs.cpp new file mode 100644 index 0000000..4f59c56 --- /dev/null +++ b/ModeliRpc/ModeliRpcCLR/NewValuesEventArgs.cpp @@ -0,0 +1,7 @@ +#include "stdafx.h" +#include "NewValuesEventArgs.h" + + +NewValuesEventArgs::NewValuesEventArgs() +{ +} diff --git a/ModeliRpc/ModeliRpcCLR/NewValuesEventArgs.h b/ModeliRpc/ModeliRpcCLR/NewValuesEventArgs.h new file mode 100644 index 0000000..cfe4f75 --- /dev/null +++ b/ModeliRpc/ModeliRpcCLR/NewValuesEventArgs.h @@ -0,0 +1,19 @@ +#pragma once +using namespace System; + +ref class NewValuesEventArgs: EventArgs +{ +public: + NewValuesEventArgs(); + property double Timestamp; + property String^ InstanceName; + property array<unsigned int>^ IntegerValueRefs; + property array<int>^ IntegerValues; + property array<unsigned int>^ RealValueRefs; + property array<double>^ RealValues; + property array<unsigned int>^ BoolValueRefs; + property array<bool>^ BoolValues; + property array<unsigned int>^ StringValueRefs; + property array<String^>^ StringValues; +}; + diff --git a/ModeliRpc/ModeliRpcNative/IRpcFrontend.h b/ModeliRpc/ModeliRpcNative/IRpcFrontend.h index df53ffd..adf9824 100644 --- a/ModeliRpc/ModeliRpcNative/IRpcFrontend.h +++ b/ModeliRpc/ModeliRpcNative/IRpcFrontend.h @@ -2,16 +2,6 @@ #include <string> #include <vector> -enum fmi2Status -{ - fmi2OK, - fmi2Warning, - fmi2Discard, - fmi2Error, - fmi2Fatal, - fmi2Pending -}; - // Struct that will be used for the NewValues callback struct ValuesStruct { @@ -50,14 +40,17 @@ public: virtual void destroy() = 0; virtual void connect(std::string address, int port) = 0; virtual void registerCallbacks(NewValuesCallback newValuesCallback, LogCallback logCallback) = 0; - virtual fmi2Status play() = 0; + /// Returns fmi2Status + virtual int play() = 0; virtual void pause() = 0; - virtual fmi2Status stop() = 0; + /// Returns fmi2Status + virtual int stop() = 0; virtual bool addFmu(std::string instanceName, std::vector<unsigned char> fmuFile) = 0; virtual bool removeFmu(std::string instanceName) = 0; virtual bool addChannelLink(ChannelLink channelLink) = 0; virtual bool removeChannelink(ChannelLink channelLink) = 0; - virtual fmi2Status setValues(ValuesStruct values) = 0; + /// Returns fmi2Status + virtual int setValues(ValuesStruct values) = 0; }; // Factory signature extern "C" __declspec(dllexport) IRpcFrontend* createRpcFrontend(); \ No newline at end of file diff --git a/ModeliRpc/ModeliRpcNative/RpcFrontend.cpp b/ModeliRpc/ModeliRpcNative/RpcFrontend.cpp index 37397e6..0fc8546 100644 --- a/ModeliRpc/ModeliRpcNative/RpcFrontend.cpp +++ b/ModeliRpc/ModeliRpcNative/RpcFrontend.cpp @@ -36,14 +36,14 @@ void RpcFrontend::registerCallbacks(NewValuesCallback newValuesCallback, LogCall } -fmi2Status RpcFrontend::play() +int RpcFrontend::play() { if (!_client) { - return fmi2Error; + return FMI2_ERROR; } auto backend = _client->getMain<ModeliBackend>(); - return static_cast<fmi2Status>(backend.playRequest().send().wait(_client->getWaitScope()).getResult()); + return backend.playRequest().send().wait(_client->getWaitScope()).getResult(); } void RpcFrontend::pause() @@ -56,14 +56,14 @@ void RpcFrontend::pause() backend.pauseRequest().send().wait(_client->getWaitScope()); } -fmi2Status RpcFrontend::stop() +int RpcFrontend::stop() { if (!_client) { - return fmi2Error; + return FMI2_ERROR; } auto backend = _client->getMain<ModeliBackend>(); - return static_cast<fmi2Status>(backend.stopRequest().send().wait(_client->getWaitScope()).getResult()); + return backend.stopRequest().send().wait(_client->getWaitScope()).getResult(); } bool RpcFrontend::addFmu(std::string instanceName, std::vector<unsigned char> fmuFile) @@ -117,15 +117,15 @@ bool RpcFrontend::removeChannelink(ChannelLink channelLink) return request.send().wait(_client->getWaitScope()).getResult(); } -fmi2Status RpcFrontend::setValues(ValuesStruct values) +int RpcFrontend::setValues(ValuesStruct values) { if (!_client) { - return fmi2Error; + return FMI2_ERROR; } // Send request auto backend = _client->getMain<ModeliBackend>(); auto request = backend.setValuesRequest(); request.setValues(CapnConverter::convertValues(values)); - return static_cast<fmi2Status>(request.send().wait(_client->getWaitScope()).getResult()); + 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 e44ecd1..e4e1e54 100644 --- a/ModeliRpc/ModeliRpcNative/RpcFrontend.h +++ b/ModeliRpc/ModeliRpcNative/RpcFrontend.h @@ -15,19 +15,20 @@ public: ~RpcFrontend(); private: std::unique_ptr<capnp::EzRpcClient> _client; + const int FMI2_ERROR = 3; // Inherited via IModeliFrontend void destroy() override; void connect(std::string address, int port) override; void registerCallbacks(NewValuesCallback newValuesCallback, LogCallback logCallback) override; - fmi2Status play() override; + int play() override; void pause() override; - fmi2Status stop() override; + int stop() override; bool addFmu(std::string instanceName, std::vector<unsigned char> fmuFile) override; bool removeFmu(std::string instanceName) override; bool addChannelLink(ChannelLink channelLink) override; bool removeChannelink(ChannelLink channelLink) override; - fmi2Status setValues(ValuesStruct values) override; + int setValues(ValuesStruct values) override; }; /// Factory method that returns an implementation of IRpcFrontend. -- GitLab