geboshi_V1/LeatherProject/GeBoShi/SysCtrl/SysMgr.cs

2305 lines
101 KiB
C#
Raw Normal View History

2024-05-21 14:22:10 +08:00
#define Online
using BarTenderPrint;
using CCWin.Win32.Const;
2024-04-01 15:23:50 +08:00
using GeBoShi.ImageDefect;
2024-05-21 14:22:10 +08:00
using HalconDotNet;
2024-04-01 15:23:50 +08:00
using HZH_Controls.Forms;
using MaiMuControl.Device;
2024-05-21 14:22:10 +08:00
using MaiMuControl.Device.CamDev;
2024-04-01 15:23:50 +08:00
using MaiMuControl.Device.IOCardDev;
using MaiMuControl.Device.IOCardDev.Advantech;
using MaiMuControl.Device.LightDev;
using MaiMuControl.Device.LightDev.CST;
using MaiMuControl.Device.LightDev.Rsee;
2024-05-21 14:22:10 +08:00
using MaiMuControl.Device.PlcDev;
2024-04-01 15:23:50 +08:00
using MaiMuControl.SysStatusMgr.CloudMgr;
using MaiMuControl.SysStatusMgr.StatusMgr;
using MaiMuControl.SysStatusMgr.UserMgr;
2024-05-21 14:22:10 +08:00
using MaiMuControl.Utils;
using Models;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using OpenCvSharp;
using OpenCvSharp.Extensions;
using S7.Net;
using SqlSugar;
2024-04-01 15:23:50 +08:00
using System;
2024-05-21 14:22:10 +08:00
using System.Collections;
2024-04-28 14:05:46 +08:00
using System.Collections.Generic;
2024-05-21 14:22:10 +08:00
using System.Data;
using System.Diagnostics;
2024-04-28 14:05:46 +08:00
using System.Drawing;
2024-05-21 14:22:10 +08:00
using System.Drawing.Imaging;
using System.IO;
2024-04-28 14:05:46 +08:00
using System.Linq;
2024-04-01 15:23:50 +08:00
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
2024-05-21 14:22:10 +08:00
using System.Windows.Forms.DataVisualization.Charting;
2024-04-01 15:23:50 +08:00
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; } }
2024-04-28 14:05:46 +08:00
//产品检测列表
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; } }
2024-05-21 14:22:10 +08:00
/// <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();
2024-04-01 15:23:50 +08:00
#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;
2024-05-21 14:22:10 +08:00
private Thread _Cam1Thread;
private Thread _Cam2Thread;
2024-04-01 15:23:50 +08:00
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;
2024-05-21 14:22:10 +08:00
Service.InitDB.ConnectionString = confMgr.DBConStr;
PdtService = new Service.ProductService();
RecordService = new Service.RecordsService();
2024-04-01 15:23:50 +08:00
}
#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);
2024-05-21 14:22:10 +08:00
2024-04-01 15:23:50 +08:00
// 硬件初始化
if (!InitAllDev())
{
throw new Exception("硬件初始化失败...");
}
InitLog("硬件初始化完成!");
// 加载硬件配置
InitLog("加载硬件驱动参数...");
if (!LoadDevConfig())
{
throw new Exception("加载硬件驱动参数失败...");
}
InitLog("加载硬件驱动参数完成!");
//Thread.Sleep(200);
// 处理运行
InitLog("AI算法核心初始化...");
2024-05-21 14:22:10 +08:00
defectLib = new DefectLib();
2024-04-01 15:23:50 +08:00
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()
{
2024-05-21 14:22:10 +08:00
if (defectLib != null)
2024-04-01 15:23:50 +08:00
{
2024-05-21 14:22:10 +08:00
defectLib.WarningEvent = (warning, msg) =>
{
Log("缺陷检测", msg, warning);
};
return true;
}
return false;
2024-04-01 15:23:50 +08:00
}
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();
2024-05-21 14:22:10 +08:00
_Cam1Thread = new Thread(() =>
{
Cam1ThreadFunction();
});
_Cam1Thread.IsBackground = true;
_Cam1Thread.Start();
_Cam2Thread = new Thread(() =>
{
Cam2ThreadFunction();
});
_Cam2Thread.IsBackground = true;
_Cam2Thread.Start();
2024-04-01 15:23:50 +08:00
}
#endregion
#region
/// <summary>
/// 中断工序运行
/// </summary>
/// <returns></returns>
private bool isBreakProcessRun()
{
return statusMgr.Status == SystemStsEnum.Pause || statusMgr.Warning == WarningEnum.High;
}
/// <summary>
2024-05-21 14:22:10 +08:00
/// 相机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>
2024-04-01 15:23:50 +08:00
/// 后台运行主线程
/// </summary>
private void MainThreadFunction()
{
while (true)
{
try
{
if (_cts.IsCancellationRequested)
break;
if (IsRuning)
{
////暂停开始
//stopWatch.Start();
2024-05-21 14:22:10 +08:00
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());
//暂停中断
2024-04-01 15:23:50 +08:00
//stopWatch.Stop();
2024-05-21 14:22:10 +08:00
pStopWatch.Stop();
2024-04-01 15:23:50 +08:00
_isRuning = false;
}
Thread.Sleep(10);
}
catch (Exception e)
{
_isRuning = false;
Log("运行报警", "流程运行出错:" + e.Message + "\n", WarningEnum.High);
}
}
}
2024-05-21 14:22:10 +08:00
#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;
}
2024-04-01 15:23:50 +08:00
#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()
{
2024-04-28 14:05:46 +08:00
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);
}
2024-04-01 15:23:50 +08:00
}
/// <summary>
/// 运行状态三色灯
/// </summary>
public void LedRun()
{
2024-04-28 14:05:46 +08:00
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);
}
2024-04-01 15:23:50 +08:00
}
/// <summary>
/// 暂停状态三色灯
/// </summary>
public void LedPause()
{
2024-04-28 14:05:46 +08:00
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);
}
2024-04-01 15:23:50 +08:00
}
//控制黄灯闪烁
private bool Blink;
private int BlinkCnt = 0;
//控制蜂鸣间隔
private int BuzzCnt = 0;
/// <summary>
/// 回原状态三色灯
/// </summary>
/// <param name="val"></param>
public void LedRset(bool val)
{
2024-04-28 14:05:46 +08:00
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;
}
2024-04-01 15:23:50 +08:00
}
#endregion
2024-05-21 14:22:10 +08:00
#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
2024-04-01 15:23:50 +08:00
#region
/// <summary>
/// 关闭
/// </summary>
public void Close()
{
_isInit = false;
_isRuning = false;
if (null != _cts)
{
_cts.Cancel();
}
if (null != _mainThread)
{
_mainThread.Join(1000);
}
2024-05-21 14:22:10 +08:00
if (null != _Cam1Thread)
{
_Cam1Thread.Join(1000);
}
if (null != _Cam2Thread)
{
_Cam2Thread.Join(1000);
}
2024-04-01 15:23:50 +08:00
//关闭相机
2024-05-21 14:22:10 +08:00
LineCamDev1.CloseCamera();
LineCamDev2.CloseCamera();
2024-04-01 15:23:50 +08:00
//关闭光源
for (int i = 0; i < LightChCount; i++)
{
lightDev.CloseLight(i + 1);
}
lightDev.CloseDev();
//关闭io
2024-04-28 14:05:46 +08:00
if (confMgr.SysConfigParams.OpenIO)
{
ioCardDev.ResetAllDO();
2024-04-01 15:23:50 +08:00
2024-04-28 14:05:46 +08:00
ioCardDev.CloseBoard();
}
2024-04-01 15:23:50 +08:00
}
#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
2024-05-21 14:22:10 +08:00
private CamDev _LinecamDev1;
/// <summary>
/// io控制卡
/// </summary>
public CamDev LineCamDev1 { get { return _LinecamDev1; } }
private CamDev _LinecamDev2;
/// <summary>
/// io控制卡
/// </summary>
public CamDev LineCamDev2 { get { return _LinecamDev2; } }
2024-04-01 15:23:50 +08:00
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通道
2024-05-21 14:22:10 +08:00
private PlcDev plcDev;
/// <summary>
/// PLC控制
/// </summary>
public PlcDev PlcDev { get { return plcDev; } }
2024-04-01 15:23:50 +08:00
private PrintControl printControl;
/// <summary>
/// 打印机模块
/// </summary>
public PrintControl PrintControl { get { return printControl; } }
#endregion
#region IO操作
private void InitDev()
{
ioCardDev = new AdvantechIO();
2024-05-21 14:22:10 +08:00
//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);
2024-04-01 15:23:50 +08:00
if (SysUseLight == LightDevNameEnum.CST)
lightDev = new CSTLight(LightName, LightChCount);
else
2024-05-21 14:22:10 +08:00
lightDev = new RseeLight(SysUseLight, LightName);
2024-04-01 15:23:50 +08:00
}
/// <summary>
/// 初始化硬件
/// </summary>
/// <returns></returns>
private bool InitAllDev()
{
bool ret = false;
InitDev();
2024-05-21 14:22:10 +08:00
#if Online
2024-04-01 15:23:50 +08:00
//打印机模块初始化
InitLog("打印机模块初始化...");
try
{
printControl = new PrintControl();
InitLog("初始化打印机模块成功!");
}
catch (Exception ex)
{
printControl = null;
InitLog($"初始化打印机模块失败! {ex.Message}");
}
2024-04-28 14:05:46 +08:00
if (confMgr.SysConfigParams.OpenPLC)
2024-04-01 15:23:50 +08:00
{
//PLC初始化
InitLog("PLC连接初始化...");
2024-05-21 14:22:10 +08:00
if(!plcDev.OpenDev())
{
InitLog("PLC连接初始化失败", "初始化", WarningEnum.High);
return ret;
}
2024-04-01 15:23:50 +08:00
InitLog("PLC连接成功");
}
2024-04-28 14:05:46 +08:00
if (confMgr.SysConfigParams.OpenIO)
2024-04-01 15:23:50 +08:00
{
//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板卡成功");
}
2024-05-21 14:22:10 +08:00
//相机初始化
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;
2024-04-01 15:23:50 +08:00
//光源初始化
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);
2024-05-21 14:22:10 +08:00
}
#endif
2024-04-01 15:23:50 +08:00
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;
}
2024-05-21 14:22:10 +08:00
#endregion
#endregion
2024-04-01 15:23:50 +08:00
#region
public static bool CheckDisk(IWin32Window owner, int max = 10)
{
2024-04-28 14:05:46 +08:00
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;
}
2024-04-01 15:23:50 +08:00
}
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);
}
}
2024-05-21 14:22:10 +08:00
/// <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);
}
}
2024-04-01 15:23:50 +08:00
#endregion
2024-04-28 14:05:46 +08:00
#region
/// <summary>
/// 加载产品列表
/// </summary>
public void LoadProductCodeList()
{
try
{
2024-05-21 14:22:10 +08:00
productCodeList = PdtService.GetListNav().Select(m => m.Name).ToList();
productIdList = PdtService.GetListNav().Select(m => m.Id).ToList();
2024-04-28 14:05:46 +08:00
}
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
2024-05-21 14:22:10 +08:00
#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
2024-04-01 15:23:50 +08:00
}
#region
/// <summary>
2024-05-21 14:22:10 +08:00
/// 流程事件
2024-04-01 15:23:50 +08:00
/// </summary>
2024-05-21 14:22:10 +08:00
public class RunEventArgs : EventArgs
2024-04-01 15:23:50 +08:00
{
2024-05-21 14:22:10 +08:00
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;
}
2024-04-01 15:23:50 +08:00
}
/// <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
}