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.
This commit is contained in:
parent
06a401a1ff
commit
2842425673
@ -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:
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
private void StartOptohead()
|
||||
{
|
||||
lock (_avgLock)
|
||||
{
|
||||
_firstSampleTime = DateTime.MinValue;
|
||||
_lastSampleTime = DateTime.MinValue;
|
||||
_averageFlow = 0;
|
||||
_averageFlowCount = 0;
|
||||
}
|
||||
|
||||
StartOptoTestInputLoop(new EventHandler<CommonRR.IPerl.communication.OptoReceivedEventArgs>(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<CommonRR.IPerl.communication.OptoReceivedEventArgs> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Stop this operation
|
||||
/// </summary>
|
||||
public void Stop()
|
||||
@ -570,78 +709,7 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Q2 correction factor calculated from the last test (Q2).
|
||||
/// This factor should be used only for R800 meters.
|
||||
/// </summary>
|
||||
/// <param name="q2TestResult">A test result from which to calculate the factor</param>
|
||||
/// <param name="nominalFlow">Nominal flow in m3/h</param>
|
||||
/// <param name="currentFactor">0 or the current Q2 correction factor when updating the factor</param>
|
||||
/// <returns>Calculated Q2 correction factor</returns>
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
/// <param name="resultAt2Hz">Test result @2Hz from which to calculate the factor</param>
|
||||
/// <param name="resultAt8Hz">Test result @8Hz from which to calculate the factor</param>
|
||||
/// <param name="hz2CorrectionFactor">The calculated Q2 correction factor</param>
|
||||
/// <returns>true = OK, false = failed</returns>
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
@ -703,147 +771,24 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader
|
||||
/// <param name="optoState">OptoState.Read or OptoState.Flush</param>
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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}");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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<CommonRR.IPerl.communication.OptoReceivedEventArgs> OnOptoReceivedHandler;
|
||||
|
||||
|
||||
|
||||
public bool IsRunning
|
||||
{
|
||||
get { return !dissableRunLoop
|
||||
&& ((Connection?.DebugModeSetting != DebugMode.Simulate) ? driver.isOpen() : true)
|
||||
&& _bRunStarted;}
|
||||
}
|
||||
|
||||
public void RunLoop(EventHandler<CommonRR.IPerl.communication.OptoReceivedEventArgs> 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;
|
||||
/// <summary>
|
||||
/// Run the service. Catch one communication to WaterMetrologyData field.
|
||||
/// </summary>
|
||||
@ -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)
|
||||
|
||||
@ -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}";
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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)
|
||||
{
|
||||
|
||||
@ -6,6 +6,6 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader.communication
|
||||
{
|
||||
[Description("..")] None,
|
||||
[Description("Nfc")] Nfc,
|
||||
[Description("Touch Capl")]Touched,
|
||||
[Description("cTouchRead")]Touched,
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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; }
|
||||
}
|
||||
}
|
||||
@ -135,7 +135,7 @@ namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication
|
||||
public static string SelectedTypeReader { get; set; }
|
||||
|
||||
private List<ICorrections> GetNewCorrectionList(ISmartTestMethod componentBase ,
|
||||
TestMethodCfg cfg, IList<Test> tests, IList<ITestParams> multiTestParams)
|
||||
ITestMethodCfg cfg, IList<Test> tests, IList<ITestParams> multiTestParams)
|
||||
{
|
||||
List<ICorrections> correctionsList = new List<ICorrections>();
|
||||
|
||||
@ -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<ISmartReader>();
|
||||
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 <b>test loop</b>
|
||||
/// - because ProcessData.RegisterReaders is initialized in test loop
|
||||
/// </summary>
|
||||
/// <param name="selectedTypeReader"></param>
|
||||
private static void InitializeSmartReaderLists()
|
||||
{
|
||||
iperlHeads = new List<ISmartReader>();
|
||||
@ -501,43 +540,7 @@ namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication
|
||||
/// <param name="lineSize">Number of watermeters in one line</param>
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,30 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.implementations
|
||||
{
|
||||
public static class EnumExtensions
|
||||
{
|
||||
public static bool TryParseByDescription<TEnum>(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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@ -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<Test> tests;
|
||||
private IList<ITestParams> multiTestParams;
|
||||
private SmartCommunicationForm _parentFrom;
|
||||
|
||||
static IList<Thread> 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<ISmartReader> 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<Thread> 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<Thread>();
|
||||
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<ISmartReader> 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<int> 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<int> 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<Task> tasks = new List<Task>();
|
||||
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<string> 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<string, PoseidonImplHeadTestCtrl.Operations> itemsOperation in PoseidonImplHeadTestCtrl.ItemsOperations)
|
||||
{
|
||||
cm.MenuItems.Add(NewMenuItem(itemsOperation.Key, itemsOperation.Value.ToDescription()));
|
||||
}
|
||||
return cm;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@ -2067,6 +2067,7 @@
|
||||
<Compile Include="Rig\Uni\SharedDialogs\SmartMetersCommunication\common\ICommonRegReader.cs" />
|
||||
<Compile Include="Rig\Uni\SharedDialogs\SmartMetersCommunication\common\ICorrections.cs" />
|
||||
<Compile Include="Rig\Uni\SharedDialogs\SmartMetersCommunication\common\ISmartReader.cs" />
|
||||
<Compile Include="Rig\Uni\SharedDialogs\SmartMetersCommunication\implementations\EnumExtensions.cs" />
|
||||
<Compile Include="Rig\Uni\SharedDialogs\SmartMetersCommunication\implementations\IPerlCorrections.cs" />
|
||||
<Compile Include="Rig\Uni\SharedDialogs\SmartMetersCommunication\implementations\PoseidonCorrections.cs" />
|
||||
<Compile Include="Rig\Uni\SharedDialogs\SmartMetersCommunication\SmartComponentBase.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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -107,6 +107,7 @@
|
||||
<Compile Include="Rig\RegisterReaders\PoseidonCmdStartStop\PoseidonReaderTest.cs" />
|
||||
<Compile Include="Rig\RegisterReaders\PoseidonReader\UniHeadTestCtrlTest.cs" />
|
||||
<Compile Include="Rig\Scales\MettlerToledo\ReadStableMassOpTest.cs" />
|
||||
<Compile Include="Rig\Uni\SharedDialogs\SmartMetersCommunication\implementations\PoseidonCorrectionsTest.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="app.config" />
|
||||
|
||||
Loading…
Reference in New Issue
Block a user