/// <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> /// Updates the audit event. /// </summary> private void UpdateAuditEvent(AuditEventState instance, EventType eventType, ONEVENTSTRUCT e) { instance.SetChildValue(m_defaultContext, Opc.Ua.BrowseNames.ActionTimeStamp, instance.Time.Value, false); instance.SetChildValue(m_defaultContext, Opc.Ua.BrowseNames.Status, true, false); instance.SetChildValue(m_defaultContext, Opc.Ua.BrowseNames.ServerId, m_defaultContext.NamespaceUris.GetString(m_namespaceIndex), false); instance.SetChildValue(m_defaultContext, Opc.Ua.BrowseNames.ClientUserId, e.szActorID, false); }
/// <summary> /// Initializes a COM-patible ONEVENTSTRUCT ready to be sent to subscribing clients /// </summary> /// <param name="oes"></param> /// <param name="pOnEventClass"></param> private void CopyToOnEventStruct(ref ONEVENTSTRUCT oes, OnEventClass pOnEventClass) { try { oes = pOnEventClass.InternalOES; ReturnedAttributeList attrIds; if (m_ReturnedAttributes.TryGetValue(oes.dwEventCategory, out attrIds) == true) { int retAttrCount = attrIds.Count; int i = 0; object[] attrVals = new object[retAttrCount]; foreach (int attrId in attrIds) { attrVals[i++] = pOnEventClass.EventAttributes[attrId]; } oes.dwNumEventAttrs = retAttrCount; oes.pEventAttributes = ComUtils.GetVARIANTs(attrVals, false); } } catch (Exception e) { Utils.Trace(e, "Unexpected error in CopyToOnEventStruct"); } }
internal static EventNotification GetEventNotification(ONEVENTSTRUCT input) { EventNotification eventNotification = new EventNotification(); eventNotification.SourceID = input.szSource; eventNotification.Time = OpcCom.Interop.GetFILETIME(Convert(input.ftTime)); eventNotification.Severity = input.dwSeverity; eventNotification.Message = input.szMessage; eventNotification.EventType = (EventType)input.dwEventType; eventNotification.EventCategory = input.dwEventCategory; eventNotification.ChangeMask = input.wChangeMask; eventNotification.NewState = input.wNewState; eventNotification.Quality = new Quality(input.wQuality); eventNotification.ConditionName = input.szConditionName; eventNotification.SubConditionName = input.szSubconditionName; eventNotification.AckRequired = (input.bAckRequired != 0); eventNotification.ActiveTime = OpcCom.Interop.GetFILETIME(Convert(input.ftActiveTime)); eventNotification.Cookie = input.dwCookie; eventNotification.ActorID = input.szActorID; object[] vARIANTs = OpcCom.Interop.GetVARIANTs(ref input.pEventAttributes, input.dwNumEventAttrs, deallocate: false); eventNotification.SetAttributes(vARIANTs); return(eventNotification); }
/// <summary> /// Clears the refresh related state from the subscription and generates a callback /// where bRefresh==true and bLastRefresh==true /// </summary> private void SendCancelRefresh() { lock (m_csData) { m_RefreshQ.Clear(); m_bCancelRefresh = false; m_RefreshID = 0; } // Create an empty event -- dwCount will be set to zero anyway ONEVENTSTRUCT[] emptyEvent = new ONEVENTSTRUCT[1]; CopyToOnEventStruct(ref emptyEvent[0], new OnEventClass(null, null, new OPCCondition())); try { lock (m_lock) { object callback = GetCallback(typeof(IOPCEventSink).GUID); if (callback == null) { return; } ((IOPCEventSink)callback).OnEvent(m_hClientSubscription, 1, 1, 0, emptyEvent); } } catch (Exception e) { Utils.Trace(e, "Unexpected error in OnEvent callback."); } finally { Marshal.FreeCoTaskMem(emptyEvent[0].pEventAttributes); } }
internal static EventNotification GetEventNotification(ONEVENTSTRUCT input) { EventNotification notification = new EventNotification { SourceID = input.szSource, Time = OpcCom.Interop.GetFILETIME(Convert(input.ftTime)), Severity = input.dwSeverity, Message = input.szMessage, EventType = (EventType)input.dwEventType, EventCategory = input.dwEventCategory, ChangeMask = input.wChangeMask, NewState = input.wNewState, Quality = new Quality(input.wQuality), ConditionName = input.szConditionName, SubConditionName = input.szSubconditionName, AckRequired = input.bAckRequired != 0, ActiveTime = OpcCom.Interop.GetFILETIME(Convert(input.ftActiveTime)), Cookie = input.dwCookie, ActorID = input.szActorID }; object[] attributes = OpcCom.Interop.GetVARIANTs(ref input.pEventAttributes, input.dwNumEventAttrs, false); notification.SetAttributes(attributes); return(notification); }
BaseEventState ConstructEvent(ONEVENTSTRUCT e) { return(null); }
/// <summary> /// Updates the non-exclusive limit event. /// </summary> private void UpdateNonExclusiveLimitAlarm(NonExclusiveLimitAlarmState instance, EventType eventType, ONEVENTSTRUCT e) { bool active = (e.wNewState & Constants.CONDITION_ACTIVE) != 0; TwoStateVariableState state = null; if (AeTypeCache.IsKnownName(e.szConditionName, "HI HI")) { instance.HighHighState = state = new TwoStateVariableState(instance); instance.HighHighState.BrowseName = Opc.Ua.BrowseNames.HighHighState; } else if (AeTypeCache.IsKnownName(e.szSubconditionName, "HI") || AeTypeCache.IsKnownName(e.szSubconditionName, "DV HI")) { instance.HighState = state = new TwoStateVariableState(instance); instance.HighState.BrowseName = Opc.Ua.BrowseNames.HighState; } else if (AeTypeCache.IsKnownName(e.szSubconditionName, "LO") || AeTypeCache.IsKnownName(e.szSubconditionName, "DV LO")) { instance.LowState = state = new TwoStateVariableState(instance); instance.LowState.BrowseName = Opc.Ua.BrowseNames.LowState; } else if (AeTypeCache.IsKnownName(e.szSubconditionName, "LO LO")) { instance.LowLowState = state = new TwoStateVariableState(instance); instance.LowLowState.BrowseName = Opc.Ua.BrowseNames.LowLowState; } if (state != null) { state.Value = new LocalizedText((active) ? ConditionStateNames.Active : ConditionStateNames.Inactive); state.SetChildValue(m_defaultContext, Opc.Ua.BrowseNames.Id, active, false); } }
/// <summary> /// Updates the exclusive limit alarm event. /// </summary> private void UpdateExclusiveLimitAlarm(ExclusiveLimitAlarmState instance, EventType eventType, ONEVENTSTRUCT e) { NodeId state = null; string text = null; if (AeTypeCache.IsKnownName(e.szSubconditionName, "HI HI")) { state = Opc.Ua.ObjectIds.ExclusiveLimitStateMachineType_HighHigh; text = ConditionStateNames.HighHighActive; } if (AeTypeCache.IsKnownName(e.szSubconditionName, "HI")) { state = Opc.Ua.ObjectIds.ExclusiveLimitStateMachineType_High; text = ConditionStateNames.HighActive; } if (AeTypeCache.IsKnownName(e.szSubconditionName, "LO")) { state = Opc.Ua.ObjectIds.ExclusiveLimitStateMachineType_Low; text = ConditionStateNames.LowActive; } if (AeTypeCache.IsKnownName(e.szSubconditionName, "LO LO")) { state = Opc.Ua.ObjectIds.ExclusiveLimitStateMachineType_LowLow; text = ConditionStateNames.LowLowActive; } instance.LimitState = new ExclusiveLimitStateMachineState(instance); instance.LimitState.BrowseName = Opc.Ua.BrowseNames.LimitState; instance.LimitState.CurrentState = new FiniteStateVariableState(instance.LimitState); instance.LimitState.CurrentState.BrowseName = Opc.Ua.BrowseNames.CurrentState; instance.LimitState.CurrentState.Value = text; instance.LimitState.CurrentState.SetChildValue(m_defaultContext, Opc.Ua.BrowseNames.Id, state, false); }
/// <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> /// Called on a threadpool thread, SendEvents pops waiting event notifications from the /// subscription queue (subject to MaxSize) and invokes the client callback /// </summary> /// <param name="q"></param> /// <param name="bRefresh"></param> /// <param name="bKeepAlive"></param> public void SendEvents(EventItemQueue <OnEventClass> q, bool bRefresh, bool bKeepAlive) { int dwCount = 0; int hClientSubscription = 0; bool bLastRefresh = false; ONEVENTSTRUCT[] events; lock (m_csData) { hClientSubscription = m_hClientSubscription; dwCount = Math.Min(q.Count, m_dwMaxSize); bLastRefresh = (dwCount == q.Count) && bRefresh; events = new ONEVENTSTRUCT[dwCount]; for (int i = 0; i < dwCount; i++) { CopyToOnEventStruct(ref events[i], q.Dequeue()); } } bool bUpdated = false; try { lock (m_lock) { object callback = GetCallback(typeof(IOPCEventSink).GUID); if (callback == null) { return; } if (dwCount > 0) // don't update time for a keep alive callback { m_LastUpdateTime = DateTime.Now; bUpdated = true; } if (bRefresh && bLastRefresh) { m_RefreshID = 0; } ((IOPCEventSink)callback).OnEvent( hClientSubscription, bRefresh ? 1 : 0, bLastRefresh ? 1 : 0, bKeepAlive ? 0 : dwCount, events); } } catch (Exception e) { Utils.Trace(e, "Unexpected error in OnEvent callback."); } finally { for (int i = 0; i < dwCount; i++) { Marshal.FreeCoTaskMem(events[i].pEventAttributes); } } if (m_server != null && bUpdated) { m_server.LastUpdateTime = m_LastUpdateTime; } }
/// <summary> /// Marshals an event for return to the client. /// </summary> private OpcRcw.Ae.ONEVENTSTRUCT Translate(AeEvent e) { OpcRcw.Ae.ONEVENTSTRUCT e2 = new ONEVENTSTRUCT(); e2.wNewState = 0; e2.wChangeMask = 0xFF; e2.szSource = e.SourceName; e2.wQuality = ComUtils.GetQualityCode(e.Quality); e2.dwEventType = e.Category.EventType; e2.dwEventCategory = (int)e.Category.LocalId; e2.bAckRequired = 0; e2.dwSeverity = e.Severity; e2.ftTime = ComUtils.GetFILETIME(e.Time); e2.szMessage = (e.Message != null) ? e.Message.Text : null; e2.szActorID = e.AuditUserId; e2.dwCookie = e.Cookie; if (e.AttributeValues != null && e.AttributeValues.Length > 0) { e2.dwNumEventAttrs = e.AttributeValues.Length; e2.pEventAttributes = ComUtils.GetVARIANTs(e.AttributeValues, true); } if ((e2.dwEventType & OpcRcw.Ae.Constants.CONDITION_EVENT) != 0) { e2.szConditionName = e.ConditionName; e2.ftActiveTime = ComUtils.GetFILETIME(e.ActiveTime); e2.bAckRequired = (e.AckedState)?0:1; // set the condition state. e2.wNewState = 0; if (e.EnabledState) { e2.wNewState |= OpcRcw.Ae.Constants.CONDITION_ENABLED; } if (e.AckedState) { e2.wNewState |= OpcRcw.Ae.Constants.CONDITION_ACKED; } if (e.ActiveState) { e2.wNewState |= OpcRcw.Ae.Constants.CONDITION_ACTIVE; } // set the subcondition if available. if (!LocalizedText.IsNullOrEmpty(e.LowState)) { e2.szSubconditionName = e.LowState.Text; } if (!LocalizedText.IsNullOrEmpty(e.HighState)) { e2.szSubconditionName = e.HighState.Text; } if (!LocalizedText.IsNullOrEmpty(e.LowLowState)) { e2.szSubconditionName = e.LowLowState.Text; } if (!LocalizedText.IsNullOrEmpty(e.HighHighState)) { e2.szSubconditionName = e.HighHighState.Text; } if (!LocalizedText.IsNullOrEmpty(e.LimitState)) { e2.szSubconditionName = e.LimitState.Text; } } if (e2.szMessage == null) { e2.szMessage = String.Empty; } if (e2.szSource == null) { e2.szSource = String.Empty; } if (e2.szConditionName == null) { e2.szConditionName = String.Empty; } if (e2.szSubconditionName == null) { e2.szSubconditionName = String.Empty; } if (e2.szActorID == null) { e2.szActorID = String.Empty; } return(e2); }