From b3855dde0cb86819d17391432ad566564e4b66d7 Mon Sep 17 00:00:00 2001
From: peizhiyong <zhiyong.pei@broconcentric.com>
Date: 星期二, 19 八月 2025 10:06:57 +0800
Subject: [PATCH] 连续NG报警功能,单机台生产数据划分白夜班功能以及S3S5相同位置缺陷放射位置优化

---
 src/Bro.M141.Process/M141Process.cs |  379 +++++++++++++++++++++++++++++++++++++++++++++++++++---
 1 files changed, 358 insertions(+), 21 deletions(-)

diff --git a/src/Bro.M141.Process/M141Process.cs b/src/Bro.M141.Process/M141Process.cs
index 3fbe71a..e0696b7 100644
--- a/src/Bro.M141.Process/M141Process.cs
+++ b/src/Bro.M141.Process/M141Process.cs
@@ -5,10 +5,12 @@
 using Bro.Device.InsCamera;
 using Bro.M135.Common;
 using Bro.M135.DBManager;
+using Bro.M141.Process.UI;
 using Bro.Process;
 using Bro.Process.DataBase.Models;
 using Bro.UI.Model.Winform;
 using HalconDotNet;
+using MySql.Data.MySqlClient;
 using Newtonsoft.Json;
 using Newtonsoft.Json.Linq;
 using NPOI.SS.Formula.Functions;
@@ -56,6 +58,8 @@
         public M141Process_Mysql mysqlhelper = new M141Process_Mysql();
 
         public event Action RerefreshBasketcodeUI;
+
+        public Action<bool, string> OnContinuousNGAlarmRaised;
 
         public void RerefreshBasketcode()
         {
@@ -133,10 +137,10 @@
                 mqtt.Connect(M141Config.MESchannel);
             }
 
-
+            InitialContinuousNGAlarm();         
         }
 
-
+        
         public override void Close()
         {
             devicestate = false;
@@ -571,11 +575,8 @@
                                 double y1 = item1.Rect.Point_LU.Y + item1.Rect.Height / 2.0;
                                 num++;
 
-                                //HOperatorSet.AffineTransPoint2d(new HTuple(products[0].Centermatrix.ToArray()), x1, y1, out HTuple qx, out HTuple qy);
-                                //HOperatorSet.ProjectiveTransPixel(new HTuple(products[0].Centermatrix.ToArray()), x1, y1, out HTuple qx, out HTuple qy);
-
                                 LogAsync(DateTime.Now, EnumHelper.LogLevel.Detail, $"{products[0].SN}  S3S5妫�娴�  鍘熷潗鏍噞num}   {x1},{y1}");
-                                HOperatorSet.ProjectiveTransPixel(new HTuple(products[0].Centermatrix.ToArray()), x1, y1, out HTuple qx, out HTuple qy);
+                                HOperatorSet.ProjectiveTransPixel(new HTuple(products[0].Centermatrix.ToArray()), y1, x1, out HTuple qx, out HTuple qy);
                                 LogAsync(DateTime.Now, EnumHelper.LogLevel.Detail, $"{products[0].SN}  S3S5妫�娴�  鏂板潗鏍噞num}   {qx},{qy}");
 
 
@@ -589,6 +590,7 @@
                                 {
                                     item1.IsAbandoned = false;
                                     item1.FinalResult = ResultState.NG;
+
                                     //products[0].Result = M141Config.defectname;
                                     LogAsync(DateTime.Now, EnumHelper.LogLevel.Action, $"浜у搧{products[0].PID}_{products[0].SEQUENCE}宸ヤ綅{measureBind.WorkPosition}   S3S5缁勫悎妫�娴嬫鍑虹己闄�:{item1.NetName}锛屼骇鍝佺粨鏋滀负{products[0].Result}");
                                     break;
@@ -741,7 +743,7 @@
                                         post = M141Config.ImageFormatOK.ToString().ToLower();
                                     }
 
-                                    string ngImageFile = Path.Combine(folder, $"{id}.{post}");                                    
+                                    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鍥剧墖宸蹭繚瀛�");
@@ -749,7 +751,7 @@
                                     try
                                     {
                                         LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"{id}OK鍥剧墖娴嬭瘯杞瓨{ngImageFile}");
-                                        imgSet.HImage.WriteImage(M141Config.ImageFormatOK.ToString().ToLower(), 0, ngImageFile);                                      
+                                        imgSet.HImage.WriteImage(M141Config.ImageFormatOK.ToString().ToLower(), 0, ngImageFile);
                                     }
                                     catch (Exception)
                                     {
@@ -1239,13 +1241,66 @@
 
 
                         mysqlhelper.UpdateProduct(p);
+
+                      
+
                         if (positionSet.IsLastPosition)
                         {
-                            UpdateProductResultAsync(p);
+                           
+
+                            //鐝缁熻鏃堕棿鍒掑垎
+                            if (M141Config.WorkShiftList.Count == 0)
+                            {
+                                //鐢熸垚涓�涓姤琛�
+                                string name = $"ProductRecord_{DateTime.Now.ToString("yyyyMMdd")}.csv";
+                                LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"鍒涘缓{name}鏁版嵁鎶ヨ〃");
+                                UpdateProductResultAsync(p, name);    
+                            }
+                            else
+                            {
+                                foreach (var item in M141Config.WorkShiftList)
+                                {
+                                    DateTime now = DateTime.Now;
+
+                                    if (item.ShiftTime_Start < item.ShiftTime_End)
+                                    {
+                                        if (now.TimeOfDay >= item.ShiftTime_Start.TimeOfDay && now.TimeOfDay < item.ShiftTime_End.TimeOfDay)
+                                        {
+                                            //鐢熸垚涓�涓姤琛�
+                                            string name = $"ProductRecord_{DateTime.Now.ToString("yyyyMMdd")}_{item.ShiftName}.csv";
+                                            LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"鍒涘缓{name}鏁版嵁鎶ヨ〃");
+                                            UpdateProductResultAsync(p, name);
+                                        }
+                                    }
+                                    else
+                                    {
+                                        if (now.TimeOfDay >= item.ShiftTime_Start.TimeOfDay )
+                                        {
+                                            //鐢熸垚涓�涓姤琛�
+                                            string name = $"ProductRecord_{DateTime.Now.ToString("yyyyMMdd")}_{item.ShiftName}.csv";
+                                            LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"鍒涘缓{name}鏁版嵁鎶ヨ〃");
+                                            UpdateProductResultAsync(p, name);
+                                        }
+                                        if (now.TimeOfDay < item.ShiftTime_End.TimeOfDay)
+                                        {
+                                            // 鐢熸垚涓�涓姤琛�
+                                            string name = $"ProductRecord_{DateTime.Now.AddDays(-1).ToString("yyyyMMdd")}_{item.ShiftName}.csv";
+                                            LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"鍒涘缓{name}鏁版嵁鎶ヨ〃");
+                                            UpdateProductResultAsync(p, name);
+                                        }
+                                    }
+                                }
+                            }
+
+                            //UpdateProductResultAsync(p);
+
                             mysqlhelper.NewForAll(p, M141Config.StationCode, M141Config.defectname);
+
                             if (M141Config.IsfinDevice)
                             {
+
                                 SummaryAllprodata(p);
+
                             }
                         }
                     });
@@ -1281,7 +1336,7 @@
 
                             if (pList[0].Result == "OK")
                             {
-                                M141Config.numpro++;                                
+                                M141Config.numpro++;
                                 Msgreceice = Task.Run(() => mqtt.MESForProduceAsync(pList[0], M141Config.mesnum2.ToString(), M141Config.numpro)).Result;
                             }
                             else
@@ -1290,16 +1345,24 @@
                                 {
                                     Msgreceice = Task.Run(() => mqtt.MESForProduceAsync(pList[0], M141Config.mesnum2.ToString(), M141Config.numpro)).Result;
                                     LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"浜у搧{pList[0].PID}鍚姩NG涓婁紶");
+
                                 }
                                 else
                                 {
                                     LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"浜у搧{pList[0].PID}鍏抽棴NG涓婁紶");
-                                }                              
-                            }                            
+                                }
+                            }
                             M141Config.mesnum2++;
-                            if (Msgreceice == null)
+                            if (Msgreceice == null && !M141Config.ISupNG)
                             {
-                                LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, $"浜у搧{pList[0].PID}鏁版嵁涓婁紶MES寮傚父 杩斿洖鏁版嵁涓簄ull");
+                                if (!M141Config.ISupNG)
+                                {
+                                    LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"浜у搧{pList[0].PID}鏁版嵁NG锛屽紑鍚叧闂璑G涓婁紶MES");
+                                }
+                                else
+                                {
+                                    LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, $"浜у搧{pList[0].PID}鏁版嵁涓婁紶MES寮傚父 杩斿洖鏁版嵁涓簄ull");
+                                }
                             }
                             else
                             {
@@ -1363,11 +1426,11 @@
                                             {
                                                 LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"浜у搧{newp.PID}鍏抽棴NG涓婁紶");
                                             }
-                                            
+
                                         }
                                         catch
                                         {
-
+                                            LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"浜у搧{i + "_1"}涓婁紶澶辫触");
                                         }
                                     }
                                 }
@@ -1375,7 +1438,7 @@
                                 {
                                     LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"鐢熶骇杩囩▼涓湭澶卞幓浜у搧");
                                 }
-                                else if ( differ<0 && differ>-29998)
+                                else if (differ < 0 && differ > -29998)
                                 {
                                     LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"PlcNumForAll涓簕PlcNumForAll}锛宯umplca涓簕numplca}");
                                     //浜у搧浠庢柊璁℃暟鏃�
@@ -1404,7 +1467,7 @@
                                             //var tems = Task.Run(() => mqtt.MESForProduceAsync(newp, M141Config.mesnum2.ToString(), M141Config.numpro)).Result;
                                             //M141Config.mesnum2++;
                                             //LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"PlcNumForAll锛屽墠绔橬G鎺掓枡涓攑lc瑙﹀彂娓呴浂浜у搧{newp.PID}鏁版嵁涓婁紶,缁撴灉涓簕newp.Result}");
-                                        
+
                                         }
                                         catch
                                         {
@@ -1452,8 +1515,6 @@
 
                     //ReplyPlcData(positionName, config.TriggerValue);
 
-                   
-
                     return pList;
 
                 }
@@ -1480,6 +1541,7 @@
 
         public void SummaryAllprodata(ProductModel p)
         {
+            
             _taskFactory.StartNew(() =>
             {
                 try
@@ -1503,6 +1565,7 @@
                             newp.Details.AddRange(item.Details);
                         }
                     }
+
                     //LogAsync(DateTime.Now, EnumHelper.LogLevel.Error, $"AllDeviceProductRecord浠庢暟鎹簱鑾峰彇鍒版暟鎹畕p.SEQUENCE} plist鏁伴噺{plist.Count} Details鏁伴噺{newp.Details.Count}");
 
                     //newp.Details.AddRange(p.Details);
@@ -1525,10 +1588,284 @@
 
 
         #endregion
+
+        List<DefectNGRecord> DefectNGRecordList = new List<DefectNGRecord>();
+
+        public void InitialContinuousNGAlarm()
+        {
+            DefectNGRecordList = M141Config.ContinuousNGAlarmColletion.Where(u => u.IsEnabled).Select(u =>
+            {
+                DefectNGRecord record = new DefectNGRecord();
+                record.DefectName = u.DefectType;
+                record.AlarmSetting = u;
+                return record;
+            }).ToList();
+            OnContinuousNGAlarmRaised = NGAlarmRaised;
+            if (M141Config.ContinuousNGAlarmAddress > 0 && Plc1 != null)
+            {
+                if (!Plc1.WriteSingleAddress(M141Config.ContinuousNGAlarmAddress, 0, out string error))
+                {
+                    LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, $"杩炵画NG鐩戞帶閫氱煡PLC閲嶇疆鎶ヨ澶辫触锛寋error}");
+                }
+            }
+        }
+        public async void CheckContinuousNGAlarmAsync(ProductModel product)
+        {
+            await Task.Run(() =>
+            {
+                if (!M141Config.IsEnableContinuousNGAlarm)
+                {
+                    LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"杩炵画NG鎶ヨ鎬诲紑鍏冲凡鍏抽棴");
+                    return;
+                }
+
+                if (DefectNGRecordList.Count == 0)
+                    return;
+
+                string allMsg = "";
+                bool isAlarmRaised = false;
+                int alarmType = 0;
+                string ngItem = "";
+                try
+                {
+                    LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"杩炵画NG鏁版嵁璁板綍");
+                    DefectNGRecordList.ForEach(d =>
+                    {
+                            string alarmMsg = "";
+                            int alarmTypeTemp = 0;
+                            
+                            if (product.Result == "OK")
+                            {
+                                if (d.CheckIsAlarmRaised(product.Result == "OK", out alarmMsg, out alarmTypeTemp))
+                                {
+                                    allMsg += $"{alarmMsg}\r\n";
+
+                                    isAlarmRaised = true;
+                                    ngItem = "浜у搧缁撴灉";
+                                    alarmType = alarmTypeTemp;
+                                    LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"{product.PID}鏁版嵁缁撴灉涓簕product.Result}鍙備笌杩炵画NG缁熻");
+                                }
+                            }
+                            else
+                            {
+                                if (product.Result.Contains(d.DefectName))
+                                {
+                                    if (d.CheckIsAlarmRaised(!product.Result.Contains(d.DefectName), out alarmMsg, out alarmTypeTemp))
+                                    {
+                                        allMsg += $"{alarmMsg}\r\n";
+                                        isAlarmRaised = true;
+                                        ngItem = "浜у搧缁撴灉";
+                                        alarmType = alarmTypeTemp;
+                                        LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"{product.PID}鏁版嵁缁撴灉涓簕product.Result}鍙備笌杩炵画NG缁熻");
+                                    }
+                                }                               
+                            }
+                    });
+                }
+                catch (Exception ex)
+                {
+                    LogAsync(DateTime.Now, EnumHelper.LogLevel.Warning, $"杩炵画NG鏁版嵁璁板綍澶辫触");
+                }
+                if (isAlarmRaised)
+                {                     
+                    LogAsync(DateTime.Now, EnumHelper.LogLevel.Warning, $"杩炵画NG鐩戞帶鎶ヨ锛寋allMsg}");
+                    if (M141Config.IsOperatorReset)
+                    {
+                        if (M141Config.ContinuousNGAlarmAddress > 0 && Plc1 != null)
+                        {
+                            if (!Plc1.WriteSingleAddress(M141Config.ContinuousNGAlarmAddress, 1, out string error))
+                            {
+                                LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, $"杩炵画NG鐩戞帶閫氱煡PLC閲嶇疆鎶ヨ澶辫触锛寋error}");
+                            }
+                        }
+                        OnContinuousNGAlarmRaised?.Invoke(true, allMsg);
+                    }
+                    else
+                    {
+                        Task.Delay(50).Wait();
+                        ResetContinuousNGAlarm();
+                    }                 
+                }
+            });
+        }
+
+        object _continuousNGAlarmLock = new object();
+
+        FrmContinuousNGAlarm _continuousNGAlarmFrm = null;
+        private async void NGAlarmRaised(bool isRaiseAlarm, string alarmMsg)
+        {
+            await Task.Run(() =>
+            {
+                if (isRaiseAlarm)
+                {
+                    if (_continuousNGAlarmFrm == null)
+                    {
+                        lock (_continuousNGAlarmLock)
+                        {
+                            if (_continuousNGAlarmFrm == null)
+                            {
+                                _continuousNGAlarmFrm = new FrmContinuousNGAlarm();
+
+                                _continuousNGAlarmFrm.TopMost = true;
+                                
+                                _continuousNGAlarmFrm.FormClosed += _continuousNGAlarmFrm_FormClosed;
+                               
+                                Task.Run(() =>
+                                {
+                                    _continuousNGAlarmFrm.ShowDialog();
+                                    
+                                });                               
+                            }
+                        }
+                    }
+                    Task.Delay(100).Wait();
+                    _continuousNGAlarmFrm.ShowAlarmMsg(alarmMsg);
+                }
+                else
+                {
+                    if (_continuousNGAlarmFrm != null)
+                    {
+                        _continuousNGAlarmFrm.Close();
+                    }
+                
+                }
+            });
+
+        }
+
+        private void _continuousNGAlarmFrm_FormClosed(object? sender, FormClosedEventArgs e)
+        {
+            ResetContinuousNGAlarm();
+            LogAsync(DateTime.Now, EnumHelper.LogLevel.Action, $"杩炵画NG鎶ヨ宸插浣�");           
+            _continuousNGAlarmFrm = null;
+        }
+
+        public void ResetContinuousNGAlarm()
+        {
+            //杩炵画NG澶嶄綅
+            DefectNGRecordList.Where(u => u.IsAlarmRaised).ToList().ForEach(u => u.ResetAlarm());
+            if (M141Config.ContinuousNGAlarmAddress > 0 && Plc1 != null)
+            {
+                if (!Plc1.WriteSingleAddress(M141Config.ContinuousNGAlarmAddress, 0, out string error))
+                {
+                    LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, $"杩炵画NG鐩戞帶閫氱煡PLC閲嶇疆鎶ヨ澶辫触锛寋error}");
+                }
+            }
+           
+        }
+
+        [ProcessMethod("", "ContinuousNGAlarmTest", "杩炵画NG鎶ヨ娴嬭瘯", InvokeType.TestInvoke)]
+        public ResponseMessage ContinuousNGAlarmTest(IOperationConfig config, IDevice invokeDevice, IDevice sourceDevice)
+        {
+            ProductModel p = new ProductModel();
+
+            p.Result = config.TriggerStr;
+
+            CheckContinuousNGAlarmAsync(p);
+
+            return new ResponseMessage();
+        }
     }
 
+    public class DefectNGRecord
+    {
+        public string DefectName { get; set; }
+        public List<DateTime> NGRecords { get; set; } = new List<DateTime>();
+        public int ContinuousNGNum { get; set; } = 0;
+        public ContinuousNGAlarm AlarmSetting { get; set; }
 
+        private object _lockObj = new object();
 
+        public bool IsAlarmRaised = false;
 
+        bool _isContinuousAlarm = false;
 
-}
+        bool _timeAlarm = false;
+
+        public bool CheckIsAlarmRaised(bool isOK, out string alarmMsg, out int alarmType)
+        {
+            alarmType = 0;
+            alarmMsg = "";
+            bool isAlarmRasied = false;
+
+            if (IsAlarmRaised)
+                return false;
+
+            lock (_lockObj)
+            {
+                if (IsAlarmRaised)
+                    return false;
+
+                if (isOK)
+                {
+                    ContinuousNGNum = 0;
+                }
+                else
+                {
+                    //杩炵画NG鏁伴噺闃堝��
+                    if (AlarmSetting.ContinuousNumThreshold > 0)
+                    {
+                        ContinuousNGNum++;
+                        CommonLogger.LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"{DefectName}杩炵画NG鏁伴噺涓猴細{ContinuousNGNum}涓�");
+                    }
+                    //鏃堕棿鍐匩G鏁伴噺闃堝��
+                    if (AlarmSetting.TimePeriodNumThresold > 0)
+                    {
+                        NGRecords.Add(DateTime.Now);
+                    }
+                }
+                
+                if (NGRecords.Count >= AlarmSetting.TimePeriodNumThresold && NGRecords.Count > 0)
+                {
+                    
+                    NGRecords = NGRecords.Skip(NGRecords.Count - AlarmSetting.TimePeriodNumThresold).OrderBy(u => u).ToList();
+
+                    int timeInMinute = (int)Math.Ceiling((NGRecords[NGRecords.Count - 1] - NGRecords[0]).TotalMinutes);
+                    //鐩戞帶鏃堕棿娈�
+                    if (timeInMinute <= AlarmSetting.TimePeriod)
+                    {
+                        isAlarmRasied = true;
+                        alarmMsg += $"{DefectName}{timeInMinute}鍒嗛挓鍐匩G{NGRecords.Count}涓� ";
+                        alarmType = AlarmSetting.TimePeriodAlarmType;
+                        _timeAlarm = true;
+                    }
+                }
+
+                if (ContinuousNGNum >= AlarmSetting.ContinuousNumThreshold)
+                {
+                    isAlarmRasied = true;
+                    alarmMsg += $"{DefectName}杩炵画NG{ContinuousNGNum}涓� ";
+                    alarmType = AlarmSetting.ContinuousAlarmType;
+                    _isContinuousAlarm = true;
+                }
+                IsAlarmRaised = isAlarmRasied;
+                return isAlarmRasied;
+            }
+        }
+
+        public void ResetAlarm()
+        {
+            string msg = "";
+            lock (_lockObj)
+            {
+                IsAlarmRaised = false;                            
+                if (_isContinuousAlarm)
+                {                
+                    _isContinuousAlarm = false;
+                    ContinuousNGNum = 0;
+                    msg += "杩炵画NG鎶ヨ ";
+                }
+
+                if (_timeAlarm)
+                {
+                    
+                    _timeAlarm = false;
+                    NGRecords.Clear();
+                    msg += "鏃舵鍐匩G鎶ヨ ";
+                }
+            }
+            CommonLogger.LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"{DefectName}{msg}宸查噸缃�");
+        }
+
+    }
+}
\ No newline at end of file

--
Gitblit v1.8.0