Skip to content

Commit

Permalink
demos: Use application base only for comm. demos; Add Orchestration d…
Browse files Browse the repository at this point in the history
…emos
  • Loading branch information
KonradBkd committed Dec 19, 2024
1 parent 9365513 commit 9f7adcc
Show file tree
Hide file tree
Showing 25 changed files with 600 additions and 90 deletions.
19 changes: 14 additions & 5 deletions Demos/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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")

Expand All @@ -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}
Expand Down Expand Up @@ -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()
Expand All @@ -136,21 +137,29 @@ 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)
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
Expand Down
81 changes: 81 additions & 0 deletions Demos/api/Orchestration/Autonomous.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// SPDX-FileCopyrightText: 2024 Vector Informatik GmbH
//
// SPDX-License-Identifier: MIT

#include <iostream>

#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] << " <ParticipantName>" << 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<void>();
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;
}
9 changes: 9 additions & 0 deletions Demos/api/Orchestration/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -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)

81 changes: 81 additions & 0 deletions Demos/api/Orchestration/Coordinated.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// SPDX-FileCopyrightText: 2024 Vector Informatik GmbH
//
// SPDX-License-Identifier: MIT

#include <iostream>

#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] << " <ParticipantName>" << 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<void>();
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<bool> 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;
}
60 changes: 60 additions & 0 deletions Demos/api/Orchestration/SimStep.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// SPDX-FileCopyrightText: 2024 Vector Informatik GmbH
//
// SPDX-License-Identifier: MIT

#include <iostream>

#include "silkit/SilKit.hpp"

using namespace std::chrono_literals;

std::ostream& operator<<(std::ostream& out, std::chrono::nanoseconds timestamp)
{
out << std::chrono::duration_cast<std::chrono::milliseconds>(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] << " <ParticipantName>" << 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;
}
102 changes: 102 additions & 0 deletions Demos/api/Orchestration/SimStepAsync.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
// SPDX-FileCopyrightText: 2024 Vector Informatik GmbH
//
// SPDX-License-Identifier: MIT

#include <iostream>

#include "silkit/SilKit.hpp"

using namespace std::chrono_literals;

std::ostream& operator<<(std::ostream& out, std::chrono::nanoseconds timestamp)
{
out << std::chrono::duration_cast<std::chrono::milliseconds>(timestamp).count() << "ms";
return out;
}

std::mutex mx;
bool doStep = false;
std::condition_variable cv;
std::atomic<bool> asyncThreadDone = false;

int main(int argc, char** argv)
{
if (argc != 2)
{
std::cerr << "Wrong number of arguments! Start demo with: " << argv[0] << " <ParticipantName>" << 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<decltype(mx)> lock(mx);
doStep = true;
cv.notify_one();

}, stepSize);

auto asyncThread = std::thread([timeSyncService, logger]() {
while (!asyncThreadDone)
{
std::unique_lock<decltype(mx)> 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;
}
Loading

0 comments on commit 9f7adcc

Please sign in to comment.