using AutoMapper; using FlyADBase.Inc; using FObjBase; using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.IO; using System.Linq; namespace FlyADBase { 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 /// /// 连接成功 /// public bool IsConnected { get; private set; } /// /// 重连次数 /// public int ConnectCnt { get; private set; } /// /// CRC 校正, “没有用,不实现这个功能” /// public bool HasCRC { get; set; } /// /// 已经从AD盒获取全部当前数据 /// public bool IsReady { get; private set; } /// /// 通过判断systick,判断AD盒是否发生重启; /// BeResetTime为上一次被复位时间, 此为 电脑的时间 /// public DateTime BeResetTime { get; private set; } /// /// 当前在同步状态 /// public bool IsSync { get; private set; } /// /// 只要connect成功,获取systick被复位,都会从AD盒设备读取参数; /// 否则, 设置参数 到 AD盒 /// public bool IsReadParamFromDev { get; set; } /// /// 同步列表,完成后,会删除 /// public ObservableCollection SyncOrders { get; } = new ObservableCollection(); #endregion #region IFlyAD property /// /// AD盒地址, 当为 TCP通讯时,为 192.168.251.200:20020; /// 当为 串口通讯时, 为 COM6 /// public string Addr { get; set; } /// /// 从flyad7 获取 的systick 转换的时间 /// public DateTime Now { get; private set; } /// /// AD盒版本号 版本1 没有systick;版本2 有systick; /// 通过通讯读取 /// public int Version { get; } = 2021; /// /// 硬件版本,设置的!!! /// public int HardwareVersion { get; set; } = 2021; /// /// 脉冲 /// public int Position { get; private set; } /// /// 速度 pps /// public int Speed { get; private set; } /// /// 纵向脉冲,也叫主轴脉冲 /// public int Position2 { get; private set; } /// /// 纵向速度 /// public int Speed2 { get; private set; } /// /// 1000ms从AD卡获取(或推送)1个AD值。此AD值只用于调试,定点 /// public int AD { get; private set; } /// /// AD值最大值 ,恒定返回65535 /// public int ADMax => 0xFFFF; /// /// 输入口状态,只有12位有效 /// public UInt16 IStatus { get; private set; } = 0xffff; /// /// 输出口状态,只有4位有效 /// public UInt16 OStatus { get; private set; } = 0xffff; /// /// 电机类型 /// public MOTORTYPE MotorType { get; set; } = MOTORTYPE.SERVO; /// /// 脉冲/grid, 最大1000个grid /// private UInt16 posofgrid = 10; /// /// 脉冲/grid, 最大1000个grid /// public UInt16 PosOfGrid { get { return posofgrid; } set { if (value < 1) value = 1; if (posofgrid != value) posofgrid = value; } } /// /// 脉冲比例 分母(电机脉冲) /// public UInt16 Ratio01 { get; set; } = 4; /// /// 脉冲比例 分子(编码器脉冲) /// public UInt16 Ratio02 { get; set; } = 1; /// /// 脉冲平移(0位处脉冲值) /// public Int16 PosOffset { set; get; } /// /// 手动速度 pps /// public UInt32 JogVelocity { get; set; } = 5000; /// /// runto 速度 pps /// public UInt32 Velocity { get; private set; } = 8000; /// /// 开始速度 pps /// public UInt32 SVelocity { get; private set; } = 200; /// /// 加速时间 ms /// public UInt32 ATime { get; private set; } = 300; /// /// 减速时间 ms /// public UInt32 DTime { get; private set; } = 200; /// /// 归0 第1段速 pps /// public UInt32 HVelocity1 { get; private set; } = 4000; /// /// 归0 第2段速 pps /// public UInt32 HVelocity2 { get; private set; } = 500; /// /// 使用码区状态 /// public AREA_STATUS AreaStatus { get; private set; } /// /// 使用码区出错码 /// public AREA_ERR AreaRet { get; private set; } /// /// 序列码byte[6], AD盒只需要 6个byte,但flysecute 软件需要 7byte, code[6]=0x06 /// public byte[] Code { get; private set; } = new byte[7]; /// /// 系统剩余时间 /// public int Surplus { get; private set; } /// /// 系统授权码access[8] /// public byte[] Access { get; private set; } = new byte[8]; /// /// 当前运行指令 /// public DRIVE_MAN_ORDER DriveOrder { get; set; } = DRIVE_MAN_ORDER.IDLE; /// /// 之前运行动作的状态 /// public DRIVE_MAN_STATUS DriveStatus { get; set; } = DRIVE_MAN_STATUS.STOP; /// /// 同步用标示 /// public Int32 Marker { get; private set; } /// /// 逻辑横向脉冲偏移 Pos1 + Pos1LCShift = Pos1LC /// public int Pos1LCShift { get; set; } /// /// 逻辑纵向脉冲偏移 Pos2 + Pos2LCShift = Pos2LC /// public int Pos2LCShift { get; set; } /// /// timegrid 事件; 版本1: 1.28s 一次; 版本2: 0.2s一次, /// ad值不会被机架修正 /// public event TimeGridEventHandler TimeGridEvent; /// /// runto 中,每经过1个grid 推送数据 /// public event MiniGridEventHandler MiniGridEvent; /// /// runto 的 grid事件 /// public event MiniGridEventHandler GridEvent; /// /// 输入状态改变事件 /// public event IStatusChangedEventHandler IStatusChangedEvent; /// /// 指令状态改变事件 /// public event DriveStatusChangedEventHandler DriveStatusChangedEvent; /// /// 脉冲1改变事件 /// public event PositionChangedEventHandler PositionChangedEvent; /// /// 脉冲2改变事件 /// public event PositionChangedEventHandler Position2ChangedEvent; #endregion IsReadyContext isReadyContext = new IsReadyContext(); SysTickContext sysTickContext = new SysTickContext(); CalSpeed calSpeed = new CalSpeed(); IFlyAd2021Comm comm; FlyAd2021Core core; /// /// 不设置服务器 /// bool bShieldSetValueEx; /// /// 用于检测当 为IsRunning时,脉冲是否停了很久。 /// int last_position = int.MinValue; /// /// 最后一次动作时间 /// DateTime drive_time; static string[] propertyName_save; List pushEventArgs = new List(); 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 += (sender, e) => { //这个线程非主线程, 数据接收完,应该快速返回。 //事件触发,都放在主线程操作。 //要有线程锁!!!!! lock (pushEventArgs) { pushEventArgs.Add(e); } }; core.PushRunResultEvent += (sender, e) => { //这个线程非主线程, 数据接收完,应该快速返回。 //事件触发,都放在主线程操作。 lock (pushEventArgs) { pushEventArgs.Add(e); } }; //避免推送太快,全部推送事件统一周期处理 PollModule.Current.Poll_Config(onPoll_PushEvent, TimeSpan.FromSeconds(0.1)); core.StartMeasure(); PollModule.Current.Poll_Config(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(() => { if (!IsConnected) return; if (Surplus < 60000) { if (Surplus > 0) { Surplus--; core.AddAccess(null, null); } } }, TimeSpan.FromMinutes(60)); //每隔1分钟发送一次 脉冲,输入输出,状态 PollModule.Current.Poll_Config(() => { if (!IsConnected) return; AfterConnected_GetFastData(); }, TimeSpan.FromSeconds(60)); //更新线速度 PollModule.Current.Poll_Config(() => { if (calSpeed.Cal(Now, out int speed1, out int speed2)) { Speed = speed1; Speed2 = speed2; } }, TimeSpan.FromSeconds(1)); //当状态为Running时,且每秒脉冲没变,需要 查 当前的状态, 也许Stop状态少推送了 PollModule.Current.Poll_Config(() => { 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); } /// /// 连接后初始化, 获取快速数据 /// void AfterConnected_GetFastData() { core.GetEncAll((asyncContext, _retData) => { PollModule.Current.Dispatcher.BeginInvoke(new Action((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((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((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); } } void _core_PushRunResultEvent(PushRunResultEventArgs e) { Now = sysTickContext.ToDateTime(e.SysTick); Marker = (int)e.Serial; DriveStatus = e.Status; isReadyContext.isReadyGetState = true; advPushStatus(); } /// /// 计数32位脉冲 /// /// 上一次脉冲 /// 低16位脉冲 /// int CalPosition(int lastPostion, UInt16 enc) { //Position UInt16 lastEnc = (UInt16)(lastPostion & 0xffff); Int16 d = (Int16)(enc - lastEnc); lastPostion += d; return lastPostion; } /// /// 低频处理事件 /// void onPoll_PushEvent() { EventArgs[] pushEventArgs; lock (this.pushEventArgs) { pushEventArgs = this.pushEventArgs.ToArray(); this.pushEventArgs.Clear(); } foreach (var e in pushEventArgs) { if (e is PushDataEventArgs) { _core_PushDataEvent(e as PushDataEventArgs); } else if (e is PushRunResultEventArgs) { _core_PushRunResultEvent(e as PushRunResultEventArgs); } } } void _core_PushDataEvent(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; } } private void Core_PushDataEvent(object sender, PushDataEventArgs _e) { //这个线程非主线程, 数据接收完,应该快速返回。 //事件触发,都放在主线程操作。 //要有线程锁!!!!! lock (pushEventArgs) { pushEventArgs.Add(_e); } } private void Core_PropertyChanged(object sender, PropertyChangedEventArgs e) { if (e.PropertyName == nameof(core.IsConnected)) { if (core.IsConnected) { ConnectCnt++; AfterConnected(); } } } /// /// 连接后初始化 /// 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((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; } /// /// 属性改变,自动保存 /// /// /// 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 /// /// 连接 /// 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); } /// /// 连接 addr /// /// 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(); } /// /// 重连 /// public void ReConnect() { Connect(); } #endregion #region IFlyAD function /// /// Out0 = 0, SetOutput(0x0001,0x0000); /// Out0 = 1, Out1 = 0, SetOutput(0x0003,0x0001); /// /// /// public void SetOutput(UInt16 mask, UInt16 enable) { core.SetOutPorts(mask, enable, (asyncConetext, _retData) => { GetOut(); }, null); } #region 运动参数 /// /// 设置 运动参数 /// /// 脉冲/grid /// 电机类型 /// 脉冲比例 分母(电机脉冲) /// 脉冲比例 分子(编码器脉冲) 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 速度参数 /// /// 设置速度参数 /// /// runto 速度 pps /// 开始速度 pps /// 加速时间 ms /// 减速时间 ms /// 归0 第1段速 pps /// 归0 第2段速 pps 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); } /// /// 设置速度 /// /// public void SetVelocity(UInt32 velocity) { core.SetRunParam_V(velocity, null, null); core.GetRunParam_V((asyncContext, retData) => Velocity = (UInt32)retData, null); } #endregion #region 密码 /// /// 输入系统授权码 /// /// 系统授权码access[8] public void SetAccess(byte[] access) { core.CheckAccessCode(access, (asyncContext, retData) => { //AreaRet = (AREA_ERR)retData; GetAccess(); }, null); } /// /// 初始化系统信息区 /// public void InitArea() { core.InitArea((asyncContext, retData) => { GetAccess(); }, null); } #endregion #region 运行动作 /// /// 运行至指定位置 /// /// 脉冲 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); } /// /// 归原点 /// public void Origin() { DriveOrder = DRIVE_MAN_ORDER.ORIGIN; DriveStatus = DRIVE_MAN_STATUS.RUNNING; drive_time = DateTime.Now; core.Org(124, null, null); } /// /// 停止 /// 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); } /// /// 反向,直到撞了限位 /// public void Backward() { DriveOrder = DRIVE_MAN_ORDER.BACKWORD; DriveStatus = DRIVE_MAN_STATUS.RUNNING; drive_time = DateTime.Now; core.Backw(125, null, null); } /// /// 正行,直到撞了限位 /// public void Forward() { DriveOrder = DRIVE_MAN_ORDER.FORWORD; DriveStatus = DRIVE_MAN_STATUS.RUNNING; drive_time = DateTime.Now; core.Forw(126, null, null); } #endregion #region 同步控制 同步状态转换规则 /// /// 进入同步状态 /// public void SyncBegin() { core.SyncRun_Start(null, null); } /// /// 退出同步状态 /// public void SyncEnd() { core.SyncRun_Stop(null, null); } /// /// 清空同步指令 /// public void SyncClear() { core.SyncRun_Clear(null, null); } #endregion #region 同步扫描 脚本指令 /// /// 同步扫描至; /// D+0xE0+开始主轴位置+结束主轴位置+结束横向脉冲位置(逻辑位置)+脉冲开关(1B)+命令识标号(4B) /// /// /// /// /// /// 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); } /// /// 位于队列头时运行,归零; /// D+0xE1+命令识标号(4B) /// /// public void SyncOrigin(Int32 marker) { core.SyncRun_Origin((UInt32)marker, null, null); } /// /// 位于队列头时运行,以速度运行至物理位置; /// D+0xE2+横向脉冲位置(4B:int32,物理位置)+速度(4B:int32)+脉冲开关(1B)+命令识标号(4B) /// /// /// /// /// public void SyncRunTo(int pos1, UInt32 velocity, bool hasDataGrid, Int32 marker) { //TODO, 怎样解决 grid 数据? core.SyncRun_RunTo(pos1, velocity, (UInt32)marker, null, null); } /// /// 位于队列头时运行,以速度运行至逻辑位置; /// D+0xE3+横向脉冲位置(4B:int32,逻辑位置)+速度(4B:int32)+脉冲开关(1B)+命令识标号(4B) /// /// /// /// /// public void SyncRunToLC(int pos1lc, UInt32 velocity, bool hasDataGrid, Int32 marker) { core.SyncRun_RunToLC(pos1lc, velocity, (UInt32)marker, null, null); } /// /// 等待,ms; /// D+0xE4+毫秒数(4B:int32)+命令识标号(4B) /// /// /// public void SyncWait(int ms, Int32 marker) { //没有实现!!!! } #endregion #endregion } class FlyAd2021JsonDb { static Mapper Mapper { get; } = new AutoMapper.Mapper(new MapperConfiguration(c => { c.CreateMap().ReverseMap(); })); public static void Save(string jsonDbPath, FlyAd2021 src) { if (string.IsNullOrEmpty(jsonDbPath)) return; var p = Mapper.Map(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(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; /// /// 硬件版本 /// version = 1,不支持 systick /// version = 2,支持 timeGridAdv /// version = 3,伟的大AD盒, io口定义不一样 /// public int HardwareVersion = 2021; public static string[] GetMemberNames() { var type = typeof(FlyAd2021JsonDb); return type.GetMembers().Select(mi => mi.Name).ToArray(); } } /// /// 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个小时。 /// class SysTickContext { byte systick_1st = 0; DateTime dt_1st = DateTime.MinValue; /// /// /// public event Action BeReseted; public void Reset() { dt_1st = DateTime.MinValue; } /// /// 输入从 flyad7 获取的 timemark, 转换为 本地 DateTime /// /// 只有低7位有效 /// 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; } /// /// 7位 systick1-systick2 /// /// /// /// 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; } } }