diff --git a/Demos/CMakeLists.txt b/Demos/CMakeLists.txt index 6623689b0..7b7184256 100755 --- a/Demos/CMakeLists.txt +++ b/Demos/CMakeLists.txt @@ -82,8 +82,6 @@ endif() set(make_silkit_demo_caller_dir ${CMAKE_CURRENT_LIST_DIR} CACHE INTERNAL "") -set(demo_list "") - add_custom_target(Demos COMMENT "Build all available Demos") set_property(TARGET Demos PROPERTY FOLDER "Demos") @@ -99,6 +97,10 @@ endif() set(SILKIT_DEMO_DIR ${CMAKE_CURRENT_SOURCE_DIR}) +####################################################################################################################### +# Demo creation macros +####################################################################################################################### + macro(make_silkit_demo executableName demoSourceFile) add_executable(${executableName} @@ -127,7 +129,6 @@ macro(make_silkit_demo executableName demoSourceFile) SilKit::SilKit Threads::Threads ) - target_include_directories(${executableName} PRIVATE ${SILKIT_DEMO_DIR}/include) if(MSVC) target_compile_options(${executableName} PRIVATE /wd4996) endif() @@ -136,11 +137,16 @@ macro(make_silkit_demo executableName demoSourceFile) endmacro() +macro(make_silkit_communication_demo executableName demoSourceFile) + + make_silkit_demo(${executableName} ${demoSourceFile}) + target_include_directories(${executableName} PRIVATE ${SILKIT_DEMO_DIR}/communication/include) + +endmacro() + ####################################################################################################################### # Add the actual demo projects ####################################################################################################################### -# C++ Demos -set_property(GLOBAL PROPERTY demo_list_property "") add_subdirectory(communication/Can) add_subdirectory(communication/Ethernet) @@ -148,9 +154,12 @@ add_subdirectory(communication/Flexray) add_subdirectory(communication/Lin) add_subdirectory(communication/PubSub) add_subdirectory(communication/Rpc) + add_subdirectory(tools/Benchmark) + add_subdirectory(api/SimpleCan) add_subdirectory(api/NetworkSimulator) +add_subdirectory(api/Orchestration) ####################################################################################################################### # VisualStudio specific setup diff --git a/Demos/api/Orchestration/Autonomous.cpp b/Demos/api/Orchestration/Autonomous.cpp new file mode 100644 index 000000000..2261425fb --- /dev/null +++ b/Demos/api/Orchestration/Autonomous.cpp @@ -0,0 +1,81 @@ +// SPDX-FileCopyrightText: 2024 Vector Informatik GmbH +// +// SPDX-License-Identifier: MIT + +#include + +#include "silkit/SilKit.hpp" + +using namespace std::chrono_literals; + +int main(int argc, char** argv) +{ + if (argc != 2) + { + std::cerr << "Wrong number of arguments! Start demo with: " << argv[0] << " " << std::endl; + return -1; + } + std::string participantName(argv[1]); + + try + { + // Setup participant, lifecycle, time synchronization and logging + const std::string registryUri = "silkit://localhost:8500"; + const std::string configString = R"({"Logging":{"Sinks":[{"Type":"Stdout","Level":"Info"}]}})"; + auto participantConfiguration = SilKit::Config::ParticipantConfigurationFromString(configString); + + auto participant = SilKit::CreateParticipant(participantConfiguration, participantName, registryUri); + auto logger = participant->GetLogger(); + + auto* lifecycleService = + participant->CreateLifecycleService({SilKit::Services::Orchestration::OperationMode::Autonomous}); + + // Start the worker thread and wait for the go from the system monitor + auto unleashWorkerThreadPromise = std::promise(); + auto unleashWorkerThreadFuture = unleashWorkerThreadPromise.get_future(); + auto systemMonitor = participant->CreateSystemMonitor(); + systemMonitor->AddParticipantStatusHandler( + [&unleashWorkerThreadPromise, participantName, + logger](const SilKit::Services::Orchestration::ParticipantStatus& participantStatus) { + if (participantStatus.participantName == participantName && participantStatus.state + == SilKit::Services::Orchestration::ParticipantState::Running) + { + logger->Info("My state is now 'Running'."); + unleashWorkerThreadPromise.set_value(); + } + }); + + // Start the worker thread and wait for the go from the system monitor + auto workerThread = std::thread([&unleashWorkerThreadFuture, lifecycleService, logger]() { + + unleashWorkerThreadFuture.wait(); + for (int i = 0; i < 10; ++i) + { + std::this_thread::sleep_for(1s); + logger->Info("Simulation stop in " + std::to_string(10-i)); + }; + + logger->Info("Stopping just me."); + lifecycleService->Stop("Stopping just me"); + }); + + // Start and wait until lifecycleService->Stop + logger->Info("Start the participant lifecycle."); + auto finalStateFuture = lifecycleService->StartLifecycle(); + finalStateFuture.get(); + + // Clean up the worker thread + if (workerThread.joinable()) + { + workerThread.join(); + } + + } + catch (const std::exception& error) + { + std::cerr << "Something went wrong: " << error.what() << std::endl; + return -3; + } + + return 0; +} diff --git a/Demos/api/Orchestration/CMakeLists.txt b/Demos/api/Orchestration/CMakeLists.txt new file mode 100644 index 000000000..8930fe76f --- /dev/null +++ b/Demos/api/Orchestration/CMakeLists.txt @@ -0,0 +1,9 @@ +# SPDX-FileCopyrightText: 2024 Vector Informatik GmbH +# +# SPDX-License-Identifier: MIT + +make_silkit_demo(SilKitDemoAutonomous Autonomous.cpp) +make_silkit_demo(SilKitDemoCoordinated Coordinated.cpp) +make_silkit_demo(SilKitDemoSimStep SimStep.cpp) +make_silkit_demo(SilKitDemoSimStepAsync SimStepAsync.cpp) + diff --git a/Demos/api/Orchestration/Coordinated.cpp b/Demos/api/Orchestration/Coordinated.cpp new file mode 100644 index 000000000..c37e40218 --- /dev/null +++ b/Demos/api/Orchestration/Coordinated.cpp @@ -0,0 +1,81 @@ +// SPDX-FileCopyrightText: 2024 Vector Informatik GmbH +// +// SPDX-License-Identifier: MIT + +#include + +#include "silkit/SilKit.hpp" + +using namespace std::chrono_literals; + +int main(int argc, char** argv) +{ + if (argc != 2) + { + std::cerr << "Wrong number of arguments! Start demo with: " << argv[0] << " " << std::endl; + return -1; + } + std::string participantName(argv[1]); + + try + { + // Setup participant, lifecycle, time synchronization and logging + const std::string registryUri = "silkit://localhost:8500"; + const std::string configString = R"({"Logging":{"Sinks":[{"Type":"Stdout","Level":"Info"}]}})"; + auto participantConfiguration = SilKit::Config::ParticipantConfigurationFromString(configString); + + auto participant = SilKit::CreateParticipant(participantConfiguration, participantName, registryUri); + auto logger = participant->GetLogger(); + + auto* lifecycleService = + participant->CreateLifecycleService({SilKit::Services::Orchestration::OperationMode::Coordinated}); + + // Start the worker thread and wait for the go from the system monitor + auto unleashWorkerThreadPromise = std::promise(); + auto unleashWorkerThreadFuture = unleashWorkerThreadPromise.get_future(); + auto systemMonitor = participant->CreateSystemMonitor(); + systemMonitor->AddParticipantStatusHandler( + [&unleashWorkerThreadPromise, participantName, + logger](const SilKit::Services::Orchestration::ParticipantStatus& participantStatus) { + if (participantStatus.participantName == participantName + && participantStatus.state == SilKit::Services::Orchestration::ParticipantState::Running) + { + logger->Info("The sil-kit-system-controller started the simulation. My state is now 'Running'."); + unleashWorkerThreadPromise.set_value(); + } + }); + + // Start the worker thread and wait for the go from the system monitor + std::atomic workerThreadDone = false; + auto workerThread = std::thread([&unleashWorkerThreadFuture, &workerThreadDone, lifecycleService, logger]() { + unleashWorkerThreadFuture.wait(); + while (!workerThreadDone) + { + std::this_thread::sleep_for(1s); + logger->Info("Simulation running. Stop via CTRL-C in the sil-kit-system-controller."); + }; + + }); + + // Start and wait until the sil-kit-system-controller is stopped + logger->Info( + "Start the participant lifecycle and wait for the sil-kit-system-controller to start the simulation."); + auto finalStateFuture = lifecycleService->StartLifecycle(); + finalStateFuture.get(); + + // Clean up the worker thread + workerThreadDone = true; + + if (workerThread.joinable()) + { + workerThread.join(); + } + } + catch (const std::exception& error) + { + std::cerr << "Something went wrong: " << error.what() << std::endl; + return -3; + } + + return 0; +} diff --git a/Demos/api/Orchestration/SimStep.cpp b/Demos/api/Orchestration/SimStep.cpp new file mode 100644 index 000000000..bdc09b80b --- /dev/null +++ b/Demos/api/Orchestration/SimStep.cpp @@ -0,0 +1,60 @@ +// SPDX-FileCopyrightText: 2024 Vector Informatik GmbH +// +// SPDX-License-Identifier: MIT + +#include + +#include "silkit/SilKit.hpp" + +using namespace std::chrono_literals; + +std::ostream& operator<<(std::ostream& out, std::chrono::nanoseconds timestamp) +{ + out << std::chrono::duration_cast(timestamp).count() << "ms"; + return out; +} + +int main(int argc, char** argv) +{ + if (argc != 2) + { + std::cerr << "Wrong number of arguments! Start demo with: " << argv[0] << " " << std::endl; + return -1; + } + std::string participantName(argv[1]); + + try + { + // Setup participant, lifecycle, time synchronization and logging + const std::string registryUri = "silkit://localhost:8500"; + const std::string configString = R"({"Logging":{"Sinks":[{"Type":"Stdout","Level":"Info"}]}})"; + auto participantConfiguration = SilKit::Config::ParticipantConfigurationFromString(configString); + + auto participant = SilKit::CreateParticipant(participantConfiguration, participantName, registryUri); + auto logger = participant->GetLogger(); + + auto* lifecycleService = + participant->CreateLifecycleService({SilKit::Services::Orchestration::OperationMode::Coordinated}); + + auto* timeSyncService = lifecycleService->CreateTimeSyncService(); + + // Simulation steps + const auto stepSize = 1ms; + timeSyncService->SetSimulationStepHandler( + [logger](std::chrono::nanoseconds now, std::chrono::nanoseconds duration) { + std::stringstream ss; + ss << "--------- Simulation step T=" << now << " ---------"; + logger->Info(ss.str()); + }, stepSize); + + auto finalStateFuture = lifecycleService->StartLifecycle(); + finalStateFuture.get(); + } + catch (const std::exception& error) + { + std::cerr << "Something went wrong: " << error.what() << std::endl; + return -3; + } + + return 0; +} diff --git a/Demos/api/Orchestration/SimStepAsync.cpp b/Demos/api/Orchestration/SimStepAsync.cpp new file mode 100644 index 000000000..03586b8b7 --- /dev/null +++ b/Demos/api/Orchestration/SimStepAsync.cpp @@ -0,0 +1,102 @@ +// SPDX-FileCopyrightText: 2024 Vector Informatik GmbH +// +// SPDX-License-Identifier: MIT + +#include + +#include "silkit/SilKit.hpp" + +using namespace std::chrono_literals; + +std::ostream& operator<<(std::ostream& out, std::chrono::nanoseconds timestamp) +{ + out << std::chrono::duration_cast(timestamp).count() << "ms"; + return out; +} + +std::mutex mx; +bool doStep = false; +std::condition_variable cv; +std::atomic asyncThreadDone = false; + +int main(int argc, char** argv) +{ + if (argc != 2) + { + std::cerr << "Wrong number of arguments! Start demo with: " << argv[0] << " " << std::endl; + return -1; + } + std::string participantName(argv[1]); + + try + { + // Setup participant, lifecycle, time synchronization and logging + const std::string registryUri = "silkit://localhost:8500"; + const std::string configString = R"({"Logging":{"Sinks":[{"Type":"Stdout","Level":"Info"}]}})"; + auto participantConfiguration = SilKit::Config::ParticipantConfigurationFromString(configString); + + auto participant = SilKit::CreateParticipant(participantConfiguration, participantName, registryUri); + auto logger = participant->GetLogger(); + + auto* lifecycleService = + participant->CreateLifecycleService({SilKit::Services::Orchestration::OperationMode::Coordinated}); + + auto* timeSyncService = lifecycleService->CreateTimeSyncService(); + + // 1. The simulation step gets called by the SIL Kit Time Synchronization algorithm. + // 2. The simulation step handler unlocks a step in the asyncThread with a condition variable. + // 3. The asyncThread performs some asynchronous operation. + // 4. The asyncThread completes the simulation step. + + // Simulation steps + const auto stepSize = 1ms; + timeSyncService->SetSimulationStepHandlerAsync( + [logger](std::chrono::nanoseconds now, std::chrono::nanoseconds duration) { + std::stringstream ss; + ss << "--------- Simulation step T=" << now << " ---------"; + logger->Info(ss.str()); + + std::unique_lock lock(mx); + doStep = true; + cv.notify_one(); + + }, stepSize); + + auto asyncThread = std::thread([timeSyncService, logger]() { + while (!asyncThreadDone) + { + std::unique_lock lock(mx); + cv.wait(lock, [] { return doStep; }); + doStep = false; + + logger->Info("Asynchronous operation in the simulation step:"); + logger->Info(" Sending a message to another participant..."); + std::this_thread::sleep_for(0.5s); + logger->Info(" Awaiting the reply of another participant..."); + std::this_thread::sleep_for(0.5s); + logger->Info(" Calling a REST API..."); + std::this_thread::sleep_for(0.5s); + logger->Info("Done."); + + timeSyncService->CompleteSimulationStep(); + } + }); + + auto finalStateFuture = lifecycleService->StartLifecycle(); + finalStateFuture.get(); + + asyncThreadDone = true; + if (asyncThread.joinable()) + { + asyncThread.join(); + } + + } + catch (const std::exception& error) + { + std::cerr << "Something went wrong: " << error.what() << std::endl; + return -3; + } + + return 0; +} diff --git a/Demos/communication/Can/CMakeLists.txt b/Demos/communication/Can/CMakeLists.txt index ee2f6c598..c45b97502 100644 --- a/Demos/communication/Can/CMakeLists.txt +++ b/Demos/communication/Can/CMakeLists.txt @@ -2,6 +2,6 @@ # # SPDX-License-Identifier: MIT -make_silkit_demo(SilKitDemoCanWriter CanWriterDemo.cpp) -make_silkit_demo(SilKitDemoCanReader CanReaderDemo.cpp) +make_silkit_communication_demo(SilKitDemoCanWriter CanWriterDemo.cpp) +make_silkit_communication_demo(SilKitDemoCanReader CanReaderDemo.cpp) diff --git a/Demos/communication/Can/CanWriterDemo.cpp b/Demos/communication/Can/CanWriterDemo.cpp index f5617449d..22bd43899 100644 --- a/Demos/communication/Can/CanWriterDemo.cpp +++ b/Demos/communication/Can/CanWriterDemo.cpp @@ -15,6 +15,7 @@ class CanWriter : public ApplicationBase ICanController* _canController{nullptr}; std::string _networkName = "CAN1"; bool _printHex{false}; + int _frameId = 0; void AddCommandLineArgs() override { @@ -52,9 +53,7 @@ class CanWriter : public ApplicationBase void SendFrame() { - // Count up message id per frame - static uint64_t messageId = 0; - messageId++; + _frameId++; // Build a CAN FD frame CanFrame canFrame{}; @@ -62,9 +61,9 @@ class CanWriter : public ApplicationBase canFrame.flags = static_cast(CanFrameFlag::Fdf) // FD Format Indicator | static_cast(CanFrameFlag::Brs); // Bit Rate Switch (for FD Format only) - // Build a payload with the message Id + // Build a payload with the frame Id std::stringstream payloadBuilder; - payloadBuilder << "CAN " << messageId % 10000; + payloadBuilder << "CAN " << _frameId % 10000; auto payloadStr = payloadBuilder.str(); std::vector payloadBytes(payloadStr.begin(), payloadStr.end()); canFrame.dataField = payloadBytes; @@ -96,6 +95,7 @@ class CanWriter : public ApplicationBase { SendFrame(); } + }; int main(int argc, char** argv) diff --git a/Demos/communication/Ethernet/CMakeLists.txt b/Demos/communication/Ethernet/CMakeLists.txt index 1f7a4517c..9952df136 100644 --- a/Demos/communication/Ethernet/CMakeLists.txt +++ b/Demos/communication/Ethernet/CMakeLists.txt @@ -2,6 +2,6 @@ # # SPDX-License-Identifier: MIT -make_silkit_demo(SilKitDemoEthernetWriter EthernetWriterDemo.cpp) -make_silkit_demo(SilKitDemoEthernetReader EthernetReaderDemo.cpp) +make_silkit_communication_demo(SilKitDemoEthernetWriter EthernetWriterDemo.cpp) +make_silkit_communication_demo(SilKitDemoEthernetReader EthernetReaderDemo.cpp) diff --git a/Demos/communication/Ethernet/EthernetWriterDemo.cpp b/Demos/communication/Ethernet/EthernetWriterDemo.cpp index e5c9f2812..809d73ddc 100644 --- a/Demos/communication/Ethernet/EthernetWriterDemo.cpp +++ b/Demos/communication/Ethernet/EthernetWriterDemo.cpp @@ -15,6 +15,7 @@ class EthernetWriter : public ApplicationBase IEthernetController* _ethernetController{nullptr}; std::string _networkName = "Eth1"; bool _printHex{false}; + int _frameId = 0; void AddCommandLineArgs() override { @@ -73,21 +74,22 @@ class EthernetWriter : public ApplicationBase EthernetDemoCommon::EthernetMac WriterMacAddr = {0xF6, 0x04, 0x68, 0x71, 0xAA, 0xC1}; EthernetDemoCommon::EthernetMac BroadcastMacAddr = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; - static int frameId = 0; + _frameId++; + std::stringstream stream; // Ensure that the payload is long enough to constitute a valid Ethernet frame - stream << "Hello from Ethernet writer! (frameId=" << frameId++ + stream << "Hello from Ethernet writer! (frameId=" << _frameId << ")----------------------------------------------------"; auto payloadString = stream.str(); std::vector payload(payloadString.begin(), payloadString.end()); auto frame = CreateFrame(BroadcastMacAddr, WriterMacAddr, payload); - const auto userContext = reinterpret_cast(static_cast(frameId)); - - _ethernetController->SendFrame(EthernetFrame{frame}, userContext); + const auto userContext = reinterpret_cast(static_cast(_frameId)); std::stringstream ss; ss << "Sending Ethernet frame, data=" << EthernetDemoCommon::PrintPayload(payload, _printHex); GetLogger()->Info(ss.str()); + + _ethernetController->SendFrame(EthernetFrame{frame}, userContext); } void DoWorkSync(std::chrono::nanoseconds /*now*/) override @@ -99,6 +101,7 @@ class EthernetWriter : public ApplicationBase { SendFrame(); } + }; int main(int argc, char** argv) diff --git a/Demos/communication/Flexray/CMakeLists.txt b/Demos/communication/Flexray/CMakeLists.txt index 5b7460518..4fd7be687 100644 --- a/Demos/communication/Flexray/CMakeLists.txt +++ b/Demos/communication/Flexray/CMakeLists.txt @@ -19,5 +19,5 @@ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -make_silkit_demo(SilKitDemoFlexrayNode0 FlexrayNode0Demo.cpp) -make_silkit_demo(SilKitDemoFlexrayNode1 FlexrayNode1Demo.cpp) +make_silkit_communication_demo(SilKitDemoFlexrayNode0 FlexrayNode0Demo.cpp) +make_silkit_communication_demo(SilKitDemoFlexrayNode1 FlexrayNode1Demo.cpp) diff --git a/Demos/communication/Flexray/FlexrayDemoCommon.hpp b/Demos/communication/Flexray/FlexrayDemoCommon.hpp index ae4a7dc49..5e29e49e5 100644 --- a/Demos/communication/Flexray/FlexrayDemoCommon.hpp +++ b/Demos/communication/Flexray/FlexrayDemoCommon.hpp @@ -93,8 +93,8 @@ class FlexrayNode IFlexrayController* _flexrayController{nullptr}; FlexrayControllerConfig _controllerConfig; FlexrayPocStatusEvent _lastPocStatus{}; + int _msgId = 0; bool _configured{false}; - ILogger* _logger; enum class MasterState @@ -130,14 +130,13 @@ class FlexrayNode if (_controllerConfig.bufferConfigs.empty()) return; - static auto msgNumber = -1; - msgNumber++; + _msgId++; - auto bufferIdx = msgNumber % _controllerConfig.bufferConfigs.size(); + auto bufferIdx = _msgId % _controllerConfig.bufferConfigs.size(); // prepare a friendly message as payload std::stringstream payloadStream; - payloadStream << "FlexrayFrameEvent#" << std::setw(4) << msgNumber << "; bufferId=" << bufferIdx; + payloadStream << "FlexrayFrameEvent#" << std::setw(4) << _msgId << "; bufferId=" << bufferIdx; auto payloadString = payloadStream.str(); std::vector payloadBytes; diff --git a/Demos/communication/Lin/CMakeLists.txt b/Demos/communication/Lin/CMakeLists.txt index 4dbc08ea5..c490f0aa7 100644 --- a/Demos/communication/Lin/CMakeLists.txt +++ b/Demos/communication/Lin/CMakeLists.txt @@ -2,8 +2,8 @@ # # SPDX-License-Identifier: MIT -make_silkit_demo(SilKitDemoLinSlave LinSlaveDemo.cpp) -make_silkit_demo(SilKitDemoLinMaster LinMasterDemo.cpp) +make_silkit_communication_demo(SilKitDemoLinSlave LinSlaveDemo.cpp) +make_silkit_communication_demo(SilKitDemoLinMaster LinMasterDemo.cpp) -make_silkit_demo(SilKitDemoLinSlaveDynamic LinSlaveDynamicDemo.cpp) -make_silkit_demo(SilKitDemoLinMasterDynamic LinMasterDynamicDemo.cpp) \ No newline at end of file +make_silkit_communication_demo(SilKitDemoLinSlaveDynamic LinSlaveDynamicDemo.cpp) +make_silkit_communication_demo(SilKitDemoLinMasterDynamic LinMasterDynamicDemo.cpp) \ No newline at end of file diff --git a/Demos/communication/PubSub/CMakeLists.txt b/Demos/communication/PubSub/CMakeLists.txt index 7fd4e5534..a5894426f 100644 --- a/Demos/communication/PubSub/CMakeLists.txt +++ b/Demos/communication/PubSub/CMakeLists.txt @@ -2,5 +2,5 @@ # # SPDX-License-Identifier: MIT -make_silkit_demo(SilKitDemoPublisher PublisherDemo.cpp) -make_silkit_demo(SilKitDemoSubscriber SubscriberDemo.cpp) +make_silkit_communication_demo(SilKitDemoPublisher PublisherDemo.cpp) +make_silkit_communication_demo(SilKitDemoSubscriber SubscriberDemo.cpp) diff --git a/Demos/communication/Rpc/CMakeLists.txt b/Demos/communication/Rpc/CMakeLists.txt index 09e191f69..27511b753 100644 --- a/Demos/communication/Rpc/CMakeLists.txt +++ b/Demos/communication/Rpc/CMakeLists.txt @@ -2,5 +2,5 @@ # # SPDX-License-Identifier: MIT -make_silkit_demo(SilKitDemoRpcServer RpcServerDemo.cpp) -make_silkit_demo(SilKitDemoRpcClient RpcClientDemo.cpp) +make_silkit_communication_demo(SilKitDemoRpcServer RpcServerDemo.cpp) +make_silkit_communication_demo(SilKitDemoRpcClient RpcClientDemo.cpp) diff --git a/Demos/include/ApplicationBase.hpp b/Demos/communication/include/ApplicationBase.hpp similarity index 96% rename from Demos/include/ApplicationBase.hpp rename to Demos/communication/include/ApplicationBase.hpp index cdb2282cb..52e047b7b 100644 --- a/Demos/include/ApplicationBase.hpp +++ b/Demos/communication/include/ApplicationBase.hpp @@ -112,6 +112,7 @@ class ApplicationBase std::unique_ptr _participant; ILifecycleService* _lifecycleService{nullptr}; ITimeSyncService* _timeSyncService{nullptr}; + ISystemMonitor* _systemMonitor{nullptr}; // For sync: wait for sil-kit-system-controller start/abort or manual user abort enum struct SystemControllerResult @@ -130,7 +131,7 @@ class ApplicationBase enum struct UnleashWorkerThreadResult { Unknown, - Start, + ParticipantStateRunning, UserAbort }; std::promise _unleashWorkerThreadPromise; @@ -466,6 +467,7 @@ class ApplicationBase { _participant = SilKit::CreateParticipant(_participantConfiguration, _arguments.participantName, _arguments.registryUri); + _systemMonitor = _participant->CreateSystemMonitor(); } void SetupLifecycle() @@ -503,10 +505,19 @@ class ApplicationBase { if (_arguments.runAsync) { - // Async: Work by the app is done in a separate thread + // Track the participant status to unleash the worker thread when in Running state + _systemMonitor->AddParticipantStatusHandler( + [this](const SilKit::Services::Orchestration::ParticipantStatus& participantStatus) { + if (participantStatus.participantName == _arguments.participantName && participantStatus.state + == SilKit::Services::Orchestration::ParticipantState::Running) + { + _unleashWorkerThreadPromise.set_value(UnleashWorkerThreadResult::ParticipantStateRunning); + } + }); + + // Start the worker thread _unleashWorkerThreadFuture = _unleashWorkerThreadPromise.get_future(); _workerThread = std::thread{&ApplicationBase::WorkerThread, this}; - _lifecycleService->SetStartingHandler([this]() { _unleashWorkerThreadPromise.set_value(UnleashWorkerThreadResult::Start); }); } else { @@ -588,6 +599,11 @@ class ApplicationBase // Only use inside class protected: + IParticipant* GetParticipant() const + { + return _participant.get(); + } + ILifecycleService* GetLifecycleService() const { return _lifecycleService; @@ -598,9 +614,9 @@ class ApplicationBase return _timeSyncService; } - IParticipant* GetParticipant() const + ISystemMonitor* GetSystemMonitor() const { - return _participant.get(); + return _systemMonitor; } ILogger* GetLogger() const diff --git a/Demos/include/CommandlineParser.hpp b/Demos/communication/include/CommandlineParser.hpp similarity index 100% rename from Demos/include/CommandlineParser.hpp rename to Demos/communication/include/CommandlineParser.hpp diff --git a/Demos/include/SignalHandler.hpp b/Demos/communication/include/SignalHandler.hpp similarity index 100% rename from Demos/include/SignalHandler.hpp rename to Demos/communication/include/SignalHandler.hpp diff --git a/docs/CHANGELOG.rst b/docs/CHANGELOG.rst index 78a42f7fe..d8e49bbf2 100644 --- a/docs/CHANGELOG.rst +++ b/docs/CHANGELOG.rst @@ -28,7 +28,7 @@ Changed - Basic SIL Kit features are implemented in a base class used by the demos - No command line arguments needed for basic execution (with time synchronization and coordinated start) - Useful command line arguments are provided for all demos (e.g. rename the participant or network, logging, execution modes) - - The old '--async' mode of the demos now is accessible by '--async --autonomous' (or short form '-aA') + - The old ``--async`` mode of the demos now is accessible by ``--async --autonomous`` (or short form ``-aA``) [4.0.54] - 2024-11-11 --------------------- diff --git a/docs/demos/abstracts.rst b/docs/demos/abstracts.rst index 0816834e9..193c46766 100644 --- a/docs/demos/abstracts.rst +++ b/docs/demos/abstracts.rst @@ -2,15 +2,15 @@ .. Communication system Demos .. |DemoAbstractCAN| replace:: - The `CanWriter` participant sends Can frames to the `CanReader` participant including frame acknowledgment handling. + The ``CanWriter`` participant sends Can frames to the ``CanReader`` participant including frame acknowledgment handling. .. |DemoAbstractETH| replace:: - The `EthernetWriter` participant sends Ethernet frames to the `EthernetReader` participant including frame acknowledgment handling. + The ``EthernetWriter`` participant sends Ethernet frames to the ``EthernetReader`` participant including frame acknowledgment handling. .. |DemoAbstractLIN| replace:: - A two-node Lin Setup with a `LinMaster` and a `LinSlave`. + A two-node Lin Setup with a ``LinMaster`` and a ``LinSlave``. Includes a simple scheduling mechanism and demonstrates controller sleep / wakeup handling. .. |DemoAbstractFlexRay| replace:: A two-node FlexRay Setup with a full cluster and node parametrization. Includes POC Status handling, buffer updates and reconfiguration. - This Demo requires a separate `Network Simulator` application to simulate the details of the FlexRay cluster, which is not included in the SIL Kit. + This Demo requires a separate ``Network Simulator`` application to simulate the details of the FlexRay cluster, which is not included in the SIL Kit. .. |DemoAbstractPubSub| replace:: One participant publishes GPS and temperature data, another participant subscribes to these topics. Including (de-)serialization of the C++ structures into a transmittable format. @@ -28,6 +28,20 @@ Demonstrates the usage of the experimental SIL Kit NetworkSimulator API. A custom network simulation for Can is set up, the network simulator application can be used together with the Can demo. +.. |DemoAbstractAutonomous| replace:: + Minimal example of a participant with an autonomous lifecycle. + The demo shows that this participant can be started and stopped independently from other participants. + +.. |DemoAbstractCoordinated| replace:: + Minimal example of a participant with a coordinated lifecycle. + This shows how multiple participants can be started and stopped simultaneously, controlled by the ``sil-kit-system-controller``. + +.. |DemoAbstractSimStep| replace:: + Minimal example of a participant with time synchronization and a simulation step handler. + +.. |DemoAbstractSimStepAsync| replace:: + Minimal example of a participant with time synchronization and an asynchronous simulation step handler. + .. Tools diff --git a/docs/demos/api.rst b/docs/demos/api.rst index f43b3af01..795234bb6 100644 --- a/docs/demos/api.rst +++ b/docs/demos/api.rst @@ -7,6 +7,10 @@ API These demos focus on basic systems or single topics of the |ProductName| API. +.. contents:: + :depth: 1 + :local: + .. _sec:simple-can-demo: Simple Can @@ -27,7 +31,157 @@ Parameters System Example Run the following commands in separate terminals: + .. parsed-literal:: + + # Registry (if not already running): + |Registry| + + # Participant P1: + |DemoDir|/SilKitDemoSimpleCan P1 + + # Participant P2: + |DemoDir|/SilKitDemoSimpleCan P2 + + # System Controller: + |SystemController| P1 P2 + + +.. _sec:autonomous-lifecycle-demo: + +Autonomous lifecycle +~~~~~~~~~~~~~~~~~~~~ + +Abstract + |DemoAbstractAutonomous| +Executables + * ``SilKitDemoAutonomous`` +Sources + * :repo-link:`Autonomous.cpp ` +Requirements + * :ref:`sil-kit-registry` +Parameters + * ```` + Name of the SIL Kit participant. +System Example + Run the following commands in separate terminals: + + .. parsed-literal:: + + # Registry (if not already running): + |Registry| + + # Participant P1: + |DemoDir|/SilKitDemoAutonomous P1 + + # Participant P2: + |DemoDir|/SilKitDemoAutonomous P2 + + +.. _sec:coordinated-lifecycle-demo: + +Coordinated lifecycle +~~~~~~~~~~~~~~~~~~~~~ + +Abstract + |DemoAbstractCoordinated| +Executables + * ``SilKitDemoCoordinated`` +Sources + * :repo-link:`Coordinated.cpp ` +Requirements + * :ref:`sil-kit-registry` + * :ref:`sil-kit-system-controller` +Parameters + * ```` + Name of the SIL Kit participant. +System Example + Run the following commands in separate terminals: + + .. parsed-literal:: + + # Registry (if not already running): + |Registry| + + # Participant P1: + |DemoDir|/SilKitDemoCoordinated P1 + + # Participant P2: + |DemoDir|/SilKitDemoCoordinated P2 + + # System Controller: + |SystemController| P1 P2 + +.. _sec:sim-step-demo: + +Simulation step handler +~~~~~~~~~~~~~~~~~~~~~~~ + +Abstract + |DemoAbstractSimStep| +Executables + * ``SilKitDemoSimStep`` +Sources + * :repo-link:`SimStep.cpp ` +Requirements + * :ref:`sil-kit-registry` + * :ref:`sil-kit-system-controller` +Parameters + * ```` + Name of the SIL Kit participant. +System Example + Run the following commands in separate terminals: + + .. parsed-literal:: + + # Registry (if not already running): + |Registry| + + # Participant P1: + |DemoDir|/SilKitDemoSimStep P1 + + # Participant P2: + |DemoDir|/SilKitDemoSimStep P2 + + # System Controller: + |SystemController| P1 P2 + + +.. _sec:sim-step-async-demo: + +Asynchronous simulation step handler +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Abstract + |DemoAbstractSimStepAsync| +Executables + * ``SilKitDemoSimStepAsync`` +Sources + * :repo-link:`SimStepAsync.cpp ` +Requirements + * :ref:`sil-kit-registry` + * :ref:`sil-kit-system-controller` +Parameters + * ```` + Name of the SIL Kit participant. +System Example + Run the following commands in separate terminals: + + .. parsed-literal:: + + # Registry (if not already running): + |Registry| + + # Participant P1: + |DemoDir|/SilKitDemoSimStepAsync P1 + + # Participant P2: + |DemoDir|/SilKitDemoSimStepAsync P2 + + # System Controller: + |SystemController| P1 P2 + + .. _sec:netsim-demo: Network Simulator API @@ -94,42 +248,3 @@ Notes # System Controller: |SystemController| CanReader CanWriter - -.. - .. _sec:autonomous-lifecycle-demo: - - Autonomous lifecycle Demo - ~~~~~~~~~~~~~~~~~~~~~~~~~ - - TODO - - .. _sec:coordinated-lifecycle-demo: - - Coordinated lifecycle Demo - ~~~~~~~~~~~~~~~~~~~~~~~~~~ - - TODO - - .. _sec:event-based-demo: - - Event based participant Demo - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - TODO - - .. _sec:timesync-demo: - - Virtual Time Synchronization Demo - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - TODO - - .. _sec:integration-demo: - - Asynchronous Simulation Step Demo - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - TODO - - - diff --git a/docs/demos/build.rst b/docs/demos/build.rst index 256223946..410d5a1c1 100644 --- a/docs/demos/build.rst +++ b/docs/demos/build.rst @@ -23,14 +23,14 @@ There are several options to build the demos, all require the installation of a VS Code ------- -#. Install the VS Code extensions `C/C++` and `CMake` +#. Install the VS Code extensions ``C/C++`` and ``CMake`` #. Open the folder with VS Code a. For the git repository: open the root folder of the repository - b. For a |ProductName| package: open the `SilKit-Demos` folder + b. For a |ProductName| package: open the ``SilKit-Demos`` folder #. Opening the folder automatically starts the CMake configuration step. - You can also manually call this step in the CMake extension page under `Project Status | Configure`. -#. In the CMake extension page, build the project under `Project Status | Build` + You can also manually call this step in the CMake extension page under ``Project Status | Configure``. +#. In the CMake extension page, build the project under ``Project Status | Build`` #. Locate the binaries a. For the git repository: The binaries reside in ``_build///`` @@ -43,10 +43,10 @@ Visual Studio #. Open the folder with Visual Studio a. For the git repository: open the root folder of the repository - b. For a |ProductName| package: open the `SilKit-Demos` folder + b. For a |ProductName| package: open the ``SilKit-Demos`` folder #. Opening the folder automatically starts the CMake configuration step. - You can also manually call this step under `Project | Configure Cache`. -#. Build the project with `Build | Build All` + You can also manually call this step under ``Project | Configure Cache``. +#. Build the project with ``Build | Build All`` #. Locate the binaries a. For the git repository: The binaries reside in ``_build///`` diff --git a/docs/demos/communication.rst b/docs/demos/communication.rst index 70d99979b..ddff6d7e5 100644 --- a/docs/demos/communication.rst +++ b/docs/demos/communication.rst @@ -8,6 +8,10 @@ Communication Protocols The demos shown here are build on top of a base implementation that provides general |ProductName| features. This allows to separate the demo specific use case (e.g. how to use Ethernet with the |ProductName|) from general features (e.g. setup the |ProductName| lifecycle). +.. contents:: + :depth: 1 + :local: + Command line arguments ~~~~~~~~~~~~~~~~~~~~~~ diff --git a/docs/demos/demos.rst b/docs/demos/demos.rst index 12fc735b9..b408fae51 100644 --- a/docs/demos/demos.rst +++ b/docs/demos/demos.rst @@ -47,9 +47,22 @@ These demos focus on a basic systems and single topic of the |ProductName| API: :ref:`sec:simple-can-demo` |DemoAbstractSimpleCan| +:ref:`sec:autonomous-lifecycle-demo` + |DemoAbstractAutonomous| + +:ref:`sec:coordinated-lifecycle-demo` + |DemoAbstractCoordinated| + +:ref:`sec:sim-step-demo` + |DemoAbstractSimStep| + +:ref:`sec:sim-step-async-demo` + |DemoAbstractSimStepAsync| + :ref:`sec:netsim-demo` |DemoAbstractNetSim| + .. rubric:: 3. Tools Tools for performance analysis: diff --git a/docs/demos/tool.rst b/docs/demos/tool.rst index d561bcc8d..f39f33dac 100644 --- a/docs/demos/tool.rst +++ b/docs/demos/tool.rst @@ -7,6 +7,10 @@ Tools Tools for performance analysis. +.. contents:: + :depth: 1 + :local: + .. _sec:benchmark-demo: Benchmark Demo