Merge branch 'feature/add-hiwin-aligner-simulator' into develop

This commit is contained in:
DESKTOP-1N1NK8A\auvkk 2023-05-18 11:11:25 +08:00
commit 50fd92ea39
7 changed files with 430 additions and 79 deletions

View File

@ -0,0 +1,205 @@
using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using MECF.Framework.Simulator.Core.Driver;
namespace MECF.Framework.Simulator.Core.Aligners.HPA48
{
public class HPA48Simulator : SerialPortDeviceSimulator
{
#region Variables
private CancellationTokenSource _cancellationTokenSource;
private readonly object _lock = new object();
private bool _isBusy = false;
#endregion
#region Constructors
public HPA48Simulator(string portName)
: base(portName, -1, "", ' ')
{
}
#endregion
#region Properties
public bool IsAlarm { get; set; }
public bool IsVacuumOn { get; set; }
#endregion
#region Methods
protected override void ProcessUnsplitMessage(string message)
{
if (message.StartsWith("ERS"))
ERS(message);
else if (message.StartsWith("BAL"))
BAL(message);
else if (message.StartsWith("HOM"))
HOM(message);
else if (message.StartsWith("CVN"))
CVN(message);
else if (message.StartsWith("CVF"))
CVF(message);
else if (message.StartsWith("MTM"))
MTM(message);
else if (message.StartsWith("DOC"))
DOC(message);
else if (message.StartsWith("STP"))
STP(message);
}
protected override void ProcessWriteMessage(string msg)
{
var msgReformatted = $"{msg}\r\n";
base.ProcessWriteMessage(msgReformatted);
}
private void SendResponse(string cmd, Action<string> handleCmd, Action customizeEcho = null)
{
lock (_lock)
{
if(_isBusy)
OnWriteMessage("BUSY");
else
{
if (_cancellationTokenSource == null)
{
_cancellationTokenSource = new CancellationTokenSource();
_isBusy = true;
Task.Run(() => { handleCmd?.Invoke(cmd); }, _cancellationTokenSource.Token).ContinueWith(t =>
{
lock (_lock)
{
_isBusy = false;
if(customizeEcho != null)
{
try
{
customizeEcho?.Invoke();
}
catch (Exception ex)
{
Trace.WriteLine(ex.Message);
Debugger.Break();
}
}
else
OnWriteMessage("END");
_cancellationTokenSource = null;
}
});
}
}
}
}
/// <summary>
/// 开始寻边。
/// </summary>
/// <param name="cmd"></param>
private void BAL(string cmd)
{
SendResponse(cmd, s =>
{
Thread.Sleep(3000);
});
}
/// <summary>
/// 回机械零点。
/// </summary>
/// <param name="cmd"></param>
private void HOM(string cmd)
{
SendResponse(cmd, s =>
{
Thread.Sleep(3000);
});
}
/// <summary>
/// 打开真空。
/// </summary>
/// <param name="cmd"></param>
private void CVN(string cmd)
{
SendResponse(cmd, s =>
{
Thread.Sleep(500);
IsVacuumOn = true;
});
}
/// <summary>
/// 关闭真空。
/// </summary>
/// <param name="cmd"></param>
private void CVF(string cmd)
{
SendResponse(cmd, s =>
{
Thread.Sleep(500);
IsVacuumOn = false;
});
}
/// <summary>
/// 清除所有报警。
/// </summary>
/// <param name="cmd"></param>
private void ERS(string cmd)
{
SendResponse(cmd, s =>
{
Thread.Sleep(100);
IsAlarm = false;
});
}
/// <summary>
/// 移动至测量中心点。
/// </summary>
/// <param name="cmd"></param>
private void MTM(string cmd)
{
SendResponse(cmd, s =>
{
Thread.Sleep(1000);
});
}
/// <summary>
///检测是否有Wafer。
/// </summary>
/// <param name="cmd"></param>
private void DOC(string cmd)
{
SendResponse(cmd, s =>
{
Thread.Sleep(1000);
OnWriteMessage("1");
});
}
/// <summary>
/// 停止运动。
/// </summary>
/// <param name="cmd"></param>
private void STP(string cmd)
{
_cancellationTokenSource?.Cancel();
}
#endregion
}
}

View File

@ -0,0 +1,69 @@
<UserControl x:Class="MECF.Framework.Simulator.Core.LoadPorts.HPA48View"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:MECF.Framework.Simulator.Core.LoadPorts"
xmlns:deviceControl="clr-namespace:MECF.Framework.UI.Core.DeviceControl;assembly=MECF.Framework.UI.Core"
xmlns:commons="clr-namespace:MECF.Framework.Simulator.Core.Commons"
Height="900" Width="900">
<UserControl.Resources>
<DataTemplate x:Key="DataTemplate1">
<StackPanel Orientation="Horizontal" Width="200" Height="15">
<TextBox Text="{Binding Index}"></TextBox>
<TextBox Text="{Binding State}"></TextBox>
<Button Content="{Binding State}" Margin="0" Width="100" Height="15" Background="LightBlue" VerticalAlignment="Center"></Button>
<TextBox Text="{Binding Index}"></TextBox>
</StackPanel>
</DataTemplate>
</UserControl.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="100"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="50"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<commons:SerialPortTitleView Grid.Row="0"/>
<StackPanel Grid.Row="2" Orientation="Horizontal" Width="900">
<Button Content="Clear Log" Width="100" Height="35" Command="{Binding ClearLogCommand}"></Button>
</StackPanel>
<DataGrid Grid.Row="3" FontSize="16" AutoGenerateColumns="False" CanUserAddRows="False" CanUserResizeRows="False" CanUserSortColumns="False" ItemsSource="{Binding TransactionLogItems}"
ScrollViewer.CanContentScroll="True"
ScrollViewer.VerticalScrollBarVisibility="Auto"
ScrollViewer.HorizontalScrollBarVisibility="Auto"
Width="900" Height="380" VerticalAlignment="Top">
<DataGrid.Columns>
<DataGridTextColumn Header="Time" Width="160" IsReadOnly="True" Binding="{Binding OccurTime, UpdateSourceTrigger=PropertyChanged}"/>
<DataGridTextColumn Header="Incoming" Width="350" IsReadOnly="True" Binding="{Binding Incoming, UpdateSourceTrigger=PropertyChanged}">
<DataGridTextColumn.ElementStyle>
<Style TargetType="TextBlock">
<Setter Property="TextWrapping" Value="Wrap"/>
<Setter Property="Height" Value="auto"/>
</Style>
</DataGridTextColumn.ElementStyle>
</DataGridTextColumn>
<DataGridTextColumn Header="Outgoing" Width="350" IsReadOnly="True" Binding="{Binding Outgoing, UpdateSourceTrigger=PropertyChanged}">
<DataGridTextColumn.ElementStyle>
<Style TargetType="TextBlock">
<Setter Property="TextWrapping" Value="Wrap"/>
<Setter Property="Height" Value="auto"/>
</Style>
</DataGridTextColumn.ElementStyle>
</DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
</Grid>
</UserControl>

View File

@ -0,0 +1,88 @@
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using Aitex.Core.UI.MVVM;
using Aitex.Core.Utilities;
using MECF.Framework.Simulator.Core.Aligners.HPA48;
using MECF.Framework.Simulator.Core.Commons;
namespace MECF.Framework.Simulator.Core.LoadPorts
{
//public class WaferItem
//{
// public int index { get; set; }
// public string Display { get; set; }
// public int State { get; set; }
//}
/// <summary>
/// TazmoAligner.xaml 的交互逻辑
/// </summary>
public partial class HPA48View : UserControl
{
public static readonly DependencyProperty PortNameProperty = DependencyProperty.Register(
"PortName", typeof(string), typeof(TazmoAlignerView),
new FrameworkPropertyMetadata("COM10", FrameworkPropertyMetadataOptions.AffectsRender));
public string PortName
{
get => (string)this.GetValue(PortNameProperty);
set => this.SetValue(PortNameProperty, value);
}
public static readonly DependencyProperty PortNumberProperty = DependencyProperty.Register(
"PortNumber", typeof(int), typeof(TazmoAlignerView),
new FrameworkPropertyMetadata(0, FrameworkPropertyMetadataOptions.AffectsRender));
public int PortNumber
{
get => (int)this.GetValue(PortNumberProperty);
set => this.SetValue(PortNumberProperty, value);
}
public HPA48View()
{
InitializeComponent();
this.Loaded += OnViewLoaded;
}
private void OnViewLoaded(object sender, RoutedEventArgs e)
{
if (DataContext == null)
{
DataContext = new HPA48ViewModel(PortName, PortNumber);
(DataContext as TimerViewModelBase).Start();
}
}
}
class HPA48ViewModel : SerialPortDeviceViewModel
{
public string Title => "HiWin HPA48 Aligner Simulator";
public ObservableCollection<WaferItem> WaferList { get; set; }
private HPA48Simulator _sim;
public HPA48ViewModel(string port, int index) : base("HPA48ViewModel")
{
_sim = new HPA48Simulator(port);
Init(_sim);
WaferList = new ObservableCollection<WaferItem>()
{
new WaferItem {Display = "1", Index = 2, State = 3}
};
}
}
}

View File

@ -2,7 +2,6 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MECF.Framework.Simulator.Core.Driver
{
@ -12,15 +11,9 @@ namespace MECF.Framework.Simulator.Core.Driver
public event Action<string> MessageOut;
public event Action<string> ErrorOccur;
public virtual bool IsEnabled
{
get { return false; }
}
public virtual bool IsEnabled => false;
public virtual bool IsConnected
{
get { return false; }
}
public virtual bool IsConnected => false;
protected SortedList<string, Action<string>> commandList = new SortedList<string, Action<string>>();

View File

@ -1,58 +1,44 @@
using System;
using System.Collections.Generic;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO.Ports;
using MECF.Framework.Common.Communications;
using MECF.Framework.Common.Communications.Tcp.Socket.Framing;
namespace MECF.Framework.Simulator.Core.Driver
{
public class SerialPortDeviceSimulator : DeviceSimulator
{
public override bool IsEnabled
{
get { return _serialPort!=null && _serialPort.IsOpen(); }
}
#region Variables
public override bool IsConnected
{
get { return IsEnabled; }
}
private readonly AsyncSerialPort _serialPort;
public string PortName
{
get { return _serialPort.PortName; }
set { _serialPort.PortName = value; }
}
#endregion
private AsyncSerialPort _serialPort;
#region Constructors
public string RemoteConnection { get; set; }
public SerialPortDeviceSimulator(string port, int commandIndex, string lineDelimiter, char msgDelimiter, bool isAscii=true)
:base(commandIndex, lineDelimiter, msgDelimiter)
public SerialPortDeviceSimulator(string port, int commandIndex, string lineDelimiter, char msgDelimiter,
bool isAscii = true)
: base(commandIndex, lineDelimiter, msgDelimiter)
{
_serialPort = new AsyncSerialPort(port, 9600, 8, Parity.None, StopBits.One, lineDelimiter, isAscii);
_serialPort.OnDataChanged += OnReadMessage;
_serialPort.OnBinaryDataChanged += OnReadMessage;
_serialPort.OnErrorHappened += OnErrorMessage;
_serialPort.OnErrorHappened += OnErrorMessage;
}
public SerialPortDeviceSimulator(string port, int commandIndex, string lineDelimiter, char msgDelimiter, bool isAscii, int dataBits)
: base(commandIndex, lineDelimiter, msgDelimiter)
public SerialPortDeviceSimulator(string port, int commandIndex, string lineDelimiter, char msgDelimiter,
bool isAscii, int dataBits)
: base(commandIndex, lineDelimiter, msgDelimiter)
{
_serialPort = new AsyncSerialPort(port, 19200, dataBits, Parity.Even, StopBits.One, lineDelimiter, isAscii);
_serialPort.OnDataChanged += OnReadMessage;
_serialPort.OnBinaryDataChanged += OnReadMessage;
_serialPort.OnErrorHappened += OnErrorMessage;
}
public SerialPortDeviceSimulator(string port, int commandIndex, string lineDelimiter, char msgDelimiter, bool isAscii,string parity)
: base(commandIndex, lineDelimiter, msgDelimiter)
public SerialPortDeviceSimulator(string port, int commandIndex, string lineDelimiter, char msgDelimiter,
bool isAscii, string parity)
: base(commandIndex, lineDelimiter, msgDelimiter)
{
_serialPort = new AsyncSerialPort(port, 9600, 8, Parity.Even, StopBits.One, lineDelimiter, isAscii);
_serialPort.OnDataChanged += OnReadMessage;
@ -60,10 +46,34 @@ namespace MECF.Framework.Simulator.Core.Driver
_serialPort.OnErrorHappened += OnErrorMessage;
}
#endregion
#region Properties
public override bool IsEnabled => _serialPort != null && _serialPort.IsOpen();
public override bool IsConnected => IsEnabled;
public string PortName
{
get => _serialPort.PortName;
set => _serialPort.PortName = value;
}
public string RemoteConnection { get; set; }
#endregion
#region Methods
public void Enable()
{
_serialPort.Open();
}
}
public void Disable()
{
@ -74,11 +84,15 @@ namespace MECF.Framework.Simulator.Core.Driver
{
_serialPort.Write(msg);
}
protected override void ProcessWriteMessage(byte[] msg)
{
_serialPort.Write(msg);
}
#endregion
}
}

View File

@ -1,47 +1,31 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO.Ports;
using System.Windows;
using System.Windows.Input;
using Aitex.Core.UI.MVVM;
using Aitex.Core.Utilities;
using MECF.Framework.Simulator.Core.Driver;
namespace MECF.Framework.Simulator.Core.Commons
{
public class SerialPortDeviceViewModel : TimerViewModelBase
{
public ObservableCollection<string> PortList { get; set; }
public List<string> PortList { get; set; }
public ICommand ClearLogCommand { get; set; }
public ICommand EnableCommand { get; set; }
public ICommand DisableCommand { get; set; }
public bool IsEnableEnable
{
get { return !_simulator.IsEnabled; }
}
public bool IsEnableDisable
{
get { return _simulator.IsEnabled; }
}
public bool IsEnableEnable => !_simulator.IsEnabled;
public string RemoteConnection
{
get { return _simulator.RemoteConnection; }
}
public bool IsEnableDisable => _simulator.IsEnabled;
public string LocalPort
{
get { return _simulator.PortName; }
}
public bool IsConnected
{
get { return _simulator.IsConnected; }
}
public string RemoteConnection => _simulator.RemoteConnection;
public string LocalPort => _simulator.PortName;
public bool IsConnected => _simulator.IsConnected;
public string ConnectionStatus
{
@ -68,16 +52,7 @@ namespace MECF.Framework.Simulator.Core.Commons
TransactionLogItems = new ObservableCollection<TransactionLogItem>();
LocalPortSetPoint = "COM2";
PortList = new ObservableCollection<string>()
{
"COM1", "COM2", "COM3", "COM4", "COM5",
"COM6", "COM7", "COM8", "COM9", "COM10",
"COM11", "COM12", "COM13", "COM14", "COM15",
"COM16", "COM17", "COM18", "COM19", "COM20",
"COM21", "COM22", "COM23", "COM24", "COM25",
};
PortList = new List<string>(SerialPort.GetPortNames());
}
protected void Init(SerialPortDeviceSimulator sim, bool enable = true)

View File

@ -83,6 +83,10 @@
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="Aligners\HPA48\HPA48Simulator.cs" />
<Compile Include="Aligners\HPA48\HPA48View.xaml.cs">
<DependentUpon>HPA48View.xaml</DependentUpon>
</Compile>
<Compile Include="Breakers\NSXBreaker.cs" />
<Compile Include="Breakers\NSXBreakerView.xaml.cs">
<DependentUpon>NSXBreakerView.xaml</DependentUpon>
@ -299,6 +303,10 @@
<Compile Include="Vacuometer\VacuometerViewModel.cs" />
</ItemGroup>
<ItemGroup>
<Page Include="Aligners\HPA48\HPA48View.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="Breakers\NSXBreakerView.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
@ -569,13 +577,12 @@
</None>
</ItemGroup>
<ItemGroup>
<Folder Include="Aligners\HonghuAligner\" />
<Folder Include="UPS\ITA\" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<ProjectExtensions>
<VisualStudio>
<UserProperties robots_4hiratar4_4iosimulatoritems_1json__JsonSchema="https://jenkins-x.io/schemas/jx-schema.json" vce_4brooksvce_4iosimulatoritems_1json__JsonSchema="http://json.schemastore.org/apibuilder.json" />
<UserProperties vce_4brooksvce_4iosimulatoritems_1json__JsonSchema="http://json.schemastore.org/apibuilder.json" robots_4hiratar4_4iosimulatoritems_1json__JsonSchema="https://jenkins-x.io/schemas/jx-schema.json" />
</VisualStudio>
</ProjectExtensions>
</Project>