geboshi_V1/LeatherProject/GeBoShi/SysCtrl/SysMgr.cs

2305 lines
101 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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
}