625 lines
23 KiB
C#
625 lines
23 KiB
C#
using Logic.ProductionToProductMapper.Cordonel;
|
|
using NLog;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.ComponentModel;
|
|
using System.IO.Ports;
|
|
using System.Linq;
|
|
using System.Net;
|
|
using System.Reflection;
|
|
using System.Runtime.CompilerServices;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using Xylem.Common.CommonCore.Configuration;
|
|
using Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore;
|
|
using Xylem.Common.Hardware.WaterMeter.Genesis.Registers;
|
|
using Xylem.Common.Hardware.WaterMeter.WaterMeterCore;
|
|
using Xylem.Common.Hardware.WaterMeter.WaterMeterCore.Consts;
|
|
using Xylem.Common.Logic.SoftwareAccessHelper;
|
|
using Xylem.Common.Utils.Logging;
|
|
|
|
namespace CordonelAssemblyLine.Model
|
|
{
|
|
internal class MarriageViewModel : INotifyPropertyChanged
|
|
{
|
|
public event EventHandler<string> OnMsgRaise;
|
|
public MarriageViewModel(string scannerPort, int slotNr)
|
|
{
|
|
_logger = NLogHelper.CreateOrGetLogger("ProductionUI");
|
|
ScannerPort = scannerPort;
|
|
SlotNr = slotNr;
|
|
}
|
|
|
|
private readonly ILogger _logger;
|
|
|
|
private string state = "Warte auf Scanner";
|
|
private string scanner = "keine Verbindung";
|
|
private string slot = "-";
|
|
private string result = "-";
|
|
|
|
private System.Windows.Media.Brush resultColor;
|
|
public System.Windows.Media.Brush ResultColor
|
|
{
|
|
get
|
|
{
|
|
return resultColor;
|
|
}
|
|
set
|
|
{
|
|
resultColor = value;
|
|
NotifyPropertyChanged(nameof(ResultColor));
|
|
}
|
|
}
|
|
public string State
|
|
{
|
|
get
|
|
{
|
|
return state;
|
|
}
|
|
set
|
|
{
|
|
state = value;
|
|
NotifyPropertyChanged(nameof(State));
|
|
}
|
|
}
|
|
public string Scanner
|
|
{
|
|
get
|
|
{
|
|
return scanner;
|
|
}
|
|
set
|
|
{
|
|
scanner = value;
|
|
NotifyPropertyChanged(nameof(Scanner));
|
|
}
|
|
}
|
|
public string Slot
|
|
{
|
|
get
|
|
{
|
|
return slot;
|
|
}
|
|
set
|
|
{
|
|
slot = value;
|
|
NotifyPropertyChanged(nameof(Slot));
|
|
}
|
|
}
|
|
public string SerialNr
|
|
{
|
|
get
|
|
{
|
|
return serialNr;
|
|
}
|
|
set
|
|
{
|
|
serialNr = value;
|
|
NotifyPropertyChanged(nameof(SerialNr));
|
|
}
|
|
}
|
|
|
|
|
|
public string Result
|
|
{
|
|
get
|
|
{
|
|
return result;
|
|
}
|
|
set
|
|
{
|
|
result = value;
|
|
NotifyPropertyChanged(nameof(Result));
|
|
}
|
|
}
|
|
|
|
public bool CanMarry
|
|
{
|
|
get
|
|
{
|
|
return canMarry;
|
|
}
|
|
set
|
|
{
|
|
canMarry = value;
|
|
NotifyPropertyChanged(nameof(CanMarry));
|
|
}
|
|
}
|
|
|
|
public string PcbId
|
|
{
|
|
get
|
|
{
|
|
return pcbId;
|
|
}
|
|
set
|
|
{
|
|
pcbId = value;
|
|
NotifyPropertyChanged(nameof(PcbId));
|
|
}
|
|
}
|
|
|
|
private string pcbId;
|
|
private bool canMarry = false;
|
|
|
|
public event PropertyChangedEventHandler PropertyChanged;
|
|
protected virtual void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
|
|
{
|
|
|
|
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
|
}
|
|
|
|
|
|
public void StartStore()
|
|
{
|
|
sm = PickingStateMachine.Store;
|
|
}
|
|
public void StartPicking(CancellationToken cancle)
|
|
{
|
|
var s = new Task(() => { PickingLoop(cancle); }, cancle);
|
|
s.Start();
|
|
}
|
|
public enum PickingStateMachine
|
|
{
|
|
Init,
|
|
WaitForScanning,
|
|
ScanningDone,
|
|
WaitForDetect,
|
|
GetMapping,
|
|
Store,
|
|
WaitForBuildingMeterReady,
|
|
MappingError,
|
|
Done
|
|
}
|
|
private PickingStateMachine sm = PickingStateMachine.Init;
|
|
|
|
private class BarScanner : IDisposable
|
|
{
|
|
public bool? IsRuning = null;
|
|
public String Input = "";
|
|
private String Port;
|
|
private CancellationToken Cancellation;
|
|
private Task WaitForScannerTask;
|
|
public BarScanner(string port, CancellationToken cancellation)
|
|
{
|
|
Port = port;
|
|
Cancellation = cancellation;
|
|
}
|
|
public void Start()
|
|
{
|
|
if (!IsRuning.HasValue || !IsRuning.Value)
|
|
{
|
|
if (Port == null)
|
|
{
|
|
return;
|
|
}
|
|
WaitForScannerTask = new Task(() =>
|
|
{
|
|
try
|
|
{
|
|
using (var a = new SerialPort(Port))
|
|
{
|
|
a.Open();
|
|
a.NewLine = "\r";
|
|
while (true)
|
|
{
|
|
if (Cancellation.IsCancellationRequested)
|
|
{
|
|
IsRuning = false;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
IsRuning = true;
|
|
Input = a.ReadLine();
|
|
a.Close();
|
|
IsRuning = false;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
IsRuning = false;
|
|
|
|
}
|
|
|
|
|
|
}, Cancellation);
|
|
WaitForScannerTask.Start();
|
|
}
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
if (WaitForScannerTask.Status != TaskStatus.Faulted && WaitForScannerTask.Status != TaskStatus.RanToCompletion && WaitForScannerTask.Status != TaskStatus.Canceled)
|
|
{
|
|
WaitForScannerTask.Dispose();
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
|
|
public bool Compare(Dictionary<UInt32, UInt32> checkAppsIdVersion, uint Frequency, uint MeterSize, bool PressurePresent)
|
|
{
|
|
using (var Batch = new MeterBatch())
|
|
{
|
|
|
|
using (var meter = new GenesisMeter())
|
|
{
|
|
|
|
meter.SetupFromConfigFile(SlotNr);
|
|
Batch.AddMeter(meter);
|
|
State = "Am Zähler anmelden";
|
|
if ((bool)meter.Login())
|
|
{
|
|
meter.SetProcessState(Xylem.Common.Hardware.WaterMeter.WaterMeterCore.Consts.DisplayCodes.PickingStarted);
|
|
var ret = RunCheck(checkAppsIdVersion, Frequency, MeterSize, PressurePresent, meter);
|
|
|
|
if (ret)
|
|
{
|
|
meter.SetProcessState(Xylem.Common.Hardware.WaterMeter.WaterMeterCore.Consts.DisplayCodes.PickingTested);
|
|
var url = $"{ServiceUrls.MeterProcessStateUrl()}SetPickingState?PcbID={meter.PcbId}&FertigungsauftragsNr={serialNr}";
|
|
var RetString = LocalWebRequest.PostRequestAsyncAndGetContent(url);
|
|
|
|
var result = false;
|
|
if (bool.TryParse(RetString, out result))
|
|
{
|
|
return result;
|
|
|
|
}
|
|
}
|
|
else
|
|
{
|
|
meter.SetProcessState(Xylem.Common.Hardware.WaterMeter.WaterMeterCore.Consts.DisplayCodes.PickingFailed);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private bool RunCheck(Dictionary<uint, uint> checkAppsIdVersion, uint Frequency, uint MeterSize, bool PressurePresent, GenesisMeter meter)
|
|
{
|
|
State = $"Üperprüfe Parameter";
|
|
var FrequencyReadOut = RegisterConverter.ConvertTo<UInt32>(meter.ReadRegister("SENSUSRADIO_FrequencyIndicator"));
|
|
if (FrequencyReadOut != Frequency)
|
|
{
|
|
State = $"Falsche Frequenz! soll {Frequency}MHz ist {FrequencyReadOut}MHz";
|
|
return false;
|
|
}
|
|
|
|
var MeterSizeReadOut = RegisterConverter.ConvertTo<UInt32>(meter.ReadRegister("GENESISFLOW_MeterSize"));
|
|
if (MeterSizeReadOut != MeterSize)
|
|
{
|
|
State = $"Meter Dn falsch! soll {MeterSize}DN ist {MeterSizeReadOut}DN";
|
|
return false;
|
|
}
|
|
|
|
|
|
var PressureReadOut = RegisterConverter.ConvertTo<bool>(meter.ReadRegister("METROLOGYASST_PressurePresent"));
|
|
if (PressureReadOut != PressurePresent)
|
|
{
|
|
if (PressurePresent)
|
|
{
|
|
State = $"Pcb mit Drucksensor. Laut Auftrag keine verbaut";
|
|
}
|
|
else
|
|
{
|
|
State = $"Pcb ohne Drucksensor. Laut Auftrag soll eine verbaut werden";
|
|
}
|
|
//todo raus
|
|
return false;
|
|
}
|
|
|
|
foreach (var item in checkAppsIdVersion)
|
|
{
|
|
|
|
try
|
|
{
|
|
var MeterFWApp = meter.MeterAppListVersion.First(a => item.Key == a.AppId);
|
|
if (MeterFWApp == null || MeterFWApp.Version != item.Value)
|
|
{
|
|
State = $"Falsche FW, bitte Updaten";
|
|
return false;
|
|
}
|
|
|
|
}
|
|
catch (Exception)
|
|
{
|
|
State = $"Fehler beim auslesen der FW";
|
|
return false;
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
try
|
|
{
|
|
meter.WriteRegister("METROLOGYASST_StoreConfiguration", 1);
|
|
Thread.Sleep(100);
|
|
var storeRet = meter.ReadRegister("METROLOGYASST_StoreConfiguration");
|
|
if (!storeRet.All(a => a.Equals(0)))
|
|
{
|
|
State = $"Filesystem corrupt";
|
|
return false;
|
|
}
|
|
|
|
}
|
|
catch (Exception)
|
|
{
|
|
State = $"Fehler beim überprüfen des Filesystems";
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
private PickingCompareItem OrderDetails;
|
|
private BarScanner barScanner;
|
|
private string serialNr;
|
|
|
|
|
|
|
|
private readonly string ScannerPort;
|
|
private readonly int SlotNr;
|
|
//PickingState,PickingScanner,PickingSlot,PickingResult
|
|
private void PickingLoop(CancellationToken token)
|
|
{
|
|
while (!token.IsCancellationRequested)
|
|
{
|
|
switch (sm)
|
|
{
|
|
case PickingStateMachine.Init:
|
|
CanMarry = false;
|
|
State = "Initialisierung";
|
|
Slot = $"Inaktiv EP {SlotNr}";
|
|
Scanner = $"Geschlossen {ScannerPort}";
|
|
//CheckAllPorts?
|
|
Scanner = $"Öfffne {ScannerPort}";
|
|
//CheckAllPorts?
|
|
barScanner = new BarScanner(ScannerPort, token);
|
|
barScanner.Start();
|
|
|
|
while (!barScanner.IsRuning.HasValue)
|
|
{
|
|
Thread.Sleep(50);
|
|
}
|
|
if (barScanner.IsRuning.HasValue && barScanner.IsRuning.Value)
|
|
{
|
|
Scanner = $"Offen {ScannerPort}";
|
|
sm = PickingStateMachine.WaitForScanning;
|
|
}
|
|
else
|
|
{
|
|
Scanner = $"Nicht geöffnet {ScannerPort}";
|
|
sm = PickingStateMachine.Init;
|
|
Thread.Sleep(5000);
|
|
}
|
|
|
|
|
|
break;
|
|
case PickingStateMachine.WaitForScanning:
|
|
OrderDetails = null;
|
|
|
|
State = $"Warte auf Scannereingabe({ScannerPort})";
|
|
if (barScanner != null && !String.IsNullOrEmpty(barScanner.Input))
|
|
{
|
|
SerialNr = barScanner.Input;
|
|
Scanner = $"Geschlossen {ScannerPort}";
|
|
barScanner = null;
|
|
sm = PickingStateMachine.WaitForDetect;
|
|
}
|
|
|
|
break;
|
|
case PickingStateMachine.WaitForDetect:
|
|
using (var Batch = new MeterBatch())
|
|
{
|
|
|
|
using (var tryMeter = new GenesisMeter())
|
|
{
|
|
try
|
|
{
|
|
State = $"Warte auf Pcb";
|
|
Slot = $"Öffne EP {SlotNr}";
|
|
tryMeter.SetupFromConfigFile(SlotNr);
|
|
Batch.AddMeter(tryMeter);
|
|
tryMeter.Logout();
|
|
Log("Try to get PcbID");
|
|
PcbId = tryMeter.GetPcbId();
|
|
|
|
var hasDetect = !string.IsNullOrEmpty(PcbId);
|
|
|
|
if (hasDetect)
|
|
{
|
|
State = $"Pcb gefunden {PcbId}";
|
|
Log($"New PcbID detected {PcbId}");
|
|
sm = PickingStateMachine.GetMapping;
|
|
}
|
|
else
|
|
{
|
|
Slot = $"Keine Konnektivität EP {SlotNr}";
|
|
Log($"No Meter found");
|
|
}
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Log($"Error occur.{ Environment.NewLine} {e.Message}");
|
|
}
|
|
}
|
|
}
|
|
|
|
break;
|
|
case PickingStateMachine.GetMapping:
|
|
|
|
State = $"Lade Auftragsdaten {serialNr}";
|
|
var retCode = 0;
|
|
var str = LocalWebRequest.GetRequestWithError($"{ServiceUrls.MarriageServiceUrl()}GetPreMarriageState?SerialNumber={serialNr}&PcbId={PcbId}", out retCode, 15000);
|
|
var retInt = MarriagePossibleEnum.None;
|
|
if (retCode != 200 || !MarriagePossibleEnum.TryParse(str, out retInt))
|
|
{
|
|
OnMsgRaise?.Invoke(this, $"Technisches Problem beim abfragen der Verfügbarkeit. Code ({retCode})");
|
|
sm = PickingStateMachine.MappingError;
|
|
}
|
|
List<string> MappingText = new List<string>();
|
|
if (retInt.HasFlag(MarriagePossibleEnum.NotPossibleDueAlredayMatch))
|
|
{
|
|
MappingText.Add("Pcb ist schon mit dieser Seriennummer verbunden.");
|
|
}
|
|
if (retInt.HasFlag(MarriagePossibleEnum.NotPossibleDuePcblocked))
|
|
{
|
|
MappingText.Add("Pcb ist schon mit einer anderen Seriennummer verbunden.");
|
|
}
|
|
if (retInt.HasFlag(MarriagePossibleEnum.NotPossibleDueSerialNumberBlocked))
|
|
{
|
|
MappingText.Add("Seriennummer ist schon mit einer anderen Pcb verbunden.");
|
|
}
|
|
if (retInt.HasFlag(MarriagePossibleEnum.PcbNotMatchingOrder))
|
|
{
|
|
MappingText.Add("Die Pcb ist noch keinem Auftrag zugeordnet.");
|
|
}
|
|
if (retInt.HasFlag(MarriagePossibleEnum.Error))
|
|
{
|
|
MappingText.Add("Ein unbestimmter Fehler ist aufgetreten.");
|
|
}
|
|
|
|
|
|
if (MappingText.Any())
|
|
{
|
|
var MsgText = "";
|
|
foreach (var item in MappingText)
|
|
{
|
|
MsgText = MsgText + Environment.NewLine + item;
|
|
}
|
|
OnMsgRaise?.Invoke(this, $"Diese Kombination ist nicht möglich.{MsgText}");
|
|
sm = PickingStateMachine.MappingError;
|
|
Log($"No Meter found");
|
|
}
|
|
else
|
|
{
|
|
sm = PickingStateMachine.WaitForBuildingMeterReady;
|
|
}
|
|
|
|
break;
|
|
case PickingStateMachine.WaitForBuildingMeterReady:
|
|
CanMarry = true;
|
|
break;
|
|
case PickingStateMachine.MappingError:
|
|
State = $"Mapping nicht möglich, bitte erneut scannen";
|
|
Log($"Mapping nicht möglich, bitte erneut scannen");
|
|
Thread.Sleep(10000);
|
|
sm = PickingStateMachine.Init;
|
|
break;
|
|
case PickingStateMachine.Store:
|
|
CanMarry = false;
|
|
var url = $"{ServiceUrls.MarriageServiceUrl()}SetPcbToSerial?PcbId={PcbId}&Scan={serialNr}&returnMetroData=0";
|
|
try
|
|
{
|
|
string resp = "";
|
|
try
|
|
{
|
|
resp = LocalWebRequest.GetRequest(url, 18000);
|
|
|
|
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
if (!ex.Message.Contains("Mapping already exist. check your marriage request"))
|
|
{
|
|
throw;
|
|
}
|
|
else
|
|
{
|
|
resp = "already store";
|
|
}
|
|
|
|
}
|
|
|
|
|
|
if (resp.Trim().ToLower().Contains("store"))
|
|
{
|
|
using (var Batch = new MeterBatch())
|
|
{
|
|
using (var tryMeter = new GenesisMeter())
|
|
{
|
|
try
|
|
{
|
|
State = $"Warte auf Pcb";
|
|
Slot = $"Öffne EP {SlotNr}";
|
|
tryMeter.SetupFromConfigFile(SlotNr);
|
|
Batch.AddMeter(tryMeter);
|
|
tryMeter.Logout();
|
|
Log("Try to get PcbID");
|
|
PcbId = tryMeter.GetPcbId();
|
|
|
|
var hasDetect = !string.IsNullOrEmpty(PcbId);
|
|
|
|
if (hasDetect)
|
|
{
|
|
tryMeter.Login();
|
|
State = $"Pcb gefunden {PcbId}";
|
|
Log($"New PcbID detected {PcbId}");
|
|
tryMeter.SetProcessState(DisplayCodes.Mounted);
|
|
tryMeter.PushProgress("AssemblyLine", Assembly.GetExecutingAssembly().GetName().Version.ToString());
|
|
|
|
sm = PickingStateMachine.Done;
|
|
}
|
|
else
|
|
{
|
|
Slot = $"Keine Konnektivität EP {SlotNr}";
|
|
Log($"No Meter found");
|
|
}
|
|
OnMsgRaise?.Invoke(this, $"Zähler verheiratet. Kann zur Prüfstation");
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Log($"Error occur.{ Environment.NewLine} {e.Message}");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
OnMsgRaise?.Invoke(this, $"Fehler beim Speichern, bitte Support Kontaktieren.Response{resp}");
|
|
}
|
|
sm = PickingStateMachine.Init;
|
|
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
if (ex is WebException)
|
|
{
|
|
Log($"Error on Store {url}: {Environment.NewLine} {((WebException)ex).Message}");
|
|
}
|
|
else
|
|
{
|
|
Log(ex.Message);
|
|
}
|
|
}
|
|
|
|
break;
|
|
case PickingStateMachine.Done:
|
|
OnMsgRaise?.Invoke(this, $"Bitte Display überprüfen. {Environment.NewLine}Sollte etwas anderes als {DisplayCodes.Mounted} im Display erscheinen ist der Zähler nicht erfolgreich bearbeitet.");
|
|
sm = PickingStateMachine.Init;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
Thread.Sleep(1000);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
public void Log(string txt)
|
|
{
|
|
_logger?.Info(txt);
|
|
}
|
|
}
|
|
|
|
|
|
}
|