Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Demos/api/Orchestration/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@
make_silkit_demo(SilKitDemoAutonomous Autonomous.cpp OFF)
make_silkit_demo(SilKitDemoCoordinated Coordinated.cpp OFF)
make_silkit_demo(SilKitDemoSimStep SimStep.cpp OFF)
make_silkit_demo(SilKitDemoDynSimStep DynSimStep.cpp OFF)
make_silkit_demo(SilKitDemoSimStepAsync SimStepAsync.cpp OFF)

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

#include <iostream>
#include <random>
#include <thread>

#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 != 5 && argc != 6)
{
std::cerr << "Wrong number of arguments! Start demo with: " << argv[0] <<
" <ParticipantName> "
"<StepSize> "
"[-A (Autonomous) | -C (Coordinated)] "
"[-M (ByMinimalDuration) | -D (ByOwnDuration)] "
"[-R (Optional; Randomize StepSize (1ms to 10ms) with 10% probability every step)]" << std::endl;
return -1;
}
// Arg 1: Participant Name
std::string participantName(argv[1]);

// Arg 2: Step Size
auto stepSize = std::chrono::milliseconds(std::stoi(argv[2]));
std::cout << "Starting with stepSize=" << stepSize << std::endl;

// Arg 3: Operation Mode
auto operationMode = SilKit::Services::Orchestration::OperationMode::Coordinated;
if (std::string(argv[3]) == "-A")
{
std::cout << "Using OperationMode::Autonomous" << std::endl;
operationMode = SilKit::Services::Orchestration::OperationMode::Autonomous;
}
else if (std::string(argv[3]) == "-C")
{
std::cout << "Using OperationMode::Coordinated" << std::endl;
}
else
{
std::cerr << "Unknown third argument '" << argv[3] << "'. Did you mean '-A' for autonomous mode or '-C' for coordinated mode?" << std::endl;
return -1;
}

// Arg 4: Time Advance Mode
auto timeAdvanceMode = SilKit::Services::Orchestration::TimeAdvanceMode::ByMinimalDuration;
if (std::string(argv[4]) == "-M")
{
std::cout << "Using TimeAdvanceMode::ByMinimalDuration" << std::endl;
}
else if (std::string(argv[4]) == "-D")
{
timeAdvanceMode = SilKit::Services::Orchestration::TimeAdvanceMode::ByOwnDuration;
std::cout << "Using TimeAdvanceMode::ByOwnDuration" << std::endl;
}
else
{
std::cerr << "Unknown argument '" << argv[4]
<< "'. Did you mean '-M' for TimeAdvanceMode::ByMinimalDuration or '-D' for TimeAdvanceMode::ByOwnDuration?" << std::endl;
return -1;
}

// Arg 5: Optional Randomize Step Size
bool randomizeStepSize = false;
if (argc == 6)
{
if (std::string(argv[5]) == "-R")
{
randomizeStepSize = true;
std::cout << "Randomizing step size every 10 steps." << std::endl << std::endl;
}
else
{
std::cerr << "Unknown argument '" << argv[5] << "'. Did you mean '-R' to randomize the step size every 10 steps?" << std::endl;
return -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({operationMode});

auto* timeSyncService = lifecycleService->CreateTimeSyncService(timeAdvanceMode);

std::random_device rd;
std::mt19937 rng(rd());
auto bounded_rand = [&rng](unsigned range) {
std::uniform_int_distribution<unsigned> dist(1, range);
return dist(rng);
};

timeSyncService->SetSimulationStepHandler(
[randomizeStepSize, logger, timeSyncService, participantName, bounded_rand](
std::chrono::nanoseconds now,
std::chrono::nanoseconds duration) {
// The invocation of this handler marks the beginning of a simulation step.
{
std::stringstream ss;
ss << "--------- Simulation step T=" << now << ", duration=" << duration << " ---------";
logger->Info(ss.str());
}

if (randomizeStepSize && bounded_rand(10) == 1)
{
auto rndStepDuration = bounded_rand(10);
timeSyncService->SetStepDuration(std::chrono::milliseconds(rndStepDuration));
std::stringstream ss;
ss << "--------- Changing step size to " << rndStepDuration << "ms ---------";
logger->Info(ss.str());
}

std::this_thread::sleep_for(500ms);

}, stepSize);

auto finalStateFuture = lifecycleService->StartLifecycle();
finalStateFuture.get();
}
catch (const std::exception& error)
{
std::cerr << "Something went wrong: " << error.what() << std::endl;
return -2;
}

return 0;
}
16 changes: 10 additions & 6 deletions Demos/api/Orchestration/SimStep.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// SPDX-License-Identifier: MIT

#include <iostream>
#include <thread>

#include "silkit/SilKit.hpp"

Expand Down Expand Up @@ -38,15 +39,18 @@ int main(int argc, char** argv)

auto* timeSyncService = lifecycleService->CreateTimeSyncService();

const auto stepSize = 1ms;
const auto stepSize = 5ms;

timeSyncService->SetSimulationStepHandler(
[logger](std::chrono::nanoseconds now, std::chrono::nanoseconds /*duration*/) {
[logger](std::chrono::nanoseconds now, std::chrono::nanoseconds duration) {
// The invocation of this handler marks the beginning of a simulation step.
{
std::stringstream ss;
ss << "--------- Simulation step T=" << now << ", duration=" << duration << " ---------";
logger->Info(ss.str());
}

std::stringstream ss;
ss << "--------- Simulation step T=" << now << " ---------";
logger->Info(ss.str());

std::this_thread::sleep_for(500ms);
// All messages sent here are guaranteed to arrive at other participants before their next simulation step is called.
// So here, we can rely on having received all messages from the past (< now).
// Note that this guarantee only holds for messages sent within a simulation step,
Expand Down
5 changes: 5 additions & 0 deletions SilKit/IntegrationTests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,11 @@ add_silkit_test_to_executable(SilKitIntegrationTests
SOURCES ITest_SimTask.cpp
)

add_silkit_test_to_executable(SilKitIntegrationTests
SOURCES ITest_DynStepSizes.cpp
)


add_silkit_test_to_executable(SilKitFunctionalTests
SOURCES FTest_WallClockCoupling.cpp
)
Expand Down
12 changes: 12 additions & 0 deletions SilKit/IntegrationTests/Hourglass/MockCapi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -614,6 +614,12 @@ extern "C"
return globalCapi->SilKit_TimeSyncService_Create(outTimeSyncService, lifecycleService);
}

SilKit_ReturnCode SilKitCALL SilKit_TimeSyncService_Create_With_TimeAdvanceMode(SilKit_TimeSyncService** outTimeSyncService,
SilKit_LifecycleService* lifecycleService, SilKit_TimeAdvanceMode timeAdvanceMode)
{
return globalCapi->SilKit_TimeSyncService_Create_With_TimeAdvanceMode(outTimeSyncService, lifecycleService, timeAdvanceMode);
}

SilKit_ReturnCode SilKitCALL SilKit_TimeSyncService_SetSimulationStepHandler(
SilKit_TimeSyncService* timeSyncService, void* context, SilKit_TimeSyncService_SimulationStepHandler_t handler,
SilKit_NanosecondsTime initialStepSize)
Expand Down Expand Up @@ -641,6 +647,12 @@ extern "C"
return globalCapi->SilKit_TimeSyncService_Now(timeSyncService, outNanosecondsTime);
}

SilKit_ReturnCode SilKitCALL SilKit_TimeSyncService_SetStepDuration(SilKit_TimeSyncService* timeSyncService,
SilKit_NanosecondsTime stepDuration)
{
return globalCapi->SilKit_TimeSyncService_SetStepDuration(timeSyncService, stepDuration);
}

SilKit_ReturnCode SilKitCALL SilKit_Experimental_TimeSyncService_AddOtherSimulationStepsCompletedHandler(
SilKit_TimeSyncService* timeSyncService, void* context,
SilKit_Experimental_TimeSyncService_OtherSimulationStepsCompletedHandler_t handler,
Expand Down
6 changes: 6 additions & 0 deletions SilKit/IntegrationTests/Hourglass/MockCapi.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,9 @@ class MockCapi
MOCK_METHOD(SilKit_ReturnCode, SilKit_TimeSyncService_Create,
(SilKit_TimeSyncService * *outTimeSyncService, SilKit_LifecycleService* lifecycleService));

MOCK_METHOD(SilKit_ReturnCode, SilKit_TimeSyncService_Create_With_TimeAdvanceMode,
(SilKit_TimeSyncService * *outTimeSyncService, SilKit_LifecycleService* lifecycleService, SilKit_TimeAdvanceMode timeAdvanceMode));

MOCK_METHOD(SilKit_ReturnCode, SilKit_TimeSyncService_SetSimulationStepHandler,
(SilKit_TimeSyncService * timeSyncService, void* context,
SilKit_TimeSyncService_SimulationStepHandler_t handler, SilKit_NanosecondsTime initialStepSize));
Expand All @@ -339,6 +342,9 @@ class MockCapi
MOCK_METHOD(SilKit_ReturnCode, SilKit_TimeSyncService_Now,
(SilKit_TimeSyncService * timeSyncService, SilKit_NanosecondsTime* outNanosecondsTime));

MOCK_METHOD(SilKit_ReturnCode, SilKit_TimeSyncService_SetStepDuration,
(SilKit_TimeSyncService * timeSyncService, SilKit_NanosecondsTime stepDuration));

MOCK_METHOD(SilKit_ReturnCode, SilKit_Experimental_TimeSyncService_AddOtherSimulationStepsCompletedHandler,
(SilKit_TimeSyncService * timeSyncService, void* context,
SilKit_Experimental_TimeSyncService_OtherSimulationStepsCompletedHandler_t handler,
Expand Down
32 changes: 32 additions & 0 deletions SilKit/IntegrationTests/Hourglass/Test_HourglassOrchestration.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,8 @@ class Test_HourglassOrchestration : public SilKitHourglassTests::MockCapiTest
.WillByDefault(DoAll(SetArgPointee<0>(mockLifecycleService), Return(SilKit_ReturnCode_SUCCESS)));
ON_CALL(capi, SilKit_TimeSyncService_Create(_, _))
.WillByDefault(DoAll(SetArgPointee<0>(mockTimeSyncService), Return(SilKit_ReturnCode_SUCCESS)));
ON_CALL(capi, SilKit_TimeSyncService_Create_With_TimeAdvanceMode(_, _, _))
.WillByDefault(DoAll(SetArgPointee<0>(mockTimeSyncService), Return(SilKit_ReturnCode_SUCCESS)));
ON_CALL(capi, SilKit_SystemMonitor_Create(_, _))
.WillByDefault(DoAll(SetArgPointee<0>(mockSystemMonitor), Return(SilKit_ReturnCode_SUCCESS)));
ON_CALL(capi, SilKit_Experimental_SystemController_Create(_, _))
Expand Down Expand Up @@ -362,6 +364,23 @@ TEST_F(Test_HourglassOrchestration, SilKit_TimeSyncService_Create)
mockLifecycleService};
}

TEST_F(Test_HourglassOrchestration, SilKit_TimeSyncService_Create_With_TimeAdvanceMode)
{
EXPECT_CALL(capi, SilKit_TimeSyncService_Create_With_TimeAdvanceMode(testing::_, mockLifecycleService,
SilKit_TimeAdvanceMode_ByMinimalDuration));

SilKit::DETAIL_SILKIT_DETAIL_NAMESPACE_NAME::Impl::Services::Orchestration::TimeSyncService
timeSyncService_ByMinimalDuration{
mockLifecycleService, SilKit::Services::Orchestration::TimeAdvanceMode::ByMinimalDuration};

EXPECT_CALL(capi, SilKit_TimeSyncService_Create_With_TimeAdvanceMode(testing::_, mockLifecycleService,
SilKit_TimeAdvanceMode_ByOwnDuration));

SilKit::DETAIL_SILKIT_DETAIL_NAMESPACE_NAME::Impl::Services::Orchestration::TimeSyncService
timeSyncService_ByOwnDuration{
mockLifecycleService, SilKit::Services::Orchestration::TimeAdvanceMode::ByOwnDuration};
}

TEST_F(Test_HourglassOrchestration, SilKit_TimeSyncService_SetSimulationStepHandler)
{
const std::chrono::nanoseconds initialStepSize{0x123456};
Expand Down Expand Up @@ -415,6 +434,19 @@ TEST_F(Test_HourglassOrchestration, SilKit_TimeSyncService_Now)
EXPECT_EQ(timeSyncService.Now(), nanoseconds);
}

TEST_F(Test_HourglassOrchestration, SilKit_TimeSyncService_SetStepDuration)
{
const std::chrono::nanoseconds stepDuration{0x123456};

SilKit::DETAIL_SILKIT_DETAIL_NAMESPACE_NAME::Impl::Services::Orchestration::TimeSyncService timeSyncService{
mockLifecycleService};

EXPECT_CALL(capi, SilKit_TimeSyncService_SetStepDuration(mockTimeSyncService, testing::_))
.WillOnce(Return(SilKit_ReturnCode_SUCCESS));

timeSyncService.SetStepDuration(stepDuration);
}

TEST_F(Test_HourglassOrchestration, SilKit_Experimental_TimeSyncService_AddOtherSimulationStepsCompletedHandler)
{
using testing::_;
Expand Down
5 changes: 4 additions & 1 deletion SilKit/IntegrationTests/ITest_AsyncSimTask.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -302,11 +302,12 @@ auto MakeCompletionThread(SimParticipant* p, ParticipantData* d) -> std::thread

TEST(ITest_AsyncSimTask, test_async_simtask_other_simulation_steps_completed_handler)
{
SimTestHarness testHarness({"A", "B", "C"}, "silkit://localhost:0");
SimTestHarness testHarness({"A", "B", "C", "D"}, "silkit://localhost:0");

const auto a = testHarness.GetParticipant("A");
const auto b = testHarness.GetParticipant("B");
const auto c = testHarness.GetParticipant("C");
const auto d = testHarness.GetParticipant("D");

ParticipantData ad, bd, cd;

Expand All @@ -316,6 +317,8 @@ TEST(ITest_AsyncSimTask, test_async_simtask_other_simulation_steps_completed_han
b->GetOrCreateLifecycleService()->SetStopHandler([&bd] { bd.running = false; });
c->GetOrCreateLifecycleService()->SetStopHandler([&cd] { cd.running = false; });

d->GetOrCreateTimeSyncService()->SetSimulationStepHandler([](auto, auto) {}, 1ms);

const auto aLifecycleService = a->GetOrCreateLifecycleService();

a->GetOrCreateTimeSyncService()->SetSimulationStepHandlerAsync([aLifecycleService, &ad](auto now, auto) {
Expand Down
Loading
Loading