feat: Add real-time IO/interlock updates, HW status display, and history page
- Implement real-time IO value updates via IOValueChanged event - Add interlock toggle and real-time interlock change events - Fix ToggleLight to check return value of DIO.SetRoomLight - Add HW status display in Footer matching WinForms HWState - Implement GetHWStatus API and 250ms broadcast interval - Create HistoryPage React component for work history viewing - Add GetHistoryData API for database queries - Add date range selection, search, filter, and CSV export - Add History button in Header navigation - Add PickerMoveDialog component for manage operations - Fix DataSet column names (idx, PRNATTACH, PRNVALID, qtymax) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -6,6 +6,7 @@ using System.IO;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using AR;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Project.WebUI
|
||||
{
|
||||
@@ -1145,7 +1146,14 @@ namespace Project.WebUI
|
||||
}
|
||||
|
||||
var cur = DIO.GetIOOutput(AR.eDOName.ROOMLIGHT);
|
||||
DIO.SetRoomLight(!cur, true);
|
||||
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);
|
||||
@@ -1173,7 +1181,7 @@ namespace Project.WebUI
|
||||
var selectedPrinter = printer.ToLower() == "left" ? PUB.PrinterL : PUB.PrinterR;
|
||||
|
||||
// Create ZPL
|
||||
string zpl = selectedPrinter.makeZPL_210908(new AR.Class.Reel
|
||||
string zpl = selectedPrinter.makeZPL_210908(new Class.Reel
|
||||
{
|
||||
SID = sid,
|
||||
venderLot = venderLot,
|
||||
@@ -1290,10 +1298,11 @@ namespace Project.WebUI
|
||||
return JsonConvert.SerializeObject(response);
|
||||
}
|
||||
|
||||
// The manage dialog (fPickerMove) cannot be opened from web UI
|
||||
// This would require implementing a separate picker management page
|
||||
// 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 = false, message = "Manage is not available in Web UI. Please use the main program." };
|
||||
|
||||
var response2 = new { success = true, message = "Manage dialog opened" };
|
||||
return JsonConvert.SerializeObject(response2);
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -1304,6 +1313,29 @@ namespace Project.WebUI
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
@@ -1433,5 +1465,837 @@ namespace Project.WebUI
|
||||
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 =====
|
||||
|
||||
/// <summary>
|
||||
/// 인터락 토글 (DIOMonitor.cs의 gvILXF_ItemClick과 동일)
|
||||
/// </summary>
|
||||
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 =====
|
||||
|
||||
/// <summary>
|
||||
/// 작업 이력 데이터 조회 (fHistory.cs의 refreshList와 동일)
|
||||
/// </summary>
|
||||
public string GetHistoryData(string startDate, string endDate, string search)
|
||||
{
|
||||
try
|
||||
{
|
||||
var results = new List<object>();
|
||||
|
||||
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<object>() });
|
||||
}
|
||||
}
|
||||
|
||||
// ===== HARDWARE STATUS METHODS =====
|
||||
|
||||
/// <summary>
|
||||
/// H/W 상태 조회 (_Interval_250ms.cs의 HWState 업데이트 로직과 동일)
|
||||
/// </summary>
|
||||
public string GetHWStatus()
|
||||
{
|
||||
try
|
||||
{
|
||||
var hwList = new List<object>();
|
||||
|
||||
// 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. 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<object>());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 인터락 목록 조회 (실시간 값 포함)
|
||||
/// </summary>
|
||||
public string GetInterlockList()
|
||||
{
|
||||
try
|
||||
{
|
||||
var interlocks = new List<object>();
|
||||
|
||||
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<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()
|
||||
});
|
||||
}
|
||||
|
||||
return JsonConvert.SerializeObject(interlocks);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"[ERROR] Failed to get interlock list: {ex.Message}");
|
||||
return JsonConvert.SerializeObject(new List<object>());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user