using System; using System.Collections.Generic; using System.Text; using Opc.Ua; using Opc.Ua.Client; using System.Data; using DBFactory; using CommonLib; using Siemens.OpcUA; using CommLayerFactory; using ICommLayer; using System.Collections.Concurrent; using System.Threading; using System.Threading.Tasks; using System.Text.RegularExpressions; namespace OPCClient { public class WorkItem { public object Parameter1 { get; set; } public DataValue Parameter2 { get; set; } // 可以添加更多的属性和参数 public WorkItem(object param1, DataValue param2) { Parameter1 = param1; Parameter2 = param2; } } public static class CCommonOPCClient { static Model.MDevice _device = null; private static ushort S7NameSpace = 2;//20151120,默认值是32位系统的值2,64位系统的值是3 private static Model.MDevice devinfo; private static Object thisLock = new Object(); static ISendDeviceOrder sdo; static Model.MDevice modifypathdevinfo; static Model.MDevice askDevinfo; static StringBuilder[] wv = { new StringBuilder("2") }; static StringBuilder[] witemnames = { new StringBuilder("") }; /// /// 一个周期内一个订阅组发送所有标签的个数 /// static Dictionary _opcSubsTagCount = new Dictionary(); /// /// 每个订阅组里对应设备发送标签名称集合 /// static Dictionary> _opcItemNamesDicInfo = new Dictionary>(); /// /// 每个订阅组里对应设备发送标签数值集合 /// static Dictionary> _opcItemValuesDicInfo = new Dictionary>(); public static event RefreshMonitorEventHandler RefreshMonitor; public static void OnRefreshMonitor(RefreshMonitorEventArgs e) { if (RefreshMonitor != null) { RefreshMonitor(e); } } public static event CUpdateDBEventHandler DealSQLExe; public static void OnDealSQLExe(object sender, CUpdateDBChangeEventArgs e) { DealSQLExe?.Invoke(sender, e); } public static event CUpdateDBEventHandler PublishDeviceState; public static void OnPublishDeviceState(object sender,CUpdateDBChangeEventArgs e) { PublishDeviceState?.Invoke(sender, e); } public static DBOperator dbo =new DBOperator(); //20130510 //20110726 private static Dictionary _connectCount = new Dictionary(); //20110726 public static Dictionary ConnectCount { get { return CCommonOPCClient._connectCount; } set { CCommonOPCClient._connectCount = value; } } private static int[] _plcStates=null ; public static int[] PlcStates { get { return CCommonOPCClient._plcStates; } //set { CCommonOPCClient._plcStates = value; } } private static Server m_Server = null; private static Siemens.OpcUA.Subscription m_Subscription; public static BlockingCollection buffer = new BlockingCollection(); private static Task pollingTask = Task.Run(() => PollMethod()); /// /// 20110309订阅的组内标签数据变化事件 /// /// 客户端句柄 /// 请求句柄 /// 标签值数组 public static void OnDataChange(object clientHandle, DataValue value) { buffer.Add(new WorkItem(clientHandle, value)); } public static void kkkk() { if (buffer.Count > 0) { foreach (WorkItem item in buffer.GetConsumingEnumerable()) { lock (thisLock) { //根据subscriptionHandle对应设备索引,依据设备种类(不同类型设备通讯数据帧不同) //分别处理:完成,报警,光电开关,PLC发起的请求 int deviceindex = 0; try { if (item.Parameter1.ToString().IndexOf("split") >= 0) { deviceindex = System.Convert.ToInt32(item.Parameter1.ToString().Substring(5)); } else { deviceindex = System.Convert.ToInt32(item.Parameter1); } devinfo = Model.CGetInfo.GetDeviceInfo(deviceindex); if (StatusCode.IsNotGood(item.Parameter2.StatusCode)) { if (devinfo == null) { OpcError = string.Format("设备索引{0}在数据库不存在!", item.Parameter1); return; } //触发一个特殊事件提示PLC断开连接 if (ConnectCount.ContainsKey(devinfo.S7Connection) == false)//20110726 { ConnectCount.Add(devinfo.S7Connection, 0); } OpcError = string.Format("{0}所在的PLC已经离线!订阅标签状态:" + item.Parameter2.StatusCode.ToString(), item.Parameter1); if (ConnectCount[devinfo.S7Connection] > 3)//20150204 { _opcError = "订阅返回数据时:OPC Server没连接到PLC:" + devinfo.S7Connection.ToString() + ",人工确认后进行【PLC初始化】";//20150204 return; } ConnectCount[devinfo.S7Connection]++;//20150204 return; } ConnectCount[devinfo.S7Connection] = 0; if (item.Parameter1.ToString().IndexOf("split") >= 0) { Array arr = (Array)item.Parameter2.Value; byte[] GDKG = null; GDKG = new byte[arr.GetLength(0)]; Array.Copy(arr, GDKG, arr.GetLength(0)); #region 解析订阅返回光电开关数据 DealWithDeviceState(out string errText, deviceindex, GDKG, null); #endregion } else { Array arr = (Array)item.Parameter2.Value; byte[] itemnamevalue = new byte[arr.GetLength(0)]; Array.Copy(arr, itemnamevalue, arr.GetLength(0)); int head = 0; head = itemnamevalue[0];//读写标志 #region 解析订阅返回状态数据,并发布主线程可订阅的事件 DealWithDeviceState(out string errText, deviceindex, null, itemnamevalue); #endregion } } catch (Exception ex) {//20120420 OpcError = string.Format("OPC服务器订阅事件异常:{0},{1}", ex.Message, ex.StackTrace); } } } } } static void PollMethod() { while (true) // 无限循环,模拟轮询 { // 这里放置你的轮询逻辑 kkkk(); // 休眠一段时间,例如1秒 Thread.Sleep(1000); } } static bool DealWithDeviceState(out string errtext, int deviceindex, byte[] splitbyteValue, byte[] devicestates) {//deviceindex设备组代表的订阅,首先把设备组按照F_DBW2Address由小到大排序,拆分到具体每个设备 //20230811richard.liu周期内按S7连接批量发送,重构CControl.cs,CCommonOPCClient.cs\DealWithDeviceState;文件夹Communication、Common内通讯CSendDeviceOrder: ISendDeviceOrder相关文件 lock (thisLock) { _opcSubsTagCount.Clear(); _opcItemNamesDicInfo.Clear(); _opcItemValuesDicInfo.Clear(); Dictionary DeviceStateInfos=new Dictionary(); errtext = string.Empty; DataView dvDevice = new DataView();//device表的设备信息 DataView dvPLCASK = new DataView();//PLCASK表数据不能更改 DataView dvbc = new DataView();//临时表可随意用 int devicebegin = 0; int DBW2Addressbegin = 0; string S7Connection = string.Empty;//int SplitBytebegin = 0; int SplitByteLength = 0; try { StringBuilder sql = new StringBuilder(string.Format("SELECT F_DeviceIndex, F_DBW2Address, F_DBWGetLength, F_SplitByte,F_S7Connection FROM T_Base_Device WHERE f_controldevice='1' and (F_DeviceKindIndex !=33) AND (F_ReadSubscription = '{0}') AND (F_DBW2Address IS NOT NULL) ORDER BY F_DBW2Address", deviceindex));//20151120,增加字段是否需要服务端处理设备的订阅 dvDevice = dbo.ExceSQL(sql.ToString()).Tables[0].DefaultView; if (dvDevice.Count > 0) {//订阅组第一个设备,设备编码是订阅组ID devicebegin = Convert.ToInt32(dvDevice[0]["F_DeviceIndex"]); DBW2Addressbegin = Convert.ToInt32(dvDevice[0]["F_DBW2Address"]); //SplitBytebegin = Convert.ToInt32(dvDevice[0]["F_SplitByte"]); S7Connection = dvDevice[0]["F_S7Connection"].ToString(); //sql.Clear(); //sql.Append(string.Format("SELECT F_DeviceIndex, F_DBW2Address, F_DBWGetLength, F_SplitByte,F_S7Connection FROM T_Base_Device WHERE (F_DeviceKindIndex =33) AND (F_ReadSubscription = '{0}') ORDER BY F_DBW2Address", deviceindex)); //dvPLCASK = dbo.ExceSQL(sql.ToString()).Tables[0].DefaultView; //if (dvPLCASK.Count > 0) //{ // SplitByteLength = Convert.ToInt32(dvPLCASK[0]["F_DBWGetLength"]); //} } else {//非订阅组第一个设备 sql = new StringBuilder(string.Format("SELECT F_DeviceIndex, F_DBW2Address, F_DBWGetLength, F_SplitByte,F_S7Connection FROM T_Base_Device WHERE (F_DeviceIndex = '{0}') AND (F_DBW2Address IS NOT NULL) ORDER BY F_DBW2Address", deviceindex)); dvDevice = dbo.ExceSQL(sql.ToString()).Tables[0].DefaultView; if (dvDevice.Count > 0) { devicebegin = Convert.ToInt32(dvDevice[0]["F_DeviceIndex"]); DBW2Addressbegin = Convert.ToInt32(dvDevice[0]["F_DBW2Address"]); //SplitBytebegin = Convert.ToInt32(dvDevice[0]["F_SplitByte"]); S7Connection = dvDevice[0]["F_S7Connection"].ToString(); sql = new StringBuilder(string.Format("SELECT F_DeviceIndex, F_DBW2Address, F_DBWGetLength, F_SplitByte,F_S7Connection FROM T_Base_Device WHERE (F_DeviceKindIndex =33) AND (F_ReadSubscription = '{0}') ORDER BY F_DBW2Address", deviceindex)); dvPLCASK = dbo.ExceSQL(sql.ToString()).Tables[0].DefaultView; if (dvPLCASK.Count > 0) { SplitByteLength = Convert.ToInt32(dvPLCASK[0]["F_DBWGetLength"]); } } else {//20120420 RefreshMonitorEventArgs rmea = new RefreshMonitorEventArgs("tsStatus", string.Format("CCommonOPCClient.DealWithDeviceState时,订阅组:{0}对应的设备索引不存在!", deviceindex)); OnRefreshMonitor(rmea); errtext = string.Format("CCommonOPCClient.DealWithDeviceState时,订阅组:{0}对应的设备索引不存在!", deviceindex); return false; } } #region 设备状态采集分解 int tempdb2addr = 0; StringBuilder sss = new StringBuilder(); StringBuilder barcode = new StringBuilder(); if (devicestates != null) { //遍历订阅内所有设备 for (int di = 0; di < dvDevice.Count; di++) { int devidx = Convert.ToInt32(dvDevice[di]["F_DeviceIndex"]); devinfo = Model.CGetInfo.GetDeviceInfo(devidx); if (DeviceStateInfos.ContainsKey(devidx) == false) { DeviceStateInfos.Add(devidx, new StringBuilder(devidx.ToString() + "#")); } witemnames[0].Clear(); witemnames[0].Append(Model.CGeneralFunction.DBGet).Append(".").Append(Convert.ToString(devinfo.Dbw2Address + 0)).Append(",b");//20141201张磊发现误写为Dbw1Address sdo = CommModeCreate.CreateSendDeviceOrder(devidx); int taskindex = 0; int state = 0; int xc = 0; int yc = 0; int devkind = devinfo.DeviceKind; //以下代码重新开发CStaticClass.MutiS7ConnReturns改为按照F_ReadSubscription tempdb2addr = Convert.ToInt32(dvDevice[di]["F_DBW2Address"]) - DBW2Addressbegin; if (3 < devinfo.Dbw2Getlength&&devkind!=5&& devkind != 13) { //state = devicestates[tempdb2addr + 1]; taskindex = (devicestates[tempdb2addr + 2] << 8) + devicestates[tempdb2addr + 3]; } if (1 < devinfo.Dbw2Getlength&&devkind!=7) { state = devicestates[tempdb2addr + 1]; } if (1 == devinfo.Dbw2Getlength ) { state = devicestates[tempdb2addr]; } if (devkind == 13 && devinfo.UnControl!="1") {//richard.liu20230718鸿安环穿0-1是心跳单独订阅;2是可下任务状态0:不可下命令,1:可下命令 state = devicestates[tempdb2addr + 1] == 0 ? 1 : 0;//可下任务状态 taskindex = (devicestates[tempdb2addr + 2] << 8) + devicestates[tempdb2addr + 3]; } #region 通用物流设备状态 devinfo = Model.CGetInfo.GetDeviceInfo(devidx); if (devinfo.RunState != 4)//20121203 { string errText = string.Empty; if (state >= 30) { #region 20160501故障信息变化,上一故障结束,新故障开始 Model.MError errs; if (devinfo.ErrorCode != state && devinfo.ErrorCode >= 30) { if (taskindex == 0 || taskindex >= 30000) { DeviceStateInfos[devidx].Append(string.Format("{0}#{1}", taskindex, state)); } #region 上一次报警或者故障时间分别统计记录 errs = Model.CGetInfo.GetErrorInfo(Convert.ToInt32(devkind.ToString() + devinfo.ErrorCode.ToString())); if (errs != null) { DataView dverr = dbo.ExceSQL(string.Format("SELECT F_ManageTaskNo,F_DeviceIndex,F_ErrorIndex,F_DateTime FROM T_Base_Device_Error_Log where F_DeviceIndex={0} and F_ErrorIndex={1} order by F_DateTime desc", devidx, errs.ErrorIndex)).Tables[0].DefaultView; if (dverr.Count > 0) {//richard.liu20181212对报警记录更新最近一个的修复时间 sql.Remove(0, sql.Length); sql.Append("UPDATE T_Base_Device_Error_Log SET F_FixDateTime ='").Append(DateTime.Now.ToString("u")).Append("' Where F_DeviceIndex=") .Append(devidx).Append(" and F_ErrorIndex=").Append(errs.ErrorIndex).Append(" and F_ManageTaskNo=").Append(Convert.ToInt32(dverr[0]["F_ManageTaskNo"])); //dbo.ExceSQL(sql.ToString()); StringBuilder[] dboArrary = new StringBuilder[1] { new StringBuilder("DBFactory") }; StringBuilder[] sqlArrary = new StringBuilder[1] { sql }; CUpdateDBChangeEventArgs exeSql = new CUpdateDBChangeEventArgs(dboArrary, sqlArrary); OnDealSQLExe("OPCClient.CCommonOPCClient.OnDataChange", exeSql); } if (errs.IfAlarm == '1') { //CStaticClass.UpdateDeviceOEE(devidx, DateTime.Now.Date, 0, 0, 0, 0 //, 0, ccf.GetAlarmTimeSpan(devidx),errs.ErrorKind, 0, out errText);//统计上次报警 //dbo.ExecuteSql(string.Format("update T_Base_Device set F_AlarmStartTime='-' where F_DeviceIndex ={0}", devidx)); } else { //CStaticClass.UpdateDeviceOEE(devidx, DateTime.Now.Date, 0, 0, 0, 0 //, ccf.GetErrorTimeSpan(devidx), 0,errs.ErrorKind, 0, out errText);//统计上次故障 //dbo.ExecuteSql(string.Format("update T_Base_Device set F_ErrorStartTime='-' where F_DeviceIndex ={0}", devidx)); } } #endregion //新的报警或故障开始计时 errs = Model.CGetInfo.GetErrorInfo(Convert.ToInt32(devkind.ToString() + state.ToString())); if (errs != null) { if (errs.IfAlarm == '1') { //dbo.ExecuteSql(string.Format("update T_Base_Device set F_AlarmStartTime='{1}' where F_DeviceIndex ={0}", devidx, DateTime.Now.ToString("u").Substring(0, 19))); //CStaticClass.UpdateDeviceOEE(devinfo.DeviceIndex, DateTime.Now.Date, 0, 0, 1, // 0, 0, 0, 'O', 0, out errText);//richard.liu20181212报警数量增加1 } else { //dbo.ExecuteSql(string.Format("update T_Base_Device set F_ErrorStartTime='{1}' where F_DeviceIndex ={0}", devidx, DateTime.Now.ToString("u").Substring(0, 19))); //CStaticClass.UpdateDeviceOEE(devinfo.DeviceIndex, DateTime.Now.Date, 0, 1, 0, // 0, 0, 0, 'O', 0, out errText);//richard.liu20181212故障数量增加1 } } } else if (devinfo.ErrorCode != state && devinfo.ErrorCode < 30) { if (taskindex == 0 || taskindex >= 30000) { DeviceStateInfos[devidx].Append(string.Format("{0}#{1}", taskindex, state)); } //求上一次运行时间 //CStaticClass.UpdateDeviceOEE(devidx, DateTime.Now.Date, 0, 0, 0, ccf.GetConveyorRunTimeSpan(devidx) // ,0,0,'O',0, out errText);//统计上次运行时间 //dbo.ExecuteSql(string.Format("update T_Base_Device set F_ConveyorRunStartTime='-' where F_DeviceIndex ={0}", devidx)); //新的报警或故障开始计时 errs = Model.CGetInfo.GetErrorInfo(Convert.ToInt32(devkind.ToString() + state.ToString())); if (errs != null) { if (errs.IfAlarm == '1') { //dbo.ExecuteSql(string.Format("update T_Base_Device set F_AlarmStartTime='{1}' where F_DeviceIndex ={0}", devidx, DateTime.Now.ToString("u").Substring(0, 19))); //CStaticClass.UpdateDeviceOEE(devinfo.DeviceIndex, DateTime.Now.Date, 0, 0, 1, // 0, 0, 0, 'O', 0, out errText);//richard.liu20181212报警数量增加1 } else { //dbo.ExecuteSql(string.Format("update T_Base_Device set F_ErrorStartTime='{1}' where F_DeviceIndex ={0}", devidx, DateTime.Now.ToString("u").Substring(0, 19))); //CStaticClass.UpdateDeviceOEE(devinfo.DeviceIndex, DateTime.Now.Date, 0, 1, 0, // 0, 0, 0, 'O', 0, out errText);//richard.liu20181212故障数量增加1 } } } #endregion devinfo.ErrorCode = state; devinfo.RunState = 2; } else {//0,1,2 #region 20160501上一故障结束,输送机任务变化:任务数增加1 //输送机状态变化:0->1开始运行;1->0运行结束,运行时间增加 if (devinfo.ErrorCode >= 30) { #region 如果上一次报警或者故障结束,清除时间,改为运行时间 Model.MError errs = Model.CGetInfo.GetErrorInfo(Convert.ToInt32(devkind.ToString() + devinfo.ErrorCode.ToString())); if (errs != null) { DataView dverr = dbo.ExceSQL(string.Format("SELECT F_ManageTaskNo,F_DeviceIndex,F_ErrorIndex,F_DateTime FROM T_Base_Device_Error_Log where F_DeviceIndex={0} and F_ErrorIndex={1} order by F_DateTime desc", devidx, errs.ErrorIndex)).Tables[0].DefaultView; if (dverr.Count > 0) {//richard.liu20181212对报警记录更新最近一个的修复时间 sql.Remove(0, sql.Length); sql.Append("UPDATE T_Base_Device_Error_Log SET F_FixDateTime ='").Append(DateTime.Now.ToString("u")).Append("' Where F_DeviceIndex=") .Append(devidx).Append(" and F_ErrorIndex=").Append(errs.ErrorIndex).Append(" and F_ManageTaskNo=").Append(Convert.ToInt32(dverr[0]["F_ManageTaskNo"])); //dbo.ExceSQL(sql.ToString()); StringBuilder[] dboArrary = new StringBuilder[1] { new StringBuilder("DBFactory") }; StringBuilder[] sqlArrary = new StringBuilder[1] { sql }; CUpdateDBChangeEventArgs exeSql = new CUpdateDBChangeEventArgs(dboArrary, sqlArrary); OnDealSQLExe("OPCClient.CCommonOPCClient.OnDataChange", exeSql); } if (errs.IfAlarm == '1') { //CStaticClass.UpdateDeviceOEE(devidx, DateTime.Now.Date, 0, 0, 0, 0 //, 0, ccf.GetAlarmTimeSpan(devidx),errs.ErrorKind, 0, out errText); //dbo.ExecuteSql(string.Format("update T_Base_Device set F_AlarmStartTime='-' where F_DeviceIndex ={0}", devidx)); } else { //CStaticClass.UpdateDeviceOEE(devidx, DateTime.Now.Date, 0, 0, 0, 0 //, ccf.GetErrorTimeSpan(devidx), 0,errs.ErrorKind, 0, out errText); //dbo.ExecuteSql(string.Format("update T_Base_Device set F_ErrorStartTime='-' where F_DeviceIndex ={0}", devidx)); } //开始记录运行时间 if (devkind == 2) { //dbo.ExecuteSql(string.Format("update T_Base_Device set F_ConveyorRunStartTime='{1}' where F_DeviceIndex ={0}", devidx, DateTime.Now.ToString("u").Substring(0, 19))); } } #endregion } else {//状态变化:0->1开始运行;1->0()运行结束,运行时间增加 if (devinfo.ErrorCode == 0 && state == 1 && devkind == 2) { //开始记录运行时间 //dbo.ExecuteSql(string.Format("update T_Base_Device set F_ConveyorRunStartTime='{1}' where F_DeviceIndex ={0}", devidx, DateTime.Now.ToString("u").Substring(0, 19))); } else if (devinfo.ErrorCode == 1 && (state == 0 || state == 2) && devkind == 2) { //CStaticClass.UpdateDeviceOEE(devidx, DateTime.Now.Date, 0, 0, 0, ccf.GetConveyorRunTimeSpan(devidx) //, 0, 0,'O', 0, out errText);//统计上次运行时间 //dbo.ExecuteSql(string.Format("update T_Base_Device set F_ConveyorRunStartTime='-' where F_DeviceIndex ={0}", devidx)); } } //任务变化 if (devinfo.TaskNo != taskindex && devkind == 2 && taskindex > 0) { //CStaticClass.UpdateDeviceOEE(devidx, DateTime.Now.Date,1, 0, 0, 0 // ,0, 0,'O', 0, out errText); } #endregion if (state == 2) { devinfo.RunState = 5; } else { devinfo.RunState = state; } devinfo.ErrorCode = state; } } devinfo.TaskNo = taskindex; if ((devinfo.DeviceKind == 1) || (devinfo.DeviceKind == 4) || (devinfo.DeviceKind == 14)) { devinfo.XCoor = devicestates[tempdb2addr + 7] + (devicestates[tempdb2addr + 6] << 8) + (devicestates[tempdb2addr + 5] << 16) + (devicestates[tempdb2addr + 4] << 32);//X坐标 if (devinfo.DeviceKind == 1) { devinfo.YCoor = devicestates[tempdb2addr + 11] + (devicestates[tempdb2addr + 10] << 8) + (devicestates[tempdb2addr + 9] << 16) + (devicestates[tempdb2addr + 8] << 32);//Y坐标 devinfo.ZCoor = devicestates[tempdb2addr + 12];//Z相对坐标(1或2\3) } } Model.CGetInfo.SetDeviceInfo(devinfo); modifypathdevinfo = Model.CGetInfo.GetModifyPathDeviceInfo(devidx); if (modifypathdevinfo != null) { modifypathdevinfo.RunState = devinfo.RunState; modifypathdevinfo.ErrorCode = devinfo.ErrorCode; modifypathdevinfo.TaskNo = devinfo.TaskNo; Model.CGetInfo.SetModifyPathDeviceInfo(modifypathdevinfo); } #endregion #region 处理设备完成、报警、运行状态;条码信息 string bc = string.Empty; int[] states = new int[(int)devinfo.Dbw2Getlength]; Array.Copy(devicestates, tempdb2addr, states, 0, (int)devinfo.Dbw2Getlength); switch (devkind) { #region 堆垛机 case 1: if (devicestates[tempdb2addr + 0] != 1) continue; #region 更新堆垛机光电开关状态 devinfo.SplitByte_0 = (devicestates[tempdb2addr + 13] & 1) == 1 ? 1 : 0; devinfo.SplitByte_1 = (devicestates[tempdb2addr + 13] & 2) == 2 ? 1 : 0; devinfo.SplitByte_2 = (devicestates[tempdb2addr + 13] & 4) == 4 ? 1 : 0; devinfo.SplitByte_3 = (devicestates[tempdb2addr + 13] & 8) == 8 ? 1 : 0; devinfo.SplitByte_4 = (devicestates[tempdb2addr + 13] & 16) == 16 ? 1 : 0; devinfo.SplitByte_5 = (devicestates[tempdb2addr + 13] & 32) == 32 ? 1 : 0; devinfo.SplitByte_6 = (devicestates[tempdb2addr + 13] & 64) == 64 ? 1 : 0; devinfo.SplitByte_7 = (devicestates[tempdb2addr + 13] & 128) == 128 ? 1 : 0; Model.CGetInfo.SetDeviceInfo(devinfo); #endregion if (IsEquals(devinfo.ReturnMessage, states, 4) == false) { bc = GetBarcodeFromMonitorIndex(taskindex); xc = devicestates[tempdb2addr + 7] + (devicestates[tempdb2addr + 6] << 8) + (devicestates[tempdb2addr + 5] << 16) + (devicestates[tempdb2addr + 4] << 32);//X坐标 yc = devicestates[tempdb2addr + 11] + (devicestates[tempdb2addr + 10] << 8) + (devicestates[tempdb2addr + 9] << 16) + (devicestates[tempdb2addr + 8] << 32);//Y坐标 devinfo.ReturnMessage = states; Model.CGetInfo.SetDeviceMessage(devinfo); sss.Remove(0, sss.Length); sss.Append("**条码:").Append(bc).Append("**读标志" + devicestates[tempdb2addr + 0]).Append("**状态" + state).Append("**任务号" + taskindex) .Append("**列坐标" + xc).Append("**层坐标" + yc); CommonClassLib.CCarryConvert.WriteDarkCasket("OPCClient", "收到堆垛机状态", devidx.ToString(), sss.ToString()); if (devicestates[tempdb2addr + 0] != 1) continue; if ((state <= 0) || (taskindex <= 0)) { continue; } AddBatchReponse(Model.CGeneralFunction.DBSend, taskindex, devidx, state); DeviceStateInfos[devidx].Append(string.Format("{0}#{1}", taskindex, state)); //cgs.GetKindDeviceState(taskindex, devidx, state); } break; #endregion #region 类输送机 case 2: #region 更新输送机光电开关状态 devinfo.SplitByte_0 = (devicestates[tempdb2addr + 4] & 1) == 1 ? 1 : 0; devinfo.SplitByte_1 = (devicestates[tempdb2addr + 4] & 2) == 2 ? 1 : 0; devinfo.SplitByte_2 = (devicestates[tempdb2addr + 4] & 4) == 4 ? 1 : 0; devinfo.SplitByte_3 = (devicestates[tempdb2addr + 4] & 8) == 8 ? 1 : 0; devinfo.SplitByte_4 = (devicestates[tempdb2addr + 4] & 16) == 16 ? 1 : 0; devinfo.SplitByte_5 = (devicestates[tempdb2addr + 4] & 32) == 32 ? 1 : 0; devinfo.SplitByte_6 = (devicestates[tempdb2addr + 4] & 64) == 64 ? 1 : 0; devinfo.SplitByte_7 = (devicestates[tempdb2addr + 4] & 128) == 128 ? 1 : 0; Model.CGetInfo.SetDeviceInfo(devinfo); #endregion if (IsEquals(devinfo.ReturnMessage, states, 4) == false) { bc = GetBarcodeFromMonitorIndex(taskindex); devinfo.ReturnMessage = states; Model.CGetInfo.SetDeviceMessage(devinfo); sss.Remove(0, sss.Length); sss.Append("**条码:").Append(bc).Append("**读标志" + devicestates[tempdb2addr + 0]).Append("**状态" + state).Append("**任务号:" + taskindex); CommonClassLib.CCarryConvert.WriteDarkCasket("OPCClient", "收到输送机机状态", devidx.ToString(), sss.ToString()); //if (devicestates[tempdb2addr + 0] != 1) continue; if (state <= 0 || taskindex <= 0)//20140305 { continue; } if (taskindex > 0) { AddBatchReponse(Model.CGeneralFunction.DBSend, taskindex, devidx, state); DeviceStateInfos[devidx].Append(string.Format("{0}#{1}", taskindex, state)); //cgs.GetKindDeviceState(taskindex, devidx, state); } } break; #endregion #region 穿梭车RGV case 4: if (devicestates[tempdb2addr + 0] != 1) continue; #region 更新穿梭车光电开关状态 devinfo.SplitByte_0 = (devicestates[tempdb2addr + 8] & 1) == 1 ? 1 : 0; devinfo.SplitByte_1 = (devicestates[tempdb2addr + 8] & 2) == 2 ? 1 : 0; devinfo.SplitByte_2 = (devicestates[tempdb2addr + 8] & 4) == 4 ? 1 : 0; devinfo.SplitByte_3 = (devicestates[tempdb2addr + 8] & 8) == 8 ? 1 : 0; devinfo.SplitByte_4 = (devicestates[tempdb2addr + 8] & 16) == 16 ? 1 : 0; devinfo.SplitByte_5 = (devicestates[tempdb2addr + 8] & 32) == 32 ? 1 : 0; devinfo.SplitByte_6 = (devicestates[tempdb2addr + 8] & 64) == 64 ? 1 : 0; devinfo.SplitByte_7 = (devicestates[tempdb2addr + 8] & 128) == 128 ? 1 : 0; #endregion Model.CGetInfo.SetDeviceInfo(devinfo); if (IsEquals(devinfo.ReturnMessage, states, 4) == false) { bc = GetBarcodeFromMonitorIndex(taskindex); xc = devicestates[tempdb2addr + 7] + (devicestates[tempdb2addr + 6] << 8) + (devicestates[tempdb2addr + 5] << 16) + (devicestates[tempdb2addr + 4] << 32);//X坐标 devinfo.ReturnMessage = states; devinfo.XCoor = xc; Model.CGetInfo.SetDeviceMessage(devinfo); sss.Remove(0, sss.Length); sss.Append("**条码:").Append(bc).Append("**读标志" + devicestates[tempdb2addr + 0]).Append("**状态" + state).Append("**任务号" + taskindex) .Append("**列坐标" + xc); CommonClassLib.CCarryConvert.WriteDarkCasket("OPCClient", "收到RGV状态", devidx.ToString(), sss.ToString()); if (devicestates[tempdb2addr + 0] != 1) continue; if ((state <= 0) || (taskindex <= 0)) { continue; } AddBatchReponse(Model.CGeneralFunction.DBSend, taskindex, devidx, state); DeviceStateInfos[devidx].Append(string.Format("{0}#{1}", taskindex, state)); //cgs.GetKindDeviceState(taskindex, devidx, state); } break; #endregion #region 条形码字符串信息 case 7: if (devicestates[tempdb2addr + 0] != 1) continue; int BoxInspection = devicestates[tempdb2addr + 1]; //尺寸检测/数量 //20140109申请任务(任务不存在)或者条码比对(任务已经存在) dvPLCASK = dbo.ExceSQL(string.Format("select F_BarCode,F_Time, F_PalletBarcodeLength,F_PalletBarcodeReservedLength,F_BarcodeReservedLength,F_WareHouse,F_ManageAskkind,F_BarcodeForkAmount,F_BarcodeLength,F_BindingDevice,F_Askkind,F_Remark from T_Base_PLC_Ask WHERE (F_DeviceIndex = {0}) ", devidx)).Tables[0].DefaultView; //20130510F_ManageAskkind if (dvPLCASK.Count > 0) { StringBuilder warehouse = new StringBuilder(dvPLCASK[0]["F_WareHouse"].ToString()); int dcode = Convert.ToInt32(dvPLCASK[0]["F_BindingDevice"]); int apptype = Convert.ToInt32(dvPLCASK[0]["F_ManageAskkind"]);//20130510 int BarcodeForkAmount = Convert.ToInt32(dvPLCASK[0]["F_BarcodeForkAmount"]); //多叉堆垛机存放箱条码的最大组数 byte[] weightbyte = new byte[4] { devicestates[tempdb2addr + 2], devicestates[tempdb2addr + 3], devicestates[tempdb2addr + 4], devicestates[tempdb2addr + 5] }; float weights = CommonClassLib.CCarryConvert.ByteToFloat(weightbyte);//重量信息 int BarcodeLength = Convert.ToInt32(dvPLCASK[0]["F_BarcodeLength"]);//多叉堆垛机取货站台上报条码、周转箱叠箱、托盘码垛 int BarcodeReservedLength = Convert.ToInt32(dvPLCASK[0]["F_BarcodeReservedLength"]);//多叉堆垛机取货站台上报条码、周转箱叠箱、托盘码垛 if (BarcodeReservedLength < BarcodeLength) { BarcodeReservedLength = BarcodeLength; } //int BarcodeTotalLength = BarcodeReservedLength * BoxInspection; int PalletBarcodeLength = Convert.ToInt32(dvPLCASK[0]["F_PalletBarcodeLength"]);//托盘条码 int PalletBarcodeReservedLength = Convert.ToInt32(dvPLCASK[0]["F_PalletBarcodeReservedLength"]); if (PalletBarcodeReservedLength < PalletBarcodeLength) { PalletBarcodeReservedLength = PalletBarcodeLength; } StringBuilder incompleteBarcode = new StringBuilder();// 1111111111111111....... StringBuilder noneBarcode = new StringBuilder();// \0\0\0\0.......... StringBuilder appbarcode = new StringBuilder(); StringBuilder[] appbarArray = new StringBuilder[BarcodeForkAmount]; StringBuilder parameter = new StringBuilder();//存放给管理上报的纸箱条码组 #region 初始化接收条码 //for (int j = 1; j <= BarcodeLength; j++) //{ // incompleteBarcode.Append("1");//PLC扫到残码,但是有货物,转换为字符'1' // noneBarcode.Append("0");//PLC没扫描,没货物,保留的空值0,转换为字符'\0' //} //for (int j = 0; j < BarcodeForkAmount; j++) //{//多叉堆垛机,在取货前上报条码格式:头+数量+条码//20140218 // appbarArray[j] = new StringBuilder(ASCIIEncoding.ASCII.GetString(devicestates, tempdb2addr + 2 + j * BarcodeReservedLength, BarcodeReservedLength).Substring(0, BarcodeLength)); //} barcode.Clear(); if (PalletBarcodeLength > 0) {//普通扫描单箱的条码申请\机器人码垛的托盘条码 incompleteBarcode.Clear();//20150103 noneBarcode.Clear();//20150103 for (int j = 1; j <= PalletBarcodeLength; j++) {//20150103 incompleteBarcode.Append("1");//PLC扫到残码,但是有货物,转换为字符'1' noneBarcode.Append("0");//PLC没扫描,没货物,保留的空值0,转换为字符'\0' } for (int j = 4; j < PalletBarcodeLength + 4; j++) { barcode.Append(Convert.ToChar(devicestates[tempdb2addr + j]).ToString().ToUpper()); } } if (IsEquals(devinfo.ReturnMessage, states, states.Length) == false) { devinfo.ReturnMessage = states; Model.CGetInfo.SetDeviceMessage(devinfo); CommonClassLib.CCarryConvert.WriteDarkCasket("OPCClient", "读PLC条码", devidx.ToString(), "读标志1**条码:" + barcode.ToString().Trim('\0').ToUpper()+"高度:"+ BoxInspection.ToString()+"任务号:"+taskindex); } #endregion //20130831richard DateTime appdt = new DateTime(); if (dvPLCASK[0]["F_Time"] == DBNull.Value) { appdt = DateTime.Now.AddSeconds(-10); } else { DateTime.TryParse(dvPLCASK[0]["F_Time"].ToString(), out appdt); } if (dvPLCASK[0]["F_BarCode"] != DBNull.Value) { if ((appdt.AddSeconds(15) > DateTime.Now) && (dvPLCASK[0]["F_BarCode"].ToString() == barcode.ToString())) { CommonClassLib.CCarryConvert.WriteDarkCasket("OPCClient", "PLC重复上报条码:", devidx.ToString(), ",站台:" + dcode + ",条码:" + barcode.ToString().ToUpper()); break; } } switch (dvPLCASK[0]["F_Askkind"].ToString()) { case "4": //普通条码申请任务 DeviceStateInfos[devidx].Append(string.Format("{0}#{1}#{2}#{3}#{4}", 0, 0, 4, barcode.ToString().Trim('\0'), BoxInspection)); break; case "6": //103合托后申请入库 DeviceStateInfos[devidx].Append(string.Format("{0}#{1}#{2}#{3}#{4}", taskindex, 0, 6, barcode.ToString().Trim('\0'), BoxInspection)); break; case "8": //二合一 DeviceStateInfos[devidx].Append(string.Format("{0}#{1}#{2}#{3}#{4}", taskindex, 0, 8, barcode.ToString().Trim('\0'), BoxInspection)); break; case "5": //比对任务报完成,申请任务 DeviceStateInfos[devidx].Append(string.Format("{0}#{1}#{2}#{3}#{4}", taskindex, 0, 5, barcode.ToString().Trim('\0'), BoxInspection)); break; case "7": //组件扫码成品入库 #region 组件条码申请任务 barcode.Clear(); for (int j = 2; j < PalletBarcodeLength; j++) { if (devicestates[tempdb2addr + j] == 13) { break; } barcode.Append(Convert.ToChar(devicestates[tempdb2addr + j]).ToString().ToUpper()); } DeviceStateInfos[devidx].Append(string.Format("{0}#{1}#{2}#{3}#{4}", 0, 0, 7, barcode.ToString().Trim('\0'), BoxInspection)); #endregion break; case "9": //大叠托机申请离开 DeviceStateInfos[devidx].Append(string.Format("{0}#{1}#{2}#{3}#{4}", 0, 0, 5, barcode.ToString().Trim('\0'), BoxInspection)); break; case "13": //条码报告完成,考虑第一个扫描器没扫到,但是第二个扫描器却扫到 //没扫到或者有码无对应任务的改道异常口 #region 条码报告完成 DeviceStateInfos[devidx].Append(string.Format("{0}#{1}#{2}#{3}#{4}", 0, 0, 13, barcode.ToString(), BoxInspection)); CommonClassLib.CCarryConvert.WriteDarkCasket("OPCClient", "写条码应答", devidx.ToString(), "写标志:2" + "**源条码:" + barcode.ToString().ToUpper()); #endregion break; case "17": #region 叠箱机上报个数和箱条码 if (parameter.ToString().Length > 0) { #region 向管理申请叠箱后入库任务 CommonClassLib.CCarryConvert.WriteDarkCasket("OPCClient", "向管理申请叠箱入库任务", devidx.ToString(), dcode + "条码" + barcode.ToString().ToUpper() + "垛条码:" + parameter.ToString()); DeviceStateInfos[devidx].Append(string.Format("{0}#{1}#{2}#{3}#{4}", 0, 0, 17, barcode.ToString(), BoxInspection)); #endregion } #endregion break; default: //无类型,条码比对或者记录条码 break; } AddBatchReponse(Model.CGeneralFunction.DBGet, 0, devidx, 2); CommonClassLib.CCarryConvert.WriteDarkCasket("OPCClient", "写条码应答", devidx.ToString(), "写标志2" + "**源条码:" + barcode.ToString().ToUpper()); } break; #endregion #region 落地机按钮申请空母托对应设备 case 36: if (devicestates[tempdb2addr + 0] != 1) continue; //0字节代表命令字:1表示PLC上报,2表示PC应答 //1字节:1申请空母托 AddBatchReponse(Model.CGeneralFunction.DBGet, 0, devidx, 2); CommonClassLib.CCarryConvert.WriteDarkCasket("OPCClient", "写落地机按钮申请空母托应答", devidx.ToString(), "写标志2**申请空母托标识:" + devicestates[tempdb2addr + 1].ToString() + ";" + witemnames[0].ToString()); DeviceStateInfos[devidx].Append(string.Format("{0}#{1}#{2}", 0, 0, devicestates[tempdb2addr + 1])); break; #endregion #region 拆叠盘机申请出入库对应设备 case 38: if (devicestates[tempdb2addr + 0] != 1) continue; //0字节代表命令字:1表示PLC上报,2表示PC应答 //1字节:1申请入库;2申请出库 AddBatchReponse(Model.CGeneralFunction.DBGet, 0, devidx, 2); CommonClassLib.CCarryConvert.WriteDarkCasket("OPCClient", "写拆叠盘机申请出入库应答", devidx.ToString(), "写标志2**出入库任务类型:" + devicestates[tempdb2addr + 1].ToString() + ";" + witemnames[0].ToString()); DeviceStateInfos[devidx].Append(string.Format("{0}#{1}#{2}", 0, 0, devicestates[tempdb2addr + 1])); break; #endregion #region 出入库方向电气申请变更 case 39: if (devicestates[tempdb2addr + 0] != 1) continue; break; #endregion #region 鸿安环穿主站 case 13: //if (devicestates[tempdb2addr + 0] != 1) continue; if (devinfo.UnControl == "1") {//主站心跳 #region 心跳反馈和判断,把电气值+1 int xt = (devicestates[tempdb2addr + 0] << 8) + devicestates[tempdb2addr + 1]; //发送心跳 if (xt >= 30000) xt = 0; devinfo.SendInterval = xt; StringBuilder[] itemname; StringBuilder[] itemvalue; itemname = new StringBuilder[1] { new StringBuilder("") }; itemname[0].Append(Model.CGeneralFunction.DBSend).Append(".").Append(devinfo.Dbw1Address).Append(",i"); itemvalue = new StringBuilder[1] { new StringBuilder("") }; itemvalue[0].Append(xt + 1); CCommonOPCClient.Hostname = CommonClassLib.AppSettings.GetValue("HostName"); CCommonOPCClient.ProgID = CommonClassLib.AppSettings.GetValue("OPCProgID"); AsyncWriteAllItemValue(devinfo.S7Connection, itemname, itemvalue); //AddBatchReponse(Model.CGeneralFunction.DBSend, 0, devidx, xt+1); //CommonClassLib.CCarryConvert.WriteDarkCasket("OPCClient", "发送环穿主站心跳", devidx.ToString(), string.Format("收到心跳:{0},发送心跳:{1}",xt,xt+1)); #endregion } else { if (IsEquals(devinfo.ReturnMessage, states, states.Length) == false) {//主站 #region 更新主站故障报警状态 int ies = (devicestates[tempdb2addr + 4] << 8) + devicestates[tempdb2addr + 5]; int isd = (devicestates[tempdb2addr + 6] << 8) + devicestates[tempdb2addr + 7]; int islg = (devicestates[tempdb2addr + 8] << 8) + devicestates[tempdb2addr + 9]; for (int hi = 0; hi <= 15; hi++) { devinfo.EmergencyStop[hi] = (ies & Convert.ToUInt16(Math.Pow(2, hi))) == Math.Pow(2, hi);//BIT0--BIT15代表#1..#16紧急停止状态BIT=0表示正常,BIT=1表示异常 devinfo.SafetyDoor[hi] = (isd & Convert.ToUInt16(Math.Pow(2, hi))) == Math.Pow(2, hi);//BIT0--BIT15代表#1..#16安全门状态BIT=0表示正常,BIT=1表示异常 devinfo.SafetyLightGrid[hi] = (islg & Convert.ToUInt16(Math.Pow(2, hi))) == Math.Pow(2, hi);// BIT0--BIT15代表#1..#16安全光栅状态BIT=0表示正常,BIT=1表示异常 } #endregion bc = GetBarcodeFromMonitorIndex(taskindex); devinfo.ReturnMessage = states; Model.CGetInfo.SetDeviceMessage(devinfo); sss.Remove(0, sss.Length); sss.Append("**条码:").Append(bc).Append("**读标志" + devicestates[tempdb2addr + 0]).Append("**状态" + state).Append("**任务号" + taskindex).Append("接收结果:").Append(devicestates[tempdb2addr + 3]) .Append("**列坐标" + xc); CommonClassLib.CCarryConvert.WriteDarkCasket("OPCClient", "收到环穿主站状态", devidx.ToString(), sss.ToString()); //if (devicestates[tempdb2addr + 0] != 1) continue;//WCS可下命令 if ((devicestates[tempdb2addr + 1] <= 0) || (taskindex <= 0)) {//1:正常接收,解锁主站,接收下一个命令;2:任务异常 continue; } DeviceStateInfos[devidx].Append(string.Format("{0}#{1}", taskindex, devicestates[tempdb2addr + 1])); //不需要回复数据AddBatchReponse("DB1", taskindex, devidx, state); //cgs.GetKindDeviceState(taskindex, devidx, devicestates[tempdb2addr + 3]); } } break; #endregion #region 鸿安环形穿梭车RGV case 14: if (devicestates[tempdb2addr + 0] != 1) continue; #region 更新环形穿梭车光电开关状态 devinfo.SplitByte_0 = (devicestates[tempdb2addr + 8] & 1) == 1 ? 1 : 0; devinfo.SplitByte_1 = (devicestates[tempdb2addr + 8] & 2) == 2 ? 1 : 0; devinfo.SplitByte_2 = (devicestates[tempdb2addr + 8] & 4) == 4 ? 1 : 0; devinfo.SplitByte_3 = (devicestates[tempdb2addr + 8] & 8) == 8 ? 1 : 0; devinfo.SplitByte_4 = (devicestates[tempdb2addr + 8] & 16) == 16 ? 1 : 0; devinfo.SplitByte_5 = (devicestates[tempdb2addr + 8] & 32) == 32 ? 1 : 0; devinfo.SplitByte_6 = (devicestates[tempdb2addr + 8] & 64) == 64 ? 1 : 0; devinfo.SplitByte_7 = (devicestates[tempdb2addr + 8] & 128) == 128 ? 1 : 0; #endregion Model.CGetInfo.SetDeviceInfo(devinfo); if (IsEquals(devinfo.ReturnMessage, states, 4) == false) { bc = GetBarcodeFromMonitorIndex(taskindex); xc = devicestates[tempdb2addr + 7] + (devicestates[tempdb2addr + 6] << 8) + (devicestates[tempdb2addr + 5] << 16) + (devicestates[tempdb2addr + 4] << 32);//X坐标 devinfo.ReturnMessage = states; Model.CGetInfo.SetDeviceMessage(devinfo); sss.Remove(0, sss.Length); sss.Append("**条码:").Append(bc).Append("**读标志" + devicestates[tempdb2addr + 0]).Append("**状态" + state).Append("**任务号" + taskindex) .Append("**列坐标" + xc); CommonClassLib.CCarryConvert.WriteDarkCasket("OPCClient", "收到环穿RGV状态", devidx.ToString(), sss.ToString()); if (devicestates[tempdb2addr + 0] != 1) continue; if ((state <= 0) || (taskindex <= 0)) { continue; } AddBatchReponse(Model.CGeneralFunction.DBSend, taskindex, devidx, state); DeviceStateInfos[devidx].Append(string.Format("{0}#{1}", taskindex, state)); //cgs.GetKindDeviceState(taskindex, devidx, state); } break; #endregion } #endregion } #region 一个订阅组内设备按订阅ID deviceindex一批发送应答20230811richard.liu StringBuilder[] itmenames = null; StringBuilder[] itmevalues = null; StringBuilder[] sbDdeviceStateInfos = new StringBuilder[DeviceStateInfos.Count]; if (_opcSubsTagCount.ContainsKey(deviceindex.ToString()) == true) { itmenames = new StringBuilder[_opcSubsTagCount[deviceindex.ToString()]]; itmevalues = new StringBuilder[_opcSubsTagCount[deviceindex.ToString()]]; int deviceTagCount = 0; if (_opcItemNamesDicInfo.Count > 0) { foreach (int devidx in _opcItemNamesDicInfo[deviceindex.ToString()].Keys) { Array.Copy(_opcItemNamesDicInfo[deviceindex.ToString()][devidx], 0, itmenames, deviceTagCount, _opcItemNamesDicInfo[deviceindex.ToString()][devidx].Length); Array.Copy(_opcItemValuesDicInfo[deviceindex.ToString()][devidx], 0, itmevalues, deviceTagCount, _opcItemValuesDicInfo[deviceindex.ToString()][devidx].Length); deviceTagCount += _opcItemNamesDicInfo[deviceindex.ToString()][devidx].Length; } } } int i = 0; foreach (int devidx in DeviceStateInfos.Keys) { if (DeviceStateInfos[devidx].ToString().Split('#').Length > 2) { sbDdeviceStateInfos[i] = DeviceStateInfos[devidx]; i++; } } if (i > 0 || itmenames != null) { StringBuilder[] sbDdeviceStateInfosNew = new StringBuilder[i]; Array.Copy(sbDdeviceStateInfos, sbDdeviceStateInfosNew, i); CUpdateDBChangeEventArgs udbe = new CUpdateDBChangeEventArgs(deviceindex, sbDdeviceStateInfosNew, itmenames, itmevalues); string ss = ""; for (int kk = 0; kk < sbDdeviceStateInfosNew.Length; kk++) { ss += sbDdeviceStateInfosNew[kk].ToString(); } //CommonClassLib.CCarryConvert.WriteDarkCasket("OPCClient", "调用on", deviceindex.ToString(), ss); OnPublishDeviceState("OPCClient.CCommonOPCClient.OnDataChange", udbe); } #endregion } #endregion return true; } catch (Exception ex) { RefreshMonitorEventArgs rmea = new RefreshMonitorEventArgs("tsStatus", "CCommonOPCClient.DealWithDeviceState时" + ex.Message + ex.StackTrace); OnRefreshMonitor(rmea); errtext = ex.Message + ex.StackTrace; return false; } finally { dvDevice.Dispose(); dvbc.Dispose(); dvPLCASK.Dispose(); } } } #region 自定义方法 static string _stockCodeCheck = "^[B|D|G|P][A-Z][0-9]{4}$"; /// /// 条码格式检查 /// public static string StockCodeCheck { get { return _stockCodeCheck; } set { int aa; if (int.TryParse(_stockCodeCheck, out aa) == true) { _stockCodeCheck = value; } else { _stockCodeCheck = "^[B|D|G|P][A-Z][0-9]{4}$"; } } } private static void AddBatchReponse(string DBBlock, int taskindex, int devidx, int state) { StringBuilder[] itemnames = new StringBuilder[0]; StringBuilder[] itemvalues = new StringBuilder[0]; try { devinfo = Model.CGetInfo.GetDeviceInfo(devidx); int devKind = devinfo.DeviceKind; if (DBBlock == "DB1") {//根据devidx类型和state判断发送应答 if (state == 1) {//运行 if ((devKind == 1)) //堆垛机 { int[] sendmes = new int[10] { 0, 0, 0, devidx, 0, 0, 0, 0, 0, 0 }; devinfo = Model.CGetInfo.GetDeviceInfo(devidx); if (IsEquals(devinfo.SendMessage, sendmes, 10) == false) { sdo = CommModeCreate.CreateSendDeviceOrder(devidx); sdo.SendDeviceOrder(0, 0, 0, devidx, 0, 0, 0, 0, 0, 0, out itemnames, out itemvalues); } } else if (devKind == 4 || devKind == 2) {//输送机、RGV运行清零 int[] sendmes = new int[5] { 0, 0, 0, devidx, 0 }; devinfo = Model.CGetInfo.GetDeviceInfo(devidx); if (devinfo.IfClearDB1 == "1" && IsEquals(devinfo.SendMessage, sendmes, 5) == false) { sdo = CommModeCreate.CreateSendDeviceOrder(devidx); sdo.SendDeviceOrder(0, 0, 0, devidx, 0, out itemnames, out itemvalues); } } } else if (state == 2) {//完成 if ((devKind == 1)) //堆垛机 { sdo = CommModeCreate.CreateSendDeviceOrder(devidx); sdo.SendDeviceOrder(2, 0, 0, devidx, 0, 0, 0, 0, 0, 0, out itemnames, out itemvalues); } else if (devKind == 14) {//环穿小车应答任务号richard.liu20230718 sdo = CommModeCreate.CreateSendDeviceOrder(devidx); sdo.SendDeviceOrder(2, taskindex, 99, devidx, 0, 0, 0, 0, 0, 0, out itemnames, out itemvalues); } else if (devKind == 4 || devKind == 2) {//输送机、RGV int taskRGV = 0; //richard.liu20230718,增加给取货输送机发送环穿取货指令索引 object obt = dbo.GetSingle(string.Format("select F_CHANNELSINDEX from T_BASE_RGV_GATE, t_base_device where F_CHANNELSINDEX=f_deviceindex and f_devicekindindex=13 and F_RGVGATEDEVICEINDEX={0}", devidx)); if (obt != null) { obt = dbo.GetSingle(string.Format("select f_monitorindex from t_monitor_task where f_monitorindex >{0} and f_deviceindex= {1} order by f_monitorindex asc", taskindex, Convert.ToInt32(obt))); if (obt != null) { taskRGV = Convert.ToInt32(obt); } } sdo = CommModeCreate.CreateSendDeviceOrder(devidx); sdo.SendDeviceOrder(2, taskRGV, 0, devidx, 0, out itemnames, out itemvalues); } else { //按state值发送应答 itemnames = new StringBuilder[1] { new StringBuilder() }; itemvalues = new StringBuilder[1] { new StringBuilder() }; itemnames[0].Append(DBBlock).Append(".").Append(Convert.ToString(devinfo.Dbw2Address + 0)).Append(",b"); itemvalues[0].Append(state); } } else { if (devKind == 1) //堆垛机 {//报警,堆垛机清零去掉残留任务 int[] sendmes = new int[10] { 0, 0, 0, devidx, 0, 0, 0, 0, 0, 0 }; if (IsEquals(devinfo.SendMessage, sendmes, 10) == false) { sdo = CommModeCreate.CreateSendDeviceOrder(devidx); sdo.SendDeviceOrder(0, 0, 0, devidx, 0, 0, 0, 0, 0, 0, out itemnames, out itemvalues); } } else if (devKind == 13) {//发送心跳,头99 sdo = CommModeCreate.CreateSendDeviceOrder(devidx); sdo.SendDeviceOrder(99, 0, state, devidx, 0, 0, 0, 0, 0, 0, out itemnames, out itemvalues); } } } else if (DBBlock == "DB2") {//按state值发送应答 itemnames = new StringBuilder[1] { new StringBuilder()}; itemvalues = new StringBuilder[1] { new StringBuilder() }; itemnames[0].Append(DBBlock).Append(".").Append(Convert.ToString(devinfo.Dbw2Address + 0)).Append(",b"); itemvalues[0].Append(state); } else { return; } //20230811richard.liu暂存标签数据 if (itemnames.Length > 0) { AddOPCSendData(devidx, itemnames, itemvalues); } } catch (Exception ex) { throw ex; } finally { } } /// /// 暂存标签数据 /// /// 设备编号 /// 地址区标签名称数组 /// 标签值数组 private static void AddOPCSendData(int deviceIndex, StringBuilder[] itemnames, StringBuilder[] itemvalues) {//20230811richard.liu周期内按S7连接批量发送,重构CControl.cs,CCommonOPCClient.cs\DealWithDeviceState;文件夹Communication、Common内通讯CSendDeviceOrder: ISendDeviceOrder相关文件 try { devinfo = Model.CGetInfo.GetDeviceInfo(deviceIndex); if (_opcItemNamesDicInfo.ContainsKey(devinfo.ReadSubscription)) {//添加OPC订阅组+dic 设备编码+数组 发送数据 if (_opcItemNamesDicInfo[devinfo.ReadSubscription].ContainsKey(devinfo.DeviceIndex) == false) { _opcSubsTagCount[devinfo.ReadSubscription] += itemnames.Length; _opcItemNamesDicInfo[devinfo.ReadSubscription].Add(devinfo.DeviceIndex, itemnames); _opcItemValuesDicInfo[devinfo.ReadSubscription].Add(devinfo.DeviceIndex, itemvalues); } } else { Dictionary OPCDeviceSendtagNamedic = new Dictionary(); Dictionary OPCDeviceSendtagValuedic = new Dictionary(); OPCDeviceSendtagNamedic.Add(devinfo.DeviceIndex, itemnames); OPCDeviceSendtagValuedic.Add(devinfo.DeviceIndex, itemvalues); _opcSubsTagCount.Add(devinfo.ReadSubscription, itemnames.Length); _opcItemNamesDicInfo.Add(devinfo.ReadSubscription, OPCDeviceSendtagNamedic); _opcItemValuesDicInfo.Add(devinfo.ReadSubscription, OPCDeviceSendtagValuedic); } } catch (Exception ex) { throw ex; } finally { } } /// /// 比较两个值型一维数组变量是否值相等 /// /// 值型一维数组1 /// 值型一维数组2 /// 比较结果,相等则true,否则false static public bool IsEquals(Array array1, Array array2, int arraylength) {//20090902新增加arraylength //比较类型是否一样 if ((array1 == null) || (array2 == null)) return false; if (!Object.ReferenceEquals(array1.GetType(), array2.GetType())) { return false; } //比较长度是否一样 if (array1.GetLength(0) != array2.GetLength(0)) { return false; } //比较成员是否对应相等 ValueType v1, v2; for (int i = 0; i < arraylength; i++) { v1 = (ValueType)array1.GetValue(i); v2 = (ValueType)array2.GetValue(i); if (!v1.Equals(v2)) { return false; } } return true; } static string GetBarcodeFromMonitorIndex(int taskindex) { DataView dvb = new DataView(); StringBuilder sss = new StringBuilder(""); try { sss.Append("SELECT F_TxtParam FROM T_Monitor_Task WHERE (F_MonitorIndex = ").Append(taskindex).Append(")"); dvb = dbo.ExceSQL(sss.ToString()).Tables[0].DefaultView; if (dvb.Count > 0) { return dvb[0]["F_TxtParam"].ToString(); } else { return "-"; } } catch (Exception ex) { throw ex; } finally { dvb.Dispose(); } } #endregion static private string _PLCconnectionID = "S7 connection_1";//OPC.UA的新写法"ns=2,S7 connection_1.db2.0,b,5"表示:"S7:[S7 connection_1]的db2.DBB0开始5个字节" /// /// 建立PLC连接的ID,例如:"S7:[S7 connection_1]" /// 或者"S7:[@LOCALSERVER]" /// public static string PlcConnectionID { get { return CCommonOPCClient._PLCconnectionID; } set { CCommonOPCClient._PLCconnectionID = value; } } static private string _opcError; static private bool _IfConnectOPCServer=false ; static private string _hostname; /// /// OPC Server的机器名称或者IP地址 /// public static string Hostname { get { return CCommonOPCClient._hostname; } set { CCommonOPCClient._hostname = value; } } static private string _progID; /// /// OPC Server的程序标识,例如:OPC.SimaticNET /// public static string ProgID { get { return CCommonOPCClient._progID; } set { CCommonOPCClient._progID = value; } } public static string OpcError { get { return CCommonOPCClient._opcError; } set { CCommonOPCClient._opcError = value; RefreshMonitorEventArgs rme = new RefreshMonitorEventArgs("tsStatus", _opcError); OnRefreshMonitor(rme); } } /// /// 《设备索引,对应设备订阅》 /// public static SubscriptionCollection SubscriptionGroup = new SubscriptionCollection();//定义组对象集合(订阅者集合)//20110309 /// /// 20110309每个设备创建一个订阅和DataChange事件 /// public static void CreateSubscriptionGroup() { if (_IfConnectOPCServer == false) { _hostname = CommonClassLib.AppSettings.GetValue("HostName"); _progID = CommonClassLib.AppSettings.GetValue("OPCProgID"); if (ConnectOPCServer(_hostname, _progID) == false) return ; } //DataView dv = dbo.ExceSQL("SELECT F_ReadSubscription, F_DeviceIndex, F_DBW2Address, F_DBWGetLength, F_S7Connection, F_SplitByte FROM T_Base_Device WHERE (F_ReadSubscription IS NOT NULL) AND (F_ReadSubscription =F_DeviceIndex) and ((f_localport!=3 and f_localport!=4 and f_localport!=7 and f_localport!=10) or f_devicekindindex=2) ORDER BY F_ReadSubscription").Tables[0].DefaultView; DataView dv = dbo.ExceSQL("SELECT F_ReadSubscription, F_DeviceIndex, F_DBW2Address, F_DBWGetLength, F_S7Connection, F_SplitByte FROM T_Base_Device WHERE (F_ReadSubscription IS NOT NULL) AND (F_ReadSubscription =F_DeviceIndex) ORDER BY F_ReadSubscription").Tables[0].DefaultView; if (dv.Count > 0) { if (dv.Count < SubscriptionGroup.Count) return; } DataView dvx; for (int i = 0; i < dv.Count; i++) { string dt = DateTime.Now.Minute.ToString() + "-" + DateTime.Now.Second.ToString() + "-" + DateTime.Now.Millisecond.ToString(); dvx = dbo.ExceSQL(string.Format("SELECT (MAX(F_DBW2Address) + F_DBWGetLength) as maxdbw2 FROM T_Base_Device WHERE (F_ReadSubscription = {0}) AND (F_DeviceKindIndex != 33) GROUP BY F_DBWGetLength ORDER BY maxdbw2 DESC", dv[i]["F_ReadSubscription"])).Tables[0].DefaultView; if (dvx.Count > 0) { NodeId nodeId; if (dv[i]["F_S7Connection"].ToString() == "@localserver"|| (Convert.ToInt32(dv[i]["F_DeviceIndex"])>=34091&& Convert.ToInt32(dv[i]["F_DeviceIndex"]) <= 34100)) { nodeId = new NodeId(dv[i]["F_S7Connection"].ToString() + "." + "DB1" + "." + dv[i]["F_DBW2Address"].ToString() + ",b," + (System.Convert.ToInt32(System.Convert.ToInt32(dvx[0]["maxdbw2"]) - System.Convert.ToInt32(dv[i]["F_DBW2Address"]))).ToString(), S7NameSpace); } else { nodeId = new NodeId(dv[i]["F_S7Connection"].ToString() + "." + Model.CGeneralFunction.DBGet + "." + dv[i]["F_DBW2Address"].ToString() + ",b," + (System.Convert.ToInt32(System.Convert.ToInt32(dvx[0]["maxdbw2"]) - System.Convert.ToInt32(dv[i]["F_DBW2Address"]))).ToString(), S7NameSpace);//20151120 } // Add the attribute name/value to the list view. object serverHandle = null; try { // Add the item and apply any changes to it. m_Subscription.AddDataMonitoredItem(nodeId, dv[i]["F_ReadSubscription"].ToString(), OnDataChange, 700, out serverHandle); } catch (ServiceResultException monitoredItemResult) { OpcError = "建立OPC订阅组时:" + monitoredItemResult.Message; if (ConnectCount.ContainsKey(dv[i]["F_S7Connection"].ToString()) == false)//20110726 { ConnectCount.Add(dv[i]["F_S7Connection"].ToString(), 1); } else { ConnectCount[dv[i]["F_S7Connection"].ToString()]++; } } } } dv = dbo.ExceSQL("SELECT F_ReadSubscription, F_DeviceIndex, F_DBW2Address, F_DBWGetLength, F_S7Connection, F_SplitByte FROM T_Base_Device WHERE (F_ReadSubscription IS NOT NULL) AND (F_DeviceKindIndex=33) ORDER BY F_ReadSubscription").Tables[0].DefaultView; for (int i = 0; i < dv.Count; i++) { NodeId nodeId = new NodeId(dv[i]["F_S7Connection"].ToString() + "." + Model.CGeneralFunction.DBGet + "." + dv[i]["F_DBW2Address"].ToString() + ",b," + System.Convert.ToInt32(dv[i]["F_DBWGetLength"]).ToString(), S7NameSpace);//20151120 // Add the attribute name/value to the list view. object serverHandle = null; try { // Add the item and apply any changes to it. m_Subscription.AddDataMonitoredItem(nodeId, "split" + dv[i]["F_ReadSubscription"].ToString(), OnDataChange, 100, out serverHandle); } catch (ServiceResultException monitoredItemResult) { OpcError = "建立OPC订阅组时:" + monitoredItemResult.Message; if (ConnectCount.ContainsKey(dv[i]["F_S7Connection"].ToString()) == false)//20110726 { ConnectCount.Add(dv[i]["F_S7Connection"].ToString(), 1); } else { ConnectCount[dv[i]["F_S7Connection"].ToString()]++; } } } } /// /// 通过设置订阅的监控模式,刷新订阅 /// /// public static bool RefreshMonitoringMode() {//20150103增加断网恢复 if (m_Subscription != null) { m_Subscription.RefreshMonitoringMode(); } return true; } /// /// 连接指定主机的OPC服务器 /// /// 主机名称 /// OPC服务器程序标识例如:"OPC.SimaticNET" /// public static bool ConnectOPCServer(string hostname, string ProgID) { try { if (ConnectCount.ContainsKey(_PLCconnectionID) == false)//20110726 { ConnectCount.Add(_PLCconnectionID, 0); } if (ConnectCount[_PLCconnectionID] > 1)//20150204 { _opcError = "WCS没连接到OPC Server:" + _PLCconnectionID.ToString() + ",人工确认后进行【PLC初始化】";//20150204 return false ; } //Uri discoveryUrl = new Uri("opc.tcp://" + hostname + ":4845"); Uri discoveryUrl = new Uri("opc.tcp://" + hostname + ":55101"); Discovery discovery = new Discovery(); EndpointDescriptionCollection endpoints = null; string rr = discovery.GetEndpoints(discoveryUrl, ref endpoints); if(endpoints == null) { if (ConnectCount.ContainsKey(_PLCconnectionID) == false)//20110726 { ConnectCount.Add(_PLCconnectionID, 0); } ConnectCount[_PLCconnectionID]++; OpcError = "连接OPC数据存取服务器时:GetEndpoints没找到OPC服务器!"; _IfConnectOPCServer = false; return false; } for (int i = 0; i < endpoints.Count; i++) { endpoints[i].EndpointUrl = discoveryUrl.ToString(); if ((endpoints[i].Server.ApplicationName.Text.IndexOf( ProgID)>-1) && (endpoints[i].SecurityMode == MessageSecurityMode.None))//20151120 { m_Server = new Server(); m_Server.CertificateEvent += new certificateValidation(m_Server_CertificateEvent); m_Server.Connect(endpoints[i]); _IfConnectOPCServer = true; if (m_Subscription == null) { m_Subscription = m_Server.AddSubscription(100); } #region 自动读取“S7:”的命名空间索引//20151120 DataValueCollection m_currentValues; NodeId nodeId=new NodeId(2255); NodeIdCollection nodesToRead = new NodeIdCollection(1); nodesToRead.Add(nodeId); m_Server.ReadValues(nodesToRead, out m_currentValues); if (m_currentValues.Count > 0) { string[] arr; arr =(string[]) m_currentValues[0].Value; S7NameSpace =(ushort) Array.IndexOf(arr, "S7:"); } #endregion return true; } } if (ConnectCount.ContainsKey(_PLCconnectionID) == false)//20110726 { ConnectCount.Add(_PLCconnectionID, 0); } ConnectCount[_PLCconnectionID]++; OpcError = "连接OPC数据存取服务器时:配置项OPCProgID和HostName不准确!"; _IfConnectOPCServer = false; return false; } catch (Exception ex) { if (ConnectCount.ContainsKey(_PLCconnectionID) == false)//20110726 { ConnectCount.Add(_PLCconnectionID, 0); } ConnectCount[_PLCconnectionID]++; OpcError = "连接OPC数据存取服务器时:" + ex.Message; _IfConnectOPCServer = false; return false; } } public static DataValueCollection SyncReadAllItemValue(StringBuilder[] itemnames) { DataValueCollection m_currentValues; if (_IfConnectOPCServer == false) { if (ConnectOPCServer(_hostname, _progID) == false) return null; } NodeIdCollection nodesToRead = new NodeIdCollection(itemnames.GetLength(0)); foreach (StringBuilder item in itemnames) { // NodeIds. String sNodeId = _PLCconnectionID + "." + item.ToString(); NodeId nodeId = new NodeId(sNodeId,S7NameSpace);//20151120 nodesToRead.Add(nodeId); } // Call to ClientAPI. m_Server.ReadValues( nodesToRead, out m_currentValues); return m_currentValues; } public static bool SyncWriteAllItemValue(StringBuilder[] itemnames, StringBuilder[] itemvalues) { try { if (ConnectCount.ContainsKey(_PLCconnectionID) == false)//20110726 { ConnectCount.Add(_PLCconnectionID, 0); } if (ConnectCount[_PLCconnectionID] > 1)//20150204 { return false; } if (_IfConnectOPCServer == false) { if (ConnectOPCServer(_hostname, _progID) == false) return false; } NodeIdCollection nodesToWrite = new NodeIdCollection(itemnames.GetLength(0)); DataValueCollection values = new DataValueCollection(itemnames.GetLength(0)); StatusCodeCollection results = null; int i = 0; foreach (StringBuilder item in itemnames) { // Values to write. String sValue = itemvalues[i].ToString(); // Leave current value if write value is empty. if (sValue.Length == 0) { i++; continue; } #region win7等64位操作系统需要指定确切的数据类型//20151120 Type gt = typeof(byte); if (item.ToString().IndexOf(",b") >= 0)//无符号字节型0--255 { gt = typeof(byte); } else if (item.ToString().IndexOf(",i") >= 0)//short:有符号两个字节的单字-32768至32767 { gt = typeof(short); } else if (item.ToString().IndexOf(",w") >= 0)//ushort:无符号两个字节的单字0至65535 { gt = typeof(ushort); } else if (item.ToString().IndexOf(",di") >= 0)//int:有符号四个字节的双字-2147483648至2147483647 { gt = typeof(int); } else if (item.ToString().IndexOf(",dw") >= 0)//uint:无符号四个字节的双字0至4294967295 { gt = typeof(uint); } else if (item.ToString().IndexOf(",dt") >= 0)//DateTime:日期和时间类型:05/31/2016 08:21:10.123 PM { gt = typeof(DateTime); } Variant variant = new Variant(Convert.ChangeType(sValue, gt)); #endregion DataValue value = new DataValue(variant); values.Add(value); // NodeIds. String sNodeId =_PLCconnectionID+"."+ item.ToString(); NodeId nodeId = new NodeId(sNodeId, S7NameSpace); //20151120 nodesToWrite.Add(nodeId); i++; } // Call to ClientAPI. m_Server.WriteValues( nodesToWrite, values, out results); int ia = 0;//richard.liu20141110 foreach (StatusCode sc in results) {//richard.liu20141110 if (sc.Code != StatusCodes.Good) { ConnectCount[_PLCconnectionID]++;//20150204 OpcError =string.Format( "向OPC数据存取服务器写数据时,WriteValues:{0},{1}" ,nodesToWrite[ia].ToString() , "的返回值有错误!"+sc.ToString()); return false; } ia++; } ConnectCount[_PLCconnectionID] = 0;//20150204 return true; } catch (Exception ex) { ConnectCount[_PLCconnectionID]++;//20150204 OpcError =string.Format( "向OPC数据存取服务器写数据时:{0},{1}" , ex.Message,ex.StackTrace); _IfConnectOPCServer = false; return false; } } //以异步的方式写入OPC数据 public static bool AsyncWriteAllItemValue(string _PLCconnectionID,StringBuilder[] itemnames, StringBuilder[] itemvalues) { lock (thisLock)////20130306richard.liu { try { if (_IfConnectOPCServer == false) { if (ConnectOPCServer(_hostname, _progID) == false) return false; } if (ConnectCount.ContainsKey(_PLCconnectionID) == false)//20110726 { ConnectCount.Add(_PLCconnectionID, 0); } if (ConnectCount[_PLCconnectionID] > 3)//20150204 { _opcError = "写数据时:OPC Server没连接到PLC:" + _PLCconnectionID.ToString() + ",人工确认后进行【PLC初始化】";//20150204 return false; } NodeIdCollection nodesToWrite = new NodeIdCollection(itemnames.GetLength(0)); DataValueCollection values = new DataValueCollection(itemnames.GetLength(0)); StatusCodeCollection results = null; int i = 0; foreach (StringBuilder item in itemnames) { // Values to write. String sValue = itemvalues[i].ToString(); // Leave current value if write value is empty. if (sValue.Length == 0) { i++; continue; } #region win7等64位操作系统需要指定确切的数据类型//20151120 Type gt = typeof(byte); if (item.ToString().IndexOf(",b") >= 0)//无符号字节型0--255 { gt = typeof(byte); } else if (item.ToString().IndexOf(",i") >= 0)//short:有符号两个字节的单字-32768至32767 { gt = typeof(short); } else if (item.ToString().IndexOf(",w") >= 0)//ushort:无符号两个字节的单字0至65535 { gt = typeof(ushort); } else if (item.ToString().IndexOf(",di") >= 0)//int:有符号四个字节的双字-2147483648至2147483647 { gt = typeof(int); } else if (item.ToString().IndexOf(",dw") >= 0)//uint:无符号四个字节的双字0至4294967295 { gt = typeof(uint); } else if (item.ToString().IndexOf(",dt") >= 0)//DateTime:日期和时间类型:05/31/2016 08:21:10.123 PM { gt = typeof(DateTime); } Variant variant = new Variant(Convert.ChangeType(sValue, gt)); #endregion DataValue value = new DataValue(variant); values.Add(value); // NodeIds. String sNodeId = _PLCconnectionID + "." + item.ToString(); NodeId nodeId = new NodeId(sNodeId, S7NameSpace); //20151120 nodesToWrite.Add(nodeId); i++; } // Call to ClientAPI. m_Server.BeginWriteValues( nodesToWrite, values, out results); //results返回值一直为null,异常在ClientAPI writeCallBack处理后赋给OpcError ConnectCount[_PLCconnectionID] = 0;//20150204 return true; } catch (Exception ex) { ConnectCount[_PLCconnectionID]++;//20150204 OpcError =string.Format( "向OPC数据存取服务器写数据时:{0},{1}", ex.Message,ex.StackTrace); _IfConnectOPCServer = false; return false; } } } /// /// 获得设备类型索引 /// /// 设备索引 /// 设备类型索引 static int GetDeviceKindIdx(int devIdx) { System.Object lockThis = new System.Object(); lock (lockThis) { try { DataView dv= dbo.ExceSQL(string.Format("SELECT F_DeviceKindIndex FROM T_Base_Device WHERE F_DeviceIndex={0}", devIdx)).Tables[0].DefaultView; if (dv.Count > 0) { return System.Convert.ToInt32(dv[0]["F_DeviceKindIndex"]); } else return 0; } catch (Exception ex) { throw ex; } } } public static void DisConnectOPCServer() { try { int result; if (m_Server == null) return; result = m_Server.Disconnect(); // Disconnect succeeded. if (result == 0) { m_Subscription.RemoveAllMonitoredItems();//20150103增加断网恢复 m_Server.RemoveSubscription(m_Subscription); m_Subscription = null; } _IfConnectOPCServer = false;//20140514张博在山东电力发现此问题 } catch (Exception ex) { OpcError = "关闭OPC数据存取服务器时:" + ex.Message; } } static void m_Server_CertificateEvent(CertificateValidator validator, CertificateValidationEventArgs e) { e.Accept = true; } } }