1585 lines
54 KiB
C#
1585 lines
54 KiB
C#
using AntdUI;
|
||
using AntdUI.Svg;
|
||
using DH.Commons.Base;
|
||
using DH.Commons.Enums;
|
||
using DH.Commons.Helper;
|
||
using DH.Commons.Models;
|
||
using DH.Devices.Camera;
|
||
using DH.Devices.Motion;
|
||
using DH.Devices.PLC;
|
||
using DH.Devices.Vision;
|
||
using DHSoftware.Languages;
|
||
using DHSoftware.Models;
|
||
using DHSoftware.Utils;
|
||
using DHSoftware.Views;
|
||
using DVPCameraType;
|
||
using HalconDotNet;
|
||
using Microsoft.VisualBasic.Logging;
|
||
using Microsoft.Win32;
|
||
using OpenCvSharp;
|
||
using SqlSugar;
|
||
using System;
|
||
using System.CodeDom;
|
||
using System.Collections.Concurrent;
|
||
using System.Collections.Generic;
|
||
using System.ComponentModel;
|
||
using System.Diagnostics;
|
||
using System.Drawing;
|
||
using System.Linq;
|
||
using System.Runtime.CompilerServices;
|
||
using System.Runtime.InteropServices;
|
||
using System.Text;
|
||
using System.Threading;
|
||
using System.Threading.Tasks;
|
||
using System.Windows.Forms;
|
||
using XKRS.UI.Device.Winform;
|
||
using static AntdUI.Math3D;
|
||
using static DH.Commons.Enums.EnumHelper;
|
||
using Camera = DHSoftware.Models.Camera;
|
||
using LogLevel = DH.Commons.Enums.EnumHelper.LogLevel;
|
||
using ResultState = DH.Commons.Base.ResultState;
|
||
using Timer = System.Threading.Timer;
|
||
|
||
namespace DHSoftware
|
||
{
|
||
public partial class MainWindow : AntdUI.Window
|
||
{
|
||
System.Windows.Forms.Timer _refreshUITimer = new System.Windows.Forms.Timer();
|
||
private Dictionary<string, List<string>> _cameraRelatedDetectionDict = null;
|
||
public event Action<LogMsg> OnLog;
|
||
|
||
public List<CameraSummary> CameraSummaries { get; set; } = new List<CameraSummary>();
|
||
public List<ProductSummary> ProductSummaries { get; set; } = new List<ProductSummary>();
|
||
static object _productSummaryLock = new object();
|
||
public event Action<DateTime, object, string> OnUpdateResult;
|
||
public event Action<DateTime, object, string> OnUpdateCamResult;
|
||
|
||
private string _loginName;
|
||
|
||
public string LoginName
|
||
{
|
||
get { return _loginName; }
|
||
set
|
||
{
|
||
_loginName = value;
|
||
UpdateLabel();
|
||
}
|
||
}
|
||
|
||
private bool _ShowConfig;
|
||
|
||
public bool ShowConfig
|
||
{
|
||
get { return _ShowConfig; }
|
||
set
|
||
{
|
||
_ShowConfig = value;
|
||
UpdateConfig();
|
||
}
|
||
}
|
||
|
||
private bool _addscheme;
|
||
|
||
public bool Addscheme
|
||
{
|
||
get { return _addscheme; }
|
||
set
|
||
{
|
||
_addscheme = value;
|
||
UpdateScheme();
|
||
}
|
||
}
|
||
|
||
private bool _deletescheme;
|
||
|
||
public bool Deleteschememe
|
||
{
|
||
get { return _deletescheme; }
|
||
set
|
||
{
|
||
_deletescheme = value;
|
||
UpdateScheme();
|
||
}
|
||
}
|
||
|
||
private bool _loadscheme;
|
||
|
||
public bool Loadscheme
|
||
{
|
||
get { return _loadscheme; }
|
||
set
|
||
{
|
||
_loadscheme = value;
|
||
UpdateScheme();
|
||
}
|
||
}
|
||
|
||
private void UpdateScheme()
|
||
{
|
||
if (this.InvokeRequired)
|
||
{
|
||
this.Invoke(new Action(UpdateScheme));
|
||
return;
|
||
}
|
||
|
||
if (Loadscheme)
|
||
{
|
||
btnDeleteProject.Visible = true;
|
||
}
|
||
else
|
||
{
|
||
btnDeleteProject.Visible = false;
|
||
}
|
||
if (Addscheme)
|
||
{
|
||
btnAddProject.Visible = true;
|
||
}
|
||
else
|
||
{
|
||
btnAddProject.Visible = false;
|
||
}
|
||
if (Deleteschememe)
|
||
{
|
||
btnLoadProject.Visible = true;
|
||
}
|
||
else
|
||
{
|
||
btnLoadProject.Visible = false;
|
||
}
|
||
}
|
||
|
||
private void UpdateLabel()
|
||
{
|
||
if (lbName.InvokeRequired)
|
||
{
|
||
lbName.Invoke(new Action(UpdateLabel));
|
||
return;
|
||
}
|
||
lbName.Text = _loginName;
|
||
}
|
||
|
||
private void UpdateConfig()
|
||
{
|
||
if (ShowConfig)
|
||
{
|
||
if (segmented1.InvokeRequired)
|
||
{
|
||
segmented1.Invoke(new Action(UpdateConfig));
|
||
return;
|
||
}
|
||
// 恢复显示时
|
||
segmented1.Items.Insert(4, itemToHide);
|
||
}
|
||
else
|
||
{
|
||
if (segmented1.InvokeRequired)
|
||
{
|
||
segmented1.Invoke(new Action(UpdateConfig));
|
||
return;
|
||
}
|
||
segmented1.Items.Remove(itemToHide);
|
||
}
|
||
}
|
||
|
||
public MainWindow()
|
||
{
|
||
InitializeComponent();
|
||
InitialCameraSumsView(); //refreshTimer.Start();
|
||
//初始化数据
|
||
InitData();
|
||
//绑定事件
|
||
BindEventHandler();
|
||
//UserConfigFrm userControlFrm = new UserConfigFrm();
|
||
|
||
//userControlFrm.Window = this;
|
||
//userControlFrm.Dock = DockStyle.Fill;
|
||
//tabPage2.Controls.Add(userControlFrm);
|
||
}
|
||
//#region OEE
|
||
// public event Action<RunState> OnProcessRunStateChanged;
|
||
#region INotifyPropertyChanged
|
||
public event PropertyChangedEventHandler PropertyChanged;
|
||
public virtual void Set<T>(ref T field, T newValue, [CallerMemberName] string propName = null)
|
||
{
|
||
if (!field.Equals(newValue))
|
||
{
|
||
field = newValue;
|
||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
|
||
}
|
||
}
|
||
#endregion
|
||
#region Properties
|
||
private int uph = 0;
|
||
private int upm = 0;
|
||
|
||
private DateTime? startTime = null;
|
||
private TimeSpan runTime = new TimeSpan();
|
||
private TimeSpan idleTime = new TimeSpan();
|
||
private TimeSpan downTime = new TimeSpan();
|
||
private TimeSpan totalTime = new TimeSpan();
|
||
private int qty_OEE = 0;
|
||
private int qty_OEE_OK = 0;
|
||
private float oee = 0;
|
||
|
||
public int UPH
|
||
{
|
||
get => uph;
|
||
set => Set(ref uph, value);
|
||
}
|
||
public int UPM
|
||
{
|
||
get => upm;
|
||
set => Set(ref upm, value);
|
||
}
|
||
public DateTime? StartTime
|
||
{
|
||
get => startTime;
|
||
set => Set(ref startTime, value);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 有效运行时间
|
||
/// </summary>
|
||
public TimeSpan RunTime
|
||
{
|
||
get => runTime;
|
||
set => Set(ref runTime, value);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 空闲待机时间
|
||
/// </summary>
|
||
public TimeSpan IdleTime
|
||
{
|
||
get => idleTime;
|
||
set => Set(ref idleTime, value);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 故障宕机时间
|
||
/// </summary>
|
||
public TimeSpan DownTime
|
||
{
|
||
get => downTime;
|
||
set => Set(ref downTime, value);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 总开机时间
|
||
/// </summary>
|
||
public TimeSpan TotalTime
|
||
{
|
||
get => totalTime;
|
||
set => Set(ref totalTime, value);
|
||
}
|
||
|
||
public float OEE
|
||
{
|
||
get => oee;
|
||
set => Set(ref oee, value);
|
||
}
|
||
#endregion
|
||
#region Timer
|
||
System.Threading.Timer _runTimer = null;
|
||
System.Threading.Timer _idleTimer = null;
|
||
System.Threading.Timer _downTimer = null;
|
||
System.Threading.Timer _checkIdleTimer = null;
|
||
//System.Threading.Timer _calculateTimer = null;
|
||
|
||
private RunState? currentState = null;
|
||
public RunState? CurrentState
|
||
{
|
||
get => currentState;
|
||
set
|
||
{
|
||
if (value != null)
|
||
{
|
||
if (value.Value == RunState.Running)
|
||
{
|
||
_checkIdleTimer?.Change(10 * 1000, -1);
|
||
}
|
||
|
||
if (currentState != value.Value)
|
||
{
|
||
switch (currentState)
|
||
{
|
||
case RunState.Idle:
|
||
//AddRunEventInBuffer(DateTime.Now, RunEvent_EventType.Idle, false);
|
||
break;
|
||
case RunState.Down:
|
||
//AddRunEventInBuffer(DateTime.Now, RunEvent_EventType.Down, false);
|
||
break;
|
||
}
|
||
|
||
switch (value.Value)
|
||
{
|
||
case RunState.Stop:
|
||
_runTimer?.Change(-1, -1);
|
||
_idleTimer?.Change(-1, -1);
|
||
_downTimer?.Change(-1, -1);
|
||
break;
|
||
case RunState.Running:
|
||
_idleTimer?.Change(-1, -1);
|
||
_downTimer?.Change(-1, -1);
|
||
_runTimer?.Change(0, 1000);
|
||
break;
|
||
case RunState.Idle:
|
||
_runTimer?.Change(-1, -1);
|
||
_downTimer?.Change(-1, -1);
|
||
_idleTimer?.Change(0, 1000);
|
||
|
||
//AddRunEventInBuffer(DateTime.Now, RunEvent_EventType.Idle, true);
|
||
break;
|
||
case RunState.Down:
|
||
_idleTimer?.Change(-1, -1);
|
||
_runTimer?.Change(-1, -1);
|
||
_downTimer?.Change(0, 1000);
|
||
|
||
//AddRunEventInBuffer(DateTime.Now, RunEvent_EventType.Down, true);
|
||
break;
|
||
}
|
||
|
||
currentState = value;
|
||
|
||
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
private void CheckIdleTimeStart(object state)
|
||
{
|
||
if (CurrentState == RunState.Running)
|
||
{
|
||
RunTime = RunTime.Add(new TimeSpan(0, 0, 0 - 10));
|
||
IdleTime = IdleTime.Add(new TimeSpan(0, 0, 10));
|
||
|
||
CurrentState = RunState.Idle;
|
||
}
|
||
}
|
||
|
||
public void InitialOEEStatistic()
|
||
{
|
||
InitialStatisticTimers();
|
||
ResetOEETimeDistribute();
|
||
ResetProductSummaries();
|
||
}
|
||
|
||
public void ResetProductSummaries()
|
||
{
|
||
ProductSummaries = new List<ProductSummary>();
|
||
}
|
||
private void InitialStatisticTimers()
|
||
{
|
||
if (_checkIdleTimer == null)
|
||
{
|
||
_checkIdleTimer = new Timer(new TimerCallback(CheckIdleTimeStart), null, -1, -1);
|
||
}
|
||
|
||
if (_runTimer == null)
|
||
{
|
||
_runTimer = new System.Threading.Timer(RunTimerCallBack, null, -1, -1);
|
||
}
|
||
|
||
if (_idleTimer == null)
|
||
{
|
||
_idleTimer = new System.Threading.Timer(IdleTimerCallBack, null, -1, -1);
|
||
}
|
||
|
||
if (_downTimer == null)
|
||
{
|
||
_downTimer = new System.Threading.Timer(DownTimerCallBack, null, -1, -1);
|
||
}
|
||
|
||
StartTime = DateTime.Now;
|
||
DownTime = IdleTime = RunTime = new TimeSpan(0, 0, 0);
|
||
CurrentState = RunState.Running;
|
||
}
|
||
|
||
private void DownTimerCallBack(object state)
|
||
{
|
||
DownTime = DownTime.Add(new TimeSpan(0, 0, 1));
|
||
GetTotalTime();
|
||
}
|
||
|
||
private void IdleTimerCallBack(object state)
|
||
{
|
||
IdleTime = IdleTime.Add(new TimeSpan(0, 0, 1));
|
||
GetTotalTime();
|
||
}
|
||
|
||
private void RunTimerCallBack(object state)
|
||
{
|
||
RunTime = RunTime.Add(new TimeSpan(0, 0, 1));
|
||
GetTotalTime();
|
||
}
|
||
|
||
private void GetTotalTime()
|
||
{
|
||
TotalTime = RunTime + IdleTime + DownTime;
|
||
}
|
||
|
||
public void ResetOEETimeDistribute()
|
||
{
|
||
StartTime = DateTime.Now;
|
||
DownTime = IdleTime = RunTime = new TimeSpan(0, 0, 0);
|
||
|
||
ProductNum_Total = ProductNum_OK = 0;
|
||
}
|
||
|
||
public void CloseStatisticTimers()
|
||
{
|
||
CloseTimer(ref _checkIdleTimer);
|
||
CloseTimer(ref _runTimer);
|
||
CloseTimer(ref _idleTimer);
|
||
CloseTimer(ref _downTimer);
|
||
|
||
CurrentState = RunState.Stop;
|
||
}
|
||
|
||
private void CloseTimer(ref System.Threading.Timer timer)
|
||
{
|
||
timer?.Change(-1, -1);
|
||
timer?.Dispose();
|
||
timer = null;
|
||
}
|
||
#endregion
|
||
|
||
#region CameraSum
|
||
private void InitialCameraSumsView()
|
||
{
|
||
dgvProductNums.AutoGenerateColumns = false;
|
||
|
||
dgvProductNums.DefaultCellStyle.Font = new Font("Tahoma", 12, FontStyle.Regular, GraphicsUnit.World);
|
||
|
||
dgvProductNums.DataSource = null;
|
||
dgvProductNums.DataSource = ProductSummaries;
|
||
|
||
|
||
dgvCamreaNums.AutoGenerateColumns = false;
|
||
|
||
dgvCamreaNums.DefaultCellStyle.Font = new Font("Tahoma", 12, FontStyle.Regular, GraphicsUnit.World);
|
||
|
||
dgvCamreaNums.DataSource = null;
|
||
dgvCamreaNums.Columns.Clear();
|
||
|
||
// 添加 CCD 列
|
||
dgvCamreaNums.Columns.Add(new DataGridViewTextBoxColumn
|
||
{
|
||
HeaderText = "CCD",
|
||
DataPropertyName = "CameraName"
|
||
});
|
||
|
||
// 添加 合格 列
|
||
var okColumn = new DataGridViewTextBoxColumn
|
||
{
|
||
HeaderText = "合格",
|
||
DataPropertyName = "OKCount"
|
||
};
|
||
okColumn.DefaultCellStyle.ForeColor = Color.LightGreen; // 设置背景为绿色
|
||
dgvCamreaNums.Columns.Add(okColumn);
|
||
|
||
// 添加 不合格 列
|
||
var ngColumn = new DataGridViewTextBoxColumn
|
||
{
|
||
HeaderText = "不合格",
|
||
DataPropertyName = "NGCount"
|
||
};
|
||
ngColumn.DefaultCellStyle.ForeColor = Color.LightCoral; // 设置背景为红色
|
||
dgvCamreaNums.Columns.Add(ngColumn);
|
||
|
||
// 添加 总数 列
|
||
dgvCamreaNums.Columns.Add(new DataGridViewTextBoxColumn
|
||
{
|
||
HeaderText = "总数",
|
||
DataPropertyName = "TotalCount"
|
||
|
||
});
|
||
|
||
// 添加 良率 列
|
||
dgvCamreaNums.Columns.Add(new DataGridViewTextBoxColumn
|
||
{
|
||
HeaderText = "良率",
|
||
DataPropertyName = "YieldStr"
|
||
});
|
||
|
||
dgvCamreaNums.DataSource = new BindingList<CameraSummary>(CameraSummaries);
|
||
}
|
||
#endregion
|
||
|
||
/// <summary>
|
||
/// 窗体对象实例
|
||
/// </summary>
|
||
private static MainWindow _instance;
|
||
|
||
internal static MainWindow Instance
|
||
{
|
||
get
|
||
{
|
||
if (_instance == null)
|
||
_instance = new MainWindow();
|
||
return _instance;
|
||
}
|
||
}
|
||
|
||
private SegmentedItem itemToHide;
|
||
|
||
private void InitData()
|
||
{
|
||
itemToHide = segmented1.Items[4];
|
||
segmented1.Items.Remove(itemToHide);
|
||
}
|
||
|
||
public void LoadScheme()
|
||
{
|
||
try
|
||
{
|
||
//方案配置初始化
|
||
SchemeHelper.Initialize();
|
||
//读取方案列表
|
||
List<string> list = SchemeHelper.GetAllSchemes();
|
||
string CurrentScheme = "默认方案";
|
||
//如果是空,新增默认数据
|
||
if (list == null || list.Count <= 0)
|
||
{
|
||
list = new() { CurrentScheme };
|
||
//显示到方案列表
|
||
sltProjects.Items.Clear();
|
||
|
||
sltProjects.Items.Add(CurrentScheme);
|
||
//保存到方案配置
|
||
SchemeHelper.AddScheme(CurrentScheme);
|
||
SchemeHelper.SetCurrentScheme(CurrentScheme);
|
||
//新构建配置文件
|
||
ConfigHelper.InitializeScheme(CurrentScheme);
|
||
|
||
sltProjects.SelectedIndex = 0;
|
||
}
|
||
else
|
||
{
|
||
foreach (string s in list)
|
||
{
|
||
sltProjects.Items.Add(s);
|
||
}
|
||
CurrentScheme = SchemeHelper.GetCurrentScheme();
|
||
sltProjects.SelectedValue = CurrentScheme;
|
||
}
|
||
SystemModel.CurrentScheme = CurrentScheme;
|
||
//加载当前方案配置
|
||
ConfigHelper.LoadConfig();
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
AntdUI.Message.error(this, ex.Message, autoClose: 3);
|
||
}
|
||
}
|
||
|
||
public void ConnectCamera()
|
||
{
|
||
Cameras.Clear();
|
||
HKCameras.Clear();
|
||
if (ConfigModel.CameraBaseList.Count > 0)
|
||
{
|
||
for (int i = 0; i < ConfigModel.CameraBaseList.Count; i++)
|
||
{
|
||
var cameraBase = ConfigModel.CameraBaseList[i];
|
||
if (cameraBase.CamType == EnumCamType.度申Do3think)
|
||
{
|
||
|
||
|
||
Do3ThinkCamera cam =new Do3ThinkCamera();
|
||
cam.IsSavePicEnabled = cameraBase.IsSavePicEnabled;
|
||
cam.CameraName = cameraBase.CameraName;
|
||
cam.CameraIP = cameraBase.CameraIP;
|
||
cam.IsEnabled = cameraBase.IsEnabled;
|
||
cam.ImageSaveDirectory = "D://Cam1//";
|
||
Cameras.Add(cam);
|
||
if(cameraBase.IsEnabled)
|
||
{
|
||
cam.OnLog -= _visionEngine_OnLog;
|
||
cam.OnLog += _visionEngine_OnLog;
|
||
cam.CameraConnect();
|
||
cam.OnHImageOutput += OnCameraHImageOutput;
|
||
}
|
||
|
||
}
|
||
else if (cameraBase.CamType == EnumCamType.海康hik)
|
||
{
|
||
HikVisionCamera cam = new HikVisionCamera();
|
||
cam.CameraName = cameraBase.CameraName;
|
||
cam.CameraIP = cameraBase.CameraIP;
|
||
cam.IsEnabled = cameraBase.IsEnabled;
|
||
HKCameras.Add(cam);
|
||
// cam.CameraConnect();
|
||
cam.OnHImageOutput += OnCameraHImageOutput;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
public void ConnectPLC()
|
||
{
|
||
if (ConfigModel.PLCBaseList.Count > 0)
|
||
{
|
||
for (int i = 0; i < ConfigModel.PLCBaseList.Count; i++)
|
||
{
|
||
var plcBase = ConfigModel.PLCBaseList[i];
|
||
if (plcBase.PLCType == EnumPLCType.信捷XC网口 || plcBase.PLCType == EnumPLCType.信捷XD网口)
|
||
{
|
||
PLC.IP = plcBase.IP;
|
||
PLC.PLCType = plcBase.PLCType;
|
||
PLC.Enable = plcBase.Enable;
|
||
PLC.PLCName = plcBase.PLCName;
|
||
PLC.PLCItemList = plcBase.PLCItemList;
|
||
PLC.Port = plcBase.Port;
|
||
PLC.OnLog -= _visionEngine_OnLog;
|
||
PLC.OnLog += _visionEngine_OnLog;
|
||
PLC.PLCConnect();
|
||
}
|
||
}
|
||
}
|
||
}
|
||
FrmLog frmLog;
|
||
public void InitModel()
|
||
{
|
||
Dectection.Clear();
|
||
_cameraRelatedDetectionDict = new();
|
||
|
||
if (ConfigModel.DetectionList.Count > 0)
|
||
{
|
||
for (int i = 0; i < ConfigModel.DetectionList.Count; i++)
|
||
{
|
||
DetectionConfig detectionConfig = ConfigModel.DetectionList[i];
|
||
var detection = ConfigModel.DetectionList[i];
|
||
detectionConfig.CameraCollects = detection.CameraCollects;
|
||
detectionConfig.ModelconfThreshold = detection.ModelconfThreshold;
|
||
detectionConfig.ModelWidth = detection.ModelWidth;
|
||
detectionConfig.ModelHeight = detection.ModelHeight;
|
||
detectionConfig.In_lable_path = detection.In_lable_path;
|
||
detectionConfig.IsEnabled = detection.IsEnabled;
|
||
|
||
detectionConfig.ShowLocation.X = (i + 1) % 5 + (i + 1) / 5;
|
||
// detectionConfig.ShowLocation.X = detection.ShowLocation.X;
|
||
detectionConfig.ShowLocation.Y = (i + 1) / 5 + 1;
|
||
// detectionConfig.ShowLocation.Y = detection.ShowLocation.Y;
|
||
DetectionConfigs.Add(detectionConfig);
|
||
}
|
||
}
|
||
DetectionConfigs.ForEach(detection =>
|
||
{
|
||
detection.CameraCollects.ForEach(cam =>
|
||
{
|
||
List<string> Dets = new List<string>
|
||
{
|
||
detection.Id
|
||
};
|
||
if (!_cameraRelatedDetectionDict.ContainsKey(cam.CameraSourceId))
|
||
{
|
||
_cameraRelatedDetectionDict.Add(cam.CameraSourceId, Dets);
|
||
}
|
||
else
|
||
{
|
||
_cameraRelatedDetectionDict[cam.CameraSourceId].Add(detection.Id);
|
||
}
|
||
}
|
||
);
|
||
});
|
||
string inferenceDevice = "CPU";
|
||
|
||
frmLog = new FrmLog();
|
||
frmLog.Dock = DockStyle.Fill;
|
||
pnlLog.Controls.Add(frmLog);
|
||
//
|
||
_visionEngine = new SimboVisionDriver();
|
||
_visionEngine.DetectionConfigs = DetectionConfigs;
|
||
_visionEngine.OnLog += _visionEngine_OnLog;
|
||
//初始化模型 加载模型
|
||
_visionEngine.Init();
|
||
|
||
CtrlVisionRunBase ctrlVisionRun = new CtrlVisionRunBase(_visionEngine);
|
||
ctrlVisionRun.Dock = DockStyle.Fill;
|
||
tabImgDisplay.Controls.Add(ctrlVisionRun);
|
||
|
||
}
|
||
|
||
private void _visionEngine_OnLog(LogMsg msg)
|
||
{
|
||
OnLog?.Invoke(msg);
|
||
LogDisplay(msg);
|
||
}
|
||
private void LogDisplay(LogMsg msg)
|
||
{
|
||
|
||
frmLog?.LogDisplay(msg);
|
||
}
|
||
public LoggerHelper LoggerHelper { get; set; } = new LoggerHelper();
|
||
public virtual void LogAsync(LogMsg msg)
|
||
{
|
||
//if (IConfig != null)
|
||
//{
|
||
// LoggerHelper.SetLogLevel(IConfig.DefaultLogLevel);
|
||
//}
|
||
//else
|
||
//{
|
||
// LoggerHelper.SetLogLevel(LogLevel.Assist);
|
||
//}
|
||
|
||
msg.ThreadId = Thread.CurrentThread.ManagedThreadId;
|
||
|
||
OnLog?.Invoke(msg);
|
||
//if (IConfig?.IsLogEnabled ?? true)
|
||
//{
|
||
LoggerHelper.LogAsync(msg);
|
||
//}
|
||
}
|
||
public virtual void LogAsync(DateTime dt, LogLevel logLevel, string msg)
|
||
{
|
||
LogAsync(new LogMsg(dt, logLevel, msg));
|
||
|
||
}
|
||
private void BindEventHandler()
|
||
{
|
||
btnAddProject.Click += BtnAddProject_Click;
|
||
btnDeleteProject.Click += BtnDeleteProject_Click;
|
||
btnLoadProject.Click += BtnLoadProject_Click;
|
||
LoggerHelper.LogPath = "D://";
|
||
LoggerHelper.LogPrefix = "Process";
|
||
OnLog -= LogDisplay;
|
||
OnLog += LogDisplay;
|
||
|
||
OnUpdateCamResult -= UpdateCamResult;
|
||
|
||
OnUpdateCamResult += UpdateCamResult;
|
||
OnUpdateResult -= UpdateResult;
|
||
OnUpdateResult += UpdateResult;
|
||
Load += (s, e) =>
|
||
{
|
||
_refreshUITimer.Interval = 1000;
|
||
_refreshUITimer.Tick += _refreshUITimer_Tick;
|
||
_refreshUITimer.Enabled = true;
|
||
};
|
||
}
|
||
private void _refreshUITimer_Tick(object sender, EventArgs e)
|
||
{
|
||
_refreshUITimer.Enabled = false;
|
||
|
||
if (this != null)
|
||
{
|
||
lblStartTime.Text = StartTime == null ? "" : StartTime.Value.ToString("yyyy/MM/dd HH:mm:ss");
|
||
lblTotalTime.Text = TotalTime.ToString(); // 运行时间
|
||
// lblRunTime.Text = RunTime.ToString(); // 有效时间
|
||
// lblIdleTime.Text = ProcessControl.IdleTime.ToString(); // 空闲时间
|
||
// lblDownTime.Text = ProcessControl.DownTime.ToString(); // 宕机时间
|
||
|
||
lblOEE_Total.Text =ProductNum_Total.ToString();
|
||
//lblOEE_OK.Text = ProcessControl.ProductNum_OK.ToString();
|
||
}
|
||
|
||
_refreshUITimer.Enabled = true;
|
||
}
|
||
private void UpdateCamResult(DateTime updateTime, object objData, string customMessage)
|
||
{
|
||
this.Invoke(new Action(() =>
|
||
{
|
||
|
||
BindingList<CameraSummary> cameraSummaries = new BindingList<CameraSummary>(CameraSummaries);
|
||
dgvCamreaNums.DataSource = cameraSummaries;
|
||
|
||
}));
|
||
|
||
}
|
||
private void UpdateResult(DateTime updateTime, object objData, string result)
|
||
{
|
||
this.Invoke(new Action(() =>
|
||
{
|
||
//dgvProductNums.DataSource = null;
|
||
|
||
BindingList<ProductSummary> productSummaries = new BindingList<ProductSummary>(ProductSummaries);
|
||
|
||
dgvProductNums.DataSource = productSummaries;
|
||
|
||
//if (dgvProductNums.Rows.Count > 0)
|
||
//{
|
||
// dgvProductNums.Height = dgvProductNums.Rows[0].Height * dgvProductNums.Rows.Count + 15;
|
||
//}
|
||
//else
|
||
//{
|
||
// dgvProductNums.Height = 15;
|
||
//}
|
||
|
||
//lblOEE_Rate.Text = ProcessControl.OEE.ToString("f2") + " %";
|
||
lblUPH.Text = UPH.ToString();
|
||
}));
|
||
}
|
||
|
||
private void BtnDeleteProject_Click(object? sender, EventArgs e)
|
||
{
|
||
try
|
||
{
|
||
if (sltProjects.Items.Count == 0 || sltProjects.SelectedIndex == -1) return;
|
||
|
||
var result = AntdUI.Modal.open(this, "删除警告!", "确认要删除该方案吗?", TType.Warn);
|
||
if (result == DialogResult.OK)
|
||
{
|
||
int selectedIndex = sltProjects.SelectedIndex;
|
||
|
||
// 删除当前选中项
|
||
SchemeHelper.DeleteScheme(sltProjects.Text);
|
||
ConfigHelper.DeleteSchemeConfig(sltProjects.Text);
|
||
AntdUI.Message.success(this, $"删除方案{sltProjects.Text}成功!", autoClose: 3);
|
||
sltProjects.Items.RemoveAt(selectedIndex);
|
||
// 自动选择下一个(如果存在)
|
||
if (sltProjects.Items.Count > 0)
|
||
{
|
||
// 如果删除的不是最后一项,则选中原位置的新项,否则选中最后一项
|
||
sltProjects.SelectedIndex = selectedIndex < sltProjects.Items.Count
|
||
? selectedIndex
|
||
: sltProjects.Items.Count - 1;
|
||
|
||
SystemModel.CurrentScheme = sltProjects.Text;
|
||
SchemeHelper.SetCurrentScheme(SystemModel.CurrentScheme);
|
||
//加载当前方案配置
|
||
ConfigHelper.LoadConfig();
|
||
}
|
||
else
|
||
{
|
||
sltProjects.SelectedIndex = -1; // 清空选择
|
||
AntdUI.Modal.open(this, "空方案警告!", "当前方案全部删除,需重启程序!", TType.Warn);
|
||
}
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
AntdUI.Message.error(this, ex.Message, autoClose: 3);
|
||
}
|
||
}
|
||
|
||
private void BtnLoadProject_Click(object? sender, EventArgs e)
|
||
{
|
||
try
|
||
{
|
||
if (sltProjects.Items.Count == 0 || sltProjects.SelectedIndex == -1) return;
|
||
if (SystemModel.CurrentScheme == sltProjects.Text)
|
||
{
|
||
AntdUI.Message.warn(this, "当前已是该方案,无需重复载入!", autoClose: 3);
|
||
return;
|
||
}
|
||
//修改当前软件当前方案
|
||
SystemModel.CurrentScheme = sltProjects.Text;
|
||
//修改配置当前方案
|
||
SchemeHelper.SetCurrentScheme(SystemModel.CurrentScheme);
|
||
//将配置文件替换为当前方案
|
||
ConfigHelper.LoadConfig();
|
||
AntdUI.Message.success(this, $"载入方案{SystemModel.CurrentScheme}成功!", autoClose: 3);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
AntdUI.Message.error(this, ex.Message, autoClose: 3);
|
||
}
|
||
}
|
||
|
||
private void BtnAddProject_Click(object? sender, EventArgs e)
|
||
{
|
||
try
|
||
{
|
||
var form = new AddSchemeControl(this, "新增方案操作") { Size = new System.Drawing.Size(400, 300) };
|
||
AntdUI.Modal.open(new AntdUI.Modal.Config(this, "", form, TType.None)
|
||
{
|
||
BtnHeight = 0,
|
||
});
|
||
if (form.submit)
|
||
{
|
||
string SchemeName = form.SchemeName;
|
||
//保存到方案配置
|
||
SchemeHelper.AddScheme(SchemeName);
|
||
if (form.NullScheme)
|
||
{
|
||
//新构建配置文件
|
||
ConfigHelper.InitializeScheme(SchemeName);
|
||
}
|
||
else
|
||
{
|
||
//派生当前方案
|
||
ConfigHelper.DeriveScheme(SchemeName);
|
||
}
|
||
//刷新方案列表
|
||
sltProjects.Items.Clear();
|
||
List<string> list = SchemeHelper.GetAllSchemes();
|
||
foreach (string s in list)
|
||
{
|
||
sltProjects.Items.Add(s);
|
||
}
|
||
string CurrentScheme = SchemeHelper.GetCurrentScheme();
|
||
sltProjects.SelectedValue = CurrentScheme;
|
||
AntdUI.Message.success(this, $"新增方案{SchemeName}成功!", autoClose: 3);
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
AntdUI.Message.error(this, ex.Message, autoClose: 3);
|
||
}
|
||
}
|
||
|
||
public List<HikVisionCamera> HKCameras { get; } = new List<HikVisionCamera>();
|
||
public List<Do3ThinkCamera> Cameras { get; } = new List<Do3ThinkCamera>();
|
||
public Dictionary<string, SimboObjectDetection> Dectection { get; } = new Dictionary<string, SimboObjectDetection>();
|
||
public XinJEPLCTcpNet PLC { get; } = XinJEPLCTcpNet.Instance;
|
||
private SLDMotion sLDMotion = new SLDMotion();
|
||
|
||
private void MainWindow_Load(object sender, EventArgs e)
|
||
{
|
||
}
|
||
|
||
private bool _isClosing = false; // 状态标志
|
||
|
||
private void MainWindow_FormClosing(object sender, FormClosingEventArgs e)
|
||
{
|
||
if (_isClosing) return;
|
||
_isClosing = true;
|
||
// 取消默认关闭行为
|
||
e.Cancel = true;
|
||
|
||
// 立即隐藏主窗口
|
||
this.Hide();
|
||
|
||
// 显示关闭界面
|
||
CloseWindow.Instance.Show();
|
||
Thread.Sleep(200);
|
||
try
|
||
{
|
||
// 执行关闭操作
|
||
foreach (var camera in Cameras)
|
||
{
|
||
camera.CameraDisConnect();
|
||
}
|
||
foreach (var camera in HKCameras)
|
||
{
|
||
camera.CameraDisConnect();
|
||
}
|
||
if (PLC != null)
|
||
{
|
||
PLC.CloseProcess();
|
||
}
|
||
_visionEngine.Stop();//释放模型
|
||
CloseWindow.Instance.Close();// 关闭提示窗口
|
||
//Application.Exit();
|
||
System.Environment.Exit(0);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
CloseWindow.Instance.Close();
|
||
|
||
System.Environment.Exit(0);
|
||
}
|
||
}
|
||
|
||
private void segmented1_SelectIndexChanged(object sender, EventArgs e)
|
||
{
|
||
// Get the index of the selected item
|
||
int selectedIndex = segmented1.SelectIndex;
|
||
|
||
// Handle each button based on its index
|
||
switch (selectedIndex)
|
||
{
|
||
case 0: // "启动" (Start)
|
||
HandleStartButton();
|
||
break;
|
||
|
||
case 1: // "停止" (Stop)
|
||
HandleStopButton();
|
||
break;
|
||
|
||
case 2: // "复位" (Reset)
|
||
HandleResetButton();
|
||
break;
|
||
|
||
case 3: // "设置" (Settings)
|
||
HandleLoginButton();
|
||
break;
|
||
|
||
case 4: // "登录" (Login)
|
||
HandleSettingsButton();
|
||
break;
|
||
|
||
default:
|
||
break;
|
||
}
|
||
segmented1.SelectIndex = -1;
|
||
}
|
||
|
||
public bool CurrentMachine = false;
|
||
public volatile int ProductNum_Total = 0;
|
||
public volatile int ProductNum_OK = 0;
|
||
private readonly object _cameraSummaryLock = new object();
|
||
public SimboVisionDriver? _visionEngine = null;
|
||
|
||
public PLCBase? _PLCConfig = null;
|
||
private List<DetectionConfig> DetectionConfigs = new List<DetectionConfig>();
|
||
private List<SimboStationMLEngineSet> SimboStationMLEngineList = new List<SimboStationMLEngineSet>();
|
||
private Dictionary<string, HDevEngineTool> HalconToolDict = new Dictionary<string, HDevEngineTool>();
|
||
public List<RecongnitionLabel> RecongnitionLabelList { get; set; } = new List<RecongnitionLabel>();
|
||
public DateTime ProcessstartTime;
|
||
|
||
private void HandleStartButton()
|
||
{
|
||
LogAsync(DateTime.Now, LogLevel.Information, "流程启动中,请稍候...");
|
||
StartProcess();
|
||
LogAsync(DateTime.Now, LogLevel.Action, "流程启动完成!");
|
||
}
|
||
|
||
|
||
|
||
private void StartProcess()
|
||
{
|
||
ProcessstartTime = DateTime.Now;
|
||
lblStartTime.Text = ProcessstartTime.ToString("yyyy-MM-dd HH:mm:ss");
|
||
//计数清零
|
||
PieceCount = 0;
|
||
|
||
|
||
if (PLC?.Enable == true)
|
||
{
|
||
PLC.OnNewPieces -= MainMotion_NewPieces;
|
||
PLC.OnNewPieces += MainMotion_NewPieces;
|
||
}
|
||
|
||
Cameras.ForEach(d =>
|
||
{
|
||
if (d is CameraBase cam)
|
||
{
|
||
cam.SnapshotCount = 0;
|
||
}
|
||
});
|
||
|
||
//PrepareBatchNO();
|
||
// isInPositionChecking = false;
|
||
//isFullTrayChecking = false;
|
||
//队列清空
|
||
// var temp = new List<ITriggerSet>();
|
||
// temp.AddRange(XKRSPLCConfig.TriggerConfigCollection);
|
||
// temp.AddRange(XKRSPLCConfig.SnapshotTriggerConfigCollection);
|
||
|
||
//temp.ForEach(t =>
|
||
//{
|
||
// var diskInfo = XKRSPLCConfig.DiskInfoList.FirstOrDefault(u => u.DiskName == t.DiskName);
|
||
// if (diskInfo != null)
|
||
// {
|
||
// t.AxisNum = diskInfo.DiskAxisNum;
|
||
// }
|
||
// else
|
||
// {
|
||
// t.AxisNum = -1;
|
||
// }
|
||
//});
|
||
|
||
//if (temp.Any(u => u.AxisNum < 0))
|
||
//{
|
||
// LogAsync(DateTime.Now, LogLevel.Error, "触发信号归属转盘未确认");
|
||
// return new ProcessResponse(false);
|
||
//}
|
||
|
||
// _diskInfoListInOrder = XKRSPLCConfig.DiskInfoList.OrderBy(u => u.DiskSequence).ToList();
|
||
// var axisNumList = _diskInfoListInOrder.Select(u => u.DiskAxisNum).ToList();
|
||
|
||
/// PrepareMLEngine();
|
||
|
||
// if (_PLCConfig?.Enable == true)
|
||
//挡料电机操作
|
||
// _PLC.FeedingMotor(_PLCConfig.CunToZeroSpeed, _PLCConfig.CunPos, _PLCConfig.CunSpeed, _PLCConfig.CunDirection);
|
||
|
||
//流程开启操作配置
|
||
// ProcessInitialAction();
|
||
// if (_PLC?Enabled == true)
|
||
//皮带
|
||
// _PLC.Belt(true);
|
||
|
||
//DeviceCollection.ForEach(d =>
|
||
//{
|
||
// if (d is CameraBase c)
|
||
// {
|
||
// c.OnHImageOutput -= OnCameraHImageOutput;
|
||
// c.OnHImageOutput += OnCameraHImageOutput;
|
||
// c.SnapshotCount = 0;
|
||
// }
|
||
//});
|
||
_productLists.Clear();
|
||
|
||
#region 虚拟相机
|
||
|
||
//mOfflineImageTimer = new System.Timers.Timer();
|
||
|
||
//mOfflineImageTimer.Elapsed += OnEmitSerialPortAsync;
|
||
//mOfflineImageTimer.Interval = 1000;
|
||
//mOfflineImageTimer.Start();
|
||
|
||
#endregion 虚拟相机
|
||
|
||
var settings = _visionEngine.DetectionConfigs.Where(u => u.IsEnabled && u.IsAddStation).ToList();
|
||
if (settings != null)
|
||
{
|
||
settings = settings.Where(s => s.IsEnabled).ToList();
|
||
ProductBaseCount = settings.Count;
|
||
|
||
for (int i = 0; i < ProductBaseCount * ProductListMulti; i++)
|
||
{
|
||
ConcurrentDictionary<uint, ProductData> products = new ConcurrentDictionary<uint, ProductData>();
|
||
_productLists.Add(products);
|
||
}
|
||
}
|
||
|
||
// _MGSCameraList = DeviceCollection
|
||
//.OfType<MGSCameraDriver>() // 直接筛选出 MGSCameraDriver 类型的元素
|
||
//.Where(camera => camera.IConfig != null && camera.IConfig.IsEnabled) // 进一步筛选 IConfig 不为 null 且 IsEnabled 为 true
|
||
//.ToList();
|
||
|
||
// ProductBaseCount = _MGSCameraList.Count;
|
||
|
||
|
||
InitialOEEStatistic();
|
||
//流程执行时PLC
|
||
PLC.StartProcess();
|
||
|
||
|
||
|
||
|
||
}
|
||
|
||
|
||
private uint PieceCount = 0;
|
||
private List<ConcurrentDictionary<uint, ProductData>> _productLists = new List<ConcurrentDictionary<uint, ProductData>>();
|
||
private int ProductListMulti = 1;
|
||
private int ProductBaseCount = 0;
|
||
|
||
private int PieceNumberToIndex(uint pn)
|
||
{
|
||
// 物料编号,取余 集合数量
|
||
|
||
int ret = (int)(pn % (ProductBaseCount * ProductListMulti));
|
||
return ret;
|
||
}
|
||
|
||
private DateTime _ctTime = DateTime.Now;
|
||
|
||
public async void MainMotion_NewPieces(int axisIndex, uint pieceNumber)
|
||
{
|
||
//if (MachineState != MachineState.Running && MachineState != MachineState.Warning)
|
||
//{
|
||
// return;
|
||
//}
|
||
|
||
PieceCount++;
|
||
|
||
int index = PieceNumberToIndex(pieceNumber);
|
||
// productDatas.Add(pData);
|
||
//转盘2 的物料是不是重新覆盖之前的pDta
|
||
if (axisIndex == 1)
|
||
{
|
||
ProductData pData = new ProductData("", pieceNumber, ProductBaseCount);
|
||
_productLists[index][pieceNumber] = pData;
|
||
LogAsync(DateTime.Now, LogLevel.Action, $">> 轴{axisIndex}新产品{pieceNumber}加入队列{index}----板卡计数{PieceCount}");
|
||
|
||
}
|
||
|
||
DateTime dtNow = DateTime.Now;
|
||
UpdateCT(null, (float)(dtNow - _ctTime).TotalSeconds);
|
||
_ctTime = dtNow;
|
||
}
|
||
|
||
public async Task UpdateCT(object objData, float ctTime)
|
||
{
|
||
await Task.Run(() =>
|
||
{
|
||
//OnUpdateCT?.Invoke(objData, ctTime);
|
||
});
|
||
}
|
||
|
||
/// <summary>
|
||
/// 相机回调
|
||
/// </summary>
|
||
/// <param name="dt"></param>
|
||
/// <param name="camera"></param>
|
||
/// <param name="imageSet"></param>
|
||
private void OnCameraHImageOutput(DateTime dt, CameraBase camera, Mat imageSet)
|
||
{
|
||
//if (camera.CameraName.Equals("cam1", StringComparison.OrdinalIgnoreCase))
|
||
//{
|
||
// Console.WriteLine();
|
||
//}
|
||
//if (camera.CameraName.Equals("cam2", StringComparison.OrdinalIgnoreCase))
|
||
//{
|
||
// Console.WriteLine();
|
||
//}
|
||
|
||
// 获取该相机的拍照计数
|
||
uint productNumber = (uint)camera.SnapshotCount;
|
||
|
||
Task.Run(async () =>
|
||
{
|
||
using (Mat localImageSet = imageSet.Clone()) // 复制 Mat 避免并发问题
|
||
{
|
||
// imageSet?.Dispose();
|
||
// 拍照计数与物件编号一致,查找对应的产品
|
||
ProductData product = null;
|
||
//内外壁模组多个相机的处理方法
|
||
//计算队列的方法不变
|
||
int index = PieceNumberToIndex(productNumber);
|
||
// 找到产品存放在哪个队列里
|
||
ConcurrentDictionary<uint, ProductData> tmpDic = _productLists[index];
|
||
|
||
try
|
||
{
|
||
int retryTimes = 100;
|
||
while (product == null && retryTimes > 0)
|
||
{
|
||
if (tmpDic.ContainsKey(productNumber))
|
||
{
|
||
product = tmpDic[productNumber];
|
||
}
|
||
else
|
||
{
|
||
Thread.Sleep(20);
|
||
//await Task.Delay(20);
|
||
}
|
||
retryTimes--;
|
||
}
|
||
// 如果产品为空,则销毁图片,提示错误
|
||
if (null == product)
|
||
{
|
||
List<uint> pnList = tmpDic.Keys.ToList();
|
||
|
||
string pnStr = "";
|
||
if (pnList != null && pnList.Count > 0)
|
||
{
|
||
pnStr = string.Join(",", pnList);
|
||
}
|
||
|
||
//LogAsync(DateTime.Now, LogLevel.Error, $"{camera.Name} 未找到产品,编号:{productNumber},队列{index}数量:{tmpDic.Count},列表:{pnStr}");
|
||
localImageSet.Dispose();
|
||
|
||
return;
|
||
}
|
||
|
||
// LogAsync(DateTime.Now, LogLevel.Information, $"{camera.Name} 找到产品{productNumber},队列{index}数量:{tmpDic.Count}");
|
||
|
||
if (!_cameraRelatedDetectionDict.ContainsKey(camera.CameraName))
|
||
{
|
||
localImageSet.Dispose();
|
||
|
||
|
||
|
||
LogAsync(DateTime.Now, LogLevel.Warning, $"{camera.CameraName} 找到产品{productNumber},但是没有推理1");
|
||
|
||
return;
|
||
}
|
||
|
||
double totalTime = 0.0;
|
||
List<ResultState> resultStates = new List<ResultState>();
|
||
List<string>? detectionDict = _cameraRelatedDetectionDict[camera.CameraName];
|
||
Stopwatch stopwatch = new Stopwatch();
|
||
stopwatch.Start();
|
||
for (int i = 0; i < detectionDict.Count; i++)
|
||
{
|
||
string detectionId = detectionDict[i];
|
||
|
||
|
||
using (Mat inferenceImage = localImageSet.Clone()) // 仅在此处克隆,确保推理过程中 Mat 有独立副本
|
||
{
|
||
DetectStationResult temp1 = _visionEngine.RunInference(inferenceImage, detectionId);
|
||
|
||
resultStates.Add(temp1.ResultState);
|
||
|
||
product.ResultCollection.Add(temp1);
|
||
}
|
||
}
|
||
stopwatch.Stop();
|
||
if (product.ResultCollection.Count != 0)
|
||
UpdateResultoverride(dt, camera, resultStates, totalTime, _cameraRelatedDetectionDict.Keys.Count);
|
||
|
||
product.InferenceOne();
|
||
|
||
// LogAsync(DateTime.Now, LogLevel.Information, $"{camera.Name} 推理完成,产品{productNumber}");
|
||
|
||
if (!product.InferenceFinished())
|
||
{
|
||
return;
|
||
}
|
||
UpdateResultPro(DateTime.Now, null, product.ProductResult.GetEnumDescription());
|
||
|
||
|
||
#region 6. 统计产品结果
|
||
|
||
product.ProductResult = product.ResultCollection.Any(u => u.ResultState != ResultState.OK)
|
||
? ResultState.B_NG
|
||
: ResultState.OK;
|
||
//if (product.ProductResult == ResultState.OK)
|
||
//{
|
||
// PLC.Blowing(productNumber, 1);
|
||
//}
|
||
//else
|
||
//{
|
||
// PLC.Blowing(productNumber, 2);
|
||
//}
|
||
product.ProductLabelCategory = product.ProductResult.GetEnumDescription();
|
||
product.ProductLabel = product.ProductResult.GetEnumDescription();
|
||
|
||
#endregion 6. 统计产品结果
|
||
|
||
// 出列
|
||
ProductData temp = null;
|
||
|
||
int tryTimes = 10;
|
||
while (temp == null && tryTimes > 0)
|
||
{
|
||
if (tmpDic.TryRemove(productNumber, out temp))
|
||
{
|
||
break;
|
||
}
|
||
|
||
tryTimes--;
|
||
Thread.Sleep(5);
|
||
}
|
||
if (temp == null)
|
||
{
|
||
string logStr = $"{DateTime.Now}产品{productNumber}出列失败:true," +
|
||
$"当前队列产品数量:{tmpDic.Count}";
|
||
this.BeginInvoke(new MethodInvoker(delegate ()
|
||
{
|
||
// int currentScrollPosition = richTextBox1.GetPositionFromCharIndex(richTextBox1.TextLength).Y;
|
||
|
||
// richTextBox1.AppendText(logStr);
|
||
|
||
// 设置回原来的滚动位置
|
||
// richTextBox1.SelectionStart = richTextBox1.TextLength;
|
||
//richTextBox1.ScrollToCaret();
|
||
}));
|
||
}
|
||
else
|
||
{
|
||
try
|
||
{
|
||
string logStr = $"{DateTime.Now}产品{productNumber}出列成功:true," +
|
||
$"产品结果:{temp.ProductResult.GetEnumDescription()}," +
|
||
$"当前队列产品数量:{tmpDic.Count}";
|
||
this.BeginInvoke(new MethodInvoker(delegate ()
|
||
{
|
||
//int currentScrollPosition = richTextBox1.GetPositionFromCharIndex(richTextBox1.TextLength).Y;
|
||
|
||
// richTextBox1.AppendText(logStr);
|
||
|
||
// 设置回原来的滚动位置
|
||
// richTextBox1.SelectionStart = richTextBox1.TextLength;
|
||
//richTextBox1.ScrollToCaret();
|
||
}));
|
||
//重新生成实例 销毁之前的实例
|
||
var saveData = temp.GetProductData();
|
||
using (StreamWriter sw = new StreamWriter("D://123log.txt", true, Encoding.UTF8))
|
||
{
|
||
sw.WriteLine(logStr);
|
||
}
|
||
}
|
||
catch (Exception) { }
|
||
finally
|
||
{
|
||
// temp.Dispose();
|
||
temp = null;
|
||
}
|
||
}
|
||
|
||
// UpdateCT((float)(dtNow - _ctTime).TotalSeconds);
|
||
//_ctTime = dtNow;
|
||
// });
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
//LogAsync(DateTime.Now, LogLevel.Error, $"流程检测未捕获的异常:{ex.GetExceptionMessage()}");
|
||
product?.Dispose();
|
||
}
|
||
}
|
||
});
|
||
}
|
||
public virtual void AddOKProduct(string resultStr)
|
||
{
|
||
if (resultStr.ToLower() == "ok")
|
||
{
|
||
ProductNum_OK++;
|
||
}
|
||
}
|
||
public async Task UpdateResultoverride(DateTime dt, CameraBase objData, List<ResultState> resultStr, double total, int _cameraDictCount)
|
||
{
|
||
// CurrentState = RunState.Running;
|
||
|
||
|
||
|
||
// 根据相机名称找到对应的信息(假设有一个字典或其他集合保存相机相关信息)
|
||
var cameraName = objData?.CameraName; // 假设 CameraBase 有 Name 属性
|
||
if (string.IsNullOrEmpty(cameraName))
|
||
{
|
||
throw new ArgumentException("相机名称不能为空");
|
||
}
|
||
|
||
|
||
|
||
lock (_cameraSummaryLock)
|
||
{
|
||
// 查找或添加相机统计项
|
||
var summary = CameraSummaries.FirstOrDefault(c => c.CameraName == cameraName)
|
||
?? new CameraSummary { CameraName = cameraName };
|
||
|
||
if (!CameraSummaries.Contains(summary))
|
||
{
|
||
CameraSummaries.Add(summary);
|
||
}
|
||
|
||
if (resultStr.Any(u => u.ToString().ToLower() == "ok"))
|
||
{
|
||
summary.OKCount++;
|
||
}
|
||
|
||
else /*if (resultStr.Equals("TBD", StringComparison.OrdinalIgnoreCase))*/
|
||
{
|
||
summary.NGCount++;
|
||
}
|
||
|
||
}
|
||
|
||
await Task.Run(() =>
|
||
{
|
||
OnUpdateCamResult?.Invoke(dt, objData, "");
|
||
});
|
||
}
|
||
|
||
public async Task UpdateResultPro(DateTime dt, object objData, string resultStr)
|
||
{
|
||
CurrentState = RunState.Running;
|
||
|
||
ProductNum_Total++;
|
||
AddOKProduct(resultStr);
|
||
|
||
|
||
|
||
lock (_productSummaryLock)
|
||
{
|
||
var product = ProductSummaries.FirstOrDefault(u => u.ResultDesc == resultStr);
|
||
if (product != null)
|
||
{
|
||
product.ProductAmount++;
|
||
}
|
||
else
|
||
{
|
||
product = new ProductSummary();
|
||
product.ResultDesc = resultStr;
|
||
product.ProductAmount = 1;
|
||
|
||
ProductSummaries.Add(product);
|
||
}
|
||
|
||
int totalNum = ProductSummaries.Sum(p => p.ProductAmount);
|
||
ProductSummaries.ForEach(p => p.PercentStr = ((double)p.ProductAmount * 100.0 / totalNum).ToString("f2") + " %");
|
||
}
|
||
|
||
CalculateOEE();
|
||
|
||
await Task.Run(() =>
|
||
{
|
||
OnUpdateResult?.Invoke(dt, objData, resultStr);
|
||
});
|
||
lock (_cameraSummaryLock)
|
||
{
|
||
// 查找或添加相机统计项
|
||
var summary = CameraSummaries.FirstOrDefault(c => c.CameraName == "合计")
|
||
?? new CameraSummary { CameraName = "合计" };
|
||
|
||
summary.OKCount = ProductNum_OK;
|
||
summary.NGCount = ProductNum_Total - ProductNum_OK;
|
||
if (!CameraSummaries.Contains(summary))
|
||
{
|
||
CameraSummaries.Add(summary);
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
}
|
||
await Task.Run(() =>
|
||
{
|
||
OnUpdateCamResult?.Invoke(dt, objData, "合计");
|
||
});
|
||
|
||
|
||
}
|
||
|
||
private void HandleStopButton()
|
||
{
|
||
// Cameras.Clear();
|
||
// Dectection.Clear();
|
||
// Add the code for the "停止" button click here
|
||
PLC.TurnStart(false);
|
||
CurrentMachine = true;
|
||
//sLDMotion.Stop();
|
||
}
|
||
|
||
|
||
|
||
public void CalculateOEE()
|
||
{
|
||
if (TotalTime.TotalHours == 0)
|
||
{
|
||
UPH = 0;
|
||
UPM = 0;
|
||
}
|
||
else
|
||
{
|
||
UPH = (int)(ProductNum_Total / RunTime.TotalHours) + 100;
|
||
UPM = (int)UPH / 60;
|
||
}
|
||
|
||
|
||
//TimeSpan timeSpan = DateTime.Now - ProcessstartTime;
|
||
|
||
//UPH = (int)(ProductNum_Total / timeSpan.TotalHours) + 100;
|
||
////UPM = (int)UPH / 60;
|
||
//this.BeginInvoke(new MethodInvoker(delegate ()
|
||
//{
|
||
// lblNowtime.Text = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
|
||
// lblUPH.Text = UPH.ToString();
|
||
// lblNum.Text = ProductNum_Total.ToString();
|
||
|
||
//}));
|
||
}
|
||
|
||
private void HandleResetButton()
|
||
{
|
||
// Add the code for the "复位" button click here
|
||
MessageBox.Show("复位按钮按下");
|
||
}
|
||
|
||
private void HandleSettingsButton()
|
||
{
|
||
// Add the code for the "设置" button click here
|
||
|
||
SettingWindow.Instance.Show();
|
||
}
|
||
|
||
private void HandleLoginButton()
|
||
{
|
||
// Add the code for the "登录" button click here
|
||
LoginWindow.Instance.Owner = this;
|
||
LoginWindow.Instance.Show();
|
||
}
|
||
|
||
private void splitter1_SplitterMoved(object sender, SplitterEventArgs e)
|
||
{
|
||
}
|
||
|
||
private void richTextBox1_TextChanged(object sender, EventArgs e)
|
||
{
|
||
|
||
}
|
||
|
||
private void splitContainer2_Panel1_Paint(object sender, PaintEventArgs e)
|
||
{
|
||
|
||
}
|
||
}
|
||
} |