RCC 패턴 변경 알림(B2506/B2409) 처리 보완

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 쓰기 반환값 로그 추가
This commit is contained in:
김승준 2026-10-28 10:39:46 +09:00
parent c517993e1a
commit a01f9d4cd7

View File

@ -1330,16 +1330,15 @@ namespace ILSOS_KS.Sequences
return null; return null;
} }
StartRccPatternChangeNotice(context);
return SequenceAction.Ok(); return SequenceAction.Ok();
} }
// RCC 패턴이 바뀌었으면 B2506 을 켜고 알림 완료로 기록한다. ACK(B2409) 가 오거나 오토런이 끝나면 끈다. 오토런은 막지 않는다. // RCC 패턴이 바뀌었으면 B2506 을 켜고, PLC ACK(B2409) 를 받았을 때만 알림 완료로 기록한다.
// ACK 없이 오토런이 끝나면 B2506 만 끄고 기록하지 않아서 다음 오토런에서 다시 알린다. 오토런은 막지 않는다.
private void StartRccPatternChangeNotice(SequenceContext context) private void StartRccPatternChangeNotice(SequenceContext context)
{ {
_RccChangeNoticeCts?.Cancel(); _RccChangeNoticeCts?.Cancel();
_PLC.WriteBit((int)eBitOutput.PC_RCC_PATTERN_CHANGED, false); WriteRccPatternChangedBit(false, "AutoRun Start Reset");
if (_SystemParameter.SequenceType != eSequenceType.RCC) if (_SystemParameter.SequenceType != eSequenceType.RCC)
{ {
@ -1361,13 +1360,11 @@ namespace ILSOS_KS.Sequences
if (RccPatternChangeRecord.IsAcknowledged(recipeKey, hash)) if (RccPatternChangeRecord.IsAcknowledged(recipeKey, hash))
{ {
Log.I("[RccPatternChange] No change. PC_RCC_PATTERN_CHANGED(B2506) False"); Log.I($"[RccPatternChange] No change. {GetRccPatternBitState()}");
return; return;
} }
_PLC.WriteBit((int)eBitOutput.PC_RCC_PATTERN_CHANGED, true); WriteRccPatternChangedBit(true, "RCC pattern changed -> Wait PLC ACK");
RccPatternChangeRecord.Acknowledge(recipeKey, hash);
Log.I("[RccPatternChange] RCC pattern changed. SET PC_RCC_PATTERN_CHANGED(B2506) True -> Recorded");
var cts = new CancellationTokenSource(); var cts = new CancellationTokenSource();
_RccChangeNoticeCts = cts; _RccChangeNoticeCts = cts;
@ -1376,16 +1373,37 @@ namespace ILSOS_KS.Sequences
bool acked = false; bool acked = false;
try 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) 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; acked = true;
Log.I("[RccPatternChange] GET PLC_RCC_PATTERN_CHANGED_ACK(B2409) True");
break; break;
} }
Thread.Sleep(100); Thread.Sleep(100);
} }
if (acked)
{
RccPatternChangeRecord.Acknowledge(recipeKey, hash);
Log.I($"[RccPatternChange] PLC ACK received -> Recorded. {GetRccPatternBitState()}");
}
} }
catch (Exception e) catch (Exception e)
{ {
@ -1394,17 +1412,32 @@ namespace ILSOS_KS.Sequences
finally finally
{ {
// 오토런을 다시 시작해 새 감시가 돌고 있으면, 새로 켠 비트를 건드리지 않는다. // 오토런을 다시 시작해 새 감시가 돌고 있으면, 새로 켠 비트를 건드리지 않는다.
if (acked || ReferenceEquals(_RccChangeNoticeCts, cts)) if (ReferenceEquals(_RccChangeNoticeCts, cts))
{ {
_PLC.WriteBit((int)eBitOutput.PC_RCC_PATTERN_CHANGED, false); WriteRccPatternChangedBit(false, acked
Log.I(acked ? "After PLC ACK"
? "[RccPatternChange] SET PC_RCC_PATTERN_CHANGED(B2506) False" : "AutoRun ended without ACK -> Not recorded, notify again next AutoRun");
: "[RccPatternChange] AutoRun ended without ACK. SET PC_RCC_PATTERN_CHANGED(B2506) False");
} }
} }
}); });
} }
// 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) private bool InitSequenceVariable(SequenceContext context)
{ {
_AutoRunStartTime = DateTime.Now; _AutoRunStartTime = DateTime.Now;
@ -1535,6 +1568,9 @@ namespace ILSOS_KS.Sequences
// PLC Interface AutoStatus Start // PLC Interface AutoStatus Start
InitAutoRunBit(); InitAutoRunBit();
// RCC 패턴 변경 알림 : 해시 계산에 시간이 걸리므로 PC_AUTO_STATUS 를 켠 뒤에 한다.
StartRccPatternChangeNotice(context);
// Laser Initialize // Laser Initialize
_Laser.PilotLaserOff(); _Laser.PilotLaserOff();
_Laser.LaserOn(); _Laser.LaserOn();
@ -1630,9 +1666,9 @@ namespace ILSOS_KS.Sequences
Log.I(string.Format($"[IOInterface] Start AutoRun IO Bit Initialize")); Log.I(string.Format($"[IOInterface] Start AutoRun IO Bit Initialize"));
_IO._iOUnit.WriteDoBit(Convert.ToInt32(eADOAddress.PCLBADReadyStatus), false); _IO._iOUnit.WriteDoBit(Convert.ToInt32(eADOAddress.PCLBADReadyStatus), false);
Log.I(string.Format($"[IOInterface]SET 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")); 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")); Log.I(string.Format($"[IOInterface]SET PCLBADWeldingStop False"));
_IO._iOUnit.WriteDoBit(Convert.ToInt32(eADOAddress.PCLBADJudgementCompleteAck), false); _IO._iOUnit.WriteDoBit(Convert.ToInt32(eADOAddress.PCLBADJudgementCompleteAck), false);
Log.I(string.Format($"[IOInterface]SET PCLBADJudgementCompleteAck False")); Log.I(string.Format($"[IOInterface]SET PCLBADJudgementCompleteAck False"));
@ -2351,6 +2387,18 @@ namespace ILSOS_KS.Sequences
return SequenceAction.Ok(); 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) private SequenceActionResult ExecuteWelding(SequenceContext context, string id, SequenceActionResult param)
{ {
Status.SetWorkingPosition(eWorkingPosition.EXECUTING_WELD); Status.SetWorkingPosition(eWorkingPosition.EXECUTING_WELD);
@ -2362,7 +2410,7 @@ namespace ILSOS_KS.Sequences
int recipeNo = _RecipeManager.ActivatedRecipe().Id; 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); //int sendresult = _LBAD.SendCellData(_LotId, _CellId, recipeNo, _ModelNo);
if (_BcrID.Contains("")) if (_BcrID.Contains(""))
@ -2428,11 +2476,11 @@ namespace ILSOS_KS.Sequences
_PLC.WriteBit((int)eBitOutput.PC_WELD_READY, false); _PLC.WriteBit((int)eBitOutput.PC_WELD_READY, false);
Log.I(string.Format($"[PLCInterface]SET 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")); 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")); Log.I(string.Format($"[IOInterface]{_PageNo} setp --> SET PCWeldingStop true"));
return SequenceAction.Ok(); return SequenceAction.Ok();
@ -2477,7 +2525,7 @@ namespace ILSOS_KS.Sequences
//LBAD 결과 받아오는 부분 우선 여기서 추가하여 테스트하고 Sub 시퀀스로 빼자 //LBAD 결과 받아오는 부분 우선 여기서 추가하여 테스트하고 Sub 시퀀스로 빼자
if (_LBAD.IsSimul) 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")); Log.I(string.Format($"[IOInterface]SET PCLBADWeldingStop false, LBAD is Simul"));
} }
else else
@ -3269,7 +3317,7 @@ namespace ILSOS_KS.Sequences
{ {
Log.I(string.Format($"[IOInterface]Get PLC_WELD_REQEUST True")); 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")); Log.I(string.Format($"[IOInterface]LBAD {_PageNoRcc} setp --> SET PCWeldingStop false"));
bool[] Page = new bool[4]; bool[] Page = new bool[4];
@ -3313,7 +3361,7 @@ namespace ILSOS_KS.Sequences
WeldingEnd = true; 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")); Log.I(string.Format($"[IOInterface]LBAD {_PageNoRcc} setp --> SET PCWeldingStop false"));
DateTime startTime = DateTime.Now; DateTime startTime = DateTime.Now;
@ -3680,6 +3728,10 @@ namespace ILSOS_KS.Sequences
private bool RestoreDeviceStatus() private bool RestoreDeviceStatus()
{ {
// RCC 패턴 변경 알림 감시 종료 + B2506 OFF (ACK 전이면 기록하지 않았으므로 다음 오토런에서 다시 알린다)
_RccChangeNoticeCts?.Cancel();
WriteRccPatternChangedBit(false, "AutoRun Stop");
//PLC All BIT OFF //PLC All BIT OFF
_PLC.WriteBit((int)eBitOutput.PC_WELD_REQEUST_ACK, false); _PLC.WriteBit((int)eBitOutput.PC_WELD_REQEUST_ACK, false);
_PLC.WriteBit((int)eBitOutput.PC_WELD_COMPLETE, 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); UpdatePLCMemoryAreaCls((int)eWordOutput.STEP1_Arc1_LowerLimit, (int)eWordOutput.WeldingOK_NG);
//LBAD IO All BIT OFF //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.PCLBADReadyStatus), false);
_IO._iOUnit.WriteDoBit(Convert.ToInt32(eADOAddress.PCLBADWeldingStop), false); WriteLBADDo(eADOAddress.PCLBADWeldingStop, false);
_IO._iOUnit.WriteDoBit(Convert.ToInt32(eADOAddress.PCLBADJudgementCompleteAck), false); _IO._iOUnit.WriteDoBit(Convert.ToInt32(eADOAddress.PCLBADJudgementCompleteAck), false);
Log.I(string.Format("[IOInterface]PC All Bit Off")); Log.I(string.Format("[IOInterface]PC All Bit Off"));
@ -3755,6 +3807,10 @@ namespace ILSOS_KS.Sequences
private void OnSeqActionStop() private void OnSeqActionStop()
{ {
// RCC 패턴 변경 알림 감시 종료 + B2506 OFF (ACK 전이면 기록하지 않았으므로 다음 오토런에서 다시 알린다)
_RccChangeNoticeCts?.Cancel();
WriteRccPatternChangedBit(false, "AutoRun Stop");
//PLC All BIT OFF //PLC All BIT OFF
_PLC.WriteBit((int)eBitOutput.PC_WELD_REQEUST_ACK, false); _PLC.WriteBit((int)eBitOutput.PC_WELD_REQEUST_ACK, false);
_PLC.WriteBit((int)eBitOutput.PC_WELD_COMPLETE, 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); UpdatePLCMemoryAreaCls((int)eWordOutput.STEP1_Arc1_LowerLimit, (int)eWordOutput.WeldingOK_NG);
//LBAD IO All BIT OFF //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.PCLBADReadyStatus), false);
_IO._iOUnit.WriteDoBit(Convert.ToInt32(eADOAddress.PCLBADWeldingStop), false); WriteLBADDo(eADOAddress.PCLBADWeldingStop, false);
_IO._iOUnit.WriteDoBit(Convert.ToInt32(eADOAddress.PCLBADJudgementCompleteAck), false); _IO._iOUnit.WriteDoBit(Convert.ToInt32(eADOAddress.PCLBADJudgementCompleteAck), false);
Log.I(string.Format("[IOInterface]PC All Bit Off")); Log.I(string.Format("[IOInterface]PC All Bit Off"));