LGES-OC5-PtoP-Welder/docs/PLC_RecipeChange_구현_수정가이드.md
NohDoyeon241104 42c5565249 feat: PLC Recipe Change 핸드셰이크 구현 (SeqAutoRunPTOP) + 주소 정합
근거: 가이드 + Excel 260618(빨간셀 M70509/M70009/D70502/D70002). Page Change 미러링.
- 주소 enum: PLC_RECIPE_CHANGE_REQ(0x09)/PC_RECIPE_CHANGE_COMPLETE(0x09)/
  PLC_RECIPE_NO(idx2)/PC_RECIPE_NO(idx2). 공용 eCommonBitOutput 동기화.
  충돌: SeqStatusMonitor RMS_USED 읽기 주석, SeqAutoRunPrismatic 참조 이름만 교체.
- 시퀀스: CheckRecipeNo(논블로킹 Decision) + CheckRecipeNoComp(.Id 1:1 조회/활성화/
  반영폴링/에코·완료비트), Builder 흐름·엣지·루프백, 리셋 비트·워드, _RecipeManager Enter 확보.
- Page 검증 상한 하드코딩 제거 → 활성 Recipe Layers.Count() 가변.
- (별도) D:\ILSOSConfig\...\External\PLC CSV 디바이스맵 4종 라벨 정합(.bak260618 백업).

빌드는 VS Rebuild로 검증 필요(레거시 포함). STEP5 UI/PLC 사양 최종정합은 후속.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-18 15:31:43 +09:00

227 lines
19 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# PLC Recipe Change 인터페이스 구현 — 수정 가이드
> 작성일: 2026-06-18
> 대상 시퀀스: **ILSOS_PrismaticRD_PTOP / SeqAutoRunPTOP** (현재 활성 AutoRun)
> 근거 문서: `Doc/유니셀 PtoP 단동기 Laser Interface_260618.xlsx` (시트 `M70K`, `D70K`, `Recipe Number`)
> 이 문서는 **다른 agent가 읽고 직접 구현**하기 위한 구현 명세서다. 분석은 끝났고, 아래 절차대로 코드를 추가하면 된다.
> 기존 **Page Change** 핸드셰이크를 그대로 본떠서 **Recipe Change** 핸드셰이크를 추가하는 것이 목표다.
---
## 1. 목표
PLC가 **Recipe 변경을 요청**하면, PC(Laser SW)가 해당 Recipe를 활성화하고 완료를 응답하는 **비트/워드 핸드셰이크**를 추가한다.
구조는 기존 Page Change와 동일하며, **Recipe가 상위 개념, Page가 하위 개념**이다 (Recipe 1개 = Page 여러 개).
핵심 원칙:
- 신규 코드는 **기존 Page Change 노드(`CheckPageNo` / `CheckPageNoComp`)를 미러링**한다.
- **런타임 실행** 시퀀스는 **`SeqAutoRunPTOP`** 하나뿐이다 (시작 근거: `UCMainAutoRunViewModel.cs:243`, 등록 `EquipmentSetup.cs:214`).
- ⚠️ 단, `SeqAutoRunPrismatic`는 **빌드 대상이다**: `EquipmentSetup.cs:202`에서 `.Builder()`가 호출되고 `:207`에서 `SequenceIds.SeqAutoRun`으로 **등록**되어 있다(다만 `.Start()`는 호출 안 됨 → 런타임 미실행). `SeqAutoRunComponentWeld`도 `:203`에서 빌드된다. 즉 **"미사용=미실행"이지 "미컴파일"이 아니다.** enum rename(충돌 ②) 시 이들이 깨질 수 있으니 STEP 1·3절을 반드시 확인.
---
## 2. 인터페이스 사양 (Excel 260618 기준)
> **출처/변경 표기**: 엑셀에는 변경이력 시트·셀 코멘트가 없고, 이번 개정의 신규 주소는 **빨간 글씨(font FFFF0000)** 로만 표시돼 있다. 워크북 전체 빨간 셀은 **5개**: `Recipe_CHGRequest`(M70509), `Recipe_CHGComplete`(M70009), `PLC_RecipeNo`(D70502), `PC_Recipe No`(D70002) — 본 문서가 다루는 4개 — 과 **별개 1개 `Head_Theta_Position`(D70510, Recipe 무관, 본 문서 범위 외)**. 즉 아래 표의 "신규" 항목은 모두 엑셀 빨간 글씨 근거.
### 2-1. 비트 핸드셰이크 — Page 대비 **오프셋 +1**
| 신호 | 방향 | M-Device | enum / 오프셋 | 비고 |
|---|---|---|---|---|
| `Page_CHGRequest` (기존) | PLC→PC (Input) | M70508 | `eBitInput.PLC_PAGE_CHANGE_REQ = 0x08` | 참고용 |
| **`Recipe_CHGRequest` (신규)** | **PLC→PC (Input)** | **M70509** | **0x09** | ⚠️ **충돌**: 현재 `PLC_RMS_USED = 0x09` |
| `Page_CHGComplete` (기존) | PC→PLC (Output) | M70008 | `eBitOutput.PC_PAGE_CHANGE_COMPLETE = 0x08` | 참고용 |
| **`Recipe_CHGComplete` (신규)** | **PC→PLC (Output)** | **M70009** | **0x09** | 현재 `PC_EMPTY01 = 0x09` (미사용, 안전) |
### 2-2. 워드 — Page 대비 **인덱스 +1**
| 신호 | 방향 | D-Device | enum index | 비고 |
|---|---|---|---|---|
| `PLC_PageNo` (기존) | PLC→PC (Input) | D70501 | `eWordInput.PLC_PAGE_NO = 1` | 참고용 |
| **`PLC_RecipeNo` (신규)** | **PLC→PC (Input)** | **D70502** | **index 2** | ⚠️ **충돌**: 현재 `PLC_STEP_NO`(index 2) |
| `PC_PageNo` (기존) | PC→PLC (Output) | D70001 | `eWordOutput.PC_PAGE_NO = 1` | 참고용 |
| **`PC_RecipeNo` (신규)** | **PC→PLC (Output)** | **D70002** | **index 2** | 현재 `EMPTY_02`(index 2) (미사용, 안전) |
> 주소 베이스: `eBitInput`=M70500, `eBitOutput`=M70000, `eWordInput`=D70500, `eWordOutput`=D70000.
> (⚠️ 베이스 절대주소 자체는 enum 코드가 아니라 외부 device-map/mmap 설정에서 온다 → 본 표의 오프셋 산술은 Excel·디바이스맵 기준이며 코드만으로는 베이스 검증 불가.)
> 정의 위치: `Machines/ILSOS_PrismaticRD_PTOP/Device/PLC/PLCController.Address.cs`
> (eBitInput L13–47, eBitOutput L49–78, eWordInput L80–146, eWordOutput L148–214)
### 2-3. Recipe Number ↔ Page 매핑 (`Recipe Number` 시트)
| Recipe No | Page 수 | 용접부 |
|---|---|---|
| 11 | 1, 2 | 양극 탭 비드 용접 / 음극 탭 비드 용접 |
| 21 | 1 ~ 5 | 전면 용접 |
| 22 | 1 ~ 5 | 후면 용접 |
| 31 | 1, 2 | 상면 용접 |
| 32 | 1, 2 | 하면 용접 |
> **중요**: Recipe No는 `11/21/22/31/32` 로 **불연속**이며, Recipe마다 **Page 수가 2~5개로 다르다**(파일 갱신으로 21/22가 4→5페이지). 특정 상한을 절대 하드코딩하지 말 것.
> 따라서 기존 `CheckPageNoComp`의 하드코딩 검증 `plcPageNo > 2 || plcPageNo < 1`(`SeqAutoRunPTOP.cs:370`)은 **Recipe별 Page 수에 따라 가변**으로 바꿔야 한다. (STEP 6 참고)
---
## 3. ⚠️ 주소 충돌 — 구현 전 반드시 확인할 것
### 충돌 ① `PLC_RMS_USED = 0x09` (eBitInput) — **현재 사용 중**
- 사용처: `Sequences/Monitoring/SeqStatusMonitor.cs:106`
```csharp
Status.RMSUse = _plc.ReadBit(PLCControllerPTOP.eBitInput.PLC_RMS_USED).data;
```
- Excel 260618은 M70509(=0x09)를 `Recipe_CHGRequest`로 재정의함.
- **즉 동일 비트(0x09)가 RMS_USED 상태와 Recipe 변경 요청으로 충돌한다.**
- **결정 필요(PLC 담당자 확인)**: RMS_USED 비트를 폐기/이설하고 0x09를 Recipe_CHGRequest로 넘길 것인지. → 4절 "미해결 질문" 참조.
### 충돌 ② `PLC_STEP_NO` (eWordInput index 2) — **레거시에서 컴파일됨**
- 사용처: `Sequences/SeqAutoRunPrismatic.cs:414`
- 활성 `SeqAutoRunPTOP`는 PLC_STEP_NO를 쓰지 않으나, `SeqAutoRunPrismatic`는 **등록·빌드 대상**(`EquipmentSetup.cs:202,207`)이다.
- ⚠️ **빌드 영향**: `PLC_STEP_NO` → `PLC_RECIPE_NO`로 **이름만 바꾸면 `:414`가 컴파일 에러**가 난다.
- **결정 필요(택1)**:
- (a) `:414`도 같이 정리(레거시 수정 허용 시) — 6절 "레거시 미수정" 원칙과 충돌하므로 사용자 승인 필요, **또는**
- (b) `PLC_STEP_NO`(index 2)는 **그대로 두고**, Recipe용으로 **별도 신규 멤버를 추가**(단, eWordInput은 암묵 순번이라 index 2를 두 이름이 가질 수 없음 → 명시값 부여 `PLC_RECIPE_NO = 2`로 두되 `PLC_STEP_NO`도 `= 2`로 명시해 공존시키거나, PLC_STEP_NO를 의미상 PLC_RECIPE_NO로 **rename + :414 동시 수정**).
→ 결국 index 2 한 칸을 누가 쓰느냐의 문제이므로 **(a) rename + :414 동시 수정**이 가장 깔끔. STEP 1에서 확정.
### 안전 (그대로 rename 가능)
- `PC_EMPTY01 = 0x09` (eBitOutput): 참조 없음 → `PC_RECIPE_CHANGE_COMPLETE`로 교체 안전.
- `EMPTY_02` (eWordOutput index 2): 참조 없음 → `PC_RECIPE_NO`로 교체 안전.
### ⚠️ enum 이중 정의 (Recipe 완료 비트 구현에 직접 영향)
- `PC_PAGE_CHANGE_COMPLETE`는 **두 곳에 0x08로 중복 정의**되어 있고 코드가 혼용한다:
- PTOP: `Device/PLC/PLCController.Address.cs` `eBitOutput.PC_PAGE_CHANGE_COMPLETE = 0x08`
- 공용: `WeldingComponents/WeldingCommon/Devices/PLC/PLCController.Address.cs` `eCommonBitOutput.PC_PAGE_CHANGE_COMPLETE = 0x08`
- 사용처가 갈린다: `RestoreDeviceStatus`(`SeqAutoRunPTOP.cs:803`)는 **`eCommonBitOutput`**, `OnSeqActionStop`(`:977`)은 **`eBitOutput`** 사용.
- **즉 신규 `PC_RECIPE_CHANGE_COMPLETE`를 PTOP `eBitOutput`에만 추가하면 `RestoreDeviceStatus`(common 경로)에서 못 쓴다.** → STEP 1에서 **양쪽 enum 동기화** 또는 캐스팅 통일 필요(STEP 4 참조).
---
## 4. 확정된 설계 결정 (2026-06-18, 사용자 협의)
| # | 결정 사항 | 채택안 | 비고 |
|---|---|---|---|
| 1 | **시퀀스 흐름/배치** | **매 사이클 Page 앞에서 확인** | `CheckInitCondition → CheckRecipeNo → CheckRecipeNoComp → CheckPageNo …`. 루프백(CheckCycleStop)은 **CheckRecipeNo로** 회귀. |
| 2 | **CheckRecipeNo 동작** | **논블로킹 peek** | Page와 달리 REQ ON까지 무한대기 ❌. REQ OFF면 현 Recipe 유지하고 즉시 Page로 통과. |
| 3 | **핸드셰이크 형태** | **기존 Page 미러형(B)** | `CheckPageNoComp` 방식 그대로. COMPLETE 비트만 처리, REQ-OFF 대기 없음(일관성 우선). |
| 4 | **RecipeNo→레시피 매핑** | **`.Id` 직접 1:1** | `Recipes().FirstOrDefault(x => x.Id == plcRecipeNo)` → 없으면 알람 → `ActivateRecipe(recipe.Id, "PLC Recipe Change")`. 선례: `RMSHandlerForPTOP.cs:125-173`. |
| 5 | **비트 0x09 충돌(①)** | **RMS_USED 폐기 → Recipe 전환** | `PLC_RMS_USED`→`PLC_RECIPE_CHANGE_REQ`. `SeqStatusMonitor.cs:106` RMSUse 읽기 제거/주석. RMS 핸들러 이미 비활성(`EquipmentSetup.cs:92-94`)이라 기능 영향 없음. |
| 6 | **Page 수 가변(2~5)** | **런타임 동적 산출** | 상한 하드코딩 금지. `Models.Layers.Count()` 또는 활성 Recipe 메타 기준(STEP 6). |
| 7 | **워드 idx 2 충돌(②)** | **rename + 레거시 :414 동시 수정** | `PLC_STEP_NO`→`PLC_RECIPE_NO` rename, `SeqAutoRunPrismatic.cs:414`의 참조도 **이름만** 교체(로직 불변). 사용자 승인 완료. |
### 사양 전제 (PLC 담당자와 정합성 확인 권장, 코드 결정 아님)
- PLC가 보내는 RecipeNo가 실제 등록 레시피의 `.Id`(`11/21/22/31/32`)와 일치한다는 전제. 불일치 시 결정 4를 매핑 테이블로 보강.
> ⚠️ 참고 — **기존 활성 Page Change 핸드셰이크는 미완결**이다. `CheckPageNoComp`(`SeqAutoRunPTOP.cs:408`)는 `PC_PAGE_CHANGE_COMPLETE`를 **false로만** 쓴다. 결정 3(미러형)에 따라 Recipe도 이 방식을 **그대로** 본뜬다(향후 Page 핸드셰이크가 보정되면 Recipe도 동일하게 따라간다).
---
## 5. 수정 절차
### STEP 1 — 주소 enum 추가
파일: `Machines/ILSOS_PrismaticRD_PTOP/Device/PLC/PLCController.Address.cs`
- `eBitInput`: `PLC_RMS_USED = 0x09` → **`PLC_RECIPE_CHANGE_REQ = 0x09`** 로 rename (결정 5). 동시에 `SeqStatusMonitor.cs:106`의 `Status.RMSUse = _plc.ReadBit(...PLC_RMS_USED)` 줄을 **제거 또는 주석** 처리(`Status.RMSUse`는 write-only·소비처 0건이라 안전).
- ⚠️ 공용 `WeldingCommon/Devices/PLC/PLCController.Address.cs`의 `eCommonBitInput.PLC_RMS_USED = 0x09`는 **별도 enum이며 참조 0건** → 빌드 영향 없음. 이름 일관성을 원하면 동반 rename(선택).
- `eBitOutput`: `PC_EMPTY01 = 0x09` → `PC_RECIPE_CHANGE_COMPLETE = 0x09` 로 교체.
- `eWordInput`: index 2(충돌 ②, 결정 7) `PLC_STEP_NO` → `PLC_RECIPE_NO` rename + **`SeqAutoRunPrismatic.cs:414`의 참조도 이름만 교체**(로직 불변, 승인 완료).
- `eWordOutput`: `EMPTY_02` → `PC_RECIPE_NO` 로 교체.
- **공용 enum 동기화(필수)**: 위 PTOP enum과 동일하게 `WeldingCommon/Devices/PLC/PLCController.Address.cs`의 `eCommonBitOutput` 0x09 자리에도 `PC_RECIPE_CHANGE_COMPLETE = 0x09`를 추가한다. (STEP 4의 `RestoreDeviceStatus`가 `eCommonBitOutput`을 쓰기 때문.) — §3 "enum 이중 정의" 참조.
> enum은 **암묵적 순번**(eWordInput/eWordOutput)이라 멤버 **이름만** 바꾸면 인덱스는 유지된다. 새 값을 끼워 넣어 뒤 순번이 밀리지 않도록 **이름 교체** 방식으로 처리할 것.
> ⚠️ index 2는 한 칸뿐이라 `PLC_STEP_NO`와 `PLC_RECIPE_NO`가 공존할 수 없다 → rename 단일화가 원칙(충돌 ② 참조).
### STEP 2 — Recipe Change 시퀀스 노드 추가
파일: `Machines/ILSOS_PrismaticRD_PTOP/Sequences/SeqAutoRunPTOP.cs`
기존 `CheckPageNo`(L277) / `CheckPageNoComp`(L331)를 본떠 **`CheckRecipeNo` / `CheckRecipeNoComp`** 추가. (결정 1~5 반영)
- **`CheckRecipeNo` (논블로킹 peek — 결정 2)**: `_PLC.ReadBit(eBitInput.PLC_RECIPE_CHANGE_REQ)`를 **1회 확인**.
- REQ **OFF** → Recipe 변경 없음. **즉시 `CheckPageNo`로 통과**(현 Recipe 유지). ⚠️ `CheckPageNo`처럼 ON까지 무한대기하지 **말 것.**
- REQ **ON** → `CheckRecipeNoComp`로 진행.
- **분기는 Decision 노드로 구현**(결정 2 확정) — STEP 3 참고.
- **`CheckRecipeNoComp`**:
1. `_PLC.ReadWord(eWordInput.PLC_RECIPE_NO)` 읽기 (필요 시 `CheckPageNoComp`의 3회 적재 패턴 재사용).
2. **레시피 조회/매핑 (결정 4 — `.Id` 직접 1:1)**:
```csharp
var recipe = AuroraEnv.RecipeManager /* 또는 _recipeEntry */
.Recipes().FirstOrDefault(x => x.Id == plcRecipeNo);
if (recipe == null) { /* "{plcRecipeNo}번 레시피 없음" 알람 */ return null; }
```
- 선례 그대로: `RMSHandlerForPTOP.cs:125-130`(조회/없음 알람), `:173`(활성화).
3. **Recipe 활성화**: `RecipeManager.ActivateRecipe(recipe.Id, "PLC Recipe Change")`
- 현재값 조회: `RecipeManager.ActivatedRecipe().Id`.
- ⚠️ **반영 확인 필수(비동기 race 주의)**: `ActivateRecipe`는 `EVENT_CHANGE_RECIPE_INFO` 이벤트 체인으로 반영되며, RMS 선례(`RMSHandlerForPTOP.cs:134,145`)는 `Dispatcher.Invoke`로 UI스레드에서 Reload/Save한다. 본 시퀀스는 **워커 스레드**이므로, 활성화 직후 `ActivatedRecipe().Id == recipe.Id` 가 될 때까지 **폴링/대기**한 뒤 다음(PageNo)으로 진행할 것. 누락 시 직후 Page 검증이 **이전 레시피 기준**으로 돌 위험.
4. `_PLC.WriteWord(eWordOutput.PC_RECIPE_NO, plcRecipeNo)` 에코.
5. **핸드셰이크 응답 (결정 3 — 기존 Page 미러형)**: `CheckPageNoComp`(`:401-409`)의 COMPLETE 비트 처리 방식을 **그대로** 본떠 `PC_RECIPE_CHANGE_COMPLETE` 처리. **REQ-OFF 대기 단계는 두지 않는다**(현 Page와 동일).
6. (선택) UI 알림: `EVENT_AUTO_RUN_UPDATE_PAGENUM` 패턴 본떠 Recipe 표시 이벤트 publish (STEP 5).
### STEP 3 — 상태머신에 노드 연결
같은 파일 `Builder()` (L114–171). 현재 흐름(L142–163):
```
ENTER → CheckInitCondition → CheckPageNo → CheckPageNoComp → (UploadWeldingList) → ... → CheckCycleStop ─(loop)→ CheckPageNo
```
Recipe는 Page의 상위이므로 **`CheckPageNo` 앞에** 삽입 (결정 1):
```
... CheckInitCondition → CheckRecipeNo → CheckRecipeNoComp → CheckPageNo → CheckPageNoComp → ...
```
- `sb.AddAction(SEQ_CHECK_RECIPENO, CheckRecipeNo);`
- `sb.AddAction(SEQ_CHECK_RECIPENO_COMPLETE, CheckRecipeNoComp);`
- 본 흐름(`Builder()` L142-161)에 두 노드를 `CheckInitCondition`과 `CheckPageNo` 사이에 끼움.
- **분기(결정 2 논블로킹)**: `CheckRecipeNo`를 **Decision 노드(`sb.AddDecision`)**로 만들어 `REQ ON → SEQ_CHECK_RECIPENO_COMPLETE`, `REQ OFF → SEQ_CHECK_PAGENO` 문자열을 반환 분기(Decision은 다음 노드 id 문자열을 반환 — `CheckInitCondition` `:259,269,273` 패턴).
- ⚠️ **엣지 선언 필수**: Decision의 반환 타깃이 유효하려면 두 분기 엣지가 그래프에 모두 존재해야 한다. 메인 Flows에 ON 경로(`CheckRecipeNo > CheckRecipeNoComp > CheckPageNo`)를 넣고, OFF 경로는 **별도로** `sb.Flows(sb[SEQ_CHECK_RECIPENO] > sb[SEQ_CHECK_PAGENO]);` 를 추가 선언할 것(선례: `CheckCycleStop`의 대체 분기 `:163`, `CheckInitCondition`의 `:164`).
- **루프백 변경**: 현재 `sb.Flows(sb[SEQ_CHECK_CYCLE_STOP] > sb[SEQ_CHECK_PAGENO]);`(L163)을 **`> sb[SEQ_CHECK_RECIPENO]`** 로 바꿔, 다음 사이클마다 Recipe부터 재확인.
### STEP 4 — 리셋/정지 시 비트 초기화
같은 파일:
- `RestoreDeviceStatus()` (L799~803): 이 메서드는 **`eCommonBitOutput`** 을 쓴다(`:803`). 따라서 `eCommonBitOutput.PC_RECIPE_CHANGE_COMPLETE` false 를 추가 — **STEP 1에서 공용 enum에 멤버를 추가했어야 컴파일된다.** (안 했으면 여기서 빌드 에러)
- `OnSeqActionStop` 계열(L977 비트, L981-982 워드, PC_PAGE 초기화 지점): 이쪽은 **`eBitOutput`/`eWordOutput`(PTOP)** 사용. `PC_RECIPE_CHANGE_COMPLETE` false, `PC_RECIPE_NO` 0 추가.
- ⚠️ 두 지점이 서로 다른 enum(common vs ptop)을 쓰므로, **사용하는 enum을 지점별로 맞출 것**(혼동 시 컴파일 에러).
### STEP 5 — (선택) UI 표시
Recipe 번호를 UI에 노출하려면 `Views/Main/UCMainAutoRunViewModel.cs`의 `CurrentPageNum`(L71-72) 패턴을 본떠 `CurrentRecipeNo` 속성 + 이벤트 구독 추가.
### STEP 6 — Page 검증 Recipe-aware 화
`CheckPageNoComp`의 페이지 범위 검증 `plcPageNo > 2 || plcPageNo < 1`(`SeqAutoRunPTOP.cs:370`)을 **활성 Recipe의 Page 수**(질문 5)에 따른 상한으로 교체.
- ⚠️ 이 검증은 **3회 폴링 게이트 `if (checknum > 2)`(`:368`) 안**에 있다. 상한만 바꾸고 `checknum > 2` 누적 폴링 구조(`plcPageNoList` 3회 적재)는 그대로 유지할 것.
- Page 수 출처 후보: 활성 Recipe 메타, 또는 `Models.Layers.Count()`(레이어 수). Recipe 21/22는 5페이지, 11/31/32는 2페이지(2-3절 표) — **상한 하드코딩 금지, 런타임 동적 산출.**
---
## 6. 변경 대상 파일 요약
| 파일 | 변경 |
|---|---|
| `ILSOS_PrismaticRD_PTOP/Device/PLC/PLCController.Address.cs` | PTOP enum 4종에 Recipe 신호 추가/교체 (STEP 1) |
| `WeldingCommon/Devices/PLC/PLCController.Address.cs` | `eCommonBitOutput`에 `PC_RECIPE_CHANGE_COMPLETE=0x09` 동기화 (STEP 1·4) |
| `Sequences/SeqAutoRunPTOP.cs` | 노드 2개 추가, Builder 흐름, 리셋, Page 검증 (STEP 2·3·4·6) |
| `Views/Main/UCMainAutoRunViewModel.cs` | (선택) Recipe 표시 (STEP 5) |
| `Sequences/Monitoring/SeqStatusMonitor.cs` | 충돌 ① 처리 시 RMS_USED 참조 정리 |
| `Sequences/SeqAutoRunPrismatic.cs` | 충돌 ②(결정 7): `:414` PLC_STEP_NO → PLC_RECIPE_NO 이름만 교체 (로직 불변, 승인 완료) |
> **런타임 미실행이지만 빌드 대상**인 레거시(`SeqAutoRunPrismatic.cs`, `SeqAutoRunComponentWeld.cs`)는 enum rename 영향이 미친다 — 컴파일 통과를 위해 필요한 최소 수정만 하되, 로직 변경은 하지 말 것.
> **완전 미참여 파일**(`SeqWaitWeldOrChangePage.cs`, `SeqTestRun.cs`)은 참고만 하고 수정하지 않는다.
---
## 7. 검증 체크리스트
- [ ] STEP 1 enum 인덱스가 밀리지 않았는가 (이름 교체 방식 확인).
- [ ] 충돌 ①(RMS_USED) / 충돌 ②(STEP_NO) 처리 방침이 확정·반영되었는가.
- [ ] `recipeNo` 유효값 `{11,21,22,31,32}` 외 입력 시 알람/중단 처리.
- [ ] `ActivateRecipe` 호출 후 실제 레시피가 바뀌고 `ActivatedRecipe().Id`가 일치하는가.
- [ ] 핸드셰이크: REQ ON → (work) → COMPLETE 응답 → REQ OFF → COMPLETE 해제 순서가 PLC 사양과 맞는가.
- [ ] 정지/리셋 시 `PC_RECIPE_CHANGE_COMPLETE`, `PC_RECIPE_NO` 초기화.
- [ ] Recipe별 Page 수 가변 검증(STEP 6)이 11/21/22/31/32 모두에서 동작.
- [ ] 솔루션 빌드 통과(레거시 포함). 빌드 실패를 경고로 넘기지 말 것.
---
## 8. 핵심 참고 코드 위치 (active path)
- 상태머신: `SeqAutoRunPTOP.Builder()` — `SeqAutoRunPTOP.cs:114-171` (흐름 L142-163)
- Page REQ 대기: `CheckPageNo` — `SeqAutoRunPTOP.cs:277-328`
- Page 확정/에코: `CheckPageNoComp` — `SeqAutoRunPTOP.cs:331-422`
- 리셋: `RestoreDeviceStatus` — `SeqAutoRunPTOP.cs:799+` / `OnSeqActionStop` 인근 L976-981
- 주소맵: `Device/PLC/PLCController.Address.cs`
- Recipe 활성화 API: `Recipes/RMSHandlerForPTOP.cs:173` (`RecipeManager.ActivateRecipe`), 조회 `:125-130`
- 레거시 완전형 핸드셰이크(참고): `Sequences/SeqWaitWeldOrChangePage.cs:251-318`