feat: 수동출사 레시피/페이지 정합성 인터락 (ISSUE-260904-03)
AutoRun 중 수동출사(Run Welding) 시 화면 띠의 PLC 지시와 실제 활성·로드 상태가 어긋난 채 출사되는 것을 차단. 검증 4종 - 활성==선택 / 활성==실제 로드파일(SelectedRecipeFile) / PLC지시 RECIPE==활성번호 / PLC지시 PAGE==현재 페이지. PLC 지시 2종은 bit15 구간에만 채워지므로 null 이면 생략. 검증 예외 시 fail-closed. 시퀀스는 무수정.
This commit is contained in:
parent
468499d559
commit
f873e066e4
@ -506,8 +506,97 @@ namespace WeldingCommon.Views
|
||||
_SeqScoutFlyingVision.Stop();
|
||||
}
|
||||
|
||||
#region [레시피/페이지 인터락 2026-09-04] 수동출사 전 정합성 검증 (요청 260904-03)
|
||||
// 배경: AutoRun 진행 중 수동출사를 할 때, 작업자는 화면 상단 띠(SyncPlcGuide, :96)에 뜬
|
||||
// "PLC 지시 RECIPE/PAGE" 를 보고 레시피와 페이지를 맞춘 뒤 Run Welding 을 누른다.
|
||||
// 그 맞춤이 실제로 되어 있는지 확인하는 코드가 없어, 어긋난 채로 출사될 수 있었다.
|
||||
//
|
||||
// 검사 4종:
|
||||
// ① 활성 레시피 == 선택 레시피
|
||||
// ② 활성 레시피 == 실제 캔버스에 로드된 파일 ← 가장 중요
|
||||
// LASA 는 레시피를 메모리에 1개만 유지하므로 활성과 화면 내용이 어긋날 수 있다.
|
||||
// 판정 기준 DB.Recipe.Recipe.SelectedRecipeFile 은 Recipe.Load() 성공 시에만
|
||||
// 세팅되는 실제 로드 이력이라 신뢰할 수 있다.
|
||||
// ③ PLC 지시 RECIPE == 활성 레시피 번호
|
||||
// ④ PLC 지시 PAGE == 현재 캔버스 페이지
|
||||
//
|
||||
// ③④ 의 Status.PlcGuide* 는 bit15(수동용접) 구간에만 채워진다(UCMainAutoRunViewModel:223).
|
||||
// null 이면 해당 검사를 생략한다 — PLC 워드를 직접 읽으면 공용 코드가 설비에 종속되므로
|
||||
// 의도적으로 Status 경유만 쓴다(260904 협의).
|
||||
//
|
||||
// 예외 시 fail-closed(차단). 검증이 안 되면 출사를 막는 것이 이 인터락의 목적이다.
|
||||
// ※ HeadTheta 인터락(SeqAutoRunPTOP)과는 별개 기능이며 서로 영향이 없다.
|
||||
|
||||
private bool CheckRecipePageBeforeTeachingRun()
|
||||
{
|
||||
try {
|
||||
var active = _Aurora.RecipeManager.ActivatedRecipe();
|
||||
if (active == null) {
|
||||
Log.E("[레시피/페이지 인터락] 활성 레시피 없음 → 출사 차단");
|
||||
MessageUtil.CreateAndShowMessageDialog("출사 차단", "활성 레시피가 없습니다.");
|
||||
return false;
|
||||
}
|
||||
|
||||
var mismatches = new List<string>();
|
||||
int curPage = CommonHelper.GetMainPage().GetCurrentPageIndex() + 1; // 0-base → 1-base
|
||||
|
||||
// ① 활성 == 선택
|
||||
var selected = RecipeHelper.SelectedRecipe.name;
|
||||
if (!string.IsNullOrWhiteSpace(selected) &&
|
||||
!string.Equals(active.Name, selected, StringComparison.OrdinalIgnoreCase)) {
|
||||
mismatches.Add($"활성 레시피 [{active.Name}] ≠ 선택 레시피 [{selected}]");
|
||||
}
|
||||
|
||||
// ② 활성 == 실제 캔버스에 로드된 파일
|
||||
var loadedFile = DB.Recipe.Recipe.SelectedRecipeFile;
|
||||
if (!string.IsNullOrWhiteSpace(loadedFile)) {
|
||||
var loadedName = System.IO.Path.GetFileName(System.IO.Path.GetDirectoryName(loadedFile));
|
||||
if (!string.Equals(active.Name, loadedName, StringComparison.OrdinalIgnoreCase)) {
|
||||
mismatches.Add($"활성 레시피 [{active.Name}] ≠ 화면 로드 [{loadedName}]");
|
||||
}
|
||||
}
|
||||
|
||||
// ③④ PLC 지시 (bit15 구간에만 채워짐)
|
||||
var gRecipe = Status.PlcGuideRecipeNo;
|
||||
var gPage = Status.PlcGuidePageNo;
|
||||
if (gRecipe != null && gPage != null) {
|
||||
if (gRecipe.Value != active.Id) {
|
||||
mismatches.Add($"PLC 지시 RECIPE [{gRecipe}] ≠ 활성 레시피 번호 [{active.Id}]");
|
||||
}
|
||||
if (gPage.Value != curPage) {
|
||||
mismatches.Add($"PLC 지시 PAGE [{gPage}] ≠ 현재 페이지 [{curPage}]");
|
||||
}
|
||||
}
|
||||
|
||||
if (mismatches.Count == 0) {
|
||||
Log.I($"[레시피/페이지 인터락] 통과. 활성=[{active.Id}:{active.Name}] " +
|
||||
$"페이지=[{curPage}] PLC지시=[{gRecipe}/{gPage}]");
|
||||
return true;
|
||||
}
|
||||
|
||||
Log.E($"[레시피/페이지 인터락] 출사 차단 — {string.Join(" / ", mismatches)}");
|
||||
MessageUtil.CreateAndShowMessageDialog("출사 차단 - 레시피/페이지 불일치",
|
||||
"다음 항목이 일치하지 않아 출사를 차단했습니다.\n\n · " +
|
||||
string.Join("\n · ", mismatches) +
|
||||
"\n\n레시피와 페이지를 다시 맞춘 뒤 시도하십시오.");
|
||||
return false;
|
||||
|
||||
} catch (Exception ex) {
|
||||
Log.E($"[레시피/페이지 인터락] 검사 실패 → 출사 차단(fail-closed): {ex.Message}");
|
||||
MessageUtil.CreateAndShowMessageDialog("출사 차단",
|
||||
$"레시피/페이지 검증 중 오류가 발생했습니다.\n\n{ex.Message}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
private void PerformCmdRunTeachingRun(object obj)
|
||||
{
|
||||
// [레시피/페이지 인터락 2026-09-04] 출사 전 정합성 검증. 불일치면 시퀀스를 태우지 않는다.
|
||||
if (!CheckRecipePageBeforeTeachingRun()) {
|
||||
return;
|
||||
}
|
||||
|
||||
var result = MessageUtil.ShowYesNoMessageDialog("Teaching Run", "Start TeachingRun Sequence?");
|
||||
if (result == false) {
|
||||
return;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user