using AutoMapper;
using FObjBase;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;

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


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

        #endregion
        #region IFlyADClient property
        /// <summary>
        /// 连接成功
        /// </summary>
        public bool IsConnected { get; private set; }

        /// <summary>
        /// 重连次数
        /// </summary>
        public int ConnectCnt { get; private set; }

        /// <summary>
        /// CRC
        /// </summary>
        public bool HasCRC { get; set; }



        /// <summary>
        /// 已经从AD盒获取全部当前数据
        /// </summary>
        public bool IsReady { get; protected set; }

        /// <summary>
        ///  通过判断systick，判断AD盒是否发生重启;
        ///  BeReseted为上一次被复位时间
        /// </summary>
        public DateTime BeResetTime { get; private set; }
        /// <summary>
        /// 用于同步， 最后一次 纵向信号 0->1 时，主轴脉冲
        /// </summary>
        public bool IsSync { get; protected set; }

        /// <summary>
        /// 只要connect成功，获取systick被复位，都会从AD盒设备读取参数；
        /// 否则， 设置参数 到 AD盒
        /// </summary>
        public bool IsReadParamFromDev { get; set; }
        /// <summary>
        /// 保存的设备参数有效
        /// </summary>
        public bool IsDevParamValid { get; set; }

        /// <summary>
        /// 同步列表，完成后，会删除
        /// </summary>
        public ObservableCollection<SyncOrder> SyncOrders { get; } = new ObservableCollection<SyncOrder>();

        #endregion
        #region IFlyAD property


        /// <summary>
        /// AD盒地址
        /// </summary>
        public string Addr { get; set; } = "192.168.251.10:20006";
        IPEndPoint LocalEP => Misc.StringConverter.ToIPEndPoint(Addr);

        /// <summary>
        /// 从flyad7 获取 的systick 转换的时间
        /// </summary>
        public DateTime Now { get; private set; }

        /// <summary>
        /// AD盒版本号 版本1 没有systick;版本2 有systick;
        /// </summary>
        public int Version
        {
            get
            {
                if (pos1_version == 2
                    && timegrid_version == 2
                    && grid_version == 2)
                    return 2;
                else
                    return 1;
            }
        }

        /// <summary>
        /// 硬件版本，设置的！！！
        /// </summary>
        public int HardwareVersion { get; set; } = 2;
        /// <summary>
        /// 脉冲
        /// </summary>
        public int Position { get; private set; }

        /// <summary>
        /// 速度 pps
        /// </summary>
        public int Speed { get; private set; }

        /// <summary>
        /// 纵向脉冲，也叫主轴脉冲
        /// </summary>
        public int Position2 { get; private set; }
        /// <summary>
        /// 纵向脉冲速度, pps, 1秒脉冲数
        /// </summary>
        public int Speed2 { get; private set; }

        /// <summary>
        /// 1000ms从AD卡获取(或推送)1个AD值。此AD值只用于调试，定点
        /// </summary>
        public int AD { get; private set; }


        /// <summary>
        /// AD值最大值 ，恒定返回65535
        /// </summary>
        public int ADMax => 0xFFFF;

        /// <summary>
        /// 输入口状态,只有12位有效, 大AD盒 16位
        /// </summary>
        public UInt16 IStatus { get; private set; } = 0xffff;

        /// <summary>
        /// 输出口状态,只有4位有效, 大AD盒 8位
        /// </summary>
        public UInt16 OStatus { get; private set; } = 0xffff;


        /// <summary>
        /// 电机类型
        /// </summary>
        public MOTORTYPE MotorType { get; set; } = MOTORTYPE.SERVO;

        private UInt16 posofgrid = 10;
        /// <summary>
        /// 脉冲/grid, 最大1000个grid
        /// </summary>
        public UInt16 PosOfGrid
        {
            get { return posofgrid; }
            set
            {
                if (value < 1)
                    value = 1;

                if (posofgrid != value)
                    posofgrid = value;

            }
        }


        /// <summary>
        /// 脉冲比例 分母(电机脉冲)
        /// </summary>
        public UInt16 Ratio01 { get; set; } = 4;

        /// <summary>
        /// 脉冲比例 分子(编码器脉冲)
        /// </summary>
        public UInt16 Ratio02 { get; set; } = 1;

        /// <summary>
        /// 脉冲平移(0位处脉冲值)
        /// </summary>
        public Int16 PosOffset { get; set; }

        /// <summary>
        /// 手动速度 pps
        /// </summary>
        public UInt32 JogVelocity { get; set; } = 5000;

        /// <summary>
        /// runto 速度 pps
        /// </summary>
        public UInt32 Velocity { get; private set; } = 8000;

        /// <summary>
        /// 开始速度 pps
        /// </summary>
        public UInt32 SVelocity { get; private set; } = 200;

        /// <summary>
        /// 加速时间 ms
        /// </summary>
        public UInt32 ATime { get; private set; } = 300;

        /// <summary>
        /// 减速时间 ms
        /// </summary>
        public UInt32 DTime { get; private set; } = 200;

        /// <summary>
        /// 归0 第1段速 pps
        /// </summary>
        public UInt32 HVelocity1 { get; private set; } = 4000;

        /// <summary>
        /// 归0 第2段速 pps
        /// </summary>
        public UInt32 HVelocity2 { get; private set; } = 500;


        /// <summary>
        /// 使用码区状态
        /// </summary>
        public AREA_STATUS AreaStatus { get; set; }

        /// <summary>
        /// 使用码区出错码
        /// </summary>
        public AREA_ERR AreaRet { get; set; }

        /// <summary>
        /// 序列码byte[6]
        /// </summary>
        public byte[] Code { get; } = new byte[7];


        /// <summary>
        /// //系统剩余时间
        /// </summary>
        public int Surplus { get; set; } = 0xffff;
        /// <summary>
        /// 系统授权码
        /// </summary>
        public byte[] Access { get; } = new byte[8];


        /// <summary>
        /// 当前运行指令
        /// </summary>
        public DRIVE_MAN_ORDER DriveOrder { get; set; } = DRIVE_MAN_ORDER.IDLE;

        /// <summary>
        /// 之前运行动作的状态
        /// </summary>
        public DRIVE_MAN_STATUS DriveStatus { get; set; } = DRIVE_MAN_STATUS.STOP;

        /// <summary>
        /// 同步用标示
        /// </summary>
        public Int32 Marker { get; protected set; }


        /// <summary>
        /// 逻辑横向脉冲偏移  Pos1 + Pos1LCShift = Pos1LC
        /// </summary>
        public int Pos1LCShift { get; set; }
        /// <summary>
        /// 逻辑纵向脉冲偏移  Pos2 + Pos2LCShift = Pos2LC
        /// </summary>
        public int Pos2LCShift { get; set; }

        /// <summary>
        /// timegrid 事件; 版本1: 1.28s 一次; 版本2: 0.2s一次， 
        /// ad值不会被机架修正
        /// </summary>
        public event TimeGridEventHandler TimeGridEvent;



        /// <summary>
        /// runto 中，每经过1个grid 推送数据
        /// </summary>
        public event MiniGridEventHandler MiniGridEvent;

        /// <summary>
        /// runto 的 grid事件
        /// </summary>
        public event MiniGridEventHandler GridEvent;

        /// <summary>
        /// 输入状态改变事件
        /// </summary>
        public event IStatusChangedEventHandler IStatusChangedEvent;

        /// <summary>
        /// 指令状态改变事件
        /// </summary>
        public event DriveStatusChangedEventHandler DriveStatusChangedEvent;

        /// <summary>
        /// 脉冲1改变事件
        /// </summary>
        public event PositionChangedEventHandler PositionChangedEvent;

        /// <summary>
        /// 脉冲2改变事件
        /// </summary>
        public event PositionChangedEventHandler Position2ChangedEvent;

        #endregion


        private int pos1_version { get; set; } = 2;
        private int io_version { get; set; } = 2;
        private int timegrid_version { get; set; } = 2;
        private int grid_version { get; set; } = 2;

        TCPCConn conn = null;
        /// <summary>
        /// 不设置服务器
        /// </summary>
        bool bShieldSetValueEx = false;


        /// <summary>
        /// 刚发送了运行指令，正常情况 AD盒会立刻推送状态给电脑，
        /// 但怕它不推送，等3秒，再问它获取一次。
        /// </summary>
        DtAndBool driveman_wait = new DtAndBool();
        /// <summary>
        /// 用于检测当 为IsRunning时，脉冲是否停了很久。
        /// </summary>
        int last_position = int.MinValue;
        /// <summary>
        /// 脉冲不变化次数
        /// </summary>
        int position_no_changed_cnt = 0;


        TimeSpan NoTGridTimeOut = TimeSpan.FromSeconds(60);
        Stopwatch stopwatch_noTGrid = new Stopwatch();




        IsReadyContext isReadyContext = new IsReadyContext();
        SysTickContext sysTickContext = new SysTickContext();
        CalSpeed calSpeed = new CalSpeed();
        static string[] propertyName_save;

        string defaultPath = "flyad.json";
        string jsonDbPath;

        DateTime lastTimeGridTime;
        static FlyAD7()
        {
            propertyName_save = FlyAD7JsonDb.GetMemberNames();
        }
        /// <summary>
        /// 
        /// </summary>
        public FlyAD7()
        {
            constructor();
            advConstructor();
        }
        void constructor()
        {
            Now = DateTime.Now;
            //sysTickContext.BeReseted += () => BeResetTime = DateTime.Now;

            this.PropertyChanged += new PropertyChangedEventHandler(FlyAD7_PropertyChanged);

            //每隔一个小时，改变剩下时间
            PollModule.Current.Poll_Config(PollModule.POLL_CONFIG.ADD, () =>
            {
                if (!IsConnected)
                    return;
                if (Surplus < 60000)
                {
                    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);
                    }
                }
            }, TimeSpan.FromMinutes(60));

            //60秒内收不到1个timegrid ，就会重连
            PollModule.Current.Poll_Config(PollModule.POLL_CONFIG.ADD,
                () =>
                {
                    if (!IsConnected)
                    {
                        stopwatch_noTGrid.Stop();
                    }
                    else
                    {
                        if (!stopwatch_noTGrid.IsRunning)
                            stopwatch_noTGrid.Restart();
                        else
                        {
                            if (stopwatch_noTGrid.Elapsed > NoTGridTimeOut)
                            {
                                logger.Error("60秒都无法接收到ad盒的timegrid,reconnect");
                                ReConnect();
                                stopwatch_noTGrid.Restart();
                            }
                        }
                    }
                }, TimeSpan.FromSeconds(1));

            //每隔1秒发送一次 GetIO
            PollModule.Current.Poll_Config(PollModule.POLL_CONFIG.ADD, () =>
            {
                if (!IsConnected)
                    return;

                //FLYIO
                CurrObjSys.GetValueEx(
                    conn,
                    FLYAD7_OBJ_INTERFACE.FLYIO_OBJ_INTERFACE.ID,
                    ID,
                    FLYAD7_OBJ_INTERFACE.FLYIO_OBJ_INTERFACE.GET_IO);
            }, TimeSpan.FromSeconds(1));

            //更新线速度
            PollModule.Current.Poll_Config(PollModule.POLL_CONFIG.ADD,
                () =>
                {
                    if (calSpeed.Cal(Now, out int speed1, out int speed2))
                    {
                        Speed = speed1;
                        Speed2 = speed2;
                    }

                }, TimeSpan.FromSeconds(1));

            //当状态为Running时,且每秒脉冲没变，需要 查 当前的状态， 也许Stop状态少推送了
            PollModule.Current.Poll_Config(PollModule.POLL_CONFIG.ADD,
                () =>
                {
                    if (!IsConnected)
                    {
                        position_no_changed_cnt = 0;
                        return;
                    }

                    if (DriveStatus != DRIVE_MAN_STATUS.RUNNING)
                    {
                        position_no_changed_cnt = 0;
                        return;
                    }

                    if (Position != last_position)
                    {
                        last_position = Position;
                        position_no_changed_cnt = 0;
                        return;
                    }
                    position_no_changed_cnt++;
                    if (position_no_changed_cnt >= 10)
                    {
                        //连续10秒，脉冲一样
                        //异常
                        DriveStatus = DRIVE_MAN_STATUS.STOP_MANUAL;
                        position_no_changed_cnt = 0;
                        return;
                    }
                    if (driveman_wait.CheckMark(TimeSpan.FromSeconds(2)))//每2秒检查一次
                    {
                        driveman_wait.Mark();
                        CurrObjSys.GetValueEx(
                            conn,
                            FLYAD7_OBJ_INTERFACE.DRIVE_MAN_INTERFACE.ID,
                            ID,
                            FLYAD7_OBJ_INTERFACE.DRIVE_MAN_INTERFACE.GET_STATE);
                    }

                }, TimeSpan.FromSeconds(1));

            Misc.BindingOperations.SetBinding(isReadyContext, nameof(isReadyContext.IsReady), this, nameof(IsReady));
        }


        void FlyAD7_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == nameof(HasCRC))
            {
                if (conn != null)
                    conn.HasCRC = HasCRC;
            }

            if (bShieldSetValueEx)
                return;

            if ((e.PropertyName == nameof(PosOffset)) ||
                (e.PropertyName == nameof(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 == nameof(MotorType)) ||
                    (e.PropertyName == nameof(PosOfGrid)) ||
                    (e.PropertyName == nameof(Ratio01)) ||
                    (e.PropertyName == nameof(Ratio02)))
            {
                FObjBase.PollModule.Current.Poll_JustOnce(
                    delegate ()
                    {
                        SetSysParam(PosOfGrid, MotorType, Ratio01, Ratio02);
                    }, this, MARKNO_SET_SYSPARAM);
            }
            else if (e.PropertyName == nameof(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 == nameof(Pos2LCShift))
            {

                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 = Pos2LCShift
                    }.ToBytes());
            }
        }

        /// <summary>
        /// 连接后初始化
        /// </summary>
        void AfterConnected()
        {
            //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);

            //注册全部推送事件
            CurrObjSys.SenseConfigEx(
                conn,
                FLYAD7_OBJ_INTERFACE.PUSH_DATA_INTERFACE.ID,
                ID,
                0xffffffff,
                SENSE_CONFIG.ADD);


            if (IsReadParamFromDev || !IsDevParamValid)
            {
                //读取全部参数！！！！！
                //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);
            }
            else
            {
                //参数不保存在设备中， 保存在电脑。
                //参数写入到设备。
                NotifyPropertyChanged(nameof(MotorType));
                NotifyPropertyChanged(nameof(PosOfGrid));
                NotifyPropertyChanged(nameof(Ratio01));
                NotifyPropertyChanged(nameof(Ratio02));
                NotifyPropertyChanged(nameof(PosOffset));
                NotifyPropertyChanged(nameof(JogVelocity));
            }

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

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

            CurrObjSys.GetValueEx(
                conn,
                FLYAD7_OBJ_INTERFACE.DRIVE_MAN_INTERFACE.ID,
                ID,
                FLYAD7_OBJ_INTERFACE.DRIVE_MAN_INTERFACE.GET_SYNC_ORDER_CNT);

            CurrObjSys.GetValueEx(
                conn,
                FLYAD7_OBJ_INTERFACE.DRIVE_MAN_INTERFACE.ID,
                ID,
                FLYAD7_OBJ_INTERFACE.DRIVE_MAN_INTERFACE.GET_SYNC_STATUS);

            //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(nameof(Pos1LCShift));//写入到AD盒
            NotifyPropertyChanged(nameof(Pos2LCShift));//写入到AD盒


            SyncClear();
            SyncEnd();

            isReadyContext.Reset();
            sysTickContext.Reset();
            calSpeed.Reset();
            lastTimeGridTime = DateTime.MinValue;

            advAfterContected();
        }

        #region FObj
        public override void ConnectNotify(IFConn from)
        {
            IsConnected = from.IsConnected;
            if (IsConnected)
            {
                ConnectCnt++;
                BeResetTime = DateTime.Now;
                AfterConnected();
            }
            else
            {
                DriveOrder = DRIVE_MAN_ORDER.IDLE;
                DriveStatus = DRIVE_MAN_STATUS.STOP;
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="from"></param>
        /// <param name="srcid"></param>
        /// <param name="memid"></param>
        /// <param name="infodata"></param>
        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:
                                {
                                    var pack = new FLYAD7_OBJ_INTERFACE.FLYADC_OBJ_INTERFACE.Pack_GetPos1AD1();
                                    if (!pack.TryParse(infodata))
                                        break;
                                    Position = pack.pos;
                                    //AD = pack.ad;
                                    advGetPos1AD1(pack.ad);

                                    isReadyContext.isReadyGetPos1AD1 = true;
                                }
                                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;

                                    advGetPos2();

                                    isReadyContext.isReadyGetPos2 = true;
                                }
                                break;
                        }
                    }
                    break;
                case FLYAD7_OBJ_INTERFACE.FLYIO_OBJ_INTERFACE.ID:
                    {
                        switch (memid)
                        {
                            case FLYAD7_OBJ_INTERFACE.FLYIO_OBJ_INTERFACE.GET_IO:
                                {
                                    var pack = new FLYAD7_OBJ_INTERFACE.FLYIO_OBJ_INTERFACE.Pack_GetIO();
                                    if (!pack.TryParse(infodata))
                                        break;

                                    IStatus = pack.istatus;
                                    OStatus = pack.ostatus;

                                    advGetIo();

                                    isReadyContext.isReadyGetIO = true;
                                }
                                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:
                                {
                                    int version;
                                    FLYAD7_OBJ_INTERFACE.DRIVE_MAN_INTERFACE.Pack_DriveState_2 pack = new FLYAD7_OBJ_INTERFACE.DRIVE_MAN_INTERFACE.Pack_DriveState_2();
                                    if (!pack.TryParse_version(infodata, out version))
                                        break;

                                    if (version == 1)
                                    {
                                        DriveOrder = pack.order;
                                        DriveStatus = pack.status;
                                    }
                                    else if (version == 2)
                                    {
                                        DriveOrder = pack.order;
                                        DriveStatus = pack.status;
                                        Marker = pack.marker;

                                        advGetState();
                                    }

                                    isReadyContext.isReadyGetState = true;
                                }
                                break;
                            case FLYAD7_OBJ_INTERFACE.DRIVE_MAN_INTERFACE.GET_SYNC_STATUS:
                                {
                                    FLYAD7_OBJ_INTERFACE.DRIVE_MAN_INTERFACE.Pack_SyncStatus p = new FLYAD7_OBJ_INTERFACE.DRIVE_MAN_INTERFACE.Pack_SyncStatus();
                                    if (!p.TryParse(infodata))
                                        break;
                                    //TODO
                                }
                                break;
                            case FLYAD7_OBJ_INTERFACE.DRIVE_MAN_INTERFACE.GET_SYNC_ORDER_CNT:
                                {
                                    FLYAD7_OBJ_INTERFACE.DRIVE_MAN_INTERFACE.Pack_SyncOrderCnt p = new FLYAD7_OBJ_INTERFACE.DRIVE_MAN_INTERFACE.Pack_SyncOrderCnt();
                                    if (!p.TryParse(infodata))
                                        break;
                                    //TODO
                                }
                                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;
                                    IsDevParamValid = true;
                                }
                                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(nameof(Code));

                                    Surplus = pack.surplus;

                                    Array.Copy(pack.access, Access, pack.access.Length);
                                    NotifyPropertyChanged(nameof(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;
                                    IsDevParamValid = true;
                                }
                                break;
                        }
                    }
                    break;
            }
            bShieldSetValueEx = false;
        }



        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;
                        pos1_version = version;

                        if (version == 1)
                        {
                            Position = pack.pos1;
                            Now = DateTime.Now;
                        }
                        else if (version == 2)
                        {
                            Position = pack.pos1;
                            DateTime dt = sysTickContext.ToDateTime(pack.systick);
                            Now = dt;

                            PositionChangedEvent?.Invoke(this, new PositionChangedEventArgs() { Time = dt, Position = Position });
                        }
                        calSpeed.SetPos1(Now, Position);

                        advPushPos1(version);
                    }
                    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;

                        if (version == 1)
                        {
                            Position2 = pack.pos2;
                            Now = DateTime.Now;
                        }
                        else if (version == 2)
                        {
                            Position2 = pack.pos2;
                            DateTime dt = sysTickContext.ToDateTime(pack.systick);
                            Now = dt;

                            Position2ChangedEvent?.Invoke(this, new PositionChangedEventArgs() { Time = dt, Position = Position });
                        }
                        calSpeed.SetPos2(Now, Position2);

                        advPushPos2(version);
                    }
                    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;

                        //AD = pack.AD;
                        advPushAd(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;
                        io_version = version;
                        if (version == 1)
                        {
                            UInt16 inchange = (UInt16)(IStatus ^ pack.istatus);
                            IStatus = pack.istatus;
                            OStatus = pack.ostatus;
                            Now = DateTime.Now;

                            IStatusChangedEvent?.Invoke(
                                this,
                                new IStatusChangedEventArgs(
                                    Now,
                                    IStatus,
                                    inchange,
                                    Position,
                                    Position2));
                        }
                        else if (version == 2)
                        {
                            if (pack.inChange == 0)
                            {
                                //异常包，， 这个是AD盒的bug,  systick 是错的！！！！！ 不能让它通过
                                return;
                            }
                            IStatus = pack.istatus;
                            OStatus = pack.ostatus;
                            Position = pack.pos1;
                            Position2 = pack.pos2;
                            DateTime dt = sysTickContext.ToDateTime(pack.systick);
                            Now = dt;
                            calSpeed.SetPos1(Now, Position);
                            calSpeed.SetPos2(Now, Position2);

                            IStatusChangedEvent?.Invoke(
                                this,
                                new IStatusChangedEventArgs(
                                    dt,
                                    pack.istatus,
                                    pack.inChange,
                                    Position,
                                    Position2));
                        }
                        advPushIo(version);
                    }
                    break;
                case FLYAD7_OBJ_INTERFACE.PUSH_DATA_INTERFACE.PUSH_TIMEGRID:
                    {
                        stopwatch_noTGrid.Restart();//收到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;
                        }
                        timegrid_version = version;

                        DateTime dt;
                        int[] data;
                        //怕数据发送出错
                        if (pack.data.Any(d => (d >> 16) != 0))
                        {
                            //异常
                            goto _end_push_info;
                        }

                        if (version == 1)
                        {
                            //怕数据发送出错
                            dt = DateTime.Now;
                            Now = dt;
                        }
                        else// if (version == 2)
                        {
                            dt = sysTickContext.ToDateTime(pack.systick);
                            Now = dt;
                        }
                        data = pack.data;





                        //放入的数据应该是1ms一个，不对就扩展
                        TimeSpan curr_ad_ts = TimeSpan.FromTicks((long)(1.28 * TimeSpan.TicksPerMillisecond));
                        List<int> data_1ms = new List<int>();
                        DateTime idealTime = dt;
                        DateTime actTime = dt;
                        for (int j = 0; j < data.Count(); j++)
                        {
                            int idx2 = data.Count() - 1 - j;
                            int ad = data[idx2];
                            actTime -= curr_ad_ts;

                            while (idealTime > actTime)
                            {
                                data_1ms.Add(ad);//导出数据
                                idealTime -= TimeSpan.FromMilliseconds(1);//导出数据时间累加
                            }
                        }
                        data_1ms.Reverse();
                        data = data_1ms.ToArray();

                        advPushTimeGrid(dt, data);

                        TimeSpan ts = TimeSpan.FromMilliseconds(1);
                        if (lastTimeGridTime != DateTime.MinValue)
                            ts = TimeSpan.FromTicks((dt - lastTimeGridTime).Ticks / data.Length);
                        lastTimeGridTime = dt;

                        TimeGridEvent?.Invoke(
                            this,
                            new TimeGridEventArgs(
                                dt,
                                ts,
                                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 == 1)
                        {
                            DriveOrder = pack.order;
                            DriveStatus = pack.status;
                        }
                        else if (version == 2)
                        {
                            DriveOrder = pack.order;
                            DriveStatus = pack.status;
                            Marker = pack.marker;
                            DateTime dt = sysTickContext.ToDateTime(pack.systick);
                            Now = dt;

                            DriveStatusChangedEvent?.Invoke(this, new DriveStatusChangedEventArgs()
                            {
                                Time = dt,
                                DriveOrder = DriveOrder,
                                DriveStatus = DriveStatus,
                                Marker = Marker,
                            });
                        }
                        advPushStatus(version);
                    }
                    break;
                case FLYAD7_OBJ_INTERFACE.PUSH_DATA_INTERFACE.PUSH_GRID:
                    {
                        int version;
                        var pack = new FLYAD7_OBJ_INTERFACE.PUSH_DATA_INTERFACE.Pack_PushGrid_2();
                        if (!pack.TryParse_version(infodata, out version))
                            break;
                        grid_version = version;
                        DateTime dt;
                        int marker;
                        if (version == 1)
                        {
                            dt = DateTime.Now;
                            marker = Marker;
                        }
                        else //if (version == 2)
                        {
                            dt = sysTickContext.ToDateTime(pack.systick);
                            marker = pack.marker;
                        }

                        advPushGrid(dt, marker, pack.direction, pack.grid_start, pack.data);

                        GridEvent?.Invoke(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;

                        advPushMiniGrid(pack.direction, pack.grid_start, pack.data);

                        MiniGridEvent?.Invoke(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

        void Drive(DRIVE_MAN_ORDER order, object param)
        {

            switch (order)
            {
                case DRIVE_MAN_ORDER.RUNTO:
                    {
                        int TargetPos = (int)param;
                        if (Position == TargetPos)
                            break;//已经到了位置！！！！！， FLYAD7 是没有动作，没有推送的！！！

                        DriveOrder = DRIVE_MAN_ORDER.RUNTO;
                        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:
                    {
                        DriveOrder = order;
                        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;
            }

            //3秒后，再次发送获取状态，怕AD盒没有推送
            driveman_wait.Mark();
        }
        void Drive(DRIVE_MAN_ORDER order)
        {
            Drive(order, null);
        }



        #region Load Save
        public bool Load()
        {
            return Load(defaultPath);
        }

        public bool Load(string jsonDbPath)
        {
            this.jsonDbPath = jsonDbPath;

            this.PropertyChanged -= FlyAD7_PropertyChanged2;

            //不需要设置到 AD盒
            bShieldSetValueEx = true;
            bool ret = FlyAD7JsonDb.Load(jsonDbPath, this);
            bShieldSetValueEx = false;


            this.PropertyChanged += FlyAD7_PropertyChanged2;

            return ret;

        }

        /// <summary>
        /// 属性改变，自动保存
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void FlyAD7_PropertyChanged2(object sender, PropertyChangedEventArgs e)
        {
            if (propertyName_save.Contains(e.PropertyName))
            {
                PollModule.Current.Poll_JustOnce(() =>
                {
                    Save();
                }, this, MARKNO_SET_SAVE);
            }
        }

        public void Save()
        {
            FlyAD7JsonDb.Save(jsonDbPath, this);
        }
        #endregion

        #region IFlyADClient function
        /// <summary>
        /// 连接
        /// </summary>
        public void Connect()
        {
            Connect(Addr);
        }

        /// <summary>
        /// 连接 ep
        /// </summary>
        /// <param name="addr"></param>
        public void Connect(string addr)
        {
            Addr = addr;

            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;
        }

        /// <summary>
        /// 重连
        /// </summary>
        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
        #region  IFlyAD function
        /// <summary>
        /// Out0 = 0, SetOutput(0x0001,0x0000);
        /// Out0 = 1, Out1 = 0, SetOutput(0x0003,0x0001);
        /// </summary>
        /// <param name="mask"></param>
        /// <param name="enable"></param>
        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());

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

        /// <summary>
        /// 设置 运动参数
        /// </summary>
        /// <param name="posOfGrid">脉冲/grid</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);
        }

        /// <summary>
        /// 设置速度参数
        /// </summary>
        /// <param name="velocity">runto 速度 pps</param>
        /// <param name="sv">开始速度 pps</param>
        /// <param name="atime">加速时间 ms</param>
        /// <param name="dtime">减速时间 ms</param>
        /// <param name="hspeed1">归0 第1段速 pps</param>
        /// <param name="hspeed2">归0 第2段速 pps</par
        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);
        }

        /// <summary>
        /// 设置速度
        /// </summary>
        /// <param name="velocity"></param>
        public void SetVelocity(UInt32 velocity)
        {
            SetPosParam(velocity, UInt32.MaxValue, UInt32.MaxValue, UInt32.MaxValue, UInt32.MaxValue, UInt32.MaxValue);
        }

        /// <summary>
        /// 输入系统授权码
        /// </summary>
        /// <param name="access">系统授权码access[8]</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);

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

        }

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

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

        #region 运行动作
        /// <summary>
        /// 运行至指定位置
        /// </summary>
        /// <param name="to">脉冲</param>
        public void Runto(int to)
        {
            Drive(DRIVE_MAN_ORDER.RUNTO, to);
        }
        /// <summary>
        /// 归原点
        /// </summary>
        public void Origin()
        {
            Drive(DRIVE_MAN_ORDER.ORIGIN);
        }
        /// <summary>
        /// 停止
        /// </summary>
        public void Stop()
        {
            Drive(DRIVE_MAN_ORDER.STOP);
        }
        /// <summary>
        /// 反向，直到撞了限位
        /// </summary>
        public void Backward()
        {
            Drive(DRIVE_MAN_ORDER.BACKWORD);
        }
        /// <summary>
        /// 正行，直到撞了限位
        /// </summary>
        public void Forward()
        {
            Drive(DRIVE_MAN_ORDER.FORWORD);
        }


        #endregion

        #region 同步




        #region 同步控制 同步状态转换规则

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

        }

        #endregion
        #region 同步扫描 脚本指令

        /// <summary>
        /// 同步扫描至;
        /// D+0xE0+开始主轴位置+结束主轴位置+结束横向脉冲位置（逻辑位置）+脉冲开关（1B）+命令识标号（4B）
        /// </summary>
        /// <param name="pos2_begin"></param>
        /// <param name="pos2_end"></param>
        /// <param name="pos1lc"></param>
        /// <param name="hasDataGrid"></param>
        /// <param name="marker"></param>
        public void SyncRunAtLC(int pos2lc_begin, int pos2lc_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 = pos2lc_begin,
                    pos2_end = pos2lc_end,
                    pos1lc = pos1lc,
                    hasDataGrid = hasDataGrid,
                    marker = marker
                }.ToBytes());

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

        /// <summary>
        /// 位于队列头时运行，归零；
        /// D+0xE1+命令识标号（4B）
        /// </summary>
        /// <param name="marker"></param>
        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
            });
        }


        /// <summary>
        /// 位于队列头时运行，以速度运行至物理位置；
        /// D+0xE2+横向脉冲位置（4B：int32，物理位置）+速度（4B：int32）+脉冲开关（1B）+命令识标号（4B）
        /// </summary>
        /// <param name="pos1"></param>
        /// <param name="velocity"></param>
        /// <param name="hasDataGrid"></param>
        /// <param name="marker"></param>
        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
            });
        }

        /// <summary>
        /// 位于队列头时运行，以速度运行至逻辑位置；
        /// D+0xE3+横向脉冲位置（4B：int32，逻辑位置）+速度（4B：int32）+脉冲开关（1B）+命令识标号（4B）
        /// </summary>
        /// <param name="pos1lc"></param>
        /// <param name="velocity"></param>
        /// <param name="hasDataGrid"></param>
        /// <param name="marker"></param>
        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
            });
        }


        /// <summary>
        /// 等待，ms；
        /// D+0xE4+毫秒数（4B：int32）+命令识标号（4B）
        /// </summary>
        /// <param name="ms"></param>
        /// <param name="marker"></param>
        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
        #endregion
    }

    class FlyAD7JsonDb
    {
        static Mapper Mapper { get; } = new AutoMapper.Mapper(new MapperConfiguration(c =>
        {
            c.CreateMap<FlyAD7, FlyAD7JsonDb>().ReverseMap();
        }));
        public static void Save(string jsonDbPath, FlyAD7 src)
        {

            if (string.IsNullOrEmpty(jsonDbPath))
                return;
            var p = FlyAD7JsonDb.Mapper.Map<FlyAD7JsonDb>(src);
            try
            {
                File.WriteAllText(jsonDbPath, JsonConvert.SerializeObject(p, Formatting.Indented));
            }
            catch
            {
                //异常，没有json 编码失败
            }
        }
        public static bool Load(string jsonDbPath, FlyAD7 src)
        {
            if (string.IsNullOrEmpty(jsonDbPath))
                return false;

            try
            {
                if (File.Exists(jsonDbPath))
                {
                    string json = File.ReadAllText(jsonDbPath);
                    var p = JsonConvert.DeserializeObject<FlyAD7JsonDb>(json);
                    Mapper.Map(p, src);
                    return true;
                }
            }
            catch
            {
                //异常，没有json 解码失败
            }
            return false;
        }
        public string Addr = "192.168.251.10:20006";
        public bool HasCRC = false;
        public int GridSmooth = 0;
        public int ADLag = 0;
        public int PosMin = 0;
        public int PosMax = 8900;
        public bool HasPosMaxMin = false;

        //备份参数
        public bool IsDevParamValid = false;
        public MOTORTYPE MotorType = MOTORTYPE.SERVO;
        public UInt16 PosOfGrid = 10;
        public UInt16 Ratio01 = 4;
        public UInt16 Ratio02 = 1;
        public Int16 PosOffset = 0;
        public UInt32 JogVelocity = 1000;

        /// <summary>
        /// 硬件版本
        /// version = 1,不支持 systick
        /// version = 2,支持 timeGridAdv
        /// version = 3,伟的大AD盒， io口定义不一样
        /// </summary>
        public int HardwareVersion = 2;


        public static string[] GetMemberNames()
        {
            var type = typeof(FlyAD7JsonDb);
            return type.GetMembers().Select(mi => mi.Name).ToArray();
        }

    }

    /// <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 SysTickContext
    {
        Int32 systick_1st = 0;
        DateTime dt_1st = DateTime.MinValue;
        public event Action BeReseted;
        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;
                //毫秒级别取整
                long tick = dt_1st.Ticks % TimeSpan.TicksPerMillisecond;
                dt_1st -= TimeSpan.FromTicks(tick);

                systick_1st = systick;
                return dt_1st;
            }

            int ms = systick - systick_1st;
            if ((ms < -1000) ||//时间被提前
                (ms > 1000 * 60 * 3))//记录与新的timemark 相差3分钟，太大了,重新生成 timemark 与 dt 的关系
            {
                //被复位了
                BeReseted?.Invoke();
                dt_1st = DateTime.Now;
                //毫秒级别取整
                long tick = dt_1st.Ticks % TimeSpan.TicksPerMillisecond;
                dt_1st -= TimeSpan.FromTicks(tick);

                systick_1st = systick;
                return dt_1st;
            }

            DateTime dt = dt_1st.AddMilliseconds(ms);

            systick_1st = systick;
            dt_1st = dt;
            //if (Math.Abs((DateTime.Now-dt).TotalSeconds) > 5000)//滞后5s，异常
            //{
            //    //修正
            //    dt = DateTime.Now;
            //    dt_1st = dt;
            //}
            return dt;
        }
    }
    class DtAndBool
    {
        bool bNeedGet;
        DateTime dt;
        /// <summary>
        /// 标记 【需要获取数据】，且登记【时间】
        /// </summary>
        public void Mark()
        {
            bNeedGet = true;
            dt = DateTime.Now;
        }

        /// <summary>
        /// 检测是否 【需要获取数据】，再把 now-【时间】，时间差大于delay 返回true；
        /// 当返回true, 【需要获取数据】被清除
        /// </summary>
        /// <param name="now"></param>
        /// <param name="delay"></param>
        /// <returns></returns>
        public bool CheckMark(TimeSpan delay)
        {
            if (!bNeedGet)
                return false;

            if ((DateTime.Now - dt) < delay)
                return false;


            bNeedGet = false;
            return true;
        }
    }
    class IsReadyContext : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        public bool isReadyGetState { get; set; }
        public bool isReadyGetPos1AD1 { get; set; }
        public bool isReadyGetPos2 { get; set; }
        public bool isReadyGetIO { get; set; }

        public bool IsReady => isReadyGetState && isReadyGetPos2 && isReadyGetPos1AD1 && isReadyGetIO;

        public void Reset()
        {
            isReadyGetState = false;
            isReadyGetPos1AD1 = false;
            isReadyGetPos2 = false;
            isReadyGetIO = false;
        }
    }
}
