From d78fca6544a9d7280f41fc5f1fc63f454d94c753 Mon Sep 17 00:00:00 2001 From: Robert Braun Date: Thu, 7 Jan 2021 10:40:09 +0100 Subject: [PATCH 01/34] Asio dependency --- dependencies/dependencies.xml | 6 ++++++ dependencies/setupAll.sh | 1 + dependencies/setupAsio.sh | 27 +++++++++++++++++++++++++++ 3 files changed, 34 insertions(+) create mode 100755 dependencies/setupAsio.sh diff --git a/dependencies/dependencies.xml b/dependencies/dependencies.xml index cb317358db..68bbdf5d79 100644 --- a/dependencies/dependencies.xml +++ b/dependencies/dependencies.xml @@ -87,6 +87,12 @@ + + + https://sourceforge.net/projects/asio/files/asio/1.12.1 (Stable)/asio-1.12.1.zip + + + https://sourceforge.net/projects/mingw-w64/files/Toolchains%20targetting%20Win64/Personal%20Builds/mingw-builds/5.4.0/threads-posix/seh/x86_64-5.4.0-release-posix-seh-rt_v5-rev0.7z diff --git a/dependencies/setupAll.sh b/dependencies/setupAll.sh index 38de193dbb..dda70ccae3 100755 --- a/dependencies/setupAll.sh +++ b/dependencies/setupAll.sh @@ -8,3 +8,4 @@ ./setupKatex.sh ./setupTclap.sh ./setupHDF5.sh +./setupAsio.sh diff --git a/dependencies/setupAsio.sh b/dependencies/setupAsio.sh new file mode 100755 index 0000000000..5cbe818dcb --- /dev/null +++ b/dependencies/setupAsio.sh @@ -0,0 +1,27 @@ +#!/bin/bash +# $Id$ + +# Shell script building HopsaGUI dependency Asio automatically + +basedir=`pwd` +name=asio +codedir=${basedir}/${name}-code +builddir=${basedir}/${name}-build +installdir=${basedir}/${name} + +# Download and verify +./download-dependencies.py ${name} + +# Copy code to build dir, not sure if out-of-source build is possible +mkdir -p $builddir +pushd $builddir +cp -a $codedir/* . + +# Generate makefiles +chmod u+x ./configure +./configure --prefix=$installdir --without-boost +cd include +make install + +popd +echo "setupAsio.sh done!" From 39952d4c2914062ffa2ba30a06c2bdd868f8842a Mon Sep 17 00:00:00 2001 From: Robert Braun Date: Thu, 7 Jan 2021 10:41:03 +0100 Subject: [PATCH 02/34] Xerces dependency --- dependencies/dependencies.xml | 6 ++++++ dependencies/setupAll.sh | 1 + dependencies/setupXerces.sh | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 41 insertions(+) create mode 100755 dependencies/setupXerces.sh diff --git a/dependencies/dependencies.xml b/dependencies/dependencies.xml index 68bbdf5d79..210f20fc0d 100644 --- a/dependencies/dependencies.xml +++ b/dependencies/dependencies.xml @@ -93,6 +93,12 @@ + + + https://github.com/apache/xerces-c/archive/v3.2.2.zip + + + https://sourceforge.net/projects/mingw-w64/files/Toolchains%20targetting%20Win64/Personal%20Builds/mingw-builds/5.4.0/threads-posix/seh/x86_64-5.4.0-release-posix-seh-rt_v5-rev0.7z diff --git a/dependencies/setupAll.sh b/dependencies/setupAll.sh index dda70ccae3..535caef9b5 100755 --- a/dependencies/setupAll.sh +++ b/dependencies/setupAll.sh @@ -9,3 +9,4 @@ ./setupTclap.sh ./setupHDF5.sh ./setupAsio.sh +./setupXerces.sh diff --git a/dependencies/setupXerces.sh b/dependencies/setupXerces.sh new file mode 100755 index 0000000000..157232b1ba --- /dev/null +++ b/dependencies/setupXerces.sh @@ -0,0 +1,34 @@ +#!/bin/bash + +# Shell script building Hopsan dependency Xerces + +basedir=$(pwd) + +name=xerces +codedir=${basedir}/${name}-code +builddir=${basedir}/${name}-build +installdir=${basedir}/${name} + +# Download and verify +./download-dependencies.py ${name} + +# Include general settings +source setHopsanBuildPaths.sh + +# Create build dir and enter it +mkdir -p $builddir +cd $builddir + +# Generate makefiles +cmake -Wno-dev -DCMAKE_INSTALL_PREFIX=$installdir ${codedir} + +# Build and install +cmake --build . +cmake --build . --target install +if [[ "$HOPSAN_BUILD_DEPENDENCIES_TEST" == "true" ]]; then + ctest +fi + +# Return to basedir +cd $basedir +echo "setupXerces.sh done!" From a4b592ab37389d3fec7c275161d2eac82c784484 Mon Sep 17 00:00:00 2001 From: Robert Braun Date: Thu, 7 Jan 2021 10:57:42 +0100 Subject: [PATCH 03/34] libzip dependency --- dependencies/dependencies.xml | 6 ++++++ dependencies/setupAll.sh | 1 + dependencies/setupLibzip.sh | 31 +++++++++++++++++++++++++++++++ 3 files changed, 38 insertions(+) create mode 100755 dependencies/setupLibzip.sh diff --git a/dependencies/dependencies.xml b/dependencies/dependencies.xml index 210f20fc0d..fd067d075d 100644 --- a/dependencies/dependencies.xml +++ b/dependencies/dependencies.xml @@ -99,6 +99,12 @@ + + + https://github.com/nih-at/libzip/archive/v1.7.3.zip + + + https://sourceforge.net/projects/mingw-w64/files/Toolchains%20targetting%20Win64/Personal%20Builds/mingw-builds/5.4.0/threads-posix/seh/x86_64-5.4.0-release-posix-seh-rt_v5-rev0.7z diff --git a/dependencies/setupAll.sh b/dependencies/setupAll.sh index 535caef9b5..7336fc38e4 100755 --- a/dependencies/setupAll.sh +++ b/dependencies/setupAll.sh @@ -10,3 +10,4 @@ ./setupHDF5.sh ./setupAsio.sh ./setupXerces.sh +./setupLibzip.sh diff --git a/dependencies/setupLibzip.sh b/dependencies/setupLibzip.sh new file mode 100755 index 0000000000..2e7834c427 --- /dev/null +++ b/dependencies/setupLibzip.sh @@ -0,0 +1,31 @@ +#!/bin/bash + +# Shell script building Hopsan dependency Libzip + +basedir=$(pwd) + +name=libzip +codedir=${basedir}/${name}-code +builddir=${basedir}/${name}-build +installdir=${basedir}/${name} + +# Download and verify +./download-dependencies.py ${name} + +# Include general settings +source setHopsanBuildPaths.sh + +# Create build dir and enter it +mkdir -p $builddir +cd $builddir + +# Generate makefiles +cmake -Wno-dev -DCMAKE_INSTALL_PREFIX=$installdir ${codedir} + +# Build and install +make -j16 +make install + +# Return to basedir +cd $basedir +echo "setupLibzip.sh done!" From b1a98174cbf8f2204c0a89199834f2534d241d11 Mon Sep 17 00:00:00 2001 From: Robert Braun Date: Thu, 7 Jan 2021 13:16:31 +0100 Subject: [PATCH 04/34] Added hopsandcp subproject with DCPLib submodule --- .gitmodules | 3 ++ HopsanNG.pro | 3 +- hopsandcp/.gitignore | 73 +++++++++++++++++++++++++++++++ hopsandcp/dependencies/DCPLib | 1 + hopsandcp/hopsandcp.pro | 82 +++++++++++++++++++++++++++++++++++ hopsandcp/main.cpp | 17 ++++++++ 6 files changed, 178 insertions(+), 1 deletion(-) create mode 100644 hopsandcp/.gitignore create mode 160000 hopsandcp/dependencies/DCPLib create mode 100644 hopsandcp/hopsandcp.pro create mode 100644 hopsandcp/main.cpp diff --git a/.gitmodules b/.gitmodules index 1e4d7a5b69..7ae717dde4 100644 --- a/.gitmodules +++ b/.gitmodules @@ -10,3 +10,6 @@ [submodule "HopsanCore/dependencies/sundials"] path = HopsanCore/dependencies/sundials url = https://github.com/LLNL/sundials +[submodule "hopsandcp/dependencies/DCPLib"] + path = hopsandcp/dependencies/DCPLib + url = https://github.com/modelica/DCPLib diff --git a/HopsanNG.pro b/HopsanNG.pro index 5eda54cf1a..777329f56a 100644 --- a/HopsanNG.pro +++ b/HopsanNG.pro @@ -1,6 +1,6 @@ TEMPLATE = subdirs -SUBDIRS = HopsanCore componentLibraries SymHop Ops HopsanGenerator hopsangeneratorgui hopsanremote hopsanhdf5exporter HopsanGUI HopsanCLI UnitTests hopsanc +SUBDIRS = HopsanCore componentLibraries SymHop Ops HopsanGenerator hopsangeneratorgui hopsanremote hopsanhdf5exporter HopsanGUI HopsanCLI UnitTests hopsanc hopsandcp componentLibraries.depends = HopsanCore HopsanGenerator.depends = HopsanCore SymHop @@ -10,3 +10,4 @@ hopsanc.depends = HopsanCore hopsanhdf5exporter.depends = HopsanCore hopsanremote.depends = HopsanCore UnitTests.depends = HopsanCore HopsanGenerator componentLibraries +hopsandcp.depends = HopsanCore diff --git a/hopsandcp/.gitignore b/hopsandcp/.gitignore new file mode 100644 index 0000000000..fab7372d79 --- /dev/null +++ b/hopsandcp/.gitignore @@ -0,0 +1,73 @@ +# This file is used to ignore files which are generated +# ---------------------------------------------------------------------------- + +*~ +*.autosave +*.a +*.core +*.moc +*.o +*.obj +*.orig +*.rej +*.so +*.so.* +*_pch.h.cpp +*_resource.rc +*.qm +.#* +*.*# +core +!core/ +tags +.DS_Store +.directory +*.debug +Makefile* +*.prl +*.app +moc_*.cpp +ui_*.h +qrc_*.cpp +Thumbs.db +*.res +*.rc +/.qmake.cache +/.qmake.stash + +# qtcreator generated files +*.pro.user* + +# xemacs temporary files +*.flc + +# Vim temporary files +.*.swp + +# Visual Studio generated files +*.ib_pdb_index +*.idb +*.ilk +*.pdb +*.sln +*.suo +*.vcproj +*vcproj.*.*.user +*.ncb +*.sdf +*.opensdf +*.vcxproj +*vcxproj.* + +# MinGW generated files +*.Debug +*.Release + +# Python byte code +*.pyc + +# Binaries +# -------- +*.dll +*.exe + diff --git a/hopsandcp/dependencies/DCPLib b/hopsandcp/dependencies/DCPLib new file mode 160000 index 0000000000..402264a2f3 --- /dev/null +++ b/hopsandcp/dependencies/DCPLib @@ -0,0 +1 @@ +Subproject commit 402264a2f349e5eb4c6ce6fbcf0d8566ca27546e diff --git a/hopsandcp/hopsandcp.pro b/hopsandcp/hopsandcp.pro new file mode 100644 index 0000000000..d735b3572c --- /dev/null +++ b/hopsandcp/hopsandcp.pro @@ -0,0 +1,82 @@ +# ------------------------------------------------- +# Global project options +# ------------------------------------------------- +include( ../Common.prf ) + +TARGET = hopsandcp +TEMPLATE = app +CONFIG += shared +DESTDIR = $${PWD}/../bin +TARGET = $${TARGET}$${DEBUG_EXT} +DEFINES += DEBUG + +QT -= core gui + +#-------------------------------------------------- +# Add the include path to our self, (hopsandcp) +INCLUDEPATH *= $${PWD}/include/ +#-------------------------------------------------- + +#-------------------------------------------------- +# Add the include path to (HopsanCore) +INCLUDEPATH *= $${PWD}/../HopsanCore/include/ +LIBS *= -L$${PWD}/../bin -lhopsancore$${DEBUG_EXT} +DEFINES *= HOPSANCORE_DLLIMPORT +#-------------------------------------------------- + +#-------------------------------------------------- +# Add the include and lib path to xerces +INCLUDEPATH *= $${PWD}/../dependencies/xerces/include/ +LIBS *= -L$${PWD}/../dependencies/xerces/lib/ +LIBS *= -lxerces-c +#-------------------------------------------------- + +#-------------------------------------------------- +# Add the include path to xerces +INCLUDEPATH *= $${PWD}/../dependencies/asio/include/ +#-------------------------------------------------- + +#-------------------------------------------------- +# Add the include and lib path to libzip +INCLUDEPATH *= $${PWD}/../dependencies/libzip/include/ +LIBS *= -L$${PWD}/../dependencies/libzip/lib/ +LIBS *= -lzip +#-------------------------------------------------- + +#-------------------------------------------------- +# Add the include and lib path to xerces +INCLUDEPATH *= $${PWD}/../dependencies/xerces/include/ +LIBS *= -L$${PWD}/../dependencies/xerces/lib/ +LIBS *= -lxerces-c +#-------------------------------------------------- + +#-------------------------------------------------- +# Add the include path to DCPLib +INCLUDEPATH *= $${PWD}/dependencies/DCPLib/include/bluetooth +INCLUDEPATH *= $${PWD}/dependencies/DCPLib/include/core +INCLUDEPATH *= $${PWD}/dependencies/DCPLib/include/ethernet +INCLUDEPATH *= $${PWD}/dependencies/DCPLib/include/master +INCLUDEPATH *= $${PWD}/dependencies/DCPLib/include/slave +INCLUDEPATH *= $${PWD}/dependencies/DCPLib/include/xml +INCLUDEPATH *= $${PWD}/dependencies/DCPLib/include/zip +#-------------------------------------------------- + +# ------------------------------------------------- +# Platform specific additional project options +# ------------------------------------------------- +win32 { + DEFINES += HOPSANGENERATOR_DLLEXPORT + DEFINES -= UNICODE +} +unix { + # Add runtime search path so that dynamically loaded libraries in the same directory can be found. + # Note! QMAKE_LFLAGS_RPATH and QMAKE_RPATHDIR does not seem hande $$ORIGIN, adding manually to LFLAGS + QMAKE_LFLAGS *= -Wl,-rpath,\'\$$ORIGIN/./\' +} + +# ------------------------------------------------- +# Project files +# ------------------------------------------------- +SOURCES = \ + main.cpp + diff --git a/hopsandcp/main.cpp b/hopsandcp/main.cpp new file mode 100644 index 0000000000..cd4c818ca9 --- /dev/null +++ b/hopsandcp/main.cpp @@ -0,0 +1,17 @@ +#include "dcp/helper/Helper.hpp" +#include "dcp/log/OstreamLog.hpp" +#include "dcp/logic/DcpManagerSlave.hpp" +#include "dcp/xml/DcpSlaveDescriptionWriter.hpp" +#include "dcp/xml/DcpSlaveDescriptionReader.hpp" +#include "dcp/model/pdu/DcpPduFactory.hpp" +#include "dcp/driver/ethernet/udp/UdpDriver.hpp" + +#include + +using namespace std; + +int main() +{ + cout << "Hello World!" << endl; + return 0; +} From 073f573296e3626628744422e04ee3e26ebe96b8 Mon Sep 17 00:00:00 2001 From: Robert Braun Date: Thu, 7 Jan 2021 15:19:05 +0100 Subject: [PATCH 05/34] Generate DCP descriptions from hopsandcp --- hopsandcp/hopsandcp.pro | 9 ++ hopsandcp/include/hopsandcp.h | 18 ++++ hopsandcp/main.cpp | 156 +++++++++++++++++++++++++++++++++- 3 files changed, 181 insertions(+), 2 deletions(-) create mode 100644 hopsandcp/include/hopsandcp.h diff --git a/hopsandcp/hopsandcp.pro b/hopsandcp/hopsandcp.pro index d735b3572c..dedcb6c9a8 100644 --- a/hopsandcp/hopsandcp.pro +++ b/hopsandcp/hopsandcp.pro @@ -9,6 +9,7 @@ CONFIG += shared DESTDIR = $${PWD}/../bin TARGET = $${TARGET}$${DEBUG_EXT} DEFINES += DEBUG +QMAKE_CXXFLAGS = -Wno-comment -Wno-switch -Wno-ignored-qualifiers -Wno-sign-compare QT -= core gui @@ -61,6 +62,11 @@ INCLUDEPATH *= $${PWD}/dependencies/DCPLib/include/xml INCLUDEPATH *= $${PWD}/dependencies/DCPLib/include/zip #-------------------------------------------------- +#-------------------------------------------------------- +# Set the tclap include path +INCLUDEPATH *= $${PWD}/../dependencies/tclap/include +#-------------------------------------------------------- + # ------------------------------------------------- # Platform specific additional project options # ------------------------------------------------- @@ -80,3 +86,6 @@ unix { SOURCES = \ main.cpp +HEADERS += \ + include/hopsandcp.h + diff --git a/hopsandcp/include/hopsandcp.h b/hopsandcp/include/hopsandcp.h new file mode 100644 index 0000000000..9280ed32c9 --- /dev/null +++ b/hopsandcp/include/hopsandcp.h @@ -0,0 +1,18 @@ +#ifndef HOPSANDCP_H +#define HOPSANDCP_H + +#include + +// Forward Declaration +namespace hopsan { + class Port; + class ComponentSystem; + class HopsanEssentials; + class HString; +} + +extern hopsan::HopsanEssentials gHopsanCore; +extern std::string gHost; +extern int gPort; + +#endif // HOPSANDCP_H diff --git a/hopsandcp/main.cpp b/hopsandcp/main.cpp index cd4c818ca9..c66296b5db 100644 --- a/hopsandcp/main.cpp +++ b/hopsandcp/main.cpp @@ -1,3 +1,9 @@ +#include "hopsandcp.h" + +#include "HopsanEssentials.h" +#include "HopsanCoreMacros.h" +#include "HopsanCoreVersion.h" + #include "dcp/helper/Helper.hpp" #include "dcp/log/OstreamLog.hpp" #include "dcp/logic/DcpManagerSlave.hpp" @@ -6,12 +12,158 @@ #include "dcp/model/pdu/DcpPduFactory.hpp" #include "dcp/driver/ethernet/udp/UdpDriver.hpp" +#include + #include +#ifndef DEFAULT_LIBRARY_ROOT +#define DEFAULT_LIBRARY_ROOT "../componentLibraries/defaultLibrary" +#endif + +#ifndef HOPSAN_INTERNALDEFAULTCOMPONENTS +#define DEFAULTLIBFILE SHAREDLIB_PREFIX "defaultcomponentlibrary" HOPSAN_DEBUG_POSTFIX "." SHAREDLIB_SUFFIX +const std::string default_library = DEFAULT_LIBRARY_ROOT "/" DEFAULTLIBFILE; +#else +const std::string default_library = ""; +#endif + using namespace std; +using namespace hopsan; + +HopsanEssentials gHopsanCore; +std::string gHost = "127.0.0.1"; +int gPort = 8080; -int main() +void printWaitingMessages() { - cout << "Hello World!" << endl; + hopsan::HString msg, type, tag; + while (gHopsanCore.checkMessage() > 0) + { + gHopsanCore.getMessage(msg,type,tag); + if(type != "debug") { + cout << msg.c_str() << endl; + } + } +} + + +SlaveDescription_t getSlaveDescription(std::string name, double timeStep, vector &inputs, vector &outputs){ + SlaveDescription_t slaveDescription = make_SlaveDescription(1, 0, name, "b5279485-720d-4542-9f29-bee4d9a75ef9"); + slaveDescription.OpMode.HardRealTime = make_HardRealTime_ptr(); + slaveDescription.OpMode.SoftRealTime = make_SoftRealTime_ptr(); + slaveDescription.OpMode.NonRealTime = make_NonRealTime_ptr(); + Resolution_t resolution = make_Resolution(); + resolution.numerator = 1; + resolution.denominator = denominator_t(1/timeStep); + slaveDescription.TimeRes.resolutions.push_back(resolution); + slaveDescription.TransportProtocols.UDP_IPv4 = make_UDP_ptr(); + slaveDescription.TransportProtocols.UDP_IPv4->Control = make_Control_ptr(gHost.c_str(), port_t(gPort)); + slaveDescription.TransportProtocols.UDP_IPv4->DAT_input_output = make_DAT_ptr(); + slaveDescription.TransportProtocols.UDP_IPv4->DAT_input_output->availablePortRanges.push_back(make_AvailablePortRange(2048, 65535)); + slaveDescription.TransportProtocols.UDP_IPv4->DAT_parameter = make_DAT_ptr(); + slaveDescription.TransportProtocols.UDP_IPv4->DAT_parameter->availablePortRanges.push_back(make_AvailablePortRange(2048, 65535)); + slaveDescription.CapabilityFlags.canAcceptConfigPdus = true; + slaveDescription.CapabilityFlags.canHandleReset = false; + slaveDescription.CapabilityFlags.canHandleVariableSteps = false; + slaveDescription.CapabilityFlags.canMonitorHeartbeat = false; + slaveDescription.CapabilityFlags.canProvideLogOnRequest = true; + slaveDescription.CapabilityFlags.canProvideLogOnNotification = true; + + for(size_t i=0; i causality = make_Output_ptr(); + slaveDescription.Variables.push_back(make_Variable_output(outputs[i], valueReference_t(i), causality)); + } + for(size_t i=0; i causality = make_CommonCausality_ptr(); + causality->Float64->start = std::make_shared>(); + causality->Float64->start->push_back(0.0); + slaveDescription.Variables.push_back(make_Variable_input(inputs[i], valueReference_t(i), causality)); + } + + slaveDescription.Log = make_Log_ptr(); + slaveDescription.Log->categories.push_back(make_Category(1, "DCP_SLAVE")); + + return slaveDescription; +} + + +void generateDescriptionFile(std::string &modelFile, std::string &targetFile) { + std::cout << "Generating " << targetFile << " from model " << modelFile << "\n"; + + double startTime=0, stopTime=1; + ComponentSystem *pHopsanSystem = gHopsanCore.loadHMFModelFile(modelFile.c_str(), startTime, stopTime); + printWaitingMessages(); + if(pHopsanSystem == nullptr) { + std::cout << "Failed to load model file: " << modelFile << "\n"; + exit(-1); + } + std::vector inputs, outputs; + for(const auto &component : pHopsanSystem->getSubComponents()) { + if(component->getTypeName() == "SignalInputInterface") { + inputs.push_back(component->getName().c_str()); + } + else if(component->getTypeName() == "SignalOutputInterface") { + outputs.push_back(component->getName().c_str()); + } + } + std::cout << "Inputs:"; + for(const auto &input : inputs) { + std::cout << " " << input; + } + std::cout << "\nOutputs:"; + for(const auto &output : outputs) { + std::cout << " " << output; + } + std::cout << "\n"; + + std::string systemName = pHopsanSystem->getName().c_str(); + writeDcpSlaveDescription(getSlaveDescription(systemName, pHopsanSystem->getTimestep(), inputs, outputs), targetFile.c_str()); +} + + +int main(int argc, char* argv[]) +{ + TCLAP::CmdLine cmd("hopsandcp", ' ', "0.1"); + + // Define a value argument and add it to the command line. + TCLAP::SwitchArg generateDescription("d","description","Generate DCP desciption file",cmd); + TCLAP::ValueArg argModelFile("m","model","Hopsan model file",false, "", "", cmd); + TCLAP::ValueArg argTargetDescriptionFile("t","target","Target file for DCP description",false, "", "", cmd); + TCLAP::ValueArg argHost("a","address","Host address",false,"127.0.0.1","",cmd); + TCLAP::ValueArg argPort("p","port","Port",false,8080,"",cmd); + // Parse the argv array. + cmd.parse( argc, argv ); + + gHost = argHost.getValue(); + gPort = argPort.getValue(); + +#ifndef HOPSAN_INTERNALDEFAULTCOMPONENTS + // Load default Hopsan component lib + string libpath = default_library; + gHopsanCore.loadExternalComponentLib(libpath.c_str()); +#endif + + printWaitingMessages(); + + if(generateDescription.isSet()) { + if(!argModelFile.isSet()) { + cout << "Generating a DCP description requires a model file.\n"; + return -1; + } + string modelFile = argModelFile.getValue(); + string targetFile; + if(argTargetDescriptionFile.isSet()) { + targetFile = argTargetDescriptionFile.getValue(); + } + else { + targetFile = argModelFile.getValue(); + targetFile = targetFile.substr(0,targetFile.find_last_of('.'))+".dcpx"; + } + + generateDescriptionFile(modelFile, targetFile); + } + + std::cout << "hopsandcp completed successfully!\n"; + return 0; } From c7a1885d2cf8bd506c26f22642daa0ab56fd7669 Mon Sep 17 00:00:00 2001 From: Robert Braun Date: Fri, 8 Jan 2021 08:37:52 +0100 Subject: [PATCH 06/34] Move DCP slave functionality to separate class --- hopsandcp/dcpslave.cpp | 127 ++++++++++++++++++++++++++++++ hopsandcp/dcpslave.h | 32 ++++++++ hopsandcp/hopsandcp.pro | 2 + hopsandcp/include/hopsandcp.h | 4 - hopsandcp/main.cpp | 142 ++++------------------------------ 5 files changed, 175 insertions(+), 132 deletions(-) create mode 100644 hopsandcp/dcpslave.cpp create mode 100644 hopsandcp/dcpslave.h diff --git a/hopsandcp/dcpslave.cpp b/hopsandcp/dcpslave.cpp new file mode 100644 index 0000000000..03dcfd119d --- /dev/null +++ b/hopsandcp/dcpslave.cpp @@ -0,0 +1,127 @@ +#include "dcpslave.h" + +#include "dcp/logic/DcpManagerSlave.hpp" +#include "dcp/xml/DcpSlaveDescriptionWriter.hpp" + +#include "HopsanEssentials.h" +#include "HopsanCoreMacros.h" +#include "HopsanCoreVersion.h" + +#ifndef DEFAULT_LIBRARY_ROOT +#define DEFAULT_LIBRARY_ROOT "../componentLibraries/defaultLibrary" +#endif + +#ifndef HOPSAN_INTERNALDEFAULTCOMPONENTS +#define DEFAULTLIBFILE SHAREDLIB_PREFIX "defaultcomponentlibrary" HOPSAN_DEBUG_POSTFIX "." SHAREDLIB_SUFFIX +const std::string default_library = DEFAULT_LIBRARY_ROOT "/" DEFAULTLIBFILE; +#else +const std::string default_library = ""; +#endif + +using namespace hopsan; + +DcpSlave::DcpSlave(const std::string modelfile, const std::string host, int port) + : mHost(host), mPort(port) +{ + //Create Hopsan object + mpHopsanCore = new HopsanEssentials(); + +#ifndef HOPSAN_INTERNALDEFAULTCOMPONENTS + // Load default Hopsan component lib + std::string libpath = default_library; + mpHopsanCore->loadExternalComponentLib(libpath.c_str()); +#endif + + //Load model file + double startTime=0, stopTime=1; + mpRootSystem = mpHopsanCore->loadHMFModelFile(modelfile.c_str(), startTime, stopTime); + printWaitingMessages(); + if(mpRootSystem == nullptr) { + std::cout << "Failed to load model file: " << modelfile << "\n"; + exit(-1); + } + + //Generate list of inputs and outputs based on interface components + for(const auto &component : mpRootSystem->getSubComponents()) { + if(component->getTypeName() == "SignalInputInterface") { + mInputs.push_back(component->getName().c_str()); + } + else if(component->getTypeName() == "SignalOutputInterface") { + mOutputs.push_back(component->getName().c_str()); + } + } + std::cout << "Inputs:"; + for(const auto &input : mInputs) { + std::cout << " " << input; + } + std::cout << "\nOutputs:"; + for(const auto &output : mOutputs) { + std::cout << " " << output; + } + std::cout << "\n"; + + printWaitingMessages(); +} + +DcpSlave::~DcpSlave() +{ + delete mpHopsanCore; +} + + +void DcpSlave::printWaitingMessages() +{ + hopsan::HString msg, type, tag; + while (mpHopsanCore->checkMessage() > 0) + { + mpHopsanCore->getMessage(msg,type,tag); + if(type != "debug") { + std::cout << msg.c_str() << std::endl; + } + } +} + + +SlaveDescription_t *DcpSlave::getSlaveDescription() { + SlaveDescription_t *slaveDescription = new SlaveDescription_t(make_SlaveDescription(1, 0, mpRootSystem->getName().c_str(), "b5279485-720d-4542-9f29-bee4d9a75ef9")); + slaveDescription->OpMode.HardRealTime = make_HardRealTime_ptr(); + slaveDescription->OpMode.SoftRealTime = make_SoftRealTime_ptr(); + slaveDescription->OpMode.NonRealTime = make_NonRealTime_ptr(); + Resolution_t resolution = make_Resolution(); + resolution.numerator = 1; + resolution.denominator = denominator_t(1/mpRootSystem->getTimestep()); + slaveDescription->TimeRes.resolutions.push_back(resolution); + slaveDescription->TransportProtocols.UDP_IPv4 = make_UDP_ptr(); + slaveDescription->TransportProtocols.UDP_IPv4->Control = make_Control_ptr(mHost.c_str(), port_t(mPort)); + slaveDescription->TransportProtocols.UDP_IPv4->DAT_input_output = make_DAT_ptr(); + slaveDescription->TransportProtocols.UDP_IPv4->DAT_input_output->availablePortRanges.push_back(make_AvailablePortRange(2048, 65535)); + slaveDescription->TransportProtocols.UDP_IPv4->DAT_parameter = make_DAT_ptr(); + slaveDescription->TransportProtocols.UDP_IPv4->DAT_parameter->availablePortRanges.push_back(make_AvailablePortRange(2048, 65535)); + slaveDescription->CapabilityFlags.canAcceptConfigPdus = true; + slaveDescription->CapabilityFlags.canHandleReset = false; + slaveDescription->CapabilityFlags.canHandleVariableSteps = false; + slaveDescription->CapabilityFlags.canMonitorHeartbeat = false; + slaveDescription->CapabilityFlags.canProvideLogOnRequest = true; + slaveDescription->CapabilityFlags.canProvideLogOnNotification = true; + + for(size_t i=0; i causality = make_Output_ptr(); + slaveDescription->Variables.push_back(make_Variable_output(mOutputs[i], valueReference_t(i), causality)); + } + for(size_t i=0; i causality = make_CommonCausality_ptr(); + causality->Float64->start = std::make_shared>(); + causality->Float64->start->push_back(0.0); + slaveDescription->Variables.push_back(make_Variable_input(mInputs[i], valueReference_t(i), causality)); + } + + slaveDescription->Log = make_Log_ptr(); + slaveDescription->Log->categories.push_back(make_Category(1, "DCP_SLAVE")); + + return slaveDescription; +} + + +void DcpSlave::generateDescriptionFile(std::string &targetFile) { + writeDcpSlaveDescription(*getSlaveDescription(), targetFile.c_str()); +} diff --git a/hopsandcp/dcpslave.h b/hopsandcp/dcpslave.h new file mode 100644 index 0000000000..e0df20bcf1 --- /dev/null +++ b/hopsandcp/dcpslave.h @@ -0,0 +1,32 @@ +#ifndef DCPSLAVE_H +#define DCPSLAVE_H + +#include +#include + +namespace hopsan { +class HopsanEssentials; +class ComponentSystem; +} + +struct SlaveDescription_t; + +class DcpSlave +{ +public: + DcpSlave(const std::string modelfile, const std::string host, int port); + ~DcpSlave(); + + void generateDescriptionFile(std::string &targetFile); + +private: + hopsan::HopsanEssentials *mpHopsanCore; + hopsan::ComponentSystem *mpRootSystem; + std::vector mInputs, mOutputs; + std::string mHost = "127.0.0.1"; + int mPort = 8080; + void printWaitingMessages(); + SlaveDescription_t *getSlaveDescription(); +}; + +#endif // DCPSLAVE_H diff --git a/hopsandcp/hopsandcp.pro b/hopsandcp/hopsandcp.pro index dedcb6c9a8..9d2f830947 100644 --- a/hopsandcp/hopsandcp.pro +++ b/hopsandcp/hopsandcp.pro @@ -84,8 +84,10 @@ unix { # Project files # ------------------------------------------------- SOURCES = \ + dcpslave.cpp \ main.cpp HEADERS += \ + dcpslave.h \ include/hopsandcp.h diff --git a/hopsandcp/include/hopsandcp.h b/hopsandcp/include/hopsandcp.h index 9280ed32c9..09e99fcb12 100644 --- a/hopsandcp/include/hopsandcp.h +++ b/hopsandcp/include/hopsandcp.h @@ -11,8 +11,4 @@ namespace hopsan { class HString; } -extern hopsan::HopsanEssentials gHopsanCore; -extern std::string gHost; -extern int gPort; - #endif // HOPSANDCP_H diff --git a/hopsandcp/main.cpp b/hopsandcp/main.cpp index c66296b5db..5296220574 100644 --- a/hopsandcp/main.cpp +++ b/hopsandcp/main.cpp @@ -1,125 +1,11 @@ -#include "hopsandcp.h" - -#include "HopsanEssentials.h" -#include "HopsanCoreMacros.h" -#include "HopsanCoreVersion.h" - -#include "dcp/helper/Helper.hpp" -#include "dcp/log/OstreamLog.hpp" -#include "dcp/logic/DcpManagerSlave.hpp" -#include "dcp/xml/DcpSlaveDescriptionWriter.hpp" -#include "dcp/xml/DcpSlaveDescriptionReader.hpp" -#include "dcp/model/pdu/DcpPduFactory.hpp" -#include "dcp/driver/ethernet/udp/UdpDriver.hpp" +//#include "hopsandcp.h" +#include "dcpslave.h" #include #include -#ifndef DEFAULT_LIBRARY_ROOT -#define DEFAULT_LIBRARY_ROOT "../componentLibraries/defaultLibrary" -#endif - -#ifndef HOPSAN_INTERNALDEFAULTCOMPONENTS -#define DEFAULTLIBFILE SHAREDLIB_PREFIX "defaultcomponentlibrary" HOPSAN_DEBUG_POSTFIX "." SHAREDLIB_SUFFIX -const std::string default_library = DEFAULT_LIBRARY_ROOT "/" DEFAULTLIBFILE; -#else -const std::string default_library = ""; -#endif - using namespace std; -using namespace hopsan; - -HopsanEssentials gHopsanCore; -std::string gHost = "127.0.0.1"; -int gPort = 8080; - -void printWaitingMessages() -{ - hopsan::HString msg, type, tag; - while (gHopsanCore.checkMessage() > 0) - { - gHopsanCore.getMessage(msg,type,tag); - if(type != "debug") { - cout << msg.c_str() << endl; - } - } -} - - -SlaveDescription_t getSlaveDescription(std::string name, double timeStep, vector &inputs, vector &outputs){ - SlaveDescription_t slaveDescription = make_SlaveDescription(1, 0, name, "b5279485-720d-4542-9f29-bee4d9a75ef9"); - slaveDescription.OpMode.HardRealTime = make_HardRealTime_ptr(); - slaveDescription.OpMode.SoftRealTime = make_SoftRealTime_ptr(); - slaveDescription.OpMode.NonRealTime = make_NonRealTime_ptr(); - Resolution_t resolution = make_Resolution(); - resolution.numerator = 1; - resolution.denominator = denominator_t(1/timeStep); - slaveDescription.TimeRes.resolutions.push_back(resolution); - slaveDescription.TransportProtocols.UDP_IPv4 = make_UDP_ptr(); - slaveDescription.TransportProtocols.UDP_IPv4->Control = make_Control_ptr(gHost.c_str(), port_t(gPort)); - slaveDescription.TransportProtocols.UDP_IPv4->DAT_input_output = make_DAT_ptr(); - slaveDescription.TransportProtocols.UDP_IPv4->DAT_input_output->availablePortRanges.push_back(make_AvailablePortRange(2048, 65535)); - slaveDescription.TransportProtocols.UDP_IPv4->DAT_parameter = make_DAT_ptr(); - slaveDescription.TransportProtocols.UDP_IPv4->DAT_parameter->availablePortRanges.push_back(make_AvailablePortRange(2048, 65535)); - slaveDescription.CapabilityFlags.canAcceptConfigPdus = true; - slaveDescription.CapabilityFlags.canHandleReset = false; - slaveDescription.CapabilityFlags.canHandleVariableSteps = false; - slaveDescription.CapabilityFlags.canMonitorHeartbeat = false; - slaveDescription.CapabilityFlags.canProvideLogOnRequest = true; - slaveDescription.CapabilityFlags.canProvideLogOnNotification = true; - - for(size_t i=0; i causality = make_Output_ptr(); - slaveDescription.Variables.push_back(make_Variable_output(outputs[i], valueReference_t(i), causality)); - } - for(size_t i=0; i causality = make_CommonCausality_ptr(); - causality->Float64->start = std::make_shared>(); - causality->Float64->start->push_back(0.0); - slaveDescription.Variables.push_back(make_Variable_input(inputs[i], valueReference_t(i), causality)); - } - - slaveDescription.Log = make_Log_ptr(); - slaveDescription.Log->categories.push_back(make_Category(1, "DCP_SLAVE")); - - return slaveDescription; -} - - -void generateDescriptionFile(std::string &modelFile, std::string &targetFile) { - std::cout << "Generating " << targetFile << " from model " << modelFile << "\n"; - - double startTime=0, stopTime=1; - ComponentSystem *pHopsanSystem = gHopsanCore.loadHMFModelFile(modelFile.c_str(), startTime, stopTime); - printWaitingMessages(); - if(pHopsanSystem == nullptr) { - std::cout << "Failed to load model file: " << modelFile << "\n"; - exit(-1); - } - std::vector inputs, outputs; - for(const auto &component : pHopsanSystem->getSubComponents()) { - if(component->getTypeName() == "SignalInputInterface") { - inputs.push_back(component->getName().c_str()); - } - else if(component->getTypeName() == "SignalOutputInterface") { - outputs.push_back(component->getName().c_str()); - } - } - std::cout << "Inputs:"; - for(const auto &input : inputs) { - std::cout << " " << input; - } - std::cout << "\nOutputs:"; - for(const auto &output : outputs) { - std::cout << " " << output; - } - std::cout << "\n"; - - std::string systemName = pHopsanSystem->getName().c_str(); - writeDcpSlaveDescription(getSlaveDescription(systemName, pHopsanSystem->getTimestep(), inputs, outputs), targetFile.c_str()); -} - int main(int argc, char* argv[]) { @@ -134,23 +20,22 @@ int main(int argc, char* argv[]) // Parse the argv array. cmd.parse( argc, argv ); - gHost = argHost.getValue(); - gPort = argPort.getValue(); - -#ifndef HOPSAN_INTERNALDEFAULTCOMPONENTS - // Load default Hopsan component lib - string libpath = default_library; - gHopsanCore.loadExternalComponentLib(libpath.c_str()); -#endif - - printWaitingMessages(); - if(generateDescription.isSet()) { if(!argModelFile.isSet()) { cout << "Generating a DCP description requires a model file.\n"; return -1; } + if(!argHost.isSet()) { + cout << "Generating a DCP description requires a host address.\n"; + return -1; + } + if(!argPort.isSet()) { + cout << "Generating a DCP description requires a port.\n"; + return -1; + } string modelFile = argModelFile.getValue(); + std::string host = argHost.getValue(); + int port = argPort.getValue(); string targetFile; if(argTargetDescriptionFile.isSet()) { targetFile = argTargetDescriptionFile.getValue(); @@ -160,7 +45,8 @@ int main(int argc, char* argv[]) targetFile = targetFile.substr(0,targetFile.find_last_of('.'))+".dcpx"; } - generateDescriptionFile(modelFile, targetFile); + DcpSlave *pSlave = new DcpSlave(modelFile,host,port); + pSlave->generateDescriptionFile(targetFile); } std::cout << "hopsandcp completed successfully!\n"; From 553ccc786a3d9bc571685de161de0141988e2d50 Mon Sep 17 00:00:00 2001 From: Robert Braun Date: Mon, 11 Jan 2021 08:36:52 +0100 Subject: [PATCH 07/34] Execute DCP slave simualtions from hopsandcp --- hopsandcp/dcpslave.cpp | 115 +++++++++++++++++++++++++++++++++++++++-- hopsandcp/dcpslave.h | 20 ++++++- hopsandcp/main.cpp | 35 ++++++++++--- 3 files changed, 158 insertions(+), 12 deletions(-) diff --git a/hopsandcp/dcpslave.cpp b/hopsandcp/dcpslave.cpp index 03dcfd119d..78b0b84acc 100644 --- a/hopsandcp/dcpslave.cpp +++ b/hopsandcp/dcpslave.cpp @@ -1,7 +1,11 @@ #include "dcpslave.h" -#include "dcp/logic/DcpManagerSlave.hpp" -#include "dcp/xml/DcpSlaveDescriptionWriter.hpp" +#include +#include +#include +#include +#include +#include #include "HopsanEssentials.h" #include "HopsanCoreMacros.h" @@ -18,6 +22,12 @@ const std::string default_library = DEFAULT_LIBRARY_ROOT "/" DEFAULTLIBFILE; const std::string default_library = ""; #endif +const LogTemplate SIM_LOG = LogTemplate( + 1, 1, DcpLogLevel::LVL_INFORMATION, + "[Time = %float64]: output = %float64", + {DcpDataType::float64, DcpDataType::float64}); + + using namespace hopsan; DcpSlave::DcpSlave(const std::string modelfile, const std::string host, int port) @@ -61,6 +71,34 @@ DcpSlave::DcpSlave(const std::string modelfile, const std::string host, int port std::cout << "\n"; printWaitingMessages(); + + + //Create UDP driver + udpDriver = new UdpDriver(host, uint16_t(port)); + + //Create slave DCP manager + mManager = new DcpManagerSlave(*getSlaveDescription(), udpDriver->getDcpDriver()); + mManager->setInitializeCallback( + std::bind(&DcpSlave::initialize, this)); + mManager->setConfigureCallback( + std::bind(&DcpSlave::configure, this)); + mManager->setSynchronizingStepCallback( + std::bind(&DcpSlave::doStep, this, std::placeholders::_1)); + mManager->setSynchronizedStepCallback( + std::bind(&DcpSlave::doStep, this, std::placeholders::_1)); + mManager->setRunningStepCallback( + std::bind(&DcpSlave::doStep, this, std::placeholders::_1)); + mManager->setRunningNRTStepCallback( + std::bind(&DcpSlave::doStep, this, std::placeholders::_1)); + mManager->setTimeResListener(std::bind(&DcpSlave::setTimeRes, this, + std::placeholders::_1, + std::placeholders::_2)); + + //Display log messages on console + stdLog = new OstreamLog(std::cout); + mManager->addLogListener( + std::bind(&OstreamLog::logOstream, *stdLog, std::placeholders::_1)); + mManager->setGenerateLogString(true); } DcpSlave::~DcpSlave() @@ -89,7 +127,7 @@ SlaveDescription_t *DcpSlave::getSlaveDescription() { slaveDescription->OpMode.NonRealTime = make_NonRealTime_ptr(); Resolution_t resolution = make_Resolution(); resolution.numerator = 1; - resolution.denominator = denominator_t(1/mpRootSystem->getTimestep()); + resolution.denominator = denominator_t(1.0/mpRootSystem->getTimestep()); slaveDescription->TimeRes.resolutions.push_back(resolution); slaveDescription->TransportProtocols.UDP_IPv4 = make_UDP_ptr(); slaveDescription->TransportProtocols.UDP_IPv4->Control = make_Control_ptr(mHost.c_str(), port_t(mPort)); @@ -112,11 +150,13 @@ SlaveDescription_t *DcpSlave::getSlaveDescription() { std::shared_ptr causality = make_CommonCausality_ptr(); causality->Float64->start = std::make_shared>(); causality->Float64->start->push_back(0.0); - slaveDescription->Variables.push_back(make_Variable_input(mInputs[i], valueReference_t(i), causality)); + slaveDescription->Variables.push_back(make_Variable_input(mInputs[i], valueReference_t(mOutputs.size()+i), causality)); } slaveDescription->Log = make_Log_ptr(); slaveDescription->Log->categories.push_back(make_Category(1, "DCP_SLAVE")); + slaveDescription->Log->templates.push_back(make_Template( + 1, 1, (uint8_t) DcpLogLevel::LVL_INFORMATION, "[Time = %float64]: output = %float64")); return slaveDescription; } @@ -125,3 +165,70 @@ SlaveDescription_t *DcpSlave::getSlaveDescription() { void DcpSlave::generateDescriptionFile(std::string &targetFile) { writeDcpSlaveDescription(*getSlaveDescription(), targetFile.c_str()); } + +void DcpSlave::start() +{ + mManager->start(); +} + + +void DcpSlave::configure() { + std::cout << "Checking model... "; + if (mpRootSystem->checkModelBeforeSimulation()) { + std::cout << "Success!\n"; + } + else { + std::cout << "Failed!\n"; + printWaitingMessages(); + exit(-1); + } + + for(size_t o=0; ogetOutput(o)); + mOutputNodePtrs.push_back(mpRootSystem->getSubComponent(mOutputs[o].c_str())->getPort("in")->getNodeDataPtr(0)); + } + for(size_t i=0; igetInput(mOutputs.size()+i)); + mInputNodePtrs.push_back(mpRootSystem->getSubComponent(mInputs[i].c_str())->getPort("out")->getNodeDataPtr(0)); + } + + std::cout << "Initializing... "; + if(mpRootSystem->initialize(0,10)) { + std::cout << "Success!\n"; + printWaitingMessages(); + } + else { + std::cout << "Failed!\n"; + printWaitingMessages(); + exit(-1); + } +} + +void DcpSlave::initialize() { + + +} + +void DcpSlave::doStep(uint64_t steps) { + + // Read inputs + for(size_t i=0; igetTimestep(); + mpRootSystem->simulate(mSimulationTime); + + // Write outputs + for(size_t o=0; oLog(SIM_LOG, mSimulationTime, *mOutputDataPtrs[o]); + } + + printWaitingMessages(); +} + +void DcpSlave::setTimeRes(const uint32_t numerator, const uint32_t denominator) { + mpRootSystem->setDesiredTimestep(double(numerator)/double(denominator)); +} diff --git a/hopsandcp/dcpslave.h b/hopsandcp/dcpslave.h index e0df20bcf1..cbb5c64ea7 100644 --- a/hopsandcp/dcpslave.h +++ b/hopsandcp/dcpslave.h @@ -10,6 +10,9 @@ class ComponentSystem; } struct SlaveDescription_t; +class DcpManagerSlave; +class UdpDriver; +class OstreamLog; class DcpSlave { @@ -18,15 +21,28 @@ class DcpSlave ~DcpSlave(); void generateDescriptionFile(std::string &targetFile); + void start(); private: + void printWaitingMessages(); + SlaveDescription_t *getSlaveDescription(); + hopsan::HopsanEssentials *mpHopsanCore; hopsan::ComponentSystem *mpRootSystem; std::vector mInputs, mOutputs; + std::vector mInputNodePtrs, mOutputNodePtrs; + std::vector mInputDataPtrs, mOutputDataPtrs; std::string mHost = "127.0.0.1"; int mPort = 8080; - void printWaitingMessages(); - SlaveDescription_t *getSlaveDescription(); + DcpManagerSlave *mManager; + OstreamLog *stdLog; + UdpDriver* udpDriver; + double mSimulationTime=0; + + void configure(); + void initialize(); + void doStep(uint64_t steps); + void setTimeRes(const uint32_t numerator, const uint32_t denominator); }; #endif // DCPSLAVE_H diff --git a/hopsandcp/main.cpp b/hopsandcp/main.cpp index 5296220574..d6692f675c 100644 --- a/hopsandcp/main.cpp +++ b/hopsandcp/main.cpp @@ -12,7 +12,8 @@ int main(int argc, char* argv[]) TCLAP::CmdLine cmd("hopsandcp", ' ', "0.1"); // Define a value argument and add it to the command line. - TCLAP::SwitchArg generateDescription("d","description","Generate DCP desciption file",cmd); + TCLAP::SwitchArg argMakeDescription("d","description","Generate DCP desciption file",cmd); + TCLAP::SwitchArg argSlave("s","slave","Run model in slave mode",cmd); TCLAP::ValueArg argModelFile("m","model","Hopsan model file",false, "", "", cmd); TCLAP::ValueArg argTargetDescriptionFile("t","target","Target file for DCP description",false, "", "", cmd); TCLAP::ValueArg argHost("a","address","Host address",false,"127.0.0.1","",cmd); @@ -20,7 +21,13 @@ int main(int argc, char* argv[]) // Parse the argv array. cmd.parse( argc, argv ); - if(generateDescription.isSet()) { + if(argMakeDescription.isSet() && argSlave.isSet()) { + cout << "Cannot both generate description and run as slave.\n"; + return -1; + } + + //GEnerate DCP description file + if(argMakeDescription.isSet()) { if(!argModelFile.isSet()) { cout << "Generating a DCP description requires a model file.\n"; return -1; @@ -33,9 +40,6 @@ int main(int argc, char* argv[]) cout << "Generating a DCP description requires a port.\n"; return -1; } - string modelFile = argModelFile.getValue(); - std::string host = argHost.getValue(); - int port = argPort.getValue(); string targetFile; if(argTargetDescriptionFile.isSet()) { targetFile = argTargetDescriptionFile.getValue(); @@ -45,10 +49,29 @@ int main(int argc, char* argv[]) targetFile = targetFile.substr(0,targetFile.find_last_of('.'))+".dcpx"; } - DcpSlave *pSlave = new DcpSlave(modelFile,host,port); + DcpSlave *pSlave = new DcpSlave(argModelFile.getValue(),argHost.getValue(),argPort.getValue()); pSlave->generateDescriptionFile(targetFile); } + //Run a simulation as slave + if(argSlave.isSet()) { + if(!argModelFile.isSet()) { + cout << "Generating a DCP description requires a model file.\n"; + return -1; + } + if(!argHost.isSet()) { + cout << "Generating a DCP description requires a host address.\n"; + return -1; + } + if(!argPort.isSet()) { + cout << "Generating a DCP description requires a port.\n"; + return -1; + } + DcpSlave *pSlave = new DcpSlave(argModelFile.getValue(),argHost.getValue(),argPort.getValue()); + pSlave->start(); + } + + std::cout << "hopsandcp completed successfully!\n"; return 0; From 0c483bb77051b867dea9d5fe74cad40f953d1d37 Mon Sep 17 00:00:00 2001 From: Robert Braun Date: Tue, 12 Jan 2021 11:16:13 +0100 Subject: [PATCH 08/34] Execute DCP master simulations from hopsandcp --- hopsandcp/dcpmaster.cpp | 259 ++++++++++++++++++++++++++++++++++++++++ hopsandcp/dcpmaster.h | 79 ++++++++++++ hopsandcp/hopsandcp.pro | 8 +- hopsandcp/main.cpp | 72 +++++++++-- 4 files changed, 406 insertions(+), 12 deletions(-) create mode 100644 hopsandcp/dcpmaster.cpp create mode 100644 hopsandcp/dcpmaster.h diff --git a/hopsandcp/dcpmaster.cpp b/hopsandcp/dcpmaster.cpp new file mode 100644 index 0000000000..69a96970a2 --- /dev/null +++ b/hopsandcp/dcpmaster.cpp @@ -0,0 +1,259 @@ +#include "dcpmaster.h" + +#include +#include +#include +#include + +#include "dcp/helper/LogHelper.hpp" +#include "dcp/model/pdu/DcpPduFactory.hpp" +#include "dcp/xml/DcpSlaveDescriptionReader.hpp" +#include "dcp/driver/ethernet/udp/UdpDriver.hpp" +#include "dcp/logic/DcpManagerMaster.hpp" + + +DcpMaster::DcpMaster(const std::string host, u_short port) + : stdLog(std::cout) +{ + driver = new UdpDriver(host, port); + + manager = new DcpManagerMaster(driver->getDcpDriver()); + + manager->setAckReceivedListener( + std::bind(&DcpMaster::receiveAck, this, std::placeholders::_1, std::placeholders::_2)); + manager->setNAckReceivedListener( + std::bind(&DcpMaster::receiveNAck, this, std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3)); + manager->setStateChangedNotificationReceivedListener( + std::bind(&DcpMaster::receiveStateChangedNotification, this, std::placeholders::_1, + std::placeholders::_2)); + manager->setDataReceivedListener( + std::bind(&DcpMaster::dataReceived, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); + manager->addLogListener(std::bind(&OstreamLog::logOstream, stdLog, std::placeholders::_1)); + manager->setGenerateLogString(true); +} + +DcpMaster::~DcpMaster() { + delete driver; + delete manager; +} + +void DcpMaster::addSlave(string &filepath) +{ + slaveDescriptions.push_back(new SlaveDescription_t(*readSlaveDescription(filepath.c_str()))); + u_char id = u_char(slaveDescriptions.size()); + uint8_t *netInfo = new uint8_t[6]; + //*((uint8_t *) netInfo) = *slaveDescriptions.back()->TransportProtocols.UDP_IPv4->Control->port; + *((uint16_t *) netInfo) = *slaveDescriptions.back()->TransportProtocols.UDP_IPv4->Control->port; + //*((uint8_t *) (netInfo + 2)) = asio::ip::address_v4::from_string(*slaveDescriptions.back()->TransportProtocols.UDP_IPv4->Control->host).to_uint(); + *((uint32_t *) (netInfo + 2)) = asio::ip::address_v4::from_string(*slaveDescriptions.back()->TransportProtocols.UDP_IPv4->Control->host).to_ulong(); + driver->getDcpDriver().setSlaveNetworkInformation(id, netInfo); + delete[] netInfo; +} + +void DcpMaster::addConnection(size_t fromSlave, size_t fromVr, std::vector toSlaves, std::vector toVrs) +{ + std::cout << "addConnection: " << fromSlave << "," << fromVr << "," << toSlaves[0] << "," << toVrs[0] << "\n"; + DcpConnection connection; + connection.fromSlave = fromSlave; + connection.fromVr = fromVr; + connection.toVrs = toVrs; + connection.toSlaves = toSlaves; + connections.push_back(connection); +} + +void DcpMaster::start() { + std::thread b(&DcpManagerMaster::start, manager); + std::chrono::seconds dura(1); + std::this_thread::sleep_for(dura); + //driver->getDcpDriver().connectToSlave(1); + std::cout << "Register Slaves" << std::endl; + for(size_t i=0; iSTC_register(u_char(i+1), DcpState::ALIVE, convertToUUID(slaveDescriptions[i]->uuid), DcpOpMode::NRT, 1, 0); + } + b.join(); +} + +void DcpMaster::initialize() { + slavesWaitingForInitialize++; + if(slavesWaitingForInitialize < slaveDescriptions.size()) { + return; + } + std::cout << "Initialize Slaves" << std::endl; + for(size_t i=0; iSTC_initialize(u_char(i), DcpState::CONFIGURED); + } + intializationRuns++; +} + +void DcpMaster::configuration() { + slavesWaitingForConfiguration++; + if(slavesWaitingForConfiguration < slaveDescriptions.size()) { + return; + } + + std::cout << "Configure Slaves" << std::endl; + + //Count received acks so that we know when all configuration messages are acknowledged + for(size_t i=0; iCFG_scope(fromSlaveId, dataId, DcpScope::Initialization_Run_NonRealTime); + manager->CFG_output(fromSlaveId, dataId, 0, connections[i].fromVr); + manager->CFG_steps(fromSlaveId, dataId, 1); + numOfCmd[fromSlaveId] += 4; + + for(size_t j=0; jCFG_scope(toSlaveId, dataId, DcpScope::Initialization_Run_NonRealTime); + manager->CFG_input(toSlaveId, dataId, 0, connections[i].toVrs[j], DcpDataType::float64); + manager->CFG_steps(toSlaveId, dataId, 1); + manager->CFG_source_network_information_UDP(toSlaveId, dataId, asio::ip::address_v4::from_string(*slaveDescriptions[toSlaveId-1]->TransportProtocols.UDP_IPv4->Control->host).to_uint(), *slaveDescriptions[toSlaveId-1]->TransportProtocols.UDP_IPv4->Control->port+1); + manager->CFG_target_network_information_UDP(fromSlaveId, dataId, asio::ip::address_v4::from_string(*slaveDescriptions[toSlaveId-1]->TransportProtocols.UDP_IPv4->Control->host).to_uint(), *slaveDescriptions[toSlaveId-1]->TransportProtocols.UDP_IPv4->Control->port); + numOfCmd[toSlaveId] += 4; + } + } +} + +void DcpMaster::configure() { + slavesWaitingForConfigure++; + if(slavesWaitingForConfigure < slaveDescriptions.size()) { + return; + } + for(size_t i=0; iSTC_configure(u_char(i+1), DcpState::PREPARED); + } +} + +void DcpMaster::run(DcpState currentState, uint8_t sender) { + std::cout << "Run Simulation" << std::endl; + std::time_t now = std::time(nullptr); + manager->STC_run(sender, currentState, now + 2); +} + +void DcpMaster::doStep() { + slavesWaitingForStep++; + if(slavesWaitingForStep < slaveDescriptions.size()) { + return; + } + slavesWaitingForStep = 0; + for(size_t i=0; iSTC_do_step(u_char(i+1),DcpState::RUNNING,1); + } +} + +void DcpMaster::stop() { + std::chrono::seconds dura(secondsToSimulate + 2); + std::this_thread::sleep_for(dura); + std::cout << "Stop Simulation" << std::endl; + for(size_t i=0; iSTC_stop(u_char(i+1), DcpState::RUNNING); + } +} + +void DcpMaster::deregister() { + slavesWaitingForDeregister++; + if(slavesWaitingForDeregister < slaveDescriptions.size()) { + return; + } + std::cout << "Deregister Slave" << std::endl; + for(size_t i=0; iSTC_deregister(u_char(i+1), DcpState::STOPPED); + } +} + +void DcpMaster::sendOutputs(DcpState currentState, uint8_t sender) { + std::cout << "Send Outputs" << std::endl; + manager->STC_send_outputs(sender, currentState); +} + +void DcpMaster::receiveAck(uint8_t sender, uint16_t pduSeqId) { + (void)pduSeqId; + std::cout << "receiveAck()\n"; + receivedAcks[sender]++; + if (receivedAcks[sender] == numOfCmd[sender]) { + manager->STC_prepare(sender, DcpState::CONFIGURATION); + } +} + +void DcpMaster::receiveNAck(uint8_t sender, uint16_t pduSeqId, DcpError errorCode) { + (void)sender; + (void)pduSeqId; + (void)errorCode; + std::cerr << "Error in slave configuration." << std::endl; + std::exit(1); +} + + + +void DcpMaster::dataReceived(uint16_t dataId, size_t length, uint8_t payload[]) { + (void)length; + (void)payload; +} + +void DcpMaster::receiveStateChangedNotification(uint8_t sender, + DcpState state) { + switch (state) { + case DcpState::CONFIGURATION: + configuration(); + break; + + case DcpState::CONFIGURED: + if (intializationRuns < maxInitRuns) { + initialize(); + + } else { + run(DcpState::CONFIGURED, sender); + } + break; + + case DcpState::SYNCHRONIZED: + run(DcpState::SYNCHRONIZED, sender); + break; + + case DcpState::PREPARED: + configure(); + break; + + case DcpState::INITIALIZED: + sendOutputs(DcpState::INITIALIZED, sender); + break; + + case DcpState::RUNNING: + if(nSteps>10000) { + stop(); + } + else { + ++nSteps; + doStep(); + } + break; + + case DcpState::COMPUTED: + sendOutputs(DcpState::COMPUTED, sender); + break; + + case DcpState::STOPPED: + deregister(); + break; + + case DcpState::ALIVE: + //simulation finished + slavesWaitingAtExit++; + if(slavesWaitingAtExit < 2) { + return; + } + std::exit(0); + + case DcpState::PREPARING: + default: + break; + } +} + diff --git a/hopsandcp/dcpmaster.h b/hopsandcp/dcpmaster.h new file mode 100644 index 0000000000..48f0b12f00 --- /dev/null +++ b/hopsandcp/dcpmaster.h @@ -0,0 +1,79 @@ +#ifndef DCPMASTER_H +#define DCPMASTER_H + +//#include "dcp/model/DcpTypes.hpp" +#include "dcp/model/constant/DcpState.hpp" +//#include "dcp/xml/DcpSlaveDescriptionElements.hpp" +#include "dcp/model/constant/DcpError.hpp" +#include "dcp/log/OstreamLog.hpp" + +#include +#include + +using namespace std; + +class DcpManagerMaster; +class UdpDriver; +class SlaveDescription_t; + +struct DcpConnection +{ + size_t fromSlave, fromVr; + std::vector toSlaves, toVrs; +}; + +class DcpMaster +{ +public: + DcpMaster(const string host, u_short port); + ~DcpMaster(); + + void addSlave(std::string &filepath); + void addConnection(size_t fromId, size_t fromVr, std::vector toIds, std::vector toVrs); + + void start(); +private: + void initialize(); + void configuration(); + void configure(); + void run(DcpState currentState, uint8_t sender); + void doStep(); + void stop(); + void deregister(); + void sendOutputs(DcpState currentState, uint8_t sender); + void receiveAck(uint8_t sender, uint16_t); + void receiveNAck(uint8_t sender, uint16_t pduSeqId, DcpError errorCode); + void dataReceived(uint16_t dataId, size_t length, uint8_t payload[]); + void receiveStateChangedNotification(uint8_t sender, DcpState state); + + std::vector connections; + + uint8_t maxInitRuns = 0; + uint8_t intializationRuns = 1; + + std::map curState; + + UdpDriver *driver; + + OstreamLog stdLog; + + DcpManagerMaster *manager; + + uint64_t nSteps=0; + uint64_t secondsToSimulate = 10; + std::map numOfCmd; + std::map receivedAcks; + + + std::vector slaveDescriptions; + + uint8_t slavesWaitingForConfigure = 0; + uint8_t slavesWaitingForStep = 0; + uint8_t slavesWaitingForConfiguration = 0; + uint8_t slavesWaitingAtExit = 0; + uint8_t slavesWaitingForDeregister = 0; + uint8_t slavesWaitingForInitialize = 0; + uint8_t slavesWaitingToRun = 0; +}; + +#endif // DCPMASTER_H diff --git a/hopsandcp/hopsandcp.pro b/hopsandcp/hopsandcp.pro index 9d2f830947..e845c8fc80 100644 --- a/hopsandcp/hopsandcp.pro +++ b/hopsandcp/hopsandcp.pro @@ -8,7 +8,8 @@ TEMPLATE = app CONFIG += shared DESTDIR = $${PWD}/../bin TARGET = $${TARGET}$${DEBUG_EXT} -DEFINES += DEBUG +DEFINES += LOGGING +#DEFINES += DEBUG QMAKE_CXXFLAGS = -Wno-comment -Wno-switch -Wno-ignored-qualifiers -Wno-sign-compare QT -= core gui @@ -84,10 +85,11 @@ unix { # Project files # ------------------------------------------------- SOURCES = \ + dcpmaster.cpp \ dcpslave.cpp \ main.cpp HEADERS += \ - dcpslave.h \ - include/hopsandcp.h + dcpmaster.h \ + dcpslave.h diff --git a/hopsandcp/main.cpp b/hopsandcp/main.cpp index d6692f675c..809ffc93eb 100644 --- a/hopsandcp/main.cpp +++ b/hopsandcp/main.cpp @@ -1,9 +1,10 @@ -//#include "hopsandcp.h" #include "dcpslave.h" +#include "dcpmaster.h" #include #include +#include using namespace std; @@ -13,20 +14,25 @@ int main(int argc, char* argv[]) // Define a value argument and add it to the command line. TCLAP::SwitchArg argMakeDescription("d","description","Generate DCP desciption file",cmd); - TCLAP::SwitchArg argSlave("s","slave","Run model in slave mode",cmd); - TCLAP::ValueArg argModelFile("m","model","Hopsan model file",false, "", "", cmd); + TCLAP::SwitchArg argSlave("s","slave","Execute simulation in slave mode",cmd); + TCLAP::SwitchArg argMaster("m","master","Execute simulation in master mode",cmd); + TCLAP::ValueArg argModelFile("i","input","Input Hopsan model file",false, "", "", cmd); TCLAP::ValueArg argTargetDescriptionFile("t","target","Target file for DCP description",false, "", "", cmd); TCLAP::ValueArg argHost("a","address","Host address",false,"127.0.0.1","",cmd); TCLAP::ValueArg argPort("p","port","Port",false,8080,"",cmd); + TCLAP::MultiArg argRemoteSlave("r","remote","Connect to remote slave",false,"",cmd); + TCLAP::MultiArg argConnect("c","connect","Add connection (fromSlave,fromVr,toSlave1,toVr1,toSlave2,toVr2...)",false,"",cmd); // Parse the argv array. cmd.parse( argc, argv ); - if(argMakeDescription.isSet() && argSlave.isSet()) { - cout << "Cannot both generate description and run as slave.\n"; + if((argMakeDescription.isSet() && (argSlave.isSet() || argMaster.isSet())) || + (argSlave.isSet() && (argMakeDescription.isSet() || argMaster.isSet())) || + (argMaster.isSet() && (argSlave.isSet() || argMakeDescription.isSet()))) { + cout << "Cannot only run in one mode at a time (make description, slave or master).\n"; return -1; } - //GEnerate DCP description file + //Generate DCP description file if(argMakeDescription.isSet()) { if(!argModelFile.isSet()) { cout << "Generating a DCP description requires a model file.\n"; @@ -56,21 +62,69 @@ int main(int argc, char* argv[]) //Run a simulation as slave if(argSlave.isSet()) { if(!argModelFile.isSet()) { - cout << "Generating a DCP description requires a model file.\n"; + cout << "Running in slave mode requires a model file.\n"; return -1; } if(!argHost.isSet()) { - cout << "Generating a DCP description requires a host address.\n"; + cout << "Running in slave mode requires a host address.\n"; return -1; } if(!argPort.isSet()) { - cout << "Generating a DCP description requires a port.\n"; + cout << "Running in slave mode requires requires a port.\n"; return -1; } DcpSlave *pSlave = new DcpSlave(argModelFile.getValue(),argHost.getValue(),argPort.getValue()); pSlave->start(); } + //Run a simulation as master + if(argMaster.isSet()) { + if(!argHost.isSet()) { + cout << "Running in master mode requires a host address.\n"; + return -1; + } + if(!argPort.isSet()) { + cout << "Running in master mode requires requires a port.\n"; + return -1; + } + + DcpMaster *pMaster = new DcpMaster(argHost.getValue(), argPort.getValue()); + for(auto slave : argRemoteSlave.getValue()) { + pMaster->addSlave(slave); + } + for(auto connection : argConnect.getValue()) { + std::deque ids; + std::stringstream ss(connection); + for (size_t i; ss >> i;) { + ids.push_back(i); + if (ss.peek() == ',') { + ss.ignore(); + } + } + if(ids.size() < 4) { + cout << "A connection must have at least one sender and one receiver.\n"; + return -1; + } + + size_t fromSlave = ids[0]; + size_t fromVr = ids[1]; + ids.pop_front(); + ids.pop_front(); + std::vector toSlaves, toVrs; + for(size_t i=0; iaddConnection(fromSlave, fromVr, toSlaves, toVrs); + } + + pMaster->start(); + } std::cout << "hopsandcp completed successfully!\n"; From 6f8a543238365e697bffd414aaeec5cec791c0e5 Mon Sep 17 00:00:00 2001 From: Robert Braun Date: Tue, 12 Jan 2021 11:40:29 +0100 Subject: [PATCH 09/34] Result logging from hopsandcp --- hopsandcp/dcpslave.cpp | 14 ++++- hopsandcp/dcpslave.h | 4 +- hopsandcp/hopsandcp.pro | 6 +- hopsandcp/main.cpp | 4 +- hopsandcp/utilities.cpp | 132 ++++++++++++++++++++++++++++++++++++++++ hopsandcp/utilities.h | 116 +++++++++++++++++++++++++++++++++++ 6 files changed, 270 insertions(+), 6 deletions(-) create mode 100644 hopsandcp/utilities.cpp create mode 100644 hopsandcp/utilities.h diff --git a/hopsandcp/dcpslave.cpp b/hopsandcp/dcpslave.cpp index 78b0b84acc..4e7f500f8f 100644 --- a/hopsandcp/dcpslave.cpp +++ b/hopsandcp/dcpslave.cpp @@ -1,4 +1,5 @@ #include "dcpslave.h" +#include "utilities.h" #include #include @@ -30,8 +31,8 @@ const LogTemplate SIM_LOG = LogTemplate( using namespace hopsan; -DcpSlave::DcpSlave(const std::string modelfile, const std::string host, int port) - : mHost(host), mPort(port) +DcpSlave::DcpSlave(const std::string modelfile, const std::string host, int port, std::string resultFile) + : mHost(host), mPort(port), mResultFile(resultFile) { //Create Hopsan object mpHopsanCore = new HopsanEssentials(); @@ -93,6 +94,8 @@ DcpSlave::DcpSlave(const std::string modelfile, const std::string host, int port mManager->setTimeResListener(std::bind(&DcpSlave::setTimeRes, this, std::placeholders::_1, std::placeholders::_2)); + mManager->setStopCallback( + std::bind(&DcpSlave::stop, this)); //Display log messages on console stdLog = new OstreamLog(std::cout); @@ -232,3 +235,10 @@ void DcpSlave::doStep(uint64_t steps) { void DcpSlave::setTimeRes(const uint32_t numerator, const uint32_t denominator) { mpRootSystem->setDesiredTimestep(double(numerator)/double(denominator)); } + +void DcpSlave::stop() +{ + if(!mResultFile.empty()) { + saveResultsToCSV(mpRootSystem, mResultFile, SaveResults::Full, std::vector()); + } +} diff --git a/hopsandcp/dcpslave.h b/hopsandcp/dcpslave.h index cbb5c64ea7..8190812f25 100644 --- a/hopsandcp/dcpslave.h +++ b/hopsandcp/dcpslave.h @@ -17,7 +17,7 @@ class OstreamLog; class DcpSlave { public: - DcpSlave(const std::string modelfile, const std::string host, int port); + DcpSlave(const std::string modelfile, const std::string host, int port, std::string resultFile=""); ~DcpSlave(); void generateDescriptionFile(std::string &targetFile); @@ -34,6 +34,7 @@ class DcpSlave std::vector mInputDataPtrs, mOutputDataPtrs; std::string mHost = "127.0.0.1"; int mPort = 8080; + std::string mResultFile; DcpManagerSlave *mManager; OstreamLog *stdLog; UdpDriver* udpDriver; @@ -43,6 +44,7 @@ class DcpSlave void initialize(); void doStep(uint64_t steps); void setTimeRes(const uint32_t numerator, const uint32_t denominator); + void stop(); }; #endif // DCPSLAVE_H diff --git a/hopsandcp/hopsandcp.pro b/hopsandcp/hopsandcp.pro index e845c8fc80..d5775c0bcd 100644 --- a/hopsandcp/hopsandcp.pro +++ b/hopsandcp/hopsandcp.pro @@ -87,9 +87,11 @@ unix { SOURCES = \ dcpmaster.cpp \ dcpslave.cpp \ - main.cpp + main.cpp \ + utilities.cpp HEADERS += \ dcpmaster.h \ - dcpslave.h + dcpslave.h \ + utilities.h diff --git a/hopsandcp/main.cpp b/hopsandcp/main.cpp index 809ffc93eb..4c2491fabf 100644 --- a/hopsandcp/main.cpp +++ b/hopsandcp/main.cpp @@ -73,7 +73,9 @@ int main(int argc, char* argv[]) cout << "Running in slave mode requires requires a port.\n"; return -1; } - DcpSlave *pSlave = new DcpSlave(argModelFile.getValue(),argHost.getValue(),argPort.getValue()); + std::string resultFile = argModelFile.getValue(); + resultFile = resultFile.substr(0,resultFile.find_last_of('.'))+".csv"; + DcpSlave *pSlave = new DcpSlave(argModelFile.getValue(),argHost.getValue(),argPort.getValue(),resultFile); pSlave->start(); } diff --git a/hopsandcp/utilities.cpp b/hopsandcp/utilities.cpp new file mode 100644 index 0000000000..a6a511e867 --- /dev/null +++ b/hopsandcp/utilities.cpp @@ -0,0 +1,132 @@ +/*----------------------------------------------------------------------------- + + Copyright 2017 Hopsan Group + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + The full license is available in the file LICENSE. + For details about the 'Hopsan Group' or information about Authors and + Contributors see the HOPSANGROUP and AUTHORS files that are located in + the Hopsan source code root directory. + +-----------------------------------------------------------------------------*/ + +//! +//! @file utilities.cpp +//! @brief Contains utilities for hopsandcp +//! + +#include +#include +#include + +#include "utilities.h" + +#include "HopsanEssentials.h" +#include "HopsanTypes.h" + +using namespace std; +using namespace hopsan; + +void generateFullSubSystemHierarchyName(const ComponentSystem *pSys, HString &rFullSysName, const HString& separator) +{ + if (pSys->getSystemParent()) + { + generateFullSubSystemHierarchyName(pSys->getSystemParent(), rFullSysName, separator); + rFullSysName.append(pSys->getName()).append(separator); + } + else + { + // Do not include top-level name in sub-system hierarchy + rFullSysName.clear(); + } +} + +HString generateFullSubSystemHierarchyName(const Component *pComponent, const HString &separator, bool includeLastSeparator) +{ + const ComponentSystem* pSystem = pComponent->isComponentSystem() ? dynamic_cast(pComponent) : pComponent->getSystemParent(); + + HString fullSysName; + generateFullSubSystemHierarchyName(pSystem, fullSysName, separator); + if (!includeLastSeparator && !fullSysName.empty()) { + fullSysName.erase(fullSysName.size()-separator.size(),separator.size()); + } + return fullSysName; +} + +//! @brief Save results to CSV format +//! @param [in] pRootSystem Pointer to component system +//! @param [in] rFileName File name for output file +//! @param [in] howMany Specifies if all results or only final values should be saved +//! @param [in] includeFilter list of full port names or variables names to include (excluding all others) +void saveResultsToCSV(ComponentSystem *pRootSystem, const string &rFileName, const SaveResults howMany, const std::vector& includeFilter) +{ + if (pRootSystem) + { + ofstream outfile; + outfile.open(rFileName.c_str()); + if (outfile.good()) { + + auto addTimeVariable = [&outfile, howMany](ComponentSystem* pSystem) { + //! @todo alias a for time ? is that even posible + HString parentSystemNames = generateFullSubSystemHierarchyName(pSystem,"$"); + if (howMany == Final) { + outfile << parentSystemNames.c_str() << "Time,,s," << std::scientific << pSystem->getTime() << endl; + } + else if (howMany == Full) { + vector *pLogTimeVector = pSystem->getLogTimeVector(); + if (pLogTimeVector->size() > 0) { + outfile << parentSystemNames.c_str() << "Time,,s"; + for (size_t t=0; tgetNumActuallyLoggedSamples(); ++t) { + outfile << "," << std::scientific << (*pLogTimeVector)[t]; + } + outfile << endl; + } + } + }; + + auto addVariable = [&outfile, howMany](const ComponentSystem* pSystem, const Component* pComponent, const Port* pPort, size_t variableIndex) { + const NodeDataDescription& variable = *pPort->getNodeDataDescription(variableIndex); + const vector< vector > *pLogData = pPort->getLogDataVectorPtr(); + if( (pLogData != nullptr) && !pLogData->empty()) { + const HString fullVarName = generateFullSubSystemHierarchyName(pSystem,"$") + pComponent->getName() + "#" + pPort->getName() + "#" + variable.name; + if (howMany == Final) { + outfile << fullVarName.c_str() << "," << pPort->getVariableAlias(variableIndex).c_str() << "," << variable.unit.c_str(); + outfile << "," << std::scientific << pPort->readNode(variableIndex) << endl; + } + else if (howMany == Full) + { + // Only write something if data has been logged (skip ports that are not logged) + // We assume that the data vector has been cleared + if (pPort->getLogDataVectorPtr()->size() > 0) { + outfile << fullVarName.c_str() << "," << pPort->getVariableAlias(variableIndex).c_str() << "," << variable.unit.c_str(); + for (size_t t=0; tgetNumActuallyLoggedSamples(); ++t) { + outfile << "," << std::scientific << (*pLogData)[t][variableIndex]; + } + outfile << endl; + } + } + } + }; + + saveResultsTo(pRootSystem, includeFilter, addTimeVariable, addVariable); + + } + else { + std::cout << "Could not open: " << rFileName << " for writing!\n"; + } + + outfile.close(); + } +} diff --git a/hopsandcp/utilities.h b/hopsandcp/utilities.h new file mode 100644 index 0000000000..46ae8fdf0b --- /dev/null +++ b/hopsandcp/utilities.h @@ -0,0 +1,116 @@ +/*----------------------------------------------------------------------------- + + Copyright 2017 Hopsan Group + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + The full license is available in the file LICENSE. + For details about the 'Hopsan Group' or information about Authors and + Contributors see the HOPSANGROUP and AUTHORS files that are located in + the Hopsan source code root directory. + +-----------------------------------------------------------------------------*/ + +//! +//! @file utilities.h +//! @brief Contains utilities for hopsandcp +//! +//$Id$ + +#ifndef UTILITIES_H +#define UTILITIES_H + +#include +#include "HopsanEssentials.h" + + + +enum SaveResults {Final, Full}; +void generateFullSubSystemHierarchyName(const hopsan::ComponentSystem *pSys, hopsan::HString &rFullSysName, const hopsan::HString &separator); +hopsan::HString generateFullSubSystemHierarchyName(const hopsan::Component *pComponent, const hopsan::HString &separator, bool includeLastSeparator=true); +void saveResultsToCSV(hopsan::ComponentSystem *pRootSystem, const std::string &rFileName, const SaveResults howMany, const std::vector& includeFilter); + +template +bool contains(const ContainerT& container, const ValueT& value) { + auto it = std::find(container.begin(), container.end(), value); + return (it != container.end()); +} + +template +void saveResultsTo(hopsan::ComponentSystem *pCurrentSystem, const std::vector& includeFilter, SaveTimeFunc writeTime, + SaveVariableFunc writeVariable ) +{ + hopsan::HString prefix = generateFullSubSystemHierarchyName(pCurrentSystem, "$"); //!< @todo not necessary every time if we use recursion instead + + // Use names to get components in alphabeteical order + const std::vector componentNames = pCurrentSystem->getSubComponentNames(); + size_t numberOfLoggedComponentsInThisSystem = 0; + for (const auto& name : componentNames) { + hopsan::Component *pComponent = pCurrentSystem->getSubComponent(name); + + size_t numberOfLoggedVariablesInThisComponent = 0; + const std::vector ports = pComponent->getPortPtrVector(); + for (const hopsan::Port* pPort : ports) { + // Ignore ports that have logging disabled + if (!pPort->isLoggingEnabled()) { + continue; + } + + hopsan::HString fullPortName = prefix + pComponent->getName() + "#" + pPort->getName(); + const bool includeAllVariablesInThisPort = (includeFilter.empty() || contains(includeFilter, fullPortName.c_str())) && + pPort->isLoggingEnabled(); + + const std::vector *pVariables = pPort->getNodeDataDescriptions(); // TODO do not return pointer + if (pVariables) + { + for (size_t v=0; vsize(); ++v) + { + const hopsan::NodeDataDescription* pVariable = &pVariables->at(v); + + // Create data vector + const std::vector< std::vector > *pLogData = pPort->getLogDataVectorPtr(); + if(pLogData == nullptr || pLogData->empty()) { + continue; + } + + hopsan::HString fullVarName = fullPortName+"#"+pVariable->name; + const bool includeThisVariable = includeAllVariablesInThisPort || contains(includeFilter, fullVarName.c_str()); + if (!includeThisVariable) { + continue; + } + + // Add variable to exporter + writeVariable(pCurrentSystem, pComponent, pPort, v); + + numberOfLoggedVariablesInThisComponent++; + } + } + } + if (numberOfLoggedVariablesInThisComponent > 0) { + numberOfLoggedComponentsInThisSystem++; + } + + // Recurse into subsystems + if (pComponent->isComponentSystem()) { + saveResultsTo(dynamic_cast(pComponent), includeFilter, writeTime, writeVariable); + } + } + + // Save this sytems time vector + if (numberOfLoggedComponentsInThisSystem > 0) { + writeTime(pCurrentSystem); + } + +} +#endif // UTILITIES_H From ca84b36683ce6de849bd2e5b4fe769cde5ca26c0 Mon Sep 17 00:00:00 2001 From: Robert Braun Date: Tue, 9 Feb 2021 12:10:14 +0100 Subject: [PATCH 10/34] Change hopsandcp to lib and supprort DCP slaves in GUI --- HopsanGUI/HopsanGUI.pro | 7 ++ HopsanGUI/MainWindow.cpp | 4 + HopsanGUI/MainWindow.h | 1 + HopsanGUI/ModelHandler.cpp | 1 + HopsanGUI/SimulationThreadHandler.cpp | 48 +++++++++ HopsanGUI/SimulationThreadHandler.h | 21 +++- HopsanGUI/Widgets/ModelWidget.cpp | 53 ++++++++++ HopsanGUI/Widgets/ModelWidget.h | 1 + hopsandcp/hopsandcp.pro | 16 +-- hopsandcp/{ => include}/dcpmaster.h | 7 +- hopsandcp/{ => include}/dcpslave.h | 14 +-- hopsandcp/include/hopsandcp_win32dll.h | 53 ++++++++++ hopsandcp/{ => include}/utilities.h | 0 hopsandcp/main.cpp | 134 ------------------------- hopsandcp/{ => src}/dcpmaster.cpp | 9 +- hopsandcp/{ => src}/dcpslave.cpp | 65 +++--------- hopsandcp/{ => src}/utilities.cpp | 0 17 files changed, 227 insertions(+), 207 deletions(-) rename hopsandcp/{ => include}/dcpmaster.h (94%) rename hopsandcp/{ => include}/dcpslave.h (74%) create mode 100644 hopsandcp/include/hopsandcp_win32dll.h rename hopsandcp/{ => include}/utilities.h (100%) delete mode 100644 hopsandcp/main.cpp rename hopsandcp/{ => src}/dcpmaster.cpp (98%) rename hopsandcp/{ => src}/dcpslave.cpp (83%) rename hopsandcp/{ => src}/utilities.cpp (100%) diff --git a/HopsanGUI/HopsanGUI.pro b/HopsanGUI/HopsanGUI.pro index 7b6e084f60..9262dac602 100644 --- a/HopsanGUI/HopsanGUI.pro +++ b/HopsanGUI/HopsanGUI.pro @@ -107,6 +107,13 @@ LIBS *= -L$${PWD}/../bin -lops$${DEBUG_EXT} DEFINES *= OPS_DLLIMPORT #-------------------------------------------------------- +#-------------------------------------------------------- +# Set Ops Paths +INCLUDEPATH *= $${PWD}/../hopsandcp/include/ +LIBS *= -L$${PWD}/../bin -lhopsandcp$${DEBUG_EXT} +DEFINES *= HOPSANDCP_DLLIMPORT +#-------------------------------------------------------- + #-------------------------------------------------------- # Set Discount (libmarkdown) paths include($${PWD}/../dependencies/discount.pri) diff --git a/HopsanGUI/MainWindow.cpp b/HopsanGUI/MainWindow.cpp index ae791fa740..0be857d94d 100644 --- a/HopsanGUI/MainWindow.cpp +++ b/HopsanGUI/MainWindow.cpp @@ -624,6 +624,9 @@ void MainWindow::createActions() mHelpPopupTextMap.insert(mpToggleRemoteCoreSimAction, "Connect or disconnect to a remote HopsanCore, this will determine if local or remote simulation is run, when calling simulate"); connect(mpToggleRemoteCoreSimAction, SIGNAL(hovered()), this, SLOT(showToolBarHelpPopup())); + mpSimulateDcpSlaveAction = new QAction(QIcon(QString(ICONPATH) + "svg/Hopsan-SimulateRemote.svg"), tr("Simulate Model as DCP Slave"), this); + mpSimulateDcpSlaveAction->setToolTip("Simulate Model as DCP Slave"); + mpOpenDebuggerAction = new QAction(QIcon(QString(ICONPATH) + "svg/Hopsan-Debug.svg"), tr("&Launch Debugger"), this); mpOpenDebuggerAction->setToolTip(tr("Launch Debugger")); connect(mpOpenDebuggerAction, SIGNAL(hovered()), this, SLOT(showToolBarHelpPopup())); @@ -1181,6 +1184,7 @@ void MainWindow::createToolbars() mpSimToolBar->addWidget(mpSimulationTimeEdit); mpSimToolBar->addAction(mpSimulateAction); mpSimToolBar->addAction(mpToggleRemoteCoreSimAction); + mpSimToolBar->addAction(mpSimulateDcpSlaveAction); mpSimToolBar->addAction(mpOpenDebuggerAction); mpSimToolBar->addAction(mpOptimizeAction); mpSimToolBar->addAction(mpSensitivityAnalysisAction); diff --git a/HopsanGUI/MainWindow.h b/HopsanGUI/MainWindow.h index f8969edc7e..c514c41418 100644 --- a/HopsanGUI/MainWindow.h +++ b/HopsanGUI/MainWindow.h @@ -220,6 +220,7 @@ class MainWindow : public QMainWindow QAction *mpShowLossesAction; QAction *mpMeasureSimulationTimeAction; QAction *mpToggleHideAllDockAreasAction; + QAction *mpSimulateDcpSlaveAction; QAction *mpDebug1Action; QAction *mpDebug2Action; diff --git a/HopsanGUI/ModelHandler.cpp b/HopsanGUI/ModelHandler.cpp index 83f2ffeb55..b0ed0de475 100644 --- a/HopsanGUI/ModelHandler.cpp +++ b/HopsanGUI/ModelHandler.cpp @@ -711,6 +711,7 @@ void ModelHandler::disconnectMainWindowConnections(ModelWidget *pModel) disconnect(gpMainWindow, SIGNAL(simulateKeyPressed()), pModel, SLOT(simulate_nonblocking())); disconnect(gpMainWindow->mpToggleRemoteCoreSimAction, SIGNAL(triggered(bool)), pModel, SLOT(setUseRemoteSimulation(bool))); + disconnect(gpMainWindow->mpSimulateDcpSlaveAction, SIGNAL(triggered()), pModel, SLOT(simulateDcpSlave())); disconnect(gpMainWindow->mpSaveAction, SIGNAL(triggered()), pModel, SLOT(save())); disconnect(gpMainWindow->mpSaveAsAction, SIGNAL(triggered()), pModel, SLOT(saveAs())); disconnect(gpMainWindow->mpExportModelParametersActionToHpf, SIGNAL(triggered()), pModel, SLOT(exportModelParametersToHpf())); diff --git a/HopsanGUI/SimulationThreadHandler.cpp b/HopsanGUI/SimulationThreadHandler.cpp index b7a6babf45..52132604b5 100644 --- a/HopsanGUI/SimulationThreadHandler.cpp +++ b/HopsanGUI/SimulationThreadHandler.cpp @@ -38,6 +38,7 @@ #include "common.h" #include "global.h" #include "GUIObjects/GUIContainerObject.h" +#include "dcpslave.h" namespace { @@ -244,6 +245,11 @@ void ProgressBarWorkerObject::setProgressBarState(SimulationState state) emit setProgressBarText(tr("Simulating...")); emit setProgressBarRange(0, 0); break; + case SimulationState::DcpSlaveSimulate: + emit setProgressBarText(tr("Running DCP simulation...")); + emit setProgressBarRange(0, 0); + startRefreshTimer(gpConfig->getProgressBarStep()); + break; case SimulationState::Finalize: stopRefreshTimer(); emit setProgressBarText(tr("Finalizing...")); @@ -329,6 +335,15 @@ void SimulationThreadHandler::initSimulateFinalizeRemote(SharedRemoteCoreSimulat } #endif +void SimulationThreadHandler::initSimulateFinalizeDcpSlave(SystemObject* pSystem, const QString &host, int port, const QString &targetFile) +{ + mvpSystems.clear(); + mvpSystems.push_back(pSystem); + mpSimulationWorkerObject = new DCPSlaveSimulationWorkerObject(pSystem, host, port, targetFile); + mpSimulationWorkerObject->setMessageHandler(mpMessageHandler); + initSimulateFinalizePrivate(); +} + void SimulationThreadHandler::initSimulateFinalize(QVector vpSystems, const bool noChanges) { mvpSystems = vpSystems; @@ -551,3 +566,36 @@ void SimulationThreadHandler::setMessageHandler(GUIMessageHandler *pMessageHandl { mpMessageHandler = pMessageHandler; } + +DCPSlaveSimulationWorkerObject::DCPSlaveSimulationWorkerObject(SystemObject *pSystem, const QString &host, int port, const QString &targetFile) +{ + mpSystem = pSystem; + mHost = host; + mPort = port; + mTargetFile = targetFile; +} + +void DCPSlaveSimulationWorkerObject::initSimulateFinalize() +{ + QTime timer; + DcpSlave *pDcpSlave = new DcpSlave(mpSystem->getCoreSystemAccessPtr()->getCoreSystemPtr(), mHost.toStdString(), mPort, mpSystem->getNumberOfLogSamples()); + + // Initializing + emit setProgressState(SimulationState::Initialize); + timer.start(); + pDcpSlave->generateDescriptionFile(mTargetFile.toStdString()); + emit initDone(true, timer.elapsed()); + + // Simulating + emit setProgressState(SimulationState::DcpSlaveSimulate); + gpMessageHandler->addInfoMessage("Starting a DCP simulation..."); + bool success = pDcpSlave->start(); + gpMessageHandler->addInfoMessage("DCP simulation finished!"); + emit simulateDone(success, timer.elapsed()); + + // Finalizing + delete pDcpSlave; + // Finalizing + emit setProgressState(SimulationState::Finalize); + emit finalizeDone(true, timer.elapsed()); +} diff --git a/HopsanGUI/SimulationThreadHandler.h b/HopsanGUI/SimulationThreadHandler.h index 75229f2fbc..f4a6ea4929 100644 --- a/HopsanGUI/SimulationThreadHandler.h +++ b/HopsanGUI/SimulationThreadHandler.h @@ -47,8 +47,8 @@ class GUIMessageHandler; #include "RemoteCoreAccess.h" #endif -enum SimulationWorkeObjectEnumT {LocalSWO, RemoteSWO}; -enum class SimulationState {Initialize, Simulate, RemoteSimulate, Finalize, Done}; +enum SimulationWorkeObjectEnumT {LocalSWO, RemoteSWO, DCPSlaveSWO}; +enum class SimulationState {Initialize, Simulate, RemoteSimulate, DcpSlaveSimulate, Finalize, Done}; Q_DECLARE_METATYPE(SimulationState); @@ -111,6 +111,22 @@ public slots: }; #endif +class DCPSlaveSimulationWorkerObject : public SimulationWorkerObjectBase +{ + Q_OBJECT +private: + SystemObject *mpSystem; + QString mHost; + int mPort; + QString mTargetFile; +public: + DCPSlaveSimulationWorkerObject(SystemObject *pSystem, const QString &host, int port, const QString &targetFile); + int swoType() const {return DCPSlaveSWO;} + +public slots: + void initSimulateFinalize(); +}; + class ProgressBarWorkerObject : public QObject { Q_OBJECT @@ -198,6 +214,7 @@ protected slots: #ifdef USEZMQ void initSimulateFinalizeRemote(SharedRemoteCoreSimulationHandlerT pRCSH, QVector *pRemoteResultVariables, double *pProgress); #endif + void initSimulateFinalizeDcpSlave(SystemObject *pSystem, const QString &host, int port, const QString &targetFile); void initSimulateFinalize(QVector vpSystems, const bool noChanges=false); void initSimulateFinalize_blocking(QVector vpSystems, const bool noChanges=false); bool wasSuccessful(); diff --git a/HopsanGUI/Widgets/ModelWidget.cpp b/HopsanGUI/Widgets/ModelWidget.cpp index 0f70c43465..de700ffb51 100644 --- a/HopsanGUI/Widgets/ModelWidget.cpp +++ b/HopsanGUI/Widgets/ModelWidget.cpp @@ -40,6 +40,8 @@ #include #include #include +#include +#include //Hopsan includes @@ -715,6 +717,57 @@ void ModelWidget::stopRealtimeSimulation() mCoreSimulationHandler.stopRealtimeSimulation(mpToplevelSystem->getCoreSystemAccessPtr()); mCoreSimulationHandler.finalize(mpToplevelSystem->getCoreSystemAccessPtr()); mSimulateMutex.unlock(); + +bool ModelWidget::simulateDcpSlave() +{ + // Save backup copy + if (!isSaved() && gpConfig->getBoolSetting(CFG_AUTOBACKUP)) + { + //! @todo this should be a help function, also we may not want to call it every time when we run optimization (not sure if that is done now but probably) + QString fileNameWithoutHmf = mpToplevelSystem->getModelFileInfo().fileName(); + fileNameWithoutHmf.chop(4); + saveTo(gpDesktopHandler->getBackupPath() + fileNameWithoutHmf + "_sim_backup.hmf"); + } + + QDialog */*pDcpSlaveDialog*/pDialog = new QDialog(gpMainWindowWidget); + QGridLayout */*pDcpSlaveDialogLayout*/pLayout = new QGridLayout(pDialog); + QLineEdit *pHostLineEdit = new QLineEdit("127.0.0.1",pDialog); + QSpinBox *pPortSpinBox = new QSpinBox(pDialog); + pPortSpinBox->setMaximum(1000000); + pPortSpinBox->setValue(8080); + pPortSpinBox->setSingleStep(1); + QLineEdit *pTargetFileLineEdit = new QLineEdit(gpDesktopHandler->getDocumentsPath()+"/"+getTopLevelSystemContainer()->getModelFileInfo().baseName()+".dcpx"); + QDialogButtonBox *pButtonBox = new QDialogButtonBox(pDialog); + QPushButton *pOkButton = pButtonBox->addButton(QDialogButtonBox::Ok); + QPushButton *pCancelButton = pButtonBox->addButton(QDialogButtonBox::Cancel); + connect(pOkButton, SIGNAL(clicked()), pDialog, SLOT(accept())); + connect(pCancelButton, SIGNAL(clicked()), pDialog, SLOT(reject())); + pLayout->addWidget(new QLabel("Host address:",pDialog),0,0); + pLayout->addWidget(pHostLineEdit,0,1,1,2); + pLayout->addWidget(new QLabel("Port:",pDialog),1,0); + pLayout->addWidget(pPortSpinBox,1,1,1,2); + pLayout->addWidget(new QLabel("XML output file:",pDialog),2,0); + pLayout->addWidget(pTargetFileLineEdit,2,1,1,2); + pLayout->addWidget(pButtonBox, 3,1,1,3); + + if(pDialog->exec() == QDialog::Rejected) { + return false; + } + + if(!mSimulateMutex.tryLock()) + { + gpMessageHandler->addErrorMessage("Simulation mutex is locked. Aborting."); + return false; + } + + mpSimulationThreadHandler->setSimulationTimeVariables(mStartTime.toDouble(), mStopTime.toDouble(), mpToplevelSystem->getLogStartTime(), mpToplevelSystem->getNumberOfLogSamples()); + mpSimulationThreadHandler->setProgressDilaogBehaviour(true, false); + mSimulationProgress=0; + mpSimulationThreadHandler->initSimulateFinalizeDcpSlave(mpToplevelSystem, pHostLineEdit->text(), pPortSpinBox->value(), pTargetFileLineEdit->text()); + + + return true; + //! @todo fix return code } diff --git a/HopsanGUI/Widgets/ModelWidget.h b/HopsanGUI/Widgets/ModelWidget.h index 1bc89818bf..31b25054e0 100644 --- a/HopsanGUI/Widgets/ModelWidget.h +++ b/HopsanGUI/Widgets/ModelWidget.h @@ -121,6 +121,7 @@ public slots: bool simulate_blocking(); bool startRealtimeSimulation(const double realtimeFactor); void stopRealtimeSimulation(); + bool simulateDcpSlave(); void save(); void saveAs(); void exportModelParametersToHpf(); diff --git a/hopsandcp/hopsandcp.pro b/hopsandcp/hopsandcp.pro index d5775c0bcd..31c682c164 100644 --- a/hopsandcp/hopsandcp.pro +++ b/hopsandcp/hopsandcp.pro @@ -4,7 +4,7 @@ include( ../Common.prf ) TARGET = hopsandcp -TEMPLATE = app +TEMPLATE = lib CONFIG += shared DESTDIR = $${PWD}/../bin TARGET = $${TARGET}$${DEBUG_EXT} @@ -85,13 +85,13 @@ unix { # Project files # ------------------------------------------------- SOURCES = \ - dcpmaster.cpp \ - dcpslave.cpp \ - main.cpp \ - utilities.cpp + src/dcpmaster.cpp \ + src/dcpslave.cpp \ + src/utilities.cpp HEADERS += \ - dcpmaster.h \ - dcpslave.h \ - utilities.h + include/dcpmaster.h \ + include/dcpslave.h \ + include/hopsandcp_win32dll.h \ + include/utilities.h diff --git a/hopsandcp/dcpmaster.h b/hopsandcp/include/dcpmaster.h similarity index 94% rename from hopsandcp/dcpmaster.h rename to hopsandcp/include/dcpmaster.h index 48f0b12f00..696af5cd28 100644 --- a/hopsandcp/dcpmaster.h +++ b/hopsandcp/include/dcpmaster.h @@ -1,9 +1,9 @@ #ifndef DCPMASTER_H #define DCPMASTER_H -//#include "dcp/model/DcpTypes.hpp" +#include "hopsandcp_win32dll.h" + #include "dcp/model/constant/DcpState.hpp" -//#include "dcp/xml/DcpSlaveDescriptionElements.hpp" #include "dcp/model/constant/DcpError.hpp" #include "dcp/log/OstreamLog.hpp" @@ -22,7 +22,7 @@ struct DcpConnection std::vector toSlaves, toVrs; }; -class DcpMaster +HOPSANDCP_DLLAPI class DcpMaster { public: DcpMaster(const string host, u_short port); @@ -74,6 +74,7 @@ class DcpMaster uint8_t slavesWaitingForDeregister = 0; uint8_t slavesWaitingForInitialize = 0; uint8_t slavesWaitingToRun = 0; + uint8_t stoppedSlaves = 0; }; #endif // DCPMASTER_H diff --git a/hopsandcp/dcpslave.h b/hopsandcp/include/dcpslave.h similarity index 74% rename from hopsandcp/dcpslave.h rename to hopsandcp/include/dcpslave.h index 8190812f25..0ac6d3af16 100644 --- a/hopsandcp/dcpslave.h +++ b/hopsandcp/include/dcpslave.h @@ -1,6 +1,8 @@ #ifndef DCPSLAVE_H #define DCPSLAVE_H +#include "hopsandcp_win32dll.h" + #include #include @@ -14,27 +16,25 @@ class DcpManagerSlave; class UdpDriver; class OstreamLog; -class DcpSlave +HOPSANDCP_DLLAPI class DcpSlave { public: - DcpSlave(const std::string modelfile, const std::string host, int port, std::string resultFile=""); + DcpSlave(hopsan::ComponentSystem *pSystem, const std::string host, int port, size_t numLogSamples); ~DcpSlave(); - void generateDescriptionFile(std::string &targetFile); - void start(); + void generateDescriptionFile(std::string targetFile); + bool start(); private: - void printWaitingMessages(); SlaveDescription_t *getSlaveDescription(); - hopsan::HopsanEssentials *mpHopsanCore; hopsan::ComponentSystem *mpRootSystem; std::vector mInputs, mOutputs; std::vector mInputNodePtrs, mOutputNodePtrs; std::vector mInputDataPtrs, mOutputDataPtrs; std::string mHost = "127.0.0.1"; int mPort = 8080; - std::string mResultFile; + size_t mNumLogSamples = 0; DcpManagerSlave *mManager; OstreamLog *stdLog; UdpDriver* udpDriver; diff --git a/hopsandcp/include/hopsandcp_win32dll.h b/hopsandcp/include/hopsandcp_win32dll.h new file mode 100644 index 0000000000..ae05c43550 --- /dev/null +++ b/hopsandcp/include/hopsandcp_win32dll.h @@ -0,0 +1,53 @@ +/*----------------------------------------------------------------------------- + + Copyright 2017 Hopsan Group + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + The full license is available in the file LICENSE. + For details about the 'Hopsan Group' or information about Authors and + Contributors see the HOPSANGROUP and AUTHORS files that are located in + the Hopsan source code root directory. + +-----------------------------------------------------------------------------*/ + +//! +//! @file win32dll.h +//! +//! @brief Defines macro for DLL symbol export and import +//! + +//$Id$ + +#ifndef HOPSANDCP_WIN32DLL_H +#define HOPSANDCP_WIN32DLL_H + +#ifdef _WIN32 + +#if defined HOPSANDCP_DLLEXPORT +#define HOPSANDCP_DLLAPI __declspec(dllexport) +#elif defined HOPSANDCP_DLLIMPORT +#define HOPSANDCP_DLLAPI __declspec(dllimport) +#else /*Symhop static library*/ +#define HOPSANDCP_DLLAPI +#endif + +#else + +// Define empty on non-windows systems +#define HOPSANDCP_DLLAPI + +#endif + +#endif // HOPSANDCP_WIN32DLL_H diff --git a/hopsandcp/utilities.h b/hopsandcp/include/utilities.h similarity index 100% rename from hopsandcp/utilities.h rename to hopsandcp/include/utilities.h diff --git a/hopsandcp/main.cpp b/hopsandcp/main.cpp deleted file mode 100644 index 4c2491fabf..0000000000 --- a/hopsandcp/main.cpp +++ /dev/null @@ -1,134 +0,0 @@ -#include "dcpslave.h" -#include "dcpmaster.h" - -#include - -#include -#include - -using namespace std; - -int main(int argc, char* argv[]) -{ - TCLAP::CmdLine cmd("hopsandcp", ' ', "0.1"); - - // Define a value argument and add it to the command line. - TCLAP::SwitchArg argMakeDescription("d","description","Generate DCP desciption file",cmd); - TCLAP::SwitchArg argSlave("s","slave","Execute simulation in slave mode",cmd); - TCLAP::SwitchArg argMaster("m","master","Execute simulation in master mode",cmd); - TCLAP::ValueArg argModelFile("i","input","Input Hopsan model file",false, "", "", cmd); - TCLAP::ValueArg argTargetDescriptionFile("t","target","Target file for DCP description",false, "", "", cmd); - TCLAP::ValueArg argHost("a","address","Host address",false,"127.0.0.1","",cmd); - TCLAP::ValueArg argPort("p","port","Port",false,8080,"",cmd); - TCLAP::MultiArg argRemoteSlave("r","remote","Connect to remote slave",false,"",cmd); - TCLAP::MultiArg argConnect("c","connect","Add connection (fromSlave,fromVr,toSlave1,toVr1,toSlave2,toVr2...)",false,"",cmd); - // Parse the argv array. - cmd.parse( argc, argv ); - - if((argMakeDescription.isSet() && (argSlave.isSet() || argMaster.isSet())) || - (argSlave.isSet() && (argMakeDescription.isSet() || argMaster.isSet())) || - (argMaster.isSet() && (argSlave.isSet() || argMakeDescription.isSet()))) { - cout << "Cannot only run in one mode at a time (make description, slave or master).\n"; - return -1; - } - - //Generate DCP description file - if(argMakeDescription.isSet()) { - if(!argModelFile.isSet()) { - cout << "Generating a DCP description requires a model file.\n"; - return -1; - } - if(!argHost.isSet()) { - cout << "Generating a DCP description requires a host address.\n"; - return -1; - } - if(!argPort.isSet()) { - cout << "Generating a DCP description requires a port.\n"; - return -1; - } - string targetFile; - if(argTargetDescriptionFile.isSet()) { - targetFile = argTargetDescriptionFile.getValue(); - } - else { - targetFile = argModelFile.getValue(); - targetFile = targetFile.substr(0,targetFile.find_last_of('.'))+".dcpx"; - } - - DcpSlave *pSlave = new DcpSlave(argModelFile.getValue(),argHost.getValue(),argPort.getValue()); - pSlave->generateDescriptionFile(targetFile); - } - - //Run a simulation as slave - if(argSlave.isSet()) { - if(!argModelFile.isSet()) { - cout << "Running in slave mode requires a model file.\n"; - return -1; - } - if(!argHost.isSet()) { - cout << "Running in slave mode requires a host address.\n"; - return -1; - } - if(!argPort.isSet()) { - cout << "Running in slave mode requires requires a port.\n"; - return -1; - } - std::string resultFile = argModelFile.getValue(); - resultFile = resultFile.substr(0,resultFile.find_last_of('.'))+".csv"; - DcpSlave *pSlave = new DcpSlave(argModelFile.getValue(),argHost.getValue(),argPort.getValue(),resultFile); - pSlave->start(); - } - - //Run a simulation as master - if(argMaster.isSet()) { - if(!argHost.isSet()) { - cout << "Running in master mode requires a host address.\n"; - return -1; - } - if(!argPort.isSet()) { - cout << "Running in master mode requires requires a port.\n"; - return -1; - } - - DcpMaster *pMaster = new DcpMaster(argHost.getValue(), argPort.getValue()); - for(auto slave : argRemoteSlave.getValue()) { - pMaster->addSlave(slave); - } - for(auto connection : argConnect.getValue()) { - std::deque ids; - std::stringstream ss(connection); - for (size_t i; ss >> i;) { - ids.push_back(i); - if (ss.peek() == ',') { - ss.ignore(); - } - } - if(ids.size() < 4) { - cout << "A connection must have at least one sender and one receiver.\n"; - return -1; - } - - size_t fromSlave = ids[0]; - size_t fromVr = ids[1]; - ids.pop_front(); - ids.pop_front(); - std::vector toSlaves, toVrs; - for(size_t i=0; iaddConnection(fromSlave, fromVr, toSlaves, toVrs); - } - - pMaster->start(); - } - - std::cout << "hopsandcp completed successfully!\n"; - - return 0; -} diff --git a/hopsandcp/dcpmaster.cpp b/hopsandcp/src/dcpmaster.cpp similarity index 98% rename from hopsandcp/dcpmaster.cpp rename to hopsandcp/src/dcpmaster.cpp index 69a96970a2..aecaaaa5c0 100644 --- a/hopsandcp/dcpmaster.cpp +++ b/hopsandcp/src/dcpmaster.cpp @@ -66,8 +66,7 @@ void DcpMaster::start() { std::thread b(&DcpManagerMaster::start, manager); std::chrono::seconds dura(1); std::this_thread::sleep_for(dura); - //driver->getDcpDriver().connectToSlave(1); - std::cout << "Register Slaves" << std::endl; + for(size_t i=0; iSTC_register(u_char(i+1), DcpState::ALIVE, convertToUUID(slaveDescriptions[i]->uuid), DcpOpMode::NRT, 1, 0); } @@ -149,7 +148,7 @@ void DcpMaster::doStep() { } void DcpMaster::stop() { - std::chrono::seconds dura(secondsToSimulate + 2); + std::chrono::seconds dura(1); std::this_thread::sleep_for(dura); std::cout << "Stop Simulation" << std::endl; for(size_t i=0; iloadExternalComponentLib(libpath.c_str()); -#endif - - //Load model file - double startTime=0, stopTime=1; - mpRootSystem = mpHopsanCore->loadHMFModelFile(modelfile.c_str(), startTime, stopTime); - printWaitingMessages(); - if(mpRootSystem == nullptr) { - std::cout << "Failed to load model file: " << modelfile << "\n"; - exit(-1); - } - //Generate list of inputs and outputs based on interface components - for(const auto &component : mpRootSystem->getSubComponents()) { + for(const auto &component : pSystem->getSubComponents()) { if(component->getTypeName() == "SignalInputInterface") { mInputs.push_back(component->getName().c_str()); } @@ -71,9 +53,6 @@ DcpSlave::DcpSlave(const std::string modelfile, const std::string host, int port } std::cout << "\n"; - printWaitingMessages(); - - //Create UDP driver udpDriver = new UdpDriver(host, uint16_t(port)); @@ -106,23 +85,8 @@ DcpSlave::DcpSlave(const std::string modelfile, const std::string host, int port DcpSlave::~DcpSlave() { - delete mpHopsanCore; } - -void DcpSlave::printWaitingMessages() -{ - hopsan::HString msg, type, tag; - while (mpHopsanCore->checkMessage() > 0) - { - mpHopsanCore->getMessage(msg,type,tag); - if(type != "debug") { - std::cout << msg.c_str() << std::endl; - } - } -} - - SlaveDescription_t *DcpSlave::getSlaveDescription() { SlaveDescription_t *slaveDescription = new SlaveDescription_t(make_SlaveDescription(1, 0, mpRootSystem->getName().c_str(), "b5279485-720d-4542-9f29-bee4d9a75ef9")); slaveDescription->OpMode.HardRealTime = make_HardRealTime_ptr(); @@ -165,13 +129,19 @@ SlaveDescription_t *DcpSlave::getSlaveDescription() { } -void DcpSlave::generateDescriptionFile(std::string &targetFile) { +void DcpSlave::generateDescriptionFile(std::string targetFile) { writeDcpSlaveDescription(*getSlaveDescription(), targetFile.c_str()); } -void DcpSlave::start() +bool DcpSlave::start() { - mManager->start(); + try { + mManager->start(); + return true; + } catch (std::exception& e) { + mpRootSystem->addErrorMessage(e.what()); + return false; + } } @@ -182,7 +152,6 @@ void DcpSlave::configure() { } else { std::cout << "Failed!\n"; - printWaitingMessages(); exit(-1); } @@ -196,13 +165,13 @@ void DcpSlave::configure() { } std::cout << "Initializing... "; + mpRootSystem->setNumLogSamples(mNumLogSamples); + mpRootSystem->setLogStartTime(0); if(mpRootSystem->initialize(0,10)) { std::cout << "Success!\n"; - printWaitingMessages(); } else { std::cout << "Failed!\n"; - printWaitingMessages(); exit(-1); } } @@ -228,8 +197,6 @@ void DcpSlave::doStep(uint64_t steps) { *(mOutputDataPtrs[o]) = *(mOutputNodePtrs[o]); mManager->Log(SIM_LOG, mSimulationTime, *mOutputDataPtrs[o]); } - - printWaitingMessages(); } void DcpSlave::setTimeRes(const uint32_t numerator, const uint32_t denominator) { @@ -238,7 +205,5 @@ void DcpSlave::setTimeRes(const uint32_t numerator, const uint32_t denominator) void DcpSlave::stop() { - if(!mResultFile.empty()) { - saveResultsToCSV(mpRootSystem, mResultFile, SaveResults::Full, std::vector()); - } + dynamic_cast(mManager)->stop(); } diff --git a/hopsandcp/utilities.cpp b/hopsandcp/src/utilities.cpp similarity index 100% rename from hopsandcp/utilities.cpp rename to hopsandcp/src/utilities.cpp From 151efabb880ca27e80dec1bec26d552ebe9827b5 Mon Sep 17 00:00:00 2001 From: Robert Braun Date: Wed, 10 Feb 2021 12:57:33 +0100 Subject: [PATCH 11/34] Support DCP master simulations from HopsanGUI --- HopsanCore/HopsanCore.pro | 1 + .../include/Components/DcpComponent.hpp | 149 +++++ HopsanCore/include/HopsanEssentials.h | 1 + HopsanCore/src/HopsanEssentials.cpp | 2 + HopsanGUI/Configuration.cpp | 2 + HopsanGUI/Configuration.h | 3 +- HopsanGUI/GUIObjects/GUIComponent.cpp | 6 +- HopsanGUI/GraphicsView.cpp | 111 ++-- HopsanGUI/HopsanGUI.pro | 2 +- HopsanGUI/MainWindow.cpp | 69 ++- HopsanGUI/MainWindow.h | 5 +- HopsanGUI/ModelHandler.cpp | 18 +- HopsanGUI/ModelHandler.h | 1 + HopsanGUI/Resources.qrc | 5 + HopsanGUI/SimulationThreadHandler.cpp | 82 +++ HopsanGUI/SimulationThreadHandler.h | 20 +- HopsanGUI/Widgets/ModelWidget.cpp | 62 +++ HopsanGUI/Widgets/ModelWidget.h | 11 + HopsanGUI/common.h | 1 + .../builtinCAF/hidden/dcpcomponent.xml | 13 + .../graphics/objecticons/dcpcomponent.svg | 87 +++ .../uiicons/svg/Hopsan-NewDcpModel.svg | 377 +++++++++++++ .../uiicons/svg/Hopsan-StartDcpManager.svg | 513 ++++++++++++++++++ .../uiicons/svg/Hopsan-StartDcpServer.svg | 430 +++++++++++++++ hopsandcp/include/dcpmaster.h | 25 +- hopsandcp/src/dcpmaster.cpp | 94 +++- hopsandcp/src/dcpslave.cpp | 4 +- 27 files changed, 1989 insertions(+), 105 deletions(-) create mode 100644 HopsanCore/include/Components/DcpComponent.hpp create mode 100644 HopsanGUI/graphics/builtinCAF/hidden/dcpcomponent.xml create mode 100644 HopsanGUI/graphics/objecticons/dcpcomponent.svg create mode 100644 HopsanGUI/graphics/uiicons/svg/Hopsan-NewDcpModel.svg create mode 100644 HopsanGUI/graphics/uiicons/svg/Hopsan-StartDcpManager.svg create mode 100644 HopsanGUI/graphics/uiicons/svg/Hopsan-StartDcpServer.svg diff --git a/HopsanCore/HopsanCore.pro b/HopsanCore/HopsanCore.pro index 26d21d29fd..afce6f37b9 100644 --- a/HopsanCore/HopsanCore.pro +++ b/HopsanCore/HopsanCore.pro @@ -213,6 +213,7 @@ HEADERS += \ include/ComponentUtilities/TempDirectoryHandle.h \ include/Parameters.h \ include/Components/DummyComponent.hpp \ + include/Components/DcpComponent.hpp \ include/ComponentUtilities/EquationSystemSolver.h \ $${PWD}/dependencies/rapidxml/hopsan_rapidxml.hpp \ include/CoreUtilities/MultiThreadingUtilities.h \ diff --git a/HopsanCore/include/Components/DcpComponent.hpp b/HopsanCore/include/Components/DcpComponent.hpp new file mode 100644 index 0000000000..197abce44f --- /dev/null +++ b/HopsanCore/include/Components/DcpComponent.hpp @@ -0,0 +1,149 @@ +/*----------------------------------------------------------------------------- + + Copyright 2017 Hopsan Group + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + The full license is available in the file LICENSE. + For details about the 'Hopsan Group' or information about Authors and + Contributors see the HOPSANGROUP and AUTHORS files that are located in + the Hopsan source code root directory. + +-----------------------------------------------------------------------------*/ + +//! +//! @file DcpComponent.hpp +//! @author Robert Braun +//! @date 2021-02-09 +//! +//! @brief Contains a wrapper component for DCP servers +//! +//$Id$ + +#ifndef DCPCOMPONENT_HPP +#define DCPCOMPONENT_HPP + +#include "ComponentEssentials.h" + +namespace hopsan { + + class DcpComponent : public ComponentSignal + { + private: + //Parameters + HString mDcpxFile; + HString mVariables; + HString mValueRefs; + HString mLastVariables; + + //Internal variables + std::vector mPorts; + std::vector mInputs; + std::vector mOutputs; + std::vector mParameters; + + public: + static Component *Creator() + { + return new DcpComponent(); + } + + void configure() + { + addConstant("dcpxFile", "", "", "", mDcpxFile); + addConstant("valueRefs", "vr1,vr2,vr3...", "", "", mValueRefs); + addConstant("variables", "in1,in2;out1,out2;par1,par2...", "", "", mVariables); + setReconfigurationParameter("variables"); + // Do nothing + } + + void reconfigure() + { + if(mVariables == mLastVariables) { + return; //Path did not change, do nothing + } + mLastVariables = mVariables; + + + for(size_t i=0; igetName()); + } + std::vector parameters; + this->getParameterNames(parameters); + for(size_t i=0; iunRegisterParameter(parameters[i]); + } + } + mPorts.clear(); + mInputs.clear(); + mOutputs.clear(); + mParameters.clear(); + + HVector splitVariables = mVariables.split(';'); + HVector splitInputs = splitVariables[0].split(','); + HVector splitOutputs = splitVariables[1].split(','); + HVector splitParameters = splitVariables[2].split(','); + + //The split function will return a single-element vector with an + //empty string if delimiter was not found, clear vector in this case + if(splitInputs.size() == 1 && splitInputs[0] == "") { + splitInputs.clear(); + } + if(splitOutputs.size() == 1 && splitOutputs[0] == "") { + splitOutputs.clear(); + } + if(splitParameters.size() == 1 && splitParameters[0] == "") { + splitParameters.clear(); + } + HVector splitValueRefs = mValueRefs.split(','); + + if(splitValueRefs.size() != splitInputs.size()+splitOutputs.size()+splitParameters.size()) { + addErrorMessage("Number of value references does not equal number of variables"); + return; + } + + for(size_t i=0; iregisterCreatorFunction(HOPSAN_BUILTIN_TYPENAME_DUMMYCOMPONENT, DummyComponent::Creator); + mpComponentFactory->registerCreatorFunction(HOPSAN_BUILTIN_TYPENAME_DCPCOMPONENT, DcpComponent::Creator); mpComponentFactory->registerCreatorFunction(HOPSAN_BUILTIN_TYPENAME_MISSINGCOMPONENT, DummyComponent::Creator); mpComponentFactory->registerCreatorFunction(HOPSAN_BUILTIN_TYPENAME_SUBSYSTEM, ComponentSystem::Creator); mpComponentFactory->registerCreatorFunction(HOPSAN_BUILTIN_TYPENAME_CONDITIONALSUBSYSTEM, ConditionalComponentSystem::Creator); diff --git a/HopsanGUI/Configuration.cpp b/HopsanGUI/Configuration.cpp index c7ac2b17d4..c36b12e3d7 100644 --- a/HopsanGUI/Configuration.cpp +++ b/HopsanGUI/Configuration.cpp @@ -1311,6 +1311,8 @@ void Configuration::registerSettings() mStringSettings.insert(cfg::dir::customtemppath, ""); mStringSettings.insert(cfg::dir::gcc64, ""); mStringSettings.insert(cfg::dir::gcc32, ""); + mStringSettings.insert(cfg::dir::dcp, gpDesktopHandler->getDocumentsPath()); + #ifndef _WIN32 #ifdef HOPSANCOMPILED64BIT mStringSettings.insert(cfg::dir::gcc64, "/usr/bin"); diff --git a/HopsanGUI/Configuration.h b/HopsanGUI/Configuration.h index 6b3d8c805c..260fe9201c 100644 --- a/HopsanGUI/Configuration.h +++ b/HopsanGUI/Configuration.h @@ -34,8 +34,6 @@ #ifndef CONFIGURATION_H #define CONFIGURATION_H - - namespace cfg { namespace paths { constexpr auto corelogfile = "corelogfile"; @@ -109,6 +107,7 @@ namespace cfg { constexpr auto labviewexport = "labviewexportdir"; constexpr auto gcc32 = "gcc32dir"; constexpr auto gcc64 = "gcc64dir"; + constexpr auto dcp = "dcpdir"; constexpr auto customtemppath = "customtemppath"; } constexpr auto preferincludedcompiler = "preferincludedcompiler"; diff --git a/HopsanGUI/GUIObjects/GUIComponent.cpp b/HopsanGUI/GUIObjects/GUIComponent.cpp index 5a8d61e9ac..901c163436 100644 --- a/HopsanGUI/GUIObjects/GUIComponent.cpp +++ b/HopsanGUI/GUIObjects/GUIComponent.cpp @@ -140,7 +140,8 @@ QString Component::getTypeCQS() const bool Component::setParameterValue(QString name, QString value, bool force) { QMap > connectionsBeforeReconfigure; - if((this->getTypeName() == "FMIWrapper" || this->getTypeName() == "FMIWrapperQ") && (name == "path" || name == "portspecs")) { + if(((this->getTypeName() == "FMIWrapper" || this->getTypeName() == "FMIWrapperQ") && (name == "path" || name == "portspecs")) || + (this->getTypeName() == "DcpComponent" && name == "variables")) { //Remove old ports QList ports = this->getPortListPtrs(); for(const auto port : ports) { @@ -152,7 +153,8 @@ bool Component::setParameterValue(QString name, QString value, bool force) bool retval = mpParentSystemObject->getCoreSystemAccessPtr()->setParameterValue(this->getName(), name, value, force); - if((this->getTypeName() == "FMIWrapper" || this->getTypeName() == "FMIWrapperQ") && (name == "path" || name == "portspecs")) { + if(((this->getTypeName() == "FMIWrapper" || this->getTypeName() == "FMIWrapperQ") && (name == "path" || name == "portspecs")) || + (this->getTypeName() == "DcpComponent" && name == "variables")) { //Get lists of input and output ports from core component QStringList visibleOutputs = getParameterValue("visibleOutputs").split(","); QStringList inputs, outputs, powerPorts; diff --git a/HopsanGUI/GraphicsView.cpp b/HopsanGUI/GraphicsView.cpp index fc62c36e64..28b913f966 100644 --- a/HopsanGUI/GraphicsView.cpp +++ b/HopsanGUI/GraphicsView.cpp @@ -61,6 +61,11 @@ #include "GUIPort.h" #include "Widgets/LibraryWidget.h" +#include "dcpmaster.h" + +#include +#include + //! @class GraphicsView //! @brief The GraphicsView class is a class which display the content of a scene of components. //! @@ -126,6 +131,10 @@ void GraphicsView::contextMenuEvent ( QContextMenuEvent * event ) { QGraphicsView::contextMenuEvent(event); QMenu menu(this); + QAction *addDcpServerAction = nullptr; + if(mpParentModelWidget->getModelType() == ModelWidget::DcpModel) { + addDcpServerAction = menu.addAction("Add DCP Server"); + } QAction *addTextBoxAction = menu.addAction("Add Text Box Widget"); addTextBoxAction->setDisabled(mpParentModelWidget->isEditingLimited() || mpContainerObject->isLocallyLocked()); QAction *addImageWidgetAction = menu.addAction("Add Image Widget"); @@ -142,6 +151,24 @@ void GraphicsView::contextMenuEvent ( QContextMenuEvent * event ) else if(selectedAction == addImageWidgetAction) { mpContainerObject->getUndoStackPtr()->newPost(); mpContainerObject->addImageWidget(this->mapToScene(event->pos()).toPoint()); + else if(addDcpServerAction != nullptr && selectedAction == addDcpServerAction) { + QString dcpxPath = QFileDialog::getOpenFileName(gpMainWindowWidget, tr("Select DCP Slave Description File"), + gpConfig->getStringSetting(CFG_DCPDIR), + tr("DCP Slave Description (*.dcpx)")); + if(dcpxPath.isEmpty()) { + return; + } + QFileInfo dcpxFileInfo(dcpxPath); + gpConfig->setStringSetting(CFG_DCPDIR, dcpxFileInfo.absolutePath()); + + hopsan::HString name, variables, valueRefs; + getDataFromSlaveDescription(dcpxFileInfo.filePath().toStdString().c_str(), name, variables, valueRefs); + + ModelObject *pObj = mpContainerObject->addModelObject(HOPSANGUIDCPCOMPONENT, this->mapToScene(event->pos()).toPoint()); + mpParentModelWidget->getTopLevelSystemContainer()->renameModelObject(pObj->getName(), (name.c_str())); + pObj->setParameterValue("dcpxFile", dcpxFileInfo.absoluteFilePath()); + pObj->setParameterValue("valueRefs", valueRefs.c_str()); + pObj->setParameterValue("variables",variables.c_str()); //Must be called AFTER the two other parameters, since this variable triggers the reconfiguration } } } @@ -209,18 +236,20 @@ void GraphicsView::insertComponentFromLineEdit() //! @todo This function seems to do nothing. Can it be removed? void GraphicsView::dragMoveEvent(QDragMoveEvent *event) { - qDebug() << "Accepting: " << event->mimeData()->text(); - - event->accept(); - -// if (event->mimeData()->hasText()) -// { -// event->accept(); -// } -// else -// { -// event->ignore(); -// } + bool isPlotData = event->mimeData()->hasText() && event->mimeData()->text().startsWith("HOPSANPLOTDATA:"); + bool isDragCopy = event->mimeData()->hasText() && event->mimeData()->text().startsWith("HOPSANDRAGCOPY"); + bool isUrl = event->mimeData()->hasUrls(); + bool editingLimited = mpParentModelWidget->isEditingLimited(); + bool locked = mpContainerObject->isLocallyLocked(); + bool isComponent = !isUrl && !isPlotData && !isDragCopy; + bool dcpModel = (mpParentModelWidget->getModelType() == ModelWidget::DcpModel); + + if((editingLimited || locked || dcpModel) && isComponent) { + event->ignore(); + } + else { + event->accept(); + } } @@ -228,11 +257,20 @@ void GraphicsView::dragMoveEvent(QDragMoveEvent *event) //! @param event contains information of the drop operation. void GraphicsView::dropEvent(QDropEvent *event) { - if(mpParentModelWidget->isEditingLimited() || mpContainerObject->isLocallyLocked()) + bool isPlotData = event->mimeData()->hasText() && event->mimeData()->text().startsWith("HOPSANPLOTDATA:"); + bool isDragCopy = event->mimeData()->hasText() && event->mimeData()->text().startsWith("HOPSANDRAGCOPY"); + bool isUrl = event->mimeData()->hasUrls(); + bool editingLimited = mpParentModelWidget->isEditingLimited(); + bool locked = mpContainerObject->isLocallyLocked(); + bool isComponent = !isUrl && !isPlotData && !isDragCopy; + bool dcpModel = (mpParentModelWidget->getModelType() == ModelWidget::DcpModel); + + if((editingLimited || locked || dcpModel) && isComponent) { return; + } //A HMF file was dropped in the graphics view, so try to open the model - if(event->mimeData()->hasUrls()) + if(isUrl) { for(int i=0; imimeData()->urls().size(); ++i) { @@ -243,42 +281,33 @@ void GraphicsView::dropEvent(QDropEvent *event) } return; } - if (event->mimeData()->hasText()) - { + if(isDragCopy) { mpParentModelWidget->hasChanged(); QString text = event->mimeData()->text(); + //These booleans must be reset here, because they are not automatically reset when dropping things. + //It doesn't really matter if it will be incorrect, because keeping the shift key pressed after a drop + //and attempting to do more ctrl-stuff does not make any sense anyway. + mShiftKeyPressed = false; + mLeftMouseButtonPressed = false; - //Dropped item is a drag copy operation - if(text == "HOPSANDRAGCOPY") - { - //These booleans must be reset here, because they are not automatically reset when dropping things. - //It doesn't really matter if it will be incorrect, because keeping the shift key pressed after a drop - //and attempting to do more ctrl-stuff does not make any sense anyway. - mShiftKeyPressed = false; - mLeftMouseButtonPressed = false; - - //Paste the drag copy component - mpContainerObject->paste(mpContainerObject->getDragCopyStackPtr()); - return; - } - - //Check if dropped item is a plot data string, and attempt to open a plot window if so - else if(text.startsWith("HOPSANPLOTDATA:")) + //Paste the drag copy component + mpContainerObject->paste(mpContainerObject->getDragCopyStackPtr()); + return; + } + else if(isPlotData) { + QStringList fields = event->mimeData()->text().split(":"); + if (fields.size() > 2) { - QStringList fields = text.split(":"); - if (fields.size() > 2) - { - getContainerPtr()->getLogDataHandler()->plotVariable("", fields[1], fields[2].toInt(), 0); - } - return; + getContainerPtr()->getLogDataHandler()->plotVariable("", fields[1], fields[2].toInt(), 0); } - - + return; + } + else if(isComponent) { //Dropped item is not a plot data string, so assume it is a component typename mpContainerObject->getUndoStackPtr()->newPost(); event->accept(); QPointF position = event->pos(); - mpContainerObject->addModelObject(text, this->mapToScene(position.toPoint())); + mpContainerObject->addModelObject(event->mimeData()->text(), this->mapToScene(position.toPoint())); this->setFocus(); } diff --git a/HopsanGUI/HopsanGUI.pro b/HopsanGUI/HopsanGUI.pro index 9262dac602..1b10309eaf 100644 --- a/HopsanGUI/HopsanGUI.pro +++ b/HopsanGUI/HopsanGUI.pro @@ -108,7 +108,7 @@ DEFINES *= OPS_DLLIMPORT #-------------------------------------------------------- #-------------------------------------------------------- -# Set Ops Paths +# Set hopsandcp Paths INCLUDEPATH *= $${PWD}/../hopsandcp/include/ LIBS *= -L$${PWD}/../bin -lhopsandcp$${DEBUG_EXT} DEFINES *= HOPSANDCP_DLLIMPORT diff --git a/HopsanGUI/MainWindow.cpp b/HopsanGUI/MainWindow.cpp index 0be857d94d..03f89af18a 100644 --- a/HopsanGUI/MainWindow.cpp +++ b/HopsanGUI/MainWindow.cpp @@ -624,8 +624,15 @@ void MainWindow::createActions() mHelpPopupTextMap.insert(mpToggleRemoteCoreSimAction, "Connect or disconnect to a remote HopsanCore, this will determine if local or remote simulation is run, when calling simulate"); connect(mpToggleRemoteCoreSimAction, SIGNAL(hovered()), this, SLOT(showToolBarHelpPopup())); - mpSimulateDcpSlaveAction = new QAction(QIcon(QString(ICONPATH) + "svg/Hopsan-SimulateRemote.svg"), tr("Simulate Model as DCP Slave"), this); - mpSimulateDcpSlaveAction->setToolTip("Simulate Model as DCP Slave"); + mpNewDcpModelAction = new QAction(QIcon(QString(ICONPATH) + "svg/Hopsan-NewDcpModel.svg"), tr("Create new DCP model"), this); + mpNewDcpModelAction->setToolTip("Create new DCP model"); + connect(mpNewDcpModelAction, SIGNAL(triggered()), mpModelHandler, SLOT(addNewDcpModel())); + + mpStartDcpManagerAction = new QAction(QIcon(QString(ICONPATH) + "svg/Hopsan-StartDcpManager.svg"), tr("Simulate model as DCP manager"), this); + mpStartDcpManagerAction->setToolTip("Simulate model as DCP manager"); + + mpStartDcpServerAction = new QAction(QIcon(QString(ICONPATH) + "svg/Hopsan-StartDcpServer.svg"), tr("Simulate model as DCP server"), this); + mpStartDcpServerAction->setToolTip("Simulate model as DCP server"); mpOpenDebuggerAction = new QAction(QIcon(QString(ICONPATH) + "svg/Hopsan-Debug.svg"), tr("&Launch Debugger"), this); mpOpenDebuggerAction->setToolTip(tr("Launch Debugger")); @@ -1184,7 +1191,6 @@ void MainWindow::createToolbars() mpSimToolBar->addWidget(mpSimulationTimeEdit); mpSimToolBar->addAction(mpSimulateAction); mpSimToolBar->addAction(mpToggleRemoteCoreSimAction); - mpSimToolBar->addAction(mpSimulateDcpSlaveAction); mpSimToolBar->addAction(mpOpenDebuggerAction); mpSimToolBar->addAction(mpOptimizeAction); mpSimToolBar->addAction(mpSensitivityAnalysisAction); @@ -1223,6 +1229,14 @@ void MainWindow::createToolbars() mpViewToolBar->addAction(mpToggleSignalsAction); mpViewToolBar->addAction(mpToggleHideAllDockAreasAction); + mpDcpToolBar = new QToolBar(tr("DCP Toolbar")); + addToolBar(Qt::TopToolBarArea, mpDcpToolBar); + mpDcpToolBar->setAllowedAreas(Qt::TopToolBarArea | Qt::LeftToolBarArea | Qt::RightToolBarArea); + mpDcpToolBar->setAttribute(Qt::WA_MouseTracking); + mpDcpToolBar->addAction(mpNewDcpModelAction); + mpDcpToolBar->addAction(mpStartDcpManagerAction); + mpDcpToolBar->addAction(mpStartDcpServerAction); + //Tools toolbar, contains all tools used to modify the model mpToolsToolBar = new QToolBar(tr("Tools Toolbar")); addToolBar(Qt::LeftToolBarArea, mpToolsToolBar); @@ -1440,25 +1454,27 @@ void MainWindow::updateToolBarsToNewTab() ModelWidget *pModel = qobject_cast(mpCentralTabs->currentWidget()); bool modelTab = modelOpen && pModel; + bool dcpTab = modelTab && (pModel->getModelType() == ModelWidget::DcpModel); bool logData = modelTab && pModel->getViewContainerObject()->getLogDataHandler(); TextEditorWidget *pEditor = qobject_cast(mpCentralTabs->currentWidget()); bool editorTab = (pEditor != nullptr); + bool hcomTab = editorTab && (pEditor->getFileInfo().suffix() == "hcom"); if(modelTab) { mpTogglePortsAction->setChecked(pModel->getTopLevelSystemContainer()->areSubComponentPortsShown()); } - mpShowLossesAction->setEnabled(logData); - mpAnimateAction->setEnabled(modelTab); + mpShowLossesAction->setEnabled(logData && !dcpTab); + mpAnimateAction->setEnabled(modelTab && !dcpTab); mpSaveAction->setEnabled(modelTab || editorTab); - mpExportToFMUMenuButton->setEnabled(modelTab); - mpExportToExeMenuButton->setEnabled(modelTab); - mpExportToExeMenu->setEnabled(modelTab); + mpExportToFMUMenuButton->setEnabled(modelTab && !dcpTab); + mpExportToExeMenuButton->setEnabled(modelTab && !dcpTab); + mpExportToExeMenu->setEnabled(modelTab && !dcpTab); mpSaveAsAction->setEnabled(modelTab || editorTab); - mpSaveAndRunAction->setEnabled(editorTab && pEditor->getFileInfo().suffix() == "hcom"); - mpExportSimulationStateAction->setEnabled(modelTab); + mpSaveAndRunAction->setEnabled(hcomTab); + mpExportSimulationStateAction->setEnabled(modelTab && !dcpTab); mpExportModelParametersMenu->setEnabled(modelTab); mpExportModelParametersMenuButton->setEnabled(modelTab); mpExportModelParametersActionToSsv->setEnabled(modelTab); @@ -1488,23 +1504,26 @@ void MainWindow::updateToolBarsToNewTab() mpFlipHorizontalAction->setEnabled(modelTab); mpFlipVerticalAction->setEnabled(modelTab); mpSimulationTimeEdit->setEnabled(modelTab); - mpSimulateAction->setEnabled(modelTab); - mpToggleRemoteCoreSimAction->setEnabled(modelTab); - mpOpenDebuggerAction->setEnabled(modelTab); - mpOptimizeAction->setEnabled(modelTab); - mpSensitivityAnalysisAction->setEnabled(modelTab); - mpMeasureSimulationTimeAction->setEnabled(modelTab); - mpPlotAction->setEnabled(logData); + mpSimulateAction->setEnabled(modelTab && !dcpTab); + mpToggleRemoteCoreSimAction->setEnabled(modelTab && !dcpTab); + mpOpenDebuggerAction->setEnabled(modelTab && !dcpTab); + mpOptimizeAction->setEnabled(modelTab && !dcpTab); + mpSensitivityAnalysisAction->setEnabled(modelTab && !dcpTab); + mpMeasureSimulationTimeAction->setEnabled(modelTab && !dcpTab); + mpPlotAction->setEnabled(logData && !dcpTab); mpPropertiesAction->setEnabled(modelTab); mpOpenSystemParametersAction->setEnabled(modelTab); - mpExportToFMU1_32Action->setEnabled(modelTab); - mpExportToFMU2_32Action->setEnabled(modelTab); - mpExportToLabviewAction->setEnabled(modelTab); - mpExportToSimulinkAction->setEnabled(modelTab); - mpImportFMUAction->setEnabled(modelTab); - mpImportModelParametersMenuButton->setEnabled(modelTab); - mpLoadModelParametersFromHpfAction->setEnabled(modelTab); - mpLoadModelParametersFromSsvAction->setEnabled(modelTab); + mpExportToFMU1_32Action->setEnabled(modelTab && !dcpTab); + mpExportToFMU2_32Action->setEnabled(modelTab && !dcpTab); + mpExportToLabviewAction->setEnabled(modelTab && !dcpTab); + mpExportToSimulinkAction->setEnabled(modelTab && !dcpTab); + mpImportFMUAction->setEnabled(modelTab && !dcpTab); + mpImportModelParametersMenuButton->setEnabled(modelTab && !dcpTab); + mpLoadModelParametersFromHpfAction->setEnabled(modelTab && !dcpTab); + mpLoadModelParametersFromSsvAction->setEnabled(modelTab && !dcpTab); + mpStartDcpServerAction->setEnabled(modelTab && !dcpTab); + + mpStartDcpManagerAction->setEnabled(dcpTab); if(gpFindWidget) { gpFindWidget->setEnabled(modelTab || editorTab); diff --git a/HopsanGUI/MainWindow.h b/HopsanGUI/MainWindow.h index c514c41418..bedf9ab8b1 100644 --- a/HopsanGUI/MainWindow.h +++ b/HopsanGUI/MainWindow.h @@ -220,7 +220,9 @@ class MainWindow : public QMainWindow QAction *mpShowLossesAction; QAction *mpMeasureSimulationTimeAction; QAction *mpToggleHideAllDockAreasAction; - QAction *mpSimulateDcpSlaveAction; + QAction *mpNewDcpModelAction; + QAction *mpStartDcpManagerAction; + QAction *mpStartDcpServerAction; QAction *mpDebug1Action; QAction *mpDebug2Action; @@ -331,6 +333,7 @@ private slots: QToolBar *mpToolsToolBar; QToolBar *mpSimToolBar; QToolBar *mpViewToolBar; + QToolBar *mpDcpToolBar; QLabel *mpTimeLabelDeliminator1; QLabel *mpTimeLabelDeliminator2; diff --git a/HopsanGUI/ModelHandler.cpp b/HopsanGUI/ModelHandler.cpp index b0ed0de475..5a4fea7da5 100644 --- a/HopsanGUI/ModelHandler.cpp +++ b/HopsanGUI/ModelHandler.cpp @@ -117,6 +117,19 @@ ModelWidget *ModelHandler::addNewModel(QString modelName, LoadOptions options) return pNewModelWidget; } +ModelWidget *ModelHandler::addNewDcpModel() +{ + QString modelName = "Untitled"+QString::number(mNumberOfUntitledModels); + ModelWidget *pNewModelWidget = new ModelWidget(this,gpCentralTabWidget); + pNewModelWidget->setModelType(ModelWidget::DcpModel); + pNewModelWidget->getTopLevelSystemContainer()->setName(modelName); + addModelWidget(pNewModelWidget, modelName, NoLoadOptions); + pNewModelWidget->setSaved(true); + mNumberOfUntitledModels++; + + return pNewModelWidget; +} + void ModelHandler::setCurrentModel(int idx) { @@ -711,7 +724,8 @@ void ModelHandler::disconnectMainWindowConnections(ModelWidget *pModel) disconnect(gpMainWindow, SIGNAL(simulateKeyPressed()), pModel, SLOT(simulate_nonblocking())); disconnect(gpMainWindow->mpToggleRemoteCoreSimAction, SIGNAL(triggered(bool)), pModel, SLOT(setUseRemoteSimulation(bool))); - disconnect(gpMainWindow->mpSimulateDcpSlaveAction, SIGNAL(triggered()), pModel, SLOT(simulateDcpSlave())); + disconnect(gpMainWindow->mpStartDcpServerAction, SIGNAL(triggered()), pModel, SLOT(simulateDcpSlave())); + disconnect(gpMainWindow->mpStartDcpManagerAction, SIGNAL(triggered()), pModel, SLOT(simulateDcpManager())); disconnect(gpMainWindow->mpSaveAction, SIGNAL(triggered()), pModel, SLOT(save())); disconnect(gpMainWindow->mpSaveAsAction, SIGNAL(triggered()), pModel, SLOT(saveAs())); disconnect(gpMainWindow->mpExportModelParametersActionToHpf, SIGNAL(triggered()), pModel, SLOT(exportModelParametersToHpf())); @@ -752,6 +766,8 @@ void ModelHandler::connectMainWindowConnections(ModelWidget *pModel) connect(gpMainWindow, SIGNAL(simulateKeyPressed()), pModel, SLOT(simulate_nonblocking()), Qt::UniqueConnection); connect(gpMainWindow->mpToggleRemoteCoreSimAction, SIGNAL(triggered(bool)), pModel, SLOT(setUseRemoteSimulation(bool)), Qt::UniqueConnection); + connect(gpMainWindow->mpStartDcpServerAction, SIGNAL(triggered()), pModel, SLOT(simulateDcpSlave()), Qt::UniqueConnection); + connect(gpMainWindow->mpStartDcpManagerAction, SIGNAL(triggered()), pModel, SLOT(simulateDcpManager()), Qt::UniqueConnection); connect(gpMainWindow->mpSaveAction, SIGNAL(triggered()), pModel, SLOT(save()), Qt::UniqueConnection); connect(gpMainWindow->mpSaveAsAction, SIGNAL(triggered()), pModel, SLOT(saveAs()), Qt::UniqueConnection); connect(gpMainWindow->mpExportModelParametersActionToHpf, SIGNAL(triggered()), pModel, SLOT(exportModelParametersToHpf()), Qt::UniqueConnection); diff --git a/HopsanGUI/ModelHandler.h b/HopsanGUI/ModelHandler.h index c6e5ef2ed7..882faa13b2 100644 --- a/HopsanGUI/ModelHandler.h +++ b/HopsanGUI/ModelHandler.h @@ -100,6 +100,7 @@ class ModelHandler : public QObject public slots: ModelWidget *addNewModel(QString modelName="Untitled", ModelHandler::LoadOptions options=NoLoadOptions); + ModelWidget *addNewDcpModel(); void loadModel(); void loadModel(QAction *action); void newTextFile(); diff --git a/HopsanGUI/Resources.qrc b/HopsanGUI/Resources.qrc index bda069a3e0..c103487db5 100644 --- a/HopsanGUI/Resources.qrc +++ b/HopsanGUI/Resources.qrc @@ -151,6 +151,11 @@ graphics/porticons/PetrinetPort.svg graphics/uiicons/svg/Hopsan-Modelica.svg graphics/uiicons/svg/Hopsan-SaveAndRun.svg + graphics/uiicons/svg/Hopsan-StartDcpServer.svg + graphics/uiicons/svg/Hopsan-StartDcpManager.svg + graphics/uiicons/svg/Hopsan-NewDcpModel.svg + graphics/builtinCAF/hidden/dcpcomponent.xml + graphics/objecticons/dcpcomponent.svg ../licenseNoticeGPLv3 diff --git a/HopsanGUI/SimulationThreadHandler.cpp b/HopsanGUI/SimulationThreadHandler.cpp index 52132604b5..08832f0fec 100644 --- a/HopsanGUI/SimulationThreadHandler.cpp +++ b/HopsanGUI/SimulationThreadHandler.cpp @@ -38,7 +38,10 @@ #include "common.h" #include "global.h" #include "GUIObjects/GUIContainerObject.h" +#include "dcpmaster.h" #include "dcpslave.h" +#include "GUIConnector.h" +#include "GUIPort.h" namespace { @@ -335,6 +338,16 @@ void SimulationThreadHandler::initSimulateFinalizeRemote(SharedRemoteCoreSimulat } #endif +void SimulationThreadHandler::initSimulateFinalizeDcpManager(SystemObject *pSystem, const QString &host, int port) +{ + mvpSystems.clear(); + mvpSystems.push_back(pSystem); + mpSimulationWorkerObject = new DCPManagerSimulationWorkerObject(pSystem, host, port); + mpSimulationWorkerObject->setMessageHandler(mpMessageHandler); + initSimulateFinalizePrivate(); +} + + void SimulationThreadHandler::initSimulateFinalizeDcpSlave(SystemObject* pSystem, const QString &host, int port, const QString &targetFile) { mvpSystems.clear(); @@ -599,3 +612,72 @@ void DCPSlaveSimulationWorkerObject::initSimulateFinalize() emit setProgressState(SimulationState::Finalize); emit finalizeDone(true, timer.elapsed()); } + +DCPManagerSimulationWorkerObject::DCPManagerSimulationWorkerObject(SystemObject *pSystem, const QString &host, int port) + : mpSystem(pSystem), mHost(host), mPort(port) +{ + +} + +void DCPManagerSimulationWorkerObject::initSimulateFinalize() +{ + // Initializing + QTime timer; + emit setProgressState(SimulationState::Initialize); + timer.start(); + + DcpMaster *pDcpMaster = new DcpMaster(mHost.toStdString(), mPort, mpSystem->getTimeStep()); + for(const auto comp : mpSystem->getModelObjects()) { + if(comp->getTypeName() == HOPSANGUIDCPCOMPONENT) { //Just in case, model shall only contain DCP components anyway + pDcpMaster->addSlave(comp->getParameterValue("dcpxFile").toStdString()); + } + } + std::map,std::pair,std::vector > > connections; + for(const auto &connection : mpSystem->getSubConnectorPtrs()) { + Port *pStartPort = connection->getStartPort(); + Port *pEndPort = connection->getEndPort(); + ModelObject *pStartComponent = pStartPort->getParentModelObject(); + ModelObject *pEndComponent = pEndPort->getParentModelObject(); + size_t fromSlave = size_t(mpSystem->getModelObjects().indexOf(pStartComponent))+1; //DCPLib uses one-based indexing + size_t toSlave = size_t(mpSystem->getModelObjects().indexOf(pEndComponent))+1; //DCPLib uses one-based indexing + QVector variameters; + size_t fromVr, toVr; + pStartComponent->getVariameterDescriptions(variameters); + for(const auto &variameter : variameters) { + if(variameter.mPortName == pStartPort->getName()) { + fromVr = variameter.mDescription.toUInt(); + } + } + pEndComponent->getVariameterDescriptions(variameters); + for(const auto &variameter : variameters) { + if(variameter.mPortName == pEndPort->getName()) { + toVr = variameter.mDescription.toUInt(); + } + } + + if(connections.count(std::make_pair(fromSlave,fromVr)) == 0) { + connections[std::make_pair(fromSlave,fromVr)] = std::make_pair(std::vector(),std::vector()); + } + connections[std::make_pair(fromSlave,fromVr)].first.push_back(toSlave); + connections[std::make_pair(fromSlave,fromVr)].second.push_back(toVr); + } + + for(const auto &con : connections) { + pDcpMaster->addConnection(con.first.first, con.first.second, con.second.first, con.second.second); + } + + emit initDone(true, timer.elapsed()); + + // Simulating + emit setProgressState(SimulationState::DcpMasterSimulate); + gpMessageHandler->addInfoMessage("Starting a DCP simulation as manager..."); + pDcpMaster->start(); + gpMessageHandler->addInfoMessage("DCP simulation finished!"); + emit simulateDone(true, timer.elapsed()); + + // Finalizing + delete pDcpMaster; + // Finalizing + emit setProgressState(SimulationState::Finalize); + emit finalizeDone(true, timer.elapsed()); +} diff --git a/HopsanGUI/SimulationThreadHandler.h b/HopsanGUI/SimulationThreadHandler.h index f4a6ea4929..30c9a52b62 100644 --- a/HopsanGUI/SimulationThreadHandler.h +++ b/HopsanGUI/SimulationThreadHandler.h @@ -47,8 +47,8 @@ class GUIMessageHandler; #include "RemoteCoreAccess.h" #endif -enum SimulationWorkeObjectEnumT {LocalSWO, RemoteSWO, DCPSlaveSWO}; -enum class SimulationState {Initialize, Simulate, RemoteSimulate, DcpSlaveSimulate, Finalize, Done}; +enum SimulationWorkeObjectEnumT {LocalSWO, RemoteSWO, DCPManagerSWO, DCPSlaveSWO}; +enum class SimulationState {Initialize, Simulate, RemoteSimulate, DcpMasterSimulate, DcpSlaveSimulate, Finalize, Done}; Q_DECLARE_METATYPE(SimulationState); @@ -111,6 +111,21 @@ public slots: }; #endif +class DCPManagerSimulationWorkerObject : public SimulationWorkerObjectBase +{ + Q_OBJECT +private: + SystemObject *mpSystem; + QString mHost; + int mPort; +public: + DCPManagerSimulationWorkerObject(SystemObject *pSystem, const QString &host, int port); + int swoType() const {return DCPManagerSWO;} + +public slots: + void initSimulateFinalize(); +}; + class DCPSlaveSimulationWorkerObject : public SimulationWorkerObjectBase { Q_OBJECT @@ -214,6 +229,7 @@ protected slots: #ifdef USEZMQ void initSimulateFinalizeRemote(SharedRemoteCoreSimulationHandlerT pRCSH, QVector *pRemoteResultVariables, double *pProgress); #endif + void initSimulateFinalizeDcpManager(SystemObject *pSystem, const QString &host, int port); void initSimulateFinalizeDcpSlave(SystemObject *pSystem, const QString &host, int port, const QString &targetFile); void initSimulateFinalize(QVector vpSystems, const bool noChanges=false); void initSimulateFinalize_blocking(QVector vpSystems, const bool noChanges=false); diff --git a/HopsanGUI/Widgets/ModelWidget.cpp b/HopsanGUI/Widgets/ModelWidget.cpp index de700ffb51..93e7837758 100644 --- a/HopsanGUI/Widgets/ModelWidget.cpp +++ b/HopsanGUI/Widgets/ModelWidget.cpp @@ -193,6 +193,16 @@ void ModelWidget::setMessageHandler(GUIMessageHandler *pMessageHandler) connect(this, SIGNAL(checkMessages()), mpMessageHandler, SLOT(collectHopsanCoreMessages()), Qt::UniqueConnection); } +void ModelWidget::setModelType(ModelWidget::ModelType type) +{ + mModelType = type; +} + +ModelWidget::ModelType ModelWidget::getModelType() const +{ + return mModelType; +} + void ModelWidget::setTopLevelSimulationTime(const QString startTime, const QString timeStep, const QString stopTime, UndoStatusEnumT undoSettings) { if(undoSettings == Undo) { @@ -765,11 +775,63 @@ bool ModelWidget::simulateDcpSlave() mSimulationProgress=0; mpSimulationThreadHandler->initSimulateFinalizeDcpSlave(mpToplevelSystem, pHostLineEdit->text(), pPortSpinBox->value(), pTargetFileLineEdit->text()); + unlockSimulateMutex(); return true; //! @todo fix return code } +bool ModelWidget::simulateDcpManager() +{ + // Save backup copy + if (!isSaved() && gpConfig->getBoolSetting(CFG_AUTOBACKUP)) + { + //! @todo this should be a help function, also we may not want to call it every time when we run optimization (not sure if that is done now but probably) + QString fileNameWithoutHmf = mpToplevelSystem->getModelFileInfo().fileName(); + fileNameWithoutHmf.chop(4); + saveTo(gpDesktopHandler->getBackupPath() + fileNameWithoutHmf + "_sim_backup.hmf"); + } + + QDialog *pDcpSettingsDialog = new QDialog(gpMainWindowWidget); + QGridLayout *pDialogLayout = new QGridLayout(pDcpSettingsDialog); + QLineEdit *pHostLineEdit = new QLineEdit("127.0.0.1",pDcpSettingsDialog); + QSpinBox *pPortSpinBox = new QSpinBox(pDcpSettingsDialog); + pPortSpinBox->setMaximum(1000000); + pPortSpinBox->setValue(8180); + pPortSpinBox->setSingleStep(1); + QDialogButtonBox *pButtonBox = new QDialogButtonBox(pDcpSettingsDialog); + QPushButton *pOkButton = pButtonBox->addButton(QDialogButtonBox::Ok); + QPushButton *pCancelButton = pButtonBox->addButton(QDialogButtonBox::Cancel); + connect(pOkButton, SIGNAL(clicked()), pDcpSettingsDialog, SLOT(accept())); + connect(pCancelButton, SIGNAL(clicked()), pDcpSettingsDialog, SLOT(reject())); + pDialogLayout->addWidget(new QLabel("Host address:",pDcpSettingsDialog),0,0); + pDialogLayout->addWidget(pHostLineEdit,0,1,1,2); + pDialogLayout->addWidget(new QLabel("Port:",pDcpSettingsDialog),1,0); + pDialogLayout->addWidget(pPortSpinBox,1,1,1,2); + pDialogLayout->addWidget(pButtonBox, 3,1,1,3); + + if(pDcpSettingsDialog->exec() == QDialog::Rejected) { + return false; + } + + if(!mSimulateMutex.tryLock()) + { + gpMessageHandler->addErrorMessage("Simulation mutex is locked. Aborting."); + return false; + } + + mpSimulationThreadHandler->setSimulationTimeVariables(mStartTime.toDouble(), mStopTime.toDouble(), mpToplevelSystem->getLogStartTime(), mpToplevelSystem->getNumberOfLogSamples()); + mpSimulationThreadHandler->setProgressDilaogBehaviour(true, false); + mSimulationProgress=0; + mpSimulationThreadHandler->initSimulateFinalizeDcpManager(mpToplevelSystem, pHostLineEdit->text(), pPortSpinBox->value()); + + unlockSimulateMutex(); + + return true; + //! @todo fix return code + +} + //! Slot that saves current project to old file name if it exists. //! @see saveModel(int index) diff --git a/HopsanGUI/Widgets/ModelWidget.h b/HopsanGUI/Widgets/ModelWidget.h index 31b25054e0..147039316c 100644 --- a/HopsanGUI/Widgets/ModelWidget.h +++ b/HopsanGUI/Widgets/ModelWidget.h @@ -67,11 +67,19 @@ class ModelWidget : public QWidget friend class ModelHandler; public: + enum ModelType { + HopsanModel = 0x0, + DcpModel = 0x1, + }; + ModelWidget(ModelHandler *pModelHandler, CentralTabWidget *pParentTabWidget = nullptr); ~ModelWidget(); void setMessageHandler(GUIMessageHandler *pMessageHandler); + void setModelType(ModelType type); + ModelType getModelType() const; + QString getStartTime(); QString getTimeStep(); QString getStopTime(); @@ -122,6 +130,7 @@ public slots: bool startRealtimeSimulation(const double realtimeFactor); void stopRealtimeSimulation(); bool simulateDcpSlave(); + bool simulateDcpManager(); void save(); void saveAs(); void exportModelParametersToHpf(); @@ -159,6 +168,8 @@ private slots: void saveModel(SaveTargetEnumT saveAsFlag, SaveContentsEnumT contents=FullModel); void createOrDestroyToplevelSystem(bool recreate); + ModelType mModelType; + QString mStartTime, mStopTime; int mLastSimulationTime; diff --git a/HopsanGUI/common.h b/HopsanGUI/common.h index 0db37ac33d..52c2081747 100644 --- a/HopsanGUI/common.h +++ b/HopsanGUI/common.h @@ -57,6 +57,7 @@ namespace hopsanweblinks { // Gui TypeName defines #define HOPSANGUISYSTEMTYPENAME "Subsystem" +#define HOPSANGUIDCPCOMPONENT "DcpComponent" #define HOPSANGUICONDITIONALSYSTEMTYPENAME "ConditionalSubsystem" #define HOPSANGUISYSTEMPORTTYPENAME "HopsanGUISystemPort" #define HOPSANGUISCOPECOMPONENTTYPENAME "SignalSink" diff --git a/HopsanGUI/graphics/builtinCAF/hidden/dcpcomponent.xml b/HopsanGUI/graphics/builtinCAF/hidden/dcpcomponent.xml new file mode 100644 index 0000000000..06e4f02ccf --- /dev/null +++ b/HopsanGUI/graphics/builtinCAF/hidden/dcpcomponent.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/HopsanGUI/graphics/objecticons/dcpcomponent.svg b/HopsanGUI/graphics/objecticons/dcpcomponent.svg new file mode 100644 index 0000000000..6cab416f2b --- /dev/null +++ b/HopsanGUI/graphics/objecticons/dcpcomponent.svg @@ -0,0 +1,87 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + diff --git a/HopsanGUI/graphics/uiicons/svg/Hopsan-NewDcpModel.svg b/HopsanGUI/graphics/uiicons/svg/Hopsan-NewDcpModel.svg new file mode 100644 index 0000000000..f957153b64 --- /dev/null +++ b/HopsanGUI/graphics/uiicons/svg/Hopsan-NewDcpModel.svg @@ -0,0 +1,377 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + diff --git a/HopsanGUI/graphics/uiicons/svg/Hopsan-StartDcpManager.svg b/HopsanGUI/graphics/uiicons/svg/Hopsan-StartDcpManager.svg new file mode 100644 index 0000000000..f9cc62cb58 --- /dev/null +++ b/HopsanGUI/graphics/uiicons/svg/Hopsan-StartDcpManager.svg @@ -0,0 +1,513 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/HopsanGUI/graphics/uiicons/svg/Hopsan-StartDcpServer.svg b/HopsanGUI/graphics/uiicons/svg/Hopsan-StartDcpServer.svg new file mode 100644 index 0000000000..e3f0ddc4a6 --- /dev/null +++ b/HopsanGUI/graphics/uiicons/svg/Hopsan-StartDcpServer.svg @@ -0,0 +1,430 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + diff --git a/hopsandcp/include/dcpmaster.h b/hopsandcp/include/dcpmaster.h index 696af5cd28..5e1d34425e 100644 --- a/hopsandcp/include/dcpmaster.h +++ b/hopsandcp/include/dcpmaster.h @@ -3,18 +3,20 @@ #include "hopsandcp_win32dll.h" -#include "dcp/model/constant/DcpState.hpp" -#include "dcp/model/constant/DcpError.hpp" -#include "dcp/log/OstreamLog.hpp" +#include "HopsanEssentials.h" +#include "ComponentUtilities/num2string.hpp" #include #include using namespace std; +class SlaveDescription_t; class DcpManagerMaster; class UdpDriver; -class SlaveDescription_t; +class OstreamLog; +enum class DcpState : uint8_t; +enum class DcpError : uint16_t; struct DcpConnection { @@ -25,10 +27,10 @@ struct DcpConnection HOPSANDCP_DLLAPI class DcpMaster { public: - DcpMaster(const string host, u_short port); + DcpMaster(const string host, int port, double comStep); ~DcpMaster(); - void addSlave(std::string &filepath); + void addSlave(string filepath); void addConnection(size_t fromId, size_t fromVr, std::vector toIds, std::vector toVrs); void start(); @@ -53,14 +55,15 @@ HOPSANDCP_DLLAPI class DcpMaster std::map curState; + double mComStep; + UdpDriver *driver; - OstreamLog stdLog; + OstreamLog *mpStdLog; DcpManagerMaster *manager; uint64_t nSteps=0; - uint64_t secondsToSimulate = 10; std::map numOfCmd; std::map receivedAcks; @@ -71,10 +74,12 @@ HOPSANDCP_DLLAPI class DcpMaster uint8_t slavesWaitingForStep = 0; uint8_t slavesWaitingForConfiguration = 0; uint8_t slavesWaitingAtExit = 0; - uint8_t slavesWaitingForDeregister = 0; + uint8_t slavesWaitingToStop = 0; uint8_t slavesWaitingForInitialize = 0; uint8_t slavesWaitingToRun = 0; - uint8_t stoppedSlaves = 0; }; +void getDataFromSlaveDescription(const hopsan::HString &rFilePath, hopsan::HString &rName, hopsan::HString &rVariables, hopsan::HString &rValueReferences); + + #endif // DCPMASTER_H diff --git a/hopsandcp/src/dcpmaster.cpp b/hopsandcp/src/dcpmaster.cpp index aecaaaa5c0..47306af87e 100644 --- a/hopsandcp/src/dcpmaster.cpp +++ b/hopsandcp/src/dcpmaster.cpp @@ -1,21 +1,24 @@ #include "dcpmaster.h" -#include -#include -#include -#include - +#include "dcp/log/OstreamLog.hpp" #include "dcp/helper/LogHelper.hpp" #include "dcp/model/pdu/DcpPduFactory.hpp" #include "dcp/xml/DcpSlaveDescriptionReader.hpp" #include "dcp/driver/ethernet/udp/UdpDriver.hpp" #include "dcp/logic/DcpManagerMaster.hpp" +#include +#include +#include +#include +#include -DcpMaster::DcpMaster(const std::string host, u_short port) - : stdLog(std::cout) +DcpMaster::DcpMaster(const std::string host, int port, double comStep=0.001) + : mComStep(comStep) { - driver = new UdpDriver(host, port); + OstreamLog stdLog(std::cout); + + driver = new UdpDriver(host, port_t(port)); manager = new DcpManagerMaster(driver->getDcpDriver()); @@ -38,7 +41,7 @@ DcpMaster::~DcpMaster() { delete manager; } -void DcpMaster::addSlave(string &filepath) +void DcpMaster::addSlave(string filepath) { slaveDescriptions.push_back(new SlaveDescription_t(*readSlaveDescription(filepath.c_str()))); u_char id = u_char(slaveDescriptions.size()); @@ -94,9 +97,12 @@ void DcpMaster::configuration() { std::cout << "Configure Slaves" << std::endl; //Count received acks so that we know when all configuration messages are acknowledged - for(size_t i=0; iCFG_time_res(uint8_t(i), 1, uint32_t(std::floor(1.0/mComStep))); + numOfCmd[dcpId_t(i)]++; } for(size_t i=0; istop(); break; case DcpState::ALIVE: //simulation finished slavesWaitingAtExit++; - if(slavesWaitingAtExit < 2) { + if(slavesWaitingAtExit < slaveDescriptions.size()) { return; } - std::exit(0); + break; case DcpState::PREPARING: default: @@ -260,3 +267,52 @@ void DcpMaster::receiveStateChangedNotification(uint8_t sender, } } + + +void getDataFromSlaveDescription(const hopsan::HString &rFilePath, hopsan::HString &rName, hopsan::HString &rVariables, hopsan::HString &rValueReferences) +{ + shared_ptr slaveDesc = readSlaveDescription(rFilePath.c_str()); + hopsan::HString inputs,outputs,pars; + hopsan::HString inputVrs, outputVrs, parVrs; + for(const auto &var : slaveDesc->Variables) { + if(var.Input.get() != nullptr) { + inputs.append(hopsan::HString(var.name.c_str())+","); + inputVrs.append(to_hstring(var.valueReference)+","); + } + else if(var.Output.get() != nullptr) { + outputs.append(hopsan::HString(var.name.c_str())+","); + outputVrs.append(to_hstring(var.valueReference)+","); + } + else if(var.Parameter.get() != nullptr) { + pars.append(hopsan::HString(var.name.c_str())+","); + parVrs.append(to_hstring(var.valueReference)+","); + } + } + if(!inputs.empty()) { + inputs.erase(inputs.size()-1); + inputVrs.erase(inputVrs.size()-1); + } + if(!outputs.empty()) { + outputs.erase(outputs.size()-1); + outputVrs.erase(outputVrs.size()-1); + } + if(!pars.empty()) { + pars.erase(pars.size()-1); + parVrs.erase(parVrs.size()-1); + } + rName = slaveDesc->dcpSlaveName.c_str(); + + //Variables names are stored in a semicolon and comma separated string. + //Variable types are separated by semicolons, while variable names within + //each type are separated by commas. + rVariables = inputs+";"+outputs+";"+pars; + + //Value references is a plain comma-separated string + rValueReferences = inputVrs+","+outputVrs+","+parVrs; + + //Value references string could end with a comma if one + //of the lists above is empty. If so, remove this. + if(rValueReferences.at(rValueReferences.size()-1) == ',') { + rValueReferences.erase(rValueReferences.size()-1); + } +} diff --git a/hopsandcp/src/dcpslave.cpp b/hopsandcp/src/dcpslave.cpp index faf3dfc064..d887f65c64 100644 --- a/hopsandcp/src/dcpslave.cpp +++ b/hopsandcp/src/dcpslave.cpp @@ -205,5 +205,7 @@ void DcpSlave::setTimeRes(const uint32_t numerator, const uint32_t denominator) void DcpSlave::stop() { - dynamic_cast(mManager)->stop(); + //dynamic_cast(mManager)->stop(); + udpDriver->getDcpDriver().stopReceiving(); + udpDriver->getDcpDriver().disconnect(); } From 84a1dc72eaf58e41060ad95322b4b6e1e9d15ee3 Mon Sep 17 00:00:00 2001 From: Robert Braun Date: Thu, 11 Feb 2021 16:10:51 +0100 Subject: [PATCH 12/34] Saving and loading of DCP master models --- HopsanGUI/ModelHandler.cpp | 1 + HopsanGUI/Utilities/XMLUtilities.cpp | 5 ++++- HopsanGUI/Utilities/XMLUtilities.h | 3 ++- HopsanGUI/Widgets/ModelWidget.cpp | 9 ++++++++- HopsanGUI/Widgets/ModelWidget.h | 2 +- 5 files changed, 16 insertions(+), 4 deletions(-) diff --git a/HopsanGUI/ModelHandler.cpp b/HopsanGUI/ModelHandler.cpp index 5a4fea7da5..29e2888b22 100644 --- a/HopsanGUI/ModelHandler.cpp +++ b/HopsanGUI/ModelHandler.cpp @@ -361,6 +361,7 @@ ModelWidget *ModelHandler::loadModel(QString modelFileName, LoadOptions options) addModelWidget(pNewModel, modelFileInfo.baseName(), options); bool loadOK = pNewModel->loadModel(modelFile); if (loadOK) { + gpMainWindow->updateToolBarsToNewTab(); emit newModelWidgetAdded(); if(!options.testFlag(Detatched)) { emit modelChanged(pNewModel); diff --git a/HopsanGUI/Utilities/XMLUtilities.cpp b/HopsanGUI/Utilities/XMLUtilities.cpp index 6386da5bad..d87b42bbf5 100644 --- a/HopsanGUI/Utilities/XMLUtilities.cpp +++ b/HopsanGUI/Utilities/XMLUtilities.cpp @@ -102,13 +102,16 @@ void appendRootXMLProcessingInstruction(QDomDocument &rDomDocument) //! @param[in] hopsanGuiVersion The version string of the Hopsan GUI Application //! @param[in] hopsanCoreVersion The version string of the Hopsan Core Library //! @returns The created root DOM element -QDomElement appendHMFRootElement(QDomDocument &rDomDocument, QString hmfVersion, QString hopsanGuiVersion, QString hopsanCoreVersion) +QDomElement appendHMFRootElement(QDomDocument &rDomDocument, QString hmfVersion, QString hopsanGuiVersion, QString hopsanCoreVersion, QString customType) { QDomElement hmfRoot = rDomDocument.createElement(hmf::root); rDomDocument.appendChild(hmfRoot); hmfRoot.setAttribute(hmf::version::hmf, hmfVersion); hmfRoot.setAttribute(hmf::version::hopsangui, hopsanGuiVersion); hmfRoot.setAttribute(hmf::version::hopsancore, hopsanCoreVersion); + if(!customType.isEmpty()) { + hmfRoot.setAttribute(hmf::customtype, customType); + } return hmfRoot; } diff --git a/HopsanGUI/Utilities/XMLUtilities.h b/HopsanGUI/Utilities/XMLUtilities.h index ddb1211f01..9e6e3e7d5a 100644 --- a/HopsanGUI/Utilities/XMLUtilities.h +++ b/HopsanGUI/Utilities/XMLUtilities.h @@ -42,7 +42,7 @@ QDomElement loadXMLDomDocument(QFile &rFile, QDomDocument &rDomDocument, QString void appendRootXMLProcessingInstruction(QDomDocument &rDomDocument); -QDomElement appendHMFRootElement(QDomDocument &rDomDocument, QString hmfVersion, QString hopsanGuiVersion, QString hopsanCoreVersion); +QDomElement appendHMFRootElement(QDomDocument &rDomDocument, QString hmfVersion, QString hopsanGuiVersion, QString hopsanCoreVersion, QString customType=QString()); QDomElement getOrAppendNewDomElement(QDomElement &rDomElement, const QString element_name); QDomComment appendComment(QDomElement &rDomElement, const QString &rComment); @@ -158,6 +158,7 @@ namespace hmf { constexpr auto simulationlogsettings = "simulationlogsettings"; constexpr auto scriptfile = "scriptfile"; constexpr auto undo = "hopsanundo"; + constexpr auto customtype = "customtype"; namespace widget { constexpr auto textboxwidget = "textboxwidget"; diff --git a/HopsanGUI/Widgets/ModelWidget.cpp b/HopsanGUI/Widgets/ModelWidget.cpp index 93e7837758..953d2430d5 100644 --- a/HopsanGUI/Widgets/ModelWidget.cpp +++ b/HopsanGUI/Widgets/ModelWidget.cpp @@ -1525,6 +1525,9 @@ bool ModelWidget::loadModel(QFile &rModelFile) // Check if this is an expected hmf xml file QDomDocument domDocument; QDomElement hmfRoot = loadXMLDomDocument(rModelFile, domDocument, hmf::root); + if(hmfRoot.attribute(hmf::customtype) == "dcp") { + mModelType = DcpModel; + } if (!hmfRoot.isNull()) { //! @todo check if we could load else give error message and don't attempt to load @@ -1627,7 +1630,11 @@ QDomDocument ModelWidget::saveToDom(SaveContentsEnumT contents) QDomElement rootElement; if(contents==FullModel) { - rootElement = appendHMFRootElement(domDocument, HMF_VERSIONNUM, HOPSANGUIVERSION, getHopsanCoreVersion()); + QString customType; + if(mModelType == DcpModel) { + customType = "dcp"; + } + rootElement = appendHMFRootElement(domDocument, HMF_VERSIONNUM, HOPSANGUIVERSION, getHopsanCoreVersion(), customType); } else { diff --git a/HopsanGUI/Widgets/ModelWidget.h b/HopsanGUI/Widgets/ModelWidget.h index 147039316c..72f8b23917 100644 --- a/HopsanGUI/Widgets/ModelWidget.h +++ b/HopsanGUI/Widgets/ModelWidget.h @@ -168,7 +168,7 @@ private slots: void saveModel(SaveTargetEnumT saveAsFlag, SaveContentsEnumT contents=FullModel); void createOrDestroyToplevelSystem(bool recreate); - ModelType mModelType; + ModelType mModelType = HopsanModel; QString mStartTime, mStopTime; int mLastSimulationTime; From de794ad316591a5c6870a15435239efb90c4ef4c Mon Sep 17 00:00:00 2001 From: Robert Braun Date: Fri, 12 Feb 2021 09:00:23 +0100 Subject: [PATCH 13/34] Use .dcp files instead of .dcpx --- HopsanCore/include/Components/DcpComponent.hpp | 6 +++--- HopsanGUI/GraphicsView.cpp | 14 +++++++------- HopsanGUI/SimulationThreadHandler.cpp | 4 ++-- HopsanGUI/Widgets/ModelWidget.cpp | 2 +- .../graphics/builtinCAF/hidden/dcpcomponent.xml | 2 +- hopsandcp/include/dcpslave.h | 2 +- hopsandcp/src/dcpmaster.cpp | 6 +++--- hopsandcp/src/dcpslave.cpp | 6 +++--- 8 files changed, 21 insertions(+), 21 deletions(-) diff --git a/HopsanCore/include/Components/DcpComponent.hpp b/HopsanCore/include/Components/DcpComponent.hpp index 197abce44f..f4305badc2 100644 --- a/HopsanCore/include/Components/DcpComponent.hpp +++ b/HopsanCore/include/Components/DcpComponent.hpp @@ -42,7 +42,7 @@ namespace hopsan { { private: //Parameters - HString mDcpxFile; + HString mDcpFile; HString mVariables; HString mValueRefs; HString mLastVariables; @@ -61,7 +61,7 @@ namespace hopsan { void configure() { - addConstant("dcpxFile", "", "", "", mDcpxFile); + addConstant("dcpFile", "", "", "", mDcpFile); addConstant("valueRefs", "vr1,vr2,vr3...", "", "", mValueRefs); addConstant("variables", "in1,in2;out1,out2;par1,par2...", "", "", mVariables); setReconfigurationParameter("variables"); @@ -82,7 +82,7 @@ namespace hopsan { std::vector parameters; this->getParameterNames(parameters); for(size_t i=0; iunRegisterParameter(parameters[i]); } } diff --git a/HopsanGUI/GraphicsView.cpp b/HopsanGUI/GraphicsView.cpp index 28b913f966..657adcae27 100644 --- a/HopsanGUI/GraphicsView.cpp +++ b/HopsanGUI/GraphicsView.cpp @@ -152,21 +152,21 @@ void GraphicsView::contextMenuEvent ( QContextMenuEvent * event ) mpContainerObject->getUndoStackPtr()->newPost(); mpContainerObject->addImageWidget(this->mapToScene(event->pos()).toPoint()); else if(addDcpServerAction != nullptr && selectedAction == addDcpServerAction) { - QString dcpxPath = QFileDialog::getOpenFileName(gpMainWindowWidget, tr("Select DCP Slave Description File"), + QString dcpPath = QFileDialog::getOpenFileName(gpMainWindowWidget, tr("Select DCP Slave Description File"), gpConfig->getStringSetting(CFG_DCPDIR), - tr("DCP Slave Description (*.dcpx)")); - if(dcpxPath.isEmpty()) { + tr("Distributed Co-Simulation Protocol File (*.dcp)")); + if(dcpPath.isEmpty()) { return; } - QFileInfo dcpxFileInfo(dcpxPath); - gpConfig->setStringSetting(CFG_DCPDIR, dcpxFileInfo.absolutePath()); + QFileInfo dcpFileInfo(dcpPath); + gpConfig->setStringSetting(CFG_DCPDIR, dcpFileInfo.absolutePath()); hopsan::HString name, variables, valueRefs; - getDataFromSlaveDescription(dcpxFileInfo.filePath().toStdString().c_str(), name, variables, valueRefs); + getDataFromSlaveDescription(dcpFileInfo.filePath().toStdString().c_str(), name, variables, valueRefs); ModelObject *pObj = mpContainerObject->addModelObject(HOPSANGUIDCPCOMPONENT, this->mapToScene(event->pos()).toPoint()); mpParentModelWidget->getTopLevelSystemContainer()->renameModelObject(pObj->getName(), (name.c_str())); - pObj->setParameterValue("dcpxFile", dcpxFileInfo.absoluteFilePath()); + pObj->setParameterValue("dcpFile", dcpFileInfo.absoluteFilePath()); pObj->setParameterValue("valueRefs", valueRefs.c_str()); pObj->setParameterValue("variables",variables.c_str()); //Must be called AFTER the two other parameters, since this variable triggers the reconfiguration } diff --git a/HopsanGUI/SimulationThreadHandler.cpp b/HopsanGUI/SimulationThreadHandler.cpp index 08832f0fec..1a0d651395 100644 --- a/HopsanGUI/SimulationThreadHandler.cpp +++ b/HopsanGUI/SimulationThreadHandler.cpp @@ -596,7 +596,7 @@ void DCPSlaveSimulationWorkerObject::initSimulateFinalize() // Initializing emit setProgressState(SimulationState::Initialize); timer.start(); - pDcpSlave->generateDescriptionFile(mTargetFile.toStdString()); + pDcpSlave->generateDcpFile(mTargetFile.toStdString()); emit initDone(true, timer.elapsed()); // Simulating @@ -629,7 +629,7 @@ void DCPManagerSimulationWorkerObject::initSimulateFinalize() DcpMaster *pDcpMaster = new DcpMaster(mHost.toStdString(), mPort, mpSystem->getTimeStep()); for(const auto comp : mpSystem->getModelObjects()) { if(comp->getTypeName() == HOPSANGUIDCPCOMPONENT) { //Just in case, model shall only contain DCP components anyway - pDcpMaster->addSlave(comp->getParameterValue("dcpxFile").toStdString()); + pDcpMaster->addSlave(comp->getParameterValue("dcpFile").toStdString()); } } std::map,std::pair,std::vector > > connections; diff --git a/HopsanGUI/Widgets/ModelWidget.cpp b/HopsanGUI/Widgets/ModelWidget.cpp index 953d2430d5..eb3ca8cd82 100644 --- a/HopsanGUI/Widgets/ModelWidget.cpp +++ b/HopsanGUI/Widgets/ModelWidget.cpp @@ -746,7 +746,7 @@ bool ModelWidget::simulateDcpSlave() pPortSpinBox->setMaximum(1000000); pPortSpinBox->setValue(8080); pPortSpinBox->setSingleStep(1); - QLineEdit *pTargetFileLineEdit = new QLineEdit(gpDesktopHandler->getDocumentsPath()+"/"+getTopLevelSystemContainer()->getModelFileInfo().baseName()+".dcpx"); + QLineEdit *pTargetFileLineEdit = new QLineEdit(gpDesktopHandler->getDocumentsPath()+"/"+getTopLevelSystemContainer()->getModelFileInfo().baseName()+".dcp"); QDialogButtonBox *pButtonBox = new QDialogButtonBox(pDialog); QPushButton *pOkButton = pButtonBox->addButton(QDialogButtonBox::Ok); QPushButton *pCancelButton = pButtonBox->addButton(QDialogButtonBox::Cancel); diff --git a/HopsanGUI/graphics/builtinCAF/hidden/dcpcomponent.xml b/HopsanGUI/graphics/builtinCAF/hidden/dcpcomponent.xml index 06e4f02ccf..f7344d1e3f 100644 --- a/HopsanGUI/graphics/builtinCAF/hidden/dcpcomponent.xml +++ b/HopsanGUI/graphics/builtinCAF/hidden/dcpcomponent.xml @@ -5,7 +5,7 @@ - + diff --git a/hopsandcp/include/dcpslave.h b/hopsandcp/include/dcpslave.h index 0ac6d3af16..6479117e2f 100644 --- a/hopsandcp/include/dcpslave.h +++ b/hopsandcp/include/dcpslave.h @@ -22,7 +22,7 @@ HOPSANDCP_DLLAPI class DcpSlave DcpSlave(hopsan::ComponentSystem *pSystem, const std::string host, int port, size_t numLogSamples); ~DcpSlave(); - void generateDescriptionFile(std::string targetFile); + void generateDcpFile(std::string targetFile); bool start(); private: diff --git a/hopsandcp/src/dcpmaster.cpp b/hopsandcp/src/dcpmaster.cpp index 47306af87e..aeb9f3aa03 100644 --- a/hopsandcp/src/dcpmaster.cpp +++ b/hopsandcp/src/dcpmaster.cpp @@ -3,7 +3,7 @@ #include "dcp/log/OstreamLog.hpp" #include "dcp/helper/LogHelper.hpp" #include "dcp/model/pdu/DcpPduFactory.hpp" -#include "dcp/xml/DcpSlaveDescriptionReader.hpp" +#include "dcp/zip/DcpSlaveReader.hpp" #include "dcp/driver/ethernet/udp/UdpDriver.hpp" #include "dcp/logic/DcpManagerMaster.hpp" @@ -43,7 +43,7 @@ DcpMaster::~DcpMaster() { void DcpMaster::addSlave(string filepath) { - slaveDescriptions.push_back(new SlaveDescription_t(*readSlaveDescription(filepath.c_str()))); + slaveDescriptions.push_back(new SlaveDescription_t(*getSlaveDescriptionFromDcpFile(1,0,filepath.c_str()))); u_char id = u_char(slaveDescriptions.size()); uint8_t *netInfo = new uint8_t[6]; //*((uint8_t *) netInfo) = *slaveDescriptions.back()->TransportProtocols.UDP_IPv4->Control->port; @@ -271,7 +271,7 @@ void DcpMaster::receiveStateChangedNotification(uint8_t sender, void getDataFromSlaveDescription(const hopsan::HString &rFilePath, hopsan::HString &rName, hopsan::HString &rVariables, hopsan::HString &rValueReferences) { - shared_ptr slaveDesc = readSlaveDescription(rFilePath.c_str()); + shared_ptr slaveDesc = getSlaveDescriptionFromDcpFile(1,0,rFilePath.c_str()); hopsan::HString inputs,outputs,pars; hopsan::HString inputVrs, outputVrs, parVrs; for(const auto &var : slaveDesc->Variables) { diff --git a/hopsandcp/src/dcpslave.cpp b/hopsandcp/src/dcpslave.cpp index d887f65c64..75ed3fe979 100644 --- a/hopsandcp/src/dcpslave.cpp +++ b/hopsandcp/src/dcpslave.cpp @@ -4,7 +4,7 @@ #include #include #include -#include +#include #include #include @@ -129,8 +129,8 @@ SlaveDescription_t *DcpSlave::getSlaveDescription() { } -void DcpSlave::generateDescriptionFile(std::string targetFile) { - writeDcpSlaveDescription(*getSlaveDescription(), targetFile.c_str()); +void DcpSlave::generateDcpFile(std::string targetFile) { + writeDcpSlaveFile(std::shared_ptr(getSlaveDescription()), targetFile.c_str()); } bool DcpSlave::start() From 1dd489b6f2ae1ab2d760a59c851798b3956c0e79 Mon Sep 17 00:00:00 2001 From: Robert Braun Date: Fri, 12 Feb 2021 09:29:53 +0100 Subject: [PATCH 14/34] Rename DCP "slaves" to "servers" --- HopsanGUI/GraphicsView.cpp | 6 +- HopsanGUI/ModelHandler.cpp | 4 +- HopsanGUI/SimulationThreadHandler.cpp | 36 +++--- HopsanGUI/SimulationThreadHandler.h | 12 +- HopsanGUI/Widgets/ModelWidget.cpp | 9 +- HopsanGUI/Widgets/ModelWidget.h | 2 +- hopsandcp/hopsandcp.pro | 4 +- hopsandcp/include/dcpmaster.h | 24 ++-- hopsandcp/include/{dcpslave.h => dcpserver.h} | 14 +-- hopsandcp/src/dcpmaster.cpp | 111 ++++++++---------- hopsandcp/src/{dcpslave.cpp => dcpserver.cpp} | 90 +++++++------- 11 files changed, 150 insertions(+), 162 deletions(-) rename hopsandcp/include/{dcpslave.h => dcpserver.h} (77%) rename hopsandcp/src/{dcpslave.cpp => dcpserver.cpp} (61%) diff --git a/HopsanGUI/GraphicsView.cpp b/HopsanGUI/GraphicsView.cpp index 657adcae27..cc38e258ab 100644 --- a/HopsanGUI/GraphicsView.cpp +++ b/HopsanGUI/GraphicsView.cpp @@ -152,9 +152,9 @@ void GraphicsView::contextMenuEvent ( QContextMenuEvent * event ) mpContainerObject->getUndoStackPtr()->newPost(); mpContainerObject->addImageWidget(this->mapToScene(event->pos()).toPoint()); else if(addDcpServerAction != nullptr && selectedAction == addDcpServerAction) { - QString dcpPath = QFileDialog::getOpenFileName(gpMainWindowWidget, tr("Select DCP Slave Description File"), + QString dcpPath = QFileDialog::getOpenFileName(gpMainWindowWidget, tr("Select Distributed Co-Simlation Protocol File"), gpConfig->getStringSetting(CFG_DCPDIR), - tr("Distributed Co-Simulation Protocol File (*.dcp)")); + tr("Distributed Co-Simulation Protocol Files (*.dcp)")); if(dcpPath.isEmpty()) { return; } @@ -162,7 +162,7 @@ void GraphicsView::contextMenuEvent ( QContextMenuEvent * event ) gpConfig->setStringSetting(CFG_DCPDIR, dcpFileInfo.absolutePath()); hopsan::HString name, variables, valueRefs; - getDataFromSlaveDescription(dcpFileInfo.filePath().toStdString().c_str(), name, variables, valueRefs); + getDataFromProtocolFile(dcpFileInfo.filePath().toStdString().c_str(), name, variables, valueRefs); ModelObject *pObj = mpContainerObject->addModelObject(HOPSANGUIDCPCOMPONENT, this->mapToScene(event->pos()).toPoint()); mpParentModelWidget->getTopLevelSystemContainer()->renameModelObject(pObj->getName(), (name.c_str())); diff --git a/HopsanGUI/ModelHandler.cpp b/HopsanGUI/ModelHandler.cpp index 29e2888b22..de895f3d95 100644 --- a/HopsanGUI/ModelHandler.cpp +++ b/HopsanGUI/ModelHandler.cpp @@ -725,7 +725,7 @@ void ModelHandler::disconnectMainWindowConnections(ModelWidget *pModel) disconnect(gpMainWindow, SIGNAL(simulateKeyPressed()), pModel, SLOT(simulate_nonblocking())); disconnect(gpMainWindow->mpToggleRemoteCoreSimAction, SIGNAL(triggered(bool)), pModel, SLOT(setUseRemoteSimulation(bool))); - disconnect(gpMainWindow->mpStartDcpServerAction, SIGNAL(triggered()), pModel, SLOT(simulateDcpSlave())); + disconnect(gpMainWindow->mpStartDcpServerAction, SIGNAL(triggered()), pModel, SLOT(simulateDcpServer())); disconnect(gpMainWindow->mpStartDcpManagerAction, SIGNAL(triggered()), pModel, SLOT(simulateDcpManager())); disconnect(gpMainWindow->mpSaveAction, SIGNAL(triggered()), pModel, SLOT(save())); disconnect(gpMainWindow->mpSaveAsAction, SIGNAL(triggered()), pModel, SLOT(saveAs())); @@ -767,7 +767,7 @@ void ModelHandler::connectMainWindowConnections(ModelWidget *pModel) connect(gpMainWindow, SIGNAL(simulateKeyPressed()), pModel, SLOT(simulate_nonblocking()), Qt::UniqueConnection); connect(gpMainWindow->mpToggleRemoteCoreSimAction, SIGNAL(triggered(bool)), pModel, SLOT(setUseRemoteSimulation(bool)), Qt::UniqueConnection); - connect(gpMainWindow->mpStartDcpServerAction, SIGNAL(triggered()), pModel, SLOT(simulateDcpSlave()), Qt::UniqueConnection); + connect(gpMainWindow->mpStartDcpServerAction, SIGNAL(triggered()), pModel, SLOT(simulateDcpServer()), Qt::UniqueConnection); connect(gpMainWindow->mpStartDcpManagerAction, SIGNAL(triggered()), pModel, SLOT(simulateDcpManager()), Qt::UniqueConnection); connect(gpMainWindow->mpSaveAction, SIGNAL(triggered()), pModel, SLOT(save()), Qt::UniqueConnection); connect(gpMainWindow->mpSaveAsAction, SIGNAL(triggered()), pModel, SLOT(saveAs()), Qt::UniqueConnection); diff --git a/HopsanGUI/SimulationThreadHandler.cpp b/HopsanGUI/SimulationThreadHandler.cpp index 1a0d651395..eeee167188 100644 --- a/HopsanGUI/SimulationThreadHandler.cpp +++ b/HopsanGUI/SimulationThreadHandler.cpp @@ -39,7 +39,7 @@ #include "global.h" #include "GUIObjects/GUIContainerObject.h" #include "dcpmaster.h" -#include "dcpslave.h" +#include "dcpserver.h" #include "GUIConnector.h" #include "GUIPort.h" @@ -248,7 +248,7 @@ void ProgressBarWorkerObject::setProgressBarState(SimulationState state) emit setProgressBarText(tr("Simulating...")); emit setProgressBarRange(0, 0); break; - case SimulationState::DcpSlaveSimulate: + case SimulationState::DcpServerSimulate: emit setProgressBarText(tr("Running DCP simulation...")); emit setProgressBarRange(0, 0); startRefreshTimer(gpConfig->getProgressBarStep()); @@ -348,11 +348,11 @@ void SimulationThreadHandler::initSimulateFinalizeDcpManager(SystemObject *pSyst } -void SimulationThreadHandler::initSimulateFinalizeDcpSlave(SystemObject* pSystem, const QString &host, int port, const QString &targetFile) +void SimulationThreadHandler::initSimulateFinalizeDcpServer(SystemObject* pSystem, const QString &host, int port, const QString &targetFile) { mvpSystems.clear(); mvpSystems.push_back(pSystem); - mpSimulationWorkerObject = new DCPSlaveSimulationWorkerObject(pSystem, host, port, targetFile); + mpSimulationWorkerObject = new DcpServerSimulationWorkerObject(pSystem, host, port, targetFile); mpSimulationWorkerObject->setMessageHandler(mpMessageHandler); initSimulateFinalizePrivate(); } @@ -580,7 +580,7 @@ void SimulationThreadHandler::setMessageHandler(GUIMessageHandler *pMessageHandl mpMessageHandler = pMessageHandler; } -DCPSlaveSimulationWorkerObject::DCPSlaveSimulationWorkerObject(SystemObject *pSystem, const QString &host, int port, const QString &targetFile) +DcpServerSimulationWorkerObject::DcpServerSimulationWorkerObject(SystemObject *pSystem, const QString &host, int port, const QString &targetFile) { mpSystem = pSystem; mHost = host; @@ -588,26 +588,26 @@ DCPSlaveSimulationWorkerObject::DCPSlaveSimulationWorkerObject(SystemObject *pSy mTargetFile = targetFile; } -void DCPSlaveSimulationWorkerObject::initSimulateFinalize() +void DcpServerSimulationWorkerObject::initSimulateFinalize() { QTime timer; - DcpSlave *pDcpSlave = new DcpSlave(mpSystem->getCoreSystemAccessPtr()->getCoreSystemPtr(), mHost.toStdString(), mPort, mpSystem->getNumberOfLogSamples()); + DcpServer *pDcpServer = new DcpServer(mpSystem->getCoreSystemAccessPtr()->getCoreSystemPtr(), mHost.toStdString(), mPort, mpSystem->getNumberOfLogSamples()); // Initializing emit setProgressState(SimulationState::Initialize); timer.start(); - pDcpSlave->generateDcpFile(mTargetFile.toStdString()); + pDcpServer->generateDcpFile(mTargetFile.toStdString()); emit initDone(true, timer.elapsed()); // Simulating - emit setProgressState(SimulationState::DcpSlaveSimulate); + emit setProgressState(SimulationState::DcpServerSimulate); gpMessageHandler->addInfoMessage("Starting a DCP simulation..."); - bool success = pDcpSlave->start(); + bool success = pDcpServer->start(); gpMessageHandler->addInfoMessage("DCP simulation finished!"); emit simulateDone(success, timer.elapsed()); // Finalizing - delete pDcpSlave; + delete pDcpServer; // Finalizing emit setProgressState(SimulationState::Finalize); emit finalizeDone(true, timer.elapsed()); @@ -629,7 +629,7 @@ void DCPManagerSimulationWorkerObject::initSimulateFinalize() DcpMaster *pDcpMaster = new DcpMaster(mHost.toStdString(), mPort, mpSystem->getTimeStep()); for(const auto comp : mpSystem->getModelObjects()) { if(comp->getTypeName() == HOPSANGUIDCPCOMPONENT) { //Just in case, model shall only contain DCP components anyway - pDcpMaster->addSlave(comp->getParameterValue("dcpFile").toStdString()); + pDcpMaster->addServer(comp->getParameterValue("dcpFile").toStdString()); } } std::map,std::pair,std::vector > > connections; @@ -638,8 +638,8 @@ void DCPManagerSimulationWorkerObject::initSimulateFinalize() Port *pEndPort = connection->getEndPort(); ModelObject *pStartComponent = pStartPort->getParentModelObject(); ModelObject *pEndComponent = pEndPort->getParentModelObject(); - size_t fromSlave = size_t(mpSystem->getModelObjects().indexOf(pStartComponent))+1; //DCPLib uses one-based indexing - size_t toSlave = size_t(mpSystem->getModelObjects().indexOf(pEndComponent))+1; //DCPLib uses one-based indexing + size_t fromServer = size_t(mpSystem->getModelObjects().indexOf(pStartComponent))+1; //DCPLib uses one-based indexing + size_t toServer = size_t(mpSystem->getModelObjects().indexOf(pEndComponent))+1; //DCPLib uses one-based indexing QVector variameters; size_t fromVr, toVr; pStartComponent->getVariameterDescriptions(variameters); @@ -655,11 +655,11 @@ void DCPManagerSimulationWorkerObject::initSimulateFinalize() } } - if(connections.count(std::make_pair(fromSlave,fromVr)) == 0) { - connections[std::make_pair(fromSlave,fromVr)] = std::make_pair(std::vector(),std::vector()); + if(connections.count(std::make_pair(fromServer,fromVr)) == 0) { + connections[std::make_pair(fromServer,fromVr)] = std::make_pair(std::vector(),std::vector()); } - connections[std::make_pair(fromSlave,fromVr)].first.push_back(toSlave); - connections[std::make_pair(fromSlave,fromVr)].second.push_back(toVr); + connections[std::make_pair(fromServer,fromVr)].first.push_back(toServer); + connections[std::make_pair(fromServer,fromVr)].second.push_back(toVr); } for(const auto &con : connections) { diff --git a/HopsanGUI/SimulationThreadHandler.h b/HopsanGUI/SimulationThreadHandler.h index 30c9a52b62..d96a3609db 100644 --- a/HopsanGUI/SimulationThreadHandler.h +++ b/HopsanGUI/SimulationThreadHandler.h @@ -47,8 +47,8 @@ class GUIMessageHandler; #include "RemoteCoreAccess.h" #endif -enum SimulationWorkeObjectEnumT {LocalSWO, RemoteSWO, DCPManagerSWO, DCPSlaveSWO}; -enum class SimulationState {Initialize, Simulate, RemoteSimulate, DcpMasterSimulate, DcpSlaveSimulate, Finalize, Done}; +enum SimulationWorkeObjectEnumT {LocalSWO, RemoteSWO, DCPManagerSWO, DcpServerSWO}; +enum class SimulationState {Initialize, Simulate, RemoteSimulate, DcpMasterSimulate, DcpServerSimulate, Finalize, Done}; Q_DECLARE_METATYPE(SimulationState); @@ -126,7 +126,7 @@ public slots: void initSimulateFinalize(); }; -class DCPSlaveSimulationWorkerObject : public SimulationWorkerObjectBase +class DcpServerSimulationWorkerObject : public SimulationWorkerObjectBase { Q_OBJECT private: @@ -135,8 +135,8 @@ class DCPSlaveSimulationWorkerObject : public SimulationWorkerObjectBase int mPort; QString mTargetFile; public: - DCPSlaveSimulationWorkerObject(SystemObject *pSystem, const QString &host, int port, const QString &targetFile); - int swoType() const {return DCPSlaveSWO;} + DcpServerSimulationWorkerObject(SystemObject *pSystem, const QString &host, int port, const QString &targetFile); + int swoType() const {return DcpServerSWO;} public slots: void initSimulateFinalize(); @@ -230,7 +230,7 @@ protected slots: void initSimulateFinalizeRemote(SharedRemoteCoreSimulationHandlerT pRCSH, QVector *pRemoteResultVariables, double *pProgress); #endif void initSimulateFinalizeDcpManager(SystemObject *pSystem, const QString &host, int port); - void initSimulateFinalizeDcpSlave(SystemObject *pSystem, const QString &host, int port, const QString &targetFile); + void initSimulateFinalizeDcpServer(SystemObject *pSystem, const QString &host, int port, const QString &targetFile); void initSimulateFinalize(QVector vpSystems, const bool noChanges=false); void initSimulateFinalize_blocking(QVector vpSystems, const bool noChanges=false); bool wasSuccessful(); diff --git a/HopsanGUI/Widgets/ModelWidget.cpp b/HopsanGUI/Widgets/ModelWidget.cpp index eb3ca8cd82..b156d3d4d4 100644 --- a/HopsanGUI/Widgets/ModelWidget.cpp +++ b/HopsanGUI/Widgets/ModelWidget.cpp @@ -727,8 +727,9 @@ void ModelWidget::stopRealtimeSimulation() mCoreSimulationHandler.stopRealtimeSimulation(mpToplevelSystem->getCoreSystemAccessPtr()); mCoreSimulationHandler.finalize(mpToplevelSystem->getCoreSystemAccessPtr()); mSimulateMutex.unlock(); +} -bool ModelWidget::simulateDcpSlave() +bool ModelWidget::simulateDcpServer() { // Save backup copy if (!isSaved() && gpConfig->getBoolSetting(CFG_AUTOBACKUP)) @@ -739,8 +740,8 @@ bool ModelWidget::simulateDcpSlave() saveTo(gpDesktopHandler->getBackupPath() + fileNameWithoutHmf + "_sim_backup.hmf"); } - QDialog */*pDcpSlaveDialog*/pDialog = new QDialog(gpMainWindowWidget); - QGridLayout */*pDcpSlaveDialogLayout*/pLayout = new QGridLayout(pDialog); + QDialog */*pDcpServerDialog*/pDialog = new QDialog(gpMainWindowWidget); + QGridLayout */*pDcpServerDialogLayout*/pLayout = new QGridLayout(pDialog); QLineEdit *pHostLineEdit = new QLineEdit("127.0.0.1",pDialog); QSpinBox *pPortSpinBox = new QSpinBox(pDialog); pPortSpinBox->setMaximum(1000000); @@ -773,7 +774,7 @@ bool ModelWidget::simulateDcpSlave() mpSimulationThreadHandler->setSimulationTimeVariables(mStartTime.toDouble(), mStopTime.toDouble(), mpToplevelSystem->getLogStartTime(), mpToplevelSystem->getNumberOfLogSamples()); mpSimulationThreadHandler->setProgressDilaogBehaviour(true, false); mSimulationProgress=0; - mpSimulationThreadHandler->initSimulateFinalizeDcpSlave(mpToplevelSystem, pHostLineEdit->text(), pPortSpinBox->value(), pTargetFileLineEdit->text()); + mpSimulationThreadHandler->initSimulateFinalizeDcpServer(mpToplevelSystem, pHostLineEdit->text(), pPortSpinBox->value(), pTargetFileLineEdit->text()); unlockSimulateMutex(); diff --git a/HopsanGUI/Widgets/ModelWidget.h b/HopsanGUI/Widgets/ModelWidget.h index 72f8b23917..6d4c54fe77 100644 --- a/HopsanGUI/Widgets/ModelWidget.h +++ b/HopsanGUI/Widgets/ModelWidget.h @@ -129,7 +129,7 @@ public slots: bool simulate_blocking(); bool startRealtimeSimulation(const double realtimeFactor); void stopRealtimeSimulation(); - bool simulateDcpSlave(); + bool simulateDcpServer(); bool simulateDcpManager(); void save(); void saveAs(); diff --git a/hopsandcp/hopsandcp.pro b/hopsandcp/hopsandcp.pro index 31c682c164..ed2c077275 100644 --- a/hopsandcp/hopsandcp.pro +++ b/hopsandcp/hopsandcp.pro @@ -86,12 +86,12 @@ unix { # ------------------------------------------------- SOURCES = \ src/dcpmaster.cpp \ - src/dcpslave.cpp \ + src/dcpserver.cpp \ src/utilities.cpp HEADERS += \ include/dcpmaster.h \ - include/dcpslave.h \ + include/dcpserver.h \ include/hopsandcp_win32dll.h \ include/utilities.h diff --git a/hopsandcp/include/dcpmaster.h b/hopsandcp/include/dcpmaster.h index 5e1d34425e..facf86b755 100644 --- a/hopsandcp/include/dcpmaster.h +++ b/hopsandcp/include/dcpmaster.h @@ -20,8 +20,8 @@ enum class DcpError : uint16_t; struct DcpConnection { - size_t fromSlave, fromVr; - std::vector toSlaves, toVrs; + size_t fromServer, fromVr; + std::vector toServers, toVrs; }; HOPSANDCP_DLLAPI class DcpMaster @@ -30,7 +30,7 @@ HOPSANDCP_DLLAPI class DcpMaster DcpMaster(const string host, int port, double comStep); ~DcpMaster(); - void addSlave(string filepath); + void addServer(string filepath); void addConnection(size_t fromId, size_t fromVr, std::vector toIds, std::vector toVrs); void start(); @@ -68,18 +68,18 @@ HOPSANDCP_DLLAPI class DcpMaster std::map receivedAcks; - std::vector slaveDescriptions; + std::vector serverDescriptions; - uint8_t slavesWaitingForConfigure = 0; - uint8_t slavesWaitingForStep = 0; - uint8_t slavesWaitingForConfiguration = 0; - uint8_t slavesWaitingAtExit = 0; - uint8_t slavesWaitingToStop = 0; - uint8_t slavesWaitingForInitialize = 0; - uint8_t slavesWaitingToRun = 0; + uint8_t serversWaitingForConfigure = 0; + uint8_t serversWaitingForStep = 0; + uint8_t serversWaitingForConfiguration = 0; + uint8_t serversWaitingAtExit = 0; + uint8_t serversWaitingToStop = 0; + uint8_t serversWaitingForInitialize = 0; + uint8_t serversWaitingToRun = 0; }; -void getDataFromSlaveDescription(const hopsan::HString &rFilePath, hopsan::HString &rName, hopsan::HString &rVariables, hopsan::HString &rValueReferences); +void getDataFromProtocolFile(const hopsan::HString &rFilePath, hopsan::HString &rName, hopsan::HString &rVariables, hopsan::HString &rValueReferences); #endif // DCPMASTER_H diff --git a/hopsandcp/include/dcpslave.h b/hopsandcp/include/dcpserver.h similarity index 77% rename from hopsandcp/include/dcpslave.h rename to hopsandcp/include/dcpserver.h index 6479117e2f..0c1306f4a2 100644 --- a/hopsandcp/include/dcpslave.h +++ b/hopsandcp/include/dcpserver.h @@ -1,5 +1,5 @@ -#ifndef DCPSLAVE_H -#define DCPSLAVE_H +#ifndef DcpServer_H +#define DcpServer_H #include "hopsandcp_win32dll.h" @@ -16,17 +16,17 @@ class DcpManagerSlave; class UdpDriver; class OstreamLog; -HOPSANDCP_DLLAPI class DcpSlave +HOPSANDCP_DLLAPI class DcpServer { public: - DcpSlave(hopsan::ComponentSystem *pSystem, const std::string host, int port, size_t numLogSamples); - ~DcpSlave(); + DcpServer(hopsan::ComponentSystem *pSystem, const std::string host, int port, size_t numLogSamples); + ~DcpServer(); void generateDcpFile(std::string targetFile); bool start(); private: - SlaveDescription_t *getSlaveDescription(); + SlaveDescription_t *getServerDescription(); hopsan::ComponentSystem *mpRootSystem; std::vector mInputs, mOutputs; @@ -47,4 +47,4 @@ HOPSANDCP_DLLAPI class DcpSlave void stop(); }; -#endif // DCPSLAVE_H +#endif // DcpServer_H diff --git a/hopsandcp/src/dcpmaster.cpp b/hopsandcp/src/dcpmaster.cpp index aeb9f3aa03..6f1d581b94 100644 --- a/hopsandcp/src/dcpmaster.cpp +++ b/hopsandcp/src/dcpmaster.cpp @@ -41,27 +41,24 @@ DcpMaster::~DcpMaster() { delete manager; } -void DcpMaster::addSlave(string filepath) +void DcpMaster::addServer(string filepath) { - slaveDescriptions.push_back(new SlaveDescription_t(*getSlaveDescriptionFromDcpFile(1,0,filepath.c_str()))); - u_char id = u_char(slaveDescriptions.size()); + serverDescriptions.push_back(new SlaveDescription_t(*getSlaveDescriptionFromDcpFile(1,0,filepath.c_str()))); + u_char id = u_char(serverDescriptions.size()); uint8_t *netInfo = new uint8_t[6]; - //*((uint8_t *) netInfo) = *slaveDescriptions.back()->TransportProtocols.UDP_IPv4->Control->port; - *((uint16_t *) netInfo) = *slaveDescriptions.back()->TransportProtocols.UDP_IPv4->Control->port; - //*((uint8_t *) (netInfo + 2)) = asio::ip::address_v4::from_string(*slaveDescriptions.back()->TransportProtocols.UDP_IPv4->Control->host).to_uint(); - *((uint32_t *) (netInfo + 2)) = asio::ip::address_v4::from_string(*slaveDescriptions.back()->TransportProtocols.UDP_IPv4->Control->host).to_ulong(); + *((uint16_t *) netInfo) = *serverDescriptions.back()->TransportProtocols.UDP_IPv4->Control->port; + *((uint32_t *) (netInfo + 2)) = asio::ip::address_v4::from_string(*serverDescriptions.back()->TransportProtocols.UDP_IPv4->Control->host).to_ulong(); driver->getDcpDriver().setSlaveNetworkInformation(id, netInfo); delete[] netInfo; } -void DcpMaster::addConnection(size_t fromSlave, size_t fromVr, std::vector toSlaves, std::vector toVrs) +void DcpMaster::addConnection(size_t fromServer, size_t fromVr, std::vector toServers, std::vector toVrs) { - std::cout << "addConnection: " << fromSlave << "," << fromVr << "," << toSlaves[0] << "," << toVrs[0] << "\n"; DcpConnection connection; - connection.fromSlave = fromSlave; + connection.fromServer = fromServer; connection.fromVr = fromVr; connection.toVrs = toVrs; - connection.toSlaves = toSlaves; + connection.toServers = toServers; connections.push_back(connection); } @@ -70,34 +67,31 @@ void DcpMaster::start() { std::chrono::seconds dura(1); std::this_thread::sleep_for(dura); - for(size_t i=0; iSTC_register(u_char(i+1), DcpState::ALIVE, convertToUUID(slaveDescriptions[i]->uuid), DcpOpMode::NRT, 1, 0); + for(size_t i=0; iSTC_register(u_char(i+1), DcpState::ALIVE, convertToUUID(serverDescriptions[i]->uuid), DcpOpMode::NRT, 1, 0); } b.join(); } void DcpMaster::initialize() { - slavesWaitingForInitialize++; - if(slavesWaitingForInitialize < slaveDescriptions.size()) { + serversWaitingForInitialize++; + if(serversWaitingForInitialize < serverDescriptions.size()) { return; } - std::cout << "Initialize Slaves" << std::endl; - for(size_t i=0; iSTC_initialize(u_char(i), DcpState::CONFIGURED); } intializationRuns++; } void DcpMaster::configuration() { - slavesWaitingForConfiguration++; - if(slavesWaitingForConfiguration < slaveDescriptions.size()) { + serversWaitingForConfiguration++; + if(serversWaitingForConfiguration < serverDescriptions.size()) { return; } - std::cout << "Configure Slaves" << std::endl; - //Count received acks so that we know when all configuration messages are acknowledged - for(size_t i=1; i<=slaveDescriptions.size(); ++i) { + for(size_t i=1; i<=serverDescriptions.size(); ++i) { receivedAcks[dcpId_t(i)] = 0; numOfCmd[dcpId_t(i)] = 0; @@ -106,49 +100,47 @@ void DcpMaster::configuration() { } for(size_t i=0; iCFG_scope(fromSlaveId, dataId, DcpScope::Initialization_Run_NonRealTime); - manager->CFG_output(fromSlaveId, dataId, 0, connections[i].fromVr); - manager->CFG_steps(fromSlaveId, dataId, 1); - numOfCmd[fromSlaveId] += 4; - - for(size_t j=0; jCFG_scope(toSlaveId, dataId, DcpScope::Initialization_Run_NonRealTime); - manager->CFG_input(toSlaveId, dataId, 0, connections[i].toVrs[j], DcpDataType::float64); - manager->CFG_steps(toSlaveId, dataId, 1); - manager->CFG_source_network_information_UDP(toSlaveId, dataId, asio::ip::address_v4::from_string(*slaveDescriptions[toSlaveId-1]->TransportProtocols.UDP_IPv4->Control->host).to_uint(), *slaveDescriptions[toSlaveId-1]->TransportProtocols.UDP_IPv4->Control->port+1); - manager->CFG_target_network_information_UDP(fromSlaveId, dataId, asio::ip::address_v4::from_string(*slaveDescriptions[toSlaveId-1]->TransportProtocols.UDP_IPv4->Control->host).to_uint(), *slaveDescriptions[toSlaveId-1]->TransportProtocols.UDP_IPv4->Control->port); - numOfCmd[toSlaveId] += 4; + uint8_t fromServerId = uint8_t(connections[i].fromServer); + manager->CFG_scope(fromServerId, dataId, DcpScope::Initialization_Run_NonRealTime); + manager->CFG_output(fromServerId, dataId, 0, connections[i].fromVr); + manager->CFG_steps(fromServerId, dataId, 1); + numOfCmd[fromServerId] += 4; + + for(size_t j=0; jCFG_scope(toServerId, dataId, DcpScope::Initialization_Run_NonRealTime); + manager->CFG_input(toServerId, dataId, 0, connections[i].toVrs[j], DcpDataType::float64); + manager->CFG_steps(toServerId, dataId, 1); + manager->CFG_source_network_information_UDP(toServerId, dataId, asio::ip::address_v4::from_string(*serverDescriptions[toServerId-1]->TransportProtocols.UDP_IPv4->Control->host).to_uint(), *serverDescriptions[toServerId-1]->TransportProtocols.UDP_IPv4->Control->port+1); + manager->CFG_target_network_information_UDP(fromServerId, dataId, asio::ip::address_v4::from_string(*serverDescriptions[toServerId-1]->TransportProtocols.UDP_IPv4->Control->host).to_uint(), *serverDescriptions[toServerId-1]->TransportProtocols.UDP_IPv4->Control->port); + numOfCmd[toServerId] += 4; } } } void DcpMaster::configure() { - slavesWaitingForConfigure++; - if(slavesWaitingForConfigure < slaveDescriptions.size()) { + serversWaitingForConfigure++; + if(serversWaitingForConfigure < serverDescriptions.size()) { return; } - for(size_t i=0; iSTC_configure(u_char(i+1), DcpState::PREPARED); } } void DcpMaster::run(DcpState currentState, uint8_t sender) { - std::cout << "Run Simulation" << std::endl; std::time_t now = std::time(nullptr); manager->STC_run(sender, currentState, now + 2); } void DcpMaster::doStep() { - slavesWaitingForStep++; - if(slavesWaitingForStep < slaveDescriptions.size()) { + serversWaitingForStep++; + if(serversWaitingForStep < serverDescriptions.size()) { return; } - slavesWaitingForStep = 0; - for(size_t i=0; iSTC_do_step(u_char(i+1),DcpState::RUNNING,1); } } @@ -156,31 +148,27 @@ void DcpMaster::doStep() { void DcpMaster::stop() { std::chrono::seconds dura(1); std::this_thread::sleep_for(dura); - std::cout << "Stop Simulation" << std::endl; - for(size_t i=0; iSTC_stop(u_char(i+1), DcpState::RUNNING); } } void DcpMaster::deregister() { - slavesWaitingToStop++; - if(slavesWaitingToStop < slaveDescriptions.size()) { + serversWaitingToStop++; + if(serversWaitingToStop < serverDescriptions.size()) { return; } - std::cout << "Deregister Slave" << std::endl; - for(size_t i=0; iSTC_deregister(u_char(i+1), DcpState::STOPPED); } } void DcpMaster::sendOutputs(DcpState currentState, uint8_t sender) { - std::cout << "Send Outputs" << std::endl; manager->STC_send_outputs(sender, currentState); } void DcpMaster::receiveAck(uint8_t sender, uint16_t pduSeqId) { (void)pduSeqId; - std::cout << "receiveAck()\n"; receivedAcks[sender]++; if (receivedAcks[sender] == numOfCmd[sender]) { manager->STC_prepare(sender, DcpState::CONFIGURATION); @@ -191,7 +179,6 @@ void DcpMaster::receiveNAck(uint8_t sender, uint16_t pduSeqId, DcpError errorCod (void)sender; (void)pduSeqId; (void)errorCode; - std::cerr << "Error in slave configuration." << std::endl; std::exit(1); } @@ -245,8 +232,8 @@ void DcpMaster::receiveStateChangedNotification(uint8_t sender, break; case DcpState::STOPPED: - slavesWaitingToStop++; - if(slavesWaitingToStop < slaveDescriptions.size()) { + serversWaitingToStop++; + if(serversWaitingToStop < serverDescriptions.size()) { return; } std::cout << "Stopping master manager\n"; @@ -255,8 +242,8 @@ void DcpMaster::receiveStateChangedNotification(uint8_t sender, case DcpState::ALIVE: //simulation finished - slavesWaitingAtExit++; - if(slavesWaitingAtExit < slaveDescriptions.size()) { + serversWaitingAtExit++; + if(serversWaitingAtExit < serverDescriptions.size()) { return; } break; @@ -269,12 +256,12 @@ void DcpMaster::receiveStateChangedNotification(uint8_t sender, -void getDataFromSlaveDescription(const hopsan::HString &rFilePath, hopsan::HString &rName, hopsan::HString &rVariables, hopsan::HString &rValueReferences) +void getDataFromProtocolFile(const hopsan::HString &rFilePath, hopsan::HString &rName, hopsan::HString &rVariables, hopsan::HString &rValueReferences) { - shared_ptr slaveDesc = getSlaveDescriptionFromDcpFile(1,0,rFilePath.c_str()); + shared_ptr desc = getSlaveDescriptionFromDcpFile(1,0,rFilePath.c_str()); hopsan::HString inputs,outputs,pars; hopsan::HString inputVrs, outputVrs, parVrs; - for(const auto &var : slaveDesc->Variables) { + for(const auto &var : desc->Variables) { if(var.Input.get() != nullptr) { inputs.append(hopsan::HString(var.name.c_str())+","); inputVrs.append(to_hstring(var.valueReference)+","); @@ -300,7 +287,7 @@ void getDataFromSlaveDescription(const hopsan::HString &rFilePath, hopsan::HStri pars.erase(pars.size()-1); parVrs.erase(parVrs.size()-1); } - rName = slaveDesc->dcpSlaveName.c_str(); + rName = desc->dcpSlaveName.c_str(); //Variables names are stored in a semicolon and comma separated string. //Variable types are separated by semicolons, while variable names within diff --git a/hopsandcp/src/dcpslave.cpp b/hopsandcp/src/dcpserver.cpp similarity index 61% rename from hopsandcp/src/dcpslave.cpp rename to hopsandcp/src/dcpserver.cpp index 75ed3fe979..6ffa077600 100644 --- a/hopsandcp/src/dcpslave.cpp +++ b/hopsandcp/src/dcpserver.cpp @@ -1,4 +1,4 @@ -#include "dcpslave.h" +#include "dcpserver.h" #include "utilities.h" #include @@ -31,7 +31,7 @@ const LogTemplate SIM_LOG = LogTemplate( using namespace hopsan; -DcpSlave::DcpSlave(ComponentSystem *pSystem, const std::string host, int port, size_t numLogSamples) +DcpServer::DcpServer(ComponentSystem *pSystem, const std::string host, int port, size_t numLogSamples) : mpRootSystem(pSystem), mHost(host), mPort(port), mNumLogSamples(numLogSamples) { //Generate list of inputs and outputs based on interface components @@ -56,25 +56,25 @@ DcpSlave::DcpSlave(ComponentSystem *pSystem, const std::string host, int port, s //Create UDP driver udpDriver = new UdpDriver(host, uint16_t(port)); - //Create slave DCP manager - mManager = new DcpManagerSlave(*getSlaveDescription(), udpDriver->getDcpDriver()); + //Create server DCP manager + mManager = new DcpManagerSlave(*getServerDescription(), udpDriver->getDcpDriver()); mManager->setInitializeCallback( - std::bind(&DcpSlave::initialize, this)); + std::bind(&DcpServer::initialize, this)); mManager->setConfigureCallback( - std::bind(&DcpSlave::configure, this)); + std::bind(&DcpServer::configure, this)); mManager->setSynchronizingStepCallback( - std::bind(&DcpSlave::doStep, this, std::placeholders::_1)); + std::bind(&DcpServer::doStep, this, std::placeholders::_1)); mManager->setSynchronizedStepCallback( - std::bind(&DcpSlave::doStep, this, std::placeholders::_1)); + std::bind(&DcpServer::doStep, this, std::placeholders::_1)); mManager->setRunningStepCallback( - std::bind(&DcpSlave::doStep, this, std::placeholders::_1)); + std::bind(&DcpServer::doStep, this, std::placeholders::_1)); mManager->setRunningNRTStepCallback( - std::bind(&DcpSlave::doStep, this, std::placeholders::_1)); - mManager->setTimeResListener(std::bind(&DcpSlave::setTimeRes, this, + std::bind(&DcpServer::doStep, this, std::placeholders::_1)); + mManager->setTimeResListener(std::bind(&DcpServer::setTimeRes, this, std::placeholders::_1, std::placeholders::_2)); mManager->setStopCallback( - std::bind(&DcpSlave::stop, this)); + std::bind(&DcpServer::stop, this)); //Display log messages on console stdLog = new OstreamLog(std::cout); @@ -83,57 +83,57 @@ DcpSlave::DcpSlave(ComponentSystem *pSystem, const std::string host, int port, s mManager->setGenerateLogString(true); } -DcpSlave::~DcpSlave() +DcpServer::~DcpServer() { } -SlaveDescription_t *DcpSlave::getSlaveDescription() { - SlaveDescription_t *slaveDescription = new SlaveDescription_t(make_SlaveDescription(1, 0, mpRootSystem->getName().c_str(), "b5279485-720d-4542-9f29-bee4d9a75ef9")); - slaveDescription->OpMode.HardRealTime = make_HardRealTime_ptr(); - slaveDescription->OpMode.SoftRealTime = make_SoftRealTime_ptr(); - slaveDescription->OpMode.NonRealTime = make_NonRealTime_ptr(); +SlaveDescription_t *DcpServer::getServerDescription() { + SlaveDescription_t *serverDescription = new SlaveDescription_t(make_SlaveDescription(1, 0, mpRootSystem->getName().c_str(), "b5279485-720d-4542-9f29-bee4d9a75ef9")); + serverDescription->OpMode.HardRealTime = make_HardRealTime_ptr(); + serverDescription->OpMode.SoftRealTime = make_SoftRealTime_ptr(); + serverDescription->OpMode.NonRealTime = make_NonRealTime_ptr(); Resolution_t resolution = make_Resolution(); resolution.numerator = 1; resolution.denominator = denominator_t(1.0/mpRootSystem->getTimestep()); - slaveDescription->TimeRes.resolutions.push_back(resolution); - slaveDescription->TransportProtocols.UDP_IPv4 = make_UDP_ptr(); - slaveDescription->TransportProtocols.UDP_IPv4->Control = make_Control_ptr(mHost.c_str(), port_t(mPort)); - slaveDescription->TransportProtocols.UDP_IPv4->DAT_input_output = make_DAT_ptr(); - slaveDescription->TransportProtocols.UDP_IPv4->DAT_input_output->availablePortRanges.push_back(make_AvailablePortRange(2048, 65535)); - slaveDescription->TransportProtocols.UDP_IPv4->DAT_parameter = make_DAT_ptr(); - slaveDescription->TransportProtocols.UDP_IPv4->DAT_parameter->availablePortRanges.push_back(make_AvailablePortRange(2048, 65535)); - slaveDescription->CapabilityFlags.canAcceptConfigPdus = true; - slaveDescription->CapabilityFlags.canHandleReset = false; - slaveDescription->CapabilityFlags.canHandleVariableSteps = false; - slaveDescription->CapabilityFlags.canMonitorHeartbeat = false; - slaveDescription->CapabilityFlags.canProvideLogOnRequest = true; - slaveDescription->CapabilityFlags.canProvideLogOnNotification = true; + serverDescription->TimeRes.resolutions.push_back(resolution); + serverDescription->TransportProtocols.UDP_IPv4 = make_UDP_ptr(); + serverDescription->TransportProtocols.UDP_IPv4->Control = make_Control_ptr(mHost.c_str(), port_t(mPort)); + serverDescription->TransportProtocols.UDP_IPv4->DAT_input_output = make_DAT_ptr(); + serverDescription->TransportProtocols.UDP_IPv4->DAT_input_output->availablePortRanges.push_back(make_AvailablePortRange(2048, 65535)); + serverDescription->TransportProtocols.UDP_IPv4->DAT_parameter = make_DAT_ptr(); + serverDescription->TransportProtocols.UDP_IPv4->DAT_parameter->availablePortRanges.push_back(make_AvailablePortRange(2048, 65535)); + serverDescription->CapabilityFlags.canAcceptConfigPdus = true; + serverDescription->CapabilityFlags.canHandleReset = false; + serverDescription->CapabilityFlags.canHandleVariableSteps = false; + serverDescription->CapabilityFlags.canMonitorHeartbeat = false; + serverDescription->CapabilityFlags.canProvideLogOnRequest = true; + serverDescription->CapabilityFlags.canProvideLogOnNotification = true; for(size_t i=0; i causality = make_Output_ptr(); - slaveDescription->Variables.push_back(make_Variable_output(mOutputs[i], valueReference_t(i), causality)); + serverDescription->Variables.push_back(make_Variable_output(mOutputs[i], valueReference_t(i), causality)); } for(size_t i=0; i causality = make_CommonCausality_ptr(); causality->Float64->start = std::make_shared>(); causality->Float64->start->push_back(0.0); - slaveDescription->Variables.push_back(make_Variable_input(mInputs[i], valueReference_t(mOutputs.size()+i), causality)); + serverDescription->Variables.push_back(make_Variable_input(mInputs[i], valueReference_t(mOutputs.size()+i), causality)); } - slaveDescription->Log = make_Log_ptr(); - slaveDescription->Log->categories.push_back(make_Category(1, "DCP_SLAVE")); - slaveDescription->Log->templates.push_back(make_Template( + serverDescription->Log = make_Log_ptr(); + serverDescription->Log->categories.push_back(make_Category(1, "DCP_SERVER")); + serverDescription->Log->templates.push_back(make_Template( 1, 1, (uint8_t) DcpLogLevel::LVL_INFORMATION, "[Time = %float64]: output = %float64")); - return slaveDescription; + return serverDescription; } -void DcpSlave::generateDcpFile(std::string targetFile) { - writeDcpSlaveFile(std::shared_ptr(getSlaveDescription()), targetFile.c_str()); +void DcpServer::generateDcpFile(std::string targetFile) { + writeDcpSlaveFile(std::shared_ptr(getServerDescription()), targetFile.c_str()); } -bool DcpSlave::start() +bool DcpServer::start() { try { mManager->start(); @@ -145,7 +145,7 @@ bool DcpSlave::start() } -void DcpSlave::configure() { +void DcpServer::configure() { std::cout << "Checking model... "; if (mpRootSystem->checkModelBeforeSimulation()) { std::cout << "Success!\n"; @@ -176,12 +176,12 @@ void DcpSlave::configure() { } } -void DcpSlave::initialize() { +void DcpServer::initialize() { } -void DcpSlave::doStep(uint64_t steps) { +void DcpServer::doStep(uint64_t steps) { // Read inputs for(size_t i=0; isetDesiredTimestep(double(numerator)/double(denominator)); } -void DcpSlave::stop() +void DcpServer::stop() { //dynamic_cast(mManager)->stop(); udpDriver->getDcpDriver().stopReceiving(); From 3de1a7c7db2c488d019fa1751429237207eb4408 Mon Sep 17 00:00:00 2001 From: Robert Braun Date: Fri, 12 Feb 2021 10:33:25 +0100 Subject: [PATCH 15/34] Correct stop time and progress bar for DCP masters --- HopsanGUI/SimulationThreadHandler.cpp | 16 +++++++++++----- HopsanGUI/SimulationThreadHandler.h | 2 +- hopsandcp/include/dcpmaster.h | 7 +++++-- hopsandcp/src/dcpmaster.cpp | 11 +++++++---- 4 files changed, 24 insertions(+), 12 deletions(-) diff --git a/HopsanGUI/SimulationThreadHandler.cpp b/HopsanGUI/SimulationThreadHandler.cpp index eeee167188..2580aea37d 100644 --- a/HopsanGUI/SimulationThreadHandler.cpp +++ b/HopsanGUI/SimulationThreadHandler.cpp @@ -249,8 +249,12 @@ void ProgressBarWorkerObject::setProgressBarState(SimulationState state) emit setProgressBarRange(0, 0); break; case SimulationState::DcpServerSimulate: - emit setProgressBarText(tr("Running DCP simulation...")); + emit setProgressBarText(tr("Running DCP simulation (server)...")); emit setProgressBarRange(0, 0); + break; + case SimulationState::DcpMasterSimulate: + emit setProgressBarText(tr("Running DCP simulation (master)...")); + emit setProgressBarRange(0, 100); startRefreshTimer(gpConfig->getProgressBarStep()); break; case SimulationState::Finalize: @@ -295,6 +299,7 @@ void ProgressBarWorkerObject::refreshProgressBar() mpProgressDialogRefreshTimer->setInterval( currentTimeStep + 10); } } + qApp->processEvents(); } void ProgressBarWorkerObject::abort() @@ -342,7 +347,7 @@ void SimulationThreadHandler::initSimulateFinalizeDcpManager(SystemObject *pSyst { mvpSystems.clear(); mvpSystems.push_back(pSystem); - mpSimulationWorkerObject = new DCPManagerSimulationWorkerObject(pSystem, host, port); + mpSimulationWorkerObject = new DCPManagerSimulationWorkerObject(pSystem, host, port, mStartT, mStopT); mpSimulationWorkerObject->setMessageHandler(mpMessageHandler); initSimulateFinalizePrivate(); } @@ -613,10 +618,11 @@ void DcpServerSimulationWorkerObject::initSimulateFinalize() emit finalizeDone(true, timer.elapsed()); } -DCPManagerSimulationWorkerObject::DCPManagerSimulationWorkerObject(SystemObject *pSystem, const QString &host, int port) +DCPManagerSimulationWorkerObject::DCPManagerSimulationWorkerObject(SystemObject *pSystem, const QString &host, int port, double startTime, double stopTime) : mpSystem(pSystem), mHost(host), mPort(port) { - + mStartTime = startTime; + mStopTime = stopTime; } void DCPManagerSimulationWorkerObject::initSimulateFinalize() @@ -626,7 +632,7 @@ void DCPManagerSimulationWorkerObject::initSimulateFinalize() emit setProgressState(SimulationState::Initialize); timer.start(); - DcpMaster *pDcpMaster = new DcpMaster(mHost.toStdString(), mPort, mpSystem->getTimeStep()); + DcpMaster *pDcpMaster = new DcpMaster(mpSystem->getCoreSystemAccessPtr()->getCoreSystemPtr(), mHost.toStdString(), mPort, mpSystem->getTimeStep(), mStartTime, mStopTime); for(const auto comp : mpSystem->getModelObjects()) { if(comp->getTypeName() == HOPSANGUIDCPCOMPONENT) { //Just in case, model shall only contain DCP components anyway pDcpMaster->addServer(comp->getParameterValue("dcpFile").toStdString()); diff --git a/HopsanGUI/SimulationThreadHandler.h b/HopsanGUI/SimulationThreadHandler.h index d96a3609db..2934ee0711 100644 --- a/HopsanGUI/SimulationThreadHandler.h +++ b/HopsanGUI/SimulationThreadHandler.h @@ -119,7 +119,7 @@ class DCPManagerSimulationWorkerObject : public SimulationWorkerObjectBase QString mHost; int mPort; public: - DCPManagerSimulationWorkerObject(SystemObject *pSystem, const QString &host, int port); + DCPManagerSimulationWorkerObject(SystemObject *pSystem, const QString &host, int port, double startTime, double stopTime); int swoType() const {return DCPManagerSWO;} public slots: diff --git a/hopsandcp/include/dcpmaster.h b/hopsandcp/include/dcpmaster.h index facf86b755..e11a6bf068 100644 --- a/hopsandcp/include/dcpmaster.h +++ b/hopsandcp/include/dcpmaster.h @@ -27,7 +27,7 @@ struct DcpConnection HOPSANDCP_DLLAPI class DcpMaster { public: - DcpMaster(const string host, int port, double comStep); + DcpMaster(hopsan::ComponentSystem *pSystem, const string host, int port, double comStep=0.001, double startTime=0, double stopTime=10); ~DcpMaster(); void addServer(string filepath); @@ -48,6 +48,8 @@ HOPSANDCP_DLLAPI class DcpMaster void dataReceived(uint16_t dataId, size_t length, uint8_t payload[]); void receiveStateChangedNotification(uint8_t sender, DcpState state); + hopsan::ComponentSystem *mpSystem; + std::vector connections; uint8_t maxInitRuns = 0; @@ -56,6 +58,8 @@ HOPSANDCP_DLLAPI class DcpMaster std::map curState; double mComStep; + double mStartTime; + double mStopTime; UdpDriver *driver; @@ -63,7 +67,6 @@ HOPSANDCP_DLLAPI class DcpMaster DcpManagerMaster *manager; - uint64_t nSteps=0; std::map numOfCmd; std::map receivedAcks; diff --git a/hopsandcp/src/dcpmaster.cpp b/hopsandcp/src/dcpmaster.cpp index 6f1d581b94..ba357c5177 100644 --- a/hopsandcp/src/dcpmaster.cpp +++ b/hopsandcp/src/dcpmaster.cpp @@ -13,9 +13,11 @@ #include #include -DcpMaster::DcpMaster(const std::string host, int port, double comStep=0.001) - : mComStep(comStep) +DcpMaster::DcpMaster(hopsan::ComponentSystem *pSystem, const std::string host, int port, double comStep, double startTime, double stopTime) + : mpSystem(pSystem), mComStep(comStep), mStartTime(startTime), mStopTime(stopTime) { + (*mpSystem->getTimePtr()) = mStartTime; + OstreamLog stdLog(std::cout); driver = new UdpDriver(host, port_t(port)); @@ -143,6 +145,8 @@ void DcpMaster::doStep() { for(size_t i=0; iSTC_do_step(u_char(i+1),DcpState::RUNNING,1); } + + (*mpSystem->getTimePtr()) += mComStep; } void DcpMaster::stop() { @@ -218,11 +222,10 @@ void DcpMaster::receiveStateChangedNotification(uint8_t sender, break; case DcpState::RUNNING: - if(nSteps>10000) { + if(mpSystem->getTime() > mStopTime) { stop(); } else { - ++nSteps; doStep(); } break; From e442e6c69ceab4a812d77b20e91def20ff35943d Mon Sep 17 00:00:00 2001 From: Robert Braun Date: Fri, 12 Feb 2021 10:41:00 +0100 Subject: [PATCH 16/34] Consistent naming of DCP master --- HopsanGUI/MainWindow.cpp | 8 ++++---- HopsanGUI/MainWindow.h | 2 +- HopsanGUI/ModelHandler.cpp | 4 ++-- HopsanGUI/SimulationThreadHandler.cpp | 10 +++++----- HopsanGUI/SimulationThreadHandler.h | 10 +++++----- HopsanGUI/Widgets/ModelWidget.cpp | 4 ++-- HopsanGUI/Widgets/ModelWidget.h | 2 +- 7 files changed, 20 insertions(+), 20 deletions(-) diff --git a/HopsanGUI/MainWindow.cpp b/HopsanGUI/MainWindow.cpp index 03f89af18a..26c88a5bad 100644 --- a/HopsanGUI/MainWindow.cpp +++ b/HopsanGUI/MainWindow.cpp @@ -628,8 +628,8 @@ void MainWindow::createActions() mpNewDcpModelAction->setToolTip("Create new DCP model"); connect(mpNewDcpModelAction, SIGNAL(triggered()), mpModelHandler, SLOT(addNewDcpModel())); - mpStartDcpManagerAction = new QAction(QIcon(QString(ICONPATH) + "svg/Hopsan-StartDcpManager.svg"), tr("Simulate model as DCP manager"), this); - mpStartDcpManagerAction->setToolTip("Simulate model as DCP manager"); + mpStartDcpMasterAction = new QAction(QIcon(QString(ICONPATH) + "svg/Hopsan-StartDcpManager.svg"), tr("Simulate model as DCP master"), this); + mpStartDcpMasterAction->setToolTip("Simulate model as DCP master"); mpStartDcpServerAction = new QAction(QIcon(QString(ICONPATH) + "svg/Hopsan-StartDcpServer.svg"), tr("Simulate model as DCP server"), this); mpStartDcpServerAction->setToolTip("Simulate model as DCP server"); @@ -1234,7 +1234,7 @@ void MainWindow::createToolbars() mpDcpToolBar->setAllowedAreas(Qt::TopToolBarArea | Qt::LeftToolBarArea | Qt::RightToolBarArea); mpDcpToolBar->setAttribute(Qt::WA_MouseTracking); mpDcpToolBar->addAction(mpNewDcpModelAction); - mpDcpToolBar->addAction(mpStartDcpManagerAction); + mpDcpToolBar->addAction(mpStartDcpMasterAction); mpDcpToolBar->addAction(mpStartDcpServerAction); //Tools toolbar, contains all tools used to modify the model @@ -1523,7 +1523,7 @@ void MainWindow::updateToolBarsToNewTab() mpLoadModelParametersFromSsvAction->setEnabled(modelTab && !dcpTab); mpStartDcpServerAction->setEnabled(modelTab && !dcpTab); - mpStartDcpManagerAction->setEnabled(dcpTab); + mpStartDcpMasterAction->setEnabled(dcpTab); if(gpFindWidget) { gpFindWidget->setEnabled(modelTab || editorTab); diff --git a/HopsanGUI/MainWindow.h b/HopsanGUI/MainWindow.h index bedf9ab8b1..b89941de88 100644 --- a/HopsanGUI/MainWindow.h +++ b/HopsanGUI/MainWindow.h @@ -221,7 +221,7 @@ class MainWindow : public QMainWindow QAction *mpMeasureSimulationTimeAction; QAction *mpToggleHideAllDockAreasAction; QAction *mpNewDcpModelAction; - QAction *mpStartDcpManagerAction; + QAction *mpStartDcpMasterAction; QAction *mpStartDcpServerAction; QAction *mpDebug1Action; diff --git a/HopsanGUI/ModelHandler.cpp b/HopsanGUI/ModelHandler.cpp index de895f3d95..f8919b34ed 100644 --- a/HopsanGUI/ModelHandler.cpp +++ b/HopsanGUI/ModelHandler.cpp @@ -726,7 +726,7 @@ void ModelHandler::disconnectMainWindowConnections(ModelWidget *pModel) disconnect(gpMainWindow, SIGNAL(simulateKeyPressed()), pModel, SLOT(simulate_nonblocking())); disconnect(gpMainWindow->mpToggleRemoteCoreSimAction, SIGNAL(triggered(bool)), pModel, SLOT(setUseRemoteSimulation(bool))); disconnect(gpMainWindow->mpStartDcpServerAction, SIGNAL(triggered()), pModel, SLOT(simulateDcpServer())); - disconnect(gpMainWindow->mpStartDcpManagerAction, SIGNAL(triggered()), pModel, SLOT(simulateDcpManager())); + disconnect(gpMainWindow->mpStartDcpMasterAction, SIGNAL(triggered()), pModel, SLOT(simulateDcpMaster())); disconnect(gpMainWindow->mpSaveAction, SIGNAL(triggered()), pModel, SLOT(save())); disconnect(gpMainWindow->mpSaveAsAction, SIGNAL(triggered()), pModel, SLOT(saveAs())); disconnect(gpMainWindow->mpExportModelParametersActionToHpf, SIGNAL(triggered()), pModel, SLOT(exportModelParametersToHpf())); @@ -768,7 +768,7 @@ void ModelHandler::connectMainWindowConnections(ModelWidget *pModel) connect(gpMainWindow, SIGNAL(simulateKeyPressed()), pModel, SLOT(simulate_nonblocking()), Qt::UniqueConnection); connect(gpMainWindow->mpToggleRemoteCoreSimAction, SIGNAL(triggered(bool)), pModel, SLOT(setUseRemoteSimulation(bool)), Qt::UniqueConnection); connect(gpMainWindow->mpStartDcpServerAction, SIGNAL(triggered()), pModel, SLOT(simulateDcpServer()), Qt::UniqueConnection); - connect(gpMainWindow->mpStartDcpManagerAction, SIGNAL(triggered()), pModel, SLOT(simulateDcpManager()), Qt::UniqueConnection); + connect(gpMainWindow->mpStartDcpMasterAction, SIGNAL(triggered()), pModel, SLOT(simulateDcpMaster()), Qt::UniqueConnection); connect(gpMainWindow->mpSaveAction, SIGNAL(triggered()), pModel, SLOT(save()), Qt::UniqueConnection); connect(gpMainWindow->mpSaveAsAction, SIGNAL(triggered()), pModel, SLOT(saveAs()), Qt::UniqueConnection); connect(gpMainWindow->mpExportModelParametersActionToHpf, SIGNAL(triggered()), pModel, SLOT(exportModelParametersToHpf()), Qt::UniqueConnection); diff --git a/HopsanGUI/SimulationThreadHandler.cpp b/HopsanGUI/SimulationThreadHandler.cpp index 2580aea37d..31361d2d77 100644 --- a/HopsanGUI/SimulationThreadHandler.cpp +++ b/HopsanGUI/SimulationThreadHandler.cpp @@ -343,11 +343,11 @@ void SimulationThreadHandler::initSimulateFinalizeRemote(SharedRemoteCoreSimulat } #endif -void SimulationThreadHandler::initSimulateFinalizeDcpManager(SystemObject *pSystem, const QString &host, int port) +void SimulationThreadHandler::initSimulateFinalizeDcpMaster(SystemObject *pSystem, const QString &host, int port) { mvpSystems.clear(); mvpSystems.push_back(pSystem); - mpSimulationWorkerObject = new DCPManagerSimulationWorkerObject(pSystem, host, port, mStartT, mStopT); + mpSimulationWorkerObject = new DcpMasterSimulationWorkerObject(pSystem, host, port, mStartT, mStopT); mpSimulationWorkerObject->setMessageHandler(mpMessageHandler); initSimulateFinalizePrivate(); } @@ -618,14 +618,14 @@ void DcpServerSimulationWorkerObject::initSimulateFinalize() emit finalizeDone(true, timer.elapsed()); } -DCPManagerSimulationWorkerObject::DCPManagerSimulationWorkerObject(SystemObject *pSystem, const QString &host, int port, double startTime, double stopTime) +DcpMasterSimulationWorkerObject::DcpMasterSimulationWorkerObject(SystemObject *pSystem, const QString &host, int port, double startTime, double stopTime) : mpSystem(pSystem), mHost(host), mPort(port) { mStartTime = startTime; mStopTime = stopTime; } -void DCPManagerSimulationWorkerObject::initSimulateFinalize() +void DcpMasterSimulationWorkerObject::initSimulateFinalize() { // Initializing QTime timer; @@ -676,7 +676,7 @@ void DCPManagerSimulationWorkerObject::initSimulateFinalize() // Simulating emit setProgressState(SimulationState::DcpMasterSimulate); - gpMessageHandler->addInfoMessage("Starting a DCP simulation as manager..."); + gpMessageHandler->addInfoMessage("Starting a DCP simulation as master..."); pDcpMaster->start(); gpMessageHandler->addInfoMessage("DCP simulation finished!"); emit simulateDone(true, timer.elapsed()); diff --git a/HopsanGUI/SimulationThreadHandler.h b/HopsanGUI/SimulationThreadHandler.h index 2934ee0711..7ed1310d68 100644 --- a/HopsanGUI/SimulationThreadHandler.h +++ b/HopsanGUI/SimulationThreadHandler.h @@ -47,7 +47,7 @@ class GUIMessageHandler; #include "RemoteCoreAccess.h" #endif -enum SimulationWorkeObjectEnumT {LocalSWO, RemoteSWO, DCPManagerSWO, DcpServerSWO}; +enum SimulationWorkeObjectEnumT {LocalSWO, RemoteSWO, DCPMasterSWO, DcpServerSWO}; enum class SimulationState {Initialize, Simulate, RemoteSimulate, DcpMasterSimulate, DcpServerSimulate, Finalize, Done}; Q_DECLARE_METATYPE(SimulationState); @@ -111,7 +111,7 @@ public slots: }; #endif -class DCPManagerSimulationWorkerObject : public SimulationWorkerObjectBase +class DcpMasterSimulationWorkerObject : public SimulationWorkerObjectBase { Q_OBJECT private: @@ -119,8 +119,8 @@ class DCPManagerSimulationWorkerObject : public SimulationWorkerObjectBase QString mHost; int mPort; public: - DCPManagerSimulationWorkerObject(SystemObject *pSystem, const QString &host, int port, double startTime, double stopTime); - int swoType() const {return DCPManagerSWO;} + DcpMasterSimulationWorkerObject(SystemObject *pSystem, const QString &host, int port, double startTime, double stopTime); + int swoType() const {return DCPMasterSWO;} public slots: void initSimulateFinalize(); @@ -229,7 +229,7 @@ protected slots: #ifdef USEZMQ void initSimulateFinalizeRemote(SharedRemoteCoreSimulationHandlerT pRCSH, QVector *pRemoteResultVariables, double *pProgress); #endif - void initSimulateFinalizeDcpManager(SystemObject *pSystem, const QString &host, int port); + void initSimulateFinalizeDcpMaster(SystemObject *pSystem, const QString &host, int port); void initSimulateFinalizeDcpServer(SystemObject *pSystem, const QString &host, int port, const QString &targetFile); void initSimulateFinalize(QVector vpSystems, const bool noChanges=false); void initSimulateFinalize_blocking(QVector vpSystems, const bool noChanges=false); diff --git a/HopsanGUI/Widgets/ModelWidget.cpp b/HopsanGUI/Widgets/ModelWidget.cpp index b156d3d4d4..0b48cfb775 100644 --- a/HopsanGUI/Widgets/ModelWidget.cpp +++ b/HopsanGUI/Widgets/ModelWidget.cpp @@ -782,7 +782,7 @@ bool ModelWidget::simulateDcpServer() //! @todo fix return code } -bool ModelWidget::simulateDcpManager() +bool ModelWidget::simulateDcpMaster() { // Save backup copy if (!isSaved() && gpConfig->getBoolSetting(CFG_AUTOBACKUP)) @@ -824,7 +824,7 @@ bool ModelWidget::simulateDcpManager() mpSimulationThreadHandler->setSimulationTimeVariables(mStartTime.toDouble(), mStopTime.toDouble(), mpToplevelSystem->getLogStartTime(), mpToplevelSystem->getNumberOfLogSamples()); mpSimulationThreadHandler->setProgressDilaogBehaviour(true, false); mSimulationProgress=0; - mpSimulationThreadHandler->initSimulateFinalizeDcpManager(mpToplevelSystem, pHostLineEdit->text(), pPortSpinBox->value()); + mpSimulationThreadHandler->initSimulateFinalizeDcpMaster(mpToplevelSystem, pHostLineEdit->text(), pPortSpinBox->value()); unlockSimulateMutex(); diff --git a/HopsanGUI/Widgets/ModelWidget.h b/HopsanGUI/Widgets/ModelWidget.h index 6d4c54fe77..f75b0e1b5d 100644 --- a/HopsanGUI/Widgets/ModelWidget.h +++ b/HopsanGUI/Widgets/ModelWidget.h @@ -130,7 +130,7 @@ public slots: bool startRealtimeSimulation(const double realtimeFactor); void stopRealtimeSimulation(); bool simulateDcpServer(); - bool simulateDcpManager(); + bool simulateDcpMaster(); void save(); void saveAs(); void exportModelParametersToHpf(); From 7e466150c0d1a280a62020f786a98940dc8afdd7 Mon Sep 17 00:00:00 2001 From: Robert Braun Date: Tue, 16 Feb 2021 13:30:08 +0100 Subject: [PATCH 17/34] Removed unused utilities from hopsandcp --- hopsandcp/include/utilities.h | 82 ----------------------------- hopsandcp/src/utilities.cpp | 99 ----------------------------------- 2 files changed, 181 deletions(-) diff --git a/hopsandcp/include/utilities.h b/hopsandcp/include/utilities.h index 46ae8fdf0b..f592e4abc1 100644 --- a/hopsandcp/include/utilities.h +++ b/hopsandcp/include/utilities.h @@ -31,86 +31,4 @@ #ifndef UTILITIES_H #define UTILITIES_H -#include -#include "HopsanEssentials.h" - - - -enum SaveResults {Final, Full}; -void generateFullSubSystemHierarchyName(const hopsan::ComponentSystem *pSys, hopsan::HString &rFullSysName, const hopsan::HString &separator); -hopsan::HString generateFullSubSystemHierarchyName(const hopsan::Component *pComponent, const hopsan::HString &separator, bool includeLastSeparator=true); -void saveResultsToCSV(hopsan::ComponentSystem *pRootSystem, const std::string &rFileName, const SaveResults howMany, const std::vector& includeFilter); - -template -bool contains(const ContainerT& container, const ValueT& value) { - auto it = std::find(container.begin(), container.end(), value); - return (it != container.end()); -} - -template -void saveResultsTo(hopsan::ComponentSystem *pCurrentSystem, const std::vector& includeFilter, SaveTimeFunc writeTime, - SaveVariableFunc writeVariable ) -{ - hopsan::HString prefix = generateFullSubSystemHierarchyName(pCurrentSystem, "$"); //!< @todo not necessary every time if we use recursion instead - - // Use names to get components in alphabeteical order - const std::vector componentNames = pCurrentSystem->getSubComponentNames(); - size_t numberOfLoggedComponentsInThisSystem = 0; - for (const auto& name : componentNames) { - hopsan::Component *pComponent = pCurrentSystem->getSubComponent(name); - - size_t numberOfLoggedVariablesInThisComponent = 0; - const std::vector ports = pComponent->getPortPtrVector(); - for (const hopsan::Port* pPort : ports) { - // Ignore ports that have logging disabled - if (!pPort->isLoggingEnabled()) { - continue; - } - - hopsan::HString fullPortName = prefix + pComponent->getName() + "#" + pPort->getName(); - const bool includeAllVariablesInThisPort = (includeFilter.empty() || contains(includeFilter, fullPortName.c_str())) && - pPort->isLoggingEnabled(); - - const std::vector *pVariables = pPort->getNodeDataDescriptions(); // TODO do not return pointer - if (pVariables) - { - for (size_t v=0; vsize(); ++v) - { - const hopsan::NodeDataDescription* pVariable = &pVariables->at(v); - - // Create data vector - const std::vector< std::vector > *pLogData = pPort->getLogDataVectorPtr(); - if(pLogData == nullptr || pLogData->empty()) { - continue; - } - - hopsan::HString fullVarName = fullPortName+"#"+pVariable->name; - const bool includeThisVariable = includeAllVariablesInThisPort || contains(includeFilter, fullVarName.c_str()); - if (!includeThisVariable) { - continue; - } - - // Add variable to exporter - writeVariable(pCurrentSystem, pComponent, pPort, v); - - numberOfLoggedVariablesInThisComponent++; - } - } - } - if (numberOfLoggedVariablesInThisComponent > 0) { - numberOfLoggedComponentsInThisSystem++; - } - - // Recurse into subsystems - if (pComponent->isComponentSystem()) { - saveResultsTo(dynamic_cast(pComponent), includeFilter, writeTime, writeVariable); - } - } - - // Save this sytems time vector - if (numberOfLoggedComponentsInThisSystem > 0) { - writeTime(pCurrentSystem); - } - -} #endif // UTILITIES_H diff --git a/hopsandcp/src/utilities.cpp b/hopsandcp/src/utilities.cpp index a6a511e867..f9a61f2d33 100644 --- a/hopsandcp/src/utilities.cpp +++ b/hopsandcp/src/utilities.cpp @@ -27,106 +27,7 @@ //! @brief Contains utilities for hopsandcp //! -#include -#include -#include - #include "utilities.h" -#include "HopsanEssentials.h" -#include "HopsanTypes.h" - -using namespace std; -using namespace hopsan; - -void generateFullSubSystemHierarchyName(const ComponentSystem *pSys, HString &rFullSysName, const HString& separator) -{ - if (pSys->getSystemParent()) - { - generateFullSubSystemHierarchyName(pSys->getSystemParent(), rFullSysName, separator); - rFullSysName.append(pSys->getName()).append(separator); - } - else - { - // Do not include top-level name in sub-system hierarchy - rFullSysName.clear(); - } -} - -HString generateFullSubSystemHierarchyName(const Component *pComponent, const HString &separator, bool includeLastSeparator) -{ - const ComponentSystem* pSystem = pComponent->isComponentSystem() ? dynamic_cast(pComponent) : pComponent->getSystemParent(); - - HString fullSysName; - generateFullSubSystemHierarchyName(pSystem, fullSysName, separator); - if (!includeLastSeparator && !fullSysName.empty()) { - fullSysName.erase(fullSysName.size()-separator.size(),separator.size()); - } - return fullSysName; -} - -//! @brief Save results to CSV format -//! @param [in] pRootSystem Pointer to component system -//! @param [in] rFileName File name for output file -//! @param [in] howMany Specifies if all results or only final values should be saved -//! @param [in] includeFilter list of full port names or variables names to include (excluding all others) -void saveResultsToCSV(ComponentSystem *pRootSystem, const string &rFileName, const SaveResults howMany, const std::vector& includeFilter) -{ - if (pRootSystem) - { - ofstream outfile; - outfile.open(rFileName.c_str()); - if (outfile.good()) { - - auto addTimeVariable = [&outfile, howMany](ComponentSystem* pSystem) { - //! @todo alias a for time ? is that even posible - HString parentSystemNames = generateFullSubSystemHierarchyName(pSystem,"$"); - if (howMany == Final) { - outfile << parentSystemNames.c_str() << "Time,,s," << std::scientific << pSystem->getTime() << endl; - } - else if (howMany == Full) { - vector *pLogTimeVector = pSystem->getLogTimeVector(); - if (pLogTimeVector->size() > 0) { - outfile << parentSystemNames.c_str() << "Time,,s"; - for (size_t t=0; tgetNumActuallyLoggedSamples(); ++t) { - outfile << "," << std::scientific << (*pLogTimeVector)[t]; - } - outfile << endl; - } - } - }; - - auto addVariable = [&outfile, howMany](const ComponentSystem* pSystem, const Component* pComponent, const Port* pPort, size_t variableIndex) { - const NodeDataDescription& variable = *pPort->getNodeDataDescription(variableIndex); - const vector< vector > *pLogData = pPort->getLogDataVectorPtr(); - if( (pLogData != nullptr) && !pLogData->empty()) { - const HString fullVarName = generateFullSubSystemHierarchyName(pSystem,"$") + pComponent->getName() + "#" + pPort->getName() + "#" + variable.name; - if (howMany == Final) { - outfile << fullVarName.c_str() << "," << pPort->getVariableAlias(variableIndex).c_str() << "," << variable.unit.c_str(); - outfile << "," << std::scientific << pPort->readNode(variableIndex) << endl; - } - else if (howMany == Full) - { - // Only write something if data has been logged (skip ports that are not logged) - // We assume that the data vector has been cleared - if (pPort->getLogDataVectorPtr()->size() > 0) { - outfile << fullVarName.c_str() << "," << pPort->getVariableAlias(variableIndex).c_str() << "," << variable.unit.c_str(); - for (size_t t=0; tgetNumActuallyLoggedSamples(); ++t) { - outfile << "," << std::scientific << (*pLogData)[t][variableIndex]; - } - outfile << endl; - } - } - } - }; - - saveResultsTo(pRootSystem, includeFilter, addTimeVariable, addVariable); - } - else { - std::cout << "Could not open: " << rFileName << " for writing!\n"; - } - outfile.close(); - } -} From ee9fd04b1a2dcca5be806dd3ed96b9fa8ec9b036 Mon Sep 17 00:00:00 2001 From: Robert Braun Date: Tue, 16 Feb 2021 14:02:04 +0100 Subject: [PATCH 18/34] Added UUID generator to hopsandcp --- hopsandcp/include/dcpserver.h | 4 ++- hopsandcp/include/utilities.h | 4 +++ hopsandcp/src/dcpserver.cpp | 53 ++++++++++++++++++----------------- hopsandcp/src/utilities.cpp | 36 ++++++++++++++++++++++++ 4 files changed, 70 insertions(+), 27 deletions(-) diff --git a/hopsandcp/include/dcpserver.h b/hopsandcp/include/dcpserver.h index 0c1306f4a2..d856d5af13 100644 --- a/hopsandcp/include/dcpserver.h +++ b/hopsandcp/include/dcpserver.h @@ -5,6 +5,7 @@ #include #include +#include namespace hopsan { class HopsanEssentials; @@ -26,8 +27,9 @@ HOPSANDCP_DLLAPI class DcpServer bool start(); private: - SlaveDescription_t *getServerDescription(); + std::shared_ptr createServerDescription(); + std::shared_ptr mpServerDescription; hopsan::ComponentSystem *mpRootSystem; std::vector mInputs, mOutputs; std::vector mInputNodePtrs, mOutputNodePtrs; diff --git a/hopsandcp/include/utilities.h b/hopsandcp/include/utilities.h index f592e4abc1..98119e77c0 100644 --- a/hopsandcp/include/utilities.h +++ b/hopsandcp/include/utilities.h @@ -31,4 +31,8 @@ #ifndef UTILITIES_H #define UTILITIES_H +#include "HopsanTypes.h" + +hopsan::HString generateUuid(); + #endif // UTILITIES_H diff --git a/hopsandcp/src/dcpserver.cpp b/hopsandcp/src/dcpserver.cpp index 6ffa077600..21bdbb4ba4 100644 --- a/hopsandcp/src/dcpserver.cpp +++ b/hopsandcp/src/dcpserver.cpp @@ -57,7 +57,8 @@ DcpServer::DcpServer(ComponentSystem *pSystem, const std::string host, int port, udpDriver = new UdpDriver(host, uint16_t(port)); //Create server DCP manager - mManager = new DcpManagerSlave(*getServerDescription(), udpDriver->getDcpDriver()); + mpServerDescription = createServerDescription(); + mManager = new DcpManagerSlave(*mpServerDescription, udpDriver->getDcpDriver()); mManager->setInitializeCallback( std::bind(&DcpServer::initialize, this)); mManager->setConfigureCallback( @@ -87,50 +88,50 @@ DcpServer::~DcpServer() { } -SlaveDescription_t *DcpServer::getServerDescription() { - SlaveDescription_t *serverDescription = new SlaveDescription_t(make_SlaveDescription(1, 0, mpRootSystem->getName().c_str(), "b5279485-720d-4542-9f29-bee4d9a75ef9")); - serverDescription->OpMode.HardRealTime = make_HardRealTime_ptr(); - serverDescription->OpMode.SoftRealTime = make_SoftRealTime_ptr(); - serverDescription->OpMode.NonRealTime = make_NonRealTime_ptr(); +std::shared_ptr DcpServer::createServerDescription() { + SlaveDescription_t serverDescription = make_SlaveDescription(1, 0, mpRootSystem->getName().c_str(), generateUuid().c_str()); + serverDescription.OpMode.HardRealTime = make_HardRealTime_ptr(); + serverDescription.OpMode.SoftRealTime = make_SoftRealTime_ptr(); + serverDescription.OpMode.NonRealTime = make_NonRealTime_ptr(); Resolution_t resolution = make_Resolution(); resolution.numerator = 1; resolution.denominator = denominator_t(1.0/mpRootSystem->getTimestep()); - serverDescription->TimeRes.resolutions.push_back(resolution); - serverDescription->TransportProtocols.UDP_IPv4 = make_UDP_ptr(); - serverDescription->TransportProtocols.UDP_IPv4->Control = make_Control_ptr(mHost.c_str(), port_t(mPort)); - serverDescription->TransportProtocols.UDP_IPv4->DAT_input_output = make_DAT_ptr(); - serverDescription->TransportProtocols.UDP_IPv4->DAT_input_output->availablePortRanges.push_back(make_AvailablePortRange(2048, 65535)); - serverDescription->TransportProtocols.UDP_IPv4->DAT_parameter = make_DAT_ptr(); - serverDescription->TransportProtocols.UDP_IPv4->DAT_parameter->availablePortRanges.push_back(make_AvailablePortRange(2048, 65535)); - serverDescription->CapabilityFlags.canAcceptConfigPdus = true; - serverDescription->CapabilityFlags.canHandleReset = false; - serverDescription->CapabilityFlags.canHandleVariableSteps = false; - serverDescription->CapabilityFlags.canMonitorHeartbeat = false; - serverDescription->CapabilityFlags.canProvideLogOnRequest = true; - serverDescription->CapabilityFlags.canProvideLogOnNotification = true; + serverDescription.TimeRes.resolutions.push_back(resolution); + serverDescription.TransportProtocols.UDP_IPv4 = make_UDP_ptr(); + serverDescription.TransportProtocols.UDP_IPv4->Control = make_Control_ptr(mHost.c_str(), port_t(mPort)); + serverDescription.TransportProtocols.UDP_IPv4->DAT_input_output = make_DAT_ptr(); + serverDescription.TransportProtocols.UDP_IPv4->DAT_input_output->availablePortRanges.push_back(make_AvailablePortRange(2048, 65535)); + serverDescription.TransportProtocols.UDP_IPv4->DAT_parameter = make_DAT_ptr(); + serverDescription.TransportProtocols.UDP_IPv4->DAT_parameter->availablePortRanges.push_back(make_AvailablePortRange(2048, 65535)); + serverDescription.CapabilityFlags.canAcceptConfigPdus = true; + serverDescription.CapabilityFlags.canHandleReset = false; + serverDescription.CapabilityFlags.canHandleVariableSteps = false; + serverDescription.CapabilityFlags.canMonitorHeartbeat = false; + serverDescription.CapabilityFlags.canProvideLogOnRequest = true; + serverDescription.CapabilityFlags.canProvideLogOnNotification = true; for(size_t i=0; i causality = make_Output_ptr(); - serverDescription->Variables.push_back(make_Variable_output(mOutputs[i], valueReference_t(i), causality)); + serverDescription.Variables.push_back(make_Variable_output(mOutputs[i], valueReference_t(i), causality)); } for(size_t i=0; i causality = make_CommonCausality_ptr(); causality->Float64->start = std::make_shared>(); causality->Float64->start->push_back(0.0); - serverDescription->Variables.push_back(make_Variable_input(mInputs[i], valueReference_t(mOutputs.size()+i), causality)); + serverDescription.Variables.push_back(make_Variable_input(mInputs[i], valueReference_t(mOutputs.size()+i), causality)); } - serverDescription->Log = make_Log_ptr(); - serverDescription->Log->categories.push_back(make_Category(1, "DCP_SERVER")); - serverDescription->Log->templates.push_back(make_Template( + serverDescription.Log = make_Log_ptr(); + serverDescription.Log->categories.push_back(make_Category(1, "DCP_SERVER")); + serverDescription.Log->templates.push_back(make_Template( 1, 1, (uint8_t) DcpLogLevel::LVL_INFORMATION, "[Time = %float64]: output = %float64")); - return serverDescription; + return std::make_shared(serverDescription); } void DcpServer::generateDcpFile(std::string targetFile) { - writeDcpSlaveFile(std::shared_ptr(getServerDescription()), targetFile.c_str()); + writeDcpSlaveFile(std::shared_ptr(mpServerDescription), targetFile.c_str()); } bool DcpServer::start() diff --git a/hopsandcp/src/utilities.cpp b/hopsandcp/src/utilities.cpp index f9a61f2d33..85e2443a18 100644 --- a/hopsandcp/src/utilities.cpp +++ b/hopsandcp/src/utilities.cpp @@ -29,5 +29,41 @@ #include "utilities.h" +#include +#include + +hopsan::HString generateUuid() +{ + std::random_device rd; + std::mt19937_64 gen(rd()); + std::uniform_int_distribution<> dis(0, 15); + std::uniform_int_distribution<> dis2(8, 11); + std::stringstream ss; + int i; + ss << std::hex; + for (i = 0; i < 8; i++) { + ss << dis(gen); + } + ss << "-"; + for (i = 0; i < 4; i++) { + ss << dis(gen); + } + ss << "-4"; + for (i = 0; i < 3; i++) { + ss << dis(gen); + } + ss << "-"; + ss << dis2(gen); + for (i = 0; i < 3; i++) { + ss << dis(gen); + } + ss << "-"; + for (i = 0; i < 12; i++) { + ss << dis(gen); + } + return ss.str().c_str(); +} + + From 5ec0af4dc4cdf8b709d862612942e817a57dc23e Mon Sep 17 00:00:00 2001 From: Robert Braun Date: Tue, 16 Feb 2021 16:04:32 +0100 Subject: [PATCH 19/34] Enable (soft) real-time simulations with DCP --- HopsanGUI/SimulationThreadHandler.cpp | 10 ++++---- HopsanGUI/SimulationThreadHandler.h | 5 ++-- HopsanGUI/Widgets/ModelWidget.cpp | 7 ++++-- hopsandcp/include/dcpmaster.h | 4 +++- hopsandcp/src/dcpmaster.cpp | 34 +++++++++++++++++++++++---- 5 files changed, 46 insertions(+), 14 deletions(-) diff --git a/HopsanGUI/SimulationThreadHandler.cpp b/HopsanGUI/SimulationThreadHandler.cpp index 31361d2d77..25ada714dc 100644 --- a/HopsanGUI/SimulationThreadHandler.cpp +++ b/HopsanGUI/SimulationThreadHandler.cpp @@ -343,11 +343,11 @@ void SimulationThreadHandler::initSimulateFinalizeRemote(SharedRemoteCoreSimulat } #endif -void SimulationThreadHandler::initSimulateFinalizeDcpMaster(SystemObject *pSystem, const QString &host, int port) +void SimulationThreadHandler::initSimulateFinalizeDcpMaster(SystemObject *pSystem, const QString &host, int port, bool realTime) { mvpSystems.clear(); mvpSystems.push_back(pSystem); - mpSimulationWorkerObject = new DcpMasterSimulationWorkerObject(pSystem, host, port, mStartT, mStopT); + mpSimulationWorkerObject = new DcpMasterSimulationWorkerObject(pSystem, host, port, mStartT, mStopT, realTime); mpSimulationWorkerObject->setMessageHandler(mpMessageHandler); initSimulateFinalizePrivate(); } @@ -618,8 +618,8 @@ void DcpServerSimulationWorkerObject::initSimulateFinalize() emit finalizeDone(true, timer.elapsed()); } -DcpMasterSimulationWorkerObject::DcpMasterSimulationWorkerObject(SystemObject *pSystem, const QString &host, int port, double startTime, double stopTime) - : mpSystem(pSystem), mHost(host), mPort(port) +DcpMasterSimulationWorkerObject::DcpMasterSimulationWorkerObject(SystemObject *pSystem, const QString &host, int port, double startTime, double stopTime, bool realTime) + : mpSystem(pSystem), mHost(host), mPort(port), mRealTime(realTime) { mStartTime = startTime; mStopTime = stopTime; @@ -632,7 +632,7 @@ void DcpMasterSimulationWorkerObject::initSimulateFinalize() emit setProgressState(SimulationState::Initialize); timer.start(); - DcpMaster *pDcpMaster = new DcpMaster(mpSystem->getCoreSystemAccessPtr()->getCoreSystemPtr(), mHost.toStdString(), mPort, mpSystem->getTimeStep(), mStartTime, mStopTime); + DcpMaster *pDcpMaster = new DcpMaster(mpSystem->getCoreSystemAccessPtr()->getCoreSystemPtr(), mHost.toStdString(), mPort, mpSystem->getTimeStep(), mStartTime, mStopTime, mRealTime); for(const auto comp : mpSystem->getModelObjects()) { if(comp->getTypeName() == HOPSANGUIDCPCOMPONENT) { //Just in case, model shall only contain DCP components anyway pDcpMaster->addServer(comp->getParameterValue("dcpFile").toStdString()); diff --git a/HopsanGUI/SimulationThreadHandler.h b/HopsanGUI/SimulationThreadHandler.h index 7ed1310d68..4fd4491da0 100644 --- a/HopsanGUI/SimulationThreadHandler.h +++ b/HopsanGUI/SimulationThreadHandler.h @@ -118,8 +118,9 @@ class DcpMasterSimulationWorkerObject : public SimulationWorkerObjectBase SystemObject *mpSystem; QString mHost; int mPort; + bool mRealTime; public: - DcpMasterSimulationWorkerObject(SystemObject *pSystem, const QString &host, int port, double startTime, double stopTime); + DcpMasterSimulationWorkerObject(SystemObject *pSystem, const QString &host, int port, double startTime, double stopTime, bool realTime); int swoType() const {return DCPMasterSWO;} public slots: @@ -229,7 +230,7 @@ protected slots: #ifdef USEZMQ void initSimulateFinalizeRemote(SharedRemoteCoreSimulationHandlerT pRCSH, QVector *pRemoteResultVariables, double *pProgress); #endif - void initSimulateFinalizeDcpMaster(SystemObject *pSystem, const QString &host, int port); + void initSimulateFinalizeDcpMaster(SystemObject *pSystem, const QString &host, int port, bool realTime); void initSimulateFinalizeDcpServer(SystemObject *pSystem, const QString &host, int port, const QString &targetFile); void initSimulateFinalize(QVector vpSystems, const bool noChanges=false); void initSimulateFinalize_blocking(QVector vpSystems, const bool noChanges=false); diff --git a/HopsanGUI/Widgets/ModelWidget.cpp b/HopsanGUI/Widgets/ModelWidget.cpp index 0b48cfb775..a8c659c4ab 100644 --- a/HopsanGUI/Widgets/ModelWidget.cpp +++ b/HopsanGUI/Widgets/ModelWidget.cpp @@ -803,12 +803,15 @@ bool ModelWidget::simulateDcpMaster() QDialogButtonBox *pButtonBox = new QDialogButtonBox(pDcpSettingsDialog); QPushButton *pOkButton = pButtonBox->addButton(QDialogButtonBox::Ok); QPushButton *pCancelButton = pButtonBox->addButton(QDialogButtonBox::Cancel); + QCheckBox *pRealTimeCheckBox = new QCheckBox("Realtime", pDcpSettingsDialog); + pRealTimeCheckBox->setChecked(false); connect(pOkButton, SIGNAL(clicked()), pDcpSettingsDialog, SLOT(accept())); connect(pCancelButton, SIGNAL(clicked()), pDcpSettingsDialog, SLOT(reject())); pDialogLayout->addWidget(new QLabel("Host address:",pDcpSettingsDialog),0,0); pDialogLayout->addWidget(pHostLineEdit,0,1,1,2); pDialogLayout->addWidget(new QLabel("Port:",pDcpSettingsDialog),1,0); pDialogLayout->addWidget(pPortSpinBox,1,1,1,2); + pDialogLayout->addWidget(pRealTimeCheckBox); pDialogLayout->addWidget(pButtonBox, 3,1,1,3); if(pDcpSettingsDialog->exec() == QDialog::Rejected) { @@ -821,10 +824,10 @@ bool ModelWidget::simulateDcpMaster() return false; } - mpSimulationThreadHandler->setSimulationTimeVariables(mStartTime.toDouble(), mStopTime.toDouble(), mpToplevelSystem->getLogStartTime(), mpToplevelSystem->getNumberOfLogSamples()); + mpSimulationThreadHandler->setSimulationTimeVariables(mStartTime.toDouble(), mStopTime.toDouble(), mpToplevelSystem->getLogStartTime(), uint(mpToplevelSystem->getNumberOfLogSamples())); mpSimulationThreadHandler->setProgressDilaogBehaviour(true, false); mSimulationProgress=0; - mpSimulationThreadHandler->initSimulateFinalizeDcpMaster(mpToplevelSystem, pHostLineEdit->text(), pPortSpinBox->value()); + mpSimulationThreadHandler->initSimulateFinalizeDcpMaster(mpToplevelSystem, pHostLineEdit->text(), pPortSpinBox->value(), pRealTimeCheckBox->isChecked()); unlockSimulateMutex(); diff --git a/hopsandcp/include/dcpmaster.h b/hopsandcp/include/dcpmaster.h index e11a6bf068..deb987cea3 100644 --- a/hopsandcp/include/dcpmaster.h +++ b/hopsandcp/include/dcpmaster.h @@ -27,7 +27,7 @@ struct DcpConnection HOPSANDCP_DLLAPI class DcpMaster { public: - DcpMaster(hopsan::ComponentSystem *pSystem, const string host, int port, double comStep=0.001, double startTime=0, double stopTime=10); + DcpMaster(hopsan::ComponentSystem *pSystem, const string host, int port, double comStep=0.001, double startTime=0, double stopTime=10, bool realTime=false); ~DcpMaster(); void addServer(string filepath); @@ -47,8 +47,10 @@ HOPSANDCP_DLLAPI class DcpMaster void receiveNAck(uint8_t sender, uint16_t pduSeqId, DcpError errorCode); void dataReceived(uint16_t dataId, size_t length, uint8_t payload[]); void receiveStateChangedNotification(uint8_t sender, DcpState state); + void timer(hopsan::ComponentSystem *pSystem, double startTime, double stopTime); hopsan::ComponentSystem *mpSystem; + bool mRealTime; std::vector connections; diff --git a/hopsandcp/src/dcpmaster.cpp b/hopsandcp/src/dcpmaster.cpp index ba357c5177..77839ace3a 100644 --- a/hopsandcp/src/dcpmaster.cpp +++ b/hopsandcp/src/dcpmaster.cpp @@ -12,9 +12,10 @@ #include #include #include +#include -DcpMaster::DcpMaster(hopsan::ComponentSystem *pSystem, const std::string host, int port, double comStep, double startTime, double stopTime) - : mpSystem(pSystem), mComStep(comStep), mStartTime(startTime), mStopTime(stopTime) +DcpMaster::DcpMaster(hopsan::ComponentSystem *pSystem, const std::string host, int port, double comStep, double startTime, double stopTime, bool realTime) + : mpSystem(pSystem), mComStep(comStep), mStartTime(startTime), mStopTime(stopTime), mRealTime(realTime) { (*mpSystem->getTimePtr()) = mStartTime; @@ -64,13 +65,18 @@ void DcpMaster::addConnection(size_t fromServer, size_t fromVr, std::vectorSTC_register(u_char(i+1), DcpState::ALIVE, convertToUUID(serverDescriptions[i]->uuid), DcpOpMode::NRT, 1, 0); + manager->STC_register(u_char(i+1), DcpState::ALIVE, convertToUUID(serverDescriptions[i]->uuid), mode, 1, 0); } b.join(); } @@ -226,7 +232,15 @@ void DcpMaster::receiveStateChangedNotification(uint8_t sender, stop(); } else { - doStep(); + if(!mRealTime) { + doStep(); + } + else { + std::thread timerThread(&DcpMaster::timer, this, mpSystem, mStartTime, mStopTime); + timerThread.join(); + serversWaitingToStop = uint8_t(serverDescriptions.size()); + stop(); + } } break; @@ -257,6 +271,18 @@ void DcpMaster::receiveStateChangedNotification(uint8_t sender, } } +void DcpMaster::timer(hopsan::ComponentSystem *pSystem, double startTime, double stopTime) +{ + std::chrono::steady_clock::time_point time = std::chrono::steady_clock::now(); + double simTime = startTime; + while(simTime < stopTime) { + time += std::chrono::milliseconds{100}; + simTime += 0.1; + (*pSystem->getTimePtr()) = simTime; + std::this_thread::sleep_until(time); + } +} + void getDataFromProtocolFile(const hopsan::HString &rFilePath, hopsan::HString &rName, hopsan::HString &rVariables, hopsan::HString &rValueReferences) From 383c3765c2f1437875d4c1a3254b73120711ac08 Mon Sep 17 00:00:00 2001 From: Robert Braun Date: Wed, 17 Feb 2021 10:39:12 +0100 Subject: [PATCH 20/34] Prevent adding same DCP server twice in same model --- HopsanGUI/GraphicsView.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/HopsanGUI/GraphicsView.cpp b/HopsanGUI/GraphicsView.cpp index cc38e258ab..9e2d372221 100644 --- a/HopsanGUI/GraphicsView.cpp +++ b/HopsanGUI/GraphicsView.cpp @@ -161,6 +161,14 @@ void GraphicsView::contextMenuEvent ( QContextMenuEvent * event ) QFileInfo dcpFileInfo(dcpPath); gpConfig->setStringSetting(CFG_DCPDIR, dcpFileInfo.absolutePath()); + //Check that DCP server is not already added to model + for(const auto &comp : mpParentModelWidget->getTopLevelSystemContainer()->getModelObjects()) { + if(comp->getParameterValue("dcpFile") == dcpFileInfo.absoluteFilePath()) { + gpMessageHandler->addErrorMessage("Specified DCP server already exists in model. Only one instance is allowed."); + return; + } + } + hopsan::HString name, variables, valueRefs; getDataFromProtocolFile(dcpFileInfo.filePath().toStdString().c_str(), name, variables, valueRefs); From 55c3fe016f91ac5ddee9f049480f322375aef87d Mon Sep 17 00:00:00 2001 From: Robert Braun Date: Thu, 23 Mar 2023 08:53:11 +0100 Subject: [PATCH 21/34] Fix some build issues --- Common.prf | 4 +++- hopsandcp/hopsandcp.pro | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Common.prf b/Common.prf index a3f970129f..2e20674f37 100644 --- a/Common.prf +++ b/Common.prf @@ -13,10 +13,12 @@ CONFIG(debug, debug|release) { # O3 = highest optimization level for speed CONFIG(debug, debug|release) { #QMAKE_CXXFLAGS += -Og + QMAKE_CXXFLAGS += -v -Wa,-mbig-obj } CONFIG(release, debug|release) { - QMAKE_CXXFLAGS += -O3 + QMAKE_CXXFLAGS += -O3 -v -Wa,-mbig-obj } +message("QMAKE_CXXFLAGS: $${QMAKE_CXXFLAGS}") # Enable C++14 CONFIG += c++14 diff --git a/hopsandcp/hopsandcp.pro b/hopsandcp/hopsandcp.pro index ed2c077275..b04ec7fe14 100644 --- a/hopsandcp/hopsandcp.pro +++ b/hopsandcp/hopsandcp.pro @@ -10,10 +10,12 @@ DESTDIR = $${PWD}/../bin TARGET = $${TARGET}$${DEBUG_EXT} DEFINES += LOGGING #DEFINES += DEBUG -QMAKE_CXXFLAGS = -Wno-comment -Wno-switch -Wno-ignored-qualifiers -Wno-sign-compare +QMAKE_CXXFLAGS += -Wno-comment -Wno-switch -Wno-ignored-qualifiers -Wno-sign-compare QT -= core gui +LIBS *= -lws2_32 + #-------------------------------------------------- # Add the include path to our self, (hopsandcp) INCLUDEPATH *= $${PWD}/include/ From 8507ceaf11c07373721578123f0d19f5f994ea50 Mon Sep 17 00:00:00 2001 From: Robert Braun Date: Tue, 28 Nov 2023 08:46:50 +0100 Subject: [PATCH 22/34] add HopsanCore/src/HString.cppAdd join() and append(vector) to HVector. Handle empty strings in HString::split(). --- HopsanCore/include/HString.h | 12 ++++++++++++ HopsanCore/include/HVector.hpp | 12 ++++++++++++ HopsanCore/src/HString.cpp | 2 +- 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/HopsanCore/include/HString.h b/HopsanCore/include/HString.h index c1397d37e8..0797115a58 100644 --- a/HopsanCore/include/HString.h +++ b/HopsanCore/include/HString.h @@ -122,6 +122,18 @@ inline HString operator+(HString lhs, const char rhs) return lhs; } +inline HString join(HVector &vec, const char delim) { + HString ret; + for(size_t i=0; i 0) { + ret.erase(ret.size()-1,1); + } + return ret; +} + } #endif // HSTRING_H diff --git a/HopsanCore/include/HVector.hpp b/HopsanCore/include/HVector.hpp index 1fb965d684..a2b1640218 100644 --- a/HopsanCore/include/HVector.hpp +++ b/HopsanCore/include/HVector.hpp @@ -132,6 +132,18 @@ class HVector mpDataArray[prevSize] = data; } + //! @brief Append data + //! @note This function is slow, it will reallocate all array memory every time + //! @param [in] data Data to append + void append(const HVector &data) + { + size_t prevSize = mSize; + resize(prevSize+data.size()); + for(int i=0; i HString::split(const char delim) const { HVector parts; size_t b = 0; - while (true) + while (true && mSize > 0) { size_t e = find(delim, b); parts.append(substr(b,e-b)); From 0ff6835f32b36cd7441bb6ad587b039109e25a6d Mon Sep 17 00:00:00 2001 From: Robert Braun Date: Tue, 28 Nov 2023 09:19:54 +0100 Subject: [PATCH 23/34] Minor cleanup --- HopsanGUI/GraphicsView.cpp | 2 +- HopsanGUI/SimulationThreadHandler.cpp | 10 ++++++---- hopsandcp/src/dcpmaster.cpp | 3 ++- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/HopsanGUI/GraphicsView.cpp b/HopsanGUI/GraphicsView.cpp index 9e2d372221..6a9c4c7f46 100644 --- a/HopsanGUI/GraphicsView.cpp +++ b/HopsanGUI/GraphicsView.cpp @@ -152,7 +152,7 @@ void GraphicsView::contextMenuEvent ( QContextMenuEvent * event ) mpContainerObject->getUndoStackPtr()->newPost(); mpContainerObject->addImageWidget(this->mapToScene(event->pos()).toPoint()); else if(addDcpServerAction != nullptr && selectedAction == addDcpServerAction) { - QString dcpPath = QFileDialog::getOpenFileName(gpMainWindowWidget, tr("Select Distributed Co-Simlation Protocol File"), + QString dcpPath = QFileDialog::getOpenFileName(gpMainWindowWidget, tr("Select Distributed Co-Simulation Protocol File"), gpConfig->getStringSetting(CFG_DCPDIR), tr("Distributed Co-Simulation Protocol Files (*.dcp)")); if(dcpPath.isEmpty()) { diff --git a/HopsanGUI/SimulationThreadHandler.cpp b/HopsanGUI/SimulationThreadHandler.cpp index 25ada714dc..47c768853c 100644 --- a/HopsanGUI/SimulationThreadHandler.cpp +++ b/HopsanGUI/SimulationThreadHandler.cpp @@ -633,13 +633,15 @@ void DcpMasterSimulationWorkerObject::initSimulateFinalize() timer.start(); DcpMaster *pDcpMaster = new DcpMaster(mpSystem->getCoreSystemAccessPtr()->getCoreSystemPtr(), mHost.toStdString(), mPort, mpSystem->getTimeStep(), mStartTime, mStopTime, mRealTime); - for(const auto comp : mpSystem->getModelObjects()) { + const QList modelObjects = mpSystem->getModelObjects(); + for(const auto comp : modelObjects) { if(comp->getTypeName() == HOPSANGUIDCPCOMPONENT) { //Just in case, model shall only contain DCP components anyway pDcpMaster->addServer(comp->getParameterValue("dcpFile").toStdString()); } } std::map,std::pair,std::vector > > connections; - for(const auto &connection : mpSystem->getSubConnectorPtrs()) { + const QList subConnectors = mpSystem->getSubConnectorPtrs(); + for(const auto &connection : subConnectors) { Port *pStartPort = connection->getStartPort(); Port *pEndPort = connection->getEndPort(); ModelObject *pStartComponent = pStartPort->getParentModelObject(); @@ -649,13 +651,13 @@ void DcpMasterSimulationWorkerObject::initSimulateFinalize() QVector variameters; size_t fromVr, toVr; pStartComponent->getVariameterDescriptions(variameters); - for(const auto &variameter : variameters) { + for(const auto &variameter : qAsConst(variameters)) { if(variameter.mPortName == pStartPort->getName()) { fromVr = variameter.mDescription.toUInt(); } } pEndComponent->getVariameterDescriptions(variameters); - for(const auto &variameter : variameters) { + for(const auto &variameter : qAsConst(variameters)) { if(variameter.mPortName == pEndPort->getName()) { toVr = variameter.mDescription.toUInt(); } diff --git a/hopsandcp/src/dcpmaster.cpp b/hopsandcp/src/dcpmaster.cpp index 77839ace3a..3e4d04145d 100644 --- a/hopsandcp/src/dcpmaster.cpp +++ b/hopsandcp/src/dcpmaster.cpp @@ -15,7 +15,7 @@ #include DcpMaster::DcpMaster(hopsan::ComponentSystem *pSystem, const std::string host, int port, double comStep, double startTime, double stopTime, bool realTime) - : mpSystem(pSystem), mComStep(comStep), mStartTime(startTime), mStopTime(stopTime), mRealTime(realTime) + : mpSystem(pSystem), mRealTime(realTime), mComStep(comStep), mStartTime(startTime), mStopTime(stopTime) { (*mpSystem->getTimePtr()) = mStartTime; @@ -195,6 +195,7 @@ void DcpMaster::receiveNAck(uint8_t sender, uint16_t pduSeqId, DcpError errorCod void DcpMaster::dataReceived(uint16_t dataId, size_t length, uint8_t payload[]) { + (void)dataId; (void)length; (void)payload; } From cd246cc7ca71085e9f516ec8f9f7949f3662892e Mon Sep 17 00:00:00 2001 From: Robert Braun Date: Tue, 28 Nov 2023 09:20:44 +0100 Subject: [PATCH 24/34] Do not unlock simulation mutex before simulation starts --- HopsanGUI/Widgets/ModelWidget.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/HopsanGUI/Widgets/ModelWidget.cpp b/HopsanGUI/Widgets/ModelWidget.cpp index a8c659c4ab..c0cac001b5 100644 --- a/HopsanGUI/Widgets/ModelWidget.cpp +++ b/HopsanGUI/Widgets/ModelWidget.cpp @@ -776,8 +776,6 @@ bool ModelWidget::simulateDcpServer() mSimulationProgress=0; mpSimulationThreadHandler->initSimulateFinalizeDcpServer(mpToplevelSystem, pHostLineEdit->text(), pPortSpinBox->value(), pTargetFileLineEdit->text()); - unlockSimulateMutex(); - return true; //! @todo fix return code } @@ -829,8 +827,6 @@ bool ModelWidget::simulateDcpMaster() mSimulationProgress=0; mpSimulationThreadHandler->initSimulateFinalizeDcpMaster(mpToplevelSystem, pHostLineEdit->text(), pPortSpinBox->value(), pRealTimeCheckBox->isChecked()); - unlockSimulateMutex(); - return true; //! @todo fix return code From 465f5878a1fdb7ffc5c70e5a4b534986ea089f98 Mon Sep 17 00:00:00 2001 From: Robert Braun Date: Tue, 28 Nov 2023 09:21:15 +0100 Subject: [PATCH 25/34] Fix DCP inputs/outputs --- HopsanGUI/GUIObjects/GUIComponent.cpp | 3 +++ hopsandcp/src/dcpmaster.cpp | 5 ++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/HopsanGUI/GUIObjects/GUIComponent.cpp b/HopsanGUI/GUIObjects/GUIComponent.cpp index 901c163436..6c5db04529 100644 --- a/HopsanGUI/GUIObjects/GUIComponent.cpp +++ b/HopsanGUI/GUIObjects/GUIComponent.cpp @@ -164,6 +164,9 @@ bool Component::setParameterValue(QString name, QString value, bool force) if("ReadPortType" == type) { inputs << port; } + else if(this->getTypeName() == "DcpComponent" && "WritePortType" == type) { + outputs << port; + } else if("WritePortType" == type && visibleOutputs.contains(port)) { outputs << port; } diff --git a/hopsandcp/src/dcpmaster.cpp b/hopsandcp/src/dcpmaster.cpp index 3e4d04145d..e5e1c6c130 100644 --- a/hopsandcp/src/dcpmaster.cpp +++ b/hopsandcp/src/dcpmaster.cpp @@ -325,7 +325,10 @@ void getDataFromProtocolFile(const hopsan::HString &rFilePath, hopsan::HString & rVariables = inputs+";"+outputs+";"+pars; //Value references is a plain comma-separated string - rValueReferences = inputVrs+","+outputVrs+","+parVrs; + hopsan::HVector valueRefVec = inputVrs.split(','); + valueRefVec.append(outputVrs.split(',')); + valueRefVec.append(parVrs.split(',')); + rValueReferences = join(valueRefVec, ','); //Value references string could end with a comma if one //of the lists above is empty. If so, remove this. From be6151c7aa75d775acb239ef7fd4d7ad986608a6 Mon Sep 17 00:00:00 2001 From: Robert Braun Date: Tue, 28 Nov 2023 09:21:38 +0100 Subject: [PATCH 26/34] Wait for all servers before stopping DCP simulation --- hopsandcp/include/dcpmaster.h | 1 + hopsandcp/src/dcpmaster.cpp | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/hopsandcp/include/dcpmaster.h b/hopsandcp/include/dcpmaster.h index deb987cea3..b0842e068c 100644 --- a/hopsandcp/include/dcpmaster.h +++ b/hopsandcp/include/dcpmaster.h @@ -80,6 +80,7 @@ HOPSANDCP_DLLAPI class DcpMaster uint8_t serversWaitingForConfiguration = 0; uint8_t serversWaitingAtExit = 0; uint8_t serversWaitingToStop = 0; + uint8_t serversRunPastStopTime = 0; uint8_t serversWaitingForInitialize = 0; uint8_t serversWaitingToRun = 0; }; diff --git a/hopsandcp/src/dcpmaster.cpp b/hopsandcp/src/dcpmaster.cpp index e5e1c6c130..f41c5bf02f 100644 --- a/hopsandcp/src/dcpmaster.cpp +++ b/hopsandcp/src/dcpmaster.cpp @@ -230,6 +230,10 @@ void DcpMaster::receiveStateChangedNotification(uint8_t sender, case DcpState::RUNNING: if(mpSystem->getTime() > mStopTime) { + serversRunPastStopTime++; + if(serversRunPastStopTime < serverDescriptions.size()) { + return; + } stop(); } else { From 0b28c1470cab761989d09b8e5072b08be8189d01 Mon Sep 17 00:00:00 2001 From: Robert Braun Date: Tue, 28 Nov 2023 09:21:56 +0100 Subject: [PATCH 27/34] Support variable resolution in DCP servers --- hopsandcp/src/dcpserver.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/hopsandcp/src/dcpserver.cpp b/hopsandcp/src/dcpserver.cpp index 21bdbb4ba4..be502faf4f 100644 --- a/hopsandcp/src/dcpserver.cpp +++ b/hopsandcp/src/dcpserver.cpp @@ -96,6 +96,7 @@ std::shared_ptr DcpServer::createServerDescription() { Resolution_t resolution = make_Resolution(); resolution.numerator = 1; resolution.denominator = denominator_t(1.0/mpRootSystem->getTimestep()); + resolution.fixed = false; serverDescription.TimeRes.resolutions.push_back(resolution); serverDescription.TransportProtocols.UDP_IPv4 = make_UDP_ptr(); serverDescription.TransportProtocols.UDP_IPv4->Control = make_Control_ptr(mHost.c_str(), port_t(mPort)); From 0395a44b3eadbd66c7c564fb0d3b4d67957061f7 Mon Sep 17 00:00:00 2001 From: Robert Braun Date: Tue, 22 Oct 2024 13:53:48 +0200 Subject: [PATCH 28/34] Add skip empty strings option to HString::split() --- .../include/Components/DcpComponent.hpp | 10 +++---- HopsanCore/include/HString.h | 4 ++- HopsanCore/src/HString.cpp | 28 ++++++++++--------- hopsandcp/src/dcpmaster.cpp | 6 ++-- 4 files changed, 26 insertions(+), 22 deletions(-) diff --git a/HopsanCore/include/Components/DcpComponent.hpp b/HopsanCore/include/Components/DcpComponent.hpp index f4305badc2..1142b596b9 100644 --- a/HopsanCore/include/Components/DcpComponent.hpp +++ b/HopsanCore/include/Components/DcpComponent.hpp @@ -91,10 +91,10 @@ namespace hopsan { mOutputs.clear(); mParameters.clear(); - HVector splitVariables = mVariables.split(';'); - HVector splitInputs = splitVariables[0].split(','); - HVector splitOutputs = splitVariables[1].split(','); - HVector splitParameters = splitVariables[2].split(','); + HVector splitVariables = mVariables.split(';', HString::SkipEmptyParts); + HVector splitInputs = splitVariables[0].split(',', HString::SkipEmptyParts); + HVector splitOutputs = splitVariables[1].split(',', HString::SkipEmptyParts); + HVector splitParameters = splitVariables[2].split(',', HString::SkipEmptyParts); //The split function will return a single-element vector with an //empty string if delimiter was not found, clear vector in this case @@ -107,7 +107,7 @@ namespace hopsan { if(splitParameters.size() == 1 && splitParameters[0] == "") { splitParameters.clear(); } - HVector splitValueRefs = mValueRefs.split(','); + HVector splitValueRefs = mValueRefs.split(',', HString::SkipEmptyParts); if(splitValueRefs.size() != splitInputs.size()+splitOutputs.size()+splitParameters.size()) { addErrorMessage("Number of value references does not equal number of variables"); diff --git a/HopsanCore/include/HString.h b/HopsanCore/include/HString.h index 0797115a58..8fcdd78d74 100644 --- a/HopsanCore/include/HString.h +++ b/HopsanCore/include/HString.h @@ -39,6 +39,8 @@ class HOPSANCORE_DLLAPI HString size_t mSize; public: + enum SplitBehaviorEnumT { KeepEmptyParts, SkipEmptyParts }; + static const size_t npos; HString(); @@ -74,7 +76,7 @@ class HOPSANCORE_DLLAPI HString bool toBool(bool *isOK) const; HString substr(const size_t pos, const size_t len=npos) const; - HVector split(const char delim) const; + HVector split(const char delim, SplitBehaviorEnumT behaviour = KeepEmptyParts) const; size_t find_first_of(const char c, size_t pos = 0) const; size_t rfind(const char c, size_t pos = npos) const; diff --git a/HopsanCore/src/HString.cpp b/HopsanCore/src/HString.cpp index f33a0b9b18..ec1d556bf0 100644 --- a/HopsanCore/src/HString.cpp +++ b/HopsanCore/src/HString.cpp @@ -523,19 +523,21 @@ HString HString::substr(const size_t pos, const size_t len) const return sub; } -HVector HString::split(const char delim) const -{ - HVector parts; - size_t b = 0; - while (true && mSize > 0) - { - size_t e = find(delim, b); - parts.append(substr(b,e-b)); - if (e == npos) +HVector HString::split(const char delim, SplitBehaviorEnumT behaviour) const +{ + HVector parts; + size_t b = 0; + while (true) { - break; + size_t e = find(delim, b); + if(behaviour == KeepEmptyParts || !substr(b,e-b).empty()) { + parts.append(substr(b,e-b)); + } + if (e == npos) + { + break; + } + b=e+1; } - b=e+1; - } - return parts; + return parts; } diff --git a/hopsandcp/src/dcpmaster.cpp b/hopsandcp/src/dcpmaster.cpp index f41c5bf02f..343dc11d89 100644 --- a/hopsandcp/src/dcpmaster.cpp +++ b/hopsandcp/src/dcpmaster.cpp @@ -329,9 +329,9 @@ void getDataFromProtocolFile(const hopsan::HString &rFilePath, hopsan::HString & rVariables = inputs+";"+outputs+";"+pars; //Value references is a plain comma-separated string - hopsan::HVector valueRefVec = inputVrs.split(','); - valueRefVec.append(outputVrs.split(',')); - valueRefVec.append(parVrs.split(',')); + hopsan::HVector valueRefVec = inputVrs.split(',', hopsan::HString::SkipEmptyParts); + valueRefVec.append(outputVrs.split(',', hopsan::HString::SkipEmptyParts)); + valueRefVec.append(parVrs.split(',', hopsan::HString::SkipEmptyParts)); rValueReferences = join(valueRefVec, ','); //Value references string could end with a comma if one From b077d422463e1f5e3b1844439064f370f0e09efb Mon Sep 17 00:00:00 2001 From: Robert Braun Date: Fri, 11 Oct 2024 15:35:58 +0200 Subject: [PATCH 29/34] Fix compilation and dependencies Fix Windows dependencies Added missing dependencies for Appveyor Added CMakeLists.txt to hopsandcp Add missing calls to dependency scripts for Appveyor Correct include directories in CMake Build all dependencies with ci-build Added Linux script for setting up DCPLib Set executable permission to DCPLib install script Added include path to libzip Fix Linux setup script for libzip Add include paths to Xerces and Asio Add include path to libzip Fix compilation error without ZMQ Remove pause from Xerces setup script Added missing include Add patch to DCPLib code to fix a missing include Add logging define to DCPLib to resolve compilation error Patch for missing function in DCPLib Enable LOGGING flag in hopsandcp Specify release build for Zlib on Windows Correct use of define in call to CMake Make Cmake define public Changed to forward slashes in CMake path Remove unneeded patch Added hopsandcp dependency to HopsanGUI Added libzip dependency to HopsanCore Patch DCPLib to make IpToString function inlined Fix release build for zlib Fix CMake build Add check for MinGW compiler flag Add Zlib, add DCPLib to setup scripts Fix Linux compilation Compilation fixes Test local libzip in ci-build Attempt to fix MSVC compilation Add Zlib setup script to Appveyor Attempt to fix MSVC linking Attempt to fix patch command for msvc Fix patch for Windows builds Attempt to link Xerces with MSVC Find local xerces with msvc Attempt to fix libzip linking on msvc --- .appveyor.yml | 6 +++- .github/workflows/ci-build.yaml | 13 +++++++-- CMakeLists.txt | 9 ++++++ HopsanGUI/CMakeLists.txt | 8 ++++-- HopsanGUI/GraphicsView.cpp | 12 ++++---- HopsanGUI/HopsanGUI.pro | 2 ++ HopsanGUI/Widgets/ModelWidget.cpp | 4 +-- HopsanGUI/Widgets/ModelWidget.h | 2 +- HopsanNG.pro | 4 +-- dependencies/dcplib-patch.txt | 4 +++ dependencies/dependencies.xml | 14 ++++++++- dependencies/libzip.cmake | 33 ++++++++++++++++++++++ dependencies/libzip.pri | 26 +++++++++++++++++ dependencies/setupAll.bat | 3 ++ dependencies/setupAll.sh | 2 +- dependencies/setupAsio.sh | 27 ------------------ dependencies/setupDCPLib.bat | 29 +++++++++++++++++++ dependencies/setupDCPLib.sh | 35 +++++++++++++++++++++++ dependencies/setupLibzip.bat | 32 +++++++++++++++++++++ dependencies/setupLibzip.sh | 6 ++-- dependencies/setupXerces.bat | 28 ++++++++++++++++++ dependencies/setupZlib.bat | 25 ++++++++++++++++ dependencies/xerces.cmake | 40 ++++++++++++++++++++++++++ dependencies/xerces.pri | 25 ++++++++++++++++ hopsandcp/CMakeLists.txt | 47 +++++++++++++++++++++++++++++++ hopsandcp/dependencies/DCPLib | 1 - hopsandcp/hopsandcp.pro | 33 ++++++++-------------- hopsandcp/src/dcpmaster.cpp | 6 ++-- hopsandcp/src/dcpserver.cpp | 3 +- 29 files changed, 405 insertions(+), 74 deletions(-) create mode 100644 dependencies/dcplib-patch.txt create mode 100644 dependencies/libzip.cmake create mode 100644 dependencies/libzip.pri delete mode 100755 dependencies/setupAsio.sh create mode 100644 dependencies/setupDCPLib.bat create mode 100755 dependencies/setupDCPLib.sh create mode 100644 dependencies/setupLibzip.bat create mode 100644 dependencies/setupXerces.bat create mode 100644 dependencies/setupZlib.bat create mode 100644 dependencies/xerces.cmake create mode 100644 dependencies/xerces.pri create mode 100644 hopsandcp/CMakeLists.txt delete mode 160000 hopsandcp/dependencies/DCPLib diff --git a/.appveyor.yml b/.appveyor.yml index 3596e82a32..d81d7a5faa 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -9,7 +9,7 @@ configuration: Release install: - git submodule update --init - cd dependencies - - download-dependencies.py discount fmilibrary qwt zeromq cppzmq msgpack-c katex tclap fmi4c + - download-dependencies.py discount fmilibrary qwt zeromq cppzmq msgpack-c katex tclap fmi4c xerces asio zlib libzip dcplib - cd .. build_script: # Remove sh.exe from PATH so that CMake works @@ -19,6 +19,10 @@ build_script: - setupDiscount.bat - setupFMILibrary.bat - setupFmi4c.bat + - setupXerces.bat + - setupZlib.bat + - setupLibzip.bat + - setupDCPLib.bat # - setupHDF5.bat (takes to long to build) - setupKatex.bat - setupTclap.bat diff --git a/.github/workflows/ci-build.yaml b/.github/workflows/ci-build.yaml index b45067d9e2..db8436146b 100644 --- a/.github/workflows/ci-build.yaml +++ b/.github/workflows/ci-build.yaml @@ -33,7 +33,7 @@ jobs: - name: Download dependencies shell: cmd working-directory: dependencies - run: python download-dependencies.py fmilibrary tclap qwt fmi4c + run: python download-dependencies.py fmilibrary tclap qwt fmi4c xerces asio zlib libzip dcplib - name: Build dependencies shell: cmd @@ -44,6 +44,10 @@ jobs: call setupFMILibrary.bat call setupQwt.bat call setupFmi4c.bat + call setupXerces.bat + call setupZlib.bat + call setupLibzip.bat + call setupDCPLib.bat - name: Configure working-directory: hopsan-build @@ -67,7 +71,7 @@ jobs: - name: Install Packages run: | sudo apt-get update - sudo apt-get install qt5-default qtbase5-dev qtbase5-private-dev libqt5webkit5-dev libqt5svg5-dev libqt5opengl5-dev libhdf5-dev libmarkdown2-dev libmsgpack-dev libqwt-qt5-dev libzmq3-dev + sudo apt-get install qt5-default qtbase5-dev qtbase5-private-dev libqt5webkit5-dev libqt5svg5-dev libqt5opengl5-dev libhdf5-dev libmarkdown2-dev libmsgpack-dev libqwt-qt5-dev libzmq3-dev zlib1g zipcmp ziptool zipmerge - name: Checkout uses: actions/checkout@v3 @@ -85,7 +89,7 @@ jobs: - name: Download dependencies shell: bash working-directory: dependencies - run: ./download-dependencies.py fmilibrary tclap fmi4c + run: ./download-dependencies.py fmilibrary tclap fmi4c xerces asio dcplib libzip - name: Build dependencies shell: bash @@ -94,6 +98,9 @@ jobs: ./setupFMILibrary.sh ./setupTclap.sh ./setupFmi4c.sh + ./setupXerces.sh + ./setupDCPLib.sh + ./setupLibzip.sh - name: Configure working-directory: hopsan-build diff --git a/CMakeLists.txt b/CMakeLists.txt index cc1bb12d40..5cbe7f9d03 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,11 +7,20 @@ cmake_policy(SET CMP0079 NEW) set(HOPSANCORE_INSTALL_DST "HopsanCore") message(WARNING "Hopsan CMake support is still experimental, but should be working for for GCC / MinGW and limited MSVC build") +include(CheckCXXCompilerFlag) +if (MINGW) + check_cxx_compiler_flag("Wa,-mbig-obj" COMPILER_HAS_MBIG_OBJ) + if (${COMPILER_HAS_MBIG_OBJ}) + set(CMAKE_CXX_FLAGS -Wa,-mbig-obj) + endif() +endif () + enable_testing() add_subdirectory(doc) add_subdirectory(HopsanCore) add_subdirectory(componentLibraries) +add_subdirectory(hopsandcp) add_subdirectory(HopsanCLI) add_subdirectory(HopsanGUI) add_subdirectory(HopsanGenerator) diff --git a/HopsanGUI/CMakeLists.txt b/HopsanGUI/CMakeLists.txt index f14eb01077..fa71ec5996 100644 --- a/HopsanGUI/CMakeLists.txt +++ b/HopsanGUI/CMakeLists.txt @@ -14,6 +14,7 @@ include(${CMAKE_CURRENT_LIST_DIR}/../helpers.cmake) include(${CMAKE_CURRENT_LIST_DIR}/../dependencies/qwt.cmake) include(${CMAKE_CURRENT_LIST_DIR}/../dependencies/discount.cmake) include(${CMAKE_CURRENT_LIST_DIR}/../dependencies/katex.cmake) +include(${CMAKE_CURRENT_LIST_DIR}/../dependencies/xerces.cmake) set(target_name hopsangui) @@ -22,7 +23,9 @@ add_executable(${target_name} ${srcfiles}) target_include_directories(${target_name} PRIVATE $ - $) + $ + $ + $) target_compile_definitions(${target_name} PRIVATE _USE_MATH_DEFINES) if(NOT CMAKE_BUILD_TYPE MATCHES Debug) @@ -31,7 +34,8 @@ if(NOT CMAKE_BUILD_TYPE MATCHES Debug) endif() target_link_libraries(${target_name} Qt5::Core Qt5::Gui Qt5::Widgets Qt5::Xml Qt5::Svg Qt5::Network Qt5::Test Qt5::PrintSupport - qwt hopsancore hopsangeneratorgui symhop ops) + qwt hopsancore hopsangeneratorgui symhop ops hopsandcp xercesc ) + target_link_optional_libraries(${target_name} libhopsanremoteclient hopsanhdf5exporter discount katex) set_target_properties(${target_name} PROPERTIES INSTALL_RPATH "\$ORIGIN/../lib") diff --git a/HopsanGUI/GraphicsView.cpp b/HopsanGUI/GraphicsView.cpp index 6a9c4c7f46..89e3c83b1f 100644 --- a/HopsanGUI/GraphicsView.cpp +++ b/HopsanGUI/GraphicsView.cpp @@ -143,24 +143,24 @@ void GraphicsView::contextMenuEvent ( QContextMenuEvent * event ) QCursor cursor; QAction *selectedAction = menu.exec(cursor.pos()); - if(selectedAction == addTextBoxAction) - { + if(selectedAction == addTextBoxAction) { mpContainerObject->getUndoStackPtr()->newPost(); mpContainerObject->addTextBoxWidget(this->mapToScene(event->pos()).toPoint()); } else if(selectedAction == addImageWidgetAction) { mpContainerObject->getUndoStackPtr()->newPost(); mpContainerObject->addImageWidget(this->mapToScene(event->pos()).toPoint()); + } else if(addDcpServerAction != nullptr && selectedAction == addDcpServerAction) { QString dcpPath = QFileDialog::getOpenFileName(gpMainWindowWidget, tr("Select Distributed Co-Simulation Protocol File"), - gpConfig->getStringSetting(CFG_DCPDIR), + gpConfig->getStringSetting(cfg::dir::dcp), tr("Distributed Co-Simulation Protocol Files (*.dcp)")); if(dcpPath.isEmpty()) { return; } QFileInfo dcpFileInfo(dcpPath); - gpConfig->setStringSetting(CFG_DCPDIR, dcpFileInfo.absolutePath()); - + gpConfig->setStringSetting(cfg::dir::dcp, dcpFileInfo.absolutePath()); + //Check that DCP server is not already added to model for(const auto &comp : mpParentModelWidget->getTopLevelSystemContainer()->getModelObjects()) { if(comp->getParameterValue("dcpFile") == dcpFileInfo.absoluteFilePath()) { @@ -171,7 +171,7 @@ void GraphicsView::contextMenuEvent ( QContextMenuEvent * event ) hopsan::HString name, variables, valueRefs; getDataFromProtocolFile(dcpFileInfo.filePath().toStdString().c_str(), name, variables, valueRefs); - + ModelObject *pObj = mpContainerObject->addModelObject(HOPSANGUIDCPCOMPONENT, this->mapToScene(event->pos()).toPoint()); mpParentModelWidget->getTopLevelSystemContainer()->renameModelObject(pObj->getName(), (name.c_str())); pObj->setParameterValue("dcpFile", dcpFileInfo.absoluteFilePath()); diff --git a/HopsanGUI/HopsanGUI.pro b/HopsanGUI/HopsanGUI.pro index 1b10309eaf..311ca1c011 100644 --- a/HopsanGUI/HopsanGUI.pro +++ b/HopsanGUI/HopsanGUI.pro @@ -80,6 +80,8 @@ have_hdf5(){ } #-------------------------------------------------------- +include($${PWD}/../dependencies/libzip.pri) + #-------------------------------------------------------- # Set HopsanCore Paths INCLUDEPATH *= $${PWD}/../HopsanCore/include/ diff --git a/HopsanGUI/Widgets/ModelWidget.cpp b/HopsanGUI/Widgets/ModelWidget.cpp index c0cac001b5..29e46c23d8 100644 --- a/HopsanGUI/Widgets/ModelWidget.cpp +++ b/HopsanGUI/Widgets/ModelWidget.cpp @@ -732,7 +732,7 @@ void ModelWidget::stopRealtimeSimulation() bool ModelWidget::simulateDcpServer() { // Save backup copy - if (!isSaved() && gpConfig->getBoolSetting(CFG_AUTOBACKUP)) + if (!isSaved() && gpConfig->getBoolSetting(cfg::autobackup)) { //! @todo this should be a help function, also we may not want to call it every time when we run optimization (not sure if that is done now but probably) QString fileNameWithoutHmf = mpToplevelSystem->getModelFileInfo().fileName(); @@ -783,7 +783,7 @@ bool ModelWidget::simulateDcpServer() bool ModelWidget::simulateDcpMaster() { // Save backup copy - if (!isSaved() && gpConfig->getBoolSetting(CFG_AUTOBACKUP)) + if (!isSaved() && gpConfig->getBoolSetting(cfg::autobackup)) { //! @todo this should be a help function, also we may not want to call it every time when we run optimization (not sure if that is done now but probably) QString fileNameWithoutHmf = mpToplevelSystem->getModelFileInfo().fileName(); diff --git a/HopsanGUI/Widgets/ModelWidget.h b/HopsanGUI/Widgets/ModelWidget.h index f75b0e1b5d..887983a6dc 100644 --- a/HopsanGUI/Widgets/ModelWidget.h +++ b/HopsanGUI/Widgets/ModelWidget.h @@ -190,9 +190,9 @@ private slots: SharedRemoteCoreSimulationHandlerT mpLocalRemoteCoreSimulationHandler; SharedRemoteCoreSimulationHandlerT mpExternalRemoteCoreSimulationHandler; SharedRemoteCoreSimulationHandlerT chooseRemoteCoreSimulationHandler() const; - double mSimulationProgress; #endif // Remote collected data + double mSimulationProgress; QVector mRemoteResultVariables; QMutex mSimulateMutex; }; diff --git a/HopsanNG.pro b/HopsanNG.pro index 777329f56a..216979127c 100644 --- a/HopsanNG.pro +++ b/HopsanNG.pro @@ -3,11 +3,11 @@ TEMPLATE = subdirs SUBDIRS = HopsanCore componentLibraries SymHop Ops HopsanGenerator hopsangeneratorgui hopsanremote hopsanhdf5exporter HopsanGUI HopsanCLI UnitTests hopsanc hopsandcp componentLibraries.depends = HopsanCore +hopsandcp.depends = HopsanCore HopsanGenerator.depends = HopsanCore SymHop HopsanCLI.depends = HopsanCore HopsanGenerator hopsanhdf5exporter Ops -HopsanGUI.depends = HopsanCore hopsangeneratorgui hopsanhdf5exporter hopsanremote Ops +HopsanGUI.depends = hopsandcp HopsanCore hopsangeneratorgui hopsanhdf5exporter hopsanremote Ops hopsanc.depends = HopsanCore hopsanhdf5exporter.depends = HopsanCore hopsanremote.depends = HopsanCore UnitTests.depends = HopsanCore HopsanGenerator componentLibraries -hopsandcp.depends = HopsanCore diff --git a/dependencies/dcplib-patch.txt b/dependencies/dcplib-patch.txt new file mode 100644 index 0000000000..1ce35b6332 --- /dev/null +++ b/dependencies/dcplib-patch.txt @@ -0,0 +1,4 @@ +5c5 +< std::string ipToString(const uint32_t ip) { +--- +> inline std::string ipToString(const uint32_t ip) { diff --git a/dependencies/dependencies.xml b/dependencies/dependencies.xml index fd067d075d..95bc239bd8 100644 --- a/dependencies/dependencies.xml +++ b/dependencies/dependencies.xml @@ -89,7 +89,7 @@ - https://sourceforge.net/projects/asio/files/asio/1.12.1 (Stable)/asio-1.12.1.zip + https://master.dl.sourceforge.net/project/asio/asio/1.12.1%20%28Stable%29/asio-1.12.1.zip @@ -99,11 +99,23 @@ + + + https://github.com/madler/zlib/releases/download/v1.3.1/zlib131.zip + + + https://github.com/nih-at/libzip/archive/v1.7.3.zip + + + + https://github.com/modelica/DCPLib/archive/refs/tags/v0.2.zip + + diff --git a/dependencies/libzip.cmake b/dependencies/libzip.cmake new file mode 100644 index 0000000000..741d1fb160 --- /dev/null +++ b/dependencies/libzip.cmake @@ -0,0 +1,33 @@ +set(local_libzip_dir ${CMAKE_CURRENT_LIST_DIR}/libzip) +if(WIN32) + set(CMAKE_FIND_LIBRARY_PREFIXES lib) +endif(WIN32) +find_library(libzip NAMES ${CMAKE_FIND_LIBRARY_PREFIXES}zip ${CMAKE_FIND_LIBRARY_PREFIXES}zip${CMAKE_SHARED_LIBRARY_SUFFIX} ${CMAKE_STATIC_LIBRARY_PREFIX}zip${CMAKE_STATIC_LIBRARY_SUFFIX} PATHS ${local_libzip_dir}/lib NO_DEFAULT_PATH) + +if (libzip) + message(STATUS "Found local libzip") + add_library(libzip STATIC IMPORTED) + if (MSVC) + set_target_properties(libzip PROPERTIES + IMPORTED_LOCATION ${local_libzip_dir}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}zip${CMAKE_STATIC_LIBRARY_SUFFIX} + INTERFACE_INCLUDE_DIRECTORIES ${local_libzip_dir}/include) + elseif (MINGW) + set_target_properties(libzip PROPERTIES + IMPORTED_LOCATION ${local_libzip_dir}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}zip${CMAKE_SHARED_LIBRARY_SUFFIX}${CMAKE_STATIC_LIBRARY_SUFFIX} + INTERFACE_INCLUDE_DIRECTORIES ${local_libzip_dir}/include) + else() + set_target_properties(libzip PROPERTIES + IMPORTED_LOCATION ${local_libzip_dir}/lib/libzip.so + INTERFACE_INCLUDE_DIRECTORIES ${local_libzip_dir}/include) + endif() + +else() + message(STATUS "Looking for libzip in system") + find_package(libzip CONFIG) # Search in system + if (libzip_FOUND) + message(STATUS "Found libzip") + add_library(libzip STATIC IMPORTED) + else() + message(WARNING "Could not find libzip") + endif() +endif() diff --git a/dependencies/libzip.pri b/dependencies/libzip.pri new file mode 100644 index 0000000000..e8c4f8fee4 --- /dev/null +++ b/dependencies/libzip.pri @@ -0,0 +1,26 @@ +libzip_dir = $${PWD}/libzip +zlib_dir = $${PWD}/zlib +message(libzip_dir) +exists($${libzip_dir}) { + INCLUDEPATH *= $${libzip_dir}/include + LIBS *= -L$${libzip_dir}/bin -lzip + + macx { + # Not supported + } win32 { + src_file = $$quote($${libzip_dir}/bin/libzip.dll) + src_file_zlib = $$quote($${zlib_dir}/bin/libzlib.dll) + dst_dir = $$quote($${PWD}/../bin) + # Replace slashes in paths with backslashes for Windows + src_file ~= s,/,\\,g + src_file_zlib ~= s,/,\\,g + dst_dir ~= s,/,\\,g + + QMAKE_POST_LINK += $$QMAKE_COPY $${src_file} $${dst_dir} $$escape_expand(\\n\\t) + QMAKE_POST_LINK += $$QMAKE_COPY $${src_file_zlib} $${dst_dir} $$escape_expand(\\n\\t) + } else { + # Note! The RPATH is absolute and only meant for dev builds in the IDE, on release runtime paths should be stripped + unix:QMAKE_RPATHDIR *= $${libzip_dir/bin} + } +} + diff --git a/dependencies/setupAll.bat b/dependencies/setupAll.bat index baeaadfbd7..ef78d27e92 100644 --- a/dependencies/setupAll.bat +++ b/dependencies/setupAll.bat @@ -8,3 +8,6 @@ start /wait cmd /c setupZeroMQ.bat start /wait cmd /c setupKatex.bat start /wait cmd /c setupTclap.bat start /wait cmd /c setupHDF5.bat +start /wait cmd /c setupXerces.bat +start /wait cmd /c setupLibzip.bat +start /wait cmd /c setupDCPLib.bat diff --git a/dependencies/setupAll.sh b/dependencies/setupAll.sh index 7336fc38e4..60613a4c02 100755 --- a/dependencies/setupAll.sh +++ b/dependencies/setupAll.sh @@ -8,6 +8,6 @@ ./setupKatex.sh ./setupTclap.sh ./setupHDF5.sh -./setupAsio.sh ./setupXerces.sh ./setupLibzip.sh +./setupDCPLib.sh diff --git a/dependencies/setupAsio.sh b/dependencies/setupAsio.sh deleted file mode 100755 index 5cbe818dcb..0000000000 --- a/dependencies/setupAsio.sh +++ /dev/null @@ -1,27 +0,0 @@ -#!/bin/bash -# $Id$ - -# Shell script building HopsaGUI dependency Asio automatically - -basedir=`pwd` -name=asio -codedir=${basedir}/${name}-code -builddir=${basedir}/${name}-build -installdir=${basedir}/${name} - -# Download and verify -./download-dependencies.py ${name} - -# Copy code to build dir, not sure if out-of-source build is possible -mkdir -p $builddir -pushd $builddir -cp -a $codedir/* . - -# Generate makefiles -chmod u+x ./configure -./configure --prefix=$installdir --without-boost -cd include -make install - -popd -echo "setupAsio.sh done!" diff --git a/dependencies/setupDCPLib.bat b/dependencies/setupDCPLib.bat new file mode 100644 index 0000000000..dc777987ae --- /dev/null +++ b/dependencies/setupDCPLib.bat @@ -0,0 +1,29 @@ +@ECHO OFF +REM Bat script building libzip dependency automatically + +setlocal +set basedir=%~dp0 +set name=dcplib +set codedir=%basedir%\%name%-code +set builddir=%basedir%\%name%-build +set installdir=%basedir%\%name% + +set xercesdir=%basedir:\=/%xerces + +call setHopsanBuildPaths.bat + +"%git_path%\..\usr\bin\patch" dcplib-code/include/core/dcp/model/pdu/IpToStr.hpp dcplib-patch.txt + +mkdir %builddir% +cd %builddir% +cmake -Wno-dev -G %HOPSAN_BUILD_CMAKE_GENERATOR% -DLOGGING=ON -DASIO_ROOT="%basedir%\asio-code" -DXercesC_LIBRARY="%xercesdir%/bin/libxerces-c.dll" -DXercesC_INCLUDE_DIR="%xercesdir%/include" -DXercesC_VERSION="3.2.2" -DZIP_LIBRARY="%basedir%\libzip\bin\libzip.dll" -DZIP_INCLUDE_DIR="%basedir%\libzip\include" -DCMAKE_INSTALL_PREFIX="%installdir%" %codedir% +cmake --build . --parallel 8 +cmake --build . --target install + +cd %basedir% +echo. +echo setupDCPLib.bat done +if "%HOPSAN_BUILD_SCRIPT_NOPAUSE%" == "" ( + pause +) +endlocal diff --git a/dependencies/setupDCPLib.sh b/dependencies/setupDCPLib.sh new file mode 100755 index 0000000000..03a62e542c --- /dev/null +++ b/dependencies/setupDCPLib.sh @@ -0,0 +1,35 @@ +#!/bin/bash + +# Shell script building Hopsan dependency DCPLib + +basedir=$(pwd) + +name=dcplib +codedir=${basedir}/${name}-code +builddir=${basedir}/${name}-build +installdir=${basedir}/${name} +xercesdir=${basedir}/xerces + +# Download and verify +./download-dependencies.py ${name} + +#Patch code to fix bug +patch dcplib-code/include/core/dcp/model/pdu/IpToStr.hpp dcplib-patch.txt + +# Include general settings +source setHopsanBuildPaths.sh + +# Create build dir and enter it +mkdir -p $builddir +cd $builddir + +# Generate makefiles +cmake -Wno-dev -DLOGGING=ON -DASIO_ROOT="${basedir}/asio-code" -DXercesC_LIBRARY="${xercesdir}/bin/libxerces-c" -DXercesC_INCLUDE_DIR="${xercesdir}/include" -DXercesC_VERSION="3.2.2" -DZIP_LIBRARY="${basedir}/libzip/bin/libzip" -DZIP_INCLUDE_DIR="${basedir}/libzip/include" -DCMAKE_INSTALL_PREFIX="${installdir}" "${codedir}" + +# Build and install +cmake --build . --parallel 8 +cmake --build . --target install + +# Return to basedir +cd $basedir +echo "setupDCPLib.sh done!" diff --git a/dependencies/setupLibzip.bat b/dependencies/setupLibzip.bat new file mode 100644 index 0000000000..7a68c12611 --- /dev/null +++ b/dependencies/setupLibzip.bat @@ -0,0 +1,32 @@ +@ECHO OFF +REM Bat script building libzip dependency automatically + +setlocal +set basedir=%~dp0 +set name=libzip +set codedir=%basedir%\%name%-code +set builddir=%basedir%\%name%-build +set installdir=%basedir%\%name% + +set zlibdir=%basedir:\=/%/zlib +echo %zlibdir% + +call setHopsanBuildPaths.bat + +mkdir %builddir% +cd %builddir% +if "%HOPSAN_BUILD_COMPILER%" == "msvc" ( +cmake -Wno-dev -G %HOPSAN_BUILD_CMAKE_GENERATOR% -DZLIB_INCLUDE_DIR="%zlibdir%/include" -DZLIB_LIBRARY="%zlibdir%/lib/zlib.lib" -DCMAKE_INSTALL_PREFIX="%installdir%" %codedir% +) else ( +cmake -Wno-dev -G %HOPSAN_BUILD_CMAKE_GENERATOR% -DZLIB_INCLUDE_DIR="%zlibdir%/include" -DZLIB_LIBRARY="%zlibdir%/bin/libzlib.dll" -DCMAKE_INSTALL_PREFIX="%installdir%" %codedir% +) +cmake --build . --parallel 8 +cmake --build . --target install + +cd %basedir% +echo. +echo setupLibzip.bat done +if "%HOPSAN_BUILD_SCRIPT_NOPAUSE%" == "" ( + pause +) +endlocal diff --git a/dependencies/setupLibzip.sh b/dependencies/setupLibzip.sh index 2e7834c427..c58fce3521 100755 --- a/dependencies/setupLibzip.sh +++ b/dependencies/setupLibzip.sh @@ -20,11 +20,11 @@ mkdir -p $builddir cd $builddir # Generate makefiles -cmake -Wno-dev -DCMAKE_INSTALL_PREFIX=$installdir ${codedir} +cmake -Wno-dev -DCMAKE_INSTALL_PREFIX=${installdir} ${codedir} # Build and install -make -j16 -make install +cmake --build . --parallel 8 +cmake --build . --target install # Return to basedir cd $basedir diff --git a/dependencies/setupXerces.bat b/dependencies/setupXerces.bat new file mode 100644 index 0000000000..7759e62c62 --- /dev/null +++ b/dependencies/setupXerces.bat @@ -0,0 +1,28 @@ +@ECHO OFF +REM Bat script building libzip dependency automatically + +setlocal +set basedir=%~dp0 +set name=xerces +set codedir=%basedir%\%name%-code +set builddir=%basedir%\%name%-build +set installdir=%basedir%\%name% + +set zlibdir=%basedir:\=/%/zlib +echo %zlibdir% + +call setHopsanBuildPaths.bat + +mkdir %builddir% +cd %builddir% +cmake -Wno-dev -G %HOPSAN_BUILD_CMAKE_GENERATOR% -DCMAKE_INSTALL_PREFIX="%installdir%" %codedir% +cmake --build . --parallel 8 +cmake --build . --target install + +cd %basedir% +echo. +echo setupXerces.bat done +if "%HOPSAN_BUILD_SCRIPT_NOPAUSE%" == "" ( + pause +) +endlocal diff --git a/dependencies/setupZlib.bat b/dependencies/setupZlib.bat new file mode 100644 index 0000000000..b932efc89c --- /dev/null +++ b/dependencies/setupZlib.bat @@ -0,0 +1,25 @@ +@ECHO OFF +REM Bat script building libzip dependency automatically + +setlocal +set basedir=%~dp0 +set name=zlib +set codedir=%basedir%\%name%-code +set builddir=%basedir%\%name%-build +set installdir=%basedir%\%name% + +call setHopsanBuildPaths.bat + +mkdir %builddir% +cd %builddir% +cmake -Wno-dev -G %HOPSAN_BUILD_CMAKE_GENERATOR% -DCMAKE_INSTALL_PREFIX="%installdir%" %codedir% +cmake --build . --config Release --parallel 8 +cmake --build . --config Release --target install + +cd %basedir% +echo. +echo setupZlib.bat done +if "%HOPSAN_BUILD_SCRIPT_NOPAUSE%" == "" ( + pause +) +endlocal diff --git a/dependencies/xerces.cmake b/dependencies/xerces.cmake new file mode 100644 index 0000000000..e7ca6f384f --- /dev/null +++ b/dependencies/xerces.cmake @@ -0,0 +1,40 @@ +if (NOT TARGET xercesc) + set(local_xerces_dir ${CMAKE_CURRENT_LIST_DIR}/xerces) + set(CMAKE_FIND_LIBRARY_PREFIXES lib) + find_library(xercesc NAMES xerces-c ${CMAKE_STATIC_LIBRARY_PREFIX}xerces-c_3D${CMAKE_STATIC_LIBRARY_SUFFIX} PATHS ${local_xerces_dir}/lib) + + #set(CMAKE_FIND_DEBUG_MODE TRUE) + #find_package(xercesc CONFIG PATHS ${local_xerces_dir} NO_DEFAULT_PATH REQUIRED) # Search for local version + #set(CMAKE_FIND_DEBUG_MODE FALSE) + + if (xercesc) + message(STATUS "Found local xerces") + #add_library(xercesc INTERFACE) + + add_library(xercesc STATIC IMPORTED) + + if (MINGW) + set_target_properties(xercesc PROPERTIES + IMPORTED_LOCATION ${local_xerces_dir}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}xerces-c${CMAKE_SHARED_LIBRARY_SUFFIX}${CMAKE_STATIC_LIBRARY_SUFFIX} + INTERFACE_INCLUDE_DIRECTORIES ${local_xerces_dir}/include) + elseif(MSVC) + set_target_properties(xercesc PROPERTIES + IMPORTED_LOCATION ${local_xerces_dir}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}xerces-c_3D${CMAKE_STATIC_LIBRARY_SUFFIX} + INTERFACE_INCLUDE_DIRECTORIES ${local_xerces_dir}/include) + else() + set_target_properties(xercesc PROPERTIES + IMPORTED_LOCATION ${local_xerces_dir}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}xerces-c${CMAKE_SHARED_LIBRARY_SUFFIX} + INTERFACE_INCLUDE_DIRECTORIES ${local_xerces_dir}/include) + endif() + + else() + message(STATUS "Looking for xerces in system") + find_package(xercesc CONFIG) # Search in system + if (xercesc_FOUND) + message(STATUS " Found xerces") + add_library(xercesc INTERFACE) + else() + message(WARNING "Could not find xerces") + endif() + endif() +endif() diff --git a/dependencies/xerces.pri b/dependencies/xerces.pri new file mode 100644 index 0000000000..fc5e2b6f5e --- /dev/null +++ b/dependencies/xerces.pri @@ -0,0 +1,25 @@ +xerces_dir = $${PWD}/xerces + +exists($${xerces_dir}) { + INCLUDEPATH *= $${xerces_dir}/include + LIBS *= -L$${xerces_dir}/bin -lxerces-c + + macx { + # Not supported + } win32 { + src_file = $$quote($${xerces_dir}/bin/libxerces-c.dll) + dst_dir = $$quote($${PWD}/../bin) + # Replace slashes in paths with backslashes for Windows + src_file ~= s,/,\\,g + dst_dir ~= s,/,\\,g + + message($${src_file}) + message($${dst_dir}) + + QMAKE_POST_LINK += $$QMAKE_COPY $${src_file} $${dst_dir} $$escape_expand(\\n\\t) + } else { + # Note! The RPATH is absolute and only meant for dev builds in the IDE, on release runtime paths should be stripped + unix:QMAKE_RPATHDIR *= $${xerces_dir/bin} + } +} + diff --git a/hopsandcp/CMakeLists.txt b/hopsandcp/CMakeLists.txt new file mode 100644 index 0000000000..81fed7ae70 --- /dev/null +++ b/hopsandcp/CMakeLists.txt @@ -0,0 +1,47 @@ +cmake_minimum_required(VERSION 3.1) +project(hopsandcp) +set(CMAKE_CXX_STANDARD 14) +set(CMAKE_DEBUG_POSTFIX _d) +if(WIN32) + set(CMAKE_SHARED_LIBRARY_PREFIX "") +endif() + +set(CMAKE_AUTOMOC ON) + +# include(${CMAKE_CURRENT_LIST_DIR}/../dependencies/xerces.cmake) +# include(${CMAKE_CURRENT_LIST_DIR}/../dependencies/libzip.cmake) +# include(${CMAKE_CURRENT_LIST_DIR}/../dependencies/zlib.cmake) +include(${CMAKE_CURRENT_LIST_DIR}/../dependencies/libzip.cmake) +#include(${CMAKE_CURRENT_LIST_DIR}/../dependencies/zlib.cmake) + +# Find source code +file(GLOB_RECURSE srcfiles src/*.cpp) +file(GLOB_RECURSE headerfiles include/*.h include/*.hpp) + +# Create library target and add source code files +add_library(hopsandcp STATIC ${srcfiles} ${headerfiles}) + +# Set include directories +target_include_directories(hopsandcp PUBLIC + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $) + +if(WIN32) + target_link_libraries(hopsandcp hopsancore libzip -lws2_32) +else() + target_link_libraries(hopsandcp hopsancore libzip) +endif() + +target_compile_definitions(hopsandcp PUBLIC LOGGING=ON) + diff --git a/hopsandcp/dependencies/DCPLib b/hopsandcp/dependencies/DCPLib deleted file mode 160000 index 402264a2f3..0000000000 --- a/hopsandcp/dependencies/DCPLib +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 402264a2f349e5eb4c6ce6fbcf0d8566ca27546e diff --git a/hopsandcp/hopsandcp.pro b/hopsandcp/hopsandcp.pro index b04ec7fe14..d2d9aac2b4 100644 --- a/hopsandcp/hopsandcp.pro +++ b/hopsandcp/hopsandcp.pro @@ -28,41 +28,30 @@ LIBS *= -L$${PWD}/../bin -lhopsancore$${DEBUG_EXT} DEFINES *= HOPSANCORE_DLLIMPORT #-------------------------------------------------- -#-------------------------------------------------- -# Add the include and lib path to xerces -INCLUDEPATH *= $${PWD}/../dependencies/xerces/include/ -LIBS *= -L$${PWD}/../dependencies/xerces/lib/ -LIBS *= -lxerces-c -#-------------------------------------------------- - #-------------------------------------------------- # Add the include path to xerces -INCLUDEPATH *= $${PWD}/../dependencies/asio/include/ +INCLUDEPATH *= $${PWD}/../dependencies/asio-code/include/ #-------------------------------------------------- #-------------------------------------------------- # Add the include and lib path to libzip -INCLUDEPATH *= $${PWD}/../dependencies/libzip/include/ -LIBS *= -L$${PWD}/../dependencies/libzip/lib/ -LIBS *= -lzip +include($${PWD}/../dependencies/libzip.pri) #-------------------------------------------------- #-------------------------------------------------- # Add the include and lib path to xerces -INCLUDEPATH *= $${PWD}/../dependencies/xerces/include/ -LIBS *= -L$${PWD}/../dependencies/xerces/lib/ -LIBS *= -lxerces-c +include($${PWD}/../dependencies/xerces.pri) #-------------------------------------------------- #-------------------------------------------------- # Add the include path to DCPLib -INCLUDEPATH *= $${PWD}/dependencies/DCPLib/include/bluetooth -INCLUDEPATH *= $${PWD}/dependencies/DCPLib/include/core -INCLUDEPATH *= $${PWD}/dependencies/DCPLib/include/ethernet -INCLUDEPATH *= $${PWD}/dependencies/DCPLib/include/master -INCLUDEPATH *= $${PWD}/dependencies/DCPLib/include/slave -INCLUDEPATH *= $${PWD}/dependencies/DCPLib/include/xml -INCLUDEPATH *= $${PWD}/dependencies/DCPLib/include/zip +INCLUDEPATH *= $${PWD}/../dependencies/dcplib-code/include/bluetooth +INCLUDEPATH *= $${PWD}/../dependencies/dcplib-code/include/core +INCLUDEPATH *= $${PWD}/../dependencies/dcplib-code/include/ethernet +INCLUDEPATH *= $${PWD}/../dependencies/dcplib-code/include/master +INCLUDEPATH *= $${PWD}/../dependencies/dcplib-code/include/slave +INCLUDEPATH *= $${PWD}/../dependencies/dcplib-code/include/xml +INCLUDEPATH *= $${PWD}/../dependencies/dcplib-code/include/zip #-------------------------------------------------- #-------------------------------------------------------- @@ -92,6 +81,8 @@ SOURCES = \ src/utilities.cpp HEADERS += \ + ../dependencies/dcplib-code/include/master/dcp/logic/DcpManagerMaster.hpp \ + ../dependencies/dcplib-code/include/slave/dcp/logic/DcpManagerSlave.hpp \ include/dcpmaster.h \ include/dcpserver.h \ include/hopsandcp_win32dll.h \ diff --git a/hopsandcp/src/dcpmaster.cpp b/hopsandcp/src/dcpmaster.cpp index 343dc11d89..45d96ddbda 100644 --- a/hopsandcp/src/dcpmaster.cpp +++ b/hopsandcp/src/dcpmaster.cpp @@ -2,7 +2,7 @@ #include "dcp/log/OstreamLog.hpp" #include "dcp/helper/LogHelper.hpp" -#include "dcp/model/pdu/DcpPduFactory.hpp" +//#include "dcp/model/pdu/DcpPduFactory.hpp" #include "dcp/zip/DcpSlaveReader.hpp" #include "dcp/driver/ethernet/udp/UdpDriver.hpp" #include "dcp/logic/DcpManagerMaster.hpp" @@ -10,10 +10,12 @@ #include #include #include -#include +//#include #include #include +#include "ComponentUtilities/num2string.hpp" + DcpMaster::DcpMaster(hopsan::ComponentSystem *pSystem, const std::string host, int port, double comStep, double startTime, double stopTime, bool realTime) : mpSystem(pSystem), mRealTime(realTime), mComStep(comStep), mStartTime(startTime), mStopTime(stopTime) { diff --git a/hopsandcp/src/dcpserver.cpp b/hopsandcp/src/dcpserver.cpp index be502faf4f..2ea0de29fd 100644 --- a/hopsandcp/src/dcpserver.cpp +++ b/hopsandcp/src/dcpserver.cpp @@ -1,4 +1,5 @@ #include "dcpserver.h" +#include "ComponentSystem.h" #include "utilities.h" #include @@ -8,7 +9,7 @@ #include #include -#include "HopsanEssentials.h" +//#include "HopsanEssentials.h" #include "HopsanCoreMacros.h" #include "HopsanCoreVersion.h" From 7484302406ac5a317eba156a68aff0ad3f25931b Mon Sep 17 00:00:00 2001 From: Robert Braun Date: Thu, 24 Oct 2024 14:16:36 +0200 Subject: [PATCH 30/34] Only download zlib on Windows, and add it to setupAll.bat --- dependencies/dependencies.xml | 2 +- dependencies/setupAll.bat | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/dependencies/dependencies.xml b/dependencies/dependencies.xml index 95bc239bd8..0bfa4a5180 100644 --- a/dependencies/dependencies.xml +++ b/dependencies/dependencies.xml @@ -100,7 +100,7 @@ - + https://github.com/madler/zlib/releases/download/v1.3.1/zlib131.zip diff --git a/dependencies/setupAll.bat b/dependencies/setupAll.bat index ef78d27e92..58ff64ce84 100644 --- a/dependencies/setupAll.bat +++ b/dependencies/setupAll.bat @@ -9,5 +9,6 @@ start /wait cmd /c setupKatex.bat start /wait cmd /c setupTclap.bat start /wait cmd /c setupHDF5.bat start /wait cmd /c setupXerces.bat +start /wait cmd /c setupZlib.bat start /wait cmd /c setupLibzip.bat start /wait cmd /c setupDCPLib.bat From e772b36a656675dc125aaf56dc39e8852e235b6d Mon Sep 17 00:00:00 2001 From: Robert Braun Date: Thu, 24 Oct 2024 15:35:38 +0200 Subject: [PATCH 31/34] Fix crash for DCPs without parameters --- HopsanCore/include/Components/DcpComponent.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HopsanCore/include/Components/DcpComponent.hpp b/HopsanCore/include/Components/DcpComponent.hpp index 1142b596b9..ee4d636918 100644 --- a/HopsanCore/include/Components/DcpComponent.hpp +++ b/HopsanCore/include/Components/DcpComponent.hpp @@ -91,7 +91,7 @@ namespace hopsan { mOutputs.clear(); mParameters.clear(); - HVector splitVariables = mVariables.split(';', HString::SkipEmptyParts); + HVector splitVariables = mVariables.split(';'); HVector splitInputs = splitVariables[0].split(',', HString::SkipEmptyParts); HVector splitOutputs = splitVariables[1].split(',', HString::SkipEmptyParts); HVector splitParameters = splitVariables[2].split(',', HString::SkipEmptyParts); From a437cb0abbe5bae361ea661753f348b6e62b5729 Mon Sep 17 00:00:00 2001 From: Robert Braun Date: Thu, 24 Oct 2024 15:41:16 +0200 Subject: [PATCH 32/34] Add mp prefix to member pointers --- hopsandcp/include/dcpmaster.h | 4 +-- hopsandcp/include/dcpserver.h | 4 +-- hopsandcp/src/dcpmaster.cpp | 62 +++++++++++++++++------------------ hopsandcp/src/dcpserver.cpp | 12 +++---- 4 files changed, 41 insertions(+), 41 deletions(-) diff --git a/hopsandcp/include/dcpmaster.h b/hopsandcp/include/dcpmaster.h index b0842e068c..9f9e65e754 100644 --- a/hopsandcp/include/dcpmaster.h +++ b/hopsandcp/include/dcpmaster.h @@ -63,11 +63,11 @@ HOPSANDCP_DLLAPI class DcpMaster double mStartTime; double mStopTime; - UdpDriver *driver; + UdpDriver *mpDriver; OstreamLog *mpStdLog; - DcpManagerMaster *manager; + DcpManagerMaster *mpManager; std::map numOfCmd; std::map receivedAcks; diff --git a/hopsandcp/include/dcpserver.h b/hopsandcp/include/dcpserver.h index d856d5af13..cbd4170871 100644 --- a/hopsandcp/include/dcpserver.h +++ b/hopsandcp/include/dcpserver.h @@ -38,8 +38,8 @@ HOPSANDCP_DLLAPI class DcpServer int mPort = 8080; size_t mNumLogSamples = 0; DcpManagerSlave *mManager; - OstreamLog *stdLog; - UdpDriver* udpDriver; + OstreamLog *mpStdLog; + UdpDriver* mpDriver; double mSimulationTime=0; void configure(); diff --git a/hopsandcp/src/dcpmaster.cpp b/hopsandcp/src/dcpmaster.cpp index 45d96ddbda..6c510708ba 100644 --- a/hopsandcp/src/dcpmaster.cpp +++ b/hopsandcp/src/dcpmaster.cpp @@ -23,27 +23,27 @@ DcpMaster::DcpMaster(hopsan::ComponentSystem *pSystem, const std::string host, i OstreamLog stdLog(std::cout); - driver = new UdpDriver(host, port_t(port)); + mpDriver = new UdpDriver(host, port_t(port)); - manager = new DcpManagerMaster(driver->getDcpDriver()); + mpManager = new DcpManagerMaster(mpDriver->getDcpDriver()); - manager->setAckReceivedListener( + mpManager->setAckReceivedListener( std::bind(&DcpMaster::receiveAck, this, std::placeholders::_1, std::placeholders::_2)); - manager->setNAckReceivedListener( + mpManager->setNAckReceivedListener( std::bind(&DcpMaster::receiveNAck, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); - manager->setStateChangedNotificationReceivedListener( + mpManager->setStateChangedNotificationReceivedListener( std::bind(&DcpMaster::receiveStateChangedNotification, this, std::placeholders::_1, std::placeholders::_2)); - manager->setDataReceivedListener( + mpManager->setDataReceivedListener( std::bind(&DcpMaster::dataReceived, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); - manager->addLogListener(std::bind(&OstreamLog::logOstream, stdLog, std::placeholders::_1)); - manager->setGenerateLogString(true); + mpManager->addLogListener(std::bind(&OstreamLog::logOstream, stdLog, std::placeholders::_1)); + mpManager->setGenerateLogString(true); } DcpMaster::~DcpMaster() { - delete driver; - delete manager; + delete mpDriver; + delete mpManager; } void DcpMaster::addServer(string filepath) @@ -53,7 +53,7 @@ void DcpMaster::addServer(string filepath) uint8_t *netInfo = new uint8_t[6]; *((uint16_t *) netInfo) = *serverDescriptions.back()->TransportProtocols.UDP_IPv4->Control->port; *((uint32_t *) (netInfo + 2)) = asio::ip::address_v4::from_string(*serverDescriptions.back()->TransportProtocols.UDP_IPv4->Control->host).to_ulong(); - driver->getDcpDriver().setSlaveNetworkInformation(id, netInfo); + mpDriver->getDcpDriver().setSlaveNetworkInformation(id, netInfo); delete[] netInfo; } @@ -69,7 +69,7 @@ void DcpMaster::addConnection(size_t fromServer, size_t fromVr, std::vectorSTC_register(u_char(i+1), DcpState::ALIVE, convertToUUID(serverDescriptions[i]->uuid), mode, 1, 0); + mpManager->STC_register(u_char(i+1), DcpState::ALIVE, convertToUUID(serverDescriptions[i]->uuid), mode, 1, 0); } b.join(); } @@ -89,7 +89,7 @@ void DcpMaster::initialize() { return; } for(size_t i=0; iSTC_initialize(u_char(i), DcpState::CONFIGURED); + mpManager->STC_initialize(u_char(i), DcpState::CONFIGURED); } intializationRuns++; } @@ -105,25 +105,25 @@ void DcpMaster::configuration() { receivedAcks[dcpId_t(i)] = 0; numOfCmd[dcpId_t(i)] = 0; - manager->CFG_time_res(uint8_t(i), 1, uint32_t(std::floor(1.0/mComStep))); + mpManager->CFG_time_res(uint8_t(i), 1, uint32_t(std::floor(1.0/mComStep))); numOfCmd[dcpId_t(i)]++; } for(size_t i=0; iCFG_scope(fromServerId, dataId, DcpScope::Initialization_Run_NonRealTime); - manager->CFG_output(fromServerId, dataId, 0, connections[i].fromVr); - manager->CFG_steps(fromServerId, dataId, 1); + mpManager->CFG_scope(fromServerId, dataId, DcpScope::Initialization_Run_NonRealTime); + mpManager->CFG_output(fromServerId, dataId, 0, connections[i].fromVr); + mpManager->CFG_steps(fromServerId, dataId, 1); numOfCmd[fromServerId] += 4; for(size_t j=0; jCFG_scope(toServerId, dataId, DcpScope::Initialization_Run_NonRealTime); - manager->CFG_input(toServerId, dataId, 0, connections[i].toVrs[j], DcpDataType::float64); - manager->CFG_steps(toServerId, dataId, 1); - manager->CFG_source_network_information_UDP(toServerId, dataId, asio::ip::address_v4::from_string(*serverDescriptions[toServerId-1]->TransportProtocols.UDP_IPv4->Control->host).to_uint(), *serverDescriptions[toServerId-1]->TransportProtocols.UDP_IPv4->Control->port+1); - manager->CFG_target_network_information_UDP(fromServerId, dataId, asio::ip::address_v4::from_string(*serverDescriptions[toServerId-1]->TransportProtocols.UDP_IPv4->Control->host).to_uint(), *serverDescriptions[toServerId-1]->TransportProtocols.UDP_IPv4->Control->port); + mpManager->CFG_scope(toServerId, dataId, DcpScope::Initialization_Run_NonRealTime); + mpManager->CFG_input(toServerId, dataId, 0, connections[i].toVrs[j], DcpDataType::float64); + mpManager->CFG_steps(toServerId, dataId, 1); + mpManager->CFG_source_network_information_UDP(toServerId, dataId, asio::ip::address_v4::from_string(*serverDescriptions[toServerId-1]->TransportProtocols.UDP_IPv4->Control->host).to_uint(), *serverDescriptions[toServerId-1]->TransportProtocols.UDP_IPv4->Control->port+1); + mpManager->CFG_target_network_information_UDP(fromServerId, dataId, asio::ip::address_v4::from_string(*serverDescriptions[toServerId-1]->TransportProtocols.UDP_IPv4->Control->host).to_uint(), *serverDescriptions[toServerId-1]->TransportProtocols.UDP_IPv4->Control->port); numOfCmd[toServerId] += 4; } } @@ -135,13 +135,13 @@ void DcpMaster::configure() { return; } for(size_t i=0; iSTC_configure(u_char(i+1), DcpState::PREPARED); + mpManager->STC_configure(u_char(i+1), DcpState::PREPARED); } } void DcpMaster::run(DcpState currentState, uint8_t sender) { std::time_t now = std::time(nullptr); - manager->STC_run(sender, currentState, now + 2); + mpManager->STC_run(sender, currentState, now + 2); } void DcpMaster::doStep() { @@ -151,7 +151,7 @@ void DcpMaster::doStep() { } serversWaitingForStep = 0; for(size_t i=0; iSTC_do_step(u_char(i+1),DcpState::RUNNING,1); + mpManager->STC_do_step(u_char(i+1),DcpState::RUNNING,1); } (*mpSystem->getTimePtr()) += mComStep; @@ -161,7 +161,7 @@ void DcpMaster::stop() { std::chrono::seconds dura(1); std::this_thread::sleep_for(dura); for(size_t i=0; iSTC_stop(u_char(i+1), DcpState::RUNNING); + mpManager->STC_stop(u_char(i+1), DcpState::RUNNING); } } @@ -171,19 +171,19 @@ void DcpMaster::deregister() { return; } for(size_t i=0; iSTC_deregister(u_char(i+1), DcpState::STOPPED); + mpManager->STC_deregister(u_char(i+1), DcpState::STOPPED); } } void DcpMaster::sendOutputs(DcpState currentState, uint8_t sender) { - manager->STC_send_outputs(sender, currentState); + mpManager->STC_send_outputs(sender, currentState); } void DcpMaster::receiveAck(uint8_t sender, uint16_t pduSeqId) { (void)pduSeqId; receivedAcks[sender]++; if (receivedAcks[sender] == numOfCmd[sender]) { - manager->STC_prepare(sender, DcpState::CONFIGURATION); + mpManager->STC_prepare(sender, DcpState::CONFIGURATION); } } @@ -261,7 +261,7 @@ void DcpMaster::receiveStateChangedNotification(uint8_t sender, return; } std::cout << "Stopping master manager\n"; - manager->stop(); + mpManager->stop(); break; case DcpState::ALIVE: diff --git a/hopsandcp/src/dcpserver.cpp b/hopsandcp/src/dcpserver.cpp index 2ea0de29fd..478545e34c 100644 --- a/hopsandcp/src/dcpserver.cpp +++ b/hopsandcp/src/dcpserver.cpp @@ -55,11 +55,11 @@ DcpServer::DcpServer(ComponentSystem *pSystem, const std::string host, int port, std::cout << "\n"; //Create UDP driver - udpDriver = new UdpDriver(host, uint16_t(port)); + mpDriver = new UdpDriver(host, uint16_t(port)); //Create server DCP manager mpServerDescription = createServerDescription(); - mManager = new DcpManagerSlave(*mpServerDescription, udpDriver->getDcpDriver()); + mManager = new DcpManagerSlave(*mpServerDescription, mpDriver->getDcpDriver()); mManager->setInitializeCallback( std::bind(&DcpServer::initialize, this)); mManager->setConfigureCallback( @@ -79,9 +79,9 @@ DcpServer::DcpServer(ComponentSystem *pSystem, const std::string host, int port, std::bind(&DcpServer::stop, this)); //Display log messages on console - stdLog = new OstreamLog(std::cout); + mpStdLog = new OstreamLog(std::cout); mManager->addLogListener( - std::bind(&OstreamLog::logOstream, *stdLog, std::placeholders::_1)); + std::bind(&OstreamLog::logOstream, *mpStdLog, std::placeholders::_1)); mManager->setGenerateLogString(true); } @@ -209,6 +209,6 @@ void DcpServer::setTimeRes(const uint32_t numerator, const uint32_t denominator) void DcpServer::stop() { //dynamic_cast(mManager)->stop(); - udpDriver->getDcpDriver().stopReceiving(); - udpDriver->getDcpDriver().disconnect(); + mpDriver->getDcpDriver().stopReceiving(); + mpDriver->getDcpDriver().disconnect(); } From 6f8bcf25aa1440737d9f0e5ab579d877e2bc482b Mon Sep 17 00:00:00 2001 From: Robert Braun Date: Thu, 24 Oct 2024 15:43:49 +0200 Subject: [PATCH 33/34] Add const prefix to string parameter --- hopsandcp/include/dcpmaster.h | 2 +- hopsandcp/src/dcpmaster.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/hopsandcp/include/dcpmaster.h b/hopsandcp/include/dcpmaster.h index 9f9e65e754..799c23b5a6 100644 --- a/hopsandcp/include/dcpmaster.h +++ b/hopsandcp/include/dcpmaster.h @@ -30,7 +30,7 @@ HOPSANDCP_DLLAPI class DcpMaster DcpMaster(hopsan::ComponentSystem *pSystem, const string host, int port, double comStep=0.001, double startTime=0, double stopTime=10, bool realTime=false); ~DcpMaster(); - void addServer(string filepath); + void addServer(const string filepath); void addConnection(size_t fromId, size_t fromVr, std::vector toIds, std::vector toVrs); void start(); diff --git a/hopsandcp/src/dcpmaster.cpp b/hopsandcp/src/dcpmaster.cpp index 6c510708ba..95728e233a 100644 --- a/hopsandcp/src/dcpmaster.cpp +++ b/hopsandcp/src/dcpmaster.cpp @@ -46,7 +46,7 @@ DcpMaster::~DcpMaster() { delete mpManager; } -void DcpMaster::addServer(string filepath) +void DcpMaster::addServer(const string filepath) { serverDescriptions.push_back(new SlaveDescription_t(*getSlaveDescriptionFromDcpFile(1,0,filepath.c_str()))); u_char id = u_char(serverDescriptions.size()); From 3e73df03b4a483eb419d6a8d85da7b758e860900 Mon Sep 17 00:00:00 2001 From: Robert Braun Date: Thu, 24 Oct 2024 16:00:07 +0200 Subject: [PATCH 34/34] Use quotes for includes and remove unused includes --- hopsandcp/src/dcpserver.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/hopsandcp/src/dcpserver.cpp b/hopsandcp/src/dcpserver.cpp index 478545e34c..c5c6b95293 100644 --- a/hopsandcp/src/dcpserver.cpp +++ b/hopsandcp/src/dcpserver.cpp @@ -2,12 +2,10 @@ #include "ComponentSystem.h" #include "utilities.h" -#include -#include -#include -#include -#include -#include +#include "dcp/log/OstreamLog.hpp" +#include "dcp/logic/DcpManagerSlave.hpp" +#include "dcp/zip/DcpSlaveWriter.hpp" +#include "dcp/driver/ethernet/udp/UdpDriver.hpp" //#include "HopsanEssentials.h" #include "HopsanCoreMacros.h"