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 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 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 checkAppsIdVersion, UInt32 frequency, UInt32 meterSize, Boolean pressurePresent, GenesisMeter meter) { State = $"Üperprüfe Parameter"; var frequencyReadOut = RegisterConverter.ByteArrayToValue(meter.ReadRegister("SENSUSRADIO_FrequencyIndicator")); if (frequencyReadOut != frequency) { State = $"Falsche Frequenz! soll {frequency}MHz ist {frequencyReadOut}MHz"; return false; } var meterSizeReadOut = RegisterConverter.ByteArrayToValue(meter.ReadRegister("GENESISFLOW_MeterSize")); if (meterSizeReadOut != meterSize) { State = $"Meter Dn falsch! soll {meterSize}DN ist {meterSizeReadOut}DN"; return false; } var pressureReadOut = RegisterConverter.ByteArrayToValue(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(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 mappingText = new List(); 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); } } }