170 lines
7.6 KiB
C#

using Aurora;
using Aurora.Api;
using Aurora.Api.Manager;
using DB;
using DB.Recipe;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Windows;
using VisionCommon;
using WeldingCommon.Sequences;
namespace WeldingCommon.Utils
{
public static class RecipeHelper
{
public static (int id, string name) SelectedRecipe;
static Logger Log = new Logger("RecipeHelper"); // [추가 2026-08-04]
static IRecipeManager mRecipeManager = Application.Current.AuroraEnv().RecipeManager;
static string GetTeachingEditorFullPath(string recipeName)
{
var recipePath = ConfigurationManager.AppSettings.Get("DATA_PATH");
var fullPath = Path.Combine(
recipePath,
RecipeExIds.RECIPE_DIR,
recipeName,
RecipeExIds.TEACHING_EDITOR_RECIPE);
var dir = Path.GetDirectoryName(fullPath);
if (!Directory.Exists(dir)) {
Directory.CreateDirectory(Path.GetDirectoryName(fullPath));
}
return fullPath;
}
public static void SaveRecipe(string recipeName, bool includeModel = true)
{
var targetPath = GetTeachingEditorFullPath(recipeName);
// [추가 2026-08-04] 관측 전용. 저장을 막지 않는다.
// 기준은 DB.Recipe.Recipe.SelectedRecipeFile - Recipe.Load(string) 성공 시에만
// Recipe.cs:69 에서 세팅되며 디스크를 거치지 않는다.
// (Dao.SystemRecipe.WorkRecipeFile 은 SystemParameterILSOS.json 에 영속되고
// Aurora SystemParameter 와 파일을 공유하므로 신원 기준으로 쓸 수 없다)
// 두 조건은 독립 신호이므로 else if 로 묶지 않는다.
var loaded = DB.Recipe.Recipe.SelectedRecipeFile;
if (string.IsNullOrWhiteSpace(loaded)) {
Log.W($"[관측] 메모리 신원 없음(로드 이력 없음). target=[{targetPath}]");
}
if (!string.IsNullOrWhiteSpace(loaded) &&
!string.Equals(loaded, targetPath, StringComparison.OrdinalIgnoreCase)) {
Log.W($"[관측] 메모리/대상 불일치. loaded=[{loaded}] target=[{targetPath}]");
}
CommonHelper.GetMainPage().SaveRecipe(targetPath, includeModel);
// 아래는 이번 저장과 무관한 다른 경로(ReloadSetting/UpdateScoutField/콤보박스)에서
// 누적된 것일 수 있다. 경로는 각 항목의 파일명으로 판독한다.
if (DB.RecipeFieldScan.SkippedEmptySaveCount > 0 || DB.RecipeFieldScan.LastSaveError != null) {
Log.W($"[관측] FieldHelper 저장 생략 {DB.RecipeFieldScan.SkippedEmptySaveCount}회 " +
$"(대상 {DB.RecipeFieldScan.SkippedFiles.Count}종: {string.Join(" | ", DB.RecipeFieldScan.SkippedFiles)}), " +
$"최근오류=[{DB.RecipeFieldScan.LastSaveError}] ※직전 저장과 무관할 수 있음");
DB.RecipeFieldScan.SkippedEmptySaveCount = 0;
DB.RecipeFieldScan.SkippedFiles.Clear();
DB.RecipeFieldScan.LastSaveError = null;
}
}
public static void OnSaveRecipeForEditing()
{
if (string.IsNullOrWhiteSpace(SelectedRecipe.name)) {
return;
}
SaveRecipe(SelectedRecipe.name);
if (SelectedRecipe.name == mRecipeManager.ActivatedRecipe().Name) {
CommonHelper.UpdateAutoRunPage();
}
}
public static void UpdateAutorunRecipe()
{
if (string.IsNullOrWhiteSpace(SelectedRecipe.name)) {
return;
}
if (SelectedRecipe.name == mRecipeManager.ActivatedRecipe().Name) {
CommonHelper.UpdateAutoRunPage();
}
}
public static void ReloadRecipe(string recipeName)
{
// ═══ [진단계측 2026-08-04] 시작 ═══════════════════════════════════
// 원본 3줄 (try 블록 안의 3줄이 원본 그대로다) :
// var camConfig = VisionEnv.AuroraEnv.DeviceManager.GetDeviceConfig(eCamId.CAM1.ToString()) as CamConfig;
// CommonHelper.GetMainPage().UpdateDefaultField(camConfig.ChildImage.ChildBufRowCols);
// CommonHelper.GetMainPage().ReloadRecipe(GetTeachingEditorFullPath(recipeName));
// 내용 전환의 성공/실패/무동작을 구분해 기록한다. 동작은 그대로다.
// 원복 : try/catch 와 Mark 호출을 걷어내고 위 원본 3줄만 남긴다.
var before = RecipeTrace.MemFingerprint();
RecipeTrace.Mark("내용변경 RELOAD 진입", $"요청=[{recipeName}] 지문(전)={before}");
try {
var camConfig = VisionEnv.AuroraEnv.DeviceManager.GetDeviceConfig(eCamId.CAM1.ToString()) as CamConfig;
CommonHelper.GetMainPage().UpdateDefaultField(camConfig.ChildImage.ChildBufRowCols);
CommonHelper.GetMainPage().ReloadRecipe(GetTeachingEditorFullPath(recipeName));
var after = RecipeTrace.MemFingerprint();
RecipeTrace.Mark(before == after ? "RELOAD 완료(내용무변화!)" : "RELOAD 완료",
$"요청=[{recipeName}] 지문(후)={after}");
} catch (System.Exception ex) {
RecipeTrace.Mark("*** RELOAD 실패 ***",
$"요청=[{recipeName}] {ex.GetType().Name}: {ex.Message}");
throw; // 기존 동작 보존 — 예외 전파는 그대로
}
// ═══ [진단계측 2026-08-04] 끝 ═════════════════════════════════════
}
public static RecipeWeldingLines getRecipeInfo(string recipeName) => CommonHelper.GetMainPage().getRecipeInfo(GetTeachingEditorFullPath(recipeName));
public static void OnActiveReloaded()
{
var activeRecipe = mRecipeManager.ActivatedRecipe();
SelectedRecipe = (activeRecipe.Id, activeRecipe.Name);
ReloadRecipe(activeRecipe.Name);
}
public static void OnActiveRecipe(int recipeId, string recipeName)
{
mRecipeManager.ActivateRecipe(recipeId, recipeName);
}
public static string SearchRecipeItem(int recipeID)
{
string recipeName = string.Empty;
var listRecipe = mRecipeManager.Recipes();
// Find the recipe with the matching ID
var recipe = listRecipe.FirstOrDefault(r => r.Id == recipeID);
// If a recipe is found, assign its name to recipeName
if (recipe != null) {
recipeName = recipe.Name;
}
return recipeName;
}
//LASA는 Recipe를 1개만 사용 할 수 있음
//TechingRecipe -> ActiavatedReicpe(AutoRun) -> TeachingRecipe
//AutoRun 완료 후 다시 Teching 중인 Recipe로 Rollback 해줘야 함
public static void RollbackRecipe()
{
Application.Current.Dispatcher.InvokeAsync(() => {
ReloadRecipe(SelectedRecipe.name);
});
}
public static bool OnChangeRecipe(int RecipeID)
{
IList<RecipeInfo> recipes = mRecipeManager.Recipes();
//list 에서 정보 얻을 수 있는것을 찾아보자
return true;
}
}
}