From 5d2cdb3452167d049baf0e6942d87de95c61c3f8 Mon Sep 17 00:00:00 2001 From: NohDoyeon241104 Date: Fri, 19 Jun 2026 09:28:22 +0900 Subject: [PATCH 1/6] =?UTF-8?q?docs:=20=EC=9E=91=EC=97=85=EC=9D=BC?= =?UTF-8?q?=EC=A7=80=202026-06-19=20-=20External/Aurora/bin=20=EC=BB=A4?= =?UTF-8?q?=EB=B0=8B=20=EC=98=88=EC=99=B8=20=EB=B0=8F=20=EA=B7=9C=EC=B9=99?= =?UTF-8?q?=20=EB=AC=B8=EC=84=9C=ED=99=94=20=EA=B8=B0=EB=A1=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.8 --- docs/작업일지/2026_06_19.md | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 docs/작업일지/2026_06_19.md diff --git a/docs/작업일지/2026_06_19.md b/docs/작업일지/2026_06_19.md new file mode 100644 index 0000000..a1b227b --- /dev/null +++ b/docs/작업일지/2026_06_19.md @@ -0,0 +1,11 @@ +# 작업일지 — 2026-06-19 + +## 09:27 +- External/Aurora/bin 을 git 커밋 대상에 포함시킴 (전역 `bin/` 무시는 유지, negation 예외 처리) + - `.gitignore`에 `!/External/Aurora/bin/`, `!/External/Aurora/bin/**` 두 줄 추가 + - `.gitignore` 자체가 `/.gitignore`로 무시되어 `git add -f`로 강제 추가 + - Aurora bin 산출물 14개 파일 + .gitignore 함께 커밋 (7f464ab) +- 위 커밋 규칙을 `docs/GIT_RULES.md`로 문서화 + - bin 무시/예외, .gitignore 자체 커밋(-f) 규칙 정리 + - `architecture.md`에 `@import ./GIT_RULES.md` 연결 (목차 7번 추가) + - 커밋 후 push (de0c1c2) From 3293455a28e8b71703db496eb44c607ce859408f Mon Sep 17 00:00:00 2001 From: NohDoyeon241104 Date: Fri, 19 Jun 2026 09:36:23 +0900 Subject: [PATCH 2/6] =?UTF-8?q?docs:=20=ED=98=91=EC=97=85=20=EA=B7=9C?= =?UTF-8?q?=EC=B9=99=205=EB=B2=88=20-=20.md=20=EC=98=81=EB=AC=B8=20?= =?UTF-8?q?=EC=9E=91=EC=84=B1=20=EC=9A=94=EA=B1=B4=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.8 --- rules.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rules.md b/rules.md index 1fc9ed3..60d3e92 100644 --- a/rules.md +++ b/rules.md @@ -7,7 +7,7 @@ 4. 코드 수정 시 한글이 안 깨지도록 수정할 것 ## 문서화 -5. `.md` 파일의 내용은 영문으로 작성하고 200줄 이상 넘지 않도록 작성 +5. `.md` 파일의 내용은 200줄 이상 넘지 않도록 작성 6. CLAUDE.md에는 라이브러리 형태로 각각의 주제에 맞는 `.md`를 `@import`하여 여러 `.md`를 사용 7. 작업을 완료할 시 `.md`에 필요한 부분이라고 생각되면 물어보고 `.md` 파일 갱신하기 From 7cb652574f606f88b0ff66a076468c47f781e4e9 Mon Sep 17 00:00:00 2001 From: NohDoyeon241104 Date: Fri, 19 Jun 2026 09:38:24 +0900 Subject: [PATCH 3/6] =?UTF-8?q?docs:=20PtoP=20PLC=20=EC=9D=B8=ED=84=B0?= =?UTF-8?q?=ED=8E=98=EC=9D=B4=EC=8A=A4=20xlsx(260617)=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.8 --- .../유니셀 PtoP 단동기 Laser Interface_260617.xlsx | Bin 52178 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 docs/PtoP 유니셀 용접기 PLC 인터페이스/유니셀 PtoP 단동기 Laser Interface_260617.xlsx diff --git a/docs/PtoP 유니셀 용접기 PLC 인터페이스/유니셀 PtoP 단동기 Laser Interface_260617.xlsx b/docs/PtoP 유니셀 용접기 PLC 인터페이스/유니셀 PtoP 단동기 Laser Interface_260617.xlsx deleted file mode 100644 index 709c1a7bb0cd7bf9415de42b824f6b079deb2812..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 52178 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 _7iZ`PM+Zv8K)rr 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 From 3724007b15fa7c97f9ee575baf6bb63d1bd19f92 Mon Sep 17 00:00:00 2001 From: NohDoyeon241104 Date: Fri, 19 Jun 2026 09:38:52 +0900 Subject: [PATCH 4/6] =?UTF-8?q?chore:=20WPF=20=EB=B9=8C=EB=93=9C=20?= =?UTF-8?q?=EC=9E=84=EC=8B=9C=20=ED=8C=8C=EC=9D=BC(*=5Fwpftmp.csproj)=20gi?= =?UTF-8?q?tignore=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.8 --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 3cded50..0c26fb2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ *.suo *.user +*_wpftmp.csproj *.pdb _ReSharper.* obj/ From 85a5aad60d2c66f5963aa1cb28427187e0403f0b Mon Sep 17 00:00:00 2001 From: NohDoyeon241104 Date: Fri, 19 Jun 2026 09:39:30 +0900 Subject: [PATCH 5/6] =?UTF-8?q?docs:=20=EC=9E=91=EC=97=85=EC=9D=BC?= =?UTF-8?q?=EC=A7=80=202026-06-19=20-=20*=5Fwpftmp.csproj=20gitignore=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=20=EA=B8=B0=EB=A1=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.8 --- docs/작업일지/2026_06_19.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/작업일지/2026_06_19.md b/docs/작업일지/2026_06_19.md index a1b227b..171fc19 100644 --- a/docs/작업일지/2026_06_19.md +++ b/docs/작업일지/2026_06_19.md @@ -9,3 +9,9 @@ - bin 무시/예외, .gitignore 자체 커밋(-f) 규칙 정리 - `architecture.md`에 `@import ./GIT_RULES.md` 연결 (목차 7번 추가) - 커밋 후 push (de0c1c2) + +## 09:39 +- WPF 빌드 자동 생성 임시 파일 `*_wpftmp.csproj`를 `.gitignore`에 추가 + - `AuroraPLC_2pjacgrp_wpftmp.csproj`는 sln/csproj 어디에도 참조되지 않는 빌드 산출물 → 커밋 대상 아님 + - 매번 git status에 안 뜨도록 `*_wpftmp.csproj` 무시 처리, push (3724007) +- 그 외 정리: rules.md 규칙 5번 .md 영문 작성 요건 제거(3293455), PtoP PLC 인터페이스 xlsx(260617) 삭제(7cb6525) 커밋·push From 3b8799aa51667dbfe0bc67c9d94e95b235cebad1 Mon Sep 17 00:00:00 2001 From: NohDoyeon241104 Date: Fri, 19 Jun 2026 12:49:08 +0900 Subject: [PATCH 6/6] =?UTF-8?q?feat/docs:=20=EA=B0=80=EC=9D=B4=EB=93=9C?= =?UTF-8?q?=EB=B9=94=C2=B7=EC=95=8C=EB=9E=8C=C2=B7PLC(MXComponent)=20?= =?UTF-8?q?=EB=B6=84=EC=84=9D=20=EB=B0=8F=20=ED=98=84=EC=9E=A5=20=EC=9E=84?= =?UTF-8?q?=EC=8B=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 분석 문서 4종 추가 (docs/분석/2026/06/19): 알람부 종합 / MX Component PLC 연결 / AjinIO.ReadDoBit / 가이드빔 TruPulse(ExtPilotOnOff 미구현) - AjinIO.ReadDoBit(int): 스텁(return true) 유지 + 구현(ReadDiBit 패턴) 주석 보존 - SeqComponentTeachingRun: 중알람 인터락 임시 주석 (현장 PLC 미연결 우회, 추후 원복) - 레시피 Guide Beam: DO 17 read/write + IsConnected 가드 주석 (필요시 주석 토글 운용) - 작업일지 2026-06-19 정리 Co-Authored-By: Claude Opus 4.8 --- .../AuroraIO/Vendor/AJINEXTEK/AjinIO.cs | 10 ++ .../Manual/SeqComponentTeachingRun.cs | 13 +- ...cannerObjectTeachingControlBoxViewModel.cs | 53 +++++--- .../06/19/110333_alarm_subsystem_analysis.md | 111 ++++++++++++++++ ...11326_mxcomponent_plc_connection_analysis.md | 82 ++++++++++++ .../06/19/122201_ajinio_readdobit_analysis.md | 68 ++++++++++ .../06/19/124752_guidebeam_trupulse_analysis.md | 59 +++++++++ docs/작업일지/2026_06_19.md | 123 ++++++++++++++++++ 8 files changed, 496 insertions(+), 23 deletions(-) create mode 100644 docs/분석/2026/06/19/110333_alarm_subsystem_analysis.md create mode 100644 docs/분석/2026/06/19/111326_mxcomponent_plc_connection_analysis.md create mode 100644 docs/분석/2026/06/19/122201_ajinio_readdobit_analysis.md create mode 100644 docs/분석/2026/06/19/124752_guidebeam_trupulse_analysis.md diff --git a/AuroraDevices/AuroraIO/Vendor/AJINEXTEK/AjinIO.cs b/AuroraDevices/AuroraIO/Vendor/AJINEXTEK/AjinIO.cs index 686ffef..af71ad8 100644 --- a/AuroraDevices/AuroraIO/Vendor/AJINEXTEK/AjinIO.cs +++ b/AuroraDevices/AuroraIO/Vendor/AJINEXTEK/AjinIO.cs @@ -497,6 +497,16 @@ namespace AuroraIO.AJINEXTEK { //현재 사용하지 않아서 추후 구현 return true; + + // [추후 구현] return true 스텁 의존 코드 확인 후 아래로 교체 (ReadDiBit(int) 패턴) + //uint data = 0; + // + //int err = (int)CAXD.AxdoReadOutport(index, ref data); + //if (err != (int)AXT_FUNC_RESULT.AXT_RT_SUCCESS) + //{ + // throw new Exception(string.Format("ERR_IO_FAIL_TO_GET_BIT;ERROR CODE:{0}", err)); + //} + //return Convert.ToBoolean(data); } public override bool ReadDiBit(int index) { diff --git a/Machines/ILSOS_PrismaticRD_PTOP/Sequences/Manual/SeqComponentTeachingRun.cs b/Machines/ILSOS_PrismaticRD_PTOP/Sequences/Manual/SeqComponentTeachingRun.cs index 0c95add..d7b97f1 100644 --- a/Machines/ILSOS_PrismaticRD_PTOP/Sequences/Manual/SeqComponentTeachingRun.cs +++ b/Machines/ILSOS_PrismaticRD_PTOP/Sequences/Manual/SeqComponentTeachingRun.cs @@ -269,12 +269,13 @@ namespace ILSOS_PrismaticRD_PTOP.Sequences private bool CheckCondition_Interlock() { //// PLC, Data, IO 등 Interlock checking - bool boolian = AlarmManager.HasAlarmLevelHigh(); - if (boolian) { - Log.E($"Clear Heavy Alarms For Welding!"); - MessageUtil.ShowWarningToast(string.Format("Clear Heavy Alarms For Welding!")); - return false; - } + // [임시 우회] 테스트용으로 High(중대) 알람 인터락 주석 처리 — 테스트 후 반드시 원복할 것! + //bool boolian = AlarmManager.HasAlarmLevelHigh(); + //if (boolian) { + // Log.E($"Clear Heavy Alarms For Welding!"); + // MessageUtil.ShowWarningToast(string.Format("Clear Heavy Alarms For Welding!")); + // return false; + //} #warning to KSJ > 지워도 무방해보임 //boolian = AlarmManager.IsPlcDoorOpen(); diff --git a/WeldingComponents/WeldingCommon/Views/Recipes/UCScannerObjectTeachingControlBoxViewModel.cs b/WeldingComponents/WeldingCommon/Views/Recipes/UCScannerObjectTeachingControlBoxViewModel.cs index dd853f5..1d2047e 100644 --- a/WeldingComponents/WeldingCommon/Views/Recipes/UCScannerObjectTeachingControlBoxViewModel.cs +++ b/WeldingComponents/WeldingCommon/Views/Recipes/UCScannerObjectTeachingControlBoxViewModel.cs @@ -171,22 +171,32 @@ namespace WeldingCommon.Views private void OnMonitoring(object sender, EventArgs e) { - // TODO: Laser Device 에 구현된 내용에 따르면, 일부 Laser Device 는 구현이 되어 있지 않은 상태. 항상 false - if (_Laser.GetPilotLaserStatus()) { - IsGuidBeam = true; - } else { - IsGuidBeam = false; - } + // Guide Beam: DI 결선 없음 → 가이드빔 제어 DO 17 명령 비트를 그대로 표시 + // (기존 _Laser.GetPilotLaserStatus()는 DO 3=GuideLaserEnable 을 봤으나, 현장 가이드빔 제어선은 DO 17) + // IO 미연결 가드는 현장PC에서 동작 안 해 주석 (개발PC에서 주석 해제) + //if (_IODevice == null || !_IODevice.IsConnected()) { + // IsGuidBeam = false; + //} else { + // IsGuidBeam = _IODevice.ReadDO(17); + //} + IsGuidBeam = _IODevice.ReadDO(17); + + // [기존 소스 보존] Laser 디바이스 기반 Pilot 상태 (DO 3=GuideLaserEnable) — 일부 Laser 미구현 시 항상 false + //if (_Laser.GetPilotLaserStatus()) { + // IsGuidBeam = true; + //} else { + // IsGuidBeam = false; + //} try { - // 시뮬 아님 + IO보드 없음 → _iOUnit == null → ReadDI에서 NRE로 꺼짐. + // 시뮬 아님 + IO보드 없음 → _iOUnit == null → ReadDI에서 NRE로 꺼짐. - 현장PC 아닌 경우 개발PC에서 주석 해제 (시뮬안하고 레시피 들어갔을 때 프로그램 종료 방지) // IsConnected()가 _iOUnit null/미연결을 체크하므로, 미연결이면 폴링 스킵(꺼짐 방지). - if (_IODevice == null || !_IODevice.IsConnected()) - { - IsLaserReady = false; - } + //if (_IODevice == null || !_IODevice.IsConnected()) + //{ + // IsLaserReady = false; + //} // 변경 후 (260618: IO 결선 변경 12&24 → 11&15) - else if (_IODevice.ReadDI(11) && _IODevice.ReadDI(15)) + if (_IODevice.ReadDI(11) && _IODevice.ReadDI(15)) { IsLaserReady = true; } @@ -455,11 +465,20 @@ namespace WeldingCommon.Views private void PerformCmdLaserGuideBeam(object obj) { - if (!_Laser.GetPilotLaserSetBitStatus()) { - _Laser.PilotLaserOn(); - } else { - _Laser.PilotLaserOff(); - } + // Guide Beam DO 17 토글 — 모니터링도 같은 DO 17 을 읽어 표시 + // IO 미연결 가드는 현장PC에서 동작 안 해 주석 (개발PC에서 주석 해제) + //if (_IODevice == null || !_IODevice.IsConnected()) { + // return; + //} + bool cur = _IODevice.ReadDO(17); + _IODevice._iOUnit.WriteDoBit(17, !cur); + + // [기존 소스 보존] Laser 디바이스 기반 Pilot On/Off 토글 (DO 3=GuideLaserEnable) + //if (!_Laser.GetPilotLaserSetBitStatus()) { + // _Laser.PilotLaserOn(); + //} else { + // _Laser.PilotLaserOff(); + //} } private void PerformCmdLaserReadyCheck(object obj) diff --git a/docs/분석/2026/06/19/110333_alarm_subsystem_analysis.md b/docs/분석/2026/06/19/110333_alarm_subsystem_analysis.md new file mode 100644 index 0000000..8800e3f --- /dev/null +++ b/docs/분석/2026/06/19/110333_alarm_subsystem_analysis.md @@ -0,0 +1,111 @@ +# ILSOS PTOP 알람부(AlarmManager) 종합 분석 — 2026-06-19 + +> 계기: 현장 PLC 미연결 상태에서 `SeqComponentTeachingRun` 시작 시 H(중)알람 인터락(202003)으로 차단됨. +> 본 문서는 알람부 전체 구조·동작·시퀀스 참조·리스크·개선안을 정리한다. + +--- + +## 1. 클래스 구조 + +| 클래스 | 위치 | 역할 | +|--------|------|------| +| `AlarmManager` (base) | `WeldingCommon/Alarm/AlarmManager.cs` | 정적 싱글톤(`_Instance`). 알람 set/조회/시퀀스 정지 | +| `AlarmManager_PTOP` | `PTOP/Alarm/AlarmManager_PTOP.cs` | `StopSequenceByAlarm` — H알람 시 AutoRun 정지 | +| `AlarmCode` / `AlarmCode_PTOP` | `.../Alarm/AlarmCode*.cs` | 알람 코드 상수. PTOP는 base 상속 후 21xxxx 추가 | +| `IAlarmService` (Aurora 프레임워크) | External/Aurora | **활성 알람 목록·설명·레벨(H/L)** 보유 | + +- 알람 **레벨(H/L)** 은 소스 상수가 아니라 **Aurora 런타임 알람 테이블**에 정의됨(코드에 `AlarmLevel.H` 할당부 없음). + +## 2. 핵심 메서드 동작 (주의점) + +- **`Alarm(code)`** (79줄): 이미 활성이면 재set 안 함 → **set-once(중복 없음)**. +- **`HasAlarmLevelHigh()`** (172줄): 활성 알람 중 H 하나라도 있으면 true. **⚠️ Simulation이면 무조건 false**(시뮬은 인터락 우회). +- **`IsAlarmLevelHigh(code)`** (194줄): 설명 모르는 코드(`desc==null`)는 **위험으로 보고 H 취급** → 미정의 코드도 인터락 유발. +- **Clear**: 개별 `ClearAlarm()`은 **빈 함수**(주석만). 실제 해제는 **`ClearAllAlarm()`(전체 일괄)** 뿐. + - 트리거: `SYS_ALARM_RESET_ALL_ALARM` / `EVENT_RESET_ALL_ALARMS_REQUEST` → `_AlarmService.ClearAllAlarm()`. +- **PLC 알람워드 직접쓰기**(`WriteBit(HeavyAlarmStatusAddr..)`)는 AlarmManager 내에서 전부 **주석 처리**됨(대신 SeqStatusMonitor가 수행). + +## 3. 알람 생성·소멸·전파 흐름 + +``` +[생성] SeqAlarmMonitor (상시 주기 감시) + ├ PLC: EMO / Heavy / Door / 통신끊김 + ├ Laser/Scanner/LBAD/OCT/Chiller: Deactivated/Disconnect/Error + └ IO: Leak / null / deactivated + → AlarmManager.Alarm(code) ← set-only, ❌조건 해소 시 Clear 안 함(LATCH) + +[전파] EquipmentSetup.OnSetAlarm(code, isHeavy) (EquipmentSetup.cs:82) + → isHeavy 면 AlarmManager_PTOP.StopSequenceByAlarm(code) → H면 StopSequence(SeqAutoRun) 비상정지 + +[PLC보고] SeqStatusMonitor.UpdateStatus (SeqStatusMonitor.cs:86) + → PC_HEAVY_ALARM_STATUS = HasAlarmLevelHigh(), PC_LIGHT_ALARM_STATUS = HasAlarmLevelLow() + → PLC_ALARM_RESET 입력 시 EVENT_RESET_ALL_ALARMS_REQUEST 발행 → ClearAllAlarm() + +[차단] 각 시퀀스 시작 시 CheckCondition_Interlock() → HasAlarmLevelHigh() H면 시작 거부 +``` + +## 4. 주요 시퀀스별 알람 참조 + +| 시퀀스 | 인터락 체크 | 비고 | +|--------|------------|------| +| **SeqComponentTeachingRun** | `HasAlarmLevelHigh()` → "Clear Heavy Alarms" + 202003 (Door/EMO 주석) | **이번에 막힌 시퀀스** | +| SeqTeachingRun (Common) | `CheckCondition_Interlock()` = **빈 체크(true)** | 알람 체크 없음 | +| **SeqAutoRunPTOP** | `CheckCondition_Interlock()` = **빈 체크(true)** | 차단은 시작이 아니라 OnSetAlarm→StopSequence | +| SeqAutoRunPrismatic / ComponentWeld | 동일 패턴(빈 체크) | | +| ScoutNormal/FlyingVision, UploadWeldingList, ReceiveCellInfo, ReportCellResult, MarkGrid, ScannerCalibration | 대부분 빈 체크 | 공통 시퀀스 | +| **SeqStatusMonitor** | 알람을 **읽어 PLC 출력** + Reset 처리 | 차단 아님 | +| **SeqAlarmMonitor** | 알람을 **생성(set-only)** | latch 원인 | + +> 실제 알람으로 "시작 차단"하는 곳은 `SeqComponentTeachingRun`이 거의 유일. AutoRun 계열은 "운전 중 H알람 발생 시 비상정지" 방식. + +## 5. 알람 코드 표 (추정 레벨 — 권위값은 런타임 테이블) + +| 코드 | 이름 | 용도 | 추정 | +|------|------|------|------| +| 200xxx~203xxx | ALARM_SEQUENCE_* | 시퀀스 결과/초기조건 실패 | 혼합 | +| 203004 | AutoRun_HeavyAlarmOccured | 자동운전 중 중알람 | H | +| 210001/2/3 | PLC Deactivated/Disconnect/**EMO** | PLC 상태/비상정지 | H | +| 210004/5/6 | PLC Light / **Heavy** / Door Interlock | PLC 경/중/도어 | 210005·6 H, 210004 L | +| 210101/2/3 | Scanner Deactivated/Disconnect/Error | 스캐너 | H/혼합 | +| 210201~205 | Laser Deactivated/Disconnect/Error/Warning/**EMO** | 레이저 | 205·201 H, 204 L | +| 210206/7 | Laser Warning/Error MSG | 레이저 메시지(동적) | L/H | +| 210301~303 | LBAD Deactivated/Disconnect/Error | LBAD | H/혼합 | +| 210401~403 | OCT Deactivated/Disconnect/Error | OCT | H/혼합 | +| 210501~503 | Chiller Deactivated/Disconnect/Error | 냉각기 | H/혼합 | +| 210600~604 | IO Null/Deactivated/Disconnect/**Leak**(Scanner/Chiller) | IO보드/누액 | H | +| 210605~614 | IO MC/BoxTemp/ChillerLeak/Fan1~6 | (현재 대부분 주석) | 혼합 | +| 210700~705 | RMS_* 타임아웃/설정 | 레시피 관리 | L 추정 | + +## 6. 리스크 / 개선 포인트 + +1. **알람 Latch (최우선)** — `SeqAlarmMonitor`가 set만 하고 조건 정상화 시 `ClearAlarm` 안 함. → **이번 PLC 미연결 사례**가 정확히 이것: 연결 복구돼도 알람이 남아 차단, 수동 ClearAll 필요. +2. **개별 Clear 부재** — `ClearAlarm()`이 빈 함수 → 전체 일괄 해제만 가능, 특정 알람만 해제 불가. +3. **Unknown=H 취급** — 미정의 코드 활성 시 무조건 H 차단 → 알람 테이블 누락 시 의도치 않은 인터락. +4. **시뮬 우회** — `HasAlarmLevelHigh()`가 Simulation이면 false → 시뮬/현장 동작 차이. +5. **인터락 일관성 부재** — TeachingRun만 알람 차단, 나머지 시작 시퀀스는 빈 체크. 안전 정책 제각각. +6. **Door/EMO 주석** — SeqComponentTeachingRun·UCMainAutoRunViewModel의 Door/EMO 인터락 주석 → 현재 중알람 1종만 차단. + +## 7. 개선 제안 — SeqAlarmMonitor self-clearing + +각 검사 항목을 "조건 나쁨 → Alarm, 조건 좋음 → Clear" 대칭 구조로. 예(개념): + +```csharp +// AS-IS +if (!_Laser.IsActivated) AlarmManager.Alarm(ALARM_DEVICE_LASER_DEACTIVATED); +else { /* clear 없음 → latch */ } + +// TO-BE (self-clearing) — AlarmManager에 개별 ClearAlarm(code) 구현 전제 +if (!_Laser.IsActivated) AlarmManager.Alarm(ALARM_DEVICE_LASER_DEACTIVATED); +else AlarmManager.ClearAlarm(ALARM_DEVICE_LASER_DEACTIVATED); +``` + +- 전제: `AlarmManager.ClearAlarm(int code)` 실구현 필요(현재 빈 함수). `_AlarmService`에 단건 해제 API 확인 후 연결. +- 효과: PLC 재연결 등 조건 복구 시 알람 자동 해제 → 수동 ClearAll 불필요, 인터락 latch 해소. +- 범위: AlarmManager(공통) 수정 → **승인 필요 영역**. 적용 전 별도 협의. + +## 8. 부록 — 이번(PLC 미연결) 사례 요약 + +- PLC 미연결 → `SeqAlarmMonitor`가 PLC Deactivated/Disconnect(H) set → latch. +- `SeqComponentTeachingRun` 시작 → `HasAlarmLevelHigh()` true → 202003, FORCE_ERROR. +- 임시조치: `SeqComponentTeachingRun.CheckCondition_Interlock()`의 H알람 블록 주석(테스트용, **원복 예정**) → 레이저 출사 확인. +- 관련: [[axis-position-interlock-todo]] diff --git a/docs/분석/2026/06/19/111326_mxcomponent_plc_connection_analysis.md b/docs/분석/2026/06/19/111326_mxcomponent_plc_connection_analysis.md new file mode 100644 index 0000000..d6de06e --- /dev/null +++ b/docs/분석/2026/06/19/111326_mxcomponent_plc_connection_analysis.md @@ -0,0 +1,82 @@ +# MX Component PLC 연결 설정 분석 — 2026-06-19 + +> 계기: 현장 PLC 미연결 → 중알람 latch → TeachingRun 인터락 차단. +> PLC를 정상 연결하려면 무엇을 PLC측에 요청하고, PC 소스/설정의 어떤 값을 맞춰야 하는지 분석(수정 없음). +> 관련: [[110333_alarm_subsystem_analysis]] + +--- + +## 1. 연결 메커니즘 (소스 기준) + +- 드라이버: `AuroraDevices/AuroraMXComponent/MXComponent.cs` — Mitsubishi **MX Component** .NET 컨트롤 `ActUtlType64Class` 사용. +- PTOP 등록(`EquipmentSetup.cs:158`): + `new PLCControllerPTOP(PLCDevice, ePLCNetType.MXComponent, IsSimulation, PLCMMapFileType.CSV, AuroraEnv)` +- 연결 흐름: + ``` + PLCBase.DoActivate (PLCBase.cs:80) + → NetworkType == MXComponent + → PLCNet.SetInitParams(connConfig.StationNumber) // = ActLogicalStationNumber + → Open() → _actUtlType.ActLogicalStationNumber = N; _actUtlType.Open() + ``` +- **핵심 파라미터 = `StationNumber` (논리국번 / Logical Station Number)**. + `MXComponent.SetInitParams(int logicalStationNo)` → `_actUtlType.ActLogicalStationNumber = logicalStationNo` (MXComponent.cs:26~29). +- Open 결과: `0x00000000` 성공, 그 외 Hex 에러. `0x0180840B`(타임아웃) 시 1회 재시도(MXComponent.cs:48). + +## 2. 맞춰야 하는 값 — PC측 + +### (A) MX Component "Communication Setup Utility" (별도 PC 도구) +- MX Component 설치 시 함께 깔리는 **통신 설정 유틸리티**에서 **Logical Station Number** 를 등록. +- 등록 시 입력: PLC **CPU 기종**, **접속 경로**(CPU 내장 이더넷 / 이더넷 모듈 / CC-Link IE / USB / 시리얼), **PLC IP/포트**, 네트워크/국번. +- 이 유틸리티에 등록된 논리국번이 실제 통신 경로를 정의함. (소스는 "번호"만 들고, 실 경로는 유틸리티가 보유) + +### (B) 소스/설정 파일 — `StationNumber` 일치 +- 정의: `AuroraDevices/AuroraPLC/PLCBase.Config.cs:37` + `PLCMXComponentConnConfig.StationNumber` 기본값 **1** (주석: "Logical station No. (By PC Tool: Communication Setting Utility)"). +- 실제 값은 **디바이스 config 파일에 저장**: `_config_device/PLC.json` + ```json + { "ConnConfig": { "StationNumber": 22, "UpdateRateMS": 50 } } + ``` + (위는 Gun 예시 = 22. PTOP는 현장 값으로 별도 설정 필요) +- **편집 경로**: 프로그램 내 PLC 디바이스 설정 화면(`UCPLCDevice`)에서도 수정 가능, 또는 위 JSON 직접 편집. +- ⚠️ **(A)의 유틸리티 논리국번 == (B)의 PLC.json StationNumber** 이어야 연결됨. (현장 PLC.json은 repo에 없음 = 현장 전용) + +## 3. PLC측에 요청해야 할 것 + +| 항목 | 내용 | +|------|------| +| CPU 기종 | Q / L / iQ-R / iQ-F 등 정확한 모델 | +| 접속 방식 | CPU 내장 이더넷 / 이더넷 모듈 / CC-Link IE / USB / 시리얼 중 무엇 | +| 네트워크 정보 | PLC **IP 주소 / 포트**, 서브넷, (CC-Link IE면) 네트워크No·국번 | +| MELSOFT 접속 허용 | 이더넷 "MELSOFT 접속" 오픈 설정, 포트 개방(보통 5007/5006 등), 방화벽 | +| 국번 구성 | 멀티 CPU/증설 시 대상 station | + +→ 위 정보를 받아 **(A) Communication Setup Utility에 논리국번으로 등록**하고, 그 번호를 **(B) PLC.json StationNumber** 에 동일하게 넣으면 연결. + +## 4. 메모리맵 CSV (연결과 별개, 데이터 정합용) + +- `PLCMMapFileType.CSV` → `PLCBase.MemMapParser.cs`가 아래 8종 CSV를 읽어 디바이스 주소 매핑: + - `External/PLC/PLC_DeviceMap_Bit_Input_B_Device.csv` / `..._Output_B_Device` + - `..._Bit_Input_M_Device` / `..._Output_M_Device` + - `..._Word_Input_W_Device` / `..._Output_W_Device` + - `..._Word_Input_D_Device` / `..._Output_D_Device` + - 경로: recipePath 기준 `External\PLC\...` (현장 config 폴더). +- 연결(Open)과는 무관하지만, 연결 후 **읽고/쓰는 주소가 PLC 실제 디바이스와 맞아야** 알람/인터페이스가 정상. PTOP는 repo에 맵 CSV 없음(현장 전용) → [[plc-devicemap-260617-pending]] 참고. + +## 5. 점검 순서 (현장) + +1. PLC측에서 **CPU기종·접속방식·IP/포트·MELSOFT 접속 허용** 확보 +2. PC에서 **MX Component Communication Setup Utility** 실행 → 위 정보로 **논리국번**(예: 1) 등록 → 유틸리티 내 "통신 테스트" 통과 확인 +3. `_config_device/PLC.json` 의 `StationNumber` 를 그 논리국번과 동일하게 설정 (또는 PLC 디바이스 설정 화면) +4. 프로그램 재기동 → PLC Activate → 로그 `PLC Open success` 확인 (`Open: 0x00000000`) +5. 연결되면 SeqAlarmMonitor의 PLC Deactivated/Disconnect 알람 조건 해소 → (단, latch라 **ClearAll 1회** 필요할 수 있음, [[110333_alarm_subsystem_analysis]] 참고) + +## 6. 참고 — 에러코드 / 매뉴얼 + +- Open/Close 반환값은 MX Component 표준 Hex 에러코드. `0x0180840B` = 타임아웃(소스에서 1회 재시도). +- 상세 절차·에러표: `Doc/메뉴얼/공통/PLC/21. MX_Component_V4_프로그래밍_매뉴얼.pdf` (Communication Setup Utility / ActUtlType / 에러코드 장 참조). + +## 7. 요약 + +- **연결 핵심 = 논리국번 1개**. PC의 MX Component 유틸리티 등록값 ↔ 소스 `PLC.json StationNumber` 일치 + PLC측 이더넷/접속 허용. +- PLC.json·맵 CSV는 **현장 전용**(repo 없음) → 현장에서 값 세팅 필요. +- 연결되면 PLC 미연결 중알람 해소 → TeachingRun 인터락 정상화 (latch면 ClearAll 1회). diff --git a/docs/분석/2026/06/19/122201_ajinio_readdobit_analysis.md b/docs/분석/2026/06/19/122201_ajinio_readdobit_analysis.md new file mode 100644 index 0000000..5b9dfc3 --- /dev/null +++ b/docs/분석/2026/06/19/122201_ajinio_readdobit_analysis.md @@ -0,0 +1,68 @@ +# AjinIO.ReadDoBit(int) 미구현 분석 — 2026-06-19 + +> 계기: `AjinIO.cs`의 `ReadDoBit(int index)`(bool 반환)가 미구현 스텁(`return true`). +> DI 패턴 대비 분석 후, 현 상태는 **스텁 유지 + 구현 주석 보존**으로 결정(현장 반영 예정). +> 관련: [[110333_alarm_subsystem_analysis]] + +--- + +## 1. 현황 + +- 파일: `AuroraDevices/AuroraIO/Vendor/AJINEXTEK/AjinIO.cs` (보호 영역, 신중 수정) +- DI/DO 오버로드 4종(`IOUnit` 추상): + - `int ReadDoBit(int, ref bool)` (469줄) — `CAXD.AxdoReadOutport` 사용, **구현됨** + - `int ReadDiBit(int, ref bool)` (483줄) — `CAXD.AxdiReadInport`, 구현됨 + - `bool ReadDoBit(int)` (496줄) — **미구현 스텁(`return true`)** ← 대상 + - `bool ReadDiBit(int)` (501줄) — `CAXD.AxdiReadInport`, 구현됨(실패 시 throw) +- 즉 **DO 읽기 API(`AxdoReadOutport`)는 같은 파일에서 이미 검증**됨(469줄·`GetDoArray` 399줄). bool 반환 오버로드만 DO쪽이 비어 있었음. + +## 2. 구현안 (DI 패턴 그대로) + +```csharp +public override bool ReadDoBit(int index) +{ + uint data = 0; + int err = (int)CAXD.AxdoReadOutport(index, ref data); + if (err != (int)AXT_FUNC_RESULT.AXT_RT_SUCCESS) + throw new Exception(string.Format("ERR_IO_FAIL_TO_GET_BIT;ERROR CODE:{0}", err)); + return Convert.ToBoolean(data); +} +``` +- `ReadDiBit(int)`(501줄)와 완전 동일 구조, API만 `AxdiReadInport → AxdoReadOutport`. + +## 3. 스텁 의존 호출처 분석 (영향 범위) + +`bool ReadDoBit(int)` 호출처 전수: + +| 호출처 | 위치 | 용도 | +|--------|------|------| +| `UCInformationPanelViewModel.cs` | 46, 53, 82, 115, 132 (5곳) | ModeKeySolOn / SafetyDoorRelease **상태 표시** | + +- 5곳 모두 **`ePDOAddress`(PAIX 주소)** 사용 → 실제 **PAIX 보드에서 실행**. +- **PAIX의 `ReadDoBit(int)`는 정상 구현**(PAIXIO.cs:288, `GetDoArray`로 읽음) → 이 호출처는 이미 정상 동작. +- `(int, ref bool)` 오버로드 호출(`UCTestDeviceViewModel.cs:264`)은 Ajin도 구현돼 있어 무관. +- **결론: Ajin 스텁(`return true`)에 실제 의존하는 코드는 사실상 없음.** 영향은 "Ajin 보드 장비에서 위 5개 호출이 도는 경우"로 한정되며, 그 경우 오히려 항상 true가 오표시였음(상태 표시용, 안전제어 아님 → 위험 낮음). + +## 4. 현재 결정 상태 (스텁 유지 + 구현 주석 보존) + +```csharp +public override bool ReadDoBit(int index) +{ + //현재 사용하지 않아서 추후 구현 + return true; + + // [추후 구현] return true 스텁 의존 코드 확인 후 아래로 교체 (ReadDiBit(int) 패턴) + //uint data = 0; + //int err = (int)CAXD.AxdoReadOutport(index, ref data); + //if (err != (int)AXT_FUNC_RESULT.AXT_RT_SUCCESS) + // throw new Exception(...); + //return Convert.ToBoolean(data); +} +``` +- 동작 변화 없음(`return true` 유지) → 현장 안전. 구현은 주석으로 보존해 추후 활성화 용이. +- 빌드 산출물: **AuroraIO.dll**. + +## 5. 후속 (활성화 조건) + +- Ajin 보드 장비에서 DO 상태 표시 정확성이 필요해질 때, 주석 해제 + 위 5개 호출처 회귀 확인. +- 활성화 시 실패 처리(throw) 영향 검토: `ReadDiBit(int)`와 동일 정책이라 일관성은 확보됨. diff --git a/docs/분석/2026/06/19/124752_guidebeam_trupulse_analysis.md b/docs/분석/2026/06/19/124752_guidebeam_trupulse_analysis.md new file mode 100644 index 0000000..8e01d2d --- /dev/null +++ b/docs/분석/2026/06/19/124752_guidebeam_trupulse_analysis.md @@ -0,0 +1,59 @@ +# 가이드빔(Guide Beam) 제어 경로 분석 — TruPulse — 2026-06-19 + +> 계기: 레시피 Guide Beam 버튼/상태가 현장에서 동작하지 않음. IO(DO)→Laser 순으로 추적. +> 결론: 가이드빔은 **Laser(TruPulse) 디바이스 기능**이며, 제어 콜백 **`ExtPilotOnOff`가 미구현(미할당)**. +> 관련: [[110333_alarm_subsystem_analysis]] + +--- + +## 1. 잘못된 경로였던 IO(DO 17) 시도 요약 + +- 레시피 ViewModel(`UCScannerObjectTeachingControlBoxViewModel.cs`)에서 `_IODevice`(메인 IO_Board=PAIX_PTOP)의 + **DO 17(EX_Red_Control)** 을 read/write 하도록 수정 → 상태 표시(읽기)는 동작 확인. +- 그러나 **물리적 가이드빔(적색광)은 출력 안 됨**. +- 현장 확인: 번들(DBW-MC Laser SW)의 `RedLight Opened/Closed` 이벤트는 **번들의 RedClosed 버튼 수동 조작** 결과로, + 우리 DO 17과 무관. `Mod1_IO:000100↔000000` 비트만 DO 17과 일치. +- → **DO 17(IO) 경로는 가이드빔 제어가 아님.** (메인 IO_Board와 레이저 가이드빔 입력은 별개) +- 현 상태: 원복하지 않고 **주석 토글로 필요시 전환**(도연님 운용). 기존 `_Laser` 코드는 주석 보존됨. + +## 2. 실제 경로 = Laser(TruPulse) 디바이스 + +레이저 타입 = **TruPulse** (`eLaserType.TruPulse`, `Laser.cs:70`). + +``` +_Laser.PilotLaserOn() (베이스 Laser, Laser.cs) + └ IsSimul 이면 return E1.OK (no-op) ← 현재 시뮬이라 여기서 멈춤 + └ 실모드: TruPulse.PilotLaserOn() (TruPulse.cs:817) + └ return PilotOnOffFunc(true) + └ (Laser.cs:74) core.PilotOnOffFunc = (on) => ExtPilotOnOff(on) + └ ExtPilotOnOff(true) ← ★ 레이저 IO 보드 write 의도 콜백 +``` + +상태 읽기: +``` +GetPilotLaserStatus() → PilotLaserEnable ← (TruPulse.cs:174) Di2 & (1<<9) + (QueryStatusHwInterface 로 TruPulse 컨트롤러에서 직접 읽음) +``` + +## 3. ★ 핵심 문제: `ExtPilotOnOff` 미구현(미할당) + +- `Laser.cs` 27~29줄에 `ExtLaserEnable` / `ExtLaserDisable` / `ExtPilotOnOff` **선언만** 존재. +- 전체 소스에 **`ExtPilotOnOff = ...` 할당부 없음**(검색 0건). `updateCore` 구독(`UCTruPulseManualViewModel`)도 core 참조만 받고 콜백 미주입. +- 결과: + - **시뮬(현재)**: 베이스에서 no-op → 빔 안 나옴, 상태 항상 true. (정상) + - **실모드**: `ExtPilotOnOff(true)` 호출 시 **null → NullReferenceException** 위험. +- → "레이저 IO 보드로 가이드빔 제어"는 **설계 의도이나 구현 미완(TODO)**. + +## 4. 결론 / TODO + +| 구간 | 상태 | +|------|------| +| 가이드빔 제어 의도 | TruPulse → `ExtPilotOnOff` → 레이저 IO 보드 DO | +| 실제 구현 | ❌ 미구현 (`ExtPilotOnOff` 미할당) | +| 현재 운영 | 시뮬 → no-op (물리 빔 안 나오는 게 정상) | +| 레시피 DO 17(`_IODevice`) 변경 | 잘못된 경로(메인 IO_Board), 원복 안 함 — 주석 토글로 운용 | + +추후 실제 가이드빔 구현 시: +- `_Laser.ExtPilotOnOff = (on) => { 레이저IO보드._iOUnit.WriteDoBit(<가이드빔 DO>, on); return 0; };` 구현 +- "레이저 IO 보드" 디바이스/DO 주소 확정 (메인 PAIX와 별개 여부) +- Laser 디바이스 **비시뮬 + Activated** diff --git a/docs/작업일지/2026_06_19.md b/docs/작업일지/2026_06_19.md index 171fc19..f1860ee 100644 --- a/docs/작업일지/2026_06_19.md +++ b/docs/작업일지/2026_06_19.md @@ -15,3 +15,126 @@ - `AuroraPLC_2pjacgrp_wpftmp.csproj`는 sln/csproj 어디에도 참조되지 않는 빌드 산출물 → 커밋 대상 아님 - 매번 git status에 안 뜨도록 `*_wpftmp.csproj` 무시 처리, push (3724007) - 그 외 정리: rules.md 규칙 5번 .md 영문 작성 요건 제거(3293455), PtoP PLC 인터페이스 xlsx(260617) 삭제(7cb6525) 커밋·push + +## 09:47 +- 어제 필드가 좁았던 부분 Scan Field size 변경하던 곳 위치 + - 프로그램상 Setting - SystemParameterILSOS - Scout 영역의 Scan field size (캔버스 영역 지정) + - 어제 그 레시피에서 캔버스 크기가 작았던 이슈 때문에 수정한 부분으로, 이 위치가 캔버스(Scan field) 크기를 수정하는 곳임 + +## 10:00 +- Recipe > Laser Shot > Laser Control - Guide Beam Status 의 Guide Beam 버튼 동작 소스 분석 + - **UI/바인딩**: `WeldingComponents/WeldingCommon/Views/Recipes/UCScannerObjectTeachingControlBox.xaml` + 의 Guide Beam 버튼 → ViewModel `CMD_LaserGuideBeam`(DelegateCommand) → `PerformCmdLaserGuideBeam()` 호출 + (ViewModel: 같은 폴더 `UCScannerObjectTeachingControlBoxViewModel.cs`) + - **버튼 핸들러(토글 동작)**: `PerformCmdLaserGuideBeam()` (456~463줄) + - `_Laser.GetPilotLaserSetBitStatus()` 가 false 면 `_Laser.PilotLaserOn()`, true 면 `_Laser.PilotLaserOff()` + - 즉 현재 파일럿(Guide) 레이저 set 비트 상태를 보고 ON/OFF 를 번갈아 보내는 토글 버튼 + - **디바이스 추상화**: `_Laser` 는 `AuroraDevices/AuroraLaser/Laser.cs` 의 베이스 `Laser` + (`DeviceManager[CommonDeviceIds.Laser]`). 베이스는 IsSimul 이면 OK, 미활성/null 이면 GENERIC(GuideBeam 미동작), + 아니면 내부 `ILaser` 구현체로 위임. 구체 타입은 `eLaserType` config 로 결정(ArmLaser/TruPulse/IPG_IO/Trumpf_IO 등) + - **실제 하드웨어 제어(예: IPG_IO `AuroraDevices/AuroraLaser/IPG/LaserIPG_IO.cs`)**: + - `PilotLaserOn()` → `SetLaserDOCommand(eADOAddress.GuideLaserEnable, true)` → IO보드 `WriteDoBit(GuideLaserEnable, true)` + - `PilotLaserOff()` → 같은 DO 비트를 false 로 Write → 가이드 빔 OFF + - **상태 표시(Guide Beam Status)**: ViewModel `OnMonitoring()` 타이머가 `_Laser.GetPilotLaserStatus()` 를 + 주기 폴링하여 `IsGuidBeam` 바인딩 갱신. IPG_IO 는 파일럿 DI 핀맵이 없어 `GuideLaserEnable` DO 상태를 그대로 읽어 표시 + - **주의**: `OnMonitoring()` 의 TODO 주석대로 일부 Laser 디바이스는 `GetPilotLaserStatus()` 미구현 → 항상 false. + 이 경우 버튼으로 DO 는 나가도 Status 표시는 갱신되지 않을 수 있음 + +## 10:21 — Guide Beam DO 주소 정합 (DO 3 → DO 17) 수정 및 현장 검증 대기 + +### 배경 / 문제 +- 현장에서 **가이드빔(적색광)이 안 나옴** → 원인 분석 결과 모니터링/제어가 보던 DO 비트가 실제 제어선과 불일치 +- 기존 소스: 버튼·모니터링 모두 `_Laser` 경로로 `eADOAddress.GuideLaserEnable`(Ajin enum = **raw 3**)을 사용 +- 현장 확인(도연님): 실제 **가이드빔 제어선은 DO 17(EX_Red_Control)**. **DO 3 은 PLC 인터페이스3 용**으로 가이드빔과 무관 +- DI 결선 없음 → 모니터링은 **DO(명령) 신호**를 그대로 표시하는 구조 + +### 분석 정리 +- 동작 체인: Guide Beam 버튼 → `CMD_LaserGuideBeam` → `PerformCmdLaserGuideBeam()` → (기존)`_Laser.PilotLaserOn/Off` + → IO Laser 는 `GuideLaserEnable`(raw 3) DO Write. 모니터링은 `OnMonitoring()` 타이머가 `GetPilotLaserStatus()`(raw 3 DO read) → `IsGuidBeam` +- `CommonDeviceIds.IODevice == "IO_Board"` (`EquipDefCommon.cs:115`) → ViewModel `_IODevice` 와 IO Laser 가 쓰는 보드 **동일**(PTOP=PAIX_PTOP) +- IO 기반 Laser(IPG_IO/TruPulse_IO/Trumpf_IO/Arm_IO)는 `GetPilotLaserStatus()` 구현되어 있음(미구현은 NL202/Rapid/YLPN/TrueDisk/TrumpfCore) +- 현장 Laser 타입 = **IO 기반** + +### 수정 내용 (커밋 보류 — 현장 검증 후 결정) +- 파일: `WeldingComponents/WeldingCommon/Views/Recipes/UCScannerObjectTeachingControlBoxViewModel.cs` +- `OnMonitoring()` (174~181줄): `_Laser.GetPilotLaserStatus()` → `_IODevice.ReadDO(17)` + IO 미연결 가드(미연결 시 false) +- `PerformCmdLaserGuideBeam()` (457~464줄): `_Laser.PilotLaserOn/Off` → `_IODevice` **DO 17 토글**(현재값 읽어 반전) +- 효과: 버튼이 쓰는 비트와 모니터링이 읽는 비트가 **동일 DO 17** → 버튼/직접 SetBit 어느 쪽으로 켜도 Status 동기화 +- 빌드 산출물: **WeldingCommon.dll** (현장 소스 덮어쓰기 시 재빌드 후 실행 폴더 반영 필요) + +### 현장 검증 체크리스트 +- [x] 현장 PC 에 수정 소스 덮어쓰기 후 WeldingCommon 재빌드 +- [x] `WeldingCommon.dll` 실행 폴더 반영 +- [x] Guide Beam 버튼 클릭 → 화면 Guide Beam Status 점등(ON) 확인 → **실패(변경 안 됨)** +- [ ] ~~Guide Beam 버튼 재클릭 → Status 소등(OFF) 확인~~ +- [x] DO 17 직접 SetBit → Status 동기화 확인 → **실패(모니터링이 DO 17 을 보는 것도 아님)** +- [x] **실제 가이드빔(적색광) 점등** 여부 확인 → **점등 안 됨** + +### 현장 검증 결과 (실패 → 원복) +- **결론: DO 17 은 가이드빔 제어선이 아님.** 버튼으로 변경도 안 되고, 모니터링이 DO 17 을 보는 것도 아니었음 +- 수정분(`UCScannerObjectTeachingControlBoxViewModel.cs` OnMonitoring/PerformCmdLaserGuideBeam) **`git checkout` 으로 원복** (커밋 안 한 상태였음) +- DO 3 / DO 17 모두 실제 가이드빔 제어선이 아닌 것으로 확인 → **실제 제어선 DO 주소 재확인 필요** + +### TODO / 후속 +- 현장 IO 인터페이스(결선)에서 **실제 가이드빔 제어 DO 주소** 재확인 (DO 3·17 아님) +- 주소 확정 후 동일 방식(버튼 write + 모니터링 read 동일 비트)으로 재시도 +- 추후 실제 점등 피드백 **DI 결선** 추가되면, 명령 DO 대신 피드백 DI 로 표시하도록 전환 검토 + +## 11:03 — TeachingRun 인터락 알람 분석 + 알람부 종합 분석 + +### TeachingRun 차단 원인 (현장 로그) +- `SeqComponentTeachingRun` 시작 시 `CheckCondition_Interlock()`의 `HasAlarmLevelHigh()`가 true → "Clear Heavy Alarms For Welding!" + 알람 202003 → FORCE_ERROR +- **원인 = 현장 PLC 미연결** → SeqAlarmMonitor가 PLC Deactivated/Disconnect(H) 알람 set → latch로 남아 인터락 +- 임시조치: `SeqComponentTeachingRun.cs` CheckCondition_Interlock()의 H알람 블록 **주석 처리(테스트용, 원복 예정)** → 레이저 출사 확인 완료 + +### 알람부 종합 분석 문서 작성 +- 문서: `docs/분석/2026/06/19/110333_alarm_subsystem_analysis.md` +- 내용: 클래스 구조, 핵심 메서드(set-once/시뮬우회/Unknown=H/Clear전체일괄), 생성·전파 흐름, 시퀀스별 알람 참조표, 알람 코드 표, 리스크 6종, SeqAlarmMonitor self-clearing 개선안 +- 핵심 리스크: **알람 latch(조건 해소 시 자동 Clear 없음)** → PLC 재연결돼도 수동 ClearAll 전까지 인터락 지속 + +### TODO / 후속 +- 현장 **MX Component 연결 설정** 후 PLC 연결 → 중알람 자연 해소 여부 확인 (별도 분석 진행 중) +- 알람 인터락 블록 **원복** (현장 PLC 정상화 후) +- `SeqAlarmMonitor` self-clearing 개선 검토 (AlarmManager 공통 수정 → 승인 필요) + +## 11:13 — MX Component PLC 연결 설정 분석 + +- 문서: `docs/분석/2026/06/19/111326_mxcomponent_plc_connection_analysis.md` +- 핵심: 연결 = **논리국번(Logical Station Number)** 1개로 결정 + - PC의 **MX Component Communication Setup Utility** 에 등록한 논리국번 ↔ 소스 `_config_device/PLC.json` 의 `ConnConfig.StationNumber`(기본 1, Gun 예시 22) **일치 필요** + - 드라이버: `AuroraMXComponent/MXComponent.cs` → `ActUtlType64Class.ActLogicalStationNumber` 설정 후 Open +- PLC측 요청: CPU 기종 / 접속방식(CPU내장이더넷·이더넷모듈·CC-Link IE 등) / **IP·포트** / MELSOFT 접속 허용 +- 메모리맵 CSV 8종(`External/PLC/PLC_DeviceMap_*.csv`)은 연결과 별개지만 데이터 정합 필요 — PTOP는 repo에 없음(현장 전용) +- 연결되면 PLC 미연결 중알람 해소 → 단 latch라 **ClearAll 1회** 필요할 수 있음 + +## 12:22 — AjinIO.ReadDoBit(int) 미구현 분석 (스텁 유지 결정) + +- 파일: `AuroraDevices/AuroraIO/Vendor/AJINEXTEK/AjinIO.cs` `ReadDoBit(int index)` (496줄~) +- 현황: bool 반환 `ReadDoBit(int)`만 미구현 스텁(`return true`). DO 읽기 API(`AxdoReadOutport`)는 같은 파일 469줄·GetDoArray에서 이미 검증됨 +- 스텁 의존 호출처: `UCInformationPanelViewModel.cs` 5곳(ModeKeySolOn/SafetyDoorRelease 상태표시) — **전부 ePDOAddress(PAIX) → PAIX 보드 실행, PAIX는 정상 구현** → Ajin 스텁 실제 의존 코드 사실상 없음 +- **결정: 스텁(`return true`) 유지 + 구현(ReadDiBit 패턴)은 주석으로 보존** → 동작 변화 없음(현장 안전), 추후 활성화 용이 +- 빌드 산출물: **AuroraIO.dll** +- 분석 문서: `docs/분석/2026/06/19/122201_ajinio_readdobit_analysis.md` + +## 12:47 — 가이드빔 제어 경로 추적 (IO → Laser/TruPulse) 및 미구현 확인 + +### 진행 경위 +- 레시피 Guide Beam 을 `_IODevice` **DO 17(EX_Red_Control)** read/write 로 수정 → 상태표시(읽기)는 동작, **물리 빔은 안 나옴** +- 번들(DBW-MC) `RedLight Opened/Closed` 이벤트는 **번들 RedClosed 버튼 수동조작** 결과, DO 17과 무관 (Mod1_IO 비트만 일치) +- → **DO 17(IO) 경로는 가이드빔 제어가 아님.** 레이저 타입 = **TruPulse** + +### 핵심 발견 (TruPulse 가이드빔 미구현) +- 경로: `_Laser.PilotLaserOn()` → (TruPulse)`PilotOnOffFunc` → `ExtPilotOnOff` (레이저 IO 보드 write 의도) +- 상태: `GetPilotLaserStatus()` → `PilotLaserEnable` ← TruPulse `Di2 bit9` +- **`ExtPilotOnOff`/`ExtLaserEnable`/`ExtLaserDisable` 가 선언만 되고 할당부 없음(미구현 TODO)** + - 시뮬(현재): 베이스 no-op → 빔 안 나옴(정상) / 실모드: null → NRE 위험 +- 현재 Laser 디바이스 = **시뮬레이션**, 제어는 레이저 IO 보드로 한다고 함 + +### 처리 / 결정 +- 레시피 DO 17 변경분 **원복 안 함** — 필요 시 도연님이 주석 토글로 운용 (기존 `_Laser` 코드 주석 보존됨) +- IO 미연결 가드(`IsConnected`)는 현장PC에서 동작 안 해 주석(개발PC에서 해제) — LaserReady 패턴과 동일 +- 분석 문서: `docs/분석/2026/06/19/124752_guidebeam_trupulse_analysis.md` + +### 금일 작업 정리 (커밋 대상) +- 코드(미커밋): `AjinIO.cs`(ReadDoBit 스텁 유지+구현 주석), `SeqComponentTeachingRun.cs`(중알람 인터락 임시 주석), `UCScannerObjectTeachingControlBoxViewModel.cs`(Guide Beam DO 17 + 가드 주석) +- 분석 문서 4종: 알람부 / MX Component / AjinIO ReadDoBit / 가이드빔 TruPulse