Added complete manual print dialog to Web UI based on fManualPrint.cs: - Created ManualPrintDialog component with all input fields (SID, Vendor Lot, Qty, MFG Date, Reel ID, Supplier, Part No) - Added printer selection (Left/Right), print count, delete after print checkbox, and barcode input - Implemented ExecuteManualPrint backend method with ZPL label generation and printer integration - Added WebSocketServer handler for EXECUTE_MANUAL_PRINT command with full parameter support - Integrated dialog into Header component with proper error handling via AlertContext 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
1438 lines
57 KiB
C#
1438 lines
57 KiB
C#
using System;
|
||
using System.Runtime.InteropServices;
|
||
using System.Windows.Forms;
|
||
using Newtonsoft.Json;
|
||
using System.IO;
|
||
using System.Linq;
|
||
using System.Collections.Generic;
|
||
using AR;
|
||
|
||
namespace Project.WebUI
|
||
{
|
||
// Important: Allows JavaScript to see this class
|
||
[ClassInterface(ClassInterfaceType.AutoDual)]
|
||
[ComVisible(true)]
|
||
public class MachineBridge
|
||
{
|
||
// Reference to the main form to update logic
|
||
private Project.Dialog.fWebView _host;
|
||
|
||
// Data folder paths
|
||
private readonly string _dataFolder;
|
||
private readonly string _settingsPath;
|
||
private readonly string _recipeFolder;
|
||
|
||
public MachineBridge(Project.Dialog.fWebView host)
|
||
{
|
||
_host = host;
|
||
|
||
// Initialize data folder paths - use existing Data folder
|
||
_dataFolder = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Data");
|
||
_settingsPath = Path.Combine(_dataFolder, "Setting.json");
|
||
_recipeFolder = Path.Combine(_dataFolder, "recipe");
|
||
|
||
// Ensure folders exist
|
||
EnsureDataFoldersExist();
|
||
}
|
||
|
||
private void EnsureDataFoldersExist()
|
||
{
|
||
try
|
||
{
|
||
if (!Directory.Exists(_dataFolder))
|
||
Directory.CreateDirectory(_dataFolder);
|
||
|
||
if (!Directory.Exists(_recipeFolder))
|
||
Directory.CreateDirectory(_recipeFolder);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Console.WriteLine($"[ERROR] Failed to create data folders: {ex.Message}");
|
||
}
|
||
}
|
||
|
||
// --- Methods called from React ---
|
||
|
||
public void MoveAxis(string axis, double value)
|
||
{
|
||
Console.WriteLine($"[C#] Moving {axis} to {value}");
|
||
_host.SetTargetPosition(axis, value);
|
||
}
|
||
|
||
public void SetIO(int id, bool isInput, bool state)
|
||
{
|
||
Console.WriteLine($"[C#] Set IO {id} to {state}");
|
||
_host.SetOutput(id, state);
|
||
}
|
||
|
||
public void SystemControl(string command)
|
||
{
|
||
Console.WriteLine($"[C#] CMD: {command}");
|
||
_host.HandleCommand(command);
|
||
}
|
||
|
||
public string InitializeDevice()
|
||
{
|
||
Console.WriteLine($"[C#] Initialize Device Request");
|
||
|
||
try
|
||
{
|
||
// Check if motion is initialized
|
||
if (PUB.flag.get(eVarBool.FG_INIT_MOTIO) == false)
|
||
{
|
||
var response = new { success = false, message = "Motion not initialized\nPlease try again later" };
|
||
return JsonConvert.SerializeObject(response);
|
||
}
|
||
|
||
var errors = new List<string>();
|
||
|
||
// Check if system is running
|
||
if (PUB.sm.isRunning == true)
|
||
errors.Add("AUTO-RUN MODE - Cannot be used during automatic execution. Please stop and try again");
|
||
|
||
// Check AIR supply
|
||
if (DIO.GetIOOutput(eDOName.SOL_AIR) == false)
|
||
errors.Add("Press the AIR button on the front to supply AIR");
|
||
|
||
// Check printer pickers
|
||
if (DIO.GetIOInput(eDIName.L_PICK_BW) == false)
|
||
errors.Add("Left printer picker is not in reverse position");
|
||
|
||
if (DIO.GetIOInput(eDIName.R_PICK_BW) == false)
|
||
errors.Add("Right printer picker is not in reverse position");
|
||
|
||
// Check picker cylinders
|
||
if (SETTING.Data.Enable_PickerCylinder)
|
||
{
|
||
if (DIO.GetIOInput(eDIName.L_CYLUP) == false)
|
||
errors.Add("Left printer picker cylinder is not in UP position");
|
||
|
||
if (DIO.GetIOInput(eDIName.R_CYLUP) == false)
|
||
errors.Add("Right printer picker cylinder is not in UP position");
|
||
}
|
||
|
||
// Check emergency stop
|
||
if (DIO.IsEmergencyOn() == true)
|
||
errors.Add("Cannot move when in emergency stop state");
|
||
|
||
// Check if running
|
||
if (PUB.sm.Step == eSMStep.RUN)
|
||
errors.Add("Cannot initialize while in operation");
|
||
|
||
if (errors.Count > 0)
|
||
{
|
||
var response = new { success = false, message = string.Join("\n", errors) };
|
||
return JsonConvert.SerializeObject(response);
|
||
}
|
||
|
||
// Start initialization
|
||
PUB.log.Add("User Request: Initialize Device", false);
|
||
PUB.sm.SetNewStep(eSMStep.HOME_FULL);
|
||
|
||
var response2 = new { success = true, message = "Device initialization started" };
|
||
return JsonConvert.SerializeObject(response2);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Console.WriteLine($"[ERROR] Failed to initialize device: {ex.Message}");
|
||
var response = new { success = false, message = ex.Message };
|
||
return JsonConvert.SerializeObject(response);
|
||
}
|
||
}
|
||
|
||
public string GetInitializeStatus()
|
||
{
|
||
try
|
||
{
|
||
var status = new
|
||
{
|
||
isInitializing = PUB.sm.Step == eSMStep.HOME_FULL,
|
||
currentStep = PUB.sm.Step.ToString(),
|
||
axes = new List<object>
|
||
{
|
||
new { name = "PZ_PICK", axisIndex = (int)eAxis.PZ_PICK, isHomeSet = PUB.mot.IsHomeSet((short)eAxis.PZ_PICK), progress = GetAxisProgress(eAxis.PZ_PICK) },
|
||
new { name = "PL_UPDN", axisIndex = (int)eAxis.PL_UPDN, isHomeSet = PUB.mot.IsHomeSet((short)eAxis.PL_UPDN), progress = GetAxisProgress(eAxis.PL_UPDN) },
|
||
new { name = "PR_UPDN", axisIndex = (int)eAxis.PR_UPDN, isHomeSet = PUB.mot.IsHomeSet((short)eAxis.PR_UPDN), progress = GetAxisProgress(eAxis.PR_UPDN) },
|
||
new { name = "PL_MOVE", axisIndex = (int)eAxis.PL_MOVE, isHomeSet = PUB.mot.IsHomeSet((short)eAxis.PL_MOVE), progress = GetAxisProgress(eAxis.PL_MOVE) },
|
||
new { name = "PR_MOVE", axisIndex = (int)eAxis.PR_MOVE, isHomeSet = PUB.mot.IsHomeSet((short)eAxis.PR_MOVE), progress = GetAxisProgress(eAxis.PR_MOVE) },
|
||
new { name = "Z_THETA", axisIndex = (int)eAxis.Z_THETA, isHomeSet = PUB.mot.IsHomeSet((short)eAxis.Z_THETA), progress = GetAxisProgress(eAxis.Z_THETA) },
|
||
new { name = "PX_PICK", axisIndex = (int)eAxis.PX_PICK, isHomeSet = PUB.mot.IsHomeSet((short)eAxis.PX_PICK), progress = GetAxisProgress(eAxis.PX_PICK) }
|
||
}
|
||
};
|
||
|
||
return JsonConvert.SerializeObject(status);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Console.WriteLine($"[ERROR] Failed to get initialize status: {ex.Message}");
|
||
return JsonConvert.SerializeObject(new { isInitializing = false, currentStep = "ERROR", axes = new List<object>() });
|
||
}
|
||
}
|
||
|
||
private int GetAxisProgress(eAxis axis)
|
||
{
|
||
// Return 100 if home is set, otherwise check motion status
|
||
if (PUB.mot.IsHomeSet((short)axis))
|
||
return 100;
|
||
|
||
// Check if axis is in motion
|
||
if (PUB.mot.IsMotion((short)axis))
|
||
return 50; // In progress
|
||
|
||
// Check if home search started
|
||
if (PUB.mot.IsOrg((short)axis) || PUB.mot.IsLimitN((short)axis))
|
||
return 75; // Near completion
|
||
|
||
return 0; // Not started
|
||
}
|
||
|
||
/// <summary>
|
||
/// 마이그레이션완료
|
||
/// </summary>
|
||
/// <param name="recipeTitle"></param>
|
||
/// <returns></returns>
|
||
public string SelectRecipe(string recipeTitle)
|
||
{
|
||
Console.WriteLine($"[C#] Selecting Recipe: {recipeTitle}");
|
||
|
||
try
|
||
{
|
||
// Check if system is running
|
||
if (PUB.sm.Step == eSMStep.RUN || PUB.sm.Step == eSMStep.WAITSTART || PUB.sm.Step == eSMStep.PAUSE)
|
||
{
|
||
var response = new { success = false, message = "Cannot change model while system is currently running (waiting)" };
|
||
return JsonConvert.SerializeObject(response);
|
||
}
|
||
|
||
// Select model using PUB.SelectModelV
|
||
bool result = PUB.SelectModelV(recipeTitle, true);
|
||
|
||
if (result)
|
||
{
|
||
// Select motion model based on conveyor usage
|
||
var motionmode = VAR.BOOL[eVarBool.Use_Conveyor] ? "Conveyor" : "Default";
|
||
bool changeMot = PUB.SelectModelM(motionmode);
|
||
if (changeMot == false)
|
||
{
|
||
PUB.log.AddE($"No Motion model ({motionmode})");
|
||
}
|
||
|
||
Console.WriteLine($"[INFO] Recipe {recipeTitle} selected successfully with motion mode: {motionmode}");
|
||
|
||
// Get the selected model data
|
||
var dr = PUB.mdm.GetDataV(recipeTitle);
|
||
if (dr == null)
|
||
{
|
||
var response = new { success = false, message = "Recipe data not found" };
|
||
return JsonConvert.SerializeObject(response);
|
||
}
|
||
|
||
// Convert DataRow to Dictionary
|
||
var recipeData = new Dictionary<string, object>();
|
||
foreach (System.Data.DataColumn col in dr.Table.Columns)
|
||
{
|
||
string colName = col.ColumnName;
|
||
object value = dr[colName];
|
||
|
||
// DBNull을 null로 변환
|
||
if (value == DBNull.Value)
|
||
value = null;
|
||
|
||
recipeData[colName] = value;
|
||
}
|
||
|
||
var response2 = new { success = true, message = "Recipe selected successfully", recipeId = recipeTitle, recipe = recipeData };
|
||
return JsonConvert.SerializeObject(response2);
|
||
}
|
||
else
|
||
{
|
||
var response = new { success = false, message = "Failed to select recipe" };
|
||
return JsonConvert.SerializeObject(response);
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Console.WriteLine($"[ERROR] Failed to select recipe: {ex.Message}");
|
||
var response = new { success = false, message = ex.Message };
|
||
return JsonConvert.SerializeObject(response);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// <20><><EFBFBD>̱<CCB1><D7B7>̼<EFBFBD> <20><><EFBFBD><EFBFBD>
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
public string GetConfig()
|
||
{
|
||
try
|
||
{
|
||
// Use SETTING.Data (CommonSetting) from the project
|
||
if (SETTING.Data == null)
|
||
{
|
||
Console.WriteLine($"[WARN] SETTING.Data is not initialized");
|
||
return "[]";
|
||
}
|
||
|
||
var settingsArray = new List<object>();
|
||
var properties = SETTING.Data.GetType().GetProperties();
|
||
|
||
foreach (var prop in properties)
|
||
{
|
||
// Skip non-browsable properties
|
||
var browsable = prop.GetCustomAttributes(typeof(System.ComponentModel.BrowsableAttribute), false)
|
||
.FirstOrDefault() as System.ComponentModel.BrowsableAttribute;
|
||
if (browsable != null && !browsable.Browsable)
|
||
continue;
|
||
|
||
// Skip filename property
|
||
if (prop.Name == "filename")
|
||
continue;
|
||
|
||
// Get property info
|
||
string key = prop.Name;
|
||
object value = prop.GetValue(SETTING.Data, null);
|
||
string type = "String";
|
||
string group = "General";
|
||
string description = key.Replace("_", " ");
|
||
|
||
// Get Category attribute
|
||
var categoryAttr = prop.GetCustomAttributes(typeof(System.ComponentModel.CategoryAttribute), false)
|
||
.FirstOrDefault() as System.ComponentModel.CategoryAttribute;
|
||
if (categoryAttr != null)
|
||
group = categoryAttr.Category;
|
||
|
||
// Get DisplayName attribute
|
||
var displayNameAttr = prop.GetCustomAttributes(typeof(System.ComponentModel.DisplayNameAttribute), false)
|
||
.FirstOrDefault() as System.ComponentModel.DisplayNameAttribute;
|
||
if (displayNameAttr != null)
|
||
description = displayNameAttr.DisplayName;
|
||
|
||
// Get Description attribute
|
||
var descAttr = prop.GetCustomAttributes(typeof(System.ComponentModel.DescriptionAttribute), false)
|
||
.FirstOrDefault() as System.ComponentModel.DescriptionAttribute;
|
||
if (descAttr != null)
|
||
description = descAttr.Description;
|
||
|
||
// Determine type based on property type
|
||
if (prop.PropertyType == typeof(bool))
|
||
{
|
||
type = "Boolean";
|
||
value = value?.ToString().ToLower() ?? "false";
|
||
}
|
||
else if (prop.PropertyType == typeof(int) || prop.PropertyType == typeof(long) ||
|
||
prop.PropertyType == typeof(double) || prop.PropertyType == typeof(float))
|
||
{
|
||
type = "Number";
|
||
value = value?.ToString() ?? "0";
|
||
}
|
||
else
|
||
{
|
||
value = value?.ToString() ?? "";
|
||
}
|
||
|
||
settingsArray.Add(new
|
||
{
|
||
Key = key,
|
||
Value = value,
|
||
Group = group,
|
||
Type = type,
|
||
Description = description
|
||
});
|
||
}
|
||
|
||
Console.WriteLine($"[INFO] Loaded {settingsArray.Count} settings from SETTING.Data");
|
||
return JsonConvert.SerializeObject(settingsArray);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Console.WriteLine($"[ERROR] Failed to load settings: {ex.Message}");
|
||
return "[]";
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// <20><><EFBFBD>̱<CCB1><D7B7>̼Ǽ<CCBC><C7BC><EFBFBD>
|
||
/// </summary>
|
||
/// <param name="configJson"></param>
|
||
public void SaveConfig(string configJson)
|
||
{
|
||
try
|
||
{
|
||
Console.WriteLine($"[Backend] SAVE CONFIG REQUEST RECEIVED");
|
||
|
||
// Parse array format from React
|
||
var settingsArray = JsonConvert.DeserializeObject<List<Dictionary<string, object>>>(configJson);
|
||
|
||
// Update SETTING.Data properties
|
||
var properties = SETTING.Data.GetType().GetProperties();
|
||
|
||
foreach (var item in settingsArray)
|
||
{
|
||
string key = item["Key"].ToString();
|
||
string value = item["Value"].ToString();
|
||
string type = item["Type"].ToString();
|
||
|
||
var prop = properties.FirstOrDefault(p => p.Name == key);
|
||
if (prop == null || !prop.CanWrite)
|
||
continue;
|
||
|
||
// Convert value based on type
|
||
try
|
||
{
|
||
if (type == "Boolean")
|
||
{
|
||
prop.SetValue(SETTING.Data, bool.Parse(value), null);
|
||
}
|
||
else if (type == "Number")
|
||
{
|
||
if (prop.PropertyType == typeof(int))
|
||
prop.SetValue(SETTING.Data, int.Parse(value), null);
|
||
else if (prop.PropertyType == typeof(long))
|
||
prop.SetValue(SETTING.Data, long.Parse(value), null);
|
||
else if (prop.PropertyType == typeof(double))
|
||
prop.SetValue(SETTING.Data, double.Parse(value), null);
|
||
else if (prop.PropertyType == typeof(float))
|
||
prop.SetValue(SETTING.Data, float.Parse(value), null);
|
||
}
|
||
else
|
||
{
|
||
prop.SetValue(SETTING.Data, value, null);
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Console.WriteLine($"[WARN] Failed to set property {key}: {ex.Message}");
|
||
}
|
||
}
|
||
|
||
// Save to file
|
||
SETTING.Data.Save();
|
||
|
||
Console.WriteLine($"[INFO] Settings saved successfully");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Console.WriteLine($"[ERROR] Failed to save settings: {ex.Message}");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 마이그레이션완료
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
public string GetIOList()
|
||
{
|
||
try
|
||
{
|
||
var result = new
|
||
{
|
||
inputs = GetDigitalInputs(),
|
||
outputs = GetDigitalOutputs(),
|
||
interlocks = GetInterlocks()
|
||
};
|
||
|
||
return JsonConvert.SerializeObject(result);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Console.WriteLine($"[ERROR] Failed to get IO list: {ex.Message}");
|
||
return JsonConvert.SerializeObject(new { inputs = new List<object>(), outputs = new List<object>(), interlocks = new List<object>() });
|
||
}
|
||
}
|
||
/// <summary>
|
||
/// 마이그레이션완료
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
private List<object> GetDigitalInputs()
|
||
{
|
||
var inputs = new List<object>();
|
||
|
||
try
|
||
{
|
||
var diNames = DIO.Pin.GetDIName;
|
||
var diPinNames = DIO.Pin.GetDIPinName;
|
||
int diCount = PUB.dio.GetDICount;
|
||
|
||
for (int i = 0; i < diCount; i++)
|
||
{
|
||
bool state = PUB.dio.GetDIValue(i);
|
||
string name = i < diNames.Length ? diNames[i] : $"DIN_{i:D2}";
|
||
string pinName = i < diPinNames.Length ? diPinNames[i] : $"X{i:D2}";
|
||
|
||
inputs.Add(new
|
||
{
|
||
id = i,
|
||
name = name,
|
||
pinName = pinName,
|
||
type = "input",
|
||
state = state
|
||
});
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Console.WriteLine($"[ERROR] Failed to get digital inputs: {ex.Message}");
|
||
}
|
||
|
||
return inputs;
|
||
}
|
||
/// <summary>
|
||
/// 마이그레이션완료
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
private List<object> GetDigitalOutputs()
|
||
{
|
||
var outputs = new List<object>();
|
||
|
||
try
|
||
{
|
||
var doNames = DIO.Pin.GetDOName;
|
||
var doPinNames = DIO.Pin.GetDOPinName;
|
||
int doCount = PUB.dio.GetDOCount;
|
||
|
||
for (int i = 0; i < doCount; i++)
|
||
{
|
||
bool state = PUB.dio.GetDOValue(i);
|
||
string name = i < doNames.Length ? doNames[i] : $"DOUT_{i:D2}";
|
||
string pinName = i < doPinNames.Length ? doPinNames[i] : $"Y{i:D2}";
|
||
|
||
outputs.Add(new
|
||
{
|
||
id = i,
|
||
name = name,
|
||
pinName = pinName,
|
||
type = "output",
|
||
state = state
|
||
});
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Console.WriteLine($"[ERROR] Failed to get digital outputs: {ex.Message}");
|
||
}
|
||
|
||
return outputs;
|
||
}
|
||
/// <summary>
|
||
/// 마이그레이션완료
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
private List<object> GetInterlocks()
|
||
{
|
||
var interlocks = new List<object>();
|
||
|
||
try
|
||
{
|
||
for (int i = 0; i < PUB.iLock.Length; i++)
|
||
{
|
||
var axisName = ((AR.eAxis)i).ToString();
|
||
var nonAxis = false;
|
||
|
||
// Check if this is a non-axis interlock (i >= 7)
|
||
if (i >= 7)
|
||
{
|
||
axisName = PUB.iLock[i].Tag.ToString();
|
||
nonAxis = true;
|
||
}
|
||
|
||
// Get enum names based on axis index
|
||
string[] ilockNames;
|
||
if (i == 7) ilockNames = Enum.GetNames(typeof(eILockPRL));
|
||
else if (i == 8) ilockNames = Enum.GetNames(typeof(eILockPRR));
|
||
else if (i == 9) ilockNames = Enum.GetNames(typeof(eILockVS0));
|
||
else if (i == 10) ilockNames = Enum.GetNames(typeof(eILockVS1));
|
||
else if (i == 11) ilockNames = Enum.GetNames(typeof(eILockVS2));
|
||
else if (i == 12 || i == 13) ilockNames = Enum.GetNames(typeof(eILockCV));
|
||
else ilockNames = Enum.GetNames(typeof(eILock));
|
||
|
||
// Get interlock values (up to 64 bits)
|
||
var lockValues = new List<object>();
|
||
for (int j = 0; j < ilockNames.Length && j < 64; j++)
|
||
{
|
||
bool state = PUB.iLock[i].get(j);
|
||
lockValues.Add(new
|
||
{
|
||
id = j,
|
||
name = ilockNames[j],
|
||
state = state
|
||
});
|
||
}
|
||
|
||
interlocks.Add(new
|
||
{
|
||
axisIndex = i,
|
||
axisName = axisName,
|
||
nonAxis = nonAxis,
|
||
locks = lockValues,
|
||
hexValue = PUB.iLock[i].Value().HexString()
|
||
});
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Console.WriteLine($"[ERROR] Failed to get interlocks: {ex.Message}");
|
||
}
|
||
|
||
return interlocks;
|
||
}
|
||
|
||
|
||
/// <summary>
|
||
/// 마이그레이션완료
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
public string GetRecipeList()
|
||
{
|
||
//PUB.mdm.dataSet.OPModel에 등록된 데이터가 모델 목록이다
|
||
|
||
try
|
||
{
|
||
var recipes = new List<object>();
|
||
|
||
if (PUB.mdm == null || PUB.mdm.dataSet == null || PUB.mdm.dataSet.OPModel == null)
|
||
{
|
||
Console.WriteLine($"[WARN] OPModel is not initialized");
|
||
return JsonConvert.SerializeObject(recipes);
|
||
}
|
||
|
||
// OPModel 테이블에서 Title이 비어있지 않은 항목만 가져오기
|
||
foreach (var row in PUB.mdm.dataSet.OPModel)
|
||
{
|
||
var modelRow = row as DataSet1.OPModelRow;
|
||
if (modelRow == null) continue;
|
||
|
||
// Title이 비어있으면 스킵
|
||
if (string.IsNullOrEmpty(modelRow.Title))
|
||
continue;
|
||
|
||
recipes.Add(new
|
||
{
|
||
id = modelRow.idx.ToString(),
|
||
name = modelRow.Title,
|
||
lastModified = DateTime.Now.ToString("yyyy-MM-dd")
|
||
});
|
||
}
|
||
|
||
Console.WriteLine($"[INFO] Loaded {recipes.Count} recipes from OPModel");
|
||
return JsonConvert.SerializeObject(recipes);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Console.WriteLine($"[ERROR] Failed to get recipe list: {ex.Message}");
|
||
return "[]";
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 마이그레이션완료
|
||
/// </summary>
|
||
/// <param name="recipeTitle"></param>
|
||
/// <returns></returns>
|
||
public string GetRecipe(string recipeTitle)
|
||
{
|
||
try
|
||
{
|
||
var dr = PUB.mdm.GetDataV(recipeTitle);
|
||
|
||
if (dr == null)
|
||
{
|
||
var response = new { success = false, message = "Recipe not found" };
|
||
return JsonConvert.SerializeObject(response);
|
||
}
|
||
|
||
// DataRow의 모든 컬럼을 Dictionary로 변환
|
||
var recipeData = new Dictionary<string, object>();
|
||
foreach (System.Data.DataColumn col in dr.Table.Columns)
|
||
{
|
||
string colName = col.ColumnName;
|
||
object value = dr[colName];
|
||
|
||
// DBNull을 null로 변환
|
||
if (value == DBNull.Value)
|
||
value = null;
|
||
|
||
recipeData[colName] = value;
|
||
}
|
||
|
||
Console.WriteLine($"[INFO] Loaded recipe {recipeTitle}");
|
||
return JsonConvert.SerializeObject(recipeData);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Console.WriteLine($"[ERROR] Failed to get recipe {recipeTitle}: {ex.Message}");
|
||
var response = new { success = false, message = ex.Message };
|
||
return JsonConvert.SerializeObject(response);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 마이그레이션완료
|
||
/// </summary>
|
||
/// <param name="recipeTitle"></param>
|
||
/// <param name="recipeData"></param>
|
||
/// <returns></returns>
|
||
public string SaveRecipe(string recipeTitle, string recipeData)
|
||
{
|
||
try
|
||
{
|
||
var dr = PUB.mdm.GetDataV(recipeTitle);
|
||
|
||
if (dr == null)
|
||
{
|
||
var response = new { success = false, message = "Recipe not found" };
|
||
return JsonConvert.SerializeObject(response);
|
||
}
|
||
|
||
// JSON 데이터를 Dictionary로 변환
|
||
var recipeDict = JsonConvert.DeserializeObject<Dictionary<string, object>>(recipeData);
|
||
|
||
// DataRow의 각 컬럼 업데이트
|
||
foreach (var kvp in recipeDict)
|
||
{
|
||
string colName = kvp.Key;
|
||
|
||
// 컬럼이 테이블에 존재하는지 확인
|
||
if (!dr.Table.Columns.Contains(colName))
|
||
continue;
|
||
|
||
// idx나 Midx 같은 자동 생성 컬럼은 스킵
|
||
if (colName == "idx" || colName == "Midx")
|
||
continue;
|
||
|
||
try
|
||
{
|
||
var col = dr.Table.Columns[colName];
|
||
object value = kvp.Value;
|
||
|
||
// null 처리
|
||
if (value == null)
|
||
{
|
||
dr[colName] = DBNull.Value;
|
||
}
|
||
else
|
||
{
|
||
// 타입 변환
|
||
if (col.DataType == typeof(bool))
|
||
dr[colName] = Convert.ToBoolean(value);
|
||
else if (col.DataType == typeof(int))
|
||
dr[colName] = Convert.ToInt32(value);
|
||
else if (col.DataType == typeof(double))
|
||
dr[colName] = Convert.ToDouble(value);
|
||
else if (col.DataType == typeof(float))
|
||
dr[colName] = Convert.ToSingle(value);
|
||
else
|
||
dr[colName] = value.ToString();
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Console.WriteLine($"[WARN] Failed to set column {colName}: {ex.Message}");
|
||
}
|
||
}
|
||
|
||
// 변경사항 저장
|
||
PUB.mdm.dataSet.OPModel.AcceptChanges();
|
||
PUB.mdm.SaveModelV();
|
||
|
||
Console.WriteLine($"[INFO] Recipe {recipeTitle} saved successfully to OPModel");
|
||
|
||
var response2 = new { success = true, message = "Recipe saved successfully", recipeId = recipeTitle };
|
||
return JsonConvert.SerializeObject(response2);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Console.WriteLine($"[ERROR] Failed to save recipe {recipeTitle}: {ex.Message}");
|
||
var response = new { success = false, message = ex.Message };
|
||
return JsonConvert.SerializeObject(response);
|
||
}
|
||
}
|
||
|
||
public string CopyRecipe(string recipeId, string newName)
|
||
{
|
||
Console.WriteLine($"[C#] Copying Recipe: {recipeId} as {newName}");
|
||
|
||
try
|
||
{
|
||
string sourcePath = Path.Combine(_recipeFolder, $"{recipeId}.json");
|
||
|
||
if (!File.Exists(sourcePath))
|
||
{
|
||
var response = new { success = false, message = "Source recipe not found" };
|
||
return JsonConvert.SerializeObject(response);
|
||
}
|
||
|
||
string newId = Guid.NewGuid().ToString().Substring(0, 8);
|
||
string destPath = Path.Combine(_recipeFolder, $"{newId}.json");
|
||
|
||
string json = File.ReadAllText(sourcePath);
|
||
var recipeData = JsonConvert.DeserializeObject<dynamic>(json);
|
||
|
||
recipeData.name = newName;
|
||
|
||
File.WriteAllText(destPath, JsonConvert.SerializeObject(recipeData, Formatting.Indented));
|
||
|
||
string timestamp = DateTime.Now.ToString("yyyy-MM-dd");
|
||
|
||
Console.WriteLine($"[INFO] Recipe copied from {recipeId} to {newId}");
|
||
|
||
var response2 = new {
|
||
success = true,
|
||
message = "Recipe copied successfully",
|
||
newRecipe = new {
|
||
id = newId,
|
||
name = newName,
|
||
lastModified = timestamp
|
||
}
|
||
};
|
||
return JsonConvert.SerializeObject(response2);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Console.WriteLine($"[ERROR] Failed to copy recipe: {ex.Message}");
|
||
var response = new { success = false, message = ex.Message };
|
||
return JsonConvert.SerializeObject(response);
|
||
}
|
||
}
|
||
|
||
public string DeleteRecipe(string recipeId)
|
||
{
|
||
Console.WriteLine($"[C#] Deleting Recipe: {recipeId}");
|
||
|
||
try
|
||
{
|
||
if (recipeId == _host.GetCurrentRecipe())
|
||
{
|
||
var response1 = new { success = false, message = "Cannot delete currently selected recipe" };
|
||
return JsonConvert.SerializeObject(response1);
|
||
}
|
||
|
||
string recipePath = Path.Combine(_recipeFolder, $"{recipeId}.json");
|
||
|
||
if (!File.Exists(recipePath))
|
||
{
|
||
var response = new { success = false, message = "Recipe not found" };
|
||
return JsonConvert.SerializeObject(response);
|
||
}
|
||
|
||
File.Delete(recipePath);
|
||
|
||
Console.WriteLine($"[INFO] Recipe {recipeId} deleted successfully");
|
||
|
||
var response2 = new { success = true, message = "Recipe deleted successfully", recipeId = recipeId };
|
||
return JsonConvert.SerializeObject(response2);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Console.WriteLine($"[ERROR] Failed to delete recipe: {ex.Message}");
|
||
var response = new { success = false, message = ex.Message };
|
||
return JsonConvert.SerializeObject(response);
|
||
}
|
||
}
|
||
|
||
public string GetProcessedData()
|
||
{
|
||
try
|
||
{
|
||
// TODO: Connect to actual data source (FMain.dataSet1.K4EE_Component_Reel_Result)
|
||
// For now, return sample data structure
|
||
var processedData = new List<object>();
|
||
|
||
// Sample data for testing - replace with actual data from FMain or database
|
||
var sampleData = new[] {
|
||
new {
|
||
target = "1",
|
||
JTYPE = "MODEL_A",
|
||
STIME = DateTime.Now.AddMinutes(-30).ToString("HH:mm:ss"),
|
||
BATCH = DateTime.Now.AddMinutes(-30).ToString("HH:mm:ss"),
|
||
SID = "SID123456",
|
||
RID = "RID789012",
|
||
VNAME = "VENDOR_A",
|
||
LOC = "L",
|
||
QTY = 1250,
|
||
qtymax = 2500,
|
||
MFGDATE = "2025-11-20",
|
||
VLOT = "LOT001",
|
||
PARTNO = "PN12345",
|
||
MCN = "CPN001",
|
||
REMARK = "",
|
||
PRNATTACH = true,
|
||
PRNVALID = true
|
||
},
|
||
new {
|
||
target = "2",
|
||
JTYPE = "MODEL_B",
|
||
STIME = DateTime.Now.AddMinutes(-25).ToString("HH:mm:ss"),
|
||
BATCH = DateTime.Now.AddMinutes(-25).ToString("HH:mm:ss"),
|
||
SID = "SID234567",
|
||
RID = "RID890123",
|
||
VNAME = "VENDOR_B",
|
||
LOC = "R",
|
||
QTY = 3500,
|
||
qtymax = 5000,
|
||
MFGDATE = "2025-11-21",
|
||
VLOT = "LOT002",
|
||
PARTNO = "PN23456",
|
||
MCN = "CPN002",
|
||
REMARK = "",
|
||
PRNATTACH = true,
|
||
PRNVALID = false
|
||
},
|
||
new {
|
||
target = "3",
|
||
JTYPE = "MODEL_A",
|
||
STIME = DateTime.Now.AddMinutes(-20).ToString("HH:mm:ss"),
|
||
BATCH = DateTime.Now.AddMinutes(-20).ToString("HH:mm:ss"),
|
||
SID = "SID345678",
|
||
RID = "RID901234",
|
||
VNAME = "VENDOR_A",
|
||
LOC = "L",
|
||
QTY = 800,
|
||
qtymax = 2500,
|
||
MFGDATE = "2025-11-22",
|
||
VLOT = "LOT003",
|
||
PARTNO = "PN34567",
|
||
MCN = "CPN003",
|
||
REMARK = "(BYPASS)",
|
||
PRNATTACH = false,
|
||
PRNVALID = true
|
||
},
|
||
new {
|
||
target = "4",
|
||
JTYPE = "MODEL_C",
|
||
STIME = DateTime.Now.AddMinutes(-15).ToString("HH:mm:ss"),
|
||
BATCH = DateTime.Now.AddMinutes(-15).ToString("HH:mm:ss"),
|
||
SID = "SID456789",
|
||
RID = "RID012345",
|
||
VNAME = "VENDOR_C",
|
||
LOC = "R",
|
||
QTY = 4200,
|
||
qtymax = 6000,
|
||
MFGDATE = "2025-11-23",
|
||
VLOT = "LOT004",
|
||
PARTNO = "PN45678",
|
||
MCN = "CPN004",
|
||
REMARK = "",
|
||
PRNATTACH = true,
|
||
PRNVALID = true
|
||
},
|
||
new {
|
||
target = "5",
|
||
JTYPE = "MODEL_B",
|
||
STIME = DateTime.Now.AddMinutes(-10).ToString("HH:mm:ss"),
|
||
BATCH = DateTime.Now.AddMinutes(-10).ToString("HH:mm:ss"),
|
||
SID = "SID567890",
|
||
RID = "RID123456",
|
||
VNAME = "VENDOR_B",
|
||
LOC = "L",
|
||
QTY = 1800,
|
||
qtymax = 5000,
|
||
MFGDATE = "2025-11-24",
|
||
VLOT = "LOT005",
|
||
PARTNO = "PN56789",
|
||
MCN = "CPN005",
|
||
REMARK = "",
|
||
PRNATTACH = true,
|
||
PRNVALID = true
|
||
}
|
||
};
|
||
|
||
foreach (var item in sampleData)
|
||
{
|
||
processedData.Add(item);
|
||
}
|
||
|
||
return JsonConvert.SerializeObject(processedData);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Console.WriteLine($"[ERROR] Failed to get processed data: {ex.Message}");
|
||
return JsonConvert.SerializeObject(new List<object>());
|
||
}
|
||
}
|
||
|
||
// ===== VISION CONTROL METHODS =====
|
||
|
||
public string CameraConnect()
|
||
{
|
||
try
|
||
{
|
||
if (PUB.wsL != null && PUB.wsL.Connected)
|
||
{
|
||
var response = new { success = false, message = "Camera is already connected" };
|
||
return JsonConvert.SerializeObject(response);
|
||
}
|
||
|
||
if (string.IsNullOrEmpty(SETTING.Data.CameraLFile))
|
||
{
|
||
var response = new { success = false, message = "Camera program filename not specified" };
|
||
return JsonConvert.SerializeObject(response);
|
||
}
|
||
|
||
var fi = new System.IO.FileInfo(SETTING.Data.CameraLFile);
|
||
if (!fi.Exists)
|
||
{
|
||
var response = new { success = false, message = $"Camera program file does not exist\n{fi.FullName}" };
|
||
return JsonConvert.SerializeObject(response);
|
||
}
|
||
|
||
PUB.log.Add("User Request: Connect Camera (QRCode)", false);
|
||
// Camera connection logic would be implemented here
|
||
// For now, return success
|
||
var response2 = new { success = true, message = "Camera connection initiated" };
|
||
return JsonConvert.SerializeObject(response2);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Console.WriteLine($"[ERROR] Failed to connect camera: {ex.Message}");
|
||
var response = new { success = false, message = ex.Message };
|
||
return JsonConvert.SerializeObject(response);
|
||
}
|
||
}
|
||
|
||
public string CameraDisconnect()
|
||
{
|
||
try
|
||
{
|
||
PUB.log.Add("User Request: Disconnect Camera (QRCode)", false);
|
||
// Camera disconnection logic
|
||
var response = new { success = true, message = "Camera disconnected" };
|
||
return JsonConvert.SerializeObject(response);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Console.WriteLine($"[ERROR] Failed to disconnect camera: {ex.Message}");
|
||
var response = new { success = false, message = ex.Message };
|
||
return JsonConvert.SerializeObject(response);
|
||
}
|
||
}
|
||
|
||
public string CameraGetImage()
|
||
{
|
||
try
|
||
{
|
||
PUB.log.Add("User Request: Get Camera Image", false);
|
||
// Get image logic
|
||
var response = new { success = true, message = "Image captured" };
|
||
return JsonConvert.SerializeObject(response);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Console.WriteLine($"[ERROR] Failed to get camera image: {ex.Message}");
|
||
var response = new { success = false, message = ex.Message };
|
||
return JsonConvert.SerializeObject(response);
|
||
}
|
||
}
|
||
|
||
public string CameraLiveView()
|
||
{
|
||
try
|
||
{
|
||
PUB.log.Add("User Request: Camera Live View", false);
|
||
// Live view logic
|
||
var response = new { success = true, message = "Live view started" };
|
||
return JsonConvert.SerializeObject(response);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Console.WriteLine($"[ERROR] Failed to start live view: {ex.Message}");
|
||
var response = new { success = false, message = ex.Message };
|
||
return JsonConvert.SerializeObject(response);
|
||
}
|
||
}
|
||
|
||
public string CameraReadTest()
|
||
{
|
||
try
|
||
{
|
||
PUB.log.Add("User Request: Camera Read Test", false);
|
||
// Read test logic
|
||
var response = new { success = true, message = "Read test completed" };
|
||
return JsonConvert.SerializeObject(response);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Console.WriteLine($"[ERROR] Failed to run read test: {ex.Message}");
|
||
var response = new { success = false, message = ex.Message };
|
||
return JsonConvert.SerializeObject(response);
|
||
}
|
||
}
|
||
|
||
public string KeyenceTriggerOn()
|
||
{
|
||
try
|
||
{
|
||
PUB.log.Add("User Request: Keyence Trigger ON", false);
|
||
PUB.keyenceF.Trigger(true);
|
||
PUB.keyenceR.Trigger(true);
|
||
var response = new { success = true, message = "Keyence trigger ON" };
|
||
return JsonConvert.SerializeObject(response);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Console.WriteLine($"[ERROR] Failed to trigger keyence on: {ex.Message}");
|
||
var response = new { success = false, message = ex.Message };
|
||
return JsonConvert.SerializeObject(response);
|
||
}
|
||
}
|
||
|
||
public string KeyenceTriggerOff()
|
||
{
|
||
try
|
||
{
|
||
PUB.log.Add("User Request: Keyence Trigger OFF", false);
|
||
PUB.keyenceF.Trigger(false);
|
||
PUB.keyenceR.Trigger(false);
|
||
var response = new { success = true, message = "Keyence trigger OFF" };
|
||
return JsonConvert.SerializeObject(response);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Console.WriteLine($"[ERROR] Failed to trigger keyence off: {ex.Message}");
|
||
var response = new { success = false, message = ex.Message };
|
||
return JsonConvert.SerializeObject(response);
|
||
}
|
||
}
|
||
|
||
public string KeyenceGetImage()
|
||
{
|
||
try
|
||
{
|
||
PUB.log.Add("User Request: Get Keyence Image", false);
|
||
var curimageF = PUB.keyenceF.GetImage();
|
||
var curimageR = PUB.keyenceR.GetImage();
|
||
var response = new { success = true, message = "Keyence images captured" };
|
||
return JsonConvert.SerializeObject(response);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Console.WriteLine($"[ERROR] Failed to get keyence image: {ex.Message}");
|
||
var response = new { success = false, message = ex.Message };
|
||
return JsonConvert.SerializeObject(response);
|
||
}
|
||
}
|
||
|
||
public string KeyenceSaveImage()
|
||
{
|
||
try
|
||
{
|
||
PUB.log.Add("User Request: Save Keyence Image", false);
|
||
var fn = System.IO.Path.Combine(AR.UTIL.CurrentPath, "Images", "keyence.bmp");
|
||
var dir = System.IO.Path.GetDirectoryName(fn);
|
||
if (!System.IO.Directory.Exists(dir))
|
||
{
|
||
System.IO.Directory.CreateDirectory(dir);
|
||
}
|
||
// SaveImage logic would go here
|
||
var response = new { success = true, message = $"Image saved to {fn}" };
|
||
return JsonConvert.SerializeObject(response);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Console.WriteLine($"[ERROR] Failed to save keyence image: {ex.Message}");
|
||
var response = new { success = false, message = ex.Message };
|
||
return JsonConvert.SerializeObject(response);
|
||
}
|
||
}
|
||
|
||
public string ToggleLight()
|
||
{
|
||
try
|
||
{
|
||
if (PUB.flag.get(AR.eVarBool.FG_INIT_MOTIO) == false)
|
||
{
|
||
var response = new { success = false, message = "Motion not initialized. Please try again later" };
|
||
return JsonConvert.SerializeObject(response);
|
||
}
|
||
|
||
var cur = DIO.GetIOOutput(AR.eDOName.ROOMLIGHT);
|
||
DIO.SetRoomLight(!cur, true);
|
||
PUB.log.Add($"User Request: Room Light {(!cur ? "ON" : "OFF")}", false);
|
||
var response2 = new { success = true, message = $"Light turned {(!cur ? "ON" : "OFF")}" };
|
||
return JsonConvert.SerializeObject(response2);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Console.WriteLine($"[ERROR] Failed to toggle light: {ex.Message}");
|
||
var response = new { success = false, message = ex.Message };
|
||
return JsonConvert.SerializeObject(response);
|
||
}
|
||
}
|
||
|
||
public string ExecuteManualPrint(string sid, string venderLot, string qty, string mfg, string rid, string spy, string partNo, string printer, int count)
|
||
{
|
||
try
|
||
{
|
||
// Parse quantity
|
||
if (!int.TryParse(qty, out int vqty))
|
||
{
|
||
var response = new { success = false, message = "Please enter quantity as a number" };
|
||
return JsonConvert.SerializeObject(response);
|
||
}
|
||
|
||
// Select printer
|
||
var selectedPrinter = printer.ToLower() == "left" ? PUB.PrinterL : PUB.PrinterR;
|
||
|
||
// Create ZPL
|
||
string zpl = selectedPrinter.makeZPL_210908(new AR.Class.Reel
|
||
{
|
||
SID = sid,
|
||
venderLot = venderLot,
|
||
venderName = spy,
|
||
qty = vqty,
|
||
id = rid,
|
||
mfg = mfg,
|
||
PartNo = partNo,
|
||
}, SETTING.Data.DrawOutbox, out string qrdata);
|
||
|
||
// Print
|
||
for (int i = 0; i < count; i++)
|
||
{
|
||
var prn = selectedPrinter.Print(zpl);
|
||
if (prn.result == false)
|
||
{
|
||
PUB.log.AddE(prn.errmessage);
|
||
var response = new { success = false, message = $"Cannot proceed further due to printing failure: {prn.errmessage}" };
|
||
return JsonConvert.SerializeObject(response);
|
||
}
|
||
else
|
||
{
|
||
if (i == 0) // Log only first print
|
||
PUB.log.Add($"User print completed: {string.Join("|", new string[] { sid, venderLot, spy, qty, rid, mfg, partNo })}", false);
|
||
}
|
||
System.Threading.Thread.Sleep(100);
|
||
}
|
||
|
||
var response2 = new { success = true, message = $"Successfully printed {count} label(s)" };
|
||
return JsonConvert.SerializeObject(response2);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Console.WriteLine($"[ERROR] Failed to execute manual print: {ex.Message}");
|
||
var response = new { success = false, message = ex.Message };
|
||
return JsonConvert.SerializeObject(response);
|
||
}
|
||
}
|
||
|
||
public string CancelJob()
|
||
{
|
||
try
|
||
{
|
||
if (PUB.flag.get(AR.eVarBool.FG_INIT_MOTIO) == false)
|
||
{
|
||
var response = new { success = false, message = "Motion not initialized. Please try again later" };
|
||
return JsonConvert.SerializeObject(response);
|
||
}
|
||
|
||
var msg = new System.Text.StringBuilder();
|
||
|
||
if (PUB.mot.HasHomeSetOff)
|
||
{
|
||
msg.AppendLine("Device initialization is not complete. Execute device initialization");
|
||
}
|
||
|
||
if (PUB.sm.isRunning == true)
|
||
{
|
||
msg.AppendLine("AUTO-RUN MODE. Cannot be used during automatic execution. Please stop and try again");
|
||
}
|
||
|
||
if (DIO.IsEmergencyOn() == true)
|
||
{
|
||
msg.AppendLine("Release emergency stop");
|
||
}
|
||
|
||
if (DIO.isSaftyDoorF() == false)
|
||
{
|
||
msg.AppendLine("Front door is open");
|
||
}
|
||
|
||
if (DIO.isSaftyDoorR() == false)
|
||
{
|
||
msg.AppendLine("Rear door is open");
|
||
}
|
||
|
||
if (msg.Length > 0)
|
||
{
|
||
PUB.log.AddE(msg.ToString());
|
||
var response = new { success = false, message = msg.ToString() };
|
||
return JsonConvert.SerializeObject(response);
|
||
}
|
||
|
||
PUB.log.Add("User Click : tray out & clear position", false);
|
||
PUB.flag.set(eVarBool.FG_USERSTEP, false, "Run_MotionPositionReset");
|
||
PUB.log.AddAT("Starting discharge and home movement");
|
||
PUB.AddSystemLog(System.Windows.Forms.Application.ProductVersion, "MAIN", "Cancel Work");
|
||
PUB.sm.SetNewStep(eSMStep.HOME_QUICK);
|
||
|
||
var response2 = new { success = true, message = "Job cancelled. Executing motion position reset" };
|
||
return JsonConvert.SerializeObject(response2);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Console.WriteLine($"[ERROR] Failed to cancel job: {ex.Message}");
|
||
var response = new { success = false, message = ex.Message };
|
||
return JsonConvert.SerializeObject(response);
|
||
}
|
||
}
|
||
|
||
public string OpenManage()
|
||
{
|
||
try
|
||
{
|
||
if (PUB.sm.isRunning)
|
||
{
|
||
var response = new { success = false, message = "Cannot use during operation" };
|
||
return JsonConvert.SerializeObject(response);
|
||
}
|
||
|
||
if (PUB.flag.get(AR.eVarBool.FG_MOVE_PICKER))
|
||
{
|
||
var response = new { success = false, message = "The window is already open" };
|
||
return JsonConvert.SerializeObject(response);
|
||
}
|
||
|
||
// The manage dialog (fPickerMove) cannot be opened from web UI
|
||
// This would require implementing a separate picker management page
|
||
PUB.log.Add("User Request: Manage (Web UI)", false);
|
||
var response2 = new { success = false, message = "Manage is not available in Web UI. Please use the main program." };
|
||
return JsonConvert.SerializeObject(response2);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Console.WriteLine($"[ERROR] Failed to open manage: {ex.Message}");
|
||
var response = new { success = false, message = ex.Message };
|
||
return JsonConvert.SerializeObject(response);
|
||
}
|
||
}
|
||
|
||
public string OpenManual()
|
||
{
|
||
try
|
||
{
|
||
string file = System.IO.Path.Combine(AR.UTIL.CurrentPath, "Manual", "Manual.pdf");
|
||
if (System.IO.File.Exists(file) == false)
|
||
{
|
||
var response = new { success = false, message = "User manual file does not exist\nFile name: " + file };
|
||
return JsonConvert.SerializeObject(response);
|
||
}
|
||
|
||
AR.UTIL.RunExplorer(file);
|
||
PUB.log.Add("User Request: Open Manual", false);
|
||
var response2 = new { success = true, message = "Manual opened" };
|
||
return JsonConvert.SerializeObject(response2);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Console.WriteLine($"[ERROR] Failed to open manual: {ex.Message}");
|
||
var response = new { success = false, message = ex.Message };
|
||
return JsonConvert.SerializeObject(response);
|
||
}
|
||
}
|
||
|
||
public string OpenLogViewer()
|
||
{
|
||
try
|
||
{
|
||
var exename = AR.UTIL.MakePath("LogView.exe");
|
||
if (System.IO.File.Exists(exename) == false)
|
||
{
|
||
var response = new { success = false, message = "Log viewer file not found\nPlease contact support" };
|
||
return JsonConvert.SerializeObject(response);
|
||
}
|
||
|
||
AR.UTIL.RunProcess(exename);
|
||
PUB.log.Add("User Request: Open Log Viewer", false);
|
||
var response2 = new { success = true, message = "Log viewer opened" };
|
||
return JsonConvert.SerializeObject(response2);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Console.WriteLine($"[ERROR] Failed to open log viewer: {ex.Message}");
|
||
var response = new { success = false, message = ex.Message };
|
||
return JsonConvert.SerializeObject(response);
|
||
}
|
||
}
|
||
|
||
public string OpenProgramFolder()
|
||
{
|
||
try
|
||
{
|
||
AR.UTIL.RunExplorer(AR.UTIL.CurrentPath);
|
||
PUB.log.Add("User Request: Open Program Folder", false);
|
||
var response = new { success = true, message = "Program folder opened" };
|
||
return JsonConvert.SerializeObject(response);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Console.WriteLine($"[ERROR] Failed to open program folder: {ex.Message}");
|
||
var response = new { success = false, message = ex.Message };
|
||
return JsonConvert.SerializeObject(response);
|
||
}
|
||
}
|
||
|
||
public string OpenLogFolder()
|
||
{
|
||
try
|
||
{
|
||
PUB.LogFlush();
|
||
var fi = new System.IO.FileInfo(PUB.log.FileName);
|
||
AR.UTIL.RunExplorer(fi.Directory.FullName);
|
||
PUB.log.Add("User Request: Open Log Folder", false);
|
||
var response = new { success = true, message = "Log folder opened" };
|
||
return JsonConvert.SerializeObject(response);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Console.WriteLine($"[ERROR] Failed to open log folder: {ex.Message}");
|
||
var response = new { success = false, message = ex.Message };
|
||
return JsonConvert.SerializeObject(response);
|
||
}
|
||
}
|
||
|
||
public string OpenScreenshotFolder()
|
||
{
|
||
try
|
||
{
|
||
string savefile = System.IO.Path.Combine(AR.UTIL.CurrentPath, "ScreenShot", DateTime.Now.ToString("yyyyMMddHHmmss") + ".png");
|
||
var grpath = new System.IO.FileInfo(savefile);
|
||
AR.UTIL.RunExplorer(grpath.Directory.FullName);
|
||
PUB.log.Add("User Request: Open Screenshot Folder", false);
|
||
var response = new { success = true, message = "Screenshot folder opened" };
|
||
return JsonConvert.SerializeObject(response);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Console.WriteLine($"[ERROR] Failed to open screenshot folder: {ex.Message}");
|
||
var response = new { success = false, message = ex.Message };
|
||
return JsonConvert.SerializeObject(response);
|
||
}
|
||
}
|
||
|
||
public string OpenSavedDataFolder()
|
||
{
|
||
try
|
||
{
|
||
var basepath = SETTING.Data.GetDataPath();
|
||
var path = System.IO.Path.Combine(
|
||
basepath, "History",
|
||
DateTime.Now.Year.ToString("0000"),
|
||
DateTime.Now.Month.ToString("00"),
|
||
DateTime.Now.Day.ToString("00"));
|
||
if (System.IO.Directory.Exists(path))
|
||
AR.UTIL.RunExplorer(path);
|
||
else
|
||
AR.UTIL.RunExplorer(System.IO.Path.Combine(SETTING.Data.GetDataPath(), "History"));
|
||
|
||
PUB.log.Add("User Request: Open Saved Data Folder", false);
|
||
var response = new { success = true, message = "Saved data folder opened" };
|
||
return JsonConvert.SerializeObject(response);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Console.WriteLine($"[ERROR] Failed to open saved data folder: {ex.Message}");
|
||
var response = new { success = false, message = ex.Message };
|
||
return JsonConvert.SerializeObject(response);
|
||
}
|
||
}
|
||
}
|
||
}
|