Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Server] Add support for SupportsFilteredRetain #2913

Draft
wants to merge 6 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 90 additions & 1 deletion Libraries/Opc.Ua.Server/Subscription/MonitoredItem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1042,7 +1042,7 @@ public virtual void QueueEvent(IFilterTarget instance, bool bypassFilter)
// apply filter.
if (!bypassFilter)
{
if (!filter.WhereClause.Evaluate(context, instance))
if ( !CanSendFilteredAlarm( context, filter, instance ) )
{
return;
}
Expand Down Expand Up @@ -1079,6 +1079,92 @@ public virtual void QueueEvent(EventFieldList fields)
}
}

/// <summary>
///
romanett marked this conversation as resolved.
Show resolved Hide resolved
/// </summary>
/// <param name="context"></param>
/// <param name="filter"></param>
/// <param name="instance"></param>
/// <returns></returns>
protected bool CanSendFilteredAlarm(FilterContext context, EventFilter filter, IFilterTarget instance)
romanett marked this conversation as resolved.
Show resolved Hide resolved
{
bool passedFilter = filter.WhereClause.Evaluate(context, instance);

ConditionState alarmCondition = null;
NodeId conditionId = null;
InstanceStateSnapshot instanceStateSnapshot = instance as InstanceStateSnapshot;
if (instanceStateSnapshot != null)
{
alarmCondition = instanceStateSnapshot.Handle as ConditionState;

if (alarmCondition != null &&
alarmCondition.SupportsFilteredRetain != null &&
alarmCondition.SupportsFilteredRetain.Value &&
filter.SelectClauses != null)
{
int lastIndex = filter.SelectClauses.Count - 1;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does lastIndex allways point to the ConditionId ? Can't the client request it in another order together with other SelectClauses?

object value = instance.GetAttributeValue(
context,
filter.SelectClauses[lastIndex].TypeDefinitionId,
filter.SelectClauses[lastIndex].BrowsePath,
filter.SelectClauses[lastIndex].AttributeId,
filter.SelectClauses[lastIndex].ParsedIndexRange);

if (value != null)
{
conditionId = value as NodeId;
}
}
}

bool canSend = passedFilter;

// ConditionId is valid only if FilteredRetain is set for the alarm condition
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is the ConditionId only valid if FilteredRetain is set ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The logic is specifically for SupportsFilterRetain, so if it is not set, the remainder of the function is not required, only the filter check at the top of the function.

This is still a work in progress, I'm going to move it to draft for now.

if (conditionId != null && alarmCondition != null)
{
HashSet<string> conditionIds = GetFilteredRetainConditionIds();

string key = conditionId.ToString();

bool saved = conditionIds.Contains(key);

if ( saved )
{
conditionIds.Remove(key);
}

if ( passedFilter )
{
// Archie - December 17 2024
// Requires discussion with Part 9 Editor
// if (alarmCondition.Retain.Value)
{
conditionIds.Add(key);
}
}
else
{
if ( saved )
{
canSend = true;
}
}
}

return canSend;
}

private HashSet<string> GetFilteredRetainConditionIds()
{
if (FilteredRetainConditionIds == null)
{
FilteredRetainConditionIds = new HashSet<string>();
}

return FilteredRetainConditionIds;
}


/// <summary>
/// Whether the item has notifications that are ready to publish.
/// </summary>
Expand Down Expand Up @@ -1873,6 +1959,9 @@ private void QueueOverflowHandler()
private IAggregateCalculator m_calculator;
private bool m_triggered;
private bool m_resendData;
HashSet<string> FilteredRetainConditionIds = null;
romanett marked this conversation as resolved.
Show resolved Hide resolved


#endregion
}
}
24 changes: 24 additions & 0 deletions Stack/Opc.Ua.Core/Stack/State/ConditionState.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,29 @@ protected override void OnAfterCreate(ISystemContext context, NodeState node)
}
#endregion

#region Public Properties

/// <remarks />
public PropertyState<bool> SupportsFilteredRetain
{
get
{
return m_supportsFilteredRetain;
}

set
{
if (!Object.ReferenceEquals(m_supportsFilteredRetain, value))
{
ChangeMasks |= NodeStateChangeMasks.Children;
}

m_supportsFilteredRetain = value;
}
}

#endregion

#region Public Methods
/// <summary>
/// Gets or sets a value indicating whether the condition will automatically report an event when a method call completes.
Expand Down Expand Up @@ -762,6 +785,7 @@ protected bool IsBranch()
///
/// </summary>
protected Dictionary<string, ConditionState> m_branches = null;
private PropertyState<bool> m_supportsFilteredRetain = null;

#endregion
}
Expand Down
Loading
Loading