/* * LimitCheckMonitor.h * * Created on: 21.07.2014 * Author: baetz */ #ifndef LIMITCHECKMONITOR_H_ #define LIMITCHECKMONITOR_H_ #include #include #include #include #include #include #include #include template class LimitCheckMonitor: public MonitoringIF { public: struct CheckParameters { CheckParameters() : oldState(HasReturnvaluesIF::RETURN_OK), parameterId( PoolVariableIF::NO_PARAMETER), sendTransitionreport( false), sendTransitionEvent(false), lowerTransitionEvent( 0), upperTransitionEvent(0), reportingObject(0), currentCounter( 0), maxCounter(0) { } CheckParameters(ReturnValue_t oldState, const uint32_t parameterId, bool sendTransitionreport, bool sendTransitionEvent, Event lowerTransitionEvent, Event upperTransitionEvent, const object_id_t reportingObject, uint16_t maxCounter = 0) : oldState(oldState), parameterId(parameterId), sendTransitionreport( sendTransitionreport), sendTransitionEvent( sendTransitionEvent), lowerTransitionEvent( lowerTransitionEvent), upperTransitionEvent( upperTransitionEvent), reportingObject(reportingObject), currentCounter( 0), maxCounter(maxCounter) { } ReturnValue_t oldState; const uint32_t parameterId; bool sendTransitionreport; bool sendTransitionEvent; Event lowerTransitionEvent; Event upperTransitionEvent; const object_id_t reportingObject; uint16_t currentCounter; uint16_t maxCounter; }; LimitCheckMonitor(object_id_t reportAs, uint32_t parameterId, T initialLower, T initialUpper, bool generateReports = true, bool throwEvents = false, Event lowerTransitionEvent = 0, Event upperTransitionEvent = 0, uint16_t confirmationNumber = 0) : lowerLimit(initialLower), upperLimit(initialUpper), parameters( UNCHECKED, parameterId, generateReports, throwEvents, lowerTransitionEvent, upperTransitionEvent, reportAs, confirmationNumber) { lowerLimit.setNext(&upperLimit); } virtual ~LimitCheckMonitor() { } virtual ReturnValue_t check() { DataSet mySet; PIDReader parameter(parameters.parameterId, &mySet); mySet.read(); if (!parameter.isValid()) { if (parameters.oldState != INVALID) { MonitoringReportContent report(parameter.getParameterId(), 0, 0, parameters.oldState, INVALID); LimitViolationReporter::sendLimitViolationReport(&report); parameters.oldState = INVALID; } } else { parameters.oldState = doCheck(parameter.value, lowerLimit, upperLimit, ¶meters); } return parameters.oldState; } static ReturnValue_t doCheck(T value, T lowerLimit, T upperLimit, CheckParameters* checkParameters, ReturnValue_t lowerReturnCode = BELOW_LOW_LIMIT, ReturnValue_t upperReturnCode = ABOVE_HIGH_LIMIT) { return doCheck(value, lowerLimit, upperLimit, checkParameters->oldState, checkParameters->parameterId, checkParameters->sendTransitionreport, checkParameters->sendTransitionEvent, checkParameters->lowerTransitionEvent, checkParameters->upperTransitionEvent, checkParameters->reportingObject, &checkParameters->currentCounter, checkParameters->maxCounter, lowerReturnCode, upperReturnCode); } static ReturnValue_t doCheck(T value, T lowerLimit, T upperLimit, ReturnValue_t oldState, uint32_t parameterId, bool sendTransitionreport, bool sendTransitionEvent, Event lowerTransitionEvent, Event upperTransitionEvent, object_id_t reportingObject, uint16_t *currentCounter = NULL, uint16_t maxCounter = 0, ReturnValue_t lowerReturnCode = BELOW_LOW_LIMIT, ReturnValue_t upperReturnCode = ABOVE_HIGH_LIMIT) { uint16_t tempCounter = 0; if (currentCounter == NULL) { currentCounter = &tempCounter; maxCounter = 0; } ReturnValue_t currentState = HasReturnvaluesIF::RETURN_OK; T crossedLimit = 0; if (value > upperLimit) { currentState = upperReturnCode; crossedLimit = upperLimit; } else if (value < lowerLimit) { currentState = lowerReturnCode; crossedLimit = lowerLimit; } if (oldState != currentState) { //confirmation *currentCounter += 1; if (*currentCounter > maxCounter || oldState == UNCHECKED) { *currentCounter = 0; // Distinction of 3 cases: up/down/(ok or default) if (currentState == upperReturnCode) { if (sendTransitionEvent) { EventManagerIF::triggerEvent(reportingObject, upperTransitionEvent, 0, 0); } } else if (currentState == lowerReturnCode) { if (sendTransitionEvent) { EventManagerIF::triggerEvent(reportingObject, lowerTransitionEvent, 0, 0); } } else { // RETURN_OK or all other cases if (oldState == lowerReturnCode) { crossedLimit = lowerLimit; } else { crossedLimit = upperLimit; } } if (sendTransitionreport) { MonitoringReportContent report(parameterId, value, crossedLimit, oldState, currentState); LimitViolationReporter::sendLimitViolationReport(&report); } else { currentState = UNSELECTED; } } else { currentState = oldState; } } else { *currentCounter = 0; } return currentState; } ReturnValue_t setLimits(uint8_t type, const uint8_t* data, uint32_t size) { if (type != getLimitType()) { return WRONG_TYPE; } UpdateLimitMonitorContent content; if (size != content.getSerializedSize()) { return INVALID_SIZE; } int32_t tempSize = size; const uint8_t* pBuffer = data; ReturnValue_t result = content.deSerialize(&pBuffer, &tempSize, true); if (result != HasReturnvaluesIF::RETURN_OK) { return result; } setLimits(content.lowValue, content.highValue); return HasReturnvaluesIF::RETURN_OK; } void setLimits(T lower, T upper) { lowerLimit = lower; upperLimit = upper; } ReturnValue_t setChecking(uint8_t strategy) { if ((strategy & REPORT_EVENTS_ONLY) != 0) { parameters.sendTransitionEvent = true; } else { parameters.sendTransitionEvent = false; } if ((strategy & REPORT_REPORTS_ONLY) != 0) { parameters.sendTransitionreport = true; } else { parameters.sendTransitionreport = false; } return HasReturnvaluesIF::RETURN_OK; } ReturnValue_t setToUnchecked() { return setToState(UNCHECKED, ¶meters); } static ReturnValue_t setToUnchecked(CheckParameters* parameters) { if (parameters->oldState != UNCHECKED) { MonitoringReportContent report(parameters->parameterId, 0, 0, parameters->oldState, UNCHECKED); LimitViolationReporter::sendLimitViolationReport(&report); parameters->oldState = UNCHECKED; } return HasReturnvaluesIF::RETURN_OK; } static ReturnValue_t setToState(ReturnValue_t newState, CheckParameters* parameters) { if (parameters->oldState != newState) { MonitoringReportContent report(parameters->parameterId, 0, 0, parameters->oldState, newState); LimitViolationReporter::sendLimitViolationReport(&report); parameters->oldState = newState; } return HasReturnvaluesIF::RETURN_OK; } ReturnValue_t serialize(uint8_t** buffer, uint32_t* size, const uint32_t max_size, bool bigEndian) const { return SerialLinkedListAdapter::serialize(&lowerLimit, buffer, size, max_size, bigEndian); } uint32_t getSerializedSize() const { return SerialLinkedListAdapter::getSerializedSize( &lowerLimit); } ReturnValue_t deSerialize(const uint8_t** buffer, int32_t* size, bool bigEndian) { return SerialLinkedListAdapter::deSerialize(&lowerLimit, buffer, size, bigEndian); } const uint8_t getLimitType() const { return LIMIT_TYPE_LIMIT_CHECK; } const uint32_t getLimitId() const { return parameters.parameterId; } T getLowerLimit() { return lowerLimit; } T getUpperLimit() { return upperLimit; } private: SerializeElement lowerLimit; SerializeElement upperLimit; CheckParameters parameters; }; //TODO: This is for float only, as this is currently the only need. typedef LinkedElementDecorator, MonitoringIF> LinkedLimitMonitor; #endif /* LIMITCHECKMONITOR_H_ */