Skip to content

Commit

Permalink
Fix Issues 1274 and 1275 (#1277)
Browse files Browse the repository at this point in the history
* Fix Issues 1274 and 1275
* Update Documentation for Publicly visible UnshelveTimeUpdateRate
* Adds a timer specifically to update UnshelveTime periodically.
* Initializes Unshelve to double maximum value or MaxTimeShelved if it exists, even for OneShotShelve method calls (Mantis 6462).
  • Loading branch information
Archie-Miller committed Feb 4, 2021
1 parent e138777 commit a2e8489
Showing 1 changed file with 109 additions and 12 deletions.
121 changes: 109 additions & 12 deletions Stack/Opc.Ua.Core/Stack/State/AlarmConditionState.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@ protected override void OnAfterCreate(ISystemContext context, NodeState node)
this.ShelvingState.TimedShelve.OnReadUserExecutable = IsTimedShelveExecutable;

this.ShelvingState.Unshelve.OnCallMethod = OnUnshelve;
this.ShelvingState.Unshelve.OnReadExecutable = IsTimedShelveExecutable;
this.ShelvingState.Unshelve.OnReadUserExecutable = IsTimedShelveExecutable;
this.ShelvingState.Unshelve.OnReadExecutable = IsUnshelveExecutable;
this.ShelvingState.Unshelve.OnReadUserExecutable = IsUnshelveExecutable;
}
}
#endregion
Expand All @@ -67,12 +67,38 @@ protected override void Dispose(bool disposing)
m_unshelveTimer.Dispose();
m_unshelveTimer = null;
}
if (m_updateUnshelveTimer != null)
{
m_updateUnshelveTimer.Dispose();
m_updateUnshelveTimer = null;
}
}

base.Dispose(disposing);
}
#endregion

#region Public Properties - Operational

/// <summary>
/// Defines how often to update the UnshelveTime when Shelving State is TimedShelve or OneShotShelved.
/// Defaults to 1000 ms
/// </summary>
public int UnshelveTimeUpdateRate
{
get
{
return m_unshelveTimeUpdateRate;
}

set
{
m_unshelveTimeUpdateRate = value;
}
}

#endregion

#region Public Methods
/// <summary>
/// Called when one or more sub-states change state.
Expand Down Expand Up @@ -228,35 +254,57 @@ public DateTime UnshelveTime
m_unshelveTimer = null;
}

if (m_updateUnshelveTimer != null)
{
m_updateUnshelveTimer.Dispose();
m_updateUnshelveTimer = null;
}

m_unshelveTime = DateTime.MinValue;

if (!shelved)
{
if (this.SuppressedState == null || !this.SuppressedState.Id.Value)
{
SuppressedOrShelved.Value = false;
}

this.ShelvingState.UnshelveTime.Value = 0.0;

this.ShelvingState.CauseProcessingCompleted(context, Methods.ShelvedStateMachineType_Unshelve);
}
else
{
SuppressedOrShelved.Value = true;
m_oneShot = oneShot;
m_unshelveTime = DateTime.MinValue;

if (oneShot)
{
this.ShelvingState.CauseProcessingCompleted(context, Methods.ShelvedStateMachineType_OneShotShelve);
// Unshelve time is still valid even for OneShotShelved - See Mantis 6462

double maxTimeShelved = (double)int.MaxValue;
if ( this.MaxTimeShelved != null && this.MaxTimeShelved.Value > 0 )
{
maxTimeShelved = this.MaxTimeShelved.Value;
}
else

double shelveTime = maxTimeShelved;

uint state = Methods.ShelvedStateMachineType_OneShotShelve;
if (!oneShot)
{
if (shelvingTime > 0)
if (shelvingTime > 0 && shelvingTime < shelveTime)
{
m_unshelveTime = DateTime.UtcNow.AddMilliseconds(shelvingTime);
m_unshelveTimer = new Timer(OnTimerExpired, context, (int)shelvingTime, Timeout.Infinite);
shelveTime = shelvingTime;
}

this.ShelvingState.CauseProcessingCompleted(context, Methods.ShelvedStateMachineType_TimedShelve);
state = Methods.ShelvedStateMachineType_TimedShelve;
}

this.ShelvingState.UnshelveTime.Value = shelveTime;
m_unshelveTime = DateTime.UtcNow.AddMilliseconds((int)shelveTime);

m_updateUnshelveTimer = new Timer(OnUnshelveTimeUpdate, context, m_unshelveTimeUpdateRate, m_unshelveTimeUpdateRate);

m_unshelveTimer = new Timer(OnTimerExpired, context, (int)shelveTime, Timeout.Infinite);
this.ShelvingState.CauseProcessingCompleted(context, state);
}

UpdateEffectiveState(context);
Expand All @@ -276,6 +324,12 @@ public DateTime UnshelveTime
/// Raised when the timed shelving period expires.
/// </summary>
public AlarmConditionTimedUnshelveEventHandler OnTimedUnshelve;

/// <summary>
/// Raised periodically when the shelving state is not Unshelved to update the UnshelveTimeValue.
/// </summary>
public AlarmConditionUnshelveTimeValueEventHandler OnUpdateUnshelveTime;

#endregion

#region Protected Method
Expand Down Expand Up @@ -382,6 +436,11 @@ protected override void UpdateEffectiveState(ISystemContext context)
if (m_unshelveTime != DateTime.MinValue)
{
delta = (m_unshelveTime - DateTime.UtcNow).TotalMilliseconds;

if ( delta < 0 )
{
m_unshelveTime = DateTime.MinValue;
}
}

value = delta;
Expand Down Expand Up @@ -648,18 +707,45 @@ private void OnTimerExpired(object state)
{
OnTimedUnshelve((ISystemContext)state, this);
}
this.OnUnshelveTimeUpdate(state);
}
catch (Exception e)
{
Utils.Trace(e, "Unexpected error unshelving alarm.");
}
}

/// <summary>
/// Called when shelved state is not Unshelved to update the UnshelveTime value.
/// </summary>
private void OnUnshelveTimeUpdate(object state)
{
try
{
ISystemContext context = (ISystemContext)state;
object unshelveTimeObject = new object();
OnReadUnshelveTime(context, null, ref unshelveTimeObject);
double unshelveTime = (double)unshelveTimeObject;
if (unshelveTime != this.ShelvingState.UnshelveTime.Value)
{
this.ShelvingState.UnshelveTime.Value = unshelveTime;
this.ClearChangeMasks(context, true);
}
}
catch (Exception e)
{
Utils.Trace(e, "Unexpected error updating UnshelveTime.");
}
}

#endregion

#region Private Fields
private DateTime m_unshelveTime;
private bool m_oneShot;
private Timer m_unshelveTimer;
private Timer m_updateUnshelveTimer;
private int m_unshelveTimeUpdateRate = 1000;
#endregion
}

Expand All @@ -686,4 +772,15 @@ private void OnTimerExpired(object state)
public delegate ServiceResult AlarmConditionTimedUnshelveEventHandler(
ISystemContext context,
AlarmConditionState alarm);

/// <summary>
/// Used to receive notifications when the shelving state is either OneShotShelved or TimedShelved.
/// Updates the value of the UnshelveTime
/// </summary>
/// <param name="context">The current system context.</param>
/// <param name="alarm">The alarm that raised the event.</param>
public delegate ServiceResult AlarmConditionUnshelveTimeValueEventHandler(
ISystemContext context,
AlarmConditionState alarm);

}

0 comments on commit a2e8489

Please sign in to comment.