#define SPEED_BY_MySelf
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.ComponentModel;
using FObjBase;
using System.IO;
using Misc;
using System.Collections.ObjectModel;


namespace FlyADBase
{
    /// <summary>
    /// 执行顺序
    /// 1. IFlyAD flyad = new FlyAD7();//加载速度参数，IP地址
    /// 2. flyad.Connect();//flyad.Connect("192.168.251.10:20006");
    /// 3. 当连接上，会设置推送，获取flyad7控制器里面所有数据，设置速度参数到控制器
    /// </summary>
    public class FlyAD7 : FObj, IFlyADClient
    {
        #region MARKNO
        public const int MARKNO_SET_VELOCITY = 1;
        public const int MARKNO_SET_ZEROPOS = 2;
        public const int MARKNO_SET_SYSPARAM = 3;
        #endregion
        #region 成员变量
        /// <summary>
        /// 不设置服务器
        /// </summary>
        private bool bShieldSetValueEx = false;
        private DateTime dt_surplus = DateTime.MinValue;

        class DtAndBool
        {
            public bool bNeedGet;
            public DateTime dt;
            public void Clear()
            {
                bNeedGet = true;
                dt = DateTime.Now;
            }
        }

        DtAndBool driveman_wait = new DtAndBool();
        DtAndBool pos_wait = new DtAndBool();
        DtAndBool sysinfo_wait = new DtAndBool();

        class SGrid
        {
            const int GRID_MAX_SIZE = 1000;
            int size;
            public int[][] data = new int[2][];//data[0]=forword, data[1]=backward
            public SGrid()
            {
                //清空所有数据
                SetSize(GRID_MAX_SIZE);
            }
            public void SetSize(int size)
            {
                this.size = size;
                data[0] = new int[size];
                data[1] = new int[size];
                Clear();
            }
            public void Clear()
            {
                //清空所有数据
                for (int i = 0; i < size; i++)
                {
                    data[0][i] = Misc.MyBase.NULL_VALUE;
                    data[1][i] = Misc.MyBase.NULL_VALUE;
                }
            }
        }
        SGrid fGrid = new SGrid();

        TCPCConn conn = null;

        #endregion

        #region IFlyADClient
        bool hascrc = false;
        public bool HasCRC
        {
            get
            {
                return hascrc;
            }
            set
            {
                if (hascrc != value)
                {
                    hascrc = value;
                    NotifyPropertyChanged("HasCRC");
                }
            }
        }
        private int gridsmooth = 0;
        /// <summary>
        /// grid数据平滑
        /// </summary>
        public int GridSmooth 
        {
            get { return gridsmooth; }
            set {
                if (value < 0)
                    value = 0;
                if (gridsmooth != value) 
                {
                    gridsmooth = value;
                    NotifyPropertyChanged("GridSmooth");
                }
            }
        }
        private int inbuflen = 0;
        public int InBufLen  //1秒刷新一次
        {
            get {
                return inbuflen;
            }
            protected set {
                if (inbuflen != value) 
                {
                    inbuflen = value;
                    NotifyPropertyChanged("InBufLen");
                }
            }
        }
        #endregion

        int noTGridCnt = 0;//没有收到timegrid的次数， 1秒加1次
        const int ReConnectTGridMaxCnt = 3;//3次收不到timegrid, 重连
        const double SpeedScale = 1000.0 / 620;
        public FlyAD7()
        {
            Now = DateTime.Now;
            Position = 0;
            Speed = 0;
            Position2 = 0;
            Speed2 = 0;
            AD = 0;
            IStatus = 0xffff;
            OStatus = 0xffff;
            MotorType = MOTORTYPE.VF0;
            PosOffset = 0;
            JogVelocity = 5000;
            PosOfGrid = 10;
            PosLen = 8900;
            Ratio01 = 4;
            Ratio02 = 1;
            Velocity = 8000;
            SVelocity = 200;
            ATime = 300;
            DTime = 300;
            HVelocity1 = 4000;
            HVelocity2 = 500;
            Marker = 0;

            Pos2Comp = 1;
            Pos1LCShift = 0;
            IsSync = false;

            fGrid.SetSize(PosLen / PosOfGrid);

            this.PropertyChanged += new PropertyChangedEventHandler(FlyAD7_PropertyChanged);
            PollModule.Current.Poll_Config(PollModule.POLL_CONFIG.ADD, new PollModule.PollHandler(OnPoll));

            //3秒内收不到1个timegrid ，就会重连
            PollModule.Current.Poll_Config(PollModule.POLL_CONFIG.ADD,
                () =>
                {
                    if (!IsConnected)
                    {
                        noTGridCnt = 0;
                    }
                    else
                    {
                        noTGridCnt++;
                        if (noTGridCnt >= ReConnectTGridMaxCnt)
                        {
                            noTGridCnt = 0;
                            ReConnect();
                        }
                    }

                }, TimeSpan.FromSeconds(1));

#if SPEED_BY_MySelf
            //更新线速度
            PollModule.Current.Poll_Config(PollModule.POLL_CONFIG.ADD,
                () =>
                {
                    if (pos1_last_for_speed != int.MinValue)
                    {
                        Speed = Position - pos1_last_for_speed;
                    }
                    pos1_last_for_speed = Position;


                    if (pos2_last_for_speed != int.MinValue)
                    { 
                        Speed2 = Position2 - pos2_last_for_speed;
                    }
                    pos2_last_for_speed = Position2;
                }, TimeSpan.FromSeconds(1));
#endif


            mCreateGridAdv.Init(this);
        }

        int pos1_last_for_speed = int.MinValue;
        int pos2_last_for_speed = int.MinValue;


        void FlyAD7_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == "HasCRC")
            {
                if (conn != null)
                    conn.HasCRC = HasCRC;
            }
            else if (e.PropertyName == "DriveStatus")
            {
                switch (DriveStatus)
                {
                    case DRIVE_MAN_STATUS.STOP_MANUAL:
                    case DRIVE_MAN_STATUS.STOP:
                    case DRIVE_MAN_STATUS.LIMIT:
                        IsFinish = true;
                        break;
                    case DRIVE_MAN_STATUS.RUNNING:
                        IsFinish = false;
                        break;
                }
            }
            else if ((e.PropertyName == "PosLen") ||
                (e.PropertyName == "PosOfGrid"))
            {
                fGrid.SetSize(PosLen / PosOfGrid);
            }
            else if (e.PropertyName == "Marker")
            {
                //if (DriveOrder == DRIVE_MAN_ORDER.SYNC)
                {
                    //同步运行中
                    //检测与哪个指令一致, 
                    //该指令置为 Doing， 前面的全部置为 Finish，并且删除
                    for (int i = 0; i < SyncOrders.Count(); i++)
                    {
                        if (SyncOrders[i].Marker == Marker)
                        {
                            SyncOrders[i].State = SyncOrderState.Doing;

                            for (int j = 0; j < i; j++)
                            {
                                SyncOrders[0].State = SyncOrderState.Finish;
                                SyncOrders.RemoveAt(0);
                            }
                        }
                    }
                }
            }
            if (bShieldSetValueEx)
                return;

            if ((e.PropertyName == "Velocity") ||
                (e.PropertyName == "SVelocity") ||
                (e.PropertyName == "ATime") ||
                (e.PropertyName == "DTime") ||
                (e.PropertyName == "HVelocity1") ||
                (e.PropertyName == "HVelocity2"))
            {
                FObjBase.PollModule.Current.Poll_JustOnce(
                    delegate()
                    {
                        //TODO,不应该直接修改Velocity，SVelocity。。。。。。
                        //所以下面也不可能存在！！！
                        SetPosParam(Velocity, SVelocity, ATime, DTime, HVelocity1, HVelocity2);
                    }, this, MARKNO_SET_VELOCITY);
            }
            else if ((e.PropertyName == "PosOffset") ||
                (e.PropertyName == "JogVelocity"))
            {
                FObjBase.PollModule.Current.Poll_JustOnce(
                    delegate()
                    {
                        CurrObjSys.SetValueEx(conn, FLYAD7_OBJ_INTERFACE.SYS_DATA_INTERFACE.ID,
                            ID, FLYAD7_OBJ_INTERFACE.SYS_DATA_INTERFACE.SET_ZERO_POS,
                            new FLYAD7_OBJ_INTERFACE.SYS_DATA_INTERFACE.Pack_ZeroPos()
                            {
                                zero_pos = PosOffset,
                                jog_velocity = JogVelocity
                            }.ToBytes());
                    }, this, MARKNO_SET_ZEROPOS);
            }
            else if ((e.PropertyName == "MotorType") ||
                    (e.PropertyName == "PosOfGrid") ||
                    (e.PropertyName == "Ratio01") ||
                    (e.PropertyName == "Ratio02"))
            {
                FObjBase.PollModule.Current.Poll_JustOnce(
                    delegate()
                    {
                        SetSysParam(PosOfGrid, MotorType, Ratio01, Ratio02);
                    }, this, MARKNO_SET_SYSPARAM);
            }
            else if (e.PropertyName == "Pos1LCShift")
            {
                
                CurrObjSys.CallFunctionEx(
                   conn,
                   FLYAD7_OBJ_INTERFACE.DRIVE_MAN_INTERFACE.ID,
                   ID,
                   FLYAD7_OBJ_INTERFACE.DRIVE_MAN_INTERFACE.CALL_PXX,
                   new FLYAD7_OBJ_INTERFACE.DRIVE_MAN_INTERFACE.Pack_Pos1LCShift()
                   {
                       pos1_LCShift = Pos1LCShift
                   }.ToBytes());
            }
            else if (e.PropertyName == "Position2")
            {
                CurrObjSys.CallFunctionEx(
                    conn,
                    FLYAD7_OBJ_INTERFACE.DRIVE_MAN_INTERFACE.ID,
                    ID,
                    FLYAD7_OBJ_INTERFACE.DRIVE_MAN_INTERFACE.CALL_PXX,
                    new FLYAD7_OBJ_INTERFACE.DRIVE_MAN_INTERFACE.Pack_Pos2()
                    {
                        pos2 = Position2
                    }.ToBytes());
            }
            else if (e.PropertyName == "Pos2Comp")
            {
                CurrObjSys.CallFunctionEx(
                    conn,
                    FLYAD7_OBJ_INTERFACE.DRIVE_MAN_INTERFACE.ID,
                    ID,
                    FLYAD7_OBJ_INTERFACE.DRIVE_MAN_INTERFACE.CALL_PXX,
                    new FLYAD7_OBJ_INTERFACE.DRIVE_MAN_INTERFACE.Pack_Pos2Comp()
                    {
                        comp = Pos2Comp
                    }.ToBytes());
            }

        }
        #region IFlyADClient
        public void Connect()
        {
            Connect(LocalEP);
        }
        public void Connect(IPEndPoint ep)
        {
            LocalEP = ep;

            if (conn != null)
            {
                if (!conn.RemoteEP.Equals(LocalEP))
                {
                    //断开之前的连接
                    CurrObjSys.Disconnect_to_Another_OBJSys(conn.RemoteEP, ID);
                }
            }

            conn = CurrObjSys.Connect_to_Another_OBJSys(LocalEP, ID);
            conn.HasCRC = HasCRC;
        }
        public void ReConnect()
        {
            if (conn != null)
            {
                //断开之前的连接
                CurrObjSys.Disconnect_to_Another_OBJSys(conn.RemoteEP, ID);
            }

            conn = CurrObjSys.Connect_to_Another_OBJSys(LocalEP, ID);
            conn.HasCRC = HasCRC;
        }
        #endregion

        private void Init()
        {
            CurrObjSys.SenseConfigEx(
                conn,
                FLYAD7_OBJ_INTERFACE.PUSH_DATA_INTERFACE.ID,
                ID,
                Misc.MyBase.BIT(FLYAD7_OBJ_INTERFACE.PUSH_DATA_INTERFACE.PUSH_POS1)
                | Misc.MyBase.BIT(FLYAD7_OBJ_INTERFACE.PUSH_DATA_INTERFACE.PUSH_POS2)
                | Misc.MyBase.BIT(FLYAD7_OBJ_INTERFACE.PUSH_DATA_INTERFACE.PUSH_AD1)
                | Misc.MyBase.BIT(FLYAD7_OBJ_INTERFACE.PUSH_DATA_INTERFACE.PUSH_IO)
                | Misc.MyBase.BIT(FLYAD7_OBJ_INTERFACE.PUSH_DATA_INTERFACE.PUSH_TIMEGRID)
                | Misc.MyBase.BIT(FLYAD7_OBJ_INTERFACE.PUSH_DATA_INTERFACE.PUSH_GRID)
                | Misc.MyBase.BIT(FLYAD7_OBJ_INTERFACE.PUSH_DATA_INTERFACE.PUSH_STATUS)
                | Misc.MyBase.BIT(FLYAD7_OBJ_INTERFACE.PUSH_DATA_INTERFACE.PUSH_MINIGRID)
                ,
                SENSE_CONFIG.ADD);

            UpdateParam();



            //DRIVE_MAN
            CurrObjSys.GetValueEx(
                conn,
                FLYAD7_OBJ_INTERFACE.DRIVE_MAN_INTERFACE.ID,
                ID,
                FLYAD7_OBJ_INTERFACE.DRIVE_MAN_INTERFACE.GET_STATE);

            //FLYADC
            CurrObjSys.GetValueEx(
                conn,
                FLYAD7_OBJ_INTERFACE.FLYADC_OBJ_INTERFACE.ID,
                ID,
                FLYAD7_OBJ_INTERFACE.FLYADC_OBJ_INTERFACE.GET_POS1AD1);

            CurrObjSys.GetValueEx(
                conn,
                FLYAD7_OBJ_INTERFACE.FLYADC_OBJ_INTERFACE.ID,
                ID,
                FLYAD7_OBJ_INTERFACE.FLYADC_OBJ_INTERFACE.GET_POS2);

            //FLYIO
            CurrObjSys.GetValueEx(
                conn,
                FLYAD7_OBJ_INTERFACE.FLYIO_OBJ_INTERFACE.ID,
                ID,
                FLYAD7_OBJ_INTERFACE.FLYIO_OBJ_INTERFACE.GET_IO);

            NotifyPropertyChanged("Pos1LCShift");
            NotifyPropertyChanged("Pos2Comp");

            SyncPos2Clear();
            SyncClear();
            SyncEnd();


            mSysTick.Reset();

            mCreateGridAdv.Clear();
        }

        #region FObj
        public override void ConnectNotify(IFConn from)
        {
            IsConnected = from.IsConnected;
            if (IsConnected)
            {
                ConnectCnt++;
                
                
                Init();
            }
            else
            {
                DriveStatus = DRIVE_MAN_STATUS.STOP;
            }
        }
        public override void PushGetValue(IFConn from, uint srcid, ushort memid, byte[] infodata)
        {
            bShieldSetValueEx = true;
            switch (srcid)
            {
                case FLYAD7_OBJ_INTERFACE.FLYADC_OBJ_INTERFACE.ID:
                    {
                        switch (memid)
                        {
                            case FLYAD7_OBJ_INTERFACE.FLYADC_OBJ_INTERFACE.GET_POS1AD1:
                                {
                                    FLYAD7_OBJ_INTERFACE.FLYADC_OBJ_INTERFACE.Pack_GetPos1AD1 pack = new FLYAD7_OBJ_INTERFACE.FLYADC_OBJ_INTERFACE.Pack_GetPos1AD1();
                                    if (!pack.TryParse(infodata))
                                        break;

                                    Position = pack.pos;
                                    mCreateGridAdv.AddPos_Default(Position, Now);

                                    if (CorrectADs != null)
                                    {
                                        int grid = Position / PosOfGrid;
                                        int[] d = new int[1];
                                        d[0] = pack.ad;
                                        CorrectADs(Misc.DIRECTION.FIX, grid, d);
                                        pack.ad = d[0];
                                    }
                                    AD = pack.ad;
                                } break;
                            case FLYAD7_OBJ_INTERFACE.FLYADC_OBJ_INTERFACE.GET_POS2:
                                {
                                    FLYAD7_OBJ_INTERFACE.FLYADC_OBJ_INTERFACE.Pack_GetPos2 pack = new FLYAD7_OBJ_INTERFACE.FLYADC_OBJ_INTERFACE.Pack_GetPos2();
                                    if (!pack.TryParse(infodata))
                                        break;

                                    Position2 = pack.pos2;
#if !SPEED_BY_MySelf
                                    Speed2 = (int)(pack.speed2 * SpeedScale);
#endif
                                } break;
                        }
                    } break;
                case FLYAD7_OBJ_INTERFACE.FLYIO_OBJ_INTERFACE.ID:
                    {
                        switch (memid)
                        {
                            case FLYAD7_OBJ_INTERFACE.FLYIO_OBJ_INTERFACE.GET_IO:
                                {
                                    FLYAD7_OBJ_INTERFACE.FLYIO_OBJ_INTERFACE.Pack_GetIO pack = new FLYAD7_OBJ_INTERFACE.FLYIO_OBJ_INTERFACE.Pack_GetIO();
                                    if (!pack.TryParse(infodata))
                                        break;

                                    IStatus = pack.istatus;
                                    OStatus = pack.ostatus;
                                    mCreateGridAdv.AddIStatus_Default(IStatus,Position, Now);
                                } break;
                        }
                    } break;
                case FLYAD7_OBJ_INTERFACE.DRIVE_MAN_INTERFACE.ID:
                    {
                        switch (memid)
                        {
                            case FLYAD7_OBJ_INTERFACE.DRIVE_MAN_INTERFACE.GET_DRIVEPARAM:
                                {
                                    FLYAD7_OBJ_INTERFACE.DRIVE_MAN_INTERFACE.Pack_DriveParam pack = new FLYAD7_OBJ_INTERFACE.DRIVE_MAN_INTERFACE.Pack_DriveParam();

                                    if (!pack.TryParse(infodata))
                                        break;
                                    Velocity = pack.Velocity;
                                    SVelocity = pack.SV;
                                    ATime = pack.ATime;
                                    DTime = pack.DTime;
                                    HVelocity1 = pack.hspeed1;
                                    HVelocity2 = pack.hspeed2;

                                } break;
                            case FLYAD7_OBJ_INTERFACE.DRIVE_MAN_INTERFACE.GET_STATE:
                                {
                                    //TODO ？？？？？
                                    FLYAD7_OBJ_INTERFACE.DRIVE_MAN_INTERFACE.Pack_DriveState p = new FLYAD7_OBJ_INTERFACE.DRIVE_MAN_INTERFACE.Pack_DriveState();
                                    if (!p.TryParse(infodata))
                                        break;
                                    DriveOrder = p.order;//TODO
                                    DriveStatus = p.status;
                                    Marker = p.marker;
                                } break;
                        }
                    } break;
                case FLYAD7_OBJ_INTERFACE.SYS_DATA_INTERFACE.ID:
                    {
                        switch (memid)
                        {
                            case FLYAD7_OBJ_INTERFACE.SYS_DATA_INTERFACE.GET_IP:
                                break;
                            case FLYAD7_OBJ_INTERFACE.SYS_DATA_INTERFACE.GET_SYSPARAM:
                                {
                                    FLYAD7_OBJ_INTERFACE.SYS_DATA_INTERFACE.Pack_SysParam pack = new FLYAD7_OBJ_INTERFACE.SYS_DATA_INTERFACE.Pack_SysParam();

                                    if (!pack.TryParse(infodata))
                                        break;
                                    PosOfGrid = pack.posOfGrid;//1个Grid=?脉冲数(2B)
                                    if ((pack.func_enable & 0x03) == 0x02)
                                        MotorType = MOTORTYPE.SERVO;
                                    else if ((pack.func_enable & 0x03) == 0x01)
                                        MotorType = MOTORTYPE.VF0;
                                    else
                                        MotorType = MOTORTYPE.NULL;

                                    Ratio01 = pack.ratio01;
                                    Ratio02 = pack.ratio02;
                                } break;
                            case FLYAD7_OBJ_INTERFACE.SYS_DATA_INTERFACE.GET_SYSINFO:
                                {
                                    FLYAD7_OBJ_INTERFACE.SYS_DATA_INTERFACE.Pack_SysInfo pack = new FLYAD7_OBJ_INTERFACE.SYS_DATA_INTERFACE.Pack_SysInfo();

                                    if (!pack.TryParse(infodata))
                                        break;

                                    AreaStatus = pack.status;
                                    AreaRet = pack.ret;

                                    Array.Copy(pack.code, Code, pack.code.Length);
                                    Code[6] = 0x06;
                                    NotifyPropertyChanged("Code");

                                    Surplus = pack.surplus;

                                    Array.Copy(pack.access, Access, pack.access.Length);
                                    NotifyPropertyChanged("Access");

                                } break;
                            case FLYAD7_OBJ_INTERFACE.SYS_DATA_INTERFACE.GET_ZERO_POS:
                                {
                                    FLYAD7_OBJ_INTERFACE.SYS_DATA_INTERFACE.Pack_ZeroPos pack = new FLYAD7_OBJ_INTERFACE.SYS_DATA_INTERFACE.Pack_ZeroPos();

                                    if (!pack.TryParse(infodata))
                                        break;

                                    PosOffset = pack.zero_pos;
                                    JogVelocity = pack.jog_velocity;
                                } break;
                        }
                    } break;
            }
            bShieldSetValueEx = false;
        }
        /// <summary>
        ///  systick 转 DateTime
        ///  不断把 从flyad7 获取的 systick 放入。  以每次systick 的差 加上 上一次 dt_1st, 得到时间。
        ///  如： 当前 获得 systick1, 之前是 systick0,   所以 dt = dt_1st+ (systick1-systick0);  dt_1st=dt;
        ///  
        /// 第1个 dt_1st, 是 从 DateTime.Now. 获取的。
        /// 
        /// 不会管 当前DateTime.Now 与 dt 差多少。 所以如果 flyad7 时间比较慢，可能会出现 3天后， DateTime.Now 与 dt 差了 1个小时。
        /// </summary>
        class TSysTick
        {
            Int32 systick_1st = 0;
            DateTime dt_1st = DateTime.MinValue;
            Int32 systick_last = 0;

            public void Reset()
            {
                dt_1st = DateTime.MinValue;
            }
            /// <summary>
            /// 输入从 flyad7 获取的 timemark, 转换为 本地 DateTime
            /// </summary>
            /// <param name="systick"></param>
            /// <returns></returns>
            public DateTime ToDateTime(int systick)
            {
                if (dt_1st == DateTime.MinValue)
                {
                    dt_1st = DateTime.Now;
                    systick_1st = systick;
                    systick_last = systick;
                    return dt_1st;
                }
                //记录与新的timemark 相差10秒，太大了,重新生成 timemark 与 dt 的关系
                else if (Math.Abs(systick - systick_last) > 10000)
                {
                    dt_1st = DateTime.Now;
                    systick_1st = systick;
                    systick_last = systick;
                    return dt_1st;
                }
                else
                {
                    int ms = systick - systick_1st;
                    systick_last = systick;


                    DateTime dt = dt_1st.AddMilliseconds(ms);

                    systick_1st = systick;
                    dt_1st = dt;

                    return dt;
                }

            }
        }
        TSysTick mSysTick = new TSysTick();
        public override void PushInfo(IFConn from, uint srcid, ushort infoid, byte[] infodata)
        {
            bShieldSetValueEx = true;
            switch (infoid)
            {
                case FLYAD7_OBJ_INTERFACE.PUSH_DATA_INTERFACE.PUSH_POS1:
                    {
                        FLYAD7_OBJ_INTERFACE.PUSH_DATA_INTERFACE.Pack_PushPos1_2 pack = new FLYAD7_OBJ_INTERFACE.PUSH_DATA_INTERFACE.Pack_PushPos1_2();
                        int version;
                        if (!pack.TryParse_version(infodata,out version))
                            break;
                        if(version == 1)
                        {
                            Position = pack.pos1;
#if !SPEED_BY_MySelf
                            Speed = (int)(pack.speed1 * SpeedScale);
#endif
                            mCreateGridAdv.AddPos(Position, DateTime.Now);
                        }
                        else if(version == 2)
                        {
                            Position = pack.pos1;
#if !SPEED_BY_MySelf
                            Speed = (int)(pack.speed1 * SpeedScale);
#endif
                            DateTime dt = mSysTick.ToDateTime(pack.systick);
                            Now = dt;
                            
                            mCreateGridAdv.AddPos(Position, dt);
                        }
                    } break;
                case FLYAD7_OBJ_INTERFACE.PUSH_DATA_INTERFACE.PUSH_POS2:
                    {
                        FLYAD7_OBJ_INTERFACE.PUSH_DATA_INTERFACE.Pack_PushPos2_2 pack = new FLYAD7_OBJ_INTERFACE.PUSH_DATA_INTERFACE.Pack_PushPos2_2();
                        int version;
                        if (!pack.TryParse_version(infodata,out version))
                            break;
                       
                        Position2 = pack.pos2;
 #if !SPEED_BY_MySelf
                        Speed2 = (int)(pack.speed2 * SpeedScale);
#endif                
                    } break;
                case FLYAD7_OBJ_INTERFACE.PUSH_DATA_INTERFACE.PUSH_AD1:
                    {
                        FLYAD7_OBJ_INTERFACE.PUSH_DATA_INTERFACE.Pack_PushAD1 pack = new FLYAD7_OBJ_INTERFACE.PUSH_DATA_INTERFACE.Pack_PushAD1();
                        if (!pack.TryParse(infodata))
                            break;

                        if (CorrectADs != null)
                        {
                            int grid = Position / PosOfGrid;
                            int[] d = new int[1];
                            d[0] = pack.AD;
                            CorrectADs(Misc.DIRECTION.FIX, grid, d);
                            pack.AD = d[0];
                        }

                        AD = pack.AD;
                    } break;
                case FLYAD7_OBJ_INTERFACE.PUSH_DATA_INTERFACE.PUSH_IO:
                    {
                        FLYAD7_OBJ_INTERFACE.PUSH_DATA_INTERFACE.Pack_PushIO_2 pack = new FLYAD7_OBJ_INTERFACE.PUSH_DATA_INTERFACE.Pack_PushIO_2();
                        int version;
                        if (!pack.TryParse_version(infodata, out version))
                            break;

                        if (version == 1) 
                        {
                            UInt16 inchange = (UInt16)(IStatus ^ pack.istatus);
                            IStatus = pack.istatus;
                            OStatus = pack.ostatus;
                            Now = DateTime.Now;

                            mCreateGridAdv.AddIStatus(IStatus, Position, Now);

                            if (IStatusChangedEvent != null)
                            {
                                IStatusChangedEvent(
                                    this,
                                    new IStatusChangedEventArgs(
                                        Now,
                                        IStatus,
                                        inchange,
                                        Position,
                                        Position2));
                            }
                        }
                        else if(version == 2)
                        {
                            IStatus = pack.istatus;
                            OStatus = pack.ostatus;
                            DateTime dt = mSysTick.ToDateTime(pack.systick);
                            Now = dt;
                            
                            mCreateGridAdv.AddIStatus(IStatus,pack.pos1, Now);

                            if (IStatusChangedEvent != null)
                            {
                                IStatusChangedEvent(
                                    this,
                                    new IStatusChangedEventArgs(
                                        dt,
                                        pack.istatus,
                                        pack.inChange,
                                        pack.pos1,
                                        pack.pos2));
                            }
                        }
                    } break;

                case FLYAD7_OBJ_INTERFACE.PUSH_DATA_INTERFACE.PUSH_AD2:
                    break;
                case FLYAD7_OBJ_INTERFACE.PUSH_DATA_INTERFACE.PUSH_TIMEGRID:
                    {
                        int version;
                        FLYAD7_OBJ_INTERFACE.PUSH_DATA_INTERFACE.Pack_PushTGrid_2 pack = new FLYAD7_OBJ_INTERFACE.PUSH_DATA_INTERFACE.Pack_PushTGrid_2();

                        if (!pack.TryParse_version(infodata, out version))
                        {
                            break;
                        }


                        DateTime dt;
                        int[] data;

                        if (version == 1)
                        {
                            //怕数据发送出错
                            foreach (int d in pack.data)
                            {
                                if ((d >> 16) != 0)
                                {
                                    //异常
                                    goto _end_push_info;

                                }
                            }
                            dt = DateTime.Now;
                        }
                        //else if (version == 2)
                        {

                            //怕数据发送出错
                            foreach (int d in pack.data)
                            {
                                if ((d >> 16) != 0)
                                {
                                    //异常
                                    goto _end_push_info;

                                }
                            }
                            dt = mSysTick.ToDateTime(pack.systick);
                            Now = dt;
                        }
                        data = pack.data;

                        mCreateGridAdv.AddAD(data, dt - TimeSpan.FromMilliseconds(ADLag));

                        noTGridCnt = 0;//收到timegrid!!!!!!!!!!!

                        {
                            double ts_ms = 1.28;
                            long ticks = (long)((ts_ms * data.Length) * TimeSpan.TicksPerMillisecond);
                            dt = dt - TimeSpan.FromTicks(ticks);

                            if (TimeGridEvent != null)
                            {
                                if (CorrectADs != null)
                                {
                                    if (PosOfGrid > 0)
                                    {
                                        int grid = Position / PosOfGrid;
                                        int[] d = new int[1];
                                        for (int i = 0; i < data.Count(); i++)
                                        {
                                            d[0] = data[i];
                                            CorrectADs(Misc.DIRECTION.FIX, grid, d);
                                            data[i] = d[0];
                                        }
                                    }
                                }

                                TimeGridEvent(
                                    this,
                                    new TimeGridEventArgs(
                                        dt,
                                        TimeSpan.FromTicks((long)(ts_ms * TimeSpan.TicksPerMillisecond)),
                                        data));
                            }
                        }
                    } break;
                case FLYAD7_OBJ_INTERFACE.PUSH_DATA_INTERFACE.PUSH_STATUS:
                    {
                        int version;
                        FLYAD7_OBJ_INTERFACE.PUSH_DATA_INTERFACE.Pack_PushStatus_2 pack = new FLYAD7_OBJ_INTERFACE.PUSH_DATA_INTERFACE.Pack_PushStatus_2();
                        if (!pack.TryParse_version(infodata, out version))
                            break;
                        if(version == 2)
                        {
                            DriveOrder = pack.order;
                            
                            DriveStatus = pack.status;
                            Marker = pack.marker;
                            DateTime dt = mSysTick.ToDateTime(pack.systick);
                            Now = dt;
                        }
                        else if(version ==1)
                        {
                            DriveOrder = pack.order;
                            DriveStatus = pack.status;
                        }

                    } break;
                case FLYAD7_OBJ_INTERFACE.PUSH_DATA_INTERFACE.PUSH_GRID:
                    {
                        int version;
                        FLYAD7_OBJ_INTERFACE.PUSH_DATA_INTERFACE.Pack_PushGrid_2 pack = new FLYAD7_OBJ_INTERFACE.PUSH_DATA_INTERFACE.Pack_PushGrid_2();
                        if (!pack.TryParse_version(infodata,out version))
                            break;

                        DateTime dt;
                        int marker;

                        if (version == 2)
                        {
                            dt = mSysTick.ToDateTime(pack.systick);
                            marker = pack.marker;
                        }
                        else
                        {
                            dt = DateTime.Now;
                            marker = Marker;
                        }
                        if (GridAdvEvent != null)
                        {
                            
                            mCreateGridAdv.MarkGrid(
                                pack.direction, pack.grid_start * PosOfGrid, pack.data.Length * PosOfGrid, marker, dt,
                                (s, e) =>
                                {
                                    if (CorrectADs != null)//机架修正
                                    {
                                        for (int i = 0; i < e.dt_data.Count(); i++)
                                        {
                                            int[] d = new int[]{e.dt_data[i].ad};
                                            CorrectADs(e.direction, e.dt_data[i].pos / PosOfGrid, d);
                                            e.dt_data[i].ad = d[0];
                                        }
                                    }

                                    GridAdvEvent(this, e);
                                });
                        }

                        mCreateGridAdv.NotifyGridIStatusEvent(
                            pack.direction, pack.grid_start * PosOfGrid, pack.data.Length * PosOfGrid, marker, dt);
  
                        {
                            int index = 0;
                            if (pack.direction == Misc.DIRECTION.BACKWARD)
                                index = 1;

                            if (pack.grid_start >= fGrid.data[index].Length)
                                return;

                            int grid_end = pack.data.Length + pack.grid_start - 1;

                            if (grid_end >= fGrid.data[index].Length)
                                grid_end = fGrid.data[index].Length - 1;

                            int len = grid_end - pack.grid_start + 1;


                            Array.Copy(pack.data, 0, fGrid.data[index], pack.grid_start, len);

                            //清空其它数据
                            for (int i = 0; i < pack.grid_start; i++)
                            {
                                fGrid.data[index][i] = Misc.MyBase.NULL_VALUE;
                            }
                            for (int i = (grid_end + 1); i < fGrid.data[index].Length; i++)
                            {
                                fGrid.data[index][i] = Misc.MyBase.NULL_VALUE;
                            }


                            if (GridEvent != null)
                            {
                                if (CorrectADs != null)
                                    CorrectADs(pack.direction, pack.grid_start, pack.data);

                                GridEvent(this, new MiniGridEventArgs()
                                {
                                    direction = pack.direction,
                                    grid_start = pack.grid_start,
                                    posOfGrid = PosOfGrid,
                                    buf = pack.data,
                                    marker = marker
                                });
                            }
                        }

                    } break;
                case FLYAD7_OBJ_INTERFACE.PUSH_DATA_INTERFACE.PUSH_MINIGRID:
                    {
                        FLYAD7_OBJ_INTERFACE.PUSH_DATA_INTERFACE.Pack_PushGrid pack = new FLYAD7_OBJ_INTERFACE.PUSH_DATA_INTERFACE.Pack_PushGrid();
                        if (!pack.TryParse(infodata))
                            break;

                        int index = 0;
                        if (pack.direction == Misc.DIRECTION.BACKWARD)
                            index = 1;

                        if (pack.grid_start >= fGrid.data[index].Length)
                            break;

                        int grid_end = pack.data.Length + pack.grid_start - 1;



                        if (grid_end >= fGrid.data[index].Length)
                            grid_end = fGrid.data[index].Length - 1;

                        int len = grid_end - pack.grid_start + 1;

                        Array.Copy(pack.data, 0, fGrid.data[index], pack.grid_start, len);

                        //清空后面的数据
                        if (pack.direction == Misc.DIRECTION.BACKWARD)
                        {
                            for (int i = 0; i < pack.grid_start; i++)
                            {
                                fGrid.data[index][i] = Misc.MyBase.NULL_VALUE;
                            }
                        }
                        else
                        {
                            for (int i = (grid_end + 1); i < fGrid.data[index].Length; i++)
                            {
                                fGrid.data[index][i] = Misc.MyBase.NULL_VALUE;
                            }
                        }
                        if (CorrectADs != null)
                            CorrectADs(pack.direction, pack.grid_start, pack.data);

                        if (MiniGridEvent != null)
                        {
                            MiniGridEvent(this, new MiniGridEventArgs()
                            {
                                direction = pack.direction,
                                grid_start = pack.grid_start,
                                posOfGrid = PosOfGrid,
                                buf = pack.data,
                                marker = Marker
                            });
                        }

                    } break;
            }
        _end_push_info:
            bShieldSetValueEx = false;
        }

        #endregion

        /// <summary>
        /// 100ms 周期
        /// </summary>
        private void OnPoll()
        {
            if (!IsConnected)
                return;

            DateTime now = DateTime.Now;

            if (Surplus != 65535)
            {
                if (dt_surplus == DateTime.MinValue)
                {
                    dt_surplus = now - TimeSpan.FromMinutes(40);//再过20分钟，就会 执行 使用时间+1
                }
                else if ((now - dt_surplus).TotalHours >= 1) //每隔一个小时 执行 使用时间+1
                {
                    dt_surplus = now;
                    if (Surplus > 0)
                    {
                        Surplus--;
                        CurrObjSys.CallFunctionEx(conn, FLYAD7_OBJ_INTERFACE.SYS_DATA_INTERFACE.ID, ID,
                            FLYAD7_OBJ_INTERFACE.SYS_DATA_INTERFACE.CALL_SURPLUS_SUB,
                            null);
                    }

                }
            }

            if (sysinfo_wait.bNeedGet)
            {
                if ((now - sysinfo_wait.dt).TotalSeconds >= 1)
                {
                    sysinfo_wait.bNeedGet = false;
                    CurrObjSys.GetValueEx(
                        conn,
                        FLYAD7_OBJ_INTERFACE.SYS_DATA_INTERFACE.ID,
                        ID,
                        FLYAD7_OBJ_INTERFACE.SYS_DATA_INTERFACE.GET_SYSINFO);

                }
            }

            if (DriveStatus == DRIVE_MAN_STATUS.RUNNING)
            {
                //if (Position == TargetPos) //已经到达位置，问AD卡是不是？
                //{
                //    if ((now - driveman_wait.dt).TotalSeconds >= 1)//每次发送必须间隔1s
                //    {
                //        driveman_wait.Clear();
                //        CurrObjSys.GetValueEx(
                //            conn,
                //            FLYAD7_OBJ_INTERFACE.DRIVE_MAN_INTERFACE.ID,
                //            ID,
                //            FLYAD7_OBJ_INTERFACE.DRIVE_MAN_INTERFACE.GET_STATE);
                //    }
                //}
                //else 
                if ((now - driveman_wait.dt).TotalSeconds >= 3)
                {
                    driveman_wait.Clear();
                    if (Position == last_position)//当前正在running，但脉冲在3秒内都没变化，问AD卡，现在什么情况。
                    {
                        CurrObjSys.GetValueEx(
                            conn,
                            FLYAD7_OBJ_INTERFACE.DRIVE_MAN_INTERFACE.ID,
                            ID,
                            FLYAD7_OBJ_INTERFACE.DRIVE_MAN_INTERFACE.GET_STATE);
                    }
                    last_position = Position;
                }
            }

        }
        int last_position = int.MinValue;
        #region IFlyAD 成员
        private bool isconnected;

        public bool IsConnected
        {
            get { return isconnected; }
            protected set
            {
                if (isconnected != value)
                {
                    isconnected = value;
                    NotifyPropertyChanged("IsConnected");
                }
            }
        }
        private int connectcnt = 0;
        public int ConnectCnt
        {
            get { return connectcnt; }
            protected set
            {
                if (connectcnt != value)
                {
                    connectcnt = value;
                    NotifyPropertyChanged("ConnectCnt");
                }
            }
        }

        #endregion

        #region INotifyPropertyChanged 成员
        protected void NotifyPropertyChanged(string propertyName)
        {
            if (this.PropertyChanged != null)
                this.PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
        public event PropertyChangedEventHandler PropertyChanged;

        #endregion


        private int poslen=8900;
        public int PosLen
        {
            get { return poslen; }
            set
            {
                if (poslen != value)
                {
                    poslen = value;
                    NotifyPropertyChanged("PosLen");
                }
            }
        }

        public void RuntoMin()
        {
            Runto(0);
        }

        public void RuntoMax()
        {
            Runto(PosLen);
        }

        #region IFlyAD 成员
        private IPEndPoint localep = new IPEndPoint(IPAddress.Parse("192.168.251.10"), 20006);
        public IPEndPoint LocalEP
        {
            get
            {
                return localep;
            }
            set
            {
                if (value == null)
                    return;
                if (!IPEndPoint.Equals(localep, value))
                {
                    localep = new IPEndPoint(value.Address, value.Port);
                    NotifyPropertyChanged("LocalEP");
                }
            }
        }
        private DateTime now;
        public DateTime Now
        {
            get
            {
                return now;
            }
            set
            {
                if (now != value)
                {
                    now = value;
                    NotifyPropertyChanged("Now");
                }
            }
        }

        private int position;
        public int Position
        {
            get { return position; }
            set
            {
                if (position != value)
                {
                    position = value;
                    NotifyPropertyChanged("Position");
                }
            }
        }
        private int speed;
        public int Speed
        {
            get { return speed; }
            set
            {
                if (speed != value)
                {
                    speed = value;
                    NotifyPropertyChanged("Speed");
                }
            }
        }

        private int ad;
        public int AD
        {
            get { return ad; }
            set
            {
                if (ad != value)
                {
                    ad = value;
                    NotifyPropertyChanged("AD");
                }
            }
        }
        public int ADMax
        {
            get { return 65535; }
        }


        private UInt16 uIStatus = 0xffff;
        public UInt16 IStatus
        {
            get { return uIStatus; }
            set
            {
                if (uIStatus != value)
                {
                    uIStatus = value;
                    NotifyPropertyChanged("IStatus");
                }
            }
        }

        private UInt16 uOStatus;
        public UInt16 OStatus
        {
            get { return uOStatus; }
            set
            {
                if (uOStatus != value)
                {
                    uOStatus = value;
                    NotifyPropertyChanged("OStatus");
                }
            }
        }
        public void SetOutputBit(int index, bool is1) 
        {
            if (index > 4)
                return;
            if (index < 0)
                return;
            if (is1)
            {
                SetOutput(
                    (UInt16)Misc.MyBase.BIT(index),
                    (UInt16)Misc.MyBase.BIT(index));
            }
            else 
            {
                SetOutput(
                    (UInt16)Misc.MyBase.BIT(index),
                    (UInt16)~Misc.MyBase.BIT(index));
            }
        }
        public void SetOutput(ushort mask, ushort enable)
        {
            CurrObjSys.CallFunctionEx(
                conn,
                FLYAD7_OBJ_INTERFACE.FLYIO_OBJ_INTERFACE.ID,
                ID,
                FLYAD7_OBJ_INTERFACE.FLYIO_OBJ_INTERFACE.CALL_OUTPORT,
                new FLYAD7_OBJ_INTERFACE.FLYIO_OBJ_INTERFACE.Pack_CallOutPort()
                {
                    mask = mask,
                    port = enable
                }.ToBytes());
        }

        /// <summary>
        /// 更新参数
        /// </summary>
        public void UpdateParam()
        {
            //OBJ_SYS_DATA
            CurrObjSys.GetValueEx(
                conn,
                FLYAD7_OBJ_INTERFACE.SYS_DATA_INTERFACE.ID,
                ID,
                FLYAD7_OBJ_INTERFACE.SYS_DATA_INTERFACE.GET_SYSPARAM);

            CurrObjSys.GetValueEx(
                conn,
                FLYAD7_OBJ_INTERFACE.SYS_DATA_INTERFACE.ID,
                ID,
                FLYAD7_OBJ_INTERFACE.SYS_DATA_INTERFACE.GET_ZERO_POS);

            CurrObjSys.GetValueEx(
                conn,
                FLYAD7_OBJ_INTERFACE.SYS_DATA_INTERFACE.ID,
                ID,
                FLYAD7_OBJ_INTERFACE.SYS_DATA_INTERFACE.GET_SYSINFO);

            //DRIVE_MAN
            CurrObjSys.GetValueEx(
                conn,
                FLYAD7_OBJ_INTERFACE.DRIVE_MAN_INTERFACE.ID,
                ID,
                FLYAD7_OBJ_INTERFACE.DRIVE_MAN_INTERFACE.GET_DRIVEPARAM);
        }

        #region 配置参数
        /// <summary>
        /// 配置参数，请不要再用
        /// </summary>
        /// <param name="posOfGrid"></param>
        /// <param name="motortype"></param>
        /// <param name="ratio01"></param>
        /// <param name="ratio02"></param>
        public void SetSysParam(UInt16 posOfGrid, MOTORTYPE motortype, UInt16 ratio01, UInt16 ratio02)
        {
            byte func_enable = 0x0e;
            if (motortype == MOTORTYPE.NULL)
                func_enable = 0x0e;
            else if (motortype == MOTORTYPE.SERVO)
                func_enable = 0x0e;
            else// if (motortype == MOTORTYPE.VF0)
                func_enable = 0x0d;

            CurrObjSys.SetValueEx(
                conn,
                FLYAD7_OBJ_INTERFACE.SYS_DATA_INTERFACE.ID,
                ID,
                FLYAD7_OBJ_INTERFACE.SYS_DATA_INTERFACE.SET_SYSPARAM,
                new FLYAD7_OBJ_INTERFACE.SYS_DATA_INTERFACE.Pack_SysParam()
                {
                    posOfGrid = posOfGrid,
                    ad1_interval = 1000,
                    ad2_interval = 1000,
                    push_interval = 100,
                    func_setting = 0,
                    func_enable = func_enable,
                    ratio01 = ratio01,
                    ratio02 = ratio02
                }.ToBytes());
            //CurrObjSys.GetValueEx(
            //    conn,
            //    FLYAD7_OBJ_INTERFACE.SYS_DATA_INTERFACE.ID,
            //    ID,
            //    0x1234,
            //    FLYAD7_OBJ_INTERFACE.SYS_DATA_INTERFACE.GET_SYSPARAM);
        }
        private MOTORTYPE motortype = MOTORTYPE.SERVO;
        public MOTORTYPE MotorType
        {
            get { return motortype; }
            set
            {
                if (motortype != value)
                {
                    motortype = value;
                    NotifyPropertyChanged("MotorType");
                }
            }
        }
        private UInt16 posofgrid;
        /// <summary>
        /// // 单位 pulse/grid
        /// </summary>
        public UInt16 PosOfGrid
        {
            get { return posofgrid; }
            set
            {
                if (posofgrid != value)
                {
                    posofgrid = value;
                    NotifyPropertyChanged("PosOfGrid");
                }
            }
        }
        private UInt16 ratio01;
        public UInt16 Ratio01
        {
            get { return ratio01; }
            set
            {
                if (ratio01 != value)
                {
                    ratio01 = value;
                    NotifyPropertyChanged("Ratio01");
                    NotifyPropertyChanged("Speed1Scale");
                }
            }
        }
        private UInt16 ratio02;
        public UInt16 Ratio02
        {
            get { return ratio02; }
            set
            {
                if (ratio02 != value)
                {
                    ratio02 = value;
                    NotifyPropertyChanged("Ratio02");
                    NotifyPropertyChanged("Speed1Scale");
                }
            }
        }
        /// <summary>
        /// Speed1 = Velocity * Speed1Scale
        /// </summary>
        public double Speed1Scale 
        {
            get {
                return (double)Ratio02 / Ratio01;
            }
        }
        #endregion

        private Int16 posoffset;
        public Int16 PosOffset
        {
            get
            {
                return posoffset;
            }
            set
            {
                if (posoffset != value)
                {
                    posoffset = value;
                    NotifyPropertyChanged("PosOffset");
                }
            }
        }//脉冲平移
        private UInt32 jogvelocity;
        public UInt32 JogVelocity
        {
            get
            {
                return jogvelocity;
            }
            set
            {
                if (jogvelocity != value)
                {
                    jogvelocity = value;
                    NotifyPropertyChanged("JogVelocity");
                }
            }
        }
        #region 速度
        public void SetVelocity(UInt32 velocity) 
        {
            SetPosParam(velocity, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff);
        }
        public void SetPosParam(UInt32 velocity, UInt32 sv, UInt32 atime, UInt32 dtime, UInt32 hspeed1, UInt32 hspeed2)
        {
            bShieldSetValueEx = true;
            if (velocity != 0xffffffff)
                Velocity = velocity;
            if (sv != 0xffffffff)
                SVelocity = sv;
            if (atime != 0xffffffff)
                ATime = atime;
            if (dtime != 0xffffffff)
                DTime = dtime;
            if (hspeed1 != 0xffffffff)
                HVelocity1 = hspeed1;
            if (hspeed2 != 0xffffffff)
                HVelocity2 = hspeed2;
            bShieldSetValueEx = false;
            CurrObjSys.SetValueEx(
                conn,
                FLYAD7_OBJ_INTERFACE.DRIVE_MAN_INTERFACE.ID,
                ID,
                FLYAD7_OBJ_INTERFACE.DRIVE_MAN_INTERFACE.SET_DRIVEPARAM,
                new FLYAD7_OBJ_INTERFACE.DRIVE_MAN_INTERFACE.Pack_DriveParam()
                {
                    Velocity = velocity,
                    SV = sv,
                    ATime = atime,
                    DTime = dtime,
                    hspeed1 = hspeed1,
                    hspeed2 = hspeed2
                }.ToBytes());
            //CurrObjSys.GetValueEx(
            //    conn,
            //    FLYAD7_OBJ_INTERFACE.DRIVE_MAN_INTERFACE.ID,
            //    ID,
            //    0x1234,
            //    FLYAD7_OBJ_INTERFACE.DRIVE_MAN_INTERFACE.GET_DRIVEPARAM);
        }
        private UInt32 velocity;
        public UInt32 Velocity
        {
            get
            {
                return velocity;
            }
            set
            {
                if (velocity != value)
                {
                    velocity = value;
                    NotifyPropertyChanged("Velocity");
                }
            }
        }
        private UInt32 svelocity;
        public UInt32 SVelocity
        {
            get
            {
                return svelocity;
            }
            set
            {
                if (svelocity != value)
                {
                    svelocity = value;
                    NotifyPropertyChanged("SVelocity");
                }
            }
        }
        private UInt32 atime;
        public UInt32 ATime
        {
            get
            {
                return atime;
            }
            set
            {
                if (atime != value)
                {
                    atime = value;
                    NotifyPropertyChanged("ATime");
                }
            }
        }
        private UInt32 dtime;
        public UInt32 DTime
        {
            get
            {
                return dtime;
            }
            set
            {
                if (dtime != value)
                {
                    dtime = value;
                    NotifyPropertyChanged("DTime");
                }
            }
        }
        private UInt32 hvelocity1;
        public UInt32 HVelocity1
        {
            get
            {
                return hvelocity1;
            }
            set
            {
                if (hvelocity1 != value)
                {
                    hvelocity1 = value;
                    NotifyPropertyChanged("HVelocity1");
                }
            }
        }
        private UInt32 hvelocity2;
        public UInt32 HVelocity2
        {
            get
            {
                return hvelocity2;
            }
            set
            {
                if (hvelocity2 != value)
                {
                    hvelocity2 = value;
                    NotifyPropertyChanged("HVelocity2");
                }
            }
        }
        #endregion

        #region 密码
        private AREA_STATUS areastatus;
        public AREA_STATUS AreaStatus
        {
            get { return areastatus; }
            set
            {
                if (areastatus != value)
                {
                    areastatus = value;
                    NotifyPropertyChanged("AreaStatus");
                }
            }
        }
        private AREA_ERR arearet;
        public AREA_ERR AreaRet
        {
            get { return arearet; }
            set
            {
                if (arearet != value)
                {
                    arearet = value;
                    NotifyPropertyChanged("AreaRet");
                }
            }
        }

        private byte[] code = new byte[7];
        public byte[] Code
        {
            get { return code; }
        }
        private int surplus = 0xffff;
        /// <summary>
        /// //系统剩余时间
        /// </summary>
        public int Surplus
        {
            get { return surplus; }
            set
            {
                if (surplus != value)
                {
                    surplus = value;
                    NotifyPropertyChanged("Surplus");
                }
            }
        }



        private byte[] access = new byte[8];
        public byte[] Access { get { return access; } }//access[8]

        /// <summary>
        /// 输入系统授权码
        /// </summary>
        /// <param name="access"></param>
        public void SetAccess(byte[] access)
        {
            CurrObjSys.CallFunctionEx(
                conn,
                FLYAD7_OBJ_INTERFACE.SYS_DATA_INTERFACE.ID,
                ID,
                FLYAD7_OBJ_INTERFACE.SYS_DATA_INTERFACE.CALL_ACCESS,
                access);
            sysinfo_wait.bNeedGet = true;
            sysinfo_wait.dt = DateTime.Now;
        }
        /// <summary>
        /// 初始化系统信息区
        /// </summary>
        public void InitArea()
        {
            CurrObjSys.CallFunctionEx(
                conn,
                FLYAD7_OBJ_INTERFACE.SYS_DATA_INTERFACE.ID,
                ID,
                FLYAD7_OBJ_INTERFACE.SYS_DATA_INTERFACE.CALL_INIT,
                new FLYAD7_OBJ_INTERFACE.SYS_DATA_INTERFACE.Pack_Init().ToBytes());
            sysinfo_wait.bNeedGet = true;
            sysinfo_wait.dt = DateTime.Now;
        }
        #endregion
        #endregion
        #region IFlyAD 成员

        public void GetGrid(Misc.DIRECTION direction, int grid_start, int grid_len, out int[] dat)
        {
            int index = 0;
            if (direction == Misc.DIRECTION.BACKWARD)
                index = 1;

            dat = new int[grid_len];

            for (int i = 0; i < dat.Length; i++)
            {
                int grid_num = grid_start + i;
                if (grid_num >= fGrid.data[index].Length)
                    break;

                if (GridSmooth > 0)
                {
                    int sum = 0;
                    int cnt = 0;
                    for (int j = 0; j < (GridSmooth * 2 + 1); j++)
                    {
                        int idx = grid_num - GridSmooth + j;
                        if(idx<0)
                            continue;
                        if(idx >= fGrid.data[index].Length)
                            break;
                        if (Misc.MyBase.ISVALIDATA(fGrid.data[index][idx]))
                        {
                            sum += fGrid.data[index][idx];
                            cnt++;
                        }
                    }
                    if (cnt > 0)
                        dat[i] = sum / cnt;
                    else
                        dat[i] = Misc.MyBase.NULL_VALUE;
                }
                else
                {
                    dat[i] = fGrid.data[index][grid_num];
                }
            }

            if (CorrectADs != null)
                CorrectADs(direction, grid_start, dat);
            return;
        }
        public void GetGrid(Misc.DIRECTION direction, out int[] dat)
        {
            GetGrid(direction, 0, fGrid.data[0].Length, out dat);
        }
        public event TimeGridEventHandler TimeGridEvent;

        public event MiniGridEventHandler MiniGridEvent;

        public event MiniGridEventHandler GridEvent;

        public event IStatusChangedEventHandler IStatusChangedEvent;

        public void Runto(int to)
        {
            Drive(DRIVE_MAN_ORDER.RUNTO, to);
        }

        public void Origin()
        {
            Drive(DRIVE_MAN_ORDER.ORIGIN);
        }
        public void Stop()
        {
            Drive(DRIVE_MAN_ORDER.STOP);
        }
        public void Backward()
        {
            Drive(DRIVE_MAN_ORDER.BACKWORD);
        }
        public void Forward()
        {
            Drive(DRIVE_MAN_ORDER.FORWORD);
        }

        private DRIVE_MAN_ORDER driveorder=DRIVE_MAN_ORDER.IDLE;
        public DRIVE_MAN_ORDER DriveOrder
        {
            get { return driveorder; }
            set
            {
                if (driveorder != value)
                {
                    driveorder = value;
                    NotifyPropertyChanged("DriveOrder");
                }

            }
        }
        private DRIVE_MAN_STATUS drivestatus=DRIVE_MAN_STATUS.STOP;
        public DRIVE_MAN_STATUS DriveStatus
        {
            get { return drivestatus; }
            set
            {
                if (drivestatus != value)
                {
                    drivestatus = value;
                    NotifyPropertyChanged("DriveStatus");
                }

            }
        }


        void Drive(DRIVE_MAN_ORDER order, object param)
        {
            
            switch (order)
            {
                case DRIVE_MAN_ORDER.RUNTO:
                    {
                        int TargetPos = (int)param;
                        if (Position == TargetPos)
                        {
                            //已经到了位置！！！！！， FLYAD7 是没有动作，没有推送的！！！
                            DriveStatus = DRIVE_MAN_STATUS.STOP;
                        }
                        else
                        {
                            DriveStatus = DRIVE_MAN_STATUS.RUNNING;
                            CurrObjSys.CallFunctionEx(
                                conn,
                                FLYAD7_OBJ_INTERFACE.DRIVE_MAN_INTERFACE.ID,
                                ID,
                                FLYAD7_OBJ_INTERFACE.DRIVE_MAN_INTERFACE.CALL_PXX,
                                new FLYAD7_OBJ_INTERFACE.DRIVE_MAN_INTERFACE.Pack_CallRunto() { to = TargetPos }.ToBytes());

                        }
                    } break;
                case DRIVE_MAN_ORDER.ORIGIN:
                case DRIVE_MAN_ORDER.BACKWORD:
                case DRIVE_MAN_ORDER.FORWORD:
                case DRIVE_MAN_ORDER.STOP:
                    {
                        DriveStatus = DRIVE_MAN_STATUS.RUNNING;
                        CurrObjSys.CallFunctionEx(
                            conn,
                            FLYAD7_OBJ_INTERFACE.DRIVE_MAN_INTERFACE.ID,
                            ID,
                            FLYAD7_OBJ_INTERFACE.DRIVE_MAN_INTERFACE.CALL_PXX,
                            new FLYAD7_OBJ_INTERFACE.DRIVE_MAN_INTERFACE.Pack_CallPXX() { order = order }.ToBytes());
                    } break;
                case DRIVE_MAN_ORDER.SYNC:
                    {
                        if (param != null)
                        {
                            CurrObjSys.CallFunctionEx(
                                conn,
                                FLYAD7_OBJ_INTERFACE.DRIVE_MAN_INTERFACE.ID,
                                ID,
                                FLYAD7_OBJ_INTERFACE.DRIVE_MAN_INTERFACE.CALL_PXX,
                                new FLYAD7_OBJ_INTERFACE.DRIVE_MAN_INTERFACE.Pack_SyncBeginWithPos2()
                                {
                                    pos2 = (int)param
                                }.ToBytes());
                        }
                        else
                        {

                            CurrObjSys.CallFunctionEx(
                                conn,
                                FLYAD7_OBJ_INTERFACE.DRIVE_MAN_INTERFACE.ID,
                                ID,
                                FLYAD7_OBJ_INTERFACE.DRIVE_MAN_INTERFACE.CALL_PXX,
                                new FLYAD7_OBJ_INTERFACE.DRIVE_MAN_INTERFACE.Pack_SyncBegin().ToBytes());
                        }
                    } break;
            }

            driveman_wait.Clear();
        }
        void Drive(DRIVE_MAN_ORDER order)
        {
            Drive(order, null);
        }

        private bool isfinish;
        public bool IsFinish
        {
            get
            {
                return isfinish;
            }
            set
            {
                if (isfinish != value)
                {
                    isfinish = value;
                    NotifyPropertyChanged("IsFinish");
                }
            }
        }


        #endregion

        #region 同步
        private Int32 marker;
        /// <summary>
        /// 同步用标示
        /// </summary>
        public Int32 Marker
        {
            get { return marker; }
            protected set
            {
                if (marker != value)
                {
                    marker = value;
                    NotifyPropertyChanged("Marker");
                }
            }
        }
        #region 横向脉冲
        private int pos1lcshift=0;
        /// <summary>
        /// 逻辑横向脉冲偏移  Pos1 + Pos1LCShift = Pos1LC
        /// </summary>
        public int Pos1LCShift
        {
            get { return pos1lcshift; }
            set
            {
                if (pos1lcshift != value)
                {
                    pos1lcshift = value;
                    NotifyPropertyChanged("Pos1LCShift");
                }
            }
        }
        #endregion
        #region 主轴脉冲
        private int speed2=0;
        /// <summary>
        /// 纵向脉冲速度, pps, 1秒脉冲数
        /// </summary>
        public int Speed2
        {
            get
            {
                return speed2;
            }
            protected set
            {
                if (speed2 != value)
                {
                    speed2 = value;
                    NotifyPropertyChanged("Speed2");
                }
            }
        }
        private int position2=0;
        /// <summary>
        /// 纵向脉冲，也叫主轴脉冲
        /// </summary>
        public int Position2
        {
            get
            {
                return position2;
            }
            set
            {
                if (position2 != value)
                {
                    position2 = value;
                    NotifyPropertyChanged("Position2");
                }
            }
        }
        private int pos2shift=0;
        /// <summary>
        /// 纵向偏移
        /// </summary>
        public void SetPos2Offset(int offset) 
        {
            CurrObjSys.CallFunctionEx(
                conn,
                FLYAD7_OBJ_INTERFACE.DRIVE_MAN_INTERFACE.ID,
                ID,
                FLYAD7_OBJ_INTERFACE.DRIVE_MAN_INTERFACE.CALL_PXX,
                new FLYAD7_OBJ_INTERFACE.DRIVE_MAN_INTERFACE.Pack_Pos2Shift()
                {
                    pos2_shift = offset
                }.ToBytes());
        }
        private float pos2comp=1;
        /// <summary>
        /// 纵向值补偿系数，补偿时，先乘除后加减
        /// </summary>
        public float Pos2Comp
        {
            get
            {
                return pos2comp;
            }
            set
            {
                if (pos2comp != value)
                {
                    pos2comp = value;
                    NotifyPropertyChanged("Pos2Comp");
                }
            }
        }
        /// <summary>
        /// 纵向同步事件，0-1事件
        /// </summary>
        /// <param name="pos2"></param>
        public void SetPos2At01(int pos2,bool immediately)
        {
            CurrObjSys.CallFunctionEx(
                conn,
                FLYAD7_OBJ_INTERFACE.DRIVE_MAN_INTERFACE.ID,
                ID,
                FLYAD7_OBJ_INTERFACE.DRIVE_MAN_INTERFACE.CALL_PXX,
                new FLYAD7_OBJ_INTERFACE.DRIVE_MAN_INTERFACE.Pack_Pos2_01()
                {
                    pos2 = pos2,
                    immediately = immediately
                }.ToBytes());
            LastPos2At01 = pos2;
        }

        #endregion
        #region 同步控制 同步状态转换规则
        /// <summary>
        /// 进入同步状态
        /// </summary>
        /// <param name="pos2"></param>
        public void SyncBegin(int pos2)
        {
            Drive(DRIVE_MAN_ORDER.SYNC, pos2);
            IsSync = true;
        }
        /// <summary>
        /// 进入同步状态
        /// </summary>
        public void SyncBegin()
        {
            Drive(DRIVE_MAN_ORDER.SYNC, null);
            IsSync = true;
        }
        /// <summary>
        /// 退出同步状态
        /// </summary>
        public void SyncEnd()
        {
            CurrObjSys.CallFunctionEx(
                conn,
                FLYAD7_OBJ_INTERFACE.DRIVE_MAN_INTERFACE.ID,
                ID,
                FLYAD7_OBJ_INTERFACE.DRIVE_MAN_INTERFACE.CALL_PXX,
                new FLYAD7_OBJ_INTERFACE.DRIVE_MAN_INTERFACE.Pack_SyncEnd().ToBytes());
            IsSync = false;
        }
        /// <summary>
        /// 清空同步指令
        /// </summary>
        public void SyncClear()
        {
            CurrObjSys.CallFunctionEx(
                conn,
                FLYAD7_OBJ_INTERFACE.DRIVE_MAN_INTERFACE.ID,
                ID,
                FLYAD7_OBJ_INTERFACE.DRIVE_MAN_INTERFACE.CALL_PXX,
                new FLYAD7_OBJ_INTERFACE.DRIVE_MAN_INTERFACE.Pack_SyncClear().ToBytes());
            
            SyncOrders.Clear();

        }
        public void SyncPos2Clear()
        {
            CurrObjSys.CallFunctionEx(
              conn,
              FLYAD7_OBJ_INTERFACE.DRIVE_MAN_INTERFACE.ID,
              ID,
              FLYAD7_OBJ_INTERFACE.DRIVE_MAN_INTERFACE.CALL_PXX,
              new FLYAD7_OBJ_INTERFACE.DRIVE_MAN_INTERFACE.Pack_SyncPos2Clear().ToBytes());
        }
        #endregion
        #region 同步扫描 脚本指令

        #region IFlyADClient 同步
        private bool issync=false;
        public bool IsSync 
        {
            get { return issync; }
            set {
                if (issync != value) 
                {
                    issync = value;
                    NotifyPropertyChanged("IsSync");
                }
            }
        }
        private int lastpos2at01 = 0;
        public int LastPos2At01 
        {
            get {
                return lastpos2at01;    
            }
            protected set {
                if (lastpos2at01 != value)
                {
                    lastpos2at01 = value;
                    NotifyPropertyChanged("LastPos2At01");
                }
            }
        }
        ObservableCollection<SyncOrder> syncorders = new ObservableCollection<SyncOrder>();
        /// <summary>
        /// 同步列表，完成后，会删除
        /// </summary>
        public ObservableCollection<SyncOrder> SyncOrders
        {
            get { return syncorders; }
        }

        #endregion
        //同步扫描至
        //D+0xE0+开始主轴位置+结束主轴位置+结束横向脉冲位置（逻辑位置）+脉冲开关（1B）+命令识标号（4B）
        public void SyncRunAtLC(int pos2_begin, int pos2_end, int pos1lc, bool hasDataGrid, Int32 marker)
        {
            CurrObjSys.CallFunctionEx(
                conn,
                FLYAD7_OBJ_INTERFACE.DRIVE_MAN_INTERFACE.ID,
                ID,
                FLYAD7_OBJ_INTERFACE.DRIVE_MAN_INTERFACE.CALL_PXX,
                new FLYAD7_OBJ_INTERFACE.DRIVE_MAN_INTERFACE.Pack_SyncRunAtLC()
                {
                    pos2_begin = pos2_begin,
                    pos2_end = pos2_end,
                    pos1lc = pos1lc,
                    hasDataGrid = hasDataGrid,
                    marker = marker
                }.ToBytes());

            SyncOrders.Add(new SyncOrder_SyncRunAtLC()
            {
                Pos2Begin = pos2_begin,
                Pos2End = pos2_end,
                Pos1LC = pos1lc,
                HasDataGrid = hasDataGrid,
                Marker = marker
            });
        }

        //7.2	位于队列头时运行，归零
        //D+0xE1+命令识标号（4B）
        public void SyncOrigin(Int32 marker)
        {
            CurrObjSys.CallFunctionEx(
                conn,
                FLYAD7_OBJ_INTERFACE.DRIVE_MAN_INTERFACE.ID,
                ID,
                FLYAD7_OBJ_INTERFACE.DRIVE_MAN_INTERFACE.CALL_PXX,
                new FLYAD7_OBJ_INTERFACE.DRIVE_MAN_INTERFACE.Pack_SyncOrigin()
                {
                    marker = marker
                }.ToBytes());

            SyncOrders.Add(new SyncOrder_SyncOrigin()
            {
                Marker = marker
            });
        }


        //7.3	位于队列头时运行，以速度运行至物理位置
        //D+0xE2+横向脉冲位置（4B：int32，物理位置）+速度（4B：int32）+脉冲开关（1B）+命令识标号（4B）
        public void SyncRunTo(int pos1, UInt32 velocity, bool hasDataGrid, Int32 marker)
        {
            CurrObjSys.CallFunctionEx(
                conn,
                FLYAD7_OBJ_INTERFACE.DRIVE_MAN_INTERFACE.ID,
                ID,
                FLYAD7_OBJ_INTERFACE.DRIVE_MAN_INTERFACE.CALL_PXX,
                new FLYAD7_OBJ_INTERFACE.DRIVE_MAN_INTERFACE.Pack_SyncRunto()
                {
                    pos1 = pos1,
                    velocity = velocity,
                    hasDataGrid = hasDataGrid,
                    marker = marker
                }.ToBytes());

            SyncOrders.Add(new SyncOrder_SyncRunTo()
            {
                Pos1 = pos1,
                Velocity = velocity,
                HasDataGrid = hasDataGrid,
                Marker = marker
            });
        }

        //7.3	位于队列头时运行，以速度运行至逻辑位置
        //D+0xE3+横向脉冲位置（4B：int32，逻辑位置）+速度（4B：int32）+脉冲开关（1B）+命令识标号（4B）
        public void SyncRunToLC(int pos1lc, UInt32 velocity, bool hasDataGrid, Int32 marker)
        {
            CurrObjSys.CallFunctionEx(
                conn,
                FLYAD7_OBJ_INTERFACE.DRIVE_MAN_INTERFACE.ID,
                ID,
                FLYAD7_OBJ_INTERFACE.DRIVE_MAN_INTERFACE.CALL_PXX,
                new FLYAD7_OBJ_INTERFACE.DRIVE_MAN_INTERFACE.Pack_SyncRuntoLC()
                {
                    pos1 = pos1lc,
                    velocity = velocity,
                    hasDataGrid = hasDataGrid,
                    marker = marker
                }.ToBytes());
            SyncOrders.Add(new SyncOrder_SyncRunToLC()
            {
                Pos1 = pos1lc,
                Velocity = velocity,
                HasDataGrid = hasDataGrid,
                Marker = marker
            });
        }


        //7.4	等待，ms
        //D+0xE4+毫秒数（4B：int32）+命令识标号（4B）
        public void SyncWait(int ms, Int32 marker)
        {
            CurrObjSys.CallFunctionEx(
                conn,
                FLYAD7_OBJ_INTERFACE.DRIVE_MAN_INTERFACE.ID,
                ID,
                FLYAD7_OBJ_INTERFACE.DRIVE_MAN_INTERFACE.CALL_PXX,
                new FLYAD7_OBJ_INTERFACE.DRIVE_MAN_INTERFACE.Pack_SyncWait()
                {
                    ms = ms,
                    marker = marker
                }.ToBytes());
            SyncOrders.Add(new SyncOrder_SyncWait()
            {
                MS = ms,
                Marker = marker
            });
        }


        #endregion
        #endregion


        public CorrectADsHandler CorrectADs { get; set; }


        #region 滞后处理
        //一共有1.AD数据池（由timegrid提供） 1min
        //2.pos数据池（pos推送提供） 1min
        //4.当接收的grid事件数据。它有 （direction, grid_start，grid_len, systick )
        //systick 就是结束的时间点。 当AD数据池出现了这个时间点
        
        //pos数据池向前找。 pos 在 grid_start*posOfGrid 范围的数据。 
        //找到开始的systick 后，整合3个数据池的数据。
        //5.最后代替 grid 推送出去。


        int adlag = 0;
        /// <summary>
        /// ad滞后修正  单位ms
        /// </summary>
        public int ADLag
        {
            get
            {
                return adlag;
            }
            set
            {
                if (adlag != value)
                {
                    adlag = value;

                    NotifyPropertyChanged("ADLag");
                }
            }
        }
        class CreateGridAdv
        {

            struct DataTimeUnit
            {
                public int data;
                public DateTime dt;
                public override string ToString()
                {
                    return data.ToString() + " |" + dt.Ticks.ToString();
                }
            }
            struct DataTimeUnit2
            {
                public UInt16 istatus;
                public int pos;
                public DateTime dt;
                public override string ToString()
                {
                    return pos.ToString()+"("+ istatus.ToString("X2") + ") |" + dt.ToString();
                }
            }
            /// <summary>
            /// AD数据池时间间隔为1.28ms, 肯定最少有一个数据
            /// </summary>
            RList<DataTimeUnit> ADPool = new RList<DataTimeUnit>(60000);
            /// <summary>
            /// pos 数据池, 肯定最少有一个数据
            /// </summary>
            RList<DataTimeUnit> PosPool = new RList<DataTimeUnit>(60000);

            /// <summary>
            /// 输入端口 数据池, 肯定最少有一个数据
            /// </summary>
            RList<DataTimeUnit2> IStatusPool = new RList<DataTimeUnit2>(60000);

            class GridData 
            {
                public DIRECTION direction;
                public int pos_start;
                public int pos_len;
                public int marker;
                public DateTime time;
                public GridAdvEventHandler GridAdvFunc;
            }

            GridData mGridData = null;


            FlyAD7 flyad;
            public void Init(FlyAD7 flyad)
            {
                this.flyad = flyad;
                Clear();
            }
            /// <summary>
            /// 添加ad数据，且判断数据量是否够触发事件
            /// </summary>
            /// <param name="ads"></param>
            /// <param name="last_dt"></param>
            public void AddAD(int[] ads, DateTime last_dt)
            {
                //------------------------------------------------------------------------------------------
                //AD数据添加
                DateTime last_dt_last=DateTime.MinValue;
                if (ADPool.Count > 0)
                {
                    last_dt_last = ADPool.Last().dt;
                }
                
                for (int i = 0; i < ads.Count(); i++)
                {
                    DateTime dt;
                    if (last_dt_last != DateTime.MinValue)
                    {
                        dt = last_dt - TimeSpan.FromTicks((long)(ads.Count()-i-1) * (last_dt - last_dt_last).Ticks / ads.Count());
                    }
                    else
                    {
                        TimeSpan ts = TimeSpan.FromTicks((long)(TimeSpan.TicksPerMillisecond * (ads.Count() - 1 - i) * 1.28));
                        dt = last_dt - ts;
                    }
                    ADPool.RAdd(new DataTimeUnit() { data = ads[i], dt = dt });
                }



                //------------------------------------------------------------------------------------------
                //数据触发
                if (mGridData != null)
                {
                    if (last_dt >= mGridData.time)//够时间触发了！！
                    {
                        int start_idx;
                        int end_idx;
                        int start_pos;
                        if (mGridData.direction == DIRECTION.FORWARD)
                        {
                            start_pos = mGridData.pos_start;
                        }
                        else
                        {
                            start_pos = mGridData.pos_start + mGridData.pos_len - 1;
                        }

                        GetIdxFromPosPool(
                            start_pos,mGridData.time, out start_idx, out end_idx);

                        List<GridAdvUnit> result = GetGridAdv(PosPool[start_idx].dt, mGridData.time);

                        mGridData.GridAdvFunc(flyad, new GridAdvEventArgs()
                        {
                            direction = mGridData.direction,
                            pos_start = mGridData.pos_start,
                            pos_len = mGridData.pos_len,
                            marker = mGridData.marker,
                            dt_data = result
                        });
                        mGridData = null;
                    }
                }
            }
            
            public void AddPos(int pos, DateTime time)
            {
                if (PosPool.Count() > 0)
                {
                    if (time < PosPool.Last().dt)
                    {
                        //异常
                        //把前面的都删除
                        PosPool.Clear();
                    }
                    else if (time == PosPool.Last().dt)
                    {
                        return;
                    }
                }
                PosPool.RAdd(new DataTimeUnit() { data = pos, dt = time });
            }

            public void AddIStatus(UInt16 istatus, int pos, DateTime time) 
            {
                if (IStatusPool.Count() > 0)
                {
                    if (time < IStatusPool.Last().dt)
                    {
                        //异常
                        //把前面的都删除
                        IStatusPool.Clear();
                    }
                }
                
                IStatusPool.RAdd(new DataTimeUnit2() { istatus = istatus, pos=pos, dt = time });

                //也添加到 PosPool
                AddPos(pos, time);
            }

            public void AddPos_Default(int pos, DateTime time)
            {
                if (PosPool.Count() == 0)
                {
                    AddPos(pos, time);
                }
            }
            public void AddIStatus_Default(UInt16 istatus, int pos, DateTime time)
            {
                if (IStatusPool.Count() == 0)
                {
                    AddIStatus(istatus, pos, time);
                }
            }
            public void Clear() 
            {
                PosPool.Clear();
                ADPool.Clear();
                IStatusPool.Clear();

                istatus_start_idx = -1;
            }
            
            /// <summary>
            /// 给定结束时间点,开始grid, 找到pos数据池 对应的开始序号 与 结束序号
            /// </summary>
            /// <param name="start_pos">开始脉冲</param>
            /// <param name="endtime">结束时间点</param>
            /// <param name="start_idx">输出 pos数据池开始序号</param>
            /// <param name="end_idx">输出 pos数据池结束序号</param>
            /// <returns>false 发生在数据池前面， true成功获取</returns>
            bool GetIdxFromPosPool(int start_pos, DateTime endtime, out int start_idx, out int end_idx)
            {
                start_idx = -1;
                end_idx = -1;
                
                for (int i = 0; i < PosPool.Count(); i++)
                {
                    int idx = PosPool.Count() - 1 - i;
                    if (PosPool[idx].dt <= endtime)
                    {
                        //从这个点开始找
                        end_idx = idx;
                        break;
                    }
                }
                if (end_idx == -1)
                {
                    //endtime 发生在过去很久以前
                    return false;
                }
                
                int pos_last = int.MinValue;
                int i_last = -1;
                for (int i = end_idx; i >= 0; i--)
                {

                    int pos = PosPool[i].data;

                    //if (pos == start_pos)//找到了！！！！
                    //{
                    //    pos_last = pos;
                    //    continue;
                    //}

                    if (pos_last == int.MinValue)
                    {
                        pos_last = pos;
                        i_last = i;
                        continue;
                    }

                    if (pos_last == pos)
                    {
                        continue;
                    }

                    if (Math.Abs(pos - start_pos) > Math.Abs(pos_last - start_pos))
                    {
                        //越找越远，
                        //上一个就是了
                        start_idx = i_last;
                        return true;
                    }
                    else if (Math.Abs(pos - start_pos) == Math.Abs(pos_last - start_pos))
                    {
                        //跨过了
                        start_idx = i_last;
                        return true;
                    }

                    pos_last = pos;
                    i_last = i;
                }
                //找完
                start_idx = 0;
                return true;
            }


            /// <summary>
            /// 上一次查找istatus的序号
            /// </summary>
            int istatus_start_idx = -1;
            /// <summary>
            /// 根据时间点，获取输入口状态
            /// </summary>
            /// <param name="time"></param>
            /// <param name="start_idx">用于加快查找速度</param>
            /// <returns></returns>
            UInt16 GetIStatus(DateTime time)
            {
                int start_idx = istatus_start_idx;
                if (start_idx >= 0 && start_idx < IStatusPool.Count())
                {
                    for (int i = start_idx; i >= 0; i--)
                    {
                        int idx = i;
                        if (time >= IStatusPool[idx].dt)
                        {
                            if (idx == start_idx)//有可能start_idx 位置 本来就在前面，看看后面再决定 
                            {
                                for (int j = start_idx + 1; j < IStatusPool.Count(); j++)
                                {
                                    idx = j;
                                    if (time < IStatusPool[idx].dt)
                                    {
                                        //找到了
                                        istatus_start_idx = idx - 1;
                                        return (UInt16)IStatusPool[istatus_start_idx].istatus;
                                    }
                                }
                                //找到最后
                                istatus_start_idx = idx;
                                return (UInt16)IStatusPool[istatus_start_idx].istatus;
                            }
                            //找到
                            istatus_start_idx = idx;
                            return (UInt16)IStatusPool[istatus_start_idx].istatus;
                        }
                    }

                }
                else
                {
                    //没有以前的记录
                    //从列表的后面向前查找
                    for (int i = 0; i < IStatusPool.Count(); i++)
                    {
                        int idx = IStatusPool.Count() - 1 - i;
                        if (time >= IStatusPool[idx].dt)
                        {
                            //找到
                            istatus_start_idx = idx;
                            return (UInt16)IStatusPool[istatus_start_idx].istatus;
                        }
                    }
                }

                //在前面发生的！！！
                if (IStatusPool.Count() > 0)
                {
                    istatus_start_idx = 0;
                    return (UInt16)IStatusPool[istatus_start_idx].istatus;
                }
                else
                {
                    //异常，一个数据都没有
                    istatus_start_idx = -1;
                    return (UInt16)0xff;
                }
                
            }

            /// <summary>
            /// 根据时间点，获取输入口状态
            /// </summary>
            /// <param name="time"></param>
            /// <param name="start_idx">用于加快查找速度</param>
            /// <returns></returns>
            UInt16 GetIStatus(DateTime time, out int istatus_idx)
            {
                UInt16 istatus = GetIStatus(time);
                istatus_idx = istatus_start_idx;
                return istatus;
            }

            /// <summary>
            /// 以 [idx，idx+1] 的比例， 给出 time 计算 pos 
            /// </summary>
            /// <param name="time"></param>
            /// <param name="idx"></param>
            /// <returns></returns>
            int GetPos(DateTime time, int idx)
            {
                if (PosPool.Count() < 0)
                    return int.MinValue;

                if (PosPool.Count() == 1)
                    return PosPool[0].data;

                if (idx < 0)
                    idx = 0;

                if (idx >= PosPool.Count())
                    idx = PosPool.Count() - 2;

                double d_pos = PosPool[idx].data - PosPool[idx + 1].data;

                TimeSpan ts = PosPool[idx].dt - PosPool[idx + 1].dt;
                double p = d_pos * (time - PosPool[idx + 1].dt).Ticks / ts.Ticks;

                return (int)(p + PosPool[idx + 1].data);
            }

            /// <summary>
            /// 获取时间对应的 位置点
            /// </summary>
            /// <param name="dt"></param>
            /// <returns></returns>
            int GetPos(DateTime dt)
            {
                int index = -1;
                for (int i = 0; i < PosPool.Count(); i++)//从后面开始查找
                {
                    int idx = PosPool.Count() - 1 - i;
                    if (PosPool[idx].dt <= dt)
                    {
                        //找到了
                        index = idx;
                        break;
                    }
                }

                if (index == PosPool.Count() - 1) 
                {
                    index = index -1;
                }
                else if(index == -1)
                {
                    index = 0;
                }

                return GetPos(dt, index);
            }


            List<GridAdvUnit> GetGridAdv(DateTime start_dt, DateTime end_dt) 
            {
                List<GridAdvUnit> result = new List<GridAdvUnit>();
               
                for(int i=0;i<ADPool.Count();i++)
                {
                    int idx = ADPool.Count()-1-i;
                    if(ADPool[idx].dt<start_dt)
                    {
                        break;
                    }
                    else if(ADPool[idx].dt<=end_dt)
                    {
                        GridAdvUnit u = new GridAdvUnit();
                        u.dt = ADPool[idx].dt;
                        u.ad = ADPool[idx].data;

                        u.pos = GetPos(u.dt);
                        u.istatus = GetIStatus(u.dt);
                        result.Add(u);
                    }
                }
                result.Reverse();
                return result;
            }


            /// <summary>
            /// 记下grid
            /// </summary>
            /// <param name="direction">一幅grid数据 方向</param>
            /// <param name="pos_start">脉冲开始位置</param>
            /// <param name="pos_len">脉冲长度</param>
            /// <param name="marker">记录号</param>
            /// <param name="dt">时间点</param>
            /// <param name="func">当够数据，触发gridadv 回调</param>
            public void MarkGrid(DIRECTION direction, int pos_start, int pos_len, int marker, DateTime dt,
                GridAdvEventHandler func) 
            {
                mGridData = new GridData()
                {
                    direction = direction,
                    pos_start = pos_start,
                    pos_len = pos_len,
                    marker = marker,
                    time = dt,
                    GridAdvFunc = func
                };


            }




            #region 子功能，grid 的 istatus 变化

            class gridistatuspush
            {
                public int istatus_no;
                public event GridIStatusEventHander GridIStatusEvent;
                public void Notify(object sender, GridIStatusEventArgs e) 
                {
                    if (GridIStatusEvent != null) 
                    {
                        GridIStatusEvent.Invoke(sender, e);
                    }
                }
                public bool IsNoEvent()
                {
                    if (GridIStatusEvent == null)
                        return true;
                    else
                        return false;
                }
            }
            List<gridistatuspush> mGridIStatusEventList = new List<gridistatuspush>();

            /// <summary>
            /// 添加事件
            /// </summary>
            /// <param name="istatus_no"></param>
            /// <param name="func"></param>
            public void GridIStatusEventAdd(int istatus_no, GridIStatusEventHander func)
            {
                var gs = from _g in mGridIStatusEventList
                         where _g.istatus_no == istatus_no
                         select _g;
                gridistatuspush g;
                if (gs.Count() > 0)
                {
                    g = gs.First();
                    g.GridIStatusEvent += func;
                }
                else
                {
                    g = new gridistatuspush() { istatus_no = istatus_no };
                    g.GridIStatusEvent += func;
                    mGridIStatusEventList.Add(g);
                }
            }
            /// <summary>
            /// 删除事件
            /// </summary>
            /// <param name="istatus_no"></param>
            /// <param name="func"></param>
            public void GridIStatusEventDel(int istatus_no, GridIStatusEventHander func)
            {
                var gs = from _g in mGridIStatusEventList
                         where _g.istatus_no == istatus_no
                         select _g;
                gridistatuspush g;
                if (gs.Count() > 0)
                {
                    g = gs.First();
                    g.GridIStatusEvent -= func;
                    if (g.IsNoEvent())
                    {
                        mGridIStatusEventList.Remove(g);
                    }
                }
            }

            /// <summary>
            /// 触发GridIStatusEvent事件
            /// </summary>
            /// <param name="direction"></param>
            /// <param name="pos_start"></param>
            /// <param name="pos_len"></param>
            /// <param name="marker"></param>
            /// <param name="dt"></param>
            public void NotifyGridIStatusEvent(DIRECTION direction, int pos_start, int pos_len, int marker, DateTime dt) 
            {
                if (mGridIStatusEventList.Count() <= 0)
                    return;

                int start_idx;
                int end_idx;
                int start_pos;
                int end_pos;
                if (direction == DIRECTION.FORWARD)
                {
                    start_pos = pos_start;
                    end_pos = pos_start + pos_len - 1;
                }
                else
                {
                    start_pos = pos_start + pos_len - 1;
                    end_pos = pos_start;
                }



                bool ret = GetIdxFromPosPool(
                    start_pos, dt, out start_idx, out end_idx);
                if (ret == false)//异常
                    return;

                DateTime start_dt = PosPool[start_idx].dt;
                DateTime end_dt = dt;

                foreach (gridistatuspush g in mGridIStatusEventList) 
                {
                    List<Range> data0;
                    List<Range> data1;

                    
                    GetIStatusRange(
                        g.istatus_no , start_dt, end_dt,
                        direction, start_pos, end_pos,
                        out data0, out data1);
                    g.Notify(flyad, new GridIStatusEventArgs()
                    {
                        direction = direction,
                        istatus_no = g.istatus_no,
                        marker = marker,
                        pos_start = pos_start,
                        pos_len = pos_len,
                        data_0 = data0,
                        data_1 = data1
                    });
                }
            }


            void GetIStatusRange(
                int istatus_no, 
                DateTime start_dt, DateTime end_dt, 
                DIRECTION direction, int start_pos, int end_pos, 
                out List<Range> data0, out List<Range> data1)
            {
                data0 = new List<Range>();
                data1 = new List<Range>();

                istatus_start_idx = -1;
                int istatus_idx;
                UInt16 istatus = GetIStatus(start_dt, out istatus_idx);

                if (istatus_idx == -1)//异常，列表没有数据
                { 
                    //全部都是1
                    if (direction == DIRECTION.FORWARD)
                        data1.Add(new Range() { Begin = start_pos, End = end_pos });
                    else
                        data1.Add(new Range() { Begin = end_pos, End = start_pos });

                    return;
                }
                bool istatus_no_b = Misc.MyBase.CHECKBIT(istatus, istatus_no - 1);

                Range r = new Range();
                
                r.Begin = start_pos;

                for (int i = istatus_idx + 1; i < IStatusPool.Count(); i++)
                {
                    istatus = IStatusPool[i].istatus;
                    int pos = IStatusPool[i].pos;
                    bool b = Misc.MyBase.CHECKBIT(istatus, istatus_no - 1);
                    if (IStatusPool[i].dt >= end_dt)
                    {
                        //结束，这是最后！！！
                        break;
                    }
                    else
                    {
                        if (b != istatus_no_b)
                        {
                            r.End = pos;
                            if (istatus_no_b)
                                data1.Add(r);
                            else
                                data0.Add(r);
                            istatus_no_b = b;
                            r = new Range();
                            r.Begin = pos;
                        }
                    }
                }
                r.End = end_pos;
                if (istatus_no_b)
                    data1.Add(r);
                else
                    data0.Add(r);

                if (direction == DIRECTION.FORWARD)
                {
                    for (int i = 0; i < data0.Count(); i++)
                    {
                        data0[i].End -= 1;
                    }
                    for (int i = 0; i < data1.Count(); i++)
                    {
                        data1[i].End -= 1;
                    }
                }
                else 
                {
                    for (int i = 0; i < data0.Count(); i++)
                    {
                        
                        data0[i].End += 1;
                        int t = data0[i].End;
                        data0[i].End = data0[i].Begin;
                        data0[i].Begin = t;
                    }
                    data0.Reverse();


                    for (int i = 0; i < data1.Count(); i++)
                    {
                        data1[i].End += 1;
                        int t = data1[i].End;
                        data1[i].End = data1[i].Begin;
                        data1[i].Begin = t;
                    }
                    data1.Reverse();
                }
            }
            #endregion
        }


        CreateGridAdv mCreateGridAdv = new CreateGridAdv();

        public event GridAdvEventHandler GridAdvEvent;

        public static GridAdvUnit[] TimeUnit2PosUnit(Misc.DIRECTION direction, int pos_start, int pos_len, List<GridAdvUnit> dt_data) 
        {
            GridAdvUnit[] pos_data = new GridAdvUnit[pos_len];

            int ad_sum = 0;
            int ad_cnt = 0;
            int last_pos_idx = -1;
            DateTime st_dt = DateTime.MinValue;
            DateTime ed_dt = DateTime.MinValue;
            UInt16 istatus = 0xff; 

            for (int i = 0; i < dt_data.Count(); i++) 
            {
                int pos_idx = dt_data[i].pos  - pos_start;
                if ((pos_idx < 0) || (pos_idx >= pos_len))//保存上一数据
                {
                    if (ad_cnt > 0)
                    {
                        GridAdvUnit u = new GridAdvUnit();
                        u.dt = st_dt.AddTicks((ed_dt - st_dt).Ticks / 2);
                        u.ad = ad_sum / ad_cnt;
                        u.pos = last_pos_idx + pos_start;
                        u.istatus = istatus;
                        pos_data[last_pos_idx] = u;
                    }


                    ad_sum = 0;
                    ad_cnt = 0;
                    istatus = 0xff;
                    last_pos_idx = -1;
                    st_dt = DateTime.MinValue;
                    ed_dt = DateTime.MinValue;
                }
                else if (last_pos_idx == pos_idx)//还是同一个数据
                {
                    ad_sum += dt_data[i].ad;
                    ad_cnt++;
                    istatus &= dt_data[i].istatus;
                    ed_dt = dt_data[i].dt;
                }
                else 
                {
                    if (last_pos_idx != -1)//保存上一个数据
                    {
                        GridAdvUnit u = new GridAdvUnit();
                        u.dt = st_dt.AddTicks((ed_dt - st_dt).Ticks / 2);
                        u.ad = ad_sum / ad_cnt;
                        u.pos = last_pos_idx + pos_start;
                        u.istatus = istatus;
                        pos_data[last_pos_idx] = u;
                    }

                    last_pos_idx = pos_idx;
                    st_dt = dt_data[i].dt;
                    ed_dt = dt_data[i].dt;
                    ad_sum = dt_data[i].ad;
                    ad_cnt = 1;
                    istatus = dt_data[i].istatus;
                }
            }

            if (last_pos_idx != -1)//保存上一个数据
            {
                GridAdvUnit u = new GridAdvUnit();
                u.dt = st_dt.AddTicks((ed_dt - st_dt).Ticks / 2);
                u.ad = ad_sum / ad_cnt;
                u.pos = last_pos_idx + pos_start;
                u.istatus = istatus;
                pos_data[last_pos_idx] = u;
            }

            return pos_data;
        }
        #endregion


        #region runto 推送 istatus 变化

        public void GridIStatusEventAdd(int istatus_no, GridIStatusEventHander func) 
        {
            mCreateGridAdv.GridIStatusEventAdd(istatus_no, func);
        }
        public void GridIStatusEventDel(int istatus_no, GridIStatusEventHander func) 
        {
            mCreateGridAdv.GridIStatusEventDel(istatus_no, func);
        }


        #endregion
    }
}
