From 2e109fc8185f6d348df503c174856f2f05360bce Mon Sep 17 00:00:00 2001 From: "Samuele E. Locatelli" Date: Wed, 19 Sep 2018 17:35:37 +0200 Subject: [PATCH] Aggiunto DataItemRed... --- MTC_Adapter/OPC-UA-REDIS/DataItemRed.cs | 378 ++++++++++++++++++++++++ 1 file changed, 378 insertions(+) diff --git a/MTC_Adapter/OPC-UA-REDIS/DataItemRed.cs b/MTC_Adapter/OPC-UA-REDIS/DataItemRed.cs index e290794..c2890fd 100644 --- a/MTC_Adapter/OPC-UA-REDIS/DataItemRed.cs +++ b/MTC_Adapter/OPC-UA-REDIS/DataItemRed.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; namespace OPC_UA_REDIS { @@ -118,4 +119,381 @@ namespace OPC_UA_REDIS return list; } } + + /// + /// A condition handles the fact that a single condition can have multiple + /// activations and needs to check when the are present and are cleared. + /// + public class ConditionRed : DataItemRed + { + /// + /// The four values for the condition. + /// + public enum Level + { + UNAVAILABLE, + NORMAL, + WARNING, + FAULT + } + + /// + /// The Activation is itself a data item. This is so it can be cleared + /// and treated like other data items when generating text. + /// + public class Active : DataItemRed + { + // The pieces of the activation are only used by the condition. + public Level mLevel; + public string mText; + public string mNativeCode; + public string mNativeSeverity; + public string mQualifier; + + /// + /// The marked flag tells if this alarm has been reasserted. + /// + public bool mMarked = true; + + /// + /// A placeholder activation is just a normal or unavailable. + /// + public bool mPlaceholder = false; + + /// + /// Create a new activation + /// + /// The name of the condition, passed from the parent + /// The condition level + /// The descriptive text for the condition + /// The native code of the alarm or warning + /// A high/low qualifier + /// The native severity of the condition + public Active(string name, Level level, string text = "", string code = "", + string qualifier = "", string severity = "") + : base(name) + { + mLevel = level; + mText = text; + mNativeCode = code; + mQualifier = qualifier; + mNativeSeverity = severity; + + if (mNativeCode.Length == 0 && (mLevel == Level.NORMAL || mLevel == Level.UNAVAILABLE)) + mPlaceholder = true; + } + + /// + /// Update the values of the activation. Also marks this activation. + /// + /// The condition level + /// The descriptive text for the condition + /// A high/low qualifier + /// The native severity of the condition + /// true if the condition has changed + public bool Set(Level level, string text = "", + string qualifier = "", string severity = "") + { + mChanged = level != mLevel || text != mText || qualifier != mQualifier || + severity != mNativeSeverity; + if (mChanged) + { + mLevel = level; + mQualifier = qualifier; + mText = text; + mNativeSeverity = severity; + } + + mMarked = true; + return mChanged; + } + + public override string ToString() + { + return mName + "|" + Enum.GetName(mLevel.GetType(), mLevel) + "|" + mNativeCode + "|" + mNativeSeverity + "|" + mQualifier + "|" + mText; + } + + /// + /// Resets the marked flag. + /// + public void Clear() + { + mMarked = false; + } + } + + /// + /// A flag to indicate that the mark and sweep has begun. + /// + bool mBegun = false; + + /// + /// A flag indicating the second phase of the mark and sweep has completed. + /// + bool mPrepared = false; + + /// + /// true means this is a simple condition and does not require + /// mark and sweep processing. + /// + bool mSimple; + List mActiveList = new List(); + + /// + /// Create a new condition + /// + /// The name of the data item + /// If this is a simple condition or if it uses + /// mark and sweep + public ConditionRed(String name, bool simple = false) : base(name) + { + mSimple = simple; + Add(new Active(mName, Level.UNAVAILABLE)); + } + + /// + /// Make this condition unavailable + /// + public override void Unavailable() + { + Add(Level.UNAVAILABLE); + } + + /// + /// This clears all the marks and begins so we can tell which + /// conditions were not added during this pass. This is not + /// required for simple conditions. + /// + public override void Begin() + { + if (!mSimple) + { + foreach (Active active in mActiveList) + active.Clear(); + mBegun = true; + } + + mPrepared = mChanged = false; + } + + /// + /// This is called before we send the actual changed data. It + /// does the diff from the previous state and finds all the + /// activations that need to be removed. This also check to see + /// if all the activations have been removed because we only + /// need to do a single normal with no native code to clear all. + /// + /// This is not required for simple conditions. + /// + public override void Prepare() + { + if (mBegun) + { + bool marked = false; + + // Check to see if we have any active marked conditions + foreach (Active active in mActiveList) + { + if (active.mPlaceholder || active.mMarked) + { + marked = true; + break; + } + } + + // If they've all been cleared, then go back to normal. + if (!marked) Normal(); + + // Sweep the old conditions and if they are not marked + // set them to normal. + foreach (Active active in mActiveList) + { + if (!active.mPlaceholder && !active.mMarked) + { + active.Set(Level.NORMAL, ""); + active.mMarked = false; + } + if (active.Changed) + mChanged = true; + } + + mPrepared = true; + } + } + + /// + /// This is the sweep phase where we removed the changed flags + /// and remove all the stale activations. + /// + public override void Cleanup() + { + base.Cleanup(); + + mBegun = mPrepared = false; + foreach (Active active in mActiveList.ToList()) + { + // It is assumed that if the activations are no longer needed, they will + // be removed here after they are returned. + if (!active.mPlaceholder && !active.mMarked) + mActiveList.Remove(active); + + active.Cleanup(); + } + + // Remvoe stale items from the active list that are not marked + } + + /// + /// Add a new activation. + /// + /// + private void Add(Active active) + { + mActiveList.Add(active); + } + + /// + /// Adds a new activation to the condition or if normal or unavailable, removes the + /// activation. + /// + /// The level + /// The descriptive text for the condition + /// The native code + /// The qualifier + /// The native severity + /// true if the activation is modified + public bool Add(Level level, string text = "", string code = "", string qualifier = "", string severity = "") + { + bool result = false; + + // Get the first activation + Active first = null; + if (mActiveList.Count > 0) + first = mActiveList.First(); + + // Check for a reset of all conditions for a normal or an unavailable + if ((level == Level.NORMAL || level == Level.UNAVAILABLE) && code.Length == 0) + { + // If we haven't changed. + if (mActiveList.Count == 1 && first.mLevel == level) + first.mMarked = true; + else + { + // Create a new placeholder activation. We don't need to remember the + // old activations because the global normal will reset everything. + mActiveList.Clear(); + Add(new Active(mName, level)); + result = mChanged = true; + } + } + else + { + // If the first entry is a normal or unavailable and we are entering + // into a warning or fault, remove the normal or unavailable + if (mActiveList.Count() == 1 && first.mPlaceholder) + { + mActiveList.Clear(); + } + + // See if we can find the activation with the same native code. + Active found = mActiveList.Find(delegate (Active ak) { return ak.mNativeCode == code; }); + + if (found != null) + { + // If we found it, update all the properties and see if it has changed. + // This will mark this activation + result = found.Set(level, text, qualifier, severity); + mChanged = mChanged || result; + } + else + { + // Otherwise, we have a new activation and we should create a new one. + Add(new Active(mName, level, text, code, qualifier, severity)); + result = mChanged = true; + } + } + + return result; + } + + /// + /// Clear a condition from the active list - Used only for simple Conditions. + /// + /// The native code + /// true if the activation is found + public bool Clear(string code) + { + // Find the activation. + Active found = mActiveList.Find(delegate (Active ak) { return ak.mNativeCode == code; }); + + if (found != null) + { + // If we've removed the last activation, go back to normal. + if (mActiveList.Count() == 1) + Add(Level.NORMAL); + else + { + // Otherwise, just clear this one. + found.Set(Level.NORMAL); + // Clear makes the activation be removed next sweep. + found.Clear(); + } + mChanged = true; + return true; + } + else + { + return false; + } + } + + // Cover to set everything to normal. + public bool Normal() + { + return Add(Level.NORMAL); + } + + /// + /// Used to get a list of the active conditions for writing out to + /// the clients. + /// + /// This flag is used to get all activations, regardless + /// of their changed state. This is used to deliver initial state to the client + /// A list of activations (also DataItems) + public override List ItemList(bool all = false) + { + List list = new List(); + if (all) + { + // Just grab all the activations. + foreach (Active active in mActiveList) + list.Add(active); + } + else if (mSimple) + { + // For a simple condition, we are only looking for the changed set. + // Since we don't care about the mark and sweep, this is similar to + // all other data items. + foreach (Active active in mActiveList) + { + if (active.Changed) + list.Add(active); + } + } + else if (mBegun && mPrepared) + { + if (mChanged) + { + // Find all the changed activations and add them to the list + foreach (Active active in mActiveList) + { + if (active.Changed) + list.Add(active); + } + } + } + + return list; + } + } }