laatzen/Common/CordonelAssemblyLine/Model/MarriageViewModel.cs
2023-08-02 12:38:58 +02:00

742 lines
30 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.Text;
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.GenesisCore.Consts;
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 sealed class MarriageViewModel : INotifyPropertyChanged
{
public event EventHandler<String> OnMsgRaise;
public MarriageViewModel(String scannerPort, Int32 slotNr)
{
//_logger = NLogHelper.CreateOrGetLogger("ProductionUI");
_scannerPort = scannerPort;
_slotNr = slotNr;
}
private readonly ILogger _logger;
private String _stateMsg = "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 => _resultColor;
set
{
_resultColor = value;
NotifyPropertyChanged();
}
}
public String State
{
get => _stateMsg;
set
{
_stateMsg = value;
NotifyPropertyChanged();
}
}
public String Scanner
{
get => _scanner;
set
{
_scanner = value;
NotifyPropertyChanged();
}
}
public String Slot
{
get => _slot;
set
{
_slot = value;
NotifyPropertyChanged();
}
}
public String SerialNr
{
get => _serialNr;
set
{
_serialNr = value;
NotifyPropertyChanged();
}
}
public String Result
{
get => _result;
set
{
_result = value;
NotifyPropertyChanged();
}
}
public Boolean CanMarry
{
get => _canMarry;
set
{
_canMarry = value;
NotifyPropertyChanged();
}
}
public String PcbId
{
get => _pcbId;
set
{
_pcbId = value;
NotifyPropertyChanged();
}
}
private String _pcbId;
private Boolean _canMarry;
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
Task _s;
private Boolean _closeTask;
public void Dispose()
{
while (!_s.IsCompleted)
{
_closeTask = true;
}
}
public void StartStore()
{
_state = PickingStateMachine.Store;
}
public void StartPicking(CancellationToken cancle)
{
_s = new Task(() => { PickingLoop(cancle); }, cancle);
_s.Start();
}
public enum PickingStateMachine
{
Init,
WaitForScanning,
ScanningDone,
WaitForDetect,
GetMapping,
Store,
WaitForBuildingMeterReady,
MappingError,
Done,
GetMappingMSG
}
private PickingStateMachine _state = PickingStateMachine.Init;
private class BarScanner : IDisposable
{
public Boolean? IsRuning;
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;
}
IsRuning = true;
Input = a.ReadLine();
a.Close();
IsRuning = false;
break;
}
}
}
catch (Exception)
{
IsRuning = false;
}
}, _cancellation);
_waitForScannerTask.Start();
}
}
public void Dispose()
{
if (_waitForScannerTask.Status != TaskStatus.Faulted && _waitForScannerTask.Status != TaskStatus.RanToCompletion && _waitForScannerTask.Status != TaskStatus.Canceled)
{
_waitForScannerTask.Dispose();
}
}
}
public Boolean Compare(Dictionary<UInt32, UInt32> checkAppsIdVersion, UInt32 frequency, UInt32 meterSize, Boolean pressurePresent)
{
using (var batch = new MeterBatch())
{
using (var meter = new GenesisMeter())
{
meter.SetupFromConfigFile(_slotNr);
batch.AddMeter(meter);
State = "Am Zähler anmelden";
if (meter.Login())
{
meter.SetProcessState(DisplayCodes.PickingStarted);
var ret = RunCheck(checkAppsIdVersion, frequency, meterSize, pressurePresent, meter);
if (ret)
{
meter.SetProcessState(DisplayCodes.PickingTested);
var url = $"{ServiceUrls.MeterProcessStateUrl()}SetPickingState?PcbID={meter.PcbId}&FertigungsauftragsNr={_serialNr}";
var retString = LocalWebRequest.PostRequestAsyncAndGetContent(url);
if (bool.TryParse(retString, out var result))
{
return result;
}
}
else
{
meter.SetProcessState(DisplayCodes.PickingFailed);
}
}
}
}
return false;
}
private Boolean RunCheck(Dictionary<UInt32, UInt32> checkAppsIdVersion, UInt32 frequency, UInt32 meterSize, Boolean 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<Boolean>(meter.ReadRegister("METROLOGYASST_PressurePresent"));
if (pressureReadOut != pressurePresent)
{
if (pressurePresent)
{
State = "Pcb mit Drucksensor. Laut Auftrag ist keiner verbaut";
}
else
{
State = "Pcb ohne Drucksensor. Laut Auftrag soll einer verbaut werden";
}
//todo raus
return false;
}
foreach (var item in checkAppsIdVersion)
{
try
{
var meterFWApp = meter.MeterAppListVersion.First(a => item.Key == a.AppId);
if (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 Boolean _requestDetails;
private readonly String _scannerPort;
private readonly Int32 _slotNr;
//PickingState,PickingScanner,PickingSlot,PickingResult
private void PickingLoop(CancellationToken token)
{
while (!token.IsCancellationRequested && !_closeTask)
{
switch (_state)
{
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}";
_state = PickingStateMachine.WaitForScanning;
}
else
{
Scanner = $"Nicht geöffnet {_scannerPort}";
_state = PickingStateMachine.Init;
Thread.Sleep(5000);
}
break;
case PickingStateMachine.WaitForScanning:
//_orderDetails = null;
State = $"Warte auf Scannereingabe({_scannerPort})";
if (_barScanner != null && !string.IsNullOrEmpty(_barScanner.Input))
{
if (_requestDetails)
{
State = $"Abfrage ";
PcbId = _barScanner.Input;
_barScanner.Input = "";
_state = PickingStateMachine.GetMappingMSG;
}
else
{
if (_barScanner.Input.Contains("%RequestMapping%"))
{
_requestDetails = true;
State = $"PCB ID scannen!";
_barScanner = new BarScanner(_scannerPort, token);
_barScanner.Start();
}
else
{
SerialNr = _barScanner.Input;
Scanner = $"Geschlossen {_scannerPort}";
_barScanner = null;
_state = 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}");
_state = 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.GetMappingMSG:
State = $"Lade Auftragsdaten {_serialNr}";
var msgStr = LocalWebRequest.GetRequestWithError($"{ServiceUrls.MarriageServiceUrl()}" +
$"GetPreMarriageStateMSG?PcbId={PcbId}", out var msgRetCode, 15000);
var msgRetInt = MarriagePossibleEnum.None;
var sbMsg = new StringBuilder();
var myJsonResponse = Newtonsoft.Json.JsonConvert.DeserializeObject<Object[]>(msgStr);
String retOrder = myJsonResponse[1]?.ToString();
String retSerial = myJsonResponse[2]?.ToString();
String retFreeSrn = myJsonResponse[3]?.ToString();
sbMsg.AppendLine($"Abfrage");
sbMsg.AppendLine($"PCB Id: \t \t \t \t {PcbId}");
sbMsg.AppendLine($"Aufrag: \t \t \t \t {retOrder}");
sbMsg.AppendLine($"Seriennummer: \t \t \t \t {retSerial}");
sbMsg.AppendLine($"Noch Verfügbare Seriennummern des Auftrages: \t {retFreeSrn}");
sbMsg.AppendLine($"Zusätzliche Infos:");
if (msgRetCode != 200 || !Enum.TryParse(myJsonResponse[0].ToString(), out msgRetInt))
{
sbMsg.AppendLine($"Technisches Problem beim abfragen der Verfügbarkeit. Code ({msgRetCode})");
}
if (msgRetInt.HasFlag(MarriagePossibleEnum.NotPossibleDueToAlreadyMarried))
{
sbMsg.AppendLine($"Pcb ist schon mit der Seriennummer {retSerial} verbunden");
}
if (msgRetInt.HasFlag(MarriagePossibleEnum.NotPossibleDuePcbLocked))
{
sbMsg.AppendLine("Pcb ist schon mit einer anderen Seriennummer verbunden.");
}
if (msgRetInt.HasFlag(MarriagePossibleEnum.NotPossibleDueSerialNumberBlocked))
{
sbMsg.AppendLine("Seriennummer ist schon mit einer anderen Pcb verbunden.");
}
if (msgRetInt.HasFlag(MarriagePossibleEnum.PcbNotMatchingOrder))
{
sbMsg.AppendLine("Die Pcb ist noch keinem Auftrag zugeordnet.");
}
if (msgRetInt.HasFlag(MarriagePossibleEnum.Error))
{
sbMsg.AppendLine("Ein unbestimmter Fehler ist aufgetreten.");
}
if (msgRetInt.HasFlag(MarriagePossibleEnum.NotPossibleDueNoPressureTestFound))
{
sbMsg.AppendLine("Druck Test fehlt");
}
if (msgRetInt.HasFlag(MarriagePossibleEnum.NotPossibleDueNoHeTestFound))
{
sbMsg.AppendLine("Heliumtest fehlt");
}
if (msgRetInt.HasFlag(MarriagePossibleEnum.Possible))
{
sbMsg.AppendLine("Verheiraten möglich");
}
OnMsgRaise?.Invoke(this, sbMsg.ToString());
_state = PickingStateMachine.WaitForScanning;
Log($"No Meter found");
break;
case PickingStateMachine.GetMapping:
State = $"Lade Auftragsdaten {_serialNr}";
var str = LocalWebRequest.GetRequestWithError(
$"{ServiceUrls.MarriageServiceUrl()}GetPreMarriageState?SerialNumber=" +
$"{_serialNr}&PcbId={PcbId}", out var retCode, 15000);
var retInt = MarriagePossibleEnum.None;
if (retCode != 200 || !Enum.TryParse(str, out retInt))
{
OnMsgRaise?.Invoke(this, $"Technisches Problem beim abfragen der Verfügbarkeit. Code ({retCode})");
_state = PickingStateMachine.MappingError;
}
List<String> mappingText = new List<String>();
if (retInt.HasFlag(MarriagePossibleEnum.NotPossibleDueToAlreadyMarried))
{
mappingText.Add("Pcb ist schon mit dieser Seriennummer verbunden.Display aktualisiert");
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());
_state = 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}");
}
}
}
}
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 (retInt.HasFlag(MarriagePossibleEnum.NotPossibleDueNoPressureTestFound))
{
mappingText.Add("Druck Test fehlt");
}
if (retInt.HasFlag(MarriagePossibleEnum.NotPossibleDueNoHeTestFound))
{
mappingText.Add("Heliumtest fehlt");
}
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}");
_state = PickingStateMachine.MappingError;
Log($"No Meter found");
}
else
{
_state = 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);
_state = 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;
}
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());
_state = 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}");
}
_state = 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.");
_state = PickingStateMachine.Init;
break;
}
Thread.Sleep(1000);
}
}
public void Log(String txt)
{
_logger?.Info(txt);
}
}
}