diff --git a/CapMachine.Model/CapMachine.Model.csproj b/CapMachine.Model/CapMachine.Model.csproj index 6385d81..eeb5253 100644 --- a/CapMachine.Model/CapMachine.Model.csproj +++ b/CapMachine.Model/CapMachine.Model.csproj @@ -8,4 +8,7 @@ + + + diff --git a/CapMachine.Model/ConfigAlarm.cs b/CapMachine.Model/ConfigAlarm.cs new file mode 100644 index 0000000..a37a311 --- /dev/null +++ b/CapMachine.Model/ConfigAlarm.cs @@ -0,0 +1,38 @@ +using FreeSql.DataAnnotations; + +namespace CapMachine.Model +{ + /// + /// 报警配置 + /// + [Table(Name = "ConfigAlarm")] + public class ConfigAlarm + { + /// + /// 主键 + /// + [Column(IsPrimary = true, IsIdentity = true)] + public long Id { get; set; } + + /// + /// 序号 + /// + [Column(Name = "IndexNo", IsNullable = false)] + public int IndexNo { get; set; } + + /// + /// 快速设置仪表名称 + /// + [Column(Name = "MeterName", IsNullable = true, StringLength = 30)] + public string MeterName { get; set; } + + /// + /// Alarm + /// + [Column(Name = "Alarm", IsNullable = true)] + public double Alarm { get; set; } + + [Column(ServerTime = DateTimeKind.Local, CanUpdate = false)] + public DateTime CreateTime { get; set; } + } +} diff --git a/CapMachine.Model/ProKpStepExecute.cs b/CapMachine.Model/ProKpStepExecute.cs index a129f1b..7e6f14a 100644 --- a/CapMachine.Model/ProKpStepExecute.cs +++ b/CapMachine.Model/ProKpStepExecute.cs @@ -7,159 +7,159 @@ using System.Threading.Tasks; namespace CapMachine.Model { - /// - /// 程序段具体步骤执行信息 - /// - [Table(Name = "ProStepExecute")] - public class ProStepExecute - { - /// - /// 主键 - /// - [Column(IsPrimary = true)] - public Guid Id { get; set; } + ///// + ///// 程序段具体步骤执行信息 + ///// + //[Table(Name = "ProStepExecute")] + //public class ProStepExecute + //{ + // /// + // /// 主键 + // /// + // [Column(IsPrimary = true)] + // public Guid Id { get; set; } - /// - /// 程序段名称 - /// - [Column(Name = "ProName", IsNullable = false, StringLength = 20)] - public string ProName { get; set; } + // /// + // /// 程序段名称 + // /// + // [Column(Name = "ProName", IsNullable = false, StringLength = 20)] + // public string ProName { get; set; } - /// - /// 程序段步骤 - /// - [Column(Name = "ProStep", IsNullable = false)] - public int ProStep { get; set; } + // /// + // /// 程序段步骤 + // /// + // [Column(Name = "ProStep", IsNullable = false)] + // public int ProStep { get; set; } - /// - /// 程序段反复 - /// - [Column(Name = "ProRepeat")] - public int ProRepeat { get; set; } + // /// + // /// 程序段反复 + // /// + // [Column(Name = "ProRepeat")] + // public int ProRepeat { get; set; } - /// - /// 是否正在执行当前程序段 - /// - [Column(Name = "IsCurrentProStep")] - public bool IsCurrentProStep { get; set; } + // /// + // /// 是否正在执行当前程序段 + // /// + // [Column(Name = "IsCurrentProStep")] + // public bool IsCurrentProStep { get; set; } - ///////////////////////////////////////////////////////////////// - ////////////////////////程序步骤/////////////////////////////// - //////////////////////////////////////////////////////////////// + // ///////////////////////////////////////////////////////////////// + // ////////////////////////程序步骤/////////////////////////////// + // //////////////////////////////////////////////////////////////// - /// - /// 是否正在执行当前程序段 - /// - [Column(Name = "IsCurrentMeterStep")] - public bool IsCurrentMeterStep { get; set; } + // /// + // /// 是否正在执行当前程序段 + // /// + // [Column(Name = "IsCurrentMeterStep")] + // public bool IsCurrentMeterStep { get; set; } - /// - /// 仪表功能名称 - /// - [Column(Name = "MeterName", IsNullable = false, StringLength = 20)] - public string MeterName { get; set; } + // /// + // /// 仪表功能名称 + // /// + // [Column(Name = "MeterName", IsNullable = false, StringLength = 20)] + // public string MeterName { get; set; } - /// - /// 步骤 - /// - [Column(Name = "MeterStep", IsNullable = false)] - public int MeterStep { get; set; } + // /// + // /// 步骤 + // /// + // [Column(Name = "MeterStep", IsNullable = false)] + // public int MeterStep { get; set; } - /// - /// 速度 DegC - /// - [Column(Name = "SV", IsNullable = true)] - public int SV { get; set; } + // /// + // /// 速度 DegC + // /// + // [Column(Name = "SV", IsNullable = true)] + // public int SV { get; set; } - /// - /// 时间-分钟 - /// - [Column(Name = "TimeMin", IsNullable = true)] - public int TimeMin { get; set; } + // /// + // /// 时间-分钟 + // /// + // [Column(Name = "TimeMin", IsNullable = true)] + // public int TimeMin { get; set; } - /// - /// 时间-秒 - /// - [Column(Name = "TimeSec", IsNullable = true)] - public int TimeSec { get; set; } + // /// + // /// 时间-秒 + // /// + // [Column(Name = "TimeSec", IsNullable = true)] + // public int TimeSec { get; set; } - /// - /// PID NO - /// - [Column(Name = "PIDNo", IsNullable = true)] - public int PIDNo { get; set; } + // /// + // /// PID NO + // /// + // [Column(Name = "PIDNo", IsNullable = true)] + // public int PIDNo { get; set; } - /// - /// Limit NO - /// - [Column(Name = "LitmitNo", IsNullable = true)] - public int LitmitNo { get; set; } + // /// + // /// Limit NO + // /// + // [Column(Name = "LitmitNo", IsNullable = true)] + // public int LitmitNo { get; set; } - /// - /// Alarm NO - /// - [Column(Name = "AlarmNo", IsNullable = true)] - public int AlarmNo { get; set; } + // /// + // /// Alarm NO + // /// + // [Column(Name = "AlarmNo", IsNullable = true)] + // public int AlarmNo { get; set; } - ///// - ///// 时间信号 - ///// - //[Column(Name = "TimeSign1", IsNullable = true)] - //public int TimeSign1 { get; set; } + // ///// + // ///// 时间信号 + // ///// + // //[Column(Name = "TimeSign1", IsNullable = true)] + // //public int TimeSign1 { get; set; } - ///// - ///// 时间信号 - ///// - //[Column(Name = "TimeSign2", IsNullable = true)] - //public int TimeSign2 { get; set; } + // ///// + // ///// 时间信号 + // ///// + // //[Column(Name = "TimeSign2", IsNullable = true)] + // //public int TimeSign2 { get; set; } - ///// - ///// 时间信号 - ///// - //[Column(Name = "TimeSign3", IsNullable = true)] - //public int TimeSign3 { get; set; } + // ///// + // ///// 时间信号 + // ///// + // //[Column(Name = "TimeSign3", IsNullable = true)] + // //public int TimeSign3 { get; set; } - /// - /// 步进重复 - /// - [Column(Name = "Repeat", IsNullable = true)] - public int StepRepeat { get; set; } + // /// + // /// 步进重复 + // /// + // [Column(Name = "Repeat", IsNullable = true)] + // public int StepRepeat { get; set; } - ///// - ///// 拓展字段1 - ///// - //[Column(Name = "FeildExte1", IsNullable = true)] - //public string FeildExte1 { get; set; } + // ///// + // ///// 拓展字段1 + // ///// + // //[Column(Name = "FeildExte1", IsNullable = true)] + // //public string FeildExte1 { get; set; } - ///// - ///// 拓展字段1 - ///// - //[Column(Name = "FeildExte2", IsNullable = true)] - //public string FeildExte2 { get; set; } + // ///// + // ///// 拓展字段1 + // ///// + // //[Column(Name = "FeildExte2", IsNullable = true)] + // //public string FeildExte2 { get; set; } - ///// - ///// 拓展字段1 - ///// - //[Column(Name = "FeildExte3", IsNullable = true)] - //public string FeildExte3 { get; set; } + // ///// + // ///// 拓展字段1 + // ///// + // //[Column(Name = "FeildExte3", IsNullable = true)] + // //public string FeildExte3 { get; set; } - ///// - ///// 拓展字段1 - ///// - //[Column(Name = "FeildExte4", IsNullable = true)] - //public string FeildExte4 { get; set; } + // ///// + // ///// 拓展字段1 + // ///// + // //[Column(Name = "FeildExte4", IsNullable = true)] + // //public string FeildExte4 { get; set; } - ///// - ///// 拓展字段1 - ///// - //[Column(Name = "FeildExte5", IsNullable = true)] - //public string FeildExte5 { get; set; } + // ///// + // ///// 拓展字段1 + // ///// + // //[Column(Name = "FeildExte5", IsNullable = true)] + // //public string FeildExte5 { get; set; } - [Column(ServerTime = DateTimeKind.Local, CanUpdate = false)] - public DateTime CreateTime { get; set; } + // [Column(ServerTime = DateTimeKind.Local, CanUpdate = false)] + // public DateTime CreateTime { get; set; } - } + //} } diff --git a/CapMachine.Wpf/App.xaml.cs b/CapMachine.Wpf/App.xaml.cs index 56bafdf..fd1991c 100644 --- a/CapMachine.Wpf/App.xaml.cs +++ b/CapMachine.Wpf/App.xaml.cs @@ -92,13 +92,16 @@ namespace CapMachine.Wpf { ////注册日志服务 containerRegistry.RegisterSingleton(); + //注册AutoMapper 将IAutoMapperProvider注入IOC容器,并对外提供IMapper注入类型。 + containerRegistry.RegisterSingleton(); + containerRegistry.Register(typeof(IMapper), GetMapper); //注册基础的服务 //containerRegistry.RegisterSingleton(); //containerRegistry.RegisterSingleton(); //containerRegistry.RegisterSingleton(); - + containerRegistry.RegisterSingleton(); containerRegistry.RegisterSingleton(); ////注册设备服务 @@ -112,10 +115,8 @@ namespace CapMachine.Wpf containerRegistry.RegisterSingleton(); containerRegistry.RegisterSingleton(); - - //注册AutoMapper 将IAutoMapperProvider注入IOC容器,并对外提供IMapper注入类型。 - containerRegistry.RegisterSingleton(); - containerRegistry.Register(typeof(IMapper), GetMapper); + + containerRegistry.RegisterSingleton(); string strsqllite = System.AppDomain.CurrentDomain.BaseDirectory + @"Db\CapMachine.db"; string strslocaldb = System.AppDomain.CurrentDomain.BaseDirectory + @"Db\CapMachineDb"; @@ -256,6 +257,7 @@ namespace CapMachine.Wpf var appVersionService10 = ContainerLocator.Container.Resolve(); //var appVersionService11 = ContainerLocator.Container.Resolve(); var appVersionService15 = ContainerLocator.Container.Resolve(); + var appVersionService16 = ContainerLocator.Container.Resolve(); diff --git a/CapMachine.Wpf/CapMachine.Wpf.csproj b/CapMachine.Wpf/CapMachine.Wpf.csproj index ed0e2f7..b30488a 100644 --- a/CapMachine.Wpf/CapMachine.Wpf.csproj +++ b/CapMachine.Wpf/CapMachine.Wpf.csproj @@ -715,8 +715,6 @@ - - diff --git a/CapMachine.Wpf/ChannelModel/ProRunChannelData.cs b/CapMachine.Wpf/ChannelModel/ProRunChannelData.cs new file mode 100644 index 0000000..4b358e1 --- /dev/null +++ b/CapMachine.Wpf/ChannelModel/ProRunChannelData.cs @@ -0,0 +1,57 @@ +using CapMachine.Wpf.Dtos; +using CapMachine.Wpf.Models.ProModelPars; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CapMachine.Wpf.ChannelModel +{ + /// + /// 程序运行管道数据 + /// + public class ProRunChannelData + { + /// + /// 参数名称 + /// + public string? MeterName { get; set; } + + /// + /// 程序Seg + /// + public string? ProSegName { get; set; } + + /// + /// 程序步骤 + /// + public int MeterStep { get; set; } + + /// + /// 斜坡打点步骤 + /// + public int SlopStepNo { get; set; } + + /// + /// 值类型 + /// + public RunStepType RunStepType { get; set; } + + /// + /// 值 + /// + public int? SV { get; set; } + + /// + /// PID的配置信息 + /// + public PID? CurLoadPID { get; set; } + + /// + /// Alarm的配置信息 + /// + public Limit? CurLoadLimit { get; set; } + + } +} diff --git a/CapMachine.Wpf/Dtos/ConfigAlarmDto.cs b/CapMachine.Wpf/Dtos/ConfigAlarmDto.cs new file mode 100644 index 0000000..3f829cc --- /dev/null +++ b/CapMachine.Wpf/Dtos/ConfigAlarmDto.cs @@ -0,0 +1,43 @@ +using Prism.Mvvm; + +namespace CapMachine.Wpf.Dtos +{ + public class ConfigAlarmDto : BindableBase + { + /// + /// 主键 + /// + public long Id { get; set; } + + private string? _MeterName; + /// + /// 仪表名称 + /// + public string? MeterName + { + get { return _MeterName; } + set { _MeterName = value; RaisePropertyChanged(); } + } + + private int _IndexNo; + /// + /// 序号 + /// + public int IndexNo + { + get { return _IndexNo; } + set { _IndexNo = value; RaisePropertyChanged(); } + } + + private double _Alarm; + /// + /// Alarm + /// + public double Alarm + { + get { return _Alarm; } + set { _Alarm = value; RaisePropertyChanged(); } + } + + } +} diff --git a/CapMachine.Wpf/Models/Meter/MeterRtDataModel.cs b/CapMachine.Wpf/Models/Meter/MeterRtDataModel.cs index 0f848cf..cc1cbd8 100644 --- a/CapMachine.Wpf/Models/Meter/MeterRtDataModel.cs +++ b/CapMachine.Wpf/Models/Meter/MeterRtDataModel.cs @@ -1,4 +1,5 @@ using CapMachine.Model; +using CapMachine.Wpf.Models.ProModelPars; using HslCommunication; using Prism.Mvvm; @@ -17,12 +18,12 @@ namespace CapMachine.Wpf.Models /// public MeterRtDataModel() { - ListProStepExecuteInfo = new List(); + ListProStepExecuteInfo = new List(); ListQuickProStepExecuteInfo = new List(); QuickRunTimeInfo = new QuickRunTime(); QuickNextMeterStep = new QuickProStepExecute(); RunTimeInfo = new MeterRunTime(); - NextMeterStep = new ProStepExecute(); + NextMeterStep = new ProStepExe(); } @@ -252,7 +253,7 @@ namespace CapMachine.Wpf.Models /// /// 程序段和程序步骤执行具体方法 /// - public List ListProStepExecuteInfo { get; set; } + public List ListProStepExecuteInfo { get; set; } /// /// 快速设置程序段和程序步骤执行具体方法 @@ -277,7 +278,7 @@ namespace CapMachine.Wpf.Models /// /// 仪表下一步具体程序步骤 /// - public ProStepExecute NextMeterStep { get; set; } + public ProStepExe NextMeterStep { get; set; } /// /// Quick仪表下一步具体程序步骤 diff --git a/CapMachine.Wpf/Models/PlcLoadConfigCell.cs b/CapMachine.Wpf/Models/PlcLoadConfigCell.cs new file mode 100644 index 0000000..8903d3a --- /dev/null +++ b/CapMachine.Wpf/Models/PlcLoadConfigCell.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CapMachine.Wpf.Models +{ + /// + /// PLC加载配置单元 + /// 下载PLC数据,用整型的数据下载,但是我们这边可能是浮点数,需要格式的转换,精度的转换 + /// + public class PlcLoadConfigCell + { + /// + /// 配置字段 名称 + /// + public string? Name { get; set; } + + /// + /// 地址 + /// + public string? Address { get; set; } + + /// + /// 精度 1,10,100,1000 + /// + public int Precision { get; set; } + } +} diff --git a/CapMachine.Wpf/Models/ProModelPars/Alarm.cs b/CapMachine.Wpf/Models/ProModelPars/Alarm.cs new file mode 100644 index 0000000..b0e190e --- /dev/null +++ b/CapMachine.Wpf/Models/ProModelPars/Alarm.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CapMachine.Wpf.Models.ProModelPars +{ + public class Alarm + { + public double AlarmValue { get; set; } + } +} diff --git a/CapMachine.Wpf/Models/ProModelPars/Limit.cs b/CapMachine.Wpf/Models/ProModelPars/Limit.cs new file mode 100644 index 0000000..8ba98d7 --- /dev/null +++ b/CapMachine.Wpf/Models/ProModelPars/Limit.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CapMachine.Wpf.Models.ProModelPars +{ + /// + /// 下载时用的Limit + /// 进制和精度也需要处理好 + /// + public class Limit + { + /// + /// Limit-Up + /// + public short Up { get; set; } + + /// + /// Limit-Down + /// + public short Down { get; set; } + + } +} diff --git a/CapMachine.Wpf/Models/ProModelPars/PID.cs b/CapMachine.Wpf/Models/ProModelPars/PID.cs new file mode 100644 index 0000000..be61531 --- /dev/null +++ b/CapMachine.Wpf/Models/ProModelPars/PID.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CapMachine.Wpf.Models.ProModelPars +{ + /// + /// 下载时用的PID + /// 进制也需要处理好 + /// + public class PID + { + /// + /// PID-P + /// + public short P { get; set; } + + /// + /// PID-I + /// + public short I { get; set; } + + + /// + /// PID-D + /// + public short D { get; set; } + + } +} diff --git a/CapMachine.Wpf/Models/ProModelPars/ParsConfigLimitDto.cs b/CapMachine.Wpf/Models/ProModelPars/ParsConfigLimitDto.cs new file mode 100644 index 0000000..164b2f6 --- /dev/null +++ b/CapMachine.Wpf/Models/ProModelPars/ParsConfigLimitDto.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CapMachine.Wpf.Models.ProModelPars +{ + /// + /// 配置限制Dto + /// + public class ParsConfigLimitDto + { + /// + /// 主键 + /// + public long Id { get; set; } + + /// + /// 设置仪表名称 + /// + public string? MeterName { get; set; } + + /// + /// 序号 + /// + public int IndexNo { get; set; } + + /// + /// 上限 + /// + public decimal Up { get; set; } + + /// + /// 下限 + /// + public decimal Down { get; set; } + } +} diff --git a/CapMachine.Wpf/Models/ProModelPars/ParsConfigPIDDto.cs b/CapMachine.Wpf/Models/ProModelPars/ParsConfigPIDDto.cs new file mode 100644 index 0000000..71473c1 --- /dev/null +++ b/CapMachine.Wpf/Models/ProModelPars/ParsConfigPIDDto.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CapMachine.Wpf.Models.ProModelPars +{ + /// + /// PID 配置模型Dto + /// + public class ParsConfigPIDDto + { + /// + /// 主键 + /// + public long Id { get; set; } + + /// + /// 设置仪表名称 + /// + public string? MeterName { get; set; } + + /// + /// 序号 + /// + public int IndexNo { get; set; } + + /// + /// P + /// + public decimal P { get; set; } + + /// + /// I + /// + public int I { get; set; } + + /// + /// D + /// + public int D { get; set; } + } +} diff --git a/CapMachine.Wpf/Models/ProModelPars/ProExModel.cs b/CapMachine.Wpf/Models/ProModelPars/ProExModel.cs new file mode 100644 index 0000000..de0a758 --- /dev/null +++ b/CapMachine.Wpf/Models/ProModelPars/ProExModel.cs @@ -0,0 +1,401 @@ +using CapMachine.Wpf.ChannelModel; +using CapMachine.Wpf.Services; +using ImTools; +using Masuit.Tools; +using Masuit.Tools.Hardware; +using Prism.Mvvm; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Channels; +using System.Threading.Tasks; +using System.Timers; + +namespace CapMachine.Wpf.Models.ProModelPars +{ + /// + /// 程序执行模型 + /// 包括程序名称和程序步骤集合、程序执行信息 + /// 一个参数(速度、排气压力)对应一个程序执行模型 + /// + public class ProExModel : BindableBase + { + /// + /// 实例化函数 + /// + public ProExModel(Channel channel) + { + ProRunChannel = channel; + + //秒触发一次 + CycleTimer = new System.Timers.Timer(1000); + CycleTimer.Elapsed += SlopExCycleAction; + CycleTimer.AutoReset = true; + CycleTimer.Enabled = true; + CycleTimer.Start(); + } + + + /// + /// 程序执行管道 + /// + public Channel ProRunChannel { get; set; } + + /// + /// 名称 + /// + public string MeterName { get; set; } + + /// + /// 当前模型是否启用 + /// 当前有很多参数都是预设,但是有些参数是为其他的项目准备的,可能在当前的项目上都不会配置和使用。 + /// 故设置Enable属性 + /// + public bool Enable { get; set; } = true; + + /// + /// 程序步骤集合 + /// + public List ListProStepExe { get; set; } + + /// + /// 仪表步骤执行时间信息 + /// + public ProRunTime ProRunTimeModel { get; set; } + + /// + /// 下一步步骤数据执行 + /// + public ProStepExe NextProStepExe { get; set; } + + /// + /// 当前步骤数据执行 + /// 给看步骤是否变化使用 + /// + public ProStepExe CurProStepExe { get; set; } + + /// + /// 上一步步骤数据执行 + /// 给看步骤是否变化使用 + /// + public ProStepExe LastProStepExe { get; set; } + + + /// + /// 当前程序段时间长 + /// + public int CurProTimeSum { get; set; } + + /// + /// 当前程序段开始时间 + /// + public DateTime CurProStartTime { set; get; } + + + #region 仪表步骤执行时间信息 + + public EventHandler RunTimeCallSglEvent; + + /// + /// 是否启用 + /// + public bool RunEnable { get; set; } = false; + + /// + /// RunTimeCallSglEvent 是否注册关联方法 + /// + public bool EventRegister { get; set; } = false; + + /// + /// 当前步骤开始运行时间 + /// + public DateTime StepStartDt { get; set; } + + /// + /// 当前步骤结束运行时间 + /// + public DateTime StepEndDt { get; set; } + + + private DateTime _CurrentDateTime; + /// + /// 当前时间 + /// + public DateTime CurrentDateTime + { + get + { + return _CurrentDateTime; + } + set + { + //value.ToString("yyyy-MM-dd HH:mm:ss") == EndDateTime.ToString("yyyy-MM-dd HH:mm:ss") + if (RunEnable == true && value >= StepEndDt) + { + _CurrentDateTime = value; + //达到后不再触发 + //RunEnable = false; + //时间到了触发下载下一步步骤 + + //不为空的数据 + if (NextProStepExe == null) + { + Console.WriteLine($"【时间】{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff")} 【参数名称】:{MeterName} " + + $"【Msg】:没有下一步,当前仪表参数全部执行完毕 "); + + //为空时不执行后续的数据 + RunEnable = false; + return; + } + + Console.WriteLine($"【时间】{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff")} 【参数名称】:{MeterName} " + + $"【程序Seg】{CurProStepExe.ProSegName} " + + $"【程序步骤】{CurProStepExe.MeterStep} " + + $"【Msg】:时间到,开始执行下一步步骤 "); + + ////////首先判断参数是否相同/////////// + + var SvResult = false;//True代表不同,false代表相同 + //判断PID是否跟上一次一样 + if (CurProStepExe.EndSV != NextProStepExe.EndSV) + { + SvResult = true; + } + var PidResult = false;//True代表不同,false代表相同 + //判断PID是否跟上一次一样 + if (CurProStepExe.PIDNo != NextProStepExe.PIDNo) + { + PidResult = true; + } + var LimitResult = false;//True代表不同,false代表相同 + //判断Limit是否跟上一次一样 + if (CurProStepExe.LimitNo != NextProStepExe.LimitNo) + { + LimitResult = true; + } + + ////////发送步骤信息/////////// + if (NextProStepExe.ExistSlop) + { + //存在坡度数据 + var SecStepDur = NextProStepExe.EndSV - NextProStepExe.StartSV; + var SecStepValue = SecStepDur * 1.0 / NextProStepExe.KeepTime; + //先清除数据 + ListSlopExStep.Clear(); + //组装斜坡数据,按照秒为间隔发送 + for (var i = 1; i <= NextProStepExe.KeepTime; i++) + { + var SlopExStep = new SlopExStep() + { + StepNo = i, + SV = NextProStepExe.StartSV + (int)(SecStepValue * i), + IsHasEx = false, + }; + ListSlopExStep.Add(SlopExStep); + } + //需要发送一次StartSV数据吗? + + //组装完成开始循环打点 + StartSlopExStep(); + + } + else//不存在斜坡数据的话,则直接发送EndSV数据即可 + { + ProRunChannel.Writer.TryWrite(new ProRunChannelData() + { + MeterName = MeterName, + SV = NextProStepExe.EndSV, + ProSegName = NextProStepExe.ProSegName, + MeterStep = NextProStepExe.MeterStep, + CurLoadLimit = LimitResult == true ? new Limit() { Up = (short)NextProStepExe.CurConfigLimitDto.Up, Down = (short)NextProStepExe.CurConfigLimitDto.Down } : new Limit(), + CurLoadPID = PidResult == true ? new PID() { P = (short)NextProStepExe.CurConfigPIDDto.P, I = (short)NextProStepExe.CurConfigPIDDto.I, D = (short)NextProStepExe.CurConfigPIDDto.D } : new PID(), + RunStepType = GetRunStepType(PidResult, LimitResult, true), + }); + } + + + ////////准备新的数据/////////// + + LastProStepExe = CurProStepExe.DeepClone(); + //准备下一步步骤数据 + CurProStepExe = NextProStepExe.DeepClone(); + + //标记状态-当前执行中 + if (ListProStepExe.Where(a => a.MeterStep == CurProStepExe.MeterStep).Any()) + { + ListProStepExe.FindFirst(a => a.MeterStep == CurProStepExe.MeterStep).MeterStepIsExeing = true; + } + //标记状态-上一个执行完毕标记 + if (ListProStepExe.Where(a => a.MeterStep == LastProStepExe.MeterStep).Any()) + { + ListProStepExe.FindFirst(a => a.MeterStep == LastProStepExe.MeterStep).MeterStepIsExeing = false; + } + //标记状态-上一个执行完成 + if (ListProStepExe.Where(a => a.MeterStep == LastProStepExe.MeterStep).Any()) + { + ListProStepExe.FindFirst(a => a.MeterStep == LastProStepExe.MeterStep).MeterStepIsOK = true; + } + + + //设置下一步步骤数据 + if (ListProStepExe.Where(x => x.MeterStep == CurProStepExe.MeterStep + 1).Any()) + { + //存在下一步数据 + NextProStepExe = ListProStepExe.FirstOrDefault(x => x.MeterStep == CurProStepExe.MeterStep + 1); + } + else + { + //没有下一步数据则判定为最后一步 + NextProStepExe = null; + } + + //设置步骤开始时间 + StepStartDt = DateTime.Now; + + //设置步骤结束时间 + StepEndDt = StepStartDt.AddSeconds(CurProStepExe.KeepTime); + + //设置下一步步骤运行时间 + RunEnable = true; + + } + else + { + _CurrentDateTime = value; + RunTime = (int)(_CurrentDateTime - StepEndDt).TotalSeconds; + } + } + } + + /// + /// 当前步骤已经运行时长-秒 + /// + public int RunTime { get; set; } + + /// + /// 通过组合Pid和Limit组合出运行步骤类型 + /// + /// PID是否不同 + /// Limit是否不同 + /// SV是否不同 + /// 运行步骤类型 + private RunStepType GetRunStepType(bool pid, bool limit, bool sv) + { + if (pid && limit && sv) + { + return RunStepType.Step; + } + else if (pid && sv) + { + return RunStepType.StepPID; + } + else if (limit && sv) + { + return RunStepType.StepLimit; + } + else if (sv) + { + return RunStepType.StepSV; + } + else + { + return RunStepType.Step; + } + } + + #endregion + + + #region 步骤斜率执行 打点执行 + + /// + /// 开始打点执行 + /// + private void StartSlopExStep() + { + SlopExEnable = true; + } + + /// + /// 斜率执行步骤集合 + /// 打点集合 + /// + public List ListSlopExStep { get; set; } = new List(); + + /// + /// 斜率执行循环周期 + /// + /// + /// + /// + private void SlopExCycleAction(object? sender, ElapsedEventArgs e) + { + try + { + //如果Execute执行的是一个很耗时的方法,会导致方法未执行完毕,定时器又启动了一个线程来执行Execute方法 + //CycleTimer.Stop(); //先关闭定时器 + if (SlopExEnable) + { + var NoExData = ListSlopExStep.Where(a => a.IsHasEx == false).OrderBy(a => a.StepNo).ToList(); + if (NoExData.Any()) + { + //发送步骤信息 + ProRunChannel.Writer.TryWrite(new ProRunChannelData() + { + MeterName = MeterName, + SV = NoExData.First().SV, + + ProSegName = CurProStepExe.ProSegName, + MeterStep = CurProStepExe.MeterStep, + SlopStepNo = NoExData.First().StepNo, + CurLoadLimit = null, + CurLoadPID = null, + RunStepType = RunStepType.SlopCell, + }); + //发送完毕后进行标记数据 + NoExData.First().IsHasEx = true; + + Console.WriteLine($"【时间】{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff")} 【参数名称】:{MeterName} " + + $"【程序Seg】{CurProStepExe.ProSegName} " + + $"【程序步骤】{CurProStepExe.MeterStep} " + + $"【斜坡打点步骤】{NoExData.First().StepNo} " + + $"【斜坡打点值SV】{NoExData.First().SV} " + + $"【Msg】:发送斜坡打点 "); + + } + else + { + //执行完毕了,没有要执行的数据效率 + SlopExEnable = false; + Console.WriteLine($"【时间】{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff")} 【参数名称】:{MeterName} " + + $"【程序Seg】{CurProStepExe.ProSegName} " + + $"【程序步骤】{CurProStepExe.MeterStep} " + + $"【Msg】:斜坡打点执行完毕 "); + return; + } + } + + //CycleTimer.Start(); //执行完毕后再开启器 + } + catch (Exception ex) + { + //CycleTimer.Start(); //执行完毕后再开启器 + //LogService.Info($"时间:{DateTime.Now.ToString()}-【PwAnalyze-CycleAction】-{ex.Message}"); + } + } + + /// + /// 周期定时器 + /// + private System.Timers.Timer CycleTimer { get; set; } + + /// + /// 步骤斜率执行使能状态 + /// + public bool SlopExEnable { get; set; } = false; + + #endregion + + } +} diff --git a/CapMachine.Wpf/Models/ProModelPars/ProRunTime.cs b/CapMachine.Wpf/Models/ProModelPars/ProRunTime.cs new file mode 100644 index 0000000..f705c57 --- /dev/null +++ b/CapMachine.Wpf/Models/ProModelPars/ProRunTime.cs @@ -0,0 +1,88 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CapMachine.Wpf.Models.ProModelPars +{ + /// + /// 程序运行时间 + /// + public class ProRunTime + { + + public EventHandler RunTimeCallSglEvent; + + /// + /// 是否启用 + /// + public bool RunEnable { get; set; } = false; + + /// + /// RunTimeCallSglEvent 是否注册关联方法 + /// + public bool EventRegister { get; set; } = false; + + /// + /// 当前仪表名称 + /// + public string MeterName { get; set; } + + /// + /// 当前程序段名称 + /// + public string ProName { get; set; } + + /// + /// 当前仪表程序步骤 + /// + public int MeterStep { get; set; } + + /// + /// 当前步骤开始运行时间 + /// + public DateTime StartDateTime { get; set; } + + /// + /// 当前步骤结束运行时间 + /// + public DateTime EndDateTime { get; set; } + + + private DateTime currentDateTime; + /// + /// 当前时间 + /// + public DateTime CurrentDateTime + { + get + { + return currentDateTime; + } + set + { + //value.ToString("yyyy-MM-dd HH:mm:ss") == EndDateTime.ToString("yyyy-MM-dd HH:mm:ss") + if (RunEnable == true && value >= EndDateTime) + { + currentDateTime = value; + RunEnable = false; + //时间到了触发下载新的步骤 + //RunTimeCallSglEvent(ProName, MeterName, MeterStep); + //RunTimeCallSglEvent.BeginInvoke(ProName, MeterName, MeterStep, null, null); + //RunEnable = false; + } + else + { + currentDateTime = value; + RunTime = (int)(currentDateTime - StartDateTime).TotalSeconds; + } + } + } + + /// + /// 当前步骤已经运行时长-秒 + /// + public int RunTime { get; set; } + } +} diff --git a/CapMachine.Wpf/Models/ProModelPars/ProStepExe.cs b/CapMachine.Wpf/Models/ProModelPars/ProStepExe.cs new file mode 100644 index 0000000..46330b5 --- /dev/null +++ b/CapMachine.Wpf/Models/ProModelPars/ProStepExe.cs @@ -0,0 +1,135 @@ +using CapMachine.Model; +using CapMachine.Wpf.Dtos; +using Prism.Mvvm; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CapMachine.Wpf.Models.ProModelPars +{ + /// + /// 程序分解后的执行步骤 + /// + public class ProStepExe : BindableBase + { + /// + /// 程序段名称 + /// + public string? ProSegName { get; set; } + + /// + /// 程序段步骤 + /// + public int ProSegStep { get; set; } + + /// + /// 程序段重复执行次数 + /// + public int ProSegRepeat { get; set; } + + /// + /// 程序段当前是否执行中 + /// + public bool ProSegIsExeing { get; set; } + + ///////////////////////////////////////////////////////////////// + ////////////////////////程序步骤/////////////////////////////// + //////////////////////////////////////////////////////////////// + + ///// + ///// 程序步骤标记 + ///// + //public StepPosMark StepPosMark { get; set; } + + /// + /// 仪表参数当前是否执行中 + /// + public bool MeterStepIsExeing { get; set; } + + /// + /// 仪表参数是否执行完成 + /// + public bool MeterStepIsOK { get; set; } + + /// + /// 仪表参数名称 + /// + public string? MeterName { get; set; } + + /// + /// 仪表参数步骤 + /// + public int MeterStep { get; set; } + + /// + /// 这个步骤是打开具体设置步骤界面的那个层面的信息,例如:2-3,代表是程序2里面的仪表步骤3,方便调试和给液击使用 + /// + public string? ProStepInfo { get; set; } + + ///// + ///// 启用状态-没有启用就是什么数据都没有 + ///// Const-常值-常值,StepValue有值,只有一个步骤,CycleTime为0 + ///// MultisStep-有步骤细节-此时在一个仪表下就会有很多步骤的细节数据 + ///// + //public ConfigValueType ConfigState { get; set; } + + /// + /// StartSV- 步骤的开始SV + /// 最终的写到PLC结果值,经过进制转换 + /// + public int StartSV { get; set; } + + /// + /// EndSV- 步骤的目标SV + /// 最终的写到PLC结果值,经过进制转换 + /// + public int EndSV { get; set; } + + /// + /// KeepTime Sec + /// + public int KeepTime { get; set; } + + /// + /// 是否启用坡度 + /// 存在斜坡容易判断,非斜坡是常值 + /// 常值有两种情况: + /// 一个是设置时就直接设定为常值, + /// 另一个是斜率步骤里面比如:起始:8000,结束:9000,那么也是常值,因为当前模型是拆分详细之后的,他可以判断详细步骤的斜坡信息 + /// + public bool ExistSlop { get; set; } + + ///// + ///// 时间-秒-斜坡时间 + ///// + //public int SlopTimeSec { get; set; } + + /// + /// PIDNo + /// + public int PIDNo { get; set; } + + /// + /// PID的配置信息 + /// + public ConfigPIDDto? CurConfigPIDDto { get; set; } + + /// + /// LimitNo + /// + public int LimitNo { get; set; } + + /// + /// AlarmNo的配置信息 + /// + public ConfigLimitDto? CurConfigLimitDto { get; set; } + + /// + /// AlarmNo + /// + public int AlarmNo { get; set; } + + } +} diff --git a/CapMachine.Wpf/Models/ProModelPars/RunStepType.cs b/CapMachine.Wpf/Models/ProModelPars/RunStepType.cs new file mode 100644 index 0000000..9089fa4 --- /dev/null +++ b/CapMachine.Wpf/Models/ProModelPars/RunStepType.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CapMachine.Wpf.Models.ProModelPars +{ + /// + /// 运行和下载的数据类型 + /// + public enum RunStepType + { + /// + /// 正常的步骤信息 SV-PID-Limit 下载数据 + /// 就是:包括:SV PID和SLIMIT的数据,当然SV PID和SLIMIT跟上次是一样的话,则不需要下载 + /// + Step = 1, + + /// + /// 正常的步骤信息-SV-PID 下载数据 + /// 就是:包括:SV PID和SLIMIT的数据,当然SV PID和SLIMIT跟上次是一样的话,则不需要下载 + /// + StepPID = 2, + + /// + /// 正常的步骤信息-SV-Limit 下载数据 + /// 就是:包括:SV PID和SLIMIT的数据,当然SV PID和SLIMIT跟上次是一样的话,则不需要下载 + /// + StepLimit = 3, + + /// + /// 正常的步骤信息-SV 下载数据 + /// 就是:包括:SV PID和SLIMIT的数据,当然SV PID和SLIMIT跟上次是一样的话,则不需要下载 + /// + StepSV = 4, + + /// + /// 斜率单元 + /// 带斜率的数据打点执行,只传送SV值 + /// 比如速度:0-5000 5秒,此时执行:第一秒:1000,第二秒:2000,第三秒:3000,第四秒:4000,第五秒:5000 + /// + SlopCell = 10 + } +} diff --git a/CapMachine.Wpf/Models/ProModelPars/SlopExStep.cs b/CapMachine.Wpf/Models/ProModelPars/SlopExStep.cs new file mode 100644 index 0000000..4829576 --- /dev/null +++ b/CapMachine.Wpf/Models/ProModelPars/SlopExStep.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CapMachine.Wpf.Models.ProModelPars +{ + /// + /// 斜率执行步骤 + /// + public class SlopExStep + { + /// + /// 步骤号 + /// + public int StepNo { get; set; } + + /// + /// SV值 + /// + public int SV { get; set; } + + /// + /// 是否已经执行 + /// + public bool IsHasEx { get; set; }=false; + } +} diff --git a/CapMachine.Wpf/Models/ProModelPars/StepPlcCell.cs b/CapMachine.Wpf/Models/ProModelPars/StepPlcCell.cs new file mode 100644 index 0000000..feb607b --- /dev/null +++ b/CapMachine.Wpf/Models/ProModelPars/StepPlcCell.cs @@ -0,0 +1,71 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CapMachine.Wpf.Models.ProModelPars +{ + /// + /// PLC下载单元 + /// + public class StepPlcCell : HslCommunication.IDataTransfer + { + public ushort ReadCount { get; set; } = 10; + + public void ParseSource(byte[] Content) + { + throw new NotImplementedException(); + } + + public byte[] ToSource() + { + throw new NotImplementedException(); + } + + + #region 步骤数据 + + /// + /// 时间-分钟 + /// + public short TimeMin { get; set; } + + /// + /// 时间-秒 + /// + public short TimeSec { get; set; } + + /// + /// SV值 + /// + public short SV { get; set; } + + /// + /// PID-P + /// + public short PID_P { get; set; } + + /// + /// PID-I + /// + public short PID_I { get; set; } + + /// + /// PID-D + /// + public short PID_D { get; set; } + + /// + /// Limit-Up + /// + public short Limit_Up { get; set; } + + /// + /// Limit-Down + /// + public short Limit_Down { get; set; } + + #endregion + } +} diff --git a/CapMachine.Wpf/Models/ProModelPars/StepPosMark.cs b/CapMachine.Wpf/Models/ProModelPars/StepPosMark.cs new file mode 100644 index 0000000..a0b7b04 --- /dev/null +++ b/CapMachine.Wpf/Models/ProModelPars/StepPosMark.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CapMachine.Wpf.Models.ProModelPars +{ + /// + /// 程序步骤标记 + /// + public enum StepPosMark + { + + } +} diff --git a/CapMachine.Wpf/Services/MachineRtDataService.cs b/CapMachine.Wpf/Services/MachineRtDataService.cs index 55ba785..b8347c3 100644 --- a/CapMachine.Wpf/Services/MachineRtDataService.cs +++ b/CapMachine.Wpf/Services/MachineRtDataService.cs @@ -5,6 +5,7 @@ using CapMachine.Wpf.Models; using CapMachine.Wpf.Models.Tag; using CapMachine.Wpf.PrismEvent; using HslCommunication; +using HslCommunication.Profinet.Melsec; using HslCommunication.Profinet.Siemens; using Prism.Events; using Prism.Mvvm; @@ -52,6 +53,11 @@ namespace CapMachine.Wpf.Services /// public SiemensS7Net SiemensDrive { get; set; } + /// + /// 三菱连接驱动程序 + /// + public MelsecMcNet MelsecMcNetDrive { get; set; } + private bool _LinkState; /// /// PLC连接状态 @@ -123,6 +129,8 @@ namespace CapMachine.Wpf.Services //stopwatch.Stop(); //停止Stopwatch //Console.WriteLine("Add Elapsed output runTime:{0}", stopwatch.Elapsed.ToString()); + //MelsecMcNetDrive. + //事件服务 _EventAggregator = eventAggregator; AlarmService = alarmService; @@ -149,7 +157,7 @@ namespace CapMachine.Wpf.Services TagManger.AddTag(new Tag("COND2压力", "COND2压力[BarA]", "Cond2Press", "程序", "VW15012", 100, 0, 100, "BarA", new ShortTagValue(), false) { DecimalPoint = 2 }); TagManger.AddTag(new Tag("OCR", "OCR[%]", "OCR", "程序", "VW15014", 100, 0, 10, "%", new ShortTagValue(), true) { DecimalPoint = 1 }); TagManger.AddTag(new Tag("HV[V]", "HV[V]", "HV", "程序", "VW15016", 100, 0, 10, "V", new ShortTagValue(), true) { DecimalPoint = 1 }); - TagManger.AddTag(new Tag("HV[A]", "HV[A]", "HVCur", "程序", "VW15018", 100, 0, 1, "A", new ShortTagValue(), false) { DecimalPoint = 1 }); + TagManger.AddTag(new Tag("HV[A]", "HV[A]", "HVCur", "程序", "VW15018", 100, 0, 100, "A", new ShortTagValue(), false) { DecimalPoint = 2 }); TagManger.AddTag(new Tag("HV[W]", "HV[W]", "HVPw", "程序", "VW15020", 100, 0, 1, "W", new ShortTagValue(), false) { DecimalPoint = 1 }); TagManger.AddTag(new Tag("LV[V]", "LV[V]", "LV", "程序", "VW15022", 100, 0, 10, "V", new ShortTagValue(), true) { DecimalPoint = 1 }); //TagManger.AddTag(new Tag("LV[A]", "LV[A]", "LVCur", "程序", "VW15024", 100, 0, 1, "A", new ShortTagValue(), false) { DecimalPoint = 1 }); @@ -163,7 +171,7 @@ namespace CapMachine.Wpf.Services TagManger.AddTag(new Tag("EVAP出口温度", "EVAP出口温度[℃]", "EVAPExpTemp", "程序", "VW15036", 100, 0, 10, "℃", new ShortTagValue(), false) { DecimalPoint = 1 }); //TagManger.AddTag(new Tag("冷媒流量", "冷媒流量[L/min]", "VRV", "程序", "VW15038", 100, 0, 1, "L/min", new ShortTagValue(), false) { DecimalPoint = 1 }); TagManger.AddTag(new Tag("冷媒流量", "冷媒流量[L/min]", "VRV", "程序", "VW15038", 100, 0, 10, "L/min", new ShortTagValue(), false) { DecimalPoint = 1 }); - TagManger.AddTag(new Tag("润滑油流量", "润滑油流量[L/min]", "LubeFlow", "程序", "VW15040", 100, 0, 1, "L/min", new ShortTagValue(), false) { DecimalPoint = 1 }); + TagManger.AddTag(new Tag("润滑油流量", "润滑油流量[L/min]", "LubeFlow", "程序", "VW15040", 100, 0, 10, "L/min", new ShortTagValue(), false) { DecimalPoint = 1 }); TagManger.AddTag(new Tag("排气温度", "排气温度[℃]", "ExTemp", "程序", "VW15042", 100, 0, 10, "℃", new ShortTagValue(), true) { DecimalPoint = 1 }); TagManger.AddTag(new Tag("膨胀阀前压力", "膨胀阀前压力[BarA]", "TxvFrPress", "程序", "VW15044", 100, 0, 100, "BarA", new ShortTagValue(), false) { DecimalPoint = 2 }); TagManger.AddTag(new Tag("膨胀阀前温度", "膨胀阀前温度[℃]", "TxvFrTemp", "程序", "VW15046", 100, 0, 10, "℃", new ShortTagValue(), false) { DecimalPoint = 1 }); @@ -173,18 +181,18 @@ namespace CapMachine.Wpf.Services TagManger.AddTag(new Tag("PTC流量", "PTC流量[L/min]", "PTCFlow", "程序", "VW15054", 100, 0, 1, "L/min", new ShortTagValue(), false) { DecimalPoint = 1 }); TagManger.AddTag(new Tag("PTC入水温度", "PTC入水温度[℃]", "PTCEntTemp", "程序", "VW15056", 100, 0, 10, "℃", new ShortTagValue(), false) { DecimalPoint = 1 }); TagManger.AddTag(new Tag("PTC出水温度", "PTC出水温度[℃]", "PTCExpTemp", "程序", "VW15058", 100, 0, 10, "℃", new ShortTagValue(), false) { DecimalPoint = 1 }); - TagManger.AddTag(new Tag("通讯Cmp母线电流", "通讯Cmp母线电流[A]", "ComCapBusCur", "程序", "VW15060", 100, 0, 1, "A", new ShortTagValue(), false) { DecimalPoint = 1 }); + TagManger.AddTag(new Tag("通讯Cmp母线电流", "通讯Cmp母线电流[A]", "ComCapBusCur", "程序", "VW15060", 100, 0, 100, "A", new ShortTagValue(), false) { DecimalPoint = 2 }); TagManger.AddTag(new Tag("通讯Cmp母线电压", "通讯Cmp母线电压[V]", "ComCapBusVol", "程序", "VW15062", 100, 0, 10, "V", new ShortTagValue(), false) { DecimalPoint = 1 }); - TagManger.AddTag(new Tag("通讯Cmp逆变器温度", "通讯Cmp逆变器温度[℃]", "ComCapInvTemp", "程序", "VW15064", 100, 0, 10, "℃", new ShortTagValue(), false) { DecimalPoint = 1 }); - TagManger.AddTag(new Tag("通讯Cmp相电流", "通讯Cmp相电流[A]", "ComCapPhCur", "程序", "VW15066", 100, 0, 1, "A", new ShortTagValue(), false) { DecimalPoint = 1 }); + TagManger.AddTag(new Tag("通讯Cmp逆变器温度", "通讯Cmp逆变器温度[℃]", "ComCapInvTemp", "程序", "VW15064", 100, 0, 1, "℃", new ShortTagValue(), false) { DecimalPoint = 0 }); + TagManger.AddTag(new Tag("通讯Cmp相电流", "通讯Cmp相电流[A]", "ComCapPhCur", "程序", "VW15066", 100, 0, 100, "A", new ShortTagValue(), false) { DecimalPoint = 1 }); TagManger.AddTag(new Tag("通讯Cmp功率", "通讯Cmp功率[W]", "ComCapPw", "程序", "VW15068", 100, 0, 1, "W", new ShortTagValue(), false) { DecimalPoint = 1 }); - TagManger.AddTag(new Tag("通讯Cmp芯片温度", "通讯Cmp芯片温度[℃]", "ComCapChipTemp", "程序", "VW15070", 100, 0, 10, "℃", new ShortTagValue(), false) { DecimalPoint = 1 }); + TagManger.AddTag(new Tag("通讯Cmp芯片温度", "通讯Cmp芯片温度[℃]", "ComCapChipTemp", "程序", "VW15070", 100, 0, 1, "℃", new ShortTagValue(), false) { DecimalPoint = 0 }); TagManger.AddTag(new Tag("通讯PTC入水温度", "通讯PTC入水温度[℃]", "ComPTCEntTemp", "程序", "VW15072", 100, 0, 10, "℃", new ShortTagValue(), false) { DecimalPoint = 1 }); TagManger.AddTag(new Tag("通讯PTC出水温度", "通讯PTC出水温度[℃]", "ComPTCExpTemp", "程序", "VW15074", 100, 0, 10, "℃", new ShortTagValue(), false) { DecimalPoint = 1 }); TagManger.AddTag(new Tag("通讯PTC峰值电流", "通讯PTC峰值电流[A]", "ComPTCPeakCur", "程序", "VW15076", 100, 0, 1, "A", new ShortTagValue(), false) { DecimalPoint = 1 }); TagManger.AddTag(new Tag("通讯PTC母线电流", "通讯PTC母线电流[A]", "ComPTCBusCur", "程序", "VW15078", 100, 0, 1, "A", new ShortTagValue(), false) { DecimalPoint = 1 }); - TagManger.AddTag(new Tag("通讯PTC膜温", "通讯PTC膜温[℃]", "ComPTCFlmTemp", "程序", "VW15080", 100, 0, 10, "℃", new ShortTagValue(), false) { DecimalPoint = 1 }); - TagManger.AddTag(new Tag("通讯PTC模块温度", "通讯PTC模块温度[℃]", "ComPTCMdTemp", "程序", "VW15082", 100, 0, 10, "℃", new ShortTagValue(), false) { DecimalPoint = 1 }); + TagManger.AddTag(new Tag("通讯PTC膜温", "通讯PTC膜温[℃]", "ComPTCFlmTemp", "程序", "VW15080", 100, 0, 1, "℃", new ShortTagValue(), false) { DecimalPoint = 0 }); + TagManger.AddTag(new Tag("通讯PTC模块温度", "通讯PTC模块温度[℃]", "ComPTCMdTemp", "程序", "VW15082", 100, 0, 1, "℃", new ShortTagValue(), false) { DecimalPoint = 0 }); #endregion @@ -1042,6 +1050,7 @@ namespace CapMachine.Wpf.Services private void InitialPLCCom() { var IPInfo = ConfigHelper.GetValue("PLCIP"); + SiemensDrive = new SiemensS7Net(SiemensPLCS.S200Smart, IPInfo); // 连接对象 diff --git a/CapMachine.Wpf/Services/ProRuntimeService.cs b/CapMachine.Wpf/Services/ProRuntimeService.cs index b33e719..68da2de 100644 --- a/CapMachine.Wpf/Services/ProRuntimeService.cs +++ b/CapMachine.Wpf/Services/ProRuntimeService.cs @@ -1,8 +1,27 @@ -using System; +using AutoMapper; +using CapMachine.Model; +using CapMachine.Shared.Controls; +using CapMachine.Wpf.ChannelModel; +using CapMachine.Wpf.Dtos; +using CapMachine.Wpf.Models; +using CapMachine.Wpf.Models.ProModelPars; +using CapMachine.Wpf.Models.Tag; +using CapMachine.Wpf.PrismEvent; +using CapMachine.Wpf.ProPars; +using CapMachine.Wpf.Tool; +using ImTools; +using System; using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Diagnostics; using System.Linq; using System.Text; +using System.Threading.Channels; using System.Threading.Tasks; +using static CapMachine.Wpf.Models.ComEnum; +using System.Windows.Forms; +using HslCommunication.Profinet.Siemens; +using Masuit.Tools.Hardware; namespace CapMachine.Wpf.Services { @@ -15,11 +34,665 @@ namespace CapMachine.Wpf.Services /// /// 实例化函数 /// - public ProRuntimeService() + public ProRuntimeService(IFreeSql freeSql, IMapper mapper, MachineRtDataService machineRtDataService, ILogService logService) { - + FreeSql = freeSql; + Mapper = mapper; + MachineRtDataService = machineRtDataService; + LogService = logService; + + //实例化函数 + ListProExModel = new List() + { + new ProExModel(ProRunChannel){ + MeterName="速度", + ListProStepExe=new List(), + + }, + new ProExModel(ProRunChannel){ + MeterName="COND1温度", + ListProStepExe=new List(), + + }, + new ProExModel(ProRunChannel){ + MeterName="COND2温度", + ListProStepExe=new List(), + + }, + new ProExModel(ProRunChannel){ + MeterName="COND2压力", + ListProStepExe=new List(), + + }, + new ProExModel(ProRunChannel){ + MeterName="EVAP出口温度", + ListProStepExe=new List(), + + }, + new ProExModel(ProRunChannel){ + MeterName="排气压力", + ListProStepExe=new List(), + + }, + new ProExModel(ProRunChannel){ + MeterName="HV电压", + ListProStepExe=new List(), + + }, + new ProExModel(ProRunChannel){ + MeterName="吸气压力", + ListProStepExe=new List(), + + }, + new ProExModel(ProRunChannel){ + MeterName="吸气温度", + ListProStepExe=new List(), + + }, + new ProExModel(ProRunChannel){ + MeterName="润滑油压力", + ListProStepExe=new List(), + + }, + new ProExModel(ProRunChannel){ + MeterName="LV电压", + ListProStepExe=new List(), + + }, + new ProExModel(ProRunChannel){ + MeterName="OCR", + ListProStepExe=new List(), + + }, + new ProExModel(ProRunChannel){ + MeterName="OS1温度", + ListProStepExe=new List(), + + }, + new ProExModel(ProRunChannel){ + MeterName="OS2温度", + ListProStepExe=new List(), + + }, + new ProExModel(ProRunChannel){ + MeterName="PTC入口温度", + ListProStepExe=new List(), + + }, + new ProExModel(ProRunChannel){ + MeterName="PTC流量", + ListProStepExe=new List(), + + }, + new ProExModel(ProRunChannel){ + MeterName="PTC功率", + ListProStepExe=new List(), + + }, + new ProExModel(ProRunChannel){ + MeterName="压缩机环境湿度", + ListProStepExe=new List(), + + }, + new ProExModel(ProRunChannel){ + MeterName="压缩机环境温度", + ListProStepExe=new List(), + + } + }; + + //驱动实例 + SiemensDrive = MachineRtDataService.SiemensDrive; + + //程序运行实时管道数据监听 + Task.Run(() => ListenProRunChannelAction()); + } + + /// + /// 选中的程序运行集合 + /// + public List SelectedListProSegRun { get; set; } + public IFreeSql FreeSql { get; } + public IMapper Mapper { get; } + public MachineRtDataService MachineRtDataService { get; } + public ILogService LogService { get; } + + /// + /// 西门子连接驱动程序 + /// + public SiemensS7Net SiemensDrive { get; set; } + + /// + /// Task扫描 程序运行时间扫描任务 + /// + private static Task ProRunTimeScanTask { get; set; } + + /// + /// 程序运行集合 + /// + public List ListProExModel { get; set; } + + /// + /// PLC加载配置数据集合 + /// + public List ListPlcLoadConfigCell { get; set; } + + /// + /// 加载选中的程序运行集合 + /// + public void LoadProSegRun(List SelectedListProSegRun) + { + if (SelectedListProSegRun == null || SelectedListProSegRun.Count() == 0) + { + return; + } + + //先清空之前的步骤数据 + foreach (var itemProExModel in ListProExModel) + { + itemProExModel.ListProStepExe.Clear(); + } + + //多个选中的程序块循环 + foreach (var itemProSegRun in SelectedListProSegRun) + { + //获取当前程序块 + //逐个对应的程序 + var CurProgramSeg = FreeSql.Select(itemProSegRun.ProgramSegId) + .IncludeMany(a => a.ProSteps, + then => then.IncludeMany(b => b.MeterSpeeds) + .IncludeMany(b => b.MeterCond1Temps) + .IncludeMany(b => b.MeterCond2Temps) + .IncludeMany(b => b.MeterCond2Presss) + .IncludeMany(b => b.MeterEVAPExpTemps) + .IncludeMany(b => b.MeterExPresss) + .IncludeMany(b => b.MeterHVVols) + .IncludeMany(b => b.MeterInhPresss) + .IncludeMany(b => b.MeterInhTemps) + .IncludeMany(b => b.MeterLubePresss) + .IncludeMany(b => b.MeterLVVols) + .IncludeMany(b => b.MeterOCRs) + .IncludeMany(b => b.MeterOS1Temps) + .IncludeMany(b => b.MeterOS2Temps) + .IncludeMany(b => b.MeterPTCEntTemps) + .IncludeMany(b => b.MeterPTCFlows) + .IncludeMany(b => b.MeterPTCPws) + .IncludeMany(b => b.MeterEnvRHs) + .IncludeMany(b => b.MeterEnvTemps) + ).ToList().FirstOrDefault(); + + //获取当前的程序 + if (CurProgramSeg != null && CurProgramSeg.ProSteps != null && CurProgramSeg.ProSteps.Any()) + { + //CurProgramSeg有重复运行的次数 + for (int SegIndex = 0; SegIndex < CurProgramSeg.ProRepeat; SegIndex++) + { + //解析程序的多行步骤,表格中的行步骤数据,牟定速度 + foreach (var itemStep in CurProgramSeg.ProSteps.OrderBy(a => a.StepNo)) + { + //单行步骤中包含多个仪表参数的配置,需要逐个仪表参数手动操作解析 + + //********* 单个速度步骤信息的解析 ********* + var CurMeterName = "速度"; + if (itemStep.MeterSpeeds != null && itemStep.MeterSpeeds.Any()) + { + switch (itemStep.MeterSpeeds.FirstOrDefault()!.ValueType) + { + case ConfigValueType.Constant: //常值 + //常值的话就一个数据,循环执行一次 + foreach (var itemMeterValueCell in itemStep.MeterSpeeds) + { + var Pid = new ConfigPID(); + if (FreeSql.Select().Where(a => a.MeterName == CurMeterName && a.IndexNo == itemMeterValueCell.ParNo).Any()) + { + Pid = FreeSql.Select().Where(a => a.MeterName == CurMeterName && a.IndexNo == itemMeterValueCell.ParNo).First(); + } + var Limit = new ConfigLimit(); + if (FreeSql.Select().Where(a => a.MeterName == CurMeterName && a.IndexNo == itemMeterValueCell.Ev).Any()) + { + Limit = FreeSql.Select().Where(a => a.MeterName == CurMeterName && a.IndexNo == itemMeterValueCell.Ev).First(); + } + var Alarm = new ConfigAlarm(); + if (FreeSql.Select().Where(a => a.MeterName == CurMeterName && a.IndexNo == itemMeterValueCell.Ev).Any()) + { + Alarm = FreeSql.Select().Where(a => a.MeterName == CurMeterName && a.IndexNo == itemMeterValueCell.Ev).First(); + } + + ListProExModel.FindFirst(a => a.MeterName == CurMeterName).ListProStepExe.Add(new ProStepExe() + { + //程序块 + ProSegName = CurProgramSeg.Name, + ProSegStep = SegIndex, + ProSegRepeat = CurProgramSeg.ProRepeat, + ProSegIsExeing = false,//配置阶段默认不执行 false + + //程序步骤数据 + StartSV = GetSVByProcess(itemMeterValueCell.Constant, CurMeterName), + EndSV = GetSVByProcess(itemMeterValueCell.Constant, CurMeterName), + KeepTime = itemMeterValueCell.KeepTime, + MeterStepIsExeing = false,//配置阶段默认不执行 false + MeterStepIsOK = false,//配置阶段默认不完成 false + ExistSlop = false,//常值没有斜率 //开始和结束不一样则存在斜率 + + MeterStep = ListProExModel.FindFirst(a => a.MeterName == CurMeterName).ListProStepExe.Count + 1, + MeterName = CurMeterName, + + LimitNo = itemMeterValueCell.ParNo, + AlarmNo = itemMeterValueCell.Ev, + PIDNo = itemMeterValueCell.Ev, + + CurConfigPIDDto = Mapper.Map(Pid), + CurConfigLimitDto = Mapper.Map(Limit), + + ProStepInfo = $"{itemStep.StepNo}-{itemMeterValueCell.StepNo}", + }); + } + break; + case ConfigValueType.Slope: //斜率 + //根据循环次数确定 + for (int StepIndex = 0; StepIndex < itemStep.SpeedCycle; StepIndex++) + { + //根据循环次数执行 + foreach (var itemMeterValueCell in itemStep.MeterSpeeds) + { + var Pid = new ConfigPID(); + if (FreeSql.Select().Where(a => a.MeterName == CurMeterName && a.IndexNo == itemMeterValueCell.ParNo).Any()) + { + Pid = FreeSql.Select().Where(a => a.MeterName == CurMeterName && a.IndexNo == itemMeterValueCell.ParNo).First(); + } + var Limit = new ConfigLimit(); + if (FreeSql.Select().Where(a => a.MeterName == CurMeterName && a.IndexNo == itemMeterValueCell.Ev).Any()) + { + Limit = FreeSql.Select().Where(a => a.MeterName == CurMeterName && a.IndexNo == itemMeterValueCell.Ev).First(); + } + var Alarm = new ConfigAlarm(); + if (FreeSql.Select().Where(a => a.MeterName == CurMeterName && a.IndexNo == itemMeterValueCell.Ev).Any()) + { + Alarm = FreeSql.Select().Where(a => a.MeterName == CurMeterName && a.IndexNo == itemMeterValueCell.Ev).First(); + } + + ListProExModel.FindFirst(a => a.MeterName == CurMeterName).ListProStepExe.Add(new ProStepExe() + { + //程序块 + ProSegName = CurProgramSeg.Name, + ProSegStep = SegIndex, + ProSegRepeat = CurProgramSeg.ProRepeat, + ProSegIsExeing = false,//配置阶段默认不执行 false + + //程序步骤数据 + //SV = CALCHelper.GetQuickSV(itemMeterValueCell.Constant, 1), + StartSV = GetSVByProcess(itemMeterValueCell.StartValue, CurMeterName), + EndSV = GetSVByProcess(itemMeterValueCell.EndValue, CurMeterName), + KeepTime = itemMeterValueCell.KeepTime, + MeterStepIsExeing = false,//配置阶段默认不执行 false + MeterStepIsOK = false,//配置阶段默认不完成 false + ExistSlop = itemMeterValueCell.StartValue == itemMeterValueCell.EndValue ? false : true,//开始和结束不一样则存在斜率 + + MeterStep = ListProExModel.FindFirst(a => a.MeterName == CurMeterName).ListProStepExe.Count + 1, + + LimitNo = itemMeterValueCell.ParNo, + AlarmNo = itemMeterValueCell.ParNo, + PIDNo = itemMeterValueCell.Ev, + + CurConfigPIDDto = Mapper.Map(Pid), + CurConfigLimitDto = Mapper.Map(Limit), + + ProStepInfo = $"{itemStep.StepNo}-{itemMeterValueCell.StepNo}", + MeterName = CurMeterName, + }); + } + } + break; + default: + break; + } + } + } + } + + } + } + + StartProRun(); + } + /// + /// 处理后获取SV的数据 + /// + /// + private int GetSVByProcess(double SV, string Name) + { + var Data = ListPlcLoadConfigCell.Where(a => a.Name == Name); + if (Data.Any()) + { + return (int)(SV / (Data.FirstOrDefault()!.Precision)); + } + else + { + LogService.Warn($"【名称】: {Name} - 未找到对应的参数配置,数据转换格式失败"); + //未找到的话,则直接返回 + return (int)SV; + } + } + + #region 程序调度执行 + + /// + /// 开始程序调度运行 + /// + public void StartProRun() + { + //开始运行前的需要进行一些设置和数据初始化 + foreach (var itemProExModel in ListProExModel) + { + //被启用和有步骤时才进行运行设置 + if (itemProExModel == null && itemProExModel.Enable && itemProExModel!.ListProStepExe.Count() > 0) continue; + itemProExModel.RunEnable = true; + + //设置下一步数据是第一步数据,然后设置时间 + itemProExModel.NextProStepExe = itemProExModel!.ListProStepExe.OrderBy(a => a.MeterStep).FirstOrDefault()!; + itemProExModel.CurProStepExe = new ProStepExe(); + itemProExModel.StepEndDt = DateTime.Now; + } + + //运行扫描任务 + ProRunTimeScan(); + } + + private bool ProRunTaskEnable = true; + + /// + /// 运行时间扫描 + /// + private void ProRunTimeScan() + { + ProRunTimeScanTask = Task.Run(async () => + { + while (ProRunTaskEnable) + { + try + { + //循环给模型的当前时间赋值,驱动步骤执行 + foreach (var itemProExModel in ListProExModel) + { + if (itemProExModel.RunEnable) + { + itemProExModel.CurrentDateTime = DateTime.Now; + } + } + + await Task.CompletedTask; + } + catch (Exception ex) + { + //LogService.Info($"时间:{DateTime.Now.ToString()}-【Meter】-{ex.Message}"); + } + //Console.WriteLine($"扫描时间:{DiagnosticsTime.Elapsed.TotalMilliseconds.ToString()}"); + } + }); + } + + + /// + /// 队列通道 + /// 当前队列消费触发的数据记录 + /// + public Channel ProRunChannel = Channel.CreateUnbounded(new UnboundedChannelOptions() + { + SingleWriter = false,//允许一次写入多条数据 + SingleReader = true //一次只能读取一条消息 + }); + + /// + /// 程序执行管道监听方法 + /// + /// + private async void ListenProRunChannelAction() + { + while (await ProRunChannel.Reader.WaitToReadAsync()) + { + if (ProRunChannel.Reader.TryRead(out var ProRunChannelData)) + { + ////第一次计时 + //stopwatch.Start(); //启动Stopwatch + if (ProRunChannelData.RunStepType == RunStepType.SlopCell) + { + Console.WriteLine($"【时间】{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff")} " + + $"【参数名称】:{ProRunChannelData.MeterName} " + + $"【程序Seg】{ProRunChannelData.ProSegName} " + + $"【程序步骤】{ProRunChannelData.MeterStep} " + + $"【斜坡打点步骤】{ProRunChannelData.SlopStepNo} " + + $"【斜坡打点值SV】{ProRunChannelData.SV} " + + $"【Msg】:接受到仿真写入PLC OK "); + } + else + { + Console.WriteLine($"【时间】{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff")} " + + $"【参数名称】:{ProRunChannelData.MeterName} " + + $"【程序Seg】{ProRunChannelData.ProSegName} " + + $"【程序步骤】{ProRunChannelData.MeterStep} " + + $"【步骤SV】{ProRunChannelData.SV} " + + $"【Msg】:接受到步骤仿真写入PLC OK "); + } + + + Thread.Sleep(50); + //DownLoadPID(); + //stopwatch.Stop(); //停止Stopwatch + //Console.WriteLine("保存数据耗时::{0}", stopwatch.Elapsed.TotalSeconds.ToString()); + //stopwatch.Reset(); + } + } + } + + ///// + ///// 下载PID 信息 + ///// + //private void DownLoadPID(ProExModel ProExecuteModel) + //{ + // //上一次PID信息不为空的话则进行比较后再下载 + // if (ProExecuteModel != null && ProExecuteModel.CurProStepExe != null && ProExecuteModel.LastProStepExe != null) + // { + // //判断是否比较PID信息 + // if (ProExecuteModel.CurProStepExe.PIDNo != ProExecuteModel.LastProStepExe.PIDNo) + // { + // //进行比较跟上一个是否相同 + // if (ProExecuteModel.CurProStepExe != ProExecuteModel.LastProStepExe) + // { + // var PlcLoadConfigCell_P = ProExecuteModel.ListPlcLoadConfigCell.First(a => a.Name == "P")!; + // var PlcLoadConfigCell_I = ProExecuteModel.ListPlcLoadConfigCell.First(a => a.Name == "I")!; + // var PlcLoadConfigCell_D = ProExecuteModel.ListPlcLoadConfigCell.First(a => a.Name == "D")!; + // //下载PID信息的P + // var ResultP = SiemensDrive.Write(PlcLoadConfigCell_P!.Address, (double)ProExecuteModel.CurProStepExe.CurConfigPIDDto!.P * 1.0 / PlcLoadConfigCell_P.Precision); + // Console.WriteLine($"【时间】{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff")} 【参数名称】:{ProExecuteModel.MeterName} " + + // $"【程序Seg】{ProExecuteModel.CurProStepExe.ProSegName} " + + // $"【程序步骤】{ProExecuteModel.CurProStepExe.MeterStep} " + + // $"【类型】:{ProExecuteModel.CurProStepExe.ExistSlop.ToString()} " + + // $"【参数】:PID-P " + + // $"【值】:{ProExecuteModel.CurProStepExe.CurConfigPIDDto!.P}" + + // $"【Msg】:{ResultP.Message} "); + + // //下载PID信息的I + // var ResultI = SiemensDrive.Write(PlcLoadConfigCell_I!.Address, (double)ProExecuteModel.CurProStepExe.CurConfigPIDDto!.I * 1.0 / PlcLoadConfigCell_I.Precision); + // Console.WriteLine($"【时间】{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff")} 【参数名称】:{ProExecuteModel.MeterName} " + + // $"【程序Seg】{ProExecuteModel.CurProStepExe.ProSegName} " + + // $"【程序步骤】{ProExecuteModel.CurProStepExe.MeterStep} " + + // $"【类型】:{ProExecuteModel.CurProStepExe.ExistSlop.ToString()} " + + // $"【参数】:PID-I " + + // $"【值】:{ProExecuteModel.CurProStepExe.CurConfigPIDDto!.I}" + + // $"【Msg】:{ResultI.Message} "); + + // //下载PID信息的D + // var ResultD = SiemensDrive.Write(PlcLoadConfigCell_D!.Address, (double)ProExecuteModel.CurProStepExe.CurConfigPIDDto!.D * 1.0 / PlcLoadConfigCell_D.Precision); + // Console.WriteLine($"【时间】{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff")} 【参数名称】:{ProExecuteModel.MeterName} " + + // $"【程序Seg】{ProExecuteModel.CurProStepExe.ProSegName} " + + // $"【程序步骤】{ProExecuteModel.CurProStepExe.MeterStep} " + + // $"【类型】:{ProExecuteModel.CurProStepExe.ExistSlop.ToString()} " + + // $"【参数】:PID-D " + + // $"【值】:{ProExecuteModel.CurProStepExe.CurConfigPIDDto!.D}" + + // $"【Msg】:{ResultD.Message} "); + // return; + // } + // //相同的则不需要下载,直接使用上一个的配置 + // return; + // } + // } + // else//Pid为空的话直接下载,可能是第一个步骤 + // { + // var PlcLoadConfigCell_P = ProExecuteModel!.ListPlcLoadConfigCell.First(a => a.Name == "P")!; + // var PlcLoadConfigCell_I = ProExecuteModel.ListPlcLoadConfigCell.First(a => a.Name == "I")!; + // var PlcLoadConfigCell_D = ProExecuteModel.ListPlcLoadConfigCell.First(a => a.Name == "D")!; + // //下载PID信息的P + // var ResultP = SiemensDrive.Write(PlcLoadConfigCell_P!.Address, (double)ProExecuteModel.CurProStepExe.CurConfigPIDDto!.P * 1.0 / PlcLoadConfigCell_P.Precision); + // Console.WriteLine($"【时间】{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff")} 【参数名称】:{ProExecuteModel.MeterName} " + + // $"【程序Seg】{ProExecuteModel.CurProStepExe.ProSegName} " + + // $"【程序步骤】{ProExecuteModel.CurProStepExe.MeterStep} " + + // $"【类型】:{ProExecuteModel.CurProStepExe.ExistSlop.ToString()} " + + // $"【参数】:PID-P " + + // $"【值】:{ProExecuteModel.CurProStepExe.CurConfigPIDDto!.P}" + + // $"【Msg】:{ResultP.Message} "); + + // //下载PID信息的I + // var ResultI = SiemensDrive.Write(PlcLoadConfigCell_I!.Address, (double)ProExecuteModel.CurProStepExe.CurConfigPIDDto!.I * 1.0 / PlcLoadConfigCell_I.Precision); + // Console.WriteLine($"【时间】{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff")} 【参数名称】:{ProExecuteModel.MeterName} " + + // $"【程序Seg】{ProExecuteModel.CurProStepExe.ProSegName} " + + // $"【程序步骤】{ProExecuteModel.CurProStepExe.MeterStep} " + + // $"【类型】:{ProExecuteModel.CurProStepExe.ExistSlop.ToString()} " + + // $"【参数】:PID-I " + + // $"【值】:{ProExecuteModel.CurProStepExe.CurConfigPIDDto!.I}" + + // $"【Msg】:{ResultI.Message} "); + + // //下载PID信息的D + // var ResultD = SiemensDrive.Write(PlcLoadConfigCell_D!.Address, (double)ProExecuteModel.CurProStepExe.CurConfigPIDDto!.D * 1.0 / PlcLoadConfigCell_D.Precision); + // Console.WriteLine($"【时间】{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff")} 【参数名称】:{ProExecuteModel.MeterName} " + + // $"【程序Seg】{ProExecuteModel.CurProStepExe.ProSegName} " + + // $"【程序步骤】{ProExecuteModel.CurProStepExe.MeterStep} " + + // $"【类型】:{ProExecuteModel.CurProStepExe.ExistSlop.ToString()} " + + // $"【参数】:PID-D " + + // $"【值】:{ProExecuteModel.CurProStepExe.CurConfigPIDDto!.D}" + + // $"【Msg】:{ResultD.Message} "); + // return; + // } + //} + + + ///// + ///// 下载Limit 信息 + ///// + //private void DownLoadLimit(ProExModel ProExecuteModel) + //{ + // //上一次Limit信息不为空的话则进行比较后再下载 + // if (ProExecuteModel != null && ProExecuteModel.CurProStepExe != null && ProExecuteModel.LastProStepExe != null) + // { + // //判断是否比较Limit信息 + // if (ProExecuteModel.CurProStepExe.LimitNo != ProExecuteModel.LastProStepExe.LimitNo) + // { + // //进行比较跟上一个是否相同 + // if (ProExecuteModel.CurProStepExe != ProExecuteModel.LastProStepExe) + // { + // var PlcLoadConfigCell_Up = ProExecuteModel.ListPlcLoadConfigCell.First(a => a.Name == "Up")!; + // var PlcLoadConfigCell_Down = ProExecuteModel.ListPlcLoadConfigCell.First(a => a.Name == "Down")!; + // //下载Limit信息的Up + // var ResultUp = SiemensDrive.Write(PlcLoadConfigCell_Up!.Address, (double)ProExecuteModel.CurProStepExe.CurConfigLimitDto!.Up * 1.0 / PlcLoadConfigCell_Up.Precision); + // Console.WriteLine($"【时间】{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff")} 【参数名称】:{ProExecuteModel.MeterName} " + + // $"【程序Seg】{ProExecuteModel.CurProStepExe.ProSegName} " + + // $"【程序步骤】{ProExecuteModel.CurProStepExe.MeterStep} " + + // $"【类型】:{ProExecuteModel.CurProStepExe.ExistSlop.ToString()} " + + // $"【参数】:Limit-Up " + + // $"【值】:{ProExecuteModel.CurProStepExe.CurConfigLimitDto!.Up}" + + // $"【Msg】:{ResultUp.Message} "); + + // //下载Limit信息的Down + // var ResultDown = SiemensDrive.Write(PlcLoadConfigCell_Down!.Address, (double)ProExecuteModel.CurProStepExe.CurConfigLimitDto!.Down * 1.0 / PlcLoadConfigCell_Down.Precision); + // Console.WriteLine($"【时间】{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff")} 【参数名称】:{ProExecuteModel.MeterName} " + + // $"【程序Seg】{ProExecuteModel.CurProStepExe.ProSegName} " + + // $"【程序步骤】{ProExecuteModel.CurProStepExe.MeterStep} " + + // $"【类型】:{ProExecuteModel.CurProStepExe.ExistSlop.ToString()} " + + // $"【参数】:Limit-Down " + + // $"【值】:{ProExecuteModel.CurProStepExe.CurConfigLimitDto!.Down}" + + // $"【Msg】:{ResultUp.Message} "); + // return; + // } + // //相同的则不需要下载,直接使用上一个的配置 + // return; + // } + // } + // else//Pid为空的话直接下载,可能是第一个步骤 + // { + // var PlcLoadConfigCell_Up = ProExecuteModel.ListPlcLoadConfigCell.First(a => a.Name == "Up")!; + // var PlcLoadConfigCell_Down = ProExecuteModel.ListPlcLoadConfigCell.First(a => a.Name == "Down")!; + // //下载Limit信息的Up + // var ResultUp = SiemensDrive.Write(PlcLoadConfigCell_Up!.Address, (double)ProExecuteModel.CurProStepExe.CurConfigLimitDto!.Up * 1.0 / PlcLoadConfigCell_Up.Precision); + // Console.WriteLine($"【时间】{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff")} 【参数名称】:{ProExecuteModel.MeterName} " + + // $"【程序Seg】{ProExecuteModel.CurProStepExe.ProSegName} " + + // $"【程序步骤】{ProExecuteModel.CurProStepExe.MeterStep} " + + // $"【类型】:{ProExecuteModel.CurProStepExe.ExistSlop.ToString()} " + + // $"【参数】:Limit-Up " + + // $"【值】:{ProExecuteModel.CurProStepExe.CurConfigLimitDto!.Up}" + + // $"【Msg】:{ResultUp.Message} "); + + // //下载Limit信息的Down + // var ResultDown = SiemensDrive.Write(PlcLoadConfigCell_Down!.Address, (double)ProExecuteModel.CurProStepExe.CurConfigLimitDto!.Down * 1.0 / PlcLoadConfigCell_Down.Precision); + // Console.WriteLine($"【时间】{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff")} 【参数名称】:{ProExecuteModel.MeterName} " + + // $"【程序Seg】{ProExecuteModel.CurProStepExe.ProSegName} " + + // $"【程序步骤】{ProExecuteModel.CurProStepExe.MeterStep} " + + // $"【类型】:{ProExecuteModel.CurProStepExe.ExistSlop.ToString()} " + + // $"【参数】:Limit-Down " + + // $"【值】:{ProExecuteModel.CurProStepExe.CurConfigLimitDto!.Down}" + + // $"【Msg】:{ResultUp.Message} "); + // return; + // } + //} + + ///// + ///// 下载SV 信息 + ///// + ///// + //private void DownLoadSV(ProExModel ProExecuteModel) + //{ + // //上一次SV信息不为空的话则进行比较后再下载 + // if (ProExecuteModel != null && ProExecuteModel.CurProStepExe != null && ProExecuteModel.LastProStepExe != null) + // { + // //判断比较SV信息 + // if (ProExecuteModel.CurProStepExe.EndSV != ProExecuteModel.LastProStepExe.EndSV) + // { + // //SV配置 + // var PlcLoadConfigCell_SV = ProExecuteModel.ListPlcLoadConfigCell.First(a => a.Name == "SV")!; + // //下载SV信息的 + // var ResultSV = SiemensDrive.Write(PlcLoadConfigCell_SV!.Address, (double)ProExecuteModel.CurProStepExe.EndSV * 1.0 / PlcLoadConfigCell_SV.Precision); + // Console.WriteLine($"【时间】{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff")} 【参数名称】:{ProExecuteModel.MeterName} " + + // $"【程序Seg】{ProExecuteModel.CurProStepExe.ProSegName} " + + // $"【程序步骤】{ProExecuteModel.CurProStepExe.MeterStep} " + + // $"【类型】:{ProExecuteModel.CurProStepExe.ExistSlop.ToString()} " + + // $"【参数】:SV " + + // $"【值】:{ProExecuteModel.CurProStepExe.CurConfigLimitDto!.Up}" + + // $"【Msg】:{ResultSV.Message} "); + // return; + // } + // else + // { + // //跟上一次的一样,不需要下载了 + // } + // } + // else//Pid为空的话直接下载,可能是第一个步骤 + // { + // //SV配置 + // var PlcLoadConfigCell_SV = ProExecuteModel.ListPlcLoadConfigCell.First(a => a.Name == "SV")!; + // //下载SV信息的 + // var ResultSV = SiemensDrive.Write(PlcLoadConfigCell_SV!.Address, (double)ProExecuteModel.CurProStepExe.EndSV * 1.0 / PlcLoadConfigCell_SV.Precision); + // Console.WriteLine($"【时间】{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff")} 【参数名称】:{ProExecuteModel.MeterName} " + + // $"【程序Seg】{ProExecuteModel.CurProStepExe.ProSegName} " + + // $"【程序步骤】{ProExecuteModel.CurProStepExe.MeterStep} " + + // $"【类型】:{ProExecuteModel.CurProStepExe.ExistSlop.ToString()} " + + // $"【参数】:SV " + + // $"【值】:{ProExecuteModel.CurProStepExe.CurConfigLimitDto!.Up}" + + // $"【Msg】:{ResultSV.Message} "); + // return; + // } + //} + + #endregion } } diff --git a/CapMachine.Wpf/Tool/CALCHelper.cs b/CapMachine.Wpf/Tool/CALCHelper.cs new file mode 100644 index 0000000..73e41de --- /dev/null +++ b/CapMachine.Wpf/Tool/CALCHelper.cs @@ -0,0 +1,287 @@ +using CapMachine.Model; +using CapMachine.Wpf.Models.ProModelPars; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CapMachine.Wpf.Tool +{ + public class CALCHelper + { + /// + /// 计算斜率-分 + /// + public static int GetSlop(double Value1, double Value2, int TimeSed) + { + var diff = Value2 - Value1; + var TimeMin = TimeSed * 1.0 / 60; + if (TimeSed == 0) return 0; + var Result = (int)Math.Ceiling(diff / TimeMin); + if (Result > 9999) + { + return 9999; + } + if (Result < -1999) + { + return -1999; + } + return Result; + } + + /// + /// 计算斜率-秒-DB表 + /// + public static int GetSlopSed(double Value1, double Value2, int TimeSed) + { + var diff = Value2 - Value1; + //var TimeMin = TimeSed * 1.0 / 60; + if (TimeSed == 0) return 0;//0应该是OFF功能 + var Result = diff / TimeSed; + if (Result > 2000) + { + return 2000; + } + if (Result < -1999.9) + { + return -1999; + } + if (Result >= 0) + { + return (int)Math.Ceiling(Result);//乘以10是DB表的通信上的范围数据要求的,实际显示x.x + } + else + { + return (int)Math.Floor(Result);//乘以10是DB表的通信上的范围数据要求的,实际显示x.x + } + + //return (int)Math.Ceiling(Result);//乘以10是DB表的通信上的范围数据要求的,实际显示x.x + } + + /// + /// 计算斜率-分鐘-DB表 + /// + public static int GetSlopMinute(double Value1, double Value2, int TimeSed) + { + var diff = Value2 - Value1; + var TimeMin = TimeSed * 1.0 / 60; + if (TimeSed == 0) return 0;//0应该是OFF功能 + var Result = diff / TimeMin; + if (Result > 2000) + { + return 2000; + } + if (Result < -1999.9) + { + return -1999; + } + if (Result >= 0) + { + return (int)Math.Ceiling(Result * 10);//乘以10是DB表的通信上的范围数据要求的,实际显示x.x + } + else + { + return (int)Math.Floor(Result * 10);//乘以10是DB表的通信上的范围数据要求的,实际显示x.x + } + + } + + /// + /// 计算斜率-小时-DB表 + /// + public static int GetSlopHour(double Value1, double Value2, int TimeSed) + { + var diff = Value2 - Value1; + var TimeHour = TimeSed * 1.0 / 3600; + if (TimeSed == 0) return 0;//0应该是OFF功能 + var Result = diff / TimeHour; + if (Result > 2000) + { + return 2000; + } + if (Result < -1999.9) + { + return -1999; + } + if (Result >= 0) + { + return (int)Math.Ceiling(Result);//乘以10是DB表的通信上的范围数据要求的,实际显示x.x + } + else + { + return (int)Math.Floor(Result);//乘以10是DB表的通信上的范围数据要求的,实际显示x.x + } + + } + + + /// + /// 计算斜率-秒-DB表 CV + /// + public static int GetSlopCVMinute(double Value1, double Value2, int TimeSed) + { + var diff = Value2 - Value1; + //var TimeMin = TimeSed * 1.0 / 60; + if (TimeSed == 0) return 0;//0应该是OFF功能 + var Result = diff / TimeSed; + if (Result > 2000) + { + return 2000; + } + if (Result < -1999.9) + { + return -1999; + } + if (Result >= 0) + { + return (int)Math.Ceiling(Result);//乘以10是DB表的通信上的范围数据要求的,实际显示x.x + } + else + { + return (int)Math.Floor(Result);//乘以10是DB表的通信上的范围数据要求的,实际显示x.x + } + + } + + ///// + ///// 计算斜率-秒-DB表 + ///// + //public static int GetSlopSed(double Value1, double Value2, int TimeSed) + //{ + // var diff = Value2 - Value1; + // //var TimeMin = TimeSed * 1.0 / 60; + // if (TimeSed == 0) return 0;//0应该是OFF功能 + // var Result = diff / TimeSed; + // if (Result > 2000) + // { + // return 2000 * 10; + // } + // if (Result < -1999.9) + // { + // return -1999 * 10; + // } + // return (int)Math.Ceiling(Result * 10);//乘以10是DB表的通信上的范围数据要求的,实际显示x.x + //} + + /// + /// SV值的数据获取 + /// + /// + /// + /// + public static int GetQuickSV(double sourceData, short accuracy) + { + return (int)(sourceData * (int)Math.Pow(10, accuracy)); + } + + /// + /// 比较是否有改变的数据 + /// + /// + /// + /// + /// + public static bool CpStepExecuteCompareInfo(ProStepExe NextData, ProStepExe CurrentData, string Field) + { + switch (Field) + { + case "PID": + if (NextData.PIDNo == CurrentData.PIDNo) return true; + return false; + case "SV": + if (NextData.EndSV == CurrentData.EndSV) return true; + return false; + case "Limit": + if (NextData.LimitNo == CurrentData.LimitNo) return true; + return false; + case "Alarm": + if (NextData.AlarmNo == CurrentData.AlarmNo) return true; + return false; + default: + return false; + } + } + /// + /// 比较是否有改变的数据 + /// + /// + /// + /// + /// + public static bool KpStepExecuteCompareInfo(ProStepExe NextData, ProStepExe CurrentData, string Field) + { + switch (Field) + { + case "PID": + if (NextData.PIDNo == CurrentData.PIDNo) return true; + return false; + case "SV": + if (NextData.EndSV == CurrentData.EndSV) return true; + return false; + case "Limit": + if (NextData.LimitNo == CurrentData.LimitNo) return true; + return false; + case "Alarm": + if (NextData.AlarmNo == CurrentData.AlarmNo) return true; + return false; + default: + return false; + } + } + + + /// + /// 判断Limit下载的次序 + /// + /// + /// + /// + public static int CpStepExecuteLimitCompareInfo(ProStepExe NextData, ProStepExe CurrentData) + { + if (NextData.CurConfigLimitDto.Down >= CurrentData.CurConfigLimitDto.Up) + { + //先下载Up,后下载Down + return 1; + } + if (NextData.CurConfigLimitDto.Up <= CurrentData.CurConfigLimitDto.Down) + { + //先下载Down,后下载Up + return 3; + } + + //正常下载 Down和Up顺序都可以 + return 2; + } + + /// + /// 判断Limit下载的次序 + /// + /// + /// + /// + public static int KpStepExecuteLimitCompareInfo(ProStepExe NextData, ProStepExe CurrentData) + { + if (NextData.CurConfigLimitDto.Down >= CurrentData.CurConfigLimitDto.Up) + { + //先下载Up,后下载Down + return 1; + } + if (NextData.CurConfigLimitDto.Up <= CurrentData.CurConfigLimitDto.Down) + { + //先下载Down,后下载Up + return 3; + } + + //正常下载 Down和Up顺序都可以 + return 2; + } + + + + //private long GetProDur(QuickStep quickStep) + //{ + // return 0; + //} + } +} diff --git a/CapMachine.Wpf/ViewModels/ProConfigViewModel.cs b/CapMachine.Wpf/ViewModels/ProConfigViewModel.cs index 74c32b4..07c63f4 100644 --- a/CapMachine.Wpf/ViewModels/ProConfigViewModel.cs +++ b/CapMachine.Wpf/ViewModels/ProConfigViewModel.cs @@ -23,7 +23,7 @@ namespace CapMachine.Wpf.ViewModels public class ProConfigViewModel : NavigationViewModel { public ProConfigViewModel(IDialogService dialogService, IFreeSql freeSql, - IEventAggregator eventAggregator, IRegionManager regionManager, SysRunService sysRunService, ConfigService configService, + IEventAggregator eventAggregator, IRegionManager regionManager, SysRunService sysRunService, ConfigService configService, ProRuntimeService proRuntimeService, MachineRtDataService machineRtDataService) { //LogService = logService; @@ -32,6 +32,7 @@ namespace CapMachine.Wpf.ViewModels RegionManager = regionManager; SysRunService = sysRunService; ConfigService = configService; + ProRuntimeService = proRuntimeService; this.MachineRtDataService = machineRtDataService; //MachineDataService = machineDataService; @@ -83,6 +84,7 @@ namespace CapMachine.Wpf.ViewModels public IRegionManager RegionManager { get; } public SysRunService SysRunService { get; } public ConfigService ConfigService { get; } + public ProRuntimeService ProRuntimeService { get; } private MachineRtDataService MachineRtDataService { get; } /// @@ -2327,48 +2329,50 @@ namespace CapMachine.Wpf.ViewModels //返回的数据 List ReturnPlcParsData = new List(); - //var Data=FreeSql.Select( - //以每个程序为单元循环执行 - foreach (var item in ProSegRunListViewItems) - { - var FindData = FreeSql.Select(item.ProgramSegId) - .IncludeMany(a => a.ProSteps, - then => then.IncludeMany(b => b.MeterSpeeds) - .IncludeMany(b => b.MeterCond1Temps) - .IncludeMany(b => b.MeterCond2Temps) - .IncludeMany(b => b.MeterCond2Presss) - .IncludeMany(b => b.MeterEVAPExpTemps) - .IncludeMany(b => b.MeterExPresss) - .IncludeMany(b => b.MeterHVVols) - .IncludeMany(b => b.MeterInhPresss) - .IncludeMany(b => b.MeterInhTemps) - .IncludeMany(b => b.MeterLubePresss) - .IncludeMany(b => b.MeterLVVols) - .IncludeMany(b => b.MeterOCRs) - .IncludeMany(b => b.MeterOS1Temps) - .IncludeMany(b => b.MeterOS2Temps) - .IncludeMany(b => b.MeterPTCEntTemps) - .IncludeMany(b => b.MeterPTCFlows) - .IncludeMany(b => b.MeterPTCPws) - .IncludeMany(b => b.MeterEnvRHs) - .IncludeMany(b => b.MeterEnvTemps) - ).ToList().FirstOrDefault(); + ProRuntimeService.LoadProSegRun(ProSegRunListViewItems.ToList()); - if (FindData != null && FindData.ProSteps != null && FindData.ProSteps.Any()) - { - //执行程序的步骤集合数据 - ReturnPlcParsData = ProParsSongZhiHelper.GetPlcParsData(FindData.ProSteps, FindData.ProRepeat); - //把次数给PLC,那么此时应该是最后一个程序给PLC了 - ProParsSongZhiHelper.LoadProCycleToPlc(MachineRtDataService.SiemensDrive, FindData.ProRepeat); - } - } + ////var Data=FreeSql.Select( + ////以每个程序为单元循环执行 + //foreach (var item in ProSegRunListViewItems) + //{ + // var FindData = FreeSql.Select(item.ProgramSegId) + // .IncludeMany(a => a.ProSteps, + // then => then.IncludeMany(b => b.MeterSpeeds) + // .IncludeMany(b => b.MeterCond1Temps) + // .IncludeMany(b => b.MeterCond2Temps) + // .IncludeMany(b => b.MeterCond2Presss) + // .IncludeMany(b => b.MeterEVAPExpTemps) + // .IncludeMany(b => b.MeterExPresss) + // .IncludeMany(b => b.MeterHVVols) + // .IncludeMany(b => b.MeterInhPresss) + // .IncludeMany(b => b.MeterInhTemps) + // .IncludeMany(b => b.MeterLubePresss) + // .IncludeMany(b => b.MeterLVVols) + // .IncludeMany(b => b.MeterOCRs) + // .IncludeMany(b => b.MeterOS1Temps) + // .IncludeMany(b => b.MeterOS2Temps) + // .IncludeMany(b => b.MeterPTCEntTemps) + // .IncludeMany(b => b.MeterPTCFlows) + // .IncludeMany(b => b.MeterPTCPws) + // .IncludeMany(b => b.MeterEnvRHs) + // .IncludeMany(b => b.MeterEnvTemps) + // ).ToList().FirstOrDefault(); - //防止上一次下载的程序多余当前的步骤,为了清空多余的步骤数据,增加一行的数据 - ReturnPlcParsData = ProParsSongZhiHelper.AddNullData(ReturnPlcParsData); - //装载PLC地址 - ReturnPlcParsData = ProParsSongZhiHelper.LoadPlcCellAddress(ReturnPlcParsData); + // if (FindData != null && FindData.ProSteps != null && FindData.ProSteps.Any()) + // { + // //执行程序的步骤集合数据 + // ReturnPlcParsData = ProParsSongZhiHelper.GetPlcParsData(FindData.ProSteps, FindData.ProRepeat); + // //把次数给PLC,那么此时应该是最后一个程序给PLC了 + // ProParsSongZhiHelper.LoadProCycleToPlc(MachineRtDataService.SiemensDrive, FindData.ProRepeat); + // } + //} - ProParsSongZhiHelper.LoadDataToPLC(MachineRtDataService.SiemensDrive, ReturnPlcParsData); + ////防止上一次下载的程序多余当前的步骤,为了清空多余的步骤数据,增加一行的数据 + //ReturnPlcParsData = ProParsSongZhiHelper.AddNullData(ReturnPlcParsData); + ////装载PLC地址 + //ReturnPlcParsData = ProParsSongZhiHelper.LoadPlcCellAddress(ReturnPlcParsData); + + //ProParsSongZhiHelper.LoadDataToPLC(MachineRtDataService.SiemensDrive, ReturnPlcParsData); //下载完成的话,则标记状态 SysRunService.MachineRunState1.IsProLoad = true;