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; using System.Threading.Tasks; 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(); // 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 { 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() }); } } 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 } /// /// 마이그레이션완료 /// /// /// 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(); 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); } } /// /// ���̱׷��̼� ���� /// /// 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(); 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 "[]"; } } /// /// ���̱׷��̼Ǽ��� /// /// public void SaveConfig(string configJson) { try { Console.WriteLine($"[Backend] SAVE CONFIG REQUEST RECEIVED"); // Parse array format from React var settingsArray = JsonConvert.DeserializeObject>>(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}"); } } /// /// 마이그레이션완료 /// /// 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(), outputs = new List(), interlocks = new List() }); } } /// /// 마이그레이션완료 /// /// private List GetDigitalInputs() { var inputs = new List(); 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; } /// /// 마이그레이션완료 /// /// private List GetDigitalOutputs() { var outputs = new List(); 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; } /// /// 마이그레이션완료 /// /// private List GetInterlocks() { var interlocks = new List(); 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(); 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; } /// /// 마이그레이션완료 /// /// public string GetRecipeList() { //PUB.mdm.dataSet.OPModel에 등록된 데이터가 모델 목록이다 try { var recipes = new List(); 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 "[]"; } } /// /// 마이그레이션완료 /// /// /// 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(); 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); } } /// /// 마이그레이션완료 /// /// /// /// 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>(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(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(); // 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()); } } // ===== 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); var success = DIO.SetRoomLight(!cur, true); if (success == false) { var response = new { success = false, message = "Failed to control room light" }; return JsonConvert.SerializeObject(response); } 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 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); } // Set flag to indicate picker move dialog is open PUB.flag.set(eVarBool.FG_MOVE_PICKER, true, "PICKERMOVE_WEB"); PUB.log.Add("User Request: Manage (Web UI)", false); var response2 = new { success = true, message = "Manage dialog opened" }; 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 CloseManage() { try { // Clear the flag PUB.flag.set(eVarBool.FG_MOVE_PICKER, false, "PICKERMOVE_WEB"); // Check if auto-init is needed: home not set AND picker is in center position bool shouldAutoInit = PUB.mot.HasHomeSetOff == true && DIO.GetIOInput(eDIName.PICKER_SAFE); PUB.log.Add($"User Request: Close Manage (Web UI), shouldAutoInit={shouldAutoInit}", false); var response = new { shouldAutoInit = shouldAutoInit }; return JsonConvert.SerializeObject(response); } catch (Exception ex) { Console.WriteLine($"[ERROR] Failed to close manage: {ex.Message}"); var response = new { shouldAutoInit = false }; 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\n{exename}\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); } } // ===== PICKER MOVE METHODS ===== private static bool _manPosL = false; private static bool _manPosR = false; public string GetPickerStatus() { try { // X축 피커 이동 가능 여부 체크 bool xEnabled = false; if (PUB.mot.IsHomeSet((int)eAxis.PZ_PICK) == false) { if (PUB.mot.IsOrg((int)eAxis.PZ_PICK) || PUB.mot.IsLimitN((int)eAxis.PZ_PICK)) xEnabled = true; } else { var PosZ = MOT.GetPZPos(ePZLoc.READY); var OffZ = MOT.getPositionOffset(PosZ); xEnabled = OffZ < 1; } var doorsafef = DIO.isSaftyDoorF(); var managementEnabled = PUB.mot.HasHomeSetOff == false && doorsafef == true; var status = new { xEnabled = xEnabled, zEnabled = xEnabled, // Z jog uses same condition pickerSafe = DIO.GetIOInput(eDIName.PICKER_SAFE), managementEnabled = managementEnabled, manPosL = _manPosL, manPosR = _manPosR }; return JsonConvert.SerializeObject(status); } catch (Exception ex) { Console.WriteLine($"[ERROR] Failed to get picker status: {ex.Message}"); return JsonConvert.SerializeObject(new { xEnabled = false, zEnabled = false, pickerSafe = false, managementEnabled = false, manPosL = false, manPosR = false }); } } private bool CheckPickerSafety(out string errorMessage) { errorMessage = null; if (DIO.isSaftyDoorF() == false) { errorMessage = "Front door is open"; return false; } if (PUB.mot.HasHomeSetOff) { errorMessage = "Motion home operation is not completed"; return false; } return true; } private bool CheckZAxisReady(out string errorMessage) { errorMessage = null; var z = MOT.GetPZPos(ePZLoc.READY); var zpos = MOT.getPositionOffset(z); if (zpos >= 0.5) { errorMessage = "Raise the Z axis and try again"; return false; } return true; } public string PickerMoveLeft() { try { if (!CheckPickerSafety(out string safetyError)) return JsonConvert.SerializeObject(new { success = false, message = safetyError }); if (!CheckZAxisReady(out string zError)) return JsonConvert.SerializeObject(new { success = false, message = zError }); var m1 = MOT.GetLMPos(eLMLoc.READY); if (MOT.getPositionMatch(m1) == false) return JsonConvert.SerializeObject(new { success = false, message = "Printer attachment is not in ready position.\nCannot move as collision may occur" }); var p1 = MOT.GetPXPos(ePXLoc.PICKOFFL); MOT.Move(eAxis.PX_PICK, p1.Position, 250, p1.Acc, false, false, false); return JsonConvert.SerializeObject(new { success = true, message = "Moving to left position" }); } catch (Exception ex) { return JsonConvert.SerializeObject(new { success = false, message = ex.Message }); } } public string PickerMoveLeftWait() { try { if (!CheckPickerSafety(out string safetyError)) return JsonConvert.SerializeObject(new { success = false, message = safetyError }); if (!CheckZAxisReady(out string zError)) return JsonConvert.SerializeObject(new { success = false, message = zError }); var m1 = MOT.GetLMPos(eLMLoc.READY); if (MOT.getPositionMatch(m1) == false) return JsonConvert.SerializeObject(new { success = false, message = "Printer attachment is not in ready position.\nCannot move as collision may occur" }); var p1 = MOT.GetPXPos(ePXLoc.READYL); MOT.Move(eAxis.PX_PICK, p1.Position, 250, p1.Acc, false, false, false); return JsonConvert.SerializeObject(new { success = true, message = "Moving to left wait position" }); } catch (Exception ex) { return JsonConvert.SerializeObject(new { success = false, message = ex.Message }); } } public string PickerMoveCenter() { try { if (!CheckPickerSafety(out string safetyError)) return JsonConvert.SerializeObject(new { success = false, message = safetyError }); if (!CheckZAxisReady(out string zError)) return JsonConvert.SerializeObject(new { success = false, message = zError }); var p1 = MOT.GetPXPos(ePXLoc.PICKON); MOT.Move(eAxis.PX_PICK, p1.Position, 250, p1.Acc, false, false, false); return JsonConvert.SerializeObject(new { success = true, message = "Moving to center position" }); } catch (Exception ex) { return JsonConvert.SerializeObject(new { success = false, message = ex.Message }); } } public string PickerMoveRightWait() { try { if (!CheckPickerSafety(out string safetyError)) return JsonConvert.SerializeObject(new { success = false, message = safetyError }); if (!CheckZAxisReady(out string zError)) return JsonConvert.SerializeObject(new { success = false, message = zError }); var m1 = MOT.GetRMPos(eRMLoc.READY); if (MOT.getPositionMatch(m1) == false) return JsonConvert.SerializeObject(new { success = false, message = "Printer attachment is not in ready position.\nCannot move as collision may occur" }); var p1 = MOT.GetPXPos(ePXLoc.READYR); MOT.Move(eAxis.PX_PICK, p1.Position, 250, p1.Acc, false, false, false); return JsonConvert.SerializeObject(new { success = true, message = "Moving to right wait position" }); } catch (Exception ex) { return JsonConvert.SerializeObject(new { success = false, message = ex.Message }); } } public string PickerMoveRight() { try { if (!CheckPickerSafety(out string safetyError)) return JsonConvert.SerializeObject(new { success = false, message = safetyError }); if (!CheckZAxisReady(out string zError)) return JsonConvert.SerializeObject(new { success = false, message = zError }); var m1 = MOT.GetRMPos(eRMLoc.READY); if (MOT.getPositionMatch(m1) == false) return JsonConvert.SerializeObject(new { success = false, message = "Printer attachment is not in ready position.\nCannot move as collision may occur" }); var p1 = MOT.GetPXPos(ePXLoc.PICKOFFR); MOT.Move(eAxis.PX_PICK, p1.Position, 250, p1.Acc, false, false, false); return JsonConvert.SerializeObject(new { success = true, message = "Moving to right position" }); } catch (Exception ex) { return JsonConvert.SerializeObject(new { success = false, message = ex.Message }); } } public string PickerJogStart(string direction) { try { switch (direction) { case "up": PUB.mot.JOG((int)eAxis.PZ_PICK, arDev.MOT.MOTION_DIRECTION.Negative, AR.SETTING.Data.JOG_Speed, AR.SETTING.Data.JOG_Acc); break; case "down": PUB.mot.JOG((int)eAxis.PZ_PICK, arDev.MOT.MOTION_DIRECTION.Positive, AR.SETTING.Data.JOG_Speed, AR.SETTING.Data.JOG_Acc); break; case "left": PUB.mot.JOG((int)eAxis.PX_PICK, arDev.MOT.MOTION_DIRECTION.Negative, AR.SETTING.Data.JOG_Speed, AR.SETTING.Data.JOG_Acc); break; case "right": PUB.mot.JOG((int)eAxis.PX_PICK, arDev.MOT.MOTION_DIRECTION.Positive, AR.SETTING.Data.JOG_Speed, AR.SETTING.Data.JOG_Acc); break; } return JsonConvert.SerializeObject(new { success = true, message = $"Jog {direction} started" }); } catch (Exception ex) { return JsonConvert.SerializeObject(new { success = false, message = ex.Message }); } } public string PickerJogStop() { try { PUB.mot.MoveStop("pmove_web", (short)eAxis.PX_PICK); PUB.mot.MoveStop("pmove_web", (short)eAxis.PZ_PICK); return JsonConvert.SerializeObject(new { success = true, message = "Jog stopped" }); } catch (Exception ex) { return JsonConvert.SerializeObject(new { success = false, message = ex.Message }); } } public string PickerStop() { try { PUB.mot.MoveStop("pmove_web", (int)eAxis.PX_PICK); return JsonConvert.SerializeObject(new { success = true, message = "Picker stopped" }); } catch (Exception ex) { return JsonConvert.SerializeObject(new { success = false, message = ex.Message }); } } public string CancelVisionValidation(string side) { try { if (side == "left") { PUB.flag.set(eVarBool.FG_PRC_VISIONL, false, "CANCEL_WEB"); PUB.flag.set(eVarBool.FG_PORTL_ITEMON, false, "CANCEL_WEB"); PUB.log.Add($"LEFT-QR verification cancelled JGUID={PUB.Result.ItemDataL.guid}"); } else { PUB.flag.set(eVarBool.FG_PRC_VISIONR, false, "CANCEL_WEB"); PUB.flag.set(eVarBool.FG_PORTR_ITEMON, false, "CANCEL_WEB"); PUB.log.Add($"RIGHT-QR verification cancelled JGUID={PUB.Result.ItemDataR.guid}"); } return JsonConvert.SerializeObject(new { success = true, message = $"{side.ToUpper()}-QR verification cancelled" }); } catch (Exception ex) { return JsonConvert.SerializeObject(new { success = false, message = ex.Message }); } } public string PickerManagePosition(string side) { try { if (PUB.sm.Step != eSMStep.IDLE) return JsonConvert.SerializeObject(new { success = false, message = "Available only in standby state" }); var Xpos = DIO.GetIOInput(eDIName.PICKER_SAFE); if (Xpos == false) return JsonConvert.SerializeObject(new { success = false, message = "Available only when picker is in center position" }); int vidx = side == "left" ? 0 : 2; Task.Run(() => { DateTime dt; if (vidx == 0) { while (DIO.GetIOInput(eDIName.L_CYLUP) == false) { var dorlt = DIO.checkDigitalO(eDOName.L_CYLDN, new TimeSpan(1), false); if (dorlt == eNormalResult.False) System.Threading.Thread.Sleep(100); else if (dorlt == eNormalResult.Error) { PUB.log.AddE("l_cylup check error"); return; } } var zPos = MOT.GetLZPos(eLZLoc.READY).Clone(); zPos.Speed = 100; MOT.Move(zPos); dt = DateTime.Now; while (MOT.getPositionMatch(zPos) == false) { if ((DateTime.Now - dt).TotalSeconds > 30) break; System.Threading.Thread.Sleep(10); } var mPos = MOT.GetLMPos(eLMLoc.PRINTL07).Clone(); mPos.Speed = 100; MOT.Move(mPos); dt = DateTime.Now; while (MOT.getPositionMatch(mPos) == false) { if ((DateTime.Now - dt).TotalSeconds > 30) break; System.Threading.Thread.Sleep(10); } var zPos2 = MOT.GetLZPos(eLZLoc.PICKOFF); var tPos = (zPos2.Position / 2f); MOT.Move(eAxis.PL_UPDN, tPos, 100, zPos.Acc); _manPosL = true; } else { while (DIO.GetIOInput(eDIName.R_CYLUP) == false) { var dorlt = DIO.checkDigitalO(eDOName.R_CYLDN, new TimeSpan(1), false); if (dorlt == eNormalResult.False) System.Threading.Thread.Sleep(100); else if (dorlt == eNormalResult.Error) { PUB.log.AddE("r_cylup check error"); return; } } var zPos = MOT.GetRZPos(eRZLoc.READY).Clone(); zPos.Speed = 100; MOT.Move(zPos); dt = DateTime.Now; while (MOT.getPositionMatch(zPos) == false) { if ((DateTime.Now - dt).TotalSeconds > 30) break; System.Threading.Thread.Sleep(10); } var mPos = MOT.GetRMPos(eRMLoc.PRINTL07).Clone(); mPos.Speed = 100; MOT.Move(mPos); dt = DateTime.Now; while (MOT.getPositionMatch(mPos) == false) { if ((DateTime.Now - dt).TotalSeconds > 30) break; System.Threading.Thread.Sleep(10); } var zPos2 = MOT.GetRZPos(eRZLoc.PICKOFF); var tPos = (zPos2.Position / 2f); MOT.Move(eAxis.PR_UPDN, tPos, 100, zPos.Acc); _manPosR = true; } }); return JsonConvert.SerializeObject(new { success = true, message = $"Moving to {side} management position" }); } catch (Exception ex) { return JsonConvert.SerializeObject(new { success = false, message = ex.Message }); } } public string PickerManageReturn() { try { var Xpos = DIO.GetIOInput(eDIName.PICKER_SAFE); if (Xpos == false) return JsonConvert.SerializeObject(new { success = false, message = "Available only when picker is in center position" }); // Recover both positions Task.Run(() => PosRecover(0)); Task.Run(() => PosRecover(2)); return JsonConvert.SerializeObject(new { success = true, message = "Returning to ready position" }); } catch (Exception ex) { return JsonConvert.SerializeObject(new { success = false, message = ex.Message }); } } private void PosRecover(int vidx) { DateTime dt; if (vidx == 0) { while (DIO.GetIOInput(eDIName.L_CYLUP) == false) { var dorlt = DIO.checkDigitalO(eDOName.L_CYLDN, new TimeSpan(1), false); if (dorlt == eNormalResult.False) System.Threading.Thread.Sleep(100); else if (dorlt == eNormalResult.Error) { PUB.log.AddE("l_cylup check error"); return; } } var zPos = MOT.GetLZPos(eLZLoc.READY).Clone(); zPos.Speed = 100; MOT.Move(zPos); dt = DateTime.Now; while (MOT.getPositionMatch(zPos) == false) { if ((DateTime.Now - dt).TotalSeconds > 30) break; System.Threading.Thread.Sleep(10); } var mPos = MOT.GetLMPos(eLMLoc.READY).Clone(); mPos.Speed = 100; MOT.Move(mPos); dt = DateTime.Now; while (MOT.getPositionMatch(mPos) == false) { if ((DateTime.Now - dt).TotalSeconds > 30) break; System.Threading.Thread.Sleep(10); } _manPosL = false; } else { while (DIO.GetIOInput(eDIName.R_CYLUP) == false) { var dorlt = DIO.checkDigitalO(eDOName.R_CYLDN, new TimeSpan(1), false); if (dorlt == eNormalResult.False) System.Threading.Thread.Sleep(100); else if (dorlt == eNormalResult.Error) { PUB.log.AddE("R_cylup check error"); return; } } var zPos = MOT.GetRZPos(eRZLoc.READY).Clone(); zPos.Speed = 100; MOT.Move(zPos); dt = DateTime.Now; while (MOT.getPositionMatch(zPos) == false) { if ((DateTime.Now - dt).TotalSeconds > 30) break; System.Threading.Thread.Sleep(10); } var mPos = MOT.GetRMPos(eRMLoc.READY).Clone(); mPos.Speed = 100; MOT.Move(mPos); dt = DateTime.Now; while (MOT.getPositionMatch(mPos) == false) { if ((DateTime.Now - dt).TotalSeconds > 30) break; System.Threading.Thread.Sleep(10); } _manPosR = false; } } public string PickerZHome() { try { MOT.Home("Management_Web", eAxis.PZ_PICK, false); return JsonConvert.SerializeObject(new { success = true, message = "Z-axis home search started" }); } catch (Exception ex) { return JsonConvert.SerializeObject(new { success = false, message = ex.Message }); } } public string PickerZZero() { try { if (PUB.mot.IsHomeSet((int)eAxis.PZ_PICK) == false) return JsonConvert.SerializeObject(new { success = false, message = "Z home operation is not completed. Please perform HOME first" }); MOT.Move(eAxis.PZ_PICK, 0, 500, 1000, false, false, false); return JsonConvert.SerializeObject(new { success = true, message = "Moving Z-axis to zero" }); } catch (Exception ex) { return JsonConvert.SerializeObject(new { success = false, message = ex.Message }); } } public string PickerTestPrint(string side) { try { if (side == "left") { PUB.PrinterL.TestPrint(AR.SETTING.Data.DrawOutbox, "", ""); PUB.log.Add("Temporary print L:" + PUB.PrinterL.LastPrintZPL); } else { PUB.PrinterR.TestPrint(AR.SETTING.Data.DrawOutbox, "", ""); PUB.log.Add("Temporary print R:" + PUB.PrinterR.LastPrintZPL); } return JsonConvert.SerializeObject(new { success = true, message = $"{side.ToUpper()} test print completed" }); } catch (Exception ex) { return JsonConvert.SerializeObject(new { success = false, message = ex.Message }); } } public string CanCloseManage() { try { if (_manPosL || _manPosR) { return JsonConvert.SerializeObject(new { canClose = false, message = "Printer motion is in management position.\nReturn to position and try again" }); } return JsonConvert.SerializeObject(new { canClose = true, message = "" }); } catch (Exception ex) { return JsonConvert.SerializeObject(new { canClose = false, message = ex.Message }); } } // ===== INTERLOCK METHODS ===== /// /// 인터락 토글 (DIOMonitor.cs의 gvILXF_ItemClick과 동일) /// public string ToggleInterlock(int axisIndex, int lockIndex) { try { if (axisIndex < 0 || axisIndex >= PUB.iLock.Length) { return JsonConvert.SerializeObject(new { success = false, message = "Invalid axis index" }); } var curValue = PUB.iLock[axisIndex].get(lockIndex); PUB.iLock[axisIndex].set(lockIndex, !curValue, "IOMONITOR_WEB"); PUB.log.Add($"[Web] Interlock toggle: axis={axisIndex}, lock={lockIndex}, newVal={!curValue}"); return JsonConvert.SerializeObject(new { success = true, newState = !curValue }); } catch (Exception ex) { Console.WriteLine($"[ERROR] Failed to toggle interlock: {ex.Message}"); return JsonConvert.SerializeObject(new { success = false, message = ex.Message }); } } // ===== HISTORY DATA ===== /// /// 작업 이력 데이터 조회 (fHistory.cs의 refreshList와 동일) /// public string GetHistoryData(string startDate, string endDate, string search) { try { var results = new List(); using (var ta = new DataSet1TableAdapters.K4EE_Component_Reel_ResultTableAdapter()) { var ds = new DataSet1(); // 검색어 처리 var searchPattern = string.IsNullOrEmpty(search) ? "%" : "%" + search + "%"; // DB에서 조회 ta.FillBySearch(ds.K4EE_Component_Reel_Result, AR.SETTING.Data.McName, startDate, endDate, searchPattern); foreach (DataSet1.K4EE_Component_Reel_ResultRow row in ds.K4EE_Component_Reel_Result.Rows) { results.Add(new { idx = row.idx, jtype = row.IsJTYPENull() ? "" : row.JTYPE, rid = row.IsRIDNull() ? "" : row.RID, sid = row.IsSIDNull() ? "" : row.SID, qty = row.IsQTYNull() ? 0 : row.QTY, vname = row.IsVNAMENull() ? "" : row.VNAME, vlot = row.IsVLOTNull() ? "" : row.VLOT, loc = row.IsLOCNull() ? "" : row.LOC, qr = row.IsQRNull() ? "" : row.QR, stime = row.STIME.ToString("yyyy-MM-dd HH:mm:ss"), etime = row.IsETIMENull() ? "" : row.ETIME.ToString("yyyy-MM-dd HH:mm:ss"), prnattach = !row.IsPRNATTACHNull() && row.PRNATTACH, prnvalid = !row.IsPRNVALIDNull() && row.PRNVALID, rid0 = row.IsRID0Null() ? "" : row.RID0, sid0 = row.IsSID0Null() ? "" : row.SID0, qtymax = row.IsqtymaxNull() ? 0 : row.qtymax }); } } return JsonConvert.SerializeObject(new { success = true, data = results, mcName = AR.SETTING.Data.McName }); } catch (Exception ex) { Console.WriteLine($"[ERROR] Failed to get history data: {ex.Message}"); return JsonConvert.SerializeObject(new { success = false, message = ex.Message, data = new List() }); } } // ===== HARDWARE STATUS METHODS ===== /// /// H/W 상태 조회 (_Interval_250ms.cs의 HWState 업데이트 로직과 동일) /// public string GetHWStatus() { try { var hwList = new List(); // 1. KeyenceF (BCD Front) - 바코드 리더 if (PUB.keyenceF != null) { hwList.Add(new { name = "BCD-F", title = PUB.keyenceF.IsConnect ? (PUB.keyenceF.IsTriggerOn ? "TRIG" : "ON") : "OFF", status = PUB.keyenceF.IsConnect ? (PUB.keyenceF.IsTriggerOn ? 2 : 1) : 3 }); } else { hwList.Add(new { name = "BCD-F", title = "SET", status = 0 }); } // 2. KeyenceR (BCD Rear) - 바코드 리더 if (PUB.keyenceR != null) { hwList.Add(new { name = "BCD-R", title = PUB.keyenceR.IsConnect ? (PUB.keyenceR.IsTriggerOn ? "TRIG" : "ON") : "OFF", status = PUB.keyenceR.IsConnect ? (PUB.keyenceR.IsTriggerOn ? 2 : 1) : 3 }); } else { hwList.Add(new { name = "BCD-R", title = "SET", status = 0 }); } // 3. Vision WebSocket Left if (PUB.wsL != null) { hwList.Add(new { name = "VIS-L", title = PUB.wsL.Connected ? "ON" : "OFF", status = PUB.wsL.Connected ? 1 : 3 }); } else { hwList.Add(new { name = "VIS-L", title = "SET", status = 0 }); } // 4. Vision WebSocket Right if (PUB.wsR != null) { hwList.Add(new { name = "VIS-R", title = PUB.wsR.Connected ? "ON" : "OFF", status = PUB.wsR.Connected ? 1 : 3 }); } else { hwList.Add(new { name = "VIS-R", title = "SET", status = 0 }); } // 5. BarcodeFix (Fixed Barcode Reader) hwList.Add(new { name = "FIX", title = PUB.BarcodeFix.IsOpen() ? AR.SETTING.Data.Barcode_Port : "OFF", status = PUB.BarcodeFix.IsOpen() ? 1 : 3 }); // 6. PrinterL if (PUB.PrinterL != null) { hwList.Add(new { name = "PRT-L", title = PUB.PrinterL.IsOpen ? AR.SETTING.Data.PrintL_Port : "OFF", status = PUB.PrinterL.IsOpen ? 1 : 3 }); } else { hwList.Add(new { name = "PRT-L", title = "SET", status = 0 }); } // 7. PrinterR if (PUB.PrinterR != null) { hwList.Add(new { name = "PRT-R", title = PUB.PrinterR.IsOpen ? AR.SETTING.Data.PrintR_Port : "OFF", status = PUB.PrinterR.IsOpen ? 1 : 3 }); } else { hwList.Add(new { name = "PRT-R", title = "SET", status = 0 }); } // 8. PLC if (PUB.plc != null) { hwList.Add(new { name = "PLC", title = PUB.plc.Init ? AR.SETTING.Data.swplc_name : "OFF", status = PUB.plc.Init ? 1 : 3 }); } else { hwList.Add(new { name = "PLC", title = "SET", status = 0 }); } // 9. DIO (Digital I/O) hwList.Add(new { name = "DIO", title = PUB.dio?.IsInit == true ? "ON" : "OFF", status = PUB.dio?.IsInit == true ? 1 : 3 }); // 10. Motion hwList.Add(new { name = "MOT", title = PUB.mot?.IsInit == true ? "ON" : "OFF", status = PUB.mot?.IsInit == true ? 1 : 3 }); return JsonConvert.SerializeObject(hwList); } catch (Exception ex) { Console.WriteLine($"[ERROR] Failed to get HW status: {ex.Message}"); return JsonConvert.SerializeObject(new List()); } } /// /// 실시간 인식 데이터 조회 (listView21과 동일한 데이터) /// Left/Center/Right 포트의 VisionData 정보 /// public string GetVisionData() { try { var visdataL = PUB.Result.ItemDataL?.VisionData; var visdataC = PUB.Result.ItemDataC?.VisionData; var visdataR = PUB.Result.ItemDataR?.VisionData; var result = new { left = new { cartSize = DIO.getCartSize(0).ToString(), enabled = PUB.flag.get(eVarBool.FG_ENABLE_LEFT), rid = visdataL?.RID ?? "", sid = visdataL?.SID ?? "", qty = visdataL?.QTY ?? "", vname = visdataL?.VNAME ?? "", vlot = visdataL?.VLOT ?? "", mfgdate = visdataL?.MFGDATE ?? "", partno = visdataL?.PARTNO ?? "", reelSize = visdataL?.ReelSize.ToString() ?? "--", batch = visdataL?.BATCH ?? "", rid2 = visdataL?.RID2 ?? "", sid2 = visdataL?.SID2 ?? "", qty2 = visdataL?.QTY2 ?? "", vname2 = visdataL?.VNAME2 ?? "", vlot2 = visdataL?.VLOT2 ?? "", mfgdate2 = visdataL?.MFGDATE2 ?? "", partno2 = visdataL?.PARTNO2 ?? "" }, center = new { cartSize = DIO.getCartSize(1).ToString(), confirm = visdataC?.Confirm ?? false, rid = visdataC?.RID ?? "", rid_trust = visdataC?.RID_Trust ?? false, rid_new = visdataC?.RIDNew ?? false, sid = visdataC?.SID ?? "", sid0 = visdataC?.SID0 ?? "", sid_trust = visdataC?.SID_Trust ?? false, qty = visdataC?.QTY ?? "", qty_trust = visdataC?.QTY_Trust ?? false, qty_rq = visdataC?.QTYRQ ?? false, vname = visdataC?.VNAME ?? "", vname_trust = visdataC?.VNAME_Trust ?? false, vlot = visdataC?.VLOT ?? "", vlot_trust = visdataC?.VLOT_Trust ?? false, mfgdate = visdataC?.MFGDATE ?? "", mfgdate_trust = visdataC?.MFGDATE_Trust ?? false, partno = visdataC?.PARTNO ?? "", partno_trust = visdataC?.PARTNO_Trust ?? false, reelSize = visdataC?.ReelSize.ToString() ?? "--", batch = visdataC?.BATCH ?? "", qtymax = visdataC?.QTYMAX ?? "", barcodeCount = visdataC?.barcodelist?.Count ?? 0, regexCount = PUB.Result.BCDPattern?.Count ?? 0 }, right = new { cartSize = DIO.getCartSize(2).ToString(), enabled = PUB.flag.get(eVarBool.FG_ENABLE_RIGHT), rid = visdataR?.RID ?? "", sid = visdataR?.SID ?? "", qty = visdataR?.QTY ?? "", vname = visdataR?.VNAME ?? "", vlot = visdataR?.VLOT ?? "", mfgdate = visdataR?.MFGDATE ?? "", partno = visdataR?.PARTNO ?? "", reelSize = visdataR?.ReelSize.ToString() ?? "--", batch = visdataR?.BATCH ?? "", rid2 = visdataR?.RID2 ?? "", sid2 = visdataR?.SID2 ?? "", qty2 = visdataR?.QTY2 ?? "", vname2 = visdataR?.VNAME2 ?? "", vlot2 = visdataR?.VLOT2 ?? "", mfgdate2 = visdataR?.MFGDATE2 ?? "", partno2 = visdataR?.PARTNO2 ?? "" } }; return JsonConvert.SerializeObject(result); } catch (Exception ex) { Console.WriteLine($"[ERROR] Failed to get vision data: {ex.Message}"); return JsonConvert.SerializeObject(new { left = new { }, center = new { }, right = new { } }); } } /// /// 인터락 목록 조회 (실시간 값 포함) /// public string GetInterlockList() { try { var interlocks = new List(); for (int i = 0; i < PUB.iLock.Length; i++) { var axisName = ((AR.eAxis)i).ToString(); var nonAxis = false; if (i >= 7) { axisName = PUB.iLock[i].Tag.ToString(); nonAxis = true; } 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)); var lockValues = new List(); 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() }); } return JsonConvert.SerializeObject(interlocks); } catch (Exception ex) { Console.WriteLine($"[ERROR] Failed to get interlock list: {ex.Message}"); return JsonConvert.SerializeObject(new List()); } } } }