- 분석_bit15_Resume_핸드셰이크_260805.md - 작업지시서_PTOP_PLC핸드셰이크_260805.md - 분석_HeavyAlarm_비트_동작_260810.md - 작업일지 2026_08_06.md
8.0 KiB
Heavy(중)알람 비트 동작 분석 — 2026-08-10
대상:
PC_HEAVY_ALARM_STATUS(PC→PLC) /PLC_HEAVY_ALARM_STATUS(PLC→PC) 질문: 어떤 경우에 Heavy Alarm 비트가 켜지고 꺼지는가
1. 한 줄 요약
"지금 떠 있는 알람 목록에 Level H가 하나라도 있으면 ON" 을 SeqStatusMonitor 가
매 주기 그대로 PLC에 덮어쓴다. 이벤트로 set/reset 하는 래칭 방식이 아니다.
2. 유일한 쓰기 지점
Machines/ILSOS_PrismaticRD_PTOP/Sequences/Monitoring/SeqStatusMonitor.cs:86-87
_plc.WriteBit(eBitOutput.PC_HEAVY_ALARM_STATUS, AlarmManager.HasAlarmLevelHigh());
_plc.WriteBit(eBitOutput.PC_LIGHT_ALARM_STATUS, AlarmManager.HasAlarmLevelLow());
| 항목 | 내용 |
|---|---|
| 주기 | UpdateStatus 노드마다. 루프는 LoopFirst → UpdateStatus → UpdateUI → UpdateIO 이고 각 노드 NODE_SLEEP = 20ms → 약 60~80ms 주기 (SeqStatusMonitor.cs:32, 74-128) |
| 방식 | 레벨 미러(매번 덮어쓰기). 조건이 사라지면 별도 클리어 없이 자동으로 내려간다 |
| 기동 | EquipmentSetup.cs:106 에서 OnStartUp 때 Start |
| 정지 | EquipmentSetup.cs:116 에서 OnShutDown 때 Stop |
판정 함수 (AlarmManager.cs:172-190)
if (ApplicationExt.IsSimulation) return false; ← 시뮬은 무조건 false
GetCurrentAlarmCodes() 중 IsAlarmLevelHigh(code)==true 가 하나라도 있으면 true
개별 알람마다 비트를 켜는 게 아니라 활성 알람 전체에 대한 OR 집계다.
3. ★ 어떤 알람이 Level H인지는 소스에 없다
IsAlarmLevelHigh()(AlarmManager.cs:194-201)는
_AlarmService.GetAlarmDescription(code).Level 을 본다. 이 Level 은 Aurora AlarmService 가
런타임에 읽는 알람 설명 데이터에서 오며, 저장소에는 그 파일이 없다
(*larm*.{csv,xlsx,xml,json} 검색 0건 — _out_prismatic_rd_ptop/ 이 .gitignore 대상).
"어떤 알람이 중알람이냐"는 코드가 아니라 설정 데이터가 정한다.
확인하려면 현장 PC의 알람 설명 파일 또는 UI Alarm > Description 화면을 봐야 한다.
4. 상황별 ON / OFF 정리
4-1. ON 되는 경우
| # | 상황 | 조건 |
|---|---|---|
| 1 | Level H 알람이 새로 발생 | 리얼 모드 + 활성 알람에 H 1개 이상 → 다음 주기(≈60~80ms)에 ON |
| 2 | PLC가 중알람 비트를 올림 | PLC_HEAVY_ALARM_STATUS ON → SeqAlarmMonitor.cs:199-201 이 210005 발생 → 그 코드가 H면 §1로 이어져 PC 비트도 ON (PLC 중알람 → PC 중알람 미러링) |
| 3 | 알람 리셋 후 원인이 그대로 | 리셋으로 목록이 비어도 감시 루프가 다음 회차에 같은 알람을 다시 올림 → 곧바로 재점등 |
주요 알람 발생원(발생 자체는 H/L 무관):
SeqAlarmMonitor — PLC EMO·Heavy·Light·Door Interlock, Scanner/Laser/LBAD/OCT/Chiller/LeakSensor 상태 ·
PLCController.LiveStatusUpdate — 210002 · 각 시퀀스 내부 알람.
4-2. OFF 되는 경우
| # | 상황 | 조건 |
|---|---|---|
| 1 | 활성 알람에 H가 하나도 없음 | 목록이 비었거나 전부 Level L → 다음 주기에 OFF |
| 2 | 시뮬레이션 모드 | AlarmManager.cs:175-176 — 실제 알람이 떠 있어도 무조건 false |
| 3 | 정상 종료 | OnShutDown(EquipmentSetup.cs:115-118) → SeqStatusMonitor Stop → PLC DoDeactivate 의 AllBitClear()(PLCBase.cs:249-250)가 출력 비트를 전부 0으로 만든다 |
4-3. ⚠ 갱신이 멈춰 마지막 값이 그대로 남는 경우
레벨 미러 방식의 함정이다. 아래 상황에서는 ON/OFF 판정 자체가 일어나지 않는다.
| # | 상황 | 결과 |
|---|---|---|
| 1 | SeqStatusMonitor 정지·미기동 |
비트가 갱신되지 않고 직전 값 유지 |
| 2 | PLC 미연결/미활성 | WriteBit 이 E2.NOT_READY/NOT_CONNECTED 로 조용히 반환(PLCBase.APIs.cs:334-341). PLC측은 마지막 값 유지 |
| 3 | 비정상 종료(강제 종료·크래시) | AllBitClear() 가 돌지 않아 PLC에 ON이 남을 수 있음 |
5. 알람 목록이 비워지는 경로 (= 비트가 내려가는 유일한 방법)
AlarmManager.Alarm() 에는 짝이 되는 ClearAlarm 호출이 없다. 원인이 사라져도 알람은
목록에 남고, 따라서 비트도 계속 ON이다. 반드시 명시적 리셋이 필요하다.
| 경로 | 흐름 |
|---|---|
| PLC 알람 리셋 | PLC_ALARM_RESET(0x1E) 상승엣지 → SeqStatusMonitor.cs:89-92 가 EVENT_RESET_ALL_ALARMS_REQUEST 발행 → AlarmManager.cs:72-77 ClearAllAlarmRequest → _AlarmService.ClearAllAlarm() |
| UI 알람 리셋 | Aurora SYS_ALARM_RESET_ALL_ALARM → AlarmManager.cs:39-41 |
리셋해도 원인이 살아 있으면 소용없다. 감시 루프가 다음 회차에 같은 알람을 다시 올린다(§4-1 #3). 먼저 원인(EMO·Door·디바이스 단선 등)을 해소한 뒤 리셋해야 비트가 실제로 내려간다.
6. 죽어 있는 경로 — 과거 방식의 잔재
AlarmManager.cs 에 같은 취지의 코드가 4곳 전부 주석 처리되어 있다.
| 위치 | 내용 |
|---|---|
:68-69 |
ClearAllAlarm → HeavyAlarmStatusAddr, false |
:75-76 |
ClearAllAlarmRequest → HeavyAlarmStatusAddr, false |
:99-103 |
Alarm() → Level H면 true |
:134-138 |
ChangeAlarmDescription() → Level H면 true |
:94·:129 주석: "PLC의 중알람의 경우 PC에서 Dialog만 발생하고 Alarm 중알람 Word를 써주지 않는다".
알람 발생 시점 직접 쓰기 → 주기 미러 방식으로 갈아탄 흔적이며, 현재 유효한 건 §2 한 곳뿐이다.
7. 주소
| 방향 | 심볼 | 오프셋 | 정의 |
|---|---|---|---|
| PC→PLC | PC_HEAVY_ALARM_STATUS |
0x05 |
PLCController.Address.cs:60 (PTOP) |
| PLC→PC | PLC_HEAVY_ALARM_STATUS |
0x05 |
PLCController.Address.cs:20 (PTOP) |
| PLC→PC | PLC_ALARM_RESET |
0x1E |
PLCController.Address.cs:35 (PTOP) |
[추론] M70015/M70515(bit15) 대응 관계를 따르면 각각 M70005 / M70505, 리셋은 M7051E.
메모리맵 CSV로 확인 필요.
8. ⚠ 발견 — 중알람이 떠도 자동운전 시퀀스가 정지되지 않는다
Level H 알람의 또 다른 소비처가 시퀀스 정지인데 대상 시퀀스가 어긋나 있다.
EquipmentSetup.cs:83-85 OnSetAlarm → isHeavy 면 AlarmManager_PTOP.StopSequenceByAlarm(code)
AlarmManager_PTOP.cs:25-27 Level H 면 StopSequence(SequenceIds.SeqAutoRun) ← 대상
그러나 실제로 도는 자동운전 시퀀스는 SeqAutoRunPTOP 이다.
UCMainAutoRunViewModel.cs:338 //_SeqAutoRun.Start(param, OnCompleteAutoRun); ← 주석
UCMainAutoRunViewModel.cs:342 _SeqAutoRunPTOP.Start(param, OnCompleteAutoRunPTOP); ← 실제 기동
UCMainAutoRunViewModel.cs:428 //_SeqAutoRun.Stop(); ← 주석
StopSequence()(AlarmManager.cs:164-169)는 RunState == Running 일 때만 EmergencyStop() 을
호출한다. SeqAutoRun(Prismatic 빌더)은 등록(EquipmentSetup.cs:211)만 되고 한 번도 기동되지
않으므로 조건에 걸리지 않아 아무 일도 일어나지 않는다.
→ 현재는 중알람 시 PC_HEAVY_ALARM_STATUS 비트는 정상 ON 되지만 PC측 자동운전은 계속 돈다. 설비가 서는 것은 PLC가 그 비트를 보고 세우기 때문일 가능성이 크다.
[추론] SeqAutoRunTDC → SeqAutoRunPTOP 전환(260605) 때 AlarmManager_PTOP 가 함께 갱신되지 않은
잔재로 보인다. EquipmentSetup.cs:262 의 AutoRun 뷰 생성자도 아직 SequenceIds.SeqAutoRunTDC 를
넘긴다(다만 VM이 :100-101 에서 ID로 직접 해석하므로 무해).
확인 필요: PLC가 중알람 시 실제로 설비를 세우는가. 세운다면 이중 안전장치 하나가 죽어 있는 상태이고, 안 세운다면 실제 위험이다.
9. 상태
- 분석만 수행. 소스 미수정.
- §3(알람 Level 데이터) · §8(시퀀스 정지 대상) 두 건은 확인 필요 상태로 남김.