Newer
Older
/*!
* \author Nadeem Shehzad (DESY)
* \date 15.05.2019
* \page statusmonitordoc Status Monitor
*
* To monitor a status of a varaible in an appplicaiton this group of
* modules provides different possiblites.
* It includes
* - MaxMonitor to monitor a value depending upon two MAX thresholds for warning and error.
* - MinMonitor to monitor a value depending upon two MIN thresholds for warning and error.
* - RangeMonitor to monitor a value depending upon two ranges of thresholds for warning and error.
* - ExactMonitor to monitor a value which should be exactly same as required value.
* - StateMonitor to monitor On/Off state.
* Depending upon the value and condition on of the four states are reported.
* - OFF, OK, WARNING, ERROR.
* Checkout the status monitor example to see in detail how it works.
* \include demoStatusMonitor.cc
/**
For more info see \ref statusmonitordoc
\example demoStatusMonitor.cc
*/
/** Generic modules for status monitoring.
* Each module monitors an input variable and depending upon the
* conditions reports four different states.
*/
namespace ChimeraTK {
/** There are four states that can be reported*/
enum States { OFF, OK, WARNING, ERROR };
template<typename T>
struct StatusMonitor : public ApplicationModule {
/** Number of convience constructors for ease of use.
* The input and output variable names can be given by user which
* should be mapped with the variables of module to be watched.
*/
Martin Killenberg
committed
StatusMonitor(EntityOwner* owner, const std::string& name, const std::string& description, const std::string& input,
const std::string& output, HierarchyModifier modifier, const std::unordered_set<std::string>& outputTags = {},
const std::unordered_set<std::string>& parameterTags = {}, const std::unordered_set<std::string>& tags = {})
: ApplicationModule(owner, name, description, modifier, tags), _parameterTags(parameterTags), oneUp(this, input),
status(this, output, "", "", outputTags) {}
StatusMonitor() { throw logic_error("Default constructor unusable. Just exists to work around gcc bug."); }
~StatusMonitor() override {}
void prepare() override {}
/**Tags for parameters. This makes it easier to connect them to e.g, to control system*/
std::unordered_set<std::string> _parameterTags;
/**Input value that should be monitored. It is moved one level up, so it's parallel to this monitor object.*/
struct OneUp : public VariableGroup {
Martin Killenberg
committed
OneUp(EntityOwner* owner, const std::string& watchName)
: VariableGroup(owner, "hidden", "", HierarchyModifier::oneUpAndHide), watch(this, watchName, "", "") {}
ScalarPushInput<T> watch;
} oneUp;
/**One of four possible states to be reported*/
ScalarOutput<uint16_t> status;
};
/** Module for status monitoring depending on a maximum threshold value*/
template<typename T>
struct MaxMonitor : public StatusMonitor<T> {
using StatusMonitor<T>::StatusMonitor;
Martin Killenberg
committed
/** WARNING state to be reported if threshold is reached or exceeded*/
Martin Killenberg
committed
ScalarPushInput<T> warning{this, "upperWarningThreshold", "", "", StatusMonitor<T>::_parameterTags};
Martin Killenberg
committed
/** ERROR state to be reported if threshold is reached or exceeded*/
Martin Killenberg
committed
ScalarPushInput<T> error{this, "upperErrorThreshold", "", "", StatusMonitor<T>::_parameterTags};
/**This is where state evaluation is done*/
void mainLoop() {
/** If there is a change either in value monitored or in thershold values, the status is re-evaluated*/
ReadAnyGroup group{StatusMonitor<T>::oneUp.watch, warning, error};
while(true) {
// evaluate and publish first, then read and wait. This takes care of the publishing the initial variables
Martin Killenberg
committed
if(StatusMonitor<T>::oneUp.watch >= error) {
StatusMonitor<T>::status = ERROR;
}
Martin Killenberg
committed
else if(StatusMonitor<T>::oneUp.watch >= warning) {
StatusMonitor<T>::status = WARNING;
}
else {
StatusMonitor<T>::status = OK;
}
StatusMonitor<T>::status.write();
}
}
};
/** Module for status monitoring depending on a minimum threshold value*/
template<typename T>
struct MinMonitor : public StatusMonitor<T> {
using StatusMonitor<T>::StatusMonitor;
/** WARNING state to be reported if threshold is crossed*/
Martin Killenberg
committed
ScalarPushInput<T> warning{this, "lowerWarningThreshold", "", "", StatusMonitor<T>::_parameterTags};
/** ERROR state to be reported if threshold is crossed*/
Martin Killenberg
committed
ScalarPushInput<T> error{this, "lowerErrorThreshold", "", "", StatusMonitor<T>::_parameterTags};
/**This is where state evaluation is done*/
void mainLoop() {
/** If there is a change either in value monitored or in thershold values, the status is re-evaluated*/
ReadAnyGroup group{StatusMonitor<T>::oneUp.watch, warning, error};
while(true) {
Martin Killenberg
committed
if(StatusMonitor<T>::oneUp.watch <= error) {
StatusMonitor<T>::status = ERROR;
}
Martin Killenberg
committed
else if(StatusMonitor<T>::oneUp.watch <= warning) {
StatusMonitor<T>::status = WARNING;
}
else {
StatusMonitor<T>::status = OK;
}
StatusMonitor<T>::status.write();
}
}
};
/** Module for status monitoring depending on range of threshold values.
* As long as a monitored value is in the range defined by user it goes
* to error or warning state. If the monitored value exceeds the upper limmit
Martin Killenberg
committed
* or goes under the lowerthreshold the state reported will be always OK.
* IMPORTANT: This module does not check for ill logic, so make sure to
* set the ranges correctly to issue warning or error.
*/
template<typename T>
struct RangeMonitor : public StatusMonitor<T> {
using StatusMonitor<T>::StatusMonitor;
/** WARNING state to be reported if value is in between the upper and
Martin Killenberg
committed
* lower threshold including the start and end of thresholds.
Martin Killenberg
committed
ScalarPushInput<T> warningUpperThreshold{this, "upperWarningThreshold", "", "", StatusMonitor<T>::_parameterTags};
ScalarPushInput<T> warningLowerThreshold{this, "lowerWarningThreshold", "", "", StatusMonitor<T>::_parameterTags};
/** ERROR state to be reported if value is in between the upper and
Martin Killenberg
committed
* lower threshold including the start and end of thresholds.
Martin Killenberg
committed
ScalarPushInput<T> errorUpperThreshold{this, "upperErrorThreshold", "", "", StatusMonitor<T>::_parameterTags};
ScalarPushInput<T> errorLowerThreshold{this, "lowerErrorThreshold", "", "", StatusMonitor<T>::_parameterTags};
/**This is where state evaluation is done*/
void mainLoop() {
/** If there is a change either in value monitored or in thershold values, the status is re-evaluated*/
ReadAnyGroup group{StatusMonitor<T>::oneUp.watch, warningUpperThreshold, warningLowerThreshold,
errorUpperThreshold, errorLowerThreshold};
while(true) {
// Check for error limits first. Like this they supersede the warning,
// even if they are stricter then the warning limits (mis-configuration)
if(StatusMonitor<T>::oneUp.watch <= errorLowerThreshold ||
StatusMonitor<T>::oneUp.watch >= errorUpperThreshold) {
StatusMonitor<T>::status = ERROR;
}
else if(StatusMonitor<T>::oneUp.watch <= warningLowerThreshold ||
StatusMonitor<T>::oneUp.watch >= warningUpperThreshold) {
StatusMonitor<T>::status = WARNING;
}
else {
StatusMonitor<T>::status = OK;
}
StatusMonitor<T>::status.write();
}
}
};
/** Module for status monitoring of an exact value.
* If value monitored is not exactly the same. an error state will be
* reported.*/
template<typename T>
struct ExactMonitor : public StatusMonitor<T> {
using StatusMonitor<T>::StatusMonitor;
/**ERROR state if value is not equal to requiredValue*/
Martin Killenberg
committed
ScalarPushInput<T> requiredValue{this, "requiredValue", "", "", StatusMonitor<T>::_parameterTags};
/**This is where state evaluation is done*/
void mainLoop() {
/** If there is a change either in value monitored or in requiredValue, the status is re-evaluated*/
ReadAnyGroup group{StatusMonitor<T>::oneUp.watch, requiredValue};
while(true) {
StatusMonitor<T>::status = ERROR;
}
else {
StatusMonitor<T>::status = OK;
}
StatusMonitor<T>::status.write();
}
}
};
/** Module for On/off status monitoring.
* If value monitored is different then desired state (on/off) an error
* will be reported, otherwise OFF(0) or OK(1) depending on state.
*/
template<typename T>
struct StateMonitor : public StatusMonitor<T> {
using StatusMonitor<T>::StatusMonitor;
Martin Killenberg
committed
/// The state that we are supposed to have
ScalarPushInput<T> nominalState{this, "nominalState", "", "", StatusMonitor<T>::_parameterTags};
/**This is where state evaluation is done*/
void mainLoop() {
/** If there is a change either in value monitored or in state, the status is re-evaluated*/
ReadAnyGroup group{StatusMonitor<T>::oneUp.watch, nominalState};
while(true) {
StatusMonitor<T>::status = ERROR;
}
Martin Killenberg
committed
else if(nominalState == OK || nominalState == OFF) {
StatusMonitor<T>::status = nominalState;
}
StatusMonitor<T>::status = ERROR;
StatusMonitor<T>::status.write();
}
}
};
} // namespace ChimeraTK