diff --git a/examples/deluxe-interface/deluxe-interface.cpp b/examples/deluxe-interface/deluxe-interface.cpp index 82621ac..c742cce 100755 --- a/examples/deluxe-interface/deluxe-interface.cpp +++ b/examples/deluxe-interface/deluxe-interface.cpp @@ -1,272 +1,320 @@ //===-- examples/deluxe-interface/deluxe-interface.cpp ----------*- C++ -*-===// // // The RoSA Framework // //===----------------------------------------------------------------------===// /// /// \file examples/deluxe-interface/deluxe-interface.cpp /// /// \author David Juhasz (david.juhasz@tuwien.ac.at) /// /// \date 2017-2019 /// /// \brief A simple example on the \c rosa::deluxe::DeluxeContext and related /// classes. //===----------------------------------------------------------------------===// #include "rosa/config/version.h" #include "rosa/deluxe/DeluxeContext.hpp" #include #include #include using namespace rosa; using namespace rosa::deluxe; using namespace rosa::terminal; /// How many cycles of simulation to perform. const size_t NumberOfSimulationCycles = 16; int main(void) { LOG_INFO_STREAM << '\n' << library_string() << " -- " << Color::Red << "deluxe-interface example" << Color::Default << '\n'; std::unique_ptr C = DeluxeContext::create("Deluxe"); // // Create deluxe sensors. // LOG_INFO("Creating sensors."); // All sensors are created without defining a normal generator function, but // with the default value of the last argument. That, however, requires the // data type to be explicitly defined. This is good for simulation only. // The first and second sensors do not receive master-input. AgentHandle BoolSensor = C->createSensor("BoolSensor"); AgentHandle IntSensor = C->createSensor("IntSensor"); // This sensor receives master-input and dumps it to \c LOG_INFO_STREAM. const std::string FloatSensorName = "FloatSensor"; AgentHandle FloatSensor = C->createSensor( FloatSensorName, [&FloatSensorName](std::pair I) { LOG_INFO_STREAM << "\n******\n" << FloatSensorName << " master-input " << (I.second ? "" : "") << " value: " << I.first << "\n******\n"; }); + // This sensor do not receive master-input but produces tuples. + using TupleType = DeluxeTuple; + AgentHandle TupleSensor = C->createSensor("TupleSensor"); + // // Create low-level deluxe agents with \c createLowLevelAgent. // LOG_INFO("Creating low-level agents."); // All agents below dump their received values to \c LOG_INFO_STREAM on each // triggering. // This agent does not receive master-input and does not produce // master-output. It results in the value it received. const std::string BoolAgentName = "BoolAgent"; using BoolResult = Optional; using BoolHandler = std::function)>; AgentHandle BoolAgent = C->createAgent( BoolAgentName, BoolHandler([&BoolAgentName](std::pair I) -> BoolResult { LOG_INFO_STREAM << "\n******\n" << BoolAgentName << " " << (I.second ? "" : "") << " value: " << I.first << "\n******\n"; return {I.first}; })); // This agent receives master-input but does not produce master-output. The // agent maintains a state in \c IntAgentOffset. The master-input handler // updates \c IntAgentOffset according to each received (new) value from its // master. The slave-input handler results in the sum of the received value // and the actual value of \c IntAgentOffset. const std::string IntAgentName = "IntAgent"; using IntMasterHandler = std::function)>; using IntResult = Optional; using IntHandler = std::function)>; uint32_t IntAgentOffset = 0; AgentHandle IntAgent = C->createAgent( IntAgentName, // Master-input handler. IntMasterHandler([&IntAgentName, &IntAgentOffset](std::pair I) { LOG_INFO_STREAM << "\n******\n" << IntAgentName << " master-input " << (I.second ? "" : "") << " value: " << I.first << "\n******\n"; if (I.second) { IntAgentOffset = I.first; } }), // Slave-input handler. IntHandler([&IntAgentName, &IntAgentOffset](std::pair I) -> IntResult { LOG_INFO_STREAM << "\n******\n" << IntAgentName << " " << (I.second ? "" : "") << " value: " << I.first << "\n******\n"; return {I.first + IntAgentOffset}; })); // This agent receives master-input and produces master-output. The // master-input handler propagaates each received (new) value to its slave as // master-output. The slave-input handler results in the value it received and // produces no actual master-output. const std::string FloatAgentName = "FloatAgent"; using FloatMasterResult = std::tuple>; using FloatMasterHandler = std::function)>; using FloatResult = std::tuple, Optional>; using FloatHandler = std::function)>; AgentHandle FloatAgent = C->createAgent( FloatAgentName, // Master-input handler. FloatMasterHandler([&FloatAgentName]( std::pair I) -> FloatMasterResult { LOG_INFO_STREAM << "\n******\n" << FloatAgentName << " master-input " << (I.second ? "" : "") << " value: " << I.first << "\n******\n"; const auto Output = I.second ? Optional(I.first) : Optional(); return {Output}; }), // Slave-input handler. FloatHandler([&FloatAgentName](std::pair I) -> FloatResult { LOG_INFO_STREAM << "\n******\n" << FloatAgentName << " " << (I.second ? "" : "") << " value: " << I.first << "\n******\n"; return {{I.first}, {}}; })); + // This agent does not receive master-input and does not produce + // master-output. It results in the sum of the values it receives in a tuple. + const std::string TupleAgentName = "TupleAgent"; + using TupleSumResult = Optional>; + using TupleHandler = + std::function)>; + AgentHandle TupleAgent = C->createAgent( + TupleAgentName, + TupleHandler( + [&TupleAgentName](std::pair I) -> TupleSumResult { + LOG_INFO_STREAM << "\n******\n" + << TupleAgentName << " " + << (I.second ? "" : "") + << " value: " << I.first << "\n******\n"; + return {std::get<0>(I.first) + std::get<1>(I.first)}; + })); + // // Connect sensors to low-level agents. // LOG_INFO("Connect sensors to their corresponding low-level agents."); C->connectSensor(BoolAgent, 0, BoolSensor, "Bool Sensor Channel"); C->connectSensor(IntAgent, 0, IntSensor, "Int Sensor Channel"); C->connectSensor(FloatAgent, 0, FloatSensor, "Float Sensor Channel"); + C->connectSensor(TupleAgent, 0, TupleSensor, "Tuple Sensor Channel"); // // Create a high-level deluxe agent. // LOG_INFO("Create high-level agent."); + using SingleDoubleOutputType = Optional>; + using SingleUInt32OutputType = Optional>; + using NoOutputType = Optional; + // This agent does not receive master-input but produces master-output for its // slaves at positions `1` and `2` but not for that at position `0`. The agent // maintains a state in \c SumAgentState. The handler increments \c // SumAgentState upon each received (new) `true` value from its slave at // position `0`. Whenever \c SumAgentState has been updated, it is sent to the // slaves at positions `1` and `2`. The handler results in the sum of the - // values received from slaves at positions `1` and `2`. - using SumResult = std::tuple, Optional, - Optional, Optional>; + // values received from slaves at positions `1`, `2`, and `3`. + using SumResult = + std::tuple; using SumHandler = std::function, std::pair, std::pair)>; + std::pair, bool>, std::pair, bool>, + std::pair, bool>, + std::pair, bool>)>; uint32_t SumAgentState = 0; AgentHandle SumAgent = C->createAgent( "Sum Agent", - SumHandler([&SumAgentState](std::pair I0, - std::pair I1, - std::pair I2) -> SumResult { + SumHandler([&SumAgentState]( + std::pair, bool> I0, + std::pair, bool> I1, + std::pair, bool> I2, + std::pair, bool> I3) -> SumResult { + const auto V0 = std::get<0>(I0.first); + const auto V1 = std::get<0>(I1.first); + const auto V2 = std::get<0>(I2.first); + const auto V3 = std::get<0>(I3.first); LOG_INFO_STREAM << "\n*******\nSum Agent triggered with values:\n" << (I0.second ? "" : "") - << " bool value: " << I0.first << "\n" + << " bool value: " << V0 << "\n" << (I1.second ? "" : "") - << " int value: " << I1.first << "\n" + << " int value: " << V1 << "\n" << (I2.second ? "" : "") - << " float value: " << I2.first << "\n******\n"; - if (I0.second && I0.first) { + << " float value: " << V2 << "\n" + << (I3.second ? "" : "") + << " double value: " << V3 << "\n******\n"; + if (I0.second && V0) { ++SumAgentState; } - const auto MasterOutput = I0.second && I0.first - ? Optional(SumAgentState) - : Optional(); - const auto Output = I1.first + I2.first; - return {{Output}, {}, {MasterOutput}, {MasterOutput}}; + const SingleUInt32OutputType MasterOutput = + I0.second && V0 + ? SingleUInt32OutputType(DeluxeTuple(SumAgentState)) + : SingleUInt32OutputType(); + const DeluxeTuple Output = {V1 + V2 + V3}; + return {{Output}, {}, {MasterOutput}, {MasterOutput}, {}}; })); // // Connect low-level agents to the high-level agent. // LOG_INFO("Connect low-level agents to the high-level agent."); C->connectAgents(SumAgent, 0, BoolAgent, "Bool Agent Channel"); C->connectAgents(SumAgent, 1, IntAgent, "Int Agent Channel"); C->connectAgents(SumAgent, 2, FloatAgent, "Float Agent Channel"); + C->connectAgents(SumAgent, 3, TupleAgent, "Tuple Agent Channel"); // // For simulation output, create a logger agent writing the output of the // high-level agent into a log stream. // LOG_INFO("Create a logger agent."); // The agent dumps each received (new) value to \c LOG_INFO_STREAM and // produces nothing; does not receive mater-input and does not produce // master-output. AgentHandle LoggerAgent = C->createAgent("Logger Agent", std::function(std::pair)>( [](std::pair Sum) -> Optional { if (Sum.second) { LOG_INFO_STREAM << "Result: " << Sum.first << "\n"; } return {}; })); // // Connect the high-level agent to the logger agent. // LOG_INFO("Connect the high-level agent to the logger agent."); C->connectAgents(LoggerAgent, 0, SumAgent, "Sum Agent Channel"); // // Do simulation. // LOG_INFO("Setting up and performing simulation."); // // Initialize deluxe context for simulation. // C->initializeSimulation(); // // Create some vectors and register them for their corresponding sensors. // std::vector BoolValues(NumberOfSimulationCycles); std::generate(BoolValues.begin(), BoolValues.end(), [i = 0](void) mutable -> bool { return (++i % 4) == 0; }); C->registerSensorValues(BoolSensor, BoolValues.begin(), BoolValues.end()); std::vector IntValues(NumberOfSimulationCycles); std::generate(IntValues.begin(), IntValues.end(), [i = 0](void) mutable { return ++i; }); C->registerSensorValues(IntSensor, IntValues.begin(), IntValues.end()); std::vector FloatValues(NumberOfSimulationCycles); std::generate(FloatValues.begin(), FloatValues.end(), [f = 0.5f](void) mutable { f += 0.3f; return std::floor(f) + 0.5f; }); C->registerSensorValues(FloatSensor, FloatValues.begin(), FloatValues.end()); + std::vector TupleValues(NumberOfSimulationCycles); + std::generate(TupleValues.begin(), TupleValues.end(), + [f1 = 0.f, f2 = 3.14f](void) mutable -> TupleType { + f1 += f2; + f2 -= f1; + return {f1, f2}; + }); + C->registerSensorValues(TupleSensor, TupleValues.begin(), TupleValues.end()); + // // Simulate. // C->simulate(NumberOfSimulationCycles); return 0; }