using System;
using System.Collections.Generic;
using System.Text;
using Opc;
using Opc.Da;
using OpcCom;
using System.Threading;
using System.Data;
using DBFactory;
namespace OPCClient
{
    public static class CCommonOPCClient
    {
        public static DBOperator dbo = new DBOperator();
        //20110216
        private static int _connectCount = 0;
        public static int ConnectCount
        {
            get { return CCommonOPCClient._connectCount; }
            set {
                if (value == 0)
                {
                    _opcError = "";
                }
                CCommonOPCClient._connectCount = value; 
            }
        }
        // 20120427南昌，S7连接标志 1- B
        static StringBuilder sbc = new StringBuilder();
        public static int[] ErrorCount = new int[2] {0,0 };

        private static int[] _plcStates=null ;

        public static int[] PlcStates
        {
            get { return CCommonOPCClient._plcStates; }
            //set { CCommonOPCClient._plcStates = value; }
        }
        
        /// <summary>
        /// 20110309订阅的组内标签数据变化事件
        /// </summary>
        /// <param name="subscriptionHandle">客户端句柄</param>
        /// <param name="requestHandle">请求句柄</param>
        /// <param name="values">标签值数组</param>
        public static void OnDataChange(object subscriptionHandle, object requestHandle, ItemValueResult[] values)
        {
            //根据subscriptionHandle对应设备索引，依据设备种类（不同类型设备通讯数据帧不同）
            //分别处理：完成，报警，光电开关，PLC发起的请求
            try
            {
                //devinfo = Model.CGetInfo.GetDeviceInfo(System.Convert.ToInt32(subscriptionHandle));
                //foreach (ItemValueResult item in values)
                //{//处理每一个ItemValueResult
                //    if (item.ClientHandle == null)
                //    {//服务器发过来的无用信息。
                //        continue;
                //    }
                //    //按设备类型拆分通讯协议
                //    switch(devinfo.DeviceKind)
                //    {
                //        #region 堆垛机
                //        case 1:

                //            break;
                //        #endregion

                //        #region 类输送机
                //        case 2:

                //            break;
                //        #endregion

                //        #region 穿梭车RGV
                //        case 4:

                //            break;
                //        #endregion

                //        #region 条形码字符串信息
                //        case 7:
                            
                //            break;
                //        #endregion

                //        #region 现场触摸屏
                //        case 22:

                //            break;
                //        #endregion

                //        #region 一号工程码字符串信息
                //        case 21:
                            
                //            break;
                //        #endregion

                //        #region 机器人码垛信息
                //        case 24:

                //            break;
                //        #endregion

                //    }
                //}
            }
            catch (Exception ex)
            {
                _opcError = "获取OPC服务器时：" + ex.Message;
                
            }
        }

        

        //WriteComplete回调
        public static void OnWriteComplete(object requestHandle, Opc.IdentifiedResult[] values)
        {
            /*Console.WriteLine("发生异步写name:{0},value:{1}", values[0].ItemName, values[0].GetType());
            if ((int)requestHandle == 2)
                Console.WriteLine("事件信号句柄为{0}", requestHandle);*/
        }

        static private string _PLCconnectionID = "S7:[S7 connection_1]";
        /// <summary>
        /// 建立PLC连接的ID，例如："S7:[S7 connection_1]"
        /// 或者"S7:[@LOCALSERVER]"
        /// </summary>
        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;
        /// <summary>
        /// OPC Server的机器名称或者IP地址
        /// </summary>
        public static string Hostname
        {
            get { return CCommonOPCClient._hostname; }
            set { CCommonOPCClient._hostname = value; }
        }
        static private string _progID;
        /// <summary>
        /// OPC Server的程序标识，例如：OPC.SimaticNET
        /// </summary>
        public static string ProgID
        {
            get { return CCommonOPCClient._progID; }
            set { CCommonOPCClient._progID = value; }
        }
        public static string OpcError
        {
            get { return CCommonOPCClient._opcError; }
            set { CCommonOPCClient._opcError = value; }
        }
        static private Opc.Da.Server m_server = null;//定义数据存取服务器
        static private Opc.Server[] servers;
        static private Opc.Da.Subscription subscription = null;//定义组对象（订阅者）
        static private Opc.Da.SubscriptionState state = null;//定义组（订阅者）状态，相当于OPC规范中组的参数
        static private Opc.Da.Subscription _readSubscription = null;//定义组对象（订阅者）
        static private Opc.Da.SubscriptionState _readstate = null;//定义组（订阅者）状态，相当于OPC规范中组的参数
        static private Opc.Da.Subscription _writeSubscription = null;//定义组对象（订阅者）
        static private Opc.Da.SubscriptionState _writestate = null;//定义组（订阅者）状态，相当于OPC规范中组的参数
        static private Opc.Da.Subscription _tempSubscription = null;//定义组对象（订阅者）
        static private Opc.Da.SubscriptionState _tempstate = null;//定义组（订阅者）状态，相当于OPC规范中组的参数
        static private Opc.IDiscovery m_discovery = new OpcCom.ServerEnumerator();//定义枚举基于COM服务器的接口，用来搜索所有的此类服务器。
        /// <summary>
        /// 《设备索引，对应设备订阅》
        /// </summary>
        public static SubscriptionCollection  SubscriptionGroup = new SubscriptionCollection();//定义组对象集合（订阅者集合）//20110309
        //static Model.MDevice devinfo;//20110309
        /// <summary>
        /// 20110309每个设备创建一个订阅和DataChange事件
        /// </summary>
        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_DeviceIndex, F_DBW2Address, F_DBWGetLength, F_S7Connection FROM T_Base_Device where F_DBW2Address >=0 and F_DBWGetLength>0 order by F_DeviceIndex asc").Tables[0].DefaultView;
            
            for (int i = 0; i < dv.Count; i++)
            {
                //设定设备订阅状态
                _tempstate = new Opc.Da.SubscriptionState();//组（订阅者）状态，相当于OPC规范中组的参数
                _tempstate.Name = dv[i]["F_DeviceIndex"].ToString();//组名
                _tempstate.ServerHandle = null;//服务器给该组分配的句柄。
                _tempstate.ClientHandle = dv[i]["F_DeviceIndex"].ToString();//客户端给该组分配的句柄。
                _tempstate.Active = true;//激活该组。
                _tempstate.UpdateRate = 100;//刷新频率为100毫秒。
                _tempstate.Deadband = 0;// 死区值，设为0时，服务器端该组内任何数据变化都通知组。
                _tempstate.Locale = null;//不设置地区值。
                //添加设备订阅
                _tempSubscription = (Opc.Da.Subscription)m_server.CreateSubscription(_tempstate);//创建设备订阅
                //添加标签
                ////定义读item列表
                Item[] items = new Item[1];//定义数据项，即item
                
                for (int ii = 0; ii < items.Length; ii++)//item初始化赋值
                {
                    items[ii] = new Item();//创建一个项Item对象。
                    items[ii].ClientHandle = Guid.NewGuid().ToString();//客户端给该数据项分配的句柄。
                    items[ii].ItemPath = null; //该数据项在服务器中的路径。
                    items[ii].ItemName = dv[i]["F_S7Connection"].ToString() +
                        Model.CGeneralFunction.DBGet + ",byte" + 
                        dv[i]["F_DBW2Address"].ToString() + "," +
                        (System.Convert.ToInt32(dv[i]["F_DBWGetLength"])).ToString(); //该数据项在服务器中的名字。
                }

                //添加读Item
                ItemResult[] irs = _tempSubscription.AddItems(items);
                //添加事件
                _tempSubscription.DataChanged += new Opc.Da.DataChangedEventHandler(OnDataChange);
                SubscriptionGroup.Add(_tempSubscription);
                //_tempSubscription.RemoveItems(_tempSubscription.Items);
            }
        }
        /// <summary>
        /// 获取主机的所有OPC服务器的标识名称数组
        /// </summary>
        /// <param name="hostname">主机名称</param>
        /// <returns></returns>
        public static List<string> GetOpcServers(string hostname)
        {
            try
            {
                servers = m_discovery.GetAvailableServers(Specification.COM_DA_20, hostname, null);
                //daver表示数据存取规范版本，Specification.COMDA_20等于2.0版本。
                //host为计算机名，null表示不需要任何网络安全认证。
                if (servers != null)
                {
                    List<string> ser =new List<string>();;
                    foreach (Opc.Da.Server server in servers)
                    {
                        ser.Add(server.Name);
                    }
                    return ser;
                }
                return null;
            }
            catch (Exception ex)
            {
                _opcError = "获取OPC服务器时：" + ex.Message;
                return null;
            }
        }
        /// <summary>
        /// 连接指定主机的OPC服务器
        /// </summary>
        /// <param name="hostname">主机名称</param>
        /// <param name="ProgID">OPC服务器程序标识例如："OPC.SimaticNET"</param>
        /// <returns></returns>
        public static bool ConnectOPCServer(string hostname, string ProgID)
        {
            try
            {
                
                GetOpcServers(hostname);
                //if (ProgID.Contains(hostname) == false)
                //{
                //    ProgID = hostname + "." + ProgID;
                //}
                foreach (Opc.Da.Server server in servers)
                {
                    //server即为需要连接的OPC数据存取服务器。
                    if (String.Compare(server.Name,  ProgID, true) == 0)//为true忽略大小写
                    {
                        m_server = server;//建立连接。
                        break;
                        
                    }
                }
                //连接服务器
                if (m_server != null)//非空连接服务器
                {
                    m_server.Connect();
                    _IfConnectOPCServer = true;
                    CreateItemGroup();
                    return true;
                }
                else
                {
                    _IfConnectOPCServer = false;
                    return false;
                }
                
            }
            catch (Exception ex)
            {
                _opcError ="连接OPC数据存取服务器时："+ ex.Message;
                _IfConnectOPCServer = false;
                return false;
            }
            
        }
        /// <summary>
        /// 创建OPC组（订阅者），定义组内变量名称
        /// </summary>
        /// <param name="groupname">OPC组（订阅者）名称</param>
        /// <param name="itemnames">指定组内所有变量名称,数组的值举例"S7:[S7 connection_1]DB1,INT1"</param>
        /// <returns></returns>
        public static Opc.Da.Subscription CreateItemGroup(string groupname, string[] itemnames)
        {
            string[] itemName ;
            //定义item列表
            Item[] items;
            ItemResult[] irs;
            try
            {
                if (_IfConnectOPCServer == false)
                {
                    if (ConnectOPCServer(_hostname, _progID) == false) return null;
                }
                //设定组状态
                state = new Opc.Da.SubscriptionState();//组（订阅者）状态，相当于OPC规范中组的参数
                state.Name = groupname;//组名
                state.ServerHandle = null;//服务器给该组分配的句柄。
                state.ClientHandle = Guid.NewGuid().ToString();//客户端给该组分配的句柄。
                state.Active = true;//激活该组。
                state.UpdateRate = 50;//刷新频率为100毫秒。
                state.Deadband = 0;// 死区值，设为0时，服务器端该组内任何数据变化都通知组。
                state.Locale = null;//不设置地区值。


                //添加组
                subscription = (Opc.Da.Subscription)m_server.CreateSubscription(state);//创建组

                //定义Item列表
                //对应类型为:{Byte,Byte,Char,Short,String,Word,Boolean}
                itemName = itemnames;//{ "S7:[S7 connection_1]DB1,INT1", "S7:[@LOCALSERVER]DB1,INT20", "S7:[@LOCALSERVER]DB1,INT30", "S7:[@LOCALSERVER]DB1,INT50" };

                //定义item列表
                items = new Item[itemName.Length];//定义数据项，即item
                int i;
                for (i = 0; i < items.Length; i++)//item初始化赋值
                {
                    items[i] = new Item();//创建一个项Item对象。
                    items[i].ClientHandle = Guid.NewGuid().ToString();//客户端给该数据项分配的句柄。
                    items[i].ItemPath = null; //该数据项在服务器中的路径。
                    items[i].ItemName = itemName[i]; //该数据项在服务器中的名字。
                }

                //添加Item
                irs = subscription.AddItems(items);
                return subscription;
            }
            catch (Exception ex)
            {
                //if ((m_server == null) || (m_server.IsConnected == false))
                //{
                _IfConnectOPCServer = false;
                //}
                _opcError = "创建OPC组时：" + ex.Message;
                return null;
            }
            finally
            {
                itemName=null;
                //定义item列表
                items=null;
                irs=null;
            }
        }
        /// <summary>
        /// 创建OPC组（订阅者），不定义组内变量名称
        /// </summary>
        /// <param name="groupname">OPC组（订阅者）名称</param>
        /// <returns></returns>
        public static Opc.Da.Subscription CreateItemGroup(string groupname)
        {
            try
            {
                if (_IfConnectOPCServer == false)
                {
                    if (ConnectOPCServer(_hostname, _progID) == false) return null;
                }
                //设定组状态
                state = new Opc.Da.SubscriptionState();//组（订阅者）状态，相当于OPC规范中组的参数
                state.Name = groupname;//组名
                state.ServerHandle = null;//服务器给该组分配的句柄。
                state.ClientHandle = Guid.NewGuid().ToString();//客户端给该组分配的句柄。
                state.Active = true;//激活该组。
                state.UpdateRate = 50;//刷新频率为100毫秒。
                state.Deadband = 0;// 死区值，设为0时，服务器端该组内任何数据变化都通知组。
                state.Locale = null;//不设置地区值。


                //添加组
                subscription = (Opc.Da.Subscription)m_server.CreateSubscription(state);//创建组

                
                return subscription;
            }
            catch (Exception ex)
            {
                //if ((m_server == null) || (m_server.IsConnected == false))
                //{
                _IfConnectOPCServer = false;
                //}
                _opcError = "创建OPC组时：" + ex.Message;
                return null;
            }
        }
        /// <summary>
        /// 创建几个默认组：read和write、临时读写组tempGroup
        /// </summary>
        /// <returns></returns>
        public static void  CreateItemGroup()
        {
            try
            {
                //if (_IfConnectOPCServer == false)
                //{
                //    if (ConnectOPCServer(_hostname, _progID) == false) return ;
                //}
                #region 建立读全部标签组
                //20110216
                
                //设定读取组状态
                _readstate = new Opc.Da.SubscriptionState();//组（订阅者）状态，相当于OPC规范中组的参数
                _readstate.Name = "readopc";//组名
                _readstate.ServerHandle = null;//服务器给该组分配的句柄。
                _readstate.ClientHandle = Guid.NewGuid().ToString();//客户端给该组分配的句柄。
                _readstate.Active = true;//激活该组。
                _readstate.UpdateRate = 50;//刷新频率为100毫秒。
                _readstate.Deadband = 0;// 死区值，设为0时，服务器端该组内任何数据变化都通知组。
                _readstate.Locale = null;//不设置地区值。
                //添加读组
                _readSubscription = (Opc.Da.Subscription)m_server.CreateSubscription(_readstate);//创建读取组
                //20110216
                //string[] itemName;
                //DataView dv = dbo.ExceSQL("SELECT F_S7Connection,F_DBW2Address,F_DBWGetLength  FROM T_Base_Device WHERE (F_DeviceKindIndex = 28)").Tables[0].DefaultView;
                //if (dv.Count > 0)
                //{
                //    itemName=new string[dv.Count];
                //    for(int i=0;i<dv.Count;i++)
                //    {
                //        itemName[i] = dv[i]["F_S7Connection"] + Model.CGeneralFunction.DBGet + ",byte"
                //            + dv[i]["F_DBW2Address"].ToString() + "," + ((int)dv[i]["F_DBWGetLength"]).ToString();
                //    }
                //    //{ "S7:[S7 connection_1]DB1,INT1", "S7:[@LOCALSERVER]DB1,INT20", "S7:[@LOCALSERVER]DB1,INT30", "S7:[@LOCALSERVER]DB1,INT50" };
                //}
                //else
                //{
                //    return ;
                //}
                ////定义读item列表
                //Item[] items = new Item[itemName.Length];//定义数据项，即item
                //int i;
                //for (i = 0; i < items.Length; i++)//item初始化赋值
                //{
                //    items[i] = new Item();//创建一个项Item对象。
                //    items[i].ClientHandle = Guid.NewGuid().ToString();//客户端给该数据项分配的句柄。
                //    items[i].ItemPath = null; //该数据项在服务器中的路径。
                //    items[i].ItemName =  itemName[i]; //该数据项在服务器中的名字。
                //}

                ////添加读Item
                //ItemResult[] irs = _readSubscription.AddItems(items);
                //_plcStates = new int[System.Convert.ToInt32( devinfo28.Dbw2Getlength)];
                //_readSubscription.DataChanged += new Opc.Da.DataChangedEventHandler(OnDataChange);
                #endregion

                //设定写组状态
                _writestate = new Opc.Da.SubscriptionState();//组（订阅者）状态，相当于OPC规范中组的参数
                _writestate.Name = "writeopc";//组名
                _writestate.ServerHandle = null;//服务器给该组分配的句柄。
                _writestate.ClientHandle = Guid.NewGuid().ToString();//客户端给该组分配的句柄。
                _writestate.Active = true;//激活该组。
                _writestate.UpdateRate = 50;//刷新频率为100毫秒。
                _writestate.Deadband = 0;// 死区值，设为0时，服务器端该组内任何数据变化都通知组。
                _writestate.Locale = null;//不设置地区值。
                //添加写入组
                _writeSubscription = (Opc.Da.Subscription)m_server.CreateSubscription(_writestate);//创建写入组

                //设定临时读组状态
                _tempstate = new Opc.Da.SubscriptionState();//组（订阅者）状态，相当于OPC规范中组的参数
                _tempstate.Name = "opctemp";//组名
                _tempstate.ServerHandle = null;//服务器给该组分配的句柄。
                _tempstate.ClientHandle = Guid.NewGuid().ToString();//客户端给该组分配的句柄。
                _tempstate.Active = true;//激活该组。
                _tempstate.UpdateRate = 50;//刷新频率为100毫秒。
                _tempstate.Deadband = 0;// 死区值，设为0时，服务器端该组内任何数据变化都通知组。
                _tempstate.Locale = null;//不设置地区值。
                //添加写入组
                _tempSubscription = (Opc.Da.Subscription)m_server.CreateSubscription(_tempstate);//创建写入组
                
            }
            catch (Exception ex)
            {
                //if ((m_server == null) || (m_server.IsConnected == false))
                //{
                _IfConnectOPCServer = false;
                //}
                _opcError = "创建OPC组时：" + ex.Message;
                return ;
            }
        }
        /// <summary>
        /// 创建OPC组（订阅者），定义组内变量名称
        /// </summary>
        /// <param name="plcConnectionID">组态软件中定义的每个PLC连接的标识</param>
        /// <param name="groupname">OPC组（订阅者）名称</param>
        /// <param name="itemnames">指定组内所有变量名称,数组的值举例"DB1,INT1"</param>
        /// <returns></returns>
        public static Opc.Da.Subscription CreateItemGroup(string plcConnectionID,string groupname, string[] itemnames)
        {
            string[] itemName;
            //定义item列表
            Item[] items;
            ItemResult[] irs;
            try
            {
                if (_IfConnectOPCServer == false)
                {
                    if (ConnectOPCServer(_hostname, _progID) == false) return null;
                }
                //设定组状态
                state = new Opc.Da.SubscriptionState();//组（订阅者）状态，相当于OPC规范中组的参数
                state.Name = groupname;//组名
                state.ServerHandle = null;//服务器给该组分配的句柄。
                state.ClientHandle = Guid.NewGuid().ToString();//客户端给该组分配的句柄。
                state.Active = true;//激活该组。
                state.UpdateRate = 50;//刷新频率为100毫秒。
                state.Deadband = 0;// 死区值，设为0时，服务器端该组内任何数据变化都通知组。
                state.Locale = null;//不设置地区值。


                //添加组
                subscription = (Opc.Da.Subscription)m_server.CreateSubscription(state);//创建组

                //定义Item列表
                //对应类型为:{Byte,Byte,Char,Short,String,Word,Boolean}
                itemName = itemnames;//{ "S7:[S7 connection_1]DB1,INT1", "S7:[@LOCALSERVER]DB1,INT20", "S7:[@LOCALSERVER]DB1,INT30", "S7:[@LOCALSERVER]DB1,INT50" };

                //定义item列表
                items = new Item[itemName.Length];//定义数据项，即item
                int i;
                for (i = 0; i < items.Length; i++)//item初始化赋值
                {
                    items[i] = new Item();//创建一个项Item对象。
                    items[i].ClientHandle = Guid.NewGuid().ToString();//客户端给该数据项分配的句柄。
                    items[i].ItemPath = null; //该数据项在服务器中的路径。
                    items[i].ItemName = plcConnectionID + itemName[i]; //该数据项在服务器中的名字。
                }

                //添加Item
                irs = subscription.AddItems(items);
                return subscription;
            }
            catch (Exception ex)
            {
                //if ((m_server == null) || (m_server.IsConnected == false))
                //{
                _IfConnectOPCServer = false;
                //}
                _opcError = "创建OPC组时：" + ex.Message;
                return null;
            }
            finally
            {
                itemName=null;
                //定义item列表
                items=null;
                irs=null;
            }
        }
        
        /// <summary>
        /// 同步读取全部OPC组内变量的值，List《变量名+ ":" +变量值》
       /// </summary>
       /// <param name="subscription">OPC组名称</param>
       /// <returns></returns>
        public static List<string> SyncReadAllItems(Opc.Da.Subscription subscription)
        {
            ItemValueResult[] values;
            List<string> itemnamevalue;
            try
            {
                if (_IfConnectOPCServer == false)
                {
                    if (ConnectOPCServer(_hostname, _progID) == false) return null;
                }
                itemnamevalue = new List<string>();
                //注册回调事件
                //subscription.DataChanged += new Opc.Da.DataChangedEventHandler(OnDataChange);

                //以下测试同步读
                //以下读整个组
                values = subscription.Read(subscription.Items);
                foreach (ItemValueResult value in values)
                {
                    itemnamevalue.Add(value.ItemName + ":" + value.Value);
                    
                }
                //subscription.RemoveItems(subscription.Items);
                //subscription.Dispose();
                return itemnamevalue;
            }
            catch (Exception ex)
            {
                //if ((m_server == null) || (m_server.IsConnected == false))
                //{
                _IfConnectOPCServer = false;
                //}
                _opcError = "同步读数据时：" + ex.Message;
                return null;
            }
            finally
            {
                values=null;
                itemnamevalue=null;
            }
        }

        /// <summary>
        /// 读取指定S7Connection所有DB1对应标签数组的数据，返回值：“标签值”组成的数组
        /// </summary>
        /// <param name="S7Connection">OPC连接</param>
        /// <returns></returns>
        public static byte[] SyncReadAllItems(string S7Connection)
        {//20110216
            ItemValueResult[] values;
            byte[] itemnamevalue;
            try
            {
                if (_IfConnectOPCServer == false)
                {
                    if (ConnectOPCServer(_hostname, _progID) == false) return null;
                }
                _readSubscription.RemoveItems(_readSubscription.Items);
                string[] itemName= new string[1];
                DataView dv = dbo.ExceSQL("SELECT F_DBW2Address,F_DBWGetLength  FROM T_Base_Device WHERE (F_DeviceKindIndex = 28 and F_S7Connection='"+S7Connection+"')").Tables[0].DefaultView;
                if (dv.Count > 0)
                {
                    
                    itemName[0] = S7Connection + Model.CGeneralFunction.DBGet + ",byte"+ dv[0]["F_DBW2Address"].ToString() + "," + (System.Convert.ToInt32( dv[0]["F_DBWGetLength"])).ToString();
                    
                }
                else
                {
                    return null ;
                }
                
                //定义读item列表
                Item[] items = new Item[itemName.Length];//定义数据项，即item
                int i;
                for (i = 0; i < items.Length; i++)//item初始化赋值
                {
                    items[i] = new Item();//创建一个项Item对象。
                    items[i].ClientHandle = Guid.NewGuid().ToString();//客户端给该数据项分配的句柄。
                    items[i].ItemPath = null; //该数据项在服务器中的路径。
                    items[i].ItemName = itemName[i]; //该数据项在服务器中的名字。
                }

                //添加读Item
                
                ItemResult[] irs = _readSubscription.AddItems(items);
                //_plcStates = new int[System.Convert.ToInt32(devinfo28.Dbw2Getlength)];
                //_readSubscription.DataChanged += new Opc.Da.DataChangedEventHandler(OnDataChange);
                
                // 每个S7连接有一个单独的计数
                sbc.Remove(0, sbc.Length);
                sbc = sbc.Append(S7Connection.Substring(S7Connection.Length - 2, 1));
                int ConnectID = 0;
                switch (S7Connection.Substring(S7Connection.Length - 2, 1))
                {
                    case "A":
                        ConnectID = 9; // 10号堆垛机
                        break;
                    case "B":
                        ConnectID = 10; // 输送机连接
                        break;
                    default:
                        ConnectID = System.Convert.ToInt32(sbc.ToString()) - 1;
                        break;
                }


                if (ErrorCount[ConnectID] > 1)
                {
                    _opcError = "同步数据时：OPC Server没连接到PLC，并且超过重复连接次数!请先关闭命令开关，检查通讯线路，确认后重新打开命令开关！";
                    return null;
                }
                //if (ConnectCount > 1)
                //{
                //    _opcError = "同步数据时：OPC Server没连接到PLC，并且超过重复连接次数!请先关闭命令开关，检查通讯线路，确认后重新打开命令开关！";
                //    return null;
                //}
                values = _readSubscription.Read(_readSubscription.Items);
                if (values.Length <= 0)
                {
                    _opcError = "同步读数据时：OPC Server没连接到PLC!";
                    return null;
                }
                if (values[0].Quality == Quality.Bad)
                {
                    ErrorCount[ConnectID]++;
                    //ConnectCount++;
                    _opcError = "同步读数据时：OPC Server没连接到PLC!";
                    return null;
                }
                else if (values[0].Quality == Quality.Good)
                {
                    // 读取成功后，计数清零
                    ErrorCount[ConnectID] = 0;
                }
                
                Array arr = (Array)values[0].Value;
                itemnamevalue = new byte[arr.GetLength(0)];
                Array.Copy(arr, itemnamevalue, arr.GetLength(0));
                _readSubscription.RemoveItems(_readSubscription.Items);
                //subscription.Dispose();
                return itemnamevalue;
            }
            catch (Exception ex)
            {
                //if ((m_server == null) || (m_server.IsConnected == false))
                //{
                _IfConnectOPCServer = false;
                //}
                _opcError = "同步读数据时：" + ex.Message;
                return null;
            }
            finally
            {
                itemnamevalue = null;
                values = null;
            }
        }

        /// <summary>
        /// 读取指定标签名称的数据
        /// </summary>
        /// <param name="itemname">标签名称</param>
        /// <returns></returns>
        public static string SyncReadItemValue(string itemname)
        {
            string[] items = new string[1] { itemname };
            Subscription subs = CreateItemGroup(_PLCconnectionID, Guid.NewGuid().ToString(), items);
            string itemnamevalue = "";
            ItemValueResult[] values = subs.Read(subs.Items);
            try
            {
                if (_IfConnectOPCServer == false)
                {
                    if (ConnectOPCServer(_hostname, _progID) == false) return null;
                }

                if (values.Length > 0)
                {
                    if (values[0].Value != null)
                    {
                        itemnamevalue = values[0].Value.ToString();
                    }
                }
                subs.RemoveItems(subs.Items);
                subs.Dispose();
                return itemnamevalue;
            }
            catch (Exception ex)
            {
                //if ((m_server == null) || (m_server.IsConnected == false))
                //{
                _IfConnectOPCServer = false;
                //}
                _opcError = "同步读数据时：" + ex.Message;
                return null;
            }
            finally
            {
                items = null;
                subs = null;
                itemnamevalue = null;
                values = null;
            }
        }

        //20100221
        #region 延吉同步读、写OPC

        /// <summary>
        /// 延吉读取整个_readSubscription组的内容
        /// </summary>
        /// <returns></returns>
        public static byte[] SyncReadAllItems()
        {
            ItemValueResult[] values;
            byte[] itemnamevalue;
            try
            {
                if (_IfConnectOPCServer == false)
                {
                    if (ConnectOPCServer(_hostname, _progID) == false) return null;
                }
                //List<string> itemnamevalue = new List<string>();
                //注册回调事件
                //subscription.DataChanged += new Opc.Da.DataChangedEventHandler(OnDataChange);

                //以下测试同步读
                //以下读整个组
                if (ConnectCount > 1)
                {
                    _opcError = "同步数据时：OPC Server没连接到PLC，并且超过重复连接次数!请先关闭命令开关，检查通讯线路，确认后重新打开命令开关！";
                    return null;
                }
                values = _readSubscription.Read(_readSubscription.Items);
                if (values.Length <= 0)
                {
                    _opcError = "同步读数据时：OPC Server没连接到PLC!";
                    return null;
                }
                if (values[0].Quality == Quality.Bad)
                {
                    ConnectCount++;
                    _opcError = "同步读数据时：OPC Server没连接到PLC!";
                    return null;
                }
                Array arr = (Array)values[0].Value;
                itemnamevalue = new byte[arr.GetLength(0)];
                Array.Copy(arr, itemnamevalue, arr.GetLength(0));
                //subscription.RemoveItems(subscription.Items);
                //subscription.Dispose();
                return itemnamevalue;
            }
            catch (Exception ex)
            {
                //if ((m_server == null) || (m_server.IsConnected == false))
                //{
                _IfConnectOPCServer = false;
                //}
                _opcError = "同步读数据时：" + ex.Message;
                return null;
            }
            finally
            {
                itemnamevalue = null;
                values = null;
            }
        }
        /// <summary>
        /// 延吉向指定OPC标签组写入数据（_writeSubscription组）
        /// </summary>
        /// <param name="itemnames"></param>
        /// <param name="itemvalue"></param>
        /// <returns></returns>
        public static bool SyncWriteAllItemValue(string[] itemnames, string[] itemvalue)
        {
            Item[] items;
            ItemValue[] itemvalues;
            IdentifiedResult[] ir;
            try
            {
                if (_IfConnectOPCServer == false)
                {
                    if (ConnectOPCServer(_hostname, _progID) == false) return false;
                }
                if (ConnectCount > 1)
                {
                    _opcError = "同步数据时：OPC Server没连接到PLC，并且超过重复连接次数!请先关闭命令开关，检查通讯线路，确认后重新打开命令开关！";
                    return false;
                }
                //定义item列表
                items = new Item[itemnames.Length];//定义数据项，即item
                int i;
                for (i = 0; i < items.Length; i++)//item初始化赋值
                {
                    items[i] = new Item();//创建一个项Item对象。
                    items[i].ClientHandle = Guid.NewGuid().ToString();//客户端给该数据项分配的句柄。
                    items[i].ItemPath = null; //该数据项在服务器中的路径。
                    items[i].ItemName = _PLCconnectionID + itemnames[i]; //该数据项在服务器中的名字。
                }
                _writeSubscription.AddItems(items);
                itemvalues = new ItemValue[_writeSubscription.Items.Length];
                for (int ii = 0; ii < _writeSubscription.Items.Length; ii++)
                {
                    itemvalues[ii] = new ItemValue((ItemIdentifier)_writeSubscription.Items[ii]);
                    itemvalues[ii].Value = itemvalue[ii];
                }

                ir = _writeSubscription.Write(itemvalues);

                _writeSubscription.RemoveItems(_writeSubscription.Items);
                //_writeSubscription.Dispose();
                //GC.Collect();
                return true;
            }
            catch (Exception ex)
            {
                //if ((m_server == null) || (m_server.IsConnected == false))
                //{
                _IfConnectOPCServer = false;
                //}
                _opcError = "同步写数据时：" + ex.Message;
                return false;
            }
            finally
            {
                items=null;
                itemvalues=null;
                ir=null;
            }
        }

        public static bool SyncWriteAllItemValue(StringBuilder[] itemnames, StringBuilder[] itemvalue)
        {
            Item[] items;
            ItemValue[] itemvalues;
            IdentifiedResult[] ir;
            try
            {
                if (_IfConnectOPCServer == false)
                {
                    if (ConnectOPCServer(_hostname, _progID) == false) return false;
                }
                if (ConnectCount > 1)
                {
                    _opcError = "同步数据时：OPC Server没连接到PLC，并且超过重复连接次数!请先关闭命令开关，检查通讯线路，确认后重新打开命令开关！";
                    return false;
                }
                //定义item列表
                items = new Item[itemnames.Length];//定义数据项，即item
                int i;
                for (i = 0; i < items.Length; i++)//item初始化赋值
                {
                    items[i] = new Item();//创建一个项Item对象。
                    items[i].ClientHandle = Guid.NewGuid().ToString();//客户端给该数据项分配的句柄。
                    items[i].ItemPath = null; //该数据项在服务器中的路径。
                    items[i].ItemName = _PLCconnectionID + itemnames[i].ToString(); //该数据项在服务器中的名字。
                }
                _writeSubscription.AddItems(items);
                itemvalues = new ItemValue[_writeSubscription.Items.Length];
                for (int ii = 0; ii < _writeSubscription.Items.Length; ii++)
                {
                    itemvalues[ii] = new ItemValue((ItemIdentifier)_writeSubscription.Items[ii]);
                    itemvalues[ii].Value = itemvalue[ii].ToString();
                }

                ir = _writeSubscription.Write(itemvalues);

                _writeSubscription.RemoveItems(_writeSubscription.Items);
                //_writeSubscription.Dispose();
                //GC.Collect();
                return true;
            }
            catch (Exception ex)
            {
                //if ((m_server == null) || (m_server.IsConnected == false))
                //{
                _IfConnectOPCServer = false;
                //}
                _opcError = "同步写数据时：" + ex.Message;
                return false;
            }
            finally
            {
                items = null;
                itemvalues = null;
                ir = null;
            }
        }
        /// <summary>
        /// 延吉读取指定OPC标签组数据（_tempSubscription组）
        /// </summary>
        /// <param name="itemnames"></param>
        /// <returns></returns>
        public static object[] SyncReadItemValues(string[] itemnames)
        {
            Item[] items;
            ItemResult[] irs;
            ItemValueResult[] values;
            object[] itemnamevalue;
            try
            {
                string ss; string ss1;
                ss = DateTime.Now.Second.ToString() + "-" + DateTime.Now.Millisecond.ToString();
                if (_IfConnectOPCServer == false)
                {
                    if (ConnectOPCServer(_hostname, _progID) == false) return null;
                }
                //定义item列表
                items = new Item[itemnames.Length];//定义数据项，即item
                int i;
                for (i = 0; i < items.Length; i++)//item初始化赋值
                {
                    items[i] = new Item();//创建一个项Item对象。
                    items[i].ClientHandle = Guid.NewGuid().ToString();//客户端给该数据项分配的句柄。
                    items[i].ItemPath = null; //该数据项在服务器中的路径。
                    items[i].ItemName = _PLCconnectionID + itemnames[i]; //该数据项在服务器中的名字。
                }
                irs = _tempSubscription.AddItems(items);

                values = _tempSubscription.Read(_tempSubscription.Items);
                if (values[0].Quality == Quality.Bad)
                {
                    _opcError = "同步读数据时：OPC Server没连接到PLC!";
                    return null;
                }
                itemnamevalue = new object[values.Length];
                int k = 0;
                foreach (ItemValueResult value in values)
                {
                    itemnamevalue[k] = value.Value;
                    k++;
                }
                //Array.Copy(values.[0].Value, itemnamevalue, values.Length);
                _tempSubscription.RemoveItems(_tempSubscription.Items);
                //_tempSubscription.Dispose();
                //GC.Collect();
                ss1 = DateTime.Now.Second.ToString() + "-" + DateTime.Now.Millisecond.ToString();
                return itemnamevalue;
            }
            catch (Exception ex)
            {
                //if ((m_server == null) || (m_server.IsConnected == false))
                //{
                _IfConnectOPCServer = false;
                //}
                _opcError = "同步读数据时：" + ex.Message;
                return null;
            }
            finally
            {
                items=null ;
                irs=null ;
                values=null ;
                itemnamevalue=null ;
            }
        }
        #endregion


        //20100221
        //#region 延吉同步写、异步读OPC
        //static byte[] AsyncReadAllItemNameValue= new byte[(int)devinfo28.Dbw2Getlength];
        //static bool AsyncReadOK=false ;
        ///// <summary>
        ///// 延吉异步读取整个_readSubscription组的内容
        ///// </summary>
        ///// <returns></returns>
        //public static void AsyncReadAllItems()
        //{
            
        //    try
        //    {
        //        if (_IfConnectOPCServer == false)
        //        {
        //            if (ConnectOPCServer(_hostname, _progID) == false) return ;
        //        }
                
        //        IRequest quest=null ;
        //        _readSubscription.Read(_readSubscription.Items, Guid.NewGuid().ToString(), OnReadComplete,out quest);
                
        //    }
        //    catch (Exception ex)
        //    {
        //        //if ((m_server == null) || (m_server.IsConnected == false))
        //        //{
        //        _IfConnectOPCServer = false;
        //        //}
        //        _opcError = "异步读数据时：" + ex.Message;
        //        AsyncReadOK = false;
        //        return ;
        //    }
        //    finally
        //    {
                
        //    }
        //}
        ///// <summary>
        ///// 延吉向指定OPC标签组同步写入数据（_writeSubscription组）
        ///// </summary>
        ///// <param name="itemnames"></param>
        ///// <param name="itemvalue"></param>
        ///// <returns></returns>
        //public static bool SyncWriteGroupItemValue(string[] itemnames, string[] itemvalue)
        //{
        //    Item[] items;
        //    ItemValue[] itemvalues;
        //    IdentifiedResult[] ir;
        //    try
        //    {
        //        if (AsyncReadOK == false) return false;
        //        if (_IfConnectOPCServer == false)
        //        {
        //            if (ConnectOPCServer(_hostname, _progID) == false) return false;
        //        }
        //        //定义item列表
        //        items = new Item[itemnames.Length];//定义数据项，即item
        //        int i;
        //        for (i = 0; i < items.Length; i++)//item初始化赋值
        //        {
        //            items[i] = new Item();//创建一个项Item对象。
        //            items[i].ClientHandle = Guid.NewGuid().ToString();//客户端给该数据项分配的句柄。
        //            items[i].ItemPath = null; //该数据项在服务器中的路径。
        //            items[i].ItemName = _PLCconnectionID + itemnames[i]; //该数据项在服务器中的名字。
        //        }
        //        _writeSubscription.AddItems(items);
        //        itemvalues = new ItemValue[_writeSubscription.Items.Length];
        //        for (int ii = 0; ii < _writeSubscription.Items.Length; ii++)
        //        {
        //            itemvalues[ii] = new ItemValue((ItemIdentifier)_writeSubscription.Items[ii]);
        //            itemvalues[ii].Value = itemvalue[ii];
        //        }

        //        ir = _writeSubscription.Write(itemvalues);

        //        _writeSubscription.RemoveItems(_writeSubscription.Items);
        //        //_writeSubscription.Dispose();
        //        GC.Collect();
        //        return true;
        //    }
        //    catch (Exception ex)
        //    {
        //        //if ((m_server == null) || (m_server.IsConnected == false))
        //        //{
        //        _IfConnectOPCServer = false;
        //        //}
        //        _opcError = "同步写数据时：" + ex.Message;
        //        return false;
        //    }
        //    finally
        //    {
        //        items = null;
        //        itemvalues = null;
        //        ir = null;
        //    }
        //}
        ////ReadComplete回调
        //public static void OnReadComplete(object requestHandle, Opc.Da.ItemValueResult[] values)
        //{
        //    /*Console.WriteLine("发生异步读name:{0},value:{1}", values[0].ItemName, values[0].Value);
        //    if ((int)requestHandle == 1)
        //        Console.WriteLine("事件信号句柄为{0}", requestHandle);*/
        //    //不区分请求句柄了，直接接收OPC数据
        //    try
        //    {
        //        if (values.Length <= 0)
        //        {
        //            _opcError = "异步读数据时：OPC Server没连接到PLC!";
        //            AsyncReadOK = false;
        //            return ;
        //        }
        //        if (values[0].Quality == Quality.Bad)
        //        {
        //            _opcError = "异步读数据时：OPC Server没连接到PLC!";
        //            AsyncReadOK = false;
        //            return ;
        //        }


        //        Array.Copy((Array)values[0].Value, AsyncReadAllItemNameValue, AsyncReadAllItemNameValue.GetLength(0));// (int)devinfo28.Dbw2Getlength
        //        AsyncReadOK = true;
        //    }
        //    catch (Exception ex)
        //    {
        //        _opcError = "异步读数据时："+ex.Message ;
        //        AsyncReadOK = false;
        //        return;
        //    }
        //    finally
        //    {
        //        values = null;
        //    }
        //}
        //#endregion



        /// <summary>
        /// 同步向OPC组名称内每个变量写入值
        /// </summary>
        /// <param name="subscription">OPC组名称</param>
        /// <param name="itemvalue">每个变量的值</param>
        /// <returns></returns>
        
    }
}
