From 2842425673d97757cf12ba20da069b01510c1109 Mon Sep 17 00:00:00 2001 From: Michal Buzik Date: Sat, 6 Dec 2025 12:46:12 +0100 Subject: [PATCH] Add simulation logic for test operations and water metrology, enhance UI initialization, and implement optohead flow rate handling. - Introduced simulation timers in `FlyingStartStopTestOp`. - Added `Simulate` methods in `WaterMetrologyData`, `WaterMetrologyDataC7`, and `WaterMetrologyDataC2`. - Enhanced `SmartCommunicationForm` with textbox resizing logic and initialization code. - Implemented flow rate and volume calculation from optohead telemetry in `SmartReader`. - Added unit tests for Poseidon correction parsing. --- .../ControlBoard/Uni/FlyingStartStopTestOp.cs | 27 + .../communication/OptoReceivedEventArgs.cs | 26 + .../PoseidonCmdStartStop/PoseidonReader.cs | 6 +- .../PoseidonReader/SmartReader.cs | 405 +++++++-------- .../communication/C7/NFCHeadServiceOld.cs | 6 +- .../communication/C7/OptoHeadService.cs | 73 ++- .../C7/Protocols/WaterMetrologyData.cs | 15 + .../C7/Protocols/WaterMetrologyDataC2.cs | 38 +- .../C7/Protocols/WaterMetrologyDataC7.cs | 41 ++ .../communication/ECommunicationInterface.cs | 2 +- .../communication/OpticalHeadTest.cs | 24 +- TBF/Rig/Sequences/MainSeq.cs | 9 +- .../ISmartTestMethod.cs | 6 + .../SmartCommunicationForm.cs | 141 ++++-- .../SmartComponentBase.cs | 9 +- .../implementations/EnumExtensions.cs | 30 ++ .../implementations/PoseidonCorrections.cs | 473 +++++++++++++++++- TBF/TBF.csproj | 1 + .../PoseidonCorrectionsTest.cs | 41 ++ TBFTests/TBFTests.csproj | 1 + 20 files changed, 1073 insertions(+), 301 deletions(-) create mode 100644 TBF/Rig/Uni/SharedDialogs/SmartMetersCommunication/implementations/EnumExtensions.cs create mode 100644 TBFTests/Rig/Uni/SharedDialogs/SmartMetersCommunication/implementations/PoseidonCorrectionsTest.cs diff --git a/TBF/Rig/ControlBoard/Uni/FlyingStartStopTestOp.cs b/TBF/Rig/ControlBoard/Uni/FlyingStartStopTestOp.cs index 0b6487c15..a8870d0d5 100644 --- a/TBF/Rig/ControlBoard/Uni/FlyingStartStopTestOp.cs +++ b/TBF/Rig/ControlBoard/Uni/FlyingStartStopTestOp.cs @@ -2,6 +2,7 @@ /// Copyright (c) 2021-2023 Sensus Slovensko a.s. /// using System; +using Common; using log4net; using TBF.Rig.Sequences; @@ -11,6 +12,10 @@ namespace TBF.Rig.ControlBoard.Uni { private static readonly ILog log = LogManager.GetLogger(typeof(FlyingStartStopTestOp)); public override string ToString() { return string.Format("FlyingStartStopTestOp()"); } + + private DateTime startTimeForSimulation; + private bool simulationTimerStarted = false; + /// Arguments of the constructor readonly UniCB uniCB; @@ -123,6 +128,28 @@ namespace TBF.Rig.ControlBoard.Uni { log.DebugFormat("Op.Run() opState={0}", opState); + //Simulation of processing time 25 seconds + if (uniCB.DebugLevel == DebugMode.Simulate) + { + if (opState == OpState.StartingTest) + { + startTimeForSimulation = DateTime.Now; + simulationTimerStarted = false; + } + if (opState == OpState.TestInProgress) + { + if (!simulationTimerStarted) + { + startTimeForSimulation = DateTime.Now; + simulationTimerStarted = true; + } + else if (DateTime.Now - startTimeForSimulation > TimeSpan.FromSeconds(25)) + { + return Event.TestCompleted; + } + } + } + switch (opState) { case OpState.StartingTest: diff --git a/TBF/Rig/RegisterReaders/CommonRR/IPerl/communication/OptoReceivedEventArgs.cs b/TBF/Rig/RegisterReaders/CommonRR/IPerl/communication/OptoReceivedEventArgs.cs index f4fcccbf9..e3a896d59 100644 --- a/TBF/Rig/RegisterReaders/CommonRR/IPerl/communication/OptoReceivedEventArgs.cs +++ b/TBF/Rig/RegisterReaders/CommonRR/IPerl/communication/OptoReceivedEventArgs.cs @@ -3,16 +3,42 @@ /// using System; +using TBF.Rig.RegisterReaders.PoseidonReader.communication.C7.Protocols; namespace TBF.Rig.RegisterReaders.CommonRR.IPerl.communication { public class OptoReceivedEventArgs : EventArgs { public string Data; + public WaterMetrologyData WaterMetrologyData; + public byte[] RawData; public OptoReceivedEventArgs(string data) { this.Data = data; + WaterMetrologyData = null; + RawData = null; + } + + public OptoReceivedEventArgs(string data, WaterMetrologyData waterMetrologyData) + { + this.Data = data; + this.WaterMetrologyData = waterMetrologyData; + RawData = null; + } + + public OptoReceivedEventArgs(byte[] data) + { + this.RawData = data; + Data = null; + WaterMetrologyData = null; + } + + public OptoReceivedEventArgs(WaterMetrologyData data) + { + WaterMetrologyData = data; + Data = null; + RawData = null; } } } diff --git a/TBF/Rig/RegisterReaders/PoseidonCmdStartStop/PoseidonReader.cs b/TBF/Rig/RegisterReaders/PoseidonCmdStartStop/PoseidonReader.cs index 437cb113b..dd6f2ebdd 100644 --- a/TBF/Rig/RegisterReaders/PoseidonCmdStartStop/PoseidonReader.cs +++ b/TBF/Rig/RegisterReaders/PoseidonCmdStartStop/PoseidonReader.cs @@ -28,8 +28,10 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop readonly PoseidonCfg registerReaderCfg; readonly ControlBoard.IControlBoard controlBoard; - - + + public int ComPortNr => registerReaderCfg?.ComPortNr ?? -1; + public PoseidonCfg RegPoseidonCfg => registerReaderCfg; + private bool activeHandlerSessioEnabled = false; private CliRunner _cliRunner; diff --git a/TBF/Rig/RegisterReaders/PoseidonReader/SmartReader.cs b/TBF/Rig/RegisterReaders/PoseidonReader/SmartReader.cs index 538cdbf52..4d7da189a 100644 --- a/TBF/Rig/RegisterReaders/PoseidonReader/SmartReader.cs +++ b/TBF/Rig/RegisterReaders/PoseidonReader/SmartReader.cs @@ -2,6 +2,7 @@ using System; using System.IO; using System.IO.Ports; using System.Linq; +using System.Windows.Forms.VisualStyles; using System.Xml.Linq; using Common; using Common.Iperl; @@ -11,6 +12,8 @@ using NHibernate; using Sensus.iPerl.NfcHandler; using TBF.Rig.Generic; using TBF.Rig.GenericDevices; +using TBF.Rig.RegisterReaders.PoseidonReader.communication.C7; +using TBF.Rig.RegisterReaders.PoseidonReader.communication.C7.Protocols; using TBF.Rig.TestMethods.iPerlCommunication.iPerlHead; using TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.common; using CalibrationStruct = TBF.Rig.RegisterReaders.CommonRR.IPerl.communication.CalibrationStruct; @@ -45,6 +48,7 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader readonly PoseidonCfg _poseidonCfg; + public PoseidonCfg RegPoseidonCfg { get { return _poseidonCfg; } } public int RfidComPortNr { get { return _poseidonCfg.RfidComPortNr; } } public int OptoComPortNr { get { return _poseidonCfg.OptoComPortNr; } } public MeterType MeterType { get { return _poseidonCfg.MeterType; } } @@ -86,6 +90,21 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader float[] x; public float[] X { get { return x; } } + + + + // Volume of water from the opto telegram + private DateTime _firstSampleTime; + private DateTime _lastSampleTime; + + private double _averageFlow; + private long _averageFlowCount; + private readonly object _avgLock = new object(); + private bool _optoheadStarted = false; + + private OptoHeadService _optoHeadService; + + /// /// Passed to OptoTelegramRaw.UpdateFromString(...) @@ -164,9 +183,7 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader /// /// Timestamp from the opto telegram /// - private Int64 lastTimestamp; - private double timestampSec; - private double timestampSec0; + int timeFromStart; /// [s] Time from test start to determine when the test start sample should be taken @@ -174,12 +191,22 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader /// Test start volume for metrology in seconds public double TimestampSecStart { - get { return TimeFromSamples(optoData, optoDataCount, TestStartTelegramIx, StartEndFilterSamplesCount2); } + get + { + return _lastSampleTime != DateTime.MinValue ? 1 : 0; // return one second if is initialized, 0 - is false + //return TimeFromSamples(optoData, optoDataCount, TestStartTelegramIx, StartEndFilterSamplesCount2); + } } /// Test end time for metrology in seconds public double TimestampSecEnd { - get { return TimeFromSamples(optoData, optoDataCount, TestEndTelegramIx, StartEndFilterSamplesCount2); } + get + { + if (_lastSampleTime == DateTime.MinValue) return 0; + TimeSpan delta = _lastSampleTime - _firstSampleTime; + return (delta.TotalSeconds + 1); + //return TimeFromSamples(optoData, optoDataCount, TestEndTelegramIx, StartEndFilterSamplesCount2); + } } /// public bool NoSamples @@ -197,12 +224,20 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader /// Test start volume for metrology in liters public double VolumeLtrStart { - get { return NoSamples ? 0 : VolumeFromSamples(optoData, optoDataCount, TestStartTelegramIx, ScalingFactor(), StartEndFilterSamplesCount2); } + get + { + return 0; + //return NoSamples ? 0 : VolumeFromSamples(optoData, optoDataCount, TestStartTelegramIx, ScalingFactor(), StartEndFilterSamplesCount2); + } } /// Test end volume for metrology in liters public double VolumeLtrEnd { - get { return NoSamples ? 0 : VolumeFromSamples(optoData, optoDataCount, TestEndTelegramIx, ScalingFactor(), StartEndFilterSamplesCount2); } + get + { + return wmVolume; // complet calculated volume (time * flowrate) + //return NoSamples ? 0 : VolumeFromSamples(optoData, optoDataCount, TestEndTelegramIx, ScalingFactor(), StartEndFilterSamplesCount2); + } } @@ -274,9 +309,10 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader { if (_poseidonCfg != null) { - OpenOptoSerialPort($"COM{_poseidonCfg.OptoComPortNr}", 9600, Parity.None, 8, StopBits.One, - Handshake.None); - CloseOptoSerialPort(); + + // OpenOptoSerialPort($"COM{_poseidonCfg.OptoComPortNr}", 9600, Parity.None, 8, StopBits.One, + // Handshake.None); + // CloseOptoSerialPort(); log.FatalFormat($"{Name} initialized: {this}"); } else @@ -401,6 +437,16 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader Q2CorrRL = 0; Q2CorrLR = 0; + + lock (_avgLock) + { + _firstSampleTime = DateTime.MinValue; + _lastSampleTime = DateTime.MinValue; + _averageFlow = 0; + _averageFlowCount = 0; + log.Debug("Initializing datastream state"); + } + simulatedPcbNr = null; dataStreamState = DataStreamState.Flush; @@ -442,6 +488,12 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader { timeFromStart += StateMachine.Period; ReadPulses(); + + //TODO read flow + if (_optoHeadService!= null && !_optoHeadService.IsRunning) + StartOptohead(); + + if (!startSampleAcquired && (timeFromStart >= 8) && (currentTelegramIx >= 0)) { @@ -462,7 +514,94 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader return Event.ReadRegisterDone; } - /// + private void StartOptohead() + { + lock (_avgLock) + { + _firstSampleTime = DateTime.MinValue; + _lastSampleTime = DateTime.MinValue; + _averageFlow = 0; + _averageFlowCount = 0; + } + + StartOptoTestInputLoop(new EventHandler(OnOptoHandler)); + } + + private bool OpenOptoConnection(PoseidonCfg iHeadCfg) + { + try + { + if (iHeadCfg != null) + { + if (_optoHeadService != null) return false; + + OptoHeadService.Con connection = new OptoHeadService.Con($"COM{iHeadCfg.OptoComPortNr}", iHeadCfg.DebugLevel); + _optoHeadService = new OptoHeadService(connection); + return _optoHeadService.CreateSerialConnection(); + } + } + catch (Exception ex) + { + throw ex; + } + return false; + } + + private bool StartOptoTestInputLoop(EventHandler onOptoReceivedHandler) + { + try + { + if (_optoHeadService != null) + { + if (_optoHeadService.IsRunning) return false; + + _optoHeadService.RunLoop(onOptoReceivedHandler); + //run loop runstate = true; + return true; + } + } + catch (Exception ex) + { + log.Error(ex.Message); + throw ex; + } + return false; + } + + private void OnOptoHandler(object sender, CommonRR.IPerl.communication.OptoReceivedEventArgs e) + { + //received data from optohead + WaterMetrologyData eWaterMetrologyData = e?.WaterMetrologyData; + if (eWaterMetrologyData != null && eWaterMetrologyData.C7Data != null) + { + double flowRateLPerS = eWaterMetrologyData.C7Data?.FlowRateLPerS ?? 0; + + lock (_avgLock) + { + if (_averageFlowCount == 0) + { + _firstSampleTime = eWaterMetrologyData.C7Data?.Dt ?? DateTime.Now; + } + + _lastSampleTime = eWaterMetrologyData.C7Data?.Dt ?? DateTime.Now; + + _averageFlowCount++; + + // Running average (no overflow) + _averageFlow += (flowRateLPerS - _averageFlow) / _averageFlowCount; + TimeSpan delta = _lastSampleTime - _firstSampleTime; + if (delta.TotalMilliseconds == 0) + wmVolume = 0; + else + wmVolume = _averageFlow * (delta.TotalMilliseconds / 1000); //volume in liters + //wmVolume = Units.ConvertFrom(Unit.l, _averageFlow * (delta.TotalMilliseconds / 1000)); + log.Info("Calculated Value:" + wmVolume); + } + } + } + + + /// /// Stop this operation /// public void Stop() @@ -570,78 +709,7 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader } - /// - /// Q2 correction factor calculated from the last test (Q2). - /// This factor should be used only for R800 meters. - /// - /// A test result from which to calculate the factor - /// Nominal flow in m3/h - /// 0 or the current Q2 correction factor when updating the factor - /// Calculated Q2 correction factor - public double CalculateQ2CorrectionFactor(Results.Entities.MeterTestRslt currentQ2Result, int currentFactor, double nominalFlow, double errorTarget = 0) - { - double nominalTestFlowLph = Units.ConvertTo(Unit.lph, nominalFlow); - double volumeRefShiftedToTarget = currentQ2Result.VolumeRef * (1.0 + errorTarget / 100.0); - double q2adjErrorShiftedToTarget = Config.Formulas.ErrorFromVolumes(currentQ2Result.VolumeMeter, volumeRefShiftedToTarget); - double A = 16.0 / ScalingFactor(); /// Raw units per ml: DN15=16, DN20=8, DN25=4, DN32=2, DN40=1 - const double B = 8.0; /// Raw units per minute, 8 - const double C = B * 60.0; /// Raw units per hour, 480 - double D = C / A; /// ml correction per hour - double F = D / (nominalTestFlowLph * 10.0); /// Error corrected with 8 Raw Units per minute [%] - double G = F / B; /// Error corrected with 1 Raw Unit per minute [%] - - /// Do not change the factor for an invalid measurement (q2adjResult.VolumeMeter == 0) - double q2CorrectionFactor = (Math.Abs(currentQ2Result.VolumeMeter) <= float.Epsilon) ? Convert.ToDouble(currentFactor) : - Convert.ToDouble(currentFactor) - (q2adjErrorShiftedToTarget / G) * (volumeRefShiftedToTarget / currentQ2Result.VolumeMeter); - - log.WarnFormat("CalculateQ2CorrectionFactor() : Pos={0}, PCB#={1}, Error={2}%, Target={3}%, Current factor={4} New factor={5}", - Name, - SerialNr, - currentQ2Result.Error.ToString("F2"), - errorTarget.ToString("F3"), - currentFactor.ToString("F1"), - q2CorrectionFactor.ToString("F1")); - - return q2CorrectionFactor; - } - - - /// - /// 2 Hz correction factor calculated from two Q3 tests - done at 2Hz and at 8Hz. - /// This factors should be used only for DN32 and DN40 meters. - /// - /// Test result @2Hz from which to calculate the factor - /// Test result @8Hz from which to calculate the factor - /// The calculated Q2 correction factor - /// true = OK, false = failed - public bool Calculate2HzCorrectionFactor(Results.Entities.MeterTestRslt resultAt2Hz, - Results.Entities.MeterTestRslt resultAt8Hz, - out double diff2Hz8Hz, out int hz2CorrectionFactor) - { - hz2CorrectionFactor = 0; - diff2Hz8Hz = 0; - - if ((resultAt2Hz == null) || (resultAt8Hz == null)) - { - return false; /// Test result @2Hz and/or @8Hz is missing ==> water meter failed - } - - diff2Hz8Hz = resultAt2Hz.Error - resultAt8Hz.Error; - - if (Math.Abs(diff2Hz8Hz) > 2.5) return false; /// Difference of errors > 2.5 % ==> water meter failed - - hz2CorrectionFactor = -1 * (int)Math.Round(10 * diff2Hz8Hz); - - log.WarnFormat("2Hz correction: Pos={0}, PCB#={1}, corrFactor={2}, erro@2Hz={3}%, erro@8Hz={4}%", - Name, - SerialNr, - hz2CorrectionFactor, - resultAt2Hz.Error.ToString("F2"), - resultAt8Hz.Error.ToString("F2")); - - return true; - } /// @@ -703,147 +771,24 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader /// OptoState.Read or OptoState.Flush void ReadOptoData(DataStreamState optoState) { - if (optoSerialPort is null) return; - lock (this) - { - int nrBytes = optoSerialPort.BytesToRead; - if (nrBytes > 0) - { - char[] buffer = new char[nrBytes]; - optoSerialPort.Read(buffer, 0, nrBytes); - string received = new string(buffer); - - string allRcvd = partOfTelegram + received; - - while (true) - { - int pos = allRcvd.IndexOf("\r\n"); - - if (pos < 0) - { - /// No CR+LF found, wait for more characters in the next invocation - partOfTelegram = allRcvd; - return; - } - else - { - /// CR+LF found - if (optoState == DataStreamState.ProcessAndSave) - { - int bufferIx = BufferIdx(optoDataCount); - - if (pos < OptoTelegramRaw.Length - 2) - { - /// CR+LF found too early, truncate the beginning incl CR+LF and keep scanning in this loop - allRcvd = allRcvd.Substring(pos + 2); - if (synchronized) - { - optoData[bufferIx].Counter = optoDataCount; - optoData[bufferIx].SetFlags(OptoTelegramFlags.SyncError); - } - synchronized = true; - } - else if (optoData[bufferIx].UpdateFromString(allRcvd.Substring(pos - OptoTelegramRaw.Length + 2), - optoDataCount, - Convert.ToSingle(Sequences.ProcessData.RefFlow.Val), - ref volumeRawExtLast, ref timestampExtLast)) - { - /// CR+LF was found && (pos >= OptoTelegramRaw.Length - 2) && the telegram is OK - flowDirectionDetection.WriteToFifo(volumeRawExtLast, timestampExtLast); - OptoTelegramReceived(optoDataCount, synchronized2, volumeRawExtLast, timestampExtLast); - synchronized2 = synchronized; - allRcvd = allRcvd.Substring(pos + 2); - } - else - { - /// CR+LF was found && (pos >= OptoTelegramRaw.Length - 2) but the telgram was not OK - optoData[bufferIx].Counter = optoDataCount; - optoDataCount++; - allRcvd = allRcvd.Substring(pos + 2); - } - - optoDataCount++; - } - else /// optoState == OptoState.Flush - { - if (pos < OptoTelegramRaw.Length - 2) - { - /// CR+LF found too early, truncate the beginning incl CR+LF and keep scanning in this loop - allRcvd = allRcvd.Substring(pos + 2); - synchronized = true; - } - // CR+LF found and (pos >= OptoTelegram.Length - 2) - else if (toBeFlushed.UpdateFromString(allRcvd.Substring(pos - OptoTelegramRaw.Length + 2), - 0, - Convert.ToSingle(Sequences.ProcessData.RefFlow.Val), - ref volumeRawExtLast, ref timestampExtLast)) - { - flowDirectionDetection.WriteToFifo(volumeRawExtLast, timestampExtLast); - synchronized2 = synchronized; - allRcvd = allRcvd.Substring(pos + 2); - } - else - { - allRcvd = allRcvd.Substring(pos + 2); - } - } - } - } - - //OnOptoReceived(this, new OptoReceivedEventArgs(s)); - } - else - { - //OnOptoReceived(this, new OptoReceivedEventArgs(".")); - } - } + + // lock (this) + // { + // + // } } public string ReadOptoData() { - if (optoSerialPort is null) return ""; string received = "."; - lock (this) - { - int nrBytes = optoSerialPort.BytesToRead; - if (nrBytes > 0) - { - char[] buffer = new char[nrBytes]; - optoSerialPort.Read(buffer, 0, nrBytes); - received = new string(buffer); - } - } + // lock (this) + // { + // + // } return received; } - - void OptoTelegramReceived(int currentIx, bool async, Int64 volumeRawExt, Int64 timestampRawExt) - { - currentTelegramIx = currentIx; - - lastVolumeRaw = volumeRawExt; - lastTimestamp = timestampRawExt; - - if (volumeLtr == 0 && volumeLtr0 == 0) - { - volumeLtr = (double)lastVolumeRaw * ScalingFactor() / 16000.0; - volumeLtr0 = volumeLtr; - } - else - { - volumeLtr = (double)lastVolumeRaw * ScalingFactor() / 16000.0; - } - - if (timestampSec == 0 && timestampSec0 == 0) - { - timestampSec = (double)lastTimestamp / 8192.0; - timestampSec0 = timestampSec; - } - else - { - timestampSec = (double)lastTimestamp / 8192.0; - } - } + /// @@ -1002,12 +947,15 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader void ReadPulses() { - beginWMState = volumeLtr0; - endWMState = volumeLtr; + TimeSpan delta = _lastSampleTime - _firstSampleTime; + double volume = _averageFlow * (delta.TotalMilliseconds / 1000); + //log.Debug("ReadPulses - Calculated Value:" + volume); + beginWMState = 1; + endWMState = beginWMState + volume ; wmVolume = Math.Abs(endWMState - beginWMState); wmPulses = (int)(wmVolume * (double)PulsesPerLtr + 0.5); wmRefPulses = StateMachine.ControlBoardMain.RefPulses; - wmTestTime = timestampSec - timestampSec0; + wmTestTime = delta.TotalSeconds; } private void OpenOptoSerialPort(string comPort, int baudRate, Parity parity, int dataBits, StopBits stopBit, Handshake handshake) @@ -1018,6 +966,7 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader /// Open serial port: 9600 Bd, 8 data bits, 1 stop bit, no parity try { + CloseOptoSerialPort(); optoSerialPort = new SerialPort(comPort, baudRate, parity, dataBits, stopBit); optoSerialPort.Handshake = handshake; @@ -1039,12 +988,15 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader private void CloseOptoSerialPort() { - if (optoSerialPort != null) + if (_optoHeadService != null) { - optoSerialPort.Close(); - optoSerialPort = null; + _optoHeadService.CloseSerialConnection(); + _optoHeadService = null; log.FatalFormat($"{Name} OptoPort closed: {this}"); } + + + communication.OpticalHeadTest.SetActiveMode(_poseidonCfg); } @@ -1056,10 +1008,14 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader { try { - OpenOptoSerialPort($"COM{_poseidonCfg.OptoComPortNr}", 9600, Parity.None, 8, StopBits.One, Handshake.None); + //set test mode via the cli + communication.OpticalHeadTest.SetTestMode(_poseidonCfg); + //open opto serial port + OpenOptoConnection(_poseidonCfg); } - catch (Exception) + catch (Exception e) { + log.Error($"{Name} OptoPort - error opening port: {_poseidonCfg.OptoComPortNr}, Details: {e.Message}"); } /// Reset opto-data, etc. optoDataCount = 0; @@ -1482,8 +1438,7 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader volumeLtr = 0; volumeLtr0 = 0; - timestampSec = 0; - timestampSec0 = 0; + extraDataPath = null; diff --git a/TBF/Rig/RegisterReaders/PoseidonReader/communication/C7/NFCHeadServiceOld.cs b/TBF/Rig/RegisterReaders/PoseidonReader/communication/C7/NFCHeadServiceOld.cs index ff56942a9..886666289 100644 --- a/TBF/Rig/RegisterReaders/PoseidonReader/communication/C7/NFCHeadServiceOld.cs +++ b/TBF/Rig/RegisterReaders/PoseidonReader/communication/C7/NFCHeadServiceOld.cs @@ -2,6 +2,8 @@ using System; using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; +using log4net; +using TBF.Rig.Output.Printers.Label; using TBF.Rig.RegisterReaders.PoseidonReader.communication.C7.Utils; using CliRunner = TBF.Rig.RegisterReaders.PoseidonReader.communication.C7.Utils.CliRunnerOld; using OptoHeadStatus = TBF.Rig.RegisterReaders.PoseidonReader.communication.C7.Protocols.OptoHeadStatus; @@ -13,6 +15,7 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader.communication.C7 public class NfcHeadServiceOld { + private static readonly ILog log = LogManager.GetLogger(typeof(NfcHeadServiceOld)); private bool activeHandlerSessioEnabled = false; private CliRunner _cliRunner; @@ -208,7 +211,8 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader.communication.C7 } else { - throw new Exception($"Failed to parse OptoHeadStatus from output. Result: {result}"); + log.Error($"Failed to parse OptoHeadStatus from output. Result: {result}"); + //throw new Exception($"Failed to parse OptoHeadStatus from output. Result: {result}"); } } diff --git a/TBF/Rig/RegisterReaders/PoseidonReader/communication/C7/OptoHeadService.cs b/TBF/Rig/RegisterReaders/PoseidonReader/communication/C7/OptoHeadService.cs index e69ff2360..c3d56d35d 100644 --- a/TBF/Rig/RegisterReaders/PoseidonReader/communication/C7/OptoHeadService.cs +++ b/TBF/Rig/RegisterReaders/PoseidonReader/communication/C7/OptoHeadService.cs @@ -1,6 +1,10 @@ using System; using System.IO.Ports; using System.Threading.Tasks; +using Common; +using log4net; +using TBF.Rig.RegisterReaders.PoseidonReader.communication.C7.Protocols; +using TBF.Rig.Sequences; using SERIAL_Driver = TBF.Rig.RegisterReaders.PoseidonReader.communication.C7.Utils.SERIAL_Driver; using WaterMetrologyData = TBF.Rig.RegisterReaders.PoseidonReader.communication.C7.Protocols.WaterMetrologyData; @@ -8,9 +12,11 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader.communication.C7 { public class OptoHeadService { - + static readonly ILog log = LogManager.GetLogger("PoseidonConnection"); + public class Con { + public string com = "COM5"; public int baudrate = 38400; public int dataBits = 8; @@ -18,6 +24,8 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader.communication.C7 public StopBits stopbits = StopBits.Two; public int readTimeout = 5000; public int writeTimeout = 1000; + private DebugMode _debugLevel; + public DebugMode DebugModeSetting { get => _debugLevel; } public Con(string com, int baudrate, int dataBits, Parity parity, StopBits stopbits, int readTimeout, int writeTimeout) : this(com) @@ -29,10 +37,23 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader.communication.C7 this.readTimeout = readTimeout; this.writeTimeout = writeTimeout; } + + public Con(DebugMode debugLevel,string com, int baudrate, int dataBits, Parity parity, StopBits stopbits, int readTimeout, + int writeTimeout) : this(com) + { + this._debugLevel = debugLevel; + this.baudrate = baudrate; + this.dataBits = dataBits; + this.parity = parity; + this.stopbits = stopbits; + this.readTimeout = readTimeout; + this.writeTimeout = writeTimeout; + } - public Con(string com) + public Con(string com, DebugMode debugLevel = DebugMode.Normal) { this.com = com; + this._debugLevel = debugLevel; } } @@ -55,11 +76,19 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader.communication.C7 OnOptoReceivedHandler = null; bool isopen = false; Con con = Connection; + if (con == null) + { + return false; + } byte[] message = {0x00}; byte[] bytesReceived; - if (!driver.isOpen()) + if (con?.DebugModeSetting == DebugMode.Simulate) + { + isopen = true; + } + else if (!driver.isOpen()) { isopen = driver.OpenConnection( @@ -72,6 +101,8 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader.communication.C7 con.writeTimeout); } + _bRunStarted = false; + return isopen; } @@ -79,24 +110,39 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader.communication.C7 { dissableRunLoop = true; OnOptoReceivedHandler = null; - driver.Close(); - OnOptoReceivedHandler = null; + if (Connection?.DebugModeSetting != DebugMode.Simulate) + { + driver.Close(); + } + _bRunStarted = false; } private EventHandler OnOptoReceivedHandler; + + + public bool IsRunning + { + get { return !dissableRunLoop + && ((Connection?.DebugModeSetting != DebugMode.Simulate) ? driver.isOpen() : true) + && _bRunStarted;} + } + public void RunLoop(EventHandler onOptoReceivedHandler) { + log.Debug("RunLoop started on event!"); OnOptoReceivedHandler = onOptoReceivedHandler; Task.Run(() => Run()); } public void RunLoop() { + log.Debug("RunLoop started!"); Task.Run(() => Run()); } private bool dissableRunLoop = false; + private bool _bRunStarted = false; /// /// Run the service. Catch one communication to WaterMetrologyData field. /// @@ -104,10 +150,12 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader.communication.C7 { while (!dissableRunLoop) { + _bRunStarted = true; WaterMetrologyData = ParseData(RunReading()); if (OnOptoReceivedHandler != null && WaterMetrologyData != null) { - OnOptoReceivedHandler.Invoke(this, new CommonRR.IPerl.communication.OptoReceivedEventArgs(WaterMetrologyData.ToString())); + log.Debug($"Received OptoData: {WaterMetrologyData}"); + OnOptoReceivedHandler?.Invoke(this, new CommonRR.IPerl.communication.OptoReceivedEventArgs(WaterMetrologyData?.ToString(), WaterMetrologyData)); } } @@ -115,13 +163,20 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader.communication.C7 byte[] RunReading() { + if (Connection?.DebugModeSetting != DebugMode.Simulate) + { + return new byte[] {0x00}; + } if (driver.isOpen()) { driver.SendMessage(new byte[] {0x00}, 1); - return driver.GetRawData(); + byte[] rawData = driver.GetRawData(); + log.Debug($"Received data size: {rawData?.Length ?? 0} bytes, raw data: {(rawData==null? "" :BitConverter.ToString(rawData))}"); + return rawData; } else { + log.Debug("Serial port is not open."); dissableRunLoop = true; } @@ -130,6 +185,10 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader.communication.C7 public WaterMetrologyData ParseData(byte[] data) { + if (Connection?.DebugModeSetting != DebugMode.Simulate) + { + return WaterMetrologyData.SimulateC7(); + } try { if (data == null || data.Length == 0) diff --git a/TBF/Rig/RegisterReaders/PoseidonReader/communication/C7/Protocols/WaterMetrologyData.cs b/TBF/Rig/RegisterReaders/PoseidonReader/communication/C7/Protocols/WaterMetrologyData.cs index 6a3b58527..21e05ab45 100644 --- a/TBF/Rig/RegisterReaders/PoseidonReader/communication/C7/Protocols/WaterMetrologyData.cs +++ b/TBF/Rig/RegisterReaders/PoseidonReader/communication/C7/Protocols/WaterMetrologyData.cs @@ -37,6 +37,21 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader.communication.C7.Protocols return waterMetrologyData; } + public static WaterMetrologyData SimulateC7() + { + WaterMetrologyData waterMetrologyData = new WaterMetrologyData(); + waterMetrologyData.c7Data = WaterMetrologyDataC7.Simulate(); + return waterMetrologyData; + } + + public static WaterMetrologyData SimulateC2() + { + WaterMetrologyData waterMetrologyData = new WaterMetrologyData(); + waterMetrologyData.c2Data = WaterMetrologyDataC2.Simulate(); + return waterMetrologyData; + } + + public override string ToString() { return $"Status: {_optoHeadStatus}, C7Data: {c7Data}, C2Data: {c2Data}"; diff --git a/TBF/Rig/RegisterReaders/PoseidonReader/communication/C7/Protocols/WaterMetrologyDataC2.cs b/TBF/Rig/RegisterReaders/PoseidonReader/communication/C7/Protocols/WaterMetrologyDataC2.cs index fba8f3ca9..b5dcb9140 100644 --- a/TBF/Rig/RegisterReaders/PoseidonReader/communication/C7/Protocols/WaterMetrologyDataC2.cs +++ b/TBF/Rig/RegisterReaders/PoseidonReader/communication/C7/Protocols/WaterMetrologyDataC2.cs @@ -21,7 +21,17 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader.communication.C7.Protocols public bool FastHPFC { get; set; } public bool FieldPolarity { get; set; } public bool ImpedancePolarity { get; set; } - + + + public double FlowRateLPerS // Flow Rate in L/s metric units + { + get + { + double flowRateGPM = FlowRate / 10000; //investigation flow meter GPM + double flowRateLPerS = flowRateGPM * 0.063090196432096 ; // conversion factor from GPM to L/s with minimal digit lost + return flowRateLPerS; + } + } public double CalcFlowmLps { get { return FlowRate / 4.0; } // FlowRate is in 1/4 mL/s @@ -41,6 +51,32 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader.communication.C7.Protocols return Parse(data, dt, dutinfo); } + public static WaterMetrologyDataC2 Simulate() + { + var result = new WaterMetrologyDataC2(); + + result.DutInfo = "dutinfo"; + result.Dt = DateTime.Now; + result.AdcSample = 1; + result.LastField = 2; + result.FlowRate = 12456; + result.Accumulator = 789465; + result.FlipPeriod = 1; + result.VinfStart = 0; + result.VinfEnd = 0; + result.ElectrodeDelta = 1; + result.Impedance = 1; + result.FieldDriveTime = 0x00 ; + + result.IsInLowFlow = false; + result.IsInEmptyPipe = false; + result.FastHPFC = false; // Fast High Pass Filter Constant in bit 2 + result.FieldPolarity = false; // Field Polarity in bit 3 + result.ImpedancePolarity = false; // Impedance Polarity in bit 4 + + return result; + } + public static WaterMetrologyDataC2 Parse(byte[] data, DateTime dt, string dutinfo) { if (data.Length < 24) diff --git a/TBF/Rig/RegisterReaders/PoseidonReader/communication/C7/Protocols/WaterMetrologyDataC7.cs b/TBF/Rig/RegisterReaders/PoseidonReader/communication/C7/Protocols/WaterMetrologyDataC7.cs index e6dd542ff..9fd40c552 100644 --- a/TBF/Rig/RegisterReaders/PoseidonReader/communication/C7/Protocols/WaterMetrologyDataC7.cs +++ b/TBF/Rig/RegisterReaders/PoseidonReader/communication/C7/Protocols/WaterMetrologyDataC7.cs @@ -23,6 +23,47 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader.communication.C7.Protocols public bool IsLearningActive { get; set; } public bool AdcShiftsUpdated { get; set; } + public static WaterMetrologyDataC7 Simulate() + { + var result = new WaterMetrologyDataC7(); + + result.DutInfo = "dutinfo"; + result.Dt = DateTime.Now; + result.AdcSample = 1; + result.LastField = 2; + result.FlowRate = 12456; + result.Accumulator = 789465; + result.FlipPeriod = 1; + result.VinfStart = 0; + result.VinfEnd = 0; + result.ElectrodeDelta = 1; + result.Impedance = 1; + result.FieldDriveTime = 0x00 ; + + result.IsInLowFlow = false; + result.IsInEmptyPipe = false; + result.FastHPFC = false; // Fast High Pass Filter Constant in bit 2 + result.FieldPolarity = false; // Field Polarity in bit 3 + result.ImpedancePolarity = false; // Impedance Polarity in bit 4 + + result.MagTamperState = true; // bits 5 and 6 represent MagTamperState + result.IsLearningActive = true; // bit 7 represents IsLearningActive + + + + result.AdcShiftsUpdated = false; // bit 0 represents AdcShiftsUpdated + + result.LastFieldmilliGauss = 0; + result.ImpedanceI = 0; // in phase + result.ImpedanceQ = 0; // out of phase + result.NoiseMetric = 0; // + result.LearningLockout = 0; + result.ReverseBuffer = 0; + result.ConditionedAdc = 0; + result.Totalalizer = 0; + + return result; + } public static WaterMetrologyDataC7 Parse(string base64Data, DateTime dt, string dutinfo) { diff --git a/TBF/Rig/RegisterReaders/PoseidonReader/communication/ECommunicationInterface.cs b/TBF/Rig/RegisterReaders/PoseidonReader/communication/ECommunicationInterface.cs index cab86e8a0..3b83f8dac 100644 --- a/TBF/Rig/RegisterReaders/PoseidonReader/communication/ECommunicationInterface.cs +++ b/TBF/Rig/RegisterReaders/PoseidonReader/communication/ECommunicationInterface.cs @@ -6,6 +6,6 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader.communication { [Description("..")] None, [Description("Nfc")] Nfc, - [Description("Touch Capl")]Touched, + [Description("cTouchRead")]Touched, } } \ No newline at end of file diff --git a/TBF/Rig/RegisterReaders/PoseidonReader/communication/OpticalHeadTest.cs b/TBF/Rig/RegisterReaders/PoseidonReader/communication/OpticalHeadTest.cs index 35f5e234a..a7440dd22 100644 --- a/TBF/Rig/RegisterReaders/PoseidonReader/communication/OpticalHeadTest.cs +++ b/TBF/Rig/RegisterReaders/PoseidonReader/communication/OpticalHeadTest.cs @@ -17,6 +17,9 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader.communication internal class OpticalHeadTest { protected static readonly ILog rfidDataLogger = LogManager.GetLogger("RfidData"); + + DebugMode _debugMode; + public DebugMode DebugMode { get => _debugMode; set => _debugMode = value; } internal static string OpenSealing(ISmartReader iHead) { @@ -26,6 +29,11 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader.communication internal static string ReadRequest_SerialNo(PoseidonCfg iHeadCfg) { + if (iHeadCfg != null && iHeadCfg.DebugLevel == DebugMode.Simulate) + { + return "1111"; + } + string serialNo = null; try { @@ -77,6 +85,11 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader.communication internal static string SetActiveMode(PoseidonCfg iHeadCfg) { + if (iHeadCfg != null && iHeadCfg.DebugLevel == DebugMode.Simulate) + { + return "OK"; + } + SerialPortData serialPortData = new SerialPortData( $"COM{iHeadCfg.RfidComPortNr}", iHeadCfg.CliProgramName, @@ -100,6 +113,11 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader.communication internal static string SetTestMode(PoseidonCfg iHeadCfg) { + if (iHeadCfg != null && iHeadCfg.DebugLevel == DebugMode.Simulate) + { + return "OK"; + } + SerialPortData serialPortData = new SerialPortData( $"COM{iHeadCfg.RfidComPortNr}", iHeadCfg.CliProgramName, @@ -123,6 +141,10 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader.communication public static void Deactivate() { + if (_lastIHeadCfg != null && _lastIHeadCfg.DebugLevel == DebugMode.Simulate) + { + return; + } StopOptoTestInputLoop(); if (_lastOptoHeadStatus != OptoHeadStatus.Unknown && _lastOptoHeadStatus != OptoHeadStatus.OptoHeadDisabled && @@ -142,7 +164,7 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader.communication { if (optoHeadService != null) return false; - OptoHeadService.Con connection = new OptoHeadService.Con($"COM{iHeadCfg.OptoComPortNr}"); + OptoHeadService.Con connection = new OptoHeadService.Con($"COM{iHeadCfg.OptoComPortNr}", iHeadCfg.DebugLevel); optoHeadService = new OptoHeadService(connection); optoHeadService.CreateSerialConnection(); optoHeadService.RunLoop(onOptoReceivedHandler); diff --git a/TBF/Rig/Sequences/MainSeq.cs b/TBF/Rig/Sequences/MainSeq.cs index b71692d16..1ae3f8e76 100644 --- a/TBF/Rig/Sequences/MainSeq.cs +++ b/TBF/Rig/Sequences/MainSeq.cs @@ -57,7 +57,11 @@ namespace TBF.Rig.Sequences try { /// 1nd argument - ITestMethodCfg iPerlCfgIPerl = cfg as ITestMethodCfg; + ITestMethodCfg testMethodCfg = cfg as ITestMethodCfg; + if (testMethodCfg == null) + { + + } /// 2rd argument: as is @@ -68,8 +72,7 @@ namespace TBF.Rig.Sequences /*myRef.modelessDlg = new TestMethods.iPerlCommunication.iPerlCommunicationForm(iPerlCfg, tests, iPerlCommParams); myRef.modelessDlg.Show();*/ - myRef.modelessDlg = new SmartCommunicationForm( - testMethod , tests, iPerlCommParams); + myRef.modelessDlg = new SmartCommunicationForm( testMethod , tests, iPerlCommParams); myRef.modelessDlg.Show(); } catch (Exception e) diff --git a/TBF/Rig/Uni/SharedDialogs/SmartMetersCommunication/ISmartTestMethod.cs b/TBF/Rig/Uni/SharedDialogs/SmartMetersCommunication/ISmartTestMethod.cs index 46852421e..393493ab9 100644 --- a/TBF/Rig/Uni/SharedDialogs/SmartMetersCommunication/ISmartTestMethod.cs +++ b/TBF/Rig/Uni/SharedDialogs/SmartMetersCommunication/ISmartTestMethod.cs @@ -1,10 +1,16 @@ +using TBF.Rig.Configs.NameOnly; +using TBF.Rig.Generic; +using TBF.Rig.RegisterReaders.CommonRR.IPerl; + namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication { public interface ISmartTestMethod { public void MeterCommMilestone(int iItem, bool bValue); public bool IsMeterCommMilestone(int iItem); + + public ITestMethodCfg TestMethodCfg { get; } } } \ No newline at end of file diff --git a/TBF/Rig/Uni/SharedDialogs/SmartMetersCommunication/SmartCommunicationForm.cs b/TBF/Rig/Uni/SharedDialogs/SmartMetersCommunication/SmartCommunicationForm.cs index a355491f4..3c2147c35 100644 --- a/TBF/Rig/Uni/SharedDialogs/SmartMetersCommunication/SmartCommunicationForm.cs +++ b/TBF/Rig/Uni/SharedDialogs/SmartMetersCommunication/SmartCommunicationForm.cs @@ -135,7 +135,7 @@ namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication public static string SelectedTypeReader { get; set; } private List GetNewCorrectionList(ISmartTestMethod componentBase , - TestMethodCfg cfg, IList tests, IList multiTestParams) + ITestMethodCfg cfg, IList tests, IList multiTestParams) { List correctionsList = new List(); @@ -154,7 +154,7 @@ namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication { if (correctionsList.Any(x => x is SmartReader)) continue; - correctionsList.Add(new PoseidonCorrections(this)); + correctionsList.Add(new PoseidonCorrections(this,log, rfidDataLogger, componentBase, cfg, tests, multiTestParams)); continue; } @@ -297,7 +297,7 @@ namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication ShuffleTextBoxes(ProcessData.WMsCount, ProcessData.LineSize); - this.ContextMenu = Correction.GetContextMenu(); + //this.ContextMenu = Correction.GetContextMenu(); } @@ -325,9 +325,11 @@ namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication { checkBoxesEditMode = false; + ITestMethodCfg cfg = (componentBase as ITestMethodCfg); + ISmartTestMethod smartTestMethod = componentBase as ISmartTestMethod; + //TODO get corrections based on defined meter - _corrections = GetNewCorrectionList(componentBase as ISmartTestMethod, - componentBase.Cfg as TestMethodCfg, tests, multiTestParams); + _corrections = GetNewCorrectionList(smartTestMethod, smartTestMethod.TestMethodCfg, tests, multiTestParams); InitializeMeterTypeItems(); UpdateHeads(); @@ -381,6 +383,27 @@ namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication private void UpdateHeads() { + if (!(waterMeterPositions0 == null || waterMeterPositions0.Count <= 0) + && labels != null && counters != null && messages != null && checkBoxes != null) + { + foreach (int position in waterMeterPositions0) + { + try + { + labels[position].Visible = false; + counters[position].Visible = false; + messages[position].Visible = false; + checkBoxes[position].Visible = false; + ckbIndex[position] = 0; + ckbState[position] = false; + } + catch (Exception e) + { + log.Error("UpdateHeads()", e); + } + } + } + iperlHeads?.Clear(); if (iperlHeads == null) iperlHeads = new List(); waterMeterPositions0?.Clear(); @@ -415,6 +438,21 @@ namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication if (wmPos >= ProcessData.WMsCount) break; } } + + + //we have items from the list, so we can enable the rows + if (iperlHeads.Count > 0) + { + WaterMetersCount = iperlHeads.Count; + ShuffleTextBoxes(WaterMetersCount, ProcessData.LineSize); + + this.ContextMenu = Correction.GetContextMenu(); + Correction.PrepareForTestsActivities(WaterMetersCount); + } + else + { + this.ContextMenu = null; + } } } @@ -458,6 +496,7 @@ namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication /// this part works fine if we are on test loop /// - because ProcessData.RegisterReaders is initialized in test loop /// + /// private static void InitializeSmartReaderLists() { iperlHeads = new List(); @@ -501,43 +540,7 @@ namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication /// Number of watermeters in one line void ShuffleTextBoxes(int wmsCount, int lineSize) { - labels = new Label[MaxTextBoxesCount] - { - wmLabel1, wmLabel2, wmLabel3, wmLabel4, wmLabel5, wmLabel6, wmLabel7, wmLabel8, wmLabel9, wmLabel10, - wmLabel11, wmLabel12, wmLabel13, wmLabel14, wmLabel15, wmLabel16, wmLabel17, wmLabel18, wmLabel19, wmLabel20, - wmLabel21, wmLabel22, wmLabel23, wmLabel24, wmLabel25, wmLabel26, wmLabel27, wmLabel28, wmLabel29, wmLabel30, - wmLabel31, wmLabel32, wmLabel33, wmLabel34, wmLabel35, wmLabel36, wmLabel37, wmLabel38, wmLabel39, wmLabel40, - wmLabel41, wmLabel42, wmLabel43, wmLabel44, wmLabel45, wmLabel46, wmLabel47, wmLabel48, - }; - counters = new PictureBox[MaxTextBoxesCount] - { - pictureBox1, pictureBox2, pictureBox3, pictureBox4, pictureBox5, pictureBox6, pictureBox7, pictureBox8, pictureBox9, pictureBox10, - pictureBox11, pictureBox12, pictureBox13, pictureBox14, pictureBox15, pictureBox16, pictureBox17, pictureBox18, pictureBox19, pictureBox20, - pictureBox21, pictureBox22, pictureBox23, pictureBox24, pictureBox25, pictureBox26, pictureBox27, pictureBox28, pictureBox29, pictureBox30, - pictureBox31, pictureBox32, pictureBox33, pictureBox34, pictureBox35, pictureBox36, pictureBox37, pictureBox38, pictureBox39, pictureBox40, - pictureBox41, pictureBox42, pictureBox43, pictureBox44, pictureBox45, pictureBox46, pictureBox47, pictureBox48, - }; - messages = new TextBox[MaxTextBoxesCount] - { - wmTextBox1, wmTextBox2, wmTextBox3, wmTextBox4, wmTextBox5, wmTextBox6, wmTextBox7, wmTextBox8, wmTextBox9, wmTextBox10, - wmTextBox11, wmTextBox12, wmTextBox13, wmTextBox14, wmTextBox15, wmTextBox16, wmTextBox17, wmTextBox18, wmTextBox19, wmTextBox20, - wmTextBox21, wmTextBox22, wmTextBox23, wmTextBox24, wmTextBox25, wmTextBox26, wmTextBox27, wmTextBox28, wmTextBox29, wmTextBox30, - wmTextBox31, wmTextBox32, wmTextBox33, wmTextBox34, wmTextBox35, wmTextBox36, wmTextBox37, wmTextBox38, wmTextBox39, wmTextBox40, - wmTextBox41, wmTextBox42, wmTextBox43, wmTextBox44, wmTextBox45, wmTextBox46, wmTextBox47, wmTextBox48, - }; - checkBoxes = new CheckBoxImage[MaxTextBoxesCount] - { - checkBoxImage1, checkBoxImage2, checkBoxImage3, checkBoxImage4, checkBoxImage5, checkBoxImage6, checkBoxImage7, checkBoxImage8, checkBoxImage9, checkBoxImage10, - checkBoxImage11, checkBoxImage12, checkBoxImage13, checkBoxImage14, checkBoxImage15, checkBoxImage16, checkBoxImage17, checkBoxImage18, checkBoxImage19, checkBoxImage20, - checkBoxImage21, checkBoxImage22, checkBoxImage23, checkBoxImage24, checkBoxImage25, checkBoxImage26, checkBoxImage27, checkBoxImage28, checkBoxImage29, checkBoxImage30, - checkBoxImage31, checkBoxImage32, checkBoxImage33, checkBoxImage34, checkBoxImage35, checkBoxImage36, checkBoxImage37, checkBoxImage38, checkBoxImage39, checkBoxImage40, - checkBoxImage41, checkBoxImage42, checkBoxImage43, checkBoxImage44, checkBoxImage45, checkBoxImage46, checkBoxImage47, checkBoxImage48, - }; - ckbIndex = new int[MaxTextBoxesCount]; - ckbState = new bool[MaxTextBoxesCount]; - - - textBoxesCount = MaxTextBoxesCount; + InitializeTextBoxArrays(); /// if (wmsCount < textBoxesCount && lineSize > 0) { @@ -576,7 +579,56 @@ namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication ResizeDlgToFitEnabledControls(); } - void ResizeDlgToFitEnabledControls() + private void InitializeTextBoxArrays() + { + //if is initialized before we ignore initialization + if (labels != null + && counters != null + && messages != null + && checkBoxes != null + && ckbIndex != null + && ckbState != null) return; + + labels = new Label[MaxTextBoxesCount] + { + wmLabel1, wmLabel2, wmLabel3, wmLabel4, wmLabel5, wmLabel6, wmLabel7, wmLabel8, wmLabel9, wmLabel10, + wmLabel11, wmLabel12, wmLabel13, wmLabel14, wmLabel15, wmLabel16, wmLabel17, wmLabel18, wmLabel19, wmLabel20, + wmLabel21, wmLabel22, wmLabel23, wmLabel24, wmLabel25, wmLabel26, wmLabel27, wmLabel28, wmLabel29, wmLabel30, + wmLabel31, wmLabel32, wmLabel33, wmLabel34, wmLabel35, wmLabel36, wmLabel37, wmLabel38, wmLabel39, wmLabel40, + wmLabel41, wmLabel42, wmLabel43, wmLabel44, wmLabel45, wmLabel46, wmLabel47, wmLabel48, + }; + counters = new PictureBox[MaxTextBoxesCount] + { + pictureBox1, pictureBox2, pictureBox3, pictureBox4, pictureBox5, pictureBox6, pictureBox7, pictureBox8, pictureBox9, pictureBox10, + pictureBox11, pictureBox12, pictureBox13, pictureBox14, pictureBox15, pictureBox16, pictureBox17, pictureBox18, pictureBox19, pictureBox20, + pictureBox21, pictureBox22, pictureBox23, pictureBox24, pictureBox25, pictureBox26, pictureBox27, pictureBox28, pictureBox29, pictureBox30, + pictureBox31, pictureBox32, pictureBox33, pictureBox34, pictureBox35, pictureBox36, pictureBox37, pictureBox38, pictureBox39, pictureBox40, + pictureBox41, pictureBox42, pictureBox43, pictureBox44, pictureBox45, pictureBox46, pictureBox47, pictureBox48, + }; + messages = new TextBox[MaxTextBoxesCount] + { + wmTextBox1, wmTextBox2, wmTextBox3, wmTextBox4, wmTextBox5, wmTextBox6, wmTextBox7, wmTextBox8, wmTextBox9, wmTextBox10, + wmTextBox11, wmTextBox12, wmTextBox13, wmTextBox14, wmTextBox15, wmTextBox16, wmTextBox17, wmTextBox18, wmTextBox19, wmTextBox20, + wmTextBox21, wmTextBox22, wmTextBox23, wmTextBox24, wmTextBox25, wmTextBox26, wmTextBox27, wmTextBox28, wmTextBox29, wmTextBox30, + wmTextBox31, wmTextBox32, wmTextBox33, wmTextBox34, wmTextBox35, wmTextBox36, wmTextBox37, wmTextBox38, wmTextBox39, wmTextBox40, + wmTextBox41, wmTextBox42, wmTextBox43, wmTextBox44, wmTextBox45, wmTextBox46, wmTextBox47, wmTextBox48, + }; + checkBoxes = new CheckBoxImage[MaxTextBoxesCount] + { + checkBoxImage1, checkBoxImage2, checkBoxImage3, checkBoxImage4, checkBoxImage5, checkBoxImage6, checkBoxImage7, checkBoxImage8, checkBoxImage9, checkBoxImage10, + checkBoxImage11, checkBoxImage12, checkBoxImage13, checkBoxImage14, checkBoxImage15, checkBoxImage16, checkBoxImage17, checkBoxImage18, checkBoxImage19, checkBoxImage20, + checkBoxImage21, checkBoxImage22, checkBoxImage23, checkBoxImage24, checkBoxImage25, checkBoxImage26, checkBoxImage27, checkBoxImage28, checkBoxImage29, checkBoxImage30, + checkBoxImage31, checkBoxImage32, checkBoxImage33, checkBoxImage34, checkBoxImage35, checkBoxImage36, checkBoxImage37, checkBoxImage38, checkBoxImage39, checkBoxImage40, + checkBoxImage41, checkBoxImage42, checkBoxImage43, checkBoxImage44, checkBoxImage45, checkBoxImage46, checkBoxImage47, checkBoxImage48, + }; + ckbIndex = new int[MaxTextBoxesCount]; + ckbState = new bool[MaxTextBoxesCount]; + + + textBoxesCount = MaxTextBoxesCount; + } + + void ResizeDlgToFitEnabledControls() { int xMax = 0; int yMax = 0; @@ -645,7 +697,7 @@ namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication } /// Start communication process by incrementing 'currentGroup'. - currentGroup++; + //currentGroup++; int wtId = 0; foreach (var wt in Correction.GetAllThreads()) @@ -869,6 +921,7 @@ namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication if (senderCombo == null) return; SelectedTypeReader = senderCombo.SelectedItem?.ToString(); UpdateHeads(); + SmartCommunicationForm_Load(this, EventArgs.Empty); } } } diff --git a/TBF/Rig/Uni/SharedDialogs/SmartMetersCommunication/SmartComponentBase.cs b/TBF/Rig/Uni/SharedDialogs/SmartMetersCommunication/SmartComponentBase.cs index b14b925b1..a437847c3 100644 --- a/TBF/Rig/Uni/SharedDialogs/SmartMetersCommunication/SmartComponentBase.cs +++ b/TBF/Rig/Uni/SharedDialogs/SmartMetersCommunication/SmartComponentBase.cs @@ -1,21 +1,28 @@ +using TBF.Rig.Configs.NameOnly; using TBF.Rig.Generic; +using TBF.Rig.RegisterReaders.CommonRR.IPerl; namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication { public abstract class SmartComponentBase : ComponentBase, ISmartTestMethod { + private ITestMethodCfg cfg; + public abstract void MeterCommMilestone(int iItem, bool bValue); public abstract bool IsMeterCommMilestone(int iItem); - + public ITestMethodCfg TestMethodCfg { get => cfg; } + public SmartComponentBase() : base() { + cfg = null; } public SmartComponentBase(IComponentCfg cfg) : base(cfg) { + this.cfg = cfg as ITestMethodCfg; } } } \ No newline at end of file diff --git a/TBF/Rig/Uni/SharedDialogs/SmartMetersCommunication/implementations/EnumExtensions.cs b/TBF/Rig/Uni/SharedDialogs/SmartMetersCommunication/implementations/EnumExtensions.cs new file mode 100644 index 000000000..3dcab96a7 --- /dev/null +++ b/TBF/Rig/Uni/SharedDialogs/SmartMetersCommunication/implementations/EnumExtensions.cs @@ -0,0 +1,30 @@ +using System; +using System.ComponentModel; + +namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.implementations +{ + public static class EnumExtensions + { + public static bool TryParseByDescription(string description, out TEnum result) + where TEnum : struct, Enum + { + foreach (var field in typeof(TEnum).GetFields()) + { + var attribute = Attribute.GetCustomAttribute(field, + typeof(DescriptionAttribute)) as DescriptionAttribute; + + if ((attribute != null && attribute.Description == description) || + field.Name == description) + { + result = (TEnum)field.GetValue(null); + return true; + } + } + + result = default; + return false; + } + + + } +} \ No newline at end of file diff --git a/TBF/Rig/Uni/SharedDialogs/SmartMetersCommunication/implementations/PoseidonCorrections.cs b/TBF/Rig/Uni/SharedDialogs/SmartMetersCommunication/implementations/PoseidonCorrections.cs index 41a08c0d3..5ec3477f8 100644 --- a/TBF/Rig/Uni/SharedDialogs/SmartMetersCommunication/implementations/PoseidonCorrections.cs +++ b/TBF/Rig/Uni/SharedDialogs/SmartMetersCommunication/implementations/PoseidonCorrections.cs @@ -1,19 +1,28 @@ using System; using System.Collections.Generic; +using System.ComponentModel; +using System.Globalization; using System.Linq; +using System.Reflection; using System.Threading; +using System.Threading.Tasks; using System.Windows.Forms; +using Common; using Config.Entities; using log4net; using Results.Entities; using TBF.Rig.Generic; using TBF.Rig.RegisterReaders.CommonRR.IPerl; -using TBF.Rig.RegisterReaders.PoseidonCmdStartStop; using TBF.Rig.RegisterReaders.PoseidonReader; +using TBF.Rig.RegisterReaders.PoseidonReader.communication; +using TBF.Rig.RegisterReaders.PoseidonReader.implementations; +using TBF.Rig.Sequences; +using TBF.Rig.TestMethods.iPerlCommunication.iPerlHead; using TBF.Rig.TestMethods.SmartTest; using TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.common; using CheckBoxImage = TBF.Boxes.CheckBoxImage; using Factory = TBF.Rig.RegisterReaders.iPerlReaderUNI.Factory; +using PoseidonReader = TBF.Rig.RegisterReaders.PoseidonCmdStartStop.PoseidonReader; namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.implementations { @@ -32,6 +41,16 @@ namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.implementations private IList tests; private IList multiTestParams; private SmartCommunicationForm _parentFrom; + + static IList workerThreads; + static bool stopWorkerThreads; + static int currentActivityStep; + static int currentGroup; + + /// form -> worker thread (0 = none) + static int lastGroup; + + static int completedCommCount; public string TypeIdentificatorName() @@ -56,12 +75,122 @@ namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.implementations public IList iperlHeads { get => ParentFrom.Heads;} + private Label activityLabel { get => ParentFrom?.ActivityLabel;} + private Label[] labels { get => ParentFrom?.Labels; } + private PictureBox[] counters{get => ParentFrom?.Counters;} + private TextBox[] messages{get => ParentFrom?.Messages;} + private CheckBoxImage[] checkBoxes{get => ParentFrom?.CheckBoxes;} + private int[] ckbIndex{get => ParentFrom?.CkbIndex;} + private bool[] ckbState{get => ParentFrom?.CkbState;} + public void Worker(object threadData) { - throw new NotImplementedException(); + int threadID = (threadData as Boxes.IntBox)?.Val ?? -1; + + int activityStep = 0; /// activity step > 0 in case multiTestParams are used + + for (int iMultiTestParamsItem = 0; iMultiTestParamsItem < MultiTestParams.Count; iMultiTestParamsItem++) + { + Test currentTest = Tests[iMultiTestParamsItem]; + ITestParams currentTestParams = MultiTestParams[iMultiTestParamsItem]; + string currentActivity = currentTestParams.Activity; /// Current activity + + TBF.UiBridge.TestProgressEventArgs.SetEstimatedTimes(new int[] { 0, 0, 10, 0, 140, 0, 0, 0 }); + TBF.UiBridge.Bridge.OnTestProgress(null, + new TBF.UiBridge.TestProgressEventArgs(currentTest, Progress.JustStarted)); + + + if (threadID == 0) + { + StartDataStreamProcessingForActiveMeters(iMultiTestParamsItem); + + /// A new activity starts - information into RFID data log + rfidDataLogger.InfoFormat(""); + rfidDataLogger.WarnFormat("Activity = {0}", currentActivity); + rfidDataLogger.InfoFormat(""); + } + + for (int group = 1; group <= lastGroup; group++) + { + /// Synchronize with QuidoRS and other threads + while (((group != currentGroup) || (activityStep != currentActivityStep)) && + !GetStopWorkerThreads()) + { + Thread.Sleep(50); + } + + if (GetStopWorkerThreads()) break; + +// #if TURA_SPECIAL + int threadIx = threadID; /// Just one thread for TURA_SPECIAL +// #else +// for (int threadIx = threadID; threadIx < threadID + 4; threadIx += Cfg.NrThreads) +// #endif + { + bool wmFound = false; + + for (int wmNr0 = 0; wmNr0 < iperlHeads.Count; wmNr0++) + { + //TODO BUMI doplnit if podomienky - last grop je teraz 1 ak existuju readre + if(iperlHeads[wmNr0] is SmartReader ihead) + // if ((ihead.Group == group) && (threadIx < muxBrdOrGroup14Nrs.Count) && + // (ihead.MuxBoardNrOrGroup14 == muxBrdOrGroup14Nrs[threadIx])) + { + wmFound = true; + + WaterMeter wm = null; + if (ProcessData.BatchRslts.Batch.WaterMeters != null) + { + foreach (var w in ProcessData.BatchRslts.Batch.WaterMeters) + { + if (w.WMPosition == wmNr0 + 1) + { + wm = w; + break; + } + } + } + + //Do worker activity + CommErr error = CommErr.None; + string resultStr = string.Empty; + + + WorkerActivity(currentActivity, ihead, wm, currentTest, + wmNr0, ref error, ref resultStr, ckbState, threadID, currentActivityStep); + ProcessResultOfWorkerActivity(iMultiTestParamsItem, currentActivity, + currentGroup, ihead, wm, wmNr0, error, resultStr, ckbState, threadID); + + break; + } + + TBF.UiBridge.Bridge.OnTestProgress(null, + new TBF.UiBridge.TestProgressEventArgs(Tests[iMultiTestParamsItem], + Progress.FlowSetting)); + } + + if (!wmFound) + { + SmartCommunicationForm.OnCommCompleted(null, + new CommCompletedEventArgs(threadID, -1, null, null, string.Empty, + CommErr.None)); /// Send negative wmNr + } + + if (GetStopWorkerThreads()) break; + } + + if (GetStopWorkerThreads()) break; + } /// for (int group + + TBF.UiBridge.Bridge.OnTestProgress(null, + new TBF.UiBridge.TestProgressEventArgs(Tests[iMultiTestParamsItem], Progress.Completed)); + activityStep++; + + if (GetStopWorkerThreads()) break; + } } public bool WorkerActivity(string currentActivity, ISmartReader iHead, WaterMeter wm, Test currentTest, int wmNr0, @@ -78,17 +207,17 @@ namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.implementations public void StopWorkerThreads(bool bStopAllThreads) { - throw new NotImplementedException(); + stopWorkerThreads = bStopAllThreads; } public bool GetStopWorkerThreads() { - throw new NotImplementedException(); + return stopWorkerThreads; } public IList GetAllThreads() { - throw new NotImplementedException(); + return workerThreads; } public ICorrections GetNewCorrection() @@ -100,37 +229,229 @@ namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.implementations { throw new NotImplementedException(); } - - public ContextMenu GetContextMenu() - { - throw new NotImplementedException(); - } + public void PrepareForTestsActivities( int waterMeterPositions0) { - throw new NotImplementedException(); + StartTime = DateTime.Now; + StartTimeSec = StateMachine.Time; + + /// + /// Prepare worker threads, 'rfidPortNrs', 'lastGroup', etc.. + /// + currentActivityStep = 0; + currentGroup = 0; + completedCommCount = 0; + stopWorkerThreads = false; + lastGroup = 0; + + if (iperlHeads != null) + { + foreach (var iSmartReader in iperlHeads) + { + try + { + if (iSmartReader is SmartReader reader){ + if (reader != null ) lastGroup = 1; + } + } + catch (Exception E) + { + log.ErrorFormat("PrepareForTestsActivities: {0}", E.Message); + } + } + } + + workerThreads = new List(); + if (Cfg != null) + { + for (int i = 0; i < Cfg.NrThreads; i++) + { + Thread thread = new Thread(Worker); + thread.CurrentCulture = CultureInfo.CurrentCulture; + thread.CurrentUICulture = CultureInfo.CurrentUICulture; + workerThreads.Add(thread); + } + } } public void Load(Label[] labels, PictureBox[] counters, TextBox[] messages, CheckBoxImage[] checkBoxes, int[] ckbIndex, bool[] ckbState, IList iperlHeads, int textBoxesCount, bool checkBoxesEditMode) { - throw new NotImplementedException(); + if (iperlHeads == null) + { + for (int i = 0; i < textBoxesCount; i++) + { + checkBoxes[i].Enabled = checkBoxes[i].Checked = ckbState[i] = true; + messages[i].Text = "---"; + } + + return; + } + /// + /// Set checkbox states accroding to iPerlHeads[i].Disabled states + /// + for (int i = 0; i < textBoxesCount; i++) + { + labels[i].Visible = counters[i].Visible = messages[i].Visible = checkBoxes[i].Visible = true; + + + ISmartReader iperlHead = iperlHeads[i]; + if (!checkBoxesEditMode && (iperlHead == null || iperlHead.Disabled)) + { + /// iPerl position i+1 is disabled + checkBoxes[i].Enabled = checkBoxes[i].Checked = ckbState[i] = false; + counters[i].BackColor = iPerlCommunicationConstants.DisabledColor; + messages[i].Text = "Strings.Head_was_disabled_by_the_user"; + } + else + { + /// iPerl position i+1 is enabled + checkBoxes[i].Enabled = checkBoxes[i].Checked = ckbState[i] = true; + messages[i].Text = "---"; + } + } } public int GetHeadsCount() { - throw new NotImplementedException(); + return ParentFrom?.Heads?.Count() ?? 0; } public void StartDataStreamProcessingForActiveMeters(int iMultiTestParamsItem) { - throw new NotImplementedException(); + /// Check whether previous activity was 'Set test mode A0' or 'A4' + if (iMultiTestParamsItem > 0 && + MultiTestParams[iMultiTestParamsItem - 1].Activity.ToLower() + .Contains(iPerlCommunicationConstants.SetTestModeStr.ToLower()) && + !MultiTestParams[iMultiTestParamsItem - 1].Activity.Contains("80")) + { + /// Start processing of opto-datastreams from all iPERL-s + int count = 0; + for (int wmNr0 = 0; wmNr0 < iperlHeads.Count; wmNr0++) + { + WaterMeter wm = (ProcessData.BatchRslts.Batch.WaterMeters != null && + ProcessData.BatchRslts.Batch.WaterMeters.Count > wmNr0) + ? ProcessData.BatchRslts.Batch.WaterMeters[wmNr0] + : null; + + ISmartReader ihead = iperlHeads[wmNr0]; + + if (ihead != null && wm != null && !wm.Disabled) + { + lock (ihead) + { + ihead.StartDataStreamProcessing(); + count++; + } + } + } + + log.WarnFormat("End of activity '{0}', StartDataStreamProcessing() of {1} heads was called.", + MultiTestParams[iMultiTestParamsItem - 1].Activity, count); + } } public void DoOnCommCompleted(object sender, CommCompletedEventArgs data, IList waterMeterPositions0) { - throw new NotImplementedException(); + try + { + /// + /// Update the text message + /// + if (data.WMNr0 >= 0) messages[data.WMNr0].Text = data.CommMessage; + + /// + /// Update head active/inactive switch + /// + if (data.WMNr0 >= 0 && data.CommErr == CommErr.HeadDisabledByUser) + { + /// iPerl head was disabled by the user + ckbState[data.WMNr0] = false; + checkBoxes[data.WMNr0].Checked = false; + checkBoxes[data.WMNr0].Enabled = false; + if (data.Ihead != null) data.Ihead.Disabled = true; + if (data.Wm != null) data.Wm.Disabled = true; + } + else if (data.WMNr0 >= 0 && data.CommErr == CommErr.None) + { + /// One RFID communication successful => iPerl cannot be disabled by the user anymore + ckbState[data.WMNr0] = true; + checkBoxes[data.WMNr0].Checked = true; + checkBoxes[data.WMNr0].Enabled = false; + } + + /// + /// Update opto-communication indication + /// + for (int i = 0; i < iperlHeads.Count; i++) + { + if (iperlHeads[i] == null || iperlHeads[i].Disabled) + { + counters[i].BackColor = iPerlCommunicationConstants.DisabledColor; + } + else + { + if (iperlHeads[i] is SmartReader iperlHead) + { + + OptoHeadState checkFlowDirection = + ((iperlHead == null) ? OptoHeadState.Disabled : iperlHead.CheckFlowDirection()); + switch (checkFlowDirection) + { + case OptoHeadState.OptoAndDirOK: + counters[i].BackColor = iPerlCommunicationConstants.OptoAndDirOKColor; + break; + + case OptoHeadState.DirNok: + counters[i].BackColor = iPerlCommunicationConstants.DirNokColor; + break; + + default: + case OptoHeadState.OptoNok: + counters[i].BackColor = iPerlCommunicationConstants.OptoNokColor; + break; + } + } + } + } + +#if !TURA_SPECIAL + /// + /// Branch + /// + lock (this) + { + if (++completedCommCount < 4) return; + completedCommCount = 0; + } +#endif + + if (currentGroup < lastGroup) + { + /// Go to the next step / next group + currentGroup++; + } + else if (currentActivityStep + 1 < MultiTestParams.Count) + { + currentGroup = 0; + currentActivityStep++; + activityLabel.Text = MultiTestParams[currentActivityStep].Activity; + currentGroup++; + } + else + { + /// Wait until all threads are finished + workerThreads[data.ThreadId].Join(2000); + ParentFrom.NormalClose(); + } + } + catch (Exception e) + { + log.ErrorFormat("DoOnCommCompleted({0}) failed: {1}", data, e.Message); + log.FatalFormat("StackTrace : {0}{1}", Environment.NewLine, e.StackTrace); + } } public void NormalClose(IList waterMeterPositions0) @@ -171,7 +492,129 @@ namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.implementations this.cfg = cfg; this.multiTestParams = multiTestParams; } + + + ////////////////////////////////////////////////////////////// + /// + private MenuItem NewMenuItem(string text, string tag) + { + MenuItem menuItem = new MenuItem { Text = text, Tag = tag }; + menuItem.Click += OnClick_Optical_Heads_Settings_Menu; + return menuItem; + } + private async void OnClick_Optical_Heads_Settings_Menu(object sender, EventArgs e) + { + // Validate sender + if (!(sender is MenuItem menuItem)) + { + log?.Error("OnClick_Optical_Heads_Settings_Menu: sender is not a MenuItem"); + return; + } + + if (activityLabel != null) + activityLabel.Text = menuItem.Text; + + List tasks = new List(); + foreach (var iSmartReader in ProcessData.SmartHeadsUni) + { + if (!(iSmartReader is SmartReader iHead)) + { + continue;//ignore different types of heads + } + + int position = iHead.Position; + if (position < 0 || position >= checkBoxes.Length || position >= messages.Length) + { + continue; // Skip this head if position is out of range + } + if (!checkBoxes[position].Checked) + { + if (position < messages.Length) messages[position].Text = ""; + continue; + } + + messages[position].Text = $@"COM{iHead.RfidComPortNr}"; + Application.DoEvents(); // Refresh UI + tasks.Add(Task.Run(async () => + { + string result = await ProcessTask(iHead.RegPoseidonCfg, menuItem.Tag); + ParentFrom?.Invoke((Action)(() => + { + messages[position].Text = result; + Application.DoEvents(); // Refresh UI + })); + + })); + + } + + await Task.WhenAll(tasks); + } + + public static bool TryParseByDescription(string description, out PoseidonImplHeadTestCtrl.Operations result) + { + foreach (PoseidonImplHeadTestCtrl.Operations op + in Enum.GetValues(typeof(PoseidonImplHeadTestCtrl.Operations))) + { + // step-by-step compare + var desc = ((Enum)op).ToDescription(); // uses extension above + + // exact compare, you can use OrdinalIgnoreCase if you want + if (string.Equals(desc, description, StringComparison.Ordinal)) + { + result = op; + return true; + } + } + + result = PoseidonImplHeadTestCtrl.Operations.Empty; + return false; + + } + + private async Task ProcessTask(IComponentCfg head, object tag) + { + string txt = ""; + PoseidonImplHeadTestCtrl.Operations operation; + if (!TryParseByDescription((string)tag, out operation)) + { + operation = PoseidonImplHeadTestCtrl.Operations.Empty; + } + + if (head is PoseidonCfg poseidonCfg) + { + switch (operation) + { + case PoseidonImplHeadTestCtrl.Operations.ReadSerialNo: + txt = OpticalHeadTest.ReadRequest_SerialNo(poseidonCfg); + break; + case PoseidonImplHeadTestCtrl.Operations.SetTestModeOn: + txt = OpticalHeadTest.SetTestMode(poseidonCfg); + break; + case PoseidonImplHeadTestCtrl.Operations.SetTestModeOff: + txt = OpticalHeadTest.SetActiveMode(poseidonCfg); + break; + default: + txt = "-"; + break; + } + } + + return txt; + } + + public ContextMenu GetContextMenu() + { + ContextMenu cm = new ContextMenu(); + foreach (KeyValuePair itemsOperation in PoseidonImplHeadTestCtrl.ItemsOperations) + { + cm.MenuItems.Add(NewMenuItem(itemsOperation.Key, itemsOperation.Value.ToDescription())); + } + return cm; + } + + } } \ No newline at end of file diff --git a/TBF/TBF.csproj b/TBF/TBF.csproj index cfa9ba9b2..69c66bf8e 100644 --- a/TBF/TBF.csproj +++ b/TBF/TBF.csproj @@ -2067,6 +2067,7 @@ + diff --git a/TBFTests/Rig/Uni/SharedDialogs/SmartMetersCommunication/implementations/PoseidonCorrectionsTest.cs b/TBFTests/Rig/Uni/SharedDialogs/SmartMetersCommunication/implementations/PoseidonCorrectionsTest.cs new file mode 100644 index 000000000..141d9294a --- /dev/null +++ b/TBFTests/Rig/Uni/SharedDialogs/SmartMetersCommunication/implementations/PoseidonCorrectionsTest.cs @@ -0,0 +1,41 @@ +using Common; +using JetBrains.Annotations; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using TBF.Rig.RegisterReaders.PoseidonReader.implementations; +using TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.implementations; + +namespace TBFTests.Rig.Uni.SharedDialogs.SmartMetersCommunication.implementations +{ + [TestClass] + [TestSubject(typeof(PoseidonCorrections))] + public class PoseidonCorrectionsTest + { + + [TestMethod] + public void TryParseByDescription_test() + { + PoseidonImplHeadTestCtrl.Operations testOp = PoseidonImplHeadTestCtrl.Operations.ReadSerialNo; + ValidateOperationParsing(testOp.ToDescription()); + testOp = PoseidonImplHeadTestCtrl.Operations.SetTestModeOn; + ValidateOperationParsing(testOp.ToDescription()); + testOp = PoseidonImplHeadTestCtrl.Operations.SetTestModeOff; + ValidateOperationParsing(testOp.ToDescription()); + + //negative test + ValidateOperationParsing("khvcdh jkbhvf", false); + } + + private static void ValidateOperationParsing(string tag, bool expectedResult = true) + { + PoseidonImplHeadTestCtrl.Operations operation; + if (!PoseidonCorrections.TryParseByDescription((string)tag, out operation)) + { + Assert.IsFalse(expectedResult); + } + else + { + Assert.IsTrue(operation.ToDescription() == tag); + } + } + } +} \ No newline at end of file diff --git a/TBFTests/TBFTests.csproj b/TBFTests/TBFTests.csproj index f3d666950..cd6a043f3 100644 --- a/TBFTests/TBFTests.csproj +++ b/TBFTests/TBFTests.csproj @@ -107,6 +107,7 @@ +