配置参数下载和解析的开发-未完成

This commit is contained in:
2025-02-24 11:21:23 +08:00
parent c22a8cc98f
commit d2ef6f9961
25 changed files with 2273 additions and 189 deletions

View File

@@ -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; }
}
}

View File

@@ -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
{
/// <summary>
/// 下载时用的Limit
/// 进制和精度也需要处理好
/// </summary>
public class Limit
{
/// <summary>
/// Limit-Up
/// </summary>
public short Up { get; set; }
/// <summary>
/// Limit-Down
/// </summary>
public short Down { get; set; }
}
}

View File

@@ -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
{
/// <summary>
/// 下载时用的PID
/// 进制也需要处理好
/// </summary>
public class PID
{
/// <summary>
/// PID-P
/// </summary>
public short P { get; set; }
/// <summary>
/// PID-I
/// </summary>
public short I { get; set; }
/// <summary>
/// PID-D
/// </summary>
public short D { get; set; }
}
}

View File

@@ -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
{
/// <summary>
/// 配置限制Dto
/// </summary>
public class ParsConfigLimitDto
{
/// <summary>
/// 主键
/// </summary>
public long Id { get; set; }
/// <summary>
/// 设置仪表名称
/// </summary>
public string? MeterName { get; set; }
/// <summary>
/// 序号
/// </summary>
public int IndexNo { get; set; }
/// <summary>
/// 上限
/// </summary>
public decimal Up { get; set; }
/// <summary>
/// 下限
/// </summary>
public decimal Down { get; set; }
}
}

View File

@@ -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
{
/// <summary>
/// PID 配置模型Dto
/// </summary>
public class ParsConfigPIDDto
{
/// <summary>
/// 主键
/// </summary>
public long Id { get; set; }
/// <summary>
/// 设置仪表名称
/// </summary>
public string? MeterName { get; set; }
/// <summary>
/// 序号
/// </summary>
public int IndexNo { get; set; }
/// <summary>
/// P
/// </summary>
public decimal P { get; set; }
/// <summary>
/// I
/// </summary>
public int I { get; set; }
/// <summary>
/// D
/// </summary>
public int D { get; set; }
}
}

View File

@@ -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
{
/// <summary>
/// 程序执行模型
/// 包括程序名称和程序步骤集合、程序执行信息
/// 一个参数(速度、排气压力)对应一个程序执行模型
/// </summary>
public class ProExModel : BindableBase
{
/// <summary>
/// 实例化函数
/// </summary>
public ProExModel(Channel<ProRunChannelData> channel)
{
ProRunChannel = channel;
//秒触发一次
CycleTimer = new System.Timers.Timer(1000);
CycleTimer.Elapsed += SlopExCycleAction;
CycleTimer.AutoReset = true;
CycleTimer.Enabled = true;
CycleTimer.Start();
}
/// <summary>
/// 程序执行管道
/// </summary>
public Channel<ProRunChannelData> ProRunChannel { get; set; }
/// <summary>
/// 名称
/// </summary>
public string MeterName { get; set; }
/// <summary>
/// 当前模型是否启用
/// 当前有很多参数都是预设,但是有些参数是为其他的项目准备的,可能在当前的项目上都不会配置和使用。
/// 故设置Enable属性
/// </summary>
public bool Enable { get; set; } = true;
/// <summary>
/// 程序步骤集合
/// </summary>
public List<ProStepExe> ListProStepExe { get; set; }
/// <summary>
/// 仪表步骤执行时间信息
/// </summary>
public ProRunTime ProRunTimeModel { get; set; }
/// <summary>
/// 下一步步骤数据执行
/// </summary>
public ProStepExe NextProStepExe { get; set; }
/// <summary>
/// 当前步骤数据执行
/// 给看步骤是否变化使用
/// </summary>
public ProStepExe CurProStepExe { get; set; }
/// <summary>
/// 上一步步骤数据执行
/// 给看步骤是否变化使用
/// </summary>
public ProStepExe LastProStepExe { get; set; }
/// <summary>
/// 当前程序段时间长
/// </summary>
public int CurProTimeSum { get; set; }
/// <summary>
/// 当前程序段开始时间
/// </summary>
public DateTime CurProStartTime { set; get; }
#region
public EventHandler<string> RunTimeCallSglEvent;
/// <summary>
/// 是否启用
/// </summary>
public bool RunEnable { get; set; } = false;
/// <summary>
/// RunTimeCallSglEvent 是否注册关联方法
/// </summary>
public bool EventRegister { get; set; } = false;
/// <summary>
/// 当前步骤开始运行时间
/// </summary>
public DateTime StepStartDt { get; set; }
/// <summary>
/// 当前步骤结束运行时间
/// </summary>
public DateTime StepEndDt { get; set; }
private DateTime _CurrentDateTime;
/// <summary>
/// 当前时间
/// </summary>
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;
}
}
}
/// <summary>
/// 当前步骤已经运行时长-秒
/// </summary>
public int RunTime { get; set; }
/// <summary>
/// 通过组合Pid和Limit组合出运行步骤类型
/// </summary>
/// <param name="pid">PID是否不同</param>
/// <param name="limit">Limit是否不同</param>
/// <param name="sv">SV是否不同</param>
/// <returns>运行步骤类型</returns>
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
/// <summary>
/// 开始打点执行
/// </summary>
private void StartSlopExStep()
{
SlopExEnable = true;
}
/// <summary>
/// 斜率执行步骤集合
/// 打点集合
/// </summary>
public List<SlopExStep> ListSlopExStep { get; set; } = new List<SlopExStep>();
/// <summary>
/// 斜率执行循环周期
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
/// <exception cref="NotImplementedException"></exception>
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}");
}
}
/// <summary>
/// 周期定时器
/// </summary>
private System.Timers.Timer CycleTimer { get; set; }
/// <summary>
/// 步骤斜率执行使能状态
/// </summary>
public bool SlopExEnable { get; set; } = false;
#endregion
}
}

View File

@@ -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
{
/// <summary>
/// 程序运行时间
/// </summary>
public class ProRunTime
{
public EventHandler<string> RunTimeCallSglEvent;
/// <summary>
/// 是否启用
/// </summary>
public bool RunEnable { get; set; } = false;
/// <summary>
/// RunTimeCallSglEvent 是否注册关联方法
/// </summary>
public bool EventRegister { get; set; } = false;
/// <summary>
/// 当前仪表名称
/// </summary>
public string MeterName { get; set; }
/// <summary>
/// 当前程序段名称
/// </summary>
public string ProName { get; set; }
/// <summary>
/// 当前仪表程序步骤
/// </summary>
public int MeterStep { get; set; }
/// <summary>
/// 当前步骤开始运行时间
/// </summary>
public DateTime StartDateTime { get; set; }
/// <summary>
/// 当前步骤结束运行时间
/// </summary>
public DateTime EndDateTime { get; set; }
private DateTime currentDateTime;
/// <summary>
/// 当前时间
/// </summary>
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;
}
}
}
/// <summary>
/// 当前步骤已经运行时长-秒
/// </summary>
public int RunTime { get; set; }
}
}

View File

@@ -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
{
/// <summary>
/// 程序分解后的执行步骤
/// </summary>
public class ProStepExe : BindableBase
{
/// <summary>
/// 程序段名称
/// </summary>
public string? ProSegName { get; set; }
/// <summary>
/// 程序段步骤
/// </summary>
public int ProSegStep { get; set; }
/// <summary>
/// 程序段重复执行次数
/// </summary>
public int ProSegRepeat { get; set; }
/// <summary>
/// 程序段当前是否执行中
/// </summary>
public bool ProSegIsExeing { get; set; }
/////////////////////////////////////////////////////////////////
////////////////////////程序步骤///////////////////////////////
////////////////////////////////////////////////////////////////
///// <summary>
///// 程序步骤标记
///// </summary>
//public StepPosMark StepPosMark { get; set; }
/// <summary>
/// 仪表参数当前是否执行中
/// </summary>
public bool MeterStepIsExeing { get; set; }
/// <summary>
/// 仪表参数是否执行完成
/// </summary>
public bool MeterStepIsOK { get; set; }
/// <summary>
/// 仪表参数名称
/// </summary>
public string? MeterName { get; set; }
/// <summary>
/// 仪表参数步骤
/// </summary>
public int MeterStep { get; set; }
/// <summary>
/// 这个步骤是打开具体设置步骤界面的那个层面的信息例如2-3,代表是程序2里面的仪表步骤3方便调试和给液击使用
/// </summary>
public string? ProStepInfo { get; set; }
///// <summary>
///// 启用状态-没有启用就是什么数据都没有
///// Const-常值-常值StepValue有值只有一个步骤CycleTime为0
///// MultisStep-有步骤细节-此时在一个仪表下就会有很多步骤的细节数据
///// </summary>
//public ConfigValueType ConfigState { get; set; }
/// <summary>
/// StartSV- 步骤的开始SV
/// 最终的写到PLC结果值经过进制转换
/// </summary>
public int StartSV { get; set; }
/// <summary>
/// EndSV- 步骤的目标SV
/// 最终的写到PLC结果值经过进制转换
/// </summary>
public int EndSV { get; set; }
/// <summary>
/// KeepTime Sec
/// </summary>
public int KeepTime { get; set; }
/// <summary>
/// 是否启用坡度
/// 存在斜坡容易判断,非斜坡是常值
/// 常值有两种情况:
/// 一个是设置时就直接设定为常值,
/// 另一个是斜率步骤里面比如起始8000结束9000那么也是常值,因为当前模型是拆分详细之后的,他可以判断详细步骤的斜坡信息
/// </summary>
public bool ExistSlop { get; set; }
///// <summary>
///// 时间-秒-斜坡时间
///// </summary>
//public int SlopTimeSec { get; set; }
/// <summary>
/// PIDNo
/// </summary>
public int PIDNo { get; set; }
/// <summary>
/// PID的配置信息
/// </summary>
public ConfigPIDDto? CurConfigPIDDto { get; set; }
/// <summary>
/// LimitNo
/// </summary>
public int LimitNo { get; set; }
/// <summary>
/// AlarmNo的配置信息
/// </summary>
public ConfigLimitDto? CurConfigLimitDto { get; set; }
/// <summary>
/// AlarmNo
/// </summary>
public int AlarmNo { get; set; }
}
}

View File

@@ -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
{
/// <summary>
/// 运行和下载的数据类型
/// </summary>
public enum RunStepType
{
/// <summary>
/// 正常的步骤信息 SV-PID-Limit 下载数据
/// 就是包括SV PID和SLIMIT的数据当然SV PID和SLIMIT跟上次是一样的话则不需要下载
/// </summary>
Step = 1,
/// <summary>
/// 正常的步骤信息-SV-PID 下载数据
/// 就是包括SV PID和SLIMIT的数据当然SV PID和SLIMIT跟上次是一样的话则不需要下载
/// </summary>
StepPID = 2,
/// <summary>
/// 正常的步骤信息-SV-Limit 下载数据
/// 就是包括SV PID和SLIMIT的数据当然SV PID和SLIMIT跟上次是一样的话则不需要下载
/// </summary>
StepLimit = 3,
/// <summary>
/// 正常的步骤信息-SV 下载数据
/// 就是包括SV PID和SLIMIT的数据当然SV PID和SLIMIT跟上次是一样的话则不需要下载
/// </summary>
StepSV = 4,
/// <summary>
/// 斜率单元
/// 带斜率的数据打点执行只传送SV值
/// 比如速度0-5000 5秒此时执行第一秒1000第二秒2000第三秒3000第四秒4000第五秒5000
/// </summary>
SlopCell = 10
}
}

View File

@@ -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
{
/// <summary>
/// 斜率执行步骤
/// </summary>
public class SlopExStep
{
/// <summary>
/// 步骤号
/// </summary>
public int StepNo { get; set; }
/// <summary>
/// SV值
/// </summary>
public int SV { get; set; }
/// <summary>
/// 是否已经执行
/// </summary>
public bool IsHasEx { get; set; }=false;
}
}

View File

@@ -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
{
/// <summary>
/// PLC下载单元
/// </summary>
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
/// <summary>
/// 时间-分钟
/// </summary>
public short TimeMin { get; set; }
/// <summary>
/// 时间-秒
/// </summary>
public short TimeSec { get; set; }
/// <summary>
/// SV值
/// </summary>
public short SV { get; set; }
/// <summary>
/// PID-P
/// </summary>
public short PID_P { get; set; }
/// <summary>
/// PID-I
/// </summary>
public short PID_I { get; set; }
/// <summary>
/// PID-D
/// </summary>
public short PID_D { get; set; }
/// <summary>
/// Limit-Up
/// </summary>
public short Limit_Up { get; set; }
/// <summary>
/// Limit-Down
/// </summary>
public short Limit_Down { get; set; }
#endregion
}
}

View File

@@ -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
{
/// <summary>
/// 程序步骤标记
/// </summary>
public enum StepPosMark
{
}
}