Compare commits

...
Author SHA1 Message Date
michal 988a8c6642 Update NuGetToolVersion to 7.0.0 in SharedComponents project configuration 2025-12-07 11:27:17 +01:00
michal 42ee9eaee3 Poseidon - Flying - Opto communication
Enhance `FlyingStartMassCollectionSeq` with Poseidon reader support, detailed error handling, and improved test data processing.
2025-12-07 11:27:00 +01:00
michal 3f28051d79 Update .gitignore to exclude NfcC7_DLL.Tests build artifacts 2025-12-07 10:59:19 +01:00
michal 65f13cc868 Add UNIHeadTestCtrl interface and implement IperlHeadTestCtrl with command handling logic. 2025-12-06 12:51:51 +01:00
michal cd8ba3cda3 Add System.Threading 4.3.0 package with support for multiple frameworks and localized XML documentation. 2025-12-06 12:49:58 +01:00
michal a5936c8f19 Fix standing start Store Data
Refactor to use `ICommonRegReader` in `StandingStartSeq` and update parameter handling in `SmartCommunicationSeq`.
2025-12-06 12:48:42 +01:00
michal 2842425673 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.
2025-12-06 12:46:12 +01:00
89 changed files with 56757 additions and 333 deletions
+2
View File
@@ -34,6 +34,8 @@ MergeResultsDBs/bin/
MergeResultsDBs/obj/
NfcC7_Dll/bin/
NfcC7_Dll/obj/
NfcC7_DLL.Tests/bin/
NfcC7_DLL.Tests/obj/
OrderManagement/bin/
OrderManagement/obj/
ProductionTracing/bin/
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
<RestoreSuccess Condition=" '$(RestoreSuccess)' == '' ">True</RestoreSuccess>
@@ -7,7 +7,7 @@
<NuGetPackageRoot Condition=" '$(NuGetPackageRoot)' == '' ">$(UserProfile)\.nuget\packages\</NuGetPackageRoot>
<NuGetPackageFolders Condition=" '$(NuGetPackageFolders)' == '' ">C:\Users\micha\.nuget\packages\</NuGetPackageFolders>
<NuGetProjectStyle Condition=" '$(NuGetProjectStyle)' == '' ">PackageReference</NuGetProjectStyle>
<NuGetToolVersion Condition=" '$(NuGetToolVersion)' == '' ">6.14.0</NuGetToolVersion>
<NuGetToolVersion Condition=" '$(NuGetToolVersion)' == '' ">7.0.0</NuGetToolVersion>
</PropertyGroup>
<ItemGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
<SourceRoot Include="C:\Users\micha\.nuget\packages\" />
@@ -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);
@@ -0,0 +1,97 @@
using System.Web.UI;
using System.Windows.Forms;
using TBF.Rig.RegisterReaders.iPerlReaderUNI.iCommon;
namespace TBF.Rig.RegisterReaders.iPerlReaderUNI.IPerlS4
{
public class IperlHeadTestCtrl : UNIHeadTestCtrl
{
System.Windows.Forms.ListBox rfidOutputListBox;
public IperlHeadTestCtrl(ListBox rfidOutputListBox)
{
this.rfidOutputListBox = rfidOutputListBox;
var foo = new[]
{
new {Name = "Read PCB", Value = "ReadPCB" },
new {Name = "Set Test Mode", Value = "SetTestMode" },
new {Name = "Set Active Mode", Value = "SetActiveMode" },
#if DEBUG
new {Name = "Start Read Opto Data", Value = "ReadOptoData" },
new {Name = "Stop Read Opto Data", Value = "StopReadOptoData" },
#endif
new {Name = " ", Value = "" },
new {Name = "Reset NFC Head", Value = "ResetNfcHead" },
new {Name = "Set NFC Head Interface", Value = "SetNfcHead" },
new {Name = "Set RFID Head interface", Value = "SetRfidHead" }
};
}
public void CommandTestButtonClick(object sender, MouseEventArgs e)
{
rfidOutputListBox.Items.Clear();
using (Tools.LogChecker logChecker = new Tools.LogChecker("RfidData", log4net.Core.Level.Debug))
{
ListItem rfidListItem = new ListItem();
rfidListItem.Attributes.Add("style", "font-weight:bold");
switch (rfidCommandComboBox.SelectedValue)
{
case "ReadPCB":
rfidListItem.Text = $"PCB: {OpticalHeadTest.ReadRequest_PCB(_iPerlReader)}";
break;
case "SetTestMode":
rfidListItem.Text = OpticalHeadTest.SetTestMode(_iPerlReader);
optoListBox.Items.Clear();
stopWorkerThread = false;
optoThread = new Thread(OptoWorker);
if (!optoThread.IsAlive)
{
_iPerlReader.StartDataStreamProcessing(); // open opto port
optoThread.Start();
}
break;
case "SetActiveMode":
rfidListItem.Text = OpticalHeadTest.SetActiveMode(_iPerlReader);
stopWorkerThread = true;
_iPerlReader.StopDataStreamProcessing(); // close opto port
break;
case "ResetNfcHead":
_iPerlReader.ResetNfcInterface();
break;
case "SetNfcHead":
_iPerlReader.SetNfcInterface();
break;
case "SetRfidHead":
_iPerlReader.SetRfidInterface();
break;
case "ReadOptoData":
optoListBox.Items.Clear();
stopWorkerThread = false;
optoThread = new Thread(OptoWorker);
if (optoThread.IsAlive)
{
stopWorkerThread = true;
_iPerlReader.StopDataStreamProcessing(); // close opto port
}
if (!optoThread.IsAlive)
{
_iPerlReader.StartDataStreamProcessing(); // open opto port
optoThread.Start();
}
break;
case "StopReadOptoData":
stopWorkerThread = true;
_iPerlReader.StopDataStreamProcessing(); // close opto port
break;
}
rfidOutputListBox.Items.Add(rfidListItem);
rfidOutputListBox.Items.AddRange(logChecker.Messages.ToArray());
}
}
}
}
@@ -0,0 +1,9 @@
using System.Windows.Forms;
namespace TBF.Rig.RegisterReaders.iPerlReaderUNI.iCommon
{
public interface UNIHeadTestCtrl
{
void CommandTestButtonClick(object sender, MouseEventArgs e);
}
}
+6 -3
View File
@@ -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)
@@ -12,6 +12,9 @@ using TBF.Boxes;
using TBF.Resources;
using TBF.UiBridge;
using TBF.Rig.GenericDevices;
using TBF.Rig.RegisterReaders.PoseidonReader;
using TBF.Rig.RegisterReaders.PoseidonReader.implementations;
using TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.common;
namespace TBF.Rig.TestMethods.FlyingStartMassCollection
{
@@ -751,25 +754,56 @@ namespace TBF.Rig.TestMethods.FlyingStartMassCollection
if (oneMTR != null && regReader != null)
{
oneMTR.RegReaderType = (int)regReader.RegisterReaderType;
oneMTR.PulsesPerLiter = regReader.PulsesPerLtr;
/// Optionally supress pulses from the large water meter
oneMTR.PulsesMeter = (isAux == 0 && compoundTestParams.SupressTrills) ? 0 : Convert.ToDouble(regReader.WMPulses);
oneMTR.PulsesMaster = Convert.ToDouble(regReader.WMRefPulses);
oneMTR.TestTime = cBrd.TestTime;
oneMTR.VolumeStart = 0;
oneMTR.VolumeEnd = 0;
oneMTR.VolumeRef = tstRslt.VolumeCTV;
if (oneMTR.PulsesMaster != 0)
if (regReader is PoseidonReader poseidon) //is Poseidon reader family
{
oneMTR.PulsesMeter *= (tstRslt.PulsesMaster / oneMTR.PulsesMaster);
oneMTR.PulsesMaster = tstRslt.PulsesMaster;
oneMTR.PulsesPerLiter = 0;
/// Optionally supress pulses from the large water meter
oneMTR.PulsesMeter = 0;
oneMTR.PulsesMaster = 0;
oneMTR.TestTime = cBrd.TestTime;
oneMTR.VolumeStart = 0;
oneMTR.VolumeEnd = 0;
oneMTR.VolumeRef = tstRslt.VolumeCTV;
if (oneMTR.PulsesMaster != 0)
{
oneMTR.PulsesMeter *= (tstRslt.PulsesMaster / oneMTR.PulsesMaster);
oneMTR.PulsesMaster = tstRslt.PulsesMaster;
}
oneMTR.VolumeMeter = poseidon.WMVolume;
oneMTR.Error =
Formulas.ErrorFromVolumes(oneMTR.VolumeMeter,
tstRslt.VolumeCTV); /// Main/Aux meter error is not usedfor evaluation
}
else
{
oneMTR.PulsesPerLiter = regReader.PulsesPerLtr;
oneMTR.VolumeMeter = oneMTR.PulsesMeter * regReader.LtrsPerPulse; /// liter
/// Optionally supress pulses from the large water meter
oneMTR.PulsesMeter = (isAux == 0 && compoundTestParams.SupressTrills)
? 0
: Convert.ToDouble(regReader.WMPulses);
oneMTR.PulsesMaster = Convert.ToDouble(regReader.WMRefPulses);
oneMTR.TestTime = cBrd.TestTime;
oneMTR.VolumeStart = 0;
oneMTR.VolumeEnd = 0;
oneMTR.VolumeRef = tstRslt.VolumeCTV;
oneMTR.Error = Formulas.ErrorFromVolumes(oneMTR.VolumeMeter, tstRslt.VolumeCTV); /// Main/Aux meter error is not usedfor evaluation
if (oneMTR.PulsesMaster != 0)
{
oneMTR.PulsesMeter *= (tstRslt.PulsesMaster / oneMTR.PulsesMaster);
oneMTR.PulsesMaster = tstRslt.PulsesMaster;
}
oneMTR.VolumeMeter = oneMTR.PulsesMeter * regReader.LtrsPerPulse; /// liter
oneMTR.Error =
Formulas.ErrorFromVolumes(oneMTR.VolumeMeter,
tstRslt.VolumeCTV); /// Main/Aux meter error is not usedfor evaluation
}
}
}
@@ -887,16 +921,58 @@ namespace TBF.Rig.TestMethods.FlyingStartMassCollection
if (dstrReader != null)
{
meterRslt.TimestampStart = dstrReader.TimestampSecStart;
meterRslt.TimestampEnd = !dstrReader.NoSamples ? dstrReader.TimestampSecEnd : (dstrReader.TimestampSecStart + tstRslt.TestTime);
meterRslt.TestTime = meterRslt.TimestampEnd - meterRslt.TimestampStart;
meterRslt.VolumeStart = dstrReader.VolumeLtrStart; /// liter
meterRslt.VolumeEnd = dstrReader.VolumeLtrEnd; /// liter
meterRslt.VolumeMeter = Math.Abs(dstrReader.VolumeLtrEnd - dstrReader.VolumeLtrStart);
meterRslt.VolumeRef = tstRslt.VolumeCTV * meterRslt.TestTime / tstRslt.TestTime;
meterRslt.PulsesMaster = tstRslt.PulsesMaster * meterRslt.TestTime / tstRslt.TestTime;
if (dstrReader is SmartReader poseidon) //is Poseidon reader family
{
log.Info("Poseidon reader detected - Results");
meterRslt.TimestampStart = poseidon.TimestampSecStart;
meterRslt.TimestampEnd = !poseidon.NoSamples
? poseidon.TimestampSecEnd
: (poseidon.TimestampSecStart + tstRslt.TestTime);
meterRslt.TestTime = meterRslt.TimestampEnd - meterRslt.TimestampStart;
meterRslt.VolumeStart = poseidon.VolumeLtrStart; /// liter
meterRslt.VolumeEnd = poseidon.VolumeLtrStart + poseidon.WMVolume; //dstrReader.VolumeLtrEnd; /// liter
meterRslt.VolumeMeter = poseidon.WMVolume;
if (iPerl != null)
if (!(meterRslt.TestTime == 0 || tstRslt.TestTime == 0))
{
meterRslt.VolumeRef = tstRslt.VolumeCTV * meterRslt.TestTime / tstRslt.TestTime;
meterRslt.PulsesMaster =
tstRslt.PulsesMaster * meterRslt.TestTime / tstRslt.TestTime;
}
else
{
meterRslt.VolumeRef = tstRslt.VolumeCTV;
meterRslt.PulsesMaster = tstRslt.PulsesMaster;
}
log.Info($"meterRslt.TimestampStart = {meterRslt.TimestampStart} \n" +
$"meterRslt.TimestampEnd = {meterRslt.TimestampEnd }\n" +
$"meterRslt.TestTime = {meterRslt.TestTime}\n" +
$"meterRslt.VolumeStart = {meterRslt.VolumeStart}\n" +
$"meterRslt.VolumeEnd = {meterRslt.VolumeEnd}\n" +
$"meterRslt.VolumeMeter = {meterRslt.VolumeMeter}\n" +
$"meterRslt.VolumeRef = {meterRslt.VolumeRef}\n" +
$"meterRslt.PulsesMaster = {meterRslt.PulsesMaster}\n");
}
else
{
meterRslt.TimestampStart = dstrReader.TimestampSecStart;
meterRslt.TimestampEnd = !dstrReader.NoSamples
? dstrReader.TimestampSecEnd
: (dstrReader.TimestampSecStart + tstRslt.TestTime);
meterRslt.TestTime = meterRslt.TimestampEnd - meterRslt.TimestampStart;
meterRslt.VolumeStart = dstrReader.VolumeLtrStart; /// liter
meterRslt.VolumeEnd = dstrReader.VolumeLtrEnd; /// liter
meterRslt.VolumeMeter =
Math.Abs(dstrReader.VolumeLtrEnd - dstrReader.VolumeLtrStart);
meterRslt.VolumeRef = tstRslt.VolumeCTV * meterRslt.TestTime / tstRslt.TestTime;
meterRslt.PulsesMaster =
tstRslt.PulsesMaster * meterRslt.TestTime / tstRslt.TestTime;
}
if (iPerl != null)
{
if (iPerl.ResultCode != 0 && (meterRslt.WaterMeter.ResultCode & (int)Results.Entities.ResultCode.OptoErrorCodeMask) == 0)
{
@@ -373,7 +373,7 @@ namespace TBF.Rig.TestMethods.SmartMeterFlyingStartMassCollection
/// Show the modeless dialog with error indication
///
string componentName = (method as IComponent)?.Name ?? string.Empty;
Program.MainWnd.Invoke(new SmartCommFormDlgt(OpenSmartCommForm), new object[] { this, componentName, test, testParams });
Program.MainWnd.Invoke(new SmartCommFormDlgt(OpenSmartCommForm), new object[] { this, method, test, testParams });
//------------------------------------------------
Bridge.OnActivity(this, Strings.iPerl_Communication_in_progress);
@@ -513,8 +513,8 @@ namespace TBF.Rig.TestMethods.StandingStart
{
GenericDevices.IRegReader rr = sensPath.RegisterReaders[i];
if (rr is ISmartReader)
(rr as ISmartReader).BeginWMState = dataEntryCmpnt.WMStartState(i);
if (rr is ICommonRegReader)
(rr as ICommonRegReader).BeginWMState = dataEntryCmpnt.WMStartState(i);
if (rr is Rig.RegisterReaders.StandingStartStop.RegisterReader)
(rr as Rig.RegisterReaders.StandingStartStop.RegisterReader).BeginWMState = dataEntryCmpnt.WMStartState(i);
@@ -766,9 +766,9 @@ namespace TBF.Rig.TestMethods.StandingStart
for (int i = 0; i < Data.WMsCount; i++)
{
GenericDevices.IRegReader rr = sensPath.RegisterReaders[i];
if (rr is ISmartReader)
(rr as ISmartReader).EndWMState = dataEntryCmpnt.WMEndState(i);
if (rr is ICommonRegReader)
(rr as ICommonRegReader).EndWMState = dataEntryCmpnt.WMEndState(i);
if (rr is Rig.RegisterReaders.StandingStartStop.RegisterReader)
(rr as Rig.RegisterReaders.StandingStartStop.RegisterReader).EndWMState = dataEntryCmpnt.WMEndState(i);
@@ -1017,6 +1017,13 @@ namespace TBF.Rig.TestMethods.StandingStart
&& (tstRslt.ErrorFlags == 0);
meterRslt.TestDone = true;
tstRslt.TestDone = true;
if (regReader is ICommonRegReader regReaderCommon)
// if (meterRslt.WaterMeter != null
// && tstRslt is ICommonRegReader tstRsltCommon
// && !string.IsNullOrEmpty(tstRsltCommon.SerialNr))
{
meterRslt.WaterMeter.SerialNr = regReaderCommon.SerialNr;
}
}
}
}
@@ -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;
}
}
}
+1
View File
@@ -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);
}
}
}
}
+1
View File
@@ -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" />
Binary file not shown.
Binary file not shown.
+31
View File
@@ -0,0 +1,31 @@
This Microsoft .NET Library may incorporate components from the projects listed
below. Microsoft licenses these components under the Microsoft .NET Library
software license terms. The original copyright notices and the licenses under
which Microsoft received such components are set forth below for informational
purposes only. Microsoft reserves all rights not expressly granted herein,
whether by implication, estoppel or otherwise.
1. .NET Core (https://github.com/dotnet/core/)
.NET Core
Copyright (c) .NET Foundation and Contributors
The MIT License (MIT)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
@@ -0,0 +1,128 @@
MICROSOFT SOFTWARE LICENSE TERMS
MICROSOFT .NET LIBRARY
These license terms are an agreement between Microsoft Corporation (or based on where you live, one of its affiliates) and you. Please read them. They apply to the software named above, which includes the media on which you received it, if any. The terms also apply to any Microsoft
· updates,
· supplements,
· Internet-based services, and
· support services
for this software, unless other terms accompany those items. If so, those terms apply.
BY USING THE SOFTWARE, YOU ACCEPT THESE TERMS. IF YOU DO NOT ACCEPT THEM, DO NOT USE THE SOFTWARE.
IF YOU COMPLY WITH THESE LICENSE TERMS, YOU HAVE THE PERPETUAL RIGHTS BELOW.
1. INSTALLATION AND USE RIGHTS.
a. Installation and Use. You may install and use any number of copies of the software to design, develop and test your programs.
b. Third Party Programs. The software may include third party programs that Microsoft, not the third party, licenses to you under this agreement. Notices, if any, for the third party program are included for your information only.
2. ADDITIONAL LICENSING REQUIREMENTS AND/OR USE RIGHTS.
a. DISTRIBUTABLE CODE. The software is comprised of Distributable Code. “Distributable Code” is code that you are permitted to distribute in programs you develop if you comply with the terms below.
i. Right to Use and Distribute.
· You may copy and distribute the object code form of the software.
· Third Party Distribution. You may permit distributors of your programs to copy and distribute the Distributable Code as part of those programs.
ii. Distribution Requirements. For any Distributable Code you distribute, you must
· add significant primary functionality to it in your programs;
· require distributors and external end users to agree to terms that protect it at least as much as this agreement;
· display your valid copyright notice on your programs; and
· indemnify, defend, and hold harmless Microsoft from any claims, including attorneys fees, related to the distribution or use of your programs.
iii. Distribution Restrictions. You may not
· alter any copyright, trademark or patent notice in the Distributable Code;
· use Microsofts trademarks in your programs names or in a way that suggests your programs come from or are endorsed by Microsoft;
· include Distributable Code in malicious, deceptive or unlawful programs; or
· modify or distribute the source code of any Distributable Code so that any part of it becomes subject to an Excluded License. An Excluded License is one that requires, as a condition of use, modification or distribution, that
· the code be disclosed or distributed in source code form; or
· others have the right to modify it.
3. SCOPE OF LICENSE. The software is licensed, not sold. This agreement only gives you some rights to use the software. Microsoft reserves all other rights. Unless applicable law gives you more rights despite this limitation, you may use the software only as expressly permitted in this agreement. In doing so, you must comply with any technical limitations in the software that only allow you to use it in certain ways. You may not
· work around any technical limitations in the software;
· reverse engineer, decompile or disassemble the software, except and only to the extent that applicable law expressly permits, despite this limitation;
· publish the software for others to copy;
· rent, lease or lend the software;
· transfer the software or this agreement to any third party; or
· use the software for commercial software hosting services.
4. BACKUP COPY. You may make one backup copy of the software. You may use it only to reinstall the software.
5. DOCUMENTATION. Any person that has valid access to your computer or internal network may copy and use the documentation for your internal, reference purposes.
6. EXPORT RESTRICTIONS. The software is subject to United States export laws and regulations. You must comply with all domestic and international export laws and regulations that apply to the software. These laws include restrictions on destinations, end users and end use. For additional information, see www.microsoft.com/exporting.
7. SUPPORT SERVICES. Because this software is “as is,” we may not provide support services for it.
8. ENTIRE AGREEMENT. This agreement, and the terms for supplements, updates, Internet-based services and support services that you use, are the entire agreement for the software and support services.
9. APPLICABLE LAW.
a. United States. If you acquired the software in the United States, Washington state law governs the interpretation of this agreement and applies to claims for breach of it, regardless of conflict of laws principles. The laws of the state where you live govern all other claims, including claims under state consumer protection laws, unfair competition laws, and in tort.
b. Outside the United States. If you acquired the software in any other country, the laws of that country apply.
10. LEGAL EFFECT. This agreement describes certain legal rights. You may have other rights under the laws of your country. You may also have rights with respect to the party from whom you acquired the software. This agreement does not change your rights under the laws of your country if the laws of your country do not permit it to do so.
11. DISCLAIMER OF WARRANTY. THE SOFTWARE IS LICENSED “AS-IS.” YOU BEAR THE RISK OF USING IT. MICROSOFT GIVES NO EXPRESS WARRANTIES, GUARANTEES OR CONDITIONS. YOU MAY HAVE ADDITIONAL CONSUMER RIGHTS OR STATUTORY GUARANTEES UNDER YOUR LOCAL LAWS WHICH THIS AGREEMENT CANNOT CHANGE. TO THE EXTENT PERMITTED UNDER YOUR LOCAL LAWS, MICROSOFT EXCLUDES THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
FOR AUSTRALIA YOU HAVE STATUTORY GUARANTEES UNDER THE AUSTRALIAN CONSUMER LAW AND NOTHING IN THESE TERMS IS INTENDED TO AFFECT THOSE RIGHTS.
12. LIMITATION ON AND EXCLUSION OF REMEDIES AND DAMAGES. YOU CAN RECOVER FROM MICROSOFT AND ITS SUPPLIERS ONLY DIRECT DAMAGES UP TO U.S. $5.00. YOU CANNOT RECOVER ANY OTHER DAMAGES, INCLUDING CONSEQUENTIAL, LOST PROFITS, SPECIAL, INDIRECT OR INCIDENTAL DAMAGES.
This limitation applies to
· anything related to the software, services, content (including code) on third party Internet sites, or third party programs; and
· claims for breach of contract, breach of warranty, guarantee or condition, strict liability, negligence, or other tort to the extent permitted by applicable law.
It also applies even if Microsoft knew or should have known about the possibility of the damages. The above limitation or exclusion may not apply to you because your country may not allow the exclusion or limitation of incidental, consequential or other damages.
Please note: As this software is distributed in Quebec, Canada, some of the clauses in this agreement are provided below in French.
Remarque : Ce logiciel étant distribué au Québec, Canada, certaines des clauses dans ce contrat sont fournies ci-dessous en français.
EXONÉRATION DE GARANTIE. Le logiciel visé par une licence est offert « tel quel ». Toute utilisation de ce logiciel est à votre seule risque et péril. Microsoft naccorde aucune autre garantie expresse. Vous pouvez bénéficier de droits additionnels en vertu du droit local sur la protection des consommateurs, que ce contrat ne peut modifier. La ou elles sont permises par le droit locale, les garanties implicites de qualité marchande, dadéquation à un usage particulier et dabsence de contrefaçon sont exclues.
LIMITATION DES DOMMAGES-INTÉRÊTS ET EXCLUSION DE RESPONSABILITÉ POUR LES DOMMAGES. Vous pouvez obtenir de Microsoft et de ses fournisseurs une indemnisation en cas de dommages directs uniquement à hauteur de 5,00 $ US. Vous ne pouvez prétendre à aucune indemnisation pour les autres dommages, y compris les dommages spéciaux, indirects ou accessoires et pertes de bénéfices.
Cette limitation concerne :
· tout ce qui est relié au logiciel, aux services ou au contenu (y compris le code) figurant sur des sites Internet tiers ou dans des programmes tiers ; et
· les réclamations au titre de violation de contrat ou de garantie, ou au titre de responsabilité stricte, de négligence ou dune autre faute dans la limite autorisée par la loi en vigueur.
Elle sapplique également, même si Microsoft connaissait ou devrait connaître l’éventualité dun tel dommage. Si votre pays nautorise pas lexclusion ou la limitation de responsabilité pour les dommages indirects, accessoires ou de quelque nature que ce soit, il se peut que la limitation ou lexclusion ci-dessus ne sappliquera pas à votre égard.
EFFET JURIDIQUE. Le présent contrat décrit certains droits juridiques. Vous pourriez avoir dautres droits prévus par les lois de votre pays. Le présent contrat ne modifie pas les droits que vous confèrent les lois de votre pays si celles-ci ne le permettent pas.
View File
View File
View File
View File
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
View File
View File
View File