# 작업지시서 — Recipe & Page Change 소스 수정 및 적용 테스트 - 작성일: 2026-06-20 (명일 2026-06-21 작업용) - 대상: `Machines/ILSOS_PrismaticRD_PTOP/Sequences/SeqAutoRunPTOP.cs` - 근거 분석: `docs/분석/2026/06/20/191351_recipe_page_통합신호_핸드셰이크_재구성_분석.md` (8장 = 확정안) - 관련: `132647_uframe_가접_recipe_추가_seqautorun_분석.md`, `133714_recipe전환시_scout필드_이전레시피_잔존_분석.md` - 현재 상태: **소스 미수정** (분석/프리뷰만 존재). 본 지시서대로 구현 착수. > 목적: 현장 PLC가 Recipe·Page 신호를 **동시에** 주는 환경에 맞춰, 비대칭 4노드 핸드셰이크를 > **단일 PAGE 게이트 1노드**로 통합한다. + 매 사이클 조건부 레시피 활성화 + Layers stale(race) 방지. --- ## 0. 착수 전 확정 사항 (PLC 담당/현장과 먼저 합의) > 아래 3개는 **코딩 시작 전에 값이 확정돼야** 한다. 미확정이면 해당 부분 TODO로 두고 진행. - [ ] **C-1. PC_PAGE_CHANGE_COMPLETE 극성**: 현재 코드 관례는 `false` write. PLC 기대값(active-high/low) 확인. - [ ] **C-2. 레시피 COMP 비트 불필요 확정**: PC_RECIPE_NO 워드 에코만으로 PLC가 만족하는가(레시피 전용 COMPLETE 비트 폐기 OK?). - [ ] **C-3. Layers race 대응안 택1**: (A) Dispatcher 동기 ReloadRecipe(**권장**) / (B) 로드완료 신호 폴링 / (C) DataModel 레시피Id 키. --- ## 1. 작업 범위 (Scope) ### 1-1. 변경 대상 파일 - `Machines/ILSOS_PrismaticRD_PTOP/Sequences/SeqAutoRunPTOP.cs` (메인) - (대응안 A 선택 시) 시퀀스에서 `RecipeHelper.ReloadRecipe` 동기 호출 경로 확인 — `WeldingComponents/.../RecipeHelper.cs`, `MainPage.cs`는 **읽기만**(수정 지양). ### 1-2. 제거 (통합으로 흡수) - 노드 4개: `CheckRecipeNo`, `CheckRecipeNoComp`, `CheckPageNo`, `CheckPageNoComp` - 상수 4개: `SEQ_CHECK_RECIPENO`, `SEQ_CHECK_RECIPENO_COMPLETE`, `SEQ_CHECK_PAGENO`, `SEQ_CHECK_PAGENO_COMPLETE` - Flow 2줄: `CheckRecipeNo→CheckPageNo`(REQ OFF 우회), 루프백 `CheckCycleStop→CheckRecipeNo` ### 1-3. 추가 - 노드 1개: `CheckPageHandshake` (+ 상수 `SEQ_CHECK_PAGE_HANDSHAKE`) - 필드: `private short _prevRecipeNo = -1;` - 헬퍼: `ReadWordVerified(eWordInput, times)`(3회 검증 공통화), `EnsureLayersReloaded(recipe)`(대응안 A) - Flow: `... > CheckInitCondition > CheckPageHandshake > SetUploadWeldingList...`, 루프백 `CheckCycleStop > CheckPageHandshake` --- ## 2. 구현 절차 (Step) ### Step 1. 단일 핸드셰이크 노드 골격 - `CheckPageHandshake` 추가. 동작 순서: 1. `PLC_PAGE_CHANGE_REQ`(0x08) ON 블로킹 대기 (기존 `CheckPageNo` 패턴 재사용, RECIPE_REQ 미감시) 2. `PLC_RECIPE_NO`, `PLC_PAGE_NO` 각 3회 더블체크 → `plcRecipeNo`, `plcPageNo`, `_CurrentPageNo = plcPageNo - 1` 3. CellId/LotId 읽어 Status 반영 (기존 `CheckPageNoComp` 로직 이식) ### Step 2. 조건부 레시피 활성화 (가드) - `recipeChanged = (plcRecipeNo != _prevRecipeNo) || (ActivatedRecipe()?.Id != plcRecipeNo)` - `recipeChanged == true` 일 때만: - `recipe = _RecipeManager.Recipes().FirstOrDefault(x => x.Id == plcRecipeNo)` (없으면 알람+`return null`) - `_RecipeManager.ActivateRecipe(recipe.Id, "PLC Recipe Change")` - **`EnsureLayersReloaded(recipe)`** ← Layers 교체 "완료"까지 보장 (대응안 A) - `else` 동일 레시피 → 활성화/재로드 스킵 - 끝에 `_prevRecipeNo = plcRecipeNo;` - 첫 사이클(`_prevRecipeNo == -1`)은 항상 1회 활성화. ### Step 3. ★ Layers race 대응 (대응안 A — EnsureLayersReloaded) - `ActivateRecipe`만으로는 캔버스 `Model.Layers`가 즉시 안 바뀜(UI Dispatcher 2-홉 비동기). - 대응안 A: 시퀀스에서 직접 동기 로드 후 진행. ```csharp Application.Current.Dispatcher.Invoke(() => RecipeHelper.ReloadRecipe(recipe.Name)); // 이중 로드 방지: 자동 체인(RMSHandlerForPTOP)과 겹치지 않도록 호출 위치/중복 확인 ``` - **검증 기준은 `ActivatedRecipe().Id` 일치가 아니라 `Model.Layers`가 새 레시피로 교체 완료.** ### Step 4. Page 검증 (레시피 활성화 "후") - `int recipePageCount = _ScannerCanvasUserCtrl.Model.Layers.Count();` - `if (plcPageNo < 1 || plcPageNo > recipePageCount) { 알람/에러 + return null; }` - **상한 하드코딩 금지** — 페이지는 사용자가 얼마든지 추가 가능. `Layers.Count()`만 신뢰. ### Step 5. 에코 + 완료비트 - `WriteWord(PC_RECIPE_NO, plcRecipeNo)`, `WriteWord(PC_PAGE_NO, plcPageNo)` - `WriteBit(PC_PAGE_CHANGE_COMPLETE, )` — **PAGE COMPLETE 하나만** (레시피 COMP 비트 미사용, C-2) - `EVENT_AUTO_RUN_UPDATE_PAGENUM` 퍼블리시(기존 유지) ### Step 6. Builder/Flow 정리 - 1-2 제거, 1-3 추가 반영. `Draw("SeqAutoRunPTOP.pdf")` 갱신 확인. ### Step 7. (선택, 별도 작업) 가접 패스 - 본 지시서 범위 밖. 가접은 Case B면 `ExecuteWelding`에 선행 패스 추가(132647 문서). 별도 지시서로 분리 권장. --- ## 3. 검증 (Test) ### 3-1. 빌드 - [ ] MSBuild Debug|x64 솔루션 빌드 오류 0개. ### 3-2. 시퀀스 동작 테스트 (Seq 동작 테스트) - [ ] **동일 레시피 + 페이지만 변경** 반복: 레시피 활성화/ReloadRecipe **스킵** 로그 확인, 페이지별 용접리스트 정상. - [ ] **레시피 변경 사이클**: RecipeNum 바뀐 사이클에만 활성화, Layers가 **새 레시피로 교체된 뒤** 용접리스트 생성되는지(=stale 아님) 확인. - [ ] 페이지 수 다른 레시피 전환(예: 2페이지 ↔ 5페이지) 시 `Layers.Count()` 가변 검증 정상. - [ ] PAGE_REQ → 에코(PC_RECIPE_NO/PC_PAGE_NO) → PAGE COMPLETE 핸드셰이크 PLC와 정상 종결. - [ ] 잘못된 PageNo(범위 밖) 수신 시 에러/알람 처리. ### 3-3. 실제 Laser 동작 확인 (명일 병행) - [ ] 레시피·페이지 정합 상태에서 실제 발진 라인이 해당 페이지 티칭과 일치. --- ## 4. 리스크 / 주의 - **이중 로드**: 대응안 A의 수동 ReloadRecipe와 자동 체인(RMSHandlerForPTOP)이 겹쳐 2회 로드될 수 있음 → 호출 위치 정리. - **Dispatcher 데드락**: 시퀀스 스레드에서 `Dispatcher.Invoke`(동기) 시 UI 대기 교착 주의 → 필요시 `InvokeAsync`+완료대기 검토. - **COMPLETE 극성 오설정**(C-1) 시 PLC 핸드셰이크 영원히 안 끝남 → 착수 전 확정. - 레시피축 stale은 어제(133714) 필드 저장 경로에서 이미 한 번 겪음 — 같은 비동기 갱신 타이밍 이슈축. --- ## 5. 완료 기준 (Definition of Done) - [ ] 4노드 → 1노드 통합, 빌드 0 오류. - [ ] 동일레시피 스킵 / 레시피변경 시 Layers 교체완료 후 용접리스트 생성, 둘 다 런타임 확인. - [ ] PLC 핸드셰이크(에코+PAGE COMPLETE) 정상 종결. - [ ] 실제 Laser 발진이 레시피×페이지 정합. - [ ] 작업일지 기록 + 커밋/푸시.