diff --git a/apps/ccam/ccam.cpp b/apps/ccam/ccam.cpp index a00334b..d9b7d97 100644 --- a/apps/ccam/ccam.cpp +++ b/apps/ccam/ccam.cpp @@ -1,567 +1,581 @@ //===-- apps/ccam/ccam.cpp --------------------------------------*- C++ -*-===// // // The RoSA Framework -- Application CCAM // // Distributed under the terms and conditions of the Boost Software /// License 1.0. // See accompanying file LICENSE. // // If you did not receive a copy of the license file, see // http://www.boost.org/LICENSE_1_0.txt. // //===----------------------------------------------------------------------===// /// /// \file apps/ccam/ccam.cpp /// /// \author Maximilian Goetzinger (maximilian.goetzinger@tuwien.ac.at) /// \author Benedikt Tutzer (benedikt.tutzer@tuwien.ac.at) /// /// \date 2019 /// /// \brief The application CCAM implements the case study from the paper: /// M. Goetzinger, N. TaheriNejad, H. A. Kholerdi, A. Jantsch, E. Willegger, /// T. Glatzl, A.M. Rahmani, T.Sauter, P. Liljeberg: Model - Free Condition /// Monitoring with Confidence /// /// \todo Clean up source files of this app: add standard RoSA header comment /// for own files and do something with 3rd party files... //===----------------------------------------------------------------------===// #include "rosa/agent/Abstraction.hpp" #include "rosa/agent/Confidence.hpp" #include "rosa/agent/FunctionAbstractions.hpp" #include #include "rosa/config/version.h" #include "rosa/agent/SignalStateDetector.hpp" #include "rosa/agent/SystemStateDetector.hpp" #include "rosa/app/Application.hpp" #include "rosa/support/csv/CSVReader.hpp" #include "rosa/support/csv/CSVWriter.hpp" #include "rosa/support/mqtt/MQTTReader.hpp" #include "rosa/app/AppTuple.hpp" #include #include #include #include #include "configuration.h" #include "statehandlerutils.h" using namespace rosa; using namespace rosa::agent; using namespace rosa::app; using namespace rosa::terminal; using namespace rosa::mqtt; const std::string AppName = "CCAM"; int main(int argc, char **argv) { LOG_INFO_STREAM << '\n' << library_string() << " -- " << Color::Red << AppName << "app" << Color::Default << '\n'; // // Read the filepath of the config file of the observed system. The filepath // is in the first argument passed to the application. Fuzzy functions etc. // are described in this file. // if (argc < 2) { LOG_ERROR("Specify config File!\nUsage:\n\tccam config.json"); return 1; } std::string ConfigPath = argv[1]; // // Load config file and read in all parameters. Fuzzy functions etc. are // described in this file. // if (!readConfigFile(ConfigPath)) { LOG_ERROR_STREAM << "Could not read config from \"" << ConfigPath << "\"\n"; return 2; } // // Create a CCAM context. // LOG_INFO("Creating Context"); std::unique_ptr AppCCAM = Application::create(AppName); // // Create following function which shall give information if the time gap // between changed input(s) and changed output(s) shows already a malfunction // of the system. // // ____________ // / // / // __________/ // std::shared_ptr> BrokenDelayFunction( new PartialFunction( {{{0, AppConfig.BrokenCounter}, std::make_shared>( 0, 0.f, AppConfig.BrokenCounter, 1.f)}, {{AppConfig.BrokenCounter, std::numeric_limits::max()}, std::make_shared>(1.f, 0.f)}}, 0.f)); // // Create following function which shall give information if the time gap // between changed input(s) and changed output(s) still shows a // well-functioning system. // // ____________ // \ // \ // \__________ // std::shared_ptr> OkDelayFunction( new PartialFunction( {{{0, AppConfig.BrokenCounter}, std::make_shared>( 0, 1.f, AppConfig.BrokenCounter, 0.f)}, {{AppConfig.BrokenCounter, std::numeric_limits::max()}, std::make_shared>(0.f, 0.f)}}, 1.f)); // // Create a AppAgent with SystemStateDetector functionality. // LOG_INFO("Create SystemStateDetector agent."); AgentHandle SystemStateDetectorAgent = createSystemStateDetectorAgent( AppCCAM, "SystemStateDetector", AppConfig.SignalConfigurations.size(), BrokenDelayFunction, OkDelayFunction); // // Set policy of SystemStateDetectorAgent that it wait for all // SignalStateDetectorAgents // std::set pos; for (size_t i = 0; i < AppConfig.SignalConfigurations.size(); ++i) pos.insert(pos.end(), i); AppCCAM->setExecutionPolicy(SystemStateDetectorAgent, AppExecutionPolicy::awaitAll(pos)); // // Create Vectors for all sensors, all signal related fuzzy functions, all // signal state detectors, all signal state agents, and all input data files. // LOG_INFO("Creating sensors, SignalStateDetector functionalities and their " "Abstractions."); std::vector Sensors; std::vector>> SampleMatchesFunctions; std::vector>> SampleMismatchesFunctions; std::vector>> SignalIsStableFunctions; std::vector>> SignalIsDriftingFunctions; std::vector>> NumOfSamplesMatchFunctions; std::vector>> NumOfSamplesMismatchFunctions; std::vector>> SampleValidFunctions; std::vector>> SampleInvalidFunctions; std::vector>> NumOfSamplesValidFunctions; std::vector>> NumOfSamplesInvalidFunctions; std::vector>> SignalStateDetectors; std::vector SignalStateDetectorAgents; std::vector DataFiles; // // Go through all signal state configurations (number of signals), and create // functionalities for SignalStateDetector. // for (auto SignalConfiguration : AppConfig.SignalConfigurations) { // // Create application sensors. // Sensors.emplace_back( AppCCAM->createSensor(SignalConfiguration.Name + "_Sensor")); // // Create following function(s) which shall give information whether one // sample matches another one (based on the relative distance between them). // // ____________ // / \ // / \ // __________/ \__________ // // SampleMatchesFunctions.emplace_back(new PartialFunction( { {{-SignalConfiguration.OuterBound, -SignalConfiguration.InnerBound}, std::make_shared>( -SignalConfiguration.OuterBound, 0.f, -SignalConfiguration.InnerBound, 1.f)}, {{-SignalConfiguration.InnerBound, SignalConfiguration.InnerBound}, std::make_shared>(1.f, 0.f)}, {{SignalConfiguration.InnerBound, SignalConfiguration.OuterBound}, std::make_shared>( SignalConfiguration.InnerBound, 1.f, SignalConfiguration.OuterBound, 0.f)}, }, 0)); // // Create following function(s) which shall give information whether one // sample mismatches another one (based on the relative distance between // them). // // ____________ ____________ // \ / // \ / // \__________/ // // SampleMismatchesFunctions.emplace_back(new PartialFunction( { {{-SignalConfiguration.OuterBound, -SignalConfiguration.InnerBound}, std::make_shared>( -SignalConfiguration.OuterBound, 1.f, -SignalConfiguration.InnerBound, 0.f)}, {{-SignalConfiguration.InnerBound, SignalConfiguration.InnerBound}, std::make_shared>(0.f, 0.f)}, {{SignalConfiguration.InnerBound, SignalConfiguration.OuterBound}, std::make_shared>( SignalConfiguration.InnerBound, 0.f, SignalConfiguration.OuterBound, 1.f)}, }, 1)); // // Create following function(s) which shall give information whether a // signal is stable. // // ____________ // / \ // / \ // __________/ \__________ // // SignalIsStableFunctions.emplace_back(new PartialFunction( { {{-SignalConfiguration.OuterBoundDrift, -SignalConfiguration.InnerBoundDrift}, std::make_shared>( -SignalConfiguration.OuterBoundDrift, 0.f, -SignalConfiguration.InnerBoundDrift, 1.f)}, {{-SignalConfiguration.InnerBoundDrift, SignalConfiguration.InnerBoundDrift}, std::make_shared>(1.f, 0.f)}, {{SignalConfiguration.InnerBoundDrift, SignalConfiguration.OuterBoundDrift}, std::make_shared>( SignalConfiguration.InnerBoundDrift, 1.f, SignalConfiguration.OuterBoundDrift, 0.f)}, }, 0)); // // Create following function(s) which shall give information whether a // signal is drifting. // // ____________ ____________ // \ / // \ / // \__________/ // // SignalIsDriftingFunctions.emplace_back(new PartialFunction( { {{-SignalConfiguration.OuterBoundDrift, -SignalConfiguration.InnerBoundDrift}, std::make_shared>( -SignalConfiguration.OuterBoundDrift, 1.f, -SignalConfiguration.InnerBoundDrift, 0.f)}, {{-SignalConfiguration.InnerBoundDrift, SignalConfiguration.InnerBoundDrift}, std::make_shared>(0.f, 0.f)}, {{SignalConfiguration.InnerBoundDrift, SignalConfiguration.OuterBoundDrift}, std::make_shared>( SignalConfiguration.InnerBoundDrift, 0.f, SignalConfiguration.OuterBoundDrift, 1.f)}, }, 1)); // // Create following function(s) which shall give information how many // history samples match another sample. // // ____________ // / // / // __________/ // NumOfSamplesMatchFunctions.emplace_back(new StepFunction( 1.0f / SignalConfiguration.SampleHistorySize, StepDirection::StepUp)); // // Create following function(s) which shall give information how many // history samples mismatch another sample. // // ____________ // \ // \ // \__________ // NumOfSamplesMismatchFunctions.emplace_back(new StepFunction( 1.0f / SignalConfiguration.SampleHistorySize, StepDirection::StepDown)); // // Create following function(s) which shall give information how good all // samples in a state match each other. // // ____________ // / \ // / \ // __________/ \__________ // // SampleValidFunctions.emplace_back(new PartialFunction( { {{-SignalConfiguration.OuterBound, -SignalConfiguration.InnerBound}, std::make_shared>( -SignalConfiguration.OuterBound, 0.f, -SignalConfiguration.InnerBound, 1.f)}, {{-SignalConfiguration.InnerBound, SignalConfiguration.InnerBound}, std::make_shared>(1.f, 0.f)}, {{SignalConfiguration.InnerBound, SignalConfiguration.OuterBound}, std::make_shared>( SignalConfiguration.InnerBound, 1.f, SignalConfiguration.OuterBound, 0.f)}, }, 0)); // // Create following function(s) which shall give information how good all // samples in a state mismatch each other. // // ____________ ____________ // \ / // \ / // \__________/ // // SampleInvalidFunctions.emplace_back(new PartialFunction( { {{-SignalConfiguration.OuterBound, -SignalConfiguration.InnerBound}, std::make_shared>( -SignalConfiguration.OuterBound, 1.f, -SignalConfiguration.InnerBound, 0.f)}, {{-SignalConfiguration.InnerBound, SignalConfiguration.InnerBound}, std::make_shared>(0.f, 0.f)}, {{SignalConfiguration.InnerBound, SignalConfiguration.OuterBound}, std::make_shared>( SignalConfiguration.InnerBound, 0.f, SignalConfiguration.OuterBound, 1.f)}, }, 1)); // // Create following function(s) which shall give information how many // history samples match each other. // // ____________ // / // / // __________/ // NumOfSamplesValidFunctions.emplace_back(new StepFunction( 1.0f / SignalConfiguration.SampleHistorySize, StepDirection::StepUp)); // // Create following function(s) which shall give information how many // history samples mismatch each other. // // ____________ // \ // \ // \__________ // NumOfSamplesInvalidFunctions.emplace_back(new StepFunction( 1.0f / SignalConfiguration.SampleHistorySize, StepDirection::StepDown)); // // Create SignalStateDetector functionality // SignalStateDetectors.emplace_back( new SignalStateDetector( SignalConfiguration.Output ? SignalProperties::OUTPUT : SignalProperties::INPUT, std::numeric_limits::max(), SampleMatchesFunctions.back(), SampleMismatchesFunctions.back(), NumOfSamplesMatchFunctions.back(), NumOfSamplesMismatchFunctions.back(), SampleValidFunctions.back(), SampleInvalidFunctions.back(), NumOfSamplesValidFunctions.back(), NumOfSamplesInvalidFunctions.back(), SignalIsDriftingFunctions.back(), SignalIsStableFunctions.back(), SignalConfiguration.SampleHistorySize, SignalConfiguration.DABSize, SignalConfiguration.DABHistorySize)); // // Create low-level application agents // SignalStateDetectorAgents.push_back(createSignalStateDetectorAgent( AppCCAM, SignalConfiguration.Name, SignalStateDetectors.back())); AppCCAM->setExecutionPolicy( SignalStateDetectorAgents.back(), AppExecutionPolicy::decimation(AppConfig.DownsamplingRate)); // // Connect sensors to low-level agents. // LOG_INFO("Connect sensors to their corresponding low-level agents."); AppCCAM->connectSensor(SignalStateDetectorAgents.back(), 0, Sensors.back(), SignalConfiguration.Name + "_Sensor ->" + SignalConfiguration.Name + "_SignalStateDetector_Agent-Channel"); AppCCAM->connectAgents( SystemStateDetectorAgent, SignalStateDetectors.size() - 1, SignalStateDetectorAgents.back(), SignalConfiguration.Name + "_SignalStateDetector_Agent->SystemStateDetector_Agent_Channel"); } // // For simulation output, create a logger agent writing the output of the // high-level agent into a CSV file. // LOG_INFO("Create a logger agent."); // Create CSV writer. std::ofstream OutputCSV(AppConfig.OutputFilePath); for (auto SignalConfiguration : AppConfig.SignalConfigurations) { OutputCSV << SignalConfiguration.Name + ","; } OutputCSV << "StateID,"; OutputCSV << "Confidence State Valid,"; OutputCSV << "Confidence State Invalid,"; OutputCSV << "Confidence Inputs Matching,"; OutputCSV << "Confidence Inputs Mismatching,"; OutputCSV << "Confidence Outputs Matching,"; OutputCSV << "Confidence Outputs Mismatching,"; OutputCSV << "Confidence State Stable,"; OutputCSV << "Confidence State Drifting,"; OutputCSV << "State Condition,"; OutputCSV << "Confidence System Functioning,"; OutputCSV << "Confidence System Malfunctioning,"; OutputCSV << "Overall Confidence,"; + //=== Log Signal State Detector Outputs ===// + for (auto SignalConfiguration : AppConfig.SignalConfigurations) { + OutputCSV << SignalConfiguration.Name + " StateID,"; + OutputCSV << SignalConfiguration.Name + " Confidence Matching,"; + OutputCSV << SignalConfiguration.Name + " Confidence Mismatching,"; + OutputCSV << SignalConfiguration.Name + " Confidence State Valid,"; + OutputCSV << SignalConfiguration.Name + " Confidence State Invalid,"; + OutputCSV << SignalConfiguration.Name + " Confidence State Stable,"; + OutputCSV << SignalConfiguration.Name + " Confidence State Drifting,"; + + OutputCSV << SignalConfiguration.Name + " StateJustGotValid,"; + OutputCSV << SignalConfiguration.Name + " StateValidAfterReentrance,"; + } + //===// OutputCSV << "\n"; // The agent writes each new input value into a CSV file and produces // nothing. using Input = std::pair; using Result = Optional>; using Handler = std::function; std::string Name = "Logger Agent"; AgentHandle LoggerAgent = AppCCAM->createAgent( "Logger Agent", Handler([&OutputCSV](Input I) -> Result { const SystemStateTuple &T = I.first; OutputCSV << std::get<0>( static_cast &>(T)) << std::endl; return Result(); })); // // Connect the high-level agent to the logger agent. // LOG_INFO("Connect the high-level agent to the logger agent."); AppCCAM->connectAgents(LoggerAgent, 0, SystemStateDetectorAgent, "SystemStateDetector Channel"); // // Only log if the SystemStateDetector actually ran // AppCCAM->setExecutionPolicy(LoggerAgent, AppExecutionPolicy::awaitAll({0})); // // Do simulation. // LOG_INFO("Setting up and performing simulation."); // // Initialize application for simulation. // AppCCAM->initializeSimulation(); // // Open CSV files and register them for their corresponding sensors. // // Make sure DataFiles will not change capacity while adding elements to it. // Changing capacity moves elements away, which invalidates references // captured by CSVIterator. DataFiles.reserve(AppConfig.SignalConfigurations.size()); uint32_t i = 0; bool hasMQTT = false; for (auto SignalConfiguration : AppConfig.SignalConfigurations) { switch (SignalConfiguration.DataInterfaceType) { case DataInterfaceTypes::CSV: DataFiles.emplace_back(SignalConfiguration.InputPath); if (!DataFiles.at(i)) { LOG_ERROR_STREAM << "Cannot open Input File \"" << SignalConfiguration.InputPath << "\" for Signal \"" << SignalConfiguration.Name << "\"" << std::endl; return 3; } AppCCAM->registerSensorValues(Sensors.at(i), csv::CSVIterator(DataFiles.at(i)), csv::CSVIterator()); LOG_INFO_STREAM << "Sensor " << SignalConfiguration.Name << " is fed by csv file " << SignalConfiguration.InputPath << std::endl; break; case DataInterfaceTypes::MQTT: { hasMQTT = true; auto it = MQTTIterator(SignalConfiguration.MQTTTopic); AppCCAM->registerSensorValues(Sensors.at(i), std::move(it), MQTTIterator()); LOG_INFO_STREAM << "Sensor " << SignalConfiguration.Name << " is fed by MQTT topic " << SignalConfiguration.MQTTTopic << std::endl; break; } default: LOG_ERROR_STREAM << "No data source for " << SignalConfiguration.Name << std::endl; break; } i++; } // // Start simulation. // auto &log = LOG_WARNING_STREAM; log << "Simulation starting."; if (hasMQTT) { log << " Publishing MQTT messages may start."; } log << std::endl; AppCCAM->simulate(AppConfig.NumberOfSimulationCycles); return 0; } diff --git a/apps/ccam/statehandlerutils.h b/apps/ccam/statehandlerutils.h index 99efe19..2c9d38f 100644 --- a/apps/ccam/statehandlerutils.h +++ b/apps/ccam/statehandlerutils.h @@ -1,274 +1,290 @@ #ifndef STATEHANDLERUTILS_H #define STATEHANDLERUTILS_H #include "rosa/agent/Abstraction.hpp" #include "rosa/agent/Confidence.hpp" #include "rosa/agent/FunctionAbstractions.hpp" #include #include #include #include #include "rosa/config/version.h" #include "rosa/agent/SignalStateDetector.hpp" #include "rosa/agent/SystemStateDetector.hpp" #include "rosa/app/Application.hpp" #include "rosa/support/csv/CSVReader.hpp" #include "rosa/support/csv/CSVWriter.hpp" #include #include #include #include using namespace rosa; using namespace rosa::agent; using namespace rosa::app; using namespace rosa::terminal; // For the convinience to write a shorter data type name using SignalStateTuple = AppTuple; AgentHandle createSignalStateDetectorAgent( std::unique_ptr &C, const std::string &Name, std::shared_ptr< SignalStateDetector> SigSD) { using Input = std::pair, bool>; using Result = Optional; using Handler = std::function; return C->createAgent( Name, Handler([&, Name, SigSD](Input I) -> Result { LOG_INFO_STREAM << "\n******\n" << Name << " " << (I.second ? "" : "") << " value: " << std::get<0>( static_cast &>(I.first)) << "\n******\n"; auto StateInfo = SigSD->detectSignalState( std::get<0>(static_cast &>(I.first))); if (I.second) { SignalStateTuple Res = { std::get<0>(static_cast &>(I.first)), StateInfo.StateID, StateInfo.SignalProperty, StateInfo.ConfidenceOfMatchingState, StateInfo.ConfidenceOfMismatchingState, StateInfo.ConfidenceStateIsValid, StateInfo.ConfidenceStateIsInvalid, StateInfo.ConfidenceStateIsStable, StateInfo.ConfidenceStateIsDrifting, StateInfo.StateCondition, StateInfo.NumberOfInsertedSamplesAfterEntrance, static_cast( (StateInfo.StateIsValid ? 4 : 0) + (StateInfo.StateJustGotValid ? 2 : 0) + (StateInfo.StateIsValidAfterReentrance ? 1 : 0))}; return Result(Res); } return Result(); })); } // System State using SystemStateTuple = AppTuple; template struct Handler_helper; template struct function_helper { static_assert(std::conjunction_v...>, "All types need to be identical"); static B function(A valA, As... valAs) { std::vector ar({valA, valAs...}); return func()(ar); } }; template struct Handler_helper<0, ret, functype, typeA, B...> { using handler = function_helper; }; template struct Handler_helper { using handler = typename Handler_helper, B...>::handler; }; template using Handler = typename Handler_helper::handler; // TODO: Change it from global to local variable if possible std::shared_ptr< SystemStateDetector> SysSD; template struct function { ret operator()(A a) { std::vector> SignalStateInfos; std::stringstream OutString; for (auto _SignalStateTuple : a) { // convert tuple to info struct out.push_back({}); OutString << std::get<0>(_SignalStateTuple.first) << ","; SignalStateInformation Info; Info.StateID = std::get<1>(_SignalStateTuple.first); Info.SignalProperty = static_cast(std::get<2>(_SignalStateTuple.first)); Info.ConfidenceOfMatchingState = std::get<3>(_SignalStateTuple.first); Info.ConfidenceOfMismatchingState = std::get<4>(_SignalStateTuple.first); Info.ConfidenceStateIsValid = std::get<5>(_SignalStateTuple.first); Info.ConfidenceStateIsInvalid = std::get<6>(_SignalStateTuple.first); Info.ConfidenceStateIsStable = std::get<7>(_SignalStateTuple.first); Info.ConfidenceStateIsDrifting = std::get<8>(_SignalStateTuple.first); Info.StateCondition = static_cast(std::get<9>(_SignalStateTuple.first)); Info.NumberOfInsertedSamplesAfterEntrance = std::get<10>(_SignalStateTuple.first); Info.StateIsValid = (std::get<11>(_SignalStateTuple.first) & 4) > 0; Info.StateJustGotValid = (std::get<11>(_SignalStateTuple.first) & 2) > 0; Info.StateIsValidAfterReentrance = (std::get<11>(_SignalStateTuple.first) & 1) > 0; SignalStateInfos.push_back(Info); } SystemStateInformation SystemStateInfo = SysSD->detectSystemState(SignalStateInfos); OutString << SystemStateInfo.StateID << ","; OutString << SystemStateInfo.ConfidenceStateIsValid << ","; OutString << SystemStateInfo.ConfidenceStateIsInvalid << ","; OutString << SystemStateInfo.ConfidenceOfInputsMatchingState << ","; OutString << SystemStateInfo.ConfidenceOfInputsMismatchingState << ","; OutString << SystemStateInfo.ConfidenceOfOutputsMatchingState << ","; OutString << SystemStateInfo.ConfidenceOfOutputsMismatchingState << ","; + OutString << SystemStateInfo.ConfidenceStateIsStable << ","; + OutString << SystemStateInfo.ConfidenceStateIsDrifting << ","; OutString << SystemStateInfo.StateCondition << ","; OutString << SystemStateInfo.ConfidenceSystemIsFunctioning << ","; OutString << SystemStateInfo.ConfidenceSystemIsMalfunctioning << ","; OutString << SystemStateInfo.ConfidenceOfAllDecisions << ","; + + //=== Log Signal State Detector Outputs ===// + for (auto SSI : SignalStateInfos) { + OutString << SSI.StateID << ","; + OutString << SSI.ConfidenceOfMatchingState << ","; + OutString << SSI.ConfidenceOfMismatchingState << ","; + OutString << SSI.ConfidenceStateIsValid << ","; + OutString << SSI.ConfidenceStateIsInvalid << ","; + OutString << SSI.ConfidenceStateIsStable << ","; + OutString << SSI.ConfidenceStateIsDrifting << ","; + + OutString << SSI.StateJustGotValid << ","; + OutString << SSI.StateIsValidAfterReentrance << ","; + } return ret(std::make_tuple(OutString.str())); } }; using arr = std::vector>; template AgentHandle createSystemStateDetectorAgent( std::unique_ptr &C, const std::string &Name, std::shared_ptr> BrokenDelayFunction, std::shared_ptr> OkDelayFunction) { LOG_TRACE("Creating fixed SystemStateDetectorAgent"); using Input = SignalStateTuple; using Result = Optional; std::shared_ptr< SystemStateDetector> _SysSD( new SystemStateDetector( std::numeric_limits::max(), NumOfSlaves, BrokenDelayFunction, OkDelayFunction)); SysSD = _SysSD; auto HandlerFunction = Handler, arr>, Input>::function; return C->createAgent(Name, std::function(HandlerFunction)); } AgentHandle createSystemStateDetectorAgent( std::unique_ptr &C, const std::string &Name, size_t NumOfSlaves, std::shared_ptr> BrokenDelayFunction, std::shared_ptr> OkDelayFunction) { LOG_TRACE("Creating dynamic SystemStateDetectorAgent"); switch (NumOfSlaves) { // clang-format off case 2: return createSystemStateDetectorAgent< 2>(C, Name, BrokenDelayFunction, OkDelayFunction); case 3: return createSystemStateDetectorAgent< 3>(C, Name, BrokenDelayFunction, OkDelayFunction); case 4: return createSystemStateDetectorAgent< 4>(C, Name, BrokenDelayFunction, OkDelayFunction); case 5: return createSystemStateDetectorAgent< 5>(C, Name, BrokenDelayFunction, OkDelayFunction); case 6: return createSystemStateDetectorAgent< 6>(C, Name, BrokenDelayFunction, OkDelayFunction); case 7: return createSystemStateDetectorAgent< 7>(C, Name, BrokenDelayFunction, OkDelayFunction); case 8: return createSystemStateDetectorAgent< 8>(C, Name, BrokenDelayFunction, OkDelayFunction); case 9: return createSystemStateDetectorAgent< 9>(C, Name, BrokenDelayFunction, OkDelayFunction); case 10: return createSystemStateDetectorAgent<10>(C, Name, BrokenDelayFunction, OkDelayFunction); case 11: return createSystemStateDetectorAgent<11>(C, Name, BrokenDelayFunction, OkDelayFunction); case 12: return createSystemStateDetectorAgent<12>(C, Name, BrokenDelayFunction, OkDelayFunction); case 13: return createSystemStateDetectorAgent<13>(C, Name, BrokenDelayFunction, OkDelayFunction); case 14: return createSystemStateDetectorAgent<14>(C, Name, BrokenDelayFunction, OkDelayFunction); case 15: return createSystemStateDetectorAgent<15>(C, Name, BrokenDelayFunction, OkDelayFunction); case 16: return createSystemStateDetectorAgent<16>(C, Name, BrokenDelayFunction, OkDelayFunction); case 17: return createSystemStateDetectorAgent<17>(C, Name, BrokenDelayFunction, OkDelayFunction); case 18: return createSystemStateDetectorAgent<18>(C, Name, BrokenDelayFunction, OkDelayFunction); case 19: return createSystemStateDetectorAgent<19>(C, Name, BrokenDelayFunction, OkDelayFunction); case 20: return createSystemStateDetectorAgent<20>(C, Name, BrokenDelayFunction, OkDelayFunction); case 21: return createSystemStateDetectorAgent<21>(C, Name, BrokenDelayFunction, OkDelayFunction); case 22: return createSystemStateDetectorAgent<22>(C, Name, BrokenDelayFunction, OkDelayFunction); case 23: return createSystemStateDetectorAgent<23>(C, Name, BrokenDelayFunction, OkDelayFunction); case 24: return createSystemStateDetectorAgent<24>(C, Name, BrokenDelayFunction, OkDelayFunction); case 25: return createSystemStateDetectorAgent<25>(C, Name, BrokenDelayFunction, OkDelayFunction); case 1: default: return createSystemStateDetectorAgent<1>(C, Name, BrokenDelayFunction, OkDelayFunction); // clang-format on } } // template // AgentHandle createMQTTSensor(std::string MQTTTopic) { // using Input = void; // using Result = Optional; // using Handler = std::function; // return C->createAgent( // Name, Handler([&, Name, SigSD](Input I) -> Result { // LOG_INFO_STREAM << "\n******\n" // << Name << " " << (I.second ? "" : "") // << " value: " // << std::get<0>( // static_cast &>(I.first)) // << "\n******\n"; // auto StateInfo = SigSD->detectSignalState( // std::get<0>(static_cast &>(I.first))); // if (I.second) { // SignalStateTuple Res = { // std::get<0>(static_cast &>(I.first)), // StateInfo.StateID, // StateInfo.SignalProperty, // StateInfo.ConfidenceOfMatchingState, // StateInfo.ConfidenceOfMismatchingState, // StateInfo.ConfidenceStateIsValid, // StateInfo.ConfidenceStateIsInvalid, // StateInfo.ConfidenceStateIsStable, // StateInfo.ConfidenceStateIsDrifting, // StateInfo.StateCondition, // StateInfo.NumberOfInsertedSamplesAfterEntrance, // static_cast( // (StateInfo.StateIsValid ? 4 : 0) + // (StateInfo.StateJustGotValid ? 2 : 0) + // (StateInfo.StateIsValidAfterReentrance ? 1 : 0))}; // return Result(Res); // } // return Result(); // })); // } #endif // STATEHANDLERUTILS_H