ProductionUiCordonel: - re-organized to support multiple production processes - final - picking can be implemented

This commit is contained in:
Thomas Wiedebusch
2025-04-15 15:58:21 +02:00
parent 30c056f128
commit 66f457dc0b
34 changed files with 467 additions and 5056 deletions
@@ -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,27 @@ 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();
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);
}
}
}
@@ -1,155 +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"
x:Class="Xylem.Common.Production.ProductionUiCordonel.Picking"
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">
<!--Tool Panel-->
<!--ToolBarTray DockPanel.Dock="Top" Visibility="Visible" Background="#FFF0F0F0" HorizontalAlignment="Stretch" -->
<Menu DockPanel.Dock="Top" Visibility="Visible" Background="#FFF0F0F0" HorizontalAlignment="Stretch">
<Menu.ItemsPanel>
<ItemsPanelTemplate>
<DockPanel HorizontalAlignment="Stretch"></DockPanel>
</ItemsPanelTemplate>
</Menu.ItemsPanel>
<MenuItem x:Name="optionsMenu" HorizontalAlignment="Right" Height="30" Width="60" Header="_Options" >
<MenuItem x:Name="optionsMenuLogin" Header="_Login" HorizontalAlignment="Left" Click="OnLogin_Click"/>
<MenuItem x:Name="optionsMenuLogout" Header="L_ogout" HorizontalAlignment="Left" Click="OnLogout_Click"/>
<MenuItem x:Name="optionsMenuChangePassword" Header="Change Password" HorizontalAlignment="Left" Click="OnChangePassword_Click"/>
</MenuItem>
<Label Content="Slot: " Margin="2,2,2,2" Visibility="Hidden"/>
<ComboBox x:Name="cbxSlotBox" Margin="2,2,2,2" SelectionChanged="CbxSlotBox_SelectionChanged" Visibility="Hidden"/>
<Label x:Name="lblApprovalText" Margin="110,1,1,1" Content="SPECIAL APPROVAL - Id.Ver: 10.07" Foreground="#FFFB0808" FontSize="16" MouseDown="LblApprovalText_Click" HorizontalAlignment="Center"/>
<MenuItem x:Name="hlpMenu" HorizontalAlignment="Right" Height="30" Width="40" FontSize="12" Header="Help" Click="HlpMenu_Click" />
<!--Special approval / requirement-->
</Menu>
<!--/-->
<!--Status Panel-->
<StatusBar DockPanel.Dock="Bottom" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Margin="2,2,2,2">
<StatusBar.ItemsPanel>
<ItemsPanelTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50" />
<ColumnDefinition Width="80" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="100" />
<ColumnDefinition Width="200" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="120" />
<ColumnDefinition Width="60" />
</Grid.ColumnDefinitions>
</Grid>
</ItemsPanelTemplate>
</StatusBar.ItemsPanel>
<StatusBarItem Grid.Column="0" Margin="0,0,0,0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<Label Content="PcbID:" Margin="2,2,0,2" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />
</StatusBarItem>
<StatusBarItem Grid.Column="1" Margin="0,0,0,0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<Label x:Name="lblPcbIdValue" Content="-" Margin="2,2,2,2" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />
</StatusBarItem>
<Separator Grid.Column="2" />
<StatusBarItem x:Name="lblOperator" Grid.Column="4" Margin="-1,1,-109,3" HorizontalAlignment="Center" VerticalAlignment="Stretch" />
<Separator Grid.Column="7" />
<StatusBarItem Grid.Column="8" Margin="0,0,0,0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<TextBlock x:Name="lblTimeText" Text="Elapsed Time [min:s]:" Margin="2,2,2,2" HorizontalAlignment="Right" VerticalAlignment="Stretch" />
</StatusBarItem>
<StatusBarItem Grid.Column="9" Margin="0,0,0,0" HorizontalAlignment="Right" VerticalAlignment="Stretch">
<Label x:Name="lblTimeValue" Content="0:00" Margin="2,2,2,2" HorizontalAlignment="Right" VerticalAlignment="Stretch" />
</StatusBarItem>
</StatusBar>
<!--Grid Design-->
<Grid Background="AliceBlue" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Margin="2,2,2,2">
<Grid.RowDefinitions>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="*"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="17"/>
<ColumnDefinition Width="113"/>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="120"/>
<ColumnDefinition Width="30"/>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="30"/>
<ColumnDefinition Width="40"/>
<ColumnDefinition Width="60"/>
</Grid.ColumnDefinitions>
<!--Cordonel information-->
<Label x:Name="lblSerialNumberTxt" Content="SerialNumber:" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="2,2,2,2" Grid.Row="0" Grid.Column="2"/>
<Label x:Name="lblOrderNumberText" Content="OrderNumber:" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="2,2,2,2" Grid.Row="1" Grid.Column="2"/>
<Label Content="Region:" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="2,2,2,2" Grid.Row="2" Grid.Column="2"/>
<Label x:Name="lblRadioAddressText" Content="RadioAddress:" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="2,2,2,2" Grid.Row="3" Grid.Column="2"/>
<Label Content="Firmware:" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="2,2,2,2" Grid.Row="0" Grid.Column="5"/>
<Label x:Name="lblLutText" Content="LUT CRC:" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="2,2,2,2" Grid.Row="1" Grid.Column="5"/>
<Label x:Name="lblMeterSizeText" Content="Meter Size:" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="2,2,2,2" Grid.Row="2" Grid.Column="5"/>
<Label Content="" x:Name="lblSerialNumberValue" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="2,2,2,2" Grid.Row="0" Grid.Column="3"/>
<Label Content="" x:Name="lblOrderNumberValue" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="2,2,2,2" Grid.Row="1" Grid.Column="3"/>
<Label Content="" x:Name="lblRegionValue" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="2,2,2,2" Grid.Row="2" Grid.Column="3"/>
<Label Content="" x:Name="lblRadioAddressValue" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="2,2,2,2" Grid.Row="3" Grid.Column="3"/>
<Label Content="" x:Name="lblFwValue" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="2,2,2,2" Grid.Row="0" Grid.Column="6"/>
<Label Content="" x:Name="lblLutValue" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="2,2,2,2" Grid.Row="1" Grid.Column="6"/>
<Label Content="" x:Name="lblMeterSizeValue" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="2,2,2,2" Grid.Row="2" Grid.Column="6"/>
<!--Pictures-->
<Border Grid.Row="0" Grid.RowSpan="4" Grid.Column="0" Margin="2,2,2,2" BorderThickness="1" BorderBrush="Black" Grid.ColumnSpan="2">
<Image Margin="0,0,-1,-1" Source="/Resources/Cordonel With Display small.JPG" Stretch="Fill" />
</Border>
<Border Grid.Row="0" Grid.RowSpan="2" Grid.Column="9" Grid.ColumnSpan="2" Margin="2,2,2,2" BorderThickness="1" BorderBrush="Black" >
<Image Margin="0,0,-1,-1" Source="/Resources/SensusLogoXylem.JPG" Stretch="Fill" />
</Border>
<!--Process Information-->
<DataGrid x:Name="dgTotalProcess" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="2,2,2,2" Grid.Row="4" Grid.RowSpan="11" Grid.Column="0" Grid.ColumnSpan="4" ItemsSource="{Binding}"
AutoGenerateColumns="True" SelectionMode="Single" IsReadOnly="True" CanUserReorderColumns="False" CanUserResizeColumns="False" CanUserResizeRows="False" CanUserSortColumns="False" IsEnabled="True" />
<StackPanel x:Name="dpSubProcess" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="2,2,2,2" Grid.Row="4" Grid.RowSpan="11" Grid.Column="5" Grid.ColumnSpan="3" />
<GroupBox Header="Info" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Grid.Row="15" Grid.RowSpan="4" Grid.Column="0" Grid.ColumnSpan="11" >
<RichTextBox x:Name="rtbLog" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />
</GroupBox>
<!--Progress Bars and Info-->
<ProgressBar x:Name="pbSubProgress" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="2,4,2,4" Grid.Row="19" Grid.Column="2" Grid.ColumnSpan="8" />
<ProgressBar x:Name="pbTotalProgress" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="2,4,2,4" Grid.Row="20" Grid.Column="2" Grid.ColumnSpan="8" />
<Label x:Name="lblSubProgressValue" HorizontalAlignment="Right" VerticalAlignment="Stretch" Margin="0,0,2,0" Grid.Row="19" Grid.Column="10" Content="0,0 %"/>
<Label x:Name="lblTotalProgressValue" HorizontalAlignment="Right" VerticalAlignment="Stretch" Margin="0,0,2,0" Grid.Row="20" Grid.Column="10" Content="0,0 %"/>
<Label x:Name="lblSingleProcessText" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="2,2,2,2" Grid.Row="19" Grid.Column="0" Content="Single Process:" Grid.ColumnSpan="2" />
<Label x:Name="lblTotalProcessText" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="2,2,2,2" Grid.Row="20" Grid.Column="0" Content="Total Process:" Grid.ColumnSpan="2" />
<!--Buttons-->
<Button x:Name="btnStart" HorizontalAlignment="Stretch" Margin="2,4,2,4" VerticalAlignment="Stretch" Grid.Column="9" Grid.ColumnSpan="2" Grid.Row="2" Grid.RowSpan="2" IsEnabled="false" Click="BtnStart_Click" Content="Start" />
<Button x:Name="btnStop" HorizontalAlignment="Stretch" Margin="2,4,2,4" VerticalAlignment="Stretch" Grid.Column="9" Grid.ColumnSpan="2" Grid.Row="4" Grid.RowSpan="2" IsEnabled="false" Click="BtnStop_Click" Content="Stop" />
</Grid>
</DockPanel>
</Window>
@@ -1,928 +0,0 @@
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 Picking.xaml
/// </summary>
public sealed partial class Picking
{
#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;
#endregion
public Picking()
{
_logger = NLogHelper.CreateOrGetLogger("ProductionUiCordonel");
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 = $"{Properties.Resources.StrSoftwareNameVersion} {_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);
}
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>
private void ProcessStateChange_Handler(Object sender, ProcessStateArgs e)
{
_logger.Debug($"Slot:{Slot} - Picking 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)
{
StoreSuccessNote(out _);
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();
_processCtrl?.SetProcessState(ProcessState.DetectCordonel);
}
private void PrintErrorNote()
{
var sb = new StringBuilder();
sb.AppendLine("========================================================================");
sb.AppendLine(Properties.Resources.StrInstructionReturnPapers);
sb.AppendLine("========================================================================");
CreateFile(sb, out var fileName);
Process.Start(fileName);
}
private void StoreSuccessNote(out String fileName)
{
var sb = new StringBuilder();
sb.AppendLine("========================================================================");
sb.AppendLine(Properties.Resources.StrInfoSuccessPapers);
sb.AppendLine("========================================================================");
CreateFile(sb, out fileName);
}
private void PrintSuccessNote()
{
StoreSuccessNote(out var fileName);
Process.Start(fileName);
}
private void CreateFile(StringBuilder sb, out String fileName)
{
if (sb == null)
sb = new StringBuilder();
var genesisMeter = _processCtrl.GetGenesisMeter();
var loggingPath = $"C:\\GenesisLog\\{DateTime.Now:yyyy-MM-dd}\\ProductionUiCordonel\\";
fileName = $"{loggingPath}{DateTime.Now.ToString("yyyyMMddHHmmss")}_Report_{genesisMeter.PcbId}.txt";
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("------------------------------------------------------------------------");
var rtbText = new TextRange(
rtbLog.Document.ContentStart,
rtbLog.Document.ContentEnd
);
sb.Append($"{rtbText.Text}");
File.WriteAllText(fileName, sb.ToString());
}
/// <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);
}
}
}
@@ -14,18 +14,18 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses
/// <remarks date="2025-Apr-14" author="Thomas Wiedebusch">
/// - Initial
/// </remarks>
public class BaseProcessStates
public class BaseProcessStatesDef : IProcessStateDef
{
/// <summary>
/// Collection of state information
/// </summary>
protected List<ProcessStateStruct> StateContainer { get; }
public List<ProcessStateStruct> StateContainer { get; }
/// <summary>
/// Ctor:
/// Initialize all hidden standard generic states
/// </summary>
protected BaseProcessStates()
protected BaseProcessStatesDef()
{
StateContainer = new List<ProcessStateStruct>
{
@@ -81,14 +81,7 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses
};
}
/// <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>
///<inheritdoc/>
public ProcessStateStruct GetProcessStateStructOfState(ProcessState stateMachineState)
{
return (from stateContainer in StateContainer
@@ -96,14 +89,7 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses
select stateContainer).FirstOrDefault();
}
/// <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>
///<inheritdoc/>
public IProductionProcess GetProcessOfState(ProcessState stateMachineState)
{
return (from stateContainer in StateContainer
@@ -111,17 +97,7 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses
select stateContainer.ProductionProcess).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>
///<inheritdoc/>
public String GetStateInfoOfState(ProcessState? stateMachineState)
{
if (stateMachineState == null)
@@ -132,14 +108,7 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses
select stateContainer.ProcessInfo).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>
///<inheritdoc/>
public String GetStateInfoOfProcess(IProductionProcess process)
{
return (from stateContainer in StateContainer
@@ -147,14 +116,7 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses
select stateContainer.ProcessInfo).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>
///<inheritdoc/>
public ProcessState GetStateOfInfoText(String text)
{
return (from stateContainer in StateContainer
@@ -162,14 +124,7 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses
select stateContainer.ProcessState).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>
///<inheritdoc/>
public ProcessState GetStateOfProcess(IProductionProcess process)
{
return (from stateContainer in StateContainer
@@ -177,34 +132,13 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses
select stateContainer.ProcessState).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>
///<inheritdoc/>
public Int32 GetNumberOfInitializedProcesses()
{
return StateContainer.Count(stateContainer => stateContainer.ProductionProcessNo != null);
}
/// <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>
///<inheritdoc/>
public List<IProductionProcess> GetAllEolRelevantProcesses()
{
var sortedList = StateContainer
@@ -590,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;
@@ -7,22 +7,46 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.EolPr
{
/// <summary>
/// Concatenation for all production process states:
/// - Production process class (representing a production process step),
/// - Production process class (representing a production process step), null if hidden process,
/// - attached state,
/// - state information to display a text message.
/// - 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="2023-Feb-14" author="Thomas Wiedebusch">
/// <remarks date="2025-Apr-15" author="Thomas Wiedebusch">
/// - Initial
/// </remarks>
public class EolStateMachineDef : BaseProcessStates
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.
///
@@ -33,30 +57,53 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.EolPr
/// 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):
/// 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 "nextStateOnSuccess: BaseProductionProcess.DoNotChangeStateAfterCompletion"
/// has to be set to avoid a state change on successfully execution of the process.
/// Instead, the "kickOffParallelState" has to be defined to immediately start the next process.
/// the actual new assigned process).
///
/// Define the (e.g.):
///
/// INSTRUCTION TO DELAY THE START OF A PROCESS:
/// --------------------------------------------
/// 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 process-state to wait for.
/// 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:
/// - set the "waitForAllProcesses" to true.
/// 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 EolStateMachineDef()
public EolProcessStateDef()
{
var stateContainer = new List<ProcessStateStruct>
{
#region ----------------------------------- GENERIC-STATES---------------------------------------------
// Usage of the generic-state to detect the Cordonel on the communication line (request protocol)
// 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(
@@ -66,7 +113,6 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.EolPr
productionProcessNo: 0,
nextStateOnSuccess: ProcessState.CheckNewMeter),
// Usage of the generic-state to check for new meter
// 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
@@ -79,7 +125,6 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.EolPr
nextStateOnSuccess: ProcessState.DetectCordonel,
errorExitState: ProcessState.ConnectCordonel),
// Usage of the generic-state to connect the Cordonel
// 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(
@@ -92,7 +137,6 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.EolPr
// Kick off parallel process execution
kickOffParallelState: ProcessState.GetSerialNumberAndRadioAddress),
// Usage of the generic-state to get the serial-number and radio-address
// 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(
@@ -105,6 +149,22 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.EolPr
// Kick off parallel process execution
kickOffParallelState:ProcessState.GetProgrammingParameters),
// This scans the order number, it has to be executed exclusively with automatic
new ProcessStateStruct(
new CheckOrderNumber(Resources.StrStateCheckOrderNumber),
ProcessState.CheckOrderNumber,
Resources.StrStateCheckOrderNumber,
11,
ProcessState.CheckSerialNumber),
// This scans the serial number, it has to be executed exclusively with automatic
new ProcessStateStruct(
new CheckSerialNumber( Resources.StrStateCheckSerialNumber),
ProcessState.CheckSerialNumber,
Resources.StrStateCheckSerialNumber,
12,
ProcessState.CheckAttachments),
#endregion -------------------------------- GENERIC-STATES --------------------------------------------
#region ----------------------------------- EOL-STATES ------------------------------------------------
@@ -124,7 +184,6 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.EolPr
// Wait until this process has been successfully completed
waitForSingleProcess: ProcessState.ConnectCordonel),
// EOL-state of the EOL software
// 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.
@@ -142,7 +201,6 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.EolPr
waitForSingleProcess: ProcessState.ConnectCordonel),
// EOL-state of the EOL software
// 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.
@@ -156,7 +214,6 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.EolPr
nextStateOnSuccess: ProcessState.ExecFinalParametrization,
waitForAllProcesses: true),
// EOL-state of the EOL software
// This writes all setups to the device, it has to be executed exclusively with automatic
new ProcessStateStruct(
productionProcess: new ExecFinalParametrization(Resources.StrStateFinalParametrization),
@@ -165,7 +222,6 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.EolPr
productionProcessNo: 6,
nextStateOnSuccess: ProcessState.ExecStoreConfiguration),
// EOL-state of the EOL software
// 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
@@ -176,86 +232,61 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.EolPr
productionProcessNo: 7,
nextStateOnSuccess: ProcessState.RebootCordonel),
// EOL-state of the EOL software
// 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,
productionProcess: new ExecRebootCordonel(Resources.StrStateRebootCordonel),
processState: ProcessState.RebootCordonel,
processInfo: Resources.StrStateRebootCordonel,
productionProcessNo: 8,
nextStateOnSuccess: ProcessState.CheckFinalParametrization),
nextStateOnSuccess: ProcessState.CheckFinalParametrization),
// EOL-state of the EOL software
// 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(
new CheckFinalParametrization(Resources.StrStateCheckParametrization),
ProcessState.CheckFinalParametrization,
Resources.StrStateCheckParametrization,
9,
ProcessState.CheckRadio),
productionProcess: new CheckFinalParametrization(Resources.StrStateCheckParametrization),
processState: ProcessState.CheckFinalParametrization,
processInfo: Resources.StrStateCheckParametrization,
productionProcessNo:9,
nextStateOnSuccess: ProcessState.CheckRadio),
// EOL-state of the EOL software
// 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(
new CheckRadio(Resources.StrStateRadioCheck),
ProcessState.CheckRadio,
Resources.StrStateRadioCheck,
10,
ProcessState.CheckOrderNumber),
productionProcess: new CheckRadio(Resources.StrStateRadioCheck),
processState: ProcessState.CheckRadio,
processInfo: Resources.StrStateRadioCheck,
productionProcessNo:10,
nextStateOnSuccess: ProcessState.CheckOrderNumber),
// EOL-state of the EOL software
// This scans the order number, it has to be executed exclusively with automatic
new ProcessStateStruct(
new CheckOrderNumber(Resources.StrStateCheckOrderNumber),
ProcessState.CheckOrderNumber,
Resources.StrStateCheckOrderNumber,
11,
ProcessState.CheckSerialNumber),
// EOL-state of the EOL software
// This scans the serial number, it has to be executed exclusively with automatic
new ProcessStateStruct(
new CheckSerialNumber( Resources.StrStateCheckSerialNumber),
ProcessState.CheckSerialNumber,
Resources.StrStateCheckSerialNumber,
12,
ProcessState.CheckAttachments),
// EOL-state of the EOL software
// Precondition: - All checks have to be executed with positive result
new ProcessStateStruct(
new CheckAttachments(Resources.StrStateCheckAttachments),
ProcessState.CheckAttachments,
Resources.StrStateCheckAttachments,
13,
ProcessState.ExecVisualInspection),
productionProcess: new CheckAttachments(Resources.StrStateCheckAttachments),
processState: ProcessState.CheckAttachments,
processInfo: Resources.StrStateCheckAttachments,
productionProcessNo:13,
nextStateOnSuccess: ProcessState.ExecVisualInspection),
// EOL-state of the EOL software
// Precondition: - All checks have to be executed with positive result
new ProcessStateStruct(
new VisualInspection(Resources.StrStateVisualInspection),
ProcessState.ExecVisualInspection,
Resources.StrStateVisualInspection,
14,
ProcessState.PrepareShippingMode),
productionProcess: new VisualInspection(Resources.StrStateVisualInspection),
processState: ProcessState.ExecVisualInspection,
processInfo: Resources.StrStateVisualInspection,
productionProcessNo:14,
nextStateOnSuccess: ProcessState.PrepareShippingMode),
// EOL-state of the EOL software
// Precondition: - All checks have to be executed with positive result
new ProcessStateStruct(
new PrepareShipping(Resources.StrStatePrepareShipping),
ProcessState.PrepareShippingMode,
Resources.StrStatePrepareShipping,
15,
ProcessState.ReadyForShipping),
productionProcess: new PrepareShipping(Resources.StrStatePrepareShipping),
processState: ProcessState.PrepareShippingMode,
processInfo: Resources.StrStatePrepareShipping,
productionProcessNo:15,
nextStateOnSuccess: ProcessState.ReadyForShipping),
// EOL-state of the EOL software
new ProcessStateStruct(
productionProcess: null,
processState:ProcessState.ReadyForShipping,
@@ -86,6 +86,9 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.EolPr
/// <remarks date="2025-Apr-07" author="Thomas Wiedebusch">
/// - CancellationToken.
/// </remarks>
/// <remarks date="2025-Apr-15" author="Thomas Wiedebusch">
/// - Retries for installation of password file.
/// </remarks>
public override StatusReturn ExecuteProcess()
{
// Uncheck executed process to leave the result open needed for retries
@@ -184,8 +187,14 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.EolPr
if (!Meter.IsLoggedOn)
Meter.Login();
retValBol = _meterPwdFile.UnlockEraseWriteMeterPwdFile();
retValBol &= _meterPwdFile.WriteMeterPwdFile() && _meterPwdFile.VerifyMeterPwdFile();
// Install and check password file
var retryCtr = 2;
do
{
retValBol = _meterPwdFile.UnlockEraseWriteMeterPwdFile();
retValBol &= _meterPwdFile.WriteMeterPwdFile() && _meterPwdFile.VerifyMeterPwdFile();
} while (retryCtr-- > 0 && !retValBol);
ActualProcessProgress++;
if (!retValBol)
@@ -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();
}
}
}
@@ -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();
}
}
}
}
@@ -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;
}
}
}
}
@@ -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;
}
}
}
}
@@ -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();
}
}
}
@@ -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;
}
}
}
}
@@ -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();
}
}
}
@@ -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
}
}
@@ -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
}
}
@@ -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;
}
}
}
@@ -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;
}
}
}
@@ -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();
}
}
}
@@ -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();
}
}
@@ -0,0 +1,168 @@
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.Idle),
#endregion -------------------------------- GENERIC-STATES --------------------------------------------
#region ----------------------------------- PICKING-STATES --------------------------------------------
//TODO Roland: implement your states here
#endregion -------------------------------- PICKING-STATES --------------------------------------------
};
StateContainer.AddRange(stateContainer);
}
}
}
@@ -8,8 +8,8 @@ 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.EolProcesses;
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
@@ -44,7 +44,7 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses
}
// Container for production process states
private BaseProcessStates _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)
@@ -113,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>
@@ -121,12 +122,13 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses
/// - Always RegisterWatchService on,
/// - Always MinMaxCHeck on.
/// </remarks>
public ProcessController(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
@@ -598,8 +600,6 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses
{
if (Processes == null)
Processes = new List<IProductionProcess>();
if (_processStateDef == null)
_processStateDef = new EolStateMachineDef();
// get all processes relevant for EOL from table which has to be sorted
var processes = _processStateDef.GetAllEolRelevantProcesses();
@@ -283,13 +283,11 @@
<Compile Include="ctls\ctlMultiModePressure.xaml.cs">
<DependentUpon>ctlMultiModePressure.xaml</DependentUpon>
</Compile>
<Compile Include="Picking.xaml.cs">
<DependentUpon>Picking.xaml</DependentUpon>
</Compile>
<Compile Include="Model\EOLHandler.cs" />
<Compile Include="ProductionProcesses\Enum\PickingProcessState.cs" />
<Compile Include="ProductionProcesses\EolProcesses\VisualInspection.cs" />
<Compile Include="ProductionProcesses\GenericStateMachineDef.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\GenericProcesses\GetSerialNumberAndRadioAddress.cs" />
@@ -300,7 +298,8 @@
<Compile Include="ProductionProcesses\Enum\ImgState.cs" />
<Compile Include="ProductionProcesses\Enum\ProcessState.cs" />
<Compile Include="ProductionProcesses\EventArgs\SingleProcessStateArgs.cs" />
<Compile Include="ProductionProcesses\EolProcesses\EolStateMachineDef.cs" />
<Compile Include="ProductionProcesses\EolProcesses\EolProcessStatesDef.cs" />
<Compile Include="ProductionProcesses\PickingProcesses\PickingProcessStatesDef.cs" />
<Compile Include="ProductionProcesses\ProcessStateStruct.cs" />
<Compile Include="Data\PickingResultData.cs" />
<Compile Include="Data\PressureResultDataNotifyable.cs" />
@@ -311,12 +310,6 @@
<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\GenericProcesses\CheckSerialNumber.cs" />
<Compile Include="ProductionProcesses\GenericProcesses\CheckOrderNumber.cs" />
@@ -376,37 +369,17 @@
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Picking.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="FinalTest.xaml">
<Page Include="ProductionWindow.xaml">
<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>
@@ -620,7 +593,6 @@
</ItemGroup>
<ItemGroup>
<Folder Include="Enum\" />
<Folder Include="ProductionProcesses\PickingProcesses\" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
@@ -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">
@@ -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;
@@ -59,13 +60,14 @@ namespace Xylem.Common.Production.ProductionUiCordonel
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 ProcessController(Slot);
_processCtrl = new ProcessController(Slot, _processStateDef);
}
catch (Exception ex)
{
@@ -19,7 +19,7 @@ namespace Xylem.Common.Production.ProductionUiCordonel.Properties {
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources {
@@ -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>
@@ -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>
@@ -733,9 +733,12 @@
<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>
@@ -733,9 +733,12 @@
<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>