M182轴承端盖外观缺陷AOI
kingno
2025-09-18 1894ccc4014d813ea60cf276ac066e5870a82566
src/Bro.M141.Process/M141Process.cs
@@ -22,6 +22,7 @@
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Text;
using Windows.ApplicationModel.Appointments;
using Windows.Networking;
using static Org.BouncyCastle.Math.EC.ECCurve;
@@ -35,52 +36,44 @@
        public M141Process(string productCode) : base(productCode) { }
        #endregion
        TaskFactory _taskFactory = new TaskFactory(TaskCreationOptions.LongRunning, TaskContinuationOptions.LongRunning);
        public event Action<string, P_PRODUCT_DETAIL, string> OnSinglePostionDetectResultUpdate;
        protected M141Config M141Config => Config as M141Config;
        public static object _productListLock = new object();
        public List<ProductModel> ProductList = new List<ProductModel>();
        MachineLearningBase ML = null;
        TcpListenerWrap TcpListener = null;
        Spec _errorSpec = null;
        public List<ProductModel> ProductSpecResultList { get; set; } = new List<ProductModel>();
        TcpListenerWrap _realTimeServer = null;
        volatile int _productIndex = 0;
        int _backgroundImageWidth = 2448;
        public event Action<string, string, List<IShapeElement>> OnPositionResultUpdated;
        public event Action<ProductModel> OnNewProductEnqueued;
        public event Action<ProductModel> OnProductDequeued;
        public event Action<List<int>> RefreshUIplc;
        public event Action<string> RefreshState;
        List<ZipImage> ZipImages = new List<ZipImage>();
        List<OKNGImage> OKNGImages = new List<OKNGImage>();
        public override void InitialProcessMethods()
        {
            base.InitialProcessMethods();
            OldDataClear.Instance.RunClearOldData(M141Config.DBDataTimeLimit);
            InitialInspectionConfig();
            InitialSummaryData();
            if (ThHeartPlc == null)
            {
                ThHeartPlc = new Thread(Heartplc);
                ThHeartPlc.IsBackground = true;
                ThHeartPlc.Start();
            }
        }
        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;
        Spec _errorSpec;
        bool isstart = false;
        public override void Open()
        {
            base.Open();
@@ -98,7 +91,7 @@
            }
            _errorSpec = M141Config.SpecCollection.FirstOrDefault(u => u.Code == M141Config.CheckErrorSpecCode) as Spec;
            InitialProductList();
            NetWarmUp();
@@ -106,25 +99,77 @@
            _positionSpecHeads.Clear();
            if (ThHeartPlc == null)
            {
                ThHeartPlc = new Thread(Heartplc);
                ThHeartPlc.IsBackground = true;
                ThHeartPlc.Start();
            }
            InitialContinuousNGAlarm();
            int vava = 0;
            if (M141Config.channelva == 3)
            {
                vava = 0;
            }
            else if (M141Config.channelva == 2)
            {
                vava = 1;
            }
            Plc1.WriteSingleAddress(3006, vava, out _);
            isstart = true;
        }
        public override void Close()
        {
            isstart = false;
            base.Close();
        }
        public void Heartplc()
        {
            Thread.Sleep(1000);
            string _statisticFilePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Statistic.json");
            if (File.Exists(_statisticFilePath))
            {
                try
                {
                    string dataStr = "";
                    using (StreamReader reader = new StreamReader(_statisticFilePath, System.Text.Encoding.UTF8))
                    {
                        dataStr = reader.ReadToEnd();
                    }
                    lock (StatisticRecordsFull)
                    {
                        var temRecords = JsonConvert.DeserializeObject<StatisticRecords_Full>(dataStr);
                        if (StatisticRecordsFull != null && temRecords != null)
                        {
                            StatisticRecordsFull.CurRecord = temRecords.CurRecord;
                            StatisticRecordsFull.HistoryRecord = temRecords.HistoryRecord;
                        }
                    }
                }
                catch (Exception ex)
                {
                    LogAsync(DateTime.Now, EnumHelper.LogLevel.Error, $"产品统计信息反序列化异常");
                    StatisticRecordsFull = new StatisticRecords_Full();
                }
            }
            int state = 0;
            int state2 = 0;
            int numsum = 0;
            DateTime dtday = DateTime.Now;
            while (true)
            {
                Thread.Sleep(1000);
                if (!isstart)
                {
                    continue;
                }
                numsum++;
                try
                {
@@ -134,10 +179,114 @@
                {
                }
                Thread.Sleep(1000);
                try
                {
                    var tem = Plc1.Read(3030, 17, out _);
                    if (M141Config.WorkShiftList != null && M141Config.WorkShiftList.Count > 0 && numsum >= 0)
                    {
                        for (int i = 0; i < M141Config.WorkShiftList.Count; i++)
                        {
                            double timeshap = (DateTime.Now - M141Config.WorkShiftList[i].ShiftTime_Start).TotalMinutes % 1440;
                            double timeshap2 = (DateTime.Now - M141Config.WorkShiftList[i].ShiftTime_End).TotalMinutes % 1440;
                            if (timeshap2 > 0 && timeshap2 < 1)
                            {
                                if (M141Config.WorkShiftList[i].IsRecordProductSummary)
                                {
                                    string csvPathAll = Path.Combine(M141Config.LogPath, "Alldata.csv");
                                    using (StreamWriter writer = new StreamWriter(csvPathAll, true, Encoding.UTF8))
                                    {
                                        try
                                        {
                                            int sum = StatisticRecordsFull.CurRecord.ProductSummary.RecordsList.Where(u => u.IsStatistic).Sum(u => u.Amount);
                                            int OKnum = 0;
                                            string okpercent = "";
                                            string headcsv = "日期,班次,总数,OK,OK占比";
                                            string datacsv = "";
                                            StatisticRecordsFull.CurRecord.ProductSummary.RecordsList.ForEach(u =>
                                            {
                                                if (u.ClassDesc.ToUpper() == "OK")
                                                {
                                                    OKnum = u.Amount;
                                                    okpercent = u.PercentStr;
                                                }
                                                else
                                                {
                                                    headcsv += $",{u.ClassDesc},{u.ClassDesc}占比";
                                                    datacsv += $",{u.Amount},{u.PercentStr}";
                                                }
                                            });
                                            string daystr = DateTime.Now.ToString("yyyyMMdd");
                                            if (M141Config.WorkShiftList[i].ShiftTime_End.TimeOfDay < M141Config.WorkShiftList[i].ShiftTime_Start.TimeOfDay)
                                            {
                                                daystr = DateTime.Now.AddDays(-1).ToString("yyyyMMdd");
                                            }
                                            datacsv = $"{daystr}T,{M141Config.WorkShiftList[i].ShiftName},{sum},{OKnum},{OKnum}" + datacsv;
                                            writer.WriteLine(headcsv);
                                            writer.WriteLine(datacsv);
                                        }
                                        catch (Exception exx)
                                        {
                                            LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, exx.ToString());
                                        }
                                    }
                                }
                                numsum = -62;
                            }
                            if (timeshap > 0 && timeshap < 1)
                            {
                                if (M141Config.WorkShiftList[i].IsClearProductSummary)
                                {
                                    StatisticRecordsFull.CurRecord.ProductSummary.RecordsList.Clear();
                                    StatisticRecordsFull.CurRecord.DefectSummary.RecordsList.Clear();
                                }
                                numsum = -62;
                            }
                        }
                    }
                    lock (StatisticRecordsFull)
                    {
                        if (numsum > 20)
                        {
                            numsum = 0;
                            using (FileStream fileStream = new FileStream(_statisticFilePath, FileMode.OpenOrCreate, FileAccess.Write))
                            {
                                fileStream.Seek(0L, SeekOrigin.Begin);
                                string s = JsonConvert.SerializeObject(StatisticRecordsFull);
                                byte[] bytes = Encoding.UTF8.GetBytes(s);
                                fileStream.Write(bytes, 0, bytes.Length);
                                fileStream.SetLength(bytes.Length);
                                fileStream.Flush();
                                fileStream.Close();
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                }
                try
                {
                    var tem = Plc1.Read(3030, 18, out _);
                    if (tem != null && RefreshUIplc != null)
                    {
                        RefreshUIplc.Invoke(tem);
@@ -147,6 +296,7 @@
                {
                }
                try
                {
                    var tem = Plc1.Read(3010, 8, out _);
@@ -164,8 +314,6 @@
                {
                    var tem = Plc1.Read(3027, 1, out _)[0];
                    var tem2 = Plc1.Read(3028, 1, out _)[0];
                    if (state != tem || state2 != tem2)
                    {
                        state = tem;
@@ -192,11 +340,9 @@
                {
                }
            }
        }
@@ -205,7 +351,7 @@
            try
            {
                Plc1.WriteSingleAddress(add, va, out _);
                var tem = Plc1.Read(3030, 16, out _);
                var tem = Plc1.Read(3030, 18, out _);
                if (tem != null && RefreshUIplc != null)
                {
                    RefreshUIplc.Invoke(tem);
@@ -311,1425 +457,12 @@
            LogAsync(DateTime.Now, EnumHelper.LogLevel.Action, "算法预热完成");
        }
        static object _positionCheckTimeLock = new object();
        Dictionary<string, List<int>> _positionCheckTimeDict = new Dictionary<string, List<int>>();
        Dictionary<string, List<string>> _positionSpecHeads = new Dictionary<string, List<string>>();
        public ResponseMessage RunImageCheck(IOperationConfig config)
        {
            ResponseMessage msg = new ResponseMessage();
            msg.Result = 1;
            List<MeasureBind> measureBinds = new List<MeasureBind>();
            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<string> cameraIds = measureBinds.Select(u => u.CameraId).ToList();
            try
            {
                ConcurrentDictionary<MeasureBind, IImageSet> imgSetDicts = new ConcurrentDictionary<MeasureBind, IImageSet>();
                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<MeasureBind> measureBinds = new List<MeasureBind>();
            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<string> cameraIds = measureBinds.Select(u => u.CameraId).ToList();
            try
            {
                ConcurrentDictionary<MeasureBind, IImageSet> imgSetDicts = new ConcurrentDictionary<MeasureBind, IImageSet>();
                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<MeasureBind> measureBinds, out string inputSequence)
        {
            Task.Run(() =>
            {
                SetProcessRunState(EnumHelper.RunState.Running);
            });
            measureBinds = new List<MeasureBind>();
            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<int> temint = new List<int>();
                if (triggerDatas[0].Contains("11111"))
                {
                    if (triggerDatas[1] == "1")
                    {
                        temint = new List<int>() { 1 };
                    }
                    else
                    {
                        temint = new List<int>() { 2 };
                    }
                }
                else
                {
                    temint = new List<int>() { 1, 2 };
                }
                //new List<int>() { 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<MeasureBind> measureBinds, out string inputSequence)
        {
            Task.Run(() =>
            {
                SetProcessRunState(EnumHelper.RunState.Running);
            });
            measureBinds = new List<MeasureBind>();
            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<int> temint = new List<int>();
                if (triggerDatas[0].Contains("1") || triggerDatas[0].Contains("0"))
                {
                    if (triggerDatas[1].Contains("1"))
                    {
                        temint = new List<int>() { 1 };
                    }
                    else
                    {
                        temint = new List<int>() { 2 };
                    }
                }
                else
                {
                    temint = new List<int>() { 1, 2 };
                }
                //new List<int>() { 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<List<ProductModel>> CheckPositionDoneAsync(string positionName, string inputSequence, IOperationConfig config, List<string> 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<int> { 1 };
                        }
                        else
                        {
                            pIndices = new List<int> { 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<string> specHeads = new List<string>();
                            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<string> specHeads = new List<string>();
                            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<List<ProductModel>> CheckPositionDoneAsync1(string positionName, string inputSequence, IOperationConfig config, List<string> 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<string> specHeads = new List<string>();
                    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<List<ProductModel>> CheckPositionDoneAsyncforsb(string positionName, string inputSequence, IOperationConfig config, List<string> 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<string> specHeads = new List<string>();
                    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<IShapeElement> eleList = new List<IShapeElement>();
                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<string>();
                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<string>(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<IShapeElement> eleList, TextDisplay txt, List<string> 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<IShapeElement> eleList = new List<IShapeElement>();
                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<string>();
                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<string>(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<ProductModel> pList)
        {
            List<int> isUploadOK = new List<int>();
            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<string> ngitem = new List<string>();
            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<string> ngitemD = ngitem.Where(u => u.ToUpper().Contains("FAI")).ToList();
            List<string> 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<string> temmescode = new List<string>();
            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)
        {
@@ -1743,14 +476,14 @@
                }
            }
            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}");
                }
            }
            //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}产品入列完成");
        }
@@ -1772,12 +505,12 @@
            }
            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}");
                }
                //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)
                {
@@ -1786,7 +519,7 @@
                    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, $"未能从数据库获取产品对象,使用临时新建产品对象");
                    LogAsync(DateTime.Now, EnumHelper.LogLevel.Warning, $"未能获取产品对象,使用临时新建产品对象");
                }
                NewProductIntoList(p, false);
@@ -1794,9 +527,6 @@
            return p;
        }
        public async Task RunImageCheckAsync(List<ProductModel> products, string triggerText, string triggerSource, IImageSet imgSet, MeasureBind measureBind)
        {
@@ -2034,249 +764,6 @@
            });
        }
        public async Task RunImageCheckAsyncForSB(List<ProductModel> products, string triggerText, string triggerSource, IImageSet imgSet, MeasureBind measureBind)
        {
            await Task.Run(() =>
            {
                List<DetectResult> resultList = new List<DetectResult>();
                if (products == null || products.Count == 0)
                {
                    LogAsync(DateTime.Now, EnumHelper.LogLevel.Error, $"工位{measureBind.WorkPosition}检测时产品信息为空");
                    imgSet.HImage?.Dispose();
                    imgSet.HImage = null;
                    return;
                }
                try
                {
                    List<string> 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<string> pidList2 = new List<string>();//pidList.Select(u => u.Split('_')[u.Split('_').Length - 1]).ToList();
                        //Dictionary<string, string> dicpid = new Dictionary<string, string>();
                        //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<DetectResult> detectResults = ML?.RunMLDetectionSync(imgSet, pidList, measureBind.DetectionId);
                        List<DetectResult> ngResults = new List<DetectResult>();
                        //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<ISpec>() { 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<DetectResult>()
                         {
                            new DetectResult()
                            {
                                Specs = new List<ISpec>()
                                {
                                    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<ProductModel> products, string triggerText, string triggerSource, IImageSet imgSet, string methodId, List<DetectResult> resultList)
        {
            try
@@ -2322,50 +809,6 @@
            {
                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;
        }
@@ -2527,40 +970,6 @@
            }
        }
        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)
        {
@@ -2627,7 +1036,6 @@
            return msg;
        }
        public void RunImageCheckPreTreat_plc(IOperationConfig config, out List<MeasureBind> measureBinds, out string inputSequence)
        {
            Task.Run(() =>
@@ -2673,20 +1081,6 @@
                    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];
@@ -2870,17 +1264,12 @@
            });
        }
        public virtual void ReplyPlcData(List<bool> result, int plcnum)
        {
        }
        #endregion
        public void wirtePLC(int add, int value)
@@ -2889,17 +1278,7 @@
        }
    }