/// <summary> /// 写数据 /// </summary> /// <param name="opcDataItem"></param> /// <param name="value"></param> /// <returns></returns> public OpcResult Write(OpcDataItem opcDataItem, object value) { OpcResult opcResult = OpcResult.Unknow; //如果未连接那么返回 if (!this.IsConnected) { if (!Equals(null, OnErrorHappened)) { OnErrorHappened(this, new OpcErrorEventArgs(OpcResult.E_FAIL, "Opc服务器未连接,请先连接再写数据项", null)); } return(opcResult); } try { if (Equals(null, opcDataItem)) { throw new ArgumentNullException("opcDataItem参数不能为空。"); } Opc.Da.Subscription tmpSubscription = this.opcServer.Subscriptions.Cast <Opc.Da.Subscription>().FirstOrDefault(a => a.State.UpdateRate == opcDataItem.UpdateRate); var itemValue = new ItemValue((ItemIdentifier)tmpSubscription.Items.FirstOrDefault(a => a.ItemName == opcDataItem.Name)); //itemValue.Value = opcDataItem.NewValue; itemValue.Value = value; var results = tmpSubscription.Write(new ItemValue[] { itemValue }); //写多次 //for (int i = 0; i < 20; i++) //{ results = tmpSubscription.Write(new ItemValue[] { itemValue }); //} if (results.Count() < 1 && !Equals(null, OnErrorHappened)) { opcResult = OpcResult.E_UNKNOWN_ITEM_NAME; OnErrorHappened(this, new OpcErrorEventArgs(opcResult, "写入数据项时发生错误,未找到数据项:" + opcDataItem.Name, null)); opcDataItem.Quality = OpcResult.Unknow; return(opcResult); } foreach (var v in results) { Enum.TryParse <OpcResult>(v.ResultID.ToString(), out opcResult); if (v.ResultID != Opc.ResultID.S_OK && !Equals(null, OnErrorHappened)) { Enum.TryParse <OpcResult>(v.ResultID.ToString(), out opcResult); OnErrorHappened(this, new OpcErrorEventArgs(opcResult, "写入数据项时发生错误:" + v.ResultID.Name, null)); } }//end foreach return(opcResult); } catch (Exception ex) { if (!Equals(null, OnErrorHappened)) { OnErrorHappened(this, new OpcHelper.OpcErrorEventArgs(OpcResult.E_FAIL, "写入数据时错误。", ex)); } return(opcResult); } }
/// <summary> /// 读数据 /// </summary> /// <param name="opcDataItem"></param> /// <returns></returns> public OpcDataItem Read(OpcDataItem opcDataItem) { OpcDataItem opcDataItemResult = null; //如果未连接那么返回 if (!this.IsConnected) { if (!Equals(null, OnErrorHappened)) { OnErrorHappened(this, new OpcErrorEventArgs(OpcResult.E_FAIL, "Opc服务器未连接,请先连接再读取数据项", null)); } return(opcDataItemResult); } try { if (Equals(null, opcDataItem)) { throw new ArgumentNullException("opcDataItem参数不能为空。"); } Opc.Da.Subscription tmpSubscription = this.opcServer.Subscriptions.Cast <Opc.Da.Subscription>().FirstOrDefault(a => a.State.UpdateRate == opcDataItem.UpdateRate); var item = tmpSubscription.Items.Where(a => a.ItemName == opcDataItem.Name); var results = tmpSubscription.Read(item.ToArray()); OpcResult opcResult; if (results.Count() < 1 && !Equals(null, OnErrorHappened)) { opcResult = OpcResult.E_UNKNOWN_ITEM_NAME; OnErrorHappened(this, new OpcErrorEventArgs(opcResult, "读取数据项时发生错误,未找到数据项:" + opcDataItem.Name, null)); opcDataItem.Quality = OpcResult.E_UNKNOWN_ITEM_NAME; return(opcDataItem); } foreach (var v in results) { Enum.TryParse <OpcResult>(v.ResultID.ToString(), out opcResult); opcDataItemResult = this.OpcDataItems.FirstOrDefault(a => a.Name == opcDataItem.Name); opcDataItemResult.Quality = opcResult; opcDataItemResult.OldValue = opcDataItemResult.NewValue; opcDataItemResult.NewValue = v.Value; if (v.ResultID != Opc.ResultID.S_OK && !Equals(null, OnErrorHappened)) { Enum.TryParse <OpcResult>(v.ResultID.ToString(), out opcResult); OnErrorHappened(this, new OpcErrorEventArgs(opcResult, "读取数据项时发生错误:" + v.ResultID.Name, null)); } }//end foreach return(opcDataItemResult.Clone() as OpcDataItem); } catch (Exception ex) { if (!Equals(null, OnErrorHappened)) { OnErrorHappened(this, new OpcHelper.OpcErrorEventArgs(OpcResult.E_FAIL, "读取数据时错误。", ex)); } return(opcDataItemResult); } }
/// <summary> /// 数据改变事件函数 /// </summary> /// <param name="subscriptionHandle"></param> /// <param name="requestHandle"></param> /// <param name="values"></param> private void ThisSubscription_DataChanged(object subscriptionHandle, object requestHandle, Opc.Da.ItemValueResult[] values) { if (!Equals(null, OnDataChanged) && IsConnected && !Equals(null, OpcDataItems)) { //异步方式 //System.Threading.Tasks.Parallel.ForEach<ItemValueResult>(values, (v) => //{ // OpcDataItem item = OpcDataItems.FirstOrDefault(a => a.Name == v.ItemName); // if (Equals(null, item)) // { // return; // } // OpcResult opcResult = OpcResult.Unknow; // Enum.TryParse<OpcResult>(v.ResultID.ToString(), out opcResult); // item.Name = v.ItemName; // item.Quality = opcResult; // item.OldValue = item.NewValue; // item.NewValue = v.Value.ToString(); // OnDataChanged(this, new OpcDataEventArgs(opcResult, item)); //}); //同步方式 foreach (var v in values) { OpcDataItem item = OpcDataItems.FirstOrDefault(a => a.Name == v.ItemName); if (Equals(null, item)) { //OnDataChanged(this, new OpcDataEventArgs(OpcResult.E_FAIL, item)); continue; } OpcResult opcResult = OpcResult.Unknow; Enum.TryParse <OpcResult>(v.ResultID.ToString(), out opcResult); item.Name = v.ItemName; item.Quality = opcResult; item.OldValue = item.NewValue; item.NewValue = v.Value?.ToString(); OnDataChanged(this, new OpcDataEventArgs(opcResult, item)); } } }
/// <summary> /// 注册Opc数据项集合 /// </summary> /// <param name="opcDataItems"></param> private void registerOpcDataItems(IList <OpcDataItem> opcDataItems) { this.OpcDataItems = opcDataItems; daemonTimer.Enabled = false; daemonTimer.Stop(); //如果未连接那么返回 if (!this.IsConnected) { if (!Equals(null, OnErrorHappened)) { OnErrorHappened(this, new OpcErrorEventArgs(OpcResult.E_FAIL, "Opc服务器未连接,请先连接在订阅数据项", null)); } return; } #region 没有数据项那么清空所有订阅 //如果订阅的DataItem没有,那么清空现在所有订阅 if (Equals(null, opcDataItems) || opcDataItems.Count() < 1) { if (!Equals(this.opcServer.Subscriptions, null) && this.opcServer.Subscriptions.Count > 0) { foreach (Opc.Da.Subscription thisSubscription in this.opcServer.Subscriptions) { thisSubscription.RemoveItems(thisSubscription.Items); thisSubscription.DataChanged -= ThisSubscription_DataChanged; this.opcServer.CancelSubscription(thisSubscription); thisSubscription.Dispose(); } this.opcServer.Subscriptions.Clear(); //订阅项取消后通知外部程序 if (!Equals(null, OnLogHappened)) { OnLogHappened(this, new OpcHelper.OpcLogEventArgs("已经取消所有订阅")); } return; } } #endregion 数据项需要更新或者删除 //根据要订阅的新数据项,增加或者移除现在的订阅 if (!IsConnected) { if (!Equals(null, OnLogHappened)) { OnLogHappened(this, new OpcLogEventArgs("Opc服务器已断开")); } return; } //根据更新频率分组 var dataItemGroups = from a in opcDataItems group a by a.UpdateRate into g select new { UpdateRate = g.Key, DataItems = g }; //循环每组订阅对象,查询是否实际订阅,有则更新,没有则新建 foreach (var dataItemGroup in dataItemGroups) { Opc.Da.Subscription thisSubscription = this.opcServer.Subscriptions.Cast <Opc.Da.Subscription>().FirstOrDefault(a => a.State.UpdateRate == dataItemGroup.UpdateRate); //未找到已经订阅的组,那么新建组并添加订阅项 if (Equals(null, thisSubscription)) { if (!IsConnected) { if (!Equals(null, OnLogHappened)) { OnLogHappened(this, new OpcLogEventArgs("Opc服务器已断开")); } return; } #region 增加订阅 //创建订阅组。订阅组状态的名称是更新频率 Opc.Da.Subscription newSubscription = this.opcServer.CreateSubscription (CreateSubscriptionState(dataItemGroup.UpdateRate.ToString(), dataItemGroup.UpdateRate)) as Opc.Da.Subscription;//创建组 //创建opc订阅项 var opcItems = ConvertItems(dataItemGroup.DataItems); //添加订阅项 var results = newSubscription.AddItems(opcItems.ToArray()); newSubscription.DataChanged += ThisSubscription_DataChanged; //订阅的结果通过事件通知给外部调用程序 foreach (var v in results) { if (!IsConnected) { if (!Equals(null, OnLogHappened)) { OnLogHappened(this, new OpcLogEventArgs("Opc服务器已断开")); } return; } //订阅成功更新状态 if (v.ResultID == Opc.ResultID.S_OK) { OpcResult opcResult = OpcResult.Unknow; Enum.TryParse <OpcResult>(v.ResultID.ToString(), out opcResult); OpcDataItems.FirstOrDefault(a => a.Name == v.ItemName).Quality = opcResult; } //未订阅成功,异常事件通知 else if (v.ResultID == Opc.ResultID.S_OK && !Equals(null, OnDataChanged)) { OnDataChanged(this, new OpcDataEventArgs(OpcResult.DataItemRegistered, dataItemGroup.DataItems.FirstOrDefault(a => a.Name == v.ItemName))); } else if (v.ResultID != Opc.ResultID.S_OK && !Equals(null, OnErrorHappened)) { OpcResult opcResult = OpcResult.Unknow; Enum.TryParse <OpcResult>(v.ResultID.ToString(), out opcResult); this.OpcDataItems.FirstOrDefault(a => a.Name == v.ItemName).Quality = opcResult; OnErrorHappened(this, new OpcErrorEventArgs(opcResult, "订阅数据项时发生错误" + v.ResultID.Name, null)); } }//end foreach #endregion } else//已经有订阅组,那么更新订阅项 { if (!IsConnected) { if (!Equals(null, OnLogHappened)) { OnLogHappened(this, new OpcLogEventArgs("Opc服务器已断开")); } return; } #region 已经有订阅组,那么更新订阅项 //查询要新增加的点, IList <OpcDataItem> newItems = new List <OpcDataItem>(); foreach (var v in dataItemGroup.DataItems) { if (!thisSubscription.Items.Any(a => a.ItemName == v.Name)) { newItems.Add(v); } } var opcItems = ConvertItems(newItems); //添加订阅项 var addResults = thisSubscription.AddItems(opcItems.ToArray()); //订阅的结果通过事件通知给外部调用程序 foreach (var v in addResults) { if (!IsConnected) { if (!Equals(null, OnLogHappened)) { OnLogHappened(this, new OpcLogEventArgs("Opc服务器已断开")); } return; } //订阅成功更新状态 if (v.ResultID == Opc.ResultID.S_OK) { OpcResult opcResult = OpcResult.Unknow; Enum.TryParse <OpcResult>(v.ResultID.ToString(), out opcResult); OpcDataItems.FirstOrDefault(a => a.Name == v.ItemName).Quality = opcResult; } //未订阅成功,异常事件通知 else if (v.ResultID == Opc.ResultID.S_OK && !Equals(null, OnDataChanged)) { OnDataChanged(this, new OpcDataEventArgs(OpcResult.DataItemRegistered, dataItemGroup.DataItems.FirstOrDefault(a => a.Name == v.ItemName))); } else if (v.ResultID != Opc.ResultID.S_OK && !Equals(null, OnErrorHappened)) { OpcResult opcResult = OpcResult.Unknow; Enum.TryParse <OpcResult>(v.ResultID.ToString(), out opcResult); this.OpcDataItems.FirstOrDefault(a => a.Name == v.ItemName).Quality = opcResult; OnErrorHappened(this, new OpcErrorEventArgs(opcResult, "订阅数据项时发生错误:" + v.ItemName + " 无效,OpcResult=" + v.ResultID.Name, null)); } }//end foreach //查询要删除的点, IList <Opc.Da.Item> deleteItems = new List <Opc.Da.Item>(); foreach (var v in thisSubscription.Items) { if (!dataItemGroup.DataItems.Any(a => a.Name == v.ItemName)) { deleteItems.Add(v); } } //删除已经订阅点 var deleteResults = thisSubscription.RemoveItems(deleteItems.ToArray()); //订阅的结果通过事件通知给外部调用程序 foreach (var v in deleteResults) { if (!IsConnected) { if (!Equals(null, OnLogHappened)) { OnLogHappened(this, new OpcLogEventArgs("Opc服务器已断开")); } return; } //未订阅成功,异常事件通知 if (v.ResultID == Opc.ResultID.S_OK && !Equals(null, OnDataChanged)) { OpcDataItem tmp2 = new OpcDataItem(v.ItemName, thisSubscription.State.UpdateRate, "", "", OpcResult.DataItemUnregistered); OnDataChanged(this, new OpcDataEventArgs(OpcResult.DataItemUnregistered, tmp2)); } else if (v.ResultID != Opc.ResultID.S_OK && !Equals(null, OnErrorHappened)) { OnErrorHappened(this, new OpcErrorEventArgs(OpcResult.E_FAIL, "取消订阅数据项时发生错误" + v.ResultID.Name, null)); } }//end foreach //删除订阅项后没有item了,那么删除thisSubscription if (thisSubscription.Items.Count() < 1) { thisSubscription.DataChanged -= ThisSubscription_DataChanged; string name = thisSubscription.Name; //this.opcServer.Subscriptions.Remove(thisSubscription); this.opcServer.CancelSubscription(thisSubscription); thisSubscription.Dispose();// if (!Equals(null, OnLogHappened)) { OnLogHappened(this, new OpcLogEventArgs("Subscription " + name + " 已经从订阅组中移除")); } name = null; } #endregion } }//end foreach (var dataItemGroup in dataItemGroups) //删除订阅项后没有item了,那么删除subscription foreach (var subscription in this.opcServer.Subscriptions.Cast <Opc.Da.Subscription>()) { var isHave = dataItemGroups.Any(a => a.UpdateRate == subscription.State.UpdateRate); if (!isHave) { subscription.DataChanged -= ThisSubscription_DataChanged; string name = subscription.Name; //his.opcServer.Subscriptions.Remove(thisSubscription); this.opcServer.CancelSubscription(subscription); subscription.Dispose();// if (!Equals(null, OnLogHappened)) { OnLogHappened(this, new OpcLogEventArgs("Subscription " + name + " 已经从订阅组中移除")); } name = null; } } if (!Equals(null, OnLogHappened)) { OnLogHappened(this, new OpcLogEventArgs("OPC Subscriptions Count:" + this.opcServer.Subscriptions.Count + ".")); } daemonTimer.Enabled = true; daemonTimer.Start(); }
public OpcDataEventArgs(OpcResult opcResult, OpcDataItem opcDataItem) { this.OpcResult = opcResult; this.OpcDataItem = opcDataItem; }