Skip to content

Commit

Permalink
SILKIT-1413 Demos do not support AbortSimulation (#732)
Browse files Browse the repository at this point in the history
* SILKIT-1413 Made demos handle simulation abort

* SILKIT-1413 Renamed messages to avoid confusion with stop state

* SILKIT-1413 Refactored demos to consistently use 'finalStateFuture'

* SILKIT-1413 Cleaned up namespace usings in demos

* SILKIT-1413 Updated CHANGELOG.rst

* SILKIT-1413 Improvements from code review

* Improved messages: Simulation is left, not stopped
* More concise state checks
* Final state is always 'ShutDown' in async mode
* Shared variable must be atomic

* SILKIT-1413 Improvements from code review #2

* Participants must also wait for state ReadyToRun
  • Loading branch information
AndreasRentschler authored and GitHub Enterprise committed Dec 12, 2023
1 parent e64e22e commit 857d011
Show file tree
Hide file tree
Showing 10 changed files with 314 additions and 209 deletions.
4 changes: 2 additions & 2 deletions Demos/Benchmark/BenchmarkDemo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -568,14 +568,14 @@ int main(int argc, char** argv)
catch (const SilKit::ConfigurationError& error)
{
std::cerr << "Invalid configuration: " << error.what() << std::endl;
std::cout << "Press enter to stop the process..." << std::endl;
std::cout << "Press enter to end the process..." << std::endl;
std::cin.ignore();
return -2;
}
catch (const std::exception& error)
{
std::cerr << "Something went wrong: " << error.what() << std::endl;
std::cout << "Press enter to stop the process..." << std::endl;
std::cout << "Press enter to end the process..." << std::endl;
std::cin.ignore();
return -3;
}
Expand Down
4 changes: 2 additions & 2 deletions Demos/Benchmark/LatencyDemo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -464,14 +464,14 @@ int main(int argc, char** argv)
catch (const SilKit::ConfigurationError& error)
{
std::cerr << "Invalid configuration: " << error.what() << std::endl;
std::cout << "Press enter to stop the process..." << std::endl;
std::cout << "Press enter to end the process..." << std::endl;
std::cin.ignore();
return -2;
}
catch (const std::exception& error)
{
std::cerr << "Something went wrong: " << error.what() << std::endl;
std::cout << "Press enter to stop the process..." << std::endl;
std::cout << "Press enter to end the process..." << std::endl;
std::cin.ignore();
return -3;
}
Expand Down
57 changes: 32 additions & 25 deletions Demos/Can/CanDemo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,9 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#include "silkit/services/can/string_utils.hpp"


using namespace SilKit::Services;
using namespace SilKit::Services::Orchestration;
using namespace SilKit::Services::Can;
using namespace SilKit::Services::Logging;

using namespace std::chrono_literals;

Expand All @@ -53,7 +54,7 @@ std::ostream& operator<<(std::ostream& out, nanoseconds timestamp)
} // namespace chrono
} // namespace std

void FrameTransmitHandler(const CanFrameTransmitEvent& ack, Logging::ILogger* logger)
void FrameTransmitHandler(const CanFrameTransmitEvent& ack, ILogger* logger)
{
std::stringstream buffer;
buffer << ">> " << ack.status
Expand All @@ -62,7 +63,7 @@ void FrameTransmitHandler(const CanFrameTransmitEvent& ack, Logging::ILogger* lo
logger->Info(buffer.str());
}

void FrameHandler(const CanFrameEvent& frameEvent, Logging::ILogger* logger)
void FrameHandler(const CanFrameEvent& frameEvent, ILogger* logger)
{
std::string payload(frameEvent.frame.dataField.begin(), frameEvent.frame.dataField.end());
std::stringstream buffer;
Expand All @@ -72,7 +73,7 @@ void FrameHandler(const CanFrameEvent& frameEvent, Logging::ILogger* logger)
logger->Info(buffer.str());
}

void SendFrame(ICanController* controller, Logging::ILogger* logger)
void SendFrame(ICanController* controller, ILogger* logger)
{
CanFrame canFrame {};
canFrame.canId = 3;
Expand Down Expand Up @@ -173,26 +174,23 @@ int main(int argc, char** argv)
FrameHandler(frameEvent, logger);
});

auto operationMode = (
runSync ? SilKit::Services::Orchestration::OperationMode::Coordinated
: SilKit::Services::Orchestration::OperationMode::Autonomous
);
auto operationMode = (runSync ? OperationMode::Coordinated : OperationMode::Autonomous);

auto* lifecycleService = participant->CreateLifecycleService({operationMode});

// Set a Stop Handler
// Observe state changes
lifecycleService->SetStopHandler([]() {
std::cout << "Stop handler called" << std::endl;
});

// Set a Shutdown Handler
lifecycleService->SetShutdownHandler([]() {
std::cout << "Shutdown handler called" << std::endl;
});
lifecycleService->SetAbortHandler([](auto lastState) {
std::cout << "Abort handler called while in state " << lastState << std::endl;
});

if (runSync)
{
// Set a CommunicationReady Handler
lifecycleService->SetCommunicationReadyHandler([canController, &participantName]() {
std::cout << "Communication ready for " << participantName << std::endl;
canController->SetBaudRate(10'000, 1'000'000, 2'000'000);
Expand Down Expand Up @@ -224,32 +222,35 @@ int main(int argc, char** argv)
auto finalState = finalStateFuture.get();

std::cout << "Simulation stopped. Final State: " << finalState << std::endl;
std::cout << "Press enter to stop the process..." << std::endl;
std::cout << "Press enter to end the process..." << std::endl;
std::cin.ignore();
}
else
{
bool isStopped = false;
std::atomic<bool> isStopRequested = {false};
std::thread workerThread;

std::promise<void> promiseObj;
std::future<void> futureObj = promiseObj.get_future();
// Set a CommunicationReady Handler
lifecycleService->SetCommunicationReadyHandler([&]() {
std::cout << "Communication ready for " << participantName << std::endl;
canController->SetBaudRate(10'000, 1'000'000, 2'000'000);

workerThread = std::thread{[&]() {
futureObj.get();
while (!isStopped)
while (lifecycleService->State() == ParticipantState::ReadyToRun ||
lifecycleService->State() == ParticipantState::Running)
{
if (participantName == "CanWriter")
{
SendFrame(canController, logger);
}
std::this_thread::sleep_for(sleepTimePerTick);
}
lifecycleService->Stop("User requested to Stop");
}
if (!isStopRequested)
{
std::cout << "Press enter to end the process..." << std::endl;
}
}};
canController->Start();
});
Expand All @@ -258,30 +259,36 @@ int main(int argc, char** argv)
promiseObj.set_value();
});

auto futureLifecycleState = lifecycleService->StartLifecycle();
std::cout << "Press enter to stop the process..." << std::endl;
lifecycleService->StartLifecycle();
std::cout << "Press enter to leave the simulation..." << std::endl;
std::cin.ignore();

isStopped = true;
isStopRequested = true;
if (lifecycleService->State() == ParticipantState::Running ||
lifecycleService->State() == ParticipantState::Paused)
{
std::cout << "User requested to stop in state " << lifecycleService->State() << std::endl;
lifecycleService->Stop("User requested to stop");
}

if (workerThread.joinable())
{
workerThread.join();
}
auto finalState = futureLifecycleState.get();
std::cout << "Simulation stopped. Final state: " << finalState << std::endl;
std::cout << "The participant has shut down and left the simulation" << std::endl;
}
}
catch (const SilKit::ConfigurationError& error)
{
std::cerr << "Invalid configuration: " << error.what() << std::endl;
std::cout << "Press enter to stop the process..." << std::endl;
std::cout << "Press enter to end the process..." << std::endl;
std::cin.ignore();
return -2;
}
catch (const std::exception& error)
{
std::cerr << "Something went wrong: " << error.what() << std::endl;
std::cout << "Press enter to stop the process..." << std::endl;
std::cout << "Press enter to end the process..." << std::endl;
std::cin.ignore();
return -3;
}
Expand Down
69 changes: 39 additions & 30 deletions Demos/Ethernet/EthernetDemo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#include "silkit/services/orchestration/string_utils.hpp"


using namespace SilKit::Services;
using namespace SilKit::Services::Orchestration;
using namespace SilKit::Services::Ethernet;

using namespace std::chrono_literals;

Expand Down Expand Up @@ -73,7 +74,7 @@ std::vector<uint8_t> CreateFrame(const EthernetMac& destinationAddress, const Et
return raw;
}

std::string GetPayloadStringFromFrame(const Ethernet::EthernetFrame& frame)
std::string GetPayloadStringFromFrame(const EthernetFrame& frame)
{
const size_t FrameHeaderSize = 2 * sizeof(EthernetMac) + sizeof(EtherType);

Expand All @@ -83,9 +84,9 @@ std::string GetPayloadStringFromFrame(const Ethernet::EthernetFrame& frame)
return payloadString;
}

void FrameTransmitHandler(Ethernet::IEthernetController* /*controller*/, const Ethernet::EthernetFrameTransmitEvent& frameTransmitEvent)
void FrameTransmitHandler(IEthernetController* /*controller*/, const EthernetFrameTransmitEvent& frameTransmitEvent)
{
if (frameTransmitEvent.status == Ethernet::EthernetTransmitStatus::Transmitted)
if (frameTransmitEvent.status == EthernetTransmitStatus::Transmitted)
{
std::cout << ">> ACK for Ethernet frame with userContext=" << frameTransmitEvent.userContext << std::endl;
}
Expand All @@ -94,18 +95,18 @@ void FrameTransmitHandler(Ethernet::IEthernetController* /*controller*/, const E
std::cout << ">> NACK for Ethernet frame with userContext=" << frameTransmitEvent.userContext;
switch (frameTransmitEvent.status)
{
case Ethernet::EthernetTransmitStatus::Transmitted:
case EthernetTransmitStatus::Transmitted:
break;
case Ethernet::EthernetTransmitStatus::InvalidFrameFormat:
case EthernetTransmitStatus::InvalidFrameFormat:
std::cout << ": InvalidFrameFormat";
break;
case Ethernet::EthernetTransmitStatus::ControllerInactive:
case EthernetTransmitStatus::ControllerInactive:
std::cout << ": ControllerInactive";
break;
case Ethernet::EthernetTransmitStatus::LinkDown:
case EthernetTransmitStatus::LinkDown:
std::cout << ": LinkDown";
break;
case Ethernet::EthernetTransmitStatus::Dropped:
case EthernetTransmitStatus::Dropped:
std::cout << ": Dropped";
break;
}
Expand All @@ -114,7 +115,7 @@ void FrameTransmitHandler(Ethernet::IEthernetController* /*controller*/, const E
}
}

void FrameHandler(Ethernet::IEthernetController* /*controller*/, const Ethernet::EthernetFrameEvent& frameEvent)
void FrameHandler(IEthernetController* /*controller*/, const EthernetFrameEvent& frameEvent)
{
auto frame = frameEvent.frame;
auto payload = GetPayloadStringFromFrame(frame);
Expand All @@ -123,7 +124,7 @@ void FrameHandler(Ethernet::IEthernetController* /*controller*/, const Ethernet:
<< "\"" << std::endl;
}

void SendFrame(Ethernet::IEthernetController* controller, const EthernetMac& from, const EthernetMac& to)
void SendFrame(IEthernetController* controller, const EthernetMac& from, const EthernetMac& to)
{
static int frameId = 0;
std::stringstream stream;
Expand All @@ -137,7 +138,7 @@ void SendFrame(Ethernet::IEthernetController* controller, const EthernetMac& fro
const auto userContext = reinterpret_cast<void *>(static_cast<intptr_t>(frameId));

auto frame = CreateFrame(to, from, payload);
controller->SendFrame(Ethernet::EthernetFrame{frame}, userContext);
controller->SendFrame(EthernetFrame{frame}, userContext);
std::cout << "<< ETH Frame sent with userContext=" << userContext << std::endl;
}

Expand Down Expand Up @@ -214,19 +215,19 @@ int main(int argc, char** argv)
ethernetController->AddFrameHandler(&FrameHandler);
ethernetController->AddFrameTransmitHandler(&FrameTransmitHandler);

auto operationMode = (runSync ? SilKit::Services::Orchestration::OperationMode::Coordinated
: SilKit::Services::Orchestration::OperationMode::Autonomous);
auto operationMode = (runSync ? OperationMode::Coordinated : OperationMode::Autonomous);
auto* lifecycleService = participant->CreateLifecycleService({operationMode});

// Set a Stop Handler
// Observe state changes
lifecycleService->SetStopHandler([]() {
std::cout << "Stop handler called" << std::endl;
});

// Set a Shutdown Handler
lifecycleService->SetShutdownHandler([]() {
std::cout << "Shutdown handler called" << std::endl;
});
lifecycleService->SetAbortHandler([](auto lastState) {
std::cout << "Abort handler called while in state " << lastState << std::endl;
});

if (runSync)
{
Expand Down Expand Up @@ -263,62 +264,70 @@ int main(int argc, char** argv)
auto finalState = finalStateFuture.get();

std::cout << "Simulation stopped. Final State: " << finalState << std::endl;
std::cout << "Press enter to stop the process..." << std::endl;
std::cout << "Press enter to end the process..." << std::endl;
std::cin.ignore();
}
else
{
std::promise<void> startHandlerPromise;
auto startHandlerFuture = startHandlerPromise.get_future();
bool isStopped = false;
std::atomic<bool> isStopRequested = {false};
std::thread workerThread;
// Set a CommunicationReady Handler

lifecycleService->SetCommunicationReadyHandler([&]() {
std::cout << "Communication ready handler called for " << participantName << std::endl;
workerThread = std::thread{[&]() {
startHandlerFuture.get();
while (!isStopped)
while (lifecycleService->State() == ParticipantState::ReadyToRun ||
lifecycleService->State() == ParticipantState::Running)
{
if (participantName == "EthernetWriter")
{
SendFrame(ethernetController, WriterMacAddr, BroadcastMacAddr);
}
std::this_thread::sleep_for(1s);
}
lifecycleService->Stop("User requested to Stop");
if (!isStopRequested)
{
std::cout << "Press enter to end the process..." << std::endl;
}
}};
ethernetController->Activate();
});


lifecycleService->SetStartingHandler([&]() {
startHandlerPromise.set_value();
});

auto finalStateFuture = lifecycleService->StartLifecycle();
std::cout << "Press enter to stop the process..." << std::endl;
lifecycleService->StartLifecycle();
std::cout << "Press enter to leave the simulation..." << std::endl;
std::cin.ignore();

isStopped = true;
isStopRequested = true;
if (lifecycleService->State() == ParticipantState::Running ||
lifecycleService->State() == ParticipantState::Paused)
{
std::cout << "User requested to stop in state " << lifecycleService->State() << std::endl;
lifecycleService->Stop("User requested to stop");
}
if (workerThread.joinable())
{
workerThread.join();
}
auto finalState = finalStateFuture.get();
std::cout << "Simulation stopped. Final State: " << finalState << std::endl;
std::cout << "The participant has shut down and left the simulation" << std::endl;
}
}
catch (const SilKit::ConfigurationError& error)
{
std::cerr << "Invalid configuration: " << error.what() << std::endl;
std::cout << "Press enter to stop the process..." << std::endl;
std::cout << "Press enter to end the process..." << std::endl;
std::cin.ignore();
return -2;
}
catch (const std::exception& error)
{
std::cerr << "Something went wrong: " << error.what() << std::endl;
std::cout << "Press enter to stop the process..." << std::endl;
std::cout << "Press enter to end the process..." << std::endl;
std::cin.ignore();
return -3;
}
Expand Down
Loading

0 comments on commit 857d011

Please sign in to comment.