셀 파이프라인 3단계 구조화 및 보고 데이터 소스 명확화
[CellInfoScheduler] - ReportTarget 제거 → Complete 슬롯 추가
- Shift()가 Complete ← Prefetch1 ← Prefetch2 3단계 자동 전진 - Prefetch1 volatile 처리로 EncoderMonitor 스레드 가시성 보장
- HasReport에 IsCanExist·WeldComplete 조건 추가
[SeqAutoRunCCWH52A]
- ReportCellResult: LotId/CellId/JigNo/WeldingSpanTime을
ActiveReportSlot에서 직접 읽도록 변경 (wd 경유 제거)
- ReportCellResult: 레시피·레이저 파라미터를
Prefetch2.InnerCellInfo에서 읽도록 변경
- GetUploadWeldingList_SeqResult: 업로드 성공 후
InnerCellInfo 및 Status 한 번에 갱신 (ReadyScannerList 중복 제거)
- UpdateProductCount/UpdateProductInfoForView 메서드 인라인화
- _TodayProduct/_TotalProduct 멤버변수 제거
- CheckCurrentEncoderAngle → CheckInsideWeldPosition 리네임 및 정리
- EncoderMonitor: JigNo > 0 방어 가드 추가
- _RecipeNo를 InitSequenceVariable에서 한 번만 설정
This commit is contained in:
parent
cb935e251e
commit
45c1de6cc8
@ -21,15 +21,15 @@ namespace ILSOS_CCW_H52A.Data
|
||||
/// 파이프라인 단계 접근을 동시에 지원하는 셀 스케줄러.
|
||||
///
|
||||
/// - 물리 지그 접근: scheduler[eJigNo.Jig5]
|
||||
/// - 파이프라인 접근: scheduler.Prefetch1, scheduler.Prefetch2
|
||||
/// - 파이프라인 접근: scheduler.Prefetch2, scheduler.Prefetch1, scheduler.Complete
|
||||
///
|
||||
/// 3단계 파이프라인: Prefetch2 → Prefetch1 → ReportTarget
|
||||
/// 3단계 파이프라인: Prefetch2 → Prefetch1 → Complete
|
||||
/// Prefetch2 : 셀 정보 수신 완료, 스캐너 리스트 업로드 전
|
||||
/// Prefetch1 : 업로드 완료, 실행 중 — EncoderMonitor 감시 + 완료 체크 대상
|
||||
/// ReportTarget: 완료, 보고 대기
|
||||
/// Complete : 용접 완료, 보고 대기
|
||||
///
|
||||
/// Shift()는 Prefetch2→Prefetch1만 전진. GC 할당 없음.
|
||||
/// Prefetch1 ← Prefetch2 ← this[nextJig]
|
||||
/// Shift()가 3단계 전체를 전진. GC 할당 없음.
|
||||
/// Complete ← Prefetch1 ← Prefetch2 ← this[nextJig]
|
||||
/// </summary>
|
||||
public class CellInfoScheduler : Dictionary<eJigNo, JigInfo>
|
||||
{
|
||||
@ -44,8 +44,7 @@ namespace ILSOS_CCW_H52A.Data
|
||||
private set => _prefetch1 = value;
|
||||
}
|
||||
|
||||
/// 현재 보고 대상 JigInfo (CheckScannerListComplete에서 지정, 보고 완료 후 null)
|
||||
public JigInfo ReportTarget { get; set; }
|
||||
public JigInfo Complete { get; private set; } // 전 셀: 용접 완료, 보고 대기
|
||||
|
||||
// 재시작 보존용 독립 슬롯 — Reset()에서 건드리지 않음
|
||||
// 재시작 시, List를 최초 리스트 2번을 생성하는 로직 때문에.. 필요함
|
||||
@ -60,7 +59,7 @@ namespace ILSOS_CCW_H52A.Data
|
||||
public bool HasPendingComplete => _pendingSlot.IsCanExist && !_pendingSlot.ReportComplete;
|
||||
|
||||
// 현재 활성 보고 슬롯 — 재시작 pending 우선
|
||||
public JigInfo ActiveReportSlot => HasPendingComplete ? _pendingSlot : ReportTarget;
|
||||
public JigInfo ActiveReportSlot => HasPendingComplete ? _pendingSlot : Complete;
|
||||
|
||||
// 정지 전 미용접 슬롯이 보존돼 있는지 (재시작 후 복원 가능 여부)
|
||||
public bool HasPendingPrefetch =>
|
||||
@ -68,7 +67,9 @@ namespace ILSOS_CCW_H52A.Data
|
||||
|| !string.IsNullOrEmpty(_pendingPrefetch2.CellId);
|
||||
|
||||
// 보고가 필요한 상태인지 (정상 + 재시작 모두 포함) >> 용접 완, 보고 미완
|
||||
public bool HasReport => HasPendingComplete || (ReportTarget != null && !ReportTarget.ReportComplete);
|
||||
// Complete는 Shift()마다 갱신되므로 IsCanExist·WeldComplete 조건을 함께 확인한다.
|
||||
public bool HasReport => HasPendingComplete ||
|
||||
(Complete != null && Complete.IsCanExist && Complete.WeldComplete && !Complete.ReportComplete);
|
||||
|
||||
public CellInfoScheduler()
|
||||
{
|
||||
@ -85,11 +86,11 @@ namespace ILSOS_CCW_H52A.Data
|
||||
public void SavePendingComplete()
|
||||
{
|
||||
// 용접 완료됐으나 보고 전 정지된 경우 (_pendingSlot)
|
||||
if (ReportTarget != null
|
||||
&& ReportTarget.IsCanExist
|
||||
&& ReportTarget.WeldComplete
|
||||
&& !ReportTarget.ReportComplete)
|
||||
_pendingSlot.CopyFrom(ReportTarget);
|
||||
if (Complete != null
|
||||
&& Complete.IsCanExist
|
||||
&& Complete.WeldComplete
|
||||
&& !Complete.ReportComplete)
|
||||
_pendingSlot.CopyFrom(Complete);
|
||||
|
||||
// 업로드 완료됐으나 로터리 정지로 용접 자체가 안 된 경우 (_pendingPrefetch1/2)
|
||||
// (연속셀이 들어왔을때, 중간에 멈춘 경우)
|
||||
@ -135,31 +136,33 @@ namespace ILSOS_CCW_H52A.Data
|
||||
return false;
|
||||
}
|
||||
|
||||
// 보고 완료 처리 — ReportTarget 마킹 및 _pendingSlot 클리어.
|
||||
// 보고 완료 처리 — Complete 마킹 및 _pendingSlot 클리어.
|
||||
// GetReportCellResult_SeqResult 성공 시 호출.
|
||||
public void CompleteReport()
|
||||
{
|
||||
_log.I($"Report >> CellId({ReportTarget.CellId}), JigNo({ReportTarget.JigNo})");
|
||||
ReportTarget?.SetReportComplete(true);
|
||||
ReportTarget = null;
|
||||
_pendingSlot.Clear();
|
||||
var reported = ActiveReportSlot;
|
||||
_log.I($"Report >> CellId({reported?.CellId}), JigNo({reported?.JigNo})");
|
||||
Complete?.SetReportComplete(true); // 정상 보고 마킹 (pending 경로면 no-op)
|
||||
_pendingSlot.Clear(); // 재시작 보존 슬롯 항상 클리어
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Prefetch2→Prefetch1 한 칸 전진. GC 할당 없음.
|
||||
/// 3단계 파이프라인 전진. GC 할당 없음.
|
||||
/// Complete ← Prefetch1 ← Prefetch2 ← this[nextJig] (Clear)
|
||||
/// 새 Prefetch2 슬롯은 Clear 후 반환 — 호출자가 셀 정보를 채워야 한다.
|
||||
/// </summary>
|
||||
/// <param name="nextJig">새 Prefetch2로 지정할 물리 지그 (eJigNo)</param>
|
||||
public void Shift(eJigNo nextJig)
|
||||
{
|
||||
Prefetch1 = Prefetch2;
|
||||
Complete = Prefetch1; // Prefetch1 → Complete
|
||||
Prefetch1 = Prefetch2; // Prefetch2 → Prefetch1 (volatile write: release fence)
|
||||
Prefetch2 = base[nextJig];
|
||||
Prefetch2.Clear();
|
||||
}
|
||||
// AutoRun에서 사용되는 자료형으로 추가 (편의 인덱서 사용)
|
||||
public void Shift(int nextJig)
|
||||
{
|
||||
Prefetch1 = Prefetch2;
|
||||
Complete = Prefetch1; // Prefetch1 → Complete
|
||||
Prefetch1 = Prefetch2; // Prefetch2 → Prefetch1 (volatile write: release fence)
|
||||
Prefetch2 = this[nextJig];
|
||||
Prefetch2.Clear();
|
||||
}
|
||||
@ -176,7 +179,7 @@ namespace ILSOS_CCW_H52A.Data
|
||||
|
||||
Prefetch2 = null;
|
||||
Prefetch1 = null;
|
||||
ReportTarget = null;
|
||||
Complete = null;
|
||||
// _pendingSlot, _pendingPrefetch1/2: SavePendingComplete()가 복사해 둔 데이터를 유지
|
||||
}
|
||||
|
||||
|
||||
@ -111,7 +111,6 @@
|
||||
<Compile Include="Sequences\ProcessObjects\ProcessManager.cs" />
|
||||
<Compile Include="Sequences\ProcessObjects\ReceivedCellInfo.cs" />
|
||||
<Compile Include="Sequences\SeqAutoRunCCWH52A.cs" />
|
||||
<Compile Include="Sequences\SeqAutoRunRMOTF.cs" />
|
||||
<Compile Include="Sequences\SequenceContextEx.cs" />
|
||||
<Compile Include="Views\Main\UCMainAutoRun.xaml.cs">
|
||||
<DependentUpon>UCMainAutoRun.xaml</DependentUpon>
|
||||
|
||||
@ -21,10 +21,12 @@ using ILSOS_CCW_H52A.RMS;
|
||||
using ILSOS_CCW_H52A.Sequences.ProcessObjects;
|
||||
using Microsoft.Win32;
|
||||
using OpenCvSharp;
|
||||
using OpenCvSharp.Aruco;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reactive.Subjects;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
using System.Windows;
|
||||
@ -107,6 +109,7 @@ namespace ILSOS_CCW_H52A.Sequences
|
||||
private SystemParameter _SystemParameter;
|
||||
private ScannerCanvasUserCtrl _ScannerCanvasUserCtrl; //스캐너 동작관련 객체 선언
|
||||
|
||||
private int _RecipeNo;
|
||||
private int _ModelNo;
|
||||
|
||||
private IRecipeManager _RecipeManager;
|
||||
@ -117,9 +120,6 @@ namespace ILSOS_CCW_H52A.Sequences
|
||||
|
||||
private SeqAutoRunCCWH52A_InitParam _InitParam;
|
||||
|
||||
private uint _TodayProduct;
|
||||
private uint _TotalProduct;
|
||||
|
||||
private double _LaserPowerByLBAD;
|
||||
|
||||
private bool _ModulationMode;
|
||||
@ -141,7 +141,6 @@ namespace ILSOS_CCW_H52A.Sequences
|
||||
private double _WeldingStartAngle;
|
||||
|
||||
private bool isTheFirstListExecute;
|
||||
private int _RecipeNo;
|
||||
|
||||
private bool UsePlcShotThemAll { get; set; } = false;
|
||||
private bool UsePlcPositionCompensation { get; set; } = false;
|
||||
@ -283,8 +282,6 @@ namespace ILSOS_CCW_H52A.Sequences
|
||||
private bool InitSequenceVariable(SequenceContext context)
|
||||
{
|
||||
_AutoRunStartTime = DateTime.Now;
|
||||
_TodayProduct = _SystemParameter.TodayProductCount;
|
||||
_TotalProduct = _SystemParameter.TotalProductCount;
|
||||
|
||||
var ActivateRecipeName = _RecipeManager.ActivatedRecipe();
|
||||
Log.I($"Current Activate Recipe, ID : {ActivateRecipeName.Id}, Name : {ActivateRecipeName.Name}");
|
||||
@ -294,8 +291,9 @@ namespace ILSOS_CCW_H52A.Sequences
|
||||
|
||||
_WeldingScannerListNo = eListNo.LIST1;
|
||||
|
||||
_RecipeNo = ActivateRecipeName.Id;
|
||||
var currentModelName = context.Recipes.ActivatedModelName();
|
||||
var modelItem = context.GetModel<EquipmentSpecificModel_CCW_H52A>(currentModelName, CommonModelIds.EquipmentSpecificModel);
|
||||
var modelItem = context.Models.ModelItem(currentModelName, CommonModelIds.EquipmentSpecificModel) as EquipmentSpecificModel_CCW_H52A;
|
||||
_ModelNo = modelItem.Model_No;
|
||||
|
||||
return true;
|
||||
@ -445,7 +443,7 @@ namespace ILSOS_CCW_H52A.Sequences
|
||||
|
||||
// JigInfo 풀 스케줄러 초기화 (전전/전/대기/완료 셀 파이프라인)
|
||||
// ── 재시작 전 미완료 보고 보존 ───────────────────────────────────────────────
|
||||
// ReportTarget이 있는 상태로 정지가 들어오면 Reset() 후 슬롯이 Clear()되어 보고 불가.
|
||||
// Complete가 있는 상태로 정지가 들어오면 Reset() 후 슬롯이 Clear()되어 보고 불가.
|
||||
// SavePendingComplete()로 _pendingSlot에 복사한 뒤 Reset()을 호출한다.
|
||||
|
||||
_CellScheduler.SavePendingComplete();
|
||||
@ -563,7 +561,7 @@ namespace ILSOS_CCW_H52A.Sequences
|
||||
Log.I($"[Warmup] ScannerList {_WeldingCount}: pipeline not ready, skip complete check");
|
||||
return SequenceAction.Ok();
|
||||
}
|
||||
if (!CheckCurrentEncoderAngle(jigComplete.StartAngle)) {
|
||||
if (!CheckInsideWeldPosition(jigComplete.StartAngle)) {
|
||||
// IsCanExist=false(공 지그)는 리스트 실행은 하지만 용접이 없으므로
|
||||
// 엔코더 범위를 벗어나도 에러가 아님
|
||||
if (jigComplete.IsCanExist) {
|
||||
@ -583,9 +581,7 @@ namespace ILSOS_CCW_H52A.Sequences
|
||||
TimeSpan weldInterval = jigComplete.WeldEndTime - _prevWeldEndTime;
|
||||
_prevWeldEndTime = jigComplete.WeldEndTime;
|
||||
|
||||
// 보고 대상 슬롯 지정 (스케줄러가 관리)
|
||||
_CellScheduler.ReportTarget = jigComplete;
|
||||
|
||||
// 보고 대상 지정 불필요 — Shift()가 Prefetch1 → Complete로 자동 전진
|
||||
Log.I(string.Format("JigNo : {0}, Weld start : {1}, Weld End : {2}, WeldTime : {3}, interval : {4:F3}",
|
||||
jigComplete.JigNo,
|
||||
jigComplete.WeldStartTime.ToString("HH:mm:ss.fff"),
|
||||
@ -597,8 +593,36 @@ namespace ILSOS_CCW_H52A.Sequences
|
||||
_PLC.WriteBit((int)eBitOutput.PC_WELD_COMPLETE_1 + jigComplete.JigNo - 1, true);
|
||||
Log.I(string.Format($"PC_WELD_COMPLETE_{jigComplete.JigNo} -> true)"));
|
||||
}
|
||||
UpdateProductCount(context);
|
||||
UpdateProductInfoForView();
|
||||
|
||||
if (_SystemParameter.LastResetTime < DateTime.Now.Date) {
|
||||
_SystemParameter.LastResetTime = DateTime.Now.Date;
|
||||
Log.I($"Today Count Reset. {_SystemParameter.TodayProductCount} -> 0");
|
||||
_SystemParameter.TodayProductCount = 0;
|
||||
}
|
||||
|
||||
if (_SystemParameter.TodayProductCount < uint.MaxValue) {
|
||||
_SystemParameter.TodayProductCount++;
|
||||
}
|
||||
if (_SystemParameter.TotalProductCount < uint.MaxValue) {
|
||||
_SystemParameter.TotalProductCount++;
|
||||
}
|
||||
|
||||
Status.GetProcessingWeldingData().TotalProduct = _SystemParameter.TotalProductCount;
|
||||
Status.GetProcessingWeldingData().TodayProduct = _SystemParameter.TodayProductCount;
|
||||
Status.GetProcessingWeldingData().AutoRunStartTime = _AutoRunStartTime;
|
||||
Status.GetProcessingWeldingData().RecipeNo = _RecipeNo;
|
||||
Status.GetProcessingWeldingData().LaserPowerByLBAD = _LaserPowerByLBAD.ToString();
|
||||
|
||||
// 보고 데이터는 스케줄러의 ActiveReportSlot(Complete 또는 PendingComplete)에서 읽음
|
||||
var report = _CellScheduler.ActiveReportSlot;
|
||||
if (report != null) {
|
||||
Status.GetProcessingWeldingData().LotId = report.LotId;
|
||||
Status.GetProcessingWeldingData().CellId = report.CellId;
|
||||
Status.GetProcessingWeldingData().WeldingStartTime = report.WeldStartTime;
|
||||
Status.GetProcessingWeldingData().WeldingEndTime = report.WeldEndTime;
|
||||
Status.GetProcessingWeldingData().WeldingSpanTimeMilliseconds = report.WeldingSpanTime.TotalMilliseconds.ToString();
|
||||
Status.GetProcessingWeldingData().WeldingJigNo = report.JigNo.ToString();
|
||||
}
|
||||
SaveCellAPD();
|
||||
}
|
||||
|
||||
@ -633,25 +657,37 @@ namespace ILSOS_CCW_H52A.Sequences
|
||||
return SequenceAction.Ok();
|
||||
}
|
||||
|
||||
public bool CheckCurrentEncoderAngle(double startAngle)
|
||||
/// <summary>
|
||||
/// startAngle startAngle+45
|
||||
/// │←── OK 구간 ────►│
|
||||
/// ────┼─────────────────┼──────────────► 로터리 각도
|
||||
/// 리스트 여기까지
|
||||
/// 시작 와야 완료 체크 가능
|
||||
/// 판정 로직:
|
||||
/// currentAngle < startAngle → Too early (아직 리스트 실행 중, 완료 체크 너무 이름)
|
||||
/// startAngle ≤ current < start+45 → OK (정상 완료 구간)
|
||||
/// currentAngle ≥ startAngle + 45 → Too late (너무 늦음, 타임오버 에러)
|
||||
/// </summary>
|
||||
/// <param name="startAngle"> 현재 지그의 시작 각도 </param>
|
||||
/// <returns> 지나갔으면 True </returns>
|
||||
public bool CheckInsideWeldPosition(double startAngle)
|
||||
{
|
||||
double encoderX, currentAngle;
|
||||
|
||||
_Scanner.GetEncoder(out encoderX, out currentAngle, true);
|
||||
|
||||
if (0 < startAngle && currentAngle < 0) {
|
||||
// Encoder 반전되는 순간이며, 이 때만 인터락 무시
|
||||
}
|
||||
else if (startAngle <= currentAngle) {
|
||||
// 다음 리스트 구간이 끝나기 전까지는 완료가 되어야 한다
|
||||
if (currentAngle < startAngle + 45) {
|
||||
if (0 < startAngle && currentAngle < 0)
|
||||
return false;
|
||||
|
||||
if (startAngle <= currentAngle && currentAngle < startAngle + 45) {
|
||||
Log.I(string.Format("Current encoder check OK, startAngle : {0}, currentAngle : {1})", startAngle, currentAngle));
|
||||
return true;
|
||||
} else
|
||||
Log.W(string.Format("Current encoder check NG(Too late), startAngle : {0}, currentAngle : {1})", startAngle, currentAngle));
|
||||
}
|
||||
else
|
||||
|
||||
if (currentAngle < startAngle)
|
||||
Log.W(string.Format("Current encoder check NG(Too early), startAngle : {0}, currentAngle : {1})", startAngle, currentAngle));
|
||||
else
|
||||
Log.W(string.Format("Current encoder check NG(Too late), startAngle : {0}, currentAngle : {1})", startAngle, currentAngle));
|
||||
|
||||
return false;
|
||||
}
|
||||
@ -717,12 +753,11 @@ namespace ILSOS_CCW_H52A.Sequences
|
||||
#warning OC2 ACW 기준 >> Cell Tracker는 어느 시점에 데이터는 주는지 모르겠지만, '전전전 셀' 쯤에서 이미 건네받음! 다른 프로젝트에서 확인 필요함
|
||||
// 복원 우선: 정지 전 업로드됐으나 로터리 감속·정지로 용접 미완된 셀 정보 복원.
|
||||
// canExist=false 지그도 TryRestoreCell을 호출하여 슬롯 소비(폐기) — 이후 오염 방지.
|
||||
(string LotId, string CellId) recvInfo = (string.Empty, string.Empty);
|
||||
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;
|
||||
recvInfo.LotId = rLot;
|
||||
recvInfo.CellId = rCell;
|
||||
Log.I($"[PendingRestore] Jig{_WeldingJigNo} 셀 복원 >> CellId({rCell})");
|
||||
}
|
||||
else {
|
||||
@ -730,25 +765,26 @@ namespace ILSOS_CCW_H52A.Sequences
|
||||
}
|
||||
}
|
||||
else if (canExist && 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;
|
||||
recvInfo.LotId = cell.LotId;
|
||||
recvInfo.CellId = cell.CellId;
|
||||
} else {
|
||||
_CellTracker.getDummyData(out string lotId, out string cellId);
|
||||
_CellScheduler.Prefetch2.LotId = lotId;
|
||||
_CellScheduler.Prefetch2.CellId = cellId;
|
||||
Status.GetProcessingWeldingData().WorkLotId = lotId;
|
||||
Status.GetProcessingWeldingData().WorkCellId = cellId;
|
||||
recvInfo.LotId = lotId;
|
||||
recvInfo.CellId = cellId;
|
||||
}
|
||||
|
||||
_CellScheduler.Prefetch2.LotId = recvInfo.LotId;
|
||||
_CellScheduler.Prefetch2.CellId = recvInfo.CellId;
|
||||
Status.GetProcessingWeldingData().WorkLotId = recvInfo.LotId;
|
||||
Status.GetProcessingWeldingData().WorkCellId = recvInfo.CellId;
|
||||
|
||||
if (_CellScheduler.Prefetch2 != null)
|
||||
Log.I($"상태 시프트(Rotate) >> 용접 전전셀({_CellScheduler.Prefetch2.CellId}) [CanExist({_CellScheduler.Prefetch2.IsCanExist})] [JigNo({_CellScheduler.Prefetch2.JigNo})] " +
|
||||
Log.I($"Prefetch2 >> CellId({_CellScheduler.Prefetch2.CellId}) [CanExist({_CellScheduler.Prefetch2.IsCanExist})] [JigNo({_CellScheduler.Prefetch2.JigNo})] " +
|
||||
$"[ListNo({_CellScheduler.Prefetch2.ListNo})] [WeldingCount({_CellScheduler.Prefetch2.WeldingCount})]" +
|
||||
$"[StartAngle(Y)({_CellScheduler.Prefetch2.StartAngle})]");
|
||||
|
||||
if(_CellScheduler.Prefetch1 != null)
|
||||
Log.I($"이번 용접대상 >> 용접 전셀({_CellScheduler.Prefetch1.CellId}) [CanExist({_CellScheduler.Prefetch1.IsCanExist})] [JigNo({_CellScheduler.Prefetch1.JigNo})] " +
|
||||
Log.I($"Prefetch1 >> CellId({_CellScheduler.Prefetch1.CellId}) [CanExist({_CellScheduler.Prefetch1.IsCanExist})] [JigNo({_CellScheduler.Prefetch1.JigNo})] " +
|
||||
$"[ListNo({_CellScheduler.Prefetch1.ListNo})] [WeldingCount({_CellScheduler.Prefetch1.WeldingCount})]" +
|
||||
$"[StartAngle(Y)({_CellScheduler.Prefetch1.StartAngle})]");
|
||||
|
||||
@ -764,9 +800,6 @@ namespace ILSOS_CCW_H52A.Sequences
|
||||
}
|
||||
#endregion
|
||||
|
||||
_RecipeNo = _RecipeManager.ActivatedRecipe().Id;
|
||||
|
||||
SetWeldingData();
|
||||
return SEQ_SET_PARAMS_UPLOAD_WELDING_LIST_SEQ;
|
||||
}
|
||||
else {
|
||||
@ -786,20 +819,6 @@ namespace ILSOS_CCW_H52A.Sequences
|
||||
|
||||
return null;
|
||||
}
|
||||
private void SetWeldingData()
|
||||
{
|
||||
ScannerParam laserParam = null;
|
||||
laserParam = GetSelectedDrawObjectData(_SelectedDrawObjectList[0]);
|
||||
|
||||
if (laserParam != null) {
|
||||
// EDC 보내는 용도
|
||||
Status.GetProcessingWeldingData().LaserPowerCore = laserParam.LaserPower1.ToString();
|
||||
Status.GetProcessingWeldingData().LaserPowerRing = laserParam.LaserPower2.ToString();
|
||||
Status.GetProcessingWeldingData().MarkSpeed = laserParam.MarkSpeed.ToString();
|
||||
Status.GetProcessingWeldingData().FocalLength = (_PLC.ReadDWord((int)eWordInput.PLC_WELDING_FOCAL_LENGTH).data / 1000f).ToString();
|
||||
Status.GetProcessingWeldingData().WeldingJigNo = _WeldingJigNo.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
public void WaitForEncoderNextRotarySection(int weldingCount, int rotaryJigCount, double rotaryAngleOffset, double encoderResetOffset, out double sectionStartAngle)
|
||||
{
|
||||
@ -833,28 +852,7 @@ namespace ILSOS_CCW_H52A.Sequences
|
||||
|
||||
public bool GetRotaryCanExist(int jigNo)
|
||||
{
|
||||
#region 지그 16개 요청기록 로그 남기기, 빠져나간 캔에 대한 Complete Bit 초기화
|
||||
//string result = "";
|
||||
|
||||
//for (int i = 1; i <= _RotaryJigCount; i++) {
|
||||
// if (_PLC.ReadBit((int)eBitInput.PLC_USE_WELD_JIG_1 + i).data)
|
||||
// result += "1, ";
|
||||
// else {
|
||||
// result += "0, ";
|
||||
|
||||
// string outId = string.Format("PC_WELD_COMPLETE_{0}", i);
|
||||
|
||||
// if (_PLC.ReadBit((int)eBitInput.PLC_USE_WELD_JIG_1 + i).data) {
|
||||
// _PLC.WriteBit((int)eBitOutput.PC_WELD_COMPLETE_1 + i, false);
|
||||
// Log.I(string.Format($"PC_WELD_COMPLETE_{1 + i} -> FALSE)"));
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
//UtilUnit.logUnit.SetLog(LogUnit.eLogType.DEBUG, MethodBase.GetCurrentMethod().Name, string.Format("PLC -> PC 용접 Cmd : ({0})", result));
|
||||
#endregion
|
||||
|
||||
if (jigNo <= _RotaryJigCount)
|
||||
//return m_rscPlc.GetDIStatus(string.Format("PLC_USE_WELD_JIG_{0}", jigNo));
|
||||
return _PLC.ReadBit((int)eBitInput.PLC_USE_WELD_JIG_1 + (jigNo - 1)).data;
|
||||
else
|
||||
return false;
|
||||
@ -884,14 +882,22 @@ namespace ILSOS_CCW_H52A.Sequences
|
||||
return SequenceAction.ForceStopByAlarm(AlarmCode.ALARM_SEQUENCE_UploadWeldingList_ResultFailed);
|
||||
//return null;
|
||||
}
|
||||
// 입력한 Scanner List를 완료대기열에 추가
|
||||
// Won : GetProcessingWeldingData().WorkLotId 는 CellTrakcer로 부터 받은 상태의 LotId
|
||||
// GetProcessingWeldingData().LotId 는 AutorunView에 표기할 용접이 완료 된 LotID
|
||||
string LotId = Status.GetProcessingWeldingData().WorkLotId; // CellTracker로 부터 WorkLotID, WorkCellID 받는 구문 추가 후 해당 데이터로 입력 필요
|
||||
string CellId = Status.GetProcessingWeldingData().WorkCellId;
|
||||
ScannerParam laserParam = null;
|
||||
laserParam = GetSelectedDrawObjectData(_SelectedDrawObjectList[0]);
|
||||
|
||||
_CellScheduler.Prefetch2.LotId = LotId;
|
||||
_CellScheduler.Prefetch2.CellId = CellId;
|
||||
_CellScheduler.Prefetch2.InnerCellInfo.RecipeNo = _RecipeNo;
|
||||
_CellScheduler.Prefetch2.InnerCellInfo.LaserPowerCore = laserParam.LaserPower1.ToString();
|
||||
_CellScheduler.Prefetch2.InnerCellInfo.LaserPowerRing = laserParam.LaserPower2.ToString();
|
||||
_CellScheduler.Prefetch2.InnerCellInfo.MarkSpeed = laserParam.MarkSpeed.ToString();
|
||||
_CellScheduler.Prefetch2.InnerCellInfo.FocalLength = (_PLC.ReadDWord((int)eWordInput.PLC_WELDING_FOCAL_LENGTH).data / 1000f).ToString();
|
||||
_CellScheduler.Prefetch2.InnerCellInfo.WeldingJigNo = _WeldingJigNo.ToString();
|
||||
|
||||
// 업로드 성공 확인 후 뷰/EDC용 Status 갱신 (ReadyScannerList에서 중복 갱신 제거)
|
||||
Status.GetProcessingWeldingData().LaserPowerCore = laserParam.LaserPower1.ToString();
|
||||
Status.GetProcessingWeldingData().LaserPowerRing = laserParam.LaserPower2.ToString();
|
||||
Status.GetProcessingWeldingData().MarkSpeed = laserParam.MarkSpeed.ToString();
|
||||
Status.GetProcessingWeldingData().FocalLength = _CellScheduler.Prefetch2.InnerCellInfo.FocalLength;
|
||||
Status.GetProcessingWeldingData().WeldingJigNo = _WeldingJigNo.ToString();
|
||||
Log.FuncI("CellTracker Load");
|
||||
return SequenceAction.Ok();
|
||||
}
|
||||
@ -948,7 +954,6 @@ namespace ILSOS_CCW_H52A.Sequences
|
||||
private SequenceActionResult EncoderMonitor(SequenceContext context, string id, SequenceActionResult param)
|
||||
{
|
||||
double send_time_offset = 0.1;
|
||||
string LotID = "", CellID = "";
|
||||
|
||||
while (!context.Stopped) {
|
||||
double encoderX, currentAngle;
|
||||
@ -968,15 +973,13 @@ namespace ILSOS_CCW_H52A.Sequences
|
||||
Log.I($"Fork Before Min Rotate Encoder X : ({encoderX}), Encoder Y : ({currentAngle}), PLC Rotary : ({CurrentPosPLC}), List {executeTarget.ListNo}, JigNo : ({executeTarget.JigNo})");
|
||||
if (!_SystemParameter.BypassModeLBAD) {
|
||||
if (!executeTarget.CheckSendCellinfo) {
|
||||
LotID = executeTarget.LotId;
|
||||
CellID = executeTarget.CellId;
|
||||
if (currentAngle > executeTarget.StartAngle) {
|
||||
executeTarget.CheckSendCellinfo = _StreamLightLBAD.SendCellInfo(LotID, CellID, _RecipeNo, _ModelNo, executeTarget.JigNo);
|
||||
executeTarget.CheckSendCellinfo = _StreamLightLBAD.SendCellInfo(executeTarget.LotId, executeTarget.CellId, _RecipeNo, _ModelNo, executeTarget.JigNo);
|
||||
|
||||
if (!executeTarget.CheckSendCellinfo)
|
||||
Log.I($"[LBAD Interface]SendCellInfo null, LotID [{LotID}], CellID [{CellID}], JigNo [{executeTarget.JigNo}]");
|
||||
Log.I($"[LBAD Interface]SendCellInfo null, LotID [{executeTarget.LotId}], CellID [{executeTarget.CellId}], JigNo [{executeTarget.JigNo}]");
|
||||
else
|
||||
Log.I($"[StreamLight]SendCellInfo LotID [{LotID}], CellID [{CellID}], JigNo [{executeTarget.JigNo}]");
|
||||
Log.I($"[StreamLight]SendCellInfo LotID [{executeTarget.LotId}], CellID [{executeTarget.CellId}], JigNo [{executeTarget.JigNo}]");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1015,46 +1018,6 @@ namespace ILSOS_CCW_H52A.Sequences
|
||||
return SequenceAction.Ok();
|
||||
}
|
||||
|
||||
private void UpdateProductCount(SequenceContext context)
|
||||
{
|
||||
if (_SystemParameter.LastResetTime < DateTime.Now.Date) {
|
||||
_SystemParameter.LastResetTime = DateTime.Now.Date;
|
||||
Log.I($"Today Count Reset. {_SystemParameter.TodayProductCount} -> 0");
|
||||
_SystemParameter.TodayProductCount = 0;
|
||||
}
|
||||
|
||||
_TodayProduct = _SystemParameter.TodayProductCount;
|
||||
_TotalProduct = _SystemParameter.TotalProductCount;
|
||||
if (_TodayProduct < uint.MaxValue) {
|
||||
_TodayProduct++;
|
||||
}
|
||||
if (_TotalProduct < uint.MaxValue) {
|
||||
_TotalProduct++;
|
||||
}
|
||||
_SystemParameter.TodayProductCount = _TodayProduct;
|
||||
_SystemParameter.TotalProductCount = _TotalProduct;
|
||||
}
|
||||
|
||||
private void UpdateProductInfoForView()
|
||||
{
|
||||
Status.GetProcessingWeldingData().TotalProduct = _TotalProduct;
|
||||
Status.GetProcessingWeldingData().TodayProduct = _TodayProduct;
|
||||
Status.GetProcessingWeldingData().AutoRunStartTime = _AutoRunStartTime;
|
||||
Status.GetProcessingWeldingData().RecipeNo = _RecipeNo;
|
||||
Status.GetProcessingWeldingData().LaserPowerByLBAD = _LaserPowerByLBAD.ToString();
|
||||
|
||||
// 보고 데이터는 스케줄러의 ActiveReportSlot(ReportTarget 또는 PendingComplete)에서 읽음
|
||||
var report = _CellScheduler.ActiveReportSlot;
|
||||
if (report != null) {
|
||||
Status.GetProcessingWeldingData().LotId = report.LotId;
|
||||
Status.GetProcessingWeldingData().CellId = report.CellId;
|
||||
Status.GetProcessingWeldingData().WeldingStartTime = report.WeldStartTime;
|
||||
Status.GetProcessingWeldingData().WeldingEndTime = report.WeldEndTime;
|
||||
Status.GetProcessingWeldingData().WeldingSpanTimeMilliseconds = report.WeldingSpanTime.TotalMilliseconds.ToString();
|
||||
Status.GetProcessingWeldingData().WeldingJigNo = report.JigNo.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
private SequenceActionResult ReportCellResult(SequenceContext context, string id, SequenceActionResult param)
|
||||
{
|
||||
Status.SetWorkingPosition(eWorkingPosition.REPORTING_RESULT);
|
||||
@ -1062,7 +1025,11 @@ namespace ILSOS_CCW_H52A.Sequences
|
||||
string strDate = DateTime.Now.Date.ToString("yyyyMMdd");
|
||||
string strTime = DateTime.Now.ToString("HHmmss");
|
||||
|
||||
// 셀 식별 정보는 스케줄러 슬롯에서 직접 읽음 (Complete 또는 pendingSlot)
|
||||
var report = _CellScheduler.ActiveReportSlot;
|
||||
// 레시피·장비 계측값은 Status에서 읽음 (TodayProduct/TotalProduct 포함)
|
||||
var wd = Status.GetProcessingWeldingData();
|
||||
|
||||
string reportDataLocalPath = _CellTracker._CellTrackerConfig.reportDataLocalPath;
|
||||
string equipName = _CellTracker._CellTrackerConfig.EquipmentName;
|
||||
|
||||
@ -1085,23 +1052,23 @@ namespace ILSOS_CCW_H52A.Sequences
|
||||
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,
|
||||
strDate, strTime, report.LotId, report.CellId,
|
||||
report.InnerCellInfo.RecipeNo, report.InnerCellInfo.LaserPowerCore, report.InnerCellInfo.MarkSpeed, report.InnerCellInfo.FocalLength,
|
||||
report.JigNo, report.WeldingSpanTime.TotalMilliseconds.ToString(), wd.LaserPowerByLBAD,
|
||||
wd.TodayProduct, wd.TotalProduct);
|
||||
_CellTracker.SendEcsData(wd.CellId, strPath, strData + "");
|
||||
Log.I($"Report to CellTracker >> [LotID({wd.LotId.Replace("\0", "").Trim()})] [CellID({wd.CellId.Replace("\0", "").Trim()})]");
|
||||
_CellTracker.SendEcsData(report.CellId, strPath, strData + "");
|
||||
Log.I($"Report to CellTracker >> [LotID({report.LotId})] [CellID({report.CellId})]");
|
||||
|
||||
// 로컬 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,
|
||||
strDate, strTime, report.LotId, report.CellId,
|
||||
report.InnerCellInfo.RecipeNo, report.InnerCellInfo.LaserPowerCore, report.InnerCellInfo.MarkSpeed, report.InnerCellInfo.FocalLength,
|
||||
report.JigNo, report.WeldingSpanTime.TotalMilliseconds.ToString(), wd.LaserPowerByLBAD,
|
||||
wd.TodayProduct, wd.TotalProduct);
|
||||
WeldingCommon.Utils.ExcelManagementUnit.AppendStringInCSV(strPath, strItem, strCsvData);
|
||||
|
||||
// 보고 완료: ReportTarget.ReportComplete=true 설정 + pendingSlot 클리어
|
||||
// 보고 완료: Complete.ReportComplete=true 설정 + pendingSlot 클리어
|
||||
_CellScheduler.CompleteReport();
|
||||
|
||||
return SequenceAction.Ok();
|
||||
@ -1151,7 +1118,7 @@ namespace ILSOS_CCW_H52A.Sequences
|
||||
private string CheckCanWelded(SequenceContext context, string id, ICollection<string> branches, SequenceActionResult param)
|
||||
{
|
||||
// ── 재시작 전 미완료 보고 우선 처리 ─────────────────────────────────────────
|
||||
// SavePendingComplete()로 보존된 슬롯이 있으면 정상 파이프라인(ReportTarget)보다 우선.
|
||||
// SavePendingComplete()로 보존된 슬롯이 있으면 정상 파이프라인(Complete)보다 우선.
|
||||
if (_CellScheduler.HasPendingComplete) {
|
||||
var p = _CellScheduler.PendingComplete;
|
||||
Log.I($"[PendingReport] 재시작 전 미완료 보고: LotId={p.LotId}, CellId={p.CellId}, JigNo={p.JigNo}");
|
||||
@ -1160,8 +1127,8 @@ namespace ILSOS_CCW_H52A.Sequences
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
// 정상 보고 경로:
|
||||
// - ReportTarget이 설정돼 있고 아직 보고 완료되지 않은 경우
|
||||
// - 첫번째, 두번째 반복은 SetReportTarget이 호출되지 않으므로 자연스럽게 통과
|
||||
// - Complete(Shift로 자동 승격)에 용접 완료된 셀이 있고 아직 보고 미완인 경우
|
||||
// - 예열 구간(Complete=null 또는 WeldComplete=false)은 자연스럽게 통과
|
||||
if (_CellScheduler.HasReport)
|
||||
return SEQ_REPORT_CELL_RESULT;
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user