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,8 @@ using Microsoft.Web.WebView2.Core;
|
||||
using Microsoft.Web.WebView2.WinForms;
|
||||
using Newtonsoft.Json;
|
||||
using Project.WebUI;
|
||||
using AR;
|
||||
using arDev.DIO;
|
||||
|
||||
namespace Project.Dialog
|
||||
{
|
||||
@@ -15,14 +17,16 @@ namespace Project.Dialog
|
||||
private Timer plcTimer;
|
||||
private WebSocketServer _wsServer;
|
||||
|
||||
// Machine State (Simulated PLC Memory)
|
||||
// Machine State
|
||||
private double currX = 0, currY = 0, currZ = 0;
|
||||
private double targetX = 0, targetY = 0, targetZ = 0;
|
||||
private bool[] inputs = new bool[32];
|
||||
private bool[] outputs = new bool[32];
|
||||
private string systemState = "IDLE";
|
||||
private string currentRecipeId = "1"; // Default recipe
|
||||
|
||||
// IO 캐시 (변경된 값만 전송하기 위함)
|
||||
private bool[] _lastInputs;
|
||||
private bool[] _lastOutputs;
|
||||
|
||||
public fWebView()
|
||||
{
|
||||
InitializeComponent();
|
||||
@@ -38,25 +42,149 @@ namespace Project.Dialog
|
||||
MessageBox.Show("Failed to start WebSocket Server (Port 8081). Run as Admin or allow port.\n" + ex.Message);
|
||||
}
|
||||
|
||||
// Set default inputs (Pressure OK, Estop OK)
|
||||
inputs[4] = true;
|
||||
inputs[6] = true;
|
||||
// IO 캐시 초기화
|
||||
int diCount = PUB.dio?.GetDICount ?? 32;
|
||||
int doCount = PUB.dio?.GetDOCount ?? 32;
|
||||
_lastInputs = new bool[diCount];
|
||||
_lastOutputs = new bool[doCount];
|
||||
|
||||
// IO 값 변경 이벤트 구독 (DIOMonitor.cs와 동일)
|
||||
if (PUB.dio != null)
|
||||
{
|
||||
PUB.dio.IOValueChanged += Dio_IOValueChanged;
|
||||
}
|
||||
|
||||
// 인터락 값 변경 이벤트 구독 (DIOMonitor.cs와 동일)
|
||||
if (PUB.iLock != null)
|
||||
{
|
||||
for (int i = 0; i < PUB.iLock.Length; i++)
|
||||
{
|
||||
PUB.iLock[i].ValueChanged += ILock_ValueChanged;
|
||||
}
|
||||
}
|
||||
|
||||
// Load event handler
|
||||
this.Load += FWebView_Load;
|
||||
this.FormClosed += FWebView_FormClosed;
|
||||
}
|
||||
|
||||
private void FWebView_FormClosed(object sender, FormClosedEventArgs e)
|
||||
{
|
||||
// IO 이벤트 구독 해제
|
||||
if (PUB.dio != null)
|
||||
{
|
||||
PUB.dio.IOValueChanged -= Dio_IOValueChanged;
|
||||
}
|
||||
|
||||
// 인터락 이벤트 구독 해제
|
||||
if (PUB.iLock != null)
|
||||
{
|
||||
for (int i = 0; i < PUB.iLock.Length; i++)
|
||||
{
|
||||
PUB.iLock[i].ValueChanged -= ILock_ValueChanged;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 인터락 값 변경 이벤트 핸들러 (DIOMonitor.cs의 LockXF_ValueChanged와 동일)
|
||||
private void ILock_ValueChanged(object sender, AR.InterfaceValueEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
var item = sender as CInterLock;
|
||||
if (item == null) return;
|
||||
|
||||
var axisIndex = item.idx;
|
||||
|
||||
var ilockUpdate = new
|
||||
{
|
||||
type = "INTERLOCK_CHANGED",
|
||||
data = new
|
||||
{
|
||||
axisIndex = axisIndex,
|
||||
lockIndex = (int)e.ArrIDX,
|
||||
state = e.NewValue,
|
||||
hexValue = item.Value().HexString()
|
||||
}
|
||||
};
|
||||
|
||||
string json = JsonConvert.SerializeObject(ilockUpdate);
|
||||
|
||||
// WebView2로 전송
|
||||
if (webView != null && webView.CoreWebView2 != null)
|
||||
{
|
||||
this.BeginInvoke(new Action(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
webView.CoreWebView2.PostWebMessageAsJson(json);
|
||||
}
|
||||
catch { }
|
||||
}));
|
||||
}
|
||||
|
||||
// WebSocket으로 전송
|
||||
_wsServer?.Broadcast(json);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"[fWebView] Interlock change broadcast error: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
// IO 값 변경 이벤트 핸들러 (DIOMonitor.cs의 dio_IOValueChanged와 동일)
|
||||
private void Dio_IOValueChanged(object sender, IOValueEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 변경된 IO만 즉시 전송
|
||||
var ioUpdate = new
|
||||
{
|
||||
type = "IO_CHANGED",
|
||||
data = new
|
||||
{
|
||||
id = e.ArrIDX,
|
||||
ioType = e.Direction == eIOPINDIR.INPUT ? "input" : "output",
|
||||
state = e.NewValue
|
||||
}
|
||||
};
|
||||
|
||||
string json = JsonConvert.SerializeObject(ioUpdate);
|
||||
|
||||
// WebView2로 전송
|
||||
if (webView != null && webView.CoreWebView2 != null)
|
||||
{
|
||||
this.BeginInvoke(new Action(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
webView.CoreWebView2.PostWebMessageAsJson(json);
|
||||
}
|
||||
catch { }
|
||||
}));
|
||||
}
|
||||
|
||||
// WebSocket으로 전송
|
||||
_wsServer?.Broadcast(json);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"[fWebView] IO change broadcast error: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.SuspendLayout();
|
||||
|
||||
// Form
|
||||
this.ClientSize = new System.Drawing.Size(1200, 800);
|
||||
this.Text = "STD Label Attach - Web UI";
|
||||
//
|
||||
// fWebView
|
||||
//
|
||||
this.ClientSize = new System.Drawing.Size(1784, 961);
|
||||
this.Name = "fWebView";
|
||||
this.StartPosition = FormStartPosition.CenterScreen;
|
||||
|
||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
|
||||
this.Text = "STD Label Attach - Web UI";
|
||||
this.ResumeLayout(false);
|
||||
|
||||
}
|
||||
|
||||
private async void InitializeWebView()
|
||||
@@ -106,6 +234,9 @@ namespace Project.Dialog
|
||||
}
|
||||
}
|
||||
|
||||
// HW 상태 업데이트 카운터 (250ms 주기 = 50ms * 5)
|
||||
private int _hwUpdateCounter = 0;
|
||||
|
||||
// --- Logic Loop ---
|
||||
private void PlcTimer_Tick(object sender, EventArgs e)
|
||||
{
|
||||
@@ -114,36 +245,105 @@ namespace Project.Dialog
|
||||
currY = Lerp(currY, targetY, 0.1);
|
||||
currZ = Lerp(currZ, targetZ, 0.1);
|
||||
|
||||
// 2. Prepare Data Packet
|
||||
// 2. 시스템 상태 업데이트
|
||||
if (PUB.sm != null)
|
||||
{
|
||||
systemState = PUB.sm.Step.ToString();
|
||||
}
|
||||
|
||||
// 3. Prepare Data Packet
|
||||
var payload = new
|
||||
{
|
||||
type = "STATUS_UPDATE",
|
||||
sysState = systemState,
|
||||
position = new { x = currX, y = currY, z = currZ },
|
||||
ioState = GetChangedIOs() // Function to return array of IO states
|
||||
ioState = GetChangedIOs() // 변경된 IO만 전송
|
||||
};
|
||||
|
||||
string json = JsonConvert.SerializeObject(payload);
|
||||
|
||||
// 3. Send to React via PostMessage (WebView2)
|
||||
// 4. Send to React via PostMessage (WebView2)
|
||||
if (webView != null && webView.CoreWebView2 != null)
|
||||
{
|
||||
webView.CoreWebView2.PostWebMessageAsJson(json);
|
||||
}
|
||||
|
||||
// 4. Broadcast to WebSocket (Dev/HMR)
|
||||
// 5. Broadcast to WebSocket (Dev/HMR)
|
||||
_wsServer?.Broadcast(json);
|
||||
|
||||
// 6. HW 상태 업데이트 (250ms 주기 - 윈폼의 _Display_Interval_250ms와 동일)
|
||||
_hwUpdateCounter++;
|
||||
if (_hwUpdateCounter >= 5) // 50ms * 5 = 250ms
|
||||
{
|
||||
_hwUpdateCounter = 0;
|
||||
BroadcastHWStatus();
|
||||
}
|
||||
}
|
||||
|
||||
// H/W 상태 브로드캐스트 (윈폼의 HWState 업데이트와 동일)
|
||||
private void BroadcastHWStatus()
|
||||
{
|
||||
try
|
||||
{
|
||||
var bridge = new WebUI.MachineBridge(this);
|
||||
string hwStatusJson = bridge.GetHWStatus();
|
||||
|
||||
var payload = new
|
||||
{
|
||||
type = "HW_STATUS_UPDATE",
|
||||
data = JsonConvert.DeserializeObject(hwStatusJson)
|
||||
};
|
||||
|
||||
string json = JsonConvert.SerializeObject(payload);
|
||||
|
||||
// WebView2로 전송
|
||||
if (webView != null && webView.CoreWebView2 != null)
|
||||
{
|
||||
webView.CoreWebView2.PostWebMessageAsJson(json);
|
||||
}
|
||||
|
||||
// WebSocket으로 전송
|
||||
_wsServer?.Broadcast(json);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"[fWebView] HW status broadcast error: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private List<object> GetChangedIOs()
|
||||
{
|
||||
// Simply return list of all active IOs or just send all for simplicity
|
||||
var list = new List<object>();
|
||||
for (int i = 0; i < 32; i++)
|
||||
|
||||
// 실제 DIO에서 값 읽기
|
||||
if (PUB.dio != null)
|
||||
{
|
||||
list.Add(new { id = i, type = "input", state = inputs[i] });
|
||||
list.Add(new { id = i, type = "output", state = outputs[i] });
|
||||
int diCount = PUB.dio.GetDICount;
|
||||
int doCount = PUB.dio.GetDOCount;
|
||||
|
||||
// DI (Digital Input) - 변경된 값만 추가
|
||||
for (int i = 0; i < diCount && i < _lastInputs.Length; i++)
|
||||
{
|
||||
bool currentValue = PUB.dio.GetDIValue(i);
|
||||
if (currentValue != _lastInputs[i])
|
||||
{
|
||||
list.Add(new { id = i, type = "input", state = currentValue });
|
||||
_lastInputs[i] = currentValue;
|
||||
}
|
||||
}
|
||||
|
||||
// DO (Digital Output) - 변경된 값만 추가
|
||||
for (int i = 0; i < doCount && i < _lastOutputs.Length; i++)
|
||||
{
|
||||
bool currentValue = PUB.dio.GetDOValue(i);
|
||||
if (currentValue != _lastOutputs[i])
|
||||
{
|
||||
list.Add(new { id = i, type = "output", state = currentValue });
|
||||
_lastOutputs[i] = currentValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
@@ -164,9 +364,37 @@ namespace Project.Dialog
|
||||
if (axis == "Z") targetZ = val;
|
||||
}
|
||||
|
||||
public void SetOutput(int id, bool state)
|
||||
// DO 출력 제어 (DIOMonitor.cs의 tblDO_ItemClick과 동일한 로직)
|
||||
public bool SetOutput(int id, bool state)
|
||||
{
|
||||
if (id < 32) outputs[id] = state;
|
||||
try
|
||||
{
|
||||
if (PUB.dio == null)
|
||||
{
|
||||
Console.WriteLine($"[fWebView] SetOutput failed: DIO not initialized");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (PUB.dio.IsInit == false)
|
||||
{
|
||||
// DIO가 초기화되지 않은 경우 가상 신호 생성 (디버그 모드)
|
||||
PUB.dio.RaiseEvent(eIOPINDIR.OUTPUT, id, state);
|
||||
PUB.log.Add($"[Web] Fake DO: idx={id}, val={state}");
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 실제 출력 제어
|
||||
PUB.dio.SetOutput(id, state);
|
||||
PUB.log.Add($"[Web] Set output: idx={id}, val={state}");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"[fWebView] SetOutput error: {ex.Message}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public void HandleCommand(string cmd)
|
||||
@@ -214,5 +442,34 @@ namespace Project.Dialog
|
||||
Console.WriteLine($"PostMessage failed: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
// 이벤트 브로드캐스트 (WebView2 + WebSocket)
|
||||
public void BroadcastEvent(string eventType, object data = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
var payload = new
|
||||
{
|
||||
type = eventType,
|
||||
data = data
|
||||
};
|
||||
string json = JsonConvert.SerializeObject(payload);
|
||||
|
||||
// WebView2로 전송
|
||||
if (webView != null && webView.CoreWebView2 != null)
|
||||
{
|
||||
webView.CoreWebView2.PostWebMessageAsJson(json);
|
||||
}
|
||||
|
||||
// WebSocket으로 전송
|
||||
_wsServer?.Broadcast(json);
|
||||
|
||||
Console.WriteLine($"[fWebView] BroadcastEvent: {eventType}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"BroadcastEvent failed: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
120
Handler/Project/Dialog/fWebView.resx
Normal file
120
Handler/Project/Dialog/fWebView.resx
Normal file
@@ -0,0 +1,120 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
||||
@@ -32,8 +32,12 @@ namespace Project
|
||||
//Pub.sm.setNewStep(eSMStep.XMOVE); //홈을 위해서 바로 이동 모션으로 가게한다
|
||||
if (PUB.mot.HasHomeSetOff == true && DIO.GetIOInput(eDIName.PICKER_SAFE) == false)
|
||||
{
|
||||
//피커의 이동이 필요한 상황
|
||||
this.BeginInvoke(new Action(() => { btManage.PerformClick(); }));
|
||||
// 웹 UI에도 자동 관리창 열기 이벤트 전송
|
||||
SendWebEvent("AUTO_OPEN_MANAGE", new { reason = "Picker needs to be moved to safe position" });
|
||||
|
||||
//피커의 이동이 필요한 상황
|
||||
this.BeginInvoke(new Action(() => { btManage.PerformClick(); }));
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -730,6 +730,9 @@
|
||||
<EmbeddedResource Include="Dialog\fVAR.resx">
|
||||
<DependentUpon>fVAR.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Dialog\fWebView.resx">
|
||||
<DependentUpon>fWebView.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Dialog\fZPLEditor.resx">
|
||||
<DependentUpon>fZPLEditor.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
|
||||
@@ -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>());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -334,6 +334,13 @@ namespace Project.WebUI
|
||||
var response = new { type = "MANAGE_RESULT", data = Newtonsoft.Json.JsonConvert.DeserializeObject(resultJson) };
|
||||
await Send(socket, Newtonsoft.Json.JsonConvert.SerializeObject(response));
|
||||
}
|
||||
else if (type == "CLOSE_MANAGE")
|
||||
{
|
||||
var bridge = new MachineBridge(_mainForm);
|
||||
string resultJson = bridge.CloseManage();
|
||||
var response = new { type = "CLOSE_MANAGE_RESULT", data = Newtonsoft.Json.JsonConvert.DeserializeObject(resultJson) };
|
||||
await Send(socket, Newtonsoft.Json.JsonConvert.SerializeObject(response));
|
||||
}
|
||||
else if (type == "OPEN_MANUAL")
|
||||
{
|
||||
var bridge = new MachineBridge(_mainForm);
|
||||
@@ -376,6 +383,151 @@ namespace Project.WebUI
|
||||
var response = new { type = "FOLDER_RESULT", data = Newtonsoft.Json.JsonConvert.DeserializeObject(resultJson) };
|
||||
await Send(socket, Newtonsoft.Json.JsonConvert.SerializeObject(response));
|
||||
}
|
||||
// ===== PICKER MOVE HANDLERS =====
|
||||
else if (type == "GET_PICKER_STATUS")
|
||||
{
|
||||
var bridge = new MachineBridge(_mainForm);
|
||||
string resultJson = bridge.GetPickerStatus();
|
||||
var response = new { type = "PICKER_STATUS", data = Newtonsoft.Json.JsonConvert.DeserializeObject(resultJson) };
|
||||
await Send(socket, Newtonsoft.Json.JsonConvert.SerializeObject(response));
|
||||
}
|
||||
else if (type == "PICKER_MOVE_LEFT")
|
||||
{
|
||||
var bridge = new MachineBridge(_mainForm);
|
||||
string resultJson = bridge.PickerMoveLeft();
|
||||
var response = new { type = "PICKER_RESULT", data = Newtonsoft.Json.JsonConvert.DeserializeObject(resultJson) };
|
||||
await Send(socket, Newtonsoft.Json.JsonConvert.SerializeObject(response));
|
||||
}
|
||||
else if (type == "PICKER_MOVE_LEFT_WAIT")
|
||||
{
|
||||
var bridge = new MachineBridge(_mainForm);
|
||||
string resultJson = bridge.PickerMoveLeftWait();
|
||||
var response = new { type = "PICKER_RESULT", data = Newtonsoft.Json.JsonConvert.DeserializeObject(resultJson) };
|
||||
await Send(socket, Newtonsoft.Json.JsonConvert.SerializeObject(response));
|
||||
}
|
||||
else if (type == "PICKER_MOVE_CENTER")
|
||||
{
|
||||
var bridge = new MachineBridge(_mainForm);
|
||||
string resultJson = bridge.PickerMoveCenter();
|
||||
var response = new { type = "PICKER_RESULT", data = Newtonsoft.Json.JsonConvert.DeserializeObject(resultJson) };
|
||||
await Send(socket, Newtonsoft.Json.JsonConvert.SerializeObject(response));
|
||||
}
|
||||
else if (type == "PICKER_MOVE_RIGHT_WAIT")
|
||||
{
|
||||
var bridge = new MachineBridge(_mainForm);
|
||||
string resultJson = bridge.PickerMoveRightWait();
|
||||
var response = new { type = "PICKER_RESULT", data = Newtonsoft.Json.JsonConvert.DeserializeObject(resultJson) };
|
||||
await Send(socket, Newtonsoft.Json.JsonConvert.SerializeObject(response));
|
||||
}
|
||||
else if (type == "PICKER_MOVE_RIGHT")
|
||||
{
|
||||
var bridge = new MachineBridge(_mainForm);
|
||||
string resultJson = bridge.PickerMoveRight();
|
||||
var response = new { type = "PICKER_RESULT", data = Newtonsoft.Json.JsonConvert.DeserializeObject(resultJson) };
|
||||
await Send(socket, Newtonsoft.Json.JsonConvert.SerializeObject(response));
|
||||
}
|
||||
else if (type == "PICKER_JOG_START")
|
||||
{
|
||||
var bridge = new MachineBridge(_mainForm);
|
||||
string direction = json["direction"]?.ToString() ?? "";
|
||||
string resultJson = bridge.PickerJogStart(direction);
|
||||
var response = new { type = "PICKER_JOG_RESULT", data = Newtonsoft.Json.JsonConvert.DeserializeObject(resultJson) };
|
||||
await Send(socket, Newtonsoft.Json.JsonConvert.SerializeObject(response));
|
||||
}
|
||||
else if (type == "PICKER_JOG_STOP")
|
||||
{
|
||||
var bridge = new MachineBridge(_mainForm);
|
||||
string resultJson = bridge.PickerJogStop();
|
||||
var response = new { type = "PICKER_JOG_RESULT", data = Newtonsoft.Json.JsonConvert.DeserializeObject(resultJson) };
|
||||
await Send(socket, Newtonsoft.Json.JsonConvert.SerializeObject(response));
|
||||
}
|
||||
else if (type == "PICKER_STOP")
|
||||
{
|
||||
var bridge = new MachineBridge(_mainForm);
|
||||
string resultJson = bridge.PickerStop();
|
||||
var response = new { type = "PICKER_RESULT", data = Newtonsoft.Json.JsonConvert.DeserializeObject(resultJson) };
|
||||
await Send(socket, Newtonsoft.Json.JsonConvert.SerializeObject(response));
|
||||
}
|
||||
else if (type == "CANCEL_VISION_VALIDATION")
|
||||
{
|
||||
var bridge = new MachineBridge(_mainForm);
|
||||
string side = json["side"]?.ToString() ?? "left";
|
||||
string resultJson = bridge.CancelVisionValidation(side);
|
||||
var response = new { type = "VISION_CANCEL_RESULT", data = Newtonsoft.Json.JsonConvert.DeserializeObject(resultJson) };
|
||||
await Send(socket, Newtonsoft.Json.JsonConvert.SerializeObject(response));
|
||||
}
|
||||
else if (type == "PICKER_MANAGE_POSITION")
|
||||
{
|
||||
var bridge = new MachineBridge(_mainForm);
|
||||
string side = json["side"]?.ToString() ?? "left";
|
||||
string resultJson = bridge.PickerManagePosition(side);
|
||||
var response = new { type = "PICKER_MANAGE_RESULT", data = Newtonsoft.Json.JsonConvert.DeserializeObject(resultJson) };
|
||||
await Send(socket, Newtonsoft.Json.JsonConvert.SerializeObject(response));
|
||||
}
|
||||
else if (type == "PICKER_MANAGE_RETURN")
|
||||
{
|
||||
var bridge = new MachineBridge(_mainForm);
|
||||
string resultJson = bridge.PickerManageReturn();
|
||||
var response = new { type = "PICKER_MANAGE_RESULT", data = Newtonsoft.Json.JsonConvert.DeserializeObject(resultJson) };
|
||||
await Send(socket, Newtonsoft.Json.JsonConvert.SerializeObject(response));
|
||||
}
|
||||
else if (type == "PICKER_Z_HOME")
|
||||
{
|
||||
var bridge = new MachineBridge(_mainForm);
|
||||
string resultJson = bridge.PickerZHome();
|
||||
var response = new { type = "PICKER_RESULT", data = Newtonsoft.Json.JsonConvert.DeserializeObject(resultJson) };
|
||||
await Send(socket, Newtonsoft.Json.JsonConvert.SerializeObject(response));
|
||||
}
|
||||
else if (type == "PICKER_Z_ZERO")
|
||||
{
|
||||
var bridge = new MachineBridge(_mainForm);
|
||||
string resultJson = bridge.PickerZZero();
|
||||
var response = new { type = "PICKER_RESULT", data = Newtonsoft.Json.JsonConvert.DeserializeObject(resultJson) };
|
||||
await Send(socket, Newtonsoft.Json.JsonConvert.SerializeObject(response));
|
||||
}
|
||||
else if (type == "PICKER_TEST_PRINT")
|
||||
{
|
||||
var bridge = new MachineBridge(_mainForm);
|
||||
string side = json["side"]?.ToString() ?? "left";
|
||||
string resultJson = bridge.PickerTestPrint(side);
|
||||
var response = new { type = "PICKER_PRINT_RESULT", data = Newtonsoft.Json.JsonConvert.DeserializeObject(resultJson) };
|
||||
await Send(socket, Newtonsoft.Json.JsonConvert.SerializeObject(response));
|
||||
}
|
||||
else if (type == "CAN_CLOSE_MANAGE")
|
||||
{
|
||||
var bridge = new MachineBridge(_mainForm);
|
||||
string resultJson = bridge.CanCloseManage();
|
||||
var response = new { type = "CAN_CLOSE_MANAGE_RESULT", data = Newtonsoft.Json.JsonConvert.DeserializeObject(resultJson) };
|
||||
await Send(socket, Newtonsoft.Json.JsonConvert.SerializeObject(response));
|
||||
}
|
||||
// ===== HISTORY DATA =====
|
||||
else if (type == "GET_HISTORY_DATA")
|
||||
{
|
||||
var bridge = new MachineBridge(_mainForm);
|
||||
string startDate = json["startDate"]?.ToString() ?? DateTime.Now.ToShortDateString();
|
||||
string endDate = json["endDate"]?.ToString() ?? DateTime.Now.ToShortDateString();
|
||||
string search = json["search"]?.ToString() ?? "";
|
||||
string resultJson = bridge.GetHistoryData(startDate, endDate, search);
|
||||
var response = new { type = "HISTORY_DATA_RESULT", data = Newtonsoft.Json.JsonConvert.DeserializeObject(resultJson) };
|
||||
await Send(socket, Newtonsoft.Json.JsonConvert.SerializeObject(response));
|
||||
}
|
||||
// ===== INTERLOCK HANDLERS =====
|
||||
else if (type == "TOGGLE_INTERLOCK")
|
||||
{
|
||||
var bridge = new MachineBridge(_mainForm);
|
||||
int axisIndex = json["axisIndex"]?.ToObject<int>() ?? 0;
|
||||
int lockIndex = json["lockIndex"]?.ToObject<int>() ?? 0;
|
||||
string resultJson = bridge.ToggleInterlock(axisIndex, lockIndex);
|
||||
var response = new { type = "TOGGLE_INTERLOCK_RESULT", data = Newtonsoft.Json.JsonConvert.DeserializeObject(resultJson) };
|
||||
await Send(socket, Newtonsoft.Json.JsonConvert.SerializeObject(response));
|
||||
}
|
||||
else if (type == "GET_INTERLOCK_LIST")
|
||||
{
|
||||
var bridge = new MachineBridge(_mainForm);
|
||||
string resultJson = bridge.GetInterlockList();
|
||||
var response = new { type = "INTERLOCK_LIST_RESULT", data = Newtonsoft.Json.JsonConvert.DeserializeObject(resultJson) };
|
||||
await Send(socket, Newtonsoft.Json.JsonConvert.SerializeObject(response));
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
@@ -493,6 +493,18 @@ namespace Project
|
||||
|
||||
Dialog.fWebView fwebview = null;
|
||||
|
||||
// 웹 UI에 이벤트 전송
|
||||
public void SendWebEvent(string eventType, object data = null)
|
||||
{
|
||||
if (fwebview != null)
|
||||
{
|
||||
this.BeginInvoke(new Action(() =>
|
||||
{
|
||||
fwebview.BroadcastEvent(eventType, data);
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
private void Plc_ValueChanged(object sender, AR.MemoryMap.Core.monitorvalueargs e)
|
||||
{
|
||||
//
|
||||
|
||||
Reference in New Issue
Block a user