From db4e95639eb7a274f433134fd3888e13eb2afbd9 Mon Sep 17 00:00:00 2001 From: Tim Uebelhoer <tim.uebelhoer@rwth-aachen.de> Date: Tue, 2 Jan 2018 15:25:45 +0100 Subject: [PATCH] Grpc now with generated files from the vcpkg. The waitable_queue is unit tested. --- BackendTests/BackendTests.vcxproj | 24 +++-- BackendTests/BackendTests.vcxproj.filters | 3 + BackendTests/SimulatorTest.cpp | 2 +- BackendTests/WaitableQueueTest.cpp | 53 +++++++++++ CreatedGrpc/CreatedGrpc.vcxitems | 8 +- {Network => CreatedGrpc}/ModeliRpc.grpc.pb.cc | 0 {Network => CreatedGrpc}/ModeliRpc.grpc.pb.h | 0 {Network => CreatedGrpc}/ModeliRpc.pb.cc | 0 {Network => CreatedGrpc}/ModeliRpc.pb.h | 0 MC_BackEnd.sln | 10 +- MC_Backend_Linux/MC_Backend_Linux.vcxproj | 14 +-- MC_Backend_Win/MC_Backend_Win.vcxproj | 10 +- Main/main.cpp | 4 +- Network/ModeliGrpcServer.cpp | 52 ++--------- Network/ModeliGrpcServer.h | 24 ++--- Network/Network.vcxitems | 4 - Network/Network.vcxitems.filters | 12 --- Simulation/{FMUEngine.cpp => Simulation.cpp} | 91 ++++++++++--------- Simulation/{FmuEngine.hpp => Simulation.hpp} | 6 +- Simulation/Simulation.vcxitems | 4 +- Simulation/Simulation.vcxitems.filters | 6 +- UtilityClasses/UtilityClasses.vcxitems | 20 ++++ UtilityClasses/WaitableQueue.h | 79 ++++++++++++++++ 23 files changed, 272 insertions(+), 154 deletions(-) create mode 100644 BackendTests/WaitableQueueTest.cpp rename {Network => CreatedGrpc}/ModeliRpc.grpc.pb.cc (100%) rename {Network => CreatedGrpc}/ModeliRpc.grpc.pb.h (100%) rename {Network => CreatedGrpc}/ModeliRpc.pb.cc (100%) rename {Network => CreatedGrpc}/ModeliRpc.pb.h (100%) rename Simulation/{FMUEngine.cpp => Simulation.cpp} (79%) rename Simulation/{FmuEngine.hpp => Simulation.hpp} (98%) create mode 100644 UtilityClasses/UtilityClasses.vcxitems create mode 100644 UtilityClasses/WaitableQueue.h diff --git a/BackendTests/BackendTests.vcxproj b/BackendTests/BackendTests.vcxproj index ee75574..dd7738f 100644 --- a/BackendTests/BackendTests.vcxproj +++ b/BackendTests/BackendTests.vcxproj @@ -63,9 +63,8 @@ <ImportGroup Label="Shared"> <Import Project="..\Simulation\Simulation.vcxitems" Label="Shared" /> <Import Project="..\Files\Files.vcxitems" Label="Shared" /> - <Import Project="..\Main\Main.vcxitems" Label="Shared" /> <Import Project="..\FMU-Core\NativeFmuShared\NativeFmuShared.vcxitems" Label="Shared" /> - <Import Project="..\Network\Network.vcxitems" Label="Shared" /> + <Import Project="..\UtilityClasses\UtilityClasses.vcxitems" Label="Shared" /> </ImportGroup> <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> @@ -99,17 +98,17 @@ <Optimization>MaxSpeed</Optimization> <FunctionLevelLinking>true</FunctionLevelLinking> <IntrinsicFunctions>true</IntrinsicFunctions> - <AdditionalIncludeDirectories>../AdditionalIncludes/flatbuffers;../AdditionalIncludes/MC_Protocol;C:\boost_1_65_1;$(VCInstallDir)UnitTest\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <AdditionalIncludeDirectories>$(VCInstallDir)UnitTest\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> <UseFullPaths>true</UseFullPaths> - <AdditionalOptions>-DBOOST_DATE_TIME_NO_LIB -DBOOST_REGEX_NO_LIB %(AdditionalOptions)</AdditionalOptions> + <AdditionalOptions>-DBOOST_DATE_TIME_NO_LIB -DBOOST_REGEX_NO_LIB -D_WIN32_WINNT=0x0A00 %(AdditionalOptions)</AdditionalOptions> </ClCompile> <Link> <SubSystem>Windows</SubSystem> <EnableCOMDATFolding>true</EnableCOMDATFolding> <OptimizeReferences>true</OptimizeReferences> <AdditionalLibraryDirectories>C:\boost_1_65_1\stage\lib;$(VCInstallDir)UnitTest\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> - <AdditionalDependencies>Winmm.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies> + <AdditionalDependencies>Winmm.lib;%(AdditionalDependencies)</AdditionalDependencies> </Link> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> @@ -117,13 +116,15 @@ <PrecompiledHeader>NotUsing</PrecompiledHeader> <WarningLevel>Level3</WarningLevel> <Optimization>Disabled</Optimization> - <AdditionalIncludeDirectories>../AdditionalIncludes/flatbuffers;../AdditionalIncludes/MC_Protocol;C:\boost_1_65_1;$(VCInstallDir)UnitTest\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <AdditionalIncludeDirectories>$(VCInstallDir)UnitTest\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>WIN32;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> <UseFullPaths>true</UseFullPaths> + <AdditionalOptions>-DBOOST_DATE_TIME_NO_LIB -DBOOST_REGEX_NO_LIB -D_WIN32_WINNT=0x0A00 %(AdditionalOptions)</AdditionalOptions> </ClCompile> <Link> <SubSystem>Windows</SubSystem> <AdditionalLibraryDirectories>$(VCInstallDir)UnitTest\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> + <AdditionalDependencies>Winmm.lib;%(AdditionalDependencies)</AdditionalDependencies> </Link> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> @@ -131,15 +132,15 @@ <PrecompiledHeader>NotUsing</PrecompiledHeader> <WarningLevel>Level3</WarningLevel> <Optimization>Disabled</Optimization> - <AdditionalIncludeDirectories>../AdditionalIncludes/flatbuffers;../AdditionalIncludes/MC_Protocol;C:\boost_1_65_1;$(VCInstallDir)UnitTest\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <AdditionalIncludeDirectories>$(VCInstallDir)UnitTest\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> <UseFullPaths>true</UseFullPaths> - <AdditionalOptions>-DBOOST_DATE_TIME_NO_LIB -DBOOST_REGEX_NO_LIB %(AdditionalOptions)</AdditionalOptions> + <AdditionalOptions>-DBOOST_DATE_TIME_NO_LIB -DBOOST_REGEX_NO_LIB -D_WIN32_WINNT=0x0A00 %(AdditionalOptions)</AdditionalOptions> </ClCompile> <Link> <SubSystem>Windows</SubSystem> <AdditionalLibraryDirectories>C:\boost_1_65_1\stage\lib;$(VCInstallDir)UnitTest\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> - <AdditionalDependencies>Winmm.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies> + <AdditionalDependencies>Winmm.lib;%(AdditionalDependencies)</AdditionalDependencies> </Link> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> @@ -149,15 +150,17 @@ <Optimization>MaxSpeed</Optimization> <FunctionLevelLinking>true</FunctionLevelLinking> <IntrinsicFunctions>true</IntrinsicFunctions> - <AdditionalIncludeDirectories>../AdditionalIncludes/flatbuffers;../AdditionalIncludes/MC_Protocol;C:\boost_1_65_1;$(VCInstallDir)UnitTest\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <AdditionalIncludeDirectories>$(VCInstallDir)UnitTest\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>WIN32;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> <UseFullPaths>true</UseFullPaths> + <AdditionalOptions>-DBOOST_DATE_TIME_NO_LIB -DBOOST_REGEX_NO_LIB -D_WIN32_WINNT=0x0A00 %(AdditionalOptions)</AdditionalOptions> </ClCompile> <Link> <SubSystem>Windows</SubSystem> <EnableCOMDATFolding>true</EnableCOMDATFolding> <OptimizeReferences>true</OptimizeReferences> <AdditionalLibraryDirectories>$(VCInstallDir)UnitTest\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> + <AdditionalDependencies>Winmm.lib;%(AdditionalDependencies)</AdditionalDependencies> </Link> </ItemDefinitionGroup> <ItemGroup> @@ -174,6 +177,7 @@ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader> </ClCompile> <ClCompile Include="SimulatorTest.cpp" /> + <ClCompile Include="WaitableQueueTest.cpp" /> </ItemGroup> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <ImportGroup Label="ExtensionTargets"> diff --git a/BackendTests/BackendTests.vcxproj.filters b/BackendTests/BackendTests.vcxproj.filters index daf54bf..de4ac7c 100644 --- a/BackendTests/BackendTests.vcxproj.filters +++ b/BackendTests/BackendTests.vcxproj.filters @@ -35,5 +35,8 @@ <ClCompile Include="EngineObserver.cpp"> <Filter>Quelldateien</Filter> </ClCompile> + <ClCompile Include="WaitableQueueTest.cpp"> + <Filter>Quelldateien</Filter> + </ClCompile> </ItemGroup> </Project> \ No newline at end of file diff --git a/BackendTests/SimulatorTest.cpp b/BackendTests/SimulatorTest.cpp index 9cecf3f..07c631e 100644 --- a/BackendTests/SimulatorTest.cpp +++ b/BackendTests/SimulatorTest.cpp @@ -15,7 +15,7 @@ namespace BackendTests TEST_METHOD(TestFmuEngine) { // Basic setup - FmuEngine fmuEngine("TestID"); + Simulation fmuEngine("TestID"); auto observer = std::make_shared<EngineObserver>(); // Add & remove observer fmuEngine.AddObserver(observer); diff --git a/BackendTests/WaitableQueueTest.cpp b/BackendTests/WaitableQueueTest.cpp new file mode 100644 index 0000000..9c6519f --- /dev/null +++ b/BackendTests/WaitableQueueTest.cpp @@ -0,0 +1,53 @@ +#include "stdafx.h" +#include "CppUnitTest.h" +#include "WaitableQueue.h" + +using namespace Microsoft::VisualStudio::CppUnitTestFramework; + +namespace BackendTests +{ + TEST_CLASS(WaitableQueueTest) + { + private: + Utility::WaitableQueue<int> _queue; + public: + + TEST_METHOD_INITIALIZE(TestWaitableQueueInitialize) + { + // Boost none is expected + Assert::IsTrue(!_queue.pop()); + } + + void produce(int n) + { + for (int i = 0; i < n; i++) + { + _queue.push(i); + } + } + + void consume(int n) + { + for (int i = 0; i < n; i++) + { + Assert::AreEqual(i, _queue.wait_and_pop()); + } + } + + TEST_METHOD(TestWaitableQueuePush_n_Pop) + { + const int COUNT = 10000; + // Produce one more than consuming + std::thread consumer(std::bind(&WaitableQueueTest::consume, this, COUNT)); + std::thread producer(std::bind(&WaitableQueueTest::produce, this, COUNT + 1)); + // Wait for the threads + producer.join(); + consumer.join(); + // One more availabe to test regular pop + Assert::AreEqual(COUNT, _queue.pop().get()); + // Nothing available + Assert::IsTrue(!_queue.pop()); + } + + }; +} \ No newline at end of file diff --git a/CreatedGrpc/CreatedGrpc.vcxitems b/CreatedGrpc/CreatedGrpc.vcxitems index e8b0d21..2a02ca3 100644 --- a/CreatedGrpc/CreatedGrpc.vcxitems +++ b/CreatedGrpc/CreatedGrpc.vcxitems @@ -14,11 +14,11 @@ <ProjectCapability Include="SourceItemsFromImports" /> </ItemGroup> <ItemGroup> - <ClCompile Include="$(MSBuildThisFileDirectory)..\ModeliProtocol\ModeliRpc_Cpp\ModeliRpc.grpc.pb.cc" /> - <ClCompile Include="$(MSBuildThisFileDirectory)..\ModeliProtocol\ModeliRpc_Cpp\ModeliRpc.pb.cc" /> + <ClInclude Include="$(MSBuildThisFileDirectory)ModeliRpc.grpc.pb.h" /> + <ClInclude Include="$(MSBuildThisFileDirectory)ModeliRpc.pb.h" /> </ItemGroup> <ItemGroup> - <ClInclude Include="$(MSBuildThisFileDirectory)..\ModeliProtocol\ModeliRpc_Cpp\ModeliRpc.grpc.pb.h" /> - <ClInclude Include="$(MSBuildThisFileDirectory)..\ModeliProtocol\ModeliRpc_Cpp\ModeliRpc.pb.h" /> + <ClCompile Include="$(MSBuildThisFileDirectory)ModeliRpc.grpc.pb.cc" /> + <ClCompile Include="$(MSBuildThisFileDirectory)ModeliRpc.pb.cc" /> </ItemGroup> </Project> \ No newline at end of file diff --git a/Network/ModeliRpc.grpc.pb.cc b/CreatedGrpc/ModeliRpc.grpc.pb.cc similarity index 100% rename from Network/ModeliRpc.grpc.pb.cc rename to CreatedGrpc/ModeliRpc.grpc.pb.cc diff --git a/Network/ModeliRpc.grpc.pb.h b/CreatedGrpc/ModeliRpc.grpc.pb.h similarity index 100% rename from Network/ModeliRpc.grpc.pb.h rename to CreatedGrpc/ModeliRpc.grpc.pb.h diff --git a/Network/ModeliRpc.pb.cc b/CreatedGrpc/ModeliRpc.pb.cc similarity index 100% rename from Network/ModeliRpc.pb.cc rename to CreatedGrpc/ModeliRpc.pb.cc diff --git a/Network/ModeliRpc.pb.h b/CreatedGrpc/ModeliRpc.pb.h similarity index 100% rename from Network/ModeliRpc.pb.h rename to CreatedGrpc/ModeliRpc.pb.h diff --git a/MC_BackEnd.sln b/MC_BackEnd.sln index a8dee85..94bdcbd 100644 --- a/MC_BackEnd.sln +++ b/MC_BackEnd.sln @@ -22,30 +22,36 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BackendTests", "BackendTest EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CreatedGrpc", "CreatedGrpc\CreatedGrpc.vcxitems", "{9C78546C-04B5-45BB-99C4-9FFBAF846BFE}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Utility", "UtilityClasses\UtilityClasses.vcxitems", "{FD95EBAC-8E33-43D3-88BA-04A2B02D7D9E}" +EndProject Global GlobalSection(SharedMSBuildProjectFiles) = preSolution Network\Network.vcxitems*{059b87b7-3153-4b08-b4db-12f671328ebb}*SharedItemsImports = 9 Files\Files.vcxitems*{500f1104-28c6-4be4-a180-8028843972ac}*SharedItemsImports = 4 FMU-Core\NativeFmuShared\NativeFmuShared.vcxitems*{500f1104-28c6-4be4-a180-8028843972ac}*SharedItemsImports = 4 - Main\Main.vcxitems*{500f1104-28c6-4be4-a180-8028843972ac}*SharedItemsImports = 4 - Network\Network.vcxitems*{500f1104-28c6-4be4-a180-8028843972ac}*SharedItemsImports = 4 Simulation\Simulation.vcxitems*{500f1104-28c6-4be4-a180-8028843972ac}*SharedItemsImports = 4 + UtilityClasses\UtilityClasses.vcxitems*{500f1104-28c6-4be4-a180-8028843972ac}*SharedItemsImports = 4 Files\Files.vcxitems*{600c8d4e-39a2-40dd-b779-ac823cd2f5cc}*SharedItemsImports = 9 + CreatedGrpc\CreatedGrpc.vcxitems*{661905ce-1efd-4d2b-8cc8-0a8bafb5242f}*SharedItemsImports = 4 Files\Files.vcxitems*{661905ce-1efd-4d2b-8cc8-0a8bafb5242f}*SharedItemsImports = 4 FMU-Core\NativeFmuShared\NativeFmuShared.vcxitems*{661905ce-1efd-4d2b-8cc8-0a8bafb5242f}*SharedItemsImports = 4 Main\Main.vcxitems*{661905ce-1efd-4d2b-8cc8-0a8bafb5242f}*SharedItemsImports = 4 Network\Network.vcxitems*{661905ce-1efd-4d2b-8cc8-0a8bafb5242f}*SharedItemsImports = 4 Simulation\Simulation.vcxitems*{661905ce-1efd-4d2b-8cc8-0a8bafb5242f}*SharedItemsImports = 4 + UtilityClasses\UtilityClasses.vcxitems*{661905ce-1efd-4d2b-8cc8-0a8bafb5242f}*SharedItemsImports = 4 Simulation\Simulation.vcxitems*{8510328c-8540-419b-96d9-1e5ff396366f}*SharedItemsImports = 9 + CreatedGrpc\CreatedGrpc.vcxitems*{87f7a408-7c05-47a8-a1d7-4a53ca350666}*SharedItemsImports = 4 Files\Files.vcxitems*{87f7a408-7c05-47a8-a1d7-4a53ca350666}*SharedItemsImports = 4 FMU-Core\NativeFmuShared\NativeFmuShared.vcxitems*{87f7a408-7c05-47a8-a1d7-4a53ca350666}*SharedItemsImports = 4 Main\Main.vcxitems*{87f7a408-7c05-47a8-a1d7-4a53ca350666}*SharedItemsImports = 4 Network\Network.vcxitems*{87f7a408-7c05-47a8-a1d7-4a53ca350666}*SharedItemsImports = 4 Simulation\Simulation.vcxitems*{87f7a408-7c05-47a8-a1d7-4a53ca350666}*SharedItemsImports = 4 + UtilityClasses\UtilityClasses.vcxitems*{87f7a408-7c05-47a8-a1d7-4a53ca350666}*SharedItemsImports = 4 CreatedGrpc\CreatedGrpc.vcxitems*{9c78546c-04b5-45bb-99c4-9ffbaf846bfe}*SharedItemsImports = 9 FMU-Core\NativeFmuShared\NativeFmuShared.vcxitems*{b23eb13a-9d85-4f36-8327-543fa7b6a01e}*SharedItemsImports = 9 Main\Main.vcxitems*{de14bb19-25d6-4ec9-8878-d5fc8ec737bb}*SharedItemsImports = 9 FMU-Core\NativeFmuShared\NativeFmuShared.vcxitems*{f31eeb13-5399-4e96-af1f-b0bcf3119b5f}*SharedItemsImports = 4 + UtilityClasses\UtilityClasses.vcxitems*{fd95ebac-8e33-43d3-88ba-04a2b02d7d9e}*SharedItemsImports = 9 EndGlobalSection GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|ARM = Debug|ARM diff --git a/MC_Backend_Linux/MC_Backend_Linux.vcxproj b/MC_Backend_Linux/MC_Backend_Linux.vcxproj index 865f522..b2d681c 100644 --- a/MC_Backend_Linux/MC_Backend_Linux.vcxproj +++ b/MC_Backend_Linux/MC_Backend_Linux.vcxproj @@ -69,6 +69,8 @@ <Import Project="..\Network\Network.vcxitems" Label="Shared" /> <Import Project="..\Simulation\Simulation.vcxitems" Label="Shared" /> <Import Project="..\Main\Main.vcxitems" Label="Shared" /> + <Import Project="..\UtilityClasses\UtilityClasses.vcxitems" Label="Shared" /> + <Import Project="..\CreatedGrpc\CreatedGrpc.vcxitems" Label="Shared" /> </ImportGroup> <ImportGroup Label="PropertySheets" /> <PropertyGroup Label="UserMacros" /> @@ -105,7 +107,7 @@ <SharedLibrarySearchPath>%(SharedLibrarySearchPath)</SharedLibrarySearchPath> </Link> <ClCompile> - <AdditionalIncludeDirectories>../FMU-Core/NativeFmuShared;../Network;../Files;../Simulation;../AdditionalIncludes/flatbuffers;../AdditionalIncludes/MC_Protocol;</AdditionalIncludeDirectories> + <AdditionalIncludeDirectories>../FMU-Core/NativeFmuShared;../Network;../Files;../Simulation</AdditionalIncludeDirectories> <AdditionalOptions>-DBOOST_DATE_TIME_NO_LIB -DBOOST_REGEX_NO_LIB </AdditionalOptions> <CppLanguageStandard>c++1y</CppLanguageStandard> </ClCompile> @@ -119,7 +121,7 @@ <SharedLibrarySearchPath>%(SharedLibrarySearchPath)</SharedLibrarySearchPath> </Link> <ClCompile> - <AdditionalIncludeDirectories>../FMU-Core/NativeFmuShared;../Network;../Files;../Simulation;../AdditionalIncludes/flatbuffers;../AdditionalIncludes/MC_Protocol;</AdditionalIncludeDirectories> + <AdditionalIncludeDirectories>../FMU-Core/NativeFmuShared;../Network;../Files;../Simulation</AdditionalIncludeDirectories> <AdditionalOptions>-DBOOST_DATE_TIME_NO_LIB -DBOOST_REGEX_NO_LIB </AdditionalOptions> <CppLanguageStandard>c++1y</CppLanguageStandard> </ClCompile> @@ -133,7 +135,7 @@ <SharedLibrarySearchPath>%(SharedLibrarySearchPath)</SharedLibrarySearchPath> </Link> <ClCompile> - <AdditionalIncludeDirectories>../FMU-Core/NativeFmuShared;../Network;../Files;../Simulation;../AdditionalIncludes/flatbuffers;../AdditionalIncludes/MC_Protocol;</AdditionalIncludeDirectories> + <AdditionalIncludeDirectories>../FMU-Core/NativeFmuShared;../Network;../Files;../Simulation</AdditionalIncludeDirectories> <AdditionalOptions>-DBOOST_DATE_TIME_NO_LIB -DBOOST_REGEX_NO_LIB</AdditionalOptions> <CppLanguageStandard>c++1y</CppLanguageStandard> </ClCompile> @@ -151,7 +153,7 @@ <SharedLibrarySearchPath>%(SharedLibrarySearchPath)</SharedLibrarySearchPath> </Link> <ClCompile> - <AdditionalIncludeDirectories>../FMU-Core/NativeFmuShared;../Network;../Files;../Simulation;../AdditionalIncludes/flatbuffers;../AdditionalIncludes/MC_Protocol;</AdditionalIncludeDirectories> + <AdditionalIncludeDirectories>../FMU-Core/NativeFmuShared;../Network;../Files;../Simulation</AdditionalIncludeDirectories> <AdditionalOptions>-DBOOST_DATE_TIME_NO_LIB -DBOOST_REGEX_NO_LIB</AdditionalOptions> <CppLanguageStandard>c++1y</CppLanguageStandard> </ClCompile> @@ -169,7 +171,7 @@ <SharedLibrarySearchPath>%(SharedLibrarySearchPath)</SharedLibrarySearchPath> </Link> <ClCompile> - <AdditionalIncludeDirectories>../FMU-Core/NativeFmuShared;../Network;../Files;../Simulation;../AdditionalIncludes/flatbuffers;../AdditionalIncludes/MC_Protocol;</AdditionalIncludeDirectories> + <AdditionalIncludeDirectories>../FMU-Core/NativeFmuShared;../Network;../Files;../Simulation</AdditionalIncludeDirectories> <AdditionalOptions>-DBOOST_DATE_TIME_NO_LIB -DBOOST_REGEX_NO_LIB</AdditionalOptions> <CppLanguageStandard>c++1y</CppLanguageStandard> </ClCompile> @@ -183,7 +185,7 @@ <SharedLibrarySearchPath>%(SharedLibrarySearchPath)</SharedLibrarySearchPath> </Link> <ClCompile> - <AdditionalIncludeDirectories>../FMU-Core/NativeFmuShared;../Network;../Files;../Simulation;../AdditionalIncludes/flatbuffers;../AdditionalIncludes/MC_Protocol;</AdditionalIncludeDirectories> + <AdditionalIncludeDirectories>../FMU-Core/NativeFmuShared;../Network;../Files;../Simulation</AdditionalIncludeDirectories> <AdditionalOptions>-DBOOST_DATE_TIME_NO_LIB -DBOOST_REGEX_NO_LIB</AdditionalOptions> <CppLanguageStandard>c++1y</CppLanguageStandard> </ClCompile> diff --git a/MC_Backend_Win/MC_Backend_Win.vcxproj b/MC_Backend_Win/MC_Backend_Win.vcxproj index 9e62d32..f2fe9b3 100644 --- a/MC_Backend_Win/MC_Backend_Win.vcxproj +++ b/MC_Backend_Win/MC_Backend_Win.vcxproj @@ -61,6 +61,8 @@ <Import Project="..\Network\Network.vcxitems" Label="Shared" /> <Import Project="..\Simulation\Simulation.vcxitems" Label="Shared" /> <Import Project="..\Main\Main.vcxitems" Label="Shared" /> + <Import Project="..\UtilityClasses\UtilityClasses.vcxitems" Label="Shared" /> + <Import Project="..\CreatedGrpc\CreatedGrpc.vcxitems" Label="Shared" /> </ImportGroup> <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> @@ -107,7 +109,7 @@ </ClCompile> <Link> <SubSystem>Console</SubSystem> - <AdditionalDependencies>Winmm.lib;ws2_32.lib;gpr.lib;grpc.lib;grpc++.lib;grpc_unsecure.lib;grpc++_unsecure.lib;libprotobuf.lib;%(AdditionalDependencies)</AdditionalDependencies> + <AdditionalDependencies>Winmm.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies> <AdditionalLibraryDirectories> </AdditionalLibraryDirectories> </Link> @@ -124,7 +126,7 @@ </ClCompile> <Link> <SubSystem>Console</SubSystem> - <AdditionalDependencies>Winmm.lib;ws2_32.lib;gpr.lib;grpc.lib;grpc++.lib;grpc_unsecure.lib;grpc++_unsecure.lib;libprotobuf.lib;%(AdditionalDependencies)</AdditionalDependencies> + <AdditionalDependencies>Winmm.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies> <AdditionalLibraryDirectories> </AdditionalLibraryDirectories> </Link> @@ -145,7 +147,7 @@ <SubSystem>Console</SubSystem> <EnableCOMDATFolding>true</EnableCOMDATFolding> <OptimizeReferences>true</OptimizeReferences> - <AdditionalDependencies>Winmm.lib;ws2_32.lib;gpr.lib;grpc.lib;grpc++.lib;grpc_unsecure.lib;grpc++_unsecure.lib;libprotobuf.lib;%(AdditionalDependencies)</AdditionalDependencies> + <AdditionalDependencies>Winmm.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies> <AdditionalLibraryDirectories> </AdditionalLibraryDirectories> </Link> @@ -166,7 +168,7 @@ <SubSystem>Console</SubSystem> <EnableCOMDATFolding>true</EnableCOMDATFolding> <OptimizeReferences>true</OptimizeReferences> - <AdditionalDependencies>Winmm.lib;ws2_32.lib;gpr.lib;grpc.lib;grpc++.lib;grpc_unsecure.lib;grpc++_unsecure.lib;libprotobuf.lib;%(AdditionalDependencies)</AdditionalDependencies> + <AdditionalDependencies>Winmm.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies> <AdditionalLibraryDirectories> </AdditionalLibraryDirectories> </Link> diff --git a/Main/main.cpp b/Main/main.cpp index 36106d7..e7c086f 100644 --- a/Main/main.cpp +++ b/Main/main.cpp @@ -1,5 +1,5 @@ #include "ModeliFile.hpp" -#include "FmuEngine.hpp" +#include "Simulation.hpp" #include "ModeliGrpcServer.h" #include "grpc++/grpc++.h" #include <chrono> @@ -42,7 +42,7 @@ int main(int argc, char *argv[]) { port = vm["port"].as<unsigned short>(); } - auto fmuEngine = std::make_shared<Simulation::FmuEngine>(std::to_string(port)); + auto fmuEngine = std::make_shared<Simulation::Simulation>(std::to_string(port)); // Load the modeli file into the engine if (vm.count("modeli")) { diff --git a/Network/ModeliGrpcServer.cpp b/Network/ModeliGrpcServer.cpp index ae7acc6..e963665 100644 --- a/Network/ModeliGrpcServer.cpp +++ b/Network/ModeliGrpcServer.cpp @@ -1,10 +1,10 @@ #include "ModeliGrpcServer.h" -#include "FmuEngine.hpp" +#include "Simulation.hpp" #include "CoSimFmu.h" using ModeliRpc::Fmi2Status; -ModeliGrpcServer::ModeliGrpcServer(std::shared_ptr<FmuEngine> fmuEngine) :_fmuEngine(fmuEngine) +ModeliGrpcServer::ModeliGrpcServer(std::shared_ptr<Simulation> fmuEngine) :_fmuEngine(fmuEngine) { } @@ -163,25 +163,9 @@ Status ModeliGrpcServer::NewValues(ServerContext * context, const::ModeliRpc::Ne { bool streamOpen = true; // Write to the stream until it is closed by the frontend - while (streamOpen) + while (writer->Write(_newValues.wait_and_pop())) { - std::unique_lock<std::mutex> lock(_newValuesMutex); - // While waiting we release the lock for the producer - _newValuesCv.wait(lock); - // We can access the queue savely - while (streamOpen && !_newValues.empty()) - { - if (writer->Write(_newValues.front())) - { - _newValues.pop(); - } - else - { - // Stop writing - streamOpen = false; - } - } - // Lock goes out of scope, the producer can add data to the queue + ; // Do nothing } return Status::OK; } @@ -190,25 +174,9 @@ Status ModeliGrpcServer::Log(ServerContext * context, const::ModeliRpc::LogReque { bool streamOpen = true; // Write to the stream until it is closed by the frontend - while (streamOpen) + while (writer->Write(_logs.wait_and_pop())) { - std::unique_lock<std::mutex> lock(_logMutex); - // While waiting we release the lock for the producer - _logCv.wait(lock); - // We can access the queue savely - while (streamOpen && !_logs.empty()) - { - if (writer->Write(_logs.front())) - { - _logs.pop(); - } - else - { - // Stop writing - streamOpen = false; - } - } - // Lock goes out of scope, the producer can add data to the queue + ; // Do nothing } return Status::OK; } @@ -247,11 +215,8 @@ void ModeliGrpcServer::ValuesArrived(const std::string instanceName, double time added->set_value_ref(stringVrs[i]); added->set_value(stringValues[i]); } - // Now safe to modify the queue - std::unique_lock<std::mutex> lock(_newValuesMutex); + // Thread safe modification & notification _newValues.push(response); - // Let the consumer do its work - _newValuesCv.notify_all(); } void ModeliGrpcServer::LogArrived(std::string instanceName, int status, std::string category, std::string message) @@ -259,5 +224,6 @@ void ModeliGrpcServer::LogArrived(std::string instanceName, int status, std::str ModeliRpc::LogResponse response; response.set_instance_name(instanceName); response.set_status(static_cast<Fmi2Status>(status)); - + // Threadsafe modification & notification + _logs.push(response); } diff --git a/Network/ModeliGrpcServer.h b/Network/ModeliGrpcServer.h index ce71994..d704768 100644 --- a/Network/ModeliGrpcServer.h +++ b/Network/ModeliGrpcServer.h @@ -1,15 +1,13 @@ #pragma once #include "ModeliRpc.grpc.pb.h" +#include "WaitableQueue.h" #include "IEngineObserver.hpp" -#include <memory> -#include <condition_variable> -#include <queue> namespace Simulation { - class FmuEngine; + class Simulation; } -using Simulation::FmuEngine; +using Simulation::Simulation; using grpc::Status; using grpc::ServerContext; using grpc::ServerWriter; @@ -18,7 +16,7 @@ using grpc::ServerReader; class ModeliGrpcServer final : public ModeliRpc::ModeliBackend::Service, Simulation::IEngineObserver { public: - ModeliGrpcServer(std::shared_ptr<FmuEngine> fmuEngine); + ModeliGrpcServer(std::shared_ptr<Simulation> fmuEngine); // Play the simulation infinetly in realtime Status Play(ServerContext* context, const ModeliRpc::PlayRequest* request, ModeliRpc::PlayResponse* response); @@ -49,7 +47,7 @@ public: // Stream log messages to the client Status Log(ServerContext* context, const ModeliRpc::LogRequest* request, ServerWriter<ModeliRpc::LogResponse>* writer); - /// Observer of the simulation + /// Observer callback virtual void ValuesArrived( std::string instanceName, ///< The instanceName of the FMU double timestamp, ///< Timestamp (current time) @@ -62,7 +60,7 @@ public: std::vector<unsigned int> stringVrs, std::vector<const char*> stringValues); - /// Observer of the simulation + /// Observer callback virtual void LogArrived( std::string instanceName, ///< The instanceName of the FMU int status, ///< Fmi2Status of the message @@ -71,15 +69,11 @@ public: ); private: // Execue the simulation commands - std::shared_ptr<FmuEngine> _fmuEngine; + std::shared_ptr<Simulation> _fmuEngine; // Wait for logs to arrive - std::mutex _logMutex; - std::condition_variable _logCv; - std::queue<ModeliRpc::LogResponse> _logs; + Utility::WaitableQueue<ModeliRpc::LogResponse> _logs; // Wait for values to arrive - std::mutex _newValuesMutex; - std::condition_variable _newValuesCv; - std::queue<ModeliRpc::NewValuesResponse> _newValues; + Utility::WaitableQueue<ModeliRpc::NewValuesResponse> _newValues; }; diff --git a/Network/Network.vcxitems b/Network/Network.vcxitems index 8bc7e13..7d769a1 100644 --- a/Network/Network.vcxitems +++ b/Network/Network.vcxitems @@ -16,12 +16,8 @@ </ItemGroup> <ItemGroup> <ClInclude Include="$(MSBuildThisFileDirectory)ModeliGrpcServer.h" /> - <ClInclude Include="$(MSBuildThisFileDirectory)ModeliRpc.grpc.pb.h" /> - <ClInclude Include="$(MSBuildThisFileDirectory)ModeliRpc.pb.h" /> </ItemGroup> <ItemGroup> <ClCompile Include="$(MSBuildThisFileDirectory)ModeliGrpcServer.cpp" /> - <ClCompile Include="$(MSBuildThisFileDirectory)ModeliRpc.grpc.pb.cc" /> - <ClCompile Include="$(MSBuildThisFileDirectory)ModeliRpc.pb.cc" /> </ItemGroup> </Project> \ No newline at end of file diff --git a/Network/Network.vcxitems.filters b/Network/Network.vcxitems.filters index 58153b3..0e5934b 100644 --- a/Network/Network.vcxitems.filters +++ b/Network/Network.vcxitems.filters @@ -14,22 +14,10 @@ <ClCompile Include="$(MSBuildThisFileDirectory)ModeliGrpcServer.cpp"> <Filter>Source</Filter> </ClCompile> - <ClCompile Include="$(MSBuildThisFileDirectory)ModeliRpc.grpc.pb.cc"> - <Filter>Source</Filter> - </ClCompile> - <ClCompile Include="$(MSBuildThisFileDirectory)ModeliRpc.pb.cc"> - <Filter>Source</Filter> - </ClCompile> </ItemGroup> <ItemGroup> <ClInclude Include="$(MSBuildThisFileDirectory)ModeliGrpcServer.h"> <Filter>Header</Filter> </ClInclude> - <ClInclude Include="$(MSBuildThisFileDirectory)ModeliRpc.grpc.pb.h"> - <Filter>Header</Filter> - </ClInclude> - <ClInclude Include="$(MSBuildThisFileDirectory)ModeliRpc.pb.h"> - <Filter>Header</Filter> - </ClInclude> </ItemGroup> </Project> \ No newline at end of file diff --git a/Simulation/FMUEngine.cpp b/Simulation/Simulation.cpp similarity index 79% rename from Simulation/FMUEngine.cpp rename to Simulation/Simulation.cpp index f0e8924..b38644c 100644 --- a/Simulation/FMUEngine.cpp +++ b/Simulation/Simulation.cpp @@ -1,5 +1,5 @@ #include "FmuFile.hpp" -#include "FmuEngine.hpp" +#include "Simulation.hpp" #include "CoSimFmu.h" // std #include <iostream> @@ -20,13 +20,13 @@ using NativeFmu::CoSimFmu; namespace Simulation { - FmuEngine::FmuEngine(std::string id) : + Simulation::Simulation(std::string id) : _controllerId(id) { _simulating = false; } - void FmuEngine::simulate() + void Simulation::simulate() { using std::chrono::high_resolution_clock; // Remember current time as oldDuration (continuing from pause) @@ -77,7 +77,7 @@ namespace Simulation fmi2False); if (status == fmi2Error || status == fmi2Fatal) { - onLog(pair.first, status, "FmuEngine", "Error on DoStep. Cannot continue the simulation!"); + onLog(pair.first, status, "Simulation", "Error on DoStep. Cannot continue the simulation!"); return; // Simulation no longer possible } } @@ -92,7 +92,8 @@ namespace Simulation // Let the CPU cool down SetProcessAsLowPrecision(); } - void FmuEngine::calculateChannelLinks() + + void Simulation::calculateChannelLinks() { // Perform each link for (ChannelLink link : _channelLinks) @@ -101,7 +102,7 @@ namespace Simulation auto masterFmuInstance = FindFmu(link.MasterInstanceName); if (!masterFmuInstance) { - onLog("FmuEngine", fmi2Warning, "FmuEngine", + onLog("Simulation", fmi2Warning, "Simulation", "Failed ChannelLink: " + link.MasterInstanceName + ": " + std::to_string(link.MasterValueRef) + "-> " + link.SlaveInstanceName + ": " + std::to_string(link.SlaveValueRef) + @@ -111,7 +112,7 @@ namespace Simulation auto slaveFmuInstance = FindFmu(link.SlaveInstanceName); if (!slaveFmuInstance) { - onLog("FmuEngine", fmi2Warning, "FmuEngine", + onLog("Simulation", fmi2Warning, "Simulation", "Failed ChannelLink: " + link.MasterInstanceName + ": " + std::to_string(link.MasterValueRef) + "-> " + link.SlaveInstanceName + ": " + std::to_string(link.SlaveValueRef) + " SlaveChannel fmu instance does not exist."); @@ -124,7 +125,7 @@ namespace Simulation if (res != fmi2OK) { // The fmu will send an error itself but send soe additional info here - onLog("FmuEngine", fmi2Warning, "FmuEngine", + onLog("Simulation", fmi2Warning, "Simulation", "Failed ChannelLink: " + link.MasterInstanceName + ": " + std::to_string(link.MasterValueRef) + "-> " + link.SlaveInstanceName + ": " + std::to_string(link.SlaveValueRef) + ", could not perform GetReal."); @@ -140,7 +141,7 @@ namespace Simulation if (res != fmi2OK) { // The fmu will send an error itself but send soe additional info here - onLog("FmuEngine", fmi2Warning, "FmuEngine", + onLog("Simulation", fmi2Warning, "Simulation", "Failed ChannelLink: " + link.MasterInstanceName + ": " + std::to_string(link.MasterValueRef) + "-> " + link.SlaveInstanceName + ": " + std::to_string(link.SlaveValueRef) + ", could not perform SetReal."); @@ -149,7 +150,8 @@ namespace Simulation } } } - void FmuEngine::sendValues() + + void Simulation::sendValues() { for (auto &pair : _fmus) { @@ -158,25 +160,25 @@ namespace Simulation auto intRes = fmu->GetInteger(); if (intRes.first != fmi2OK) { - onLog(fmu->GetInstanceName(), intRes.first, "FmuEngine", "GetInteger failed."); + onLog(fmu->GetInstanceName(), intRes.first, "Simulation", "GetInteger failed."); } // Real auto realRes = fmu->GetReal(); if (realRes.first != fmi2OK) { - onLog(fmu->GetInstanceName(), realRes.first, "FmuEngine", "GetReal failed."); + onLog(fmu->GetInstanceName(), realRes.first, "Simulation", "GetReal failed."); } // Bool auto boolRes = fmu->GetBoolean(); if (boolRes.first != fmi2OK) { - onLog(fmu->GetInstanceName(), boolRes.first, "FmuEngine", "GetBoolean failed."); + onLog(fmu->GetInstanceName(), boolRes.first, "Simulation", "GetBoolean failed."); } // String auto stringRes = fmu->GetString(); if (stringRes.first != fmi2OK) { - onLog(fmu->GetInstanceName(), stringRes.first, "FmuEngine", "GetString failed."); + onLog(fmu->GetInstanceName(), stringRes.first, "Simulation", "GetString failed."); } // Send the values @@ -190,14 +192,14 @@ namespace Simulation } } - double FmuEngine::getSeconds(std::chrono::milliseconds duration) + double Simulation::getSeconds(std::chrono::milliseconds duration) { // seconds as double typedef std::chrono::duration<double> double_seconds; return std::chrono::duration_cast<double_seconds>(duration).count(); } - int FmuEngine::startSimulation() + int Simulation::startSimulation() { // Play from initialized or stopped state if (!_simulating) @@ -210,30 +212,30 @@ namespace Simulation int status = fmu->ExitInitializationMode(); if (!(status == fmi2OK || status == fmi2Warning)) { - onLog(fmu->GetInstanceName(), status, "FmuEngine", "ExitInitializationMode failed"); + onLog(fmu->GetInstanceName(), status, "Simulation", "ExitInitializationMode failed"); return status; } } // Start simulating _simulating = true; // Create new thread for the simulation - _simThread = std::thread(&FmuEngine::simulate, this); + _simThread = std::thread(&Simulation::simulate, this); } return fmi2OK; } - void FmuEngine::AddObserver(std::shared_ptr<IEngineObserver> observer) + void Simulation::AddObserver(std::shared_ptr<IEngineObserver> observer) { _observers.push_back(observer); } - void FmuEngine::RemoveObserver(std::shared_ptr<IEngineObserver> observer) + void Simulation::RemoveObserver(std::shared_ptr<IEngineObserver> observer) { // Guarenteed not to throw _observers.remove(observer); } - int FmuEngine::Play() + int Simulation::Play() { // Play infinite _endDuration = std::chrono::milliseconds(0); @@ -241,7 +243,8 @@ namespace Simulation _playFast = false; return startSimulation(); } - int FmuEngine::PlayFast(double endTime_sec) + + int Simulation::PlayFast(double endTime_sec) { // Update the _endTime _endDuration = std::chrono::milliseconds(static_cast<unsigned long>(endTime_sec * 1000)); @@ -249,16 +252,18 @@ namespace Simulation _playFast = true; return startSimulation(); } + // Stop the simulation thread - void FmuEngine::Pause() + void Simulation::Pause() { // Only try to obtain ownership over the thread without blocking the current thread _simulating = false; // Wait until the current run has finished _simThread.join(); } + // Stop the thread and reset the simulation - int FmuEngine::Stop() + int Simulation::Stop() { // Stop simulation _simulating = false; @@ -301,7 +306,7 @@ namespace Simulation return fmi2OK; } - int FmuEngine::initializeFmu(std::shared_ptr<CoSimFmu> fmu) + int Simulation::initializeFmu(std::shared_ptr<CoSimFmu> fmu) { // No error estimation and no pre-defined stoptime -> 10.0 is meaningless int status = fmu->SetupExperiment(fmi2False, 0, 0, fmi2False, 0); @@ -313,7 +318,7 @@ namespace Simulation return fmu->EnterInitializationMode(); } - void FmuEngine::onValuesArrived(const std::string instanceName, double timestamp, const std::vector<unsigned int> intVrs, const std::vector<int> intValues, const std::vector<unsigned int> realVrs, const std::vector<double> realValues, const std::vector<unsigned int> boolVrs, const std::vector<int> boolValues, const std::vector<unsigned int> stringVrs, const std::vector<const char*> stringValues) + void Simulation::onValuesArrived(const std::string instanceName, double timestamp, const std::vector<unsigned int> intVrs, const std::vector<int> intValues, const std::vector<unsigned int> realVrs, const std::vector<double> realValues, const std::vector<unsigned int> boolVrs, const std::vector<int> boolValues, const std::vector<unsigned int> stringVrs, const std::vector<const char*> stringValues) { // Invoke each observer for (auto observer : _observers) @@ -327,7 +332,7 @@ namespace Simulation } } - void FmuEngine::onLog(std::string instanceName, int status, std::string category, std::string message) + void Simulation::onLog(std::string instanceName, int status, std::string category, std::string message) { // Invoke each observer for (auto observer : _observers) @@ -336,18 +341,18 @@ namespace Simulation } } - bool FmuEngine::AddChannelLink(ChannelLink channelLink) + bool Simulation::AddChannelLink(ChannelLink channelLink) { // Check existance of instances if (!FindFmu(channelLink.MasterInstanceName)) { - onLog("FmuEngine", fmi2Warning, "FmuEngine", + onLog("Simulation", fmi2Warning, "Simulation", "MasterInstanceName of ChannelLink not found: " + channelLink.MasterInstanceName); return false; } if (!FindFmu(channelLink.SlaveInstanceName)) { - onLog("FmuEngine", fmi2Warning, "FmuEngine", + onLog("Simulation", fmi2Warning, "Simulation", "SlaveInstanceName of ChannelLink not found: " + channelLink.SlaveInstanceName); return false; } @@ -357,13 +362,13 @@ namespace Simulation return true; } - bool FmuEngine::RemoveChannelLink(ChannelLink channelLink) + bool Simulation::RemoveChannelLink(ChannelLink channelLink) { _channelLinks.remove(channelLink); return true; } - bool FmuEngine::AddChannelLink(const std::string& masterInstanceName, const std::string& slaveInstanceName, + bool Simulation::AddChannelLink(const std::string& masterInstanceName, const std::string& slaveInstanceName, unsigned int masterValueRef, unsigned int slaveValueRef, double factor, double shift) { // Create the channelLink @@ -377,7 +382,7 @@ namespace Simulation // Add it! return AddChannelLink(channelLink); } - bool FmuEngine::RemoveChannelLink(const std::string& masterInstanceName, const std::string& slaveInstanceName, + bool Simulation::RemoveChannelLink(const std::string& masterInstanceName, const std::string& slaveInstanceName, unsigned int masterValueRef, unsigned int slaveValueRef) { // Create the channelLink @@ -390,13 +395,13 @@ namespace Simulation return RemoveChannelLink(channelLink); } - bool FmuEngine::AddFmu(std::shared_ptr<FmuFile> fmuFile) + bool Simulation::AddFmu(std::shared_ptr<FmuFile> fmuFile) { // Check if the instanceName is in use if (FindFmu(fmuFile->GetInstanceName())) { // Error: The element has been found but we can not have two identical instances - onLog(fmuFile->GetInstanceName(), fmi2Warning, "FmuEngine", "The instanceName already exists."); + onLog(fmuFile->GetInstanceName(), fmi2Warning, "Simulation", "The instanceName already exists."); return false; } @@ -405,17 +410,17 @@ namespace Simulation std::pair<bool, std::string> loadDllRes = coSimFmu->LoadDll(fmuFile->GetBinaryPath()); if (!loadDllRes.first) { - onLog(fmuFile->GetInstanceName(), fmi2Warning, "FmuEngine", "Failed LoadLibrary, Error: " + loadDllRes.second); + onLog(fmuFile->GetInstanceName(), fmi2Warning, "Simulation", "Failed LoadLibrary, Error: " + loadDllRes.second); return false; } // Setup callbacks and parameters namespace ph = std::placeholders; - coSimFmu->SetLoggerCallback(std::bind(&FmuEngine::onLog, this, ph::_1, ph::_2, ph::_3, ph::_4)); + coSimFmu->SetLoggerCallback(std::bind(&Simulation::onLog, this, ph::_1, ph::_2, ph::_3, ph::_4)); // Instantiate if (!coSimFmu->Instantiate(fmuFile->GetInstanceName(), fmuFile->GetGUID(), fmuFile->GetResourceUri())) { - onLog(fmuFile->GetInstanceName(), fmi2Warning, "FmuEngine", "Instantiation failed for instance: " + fmuFile->GetInstanceName()); + onLog(fmuFile->GetInstanceName(), fmi2Warning, "Simulation", "Instantiation failed for instance: " + fmuFile->GetInstanceName()); return false; } @@ -430,19 +435,19 @@ namespace Simulation return true; } - bool FmuEngine::AddFmu(std::string instanceName, std::string path) + bool Simulation::AddFmu(std::string instanceName, std::string path) { // Add the fmu from file return AddFmu(std::make_shared<FmuFile>(path, _controllerId, instanceName)); } - bool FmuEngine::AddFmu(std::string instanceName, const std::vector<unsigned char> &bytes) + bool Simulation::AddFmu(std::string instanceName, const std::vector<unsigned char> &bytes) { // Add the fmu from file return AddFmu(std::make_shared<FmuFile>(bytes, _controllerId, instanceName)); } - bool FmuEngine::RemoveFMU(std::string instanceName) + bool Simulation::RemoveFMU(std::string instanceName) { // Make sure we stopped the simulation Stop(); @@ -455,12 +460,12 @@ namespace Simulation } else { - onLog(instanceName, fmi2Warning, "FmuEngine", "Instance can not be removed, it does not exist: " + instanceName); + onLog(instanceName, fmi2Warning, "Simulation", "Instance can not be removed, it does not exist: " + instanceName); return false; } } - boost::optional<FmuFilePair> FmuEngine::FindFmu(std::string instanceName) + boost::optional<FmuFilePair> Simulation::FindFmu(std::string instanceName) { auto iter = _fmus.find(instanceName); if (iter == _fmus.end()) diff --git a/Simulation/FmuEngine.hpp b/Simulation/Simulation.hpp similarity index 98% rename from Simulation/FmuEngine.hpp rename to Simulation/Simulation.hpp index 4cc0386..d1726cb 100644 --- a/Simulation/FmuEngine.hpp +++ b/Simulation/Simulation.hpp @@ -35,11 +35,11 @@ namespace Simulation std::shared_ptr<FmuFile> File; }; - class FmuEngine + class Simulation { public: - ///< Creates a new instance of the FmuEngine - FmuEngine( + ///< Creates a new instance of the Simulation + Simulation( std::string id ///< A unique identification, used to create a dir where the models will be stored ); diff --git a/Simulation/Simulation.vcxitems b/Simulation/Simulation.vcxitems index a22d006..d941352 100644 --- a/Simulation/Simulation.vcxitems +++ b/Simulation/Simulation.vcxitems @@ -17,11 +17,11 @@ <ClInclude Include="$(MSBuildThisFileDirectory)ChannelLink.h" /> <ClInclude Include="$(MSBuildThisFileDirectory)fmi2FunctionTypes.h" /> <ClInclude Include="$(MSBuildThisFileDirectory)fmi2TypesPlatform.h" /> - <ClInclude Include="$(MSBuildThisFileDirectory)FmuEngine.hpp" /> + <ClInclude Include="$(MSBuildThisFileDirectory)Simulation.hpp" /> <ClInclude Include="$(MSBuildThisFileDirectory)IEngineObserver.hpp" /> </ItemGroup> <ItemGroup> <ClCompile Include="$(MSBuildThisFileDirectory)ChannelLink.cpp" /> - <ClCompile Include="$(MSBuildThisFileDirectory)FMUEngine.cpp" /> + <ClCompile Include="$(MSBuildThisFileDirectory)Simulation.cpp" /> </ItemGroup> </Project> \ No newline at end of file diff --git a/Simulation/Simulation.vcxitems.filters b/Simulation/Simulation.vcxitems.filters index 535ee7b..2d58f89 100644 --- a/Simulation/Simulation.vcxitems.filters +++ b/Simulation/Simulation.vcxitems.filters @@ -20,10 +20,10 @@ <ClInclude Include="$(MSBuildThisFileDirectory)fmi2TypesPlatform.h"> <Filter>Header</Filter> </ClInclude> - <ClInclude Include="$(MSBuildThisFileDirectory)FmuEngine.hpp"> + <ClInclude Include="$(MSBuildThisFileDirectory)IEngineObserver.hpp"> <Filter>Header</Filter> </ClInclude> - <ClInclude Include="$(MSBuildThisFileDirectory)IEngineObserver.hpp"> + <ClInclude Include="C:\Users\alldocube\Documents\GitRepo\MC_BackEnd\Simulation\Simulation.hpp"> <Filter>Header</Filter> </ClInclude> </ItemGroup> @@ -31,7 +31,7 @@ <ClCompile Include="$(MSBuildThisFileDirectory)ChannelLink.cpp"> <Filter>Source</Filter> </ClCompile> - <ClCompile Include="$(MSBuildThisFileDirectory)FMUEngine.cpp"> + <ClCompile Include="C:\Users\alldocube\Documents\GitRepo\MC_BackEnd\Simulation\Simulation.cpp"> <Filter>Source</Filter> </ClCompile> </ItemGroup> diff --git a/UtilityClasses/UtilityClasses.vcxitems b/UtilityClasses/UtilityClasses.vcxitems new file mode 100644 index 0000000..358818e --- /dev/null +++ b/UtilityClasses/UtilityClasses.vcxitems @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <PropertyGroup Label="Globals"> + <MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects> + <HasSharedItems>true</HasSharedItems> + <ItemsProjectGuid>{fd95ebac-8e33-43d3-88ba-04a2b02d7d9e}</ItemsProjectGuid> + <ItemsProjectName>Utility</ItemsProjectName> + </PropertyGroup> + <ItemDefinitionGroup> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(MSBuildThisFileDirectory)</AdditionalIncludeDirectories> + </ClCompile> + </ItemDefinitionGroup> + <ItemGroup> + <ProjectCapability Include="SourceItemsFromImports" /> + </ItemGroup> + <ItemGroup> + <ClInclude Include="$(MSBuildThisFileDirectory)WaitableQueue.h" /> + </ItemGroup> +</Project> \ No newline at end of file diff --git a/UtilityClasses/WaitableQueue.h b/UtilityClasses/WaitableQueue.h new file mode 100644 index 0000000..cf5cf87 --- /dev/null +++ b/UtilityClasses/WaitableQueue.h @@ -0,0 +1,79 @@ +#pragma once +#include "boost/optional.hpp" +#include <functional> +#include <queue> +#include <mutex> + +namespace Utility +{ + /// This class enables thread safe access to the queue. + /// It uses conditional variables to for efficient waiting. + /// No hard exception safety for better interface. + template <typename T> + class WaitableQueue + { + private: + std::queue<T> _queue; + std::mutex _mutex; + std::condition_variable _cond_var; + + // Functional style for boilerplate + /// Locks the mutex before executing the action. + /// After the execution has finished the conditional variable will be notified. + void executeAndNotify(std::function<void()> action) + { + std::unique_lock<std::mutex> lock(_mutex); + action(); + lock.unlock(); + _cond_var.notify_one(); + } + + public: + /// Immediately returns the item from the front (or boost::none). + boost::optional<T> pop() + { + std::unique_lock<std::mutex> lock(_mutex); + if (_queue.empty()) + { + return boost::none; + } + else + { + auto item = _queue.front(); + _queue.pop(); + return item; + } + } + /// Waits for data to become available and returns the first element. + T wait_and_pop() + { + // Wait for signal + std::unique_lock<std::mutex> lock(_mutex); + // Prevent spurious wakeups by checking the queue + _cond_var.wait(lock, [&]() + { + return !_queue.empty(); + }); + // Return the front + auto item = _queue.front(); + _queue.pop(); + return item; + } + /// Add an item to the end of the queue + void push(const T& item) + { + executeAndNotify([&]() + { + _queue.push(item); + }); + } + /// Add an item to the end of the queue + void push(T&& item) + { + executeAndNotify([&]() + { + _queue.push(std::move(item)); + }); + } + }; +} -- GitLab