|
| 1 | +// SPDX-FileCopyrightText: 2024 Vector Informatik GmbH |
| 2 | +// |
| 3 | +// SPDX-License-Identifier: MIT |
| 4 | + |
| 5 | +#include <iostream> |
| 6 | +#include <random> |
| 7 | + |
| 8 | +#include "silkit/SilKit.hpp" |
| 9 | + |
| 10 | +using namespace std::chrono_literals; |
| 11 | + |
| 12 | +std::ostream& operator<<(std::ostream& out, std::chrono::nanoseconds timestamp) |
| 13 | +{ |
| 14 | + out << std::chrono::duration_cast<std::chrono::milliseconds>(timestamp).count() << "ms"; |
| 15 | + return out; |
| 16 | +} |
| 17 | + |
| 18 | +int main(int argc, char** argv) |
| 19 | +{ |
| 20 | + if (argc != 2) |
| 21 | + { |
| 22 | + std::cerr << "Wrong number of arguments! Start demo with: " << argv[0] << " <ParticipantName>" << std::endl; |
| 23 | + return -1; |
| 24 | + } |
| 25 | + std::string participantName(argv[1]); |
| 26 | + |
| 27 | + try |
| 28 | + { |
| 29 | + // Setup participant, lifecycle, time synchronization and logging. |
| 30 | + const std::string registryUri = "silkit://localhost:8500"; |
| 31 | + const std::string configString = R"({"Logging":{"Sinks":[{"Type":"Stdout","Level":"Info"}]}})"; |
| 32 | + auto participantConfiguration = SilKit::Config::ParticipantConfigurationFromString(configString); |
| 33 | + |
| 34 | + auto participant = SilKit::CreateParticipant(participantConfiguration, participantName, registryUri); |
| 35 | + auto logger = participant->GetLogger(); |
| 36 | + |
| 37 | + auto* lifecycleService = |
| 38 | + participant->CreateLifecycleService({SilKit::Services::Orchestration::OperationMode::Coordinated}); |
| 39 | + |
| 40 | + auto* timeSyncService = lifecycleService->CreateTimeSyncService(SilKit::Services::Orchestration::TimeAdvanceMode::ByMinimalDuration); |
| 41 | + |
| 42 | + const auto stepSize = 10ms; |
| 43 | + static int stepCounter = 0; |
| 44 | + std::random_device rd; |
| 45 | + std::mt19937 rng(rd()); |
| 46 | + auto bounded_rand = [&rng](unsigned range) { |
| 47 | + std::uniform_int_distribution<unsigned> dist(1, range); |
| 48 | + return dist(rng); |
| 49 | + }; |
| 50 | + |
| 51 | + |
| 52 | + timeSyncService->SetSimulationStepHandler( |
| 53 | + [logger, timeSyncService, participantName, bounded_rand](std::chrono::nanoseconds now, |
| 54 | + std::chrono::nanoseconds duration) { |
| 55 | + // The invocation of this handler marks the beginning of a simulation step. |
| 56 | + { |
| 57 | + std::stringstream ss; |
| 58 | + ss << "--------- Simulation step T=" << now << ", duration=" << duration << " ---------"; |
| 59 | + logger->Info(ss.str()); |
| 60 | + } |
| 61 | + |
| 62 | + if (bounded_rand(10) == 1)// && participantName == "P1") |
| 63 | + { |
| 64 | + auto rndStepDuration = bounded_rand(10); |
| 65 | + timeSyncService->SetStepDuration(std::chrono::milliseconds(rndStepDuration)); |
| 66 | + std::stringstream ss; |
| 67 | + ss << "--------- Changing step size to " << rndStepDuration << "ms ---------"; |
| 68 | + logger->Info(ss.str()); |
| 69 | + } |
| 70 | + |
| 71 | + std::this_thread::sleep_for(500ms); |
| 72 | + // All messages sent here are guaranteed to arrive at other participants before their next simulation step is called. |
| 73 | + // So here, we can rely on having received all messages from the past (< now). |
| 74 | + // Note that this guarantee only holds for messages sent within a simulation step, |
| 75 | + // not for messages send outside of this handler (e.g. directly in a reception handler). |
| 76 | + |
| 77 | + // Returning from the handler marks the end of a simulation step. |
| 78 | + }, stepSize); |
| 79 | + |
| 80 | + auto finalStateFuture = lifecycleService->StartLifecycle(); |
| 81 | + finalStateFuture.get(); |
| 82 | + } |
| 83 | + catch (const std::exception& error) |
| 84 | + { |
| 85 | + std::cerr << "Something went wrong: " << error.what() << std::endl; |
| 86 | + return -2; |
| 87 | + } |
| 88 | + |
| 89 | + return 0; |
| 90 | +} |
0 commit comments