using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using FObjBase;
using System.IO;
using System.ComponentModel;
using System.Xml.Serialization;
using FlyADBase;

namespace FLY.Simulation.Flyad7
{
    public class FLYAD7 : IFlyAD, INotifyPropertyChanged, Misc.ISaveToXml
    {

        private IPEndPoint localep = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 20008);
        public IPEndPoint LocalEP
        {
            get
            {
                return localep;
            }
            set
            {
                if (!IPEndPoint.Equals(localep, value))
                {
                    localep.Address = value.Address;
                    localep.Port = value.Port;
                    NotifyPropertyChanged("LocalEP");
                }
            }
        }

        private int adforshow;
        public int ADForShow 
        {
            get { return adforshow; }
            set
            {
                if (adforshow != value)
                {
                    adforshow = value;
                    NotifyPropertyChanged("ADForShow");
                }
            }
        }

        private int posforshow;
        public int PosForShow
        {
            get { return posforshow; }
            set
            {
                if (posforshow != value)
                {
                    posforshow = value;
                    NotifyPropertyChanged("PosForShow");
                }
            }
        }

        private int pos2forshow;
        public int Pos2ForShow
        {
            get { return pos2forshow; }
            set
            {
                if (pos2forshow != value)
                {
                    pos2forshow = value;
                    NotifyPropertyChanged("Pos2ForShow");
                }
            }
        }

        private int ADSum;
        private int ADCnt;

        public List<int> TimeGrid = new List<int>();

        private double timespan1ms;
        public double TimeSpan1ms
        {
            get { return timespan1ms; }
            set
            {
                if (timespan1ms != value)
                {
                    timespan1ms = value;
                    NotifyPropertyChanged("TimeSpan1ms");
                }
            }
        }

        /// <summary>
        /// 原始脉冲值
        /// </summary>
        public int PositionOrg=0;

        #region 模拟部分
        SimDrive mSimDrive = new SimDrive();
        public OrderMan mOrderMan = new OrderMan();

        public enum SIM_MODE 
        {
            /// <summary>
            /// 吹膜
            /// </summary>
            Blowing,
            /// <summary>
            /// 涂布
            /// </summary>
            Coating,
            /// <summary>
            /// 头尾部检测
            /// </summary>
            HeaderAndTailer,
            /// <summary>
            /// 流延
            /// </summary>
            Casting
        }
        private SIM_MODE simmode = SIM_MODE.Coating;
        /// <summary>
        /// 系统重启时,mSimModeCurr = SimMode ,之后怎么变化都不会影响 mSimModeCurr
        /// </summary>
        public SIM_MODE SimMode 
        {
            get {
                return simmode;
            }
            set {
                if (simmode != value)
                {
                    simmode = value;
                    NotifyPropertyChanged("SimMode");
                }
            }
        }

        /// <summary>
        /// 当前模拟类型
        /// </summary>
        SIM_MODE mSimMode = SIM_MODE.Blowing;
        public FLY.Simulation.ISimulationGageAD mSimGageAD;
        //public SimDrive_VF0 mSimDriveVF0 = new SimDrive_VF0();
        //public SimDrive_Servo mSimDriveServo = new SimDrive_Servo();
        #endregion

        private string param_path;
        public FLYAD7():this("simulation_flyad7.xml")
        {

        }
        public FLYAD7(string param_path) 
        {
            this.param_path = param_path;

            PosOfGrid = 10;
            Load();
            mSimMode = SimMode;

            switch (mSimMode)
            {
                case SIM_MODE.Blowing:
                    mSimGageAD = new FLY.Simulation.Blowing.GageAD();
                    break;
                case SIM_MODE.HeaderAndTailer:
                    mSimGageAD = new FLY.Simulation.HeaderAndTailer.GageAD();
                    break;
                case SIM_MODE.Casting:
                    mSimGageAD = new FLY.Simulation.Casting.GageAD();
                    break;
                case SIM_MODE.Coating:
                    mSimGageAD = new FLY.Simulation.Coating.GageAD();
                    break;
                default:
                    throw new Exception("不支持 SIM_MODE" + mSimGageAD.ToString());
            }
            
            PollModule.Current.Poll_Config(
                PollModule.POLL_CONFIG.ADD,
                new PollModule.PollHandler(OnPoll),
                new TimeSpan((long)(TimeSpan.TicksPerMillisecond * 1.28)));
            //一定只能用TimeSpan.FromTicks(12800)
            //TimeSpan.FromMilliseconds(1.28) 会被取整,最后是 1ms

            this.PropertyChanged += new PropertyChangedEventHandler(FLYAD7_PropertyChanged);

            mOrderMan.Init(this, mSimDrive);
            mSimGageAD.Mmpp = mSimDrive.Mmpp;

            HVelocity1 = (UInt32)((5 * 1000) / mSimDrive.Mmpp / 60);
            HVelocity2 = (UInt32)((1 * 1000) / mSimDrive.Mmpp / 60);
            Velocity = (UInt32)((12 * 1000) / mSimDrive.Mmpp / 60);
            SVelocity = (UInt32)((0 * 1000) / mSimDrive.Mmpp / 60);
            JogVelocity = (UInt32)((8 * 1000) / mSimDrive.Mmpp / 60);
            ATime = 500;
            DTime = 500;


            mOrderMan.order_org.Velocity1 = (int)HVelocity1;
            mOrderMan.order_org.Velocity2 = (int)HVelocity2;

            mOrderMan.order_runto.Velocity = (int)Velocity;
            mOrderMan.order_forw.Velocity = (int)JogVelocity;
            mOrderMan.order_backw.Velocity = (int)JogVelocity;

            mSimDrive.AccTime = ATime;
            mSimDrive.DecTime = DTime;


            mOrderMan.order_sync.mSyncOrderList = mSyncOrderList;
            mOrderMan.FinishEvent += new OrderMan.FinishEventHandler(mSimDriveMan_FinishEvent);
        }
        void mSimDriveMan_FinishEvent(bool isNormalStop)
        {
            if (isNormalStop)
                DriveStatus = DRIVE_MAN_STATUS.STOP;
            else
                DriveStatus = DRIVE_MAN_STATUS.LIMIT;

            DriveOrder = DRIVE_MAN_ORDER.IDLE;
        }

        void FLYAD7_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == "DriveOrder")
            {
                switch (DriveOrder) 
                {

                    case DRIVE_MAN_ORDER.FORWORD:
                        DriveStatus = DRIVE_MAN_STATUS.RUNNING;
                        mOrderMan.Forw();
                        break;
                    case DRIVE_MAN_ORDER.BACKWORD:
                        DriveStatus = DRIVE_MAN_STATUS.RUNNING;
                        mOrderMan.Backw();
                        break;
                    case DRIVE_MAN_ORDER.ORIGIN:
                        DriveStatus = DRIVE_MAN_STATUS.RUNNING;
                        mOrderMan.Org();
                        break;
                    case DRIVE_MAN_ORDER.RUNTO:
                        DriveStatus = DRIVE_MAN_STATUS.RUNNING;
                        mOrderMan.Runto(DriveRuntoTarget);
                        break;
                    case DRIVE_MAN_ORDER.SYNC:
                        DriveStatus = DRIVE_MAN_STATUS.RUNNING;
                        mOrderMan.Sync();
                        break;
                    case DRIVE_MAN_ORDER.STOP:
                        DriveStatus = DRIVE_MAN_STATUS.RUNNING;
                        mOrderMan.Stop();
                        break;
                    case DRIVE_MAN_ORDER.IDLE:
                        DriveStatus = DRIVE_MAN_STATUS.STOP;
                        break;
                }
            }
        }
































        class SimulationDataCell
        {
            public UInt16 istatus;
            public UInt32 ad;
            public override string ToString()
            {
                return "ad=" + ad.ToString() + " istatus=" + istatus.ToString("X3");
            }
        }



        public void Save() 
        {
            Misc.SaveToXmlHepler.Save(param_path, this);
        }
        public void Load() 
        {
            Misc.SaveToXmlHepler.Load(param_path, this);
        }







        double systick;
        public Int32 GetSysTick()
        {
            //以读到的 mSimulationDatas_idx 作为时间, 一个为1.28ms
            return (Int32)systick;
        }
        public Int32 GetSysTick(DateTime dt) 
        {
            return (Int32)(systick + (dt - Now).TotalMilliseconds);
        }
        


        //1.28ms 触发一次
        void OnPoll() 
        {
            if (Now == DateTime.MinValue)
            {
                Now = DateTime.Now;
                systick = 0;
            }
            else
            {
                Now += TimeSpan.FromTicks((int)(TimeSpan.TicksPerMillisecond * 1.28));
                systick += 1.28;
            }

            UpdateAD();
            UpdatePos();
            UpdateIO();
            UpdateDrive();
        }

        DateTime dt = DateTime.MinValue;
        void UpdateTimeSpan1ms()
        {
            DateTime d = DateTime.Now;
            if (dt == DateTime.MinValue)
                dt = d;
            else
            {
                TimeSpan1ms = (d-dt).TotalMilliseconds;
                dt = d;
            }
        }
        void UpdateAD() 
        {
            mSimGageAD.OnPoll(Now);
            int ad = mSimGageAD.GetAD(Position);

            ADSum += ad;
            ADCnt++;
            AD = ad;
            TimeGrid.Add(ad);
            if (TimeGrid.Count >= 1000)
            {
                ADForShow = ADSum / ADCnt;
                ADSum = 0;
                ADCnt = 0;

                UpdateTimeSpan1ms();
                if (TimeGridEvent != null) 
                {
                    TimeGridEvent.Invoke(this,
                        new TimeGridEventArgs(
                            Now,
                            TimeSpan.FromMilliseconds(1.28),
                            TimeGrid.ToArray()));
                }
                TimeGrid.Clear();
            }
        }

        public class PosGrid 
        {
            
            public int[] Datas = new int[1000];
            List<int> gridsum = new List<int>();
            int grid_index_last = -1;//上一个grid_index
            bool isEnable;
            int grid_start = 0;
            public void Start() 
            {
                isEnable = true;
                grid_start = grid_index_last;
            }
            public void End() 
            {
                if (isEnable)
                {
                    if (gridsum.Count > 0)
                    {
                        Datas[grid_index_last] = (int)(gridsum.Average());
                        gridsum.Clear();
                    }
                    int grid_end = grid_index_last;
                    Misc.DIRECTION dir = Misc.DIRECTION.FORWARD;

                    if (grid_end < grid_start)
                    {
                        int t = grid_start;
                        grid_start = grid_end;
                        grid_end = t;
                        dir = Misc.DIRECTION.BACKWARD;
                    }
                    int len = grid_end - grid_start + 1;
                    int[] data = Datas.Skip(grid_start).Take(len).ToArray();
                    if (PushEvent != null)
                        PushEvent(false, dir, grid_start, data);
                } isEnable = false;
                
            }
            public delegate void PushEventHandler(bool isMini, Misc.DIRECTION dir, int grid_start, int[] data);
            public event PushEventHandler PushEvent;

            public void UpdateGrid(int grid_index, int ad) 
            {
                if (grid_index >= 0 && grid_index < Datas.Count())
                {
                    if (grid_index_last == grid_index)
                    {
                        gridsum.Add(ad);
                    }
                    else
                    {
                        Misc.DIRECTION dir = Misc.DIRECTION.FORWARD;
                        if (grid_index < grid_index_last)
                            dir = Misc.DIRECTION.BACKWARD;
                        if (gridsum.Count > 0)
                        {
                            Datas[grid_index_last] = (int)(gridsum.Average());
                            gridsum.Clear();
                            //TODO 推送MINIGRID
                            if (isEnable) 
                            {
                                int[] data = new int[1];
                                data[0] = Datas[grid_index_last];
                                if (PushEvent != null)
                                    PushEvent(true, dir, grid_index_last, data);
                            }
                        }
                        grid_index_last = grid_index;
                    }
                }
            }    
        }
        public PosGrid mPosGrid = new PosGrid();
        
        void UpdatePos() 
        {
            Position = mSimDrive.Pos;
            //Speed = mSimDrive.Speed;    
            mPosGrid.UpdateGrid(Position / PosOfGrid, AD);


            Position2Org = mSimGageAD.GetPosition2();
            int pos2;
            if(mSyncPos2List.Position2Changed(Position2, out pos2))
            {
                Position2 = pos2;
            }

            Speed2 = mSimGageAD.GetSpeed2();
        }


       
        void UpdateIO() 
        {
            UInt16 istatus = mSimGageAD.GetInput();

            if (mSimDrive.IsMaxLimit)
                Misc.MyBase.SIGNBIT(ref istatus, IODefinition.IN_MAXLIMIT - 1);
            else
                Misc.MyBase.CLEARBIT(ref istatus, IODefinition.IN_MAXLIMIT - 1);
            if (mSimDrive.IsMinLimit)
                Misc.MyBase.SIGNBIT(ref istatus, IODefinition.IN_MINLIMIT - 1);
            else
                Misc.MyBase.CLEARBIT(ref istatus, IODefinition.IN_MINLIMIT - 1);

            if (mSimDrive.IsOrg)
                Misc.MyBase.CLEARBIT(ref istatus, IODefinition.IN_ORG - 1);
            else
                Misc.MyBase.SIGNBIT(ref istatus, IODefinition.IN_ORG - 1);

            UInt16 inchange = (UInt16)(istatus ^ IStatus);
            if (Misc.MyBase.CHECKBIT(inchange, IODefinition.IN_VSENSOR - 1)) 
            {
                //处理position2
                int pos2;
                if(mSyncPos2List.VSensorChanged(Misc.MyBase.CHECKBIT(istatus, IODefinition.IN_VSENSOR - 1), Position2, out pos2))
                {
                    Position2 = pos2;
                }
            }
            IStatus = istatus;
        }
        class SyncPos2Collection
        {
            List<SyncPos2Item> list = new List<SyncPos2Item>();
            int curr_offset = int.MaxValue;
            public void Add(SyncPos2Item item) 
            {
                list.Add(item);
            }
            public void Clear() 
            {
                list.Clear();
            }
            /// <summary>
            /// 信号改变时调用
            /// </summary>
            /// <param name="vsensor"></param>
            /// <param name="position2"></param>
            public bool VSensorChanged(bool vsensor, int position2, out int correct_pos2) 
            {
                correct_pos2 = position2;
                if (list.Count() == 0)
                    return false;//列表是空的,什么都不干

                SyncPos2Item spitem = list.First();//当前在处理的项

                if (vsensor == spitem.At01) 
                {
                    int offset = position2 - spitem.pos2;
                    if (Math.Abs(curr_offset) > Math.Abs(offset))
                    {
                        curr_offset = offset;
                        return false;
                    }
                    else
                    {
                        //已经找到最近的一个
                        correct_pos2 = spitem.pos2 + curr_offset;
                        curr_offset = int.MaxValue;
                        list.RemoveAt(0);

                        if (list.Count() > 0)
                        {
                            spitem = list.First();//当前在处理的项
                            if (vsensor == spitem.At01)
                                curr_offset = position2 - spitem.pos2;
                        }
                        return true;
                    }
                }
                return false;
            }
            /// <summary>
            /// 脉冲改变时调用
            /// </summary>
            /// <param name="position2"></param>
            /// <param name="correct_pos2"></param>
            /// <returns></returns>
            public bool Position2Changed(int position2, out int correct_pos2) 
            {
                correct_pos2 = position2;
                if (list.Count() == 0)
                    return false;//列表是空的,什么都不干

                SyncPos2Item spitem = list.First();//当前在处理的项

                if(curr_offset!=int.MaxValue)//之前有一个信号
                {
                    int offset = position2 - spitem.pos2;
                    if (Math.Abs(curr_offset) > Math.Abs(offset))
                    {
                        return false;
                    }
                    else
                    {
                        //已经找到最近的一个
                        correct_pos2 = spitem.pos2 + curr_offset;
                        curr_offset = int.MaxValue;
                        list.RemoveAt(0);
                        return true;
                    }
                }
                return false;
            }

        }

        void UpdateDrive() 
        {
            mSimDrive.OnPoll(Now);
            mOrderMan.OnPoll();
        }

        

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

        #endregion


        #region IFlyAD接口

        DateTime now = DateTime.MinValue;
        /// <summary>
        /// systick 转换的时间
        /// </summary>
        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 0xffff; }
        }

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

        private UInt16 ostatus = 0xf;
        public UInt16 OStatus
        {
            get { return ostatus; }
            set
            {
                if (ostatus != value)
                {
                    ostatus = value;
                    NotifyPropertyChanged("OStatus");
                }
            }
        }

        public void SetOutput(ushort mask, ushort enable)
        {
            UInt16 ostatus = OStatus;
            for (int i = 0; i < 16; i++)
            {
                if (Misc.MyBase.CHECKBIT(mask, i))
                {
                    if (Misc.MyBase.CHECKBIT(enable, i))
                        Misc.MyBase.SIGNBIT(ref ostatus, i);
                    else
                        Misc.MyBase.CLEARBIT(ref ostatus, i);
                }
            }
            OStatus = ostatus;
        }

        public void UpdateParam()
        {
            //throw new NotImplementedException();
        }
        #region 配置参数
        public void SetSysParam(ushort posOfGrid, FlyADBase.MOTORTYPE motortype, ushort ratio01, ushort ratio02)
        {
            MotorType = motortype;

        }

        private MOTORTYPE motorType = MOTORTYPE.VF0;
        public MOTORTYPE MotorType
        {
            get
            {
                return motorType;
            }
            set
            {
                if (motorType != value) 
                {
                    motorType = value;
                    //TODO
                    mSimDrive.MotorType = value;
                    NotifyPropertyChanged("MotorType");
                }
            }
        }

        UInt16 posOfGrid;//1个Grid=?脉冲数(2B)
        public UInt16 PosOfGrid
        {
            get
            {
                return posOfGrid;
            }
            set
            {
                if (posOfGrid != value) 
                {
                    posOfGrid = value;
                    NotifyPropertyChanged("PosOfGrid");
                }
            }
        }



        UInt16 ratio01=1;
        /// <summary>
        /// //电机比例(2B)
        /// </summary>
        public UInt16 Ratio01
        {
            get
            {
                return ratio01;
            }
            set
            {
                if (ratio01 != value)
                {
                    ratio01 = value;
                    NotifyPropertyChanged("Ratio01");
                }
            }
        }
        UInt16 ratio02=1;//脉冲比例(2B)
        public UInt16 Ratio02
        {
            get
            {
                return ratio02;
            }
            set
            {
                if (ratio02 != value) 
                {
                    ratio02 = value;
                    NotifyPropertyChanged("Ratio02");
                }
            }
        }
        #endregion

        Int16 posOffset;
        public Int16 PosOffset
        {
            get
            {
                return posOffset;
            }
            set
            {
                if (posOffset != value) 
                {
                    posOffset = value;
                    NotifyPropertyChanged("PosOffset");
                }
            }
        }

        UInt32 jogVelocity=500;
        public UInt32 JogVelocity
        {
            get
            {
                return jogVelocity;
            }
            set
            {
                if (jogVelocity != value) 
                {
                    jogVelocity = value;
                    NotifyPropertyChanged("JogVelocity");
                    mOrderMan.order_forw.Velocity = (int)JogVelocity;
                    mOrderMan.order_backw.Velocity = (int)JogVelocity;
                }
            }
        }

        #region 速度
        UInt32 velocity;
        public UInt32 Velocity
        {
            get
            {
                return velocity;
            }
            set
            {
                if (velocity != value) 
                {
                    velocity = value;
                    NotifyPropertyChanged("Velocity");
                    mOrderMan.order_runto.Velocity = (int)Velocity;
                }
            }
        }
        UInt32 svelocity;
        public uint SVelocity
        {
            get
            {
                return svelocity;
            }
            set
            {
                if (svelocity != value)
                {
                    svelocity = value;
                    NotifyPropertyChanged("SVelocity");
                }
            }
        }
        UInt32 atime;
        public UInt32 ATime
        {
            get
            {
                return atime;
            }
            set
            {
                if (atime != value)
                {
                    atime = value;
                    NotifyPropertyChanged("ATime");
                    mSimDrive.AccTime = atime;
                }
            }
        }
        UInt32 dtime;
        public UInt32 DTime
        {
            get
            {
                return dtime;
            }
            set
            {
                if (dtime != value)
                {
                    dtime = value;
                    NotifyPropertyChanged("DTime");
                    mSimDrive.DecTime = dtime;
                }
            }
        }
        UInt32 hvelocity1;

        public UInt32 HVelocity1
        {
            get
            {
                return hvelocity1;
            }
            set
            {
                if (hvelocity1 != value)
                {
                    hvelocity1 = value;

                    NotifyPropertyChanged("HVelocity1");

                    mOrderMan.order_org.Velocity1 = (int)HVelocity1;
                }
            }
        }
        UInt32 hvelocity2;
        public UInt32 HVelocity2
        {
            get
            {
                return hvelocity2;
            }
            set
            {
                if (hvelocity2 != value)
                {
                    hvelocity2 = value;
                    NotifyPropertyChanged("HVelocity2");

                    mOrderMan.order_org.Velocity2 = (int)HVelocity2;;
                }
            }
        }
        public void SetPosParam(uint velocity, uint sv, uint atime, uint dtime, uint hspeed1, uint hspeed2)
        {
            throw new NotImplementedException();
        }

        #endregion

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

        byte[] code = new byte[7] { 0x74, 0xB7, 0x07, 0x4E, 0x52, 0x3D, 0x06 };
        int surplus = 8000;
        byte[] access = new byte[8] { 0x19, 0x4A, 0xA5, 0x21, 0x7B, 0x74, 0x1A, 0x00 };


        public byte[] Code
        {
            get { return code; }
        }


        public int Surplus
        {
            get { return surplus; }
            set {
                if (surplus != value) {
                    surplus = value;
                    NotifyPropertyChanged("Surplus");
                }
            }
        }

        public byte[] Access
        {
            get { return access; }
        }

        public void SetAccess(byte[] access)
        {
            if (access.Length != 8)
                return;
            Array.Copy(access, Access, 8);
            AreaStatus = AREA_STATUS.VALID; 
            AreaRet = AREA_ERR.NO_ERR;
            Surplus = 8000;
        }

        public void InitArea()
        {
            throw new NotImplementedException();
        }
        #endregion



        public void GetGrid(Misc.DIRECTION direction, int grid_start, int grid_len, out int[] dat) 
        {
            dat = null;
        }
        public void GetGrid(Misc.DIRECTION direction, out int[] dat) 
        {
            GetGrid(direction, 0, 1000,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);
        }


        DRIVE_MAN_ORDER driveorder;
        public DRIVE_MAN_ORDER DriveOrder
        {
            get
            {
                return driveorder;
            }
            set
            {
                if (driveorder != value)
                {
                    driveorder = value;
                    NotifyPropertyChanged("DriveOrder");
                }
            }
        }
        DRIVE_MAN_STATUS drivestatus;
        public DRIVE_MAN_STATUS DriveStatus
        {
            get { return drivestatus; }
            set
            {
                if (drivestatus != value)
                {
                    drivestatus = value;
                    NotifyPropertyChanged("DriveStatus");
                }
            }
        }

        int DriveRuntoTarget;

        void Drive(DRIVE_MAN_ORDER order, object param) 
        {
            if (order == DRIVE_MAN_ORDER.RUNTO)
            {
                DriveRuntoTarget = (int)param; 
            }
            DriveOrder = order;
        }
        void Drive(DRIVE_MAN_ORDER order) 
        {
            Drive(order, null);
        }
        #endregion

        #region 同步
        Int32 marker;
        /// <summary>
        /// 同步用标示
        /// </summary>
        public Int32 Marker {
            get {
                return marker;
            }
            set {
                if (marker != value)
                {
                    marker = value;
                    NotifyPropertyChanged("Marker");
                }
            }
        }
        #region 横向脉冲
        int pos1lcshift;
        /// <summary>
        /// 逻辑横向脉冲偏移  Pos1 + Pos1LCShift = Pos1LC
        /// </summary>
        public int Pos1LCShift 
        {
            get {
                return pos1lcshift;
            }
            set {
                if (pos1lcshift != value) 
                {
                    pos1lcshift = value;
                    NotifyPropertyChanged("Pos1LCShift");
                }
            }
        }
        public void SetPos1LCShift(int value)
        {
            Pos1LCShift = value;
        }
        #endregion
        #region 主轴脉冲
        private int position2_org;
        int Position2Org 
        {
            get { return position2_org; }
            set {
                if (position2_org != value) 
                {
                    position2_org = value;
                    
                    NotifyPropertyChanged("Position2Org");
                    cal_position2();
                }
            }
        }
        private int position2;
        /// <summary>
        /// 纵向脉冲,也叫主轴脉冲
        /// </summary>
        public int Position2 {
            get { return position2; }
            set {
                if (position2 != value) 
                {
                    position2 = value;

                    NotifyPropertyChanged("Position2");
                    Pos2Shift = position2 - (int)(Position2Org * Pos2Comp);
                }
            }
        }

        void cal_position2() 
        {
            position2 = (int)(Position2Org * Pos2Comp + Pos2Shift);
        }
        private int speed2;
        public int Speed2 {
            get { return speed2; }
            set {
                if (speed2 != value)
                {
                    speed2 = value;
                    NotifyPropertyChanged("Speed2");
                }
            }
        }
        int pos2shift=0;
        /// <summary>
        /// 纵向偏移
        /// </summary>
        int Pos2Shift
        {
            get {
                return pos2shift;
            }

            set {
                if (pos2shift != value) 
                {
                    pos2shift = value;
                    NotifyPropertyChanged("Pos2Shift");
                    cal_position2();
                }
            }
        }
        public void SetPos2Offset(int offest) 
        {
            Pos2Shift += offest;
        }

        private float pos2comp=1;
        /// <summary>
        /// 纵向值补偿系数,补偿时,先乘除后加减
        /// </summary>
        public float Pos2Comp 
        {
            get {
                return pos2comp;
            }
            set {
                if (pos2comp != value) 
                {
                    pos2comp = value;
                    NotifyPropertyChanged("Pos2Comp");
                    cal_position2();
                }
            }
        }

        struct SyncPos2Item
        {
            public bool At01;//? or At10
            public int pos2;
            public bool immediately;
        }
        SyncPos2Collection mSyncPos2List = new SyncPos2Collection();
        
        /// <summary>
        /// 纵向同步事件,0-1事件
        /// </summary>
        /// <param name="pos2"></param>
        public void SetPos2At01(int pos2,bool immediately) 
        {
            mSyncPos2List.Add(new SyncPos2Item() { At01 = true, pos2 = pos2, immediately = immediately });
        }

        #endregion
        #region 同步控制 同步状态转换规则
        /// <summary>
        /// 进入同步状态
        /// </summary>
        /// <param name="pos2"></param>
        public void SyncBegin(int pos2) 
        {
            Position2 = pos2;
            SyncBegin();
        }
        /// <summary>
        /// 进入同步状态
        /// </summary>
        public void SyncBegin() 
        {
            Drive(DRIVE_MAN_ORDER.SYNC);
        }
        /// <summary>
        /// 退出同步状态
        /// </summary>
        public void SyncEnd() 
        {
            Drive(DRIVE_MAN_ORDER.STOP);
        }

        /// <summary>
        /// 清空同步指令
        /// </summary>
        public void SyncClear()
        {
            mSyncOrderList.Clear();
        }
        /// <summary>
        /// 清空POS2同步列表
        /// </summary>
        public void SyncPos2Clear()
        {
            mSyncPos2List.Clear();
        }
        #endregion
        #region 同步扫描 脚本指令



        List<ASyncOrder> mSyncOrderList = new List<ASyncOrder>();




        //同步扫描至
        //D+0xE0+开始主轴位置+结束主轴位置+结束横向脉冲位置(逻辑位置)+脉冲开关(1B)+命令识标号(4B)
        public void SyncRunAtLC(int pos2_begin, int pos2_end, int pos1lc, bool hasDataGrid, Int32 marker) 
        {
            mSyncOrderList.Add(
                new SyncOrder_RunAtLC()
                {
                    pos2_begin = pos2_begin,
                    pos2_end = pos2_end,
                    pos1lc_end = pos1lc,
                    hasDataGrid = hasDataGrid,
                    marker = marker
                });
        }

        //7.2	位于队列头时运行,归零
        //D+0xE1+命令识标号(4B)
        public void SyncOrigin(Int32 marker) 
        {
            mSyncOrderList.Add(
                new SyncOrder_Origin()
                {
                    marker = marker
                });
        }


        //7.3	位于队列头时运行,以速度运行至物理位置
        //D+0xE2+横向脉冲位置(4B:int32,物理位置)+速度(4B:int32)+脉冲开关(1B)+命令识标号(4B)
        public void SyncRunTo(int pos1, UInt32 velocity, bool hasDataGrid, Int32 marker)
        {
            mSyncOrderList.Add(
                new SyncOrder_RunTo()
                {
                    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)
        {
            mSyncOrderList.Add(
                new SyncOrder_RunToLC()
                {
                    pos1lc = pos1lc,
                    velocity = velocity,
                    hasDataGrid = hasDataGrid,
                    marker = marker
                });
        }


        //7.4	等待,ms
        //D+0xE4+毫秒数(4B:int32)+命令识标号(4B)
        public void SyncWait(int ms, Int32 marker)
        {
            mSyncOrderList.Add(
                new SyncOrder_Wait()
                {
                    ms = ms,
                    marker = marker
                });
        }


        #endregion
        #endregion

        public string[] GetSavePropertyNames()
        {
            return new string[] { 
                "LocalEP",
                "SimMode",
                "MotorType"
            };
        }
    }
    public static class FLYAD7_IODefinition
    {
        public const int IN_ORG = 2;
                public const int IN_MINLIMIT = 3;
                public const int IN_MAXLIMIT = 4;
                public const int IN_FORW = 7;
                public const int IN_BACKW = 8;
                public const int IN_VSENSOR = 12;
    }
}