PLC가 PC 에코 넘버(PC_PAGE_NO/PC_RECIPE_NO) 일치를 상시 확인하는 것으로 확정(260806)됨에 따라, PC 책임을 검증에서 '정확히 읽고 → 내부 상태 갱신 → 에코'로 전환. - CheckRecipeNoComp/CheckPageNoComp를 수렴 루프로 재작성 (에코 후 되읽어 일치 확인, 어긋나면 재읽기, 맞는 즉시 다음 노드로) - 에코 없이 return 하던 경로 제거 (RecipeNo=0/미등록 → 에코 안 하고 재시도) - 범위 밖 PageNo: 3초 무한대기 → 200ms 재읽기, 에코 안 함 - Page 3회 수집(600ms)·Recipe 800ms 재폴링 제거 → 정상 흐름 지연 0 - while 탈출 후 context.Stopped 가드 추가 - ReadOutWord(eWordOutput) 헬퍼 추가 (ReadOutBit 패턴 준용) - 시뮬레이션 가드: IsSimul이면 수렴 생략 (PLC 워드가 항상 0이라 못 빠져나감) 구버전은 #region 260806 으로 전량 주석 보존 — 원복 시 블록 교체. 분석: docs/분석/2026/08/06/
11 KiB
Recipe/Page 핸드셰이크 — "에코 보장" 방침 전환 분석
- 작성일: 2026-08-06
- 대상 브랜치:
feature/ubisam-pptx-integration - 분류: 분석 전용 — 소스 미수정
- 발단: PLC측 시퀀스 확정 완료. PLC는 Page/Recipe 넘버 일치만 보고 넘어간다(2026-08-06 확인)
- 관련: AutoRun 재기동 워드 미반영 원인분석
- 후속: 에코 수렴 루프 설계안 — 2026-08-06 추가 확인 (PLC는 일치를 상시 확인한다. 30초는 확인 간격이 아니라 한 번의 확인 창이며 반복된다)으로 §5 조치표 일부가 정정됐습니다. 설계안을 우선 참조하세요.
0. 결론
PC측 책임이 "검증"에서 "에코 보장"으로 바뀝니다.
PLC가 넘버 일치를 판정하므로, PC가 자체 검증으로 대기·중단하는 코드는 전부 교착 요인입니다. PC가 멈추면 에코가 안 나가고, 에코가 안 나가면 PLC도 멈춰 양쪽이 서로 기다립니다.
현재 코드에는 에코를 하지 않고 빠져나가거나 무한 대기하는 경로가 4건 있습니다(§2). 전부 "PC가 신중하게 확인하려고" 넣은 것인데, 새 방침에서는 정확히 반대로 작동합니다.
단, "잘 써주기"의 전제는 "제대로 읽기"입니다. 틀린 값을 에코하면 PLC가 불일치로 안 넘어가 결국 멈춥니다. 따라서 08/04 §4의 상승엣지 전환(조치 A)은 이 방침에서도 그대로 유효하며, 오히려 전제 조건이 됩니다. → §4
1. 확정된 프로토콜 (2026-08-06)
| 주체 | 동작 |
|---|---|
| PLC | Recipe·Page 워드를 동시에 쓴다 → M70508(PLC_PAGE_CHANGE_REQ, bit 0x08) ON |
| PLC | PC_PAGE_NO·PC_RECIPE_NO가 자기가 쓴 값과 같아지면 다음 스텝으로 진행 |
| PC | bit8 감지 → Recipe 읽기·활성화 → Page 읽기 → 에코 |
게이트는 워드다. PC_PAGE_CHANGE_COMPLETE(M70008, eBitOutput 0x08)는 PLC가 보지 않는다.
코드 주석이 이와 반대로 적혀 있다
SeqAutoRunPTOP.cs:1225 (OnSeqActionStop), 에코 워드 0 초기화를 롤백한 근거:
② PLC가 보는 핸드셰이크 게이트는 워드가 아니라 PC_PAGE_CHANGE_COMPLETE 비트이고,
그 비트는 바로 위에서 이미 false로 내렸다 → 잔재 워드를 유효값으로 읽을 경로가 없다.
→ 이 전제는 틀렸습니다. 롤백 판단의 근거가 무효이므로 재검토 대상입니다.
다만 워드 0 초기화는 SeqStatusMonitor.cs:104-109가 Auto OFF 시 이미 수행하므로
중복 구현 상태입니다(OnSeqActionStop은 로그만, :1231-1240).
안전 측면은 PLC가 커버한다 (검증됨)
용접 실행은 PLC_WELD_TRIGGER_REQ(M70516) ON 대기가 별도 게이트입니다
(SeqAutoRunPTOP.cs:196, :705). PC가 페이지를 오독하면 → 에코 불일치 → PLC가 트리거를
주지 않음 → 용접이 나가지 않습니다. 오독이 잘못된 용접으로 이어지는 경로는 없습니다.
남는 비용은 안전이 아니라 정지 시간입니다. 그래서 이 문서의 초점은 "멈춤 제거"입니다.
2. ★ 핑퐁을 끊는 지점 전수 (에코 누락·무한 대기)
① CheckRecipeNoComp — 에코 없이 return 하는 경로 2건
정정(2026-08-06): PLC는 일치를 상시 확인하므로 아래 "대기"는 영구 교착이 아닙니다. PC가 맞추는 즉시 진행됩니다. → 수렴 루프 설계안 §0
| 위치 | 조건 | PC_RECIPE_NO |
PLC 결과 |
|---|---|---|---|
:353-357 |
plcRecipeNo == 0 |
미기록 (직전 값 잔존) | 불일치 → 재시도 대기 (PC는 복구 시도 안 함) |
:361-365 |
미등록 번호 (Log.W 한 줄) |
미기록 | 불일치 → 재시도 대기 (PC는 복구 시도 안 함) |
:395-398 |
이미 활성 + 4회 폴링 동안 불변 | preActivated.Id |
PLC 요구값과 다르면 대기 |
:429 |
실제 전환 완료 | plcRecipeNo |
통과 |
ReadWord는 (int err, short data)인데(PLCController.Logic.cs:16) :349가 .data만 씁니다.
PLC 미연결·미활성이면 에러 없이 0을 반환하므로(PLCBase.APIs.cs:105, :109)
통신 이상이 자동으로 :353 경로에 빠집니다. 화면 표시 없음, 로그 1줄뿐.
② CheckPageNoComp:534-556 — 범위 밖이면 3초 주기 무한 대기
260805에 return null(시퀀스 중단)에서 대기 루프로 바꾼 지점입니다. 중단은 아니지만
에코를 하지 않은 채 머무릅니다. PLC도 대기 중이므로 완전 교착입니다.
탈출구는 while (!context.Stopped)(:501) 하나 — 작업자가 정지를 눌러야 합니다.
③ CheckRecipeNoComp:408-419 — ActivateRecipe 반영 대기가 사실상 무한
타임아웃 분기(:413-417)가 Log.W 후 actStart를 리셋합니다. 빠져나가지 않습니다.
④ CheckPageNoComp:501 while 탈출 후 Stopped 가드 없음
형제 노드는 둘 다 있습니다(CheckPageNo:483, CheckRecipeNoComp:420).
정지로 루프를 빠져나와도 :573이 실행돼 미검증 값을 에코합니다.
워드가 게이트이므로 이건 로그 오염이 아니라 정지한 PC가 PLC에 GO를 쏘는 것입니다.
3. 방침에 비추어 과잉인 코드
| 위치 | 현재 | 새 방침에서의 평가 |
|---|---|---|
CheckPageNoComp:499-566 |
Page 3회 수집 (Sleep(200) × 3) |
과잉. 최소 600ms 지연만 발생. 값 검증은 PLC 몫 |
:492, :527 로그 |
"3회 연속 검증" | 거짓 로그. 3개 값을 비교하는 코드가 없다 (:561은 출력뿐, 판정은 마지막 값 plcPageNo 하나) |
CheckRecipeNoComp:374-399 |
값 변화를 최대 4회(약 800ms) 기다림 | 과잉 + 유해. 잘못된 트리거 시점의 우회책. 08/04 조치 B와 동일 판정 |
CheckPageNoComp:581-584 |
에코 후 재읽기·비교 → ACK 비트 | 무효. PLC가 M70008을 안 본다. 불일치여도 Ok() 반환(:597)이라 PC 흐름에도 영향 없음. PC 로그용으로만 의미 |
:374-399의count++ < 3은 실제로 4회 순회합니다(count 0·1·2·3). 주석("3번 체크하자")과 불일치.
4. "잘 써주기"의 전제 — 읽기 시점
새 방침은 PC측 검증을 덜어내지만, 읽는 값 자체가 틀리면 에코도 틀리고 결국 멈춥니다.
CheckPageNo:457은 PLC_PAGE_CHANGE_REQ를 레벨(ON)로 판정합니다. 상승엣지가 아닙니다.
PLC 프로토콜이 워드 write → REQ raise 순서이므로(08/04 §4),
상승엣지 직후에 읽으면 워드는 항상 새 값입니다. 반면 레벨 판정은 이미 ON인 잔재 신호에
붙어 갱신 전 값을 읽습니다.
| 트리거 판정 | 워드 정합성 | 에코 결과 |
|---|---|---|
| 레벨 (현재) | 보장 없음 | 옛 값 에코 → PLC 불일치 → 멈춤 |
| 상승엣지 | 보장됨 | 새 값 에코 → 핑퐁 성립 |
→ 엣지 전환은 검증 강화가 아니라 "정확히 1회 읽고 즉시 에코"를 가능하게 하는 선행 조치입니다. 엣지로 바꾸면 §3의 3회 수집·800ms 재폴링을 둘 다 안전하게 제거할 수 있습니다.
5. 조치 후보 (미승인 — 승인 시 별도 작업지시서)
⚠ 이 표는 수렴 루프 설계안 §6에서 갱신됐습니다. P2·P3 정정, P4·P5 제거, P1 우선순위 하향. 설계안 §6을 정본으로 봅니다.
원칙: PC는 자기가 읽은 값·실제 상태를 지체 없이 에코한다. 일치 판정은 PLC에 맡긴다.
| # | 대상 | 내용 | 근거 |
|---|---|---|---|
| P1 | CheckPageNo:457 |
레벨 → 상승엣지 판정 | §4 (= 08/04 조치 A) |
| P2 | CheckRecipeNoComp:353-365 |
에코 없이 return 하는 2경로에 에코 추가(현재 활성 레시피 번호) + 알람/토스트 | §2-① |
| P3 | CheckPageNoComp:534-556 |
무한 대기 제거 → 읽은 값 그대로 에코하고 진행. Layer 선택은 기존 폴백(:626-628) 사용 |
§2-② |
| P4 | CheckPageNoComp:499-566 |
3회 수집 → 1회 읽기로 축소 | §3 (P1 선행) |
| P5 | CheckRecipeNoComp:374-399 |
800ms 재폴링 제거 | §3 (P1 선행) |
| P6 | :349, :510 |
err 확인 — 중단이 아니라 재읽기 목적. err != OK면 즉시 재시도 |
§2-① |
| P7 | CheckPageNoComp:501 직후 |
if (context.Stopped) return null; 추가 |
§2-④ |
| P8 | CheckRecipeNoComp:413-417 |
타임아웃 시 리셋 대신 탈출 + 알람 | §2-③ |
| P9 | :492, :527 |
로그 문구 정정 ("3회 연속 검증" → 실제 동작) | §3 · rules.md #1 |
| P10 | :1219-1241 |
주석 ②의 잘못된 전제 정정 + SeqStatusMonitor와 중복 정리 |
§1 |
P1~P3이 "멈춤 제거"의 직접 조치입니다. P4·P5는 P1 적용 후에만 안전합니다.
주의 — ResumeMode(bit15) 예외
OnSeqActionStop:1227·:1236-1240, SeqStatusMonitor:104는 M70515 ON 구간에서 에코 워드를
보존합니다. 가접 Resume이 직전 Recipe/Page 에코에 의존하기 때문입니다.
P2·P10 적용 시 이 예외를 반드시 유지해야 합니다.
6. PLC측 질문 정리 (08/04 ★ 항목 갱신)
| # | 질문 | 상태 |
|---|---|---|
| 워드를 쓴 뒤 REQ를 올리는가 | 해소(08/04) — write → raise 확정 |
|
PC_PAGE_CHANGE_COMPLETE 하강을 REQ 재발행 조건으로 쓰는가 |
해소(08/06) — PLC는 넘버만 본다 | |
| ★1 | Manual 전환 / PC 정지 시 M70508을 PLC가 OFF 시키는가 | 미해소 — P1(엣지 전환) 필요성의 근거 |
| ★2 | M70515(Weld Ready REQ)를 PLC가 언제 OFF 시키는가 | 미해소 — bit15 Resume 교착 |
| ★5 | PC_WELD_READY_ACK(M70015)를 레벨로 보는가 펄스로 보는가 |
미해소 |
★1이 "OFF 시킨다"로 확인되면 P1 없이도 대부분 해소되지만, 엣지 판정이 더 강한 보장이라 어느 쪽이든 P1을 권장합니다.
7. 부수 확인 사항
CheckPageNoComp:521-525— CellId/LotId를 매 회차 읽어Status에 즉시 대입. 읽기 실패 시string.Empty가 그대로 들어갑니다(PLCController.Address.cs:227,:239). 빈 값 체크 없음.CheckRecipeNoComp:376의 재폴링이plcRecipeNo필드를 덮어써,ScoutSaveTag:886파일명에 0이 박힐 수 있습니다. (경미 — P5로 함께 해소)- 에코 워드 0 초기화 주체가
SeqStatusMonitor:106-107한 곳입니다.OnSeqActionStop은 로그만 남깁니다(:1231-1240). 두 파일의 주석이 서로 다른 전제를 적고 있어 정리가 필요합니다.