package org.yamcs.xtceproc; import java.util.Collection; import java.util.Set; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.yamcs.InvalidIdentification; import org.yamcs.parameter.ParameterValue; import org.yamcs.alarms.AlarmReporter; import org.yamcs.alarms.AlarmServer; import org.yamcs.parameter.ParameterRequestManagerImpl; import org.yamcs.parameter.ParameterValueList; import org.yamcs.protobuf.Pvalue.MonitoringResult; import org.yamcs.protobuf.Pvalue.RangeCondition; import org.yamcs.protobuf.Yamcs.Value.Type; import org.yamcs.xtce.AlarmLevels; import org.yamcs.xtce.AlarmRanges; import org.yamcs.xtce.AlarmType; import org.yamcs.xtce.CriteriaEvaluator; import org.yamcs.xtce.EnumeratedParameterType; import org.yamcs.xtce.EnumerationAlarm; import org.yamcs.xtce.EnumerationAlarm.EnumerationAlarmItem; import org.yamcs.xtce.EnumerationContextAlarm; import org.yamcs.xtce.FloatParameterType; import org.yamcs.xtce.FloatRange; import org.yamcs.xtce.IntegerParameterType; import org.yamcs.xtce.NumericAlarm; import org.yamcs.xtce.NumericContextAlarm; import org.yamcs.xtce.Parameter; import org.yamcs.xtce.ParameterType; /** * Part of the TM processing chain. Is called upon by the * ParameterRequestManager whenever a new parameter value may need alarms * published together with it. */ public class AlarmChecker { private AlarmReporter alarmReporter; private AlarmServer alarmServer; private final int subscriptionId; ParameterRequestManagerImpl prm; Logger log = LoggerFactory.getLogger(this.getClass()); //keep the last values of parameters that are needed to check alarms (for alarms that are enabled/disabled based on some other parameters) ParameterValueList lastValues = new ParameterValueList(); public AlarmChecker(ParameterRequestManagerImpl prm, int subscriptionId) { this.subscriptionId = subscriptionId; this.prm = prm; } /** * Called from the ParameterRequestManager when a new parameter has been subscribed * Check and subscribe any dependencies required for alarm checking */ public void parameterSubscribed(Parameter p) { ParameterType ptype = p.getParameterType(); if(ptype==null) { log.debug("Parameter "+p.getName()+" has no type"); return; } Set<Parameter> params = ptype.getDependentParameters(); if(params!=null) { for(Parameter p1:params) { try { prm.addItemsToRequest(subscriptionId, p1); } catch (InvalidIdentification e) { log.warn("Got exception when subscribing for {} which is a dependency for {}", p1, p.getName()); } } } } /** * Update the list of parameters used for alarm checking * @param pvals */ public void updateParameters(Collection<ParameterValue> pvals) { synchronized(lastValues) { for(ParameterValue pv: pvals) { lastValues.removeFirst(pv.getParameter()); lastValues.add(pv); } } } /** * Updates the supplied ParameterValues with monitoring (out of limits) * information. */ public void performAlarmChecking(Collection<ParameterValue> pvals) { CriteriaEvaluator criteriaEvaluator = new CriteriaEvaluatorImpl(lastValues); for(ParameterValue pval:pvals) { if(pval.getParameter().getParameterType()!=null && pval.getParameter().getParameterType().hasAlarm()) { performAlarmChecking(pval, criteriaEvaluator); } //else do not set the MonitoringResult } } public void enableReporting(AlarmReporter reporter) { this.alarmReporter=reporter; } public void enableServer(AlarmServer server) { this.alarmServer = server; } /** * Updates the ParameterValue with monitoring (out of limits) information */ private void performAlarmChecking(ParameterValue pv, CriteriaEvaluator criteriaEvaluator) { ParameterType ptype=pv.getParameter().getParameterType(); if(ptype instanceof FloatParameterType) { performAlarmCheckingFloat((FloatParameterType) ptype, pv, criteriaEvaluator); } else if(ptype instanceof EnumeratedParameterType) { performAlarmCheckingEnumerated((EnumeratedParameterType) ptype, pv, criteriaEvaluator); } else if(ptype instanceof IntegerParameterType) { performAlarmCheckingInteger((IntegerParameterType) ptype, pv, criteriaEvaluator); } } private void performAlarmCheckingInteger(IntegerParameterType ipt, ParameterValue pv, CriteriaEvaluator criteriaEvaluator) { long intCalValue=0; if(pv.getEngValue().getType()==Type.SINT32) { intCalValue=pv.getEngValue().getSint32Value(); } else if(pv.getEngValue().getType()==Type.UINT32) { intCalValue=0xFFFFFFFFL & pv.getEngValue().getUint32Value(); } else if(pv.getEngValue().getType()==Type.SINT64) { intCalValue=pv.getEngValue().getSint64Value(); } else if(pv.getEngValue().getType()==Type.UINT64) { intCalValue=pv.getEngValue().getUint64Value(); } else { throw new IllegalStateException("Unexpected integer value"); } // Determine applicable ranges based on context boolean mon=false; AlarmType alarmType=null; AlarmRanges staticAlarmRanges=null; int minViolations=1; if(ipt.getContextAlarmList()!=null) { for(NumericContextAlarm nca:ipt.getContextAlarmList()) { if(nca.getContextMatch().isMet(criteriaEvaluator)) { mon=true; alarmType=nca; staticAlarmRanges=nca.getStaticAlarmRanges(); minViolations=nca.getMinViolations(); break; } } } NumericAlarm defaultAlarm=ipt.getDefaultAlarm(); if(!mon && defaultAlarm!=null) { alarmType=defaultAlarm; staticAlarmRanges=defaultAlarm.getStaticAlarmRanges(); minViolations=defaultAlarm.getMinViolations(); } // Set MonitoringResult pv.setMonitoringResult(null); // The default is DISABLED, but set it to null, so that below code is more readable if(staticAlarmRanges!=null) { checkStaticAlarmRanges(pv, intCalValue, staticAlarmRanges); } // Notify when severity changes if(alarmReporter!=null) { alarmReporter.reportNumericParameterEvent(pv, alarmType, minViolations); } if(alarmServer!=null) { alarmServer.update(pv, minViolations); } } private void performAlarmCheckingFloat(FloatParameterType fpt, ParameterValue pv, CriteriaEvaluator criteriaEvaluator) { double doubleCalValue=0; if(pv.getEngValue().getType()==Type.FLOAT) { doubleCalValue=pv.getEngValue().getFloatValue(); } else if(pv.getEngValue().getType()==Type.DOUBLE) { doubleCalValue=pv.getEngValue().getDoubleValue(); } else { throw new IllegalStateException("Unexpected float value"); } // Determine applicable AlarmType based on context boolean mon=false; AlarmType alarmType=null; AlarmRanges staticAlarmRanges=null; int minViolations=1; if(fpt.getContextAlarmList()!=null) { for(NumericContextAlarm nca:fpt.getContextAlarmList()) { if(nca.getContextMatch().isMet(criteriaEvaluator)) { mon=true; alarmType=nca; staticAlarmRanges=nca.getStaticAlarmRanges(); minViolations=nca.getMinViolations(); break; } } } NumericAlarm defaultAlarm=fpt.getDefaultAlarm(); if(!mon && defaultAlarm!=null) { alarmType=defaultAlarm; staticAlarmRanges=defaultAlarm.getStaticAlarmRanges(); minViolations=defaultAlarm.getMinViolations(); } // Set MonitoringResult pv.setMonitoringResult(null); // The default is DISABLED, but set it to null, so that below code is more readable if(staticAlarmRanges!=null) { checkStaticAlarmRanges(pv, doubleCalValue, staticAlarmRanges); } // Notify when severity changes if(alarmReporter!=null) { alarmReporter.reportNumericParameterEvent(pv, alarmType, minViolations); } if(alarmServer!=null) { alarmServer.update(pv, minViolations); } } /** * Verify limits, giving priority to highest severity */ private void checkStaticAlarmRanges(ParameterValue pv, double doubleCalValue, AlarmRanges staticAlarmRanges) { pv.setMonitoringResult(null); FloatRange watchRange=staticAlarmRanges.getWatchRange(); FloatRange warningRange=staticAlarmRanges.getWarningRange(); FloatRange distressRange=staticAlarmRanges.getDistressRange(); FloatRange criticalRange=staticAlarmRanges.getCriticalRange(); FloatRange severeRange=staticAlarmRanges.getSevereRange(); if(severeRange!=null) { if(severeRange.getMinInclusive()>doubleCalValue) { pv.setMonitoringResult(MonitoringResult.SEVERE); pv.setRangeCondition(RangeCondition.LOW); } else if(severeRange.getMaxInclusive()<doubleCalValue) { pv.setMonitoringResult(MonitoringResult.SEVERE); pv.setRangeCondition(RangeCondition.HIGH); } } if(pv.getMonitoringResult()==null && criticalRange!=null) { if(criticalRange.getMinInclusive()>doubleCalValue) { pv.setMonitoringResult(MonitoringResult.CRITICAL); pv.setRangeCondition(RangeCondition.LOW); } else if(criticalRange.getMaxInclusive()<doubleCalValue) { pv.setMonitoringResult(MonitoringResult.CRITICAL); pv.setRangeCondition(RangeCondition.HIGH); } } if(pv.getMonitoringResult()==null && distressRange!=null) { if(distressRange.getMinInclusive()>doubleCalValue) { pv.setMonitoringResult(MonitoringResult.DISTRESS); pv.setRangeCondition(RangeCondition.LOW); } else if(distressRange.getMaxInclusive()<doubleCalValue) { pv.setMonitoringResult(MonitoringResult.DISTRESS); pv.setRangeCondition(RangeCondition.HIGH); } } if(pv.getMonitoringResult()==null && warningRange!=null) { if(warningRange.getMinInclusive()>doubleCalValue) { pv.setMonitoringResult(MonitoringResult.WARNING); pv.setRangeCondition(RangeCondition.LOW); } else if(warningRange.getMaxInclusive()<doubleCalValue) { pv.setMonitoringResult(MonitoringResult.WARNING); pv.setRangeCondition(RangeCondition.HIGH); } } if(pv.getMonitoringResult()==null && watchRange!=null) { if(watchRange.getMinInclusive()>doubleCalValue) { pv.setMonitoringResult(MonitoringResult.WATCH); pv.setRangeCondition(RangeCondition.LOW); } else if(watchRange.getMaxInclusive()<doubleCalValue) { pv.setMonitoringResult(MonitoringResult.WATCH); pv.setRangeCondition(RangeCondition.HIGH); } } if (pv.getMonitoringResult() == null) { pv.setMonitoringResult(MonitoringResult.IN_LIMITS); } pv.setWatchRange(watchRange); pv.setWarningRange(warningRange); pv.setDistressRange(distressRange); pv.setCriticalRange(criticalRange); pv.setSevereRange(severeRange); } private void performAlarmCheckingEnumerated(EnumeratedParameterType ept, ParameterValue pv, CriteriaEvaluator criteriaEvaluator) { pv.setMonitoringResult(null); // Default is DISABLED, but that doesn't seem fit when we are checking String s=pv.getEngValue().getStringValue(); EnumerationAlarm alarm=ept.getDefaultAlarm(); int minViolations=(alarm==null)?1:alarm.getMinViolations(); if(ept.getContextAlarmList()!=null) { for(EnumerationContextAlarm nca:ept.getContextAlarmList()) { if(nca.getContextMatch().isMet(criteriaEvaluator)) { alarm=nca; minViolations=nca.getMinViolations(); break; } } } if(alarm != null) { AlarmLevels level=alarm.getDefaultAlarmLevel(); for(EnumerationAlarmItem eai:alarm.getAlarmList()) { if(eai.getEnumerationLabel().equals(s)) level=eai.getAlarmLevel(); } switch(level) { case normal: pv.setMonitoringResult(MonitoringResult.IN_LIMITS); break; case watch: pv.setMonitoringResult(MonitoringResult.WATCH); break; case warning: pv.setMonitoringResult(MonitoringResult.WARNING); break; case distress: pv.setMonitoringResult(MonitoringResult.DISTRESS); break; case critical: pv.setMonitoringResult(MonitoringResult.CRITICAL); break; case severe: pv.setMonitoringResult(MonitoringResult.SEVERE); break; } if(alarmReporter!=null) { alarmReporter.reportEnumeratedParameterEvent(pv, alarm, minViolations); } } if(alarmServer!=null) { alarmServer.update(pv, minViolations); } } public int getSubscriptionId() { return subscriptionId; } }