using Bro.Common.Base; using Bro.Common.Helper; using Bro.Common.Interface; using Bro.Common.Model; using Bro.Device.InsCamera; using Bro.M135.Common; using Bro.M135.DBManager; using Bro.Process; using Bro.Process.DataBase.Models; using Bro.UI.Model.Winform; using HalconDotNet; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using NPOI.SS.Formula.Functions; using Org.BouncyCastle.Asn1.X509; using Org.BouncyCastle.Ocsp; using ScottPlot.Drawing.Colormaps; using Sunny.UI; using Sunny.UI.Win32; using System.Collections.Concurrent; using System.Collections.Generic; using System.Drawing.Imaging; using System.IO; using System.Linq; using Windows.ApplicationModel.Appointments; using Windows.Networking; using static Org.BouncyCastle.Math.EC.ECCurve; namespace Bro.M141.Process { public partial class M141Process : ProcessControl { #region constructor public M141Process() { } public M141Process(string productCode) : base(productCode) { } #endregion public event Action OnSinglePostionDetectResultUpdate; protected M141Config M141Config => Config as M141Config; public static object _productListLock = new object(); public List ProductList = new List(); MachineLearningBase ML = null; TcpListenerWrap TcpListener = null; Spec _errorSpec = null; public List ProductSpecResultList { get; set; } = new List(); TcpListenerWrap _realTimeServer = null; volatile int _productIndex = 0; int _backgroundImageWidth = 2448; public event Action> OnPositionResultUpdated; public event Action OnNewProductEnqueued; public event Action OnProductDequeued; public event Action> RefreshUIplc; public event Action RefreshState; List ZipImages = new List(); List OKNGImages = new List(); public override void InitialProcessMethods() { base.InitialProcessMethods(); OldDataClear.Instance.RunClearOldData(M141Config.DBDataTimeLimit); InitialInspectionConfig(); InitialSummaryData(); } public override void ProcessRunStateChanged() { base.ProcessRunStateChanged(); if (CurrentState == EnumHelper.RunState.Running) { OldDataClear.Instance.SetAllowFlag(false, M141Config.DBDataTimeLimit); } else { OldDataClear.Instance.SetAllowFlag(true, M141Config.DBDataTimeLimit); } } public PLCBase Plc1; Thread ThHeartPlc; public override void Open() { base.Open(); ML = DeviceCollection.FirstOrDefault(u => u is MachineLearningBase) as MachineLearningBase; if (ML == null) { LogAsync(DateTime.Now, EnumHelper.LogLevel.Information, $"未设置ML实例"); } Plc1 = DeviceCollection.FirstOrDefault(u => u is PLCBase) as PLCBase; if (Plc1 == null) { LogAsync(DateTime.Now, EnumHelper.LogLevel.Error, $"未设置plc"); } _errorSpec = M141Config.SpecCollection.FirstOrDefault(u => u.Code == M141Config.CheckErrorSpecCode) as Spec; InitialProductList(); NetWarmUp(); _positionCheckTimeDict.Clear(); _positionSpecHeads.Clear(); if (ThHeartPlc == null) { ThHeartPlc = new Thread(Heartplc); ThHeartPlc.IsBackground = true; ThHeartPlc.Start(); } InitialContinuousNGAlarm(); } public void Heartplc() { int state = 0; int state2 = 0; while (true) { try { Plc1.WriteSingleAddress(3009, 2, out _); } catch { } Thread.Sleep(1000); try { var tem = Plc1.Read(3030, 17, out _); if (tem != null && RefreshUIplc != null) { RefreshUIplc.Invoke(tem); } } catch { } try { var tem = Plc1.Read(3010, 8, out _); if (tem != null && RefreshUIplc != null) { RefreshUIplc.Invoke(tem); } } catch { } try { var tem = Plc1.Read(3027, 1, out _)[0]; var tem2 = Plc1.Read(3028, 1, out _)[0]; if (state != tem || state2 != tem2) { state = tem; state2 = tem2; if (RefreshState != null) { if (state == 1) { RefreshState.Invoke("调试模式"); } else if (state2 == 1) { RefreshState.Invoke("离线模式"); } else { RefreshState.Invoke("正常模式"); } } } } catch { } } } public void PlcWrite(int add, int va) { try { Plc1.WriteSingleAddress(add, va, out _); var tem = Plc1.Read(3030, 16, out _); if (tem != null && RefreshUIplc != null) { RefreshUIplc.Invoke(tem); } } catch { } } /// /// 网络预热 /// /// private void NetWarmUp() { string warmUpImageFolder = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "WarmUp"); if (!Directory.Exists(warmUpImageFolder)) { LogAsync(DateTime.Now, EnumHelper.LogLevel.Error, $"程序根目录下没有\"WarmUp\"预热图片文件夹"); return; } var ml = DeviceCollection.FirstOrDefault(u => u is MachineLearningBase && u.CurrentState == EnumHelper.DeviceState.DSOpen) as MachineLearningBase; if (ml == null) { LogAsync(DateTime.Now, EnumHelper.LogLevel.Error, $"预热时未能获取开启的深度学习驱动"); return; } var netNames = ml.IConfig.NetCollections.Where(u => u.IsEnabled).Select(u => u.Name).ToList(); var imageFiles = new DirectoryInfo(warmUpImageFolder).GetFiles().Select(u => u.FullName).ToList(); Parallel.ForEach(netNames, n => { Parallel.ForEach(imageFiles, i => { HImage hImage = new HImage(); hImage.ReadImage(i); ml.RunNetEvaluate(n, hImage); hImage.Dispose(); hImage = null; }); }); LogAsync(DateTime.Now, EnumHelper.LogLevel.Action, "深度学习驱动预热完成"); if (M141Config.WarmUp && M141Config.WarmUpList.Count > 0) { M141Config.WarmUpList.AsParallel().ForAll(x => { try { HImage im = new HImage(x.PicFilePath); var tool = GetHalconTool(null, "", x.HalconFilePath); if (tool != null) { //int num = 0; //for (int i = 0; i < 10; i++) //{ try { var res = tool.RunProcedure(null, new Dictionary() { { "INPUT_Image", im } }, new List() { "OUTPUT_Results_1", "OUTPUT_Results_2" }, null); //if (res != null) //{ // if (res.Item1&& res.Item2[$"OUTPUT_Results_{i}"].HTupleToDouble()[0]!=-1234) // { // num++; // if (num >= 2) // { // LogAsync(DateTime.Now, EnumHelper.LogLevel.Detail, $"算法{x.HalconFilePath}预热完成{i}"); // break; // } // } //} } catch { } //if (i==9) //{ // LogAsync(DateTime.Now, EnumHelper.LogLevel.Error, $"算法{x.HalconFilePath}预热失败{num}"); //} //} } im.Dispose(); } catch { LogAsync(DateTime.Now, EnumHelper.LogLevel.Error, $"算法{x.HalconFilePath}预热失败"); } }); } LogAsync(DateTime.Now, EnumHelper.LogLevel.Action, "算法预热完成"); } static object _positionCheckTimeLock = new object(); Dictionary> _positionCheckTimeDict = new Dictionary>(); Dictionary> _positionSpecHeads = new Dictionary>(); public ResponseMessage RunImageCheck(IOperationConfig config) { ResponseMessage msg = new ResponseMessage(); msg.Result = 1; List measureBinds = new List(); string inputSequence = ""; var triggerDatas = config.TriggerStr.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); try { RunImageCheckPreTreat(config, out measureBinds, out inputSequence); } catch (Exception ex) { LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, $"检测预处理异常,{ex.GetExceptionMessage()}"); msg.Result = -1; msg.Message = ex.Message; return msg; } List cameraIds = measureBinds.Select(u => u.CameraId).ToList(); try { ConcurrentDictionary imgSetDicts = new ConcurrentDictionary(); measureBinds.AsParallel().ForAll(b => { var camera = DeviceCollection.FirstOrDefault(u => u.Id == b.CameraId) as CameraBase; if (camera == null) { LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, $"检测配置{b.GetDisplayText()}未能获取相机设备"); imgSetDicts[b] = null; return; } imgSetDicts[b] = null; //if (config.TriggerStr.Split(',')[0].Contains("2")) //{ //camera.ClearImageBufferQueue(); try { imgSetDicts[b] = CollectHImage(camera, b.SnapshotOpConfig); camera.ClearImageBufferQueue(); } catch (Exception ea) { LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, $"工位{measureBinds[0].WorkPosition}的第{measureBinds[0].CheckIndex}检测获取图像信息异常 {ea.ToString()}"); } finally { //try //{ // if (imgSetDicts[b] == null || imgSetDicts[b].HImage == null) // { // LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, $"工位{measureBinds[0].WorkPosition}的第{measureBinds[0].CheckIndex}检测获取图像信息为null "); // //if (camera is InsCameraDriver insCamera) // //{ // // insCamera.Restart(); // //} // } //} //catch (Exception ec) //{ // LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, "ins相机重连异常" + ec.ToString()); //} } var pList = b.ProductIndices.Select(pi => { string pid = $"{inputSequence}_{pi}"; return FindProductBySequence(pid, true); }).ToList(); RunImageCheckAsync(pList, config.TriggerStr, config.TriggerSource, imgSetDicts[b], b); }); //if (imgSetDicts.Values.Any(u => u == null || u.HImage == null)) //{ // //msg.Result = -1; // //msg.Message = $"工位{measureBinds[0].WorkPosition}的第{measureBinds[0].CheckIndex}检测获取图像信息失败"; // //return msg; // throw new ProcessException($"工位{measureBinds[0].WorkPosition}的第{measureBinds[0].CheckIndex}检测获取图像信息失败"); //} } catch (Exception ex) { LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, $"检测处理异常,{ex.GetExceptionMessage()}"); msg.Result = -1; msg.Message = ex.Message; return msg; } //if (triggerDatas[0].Contains("1")) //{ // msg.Result = -1; // return msg; //} CheckPositionDoneAsync(measureBinds[0].WorkPosition, inputSequence, config, cameraIds); return msg; } public ResponseMessage RunImageCheck1(IOperationConfig config) { ResponseMessage msg = new ResponseMessage(); msg.Result = 1; List measureBinds = new List(); string inputSequence = ""; try { RunImageCheckPreTreat1(config, out measureBinds, out inputSequence); } catch (Exception ex) { LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, $"检测预处理异常,{ex.GetExceptionMessage()}"); msg.Result = -1; msg.Message = ex.Message; return msg; } List cameraIds = measureBinds.Select(u => u.CameraId).ToList(); try { ConcurrentDictionary imgSetDicts = new ConcurrentDictionary(); measureBinds.AsParallel().ForAll(b => { var camera = DeviceCollection.FirstOrDefault(u => u.Id == b.CameraId) as CameraBase; if (camera == null) { LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, $"检测配置{b.GetDisplayText()}未能获取相机设备"); imgSetDicts[b] = null; return; } imgSetDicts[b] = null; try { imgSetDicts[b] = CollectHImage(camera, b.SnapshotOpConfig); camera.ClearImageBufferQueue(); } catch (Exception ea) { LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, $"工位{measureBinds[0].WorkPosition}的第{measureBinds[0].CheckIndex}检测获取图像信息失败 {ea.ToString()}"); } var pList = b.ProductIndices.Select(pi => { string pid = $"{inputSequence}_{pi}"; return FindProductBySequence(pid, true); }).ToList(); RunImageCheckAsync(pList, config.TriggerStr, config.TriggerSource, imgSetDicts[b], b); }); //DateTime.Now.DayOfWeek } catch (Exception ex) { LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, $"检测处理异常,{ex.GetExceptionMessage()}"); msg.Result = -1; msg.Message = ex.Message; return msg; } CheckPositionDoneAsync1(measureBinds[0].WorkPosition, inputSequence, config, cameraIds); return msg; } public void RunImageCheckPreTreat1(IOperationConfig config, out List measureBinds, out string inputSequence) { Task.Run(() => { SetProcessRunState(EnumHelper.RunState.Running); }); measureBinds = new List(); inputSequence = ""; var triggerDatas = config.TriggerStr.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); if (triggerDatas.Length < 2) { throw new ProcessException($"触发文本{config.TriggerStr}解析失败,数据长度小于2"); } string positionValue = triggerDatas[0]; int checkIndex = -1; if (!int.TryParse(triggerDatas[1], out checkIndex)) { throw new ProcessException($"触发文本{config.TriggerStr}解析失败,未能获取检测序号"); } var positionSet = M141Config.WorkPositionCollection.Where(u => u.IsEnabled).FirstOrDefault(u => u.TriggerValue == positionValue); if (positionSet == null) { throw new ProcessException($"触发文本{config.TriggerStr}未能获取{positionValue}对应的可用工位信息"); } measureBinds = M141Config.MeasureBindCollection.Where(u => u.WorkPosition == positionSet.PositionName && u.CheckIndex == checkIndex).ToList(); if (measureBinds.Count == 0) { throw new ProcessException($"未能获取工位{positionSet.PositionName}的第{checkIndex}检测配置信息"); } measureBinds.Select(u => u.CameraId).ToList().ForEach(c => { var camera = DeviceCollection.FirstOrDefault(u => u.Id == c) as CameraBase; if (camera != null) { camera.ClearImageBufferQueue(); LogAsync(DateTime.Now, EnumHelper.LogLevel.Action, $"相机{camera.Name}检测前清理缓存完成"); } }); if (positionSet.IsSendClearSingal) { var sourceData = config.TriggerSource.Split(':'); string ip = ""; int port = 0; if (sourceData.Length >= 2) { ip = sourceData[0]; port = int.Parse(sourceData[1]); } TcpListener?.WriteAndRead(positionSet.ClearStr, out _, out _, false, ip, port); } inputSequence = triggerDatas[triggerDatas.Length - 1]; string tempPID = inputSequence; string pidstr = DateTime.Now.ToString("yyyyMMddHHmmssfff"); measureBinds.Where(b => b.IsFirstPosition).ToList().ForEach(b => { b.ProductIndices.ForEach(i => { ProductModel p = new ProductModel(); p.SEQUENCE = $"{tempPID}_{i}"; p.PID = $"{pidstr}T_{i}"; p.Initial(M141Config.StationCode, M141Config.WorkPositionCollection.Select(u => u.PositionName).ToList()); NewProductIntoList(p, true); }); }); int de = 2; //if (triggerDatas[0].Contains("11111")) //{ // de = 2; //} //else //{ // de = 2; //} measureBinds.Where(b => (b.CheckIndex == de || b.CheckIndex == 1) && b.ImageIndex == 0).AsParallel().ForAll(b => { List temint = new List(); if (triggerDatas[0].Contains("11111")) { if (triggerDatas[1] == "1") { temint = new List() { 1 }; } else { temint = new List() { 2 }; } } else { temint = new List() { 1, 2 }; } //new List() { 1, 2 }.ForEach(i => temint.ForEach(i => { string sequence = $"{tempPID}_{i}"; var p = FindProductBySequence(sequence, b.IsEnabelQueryFromQueue); //初始化产品的检测次数 var checkIndexList = M141Config.MeasureBindCollection.Where(u => u.WorkPosition == b.WorkPosition && u.ProductIndices.Contains(i)).Select(u => u.CheckIndex).OrderBy(u => u).ToList(); p.InitialPositionCheckList(b.WorkPosition, checkIndexList); //p.ClearPositionResult(M141Config.StationCode, b.WorkPosition); LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"产品{p.PID}_{p.SEQUENCE}已清理{b.WorkPosition}检测数据。当前已完成工位{string.Join(",", p.Details.Select(u => u.PositionName))}"); }); //初始化工位的检测次数 var positionCheckTimes = M141Config.MeasureBindCollection.Where(u => u.WorkPosition == b.WorkPosition).Select(u => u.CheckIndex).ToList(); lock (_positionCheckTimeLock) { _positionCheckTimeDict[b.WorkPosition] = positionCheckTimes; LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"工位{b.WorkPosition}初始化检测次数:{string.Join(",", positionCheckTimes)}"); } }); measureBinds.AsParallel().ForAll(b => { lock (_positionCheckTimeLock) { _positionCheckTimeDict[b.WorkPosition].RemoveAll(u => u == b.CheckIndex); LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"工位{b.WorkPosition}开始第{b.CheckIndex}次检测,待检测序号:{string.Join(",", _positionCheckTimeDict[b.WorkPosition])}"); } }); } public void RunImageCheckPreTreat(IOperationConfig config, out List measureBinds, out string inputSequence) { Task.Run(() => { SetProcessRunState(EnumHelper.RunState.Running); }); measureBinds = new List(); inputSequence = ""; var triggerDatas = config.TriggerStr.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); if (triggerDatas.Length < 2) { throw new ProcessException($"触发文本{config.TriggerStr}解析失败,数据长度小于2"); } string positionValue = triggerDatas[0]; int checkIndex = -1; if (!int.TryParse(triggerDatas[1].Replace("Scan", ""), out checkIndex)) { throw new ProcessException($"触发文本{config.TriggerStr}解析失败,未能获取检测序号"); } var positionSet = M141Config.WorkPositionCollection.Where(u => u.IsEnabled).FirstOrDefault(u => u.TriggerValue == positionValue); if (positionSet == null) { throw new ProcessException($"触发文本{config.TriggerStr}未能获取{positionValue}对应的可用工位信息"); } measureBinds = M141Config.MeasureBindCollection.Where(u => u.WorkPosition == positionSet.PositionName && u.CheckIndex == checkIndex).ToList(); if (measureBinds.Count == 0) { throw new ProcessException($"未能获取工位{positionSet.PositionName}的第{checkIndex}检测配置信息"); } measureBinds.Select(u => u.CameraId).ToList().ForEach(c => { var camera = DeviceCollection.FirstOrDefault(u => u.Id == c) as CameraBase; if (camera != null) { camera.ClearImageBufferQueue(); LogAsync(DateTime.Now, EnumHelper.LogLevel.Action, $"相机{camera.Name}检测前清理缓存完成"); } }); if (positionSet.IsSendClearSingal) { var sourceData = config.TriggerSource.Split(':'); string ip = ""; int port = 0; if (sourceData.Length >= 2) { ip = sourceData[0]; port = int.Parse(sourceData[1]); } TcpListener?.WriteAndRead(positionSet.ClearStr, out _, out _, false, ip, port); } inputSequence = triggerDatas[triggerDatas.Length - 1]; string tempPID = inputSequence; string pidstr = DateTime.Now.ToString("yyyyMMddHHmmssfff"); measureBinds.Where(b => b.IsFirstPosition).ToList().ForEach(b => { b.ProductIndices.ForEach(i => { ProductModel p = new ProductModel(); p.SEQUENCE = $"{tempPID}_{i}"; p.PID = $"{pidstr}T_{i}"; p.Initial(M141Config.StationCode, M141Config.WorkPositionCollection.Select(u => u.PositionName).ToList()); NewProductIntoList(p, true); }); }); int de = 0; if (triggerDatas[0].Contains("1") || triggerDatas[0].Contains("0")) { de = 2; } else { de = 1; } measureBinds.Where(b => (b.CheckIndex == de || b.CheckIndex == 1) && b.ImageIndex == 0).AsParallel().ForAll(b => { List temint = new List(); if (triggerDatas[0].Contains("1") || triggerDatas[0].Contains("0")) { if (triggerDatas[1].Contains("1")) { temint = new List() { 1 }; } else { temint = new List() { 2 }; } } else { temint = new List() { 1, 2 }; } //new List() { 1, 2 }.ForEach(i => temint.ForEach(i => { string sequence = $"{tempPID}_{i}"; var p = FindProductBySequence(sequence, b.IsEnabelQueryFromQueue); //初始化产品的检测次数 var checkIndexList = M141Config.MeasureBindCollection.Where(u => u.WorkPosition == b.WorkPosition && u.ProductIndices.Contains(i)).Select(u => u.CheckIndex).OrderBy(u => u).ToList(); p.InitialPositionCheckList(b.WorkPosition, checkIndexList); //p.ClearPositionResult(M141Config.StationCode, b.WorkPosition); LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"产品{p.PID}_{p.SEQUENCE}已清理{b.WorkPosition}检测数据。当前已完成工位{string.Join(",", p.Details.Select(u => u.PositionName))}"); }); //初始化工位的检测次数 var positionCheckTimes = M141Config.MeasureBindCollection.Where(u => u.WorkPosition == b.WorkPosition).Select(u => u.CheckIndex).ToList(); lock (_positionCheckTimeLock) { _positionCheckTimeDict[b.WorkPosition] = positionCheckTimes; LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"工位{b.WorkPosition}初始化检测次数:{string.Join(",", positionCheckTimes)}"); } }); measureBinds.AsParallel().ForAll(b => { lock (_positionCheckTimeLock) { _positionCheckTimeDict[b.WorkPosition].RemoveAll(u => u == b.CheckIndex); LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"工位{b.WorkPosition}开始第{b.CheckIndex}次检测,待检测序号:{string.Join(",", _positionCheckTimeDict[b.WorkPosition])}"); } }); } public async Task> CheckPositionDoneAsync(string positionName, string inputSequence, IOperationConfig config, List cameraIds) { string triggerSource = config.TriggerSource; return await _taskFactory.StartNew(() => { try { if (positionName.Contains("1") || positionName.Contains("0")) { string index = config.TriggerStr.Split(',')[1]; var positionSet = M141Config.WorkPositionCollection.FirstOrDefault(u => u.PositionName == positionName); var checkRemains = _positionCheckTimeDict[positionName]; //if (checkRemains.Count != 0) //{ // LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"工位{positionName}检测未完成,剩余:{string.Join(",", checkRemains)}"); // return null; //} string replyData = M141Config.WorkPositionCollection.FirstOrDefault(u => u.PositionName == positionName).TriggerValue; //if (checkRemains.Count != 0) //{ replyData += "," + index; //} //else //{ // replyData += ",2"; //} var pIndices = M141Config.MeasureBindCollection.Where(u => u.WorkPosition == positionName).SelectMany(u => u.ProductIndices).Distinct().OrderBy(u => u).ToList(); if (index.Contains("1")) { pIndices = new List { 1 }; } else { pIndices = new List { 2 }; } //var measureNum = M141Config.MeasureBindCollection.Count(u => u.WorkPosition == positionName && u.ProductIndices.Contains(pIndices[0])); //if (measureNum > 1) //{ // replyData += ",C"; //} var pList = pIndices.Select(u => { string sequence = $"{inputSequence}_{u}"; return FindProductBySequence(sequence, true); }).ToList(); if (pList.Any(u => u == null)) { LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, $"获取工位{positionName}汇总结果时产品信息为空"); pList.ForEach(u => { replyData += ",NG"; }); } else { int waitInterval = 300; int repeatTime = M141Config.DetectTimeout / waitInterval; do { if (!pList.All(p => { p.GetPositionResult(M141Config.StationCode, positionName, out P_PRODUCT_DETAIL detail); return detail?.IsDone ?? false; })) { Thread.Sleep(waitInterval); repeatTime--; } else { LogAsync(DateTime.Now, EnumHelper.LogLevel.Action, $"成功完成工位{positionName}产品{string.Join(",", pList.Select(u => $"{u.PID}_{u.SEQUENCE}"))}检测"); break; } if (repeatTime < 0) { LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, $"工位{positionName}产品{string.Join(",", pList.Select(u => $"{u.PID}_{u.SEQUENCE}"))}检测获取结果超时"); break; } } while (true); } pList.ForEach(p => { var isOK = p.GetPositionResult(M141Config.StationCode, positionName, out P_PRODUCT_DETAIL detail); replyData += $",{(isOK ? "OK" : "NG")}"; List specHeads = new List(); string head = p.GetCSVHead(ref specHeads, positionName); if (!_positionSpecHeads.ContainsKey(positionName)) { _positionSpecHeads[positionName] = specHeads; } string data = p.GetCSVData(_positionSpecHeads[positionName], positionName); CSVRecordAsync($"{positionName}_Record_{DateTime.Now.ToString("yyyyMMdd")}.csv", data, head); UpdatePositionResultToDB(detail); var seqData = p.SEQUENCE.Split(new char[] { '_' }, StringSplitOptions.RemoveEmptyEntries).ToList(); UpdatePositionResultDisplay(detail, isOK, positionName, seqData[seqData.Count - 1]); if (IsInspectionDoing) { OnSinglePostionDetectResultUpdate.Invoke(positionName, detail, seqData[seqData.Count - 1]); } if (positionSet.IsLastPosition) { UpdateProductResultAsync(p); UpdateOverAllProductResultToUI(p, isOK); OnNewProductEnqueued?.Invoke(p); OnProductDequeued?.Invoke(p); } SetSpecResult(p); }); if (positionSet.IsLastPosition) { if (_ct != null) { UpdateCT(null, (float)((DateTime.Now - _ct.Value).TotalSeconds / 2.0)); } _ct = DateTime.Now; } //replyData += ",No Read,No Read"; if (positionName.Contains("0")) { var isOK = pList[0].GetPositionResult(M141Config.StationCode, positionName, out P_PRODUCT_DETAIL detail); if (index.Contains("1")) { replyData = "0#,Scan1,Scan" + (isOK ? "OK" : "NG") + "1"; } else { replyData = "0#,Scan2,Scan" + (isOK ? "OK" : "NG") + "2"; //replyData = "0#,Scan2,ScanOK2"; } } ReplyTcpData(positionName, triggerSource, replyData); cameraIds.ForEach(c => { var camera = DeviceCollection.FirstOrDefault(u => u.Id == c) as CameraBase; if (camera != null) { camera.ClearImageBufferQueue(); LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"相机{camera.Name}清理缓存"); } }); return pList; } else { var positionSet = M141Config.WorkPositionCollection.FirstOrDefault(u => u.PositionName == positionName); var checkRemains = _positionCheckTimeDict[positionName]; if (checkRemains.Count != 0) { LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"工位{positionName}检测未完成,剩余:{string.Join(",", checkRemains)}"); return null; } LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"工位{positionName}检测已完成,等待输出结果"); string replyData = M141Config.WorkPositionCollection.FirstOrDefault(u => u.PositionName == positionName).TriggerValue; var pIndices = M141Config.MeasureBindCollection.Where(u => u.WorkPosition == positionName).SelectMany(u => u.ProductIndices).Distinct().OrderBy(u => u).ToList(); var measureNum = M141Config.MeasureBindCollection.Count(u => u.WorkPosition == positionName && u.ProductIndices.Contains(pIndices[0])); if (measureNum > 1) { replyData += ",C"; } var pList = pIndices.Select(u => { string sequence = $"{inputSequence}_{u}"; return FindProductBySequence(sequence, true); }).ToList(); if (pList.Any(u => u == null)) { LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, $"获取工位{positionName}汇总结果时产品信息为空"); pList.ForEach(u => { replyData += ",NG"; }); } else { int waitInterval = 300; int repeatTime = M141Config.DetectTimeout / waitInterval; do { if (!pList.All(p => { p.GetPositionResult(M141Config.StationCode, positionName, out P_PRODUCT_DETAIL detail); return detail?.IsDone ?? false; })) { Thread.Sleep(waitInterval); repeatTime--; } else { LogAsync(DateTime.Now, EnumHelper.LogLevel.Action, $"成功完成工位{positionName}产品{string.Join(",", pList.Select(u => $"{u.PID}_{u.SEQUENCE}"))}检测"); break; } if (repeatTime < 0) { LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, $"工位{positionName}产品{string.Join(",", pList.Select(u => $"{u.PID}_{u.SEQUENCE}"))}检测获取结果超时"); break; } } while (true); } pList.ForEach(p => { var isOK = p.GetPositionResult(M141Config.StationCode, positionName, out P_PRODUCT_DETAIL detail); replyData += $",{(isOK ? "OK" : "NG")}"; List specHeads = new List(); string head = p.GetCSVHead(ref specHeads, positionName); if (!_positionSpecHeads.ContainsKey(positionName)) { _positionSpecHeads[positionName] = specHeads; } string data = p.GetCSVData(_positionSpecHeads[positionName], positionName); CSVRecordAsync($"{positionName}_Record_{DateTime.Now.ToString("yyyyMMdd")}.csv", data, head); UpdatePositionResultToDB(detail); var seqData = p.SEQUENCE.Split(new char[] { '_' }, StringSplitOptions.RemoveEmptyEntries).ToList(); UpdatePositionResultDisplay(detail, isOK, positionName, seqData[seqData.Count - 1]); if (IsInspectionDoing) { OnSinglePostionDetectResultUpdate.Invoke(positionName, detail, seqData[seqData.Count - 1]); } if (positionSet.IsLastPosition) { UpdateProductResultAsync(p); UpdateOverAllProductResultToUI(p, isOK); OnNewProductEnqueued?.Invoke(p); OnProductDequeued?.Invoke(p); } SetSpecResult(p); }); if (positionSet.IsLastPosition) { if (_ct != null) { UpdateCT(null, (float)((DateTime.Now - _ct.Value).TotalSeconds / 2.0)); } _ct = DateTime.Now; } replyData += "," + pList[0]?.SN + "," + pList[1]?.SN; ReplyTcpData(positionName, triggerSource, replyData); cameraIds.ForEach(c => { var camera = DeviceCollection.FirstOrDefault(u => u.Id == c) as CameraBase; if (camera != null) { camera.ClearImageBufferQueue(); LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"相机{camera.Name}清理缓存"); } }); return pList; } } catch (Exception ex) { LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, ex.ToString()); return null; } }); } public async Task> CheckPositionDoneAsync1(string positionName, string inputSequence, IOperationConfig config, List cameraIds) { string triggerSource = config.TriggerSource; return await _taskFactory.StartNew(() => { var positionSet = M141Config.WorkPositionCollection.FirstOrDefault(u => u.PositionName == positionName); var checkRemains = _positionCheckTimeDict[positionName]; if (checkRemains.Count != 0) { LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"工位{positionName}检测未完成,剩余:{string.Join(",", checkRemains)}"); return null; } LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"工位{positionName}检测已完成,等待输出结果"); string replyData = M141Config.WorkPositionCollection.FirstOrDefault(u => u.PositionName == positionName).TriggerValue; var pIndices = M141Config.MeasureBindCollection.Where(u => u.WorkPosition == positionName).SelectMany(u => u.ProductIndices).Distinct().OrderBy(u => u).ToList(); var measureNum = M141Config.MeasureBindCollection.Count(u => u.WorkPosition == positionName && u.ProductIndices.Contains(pIndices[0])); if (measureNum > 1) { replyData += ",C"; } var pList = pIndices.Select(u => { string sequence = $"{inputSequence}_{u}"; return FindProductBySequence(sequence, true); }).ToList(); if (pList.Any(u => u == null)) { LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, $"获取工位{positionName}汇总结果时产品信息为空"); pList.ForEach(u => { replyData += ",NG"; }); } else { int waitInterval = 300; int repeatTime = M141Config.DetectTimeout / waitInterval; do { if (!pList.All(p => { p.GetPositionResult(M141Config.StationCode, positionName, out P_PRODUCT_DETAIL detail); return detail?.IsDone ?? false; })) { Thread.Sleep(waitInterval); repeatTime--; } else { LogAsync(DateTime.Now, EnumHelper.LogLevel.Action, $"成功完成工位{positionName}产品{string.Join(",", pList.Select(u => $"{u.PID}_{u.SEQUENCE}"))}检测"); break; } if (repeatTime < 0) { LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, $"工位{positionName}产品{string.Join(",", pList.Select(u => $"{u.PID}_{u.SEQUENCE}"))}检测获取结果超时"); break; } } while (true); } pList.ForEach(p => { var isOK = p.GetPositionResult(M141Config.StationCode, positionName, out P_PRODUCT_DETAIL detail); replyData += $",{(isOK ? "OK" : "NG")}"; List specHeads = new List(); string head = p.GetCSVHead(ref specHeads, positionName); if (!_positionSpecHeads.ContainsKey(positionName)) { _positionSpecHeads[positionName] = specHeads; } string data = p.GetCSVData(_positionSpecHeads[positionName], positionName); CSVRecordAsync($"{positionName}_Record_{DateTime.Now.ToString("yyyyMMdd")}.csv", data, head); UpdatePositionResultToDB(detail); var seqData = p.SEQUENCE.Split(new char[] { '_' }, StringSplitOptions.RemoveEmptyEntries).ToList(); UpdatePositionResultDisplay(detail, isOK, positionName, seqData[seqData.Count - 1]); if (IsInspectionDoing) { OnSinglePostionDetectResultUpdate.Invoke(positionName, detail, seqData[seqData.Count - 1]); } if (positionSet.IsLastPosition) { UpdateProductResultAsync(p); UpdateOverAllProductResultToUI(p, isOK); OnNewProductEnqueued?.Invoke(p); OnProductDequeued?.Invoke(p); } SetSpecResult(p); }); if (positionSet.IsLastPosition) { if (_ct != null) { UpdateCT(null, (float)((DateTime.Now - _ct.Value).TotalSeconds / 2.0)); } _ct = DateTime.Now; } replyData += "," + pList[0].SN + "," + pList[1].SN; if (!positionName.Contains("0")) { ReplyTcpData(positionName, triggerSource, replyData); } else { //replyData += "," + pList[0].SN=="NOREAD" + "," + pList[1]?.SN; //replyData = "0#,2,"+ ((pList[0].SN == "NOREAD" || pList[1]?.SN=="NOREAD")? "NG":"OK") +","+ pList[0].SN+ ","+ pList[1].SN; replyData = "0#,2,OK," + pList[0].SN + "," + pList[1].SN; ReplyTcpData(positionName, triggerSource, replyData); } cameraIds.ForEach(c => { var camera = DeviceCollection.FirstOrDefault(u => u.Id == c) as CameraBase; if (camera != null) { camera.ClearImageBufferQueue(); LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"相机{camera.Name}清理缓存"); } }); return pList; }); } public async Task> CheckPositionDoneAsyncforsb(string positionName, string inputSequence, IOperationConfig config, List cameraIds) { string triggerSource = config.TriggerSource; return await _taskFactory.StartNew(() => { var positionSet = M141Config.WorkPositionCollection.FirstOrDefault(u => u.PositionName == positionName); var checkRemains = _positionCheckTimeDict[positionName]; if (checkRemains.Count != 0) { LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"工位{positionName}检测未完成,剩余:{string.Join(",", checkRemains)}"); return null; } LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"工位{positionName}检测已完成,等待输出结果"); string replyData = M141Config.WorkPositionCollection.FirstOrDefault(u => u.PositionName == positionName).TriggerValue; var pIndices = M141Config.MeasureBindCollection.Where(u => u.WorkPosition == positionName).SelectMany(u => u.ProductIndices).Distinct().OrderBy(u => u).ToList(); var measureNum = M141Config.MeasureBindCollection.Count(u => u.WorkPosition == positionName && u.ProductIndices.Contains(pIndices[0])); if (measureNum > 1) { replyData += ",C"; } var pList = pIndices.Select(u => { string sequence = $"{inputSequence}_{u}"; return FindProductBySequence(sequence, true); }).ToList(); if (pList.Any(u => u == null)) { LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, $"获取工位{positionName}汇总结果时产品信息为空"); pList.ForEach(u => { replyData += ",NG"; }); } else { int waitInterval = 300; int repeatTime = M141Config.DetectTimeout / waitInterval; do { if (!pList.All(p => { p.GetPositionResult(M141Config.StationCode, positionName, out P_PRODUCT_DETAIL detail); return detail?.IsDone ?? false; })) { Thread.Sleep(waitInterval); repeatTime--; } else { LogAsync(DateTime.Now, EnumHelper.LogLevel.Action, $"成功完成工位{positionName}产品{string.Join(",", pList.Select(u => $"{u.PID}_{u.SEQUENCE}"))}检测"); break; } if (repeatTime < 0) { LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, $"工位{positionName}产品{string.Join(",", pList.Select(u => $"{u.PID}_{u.SEQUENCE}"))}检测获取结果超时"); break; } } while (true); } pList.ForEach(p => { var isOK = p.GetPositionResult(M141Config.StationCode, positionName, out P_PRODUCT_DETAIL detail); replyData += $",{(isOK ? "OK" : "NG")}"; List specHeads = new List(); string head = p.GetCSVHead(ref specHeads, positionName); if (!_positionSpecHeads.ContainsKey(positionName)) { _positionSpecHeads[positionName] = specHeads; } string data = p.GetCSVData(_positionSpecHeads[positionName], positionName); CSVRecordAsync($"{positionName}_Record_{DateTime.Now.ToString("yyyyMMdd")}.csv", data, head); UpdatePositionResultToDB(detail); var seqData = p.SEQUENCE.Split(new char[] { '_' }, StringSplitOptions.RemoveEmptyEntries).ToList(); UpdatePositionResultDisplay(detail, isOK, positionName, seqData[seqData.Count - 1]); var temokimage = OKNGImages.Where(u => u.pid == p.PID).ToList(); if (isOK) { if (temokimage.Any(u => u.issave)) { for (int i = 0; i < temokimage.Count; i++) { string realpath = Path.Combine(temokimage[i].path, $"{temokimage[i].name}.{temokimage[i].post}"); temokimage[i].bitmap.Save(realpath, temokimage[i].ImageFormat); } } } else { if (temokimage.Any(u => u.issave)) { var temin = temokimage.FirstOrDefault(u => u.result == "NG"); if (temin != null) { for (int i = 0; i < temokimage.Count; i++) { string realpath = Path.Combine(temin.path, $"{temokimage[i].name}.{temokimage[i].post}"); temokimage[i].bitmap.Save(realpath, temokimage[i].ImageFormat); } } else { for (int i = 0; i < temokimage.Count; i++) { string realpath = Path.Combine(temokimage[i].path, $"{temokimage[i].name}.{temokimage[i].post}"); temokimage[i].bitmap.Save(realpath, temokimage[i].ImageFormat); } } } } //string ngImageFile = Path.Combine(folder, $"{id}.{post}"); //var bitmap = imgSet.HImage.ConvertHImageToBitmap(); //bitmap.Save(ngImageFile, M141Config.ImageFormatNG); //LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"{id}NG图片已保存"); if (IsInspectionDoing) { OnSinglePostionDetectResultUpdate.Invoke(positionName, detail, seqData[seqData.Count - 1]); } if (positionSet.IsLastPosition) { UpdateProductResultAsync(p); UpdateOverAllProductResultToUI(p, isOK); OnNewProductEnqueued?.Invoke(p); OnProductDequeued?.Invoke(p); } SetSpecResult(p); }); OKNGImages.ForEach(x => { x.bitmap.Dispose(); }); OKNGImages.Clear(); if (positionSet.IsLastPosition) { if (_ct != null) { UpdateCT(null, (float)((DateTime.Now - _ct.Value).TotalSeconds / 2.0)); } _ct = DateTime.Now; } replyData += "," + pList[0].SN + "," + pList[1].SN; if (!positionName.Contains("0")) { ReplyTcpData(positionName, triggerSource, replyData); } else { //replyData += "," + pList[0].SN=="NOREAD" + "," + pList[1]?.SN; //replyData = "0#,2,"+ ((pList[0].SN == "NOREAD" || pList[1]?.SN=="NOREAD")? "NG":"OK") +","+ pList[0].SN+ ","+ pList[1].SN; replyData = "0#,2,OK," + pList[0].SN + "," + pList[1].SN; ReplyTcpData(positionName, triggerSource, replyData); } cameraIds.ForEach(c => { var camera = DeviceCollection.FirstOrDefault(u => u.Id == c) as CameraBase; if (camera != null) { camera.ClearImageBufferQueue(); LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"相机{camera.Name}清理缓存"); } }); return pList; }); } private async void UpdatePositionResultDisplay(P_PRODUCT_DETAIL detail, bool isOK, string positionName, string productSequence) { await Task.Run(() => { if (detail == null) { LogAsync(DateTime.Now, EnumHelper.LogLevel.Warning, $"无法显示检测明细信息"); return; } List eleList = new List(); TextDisplay txt = new TextDisplay(); txt.LineLimit = 30; eleList.Add(txt); txt.StartX = txt.StartY = 0; txt.AddText($"{detail.SN} {(isOK ? "OK" : "NG")}", isOK ? Color.Lime : Color.White, isOK ? Color.Transparent : Color.Red); txt.AddText(" ", Color.Transparent, Color.Transparent); var ngSpecCode = new List(); detail.SpecList.ToList().ForEach(s => { GetIndicatorFromSpec(s, eleList, txt, ngSpecCode); }); detail.ResultList.ToList().SelectMany(u => u.Specs).ToList().ForEach(s => { GetIndicatorFromSpec(s, eleList, txt, ngSpecCode); }); var defects = new List(detail.DefectList); defects.AddRange(detail.ResultList.GetDefectDescList()); defects = defects.Except(ngSpecCode).Distinct().ToList(); defects.ForEach(u => { txt.AddText(u, Color.Red, Color.Transparent); var indicator = M141Config.DefectIndicatorCollection.FirstOrDefault(d => d.DefectName == u); if (indicator != null) { var cloneIndicator = indicator.Clone() as DefectRectangleIndicator; eleList.Add(cloneIndicator); } }); OnPositionResultUpdated?.Invoke(positionName, productSequence, eleList); //LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"产品{detail.PID} 序号{productSequence} 工位{positionName}显示信息{JsonConvert.SerializeObject(detail)}"); }); } private void GetIndicatorFromSpec(ISpec s, List eleList, TextDisplay txt, List ngSpecCode) { txt.AddText($"{s.Code} {s.GetMeasureValueStr()}", s.MeasureResult == true ? Color.Lime : Color.Red, Color.Transparent); var indicator = M141Config.DefectIndicatorCollection.FirstOrDefault(u => u.DefectName == s.Code); if (indicator != null) { var cloneIndicator = indicator.Clone() as DefectRectangleIndicator; cloneIndicator.DefectName += $"{s.Code} {s.GetMeasureValueStr()}"; cloneIndicator.IsOK = s.MeasureResult == true; eleList.Add(cloneIndicator); } if (s.MeasureResult != true) { ngSpecCode.Add(s.Code); } } private async void UpdateOverAllProductResultToUI(ProductModel product, bool isOK) { await Task.Run(() => { List eleList = new List(); TextDisplay txt = new TextDisplay(); txt.LineLimit = 30; eleList.Add(txt); txt.StartX = txt.StartY = 0; txt.AddText($"{product.SN} {product.Result}", isOK ? Color.Lime : Color.White, isOK ? Color.Transparent : Color.Red); txt.AddText(" ", Color.Transparent, Color.Transparent); var ngSpecCode = new List(); product.Details.ForEach(d => { d.SpecList.ForEach(s => { GetIndicatorFromSpec(s, eleList, txt, ngSpecCode); }); d.ResultList.SelectMany(u => u.Specs).ToList().ForEach(s => { GetIndicatorFromSpec(s, eleList, txt, ngSpecCode); }); var defects = new List(d.DefectList); defects.AddRange(d.ResultList.GetDefectDescList()); defects = defects.Except(ngSpecCode).Distinct().ToList(); defects.ForEach(u => { txt.AddText(u, Color.Red, Color.Transparent); var indicator = M141Config.DefectIndicatorCollection.FirstOrDefault(d => d.DefectName == u); if (indicator != null) { var cloneIndicator = indicator.Clone() as DefectRectangleIndicator; eleList.Add(cloneIndicator); } }); }); OnPositionResultUpdated?.Invoke("", product.SEQUENCE.Split("_")[product.SEQUENCE.Split("_").Count() - 1], eleList); }); } public virtual int UploadProductDataToMES(List pList) { List isUploadOK = new List(); pList.ForEach(p => { var pData = GetProductUploadMESData(p, p.Result); ResponseMessage response = UploadDataToMES(new OperationConfigBase() { TriggerStr = pData }, null, null); if (response.Result == -1) { //先上传一次,如果失败再试2次 for (int i = 0; i < 2; i++) { Thread.Sleep(500); response = UploadDataToMES(new OperationConfigBase() { TriggerStr = pData }, null, null); if (response.Result != -1) { break; } } } if (p.SN.Replace(" ", "").ToLower().Contains("noread") && response.Result == 1000) { isUploadOK.Add(3); } else { isUploadOK.Add(response.Result); } }); if (isUploadOK.All(u => u == 1000)) { return 0; } else if (isUploadOK.Contains(1)) { return 1; } else if (isUploadOK.Contains(4)) { return 4; } else if (isUploadOK.Contains(-1)) { return 2; } else if (isUploadOK.Contains(3)) { return 3; } return 2; } volatile int uploadId = 0; private string GetProductUploadMESData(ProductModel p, string pResult) { JObject jObj = new JObject(); Interlocked.Increment(ref uploadId); //jObj.Add($"id", uploadId); //jObj.Add($"Createor", Config.StationCode ?? "2966AOI3"); //jObj.Add($"CreateTime", p.CREATE_TIME.Value.ToString("yyyy-MM-dd HH:mm:ss")); //jObj.Add($"Project", M141Config.MESProjectCode); //jObj.Add($"MachineNumber", M141Config.MESMachineNum); //jObj.Add($"DateTime", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")); //jObj.Add($"Cycle", ((p.EndTime ?? DateTime.Now) - p.CREATE_TIME.Value).TotalSeconds.ToString("f2")); //jObj.Add($"SN", p.SN); //jObj.Add($"Result", pResult == "OK" ? "OK" : "NG"); //jObj.Add($"id", uploadId); //jObj.Add($"Createor", Config.StationCode ?? "2966AOI3"); jObj.Add($"CreateTime", p.CREATE_TIME.Value.ToString("yyyy-MM-dd HH:mm:ss")); jObj.Add($"SN", p.SN); jObj.Add($"Project", M141Config.MESProjectCode); jObj.Add($"MachineNumber", M141Config.MESMachineNum); jObj.Add($"DateTime", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")); List ngitem = new List(); foreach (var v in p.Details) { ngitem.AddRange(v.ResultList.GetDefectDescList()); ngitem.AddRange(v.DefectList); } ngitem = ngitem.Distinct().ToList(); //LogAsync(DateTime.Now, EnumHelper.LogLevel.Action, $"MES 产品NG项汇总:{string.Join(",", ngitem)}"); //LogAsync(DateTime.Now, EnumHelper.LogLevel.Action, $"MES :{JsonConvert.SerializeObject(p)}"); List ngitemD = ngitem.Where(u => u.ToUpper().Contains("FAI")).ToList(); List ngitemC = ngitem.Where(u => !u.ToUpper().Contains("FAI")).ToList(); jObj.Add($"Result_Dimension", ngitemD.Count == 0 ? "OK" : "NG"); jObj.Add($"Dimension_NGItems", string.Join(",", ngitemD)); //jObj.Add("NGItems", string.Join(",", defectList)); jObj.Add($"Result_Cosmetic", ngitemC.Count == 0 ? "OK" : "NG"); jObj.Add($"Cosmetic_NGItems", string.Join(",", ngitemC)); jObj.Add($"CycleTime", ((p.EndTime ?? DateTime.Now) - p.CREATE_TIME.Value).TotalSeconds.ToString("f2")); var specList = p.Details.SelectMany(u => u.ResultList.SelectMany(r => r.Specs)).ToList(); p.Details.SelectMany(u => u.SpecList).ToList().ForEach(s => { if (!specList.Any(u => u.Code == s.Code)) { specList.Add(s); } }); List temmescode = new List(); specList.ForEach(s => { var mapping = M141Config.MESCodeMappingCollection.FirstOrDefault(u => u.SpcCode == s.Code); if (mapping != null) { if (!temmescode.Contains(mapping.MESCode)) { temmescode.Add(mapping.MESCode); jObj.Add(mapping.MESCode, s.GetMeasureValueStr(4)); } } else { if (!temmescode.Contains(s.Code)) { temmescode.Add(s.Code); jObj.Add(s.Code, s.GetMeasureValueStr(4)); } } }); var defectList = p.Details.SelectMany(u => u.ResultList).ToList().GetDefectDescList(); defectList.AddRange(p.Details.SelectMany(u => u.DefectList)); defectList = defectList.Except(specList.Select(u => u.Code)).Distinct().ToList(); //jObj.Add("NGItems", string.Join(",", defectList)); return JsonConvert.SerializeObject(jObj); } protected void ReplyTcpData(string positionName, string triggerSource, string replyData) { if (!string.IsNullOrWhiteSpace(triggerSource)) { var sourceData = triggerSource.Split(':'); string ip = ""; int port = 0; if (sourceData.Length >= 2) { ip = sourceData[0]; port = int.Parse(sourceData[1]); } string error = ""; if (!(TcpListener?.WriteAndRead(replyData, out error, out _, false, ip, port) ?? false)) { LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, $"工位{positionName}检测结果反馈异常,{error}"); } else { LogAsync(DateTime.Now, EnumHelper.LogLevel.Action, $"工位{positionName}检测结果反馈完成,{replyData}"); } } } public void NewProductIntoList(ProductModel p, bool isSaveDB) { lock (_productListLock) { ProductList.RemoveAll(u => u.PID == p.PID || u.SEQUENCE == p.SEQUENCE); ProductList.Insert(0, p); while (ProductList.Count > 200) { ProductList.RemoveAt(ProductList.Count - 1); } } if (isSaveDB) { var isNewDone = _manager_P_Product.NewProduct(p, p.Details, out string msg); if (!isNewDone) { LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, $"产品{p.PID}数据库新增异常,{msg}"); } } LogAsync(DateTime.Now, EnumHelper.LogLevel.Action, $"{p.PID}_{p.SEQUENCE}产品入列完成"); } public virtual ProductModel FindProductBySequence(string sequence, bool isEnabelQueue) { ProductModel p = null; if (isEnabelQueue) { lock (_productListLock) { p = ProductList.FirstOrDefault(u => u.SEQUENCE == sequence); } } if (p != null) { return p; } else { var pDB = _manager_P_Product.QueryProductBySequence(sequence); if (pDB != null) { p = new ProductModel(pDB); LogAsync(DateTime.Now, EnumHelper.LogLevel.Action, $"从数据库获取产品对象{pDB.PID},序号{pDB.SEQUENCE},条码{pDB.SN}"); } if (p == null) { p = new ProductModel(); p.SEQUENCE = sequence; p.PID = p.PID + "_" + sequence.Split('_')[sequence.Split('_').Length - 1]; p.Initial(M141Config.StationCode, M141Config.WorkPositionCollection.Where(u => u.IsEnabled).Select(u => u.PositionName).ToList()); LogAsync(DateTime.Now, EnumHelper.LogLevel.Warning, $"未能从数据库获取产品对象,使用临时新建产品对象"); } NewProductIntoList(p, false); } return p; } public async Task RunImageCheckAsync(List products, string triggerText, string triggerSource, IImageSet imgSet, MeasureBind measureBind) { await Task.Run(() => { List resultList = new List(); if (products == null || products.Count == 0) { LogAsync(DateTime.Now, EnumHelper.LogLevel.Error, $"工位{measureBind.WorkPosition}检测时产品信息为空"); imgSet.HImage?.Dispose(); imgSet.HImage = null; return; } try { List pidList = products.Select(u => u.PID).OrderBy(u => u).ToList(); if (imgSet == null || imgSet.HImage == null) { throw new Exception($"产品{string.Join(",", pidList)}检测{measureBind.GetDisplayText()}未能获取图片对象"); } //检测顺序 ML->自定义检测 if (!string.IsNullOrWhiteSpace(measureBind.DetectionId)) { string detectionName = (ML.InitialConfig as MLInitialConfigBase).DetectionConfigs.FirstOrDefault(u => u.Id == measureBind.DetectionId)?.Name; //List pidList2 = new List();//pidList.Select(u => u.Split('_')[u.Split('_').Length - 1]).ToList(); //Dictionary dicpid = new Dictionary(); //for (int i = 0; i < pidList.Count; i++) //{ // var tem = pidList[i].Split('_')[pidList[i].Split('_').Length - 1]; // pidList2.Add(tem); // dicpid[tem] = pidList[i]; //} List detectResults = ML?.RunMLDetectionSync(imgSet, pidList, measureBind.DetectionId); List ngResults = new List(); //for (int i = 0; i < detectResults.Count; i++) //{ // detectResults[i].PID = dicpid[detectResults[i].PID]; //} detectResults.GroupBy(u => u.PID).ToList().ForEach(u => { if (u.ToList().Count > 0 && u.ToList().Any(m => m.ResultState != EnumHelper.ResultState.OK)) { if (u.ToList().GetDefectDescList().Count == 0) { var errorSpec = _errorSpec.Copy(); errorSpec.Code = "检测TBD"; errorSpec.ActualValue = -999; DetectResult ngResult = new DetectResult() { Specs = new List() { errorSpec }, PID = u.Key }; ngResults.Add(ngResult); } } }); detectResults.AddRange(ngResults); resultList.AddRange(detectResults); //detectResults[0].ActionForAllNetResults(n => //{ // if (n.DetectDetails.Count == 0) // { // string data = $"{n.DetectTime.ToString("HH:mm:ss.fff")},{pid},,,,{detectResult.DetectionName},{n.IsAbandoned},{n.NetName},{set.ImageIndex},OK,OK,,,,,,,,"; // CSVHelper.CSVOutputAsync(csvpartfilename, data, Part_CSV_Head); // } // else // { // n.DetectDetails.ForEach(d => // { // string data = $"{n.DetectTime.ToString("HH:mm:ss.fff")},{pid},{d.Id},{string.Join("|", d.ParentIds)},{d.Remark},{detectResult.DetectionName},{d.IsAbandoned},{n.NetName},{set.ImageIndex},{d.FinalResult},{d.DetectResult},{d.ClassName},{(d.Rect.Width * d.PixelSize).ToString("f4")},{(d.Rect.Height * d.PixelSize).ToString("f4")},{d.Probability},{d.Uncertainty},{d.Area},{d.AreaInCrop},{d.AreaInActual.ToString("f4")},{d.Rect.X.ToString("f4")},{d.Rect.Y.ToString("f4")}"; // CSVHelper.CSVOutputAsync(csvpartfilename, data, Part_CSV_Head); // }); // } //}); } RunCustomizedMethod(products, triggerText, triggerSource, imgSet, measureBind.CustomizedMonitorId, resultList); RunCustomizedMethod(products, triggerText, triggerSource, imgSet, measureBind.CustomizedCombineMethodId, resultList); } catch (Exception ex) { LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, $"工位{measureBind.WorkPosition}检测过程异常,{ex.ToString()}"); var errorSpec = _errorSpec.Copy(); errorSpec.ActualValue = -999; products.ForEach(p => { p.AddNewDetectResults(M141Config.StationCode, measureBind.WorkPosition, new List() { new DetectResult() { Specs = new List() { errorSpec }, PID = p.PID, } }); }); } finally { try { if (resultList.Count > 0) { products.ForEach(p => { var pResults = resultList.Where(u => u.PID == p.PID).ToList(); p.AddNewDetectResults(M141Config.StationCode, measureBind.WorkPosition, pResults); LogAsync(DateTime.Now, EnumHelper.LogLevel.Action, $"产品{p.PID}_{p.SEQUENCE}添加工位{measureBind.WorkPosition}检测结果,数量{pResults.Count}"); }); } products.ForEach(p => { if (p.PositoinCheckDone(measureBind.WorkPosition, measureBind.CheckIndex, out string msg)) { LogAsync(DateTime.Now, EnumHelper.LogLevel.Action, $"产品{p.PID}_{p.SEQUENCE}工位{measureBind.WorkPosition}的第{measureBind.CheckIndex}检测完成,该工位检测全部结束"); } else { LogAsync(DateTime.Now, EnumHelper.LogLevel.Action, $"产品{p.PID}_{p.SEQUENCE}工位{measureBind.WorkPosition}的第{measureBind.CheckIndex}检测完成,{msg}"); } }); if (resultList.Any(u => u.ResultState != EnumHelper.ResultState.OK)) { if (!products[0].SEQUENCE.ToLower().Contains("test")) { SaveZipPreparation(string.Join("_", products.Select(u => $"{u.PID}_{u.SN}")) + $"-{measureBind.ImageIndex}_{DateTime.Now.ToString("HHmmssfff")}", imgSet, measureBind.WorkPosition); } if (measureBind.NGImageSwitch) { if (string.IsNullOrWhiteSpace(M141Config.NGImageFolder)) { LogAsync(DateTime.Now, EnumHelper.LogLevel.Error, $"未配置NG图片保存目录"); } else { string folder = Path.Combine(M141Config.NGImageFolder, DateTime.Now.ToString("yyyyMMdd"), measureBind.WorkPosition, "NG"); if (!Directory.Exists(folder)) { Directory.CreateDirectory(folder); } string id = string.Join("_", products.Select(u => $"{u.PID}_{u.SN}")) + $"-{measureBind.ImageIndex}_{DateTime.Now.ToString("HHmmssfff")}"; string post = ""; if (ImageSet.ImageFormatPostDict.ContainsKey(M141Config.ImageFormatNG)) { post = ImageSet.ImageFormatPostDict[M141Config.ImageFormatNG]; } else { post = M141Config.ImageFormatNG.ToString().ToLower(); } string ngImageFile = Path.Combine(folder, $"{id}.{post}"); var bitmap = imgSet.HImage.ConvertHImageToBitmap(); bitmap.Save(ngImageFile, M141Config.ImageFormatNG); LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"{id}NG图片已保存"); bitmap.Dispose(); } } } else { if (!products[0].SEQUENCE.ToLower().Contains("test")) { SaveZipPreparation(string.Join("_", products.Select(u => $"{u.PID}_{u.SN}")) + $"-{measureBind.ImageIndex}_{DateTime.Now.ToString("HHmmssfff")}", imgSet, measureBind.WorkPosition); } if (measureBind.OKImageSwitch) { if (string.IsNullOrWhiteSpace(M141Config.NGImageFolder)) { LogAsync(DateTime.Now, EnumHelper.LogLevel.Error, $"未配置NG图片保存目录"); } else { string folder = Path.Combine(M141Config.NGImageFolder, DateTime.Now.ToString("yyyyMMdd"), measureBind.WorkPosition, "OK"); if (!Directory.Exists(folder)) { Directory.CreateDirectory(folder); } string id = string.Join("_", products.Select(u => $"{u.PID}_{u.SN}")) + $"-{measureBind.ImageIndex}_{DateTime.Now.ToString("HHmmssfff")}"; string post = ""; if (ImageSet.ImageFormatPostDict.ContainsKey(M141Config.ImageFormatOK)) { post = ImageSet.ImageFormatPostDict[M141Config.ImageFormatOK]; } else { post = M141Config.ImageFormatOK.ToString().ToLower(); } string ngImageFile = Path.Combine(folder, $"{id}.{post}"); var bitmap = imgSet.HImage.ConvertHImageToBitmap(); bitmap.Save(ngImageFile, M141Config.ImageFormatOK); LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"{id}OK图片已保存"); bitmap.Dispose(); } } } } catch (Exception ex) { LogAsync(DateTime.Now, EnumHelper.LogLevel.Error, $"{measureBind.WorkPosition},产品{string.Join(",", products.Select(u => u.PID))}的NG图片保存异常,{ex.GetExceptionMessage()}"); } LogAsync(DateTime.Now, EnumHelper.LogLevel.Action, $"图片{imgSet.PID}开始释放"); imgSet.HImage?.Dispose(); imgSet.HImage = null; imgSet.Dispose(); imgSet = null; LogAsync(DateTime.Now, EnumHelper.LogLevel.Action, $"图片已释放"); } }); } public async Task RunImageCheckAsyncForSB(List products, string triggerText, string triggerSource, IImageSet imgSet, MeasureBind measureBind) { await Task.Run(() => { List resultList = new List(); if (products == null || products.Count == 0) { LogAsync(DateTime.Now, EnumHelper.LogLevel.Error, $"工位{measureBind.WorkPosition}检测时产品信息为空"); imgSet.HImage?.Dispose(); imgSet.HImage = null; return; } try { List pidList = products.Select(u => u.PID).OrderBy(u => u).ToList(); if (imgSet == null || imgSet.HImage == null) { throw new Exception($"产品{string.Join(",", pidList)}检测{measureBind.GetDisplayText()}未能获取图片对象"); } //检测顺序 ML->自定义检测 if (!string.IsNullOrWhiteSpace(measureBind.DetectionId)) { string detectionName = (ML.InitialConfig as MLInitialConfigBase).DetectionConfigs.FirstOrDefault(u => u.Id == measureBind.DetectionId)?.Name; //List pidList2 = new List();//pidList.Select(u => u.Split('_')[u.Split('_').Length - 1]).ToList(); //Dictionary dicpid = new Dictionary(); //for (int i = 0; i < pidList.Count; i++) //{ // var tem = pidList[i].Split('_')[pidList[i].Split('_').Length - 1]; // pidList2.Add(tem); // dicpid[tem] = pidList[i]; //} List detectResults = ML?.RunMLDetectionSync(imgSet, pidList, measureBind.DetectionId); List ngResults = new List(); //for (int i = 0; i < detectResults.Count; i++) //{ // detectResults[i].PID = dicpid[detectResults[i].PID]; //} detectResults.GroupBy(u => u.PID).ToList().ForEach(u => { if (u.ToList().Count > 0 && u.ToList().Any(m => m.ResultState != EnumHelper.ResultState.OK)) { if (u.ToList().GetDefectDescList().Count == 0) { var errorSpec = _errorSpec.Copy(); errorSpec.Code = "检测TBD"; errorSpec.ActualValue = -999; DetectResult ngResult = new DetectResult() { Specs = new List() { errorSpec }, PID = u.Key }; ngResults.Add(ngResult); } } }); detectResults.AddRange(ngResults); resultList.AddRange(detectResults); } RunCustomizedMethod(products, triggerText, triggerSource, imgSet, measureBind.CustomizedMonitorId, resultList); RunCustomizedMethod(products, triggerText, triggerSource, imgSet, measureBind.CustomizedCombineMethodId, resultList); } catch (Exception ex) { LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, $"工位{measureBind.WorkPosition}检测过程异常,{ex.ToString()}"); var errorSpec = _errorSpec.Copy(); errorSpec.ActualValue = -999; products.ForEach(p => { p.AddNewDetectResults(M141Config.StationCode, measureBind.WorkPosition, new List() { new DetectResult() { Specs = new List() { errorSpec }, PID = p.PID, } }); }); } finally { try { if (resultList.Count > 0) { products.ForEach(p => { var pResults = resultList.Where(u => u.PID == p.PID).ToList(); p.AddNewDetectResults(M141Config.StationCode, measureBind.WorkPosition, pResults); LogAsync(DateTime.Now, EnumHelper.LogLevel.Action, $"产品{p.PID}_{p.SEQUENCE}添加工位{measureBind.WorkPosition}检测结果,数量{pResults.Count}"); }); } products.ForEach(p => { if (p.PositoinCheckDone(measureBind.WorkPosition, measureBind.CheckIndex, out string msg)) { LogAsync(DateTime.Now, EnumHelper.LogLevel.Action, $"产品{p.PID}_{p.SEQUENCE}工位{measureBind.WorkPosition}的第{measureBind.CheckIndex}检测完成,该工位检测全部结束"); } else { LogAsync(DateTime.Now, EnumHelper.LogLevel.Action, $"产品{p.PID}_{p.SEQUENCE}工位{measureBind.WorkPosition}的第{measureBind.CheckIndex}检测完成,{msg}"); } }); if (resultList.Any(u => u.ResultState != EnumHelper.ResultState.OK)) { if (!products[0].SEQUENCE.ToLower().Contains("test")) { SaveZipPreparation(string.Join("_", products.Select(u => $"{u.PID}_{u.SN}")) + $"-{measureBind.ImageIndex}_{DateTime.Now.ToString("HHmmssfff")}", imgSet, measureBind.WorkPosition); } //if (measureBind.NGImageSwitch) //{ if (string.IsNullOrWhiteSpace(M141Config.NGImageFolder)) { LogAsync(DateTime.Now, EnumHelper.LogLevel.Error, $"未配置NG图片保存目录"); } else { string folder = Path.Combine(M141Config.NGImageFolder, DateTime.Now.ToString("yyyyMMdd"), measureBind.WorkPosition, "NG"); if (!Directory.Exists(folder)) { Directory.CreateDirectory(folder); } string id = string.Join("_", products.Select(u => $"{u.PID}_{u.SN}")) + $"-{measureBind.ImageIndex}_{DateTime.Now.ToString("HHmmssfff")}"; string post = ""; if (ImageSet.ImageFormatPostDict.ContainsKey(M141Config.ImageFormatNG)) { post = ImageSet.ImageFormatPostDict[M141Config.ImageFormatNG]; } else { post = M141Config.ImageFormatNG.ToString().ToLower(); } //string ngImageFile = Path.Combine(folder, $"{id}.{post}"); //var bitmap = imgSet.HImage.ConvertHImageToBitmap(); //bitmap.Save(ngImageFile, M141Config.ImageFormatNG); //LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"{id}NG图片已保存"); OKNGImages.Add(new OKNGImage() { pid = products[0].PID, name = id, path = folder, post = post, result = "NG", bitmap = imgSet.HImage.ConvertHImageToBitmap(), ImageFormat = M141Config.ImageFormatNG, issave = measureBind.NGImageSwitch }); } //} } else { if (!products[0].SEQUENCE.ToLower().Contains("test")) { SaveZipPreparation(string.Join("_", products.Select(u => $"{u.PID}_{u.SN}")) + $"-{measureBind.ImageIndex}_{DateTime.Now.ToString("HHmmssfff")}", imgSet, measureBind.WorkPosition); } //if (measureBind.OKImageSwitch) //{ if (string.IsNullOrWhiteSpace(M141Config.NGImageFolder)) { LogAsync(DateTime.Now, EnumHelper.LogLevel.Error, $"未配置NG图片保存目录"); } else { string folder = Path.Combine(M141Config.NGImageFolder, DateTime.Now.ToString("yyyyMMdd"), measureBind.WorkPosition, "OK"); if (!Directory.Exists(folder)) { Directory.CreateDirectory(folder); } string id = string.Join("_", products.Select(u => $"{u.PID}_{u.SN}")) + $"-{measureBind.ImageIndex}_{DateTime.Now.ToString("HHmmssfff")}"; string post = ""; if (ImageSet.ImageFormatPostDict.ContainsKey(M141Config.ImageFormatOK)) { post = ImageSet.ImageFormatPostDict[M141Config.ImageFormatOK]; } else { post = M141Config.ImageFormatOK.ToString().ToLower(); } //string ngImageFile = Path.Combine(folder, $"{id}.{post}"); //var bitmap = imgSet.HImage.ConvertHImageToBitmap(); //bitmap.Save(ngImageFile, M141Config.ImageFormatOK); //LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"{id}OK图片已保存"); OKNGImages.Add(new OKNGImage() { pid = products[0].PID, name = id, path = folder, post = post, result = "OK", bitmap = imgSet.HImage.ConvertHImageToBitmap(), ImageFormat = M141Config.ImageFormatOK, issave = measureBind.OKImageSwitch }); } //} } } catch (Exception ex) { LogAsync(DateTime.Now, EnumHelper.LogLevel.Error, $"{measureBind.WorkPosition},产品{string.Join(",", products.Select(u => u.PID))}的NG图片保存异常,{ex.GetExceptionMessage()}"); } LogAsync(DateTime.Now, EnumHelper.LogLevel.Action, $"图片{imgSet.PID}开始释放"); imgSet.HImage?.Dispose(); imgSet.HImage = null; imgSet.Dispose(); imgSet = null; LogAsync(DateTime.Now, EnumHelper.LogLevel.Action, $"图片已释放"); } }); } private void RunCustomizedMethod(List products, string triggerText, string triggerSource, IImageSet imgSet, string methodId, List resultList) { try { if (!string.IsNullOrWhiteSpace(methodId)) { var monitorSet = Config.GetAllMonitorSet().FirstOrDefault(u => u.Id == methodId); if (monitorSet.OpConfig is IImageCheckOperationConfig iConfig) { var opConfig = iConfig.Clone(); opConfig.Products = new List(products); opConfig.ImageSet = imgSet; opConfig.TriggerStr = triggerText; opConfig.TriggerSource = triggerSource; opConfig.ExecuteDevice = iConfig.ExecuteDevice; //LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, $"图片id,{imgSet.id}"); var res = RunSelectedMonitorSetByManual(methodId, opConfig); if (res.DataObj is List dr) { dr.ForEach(r => { r.IsPreTreatDone = r.IsNetCheckDone = r.IsAfterTreatDone = true; r.SetResult(); }); resultList.AddRange(dr); } if (res.Result != 1) { LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, $"自定义检测过程异常,{res.Message}"); } } } } catch (Exception ex) { LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, $"自定义检测过程异常,{ex.GetExceptionMessage()}"); } } private void SetSpecResult(ProductModel productModel) { // 更新既有的检测记录内容 var existProduct = ProductSpecResultList.FirstOrDefault(x => x.PID == productModel.PID); if (existProduct != null) { existProduct.Details = productModel.Details; return; } // 新增检测产品记录 ProductSpecResultList.Insert(0, productModel); while (ProductSpecResultList.Count > M141Config.MaxProductListAmount) { ProductSpecResultList.RemoveAt(ProductSpecResultList.Count - 1); } } [ProcessMethod("", "HeartBeat", "心跳", InvokeType.TestInvoke)] public ResponseMessage HeartBeat(IOperationConfig config, IDevice invokeDevice, IDevice sourceDevice) { ResponseMessage msg = new ResponseMessage(); msg.IsReply = true; msg.DataStr = M141Config.Heartstr; if (M141Config.PointState) { if (!CheckInspectionInPeriodic(3000)) { msg.IsReply = false; } } //DateTime now = DateTime.Now; //DateTime today8am = new DateTime(now.Year, now.Month, now.Day, 8, 0, 0); //DateTime today20am = new DateTime(now.Year, now.Month, now.Day, 20, 0, 0); //InitialOEEStatistic() return msg; } public void SaveZipPreparation(string id, IImageSet imgSet, string workstation) { try { if (M141Config.SaveStateZip) { if (M141Config.PositionZip.Any(u => u.WorkPosition == workstation)) { if (M141Config.SaveTwoPathZip) { if (!string.IsNullOrEmpty(M141Config.SavePathZip) || !string.IsNullOrEmpty(M141Config.SavePathZip2)) { if (string.IsNullOrEmpty(M141Config.CurrPathZip)) { M141Config.CurrPathZip = M141Config.SavePathZip; } if (M141Config.CurrPathZip != M141Config.SavePathZip && M141Config.CurrPathZip != M141Config.SavePathZip2) { M141Config.CurrPathZip = M141Config.SavePathZip; } DriveInfo driveInfo3 = DriveInfo.GetDrives().First(d => M141Config.CurrPathZip.StartsWith(d.Name)); double freespace3 = (double)driveInfo3.AvailableFreeSpace / (double)driveInfo3.TotalSize * 100; if (freespace3 < M141Config.SaveMinPercentZip) { DriveInfo driveInfo1 = DriveInfo.GetDrives().First(d => M141Config.SavePathZip.StartsWith(d.Name)); double freespace1 = (double)driveInfo1.AvailableFreeSpace / (double)driveInfo1.TotalSize * 100; DriveInfo driveInfo2 = DriveInfo.GetDrives().First(d => M141Config.SavePathZip2.StartsWith(d.Name)); double freespace2 = (double)driveInfo2.AvailableFreeSpace / (double)driveInfo2.TotalSize * 100; if (freespace1 > M141Config.SaveMinPercentZip) { M141Config.CurrPathZip = M141Config.SavePathZip; SaveProcessConfig(M141Config); } else if (freespace2 > M141Config.SaveMinPercentZip) { M141Config.CurrPathZip = M141Config.SavePathZip2; SaveProcessConfig(M141Config); } else { LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, $"双磁盘都达到存储极限,不再保存压缩图片"); return; } } string folder = Path.Combine(M141Config.CurrPathZip, DateTime.Now.ToString("yyyyMMdd"), workstation); if (!Directory.Exists(folder)) { Directory.CreateDirectory(folder); } string post = ""; if (ImageSet.ImageFormatPostDict.ContainsKey(M141Config.ImageFormatZip)) { post = ImageSet.ImageFormatPostDict[M141Config.ImageFormatZip]; } else { post = M141Config.ImageFormatZip.ToString().ToLower(); } HImage zoomimage; if ((int)M141Config.SavezipZip != 10) { //// 调用zoom_image_factor算子 HOperatorSet.ZoomImageFactor(imgSet.HImage, out HObject zoomHob, ((double)M141Config.SavezipZip) / 10, ((double)M141Config.SavezipZip) / 10, "constant"); zoomimage = zoomHob.ConvertHObjectToHImage(); } else { zoomimage = imgSet.HImage; } //string ngImageFile = Path.Combine(folder, $"{id}.{post}"); //var bitmap = zoomimage.ConvertHImageToBitmap(); //bitmap.Save(ngImageFile, M141Config.ImageFormatZip); //LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"{id}压缩图片已保存"); //zoomimage.Dispose(); //bitmap.Dispose(); lock (ZipImages) { ZipImages.Add(new ZipImage { path = folder, name = id, post = post, image = zoomimage, }); } } else { LogAsync(DateTime.Now, EnumHelper.LogLevel.Error, $"压缩图片保存双路径为空"); } } else { if (!string.IsNullOrEmpty(M141Config.SavePathZip)) { string folder = Path.Combine(M141Config.SavePathZip, DateTime.Now.ToString("yyyyMMdd"), workstation); if (!Directory.Exists(folder)) { Directory.CreateDirectory(folder); } string post = ""; if (ImageSet.ImageFormatPostDict.ContainsKey(M141Config.ImageFormatZip)) { post = ImageSet.ImageFormatPostDict[M141Config.ImageFormatZip]; } else { post = M141Config.ImageFormatZip.ToString().ToLower(); } //// 调用zoom_image_factor算子 HOperatorSet.ZoomImageFactor(imgSet.HImage, out HObject zoomHob, ((double)M141Config.SavezipZip) / 10, ((double)M141Config.SavezipZip) / 10, "constant"); HImage zoomimage = zoomHob.ConvertHObjectToHImage(); //string ngImageFile = Path.Combine(folder, $"{id}_{Result}.{post}"); //var bitmap = zoomimage.ConvertHImageToBitmap(); //bitmap.Save(ngImageFile, M141Config.ImageFormatZip); //LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"{id}压缩图片已保存"); //zoomimage.Dispose(); lock (ZipImages) { ZipImages.Add(new ZipImage { path = folder, name = id, post = post, image = zoomimage, }); } } else { LogAsync(DateTime.Now, EnumHelper.LogLevel.Error, $"压缩图片保存路径为空"); } } } } } catch (Exception e) { LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, $"压缩图片整理异常{e.ToString()}"); } } public void SaveZip(string pid, string result) { try { if (M141Config.SaveStateZip) { lock (ZipImages) { var zipimagespid = ZipImages.Where(u => u.name.Contains(pid)).ToList(); if (zipimagespid != null) { for (int i = 0; i < zipimagespid.Count; i++) { string ngImageFile = Path.Combine(zipimagespid[i].path, $"{zipimagespid[i].name}_{result}.{zipimagespid[i].post}"); var bitmap = zipimagespid[i].image.ConvertHImageToBitmap(); bitmap.Save(ngImageFile, M141Config.ImageFormatZip); LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"{zipimagespid[i].name}压缩图片已保存"); zipimagespid[i].image.Dispose(); zipimagespid[i].image = null; bitmap.Dispose(); } ZipImages.RemoveAll(u => u.name.Contains(pid)); } } } } catch (Exception e) { LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, $"压缩图片保存异常{e.ToString()}"); } } #region plc public ResponseMessage RunImageCheck_plc(IOperationConfig config, int plcnum) { ResponseMessage msg = new ResponseMessage(); msg.Result = 1; List measureBinds = new List(); string inputSequence = ""; var triggerDatas = config.TriggerStr.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); try { RunImageCheckPreTreat_plc(config, out measureBinds, out inputSequence); } catch (Exception ex) { LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, $"检测预处理异常,{ex.GetExceptionMessage()}"); msg.Result = -1; msg.Message = ex.Message; return msg; } List cameraIds = measureBinds.Select(u => u.CameraId).ToList(); try { ConcurrentDictionary imgSetDicts = new ConcurrentDictionary(); measureBinds.AsParallel().ForAll(b => { var camera = DeviceCollection.FirstOrDefault(u => u.Id == b.CameraId) as CameraBase; if (camera == null) { LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, $"检测配置{b.GetDisplayText()}未能获取相机设备"); imgSetDicts[b] = null; return; } imgSetDicts[b] = null; try { imgSetDicts[b] = CollectHImage(camera, b.SnapshotOpConfig); } catch (Exception ea) { LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, $"工位{measureBinds[0].WorkPosition}的第{measureBinds[0].CheckIndex}检测获取图像信息异常 {ea.ToString()}"); } var pList = b.ProductIndices.Select(pi => { string pid = $"{inputSequence}_{pi}"; return FindProductBySequence(pid, true); }).ToList(); RunImageCheckAsync(pList, config.TriggerStr, config.TriggerSource, imgSetDicts[b], b); }); } catch (Exception ex) { LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, $"检测处理异常,{ex.GetExceptionMessage()}"); msg.Result = -1; msg.Message = ex.Message; return msg; } CheckPositionDoneAsync_plc(measureBinds[0].WorkPosition, inputSequence, config, cameraIds, plcnum); return msg; } public void RunImageCheckPreTreat_plc(IOperationConfig config, out List measureBinds, out string inputSequence) { Task.Run(() => { SetProcessRunState(EnumHelper.RunState.Running); }); measureBinds = new List(); inputSequence = ""; var triggerDatas = config.TriggerStr.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); if (triggerDatas.Length < 2) { throw new ProcessException($"触发文本{config.TriggerStr}解析失败,数据长度小于2"); } string positionValue = triggerDatas[0]; int checkIndex = -1; if (!int.TryParse(triggerDatas[1].Replace("Scan", ""), out checkIndex)) { throw new ProcessException($"触发文本{config.TriggerStr}解析失败,未能获取检测序号"); } var positionSet = M141Config.WorkPositionCollection.Where(u => u.IsEnabled).FirstOrDefault(u => u.TriggerValue == positionValue); if (positionSet == null) { throw new ProcessException($"触发文本{config.TriggerStr}未能获取{positionValue}对应的可用工位信息"); } measureBinds = M141Config.MeasureBindCollection.Where(u => u.WorkPosition == positionSet.PositionName && u.CheckIndex == checkIndex).ToList(); if (measureBinds.Count == 0) { throw new ProcessException($"未能获取工位{positionSet.PositionName}的第{checkIndex}检测配置信息"); } measureBinds.Select(u => u.CameraId).ToList().ForEach(c => { var camera = DeviceCollection.FirstOrDefault(u => u.Id == c) as CameraBase; if (camera != null) { camera.ClearImageBufferQueue(); LogAsync(DateTime.Now, EnumHelper.LogLevel.Action, $"相机{camera.Name}检测前清理缓存完成"); } }); if (positionSet.IsSendClearSingal) { var sourceData = config.TriggerSource.Split(':'); string ip = ""; int port = 0; if (sourceData.Length >= 2) { ip = sourceData[0]; port = int.Parse(sourceData[1]); } TcpListener?.WriteAndRead(positionSet.ClearStr, out _, out _, false, ip, port); } inputSequence = triggerDatas[triggerDatas.Length - 1]; string tempPID = inputSequence; string pidstr = DateTime.Now.ToString("yyyyMMddHHmmssfff"); measureBinds.Where(b => b.IsFirstPosition).ToList().ForEach(b => { b.ProductIndices.ForEach(i => { ProductModel p = new ProductModel(); p.SEQUENCE = $"{tempPID}_{i}"; p.PID = $"{pidstr}T_{i}"; p.Initial(M141Config.StationCode, M141Config.WorkPositionCollection.Select(u => u.PositionName).ToList()); NewProductIntoList(p, true); }); }); int de = 0; measureBinds.Where(b => (b.CheckIndex == de || b.CheckIndex == 1) && b.ImageIndex == 0).AsParallel().ForAll(b => { List temint = new List(); temint = new List() { 1, 2, 3 }; temint.ForEach(i => { string sequence = $"{tempPID}_{i}"; var p = FindProductBySequence(sequence, b.IsEnabelQueryFromQueue); //初始化产品的检测次数 var checkIndexList = M141Config.MeasureBindCollection.Where(u => u.WorkPosition == b.WorkPosition && u.ProductIndices.Contains(i)).Select(u => u.CheckIndex).OrderBy(u => u).ToList(); p.InitialPositionCheckList(b.WorkPosition, checkIndexList); LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"产品{p.PID}_{p.SEQUENCE}已清理{b.WorkPosition}检测数据。当前已完成工位{string.Join(",", p.Details.Select(u => u.PositionName))}"); }); //初始化工位的检测次数 var positionCheckTimes = M141Config.MeasureBindCollection.Where(u => u.WorkPosition == b.WorkPosition).Select(u => u.CheckIndex).ToList(); lock (_positionCheckTimeLock) { _positionCheckTimeDict[b.WorkPosition] = positionCheckTimes; LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"工位{b.WorkPosition}初始化检测次数:{string.Join(",", positionCheckTimes)}"); } }); measureBinds.AsParallel().ForAll(b => { lock (_positionCheckTimeLock) { _positionCheckTimeDict[b.WorkPosition].RemoveAll(u => u == b.CheckIndex); LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"工位{b.WorkPosition}开始第{b.CheckIndex}次检测,待检测序号:{string.Join(",", _positionCheckTimeDict[b.WorkPosition])}"); } }); } public async Task> CheckPositionDoneAsync_plc(string positionName, string inputSequence, IOperationConfig config, List cameraIds, int plcnum) { string triggerSource = config.TriggerSource; return await _taskFactory.StartNew(() => { try { string index = config.TriggerStr.Split(',')[1]; var positionSet = M141Config.WorkPositionCollection.FirstOrDefault(u => u.PositionName == positionName); var checkRemains = _positionCheckTimeDict[positionName]; var pIndices = M141Config.MeasureBindCollection.Where(u => u.WorkPosition == positionName).SelectMany(u => u.ProductIndices).Distinct().OrderBy(u => u).ToList(); pIndices = new List { 1, 2, 3 }; var pList = pIndices.Select(u => { string sequence = $"{inputSequence}_{u}"; return FindProductBySequence(sequence, true); }).ToList(); List plcresult = new List(); if (pList.Any(u => u == null)) { plcresult = new List() { false, false, false }; LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, $"获取工位{positionName}汇总结果时产品信息为空"); } else { int waitInterval = 20; int repeatTime = M141Config.DetectTimeout / waitInterval; do { if (!pList.All(p => { p.GetPositionResult(M141Config.StationCode, positionName, out P_PRODUCT_DETAIL detail); return detail?.IsDone ?? false; })) { Thread.Sleep(waitInterval); repeatTime--; } else { //Thread.Sleep(50); LogAsync(DateTime.Now, EnumHelper.LogLevel.Action, $"成功完成工位{positionName}产品{string.Join(",", pList.Select(u => $"{u.PID}_{u.SEQUENCE}"))}检测"); break; } if (repeatTime < 0) { LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, $"工位{positionName}产品{string.Join(",", pList.Select(u => $"{u.PID}_{u.SEQUENCE}"))}检测获取结果超时"); break; } } while (true); } pList.ForEach(p => { var isOK = p.GetPositionResult(M141Config.StationCode, positionName, out P_PRODUCT_DETAIL detail); plcresult.Add(isOK); //List specHeads = new List(); //string head = p.GetCSVHead(ref specHeads, positionName); //if (!_positionSpecHeads.ContainsKey(positionName)) //{ // _positionSpecHeads[positionName] = specHeads; //} //string data = p.GetCSVData(_positionSpecHeads[positionName], positionName); //CSVRecordAsync($"{positionName}_Record_{DateTime.Now.ToString("yyyyMMdd")}.csv", data, head); ////UpdatePositionResultToDB(detail); //var seqData = p.SEQUENCE.Split(new char[] { '_' }, StringSplitOptions.RemoveEmptyEntries).ToList(); //UpdatePositionResultDisplay(detail, isOK, positionName, seqData[seqData.Count - 1]); //if (IsInspectionDoing) //{ // OnSinglePostionDetectResultUpdate.Invoke(positionName, detail, seqData[seqData.Count - 1]); //} if (positionSet.IsLastPosition) { UpdateProductResultAsync(p); //UpdateOverAllProductResultToUI(p, isOK); //OnNewProductEnqueued?.Invoke(p); //OnProductDequeued?.Invoke(p); CheckContinuousNGAlarmAsync(p); } //SetSpecResult(p); }); ReplyPlcData(plcresult, plcnum); if (positionSet.IsLastPosition) { if (_ct != null) { UpdateCT(null, (float)((DateTime.Now - _ct.Value).TotalSeconds) / 3); } _ct = DateTime.Now; } //ReplyPlcData(positionName, config.TriggerValue); //cameraIds.ForEach(c => //{ // var camera = DeviceCollection.FirstOrDefault(u => u.Id == c) as CameraBase; // if (camera != null) // { // camera.ClearImageBufferQueue(); // LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"相机{camera.Name}清理缓存"); // } //}); return pList; } catch (Exception ex) { LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, ex.ToString()); return null; } }); } public virtual void ReplyPlcData(List result, int plcnum) { } #endregion public void wirtePLC(int add, int value) { Plc1?.WriteSingleAddress(add, value, out _); } } public class ZipImage { public string path { set; get; } public string name { set; get; } public string post { set; get; } public HImage image { set; get; } } public class OKNGImage { public string pid { set; get; } public string path { set; get; } public string name { set; get; } public string post { set; get; } public string result { set; get; } public Bitmap bitmap { set; get; } public ImageFormat ImageFormat { set; get; } public bool issave { set; get; } } }