using FlyAd2021.Inc;
using FlyADBase;
using NLog;
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 FlyAd2021Core : IFlyAd2021Core
    {
        Logger logger = NLog.LogManager.GetCurrentClassLogger();

        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 SendMsgEventHander SendMsgEvent;

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

        /// <summary>
        /// 运行状态推送事件
        /// </summary>
        public event PushRunResultEventHandler PushRunResultEvent;

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



        /// <summary>
        /// 全部指令类别
        /// </summary>
        Dictionary<COMMREQ_Type,COMMREQ> COMMREQs;
        /// <summary>
        /// 指令队列，必须等上1条指令回复了，才能发下条指令
        /// </summary>
        List<COMMREQ_Transaction> Transactions;


        /// <summary>
        /// 当前正在等待回复的指令
        /// </summary>
        COMMREQ_Transaction currTran;
        /// <summary>
        /// currTran 发送后，开始计时
        /// </summary>
        Stopwatch stopwatch_timeOut;
        /// <summary>
        /// currTran 重发次数
        /// </summary>
        int retryCnt = 0;

        COMMREQ COMMREQ_RN;
        public FlyAd2021Core()
        {
            //COMMREQ_RN 作为事件，会触发一次，作为指令，也会回复一次
            COMMREQ_RN = new COMMREQ(COMMREQ_Type.RN, 5, (pack, dataIdx) =>
            {
                DRIVE_MAN_STATUS result = (DRIVE_MAN_STATUS)pack[dataIdx];
                dataIdx += 1;
                UInt32 serial = BitConverter.ToUInt32(pack, dataIdx);
                dataIdx += 4;

                return new GetRunResult_Reponse()
                {
                    result = result,
                    serial = serial
                };
            });

            var _COMMREQs = new List<COMMREQ>
            {
                COMMREQ_RN,

                #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.RR),
                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

                #region SysParamComm 系统参数指令
                new COMMREQ(COMMREQ_Type.ST,4,(pack,dataIdx)=>BitConverter.ToInt32(pack, dataIdx)),
                new COMMREQ(COMMREQ_Type.SI0,1,(pack,dataIdx)=> pack[dataIdx] == (byte)'O'),
                new COMMREQ(COMMREQ_Type.SA,2,(pack,dataIdx)=>{
                    short ret = BitConverter.ToInt16(pack, dataIdx);
                    if(ret == 0)
                        return AREA_ERR.NO_ERR;
                    else if(ret == -105)
                        return AREA_ERR.DUP_ACCESS;
                    else// if(ret == -101)
                        return AREA_ERR.ERR_ACCESS;
                }),
                new COMMREQ(COMMREQ_Type.Sa,18,(pack,dataIdx)=>{
                    GetAccess_Reponse reponse = new GetAccess_Reponse();
                    int idx = dataIdx;
                    reponse.status = (AREA_STATUS)pack[idx];
                    idx++;
                    reponse.ret = (AREA_ERR)pack[idx];
                    idx++;

                    Array.Copy(pack, idx, reponse.code, 0, 6);
                    idx += 6;
                    reponse.surplus = BitConverter.ToUInt16(pack, idx);
                    idx += 2;
                    Array.Copy(pack, idx, reponse.access, 0, 8);
                    idx += 8;
                    return reponse;
                }),
                new COMMREQ(COMMREQ_Type.S1),
                #endregion

                #region GetSysParam 读运行参数
                new COMMREQ(COMMREQ_Type.SpM,1,(pack,dataIdx)=>{
                    byte motorType = pack[dataIdx];
                    motorType &= 3;
                    return (MOTORTYPE)motorType;
                }),

                new COMMREQ(COMMREQ_Type.Spm,2,(pack,dataIdx)=>BitConverter.ToUInt16(pack, dataIdx)),
                new COMMREQ(COMMREQ_Type.SpE,2,(pack,dataIdx)=>BitConverter.ToUInt16(pack, dataIdx)),
                new COMMREQ(COMMREQ_Type.SpZ,2,(pack,dataIdx)=>BitConverter.ToInt16(pack, dataIdx)),
                new COMMREQ(COMMREQ_Type.SpJ,4,(pack,dataIdx)=>BitConverter.ToUInt32(pack, dataIdx)),
                #endregion

                #region SetSysParam 读运行参数
                new COMMREQ(COMMREQ_Type.SPM),
                new COMMREQ(COMMREQ_Type.SPm),
                new COMMREQ(COMMREQ_Type.SPE),
                new COMMREQ(COMMREQ_Type.SPZ),
                new COMMREQ(COMMREQ_Type.SPJ),
                #endregion
            };

            COMMREQs = new Dictionary<COMMREQ_Type, COMMREQ>();
            foreach (var commreq in _COMMREQs) {
                COMMREQs.Add(commreq.CType, commreq);
            }

            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>
        public void OnPoll_TimeOut()
        {
            //TODO 要处理  TimeOut / ParseFuncPack / GetSendMsg 线性同步问题
            if (!IsConnected)
                return;

            if (currTran == null)
                return;//没有指令

            if (!stopwatch_timeOut.IsRunning)
                return;//还没开始发送

            if (stopwatch_timeOut.Elapsed < TimeSpan.FromSeconds(1))
                return;//发送到现在，还没到1秒，继续等

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

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

                //清空 指令队列
                Transactions.Clear();
                return;
            }
            else {
                //再发一次指令
                SendMsgEvent?.Invoke(this);
            }
        }

        public void RecMsg(byte[] recBuf)
        {
            IsConnected = true;
            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()
        {
            //TODO 要处理  TimeOut / ParseFuncPack / GetSendMsg 线性同步问题

            if (currTran == null)
            {
                //当前没有指令正在发送

                if (Transactions.Count() == 0)//队列没有需要发送的指令
                    return null;


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

            //找出 COMMREQ
            var commReq = COMMREQs[currTran.ctype];
            List<byte> pack = new List<byte>();
            pack.AddRange(commReq.Prefix);
            if (currTran.datas != null)
                pack.AddRange(currTran.datas);
            if(currTran.datasObj==null)
                logger.Debug($"REQ {commReq.CType}");
            else
                logger.Debug($"REQ {commReq.CType} {Newtonsoft.Json.JsonConvert.SerializeObject(currTran.datasObj)}");

            //获取需要发送出去的数据
            var buf = GetSendPack(pack).ToArray();

            //开始计时
            stopwatch_timeOut.Restart();

            return buf;
        }

        /// <summary>
        /// 复位全部状态，通常由于通讯模块检测到连接断开导致的
        /// </summary>
        public void ResetMsg()
        {
            currTran = null;
            stopwatch_timeOut.Stop();
            recCnt = 0;
            IsConnected = false;
            Transactions.Clear();
        }

        /// 包解析
        /// </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();

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

            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)
            {
                ReponseLen += 2;
                if (ReponseLen > pack.Count())
                {
                    //失败，指令长度不对！！
                    ErrCnt++;
                    return;
                }

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

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

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

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


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

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

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

            PushDataEvent?.Invoke(this, eventArgs);
        }
        void ParseFuncPack_PushRunResultEvent(byte[] pack) {

            PushRunResultEventArgs eventArgs = new PushRunResultEventArgs();

            var retData = COMMREQ_RN.ParseFuncPack(pack, 1 + COMMREQ_RN.Prefix.Count()) as GetRunResult_Reponse;
            eventArgs.Status = retData.result;
            eventArgs.Serial = retData.serial;

            logger.Debug($"REQ RN {Newtonsoft.Json.JsonConvert.SerializeObject(retData)}");

            byte systick = pack[0];
            Misc.MyBase.CLEARBIT(ref systick, 7);
            eventArgs.SysTick = systick;
            PushRunResultEvent?.Invoke(this, eventArgs);
        }
        /// <summary>
        /// 功能包解析
        /// </summary>
        /// <param name="datas"></param>
        void ParseFuncPack(byte[] pack)
        {
            //TODO 要处理  TimeOut / ParseFuncPack / GetSendMsg 线性同步问题

            //优先处理 PushRunResultEvent 事件
            if (IsMatch(COMMREQ_RN, pack))
            {
                //还有B0
                if (COMMREQ_RN.ReponseLen+1 > pack.Count())
                {
                    //失败，指令长度不对！！
                    ErrCnt++;
                    return;
                }

                

                ParseFuncPack_PushRunResultEvent(pack);
            }

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

            var commReq = COMMREQs[currTran.ctype];
            if (!IsMatch(commReq, pack))
            {
                logger.Error($"ACK expect:{commReq.CType} ,but reponse: {Newtonsoft.Json.JsonConvert.SerializeObject(pack)}");
                //回复对不上请求
                return;
            }

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

            //处理指令
            //还有B0
            object retData = null;
            if (commReq.ParseFuncPack != null)//解析回复数据
                retData = commReq.ParseFuncPack(pack, commReq.Prefix.Count() + 1);
            if (retData == null)
                logger.Debug($"ACK {commReq.CType}");
            else
                logger.Debug($"ACK {commReq.CType} {Newtonsoft.Json.JsonConvert.SerializeObject(retData)}");

            //有很多指令是没有回复数据的， 回调只是通知 指令已经执行了而已
            //调用回调
            currTran.asyncDelegate?.Invoke(currTran.asyncContext, retData);

            stopwatch_timeOut.Stop();
            currTran = null;
            if (Transactions.Count() > 0)
            {
                //队列还有需要发送的指令
                SendMsgEvent?.Invoke(this);
            }

        }

        bool IsMatch(COMMREQ commreq, byte[] datas)
        {
            //datas[0] 是B0, 不应该用于判断
            if (datas.Count() < commreq.Prefix.Length+1)
                return false;

            for (int i = 0; i < commreq.Prefix.Length; i++)
            {
                if (commreq.Prefix[i] != datas[1+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;
        }
        void AddTran(COMMREQ_Transaction tran)
        {
            //放入 交易队列
            Transactions.Add(tran);
            if (currTran == null)
            {
                //当前没有指令正在发送
                SendMsgEvent?.Invoke(this);
            }
        }

        #region IOComm IO指令
        /// <summary>
        /// 获取输入口状态
        /// </summary>
        /// <param name="asyncDelegate"></param>
        /// <param name="asyncContext"></param>
        [CallBack(typeof(UInt16))]
        public void GetIn(CallBackHandler asyncDelegate, object asyncContext)
        {
            //放入 交易队列
            AddTran(
                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)
        {
            //放入 交易队列
            AddTran(
            new COMMREQ_Transaction()
            {
                ctype = COMMREQ_Type.IGO,
                asyncDelegate = asyncDelegate,
                asyncContext = asyncContext
            });
        }

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

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

        [CallBack(typeof(GetEncAll_Reponse))]
        public void GetEncAll(CallBackHandler asyncDelegate, object asyncContext)
        {
            //放入 交易队列
            AddTran(
                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));

            //放入 交易队列
            AddTran(
                new COMMREQ_Transaction()
                {
                    ctype = COMMREQ_Type.ISO,
                    asyncDelegate = asyncDelegate,
                    asyncContext = asyncContext,
                    datas = datas.ToArray(),
                    datasObj = new { mask, value }
                });

        }
        #endregion

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

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

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

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

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

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

        #endregion

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

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

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

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

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

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

        #endregion


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

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

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

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

            //放入 交易队列
            AddTran(
                new COMMREQ_Transaction()
                {
                    ctype = COMMREQ_Type.RR,
                    asyncDelegate = asyncDelegate,
                    asyncContext = asyncContext,
                    datas = datas.ToArray(),
                    datasObj = new { targetPos, serial }
                });
        }
        public void Stop(CallBackHandler asyncDelegate, object asyncContext)
        {

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

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

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

        public void SyncRun_Start(CallBackHandler asyncDelegate, object asyncContext)
        {
            //放入 交易队列
            AddTran(
                new COMMREQ_Transaction()
                {
                    ctype = COMMREQ_Type.RD0x02,
                    asyncDelegate = asyncDelegate,
                    asyncContext = asyncContext
                });
        }
        public void SyncRun_Stop(CallBackHandler asyncDelegate, object asyncContext)
        {
            //放入 交易队列
            AddTran(
                new COMMREQ_Transaction()
                {
                    ctype = COMMREQ_Type.RD0x03,
                    asyncDelegate = asyncDelegate,
                    asyncContext = asyncContext
                });
        }
        public void SyncRun_Clear(CallBackHandler asyncDelegate, object asyncContext)
        {
            //放入 交易队列
            AddTran(
                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));


            //放入 交易队列
            AddTran(
                new COMMREQ_Transaction()
                {
                    ctype = COMMREQ_Type.RD0xE0,
                    asyncDelegate = asyncDelegate,
                    asyncContext = asyncContext,
                    datas = datas.ToArray(),
                    datasObj = new { pos2_begin, pos2_end, pos1lc, serial }
                });
        }

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


            //放入 交易队列
            AddTran(
                new COMMREQ_Transaction()
                {
                    ctype = COMMREQ_Type.RD0xE2,
                    asyncDelegate = asyncDelegate,
                    asyncContext = asyncContext,
                    datas = datas.ToArray(),
                    datasObj = new { pos1, velocity, serial }
                });
        }


        /// <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));


            //放入 交易队列
            AddTran(
                new COMMREQ_Transaction()
                {
                    ctype = COMMREQ_Type.RD0xE3,
                    asyncDelegate = asyncDelegate,
                    asyncContext = asyncContext,
                    datas = datas.ToArray(),
                    datasObj = new { pos1lc, velocity, serial }
                });
        }

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

        #endregion

        #region SysParamComm 系统参数指令
        /// <summary>
        /// 获取系统当前Tick
        /// </summary>
        [CallBack(typeof(UInt32))]
        public void GetSysTick(CallBackHandler asyncDelegate, object asyncContext)
        {
            //放入 交易队列
            AddTran(
                new COMMREQ_Transaction()
                {
                    ctype = COMMREQ_Type.ST,
                    asyncDelegate = asyncDelegate,
                    asyncContext = asyncContext
                });
        }

        /// <summary>
        /// 初始化系统信息区
        /// </summary>
        /// <param name="asyncDelegate"></param>
        /// <param name="asyncContext"></param>
        [CallBack(typeof(bool))]
        public void InitArea(CallBackHandler asyncDelegate, object asyncContext)
        {
            string password = "@flymeasure!";
            List<byte> datas = new List<byte>();
            datas.AddRange(password.Select(p => (byte)p));

            //放入 交易队列
            AddTran(
                new COMMREQ_Transaction()
                {
                    ctype = COMMREQ_Type.SI0,
                    asyncDelegate = asyncDelegate,
                    asyncContext = asyncContext,
                    datas = datas.ToArray(),
                    datasObj = new { password }
                });
        }

        /// <summary>
        /// 输入系统授权码
        /// </summary>
        /// <param name="access"></param>
        /// <param name="asyncDelegate"></param>
        /// <param name="asyncContext"></param>
        [CallBack(typeof(AREA_ERR))]
        public void CheckAccessCode(byte[] access, CallBackHandler asyncDelegate, object asyncContext)
        {
            //放入 交易队列
            AddTran(
                new COMMREQ_Transaction()
                {
                    ctype = COMMREQ_Type.SA,
                    asyncDelegate = asyncDelegate,
                    asyncContext = asyncContext,
                    datas = access,
                    datasObj = access
                });
        }

        /// <summary>
        /// 获取系统授权信息
        /// </summary>
        /// <param name="asyncDelegate"></param>
        /// <param name="asyncContext"></param>
        [CallBack(typeof(GetAccess_Reponse))]
        public void GetAccess(CallBackHandler asyncDelegate, object asyncContext)
        {
            //放入 交易队列
            AddTran(
                new COMMREQ_Transaction()
                {
                    ctype = COMMREQ_Type.Sa,
                    asyncDelegate = asyncDelegate,
                    asyncContext = asyncContext
                });
        }


        /// <summary>
        /// 系统运行时间+1
        /// </summary>
        /// <param name="asyncDelegate"></param>
        /// <param name="asyncContext"></param>
        public void AddAccess(CallBackHandler asyncDelegate, object asyncContext) 
        {
            //放入 交易队列
            AddTran(
                new COMMREQ_Transaction()
                {
                    ctype = COMMREQ_Type.S1,
                    asyncDelegate = asyncDelegate,
                    asyncContext = asyncContext
                });
        }
        #endregion

        #region GetSysParam 读运行参数
        [CallBack(typeof(MOTORTYPE))]
        public void GetSysParam_MotorType(CallBackHandler asyncDelegate, object asyncContext)
        {
            //放入 交易队列
            AddTran(
                new COMMREQ_Transaction()
                {
                    ctype = COMMREQ_Type.SpM,
                    asyncDelegate = asyncDelegate,
                    asyncContext = asyncContext
                });
        }

        [CallBack(typeof(UInt16))]
        public void GetSysParam_Ratio01(CallBackHandler asyncDelegate, object asyncContext)
        {
            //放入 交易队列
            AddTran(
                new COMMREQ_Transaction()
                {
                    ctype = COMMREQ_Type.Spm,
                    asyncDelegate = asyncDelegate,
                    asyncContext = asyncContext
                });
        }

        [CallBack(typeof(UInt16))]
        public void GetSysParam_Ratio02(CallBackHandler asyncDelegate, object asyncContext)
        {
            //放入 交易队列
            AddTran(
                new COMMREQ_Transaction()
                {
                    ctype = COMMREQ_Type.SpE,
                    asyncDelegate = asyncDelegate,
                    asyncContext = asyncContext
                });
        }

        [CallBack(typeof(Int16))]
        public void GetSysParam_Zero(CallBackHandler asyncDelegate, object asyncContext)
        {
            //放入 交易队列
            AddTran(
                new COMMREQ_Transaction()
                {
                    ctype = COMMREQ_Type.SpZ,
                    asyncDelegate = asyncDelegate,
                    asyncContext = asyncContext
                });
        }

        [CallBack(typeof(UInt32))]
        public void GetSysParam_Jog(CallBackHandler asyncDelegate, object asyncContext)
        {
            //放入 交易队列
            AddTran(
                new COMMREQ_Transaction()
                {
                    ctype = COMMREQ_Type.SpJ,
                    asyncDelegate = asyncDelegate,
                    asyncContext = asyncContext
                });
        }
        #endregion

        #region SetSysParam 设置运行参数
        public void SetSysParam_MotorType(MOTORTYPE motorType, CallBackHandler asyncDelegate, object asyncContext)
        {
            byte request = (byte)motorType;
            Misc.MyBase.SIGNBIT(ref request, 5);

            //放入 交易队列
            AddTran(
                new COMMREQ_Transaction()
                {
                    ctype = COMMREQ_Type.SPM,
                    asyncDelegate = asyncDelegate,
                    asyncContext = asyncContext,
                    datas = new byte[] { request },
                    datasObj = motorType
                });
        }


        public void SetSysParam_Ratio01(UInt16 ratio01, CallBackHandler asyncDelegate, object asyncContext)
        {
            //放入 交易队列
            AddTran(
                new COMMREQ_Transaction()
                {
                    ctype = COMMREQ_Type.SPm,
                    asyncDelegate = asyncDelegate,
                    asyncContext = asyncContext,
                    datas = BitConverter.GetBytes(ratio01),
                    datasObj = ratio01
                });
        }

        public void SetSysParam_Ratio02(UInt16 ratio02, CallBackHandler asyncDelegate, object asyncContext)
        {
            //放入 交易队列
            AddTran(
                new COMMREQ_Transaction()
                {
                    ctype = COMMREQ_Type.SPE,
                    asyncDelegate = asyncDelegate,
                    asyncContext = asyncContext,
                    datas = BitConverter.GetBytes(ratio02),
                    datasObj = ratio02
                });
        }

        public void SetSysParam_Zero(Int16 zero, CallBackHandler asyncDelegate, object asyncContext)
        {
            //放入 交易队列
            AddTran(
                new COMMREQ_Transaction()
                {
                    ctype = COMMREQ_Type.SPZ,
                    asyncDelegate = asyncDelegate,
                    asyncContext = asyncContext,
                    datas = BitConverter.GetBytes(zero),
                    datasObj = zero
                });
        }

        public void SetSysParam_Jog(UInt32 jog, CallBackHandler asyncDelegate, object asyncContext)
        {
            //放入 交易队列
            AddTran(
                new COMMREQ_Transaction()
                {
                    ctype = COMMREQ_Type.SPJ,
                    asyncDelegate = asyncDelegate,
                    asyncContext = asyncContext,
                    datas = BitConverter.GetBytes(jog),
                    datasObj = jog
                });
        }
        #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,
        RR,
        RS,
        RT,
        RN,
        #endregion


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

        #region SysParamComm 系统参数指令
        ST,
        SI0,
        SA,
        Sa,
        S1,
        #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;

        /// <summary>
        /// 数据的object 表达，只用于调试而已
        /// </summary>
        public object datasObj;
    }

}
