Merge branch 'Dev_Picking'
# Conflicts: # Common/.shared/SharedAssemblyInfo.cs # Common/Production/ProductionUiCordonel/App.config # Common/Production/ProductionUiCordonel/App.xaml.cs # Common/Production/ProductionUiCordonel/ProductionUiCordonel.csproj # Common/Production/ProductionUiCordonel/ProductionWindow.xaml # Common/Production/ProductionUiCordonel/ProductionWindow.xaml.cs
This commit is contained in:
@@ -34,11 +34,11 @@
|
||||
|
||||
|
||||
<appSettings>
|
||||
<add key="Mode" value="1" /> <!--1 = EOL ; 2 = Picking-->
|
||||
<add key="SirtComport433" value="14" /> <!--Individual for Thomas-->
|
||||
<add key="SirtComport868" value="15" /> <!--Individual for Thomas-->
|
||||
<add key="SirtBoxNr" value="2" /> <!--Roland and Thomas, box for development, box at shipping station is 1-->
|
||||
<add key="StationID" value="2" /> <!--Roland and Thomas, shipping station is 1-->
|
||||
<add key="Mode" value="2" /> <!--1 = EOL ; 2 = Picking-->
|
||||
<add key="SirtComport433" value="14" /> <!--Individual for Thomas-->
|
||||
<add key="SirtComport868" value="15" /> <!--Individual for Thomas-->
|
||||
<add key="SirtBoxNr" value="2" /> <!--Roland and Thomas, box for development, box at shipping station is 1-->
|
||||
<add key="StationID" value="1" /> <!--Roland and Thomas, shipping station is 1-->
|
||||
|
||||
</appSettings>
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
using System;
|
||||
using System.Configuration;
|
||||
using System.Windows;
|
||||
using Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.EolProcesses;
|
||||
using Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.PickingProcesses;
|
||||
|
||||
namespace Xylem.Common.Production.ProductionUiCordonel
|
||||
{
|
||||
@@ -11,24 +13,29 @@ namespace Xylem.Common.Production.ProductionUiCordonel
|
||||
{
|
||||
private void Application_Startup(Object sender, StartupEventArgs e)
|
||||
{
|
||||
switch (ConfigurationManager.AppSettings[$"Mode"])
|
||||
switch (ConfigurationManager.AppSettings["Mode"])
|
||||
{
|
||||
case "1":
|
||||
|
||||
var mainWindow = new FinalTest();
|
||||
mainWindow.Show();
|
||||
var ProductionWindow = new ProductionWindow(
|
||||
ProductionUiCordonel.Properties.Resources.StrEolSoftwareNameVersion,
|
||||
"ProductionUiCordonel", new EolProcessStateDef());
|
||||
ProductionWindow.Show();
|
||||
break;
|
||||
//case "2":
|
||||
// var Picking = new Picking();
|
||||
// Picking.Show();
|
||||
// break;
|
||||
|
||||
case "2":
|
||||
ProductionWindow = new ProductionWindow(
|
||||
ProductionUiCordonel.Properties.Resources.StrPickingSoftwareNameVersion,
|
||||
"PickingUiCordonel", new PickingProcessStateDef());
|
||||
ProductionWindow.Show();
|
||||
break;
|
||||
|
||||
default:
|
||||
var mainWindowDef = new FinalTest();
|
||||
mainWindowDef.Show();
|
||||
ProductionWindow = new ProductionWindow(
|
||||
ProductionUiCordonel.Properties.Resources.StrEolSoftwareNameVersion,
|
||||
"ProductionUiCordonel", new EolProcessStateDef());
|
||||
ProductionWindow.Show();
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,78 +0,0 @@
|
||||
<Window x:Class="Xylem.Common.Production.ProductionUiCordonel.MainWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:productionUiCordonel="clr-namespace:Xylem.Common.Production.ProductionUiCordonel"
|
||||
mc:Ignorable="d"
|
||||
Title="Cordonel Production UI" MinHeight="500" MinWidth="400" Height="600" Width="644" Initialized="Window_Initialized" Closing="Window_Closing">
|
||||
|
||||
<DockPanel HorizontalAlignment="Right" Width="634" Height="569" VerticalAlignment="Top" Margin="0,0,2,0">
|
||||
<ToolBarTray DockPanel.Dock="Top">
|
||||
<ToolBar>
|
||||
<Label>Slot:</Label>
|
||||
<ComboBox Name="cbxSlotBox" Margin="0,5,0,0" VerticalAlignment="Top" SelectionChanged="CbxSlotBox_SelectionChanged" />
|
||||
|
||||
|
||||
<Button Name="BtnConntect" VerticalAlignment="Top" Click="BtnConnect_Click" HorizontalAlignment="Right" ToolTip="Force connect to meter">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Image Source="/Resources/Connect_16x.png" />
|
||||
<TextBlock Margin="3,0,0,0">Connect</TextBlock>
|
||||
</StackPanel>
|
||||
</Button>
|
||||
|
||||
|
||||
</ToolBar>
|
||||
<ToolBar Name="tbarOrder">
|
||||
<Label>Order:</Label>
|
||||
<TextBox Name="txtOrderNr" HorizontalAlignment="Left" Height="26" IsEnabled="False" TextWrapping="Wrap" Text="" VerticalAlignment="Top" Width="81" />
|
||||
|
||||
</ToolBar>
|
||||
<ToolBar>
|
||||
<Label>Autodetect:</Label>
|
||||
<Button Name="BtnSwitchAutoDetect" VerticalAlignment="Top" Click="BtnSwitchAutoDetect_Click" HorizontalAlignment="Right" >
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Image Source="/Resources/Refresh_16x.png" />
|
||||
<TextBlock Name="tblkAutodetectState" Text="Off" Margin="3,0,0,0"/>
|
||||
</StackPanel>
|
||||
</Button>
|
||||
</ToolBar>
|
||||
</ToolBarTray>
|
||||
<StatusBar DockPanel.Dock="Bottom">
|
||||
<StatusBar.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="50" />
|
||||
<ColumnDefinition Width="100" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="100" />
|
||||
</Grid.ColumnDefinitions>
|
||||
</Grid>
|
||||
</ItemsPanelTemplate>
|
||||
</StatusBar.ItemsPanel>
|
||||
<StatusBarItem Grid.Column="0">
|
||||
<Label Content="PcbID:"/>
|
||||
</StatusBarItem>
|
||||
<StatusBarItem Grid.Column="1">
|
||||
<Label Name="lblPcbID" Content="-"/>
|
||||
</StatusBarItem>
|
||||
<Separator Grid.Column="2" />
|
||||
<StatusBarItem Grid.Column="3">
|
||||
<TextBlock Name="lblMessage" Text="Init" />
|
||||
</StatusBarItem>
|
||||
<Separator Grid.Column="4" />
|
||||
<StatusBarItem Grid.Column="5">
|
||||
<Label x:Name="lblState" Content="" HorizontalAlignment="Left" Height="Auto" VerticalAlignment="Top" />
|
||||
</StatusBarItem>
|
||||
</StatusBar>
|
||||
|
||||
|
||||
<StackPanel Background="#FFE5E5E5" SizeChanged="StackPanel_SizeChanged" Height="506" VerticalAlignment="Top" HorizontalAlignment="Stretch" Width="625" >
|
||||
<productionUiCordonel:FinalTest x:Name="ucFinalRadioTest" Loaded="UcFinalRadioTest_Loaded" Width="Auto" VerticalAlignment="Top" HorizontalAlignment="Stretch" />
|
||||
</StackPanel>
|
||||
|
||||
</DockPanel>
|
||||
</Window>
|
||||
@@ -1,451 +0,0 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
using System.Timers;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Threading;
|
||||
using Newtonsoft.Json;
|
||||
using Xylem.Common.CommonCore.Configuration;
|
||||
using Xylem.Common.CommonCore.Consts;
|
||||
using Xylem.Common.Hardware.Interfaces.Ports.PortCore;
|
||||
using Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore;
|
||||
using Xylem.Common.Hardware.WaterMeter.WaterMeterCore;
|
||||
using Xylem.Common.Logic.SoftwareAccessHelper;
|
||||
using Xylem.Common.Production.ProductionUiCordonel.Model;
|
||||
|
||||
namespace Xylem.Common.Production.ProductionUiCordonel
|
||||
{
|
||||
//public class QuantityToBackgroundConverter : IValueConverter
|
||||
//{
|
||||
// public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
// {
|
||||
// var dc = DisplayCodes.None;
|
||||
|
||||
// if (DisplayCodes.TryParse(value.ToString(), out dc))
|
||||
// {
|
||||
// string hex = "";
|
||||
// int intValue;
|
||||
// if (int.TryParse(value.ToString(), out intValue))
|
||||
// {
|
||||
// hex = intValue.ToString("X");
|
||||
// }
|
||||
// return $"{dc} ({hex})";
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// return "?";
|
||||
// }
|
||||
|
||||
|
||||
// }
|
||||
|
||||
// public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
// {
|
||||
// throw new NotImplementedException();
|
||||
// }
|
||||
//}
|
||||
|
||||
/// <summary>
|
||||
/// Interaction logic for MainWindow.xaml
|
||||
/// </summary>
|
||||
public partial class MainWindow
|
||||
{
|
||||
private Timer tmrAutoDetect;
|
||||
|
||||
public EventHandler OnPcbIdDetect;
|
||||
|
||||
private Int32 intervalWithoutDetect = 1000;
|
||||
private Int32 intervalWithDetect = 10000;
|
||||
private String _currentPcbID;
|
||||
|
||||
|
||||
public PickingViewModel PickingData = new PickingViewModel();
|
||||
|
||||
public String CurrentPcbID
|
||||
{
|
||||
set
|
||||
{
|
||||
if (_currentPcbID != value && !(string.IsNullOrEmpty(_currentPcbID) && value == null))
|
||||
{
|
||||
|
||||
if (_currentPcbID != value)
|
||||
{
|
||||
|
||||
if (!string.IsNullOrEmpty(_currentPcbID) && string.IsNullOrEmpty(value))
|
||||
{
|
||||
_currentPcbID = value;
|
||||
updateUi(lblPcbID, _currentPcbID);
|
||||
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
_currentPcbID = value;
|
||||
updateUi(lblPcbID, _currentPcbID);
|
||||
|
||||
if (!string.IsNullOrEmpty(_currentPcbID))
|
||||
{
|
||||
GetPcbMapping(_currentPcbID);
|
||||
}
|
||||
}
|
||||
}
|
||||
OnPcbIdDetect?.Invoke(CurrentPcbID, EventArgs.Empty);
|
||||
}
|
||||
|
||||
}
|
||||
get => _currentPcbID;
|
||||
}
|
||||
|
||||
public enum uiState
|
||||
{
|
||||
not_connected,
|
||||
connected
|
||||
}
|
||||
|
||||
private uiState _currentState;
|
||||
public uiState CurrentState
|
||||
{
|
||||
set
|
||||
{
|
||||
_currentState = value;
|
||||
updateUi(lblState, _currentState.ToString());
|
||||
}
|
||||
get => _currentState;
|
||||
}
|
||||
|
||||
private String _lastMsg;
|
||||
public String LastMsg
|
||||
{
|
||||
set
|
||||
{
|
||||
_lastMsg = value;
|
||||
updateUi(lblMessage, _lastMsg);
|
||||
}
|
||||
get => _lastMsg;
|
||||
}
|
||||
|
||||
public MainWindow()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (true)
|
||||
{
|
||||
|
||||
}
|
||||
InitializeComponent();
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
MessageBox.Show(ex.Message + Environment.NewLine + ex.StackTrace);
|
||||
}
|
||||
|
||||
}
|
||||
public ApplicationSettings Settings { get; set; }
|
||||
private void Window_Initialized(Object sender, EventArgs e)
|
||||
{
|
||||
var configfile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
|
||||
nameof(Hardware.WaterMeter.Genesis), ProgramConfig.SerialConfigFileName);
|
||||
|
||||
if (!File.Exists(configfile))
|
||||
{
|
||||
throw new ApplicationException($"Configuration file {configfile} not found ");
|
||||
}
|
||||
var tr = new StreamReader(configfile);
|
||||
var meterConfigList = JsonConvert.DeserializeObject<SlotConfig[]>(tr.ReadToEnd());
|
||||
|
||||
cbxSlotBox.Items.Clear();
|
||||
foreach (var item in meterConfigList.OrderBy(s => s.Slot))
|
||||
{
|
||||
cbxSlotBox.Items.Add(item.Slot);
|
||||
}
|
||||
|
||||
cbxSlotBox.SelectedIndex = 0;
|
||||
tmrAutoDetect = new Timer(intervalWithoutDetect);
|
||||
tmrAutoDetect.Elapsed += TmrAutoDetect_Elapsed;
|
||||
tmrAutoDetect.Enabled = false;
|
||||
|
||||
|
||||
Settings = new ApplicationSettings("ProductionUiConfig.json");
|
||||
|
||||
|
||||
useSetting(true);
|
||||
}
|
||||
|
||||
private void TmrAutoDetect_Elapsed(Object sender, ElapsedEventArgs e)
|
||||
{
|
||||
tmrAutoDetect.Enabled = false;
|
||||
var hasDetect = Detect(true, 1);
|
||||
if (hasDetect)
|
||||
{
|
||||
tmrAutoDetect.Interval = intervalWithDetect;
|
||||
}
|
||||
else
|
||||
{
|
||||
tmrAutoDetect.Interval = intervalWithoutDetect;
|
||||
}
|
||||
tmrAutoDetect.Enabled = Settings.AutoDetect;
|
||||
}
|
||||
|
||||
|
||||
private void BtnConnect_Click(Object sender, RoutedEventArgs e)
|
||||
{
|
||||
var hasDetect = Detect(false, (Int32)cbxSlotBox.SelectedValue);
|
||||
|
||||
Settings.Slot = (Int32)cbxSlotBox.SelectedValue;
|
||||
storeSetting();
|
||||
}
|
||||
|
||||
private void updateUi(ContentControl c, String content)
|
||||
{
|
||||
c.Dispatcher.Invoke(DispatcherPriority.Normal,
|
||||
new Action(() => { c.Content = content; }));
|
||||
}
|
||||
private void updateUi(TextBox c, String content)
|
||||
{
|
||||
c.Dispatcher.Invoke(DispatcherPriority.Normal,
|
||||
new Action(() => { c.Text = content; }));
|
||||
}
|
||||
private void updateUi(TextBlock c, String content)
|
||||
{
|
||||
c.Dispatcher.Invoke(DispatcherPriority.Normal,
|
||||
new Action(() => { c.Text = content; }));
|
||||
}
|
||||
|
||||
private MeterBatch CurrentBatch;
|
||||
private IGenesisMeter _currentMeter;
|
||||
private Boolean detectIsLocked;
|
||||
|
||||
private IGenesisMeter CurrentMeter
|
||||
{
|
||||
get => _currentMeter;
|
||||
set
|
||||
{
|
||||
_currentMeter = value;
|
||||
if (ucFinalRadioTest != null)
|
||||
{
|
||||
if (_currentMeter?.PcbId != null)
|
||||
{
|
||||
// ucFinalRadioTest.GenesisMeter = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
// ucFinalRadioTest.GenesisMeter = null;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Boolean Detect(Boolean ignoreErrors, Int32 slot)
|
||||
{
|
||||
if (!detectIsLocked)
|
||||
{
|
||||
LastMsg = "Start Detect";
|
||||
Boolean hasDetect = false;
|
||||
if (string.IsNullOrEmpty(CurrentPcbID) || CurrentMeter == null)
|
||||
{
|
||||
var mb = new MeterBatch();
|
||||
var tryMeter = new GenesisMeter();
|
||||
try
|
||||
{
|
||||
tryMeter.SetupFromConfigFile(slot);
|
||||
mb.AddMeter(tryMeter);
|
||||
tryMeter.Logout();
|
||||
LastMsg = "Try to get PcbID";
|
||||
CurrentPcbID = tryMeter.GetPcbId();
|
||||
|
||||
hasDetect = !string.IsNullOrEmpty(CurrentPcbID);
|
||||
CurrentBatch = mb;
|
||||
CurrentMeter = tryMeter;
|
||||
if (hasDetect)
|
||||
{
|
||||
LastMsg = $"New PcbID detected {CurrentPcbID}";
|
||||
|
||||
CurrentMeter.Login();
|
||||
}
|
||||
else
|
||||
{
|
||||
LastMsg = "No Meter found";
|
||||
DisposeAllConnections();
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (!ignoreErrors)
|
||||
{
|
||||
MessageBox.Show($"Error occur.{ Environment.NewLine} {e.Message}");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
LastMsg = "Check if Meter is still connected";
|
||||
var ret = CurrentMeter.GetPcbId();
|
||||
if (string.IsNullOrEmpty(ret) || ret != CurrentPcbID)
|
||||
{
|
||||
LastMsg = "Meter connection lost";
|
||||
hasDetect = false;
|
||||
DisposeAllConnections();
|
||||
|
||||
CurrentPcbID = "";
|
||||
}
|
||||
else
|
||||
{
|
||||
LastMsg = "Meter is still connected";
|
||||
hasDetect = true;
|
||||
}
|
||||
}
|
||||
return hasDetect;
|
||||
}
|
||||
|
||||
LastMsg = "Meter is still connected (locked)";
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void Window_Closing(Object sender, CancelEventArgs e)
|
||||
{
|
||||
DisposeAllConnections();
|
||||
}
|
||||
|
||||
private void DisposeAllConnections()
|
||||
{
|
||||
|
||||
if (CurrentBatch != null)
|
||||
{
|
||||
CurrentBatch.RemoveAllMeters();
|
||||
if (CurrentMeter != null)
|
||||
{
|
||||
CurrentMeter.Dispose();
|
||||
}
|
||||
CurrentBatch.Dispose();
|
||||
}
|
||||
PickingData.Empty();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private void GetPcbMapping(String pcbID)
|
||||
{
|
||||
if (string.IsNullOrEmpty(pcbID))
|
||||
{
|
||||
return;
|
||||
}
|
||||
var url = $"{ServiceUrls.MarriageServiceUrl()}GetSerialNumberAndOrderNumber?PcbId={pcbID}&withRadioAdress=true";
|
||||
|
||||
Task.Run(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var responseJson = LocalWebRequest.GetRequest(url);
|
||||
var a = JsonConvert.DeserializeObject<String[]>(responseJson);
|
||||
|
||||
|
||||
if (ucFinalRadioTest != null)
|
||||
{
|
||||
var tmpInt = 0;
|
||||
int.TryParse(a[1], out tmpInt);
|
||||
// ucFinalRadioTest.OrderNumber = tmpInt;
|
||||
|
||||
tmpInt = 0;
|
||||
if (a.Length > 2)
|
||||
{
|
||||
int.TryParse(a[2], out tmpInt);
|
||||
|
||||
}
|
||||
|
||||
//ucFinalRadioTest.RadioAddress = tmpInt;
|
||||
// ucFinalRadioTest.SerialNumber = a[0] + "/" + a[3];
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (ex is WebException)
|
||||
{
|
||||
MessageBox.Show($"Error on Store: {Environment.NewLine} { ((WebException)ex).Message}");
|
||||
}
|
||||
|
||||
MessageBox.Show(ex.Message);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
private void Button_Click(Object sender, RoutedEventArgs e)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private void UcFinalRadioTest_OnLockMeter(Object sender, EventArgs e)
|
||||
{
|
||||
detectIsLocked = true;
|
||||
|
||||
}
|
||||
|
||||
private void UcFinalRadioTestOnOnReleaseMeter(Object sender, EventArgs e)
|
||||
{
|
||||
detectIsLocked = false;
|
||||
//ucFinalRadioTest.SetUpBlank(false);
|
||||
}
|
||||
|
||||
|
||||
private void BtnSwitchAutoDetect_Click(Object sender, RoutedEventArgs e)
|
||||
{
|
||||
Settings.AutoDetect = !Settings.AutoDetect;
|
||||
storeSetting();
|
||||
useSetting();
|
||||
}
|
||||
|
||||
private void CbxSlotBox_SelectionChanged(Object sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
|
||||
}
|
||||
private void storeSetting()
|
||||
{
|
||||
Settings.Update("ProductionUiConfig.json");
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void useSetting(Boolean setSlot = false)
|
||||
{
|
||||
tmrAutoDetect.Enabled = Settings.AutoDetect;
|
||||
tblkAutodetectState.Text = "Off";
|
||||
if (Settings.AutoDetect)
|
||||
{
|
||||
tblkAutodetectState.Text = "On";
|
||||
}
|
||||
if (setSlot)
|
||||
{
|
||||
cbxSlotBox.SelectedValue = Settings.Slot;
|
||||
}
|
||||
}
|
||||
|
||||
private void StackPanel_SizeChanged(Object sender, SizeChangedEventArgs e)
|
||||
{
|
||||
ucFinalRadioTest.Height = e.NewSize.Height;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,152 +0,0 @@
|
||||
<Window x:Class="Xylem.Common.Production.ProductionUiCordonel.MultiMode"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d"
|
||||
Title="MultiMode" Height="322.026" Width="660.69" Loaded="Window_Loaded" Closed="Window_Closed">
|
||||
<Grid Margin="0,0,28,0">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="30"/>
|
||||
<RowDefinition Height="30"/>
|
||||
<RowDefinition Height="30"/>
|
||||
<RowDefinition Height="30"/>
|
||||
<RowDefinition Height="238" MinHeight="150"/>
|
||||
<RowDefinition Height="28"/>
|
||||
<RowDefinition Height="28"/>
|
||||
<RowDefinition MinHeight="50"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="125"/>
|
||||
<ColumnDefinition Width="125"/>
|
||||
<ColumnDefinition Width="125"/>
|
||||
<ColumnDefinition Width="125"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Label Background="{Binding PickingResultColor}" Content="Kommissionierung" HorizontalAlignment="Left" Margin="10,1,0,0" VerticalAlignment="Top" Grid.Row="0" Grid.Column="0" Height="26" Width="115" />
|
||||
|
||||
<Label Background="{Binding PickingResultColor}" Content="Scanner:" HorizontalAlignment="Left" Margin="10,1,0,0" VerticalAlignment="Top" Grid.Row="1" Grid.Column="0" Height="26" Width="115" />
|
||||
|
||||
<Label Background="{Binding PickingResultColor}" Content="{Binding PickingScanner, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Left" Margin="10,1,0,0" VerticalAlignment="Top" Grid.Row="1" Grid.Column="1" Height="26" Width="115" />
|
||||
<Label Background="{Binding PickingResultColor}" Content="Ep:" HorizontalAlignment="Left" Margin="10,1,0,0" VerticalAlignment="Top" Grid.Row="1" Grid.Column="2" Height="26" Width="115" />
|
||||
|
||||
<Label Background="{Binding PickingResultColor}" Content="{Binding PickingSlot, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Left" Margin="10,1,0,0" VerticalAlignment="Top" Grid.Row="1" Grid.Column="3" Height="26" Width="115" />
|
||||
|
||||
<Label Background="{Binding PickingResultColor}" Content="Medlung:" HorizontalAlignment="Left" Margin="10,1,0,0" VerticalAlignment="Top" Grid.Row="2" Grid.Column="0" Height="26" Width="115" />
|
||||
|
||||
<Label Background="{Binding PickingResultColor}" Content="{Binding PickingState, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Left" Margin="36,1,0,0" VerticalAlignment="Top" Grid.Row="2" Grid.Column="1" Grid.ColumnSpan="3" Height="26" Width="332" />
|
||||
|
||||
<Label Background="{Binding PickingResultColor}" Content="Ergebnis:" HorizontalAlignment="Left" Margin="10,1,0,0" VerticalAlignment="Top" Grid.Row="3" Grid.Column="0" Height="26" Width="115" />
|
||||
|
||||
<Label Background="{Binding PickingResultColor}" Content="{Binding PickingResult, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Left" Margin="10,1,0,0" VerticalAlignment="Top" Grid.Row="3" Grid.Column="1" Grid.ColumnSpan="3" Height="26" Width="359" />
|
||||
|
||||
|
||||
|
||||
<!--<Label Content="Dichtigkeit" HorizontalAlignment="Left" Margin="10,1,0,0" VerticalAlignment="Top" Grid.Row="1" Grid.Column="0" Height="26" Width="105" />
|
||||
<Label Content="{Binding PressureHe.Sate}" HorizontalAlignment="Left" Margin="10,1,0,0" VerticalAlignment="Top" Grid.Row="1" Grid.Column="1" Height="26" Width="105" />
|
||||
|
||||
<Label Content="Druck" HorizontalAlignment="Left" Margin="10,1,0,0" VerticalAlignment="Top" Grid.Row="2" Grid.Column="0" Height="26" Width="105" />
|
||||
<Label Content="{Binding PressureSate}" HorizontalAlignment="Left" Margin="10,1,0,0" VerticalAlignment="Top" Grid.Row="2" Grid.Column="1" Height="26" Width="105" />
|
||||
|
||||
<Label Content="Verknüpfung" HorizontalAlignment="Left" Margin="10,1,0,0" VerticalAlignment="Top" Grid.Row="3" Grid.Column="0" Height="26" Width="105" />
|
||||
<Label Content="{Binding MarrySate}" HorizontalAlignment="Left" Margin="10,1,0,0" VerticalAlignment="Top" Grid.Row="3" Grid.Column="1" Height="26" Width="105" />-->
|
||||
|
||||
|
||||
|
||||
|
||||
<!--<Grid Grid.Row="1" Grid.Column="0" Grid.RowSpan="4">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="12*"/>
|
||||
|
||||
<RowDefinition Height="10*"/>
|
||||
<RowDefinition Height="10*"/>
|
||||
<RowDefinition Height="10*"/>
|
||||
<RowDefinition Height="100*"/>
|
||||
<RowDefinition Height="1*"/>
|
||||
<RowDefinition Height="20*"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="120" />
|
||||
<ColumnDefinition Width="180" />
|
||||
<ColumnDefinition Width="100" />
|
||||
<ColumnDefinition Width="200" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
|
||||
<Label x:Name="lblHeadline" Content="HE-Schnüffeln" Grid.Column="0" Grid.Row="0" FontWeight="Bold" FontSize="24" Height="47" VerticalAlignment="Top" Margin="0,0,113,0" Grid.RowSpan="2" Grid.ColumnSpan="2" />
|
||||
|
||||
<Label x:Name="lblLeakrate" Content="Grenz-Leckrate >" HorizontalAlignment="Left" Margin="0,0,0,0" VerticalAlignment="Top" Grid.Row="0" Grid.Column="2" Height="26" Width="123" />
|
||||
<TextBox x:Name="txtLeakrate" Height="26" IsEnabled="True" TextWrapping="Wrap" Text="{Binding Result.LeakRate, UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Top" Grid.Row="0" Grid.Column="3" HorizontalAlignment="Left" Width="171" TextChanged="TextBox_TextChanged"/>
|
||||
|
||||
|
||||
|
||||
<TextBox x:Name="TxtPresurePcbId" Height="26" IsEnabled="False" TextWrapping="Wrap" Text="{Binding CurrentPcbID, UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Top" Grid.Row="1" Grid.Column="1" HorizontalAlignment="Left" Width="150" TextChanged="TextBox_TextChanged"/>
|
||||
<Label Content="PcbId" HorizontalAlignment="Left" Margin="0,0,0,0" VerticalAlignment="Top" Grid.Row="1" Grid.Column="0" Height="26" Width="40"/>
|
||||
|
||||
|
||||
<StackPanel Orientation="Horizontal" Grid.Row="1" Grid.Column="2">
|
||||
<TextBlock Text="Rev: "/>
|
||||
<Label Content="{Binding Result.Rev, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Left" VerticalAlignment="Top" Height="26" Width="40"/>
|
||||
</StackPanel>
|
||||
|
||||
|
||||
<Label Content="Prüfdruck in bar" HorizontalAlignment="Left" Margin="0,0,0,0" VerticalAlignment="Top" Grid.Row="2" Grid.Column="0" Height="26" Width="113" Grid.ColumnSpan="2" />
|
||||
<TextBox x:Name="txtPressure" Height="26" IsEnabled="True" TextWrapping="Wrap" Text="{Binding Result.TestPressure, UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Top" Grid.Row="2" Grid.Column="1" HorizontalAlignment="Left" Width="150" TextChanged="TextBox_TextChanged"/>
|
||||
|
||||
|
||||
<TextBox x:Name="txtTester" Height="26" IsEnabled="True" TextWrapping="Wrap" Text="{Binding Result.TesterName, UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Top" Grid.Row="3" Grid.Column="1" HorizontalAlignment="Left" Width="150" TextChanged="TextBox_TextChanged" />
|
||||
|
||||
|
||||
<Label Content="Prüfer" HorizontalAlignment="Left" Margin="0,0,0,0" VerticalAlignment="Top" Grid.Row="3" Grid.Column="0" Height="26" Width="85" />
|
||||
|
||||
|
||||
<ListView x:Name="listViewTestPotins" ItemsSource="{Binding Result.Testpoints, UpdateSourceTrigger=PropertyChanged}" Grid.Row="2" Grid.Column="2" Grid.RowSpan="4" HorizontalAlignment="left" Width="251" Margin="10,10,0,0" Grid.ColumnSpan="2" >
|
||||
<ListView.View>
|
||||
<GridView >
|
||||
<GridViewColumn Header="Nr" >
|
||||
<GridViewColumn.CellTemplate>
|
||||
<DataTemplate >
|
||||
<Label Content="{Binding Ident}" Height="22" FontWeight="Bold" FontSize="10" />
|
||||
</DataTemplate>
|
||||
</GridViewColumn.CellTemplate>
|
||||
</GridViewColumn>
|
||||
<GridViewColumn Header="Wert" >
|
||||
|
||||
<GridViewColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<TextBox Text="{Binding Input}" Height="22" Width="100" FontWeight="Bold" FontSize="13" TextChanged="TextBox_TextChanged" />
|
||||
</DataTemplate>
|
||||
</GridViewColumn.CellTemplate>
|
||||
|
||||
</GridViewColumn>
|
||||
|
||||
<GridViewColumn Header="" >
|
||||
|
||||
<GridViewColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<Button Content="Für alle übernehmen" Height="22" FontWeight="Bold" FontSize="13" Click="Button_Click" />
|
||||
</DataTemplate>
|
||||
</GridViewColumn.CellTemplate>
|
||||
|
||||
</GridViewColumn>
|
||||
|
||||
</GridView>
|
||||
</ListView.View>
|
||||
</ListView>
|
||||
|
||||
<Label Content="Bemerkung" HorizontalAlignment="Left" Margin="0,10,0,0" VerticalAlignment="Top" Height="26" Width="113" Grid.Column="0" Grid.Row="4" Grid.ColumnSpan="2" />
|
||||
|
||||
<TextBox Text="{Binding Result.Remark, UpdateSourceTrigger=PropertyChanged}" Margin="10,10,10,7" TextWrapping="Wrap" AcceptsReturn="True" AcceptsTab="True" SpellCheck.IsEnabled="True" SpellCheck.SpellingReform="PreAndPostreform" Grid.Row="4" Grid.Column="1" TextChanged="TextBox_TextChanged"/>
|
||||
|
||||
|
||||
<Button Name="btnPresueOk" Background="LightGreen" Grid.ColumnSpan="2" Content="Bestanden" HorizontalAlignment="Left" Height="35" Margin="10,5,0,0" Grid.Row="6" VerticalAlignment="Top" Width="280" Click="BtnPresueOk_Click" Grid.Column="2"/>
|
||||
|
||||
<Button Name="btnPresueFailed" Background="LightPink" Grid.ColumnSpan="2" Content="Nicht Bestanden" HorizontalAlignment="Left" Height="35" Margin="9,5,0,0" Grid.Row="6" VerticalAlignment="Top" Width="281" Click="BtnPresueFailed_Click" Grid.Column="0" />
|
||||
|
||||
|
||||
|
||||
|
||||
</Grid>-->
|
||||
</Grid>
|
||||
</Window>
|
||||
@@ -1,206 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
using Xylem.Common.Production.ProductionUiCordonel.Model;
|
||||
|
||||
namespace Xylem.Common.Production.ProductionUiCordonel
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaktionslogik für MultiMode.xaml
|
||||
/// </summary>
|
||||
public partial class MultiMode : Window
|
||||
{
|
||||
//#region Raw Input API
|
||||
|
||||
//[DllImport("User32.dll")]
|
||||
//extern static uint GetRawInputDeviceList(IntPtr pRawInputDeviceList, ref uint uiNumDevices, uint cbSize);
|
||||
|
||||
//[DllImport("User32.dll")]
|
||||
//extern static uint GetRawInputDeviceInfo(IntPtr hDevice, uint uiCommand, IntPtr pData, ref uint pcbSize);
|
||||
|
||||
//[DllImport("User32.dll")]
|
||||
//extern static bool RegisterRawInputDevices(RAWINPUTDEVICE[] pRawInputDevice, uint uiNumDevices, uint cbSize);
|
||||
|
||||
//[DllImport("User32.dll")]
|
||||
//extern static uint GetRawInputData(IntPtr hRawInput, uint uiCommand, IntPtr pData, ref uint pcbSize, uint cbSizeHeader);
|
||||
|
||||
//#endregion
|
||||
|
||||
MultiModeMasterViewModel multiModeMasterViewModel = new MultiModeMasterViewModel();
|
||||
|
||||
private List<MultiModeChild> Childs = new List<MultiModeChild>();
|
||||
|
||||
public ApplicationSettings AppSettings { get; private set; }
|
||||
//class RawInputDevice : InputDevice
|
||||
//{
|
||||
// public override IInputElement Target => throw new NotImplementedException();
|
||||
|
||||
// public override PresentationSource ActiveSource => throw new NotImplementedException();
|
||||
//}
|
||||
public MultiMode()
|
||||
{
|
||||
|
||||
DataContext = multiModeMasterViewModel;
|
||||
|
||||
InitializeComponent();
|
||||
Topmost = false;
|
||||
}
|
||||
private void keyUp(Object sender, KeyEventArgs e)
|
||||
{
|
||||
|
||||
}
|
||||
public void SetBaseFocus()
|
||||
{
|
||||
//foreach (var item in Childs)
|
||||
//{
|
||||
// item.Key.Activate();
|
||||
//}
|
||||
//this.Activate();
|
||||
//txtBarcodeInput.Focus();
|
||||
|
||||
}
|
||||
|
||||
|
||||
private MultiModeChild addChild(IMultiModeChildViewModel model)
|
||||
{
|
||||
var a = new MultiModeChild(model);
|
||||
|
||||
a.Show();
|
||||
return a;
|
||||
}
|
||||
CancellationTokenSource cts;
|
||||
|
||||
private void Window_Loaded(Object sender, RoutedEventArgs e)
|
||||
{
|
||||
cts = new CancellationTokenSource();
|
||||
AppSettings = new ApplicationSettings("MultiProductionUiConfig.json");
|
||||
multiModeMasterViewModel.StartPicking(cts);
|
||||
//var trigger = new List<string>();
|
||||
|
||||
//if (AppSettings.ChildForms == null || !AppSettings.ChildForms.Any())
|
||||
//{
|
||||
// AppSettings.ChildForms = new List<ApplicationSettings.MultiFormChilds>();
|
||||
|
||||
// AppSettings.ChildForms.Add(new ApplicationSettings.MultiFormChilds() { Name = "Picking", Slot = 1, ViewModelType = typeof(PickingMultiModeViewModel), StartPos = null, Visisble = true, TextPort = "COM11" });
|
||||
// AppSettings.ChildForms.Add(new ApplicationSettings.MultiFormChilds() { Name = "PressureHE", Slot = 3, ViewModelType = typeof(PressureMultiModeViewModel), StartPos = null, Visisble = true, TextPort = null });
|
||||
// AppSettings.ChildForms.Add(new ApplicationSettings.MultiFormChilds() { Name = "PressureHY", Slot = 1, ViewModelType = typeof(PressureMultiModeViewModel), StartPos = null, Visisble = true, TextPort = null });
|
||||
// AppSettings.ChildForms.Add(new ApplicationSettings.MultiFormChilds() { Name = "Marriage", Slot = 4, ViewModelType = typeof(MarriageMultiModeViewModel), StartPos = null, Visisble = true, TextPort = "COM1" });
|
||||
// AppSettings.Update("MultiProductionUiConfig.json");
|
||||
//}
|
||||
|
||||
|
||||
////AppSettings.ChildForms.ForEach(c => trigger.Add(c.TextPort.ToString()));
|
||||
|
||||
//cts = new CancellationTokenSource();
|
||||
|
||||
//foreach (var item in AppSettings.ChildForms)
|
||||
//{
|
||||
// if (item.Visisble)
|
||||
// {
|
||||
|
||||
|
||||
// IMultiModeChildViewModel mdl = null;
|
||||
// if (item.ViewModelType == typeof(PickingMultiModeViewModel))
|
||||
// {
|
||||
// mdl = new PickingMultiModeViewModel(item.Name, item.Slot, trigger, AppSettings.StationId);
|
||||
// }
|
||||
// else if (item.ViewModelType == typeof(PressureMultiModeViewModel))
|
||||
// {
|
||||
// mdl = new PressureMultiModeViewModel(item.Name, item.Slot, trigger, AppSettings.StationId);
|
||||
// }
|
||||
// else if (item.ViewModelType == typeof(MarriageMultiModeViewModel))
|
||||
// {
|
||||
// mdl = new MarriageMultiModeViewModel(item.Name, item.Slot, trigger, AppSettings.StationId);
|
||||
// }
|
||||
// if (mdl == null)
|
||||
// {
|
||||
// throw new ApplicationException("Bad configuration or old software");
|
||||
// }
|
||||
// var child = addChild(mdl);
|
||||
|
||||
// child.StartTextInputListener(item.TextPort, cts.Token);
|
||||
|
||||
// if (item.StartPos != null)
|
||||
// {
|
||||
// child.WindowStartupLocation = WindowStartupLocation.Manual;
|
||||
// child.Top = item.StartPos.Top;
|
||||
// child.Left = item.StartPos.Left;
|
||||
// child.Height = item.StartPos.Height;
|
||||
// child.Width = item.StartPos.Width;
|
||||
// child.UseDefaultPos = false;
|
||||
// }
|
||||
// child.PosChanged += delegate (object val, EventArgs a)
|
||||
// {
|
||||
// if (val is MultiModeChild mmc)
|
||||
// {
|
||||
// if (mmc.ViewModel is BaseMultiModeChildViewModel baseChild)
|
||||
// {
|
||||
// var aasd = AppSettings.ChildForms.FirstOrDefault(c => c.Name == baseChild.ChildName);
|
||||
// aasd.StartPos = new ApplicationSettings.Pos() { Height = mmc.Height, Left = mmc.Left, Top = mmc.Top, Width = mmc.Width };
|
||||
|
||||
// AppSettings.Update("MultiProductionUiConfig.json");
|
||||
// }
|
||||
// }
|
||||
|
||||
// };
|
||||
|
||||
|
||||
// child.Show();
|
||||
|
||||
// Childs.Add(child);
|
||||
|
||||
// }
|
||||
|
||||
//}
|
||||
|
||||
|
||||
|
||||
//SetBaseFocus();
|
||||
}
|
||||
|
||||
private void delegeChild_PosChange(Object sender, EventArgs e)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private void TxtBarcodeInput_TextChanged(Object sender, TextChangedEventArgs e)
|
||||
{
|
||||
//if (sender is TextBox text)
|
||||
//{
|
||||
// if (text.Text.ToLower().Contains("clear"))
|
||||
// {
|
||||
// text.Text = string.Empty;
|
||||
// }
|
||||
// else if (text.Text.Contains(System.Environment.NewLine))
|
||||
// {
|
||||
// foreach (var dispatchChild in Childs.Where(x => x.Value == text.Text[0]))
|
||||
// {
|
||||
// dispatchChild.Key.InputText(text.Text.Substring(1, text.Text.Length - 1).Trim());
|
||||
// }
|
||||
|
||||
// text.Text = "";
|
||||
// SetBaseFocus();
|
||||
// }
|
||||
|
||||
//}
|
||||
|
||||
}
|
||||
|
||||
private void Window_Closed(Object sender, EventArgs e)
|
||||
{
|
||||
|
||||
cts.Cancel();
|
||||
|
||||
|
||||
foreach (var item in Childs)
|
||||
{
|
||||
item.Dispose();
|
||||
|
||||
item.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,84 +0,0 @@
|
||||
<Window
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:ctls="clr-namespace:Xylem.Common.Production.ProductionUiCordonel.ctls"
|
||||
x:Class="Xylem.Common.Production.ProductionUiCordonel.MultiModeChild"
|
||||
mc:Ignorable="d"
|
||||
|
||||
Title="MultiModeChild" Height="802.824" Width="704.975" WindowStartupLocation="Manual">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="25"/>
|
||||
<RowDefinition Height="60"/>
|
||||
<RowDefinition Height="25"/>
|
||||
<RowDefinition Height="60"/>
|
||||
<RowDefinition Height="25"/>
|
||||
<RowDefinition Height="60"/>
|
||||
<RowDefinition Height="25"/>
|
||||
<RowDefinition Height="60"/>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="20"/>
|
||||
<RowDefinition Height="20"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Label Content="Name"
|
||||
HorizontalAlignment="Left"
|
||||
Margin="0,0,0,0"
|
||||
VerticalAlignment="Top"
|
||||
Grid.Row="0"/>
|
||||
|
||||
<Label Background="LightGray" FontSize="17pt"
|
||||
HorizontalContentAlignment="Right" Margin="10,5,10,0"
|
||||
VerticalAlignment="Top" Height="40"
|
||||
Content="{Binding ChildName}"
|
||||
Grid.Row="1" />
|
||||
<Label Content="Order"
|
||||
HorizontalAlignment="Left"
|
||||
Margin="0,0,0,0"
|
||||
VerticalAlignment="Top"
|
||||
Grid.Row="2"/>
|
||||
|
||||
<Label Background="LightGray" FontSize="17pt"
|
||||
HorizontalContentAlignment="Right" Margin="10,10,10,0"
|
||||
VerticalAlignment="Top" Height="40"
|
||||
Content="{Binding Order, UpdateSourceTrigger=PropertyChanged}"
|
||||
Grid.Row="3" />
|
||||
|
||||
<Label Content="SlotInfo"
|
||||
HorizontalAlignment="Left"
|
||||
Margin="0,0,0,0"
|
||||
VerticalAlignment="Top"
|
||||
Grid.Row="4"/>
|
||||
|
||||
<Label Background="LightGray" FontSize="17pt"
|
||||
HorizontalContentAlignment="Right" Margin="10,10,10,0"
|
||||
VerticalAlignment="Top" Height="40"
|
||||
Content="{Binding SlotInfo, UpdateSourceTrigger=PropertyChanged}"
|
||||
Grid.Row="5"/>
|
||||
|
||||
<Label Content="State"
|
||||
HorizontalAlignment="Left"
|
||||
Margin="0,0,0,0"
|
||||
VerticalAlignment="Top"
|
||||
Grid.Row="6"/>
|
||||
|
||||
<Label Background="LightGray" FontSize="17pt"
|
||||
HorizontalContentAlignment="Right" Margin="10,10,10,0"
|
||||
VerticalAlignment="Top" Height="40"
|
||||
Content="{Binding CurrentSlotStateText, UpdateSourceTrigger=PropertyChanged}"
|
||||
Grid.Row="7"/>
|
||||
|
||||
<ctls:ctlMultiModePressure x:Name="PressureControl" Visibility="{Binding VisibilityPressure}" Grid.Row="8" Margin="0,0,0,0" OnBarcodeInput="PressureControl_OnBarcodeInput" />
|
||||
<ctls:ctlMultiModePicking x:Name="PickingControl" Visibility="{Binding VisibilityPicking}" Grid.Row="8" Margin="0,0,0,0" />
|
||||
<ctls:ctlMultiModeMarriage x:Name="MarriageControl" Visibility="{Binding VisibilityMarriage}" Grid.Row="8" Margin="0,0,0,0"/>
|
||||
|
||||
<Button Content="POS" Grid.Row="9" Click="Button_Click" />
|
||||
<Button Content="Store" Grid.Row="10" Click="Button_Click_1" />
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</Grid>
|
||||
</Window>
|
||||
@@ -1,135 +0,0 @@
|
||||
using System;
|
||||
using System.IO.Ports;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Threading;
|
||||
using Xylem.Common.Production.ProductionUiCordonel.Event;
|
||||
using Xylem.Common.Production.ProductionUiCordonel.Model;
|
||||
|
||||
namespace Xylem.Common.Production.ProductionUiCordonel
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaktionslogik für MultiModeChild.xaml
|
||||
/// </summary>
|
||||
public partial class MultiModeChild : Window, IDisposable
|
||||
{
|
||||
public IMultiModeChildViewModel ViewModel;
|
||||
|
||||
public Boolean UseDefaultPos { get; internal set; } = true;
|
||||
public event EventHandler PosChanged;
|
||||
|
||||
|
||||
public MultiModeChild(IMultiModeChildViewModel viewModel)
|
||||
{
|
||||
InitializeComponent();
|
||||
ViewModel = viewModel;
|
||||
DataContext = ViewModel;
|
||||
if (ViewModel is PressureMultiModeViewModel pressureModel)
|
||||
{
|
||||
PressureControl.setViewModel(pressureModel);
|
||||
|
||||
Left = 0;
|
||||
Top = 250;
|
||||
Height = SystemParameters.PrimaryScreenHeight - 300;
|
||||
Width = SystemParameters.PrimaryScreenWidth / 2;
|
||||
}
|
||||
if (ViewModel is PickingMultiModeViewModel pickingModel)
|
||||
{
|
||||
PickingControl.setViewModel(pickingModel);
|
||||
|
||||
Left = SystemParameters.VirtualScreenLeft;
|
||||
Top = SystemParameters.VirtualScreenTop;
|
||||
Height = SystemParameters.VirtualScreenHeight;
|
||||
Width = SystemParameters.VirtualScreenWidth - SystemParameters.PrimaryScreenWidth;
|
||||
}
|
||||
if (ViewModel is MarriageMultiModeViewModel marriageModel)
|
||||
{
|
||||
MarriageControl.setViewModel(marriageModel);
|
||||
|
||||
Left = SystemParameters.PrimaryScreenWidth / 2;
|
||||
Top = 250;
|
||||
Height = SystemParameters.PrimaryScreenHeight - 300;
|
||||
Width = SystemParameters.PrimaryScreenWidth / 2;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
internal void StartTextInputListener(String port, CancellationToken cancellation)
|
||||
{
|
||||
if (port == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
var task = new Task(() =>
|
||||
{
|
||||
var a = new SerialPort(port);
|
||||
a.Open();
|
||||
a.NewLine = "\r";
|
||||
while (true)
|
||||
{
|
||||
if (cancellation.IsCancellationRequested)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
var resText = a.ReadLine();
|
||||
Dispatcher.Invoke(DispatcherPriority.Normal,
|
||||
new Action(() =>
|
||||
{
|
||||
ViewModel.InputText(resText);
|
||||
}
|
||||
));
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}, cancellation);
|
||||
task.Start();
|
||||
|
||||
|
||||
}
|
||||
|
||||
internal void InputText(String text)
|
||||
{
|
||||
ViewModel.InputText(text);
|
||||
}
|
||||
|
||||
private void BtnPresueFailed_Click(Object sender, RoutedEventArgs e)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private void TxtPresurePcbId_TextChanged(Object sender, TextChangedEventArgs e)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private void PressureControl_OnBarcodeInput(Object sender, StringArgs e)
|
||||
{
|
||||
InputText(e.Content);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
ViewModel.Dispose();
|
||||
|
||||
}
|
||||
|
||||
private void Button_Click(Object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (sender is Button btn)
|
||||
{
|
||||
btn.Content = $"POS L{Left},T{Top },H{Height},W{Width}";
|
||||
}
|
||||
}
|
||||
|
||||
private void Button_Click_1(Object sender, RoutedEventArgs e)
|
||||
{
|
||||
PosChanged?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,150 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.Enum;
|
||||
using Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.GenericProcesses;
|
||||
using Xylem.Common.Production.ProductionUiCordonel.Properties;
|
||||
|
||||
|
||||
namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses
|
||||
{
|
||||
/// <summary>
|
||||
/// Concatenation for all production process states:
|
||||
/// </summary>
|
||||
/// <remarks date="2025-Apr-14" author="Thomas Wiedebusch">
|
||||
/// - Initial
|
||||
/// </remarks>
|
||||
public class BaseProcessStatesDef : IProcessStateDef
|
||||
{
|
||||
/// <summary>
|
||||
/// Collection of state information
|
||||
/// </summary>
|
||||
public List<ProcessStateStruct> StateContainer { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Ctor:
|
||||
/// Initialize all hidden standard generic states
|
||||
/// </summary>
|
||||
protected BaseProcessStatesDef()
|
||||
{
|
||||
StateContainer = new List<ProcessStateStruct>
|
||||
{
|
||||
new ProcessStateStruct(
|
||||
productionProcess: null,
|
||||
processState: ProcessState.Idle,
|
||||
processInfo: Resources.StrStateIdle,
|
||||
productionProcessNo: null,
|
||||
nextStateOnSuccess: ProcessState.Idle),
|
||||
|
||||
new ProcessStateStruct(
|
||||
productionProcess: new ErrorHandler(null),
|
||||
processState: ProcessState.Error,
|
||||
processInfo: Resources.StrProcessStateError,
|
||||
productionProcessNo: null,
|
||||
nextStateOnSuccess: ProcessState.Idle,
|
||||
startAlways: true),
|
||||
|
||||
new ProcessStateStruct(
|
||||
productionProcess: null,
|
||||
processState: ProcessState.RepeatFailedTests,
|
||||
processInfo: Resources.StrStateRepeatFinalTest,
|
||||
productionProcessNo: null,
|
||||
nextStateOnSuccess: BaseProductionProcess.DoNotChangeStateAfterCompletion),
|
||||
|
||||
new ProcessStateStruct(
|
||||
productionProcess: null,
|
||||
processState:ProcessState.AbortTest,
|
||||
processInfo:Resources.StrStateSkipping,
|
||||
productionProcessNo:null,
|
||||
nextStateOnSuccess:ProcessState.Idle),
|
||||
|
||||
new ProcessStateStruct(
|
||||
productionProcess: null,
|
||||
processState:ProcessState.Stop,
|
||||
processInfo:Resources.StrStateUserStop,
|
||||
productionProcessNo:null,
|
||||
nextStateOnSuccess:ProcessState.Idle),
|
||||
|
||||
new ProcessStateStruct(
|
||||
productionProcess: null,
|
||||
processState:ProcessState.PrintSuccessReport,
|
||||
processInfo:Resources.StrStatePrintSuccessReport,
|
||||
productionProcessNo:null,
|
||||
nextStateOnSuccess:ProcessState.Idle),
|
||||
|
||||
new ProcessStateStruct(
|
||||
productionProcess: null,
|
||||
processState:ProcessState.PrintReturnReport,
|
||||
processInfo:Resources.StrStatePrintReturnReport,
|
||||
productionProcessNo:null,
|
||||
nextStateOnSuccess:ProcessState.Idle)
|
||||
};
|
||||
}
|
||||
|
||||
///<inheritdoc/>
|
||||
public ProcessStateStruct GetProcessStateStructOfState(ProcessState stateMachineState)
|
||||
{
|
||||
return (from stateContainer in StateContainer
|
||||
where stateContainer.ProcessState == stateMachineState
|
||||
select stateContainer).FirstOrDefault();
|
||||
}
|
||||
|
||||
///<inheritdoc/>
|
||||
public IProductionProcess GetProcessOfState(ProcessState stateMachineState)
|
||||
{
|
||||
return (from stateContainer in StateContainer
|
||||
where stateContainer.ProcessState == stateMachineState
|
||||
select stateContainer.ProductionProcess).FirstOrDefault();
|
||||
}
|
||||
|
||||
///<inheritdoc/>
|
||||
public String GetStateInfoOfState(ProcessState? stateMachineState)
|
||||
{
|
||||
if (stateMachineState == null)
|
||||
stateMachineState = ProcessState.Error;
|
||||
|
||||
return (from stateContainer in StateContainer
|
||||
where stateContainer.ProcessState == stateMachineState
|
||||
select stateContainer.ProcessInfo).FirstOrDefault();
|
||||
}
|
||||
|
||||
///<inheritdoc/>
|
||||
public String GetStateInfoOfProcess(IProductionProcess process)
|
||||
{
|
||||
return (from stateContainer in StateContainer
|
||||
where stateContainer.ProductionProcess == process
|
||||
select stateContainer.ProcessInfo).FirstOrDefault();
|
||||
}
|
||||
|
||||
///<inheritdoc/>
|
||||
public ProcessState GetStateOfInfoText(String text)
|
||||
{
|
||||
return (from stateContainer in StateContainer
|
||||
where stateContainer.ProcessInfo == text
|
||||
select stateContainer.ProcessState).FirstOrDefault();
|
||||
}
|
||||
|
||||
///<inheritdoc/>
|
||||
public ProcessState GetStateOfProcess(IProductionProcess process)
|
||||
{
|
||||
return (from stateContainer in StateContainer
|
||||
where stateContainer.ProductionProcess == process
|
||||
select stateContainer.ProcessState).FirstOrDefault();
|
||||
}
|
||||
|
||||
///<inheritdoc/>
|
||||
public Int32 GetNumberOfInitializedProcesses()
|
||||
{
|
||||
return StateContainer.Count(stateContainer => stateContainer.ProductionProcessNo != null);
|
||||
}
|
||||
|
||||
///<inheritdoc/>
|
||||
public List<IProductionProcess> GetAllEolRelevantProcesses()
|
||||
{
|
||||
var sortedList = StateContainer
|
||||
.Where(y => y.ProductionProcessNo != null)
|
||||
.OrderBy(x => x.ProductionProcessNo);
|
||||
return (from state in sortedList select state.ProductionProcess).ToList();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,7 @@ using Xylem.Common.Logic.ProductionOrderCore;
|
||||
using Xylem.Common.Production.ProductionUiCordonel.Properties;
|
||||
using Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.Enum;
|
||||
using Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.EventArgs;
|
||||
using Xylem.Common.Production.ProductionUiCordonel.UserControls.FinalTest;
|
||||
using Xylem.Common.Production.ProductionUiCordonel.UserControls;
|
||||
using Xylem.Common.Utils.ProcessExec;
|
||||
using Xylem.Common.Utils.ProcessExec.EventArguments;
|
||||
|
||||
@@ -292,7 +292,7 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses
|
||||
|
||||
/// <inheritdoc cref="IProductionProcess"/>
|
||||
public void StartProcess(ProcessState? successExitState, ProcessState errorExitState = ProcessState.Error,
|
||||
ProcessState breakExitState = ProcessState.AbortFinalTest)
|
||||
ProcessState breakExitState = ProcessState.AbortTest)
|
||||
{
|
||||
if (Meter == null)
|
||||
{
|
||||
|
||||
@@ -19,18 +19,14 @@
|
||||
/// </summary>
|
||||
Error,
|
||||
/// <summary>
|
||||
/// Abort final test execution
|
||||
/// Abort test execution
|
||||
/// </summary>
|
||||
AbortFinalTest,
|
||||
AbortTest,
|
||||
/// <summary>
|
||||
/// Repeat the entire final test
|
||||
/// Repeat the entire test
|
||||
/// </summary>
|
||||
RepeatFailedTests,
|
||||
/// <summary>
|
||||
/// Final test failed
|
||||
/// </summary>
|
||||
FinalTestFailed,
|
||||
/// <summary>
|
||||
/// User stopped process
|
||||
/// </summary>
|
||||
Stop,
|
||||
|
||||
+1
-1
@@ -9,7 +9,7 @@ using Xylem.Common.Logic.ProductionOrderCore.Vako;
|
||||
using Xylem.Common.Logic.SoftwareAccessHelper;
|
||||
using Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.Enum;
|
||||
using Xylem.Common.Production.ProductionUiCordonel.Properties;
|
||||
using Xylem.Common.Production.ProductionUiCordonel.UserControls.FinalTest;
|
||||
using Xylem.Common.Production.ProductionUiCordonel.UserControls;
|
||||
|
||||
namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.EolProcesses
|
||||
{
|
||||
|
||||
+8
-7
@@ -16,6 +16,7 @@ using Xylem.Common.Logic.ProductionOrderCore.OrderData;
|
||||
using Xylem.Common.Logic.ProductionOrderCore.TestResults;
|
||||
using Xylem.Common.Production.ProductionUiCordonel.Model;
|
||||
using Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.Enum;
|
||||
using Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.GenericProcesses;
|
||||
using Xylem.Common.Production.ProductionUiCordonel.Properties;
|
||||
|
||||
namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.EolProcesses
|
||||
@@ -589,7 +590,7 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.EolPr
|
||||
}
|
||||
|
||||
// Set the information of this software
|
||||
EolProgress.EOLSoftwareNameAndVersion = $"{Resources.StrSoftwareNameVersion} " +
|
||||
EolProgress.EOLSoftwareNameAndVersion = $"{Resources.StrEolSoftwareNameVersion} " +
|
||||
$"{Assembly.GetExecutingAssembly().GetName().Version}";
|
||||
|
||||
return EolProgress.EOLSoftwareNameAndVersion;
|
||||
@@ -726,7 +727,7 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.EolPr
|
||||
{
|
||||
if (EolProgress != null)
|
||||
EolProgress.RequirementPcbIdChecked = EOLStatus.FAIL;
|
||||
feedbackMsg = Resources.StrSuccessMsgOrderBasedRequirements;
|
||||
feedbackMsg = Resources.StrErrorMsgRequirementPcbId;
|
||||
return EOLStatus.FAIL;
|
||||
}
|
||||
|
||||
@@ -1033,14 +1034,14 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.EolPr
|
||||
// Create an output message addon for alternative power consumption calculation
|
||||
var strAlternativeCalc = ProductionStatus.AlternativeRequiredBatteryLoadPercent == null
|
||||
? ""
|
||||
: $" - {Resources.StrMsgRequirementAbsolutLimitDrainedBatteryAtEol}: " +
|
||||
: $" - {Resources.StrMsgRequirementAbsolutLimitDrainedBattery}: " +
|
||||
$"{ProductionRequirements.MaxDrainedBatteryLoadPercentShipping:F2} %" +
|
||||
$" ({Resources.StrMsgAlternativeDrainedBatteryCalculation})";
|
||||
|
||||
var batteryLoad = $"{Resources.StrMsgDrainedBatteryAtEol}: " +
|
||||
var batteryLoad = $"{Resources.StrMsgDrainedBattery}: " +
|
||||
// Actual calculated battery load based on readings from meter
|
||||
$"{ProductionStatus.DrainedBatteryLoadPercent:F2} %" +
|
||||
$" - {Resources.StrMsgRequirementLimitDrainedBatteryAtEol}: " +
|
||||
$" - {Resources.StrMsgRequirementLimitDrainedBattery}: " +
|
||||
// Required battery load from standard or special requirement
|
||||
$"{threshold:F2} % {strAlternativeCalc}";
|
||||
|
||||
@@ -1108,11 +1109,11 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.EolPr
|
||||
}
|
||||
|
||||
// Build message for required versus calculated lifetime
|
||||
var lifeTime = $"{Resources.StrMsgRemainingLifeTimeAtEol}: " +
|
||||
var lifeTime = $"{Resources.StrMsgRemainingLifeTime}: " +
|
||||
// Actual calculated lifetime based on readings from meter
|
||||
$"{ProductionStatus.RemainingLifeTimeYears:F2} " +
|
||||
$"{Resources.StrMsgYears}" +
|
||||
$" - {Resources.StrMsgRequiredLifeTimeAtEol}: " +
|
||||
$" - {Resources.StrMsgRequiredLifeTime}: " +
|
||||
// Required lifetime from special or standard requirement
|
||||
$"{ProductionRequirements.RequiredLifeTimeYearsShipping:F2} " +
|
||||
$"{Resources.StrMsgYears}";
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@ using Xylem.Common.Logic.ProductionOrderCore;
|
||||
using Xylem.Common.Logic.SoftwareAccessHelper;
|
||||
using Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.Enum;
|
||||
using Xylem.Common.Production.ProductionUiCordonel.Properties;
|
||||
using Xylem.Common.Production.ProductionUiCordonel.UserControls.FinalTest;
|
||||
using Xylem.Common.Production.ProductionUiCordonel.UserControls;
|
||||
using Button = System.Windows.Controls.Button;
|
||||
// ReSharper disable UnusedAutoPropertyAccessor.Local
|
||||
|
||||
|
||||
+302
@@ -0,0 +1,302 @@
|
||||
using System.Collections.Generic;
|
||||
using Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.Enum;
|
||||
using Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.GenericProcesses;
|
||||
using Xylem.Common.Production.ProductionUiCordonel.Properties;
|
||||
|
||||
namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.EolProcesses
|
||||
{
|
||||
/// <summary>
|
||||
/// Concatenation for all production process states:
|
||||
/// - Production process class (representing a production process step), null if hidden process,
|
||||
/// - attached state,
|
||||
/// - state information to display a text message,
|
||||
/// - production process number to define where to display in the overview,
|
||||
/// - next state which should be executed after this succeeded,
|
||||
/// [optional]:
|
||||
/// - own error state,
|
||||
/// - own break state,
|
||||
/// - kick off state for parallel execution after starting this process in a separate task,
|
||||
/// - wait for single process to finish successfully,
|
||||
/// - wait for all processes to finish successfully,
|
||||
/// - start always independent of any result, e.g. the error state needs to be started if called!
|
||||
/// </summary>
|
||||
/// <remarks date="2025-Apr-15" author="Thomas Wiedebusch">
|
||||
/// - Initial
|
||||
/// </remarks>
|
||||
public class EolProcessStateDef : BaseProcessStatesDef
|
||||
{
|
||||
/// <summary>
|
||||
/// State-machine definitions of production-processes which feeds the state-machine.
|
||||
///
|
||||
///
|
||||
/// INSTRUCTION FOR PREPARATION:
|
||||
/// -----------------------------
|
||||
/// STEP 1: Define some states for your processes <see cref="ProcessState"/>
|
||||
/// STEP 2: Implement your processes like <see cref="DetectCordonel"/>
|
||||
/// STEP 3: Register and chain your states here
|
||||
///
|
||||
///
|
||||
/// INSTRUCTION FOR NORMAL USAGE:
|
||||
/// -----------------------------
|
||||
/// Means one state automatically switched on successfully execution to the next required state.
|
||||
///
|
||||
/// Define the (e.g.):
|
||||
/// productionProcess: new DetectCordonel(Resources.StrStateDetectCordonel),
|
||||
/// processState: ProcessState.DetectCordonel,
|
||||
/// processInfo: Resources.StrStateDetectCordonel,
|
||||
/// productionProcessNo: 0,
|
||||
/// nextStateOnSuccess: ProcessState.CheckNewMeter),
|
||||
///
|
||||
/// If a special state is needed on errorExitState or breakExitState these can be assigned. Otherwise, the
|
||||
/// "errorExitState" is linked to the generic-error-state, the "breakExitState" to the abort-test-state.
|
||||
///
|
||||
///
|
||||
/// INSTRUCTION FOR NON-BLOCKING MULTIPLE PROCESSES SIMULTANEOUSLY ACTIVITIES:
|
||||
/// --------------------------------------------------------------------------
|
||||
/// Sometimes production processes may be able to be executed simultaneously as they are independent of each
|
||||
/// other. One example is a database access for data collection from different tables.
|
||||
///
|
||||
/// This is needed for non-blocking immediately new state change (not waiting for the successful execution of
|
||||
/// the actual new assigned process).
|
||||
///
|
||||
/// Define the (e.g.):
|
||||
///
|
||||
/// productionProcess: new ConnectCordonel(Resources.StrStateConnectCordonel),
|
||||
/// processState: ProcessState.ConnectCordonel,
|
||||
/// processInfo: Resources.StrStateConnectCordonel,
|
||||
/// productionProcessNo: 1,
|
||||
/// // Avoid automatic change after completion as parallel process is active
|
||||
/// nextStateOnSuccess: BaseProductionProcess.DoNotChangeStateAfterCompletion,
|
||||
/// // Kick off parallel process execution after starting the "ConnectCordonel() task"
|
||||
/// kickOffParallelState: ProcessState.GetSerialNumberAndRadioAddress),
|
||||
///
|
||||
///
|
||||
/// INSTRUCTION TO DELAY THE START OF A PROCESS AND WAIT ON RESULTS OF OTHER PROCESS(ES):
|
||||
/// -------------------------------------------------------------------------------------
|
||||
/// Each new process execution can be delayed as it may need the result of another process which is active.
|
||||
///
|
||||
/// Wait for a single process to complete:
|
||||
/// Set the "waitForSingleProcess" to the state of the process needed to wait for (e.g.):
|
||||
///
|
||||
/// productionProcess: new CheckProductionState(Resources.StrStateCheckProductionState),
|
||||
/// processState: ProcessState.CheckProductionState,
|
||||
/// processInfo: Resources.StrStateCheckProductionState,
|
||||
/// productionProcessNo: 4,
|
||||
/// // Avoid automatic change after completion as parallel process is active
|
||||
/// nextStateOnSuccess: BaseProductionProcess.DoNotChangeStateAfterCompletion,
|
||||
/// // Kick off parallel process execution after starting
|
||||
/// kickOffParallelState: ProcessState.ProcessPasswordFile,
|
||||
/// // Wait until this process has been successfully completed
|
||||
/// waitForSingleProcess: ProcessState.ConnectCordonel),
|
||||
///
|
||||
/// Wait for all preceding processes to complete to be sure to get all data and all processed are succeeded:
|
||||
/// Set the "waitForAllProcesses" to true (e.g.):
|
||||
/// productionProcess: new ExecPasswordFile(Resources.StrStatePasswordFile),
|
||||
/// processState: ProcessState.ProcessPasswordFile,
|
||||
/// processInfo: Resources.StrStatePasswordFile,
|
||||
/// productionProcessNo: 5,
|
||||
/// nextStateOnSuccess: ProcessState.ExecFinalParametrization,
|
||||
/// waitForAllProcesses: true),
|
||||
///
|
||||
/// </summary>
|
||||
public EolProcessStateDef()
|
||||
{
|
||||
var stateContainer = new List<ProcessStateStruct>
|
||||
{
|
||||
#region ----------------------------------- GENERIC-STATES---------------------------------------------
|
||||
// Detection of Cordonel has to be completed before assigning next state, so leave to automatic
|
||||
// to change the state after successfully execution. The detection is the base for all others.
|
||||
new ProcessStateStruct(
|
||||
productionProcess: new DetectCordonel(Resources.StrStateDetectCordonel),
|
||||
processState: ProcessState.DetectCordonel,
|
||||
processInfo: Resources.StrStateDetectCordonel,
|
||||
productionProcessNo: 0,
|
||||
nextStateOnSuccess: ProcessState.CheckNewMeter),
|
||||
|
||||
// Detection of Cordonel has to be completed before assigning next state. It has to be checked if
|
||||
// the meter changed to clear all collected contents of previous run. To UPDATE ALL INFORMATION after
|
||||
// new meter assignment the "DetectCordonel" has to be repeated to return here "Old Meter" and then
|
||||
// enter the "ConnectCordonel"!
|
||||
new ProcessStateStruct(
|
||||
productionProcess: null,
|
||||
processState: ProcessState.CheckNewMeter,
|
||||
processInfo: Resources.StrProcessStateCheckNewMeter,
|
||||
productionProcessNo: null,
|
||||
nextStateOnSuccess: ProcessState.DetectCordonel,
|
||||
errorExitState: ProcessState.ConnectCordonel),
|
||||
|
||||
// Precondition: - The detection process has to be completed as the PcbId is needed.
|
||||
// AVOID to change the process state on completion as parallel process is active!
|
||||
new ProcessStateStruct(
|
||||
productionProcess: new ConnectCordonel(Resources.StrStateConnectCordonel),
|
||||
processState: ProcessState.ConnectCordonel,
|
||||
processInfo: Resources.StrStateConnectCordonel,
|
||||
productionProcessNo: 1,
|
||||
// Avoid automatic change after completion as parallel process is active
|
||||
nextStateOnSuccess: BaseProductionProcess.DoNotChangeStateAfterCompletion,
|
||||
// Kick off parallel process execution
|
||||
kickOffParallelState: ProcessState.GetSerialNumberAndRadioAddress),
|
||||
|
||||
// Precondition: - The detection process has to be completed as the PcbId is needed.
|
||||
// AVOID to change the process state on completion as parallel process is active!
|
||||
new ProcessStateStruct(
|
||||
productionProcess: new GetSerialNumberAndRadioAddress(Resources.StrStateGetSerialAndRadioAddress),
|
||||
processState:ProcessState.GetSerialNumberAndRadioAddress,
|
||||
processInfo:Resources.StrStateGetSerialAndRadioAddress,
|
||||
productionProcessNo: 2,
|
||||
// Avoid automatic change after completion as parallel process is active
|
||||
nextStateOnSuccess: BaseProductionProcess.DoNotChangeStateAfterCompletion,
|
||||
// Kick off parallel process execution
|
||||
kickOffParallelState:ProcessState.GetProgrammingParameters),
|
||||
|
||||
// This scans the order number, it has to be executed exclusively with automatic
|
||||
new ProcessStateStruct(
|
||||
productionProcess: new CheckOrderNumber(Resources.StrStateCheckOrderNumber),
|
||||
processState: ProcessState.CheckOrderNumber,
|
||||
processInfo: Resources.StrStateCheckOrderNumber,
|
||||
productionProcessNo: 11,
|
||||
nextStateOnSuccess: ProcessState.CheckSerialNumber),
|
||||
|
||||
// This scans the serial number, it has to be executed exclusively with automatic
|
||||
new ProcessStateStruct(
|
||||
productionProcess: new CheckSerialNumber( Resources.StrStateCheckSerialNumber),
|
||||
processState: ProcessState.CheckSerialNumber,
|
||||
processInfo: Resources.StrStateCheckSerialNumber,
|
||||
productionProcessNo: 12,
|
||||
nextStateOnSuccess: ProcessState.CheckAttachments),
|
||||
|
||||
#endregion -------------------------------- GENERIC-STATES --------------------------------------------
|
||||
|
||||
#region ----------------------------------- EOL-STATES ------------------------------------------------
|
||||
// Precondition: - The connection process has to be completed as a readout of some register
|
||||
// values from the Cordonel are needed to check the update capability:
|
||||
// - Wait on completed connection process before starting this process.
|
||||
// AVOID to change the process state on completion as parallel process is active!
|
||||
new ProcessStateStruct(
|
||||
productionProcess: new GetFinalParametrization(Resources.StrStateGetProgrammingParameters),
|
||||
processState: ProcessState.GetProgrammingParameters,
|
||||
processInfo: Resources.StrStateGetProgrammingParameters,
|
||||
productionProcessNo: 3,
|
||||
// Avoid automatic change after completion as parallel process is active
|
||||
nextStateOnSuccess: BaseProductionProcess.DoNotChangeStateAfterCompletion,
|
||||
// Kick off parallel process execution
|
||||
kickOffParallelState: ProcessState.CheckProductionState,
|
||||
// Wait until this process has been successfully completed
|
||||
waitForSingleProcess: ProcessState.ConnectCordonel),
|
||||
|
||||
// Precondition: - The connection process has to be completed as a readout of some register
|
||||
// values from the Cordonel are needed to check the update capability:
|
||||
// - Wait on completed connection process before starting this process.
|
||||
// AVOID to change the process state on completion as parallel process is active!
|
||||
new ProcessStateStruct(
|
||||
productionProcess: new CheckProductionState(Resources.StrStateCheckProductionState),
|
||||
processState: ProcessState.CheckProductionState,
|
||||
processInfo: Resources.StrStateCheckProductionState,
|
||||
productionProcessNo: 4,
|
||||
// Avoid automatic change after completion as parallel process is active
|
||||
nextStateOnSuccess: BaseProductionProcess.DoNotChangeStateAfterCompletion,
|
||||
// Kick off parallel process execution
|
||||
kickOffParallelState: ProcessState.ProcessPasswordFile,
|
||||
// Wait until this process has been successfully completed
|
||||
waitForSingleProcess: ProcessState.ConnectCordonel),
|
||||
|
||||
|
||||
// Precondition: - The connection process has to be completed as a password change in the DB
|
||||
// will take place: Skeleton to Password Level 8. Not waiting for completion may cause side
|
||||
// effects on login. Wait for all processes to complete.
|
||||
// Leave state switch to automatic to avoid side effects on incomplete updated DB for next
|
||||
// steps.
|
||||
new ProcessStateStruct(
|
||||
productionProcess: new ExecPasswordFile(Resources.StrStatePasswordFile),
|
||||
processState: ProcessState.ProcessPasswordFile,
|
||||
processInfo: Resources.StrStatePasswordFile,
|
||||
productionProcessNo: 5,
|
||||
nextStateOnSuccess: ProcessState.ExecFinalParametrization,
|
||||
waitForAllProcesses: true),
|
||||
|
||||
// This writes all setups to the device, it has to be executed exclusively with automatic
|
||||
new ProcessStateStruct(
|
||||
productionProcess: new ExecFinalParametrization(Resources.StrStateFinalParametrization),
|
||||
processState: ProcessState.ExecFinalParametrization,
|
||||
processInfo: Resources.StrStateFinalParametrization,
|
||||
productionProcessNo: 6,
|
||||
nextStateOnSuccess: ProcessState.ExecStoreConfiguration),
|
||||
|
||||
// Precondition: - The final parametrization has to be finished as this shall be stored
|
||||
// to non-volatile memory and checked if remaining valid after the reboot.
|
||||
// Store configuration has to be executed exclusively with automatic
|
||||
new ProcessStateStruct(
|
||||
productionProcess: new ExecStoreConfiguration(Resources.StrStateStoreConfiguration),
|
||||
processState: ProcessState.ExecStoreConfiguration,
|
||||
processInfo: Resources.StrStateStoreConfiguration,
|
||||
productionProcessNo: 7,
|
||||
nextStateOnSuccess: ProcessState.RebootCordonel),
|
||||
|
||||
// Precondition: - The store configuration has to be executed to safe all settings
|
||||
// to non-volatile memory and checked if remaining valid after the reboot.
|
||||
// Reboot has to be executed exclusively with automatic
|
||||
new ProcessStateStruct(
|
||||
productionProcess: new ExecRebootCordonel(Resources.StrStateRebootCordonel),
|
||||
processState: ProcessState.RebootCordonel,
|
||||
processInfo: Resources.StrStateRebootCordonel,
|
||||
productionProcessNo: 8,
|
||||
nextStateOnSuccess: ProcessState.CheckFinalParametrization),
|
||||
|
||||
// Precondition: - The reboot process including the store all configurations has to be
|
||||
// completed.
|
||||
// Check final configuration has to be executed exclusively with automatic
|
||||
new ProcessStateStruct(
|
||||
productionProcess: new CheckFinalParametrization(Resources.StrStateCheckParametrization),
|
||||
processState: ProcessState.CheckFinalParametrization,
|
||||
processInfo: Resources.StrStateCheckParametrization,
|
||||
productionProcessNo:9,
|
||||
nextStateOnSuccess: ProcessState.CheckRadio),
|
||||
|
||||
// Precondition: - The final parametrization, reboot process including the store all
|
||||
// configurations and the check of all setups survived the reboot have to be completed.
|
||||
// Radio signal level check, skipped on NA region or if skipping is required by special
|
||||
// approval
|
||||
new ProcessStateStruct(
|
||||
productionProcess: new CheckRadio(Resources.StrStateRadioCheck),
|
||||
processState: ProcessState.CheckRadio,
|
||||
processInfo: Resources.StrStateRadioCheck,
|
||||
productionProcessNo:10,
|
||||
nextStateOnSuccess: ProcessState.CheckOrderNumber),
|
||||
|
||||
// Precondition: - All checks have to be executed with positive result
|
||||
new ProcessStateStruct(
|
||||
productionProcess: new CheckAttachments(Resources.StrStateCheckAttachments),
|
||||
processState: ProcessState.CheckAttachments,
|
||||
processInfo: Resources.StrStateCheckAttachments,
|
||||
productionProcessNo:13,
|
||||
nextStateOnSuccess: ProcessState.ExecVisualInspection),
|
||||
|
||||
// Precondition: - All checks have to be executed with positive result
|
||||
new ProcessStateStruct(
|
||||
productionProcess: new VisualInspection(Resources.StrStateVisualInspection),
|
||||
processState: ProcessState.ExecVisualInspection,
|
||||
processInfo: Resources.StrStateVisualInspection,
|
||||
productionProcessNo:14,
|
||||
nextStateOnSuccess: ProcessState.PrepareShippingMode),
|
||||
|
||||
// Precondition: - All checks have to be executed with positive result
|
||||
new ProcessStateStruct(
|
||||
productionProcess: new PrepareShipping(Resources.StrStatePrepareShipping),
|
||||
processState: ProcessState.PrepareShippingMode,
|
||||
processInfo: Resources.StrStatePrepareShipping,
|
||||
productionProcessNo:15,
|
||||
nextStateOnSuccess: ProcessState.ReadyForShipping),
|
||||
|
||||
new ProcessStateStruct(
|
||||
productionProcess: null,
|
||||
processState:ProcessState.ReadyForShipping,
|
||||
processInfo:Resources.StrStateReadyForShipping,
|
||||
productionProcessNo:null,
|
||||
nextStateOnSuccess:ProcessState.Idle),
|
||||
#endregion -------------------------------- EOL-STATES ------------------------------------------------
|
||||
|
||||
};
|
||||
StateContainer.AddRange(stateContainer);
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -10,7 +10,7 @@ using Xylem.Common.Hardware.WaterMeter.Genesis.Registers;
|
||||
using Xylem.Common.Logic.ProductionOrderCore;
|
||||
using Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.Enum;
|
||||
using Xylem.Common.Production.ProductionUiCordonel.Properties;
|
||||
using Xylem.Common.Production.ProductionUiCordonel.UserControls.FinalTest;
|
||||
using Xylem.Common.Production.ProductionUiCordonel.UserControls;
|
||||
|
||||
//using Xylem.Common.Ui.ProductionUiCordonel.UserControls.FinalTest;
|
||||
|
||||
@@ -66,7 +66,7 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.EolPr
|
||||
/// <remarks date="2023-Jul-11" author="Thomas Wiedebusch">
|
||||
/// - Speed up to quick return if passwords are already set.
|
||||
///
|
||||
/// ATTENTION: This requires to remove those on new PcbId <see cref="FinalProcessController"/>
|
||||
/// ATTENTION: This requires to remove those on new PcbId <see cref="ProcessController"/>
|
||||
/// for CheckMeterChange!
|
||||
///
|
||||
/// </remarks>
|
||||
|
||||
+2
-1
@@ -7,6 +7,7 @@ using Xylem.Common.CommonCore.Consts;
|
||||
using Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore;
|
||||
using Xylem.Common.Hardware.WaterMeter.Genesis.Registers;
|
||||
using Xylem.Common.Logic.SoftwareAccessHelper;
|
||||
using Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.GenericProcesses;
|
||||
using Xylem.Common.Production.ProductionUiCordonel.Properties;
|
||||
|
||||
namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.EolProcesses
|
||||
@@ -38,7 +39,7 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.EolPr
|
||||
/// <remarks date="2023-Jul-11" author="Thomas Wiedebusch">
|
||||
/// - Speed up to quick return if programming parameters are already set.
|
||||
///
|
||||
/// ATTENTION: This requires to remove those on new PcbId <see cref="FinalProcessController"/>
|
||||
/// ATTENTION: This requires to remove those on new PcbId <see cref="ProcessController"/>
|
||||
/// for CheckMeterChange!
|
||||
/// </remarks>
|
||||
/// <remarks date="2023-Jul-19" author="Thomas Wiedebusch">
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@ using Xylem.Common.CommonCore.Consts;
|
||||
using Xylem.Common.Production.ProductionUiCordonel.Model;
|
||||
using Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.Enum;
|
||||
using Xylem.Common.Production.ProductionUiCordonel.Properties;
|
||||
using Xylem.Common.Production.ProductionUiCordonel.UserControls.FinalTest;
|
||||
using Xylem.Common.Production.ProductionUiCordonel.UserControls;
|
||||
|
||||
namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.EolProcesses
|
||||
{
|
||||
|
||||
-192
@@ -1,192 +0,0 @@
|
||||
using Newtonsoft.Json;
|
||||
using ProductionUiCordonel.ProductionProcesses.Enum;
|
||||
using ProductionUiCordonel.UserControls.FinalTest;
|
||||
using System;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Threading;
|
||||
using Xylem.Common.CommonCore.Configuration;
|
||||
using Xylem.Common.Hardware.WaterMeter.Genesis.GenesisStatus;
|
||||
using Xylem.Common.Logic.SoftwareAccessHelper;
|
||||
|
||||
namespace ProductionUiCordonel.ProductionProcesses.Actions
|
||||
{
|
||||
public class ProductionCheckShippingState : BaseProductionProcess
|
||||
{
|
||||
private UcPlain UserControl;
|
||||
public ProductionCheckShippingState()
|
||||
{
|
||||
name = "Prüfe versandbereitschaft des Zählers";
|
||||
currentProcessState = ProductionProcessState.Waiting;
|
||||
}
|
||||
public override void InitUserControl()
|
||||
{
|
||||
UserControl = new UcPlain();
|
||||
UserControl.lblHl.Content = name;
|
||||
UserControl.lblText.Content = "Hydraulisch geprüft? Batterie i.O?";
|
||||
}
|
||||
|
||||
public override UserControl GetControl()
|
||||
{
|
||||
if (UserControl == null)
|
||||
{
|
||||
throw new Exception($"UserControl {GetType()} not Ready");
|
||||
}
|
||||
return UserControl;
|
||||
}
|
||||
|
||||
|
||||
public override void ProcessDone()
|
||||
{
|
||||
//clear
|
||||
}
|
||||
|
||||
|
||||
private void doStartProcessLoop()
|
||||
{
|
||||
var retriesRemaining = 1;
|
||||
while (retriesRemaining >= 0)
|
||||
{
|
||||
try
|
||||
{
|
||||
Progress = 0;
|
||||
//var url = $"http://localhost:56011/api/FinalCheck/GetProgrammingParameters?PcbID={Meter.PcbId}";
|
||||
var url = $"{ServiceUrls.MeterInfoForTestBench()}{Meter.PcbId}";
|
||||
var csdRet = LocalWebRequest.GetRequest(url);
|
||||
|
||||
var res = JsonConvert.DeserializeObject<String[]>(csdRet);
|
||||
|
||||
var CalibrationRun = res[4];
|
||||
var LastTestBechState = 0;
|
||||
Boolean? HyState;
|
||||
Boolean? preState = null;
|
||||
if (!string.IsNullOrEmpty(res[5]))
|
||||
{
|
||||
int.TryParse(res[5], out var tmp);
|
||||
LastTestBechState = tmp;
|
||||
}
|
||||
|
||||
if (LastTestBechState <= 20)
|
||||
{
|
||||
HyState = null;
|
||||
}
|
||||
else if (LastTestBechState <= 30)
|
||||
{
|
||||
HyState = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
HyState = false;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(CalibrationRun))
|
||||
{
|
||||
preState = true;
|
||||
}
|
||||
|
||||
|
||||
if (!HyState.HasValue || !HyState.Value)
|
||||
{
|
||||
UserControl.lblText.Dispatcher.Invoke(DispatcherPriority.Send,
|
||||
new Action(() =>
|
||||
{
|
||||
UserControl.lblText.Content = "Zähler nicht erfolgreich geprüft";
|
||||
}
|
||||
));
|
||||
|
||||
currentProcessState = ProductionProcessState.Error;
|
||||
}
|
||||
if (!preState.HasValue || !preState.Value)
|
||||
{
|
||||
UserControl.lblText.Dispatcher.Invoke(DispatcherPriority.Send,
|
||||
new Action(() =>
|
||||
{
|
||||
UserControl.lblText.Content = "Zähler nicht erfolgreich vorbehandelt";
|
||||
}
|
||||
));
|
||||
currentProcessState = ProductionProcessState.Error;
|
||||
}
|
||||
|
||||
Progress = 50;
|
||||
|
||||
var genesisStatus = new GenesisStatus();
|
||||
|
||||
// this calculates all life time values
|
||||
if (!GenesisStatusHandler.BuildLifeTimeInformation(Meter, genesisStatus))
|
||||
{
|
||||
|
||||
UserControl.lblText.Dispatcher.Invoke(DispatcherPriority.Send,
|
||||
new Action(() =>
|
||||
{
|
||||
UserControl.lblText.Content = "Batterie nicht lesbar";
|
||||
}
|
||||
));
|
||||
Meter.WriteLog("Batterie nicht lesbar");
|
||||
break;
|
||||
}
|
||||
|
||||
//lastFrame
|
||||
Meter.WriteLog($"totalUsed at EOL {genesisStatus.DrainedBatteryLoadPercent:F2}");
|
||||
if (res[1] == "3212095")
|
||||
{
|
||||
currentProcessState = ProductionProcessState.Done;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (genesisStatus.RemainingLifeTimeYears < 20)
|
||||
{
|
||||
if (genesisStatus.DrainedBatteryLoadPercent > 8)
|
||||
{
|
||||
currentProcessState = ProductionProcessState.Error;
|
||||
UserControl.lblText.Content = "Batterie über 10% entladen";
|
||||
Meter.WriteLog("Batterie über 10% entladen");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
try
|
||||
{
|
||||
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
|
||||
throw;
|
||||
}
|
||||
//;
|
||||
if (Meter.LutCrc != $@"0x{int.Parse(res[8]):X4}")
|
||||
{
|
||||
currentProcessState = ProductionProcessState.Error;
|
||||
UserControl.lblText.Content = "Lut not correct";
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (currentProcessState != ProductionProcessState.Error)
|
||||
{
|
||||
currentProcessState = ProductionProcessState.Done;
|
||||
return;
|
||||
}
|
||||
retriesRemaining -= 1;
|
||||
|
||||
currentProcessState = ProductionProcessState.Error;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Meter.WriteLog($"{ex}");
|
||||
currentProcessState = ProductionProcessState.Error;
|
||||
retriesRemaining -= 1;
|
||||
}
|
||||
}
|
||||
currentProcessState = ProductionProcessState.Error;
|
||||
}
|
||||
|
||||
public override void StartProcess()
|
||||
{
|
||||
doStartProcessLoop();
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
-143
@@ -1,143 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Windows.Controls;
|
||||
using ProductionUiCordonel.ProductionProcesses.Enum;
|
||||
using ProductionUiCordonel.UserControls.FinalTest;
|
||||
|
||||
namespace ProductionUiCordonel.ProductionProcesses.Actions
|
||||
{
|
||||
public class ProductionProcessDone : BaseProductionProcess
|
||||
{
|
||||
public event EventHandler<Tuple<Boolean,Boolean, Boolean>> isDone;
|
||||
private UcDialog UserControl;
|
||||
public DialogResult Result = DialogResult.None;
|
||||
public enum DialogResult
|
||||
{
|
||||
None,
|
||||
Retry,
|
||||
Print,
|
||||
Abort
|
||||
}
|
||||
public Boolean DialogIsDone { get; }
|
||||
private Boolean Error;
|
||||
public ProductionProcessDone(Boolean error = false)
|
||||
{
|
||||
Error = error;
|
||||
DialogIsDone = false;
|
||||
name = "Fertig";
|
||||
currentProcessState = ProductionProcessState.Waiting;
|
||||
}
|
||||
public override void InitUserControl()
|
||||
{
|
||||
UserControl = new UcDialog();
|
||||
}
|
||||
|
||||
public override UserControl GetControl()
|
||||
{
|
||||
if (UserControl == null)
|
||||
{
|
||||
throw new Exception($"UserControl {GetType()} not Ready");
|
||||
}
|
||||
return UserControl;
|
||||
}
|
||||
|
||||
|
||||
public override void ProcessDone()
|
||||
{
|
||||
//clear
|
||||
}
|
||||
|
||||
private void StepDone()
|
||||
{
|
||||
currentProcessState = ProductionProcessState.Done;
|
||||
var retry = false;
|
||||
var abort = false;
|
||||
var print = false;
|
||||
if (Error)
|
||||
{
|
||||
switch (Result)
|
||||
{
|
||||
|
||||
case DialogResult.Retry:
|
||||
retry = true;
|
||||
break;
|
||||
case DialogResult.Print:
|
||||
abort = true;
|
||||
print = true;
|
||||
break;
|
||||
case DialogResult.Abort:
|
||||
abort = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
isDone?.Invoke(null, new Tuple<Boolean, Boolean,Boolean>(retry, abort, print));
|
||||
}
|
||||
|
||||
private void StepError(String ErrorText = "Ein Fehler ist aufgetreten")
|
||||
{
|
||||
|
||||
UserControl.SetDesc(ErrorText);
|
||||
var errorOptionList = new List<UcDialog.DialogOption>();
|
||||
var retry = new UcDialog.DialogOption("Wiederholen", "Alle Schritte werden wiederholt", () =>
|
||||
{
|
||||
Result = DialogResult.Retry;
|
||||
StepDone();
|
||||
|
||||
});
|
||||
|
||||
var Abort = new UcDialog.DialogOption("Abbruch", "Diesen Zähler NICHT verpacken", () =>
|
||||
{
|
||||
Result = DialogResult.Abort;
|
||||
StepDone();
|
||||
|
||||
});
|
||||
var print = new UcDialog.DialogOption("Rückläuferschein drucken", "Rückläuferschein beim Zähler lassen und auf Klärung durch QS warten", () =>
|
||||
{
|
||||
Result = DialogResult.Print;
|
||||
StepDone();
|
||||
|
||||
});
|
||||
|
||||
|
||||
errorOptionList.Add(retry);
|
||||
errorOptionList.Add(Abort);
|
||||
errorOptionList.Add(print);
|
||||
|
||||
UserControl.SetDialogOptions(errorOptionList);
|
||||
}
|
||||
|
||||
private void StepSuccsess()
|
||||
{
|
||||
|
||||
UserControl.SetDesc("Zähler verpacken");
|
||||
var OptionList = new List<UcDialog.DialogOption>();
|
||||
var retry = new UcDialog.DialogOption("Ok", "", () =>
|
||||
{
|
||||
Result = DialogResult.None;
|
||||
StepDone();
|
||||
|
||||
});
|
||||
|
||||
|
||||
OptionList.Add(retry);
|
||||
|
||||
UserControl.SetDialogOptions(OptionList);
|
||||
}
|
||||
|
||||
public override void StartProcess()
|
||||
{
|
||||
if (Error)
|
||||
{
|
||||
StepError();
|
||||
}
|
||||
else
|
||||
{
|
||||
StepSuccsess();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
-364
@@ -1,364 +0,0 @@
|
||||
using Newtonsoft.Json;
|
||||
using ProductionUiCordonel.ProductionProcesses.Enum;
|
||||
using ProductionUiCordonel.UserControls.FinalTest;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Controls;
|
||||
using Xylem.Common.CommonCore.Configuration;
|
||||
using Xylem.Common.Hardware.WaterMeter.Genesis.DataPackages;
|
||||
using Xylem.Common.Hardware.WaterMeter.Genesis.Registers;
|
||||
|
||||
namespace ProductionUiCordonel.ProductionProcesses.Actions
|
||||
{
|
||||
public class ProductionProcessFinalParameterization : BaseProductionProcess
|
||||
{
|
||||
private UcPlain UserControl;
|
||||
public ProductionProcessFinalParameterization()
|
||||
{
|
||||
name = "Final Parameterization";
|
||||
currentProcessState = ProductionProcessState.Waiting;
|
||||
}
|
||||
public override void InitUserControl()
|
||||
{
|
||||
UserControl = new UcPlain();
|
||||
}
|
||||
|
||||
public override UserControl GetControl()
|
||||
{
|
||||
if (UserControl == null)
|
||||
{
|
||||
throw new Exception($"UserControl {this.GetType()} not Ready");
|
||||
}
|
||||
return UserControl;
|
||||
}
|
||||
|
||||
|
||||
public override void ProcessDone()
|
||||
{
|
||||
//clear
|
||||
}
|
||||
|
||||
public Task<Tuple<String, Boolean>> _currentGenesis_WriteRegister<T>(String reg, T value, Boolean waitForResult = true,
|
||||
Boolean checkRegister = false)
|
||||
{
|
||||
return new Task<Tuple<String, Boolean>>(() =>
|
||||
{
|
||||
|
||||
var ret = Meter.WriteRegister(reg, value, waitForResult, checkRegister);
|
||||
if (!ret)
|
||||
{
|
||||
ret = Meter.WriteRegister(reg, value, waitForResult, checkRegister);
|
||||
}
|
||||
return new Tuple<String, Boolean>(reg, ret);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
public Task<Tuple<String, Boolean>> wirteRegisterInBetweenCheck(String reg, Int32 value, Boolean waitForResult = true,
|
||||
Boolean checkRegister = false, int addToCheck = 10, int addFromCheck = 0)
|
||||
{
|
||||
return new Task<Tuple<String, Boolean>>(() =>
|
||||
{
|
||||
Meter.WriteRegister(reg, value, waitForResult);
|
||||
|
||||
var accucalValue = RegisterConverter.ConvertTo<Int32>(Meter.ReadRegister(reg));
|
||||
if (accucalValue >= (value + addFromCheck) && value <= accucalValue + (addToCheck))
|
||||
{
|
||||
return new Tuple<String, Boolean>(reg, true);
|
||||
}
|
||||
return new Tuple<String, Boolean>(reg, false);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
public override void StartProcess()
|
||||
{
|
||||
|
||||
|
||||
base.Progress = 0;
|
||||
|
||||
var useRadio = true;
|
||||
var radioParams = new RadioConfigurationParams();
|
||||
if (useRadio)
|
||||
{
|
||||
|
||||
|
||||
|
||||
var url = ServiceUrls.GenesisFinalCheckServiceUrl();
|
||||
url = url + $"GetRadioConfiguration?PcbId={Meter.PcbId}";
|
||||
|
||||
|
||||
var http = (HttpWebRequest)WebRequest.Create(url);
|
||||
http.Method = "GET";
|
||||
http.Timeout = 2000;
|
||||
var response = (HttpWebResponse)http.GetResponse();
|
||||
var responseStream = response.GetResponseStream();
|
||||
if (responseStream == null)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
using (var sr = new StreamReader(responseStream))
|
||||
{
|
||||
var responseJson = sr.ReadToEnd();
|
||||
radioParams = JsonConvert.DeserializeObject<RadioConfigurationParams>(responseJson);
|
||||
}
|
||||
}
|
||||
base.Progress = 20;
|
||||
|
||||
|
||||
|
||||
|
||||
var overAllResult = new List<Task<Tuple<String, Boolean>>>();
|
||||
//611.219.280
|
||||
//
|
||||
var ts = DateTimeOffset.UtcNow - new DateTimeOffset(2000, 1, 1, 0, 0, 0, new TimeSpan(0));
|
||||
|
||||
//Alarms
|
||||
////_currentGenesis.WriteRegister("SENSUSRADIO_MainAlarmMask?
|
||||
////_currentGenesis.WriteRegister("SENSUSRADIO_ExtendedAlarmMask ?
|
||||
//CUSTOMER_AlarmBroadcastMask?
|
||||
//CUSTOMER_AlarmEnableMask ?
|
||||
//CUSTOMER_AlarmVisualAutoClearMask?
|
||||
//CUSTOMER_AlarmVisualMask ?
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("GENESISFLOW_SealDisplay",
|
||||
(new Byte[] { 0x00, 0x00, 0x00, 0x00 }).Reverse().ToArray(), true, true));
|
||||
//Meter.SetLcdText(true, null);
|
||||
//overAllResult.Add(_currentGenesis_WriteRegister(Register.Customer.TriggerAlarmCancel,
|
||||
// (new Byte[] { 0xFF, 0xFF, 0xFF, 0xFF }).Reverse().ToArray(), true, false));
|
||||
|
||||
|
||||
|
||||
overAllResult.Add(wirteRegisterInBetweenCheck("CUSTOMER_LeakFlowThreshold", 375, true, true, 1, -1));
|
||||
overAllResult.Add(wirteRegisterInBetweenCheck("CUSTOMER_ExcessFlowVolumeThreshold", 25000, true, true, 1, -1));
|
||||
|
||||
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("CUSTOMER_ExcessFlowTimeThreshold",
|
||||
(new Byte[] { 0x00, 0x00, 0x00, 0x05 }).Reverse().ToArray(), true, true));
|
||||
|
||||
|
||||
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("CUSTOMER_LeakTimeThreshold",
|
||||
(new Byte[] { 0x00, 0x00, 0x4E, 0xC0 }).Reverse().ToArray(), true, true));
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("CUSTOMER_Locale",
|
||||
(new Byte[] { 0x00, 0x00, 0x00, 0xD0 }).Reverse().ToArray(), true, true));
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("CUSTOMER_PressureHighDelay",
|
||||
(new Byte[] { 0x00, 0x00, 0x02, 0x58 }).Reverse().ToArray(), true, true));
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("CUSTOMER_PressureHighThreshold",
|
||||
(new Byte[] { 0x00, 0x0B, 0x71, 0xB0 }).Reverse().ToArray(), true, true));
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("CUSTOMER_PressureLowDelay",
|
||||
(new Byte[] { 0x00, 0x00, 0x02, 0x58 }).Reverse().ToArray(), true, true));
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("CUSTOMER_PressureLowThreshold",
|
||||
(new Byte[] { 0x00, 0x00, 0x75, 0x30 }).Reverse().ToArray(), true, true));
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("CUSTOMER_ReverseFlowTimeThreshold",
|
||||
(new Byte[] { 0x00, 0x00, 0x00, 0x78 }).Reverse().ToArray(), true, true));
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("CUSTOMER_TemperatureHighDelay",
|
||||
(new Byte[] { 0x00, 0x00, 0x01, 0x2C }).Reverse().ToArray(), true, true));
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("CUSTOMER_TemperatureHighThreshold",
|
||||
(new Byte[] { 0x00, 0x00, 0x01, 0xF4 }).Reverse().ToArray(), true, true));
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("CUSTOMER_TemperatureLowDelay",
|
||||
(new Byte[] { 0x00, 0x00, 0x01, 0x2C }).Reverse().ToArray(), true, true));
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("CUSTOMER_TemperatureLowThreshold",
|
||||
(new Byte[] { 0x00, 0x00, 0x00, 0x14 }).Reverse().ToArray(), true, true));
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("GENESISFLOW_ArrowThreshold",
|
||||
(new Byte[] { 0x00, 0x1E, 0x84, 0x80 }).Reverse().ToArray(), true, true));
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("GENESISFLOW_DisplayPow10",
|
||||
(new Byte[] { 0x00, 0x00, 0x00, 0xFD }).Reverse().ToArray(), true, true));
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("GENESISFLOW_DisplayUnits",
|
||||
(new Byte[] { 0x00, 0x00, 0x00, 0x00 }).Reverse().ToArray(), true, true));
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("GENESISFLOW_ForwardArrow",
|
||||
(new Byte[] { 0x00, 0x00, 0x00, 0x00 }).Reverse().ToArray(), true, true));
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("GENESISFLOW_HardErrorLimit",
|
||||
(new Byte[] { 0x00, 0x00, 0x00, 0x04 }).Reverse().ToArray(), true, true));
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("GENESISFLOW_LedMode",
|
||||
(new Byte[] { 0x00, 0x00, 0x00, 0x00 }).Reverse().ToArray(), true, true));
|
||||
//overAllResult.Add(_currentGenesis_WriteRegister("GENESISFLOW_LowFlowMaxPeriod", (new Byte[] { 0x00, 0x00, 0x00, 0x3C }).Reverse().ToArray(), true, true));
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("GENESISFLOW_LowFlowMaxPeriod", 60 << 16, true, true));
|
||||
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("GENESISFLOW_LowFlowThreshold",
|
||||
(new Byte[] { 0x00, 0x00, 0x00, 0xC8 }).Reverse().ToArray(), true, true));
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("GENESISFLOW_MeterSize",
|
||||
(new Byte[] { 0x00, 0x00, 0x00, 0x01 }).Reverse().ToArray(), true, true));
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("GENESISFLOW_PipeFillingDelay",
|
||||
(new Byte[] { 0x00, 0x00, 0x00, 0x1E }).Reverse().ToArray(), true, true));
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("GENESISFLOW_ResetAccumulators",
|
||||
(new Byte[] { 0x00, 0x00, 0x00, 0x01 }).Reverse().ToArray(), true, false));
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("GENESISFLOW_SampleRate",
|
||||
(new Byte[] { 0x00, 0x00, 0x00, 0x02 }).Reverse().ToArray(), true, true));
|
||||
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("GENESISFLOW_UpdateThreshold",
|
||||
(new Byte[] { 0x00, 0x00, 0x00, 0x00 }).Reverse().ToArray(), true, true));
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("IRDA_AdapterPresenceLimit",
|
||||
(new Byte[] { 0x00, 0x00, 0x00, 0x60 }).Reverse().ToArray(), true, true));
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("IRDA_PulseReportRate",
|
||||
(new Byte[] { 0x00, 0x00, 0x00, 0x00 }).Reverse().ToArray(), true, true));
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("METROLOGYASST_FlowPoint",
|
||||
(new Byte[] { 0x00, 0x00, 0x00, 0x02 }).Reverse().ToArray(), true, true));
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("METROLOGYASST_FlowUnits",
|
||||
(new Byte[] { 0x00, 0x00, 0x00, 0x04 }).Reverse().ToArray(), true, true));
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("METROLOGYASST_PressureOffset",
|
||||
(new Byte[] { 0x00, 0x00, 0x03, 0xF5 }).Reverse().ToArray(), true, true));
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("METROLOGYASST_PressurePresent",
|
||||
(new Byte[] { 0x00, 0x00, 0x00, 0x00 }).Reverse().ToArray(), true, true));
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("METROLOGYASST_PressureRate",
|
||||
(new Byte[] { 0x00, 0x0D, 0xBB, 0xA0 }).Reverse().ToArray(), true, true));
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("METROLOGYASST_PressureUnits",
|
||||
(new Byte[] { 0x00, 0x00, 0x00, 0x00 }).Reverse().ToArray(), true, true));
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("METROLOGYASST_PulseLength",
|
||||
(new Byte[] { 0x00, 0x00, 0x00, 0x07 }).Reverse().ToArray(), true, true));
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("METROLOGYASST_PulseMode",
|
||||
(new Byte[] { 0x00, 0x00, 0x00, 0x01 }).Reverse().ToArray(), true, true));
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("METROLOGYASST_PulseWeight",
|
||||
(new Byte[] { 0x00, 0x00, 0x27, 0x10 }).Reverse().ToArray(), true, true));
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("METROLOGYASST_TemperatureUnits",
|
||||
(new Byte[] { 0x00, 0x00, 0x00, 0x00 }).Reverse().ToArray(), true, true));
|
||||
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("PERIODICLOG_AverageFlowPeriod",
|
||||
(new Byte[] { 0x00, 0x00, 0x00, 0x05 }).Reverse().ToArray(), true, true));
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("PERIODICLOG_DataLogContents",
|
||||
(new Byte[] { 0x0C, 0x00, 0x24, 0x03 }).Reverse().ToArray(), true, false));
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("PERIODICLOG_DataLogPeriod",
|
||||
(new Byte[] { 0x00, 0x00, 0x00, 0x3C }).Reverse().ToArray(), true, false));
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("PERIODICLOG_FixedDateDayOfMonth",
|
||||
(new Byte[] { 0x00, 0x00, 0x00, 0x01 }).Reverse().ToArray(), true, false));
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("PERIODICLOG_FixedDateReadingContents",
|
||||
(new Byte[] { 0x0C, 0x00, 0x24, 0x03 }).Reverse().ToArray(), true, false));
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("PERIODICLOG_PeriodicLogLifeTimeCounter",
|
||||
(new Byte[] { 0x00, 0x00, 0x00, 0x0 }).Reverse().ToArray(), true, false));
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("PERIODICLOG_ResetCounter",
|
||||
(new Byte[] { 0x00, 0x00, 0x00, 0x0 }).Reverse().ToArray(), true, true));
|
||||
|
||||
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("POWERMON_BatterySelection",
|
||||
(new Byte[] { 0x00, 0x00, 0x00, 0x00 }).Reverse().ToArray(), true, false));
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("POWERMON_WarnFromClamp",
|
||||
(new Byte[] { 0x25, 0x89, 0x06, 0x00 }).Reverse().ToArray(), true, true));
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("SENSUSRADIO_WakeupInterval",
|
||||
(new Byte[] { 0x00, 0x00, 0x00, 0x03 }).Reverse().ToArray(), true, true));
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("SENSUSRADIO_MbusState",
|
||||
(new Byte[] { 0x00, 0x00, 0x00, 0x07 }).Reverse().ToArray(), true, true));
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("SENSUSRADIO_UtcTimeOffset",
|
||||
(new Byte[] { 0x00, 0x00, 0x00, 0x00 }).Reverse().ToArray(), true, true));
|
||||
|
||||
//// just read later //overAllResult.Add(_currentGenesis_WriteRegister("SENSUSRADIO_FrequencyIndicator}).Reverse(), true, true);
|
||||
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("SENSUSRADIO_HistoricalAlarmsDays",
|
||||
(new Byte[] { 0x00, 0x00, 0x00, 0x1D }).Reverse().ToArray(), true, true));
|
||||
|
||||
|
||||
//Original
|
||||
//0x11, 0x12, 0x13, 0x14, 0x21, 0x22, 0x23, 0x24, 0x31, 0x32, 0x33, 0x34, 0x41, 0x42, 0x43, 0x44
|
||||
//Write to register
|
||||
//0x14, 0x13, 0x12, 0x11, 0x24, 0x23, 0x22, 0x21, 0x34, 0x33, 0x32, 0x31, 0x44, 0x43, 0x42, 0x41
|
||||
|
||||
|
||||
//good one
|
||||
//E6-C8-88-00-DE-B8-68-C0-D6-A8-48-80-CE-98-28-40
|
||||
//0E-05-04-04-00-14-30-68-D0-14-0E-80-40-63-93-73-22
|
||||
|
||||
//&bad one
|
||||
//0E-05-04-05-00-00-88-C8-E6-C0-68-B8-DE-80-48-A8-D6-40-28-98-CE
|
||||
|
||||
|
||||
//0E-05-04-04-00-22-73-93-63-40-80-0E-14-D0-68-30-14
|
||||
|
||||
if (useRadio)
|
||||
{
|
||||
|
||||
|
||||
//var funkadresse = new List<byte>();
|
||||
//funkadresse.AddRange((new Byte[] { 0xE6, 0xC8, 0x88, 0x00 }).ToArray());
|
||||
//funkadresse.AddRange((new Byte[] { 0xDE, 0xB8, 0x68, 0xC0 }).ToArray());
|
||||
//funkadresse.AddRange((new Byte[] { 0xD6, 0xA8, 0x48, 0x80 }).ToArray());
|
||||
//funkadresse.AddRange((new Byte[] { 0xCE, 0x98, 0x28, 0x40 }).ToArray());
|
||||
//overAllResult.Add(_currentGenesis_WriteRegister("SENSUSRADIO_EncryptionKey", funkadresse.ToArray(),
|
||||
// true, true));
|
||||
|
||||
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("SENSUSRADIO_EncryptionKey",
|
||||
(new Byte[]
|
||||
{
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
}).ToArray(), true, true));
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("SENSUSRADIO_RadioAddress", radioParams.RadioAddress, true, true));
|
||||
|
||||
if (radioParams.PowerLevel > 0 && radioParams.PowerLevelOption > 0 && radioParams.ImpedanceCodeNew > 0 && radioParams.ImpedanceCodeOption > 0)
|
||||
{
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("SENSUSRADIO_PowerLevel", radioParams.PowerLevel, true, true));
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("SENSUSRADIO_PowerLevelOption", radioParams.PowerLevelOption, true, true));
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("SENSUSRADIO_ImpedanceCodeNew", radioParams.ImpedanceCodeNew, true, true));
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("SENSUSRADIO_ImpedanceCodeOption", radioParams.ImpedanceCodeOption, true, true));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
base.currentProcessState = ProductionProcessState.Error;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//_currentGenesis_WriteRegister("SENSUSRADIO_CustomerText",
|
||||
// (new Byte[] { 0x00, 0x00, 0x00, 0x00 }).Reverse().ToArray(), true, false);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
overAllResult.Add(wirteRegisterInBetweenCheck("SYSTEM_CalendarSeconds", Convert.ToInt32(ts.TotalSeconds)));
|
||||
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("GENESISFLOW_SealDisplay",
|
||||
(new Byte[] { 0x00, 0x00, 0x00, 0x01 }).Reverse().ToArray(), true, true));
|
||||
|
||||
////radio end state!
|
||||
//overAllResult.Add(_currentGenesis_WriteRegister("SENSUSRADIO_SystemState",
|
||||
// (new Byte[] { 0x00, 0x00, 0x00, 0xFF }).Reverse().ToArray(), true, false));
|
||||
|
||||
//overAllResult.Add(_currentGenesis_WriteRegister("SENSUSRADIO_SystemState",
|
||||
// (new Byte[] { 0x00, 0x00, 0x00, 0x02 }).Reverse().ToArray(), true, true));
|
||||
|
||||
|
||||
|
||||
var ret = true;
|
||||
int done = 0;
|
||||
foreach (var cTask in overAllResult)
|
||||
{
|
||||
cTask.RunSynchronously();
|
||||
if (cTask.Result.Item2)
|
||||
{
|
||||
base.NewStatus($"set Parameter {cTask.Result.Item1} succeed");
|
||||
}
|
||||
else
|
||||
{
|
||||
base.NewStatus($"set Parameter {cTask.Result.Item1} failed");
|
||||
ret = false;
|
||||
break;
|
||||
}
|
||||
|
||||
base.Progress = 20 + ((Int32)Math.Round(((Double)done / (Double)overAllResult.Count) * 80, 0));
|
||||
done = done + 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (!ret)
|
||||
{
|
||||
base.currentProcessState = ProductionProcessState.Error;
|
||||
}
|
||||
else
|
||||
{
|
||||
currentProcessState = ProductionProcessState.Done;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
-355
@@ -1,355 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Controls;
|
||||
using Newtonsoft.Json;
|
||||
using ProductionUiCordonel.ProductionProcesses.Enum;
|
||||
using ProductionUiCordonel.UserControls.FinalTest;
|
||||
using Xylem.Common.Hardware.WaterMeter.Genesis.DataPackages;
|
||||
using Xylem.Common.Hardware.WaterMeter.Genesis.Registers;
|
||||
|
||||
namespace ProductionUiCordonel.ProductionProcesses.Actions
|
||||
{
|
||||
public class ProductionProcessFinalParametrizationFix : BaseProductionProcess
|
||||
{
|
||||
private UcPlain UserControl;
|
||||
public ProductionProcessFinalParametrizationFix()
|
||||
{
|
||||
name = "Final Parametrization";
|
||||
currentProcessState = ProductionProcessState.Waiting;
|
||||
}
|
||||
public override void InitUserControl()
|
||||
{
|
||||
UserControl = new UcPlain();
|
||||
}
|
||||
|
||||
public override UserControl GetControl()
|
||||
{
|
||||
if (UserControl == null)
|
||||
{
|
||||
throw new Exception($"UserControl {GetType()} not Ready");
|
||||
}
|
||||
return UserControl;
|
||||
}
|
||||
|
||||
|
||||
public override void ProcessDone()
|
||||
{
|
||||
//clear
|
||||
}
|
||||
|
||||
public Task<Tuple<String, Boolean>> _currentGenesis_WriteRegister<T>(String reg, T value, Boolean waitForResult = true,
|
||||
Boolean checkRegister = false)
|
||||
{
|
||||
return new Task<Tuple<String, Boolean>>(() =>
|
||||
{
|
||||
|
||||
var ret = Meter.WriteRegister(reg, value, waitForResult, checkRegister);
|
||||
if (!ret)
|
||||
{
|
||||
ret = Meter.WriteRegister(reg, value, waitForResult, checkRegister);
|
||||
}
|
||||
return new Tuple<String, Boolean>(reg, ret);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
public Task<Tuple<String, Boolean>> wirteRegisterInBetweenCheck(String reg, Int32 value, Boolean waitForResult = true,
|
||||
Boolean checkRegister = false, Int32 addToCheck = 10, Int32 addFromCheck = 0)
|
||||
{
|
||||
return new Task<Tuple<String, Boolean>>(() =>
|
||||
{
|
||||
Meter.WriteRegister(reg, value, waitForResult);
|
||||
|
||||
var accucalValue = RegisterConverter.ConvertTo<Int32>(Meter.ReadRegister(reg));
|
||||
if (accucalValue >= (value + addFromCheck) && value <= accucalValue + (addToCheck))
|
||||
{
|
||||
return new Tuple<String, Boolean>(reg, true);
|
||||
}
|
||||
return new Tuple<String, Boolean>(reg, false);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
public override void StartProcess()
|
||||
{
|
||||
Progress = 0;
|
||||
|
||||
RadioConfigurationParams radioParams;
|
||||
{
|
||||
var url = "http://localhost:56011/api/FinalCheck/";
|
||||
url += $"GetRadioConfiguration?PcbId={Meter.PcbId}&withPressure=false";
|
||||
|
||||
var http = (HttpWebRequest)WebRequest.Create(url);
|
||||
http.Method = "GET";
|
||||
http.Timeout = 20000;
|
||||
var response = (HttpWebResponse)http.GetResponse();
|
||||
var responseStream = response.GetResponseStream();
|
||||
if (responseStream == null)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
using (var sr = new StreamReader(responseStream))
|
||||
{
|
||||
var responseJson = sr.ReadToEnd();
|
||||
radioParams = JsonConvert.DeserializeObject<RadioConfigurationParams>(responseJson);
|
||||
}
|
||||
}
|
||||
Progress = 20;
|
||||
|
||||
|
||||
|
||||
|
||||
var overAllResult = new List<Task<Tuple<String, Boolean>>>();
|
||||
//611.219.280
|
||||
//
|
||||
|
||||
//Alarms
|
||||
////_currentGenesis.WriteRegister("SENSUSRADIO_MainAlarmMask?
|
||||
////_currentGenesis.WriteRegister("SENSUSRADIO_ExtendedAlarmMask ?
|
||||
//CUSTOMER_AlarmBroadcastMask?
|
||||
//CUSTOMER_AlarmEnableMask ?
|
||||
//CUSTOMER_AlarmVisualAutoClearMask?
|
||||
//CUSTOMER_AlarmVisualMask ?
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("GENESISFLOW_SealDisplay",
|
||||
(new Byte[] { 0x00, 0x00, 0x00, 0x00 }).Reverse().ToArray(), true, true));
|
||||
//Meter.SetLcdText(true, null);
|
||||
//overAllResult.Add(_currentGenesis_WriteRegister(Register.Customer.TriggerAlarmCancel,
|
||||
// (new Byte[] { 0xFF, 0xFF, 0xFF, 0xFF }).Reverse().ToArray(), true, false));
|
||||
|
||||
|
||||
|
||||
overAllResult.Add(wirteRegisterInBetweenCheck("CUSTOMER_LeakFlowThreshold", 375, true, true, 1, -1));
|
||||
overAllResult.Add(wirteRegisterInBetweenCheck("CUSTOMER_ExcessFlowVolumeThreshold", 25000, true, true, 1, -1));
|
||||
|
||||
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("CUSTOMER_ExcessFlowTimeThreshold",
|
||||
(new Byte[] { 0x00, 0x00, 0x00, 0x05 }).Reverse().ToArray(), true, true));
|
||||
|
||||
|
||||
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("CUSTOMER_LeakTimeThreshold",
|
||||
(new Byte[] { 0x00, 0x00, 0x4E, 0xC0 }).Reverse().ToArray(), true, true));
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("CUSTOMER_Locale",
|
||||
(new Byte[] { 0x00, 0x00, 0x00, 0xD0 }).Reverse().ToArray(), true, true));
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("CUSTOMER_PressureHighDelay",
|
||||
(new Byte[] { 0x00, 0x00, 0x02, 0x58 }).Reverse().ToArray(), true, true));
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("CUSTOMER_PressureHighThreshold",
|
||||
(new Byte[] { 0x00, 0x0B, 0x71, 0xB0 }).Reverse().ToArray(), true, true));
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("CUSTOMER_PressureLowDelay",
|
||||
(new Byte[] { 0x00, 0x00, 0x02, 0x58 }).Reverse().ToArray(), true, true));
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("CUSTOMER_PressureLowThreshold",
|
||||
(new Byte[] { 0x00, 0x00, 0x75, 0x30 }).Reverse().ToArray(), true, true));
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("CUSTOMER_ReverseFlowTimeThreshold",
|
||||
(new Byte[] { 0x00, 0x00, 0x00, 0x78 }).Reverse().ToArray(), true, true));
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("CUSTOMER_TemperatureHighDelay",
|
||||
(new Byte[] { 0x00, 0x00, 0x01, 0x2C }).Reverse().ToArray(), true, true));
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("CUSTOMER_TemperatureHighThreshold",
|
||||
(new Byte[] { 0x00, 0x00, 0x01, 0xF4 }).Reverse().ToArray(), true, true));
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("CUSTOMER_TemperatureLowDelay",
|
||||
(new Byte[] { 0x00, 0x00, 0x01, 0x2C }).Reverse().ToArray(), true, true));
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("CUSTOMER_TemperatureLowThreshold",
|
||||
(new Byte[] { 0x00, 0x00, 0x00, 0x14 }).Reverse().ToArray(), true, true));
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("GENESISFLOW_ArrowThreshold",
|
||||
(new Byte[] { 0x00, 0x1E, 0x84, 0x80 }).Reverse().ToArray(), true, true));
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("GENESISFLOW_DisplayPow10",
|
||||
(new Byte[] { 0x00, 0x00, 0x00, 0xFD }).Reverse().ToArray(), true, true));
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("GENESISFLOW_DisplayUnits",
|
||||
(new Byte[] { 0x00, 0x00, 0x00, 0x00 }).Reverse().ToArray(), true, true));
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("GENESISFLOW_ForwardArrow",
|
||||
(new Byte[] { 0x00, 0x00, 0x00, 0x00 }).Reverse().ToArray(), true, true));
|
||||
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("GENESISFLOW_HardErrorLimit",
|
||||
(new Byte[] { 0x00, 0x00, 0x00, 0x04 }).Reverse().ToArray(), true, true));
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("GENESISFLOW_LedMode",
|
||||
(new Byte[] { 0x00, 0x00, 0x00, 0x00 }).Reverse().ToArray(), true, true));
|
||||
//overAllResult.Add(_currentGenesis_WriteRegister("GENESISFLOW_LowFlowMaxPeriod", (new Byte[] { 0x00, 0x00, 0x00, 0x3C }).Reverse().ToArray(), true, true));
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("GENESISFLOW_LowFlowMaxPeriod", 60 << 16, true, true));
|
||||
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("GENESISFLOW_LowFlowThreshold",
|
||||
(new Byte[] { 0x00, 0x00, 0x00, 0xC8 }).Reverse().ToArray(), true, true));
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("GENESISFLOW_MeterSize",
|
||||
(new Byte[] { 0x00, 0x00, 0x00, 0x01 }).Reverse().ToArray(), true, true));
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("GENESISFLOW_PipeFillingDelay",
|
||||
(new Byte[] { 0x00, 0x00, 0x00, 0x1E }).Reverse().ToArray(), true, true));
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("GENESISFLOW_ResetAccumulators",
|
||||
(new Byte[] { 0x00, 0x00, 0x00, 0x01 }).Reverse().ToArray()));
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("GENESISFLOW_SampleRate",
|
||||
(new Byte[] { 0x00, 0x00, 0x00, 0x02 }).Reverse().ToArray(), true, true));
|
||||
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("GENESISFLOW_MinValidAmplitude",
|
||||
(new Byte[] { 0x25, 0x80, 0x00, 0x00 }).Reverse().ToArray(), true, true));
|
||||
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("GENESISFLOW_MaxValidDeltaToF",
|
||||
(new Byte[] { 0x00, 0x03, 0xC6, 0x5E }).Reverse().ToArray(), true, true));
|
||||
|
||||
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("GENESISFLOW_UpdateThreshold",
|
||||
(new Byte[] { 0x00, 0x00, 0x00, 0x00 }).Reverse().ToArray(), true, true));
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("IRDA_AdapterPresenceLimit",
|
||||
(new Byte[] { 0x00, 0x00, 0x00, 0x60 }).Reverse().ToArray(), true, true));
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("IRDA_PulseReportRate",
|
||||
(new Byte[] { 0x00, 0x00, 0x00, 0x00 }).Reverse().ToArray(), true, true));
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("METROLOGYASST_FlowPoint",
|
||||
(new Byte[] { 0x00, 0x00, 0x00, 0x02 }).Reverse().ToArray(), true, true));
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("METROLOGYASST_FlowUnits",
|
||||
(new Byte[] { 0x00, 0x00, 0x00, 0x04 }).Reverse().ToArray(), true, true));
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("METROLOGYASST_PressureOffset",
|
||||
(new Byte[] { 0x00, 0x00, 0x03, 0xF5 }).Reverse().ToArray(), true, true));
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("METROLOGYASST_PressurePresent",
|
||||
(new Byte[] { 0x00, 0x00, 0x00, 0x00 }).Reverse().ToArray(), true, true));
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("METROLOGYASST_PressureRate",
|
||||
(new Byte[] { 0x00, 0x0D, 0xBB, 0xA0 }).Reverse().ToArray(), true, true));
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("METROLOGYASST_PressureUnits",
|
||||
(new Byte[] { 0x00, 0x00, 0x00, 0x00 }).Reverse().ToArray(), true, true));
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("METROLOGYASST_PulseLength",
|
||||
(new Byte[] { 0x00, 0x00, 0x00, 0x07 }).Reverse().ToArray(), true, true));
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("METROLOGYASST_PulseMode",
|
||||
(new Byte[] { 0x00, 0x00, 0x00, 0x01 }).Reverse().ToArray(), true, true));
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("METROLOGYASST_PulseWeight",
|
||||
(new Byte[] { 0x00, 0x00, 0x27, 0x10 }).Reverse().ToArray(), true, true));
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("METROLOGYASST_TemperatureUnits",
|
||||
(new Byte[] { 0x00, 0x00, 0x00, 0x00 }).Reverse().ToArray(), true, true));
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("POWERMON_BatterySelection",
|
||||
(new Byte[] { 0x00, 0x00, 0x00, 0x00 }).Reverse().ToArray()));
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("POWERMON_WarnFromClamp",
|
||||
(new Byte[] { 0x25, 0x89, 0x06, 0x00 }).Reverse().ToArray(), true, true));
|
||||
|
||||
//// just read later //overAllResult.Add(_currentGenesis_WriteRegister("SENSUSRADIO_FrequencyIndicator}).Reverse(), true, true);
|
||||
|
||||
//Original
|
||||
//0x11, 0x12, 0x13, 0x14, 0x21, 0x22, 0x23, 0x24, 0x31, 0x32, 0x33, 0x34, 0x41, 0x42, 0x43, 0x44
|
||||
//Write to register
|
||||
//0x14, 0x13, 0x12, 0x11, 0x24, 0x23, 0x22, 0x21, 0x34, 0x33, 0x32, 0x31, 0x44, 0x43, 0x42, 0x41
|
||||
|
||||
//good one
|
||||
//E6-C8-88-00-DE-B8-68-C0-D6-A8-48-80-CE-98-28-40
|
||||
//0E-05-04-04-00-14-30-68-D0-14-0E-80-40-63-93-73-22
|
||||
|
||||
//&bad one
|
||||
//0E-05-04-05-00-00-88-C8-E6-C0-68-B8-DE-80-48-A8-D6-40-28-98-CE
|
||||
|
||||
//0E-05-04-04-00-22-73-93-63-40-80-0E-14-D0-68-30-14
|
||||
|
||||
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("SENSUSRADIO_WakeupInterval",
|
||||
(new Byte[] { 0x00, 0x00, 0x00, 0x03 }).Reverse().ToArray(), true, true));
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("SENSUSRADIO_MbusState",
|
||||
(new Byte[] { 0x00, 0x00, 0x00, 0x07 }).Reverse().ToArray(), true, true));
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("SENSUSRADIO_UtcTimeOffset",
|
||||
(new Byte[] { 0x00, 0x00, 0x00, 0x00 }).Reverse().ToArray(), true, true));
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("SENSUSRADIO_HistoricalAlarmsDays",
|
||||
(new Byte[] { 0x00, 0x00, 0x00, 0x1D }).Reverse().ToArray(), true, true));
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("PERIODICLOG_AverageFlowPeriod",
|
||||
(new Byte[] { 0x00, 0x00, 0x00, 0x05 }).Reverse().ToArray(), true, true));
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("PERIODICLOG_DataLogContents",
|
||||
(new Byte[] { 0x0C, 0x00, 0x24, 0x03 }).Reverse().ToArray()));
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("PERIODICLOG_DataLogPeriod",
|
||||
(new Byte[] { 0x00, 0x00, 0x00, 0x3C }).Reverse().ToArray()));
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("PERIODICLOG_FixedDateDayOfMonth",
|
||||
(new Byte[] { 0x00, 0x00, 0x00, 0x01 }).Reverse().ToArray()));
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("PERIODICLOG_FixedDateReadingContents",
|
||||
(new Byte[] { 0x0C, 0x00, 0x24, 0x03 }).Reverse().ToArray()));
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("PERIODICLOG_PeriodicLogLifeTimeCounter",
|
||||
(new Byte[] { 0x00, 0x00, 0x00, 0x0 }).Reverse().ToArray()));
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("PERIODICLOG_ResetCounter",
|
||||
(new Byte[] { 0x00, 0x00, 0x00, 0x0 }).Reverse().ToArray(), true, true));
|
||||
|
||||
//var funkadresse = new List<byte>();
|
||||
//funkadresse.AddRange((new Byte[] { 0xE6, 0xC8, 0x88, 0x00 }).ToArray());
|
||||
//funkadresse.AddRange((new Byte[] { 0xDE, 0xB8, 0x68, 0xC0 }).ToArray());
|
||||
//funkadresse.AddRange((new Byte[] { 0xD6, 0xA8, 0x48, 0x80 }).ToArray());
|
||||
//funkadresse.AddRange((new Byte[] { 0xCE, 0x98, 0x28, 0x40 }).ToArray());
|
||||
//overAllResult.Add(_currentGenesis_WriteRegister("SENSUSRADIO_EncryptionKey", funkadresse.ToArray(),
|
||||
// true, true));
|
||||
|
||||
|
||||
//overAllResult.Add(_currentGenesis_WriteRegister("SENSUSRADIO_EncryptionKey",
|
||||
// (new Byte[]
|
||||
// {
|
||||
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
// }).ToArray(), true, true));
|
||||
|
||||
|
||||
|
||||
var funkadresse = new List<Byte>();
|
||||
funkadresse.AddRange((new Byte[] { 0x0E, 0x9F, 0xAC, 0xC6 }).ToArray());
|
||||
funkadresse.AddRange((new Byte[] { 0xA0, 0xE1, 0xEF, 0x1C }).ToArray());
|
||||
funkadresse.AddRange((new Byte[] { 0x3B, 0x27, 0xA4, 0x9B }).ToArray());
|
||||
funkadresse.AddRange((new Byte[] { 0xAC, 0x21, 0x65, 0x35 }).ToArray());
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("SENSUSRADIO_EncryptionKey", funkadresse.ToArray(), true, true));
|
||||
|
||||
|
||||
|
||||
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("SENSUSRADIO_RadioAddress", radioParams.RadioAddress, true, true));
|
||||
|
||||
if (radioParams.PowerLevel > 0 && radioParams.PowerLevelOption > 0 && radioParams.ImpedanceCodeNew > 0 && radioParams.ImpedanceCodeOption > 0)
|
||||
{
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("SENSUSRADIO_PowerLevel", radioParams.PowerLevel, true, true));
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("SENSUSRADIO_PowerLevelOption", radioParams.PowerLevelOption, true, true));
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("SENSUSRADIO_ImpedanceCodeNew", radioParams.ImpedanceCodeNew, true, true));
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("SENSUSRADIO_ImpedanceCodeOption", radioParams.ImpedanceCodeOption, true, true));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
currentProcessState = ProductionProcessState.Error;
|
||||
return;
|
||||
}
|
||||
|
||||
//_currentGenesis_WriteRegister("SENSUSRADIO_CustomerText",
|
||||
// (new Byte[] { 0x00, 0x00, 0x00, 0x00 }).Reverse().ToArray(), true, false);
|
||||
|
||||
var ts = DateTimeOffset.UtcNow - new DateTimeOffset(2000, 1, 1, 0, 0, 0, new TimeSpan(0));
|
||||
overAllResult.Add(wirteRegisterInBetweenCheck("SYSTEM_CalendarSeconds", Convert.ToInt32(ts.TotalSeconds)));
|
||||
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("GENESISFLOW_SealDisplay",
|
||||
(new Byte[] { 0x00, 0x00, 0x00, 0x01 }).Reverse().ToArray(), true, true));
|
||||
|
||||
////radio end state!
|
||||
//overAllResult.Add(_currentGenesis_WriteRegister("SENSUSRADIO_SystemState",
|
||||
// (new Byte[] { 0x00, 0x00, 0x00, 0xFF }).Reverse().ToArray(), true, false));
|
||||
|
||||
//overAllResult.Add(_currentGenesis_WriteRegister("SENSUSRADIO_SystemState",
|
||||
// (new Byte[] { 0x00, 0x00, 0x00, 0x02 }).Reverse().ToArray(), true, true));
|
||||
|
||||
|
||||
|
||||
var ret = true;
|
||||
Int32 done = 0;
|
||||
foreach (var cTask in overAllResult)
|
||||
{
|
||||
cTask.RunSynchronously();
|
||||
if (cTask.Result.Item2)
|
||||
{
|
||||
NewStatus($"set Parameter {cTask.Result.Item1} succeed");
|
||||
}
|
||||
else
|
||||
{
|
||||
NewStatus($"set Parameter {cTask.Result.Item1} failed");
|
||||
ret = false;
|
||||
break;
|
||||
}
|
||||
|
||||
Progress = 20 + ((Int32)Math.Round((done / (Double)overAllResult.Count) * 80, 0));
|
||||
done += 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (!ret)
|
||||
{
|
||||
currentProcessState = ProductionProcessState.Error;
|
||||
}
|
||||
else
|
||||
{
|
||||
currentProcessState = ProductionProcessState.Done;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
-273
@@ -1,273 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Controls;
|
||||
using ProductionUiCordonel.ProductionProcesses.Enum;
|
||||
using ProductionUiCordonel.UserControls.FinalTest;
|
||||
using Xylem.Common.Hardware.WaterMeter.Genesis.Registers;
|
||||
using Xylem.Common.Logic.ProductionOrderCore;
|
||||
|
||||
namespace ProductionUiCordonel.ProductionProcesses.Actions
|
||||
{
|
||||
public class ProductionProcessFinalParametrizationVakoCsd : BaseProductionProcess
|
||||
{
|
||||
private UcPlain UserControl;
|
||||
private ProductionProcessConnect connectProcess;
|
||||
private Boolean hasRadio;
|
||||
|
||||
public ProductionProcessFinalParametrizationVakoCsd(ProductionProcessConnect connectProcess, Boolean registerHasRadio = true)
|
||||
{
|
||||
this.connectProcess = connectProcess;
|
||||
name = "Kunden Parametrierung";
|
||||
currentProcessState = ProductionProcessState.Waiting;
|
||||
hasRadio = registerHasRadio;
|
||||
}
|
||||
|
||||
public override void InitUserControl()
|
||||
{
|
||||
UserControl = new UcPlain
|
||||
{
|
||||
lblHl =
|
||||
{
|
||||
Content = name
|
||||
},
|
||||
lblText =
|
||||
{
|
||||
Content = "Dieser Vorgang kann bis zu 1 Minute dauern!"
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public override UserControl GetControl()
|
||||
{
|
||||
if (UserControl == null)
|
||||
{
|
||||
throw new Exception($"UserControl {GetType()} not Ready");
|
||||
}
|
||||
return UserControl;
|
||||
}
|
||||
|
||||
|
||||
public override void ProcessDone()
|
||||
{
|
||||
//clear
|
||||
}
|
||||
|
||||
public Task<Tuple<String, Boolean>> _currentGenesis_WriteRegister<T>(String reg, T value, Boolean waitForResult = true,
|
||||
Boolean checkRegister = false)
|
||||
{
|
||||
return new Task<Tuple<String, Boolean>>(() =>
|
||||
{
|
||||
Task.Delay(10).Wait();
|
||||
var ret = Meter.WriteRegister(reg, value, waitForResult, checkRegister);
|
||||
if (!ret)
|
||||
{
|
||||
ret = Meter.WriteRegister(reg, value, waitForResult, checkRegister);
|
||||
}
|
||||
return new Tuple<String, Boolean>(reg, ret);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
public Task<Tuple<String, Boolean>> wirteRegisterInBetweenCheck(String reg, Int32 value, Boolean waitForResult = true,
|
||||
Int32 addToCheck = 10, Int32 addFromCheck = 0)
|
||||
{
|
||||
return new Task<Tuple<String, Boolean>>(() =>
|
||||
{
|
||||
Meter.WriteRegister(reg, value, waitForResult);
|
||||
|
||||
var actualValue = RegisterConverter.ConvertTo<Int32>(Meter.ReadRegister(reg));
|
||||
if (actualValue >= (value + addFromCheck) && value <= actualValue + (addToCheck))
|
||||
{
|
||||
return new Tuple<String, Boolean>(reg, true);
|
||||
}
|
||||
return new Tuple<String, Boolean>(reg, false);
|
||||
});
|
||||
}
|
||||
|
||||
private void doStartProcessLoop()
|
||||
{
|
||||
var remainingRetries = 4;
|
||||
while (remainingRetries >= 0)
|
||||
{
|
||||
try
|
||||
{
|
||||
while (connectProcess.asyncProgrammingParametersTask.Status == TaskStatus.Running)
|
||||
{
|
||||
|
||||
Thread.Sleep(500);
|
||||
}
|
||||
if (connectProcess.asyncProgrammingParametersTask.Status == TaskStatus.RanToCompletion
|
||||
&& connectProcess.asyncProgrammingParametersTask.Result != null
|
||||
&& connectProcess.asyncProgrammingParametersTask.Result.Any())
|
||||
{
|
||||
var myJsonResponse = connectProcess.asyncProgrammingParametersTask.Result;
|
||||
|
||||
Progress = 15;
|
||||
|
||||
//fix
|
||||
// CUSTOMER_LeakFlowThreshold
|
||||
//CUSTOMER_ExcessFlowVolumeThreshold
|
||||
|
||||
var overAllResult = new List<Task<Tuple<String, Boolean>>>();
|
||||
//611.219.280
|
||||
//
|
||||
var ts = DateTimeOffset.UtcNow - new DateTimeOffset(2000, 1, 1, 0, 0, 0, new TimeSpan(0));
|
||||
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("GENESISFLOW_SealDisplay",
|
||||
(new Byte[] { 0x00, 0x00, 0x00, 0x00 }).Reverse().ToArray(), true, true));
|
||||
|
||||
// keien frq aber radio parameter
|
||||
if (!Meter.RadioFrequencyMhz.HasValue && myJsonResponse.Any(a => a.RegisterName.Contains("RADIO")))
|
||||
{
|
||||
throw new ApplicationException("Radio inconsistent between meter and programmingparameters");
|
||||
}
|
||||
// eine frequen aber keine radio parameter
|
||||
if (Meter.RadioFrequencyMhz.HasValue && !myJsonResponse.Any(a => a.RegisterName.Contains("RADIO")))
|
||||
{
|
||||
throw new ApplicationException("Radio inconsistent between meter and programmingparameters");
|
||||
}
|
||||
foreach (var item in myJsonResponse.Where(m => m.Source == ProgrammingSource.Vako))
|
||||
{
|
||||
|
||||
if (item.RegisterName == "CUSTOMER_LeakFlowThreshold")
|
||||
{
|
||||
|
||||
}
|
||||
//todo: find a better sln for SENSUSRADIO_EncryptionKey
|
||||
//SENSUSRADIO_EncryptionKey dont reserve SENSUSRADIO_EncryptionKey!
|
||||
if (item.RegisterName.ToLower().Contains("displaypow".ToLower()) || item.RegisterName.ToLower().Contains("METROLOGYASST_FlowPoint".ToLower()))
|
||||
{
|
||||
overAllResult.Add(_currentGenesis_WriteRegister(item.RegisterName, new[] { item.RegisterValue.ToArray()[0] }, true, true));
|
||||
}
|
||||
else if (item.RegisterName.ToLower().Contains("SENSUSRADIO_EncryptionKey".ToLower()))
|
||||
{
|
||||
overAllResult.Add(_currentGenesis_WriteRegister(item.RegisterName, item.RegisterValue.ToArray(), true, true));
|
||||
}
|
||||
else
|
||||
{
|
||||
overAllResult.Add(_currentGenesis_WriteRegister(item.RegisterName, item.RegisterValue.Reverse().ToArray(), true, true));
|
||||
|
||||
}
|
||||
|
||||
//else if (!item.RegisterName.ToLower().Contains("apparrangement"))
|
||||
//{
|
||||
// overAllResult.Add(_currentGenesis_WriteRegister(item.RegisterName, item.RegisterValue.Reverse().ToArray(), true, true));
|
||||
//}
|
||||
}
|
||||
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("CUSTOMER_AlarmEnableMask", new Byte[] { 0x00, 0x00, 0x80, 0x53 }.Reverse().ToArray()));
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("CUSTOMER_AlarmBroadcastMask", new Byte[] { 0x00, 0x00, 0x1f, 0xdc }.Reverse().ToArray()));
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("CUSTOMER_AlarmVisualMask", new Byte[] { 0x00, 0x00, 0x1f, 0xdc }.Reverse().ToArray()));
|
||||
|
||||
foreach (var item in myJsonResponse.Where(m => m.Source == ProgrammingSource.Csd))
|
||||
{
|
||||
//todo: find a better sln for SENSUSRADIO_EncryptionKey
|
||||
//SENSUSRADIO_EncryptionKey dont reserve SENSUSRADIO_EncryptionKey!
|
||||
if (item.RegisterName.ToLower().Contains("SENSUSRADIO_EncryptionKey".ToLower()))
|
||||
{
|
||||
overAllResult.Add(_currentGenesis_WriteRegister(item.RegisterName, item.RegisterValue.ToArray(), true, true));
|
||||
}
|
||||
else if (!item.RegisterName.ToLower().Contains("apparrangement"))
|
||||
{
|
||||
overAllResult.Add(_currentGenesis_WriteRegister(item.RegisterName, item.RegisterValue.Reverse().ToArray(), true, true));
|
||||
}
|
||||
}
|
||||
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("GENESISFLOW_ResetAccumulators",
|
||||
(new Byte[] { 0x00, 0x00, 0x00, 0x01 }).Reverse().ToArray()));
|
||||
|
||||
overAllResult.Add(wirteRegisterInBetweenCheck("SYSTEM_CalendarSeconds", Convert.ToInt32(ts.TotalSeconds)));
|
||||
overAllResult.Add(wirteRegisterInBetweenCheck("IRDA_MfgDate", Convert.ToInt32(ts.TotalSeconds)));
|
||||
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("NFC_EraseRMA",
|
||||
(new Byte[] { 0x00, 0x00, 0x00, 0x01 }).Reverse().ToArray()));
|
||||
|
||||
if (Meter.RadioFrequencyMhz.HasValue)
|
||||
{
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("LOGGER_TriggerLogFlush",
|
||||
(new Byte[] { 0x00, 0x00, 0x00, 0x01 }).Reverse().ToArray()));
|
||||
|
||||
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("PERIODICLOG_ResetCounter",
|
||||
(new Byte[] { 0x00, 0x00, 0x00, 0x00 }).Reverse().ToArray()));
|
||||
}
|
||||
overAllResult.Add(_currentGenesis_WriteRegister("GENESISFLOW_SealDisplay",
|
||||
(new Byte[] { 0x00, 0x00, 0x00, 0x01 }).Reverse().ToArray(), true, true));
|
||||
|
||||
|
||||
var ret = true;
|
||||
Int32 done = 0;
|
||||
|
||||
foreach (var cTask in overAllResult)
|
||||
{
|
||||
try
|
||||
{
|
||||
Thread.Sleep(50);
|
||||
cTask.RunSynchronously();
|
||||
if (cTask.Result.Item2)
|
||||
{
|
||||
NewStatus($"Schreiben des Parameter {cTask.Result.Item1} war erfolgreich");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (cTask.Result.Item1.ToLower().Contains("Metersize".ToLower()) || cTask.Result.Item1.ToLower().Contains("NFC_EraseRMA".ToLower()) || cTask.Result.Item1.ToLower().Contains("CUSTOMER_ExcessFlowVolumeThreshold".ToLower()) || cTask.Result.Item1.ToLower().Contains("CUSTOMER_LeakFlowThreshold".ToLower()) || cTask.Result.Item1.ToLower() == "SENSUSRADIO_MetroRadioLifeTimeCounter".ToLower())
|
||||
{
|
||||
NewStatus($"Warnung! Fehler beim Schreiben des Parameters {cTask.Result.Item1}");
|
||||
}
|
||||
else
|
||||
{
|
||||
NewStatus($"Warnung! Fehler beim Schreiben des Parameters {cTask.Result.Item1}");
|
||||
|
||||
ret = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
if (cTask.Result.Item1 != "GENESISFLOW_MaxDeltaToFRange")
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
Progress = 15 + ((Int32)Math.Round((done / (Double)overAllResult.Count) * 85, 0));
|
||||
done += 1;
|
||||
}
|
||||
|
||||
if (!ret)
|
||||
{
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
currentProcessState = ProductionProcessState.Done;
|
||||
return;
|
||||
}
|
||||
remainingRetries -= 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
currentProcessState = ProductionProcessState.Error;
|
||||
remainingRetries = -1;
|
||||
NewStatus("Warnung! Fehler beim Laden des Parametersatzes");
|
||||
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
currentProcessState = ProductionProcessState.Error;
|
||||
NewStatus($"Warnung! Fehler beim Behandeln von {ex.Message}");
|
||||
remainingRetries = remainingRetries - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void StartProcess()
|
||||
{
|
||||
doStartProcessLoop();
|
||||
}
|
||||
}
|
||||
}
|
||||
-107
@@ -1,107 +0,0 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Threading;
|
||||
using ProductionUiCordonel.ProductionProcesses.Enum;
|
||||
using ProductionUiCordonel.UserControls.FinalTest;
|
||||
using Xylem.Common.Hardware.WaterMeter.Genesis.Registers;
|
||||
|
||||
namespace ProductionUiCordonel.ProductionProcesses.Actions
|
||||
{
|
||||
public class ProductionProcessFullReadOut : BaseProductionProcess
|
||||
{
|
||||
private UcFullReadOut UserControl;
|
||||
public ProductionProcessFullReadOut()
|
||||
{
|
||||
name = "Sicherung des Zählerzustandes";
|
||||
currentProcessState = ProductionProcessState.Waiting;
|
||||
}
|
||||
|
||||
public override void InitUserControl()
|
||||
{
|
||||
UserControl = new UcFullReadOut();
|
||||
}
|
||||
|
||||
public override UserControl GetControl()
|
||||
{
|
||||
if (UserControl == null)
|
||||
{
|
||||
throw new Exception($"UserControl {GetType()} not Ready");
|
||||
}
|
||||
return UserControl;
|
||||
}
|
||||
|
||||
public override void ProcessDone()
|
||||
{
|
||||
//clear
|
||||
}
|
||||
|
||||
public override void StartProcess()
|
||||
{
|
||||
try
|
||||
{
|
||||
UserControl.lblHl.Dispatcher.Invoke(DispatcherPriority.Send,
|
||||
new Action(() => { UserControl.lblHl.Content = "Read out Registers"; }
|
||||
));
|
||||
var oldConfigEntry = Meter.Configuration.UseRegisterWatchService;
|
||||
if (oldConfigEntry)
|
||||
{
|
||||
Meter.Configuration.UseRegisterWatchService = false;
|
||||
}
|
||||
|
||||
var total = Meter.GetRegistersDic().Keys.ToList();
|
||||
var done = 0;
|
||||
foreach (var dic in total)
|
||||
{
|
||||
try
|
||||
{
|
||||
var done1 = done;
|
||||
UserControl.lblText.Dispatcher.Invoke(DispatcherPriority.Send,
|
||||
new Action(() =>
|
||||
{
|
||||
UserControl.lblText.Content = $"Read {dic.GetIdent()}({done1}/{total.Count})";
|
||||
}
|
||||
));
|
||||
if (dic.RegisterName.ToLower() != "password" && dic.RegisterDetail.Privilege.Lvl8 != Access.WO)
|
||||
{
|
||||
switch (dic.GetIdent().ToLower())
|
||||
{
|
||||
case "sensusradio_encryptionkey":
|
||||
Meter.ReadRegister(dic.GetIdent(), 32);
|
||||
break;
|
||||
default:
|
||||
if (dic.DataType == typeof(UInt64) || dic.DataType == typeof(Int64))
|
||||
{
|
||||
Meter.ReadRegister(dic.GetIdent(), 32);
|
||||
}
|
||||
else
|
||||
{
|
||||
Meter.ReadRegister(dic.GetIdent());
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
Progress = (Int32)Math.Round(((Double)done / total.Count) * 100, 0);
|
||||
}
|
||||
catch (Exception )
|
||||
{
|
||||
//todo: error logger
|
||||
}
|
||||
|
||||
done += 1;
|
||||
}
|
||||
|
||||
Meter.StoreCurrentRegisterDic();
|
||||
Meter.Configuration.UseRegisterWatchService = oldConfigEntry;
|
||||
|
||||
currentProcessState = ProductionProcessState.Done;
|
||||
}
|
||||
catch (Exception )
|
||||
{
|
||||
currentProcessState = ProductionProcessState.Error;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
-86
@@ -1,86 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Windows.Controls;
|
||||
using Newtonsoft.Json;
|
||||
using ProductionUiCordonel.ProductionProcesses.Enum;
|
||||
using ProductionUiCordonel.UserControls.FinalTest;
|
||||
using Xylem.Common.CommonCore.Configuration;
|
||||
using Xylem.Common.Logic.ProductionOrderCore;
|
||||
using Xylem.Common.Logic.SoftwareAccessHelper;
|
||||
|
||||
namespace ProductionUiCordonel.ProductionProcesses.Actions
|
||||
{
|
||||
public class ProductionProcessGetFinalParametrizationVakoCsd : BaseProductionProcess
|
||||
{
|
||||
public IList<ProgrammingParameters> Result = new List<ProgrammingParameters>();
|
||||
private UcPlain UserControl;
|
||||
public ProductionProcessGetFinalParametrizationVakoCsd()
|
||||
{
|
||||
name = "Hole Kunden Parametrierung";
|
||||
currentProcessState = ProductionProcessState.Waiting;
|
||||
}
|
||||
public override void InitUserControl()
|
||||
{
|
||||
UserControl = new UcPlain();
|
||||
UserControl.lblHl.Content = name;
|
||||
UserControl.lblText.Content = "Kann bis zu 1 Minute dauern!";
|
||||
}
|
||||
|
||||
public override UserControl GetControl()
|
||||
{
|
||||
if (UserControl == null)
|
||||
{
|
||||
throw new Exception($"UserControl {GetType()} not Ready");
|
||||
}
|
||||
return UserControl;
|
||||
}
|
||||
|
||||
|
||||
public override void ProcessDone()
|
||||
{
|
||||
//clear
|
||||
}
|
||||
|
||||
|
||||
private void doStartProcessLoop()
|
||||
{
|
||||
var retriesRemaining = 2;
|
||||
while (retriesRemaining >= 0)
|
||||
{
|
||||
try
|
||||
{
|
||||
Progress = 0;
|
||||
//var url = $"http://localhost:56011/api/FinalCheck/GetProgrammingParameters?PcbID={Meter.PcbId}";
|
||||
var url = $"{ServiceUrls.GenesisFinalCheckServiceUrl()}GetProgrammingParameters?PcbID={Meter.PcbId}";
|
||||
var csdRet = LocalWebRequest.GetRequest(url, 60000);
|
||||
|
||||
Result = JsonConvert.DeserializeObject<IList<ProgrammingParameters>>(csdRet);
|
||||
|
||||
Progress = 100;
|
||||
|
||||
if (!Result.Any())
|
||||
{
|
||||
currentProcessState = ProductionProcessState.Error;
|
||||
}
|
||||
else
|
||||
{
|
||||
currentProcessState = ProductionProcessState.Done;
|
||||
return;
|
||||
}
|
||||
retriesRemaining -= 1;
|
||||
}
|
||||
catch (Exception )
|
||||
{
|
||||
currentProcessState = ProductionProcessState.Error;
|
||||
retriesRemaining -= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void StartProcess()
|
||||
{
|
||||
doStartProcessLoop();
|
||||
}
|
||||
}
|
||||
}
|
||||
-155
@@ -1,155 +0,0 @@
|
||||
using ProductionUiCordonel.ProductionProcesses.Enum;
|
||||
using ProductionUiCordonel.UserControls.FinalTest;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Windows.Controls;
|
||||
using Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile;
|
||||
using Xylem.Common.Hardware.WaterMeter.Genesis.GenesisPwd;
|
||||
|
||||
namespace ProductionUiCordonel.ProductionProcesses.Actions
|
||||
{
|
||||
public class ProductionProcessPasswordFile : BaseProductionProcess
|
||||
{
|
||||
private UcPasswordFile _userControl;
|
||||
private MeterPwdDb _pwdContainer = new MeterPwdDb();
|
||||
private MeterPwdFile _meterPwdFile;
|
||||
|
||||
public ProductionProcessPasswordFile()
|
||||
{
|
||||
name = "PasswordFile";
|
||||
currentProcessState = ProductionProcessState.Waiting;
|
||||
}
|
||||
|
||||
public override void InitUserControl()
|
||||
{
|
||||
_userControl = new UcPasswordFile();
|
||||
}
|
||||
|
||||
public override UserControl GetControl()
|
||||
{
|
||||
if (_userControl == null)
|
||||
{
|
||||
throw new Exception($"UserControl {GetType()} not Ready");
|
||||
}
|
||||
return _userControl;
|
||||
}
|
||||
|
||||
private void updateImage(Image ctlImage, Boolean? success = null)
|
||||
{
|
||||
if (success.HasValue)
|
||||
{
|
||||
if (success.Value)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void StartProcess()
|
||||
{
|
||||
var ret = MeterPwdHandlerDb.RequestPwdFileFromDb(Meter.PcbId, out _pwdContainer);
|
||||
updateImage(_userControl.RequestPassword, ret);
|
||||
Progress += 16;
|
||||
Meter.Logout();
|
||||
ret = Meter.Login();
|
||||
|
||||
|
||||
//If the password file is written, the "Password" from _pwdContainer is overwritten from Skeleton-key
|
||||
//to the "level 8 password" form the LuDB server. The DB password column is the current login password
|
||||
//for production. Initially the "Password" is the Skeleton-key which can not be part of the list of
|
||||
//Passwords. The level 8 password is the last in the _pwdContainer list of passwords.
|
||||
if (Encoding.UTF8.GetString(_pwdContainer.ListOfPasswords.Last()) == _pwdContainer.Password)
|
||||
{
|
||||
NewStatus("Passwörter schon geschrieben. Prozess wird übersprungen");
|
||||
|
||||
currentProcessState = ProductionProcessState.Done;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
//Get the passwords from LuDB, insert the skeleton-kay and generate the password file
|
||||
if (ret)
|
||||
{
|
||||
ret = CreatePasswordFile();
|
||||
}
|
||||
|
||||
updateImage(_userControl.CreateFile, ret);
|
||||
Progress += 16;
|
||||
|
||||
//Write the password file to the Cordonel, read it back and make a binary verification
|
||||
if (ret)
|
||||
{
|
||||
ret = WriteAndVerifyPasswordFileToMeter();
|
||||
}
|
||||
|
||||
updateImage(_userControl.WriteToMeter, ret);
|
||||
Progress += 16;
|
||||
|
||||
//Check if new password is in the meter ... even if the file write wasn't successful
|
||||
if (ret)
|
||||
{
|
||||
Meter.Logout();
|
||||
ret = Meter.Login(Encoding.UTF8.GetString(_pwdContainer.ListOfPasswords.Last()));
|
||||
}
|
||||
|
||||
//Password in Production DB can be updated (overwrite Skeleton-key in Password column with
|
||||
//password level 8 from LuDB) because the login with installed password file succeeded,
|
||||
//this is the indicator, that the password file is valid.
|
||||
if (ret)
|
||||
{
|
||||
ret = MeterPwdHandlerDb.SetPwdFromSkeletonToLvl8inDd(Meter.PcbId, _pwdContainer);
|
||||
}
|
||||
updateImage(_userControl.UpdatePassword, ret);
|
||||
Progress += 16;
|
||||
|
||||
if (ret)
|
||||
{
|
||||
ret = Meter.Logout();
|
||||
}
|
||||
updateImage(_userControl.Logout, ret);
|
||||
Progress += 16;
|
||||
|
||||
//test the production database password
|
||||
if (ret)
|
||||
{
|
||||
Meter.ClearPassword();
|
||||
ret = Meter.Login();
|
||||
}
|
||||
updateImage(_userControl.CheckNewPassword, ret);
|
||||
Progress = 100;
|
||||
|
||||
if (!ret)
|
||||
{
|
||||
currentProcessState = ProductionProcessState.Error;
|
||||
}
|
||||
else
|
||||
{
|
||||
currentProcessState = ProductionProcessState.Done;
|
||||
}
|
||||
}
|
||||
public override void ProcessDone()
|
||||
{
|
||||
//clear
|
||||
}
|
||||
|
||||
#region realWork
|
||||
public Boolean CreatePasswordFile()
|
||||
{
|
||||
_meterPwdFile = new MeterPwdFile(Meter);
|
||||
return _meterPwdFile.BuildPwdFile(_pwdContainer.ListOfPasswords, 1, _pwdContainer.Skeleton);
|
||||
}
|
||||
public Boolean WriteAndVerifyPasswordFileToMeter()
|
||||
{
|
||||
if (_meterPwdFile.UnlockEraseWriteMeterPwdFile())
|
||||
{
|
||||
if (_meterPwdFile.WriteMeterPwdFile())
|
||||
{
|
||||
return _meterPwdFile.VerifyMeterPwdFile();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
-473
@@ -1,473 +0,0 @@
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using ProductionUiCordonel.ProductionProcesses.Enum;
|
||||
using ProductionUiCordonel.UserControls.FinalTest;
|
||||
using SIRTCOM;
|
||||
using System;
|
||||
using System.Configuration;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using System.Windows.Threading;
|
||||
using Xylem.Common.CommonCore.Configuration;
|
||||
using Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore;
|
||||
using Xylem.Common.Hardware.WaterMeter.Genesis.Registers;
|
||||
using Xylem.Common.Logic.SoftwareAccessHelper;
|
||||
using Button = System.Windows.Controls.Button;
|
||||
using UserControl = System.Windows.Controls.UserControl;
|
||||
|
||||
namespace ProductionUiCordonel.ProductionProcesses.Actions
|
||||
{
|
||||
public class ProductionProcessRadioCheck : BaseProductionProcess
|
||||
{
|
||||
private UcRadioCheck UserControl;
|
||||
public ProductionProcessRadioCheck()
|
||||
{
|
||||
|
||||
name = "Radio Check";
|
||||
currentProcessState = ProductionProcessState.Waiting;
|
||||
|
||||
|
||||
}
|
||||
public override void InitUserControl()
|
||||
{
|
||||
UserControl = new UcRadioCheck();
|
||||
|
||||
UserControl.OnRetryRequested += delegate { GetRssi(); };
|
||||
|
||||
|
||||
UserControl.OnResetRequested += delegate { Reset(); };
|
||||
UserControl.OnForceAPam += delegate { forcePush(); };
|
||||
UserControl.OnDoneRequested += delegate
|
||||
{
|
||||
currentProcessState = ProductionProcessState.Done;
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
public override UserControl GetControl()
|
||||
{
|
||||
if (UserControl == null)
|
||||
{
|
||||
throw new Exception($"UserControl {GetType()} not Ready");
|
||||
}
|
||||
return UserControl;
|
||||
}
|
||||
|
||||
|
||||
public override void ProcessDone()
|
||||
{
|
||||
if (SENSUSRADIO_WakeupInterval != null)
|
||||
{
|
||||
var ret = Meter.WriteRegister("SENSUSRADIO_WakeupInterval", SENSUSRADIO_WakeupInterval, true, true);
|
||||
|
||||
if (!ret)
|
||||
{
|
||||
currentProcessState = ProductionProcessState.Error;
|
||||
}
|
||||
}
|
||||
//clear
|
||||
}
|
||||
|
||||
private Byte[] SENSUSRADIO_WakeupInterval;
|
||||
public override void StartProcess()
|
||||
{
|
||||
|
||||
//readout adress, freq,
|
||||
|
||||
if (Meter.RadioFrequencyMhz.HasValue)
|
||||
{
|
||||
|
||||
|
||||
var freq = RegisterConverter.ConvertTo<UInt32>(Meter.ReadRegister("SENSUSRADIO_FrequencyIndicator"));
|
||||
RadioAdress = RegisterConverter.ConvertTo<UInt32>(Meter.ReadRegister("SENSUSRADIO_RadioAddress"));
|
||||
|
||||
|
||||
Comport = Convert.ToByte(ConfigurationManager.AppSettings[$"SirtComport{freq}"]);
|
||||
var enc = Meter.ReadRegister("SENSUSRADIO_EncryptionKey", 16);
|
||||
|
||||
EncyptionKey = LocalWebRequest.GetRequest($"{ServiceUrls.GenesisFinalCheckServiceUrl()}GetEncryptionKey?PcbID={Meter.PcbId}", 80000).ToUpper().Trim('\"');
|
||||
if (!EncyptionKey.Equals(BitConverter.ToString(enc.ToArray()).Replace("-", "")))
|
||||
{
|
||||
MessageBox.Show("Funkschlüssel überprüfen!");
|
||||
}
|
||||
|
||||
EncyptionKey = BitConverter.ToString(enc.ToArray()).Replace("-", "");
|
||||
|
||||
//if (freq == 868)
|
||||
//{
|
||||
// Comport = 8;
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// Comport = 7;
|
||||
//}
|
||||
BoxNr = Convert.ToByte(ConfigurationManager.AppSettings["SirtBoxNr"]);
|
||||
|
||||
DebugMessage($"Start RadioCheck Comport:{Comport} ,BoxNr:{BoxNr}, freq: {freq}, RadioAddress:{RadioAdress}s\r\n");
|
||||
|
||||
Meter.WriteRegister("SENSUSRADIO_IrDAModulePresent", 1, true, true);
|
||||
|
||||
|
||||
SENSUSRADIO_WakeupInterval = Meter.ReadRegister("SENSUSRADIO_WakeupInterval");
|
||||
Meter.WriteRegister("SENSUSRADIO_WakeupInterval", 0);
|
||||
|
||||
|
||||
GetRssi();
|
||||
}
|
||||
else
|
||||
{
|
||||
currentProcessState = ProductionProcessState.Done;
|
||||
}
|
||||
}
|
||||
|
||||
#region FormerForm
|
||||
|
||||
private SaveData saveData;
|
||||
private Statemashine stm;
|
||||
private static HttpClient httpclient;
|
||||
|
||||
private Byte? RSSI_PAM_Min;
|
||||
private Byte? RSSI_PAM_Max;
|
||||
private Byte? RSSI_PAM;
|
||||
private Byte? RSSI_SEMI_Min;
|
||||
private Byte? RSSI_SEMI_Max;
|
||||
private Byte? RSSI_SEMI;
|
||||
|
||||
public Byte BoxNr;
|
||||
|
||||
public Int32 Ordernumber;
|
||||
public UInt32 RadioAdress;
|
||||
|
||||
public Byte Comport;
|
||||
|
||||
public String EncyptionKey = "";
|
||||
|
||||
|
||||
private void enableBtn(Button btn, Boolean enable)
|
||||
{
|
||||
btn.Dispatcher.Invoke(DispatcherPriority.Send,
|
||||
new Action(() =>
|
||||
{
|
||||
btn.IsEnabled = enable;
|
||||
}
|
||||
));
|
||||
}
|
||||
|
||||
private void SetUi()
|
||||
{
|
||||
UserControl.SetUi(new UcRadioCheck.UIContainer(RSSI_PAM_Min, RSSI_SEMI_Min, RSSI_PAM, RSSI_SEMI, RSSI_PAM_Max, RSSI_SEMI_Max));
|
||||
}
|
||||
|
||||
private async void GetRssi()
|
||||
{
|
||||
|
||||
//StartProcess();
|
||||
enableBtn(UserControl.btnGetRssi, false);
|
||||
|
||||
DebugMessage("");
|
||||
|
||||
|
||||
saveData = new SaveData();
|
||||
|
||||
SetUi();
|
||||
|
||||
|
||||
|
||||
//Meter.WriteRegister("SENSUSRADIO_PowerLevel", 67, true, true);
|
||||
//Meter.WriteRegister("SENSUSRADIO_PowerLevelOption", 59, true, true);
|
||||
//Meter.WriteRegister("SENSUSRADIO_ImpedanceCodeNew", 2992, true, true);
|
||||
//Meter.WriteRegister("SENSUSRADIO_ImpedanceCodeOption", 2936, true, true);
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
await GetRssiMinMaxAsync(BoxNr, Ordernumber);
|
||||
SetUi();
|
||||
GetRSSI((Int32)RadioAdress, Comport, EncyptionKey);
|
||||
SetUi();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
DebugMessage($"Fehler in buttonSende_Click():\r\n{ex.Message}\r\n{ex.InnerException}", true);
|
||||
}
|
||||
enableBtn(UserControl.btnGetRssi, true);
|
||||
|
||||
}
|
||||
|
||||
private void clearRssi()
|
||||
{
|
||||
RSSI_PAM_Min = null;
|
||||
RSSI_PAM_Max = null;
|
||||
RSSI_PAM = null;
|
||||
RSSI_SEMI_Min = null;
|
||||
RSSI_SEMI_Max = null;
|
||||
RSSI_SEMI = null;
|
||||
}
|
||||
|
||||
private void Reset()
|
||||
{
|
||||
if (!(stm == null))
|
||||
{
|
||||
stm.ClearPam();
|
||||
stm.Stop();
|
||||
}
|
||||
DebugMessage("Reset\r\n");
|
||||
clearRssi();
|
||||
SetUi();
|
||||
StartProcess();
|
||||
}
|
||||
|
||||
private class SaveData
|
||||
{
|
||||
public Int32 RadioAdress { get; set; }
|
||||
public Byte RSSI_PAM { get; set; }
|
||||
public Byte RSSI_SEMI { get; set; }
|
||||
public Int32 LimitId { get; set; }
|
||||
public Byte Result { get; set; }
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Speichert das gefüllte saveData Objekt via SaveRSSI Webservice
|
||||
/// </summary>
|
||||
private async void SaveDataToDB()
|
||||
{
|
||||
DebugMessage("Calling SaveRSSI Webservice...", true);
|
||||
try
|
||||
{
|
||||
saveData.RadioAdress = (Int32)RadioAdress; // 0-4294967295
|
||||
String url = $"{ServiceUrls.GenesisRadioCheckServiceUrl()}SaveRSSI";
|
||||
String body = JsonConvert.SerializeObject(saveData);
|
||||
await PostDataAsync(url, body);
|
||||
DebugMessage(" Ready\r\n", true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
DebugMessage($"Fehler in SaveDataToDB():\r\n{ex.Message}\r\n{ex.InnerException}", true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private async Task GetRssiMinMaxAsync(Byte BoxNr, Int32 FaNr)
|
||||
{
|
||||
//DebugMessage("Calling GetLimits Webservice...", true);
|
||||
try
|
||||
{
|
||||
// TODO anpassen
|
||||
String url = $"{ServiceUrls.GenesisRadioCheckServiceUrl()}GetLimits/{BoxNr}/{FaNr}";
|
||||
String body = await GetResponseAsync(url);
|
||||
JObject o = JObject.Parse(body);
|
||||
|
||||
saveData.LimitId = Convert.ToInt32(o.SelectToken("LimitId").ToString());
|
||||
RSSI_PAM_Min = Convert.ToByte(o.SelectToken("RSSI_PAM_Min").ToString());
|
||||
RSSI_PAM_Max = Convert.ToByte(o.SelectToken("RSSI_PAM_Max").ToString());
|
||||
RSSI_SEMI_Min = Convert.ToByte(o.SelectToken("RSSI_SEMI_Min").ToString());
|
||||
RSSI_SEMI_Max = Convert.ToByte(o.SelectToken("RSSI_SEMI_Max").ToString());
|
||||
DebugMessage(" Ready\r\n", true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
saveData.LimitId = 0;
|
||||
RSSI_PAM_Min = 100;
|
||||
|
||||
RSSI_PAM_Max = 200;
|
||||
RSSI_SEMI_Min = 100;
|
||||
RSSI_SEMI_Max = 200;
|
||||
// RSSI_PAM_Min RSSI_PAM_Max RSSI_SEMI_Min RSSI_SEMI_Max
|
||||
//145 164 182
|
||||
|
||||
// throw new Exception("Fehler in GetRssiMinMax()", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private void GetRSSI(Int32 RadioAdress, Int32 ByteCOMPort, String strKey)
|
||||
{
|
||||
|
||||
RSSI_PAM = null;
|
||||
RSSI_SEMI = null;
|
||||
|
||||
stm = new Statemashine();
|
||||
|
||||
Byte P81_1 = 0;
|
||||
|
||||
saveData.RadioAdress = RadioAdress;
|
||||
|
||||
stm.initialise((Byte)ByteCOMPort);
|
||||
Wrapper wrp = new Wrapper();
|
||||
stm.StartLoggin("C:\\GenesisLog\\log.txt");
|
||||
|
||||
// ist wohl nicht nötig da der SIRT richtig konfiguroert ist:
|
||||
// wrp.ActivateSirt(byte modul1, byte modul2, byte actTimeout, out byte outP12_01, out byte outP12_02);
|
||||
|
||||
DebugMessage($"Sending PAM to {RadioAdress.ToString()} ...", true);
|
||||
stm.ClearPam();
|
||||
stm.Timeout_s = 60;
|
||||
|
||||
if (strKey == "")
|
||||
{
|
||||
// Dummy PAM 00 OHNE Funkschlüssel
|
||||
stm.SendPAM(RadioAdress.ToString(), "00", "", P81_1, 1, 0, "", "0", false);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Dummy PAM 00 mit Funkschlüssel
|
||||
stm.SendPAM(RadioAdress.ToString(), "00", "", P81_1, 1, 0, strKey, "0", true);
|
||||
}
|
||||
|
||||
stm.OnStateChanged += Stm_OnStateChanged;
|
||||
stm.Start(); // Start polling
|
||||
|
||||
DebugMessage(" OK\r\n", true);
|
||||
Meter.ResetAlarm(GenesisMeter.Alarm.EMPTY_PIPE);
|
||||
Thread.Sleep(5000);
|
||||
//Meter.WriteRegister("SENSUSRADIO_SYSTEMSTATE", 0x01, true, false);
|
||||
forcePush();
|
||||
if (false)
|
||||
{
|
||||
GotRSSICallback(1, 1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void forcePush()
|
||||
{
|
||||
Meter.WriteRegister("SENSUSRADIO_SYSTEMSTATE", 0x55);
|
||||
Meter.WriteRegister("SENSUSRADIO_SYSTEMSTATE", 0x02);
|
||||
}
|
||||
|
||||
|
||||
public void DebugMessage(String value, Boolean Append = false)
|
||||
{
|
||||
NewStatus(value);
|
||||
}
|
||||
|
||||
private void GotRSSICallback(Byte Rssi_Semi_Sirt, Byte Rssi_Pam_Cord)
|
||||
{
|
||||
// RSSI beim Empfangen der PAM gemessen vom Cordonel (Sendestärke des SIRT verpackt in SEMI, byte 20)
|
||||
DebugMessage($"RSSI Cord of PAM (Sirt => Cord):{Rssi_Pam_Cord}\r\n", true);
|
||||
RSSI_PAM = Rssi_Pam_Cord;
|
||||
RSSI_SEMI = Rssi_Semi_Sirt;
|
||||
|
||||
// RSSI beim Empfangen der SEMI gemessen vom SIRT (Sendestärke des Cordonel in byte 4)
|
||||
DebugMessage($"RSSI Sirt of SEMI (Cord => Sirt):{Rssi_Semi_Sirt}\r\n", true);
|
||||
saveData.RSSI_PAM = Rssi_Pam_Cord;
|
||||
saveData.RSSI_SEMI = Rssi_Semi_Sirt;
|
||||
|
||||
saveData.Result = 1;
|
||||
|
||||
if (RSSI_PAM < RSSI_PAM_Min)
|
||||
{
|
||||
saveData.Result = 0;
|
||||
}
|
||||
|
||||
if (RSSI_SEMI < RSSI_SEMI_Min)
|
||||
{
|
||||
saveData.Result = 0;
|
||||
}
|
||||
|
||||
if (RSSI_PAM > RSSI_PAM_Max)
|
||||
{
|
||||
saveData.Result = 0;
|
||||
}
|
||||
|
||||
if (RSSI_SEMI > RSSI_SEMI_Max)
|
||||
{
|
||||
saveData.Result = 0;
|
||||
}
|
||||
|
||||
|
||||
SaveDataToDB();
|
||||
SetUi();
|
||||
if (saveData.Result == 1)
|
||||
{
|
||||
UserControl.ViewResult();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private void Stm_OnStateChanged(Object sender, MyEventArgs e)
|
||||
{
|
||||
// our Pam
|
||||
PAM Pam = stm.GetPAM(1);
|
||||
|
||||
if (Pam.State == PAM.PAMStates.Timeout)
|
||||
{
|
||||
DebugMessage($"Timeout nach {Pam.GetTime()} s\r\n");
|
||||
}
|
||||
|
||||
if (Pam.CountSemi > 0)
|
||||
{
|
||||
// we recieved the SEMI
|
||||
|
||||
//btnGetRssi.IsEnabled = true;
|
||||
stm.Stop();
|
||||
stm.ClearPam();
|
||||
|
||||
String HexbytesSEMI = Pam.Semi.HexData.Replace(" ", "");
|
||||
Byte[] SEMI_bytes = new Byte[HexbytesSEMI.Length / 2];
|
||||
|
||||
for (Int32 i = 0; i < HexbytesSEMI.Length; i += 2)
|
||||
{
|
||||
SEMI_bytes[i / 2] = Convert.ToByte(HexbytesSEMI.Substring(i, 2), 16);
|
||||
}
|
||||
|
||||
// SEMI Status
|
||||
if (SEMI_bytes[19] == 0)
|
||||
{
|
||||
// RSSI beim Empfangen der SEMI gemessen vom Sirt
|
||||
Byte Semi_Rssi_Sirt = SEMI_bytes[2];
|
||||
|
||||
// RSSI beim Empfangen der PAM gemessen vom Cordonel
|
||||
Byte Pam_Rssi_Cord = SEMI_bytes[20];
|
||||
|
||||
GotRSSICallback(Semi_Rssi_Sirt, Pam_Rssi_Cord);
|
||||
}
|
||||
else
|
||||
{
|
||||
// SEMI Status ist nicht 0.
|
||||
DebugMessage(Pam.Semi.GetPamErrorMessage(), true);
|
||||
}
|
||||
stm.ClearPam();
|
||||
}
|
||||
else
|
||||
{
|
||||
DebugMessage($"BUPS:{Pam.CountBup}\r\n", true);
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task<String> PostDataAsync(String url, String data)
|
||||
{
|
||||
httpclient = new HttpClient();
|
||||
// 20 Sekunden Timeout
|
||||
httpclient.Timeout = new TimeSpan(0, 0, 20);
|
||||
|
||||
StringContent queryString = new StringContent(data, Encoding.UTF8, "application/json");
|
||||
HttpResponseMessage response = await httpclient.PostAsync(url, queryString);
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
String content = await response.Content.ReadAsStringAsync();
|
||||
return content;
|
||||
}
|
||||
|
||||
private static async Task<String> GetResponseAsync(String url)
|
||||
{
|
||||
httpclient = new HttpClient();
|
||||
// 20 Sekunden Timeout
|
||||
httpclient.Timeout = new TimeSpan(0, 0, 20);
|
||||
|
||||
HttpResponseMessage response = httpclient.GetAsync(url).Result;
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
String content = await response.Content.ReadAsStringAsync();
|
||||
return content;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
-72
@@ -1,72 +0,0 @@
|
||||
using ProductionUiCordonel.ProductionProcesses.Enum;
|
||||
using ProductionUiCordonel.UserControls.FinalTest;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Threading;
|
||||
using Xylem.Common.Hardware.WaterMeter.Genesis.Registers;
|
||||
|
||||
namespace ProductionUiCordonel.ProductionProcesses.Actions
|
||||
{
|
||||
public class ProductionProcessRegisterWatch : BaseProductionProcess
|
||||
{
|
||||
private UcFullReadOut UserControl;
|
||||
public ProductionProcessRegisterWatch()
|
||||
{
|
||||
name = "Sicherung des Zählerzustandes";
|
||||
currentProcessState = ProductionProcessState.Waiting;
|
||||
}
|
||||
|
||||
public override void InitUserControl()
|
||||
{
|
||||
UserControl = new UcFullReadOut();
|
||||
}
|
||||
|
||||
public override UserControl GetControl()
|
||||
{
|
||||
if (UserControl == null)
|
||||
{
|
||||
throw new Exception($"UserControl {GetType()} not Ready");
|
||||
}
|
||||
return UserControl;
|
||||
}
|
||||
|
||||
public override void ProcessDone()
|
||||
{
|
||||
//clear
|
||||
}
|
||||
|
||||
public override void StartProcess()
|
||||
{
|
||||
|
||||
UserControl.lblHl.Dispatcher.Invoke(DispatcherPriority.Send,
|
||||
new Action(() => { UserControl.lblHl.Content = "Read out Registers"; }
|
||||
));
|
||||
|
||||
var total = Meter.GetRegistersDic().Keys.Where(n => n.RegisterName == "TemperatureMeasurePeriod" || n.RegisterName == "PressureMeasurePeriod" || n.RegisterName == "METROLOGYASST_PressureRate").ToList();
|
||||
var done = 0;
|
||||
foreach (var dic in total)
|
||||
{
|
||||
var ret = Meter.ReadRegister(dic.GetIdent());
|
||||
|
||||
if (dic.AppName == "SENSUSRADIO")
|
||||
{
|
||||
Meter.WriteLog($"Register Watch: {dic.RegisterName} = { RegisterConverter.ConvertTo<UInt16>(ret)}");
|
||||
}
|
||||
else
|
||||
{
|
||||
Meter.WriteLog($"Register Watch: {dic.RegisterName} = { RegisterConverter.ConvertTo<UInt32>(ret)}");
|
||||
}
|
||||
}
|
||||
done += 1;
|
||||
|
||||
|
||||
//Meter.StoreCurrentRegisterDic();
|
||||
//Meter.Configuration.UseRegisterWatchService = oldConfigEntry;
|
||||
|
||||
currentProcessState = ProductionProcessState.Done;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
-258
@@ -1,258 +0,0 @@
|
||||
using ProductionUiCordonel.ProductionProcesses.Enum;
|
||||
using ProductionUiCordonel.UserControls.FinalTest;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Windows.Controls;
|
||||
using Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore;
|
||||
using Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile;
|
||||
|
||||
namespace ProductionUiCordonel.ProductionProcesses.Actions
|
||||
{
|
||||
public class ProductionProcessShippingMode : BaseProductionProcess
|
||||
{
|
||||
private UcPlain UserControl;
|
||||
private Boolean doRestart;
|
||||
private Boolean hasRadio;
|
||||
public ProductionProcessShippingMode(Boolean restart = false, Boolean registerHasRadio = true)
|
||||
{
|
||||
name = "Versandbereitschaft herstellen";
|
||||
currentProcessState = ProductionProcessState.Waiting;
|
||||
doRestart = restart;
|
||||
hasRadio = registerHasRadio;
|
||||
}
|
||||
public override void InitUserControl()
|
||||
{
|
||||
UserControl = new UcPlain();
|
||||
UserControl.lblHl.Content = name;
|
||||
UserControl.lblText.Content = "Display und Alarme für den Kunden einstellen.";
|
||||
}
|
||||
|
||||
public override UserControl GetControl()
|
||||
{
|
||||
if (UserControl == null)
|
||||
{
|
||||
throw new Exception($"UserControl {GetType()} not Ready");
|
||||
}
|
||||
return UserControl;
|
||||
}
|
||||
|
||||
|
||||
public override void ProcessDone()
|
||||
{
|
||||
//clear
|
||||
}
|
||||
|
||||
public override void StartProcess()
|
||||
{
|
||||
|
||||
|
||||
hasRadio = Meter.RadioFrequencyMhz.HasValue;
|
||||
|
||||
|
||||
|
||||
if (hasRadio)
|
||||
{
|
||||
if (Meter.StoreAllConfigurations())
|
||||
{
|
||||
if (doRestart)
|
||||
{
|
||||
var CheckValuesAfterBoot = new List<Tuple<String, Byte[]>>
|
||||
{
|
||||
new Tuple<String, Byte[]>("METROLOGYASST_PulseLength",
|
||||
Meter.ReadRegister("METROLOGYASST_PulseLength")),
|
||||
new Tuple<String, Byte[]>("POWERMON_BatteryQuantity",
|
||||
Meter.ReadRegister("POWERMON_BatteryQuantity")),
|
||||
new Tuple<String, Byte[]>("GENESISFLOW_MeterSize", Meter.ReadRegister("GENESISFLOW_MeterSize")),
|
||||
new Tuple<String, Byte[]>("GENESISFLOW_CalFactor1", Meter.ReadRegister("GENESISFLOW_CalFactor1")),
|
||||
new Tuple<String, Byte[]>("SENSUSRADIO_RadioAddress", Meter.ReadRegister("SENSUSRADIO_RadioAddress"))
|
||||
};
|
||||
var _meterResetPsu = new MeterResetPsu(Meter)
|
||||
{
|
||||
StoreConfigEnable = true
|
||||
};
|
||||
var rebootSucceeded = _meterResetPsu.MeterResetPsuExecute();
|
||||
|
||||
Thread.Sleep(10000);
|
||||
if (!Meter.Login())
|
||||
|
||||
{
|
||||
Meter.WriteLog("relogin first attempt Failed");
|
||||
Thread.Sleep(5000);
|
||||
if (!Meter.Login())
|
||||
{
|
||||
Meter.WriteLog("relogins Failed");
|
||||
currentProcessState = ProductionProcessState.Error;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Boolean? hasDiffrences = null;
|
||||
foreach (var item in CheckValuesAfterBoot)
|
||||
{
|
||||
if (!item.Item2.SequenceEqual(Meter.ReadRegister(item.Item1)))
|
||||
{
|
||||
hasDiffrences = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!hasDiffrences.HasValue)
|
||||
{
|
||||
hasDiffrences = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (rebootSucceeded && hasDiffrences.HasValue && !hasDiffrences.Value)
|
||||
{
|
||||
|
||||
Meter.WriteRegister("SENSUSRADIO_SystemState", 0xFF);
|
||||
Meter.Logout();
|
||||
Thread.Sleep(5000);
|
||||
if (!Meter.Login())
|
||||
{
|
||||
Meter.WriteLog("relogin first attempt Failed");
|
||||
Thread.Sleep(5000);
|
||||
|
||||
if (!Meter.Login())
|
||||
{
|
||||
Meter.WriteLog("relogin Failed");
|
||||
currentProcessState = ProductionProcessState.Error;
|
||||
}
|
||||
}
|
||||
var SENSUSRADIO_MainAlarmMask = Meter.ReadRegister("SENSUSRADIO_MainAlarmMask");
|
||||
var SENSUSRADIO_ExtendedAlarmMask = Meter.ReadRegister("SENSUSRADIO_ExtendedAlarmMask");
|
||||
var SENSUSRADIO_SystemState = Meter.ReadRegister("SENSUSRADIO_SystemState");
|
||||
if (SENSUSRADIO_SystemState[0] == 0x02 && SENSUSRADIO_MainAlarmMask[0] != 0)
|
||||
{
|
||||
currentProcessState = ProductionProcessState.Done;
|
||||
}
|
||||
else
|
||||
{
|
||||
Meter.WriteLog("resetRadio Failed");
|
||||
currentProcessState = ProductionProcessState.Error;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
Meter.WriteLog("reboot compare failed");
|
||||
currentProcessState = ProductionProcessState.Error;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Meter.ResetAlarm(GenesisMeter.Alarm.ALL);//(true, new byte[] { 0x00, 0x00, 0x00, 0x01 });
|
||||
|
||||
Meter.SetLcdText(true, new Byte[] { 0x00, 0x00, 0x00, 0x01 });
|
||||
|
||||
Meter.ResetAlarm(GenesisMeter.Alarm.EMPTY_PIPE);//(true, new byte[] { 0x00, 0x00, 0x00, 0x01 });
|
||||
|
||||
Meter.WriteRegister("SENSUSRADIO_SystemState", 0xFF);
|
||||
Meter.Logout();
|
||||
Thread.Sleep(5000);
|
||||
if (!Meter.Login())
|
||||
{
|
||||
Thread.Sleep(5000);
|
||||
if (!Meter.Login())
|
||||
{
|
||||
currentProcessState = ProductionProcessState.Error;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
var SENSUSRADIO_MainAlarmMask = Meter.ReadRegister("SENSUSRADIO_MainAlarmMask");
|
||||
var SENSUSRADIO_ExtendedAlarmMask = Meter.ReadRegister("SENSUSRADIO_ExtendedAlarmMask");
|
||||
var SENSUSRADIO_SystemState = Meter.ReadRegister("SENSUSRADIO_SystemState");
|
||||
if (SENSUSRADIO_SystemState[0] == 0x02 && SENSUSRADIO_MainAlarmMask[0] != 0)
|
||||
{
|
||||
currentProcessState = ProductionProcessState.Done;
|
||||
}
|
||||
else
|
||||
{
|
||||
Meter.WriteLog("resetRadio Failed");
|
||||
currentProcessState = ProductionProcessState.Error;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
currentProcessState = ProductionProcessState.Error;
|
||||
}
|
||||
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Meter.StoreAllConfigurations())
|
||||
{
|
||||
if (doRestart)
|
||||
{
|
||||
var CheckValuesAufterBoot = new List<Tuple<String, Byte[]>>();
|
||||
CheckValuesAufterBoot.Add(new Tuple<String, Byte[]>("METROLOGYASST_PulseLength", Meter.ReadRegister("METROLOGYASST_PulseLength")));
|
||||
CheckValuesAufterBoot.Add(new Tuple<String, Byte[]>("POWERMON_BatteryQuantity", Meter.ReadRegister("POWERMON_BatteryQuantity")));
|
||||
CheckValuesAufterBoot.Add(new Tuple<String, Byte[]>("GENESISFLOW_MeterSize", Meter.ReadRegister("GENESISFLOW_MeterSize")));
|
||||
CheckValuesAufterBoot.Add(new Tuple<String, Byte[]>("GENESISFLOW_CalFactor1", Meter.ReadRegister("GENESISFLOW_CalFactor1")));
|
||||
|
||||
var _meterResetPsu = new MeterResetPsu(Meter)
|
||||
{
|
||||
StoreConfigEnable = true
|
||||
};
|
||||
var rebootSucceeded = _meterResetPsu.MeterResetPsuExecute();
|
||||
|
||||
Thread.Sleep(10000);
|
||||
Meter.Login();
|
||||
|
||||
|
||||
Boolean? hasDiffrences = null;
|
||||
foreach (var item in CheckValuesAufterBoot)
|
||||
{
|
||||
if (!item.Item2.SequenceEqual(Meter.ReadRegister(item.Item1)))
|
||||
{
|
||||
hasDiffrences = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!hasDiffrences.HasValue)
|
||||
{
|
||||
hasDiffrences = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Meter.ResetAlarm(GenesisMeter.Alarm.ALL);//(true, new byte[] { 0x00, 0x00, 0x00, 0x01 });
|
||||
|
||||
Meter.SetLcdText(true, new Byte[] { 0x00, 0x00, 0x00, 0x01 });
|
||||
|
||||
Meter.ResetAlarm(GenesisMeter.Alarm.EMPTY_PIPE);//(true, new byte[] { 0x00, 0x00, 0x00, 0x01 });
|
||||
|
||||
if (rebootSucceeded && hasDiffrences.HasValue && !hasDiffrences.Value)
|
||||
{
|
||||
currentProcessState = ProductionProcessState.Done;
|
||||
}
|
||||
else
|
||||
{
|
||||
Meter.WriteLog("reboot compare failed");
|
||||
currentProcessState = ProductionProcessState.Error;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
currentProcessState = ProductionProcessState.Done;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
currentProcessState = ProductionProcessState.Error;
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
-162
@@ -1,162 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Windows.Controls;
|
||||
using ProductionUiCordonel.ProductionProcesses.Enum;
|
||||
using ProductionUiCordonel.UserControls.FinalTest;
|
||||
|
||||
namespace ProductionUiCordonel.ProductionProcesses.Actions
|
||||
{
|
||||
public class ProductionProcessSpecialConfig : BaseProductionProcess
|
||||
{
|
||||
private UcDialog UserControl;
|
||||
|
||||
public Boolean DialogIsDone { get; }
|
||||
|
||||
public ProductionProcessSpecialConfig()
|
||||
{
|
||||
DialogIsDone = false;
|
||||
name = "Customer Parameterization";
|
||||
currentProcessState = ProductionProcessState.Waiting;
|
||||
}
|
||||
public override void InitUserControl()
|
||||
{
|
||||
UserControl = new UcDialog();
|
||||
}
|
||||
|
||||
public override UserControl GetControl()
|
||||
{
|
||||
if (UserControl == null)
|
||||
{
|
||||
throw new Exception($"UserControl {GetType()} not Ready");
|
||||
}
|
||||
return UserControl;
|
||||
}
|
||||
|
||||
|
||||
public override void ProcessDone()
|
||||
{
|
||||
//clear
|
||||
}
|
||||
|
||||
private void StepDone()
|
||||
{
|
||||
currentProcessState = ProductionProcessState.Done;
|
||||
}
|
||||
|
||||
private void StepRadio()
|
||||
{
|
||||
|
||||
UserControl.SetDesc("Set EncryptionKey");
|
||||
var radioOptionList = new List<UcDialog.DialogOption>();
|
||||
var radioDefault = new UcDialog.DialogOption("old default", "same as iperl", () =>
|
||||
{
|
||||
|
||||
var funkadresse = new List<Byte>();
|
||||
funkadresse.AddRange((new Byte[] { 0xE6, 0xC8, 0x88, 0x00 }).ToArray());
|
||||
funkadresse.AddRange((new Byte[] { 0xDE, 0xB8, 0x68, 0xC0 }).ToArray());
|
||||
funkadresse.AddRange((new Byte[] { 0xD6, 0xA8, 0x48, 0x80 }).ToArray());
|
||||
funkadresse.AddRange((new Byte[] { 0xCE, 0x98, 0x28, 0x40 }).ToArray());
|
||||
Meter.WriteRegister("SENSUSRADIO_EncryptionKey", funkadresse.ToArray(), true, true);
|
||||
StepDone();
|
||||
|
||||
});
|
||||
|
||||
var upRadioOnly = new UcDialog.DialogOption("alpha", "000...", () =>
|
||||
{
|
||||
Meter.WriteRegister("SENSUSRADIO_EncryptionKey", (new Byte[]
|
||||
{
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
}).ToArray(), true, true);
|
||||
StepDone();
|
||||
|
||||
});
|
||||
|
||||
var optOneLiter = new UcDialog.DialogOption("new default", "new default key", () =>
|
||||
{
|
||||
var funkadresse = new List<Byte>();
|
||||
funkadresse.AddRange((new Byte[] { 0x0E, 0x9F, 0xAC, 0xC6 }).ToArray());
|
||||
funkadresse.AddRange((new Byte[] { 0xA0, 0xE1, 0xEF, 0x1C }).ToArray());
|
||||
funkadresse.AddRange((new Byte[] { 0x3B, 0x27, 0xA4, 0x9B }).ToArray());
|
||||
funkadresse.AddRange((new Byte[] { 0xAC, 0x21, 0x65, 0x35 }).ToArray());
|
||||
Meter.WriteRegister("SENSUSRADIO_EncryptionKey", funkadresse.ToArray(), true, true);
|
||||
StepDone();
|
||||
});
|
||||
|
||||
radioOptionList.Add(radioDefault);
|
||||
radioOptionList.Add(upRadioOnly);
|
||||
radioOptionList.Add(optOneLiter);
|
||||
|
||||
UserControl.SetDialogOptions(radioOptionList);
|
||||
}
|
||||
private void StepWakeUp()
|
||||
{
|
||||
UserControl.SetDesc("Set Radio WakeUp");
|
||||
var wakeupOptionList = new List<UcDialog.DialogOption>();
|
||||
var wakeUpDefault = new UcDialog.DialogOption("wakeup Water and Radio", "Default for nearly all", () =>
|
||||
{
|
||||
Meter.WriteRegister("SENSUSRADIO_WakeupInterval", (new Byte[] { 0x00, 0x00, 0x00, 0x03 }).Reverse().ToArray(), true, true);
|
||||
StepRadio();
|
||||
});
|
||||
|
||||
var wakeUpRadioOnly = new UcDialog.DialogOption("wakeup only Radio", "WakeupInterval to 6 (only radio)", () =>
|
||||
{
|
||||
Meter.WriteRegister("SENSUSRADIO_WakeupInterval", (new Byte[] { 0x00, 0x00, 0x00, 0x06 }).Reverse().ToArray(), true, true);
|
||||
StepRadio();
|
||||
});
|
||||
|
||||
var pulseOptOneLiter = new UcDialog.DialogOption("wakeup off", "WakeupInterval to 0, no Radio active (e.g. USA))", () =>
|
||||
{
|
||||
Meter.WriteRegister("SENSUSRADIO_WakeupInterval", (new Byte[] { 0x00, 0x00, 0x00, 0x00 }).Reverse().ToArray(), true, true);
|
||||
StepRadio();
|
||||
});
|
||||
|
||||
wakeupOptionList.Add(wakeUpDefault);
|
||||
wakeupOptionList.Add(wakeUpRadioOnly);
|
||||
wakeupOptionList.Add(pulseOptOneLiter);
|
||||
|
||||
UserControl.SetDialogOptions(wakeupOptionList);
|
||||
}
|
||||
|
||||
private void StepPulse()
|
||||
{
|
||||
UserControl.SetDesc("Set Pulse Configuration");
|
||||
var pulseOptionList = new List<UcDialog.DialogOption>();
|
||||
var pulseOptOff = new UcDialog.DialogOption("Pulse off", "set pulsemode to off", () =>
|
||||
{
|
||||
Meter.WriteRegister("METROLOGYASST_PulseLength", (new Byte[] { 0x00, 0x00, 0x00, 0x07 }).Reverse().ToArray(), true, true);
|
||||
Meter.WriteRegister("METROLOGYASST_PulseMode", (new Byte[] { 0x00, 0x00, 0x00, 0x00 }).Reverse().ToArray(), true, true);
|
||||
Meter.WriteRegister("METROLOGYASST_PulseWeight", (new Byte[] { 0x00, 0x00, 0x27, 0x10 }).Reverse().ToArray(), true, true);
|
||||
StepWakeUp();
|
||||
});
|
||||
|
||||
var pulseOptDefault = new UcDialog.DialogOption("Pulse Default", "1 pulse per 10 l, pulse mode a4 and 200ms pulse length", () =>
|
||||
{
|
||||
Meter.WriteRegister("METROLOGYASST_PulseLength", (new Byte[] { 0x00, 0x00, 0x00, 0x07 }).Reverse().ToArray(), true, true);
|
||||
Meter.WriteRegister("METROLOGYASST_PulseMode", (new Byte[] { 0x00, 0x00, 0x00, 0x01 }).Reverse().ToArray(), true, true);
|
||||
Meter.WriteRegister("METROLOGYASST_PulseWeight", (new Byte[] { 0x00, 0x00, 0x27, 0x10 }).Reverse().ToArray(), true, true);
|
||||
StepWakeUp();
|
||||
});
|
||||
|
||||
var pulseOptOneLiter = new UcDialog.DialogOption("One Liter Pulse", "1 pulse per 1l, pulse mode a4 and 20ms pulse length", () =>
|
||||
{
|
||||
Meter.WriteRegister("METROLOGYASST_PulseLength", (new Byte[] { 0x00, 0x00, 0x00, 0x04 }).Reverse().ToArray(), true, true);
|
||||
Meter.WriteRegister("METROLOGYASST_PulseMode", (new Byte[] { 0x00, 0x00, 0x00, 0x01 }).Reverse().ToArray(), true, true);
|
||||
Meter.WriteRegister("METROLOGYASST_PulseWeight", (new Byte[] { 0x00, 0x00, 0x03, 0xE8 }).Reverse().ToArray(), true, true);
|
||||
StepWakeUp();
|
||||
});
|
||||
|
||||
pulseOptionList.Add(pulseOptOff);
|
||||
pulseOptionList.Add(pulseOptDefault);
|
||||
pulseOptionList.Add(pulseOptOneLiter);
|
||||
|
||||
UserControl.SetDialogOptions(pulseOptionList);
|
||||
}
|
||||
|
||||
public override void StartProcess()
|
||||
{
|
||||
StepPulse();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -3,7 +3,7 @@ using System.Collections.Generic;
|
||||
using Xylem.Common.CommonCore.Consts;
|
||||
using Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.Enum;
|
||||
using Xylem.Common.Production.ProductionUiCordonel.Properties;
|
||||
using Xylem.Common.Production.ProductionUiCordonel.UserControls.FinalTest;
|
||||
using Xylem.Common.Production.ProductionUiCordonel.UserControls;
|
||||
|
||||
namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.EolProcesses
|
||||
{
|
||||
|
||||
+2
-2
@@ -2,9 +2,9 @@
|
||||
using Xylem.Common.CommonCore.Consts;
|
||||
using Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.Enum;
|
||||
using Xylem.Common.Production.ProductionUiCordonel.Properties;
|
||||
using Xylem.Common.Production.ProductionUiCordonel.UserControls.FinalTest;
|
||||
using Xylem.Common.Production.ProductionUiCordonel.UserControls;
|
||||
|
||||
namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.EolProcesses
|
||||
namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.GenericProcesses
|
||||
{
|
||||
public class CheckOrderNumber : BaseProductionProcess
|
||||
{
|
||||
+2
-2
@@ -2,9 +2,9 @@
|
||||
using Xylem.Common.CommonCore.Consts;
|
||||
using Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.Enum;
|
||||
using Xylem.Common.Production.ProductionUiCordonel.Properties;
|
||||
using Xylem.Common.Production.ProductionUiCordonel.UserControls.FinalTest;
|
||||
using Xylem.Common.Production.ProductionUiCordonel.UserControls;
|
||||
|
||||
namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.EolProcesses
|
||||
namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.GenericProcesses
|
||||
{
|
||||
public class CheckSerialNumber : BaseProductionProcess
|
||||
{
|
||||
+1
-1
@@ -3,7 +3,7 @@ using Xylem.Common.CommonCore.Consts;
|
||||
using Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.Enum;
|
||||
using Xylem.Common.Production.ProductionUiCordonel.Properties;
|
||||
|
||||
namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.EolProcesses
|
||||
namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.GenericProcesses
|
||||
{
|
||||
public class ConnectCordonel : BaseProductionProcess
|
||||
{
|
||||
+1
-1
@@ -3,7 +3,7 @@ using Xylem.Common.CommonCore.Consts;
|
||||
using Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.Enum;
|
||||
using Xylem.Common.Production.ProductionUiCordonel.Properties;
|
||||
|
||||
namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.EolProcesses
|
||||
namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.GenericProcesses
|
||||
{
|
||||
/// <summary>
|
||||
/// Production process detects the serial number of the Cordonel.
|
||||
+2
-2
@@ -3,9 +3,9 @@ using System.Collections.Generic;
|
||||
using Xylem.Common.CommonCore.Consts;
|
||||
using Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.Enum;
|
||||
using Xylem.Common.Production.ProductionUiCordonel.Properties;
|
||||
using Xylem.Common.Production.ProductionUiCordonel.UserControls.FinalTest;
|
||||
using Xylem.Common.Production.ProductionUiCordonel.UserControls;
|
||||
|
||||
namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.EolProcesses
|
||||
namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.GenericProcesses
|
||||
{
|
||||
public class ErrorHandler : BaseProductionProcess
|
||||
{
|
||||
+1
-1
@@ -8,7 +8,7 @@ using Xylem.Common.Logic.SoftwareAccessHelper;
|
||||
using Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.Enum;
|
||||
using Xylem.Common.Production.ProductionUiCordonel.Properties;
|
||||
|
||||
namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.EolProcesses
|
||||
namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.GenericProcesses
|
||||
{
|
||||
/// <summary>
|
||||
/// Request the serial number and radio address from DB.
|
||||
@@ -0,0 +1,104 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.Enum;
|
||||
|
||||
namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses
|
||||
{
|
||||
public interface IProcessStateDef
|
||||
{
|
||||
/// <summary>
|
||||
/// Collection of state information
|
||||
/// </summary>
|
||||
List<ProcessStateStruct> StateContainer { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Get the process start struct linked to state of state machine
|
||||
/// </summary>
|
||||
/// <param name="stateMachineState">state to search for information text</param>
|
||||
/// <returns>process state struct of the attached state</returns>
|
||||
/// <remarks date="2025-Apr-15" author="Thomas Wiedebusch">
|
||||
/// - Initial
|
||||
/// </remarks>
|
||||
ProcessStateStruct GetProcessStateStructOfState(ProcessState stateMachineState);
|
||||
|
||||
/// <summary>
|
||||
/// Get the process linked to state of state machine
|
||||
/// </summary>
|
||||
/// <param name="stateMachineState">state to search for information text</param>
|
||||
/// <returns>process attached to the state</returns>
|
||||
/// <remarks date="2023-Feb-14" author="Thomas Wiedebusch">
|
||||
/// - Initial
|
||||
/// </remarks>
|
||||
IProductionProcess GetProcessOfState(ProcessState stateMachineState);
|
||||
|
||||
/// <summary>
|
||||
/// Get the current information of the state machine state
|
||||
/// </summary>
|
||||
/// <param name="stateMachineState">state to search for information text</param>
|
||||
/// <returns>information attached to state depending on region</returns>
|
||||
/// <remarks date="2023-Feb-14" author="Thomas Wiedebusch">
|
||||
/// - Initial
|
||||
/// </remarks>
|
||||
/// <remarks date="2024-Mar-18" author="Thomas Wiedebusch">
|
||||
/// - If state == null return error message.
|
||||
/// </remarks>
|
||||
String GetStateInfoOfState(ProcessState? stateMachineState);
|
||||
|
||||
/// <summary>
|
||||
/// Get the info text from production process
|
||||
/// </summary>
|
||||
/// <param name="process">process to look for state info text</param>
|
||||
/// <returns>information attached to process depending on region</returns>
|
||||
/// <remarks date="2023-Mar-20" author="Thomas Wiedebusch">
|
||||
/// - Initial
|
||||
/// </remarks>
|
||||
String GetStateInfoOfProcess(IProductionProcess process);
|
||||
|
||||
/// <summary>
|
||||
/// Get the state machine state of the text
|
||||
/// </summary>
|
||||
/// <param name="text">information text to search if state is assigned</param>
|
||||
/// <returns>state attached to information text</returns>
|
||||
/// <remarks date="2023-Feb-14" author="Thomas Wiedebusch">
|
||||
/// - Initial
|
||||
/// </remarks>
|
||||
ProcessState GetStateOfInfoText(String text);
|
||||
|
||||
/// <summary>
|
||||
/// Get the state machine state from for the process
|
||||
/// </summary>
|
||||
/// <param name="process">process to look for state info text</param>
|
||||
/// <returns>state attached to process</returns>
|
||||
/// <remarks date="2023-Mar-20" author="Thomas Wiedebusch">
|
||||
/// - Initial
|
||||
/// </remarks>
|
||||
ProcessState GetStateOfProcess(IProductionProcess process);
|
||||
|
||||
/// <summary>
|
||||
/// Get number of EOL relevant processes for statistic e.g. progress bar
|
||||
/// </summary>
|
||||
/// <returns>number of initialized processes</returns>
|
||||
/// <remarks date="2023-Mar-20" author="Thomas Wiedebusch">
|
||||
/// - Initial
|
||||
/// </remarks>
|
||||
/// <remarks date="2024-Sep-01" author="Thomas Wiedebusch">
|
||||
/// - Used marker for production relevant processes
|
||||
/// </remarks>
|
||||
Int32 GetNumberOfInitializedProcesses();
|
||||
|
||||
/// <summary>
|
||||
/// Get a sorted list of all production processes in order of the execution sequence
|
||||
/// </summary>
|
||||
/// <returns>list of initialized processes</returns>
|
||||
/// <remarks date="2024-Jul-15" author="Thomas Wiedebusch">
|
||||
/// - Initial
|
||||
/// </remarks>
|
||||
/// <remarks date="2024-Sep-01" author="Thomas Wiedebusch">
|
||||
/// - Used marker for production relevant processes
|
||||
/// </remarks>
|
||||
/// <remarks date="2025-Apr-14" author="Thomas Wiedebusch">
|
||||
/// - Changed to sorted list by production process number
|
||||
/// </remarks>
|
||||
List<IProductionProcess> GetAllEolRelevantProcesses();
|
||||
}
|
||||
}
|
||||
+840
@@ -0,0 +1,840 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using Logic.ProductionToProductMapper.Files.Fw;
|
||||
using Xylem.Common.CommonCore.Consts;
|
||||
using Xylem.Common.Hardware.WaterMeter.Genesis.Applications;
|
||||
using Xylem.Common.Hardware.WaterMeter.Genesis.Applications.Const;
|
||||
using Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore;
|
||||
using Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile;
|
||||
using Xylem.Common.Hardware.WaterMeter.Genesis.GenesisStatus;
|
||||
using Xylem.Common.Logic.ProductionOrderCore.OrderData;
|
||||
using Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.GenericProcesses;
|
||||
using Xylem.Common.Production.ProductionUiCordonel.Properties;
|
||||
|
||||
namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.PickingProcesses
|
||||
{
|
||||
/// <summary>
|
||||
/// Check all parameters needed as preparation for assembly.
|
||||
/// </summary>
|
||||
public class CheckProductionState : BaseProductionProcess
|
||||
{
|
||||
/// <summary>
|
||||
/// Maximum of expected processing steps for this process to feed the GUI progress bar.
|
||||
/// </summary>
|
||||
private const Int32 MaxActualProgressSteps = 13;
|
||||
|
||||
/// <summary>
|
||||
/// FW update package containing the ABC and the ADF.
|
||||
/// </summary>
|
||||
public List<FilePart> FwUpdatePackage
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ctor
|
||||
/// </summary>
|
||||
public CheckProductionState(String name) : base(name)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Start database calls and meter readouts here for better testability and ability to fill the
|
||||
/// objects manually by the test routine.
|
||||
/// </summary>
|
||||
/// <remarks date="2025-Mai-15" author="Thomas Wiedebusch">
|
||||
/// - Initial.
|
||||
/// </remarks>
|
||||
public override StatusReturn PreExecuteProcess()
|
||||
{
|
||||
if (Meter == null || string.IsNullOrEmpty(Meter.PcbId) || Meter.PcbId.Length < GenesisMeter.MinPcbIdLength)
|
||||
{
|
||||
Meter?.WriteLog("PcbId requirements do not match");
|
||||
return StatusReturn.Failed;
|
||||
}
|
||||
|
||||
// Some statistics for GUI and internal processing
|
||||
SignalRunningState(MaxActualProgressSteps);
|
||||
|
||||
// Get the requirement (Standard or special)
|
||||
if (!GenesisStatusHandler.GetCordonelRequirementInfoFromDb(Meter.PcbId, ProductionRequirements,
|
||||
out var error) || ProductionRequirements == null)
|
||||
{
|
||||
Meter.WriteLog(error);
|
||||
ErrorMsgDispatcher(Resources.StrErrorMsgProductionRequirements);
|
||||
return StatusReturn.Failed;
|
||||
}
|
||||
|
||||
// Exit if meanwhile cancellation is required
|
||||
if (CancellationToken.IsCancellationRequested)
|
||||
return CancellationProcedure();
|
||||
|
||||
ActualProcessProgress++;
|
||||
|
||||
// Get clustered FileId of firmware package for production or on special requirement release candidates
|
||||
var isSpecialActive = ProductionRequirements.IsSpecialActive != null &&
|
||||
(Boolean)ProductionRequirements.IsSpecialActive &&
|
||||
ProductionRequirements.IsSpecialApproved != null &&
|
||||
(Boolean)ProductionRequirements.IsSpecialApproved;
|
||||
|
||||
if (string.IsNullOrEmpty(ProductionRequirements.FwVersion) ||
|
||||
!MeterFwUpdate.SearchProdFwInDb(ProductionRequirements.FwVersion, out var parentFileId, out error,
|
||||
!isSpecialActive) || parentFileId == null)
|
||||
{
|
||||
Meter.WriteLog(error);
|
||||
ErrorMsgDispatcher(Resources.StrErrorMsgLoadingFwFromDb);
|
||||
return StatusReturn.Failed;
|
||||
}
|
||||
|
||||
// Exit if meanwhile cancellation is required
|
||||
if (CancellationToken.IsCancellationRequested)
|
||||
return CancellationProcedure();
|
||||
|
||||
ActualProcessProgress++;
|
||||
|
||||
// Get the real content of the FW package including all binaries of each app and the application description file
|
||||
FwUpdatePackage = new List<FilePart>();
|
||||
if (!MeterFwUpdate.GetFwPackageFromDb((Int32)parentFileId, FwUpdatePackage, out error) ||
|
||||
FwUpdatePackage == null)
|
||||
{
|
||||
Meter.WriteLog(error);
|
||||
ErrorMsgDispatcher(Resources.StrErrorMsgLoadingFwFromDb);
|
||||
return StatusReturn.Failed;
|
||||
}
|
||||
|
||||
// Exit if meanwhile cancellation is required
|
||||
if (CancellationToken.IsCancellationRequested)
|
||||
return CancellationProcedure();
|
||||
|
||||
ActualProcessProgress++;
|
||||
|
||||
// Read out the Cordonel and calculate remaining lifetime and fill the ProductionStatus
|
||||
if (!GenesisStatusHandler.BuildLifeTimeInformation(Meter, ProductionStatus, out error))
|
||||
{
|
||||
Meter.WriteLog(error);
|
||||
ErrorMsgDispatcher(Resources.StrErrorMsgLifeTimeCalculation);
|
||||
return StatusReturn.Failed;
|
||||
}
|
||||
|
||||
// Exit if meanwhile cancellation is required
|
||||
if (CancellationToken.IsCancellationRequested)
|
||||
return CancellationProcedure();
|
||||
|
||||
ActualProcessProgress++;
|
||||
|
||||
return StatusReturn.Okay;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check all parameters needed as preparation for completion to validate the status and the
|
||||
/// remaining operational time. This includes special permissions for individual parameters.
|
||||
/// The picking requirements including the special permissions are taken from the DB and can be
|
||||
/// assigned to an order number (meaning for all devices produced under this order) or an individual
|
||||
/// pcbId. The setup and calculation of the exceeded time and drained will be taken from the Cordonel
|
||||
/// (read from registers in POWERMON).
|
||||
/// Precondition: - The <see cref="GetSerialNumberAndRadioAddress"/> process has to
|
||||
/// be completed as the PcbId and the order number is needed.
|
||||
/// Checks:
|
||||
/// - Requirements are collected,
|
||||
/// - PcbId,
|
||||
/// - Region,
|
||||
/// - FW,
|
||||
/// - LUT CRC,
|
||||
/// - Meter size
|
||||
/// - Drained battery load versus required remaining battery load in percent,
|
||||
/// - Remaining run time in years,
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
/// <remarks date="2025-Mai-15" author="Roland Drahbesh">
|
||||
/// - Initial.
|
||||
/// </remarks>
|
||||
public override StatusReturn ExecuteProcess()
|
||||
{
|
||||
#region ----------------------------------- Check Requirements --------------------------------------------
|
||||
|
||||
var statusReturn = CheckRequirements(out var feedbackMsg);
|
||||
if (StatusReturn.Failed == statusReturn)
|
||||
{
|
||||
ErrorMsgDispatcher(feedbackMsg);
|
||||
return StatusReturn.Failed;
|
||||
}
|
||||
|
||||
SuccessMsgDispatcher(feedbackMsg);
|
||||
ActualProcessProgress++;
|
||||
#endregion
|
||||
|
||||
#region ----------------------------------- Check Production Order ----------------------------------------
|
||||
|
||||
// Production order
|
||||
if (StatusReturn.Failed == CheckProductionOrderNumber(out feedbackMsg))
|
||||
{
|
||||
ErrorMsgDispatcher(feedbackMsg);
|
||||
return StatusReturn.Failed;
|
||||
}
|
||||
|
||||
SuccessMsgDispatcher(feedbackMsg);
|
||||
ActualProcessProgress++;
|
||||
#endregion
|
||||
|
||||
#region ----------------------------------- Check PCBID ---------------------------------------------------
|
||||
// PCBID read from meter compared with requirement PcbIds
|
||||
statusReturn = CheckPcbId(out feedbackMsg);
|
||||
|
||||
// Exit here with error
|
||||
if (StatusReturn.Failed == statusReturn)
|
||||
{
|
||||
ErrorMsgDispatcher(feedbackMsg);
|
||||
return StatusReturn.Failed;
|
||||
}
|
||||
|
||||
SuccessMsgDispatcher(feedbackMsg);
|
||||
ActualProcessProgress++;
|
||||
#endregion
|
||||
|
||||
#region ----------------------------------- Check Region --------------------------------------------------
|
||||
|
||||
if (StatusReturn.Failed == CheckRegion(out feedbackMsg))
|
||||
{
|
||||
ErrorMsgDispatcher(feedbackMsg);
|
||||
return StatusReturn.Failed;
|
||||
}
|
||||
|
||||
SuccessMsgDispatcher(feedbackMsg);
|
||||
ActualProcessProgress++;
|
||||
#endregion
|
||||
|
||||
#region ----------------------------------- Check LUT CRC -------------------------------------------------
|
||||
|
||||
if (string.IsNullOrEmpty(CheckLutCrc(out feedbackMsg)))
|
||||
{
|
||||
ErrorMsgDispatcher(feedbackMsg);
|
||||
return StatusReturn.Failed;
|
||||
}
|
||||
|
||||
SuccessMsgDispatcher(feedbackMsg);
|
||||
ActualProcessProgress++;
|
||||
#endregion
|
||||
|
||||
#region ----------------------------------- Check Meter Size ----------------------------------------------
|
||||
|
||||
if (string.IsNullOrEmpty(CheckMeterSize(out feedbackMsg)))
|
||||
{
|
||||
ErrorMsgDispatcher(feedbackMsg);
|
||||
return StatusReturn.Failed;
|
||||
}
|
||||
|
||||
SuccessMsgDispatcher(feedbackMsg);
|
||||
ActualProcessProgress++;
|
||||
#endregion
|
||||
|
||||
#region ----------------------------------- Check Firmware and Apps ---------------------------------------
|
||||
|
||||
if (string.IsNullOrEmpty(CheckFwAndApps(out feedbackMsg)))
|
||||
{
|
||||
ErrorMsgDispatcher(feedbackMsg);
|
||||
return StatusReturn.Failed;
|
||||
}
|
||||
|
||||
SuccessMsgDispatcher(feedbackMsg);
|
||||
ActualProcessProgress++;
|
||||
#endregion
|
||||
|
||||
#region ----------------------------------- Check Remaining Battery Load ----------------------------------
|
||||
|
||||
var erroneousSequenceStep = false;
|
||||
if (StatusReturn.Failed == CheckRemainingBatteryLoad(out feedbackMsg))
|
||||
{
|
||||
ErrorMsgDispatcher(feedbackMsg);
|
||||
//return StatusReturn.Failed;
|
||||
// Do not return immediately to avoid multiple special-requirements on multiple errors
|
||||
erroneousSequenceStep = true;
|
||||
}
|
||||
SuccessMsgDispatcher(feedbackMsg);
|
||||
|
||||
ActualProcessProgress++;
|
||||
#endregion
|
||||
|
||||
#region ----------------------------------- Check Remaining Life Time -------------------------------------
|
||||
|
||||
if (StatusReturn.Failed == CheckRemainingLifetime(out feedbackMsg))
|
||||
{
|
||||
ErrorMsgDispatcher(feedbackMsg);
|
||||
//return StatusReturn.Failed;
|
||||
// Do not return immediately to avoid multiple special-requirements on multiple errors
|
||||
erroneousSequenceStep = true;
|
||||
}
|
||||
SuccessMsgDispatcher(feedbackMsg);
|
||||
|
||||
ActualProcessProgress++;
|
||||
#endregion
|
||||
|
||||
#region ----------------------------------- Check Storage Months ------------------------------------------
|
||||
|
||||
if (StatusReturn.Failed == CheckStorageMonths(out feedbackMsg))
|
||||
{
|
||||
ErrorMsgDispatcher(feedbackMsg);
|
||||
//return StatusReturn.Failed;
|
||||
// Do not return immediately to avoid multiple special-requirements on multiple errors
|
||||
erroneousSequenceStep = true;
|
||||
}
|
||||
SuccessMsgDispatcher(feedbackMsg);
|
||||
|
||||
ActualProcessProgress++;
|
||||
#endregion
|
||||
|
||||
#region ----------------------------------- Summarize Check Results ---------------------------------------
|
||||
|
||||
// One or more checks failed
|
||||
if (erroneousSequenceStep)
|
||||
return StatusReturn.Failed;
|
||||
|
||||
// Here everything went fine
|
||||
SuccessMsgDispatcher(feedbackMsg);
|
||||
|
||||
ActualProcessProgress++;
|
||||
|
||||
// All test successfully passed reaching this line
|
||||
return StatusReturn.Okay;
|
||||
#endregion -------------------------------- Summarize Check Results ---------------------------------------
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Common routine to exit with error and user window with error message
|
||||
/// </summary>
|
||||
/// <param name="errorMsg"></param>
|
||||
/// <remarks date="2024-Nov-06" author="Thomas Wiedebusch">
|
||||
/// - Extracted from <see cref="ExecuteProcess"/> for better testability.
|
||||
/// </remarks>
|
||||
private StatusReturn ExitWithErrorAndUserWindow(String errorMsg)
|
||||
{
|
||||
ErrorMsgDispatcher(errorMsg);
|
||||
MessageBox.Show(errorMsg, Resources.StrProcessStateError, MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
return StatusReturn.Failed;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check for requirement permission special or standard or none:
|
||||
/// - If the special requirement is active all fields a filled with the according values from this "special"
|
||||
/// requirement,
|
||||
/// - Else those fields contain the "standard" requirements!
|
||||
///
|
||||
/// Software Requirement Specification:
|
||||
/// [SRS_TBF_PICK_PP_CHECK_PROD_STATE_001]_Check_Requirements
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="feedbackMsg"></param>
|
||||
/// <returns></returns>
|
||||
/// <remarks date="2025-Mai-15" author="Thomas Wiedebusch">
|
||||
/// - Initial.
|
||||
/// </remarks>
|
||||
private StatusReturn CheckRequirements(out String feedbackMsg)
|
||||
{
|
||||
feedbackMsg = "";
|
||||
if (ProductionRequirements == null)
|
||||
{
|
||||
feedbackMsg = Resources.StrErrorMsgProductionRequirements;
|
||||
return StatusReturn.Failed;
|
||||
}
|
||||
|
||||
// Check if requirement is active (free for production) and approved by a second person. Priority special
|
||||
// requirement.
|
||||
var isSpecialActive = false;
|
||||
var isStandardActive = false;
|
||||
if (ProductionRequirements.IsSpecialActive != null && (Boolean)ProductionRequirements.IsSpecialActive &&
|
||||
ProductionRequirements.IsSpecialApproved != null && (Boolean)ProductionRequirements.IsSpecialApproved)
|
||||
isSpecialActive = true;
|
||||
if (ProductionRequirements.IsStandardActive != null && (Boolean)ProductionRequirements.IsStandardActive &&
|
||||
ProductionRequirements.IsStandardApproved != null && (Boolean)ProductionRequirements.IsStandardApproved)
|
||||
isStandardActive = true;
|
||||
|
||||
// At least one requirement needs to be active and a requirement number and version has to be set
|
||||
if ((!isStandardActive && !isSpecialActive) ||
|
||||
// The standard Id and version have always to be set even if the special is active
|
||||
ProductionRequirements.StandardId == null || ProductionRequirements.StandardVersion == null ||
|
||||
// If the special is active the version and Id have to be defined
|
||||
(isSpecialActive && (ProductionRequirements.SpecialId == null ||
|
||||
ProductionRequirements.SpecialVersion == null)))
|
||||
{
|
||||
feedbackMsg = Resources.StrErrorMsgRequirementInactive;
|
||||
return StatusReturn.Failed;
|
||||
}
|
||||
|
||||
feedbackMsg = isSpecialActive &&
|
||||
ProductionRequirements.SpecialId != null &&
|
||||
ProductionRequirements.SpecialVersion != null ?
|
||||
Resources.StrWarningMsgSpecialRequirementActive +
|
||||
$" Id.Ver: {ProductionRequirements.SpecialId}.{ProductionRequirements.SpecialVersion}" :
|
||||
Resources.StrSuccessMsgRequirementActive +
|
||||
$" Id.Ver {ProductionRequirements.StandardId}.{ProductionRequirements.StandardVersion}";
|
||||
|
||||
|
||||
return StatusReturn.Okay;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check production order number between meter and requirements.
|
||||
///
|
||||
/// Software Requirement Specification:
|
||||
/// [SRS_TBF_PICK_PP_CHECK_PROD_STATE_002]_Check_ProductionOrderNo
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="feedbackMsg"></param>
|
||||
/// <returns></returns>
|
||||
/// <remarks date="2025-Mai-15" author="Thomas Wiedebusch">
|
||||
/// - Initial.
|
||||
/// </remarks>
|
||||
private StatusReturn CheckProductionOrderNumber(out String feedbackMsg)
|
||||
{
|
||||
feedbackMsg = "";
|
||||
if (Meter == null ||
|
||||
ProductionRequirements == null ||
|
||||
ProductionRequirements.ProductionOrderNr != Meter.OrderNumber)
|
||||
{
|
||||
feedbackMsg = Resources.StrErrorMsgRequirementProductionOrder;
|
||||
return StatusReturn.Failed;
|
||||
}
|
||||
|
||||
feedbackMsg = $"{Resources.StrSuccessMsgRequirementProductionOrder} - " +
|
||||
$"{Resources.StrLblOrderNumberTxt}: {Meter.OrderNumber}";
|
||||
return StatusReturn.Okay;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check PcbId of meter and requirements. Mark PcbId as skipped if
|
||||
/// production requirements PcbId is null as this is the indication that all Cordonels
|
||||
/// assigned to this production order are produced according to this requirement.
|
||||
///
|
||||
/// Software Requirement Specification:
|
||||
/// [SRS_TBF_PICK_PP_CHECK_PROD_STATE_003]_Check_PcbId
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="feedbackMsg"></param>
|
||||
/// <returns></returns>
|
||||
/// <remarks date="2025-Mai-15" author="Thomas Wiedebusch">
|
||||
/// - Initial.
|
||||
/// </remarks>
|
||||
private StatusReturn CheckPcbId(out String feedbackMsg)
|
||||
{
|
||||
feedbackMsg = "";
|
||||
if (Meter == null ||
|
||||
ProductionRequirements == null ||
|
||||
Meter.PcbId == null ||
|
||||
Meter.PcbId.Length < GenesisMeter.MinPcbIdLength)
|
||||
{
|
||||
feedbackMsg = Resources.StrErrorMsgRequirementPcbId;
|
||||
return StatusReturn.Failed;
|
||||
}
|
||||
|
||||
if (ProductionRequirements.PcbId == null)
|
||||
{
|
||||
feedbackMsg = Resources.StrSuccessMsgOrderBasedRequirements;
|
||||
return StatusReturn.Okay;
|
||||
}
|
||||
if (Meter.PcbId.Equals(ProductionRequirements.PcbId.ToString()))
|
||||
{
|
||||
feedbackMsg = $"{Resources.StrSuccessMsgRequirementPcbId} - PcbId: {Meter.PcbId}";
|
||||
return StatusReturn.Okay;
|
||||
}
|
||||
|
||||
feedbackMsg = Resources.StrErrorMsgRequirementPcbId;
|
||||
return StatusReturn.Failed;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check region between meter and requirements
|
||||
///
|
||||
/// Software Requirement Specification:
|
||||
/// [SRS_TBF_PICK_PP_CHECK_PROD_STATE_004]_Check_Region
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="feedbackMsg"></param>
|
||||
/// <returns></returns>
|
||||
/// <remarks date="2025-Mai-15" author="Thomas Wiedebusch">
|
||||
/// - Initial.
|
||||
/// </remarks>
|
||||
private StatusReturn CheckRegion(out String feedbackMsg)
|
||||
{
|
||||
feedbackMsg = "";
|
||||
if (ProductionRequirements == null ||
|
||||
string.IsNullOrEmpty(ProductionRequirements.Region) ||
|
||||
string.IsNullOrEmpty(Meter.Region) ||
|
||||
!Meter.Region.Equals(ProductionRequirements.Region))
|
||||
{
|
||||
feedbackMsg = Resources.StrErrorMsgRequirementRegion;
|
||||
return StatusReturn.Failed;
|
||||
}
|
||||
|
||||
feedbackMsg = $"{Resources.StrSuccessMsgRequirementRegion} - Region: {Meter.Region}";
|
||||
return StatusReturn.Okay;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check Look-Up-Table (LUT) for metrology calibration values for the checksum (CRC) of this table
|
||||
///
|
||||
/// Software Requirement Specification:
|
||||
/// [SRS_TBF_PICK_PP_CHECK_PROD_STATE_005]_Check_LUT_CRC
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="feedbackMsg"></param>
|
||||
/// <returns></returns>
|
||||
/// <remarks date="2025-Mai-15" author="Thomas Wiedebusch">
|
||||
/// - Initial.
|
||||
/// </remarks>
|
||||
private String CheckLutCrc(out String feedbackMsg)
|
||||
{
|
||||
feedbackMsg = "";
|
||||
if (Meter == null ||
|
||||
ProductionRequirements == null ||
|
||||
string.IsNullOrEmpty(ProductionRequirements.LutCrc) ||
|
||||
string.IsNullOrEmpty(Meter.LutCrc) ||
|
||||
!Meter.LutCrc.Equals(ProductionRequirements.LutCrc))
|
||||
{
|
||||
feedbackMsg = Resources.StrErrorMsgRequirementLut;
|
||||
return "";
|
||||
}
|
||||
|
||||
feedbackMsg = $"{Resources.StrSuccessMsgRequirementLut} - LUT CRC: {Meter.LutCrc}";
|
||||
|
||||
return Meter.LutCrc;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check meter size
|
||||
///
|
||||
/// Software Requirement Specification:
|
||||
/// [SRS_TBF_PICK_PP_CHECK_PROD_STATE_006]_Check_Meter_Size
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="feedbackMsg"></param>
|
||||
/// <returns></returns>
|
||||
/// <remarks date="2025-Mai-15" author="Thomas Wiedebusch">
|
||||
/// - Initial.
|
||||
/// </remarks>
|
||||
private String CheckMeterSize(out String feedbackMsg)
|
||||
{
|
||||
feedbackMsg = "";
|
||||
if (Meter == null ||
|
||||
ProductionRequirements == null || string.IsNullOrEmpty(ProductionRequirements.MeterSize) ||
|
||||
string.IsNullOrEmpty(Meter.MeterSize) ||
|
||||
MeterSizeConverter.ConvertMeterSizeNameToEnum(Meter.MeterSize) !=
|
||||
MeterSizeConverter.ConvertMeterSizeNameToEnum(ProductionRequirements.MeterSize))
|
||||
{
|
||||
feedbackMsg = Resources.StrErrorMsgRequirementMeterSize;
|
||||
return "";
|
||||
}
|
||||
|
||||
feedbackMsg = $"{Resources.StrSuccessMsgRequirementMeterSize} - " +
|
||||
$"{Resources.StrLblMeterSizeTxt}: {Meter.MeterSize}";
|
||||
|
||||
return ProductionRequirements.MeterSize;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check the installed firmware (FW) and all individual applications (Apps) installed to the meter:
|
||||
/// - Take the FLEXNETVERSION as base information which FW is installed in the Cordonel and compare this with
|
||||
/// the production-requirement,
|
||||
/// - The downloaded FW package containing all Apps as application-binary-container (ABC) will be compared with
|
||||
/// the reported Apps by the Cordonel for their version and CRC using the "<see cref="MeterFwUpdate"/> class,
|
||||
/// - Crosscheck if the application-description-file (ADF) states all Apps which are installed in the Cordonel,
|
||||
/// - Check the Core-Revision of the Cordonel against the ADF to guarantee that this FW is supported by the
|
||||
/// Cordonel operational system (Breeze).
|
||||
///
|
||||
/// Software Requirement Specification:
|
||||
/// [SRS_TBF_PICK_PP_CHECK_PROD_STATE_007]_Check_FW_and_Apps
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="feedbackMsg"></param>
|
||||
/// <returns></returns>
|
||||
/// <remarks date="2025-Mai-15" author="Thomas Wiedebusch">
|
||||
/// - Initial.
|
||||
/// </remarks>
|
||||
private String CheckFwAndApps(out String feedbackMsg)
|
||||
{
|
||||
feedbackMsg = "";
|
||||
// Check installed FW version with FLEXNET information
|
||||
var fwUpdate = new MeterFwUpdate(Meter);
|
||||
if (Meter == null ||
|
||||
ProductionRequirements == null ||
|
||||
string.IsNullOrEmpty(ProductionRequirements.FwVersion) ||
|
||||
string.IsNullOrEmpty(Meter.FwVersion) ||
|
||||
!Meter.FwVersion.Equals(ProductionRequirements.FwVersion) ||
|
||||
// Check if FW package has been loaded and contains at least the minimal required files
|
||||
FwUpdatePackage == null ||
|
||||
FwUpdatePackage.Count < MeterFwUpdate.MinAppsRequiredForOperation)
|
||||
{
|
||||
feedbackMsg += $"{Resources.StrErrorMsgRequirementFw}\n";
|
||||
return "";
|
||||
}
|
||||
|
||||
var fileApps = new List<FileApplications>();
|
||||
if (FwUpdatePackage != null)
|
||||
{
|
||||
foreach (var file in FwUpdatePackage)
|
||||
{
|
||||
// load the ABC (application binary container)
|
||||
if (file.FileName.Contains("binfile") &&
|
||||
file.FileName.EndsWith(".bin") &&
|
||||
// Sometimes the * complete *.bin is part of the binaries containing all app in one file.
|
||||
// As this is not part of the ADF it has to be skipped from loading!!!!
|
||||
!file.FileName.Contains("complete"))
|
||||
{
|
||||
var fileApplication = new FileApplications(file.FileName)
|
||||
{
|
||||
BinData = new List<Byte>(file.FileContent.ToList())
|
||||
};
|
||||
fileApps.Add(fileApplication);
|
||||
}
|
||||
// Load the ADF (application description file, containing the information
|
||||
// of each application)
|
||||
else if (file.FileName.Contains("product") && file.FileName.EndsWith(".txt"))
|
||||
{
|
||||
var enc = new System.Text.ASCIIEncoding();
|
||||
var adf = enc.GetString(file.FileContent.ToArray());
|
||||
fwUpdate.LoadPackageFileFromText(adf);
|
||||
}
|
||||
}
|
||||
|
||||
fwUpdate.LoadFileApps(fileApps);
|
||||
}
|
||||
|
||||
var checkSucceeded = true;
|
||||
// Compare every installed application for version and CRC with the required to be defined by the downloaded
|
||||
// ABC (application binary container)
|
||||
fwUpdate.CompareAllMeterAndFileApps();
|
||||
|
||||
if (// Validate package description file with required Apps (fileApps) and build the CORE REVISIONS MIN MAX
|
||||
!fwUpdate.ValidateFileAppsWithPackageFile() ||
|
||||
// Check if any meter Apps is outdated or does contain an un-matching CRC
|
||||
Meter.MeterAppListVersion.Any(app => app.Status != MeterAppState.MeterAppUpToDate &&
|
||||
app.Status != MeterAppState.MeterAppNotRequired))
|
||||
{
|
||||
feedbackMsg += $"{Resources.StrErrorMsgAppVersionOrCrc}\n";
|
||||
checkSucceeded = false;
|
||||
// Do not immediately return to summarize all errors following up
|
||||
}
|
||||
|
||||
// The package description file has to be parsed in advance using the fwUpdate.ValidateFileAppsWithPackageFile()!!
|
||||
if (!fwUpdate.CheckCoreRevision(Meter.CoreRevision))
|
||||
{
|
||||
feedbackMsg += $"{Resources.StrErrorMsgCoreRevision}\n";
|
||||
// Do not immediately return to summarize all errors following up
|
||||
checkSucceeded = false;
|
||||
}
|
||||
|
||||
if (!checkSucceeded)
|
||||
{
|
||||
feedbackMsg += $"{Resources.StrErrorMsgRequirementFw}\n";
|
||||
return "";
|
||||
}
|
||||
feedbackMsg = $"{Resources.StrSuccessMsgRequirementFw} - Firmware: {Meter.FwVersion}";
|
||||
return Meter.FwVersion;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check the remaining battery load based on the thresholds which can be either:
|
||||
/// - The AlternativeRequiredBatteryLoadPercent if the QuiescentCurrent_uA is set to a value greater than 50 uA
|
||||
/// and the EstimatedProductionBatteryLoadPercent is greater than 0.0 %
|
||||
/// and
|
||||
/// - the MaxDrainedBatteryLoadPercentAssembly limits the threshold,
|
||||
/// or only
|
||||
/// - the MaxDrainedBatteryLoadPercentAssembly limits the threshold as absolut limit.
|
||||
///
|
||||
/// ATTENTION: The MaxDrainedBatteryLoadPercentAssembly forces the absolut limit even if the alternative
|
||||
/// calculation is being used.
|
||||
///
|
||||
/// Software Requirement Specification:
|
||||
/// [SRS_TBF_PICK_PP_CHECK_PROD_STATE_008]_Check_Remaining_Battery_Load
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="feedbackMsg"></param>
|
||||
/// <returns></returns>
|
||||
/// <remarks date="2025-Mai-15" author="Thomas Wiedebusch">
|
||||
/// - Initial.
|
||||
/// </remarks>
|
||||
private StatusReturn CheckRemainingBatteryLoad(out String feedbackMsg)
|
||||
{
|
||||
if (Meter == null ||
|
||||
ProductionRequirements?.MaxDrainedBatteryLoadPercentAssembly == null ||
|
||||
ProductionStatus == null)
|
||||
{
|
||||
feedbackMsg = Resources.StrErrorMsgBatteryLoadCalculation;
|
||||
return StatusReturn.Failed;
|
||||
}
|
||||
|
||||
// If the values for calculation of drained battery load and exceeded lifetime are not accessible
|
||||
if (ProductionStatus.DrainedBatteryLoad_uAs == 0 || ProductionStatus.ExceededLifeTime_s == 0)
|
||||
{
|
||||
feedbackMsg = Resources.StrErrorMsgBatteryLoadCalculation;
|
||||
return StatusReturn.Failed;
|
||||
}
|
||||
|
||||
// Set up the alternative calculation values needed for given current and supplement for production.
|
||||
// These values will be set by the requirement and have a higher priority than the standard calculation
|
||||
// based on the drained battery load and the estimated prediction based on this and the time of operation.
|
||||
if (ProductionRequirements.QuiescentCurrent_uA > GenesisMeter.QuiescentCurrent_uA &&
|
||||
ProductionRequirements.EstimatedProductionBatteryLoadPercent > 0)
|
||||
{
|
||||
ProductionStatus.QuiescentCurrent_uA = ProductionRequirements.QuiescentCurrent_uA;
|
||||
ProductionStatus.EstimatedProductionBatteryLoadPercent =
|
||||
ProductionRequirements.EstimatedProductionBatteryLoadPercent;
|
||||
}
|
||||
|
||||
// Calculate the power consumption
|
||||
if (!GenesisStatusHandler.CalculateLifeTime(ProductionStatus))
|
||||
{
|
||||
feedbackMsg = Resources.StrErrorMsgBatteryLoadCalculation;
|
||||
return StatusReturn.Failed;
|
||||
}
|
||||
|
||||
// Check battery load in percent and compare with requirements for limits for drained battery load
|
||||
// For the alternative calculation based quiescent current and production supplement this will be used.
|
||||
// Build message for required versus calculated lifetime
|
||||
var threshold = ProductionStatus.AlternativeRequiredBatteryLoadPercent ??
|
||||
ProductionRequirements.MaxDrainedBatteryLoadPercentAssembly;
|
||||
|
||||
// Create an output message addon for alternative power consumption calculation
|
||||
var strAlternativeCalc = ProductionStatus.AlternativeRequiredBatteryLoadPercent == null
|
||||
? ""
|
||||
: $" - {Resources.StrMsgRequirementAbsolutLimitDrainedBattery}: " +
|
||||
$"{ProductionRequirements.MaxDrainedBatteryLoadPercentAssembly:F2} %" +
|
||||
$" ({Resources.StrMsgAlternativeDrainedBatteryCalculation})";
|
||||
|
||||
var batteryLoad = $"{Resources.StrMsgDrainedBattery}: " +
|
||||
// Actual calculated battery load based on readings from meter
|
||||
$"{ProductionStatus.DrainedBatteryLoadPercent:F2} %" +
|
||||
$" - {Resources.StrMsgRequirementLimitDrainedBattery}: " +
|
||||
// Required battery load from standard or special requirement
|
||||
$"{threshold:F2} % {strAlternativeCalc}";
|
||||
|
||||
|
||||
// This is the absolut limit even if the "AlternativeRequiredBatteryLoadPercent" will be used
|
||||
if (ProductionStatus.DrainedBatteryLoadPercent >
|
||||
ProductionRequirements.MaxDrainedBatteryLoadPercentAssembly)
|
||||
{
|
||||
feedbackMsg = $"{Resources.StrErrorMsg}: {batteryLoad}";
|
||||
return StatusReturn.Failed;
|
||||
}
|
||||
|
||||
// This is the limit given by the "AlternativeRequiredBatteryLoadPercent"
|
||||
if (ProductionStatus.AlternativeRequiredBatteryLoadPercent != null &&
|
||||
ProductionStatus.DrainedBatteryLoadPercent > ProductionStatus.AlternativeRequiredBatteryLoadPercent)
|
||||
{
|
||||
feedbackMsg = $"{Resources.StrErrorMsg}: {batteryLoad}";
|
||||
return StatusReturn.Failed;
|
||||
}
|
||||
|
||||
feedbackMsg = $"{Resources.StrSuccessMsg}: {batteryLoad}";
|
||||
|
||||
return StatusReturn.Okay;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check the remaining lifetime
|
||||
///
|
||||
/// Software Requirement Specification:
|
||||
/// [SRS_TBF_PICK_PP_CHECK_PROD_STATE_009]_Check_Remaining_Lifetime
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="feedbackMsg"></param>
|
||||
/// <returns></returns>
|
||||
/// <remarks date="2025-Mai-15" author="Thomas Wiedebusch">
|
||||
/// - Initial.
|
||||
/// </remarks>
|
||||
private StatusReturn CheckRemainingLifetime(out String feedbackMsg)
|
||||
{
|
||||
if (Meter == null ||
|
||||
ProductionRequirements?.RequiredLifeTimeYearsAssembly == null ||
|
||||
ProductionRequirements.RequiredLifeTimeYearsAssembly <= 0 ||
|
||||
ProductionStatus == null)
|
||||
{
|
||||
feedbackMsg = Resources.StrErrorMsgLifeTimeCalculation;
|
||||
return StatusReturn.Failed;
|
||||
}
|
||||
|
||||
// Calculate the power consumption
|
||||
if (!GenesisStatusHandler.CalculateLifeTime(ProductionStatus))
|
||||
{
|
||||
feedbackMsg = Resources.StrErrorMsgBatteryLoadCalculation;
|
||||
return StatusReturn.Failed;
|
||||
}
|
||||
|
||||
// Build message for required versus calculated lifetime
|
||||
var lifeTime = $"{Resources.StrMsgRemainingLifeTime}: " +
|
||||
// Actual calculated lifetime based on readings from meter
|
||||
$"{ProductionStatus.RemainingLifeTimeYears:F2} " +
|
||||
$"{Resources.StrMsgYears}" +
|
||||
$" - {Resources.StrMsgRequiredLifeTime}: " +
|
||||
// Required lifetime from special or standard requirement
|
||||
$"{ProductionRequirements.RequiredLifeTimeYearsAssembly:F2} " +
|
||||
$"{Resources.StrMsgYears}";
|
||||
|
||||
// Check required years for assembly
|
||||
if (ProductionRequirements.RequiredLifeTimeYearsAssembly > ProductionStatus.RemainingLifeTimeYears)
|
||||
{
|
||||
feedbackMsg = $"{Resources.StrErrorMsg}: {lifeTime}";
|
||||
return StatusReturn.Failed;
|
||||
}
|
||||
|
||||
feedbackMsg = $"{Resources.StrSuccessMsg}: {lifeTime}";
|
||||
return StatusReturn.Okay;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check the months between first battery activation and now
|
||||
///
|
||||
/// Software Requirement Specification:
|
||||
/// [SRS_TBF_PICK_PP_CHECK_PROD_STATE_010]_Check_Storage_Months
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="feedbackMsg"></param>
|
||||
/// <returns></returns>
|
||||
/// <remarks date="2025-Mai-15" author="Thomas Wiedebusch">
|
||||
/// - Initial.
|
||||
/// </remarks>
|
||||
private StatusReturn CheckStorageMonths(out String feedbackMsg)
|
||||
{
|
||||
// Based on first attached battery and the POWEMON_TotalUsedSeconds (Kitron production date) and actual date
|
||||
if (Meter == null ||
|
||||
ProductionRequirements?.MaxStorageMonths == null ||
|
||||
ProductionRequirements.MaxStorageMonths < 0.0 ||
|
||||
ProductionStatus == null ||
|
||||
ProductionStatus.DrainedBatteryLoad_uAs == 0 ||
|
||||
ProductionStatus.ExceededLifeTime_s == 0)
|
||||
{
|
||||
// Storage months requirement or Kitron production date unknown
|
||||
feedbackMsg = Resources.StrErrorMsgRequirementMaximumStorageMonthUnknown;
|
||||
return StatusReturn.Failed;
|
||||
}
|
||||
|
||||
// Calculate the power consumption
|
||||
if (!GenesisStatusHandler.CalculateLifeTime(ProductionStatus) || ProductionStatus.BatteryAssemblyDateTimeUtc == null)
|
||||
{
|
||||
feedbackMsg = Resources.StrErrorMsgRequirementMaximumStorageMonthUnknown;
|
||||
return StatusReturn.Failed;
|
||||
}
|
||||
|
||||
var actualDate = DateTime.UtcNow.Date;
|
||||
var batteryAssemblyDate = ProductionStatus.BatteryAssemblyDateTimeUtc.Value.Date;
|
||||
// Give one day more as rounding issue
|
||||
var expirationDate = batteryAssemblyDate.AddDays((Double)ProductionRequirements.MaxStorageMonths * GenesisStatusHandler.DAYS_PER_MONTH + 1.0);
|
||||
var strStorageProduction = $"{Resources.StrLblKitronProductionDate}: " +
|
||||
$"{ProductionStatus.BatteryAssemblyDateTimeUtc.Value:dd-MMM-yyyy} - " +
|
||||
$"{Resources.StrLblExpirationDate}: {expirationDate:dd-MMM-yyyy} - " +
|
||||
$"{Resources.StrLblMaxStorageMonths}: " +
|
||||
$"{(Int32)ProductionRequirements.MaxStorageMonths} {Resources.StrLblMonths}";
|
||||
|
||||
if (actualDate >= expirationDate)
|
||||
{
|
||||
// Storage months exceeded
|
||||
feedbackMsg = $"{Resources.StrErrorMsgRequirementMaximumStorageMonth} - " + strStorageProduction;
|
||||
return StatusReturn.Failed;
|
||||
}
|
||||
|
||||
feedbackMsg = $"{Resources.StrSuccessMsgRequirementMaximumStorageMonth} - " + strStorageProduction;
|
||||
return StatusReturn.Okay;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+178
@@ -0,0 +1,178 @@
|
||||
using System.Collections.Generic;
|
||||
using Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.Enum;
|
||||
using Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.GenericProcesses;
|
||||
using Xylem.Common.Production.ProductionUiCordonel.Properties;
|
||||
|
||||
namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.PickingProcesses
|
||||
{
|
||||
/// <summary>
|
||||
/// Concatenation for all production process states to feed the state machine:
|
||||
/// - Production process class (representing a production process step), null if hidden process,
|
||||
/// - attached state,
|
||||
/// - state information to display a text message,
|
||||
/// - production process number to define where to display in the overview,
|
||||
/// - next state which should be executed after this succeeded,
|
||||
/// [optional]:
|
||||
/// - own error state,
|
||||
/// - own break state,
|
||||
/// - kick off state for parallel execution after starting this process in a separate task,
|
||||
/// - wait for single process to finish successfully,
|
||||
/// - wait for all processes to finish successfully,
|
||||
/// - start always independent of any result, e.g. the error state needs to be started if called!
|
||||
/// </summary>
|
||||
/// <remarks date="2025-Apr-15" author="Thomas Wiedebusch">
|
||||
/// - Initial
|
||||
/// </remarks>
|
||||
public class PickingProcessStateDef : BaseProcessStatesDef
|
||||
{
|
||||
/// <summary>
|
||||
/// State-machine definitions of production-processes which feeds the state-machine.
|
||||
///
|
||||
///
|
||||
/// INSTRUCTION FOR PREPARATION:
|
||||
/// -----------------------------
|
||||
/// STEP 1: Define some states for your processes <see cref="ProcessState"/>
|
||||
/// STEP 2: Implement your processes like <see cref="DetectCordonel"/>
|
||||
/// STEP 3: Register and chain your states here
|
||||
///
|
||||
///
|
||||
/// INSTRUCTION FOR NORMAL USAGE:
|
||||
/// -----------------------------
|
||||
/// Means one state automatically switched on successfully execution to the next required state.
|
||||
///
|
||||
/// Define the (e.g.):
|
||||
/// productionProcess: new DetectCordonel(Resources.StrStateDetectCordonel),
|
||||
/// processState: ProcessState.DetectCordonel,
|
||||
/// processInfo: Resources.StrStateDetectCordonel,
|
||||
/// productionProcessNo: 0,
|
||||
/// nextStateOnSuccess: ProcessState.CheckNewMeter),
|
||||
///
|
||||
/// If a special state is needed on errorExitState or breakExitState these can be assigned. Otherwise, the
|
||||
/// "errorExitState" is linked to the generic-error-state, the "breakExitState" to the abort-test-state.
|
||||
///
|
||||
///
|
||||
/// INSTRUCTION FOR NON-BLOCKING MULTIPLE PROCESSES SIMULTANEOUSLY ACTIVITIES:
|
||||
/// --------------------------------------------------------------------------
|
||||
/// Sometimes production processes may be able to be executed simultaneously as they are independent of each
|
||||
/// other. One example is a database access for data collection from different tables.
|
||||
///
|
||||
/// This is needed for non-blocking immediately new state change (not waiting for the successful execution of
|
||||
/// the actual new assigned process).
|
||||
///
|
||||
/// Define the (e.g.):
|
||||
///
|
||||
/// productionProcess: new ConnectCordonel(Resources.StrStateConnectCordonel),
|
||||
/// processState: ProcessState.ConnectCordonel,
|
||||
/// processInfo: Resources.StrStateConnectCordonel,
|
||||
/// productionProcessNo: 1,
|
||||
/// // Avoid automatic change after completion as parallel process is active
|
||||
/// nextStateOnSuccess: BaseProductionProcess.DoNotChangeStateAfterCompletion,
|
||||
/// // Kick off parallel process execution after starting the "ConnectCordonel() task"
|
||||
/// kickOffParallelState: ProcessState.GetSerialNumberAndRadioAddress),
|
||||
///
|
||||
///
|
||||
/// INSTRUCTION TO DELAY THE START OF A PROCESS AND WAIT ON RESULTS OF OTHER PROCESS(ES):
|
||||
/// -------------------------------------------------------------------------------------
|
||||
/// Each new process execution can be delayed as it may need the result of another process which is active.
|
||||
///
|
||||
/// Wait for a single process to complete:
|
||||
/// Set the "waitForSingleProcess" to the state of the process needed to wait for (e.g.):
|
||||
///
|
||||
/// productionProcess: new CheckProductionState(Resources.StrStateCheckProductionState),
|
||||
/// processState: ProcessState.CheckProductionState,
|
||||
/// processInfo: Resources.StrStateCheckProductionState,
|
||||
/// productionProcessNo: 4,
|
||||
/// // Avoid automatic change after completion as parallel process is active
|
||||
/// nextStateOnSuccess: BaseProductionProcess.DoNotChangeStateAfterCompletion,
|
||||
/// // Kick off parallel process execution after starting
|
||||
/// kickOffParallelState: ProcessState.ProcessPasswordFile,
|
||||
/// // Wait until this process has been successfully completed
|
||||
/// waitForSingleProcess: ProcessState.ConnectCordonel),
|
||||
///
|
||||
/// Wait for all preceding processes to complete to be sure to get all data and all processed are succeeded:
|
||||
/// Set the "waitForAllProcesses" to true (e.g.):
|
||||
/// productionProcess: new ExecPasswordFile(Resources.StrStatePasswordFile),
|
||||
/// processState: ProcessState.ProcessPasswordFile,
|
||||
/// processInfo: Resources.StrStatePasswordFile,
|
||||
/// productionProcessNo: 5,
|
||||
/// nextStateOnSuccess: ProcessState.ExecFinalParametrization,
|
||||
/// waitForAllProcesses: true),
|
||||
///
|
||||
/// </summary>
|
||||
public PickingProcessStateDef()
|
||||
{
|
||||
var stateContainer = new List<ProcessStateStruct>
|
||||
{
|
||||
#region ----------------------------------- GENERIC-STATES---------------------------------------------
|
||||
// Detection of Cordonel has to be completed before assigning next state, so leave to automatic
|
||||
// to change the state after successfully execution. The detection is the base for all others.
|
||||
new ProcessStateStruct(
|
||||
productionProcess: new DetectCordonel(Resources.StrStateDetectCordonel),
|
||||
processState: ProcessState.DetectCordonel,
|
||||
processInfo: Resources.StrStateDetectCordonel,
|
||||
productionProcessNo: 0,
|
||||
nextStateOnSuccess: ProcessState.CheckNewMeter),
|
||||
|
||||
// Detection of Cordonel has to be completed before assigning next state. It has to be checked if
|
||||
// the meter changed to clear all collected contents of previous run. To UPDATE ALL INFORMATION after
|
||||
// new meter assignment the "DetectCordonel" has to be repeated to return here "Old Meter" and then
|
||||
// enter the "ConnectCordonel"!
|
||||
new ProcessStateStruct(
|
||||
productionProcess: null,
|
||||
processState: ProcessState.CheckNewMeter,
|
||||
processInfo: Resources.StrProcessStateCheckNewMeter,
|
||||
productionProcessNo: null,
|
||||
nextStateOnSuccess: ProcessState.DetectCordonel,
|
||||
errorExitState: ProcessState.ConnectCordonel),
|
||||
|
||||
// Precondition: - The detection process has to be completed as the PcbId is needed.
|
||||
// AVOID to change the process state on completion as parallel process is active!
|
||||
new ProcessStateStruct(
|
||||
productionProcess: new ConnectCordonel(Resources.StrStateConnectCordonel),
|
||||
processState: ProcessState.ConnectCordonel,
|
||||
processInfo: Resources.StrStateConnectCordonel,
|
||||
productionProcessNo: 1,
|
||||
// Avoid automatic change after completion as parallel process is active
|
||||
nextStateOnSuccess: BaseProductionProcess.DoNotChangeStateAfterCompletion,
|
||||
// Kick off parallel process execution
|
||||
kickOffParallelState: ProcessState.GetSerialNumberAndRadioAddress),
|
||||
|
||||
// Precondition: - The detection process has to be completed as the PcbId is needed.
|
||||
// AVOID to change the process state on completion as parallel process is active!
|
||||
new ProcessStateStruct(
|
||||
productionProcess: new GetSerialNumberAndRadioAddress(Resources.StrStateGetSerialAndRadioAddress),
|
||||
processState: ProcessState.GetSerialNumberAndRadioAddress,
|
||||
processInfo: Resources.StrStateGetSerialAndRadioAddress,
|
||||
productionProcessNo: 2,
|
||||
nextStateOnSuccess: ProcessState.CheckOrderNumber,
|
||||
waitForAllProcesses: true),
|
||||
|
||||
// This scans the order number, it has to be executed exclusively with automatic
|
||||
new ProcessStateStruct(
|
||||
productionProcess: new CheckOrderNumber(Resources.StrStateCheckOrderNumber),
|
||||
processState: ProcessState.CheckOrderNumber,
|
||||
processInfo: Resources.StrStateCheckOrderNumber,
|
||||
productionProcessNo:3,
|
||||
nextStateOnSuccess: ProcessState.CheckProductionState),
|
||||
|
||||
#endregion -------------------------------- GENERIC-STATES --------------------------------------------
|
||||
|
||||
#region ----------------------------------- PICKING-STATES --------------------------------------------
|
||||
// Precondition: - The connection process has to be completed as a readout of some register
|
||||
// values from the Cordonel are needed to check the update capability:
|
||||
// - Wait on completed connection process before starting this process.
|
||||
new ProcessStateStruct(
|
||||
productionProcess: new CheckProductionState(Resources.StrStateCheckProductionState),
|
||||
processState: ProcessState.CheckProductionState,
|
||||
processInfo: Resources.StrStateCheckProductionState,
|
||||
productionProcessNo: 4,
|
||||
nextStateOnSuccess: ProcessState.Idle),
|
||||
|
||||
//TODO Roland: implement your states here
|
||||
#endregion -------------------------------- PICKING-STATES --------------------------------------------
|
||||
|
||||
};
|
||||
StateContainer.AddRange(stateContainer);
|
||||
}
|
||||
}
|
||||
}
|
||||
+92
-233
@@ -9,22 +9,15 @@ using Xylem.Common.Hardware.WaterMeter.Genesis.GenesisStatus;
|
||||
using Xylem.Common.Hardware.WaterMeter.WaterMeterCore;
|
||||
using Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.Enum;
|
||||
using Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.EventArgs;
|
||||
using Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.GenericProcesses;
|
||||
using Timer = System.Threading.Timer;
|
||||
|
||||
namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses
|
||||
{
|
||||
/// <summary>
|
||||
/// Preparing the Cordonel for shipping:
|
||||
/// - Setup device with standard parameters covered by the VAKO or customer specific CSD,
|
||||
/// - If radio is installed: radio test,
|
||||
/// - Requiring radio key from LuDB,
|
||||
/// - Requiring 7 passwords for the Cordonel access levels,
|
||||
/// - Building the password file (Level 3 is the modified skeleton key),
|
||||
/// - Store all configurations,
|
||||
/// - Reboot the Cordonel to load all settings from FLASH to RAM,
|
||||
/// - Configuration check of all parameters defined by VAKO and CSD.
|
||||
/// Implementation for all methods needed to drive the state machine of the process controller
|
||||
/// </summary>
|
||||
public sealed class FinalProcessController
|
||||
public class ProcessController
|
||||
{
|
||||
#region ------------------------------------------ Variables --------------------------------------------------
|
||||
// actual genesis meter
|
||||
@@ -46,11 +39,12 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses
|
||||
// List of production processes
|
||||
public List<IProductionProcess> Processes
|
||||
{
|
||||
get; private set;
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
// Container for production process states
|
||||
private ProcessStateDef _processStateDef;
|
||||
private IProcessStateDef _processStateDef;
|
||||
|
||||
// Container for production status information, a list is used to keep the content over all classes of production
|
||||
// processes as a reference seems not to return their value (always reset to the initial value)
|
||||
@@ -69,15 +63,27 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses
|
||||
// reminder for slot
|
||||
private readonly Int32 _slot;
|
||||
|
||||
// processing retries
|
||||
private const Int32 MaxProcessRetries = 2;
|
||||
//private static Int32 _processRetryCtr;
|
||||
|
||||
//event for process list change or state of single process step change
|
||||
/// <summary>
|
||||
/// Change the overview table of the GUI to the state of the individual process
|
||||
/// </summary>
|
||||
public event EventHandler<SingleProcessStateArgs> OnSingleProcessStateChanged;
|
||||
|
||||
/// <summary>
|
||||
/// The overall process chain changed needed to signal to the GUI
|
||||
/// - Can be forced by the state machine to invoke,
|
||||
/// - Will be used via the OverallProcessStateChanged_Handler by the individual processes to return the next
|
||||
/// required sate after break, error or completion to change the state of the state machine.
|
||||
/// </summary>
|
||||
public event EventHandler<ProcessStateArgs> OnOverallProcessStateChanged;
|
||||
|
||||
/// <summary>
|
||||
/// Request for logging to GUI output and log-file
|
||||
/// </summary>
|
||||
public event EventHandler<ProcessLogArgs> OnProcessLogRequest;
|
||||
// progress bar and screen info of ongoing processes
|
||||
|
||||
/// <summary>
|
||||
/// Keep the progress bars of the GUI up to date
|
||||
/// </summary>
|
||||
public event EventHandler<ProcessProgressArgs> OnProcessProgressChanged;
|
||||
|
||||
// cancellation token
|
||||
@@ -88,11 +94,15 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses
|
||||
private Timer _processCtrlTimer;
|
||||
private const Int32 ProcessTimerCycleMs = 250;
|
||||
|
||||
// defines for state machine
|
||||
/// <summary>
|
||||
/// Avoid waiting for a single process completion.
|
||||
/// </summary>
|
||||
private const IProductionProcess DoNotWaitForSingleProcessCompletion = null;
|
||||
public const IProductionProcess DoNotWaitForSingleProcessCompletion = null;
|
||||
|
||||
/// <summary>
|
||||
/// Kick off a parallel execution of the state machine.
|
||||
/// </summary>
|
||||
public const Boolean ExecuteInParallel = true;
|
||||
|
||||
#endregion --------------------------------------- Variables --------------------------------------------------
|
||||
#region ------------------------------------------ Class ------------------------------------------------------
|
||||
@@ -103,6 +113,7 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses
|
||||
/// - Create and setup Cordonel.
|
||||
/// </summary>
|
||||
/// <param name="slot">physical slot for this meter</param>
|
||||
/// <param name="processSateDef"></param>
|
||||
/// <remarks date="2023-Feb-14" author="Thomas Wiedebusch">
|
||||
/// - Initial
|
||||
/// </remarks>
|
||||
@@ -111,12 +122,13 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses
|
||||
/// - Always RegisterWatchService on,
|
||||
/// - Always MinMaxCHeck on.
|
||||
/// </remarks>
|
||||
public FinalProcessController(Int32 slot)
|
||||
public ProcessController(Int32 slot, IProcessStateDef processSateDef)
|
||||
{
|
||||
_processCtrlTimer = new Timer(TmrProcessCtrlCycle_Elapsed, null, ProcessTimerCycleMs, ProcessTimerCycleMs);
|
||||
_slot = slot;
|
||||
_cancellationTokenSource = new CancellationTokenSource();
|
||||
_cancellationToken = _cancellationTokenSource.Token;
|
||||
_processStateDef = processSateDef;
|
||||
InitNewMeter();
|
||||
InitProcesses();
|
||||
// program start with idle process
|
||||
@@ -247,7 +259,6 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses
|
||||
{
|
||||
OnProcessLogRequest?.Invoke(sender, e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handler to set a new state for the state machine regarding the entire final-process
|
||||
/// </summary>
|
||||
@@ -282,60 +293,22 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses
|
||||
|
||||
#endregion --------------------------------------- Events -----------------------------------------------------
|
||||
#region ------------------------------------------ State Machine ----------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// State machine of FinalProcessController which serves as preparation for SHIPPING named EOL (End-Of-Line).
|
||||
/// State-machine of ProcessController which serves all production processes.
|
||||
/// This-state machine executes all states defined in the "GenericStateMachineDef" and the individual
|
||||
/// production-process specific "XxxStateMachineDef".
|
||||
///
|
||||
///
|
||||
/// INSTRUCTION FOR NORMAL USAGE:
|
||||
/// -----------------------------
|
||||
/// Call the SetupProcess() with the
|
||||
/// - new process automatically collected from <see cref="ProcessStateDef.GetProcessOfState"/> with new
|
||||
/// _actualProcessState as input,
|
||||
/// - successExitState set to the next required state after successfully execution.
|
||||
/// That's it! The normal state change has always only one production process active and waits for completion
|
||||
/// before changing to a new state and therefore a new production process.
|
||||
///
|
||||
/// If a special state is needed on errorExitState or breakExitState these can be assigned. Otherwise, the
|
||||
/// errorExitState is linked to the error state, the breakExitState to the stop state.
|
||||
///
|
||||
///
|
||||
/// INSTRUCTION FOR NON-BLOCKING MULTIPLE PROCESSES SIMULTANEOUSLY ACTIVITIES:
|
||||
/// --------------------------------------------------------------------------
|
||||
/// Sometimes production processes may be able to be executed simultaneously as they are independent of each
|
||||
/// other. One example is a database access for data collection from different tables.
|
||||
///
|
||||
/// Call the SetupProcess with the
|
||||
/// - new process automatically collected from <see cref="ProcessStateDef.GetProcessOfState"/> with new
|
||||
/// _actualProcessState as input,
|
||||
/// - successExitState being set to <see cref="BaseProductionProcess.DoNotChangeStateAfterCompletion"/> (null).
|
||||
/// This will lock the sate change after completion as multiple processes may be active and a state change after
|
||||
/// completion may cause unpredictable operation, the state is already where it should be (manually changed),
|
||||
/// - change the state after the SetupProcess() call manually.
|
||||
///
|
||||
/// This is needed for non-blocking immediately new state change (not waiting for the successful execution of
|
||||
/// the actual new assigned process):
|
||||
/// E.g. all DB accesses need a certain time to get data, kicking off (fire and forget) the process without
|
||||
/// waiting for the result, the exitSuccessState has to be set to null to avoid a state change on successfully
|
||||
/// execution of the process. Instead, change the state here to go ahead with the next state. This forces a wait
|
||||
/// on the state who needs the data from the "fire and forget" states, SEE next instruction how to proceed!
|
||||
///
|
||||
///
|
||||
/// INSTRUCTION TO DELAY THE START OF A PROCESS:
|
||||
/// --------------------------------------------
|
||||
/// Each new process execution can be delayed as it may need the result of another process which is active.
|
||||
///
|
||||
/// Wait for a single process to complete:
|
||||
/// - set the "waitForSingleProcess" to the process to wait for.
|
||||
/// Wait for all preceding processes to complete:
|
||||
/// - set the "waitForAllProcesses" to true.
|
||||
///
|
||||
/// A few states with special functions will be caught in advance in this StateMachine
|
||||
/// </summary>
|
||||
/// <remarks date="2023-Jan-17" author="Thomas Wiedebusch">
|
||||
/// - Initial
|
||||
/// </remarks>
|
||||
/// <remarks date="2025-Apr-15" author="Thomas Wiedebusch">
|
||||
/// - Generic implementation
|
||||
/// </remarks>
|
||||
private void StateMachine()
|
||||
{
|
||||
// avoid repeated execution of the state machine on unchanged state
|
||||
{// avoid repeated execution of the state machine on unchanged state
|
||||
if (_stateMachineState == _lockedProcessState)
|
||||
{
|
||||
Thread.Sleep(ProcessTimerCycleMs >> 1);
|
||||
@@ -353,9 +326,9 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses
|
||||
// signal state change to logger
|
||||
OnOverallProcessStateChanged?.Invoke(this, new ProcessStateArgs(_stateMachineState));
|
||||
|
||||
// get the actual required process from the state definition list
|
||||
var process = _processStateDef?.GetProcessOfState(_stateMachineState);
|
||||
|
||||
// get the processStateStruct of the actual set stateMachineSTate
|
||||
var processStateStruct = _processStateDef.GetProcessStateStructOfState(_stateMachineState);
|
||||
|
||||
switch (_stateMachineState)
|
||||
{
|
||||
case ProcessState.Idle:
|
||||
@@ -366,7 +339,7 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses
|
||||
// Wait for cancellation
|
||||
if (_cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
Thread.Sleep(1000);
|
||||
Thread.Sleep(500);
|
||||
// Reset the cancellation request
|
||||
_cancellationTokenSource?.Dispose();
|
||||
_cancellationTokenSource = new CancellationTokenSource();
|
||||
@@ -378,7 +351,7 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses
|
||||
|
||||
// Detection of Cordonel has to be completed before assigning next state, so leave to automatic
|
||||
// to change the state after successfully execution. The detection is the base for all others.
|
||||
StartProcess(process, ProcessState.CheckNewMeter);
|
||||
StartProcess(processStateStruct);
|
||||
break;
|
||||
|
||||
case ProcessState.CheckNewMeter:
|
||||
@@ -389,129 +362,12 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses
|
||||
_stateMachineState = CheckForNewMeter() ? ProcessState.DetectCordonel : ProcessState.ConnectCordonel;
|
||||
break;
|
||||
|
||||
case ProcessState.ConnectCordonel:
|
||||
// Precondition: - The detection process has to be completed as the PcbId is needed.
|
||||
// AVOID to change the process state on completion as parallel process is active!
|
||||
StartProcess(process, BaseProductionProcess.DoNotChangeStateAfterCompletion);
|
||||
// Do not wait on completion as new parallel process can be started by manually state change.
|
||||
_stateMachineState = ProcessState.GetSerialNumberAndRadioAddress;
|
||||
break;
|
||||
|
||||
case ProcessState.GetSerialNumberAndRadioAddress:
|
||||
// Precondition: - The detection process has to be completed as the PcbId is needed.
|
||||
// AVOID to change the process state on completion as parallel process is active!
|
||||
StartProcess(process, BaseProductionProcess.DoNotChangeStateAfterCompletion);
|
||||
// Do not wait on completion as new parallel process can be started by manually state change.
|
||||
_stateMachineState = ProcessState.GetProgrammingParameters;
|
||||
break;
|
||||
|
||||
case ProcessState.GetProgrammingParameters:
|
||||
// Precondition: - The connection process has to be completed as a readout of some register
|
||||
// values from the Cordonel are needed to check the update capability:
|
||||
// - Wait on completed connection process before starting this process.
|
||||
// AVOID to change the process state on completion as parallel process is active!
|
||||
StartProcess(process, BaseProductionProcess.DoNotChangeStateAfterCompletion,
|
||||
waitForSingleProcess: _processStateDef?.GetProcessOfState(ProcessState.ConnectCordonel));
|
||||
// Do not wait on completion as new parallel process can be started by manually state change.
|
||||
_stateMachineState = ProcessState.CheckProductionState;
|
||||
break;
|
||||
|
||||
case ProcessState.CheckProductionState:
|
||||
// Precondition: - The connection process has to be completed as a readout of some register
|
||||
// values from the Cordonel are needed to check the update capability:
|
||||
// - Wait on completed connection process before starting this process.
|
||||
// AVOID to change the process state on completion as parallel process is active!
|
||||
StartProcess(process, BaseProductionProcess.DoNotChangeStateAfterCompletion,
|
||||
waitForSingleProcess: _processStateDef?.GetProcessOfState(ProcessState.ConnectCordonel));
|
||||
// Do not wait on completion as new parallel process can be started by manually state change.
|
||||
_stateMachineState = ProcessState.ProcessPasswordFile;
|
||||
break;
|
||||
|
||||
case ProcessState.ProcessPasswordFile:
|
||||
// Precondition: - The connection process has to be completed as a password change in the DB
|
||||
// will take place: Skeleton to Password Level 8. Not waiting for completion may cause side
|
||||
// effects on login. Wait for all processes to complete.
|
||||
// Leave state switch to automatic to avoid side effects on incomplete updated DB for next
|
||||
// steps.
|
||||
StartProcess(process, ProcessState.ExecFinalParametrization, waitForAllProcesses: true);
|
||||
break;
|
||||
|
||||
case ProcessState.ExecFinalParametrization:
|
||||
// This writes all setups to the device, it has to be executed exclusively with automatic
|
||||
StartProcess(process, ProcessState.ExecStoreConfiguration);
|
||||
break;
|
||||
|
||||
case ProcessState.ExecStoreConfiguration:
|
||||
// Precondition: - The final parametrization has to be finished as this shall be stored
|
||||
// to non-volatile memory and checked if remaining valid after the reboot.
|
||||
// Store configuration has to be executed exclusively with automatic
|
||||
StartProcess(process, ProcessState.RebootCordonel);
|
||||
break;
|
||||
|
||||
case ProcessState.RebootCordonel:
|
||||
// Precondition: - The store configuration has to be executed to safe all settings
|
||||
// to non-volatile memory and checked if remaining valid after the reboot.
|
||||
// Reboot has to be executed exclusively with automatic
|
||||
StartProcess(process, ProcessState.CheckFinalParametrization);
|
||||
break;
|
||||
|
||||
case ProcessState.CheckFinalParametrization:
|
||||
// Precondition: - The reboot process including the store all configurations has to be
|
||||
// completed.
|
||||
// Check final configuration has to be executed exclusively with automatic
|
||||
StartProcess(process, ProcessState.CheckRadio);
|
||||
break;
|
||||
|
||||
case ProcessState.CheckRadio:
|
||||
// Precondition: - The final parametrization, reboot process including the store all
|
||||
// configurations and the check of all setups survived the reboot have to be completed.
|
||||
// Radio signal level check, skipped on NA region or if skipping is required by special
|
||||
// approval
|
||||
StartProcess(process, ProcessState.CheckOrderNumber);
|
||||
break;
|
||||
|
||||
case ProcessState.CheckOrderNumber:
|
||||
// This scans the order number, it has to be executed exclusively with automatic
|
||||
StartProcess(process, ProcessState.CheckSerialNumber, waitForAllProcesses: true);
|
||||
break;
|
||||
|
||||
case ProcessState.CheckSerialNumber:
|
||||
// This scans the serial number, it has to be executed exclusively with automatic
|
||||
StartProcess(process, ProcessState.CheckAttachments);
|
||||
break;
|
||||
|
||||
case ProcessState.CheckAttachments:
|
||||
// Precondition: - All checks have to be executed with positive result
|
||||
StartProcess(process, ProcessState.ExecVisualInspection);
|
||||
break;
|
||||
|
||||
case ProcessState.ExecVisualInspection:
|
||||
// Precondition: - All checks have to be executed with positive result
|
||||
StartProcess(process, ProcessState.PrepareShippingMode);
|
||||
break;
|
||||
|
||||
case ProcessState.PrepareShippingMode:
|
||||
// Precondition: - All checks have to be executed with positive result
|
||||
StartProcess(process, ProcessState.ReadyForShipping);
|
||||
break;
|
||||
|
||||
case ProcessState.ReadyForShipping:
|
||||
_stateMachineState = ProcessState.Idle;
|
||||
break;
|
||||
|
||||
|
||||
case ProcessState.RepeatFailedTests:
|
||||
_stateMachineState = RepeatFailedTests();
|
||||
break;
|
||||
|
||||
case ProcessState.PrintReturnReport:
|
||||
_stateMachineState = ProcessState.Idle;
|
||||
break;
|
||||
|
||||
case ProcessState.PrintSuccessReport:
|
||||
_stateMachineState = ProcessState.Idle;
|
||||
break;
|
||||
|
||||
case ProcessState.AbortFinalTest:
|
||||
case ProcessState.AbortTest:
|
||||
AbortProcesses();
|
||||
_stateMachineState = ProcessState.Idle;
|
||||
break;
|
||||
@@ -527,14 +383,22 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses
|
||||
// Start the error handler with its user feedback request. It has to be started
|
||||
// always even if the abortion of all processes is required! The error handler
|
||||
// will change the exit state based on the user input.
|
||||
StartProcess(process, ProcessState.Idle, startAlways: true);
|
||||
StartProcess(processStateStruct);
|
||||
break;
|
||||
|
||||
case ProcessState.StateListDelimiter:
|
||||
default:
|
||||
_stateMachineState = ProcessState.Idle;
|
||||
break;
|
||||
}//
|
||||
|
||||
default:
|
||||
// This is the call to the processes for a specific test
|
||||
StartProcess(processStateStruct);
|
||||
if (processStateStruct.KickOffParallelState != null)
|
||||
{
|
||||
_stateMachineState = (ProcessState)processStateStruct.KickOffParallelState;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (ThreadAbortException ex)
|
||||
{
|
||||
@@ -549,6 +413,7 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses
|
||||
}
|
||||
}// state locked against repeated execution
|
||||
|
||||
|
||||
#endregion --------------------------------------- State Machine ----------------------------------------------
|
||||
#region ------------------------------------------ Tools ------------------------------------------------------
|
||||
/// <summary>
|
||||
@@ -738,8 +603,6 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses
|
||||
{
|
||||
if (Processes == null)
|
||||
Processes = new List<IProductionProcess>();
|
||||
if (_processStateDef == null)
|
||||
_processStateDef = new ProcessStateDef();
|
||||
|
||||
// get all processes relevant for EOL from table which has to be sorted
|
||||
var processes = _processStateDef.GetAllEolRelevantProcesses();
|
||||
@@ -768,14 +631,8 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses
|
||||
/// - Adds event handlers for process information,
|
||||
/// - Starts process.
|
||||
/// </summary>
|
||||
/// <param name="process"></param>
|
||||
/// <param name="successExitState"></param>
|
||||
/// <param name="errorExitState"></param>
|
||||
/// <param name="breakExitState"></param>
|
||||
/// <param name="waitForSingleProcess">wait for single processes to complete before execution</param>
|
||||
/// <param name="waitForAllProcesses">wait for all processes to complete before execution</param>
|
||||
/// <param name="startAlways">start even if abort is required</param>
|
||||
/// <returns>actual state</returns>
|
||||
/// <param name="processStateStruct"></param>
|
||||
/// <returns>actual state</returns>
|
||||
/// <remarks date="2023-Jan-31" author="Thomas Wiedebusch">
|
||||
/// - Initial
|
||||
/// </remarks>
|
||||
@@ -794,41 +651,42 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses
|
||||
/// <remarks date="2024-Sep-01" author="Thomas Wiedebusch">
|
||||
/// - Changed setup process to start process being able to create a process list in advance.
|
||||
/// </remarks>
|
||||
private void StartProcess(IProductionProcess process, ProcessState? successExitState,
|
||||
ProcessState errorExitState = ProcessState.Error, ProcessState breakExitState = ProcessState.Stop,
|
||||
IProductionProcess waitForSingleProcess = DoNotWaitForSingleProcessCompletion,
|
||||
Boolean waitForAllProcesses = false, Boolean startAlways = false)
|
||||
/// <remarks date="2025-Apr-15" author="Thomas Wiedebusch">
|
||||
/// - Feed with processStateStruct.
|
||||
/// </remarks>
|
||||
protected void StartProcess(ProcessStateStruct processStateStruct)
|
||||
{
|
||||
// deny access if uninitialized
|
||||
if (Processes == null || process == null)
|
||||
if (Processes == null || processStateStruct.ProductionProcess == null)
|
||||
return;
|
||||
|
||||
// do not start a new process if any error or abort request is signaled
|
||||
if (!startAlways && AnyProcessRequiresAbortion())
|
||||
if (AnyProcessRequiresAbortion() && !processStateStruct.StartAlways )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// process is waiting for execution after init, this overrides the eventually abort state
|
||||
process.InitProcess();
|
||||
processStateStruct.ProductionProcess.InitProcess();
|
||||
|
||||
// wait for a single process to complete before start of new depending on process
|
||||
if (waitForSingleProcess != DoNotWaitForSingleProcessCompletion)
|
||||
if (processStateStruct.WaitForSingleProcess != null)
|
||||
{
|
||||
// each process will have its own timer until a timeout will change the state
|
||||
while (Processes.Any(pp => pp.ProcessName == waitForSingleProcess.ProcessName
|
||||
&& WaitForProcess(pp)
|
||||
&& !AnyProcessRequiresAbortion()))
|
||||
while (Processes.Any(pp => !AnyProcessRequiresAbortion()
|
||||
&& _processStateDef.GetStateOfProcess(pp) == processStateStruct.WaitForSingleProcess
|
||||
&& WaitForProcess(pp)))
|
||||
{
|
||||
Thread.Sleep(50);
|
||||
}
|
||||
}
|
||||
|
||||
// wait for all initialized processes to complete before start the new process
|
||||
if (waitForAllProcesses)
|
||||
if (processStateStruct.WaitForAllProcesses)
|
||||
{
|
||||
// each process will have its own timer until a timeout will change the state,
|
||||
// avoid checking the new process, which is not started due to this waiting loop
|
||||
while (Processes.Any(pp => pp.ProcessName != process.ProcessName
|
||||
while (Processes.Any(pp => pp.ProcessName != processStateStruct.ProductionProcess.ProcessName
|
||||
&& WaitForProcess(pp)
|
||||
&& !AnyProcessRequiresAbortion()))
|
||||
{
|
||||
@@ -837,28 +695,29 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses
|
||||
}
|
||||
|
||||
// if any process exits meanwhile with an error or abort request avoid a start of this process
|
||||
if ((!startAlways && AnyProcessRequiresAbortion())
|
||||
|| process.SingleProcessState == SingleProcessState.Idle
|
||||
|| process.SingleProcessState == SingleProcessState.Abort)
|
||||
if (( !processStateStruct.StartAlways && AnyProcessRequiresAbortion())
|
||||
|| processStateStruct.ProductionProcess.SingleProcessState == SingleProcessState.Idle
|
||||
|| processStateStruct.ProductionProcess.SingleProcessState == SingleProcessState.Abort)
|
||||
{
|
||||
process.AbortProcess();
|
||||
processStateStruct.ProductionProcess.AbortProcess();
|
||||
return;
|
||||
}
|
||||
|
||||
// References to commonly used production process objects
|
||||
process.Meter = _genesisMeter;
|
||||
process.RegisterRestorer = _registerRestorer;
|
||||
process.RadioEncryptionKey = _radioEncryptionKey;
|
||||
process.PwdContainer = _pwdContainer;
|
||||
process.ProductionStatus = _productionStatus;
|
||||
process.ProductionRequirements = _cordonelRequirements;
|
||||
process.EolProgress = _cordonelEolProgress;
|
||||
process.CancellationToken = _cancellationToken;
|
||||
processStateStruct.ProductionProcess.Meter = _genesisMeter;
|
||||
processStateStruct.ProductionProcess.RegisterRestorer = _registerRestorer;
|
||||
processStateStruct.ProductionProcess.RadioEncryptionKey = _radioEncryptionKey;
|
||||
processStateStruct.ProductionProcess.PwdContainer = _pwdContainer;
|
||||
processStateStruct.ProductionProcess.ProductionStatus = _productionStatus;
|
||||
processStateStruct.ProductionProcess.ProductionRequirements = _cordonelRequirements;
|
||||
processStateStruct.ProductionProcess.EolProgress = _cordonelEolProgress;
|
||||
processStateStruct.ProductionProcess.CancellationToken = _cancellationToken;
|
||||
|
||||
// kick off process execution, the breakExitState will not be used
|
||||
process.StartProcess(successExitState, errorExitState, breakExitState);
|
||||
processStateStruct.ProductionProcess.StartProcess(processStateStruct.NextStateOnSuccess,
|
||||
processStateStruct.ErrorExitState, processStateStruct.BreakExitState);
|
||||
// connect process events to actual process
|
||||
AddProcessEvents(process);
|
||||
AddProcessEvents(processStateStruct.ProductionProcess);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -0,0 +1,860 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using LaaPackages.Features.Cordonel.Models;
|
||||
using Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore;
|
||||
using Xylem.Common.Hardware.WaterMeter.Genesis.GenesisPwd;
|
||||
using Xylem.Common.Hardware.WaterMeter.Genesis.GenesisStatus;
|
||||
using Xylem.Common.Hardware.WaterMeter.WaterMeterCore;
|
||||
using Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.Enum;
|
||||
using Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.EventArgs;
|
||||
using Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.GenericProcesses;
|
||||
using Timer = System.Threading.Timer;
|
||||
|
||||
namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses
|
||||
{
|
||||
/// <summary>
|
||||
/// Implementation for all methods needed to drive the state machine of the process controller
|
||||
/// </summary>
|
||||
public class ProcessController
|
||||
{
|
||||
#region ------------------------------------------ Variables --------------------------------------------------
|
||||
// actual genesis meter
|
||||
private IGenesisMeter _genesisMeter;
|
||||
// Cordonel requirements for production
|
||||
private CordonelRequirements _cordonelRequirements;
|
||||
// EOL progress states for production
|
||||
private EOLProgressModel _cordonelEolProgress;
|
||||
// last pcbId for check of changed genesisMeter
|
||||
private String _lastPcbId;
|
||||
// batch just used for setup, as only one meter will be assigned
|
||||
private MeterBatch _meterBatch;
|
||||
// state of the state machine
|
||||
private ProcessState _stateMachineState;
|
||||
// locker to avoid repeated state execution
|
||||
private ProcessState _lockedProcessState;
|
||||
// sender of state change event to evaluate in e.g. error process
|
||||
private IProductionProcess _stateChangeRequestProcess;
|
||||
// List of production processes
|
||||
public List<IProductionProcess> Processes
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
// Container for production process states
|
||||
private IProcessStateDef _processStateDef;
|
||||
|
||||
// Container for production status information, a list is used to keep the content over all classes of production
|
||||
// processes as a reference seems not to return their value (always reset to the initial value)
|
||||
private GenesisStatus _productionStatus;
|
||||
|
||||
// register restorer
|
||||
private RegisterRestorer _registerRestorer;
|
||||
|
||||
// sensus radio encryption key
|
||||
private List<String> _radioEncryptionKey;
|
||||
|
||||
// Password container with all information, a list is used to keep the content over all classes of production
|
||||
// processes as a reference seems not to return their value (always reset to the initial value)
|
||||
private MeterPwdDb _pwdContainer;
|
||||
|
||||
// reminder for slot
|
||||
private readonly Int32 _slot;
|
||||
|
||||
/// <summary>
|
||||
/// Change the overview table of the GUI to the state of the individual process
|
||||
/// </summary>
|
||||
public event EventHandler<SingleProcessStateArgs> OnSingleProcessStateChanged;
|
||||
|
||||
/// <summary>
|
||||
/// The overall process chain changed needed to signal to the GUI
|
||||
/// - Can be forced by the state machine to invoke,
|
||||
/// - Will be used via the OverallProcessStateChanged_Handler by the individual processes to return the next
|
||||
/// required sate after break, error or completion to change the state of the state machine.
|
||||
/// </summary>
|
||||
public event EventHandler<ProcessStateArgs> OnOverallProcessStateChanged;
|
||||
|
||||
/// <summary>
|
||||
/// Request for logging to GUI output and log-file
|
||||
/// </summary>
|
||||
public event EventHandler<ProcessLogArgs> OnProcessLogRequest;
|
||||
|
||||
/// <summary>
|
||||
/// Keep the progress bars of the GUI up to date
|
||||
/// </summary>
|
||||
public event EventHandler<ProcessProgressArgs> OnProcessProgressChanged;
|
||||
|
||||
// cancellation token
|
||||
private CancellationTokenSource _cancellationTokenSource;
|
||||
private CancellationToken _cancellationToken;
|
||||
|
||||
// cyclic timer for state machine call
|
||||
private Timer _processCtrlTimer;
|
||||
private const Int32 ProcessTimerCycleMs = 250;
|
||||
|
||||
/// <summary>
|
||||
/// Avoid waiting for a single process completion.
|
||||
/// </summary>
|
||||
public const IProductionProcess DoNotWaitForSingleProcessCompletion = null;
|
||||
|
||||
/// <summary>
|
||||
/// Kick off a parallel execution of the state machine.
|
||||
/// </summary>
|
||||
public const Boolean ExecuteInParallel = true;
|
||||
|
||||
#endregion --------------------------------------- Variables --------------------------------------------------
|
||||
#region ------------------------------------------ Class ------------------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// Ctor:
|
||||
/// - Setup process timer for cyclic call of state machine,
|
||||
/// - Create and setup Cordonel.
|
||||
/// </summary>
|
||||
/// <param name="slot">physical slot for this meter</param>
|
||||
/// <param name="processSateDef"></param>
|
||||
/// <remarks date="2023-Feb-14" author="Thomas Wiedebusch">
|
||||
/// - Initial
|
||||
/// </remarks>
|
||||
/// <remarks date="2023-Jul-04" author="Thomas Wiedebusch">
|
||||
/// - Always set to production mode to load the registers for this FW and not the latest,
|
||||
/// - Always RegisterWatchService on,
|
||||
/// - Always MinMaxCHeck on.
|
||||
/// </remarks>
|
||||
public ProcessController(Int32 slot, IProcessStateDef processSateDef)
|
||||
{
|
||||
_processCtrlTimer = new Timer(TmrProcessCtrlCycle_Elapsed, null, ProcessTimerCycleMs, ProcessTimerCycleMs);
|
||||
_slot = slot;
|
||||
_cancellationTokenSource = new CancellationTokenSource();
|
||||
_cancellationToken = _cancellationTokenSource.Token;
|
||||
_processStateDef = processSateDef;
|
||||
InitNewMeter();
|
||||
InitProcesses();
|
||||
// program start with idle process
|
||||
_stateMachineState = ProcessState.Idle;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initialization of new meter
|
||||
/// </summary>
|
||||
/// <remarks date="2023-Feb-14" author="Thomas Wiedebusch">
|
||||
/// - Initial
|
||||
/// </remarks>
|
||||
/// <remarks date="2024-Jul-15" author="Thomas Wiedebusch">
|
||||
/// - Initialize processes to build a list of all production processes.
|
||||
/// </remarks>
|
||||
/// <remarks date="2024-Sep-09" author="Thomas Wiedebusch">
|
||||
/// - Removed list of failed production processes
|
||||
/// </remarks>
|
||||
private void InitNewMeter()
|
||||
{
|
||||
_genesisMeter = new GenesisMeter();
|
||||
_genesisMeter.SetupFromConfigFile(_slot);
|
||||
// Important setup to overwrite setting from "Setup" in GTB
|
||||
_genesisMeter.Configuration.ProductionMode = true;
|
||||
_genesisMeter.Configuration.UseRegisterWatchService = true;
|
||||
_genesisMeter.Configuration.UseMinMaxCheck = true;
|
||||
// Meter batch even if only one meter in use as the meter batch routines can be used
|
||||
_meterBatch = new MeterBatch();
|
||||
_meterBatch.AddMeter(_genesisMeter);
|
||||
// Set lock process to unreachable state delimiter to force initial entry of state machine
|
||||
_lockedProcessState = ProcessState.StateListDelimiter;
|
||||
// Create a register restorer
|
||||
_registerRestorer = new RegisterRestorer(_genesisMeter);
|
||||
_radioEncryptionKey = new List<String>();
|
||||
// Containers for production status and standard or special requirement for production
|
||||
_productionStatus = new GenesisStatus();
|
||||
_cordonelRequirements = new CordonelRequirements();
|
||||
// Password container as reminder for repeated test on identical device
|
||||
_pwdContainer = new MeterPwdDb();
|
||||
// EOL progress to feed the sentinel
|
||||
_cordonelEolProgress = new EOLProgressModel();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removal of old meter
|
||||
/// </summary>
|
||||
private void RemoveMeter()
|
||||
{
|
||||
_genesisMeter?.ClearPassword();
|
||||
// meter batch dispose disposes all IMeters
|
||||
_meterBatch?.Dispose();
|
||||
_meterBatch = null;
|
||||
_genesisMeter = null;
|
||||
_registerRestorer = null;
|
||||
_radioEncryptionKey = null;
|
||||
_productionStatus = null;
|
||||
_cordonelRequirements = null;
|
||||
_pwdContainer = null;
|
||||
_cordonelEolProgress = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dispose.
|
||||
/// </summary>
|
||||
/// <remarks date="2023-Feb-14" author="Thomas Wiedebusch">
|
||||
/// - Initial
|
||||
/// </remarks>
|
||||
public void Dispose()
|
||||
{
|
||||
_processCtrlTimer?.Dispose();
|
||||
_processCtrlTimer = null;
|
||||
_processStateDef = null;
|
||||
KillProcesses();
|
||||
RemoveMeter();
|
||||
}
|
||||
|
||||
#endregion --------------------------------------- Class ------------------------------------------------------
|
||||
#region ------------------------------------------ Events -----------------------------------------------------
|
||||
/// <summary>
|
||||
/// Single process state or process list changed event,
|
||||
/// Use event to force special procedure like uninstalling events
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
/// <remarks date="2023-Feb-14" author="Thomas Wiedebusch">
|
||||
/// - Initial
|
||||
/// </remarks>
|
||||
/// <remarks date="2023-Jun-29" author="Thomas Wiedebusch">
|
||||
/// - Remove process events if process is finished.
|
||||
/// </remarks>
|
||||
/// <remarks date="2023-Jul-17" author="Thomas Wiedebusch">
|
||||
/// - Remove process events if process is finished or skipped.
|
||||
/// </remarks>
|
||||
private void SingleProcessStateChanged_Handler(Object sender, SingleProcessStateArgs e)
|
||||
{
|
||||
IProductionProcess pp = null;
|
||||
if (sender is IProductionProcess process)
|
||||
{
|
||||
pp = process;
|
||||
}
|
||||
// uninstall events
|
||||
switch (e.SingleProcessState)
|
||||
{
|
||||
// after execution independent of the result, the events coming from the process
|
||||
// are needed to be removed
|
||||
case SingleProcessState.Succeeded:
|
||||
case SingleProcessState.Skipped:
|
||||
case SingleProcessState.Abort:
|
||||
case SingleProcessState.Error:
|
||||
RemoveProcessEvents(pp);
|
||||
break;
|
||||
|
||||
case SingleProcessState.Retry:
|
||||
case SingleProcessState.Waiting:
|
||||
case SingleProcessState.Running:
|
||||
break;
|
||||
}
|
||||
// signal state change to GUI
|
||||
OnSingleProcessStateChanged?.Invoke(sender, e);
|
||||
}
|
||||
|
||||
private void ProcessProgress_Handler(Object sender, ProcessProgressArgs e)
|
||||
{
|
||||
OnProcessProgressChanged?.Invoke(sender, e);
|
||||
}
|
||||
|
||||
private void ProcessLog_Handler(Object sender, ProcessLogArgs e)
|
||||
{
|
||||
OnProcessLogRequest?.Invoke(sender, e);
|
||||
}
|
||||
/// <summary>
|
||||
/// Handler to set a new state for the state machine regarding the entire final-process
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
/// <remarks date="2023-Mar-03" author="Thomas Wiedebusch">
|
||||
/// - Initial
|
||||
/// </remarks>
|
||||
private void OverallProcessStateChanged_Handler(Object sender, ProcessStateArgs e)
|
||||
{
|
||||
// remind caller of the state change request to act on e.g. error processing
|
||||
_stateChangeRequestProcess = (IProductionProcess)sender;
|
||||
|
||||
// received new status from external
|
||||
if (e.State != null)
|
||||
{
|
||||
_stateMachineState = (ProcessState)e.State;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Process timer
|
||||
/// </summary>
|
||||
/// <param name="state"></param>
|
||||
/// <remarks date="2023-Jan-31" author="Thomas Wiedebusch">
|
||||
/// - Initial
|
||||
/// </remarks>
|
||||
private void TmrProcessCtrlCycle_Elapsed(Object state)
|
||||
{
|
||||
StateMachine();
|
||||
}
|
||||
|
||||
#endregion --------------------------------------- Events -----------------------------------------------------
|
||||
#region ------------------------------------------ State Machine ----------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// State-machine of ProcessController which serves all production processes.
|
||||
/// This-state machine executes all states defined in the "GenericStateMachineDef" and the individual
|
||||
/// production-process specific "XxxStateMachineDef".
|
||||
///
|
||||
/// A few states with special functions will be caught in advance in this StateMachine
|
||||
/// </summary>
|
||||
/// <remarks date="2023-Jan-17" author="Thomas Wiedebusch">
|
||||
/// - Initial
|
||||
/// </remarks>
|
||||
/// <remarks date="2025-Apr-15" author="Thomas Wiedebusch">
|
||||
/// - Generic implementation
|
||||
/// </remarks>
|
||||
private void StateMachine()
|
||||
{// avoid repeated execution of the state machine on unchanged state
|
||||
if (_stateMachineState == _lockedProcessState)
|
||||
{
|
||||
Thread.Sleep(ProcessTimerCycleMs >> 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
// remind backup state to avoid repeated execution and side effects
|
||||
_lockedProcessState = _stateMachineState;
|
||||
|
||||
// signal overall process progress to GUI based on ready processes
|
||||
CalcAndPushOverAllProgress();
|
||||
|
||||
// signal state change to logger
|
||||
OnOverallProcessStateChanged?.Invoke(this, new ProcessStateArgs(_stateMachineState));
|
||||
|
||||
// get the processStateStruct of the actual set stateMachineSTate
|
||||
var processStateStruct = _processStateDef.GetProcessStateStructOfState(_stateMachineState);
|
||||
|
||||
switch (_stateMachineState)
|
||||
{
|
||||
case ProcessState.Idle:
|
||||
// This state needs an external state change like user input to go ahead
|
||||
break;
|
||||
|
||||
case ProcessState.DetectCordonel:
|
||||
// Wait for cancellation
|
||||
if (_cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
Thread.Sleep(500);
|
||||
// Reset the cancellation request
|
||||
_cancellationTokenSource?.Dispose();
|
||||
_cancellationTokenSource = new CancellationTokenSource();
|
||||
_cancellationToken = _cancellationTokenSource.Token;
|
||||
}
|
||||
|
||||
// Set up the counter for maximum overall process progress bar in GUI
|
||||
CalcAndPushMaxOverAllProcessSteps();
|
||||
|
||||
// Detection of Cordonel has to be completed before assigning next state, so leave to automatic
|
||||
// to change the state after successfully execution. The detection is the base for all others.
|
||||
StartProcess(processStateStruct);
|
||||
break;
|
||||
|
||||
case ProcessState.CheckNewMeter:
|
||||
// Detection of Cordonel has to be completed before assigning next state. It has to be checked if
|
||||
// the meter changed to clear all collected contents of previous run. To UPDATE ALL INFORMATION after
|
||||
// new meter assignment the "DetectCordonel" has to be repeated to return here "Old Meter" and then
|
||||
// enter the "ConnectCordonel"!
|
||||
_stateMachineState = CheckForNewMeter() ? ProcessState.DetectCordonel : ProcessState.ConnectCordonel;
|
||||
break;
|
||||
|
||||
|
||||
case ProcessState.RepeatFailedTests:
|
||||
_stateMachineState = RepeatFailedTests();
|
||||
break;
|
||||
|
||||
case ProcessState.AbortTest:
|
||||
AbortProcesses();
|
||||
_stateMachineState = ProcessState.Idle;
|
||||
break;
|
||||
|
||||
case ProcessState.Stop:
|
||||
KillProcesses();
|
||||
_stateMachineState = ProcessState.Idle;
|
||||
break;
|
||||
|
||||
case ProcessState.Error:
|
||||
// Common error handling routine
|
||||
ProcessErrorHandler(_stateChangeRequestProcess);
|
||||
// Start the error handler with its user feedback request. It has to be started
|
||||
// always even if the abortion of all processes is required! The error handler
|
||||
// will change the exit state based on the user input.
|
||||
StartProcess(processStateStruct);
|
||||
break;
|
||||
|
||||
case ProcessState.StateListDelimiter:
|
||||
_stateMachineState = ProcessState.Idle;
|
||||
break;
|
||||
|
||||
default:
|
||||
// This is the call to the processes for a specific test
|
||||
StartProcess(processStateStruct);
|
||||
if (processStateStruct.KickOffParallelState != null)
|
||||
{
|
||||
_stateMachineState = (ProcessState)processStateStruct.KickOffParallelState;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (ThreadAbortException ex)
|
||||
{
|
||||
_genesisMeter?.WriteLog(ex.Message);
|
||||
_stateMachineState = ProcessState.Idle;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_genesisMeter?.WriteLog(ex.Message);
|
||||
_stateMachineState = ProcessState.Error;
|
||||
}
|
||||
}
|
||||
}// state locked against repeated execution
|
||||
|
||||
|
||||
#endregion --------------------------------------- State Machine ----------------------------------------------
|
||||
#region ------------------------------------------ Tools ------------------------------------------------------
|
||||
/// <summary>
|
||||
/// Returns the currentGenesis information for display
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
/// <remarks date="2023-Feb-27" author="Thomas Wiedebusch">
|
||||
/// - Initial
|
||||
/// </remarks>
|
||||
public CordonelRequirements GetProductionRequirements()
|
||||
{
|
||||
return _cordonelRequirements;
|
||||
}
|
||||
/// <summary>
|
||||
/// Returns the currentGenesis information for display
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
/// <remarks date="2023-Feb-27" author="Thomas Wiedebusch">
|
||||
/// - Initial
|
||||
/// </remarks>
|
||||
public IGenesisMeter GetGenesisMeter()
|
||||
{
|
||||
return _genesisMeter;
|
||||
}
|
||||
/// <summary>
|
||||
/// Clears all collected data on new genesisMeter and reminds the detected for next
|
||||
/// detection and run of this comparison.
|
||||
/// </summary>
|
||||
/// <returns>true for new meter</returns>
|
||||
/// <remarks date="2023-Jun-28" author="Thomas Wiedebusch">
|
||||
/// - Initial
|
||||
/// </remarks>
|
||||
/// <remarks date="2023-Jul-17" author="Thomas Wiedebusch">
|
||||
/// - The StartProcessSequence has already removed all processes from list to have a clean start,
|
||||
/// avoid it here again, because the detect is now in the list!
|
||||
/// </remarks>
|
||||
/// <remarks date="2024-Jul-15" author="Thomas Wiedebusch">
|
||||
/// - Handle genesis meter is null as new meter.
|
||||
/// </remarks>
|
||||
/// <remarks date="2025-Mai-12" author="Thomas Wiedebusch">
|
||||
/// - Check _genesisMeter not null before equality with old pcbid.
|
||||
/// </remarks>
|
||||
private Boolean CheckForNewMeter()
|
||||
{
|
||||
if (_genesisMeter == null ||
|
||||
(!string.IsNullOrEmpty(_lastPcbId) &&
|
||||
_genesisMeter?.PcbId != null && !_genesisMeter.PcbId.Equals(_lastPcbId)))
|
||||
{
|
||||
// This loop will be entered after the meter has changed, but not on the initial meter
|
||||
// after program start.
|
||||
KillProcesses();
|
||||
RemoveMeter();
|
||||
InitNewMeter();
|
||||
InitProcesses();
|
||||
// Remind actual genesis
|
||||
_lastPcbId = _genesisMeter?.PcbId;
|
||||
|
||||
// New meter detected
|
||||
return true;
|
||||
}
|
||||
|
||||
// Remind actual genesis
|
||||
_lastPcbId = _genesisMeter?.PcbId;
|
||||
|
||||
// Old meter
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Restart final test on first failed or aborted test.
|
||||
/// </summary>
|
||||
/// <remarks date="2023-Jul-18" author="Thomas Wiedebusch">
|
||||
/// - Initial
|
||||
/// </remarks>
|
||||
/// <remarks date="2024-Sep-09" author="Thomas Wiedebusch">
|
||||
/// - Removed list of failed production processes and search in Processes
|
||||
/// </remarks>
|
||||
/// <remarks date="2024-Oct-21" author="Thomas Wiedebusch">
|
||||
/// - Leave skipped processes as is.
|
||||
/// </remarks>
|
||||
private ProcessState RepeatFailedTests()
|
||||
{
|
||||
var state = ProcessState.Idle;
|
||||
|
||||
// Search for first test in processes list which failed or aborted due to final test in
|
||||
// parallel processing forced abort of active processes
|
||||
foreach (var p in Processes)
|
||||
{
|
||||
if (p.SingleProcessState == SingleProcessState.Error ||
|
||||
p.SingleProcessState == SingleProcessState.Abort ||
|
||||
p.SingleProcessState == SingleProcessState.Retry)
|
||||
{
|
||||
// set the state to the first entry to kick off the state machine here
|
||||
state = _processStateDef.GetStateOfProcess(p);
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Put all processes which are not successfully completed to init (Waiting for execution)
|
||||
foreach (var pp in Processes.Where(pp => pp.SingleProcessState != SingleProcessState.Succeeded &&
|
||||
pp.SingleProcessState != SingleProcessState.Skipped))
|
||||
{
|
||||
pp.IdleProcess();
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
/// <summary>
|
||||
/// Error handler
|
||||
/// </summary>
|
||||
/// <remarks date="2023-Feb-15" author="Thomas Wiedebusch">
|
||||
/// - Initial
|
||||
/// </remarks>
|
||||
/// <remarks date="2024-Feb-07" author="Thomas Wiedebusch">
|
||||
/// - Activated check for sequences in production process for ProductionProcessCheckFinalParametrization
|
||||
/// to re-start with ProductionProcessExecFinalParametrization.
|
||||
/// </remarks>
|
||||
/// <remarks date="2024-Sep-09" author="Thomas Wiedebusch">
|
||||
/// - Removed list of failed production processes
|
||||
/// </remarks>
|
||||
/// <remarks date="2025-Jan-28" author="Thomas Wiedebusch">
|
||||
/// - Kick off exec parametrization if check after reboot failed.
|
||||
/// </remarks>
|
||||
private void ProcessErrorHandler(IProductionProcess process)
|
||||
{
|
||||
if (process == null)
|
||||
return;
|
||||
// Special action if parametrization check failed to repeat it
|
||||
if (ProcessState.CheckFinalParametrization == _processStateDef.GetStateOfProcess(process))
|
||||
{
|
||||
// Signal state change to retry sequence exec config, store config, reboot, check config
|
||||
var pp = _processStateDef.GetProcessOfState(ProcessState.ExecFinalParametrization);
|
||||
pp.RetryProcess();
|
||||
pp = _processStateDef.GetProcessOfState(ProcessState.ExecStoreConfiguration);
|
||||
pp.RetryProcess();
|
||||
pp = _processStateDef.GetProcessOfState(ProcessState.RebootCordonel);
|
||||
pp.RetryProcess();
|
||||
pp = _processStateDef.GetProcessOfState(ProcessState.CheckFinalParametrization);
|
||||
pp.RetryProcess();
|
||||
}
|
||||
|
||||
// Error signal needed to abort to all processes
|
||||
AbortProcesses();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calculate the maximum of all processes expected to execute and signal to GUI.
|
||||
/// </summary>
|
||||
private void CalcAndPushMaxOverAllProcessSteps()
|
||||
{
|
||||
if (_processStateDef == null)
|
||||
return;
|
||||
|
||||
var _maxOverallProcessesSteps = _processStateDef.GetNumberOfInitializedProcesses();
|
||||
OnProcessProgressChanged?.Invoke(this, new ProcessProgressArgs(_maxOverallProcessesSteps,
|
||||
ProcessProgressArgs.ProcessProgressType.MaxOverallProcessSteps));
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Calculate all processes which are completed or skipped and signal to GUI.
|
||||
/// </summary>
|
||||
private void CalcAndPushOverAllProgress()
|
||||
{
|
||||
if (Processes == null)
|
||||
return;
|
||||
|
||||
// check the readiness of all processes in the loop
|
||||
var _overallReadyProcesses = 0;
|
||||
foreach (var p in Processes)
|
||||
{
|
||||
if (p.SingleProcessState == SingleProcessState.Succeeded ||
|
||||
p.SingleProcessState == SingleProcessState.Skipped)
|
||||
_overallReadyProcesses++;
|
||||
}
|
||||
|
||||
OnProcessProgressChanged?.Invoke(this, new ProcessProgressArgs(_overallReadyProcesses,
|
||||
ProcessProgressArgs.ProcessProgressType.OverallProcessesSteps));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initialize all processes which are connected to a production process.
|
||||
/// </summary>
|
||||
/// <remarks date="2024-Jul-15" author="Thomas Wiedebusch">
|
||||
/// - Initial
|
||||
/// </remarks>
|
||||
private void InitProcesses()
|
||||
{
|
||||
if (Processes == null)
|
||||
Processes = new List<IProductionProcess>();
|
||||
|
||||
// get all processes relevant for EOL from table which has to be sorted
|
||||
var processes = _processStateDef.GetAllEolRelevantProcesses();
|
||||
|
||||
foreach (var process in processes)
|
||||
{
|
||||
// process is standby for execution after idle, this overrides the eventually abort state
|
||||
process.IdleProcess();
|
||||
|
||||
// add process to list to feed the process window in main screen
|
||||
if (Processes.All(pp => pp.ProcessName != process.ProcessName))
|
||||
{
|
||||
Processes.Add(process);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Production process kick off:
|
||||
/// - Sets single process state to waiting within the process init,
|
||||
/// - Adds new process to process list,
|
||||
/// - Optional waits for single process to complete before process is going to be started,
|
||||
/// - Optional waits for all previously assigned and started processes to complete before process is going to
|
||||
/// be started,
|
||||
/// - Assigns slot, productionStatus, programmingParameters and genesisMeter to process,
|
||||
/// - Adds event handlers for process information,
|
||||
/// - Starts process.
|
||||
/// </summary>
|
||||
/// <param name="processStateStruct"></param>
|
||||
/// <returns>actual state</returns>
|
||||
/// <remarks date="2023-Jan-31" author="Thomas Wiedebusch">
|
||||
/// - Initial
|
||||
/// </remarks>
|
||||
/// <remarks date="2023-Jun-21" author="Thomas Wiedebusch">
|
||||
/// - Skipped process due to one of the previous processes failed
|
||||
/// </remarks>
|
||||
/// <remarks date="2023-Jul-17" author="Thomas Wiedebusch">
|
||||
/// - Restructured to avoid process start if processes to wait for are not completed
|
||||
/// </remarks>
|
||||
/// <remarks date="2023-Dec-15" author="Thomas Wiedebusch">
|
||||
/// - Changed from programming parameters to register restorer
|
||||
/// </remarks>
|
||||
/// <remarks date="2024-Jul-15" author="Thomas Wiedebusch">
|
||||
/// - Changed setup process to start process being able to create a process list in advance.
|
||||
/// </remarks>
|
||||
/// <remarks date="2024-Sep-01" author="Thomas Wiedebusch">
|
||||
/// - Changed setup process to start process being able to create a process list in advance.
|
||||
/// </remarks>
|
||||
/// <remarks date="2025-Apr-15" author="Thomas Wiedebusch">
|
||||
/// - Feed with processStateStruct.
|
||||
/// </remarks>
|
||||
protected void StartProcess(ProcessStateStruct processStateStruct)
|
||||
{
|
||||
// deny access if uninitialized
|
||||
if (Processes == null || processStateStruct.ProductionProcess == null)
|
||||
return;
|
||||
|
||||
// do not start a new process if any error or abort request is signaled
|
||||
if (AnyProcessRequiresAbortion() && !processStateStruct.StartAlways )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// process is waiting for execution after init, this overrides the eventually abort state
|
||||
processStateStruct.ProductionProcess.InitProcess();
|
||||
|
||||
// wait for a single process to complete before start of new depending on process
|
||||
if (processStateStruct.WaitForSingleProcess != null)
|
||||
{
|
||||
// each process will have its own timer until a timeout will change the state
|
||||
while (Processes.Any(pp => !AnyProcessRequiresAbortion()
|
||||
&& _processStateDef.GetStateOfProcess(pp) == processStateStruct.WaitForSingleProcess
|
||||
&& WaitForProcess(pp)))
|
||||
{
|
||||
Thread.Sleep(50);
|
||||
}
|
||||
}
|
||||
|
||||
// wait for all initialized processes to complete before start the new process
|
||||
if (processStateStruct.WaitForAllProcesses)
|
||||
{
|
||||
// each process will have its own timer until a timeout will change the state,
|
||||
// avoid checking the new process, which is not started due to this waiting loop
|
||||
while (Processes.Any(pp => pp.ProcessName != processStateStruct.ProductionProcess.ProcessName
|
||||
&& WaitForProcess(pp)
|
||||
&& !AnyProcessRequiresAbortion()))
|
||||
{
|
||||
Thread.Sleep(50);
|
||||
}
|
||||
}
|
||||
|
||||
// if any process exits meanwhile with an error or abort request avoid a start of this process
|
||||
if (( !processStateStruct.StartAlways && AnyProcessRequiresAbortion())
|
||||
|| processStateStruct.ProductionProcess.SingleProcessState == SingleProcessState.Idle
|
||||
|| processStateStruct.ProductionProcess.SingleProcessState == SingleProcessState.Abort)
|
||||
{
|
||||
processStateStruct.ProductionProcess.AbortProcess();
|
||||
return;
|
||||
}
|
||||
|
||||
// References to commonly used production process objects
|
||||
processStateStruct.ProductionProcess.Meter = _genesisMeter;
|
||||
processStateStruct.ProductionProcess.RegisterRestorer = _registerRestorer;
|
||||
processStateStruct.ProductionProcess.RadioEncryptionKey = _radioEncryptionKey;
|
||||
processStateStruct.ProductionProcess.PwdContainer = _pwdContainer;
|
||||
processStateStruct.ProductionProcess.ProductionStatus = _productionStatus;
|
||||
processStateStruct.ProductionProcess.ProductionRequirements = _cordonelRequirements;
|
||||
processStateStruct.ProductionProcess.EolProgress = _cordonelEolProgress;
|
||||
processStateStruct.ProductionProcess.CancellationToken = _cancellationToken;
|
||||
|
||||
// kick off process execution, the breakExitState will not be used
|
||||
processStateStruct.ProductionProcess.StartProcess(processStateStruct.NextStateOnSuccess,
|
||||
processStateStruct.ErrorExitState, processStateStruct.BreakExitState);
|
||||
// connect process events to actual process
|
||||
AddProcessEvents(processStateStruct.ProductionProcess);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check all processes for error or abort request
|
||||
/// </summary>
|
||||
/// <returns>true if abort required</returns>
|
||||
/// <remarks date="2025-Apr-10" author="Thomas Wiedebusch">
|
||||
/// - Cancellation token.
|
||||
/// </remarks>
|
||||
private Boolean AnyProcessRequiresAbortion()
|
||||
{
|
||||
return Processes.Any(pp => pp.SingleProcessState == SingleProcessState.Error ||
|
||||
pp.SingleProcessState == SingleProcessState.Abort ||
|
||||
_cancellationToken.IsCancellationRequested);
|
||||
}
|
||||
/// <summary>
|
||||
/// Check process if in status waiting or running (incomplete)
|
||||
/// </summary>
|
||||
/// <param name="pp">production process</param>
|
||||
/// <returns>true if process to wait for execution or exit running state</returns>
|
||||
private Boolean WaitForProcess(IProductionProcess pp)
|
||||
{
|
||||
return pp.SingleProcessState == SingleProcessState.Waiting ||
|
||||
pp.SingleProcessState == SingleProcessState.Running;
|
||||
}
|
||||
/// <summary>
|
||||
/// Install process events
|
||||
/// </summary>
|
||||
/// <param name="process"></param>
|
||||
private void AddProcessEvents(IProductionProcess process)
|
||||
{
|
||||
if (process == null)
|
||||
return;
|
||||
|
||||
process.OnProcessProgressChanged += ProcessProgress_Handler;
|
||||
process.OnProcessLogRequest += ProcessLog_Handler;
|
||||
process.OnSingleProcessStateChanged += SingleProcessStateChanged_Handler;
|
||||
process.OnOverallProcessStateChanged += OverallProcessStateChanged_Handler;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove process events
|
||||
/// </summary>
|
||||
/// <param name="process"></param>
|
||||
private void RemoveProcessEvents(IProductionProcess process)
|
||||
{
|
||||
if (process == null)
|
||||
return;
|
||||
|
||||
process.OnProcessProgressChanged -= ProcessProgress_Handler;
|
||||
process.OnProcessLogRequest -= ProcessLog_Handler;
|
||||
process.OnSingleProcessStateChanged -= SingleProcessStateChanged_Handler;
|
||||
process.OnOverallProcessStateChanged -= OverallProcessStateChanged_Handler;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the actual process state of the state machine
|
||||
/// </summary>
|
||||
/// <returns>actual process state</returns>
|
||||
/// <remarks date="2023-Jan-17" author="Thomas Wiedebusch">
|
||||
/// - Initial
|
||||
/// </remarks>
|
||||
private ProcessState GetProcessState()
|
||||
{
|
||||
return _stateMachineState;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the new process state of the state machine
|
||||
/// </summary>
|
||||
/// <returns>true, if process state is set</returns>
|
||||
/// <remarks date="2023-Jan-17" author="Thomas Wiedebusch">
|
||||
/// - Initial
|
||||
/// </remarks>
|
||||
public Boolean SetProcessState(ProcessState newProcessState)
|
||||
{
|
||||
if (newProcessState != _stateMachineState)
|
||||
{
|
||||
_stateMachineState = newProcessState;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove all processes from the <see cref="Processes"/> list:
|
||||
/// - Signal change to GUI,
|
||||
/// - Remove process events all,
|
||||
/// - Set state to abort.
|
||||
/// </summary>
|
||||
/// <remarks date="2023-Jul-11" author="Thomas Wiedebusch">
|
||||
/// - Initial
|
||||
/// </remarks>
|
||||
/// <remarks date="2025-Feb-13" author="Thomas Wiedebusch">
|
||||
/// - Abort register access.
|
||||
/// </remarks>
|
||||
/// <remarks date="2025-Apr-07" author="Thomas Wiedebusch">
|
||||
/// - Cancellation token source.
|
||||
/// </remarks>
|
||||
private void KillProcesses()
|
||||
{
|
||||
_cancellationTokenSource?.Cancel();
|
||||
Thread.Sleep(1000);
|
||||
|
||||
if (Processes == null || Processes.Count == 0)
|
||||
return;
|
||||
|
||||
// put all processes to idle and remove events of these processes
|
||||
foreach (var pp in Processes)
|
||||
{
|
||||
pp.IdleProcess();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Abort all processes if one previous process failed, but leave the <see cref="Processes"/> list intact.
|
||||
/// Leave all events for those which are already running intact to force a clean stop.
|
||||
/// </summary>
|
||||
/// <remarks date="2023-Jun-21" author="Thomas Wiedebusch">
|
||||
/// - Initial
|
||||
/// </remarks>
|
||||
private void AbortProcesses()
|
||||
{
|
||||
if (Processes == null || Processes.Count == 0)
|
||||
return;
|
||||
|
||||
// Skip all processes which are not succeeded, erroneous or skipped to leave the status intact
|
||||
// and request abort for all others
|
||||
foreach (var pp in Processes.Where(pp => pp.SingleProcessState != SingleProcessState.Succeeded &&
|
||||
pp.SingleProcessState != SingleProcessState.Error &&
|
||||
pp.SingleProcessState != SingleProcessState.Skipped &&
|
||||
pp.SingleProcessState != SingleProcessState.Retry))
|
||||
{
|
||||
pp.AbortProcess();
|
||||
}
|
||||
}
|
||||
#endregion --------------------------------------- Tools ------------------------------------------------------
|
||||
}
|
||||
}
|
||||
@@ -1,306 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Xylem.Common.Production.ProductionUiCordonel.Properties;
|
||||
using Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.Enum;
|
||||
using Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.EolProcesses;
|
||||
|
||||
namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses
|
||||
{
|
||||
/// <summary>
|
||||
/// Concatenation for all production process states:
|
||||
/// - Production process class (representing a production process step),
|
||||
/// - attached state,
|
||||
/// - state information to display a text message.
|
||||
/// </summary>
|
||||
/// <remarks date="2023-Feb-14" author="Thomas Wiedebusch">
|
||||
/// - Initial
|
||||
/// </remarks>
|
||||
public class ProcessStateDef
|
||||
{
|
||||
/// <summary>
|
||||
/// Collection of state information
|
||||
/// </summary>
|
||||
private readonly List<ProcessStateStruct> _stateContainer;
|
||||
|
||||
/// <summary>
|
||||
/// Ctor
|
||||
/// - Setup state and state informal text,
|
||||
/// - Setup ProductionProcessFunctions, if these are null, it is just a state without any predefined function
|
||||
/// - Sort the active steps from first til last step as this is the order as those will be sorted in the
|
||||
/// process list UI.
|
||||
/// </summary>
|
||||
public ProcessStateDef()
|
||||
{
|
||||
_stateContainer = new List<ProcessStateStruct>
|
||||
{
|
||||
new ProcessStateStruct(
|
||||
null,
|
||||
ProcessState.Idle,
|
||||
Resources.StrStateIdle,
|
||||
false),
|
||||
|
||||
new ProcessStateStruct(
|
||||
null,
|
||||
ProcessState.CheckNewMeter,
|
||||
Resources.StrProcessStateCheckNewMeter,
|
||||
false),
|
||||
|
||||
new ProcessStateStruct(
|
||||
new ErrorHandler(null),
|
||||
ProcessState.Error,
|
||||
Resources.StrProcessStateError,
|
||||
false),
|
||||
|
||||
new ProcessStateStruct(
|
||||
null,
|
||||
ProcessState.RepeatFailedTests,
|
||||
Resources.StrStateRepeatFinalTest,
|
||||
false),
|
||||
|
||||
new ProcessStateStruct(
|
||||
null,
|
||||
ProcessState.AbortFinalTest,
|
||||
Resources.StrStateSkipping,
|
||||
false),
|
||||
|
||||
new ProcessStateStruct(
|
||||
null,
|
||||
ProcessState.Stop,
|
||||
Resources.StrStateUserStop,
|
||||
false),
|
||||
|
||||
new ProcessStateStruct(
|
||||
null,
|
||||
ProcessState.FinalTestFailed,
|
||||
Resources.StrStateFinalTestFailed,
|
||||
false),
|
||||
|
||||
new ProcessStateStruct(
|
||||
null,
|
||||
ProcessState.ReadyForShipping,
|
||||
Resources.StrStateReadyForShipping,
|
||||
false),
|
||||
|
||||
new ProcessStateStruct(
|
||||
null,
|
||||
ProcessState.PrintSuccessReport,
|
||||
Resources.StrStatePrintSuccessReport,
|
||||
false),
|
||||
|
||||
new ProcessStateStruct(
|
||||
null,
|
||||
ProcessState.PrintReturnReport,
|
||||
Resources.StrStatePrintReturnReport,
|
||||
false),
|
||||
|
||||
new ProcessStateStruct(
|
||||
new DetectCordonel(Resources.StrStateDetectCordonel),
|
||||
ProcessState.DetectCordonel,
|
||||
Resources.StrStateDetectCordonel,
|
||||
true),
|
||||
|
||||
new ProcessStateStruct(
|
||||
new ConnectCordonel(Resources.StrStateConnectCordonel),
|
||||
ProcessState.ConnectCordonel,
|
||||
Resources.StrStateConnectCordonel,
|
||||
true),
|
||||
|
||||
new ProcessStateStruct(
|
||||
new GetSerialNumberAndRadioAddress(Resources.StrStateGetSerialAndRadioAddress),
|
||||
ProcessState.GetSerialNumberAndRadioAddress,
|
||||
Resources.StrStateGetSerialAndRadioAddress,
|
||||
true),
|
||||
|
||||
new ProcessStateStruct(
|
||||
new GetFinalParametrization(Resources.StrStateGetProgrammingParameters),
|
||||
ProcessState.GetProgrammingParameters,
|
||||
Resources.StrStateGetProgrammingParameters,
|
||||
true),
|
||||
|
||||
new ProcessStateStruct(
|
||||
new CheckProductionState(Resources.StrStateCheckProductionState),
|
||||
ProcessState.CheckProductionState,
|
||||
Resources.StrStateCheckProductionState,
|
||||
true),
|
||||
|
||||
new ProcessStateStruct(
|
||||
new ExecPasswordFile(Resources.StrStatePasswordFile),
|
||||
ProcessState.ProcessPasswordFile,
|
||||
Resources.StrStatePasswordFile,
|
||||
true),
|
||||
|
||||
new ProcessStateStruct(
|
||||
new ExecFinalParametrization(Resources.StrStateFinalParametrization),
|
||||
ProcessState.ExecFinalParametrization,
|
||||
Resources.StrStateFinalParametrization,
|
||||
true),
|
||||
|
||||
new ProcessStateStruct(
|
||||
new ExecStoreConfiguration(Resources.StrStateStoreConfiguration),
|
||||
ProcessState.ExecStoreConfiguration,
|
||||
Resources.StrStateStoreConfiguration,
|
||||
true),
|
||||
|
||||
new ProcessStateStruct(
|
||||
new ExecRebootCordonel(Resources.StrStateRebootCordonel),
|
||||
ProcessState.RebootCordonel,
|
||||
Resources.StrStateRebootCordonel,
|
||||
true),
|
||||
|
||||
new ProcessStateStruct(
|
||||
new CheckFinalParametrization(Resources.StrStateCheckParametrization),
|
||||
ProcessState.CheckFinalParametrization,
|
||||
Resources.StrStateCheckParametrization,
|
||||
true),
|
||||
|
||||
new ProcessStateStruct(
|
||||
new CheckRadio(Resources.StrStateRadioCheck),
|
||||
ProcessState.CheckRadio, Resources.StrStateRadioCheck,
|
||||
true),
|
||||
|
||||
new ProcessStateStruct(
|
||||
new CheckOrderNumber(Resources.StrStateCheckOrderNumber),
|
||||
ProcessState.CheckOrderNumber,
|
||||
Resources.StrStateCheckOrderNumber,
|
||||
true),
|
||||
|
||||
new ProcessStateStruct(
|
||||
new CheckSerialNumber( Resources.StrStateCheckSerialNumber),
|
||||
ProcessState.CheckSerialNumber,
|
||||
Resources.StrStateCheckSerialNumber,
|
||||
true),
|
||||
|
||||
new ProcessStateStruct(
|
||||
new CheckAttachments(Resources.StrStateCheckAttachments),
|
||||
ProcessState.CheckAttachments,
|
||||
Resources.StrStateCheckAttachments,
|
||||
true),
|
||||
|
||||
new ProcessStateStruct(
|
||||
new VisualInspection(Resources.StrStateVisualInspection),
|
||||
ProcessState.ExecVisualInspection,
|
||||
Resources.StrStateVisualInspection,
|
||||
true),
|
||||
|
||||
new ProcessStateStruct(
|
||||
new PrepareShipping(Resources.StrStatePrepareShipping),
|
||||
ProcessState.PrepareShippingMode,
|
||||
Resources.StrStatePrepareShipping,
|
||||
true)
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the process linked to state of state machine
|
||||
/// </summary>
|
||||
/// <param name="stateMachineState">state to search for information text</param>
|
||||
/// <returns>process attached to state</returns>
|
||||
/// <remarks date="2023-Feb-14" author="Thomas Wiedebusch">
|
||||
/// - Initial
|
||||
/// </remarks>
|
||||
public IProductionProcess GetProcessOfState(ProcessState stateMachineState)
|
||||
{
|
||||
return (from stateContainer in _stateContainer
|
||||
where stateContainer.State == stateMachineState
|
||||
select stateContainer.Process).FirstOrDefault();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the current information of the state machine state
|
||||
/// </summary>
|
||||
/// <param name="stateMachineState">state to search for information text</param>
|
||||
/// <returns>information attached to state depending on region</returns>
|
||||
/// <remarks date="2023-Feb-14" author="Thomas Wiedebusch">
|
||||
/// - Initial
|
||||
/// </remarks>
|
||||
/// <remarks date="2024-Mar-18" author="Thomas Wiedebusch">
|
||||
/// - If state == null return error message.
|
||||
/// </remarks>
|
||||
public String GetStateInfoOfState(ProcessState? stateMachineState)
|
||||
{
|
||||
if (stateMachineState == null)
|
||||
stateMachineState = ProcessState.Error;
|
||||
|
||||
return (from stateContainer in _stateContainer
|
||||
where stateContainer.State == stateMachineState
|
||||
select stateContainer.Info).FirstOrDefault();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the info text from production process
|
||||
/// </summary>
|
||||
/// <param name="process">process to look for state info text</param>
|
||||
/// <returns>information attached to process depending on region</returns>
|
||||
/// <remarks date="2023-Mar-20" author="Thomas Wiedebusch">
|
||||
/// - Initial
|
||||
/// </remarks>
|
||||
public String GetStateInfoOfProcess(IProductionProcess process)
|
||||
{
|
||||
return (from stateContainer in _stateContainer
|
||||
where stateContainer.Process == process
|
||||
select stateContainer.Info).FirstOrDefault();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the state machine state of the text
|
||||
/// </summary>
|
||||
/// <param name="text">information text to search if state is assigned</param>
|
||||
/// <returns>state attached to information text</returns>
|
||||
/// <remarks date="2023-Feb-14" author="Thomas Wiedebusch">
|
||||
/// - Initial
|
||||
/// </remarks>
|
||||
public ProcessState GetStateOfInfoText(String text)
|
||||
{
|
||||
return (from stateContainer in _stateContainer
|
||||
where stateContainer.Info == text
|
||||
select stateContainer.State).FirstOrDefault();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the state machine state from for the process
|
||||
/// </summary>
|
||||
/// <param name="process">process to look for state info text</param>
|
||||
/// <returns>state attached to process</returns>
|
||||
/// <remarks date="2023-Mar-20" author="Thomas Wiedebusch">
|
||||
/// - Initial
|
||||
/// </remarks>
|
||||
public ProcessState GetStateOfProcess(IProductionProcess process)
|
||||
{
|
||||
return (from stateContainer in _stateContainer
|
||||
where stateContainer.Process == process
|
||||
select stateContainer.State).FirstOrDefault();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get number of EOL relevant processes for statistic e.g. progress bar
|
||||
/// </summary>
|
||||
/// <returns>number of initialized processes</returns>
|
||||
/// <remarks date="2023-Mar-20" author="Thomas Wiedebusch">
|
||||
/// - Initial
|
||||
/// </remarks>
|
||||
/// <remarks date="2024-Sep-01" author="Thomas Wiedebusch">
|
||||
/// - Used marker for production relevant processes
|
||||
/// </remarks>
|
||||
public Int32 GetNumberOfInitializedProcesses()
|
||||
{
|
||||
return _stateContainer.Count(stateContainer => stateContainer.ProductionRelevant );
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get all EOL relevant states
|
||||
/// </summary>
|
||||
/// <returns>list of initialized processes</returns>
|
||||
/// <remarks date="2024-Jul-15" author="Thomas Wiedebusch">
|
||||
/// - Initial
|
||||
/// </remarks>
|
||||
/// <remarks date="2024-Sep-01" author="Thomas Wiedebusch">
|
||||
/// - Used marker for production relevant processes
|
||||
/// </remarks>
|
||||
public List<IProductionProcess> GetAllEolRelevantProcesses()
|
||||
{
|
||||
return (from state in _stateContainer where state.ProductionRelevant
|
||||
select state.Process).ToList();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,42 +4,105 @@ using Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.Enum;
|
||||
namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses
|
||||
{
|
||||
/// <summary>
|
||||
/// Concatenation between final test state and text
|
||||
/// Concatenation between test state and text feeding the state machine with next state.
|
||||
/// </summary>
|
||||
public struct ProcessStateStruct
|
||||
{
|
||||
/// <summary>
|
||||
/// Assign process state information
|
||||
/// </summary>
|
||||
/// <param name="process">production process</param>
|
||||
/// <param name="state">assigned state for call of this process</param>
|
||||
/// <param name="info">name for process to display a message</param>
|
||||
/// <param name="productionRelevant">all processes which are relevant for the EOL production</param>
|
||||
/// <param name="productionProcess">production process, set to null for "invisible" states</param>
|
||||
/// <param name="processState">assigned state for call of this process used by the state machine</param>
|
||||
/// <param name="processInfo">name for process to display a message in the GUI</param>
|
||||
/// <param name="productionProcessNo">set a unique number to sort the table of production processes,
|
||||
/// set to null for all hidden processes which are not a production process</param>
|
||||
/// <param name="nextStateOnSuccess">BaseProductionProcess.DoNotChangeStateAfterCompletion will not
|
||||
/// change the state automatically</param>
|
||||
/// <param name="errorExitState"></param>
|
||||
/// <param name="breakExitState"></param>
|
||||
/// <param name="kickOffParallelState">start a parallel process</param>
|
||||
/// <param name="waitForSingleProcess">wait for single processes to complete before execution</param>
|
||||
/// <param name="waitForAllProcesses">wait for all processes to complete before execution</param>
|
||||
/// <param name="startAlways">start even if abort is required</param>
|
||||
/// <remarks date="2023-Jan-17" author="Thomas Wiedebusch">
|
||||
/// - Initial
|
||||
/// </remarks>
|
||||
public ProcessStateStruct(IProductionProcess process, ProcessState state, String info, Boolean productionRelevant)
|
||||
/// <remarks date="2025-Apr-14" author="Thomas Wiedebusch">
|
||||
/// - Extended to steer state machine with this struct.
|
||||
/// </remarks>
|
||||
public ProcessStateStruct(IProductionProcess productionProcess, ProcessState processState, String processInfo,
|
||||
UInt32? productionProcessNo, ProcessState? nextStateOnSuccess, ProcessState errorExitState = ProcessState.Error,
|
||||
ProcessState breakExitState = ProcessState.Stop,
|
||||
ProcessState? kickOffParallelState = null,
|
||||
ProcessState? waitForSingleProcess = null,
|
||||
Boolean waitForAllProcesses = false, Boolean startAlways = false)
|
||||
{
|
||||
Process = process;
|
||||
State = state;
|
||||
Info = info;
|
||||
ProductionRelevant = productionRelevant;
|
||||
ProductionProcess = productionProcess;
|
||||
ProcessState = processState;
|
||||
ProcessInfo = processInfo;
|
||||
ProductionProcessNo = productionProcessNo;
|
||||
NextStateOnSuccess = nextStateOnSuccess;
|
||||
ErrorExitState = errorExitState;
|
||||
BreakExitState = breakExitState;
|
||||
KickOffParallelState = kickOffParallelState;
|
||||
WaitForSingleProcess = waitForSingleProcess;
|
||||
WaitForAllProcesses = waitForAllProcesses;
|
||||
StartAlways = startAlways;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Start a parallel process
|
||||
/// </summary>
|
||||
public ProcessState? KickOffParallelState { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The state of the final test
|
||||
/// </summary>
|
||||
public IProductionProcess Process { get; }
|
||||
public IProductionProcess ProductionProcess { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The state of the final test
|
||||
/// </summary>
|
||||
public ProcessState State { get; }
|
||||
public ProcessState ProcessState { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The info message of the state
|
||||
/// </summary>
|
||||
public String Info { get; }
|
||||
public String ProcessInfo { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Processes which are relevant for the EOL production
|
||||
/// Processes which are relevant for the production have a number for the sequence they should be displayed
|
||||
/// in the GUI, all hidden (non-)production processes are set to null
|
||||
/// </summary>
|
||||
public Boolean ProductionRelevant { get; }
|
||||
public UInt32? ProductionProcessNo { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Next state required after successfully execution
|
||||
/// </summary>
|
||||
public ProcessState? NextStateOnSuccess { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Special state used for error or for the second output of the process
|
||||
/// </summary>
|
||||
public ProcessState ErrorExitState { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Special state required on user break
|
||||
/// </summary>
|
||||
public ProcessState BreakExitState { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Wait for a single process named here to take the result into account
|
||||
/// </summary>
|
||||
public ProcessState? WaitForSingleProcess { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Wait until all preceding processes are finished with success
|
||||
/// </summary>
|
||||
public Boolean WaitForAllProcesses { get; }
|
||||
/// <summary>
|
||||
/// Sate which has to be active always even if a predecessor failed (e.g. error state)
|
||||
/// </summary>
|
||||
public Boolean StartAlways { get; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -286,17 +286,21 @@
|
||||
<Compile Include="Model\EOLHandler.cs" />
|
||||
<Compile Include="ProductionProcesses\Enum\PickingProcessState.cs" />
|
||||
<Compile Include="ProductionProcesses\EolProcesses\VisualInspection.cs" />
|
||||
<Compile Include="ProductionProcesses\EolProcesses\ErrorHandler.cs" />
|
||||
<Compile Include="ProductionProcesses\IProcessStateDef.cs" />
|
||||
<Compile Include="ProductionProcesses\BaseProcessStatesDef.cs" />
|
||||
<Compile Include="ProductionProcesses\GenericProcesses\ErrorHandler.cs" />
|
||||
<Compile Include="ProductionProcesses\EolProcesses\ExecStoreConfiguration.cs" />
|
||||
<Compile Include="ProductionProcesses\EolProcesses\GetSerialNumberAndRadioAddress.cs" />
|
||||
<Compile Include="ProductionProcesses\EolProcesses\DetectCordonel.cs" />
|
||||
<Compile Include="ProductionProcesses\GenericProcesses\GetSerialNumberAndRadioAddress.cs" />
|
||||
<Compile Include="ProductionProcesses\GenericProcesses\DetectCordonel.cs" />
|
||||
<Compile Include="ProductionProcesses\EolProcesses\ExecRebootCordonel.cs" />
|
||||
<Compile Include="ProductionProcesses\EolProcesses\PrepareShipping.cs" />
|
||||
<Compile Include="ProductionProcesses\Enum\DialogResult.cs" />
|
||||
<Compile Include="ProductionProcesses\Enum\ImgState.cs" />
|
||||
<Compile Include="ProductionProcesses\Enum\ProcessState.cs" />
|
||||
<Compile Include="ProductionProcesses\EventArgs\SingleProcessStateArgs.cs" />
|
||||
<Compile Include="ProductionProcesses\ProcessStateDef.cs" />
|
||||
<Compile Include="ProductionProcesses\EolProcesses\EolProcessStatesDef.cs" />
|
||||
<Compile Include="ProductionProcesses\PickingProcesses\CheckProductionState.cs" />
|
||||
<Compile Include="ProductionProcesses\PickingProcesses\PickingProcessStatesDef.cs" />
|
||||
<Compile Include="ProductionProcesses\ProcessStateStruct.cs" />
|
||||
<Compile Include="Data\PickingResultData.cs" />
|
||||
<Compile Include="Data\PressureResultDataNotifyable.cs" />
|
||||
@@ -307,27 +311,21 @@
|
||||
<Compile Include="Model\MarriageMultiModeViewModel.cs" />
|
||||
<Compile Include="Model\PickingMultiModeViewModel.cs" />
|
||||
<Compile Include="Model\PickingViewModel.cs" />
|
||||
<Compile Include="MultiMode.xaml.cs">
|
||||
<DependentUpon>MultiMode.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="MultiModeChild.xaml.cs">
|
||||
<DependentUpon>MultiModeChild.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Model\IMultiModeChildViewModel.cs" />
|
||||
<Compile Include="ProductionProcesses\EolProcesses\CheckSerialNumber.cs" />
|
||||
<Compile Include="ProductionProcesses\EolProcesses\CheckOrderNumber.cs" />
|
||||
<Compile Include="ProductionProcesses\GenericProcesses\CheckSerialNumber.cs" />
|
||||
<Compile Include="ProductionProcesses\GenericProcesses\CheckOrderNumber.cs" />
|
||||
<Compile Include="ProductionProcesses\EolProcesses\CheckAttachments.cs" />
|
||||
<Compile Include="ProductionProcesses\EolProcesses\CheckProductionState.cs" />
|
||||
<Compile Include="ProductionProcesses\EolProcesses\CheckFinalParametrization.cs" />
|
||||
<Compile Include="ProductionProcesses\EolProcesses\GetFinalParametrization.cs" />
|
||||
<Compile Include="ProductionProcesses\EolProcesses\ExecFinalParametrization.cs" />
|
||||
<Compile Include="ProductionProcesses\EolProcesses\CheckRadio.cs" />
|
||||
<Compile Include="ProductionProcesses\EolProcesses\ConnectCordonel.cs" />
|
||||
<Compile Include="ProductionProcesses\GenericProcesses\ConnectCordonel.cs" />
|
||||
<Compile Include="ProductionProcesses\EolProcesses\ExecPasswordFile.cs" />
|
||||
<Compile Include="ProductionProcesses\BaseProductionProcess.cs" />
|
||||
<Compile Include="ProductionProcesses\Enum\SingleProcessState.cs" />
|
||||
<Compile Include="ProductionProcesses\IProductionProcess.cs" />
|
||||
<Compile Include="ProductionProcesses\FinalProcessController.cs" />
|
||||
<Compile Include="ProductionProcesses\ProcessController.cs" />
|
||||
<Compile Include="ProductionProcesses\EventArgs\ProcessStateArgs.cs" />
|
||||
<Compile Include="ProductionProcesses\EventArgs\ProcessLogArgs.cs" />
|
||||
<Compile Include="ProductionProcesses\EventArgs\ProcessProgressArgs.cs" />
|
||||
@@ -344,20 +342,20 @@
|
||||
<Compile Include="UserAccessWindow.xaml.cs">
|
||||
<DependentUpon>UserAccessWindow.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="UserControls\FinalTest\IUserControl.cs" />
|
||||
<Compile Include="UserControls\FinalTest\UcBarcodeInput.xaml.cs">
|
||||
<Compile Include="UserControls\IUserControl.cs" />
|
||||
<Compile Include="UserControls\UcBarcodeInput.xaml.cs">
|
||||
<DependentUpon>UcBarcodeInput.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="UserControls\FinalTest\UcDialog.xaml.cs">
|
||||
<Compile Include="UserControls\UcDialog.xaml.cs">
|
||||
<DependentUpon>UcDialog.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="UserControls\FinalTest\UcRadioCheck.xaml.cs">
|
||||
<Compile Include="UserControls\UcRadioCheck.xaml.cs">
|
||||
<DependentUpon>UcRadioCheck.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="UserControls\FinalTest\UcPlain.xaml.cs">
|
||||
<Compile Include="UserControls\UcPlain.xaml.cs">
|
||||
<DependentUpon>UcPlain.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="UserControls\FinalTest\UcPasswordFile.xaml.cs">
|
||||
<Compile Include="UserControls\UcPasswordFile.xaml.cs">
|
||||
<DependentUpon>UcPasswordFile.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Page Include="ctls\ctlMultiModeMarriage.xaml">
|
||||
@@ -372,54 +370,42 @@
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<<<<<<< HEAD
|
||||
<Page Include="FinalTest.xaml">
|
||||
=======
|
||||
<Page Include="ProductionWindow.xaml">
|
||||
>>>>>>> Dev_Picking
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="MainWindow.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Compile Include="App.xaml.cs">
|
||||
<DependentUpon>App.xaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="FinalTest.xaml.cs">
|
||||
<DependentUpon>FinalTest.xaml</DependentUpon>
|
||||
<Compile Include="ProductionWindow.xaml.cs">
|
||||
<DependentUpon>ProductionWindow.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="MainWindow.xaml.cs">
|
||||
<DependentUpon>MainWindow.xaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Page Include="MultiMode.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="MultiModeChild.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="UserAccessWindow.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="UserControls\FinalTest\UcBarcodeInput.xaml">
|
||||
<Page Include="UserControls\UcBarcodeInput.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Include="UserControls\FinalTest\UcDialog.xaml">
|
||||
<Page Include="UserControls\UcDialog.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Include="UserControls\FinalTest\UcRadioCheck.xaml">
|
||||
<Page Include="UserControls\UcRadioCheck.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Include="UserControls\FinalTest\UcPlain.xaml">
|
||||
<Page Include="UserControls\UcPlain.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="UserControls\FinalTest\UcPasswordFile.xaml">
|
||||
<Page Include="UserControls\UcPasswordFile.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
@@ -612,7 +598,6 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="Enum\" />
|
||||
<Folder Include="ProductionProcesses\PickingProcesses\" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
x:Class="Xylem.Common.Production.ProductionUiCordonel.FinalTest"
|
||||
x:Class="Xylem.Common.Production.ProductionUiCordonel.ProductionWindow"
|
||||
mc:Ignorable="d"
|
||||
Title="FinalTest" MinHeight="730" MinWidth="820" Height="730" Width="820" Initialized="Window_Initialized" Closing="Window_Closing" ResizeMode="CanMinimize" HorizontalAlignment="Right" WindowStartupLocation="CenterScreen" Loaded="Window_Loaded">
|
||||
<DockPanel VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Margin="2,2,2,2">
|
||||
+9
-7
@@ -21,6 +21,7 @@ using Xylem.Common.CommonCore.Consts;
|
||||
using Xylem.Common.Hardware.Interfaces.Ports.PortCore;
|
||||
using Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses;
|
||||
using Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.Enum;
|
||||
using Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.EolProcesses;
|
||||
using Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.EventArgs;
|
||||
using Xylem.Common.Utils.Logging;
|
||||
using Xylem.Common.Utils.UserAccessCtrl;
|
||||
@@ -33,7 +34,7 @@ namespace Xylem.Common.Production.ProductionUiCordonel
|
||||
/// <summary>
|
||||
/// Interaction logic for FinalTest.xaml
|
||||
/// </summary>
|
||||
public sealed partial class FinalTest
|
||||
public sealed partial class ProductionWindow
|
||||
{
|
||||
#region variables and properties
|
||||
private readonly ILogger _logger;
|
||||
@@ -53,19 +54,20 @@ namespace Xylem.Common.Production.ProductionUiCordonel
|
||||
// maximum processing steps for calculation of progress bar
|
||||
private Int32 _maxOverallProcessSteps;
|
||||
private Int32 _maxSingleProcessSteps;
|
||||
private FinalProcessController _processCtrl;
|
||||
private ProcessController _processCtrl;
|
||||
private DateTimeOffset _startTime;
|
||||
private DispatcherTimer _timer;
|
||||
private String _lastLoggingTextToAvoidRepetition;
|
||||
private CordonelRequirements _productionRequirements;
|
||||
private UserAccessWindow _userAccessWindow;
|
||||
private IProcessStateDef _processStateDef;
|
||||
|
||||
#endregion
|
||||
|
||||
public FinalTest()
|
||||
public ProductionWindow(String softwareName, String projectName, IProcessStateDef processStateDef)
|
||||
{
|
||||
_logger = NLogHelper.CreateOrGetLogger("ProductionUiCordonel");
|
||||
|
||||
_logger = NLogHelper.CreateOrGetLogger(projectName);
|
||||
_processStateDef = processStateDef;
|
||||
String msg;
|
||||
try
|
||||
{
|
||||
@@ -93,7 +95,7 @@ namespace Xylem.Common.Production.ProductionUiCordonel
|
||||
|
||||
InitializeComponent();
|
||||
// Log version to files for debug purposes
|
||||
_strSoftwareNameVersion = $"{Properties.Resources.StrSoftwareNameVersion} {_version}";
|
||||
_strSoftwareNameVersion = $"{softwareName} {_version}";
|
||||
_logger.Info(_strSoftwareNameVersion);
|
||||
|
||||
Title = _strSoftwareNameVersion;
|
||||
@@ -177,7 +179,7 @@ namespace Xylem.Common.Production.ProductionUiCordonel
|
||||
|
||||
try
|
||||
{
|
||||
_processCtrl = new FinalProcessController(Slot);
|
||||
_processCtrl = new ProcessController(Slot, _processStateDef);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -0,0 +1,977 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Data;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Threading;
|
||||
using LaaPackages.Features.Cordonel.Models;
|
||||
using Newtonsoft.Json;
|
||||
using NLog;
|
||||
using Xylem.Common.CommonCore.Configuration;
|
||||
using Xylem.Common.CommonCore.Consts;
|
||||
using Xylem.Common.Hardware.Interfaces.Ports.PortCore;
|
||||
using Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses;
|
||||
using Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.Enum;
|
||||
using Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.EolProcesses;
|
||||
using Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.EventArgs;
|
||||
using Xylem.Common.Utils.Logging;
|
||||
using Xylem.Common.Utils.UserAccessCtrl;
|
||||
using Control = System.Windows.Forms.Control;
|
||||
using TextBox = System.Windows.Controls.TextBox;
|
||||
using UserControl = System.Windows.Controls.UserControl;
|
||||
|
||||
namespace Xylem.Common.Production.ProductionUiCordonel
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for FinalTest.xaml
|
||||
/// </summary>
|
||||
public sealed partial class ProductionWindow
|
||||
{
|
||||
#region variables and properties
|
||||
private readonly ILogger _logger;
|
||||
// remind manually changed culture setting
|
||||
private static readonly CultureInfo _cultureInfo = Thread.CurrentThread.CurrentCulture;
|
||||
private static readonly AssemblyName _assemblyName = Assembly.GetExecutingAssembly().GetName();
|
||||
private static readonly String _assemblyExecRootPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
|
||||
private static readonly Version _version = _assemblyName.Version;
|
||||
private readonly String _strSoftwareNameVersion;
|
||||
private RegisterLDAPUser _registerForm;
|
||||
|
||||
private Int32 Slot
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
// maximum processing steps for calculation of progress bar
|
||||
private Int32 _maxOverallProcessSteps;
|
||||
private Int32 _maxSingleProcessSteps;
|
||||
private ProcessController _processCtrl;
|
||||
private DateTimeOffset _startTime;
|
||||
private DispatcherTimer _timer;
|
||||
private String _lastLoggingTextToAvoidRepetition;
|
||||
private CordonelRequirements _productionRequirements;
|
||||
private UserAccessWindow _userAccessWindow;
|
||||
private IProcessStateDef _processStateDef;
|
||||
|
||||
#endregion
|
||||
|
||||
public ProductionWindow(String softwareName, String projectName, IProcessStateDef processStateDef)
|
||||
{
|
||||
_logger = NLogHelper.CreateOrGetLogger(projectName);
|
||||
_processStateDef = processStateDef;
|
||||
String msg;
|
||||
try
|
||||
{
|
||||
// returns true in DEBUG configuration
|
||||
if (!Logic.SoftwareAccessHelper.Access.HasAccess(_assemblyName))
|
||||
{
|
||||
msg = $"{Properties.Resources.StrStartMessageSwLicenseExpired} {_version}";
|
||||
_logger.Error(msg);
|
||||
MessageBox.Show(msg, Properties.Resources.StrProcessStateError,
|
||||
MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
Close();
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
msg = Properties.Resources.StrErrorMsgMissingNetworkConnetction + " " + e.Message;
|
||||
_logger.Error(msg);
|
||||
MessageBox.Show(msg,
|
||||
Properties.Resources.StrProcessStateError,
|
||||
MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
Close();
|
||||
return;
|
||||
}
|
||||
|
||||
InitializeComponent();
|
||||
// Log version to files for debug purposes
|
||||
_strSoftwareNameVersion = $"{softwareName} {_version}";
|
||||
_logger.Info(_strSoftwareNameVersion);
|
||||
|
||||
Title = _strSoftwareNameVersion;
|
||||
|
||||
//static labels
|
||||
UpdateContentControl(lblSerialNumberTxt, Properties.Resources.StrLblSerialNumberTxt + ":");
|
||||
UpdateContentControl(lblRadioAddressText, Properties.Resources.StrLblRadioAddressTxt + ":");
|
||||
UpdateContentControl(lblOrderNumberText, Properties.Resources.StrLblOrderNumberTxt + ":");
|
||||
UpdateContentControl(lblMeterSizeText, Properties.Resources.StrLblMeterSizeTxt + ":");
|
||||
UpdateContentControl(lblSingleProcessText, Properties.Resources.StrLblSingleProcessText + ":");
|
||||
UpdateContentControl(lblTotalProcessText, Properties.Resources.StrLblTotalProcessText + ":");
|
||||
optionsMenu.Header = Properties.Resources.StrMenuOptionsText;
|
||||
optionsMenuChangePassword.Header = Properties.Resources.StrMenuChangePasswordText;
|
||||
hlpMenu.Header = Properties.Resources.StrMenuHelpText;
|
||||
UpdateUi(lblApprovalText, "");
|
||||
UpdateUi(lblTimeText, Properties.Resources.StrLblTimeText + ":");
|
||||
|
||||
// buttons
|
||||
UpdateContentControl(btnStart, Properties.Resources.StrBtnStart);
|
||||
UpdateContentControl(btnStop, Properties.Resources.StrBtnStop);
|
||||
|
||||
InitializeFormState();
|
||||
|
||||
}
|
||||
|
||||
private ApplicationSettings Settings
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initialize the FinalTest GUI:
|
||||
/// - Read the configuration file for slot and port assignments and settings,
|
||||
/// - Dispatch slots to slot combobox,
|
||||
/// - Read setting from "ProductionUiConfig.json" file for GUI and slot setup,
|
||||
/// - Create final process controller and install events,
|
||||
/// - Create a dispatch timer to display the elapsed time of the process.
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
private void Window_Initialized(Object sender, EventArgs e)
|
||||
{
|
||||
var configFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
|
||||
nameof(Hardware.WaterMeter.Genesis), ProgramConfig.SerialConfigFileName);
|
||||
|
||||
if (!File.Exists(configFile))
|
||||
{
|
||||
var msg = Properties.Resources.StrErrorMsgMissingConfigurationFile;
|
||||
MessageBox.Show(msg,
|
||||
Properties.Resources.StrProcessStateError,
|
||||
MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
_logger.Error(msg);
|
||||
throw new ApplicationException(msg);
|
||||
}
|
||||
var tr = new StreamReader(configFile);
|
||||
var meterConfigList = JsonConvert.DeserializeObject<SlotConfig[]>(tr.ReadToEnd());
|
||||
|
||||
cbxSlotBox.Items.Clear();
|
||||
if (meterConfigList != null)
|
||||
{
|
||||
foreach (var item in meterConfigList.OrderBy(s => s.Slot))
|
||||
{
|
||||
cbxSlotBox.Items.Add(item.Slot);
|
||||
}
|
||||
}
|
||||
|
||||
cbxSlotBox.SelectedIndex = 0;
|
||||
Settings = new ApplicationSettings("ProductionUiConfig.json");
|
||||
|
||||
UseSetting(true);
|
||||
|
||||
if (cbxSlotBox.SelectedItem == null || string.IsNullOrEmpty(cbxSlotBox.SelectedItem.ToString()) ||
|
||||
!int.TryParse(cbxSlotBox.SelectedItem.ToString(), out var slot))
|
||||
{
|
||||
Slot = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
Slot = slot;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
_processCtrl = new ProcessController(Slot, _processStateDef);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Error(ex.Message);
|
||||
MessageBox.Show(ex.Message,
|
||||
Properties.Resources.StrProcessStateError,
|
||||
MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
throw new ApplicationException(ex.Message);
|
||||
}
|
||||
|
||||
//install the process changed event handler for single processes
|
||||
_processCtrl.OnSingleProcessStateChanged += SingleProcessStateChanged_Handler;
|
||||
_processCtrl.OnProcessLogRequest += ProcessLog_Handler;
|
||||
_processCtrl.OnProcessProgressChanged += ProcessProgress_Handler;
|
||||
_processCtrl.OnOverallProcessStateChanged += ProcessStateChange_Handler;
|
||||
|
||||
_timer = new DispatcherTimer();
|
||||
_timer.Tick += TmrProgressUpdate_Tick;
|
||||
_timer.Interval = TimeSpan.FromMilliseconds(500);
|
||||
|
||||
UpdateStatusGrid();
|
||||
}
|
||||
|
||||
private void Window_Closing(Object sender, CancelEventArgs e)
|
||||
{
|
||||
_userAccessWindow?.Close();
|
||||
_processCtrl.OnSingleProcessStateChanged -= SingleProcessStateChanged_Handler;
|
||||
_processCtrl.OnProcessLogRequest -= ProcessLog_Handler;
|
||||
_processCtrl.OnProcessProgressChanged -= ProcessProgress_Handler;
|
||||
_processCtrl.OnOverallProcessStateChanged -= ProcessStateChange_Handler;
|
||||
_userAccessWindow = null;
|
||||
|
||||
_processCtrl.Dispose();
|
||||
_processCtrl = null;
|
||||
_timer.Stop();
|
||||
_timer.Tick -= TmrProgressUpdate_Tick;
|
||||
_timer = null;
|
||||
_registerForm = null;
|
||||
}
|
||||
private void UseSetting(Boolean setSlot = false)
|
||||
{
|
||||
//tblkAutodetectState.Text = "Off";
|
||||
//if (Settings.AutoDetect)
|
||||
//{
|
||||
// tblkAutodetectState.Text = "On";
|
||||
//}
|
||||
if (setSlot)
|
||||
{
|
||||
cbxSlotBox.SelectedValue = Settings.Slot;
|
||||
}
|
||||
}
|
||||
|
||||
private void InitializeFormState()
|
||||
{
|
||||
if (Software.IsRegistrationPending)
|
||||
{
|
||||
_registerForm = new RegisterLDAPUser();
|
||||
_registerForm.OnCancellation += OnUserAccessControlCancellation;
|
||||
UiElmEnable(optionsMenu, false, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
UiElmEnable(optionsMenu, true);
|
||||
UiElmEnable(optionsMenuChangePassword, Software.IsAutenticated);
|
||||
UiElmEnable(optionsMenuLogout, Software.IsAutenticated);
|
||||
UiElmEnable(optionsMenuLogin, !Software.IsAutenticated);
|
||||
UiElmEnable(btnStart, Software.IsAutenticated);
|
||||
UiElmEnable(btnStop, false);
|
||||
UpdateContentControl(lblOperator,
|
||||
Software.IsAutenticated
|
||||
? $"{Properties.Resources.StrLblOperatorNameText}: {Software.UserName}"
|
||||
: $"{Properties.Resources.StrLblOperatorNameText}: ?");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Shows the user access window with login form or password change form.
|
||||
/// </summary>
|
||||
/// <param name="visible"></param>
|
||||
/// <param name="control">Windows forms control</param>
|
||||
/// <param name="headerTxt"></param>
|
||||
/// <remarks date="2025-Mar-25" author="Thomas Wiedebusch">
|
||||
/// - Initial.
|
||||
/// </remarks>
|
||||
private void ShowUserAccessWindow(Boolean visible = true, Control control = null, String headerTxt = "")
|
||||
{
|
||||
if (visible && control != null)
|
||||
{
|
||||
UiElmEnable(optionsMenu, false);
|
||||
|
||||
if (_userAccessWindow == null)
|
||||
_userAccessWindow = new UserAccessWindow(control, headerTxt);
|
||||
// View the user access window as container for the windows forms password change and login
|
||||
_userAccessWindow.OnCloseWindow += OnUserAccessWindowClosed_Handler;
|
||||
_userAccessWindow.ShowDialog();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_userAccessWindow != null)
|
||||
{
|
||||
_userAccessWindow.OnCloseWindow -= OnUserAccessWindowClosed_Handler;
|
||||
try
|
||||
{
|
||||
_userAccessWindow.Close();
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
//ignore
|
||||
}
|
||||
_userAccessWindow = null;
|
||||
}
|
||||
|
||||
if (_registerForm != null)
|
||||
_registerForm.OnCancellation -= OnUserAccessControlCancellation;
|
||||
|
||||
UiElmEnable(optionsMenu, true);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Close event handler of the user access window with login form or password change form.
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="eventArgs"></param>
|
||||
/// <remarks date="2025-Mar-25" author="Thomas Wiedebusch">
|
||||
/// - Initial.
|
||||
/// </remarks>
|
||||
private void OnUserAccessWindowClosed_Handler(Object sender, EventArgs eventArgs)
|
||||
{
|
||||
ShowUserAccessWindow(false);
|
||||
InitializeFormState();
|
||||
}
|
||||
|
||||
private void UpdateUi(ContentControl c, String content, Brush color = null)
|
||||
{
|
||||
if (color == null)
|
||||
color = Brushes.Black;
|
||||
|
||||
c.Dispatcher.Invoke(DispatcherPriority.Normal,
|
||||
new Action(() =>
|
||||
{
|
||||
c.Content = content;
|
||||
c.Foreground = color;
|
||||
}));
|
||||
}
|
||||
|
||||
private void UpdateUi(TextBox c, String content, Brush color = null)
|
||||
{
|
||||
if (color == null)
|
||||
color = Brushes.Black;
|
||||
|
||||
c.Dispatcher.Invoke(DispatcherPriority.Normal,
|
||||
new Action(() =>
|
||||
{
|
||||
c.Text = content;
|
||||
c.Foreground = color;
|
||||
}));
|
||||
}
|
||||
private void UpdateUi(TextBlock c, String content, Brush color = null)
|
||||
{
|
||||
if (color == null)
|
||||
color = Brushes.Black;
|
||||
|
||||
c.Dispatcher.Invoke(DispatcherPriority.Normal,
|
||||
new Action(() =>
|
||||
{
|
||||
c.Text = content;
|
||||
c.Foreground = color;
|
||||
}));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update the elapsed time as information
|
||||
/// </summary>
|
||||
/// <returns>information attached to process depending on region</returns>
|
||||
/// <remarks date="2024-Jul-11" author="Thomas Wiedebusch">
|
||||
/// - Initial
|
||||
/// </remarks>
|
||||
private void SetTimeDisplay()
|
||||
{
|
||||
var time = DateTimeOffset.UtcNow;
|
||||
var timeSpan = time - _startTime;
|
||||
UpdateContentControl(lblTimeValue, $@"{(UInt32)timeSpan.TotalMinutes}:{timeSpan.Seconds:00}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Common routine for state change:
|
||||
/// - Log state change,
|
||||
/// - Execute stop procedure on error.
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
/// <remarks date="2020-Dec-12" author="Roland Drabesch">
|
||||
/// - Initial
|
||||
/// </remarks>
|
||||
/// <remarks date="2024-Aug-30" author="Thomas Wiedebusch">
|
||||
/// - Extended.
|
||||
/// </remarks>
|
||||
/// <remarks date="2025-Apr-10" author="Thomas Wiedebusch">
|
||||
/// - Extended.
|
||||
/// </remarks>
|
||||
private void ProcessStateChange_Handler(Object sender, ProcessStateArgs e)
|
||||
{
|
||||
_logger.Debug($"Slot:{Slot} - Final test state: {e.State}");
|
||||
|
||||
// Nothing to display
|
||||
if (e.State == ProcessState.Idle)
|
||||
{
|
||||
// Update progress bars
|
||||
ProcessProgress_Handler(this, new ProcessProgressArgs(0,
|
||||
ProcessProgressArgs.ProcessProgressType.OverallProcessesSteps));
|
||||
ProcessProgress_Handler(this, new ProcessProgressArgs(0,
|
||||
ProcessProgressArgs.ProcessProgressType.ActualProcessSteps));
|
||||
}
|
||||
// Stop all procedures
|
||||
if (e.State == ProcessState.Stop)
|
||||
{
|
||||
_timer?.Stop();
|
||||
UiElmEnable(btnStart, true);
|
||||
UiElmEnable(btnStop, false);
|
||||
// update progress bars
|
||||
ProcessProgress_Handler(this, new ProcessProgressArgs(0,
|
||||
ProcessProgressArgs.ProcessProgressType.OverallProcessesSteps));
|
||||
ProcessProgress_Handler(this, new ProcessProgressArgs(0,
|
||||
ProcessProgressArgs.ProcessProgressType.ActualProcessSteps));
|
||||
// remove user control
|
||||
SetNewUserControl(null);
|
||||
}
|
||||
// Repeat failed tests
|
||||
if (e.State == ProcessState.RepeatFailedTests)
|
||||
{
|
||||
UiElmEnable(btnStart, false);
|
||||
UiElmEnable(btnStop, true);
|
||||
_timer?.Start();
|
||||
}
|
||||
// Stop time for manual operation and visual inspection as this is not part of the configuration
|
||||
if (e.State == ProcessState.CheckOrderNumber)
|
||||
{
|
||||
_timer?.Stop();
|
||||
}
|
||||
// Prepare shipping
|
||||
if (e.State == ProcessState.PrepareShippingMode)
|
||||
{
|
||||
_timer?.Stop();
|
||||
UiElmEnable(btnStart, false);
|
||||
UiElmEnable(btnStop, false);
|
||||
}
|
||||
// Ready for shipping
|
||||
if (e.State == ProcessState.ReadyForShipping)
|
||||
{
|
||||
// Create extended report including all steps and each register write, read and comparison
|
||||
CreateFile(Properties.Resources.StrInfoSuccessPapers);
|
||||
BtnStop_Click(this, null);
|
||||
}
|
||||
// Print return report
|
||||
if (e.State == ProcessState.PrintReturnReport)
|
||||
{
|
||||
PrintErrorNote();
|
||||
BtnStop_Click(this, null);
|
||||
}
|
||||
// Print success report
|
||||
if (e.State == ProcessState.PrintSuccessReport)
|
||||
{
|
||||
PrintSuccessNote();
|
||||
BtnStop_Click(this, null);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enable UI elements
|
||||
/// </summary>
|
||||
/// <param name="elm"></param>
|
||||
/// <param name="isEnabled"></param>
|
||||
/// <param name="isVisible"></param>
|
||||
private void UiElmEnable(UIElement elm, Boolean isEnabled, Boolean isVisible = true)
|
||||
{
|
||||
elm.Dispatcher.Invoke(DispatcherPriority.Normal,
|
||||
new Action(() =>
|
||||
{
|
||||
elm.Visibility = isVisible ? Visibility.Visible : Visibility.Hidden;
|
||||
elm.IsEnabled = isEnabled;
|
||||
|
||||
}));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fill logging window with information
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
/// <remarks date="????" author="Roland Drabesch">
|
||||
/// - Initial
|
||||
/// </remarks>
|
||||
/// <remarks date="2023-07-06" author="Thomas Wiedebusch">
|
||||
/// - Changed to rich text edit with colored output.
|
||||
/// </remarks>
|
||||
/// <remarks date="2024-08-28" author="Thomas Wiedebusch">
|
||||
/// - Avoid output of repeated text or useless empty text.
|
||||
/// </remarks>
|
||||
private void ProcessLog_Handler(Object sender, ProcessLogArgs e)
|
||||
{
|
||||
rtbLog.Dispatcher.Invoke(DispatcherPriority.Normal,
|
||||
new Action(() =>
|
||||
{
|
||||
if (e != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
// remove unacceptable spacing between the lines
|
||||
rtbLog.Document.LineHeight = 1;
|
||||
|
||||
var color = e.Color ?? Brushes.Black;
|
||||
var text = e.Data;
|
||||
if (!string.IsNullOrEmpty(text) && !text.Equals(_lastLoggingTextToAvoidRepetition))
|
||||
{
|
||||
var tr = new TextRange(rtbLog.Document.ContentEnd, rtbLog.Document.ContentEnd)
|
||||
{
|
||||
Text = text
|
||||
};
|
||||
tr.ApplyPropertyValue(TextElement.ForegroundProperty, color);
|
||||
rtbLog.ScrollToEnd();
|
||||
rtbLog.AppendText(Environment.NewLine);
|
||||
}
|
||||
|
||||
_lastLoggingTextToAvoidRepetition = text;
|
||||
}
|
||||
catch (FormatException)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set values for progress bar, maximum and actual for single process and overall process.
|
||||
/// - Limit values to 0.0..100.0.
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
/// <remarks date="????" author="Roland Drabesch">
|
||||
/// - Initial
|
||||
/// </remarks>
|
||||
/// <remarks date="2024-07-18" author="Thomas Wiedebusch">
|
||||
/// - Introduced multi line text with center alignment.
|
||||
/// </remarks>
|
||||
private void ProcessProgress_Handler(Object sender, ProcessProgressArgs e)
|
||||
{
|
||||
if (e.ProgressType == ProcessProgressArgs.ProcessProgressType.MaxOverallProcessSteps)
|
||||
{
|
||||
_maxOverallProcessSteps = e.Progress;
|
||||
}
|
||||
else if (e.ProgressType == ProcessProgressArgs.ProcessProgressType.MaxActualProcessSteps)
|
||||
{
|
||||
_maxSingleProcessSteps = e.Progress;
|
||||
}
|
||||
if (e.ProgressType == ProcessProgressArgs.ProcessProgressType.OverallProcessesSteps)
|
||||
{
|
||||
pbTotalProgress.Dispatcher.Invoke(DispatcherPriority.Normal,
|
||||
new Action(() =>
|
||||
{
|
||||
// limit output to progress bar to 0..100 as integer for process bar
|
||||
var progress = _maxOverallProcessSteps <= 0 ? 0.0 : e.Progress * 100.0 / _maxOverallProcessSteps;
|
||||
progress = progress > 100.0 ? 100.0 : progress < 0.0 ? 0.0 : progress;
|
||||
pbTotalProgress.Value = (Int32)progress;
|
||||
UpdateContentControl(lblTotalProgressValue, $@"{progress:##0.0} %");
|
||||
}
|
||||
));
|
||||
}
|
||||
else if (e.ProgressType == ProcessProgressArgs.ProcessProgressType.ActualProcessSteps)
|
||||
{
|
||||
pbSubProgress.Dispatcher.Invoke(DispatcherPriority.Normal,
|
||||
new Action(() =>
|
||||
{
|
||||
// limit output to progress bar to 0..100 as integer for process bar
|
||||
var progress = _maxSingleProcessSteps <= 0 ? 0.0 : e.Progress * 100.0 / _maxSingleProcessSteps;
|
||||
progress = progress > 100.0 ? 100.0 : progress < 0.0 ? 0.0 : progress;
|
||||
pbSubProgress.Value = (Int32)progress;
|
||||
UpdateContentControl(lblSubProgressValue, $@"{progress:##0.0} %");
|
||||
}
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Output message to control without access violation.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
/// <remarks date="????" author="Roland Drabesch">
|
||||
/// - Initial
|
||||
/// </remarks>
|
||||
/// <remarks date="2023-07-11" author="Thomas Wiedebusch">
|
||||
/// - Introduced multi line text with center alignment.
|
||||
/// </remarks>
|
||||
private static void UpdateContentControl(ContentControl ctl, String text)
|
||||
{
|
||||
ctl.Dispatcher.Invoke(DispatcherPriority.Normal,
|
||||
new Action(() =>
|
||||
{
|
||||
ctl.Content = new TextBlock()
|
||||
{
|
||||
Text = text,
|
||||
TextWrapping = TextWrapping.Wrap,
|
||||
TextAlignment = TextAlignment.Center
|
||||
};
|
||||
}
|
||||
));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Status grid update for all single processes
|
||||
/// </summary>
|
||||
private void UpdateStatusGrid()
|
||||
{
|
||||
var dt = new DataTable();
|
||||
dt.Columns.Add(Properties.Resources.StrDataTableColumnProcess);
|
||||
dt.Columns.Add(Properties.Resources.StrDataTableColumnState);
|
||||
var i = 0;
|
||||
if (_processCtrl?.Processes == null)
|
||||
return;
|
||||
foreach (var item in _processCtrl.Processes)
|
||||
{
|
||||
dt.Rows.Add();
|
||||
dt.Rows[i][0] = item.ProcessName;
|
||||
dt.Rows[i][1] = ProductionProcessStateHelper.GetTextFromProductionProcessState(item.SingleProcessState);
|
||||
i++;
|
||||
}
|
||||
|
||||
dgTotalProcess.Dispatcher.Invoke(DispatcherPriority.Normal,
|
||||
new Action(() =>
|
||||
{
|
||||
dgTotalProcess.DataContext = dt;
|
||||
}
|
||||
));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dispatch new user control to main screen
|
||||
/// </summary>
|
||||
/// <param name="uc"></param>
|
||||
private void SetNewUserControl(UserControl uc)
|
||||
{
|
||||
dgTotalProcess.Dispatcher.Invoke(DispatcherPriority.Normal,
|
||||
new Action(() =>
|
||||
{
|
||||
// remove last userControl
|
||||
dpSubProcess.Children.Clear();
|
||||
if (uc != null)
|
||||
{
|
||||
dpSubProcess.Children.Add(uc);
|
||||
DockPanel.SetDock(uc, Dock.Top); // & Dock.Left);
|
||||
}
|
||||
}
|
||||
));
|
||||
}
|
||||
|
||||
#region TimerControls
|
||||
/// <summary>
|
||||
/// Handle timing depending updates.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
/// <remarks date="2024-07-11" author="Thomas Wiedebusch">
|
||||
/// - Initial
|
||||
/// </remarks>
|
||||
private void TmrProgressUpdate_Tick(Object sender, EventArgs e)
|
||||
{
|
||||
SetTimeDisplay();
|
||||
}
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Update of status grid with information returned by user control.
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
/// <remarks date="????" author="Roland Drabesch">
|
||||
/// - Initial
|
||||
/// </remarks>
|
||||
/// <remarks date="2024-08-28" author="Thomas Wiedebusch">
|
||||
/// - Activate new user control on start of process.
|
||||
/// </remarks>
|
||||
private void SingleProcessStateChanged_Handler(Object sender, SingleProcessStateArgs e)
|
||||
{
|
||||
if (sender is IProductionProcess productionProcess)
|
||||
{
|
||||
if (e.SingleProcessState == SingleProcessState.Running)
|
||||
{
|
||||
// Set new user control
|
||||
SetNewUserControl(productionProcess.GetUserControl());
|
||||
}
|
||||
else
|
||||
{
|
||||
// remove user control on idle, skipped, abort or error
|
||||
SetNewUserControl(null);
|
||||
}
|
||||
}
|
||||
|
||||
UpdateStatusGrid();
|
||||
UpdateGuiWithProductInfos();
|
||||
}
|
||||
|
||||
private void OnUserAccessControlCancellation(Control control)
|
||||
{
|
||||
OnUserAccessWindowClosed_Handler(this, null);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Set labels of device information and order number
|
||||
/// </summary>
|
||||
/// <remarks date="????" author="Roland Drabesch">
|
||||
/// - Initial
|
||||
/// </remarks>
|
||||
/// <remarks date="2024-07-15" author="Thomas Wiedebusch">
|
||||
/// - Additional info of Cordonel.
|
||||
/// </remarks>
|
||||
private void UpdateGuiWithProductInfos()
|
||||
{
|
||||
var genesisMeter = _processCtrl?.GetGenesisMeter();
|
||||
_productionRequirements = _processCtrl?.GetProductionRequirements();
|
||||
|
||||
if (genesisMeter == null)
|
||||
return;
|
||||
|
||||
UpdateContentControl(lblOrderNumberValue,
|
||||
genesisMeter.OrderNumber != 0 ? genesisMeter.OrderNumber.ToString() : "?");
|
||||
|
||||
UpdateContentControl(lblRadioAddressValue,
|
||||
genesisMeter.RadioAddress != 0 ? genesisMeter.RadioAddress.ToString() : "");
|
||||
UpdateContentControl(lblRadioAddressText,
|
||||
genesisMeter.RadioAddress != 0 ? Properties.Resources.StrLblRadioAddressTxt + ":" : "");
|
||||
|
||||
UpdateContentControl(lblFwValue,
|
||||
!string.IsNullOrEmpty(genesisMeter.FwVersion) ? genesisMeter.FwVersion : "?");
|
||||
|
||||
UpdateContentControl(lblMeterSizeValue,
|
||||
!string.IsNullOrEmpty(genesisMeter.MeterSize) ? genesisMeter.MeterSize : "?");
|
||||
|
||||
UpdateContentControl(lblLutValue,
|
||||
!string.IsNullOrEmpty(genesisMeter.LutCrc) ? genesisMeter.LutCrc : "?");
|
||||
|
||||
|
||||
UpdateContentControl(lblSerialNumberValue,
|
||||
!string.IsNullOrEmpty(genesisMeter.CustomerSerialNumber) ? genesisMeter.CustomerSerialNumber : "?");
|
||||
|
||||
UpdateContentControl(lblRegionValue,
|
||||
!string.IsNullOrEmpty(genesisMeter.Region) ? genesisMeter.Region : "?");
|
||||
|
||||
UpdateUi(lblPcbIdValue, !string.IsNullOrEmpty(genesisMeter.PcbId) ? genesisMeter.PcbId : "?");
|
||||
|
||||
var msg = "";
|
||||
var color = Brushes.Black;
|
||||
if (_productionRequirements?.IsSpecialActive != null && (Boolean)_productionRequirements.IsSpecialActive &&
|
||||
_productionRequirements?.IsSpecialApproved != null && (Boolean)_productionRequirements.IsSpecialApproved)
|
||||
{
|
||||
msg = $"{Properties.Resources.StrLblSpecialRequirement} - Id.Ver: {_productionRequirements.SpecialId}." +
|
||||
$"{_productionRequirements.SpecialVersion}";
|
||||
color = Brushes.Red;
|
||||
}
|
||||
else if (_productionRequirements?.IsStandardActive != null && (Boolean)_productionRequirements.IsStandardActive &&
|
||||
_productionRequirements?.IsStandardApproved != null && (Boolean)_productionRequirements.IsStandardApproved)
|
||||
{
|
||||
msg = $"{Properties.Resources.StrLblStandardRequirement} - Id.Ver: {_productionRequirements.StandardId}." +
|
||||
$"{_productionRequirements.StandardVersion}";
|
||||
}
|
||||
|
||||
UpdateUi(lblApprovalText, msg, color);
|
||||
}
|
||||
|
||||
//private void BtnSwitchAutoDetect_Click(Object sender, RoutedEventArgs e)
|
||||
//{
|
||||
// //Settings.AutoDetect = !Settings.AutoDetect;
|
||||
// //StoreSetting();
|
||||
// //UseSetting();
|
||||
//}
|
||||
|
||||
private void OnLogout_Click(Object sender, EventArgs e)
|
||||
{
|
||||
Software.Logout();
|
||||
InitializeFormState();
|
||||
}
|
||||
|
||||
private void OnLogin_Click(Object sender, EventArgs args)
|
||||
{
|
||||
ShowUserAccessWindow(true, new LoginForm(OnUserAccessControlCancellation),
|
||||
Properties.Resources.StrLoginMsg);
|
||||
}
|
||||
|
||||
private void OnChangePassword_Click(Object _, EventArgs _1)
|
||||
{
|
||||
ShowUserAccessWindow(true, new ChangePassword(OnUserAccessControlCancellation),
|
||||
Properties.Resources.StrChangePasswordMsg);
|
||||
}
|
||||
|
||||
private void CbxSlotBox_SelectionChanged(Object sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private void StoreSetting()
|
||||
{
|
||||
Settings.Update("ProductionUiConfig.json");
|
||||
}
|
||||
|
||||
//private void BtnConnect_Click(Object sender, RoutedEventArgs e)
|
||||
//{
|
||||
// Settings.Slot = (Int32)cbxSlotBox.SelectedValue;
|
||||
// StoreSetting();
|
||||
//}
|
||||
|
||||
private void BtnStart_Click(Object sender, RoutedEventArgs e)
|
||||
{
|
||||
UiElmEnable(btnStart, false);
|
||||
UiElmEnable(btnStop, true);
|
||||
|
||||
_startTime = DateTimeOffset.UtcNow;
|
||||
_timer?.Start();
|
||||
|
||||
// remove last userControl
|
||||
dpSubProcess.Children.Clear();
|
||||
rtbLog.Document.Blocks.Clear();
|
||||
|
||||
// clear all visual fields as it may be a new pcbId
|
||||
UpdateContentControl(lblOrderNumberValue, "?");
|
||||
UpdateContentControl(lblRadioAddressValue, "");
|
||||
UpdateContentControl(lblRadioAddressText, "");
|
||||
UpdateContentControl(lblFwValue, "?");
|
||||
UpdateContentControl(lblMeterSizeValue, "?");
|
||||
UpdateContentControl(lblLutValue, "?");
|
||||
UpdateContentControl(lblSerialNumberValue, "?");
|
||||
UpdateContentControl(lblRegionValue, "?");
|
||||
UpdateUi(lblPcbIdValue, "?");
|
||||
|
||||
_processCtrl?.SetProcessState(ProcessState.DetectCordonel);
|
||||
}
|
||||
|
||||
private void PrintErrorNote()
|
||||
{
|
||||
// Safe report to file
|
||||
CreateFile(Properties.Resources.StrInstructionReturnPapers, true, true);
|
||||
}
|
||||
|
||||
private void PrintSuccessNote()
|
||||
{
|
||||
// Safe report to file
|
||||
CreateFile(Properties.Resources.StrInfoSuccessPapers, true, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Logging a file with all process information, building a compressed report for printout.
|
||||
/// </summary>
|
||||
/// <remarks date="2025-Apr-10" author="Thomas Wiedebusch">
|
||||
/// - Reduced printout.
|
||||
/// </remarks>
|
||||
private void CreateFile(String headerInfo, Boolean shortReport = false, Boolean printReport = false)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
var genesisMeter = _processCtrl.GetGenesisMeter();
|
||||
|
||||
sb.AppendLine("========================================================================");
|
||||
sb.AppendLine(headerInfo);
|
||||
sb.AppendLine("========================================================================");
|
||||
sb.AppendLine(_strSoftwareNameVersion);
|
||||
sb.AppendLine("------------------------------------------------------------------------");
|
||||
sb.AppendLine($"{Properties.Resources.StrDateTime}: {DateTime.Now}");
|
||||
sb.AppendLine("------------------------------------------------------------------------");
|
||||
sb.AppendLine($"PcbId: {genesisMeter.PcbId}");
|
||||
sb.AppendLine($"{Properties.Resources.StrPrintOrderNumberTxt}: {genesisMeter.OrderNumber}");
|
||||
sb.AppendLine($"{Properties.Resources.StrLblSerialNumberTxt}: {genesisMeter.CustomerSerialNumber}");
|
||||
sb.AppendLine($"{Properties.Resources.StrLblOperatorNameText}: {Software.UserName}");
|
||||
sb.AppendLine("------------------------------------------------------------------------");
|
||||
|
||||
//TODO THW take the log path from setup (done with GTB)
|
||||
var loggingPath = $"C:\\GenesisLog\\{DateTime.Now:yyyy-MM-dd}\\ProductionUiCordonel\\";
|
||||
var fileName = $"{loggingPath}{DateTime.Now.ToString("yyyyMMddHHmmss")}_ExtendedReport_{genesisMeter.PcbId}.txt";
|
||||
|
||||
// Copy the header to the compressed string builder
|
||||
var compressedSb = new StringBuilder();
|
||||
if (shortReport)
|
||||
{
|
||||
compressedSb.Append(sb);
|
||||
}
|
||||
|
||||
var rtbText = new TextRange(
|
||||
rtbLog.Document.ContentStart,
|
||||
rtbLog.Document.ContentEnd
|
||||
);
|
||||
sb.Append($"{rtbText.Text}");
|
||||
// Write the complete report to the file
|
||||
File.WriteAllText(fileName, sb.ToString());
|
||||
|
||||
// Reduce sb content to compress it for printout
|
||||
if (shortReport)
|
||||
{
|
||||
|
||||
fileName = $"{loggingPath}{DateTime.Now.ToString("yyyyMMddHHmmss")}" +
|
||||
$"_ShortReport_{genesisMeter.PcbId}.txt";
|
||||
var sr = new StringReader(rtbText.Text);
|
||||
var srLine = sr.ReadLine();
|
||||
while (srLine != null)
|
||||
{
|
||||
if (srLine.Contains(Properties.Resources.StrProcessStateError) ||
|
||||
srLine.Contains(Properties.Resources.StrProcessStateDone) ||
|
||||
srLine.Contains(Properties.Resources.StrProcessStateWarning) ||
|
||||
srLine.Contains(Properties.Resources.StrProcessStateSkipped) ||
|
||||
srLine.Contains(Properties.Resources.StrWarningMsgSpecialRequirementActive))
|
||||
compressedSb.AppendLine(srLine);
|
||||
srLine = sr.ReadLine();
|
||||
}
|
||||
|
||||
// Returns the compressed file for error report printout
|
||||
File.WriteAllText(fileName, compressedSb.ToString());
|
||||
if (printReport)
|
||||
{
|
||||
Process.Start(fileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stop button as user interaction to kill the finalization process
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
private void BtnStop_Click(Object sender, RoutedEventArgs e)
|
||||
{
|
||||
//set the process state to the state machine
|
||||
_processCtrl?.SetProcessState(ProcessState.Stop);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Open requirement in Web-Browser.
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
private void LblApprovalText_Click(Object sender, System.Windows.Input.MouseButtonEventArgs e)
|
||||
{
|
||||
var requirementId = 0;
|
||||
var requirementWebPageLink = ServiceUrls.InspectCordonelRequirementInfoServiceUrl();
|
||||
if (_productionRequirements?.SpecialId != null &&
|
||||
_productionRequirements?.IsSpecialApproved != null &&
|
||||
_productionRequirements.SpecialId != 0)
|
||||
{
|
||||
requirementId = (Int32)_productionRequirements.SpecialId;
|
||||
requirementWebPageLink += $"SpecialRequirements#{requirementId}";
|
||||
}
|
||||
else if (_productionRequirements?.StandardId != null &&
|
||||
_productionRequirements?.IsStandardApproved != null &&
|
||||
_productionRequirements.StandardId != 0)
|
||||
{
|
||||
requirementId = (Int32)_productionRequirements.StandardId;
|
||||
requirementWebPageLink += $"StandardRequirements#{requirementId}";
|
||||
}
|
||||
|
||||
if (requirementId != 0)
|
||||
{
|
||||
Process.Start(requirementWebPageLink);
|
||||
}
|
||||
}
|
||||
|
||||
private void HlpMenu_Click(Object sender, RoutedEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
var filename = "";
|
||||
if (Thread.CurrentThread.CurrentCulture.Name.Contains("de"))
|
||||
{
|
||||
filename = Path.Combine(_assemblyExecRootPath, "Docu", @"Handbuch Cordonel Versandfertigmachen (VFM).pdf");
|
||||
}
|
||||
else if (Thread.CurrentThread.CurrentCulture.Name.Contains("en"))
|
||||
{
|
||||
filename = Path.Combine(_assemblyExecRootPath, "Docu", @"Manual Cordonel End of Line Test (EOL).pdf");
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(filename))
|
||||
{
|
||||
Process.Start(filename);
|
||||
}
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Console.WriteLine(exception);
|
||||
}
|
||||
}
|
||||
|
||||
private void Window_Loaded(Object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (!Software.IsAutenticated)
|
||||
OnLogin_Click(this, null);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -285,6 +285,15 @@ namespace Xylem.Common.Production.ProductionUiCordonel.Properties {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Cordonel - Shipping Preparation - Version.
|
||||
/// </summary>
|
||||
internal static string StrEolSoftwareNameVersion {
|
||||
get {
|
||||
return ResourceManager.GetString("StrEolSoftwareNameVersion", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to ERROR.
|
||||
/// </summary>
|
||||
@@ -855,18 +864,18 @@ namespace Xylem.Common.Production.ProductionUiCordonel.Properties {
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to ERROR: Maximum drained battery load overflow.
|
||||
/// </summary>
|
||||
internal static string StrErrorMsgThresholdDrainedBatteryAtEol {
|
||||
internal static string StrErrorMsgThresholdDrainedBattery {
|
||||
get {
|
||||
return ResourceManager.GetString("StrErrorMsgThresholdDrainedBatteryAtEol", resourceCulture);
|
||||
return ResourceManager.GetString("StrErrorMsgThresholdDrainedBattery", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to ERROR: Minimum required lifetime underflow.
|
||||
/// </summary>
|
||||
internal static string StrErrorMsgThresholdRemainingLifeTimeAtEol {
|
||||
internal static string StrErrorMsgThresholdRemainingLifeTime {
|
||||
get {
|
||||
return ResourceManager.GetString("StrErrorMsgThresholdRemainingLifeTimeAtEol", resourceCulture);
|
||||
return ResourceManager.GetString("StrErrorMsgThresholdRemainingLifeTime", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1260,9 +1269,9 @@ namespace Xylem.Common.Production.ProductionUiCordonel.Properties {
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Drained battery load.
|
||||
/// </summary>
|
||||
internal static string StrMsgDrainedBatteryAtEol {
|
||||
internal static string StrMsgDrainedBattery {
|
||||
get {
|
||||
return ResourceManager.GetString("StrMsgDrainedBatteryAtEol", resourceCulture);
|
||||
return ResourceManager.GetString("StrMsgDrainedBattery", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1332,36 +1341,36 @@ namespace Xylem.Common.Production.ProductionUiCordonel.Properties {
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Estimated remaining lifetime.
|
||||
/// </summary>
|
||||
internal static string StrMsgRemainingLifeTimeAtEol {
|
||||
internal static string StrMsgRemainingLifeTime {
|
||||
get {
|
||||
return ResourceManager.GetString("StrMsgRemainingLifeTimeAtEol", resourceCulture);
|
||||
return ResourceManager.GetString("StrMsgRemainingLifeTime", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Minimum required lifetime.
|
||||
/// </summary>
|
||||
internal static string StrMsgRequiredLifeTimeAtEol {
|
||||
internal static string StrMsgRequiredLifeTime {
|
||||
get {
|
||||
return ResourceManager.GetString("StrMsgRequiredLifeTimeAtEol", resourceCulture);
|
||||
return ResourceManager.GetString("StrMsgRequiredLifeTime", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Absolut restriction.
|
||||
/// </summary>
|
||||
internal static string StrMsgRequirementAbsolutLimitDrainedBatteryAtEol {
|
||||
internal static string StrMsgRequirementAbsolutLimitDrainedBattery {
|
||||
get {
|
||||
return ResourceManager.GetString("StrMsgRequirementAbsolutLimitDrainedBatteryAtEol", resourceCulture);
|
||||
return ResourceManager.GetString("StrMsgRequirementAbsolutLimitDrainedBattery", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Maximum allowed.
|
||||
/// </summary>
|
||||
internal static string StrMsgRequirementLimitDrainedBatteryAtEol {
|
||||
internal static string StrMsgRequirementLimitDrainedBattery {
|
||||
get {
|
||||
return ResourceManager.GetString("StrMsgRequirementLimitDrainedBatteryAtEol", resourceCulture);
|
||||
return ResourceManager.GetString("StrMsgRequirementLimitDrainedBattery", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1392,6 +1401,15 @@ namespace Xylem.Common.Production.ProductionUiCordonel.Properties {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Cordonel - Picking - Version.
|
||||
/// </summary>
|
||||
internal static string StrPickingSoftwareNameVersion {
|
||||
get {
|
||||
return ResourceManager.GetString("StrPickingSoftwareNameVersion", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Production Order Number .
|
||||
/// </summary>
|
||||
@@ -1518,15 +1536,6 @@ namespace Xylem.Common.Production.ProductionUiCordonel.Properties {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Cordonel - Shipping Preparation - Version.
|
||||
/// </summary>
|
||||
internal static string StrSoftwareNameVersion {
|
||||
get {
|
||||
return ResourceManager.GetString("StrSoftwareNameVersion", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to New Cordonel EOL Software available! The software is going to exit! This version:.
|
||||
/// </summary>
|
||||
@@ -2052,9 +2061,9 @@ namespace Xylem.Common.Production.ProductionUiCordonel.Properties {
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Success: Minimum required lifetime is in range.
|
||||
/// </summary>
|
||||
internal static string StrSuccessMsgThresholdRemainingLifeTimeAtEol {
|
||||
internal static string StrSuccessMsgThresholdRemainingLifeTime {
|
||||
get {
|
||||
return ResourceManager.GetString("StrSuccessMsgThresholdRemainingLifeTimeAtEol", resourceCulture);
|
||||
return ResourceManager.GetString("StrSuccessMsgThresholdRemainingLifeTime", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -700,42 +700,45 @@
|
||||
<data name="StrSuccessMsgDbToMeterEncryptionKey" xml:space="preserve">
|
||||
<value>Erfolg: Datenbank und Cordonel Funkschlüssel erfolgreich abgeglichen</value>
|
||||
</data>
|
||||
<data name="StrMsgDrainedBatteryAtEol" xml:space="preserve">
|
||||
<data name="StrMsgDrainedBattery" xml:space="preserve">
|
||||
<value>Verbrauchte Batterieladung</value>
|
||||
</data>
|
||||
<data name="StrMsgAlternativeDrainedBatteryCalculation" xml:space="preserve">
|
||||
<value>Berechnung basierend auf Ruhestrom und Produktionszuschlag</value>
|
||||
</data>
|
||||
<data name="StrErrorMsgThresholdDrainedBatteryAtEol" xml:space="preserve">
|
||||
<data name="StrErrorMsgThresholdDrainedBattery" xml:space="preserve">
|
||||
<value>FEHLER: Maximale erlaubte Batterieentladung überschritten</value>
|
||||
</data>
|
||||
<data name="StrMsgRequirementAbsolutLimitDrainedBatteryAtEol" xml:space="preserve">
|
||||
<data name="StrMsgRequirementAbsolutLimitDrainedBattery" xml:space="preserve">
|
||||
<value>Absoluter Grenzwert</value>
|
||||
</data>
|
||||
<data name="StrMsgRequirementLimitDrainedBatteryAtEol" xml:space="preserve">
|
||||
<data name="StrMsgRequirementLimitDrainedBattery" xml:space="preserve">
|
||||
<value>Maximal erlaubt</value>
|
||||
</data>
|
||||
<data name="StrMsgRemainingLifeTimeAtEol" xml:space="preserve">
|
||||
<data name="StrMsgRemainingLifeTime" xml:space="preserve">
|
||||
<value>Abgeschätzte Restlaufzeit</value>
|
||||
</data>
|
||||
<data name="StrErrorMsgThresholdRemainingLifeTimeAtEol" xml:space="preserve">
|
||||
<data name="StrErrorMsgThresholdRemainingLifeTime" xml:space="preserve">
|
||||
<value>FEHLER: Minimale geforderte Restlaufzeit unterschritten</value>
|
||||
</data>
|
||||
<data name="StrErrorMsgBatteryLoadCalculation" xml:space="preserve">
|
||||
<value>FEHLER: Batterieentladung konnte nicht berechnet werden</value>
|
||||
</data>
|
||||
<data name="StrSuccessMsgThresholdRemainingLifeTimeAtEol" xml:space="preserve">
|
||||
<data name="StrSuccessMsgThresholdRemainingLifeTime" xml:space="preserve">
|
||||
<value>Erfolg: Minimale Restlaufzeit eingehalten</value>
|
||||
</data>
|
||||
<data name="StrMsgRequiredLifeTimeAtEol" xml:space="preserve">
|
||||
<data name="StrMsgRequiredLifeTime" xml:space="preserve">
|
||||
<value>Minimal geforderte Restlaufzeit</value>
|
||||
</data>
|
||||
<data name="StrMsgYears" xml:space="preserve">
|
||||
<value>Jahre</value>
|
||||
</data>
|
||||
<data name="StrSoftwareNameVersion" xml:space="preserve">
|
||||
<data name="StrEolSoftwareNameVersion" xml:space="preserve">
|
||||
<value>Cordonel - Versandfertigmachen - Version</value>
|
||||
</data>
|
||||
<data name="StrPickingSoftwareNameVersion" xml:space="preserve">
|
||||
<value>Cordonel - Montage - Version</value>
|
||||
</data>
|
||||
<data name="StrInstructionScanHousing" xml:space="preserve">
|
||||
<value>Deckel scannen</value>
|
||||
</data>
|
||||
|
||||
@@ -700,42 +700,45 @@
|
||||
<data name="StrSuccessMsgDbToMeterEncryptionKey" xml:space="preserve">
|
||||
<value>Success: Database with Cordonel radio encryption key successfully crosschecked</value>
|
||||
</data>
|
||||
<data name="StrMsgDrainedBatteryAtEol" xml:space="preserve">
|
||||
<data name="StrMsgDrainedBattery" xml:space="preserve">
|
||||
<value>Drained battery load</value>
|
||||
</data>
|
||||
<data name="StrMsgAlternativeDrainedBatteryCalculation" xml:space="preserve">
|
||||
<value>Calculation based on quiescent current and production supplement</value>
|
||||
</data>
|
||||
<data name="StrErrorMsgThresholdDrainedBatteryAtEol" xml:space="preserve">
|
||||
<data name="StrErrorMsgThresholdDrainedBattery" xml:space="preserve">
|
||||
<value>ERROR: Maximum drained battery load overflow</value>
|
||||
</data>
|
||||
<data name="StrMsgRequirementAbsolutLimitDrainedBatteryAtEol" xml:space="preserve">
|
||||
<data name="StrMsgRequirementAbsolutLimitDrainedBattery" xml:space="preserve">
|
||||
<value>Absolut restriction</value>
|
||||
</data>
|
||||
<data name="StrMsgRequirementLimitDrainedBatteryAtEol" xml:space="preserve">
|
||||
<data name="StrMsgRequirementLimitDrainedBattery" xml:space="preserve">
|
||||
<value>Maximum allowed</value>
|
||||
</data>
|
||||
<data name="StrMsgRemainingLifeTimeAtEol" xml:space="preserve">
|
||||
<data name="StrMsgRemainingLifeTime" xml:space="preserve">
|
||||
<value>Estimated remaining lifetime</value>
|
||||
</data>
|
||||
<data name="StrErrorMsgThresholdRemainingLifeTimeAtEol" xml:space="preserve">
|
||||
<data name="StrErrorMsgThresholdRemainingLifeTime" xml:space="preserve">
|
||||
<value>ERROR: Minimum required lifetime underflow</value>
|
||||
</data>
|
||||
<data name="StrErrorMsgBatteryLoadCalculation" xml:space="preserve">
|
||||
<value>ERROR: Failed to calculate battery load</value>
|
||||
</data>
|
||||
<data name="StrSuccessMsgThresholdRemainingLifeTimeAtEol" xml:space="preserve">
|
||||
<data name="StrSuccessMsgThresholdRemainingLifeTime" xml:space="preserve">
|
||||
<value>Success: Minimum required lifetime is in range</value>
|
||||
</data>
|
||||
<data name="StrMsgRequiredLifeTimeAtEol" xml:space="preserve">
|
||||
<data name="StrMsgRequiredLifeTime" xml:space="preserve">
|
||||
<value>Minimum required lifetime</value>
|
||||
</data>
|
||||
<data name="StrMsgYears" xml:space="preserve">
|
||||
<value>years</value>
|
||||
</data>
|
||||
<data name="StrSoftwareNameVersion" xml:space="preserve">
|
||||
<data name="StrEolSoftwareNameVersion" xml:space="preserve">
|
||||
<value>Cordonel - Shipping Preparation - Version</value>
|
||||
</data>
|
||||
<data name="StrPickingSoftwareNameVersion" xml:space="preserve">
|
||||
<value>Cordonel - Picking - Version</value>
|
||||
</data>
|
||||
<data name="StrInstructionScanHousing" xml:space="preserve">
|
||||
<value>Scan housing</value>
|
||||
</data>
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
namespace Xylem.Common.Production.ProductionUiCordonel.UserControls.FinalTest
|
||||
namespace Xylem.Common.Production.ProductionUiCordonel.UserControls
|
||||
{
|
||||
public interface IUserControl
|
||||
{
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
<UserControl x:Class="Xylem.Common.Production.ProductionUiCordonel.UserControls.FinalTest.UcBarcodeInput"
|
||||
<UserControl x:Class="Xylem.Common.Production.ProductionUiCordonel.UserControls.UcBarcodeInput"
|
||||
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"
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Threading;
|
||||
|
||||
namespace Xylem.Common.Production.ProductionUiCordonel.UserControls.FinalTest
|
||||
namespace Xylem.Common.Production.ProductionUiCordonel.UserControls
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for UcDialog.xaml
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
<UserControl x:Class="Xylem.Common.Production.ProductionUiCordonel.UserControls.FinalTest.UcDialog"
|
||||
<UserControl x:Class="Xylem.Common.Production.ProductionUiCordonel.UserControls.UcDialog"
|
||||
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"
|
||||
+1
-1
@@ -5,7 +5,7 @@ using System.Windows.Controls;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Threading;
|
||||
|
||||
namespace Xylem.Common.Production.ProductionUiCordonel.UserControls.FinalTest
|
||||
namespace Xylem.Common.Production.ProductionUiCordonel.UserControls
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for UcDialog.xaml
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
<UserControl x:Class="Xylem.Common.Production.ProductionUiCordonel.UserControls.FinalTest.UcPasswordFile"
|
||||
<UserControl x:Class="Xylem.Common.Production.ProductionUiCordonel.UserControls.UcPasswordFile"
|
||||
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"
|
||||
+1
-1
@@ -4,7 +4,7 @@ using System.Windows.Controls;
|
||||
using System.Windows.Threading;
|
||||
using Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.Enum;
|
||||
|
||||
namespace Xylem.Common.Production.ProductionUiCordonel.UserControls.FinalTest
|
||||
namespace Xylem.Common.Production.ProductionUiCordonel.UserControls
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for UcPasswordFile.xaml
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
<UserControl x:Class="Xylem.Common.Production.ProductionUiCordonel.UserControls.FinalTest.UcPlain"
|
||||
<UserControl x:Class="Xylem.Common.Production.ProductionUiCordonel.UserControls.UcPlain"
|
||||
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"
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
using System;
|
||||
using System.Windows.Threading;
|
||||
|
||||
namespace Xylem.Common.Production.ProductionUiCordonel.UserControls.FinalTest
|
||||
namespace Xylem.Common.Production.ProductionUiCordonel.UserControls
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for UcPlain.xaml
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
<UserControl x:Class="Xylem.Common.Production.ProductionUiCordonel.UserControls.FinalTest.UcRadioCheck"
|
||||
<UserControl x:Class="Xylem.Common.Production.ProductionUiCordonel.UserControls.UcRadioCheck"
|
||||
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"
|
||||
+1
-1
@@ -6,7 +6,7 @@ using System.Windows.Media;
|
||||
using System.Windows.Threading;
|
||||
using Color = System.Drawing.Color;
|
||||
|
||||
namespace Xylem.Common.Production.ProductionUiCordonel.UserControls.FinalTest
|
||||
namespace Xylem.Common.Production.ProductionUiCordonel.UserControls
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for UcRadioCheck.xaml
|
||||
Reference in New Issue
Block a user