/// <summary> /// Finds the category for the event. /// </summary> private AeEventCategory FindCategory(Session session, AeEvent e) { AeEventCategory category = m_mapper.GetCategory(e.EventType); NodeId subTypeId = e.EventType; NodeId superTypeId = null; // follow the type tree if type not recognized. while (category == null) { superTypeId = session.NodeCache.FindSuperType(subTypeId); if (!NodeId.IsNull(superTypeId)) { category = m_mapper.GetCategory(superTypeId); if (category != null) { return(category); } } subTypeId = superTypeId; } // default to base event type. if (category == null) { category = m_mapper.GetCategory(Opc.Ua.ObjectTypeIds.BaseEventType); } return(category); }
/// <summary> /// Processes an event (assigns a cookie if acknowledgment is required). /// </summary> public void ProcessEvent(AeEvent e) { if (NodeId.IsNull(e.ConditionId)) { return; } lock (m_lock) { string conditionId = GetConditionId(e); // assign a cookie to the condition/branch. int cookie = 0; if (!m_cookies.TryGetValue(conditionId, out cookie)) { cookie = ++m_counter; m_cookies[conditionId] = cookie; } // remove acked events. if (e.AckedState) { m_events.Remove(cookie); m_cookies.Remove(conditionId); } // save event for acking. else { m_events[cookie] = e; e.Cookie = cookie; } } }
/// <summary> /// Combines the condition id/branch id in a unique identifier. /// </summary> private string GetConditionId(AeEvent e) { StringBuilder buffer = new StringBuilder(); buffer.Append(e.ConditionId); if (NodeId.IsNull(e.BranchId)) { buffer.Append(e.BranchId); } return(buffer.ToString()); }
/// <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; }
/// <summary> /// Acknowledges one or more events. /// </summary> public int[] AcknowledgeEvents( Session session, string comment, string acknowledgerId, AeAcknowledgeRequest[] requests) { if (session == null || !session.Connected) { throw ComUtils.CreateComException(ResultIds.E_FAIL); } StringBuilder buffer = new StringBuilder(); buffer.Append('['); buffer.Append(acknowledgerId); buffer.Append(']'); if (!String.IsNullOrEmpty(comment)) { buffer.Append(comment); } // wrap the comment once. Variant commentToWrite = new Variant(new LocalizedText(buffer.ToString())); int[] errors = new int[requests.Length]; CallMethodRequestCollection methodsToCall = new CallMethodRequestCollection(); for (int ii = 0; ii < requests.Length; ii++) { int cookie = requests[ii].Cookie; AeEvent e = null; lock (m_lock) { // look up the event. if (!m_events.TryGetValue(cookie, out e)) { errors[ii] = ResultIds.E_INVALIDARG; if (cookie < m_counter) { errors[ii] = ResultIds.S_ALREADYACKED; } continue; } if (e.SourceName != requests[ii].SourceName) { errors[ii] = ResultIds.E_INVALIDARG; continue; } if (e.ConditionName != requests[ii].ConditionName) { errors[ii] = ResultIds.E_INVALIDARG; continue; } if (e.ActiveTime != requests[ii].ActiveTime) { errors[ii] = ResultIds.E_INVALIDTIME; continue; } // check that the cookie is still valid. string conditionId = GetConditionId(e); int expectedCookie = 0; if (!m_cookies.TryGetValue(conditionId, out expectedCookie)) { errors[ii] = ResultIds.S_ALREADYACKED; continue; } // check cookie. if (expectedCookie != cookie) { errors[ii] = ResultIds.E_INVALIDARG; continue; } m_events.Remove(cookie); } CallMethodRequest request = new CallMethodRequest(); request.MethodId = Opc.Ua.MethodIds.AcknowledgeableConditionType_Acknowledge; request.ObjectId = e.ConditionId; request.InputArguments.Add(new Variant(e.EventId)); request.InputArguments.Add(commentToWrite); request.Handle = ii; methodsToCall.Add(request); } if (methodsToCall.Count > 0) { try { // call the server. CallMethodResultCollection results = null; DiagnosticInfoCollection diagnosticInfos = null; session.Call( null, methodsToCall, out results, out diagnosticInfos); // verify that the server returned the correct number of results. ClientBase.ValidateResponse(results, methodsToCall); ClientBase.ValidateDiagnosticInfos(diagnosticInfos, methodsToCall); // process results. for (int ii = 0; ii < methodsToCall.Count; ii++) { int index = (int)methodsToCall[ii].Handle; if (StatusCode.IsBad(results[ii].StatusCode)) { errors[ii] = ResultIds.E_FAIL; continue; } } } catch (Exception) { // report error. for (int ii = 0; ii < methodsToCall.Count; ii++) { int index = (int)methodsToCall[ii].Handle; errors[ii] = ResultIds.E_FAIL; } } } return(errors); }
/// <summary> /// Translates an event notification in an AE event. /// </summary> public AeEvent TranslateNotification(Session session, EventFieldList e) { AeEvent e2 = new AeEvent(); // extract the required event fields. int index = 0; e2.EventId = ExtractField <byte[]>(e, index++, null); e2.EventType = ExtractField <NodeId>(e, index++, null); e2.SourceName = ExtractField <string>(e, index++, null); e2.Time = ExtractField <DateTime>(e, index++, DateTime.MinValue); e2.Message = ExtractField <LocalizedText>(e, index++, null); e2.Severity = ExtractField <ushort>(e, index++, 0); if ((EventTypes & OpcRcw.Ae.Constants.TRACKING_EVENT) != 0) { e2.AuditUserId = ExtractField <string>(e, index++, null); } if ((EventTypes & OpcRcw.Ae.Constants.CONDITION_EVENT) != 0) { e2.BranchId = ExtractField <byte[]>(e, index++, null); e2.ConditionName = ExtractField <string>(e, index++, null); e2.Quality = ExtractField <StatusCode>(e, index++, StatusCodes.Good); e2.Comment = ExtractField <LocalizedText>(e, index++, null); e2.CommentUserId = ExtractField <string>(e, index++, null); e2.EnabledState = ExtractField <bool>(e, index++, false); e2.AckedState = ExtractField <bool>(e, index++, false); e2.ActiveState = ExtractField <bool>(e, index++, false); e2.ActiveTime = ExtractField <DateTime>(e, index++, DateTime.MinValue); e2.LimitState = ExtractField <LocalizedText>(e, index++, null); e2.HighHighState = ExtractField <LocalizedText>(e, index++, null); e2.HighState = ExtractField <LocalizedText>(e, index++, null); e2.LowState = ExtractField <LocalizedText>(e, index++, null); e2.LowLowState = ExtractField <LocalizedText>(e, index++, null); // condition id is always last. e2.ConditionId = ExtractField <NodeId>(e, e.EventFields.Count - 1, null); } // find the category for the event. e2.Category = FindCategory(session, e2); // extract any additional attributes. if (RequestedAttributeIds != null) { uint[] attributeIds = null; if (!RequestedAttributeIds.TryGetValue(e2.Category.LocalId, out attributeIds)) { return(e2); } // nothing more to do. if (attributeIds == null || attributeIds.Length == 0) { return(e2); } // search for the requested attributes. object[] values = new object[attributeIds.Length]; for (int ii = 0; ii < attributeIds.Length; ii++) { // look for matching attribute. for (int jj = 0; jj < SelectedAttributes.Count; jj++) { if (jj >= e.EventFields.Count) { break; } AeEventAttribute attribute = SelectedAttributes[jj]; if (attribute == null || attribute.LocalId != attributeIds[ii]) { continue; } values[ii] = GetLocalAttributeValue(e.EventFields[jj], attribute); } } e2.AttributeValues = values; } return(e2); }
/// <summary> /// Combines the condition id/branch id in a unique identifier. /// </summary> private string GetConditionId(AeEvent e) { StringBuilder buffer = new StringBuilder(); buffer.Append(e.ConditionId); if (NodeId.IsNull(e.BranchId)) { buffer.Append(e.BranchId); } return buffer.ToString(); }
private void OnEventNotification(Subscription subscription, EventNotificationList notification, IList <string> stringTable) { try { // check if disposed. if (m_disposed) { return; } // check if session still active. Session session = m_server.Session; if (session == null || !session.Connected) { return; } // check if events are being reported. if (m_callback == null) { return; } lock (m_lock) { foreach (EventFieldList e in notification.Events) { // translate the notification and send the response. AeEvent e2 = m_filter.TranslateNotification(m_server.Session, e); if (e2 != null) { // check if refresh has started. if (e2.EventType == Opc.Ua.ObjectTypeIds.RefreshStartEventType) { m_refreshInProgress = true; continue; } // check if refresh has ended. if (e2.EventType == Opc.Ua.ObjectTypeIds.RefreshEndEventType) { m_refreshInProgress = false; // turn off publishing if the subscription is not active, if (!Active) { m_subscription.SetPublishingMode(false); List <MonitoredItem> itemsToUpdate = new List <MonitoredItem>(m_notifiers.Values); m_subscription.SetMonitoringMode(MonitoringMode.Disabled, itemsToUpdate); } if (m_refreshQueue != null) { ThreadPool.QueueUserWorkItem(DoRefresh, m_refreshQueue); } continue; } // cache any conditions requiring acknowledgement. m_conditionManager.ProcessEvent(e2); // queue on refresh. if (m_refreshInProgress) { if (m_refreshQueue != null) { m_refreshQueue.Enqueue(e2); } continue; } // queue the event. if (Active) { lock (m_queue) { m_queue.Enqueue(e2); } } } } } } catch (Exception exception) { Utils.Trace(exception, "Error processing event callback."); } }
/// <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); }