NohDoyeon241104 dd4f087e95 fix: 페이지 핸드셰이크 ACK 정정 + Auto OFF 시 에코워드 조건부 초기화
- CheckPageNoComp: PC_PAGE_NO 에코값과 현재 PLC_PAGE_NO 비교해
  일치 시 PC_PAGE_CHANGE_COMPLETE=true, 불일치 시 false (기존 무조건 false)
  → 동일 Recipe/Page 반복 시 완료 ACK 전달
- SeqStatusMonitor: PLC/PC Auto State OFF 에지 감시 →
  PC_RECIPE_NO/PC_PAGE_NO 0 초기화. 단 PC Auto OFF는
  M70515(Weld_01 Ready) 살아있으면 보존(Resume 시나리오)
- ExecuteWelding: 완료비트 송신 간 딜레이 5→50ms 여유 확보

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 00:55:27 +09:00

139 lines
5.5 KiB
C#

using Aurora.Api;
using AuroraIO;
using AuroraLaser;
using ILSOS_PrismaticRD_PTOP.Device;
using System.Collections.Generic;
using System.Threading;
using WeldingCommon.Alarm;
using WeldingCommon.Settings;
using WeldingCommon.Utils;
namespace WeldingCommon.Sequences
{
public class SeqStatusMonitor
{
static readonly Logger Log = new Logger("SeqStatusMonitor");
const string SEQ_START = "SEQ START"; // 딱 한번 Sequence 진입 시에만 실행될 Node
const string SEQ_LoopFirst = "SEQ Loop First";
public const string UPDATE_STATUS = "Update Status";
public const string UPDATE_UI = "Update UI";
public const string UPDATE_IO = "Update IO";
private static SequenceSetting _SequenceSetting;
private static Laser _laser;
private static PLCControllerPTOP _plc;
private static IODevice _io;
public const int TIMEOUT_PLC_LIVE_CHECK = 2000; // msec
public const int NODE_SLEEP = 20;
public static SequenceBuilder Builder()
{
SequenceBuilder sb = new SequenceBuilder(1000, true);
sb.AddAction(SEQ_START, StartNode);
sb.AddDecision(SEQ_LoopFirst, LoopFirstNode);
sb.AddAction(UPDATE_STATUS, UpdateStatus);
sb.AddAction(UPDATE_UI, UpdateUI);
sb.AddAction(UPDATE_IO, UpdateIO);
sb.Flows(sb.Init > sb[SEQ_START] > sb[SEQ_LoopFirst]
> sb[UPDATE_STATUS] > sb[UPDATE_UI]
> sb[UPDATE_IO] > sb[SEQ_LoopFirst]);
sb.Flows(sb[SEQ_LoopFirst] > sb.Final);
sb.OnStopped(OnStopped);
sb.OnForceError(OnForceError);
//sb.Draw("SeqAlarmMonitor.pdf");
return sb;
}
private static SequenceActionResult StartNode(SequenceContext context, string id, SequenceActionResult param)
{
_SequenceSetting = context.Settings[CommonSettingIds.Sequence] as SequenceSetting;
if (_plc is null)
_plc = context.Devices[CommonDeviceIds.PLCDevice] as PLCControllerPTOP;
if (_laser is null)
_laser = context.Devices[CommonDeviceIds.Laser] as Laser;
if (_io is null)
_io = context.Devices[CommonDeviceIds.IODevice] as IODevice;
return SequenceAction.Ok();
}
private static string LoopFirstNode(SequenceContext context, string id, ICollection<string> branches, SequenceActionResult param)
{
while (!context.Stopped) {
Thread.Sleep(NODE_SLEEP);
return UPDATE_STATUS;
}
return SeqNodeIds.FINAL;
}
private static SequenceActionResult UpdateStatus(SequenceContext context, string id, SequenceActionResult param)
{
_plc.WriteBit(PLCControllerPTOP.eBitOutput.PC_HEAVY_ALARM_STATUS, AlarmManager.HasAlarmLevelHigh());
_plc.WriteBit(PLCControllerPTOP.eBitOutput.PC_LIGHT_ALARM_STATUS, AlarmManager.HasAlarmLevelLow());
var boolian = _plc.ReadBit(PLCControllerPTOP.eBitInput.PLC_ALARM_RESET).data;
if (ChangeChecker.IsChangedBoolMonitoring("AlarmReset", boolian, true)){
context.EventPublisher.Publish(new EventMessage("SeqStatusMonitor", CommonEventIds.EVENT_RESET_ALL_ALARMS_REQUEST));
}
// ── Auto State OFF 시 에코 워드(PC_RECIPE_NO/PC_PAGE_NO) 0 초기화 ──────────────
// PLC Auto OFF : 무조건 초기화
// PC Auto OFF : M70515(PLC_WELD_READY_REQ, Weld_01 Ready) 살아있으면 보존(초기화 생략)
bool plcAutoOff = ChangeChecker.IsChangedBoolMonitoring("PlcAutoStateOff",
_plc.ReadBit(PLCControllerPTOP.eBitInput.PLC_AUTO_STATUS).data, false);
bool pcAutoOff = ChangeChecker.IsChangedBoolMonitoring("PcAutoStateOff",
_plc.ReadOutBit(PLCControllerPTOP.eBitOutput.PC_AUTO_STATUS).data, false);
bool weldReadyAlive = _plc.ReadBit(PLCControllerPTOP.eBitInput.PLC_WELD_READY_REQ).data; // M70515
if (plcAutoOff || (pcAutoOff && !weldReadyAlive))
{
_plc.WriteWord(PLCControllerPTOP.eWordOutput.PC_RECIPE_NO, 0);
_plc.WriteWord(PLCControllerPTOP.eWordOutput.PC_PAGE_NO, 0);
Log.W($"[StatusMonitor] Auto OFF(PLC:{plcAutoOff}/PC:{pcAutoOff}, M70515:{weldReadyAlive}) → PC_RECIPE_NO/PC_PAGE_NO 0 초기화");
}
Thread.Sleep(NODE_SLEEP);
return SequenceAction.Ok();
}
private static SequenceActionResult UpdateUI(SequenceContext context, string id, SequenceActionResult param)
{
Thread.Sleep(NODE_SLEEP);
return SequenceAction.Ok();
}
private static SequenceActionResult UpdateIO(SequenceContext context, string id, SequenceActionResult param)
{
// 260618: M70509(구 PLC_RMS_USED)를 Recipe 변경 요청(PLC_RECIPE_CHANGE_REQ)으로 재정의.
// RMS 핸들러는 비활성(EquipmentSetup) 상태이고 Status.RMSUse 소비처가 없어 읽기 제거.
//Status.RMSUse = _plc.ReadBit(PLCControllerPTOP.eBitInput.PLC_RMS_USED).data;
Thread.Sleep(NODE_SLEEP);
return SequenceAction.Ok();
}
private static void OnStopped(SequenceContext context)
{
}
private static void OnForceError(SequenceContext context, string arg2)
{
}
}
}