[bugfix] 재시작할때 미보고 발생하는 케이스 수정

- pending(보류) data 추가
- Reset을 해야하는 이유는 최초 2번의 WeldingListUpload를 하기 위해 필요함
- Reset을 하니까 pending data 영역이 필요해짐

자동 시퀀스 간소화
- Sub Sequence를 자동 시퀀스 내에 함수 단위로 변경함
 .receive / report..
This commit is contained in:
최이근 2026-03-01 10:24:29 +09:00
parent 614b5f1a5b
commit 6279c02cd6
8 changed files with 290 additions and 103 deletions

View File

@ -28,6 +28,8 @@ namespace AuroraCellTracker
public int LotIdStartNo { get; set; } public int LotIdStartNo { get; set; }
public int LotIdLength { get; set; } public int LotIdLength { get; set; }
public int CellIdReceiveMethod { get; set; } public int CellIdReceiveMethod { get; set; }
[DirectoryPath]
public string reportDataLocalPath { get; set; } = "D:\\ILSOSConfig\\_device\\_cellTracker\\";
public string EquipmentName { get; set; } = "CCW";
} }
} }

View File

@ -21,6 +21,8 @@ namespace AuroraCellTracker.DaekhonCoporation
Logger _Logger = new Logger("CellTrackerDaekhon"); Logger _Logger = new Logger("CellTrackerDaekhon");
private const string REG_PATH = @"Software\H52A\H52A_ADPT_CELL"; private const string REG_PATH = @"Software\H52A\H52A_ADPT_CELL";
public event Action<string, string> OnCellReceived;
public CellInfoStr CellInfoStrings { get; set; } = new CellInfoStr(); public CellInfoStr CellInfoStrings { get; set; } = new CellInfoStr();
public ConcurrentQueue<CellInfoStr> CellInfoQueue { get; set; } = new ConcurrentQueue<CellInfoStr>(); public ConcurrentQueue<CellInfoStr> CellInfoQueue { get; set; } = new ConcurrentQueue<CellInfoStr>();
@ -318,6 +320,7 @@ namespace AuroraCellTracker.DaekhonCoporation
CalcCellInfo(str, out lotId, out cellId); CalcCellInfo(str, out lotId, out cellId);
AddCellInfo(lotId, cellId); AddCellInfo(lotId, cellId);
OnCellReceived?.Invoke(lotId, cellId);
} catch (Exception e) { } catch (Exception e) {
_Logger.E(string.Format($"{e.Message}")); _Logger.E(string.Format($"{e.Message}"));
} }
@ -339,6 +342,7 @@ namespace AuroraCellTracker.DaekhonCoporation
//CalcCellInfo(str, out lotId, out cellId); //CalcCellInfo(str, out lotId, out cellId);
AddCellInfo(lotId, cellId); AddCellInfo(lotId, cellId);
OnCellReceived?.Invoke(lotId, cellId);
} catch (Exception e) { } catch (Exception e) {
_Logger.E(string.Format($"{e.Message}")); _Logger.E(string.Format($"{e.Message}"));
} }

View File

@ -10,6 +10,12 @@ namespace AuroraCellTracker
{ {
public interface ICellTracker public interface ICellTracker
{ {
/// <summary>
/// DllSocket_ReceiveDataBuffer에서 lotId/cellId 파싱 완료 시 발화.
/// ProcessManager 등 외부에서 구독하여 직접 수신 가능.
/// </summary>
event Action<string, string> OnCellReceived;
void Initialize(eMode mode, string dllDirectory); void Initialize(eMode mode, string dllDirectory);
void Close(); void Close();
void CheckDllStatus(); void CheckDllStatus();

View File

@ -1,7 +1,9 @@
using Aurora.Api;
using Aurora.Util.HislogPlus;
using ILSOS_CCW_H52A.Data;
using ILSOS_CCW_H52A.Sequences;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using ILSOS_CCW_H52A.Sequences;
using ILSOS_CCW_H52A.Data;
namespace ILSOS_CCW_H52A.Data namespace ILSOS_CCW_H52A.Data
{ {
@ -15,7 +17,7 @@ namespace ILSOS_CCW_H52A.Data
} }
/// <summary> /// <summary>
/// Dictionary&lt;eJigNo, JigInfo&gt; 상속으로 물리 지그 번호 직접 접근과 /// Dictionary<eJigNo, JigInfo> 상속으로 물리 지그 번호 직접 접근과
/// 파이프라인 단계 접근을 동시에 지원하는 셀 스케줄러. /// 파이프라인 단계 접근을 동시에 지원하는 셀 스케줄러.
/// ///
/// - 물리 지그 접근: scheduler[eJigNo.Jig5] /// - 물리 지그 접근: scheduler[eJigNo.Jig5]
@ -31,6 +33,7 @@ namespace ILSOS_CCW_H52A.Data
/// </summary> /// </summary>
public class CellInfoScheduler : Dictionary<eJigNo, JigInfo> public class CellInfoScheduler : Dictionary<eJigNo, JigInfo>
{ {
private readonly Logger _log = new Logger("CellInfoScheduler");
public JigInfo Prefetch2 { get; private set; } // 전전 셀: 셀 정보 수신, 업로드 전 public JigInfo Prefetch2 { get; private set; } // 전전 셀: 셀 정보 수신, 업로드 전
public JigInfo Prefetch1 { get; private set; } // 전 셀: 업로드 완료, 실행 중 / 완료 체크 대상 public JigInfo Prefetch1 { get; private set; } // 전 셀: 업로드 완료, 실행 중 / 완료 체크 대상
@ -38,23 +41,27 @@ namespace ILSOS_CCW_H52A.Data
public JigInfo ReportTarget { get; set; } public JigInfo ReportTarget { get; set; }
// 재시작 보존용 독립 슬롯 — Reset()에서 건드리지 않음 // 재시작 보존용 독립 슬롯 — Reset()에서 건드리지 않음
private readonly JigInfo _pendingSlot = new JigInfo(); // 재시작 시, List를 최초 리스트 2번을 생성하는 로직 때문에.. 필요함
private readonly JigInfo _pendingSlot = new JigInfo(); // 용접 직후 (용접 완, 보고 미완)
private readonly JigInfo _pendingPrefetch1 = new JigInfo(); // 정지 직전 Prefetch1 (업로드 완료, 용접 미완)
private readonly JigInfo _pendingPrefetch2 = new JigInfo(); // 정지 직전 Prefetch2 (업로드 완료, 용접 미완)
// 재시작 전 미완료 보고 슬롯 (유효 시 non-null) // 재시작 전 미완료 보고 슬롯 (유효 시 non-null)
public JigInfo PendingComplete => HasPendingComplete ? _pendingSlot : null; public JigInfo PendingComplete => HasPendingComplete ? _pendingSlot : null;
// 재시작 보존 보고가 있는지 // 재시작 보존 보고가 있는지
public bool HasPendingComplete public bool HasPendingComplete => _pendingSlot.IsCanExist && !_pendingSlot.ReportComplete;
=> _pendingSlot.IsCanExist && !_pendingSlot.ReportComplete;
// 현재 활성 보고 슬롯 — 재시작 pending 우선 // 현재 활성 보고 슬롯 — 재시작 pending 우선
public JigInfo ActiveReportSlot public JigInfo ActiveReportSlot => HasPendingComplete ? _pendingSlot : ReportTarget;
=> HasPendingComplete ? _pendingSlot : ReportTarget;
// 보고가 필요한 상태인지 (정상 + 재시작 모두 포함) // 정지 전 미용접 슬롯이 보존돼 있는지 (재시작 후 복원 가능 여부)
public bool HasReport public bool HasPendingPrefetch =>
=> HasPendingComplete !string.IsNullOrEmpty(_pendingPrefetch1.CellId)
|| (ReportTarget != null && !ReportTarget.ReportComplete); || !string.IsNullOrEmpty(_pendingPrefetch2.CellId);
// 보고가 필요한 상태인지 (정상 + 재시작 모두 포함) >> 용접 완, 보고 미완
public bool HasReport => HasPendingComplete || (ReportTarget != null && !ReportTarget.ReportComplete);
public CellInfoScheduler() public CellInfoScheduler()
{ {
@ -62,17 +69,63 @@ namespace ILSOS_CCW_H52A.Data
Add(no, new JigInfo()); Add(no, new JigInfo());
} }
// 1-based jigNo (_WeldingJigNo 등) → 0-based eJigNo 변환 편의 인덱서 // 1-based jigNo (_WeldingJigNo 등) → 0-based eJigNo 변환 의의 인덱서
public JigInfo this[int jigNo] { public JigInfo this[int jigNo] {
get => base[(eJigNo)(jigNo - 1)]; get => base[(eJigNo)(jigNo - 1)];
} }
// Reset() 전에 호출 — 미완료 보고가 있으면 보류 슬롯(_pendingSlot)에 복사하여 보존. // Reset() 전에 호출 — 미완료 보고 및 미용접 슬롯을 보존.
public void SavePendingComplete() public void SavePendingComplete()
{ {
if (ReportTarget != null && ReportTarget.IsCanExist // 용접 완료됐으나 보고 전 정지된 경우 (_pendingSlot)
&& ReportTarget.WeldComplete && !ReportTarget.ReportComplete) if (ReportTarget != null
&& ReportTarget.IsCanExist
&& ReportTarget.WeldComplete
&& !ReportTarget.ReportComplete)
_pendingSlot.CopyFrom(ReportTarget); _pendingSlot.CopyFrom(ReportTarget);
// 업로드 완료됐으나 로터리 정지로 용접 자체가 안 된 경우 (_pendingPrefetch1/2)
// (연속셀이 들어왔을때, 중간에 멈춘 경우)
if (Prefetch1 != null
&& Prefetch1.IsCanExist
&& !string.IsNullOrEmpty(Prefetch1.CellId)
&& !Prefetch1.WeldComplete)
_pendingPrefetch1.CopyFrom(Prefetch1);
else
_pendingPrefetch1.Clear();
if (Prefetch2 != null
&& Prefetch2.IsCanExist
&& !string.IsNullOrEmpty(Prefetch2.CellId)
&& !Prefetch2.WeldComplete)
_pendingPrefetch2.CopyFrom(Prefetch2);
else
_pendingPrefetch2.Clear();
}
/// <summary>
/// 재시작 시 해당 JigNo의 보존된 셀 정보 복원 시도.
/// 성공 시 해당 슬롯을 즉시 클리어하여 한 번만 사용되도록 보장.
/// canExist=false 지그가 들어오면 슬롯을 소비(폐기)하여 이후 오염 방지.
/// </summary>
/// <returns>복원 성공 시 true (ReceivedCellInfoQueue TryDequeue 불필요)</returns>
public bool TryRestoreCell(int jigNo, out string lotId, out string cellId)
{
if (_pendingPrefetch1.JigNo == jigNo && !string.IsNullOrEmpty(_pendingPrefetch1.CellId)) {
lotId = _pendingPrefetch1.LotId;
cellId = _pendingPrefetch1.CellId;
_pendingPrefetch1.Clear();
return true;
}
if (_pendingPrefetch2.JigNo == jigNo && !string.IsNullOrEmpty(_pendingPrefetch2.CellId)) {
lotId = _pendingPrefetch2.LotId;
cellId = _pendingPrefetch2.CellId;
_pendingPrefetch2.Clear();
return true;
}
lotId = null;
cellId = null;
return false;
} }
// 보고 완료 처리 — ReportTarget 마킹 및 _pendingSlot 클리어. // 보고 완료 처리 — ReportTarget 마킹 및 _pendingSlot 클리어.
@ -90,6 +143,13 @@ namespace ILSOS_CCW_H52A.Data
/// </summary> /// </summary>
/// <param name="nextJig">새 Prefetch2로 지정할 물리 지그 (eJigNo)</param> /// <param name="nextJig">새 Prefetch2로 지정할 물리 지그 (eJigNo)</param>
public void Shift(eJigNo nextJig) public void Shift(eJigNo nextJig)
{
Prefetch1 = Prefetch2;
Prefetch2 = base[nextJig];
Prefetch2.Clear();
}
// AutoRun에서 사용되는 자료형으로 추가 (편의 인덱서 사용)
public void Shift(int nextJig)
{ {
Prefetch1 = Prefetch2; Prefetch1 = Prefetch2;
Prefetch2 = this[nextJig]; Prefetch2 = this[nextJig];
@ -99,7 +159,7 @@ namespace ILSOS_CCW_H52A.Data
/// <summary> /// <summary>
/// 전체 초기화 (AutoRun 시작 시 호출). /// 전체 초기화 (AutoRun 시작 시 호출).
/// SavePendingComplete() 호출 후 이 메서드를 호출할 것. /// SavePendingComplete() 호출 후 이 메서드를 호출할 것.
/// _pendingSlot은 재시작 보고 보존을 위해 건드리지 않음. /// _pendingSlot / _pendingPrefetch1 / _pendingPrefetch2 는 재시작 복원을 위해 건드리지 않음.
/// </summary> /// </summary>
public void Reset() public void Reset()
{ {
@ -109,7 +169,7 @@ namespace ILSOS_CCW_H52A.Data
Prefetch2 = null; Prefetch2 = null;
Prefetch1 = null; Prefetch1 = null;
ReportTarget = null; ReportTarget = null;
// _pendingSlot: SavePendingComplete()가 복사해 둔 데이터를 유지 // _pendingSlot, _pendingPrefetch1/2: SavePendingComplete()가 복사해 둔 데이터를 유지
} }
/// <summary> /// <summary>

View File

@ -23,13 +23,12 @@ namespace ILSOS_CCW_H52A.Data
public DateTime WeldEndTime; public DateTime WeldEndTime;
public TimeSpan WeldingSpanTime; // 스캐너 리스트 실행 시간 (GetTime() 결과) public TimeSpan WeldingSpanTime; // 스캐너 리스트 실행 시간 (GetTime() 결과)
// --- CellTracker 수신 정보 (GetReceiveCellInfo_SeqResult에서 채워짐) --- // CellTracker 수신 정보
public string LotId; public string LotId;
public string CellId; public string CellId;
// --- 플래그 --- // --- 플래그 ---
public bool CheckSendCellinfo; public bool CheckSendCellinfo;
public bool CheckSendPLCLaserPower;
public bool ReportComplete; public bool ReportComplete;
// --- 리포팅/뷰 용 상세 정보 --- // --- 리포팅/뷰 용 상세 정보 ---
@ -48,22 +47,21 @@ namespace ILSOS_CCW_H52A.Data
/// </summary> /// </summary>
public void CopyFrom(JigInfo src) public void CopyFrom(JigInfo src)
{ {
JigNo = src.JigNo; JigNo = src.JigNo;
ListNo = src.ListNo; ListNo = src.ListNo;
WriteTime = src.WriteTime; WriteTime = src.WriteTime;
StartAngle = src.StartAngle; StartAngle = src.StartAngle;
WeldingCount = src.WeldingCount; WeldingCount = src.WeldingCount;
IsCanExist = src.IsCanExist; IsCanExist = src.IsCanExist;
IsWelding = src.IsWelding; IsWelding = src.IsWelding;
WeldComplete = src.WeldComplete; WeldComplete = src.WeldComplete;
WeldStartTime = src.WeldStartTime; WeldStartTime = src.WeldStartTime;
WeldEndTime = src.WeldEndTime; WeldEndTime = src.WeldEndTime;
WeldingSpanTime = src.WeldingSpanTime; WeldingSpanTime = src.WeldingSpanTime;
LotId = src.LotId; LotId = src.LotId;
CellId = src.CellId; CellId = src.CellId;
CheckSendCellinfo = src.CheckSendCellinfo; CheckSendCellinfo = src.CheckSendCellinfo;
CheckSendPLCLaserPower = src.CheckSendPLCLaserPower; ReportComplete = src.ReportComplete;
ReportComplete = src.ReportComplete;
UpdateCellInfo(src.InnerCellInfo); UpdateCellInfo(src.InnerCellInfo);
} }
@ -81,40 +79,17 @@ namespace ILSOS_CCW_H52A.Data
IsCanExist = false; IsCanExist = false;
IsWelding = false; IsWelding = false;
WeldComplete = false; WeldComplete = false;
WeldStartTime = DateTime.MinValue; WeldStartTime = DateTime.MinValue;
WeldEndTime = DateTime.MinValue; WeldEndTime = DateTime.MinValue;
WeldingSpanTime = TimeSpan.Zero; WeldingSpanTime = TimeSpan.Zero;
LotId = string.Empty; LotId = string.Empty;
CellId = string.Empty; CellId = string.Empty;
CheckSendCellinfo = false; CheckSendCellinfo = false;
CheckSendPLCLaserPower = false;
ReportComplete = false; ReportComplete = false;
InnerCellInfo.CellId = string.Empty; InnerCellInfo.Clear();
InnerCellInfo.LotId = string.Empty;
InnerCellInfo.AutoRunStartTime = DateTime.MinValue;
InnerCellInfo.WeldingStartTime = DateTime.MinValue;
InnerCellInfo.WeldingEndTime = DateTime.MinValue;
InnerCellInfo.WeldingSpanTimeMilliseconds = string.Empty;
InnerCellInfo.TodayProduct = 0;
InnerCellInfo.TotalProduct = 0;
InnerCellInfo.RecipeNo = 0;
InnerCellInfo.WeldStartTime = string.Empty;
InnerCellInfo.WeldTime = string.Empty;
InnerCellInfo.WorkCellId = string.Empty;
InnerCellInfo.WorkLotId = string.Empty;
InnerCellInfo.LBAD_Judge = string.Empty;
InnerCellInfo.LDD_Judge = string.Empty;
InnerCellInfo.LaserPowerCore = string.Empty;
InnerCellInfo.LaserPowerRing = string.Empty;
InnerCellInfo.MarkSpeed = string.Empty;
InnerCellInfo.FocalLength = string.Empty;
InnerCellInfo.WeldingJigNo = string.Empty;
InnerCellInfo.LaserPowerByLBAD = string.Empty;
InnerCellInfo.CheckCanExist = false;
InnerCellInfo.CheckScannerListEnd = false;
} }
/// <summary> /// <summary>

View File

@ -1,10 +1,12 @@
using Aurora; using Aurora;
using Aurora.Api; using Aurora.Api;
using Aurora.Util.HislogPlus; using Aurora.Util.HislogPlus;
using AuroraCellTracker;
using AuroraLaserScanner; using AuroraLaserScanner;
using AuroraPLC; using AuroraPLC;
using ILSOS_CCW_H52A.Data; using ILSOS_CCW_H52A.Data;
using ILSOS_CCW_H52A.Device; using ILSOS_CCW_H52A.Device;
using OpenCvSharp;
using System; using System;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
@ -38,9 +40,15 @@ namespace ILSOS_CCW_H52A.Sequences.ProcessObjects
private IAuroraEnvironment _env; private IAuroraEnvironment _env;
private PLCControllerCCWH52A _plc; private PLCControllerCCWH52A _plc;
private ScannerCCWH52A _scanner; private ScannerCCWH52A _scanner;
private CellTracker _cellTracker;
public CellInfoScheduler cellScheduler { get; set; } public CellInfoScheduler cellScheduler { get; set; }
/// CellTracker 콜백에서 직접 수신한 (LotId, CellId) 큐.
/// DllSocket_ReceiveDataBuffer 발화 시 즉시 Enqueue — 시퀀스는 TryDequeue로 소비.
public ConcurrentQueue<(string LotId, string CellId)> ReceivedCellInfoQueue { get; }
= new ConcurrentQueue<(string, string)>();
public const double compensateEncoderReset = 0.015; // 엔코더 리셋 보상 각도 설정(70도/sec 기준 약 0.015도) public const double compensateEncoderReset = 0.015; // 엔코더 리셋 보상 각도 설정(70도/sec 기준 약 0.015도)
public const int RotaryJigCount = 16; public const int RotaryJigCount = 16;
public const int RotaryMaxAngle = 360; public const int RotaryMaxAngle = 360;
@ -53,8 +61,21 @@ namespace ILSOS_CCW_H52A.Sequences.ProcessObjects
_env = env; _env = env;
_plc = _env.DeviceManager[DeviceIds.PLCDevice] as PLCControllerCCWH52A; _plc = _env.DeviceManager[DeviceIds.PLCDevice] as PLCControllerCCWH52A;
_scanner = _env.DeviceManager[DeviceIds.Scanner] as ScannerCCWH52A; _scanner = _env.DeviceManager[DeviceIds.Scanner] as ScannerCCWH52A;
_cellTracker = _env.DeviceManager[CommonDeviceIds.CellTracker] as CellTracker;
//CellTracker의 OnCellReceived 이벤트를 구독하여 콜백 수신 시 CellQueue에 직접 적재
if (_cellTracker._CellTracker != null)
_cellTracker._CellTracker.OnCellReceived += OnCellReceived;
cellScheduler = new CellInfoScheduler(); cellScheduler = new CellInfoScheduler();
} }
private void OnCellReceived(string lotId, string cellId)
{
ReceivedCellInfoQueue.Enqueue((lotId, cellId));
_log.I($"Cell Tracker CallBack Received >> LotId({lotId}) / CellId({cellId})");
}
public IEnumerable<bool> CheckRotaryState() public IEnumerable<bool> CheckRotaryState()
{ {
List<bool> rotaryStates = new List<bool>(); List<bool> rotaryStates = new List<bool>();

View File

@ -19,6 +19,8 @@ using ILSOS_CCW_H52A.Device;
using ILSOS_CCW_H52A.Models; using ILSOS_CCW_H52A.Models;
using ILSOS_CCW_H52A.RMS; using ILSOS_CCW_H52A.RMS;
using ILSOS_CCW_H52A.Sequences.ProcessObjects; using ILSOS_CCW_H52A.Sequences.ProcessObjects;
using Microsoft.Win32;
using OpenCvSharp;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
@ -26,6 +28,7 @@ using System.Linq;
using System.Reflection; using System.Reflection;
using System.Threading; using System.Threading;
using System.Windows; using System.Windows;
using System.Windows.Media.Animation;
using WeldingCommon; using WeldingCommon;
using WeldingCommon.Alarm; using WeldingCommon.Alarm;
using WeldingCommon.Devices; using WeldingCommon.Devices;
@ -57,9 +60,9 @@ namespace ILSOS_CCW_H52A.Sequences
public const string SEQ_CHECK_SCANNER_LIST_COMPLETE = "[SeqAutoRunCCWH52A] Check Scanner List Complete"; public const string SEQ_CHECK_SCANNER_LIST_COMPLETE = "[SeqAutoRunCCWH52A] Check Scanner List Complete";
const string SEQ_READY_SCANNER_LIST = "[SeqAutoRunCCWH52A] Ready ScannerList"; const string SEQ_READY_SCANNER_LIST = "[SeqAutoRunCCWH52A] Ready ScannerList";
const string SEQ_SET_PARAMS_RECEIVE_CELL_INFO_SEQ = "[SeqAutoRunCCWH52A] Set Sequence Param (ReceiveCellInfo Seq)"; //const string SEQ_SET_PARAMS_RECEIVE_CELL_INFO_SEQ = "[SeqAutoRunCCWH52A] Set Sequence Param (ReceiveCellInfo Seq)";
const string SEQ_DO_ID_RECEIVE_CELL_INFO_SEQ = "[SeqAutoRunCCWH52A] Process (ReceiveCellInfo Seq)"; //const string SEQ_DO_ID_RECEIVE_CELL_INFO_SEQ = "[SeqAutoRunCCWH52A] Process (ReceiveCellInfo Seq)";
const string SEQ_GET_PARAMS_RECEIVE_CELL_INFO_SEQ = "[SeqAutoRunCCWH52A] Get Sequence Result (ReceiveCellInfo Seq)"; //const string SEQ_GET_PARAMS_RECEIVE_CELL_INFO_SEQ = "[SeqAutoRunCCWH52A] Get Sequence Result (ReceiveCellInfo Seq)";
const string SEQ_SET_PARAMS_UPLOAD_WELDING_LIST_SEQ = "[SeqAutoRunCCWH52A] Set Sequence Param (UploadWeldingList Seq)"; const string SEQ_SET_PARAMS_UPLOAD_WELDING_LIST_SEQ = "[SeqAutoRunCCWH52A] Set Sequence Param (UploadWeldingList Seq)";
const string SEQ_DO_ID_UPLOAD_WELDING_LIST_SEQ = "[SeqAutoRunCCWH52A] Process (UploadWeldingList Seq)"; const string SEQ_DO_ID_UPLOAD_WELDING_LIST_SEQ = "[SeqAutoRunCCWH52A] Process (UploadWeldingList Seq)";
@ -68,10 +71,11 @@ namespace ILSOS_CCW_H52A.Sequences
const string SEQ_EXECUTE_WELDING = "[SeqAutoRunCCWH52A] Execute Welding"; const string SEQ_EXECUTE_WELDING = "[SeqAutoRunCCWH52A] Execute Welding";
const string SEQ_REQUEST_UNLOAD_CELL = "[SeqAutoRunCCWH52A] Request Unload Cell"; const string SEQ_REQUEST_UNLOAD_CELL = "[SeqAutoRunCCWH52A] Request Unload Cell";
//const string SEQ_WAIT_LBAD_JUDGE = "[SeqAutoRunCCWH52A] Wait LBAD Judge"; //const string SEQ_WAIT_LBAD_JUDGE = "[SeqAutoRunCCWH52A] Wait LBAD Judge";
const string SEQ_REPORT_CELL_RESULT = "[SeqAutoRunCCWH52A] Report Cell Result";
const string SEQ_SET_PARAMS_REPORT_CELL_RESULT_SEQ = "[SeqAutoRunCCWH52A] Set Sequence Param (ReportCellResult Seq)"; //const string SEQ_SET_PARAMS_REPORT_CELL_RESULT_SEQ = "[SeqAutoRunCCWH52A] Set Sequence Param (ReportCellResult Seq)";
const string SEQ_DO_ID_REPORT_CELL_RESULT_SEQ = "[SeqAutoRunCCWH52A] Process (ReportCellResult Seq)"; //const string SEQ_DO_ID_REPORT_CELL_RESULT_SEQ = "[SeqAutoRunCCWH52A] Process (ReportCellResult Seq)";
const string SEQ_GET_RESULT_REPORT_CELL_RESULT_SEQ = "[SeqAutoRunCCWH52A] Get Sequence Result (ReportCellResult Seq)"; //const string SEQ_GET_RESULT_REPORT_CELL_RESULT_SEQ = "[SeqAutoRunCCWH52A] Get Sequence Result (ReportCellResult Seq)";
//const string SEQ_REPORT_CELLINFO_TO_PLC = "[SeqAutoRunCCWH52A] ReportCellInfoToPLC"; //const string SEQ_REPORT_CELLINFO_TO_PLC = "[SeqAutoRunCCWH52A] ReportCellInfoToPLC";
const string SEQ_CHECK_CYCLE_STOP = "[SeqAutoRunCCWH52A] Check Cycle Stop"; const string SEQ_CHECK_CYCLE_STOP = "[SeqAutoRunCCWH52A] Check Cycle Stop";
@ -168,9 +172,10 @@ namespace ILSOS_CCW_H52A.Sequences
sb.AddAction(SEQ_CHECK_SCANNER_LIST_COMPLETE, CheckScannerListComplete); sb.AddAction(SEQ_CHECK_SCANNER_LIST_COMPLETE, CheckScannerListComplete);
sb.AddDecision(SEQ_READY_SCANNER_LIST, ReadyScannerList); sb.AddDecision(SEQ_READY_SCANNER_LIST, ReadyScannerList);
sb.AddAction(SEQ_SET_PARAMS_RECEIVE_CELL_INFO_SEQ, SetReceiveCellInfo_SeqParams); // Cell 정보를 받아와 입력한다. #warning 아래 서브시퀀스가 CellTracker에서 받은 데이터를 WeldingData에 넣기만함, ProcessManager에서 Cell정보를 직접 Callback으로 받도록 수정함
sb.AddSubsequence(SEQ_DO_ID_RECEIVE_CELL_INFO_SEQ, SequenceManager.GetSeqBuilder_SeqReceiveCellInfo()); // cell 정보를 받아오는 Sub Seq 실행 //sb.AddAction(SEQ_SET_PARAMS_RECEIVE_CELL_INFO_SEQ, SetReceiveCellInfo_SeqParams); // Cell 정보를 받아와 입력한다.
sb.AddAction(SEQ_GET_PARAMS_RECEIVE_CELL_INFO_SEQ, GetReceiveCellInfo_SeqResult); // Cell 정보를 가져온다 //sb.AddSubsequence(SEQ_DO_ID_RECEIVE_CELL_INFO_SEQ, SequenceManager.GetSeqBuilder_SeqReceiveCellInfo()); // cell 정보를 받아오는 Sub Seq 실행
//sb.AddAction(SEQ_GET_PARAMS_RECEIVE_CELL_INFO_SEQ, GetReceiveCellInfo_SeqResult); // Cell 정보를 가져온다
sb.AddAction(SEQ_SET_PARAMS_UPLOAD_WELDING_LIST_SEQ, SetUploadWeldingList_SeqParams); sb.AddAction(SEQ_SET_PARAMS_UPLOAD_WELDING_LIST_SEQ, SetUploadWeldingList_SeqParams);
sb.AddSubsequence(SEQ_DO_ID_UPLOAD_WELDING_LIST_SEQ, SequenceManager.GetSeqBuilder_SeqUploadWeldingList()); sb.AddSubsequence(SEQ_DO_ID_UPLOAD_WELDING_LIST_SEQ, SequenceManager.GetSeqBuilder_SeqUploadWeldingList());
@ -178,13 +183,15 @@ namespace ILSOS_CCW_H52A.Sequences
sb.AddAction(SEQ_EXECUTE_WELDING, ExecuteWelding); sb.AddAction(SEQ_EXECUTE_WELDING, ExecuteWelding);
sb.AddAction(SEQ_REQUEST_UNLOAD_CELL, RequestUnloadCell); sb.AddAction(SEQ_REQUEST_UNLOAD_CELL, RequestUnloadCell);
sb.AddDecision(SEQ_CHECK_CAN_WELDED, CheckCanWelded);
sb.AddAction(SEQ_REPORT_CELL_RESULT, ReportCellResult);
sb.AddAction(SEQ_SET_PARAMS_REPORT_CELL_RESULT_SEQ, SetReportCellResult_SeqParams); #warning ReportCellResult함수로 아래 시퀀스 대체
sb.AddSubsequence(SEQ_DO_ID_REPORT_CELL_RESULT_SEQ, SequenceManager.GetSeqBuilder_SeqReportCellResult()); //sb.AddAction(SEQ_SET_PARAMS_REPORT_CELL_RESULT_SEQ, SetReportCellResult_SeqParams);
sb.AddAction(SEQ_GET_RESULT_REPORT_CELL_RESULT_SEQ, GetReportCellResult_SeqResult); //sb.AddSubsequence(SEQ_DO_ID_REPORT_CELL_RESULT_SEQ, SequenceManager.GetSeqBuilder_SeqReportCellResult());
//sb.AddAction(SEQ_GET_RESULT_REPORT_CELL_RESULT_SEQ, GetReportCellResult_SeqResult);
sb.AddDecision(SEQ_CHECK_CYCLE_STOP, CheckCycleStop); sb.AddDecision(SEQ_CHECK_CYCLE_STOP, CheckCycleStop);
sb.AddDecision(SEQ_CHECK_CAN_WELDED, CheckCanWelded);
sb.AddAction(SEQ_SAVE_RESULT_DATA, SaveResultData); // 해당 공정의 정보를 기록 함. sb.AddAction(SEQ_SAVE_RESULT_DATA, SaveResultData); // 해당 공정의 정보를 기록 함.
sb.AddAction(SEQ_WRITE_COMPLETION_PLC_BIT, WriteCompletionPLCBit); // 정상적으로 종료 되면, complete bit write sb.AddAction(SEQ_WRITE_COMPLETION_PLC_BIT, WriteCompletionPLCBit); // 정상적으로 종료 되면, complete bit write
@ -193,12 +200,11 @@ namespace ILSOS_CCW_H52A.Sequences
sb.Flows(sb.Init > sb[SEQ_ENTER] > sb[SEQ_CHECK_INIT_CONDITION] > sb[SEQ_FORK_ENCODER_MONITOR] > sb[SEQ_CHECK_LOAD_COMPLETE] sb.Flows(sb.Init > sb[SEQ_ENTER] > sb[SEQ_CHECK_INIT_CONDITION] > sb[SEQ_FORK_ENCODER_MONITOR] > sb[SEQ_CHECK_LOAD_COMPLETE]
> sb[SEQ_CHECK_SCANNER_LIST_COMPLETE] > sb[SEQ_READY_SCANNER_LIST] > sb[SEQ_CHECK_SCANNER_LIST_COMPLETE] > sb[SEQ_READY_SCANNER_LIST]
> sb[SEQ_SET_PARAMS_RECEIVE_CELL_INFO_SEQ] > sb[SEQ_DO_ID_RECEIVE_CELL_INFO_SEQ] > sb[SEQ_GET_PARAMS_RECEIVE_CELL_INFO_SEQ]
> sb[SEQ_SET_PARAMS_UPLOAD_WELDING_LIST_SEQ] > sb[SEQ_DO_ID_UPLOAD_WELDING_LIST_SEQ] > sb[SEQ_GET_RESULT_UPLOAD_WELDING_LIST_SEQ] > sb[SEQ_SET_PARAMS_UPLOAD_WELDING_LIST_SEQ] > sb[SEQ_DO_ID_UPLOAD_WELDING_LIST_SEQ] > sb[SEQ_GET_RESULT_UPLOAD_WELDING_LIST_SEQ]
> sb[SEQ_EXECUTE_WELDING] > sb[SEQ_REQUEST_UNLOAD_CELL] > sb[SEQ_CHECK_CAN_WELDED] > sb[SEQ_EXECUTE_WELDING] > sb[SEQ_REQUEST_UNLOAD_CELL] > sb[SEQ_CHECK_CAN_WELDED] > sb[SEQ_REPORT_CELL_RESULT]
> sb[SEQ_SET_PARAMS_REPORT_CELL_RESULT_SEQ] > sb[SEQ_DO_ID_REPORT_CELL_RESULT_SEQ] > sb[SEQ_GET_RESULT_REPORT_CELL_RESULT_SEQ] //> sb[SEQ_SET_PARAMS_REPORT_CELL_RESULT_SEQ] > sb[SEQ_DO_ID_REPORT_CELL_RESULT_SEQ] > sb[SEQ_GET_RESULT_REPORT_CELL_RESULT_SEQ]
> sb[SEQ_SAVE_RESULT_DATA] > sb[SEQ_CHECK_CYCLE_STOP] > sb[SEQ_SAVE_RESULT_DATA] > sb[SEQ_CHECK_CYCLE_STOP]
> sb[SEQ_WRITE_COMPLETION_PLC_BIT] > sb[SEQ_JOIN_ENCODER_MONITOR] > sb[SEQ_COMPLETE]); > sb[SEQ_WRITE_COMPLETION_PLC_BIT] > sb[SEQ_JOIN_ENCODER_MONITOR] > sb[SEQ_COMPLETE] > sb.Final);
sb.Flows(sb[SEQ_READY_SCANNER_LIST] > sb[SEQ_EXECUTE_WELDING]); sb.Flows(sb[SEQ_READY_SCANNER_LIST] > sb[SEQ_EXECUTE_WELDING]);
@ -206,7 +212,7 @@ namespace ILSOS_CCW_H52A.Sequences
sb.Flows(sb[SEQ_CHECK_CYCLE_STOP] > sb[SEQ_CHECK_LOAD_COMPLETE]); sb.Flows(sb[SEQ_CHECK_CYCLE_STOP] > sb[SEQ_CHECK_LOAD_COMPLETE]);
sb.Flows(sb[SEQ_CHECK_INIT_CONDITION] > sb[SEQ_INIT_CONDITION_ERROR] > sb.Final); sb.Flows(sb[SEQ_CHECK_INIT_CONDITION] > sb[SEQ_INIT_CONDITION_ERROR] > sb.Final);
sb.Flows(sb[SEQ_FORK_ENCODER_MONITOR] > sb[SEQ_ENCODER_MONITOR] > sb[SEQ_JOIN_ENCODER_MONITOR] > sb[SEQ_COMPLETE]); sb.Flows(sb[SEQ_FORK_ENCODER_MONITOR] > sb[SEQ_ENCODER_MONITOR] > sb[SEQ_JOIN_ENCODER_MONITOR] > sb[SEQ_COMPLETE] > sb.Final);
#region #region
//sb.Flows(sb[SEQ_FORK_ENCODER_MONITOR] > sb[SEQ_ENCODER_MONITOR]); //sb.Flows(sb[SEQ_FORK_ENCODER_MONITOR] > sb[SEQ_ENCODER_MONITOR]);
@ -443,6 +449,8 @@ namespace ILSOS_CCW_H52A.Sequences
// SavePendingComplete()로 _pendingSlot에 복사한 뒤 Reset()을 호출한다. // SavePendingComplete()로 _pendingSlot에 복사한 뒤 Reset()을 호출한다.
_CellScheduler.SavePendingComplete(); _CellScheduler.SavePendingComplete();
if (_CellScheduler.HasPendingPrefetch)
Log.I("[PendingRestore] 미용접 셀 보존됨 — 재시작 후 JigNo 매칭 시 복원 예정");
_CellScheduler.Reset(); _CellScheduler.Reset();
// ───────────────────────────────────────────────────────────────────────────── // ─────────────────────────────────────────────────────────────────────────────
@ -690,11 +698,11 @@ namespace ILSOS_CCW_H52A.Sequences
else else
canExist = GetRotaryCanExist(_WeldingJigNo); canExist = GetRotaryCanExist(_WeldingJigNo);
Log.I("Can Exist : " + canExist.ToString() + ", JigNo " + _WeldingJigNo + " ,CountNo " + _WeldingCount + ", StartAngle(Y) : " + _WeldingStartAngle); //Log.I("Can Exist : " + canExist.ToString() + ", JigNo " + _WeldingJigNo + " ,CountNo " + _WeldingCount + ", StartAngle(Y) : " + _WeldingStartAngle);
// canExist 여부와 무관하게 매 지그마다 파이프라인 전진 // canExist 여부와 무관하게 매 지그마다 파이프라인 전진
// canExist=false 지그도 Shift()해야 Prefetch1 타이밍이 올바르게 유지됨. // canExist=false 지그도 Shift()해야 Prefetch1 타이밍이 올바르게 유지됨.
_CellScheduler.Shift((eJigNo)(_WeldingJigNo - 1)); _CellScheduler.Shift(_WeldingJigNo);
_CellScheduler.Prefetch2.JigNo = _WeldingJigNo; _CellScheduler.Prefetch2.JigNo = _WeldingJigNo;
_CellScheduler.Prefetch2.ListNo = _WeldingScannerListNo; _CellScheduler.Prefetch2.ListNo = _WeldingScannerListNo;
@ -703,6 +711,36 @@ namespace ILSOS_CCW_H52A.Sequences
_CellScheduler.Prefetch2.WeldingCount = _WeldingCount; _CellScheduler.Prefetch2.WeldingCount = _WeldingCount;
_CellScheduler.Prefetch2.IsCanExist = canExist; _CellScheduler.Prefetch2.IsCanExist = canExist;
#warning OC2 ACW 기준 >> Cell Tracker는 어느 시점에 데이터는 주는지 모르겠지만, '전전전 셀' 쯤에서 이미 건네받음! 다른 프로젝트에서 확인 필요함
// 복원 우선: 정지 전 업로드됐으나 로터리 감속·정지로 용접 미완된 셀 정보 복원.
// canExist=false 지그도 TryRestoreCell을 호출하여 슬롯 소비(폐기) — 이후 오염 방지.
if (_CellScheduler.TryRestoreCell(_WeldingJigNo, out var rLot, out var rCell)) {
if (canExist) {
_CellScheduler.Prefetch2.LotId = rLot;
_CellScheduler.Prefetch2.CellId = rCell;
Status.GetProcessingWeldingData().WorkLotId = rLot;
Status.GetProcessingWeldingData().WorkCellId = rCell;
Log.I($"[PendingRestore] Jig{_WeldingJigNo} 셀 복원 >> CellId({rCell})");
}
else {
Log.W($"[PendingRestore] Jig{_WeldingJigNo} canExist=false, 복원 데이터 폐기 >> CellId({rCell})");
}
}
else if (ProcessManager.Instance.ReceivedCellInfoQueue.TryDequeue(out var cell)) {
_CellScheduler.Prefetch2.LotId = cell.LotId;
_CellScheduler.Prefetch2.CellId = cell.CellId;
Status.GetProcessingWeldingData().WorkLotId = cell.LotId;
Status.GetProcessingWeldingData().WorkCellId = cell.CellId;
}
Log.I($"상태 시프트(Rotate) >> 용접 전전셀({_CellScheduler.Prefetch2.CellId}) [CanExist({_CellScheduler.Prefetch2.IsCanExist})] [JigNo({_CellScheduler.Prefetch2.JigNo})] " +
$"[ListNo({_CellScheduler.Prefetch2.ListNo})] [WeldingCount({_CellScheduler.Prefetch2.WeldingCount})]" +
$"[StartAngle(Y)({_CellScheduler.Prefetch2.StartAngle})]");
Log.I($"이번 용접대상 >> 용접 전셀({_CellScheduler.Prefetch1.CellId}) [CanExist({_CellScheduler.Prefetch1.IsCanExist})] [JigNo({_CellScheduler.Prefetch1.JigNo})] " +
$"[ListNo({_CellScheduler.Prefetch1.ListNo})] [WeldingCount({_CellScheduler.Prefetch1.WeldingCount})]" +
$"[StartAngle(Y)({_CellScheduler.Prefetch1.StartAngle})]");
if (canExist) { if (canExist) {
#region 용접할 Objects 선택 #region 용접할 Objects 선택
if (_WeldingJigNo - 1 < _ScannerCanvasUserCtrl.Model.Layers.Length) { if (_WeldingJigNo - 1 < _ScannerCanvasUserCtrl.Model.Layers.Length) {
@ -718,7 +756,7 @@ namespace ILSOS_CCW_H52A.Sequences
_RecipeNo = _RecipeManager.ActivatedRecipe().Id; _RecipeNo = _RecipeManager.ActivatedRecipe().Id;
SetWeldingData(); SetWeldingData();
return SEQ_SET_PARAMS_RECEIVE_CELL_INFO_SEQ; return SEQ_SET_PARAMS_UPLOAD_WELDING_LIST_SEQ;
} }
else { else {
return SEQ_EXECUTE_WELDING; return SEQ_EXECUTE_WELDING;
@ -847,22 +885,22 @@ namespace ILSOS_CCW_H52A.Sequences
return SequenceAction.Ok(); return SequenceAction.Ok();
} }
private SequenceActionResult SetReceiveCellInfo_SeqParams(SequenceContext context, string id, SequenceActionResult param) //private SequenceActionResult SetReceiveCellInfo_SeqParams(SequenceContext context, string id, SequenceActionResult param)
{ //{
SeqReceiveCellInfo_InitParam seqParams = new SeqReceiveCellInfo_InitParam() { // SeqReceiveCellInfo_InitParam seqParams = new SeqReceiveCellInfo_InitParam() {
}; // };
return SequenceAction.Ok(seqParams); // return SequenceAction.Ok(seqParams);
} //}
private SequenceActionResult GetReceiveCellInfo_SeqResult(SequenceContext context, string id, SequenceActionResult param) //private SequenceActionResult GetReceiveCellInfo_SeqResult(SequenceContext context, string id, SequenceActionResult param)
{ //{
var resultOutParam = param.Param as SeqReceiveCellInfo_OutParam; // var resultOutParam = param.Param as SeqReceiveCellInfo_OutParam;
if (resultOutParam.Success == false) { // if (resultOutParam.Success == false) {
return null; // return null;
} // }
return SequenceAction.Ok(); // return SequenceAction.Ok();
} //}
private SequenceActionResult ExecuteWelding(SequenceContext context, string id, SequenceActionResult param) private SequenceActionResult ExecuteWelding(SequenceContext context, string id, SequenceActionResult param)
{ {
@ -905,7 +943,8 @@ namespace ILSOS_CCW_H52A.Sequences
double encoderX, currentAngle; double encoderX, currentAngle;
_Scanner.GetEncoder(out encoderX, out currentAngle, true); _Scanner.GetEncoder(out encoderX, out currentAngle, true);
double CurrentPosPLC = GetRotaryCurrentPosition(); double CurrentPosPLC = GetRotaryCurrentPosition();
bool WeldingInPosition = encoderX > _Scanner.Config.MarkingRangeMinRotate + 11.25 - send_time_offset - 0.1 && encoderX < _Scanner.Config.MarkingRangeMinRotate + 11.25 - send_time_offset + 0.1; bool WeldingInPosition = encoderX > _Scanner.Config.MarkingRangeMinRotate + 11.25 - send_time_offset - 0.1
&& encoderX < _Scanner.Config.MarkingRangeMinRotate + 11.25 - send_time_offset + 0.1;
// ── JigScheduler: 포크 내에서 참조 캡처 (Shift와의 경합 방지) ────── // ── JigScheduler: 포크 내에서 참조 캡처 (Shift와의 경합 방지) ──────
// Prefetch1: 2회 전 업로드된 지그 = 현재 물리적으로 실행 중인 지그. // Prefetch1: 2회 전 업로드된 지그 = 현재 물리적으로 실행 중인 지그.
@ -945,7 +984,7 @@ namespace ILSOS_CCW_H52A.Sequences
var IsLaserToggle = ChangeChecker.IsChangedBool("LaserToggle", LaserIO); var IsLaserToggle = ChangeChecker.IsChangedBool("LaserToggle", LaserIO);
if (IsLaserToggle) if (IsLaserToggle)
Log.I($"Fork Laser On({IsLaserToggle}) Encoder X : ({encoderX}), Encoder Y : ({currentAngle}), PLC Rotary : ({CurrentPosPLC}), List {executeTarget?.ListNo}, JigNo : ({executeTarget?.JigNo})"); Log.I($"Fork Laser On({LaserIO}) Encoder X : ({encoderX}), Encoder Y : ({currentAngle}), PLC Rotary : ({CurrentPosPLC}), List {executeTarget?.ListNo}, JigNo : ({executeTarget?.JigNo})");
for (int i = 0; i < _RotaryJigCount; i++) { for (int i = 0; i < _RotaryJigCount; i++) {
if (_PLC.ReadBit((int)eBitInput.PLC_USE_WELD_JIG_1 + i).data == false) { if (_PLC.ReadBit((int)eBitInput.PLC_USE_WELD_JIG_1 + i).data == false) {
@ -998,6 +1037,58 @@ namespace ILSOS_CCW_H52A.Sequences
Status.GetProcessingWeldingData().WeldingJigNo = report.JigNo.ToString(); Status.GetProcessingWeldingData().WeldingJigNo = report.JigNo.ToString();
} }
} }
private SequenceActionResult ReportCellResult(SequenceContext context, string id, SequenceActionResult param)
{
Status.SetWorkingPosition(eWorkingPosition.REPORTING_RESULT);
string strDate = DateTime.Now.Date.ToString("yyyyMMdd");
string strTime = DateTime.Now.ToString("HHmmss");
var wd = Status.GetProcessingWeldingData();
string reportDataLocalPath = _CellTracker._CellTrackerConfig.reportDataLocalPath;
string equipName = _CellTracker._CellTrackerConfig.EquipmentName;
string directory = string.Format(reportDataLocalPath + "{0}", strDate);
if (!Directory.Exists(directory))
Directory.CreateDirectory(directory);
string strPath = string.Format(reportDataLocalPath + "{0}\\{1}_{2}_{3}.csv",
strDate, strDate, "H52A_" + equipName, strTime.Substring(0, 2));
// ECS 전송용 strData 빌드
string strData = string.Format(
"Date={0},Time={1},LotID={2},CellID={3}," +
equipName + "DATA001={4}," +
equipName + "DATA002={5}," +
equipName + "DATA003={6}," +
equipName + "DATA004={7}," +
equipName + "DATA005={8}," +
equipName + "DATA006={9}," +
equipName + "DATA007={10}," +
equipName + "DATA008={11}," +
equipName + "DATA009={12}",
strDate, strTime, wd.LotId, wd.CellId,
wd.RecipeNo, wd.LaserPowerCore, wd.MarkSpeed, wd.FocalLength,
wd.WeldingJigNo, wd.WeldingSpanTimeMilliseconds, wd.LaserPowerByLBAD,
wd.TodayProduct, wd.TotalProduct);
_CellTracker.SendEcsData(wd.CellId, strPath, strData);
// 로컬 CSV 저장
string strItem = "//Date, Time, LotID, CellID, RecipeNo, LaserPower, MarkSpeed, FocalLength, HeadNo, WeldingTime, LaserPowerByLBAD, TodayCount, TotalCount";
string strCsvData = string.Format("{0}, {1}, {2}, {3}, {4}, {5}, {6}, {7}, {8}, {9}, {10}, {11}, {12}",
strDate, strTime, wd.LotId, wd.CellId,
wd.RecipeNo, wd.LaserPowerCore, wd.MarkSpeed, wd.FocalLength,
wd.WeldingJigNo, wd.WeldingSpanTimeMilliseconds, wd.LaserPowerByLBAD,
wd.TodayProduct, wd.TotalProduct);
WeldingCommon.Utils.ExcelManagementUnit.AppendStringInCSV(strPath, strItem, strCsvData);
// 보고 완료: ReportTarget.ReportComplete=true 설정 + pendingSlot 클리어
_CellScheduler.CompleteReport();
return SequenceAction.Ok();
}
private SequenceActionResult SetReportCellResult_SeqParams(SequenceContext context, string id, SequenceActionResult param) private SequenceActionResult SetReportCellResult_SeqParams(SequenceContext context, string id, SequenceActionResult param)
{ {
Status.SetWorkingPosition(eWorkingPosition.REPORTING_RESULT); Status.SetWorkingPosition(eWorkingPosition.REPORTING_RESULT);
@ -1049,7 +1140,7 @@ namespace ILSOS_CCW_H52A.Sequences
if (_CellScheduler.HasPendingComplete) { if (_CellScheduler.HasPendingComplete) {
var p = _CellScheduler.PendingComplete; var p = _CellScheduler.PendingComplete;
Log.I($"[PendingReport] 재시작 전 미완료 보고: LotId={p.LotId}, CellId={p.CellId}, JigNo={p.JigNo}"); Log.I($"[PendingReport] 재시작 전 미완료 보고: LotId={p.LotId}, CellId={p.CellId}, JigNo={p.JigNo}");
return SEQ_SET_PARAMS_REPORT_CELL_RESULT_SEQ; return SEQ_REPORT_CELL_RESULT;
} }
// ───────────────────────────────────────────────────────────────────────────── // ─────────────────────────────────────────────────────────────────────────────
@ -1057,7 +1148,7 @@ namespace ILSOS_CCW_H52A.Sequences
// - ReportTarget이 설정돼 있고 아직 보고 완료되지 않은 경우 // - ReportTarget이 설정돼 있고 아직 보고 완료되지 않은 경우
// - 첫번째, 두번째 반복은 SetReportTarget이 호출되지 않으므로 자연스럽게 통과 // - 첫번째, 두번째 반복은 SetReportTarget이 호출되지 않으므로 자연스럽게 통과
if (_CellScheduler.HasReport) if (_CellScheduler.HasReport)
return SEQ_SET_PARAMS_REPORT_CELL_RESULT_SEQ; return SEQ_REPORT_CELL_RESULT;
return SEQ_CHECK_CYCLE_STOP; return SEQ_CHECK_CYCLE_STOP;
} }
@ -1073,7 +1164,6 @@ namespace ILSOS_CCW_H52A.Sequences
} }
private SequenceActionResult SaveResultData(SequenceContext context, string id, SequenceActionResult param) private SequenceActionResult SaveResultData(SequenceContext context, string id, SequenceActionResult param)
{ {
context.PutValue(ContextKey.KEY_SEQUENCE_RESULT, true); context.PutValue(ContextKey.KEY_SEQUENCE_RESULT, true);
return SequenceAction.Ok(); return SequenceAction.Ok();
} }
@ -1201,6 +1291,12 @@ namespace ILSOS_CCW_H52A.Sequences
} }
} }
// 정지 시점 파이프라인 상태 로그 (재시작 후 복원 여부 사전 확인용)
if (_CellScheduler.Prefetch1 != null && !string.IsNullOrEmpty(_CellScheduler.Prefetch1.CellId))
Log.I($"Stoped Seq >> Prefetch1[Jig{_CellScheduler.Prefetch1.JigNo}] CellId={_CellScheduler.Prefetch1.CellId}, WeldComplete={_CellScheduler.Prefetch1.WeldComplete}");
if (_CellScheduler.Prefetch2 != null && !string.IsNullOrEmpty(_CellScheduler.Prefetch2.CellId))
Log.I($"Stoped Seq >> Prefetch2[Jig{_CellScheduler.Prefetch2.JigNo}] CellId={_CellScheduler.Prefetch2.CellId}, WeldComplete={_CellScheduler.Prefetch2.WeldComplete}");
//PLC All BIT OFF //PLC All BIT OFF
for (int i = 0; i < _RotaryJigCount; i++) for (int i = 0; i < _RotaryJigCount; i++)
_PLC.WriteBit(eBitOutput.PC_WELD_COMPLETE_1 + i, false); _PLC.WriteBit(eBitOutput.PC_WELD_COMPLETE_1 + i, false);

View File

@ -103,11 +103,34 @@ namespace WeldingCommon.Data
public WeldingData() public WeldingData()
{ {
Clear();
} }
public void Clear() public void Clear()
{ {
this.CellId = string.Empty;
this.LotId = string.Empty;
this.AutoRunStartTime = DateTime.MinValue;
this.WeldingStartTime = DateTime.MinValue;
this.WeldingEndTime = DateTime.MinValue;
this.WeldingSpanTimeMilliseconds = string.Empty;
this.TodayProduct = 0;
this.TotalProduct = 0;
this.RecipeNo = 0;
this.WeldStartTime = string.Empty;
this.WeldTime = string.Empty;
this.WorkCellId = string.Empty;
this.WorkLotId = string.Empty;
this.LBAD_Judge = string.Empty;
this.LDD_Judge = string.Empty;
this.LaserPowerCore = string.Empty;
this.LaserPowerRing = string.Empty;
this.MarkSpeed = string.Empty;
this.FocalLength = string.Empty;
this.WeldingJigNo = string.Empty;
this.LaserPowerByLBAD = string.Empty;
this.CheckCanExist = false;
this.CheckScannerListEnd = false;
} }
public object Clone() public object Clone()