From a01f9d4cd7f9fb73eef2908a49cb0120a488c2b9 Mon Sep 17 00:00:00 2001 From: ksj09406 Date: Wed, 28 Oct 2026 10:39:46 +0900 Subject: [PATCH] =?UTF-8?q?RCC=20=ED=8C=A8=ED=84=B4=20=EB=B3=80=EA=B2=BD?= =?UTF-8?q?=20=EC=95=8C=EB=A6=BC(B2506/B2409)=20=EC=B2=98=EB=A6=AC=20?= =?UTF-8?q?=EB=B3=B4=EC=99=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit B2506 : PC → PLC RCC 패턴 변경 알림 (PC_RCC_PATTERN_CHANGED) B2409 : PLC → PC 알림 수신 ACK (PLC_RCC_PATTERN_CHANGED_ACK) - 알림 완료 기록을 B2506 ON 시점이 아닌 ACK(B2409) 수신 시점으로 변경 (ACK 없이 오토런이 끝나면 기록하지 않고 다음 오토런에서 다시 알림) - ACK 는 B2409 OFF→ON 순간만 인정 - 알림 호출을 PC_AUTO_STATUS ON 이후로 이동(InitializeDeviceStatus) - 오토런 정지·종료 시 B2506 직접 OFF - B2506/B2409 상태를 직접 읽어 로그 기록, LBAD Trigger/Stop 쓰기 반환값 로그 추가 --- Machines/ILSOS_KS/Sequences/SeqAutoRunKS.cs | 110 +++++++++++++++----- 1 file changed, 83 insertions(+), 27 deletions(-) diff --git a/Machines/ILSOS_KS/Sequences/SeqAutoRunKS.cs b/Machines/ILSOS_KS/Sequences/SeqAutoRunKS.cs index 9889144..0d62235 100644 --- a/Machines/ILSOS_KS/Sequences/SeqAutoRunKS.cs +++ b/Machines/ILSOS_KS/Sequences/SeqAutoRunKS.cs @@ -1330,16 +1330,15 @@ namespace ILSOS_KS.Sequences return null; } - StartRccPatternChangeNotice(context); - return SequenceAction.Ok(); } - // RCC 패턴이 바뀌었으면 B2506 을 켜고 알림 완료로 기록한다. ACK(B2409) 가 오거나 오토런이 끝나면 끈다. 오토런은 막지 않는다. + // RCC 패턴이 바뀌었으면 B2506 을 켜고, PLC ACK(B2409) 를 받았을 때만 알림 완료로 기록한다. + // ACK 없이 오토런이 끝나면 B2506 만 끄고 기록하지 않아서 다음 오토런에서 다시 알린다. 오토런은 막지 않는다. private void StartRccPatternChangeNotice(SequenceContext context) { _RccChangeNoticeCts?.Cancel(); - _PLC.WriteBit((int)eBitOutput.PC_RCC_PATTERN_CHANGED, false); + WriteRccPatternChangedBit(false, "AutoRun Start Reset"); if (_SystemParameter.SequenceType != eSequenceType.RCC) { @@ -1361,13 +1360,11 @@ namespace ILSOS_KS.Sequences if (RccPatternChangeRecord.IsAcknowledged(recipeKey, hash)) { - Log.I("[RccPatternChange] No change. PC_RCC_PATTERN_CHANGED(B2506) False"); + Log.I($"[RccPatternChange] No change. {GetRccPatternBitState()}"); return; } - _PLC.WriteBit((int)eBitOutput.PC_RCC_PATTERN_CHANGED, true); - RccPatternChangeRecord.Acknowledge(recipeKey, hash); - Log.I("[RccPatternChange] RCC pattern changed. SET PC_RCC_PATTERN_CHANGED(B2506) True -> Recorded"); + WriteRccPatternChangedBit(true, "RCC pattern changed -> Wait PLC ACK"); var cts = new CancellationTokenSource(); _RccChangeNoticeCts = cts; @@ -1376,16 +1373,37 @@ namespace ILSOS_KS.Sequences bool acked = false; try { + // 이전 ACK 가 켜진 채로 남아 있으면 꺼질 때까지 기다린 뒤, 새로 켜지는 순간(OFF -> ON)만 ACK 로 본다. + bool ackArmed = !_PLC.ReadBit((int)eBitInput.PLC_RCC_PATTERN_CHANGED_ACK).data; + if (!ackArmed) + { + Log.I($"[RccPatternChange] PLC ACK is already ON. Wait ACK OFF. {GetRccPatternBitState()}"); + } + while (!cts.IsCancellationRequested && !context.Stopped) { - if (_PLC.ReadBit((int)eBitInput.PLC_RCC_PATTERN_CHANGED_ACK).data) + bool ack = _PLC.ReadBit((int)eBitInput.PLC_RCC_PATTERN_CHANGED_ACK).data; + if (!ackArmed) + { + if (!ack) + { + ackArmed = true; + Log.I($"[RccPatternChange] PLC ACK OFF. Wait new ACK. {GetRccPatternBitState()}"); + } + } + else if (ack) { acked = true; - Log.I("[RccPatternChange] GET PLC_RCC_PATTERN_CHANGED_ACK(B2409) True"); break; } Thread.Sleep(100); } + + if (acked) + { + RccPatternChangeRecord.Acknowledge(recipeKey, hash); + Log.I($"[RccPatternChange] PLC ACK received -> Recorded. {GetRccPatternBitState()}"); + } } catch (Exception e) { @@ -1394,17 +1412,32 @@ namespace ILSOS_KS.Sequences finally { // 오토런을 다시 시작해 새 감시가 돌고 있으면, 새로 켠 비트를 건드리지 않는다. - if (acked || ReferenceEquals(_RccChangeNoticeCts, cts)) + if (ReferenceEquals(_RccChangeNoticeCts, cts)) { - _PLC.WriteBit((int)eBitOutput.PC_RCC_PATTERN_CHANGED, false); - Log.I(acked - ? "[RccPatternChange] SET PC_RCC_PATTERN_CHANGED(B2506) False" - : "[RccPatternChange] AutoRun ended without ACK. SET PC_RCC_PATTERN_CHANGED(B2506) False"); + WriteRccPatternChangedBit(false, acked + ? "After PLC ACK" + : "AutoRun ended without ACK -> Not recorded, notify again next AutoRun"); } } }); } + // B2506 을 쓰고, 쓴 뒤의 B2506 / B2409 상태를 읽어서 로그로 남긴다. + private void WriteRccPatternChangedBit(bool value, string reason) + { + int ret = _PLC.WriteBit((int)eBitOutput.PC_RCC_PATTERN_CHANGED, value); + Log.I($"[RccPatternChange] {reason} : ret={ret}, {GetRccPatternBitState()}"); + } + + // PC_RCC_PATTERN_CHANGED(B2506, PC 출력 블록) 와 PLC_RCC_PATTERN_CHANGED_ACK(B2409, PLC 입력) 를 읽어서 상태 문자열로 만든다. + private string GetRccPatternBitState() + { + var pc = _PLC.ReadBit((int)eBitOutput.PC_RCC_PATTERN_CHANGED, isInput: false); + var ack = _PLC.ReadBit((int)eBitInput.PLC_RCC_PATTERN_CHANGED_ACK); + return $"PC_RCC_PATTERN_CHANGED(B2506)={(pc.err == 0 ? pc.data.ToString() : $"ReadErr{pc.err}")}, " + + $"PLC_RCC_PATTERN_CHANGED_ACK(B2409)={(ack.err == 0 ? ack.data.ToString() : $"ReadErr{ack.err}")}"; + } + private bool InitSequenceVariable(SequenceContext context) { _AutoRunStartTime = DateTime.Now; @@ -1535,6 +1568,9 @@ namespace ILSOS_KS.Sequences // PLC Interface AutoStatus Start InitAutoRunBit(); + // RCC 패턴 변경 알림 : 해시 계산에 시간이 걸리므로 PC_AUTO_STATUS 를 켠 뒤에 한다. + StartRccPatternChangeNotice(context); + // Laser Initialize _Laser.PilotLaserOff(); _Laser.LaserOn(); @@ -1630,9 +1666,9 @@ namespace ILSOS_KS.Sequences Log.I(string.Format($"[IOInterface] Start AutoRun IO Bit Initialize")); _IO._iOUnit.WriteDoBit(Convert.ToInt32(eADOAddress.PCLBADReadyStatus), false); Log.I(string.Format($"[IOInterface]SET PCLBADReadyStatus False")); - _IO._iOUnit.WriteDoBit(Convert.ToInt32(eADOAddress.PCLBADWeldingTrigger), false); + WriteLBADDo(eADOAddress.PCLBADWeldingTrigger, false); Log.I(string.Format($"[IOInterface]SET PCLBADWeldingTrigger False")); - _IO._iOUnit.WriteDoBit(Convert.ToInt32(eADOAddress.PCLBADWeldingStop), false); + WriteLBADDo(eADOAddress.PCLBADWeldingStop, false); Log.I(string.Format($"[IOInterface]SET PCLBADWeldingStop False")); _IO._iOUnit.WriteDoBit(Convert.ToInt32(eADOAddress.PCLBADJudgementCompleteAck), false); Log.I(string.Format($"[IOInterface]SET PCLBADJudgementCompleteAck False")); @@ -2351,6 +2387,18 @@ namespace ILSOS_KS.Sequences return SequenceAction.Ok(); } + // LBAD IO 출력 : 쓰기 반환값(0 = 성공)을 로그로 남기고, 실패하면 에러 로그를 남긴다. + private int WriteLBADDo(eADOAddress address, bool value) + { + int ret = _IO._iOUnit.WriteDoBit(Convert.ToInt32(address), value); + Log.I(string.Format($"[IOInterface] WriteDoBit {address}({Convert.ToInt32(address)}) {value} ret={ret}")); + if (ret != 0) + { + Log.E(string.Format($"[IOInterface] WriteDoBit {address}({Convert.ToInt32(address)}) {value} FAIL ret={ret}")); + } + return ret; + } + private SequenceActionResult ExecuteWelding(SequenceContext context, string id, SequenceActionResult param) { Status.SetWorkingPosition(eWorkingPosition.EXECUTING_WELD); @@ -2362,7 +2410,7 @@ namespace ILSOS_KS.Sequences int recipeNo = _RecipeManager.ActivatedRecipe().Id; - _IO._iOUnit.WriteDoBit(Convert.ToInt32(eADOAddress.PCLBADWeldingTrigger), true); + WriteLBADDo(eADOAddress.PCLBADWeldingTrigger, true); //int sendresult = _LBAD.SendCellData(_LotId, _CellId, recipeNo, _ModelNo); if (_BcrID.Contains("")) @@ -2428,11 +2476,11 @@ namespace ILSOS_KS.Sequences _PLC.WriteBit((int)eBitOutput.PC_WELD_READY, false); Log.I(string.Format($"[PLCInterface]SET PC_WELD_READY False")); - _IO._iOUnit.WriteDoBit(Convert.ToInt32(eADOAddress.PCLBADWeldingTrigger), false); + WriteLBADDo(eADOAddress.PCLBADWeldingTrigger, false); Log.I(string.Format($"[IOInterface]SET PCWeldingTrigger false")); - _IO._iOUnit.WriteDoBit(Convert.ToInt32(eADOAddress.PCLBADWeldingStop), true); + WriteLBADDo(eADOAddress.PCLBADWeldingStop, true); Log.I(string.Format($"[IOInterface]{_PageNo} setp --> SET PCWeldingStop true")); return SequenceAction.Ok(); @@ -2477,7 +2525,7 @@ namespace ILSOS_KS.Sequences //LBAD 결과 받아오는 부분 우선 여기서 추가하여 테스트하고 Sub 시퀀스로 빼자 if (_LBAD.IsSimul) { - _IO._iOUnit.WriteDoBit(Convert.ToInt32(eADOAddress.PCLBADWeldingStop), false); + WriteLBADDo(eADOAddress.PCLBADWeldingStop, false); Log.I(string.Format($"[IOInterface]SET PCLBADWeldingStop false, LBAD is Simul")); } else @@ -3269,7 +3317,7 @@ namespace ILSOS_KS.Sequences { Log.I(string.Format($"[IOInterface]Get PLC_WELD_REQEUST True")); - _IO._iOUnit.WriteDoBit(Convert.ToInt32(eADOAddress.PCLBADWeldingStop), false); + WriteLBADDo(eADOAddress.PCLBADWeldingStop, false); Log.I(string.Format($"[IOInterface]LBAD {_PageNoRcc} setp --> SET PCWeldingStop false")); bool[] Page = new bool[4]; @@ -3313,7 +3361,7 @@ namespace ILSOS_KS.Sequences WeldingEnd = true; - _IO._iOUnit.WriteDoBit(Convert.ToInt32(eADOAddress.PCLBADWeldingStop), false); + WriteLBADDo(eADOAddress.PCLBADWeldingStop, false); Log.I(string.Format($"[IOInterface]LBAD {_PageNoRcc} setp --> SET PCWeldingStop false")); DateTime startTime = DateTime.Now; @@ -3680,6 +3728,10 @@ namespace ILSOS_KS.Sequences private bool RestoreDeviceStatus() { + // RCC 패턴 변경 알림 감시 종료 + B2506 OFF (ACK 전이면 기록하지 않았으므로 다음 오토런에서 다시 알린다) + _RccChangeNoticeCts?.Cancel(); + WriteRccPatternChangedBit(false, "AutoRun Stop"); + //PLC All BIT OFF _PLC.WriteBit((int)eBitOutput.PC_WELD_REQEUST_ACK, false); _PLC.WriteBit((int)eBitOutput.PC_WELD_COMPLETE, false); @@ -3696,9 +3748,9 @@ namespace ILSOS_KS.Sequences UpdatePLCMemoryAreaCls((int)eWordOutput.STEP1_Arc1_LowerLimit, (int)eWordOutput.WeldingOK_NG); //LBAD IO All BIT OFF - _IO._iOUnit.WriteDoBit(Convert.ToInt32(eADOAddress.PCLBADWeldingTrigger), false); + WriteLBADDo(eADOAddress.PCLBADWeldingTrigger, false); _IO._iOUnit.WriteDoBit(Convert.ToInt32(eADOAddress.PCLBADReadyStatus), false); - _IO._iOUnit.WriteDoBit(Convert.ToInt32(eADOAddress.PCLBADWeldingStop), false); + WriteLBADDo(eADOAddress.PCLBADWeldingStop, false); _IO._iOUnit.WriteDoBit(Convert.ToInt32(eADOAddress.PCLBADJudgementCompleteAck), false); Log.I(string.Format("[IOInterface]PC All Bit Off")); @@ -3755,6 +3807,10 @@ namespace ILSOS_KS.Sequences private void OnSeqActionStop() { + // RCC 패턴 변경 알림 감시 종료 + B2506 OFF (ACK 전이면 기록하지 않았으므로 다음 오토런에서 다시 알린다) + _RccChangeNoticeCts?.Cancel(); + WriteRccPatternChangedBit(false, "AutoRun Stop"); + //PLC All BIT OFF _PLC.WriteBit((int)eBitOutput.PC_WELD_REQEUST_ACK, false); _PLC.WriteBit((int)eBitOutput.PC_WELD_COMPLETE, false); @@ -3771,9 +3827,9 @@ namespace ILSOS_KS.Sequences UpdatePLCMemoryAreaCls((int)eWordOutput.STEP1_Arc1_LowerLimit, (int)eWordOutput.WeldingOK_NG); //LBAD IO All BIT OFF - _IO._iOUnit.WriteDoBit(Convert.ToInt32(eADOAddress.PCLBADWeldingTrigger), false); + WriteLBADDo(eADOAddress.PCLBADWeldingTrigger, false); _IO._iOUnit.WriteDoBit(Convert.ToInt32(eADOAddress.PCLBADReadyStatus), false); - _IO._iOUnit.WriteDoBit(Convert.ToInt32(eADOAddress.PCLBADWeldingStop), false); + WriteLBADDo(eADOAddress.PCLBADWeldingStop, false); _IO._iOUnit.WriteDoBit(Convert.ToInt32(eADOAddress.PCLBADJudgementCompleteAck), false); Log.I(string.Format("[IOInterface]PC All Bit Off"));