/// <summary> /// Called when thes status timer expires. /// </summary> /// <param name="state">The state.</param> private void OnStatusTimerExpired(object state) { try { // create the client if it has not already been created. if (m_defaultClient == null) { m_defaultClient = CreateClient(); m_defaultClient.CreateInstance(); m_lastStatusUpdate = DateTime.UtcNow; } // check if the last status updates appear to be hanging. if (m_lastStatusUpdate.AddMilliseconds(m_statusUpdateInterval * 1.1) < DateTime.UtcNow) { // dispose existing client in the background in case it blocks. ThreadPool.QueueUserWorkItem(OnDisposeClient, m_defaultClient); // create a new client. m_defaultClient = CreateClient(); m_defaultClient.CreateInstance(); } // fetches the status from the server and updates the status node. if (UpdateStatus()) { m_lastStatusUpdate = DateTime.UtcNow; } } catch (Exception e) { ComUtils.TraceComError(e, "Error fetching status from the COM server."); } }
/// <summary> /// Gets the property item ids. /// </summary> /// <param name="itemId">The item id.</param> /// <param name="properties">The properties to update.</param> private void GetPropertyItemIds(string itemId, DaProperty[] properties) { string methodName = "IOPCItemProperties.LookupItemIDs"; int count = properties.Length; // get list of ids to request. int[] propertyIds = new int[count]; for (int ii = 0; ii < propertyIds.Length; ii++) { propertyIds[ii] = properties[ii].PropertyId; } // request the item ids. IntPtr pItemIds = IntPtr.Zero; IntPtr pErrors = IntPtr.Zero; try { IOPCItemProperties server = BeginComCall <IOPCItemProperties>(methodName, true); server.LookupItemIDs( itemId, count, propertyIds, out pItemIds, out pErrors); } catch (Exception e) { if (ComUtils.IsUnknownError(e, ResultIds.E_FAIL, ResultIds.E_UNKNOWNITEMID, ResultIds.E_INVALIDITEMID)) { ComUtils.TraceComError(e, methodName); } return; } finally { EndComCall(methodName); } // unmarshal results. string[] itemIds = ComUtils.GetUnicodeStrings(ref pItemIds, count, true); int[] errors = ComUtils.GetInt32s(ref pErrors, count, true); // update the objects. for (int ii = 0; ii < count; ii++) { if (errors[ii] >= 0) { properties[ii].ItemId = itemIds[ii]; } else { properties[ii].ItemId = null; } } }
/// <summary> /// Writes the values for a set of items. /// </summary> public int[] SyncWrite(int[] serverHandles, object[] values, int count) { // initialize output parameters. IntPtr pErrors = IntPtr.Zero; string methodName = "IOPCSyncIO.Write"; try { IOPCSyncIO server = BeginComCall <IOPCSyncIO>(methodName, true); server.Write( count, serverHandles, values, out pErrors); } catch (Exception e) { ComUtils.TraceComError(e, methodName); return(null); } finally { EndComCall(methodName); } // unmarshal output parameters. return(ComUtils.GetInt32s(ref pErrors, count, true)); }
/// <summary> /// Creates an instance of the COM server. /// </summary> public void CreateInstance() { // multiple calls are not allowed - may block for a while due to network operation. lock (m_lock) { ServerFactory factory = new ServerFactory(); try { // create the server. Unknown = factory.CreateServer(new Uri(m_url), null); // fetch the available locales. m_availableLocaleIds = QueryAvailableLocales(); // do any post-connect processing. OnConnected(); } catch (Exception e) { ComUtils.TraceComError(e, "Could not connect to server ({0}).", m_url); // cleanup on error. Close(); } finally { factory.Dispose(); } } }
/// <summary> /// Modifies the group. /// </summary> /// <returns>The error. S_OK on success.</returns> public int ModifyGroup() { m_actualSamplingInterval = 0; int localeId = m_server.LocaleId; GCHandle hSamplingInterval = GCHandle.Alloc(m_samplingInterval, GCHandleType.Pinned); GCHandle hDeadband = GCHandle.Alloc(m_deadband, GCHandleType.Pinned); string methodName = "IOPCGroupStateMgt.SetState"; try { IOPCGroupStateMgt server = BeginComCall <IOPCGroupStateMgt>(methodName, true); server.SetState( hSamplingInterval.AddrOfPinnedObject(), out m_actualSamplingInterval, IntPtr.Zero, IntPtr.Zero, hDeadband.AddrOfPinnedObject(), IntPtr.Zero, IntPtr.Zero); /* * Utils.Trace( * "Group {0} Modified({4}) {1}/{2}ms {3}%", * m_clientHandle, * m_samplingInterval, * m_actualSamplingInterval, * m_deadband, * m_items.Count); */ return(ResultIds.S_OK); } catch (Exception e) { ComUtils.TraceComError(e, methodName); return(Marshal.GetHRForException(e)); } finally { EndComCall(methodName); hSamplingInterval.Free(); hDeadband.Free(); } }
/// <summary> /// Creates a group. /// </summary> public object CreateGroup( int groupId, int samplingInterval, float deadband, out int groupHandle, out int revisedSamplingInterval) { groupHandle = 0; revisedSamplingInterval = 0; GCHandle hDeadband = GCHandle.Alloc(deadband, GCHandleType.Pinned); string methodName = "IOPCServer.AddGroup"; try { IOPCServer server = BeginComCall <IOPCServer>(methodName, true); object group = null; Guid iid = typeof(OpcRcw.Da.IOPCItemMgt).GUID; server.AddGroup( String.Empty, 1, samplingInterval, 0, IntPtr.Zero, hDeadband.AddrOfPinnedObject(), ComUtils.LOCALE_SYSTEM_DEFAULT, out groupHandle, out revisedSamplingInterval, ref iid, out group); return(group); } catch (Exception e) { ComUtils.TraceComError(e, methodName); return(null); } finally { EndComCall(methodName); hDeadband.Free(); } }
/// <summary> /// Reads the values for a set of items. /// </summary> public DaValue[] SyncRead(int[] serverHandles, int count) { // initialize output parameters. IntPtr pValues = IntPtr.Zero; IntPtr pErrors = IntPtr.Zero; if (count > 0) { string methodName = "IOPCSyncIO.Read"; try { IOPCSyncIO server = BeginComCall <IOPCSyncIO>(methodName, true); server.Read( OPCDATASOURCE.OPC_DS_DEVICE, count, serverHandles, out pValues, out pErrors); } catch (Exception e) { ComUtils.TraceComError(e, methodName); return(null); } finally { EndComCall(methodName); } } // unmarshal output parameters. DaValue[] values = GetItemValues(ref pValues, count, true); int[] errors = ComUtils.GetInt32s(ref pErrors, count, true); // save error codes. for (int ii = 0; ii < count; ii++) { values[ii].Error = errors[ii]; } return(values); }
/// <summary> /// Removes a group. /// </summary> public void RemoveGroup(int groupHandle) { string methodName = "IOPCServer.RemoveGroup"; try { IOPCServer server = BeginComCall <IOPCServer>(methodName, true); server.RemoveGroup(groupHandle, 0); } catch (Exception e) { ComUtils.TraceComError(e, methodName); return; } finally { EndComCall(methodName); } }
/// <summary> /// Creates an instance of the COM server. /// </summary> public void CreateInstance() { // multiple calls are not allowed - may block for a while due to network operation. lock (m_lock) { ServerFactory factory = new ServerFactory(); try { // create the server. Unknown = factory.CreateServer(new Uri(m_url), null); // set the locale. SetLocale(LocaleId); if (UserIdentity != null) { SetUserIdentity(UserIdentity); } // do any post-connect processing. OnConnected(); } catch (Exception e) { ComUtils.TraceComError(e, "Could not connect to server ({0}).", m_url); // cleanup on error. Close(); } finally { factory.Dispose(); } } }
/// <summary> /// Called when thes status timer expires. /// </summary> /// <param name="state">The state.</param> private void OnStatusTimerExpired(object state) { try { // create the client if it has not already been created. if (m_defaultClient == null) { m_defaultClient = CreateClient(); m_defaultClient.Key = String.Empty; // set default locale. if (AvailableLocaleIds != null && AvailableLocaleIds.Length > 0) { m_defaultClient.LocaleId = AvailableLocaleIds[0]; } else { m_defaultClient.LocaleId = ComUtils.LOCALE_SYSTEM_DEFAULT; } m_defaultClient.CreateInstance(); m_lastStatusUpdate = DateTime.UtcNow; } // check if the last status updates appear to be hanging. bool reconnected = false; if (m_lastStatusUpdate.AddMilliseconds(m_statusUpdateInterval * 1.1) < DateTime.UtcNow) { if (m_reconnecting) { return; } m_reconnecting = true; try { Utils.Trace("Communication with COM server failed. Disposing server and reconnecting."); // dispose existing client in the background in case it blocks. ThreadPool.QueueUserWorkItem(OnDisposeClient, m_defaultClient); // dispose localized clients. if (m_localizedClients != null) { foreach (ComClient localizedClient in m_localizedClients.Values) { ThreadPool.QueueUserWorkItem(OnDisposeClient, localizedClient); } m_localizedClients.Clear(); } // create a new client. m_defaultClient = CreateClient(); m_defaultClient.CreateInstance(); reconnected = true; } finally { m_reconnecting = false; } } // fetches the status from the server and updates the status node. if (UpdateStatus()) { AvailableLocaleIds = m_defaultClient.QueryAvailableLocales(); m_lastStatusUpdate = DateTime.UtcNow; if (reconnected && m_reconnectCallback != null) { m_reconnectCallback(this); } } } catch (Exception e) { ComUtils.TraceComError(e, "Error fetching status from the COM server."); } }
/// <summary> /// Removes the items from the group that have been marked as deleted. /// </summary> public void RemoveItems() { // count the number of items to remove. List <GroupItem> itemsToRemove = new List <GroupItem>(); lock (Lock) { List <GroupItem> itemsToKeep = new List <GroupItem>(); for (int ii = 0; ii < m_items.Count; ii++) { if (m_items[ii].Deleted && m_items[ii].Created) { itemsToRemove.Add(m_items[ii]); continue; } itemsToKeep.Add(m_items[ii]); } m_items = itemsToKeep; } // check if nothing to do. if (itemsToRemove.Count == 0) { return; } // build list of items to remove. int count = itemsToRemove.Count; int[] serverHandles = new int[count]; for (int ii = 0; ii < itemsToRemove.Count; ii++) { serverHandles[ii] = itemsToRemove[ii].ServerHandle; // remove the associated monitored items. if (m_monitoredItems != null) { lock (m_monitoredItems) { m_monitoredItems.Remove(itemsToRemove[ii].ClientHandle); } } } IntPtr pErrors = IntPtr.Zero; string methodName = "IOPCItemMgt.RemoveItems"; try { IOPCItemMgt server = BeginComCall <IOPCItemMgt>(methodName, true); // remove items. server.RemoveItems( count, serverHandles, out pErrors); } catch (Exception e) { ComUtils.TraceComError(e, methodName); for (int ii = 0; ii < itemsToRemove.Count; ii++) { itemsToRemove[ii].Created = false; itemsToRemove[ii].ErrorId = Marshal.GetHRForException(e); } return; } finally { EndComCall(methodName); } // free returned error array. int[] errors = ComUtils.GetInt32s(ref pErrors, count, true); // save error codes. for (int ii = 0; ii < count; ii++) { itemsToRemove[ii].Created = false; itemsToRemove[ii].ErrorId = errors[ii]; } /* * Utils.Trace( * "Group {0} RemoveItems({4}/{5}) {1}/{2}ms {3}%", * m_clientHandle, * m_samplingInterval, * m_actualSamplingInterval, * m_deadband, * itemsToRemove.Count, * m_items.Count); */ }
/// <summary> /// Sets the active state for a set of items in a group. /// </summary> public void ActivateItems(bool active) { // count the number of items to activate. List <GroupItem> itemsToActivate = new List <GroupItem>(); lock (Lock) { for (int ii = 0; ii < m_items.Count; ii++) { if (m_items[ii].ActiveChanged && m_items[ii].Active == active && m_items[ii].Created) { itemsToActivate.Add(m_items[ii]); } } } // check if nothing to do. if (itemsToActivate.Count == 0) { return; } // build list of items to remove. int count = itemsToActivate.Count; int[] serverHandles = new int[count]; for (int ii = 0; ii < itemsToActivate.Count; ii++) { serverHandles[ii] = itemsToActivate[ii].ServerHandle; } // initialize output parameters. IntPtr pErrors = IntPtr.Zero; string methodName = "IOPCItemMgt.SetActiveState"; try { IOPCItemMgt server = BeginComCall <IOPCItemMgt>(methodName, true); server.SetActiveState( count, serverHandles, (active) ? 1 : 0, out pErrors); } catch (Exception e) { ComUtils.TraceComError(e, methodName); for (int ii = 0; ii < itemsToActivate.Count; ii++) { itemsToActivate[ii].ActiveChanged = false; itemsToActivate[ii].ErrorId = Marshal.GetHRForException(e); } } finally { EndComCall(methodName); } // free returned error array. int[] errors = ComUtils.GetInt32s(ref pErrors, count, true); // save error codes. for (int ii = 0; ii < count; ii++) { itemsToActivate[ii].ActiveChanged = false; itemsToActivate[ii].ErrorId = errors[ii]; } /* * Utils.Trace( * "Group {0} ActivateItems({4}/{5}) {1}/{2}ms {3}%", * m_clientHandle, * m_samplingInterval, * m_actualSamplingInterval, * m_deadband, * active, * itemsToActivate.Count); */ }
/// <summary> /// Adds all items to the group that have not already been added. /// </summary> public void AddItems() { // count the number of items to add. List <GroupItem> itemsToAdd = new List <GroupItem>(); lock (Lock) { for (int ii = 0; ii < m_items.Count; ii++) { if (!m_items[ii].Created) { itemsToAdd.Add(m_items[ii]); } } } // check if nothing to do. if (itemsToAdd.Count == 0) { return; } // create item definitions. int count = itemsToAdd.Count; OpcRcw.Da.OPCITEMDEF[] definitions = new OpcRcw.Da.OPCITEMDEF[count]; for (int ii = 0; ii < count; ii++) { definitions[ii] = new OpcRcw.Da.OPCITEMDEF(); definitions[ii].szItemID = itemsToAdd[ii].ItemId; definitions[ii].bActive = (itemsToAdd[ii].Active) ? 1 : 0; definitions[ii].szAccessPath = String.Empty; definitions[ii].vtRequestedDataType = (short)VarEnum.VT_EMPTY; definitions[ii].hClient = itemsToAdd[ii].ClientHandle; } // initialize output parameters. IntPtr pResults = IntPtr.Zero; IntPtr pErrors = IntPtr.Zero; // add items to group. string methodName = "IOPCItemMgt.AddItems"; try { IOPCItemMgt server = BeginComCall <IOPCItemMgt>(methodName, true); server.AddItems( count, definitions, out pResults, out pErrors); } catch (Exception e) { ComUtils.TraceComError(e, methodName); for (int ii = 0; ii < itemsToAdd.Count; ii++) { itemsToAdd[ii].ErrorId = Marshal.GetHRForException(e); } return; } finally { EndComCall(methodName); } // unmarshal output parameters. int[] serverHandles = GetItemResults(ref pResults, count, true); int[] errors = ComUtils.GetInt32s(ref pErrors, count, true); // save handles and error codes. for (int ii = 0; ii < count; ii++) { GroupItem item = itemsToAdd[ii]; item.ServerHandle = serverHandles[ii]; item.ErrorId = errors[ii]; if (item.ErrorId >= 0) { itemsToAdd[ii].Created = true; } } /* * Utils.Trace( * "Group {0} AddItems({4}/{5}) {1}/{2}ms {3}%", * m_clientHandle, * m_samplingInterval, * m_actualSamplingInterval, * m_deadband, * itemsToAdd.Count, * m_items.Count); */ }
/// <summary> /// Must called if a COM call returns an unexpected exception. /// </summary> /// <param name="methodName">Name of the method.</param> /// <param name="e">The exception.</param> /// <remarks>Note that some COM calls are expected to return errors.</remarks> protected void ComCallError(string methodName, Exception e) { ComUtils.TraceComError(e, methodName); }
/// <summary> /// Reads the values of the properties from the server. /// </summary> /// <param name="itemId">The item id.</param> /// <param name="propertyIds">The list of property ids to read. All properties are read if null.</param> /// <returns>True if the element has properies.</returns> private DaValue[] ReadPropertyValues(string itemId, params int[] propertyIds) { string methodName = "IOPCItemProperties.GetItemProperties"; // check for trivial case. if (propertyIds == null) { return(null); } int count = propertyIds.Length; DaValue[] results = new DaValue[count]; // check for empty list. if (count == 0) { return(results); } // get the values from the server. IntPtr pValues = IntPtr.Zero; IntPtr pErrors = IntPtr.Zero; try { IOPCItemProperties server = BeginComCall <IOPCItemProperties>(methodName, true); server.GetItemProperties( itemId, count, propertyIds, out pValues, out pErrors); } catch (Exception e) { if (ComUtils.IsUnknownError(e, ResultIds.E_FAIL, ResultIds.E_UNKNOWNITEMID, ResultIds.E_INVALIDITEMID)) { ComUtils.TraceComError(e, methodName); return(null); } for (int ii = 0; ii < count; ii++) { DaValue result = results[ii] = new DaValue(); result.Value = null; result.Quality = OpcRcw.Da.Qualities.OPC_QUALITY_GOOD; result.Timestamp = DateTime.UtcNow; result.Error = Marshal.GetHRForException(e); } return(results); } finally { EndComCall(methodName); } // unmarshal results. object[] values = ComUtils.GetVARIANTs(ref pValues, count, true); int[] errors = ComUtils.GetInt32s(ref pErrors, count, true); for (int ii = 0; ii < count; ii++) { DaValue result = results[ii] = new DaValue(); result.Value = ComUtils.ProcessComValue(values[ii]); result.Quality = OpcRcw.Da.Qualities.OPC_QUALITY_GOOD; result.Timestamp = DateTime.UtcNow; result.Error = errors[ii]; } return(results); }
/// <summary> /// Read the available non-built in properties from the server. /// </summary> /// <param name="itemId">The item id.</param> /// <param name="updateCache">if set to <c>true</c> the cache is updated.</param> /// <returns>The array of properties.</returns> public DaProperty[] ReadAvailableProperties(string itemId, bool updateCache) { string methodName = "IOPCItemProperties.QueryAvailableProperties"; // query for available properties. int count = 0; IntPtr pPropertyIds = IntPtr.Zero; IntPtr pDescriptions = IntPtr.Zero; IntPtr pDataTypes = IntPtr.Zero; try { IOPCItemProperties server = BeginComCall <IOPCItemProperties>(methodName, true); server.QueryAvailableProperties( itemId, out count, out pPropertyIds, out pDescriptions, out pDataTypes); } catch (Exception e) { if (ComUtils.IsUnknownError(e, ResultIds.E_FAIL, ResultIds.E_UNKNOWNITEMID, ResultIds.E_INVALIDITEMID)) { ComUtils.TraceComError(e, methodName); } return(null); } finally { EndComCall(methodName); } // unmarshal results. int[] propertyIds = ComUtils.GetInt32s(ref pPropertyIds, count, true); string[] descriptions = ComUtils.GetUnicodeStrings(ref pDescriptions, count, true); short[] datatype = ComUtils.GetInt16s(ref pDataTypes, count, true); List <DaProperty> properties = new List <DaProperty>(); for (int ii = 0; ii < count; ii++) { // do not return any of the built in properties. if (propertyIds[ii] <= PropertyIds.TimeZone) { continue; } DaProperty property = new DaProperty(); property.PropertyId = propertyIds[ii]; property.Name = descriptions[ii]; property.DataType = datatype[ii]; properties.Add(property); } // fetch the item ids. if (properties.Count > 0) { DaProperty[] array = properties.ToArray(); GetPropertyItemIds(itemId, array); // update the cache. if (updateCache) { lock (m_cache) { DaElement element = null; if (m_cache.TryGetValue(itemId, out element)) { element.Properties = array; } } } return(array); } return(null); }