403 lines
22 KiB
Plaintext
403 lines
22 KiB
Plaintext
================================================================================
|
|
작업지시서 — Laser Recipe Save 교차 오염 (선택 레시피에 Active 레시피가 덮어써짐)
|
|
================================================================================
|
|
작성일 : 2026-08-03
|
|
대상 : LGES-OC5-PtoP-Welder / ILSOS_PrismaticRD_PTOP
|
|
분류 : 버그 수정 (데이터 손실)
|
|
원본분석 : docs/분석/2026/08/03/173852_Laser_Recipe_Save_교차오염_분석.md
|
|
상태 : 소스 미수정. 본 지시서대로 작업 PC에서 적용할 것.
|
|
|
|
[!] 경고 1 - 본 작업은 WeldingComponents 하위 파일을 수정한다.
|
|
프로젝트 규약상 WeldingComponents / External/Aurora 수정은
|
|
반드시 사전 승인이 필요하다. 승인 없이 적용하지 말 것.
|
|
|
|
[!] 경고 2 - 한글 포함 파일 수정 시 UTF-8 인코딩을 유지할 것.
|
|
(기존 파일 인코딩을 그대로 두고 편집. 새 인코딩으로 저장 금지)
|
|
|
|
[!] 경고 3 - 아래 1단계(가드)를 먼저 단독 적용하고 현장 로그를 확보한 뒤
|
|
2~4단계를 적용할 것. 한 번에 전부 넣지 말 것.
|
|
|
|
|
|
================================================================================
|
|
1. 증상
|
|
================================================================================
|
|
- 레시피 저장 경로 : D:\ILSOSConfig\ILSOS_PrismaticRD_PTOP\_config_recipe
|
|
- Laser Recipe를 Save하면 "어쩌다 한 번씩" Active 레시피의 내용이
|
|
현재 선택된 레시피에 덮어써진다.
|
|
- 선택 레시피의 Page와 Param이 전부 Active 레시피 것으로 바뀐다.
|
|
- AutoRun 뿐 아니라 Manual 상태에서도 발생했다고 보고됨.
|
|
|
|
|
|
================================================================================
|
|
2. 원인 요약
|
|
================================================================================
|
|
저장 "대상"과 저장 "내용"이 서로 다른 전역 변수이고, 둘을 묶는 검사가 없다.
|
|
|
|
저장 내용(소스) : LASA/GUI/DB/Dao.cs:7
|
|
public static RecipeWeldingLines WeldingLinesRecipe
|
|
-> 프로세스 전역 싱글톤 1개
|
|
|
|
저장 대상(경로) : WeldingCommon/Utils/RecipeHelper.cs:18
|
|
public static (int id, string name) SelectedRecipe
|
|
|
|
Page 데이터 : LASA/GUI/DB/RecipeFieldScan.cs:18-22 Instance (또 다른 싱글톤)
|
|
|
|
MainPage.SaveRecipe(fullpath) (LASA/GUI/Page/MainPage.cs:425-434) 는
|
|
"지금 메모리에 있는 것을 지정 경로에 덤프"할 뿐, 그 메모리가 그 경로의
|
|
레시피인지 확인하지 않는다.
|
|
|
|
확인할 수단은 이미 있는데 안 쓰고 있다:
|
|
MainPage.cs:466 ReloadRecipe 가 DB.Dao.SystemRecipe.WorkRecipeFile = fullpath
|
|
로 "메모리에 든 레시피"를 기록한다.
|
|
그러나 WorkRecipeFile 을 읽는 곳은 MainPage.cs:537 / 547 /
|
|
RecipeLaserInterlock.cs:25 뿐이고 SaveRecipe 는 조회조차 하지 않는다.
|
|
|
|
여기에 저장 대상이 UI 인자가 아니라 static 필드로 정해진다:
|
|
UCScannerObjectTeachingViewModel.cs:202-208
|
|
public void OnSaved(int id, string recipeName)
|
|
-> 인자 id / recipeName 을 한 번도 참조하지 않고
|
|
RecipeHelper.SelectedRecipe.name 으로 저장한다.
|
|
|
|
=> 두 전역이 어긋난 순간, Save 한 번이 곧 레시피 교차 복사가 된다.
|
|
Page 까지 같이 바뀌는 이유도 동일하다 (MainPage.cs:433 이 싱글톤
|
|
RecipeFieldScan.Instance 를 대상 레시피의 FieldHelper.json 에 쓴다).
|
|
|
|
|
|
[ 유력 발생 경로 - 우선순위 순 ]
|
|
|
|
(1) 정상 경로의 부분 실패 <= 최유력. 트리거(Save 클릭)와 간헐성이 모두 일치
|
|
아래 세 곳 모두 "대상을 먼저 바꾸고 내용을 나중에" 로드한다. 원자적이지 않다.
|
|
|
|
RecipeHelper.cs:76-78 SelectedRecipe = ... -> ReloadRecipe(...)
|
|
UCScannerObjectTeachingViewModel.cs:165-166 SelectedRecipe = ... -> ReloadRecipe(...)
|
|
UCScannerObjectTeachingViewModel.cs:172-173 SelectedRecipe = ... -> ReloadRecipe(...)
|
|
|
|
ReloadRecipe 가 예외로 끝나거나 조용히 무동작하면
|
|
-> 대상 = 새 레시피 / 내용 = 직전(대개 Active) 그대로
|
|
-> 다음 Save 가 그대로 교차 복사.
|
|
|
|
ReloadRecipe 실패/무동작 지점:
|
|
RecipeHelper.cs:66-67 GetDeviceConfig(CAM1) as CamConfig 가 null 이면 NRE
|
|
MainPage.cs:464 -> LASA/DB/Recipe/Recipe.cs:42-70 파일IO/파싱 실패 시 throw
|
|
MainPage.cs:474 UpdateWeldingLinesRecipe() -> MainPage.cs:409-417 throw
|
|
MainPage.cs:485 -> RecipeFieldScan.cs:88 throw
|
|
Recipe.cs:64 루트 자식 노드 이름이 RecipeWeldingLines 가 아니면
|
|
"무예외 무동작"으로 성공 반환 (가장 위험)
|
|
RecipeWeldingLines.cs:68-75 예외를 삼킴
|
|
-> 파라미터는 새 것, 페이지는 옛 것인 혼합 상태
|
|
|
|
(2) PLC 레시피 전환 시 역방향 오염 (신규 Active 파일이 구 레시피 내용으로 덮어써짐)
|
|
UCScannerObjectTeachingViewModel.cs:155-156
|
|
var activeRecipe = _RecipeManager.ActivatedRecipe();
|
|
RecipeHelper.SaveRecipe(activeRecipe.Name); // 이 시점 메모리는 아직 구 레시피
|
|
|
|
SeqAutoRunPTOP.cs:403 이 백그라운드 스레드에서 ActivateRecipe 호출
|
|
-> SYS_RECIPE_ACTIVATED 가 ObserveOnDispatcher 로 UI 큐 1홉
|
|
-> 위 SaveRecipe 가 먼저 실행되고, 메모리 갱신(SeqAutoRunPTOP.cs:425)은 2홉 뒤.
|
|
|
|
같은 1홉/2홉 시차는 이미 다른 개발자가 발견해 주석으로 남겨 두었다
|
|
(UCScannerObjectTeachingControlBoxViewModel.cs:193-195).
|
|
다만 자기 화면만 회피했고 :156 의 SaveRecipe 는 손대지 않았다.
|
|
|
|
(3) Manual 복귀 시 대상 미복구
|
|
EquipmentSetup.cs:276-283 - Auto 진입 시 OnActiveReloaded()(279)로
|
|
SelectedRecipe 가 Active 로 바뀌지만, Manual 복귀 분기의
|
|
RollbackRecipe() 는 주석 처리(282) 되어 있다.
|
|
|
|
[중요] 이 주석을 풀어도 고쳐지지 않는다.
|
|
RollbackRecipe(RecipeHelper.cs:105-110)는 ReloadRecipe(SelectedRecipe.name)
|
|
인데, Auto 진입 시 OnActiveReloaded(RecipeHelper.cs:76)가 이미
|
|
SelectedRecipe 를 Active 로 덮어써서 되돌릴 원본이 없다(백업 필드 0건).
|
|
=> "Active 를 Active 로 다시 로드"하는 의미 없는 동작.
|
|
=> 282행 주석 해제는 이번 작업 범위에서 제외한다.
|
|
|
|
(4) 신규 레시피 생성 시 메모리 미갱신 저장
|
|
UCScannerObjectTeachingViewModel.cs:114-115
|
|
SelectedRecipe = 신규 직후, 메모리 재로드 없이 SaveRecipe(신규) 호출.
|
|
|
|
|
|
[ 원인이 아닌 것 - 같은 오답 반복 방지 ]
|
|
|
|
RMSHandlerForPTOP 은 원인이 아니다. 한 번도 등록되지 않는다.
|
|
EquipmentSetup.cs:95 //AuroraEx.RegisterRmsHandler<RMSHandlerForPTOP>();
|
|
EquipmentSetup.cs:96 //AuroraEnv.RecipeManager.RmsHandler().RegistryDeviceHandler(AuroraEnv);
|
|
EquipmentSetup.cs:97 //AuroraEnv.RecipeManager.RmsHandler().Start();
|
|
RegisterRmsHandler 호출은 저장소 전체에서 이 3줄(전부 주석)이 전부다.
|
|
따라서 RMSHandlerForPTOP.cs:62-66 / :103-149 의 레이스는 실행되지 않는다.
|
|
여기를 고쳐도 증상은 그대로 재발한다.
|
|
|
|
1차 분석의 "PLC Word 를 읽어서 메모리에 Active 가 남는다" 도 인과가 틀렸다.
|
|
AutoRun 의 PLC_RECIPE_NO 읽기(SeqAutoRunPTOP.cs:346-425)는 OnActiveReloaded()로
|
|
대상과 내용을 함께 갱신하므로 신고된 방향의 오염을 만들지 못한다.
|
|
(단 "메모리에 Active 가 남는다"는 상태 서술 자체는 맞다. 경로가 다를 뿐이다.)
|
|
|
|
|
|
================================================================================
|
|
3. 수정 작업 - 1단계 (최우선. 이것부터 단독 적용)
|
|
================================================================================
|
|
목적 : 잘못된 저장을 실제로 차단하고, 원인 확정을 위한 로그를 남긴다.
|
|
이것만 적용해도 데이터 손실은 멈춘다.
|
|
|
|
파일 : WeldingComponents/WeldingCommon/Utils/RecipeHelper.cs
|
|
|
|
[현재 36~39행]
|
|
public static void SaveRecipe(string recipeName, bool includeModel = true)
|
|
{
|
|
CommonHelper.GetMainPage().SaveRecipe(GetTeachingEditorFullPath(recipeName), includeModel);
|
|
}
|
|
|
|
[변경안]
|
|
public static void SaveRecipe(string recipeName, bool includeModel = true)
|
|
{
|
|
var targetPath = GetTeachingEditorFullPath(recipeName);
|
|
|
|
// [추가 2026-08-03] 저장 대상과 메모리에 로드된 레시피가 다르면 저장 거부.
|
|
// MainPage.SaveRecipe 는 전역 싱글톤(DB.Dao.WeldingLinesRecipe)을 지정 경로에
|
|
// 그대로 덤프하므로, 둘이 어긋나면 레시피가 교차 복사된다.
|
|
// ReloadRecipe(MainPage.cs:466)가 기록해 둔 WorkRecipeFile 이 유일한 신원 정보다.
|
|
var loadedPath = DB.Dao.SystemRecipe.WorkRecipeFile;
|
|
if (!string.IsNullOrWhiteSpace(loadedPath) &&
|
|
!string.Equals(System.IO.Path.GetFullPath(loadedPath),
|
|
System.IO.Path.GetFullPath(targetPath),
|
|
System.StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
// 저장하지 않고 중단 - 교차 오염 차단
|
|
UtilUnit.logUnit.SetLog(LogUnit.eLogType.ALARM, "RecipeHelper.SaveRecipe",
|
|
$"저장 거부 - 메모리 레시피와 저장 대상 불일치. loaded=[{loadedPath}] target=[{targetPath}]");
|
|
return;
|
|
}
|
|
|
|
CommonHelper.GetMainPage().SaveRecipe(targetPath, includeModel);
|
|
}
|
|
|
|
[구현 시 확인 사항]
|
|
- DB.Dao.SystemRecipe.WorkRecipeFile 이 WeldingCommon 프로젝트에서 참조 가능한지
|
|
빌드로 먼저 확인할 것. RecipeHelper.cs 상단에 이미 using DB; using DB.Recipe; 가 있으나
|
|
Dao.SystemRecipe 는 LASAGUI 쪽 partial class 이므로 참조가 안 될 수 있다.
|
|
=> 참조 불가 시 대안: 동일한 가드를 LASA/GUI/Page/MainPage.cs 의 SaveRecipe(425행)
|
|
맨 앞에 넣는다. 그 파일 안에서는 DB.Dao.SystemRecipe 접근이 확실히 가능하다
|
|
(MainPage.cs:466 에서 이미 쓰고 있음).
|
|
- 로그 API(UtilUnit.logUnit.SetLog) 역시 WeldingCommon 에서 접근 안 되면
|
|
Logger 또는 MessageUtil.ShowErrorToast 로 대체할 것. 중요한 것은
|
|
"저장을 중단한다" + "불일치 사실을 로그로 남긴다" 두 가지다.
|
|
- loadedPath 가 비어 있을 때(초기 기동 등)는 기존 동작 유지(저장 허용).
|
|
처음부터 막으면 정상 저장까지 못 하게 된다.
|
|
|
|
[1단계 적용 후 반드시 할 것]
|
|
- 현장에서 며칠 운용하며 ALARM 로그에 "저장 거부 - 메모리 레시피와 저장 대상 불일치"
|
|
항목이 찍히는지 확인한다.
|
|
- 찍히면 loaded / target 값으로 어느 경로에서 어긋났는지 확정된다.
|
|
그 결과를 보고 2~4단계 중 필요한 것만 적용한다.
|
|
|
|
|
|
================================================================================
|
|
4. 수정 작업 - 2단계 (1단계 로그 확보 후)
|
|
================================================================================
|
|
목적 : 원인 (1) 차단. 대상과 내용의 갱신 순서를 바로잡는다.
|
|
"내용 로드가 성공한 뒤에만 대상을 바꾼다".
|
|
|
|
[2-A] WeldingComponents/WeldingCommon/Utils/RecipeHelper.cs 73~79행
|
|
|
|
[현재]
|
|
public static void OnActiveReloaded()
|
|
{
|
|
var activeRecipe = mRecipeManager.ActivatedRecipe();
|
|
SelectedRecipe = (activeRecipe.Id, activeRecipe.Name);
|
|
|
|
ReloadRecipe(activeRecipe.Name);
|
|
}
|
|
|
|
[변경안]
|
|
public static void OnActiveReloaded()
|
|
{
|
|
var activeRecipe = mRecipeManager.ActivatedRecipe();
|
|
|
|
// [변경 2026-08-03] 로드 성공 후에 대상(SelectedRecipe)을 갱신한다.
|
|
// 먼저 대입하면 ReloadRecipe 실패 시 대상만 새 레시피이고
|
|
// 메모리는 직전 레시피인 상태로 남아, 다음 Save 가 교차 복사가 된다.
|
|
ReloadRecipe(activeRecipe.Name);
|
|
SelectedRecipe = (activeRecipe.Id, activeRecipe.Name);
|
|
}
|
|
|
|
[2-B] WeldingComponents/WeldingCommon/Views/Recipes/UCScannerObjectTeachingViewModel.cs
|
|
163~174행
|
|
|
|
[현재]
|
|
public void OnChanged((int id, string name) recipe)
|
|
{
|
|
RecipeHelper.SelectedRecipe = recipe;
|
|
RecipeHelper.ReloadRecipe(recipe.name);
|
|
_RecipeBeforeChanged = RecipeHelper.getRecipeInfo(recipe.name);
|
|
}
|
|
|
|
public void Reloaded((int id, string name) recipe)
|
|
{
|
|
RecipeHelper.SelectedRecipe = recipe;
|
|
RecipeHelper.ReloadRecipe(recipe.name);
|
|
}
|
|
|
|
[변경안]
|
|
public void OnChanged((int id, string name) recipe)
|
|
{
|
|
// [변경 2026-08-03] 로드 성공 후에 대상 갱신 (교차 저장 방지)
|
|
RecipeHelper.ReloadRecipe(recipe.name);
|
|
RecipeHelper.SelectedRecipe = recipe;
|
|
_RecipeBeforeChanged = RecipeHelper.getRecipeInfo(recipe.name);
|
|
}
|
|
|
|
public void Reloaded((int id, string name) recipe)
|
|
{
|
|
// [변경 2026-08-03] 로드 성공 후에 대상 갱신 (교차 저장 방지)
|
|
RecipeHelper.ReloadRecipe(recipe.name);
|
|
RecipeHelper.SelectedRecipe = recipe;
|
|
}
|
|
|
|
[주의] 순서를 바꾸면 ReloadRecipe 가 예외를 던졌을 때 SelectedRecipe 가
|
|
직전 값으로 남는다. 이는 의도된 동작이다(메모리 내용과 일치하므로).
|
|
다만 화면 선택과 SelectedRecipe 가 달라질 수 있으므로,
|
|
예외 발생 시 사용자에게 토스트로 알리는 것을 함께 검토할 것.
|
|
|
|
|
|
================================================================================
|
|
5. 수정 작업 - 3단계
|
|
================================================================================
|
|
목적 : 원인 (2) 차단. PLC 레시피 전환 시 신규 Active 파일이
|
|
구 레시피 내용으로 덮어써지는 것을 막는다.
|
|
|
|
파일 : WeldingComponents/WeldingCommon/Views/Recipes/UCScannerObjectTeachingViewModel.cs
|
|
133~161행 OnActivatedRecipe
|
|
|
|
[현재 155~156행]
|
|
var activeRecipe = _RecipeManager.ActivatedRecipe();
|
|
RecipeHelper.SaveRecipe(activeRecipe.Name);
|
|
|
|
[변경안 - 택1]
|
|
|
|
(A안, 권장) SaveRecipe 호출 제거
|
|
var activeRecipe = _RecipeManager.ActivatedRecipe();
|
|
// [변경 2026-08-03] SYS_RECIPE_ACTIVATED 1홉 시점에는 메모리가 아직 구 레시피다.
|
|
// 여기서 저장하면 신규 Active 파일이 구 레시피 내용으로 덮어써진다.
|
|
// 저장이 필요하면 레시피 전환 전에 별도로 수행할 것.
|
|
// RecipeHelper.SaveRecipe(activeRecipe.Name);
|
|
|
|
(B안) 3단계 1단계 가드가 이미 들어가 있다면 그대로 두어도 가드가 막는다.
|
|
단 이때 ALARM 로그가 레시피 전환마다 찍히므로 로그 노이즈를 감수해야 한다.
|
|
A안이 더 깨끗하다.
|
|
|
|
[주의] 이 호출을 지우면 "레시피 활성화 시 자동 저장" 동작이 사라진다.
|
|
해당 동작에 의존하는 곳이 있는지 확인할 것.
|
|
RMSHandlerForPTOP.cs:171 의 주석이 이 연쇄를 의도된 설계로 기술하고 있으나,
|
|
그 RMS 핸들러 자체가 죽어 있으므로(2절 참조) 실사용 의존은 없을 가능성이 높다.
|
|
=> 현장 확인 필요.
|
|
|
|
|
|
================================================================================
|
|
6. 수정 작업 - 4단계 (선택)
|
|
================================================================================
|
|
목적 : 원인 (4) 차단. 신규 레시피 생성 시 직전 레시피 내용이 기록되는 것을 막는다.
|
|
|
|
파일 : WeldingComponents/WeldingCommon/Views/Recipes/UCScannerObjectTeachingViewModel.cs
|
|
110~115행 OnRecipeEntryChanged 의 New 분기
|
|
|
|
[현재]
|
|
if (param.AddedId != -1) { //New
|
|
var recipe = _RecipeManager.Recipes().FirstOrDefault(x => x.Id == param.AddedId);
|
|
if (recipe == null) return;
|
|
RecipeHelper.SelectedRecipe = (recipe.Id, recipe.Name);
|
|
RecipeHelper.SaveRecipe(recipe.Name, includeModel: false);
|
|
}
|
|
|
|
[변경안]
|
|
if (param.AddedId != -1) { //New
|
|
var recipe = _RecipeManager.Recipes().FirstOrDefault(x => x.Id == param.AddedId);
|
|
if (recipe == null) return;
|
|
// [변경 2026-08-03] 메모리를 새 레시피로 먼저 맞춘 뒤 저장한다.
|
|
// 그렇지 않으면 직전 레시피 내용이 신규 파일에 기록된다.
|
|
RecipeHelper.ReloadRecipe(recipe.Name);
|
|
RecipeHelper.SelectedRecipe = (recipe.Id, recipe.Name);
|
|
RecipeHelper.SaveRecipe(recipe.Name, includeModel: false);
|
|
}
|
|
|
|
[주의] 신규 생성 직후 파일이 아직 없거나 비어 있으면 ReloadRecipe 가
|
|
실패할 수 있다. 이 경우 try/catch 로 감싸고 실패 시 저장을 건너뛸 것.
|
|
빈 레시피를 만드는 것이 목적이라면 SaveRecipe 자체가 불필요할 수도 있다.
|
|
=> 실동작 확인 후 적용. 4단계는 필수가 아니다.
|
|
|
|
|
|
================================================================================
|
|
7. 이번 작업에서 하지 않을 것
|
|
================================================================================
|
|
- RMSHandlerForPTOP 수정 : 죽은 코드다. 고쳐도 증상은 재발한다.
|
|
- EquipmentSetup.cs:282 RollbackRecipe 주석 해제 : 의미 없는 동작이다.
|
|
되돌릴 원본(Auto 진입 이전 선택 레시피)을 백업하는 코드가 없기 때문이다.
|
|
진짜 롤백이 필요하면 별도 백업 필드 신설이 선행되어야 하며 별건으로 다룬다.
|
|
- SeqAutoRunPTOP.cs 의 CheckRecipeNoComp 수정 : 별건(2026-06-21 분석 참조).
|
|
|
|
|
|
================================================================================
|
|
8. 검증 절차
|
|
================================================================================
|
|
[빌드]
|
|
1) ILSOS_All.sln 을 Visual Studio 2022 로 열고 Release|x64 빌드.
|
|
2) 경고를 "사소한 것"으로 넘기지 말 것. 빌드 실패 시 진행 중단.
|
|
|
|
[기능 확인 - 정상 경로가 깨지지 않았는지]
|
|
3) Manual 상태에서 Recipe 화면 진입 -> 레시피 A 선택 -> 파라미터 수정 -> Save
|
|
-> A 파일만 바뀌었는지 확인 (B, Active 레시피 파일 타임스탬프 불변 확인)
|
|
4) 레시피 B 선택 -> Save -> B 파일만 바뀌는지 확인
|
|
5) 레시피 전환(A->B->A)을 10회 반복 후 A/B 내용이 서로 섞이지 않았는지 확인
|
|
6) AutoRun 기동 -> PLC 레시피 전환 발생 -> Manual 복귀 -> Recipe 화면에서
|
|
선택 레시피 Save -> 엉뚱한 파일이 바뀌지 않는지 확인
|
|
|
|
[로그 확인]
|
|
7) ALARM 로그에 "저장 거부 - 메모리 레시피와 저장 대상 불일치" 가 찍히는지 확인.
|
|
찍힌다면 loaded / target 경로를 기록해 둘 것. 원인 경로 확정 근거가 된다.
|
|
8) 함께 확인할 기존 ALARM 항목:
|
|
ReloadRecipe / UpdateWeldingLinesRecipe / LoadFieldHelper
|
|
사고 시각 근처에 이 항목이 있으면 원인 (1)이 확정된다.
|
|
|
|
[백업]
|
|
9) 작업 전 D:\ILSOSConfig\ILSOS_PrismaticRD_PTOP\_config_recipe 폴더를
|
|
통째로 복사해 둘 것. 검증 중 레시피가 오염될 수 있다.
|
|
|
|
|
|
================================================================================
|
|
9. 확인이 필요한 항목 (미확정 - 추측으로 메우지 말 것)
|
|
================================================================================
|
|
1) 현장 PC 에 배포된 바이너리가 이 소스와 동일한지 미확인.
|
|
다르면 "RMSHandlerForPTOP 은 죽은 코드" 판정이 뒤집힌다.
|
|
=> 설비 로그에서 아래 문자열을 검색해 판별할 것.
|
|
"Complete OnParameterReadRequest"
|
|
"RMS Change Recipe Parameter"
|
|
하나라도 나오면 RMS 핸들러가 살아 있는 빌드이므로 재분석 필요.
|
|
|
|
2) 원인 (1)의 실제 발생 여부 미측정. 3단계 1단계 가드 로그로 확정한다.
|
|
|
|
3) Aurora 바이너리(External/Aurora/bin)의 UCRecipe 호출 규약 미확인.
|
|
OnChanged / Reloaded / OnSaved 가 언제 호출되는지 소스가 없어 알 수 없다.
|
|
PreSaved 가 false 를 반환할 때 Aurora 가 실제로 저장을 중단하는지도 미확인.
|
|
|
|
4) UCScannerObjectTeachingViewModel.cs:189-192 가 Auto 상태 Save 를 막고 있다.
|
|
따라서 "AutoRun 에서도 발생" 이라는 현장 보고 자체가 검증 대상이다.
|
|
=> 발생 당시 설비가 정말 Auto 였는지 재확인 요청.
|
|
|
|
5) _config_recipe 실물 파일 구조 미보유 -> Recipe.cs:64 무동작 가설 미검증.
|
|
|
|
|
|
================================================================================
|
|
10. 변경 파일 요약
|
|
================================================================================
|
|
1단계 : WeldingComponents/WeldingCommon/Utils/RecipeHelper.cs (36-39행)
|
|
또는 WeldingComponents/LASA/GUI/Page/MainPage.cs (425행)
|
|
2단계 : WeldingComponents/WeldingCommon/Utils/RecipeHelper.cs (73-79행)
|
|
WeldingComponents/WeldingCommon/Views/Recipes/UCScannerObjectTeachingViewModel.cs (163-174행)
|
|
3단계 : WeldingComponents/WeldingCommon/Views/Recipes/UCScannerObjectTeachingViewModel.cs (155-156행)
|
|
4단계 : WeldingComponents/WeldingCommon/Views/Recipes/UCScannerObjectTeachingViewModel.cs (110-115행)
|
|
|
|
전부 WeldingComponents 하위 => 사전 승인 필요.
|
|
ILSOS_PrismaticRD_PTOP 소스는 이번 작업에서 수정하지 않는다.
|
|
|
|
================================================================================
|
|
끝.
|
|
================================================================================
|