From 4f3e308d3d15aa6746348aec5667bd60003dcf7a Mon Sep 17 00:00:00 2001
From: "SIC1016\\caipeilun" <905168240@qq.com>
Date: Thu, 13 Aug 2026 22:07:07 +0800
Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E7=9B=B8=E6=9C=BA=E7=95=8C?=
=?UTF-8?q?=E9=9D=A2?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
App/SicRT/Config/Menu.xml | 1 +
App/SicUI/Controls/CameraControl.xaml | 31 +
App/SicUI/Controls/CameraControl.xaml.cs | 160 ++++
.../Models/Maintenances/TM/Device2View.xaml | 841 ++++++++++++++++++
.../Maintenances/TM/Device2View.xaml.cs | 29 +
.../Maintenances/TM/Device2ViewModel.cs | 216 +++++
App/SicUI/SicUI.csproj | 87 ++
7 files changed, 1365 insertions(+)
create mode 100644 App/SicUI/Controls/CameraControl.xaml
create mode 100644 App/SicUI/Controls/CameraControl.xaml.cs
create mode 100644 App/SicUI/Models/Maintenances/TM/Device2View.xaml
create mode 100644 App/SicUI/Models/Maintenances/TM/Device2View.xaml.cs
create mode 100644 App/SicUI/Models/Maintenances/TM/Device2ViewModel.cs
diff --git a/App/SicRT/Config/Menu.xml b/App/SicRT/Config/Menu.xml
index a53e586..a145464 100644
--- a/App/SicRT/Config/Menu.xml
+++ b/App/SicRT/Config/Menu.xml
@@ -11,6 +11,7 @@
+
diff --git a/App/SicUI/Controls/CameraControl.xaml b/App/SicUI/Controls/CameraControl.xaml
new file mode 100644
index 0000000..b9e17d9
--- /dev/null
+++ b/App/SicUI/Controls/CameraControl.xaml
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/App/SicUI/Controls/CameraControl.xaml.cs b/App/SicUI/Controls/CameraControl.xaml.cs
new file mode 100644
index 0000000..c1ab6ff
--- /dev/null
+++ b/App/SicUI/Controls/CameraControl.xaml.cs
@@ -0,0 +1,160 @@
+using Aitex.Core.RT.Log;
+using CommandLine;
+using MECF.Framework.Common.DataCenter;
+using SicUI.Controls.M2C4Parts;
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Drawing.Imaging;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using System.Security.Cryptography;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Navigation;
+using System.Windows.Shapes;
+using System.Windows.Threading;
+using VM.PlatformSDKCS;
+
+namespace SicUI.Controls
+{
+ ///
+ /// CameraControl.xaml 的交互逻辑
+ ///
+ public partial class CameraControl : UserControl
+ {
+
+ private WriteableBitmap _bitmap;
+ private Int32Rect _rect;
+ private CancellationTokenSource _cts;
+
+ public CameraControl()
+ {
+ InitializeComponent();
+
+ // 获取摄像头分辨率
+ var width = (int)QueryDataClient.Instance.Service.GetConfig("HikGigeCamera.Width");
+ var height = (int)QueryDataClient.Instance.Service.GetConfig("HikGigeCamera.Height");
+
+ // 创建 WriteableBitmap,注意像素格式需要与摄像头输出匹配(例如 Bgr24)
+ _bitmap = new WriteableBitmap(width, height, 96, 96, System.Windows.Media.PixelFormats.Bgr24, null);
+ _rect = new Int32Rect(0, 0, _bitmap.PixelWidth, _bitmap.PixelHeight);
+ // 只需设置一次 Source,不必每帧重新赋值
+ imageControl.Source = _bitmap;
+
+ }
+
+ private async Task CaptureLoop(CancellationToken token)
+ {
+ while (!token.IsCancellationRequested)
+ {
+ try
+ {
+ var obj = QueryDataClient.Instance.Service.GetData($"LoadLock.HikGigeCamera.CamBitmap");
+ if (obj != null)
+ {
+ Bitmap b = BytesToBitmap((byte[])obj);
+ // 在 UI 线程更新图像数据
+#pragma warning disable CS4014
+ Application.Current.Dispatcher.BeginInvoke(
+ DispatcherPriority.Background,
+ new Action(() => UpdateBitmap(b)));
+#pragma warning restore CS4014
+ }
+ }
+ catch (Exception ex)
+ {
+ LOG.Warning($"Camera Capture failed{ex}");
+ }
+
+ // 根据需要调整延时,防止 CPU 占用过高
+ // 异步延时,释放后台线程资源,并响应取消请求
+ try
+ {
+ await Task.Delay(20, token);
+ }
+ catch (OperationCanceledException)
+ {
+ break;
+ }
+ }
+ }
+
+ public Bitmap BytesToBitmap(byte[] bytes)
+ {
+ using (MemoryStream ms = new MemoryStream(bytes))
+ {
+ return new Bitmap(ms); // 或使用Image.FromStream:ml-citation{ref="1,18" data="citationList"}
+ }
+ }
+
+ ///
+ /// 更新预先创建的 WriteableBitmap 的像素数据
+ ///
+ private void UpdateBitmap(Bitmap frame)
+ {
+ if (frame == null || _bitmap == null) return;
+
+ _bitmap.Lock();
+ try
+ {
+ // 3. 移除类级别的 _bitmapData,改为局部变量
+ var rect = new System.Drawing.Rectangle(0, 0, frame.Width, frame.Height);
+ var bitmapData = frame.LockBits(rect, ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
+ try
+ {
+ int size = bitmapData.Height * bitmapData.Stride;
+ _bitmap.WritePixels(_rect, bitmapData.Scan0, size, bitmapData.Stride, 0, 0);
+ }
+ finally
+ {
+ // 4. 无论如何必须解锁 GDI 数据
+ frame.UnlockBits(bitmapData);
+ }
+ }
+ finally
+ {
+ // 5. 无论如何必须释放 Bitmap 和解锁 WriteableBitmap
+ frame.Dispose();
+ _bitmap.Unlock();
+ }
+
+ }
+
+ private void ButtonGrab_Click(object sender, RoutedEventArgs e)
+ {
+ InvokeClient.Instance.Service.DoOperation($"LoadLock.HikGigeCamera.Grab","UIGrab");
+ }
+
+ private void ButtonGrabbing_Click(object sender, RoutedEventArgs e)
+ {
+ InvokeClient.Instance.Service.DoOperation($"LoadLock.HikGigeCamera.Grabbing");
+ }
+
+ private void CameraControl_Unloaded(object sender, RoutedEventArgs e)
+ {
+ _cts?.Cancel();
+ InvokeClient.Instance.Service.DoOperation($"LoadLock.HikGigeCamera.Stop");
+ }
+
+ private void CameraControl_loaded(object sender, RoutedEventArgs e)
+ {
+ _cts = new CancellationTokenSource();
+ _ = CaptureLoop(_cts.Token);
+ }
+
+ private void ButtonStop_Click(object sender, RoutedEventArgs e)
+ {
+ InvokeClient.Instance.Service.DoOperation($"LoadLock.HikGigeCamera.Stop");
+ }
+ }
+}
diff --git a/App/SicUI/Models/Maintenances/TM/Device2View.xaml b/App/SicUI/Models/Maintenances/TM/Device2View.xaml
new file mode 100644
index 0000000..c0ee9d7
--- /dev/null
+++ b/App/SicUI/Models/Maintenances/TM/Device2View.xaml
@@ -0,0 +1,841 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/App/SicUI/Models/Maintenances/TM/Device2View.xaml.cs b/App/SicUI/Models/Maintenances/TM/Device2View.xaml.cs
new file mode 100644
index 0000000..a384180
--- /dev/null
+++ b/App/SicUI/Models/Maintenances/TM/Device2View.xaml.cs
@@ -0,0 +1,29 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using VMControls.Interface;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Navigation;
+using System.Windows.Shapes;
+
+namespace SicUI.Client.Models.Platform.TM
+{
+ ///
+ /// DeviceView.xaml 的交互逻辑
+ ///
+ public partial class Device2View : UserControl
+ {
+ public Device2View()
+ {
+ InitializeComponent();
+ }
+ }
+}
diff --git a/App/SicUI/Models/Maintenances/TM/Device2ViewModel.cs b/App/SicUI/Models/Maintenances/TM/Device2ViewModel.cs
new file mode 100644
index 0000000..7c7eac2
--- /dev/null
+++ b/App/SicUI/Models/Maintenances/TM/Device2ViewModel.cs
@@ -0,0 +1,216 @@
+using SicUI.Models;
+using System;
+using System.Collections.Generic;
+using Aitex.Core.Common.DeviceData;
+using System.IO;
+using System.Drawing;
+using Aitex.Core.Util;
+using VM.PlatformSDKCS;
+
+namespace SicUI.Client.Models.Platform.TM
+{
+ public class Device2ViewModel : SicUIViewModelBase
+ {
+ [Subscription("Load.Rotation.IsServoBusy")]
+ public bool LdRotationIsBusy { get; set; }
+
+ [Subscription("Load.Rotation.IsServoOn")]
+ public bool LdRotationIsServoOn { get; set; }
+
+ [Subscription("Load.Rotation.IsMoveDone")]
+ public bool LdRotationIsServoDone { get; set; }
+
+ [Subscription("Load.Rotation.IsServoError")]
+ public bool LdRotationIsServoError { get; set; }
+
+ [Subscription("TM.LLTrayPresence.DeviceData")]
+ public AITSensorData LoadTrayPresence { get; set; }
+
+ [Subscription("TM.LoadTrayHomeSensor.DeviceData")]
+ public AITSensorData LoadTrayHomeSensor { get; set; }
+
+ [Subscription("TM.LLWaferPlaced.DeviceData")]
+ public AITSensorData LoadWaferPlaced { get; set; }
+
+ [Subscription("Load.Rotation.CurPos")]
+ public double LdRotationCurPos { get; set; }
+
+ [Subscription("Load.Rotation.CCD1Degree")]
+ public double LdCCD1Degree { get; set; }
+
+ [Subscription("Load.Rotation.CCD2Degree")]
+ public double LdCCD2Degree { get; set; }
+
+ [Subscription("Load.Rotation.CCD3Degree")]
+ public double LdCCD3Degree { get; set; }
+
+ [Subscription("LoadLock.IsOnline")]
+ public bool LoadLockIsOnline { get; set; }
+
+ [Subscription("LoadLock.Status")]
+ public string LLStatus { get; set; }
+
+ public bool LdRotationBtnEnable => !LdRotationIsBusy && !LdRotationIsServoError && !LoadLockIsOnline && LLStatus == "Idle";
+ public Device2ViewModel()
+ {
+
+ }
+
+ protected override void OnActivate()
+ {
+ base.OnActivate();
+ }
+
+ protected override void OnDeactivate(bool close)
+ {
+ base.OnDeactivate(close);
+ }
+
+ //protected override void InvokeAfterUpdateProperty(Dictionary data)
+ //{
+ // base.InvokeAfterUpdateProperty(data);
+ // if (data.ContainsKey("LoadLock.HikVisionMaster.OutputImage"))
+ // {
+ // var bp = (Bitmap)data["LoadLock.HikVisionMaster.OutputImage"];
+ // OutputRanderImage = new(bp);
+ // }
+ //}
+
+ private byte[] _oldbyte;
+ protected override void InvokeBeforeUpdateProperty(Dictionary data)
+ {
+ base.InvokeBeforeUpdateProperty(data);
+ var bp = (byte[])QueryDataClient.Instance.Service.GetData("LoadLock.HikVisionMaster.OutputImage");
+ if (bp != null)
+ {
+ if (_oldbyte!=null&&!Array.Equals(_oldbyte,bp))
+ {
+ Bitmap b = BytesToBitmap(bp);
+ OutputRanderImage?.Dispose();
+ OutputRanderImage = new ImageBaseData(b);
+ }
+ }
+ _oldbyte = bp;
+ }
+
+ public Bitmap BytesToBitmap(byte[] bytes)
+ {
+ using (MemoryStream ms = new MemoryStream(bytes))
+ {
+ return new Bitmap(ms); // 或使用Image.FromStream:ml-citation{ref="1,18" data="citationList"}
+ }
+ }
+
+ public void LdRotationStop()
+ {
+ InvokeClient.Instance.Service.DoOperation($"Load.Rotation.Stop");
+ }
+
+ public void LdRotationReset()
+ {
+ InvokeClient.Instance.Service.DoOperation($"Load.Rotation.ServoReset");
+ }
+
+ public void LdRotationServoOn()
+ {
+ InvokeClient.Instance.Service.DoOperation($"Load.Rotation.ServoOn");
+ }
+
+ public void LdRotationMoveOneCircle()
+ {
+ InvokeClient.Instance.Service.DoOperation($"LoadLock.MoveOneCircle");
+ }
+
+ public void LdRotationRelativeHome()
+ {
+ InvokeClient.Instance.Service.DoOperation($"Load.Rotation.MoveRelativeHome");
+ }
+
+ public void LdRotationRelativeHomeOffset()
+ {
+ InvokeClient.Instance.Service.DoOperation($"Load.Rotation.HomeOffset");
+ }
+
+ public void LdRotationMoveCCD1Pos()
+ {
+ InvokeClient.Instance.Service.DoOperation($"Load.Rotation.MoveCCD1Pos");
+ }
+
+ public void LdRotationMoveCCD2Pos()
+ {
+ InvokeClient.Instance.Service.DoOperation($"Load.Rotation.MoveCCD2Pos");
+ }
+
+ public void LdRotationMoveCCD3Pos()
+ {
+ InvokeClient.Instance.Service.DoOperation($"Load.Rotation.MoveCCD3Pos");
+ }
+
+ public void LdRotationJogCW(float angle)
+ {
+ InvokeClient.Instance.Service.DoOperation($"Load.Rotation.JogCW", angle);
+ }
+
+ public void LdRotationJogCCW(float angle)
+ {
+ InvokeClient.Instance.Service.DoOperation($"Load.Rotation.JogCCW", angle);
+ }
+
+ #region CCD
+ [Subscription("LoadLock.HikGigeCamera.IsConnected")]
+ public bool CamConnection { get; set; }
+
+ [Subscription("LoadLock.HikGigeCamera.Message")]
+ public string CamMessage { get; set; }
+
+ public bool CTS { get; set; } = false;
+ #endregion
+
+ #region VM
+
+ [Subscription("LoadLock.HikVisionMaster.SampleCircle")]
+ public double[] SampleCircle { get; set; }
+
+ [Subscription("LoadLock.HikVisionMaster.CurrentCircle")]
+ public double[] CurrentCircle { get; set; }
+
+ [Subscription("LoadLock.HikVisionMaster.Distance")]
+ public double Distance { get; set; }
+
+ [Subscription("LoadLock.HikVisionMaster.IsProcessing")]
+ public string VMIsProcessing { get; set; }
+
+ [Subscription("LoadLock.HikVisionMaster.LoadFile")]
+ public string VMIsLoad { get; set; }
+
+ [Subscription("LoadLock.HikVisionMaster.ModuleStatus")]
+ public bool VMRun { get; set; }
+
+ [Subscription("LoadLock.HikVisionMaster.Result")]
+ public bool VMResult { get; set; }
+
+ public ImageBaseData OutputRanderImage { get; set; }
+
+ public void TestLocalFile(string value, bool isinch6)
+ {
+ InvokeClient.Instance.Service.DoOperation($"LoadLock.HikVisionMaster.ExecuteLocalFile", value + (isinch6 ? "FindLine" : ""));
+ }
+
+ public void TestCCD(string value,bool isinch6)
+ {
+ InvokeClient.Instance.Service.DoOperation($"LoadLock.HikVisionMaster.ExecuteGrab", value + (isinch6? "FindLine" : ""));
+ }
+
+ public void SetSample(string value)
+ {
+ InvokeClient.Instance.Service.DoOperation($"LoadLock.HikVisionMaster.SetSample", value);
+ }
+
+ public void ReloadSolution()
+ {
+ InvokeClient.Instance.Service.DoOperation($"LoadLock.HikVisionMaster.ReloadSolution");
+ }
+ #endregion
+
+ }
+}
diff --git a/App/SicUI/SicUI.csproj b/App/SicUI/SicUI.csproj
index d64cdd0..9bbd5a4 100644
--- a/App/SicUI/SicUI.csproj
+++ b/App/SicUI/SicUI.csproj
@@ -57,9 +57,41 @@
+
+ False
+ ..\..\Dependencies\VisionMaster\Apps.Data.dll
+
+
+ False
+ ..\..\Dependencies\VisionMaster\CalculatorModuleCs.dll
+
..\..\Dependencies\CommandLine.dll
+
+ False
+ ..\..\Dependencies\VisionMaster\GlobalVariableModuleCs.dll
+
+
+ False
+ ..\..\Dependencies\VisionMaster\IfModuleCs.dll
+
+
+ False
+ ..\..\Dependencies\VisionMaster\ImageSourceModuleCs.dll
+
+
+ False
+ ..\..\Dependencies\VisionMaster\IMVSCaliperEdgeModuCs.dll
+
+
+ False
+ ..\..\Dependencies\VisionMaster\IMVSCircleFitModuCs.dll
+
+
+ False
+ ..\..\Dependencies\VisionMaster\IMVSLineFindModuCs.dll
+
..\..\Dependencies\KXGEM.dll
@@ -72,6 +104,10 @@
+
+ False
+ ..\..\Dependencies\VisionMaster\SaveImageCs.dll
+
..\..\Dependencies\SciCart\SciChart.Charting.dll
@@ -104,6 +140,42 @@
4.0
+
+ False
+ ..\..\Dependencies\VisionMaster\VM.Core.dll
+
+
+ False
+ ..\..\Dependencies\VisionMaster\VM.PlatformSDKCS.dll
+
+
+ False
+ ..\..\Dependencies\VisionMaster\VM.Util.dll
+
+
+ False
+ ..\..\Dependencies\VisionMaster\VM.Utility.dll
+
+
+ False
+ ..\..\Dependencies\VisionMaster\VMControls.BaseInterface.dll
+
+
+ False
+ ..\..\Dependencies\VisionMaster\VMControls.Interface.dll
+
+
+ False
+ ..\..\Dependencies\VisionMaster\VMControls.RenderInterface.dll
+
+
+ False
+ ..\..\Dependencies\VisionMaster\VMControls.Winform.Release.dll
+
+
+ False
+ ..\..\Dependencies\VisionMaster\VMControls.WPF.Release.dll
+
@@ -142,6 +214,9 @@
BodyLid.xaml
+
+ CameraControl.xaml
+
ChooseDialogBoxView.xaml
@@ -213,6 +288,10 @@
RuntimeView.xaml
+
+ Device2View.xaml
+
+
DeviceView.xaml
@@ -371,6 +450,10 @@
Designer
MSBuild:Compile
+
+ MSBuild:Compile
+ Designer
+
Designer
MSBuild:Compile
@@ -447,6 +530,10 @@
MSBuild:Compile
Designer
+
+ MSBuild:Compile
+ Designer
+
Designer
MSBuild:Compile