# 작업일지 — 2026-08-10 ## 1. PLC 기동 오알람 210002 — 원인 확정 및 해결 ### 증상 프로그램 첫 기동 시 PLC 연결이 열리기도 전에 `ALARM_DEVICE_PLC_DISCONNECT`(210002) 발생. 연결은 곧 붙지만 알람은 남는다(자동 해제 없음). 시뮬 모드에서는 무발생. ### 210002를 올리는 경로가 2개였음 | | 위치 | 판정 | 임계 | 상태 | |---|---|---|---|---| | A | `PLCController.Config.cs:146` (디바이스, 100ms 타이머) | **엣지** — 비트가 바뀌어야 정상 | 10000ms | 활성 | | B | `SeqAlarmMonitor.cs:182` (시퀀스) | **레벨** — 2초 안에 true면 정상 | 2000ms | 활성 | | — | `AlarmMonitoring.cs:169` (공통 시퀀스) | — | — | **죽은 코드** | - `AlarmCode_PTOP : AlarmCode`(`AlarmCode_PTOP.cs:10`) 상속이고 210002는 재정의 없음 → **A와 B가 같은 코드**를 써서 화면만 봐서는 구분 불가. - `AlarmMonitoring.Builder()` 호출처는 `SequenceManager.cs:83` 주석 한 줄뿐(등록 0건). 주석을 풀어도 동작하지 않는다. ### 근본 원인 `PLCController.Config.cs` - `DateTime Livetimer`(`:33`)가 초기화되지 않아 `DateTime.MinValue`. 대입 지점은 토글 감지 시(`:138`) 한 곳뿐이라, 기동 직후에는 값이 들어가지 않는다. → `(Now - MinValue)`가 항상 10000ms를 초과 → 워치독 오판. **임계값 10000을 20000으로 키우는 방식은 원리적으로 무효**(MinValue 앞에서는 어떤 값이든 초과). - `_monitorPlcInterfaceMap.Start()`(`:185`)가 `base.DoActivate()`(`:187`)보다 **앞**에 있어 연결 확립 전에 타이머가 돌았다. `beforeLiveStatus` 리셋(`:195`)도 그보다 뒤. ### 진단 계측 (적용 → 결과 확보 → 원복 완료) A/B 중 어느 쪽인지 확정하기 위해 두 곳에 임시 로그를 넣고 재기동. 현장 로그: ``` 16:12:25.903 MicroTimer: timer interval: 100 [ms] 16:12:25.904 E PLCController: [210002][A:PLCController.LiveStatusUpdate] Livetimer=0001-01-01 00:00:00.000, elapsed=63921975145904ms, isLive=False, beforeLiveStatus=False, IsActivated=False, IsConnected=False ``` - `Livetimer=0001-01-01` → 미초기화 확정. - `IsActivated=False, IsConnected=False` → **연결 확립 전 발생 확정.** 사전에 `[추론]`으로 달아 뒀던 "Aurora가 `IsActivated`를 `DoActivate` 반환 뒤에 세팅한다"도 함께 검증됨. - `[B:...]` 로그 미출현 → **A 단독**. 시퀀스 계층은 이번 건과 무관. - 타이머 기동(`.903`)과 알람(`.904`) 간격이 1ms → `MicroTimer` 첫 콜백이 주기(100ms) 뒤가 아니라 `Start()` 직후에 발생. 경합이 아니라 **100% 재현되는 결정적 버그**였다. 계측 코드는 결과 확보 후 전량 원복(`.cs` 잔존 0건 확인). > 로그 파일에서 한글이 깨진다(`[진단210002]` → `[ 210002]`, `위치:` → `ġ:`). > 검색어는 `210002][` 를 쓸 것. ### 수정 (최소 수정) `WeldingComponents/WeldingCommon/Devices/PLC/PLCController.Config.cs` 의 `DoActivate()` **1개 메서드만** 변경. `SeqAlarmMonitor.cs` 등 다른 파일 미변경. - `_monitorPlcInterfaceMap.Start()` 를 `base.DoActivate()` 성공 이후로 이동 - `Livetimer = DateTime.Now` 로 기준시각 확보 후 타이머 기동 - **두 조치는 각각 단독으로는 무효** — 타이머만 옮기면 `Livetimer`가 여전히 `MinValue`, 초기화만 하면 타이머가 그 앞에서 이미 발화. 반드시 함께 적용해야 한다. - 수정 전/후를 `#region` 2개로 기록해 원복 가능하게 함 (검색어: `260810 기동 오알람`) 부수 효과: `Activate` 실패 시 타이머가 계속 돌던 문제 해소. [추론] `LoadMemoryMapFromFiles()` 중 타이머가 같은 맵을 읽던 겹침도 함께 사라진다. ### 검증 **현장 재기동 확인 — 기동 시 210002 미발생. 해결 완료.** ### 잔여 과제 (별건) - `Livetimer` 가 에코 1초 타이머(`:130`)와 워치독 10초 기준시각(`:144`)을 겸용하는 구조 - `LiveStatusUpdate` 가 `ReadBit` 의 `.err` 를 버려 "PLC 미송신"과 "PC 미수신"이 구분 안 됨 - `AlarmManager.Alarm`(`AlarmManager.cs:79-104`)에 짝이 되는 `ClearAlarm` 이 없어 통신 복구 후에도 알람 잔존 - `SeqAlarmMonitor` — `WaitTime` 무지연 루프(`:145-148`), Laser/Chiller 즉시 알람(grace 없음), `:190-193` `_Laser` null 시 NRE 위험, `InitDev` 진입 1회만 실행 - `AlarmMonitoring.cs` 죽은 코드 정리 - `Light` 디바이스 `SerialPort.Open()` 실패 (`16:12:25.875 E EquipmentSetup: Light connect fail.`) — 본 건과 무관, 미확인 ### 산출 - `docs/분석_PLC210002_기동오알람_260810.md` (분석 상세) - 커밋 대상: 위 분석 문서 + `PLCController.Config.cs`