2305 lines
101 KiB
C#
2305 lines
101 KiB
C#
#define Online
|
||
using BarTenderPrint;
|
||
using CCWin.Win32.Const;
|
||
using GeBoShi.ImageDefect;
|
||
using HalconDotNet;
|
||
using HZH_Controls.Forms;
|
||
using MaiMuControl.Device;
|
||
using MaiMuControl.Device.CamDev;
|
||
using MaiMuControl.Device.IOCardDev;
|
||
using MaiMuControl.Device.IOCardDev.Advantech;
|
||
using MaiMuControl.Device.LightDev;
|
||
using MaiMuControl.Device.LightDev.CST;
|
||
using MaiMuControl.Device.LightDev.Rsee;
|
||
using MaiMuControl.Device.PlcDev;
|
||
using MaiMuControl.SysStatusMgr.CloudMgr;
|
||
using MaiMuControl.SysStatusMgr.StatusMgr;
|
||
using MaiMuControl.SysStatusMgr.UserMgr;
|
||
using MaiMuControl.Utils;
|
||
using Models;
|
||
using Newtonsoft.Json;
|
||
using Newtonsoft.Json.Linq;
|
||
using OpenCvSharp;
|
||
using OpenCvSharp.Extensions;
|
||
using S7.Net;
|
||
using SqlSugar;
|
||
using System;
|
||
using System.Collections;
|
||
using System.Collections.Generic;
|
||
using System.Data;
|
||
using System.Diagnostics;
|
||
using System.Drawing;
|
||
using System.Drawing.Imaging;
|
||
using System.IO;
|
||
using System.Linq;
|
||
using System.Threading;
|
||
using System.Threading.Tasks;
|
||
using System.Windows.Forms;
|
||
using System.Windows.Forms.DataVisualization.Charting;
|
||
using ToolKits.Disk;
|
||
|
||
namespace GeBoShi.SysCtrl
|
||
{
|
||
/// <summary>
|
||
/// 主系统控制
|
||
/// </summary>
|
||
public class SysMgr
|
||
{
|
||
#region singleton实例化
|
||
private static SysMgr _instance;
|
||
private static readonly object _lock = new object();
|
||
public static SysMgr Instance
|
||
{
|
||
get
|
||
{
|
||
if (_instance == null)
|
||
{
|
||
lock (_lock)
|
||
{
|
||
if (_instance == null)
|
||
{
|
||
_instance = new SysMgr();
|
||
}
|
||
}
|
||
}
|
||
return _instance;
|
||
}
|
||
}
|
||
#endregion
|
||
|
||
#region 私有
|
||
//系统状态
|
||
private StatusMgr statusMgr;
|
||
public StatusMgr StatusMgr { get { return statusMgr; } }
|
||
//用户管理
|
||
private UserMgr userMgr;
|
||
public UserMgr UserMgr { get { return userMgr; } }
|
||
|
||
//系统配置管理
|
||
private ConfMgr confMgr;
|
||
|
||
//图像处理
|
||
private DefectLib defectLib;
|
||
public DefectLib DefectLib { get { return defectLib; } }
|
||
|
||
//产品检测列表
|
||
private List<string> productCodeList = new List<string>();
|
||
public List<string> ProductCodeList { get { return productCodeList; } }
|
||
|
||
//产品ID列表
|
||
private List<int> productIdList = new List<int>();
|
||
public List<int> ProductIdList { get { return productIdList; } }
|
||
|
||
/// <summary>
|
||
/// 当前产品
|
||
/// </summary>
|
||
private Models.Product CurrProductModel = null;
|
||
|
||
//数据锁
|
||
private object lockCurrKey = new object();
|
||
//当前运行数据key
|
||
private int currKey = 0;
|
||
//线程管控
|
||
private Hashtable htTask = new Hashtable();//默认单线程写入不用lock, 多线程安全同步读取用Synchronized
|
||
|
||
//是否处理完成
|
||
private bool _isDefect = false;
|
||
//计算速度用,暂停时停止计数
|
||
private Stopwatch pStopWatch = new Stopwatch();
|
||
|
||
//图片队列
|
||
private int listCntMax = 5;
|
||
private int Cam1Cnt = 0;
|
||
private int Cam2Cnt = 0;
|
||
#region 处理类型
|
||
private class ScanPhotoInfo
|
||
{
|
||
/// <summary>
|
||
///
|
||
/// </summary>
|
||
/// <param name="_devIndex"></param>
|
||
/// <param name="_photoIndex">1-n 第1张会把1改为0</param>
|
||
/// <param name="_path"></param>
|
||
public ScanPhotoInfo(int _devIndex, int _photoIndex, string _path)
|
||
{
|
||
devIndex = _devIndex;
|
||
photoIndex = _photoIndex;
|
||
path = _path;
|
||
}
|
||
public ScanPhotoInfo(int _devIndex, int _photoIndex, Mat _mat)
|
||
{
|
||
devIndex = _devIndex;
|
||
photoIndex = _photoIndex;
|
||
mat = _mat;
|
||
}
|
||
public int devIndex { get; set; }
|
||
/// <summary>
|
||
/// 0-n
|
||
/// </summary>
|
||
public int photoIndex { get; set; }
|
||
public string path { get; set; }
|
||
public Mat mat { get; set; }
|
||
|
||
}
|
||
#endregion
|
||
private Queue<ScanPhotoInfo> _matList1 = new Queue<ScanPhotoInfo>();
|
||
private Queue<ScanPhotoInfo> _matList2 = new Queue<ScanPhotoInfo>();
|
||
|
||
private Service.ProductService PdtService = new Service.ProductService();
|
||
private Service.RecordsService RecordService = new Service.RecordsService();
|
||
#endregion
|
||
|
||
#region 公开字段
|
||
private bool _isInit;
|
||
/// <summary>
|
||
/// 是否初始化完成
|
||
/// </summary>
|
||
public bool IsInit { get { return _isInit; } }
|
||
private bool _isRuning;
|
||
/// <summary>
|
||
/// 设备正在运行
|
||
/// </summary>
|
||
public bool IsRuning { get { return _isRuning; } }
|
||
|
||
private bool _isAuto;
|
||
/// <summary>
|
||
/// 设备正在自动化流程中
|
||
/// </summary>
|
||
public bool IsAuto { get { return _isAuto; } }
|
||
#endregion
|
||
|
||
#region 私有流程
|
||
//主流程
|
||
private Thread _mainThread;
|
||
private Thread _Cam1Thread;
|
||
private Thread _Cam2Thread;
|
||
private CancellationTokenSource _cts;
|
||
#endregion
|
||
|
||
#region 云端
|
||
//局域网云端
|
||
private bool init_Cloud;
|
||
private CloudMgr cloudMgr;
|
||
private int DailyOutput;
|
||
#endregion
|
||
private SysMgr()
|
||
{
|
||
_isInit = false;
|
||
_isRuning = false;
|
||
_isAuto = false;
|
||
|
||
statusMgr = StatusMgr.Instance;
|
||
confMgr = ConfMgr.Instance;
|
||
|
||
userMgr = new UserMgr(statusMgr.MySqlIP);
|
||
|
||
_cts = new CancellationTokenSource();
|
||
|
||
init_Cloud = false;
|
||
cloudMgr = new CloudMgr();
|
||
DailyOutput = 0;
|
||
|
||
Service.InitDB.ConnectionString = confMgr.DBConStr;
|
||
PdtService = new Service.ProductService();
|
||
RecordService = new Service.RecordsService();
|
||
}
|
||
|
||
#region 本地云上传
|
||
/// <summary>
|
||
/// 上传当日产量
|
||
/// </summary>
|
||
private void SendDailyOutput()
|
||
{
|
||
//开启云端
|
||
if (init_Cloud)
|
||
{
|
||
try
|
||
{
|
||
if (!cloudMgr.SendTopic("device/attributes", $"{{ \"DailyOutput\": \"{DailyOutput}\"}}"))
|
||
Log("云端", $"上传失败", WarningEnum.Low);
|
||
}
|
||
catch (Exception e)
|
||
{
|
||
Log("云端", $"上传失败:{e.Message}", WarningEnum.Low);
|
||
}
|
||
}
|
||
}
|
||
/// <summary>
|
||
/// 上传正常状态
|
||
/// </summary>
|
||
public void SendStatus()
|
||
{
|
||
//开启云端
|
||
if (init_Cloud)
|
||
{
|
||
//上传报警状态和信息
|
||
string statusStr = "正常";
|
||
switch (StatusMgr.Status)
|
||
{
|
||
case SystemStsEnum.Manual:
|
||
statusStr = "人工操作";
|
||
break;
|
||
case SystemStsEnum.Standby:
|
||
statusStr = "正常待机";
|
||
break;
|
||
case SystemStsEnum.Initial:
|
||
statusStr = "初始化";
|
||
break;
|
||
case SystemStsEnum.Auto:
|
||
statusStr = "自动运行";
|
||
break;
|
||
case SystemStsEnum.Pause:
|
||
statusStr = "自动暂停";
|
||
break;
|
||
case SystemStsEnum.SetParams:
|
||
statusStr = "参数设置";
|
||
break;
|
||
case SystemStsEnum.Debug:
|
||
statusStr = "调试";
|
||
break;
|
||
case SystemStsEnum.Warning:
|
||
statusStr = "系统报警";
|
||
break;
|
||
case SystemStsEnum.Bootload:
|
||
statusStr = "Bootload";
|
||
break;
|
||
default:
|
||
statusStr = "未知";
|
||
break;
|
||
}
|
||
try
|
||
{
|
||
if (!cloudMgr.SendTopic("device/attributes", $"{{\"status\": \"{statusStr}\", \"alm\": \"无报警信息\", " +
|
||
$"\"name\": \"{confMgr.SysConfigParams.CloudThisName}\", \"DailyOutput\": \"{DailyOutput}\"}}"))
|
||
Log("云端", $"上传失败", WarningEnum.Low);
|
||
}
|
||
catch (Exception e)
|
||
{
|
||
Log("云端", $"上传失败:{e.Message}", WarningEnum.Low);
|
||
}
|
||
}
|
||
}
|
||
#endregion
|
||
|
||
#region 用户+登入+管理
|
||
/// <summary>
|
||
/// 登入
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
public bool LoginSystem()
|
||
{
|
||
return userMgr.UserLoginDialog();
|
||
}
|
||
/// <summary>
|
||
/// 用户权限
|
||
/// </summary>
|
||
public void UserPermissiomMgr()
|
||
{
|
||
userMgr.RightManageDialog();
|
||
}
|
||
/// <summary>
|
||
/// 用户管理
|
||
/// </summary>
|
||
public void UserListMgr()
|
||
{
|
||
userMgr.UserManagerDialog();
|
||
}
|
||
#endregion
|
||
|
||
#region 系统初始化&&运行
|
||
/// <summary>
|
||
/// 系统初始化
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
public bool Initial()
|
||
{
|
||
try
|
||
{
|
||
bool ret = false;
|
||
string err = "";
|
||
InitLog("系统开始初始化...");
|
||
//Thread.Sleep(200);
|
||
|
||
// 加载系统配置
|
||
InitLog("加载系统参数...");
|
||
ret = confMgr.LoadSystemConfig();
|
||
|
||
if (!ret)
|
||
{
|
||
throw new Exception("系统参数加载失败...");
|
||
}
|
||
InitLog("系统参数加载完成!");
|
||
//根据llog路径,开始记录日志
|
||
statusMgr.StartLog(confMgr.SysConfigParams.LogPath);
|
||
statusMgr.GotoInitial();
|
||
SendStatus();
|
||
//Thread.Sleep(200);
|
||
|
||
|
||
// 硬件初始化
|
||
if (!InitAllDev())
|
||
{
|
||
throw new Exception("硬件初始化失败...");
|
||
}
|
||
InitLog("硬件初始化完成!");
|
||
|
||
// 加载硬件配置
|
||
InitLog("加载硬件驱动参数...");
|
||
if (!LoadDevConfig())
|
||
{
|
||
throw new Exception("加载硬件驱动参数失败...");
|
||
}
|
||
InitLog("加载硬件驱动参数完成!");
|
||
//Thread.Sleep(200);
|
||
// 处理运行
|
||
InitLog("AI算法核心初始化...");
|
||
defectLib = new DefectLib();
|
||
if (!defectLib.start())
|
||
throw new Exception("外观检测核心初始化失败...");
|
||
InitLog("AI算法核心初始化完成!");
|
||
|
||
LedReady();
|
||
|
||
//初始化成功
|
||
_isInit = true;
|
||
statusMgr.GotoNormalStandby();
|
||
SendStatus();
|
||
|
||
OnInitRuning(new InitEventArgs("系统初始化完成...", this.IsInit));
|
||
|
||
Run();
|
||
|
||
return ret;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
InitLog(ex.Message, "初始化", WarningEnum.High);
|
||
InitLog("系统初始化失败!", "初始化", WarningEnum.High);
|
||
//statusMgr.GotoWarning(MaiMuControl.Device.WarningEnum.High, "初始化", ex.Message);
|
||
return false;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 初始化图像处理报警
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
public bool InitDefectEvent()
|
||
{
|
||
if (defectLib != null)
|
||
{
|
||
defectLib.WarningEvent = (warning, msg) =>
|
||
{
|
||
Log("缺陷检测", msg, warning);
|
||
};
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
public bool InitCloudConnect()
|
||
{
|
||
if (confMgr.SysConfigParams.OpenCloud)
|
||
{
|
||
if (cloudMgr.ConnectCloud(confMgr.SysConfigParams.CloudServerIP, confMgr.SysConfigParams.CloudServerPort,
|
||
confMgr.SysConfigParams.CloudUser, confMgr.SysConfigParams.CloudPassword))
|
||
{
|
||
init_Cloud = true;
|
||
Log("云端数据", "开启云端连接");
|
||
return true;
|
||
}
|
||
Log("云端数据", "云端连接失败!", WarningEnum.Low);
|
||
return false;
|
||
}
|
||
return true;
|
||
}
|
||
/// <summary>
|
||
/// 运行主线程
|
||
/// </summary>
|
||
private void Run()
|
||
{
|
||
_mainThread = new Thread(() =>
|
||
{
|
||
MainThreadFunction();
|
||
});
|
||
_mainThread.IsBackground = true;
|
||
_mainThread.Start();
|
||
|
||
_Cam1Thread = new Thread(() =>
|
||
{
|
||
Cam1ThreadFunction();
|
||
});
|
||
_Cam1Thread.IsBackground = true;
|
||
_Cam1Thread.Start();
|
||
|
||
_Cam2Thread = new Thread(() =>
|
||
{
|
||
Cam2ThreadFunction();
|
||
});
|
||
_Cam2Thread.IsBackground = true;
|
||
_Cam2Thread.Start();
|
||
}
|
||
#endregion
|
||
|
||
#region 后台
|
||
/// <summary>
|
||
/// 中断工序运行
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
private bool isBreakProcessRun()
|
||
{
|
||
return statusMgr.Status == SystemStsEnum.Pause || statusMgr.Warning == WarningEnum.High;
|
||
}
|
||
/// <summary>
|
||
/// 相机1采图预处理
|
||
/// </summary>
|
||
private void Cam1ThreadFunction()
|
||
{
|
||
while (true)
|
||
{
|
||
try
|
||
{
|
||
if (_cts.IsCancellationRequested)
|
||
break;
|
||
|
||
if (IsRuning)
|
||
{
|
||
////暂停开始
|
||
//stopWatch.Start();
|
||
do
|
||
{
|
||
#region 实时采图
|
||
#if Online
|
||
//采集图片
|
||
Acquisition acq = _LinecamDev1.GetFrames(1, 10);
|
||
if (acq.GrabStatus == "GrabPass")
|
||
{
|
||
//显示
|
||
OnAutoRuning(new RunEventArgs(1, acq.Image));
|
||
lock (lockCurrKey)
|
||
{
|
||
//存在数据队列
|
||
if (currKey != 0 || htTask.ContainsKey(currKey))
|
||
{
|
||
Mat img = CamDev.HImageToMat(acq.Image.CopyObj(1, -1));
|
||
if (_matList1.Count > listCntMax)
|
||
{
|
||
_matList1.Dequeue();
|
||
System.GC.Collect();
|
||
}
|
||
//预处理
|
||
Stopwatch stopWatch = new Stopwatch();
|
||
Log($"图像预处理", $"相机1-{Cam1Cnt}");
|
||
string time = "";
|
||
stopWatch.Start();
|
||
int errStep = 0;
|
||
Mat mat = img;
|
||
try
|
||
{
|
||
errStep = 1;
|
||
|
||
//反转+相机索引调换
|
||
|
||
//裁边,两侧和中间重合部分
|
||
if (confMgr.SysConfigParams.MidCoin > 0)//中间重合部分
|
||
{
|
||
errStep = 3;
|
||
int width = mat.Width - confMgr.SysConfigParams.MidCoin / 2;
|
||
mat = OpencvUtils.CutImage(mat, 0, 0, width, mat.Height);
|
||
time += $"->相机1-去重({stopWatch.ElapsedMilliseconds})";
|
||
}
|
||
Log($"裁边", $"(相机1-图像{Cam1Cnt})-左图去重后:{mat.Width}*{mat.Height}," + $"重复值:{confMgr.SysConfigParams.MidCoin / 2}");
|
||
errStep = 4;
|
||
//左裁边
|
||
int marginWidth0;
|
||
mat = OpencvUtils.getMaxInsetRect2(mat, true, confMgr.SysConfigParams.HolePx, out marginWidth0);
|
||
errStep = 5;
|
||
time += $"->相机1裁边({stopWatch.ElapsedMilliseconds})";
|
||
}
|
||
catch (Exception e)
|
||
{
|
||
Log($"图像处理", $"异常({errStep}):(相机1-图像{Cam1Cnt})-{e.Message}", WarningEnum.High);
|
||
}
|
||
//Cv2.Flip(img, img, FlipMode.XY);//翻转
|
||
_matList1.Enqueue(new ScanPhotoInfo(0, Cam1Cnt++, mat.Clone()));
|
||
}
|
||
else
|
||
Log($"相机1", $"(图像)-未扫码,图像丢弃!", WarningEnum.Low);
|
||
}
|
||
|
||
}
|
||
#endif
|
||
#endregion
|
||
Thread.Sleep(50);
|
||
} while (!isBreakProcessRun());
|
||
//暂停中断
|
||
//stopWatch.Stop();
|
||
pStopWatch.Stop();
|
||
//_isRuning = false;
|
||
}
|
||
Thread.Sleep(10);
|
||
}
|
||
catch (Exception e)
|
||
{
|
||
_isRuning = false;
|
||
|
||
Log("运行报警", "相机1流程运行出错:" + e.Message + "\n", WarningEnum.High);
|
||
}
|
||
}
|
||
}
|
||
/// <summary>
|
||
/// 相机2采图预处理
|
||
/// </summary>
|
||
private void Cam2ThreadFunction()
|
||
{
|
||
while (true)
|
||
{
|
||
try
|
||
{
|
||
if (_cts.IsCancellationRequested)
|
||
break;
|
||
|
||
if (IsRuning)
|
||
{
|
||
////暂停开始
|
||
//stopWatch.Start();
|
||
do
|
||
{
|
||
#region 实时采图
|
||
#if Online
|
||
//采集图片
|
||
Acquisition acq = _LinecamDev2.GetFrames(1, 10);
|
||
if (acq.GrabStatus == "GrabPass")
|
||
{
|
||
//显示
|
||
OnAutoRuning(new RunEventArgs(2, acq.Image));
|
||
lock (lockCurrKey)
|
||
{
|
||
//存在数据队列
|
||
if (currKey != 0 || htTask.ContainsKey(currKey))
|
||
{
|
||
Mat img = CamDev.HImageToMat(acq.Image.CopyObj(1, -1));
|
||
if (_matList2.Count > listCntMax)
|
||
{
|
||
_matList2.Dequeue();
|
||
System.GC.Collect();
|
||
}
|
||
//预处理
|
||
Stopwatch stopWatch = new Stopwatch();
|
||
Log($"图像预处理", $"相机2-{Cam2Cnt}");
|
||
string time = "";
|
||
stopWatch.Start();
|
||
int errStep = 0;
|
||
Mat mat = img;
|
||
try
|
||
{
|
||
errStep = 1;
|
||
|
||
//反转+相机索引调换
|
||
|
||
//裁边,两侧和中间重合部分
|
||
if (confMgr.SysConfigParams.MidCoin > 0)//中间重合部分
|
||
{
|
||
errStep = 3;
|
||
int width = mat.Width - confMgr.SysConfigParams.MidCoin / 2;
|
||
mat = OpencvUtils.CutImage(mat, confMgr.SysConfigParams.MidCoin / 2, 0, width, mat.Height);
|
||
time += $"->相机2-去重({stopWatch.ElapsedMilliseconds})";
|
||
}
|
||
Log($"裁边", $"(相机2-图像{Cam2Cnt})-右图去重后:{mat.Width}*{mat.Height}," + $"重复值:{confMgr.SysConfigParams.MidCoin / 2}");
|
||
errStep = 4;
|
||
//右裁边
|
||
int marginWidth0;
|
||
mat = OpencvUtils.getMaxInsetRect2(mat, false, confMgr.SysConfigParams.HolePx, out marginWidth0);
|
||
errStep = 5;
|
||
time += $"->相机2裁边({stopWatch.ElapsedMilliseconds})";
|
||
}
|
||
catch (Exception e)
|
||
{
|
||
Log($"图像处理", $"异常({errStep}):(相机2-图像{Cam2Cnt})-{e.Message}", WarningEnum.High);
|
||
}
|
||
//Cv2.Flip(img, img, FlipMode.XY);//翻转
|
||
_matList2.Enqueue(new ScanPhotoInfo(1, Cam2Cnt++, mat.Clone()));
|
||
}
|
||
else
|
||
Log($"相机2", $"(图像)-未扫码,图像丢弃!", WarningEnum.Low);
|
||
}
|
||
|
||
}
|
||
#endif
|
||
#endregion
|
||
Thread.Sleep(50);
|
||
} while (!isBreakProcessRun());
|
||
//暂停中断
|
||
//stopWatch.Stop();
|
||
pStopWatch.Stop();
|
||
//_isRuning = false;
|
||
}
|
||
Thread.Sleep(10);
|
||
}
|
||
catch (Exception e)
|
||
{
|
||
_isRuning = false;
|
||
|
||
Log("运行报警", "相机1流程运行出错:" + e.Message + "\n", WarningEnum.High);
|
||
}
|
||
}
|
||
}
|
||
/// <summary>
|
||
/// 后台运行主线程
|
||
/// </summary>
|
||
private void MainThreadFunction()
|
||
{
|
||
while (true)
|
||
{
|
||
try
|
||
{
|
||
if (_cts.IsCancellationRequested)
|
||
break;
|
||
|
||
if (IsRuning)
|
||
{
|
||
////暂停开始
|
||
//stopWatch.Start();
|
||
do
|
||
{
|
||
#region 长度剩余提醒
|
||
//长度剩余提醒
|
||
Records curRecord = Hashtable.Synchronized(htTask)[currKey] as Records;
|
||
if (CurrProductModel.residueWarnningLen > 0 && curRecord.ErpLen > 0 && CurrProductModel.residueWarnningLen >= curRecord.ErpLen - curRecord.Len)
|
||
{
|
||
Log($"长度告警", $"已达剩余长度不足提醒!({curRecord.ErpLen - curRecord.Len}<={CurrProductModel.residueWarnningLen})", WarningEnum.Low);
|
||
}
|
||
#endregion
|
||
|
||
#region 处理2次判定
|
||
//处理2次判定
|
||
#endregion
|
||
|
||
#region 图像裁边预处理
|
||
//预处理,队列都有数据,且数据长度一致
|
||
#if Online
|
||
if (_matList1.Count > 0 && _matList2.Count > 0 && (_matList1.Count == _matList2.Count))
|
||
{
|
||
Stopwatch stopWatch = new Stopwatch();
|
||
ScanPhotoInfo scanPhotos0 = _matList1.Dequeue();
|
||
ScanPhotoInfo scanPhotos1 = _matList2.Dequeue();
|
||
Log($"图像拼接处理", $"相机1-{scanPhotos0.photoIndex},相机2-{scanPhotos1.photoIndex}");
|
||
string time = "";
|
||
stopWatch.Start();
|
||
int errStep = 0;
|
||
try
|
||
{
|
||
if (scanPhotos0.mat.Height != scanPhotos1.mat.Height)
|
||
{
|
||
Log($"警告", $"两相机采集图高度不一致({scanPhotos0.photoIndex}),dev1.Height={scanPhotos0.mat.Height},dev2.Height={scanPhotos1.mat.Height},重新resize...", WarningEnum.Low);
|
||
if (scanPhotos0.mat.Height > scanPhotos1.mat.Height)
|
||
scanPhotos1.mat = OpencvUtils.ResizeMat(scanPhotos1.mat, scanPhotos0.mat.Width, scanPhotos0.mat.Height);
|
||
else
|
||
scanPhotos0.mat = OpencvUtils.ResizeMat(scanPhotos0.mat, scanPhotos1.mat.Width, scanPhotos1.mat.Height);
|
||
}
|
||
errStep = 1;
|
||
|
||
//反转+相机索引调换
|
||
Mat mat0 = scanPhotos1.mat;
|
||
Mat mat1 = scanPhotos0.mat;
|
||
|
||
//水平合并l
|
||
Mat mat = OpencvUtils.MergeImage_sameSize(new Mat[] { mat0, mat1 });//这里相机反装,左右反转下
|
||
Log($"合并", $"(图像{scanPhotos0.photoIndex})-裁边去孔洞后:({mat0.Width}+{mat1.Width});合并后(去孔洞):{mat.Width}*{mat.Height}");
|
||
//float widthRatio = mat.Width * 1.0f / resize.Width;//宽度比例
|
||
time += $"->图1+2合并({stopWatch.ElapsedMilliseconds})";
|
||
|
||
//门幅更新(含两侧孔洞)x,y cm
|
||
float faceWidthX_cm = (float)Math.Round((scanPhotos0.photoIndex + 1) * mat.Height * 1.0f / confMgr.SysConfigParams.Cm2px_y, 2);
|
||
float faceWidthY_cm = (float)Math.Round((mat.Width + confMgr.SysConfigParams.HolePx * 2) * 1.0f / confMgr.SysConfigParams.Cm2px_x, 2);
|
||
#else
|
||
string imgfilePath = "E:\\CPL\\测试代码\\革测试\\1-1\\现场原图";
|
||
|
||
if (!Directory.Exists(imgfilePath))
|
||
{
|
||
Log($"图像处理", $"模拟错误-路径错误{imgfilePath}", WarningEnum.High);
|
||
break;
|
||
}
|
||
string[] files = Directory.GetFiles(imgfilePath, $"*.bmp", SearchOption.TopDirectoryOnly);
|
||
|
||
if (files.Length > 0 && Cam1Cnt < files.Length)
|
||
{
|
||
Stopwatch stopWatch = new Stopwatch();
|
||
|
||
string time = "";
|
||
//stopWatch.Start();
|
||
|
||
ScanPhotoInfo scanPhotos0 = new ScanPhotoInfo(0, Cam1Cnt, new Mat(4096, 4096 * 2, MatType.CV_8UC3, new Scalar(0, 0, 0)));
|
||
ScanPhotoInfo scanPhotos1 = new ScanPhotoInfo(1, Cam1Cnt, new Mat(4096, 4096 * 2, MatType.CV_8UC3, new Scalar(0, 0, 0)));
|
||
|
||
stopWatch.Start();
|
||
int errStep = 0;
|
||
try
|
||
{
|
||
Log($"图像处理", $"模拟{files[Cam1Cnt]}");
|
||
Mat mat = new Mat(files[Cam1Cnt]);
|
||
Cam1Cnt++;
|
||
Mat mat0 = scanPhotos1.mat;
|
||
Mat mat1 = scanPhotos0.mat;
|
||
|
||
float faceWidthX_cm = (float)Math.Round((scanPhotos0.photoIndex + 1) * mat.Height * 1.0f / confMgr.SysConfigParams.Cm2px_y, 2);
|
||
float faceWidthY_cm = (float)Math.Round((mat.Width + confMgr.SysConfigParams.HolePx * 2) * 1.0f / confMgr.SysConfigParams.Cm2px_x, 2);
|
||
#endif
|
||
//显示图片
|
||
OnAutoRuning(new RunEventArgs(mat.Clone()));
|
||
|
||
faceWidthX_cm = (float)Math.Round(faceWidthX_cm, 2);
|
||
faceWidthY_cm = (float)Math.Round(faceWidthY_cm, 2);
|
||
if (curRecord.FaceWidthMin == 0 || curRecord.FaceWidthMin > faceWidthY_cm)
|
||
curRecord.FaceWidthMin = faceWidthY_cm;
|
||
if (curRecord.FaceWidthMax < faceWidthY_cm)
|
||
curRecord.FaceWidthMax = faceWidthY_cm;
|
||
var point = new float[] { faceWidthX_cm, faceWidthY_cm };// new System.Drawing.PointF(faceWidthX_cm, faceWidthY_cm);
|
||
Log($"门幅", $"(图像{scanPhotos0.photoIndex})-({scanPhotos0.photoIndex})位置:{point[0]}; 幅宽:{point[1]}");
|
||
curRecord.FacePointList.Add(point);
|
||
|
||
//判定门幅
|
||
//if (x < XSizeRange[0])
|
||
// Log($"绘图", $"门幅宽度超限 1!!!! {x}<{XSizeRange[0]}", WarningEnum.High);
|
||
//if (x > XSizeRange[1])
|
||
// Log($"绘图", $"门幅宽度超限 2!!!! {x}>{XSizeRange[1]}", WarningEnum.High);
|
||
//if (item[1] < YSizeRange[0])
|
||
// Log($"绘图", $"门幅宽度超限 3!!!! {item[1]}<{YSizeRange[0]}", WarningEnum.High);
|
||
//if (item[1] > YSizeRange[1])
|
||
// Log($"绘图", $"门幅宽度超限 4!!!! {item[1]}>{YSizeRange[1]}", WarningEnum.High);
|
||
|
||
//显示门幅绘图
|
||
OnAutoRuning(new RunEventArgs(curRecord.FacePointList));
|
||
errStep = 7;
|
||
time += $"->门幅刷新({stopWatch.ElapsedMilliseconds})";
|
||
//去除两侧孔洞(门幅计算时不能去除)
|
||
//if (Config.MarginHoleWidth > 0)
|
||
// mat = OpenCVUtil.cutImage(mat, Config.MarginHoleWidth, 0, mat.Width - Config.MarginHoleWidth * 2, mat.Height);
|
||
|
||
//计算速度
|
||
double lenMi = Math.Round(faceWidthX_cm / 100, 2);
|
||
curRecord.Len = lenMi;
|
||
curRecord.TimeLen = pStopWatch.ElapsedMilliseconds / 1000.0d / 60.0d;//总时间 分
|
||
//显示速度
|
||
OnAutoRuning(new RunEventArgs(lenMi, Math.Round(lenMi / curRecord.TimeLen, 2)));
|
||
|
||
errStep = 9;
|
||
time += $"->速度刷新({stopWatch.ElapsedMilliseconds})";
|
||
//----缺陷队列
|
||
//比例缩放图片
|
||
int xw;
|
||
int resizeWidth = OpencvUtils.GetWidthForResize(mat0.Width + mat1.Width - confMgr.SysConfigParams.MidCoin);
|
||
if (resizeWidth == 0)
|
||
throw new Exception("GetWidthForResize result 0 失败!");
|
||
var resize = new System.Drawing.Size(resizeWidth, OpencvUtils.image_height * 2);//固定8192*2张*4096
|
||
mat = OpencvUtils.Resize(mat, resize.Width, resize.Height, out xw);
|
||
Log($"图像处理", $"(图像{scanPhotos0.photoIndex})-合成图resize后:{mat.Width}*{mat.Height}");
|
||
defectLib.add(new DefectTask()
|
||
{
|
||
modelName = curRecord.ProductInfo.ModelName,
|
||
record = curRecord,
|
||
bmp = mat,
|
||
bmpTag = mat.Clone(),
|
||
photoIndex = scanPhotos0.photoIndex,//0-n 首张必需为0,因下面计算长度是从0开始
|
||
widthRatio = 1.0f,//等比例缩放,高度不变
|
||
qualifiedLimitList = curRecord.ProductInfo.QualifiedLimitList,
|
||
labelDic = GetDefectCode(),
|
||
finishEvent = callBackDefectEvent,
|
||
xw = xw,
|
||
cm2px_x = confMgr.SysConfigParams.Cm2px_x,
|
||
cm2px_y = confMgr.SysConfigParams.Cm2px_y,
|
||
expand_pixel = confMgr.SysConfigParams.Expand_pixel,
|
||
});
|
||
errStep = 10;
|
||
time += $"->加入瑕疵待检队列({stopWatch.ElapsedMilliseconds})";
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
curRecord.ScannerPhotoFinishCount++;//失败时不能因数量不一致无法保存
|
||
Log( $"图像处理", $"异常({errStep}):(图像{scanPhotos0.photoIndex})-{ex.Message}", WarningEnum.High);
|
||
//string dirPath = FileUtil.initFolder($"{Config.ImagePath}{curRecord.BatchId}_{curRecord.ReelId}\\Err\\");
|
||
//OpenCvSharp.Extensions.BitmapConverter.ToBitmap(scanPhotos0.mat).Save($"{dirPath}{scanPhotos0.photoIndex}_0_Step{errStep}.bmp", ImageFormat.Bmp);
|
||
//OpenCvSharp.Extensions.BitmapConverter.ToBitmap(scanPhotos1.mat).Save($"{dirPath}{scanPhotos1.photoIndex}_1_Step{errStep}.bmp", ImageFormat.Bmp);
|
||
}
|
||
finally
|
||
{
|
||
Log($"图像处理", $"(图像{scanPhotos0.photoIndex})-进度计时:{time}");
|
||
scanPhotos0.mat.Dispose();
|
||
scanPhotos1.mat.Dispose();
|
||
scanPhotos0 = scanPhotos1 = null;
|
||
//task = null;
|
||
System.GC.Collect();
|
||
}
|
||
}
|
||
#endregion
|
||
|
||
Thread.Sleep(50);
|
||
} while (!isBreakProcessRun());
|
||
//暂停中断
|
||
//stopWatch.Stop();
|
||
pStopWatch.Stop();
|
||
_isRuning = false;
|
||
}
|
||
Thread.Sleep(10);
|
||
}
|
||
catch (Exception e)
|
||
{
|
||
_isRuning = false;
|
||
|
||
Log("运行报警", "流程运行出错:" + e.Message + "\n", WarningEnum.High);
|
||
}
|
||
}
|
||
}
|
||
#endregion
|
||
|
||
#region 模型label
|
||
private JArray _defectItemList;
|
||
/// <summary>
|
||
/// 获取模型对应标签信息
|
||
/// </summary>
|
||
private void GetDefectAllLabel()
|
||
{
|
||
string labels = CurrProductModel.ModelName.Replace(".trt", ".json");
|
||
string configPath = confMgr.SysConfigParams.AIModelPath + $"\\{labels}";
|
||
string lsTmp = File.ReadAllText(configPath);
|
||
JArray defectItemList = JArray.Parse(lsTmp);
|
||
_defectItemList = defectItemList;
|
||
//var item = defectItemList.FirstOrDefault(m => m.Value<int>("id") == id);
|
||
//if (item == null)
|
||
// return null;
|
||
//return (JObject)item;
|
||
}
|
||
/// <summary>
|
||
/// 根据id获取标签信息
|
||
/// </summary>
|
||
/// <param name="id"></param>
|
||
/// <returns></returns>
|
||
public JObject GetDefectLabel(int id)
|
||
{
|
||
if (_defectItemList != null && _defectItemList.Count > 0)
|
||
{
|
||
var item = _defectItemList.FirstOrDefault(m => m.Value<int>("id") == id);
|
||
if (item == null)
|
||
return null;
|
||
return (JObject)item;
|
||
}
|
||
else
|
||
return null;
|
||
}
|
||
/// <summary>
|
||
/// 根据name获取标签信息
|
||
/// </summary>
|
||
/// <param name="id"></param>
|
||
/// <returns></returns>
|
||
public JObject GetDefectLabel(string name)
|
||
{
|
||
if (_defectItemList != null && _defectItemList.Count > 0)
|
||
{
|
||
var item = _defectItemList.FirstOrDefault(m => m.Value<string>("name") == name);
|
||
if (item == null)
|
||
return null;
|
||
return (JObject)item;
|
||
}
|
||
else
|
||
return null;
|
||
}
|
||
public string GetDefectName(string code)
|
||
{
|
||
if (_defectItemList != null && _defectItemList.Count > 0)
|
||
{
|
||
var item = _defectItemList.FirstOrDefault(m => m.Value<string>("code") == code);
|
||
if (item == null)
|
||
return null;
|
||
return item.Value<string>("name");
|
||
}
|
||
else
|
||
return null;
|
||
}
|
||
public Dictionary<int, string> GetDefectCode()
|
||
{
|
||
Dictionary<int, string> dic = new Dictionary<int, string>();
|
||
for (int i = 0; i < _defectItemList.Count; i++)
|
||
{
|
||
var tt = _defectItemList[i];
|
||
dic.Add(tt.Value<int>("id"), tt.Value<string>("code"));
|
||
}
|
||
return dic;
|
||
}
|
||
#endregion
|
||
|
||
#region 推理完成处理
|
||
private void callBackDefectEvent(DefectTask res)
|
||
{
|
||
{
|
||
int step = 0;
|
||
try
|
||
{
|
||
Log($"检测完成", $"图像队列:{res.record.ScannerPhotoFinishCount + 1}/{res.record.ScannerPhotoCount} (图像{res.photoIndex})检测结果:{res.isSucceed}");
|
||
//string dirPath = FileUtil.initFolder($"{Config.ImagePath}{res.record.BatchId}_{res.record.ReelId}\\");
|
||
//string dirSourcePath = FileUtil.initFolder($"{Config.ImagePath}{res.record.BatchId}_{res.record.ReelId}\\源图\\");
|
||
//Cv2.Flip(res.bmp, res.bmp, FlipMode.XY);//翻转
|
||
string dirPath = Util.CreateSubDir(confMgr.SysConfigParams.DefectSrcImag.SavePath, new List<string> { $"{ res.record.BatchId }_{ res.record.ReelId }" });
|
||
if (confMgr.SysConfigParams.DefectSrcImag.AutoSave)//保存所有原图
|
||
OpenCvSharp.Extensions.BitmapConverter.ToBitmap(res.bmp).Save($"{dirPath}+{res.photoIndex}.bmp", ImageFormat.Bmp);
|
||
|
||
if (res.isSucceed)
|
||
{
|
||
step = 1;
|
||
Log($"检测完成", $"(图像{res.photoIndex})-瑕疵检测完成,共{res.excelTable.Rows.Count}个瑕疵!各环节用时:{string.Join(",", res.stopwatch)}");
|
||
//AddTextEvent(DateTime.Now,$"打标完成", $"第 ({res.photoIndex}) 张照片,计算过程:{res.resultInfo}");
|
||
//if (!Config.IsSaveAllImage && Config.IsSaveDefectSourceImage)
|
||
// OpenCvSharp.Extensions.BitmapConverter.ToBitmap(res.bmp).Save($"{dirSourcePath}{res.photoIndex}.bmp", ImageFormat.Bmp);
|
||
|
||
step = 2;
|
||
if (res.excelTable.Rows.Count > 0)
|
||
{
|
||
res.record.dicPhoto_Defect[res.photoIndex] = true;//改为此图有瑕疵
|
||
//有瑕疵打标图必需保存 Jpeg
|
||
dirPath = Util.CreateSubDir(confMgr.SysConfigParams.DefectSplicImag.SavePath, new List<string> { $"{res.record.BatchId}_{res.record.ReelId}" });
|
||
if (confMgr.SysConfigParams.DefectSplicImag.AutoSave)//保存瑕疵图
|
||
OpenCvSharp.Extensions.BitmapConverter.ToBitmap(res.bmpTag).Save($"{dirPath}{res.photoIndex}_tag.jpg", ImageFormat.Jpeg);
|
||
step = 3;
|
||
res.record.DefectTotalCount += res.excelTable.Rows.Count;
|
||
if (res.record.DefectInfoList == null)
|
||
res.record.DefectInfoList = new List<DefectInfo>();
|
||
|
||
step = 4;
|
||
JObject defectNameInfo;
|
||
DefectInfo defectInfo = null;
|
||
List<object[]> dataRowlist = new List<object[]>();
|
||
long preTicks = pStopWatch.ElapsedMilliseconds;// DateTime.Now.Ticks;
|
||
for (int i = 0; i < res.lstDefectBmp.Count; i++)
|
||
{
|
||
step = 5 + i * 10;
|
||
defectNameInfo = GetDefectLabel(int.Parse(res.excelTable.Rows[i]["类别"].ToString()));
|
||
if(defectNameInfo == null)
|
||
{
|
||
Log($"告警", $"模型标签为空,或未找到标签!", WarningEnum.High);
|
||
continue;
|
||
}
|
||
defectInfo = new DefectInfo
|
||
{
|
||
PhotoIndex = res.photoIndex,
|
||
Code = defectNameInfo.Value<string>("code"),
|
||
Name = defectNameInfo.Value<string>("name"),
|
||
X = double.Parse(res.excelTable.Rows[i]["X"].ToString()),//cm
|
||
Y = Math.Round((res.photoIndex * res.bmp.Height * 1.0d / confMgr.SysConfigParams.Cm2px_y + double.Parse(res.excelTable.Rows[i]["Y"].ToString())), 2),//cm
|
||
Width = double.Parse(res.excelTable.Rows[i]["W"].ToString()),//cm
|
||
Height = double.Parse(res.excelTable.Rows[i]["H"].ToString()),//cm
|
||
ZXD = double.Parse(res.excelTable.Rows[i]["置信度"].ToString()),
|
||
Contrast = double.Parse(res.excelTable.Rows[i]["对比度"].ToString()),
|
||
Target = int.Parse(res.excelTable.Rows[i]["目标"].ToString()),
|
||
image = BitmapConverter.ToBitmap(res.lstDefectBmp[i])
|
||
};
|
||
defectInfo.ModifyUserCode = defectInfo.CreateUserCode = res.record.CreateUserCode;
|
||
step = 6 + i * 10;
|
||
res.record.DefectInfoList.Add(defectInfo);
|
||
defectInfo.uid = preTicks++;// res.record.DefectInfoList.Count;//程序中的唯一索引,用于移除用索引
|
||
//AddTextEvent(DateTime.Now,$"打标完成", $"第{i}个缺陷:{ JsonConvert.SerializeObject(defectInfo)}; Y={res.photoIndex * res.bmp.Height * 1.0d / Config.cm2px_y}+{res.excelTable.Rows[i]["Y"].ToString()}");
|
||
step = 7 + i * 10;
|
||
//保存打标小图
|
||
if (confMgr.SysConfigParams.DefectSmallImag.AutoSave)
|
||
{
|
||
dirPath = Util.CreateSubDir(confMgr.SysConfigParams.DefectSmallImag.SavePath, new List<string> { $"{res.record.BatchId}_{res.record.ReelId}" });
|
||
string filename = $"{dirPath}{res.photoIndex}_X{defectInfo.X}_Y{defectInfo.Y}_W{defectInfo.Width}_H{defectInfo.Height}_目标{defectInfo.Target}_类别{defectInfo.Code}_置信度{defectInfo.ZXD}.jpg";
|
||
OpenCvSharp.Extensions.BitmapConverter.ToBitmap(res.lstDefectBmp[i]).Save(filename, ImageFormat.Jpeg);
|
||
defectInfo.TagFilePath = filename;
|
||
}
|
||
step = 8 + i * 10;
|
||
|
||
res.lstDefectBmp[i].Dispose();
|
||
dataRowlist.Add(new object[]{ defectInfo.uid,defectInfo.Code, defectInfo.PhotoIndex,defectInfo.Name,
|
||
defectInfo.CentreX, defectInfo.CentreY / 100,defectInfo.Width * 10,defectInfo.Height * 10, defectInfo.Area * 100, defectInfo.ZXD, defectInfo.Contrast});
|
||
|
||
step = 9 + i * 10;
|
||
//告警判断???在此还是在收到新照片时触发???
|
||
if (res.record.ProductInfo.DefectAreaLimit > 0 && defectInfo.Area >= res.record.ProductInfo.DefectAreaLimit)
|
||
{
|
||
Log($"告警", $"瑕疵面积达到阈值!({defectInfo.Area}>={res.record.ProductInfo.DefectAreaLimit})", WarningEnum.High);
|
||
}
|
||
}
|
||
Log($"检测完成", "更新UI");
|
||
//更新UI
|
||
int bmpHeight = res.bmp.Height;
|
||
//显示图片
|
||
//OnAutoRuning(new RunEventArgs(defectInfo.image));
|
||
//显示瑕疵图
|
||
OnAutoRuning(new RunEventArgs(dataRowlist));
|
||
|
||
step = 9;
|
||
Log($"检测完成", "保存CSV");
|
||
//保存CSV
|
||
dirPath = Util.CreateSubDir(confMgr.SysConfigParams.DefectSrcImag.SavePath, new List<string> { $"{res.record.BatchId}_{res.record.ReelId}" });
|
||
bool b = Utils.ExcelUtil.DataTable2CSV($"{dirPath}{res.photoIndex}.csv", res.excelTable);
|
||
//AddTextEvent(DateTime.Now,$"打标完成", $"{res.tag}.xlsx {(b ? "保存成功!" : "保存失败!")}");
|
||
step = 10;
|
||
|
||
//每百米告警判断???在此还是在收到新照片时触发???
|
||
if (res.record.ProductInfo.DefectCountLimit > 0 && res.record.DefectTotalCount >= res.record.ProductInfo.DefectCountLimit)
|
||
{
|
||
int compLen = 100 * 100;//每百米 to cm
|
||
int compCount = compLen * confMgr.SysConfigParams.Cm2px_y / res.bmp.Height;
|
||
//从上次告警后重新开始计算长度及数量
|
||
int defectCount = res.record.DefectInfoList.Where(m => m.PhotoIndex >= res.record.preWarningPhotoIndex && m.PhotoIndex >= res.photoIndex + 1 - compCount).Count();
|
||
if (defectCount >= res.record.ProductInfo.DefectCountLimit)
|
||
{
|
||
res.record.preWarningPhotoIndex = res.photoIndex + 1;
|
||
Log($"告警", $"每百米瑕疵数量达到阈值!({defectCount}>={res.record.ProductInfo.DefectCountLimit})", WarningEnum.High);
|
||
}
|
||
step = 11;
|
||
//按缺陷计算没X米多少缺陷报警
|
||
for (int i = 0; i < res.record.ProductInfo.QualifiedLimitList.Count; i++)
|
||
{
|
||
var defectWarn = res.record.ProductInfo.QualifiedLimitList[i];
|
||
if (defectWarn.DefectWarnLength > 0 || defectWarn.DefectWarnCnt > 0)
|
||
{
|
||
step = 12;
|
||
int warnLen = defectWarn.DefectWarnLength * 100;//每百米 to cm
|
||
int warnCount = warnLen * confMgr.SysConfigParams.Cm2px_y / res.bmp.Height;
|
||
//从上次告警后重新开始计算长度及数量
|
||
int warnDefectCount = res.record.DefectInfoList.Where(m => m.PhotoIndex >= res.record.preWarningPhotoIndexByLabel[i] && m.PhotoIndex >= res.photoIndex + 1 - warnCount).Count();
|
||
if (warnDefectCount >= defectWarn.DefectWarnCnt)
|
||
{
|
||
res.record.preWarningPhotoIndexByLabel[i] = res.photoIndex + 1;
|
||
Log($"告警{Thread.CurrentThread.ManagedThreadId}", $"每{defectWarn.DefectWarnLength}米{GetDefectName(defectWarn.Code)}瑕疵数量达到阈值!({warnDefectCount}>={defectWarn.DefectWarnCnt})", WarningEnum.High);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
}
|
||
else
|
||
{
|
||
Log($"打标失败", $"(图像{res.photoIndex})-瑕疵检测失败", WarningEnum.Low);
|
||
}
|
||
res.bmp.Dispose();
|
||
res.bmpTag.Dispose();
|
||
res.bmps_cut = null;
|
||
res.excelTable.Dispose();
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Log($"打标失败", $"(图像{res.photoIndex})-瑕疵检测异常({step}):{ex.Message}");
|
||
}
|
||
finally
|
||
{
|
||
res.record.ScannerPhotoFinishCount++;
|
||
int liScannerPhotoFinishCount = res.record.ScannerPhotoFinishCount;
|
||
int liScannerPhotoCount = res.record.ScannerPhotoCount;
|
||
Log($"检测完成", $"{liScannerPhotoFinishCount}/{liScannerPhotoCount}");
|
||
//this.BeginInvoke(new System.Action(() =>
|
||
//{
|
||
// this.lblWaitImageCount.Text = $"{liScannerPhotoCount - liScannerPhotoFinishCount}";
|
||
//}));
|
||
res = null;
|
||
System.GC.Collect();
|
||
}
|
||
}
|
||
}
|
||
#endregion
|
||
|
||
#region 结束验布
|
||
public bool DefectEnd(Form fatherFrm)
|
||
{
|
||
Log("结束验布", "结束验布!");
|
||
if (confMgr.SysConfigParams.OpenPLC)
|
||
{
|
||
if (plcDev.IsInit())
|
||
{
|
||
plcDev.WriteCoil("DB3.DBX0.0", false);//zt
|
||
plcDev.WriteCoil("DB3.DBX0.1", true);
|
||
}
|
||
else
|
||
{
|
||
Log("运行", "PLC连接异常!", WarningEnum.High);
|
||
return false;
|
||
}
|
||
}
|
||
else if (confMgr.SysConfigParams.OpenIO)
|
||
{
|
||
ioCardDev.WriteBitState((int)DOName.停止, (int)DOName.停止, true);
|
||
Task.Run(async () =>
|
||
{
|
||
await Task.Delay(500);
|
||
ioCardDev.WriteBitState((int)DOName.停止, (int)DOName.停止, false);
|
||
});
|
||
}
|
||
//CurrentState = CurrentStateEnum.初始;
|
||
|
||
if (currKey > 0 )
|
||
{
|
||
if (FrmDialog.ShowDialog(fatherFrm, $"是否保存当前检测结果?", "提示", true) == DialogResult.OK)
|
||
{
|
||
string szBatchId, szReelId;
|
||
double ldErpLen;
|
||
//szBatchId = ;
|
||
//szReelId = txtReelId.Text.Trim();
|
||
//ldErpLen = numErpLen.IsEmpty ? 0 : Convert.ToDouble(numErpLen.Text.Trim());
|
||
|
||
int myKey = currKey;
|
||
Task.Run(() => { saveCurrRecord(myKey); });
|
||
//resetUIValue();
|
||
|
||
pStopWatch.Stop();
|
||
_isAuto = false;
|
||
//this.btnStart.Enabled = true;
|
||
//this.btnEnd.Enabled = this.btnPause.Enabled = false;//这里有问题,应该是devPlc回调设置
|
||
OnAutoRuning(new RunEventArgs(_isAuto));
|
||
}
|
||
else
|
||
{
|
||
Log("结束验布", "不保存数据结束验布!");
|
||
return false;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
Log("结束验布", "无数据结束验布!");
|
||
_isDefect = false;
|
||
return false;
|
||
}
|
||
return true;
|
||
}
|
||
#endregion
|
||
|
||
#region IO解析
|
||
private int GetIOPortIndex(int DIDOEnum)
|
||
{
|
||
return DIDOEnum / 8;
|
||
}
|
||
private int GetIOBitIndex(int DIDOEnum)
|
||
{
|
||
return DIDOEnum % 8;
|
||
}
|
||
#endregion
|
||
|
||
#region 三色灯
|
||
/// <summary>
|
||
/// 三色灯初始化
|
||
/// </summary>
|
||
public void LedReady()
|
||
{
|
||
if (confMgr.SysConfigParams.OpenIO)
|
||
{
|
||
ioCardDev.WriteBitState(GetIOPortIndex((int)DOName.三色灯绿灯), GetIOBitIndex((int)DOName.三色灯绿灯), false);
|
||
ioCardDev.WriteBitState(GetIOPortIndex((int)DOName.三色灯黄灯), GetIOBitIndex((int)DOName.三色灯黄灯), false);
|
||
ioCardDev.WriteBitState(GetIOPortIndex((int)DOName.三色灯红灯), GetIOBitIndex((int)DOName.三色灯红灯), false);
|
||
ioCardDev.WriteBitState(GetIOPortIndex((int)DOName.三色灯蜂鸣器), GetIOBitIndex((int)DOName.三色灯蜂鸣器), false);
|
||
}
|
||
}
|
||
/// <summary>
|
||
/// 运行状态三色灯
|
||
/// </summary>
|
||
public void LedRun()
|
||
{
|
||
if (confMgr.SysConfigParams.OpenIO)
|
||
{
|
||
ioCardDev.WriteBitState(GetIOPortIndex((int)DOName.三色灯绿灯), GetIOBitIndex((int)DOName.三色灯绿灯), true);
|
||
ioCardDev.WriteBitState(GetIOPortIndex((int)DOName.三色灯黄灯), GetIOBitIndex((int)DOName.三色灯黄灯), false);
|
||
ioCardDev.WriteBitState(GetIOPortIndex((int)DOName.三色灯红灯), GetIOBitIndex((int)DOName.三色灯红灯), false);
|
||
ioCardDev.WriteBitState(GetIOPortIndex((int)DOName.三色灯蜂鸣器), GetIOBitIndex((int)DOName.三色灯蜂鸣器), false);
|
||
}
|
||
}
|
||
/// <summary>
|
||
/// 暂停状态三色灯
|
||
/// </summary>
|
||
public void LedPause()
|
||
{
|
||
if (confMgr.SysConfigParams.OpenIO)
|
||
{
|
||
ioCardDev.WriteBitState(GetIOPortIndex((int)DOName.三色灯绿灯), GetIOBitIndex((int)DOName.三色灯绿灯), false);
|
||
ioCardDev.WriteBitState(GetIOPortIndex((int)DOName.三色灯黄灯), GetIOBitIndex((int)DOName.三色灯黄灯), false);
|
||
ioCardDev.WriteBitState(GetIOPortIndex((int)DOName.三色灯红灯), GetIOBitIndex((int)DOName.三色灯红灯), true);
|
||
ioCardDev.WriteBitState(GetIOPortIndex((int)DOName.三色灯蜂鸣器), GetIOBitIndex((int)DOName.三色灯蜂鸣器), false);
|
||
}
|
||
}
|
||
//控制黄灯闪烁
|
||
private bool Blink;
|
||
private int BlinkCnt = 0;
|
||
//控制蜂鸣间隔
|
||
private int BuzzCnt = 0;
|
||
/// <summary>
|
||
/// 回原状态三色灯
|
||
/// </summary>
|
||
/// <param name="val"></param>
|
||
public void LedRset(bool val)
|
||
{
|
||
if (confMgr.SysConfigParams.OpenIO)
|
||
{
|
||
ioCardDev.WriteBitState(GetIOPortIndex((int)DOName.三色灯绿灯), GetIOBitIndex((int)DOName.三色灯绿灯), false);
|
||
//ioCardDev.WriteBitState(GetIOPortIndex((int)DOName.三色灯黄灯), GetIOBitIndex((int)DOName.三色灯黄灯), val);
|
||
ioCardDev.WriteBitState(GetIOPortIndex((int)DOName.三色灯红灯), GetIOBitIndex((int)DOName.三色灯红灯), false);
|
||
ioCardDev.WriteBitState(GetIOPortIndex((int)DOName.三色灯蜂鸣器), GetIOBitIndex((int)DOName.三色灯蜂鸣器), false);
|
||
|
||
Blink = val;
|
||
BlinkCnt = 0;
|
||
}
|
||
}
|
||
#endregion
|
||
|
||
#region 报警等、按钮IO
|
||
/// <summary>
|
||
/// 三色灯报警状态显示
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
public bool WarningShowLed(bool DisEnableBuzz)
|
||
{
|
||
bool sts = false;
|
||
if (statusMgr.Warning == WarningEnum.Normal)
|
||
{
|
||
if (statusMgr.Status == SystemStsEnum.Auto)
|
||
ioCardDev.WriteBitState(GetIOPortIndex((int)DOName.三色灯绿灯), GetIOBitIndex((int)DOName.三色灯绿灯), true);
|
||
else
|
||
ioCardDev.WriteBitState(GetIOPortIndex((int)DOName.三色灯绿灯), GetIOBitIndex((int)DOName.三色灯绿灯), false);
|
||
if (statusMgr.Status == SystemStsEnum.Pause)
|
||
ioCardDev.WriteBitState(GetIOPortIndex((int)DOName.三色灯红灯), GetIOBitIndex((int)DOName.三色灯红灯), true);
|
||
else
|
||
ioCardDev.WriteBitState(GetIOPortIndex((int)DOName.三色灯红灯), GetIOBitIndex((int)DOName.三色灯红灯), false);
|
||
ioCardDev.WriteBitState(GetIOPortIndex((int)DOName.三色灯蜂鸣器), GetIOBitIndex((int)DOName.三色灯蜂鸣器), false);
|
||
BuzzCnt = 0;
|
||
//判断黄灯是否需要闪烁,调用200ms一次
|
||
if (Blink)
|
||
{
|
||
if (BlinkCnt < 3)
|
||
ioCardDev.WriteBitState(GetIOPortIndex((int)DOName.三色灯黄灯), GetIOBitIndex((int)DOName.三色灯黄灯), true);
|
||
else if (BlinkCnt < 6)
|
||
ioCardDev.WriteBitState(GetIOPortIndex((int)DOName.三色灯黄灯), GetIOBitIndex((int)DOName.三色灯黄灯), false);
|
||
BlinkCnt++;
|
||
if (BlinkCnt == 6)
|
||
BlinkCnt = 0;
|
||
}
|
||
else
|
||
ioCardDev.WriteBitState(GetIOPortIndex((int)DOName.三色灯黄灯), GetIOBitIndex((int)DOName.三色灯黄灯), false);
|
||
}
|
||
if (statusMgr.Warning == WarningEnum.Low)
|
||
{
|
||
//ioCardDev.WriteBitState(GetIOPortIndex((int)DOName.启动按钮绿灯), GetIOBitIndex((int)DOName.启动按钮绿灯), false);
|
||
//ioCardDev.WriteBitState(GetIOPortIndex((int)DOName.停止按钮红灯), GetIOBitIndex((int)DOName.停止按钮红灯), true);
|
||
ioCardDev.WriteBitState(GetIOPortIndex((int)DOName.三色灯红灯), GetIOBitIndex((int)DOName.三色灯红灯), true);
|
||
//ioCardDev.WriteBitState(GetIOPortIndex((int)DOName.三色灯绿灯), GetIOBitIndex((int)DOName.三色灯绿灯), false);
|
||
//sts = true;
|
||
}
|
||
if (statusMgr.Warning == WarningEnum.High)
|
||
{
|
||
sts = true;
|
||
ioCardDev.WriteBitState(GetIOPortIndex((int)DOName.三色灯红灯), GetIOBitIndex((int)DOName.三色灯红灯), true);
|
||
ioCardDev.WriteBitState(GetIOPortIndex((int)DOName.三色灯绿灯), GetIOBitIndex((int)DOName.三色灯绿灯), false);
|
||
if (confMgr.SysConfigParams.OpenBuzzer && !DisEnableBuzz)
|
||
{
|
||
if (BuzzCnt < 3)
|
||
ioCardDev.WriteBitState(GetIOPortIndex((int)DOName.三色灯蜂鸣器), GetIOBitIndex((int)DOName.三色灯蜂鸣器), true);
|
||
else if (BuzzCnt < 6)
|
||
ioCardDev.WriteBitState(GetIOPortIndex((int)DOName.三色灯蜂鸣器), GetIOBitIndex((int)DOName.三色灯蜂鸣器), false);
|
||
BuzzCnt++;
|
||
if (BuzzCnt == 6)
|
||
BuzzCnt = 0;
|
||
}
|
||
}
|
||
return sts;
|
||
}
|
||
/// <summary>
|
||
/// 按钮IO检测
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
public int ButtonIOTrg(bool DisEnableDoorAlm)
|
||
{
|
||
int ret = 0;
|
||
bool sts;
|
||
if (confMgr.SysConfigParams.OpenDoor && !DisEnableDoorAlm)
|
||
{
|
||
ioCardDev.GetDIBitState(GetIOPortIndex((int)DIName.门磁), GetIOBitIndex((int)DIName.门磁), out sts);
|
||
if ((!sts) && (statusMgr.Status == SystemStsEnum.Auto))
|
||
{
|
||
Log("暂停", "门磁报警-门打开", WarningEnum.Low);
|
||
statusMgr.GotoPause();
|
||
SendStatus();
|
||
ret = 2;
|
||
}
|
||
}
|
||
ioCardDev.GetDIBitState(GetIOPortIndex((int)DIName.暂停按钮), GetIOBitIndex((int)DIName.暂停按钮), out sts);
|
||
if (sts)
|
||
{
|
||
Log("暂停", "手动暂停");
|
||
statusMgr.GotoPause();
|
||
SendStatus();
|
||
ret = 2;
|
||
}
|
||
ioCardDev.GetDIBitState(GetIOPortIndex((int)DIName.复位按钮), GetIOBitIndex((int)DIName.复位按钮), out sts);
|
||
if (sts)
|
||
{
|
||
ret = 3;
|
||
|
||
}
|
||
ioCardDev.GetDIBitState(GetIOPortIndex((int)DIName.启动按钮), GetIOBitIndex((int)DIName.启动按钮), out sts);
|
||
if (sts)
|
||
ret = 1;
|
||
|
||
return ret;
|
||
}
|
||
#endregion
|
||
|
||
#region 系统关闭
|
||
/// <summary>
|
||
/// 关闭
|
||
/// </summary>
|
||
public void Close()
|
||
{
|
||
_isInit = false;
|
||
_isRuning = false;
|
||
if (null != _cts)
|
||
{
|
||
_cts.Cancel();
|
||
}
|
||
if (null != _mainThread)
|
||
{
|
||
_mainThread.Join(1000);
|
||
}
|
||
if (null != _Cam1Thread)
|
||
{
|
||
_Cam1Thread.Join(1000);
|
||
}
|
||
if (null != _Cam2Thread)
|
||
{
|
||
_Cam2Thread.Join(1000);
|
||
}
|
||
|
||
//关闭相机
|
||
LineCamDev1.CloseCamera();
|
||
LineCamDev2.CloseCamera();
|
||
|
||
//关闭光源
|
||
for (int i = 0; i < LightChCount; i++)
|
||
{
|
||
lightDev.CloseLight(i + 1);
|
||
}
|
||
|
||
lightDev.CloseDev();
|
||
|
||
|
||
//关闭io
|
||
if (confMgr.SysConfigParams.OpenIO)
|
||
{
|
||
ioCardDev.ResetAllDO();
|
||
|
||
ioCardDev.CloseBoard();
|
||
}
|
||
|
||
}
|
||
#endregion
|
||
|
||
#region 日志报警
|
||
/// <summary>
|
||
/// 初始化记录报警和显示
|
||
/// </summary>
|
||
/// <param name="tag">标头</param>
|
||
/// <param name="msg">内容</param>
|
||
/// <param name="warning">报警状态</param>
|
||
private void InitLog(string msg, string tag = "初始化", WarningEnum warning = WarningEnum.Normal)
|
||
{
|
||
OnInitRuning(new InitEventArgs(msg));
|
||
statusMgr.GotoWarning(warning, tag, msg);
|
||
}
|
||
/// <summary>
|
||
/// 记录报警和显示
|
||
/// </summary>
|
||
/// <param name="tag">标头</param>
|
||
/// <param name="msg">内容</param>
|
||
/// <param name="warning">报警状态</param>
|
||
private void Log(string tag, string msg, WarningEnum warning = WarningEnum.Normal)
|
||
{
|
||
OnMainRuning(new MainEventArgs(tag, msg, warning));
|
||
statusMgr.GotoWarning(warning, tag, msg);
|
||
//开启云端
|
||
if ((init_Cloud) && (warning != WarningEnum.Normal))
|
||
{
|
||
//上传报警状态和信息
|
||
string statusStr = warning == WarningEnum.Normal ? "正常" : warning == WarningEnum.Low ? "警告" : "系统报警";
|
||
cloudMgr.SendTopic("device/attributes", $"{{\"status\": \"{statusStr}\", \"alm\": \"{tag}-{msg}\", " +
|
||
$"\"name\": \"{confMgr.SysConfigParams.CloudThisName}\", \"DailyOutput\": \"{DailyOutput}\"}}");
|
||
}
|
||
}
|
||
#endregion
|
||
|
||
#region 硬件
|
||
|
||
#region 硬件型号配置
|
||
public LightDevNameEnum SysUseLight = LightDevNameEnum.CST;
|
||
#endregion
|
||
|
||
#region 硬件字段
|
||
private CamDev _LinecamDev1;
|
||
/// <summary>
|
||
/// io控制卡
|
||
/// </summary>
|
||
public CamDev LineCamDev1 { get { return _LinecamDev1; } }
|
||
private CamDev _LinecamDev2;
|
||
/// <summary>
|
||
/// io控制卡
|
||
/// </summary>
|
||
public CamDev LineCamDev2 { get { return _LinecamDev2; } }
|
||
|
||
private IOCardDev ioCardDev;
|
||
/// <summary>
|
||
/// io控制卡
|
||
/// </summary>
|
||
public IOCardDev IOCardDev { get { return ioCardDev; } }
|
||
|
||
private LightDev lightDev;
|
||
/// <summary>
|
||
/// 光源控制
|
||
/// </summary>
|
||
public LightDev LightDev { get { return lightDev; } }
|
||
public string LightName { get { return "Light"; } }
|
||
public int LightChCount = 6;//美尚4通道,其他6通道
|
||
|
||
private PlcDev plcDev;
|
||
/// <summary>
|
||
/// PLC控制
|
||
/// </summary>
|
||
public PlcDev PlcDev { get { return plcDev; } }
|
||
|
||
private PrintControl printControl;
|
||
/// <summary>
|
||
/// 打印机模块
|
||
/// </summary>
|
||
public PrintControl PrintControl { get { return printControl; } }
|
||
#endregion
|
||
|
||
#region 初始化和基本电机IO操作
|
||
private void InitDev()
|
||
{
|
||
ioCardDev = new AdvantechIO();
|
||
|
||
//CpuType.S71200 = 30
|
||
plcDev = new PlcDev(CpuType.S71200, confMgr.SysConfigParams.PLC_IP, (short)confMgr.SysConfigParams.PLC_Rack, (short)confMgr.SysConfigParams.PLC_Solt);
|
||
|
||
_LinecamDev1 = new CamDev(CameraEnumType.IKap, confMgr.SysConfigParams.CamIndex_1.ToString(), confMgr.SysConfigParams.CamPath_1, confMgr.SysConfigParams.CamDev_1);
|
||
_LinecamDev2 = new CamDev(CameraEnumType.IKap, confMgr.SysConfigParams.CamIndex_2.ToString(), confMgr.SysConfigParams.CamPath_2, confMgr.SysConfigParams.CamDev_2);
|
||
|
||
if (SysUseLight == LightDevNameEnum.CST)
|
||
lightDev = new CSTLight(LightName, LightChCount);
|
||
else
|
||
lightDev = new RseeLight(SysUseLight, LightName);
|
||
}
|
||
/// <summary>
|
||
/// 初始化硬件
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
private bool InitAllDev()
|
||
{
|
||
bool ret = false;
|
||
InitDev();
|
||
#if Online
|
||
//打印机模块初始化
|
||
InitLog("打印机模块初始化...");
|
||
try
|
||
{
|
||
printControl = new PrintControl();
|
||
InitLog("初始化打印机模块成功!");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
printControl = null;
|
||
InitLog($"初始化打印机模块失败! {ex.Message}");
|
||
}
|
||
|
||
if (confMgr.SysConfigParams.OpenPLC)
|
||
{
|
||
//PLC初始化
|
||
InitLog("PLC连接初始化...");
|
||
if(!plcDev.OpenDev())
|
||
{
|
||
InitLog("PLC连接初始化失败!", "初始化", WarningEnum.High);
|
||
return ret;
|
||
}
|
||
InitLog("PLC连接成功!");
|
||
}
|
||
if (confMgr.SysConfigParams.OpenIO)
|
||
{
|
||
//IO初始化
|
||
InitLog("IO板卡初始化...");
|
||
if (ioCardDev.InitBoard(MaiMuControl.Device.IOBordType.Advantech) < 0)
|
||
{
|
||
InitLog("IO板卡初始化失败!", "初始化", WarningEnum.High);
|
||
return ret;
|
||
}
|
||
if (ioCardDev.OpenBoard(confMgr.SysConfigParams.IODevName, confMgr.SysConfigParams.IOCfgPath) < 0)
|
||
{
|
||
InitLog("打开IO板卡失败!", "初始化", WarningEnum.High);
|
||
return ret;
|
||
}
|
||
if (ioCardDev.ResetAllDO() < 0)
|
||
{
|
||
InitLog("IO Reset失败!", "初始化", WarningEnum.High);
|
||
return ret;
|
||
}
|
||
InitLog("初始化IO板卡成功!");
|
||
}
|
||
|
||
//相机初始化
|
||
if(!_LinecamDev1.InitCamera())
|
||
{
|
||
InitLog("相机1初始化失败!", "初始化", WarningEnum.High);
|
||
return ret;
|
||
}
|
||
if(!_LinecamDev1.OpenCamera())
|
||
{
|
||
InitLog("相机1打开失败!", "初始化", WarningEnum.High);
|
||
return ret;
|
||
}
|
||
_LinecamDev1.IsMirrorX = confMgr.SysConfigParams.Cam1_flipX;
|
||
_LinecamDev1.IsMirrorY = confMgr.SysConfigParams.Cam1_flipY;
|
||
if (!_LinecamDev2.InitCamera())
|
||
{
|
||
InitLog("相机2初始化失败!", "初始化", WarningEnum.High);
|
||
return ret;
|
||
}
|
||
if (!_LinecamDev2.OpenCamera())
|
||
{
|
||
InitLog("相机2打开失败!", "初始化", WarningEnum.High);
|
||
return ret;
|
||
}
|
||
_LinecamDev2.IsMirrorX = confMgr.SysConfigParams.Cam2_flipX;
|
||
_LinecamDev2.IsMirrorY = confMgr.SysConfigParams.Cam2_flipY;
|
||
|
||
//光源初始化
|
||
InitLog("光源控制器初始化...");
|
||
int com_num = int.Parse(confMgr.SysConfigParams.LightCom.Remove(0, 3));
|
||
if (lightDev.InitDev(com_num, confMgr.SysConfigParams.LightComBaud) < 0)
|
||
{
|
||
InitLog("光源控制器初始化失败!", "初始化", WarningEnum.High);
|
||
return ret;
|
||
}
|
||
InitLog("初始化光源控制器成功!");
|
||
//关闭光源
|
||
for (int i = 0; i < LightChCount; i++)
|
||
{
|
||
lightDev.CloseLight(i + 1);
|
||
}
|
||
#endif
|
||
ret = true;
|
||
return ret;
|
||
}
|
||
/// <summary>
|
||
/// 读取硬件配置
|
||
/// </summary>
|
||
private bool LoadDevConfig()
|
||
{
|
||
LightParams lightParams = new LightParams(LightName, LightChCount);
|
||
//LightChCount = 6;
|
||
//lightParams.DevName = LightName;
|
||
lightParams.ComName = confMgr.SysConfigParams.LightCom;
|
||
lightParams.Buad = confMgr.SysConfigParams.LightComBaud;
|
||
//lightParams.ChCount = LightChCount;
|
||
lightDev.WriteCfgInfo(confMgr.DevConfigPath, lightParams);
|
||
return true;
|
||
}
|
||
|
||
#endregion
|
||
#endregion
|
||
|
||
#region 硬盘检测
|
||
public static bool CheckDisk(IWin32Window owner, int max = 10)
|
||
{
|
||
if (!string.IsNullOrEmpty(ConfMgr.Instance.SysConfigParams.DefectSrcImag.SavePath))
|
||
{
|
||
string path = ConfMgr.Instance.SysConfigParams.DefectSrcImag.SavePath;
|
||
string volume = path.Substring(0, path.IndexOf(':'));
|
||
long freespace = DiskAPI.GetHardDiskSpace(volume);
|
||
if (freespace < max)
|
||
{
|
||
string tip = $"当前{volume}硬盘容量:{freespace}GB,小于{max}GB。注意清理!!";
|
||
FrmDialog.ShowDialog(owner, tip, "警告", true);
|
||
return false;
|
||
}
|
||
}
|
||
return true;
|
||
}
|
||
#endregion
|
||
|
||
#region 初始化事件
|
||
/// <summary>
|
||
/// 初始化回调
|
||
/// </summary>
|
||
/// <param name="sender"></param>
|
||
/// <param name="e"></param>
|
||
public delegate void InitEventHandler(Object sender, InitEventArgs e);
|
||
public event InitEventHandler InitRuning;
|
||
protected virtual void OnInitRuning(InitEventArgs e)
|
||
{
|
||
if (null != InitRuning)
|
||
{
|
||
InitRuning(this, e);
|
||
}
|
||
}
|
||
#endregion
|
||
|
||
#region 主窗体显示事件
|
||
/// <summary>
|
||
/// 主窗体回调
|
||
/// </summary>
|
||
/// <param name="sender"></param>
|
||
/// <param name="e"></param>
|
||
public delegate void MainEventHandler(Object sender, MainEventArgs e);
|
||
public event MainEventHandler MainRuning;
|
||
protected virtual void OnMainRuning(MainEventArgs e)
|
||
{
|
||
if (null != MainRuning)
|
||
{
|
||
MainRuning(this, e);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 流程回调
|
||
/// </summary>
|
||
/// <param name="sender"></param>
|
||
/// <param name="e"></param>
|
||
public delegate void RunEventHandler(Object sender, RunEventArgs e);
|
||
public event RunEventHandler AutoRuning;
|
||
protected virtual void OnAutoRuning(RunEventArgs e)
|
||
{
|
||
if (null != AutoRuning)
|
||
{
|
||
AutoRuning(this, e);
|
||
}
|
||
}
|
||
#endregion
|
||
|
||
#region 加载测试列表
|
||
/// <summary>
|
||
/// 加载产品列表
|
||
/// </summary>
|
||
public void LoadProductCodeList()
|
||
{
|
||
try
|
||
{
|
||
productCodeList = PdtService.GetListNav().Select(m => m.Name).ToList();
|
||
productIdList = PdtService.GetListNav().Select(m => m.Id).ToList();
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
OnMainRuning(new MainEventArgs("启动", "加载检测标准失败:" + ex.Message, WarningEnum.High));
|
||
statusMgr.GotoWarning(WarningEnum.High, "启动", "加载检测标准失败:" + ex.Message);
|
||
SendStatus();
|
||
}
|
||
}
|
||
#endregion
|
||
|
||
#region 界面显示
|
||
public static void showRowNum_onDataGrid_RowPostPaint(DataGridView dgv, object sender, DataGridViewRowPostPaintEventArgs e)
|
||
{
|
||
Rectangle rectangle = new Rectangle(e.RowBounds.Location.X, e.RowBounds.Location.Y, dgv.RowHeadersWidth - 4, e.RowBounds.Height);
|
||
TextRenderer.DrawText(e.Graphics, (e.RowIndex + 1).ToString(), dgv.RowHeadersDefaultCellStyle.Font, rectangle, dgv.RowHeadersDefaultCellStyle.ForeColor, TextFormatFlags.VerticalCenter | TextFormatFlags.Right);
|
||
}
|
||
/// <summary>
|
||
/// IO二进制数据格式化到8位 XXXX10X0
|
||
/// </summary>
|
||
/// <param name="datas"></param>
|
||
/// <returns></returns>
|
||
public static string[] IODataFormatBinaryStr(string[] datas, bool clone, char defaultPadChar = 'X')
|
||
{
|
||
string[] datas2 = new string[datas.Length];
|
||
for (int i = 0; i < datas.Length; i++)
|
||
{
|
||
if (clone)
|
||
{
|
||
datas2[i] = datas[i].Replace(" ", "");
|
||
if (datas2[i].Length > 8)
|
||
datas2[i] = datas2[i].Substring(datas2[i].Length - 8);
|
||
else if (datas2[i].Length < 8)
|
||
datas2[i] = datas2[i].PadLeft(8, defaultPadChar);
|
||
}
|
||
else
|
||
{
|
||
datas[i] = datas[i].Replace(" ", "");
|
||
if (datas[i].Length > 8)
|
||
datas[i] = datas[i].Substring(datas[i].Length - 8);
|
||
else if (datas[i].Length < 8)
|
||
datas[i] = datas[i].PadLeft(8, defaultPadChar);
|
||
|
||
datas2 = datas;
|
||
}
|
||
}
|
||
|
||
return datas2;
|
||
}
|
||
/// <summary>
|
||
///
|
||
/// </summary>
|
||
/// <param name="op_show_list">[XXHL XXXX,XXXX XXXX,...]</param>
|
||
/// <param name="currIoDatas">[byte,byte,byte,byte]</param>
|
||
/// <returns></returns>
|
||
public static bool compareIOInput(string[] op_show_list, byte[] currIoDatas)
|
||
{
|
||
int isok = 0;//1-true 2-false
|
||
string IN_OP_SHOW;
|
||
for (int i = 0; i < currIoDatas.Length; i++)
|
||
{
|
||
IN_OP_SHOW = op_show_list[i].Replace(" ", "").PadLeft(8, 'X');
|
||
if (IN_OP_SHOW.IndexOf('H') < 0 && IN_OP_SHOW.IndexOf('L') < 0)
|
||
continue;
|
||
|
||
for (int j = 7; j >= 0; j--)
|
||
{
|
||
byte bit = (byte)(1 << 7 - j);
|
||
if (IN_OP_SHOW[j] == 'H')
|
||
{
|
||
if ((bit & currIoDatas[i]) > 0)
|
||
isok = 1;
|
||
else
|
||
{
|
||
isok = 2;
|
||
break;
|
||
}
|
||
}
|
||
else if (IN_OP_SHOW[j] == 'L')
|
||
{
|
||
if ((currIoDatas[i] ^ (currIoDatas[i] | bit)) > 0)
|
||
isok = 1;
|
||
else
|
||
{
|
||
isok = 2;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
//已经不符
|
||
if (isok == 2) break;
|
||
}
|
||
|
||
//
|
||
return isok == 1;
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 启动
|
||
/// <summary>
|
||
/// 加载ERP数据库数据
|
||
/// </summary>
|
||
/// <param name="barCode"></param>
|
||
/// <returns></returns>
|
||
private DataRow loadErpData(string barCode)
|
||
{
|
||
var paramList = new List<SugarParameter>() {
|
||
new SugarParameter("@code", barCode)
|
||
};
|
||
Stopwatch stopwatch = Stopwatch.StartNew();
|
||
var data = confMgr.execSql(confMgr.SysConfigParams.ErpSql, paramList);
|
||
if (data != null && data.Rows.Count < 1)
|
||
{
|
||
Log("Erp查询结果", $"{barCode}: 时长={stopwatch.ElapsedMilliseconds}ms, 无数据!", WarningEnum.Normal);
|
||
return null;
|
||
}
|
||
|
||
Log("Erp查询结果", $"{barCode}: 时长={stopwatch.ElapsedMilliseconds}ms, {JsonConvert.SerializeObject(data.Rows[0])}", WarningEnum.Normal);
|
||
return data.Rows[0];
|
||
}
|
||
/// <summary>
|
||
/// 自动运行
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
public bool StartRun(Form fatherFrm, string sn, ref string DefectName, ref string name, ref string batch, ref string reel, ref string cnt)
|
||
{
|
||
bool ret = true;
|
||
|
||
string barCodeName = "", len = "0", batchId = "", reelId = "";
|
||
if(string.IsNullOrEmpty(name))
|
||
name = "未找到";
|
||
//运行前清除过期图片文件
|
||
//DateTime st = DateTime.Now;
|
||
DelectPictureFile();
|
||
if ((statusMgr.Status != SystemStsEnum.Standby) && (statusMgr.Status != SystemStsEnum.Pause))
|
||
{
|
||
Log("运行", "系统非可运行状态", WarningEnum.Low);
|
||
return false;
|
||
}
|
||
|
||
if (string.IsNullOrEmpty(sn))
|
||
{
|
||
Log("运行", "产品条码为空!", WarningEnum.Low);
|
||
return false;
|
||
}
|
||
|
||
//禾欣数据 sn,长度数量, 批号, 卷号
|
||
if (!string.IsNullOrWhiteSpace(confMgr.SysConfigParams.ErpDBConStr) && !string.IsNullOrWhiteSpace(confMgr.SysConfigParams.ErpSql) && !string.IsNullOrWhiteSpace(sn))
|
||
{
|
||
Log("扫码", $"产品条码({sn})到ERP查询对应数据...", WarningEnum.Normal);
|
||
var rowData = this.loadErpData(sn);
|
||
if (rowData == null)
|
||
{
|
||
Log("扫码", $"产品条码({sn})无对应ERP数据,不做响应!", WarningEnum.High);
|
||
return false;
|
||
}
|
||
|
||
barCodeName = rowData[0].ToString();
|
||
if (rowData.ItemArray.Length > 1) len = rowData[1].ToString();
|
||
if (rowData.ItemArray.Length > 2) batchId = rowData[2].ToString();
|
||
if (rowData.ItemArray.Length > 3) reelId = rowData[3].ToString();
|
||
}
|
||
else
|
||
barCodeName = sn;//没有ERP对应关系时直接使用条码做为品名
|
||
|
||
//Log("调试", $"time1:{(DateTime.Now - st).Milliseconds}");
|
||
//st = DateTime.Now;
|
||
int errStep = 0;
|
||
try
|
||
{
|
||
Product model;
|
||
//禾欣客户使用
|
||
if(confMgr.SysConfigParams.CustomerName == "hexin")
|
||
{
|
||
errStep = 1;
|
||
//SHNY-PX-6-***
|
||
string[] codes = barCodeName.Split(new char[] { '-' });
|
||
if (codes.Length < 4)
|
||
{
|
||
Log("扫码", $"产品品名({barCodeName})格式错误,不做响应!", WarningEnum.Low);
|
||
return false;
|
||
}
|
||
errStep = 2;
|
||
//加载新产品
|
||
string pcode = "1-" + codes[2];
|
||
if (codes[1] == "0" || confMgr.SysConfigParams.SuedeList.Contains(codes[1]))
|
||
pcode = "0-" + codes[2];
|
||
model = PdtService.GetModelNav(pcode); //frmProduct.loadProduct(code);
|
||
|
||
name = barCodeName;
|
||
batch = batchId;
|
||
reel = reelId;
|
||
cnt = len;
|
||
}
|
||
else
|
||
{
|
||
if (string.IsNullOrEmpty(name) || name == "未找到")
|
||
{
|
||
Log("运行", "产品品名为空!", WarningEnum.Low);
|
||
return false;
|
||
}
|
||
if (string.IsNullOrEmpty(DefectName))
|
||
{
|
||
Log("运行", "检测标准未选择!", WarningEnum.Low);
|
||
return false;
|
||
}
|
||
if (string.IsNullOrEmpty(batch))
|
||
{
|
||
Log("运行", "批号为空!", WarningEnum.Low);
|
||
return false;
|
||
}
|
||
if (string.IsNullOrEmpty(reel))
|
||
{
|
||
Log("运行", "卷号为空!", WarningEnum.Low);
|
||
return false;
|
||
}
|
||
barCodeName = name;
|
||
batchId = batch;
|
||
reelId = reel;
|
||
double t;
|
||
cnt = double.TryParse(cnt, out t) ?cnt:"0";
|
||
model = PdtService.GetModelNavByName(DefectName);
|
||
}
|
||
if (model == null)
|
||
{
|
||
Log("扫码", $"编码({sn})对应配方不存在,请先添加产品配方设置,暂停设备!", WarningEnum.High);
|
||
return false;
|
||
}
|
||
DefectName = model.Name;
|
||
|
||
//数据处理
|
||
Records record;
|
||
lock (lockCurrKey)
|
||
{
|
||
errStep = 3;
|
||
//保存,这里队列图片可能还未检测完
|
||
if (currKey > 0)
|
||
{
|
||
string szBatchId, szReelId;
|
||
double ldErpLen;
|
||
szBatchId = batch;
|
||
szReelId = reel;
|
||
ldErpLen = Convert.ToDouble(cnt);
|
||
//BatchId = code,//code[2]
|
||
//ReelId = "1",//code[3]
|
||
int mykey = currKey;
|
||
Task.Run(() => { saveCurrRecord(mykey); });
|
||
currKey = 0;
|
||
}
|
||
|
||
errStep = 4;
|
||
var now = DateTime.Now;
|
||
currKey = now.Hour * 10000 + now.Minute * 100 + now.Second;
|
||
//var materialItem = codes[0]+"-"+ codes[1];
|
||
//var colorItem = Config.getColorItem(int.Parse(codes[2]));
|
||
record = new Records()
|
||
{
|
||
currKey = currKey,
|
||
ProductId = model.Id,
|
||
ProductInfo = model,//后面计算合格时用
|
||
Color = model.ColorName,
|
||
Material = model.Material,//codes[0] + "-" + codes[1],// (materialItem == null ? "未知" : materialItem["name"].ToString()),
|
||
BarCode = sn,
|
||
BarCodeName = barCodeName,
|
||
ErpLen = double.Parse(len),
|
||
BatchId = batchId,
|
||
ReelId = reelId,
|
||
ModifyUserCode = userMgr.LoginUser.Code,
|
||
CreateUserCode = userMgr.LoginUser.Code,
|
||
};
|
||
htTask.Add(currKey, record);
|
||
}
|
||
errStep = 8;
|
||
//
|
||
errStep = 9;
|
||
Log("扫码", $"品名({barCodeName}),加载产品信息({model.Code})完成,加载配方(光源={model.LightValue},曝光={model.ExposureTime},增益={model.Gain})...");
|
||
errStep = 10;
|
||
#if Online
|
||
if (model.LightValue > 0)//光源 - 通道0
|
||
lightDev.SetLightDigitalValue(1, model.LightValue);
|
||
errStep = 11;
|
||
if (model.ExposureTime > 0 || model.Gain > 0)//相机曝光 增益
|
||
{
|
||
LineCamDev1.SetExposure((float)(model.ExposureTime > 0 ? model.ExposureTime : 0));
|
||
LineCamDev1.SetGain((float)(model.Gain > 0 ? model.Gain : 0));
|
||
|
||
LineCamDev2.SetExposure((float)(model.ExposureTime > 0 ? model.ExposureTime : 0));
|
||
LineCamDev2.SetGain((float)(model.Gain > 0 ? model.Gain : 0));
|
||
}
|
||
#endif
|
||
errStep = 15;
|
||
Log("扫码", $"品名({barCodeName}),配方设置完成:光源={model.LightValue},曝光={model.ExposureTime}");
|
||
|
||
Log("启动", "下发启动指令...");
|
||
if (confMgr.SysConfigParams.OpenPLC)
|
||
{
|
||
if (plcDev.IsInit())
|
||
{
|
||
plcDev.WriteCoil("DB3.DBX0.1", false);
|
||
plcDev.WriteCoil("DB3.DBX0.0", true);//启动
|
||
}
|
||
else
|
||
{
|
||
Log("运行", "PLC连接异常!", WarningEnum.High);
|
||
return false;
|
||
}
|
||
}
|
||
else if (confMgr.SysConfigParams.OpenIO)
|
||
{
|
||
bool sts;
|
||
ioCardDev.GetDIBitState(GetIOPortIndex((int)DIName.暂停按钮), GetIOBitIndex((int)DIName.暂停按钮), out sts);
|
||
if (!sts)
|
||
{
|
||
ioCardDev.WriteBitState((int)DOName.启动, (int)DOName.启动, true);
|
||
Task.Run(async () =>
|
||
{
|
||
await Task.Delay(500);
|
||
ioCardDev.WriteBitState((int)DOName.启动, (int)DOName.启动, false);
|
||
});
|
||
}
|
||
else
|
||
Log("运行", "存在暂停信号!", WarningEnum.Low);
|
||
}
|
||
|
||
pStopWatch.Restart();
|
||
_matList1.Clear();
|
||
_matList2.Clear();
|
||
Cam1Cnt = 0;
|
||
Cam2Cnt = 0;
|
||
|
||
System.GC.Collect();
|
||
errStep = 16;
|
||
LedRun();
|
||
_isRuning = true;
|
||
_isAuto = true;
|
||
statusMgr.GotoAuto();
|
||
SendStatus();
|
||
CurrProductModel = model;
|
||
|
||
//获取模型label
|
||
GetDefectAllLabel();
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Log("运行", $"程序错误-{errStep}:" + ex.Message + "\n", WarningEnum.High);
|
||
}
|
||
|
||
return ret;
|
||
}
|
||
/// <summary>
|
||
/// 暂停重启
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
public bool ReStartRun()
|
||
{
|
||
bool ret = false;
|
||
|
||
Log("启动", "下发启动指令...");
|
||
if (confMgr.SysConfigParams.OpenPLC)
|
||
{
|
||
if (plcDev.IsInit())
|
||
{
|
||
plcDev.WriteCoil("DB3.DBX0.1", false);
|
||
plcDev.WriteCoil("DB3.DBX0.0", true);//启动
|
||
}
|
||
else
|
||
{
|
||
Log("运行", "PLC连接异常!", WarningEnum.High);
|
||
return false;
|
||
}
|
||
}
|
||
else if (confMgr.SysConfigParams.OpenIO)
|
||
{
|
||
bool sts;
|
||
ioCardDev.GetDIBitState(GetIOPortIndex((int)DIName.暂停按钮), GetIOBitIndex((int)DIName.暂停按钮), out sts);
|
||
if (!sts)
|
||
{
|
||
ioCardDev.WriteBitState((int)DOName.启动, (int)DOName.启动, true);
|
||
Task.Run(async () =>
|
||
{
|
||
await Task.Delay(500);
|
||
ioCardDev.WriteBitState((int)DOName.启动, (int)DOName.启动, false);
|
||
});
|
||
}
|
||
}
|
||
|
||
pStopWatch.Start();
|
||
Log("启动", $"暂停 -> 继续");
|
||
LedRun();
|
||
_isRuning = true;
|
||
statusMgr.GotoAuto();
|
||
SendStatus();
|
||
ret = true;
|
||
|
||
return ret;
|
||
}
|
||
#endregion
|
||
|
||
#region 文件删除
|
||
public void DelectPictureFile()
|
||
{
|
||
//删除文件
|
||
Task.Factory.StartNew(() =>
|
||
{
|
||
//图片
|
||
if (confMgr.SysConfigParams.DefectSrcImag.AutoDelete)
|
||
statusMgr.DeleteFiles(confMgr.SysConfigParams.DefectSrcImag.SavePath, confMgr.SysConfigParams.DefectSrcImag.AutoDeleteDays, true);
|
||
if (confMgr.SysConfigParams.DefectSmallImag.AutoDelete)
|
||
statusMgr.DeleteFiles(confMgr.SysConfigParams.DefectSmallImag.SavePath, confMgr.SysConfigParams.DefectSmallImag.AutoDeleteDays, true);
|
||
if (confMgr.SysConfigParams.DefectSplicImag.AutoDelete)
|
||
statusMgr.DeleteFiles(confMgr.SysConfigParams.DefectSplicImag.SavePath, confMgr.SysConfigParams.DefectSplicImag.AutoDeleteDays, true);
|
||
|
||
//日志
|
||
if (confMgr.SysConfigParams.AutoDeleteLog)
|
||
statusMgr.DeleteFiles(confMgr.SysConfigParams.LogPath, confMgr.SysConfigParams.AutoDeleteLogData, true);
|
||
});
|
||
}
|
||
|
||
#region 数据保存
|
||
|
||
private async void saveCurrRecord(int key)
|
||
{
|
||
Records model = null;
|
||
int step = 0;
|
||
try
|
||
{
|
||
_isDefect = true;
|
||
Log( "入库", $"准备入库key={key}");
|
||
//foreach (int itemKey in htTask.Keys)
|
||
// AddTextEvent(DateTime.Now,"入库", $"htTask {itemKey}");
|
||
|
||
step = 1;
|
||
model = Hashtable.Synchronized(htTask)[key] as Records;
|
||
//model = htTask[key] as Records;
|
||
step = 2;
|
||
if (model.Len == 0)
|
||
{
|
||
_isDefect = false;
|
||
return;
|
||
}
|
||
|
||
//model.BatchId = batchId;
|
||
//model.ReelId = reelId;
|
||
//model.ErpLen = erpLen;
|
||
while (model.ScannerPhotoCount > model.ScannerPhotoFinishCount)
|
||
await Task.Delay(100);
|
||
step = 3;
|
||
//计算等级标准
|
||
List<GradeLimit> gradeLimitList = model.ProductInfo.GradeLimitList;
|
||
if (gradeLimitList != null && gradeLimitList.Count > 0)
|
||
{
|
||
step = 4;
|
||
int count;
|
||
foreach (GradeLimit item in gradeLimitList)
|
||
{
|
||
count = model.DefectInfoList.Where(m => m.Code == item.Code).Count();
|
||
if (count <= item.A && model.Grade <= 1) model.Grade = 1;
|
||
else if (count <= item.B && item.B > 0 && model.Grade <= 2) model.Grade = 2;
|
||
else if (count <= item.C && item.C > 0 && model.Grade <= 3) model.Grade = 3;
|
||
else if (count <= item.D && item.D > 0 && model.Grade <= 4) model.Grade = 4;
|
||
else if (count <= item.E && item.E > 0 && model.Grade <= 5) model.Grade = 5;
|
||
else if (count > 0) model.Grade = 6;//不合格
|
||
Log("标准判断", $"({key}) 批号({model.BatchId}),标准={(char)(model.Grade + 64)} [{item.Code}:{count};A<={item.A};B<={item.B};C<={item.C};D<={item.D};E<={item.E}]");
|
||
}
|
||
step = 5;
|
||
}
|
||
model.Qualified = (model.Grade < 6);//是否合格
|
||
if (!RecordService.InsertNav(model))
|
||
throw new Exception("写库失败!");
|
||
Log("入库完成", $"({key}) 批号({model.BatchId})已完成检测。");
|
||
htTask.Remove(key);
|
||
_isDefect = false;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
_isDefect = false;
|
||
if (model == null)
|
||
Log("入库失败", $"记录({key})不存在{step}!" + ex.Message, WarningEnum.High);
|
||
else
|
||
Log("入库失败", $"({key}) 批号({model.BatchId})检测完成,但保存检测记录失败{step}:" + ex.Message, WarningEnum.High);
|
||
}
|
||
}
|
||
#endregion
|
||
|
||
#endregion
|
||
|
||
#region 表格事件查询
|
||
public DefectInfo GetDefectInfo(long uid)
|
||
{
|
||
if (currKey == 0)
|
||
return null;
|
||
Records record = Hashtable.Synchronized(htTask)[currKey] as Records;
|
||
//var defectInfo = record.DefectInfoList[record.DefectInfoList.Count - e.RowIndex-1];//按顺序索引引用
|
||
var defectInfo = record.DefectInfoList.FirstOrDefault(m => m.uid == uid);
|
||
return defectInfo;
|
||
}
|
||
#endregion
|
||
}
|
||
#region 系统事件
|
||
/// <summary>
|
||
/// 流程事件
|
||
/// </summary>
|
||
public class RunEventArgs : EventArgs
|
||
{
|
||
private int _cmd;
|
||
public int Cmd { get { return _cmd; } }
|
||
|
||
private int _picIndex;
|
||
public int PicIndex { get { return _picIndex; } }
|
||
private HObject _pic;
|
||
public HObject Pic { get { return _pic; } }
|
||
public RunEventArgs(int index, HObject pic)
|
||
{
|
||
this._cmd = 6;
|
||
this._picIndex = index;
|
||
this._pic = pic.Clone();
|
||
}
|
||
|
||
private bool _over;
|
||
public bool Over { get { return _over; } }
|
||
public RunEventArgs(bool ov)
|
||
{
|
||
this._cmd = 10;
|
||
this._over = ov;
|
||
}
|
||
|
||
private List<object[]> _dataRowlist = new List<object[]>();
|
||
public List<object[]> DataRowlist { get { return _dataRowlist; } }
|
||
public RunEventArgs(List<object[]> dataRowlist)
|
||
{
|
||
this._cmd = 11;
|
||
this._dataRowlist = dataRowlist;
|
||
}
|
||
|
||
private Image _defectimg;
|
||
public Image Defectimg { get { return _defectimg; } }
|
||
public RunEventArgs(Image defectimg)
|
||
{
|
||
this._cmd = 12;
|
||
this._defectimg = defectimg;
|
||
}
|
||
|
||
private List<float[]> _points;
|
||
public List<float[]> Points { get { return _points; } }
|
||
public RunEventArgs(List<float[]> pints)
|
||
{
|
||
this._cmd = 13;
|
||
this._points = pints;
|
||
}
|
||
|
||
private double _len;
|
||
public double Len { get { return _len; } }
|
||
private double _speed;
|
||
public double Speed { get { return _speed; } }
|
||
public RunEventArgs(double len, double spd)
|
||
{
|
||
this._cmd = 14;
|
||
this._len = len;
|
||
this._speed = spd;
|
||
}
|
||
|
||
private Mat _Matimg;
|
||
public Mat DefectMat { get { return _Matimg; } }
|
||
public RunEventArgs(Mat defectimg)
|
||
{
|
||
this._cmd = 15;
|
||
this._Matimg = defectimg;
|
||
}
|
||
}
|
||
/// <summary>
|
||
/// 主窗体事件
|
||
/// </summary>
|
||
public class MainEventArgs : EventArgs
|
||
{
|
||
private string _tag;
|
||
public string Tag { get { return _tag; } }
|
||
|
||
private string _message;
|
||
public string Message { get { return _message; } }
|
||
|
||
private int _showIndex;
|
||
public int ShowIndex { get { return _showIndex; } }
|
||
|
||
private WarningEnum _warning;
|
||
public WarningEnum Warning { get { return _warning; } }
|
||
public MainEventArgs(int index)
|
||
{
|
||
this._showIndex = index;
|
||
}
|
||
public MainEventArgs(int index, string message)
|
||
{
|
||
this._message = message;
|
||
this._showIndex = index;
|
||
}
|
||
public MainEventArgs(string tag, string message, WarningEnum warning = WarningEnum.Normal)
|
||
{
|
||
this._tag = tag;
|
||
this._message = message;
|
||
this._showIndex = 0;
|
||
this._warning = warning;
|
||
}
|
||
}
|
||
/// <summary>
|
||
/// 初始化事件
|
||
/// </summary>
|
||
public class InitEventArgs : EventArgs
|
||
{
|
||
private string _message;
|
||
public string Message { get { return _message; } }
|
||
|
||
private bool _isInitialized;
|
||
public bool IsInitialized { get { return _isInitialized; } }
|
||
public InitEventArgs()
|
||
{
|
||
|
||
}
|
||
public InitEventArgs(string message, bool isInitialized = false)
|
||
{
|
||
this._message = message;
|
||
this._isInitialized = isInitialized;
|
||
}
|
||
}
|
||
#endregion
|
||
}
|