2026-03-30 17:09:29 +09:00

382 lines
15 KiB
C#

using Aurora.Api;
using AuroraChiller;
using AuroraIO;
using AuroraLaser;
using AuroraLaserScanner;
using AuroraLBAD;
using AuroraOCT;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using WeldingCommon.Alarm;
using WeldingCommon.Devices;
using WeldingCommon.Settings;
using static AuroraIO.AJINEXTEK.AjinIO.IOModuleInfo;
using static WeldingCommon.Devices.PLCController;
namespace WeldingCommon.Sequences
{
class AlarmMonitoring
{
static readonly Logger Log = new Logger("AlarmMonitoring");
const string SEQ_START = "SEQ START"; // 딱 한번 Sequence 진입 시에만 실행될 Node
const string SEQ_LoopFirst = "SEQ Loop First";
const string SEQ_WAIT_TIME = "SEQ Wait Time";
//const string SEQ_LoopLast = "SEQ Loop Last";
public const string CHECK_ALARM_PLC = "Check Alarm PLC";
public const string CHECK_ALARM_SCANNER = "Check Alarm Scanner";
public const string CHECK_ALARM_LASER = "Check Alarm Laser";
public const string CHECK_ALARM_LBAD = "Check Alarm LBAD";
public const string CHECK_ALARM_OCT = "Check Alarm OCT";
public const string CHECK_ALARM_CHILLER = "Check Alarm Chiller";
public const string CHECK_ALARM_LEAK_SENSOR = "Check Alarm LeakSensor";
private static SequenceSetting _SequenceSetting;
private static PLCController _Plc;
private static Scanner _Scanner;
private static Laser _Laser;
private static IODevice _IO;
private static SmcChiller _Chiller;
private static OCT _OCT;
private static LBAD _LBAD;
public const int TIMEOUT_PLC_LIVE_CHECK = 2000; // msec
public static SequenceBuilder Builder()
{
SequenceBuilder sb = new SequenceBuilder(1000, true);
sb.AddAction(SEQ_START, StartNode);
sb.AddDecision(SEQ_LoopFirst, LoopFirstNode);
sb.AddAction(SEQ_WAIT_TIME, WaitTime);
sb.AddAction(CHECK_ALARM_PLC, CheckAlarmPLC);
sb.AddAction(CHECK_ALARM_SCANNER, CheckAlarmScanner);
sb.AddAction(CHECK_ALARM_LASER, CheckAlarmLaser);
sb.AddAction(CHECK_ALARM_LBAD, CheckAlarmLBAD);
sb.AddAction(CHECK_ALARM_OCT, CheckAlarmOCT);
sb.AddAction(CHECK_ALARM_CHILLER, CheckAlarmChiller);
sb.AddAction(CHECK_ALARM_LEAK_SENSOR, CheckAlarmLeakSensor);
//sb.AddAction(SEQ_LoopLast, LoopLastNode);
sb.Flows(sb.Init > sb[SEQ_START] > sb[SEQ_LoopFirst] > sb[SEQ_WAIT_TIME]
> sb[CHECK_ALARM_PLC] > sb[CHECK_ALARM_SCANNER]
> sb[CHECK_ALARM_LASER] > sb[CHECK_ALARM_LBAD]
> sb[CHECK_ALARM_OCT] > sb[CHECK_ALARM_CHILLER] > sb[CHECK_ALARM_LEAK_SENSOR]
//> sb[SEQ_LoopLast] > sb[SEQ_LoopFirst]);
> sb[SEQ_LoopFirst]);
sb.Flows(sb[SEQ_LoopFirst] > sb.Final);
sb.OnStopped(OnStopped);
sb.OnForceError(OnForceError);
//sb.Draw("AlarmMonitor.pdf");
return sb;
}
private static SequenceActionResult StartNode(SequenceContext context, string id, SequenceActionResult param)
{
_SequenceSetting = context.GetSetting<SequenceSetting>(CommonSettingIds.Sequence);
InitDev(context);
return SequenceAction.Ok();
}
private static void InitDev(SequenceContext context)
{
if (_SequenceSetting.PlcActivated) {
_Plc = context.GetPLC();
}
if (_SequenceSetting.ScannerActivated) {
_Scanner = context.GetLaserScanner();
}
if (_SequenceSetting.LaserActivated) {
_Laser = context.GetLaser();
}
if (_SequenceSetting.LbadActivated) {
_LBAD = context.GetLBAD();
}
if (_SequenceSetting.OctActivated) {
_OCT = context.GetOCT();
}
if (_SequenceSetting.ChillerActivated) {
_Chiller = context.GetChiller();
}
// Scanner, Laser, LBAD, OCT, Chiller, LeakSensor 는 IO 로도 상태 check 할 수 있음.
if (_SequenceSetting.ScannerActivatedWithIO
|| _SequenceSetting.LaserActivatedWithIO
|| _SequenceSetting.LbadActivatedWithIO
|| _SequenceSetting.OctActivatedWithIO
|| _SequenceSetting.ChillerActivatedWithIO
|| _SequenceSetting.LeakSensorActivatedWithIO) {
_IO = context.GetIOUnit();
}
}
private static string LoopFirstNode(SequenceContext context, string id, ICollection<string> branches, SequenceActionResult param)
{
while (!context.Stopped) {
_SequenceSetting = context.GetSetting<SequenceSetting>(CommonSettingIds.Sequence);
return SEQ_WAIT_TIME;
}
return SeqNodeIds.FINAL;
}
private static SequenceActionResult WaitTime(SequenceContext context, string id, SequenceActionResult param)
{
Thread.Sleep(100); // Delay 가 얼마가 적당 한가
return SequenceAction.Ok();
}
private static SequenceActionResult CheckAlarmPLC(SequenceContext context, string id, SequenceActionResult param)
{
if (_Plc == null || _SequenceSetting.PlcActivated == false) {
return SequenceAction.Ok();
}
if (_Plc.IsSimul) {
return SequenceAction.Ok();
}
if (!_Plc.IsActivated) {
// 임시 주석
//AlarmManager.Alarm(AlarmCode.ALARM_DEVICE_PLC_DEACTIVATED);
} else {
if (_SequenceSetting.PlcActivatedLive) {
//PLC Live Check 시간은 확인 필요
Stopwatch sw = Stopwatch.StartNew();
while (!context.Stopped) {
if (_Plc.ReadBit(eCommonBitInput.PLC_LIVE_STATUS).data == true) {
break;
}
if (sw.ElapsedMilliseconds > TIMEOUT_PLC_LIVE_CHECK) {
AlarmManager.Alarm(AlarmCode.ALARM_DEVICE_PLC_DISCONNECT);
break;
}
Thread.Sleep(10);
}
}
}
return SequenceAction.Ok();
}
private static SequenceActionResult CheckAlarmScanner(SequenceContext context, string id, SequenceActionResult param)
{
if (_Scanner == null || _SequenceSetting.ScannerActivated == false) {
return SequenceAction.Ok();
}
if (_Scanner.IsSimul) {
return SequenceAction.Ok();
}
if (!_Scanner.IsActivated) {
AlarmManager.Alarm(AlarmCode.ALARM_DEVICE_SCANNER_DEACTIVATED);
} else {
var lastErrorcode = _Scanner.GetLastError();
//Scanner의 activate 상태를 체크하면.. 수동상태에서 디바이스를 deactivaed시키면 알람 발생하므로 조건문 변경 필요
if (lastErrorcode != 0) {
AlarmManager.Alarm(AlarmCode.ALARM_DEVICE_SCANNER_ERROR);
Log.E($"Scanner Error Code : {lastErrorcode}");
}
// TODO: Scanner 는 Alarm 과 연결되어 있지 않음. 알람 추가되었을 시에 어떤 IO 를 check 하지??
}
return SequenceAction.Ok();
}
private static SequenceActionResult CheckAlarmLaser(SequenceContext context, string id, SequenceActionResult param)
{
if (_Laser == null || _SequenceSetting.LaserActivated == false) {
return SequenceAction.Ok();
}
if (_Laser.IsSimul) {
return SequenceAction.Ok();
}
if (!_Laser.IsActivated) {
AlarmManager.Alarm(AlarmCode.ALARM_DEVICE_LASER_DEACTIVATED);
} else {
if (!_Laser.GetConnected()) {
AlarmManager.Alarm(AlarmCode.ALARM_DEVICE_IO_LASER_DISCONNECT);
}
if (_SequenceSetting.LaserActivatedWithIO && CheckDeviceIO()) {
//Laser Disconnect Check 조건문 변경 필요
if (!_IO._iOUnit.ReadDiBit(Convert.ToInt32(eADIAddress.LaserAssigned))) {
AlarmManager.Alarm(AlarmCode.ALARM_DEVICE_IO_LASER_DISCONNECT);
}
if (_IO._iOUnit.ReadDiBit(Convert.ToInt32(eADIAddress.LaserError))) {
AlarmManager.Alarm(AlarmCode.ALARM_DEVICE_IO_LASER_ERROR);
}
if (_IO._iOUnit.ReadDiBit(Convert.ToInt32(eADIAddress.Warning))) {
AlarmManager.Alarm(AlarmCode.ALARM_DEVICE_IO_LASER_WARNING);
}
//Laser EMO IO Map 확인 필요
if (!_IO._iOUnit.ReadDiBit(Convert.ToInt32(eADIAddress.LaserEMO_1)) || !_IO._iOUnit.ReadDiBit(Convert.ToInt32(eADIAddress.LaserEMO_2))) {
AlarmManager.Alarm(AlarmCode.ALARM_DEVICE_IO_LASER_EMO);
}
}
}
return SequenceAction.Ok();
}
private static SequenceActionResult CheckAlarmLBAD(SequenceContext context, string id, SequenceActionResult param)
{
if (_LBAD == null || _SequenceSetting.LbadActivated == false) {
return SequenceAction.Ok();
}
if (_LBAD.IsSimul) {
return SequenceAction.Ok();
}
if (!_LBAD.IsActivated) {
AlarmManager.Alarm(AlarmCode.ALARM_DEVICE_LBAD_DEACTIVATED);
} else {
// TODO: ReadyByAuto 는 Auto 돌렸을 때, Sequence 안뜨도록 하는 로직 이라고 함. 이 부분 수정이 필요 할 듯.
// 이게 Sequence 안에서 Try 하면서 계속 붙이는 부분과 관련이 있는 듯함.
if (_LBAD.GetReadybyAuto()) {
if (!_LBAD.GetConnected()) {
AlarmManager.Alarm(AlarmCode.ALARM_DEVICE_LBAD_DISCONNECT);
}
// TODO: 이건 바로 밖의 else 부분으로 빼야 할 지도, Device check 와 IO 로 check 는 다르므로
if (_SequenceSetting.LbadActivatedWithIO && CheckDeviceIO()) {
if (!_IO._iOUnit.ReadDiBit(Convert.ToInt32(eADIAddress.LBADReadyStatus))) {
AlarmManager.Alarm(AlarmCode.ALARM_DEVICE_IO_LBAD_ERROR);
}
}
}
}
return SequenceAction.Ok();
}
private static SequenceActionResult CheckAlarmOCT(SequenceContext context, string id, SequenceActionResult param)
{
if (_OCT == null || _SequenceSetting.OctActivated == false) {
return SequenceAction.Ok();
}
if (_OCT.IsSimul) {
return SequenceAction.Ok();
}
if (!_OCT.IsActivated) {
AlarmManager.Alarm(AlarmCode.ALARM_DEVICE_OCT_DEACTIVATED);
} else {
if (!_OCT.GetConnected()) {
AlarmManager.Alarm(AlarmCode.ALARM_DEVICE_OCT_DISCONNECT);
}
if (_SequenceSetting.OctActivatedWithIO && CheckDeviceIO()) {
if (!_IO._iOUnit.ReadDiBit(Convert.ToInt32(eADIAddress.LDDError))) {
AlarmManager.Alarm(AlarmCode.ALARM_DEVICE_IO_OCT_ERROR);
}
}
}
return SequenceAction.Ok();
}
private static SequenceActionResult CheckAlarmChiller(SequenceContext context, string id, SequenceActionResult param)
{
if (_Chiller == null || _SequenceSetting.ChillerActivated == false) {
return SequenceAction.Ok();
}
if (_Chiller.IsSimul) {
return SequenceAction.Ok();
}
if (!_Chiller.IsActivated) {
AlarmManager.Alarm(AlarmCode.ALARM_DEVICE_CHILLER_DEACTIVATED);
} else {
if (!_Chiller.GetConnected()) {
AlarmManager.Alarm(AlarmCode.ALARM_DEVICE_CHILLER_DISCONNECT);
}
if (_Chiller.GetChillerRunningFlag()) {
AlarmManager.Alarm(AlarmCode.ALARM_DEVICE_CHILLER_ERROR);
}
if (_SequenceSetting.ChillerActivatedWithIO && CheckDeviceIO()) {
// TODO: IO 로 Chiller check 하는 것이 있으면 추가
}
}
return SequenceAction.Ok();
}
private static SequenceActionResult CheckAlarmLeakSensor(SequenceContext context, string id, SequenceActionResult param)
{
if (_SequenceSetting.LeakSensorActivatedWithIO && CheckDeviceIO()) {
//Leak Sensor IO Map 추가 필요
if (_IO._iOUnit.ReadDiBit(Convert.ToInt32(eADIAddress.LeakSensorHead))) {
AlarmManager.Alarm(AlarmCode.ALARM_DEVICE_IO_LEAK_SENSOR_DETECT_SCANNER);
}
if (_IO._iOUnit.ReadDiBit(Convert.ToInt32(eADIAddress.LeakSensorChiller))) {
AlarmManager.Alarm(AlarmCode.ALARM_DEVICE_IO_LEAK_SENSOR_DETECT_CHILLER);
}
}
return SequenceAction.Ok();
}
private static bool CheckDeviceIO()
{
// IO 가 Simul 이면, Read Bit 를 해주지 않기 위해
if (_IO.IsSimul) {
return false;
}
if (_IO == null) {
AlarmManager.Alarm(AlarmCode.ALARM_DEVICE_IO_IS_NULL);
return false;
}
if (_IO.IsActivated == false) {
AlarmManager.Alarm(AlarmCode.ALARM_DEVICE_IO_DEACTIVATED);
return false;
}
// 우선 주석 처리 함. 잦은 호출이 발생할 수 있어서
//if (_IO.IsConnected() == false) {
// AlarmManager.Alarm(AlarmCode.ALARM_DEVICE_IO_DISCONNECT);
//}
return true;
}
//private static SequenceActionResult LoopLastNode(SequenceContext context, string id, SequenceActionResult param)
//{
// //Thread.Sleep(100);
// return SequenceAction.Ok();
//}
private static void OnForceError(SequenceContext arg1, string arg2)
{
}
private static void OnStopped(SequenceContext obj)
{
}
}
}