using FlyAd2021.Inc;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace FlyAd2021
{
    public class FlyAd2021Base : IFlyAd2021Base
    {
        public event PropertyChangedEventHandler PropertyChanged;

        #region 测量速度
        public bool IsMeasuring { get; private set; }

        /// <summary>
        ///  通讯速度 byte/s
        /// </summary>
        public double CommSpeed { get; private set; }

        /// <summary>
        /// 传输速度 单位 pack/s
        /// </summary>
        public double PackSpeed { get; private set; }


        #endregion

        /// <summary>
        /// 包出错次数
        /// </summary>
        public int ErrCnt { get; private set; }
        /// <summary>
        /// 连接成功；
        /// 当命令多次发送失败，IsConnected = false
        /// </summary>
        public bool IsConnected { get; private set; }

        /// <summary>
        /// 数据推送事件
        /// </summary>
        public event PushDataEventHandler PushDataEvent;

        List<byte> currPack = new List<byte>();

        int packCnt = 0;
        int recCnt = 0;
        List<COMMREQ> COMMREQs;
        Stopwatch stopwatch = new Stopwatch();
        CancellationTokenSource cancellationTokenSource;


        /// <summary>
        /// 指令队列，必须等上1条指令回复了，才能发下条指令
        /// </summary>
        List<COMMREQ_Transaction> Transactions;
        /// <summary>
        /// 当前正在等待回复的指令
        /// </summary>
        COMMREQ_Transaction currTran;
        Stopwatch stopwatch_timeOut;
        int retryCnt=0;

        public FlyAd2021Base() 
        {
            COMMREQs = new List<COMMREQ>
            {
                #region IOComm IO指令
                new COMMREQ(COMMREQ_Type.IGI,2,(pack,dataIdx)=>BitConverter.ToUInt16(pack, dataIdx)),
                new COMMREQ(COMMREQ_Type.IGO,2,(pack,dataIdx)=>BitConverter.ToUInt16(pack, dataIdx)),
                new COMMREQ(COMMREQ_Type.IGP0,4,(pack,dataIdx)=>BitConverter.ToInt32(pack, dataIdx)),
                new COMMREQ(COMMREQ_Type.IGP1,4,(pack,dataIdx)=>BitConverter.ToInt32(pack, dataIdx)),
                new COMMREQ(COMMREQ_Type.IGPA,8,(pack,dataIdx)=>{
                    int pos1 = BitConverter.ToInt32(pack, dataIdx);
                        dataIdx += 4;
                        int pos2 = BitConverter.ToInt32(pack, dataIdx);
                        dataIdx += 4;
                        return new GetEncAll_Reponse()
                        {
                            pos1 = pos1,
                            pos2 = pos2
                        };
                }),
                new COMMREQ(COMMREQ_Type.ISO),
                #endregion
                
                #region RunComm 运行指令 SetRunParam
                new COMMREQ(COMMREQ_Type.RPV),
                new COMMREQ(COMMREQ_Type.RPS),
                new COMMREQ(COMMREQ_Type.RPU),
                new COMMREQ(COMMREQ_Type.RPD),
                new COMMREQ(COMMREQ_Type.RP1),
                new COMMREQ(COMMREQ_Type.RP2),
                #endregion

                #region RunComm 运行指令 GetRunParam
                new COMMREQ(COMMREQ_Type.RpV,4,(pack,dataIdx)=>BitConverter.ToUInt32(pack, dataIdx)),
                new COMMREQ(COMMREQ_Type.RpS,4,(pack,dataIdx)=>BitConverter.ToUInt32(pack, dataIdx)),
                new COMMREQ(COMMREQ_Type.RpU,4,(pack,dataIdx)=>BitConverter.ToUInt32(pack, dataIdx)),
                new COMMREQ(COMMREQ_Type.RpD,4,(pack,dataIdx)=>BitConverter.ToUInt32(pack, dataIdx)),
                new COMMREQ(COMMREQ_Type.Rp1,4,(pack,dataIdx)=>BitConverter.ToUInt32(pack, dataIdx)),
                new COMMREQ(COMMREQ_Type.Rp2,4,(pack,dataIdx)=>BitConverter.ToUInt32(pack, dataIdx)),

                #endregion

                #region RunComm 运行指令
                new COMMREQ(COMMREQ_Type.RN,5,(pack,dataIdx)=>{
                    byte result = pack[dataIdx];
                    dataIdx += 1;
                    UInt32 serial = BitConverter.ToUInt32(pack, dataIdx);
                    dataIdx += 4;
                    return new GetRunResult_Reponse()
                    {
                        result = result,
                        serial = serial
                    };
                }),
                new COMMREQ(COMMREQ_Type.RRP),
                new COMMREQ(COMMREQ_Type.RO),
                new COMMREQ(COMMREQ_Type.RF),
                new COMMREQ(COMMREQ_Type.RB),
                new COMMREQ(COMMREQ_Type.RS),
                new COMMREQ(COMMREQ_Type.RT),
                #endregion

                #region 同步运行指令
                new COMMREQ(COMMREQ_Type.RD0x80,new byte[]{ (byte)'R', (byte)'D',0x80}),
                new COMMREQ(COMMREQ_Type.RD0x81,new byte[]{ (byte)'R', (byte)'D',0x81}),
                new COMMREQ(COMMREQ_Type.RD0x02,new byte[]{ (byte)'R', (byte)'D',0x02}),
                new COMMREQ(COMMREQ_Type.RD0x03,new byte[]{ (byte)'R', (byte)'D',0x03}),
                new COMMREQ(COMMREQ_Type.RD0x04,new byte[]{ (byte)'R', (byte)'D',0x04}),
                new COMMREQ(COMMREQ_Type.RD0xE0,new byte[]{ (byte)'R', (byte)'D',0xE0}),
                new COMMREQ(COMMREQ_Type.RD0xE1,new byte[]{ (byte)'R', (byte)'D',0xE1}),
                new COMMREQ(COMMREQ_Type.RD0xE2,new byte[]{ (byte)'R', (byte)'D',0xE3}),
                new COMMREQ(COMMREQ_Type.RGD,2),
                #endregion

            };

            Transactions = new List<COMMREQ_Transaction>();

            stopwatch_timeOut = new Stopwatch();
        }
        #region 测量
        public void StartMeasure() 
        {
            if (IsMeasuring)
                return;
            IsMeasuring = true;
            cancellationTokenSource = new CancellationTokenSource();
            //启动线程，测量速度
            Task.Factory.StartNew(MeasureTask, cancellationTokenSource.Token);
        }
        public void StopMeasure()
        {
            cancellationTokenSource.Cancel();
            //停止线程
            IsMeasuring = false;
        }
        async void MeasureTask()
        {

            stopwatch.Start();
            while (!cancellationTokenSource.IsCancellationRequested)
            {
                if (stopwatch.Elapsed > TimeSpan.FromSeconds(1))
                {
                    //1秒均值
                    CommSpeed = recCnt / stopwatch.Elapsed.TotalSeconds;
                    PackSpeed = packCnt / stopwatch.Elapsed.TotalSeconds;
                    recCnt = 0;
                    packCnt = 0;
                    stopwatch.Restart();
                }
                await Task.Delay(100);
            }
            stopwatch.Stop();
        }
        #endregion


        /// <summary>
        /// 发送指令的超时判断
        /// </summary>
        void OnPoll_TimeOut() 
        {
            if (currTran == null)
                return;
            
            if (!stopwatch_timeOut.IsRunning)
                return;

            if (stopwatch_timeOut.Elapsed < TimeSpan.FromSeconds(1)) 
                return;

            //大于1秒也没回复，异常
            //重试3次
            retryCnt++;
            stopwatch_timeOut.Stop();

            if (retryCnt >= 3) {
                //已经重试了3次，放弃
                IsConnected = false;
                currTran = null;

                //清空 指令队列
                Transactions.Clear();
                return;
            }
        }

        public void RecMsg(byte[] recBuf)
        {
            for (int i = 0; i < recBuf.Count(); i++)
            {
                if (recBuf[i] == 0x7e)
                {
                    //找到头了
                    //结束之前的包
                    if (currPack.Count > 0)
                    {
                        var pack = currPack.ToArray();
                        ParsePack(pack);
                        currPack.Clear();
                        packCnt++;
                    }
                }
                currPack.Add(recBuf[i]);
            }


            OnPoll_TimeOut();
        }
        
        /// <summary>
        /// 获取 发送队列 第1条msg
        /// </summary>
        /// <returns></returns>
        public byte[] GetSendMsg() 
        {
            if (currTran == null)
            {
                if (Transactions.Count() == 0)//队列没有需要发送的指令
                    return null;

                currTran = Transactions.First();
                Transactions.RemoveAt(0);

                stopwatch_timeOut.Restart();
                retryCnt = 0;
            }
            else 
            {
                //发送出去中，等待回复
                if (stopwatch.IsRunning)
                    return null;//已经发送了，计时器都启动了

                //等重试
                stopwatch_timeOut.Restart();
                
            }

            //找出 COMMREQ
            var commReq = COMMREQs.Find(c => c.CType == currTran.ctype);
            List<byte> pack = new List<byte>();
            pack.AddRange(commReq.Prefix);
            if (currTran.datas != null)
                pack.AddRange(currTran.datas);
                        
            return GetSendPack(pack).ToArray();
        }

        /// 包解析
        /// </summary>
        void ParsePack(byte[] pack)
        {
            //第0个肯定是7E
            if (pack.Count() == 1)
            {
                //只有一个 7E
                return;
            }

            //转义数据
            if (!ProtocolCommon.Pdu2Data(pack, out List<byte> datas))
            {
                //异常
                return;
            }

            pack = datas.ToArray();

            //解析后的 datas 没有了 帧包装 7E
            byte crc8 = Misc.CRC.CRC8(pack, 0, pack.Count() - 1);
            if (pack.Last() != crc8)
            {
                //CRC8 出错
                ErrCnt++;
                return;
            }
            
            byte B0 = pack[0];
            bool PT = Misc.MyBase.CHECKBIT(B0, 7);
            if (!PT)
            {
                ParseDataPack(pack);
            }
            else
            {

                ParseFuncPack(pack);
            }

        }


        void ParseDataPack(byte[] pack) {
            PushDataEventArgs eventArgs = new PushDataEventArgs();


            byte systick = pack[0];
            Misc.MyBase.CLEARBIT(ref systick, 7);
            eventArgs.SysTick = systick;

            byte B1 = pack[1];
            bool hasIn = Misc.MyBase.CHECKBIT(B1, 7);
            bool hasENC1 = Misc.MyBase.CHECKBIT(B1, 6);
            bool hasENC2 = Misc.MyBase.CHECKBIT(B1, 5);
            bool hasOut = Misc.MyBase.CHECKBIT(B1, 4);

            var buf = pack;
            int index = 2;
            eventArgs.AD = BitConverter.ToUInt16(buf, index);


            index += 2;
            if (hasENC1)
            {
                eventArgs.ENC1 = BitConverter.ToUInt16(buf, index);
                index += 2;
            }

            if (hasENC2)
            {
                eventArgs.ENC2 = BitConverter.ToUInt16(buf, index);
                index += 2;
            }

            if (hasIn)
            {
                eventArgs.In = BitConverter.ToUInt16(buf, index);
                index += 2;
                eventArgs.InChange = BitConverter.ToUInt16(buf, index);
                index += 2;
            }

            if (hasOut)
            {
                eventArgs.Out = BitConverter.ToUInt16(buf, index);
                index += 2;
            }

            PushDataEvent?.Invoke(this, eventArgs);
        }
        /// <summary>
        /// 功能包解析
        /// </summary>
        /// <param name="datas"></param>
        void ParseFuncPack(byte[] pack)
        {
            var commReq = COMMREQs.Find(_commreq => IsMatch(_commreq, pack));

            if (commReq == null)
            {
                //失败，指令错误！！！
                ErrCnt++;
                return;
            }

            if (commReq.ReponseLen > pack.Count())
            {
                //失败，指令长度不对！！
                ErrCnt++;
            }

            if(currTran==null)
            {
                //没有请求。。。
                return;
            }

            if (currTran.ctype != commReq.CType) {
                //回复对不上请求
                return;
            }

            //处理指令
            var retData = commReq.ParseFuncPack(pack, commReq.Prefix.Count());

            //调用回调
            currTran.asyncDelegate(currTran.asyncDelegate, retData);
            stopwatch_timeOut.Stop();
            currTran = null;
        }

        bool IsMatch(COMMREQ commreq, byte[] datas)
        {
            if (datas.Count() < commreq.Prefix.Length)
                return false;

            for (int i = 0; i < commreq.Prefix.Length; i++)
            {
                if (commreq.Prefix[i] != datas[i])
                {
                    return false;
                }
            }

            return true;
        }


        /// <summary>
        /// 数据发送，不需要包含开头的7E
        /// </summary>
        /// <param name="datas"></param>
        List<byte> GetSendPack(List<byte> datas)
        {
            datas.Insert(0, 0x80);//插入B0

            //需要在后面添加CRC8
            byte crc8 = Misc.CRC.CRC8(datas, 0, datas.Count);
            datas.Add(crc8);

            ProtocolCommon.Data2Pdu(datas, out List<byte> pack);
            pack.Add(0x7E);//一定要加0x7E
            return pack;
        }
        #region IOComm IO指令
        /// <summary>
        /// 获取输入口状态
        /// </summary>
        /// <param name="asyncDelegate"></param>
        /// <param name="asyncContext"></param>
        public void GetIn(CallBackHandler asyncDelegate, object asyncContext) 
        {
            //放入 交易队列
            Transactions.Add(
                new COMMREQ_Transaction()
                {
                    ctype = COMMREQ_Type.IGI,
                    asyncDelegate = asyncDelegate,
                    asyncContext = asyncContext
                });
            
        }

        /// <summary>
        /// 获取输出口状态
        /// </summary>
        /// <param name="asyncDelegate"></param>
        /// <param name="asyncContext"></param>
        [CallBack(typeof(UInt16))]
        public void GetOut(CallBackHandler asyncDelegate, object asyncContext) 
        {
            //放入 交易队列
            Transactions.Add(
            new COMMREQ_Transaction()
            {
                ctype = COMMREQ_Type.IGO,
                asyncDelegate = asyncDelegate,
                asyncContext = asyncContext
            });
        }

        [CallBack(typeof(Int32))]
        public void GetEnc1(CallBackHandler asyncDelegate, object asyncContext) 
        {
            //放入 交易队列
            Transactions.Add(
                new COMMREQ_Transaction()
                {
                    ctype = COMMREQ_Type.IGP0,
                    asyncDelegate = asyncDelegate,
                    asyncContext = asyncContext
                });
        }

        [CallBack(typeof(Int32))]
        public void GetEnc2(CallBackHandler asyncDelegate, object asyncContext) 
        {
            //放入 交易队列
            Transactions.Add(
                new COMMREQ_Transaction()
                {
                    ctype = COMMREQ_Type.IGP1,
                    asyncDelegate = asyncDelegate,
                    asyncContext = asyncContext
                });
        }

        [CallBack(typeof(GetEncAll_Reponse))]
        public void GetEncAll(CallBackHandler asyncDelegate, object asyncContext) 
        {
            //放入 交易队列
            Transactions.Add(
                new COMMREQ_Transaction()
                {
                    ctype = COMMREQ_Type.IGPA,
                    asyncDelegate = asyncDelegate,
                    asyncContext = asyncContext
                });
        }

        public void SetOutPorts(UInt16 mask, UInt16 value, CallBackHandler asyncDelegate, object asyncContext) 
        {
            List<byte> datas = new List<byte>();
            datas.AddRange(BitConverter.GetBytes(mask));
            datas.AddRange(BitConverter.GetBytes(value));

            //放入 交易队列
            Transactions.Add(
                new COMMREQ_Transaction()
                {
                    ctype = COMMREQ_Type.RPV,
                    asyncDelegate = asyncDelegate,
                    asyncContext = asyncContext,
                    datas = datas.ToArray()
                });
        }
        #endregion

        #region RunComm 运行指令 SetRunParam
        public void SetRunParamV(UInt32 velocity, CallBackHandler asyncDelegate, object asyncContext) 
        {
            //放入 交易队列
            Transactions.Add(
                new COMMREQ_Transaction()
                {
                    ctype = COMMREQ_Type.RPV,
                    asyncDelegate = asyncDelegate,
                    asyncContext = asyncContext,
                    datas = BitConverter.GetBytes(velocity)
                });
        }

        public void SetRunParamSV(UInt32 sv, CallBackHandler asyncDelegate, object asyncContext)
        {
            //放入 交易队列
            Transactions.Add(
                new COMMREQ_Transaction()
                {
                    ctype = COMMREQ_Type.RPS,
                    asyncDelegate = asyncDelegate,
                    asyncContext = asyncContext,
                    datas = BitConverter.GetBytes(sv)
                });
        }

        public void SetRunParamAccTime(UInt32 accTime, CallBackHandler asyncDelegate, object asyncContext)
        {
            //放入 交易队列
            Transactions.Add(
                new COMMREQ_Transaction()
                {
                    ctype = COMMREQ_Type.RPU,
                    asyncDelegate = asyncDelegate,
                    asyncContext = asyncContext,
                    datas = BitConverter.GetBytes(accTime)
                });
        }

        public void SetRunParamDecTime(UInt32 decTime, CallBackHandler asyncDelegate, object asyncContext)
        {
            //放入 交易队列
            Transactions.Add(
                new COMMREQ_Transaction()
                {
                    ctype = COMMREQ_Type.RPD,
                    asyncDelegate = asyncDelegate,
                    asyncContext = asyncContext,
                    datas = BitConverter.GetBytes(decTime)
                });
        }

        public void SetRunParamHSpd1(UInt32 homespd1, CallBackHandler asyncDelegate, object asyncContext)
        {
            //放入 交易队列
            Transactions.Add(
                new COMMREQ_Transaction()
                {
                    ctype = COMMREQ_Type.RP1,
                    asyncDelegate = asyncDelegate,
                    asyncContext = asyncContext,
                    datas = BitConverter.GetBytes(homespd1)
                });
        }

        public void SetRunParamHSpd2(UInt32 homespd2, CallBackHandler asyncDelegate, object asyncContext)
        {
            //放入 交易队列
            Transactions.Add(
                new COMMREQ_Transaction()
                {
                    ctype = COMMREQ_Type.RP2,
                    asyncDelegate = asyncDelegate,
                    asyncContext = asyncContext,
                    datas = BitConverter.GetBytes(homespd2)
                });
        }

        #endregion

        #region RunComm 运行指令 GetRunParam
        public void GetRunParamV(CallBackHandler asyncDelegate, object asyncContext)
        {
            //放入 交易队列
            Transactions.Add(
                new COMMREQ_Transaction()
                {
                    ctype = COMMREQ_Type.RpV,
                    asyncDelegate = asyncDelegate,
                    asyncContext = asyncContext
                });
        }

        public void GetRunParamSV(CallBackHandler asyncDelegate, object asyncContext)
        {
            //放入 交易队列
            Transactions.Add(
                new COMMREQ_Transaction()
                {
                    ctype = COMMREQ_Type.RpS,
                    asyncDelegate = asyncDelegate,
                    asyncContext = asyncContext
                });
        }

        public void GetRunParamAccTime(CallBackHandler asyncDelegate, object asyncContext)
        {
            //放入 交易队列
            Transactions.Add(
                new COMMREQ_Transaction()
                {
                    ctype = COMMREQ_Type.RpU,
                    asyncDelegate = asyncDelegate,
                    asyncContext = asyncContext
                });
        }

        public void GetRunParamDecTime(CallBackHandler asyncDelegate, object asyncContext)
        {
            //放入 交易队列
            Transactions.Add(
                new COMMREQ_Transaction()
                {
                    ctype = COMMREQ_Type.RpD,
                    asyncDelegate = asyncDelegate,
                    asyncContext = asyncContext
                });
        }

        public void GetRunParamHSpd1(CallBackHandler asyncDelegate, object asyncContext)
        {
            //放入 交易队列
            Transactions.Add(
                new COMMREQ_Transaction()
                {
                    ctype = COMMREQ_Type.Rp1,
                    asyncDelegate = asyncDelegate,
                    asyncContext = asyncContext
                });
        }

        public void GetRunParamHSpd2(CallBackHandler asyncDelegate, object asyncContext)
        {
            //放入 交易队列
            Transactions.Add(
                new COMMREQ_Transaction()
                {
                    ctype = COMMREQ_Type.Rp2,
                    asyncDelegate = asyncDelegate,
                    asyncContext = asyncContext
                });
        }

        #endregion


        #region RunComm 运行指令
        public void GetRunResult(CallBackHandler asyncDelegate, object asyncContext) 
        {
            {
                //放入 交易队列
                Transactions.Add(
                    new COMMREQ_Transaction()
                    {
                        ctype = COMMREQ_Type.RN,
                        asyncDelegate = asyncDelegate,
                        asyncContext = asyncContext
                    });
            }
        }

        public void Forw(Int32 serial, CallBackHandler asyncDelegate, object asyncContext)
        {
            //放入 交易队列
            Transactions.Add(
                new COMMREQ_Transaction()
                {
                    ctype = COMMREQ_Type.RF,
                    asyncDelegate = asyncDelegate,
                    asyncContext = asyncContext,
                    datas = BitConverter.GetBytes(serial)
                });
        }

        public void Backw(Int32 serial, CallBackHandler asyncDelegate, object asyncContext)
        {
            //放入 交易队列
            Transactions.Add(
                new COMMREQ_Transaction()
                {
                    ctype = COMMREQ_Type.RB,
                    asyncDelegate = asyncDelegate,
                    asyncContext = asyncContext,
                    datas = BitConverter.GetBytes(serial)
                });
        }
        public void Org(Int32 serial, CallBackHandler asyncDelegate, object asyncContext)
        {
            //放入 交易队列
            Transactions.Add(
                new COMMREQ_Transaction()
                {
                    ctype = COMMREQ_Type.RO,
                    asyncDelegate = asyncDelegate,
                    asyncContext = asyncContext,
                    datas = BitConverter.GetBytes(serial)
                });
        }

        public void RunTo(int targetPos, Int32 serial, CallBackHandler asyncDelegate, object asyncContext) 
        {
            List<byte> datas = new List<byte>();
            datas.AddRange(BitConverter.GetBytes(targetPos));
            datas.AddRange(BitConverter.GetBytes(serial));

            //放入 交易队列
            Transactions.Add(
                new COMMREQ_Transaction()
                {
                    ctype = COMMREQ_Type.RRP,
                    asyncDelegate = asyncDelegate,
                    asyncContext = asyncContext,
                    datas = datas.ToArray()
                });
        }
        public void Stop(CallBackHandler asyncDelegate, object asyncContext)
        {

            //放入 交易队列
            Transactions.Add(
                new COMMREQ_Transaction()
                {
                    ctype = COMMREQ_Type.RS,
                    asyncDelegate = asyncDelegate,
                    asyncContext = asyncContext
                });
        }
        public void EStop(CallBackHandler asyncDelegate, object asyncContext)
        {

            //放入 交易队列
            Transactions.Add(
                new COMMREQ_Transaction()
                {
                    ctype = COMMREQ_Type.RT,
                    asyncDelegate = asyncDelegate,
                    asyncContext = asyncContext
                });
        }
        #endregion

        #region 同步运行指令
        public void SyncRun_SetHShift(int hShift, CallBackHandler asyncDelegate, object asyncContext) 
        {
            //放入 交易队列
            Transactions.Add(
                new COMMREQ_Transaction()
                {
                    ctype = COMMREQ_Type.RD0x80,
                    asyncDelegate = asyncDelegate,
                    asyncContext = asyncContext,
                    datas = BitConverter.GetBytes(hShift)
                });
        }
        public void SyncRun_SetVShift(int vShift, CallBackHandler asyncDelegate, object asyncContext)
        {
            //放入 交易队列
            Transactions.Add(
                new COMMREQ_Transaction()
                {
                    ctype = COMMREQ_Type.RD0x81,
                    asyncDelegate = asyncDelegate,
                    asyncContext = asyncContext,
                    datas = BitConverter.GetBytes(vShift)
                });
        }

        public void SyncRun_Start(CallBackHandler asyncDelegate, object asyncContext) 
        {
            //放入 交易队列
            Transactions.Add(
                new COMMREQ_Transaction()
                {
                    ctype = COMMREQ_Type.RD0x02,
                    asyncDelegate = asyncDelegate,
                    asyncContext = asyncContext
                });
        }
        public void SyncRun_Stop(CallBackHandler asyncDelegate, object asyncContext)
        {
            //放入 交易队列
            Transactions.Add(
                new COMMREQ_Transaction()
                {
                    ctype = COMMREQ_Type.RD0x03,
                    asyncDelegate = asyncDelegate,
                    asyncContext = asyncContext
                });
        }
        public void SyncRun_Clear(CallBackHandler asyncDelegate, object asyncContext)
        {
            //放入 交易队列
            Transactions.Add(
                new COMMREQ_Transaction()
                {
                    ctype = COMMREQ_Type.RD0x04,
                    asyncDelegate = asyncDelegate,
                    asyncContext = asyncContext
                });
        }

        /// <summary>
        /// 同步扫描至;
        /// D+0xE0+开始主轴位置+结束主轴位置+结束横向脉冲位置（逻辑位置）+命令识标号（4B）
        /// </summary>
        /// <param name="pos2_begin"></param>
        /// <param name="pos2_end"></param>
        /// <param name="pos1lc"></param>
        /// <param name="serial"></param>
        public void SyncRun_RunAtLC(int pos2_begin, int pos2_end, int pos1lc, UInt32 serial, CallBackHandler asyncDelegate, object asyncContext) 
        {
            List<byte> datas = new List<byte>();
            datas.AddRange(BitConverter.GetBytes(pos2_begin));
            datas.AddRange(BitConverter.GetBytes(pos2_end));
            datas.AddRange(BitConverter.GetBytes(pos1lc));
            datas.AddRange(BitConverter.GetBytes(serial));


            //放入 交易队列
            Transactions.Add(
                new COMMREQ_Transaction()
                {
                    ctype = COMMREQ_Type.RD0xE0,
                    asyncDelegate = asyncDelegate,
                    asyncContext = asyncContext,
                    datas = datas.ToArray()
                });
        }

        /// <summary>
        /// 位于队列头时运行，归零；
        /// D+0xE1+命令识标号（4B）
        /// </summary>
        /// <param name="marker"></param>
        public void SyncRun_Origin(UInt32 serial, CallBackHandler asyncDelegate, object asyncContext)
        {
            //放入 交易队列
            Transactions.Add(
                new COMMREQ_Transaction()
                {
                    ctype = COMMREQ_Type.RD0xE1,
                    asyncDelegate = asyncDelegate,
                    asyncContext = asyncContext,
                    datas = BitConverter.GetBytes(serial)
                });
        }


        /// <summary>
        /// 位于队列头时运行，以速度运行至物理位置；
        /// D+0xE2+横向脉冲位置（4B：int32，物理位置）+速度（4B：int32）+命令识标号（4B）
        /// </summary>
        /// <param name="pos1"></param>
        /// <param name="velocity"></param>
        /// <param name="serial"></param>
        public void SyncRun_RunTo(int pos1, UInt32 velocity, UInt32 serial, CallBackHandler asyncDelegate, object asyncContext)
        {
            List<byte> datas = new List<byte>();
            datas.AddRange(BitConverter.GetBytes(pos1));
            datas.AddRange(BitConverter.GetBytes(velocity));
            datas.AddRange(BitConverter.GetBytes(serial));


            //放入 交易队列
            Transactions.Add(
                new COMMREQ_Transaction()
                {
                    ctype = COMMREQ_Type.RD0xE2,
                    asyncDelegate = asyncDelegate,
                    asyncContext = asyncContext,
                    datas = datas.ToArray()
                });
        }


        /// <summary>
        /// 位于队列头时运行，以速度运行至逻辑位置；
        /// D+0xE3+横向脉冲位置（4B：int32，逻辑位置）+速度（4B：int32）+命令识标号（4B）
        /// </summary>
        /// <param name="pos1lc"></param>
        /// <param name="velocity"></param>
        /// <param name="hasDataGrid"></param>
        /// <param name="marker"></param>
        public void SyncRun_RunToLC(int pos1lc, UInt32 velocity, UInt32 serial, CallBackHandler asyncDelegate, object asyncContext)
        {
            List<byte> datas = new List<byte>();
            datas.AddRange(BitConverter.GetBytes(pos1lc));
            datas.AddRange(BitConverter.GetBytes(velocity));
            datas.AddRange(BitConverter.GetBytes(serial));


            //放入 交易队列
            Transactions.Add(
                new COMMREQ_Transaction()
                {
                    ctype = COMMREQ_Type.RD0xE3,
                    asyncDelegate = asyncDelegate,
                    asyncContext = asyncContext,
                    datas = datas.ToArray()
                });
        }

        /// <summary>
        /// 获取队列长度
        /// </summary>
        /// <param name="asyncDelegate"></param>
        /// <param name="asyncContext"></param>
        public void SyncRun_GetListCount(CallBackHandler asyncDelegate, object asyncContext) 
        {
            //放入 交易队列
            Transactions.Add(
                new COMMREQ_Transaction()
                {
                    ctype = COMMREQ_Type.RGD,
                    asyncDelegate = asyncDelegate,
                    asyncContext = asyncContext
                });
        }

        #endregion
    }



    /// <summary>
    /// 通知指令
    /// </summary>
    class COMMREQ
    {
        public COMMREQ_Type CType;
        /// <summary>
        /// 指令 前缀
        /// </summary>
        public byte[] Prefix;
        public string PrefixString
        {
            get {
                StringBuilder stringBuilder = new StringBuilder();
                for (int i = 0; i < Prefix.Count(); i++) {
                    stringBuilder.Append((char)Prefix[i]);
                }
                return stringBuilder.ToString();
            }
        }

        /// <summary>
        /// 回复数据 总长度，含前序
        /// </summary>
        public int ReponseLen;

        public delegate object ParseFuncPackHandler(byte[] pack, int dataIdx);

        public ParseFuncPackHandler ParseFuncPack;

        public COMMREQ(COMMREQ_Type ctype)
        {
            CType = ctype;
            string prefixString = CType.ToString();
            
            Prefix = new byte[prefixString.Count()];
            this.Prefix = prefixString.Select(p => (byte)p).ToArray();

            this.ReponseLen = Prefix.Length;
        }

        public COMMREQ(COMMREQ_Type ctype, int reponseLen)
        {
            CType = ctype;
            string prefixString = CType.ToString();

            Prefix = new byte[prefixString.Count()];
            this.Prefix = prefixString.Select(p => (byte)p).ToArray();

            this.ReponseLen = reponseLen;
        }

        public COMMREQ(COMMREQ_Type ctype, int dataLen, ParseFuncPackHandler parseFuncPack)
        {
            CType = ctype;
            string prefixString = CType.ToString();

            Prefix = new byte[prefixString.Count()];
            this.Prefix = prefixString.Select(p => (byte)p).ToArray();
            this.ParseFuncPack = parseFuncPack;

            this.ReponseLen = Prefix.Count() + dataLen;
        }

        public COMMREQ(COMMREQ_Type ctype, string prefix, int reponseLen, ParseFuncPackHandler parseFuncPack)
        {
            CType = ctype;
            Prefix = new byte[prefix.Count()];
            this.Prefix = prefix.Select(p => (byte)p).ToArray();
            this.ParseFuncPack = parseFuncPack;

            this.ReponseLen = reponseLen;
        }

        public COMMREQ(COMMREQ_Type ctype, byte[] prefixs, int reponseLen, ParseFuncPackHandler parseFuncPack)
        {
            CType = ctype;
            this.Prefix = prefixs;
            this.ParseFuncPack = parseFuncPack;
            this.ReponseLen = reponseLen;
        }

        public COMMREQ(COMMREQ_Type ctype, byte[] prefixs)
        {
            CType = ctype;
            this.Prefix = prefixs;
            this.ReponseLen = prefixs.Length;
        }
    }

    enum COMMREQ_Type 
    {
        #region IOComm IO指令
        IGI,
        IGO,
        IGP0,
        IGP1,
        IGPA,
        ISO,
        #endregion

        #region RunComm 运行指令 SetRunParam
        RPV,
        RPS,
        RPU,
        RPD,
        RP1,
        RP2,
        #endregion

        #region RunComm 运行指令 GetRunParam
        RpV,
        RpS,
        RpU,
        RpD,
        Rp1,
        Rp2,
        #endregion

        #region RunComm 运行指令
        RF,
        RB,
        RO,
        RRP,
        RS,
        RT,
        RN,
        #endregion


        #region D,同步运行指令
        RD0x80,
        RD0x81,
        RD0x02,
        RD0x03,
        RD0x04,
        RD0xE0,
        RD0xE1,
        RD0xE2,
        RD0xE3,
        RGD,
        #endregion

        #region SysParamComm 系统参数指令
        
        
        #endregion

        #region GetSysParam 读运行参数
        SpM,
        Spm,
        SpE,
        SpZ,
        SpJ,
        #endregion

        #region SetSysParam 设置运行参数
        SPM,
        SPm,
        SPE,
        SPZ,
        SPJ,
        #endregion


    }
    class COMMREQ_Transaction 
    {
        /// <summary>
        /// 请求的前缀
        /// </summary>
        public COMMREQ_Type ctype;
        
        /// <summary>
        /// 回复 callback
        /// </summary>
        public CallBackHandler asyncDelegate;
        
        /// <summary>
        /// 上下文
        /// </summary>
        public object asyncContext;

        /// <summary>
        /// 数据
        /// </summary>
        public byte[] datas;
    }

}
