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 { isReadyContext.Reset(); 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; } } }