/// <summary>
        /// 启动串口通讯
        ///
        ///		PLC 的 D8120 设置为 0x0897,则表示 19200,7,1,E
        ///		PLC 的 D8120 设置为 0x0C8E,则表示 9600,7,1,E
        /// </summary>
        /// <returns>如果成功返回 true,否则返回 false</returns>
        public bool Start(int portNo)
        {
            string            cmd;
            FxCommandResponse res;

            bool bOpen = false;

            if (false == bDefaultBaudRate)
            {
                bOpen     = Start(portNo, "115200,E,7,1");
                nBaudrate = 115200;
                if (bOpen)
                {
                    cmd = FxCommandHelper.Make(FxCommandConst.FxCmdRead, new FxAddress("X0", ControllerTypeConst.ctPLC_Fx), 2);
                    res = Send(0, cmd);
                    if (res.ResultCode != ResultCodeConst.rcSuccess)
                    {
                        bOpen = false;
                        _SerialPort.ClosePort();
                    }
                }
            }

            if (false == bOpen)
            {
                bOpen     = Start(portNo, "9600,E,7,1");
                nBaudrate = 9600;
                if (bOpen)
                {
                    cmd = FxCommandHelper.Make(FxCommandConst.FxCmdRead, new FxAddress("X0", ControllerTypeConst.ctPLC_Fx), 2);
                    res = Send(0, cmd);
                    if (res.ResultCode != ResultCodeConst.rcSuccess)
                    {
                        bOpen = false;
                        _SerialPort.ClosePort();
                        nBaudrate = 0;
                    }
                }
            }

            return(bOpen);
            //return Start(portNo, "9600,E,7,1");
        }
        /// <summary>
        /// 将给定节点的“输出值”写入外部设备或PLC
        /// </summary>
        /// <param name="sourceList">节点列表</param>
        /// <param name="timeout">最大超时值</param>
        /// <returns>返回成功写的点数</returns>
        public override int WritePoints(List <AcquirePoint> outputList, TimeSpan timeout)
        {
            int               ct = 0;
            string            cmd;
            FxCommandResponse res;

            foreach (AcquirePoint ap in outputList)
            {
                if (ap.ControllerObject.ControllerId != base.ControllerId)
                {
                    continue;
                }
                if (ap.AV.Output.IsNull)
                {
                    continue;
                }

                if (ap.AV.Output.B)
                {
                    cmd = FxCommandHelper.Make(FxCommandConst.FxCmdForceOn, new FxAddress(ap.ChannelNoAlias, FxAddressLayoutType.AddressLayoutByte));
                }
                else
                {
                    cmd = FxCommandHelper.Make(FxCommandConst.FxCmdForceOff, new FxAddress(ap.ChannelNoAlias, FxAddressLayoutType.AddressLayoutByte));
                }

                res = Send(0, cmd);

#if DEBUG
                //Logger.Instance.WriteLine("FxPLC输出: {0} ", res.ToString());
#endif

                ct++;
            }

            return(ct);
        }
        /// <summary>
        /// 读取设备所有IO点数据,并返回这些点的数据值
        /// </summary>
        public override List <AcquireRawValue> ReadAllPoints(List <AcquirePoint> sourceAPList, TimeSpan timeout)
        {
            if (_SerialPort == null || !_SerialPort.IsOpen)
            {
                return(null);
            }

            List <AcquireRawValue> vlist = new List <AcquireRawValue>();

            if (sourceAPList != null)
            {
                sourceAPList.ForEach(o => {
                    if (o.ControllerObject.ControllerId == this.ControllerId)
                    {
                        vlist.Add(new AcquireRawValue(o.Id, o.ControllerObject, o.ChannelNoAlias));
                    }
                });
            }
            else
            {
                //for(int result = 0; result < 127; result++) {
                //    vlist.Add(new AcquireRawValue(0, 0, string.Format("X{0}", result)));
                //    vlist.Add(new AcquireRawValue(0, 0, string.Format("Y{0}", result)));
                //}
            }

            string            cmd;
            FxCommandResponse res;

            // 读取 X0..X177,一次性读取所有X
            cmd = FxCommandHelper.Make(FxCommandConst.FxCmdRead, new FxAddress("X0", ControllerTypeConst.ctPLC_Fx), 16);
            res = Send(0, cmd);
            //Debug.Print("X0--X177 = {0}", res.ToString());

            // 根据通道号别名,例如"X001","Y177","Mxxx"等内容更新
            if (res.ResultCode == ResultCodeConst.rcSuccess)
            {
                foreach (AcquireRawValue o in vlist)
                {
                    if (o.PLCAddr != null && o.PLCAddr.AddressType == FxAddressType.X)
                    {
                        int byteIndex = (int)(o.PLCAddr.TagOffset / 8);
                        int byteOff   = (int)(o.PLCAddr.TagOffset % 8);

                        if (byteIndex >= 0 && byteIndex < res.ResponseValue.Count)
                        {
                            o.Value = new ValueStruct(((res.ResponseValue[byteIndex] >> byteOff) & 0x01) == 0x01);

                            //Debug.Print("X{0} <== {1}", Convert.ToString(o.PLCAddr.TagOffset, 8), o.Value);
                        }
                        else
                        {
                            //Debug.Print("X{0} <== {1}", Convert.ToString(o.PLCAddr.TagOffset, 8), o.Value);
                        }
                    }
                }
            }
            else
            {
                Debug.Print("{0}\t{1} 读取失败(X001-X177)", DateTime.Now, this.ToString());
            }

            // 读取 Y0..Y177,一次性读取所有Y
            cmd = FxCommandHelper.Make(FxCommandConst.FxCmdRead, new FxAddress("Y0", ControllerTypeConst.ctPLC_Fx), 16);
            res = Send(0, cmd);
            //Debug.Print("Y0--Y177 = {0}", res.ToString());
            // 根据通道号别名,例如"Y177"等内容更新
            if (res.ResultCode == ResultCodeConst.rcSuccess)
            {
                foreach (AcquireRawValue o in vlist)
                {
                    if (o.PLCAddr != null && o.PLCAddr.AddressType == FxAddressType.Y)
                    {
                        int byteIndex = (int)(o.PLCAddr.TagOffset / 8);
                        int byteOff   = (int)(o.PLCAddr.TagOffset % 8);

                        if (byteIndex >= 0 && byteIndex < res.ResponseValue.Count)
                        {
                            o.Value = new ValueStruct(((res.ResponseValue[byteIndex] >> byteOff) & 0x01) == 0x01);
                        }
                        else
                        {
                            //Debug.Print("Y{0} <== {1}", Convert.ToString(o.PLCAddr.TagOffset, 8), o.Value);
                        }
                    }
                }
            }
            else
            {
                Debug.Print("{0}\t{1} 读取失败(Y001-Y177)", DateTime.Now, this.ToString());
            }

            // 一次性读取 M0..M499
            cmd = FxCommandHelper.Make(FxCommandConst.FxCmdRead, new FxAddress("M0", ControllerTypeConst.ctPLC_Fx), 64);
            res = Send(0, cmd);

            //Debug.Print("M0--M499 = {0}", res.ToString());
            // 根据通道号别名,例如"M19"等内容更新
            if (res.ResultCode == ResultCodeConst.rcSuccess)
            {
                foreach (AcquireRawValue o in vlist)
                {
                    if (o.PLCAddr != null && o.PLCAddr.AddressType == FxAddressType.M && o.PLCAddr.TagOffset < 1000)
                    {
                        int byteIndex = (int)(o.PLCAddr.TagOffset / 8);
                        int byteOff   = (int)(o.PLCAddr.TagOffset % 8);

                        if (byteIndex >= 0 && byteIndex < res.ResponseValue.Count)
                        {
                            o.Value = new ValueStruct(((res.ResponseValue[byteIndex] >> byteOff) & 0x01) == 0x01);
                        }
                        else
                        {
                            //Debug.Print("M{0} <== {1}", Convert.ToString(o.PLCAddr.TagOffset, 8), o.Value);
                        }
                    }
                }
            }
            else
            {
                Debug.Print("{0}\t{1} 读取失败(M001-M499)", DateTime.Now, this.ToString());
            }

            #region 一次性读取 M1000-1999 ---- 目前不读取这个范围的 M 点
            if (false)
            {
                cmd = FxCommandHelper.Make(FxCommandConst.FxCmdRead, new FxAddress("M1000", ControllerTypeConst.ctPLC_Fx), 32);
                res = Send(0, cmd);
                //Debug.Print("M1000--M1127 = {0}", res.ToString());
                // 根据通道号别名,例如"M1099"等内容更新
                if (res.ResultCode == ResultCodeConst.rcSuccess)
                {
                    foreach (AcquireRawValue o in vlist)
                    {
                        if (o.PLCAddr != null && o.PLCAddr.AddressType == FxAddressType.M && o.PLCAddr.TagOffset >= 1000)
                        {
                            int byteIndex = (int)((o.PLCAddr.TagOffset - 1000) / 8);
                            int byteOff   = (int)((o.PLCAddr.TagOffset - 1000) % 8);

                            if (byteIndex >= 0 && byteIndex < res.ResponseValue.Count)
                            {
                                o.Value = new ValueStruct(((res.ResponseValue[byteIndex] >> byteOff) & 0x01) == 0x01);
                            }
                            else
                            {
                                //Debug.Print("M{0} <== {1}", o.PLCAddr.TagOffset, o.Value);
                            }
                        }
                    }
                }
            }
            #endregion

            // 读取其他内容:C/D/T
            foreach (AcquireRawValue o in vlist)
            {
                if (o.PLCAddr != null)
                {
                    switch (o.PLCAddr.AddressType)
                    {
                    case FxAddressType.C:
                        cmd = FxCommandHelper.Make(FxCommandConst.FxCmdRead, o.PLCAddr, 2);
                        break;

                    case FxAddressType.D:
                        cmd = FxCommandHelper.Make(FxCommandConst.FxCmdRead, o.PLCAddr, 2);
                        break;

                    case FxAddressType.T:
                        cmd = FxCommandHelper.Make(FxCommandConst.FxCmdRead, o.PLCAddr, 2);
                        break;

                    case FxAddressType.S:
                        cmd = FxCommandHelper.Make(FxCommandConst.FxCmdRead, o.PLCAddr, 2);
                        break;

                    default:
                        continue;
                    }

                    res = Send(0, cmd);
                    if (res.ResultCode == ResultCodeConst.rcSuccess)
                    {
                        o.Value = new ValueStruct((int)res.ResponseValue[0]);
                        //Debug.Print("{0} <== {1}", o.PLCAddr.ToString(), o.Value);
                    }
                    else
                    {
                        //Debug.Print("{0} <== {1}. Error", o.PLCAddr.ToString(), o.Value);
                    }
                }
            }

            return(vlist);
        }
        public void Test_All()
        {
            string            cmd;
            FxCommandResponse res;
            Random            _Random = new Random();

            //// 置位
            //response = FxCommandHelper.Make(FxCommandConst.FxCmdForceOn, new FxAddress("S1"));
            //res = _FxSerial.SendCmdToQnCPU(0, response);

            //// 复位
            //response = FxCommandHelper.Make(FxCommandConst.FxCmdForceOff, new FxAddress("S1"));
            //res = _FxSerial.SendCmdToQnCPU(0, response);


            #region 读取所有 X/Y/M/ ,并计算其耗时

            Stopwatch sw = new Stopwatch();
            sw.Start();
            for (int ct = 0; ct < 10; ct++)
            {
                // 一次性读取多个字节的 X,例如 16 字节::必须采用 AddressLayoutBin 方式
                cmd = FxCommandHelper.Make(FxCommandConst.FxCmdRead, new FxAddress("X0", ControllerTypeConst.ctPLC_Fx), 16);
                res = _FxSerial.Send(0, cmd);
                //Debug.WriteLine(string.Format("成批读X0..X177 \t{0}", res.ToString()));
                //System.Threading.Thread.Sleep(1000);

                // 一次性读取多个字节的 Y,例如 16 字节::必须采用 AddressLayoutBin 方式
                cmd = FxCommandHelper.Make(FxCommandConst.FxCmdRead, new FxAddress("Y0", ControllerTypeConst.ctPLC_Fx), 16);
                res = _FxSerial.Send(0, cmd);
                //Debug.WriteLine(string.Format("成批读Y0..Y177 \t{0}", res.ToString()));
                //System.Threading.Thread.Sleep(1000);

                // 一次性读取多个字节的 M,每次读取128个单元::必须采用 AddressLayoutBin 方式
                cmd = FxCommandHelper.Make(FxCommandConst.FxCmdRead, new FxAddress("M0", ControllerTypeConst.ctPLC_Fx), 128);
                res = _FxSerial.Send(0, cmd);
                //Debug.WriteLine(string.Format("成批读M{0}..M{1} \t{2}", result, result + 128, res.ToString()));

                Debug.Print("=====================> {0}", sw.ElapsedMilliseconds);
            }

            System.Threading.Thread.Sleep(1000);

            #endregion

            #region 针对 X/Y 的设置、读取

            // 置位与复位:必须采用 AddressLayoutByte 方式
            cmd = FxCommandHelper.Make(FxCommandConst.FxCmdForceOn, new FxAddress("Y20", FxAddressLayoutType.AddressLayoutByte));
            res = _FxSerial.Send(0, cmd);
            Debug.WriteLine(res.ToString());
            System.Threading.Thread.Sleep(1000);

            cmd = FxCommandHelper.Make(FxCommandConst.FxCmdForceOff, new FxAddress("Y20", FxAddressLayoutType.AddressLayoutByte));
            res = _FxSerial.Send(0, cmd);
            Debug.WriteLine(res.ToString());
            System.Threading.Thread.Sleep(1000);

            // 针对 Y001..Y177 设置与读取
            for (int i = 0; i < 128; i++)
            {
                cmd = FxCommandHelper.Make(FxCommandConst.FxCmdForceOff,
                                           new FxAddress(string.Format("Y{0}", Convert.ToString(i, 8)), FxAddressLayoutType.AddressLayoutByte));
                res = _FxSerial.Send(0, cmd);
            }

            // 针对 Y001..Y077 设置与读取
            for (int i = 0; i < 128; i++)
            {
                cmd = FxCommandHelper.Make(FxCommandConst.FxCmdForceOn,
                                           new FxAddress(string.Format("Y{0}", Convert.ToString(i, 8)), FxAddressLayoutType.AddressLayoutByte));
                res = _FxSerial.Send(0, cmd);
                //Debug.WriteLine(res.ToString());
                System.Threading.Thread.Sleep(100);

                if ((i - 8) >= 0)
                {
                    cmd = FxCommandHelper.Make(FxCommandConst.FxCmdForceOff,
                                               new FxAddress(string.Format("Y{0}", Convert.ToString(i - 8, 8)), FxAddressLayoutType.AddressLayoutByte));
                    res = _FxSerial.Send(0, cmd);
                    Debug.WriteLine(string.Format("Y{0}\t{1}", Convert.ToString(i, 8), res.ToString()));
                }

                //System.Threading.Thread.Sleep(1000);
            }

            // 一次性读取多个字节的 X,例如 16 字节::必须采用 AddressLayoutBin 方式
            cmd = FxCommandHelper.Make(FxCommandConst.FxCmdRead, new FxAddress("X0", ControllerTypeConst.ctPLC_Fx), 16);
            res = _FxSerial.Send(0, cmd);
            Debug.WriteLine(string.Format("成批读X0..X177 \t{0}", res.ToString()));
            System.Threading.Thread.Sleep(1000);

            // 一次性读取多个字节的 Y,例如 16 字节::必须采用 AddressLayoutBin 方式
            cmd = FxCommandHelper.Make(FxCommandConst.FxCmdRead, new FxAddress("Y0", ControllerTypeConst.ctPLC_Fx), 16);
            res = _FxSerial.Send(0, cmd);
            Debug.WriteLine(string.Format("成批读Y0..Y177 \t{0}", res.ToString()));
            System.Threading.Thread.Sleep(1000);

            #endregion


            #region 针对 M 类型的读写
            // 针对 M001..M077 设置与读取
            for (int i = 0; i < 64; i++)
            {
                cmd = FxCommandHelper.Make(FxCommandConst.FxCmdForceOn,
                                           new FxAddress(string.Format("M{0}", i), FxAddressLayoutType.AddressLayoutByte));
                res = _FxSerial.Send(0, cmd);
                Debug.WriteLine(res.ToString());

                //response = FxCommandHelper.Make(FxCommandConst.FxCmdForceOff,
                //                        new FxAddress(string.Format("M{0}", Convert.ToString(result, 8)), FxAddressLayoutType.AddressLayoutByte));
                //res = _FxSerial.SendCmdToQnCPU(0, response);
                //Debug.WriteLine(res.ToString());

                //System.Threading.Thread.Sleep(100);
            }

            // 一次性读取多个字节的 M,例如 16 字节::必须采用 AddressLayoutBin 方式
            cmd = FxCommandHelper.Make(FxCommandConst.FxCmdRead, new FxAddress("M0", ControllerTypeConst.ctPLC_Fx), 64);
            res = _FxSerial.Send(0, cmd);
            Debug.WriteLine(string.Format("成批读M0..M77 \t{0}", res.ToString()));
            System.Threading.Thread.Sleep(1000);

            #endregion


            #region 循环设置与读取 Dxxx 的数据
            for (int i = 0; i < 1; i++)
            {
                List <uint> lst = new List <uint>()
                {
                    (uint)i
                };
                for (int k = 0; k < 10; k++)
                {
                    lst.Add((uint)_Random.Next());
                }

                cmd = FxCommandHelper.Make <UInt32DataType>(FxCommandConst.FxCmdWrite, new FxAddress("D1", ControllerTypeConst.ctPLC_Fx), lst);
                res = _FxSerial.Send(0, cmd);
                Debug.WriteLine(res.ToString());

                cmd = FxCommandHelper.Make(FxCommandConst.FxCmdRead, new FxAddress("D1", ControllerTypeConst.ctPLC_Fx), lst.Count * 4);
                res = _FxSerial.Send(0, cmd, UInt32DataType.Default);
                Debug.WriteLine(res.ToString());

                if (res.ResponseValue != null && res.ResponseValue.Count > 0)
                {
                    Debug.WriteLine("");
                    Debug.Write(DateTime.Now.ToString());
                    Debug.Write("\t");
                    for (int j = 0; j < res.ResponseValue.Count; j++)
                    {
                        Debug.Write(res.ResponseValue[j]);
                        Debug.Write(',');
                    }
                }
                else
                {
                    Debug.WriteLine("没有收到FX PLC响应。");
                }
            }
            #endregion


            Debug.Assert(false, "运行暂停!!!");
        }