Explorar el Código

1. 修改多配方执行流程。2. 添加批量下发配方功能。3. 添加变量监控界面。

master
Nah hace 1 año
padre
commit
39555d0b18
Se han modificado 18 ficheros con 878 adiciones y 283 borrados
  1. +101
    -0
      BPA.Model/Attributes/VariableMonitorAttribute.cs
  2. +1
    -1
      BPA.Model/BPA.Model.csproj
  3. +23
    -2
      BPA.Model/GlobalData.cs
  4. +12
    -0
      BPA.Model/IStatus.cs
  5. +8
    -0
      BPA.Model/Recipe/RecipeData.cs
  6. +73
    -0
      BPA.Model/VariableMonitor.cs
  7. +21
    -7
      BPA.SingleDevice/Business/Conveyer.cs
  8. +114
    -181
      BPA.SingleDevice/Business/ProcessControl.cs
  9. +10
    -6
      BPA.SingleDevice/Interface/IConveyer.cs
  10. +6
    -1
      BPA.SingleDevice/Interface/IProcessControl.cs
  11. +2
    -0
      BPA.SingleDevice/View/DebugView.xaml
  12. +5
    -6
      BPA.SingleDevice/View/OrderMainView.xaml
  13. +68
    -9
      BPA.SingleDevice/View/ParamsSetView.xaml
  14. +161
    -2
      BPA.SingleDevice/View/VarMonitorView.xaml
  15. +36
    -5
      BPA.SingleDevice/ViewModel/DebugViewModel.cs
  16. +21
    -61
      BPA.SingleDevice/ViewModel/OrderMainViewModel.cs
  17. +54
    -1
      BPA.SingleDevice/ViewModel/ParamsSetViewModel.cs
  18. +162
    -1
      BPA.SingleDevice/ViewModel/VarMonitorViewModel.cs

+ 101
- 0
BPA.Model/Attributes/VariableMonitorAttribute.cs Ver fichero

@@ -0,0 +1,101 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace BPA.Model.Attributes
{
public class VariableMonitorAttribute : Attribute
{
/// <summary>
/// 变量描述
/// </summary>
/// <param name="Notes">描述</param>
/// <param name="PLCAddress">PLC 地址</param>
/// <param name="ModbusTcpAddress">Modbus TCP 地址</param>
public VariableMonitorAttribute(string Notes, string PLCAddress = "", string ModbusTcpAddress = "")
{
this.PLCAddress = PLCAddress;
this.ModbusTcpAddress = GetModbusTcpAdd(PLCAddress);// ModbusTcpAddress;
this.Notes = Notes;
}

private string GetModbusTcpAdd(string address)
{
if (address == null)
return "";
if (address.Length > 0)
{
address = address.Trim();
if (address.ToUpper().Contains("GM") && address.Length >= 3)
{
var res = address.Remove(0, 2);
if (res != null && res.Length > 0)
return (int.Parse(res) + 4096).ToString();
}
else if (address.ToUpper().Contains("M") && address.Length >= 4)
{
var res = address.Substring(1).Split('.');
if (res != null && res.Length == 2)
{
if (int.TryParse(res[0], out int firstAddress) && int.TryParse(res[1], out int ExitAddress))
{
if (ExitAddress >= 0 && ExitAddress <= 7)
{
return ((firstAddress * 8) + 320 + ExitAddress).ToString();
}
}
}
}
else if (address.ToUpper().Contains("GI") && address.Length >= 3)
{
var res = address.Remove(0, 2);
if (res != null && res.Length > 0)
return res;
}
else if (address.ToUpper().Contains("LB") && address.Length >= 3)
{
var res = address.Substring(2);
if (res != null && res.Length > 0)
{
if (int.TryParse(res, out int firstAddress))
return firstAddress.ToString();
}
}
else if ((address.ToUpper().Contains("VW") || address.ToUpper().Contains("VD")) && address.Length >= 3)
{
var res = address.Substring(2);
if (res != null && int.TryParse(res, out int tempAddress))
{
return ((tempAddress / 2) + 100).ToString();
}
}
else if (address.ToUpper().Contains("LW") && address.Length >= 3)
{
var res = address.Substring(2);
if (res != null && int.TryParse(res, out int LwAddress))
{
return LwAddress.ToString();
}
}
}
return "";
}

/// <summary>
/// PLC 地址
/// </summary>
public string PLCAddress { get; set; }

/// <summary>
/// Modbus TCP 地址
/// </summary>
public string ModbusTcpAddress { get; set; }

/// <summary>
/// 描述
/// </summary>
public string Notes { get; set; }
}
}

+ 1
- 1
BPA.Model/BPA.Model.csproj Ver fichero

@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net6.0-windows</TargetFramework>


+ 23
- 2
BPA.Model/GlobalData.cs Ver fichero

@@ -6,23 +6,44 @@ using System.Threading.Tasks;
using System.Collections.Concurrent;
using BPA.Model.Recipe;
using BPA.Model.Enums;
using BPA.SingleDevice.Interface;
using BPA.Model.Attributes;

namespace BPA.Model
{
public class GlobalData
public class GlobalData: IStatus
{
public ConcurrentQueue<GoodsModel> GoodsModels { get; set; } = new ConcurrentQueue<GoodsModel>();
/// <summary>
/// 需要执行的配方队列。
/// </summary>
public ConcurrentQueue<RecipeData> RecipeQueue { get; set; } = new();

#region 配料机
/// <summary>
/// 是否配料完成。
/// </summary>
[VariableMonitor("配料机完成状态")]
public bool[] IsCompleted { get; set; } = new bool[4];

#endregion

#region 传送带
[VariableMonitor("传送带移动状态步")]
public MoveConveyerStep MoveConveyerStep { get; set; }

[VariableMonitor("传送带移动完成")]
public bool ConveyerMoveComplete { get; set; }

[VariableMonitor("工站容器到位检测")]
public bool[] HaveVessel { get; set; } = new bool[5];
#endregion

#region 全局流程相关
[VariableMonitor("待制作配方数量")]
public int WaitMakeRecipeCount { get=>RecipeQueue.Count; }

[VariableMonitor("开机目前完成配方数量")]
public int CompletedCount { get; set; }
#endregion
}
}

+ 12
- 0
BPA.Model/IStatus.cs Ver fichero

@@ -0,0 +1,12 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace BPA.SingleDevice.Interface
{
public interface IStatus
{
}
}

+ 8
- 0
BPA.Model/Recipe/RecipeData.cs Ver fichero

@@ -30,6 +30,14 @@ namespace BPA.Model.Recipe
/// 下发时间
/// </summary>
public DateTime IssueTime { get; set; }
/// <summary>
/// 开始制作时间
/// </summary>
public DateTime StartTime { get; set; }
/// <summary>
/// 制作完成时间。
/// </summary>
public DateTime CompleteTime { get; set; }
public Dictionary<int,BatchStep> BatchStatus { get; set; }
public RecipeData(string id,string name, Dictionary<int, ushort[]> materialData,int stationCount=5)
{


+ 73
- 0
BPA.Model/VariableMonitor.cs Ver fichero

@@ -0,0 +1,73 @@
using BPA.Helper;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace BPA.Model
{
public class VariableMonitor : NotifyBase
{
public int Id { get { return _mId; } set { _mId = value; OnPropertyChanged(); } }
private int _mId;


public string VarName { get { return _mVarName; } set { _mVarName = value; OnPropertyChanged(); } }
private string _mVarName;


public string PLCAddress { get { return _mPLCAddress; } set { _mPLCAddress = value; OnPropertyChanged(); } }
private string _mPLCAddress;


public string Notes { get { return _mNotes; } set { _mNotes = value; OnPropertyChanged(); } }
private string _mNotes;


public string ModbusTcpAddress { get { return _mModbusTcpAddress; } set { _mModbusTcpAddress = value; OnPropertyChanged(); } }
private string _mModbusTcpAddress;


public string CurrentValue
{
get { return _mCurrentValue; }
set
{
_mCurrentValue = value;
OnPropertyChanged();
if (_mCurrentValue == "False" || _mCurrentValue == "True")
{
if (_mCurrentValue == "True")
StatusColor = new { r = 51, g = 232, b = 34, a = 1 };
else
StatusColor = new { r = 255, g = 0, b = 0, a = 1 };
}
else
StatusColor = new { r = 51, g = 232, b = 34, a = 1 };
}
}
private string _mCurrentValue;
public bool SwitchValue
{
get { return _sWitchValue; }
set
{
_sWitchValue = value;
OnPropertyChanged();
}
}
private bool _sWitchValue;
public int IntValue
{
get { return _intValue; }
set
{
_intValue = value;
OnPropertyChanged();
}
}
private int _intValue;
public object StatusColor { get; set; }
}
}

+ 21
- 7
BPA.SingleDevice/Business/Conveyer.cs Ver fichero

@@ -15,8 +15,8 @@ namespace BPA.SingleDevice.Business

public bool[] HaveVessel { get; set; }
public int IsReverse { get; set ; }
public float InchSpeed { get; set; }
public float MoveSpeed { get; set; }
public int InchSpeed { get; set; }
public int MoveSpeed { get; set; }
public int AccTime { get; set; }
public int MoveLength { get; set; }
public bool MoveComplete { get;set; }
@@ -69,7 +69,7 @@ namespace BPA.SingleDevice.Business
this.ID = id;
}

public void InchMove()
public void StartInchMove()
{
if (IsConnected)
{
@@ -84,7 +84,21 @@ namespace BPA.SingleDevice.Business
}
}
}
public void StopInchMove()
{
if (IsConnected)
{
try
{
modbus.Write<ushort>("VW0".ToModbusAdd(), 0);
}
catch (Exception ex)
{
MessageLog.GetInstance.Show(ex.Message);

}
}
}
public bool MoveOnce()
{
if (IsConnected && AllowMove)
@@ -105,13 +119,13 @@ namespace BPA.SingleDevice.Business
return false;
}

public bool SetInchParam(int isReverse, float inchSpeed)
public bool SetInchParam(int isReverse, int inchSpeed)
{
if (IsConnected)
{
try
{
var result1= modbus.Write<float>("VD100".ToModbusAdd(), inchSpeed);
var result1= modbus.Write<int>("VD100".ToModbusAdd(), inchSpeed);
var result2= modbus.Write<int>("VW200".ToModbusAdd(), isReverse);
return result1.IsSuccess && result2.IsSuccess;
}
@@ -123,13 +137,13 @@ namespace BPA.SingleDevice.Business
return false;
}

public bool SetMoveParam(float moveSpeed, int accTime, int moveLength)
public bool SetMoveParam(int moveSpeed, int accTime, int moveLength)
{
if (IsConnected)
{
try
{
var result1 = modbus.Write<float>("VD104".ToModbusAdd(), moveSpeed);
var result1 = modbus.Write<int>("VD104".ToModbusAdd(), moveSpeed);
var result2 = modbus.Write<int>("VW122".ToModbusAdd(), accTime);
var result3 = modbus.Write<int>("VD108".ToModbusAdd(), moveLength);
return result1.IsSuccess && result2.IsSuccess && result3.IsSuccess;


+ 114
- 181
BPA.SingleDevice/Business/ProcessControl.cs Ver fichero

@@ -28,16 +28,14 @@ namespace BPA.SingleDevice.Business
/// <summary>
/// 键就是配料设备对应的ID。这里分别为1,2,4,5。
/// </summary>
ConcurrentDictionary<int, IBatchcer> batchers = new();
public ConcurrentDictionary<int, IBatchcer> Batchers { get; set; } = new();

List<TaskServer> currentTask = new();
//ConcurrentDictionary<int, TaskServer> test = new();

List<RecipeData> currentRecipes = new();

IConveyer conveyer = new Conveyer();
public List<RecipeData> CurrentRecipes { get; set; } = new();
private readonly ILogService logService;
private GlobalData global;

public IConveyer Conveyer { get ; set ; } = new Conveyer();
//RecipeData currentRecipe;

//CancellationTokenSource cts;
@@ -57,119 +55,99 @@ namespace BPA.SingleDevice.Business
Json<ConnectConfig>.Save();
}



#region 实例初始化配料机
batchers.TryAdd(1, new Batcher());
batchers.TryAdd(2, new Batcher());
batchers.TryAdd(4, new Batcher());
batchers.TryAdd(5, new Batcher());
//Batchers.TryAdd(1, new Batcher());
//Batchers.TryAdd(2, new Batcher());
//Batchers.TryAdd(4, new Batcher());
//Batchers.TryAdd(5, new Batcher());

//SetBatcherComm(1, "192.168.6.100");
//SetBatcherComm(2, "192.168.6.101");
//SetBatcherComm(4, "192.168.6.102");
//SetBatcherComm(5, "192.168.6.103");

SetBatcherComm(1, "127.0.0.1", 503);
SetBatcherComm(2, "127.0.0.1", 504);
SetBatcherComm(4, "127.0.0.1", 505);
SetBatcherComm(5, "127.0.0.1", 506);
foreach (var batcher in batchers.Values)
{
await batcher.Initial();
}
//SetBatcherComm(1, "127.0.0.1", 503);
//SetBatcherComm(2, "127.0.0.1", 504);
//SetBatcherComm(4, "127.0.0.1", 505);
//SetBatcherComm(5, "127.0.0.1", 506);
//foreach (var batcher in Batchers.Values)
//{
// await batcher.Initial();
//}

InitalBatcher(Json<ConnectConfig>.Data.BatcherConfigs);
#endregion

//conveyer.SetCommParam(1, "192.168.6.104",508);
conveyer.SetCommParam(1, "127.0.0.1",510);
await conveyer.Initial();
Conveyer.SetCommParam(1, "192.168.6.104",508);
//Conveyer.SetCommParam(1, "127.0.0.1",510);
await Conveyer.Initial();

currentTask.Clear();
CurrentRecipes.Clear();
ActionRegister();

TaskManage.GetInstance.StartLong(() =>
{
InterActive();

//for (int i = 0; i < currentTask.Count; i++)
//{
// if (currentTask[i].CurrentRecipe.IsMakeComplete.All(b=>b==true))
// {
// currentTask.RemoveAt(i);
// break;
// }
//}

for (int i = 0; i < currentRecipes.Count; i++)
#region 移除配方
for (int i = 0; i < CurrentRecipes.Count; i++)
{
if (currentRecipes[i].IsMakeComplete.All(b => b == true))
if (CurrentRecipes[i].IsMakeComplete.All(b => b == true))
{
var recipeName = currentRecipes[i].Name;
var time = DateTime.Now.Subtract(currentRecipes[i].IssueTime);
currentRecipes.RemoveAt(i);
logService.LogRecipeCompleteInfo($"【{recipeName}】,耗时【{time.Seconds}】秒。");
logService.LogRunInfo($"配方【{recipeName}】-- 整体配料完成,已从配料队列移除。");

var recipe = CurrentRecipes[i];
recipe.CompleteTime = DateTime.Now;
var recipeName = recipe.Name;
var time = recipe.CompleteTime.Subtract(recipe.StartTime);
var issueTime = recipe.IssueTime.ToString("HH:mm:ss");
CurrentRecipes.RemoveAt(i);
global.CompletedCount++;
logService.LogRecipeCompleteInfo($"【{recipeName}】,下发时间【{issueTime}】,开始制作时间【{recipe.StartTime.ToString("HH:mm:ss")}】,耗时【{(int)time.TotalSeconds}】秒。");
logService.LogRunInfo($"配方【{recipeName}】,下发时间【{issueTime}】,开始制作时间【{recipe.StartTime.ToString("HH:mm:ss")}】-- 整体配料完成,已从配料队列移除。");
break;
}
}
#endregion

if (global.RecipeQueue.Count>0/* && currentRecipe is null*/ )
#region 配方加入队列
if (global.RecipeQueue.Count > 0 && CanIssueRecipe())
{
//多配方情况下,必须在工位1没有碗位置,才能进行下发,否则会与之前的配方冲突。
//if (/*!conveyer.HaveVessel[0] &&*/ global.RecipeQueue.ElementAt(0) is not null && global.RecipeQueue.ElementAt(0) is RecipeData && currentTask.Count <5 )
//{

//global.RecipeQueue.TryDequeue(out currentRecipe);
//cts = new();
//Task.Run(() => { Batching(currentRecipe); }, cts.Token);
//logService.LogRunInfo($"配方【{currentRecipe.Name}】-- 开始执行配料。");

//global.RecipeQueue.TryDequeue(out RecipeData recipe);
//if (recipe !=null)
//{
// currentTask.Add(new TaskServer() { RunTask = Task.Run(() => { Batching(recipe); }),
// ID = recipe.IssueTime.Ticks,CurrentRecipe=recipe });
// logService.LogRunInfo($"配方【{recipe.Name}】-- 开始执行配料。");
//}
//}


if (/*!conveyer.HaveVessel[0] &&*/ global.RecipeQueue.ElementAt(0) is not null && global.RecipeQueue.ElementAt(0) is RecipeData && currentRecipes.Count <5 )
if (global.RecipeQueue.ElementAt(0) is not null && global.RecipeQueue.ElementAt(0) is RecipeData && CurrentRecipes.Count < 5)
{
global.RecipeQueue.TryDequeue(out RecipeData recipe);
if (recipe != null)
{
currentRecipes.Add(recipe);
recipe.StartTime = DateTime.Now;
CurrentRecipes.Add(recipe);
logService.LogRunInfo($"配方【{recipe.Name}】-- 开始执行配料。");
}
}
}
}
#endregion

Batching();

RefreshData();
}, "MonitorRecipeIssue", true);
}
/// <summary>
/// 配料
/// 显示数据的赋值。
/// </summary>
/// <param name="recipe">需要配料的配方</param>
[Obsolete("流程有错误")]
private async void Batching(RecipeData recipe)
private void RefreshData()
{
if (recipe is null)
{
logService.LogRunInfo($"参数<recipe>值为null,配料流程结束。");
return;
}
while (recipe.IsMakeComplete[0] == false)
global.IsCompleted[0] = Batchers[1].BatchComplete;
global.IsCompleted[1] = Batchers[2].BatchComplete;
global.IsCompleted[2] = Batchers[4].BatchComplete;
global.IsCompleted[3] = Batchers[5].BatchComplete;
for (int i = 0; i < Conveyer.HaveVessel.Length; i++)
{
//await StationBatching(recipe, 1);
global.HaveVessel[i] = Conveyer.HaveVessel[i];
}
for (int stationNum = 2; stationNum <= 5; stationNum++)
{
await MoveOnceAndBatach(recipe, stationNum);
}
//ToDo:如果最后需要移动一次才能出餐,在这里添加一次移动传送带。
logService.LogRunInfo($"配方【{recipe.Name}】配料完成。");
logService.LogRecipeCompleteInfo($"【{recipe.Name}】");
//currentRecipe = null;
global.ConveyerMoveComplete = Conveyer.MoveComplete;
}

/// <summary>
@@ -181,13 +159,8 @@ namespace BPA.SingleDevice.Business
{
#region 数据验证
//if (recipe is null)
//{
// logService.LogRunInfo($"参数<recipe>值为null,配料流程结束。");
// return;
//}
//如果配料机里没连接该工位的配料机,则直接完成。
if (!batchers.ContainsKey(stationNum))
if (!Batchers.ContainsKey(stationNum))
{
recipe.BatchStatus[stationNum] = BatchStep.BatchCompleted;
recipe.IsMakeComplete[stationNum - 1] = true;
@@ -195,9 +168,9 @@ namespace BPA.SingleDevice.Business
return;
}
#endregion
//数组起始索引是0,工位起始ID是1。
if (conveyer.HaveVessel[stationNum-1])
if (Conveyer.HaveVessel[stationNum-1])
{
ushort[] materialList=new ushort[14];
//获取工位需要的配料数据。
@@ -213,9 +186,10 @@ namespace BPA.SingleDevice.Business
logService.LogRunInfo($"参数<stationNum>值为[{stationNum}],该配方无该工位配料需求。");
return;
}

//配料机配料完成的上升沿检测。
var completeTrig =RTrig.GetInstance($"Batchers[{stationNum}].BatchComplete").Start(batchers[stationNum].BatchComplete);
var completeTrig = RTrig.GetInstance($"Batchers[{stationNum}].BatchComplete").Start(Batchers[stationNum].BatchComplete);
//配料流程。
switch (recipe.BatchStatus[stationNum])
{
@@ -225,7 +199,7 @@ namespace BPA.SingleDevice.Business
case BatchStep.WriteBatchParam:
if (materialList is not null && materialList.Length == 14)
{
if (batchers[stationNum].WriteBatchData(materialList))
if (Batchers[stationNum].WriteBatchData(materialList))
{
recipe.BatchStatus[stationNum] = BatchStep.StartBatch;
logService.LogRunInfo($"配方【{recipe.Name}】写入工位【{stationNum}】的下料参数【{String.Join(',',materialList)}】成功。");
@@ -243,7 +217,7 @@ namespace BPA.SingleDevice.Business
}
break;
case BatchStep.StartBatch:
if (batchers[stationNum].StartBatching())
if (Batchers[stationNum].StartBatching())
{
recipe.BatchStatus[stationNum] = BatchStep.WaitBatchComplete;
logService.LogRunInfo($"配方【{recipe.Name}】工位【{stationNum}】开始配料,等待配料完成信号上升沿。");
@@ -272,49 +246,6 @@ namespace BPA.SingleDevice.Business
Task.Delay(3000).Wait();
}
}
[Obsolete("流程有错误")]
private async Task MoveOnceAndBatach(RecipeData recipe,int stationNum)
{
global.MoveConveyerStep = MoveConveyerStep.WaitMove;
while (global.MoveConveyerStep != MoveConveyerStep.MoveComplete)
{
var moveCompleteTrig = RTrig.GetInstance("MoveCompleted").Start(conveyer.MoveComplete);
switch (global.MoveConveyerStep)
{
case MoveConveyerStep.WaitMove:
conveyer.InitalMoveParam();
await Task.Delay(500);
if (conveyer.MoveOnce())
{
logService.LogRunInfo($"配方【{recipe.Name}】控制传送带去下个工位,等待动作完成信号上升沿。");
global.MoveConveyerStep = MoveConveyerStep.Moveing;
}
else
{
logService.LogRunInfo($"配方【{recipe.Name}】控制传送带去下个工位失败,可能连接异常或不允许移动,3S后重试。");
await Task.Delay(3000);
}
break;
case MoveConveyerStep.Moveing:
if (moveCompleteTrig)
{
logService.LogRunInfo($"配方【{recipe.Name}】控制传送带移动结束。");
conveyer.InitalMoveParam();
while (recipe.IsMakeComplete[stationNum - 1] == false)
{
//await StationBatching(recipe, stationNum);
}
global.MoveConveyerStep = MoveConveyerStep.MoveComplete;
}
break;
case MoveConveyerStep.MoveComplete:
//logService.LogRunInfo($"配方【{recipe.Name}】控制传送带移动结束。");
//await StationBatching(recipe, stationNum);
break;
}
}
}
/// <summary>
/// 移动传送带。
/// </summary>
@@ -324,15 +255,16 @@ namespace BPA.SingleDevice.Business
//global.MoveConveyerStep = MoveConveyerStep.WaitMove;
//while (global.MoveConveyerStep != MoveConveyerStep.MoveComplete)
//{
var moveCompleteTrig = RTrig.GetInstance("MoveCompleted").Start(conveyer.MoveComplete);
var moveCompleteTrig = RTrig.GetInstance("MoveCompleted").Start(Conveyer.MoveComplete);
switch (global.MoveConveyerStep)
{
case MoveConveyerStep.WaitMove:
conveyer.InitalMoveParam();
Conveyer.InitalMoveParam();
Task.Delay(500).Wait();
if (conveyer.MoveOnce())
if (Conveyer.MoveOnce())
{
logService.LogRunInfo($"控制传送带去下个工位,等待动作完成信号上升沿。");
Task.Delay(500).Wait();
global.MoveConveyerStep = MoveConveyerStep.Moveing;
}
else
@@ -350,7 +282,7 @@ namespace BPA.SingleDevice.Business
}
break;
case MoveConveyerStep.MoveComplete:
conveyer.InitalMoveParam();
Conveyer.InitalMoveParam();
UpdateRecipe();
global.MoveConveyerStep = MoveConveyerStep.WaitMove;
//不会执行该步骤,会直接跳出循环。
@@ -366,9 +298,9 @@ namespace BPA.SingleDevice.Business
/// <param name="port">端口号,默认为502。</param>
private void SetBatcherComm(int id,string ip,int port=502)
{
if (batchers.ContainsKey(id))
if (Batchers.ContainsKey(id))
{
batchers[id].SetCommParam(id, ip, port);
Batchers[id].SetCommParam(id, ip, port);
}
else
{
@@ -380,27 +312,24 @@ namespace BPA.SingleDevice.Business
{
ActionManage.GetInstance.Register<bool>(new Func<bool>(() =>
{
//目前如果工位1 没有碗或者当前没配方就可以下配方。
//foreach (var item in currentTask)
//{
// //起始工位没完成的不允许下配方。
// if (!item.CurrentRecipe.IsMakeComplete[0])
// {
// return false;
// }
//}
//return true;
//2023.10.14修改:如果在配方队列里,有配方的当前工位是1,则不允许下发新的配方。
foreach (var item in currentRecipes)
return CanIssueRecipe();
}), "CanIssueRecipe", true);
}
/// <summary>
/// 是否允许下发配方。
/// </summary>
/// <returns></returns>
private bool CanIssueRecipe()
{
foreach (var item in CurrentRecipes)
{
//如果在配方队列里,有配方的当前工位是1,则不允许下发新的配方。
if (item.CurrentStation == 1)
{
if (item.CurrentStation==1)
{
return false;
}
return false;
}
return true;
}), "CanIssueRecipe", true);
}
return global.MoveConveyerStep == MoveConveyerStep.WaitMove;
}
/// <summary>
/// 传送带和配料机之间的信号交互。
@@ -408,14 +337,14 @@ namespace BPA.SingleDevice.Business
private void InterActive()
{
#region 配料机
foreach (var batcher in batchers.Values)
foreach (var batcher in Batchers.Values)
{
batcher.AllowBatching = conveyer.HaveVessel[batcher.ID - 1];
batcher.AllowBatching = Conveyer.HaveVessel[batcher.ID - 1];
}
#endregion

#region 传送带
conveyer.AllowMove = /*conveyer.MoveComplete &&*/ GetBatcherAllowMove();
Conveyer.AllowMove = GetBatcherAllowMove();
#endregion
}
/// <summary>
@@ -425,9 +354,9 @@ namespace BPA.SingleDevice.Business
private bool GetBatcherAllowMove()
{
foreach (var task in currentTask)
foreach (var recipe in CurrentRecipes)
{
foreach (var item in task.CurrentRecipe.BatchStatus.Values)
foreach (var item in recipe.BatchStatus.Values)
{
switch (item)
{
@@ -447,7 +376,7 @@ namespace BPA.SingleDevice.Business
/// <returns></returns>
private bool IsAllowConveyerMove()
{
foreach (var item in currentRecipes)
foreach (var item in CurrentRecipes)
{
if (item.IsMakeComplete[item.CurrentStation-1]==false)
{
@@ -483,17 +412,22 @@ namespace BPA.SingleDevice.Business
/// 初始化配料机。
/// </summary>
/// <param name="configs"></param>
private void InitalBatcher(IList<BatcherConfig> configs)
private async void InitalBatcher(IList<BatcherConfig> configs)
{
foreach (var item in configs)
{
if (item.IsConnect)
{
batchers.TryAdd(item.StationID, new Batcher());
Batchers.TryAdd(item.StationID, new Batcher());
SetBatcherComm(item.StationID, item.IP, item.Port);
batchers[item.StationID].Initial();
}
}
foreach (var batcher in Batchers.Values)
{

await batcher.Initial();

}
}

/// <summary>
@@ -501,16 +435,11 @@ namespace BPA.SingleDevice.Business
/// </summary>
private void UpdateRecipe()
{
foreach (var item in currentRecipes)
foreach (var item in CurrentRecipes)
{
//if (item.CurrentStation<5 && conveyer.HaveVessel[item.CurrentStation])
//{
// item.CurrentStation++;
//}

if (item.CurrentStation<5)
{
while (!conveyer.HaveVessel[item.CurrentStation])
while (!Conveyer.HaveVessel[item.CurrentStation])
{
logService.LogRunInfo($"未检测到配方【{item.Name}】在工位【{item.CurrentStation + 1}】的容器到位信号,请检查。");
Task.Delay(3000).Wait();
@@ -524,18 +453,22 @@ namespace BPA.SingleDevice.Business
/// </summary>
private void Batching()
{
if (currentRecipes.Count>0 && IsAllowConveyerMove())
if (CurrentRecipes.Count>0 && IsAllowConveyerMove())
{
MoveConveyer();
}
foreach (var item in currentRecipes)
else if(global.MoveConveyerStep==MoveConveyerStep.WaitMove)
{
if (!item.IsMakeComplete[item.CurrentStation-1])
foreach (var item in CurrentRecipes)
{
StationBatching(item, item.CurrentStation);
if (!item.IsMakeComplete[item.CurrentStation - 1])
{
StationBatching(item, item.CurrentStation);
}
}

}
}
}



+ 10
- 6
BPA.SingleDevice/Interface/IConveyer.cs Ver fichero

@@ -24,11 +24,11 @@ namespace BPA.SingleDevice.Interface
/// <summary>
/// 寸动速度。
/// </summary>
float InchSpeed { get; set; }
int InchSpeed { get; set; }
/// <summary>
/// 传动带移动速度。
/// </summary>
float MoveSpeed { get; set; }
int MoveSpeed { get; set; }
/// <summary>
/// 加速时间,一般不改动。
/// </summary>
@@ -58,16 +58,20 @@ namespace BPA.SingleDevice.Interface
/// </summary>
void SetCommParam(int id, string ip, int port = 502);
/// <summary>
/// 寸动【调试状态】
/// 开始寸动【调试状态】
/// </summary>
void InchMove();
void StartInchMove();
/// <summary>
/// 停止寸动。
/// </summary>
void StopInchMove();
/// <summary>
/// 设置寸动参数
/// </summary>
/// <param name="isReverse">是否反转</param>
/// <param name="inchSpeed">寸动速度</param>
/// <returns>设置是否成功</returns>
bool SetInchParam(int isReverse,float inchSpeed);
bool SetInchParam(int isReverse,int inchSpeed);
/// <summary>
/// 设置移动参数
/// </summary>
@@ -75,7 +79,7 @@ namespace BPA.SingleDevice.Interface
/// <param name="accTime">移动加速时间</param>
/// <param name="moveLength">移动长度</param>
/// <returns>设置是否成功</returns>
bool SetMoveParam(float moveSpeed, int accTime, int moveLength);
bool SetMoveParam(int moveSpeed, int accTime, int moveLength);
/// <summary>
/// 移动一次。
/// </summary>


+ 6
- 1
BPA.SingleDevice/Interface/IProcessControl.cs Ver fichero

@@ -1,4 +1,5 @@
using System;
using BPA.Model.Recipe;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
@@ -12,5 +13,9 @@ namespace BPA.SingleDevice.Interface
/// 初始化即开始。
/// </summary>
void Inital();
List<RecipeData> CurrentRecipes { get; set; }
//ConcurrentBag<RecipeData> CurrentRecipes { get; set; }
IConveyer Conveyer { get; set; }
ConcurrentDictionary<int, IBatchcer> Batchers { get; set; }
}
}

+ 2
- 0
BPA.SingleDevice/View/DebugView.xaml Ver fichero

@@ -21,6 +21,7 @@
Margin="10"
HorizontalAlignment="Right"
bpa:ToggleButtonHelper.CheckedContent="调试模式"
x:Name="ModeButton"
Command="{Binding SwitchSystemModeCommand}"
CommandParameter="{Binding RelativeSource={RelativeSource Self}, Path=IsChecked}"
Content="配料模式"
@@ -36,6 +37,7 @@
<StackPanel
HorizontalAlignment="Stretch"
VerticalAlignment="Top"
IsEnabled="{Binding ElementName=ModeButton,Path=IsChecked}"
Orientation="Horizontal">
<Button
Width="100"


+ 5
- 6
BPA.SingleDevice/View/OrderMainView.xaml Ver fichero

@@ -51,15 +51,14 @@
Grid.Row="2"
Margin="0,5,0,0"
bpa:GridHelper.ColumnDefinitions="*,*">
<!--<bpa:NumericBox
<bpa:NumericBox
bpa:ControlHelper.FocusBorderBrush="{DynamicResource Secondary}"
BorderThickness="0"
IsReadOnly="True"
BorderThickness="0" Width="90"
Style="{StaticResource FrontBackNumericBox}"
Value="{Binding Count}" />-->
Value="{Binding Count}" />
<Button
Grid.Column="0" Grid.ColumnSpan="2"
Margin="10,0"
Grid.Column="1"
Margin="10,0,0,0"
Command="{Binding DataContext.DownRecipeCommand, RelativeSource={RelativeSource AncestorType=local:OrderMainView}}"
CommandParameter="{Binding Id}"
Content="开始下单"


+ 68
- 9
BPA.SingleDevice/View/ParamsSetView.xaml Ver fichero

@@ -1,12 +1,71 @@
<UserControl x:Class="BPA.SingleDevice.View.ParamsSetView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:BPA.SingleDevice.View"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<UserControl
x:Class="BPA.SingleDevice.View.ParamsSetView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:bpa="http://BPAUIControl.io/winfx/xaml/toolkit"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:BPA.SingleDevice.View"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="clr-namespace:BPA.SingleDevice.ViewModel"
d:DesignHeight="450"
d:DesignWidth="800"
mc:Ignorable="d">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="1*" />
<RowDefinition Height="1*" />
</Grid.RowDefinitions>
<!--#region 设备连接设置-->
<Border
Margin="5"
BorderBrush="Gray"
BorderThickness="3">
<StackPanel Margin="5" Orientation="Horizontal" />
</Border>
<!--#endregion-->

<!--#region 流水线参数设置-->
<Border
Grid.Row="1"
Margin="5"
BorderBrush="Gray"
BorderThickness="3">
<StackPanel Margin="5" Orientation="Vertical">
<Grid Margin="0,0,0,10">
<TextBlock Text="流水线移动参数设置" FontSize="22" Foreground="White"/>
<Button
Width="100"
Height="40"
HorizontalAlignment="Right"
bpa:ButtonHelper.Shape="Round"
Command="{Binding WriteParamsCommand}"
Content="保存并写入设置" />
</Grid>
<StackPanel Margin="5" Orientation="Horizontal">
<TextBlock
FontSize="22"
Foreground="White"
Text="移动速度:" />
<TextBox Width="120" Text="{Binding MoveSpeed}" />
</StackPanel>
<StackPanel Margin="5" Orientation="Horizontal">
<TextBlock
FontSize="22"
Foreground="White"
Text="加速时间:" />
<TextBox Width="120" Text="{Binding AccTime}" />
</StackPanel>
<StackPanel Margin="5" Orientation="Horizontal">
<TextBlock
FontSize="22"
Foreground="White"
Text="移动长度:" />
<TextBox Width="120" Text="{Binding MoveLength}" />
</StackPanel>
</StackPanel>
</Border>

<!--#endregion-->
</Grid>
</UserControl>

+ 161
- 2
BPA.SingleDevice/View/VarMonitorView.xaml Ver fichero

@@ -6,7 +6,166 @@
xmlns:local="clr-namespace:BPA.SingleDevice.View"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
<Grid Margin="10">
<Grid.RowDefinitions>
<RowDefinition Height="30" />
<RowDefinition />
</Grid.RowDefinitions>

<!--#region 表格标题栏设置-->
<Grid Background="#dd2AB2E7">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.3*" />
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition Width="0.7*" />
<ColumnDefinition Width="0.7*" />
</Grid.ColumnDefinitions>
<TextBlock
Grid.Column="0"
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontSize="16"
Text="ID" />

<Grid Grid.Column="1">
<TextBlock
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontSize="16"
Text="变量名" />
<Border
BorderThickness="1,0,1,0" BorderBrush="Gray"
Cursor="SizeWE" />
</Grid>

<TextBlock
Grid.Column="2"
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontSize="16"
Text="PLC 地址" />

<Grid Grid.Column="3">
<TextBlock
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontSize="16"
Text="注释" />
<Border
BorderThickness="1,0,0,0" BorderBrush="Gray"
Cursor="SizeWE" />
</Grid>

<Grid Grid.Column="4">
<TextBlock
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontSize="16"
Text="Modbus TCP 地址" />
<Border
BorderThickness="1,0,1,0" BorderBrush="Gray"
Cursor="SizeWE" />
</Grid>

<TextBlock
Grid.Column="5"
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontSize="16"
Text="当前值" />
</Grid>
<!--#endregion-->

<!--#region 表格数据显示-->
<ScrollViewer
Grid.Row="1"
HorizontalScrollBarVisibility="Hidden"
VerticalScrollBarVisibility="Auto">
<ItemsControl ItemsSource="{Binding VariableMonitors}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid x:Name="gr" Height="30">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.3*" />
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition Width="0.7*" />
<ColumnDefinition Width="0.7*" />
</Grid.ColumnDefinitions>

<TextBlock
Grid.Column="0"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Background="Transparent"
FontSize="14"
Text="{Binding Id}" />

<Grid Grid.Column="1">
<TextBlock
Margin="5,0,0,0"
VerticalAlignment="Center"
Background="Transparent"
FontSize="14"
Text="{Binding VarName}" />
<Border BorderBrush="Gray" BorderThickness="1,0,1,0" />
</Grid>

<TextBlock
Grid.Column="2"
Margin="5,0,0,0"
VerticalAlignment="Center"
Background="Transparent"
FontSize="14"
Text="{Binding PLCAddress}" />

<Grid Grid.Column="3">
<TextBlock
Margin="5,0,0,0"
VerticalAlignment="Center"
Background="Transparent"
FontSize="14"
Text="{Binding Notes}" />
<Border BorderBrush="Gray" BorderThickness="1,0,0,0" />
</Grid>

<Grid Grid.Column="4">
<TextBlock
Margin="5,0,0,0"
VerticalAlignment="Center"
Background="Transparent"
FontSize="14"
Foreground="White"
Text="{Binding ModbusTcpAddress}" />
<Border BorderBrush="Gray" BorderThickness="1,0,1,0" />
</Grid>

<TextBlock
Grid.Column="5"
Margin="5,0,0,0"
VerticalAlignment="Center"
Background="Transparent"
FontSize="14" Foreground="White"
Text="{Binding CurrentValue}" />

<Border
Grid.ColumnSpan="8"
BorderBrush="Gray"
BorderThickness="1" />
</Grid>

<DataTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter TargetName="gr" Property="Background" Value="#112AB2E7" />
</Trigger>
</DataTemplate.Triggers>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
<!--#endregion-->
</Grid>
</UserControl>

+ 36
- 5
BPA.SingleDevice/ViewModel/DebugViewModel.cs Ver fichero

@@ -1,4 +1,6 @@
using System;
using BPA.SingleDevice.Interface;
using BPA.SingleDevice.Services;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
@@ -8,9 +10,38 @@ namespace BPA.SingleDevice.ViewModel
{
public class DebugViewModel:NotifyBase
{
public DebugViewModel()
private readonly IProcessControl process;
private readonly ILogService logService;

public DebugViewModel(IProcessControl process,ILogService logService)
{
StartMoveInchCommand = new(() =>
{
if (process.CurrentRecipes.Count!=0)
{
Message.ShowGlobal("当前有配方正在执行,不可对流水线进行寸动控制。");
return;
}
var isSuccess= process.Conveyer?.SetInchParam(IsReverse ? 1 : 0, InchSpeed);
if (isSuccess is not null && isSuccess==true)
{
process.Conveyer?.StartInchMove();
Message.ShowGlobal("设置流水线寸动开始成功。");
logService.LogUserInfo("设置流水线寸动开始。");
}
else
{
Message.ShowGlobal("设置流水线寸动开始失败,写入寸动参数失败了。");
}
});
StopMoveInchCommand = new(() =>
{
process.Conveyer.StopInchMove();
Message.ShowGlobal("设置流水线寸动停止成功。");
logService.LogUserInfo("设置流水线寸动停止。");
});
this.process = process;
this.logService = logService;
}

public BPARelayCommand<bool> SwitchSystemModeCommand { get; set; }
@@ -21,11 +52,11 @@ namespace BPA.SingleDevice.ViewModel
/// <summary>
/// 开始寸动。
/// </summary>
public BPARelayCommand EndMoveInchCommand { get; set; }
public BPARelayCommand StopMoveInchCommand { get; set; }
/// <summary>
/// 寸动是否反转。
/// </summary>
public bool IsReverse { get; set; }
public float InchSpeed { get; set; }
public int InchSpeed { get; set; } = 1000;
}
}

+ 21
- 61
BPA.SingleDevice/ViewModel/OrderMainViewModel.cs Ver fichero

@@ -12,6 +12,7 @@ using BPA.Model.Recipe;
using BPA.SingleDevice.Services;
using System.Net.WebSockets;
using System.Windows;
using Newtonsoft.Json;

namespace BPA.SingleDevice.ViewModel
{
@@ -37,21 +38,26 @@ namespace BPA.SingleDevice.ViewModel

DownRecipeCommand = new BPARelayCommand<object>(o =>
{
if (o != null && !string.IsNullOrEmpty(o.ToString()))
var result = ActionManage.GetInstance.Send<bool>("CanIssueRecipe");
if (result != null && result.IsSuccess && result.Content == true)
{
if (MessageBoxR.ConfirmGlobal("是否下发配方?","提示")==MessageBoxResult.Yes)
if (o != null && !string.IsNullOrEmpty(o.ToString()))
{
var result= ActionManage.GetInstance.Send<bool>("CanIssueRecipe");
if (result != null && result.IsSuccess && result.Content==true)
if (MessageBoxR.ConfirmGlobal("是否下发配方?", "提示") == MessageBoxResult.Yes)
{
GenerateRecipe(o.ToString()!);
}
else
{
Message.ErrorGlobal("下发配方失败,当前有配方在执行工位【1】的配料流程,请检查后重试。");
}
}
else
{
Message.ErrorGlobal("下发配方失败,输入的配方ID为Null或空,请联系人员检查后。");
}
}
else
{
Message.ErrorGlobal("下发配方失败,当前有配方在执行工位【1】的配料流程,请检查后重试。");
}

});
}
private List<RawMaterTB> RawMaters { get; set; } = new List<RawMaterTB>();
@@ -117,9 +123,13 @@ namespace BPA.SingleDevice.ViewModel
materialData.Add(device.Key, channelWeight);
}
RecipeData recipeData = new(recipeID, recipeName, materialData);
global.RecipeQueue.Enqueue(recipeData);
Message.SuccessGlobal($"下发配方【{recipeName}】成功。");
logService.LogUserInfo($"下发配方【{recipeName}】成功。");
var str = recipeData.ToJson();
for (int i = 0; i < res.Count; i++)
{
global.RecipeQueue.Enqueue(str.FromJSON<RecipeData>());
}
Message.SuccessGlobal($"下发配方【{recipeName}】,份数【{res.Count}】成功。");
logService.LogUserInfo($"下发配方【{recipeName}】,份数【{res.Count}】成功。");
}
else
{
@@ -127,55 +137,5 @@ namespace BPA.SingleDevice.ViewModel
}
}
}
/// <summary>
/// 之前的配方数据解析。
/// </summary>
/// <param name="o"></param>
private void OldDataPrase(object o)
{
var res = Goods.FirstOrDefault(p => p.Id == o.ToString());
if (res != null)
{
List<RawMaterModel> rawMaters = new List<RawMaterModel>();
SqlHelper.GetInstance.GetRawMaterIds(res.Id).Result.OnSuccess(s =>
{
s.ForEach(item =>
{
var rmtb = RawMaters.FirstOrDefault(p => p.Id == item.RawMaterId);
if (rmtb != null)
{
rawMaters.Add(new RawMaterModel()
{
Weight = item.Weight,
DeviceNum = rmtb.DeviceNum,
Id = rmtb.Id,
LastModified = rmtb.LastModified,
Name = rmtb.Name,
WarehouseNum = rmtb.WarehouseNum,
});
}
});
});

for (int i = 0; i < res.Count; i++)
{
List<RawMaterModel> temp = new List<RawMaterModel>();
rawMaters.ForEach(item =>
{
temp.Add(new RawMaterModel()
{
Weight = item.Weight,
WarehouseNum = item.WarehouseNum,
Name = item.Name,
LastModified = item.LastModified,
Id = item.Id,
DeviceNum = item.DeviceNum
});
});
global.GoodsModels.Enqueue(new GoodsModel() { RawMaters = temp });
}
}
}
}
}

+ 54
- 1
BPA.SingleDevice/ViewModel/ParamsSetViewModel.cs Ver fichero

@@ -1,4 +1,5 @@
using System;
using BPA.SingleDevice.Interface;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
@@ -8,5 +9,57 @@ namespace BPA.SingleDevice.ViewModel
{
public class ParamsSetViewModel:NotifyBase
{
public ParamsSetViewModel(IProcessControl processControl)
{
WriteParamsCommand = new(() =>
{
//数据验证。
if (ValidateData())
{
var isSuccess= processControl?.Conveyer.SetMoveParam(MoveSpeed, AccTime, MoveLength);
if (isSuccess is not null && isSuccess==true)
{
Message.SuccessGlobal("写入流水线参数成功。");
}
else
{
Message.ErrorGlobal("写入流水线参数失败,请检查后重试。");
}
}
else
{
Message.ErrorGlobal("写入错误,数据验证失败。");
}
});
}

private bool ValidateData()
{
return true;
}
/// <summary>
/// 流水线移动速度。
/// </summary>
public int MoveSpeed { get; set; }
/// <summary>
/// 加速时间
/// </summary>
public int AccTime { get; set; }
/// <summary>
/// 移动一次的距离。
/// </summary>
public int MoveLength { get; set; } = 2000;

/// <summary>
/// 保存设置。
/// </summary>
public BPARelayCommand SaveCommand { get; set; }
/// <summary>
/// 向流水线写入移动参数。
/// </summary>
public BPARelayCommand WriteParamsCommand { get; set; }
}

}

+ 162
- 1
BPA.SingleDevice/ViewModel/VarMonitorViewModel.cs Ver fichero

@@ -1,6 +1,10 @@
using System;
using BPA.Model;
using BPA.Model.Attributes;
using BPA.SingleDevice.Interface;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

@@ -8,6 +12,163 @@ namespace BPA.SingleDevice.ViewModel
{
public class VarMonitorViewModel:NotifyBase
{
private readonly GlobalData global;

public VarMonitorViewModel(GlobalData global)
{
this.global = global;
GetMonitorData(global);

TaskManage.GetInstance.StartLong(() =>
{
UpdateValue(global);
}, "UpdateValue", true);
}
public ObservableCollection<VariableMonitor> VariableMonitors { get; set; } = new ObservableCollection<VariableMonitor>();
/// <summary>
/// 获取监控信息
/// </summary>
private void GetMonitorData(IStatus status)
{
if (status == null)
return;
List<VariableMonitor> vm = new List<VariableMonitor>();
foreach (var item in status.GetType().GetProperties())
{
if (item.CustomAttributes.Count() > 0)
{
var attributeName = item.CustomAttributes.FirstOrDefault(p => p.AttributeType.Name == "VariableMonitorAttribute");
if (attributeName == null)
return;
var plcadd = item.GetCustomAttribute<VariableMonitorAttribute>()?.PLCAddress;
var modadd = item.GetCustomAttribute<VariableMonitorAttribute>()?.ModbusTcpAddress;
var notes = item.GetCustomAttribute<VariableMonitorAttribute>()?.Notes;

if (item.PropertyType?.BaseType?.Name == "Array")
{
if (plcadd?.Length > 0)
{
var arrayRes = item.GetValue(status, null);
if (arrayRes != null && arrayRes is Array arr)
{
for (int i = 0; i < arr.Length; i++)
{
var res = vm.FirstOrDefault(p => p.VarName == $"{item.Name}_{i + 1}");
if (res == null)
{
string[] plc = plcadd?.Substring(1).Split('.');
string TempPlcAddress = string.Empty;
if (plc?.Length == 2)
{
int add = int.Parse(plc[1]);
int firstAdd = int.Parse(plc[0]);
if (add >= 0 && add < 7)
{
add += i;
}
else if (add >= 7)
{
add = 0;
firstAdd++;
}
plc[0] = firstAdd.ToString();
plc[1] = add.ToString();
TempPlcAddress = $"M{plc[0]}.{plc[1]}";
}

vm.Add(new VariableMonitor()
{
Id = vm.Count+1,
VarName = $"{item.Name}_{i + 1}",
Notes = $"{notes}_{i + 1}",
ModbusTcpAddress = $"{int.Parse(modadd) + i}",
PLCAddress = TempPlcAddress,

});
}
}
}
}
else
{
var arrayRes = item.GetValue(status, null);
if (arrayRes != null && arrayRes is Array arr)
{
for (int i = 0; i < arr.Length; i++)
{
var res = vm.FirstOrDefault(p => p.VarName == $"{item.Name}_{i + 1}");
if (res == null)
{
vm.Add(new VariableMonitor()
{
Id = vm.Count+1,
VarName = $"{item.Name}_{i + 1}",
Notes = $"{notes}_{i + 1}",

});
}
}
}
}
}
else
{
var res = vm.FirstOrDefault(p => p.VarName == item.Name);
if (res == null)
{
vm.Add(new VariableMonitor()
{
Id = vm.Count+1,
VarName = item.Name,
Notes = notes,
ModbusTcpAddress = modadd,
PLCAddress = plcadd,

});
}
}

}
}

vm.ForEach(item => { VariableMonitors.Add(item); });

}


public void UpdateValue(IStatus status)
{
if (status == null)
return;
foreach (var item in status.GetType().GetProperties())
{
if (item.CustomAttributes.Count() > 0)
{
if (item.PropertyType?.BaseType?.Name == "Array")
{
var arrayRes = item.GetValue(status);
if (arrayRes != null && arrayRes is Array arr)
{
for (int i = 0; i < arr.Length; i++)
{
int index = Array.FindIndex(VariableMonitors.ToArray(), p => p.VarName == $"{item.Name}_{i + 1}");
if (index >= 0 && index < VariableMonitors.Count)
{
VariableMonitors.ElementAt(index).CurrentValue = arr.GetValue(i)?.ToString();
}
}
}
}
else
{
int index = Array.FindIndex(VariableMonitors.ToArray(), p => p.VarName == item.Name);
if (index >= 0 && index < VariableMonitors.Count)
{
VariableMonitors.ElementAt(index).CurrentValue = item.GetValue(status)?.ToString();
}
}
}
}
}
}
}

Cargando…
Cancelar
Guardar