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.Text.RegularExpressions;
using System.Reflection.Emit;
using System.Security.AccessControl;

namespace OPCClient
{
    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 string OPCGroupEndDevice = "24103,24102,24101,24105,24104,24112,24111,24110,24109,24108";
        /// <summary>
        /// 一个周期内一个订阅组发送所有标签的个数
        /// </summary>
        static Dictionary<string, int> _opcSubsTagCount = new Dictionary<string, int>();
        /// <summary>
        /// 每个订阅组里对应设备发送标签名称集合
        /// </summary>
        static Dictionary<string, Dictionary<int, StringBuilder[]>> _opcItemNamesDicInfo = new Dictionary<string, Dictionary<int, StringBuilder[]>>();
        /// <summary>
        /// 每个订阅组里对应设备发送标签数值集合
        /// </summary>
        static Dictionary<string, Dictionary<int, StringBuilder[]>> _opcItemValuesDicInfo = new Dictionary<string, Dictionary<int, StringBuilder[]>>();

        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);
            //PublishDeviceState(sender, e);
        }
        public static DBOperator dbo = new DBOperator(); //20130510

        public static DBOperator dboMADD = new DBOperator("ManConnString", "ManDBFactory");//20130510
        //20110726
        private static Dictionary<string, int> _connectCount = new Dictionary<string, int>();
        //20110726
        public static Dictionary<string, int> 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;

        /// <summary>
        /// 20110309订阅的组内标签数据变化事件
        /// </summary>
        /// <param name="subscriptionHandle">客户端句柄</param>
        /// <param name="requestHandle">请求句柄</param>
        /// <param name="values">标签值数组</param>
        public static void OnDataChange(object clientHandle, DataValue value)
        {
            lock (thisLock)
            {
                //根据subscriptionHandle对应设备索引,依据设备种类(不同类型设备通讯数据帧不同)
                //分别处理:完成,报警,光电开关,PLC发起的请求
                int deviceindex = 0;
                try
                {
                    if (clientHandle.ToString().IndexOf("split") >= 0)
                    {
                        deviceindex = System.Convert.ToInt32(clientHandle.ToString().Substring(5));
                    }
                    else
                    {
                        deviceindex = System.Convert.ToInt32(clientHandle);
                    }
                    devinfo = Model.CGetInfo.GetDeviceInfo(deviceindex);
                    if (StatusCode.IsNotGood(value.StatusCode))
                    {
                        if (devinfo == null)
                        {
                            OpcError = string.Format("设备索引{0}在数据库不存在!", clientHandle);

                            return;
                        }

                        //触发一个特殊事件提示PLC断开连接
                        if (ConnectCount.ContainsKey(devinfo.S7Connection) == false)//20110726
                        {
                            ConnectCount.Add(devinfo.S7Connection, 0);
                        }

                        OpcError = string.Format("{0}所在的PLC已经离线!订阅标签状态:" + value.StatusCode.ToString(), clientHandle);
                        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 (clientHandle.ToString().IndexOf("split") >= 0)
                    {
                        Array arr = (Array)value.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)value.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 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<int, StringBuilder> DeviceStateInfos = new Dictionary<int, StringBuilder>();

                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,增加字段是否需要服务端处理设备的订阅
                    StringBuilder sql1 = 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}') 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(dbo.ExceSQL(sql1.ToString()).Tables[0].DefaultView[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)
                            {
                                taskindex = (devicestates[tempdb2addr + 2] << 8) + devicestates[tempdb2addr + 3];
                            }
                            if (1 < devinfo.Dbw2Getlength)
                            {
                                state = devicestates[tempdb2addr + 1];

                            }
                            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)
                                    {
                                        #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)
                                    {//求上一次运行时间
                                     //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 更新光电开关状态
                                    ////动态晶澳添加组件车间申请托盘垛
                                    if (((devinfo.DeviceIndex == 22155) || (devinfo.DeviceIndex == 22128) || (devinfo.DeviceIndex == 22130)))//功能屏蔽组件车间缓存&& (1 == 0)
                                    {
                                        if ((devinfo.SplitByte_0 == 1) && ((devicestates[tempdb2addr + 4] & 1) == 0))
                                        {
                                            StringBuilder dtime = new StringBuilder(DateTime.Now.ToString("u"));
                                            dtime.Remove(dtime.Length - 1, 1);
                                            object[] ob = new object[8] { 2, devinfo.DeviceIndex, 0, 0, dtime, "", "1", 0 };

                                            try
                                            {
                                                if (dbo.GetSingle(String.Format("select fid from T_Manage_Task where FENDDEVICE='{0}'", devinfo.DeviceIndex.ToString())) == null)
                                                {

                                                    dboMADD.ExecuteSql(string.Format("INSERT INTO IO_CONTROL_APPLY(CONTROL_APPLY_ID,CONTROL_APPLY_TYPE,DEVICE_CODE, STOCK_BARCODE, APPLY_TASK_STATUS, CREATE_TIME,WAREHOUSE_CODE,STOCK_HEIGHT)VALUES(IO_CONTROL_APPLY_SEQ.nextval,{0},'{1}','{2}',0,'{4}','{6}','{7}')", ob));
                                                    CommonClassLib.CCarryConvert.WriteDarkCasket("OPCClient", "组件车间向管理申请空托盘垛任务任务:", devidx.ToString(), string.Format(",站台:{0},申请类型:2 ", devidx.ToString()));
                                                }
                                                else
                                                {
                                                    CommonClassLib.CCarryConvert.WriteDarkCasket("OPCClient", "有来此站台的任务不申请空托盘垛任务任务:", devidx.ToString(), string.Format(",站台:{0},申请类型:2 ", devidx.ToString()));
                                                }
                                            }
                                            catch (Exception ex)
                                            {
                                                RefreshMonitorEventArgs rmea = new RefreshMonitorEventArgs("tsStatus", "向管理申请组件车间出库托盘垛任务时发生错误:" + ex.StackTrace + ex.Message);
                                                OnRefreshMonitor(rmea);
                                                continue;
                                            }
                                        }
                                    }
                                    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 = 2; j < PalletBarcodeLength + 2; 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().ToUpper());

                                        }

                                        #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(), BoxInspection));

                                                break;
                                            case "5":
                                                //比对任务报完成,申请任务
                                                DeviceStateInfos[devidx].Append(string.Format("{0},{1},{2},{3},{4}", 0, 0, 5, barcode.ToString(), 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(), BoxInspection));

                                                #endregion
                                                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:
                                     //更改上报AGV还是人拖走1/3
                                    if (((devicestates[tempdb2addr + 0] != 1)&&(devicestates[tempdb2addr + 0] != 3))||(deviceindex<324000)) continue;//屏蔽39非过账的设备变化

                                    AddBatchReponse(Model.CGeneralFunction.DBSend, 0, devidx, 2);
                                    CommonClassLib.CCarryConvert.WriteDarkCasket("OPCClient", "写过账申请应答", devidx.ToString(), "写标志2**");
                                    DeviceStateInfos[devidx].Append(string.Format("{0},{1},{2}", 0, 0, devicestates[0]));

                                    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]);
                                            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}$";
        /// <summary>
        /// 条码格式检查
        /// </summary>
        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}$";
                }
            }
        }
        public 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//更改到给环穿发送任务的sendOK处
                            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
            {


            }
        }
        /// <summary>
        /// 暂存标签数据
        /// </summary>
        /// <param name="deviceIndex">设备编号</param>
        /// <param name="itemnames">地址区标签名称数组</param>
        /// <param name="itemvalues">标签值数组</param>
        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<int, StringBuilder[]> OPCDeviceSendtagNamedic = new Dictionary<int, StringBuilder[]>();
                    Dictionary<int, StringBuilder[]> OPCDeviceSendtagValuedic = new Dictionary<int, StringBuilder[]>();
                    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
            {


            }
        }

        /// <summary> 
        /// 比较两个值型一维数组变量是否值相等 
        /// </summary> 
        /// <param name="array1">值型一维数组1</param> 
        /// <param name="array2">值型一维数组2</param> 
        /// <returns>比较结果,相等则true,否则false</returns> 
        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个字节"
        /// <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;
                RefreshMonitorEventArgs rme = new RefreshMonitorEventArgs("tsStatus", _opcError);
                OnRefreshMonitor(rme);
            }
        }

        /// <summary>
        /// 《设备索引,对应设备订阅》
        /// </summary>
        public static SubscriptionCollection SubscriptionGroup = new SubscriptionCollection();//定义组对象集合(订阅者集合)//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_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")
                    {
                        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, 300, 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, 300, 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()]++;
                    }
                }


            }
        }
        /// <summary>
        /// 通过设置订阅的监控模式,刷新订阅
        /// </summary>
        /// <returns></returns>
        public static bool RefreshMonitoringMode()
        {//20150103增加断网恢复
            if (m_Subscription != null)
            {
                m_Subscription.RefreshMonitoringMode();
            }
            return true;
        }
        /// <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
            {
                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(300);
                        }
                        #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)
            {
                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;
                }
            }
        }

        /// <summary>
        /// 获得设备类型索引
        /// </summary>
        /// <param name="devIdx">设备索引</param>
        /// <returns>设备类型索引</returns>
        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;

        }
    }
}