근거: 가이드 + 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>
19 KiB
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:106Status.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에서 확정.
- (a)
안전 (그대로 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.cseBitOutput.PC_PAGE_CHANGE_COMPLETE = 0x08 - 공용:
WeldingComponents/WeldingCommon/Devices/PLC/PLCController.Address.cseCommonBitOutput.PC_PAGE_CHANGE_COMPLETE = 0x08
- PTOP:
- 사용처가 갈린다:
RestoreDeviceStatus(SeqAutoRunPTOP.cs:803)는eCommonBitOutput,OnSeqActionStop(:977)은eBitOutput사용. - 즉 신규
PC_RECIPE_CHANGE_COMPLETE를 PTOPeBitOutput에만 추가하면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_NOrename +SeqAutoRunPrismatic.cs:414의 참조도 이름만 교체(로직 불변, 승인 완료).eWordOutput:EMPTY_02→PC_RECIPE_NO로 교체.- 공용 enum 동기화(필수): 위 PTOP enum과 동일하게
WeldingCommon/Devices/PLC/PLCController.Address.cs의eCommonBitOutput0x09 자리에도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 참고.
- REQ OFF → Recipe 변경 없음. 즉시
CheckRecipeNoComp:_PLC.ReadWord(eWordInput.PLC_RECIPE_NO)읽기 (필요 시CheckPageNoComp의 3회 적재 패턴 재사용).- 레시피 조회/매핑 (결정 4 —
.Id직접 1:1):var recipe = AuroraEnv.RecipeManager /* 또는 _recipeEntry */ .Recipes().FirstOrDefault(x => x.Id == plcRecipeNo); if (recipe == null) { /* "{plcRecipeNo}번 레시피 없음" 알람 */ return null; }- 선례 그대로:
RMSHandlerForPTOP.cs:125-130(조회/없음 알람),:173(활성화).
- 선례 그대로:
- 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 검증이 이전 레시피 기준으로 돌 위험.
- 현재값 조회:
_PLC.WriteWord(eWordOutput.PC_RECIPE_NO, plcRecipeNo)에코.- 핸드셰이크 응답 (결정 3 — 기존 Page 미러형):
CheckPageNoComp(:401-409)의 COMPLETE 비트 처리 방식을 그대로 본떠PC_RECIPE_CHANGE_COMPLETE처리. REQ-OFF 대기 단계는 두지 않는다(현 Page와 동일). - (선택) 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).
- ⚠️ 엣지 선언 필수: Decision의 반환 타깃이 유효하려면 두 분기 엣지가 그래프에 모두 존재해야 한다. 메인 Flows에 ON 경로(
- 루프백 변경: 현재
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_COMPLETEfalse 를 추가 — STEP 1에서 공용 enum에 멤버를 추가했어야 컴파일된다. (안 했으면 여기서 빌드 에러)OnSeqActionStop계열(L977 비트, L981-982 워드, PC_PAGE 초기화 지점): 이쪽은eBitOutput/eWordOutput(PTOP) 사용.PC_RECIPE_CHANGE_COMPLETEfalse,PC_RECIPE_NO0 추가.- ⚠️ 두 지점이 서로 다른 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누적 폴링 구조(plcPageNoList3회 적재)는 그대로 유지할 것. - 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