Skip to content

Commit

Permalink
Implement a common method for creating branches (#1603)
Browse files Browse the repository at this point in the history
Implement a mechanism to create Alarm Branches, store them, allow AddComment, Acknowledge, and Confirm them.

Updates the Retain flag automatically.
Cleans up branches on Ack/Confirm

Allows servers to retrieve branches to clear them all if necessary.
  • Loading branch information
Archie-Miller committed Jan 25, 2022
1 parent 5cbffcf commit 5d33c16
Show file tree
Hide file tree
Showing 3 changed files with 434 additions and 10 deletions.
128 changes: 123 additions & 5 deletions Stack/Opc.Ua.Core/Stack/State/AcknowledgeableConditionState.cs
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ protected override void UpdateEffectiveState(ISystemContext context)
return;
}

if (this.ConfirmedState != null)
if (SupportsConfirm())
{
if (!this.ConfirmedState.Id.Value)
{
Expand Down Expand Up @@ -148,14 +148,42 @@ protected override void UpdateEffectiveState(ISystemContext context)

if (ServiceResult.IsGood(error))
{
SetAcknowledgedState(context, true);
AcknowledgeableConditionState branch = GetAcknowledgeableBranch(eventId);

if ( branch != null )
{
branch.OnAcknowledgeCalled(context, method, objectId, eventId, comment);

if (SupportsConfirm())
{
ReplaceBranchEvent(eventId, branch);
}
else
{
RemoveBranchEvent(eventId);
}
}
else
{
SetAcknowledgedState(context, true);

if (SupportsConfirm())
{
SetConfirmedState(context, false);
}
}

// If this is a branch, the comment goes to both the branch and the original event
if (CanSetComment(comment))
{
SetComment(context, comment, GetCurrentUserId(context));
}

UpdateRetainState();

}

if (this.AreEventsMonitored)
if (EventsMonitored())
{
// report a state change event.
if (ServiceResult.IsGood(error))
Expand Down Expand Up @@ -293,14 +321,28 @@ protected virtual void UpdateStateAfterUnacknowledge(ISystemContext context)

if (ServiceResult.IsGood(error))
{
SetConfirmedState(context, true);
AcknowledgeableConditionState branch = GetAcknowledgeableBranch(eventId);

if (branch != null)
{
branch.OnConfirmCalled(context, method, objectId, eventId, comment);
RemoveBranchEvent(eventId);
}
else
{
SetConfirmedState(context, true);
}

// If this is a branch, the comment goes to both the branch and the original event
if (CanSetComment(comment))
{
SetComment(context, comment, GetCurrentUserId(context));
}

UpdateRetainState();
}

if (this.AreEventsMonitored)
if (EventsMonitored())
{
// report a state change event.
if (ServiceResult.IsGood(error))
Expand Down Expand Up @@ -455,6 +497,82 @@ private bool CanSetComment(LocalizedText comment)

return canSetComment;
}

/// <summary>
/// Determines if this Event supports Confirm.
/// </summary>
/// <returns>
/// Boolean stating whether the Confirm is supported
/// </returns>
public bool SupportsConfirm()
{
bool supportsConfirm = false;

if (this.ConfirmedState != null && this.ConfirmedState.Value != null )
{
supportsConfirm = true;
}

return supportsConfirm;
}

/// <summary>
/// Determines whether a specified branch exists, and returns it as AcknowledgeableConditionState
/// </summary>
/// <param name="eventId">Desired Event Id</param>
/// <returns>
/// AcknowledgeableConditionState branch if it exists
/// </returns>
private AcknowledgeableConditionState GetAcknowledgeableBranch(byte[] eventId)
{
AcknowledgeableConditionState acknowledgeableBranch = null;
ConditionState branch = GetBranch(eventId);

if (branch != null)
{
object acknowledgeable = branch as AcknowledgeableConditionState;
if (acknowledgeable != null)
{
acknowledgeableBranch = (AcknowledgeableConditionState)acknowledgeable;
}
}

return acknowledgeableBranch;
}

/// <summary>
/// Determines the desired Retain state based off of the values of AckedState and
/// ConfirmedState if ConfirmedState is supported
/// </summary>
/// <remarks>
/// All implementations of this method should check the enabled state
/// </remarks>
protected override bool GetRetainState()
{
bool retainState = false;

if (this.EnabledState.Id.Value)
{
retainState = base.GetRetainState();

if (!this.AckedState.Id.Value)
{
retainState = true;
}
else
{
if ( SupportsConfirm() && !this.ConfirmedState.Id.Value)
{
retainState = true;
}
}
}

return retainState;
}



#endregion

#region Public Interface
Expand Down
57 changes: 56 additions & 1 deletion Stack/Opc.Ua.Core/Stack/State/AlarmConditionState.cs
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,7 @@ public DateTime UnshelveTime

// Unshelve time is still valid even for OneShotShelved - See Mantis 6462

double maxTimeShelved = (double)int.MaxValue;
double maxTimeShelved = double.MaxValue;
if ( this.MaxTimeShelved != null && this.MaxTimeShelved.Value > 0 )
{
maxTimeShelved = this.MaxTimeShelved.Value;
Expand Down Expand Up @@ -309,6 +309,61 @@ public DateTime UnshelveTime

UpdateEffectiveState(context);
}

/// <summary>
/// Determines the desired Retain state based off of the values of AckedState and
/// ConfirmedState if ConfirmedState is supported
/// </summary>
/// <remarks>
/// All implementations of this method should check the enabled state
/// </remarks>
protected override bool GetRetainState()
{
bool retainState = false;

if (this.EnabledState.Id.Value)
{
retainState = base.GetRetainState();

if (!IsBranch())
{
if (this.ActiveState.Id.Value)
{
retainState = true;
}
}
}

return retainState;
}

/// <summary>
/// Returns the method with the specified NodeId or MethodDeclarationId. Looks specifically for
/// Shelving State Methods
/// </summary>
/// <param name="context">The system context.</param>
/// <param name="methodId">The identifier for the method to find.</param>
/// <returns>Returns the method. Null if no method found.</returns>
/// <remarks>
/// It is possible to call ShelvingState Methods by using only the ConditionId (1.04 Part 9 5.8.10.4).
/// Look to the Shelving State object for the method if it cannot be found by the normal mechanism.
/// </remarks>

public override MethodState FindMethod(ISystemContext context, NodeId methodId)
{
MethodState method = base.FindMethod(context, methodId);

if ( method == null )
{
if ( this.ShelvingState != null )
{
method = this.ShelvingState.FindMethod(context, methodId);
}
}

return method;
}

#endregion

#region Event Handlers
Expand Down

0 comments on commit 5d33c16

Please sign in to comment.