using AutoMapper; using FlyAd2021.Inc; using FlyADBase; 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.IO.Ports; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows.Threading; namespace FlyAd2021 { public partial class FlyAd2021 : IFlyADClient { #region MARKNO 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; private set; } /// <summary> /// 通过判断systick,判断AD盒是否发生重启; /// BeResetTime为上一次被复位时间, 此为 电脑的时间 /// </summary> public DateTime BeResetTime { get; private set; } /// <summary> /// 当前在同步状态 /// </summary> public bool IsSync{ get; private set; } /// <summary> /// 只要connect成功,获取systick被复位,都会从AD盒设备读取参数; /// 否则, 设置参数 到 AD盒 /// </summary> public bool IsReadParamFromDev { get; set; } /// <summary> /// 同步列表,完成后,会删除 /// </summary> public ObservableCollection<SyncOrder> SyncOrders { get; } = new ObservableCollection<SyncOrder>(); #endregion #region IFlyAD property /// <summary> /// AD盒地址, 当为 TCP通讯时,为 192.168.251.200:20020; /// 当为 串口通讯时, 为 COM6 /// </summary> public string Addr { get; set; } /// <summary> /// 从flyad7 获取 的systick 转换的时间 /// </summary> public DateTime Now { get; private set; } /// <summary> /// AD盒版本号 版本1 没有systick;版本2 有systick; /// 通过通讯读取 /// </summary> public int Version { get; } = 2021; /// <summary> /// 硬件版本,设置的!!! /// </summary> public int HardwareVersion { get; set; } = 2021; /// <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> /// 纵向速度 /// </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位有效 /// </summary> public UInt16 IStatus { get; private set; } = 0xffff; /// <summary> /// 输出口状态,只有4位有效 /// </summary> public UInt16 OStatus { get; private set; } = 0xffff; /// <summary> /// 电机类型 /// </summary> public MOTORTYPE MotorType { get; set; } = MOTORTYPE.SERVO; /// <summary> /// 脉冲/grid, 最大1000个grid /// </summary> 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 { set; get; } /// <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; private set; } /// <summary> /// 使用码区出错码 /// </summary> public AREA_ERR AreaRet { get; private set; } /// <summary> /// 序列码byte[6], AD盒只需要 6个byte,但flysecute 软件需要 7byte, code[6]=0x06 /// </summary> public byte[] Code { get; private set; } = new byte[7]; /// <summary> /// 系统剩余时间 /// </summary> public int Surplus { get; private set; } /// <summary> /// 系统授权码access[8] /// </summary> public byte[] Access { get; private set; } = 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; private 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 IsReadyContext isReadyContext = new IsReadyContext(); SysTickContext sysTickContext = new SysTickContext(); CalSpeed calSpeed = new CalSpeed(); IFlyAd2021Comm comm; FlyAd2021Core core; /// <summary> /// 不设置服务器 /// </summary> bool bShieldSetValueEx; /// <summary> /// 用于检测当 为IsRunning时,脉冲是否停了很久。 /// </summary> int last_position = int.MinValue; /// <summary> /// 最后一次动作时间 /// </summary> DateTime drive_time; static string[] propertyName_save; string defaultPath = "flyad.json"; string jsonDbPath; static FlyAd2021() { propertyName_save = FlyAd2021JsonDb.GetMemberNames(); } public FlyAd2021() { constructor(); advConstructor(); } void constructor() { Now = DateTime.Now; sysTickContext.BeReseted += () => BeResetTime = DateTime.Now; core = new FlyAd2021Core(); core.SendMsgEvent += (s) => { byte[] msg = core.GetSendMsg(); if (msg == null) return; comm?.SendMsg(msg); }; core.PushDataEvent += Core_PushDataEvent; core.PushRunResultEvent += Core_PushRunResultEvent; core.StartMeasure(); PollModule.Current.Poll_Config(PollModule.POLL_CONFIG.ADD, core.OnPoll_TimeOut, TimeSpan.FromSeconds(0.5)); core.PropertyChanged += Core_PropertyChanged; Misc.BindingOperations.SetBinding(core, nameof(core.IsConnected), this, nameof(IsConnected)); Misc.BindingOperations.SetBinding(isReadyContext, nameof(isReadyContext.IsReady), this, nameof(IsReady)); this.PropertyChanged += FlyAd2021_PropertyChanged; //每隔一个小时,改变剩下时间 PollModule.Current.Poll_Config(PollModule.POLL_CONFIG.ADD, () => { if (!IsConnected) return; if (Surplus < 60000) { if (Surplus > 0) { Surplus--; core.AddAccess(null, null); } } }, TimeSpan.FromMinutes(60)); //每隔1秒发送一次 脉冲,输入输出,状态 PollModule.Current.Poll_Config(PollModule.POLL_CONFIG.ADD, () => { if (!IsConnected) return; AfterConnected_GetFastData(); }, TimeSpan.FromSeconds(60)); //更新线速度 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) return; if (DriveStatus != DRIVE_MAN_STATUS.RUNNING) return; if (Position != last_position) { last_position = Position; return; } if (DateTime.Now-drive_time>=TimeSpan.FromSeconds(3))//每3秒检查一次 { drive_time = DateTime.Now; GetRunResult(); } }, TimeSpan.FromSeconds(1)); } void GetRunResult() { //不需要处理回复数据。 它会作为事件被处理 core.GetRunResult(null, null); } /// <summary> /// 连接后初始化, 获取快速数据 /// </summary> void AfterConnected_GetFastData() { core.GetEncAll((asyncContext, _retData) => { PollModule.Current.Dispatcher.BeginInvoke(new Action<object>((retData) => { var reponse = retData as GetEncAll_Reponse; Position = reponse.pos1; Position2 = reponse.pos2; calSpeed.SetPos1(Now, Position); calSpeed.SetPos2(Now, Position2); isReadyContext.isReadyGetPos = true; advPushPosAll(); }), _retData); }, null); core.GetIn((asyncContext, _retData) => { PollModule.Current.Dispatcher.BeginInvoke(new Action<object>((retData) => { var reponse = (UInt16)retData; IStatus = reponse; isReadyContext.isReadyGetIn = true; advPushIn(); }), _retData); }, null); } void GetOut() { core.GetOut((asyncContext, _retData) => { PollModule.Current.Dispatcher.BeginInvoke(new Action<object>((retData) => { var reponse = (UInt16)retData; OStatus = reponse; isReadyContext.isReadyGetOut = true; }), _retData); }, null); } private void FlyAd2021_PropertyChanged(object sender, PropertyChangedEventArgs e) { if (bShieldSetValueEx) return; if (e.PropertyName == nameof(PosOffset)) { core.SetSysParam_Zero(PosOffset, null, null); } else if (e.PropertyName == nameof(JogVelocity)) { core.SetSysParam_Jog(JogVelocity, null, null); } else if (e.PropertyName == nameof(MotorType)) { core.SetSysParam_MotorType(MotorType, null, null); } else if (e.PropertyName == nameof(Ratio01)) { core.SetSysParam_Ratio01(Ratio01, null, null); } else if (e.PropertyName == nameof(Ratio02)) { core.SetSysParam_Ratio02(Ratio02, null, null); } else if (e.PropertyName == nameof(Pos1LCShift)) { core.SyncRun_SetHShift(Pos1LCShift, null, null); } else if (e.PropertyName == nameof(Pos2LCShift)) { core.SyncRun_SetVShift(Pos2LCShift, null, null); } } private void Core_PushRunResultEvent(object sender, PushRunResultEventArgs _e) { //这个线程非主线程, 数据接收完,应该快速返回。 //事件触发,都放在主线程操作。 PollModule.Current.Dispatcher.BeginInvoke(new Action<PushRunResultEventArgs>((e) => { Now = sysTickContext.ToDateTime(e.SysTick); Marker = (int)e.Serial; DriveStatus = e.Status; isReadyContext.isReadyGetState = true; advPushStatus(); }), _e); } /// <summary> /// 计数32位脉冲 /// </summary> /// <param name="lastPostion">上一次脉冲</param> /// <param name="enc">低16位脉冲</param> /// <returns></returns> int CalPosition(int lastPostion, UInt16 enc) { //Position UInt16 lastEnc = (UInt16)(lastPostion & 0xffff); Int16 d = (Int16)(enc - lastEnc); lastPostion += d; return lastPostion; } private void Core_PushDataEvent(object sender, PushDataEventArgs _e) { //这个线程非主线程, 数据接收完,应该快速返回。 //事件触发,都放在主线程操作。 //要有线程锁!!!!! PollModule.Current.Dispatcher.BeginInvoke(new Action<PushDataEventArgs>((e) => { Now = sysTickContext.ToDateTime(e.SysTick); advPushAd(e.AD); if (e.ENC1 != null) { if (isReadyContext.isReadyGetPos) { Position = CalPosition(Position, (UInt16)e.ENC1); calSpeed.SetPos1(Now, Position); advPushPos1(); } } if (e.ENC2 != null) { if (isReadyContext.isReadyGetPos) { Position2 = CalPosition(Position2, (UInt16)e.ENC2); calSpeed.SetPos2(Now, Position2); advPushPos2(); } } if (e.In != null) { IStatus = (UInt16)e.In; isReadyContext.isReadyGetIn = true; advPushIn(); } if (e.Out != null) { OStatus = (UInt16)e.Out; isReadyContext.isReadyGetOut = true; } }), _e); } private void Core_PropertyChanged(object sender, PropertyChangedEventArgs e) { if (e.PropertyName == nameof(core.IsConnected)) { if (core.IsConnected) { ConnectCnt++; AfterConnected(); } } } /// <summary> /// 连接后初始化 /// </summary> void AfterConnected() { if (IsReadParamFromDev) { //从设备读取参数 //获取当前全部状态 core.GetSysParam_Jog((asyncContext, retData) => JogVelocity = (UInt32)retData, null); core.GetSysParam_Zero((asyncContext, retData) => PosOffset = (Int16)retData, null); core.GetSysParam_MotorType((asyncContext, retData) => MotorType = (MOTORTYPE)retData, null); core.GetSysParam_Ratio01((asyncContext, retData) => Ratio01 = (UInt16)retData, null); core.GetSysParam_Ratio02((asyncContext, retData) => Ratio02 = (UInt16)retData, null); core.GetRunParam_V((asyncContext, retData) => Velocity = (UInt32)retData, null); core.GetRunParam_SV((asyncContext, retData) => SVelocity = (UInt32)retData, null); core.GetRunParam_AccTime((asyncContext, retData) => ATime = (UInt32)retData, null); core.GetRunParam_DecTime((asyncContext, retData) => DTime = (UInt32)retData, null); core.GetRunParam_HSpd1((asyncContext, retData) => HVelocity1 = (UInt32)retData, null); core.GetRunParam_HSpd2((asyncContext, retData) => HVelocity2 = (UInt32)retData, null); } else { //参数不保存在设备中, 保存在电脑。 //参数写入到设备。 NotifyPropertyChanged(nameof(MotorType)); NotifyPropertyChanged(nameof(Ratio01)); NotifyPropertyChanged(nameof(Ratio02)); NotifyPropertyChanged(nameof(PosOffset)); NotifyPropertyChanged(nameof(JogVelocity)); } GetAccess(); NotifyPropertyChanged(nameof(Pos1LCShift));//写入到AD盒 NotifyPropertyChanged(nameof(Pos2LCShift));//写入到AD盒 SyncClear(); SyncEnd(); //连接断开,复位 脉冲计数。。。,时间计数 isReadyContext.Reset(); sysTickContext.Reset(); calSpeed.Reset(); GetRunResult(); GetOut(); AfterConnected_GetFastData(); advAfterContected(); } void GetAccess() { core.GetAccess((asyncContext, _retData) => { PollModule.Current.Dispatcher.BeginInvoke(new Action<object>((retData) => { GetAccess_Reponse reponse = (GetAccess_Reponse)retData; AreaStatus = reponse.status; AreaRet = reponse.ret; Array.Copy(reponse.code, Code, reponse.code.Length); Code[6] = 0x06; NotifyPropertyChanged(nameof(Code)); Surplus = reponse.surplus; Array.Copy(reponse.access, Access, reponse.access.Length); NotifyPropertyChanged(nameof(Access)); }), _retData); }, 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 = FlyAd2021JsonDb.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() { FlyAd2021JsonDb.Save(jsonDbPath, this); } #endregion #region IFlyADClient function /// <summary> /// 连接 /// </summary> public void Connect() { Connect(Addr); } void createComm() { if (Addr.ToLower().StartsWith("com")) comm = new FlyAd2021Comm_SerialPort(); else comm = new FlyAd2021Comm_TcpClient(); comm.RecMsg += (msg) => core.RecMsg(msg); } /// <summary> /// 连接 addr /// </summary> /// <param name="addr"></param> public void Connect(string addr) { Addr = addr; if (comm == null) { createComm(); } else { comm.Stop(); if ((Addr.ToLower().StartsWith("com") && (comm is FlyAd2021Comm_SerialPort)) || (!Addr.ToLower().StartsWith("com") && (comm is FlyAd2021Comm_TcpClient))) { //不用重建 } else { createComm(); } } comm.Addr = addr; comm.Start(); } /// <summary> /// 重连 /// </summary> public void ReConnect() { Connect(); } #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(UInt16 mask, UInt16 enable) { core.SetOutPorts(mask, enable, (asyncConetext,_retData)=> { GetOut(); }, null); } #region 运动参数 /// <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) { core.SetSysParam_MotorType(motortype, null, null); core.SetSysParam_Ratio01(ratio01, null, null); core.SetSysParam_Ratio02(ratio02, null, null); } #endregion #region 速度参数 /// <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</param> public void SetPosParam(UInt32 velocity, UInt32 sv, UInt32 atime, UInt32 dtime, UInt32 hspeed1, UInt32 hspeed2) { core.SetRunParam_V(velocity, null, null); core.SetRunParam_SV(sv, null, null); core.SetRunParam_AccTime(atime, null, null); core.SetRunParam_DecTime(dtime, null, null); core.SetRunParam_HSpd1(hspeed1, null, null); core.SetRunParam_HSpd2(hspeed2, null, null); core.GetRunParam_V((asyncContext, retData) => Velocity = (UInt32)retData, null); core.GetRunParam_SV((asyncContext, retData) => SVelocity = (UInt32)retData, null); core.GetRunParam_AccTime((asyncContext, retData) => ATime = (UInt32)retData, null); core.GetRunParam_DecTime((asyncContext, retData) => DTime = (UInt32)retData, null); core.GetRunParam_HSpd1((asyncContext, retData) => HVelocity1 = (UInt32)retData, null); core.GetRunParam_HSpd2((asyncContext, retData) => HVelocity2 = (UInt32)retData, null); } /// <summary> /// 设置速度 /// </summary> /// <param name="velocity"></param> public void SetVelocity(UInt32 velocity) { core.SetRunParam_V(velocity, null, null); core.GetRunParam_V((asyncContext, retData) => Velocity = (UInt32)retData, null); } #endregion #region 密码 /// <summary> /// 输入系统授权码 /// </summary> /// <param name="access">系统授权码access[8]</param> public void SetAccess(byte[] access) { core.CheckAccessCode(access, (asyncContext, retData) => { //AreaRet = (AREA_ERR)retData; GetAccess(); }, null); } /// <summary> /// 初始化系统信息区 /// </summary> public void InitArea() { core.InitArea((asyncContext, retData) => { GetAccess(); }, null); } #endregion #region 运行动作 /// <summary> /// 运行至指定位置 /// </summary> /// <param name="to">脉冲</param> public void Runto(int to) { if (Position == to) return; DriveOrder = DRIVE_MAN_ORDER.RUNTO; DriveStatus = DRIVE_MAN_STATUS.RUNNING; drive_time = DateTime.Now; core.RunTo(to, 123, null, null); } /// <summary> /// 归原点 /// </summary> public void Origin() { DriveOrder = DRIVE_MAN_ORDER.ORIGIN; DriveStatus = DRIVE_MAN_STATUS.RUNNING; drive_time = DateTime.Now; core.Org(124, null, null); } /// <summary> /// 停止 /// </summary> public void Stop() { if (DriveOrder == DRIVE_MAN_ORDER.IDLE) return;//已经停了 DriveOrder = DRIVE_MAN_ORDER.STOP; DriveStatus = DRIVE_MAN_STATUS.RUNNING; drive_time = DateTime.Now; core.Stop(null, null); } /// <summary> /// 反向,直到撞了限位 /// </summary> public void Backward() { DriveOrder = DRIVE_MAN_ORDER.BACKWORD; DriveStatus = DRIVE_MAN_STATUS.RUNNING; drive_time = DateTime.Now; core.Backw(125, null, null); } /// <summary> /// 正行,直到撞了限位 /// </summary> public void Forward() { DriveOrder = DRIVE_MAN_ORDER.FORWORD; DriveStatus = DRIVE_MAN_STATUS.RUNNING; drive_time = DateTime.Now; core.Forw(126, null, null); } #endregion #region 同步控制 同步状态转换规则 /// <summary> /// 进入同步状态 /// </summary> public void SyncBegin() { core.SyncRun_Start(null, null); } /// <summary> /// 退出同步状态 /// </summary> public void SyncEnd() { core.SyncRun_Stop(null, null); } /// <summary> /// 清空同步指令 /// </summary> public void SyncClear() { core.SyncRun_Clear(null, null); } #endregion #region 同步扫描 脚本指令 /// <summary> /// 同步扫描至; /// D+0xE0+开始主轴位置+结束主轴位置+结束横向脉冲位置(逻辑位置)+脉冲开关(1B)+命令识标号(4B) /// </summary> /// <param name="pos2lc_begin"></param> /// <param name="pos2lc_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) { //TODO, 怎样解决 grid 数据? core.SyncRun_RunAtLC(pos2lc_begin, pos2lc_end, pos1lc, (UInt32)marker, null, null); } /// <summary> /// 位于队列头时运行,归零; /// D+0xE1+命令识标号(4B) /// </summary> /// <param name="marker"></param> public void SyncOrigin(Int32 marker) { core.SyncRun_Origin((UInt32)marker, null, null); } /// <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) { //TODO, 怎样解决 grid 数据? core.SyncRun_RunTo(pos1, velocity, (UInt32)marker, null, null); } /// <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) { core.SyncRun_RunToLC(pos1lc, velocity, (UInt32)marker, null, null); } /// <summary> /// 等待,ms; /// D+0xE4+毫秒数(4B:int32)+命令识标号(4B) /// </summary> /// <param name="ms"></param> /// <param name="marker"></param> public void SyncWait(int ms, Int32 marker) { //没有实现!!!! } #endregion #endregion } class FlyAd2021JsonDb { static Mapper Mapper { get; } = new AutoMapper.Mapper(new MapperConfiguration(c => { c.CreateMap<FlyAd2021, FlyAd2021JsonDb>().ReverseMap(); })); public static void Save(string jsonDbPath, FlyAd2021 src) { if (string.IsNullOrEmpty(jsonDbPath)) return; var p = Mapper.Map<FlyAd2021JsonDb>(src); try { File.WriteAllText(jsonDbPath, JsonConvert.SerializeObject(p, Formatting.Indented)); } catch { //异常,没有json 编码失败 } } public static bool Load(string jsonDbPath, FlyAd2021 src) { if (string.IsNullOrEmpty(jsonDbPath)) return false; try { if (File.Exists(jsonDbPath)) { string json = File.ReadAllText(jsonDbPath); var p = JsonConvert.DeserializeObject<FlyAd2021JsonDb>(json); Mapper.Map(p, src); return true; } } catch { //异常,没有json 解码失败 } return false; } public string Addr = "192.168.251.10:20006"; public int GridSmooth = 0; public int ADLag = 0; public int PosMin = 0; public int PosMax = 8900; public bool HasPosMaxMin = 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 = 2021; public static string[] GetMemberNames() { var type = typeof(FlyAd2021JsonDb); 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 { byte systick_1st = 0; DateTime dt_1st = DateTime.MinValue; /// <summary> /// /// </summary> public event Action BeReseted; public void Reset() { dt_1st = DateTime.MinValue; } /// <summary> /// 输入从 flyad7 获取的 timemark, 转换为 本地 DateTime /// </summary> /// <param name="systick">只有低7位有效</param> /// <returns></returns> public DateTime ToDateTime(byte systick) { if (dt_1st == DateTime.MinValue) { dt_1st = DateTime.Now; systick_1st = systick; return dt_1st; } int ms = SystickSub(systick, systick_1st); if ((ms > 30))//记录与新的timemark 相差30ms,掉包很严重 { //被复位了 BeReseted?.Invoke(); } DateTime dt = dt_1st.AddMilliseconds(ms); systick_1st = systick; dt_1st = dt; return dt; } /// <summary> /// 7位 systick1-systick2 /// </summary> /// <param name="systick1"></param> /// <param name="systick2"></param> /// <returns></returns> int SystickSub(byte systick1, byte systick2) { if (systick1 >= systick2) return systick1 - systick2; else { return systick1 + 0x80 - systick2; } } } class IsReadyContext : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; public bool isReadyGetState { get; set; } public bool isReadyGetPos { get; set; } public bool isReadyGetIn { get; set; } public bool isReadyGetOut { get; set; } public bool IsReady { get; private set; } void updateIsReady() { if (isReadyGetState == false) { IsReady = false; return; } if (isReadyGetPos == false) { IsReady = false; return; } if (isReadyGetIn == false) { IsReady = false; return; } if (isReadyGetOut == false) { IsReady = false; return; } IsReady = true; return; } public IsReadyContext() { this.PropertyChanged += IsReadyContext_PropertyChanged; } private void IsReadyContext_PropertyChanged(object sender, PropertyChangedEventArgs e) { if (e.PropertyName != nameof(IsReady)) { updateIsReady(); } } public void Reset() { isReadyGetState = false; isReadyGetPos = false; isReadyGetIn = false; isReadyGetOut = false; } } }