using Logic.ProductionToProductMapper.Cordonel; using Newtonsoft.Json; using System; using System.Collections.Generic; using System.ComponentModel; using System.IO.Ports; using System.Linq; using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; using Ui.ProductionControls; 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.Logic.SoftwareAccessHelper; using static Ui.ProductionControls.ctlPictureProgressBar; namespace CordonelAssemblyLine.Model { internal class PickingViewModel : INotifyPropertyChanged { 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 void UpdateLogText(string text, bool forceGuiUpdate = true) { logText = $"{text}{Environment.NewLine}{logText}"; if (logText.Length > 2503) { logText = $"{logText.Substring(0, 2500)}..."; } if (forceGuiUpdate) { LogText = logText; } } private string historyText = "-"; public string HistoryText { get { return historyText; } set { historyText = value; NotifyPropertyChanged(nameof(HistoryText)); } } private string logText = "Start"; public string LogText { get { return logText; } set { logText = value; NotifyPropertyChanged(nameof(LogText)); } } public string Slot { get { return slot; } set { slot = value; NotifyPropertyChanged(nameof(Slot)); } } public string Result { get { return result; } set { result = value; NotifyPropertyChanged(nameof(Result)); } } public PickingViewModel() { InitProgressBar(); } private void InitProgressBar() { ProgressBar = new List(); ProgressBar.Add(new ImageElement() { Name = "Init", Image = Ui.ProductionControls.Enums.Img.Waiting }); ProgressBar.Add(new ImageElement() { Name = "Scan", Image = Ui.ProductionControls.Enums.Img.BarcodeScanner }); ProgressBar.Add(new ImageElement() { Name = "Connect", Image = Ui.ProductionControls.Enums.Img.Plugin }); ProgressBar.Add(new ImageElement() { Name = "Order data", Image = Ui.ProductionControls.Enums.Img.Cloud }); ProgressBar.Add(new ImageElement() { Name = "Compare", Image = Ui.ProductionControls.Enums.Img.Compare }); ProgressBar.Add(new ImageElement() { Name = "Compare Result", Image = Ui.ProductionControls.Enums.Img.Default }); ProgressBar.Add(new ImageElement() { Name = "Scan Build", Image = Ui.ProductionControls.Enums.Img.BarcodeScanner }); ProgressBar.Add(new ImageElement() { Name = "Scan Build Pressure", Image = Ui.ProductionControls.Enums.Img.BarcodeScanner }); } public List ProgressBar { get; internal set; } public event PropertyChangedEventHandler PropertyChanged; protected virtual void NotifyPropertyChanged([CallerMemberName] String propertyName = "") { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } public void StartPicking(CancellationToken cancle, string scannerPort, int slotNr) { ScannerPort = scannerPort; SlotNr = slotNr; var s = new Task(() => { PickingLoop(cancle); }, cancle); s.Start(); } public enum PickingStateMachine { Init, WaitForScanning, ScanningDone, WaitForDetect, GetOrderDetails, Compare, MeterDone, MeterError, StartCom, WaitForBuildingMeterReady, WaitForBuildingPressureReady, } private PickingStateMachine sm = PickingStateMachine.Init; private class BarScanner : IDisposable { private bool isRuning = false; 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) { if (Port == null) { return; } WaitForScannerTask = new Task(() => { using (var a = new SerialPort(Port)) { try { a.Open(); a.NewLine = "\r"; while (true) { if (Cancellation.IsCancellationRequested) { isRuning = false; break; } else { Input = a.ReadLine(); a.Close(); isRuning = false; break; } } } catch (Exception ex) { Input = ex.Message; isRuning = false; } } }, Cancellation); WaitForScannerTask.Start(); } } public void Dispose() { if (WaitForScannerTask.Status != TaskStatus.Faulted && WaitForScannerTask.Status != TaskStatus.RanToCompletion && WaitForScannerTask.Status != TaskStatus.Canceled) { WaitForScannerTask.Dispose(); } } } public void setState(string state) { State = state; UpdateLogText($"Status:{State}"); } public bool Compare(Dictionary checkAppsIdVersion, uint Frequency, uint MeterSize, bool PressurePresent) { using (var Batch = new MeterBatch()) { using (var meter = new GenesisMeter()) { meter.SetupFromConfigFile(SlotNr); Batch.AddMeter(meter); setState("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={Order}"; 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 checkAppsIdVersion, uint Frequency, uint MeterSize, bool PressurePresent, GenesisMeter meter) { setState($"Üperprüfe Parameter"); var FrequencyReadOut = RegisterConverter.ConvertTo(meter.ReadRegister("SENSUSRADIO_FrequencyIndicator")); if (FrequencyReadOut != Frequency) { setState($"Falsche Frequenz! soll {Frequency}MHz ist {FrequencyReadOut}MHz"); meter.WriteLog(State); return false; } //TODO: metersize check for bigger dn sizes!!! //var MeterSizeReadOut = RegisterConverter.ConvertTo(meter.ReadRegister("GENESISFLOW_MeterSize")); //if (MeterSizeReadOut != MeterSize) //{ // setState($"Meter Dn falsch! soll {MeterSize}DN ist {MeterSizeReadOut}DN"); // meter.WriteLog(State); // return false; //} meter.WriteRegister("METROLOGYASST_PressurePresent", 0, true); var PressureReadOut = RegisterConverter.ConvertTo(meter.ReadRegister("METROLOGYASST_PressurePresent")); if (!PressureReadOut) { meter.WriteRegister("METROLOGYASST_PressurePresent", 1, true); meter.WriteRegister("METROLOGYASST_PressureMeasure", 1, true); var pressure = RegisterConverter.ConvertTo(meter.ReadRegister("METROLOGYASST_PressureMeasure")); setState($"Prüfe Drucksensor. {pressure}"); meter.WriteRegister("METROLOGYASST_PressureMeasure", 1, true); var pressureS = RegisterConverter.ConvertTo(meter.ReadRegister("METROLOGYASST_PressureMeasure")); if (pressure - pressureS == 0) { PressureReadOut = false; meter.WriteRegister("METROLOGYASST_PressurePresent", 0, true); } else { setState($"Pcb mit Drucksensor. Registerwert überschrieben"); PressureReadOut = true; } } if (PressureReadOut != PressurePresent) { if (!PressurePresent) { setState($"Pcb mit Drucksensor. Laut Auftrag keine verbaut"); meter.WriteLog(State); } else { setState($"Pcb ohne Drucksensor. Laut Auftrag soll eine verbaut werden"); meter.WriteLog(State); } //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) { setState($"Falsche FW, bitte Updaten AppId:{item.Key} sollte {item.Value} haben, hat aber {MeterFWApp.Version}"); meter.WriteLog(State); return false; } } catch (Exception) { setState($"Fehler beim auslesen der FW"); meter.WriteLog(State); return false; } } try { meter.WriteRegister("METROLOGYASST_StoreConfiguration", 1); Thread.Sleep(2500); meter.Logout(); Thread.Sleep(2500); meter.ReLogin(); var storeRet = meter.ReadRegister("METROLOGYASST_StoreConfiguration"); if (meter.PcbId != "18440026" && meter.PcbId != "193300058" && meter.PcbId != "194800276" && meter.PcbId != "201420255" && !storeRet.All(a => a.Equals(0))) { setState($"Filesystem corrupt"); meter.WriteLog(State); return false; } } catch (Exception) { setState($"Fehler beim überprüfen des Filesystems"); meter.WriteLog(State); return false; } return true; } private PickingCompareItem OrderDetails; private OrderOverViewCordonelWithPicking OrderOverview; private BarScanner barScanner; private string Order; private string PcbId; private string ScannerPort = "COM20"; private int SlotNr = 1; //PickingState,PickingScanner,PickingSlot,PickingResult private void PickingLoop(CancellationToken token) { var converter = new System.Windows.Media.BrushConverter(); while (!token.IsCancellationRequested) { switch (sm) { case PickingStateMachine.Init: setState("Initialisierung"); Slot = $"Inaktiv EP {SlotNr}"; Scanner = $"Geschlossen {ScannerPort}"; //CheckAllPorts? sm = PickingStateMachine.StartCom; InitProgressBar(); break; case PickingStateMachine.StartCom: OrderDetails = null; OrderOverview = null; Scanner = $"Öfffne {ScannerPort}"; //CheckAllPorts? barScanner = new BarScanner(ScannerPort, token); barScanner.Start(); sm = PickingStateMachine.WaitForScanning; var c = (System.Windows.Media.Brush)converter.ConvertFromString("Aquamarine"); c.Freeze(); ResultColor = c; ProgressBar.Where(n => n.Name == "Init").First().State = Ui.ProductionControls.Enums.ImgStatus.Success; ProgressBar.Where(n => n.Name == "Scan").First().State = Ui.ProductionControls.Enums.ImgStatus.InProgress; break; case PickingStateMachine.WaitForScanning: Scanner = $"Offen {ScannerPort}"; setState($"Warte auf Scannereingabe({ScannerPort})"); if (barScanner != null && !String.IsNullOrEmpty(barScanner.Input)) { Order = barScanner.Input; Scanner = $"Geschlossen {ScannerPort}"; barScanner = null; sm = PickingStateMachine.WaitForDetect; ProgressBar.Where(n => n.Name == "Scan").First().State = Ui.ProductionControls.Enums.ImgStatus.Success; ProgressBar.Where(n => n.Name == "Connect").First().State = Ui.ProductionControls.Enums.ImgStatus.InProgress; } break; case PickingStateMachine.WaitForDetect: using (var Batch = new MeterBatch()) { using (var tryMeter = new GenesisMeter()) { try { setState($"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) { setState( $"Pcb gefunden {PcbId}"); Log($"New PcbID detected {PcbId}"); sm = PickingStateMachine.GetOrderDetails; ProgressBar.Where(n => n.Name == "Connect").First().State = Ui.ProductionControls.Enums.ImgStatus.Success; ProgressBar.Where(n => n.Name == "Order data").First().State = Ui.ProductionControls.Enums.ImgStatus.InProgress; } else { Slot = $"Keine Konnektivität EP {SlotNr}"; Log($"No Meter found"); } } catch (Exception e) { Log($"Error occur.{ Environment.NewLine} {e.Message}"); } } } break; case PickingStateMachine.GetOrderDetails: setState($"Lade Auftragsdaten {Order}"); var retCode = 0; var str = LocalWebRequest.GetRequestWithError($"{ServiceUrls.GenesisFinalCheckServiceUrl()}GetOrderOverview?ProductionOrderNumber={Order}&CheckPcbId={PcbId}", out retCode, 35000); if (retCode == 417) { sm = PickingStateMachine.MeterError; Result = "Keine Radio Parameter"; UpdateLogText(Result, true); ProgressBar.Where(n => n.Name == "Compare Result").First().State = Ui.ProductionControls.Enums.ImgStatus.Error; ProgressBar.Where(n => n.Name == "Order data").First().State = Ui.ProductionControls.Enums.ImgStatus.Error; } else { OrderOverview = JsonConvert.DeserializeObject(str); OrderDetails = OrderOverview.PickingCompareItem; if (OrderOverview.OrderOverViewCordonel.Count == OrderOverview.OrderOverViewCordonel.AssignedPicking) { Result = "Auftrag schon komplett"; UpdateLogText(Result, true); sm = PickingStateMachine.MeterError; ProgressBar.Where(n => n.Name == "Compare Result").First().State = Ui.ProductionControls.Enums.ImgStatus.Error; ProgressBar.Where(n => n.Name == "Order data").First().State = Ui.ProductionControls.Enums.ImgStatus.Error; } else { setState($"Auftragsdaten geladen {Order}"); sm = PickingStateMachine.Compare; ProgressBar.Where(n => n.Name == "Order data").First().State = Ui.ProductionControls.Enums.ImgStatus.Success; ProgressBar.Where(n => n.Name == "Compare").First().State = Ui.ProductionControls.Enums.ImgStatus.InProgress; } } break; case PickingStateMachine.Compare: //Compare setState($"Vergleiche Auftragsdaten {Order} mit Pcb Eigenschaften"); var minDate = DateTime.Now; minDate = minDate.AddMonths(OrderOverview.OrderOverViewCordonel.Count < 5 ? -9 : -3); setState($"Register wurde am {OrderOverview.KitronProductionDate } hergestellt, für diesen Auftrag ist muss das Register vor {minDate} hergestellt worden sein"); if (OrderOverview.KitronProductionDate <= minDate) { setState($"Fehlgeschlagen Register ist zu alt! Bitte QS informieren. KitronProductionDate:{OrderOverview.KitronProductionDate }"); // sm = PickingStateMachine.MeterError; var b = (System.Windows.Media.Brush)converter.ConvertFromString("#FFFF00"); b.Freeze(); ResultColor = b; //break; } if (Compare(OrderDetails.CheckAppsIdVersion, OrderDetails.FrequencyIndicator, OrderDetails.MeterSize, OrderDetails.PressurePresent)) { //erfolg anzeigen und weiter ProgressBar.Where(n => n.Name == "Compare Result").First().State = Ui.ProductionControls.Enums.ImgStatus.Success; ProgressBar.Where(n => n.Name == "Compare").First().State = Ui.ProductionControls.Enums.ImgStatus.Success; sm = PickingStateMachine.MeterDone; } else { sm = PickingStateMachine.MeterError; ProgressBar.Where(n => n.Name == "Compare Result").First().State = Ui.ProductionControls.Enums.ImgStatus.Error; ProgressBar.Where(n => n.Name == "Compare").First().State = Ui.ProductionControls.Enums.ImgStatus.Error; var b = (System.Windows.Media.Brush)converter.ConvertFromString("#FF8000"); b.Freeze(); ResultColor = b; } break; case PickingStateMachine.MeterError: OrderDetails = null; OrderOverview = null; setState($"Vergleich abgeschlossen:{State}"); Result = $"Vergleich fertig fehlgeschlagen"; Thread.Sleep(10000); sm = PickingStateMachine.StartCom; break; case PickingStateMachine.MeterDone: setState($"Vergleich abgeschlossen warten auf Montage Rückmeldung"); Result = $"Pcb {PcbId} wurde dem Auftrag {Order} hinzugefügt"; Scanner = $"Öfffne {ScannerPort}"; barScanner = new BarScanner(ScannerPort, token); HistoryText = $"{HistoryText} {Environment.NewLine}{Order}({OrderOverview.OrderOverViewCordonel.AssignedPicking + 1 }/{ OrderOverview.OrderOverViewCordonel.Count})"; barScanner.Start(); sm = PickingStateMachine.WaitForBuildingMeterReady; Thread.Sleep(10000); //CheckAllPorts? ProgressBar.Where(n => n.Name == "Scan Build").First().State = Ui.ProductionControls.Enums.ImgStatus.InProgress; break; case PickingStateMachine.WaitForBuildingMeterReady: if (barScanner != null && !String.IsNullOrEmpty(barScanner.Input)) { if (barScanner.Input == "%Cordonel_SAP_100%") { ProgressBar.Where(n => n.Name == "Scan Build").First().State = Ui.ProductionControls.Enums.ImgStatus.Success; var url = ServiceUrls.MeterProcessStateUrl(); url = url + $"setSapState?PcbID={PcbId}&code=100&version=1"; try { LocalWebRequest.PostRequestAsync(url); } catch (Exception ex) { } if (OrderDetails.PressurePresent) { barScanner = new BarScanner(ScannerPort, token); barScanner.Start(); setState($"Montage Rückmeldung erhalten, Montage des Drucksensors bestätigen"); sm = PickingStateMachine.WaitForBuildingPressureReady; ProgressBar.Where(n => n.Name == "Scan Build Pressure").First().State = Ui.ProductionControls.Enums.ImgStatus.InProgress; } else { setState($"Montage Rückmeldung erhalten, auftrag Scannen"); sm = PickingStateMachine.StartCom; Thread.Sleep(5000); var b = (System.Windows.Media.Brush)converter.ConvertFromString("#419C14"); b.Freeze(); ResultColor = b; } } } break; case PickingStateMachine.WaitForBuildingPressureReady: if (barScanner != null && !String.IsNullOrEmpty(barScanner.Input)) { if (barScanner.Input == "%Cordonel_SAP_101%") { var url = ServiceUrls.MeterProcessStateUrl(); url = url + $"setSapState?PcbID={PcbId}&code=101&version=1"; try { LocalWebRequest.PostRequestAsync(url); } catch (Exception ex) { } var b = (System.Windows.Media.Brush)converter.ConvertFromString("#419C14"); b.Freeze(); ResultColor = b; Thread.Sleep(5000); setState($"Montage Rückmeldung erhalten, auftrag Scannen"); sm = PickingStateMachine.StartCom; } } break; default: break; } Thread.Sleep(1000); } } private void Log(string v) { //throw new NotImplementedException(); } } }