/// <summary> /// Updates the base event. /// </summary> private void UpdateBaseEvent(BaseEventState instance, EventType eventType, ONEVENTSTRUCT e) { BinaryEncoder encoder = new BinaryEncoder(ServiceMessageContext.GlobalContext); encoder.WriteString(null, e.szSource); encoder.WriteString(null, e.szConditionName); encoder.WriteInt32(null, e.ftActiveTime.dwHighDateTime); encoder.WriteInt32(null, e.ftActiveTime.dwLowDateTime); encoder.WriteInt32(null, e.dwCookie); byte[] eventId = encoder.CloseAndReturnBuffer(); NodeId eventTypeId = AeParsedNodeId.Construct(e.dwEventType, e.dwEventCategory, e.szConditionName, m_namespaceIndex); NodeId sourceNode = AeModelUtils.ConstructIdForSource(e.szSource, null, m_namespaceIndex); string sourceName = e.szSource; DateTime time = ComUtils.GetDateTime(e.ftTime); DateTime receiveTime = DateTime.UtcNow; LocalizedText message = e.szMessage; ushort severity = (ushort)e.dwSeverity; instance.TypeDefinitionId = eventTypeId; instance.SetChildValue(m_defaultContext, Opc.Ua.BrowseNames.EventId, eventId, false); instance.SetChildValue(m_defaultContext, Opc.Ua.BrowseNames.EventType, eventTypeId, false); instance.SetChildValue(m_defaultContext, Opc.Ua.BrowseNames.SourceNode, sourceNode, false); instance.SetChildValue(m_defaultContext, Opc.Ua.BrowseNames.SourceName, sourceName, false); instance.SetChildValue(m_defaultContext, Opc.Ua.BrowseNames.Time, time, false); instance.SetChildValue(m_defaultContext, Opc.Ua.BrowseNames.ReceiveTime, receiveTime, false); instance.SetChildValue(m_defaultContext, Opc.Ua.BrowseNames.Message, message, false); instance.SetChildValue(m_defaultContext, Opc.Ua.BrowseNames.Severity, severity, false); }
/// <summary> /// Initializes a new instance of the <see cref="AeConditionState"/> class. /// </summary> /// <param name="context">The context.</param> /// <param name="handle">The handle.</param> /// <param name="acknowledgeMethod">The acknowledge method.</param> public AeConditionState(ISystemContext context, NodeHandle handle, AddCommentMethodState acknowledgeMethod) : base(null) { AeParsedNodeId parsedNodeId = (AeParsedNodeId)handle.ParsedNodeId; this.NodeId = handle.NodeId; this.TypeDefinitionId = AeParsedNodeId.Construct( Constants.CONDITION_EVENT, parsedNodeId.CategoryId, parsedNodeId.ConditionName, parsedNodeId.NamespaceIndex); this.Acknowledge = acknowledgeMethod; this.AddChild(acknowledgeMethod); }
/// <summary> /// Initializes a new instance of the <see cref="AeEventTypeMappingState"/> class. /// </summary> public AeEventTypeMappingState(EventTypeMapping eventType, ushort namespaceIndex) { m_eventType = eventType; // create the name for the event type. string name = "COMAE" + eventType.ToString(); // the attributes. this.NodeId = AeParsedNodeId.Construct(eventType, namespaceIndex); this.BrowseName = new QualifiedName(name, namespaceIndex); this.DisplayName = this.BrowseName.Name; this.IsAbstract = true; // set the supertype. switch (eventType) { case EventTypeMapping.AlarmConditionType: { SuperTypeId = Opc.Ua.ObjectTypeIds.AlarmConditionType; break; } case EventTypeMapping.AuditEventType: { SuperTypeId = Opc.Ua.ObjectTypeIds.AuditEventType; break; } case EventTypeMapping.BaseEventType: { SuperTypeId = Opc.Ua.ObjectTypeIds.BaseEventType; break; } case EventTypeMapping.DeviceFailureEventType: { SuperTypeId = Opc.Ua.ObjectTypeIds.DeviceFailureEventType; break; } case EventTypeMapping.DiscreteAlarmType: { SuperTypeId = Opc.Ua.ObjectTypeIds.DiscreteAlarmType; break; } case EventTypeMapping.NonExclusiveDeviationAlarmType: { SuperTypeId = Opc.Ua.ObjectTypeIds.NonExclusiveDeviationAlarmType; break; } case EventTypeMapping.ExclusiveLevelAlarmType: { SuperTypeId = Opc.Ua.ObjectTypeIds.ExclusiveLevelAlarmType; break; } case EventTypeMapping.LimitAlarmType: { SuperTypeId = Opc.Ua.ObjectTypeIds.LimitAlarmType; break; } case EventTypeMapping.NonExclusiveLevelAlarmType: { SuperTypeId = Opc.Ua.ObjectTypeIds.NonExclusiveLevelAlarmType; break; } case EventTypeMapping.OffNormalAlarmType: { SuperTypeId = Opc.Ua.ObjectTypeIds.OffNormalAlarmType; break; } case EventTypeMapping.SystemEventType: { SuperTypeId = Opc.Ua.ObjectTypeIds.SystemEventType; break; } case EventTypeMapping.TripAlarmType: { SuperTypeId = Opc.Ua.ObjectTypeIds.TripAlarmType; break; } case EventTypeMapping.ConditionClassType: { SuperTypeId = Opc.Ua.ObjectTypeIds.BaseConditionClassType; break; } } }
/// <summary> /// Parses the specified node identifier. /// </summary> /// <param name="nodeId">The node identifier.</param> /// <returns>The parsed node identifier. Null if the identifier cannot be parsed.</returns> public static new AeParsedNodeId Parse(NodeId nodeId) { // can only parse non-null string node identifiers. if (NodeId.IsNull(nodeId)) { return(null); } string identifier = nodeId.Identifier as string; if (String.IsNullOrEmpty(identifier)) { return(null); } AeParsedNodeId parsedNodeId = new AeParsedNodeId(); parsedNodeId.NamespaceIndex = nodeId.NamespaceIndex; int start = 0; // extract the type of identifier. parsedNodeId.RootType = (int)ExtractNumber(identifier, ref start); if (start >= identifier.Length || identifier[start] != ':') { return(null); } // extract any component path. StringBuilder buffer = new StringBuilder(); int index = start + 1; parsedNodeId.RootId = ExtractAndUnescapeString(identifier, ref index, '&', '?'); // extract any component. int end = index + 1; parsedNodeId.ComponentPath = null; // extract the component path. if (end < identifier.Length) { parsedNodeId.ComponentPath = identifier.Substring(end); } // extract the category and condition name. start = 0; identifier = parsedNodeId.RootId; switch (parsedNodeId.RootType) { case AeModelUtils.AeEventTypeMapping: { EventTypeMapping mapping = (EventTypeMapping)(int)ExtractNumber(identifier, ref start); if (start < identifier.Length) { return(null); } parsedNodeId.CategoryId = (int)mapping; break; } case AeModelUtils.AeSimpleEventType: case AeModelUtils.AeTrackingEventType: { parsedNodeId.CategoryId = Utils.ToInt32(ExtractNumber(identifier, ref start)); if (start < identifier.Length) { return(null); } break; } case AeModelUtils.AeConditionEventType: { parsedNodeId.CategoryId = Utils.ToInt32(ExtractNumber(identifier, ref start)); if (start < identifier.Length) { if (identifier[start] != ':') { return(null); } parsedNodeId.ConditionName = identifier.Substring(start + 1); } break; } case AeModelUtils.AeCondition: { parsedNodeId.SourceId = ExtractAndUnescapeString(identifier, ref start, '0', ':'); if (start < identifier.Length && identifier[start] != ':') { return(null); } start++; parsedNodeId.CategoryId = Utils.ToInt32(ExtractNumber(identifier, ref start)); if (start < identifier.Length) { if (identifier[start] != ':') { return(null); } parsedNodeId.ConditionName = identifier.Substring(start + 1); } break; } } // extract the attribute id. if (!String.IsNullOrEmpty(parsedNodeId.ComponentPath)) { start = 0; identifier = parsedNodeId.ComponentPath; switch (parsedNodeId.RootType) { case AeModelUtils.AeSimpleEventType: case AeModelUtils.AeTrackingEventType: case AeModelUtils.AeConditionEventType: { parsedNodeId.AttributeName = identifier.Substring(start + 1); break; } } } return(parsedNodeId); }
/// <summary> /// Initializes a new instance of the <see cref="AeEventTypeState"/> class. /// </summary> public AeEventTypeState(EventType eventType, ushort namespaceIndex) { m_eventType = eventType; // create the name for the event type. string name = eventType.Description; if (!String.IsNullOrEmpty(eventType.ConditionName)) { name = eventType.ConditionName; } if (!name.EndsWith("Type")) { if (eventType.EventTypeId == OpcRcw.Ae.Constants.CONDITION_EVENT) { name += "AlarmType"; } else { name += "EventType"; } } // the attributes. this.NodeId = AeParsedNodeId.Construct(eventType, null, namespaceIndex); this.BrowseName = new QualifiedName(name, namespaceIndex); this.DisplayName = eventType.Description; this.IsAbstract = false; this.SuperTypeId = AeParsedNodeId.Construct(eventType.EventTypeMapping, namespaceIndex); // add the attributes as properties. if (eventType.Attributes != null) { for (int ii = 0; ii < eventType.Attributes.Count; ii++) { string propertyName = eventType.Attributes[ii].Description; if (AeTypeCache.IsKnownName(propertyName, "ACK COMMENT")) { continue; } PropertyState property = new PropertyState(this); property.SymbolicName = propertyName; property.ReferenceTypeId = Opc.Ua.ReferenceTypeIds.HasProperty; property.TypeDefinitionId = Opc.Ua.VariableTypeIds.PropertyType; property.ModellingRuleId = Opc.Ua.ObjectIds.ModellingRule_Optional; property.NodeId = AeParsedNodeId.Construct(eventType, propertyName, namespaceIndex); property.BrowseName = new QualifiedName(propertyName, namespaceIndex); property.DisplayName = property.BrowseName.Name; property.AccessLevel = AccessLevels.None; property.UserAccessLevel = AccessLevels.None; property.MinimumSamplingInterval = MinimumSamplingIntervals.Indeterminate; property.Historizing = false; bool isArray = false; property.DataType = ComUtils.GetDataTypeId(eventType.Attributes[ii].VarType, out isArray); property.ValueRank = (isArray) ? ValueRanks.OneDimension : ValueRanks.Scalar; this.AddChild(property); } } }
/// <summary> /// Parses the specified node identifier. /// </summary> /// <param name="nodeId">The node identifier.</param> /// <returns>The parsed node identifier. Null if the identifier cannot be parsed.</returns> public static new AeParsedNodeId Parse(NodeId nodeId) { // can only parse non-null string node identifiers. if (NodeId.IsNull(nodeId)) { return null; } string identifier = nodeId.Identifier as string; if (String.IsNullOrEmpty(identifier)) { return null; } AeParsedNodeId parsedNodeId = new AeParsedNodeId(); parsedNodeId.NamespaceIndex = nodeId.NamespaceIndex; int start = 0; // extract the type of identifier. parsedNodeId.RootType = (int)ExtractNumber(identifier, ref start); if (start >= identifier.Length || identifier[start] != ':') { return null; } // extract any component path. StringBuilder buffer = new StringBuilder(); int index = start+1; parsedNodeId.RootId = ExtractAndUnescapeString(identifier, ref index, '&', '?'); // extract any component. int end = index+1; parsedNodeId.ComponentPath = null; // extract the component path. if (end < identifier.Length) { parsedNodeId.ComponentPath = identifier.Substring(end); } // extract the category and condition name. start = 0; identifier = parsedNodeId.RootId; switch (parsedNodeId.RootType) { case AeModelUtils.AeEventTypeMapping: { EventTypeMapping mapping = (EventTypeMapping)(int)ExtractNumber(identifier, ref start); if (start < identifier.Length) { return null; } parsedNodeId.CategoryId = (int)mapping; break; } case AeModelUtils.AeSimpleEventType: case AeModelUtils.AeTrackingEventType: { parsedNodeId.CategoryId = Utils.ToInt32(ExtractNumber(identifier, ref start)); if (start < identifier.Length) { return null; } break; } case AeModelUtils.AeConditionEventType: { parsedNodeId.CategoryId = Utils.ToInt32(ExtractNumber(identifier, ref start)); if (start < identifier.Length) { if (identifier[start] != ':') { return null; } parsedNodeId.ConditionName = identifier.Substring(start+1); } break; } case AeModelUtils.AeCondition: { parsedNodeId.SourceId = ExtractAndUnescapeString(identifier, ref start, '0', ':'); if (start < identifier.Length && identifier[start] != ':') { return null; } start++; parsedNodeId.CategoryId = Utils.ToInt32(ExtractNumber(identifier, ref start)); if (start < identifier.Length) { if (identifier[start] != ':') { return null; } parsedNodeId.ConditionName = identifier.Substring(start+1); } break; } } // extract the attribute id. if (!String.IsNullOrEmpty(parsedNodeId.ComponentPath)) { start = 0; identifier = parsedNodeId.ComponentPath; switch (parsedNodeId.RootType) { case AeModelUtils.AeSimpleEventType: case AeModelUtils.AeTrackingEventType: case AeModelUtils.AeConditionEventType: { parsedNodeId.AttributeName = identifier.Substring(start+1); break; } } } return parsedNodeId; }
/// <summary> /// Updates the condition event. /// </summary> private void UpdateAlarm(AlarmConditionState instance, EventType eventType, ONEVENTSTRUCT e) { instance.NodeId = AeParsedNodeId.ConstructIdForCondition(e.szSource, e.dwEventCategory, e.szConditionName, m_namespaceIndex); // find the condition class. NodeId classId = AeParsedNodeId.Construct(e.dwEventType, e.dwEventCategory, null, m_namespaceIndex); AeEventTypeState conditionClassType = m_cache.FindType(m_defaultContext, classId); if (conditionClassType != null) { instance.SetChildValue(m_defaultContext, Opc.Ua.BrowseNames.ConditionClassId, classId, false); instance.SetChildValue(m_defaultContext, Opc.Ua.BrowseNames.ConditionClassName, conditionClassType.EventType.Description, false); } else { instance.SetChildValue(m_defaultContext, Opc.Ua.BrowseNames.ConditionClassId, Opc.Ua.ObjectTypeIds.BaseConditionClassType, false); instance.SetChildValue(m_defaultContext, Opc.Ua.BrowseNames.ConditionClassName, "BaseConditionClass", false); } instance.SetChildValue(m_defaultContext, Opc.Ua.BrowseNames.ConditionName, e.szConditionName, false);; instance.SetChildValue(m_defaultContext, Opc.Ua.BrowseNames.ClientUserId, e.szActorID, false); instance.SetChildValue(m_defaultContext, Opc.Ua.BrowseNames.Quality, ComUtils.GetQualityCode(e.wQuality), false); bool acknowledged = (e.wNewState & Constants.CONDITION_ACKED) != 0; bool active = (e.wNewState & Constants.CONDITION_ACTIVE) != 0; bool enabled = (e.wNewState & Constants.CONDITION_ENABLED) != 0; bool retain = enabled & (active || !acknowledged); LocalizedText effectiveDisplayName = ConditionStateNames.Inactive; if (!enabled) { effectiveDisplayName = ConditionStateNames.Disabled; } else if (!acknowledged) { effectiveDisplayName = ConditionStateNames.Unacknowledged; } else if (active) { effectiveDisplayName = ConditionStateNames.Active; } instance.SetChildValue(m_defaultContext, Opc.Ua.BrowseNames.Retain, true, false); instance.EnabledState = new TwoStateVariableState(instance); instance.EnabledState.BrowseName = Opc.Ua.BrowseNames.EnabledState; instance.EnabledState.Value = new LocalizedText((enabled) ? ConditionStateNames.Enabled : ConditionStateNames.Disabled); instance.EnabledState.SetChildValue(m_defaultContext, Opc.Ua.BrowseNames.Id, enabled, false); instance.EnabledState.SetChildValue(m_defaultContext, Opc.Ua.BrowseNames.EffectiveDisplayName, effectiveDisplayName, false); instance.AckedState = new TwoStateVariableState(instance); instance.AckedState.BrowseName = Opc.Ua.BrowseNames.AckedState; instance.AckedState.Value = new LocalizedText((acknowledged) ? ConditionStateNames.Acknowledged : ConditionStateNames.Unacknowledged); instance.AckedState.SetChildValue(m_defaultContext, Opc.Ua.BrowseNames.Id, acknowledged, false); instance.ActiveState = new TwoStateVariableState(instance); instance.ActiveState.BrowseName = Opc.Ua.BrowseNames.ActiveState; instance.ActiveState.Value = new LocalizedText((active) ? ConditionStateNames.Active : ConditionStateNames.Inactive); instance.ActiveState.SetChildValue(m_defaultContext, Opc.Ua.BrowseNames.Id, active, false); instance.ActiveState.SetChildValue(m_defaultContext, Opc.Ua.BrowseNames.TransitionTime, ComUtils.GetDateTime(e.ftActiveTime), false); if (!String.IsNullOrEmpty(e.szSubconditionName)) { instance.ActiveState.SetChildValue(m_defaultContext, Opc.Ua.BrowseNames.EffectiveDisplayName, e.szSubconditionName, false); } }
/// <summary> /// Dispatches the event. /// </summary> private BaseEventState DispatchEvent(ONEVENTSTRUCT e) { NodeId typeId = AeParsedNodeId.Construct(e.dwEventType, e.dwEventCategory, e.szConditionName, m_namespaceIndex); // find the type. AeEventTypeState eventType = m_cache.FindType(m_defaultContext, typeId); if (eventType == null) { return(null); } // create a new instance. BaseEventState instance = m_cache.CreateInstance(m_defaultContext, eventType); if (instance == null) { return(null); } // fill in fields. UpdateBaseEvent(instance, eventType.EventType, e); if (instance is AuditEventState) { UpdateAuditEvent((AuditEventState)instance, eventType.EventType, e); } if (instance is AlarmConditionState) { UpdateAlarm((AlarmConditionState)instance, eventType.EventType, e); } if (instance is ExclusiveLimitAlarmState) { UpdateExclusiveLimitAlarm((ExclusiveLimitAlarmState)instance, eventType.EventType, e); } else if (instance is NonExclusiveLimitAlarmState) { UpdateNonExclusiveLimitAlarm((NonExclusiveLimitAlarmState)instance, eventType.EventType, e); } // process attributes. bool ackCommentFound = false; object[] values = ComUtils.GetVARIANTs(ref e.pEventAttributes, e.dwNumEventAttrs, false); for (int ii = 0; ii < eventType.EventType.Attributes.Count; ii++) { EventAttribute attribute = eventType.EventType.Attributes[ii]; if (ii >= e.dwNumEventAttrs) { continue; } if (!ackCommentFound && AeTypeCache.IsKnownName(attribute.Description, "ACK COMMENT")) { ConditionState condition = instance as ConditionState; if (condition != null) { condition.Comment = new ConditionVariableState <LocalizedText>(condition); condition.Comment.BrowseName = Opc.Ua.BrowseNames.Comment; condition.Comment.Value = new LocalizedText(values[ii] as string); } ackCommentFound = true; continue; } PropertyState property = new PropertyState(instance); property.SymbolicName = attribute.Description; property.BrowseName = new QualifiedName(property.SymbolicName, m_namespaceIndex); property.Value = values[ii]; instance.AddChild(property); } return(instance); }
/// <summary> /// Verifies that the specified node exists. /// </summary> protected override NodeState ValidateNode( ServerSystemContext context, NodeHandle handle, IDictionary <NodeId, NodeState> cache) { // not valid if no root. if (handle == null) { return(null); } // check if previously validated. if (handle.Validated) { return(handle.Node); } NodeState target = null; // check if already in the cache. if (cache != null) { if (cache.TryGetValue(handle.NodeId, out target)) { // nulls mean a NodeId which was previously found to be invalid has been referenced again. if (target == null) { return(null); } handle.Node = target; handle.Validated = true; return(handle.Node); } target = null; } try { // check if the node id has been parsed. AeParsedNodeId parsedNodeId = handle.ParsedNodeId as AeParsedNodeId; if (parsedNodeId == null) { return(null); } ComAeClient client = m_system.SelectClient(context, false); switch (parsedNodeId.RootType) { case AeModelUtils.AeSimpleEventType: case AeModelUtils.AeTrackingEventType: case AeModelUtils.AeConditionEventType: { if (m_typeCache == null) { return(null); } BaseObjectTypeState eventTypeNode = null; NodeId rootId = AeParsedNodeId.Construct(parsedNodeId.RootType, parsedNodeId.CategoryId, parsedNodeId.ConditionName, parsedNodeId.NamespaceIndex); if (!m_typeCache.EventTypeNodes.TryGetValue(rootId, out eventTypeNode)) { return(null); } target = eventTypeNode; break; } case AeModelUtils.AeArea: { ComAeBrowserClient browser = new ComAeBrowserClient(client, null); target = browser.FindArea(context, parsedNodeId.RootId, NamespaceIndex); browser.Dispose(); handle.Validated = true; handle.Node = target; return(handle.Node); } case AeModelUtils.AeSource: { ComAeBrowserClient browser = new ComAeBrowserClient(client, null); target = browser.FindSource(context, parsedNodeId.RootId, parsedNodeId.ComponentPath, NamespaceIndex); browser.Dispose(); handle.Validated = true; handle.Node = target; return(handle.Node); } case AeModelUtils.AeCondition: { target = new AeConditionState(context, handle, m_templateAlarm.Acknowledge); break; } } // node does not exist. if (target == null) { return(null); } if (!String.IsNullOrEmpty(parsedNodeId.ComponentPath)) { // validate component. NodeState component = target.FindChildBySymbolicName(context, parsedNodeId.ComponentPath); // component does not exist. if (component == null) { return(null); } target = component; } // found a valid component. handle.Validated = true; handle.Node = target; return(handle.Node); } finally { // store the node in the cache to optimize subsequent lookups. if (cache != null) { cache.Add(handle.NodeId, target); } } }
/// <summary> /// Returns a unique handle for the node. /// </summary> protected override NodeHandle GetManagerHandle(ServerSystemContext context, NodeId nodeId, IDictionary <NodeId, NodeState> cache) { lock (Lock) { // quickly exclude nodes that are not in the namespace. if (!IsNodeIdInNamespace(nodeId)) { return(null); } // check cache. if (cache != null) { NodeState node = null; if (cache.TryGetValue(nodeId, out node)) { return(new NodeHandle(nodeId, node)); } } NodeHandle handle = null; try { // check if node already being monitored. if (MonitoredNodes != null) { MonitoredNode2 monitoredNode2 = null; if (MonitoredNodes.TryGetValue(nodeId, out monitoredNode2)) { handle = new NodeHandle(nodeId, monitoredNode2.Node); handle.MonitoredNode = monitoredNode2; return(handle); } } // check for predefined nodes. if (PredefinedNodes != null) { NodeState node = null; if (PredefinedNodes.TryGetValue(nodeId, out node)) { return(handle = new NodeHandle(nodeId, node)); } } // parse the identifier. AeParsedNodeId parsedNodeId = AeParsedNodeId.Parse(nodeId); if (parsedNodeId != null) { if (parsedNodeId.RootType == AeModelUtils.AeEventTypeMapping && m_typeCache != null) { AeEventTypeMappingState mappingNode = m_typeCache.GetMappingNode(SystemContext, nodeId); if (mappingNode != null) { return(handle = new NodeHandle(nodeId, mappingNode)); } return(null); } handle = new NodeHandle(); handle.NodeId = nodeId; handle.Validated = false; handle.Node = null; handle.ParsedNodeId = parsedNodeId; return(handle); } } finally { if (handle != null && handle.Node != null && cache != null) { cache.Add(nodeId, handle.Node); } } return(null); } }