Iperl -> Iperl ASIC
Refactor iPerl communication system: - Consolidate redundant OptoHead methods. - Introduce new utilities for diagnostic LED state handling and volume unit conversions. - Improve FIFO logic in flow direction detection with enhanced regression calculation. - Add enhanced debugging and logging within communication layers (`SerialDriver` and `RadioService`). - Update communication protocols for improved response handling and configuration management. - Replace raw volume with meaningful unit-based values (`RawVolume1to4`).
This commit is contained in:
parent
aa0d775b8e
commit
90cd53b05f
@ -40,11 +40,11 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.common
|
||||
public Int32 EmfRaw; /// Signed EMF from iPerl opto data
|
||||
public Int16 MagneticFieldRaw;
|
||||
public Int16 FlowRaw;
|
||||
public UInt32 VolumeRaw;
|
||||
public Int64 VolumeRawExt;
|
||||
public double VolumeRaw;
|
||||
public double VolumeRawExt;
|
||||
public Int16 Impedance;
|
||||
public UInt32 Timestamp;
|
||||
public Int64 TimestampExt;
|
||||
public double Timestamp;
|
||||
public double TimestampExt;
|
||||
public byte CheckSum;
|
||||
|
||||
///
|
||||
@ -106,146 +106,148 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.common
|
||||
/// </description>
|
||||
/// <param name="data">A complete byte array data</param>
|
||||
/// <returns>true = telegram OK, false = telegram NOK</returns>
|
||||
public bool UpdateFromString(string telegram, int counter, float refFlow, ref Int64 volumeRawExtLast, ref Int64 timestampExtLast, bool isLog = false)
|
||||
{
|
||||
DateTime = DateTime.Now;
|
||||
Counter = counter;
|
||||
RefFlow = refFlow;
|
||||
// public bool UpdateFromString(string telegram, int counter, float refFlow, ref Int64 volumeRawExtLast, ref Int64 timestampExtLast, bool isLog = false)
|
||||
// {
|
||||
// DateTime = DateTime.Now;
|
||||
// Counter = counter;
|
||||
// RefFlow = refFlow;
|
||||
//
|
||||
// if ((telegram == null) || (telegram.Length < Length) ||
|
||||
// (telegram[6] != '\t') || (telegram[11] != '\t') || (telegram[16] != '\t') ||
|
||||
// (telegram[23] != '\t') || (telegram[28] != '\t') || (telegram[37] != '\t') ||
|
||||
// (!isLog && (telegram[40] != '\r' || telegram[41] != '\n')))
|
||||
// {
|
||||
// Flags = OptoTelegramFlags.InvalidTelegram;
|
||||
// return false;
|
||||
// }
|
||||
//
|
||||
// UInt32 uEmfRaw;
|
||||
// bool f1 = UInt32.TryParse(telegram.Substring(0, 6), NumberStyles.HexNumber, CultureInfo.CurrentCulture, out uEmfRaw);
|
||||
// EmfRaw = (uEmfRaw > 0x7FFFFF) ? ((int)uEmfRaw - 0x1000000) : (int)uEmfRaw;
|
||||
//
|
||||
// bool f2 = Int16.TryParse(telegram.Substring(7, 4), NumberStyles.HexNumber, CultureInfo.CurrentCulture, out MagneticFieldRaw);
|
||||
// bool f3 = Int16.TryParse(telegram.Substring(12, 4), NumberStyles.HexNumber, CultureInfo.CurrentCulture, out FlowRaw);
|
||||
// bool f4 = UInt32.TryParse(telegram.Substring(17, 6), NumberStyles.HexNumber, CultureInfo.CurrentCulture, out VolumeRaw);
|
||||
// bool f5 = Int16.TryParse(telegram.Substring(24, 4), NumberStyles.HexNumber, CultureInfo.CurrentCulture, out Impedance);
|
||||
// bool f6 = UInt32.TryParse(telegram.Substring(29, 8), NumberStyles.HexNumber, CultureInfo.CurrentCulture, out Timestamp);
|
||||
// bool f7 = byte.TryParse(telegram.Substring(38, 2), NumberStyles.HexNumber, CultureInfo.CurrentCulture, out CheckSum);
|
||||
//
|
||||
// byte calculatedCheckSum = 0;
|
||||
// for (int i = 0; i < Length - 4; i++)
|
||||
// {
|
||||
// calculatedCheckSum += (byte)telegram[i];
|
||||
// }
|
||||
//
|
||||
// bool allOk = f1 && f2 && f3 && f4 && f5 && f6 && f7 && (calculatedCheckSum == CheckSum);
|
||||
//
|
||||
// if (allOk)
|
||||
// {
|
||||
// ///
|
||||
// /// Cope with 'VolumeRaw' overflow
|
||||
// ///
|
||||
// Int64 uncorrected = (Int64)(((UInt64)volumeRawExtLast & 0xFFFFFFFFFF000000UL) | VolumeRaw);
|
||||
// if (Math.Abs(uncorrected - volumeRawExtLast) <= 0x800000L)
|
||||
// {
|
||||
// VolumeRawExt = volumeRawExtLast = uncorrected;
|
||||
// }
|
||||
// else if (Math.Abs(uncorrected + 0x1000000L - volumeRawExtLast) <= 0x800000L)
|
||||
// {
|
||||
// VolumeRawExt = volumeRawExtLast = uncorrected + 0x1000000L;
|
||||
// }
|
||||
// else if (Math.Abs(uncorrected - 0x1000000L - volumeRawExtLast) <= 0x800000L)
|
||||
// {
|
||||
// VolumeRawExt = volumeRawExtLast = uncorrected - 0x1000000L;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// VolumeRawExt = volumeRawExtLast = uncorrected;
|
||||
// }
|
||||
//
|
||||
// ///
|
||||
// /// Cope with 'Timestamp' overflow
|
||||
// ///
|
||||
// uncorrected = (Int64)(((UInt64)timestampExtLast & 0xFFFFFFFF00000000UL) | Timestamp);
|
||||
// if (Math.Abs(uncorrected - timestampExtLast) <= 0x80000000L)
|
||||
// {
|
||||
// TimestampExt = timestampExtLast = uncorrected;
|
||||
// }
|
||||
// else if (Math.Abs(uncorrected + 0x100000000L - timestampExtLast) <= 0x80000000L)
|
||||
// {
|
||||
// TimestampExt = timestampExtLast = uncorrected + 0x100000000L;
|
||||
// }
|
||||
// else if (Math.Abs(uncorrected - 0x100000000L - timestampExtLast) <= 0x80000000L)
|
||||
// {
|
||||
// TimestampExt = timestampExtLast = uncorrected - 0x100000000L;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// TimestampExt = timestampExtLast = uncorrected;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// Flags = allOk ? OptoTelegramFlags.OK : OptoTelegramFlags.InvalidTelegram;
|
||||
//
|
||||
// return allOk;
|
||||
// }
|
||||
|
||||
if ((telegram == null) || (telegram.Length < Length) ||
|
||||
(telegram[6] != '\t') || (telegram[11] != '\t') || (telegram[16] != '\t') ||
|
||||
(telegram[23] != '\t') || (telegram[28] != '\t') || (telegram[37] != '\t') ||
|
||||
(!isLog && (telegram[40] != '\r' || telegram[41] != '\n')))
|
||||
{
|
||||
Flags = OptoTelegramFlags.InvalidTelegram;
|
||||
return false;
|
||||
}
|
||||
// -------- TIMESTAMP (seconds) --------
|
||||
const double TS_TICKS_PER_SEC = 4096.0;
|
||||
const double TS_RANGE = (1UL << 32) / TS_TICKS_PER_SEC;
|
||||
//const double TS_HALF = TS_RANGE / 2.0;
|
||||
|
||||
UInt32 uEmfRaw;
|
||||
bool f1 = UInt32.TryParse(telegram.Substring(0, 6), NumberStyles.HexNumber, CultureInfo.CurrentCulture, out uEmfRaw);
|
||||
EmfRaw = (uEmfRaw > 0x7FFFFF) ? ((int)uEmfRaw - 0x1000000) : (int)uEmfRaw;
|
||||
|
||||
bool f2 = Int16.TryParse(telegram.Substring(7, 4), NumberStyles.HexNumber, CultureInfo.CurrentCulture, out MagneticFieldRaw);
|
||||
bool f3 = Int16.TryParse(telegram.Substring(12, 4), NumberStyles.HexNumber, CultureInfo.CurrentCulture, out FlowRaw);
|
||||
bool f4 = UInt32.TryParse(telegram.Substring(17, 6), NumberStyles.HexNumber, CultureInfo.CurrentCulture, out VolumeRaw);
|
||||
bool f5 = Int16.TryParse(telegram.Substring(24, 4), NumberStyles.HexNumber, CultureInfo.CurrentCulture, out Impedance);
|
||||
bool f6 = UInt32.TryParse(telegram.Substring(29, 8), NumberStyles.HexNumber, CultureInfo.CurrentCulture, out Timestamp);
|
||||
bool f7 = byte.TryParse(telegram.Substring(38, 2), NumberStyles.HexNumber, CultureInfo.CurrentCulture, out CheckSum);
|
||||
|
||||
byte calculatedCheckSum = 0;
|
||||
for (int i = 0; i < Length - 4; i++)
|
||||
{
|
||||
calculatedCheckSum += (byte)telegram[i];
|
||||
}
|
||||
|
||||
bool allOk = f1 && f2 && f3 && f4 && f5 && f6 && f7 && (calculatedCheckSum == CheckSum);
|
||||
|
||||
if (allOk)
|
||||
{
|
||||
///
|
||||
/// Cope with 'VolumeRaw' overflow
|
||||
///
|
||||
Int64 uncorrected = (Int64)(((UInt64)volumeRawExtLast & 0xFFFFFFFFFF000000UL) | VolumeRaw);
|
||||
if (Math.Abs(uncorrected - volumeRawExtLast) <= 0x800000L)
|
||||
{
|
||||
VolumeRawExt = volumeRawExtLast = uncorrected;
|
||||
}
|
||||
else if (Math.Abs(uncorrected + 0x1000000L - volumeRawExtLast) <= 0x800000L)
|
||||
{
|
||||
VolumeRawExt = volumeRawExtLast = uncorrected + 0x1000000L;
|
||||
}
|
||||
else if (Math.Abs(uncorrected - 0x1000000L - volumeRawExtLast) <= 0x800000L)
|
||||
{
|
||||
VolumeRawExt = volumeRawExtLast = uncorrected - 0x1000000L;
|
||||
}
|
||||
else
|
||||
{
|
||||
VolumeRawExt = volumeRawExtLast = uncorrected;
|
||||
}
|
||||
|
||||
///
|
||||
/// Cope with 'Timestamp' overflow
|
||||
///
|
||||
uncorrected = (Int64)(((UInt64)timestampExtLast & 0xFFFFFFFF00000000UL) | Timestamp);
|
||||
if (Math.Abs(uncorrected - timestampExtLast) <= 0x80000000L)
|
||||
{
|
||||
TimestampExt = timestampExtLast = uncorrected;
|
||||
}
|
||||
else if (Math.Abs(uncorrected + 0x100000000L - timestampExtLast) <= 0x80000000L)
|
||||
{
|
||||
TimestampExt = timestampExtLast = uncorrected + 0x100000000L;
|
||||
}
|
||||
else if (Math.Abs(uncorrected - 0x100000000L - timestampExtLast) <= 0x80000000L)
|
||||
{
|
||||
TimestampExt = timestampExtLast = uncorrected - 0x100000000L;
|
||||
}
|
||||
else
|
||||
{
|
||||
TimestampExt = timestampExtLast = uncorrected;
|
||||
}
|
||||
}
|
||||
|
||||
Flags = allOk ? OptoTelegramFlags.OK : OptoTelegramFlags.InvalidTelegram;
|
||||
|
||||
return allOk;
|
||||
}
|
||||
// -------- VOLUME (liters) --------
|
||||
const double GAL_TO_LITER = 3.785411784;
|
||||
const double VOL_LITERS_PER_TICK =
|
||||
(4.0 / 1000.0) / GAL_TO_LITER / 2.0;
|
||||
|
||||
const double VOL_RANGE = (1 << 24) * VOL_LITERS_PER_TICK;
|
||||
//const double VOL_HALF = VOL_RANGE / 2.0;
|
||||
|
||||
//New IPERL ASIC
|
||||
public void UpdateFromSmart(DiagnosticLedState4Data data, int counter, float refFlow,
|
||||
ref Int64 volumeRawExtLast, ref Int64 timestampExtLast)
|
||||
{
|
||||
DateTime = DateTime.Now;
|
||||
Counter = counter;
|
||||
RefFlow = refFlow;
|
||||
|
||||
FlowRaw = data.RawFlow;
|
||||
VolumeRaw = data.RawVolume;
|
||||
Timestamp = data.AsicTimestamp;
|
||||
|
||||
|
||||
///
|
||||
/// Cope with 'VolumeRaw' overflow
|
||||
///
|
||||
Int64 uncorrected = (Int64)(((UInt64)volumeRawExtLast & 0xFFFFFFFFFF000000UL) | VolumeRaw);
|
||||
if (Math.Abs(uncorrected - volumeRawExtLast) <= 0x800000L)
|
||||
{
|
||||
VolumeRawExt = volumeRawExtLast = uncorrected;
|
||||
}
|
||||
else if (Math.Abs(uncorrected + 0x1000000L - volumeRawExtLast) <= 0x800000L)
|
||||
{
|
||||
VolumeRawExt = volumeRawExtLast = uncorrected + 0x1000000L;
|
||||
}
|
||||
else if (Math.Abs(uncorrected - 0x1000000L - volumeRawExtLast) <= 0x800000L)
|
||||
{
|
||||
VolumeRawExt = volumeRawExtLast = uncorrected - 0x1000000L;
|
||||
}
|
||||
else
|
||||
{
|
||||
VolumeRawExt = volumeRawExtLast = uncorrected;
|
||||
}
|
||||
public void UpdateFromSmart(
|
||||
DiagnosticLedState4Data data,
|
||||
int counter,
|
||||
float refFlow,
|
||||
ref double volumeRawExtLast,
|
||||
ref double timestampExtLast)
|
||||
{
|
||||
DateTime = DateTime.Now;
|
||||
Counter = counter;
|
||||
RefFlow = refFlow;
|
||||
|
||||
///
|
||||
/// Cope with 'Timestamp' overflow
|
||||
///
|
||||
uncorrected = (Int64)(((UInt64)timestampExtLast & 0xFFFFFFFF00000000UL) | Timestamp);
|
||||
if (Math.Abs(uncorrected - timestampExtLast) <= 0x80000000L)
|
||||
{
|
||||
TimestampExt = timestampExtLast = uncorrected;
|
||||
}
|
||||
else if (Math.Abs(uncorrected + 0x100000000L - timestampExtLast) <= 0x80000000L)
|
||||
{
|
||||
TimestampExt = timestampExtLast = uncorrected + 0x100000000L;
|
||||
}
|
||||
else if (Math.Abs(uncorrected - 0x100000000L - timestampExtLast) <= 0x80000000L)
|
||||
{
|
||||
TimestampExt = timestampExtLast = uncorrected - 0x100000000L;
|
||||
}
|
||||
else
|
||||
{
|
||||
TimestampExt = timestampExtLast = uncorrected;
|
||||
}
|
||||
}
|
||||
FlowRaw = data.RawFlow;
|
||||
VolumeRaw = data.RawVolume;
|
||||
Timestamp = data.AsicTimestamp;
|
||||
|
||||
// ---------- VOLUME UNWRAP ----------
|
||||
double uncorrected = VolumeRaw;
|
||||
|
||||
if (double.IsNaN(volumeRawExtLast))
|
||||
{
|
||||
VolumeRawExt = volumeRawExtLast = uncorrected;
|
||||
}
|
||||
else
|
||||
{
|
||||
double k = Math.Round((volumeRawExtLast - uncorrected) / VOL_RANGE);
|
||||
VolumeRawExt = volumeRawExtLast = uncorrected + k * VOL_RANGE;
|
||||
}
|
||||
|
||||
// ---------- TIMESTAMP UNWRAP ----------
|
||||
uncorrected = Timestamp;
|
||||
|
||||
if (double.IsNaN(timestampExtLast))
|
||||
{
|
||||
TimestampExt = timestampExtLast = uncorrected;
|
||||
}
|
||||
else
|
||||
{
|
||||
double k = Math.Round((timestampExtLast - uncorrected) / TS_RANGE);
|
||||
TimestampExt = timestampExtLast = uncorrected + k * TS_RANGE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Alternative to UpdateFromString(...) when data are flushed
|
||||
/// </summary>
|
||||
|
||||
@ -39,7 +39,7 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.communication.C4.diagnosticLed.
|
||||
/// </summary>
|
||||
public abstract class DiagnosticLedData
|
||||
{
|
||||
|
||||
const double GalToLiterConversion = 3.785411784D;
|
||||
public abstract int GetByteCount();
|
||||
|
||||
/// <summary>
|
||||
@ -66,10 +66,35 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.communication.C4.diagnosticLed.
|
||||
public short RawFlow { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// Unsigned 24-bit raw volume accumulation in units of ¼ milliliter per bit.
|
||||
/// Unsigned 24-bit raw volume accumulation in units of ¼ milliliter per bit. it is in Gal * 2
|
||||
/// </summary>
|
||||
public uint RawVolume { get; protected set; }
|
||||
|
||||
public uint RawVolume1to4 { get; protected set; } // in 1/4 ml Gal * 2
|
||||
|
||||
/// <summary>
|
||||
/// Raw volume in liters
|
||||
/// </summary>
|
||||
public double RawVolume // in liter
|
||||
{
|
||||
get
|
||||
{
|
||||
double volume = (RawVolume1to4 * 0.00025) ; // convert to liters
|
||||
return volume;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raw volume in Gal
|
||||
/// </summary>
|
||||
public double RawVolumeInGal // in Gal
|
||||
{
|
||||
get
|
||||
{
|
||||
double volume = (RawVolume1to4 * 4.0) / 1000.0F; // convert to Gal
|
||||
//volume = (volume / GalToLiterConversion) / 2; // convert to liter
|
||||
return volume;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unsigned 16-bit millivolt delta measured on the field drive capacitor.
|
||||
/// </summary>
|
||||
|
||||
@ -33,7 +33,7 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.communication.C4.diagnosticLed.
|
||||
Adc24 = DiagnosticHex.ParseInt24(f[0]);
|
||||
FieldStrength = DiagnosticHex.ParseUInt16(f[1]);
|
||||
RawFlow = DiagnosticHex.ParseInt16(f[2]);
|
||||
RawVolume = DiagnosticHex.ParseUInt24(f[3]);
|
||||
RawVolume1to4 = DiagnosticHex.ParseUInt24(f[3]);
|
||||
CapacitorMv = DiagnosticHex.ParseUInt16(f[4]);
|
||||
}
|
||||
|
||||
|
||||
@ -59,7 +59,7 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.communication.C4.diagnosticLed.
|
||||
Adc24 = DiagnosticHex.ParseInt24(fields[0]);
|
||||
FieldStrength = DiagnosticHex.ParseUInt16(fields[1]);
|
||||
RawFlow = DiagnosticHex.ParseInt16(fields[2]);
|
||||
RawVolume = DiagnosticHex.ParseUInt24(fields[3]);
|
||||
RawVolume1to4 = DiagnosticHex.ParseUInt24(fields[3]);
|
||||
CapacitorMv = DiagnosticHex.ParseUInt16(fields[4]);
|
||||
|
||||
// ---- State #2 specific ----
|
||||
|
||||
@ -59,7 +59,7 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.communication.C4.diagnosticLed.
|
||||
Adc24 = DiagnosticHex.ParseInt24(fields[0]);
|
||||
FieldStrength = DiagnosticHex.ParseUInt16(fields[1]);
|
||||
RawFlow = DiagnosticHex.ParseInt16(fields[2]);
|
||||
RawVolume = DiagnosticHex.ParseUInt24(fields[3]);
|
||||
RawVolume1to4 = DiagnosticHex.ParseUInt24(fields[3]);
|
||||
CapacitorMv = DiagnosticHex.ParseUInt16(fields[4]);
|
||||
|
||||
// ---- State #3 specific fields ----
|
||||
|
||||
@ -13,7 +13,7 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.communication.C4.diagnosticLed.
|
||||
/// <item><term>0 – xxxxxx</term><description>signed 24-bit ADC value</description></item>
|
||||
/// <item><term>1 – aaaa</term><description>unsigned 16-bit Field strength</description></item>
|
||||
/// <item><term>2 – yyyy</term><description>signed 16-bit Raw flow rate (1/4 ml per bit)</description></item>
|
||||
/// <item><term>3 – vvvvvv</term><description>unsigned 24-bit Raw volume accumulation</description></item>
|
||||
/// <item><term>3 – vvvvvv</term><description>unsigned 24 bit raw volume accumulation in ¼ ml per bit</description></item>
|
||||
/// <item><term>4 – cccc</term><description>unsigned 16-bit Capacitor mV delta</description></item>
|
||||
/// <item><term>5 – tttt</term><description>unsigned 16-bit Field calibration</description></item>
|
||||
/// <item><term>6 – bbbbbbbb</term><description>unsigned 32-bit ASIC timestamp</description></item>
|
||||
@ -30,7 +30,19 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.communication.C4.diagnosticLed.
|
||||
public sealed class DiagnosticLedState4Data : DiagnosticLedData
|
||||
{
|
||||
public ushort FieldCalibration { get; }
|
||||
public uint AsicTimestamp { get; }
|
||||
|
||||
/// <summary>
|
||||
/// ASIC timestamp in seconds
|
||||
/// </summary>
|
||||
public double AsicTimestamp
|
||||
{
|
||||
get { return AsicTimestampTicks / 8192; } //4096.0; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ASIC timestamp in units of 1 / 4096 seconds.
|
||||
/// </summary>
|
||||
public uint AsicTimestampTicks { get; }
|
||||
public byte FieldDriveTimeUs { get; }
|
||||
|
||||
public int MeanFlowRate { get; }
|
||||
@ -50,12 +62,13 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.communication.C4.diagnosticLed.
|
||||
Adc24 = DiagnosticHex.ParseInt24(fields[0]);
|
||||
FieldStrength = DiagnosticHex.ParseUInt16(fields[1]);
|
||||
RawFlow = DiagnosticHex.ParseInt16(fields[2]);
|
||||
RawVolume = DiagnosticHex.ParseUInt24(fields[3]);
|
||||
RawVolume1to4 = DiagnosticHex.ParseUInt24(fields[3]); //1/4 ml Gal double
|
||||
CapacitorMv = DiagnosticHex.ParseUInt16(fields[4]);
|
||||
|
||||
// ---- State #4 specific ----
|
||||
FieldCalibration = DiagnosticHex.ParseUInt16(fields[5]);
|
||||
AsicTimestamp = DiagnosticHex.ParseUInt32(fields[6]);
|
||||
|
||||
AsicTimestampTicks = DiagnosticHex.ParseUInt32(fields[6]);
|
||||
FieldDriveTimeUs = DiagnosticHex.ParseByte(fields[7]);
|
||||
|
||||
MeanFlowRate = unchecked((int)DiagnosticHex.ParseUInt32(fields[8]));
|
||||
@ -71,7 +84,7 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.communication.C4.diagnosticLed.
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"DiagnosticLedState4Data: Adc24={Adc24}, FieldStrength={FieldStrength}, RawFlow={RawFlow}, RawVolume={RawVolume}, CapacitorMv={CapacitorMv}, FieldCalibration={FieldCalibration}, AsicTimestamp={AsicTimestamp}, FieldDriveTimeUs={FieldDriveTimeUs}, MeanFlowRate={MeanFlowRate}, Field1Measurement={Field1Measurement}, Field2Measurement={Field2Measurement}, IntegratorCalibrationPositive={IntegratorCalibrationPositive}, IntegratorCalibrationNegative={IntegratorCalibrationNegative}, AsicState={AsicState}";
|
||||
return $"DiagnosticLedState4Data: Adc24={Adc24}, FieldStrength={FieldStrength}, RawFlow={RawFlow}, RawVolume={RawVolume}, RawVolume1to4 = {RawVolume1to4}, RawVolumeGal={RawVolumeInGal}, CapacitorMv={CapacitorMv}, FieldCalibration={FieldCalibration}, AsicTimestamp={AsicTimestamp}, FieldDriveTimeUs={FieldDriveTimeUs}, MeanFlowRate={MeanFlowRate}, Field1Measurement={Field1Measurement}, Field2Measurement={Field2Measurement}, IntegratorCalibrationPositive={IntegratorCalibrationPositive}, IntegratorCalibrationNegative={IntegratorCalibrationNegative}, AsicState={AsicState}, RawLine={RawLine}";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@ -69,7 +69,7 @@ public sealed class DiagnosticLedState5Data : DiagnosticLedData
|
||||
Adc24 = DiagnosticHex.ParseInt24(fields[0]);
|
||||
FieldStrength = DiagnosticHex.ParseUInt16(fields[1]);
|
||||
RawFlow = DiagnosticHex.ParseInt16(fields[2]);
|
||||
RawVolume = DiagnosticHex.ParseUInt24(fields[3]);
|
||||
RawVolume1to4 = DiagnosticHex.ParseUInt24(fields[3]);
|
||||
CapacitorMv = DiagnosticHex.ParseUInt16(fields[4]);
|
||||
|
||||
// ---- State #5 specific ----
|
||||
|
||||
@ -69,7 +69,7 @@ public sealed class DiagnosticLedState6Data : DiagnosticLedData
|
||||
Adc24 = DiagnosticHex.ParseInt24(fields[0]);
|
||||
FieldStrength = DiagnosticHex.ParseUInt16(fields[1]);
|
||||
RawFlow = DiagnosticHex.ParseInt16(fields[2]);
|
||||
RawVolume = DiagnosticHex.ParseUInt24(fields[3]);
|
||||
RawVolume1to4 = DiagnosticHex.ParseUInt24(fields[3]);
|
||||
CapacitorMv = DiagnosticHex.ParseUInt16(fields[4]);
|
||||
|
||||
// ---- State #6 specific ----
|
||||
|
||||
@ -98,7 +98,7 @@ public sealed class DiagnosticLedState7Data : DiagnosticLedData
|
||||
Adc24 = DiagnosticHex.ParseInt24(fields[0]);
|
||||
FieldStrength = DiagnosticHex.ParseUInt16(fields[1]);
|
||||
RawFlow = DiagnosticHex.ParseInt16(fields[2]);
|
||||
RawVolume = DiagnosticHex.ParseUInt24(fields[3]);
|
||||
RawVolume1to4 = DiagnosticHex.ParseUInt24(fields[3]);
|
||||
CapacitorMv = DiagnosticHex.ParseUInt16(fields[4]);
|
||||
|
||||
// ---- State #6 fields ----
|
||||
|
||||
@ -0,0 +1,49 @@
|
||||
using TBF.Rig.TestMethods.iPerlCommunication.communication.C4.diagnosticLed.parserer;
|
||||
using TBF.Rig.TestMethods.iPerlCommunication.iPerlHead;
|
||||
|
||||
namespace TBF.Rig.TestMethods.iPerlCommunication.communication.C4.diagnosticLed.utils
|
||||
{
|
||||
public class DiagnostigLedDataByUnit
|
||||
{
|
||||
private readonly Common.Unit _unitFlow;
|
||||
private readonly Common.Unit _unitVolume;
|
||||
private readonly DiagnosticLedState4Data _data;
|
||||
|
||||
public DiagnostigLedDataByUnit(Common.Unit unitFlow, Common.Unit unitVolume, DiagnosticLedState4Data data)
|
||||
{
|
||||
this._unitFlow = unitFlow;
|
||||
this._unitVolume = unitVolume;
|
||||
this._data = data;
|
||||
}
|
||||
|
||||
public Common.Unit Unit => _unitVolume;
|
||||
public DiagnosticLedState4Data Data => _data;
|
||||
|
||||
public double RawFlow {
|
||||
get { return UnitVolume(_unitFlow, _data.RawFlow); }
|
||||
}
|
||||
|
||||
public double RawVolume
|
||||
{
|
||||
get { return Common.Units.ConvertFrom(_unitVolume, _data.RawVolume); }
|
||||
}
|
||||
|
||||
public double AsicTimestamp
|
||||
{
|
||||
get { return _data.AsicTimestamp; }
|
||||
}
|
||||
|
||||
public static double UnitVolume(Common.Unit unit, double volume)
|
||||
{
|
||||
return Common.Units.ConvertFrom(unit, volume); /// 1 liter
|
||||
}
|
||||
|
||||
public static uint DeltaTicks(uint oldTicks, uint newTicks)
|
||||
{
|
||||
return newTicks >= oldTicks
|
||||
? newTicks - oldTicks
|
||||
: uint.MaxValue - oldTicks + newTicks + 1;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -8,6 +8,7 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.communication.C4.hexLogger
|
||||
public static class HexFormatter
|
||||
{
|
||||
/// <summary>
|
||||
/// Byte to hex string.
|
||||
/// Formats a single byte as 0xNN.
|
||||
/// Example: 0x0D
|
||||
/// </summary>
|
||||
@ -17,7 +18,7 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.communication.C4.hexLogger
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// int to byte securely
|
||||
/// int to byte - securely
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
|
||||
@ -4,7 +4,7 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.communication
|
||||
{
|
||||
public class OpthoHeadService
|
||||
{
|
||||
protected static readonly ILog rfidDataLogger = LogManager.GetLogger("RfidData");
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@ -10,9 +10,11 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.communication
|
||||
{
|
||||
public class OptoHeadTest : IDisposable
|
||||
{
|
||||
protected static readonly ILog rfidDataLogger = LogManager.GetLogger("RfidData");
|
||||
//protected static readonly ILog rfidDataLogger = LogManager.GetLogger("RfidData");
|
||||
private static readonly ILog log = LogManager.GetLogger(typeof(OptoHeadTest));
|
||||
|
||||
private static SerialDriver serialDriver;
|
||||
private IperlHead iperlHead;
|
||||
private SerialDriver serialDriver;
|
||||
|
||||
public static SerialDriver BuildConnection(IperlHead iHead)
|
||||
{
|
||||
@ -27,29 +29,36 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.communication
|
||||
|
||||
}
|
||||
|
||||
public OptoHeadTest(IperlHead iperlHead)
|
||||
{
|
||||
this.iperlHead = iperlHead;
|
||||
}
|
||||
|
||||
private void CloseConnection()
|
||||
{
|
||||
if (serialDriver != null)
|
||||
serialDriver.CloseConnection();
|
||||
serialDriver = null;
|
||||
}
|
||||
|
||||
|
||||
public static string ReadRequest_PCB(ref IperlHead iHead)
|
||||
public string ReadRequest_PCB()
|
||||
{
|
||||
if (iHead.DebugLevel == DebugMode.Simulate)
|
||||
if (iperlHead.DebugLevel == DebugMode.Simulate)
|
||||
{
|
||||
return "-OK Simulated response-";
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (iHead != null)
|
||||
if (iperlHead != null)
|
||||
{
|
||||
if (serialDriver == null)
|
||||
serialDriver = BuildConnection(iHead);
|
||||
serialDriver = BuildConnection(iperlHead);
|
||||
|
||||
RadioService headService = new RadioService(serialDriver);
|
||||
string serialNo = headService.ReadRequest_PCB(ref iHead);
|
||||
string serialNo = headService.ReadRequest_PCB(ref iperlHead);
|
||||
log.Info($"PCB Number: {serialNo} on COM{iperlHead.RfidComPortNr} serialDriver: {serialDriver}");
|
||||
return serialNo;
|
||||
}
|
||||
}
|
||||
@ -66,12 +75,13 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.communication
|
||||
/// </summary>
|
||||
/// <param name="iHead"></param>
|
||||
/// <returns></returns>
|
||||
public static bool SetTestMode(ref IperlHead iHead)
|
||||
public bool SetTestMode()
|
||||
{
|
||||
bool activityModeActive = SetActivityMode_Active(iHead);
|
||||
bool optActiveMode = SetOptTestMode(ref iHead);
|
||||
|
||||
log.Debug("SetTestMode called for iHead: " + iperlHead.ToString());
|
||||
bool activityModeActive = SetActivityMode_Active();
|
||||
bool optActiveMode = SetOptTestMode();
|
||||
|
||||
log.Debug("SetTestMode result: optoMod-> " + optActiveMode + " meterModeActive ->" + activityModeActive);
|
||||
return (optActiveMode && activityModeActive);
|
||||
}
|
||||
|
||||
@ -80,10 +90,11 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.communication
|
||||
/// </summary>
|
||||
/// <param name="iHead"></param>
|
||||
/// <returns></returns>
|
||||
public static bool SetActiveMode(ref IperlHead iHead)
|
||||
public bool SetActiveMode()
|
||||
{
|
||||
bool optActiveMode = SetOptActiveMode(iHead);
|
||||
bool activityModeIdle = SetActivityMode_Idle(iHead);
|
||||
log.Debug("SetActiveMode called for iHead: " + iperlHead.ToString());
|
||||
bool optActiveMode = SetOptActiveMode(iperlHead);
|
||||
bool activityModeIdle = SetActivityMode_Idle();
|
||||
|
||||
return (optActiveMode && activityModeIdle);
|
||||
}
|
||||
@ -94,9 +105,9 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.communication
|
||||
/// <param name="iHead"></param>
|
||||
/// <param name="isTestModeSuccessful"></param>
|
||||
/// <returns></returns>
|
||||
public static string SetTestMode(ref IperlHead iHead, ref bool isTestModeSuccessful)
|
||||
public string SetTestMode(ref bool isTestModeSuccessful)
|
||||
{
|
||||
if (iHead.DebugLevel == DebugMode.Simulate)
|
||||
if (iperlHead.DebugLevel == DebugMode.Simulate)
|
||||
{
|
||||
isTestModeSuccessful = true;
|
||||
return "-OK Simulated response-";
|
||||
@ -104,10 +115,12 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.communication
|
||||
|
||||
try
|
||||
{
|
||||
isTestModeSuccessful = SetTestMode(ref iHead);
|
||||
return isTestModeSuccessful ? "Set Test Mode - OK" : "Set Test Mode - FAILED";
|
||||
bool testMode = SetTestMode();
|
||||
isTestModeSuccessful = testMode;
|
||||
return testMode ? "Set Test Mode - OK" : "Set Test Mode - FAILED";
|
||||
}catch (Exception ex)
|
||||
{
|
||||
log.Error("SetTestMode() - Exception:" + ex.StackTrace);
|
||||
return "Set Test Mode - Exception";
|
||||
}
|
||||
}
|
||||
@ -120,18 +133,19 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.communication
|
||||
/// <param name="iHead"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="Exception"></exception>
|
||||
private static bool SetOptTestMode(ref IperlHead iHead)
|
||||
private bool SetOptTestMode()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (iHead != null)
|
||||
if (iperlHead != null)
|
||||
{
|
||||
if (serialDriver == null)
|
||||
serialDriver = BuildConnection(iHead);
|
||||
serialDriver = BuildConnection(iperlHead);
|
||||
|
||||
RadioService headService = new RadioService(serialDriver);
|
||||
var optTestMode = headService.SetOptTestMode(iHead);
|
||||
iHead.ConfigStruct.OpthoStatusMode = optTestMode ? DiagnosticLedState.State4 : DiagnosticLedState.StatusUnknown;
|
||||
bool optTestMode = headService.SetOptTestMode(iperlHead);
|
||||
if (iperlHead.ConfigStruct != null)
|
||||
iperlHead.ConfigStruct.OpthoStatusMode = optTestMode ? DiagnosticLedState.State4 : DiagnosticLedState.StatusUnknown;
|
||||
return optTestMode;
|
||||
}
|
||||
}
|
||||
@ -148,9 +162,9 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.communication
|
||||
/// <param name="iHead"></param>
|
||||
/// <param name="isTestModeSuccessful"></param>
|
||||
/// <returns></returns>
|
||||
public static string SetActiveMode(ref IperlHead iHead, ref bool isTestModeSuccessful)
|
||||
public string SetActiveMode(ref bool isTestModeSuccessful)
|
||||
{
|
||||
if (iHead.DebugLevel == DebugMode.Simulate)
|
||||
if (iperlHead.DebugLevel == DebugMode.Simulate)
|
||||
{
|
||||
isTestModeSuccessful = true;
|
||||
return "-OK Simulated response-";
|
||||
@ -158,8 +172,9 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.communication
|
||||
|
||||
try
|
||||
{
|
||||
isTestModeSuccessful = SetActiveMode(ref iHead);
|
||||
return isTestModeSuccessful ? "Set Active Mode - OK" : "Set Active Mode - FAILED";
|
||||
bool activeMode = SetActiveMode();
|
||||
isTestModeSuccessful = activeMode;
|
||||
return activeMode ? "Set Active Mode - OK" : "Set Active Mode - FAILED";
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@ -172,7 +187,7 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.communication
|
||||
/// <param name="iHead"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="Exception"></exception>
|
||||
private static bool SetOptActiveMode(IperlHead iHead)
|
||||
private bool SetOptActiveMode(IperlHead iHead)
|
||||
{
|
||||
try
|
||||
{
|
||||
@ -180,7 +195,7 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.communication
|
||||
{
|
||||
if (serialDriver == null)
|
||||
serialDriver = BuildConnection(iHead);
|
||||
|
||||
|
||||
RadioService headService = new RadioService(serialDriver);
|
||||
return headService.SetOptActiveMode(iHead);
|
||||
}
|
||||
@ -199,17 +214,18 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.communication
|
||||
/// <param name="iHead"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="Exception"></exception>
|
||||
private static bool SetActivityMode_Active(IperlHead iHead)
|
||||
private bool SetActivityMode_Active()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (iHead != null)
|
||||
if (iperlHead != null)
|
||||
{
|
||||
if (serialDriver == null)
|
||||
serialDriver = BuildConnection(iHead);
|
||||
serialDriver = BuildConnection(iperlHead);
|
||||
|
||||
log.Debug("SetActivityMode_Active called for iHead: " + iperlHead.ToString() + " serialDriver: " + serialDriver);
|
||||
RadioService headService = new RadioService(serialDriver);
|
||||
return headService.SetActivityMode_Active(iHead);
|
||||
return headService.SetActivityMode_Active(iperlHead);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
@ -226,17 +242,19 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.communication
|
||||
/// <param name="iHead"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="Exception"></exception>
|
||||
private static bool SetActivityMode_Idle(IperlHead iHead)
|
||||
private bool SetActivityMode_Idle()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (iHead != null)
|
||||
if (iperlHead != null)
|
||||
{
|
||||
if (serialDriver == null)
|
||||
serialDriver = BuildConnection(iHead);
|
||||
serialDriver = BuildConnection(iperlHead);
|
||||
|
||||
log.Debug("SetActivityMode_Idle called for iHead: " + iperlHead.ToString() + " serialDriver: " + serialDriver);
|
||||
|
||||
RadioService headService = new RadioService(serialDriver);
|
||||
return headService.SetActivityMode_Idle(iHead);
|
||||
return headService.SetActivityMode_Idle(iperlHead);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
@ -260,9 +278,9 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.communication
|
||||
/// <param name="iHead"></param>
|
||||
/// <param name="ledState"></param>
|
||||
/// <returns></returns>
|
||||
public static bool ReadConfiguration(ref IperlHead iHead, DiagnosticLedState ledState )
|
||||
public bool ReadConfiguration(DiagnosticLedState ledState )
|
||||
{
|
||||
if (iHead.DebugLevel == DebugMode.Simulate)
|
||||
if (iperlHead.DebugLevel == DebugMode.Simulate)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@ -270,26 +288,28 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.communication
|
||||
try
|
||||
{
|
||||
|
||||
if (iHead != null)
|
||||
if (iperlHead != null)
|
||||
{
|
||||
iHead.ConfigStruct = new ConfigStruct();
|
||||
iperlHead.ConfigStruct = new ConfigStruct();
|
||||
|
||||
if (serialDriver == null)
|
||||
serialDriver = BuildConnection(iHead);
|
||||
serialDriver = BuildConnection(iperlHead);
|
||||
|
||||
RadioService headService = new RadioService(serialDriver);
|
||||
iHead.ConfigStruct.PCBNumberString = headService.ReadRequest_PCB(ref iHead);
|
||||
iHead.ConfigStruct.StatusMode = headService.GetActivityStatusMode(iHead);
|
||||
iperlHead.ConfigStruct.PCBNumberString = headService.ReadRequest_PCB(ref iperlHead);
|
||||
iperlHead.ConfigStruct.StatusMode = headService.GetActivityStatusMode(iperlHead);
|
||||
iperlHead.ConfigStruct.Unit = headService.GetUnit(iperlHead);
|
||||
|
||||
if (ledState != DiagnosticLedState.StatusUnknown) // do set
|
||||
{
|
||||
iHead.ConfigStruct.OpthoStatusMode = headService.SetOptoStatusMode(iHead, ledState);
|
||||
iperlHead.ConfigStruct.OpthoStatusMode = headService.SetOptoStatusMode(iperlHead, ledState);
|
||||
}
|
||||
else
|
||||
{
|
||||
iHead.ConfigStruct.OpthoStatusMode = DiagnosticLedState.StatusUnknown;
|
||||
iperlHead.ConfigStruct.OpthoStatusMode = DiagnosticLedState.StatusUnknown;
|
||||
}
|
||||
|
||||
iHead.ConfigStruct.Version = headService.GetVersion(iHead);
|
||||
iperlHead.ConfigStruct.Version = headService.GetVersion(iperlHead);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
using log4net;
|
||||
using TBF.Rig.TestMethods.iPerlCommunication.communication.C4.diagnosticLed;
|
||||
using TBF.Rig.TestMethods.iPerlCommunication.communication.C4.IperlHatProtocol;
|
||||
using TBF.Rig.TestMethods.iPerlCommunication.communication.C4.protocolCommons;
|
||||
@ -8,6 +9,7 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.communication
|
||||
{
|
||||
public class RadioService
|
||||
{
|
||||
private static readonly ILog log = LogManager.GetLogger(typeof(RadioService));
|
||||
|
||||
static string okResponse = "Command complete, no errors";
|
||||
static string errorResponse = "Unable to execute";
|
||||
@ -16,6 +18,7 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.communication
|
||||
public RadioService(SerialDriver serialDriver)
|
||||
{
|
||||
this.serialDriver = serialDriver;
|
||||
log.Debug("RadioService created with serialDriver= " + serialDriver + "");
|
||||
}
|
||||
|
||||
public string ReadRequest_PCB(ref IperlHead iHead)
|
||||
@ -97,6 +100,7 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.communication
|
||||
var parser = new IperlHatFrameParser();
|
||||
IperlHatResponse decoded = parser.Parse(rawData);
|
||||
|
||||
log.Debug("SetOptoStatusMode isOK: " + decoded.IsOk);
|
||||
// if is response ok - it set it correctly
|
||||
if (!decoded.IsOk)
|
||||
return DiagnosticLedState.StatusUnknown;
|
||||
@ -135,6 +139,7 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.communication
|
||||
// parse rawData
|
||||
var parser = new IperlHatFrameParser();
|
||||
IperlHatResponse decoded = parser.Parse(rawData);
|
||||
log.Debug("GetVersion isOK: " + decoded.IsOk);
|
||||
if (decoded.IsOk)
|
||||
{
|
||||
return decoded.GetAsciiPayload();
|
||||
@ -158,7 +163,7 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.communication
|
||||
.AddSubCommand(ProtocolStatuses.Active) // Active
|
||||
.BuildBytes();
|
||||
|
||||
byte[] rawData = serialDriver.SendAndWait(request, 2000);
|
||||
byte[] rawData = serialDriver.SendAndWait(request, 5000);
|
||||
if (rawData == null)
|
||||
return false;
|
||||
|
||||
@ -166,6 +171,7 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.communication
|
||||
// parse rawData
|
||||
var parser = new IperlHatFrameParser();
|
||||
IperlHatResponse decoded = parser.Parse(rawData);
|
||||
log.Debug("SetActivityMode_Active isOK: " + decoded.IsOk);
|
||||
return decoded.IsOk;
|
||||
}
|
||||
|
||||
@ -191,6 +197,7 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.communication
|
||||
// parse rawData
|
||||
var parser = new IperlHatFrameParser();
|
||||
IperlHatResponse decoded = parser.Parse(rawData);
|
||||
log.Debug("SetActivityMode_Idle isOK: " + decoded.IsOk);
|
||||
return decoded.IsOk;
|
||||
}
|
||||
|
||||
@ -202,11 +209,13 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.communication
|
||||
}
|
||||
|
||||
//Set LED to state 4
|
||||
byte[] request = new IperlHatFrameBuilder()
|
||||
.AddDiagnosticLedState(DiagnosticLedState.State4)
|
||||
var request = new IperlHatFrameBuilder()
|
||||
.RequestResponse(true)
|
||||
.AddDeviceCommand(ProtocolDeviceSubCommand.SetDiagnosticLEDState)
|
||||
.AddPayload(DiagnosticLedState.State4)
|
||||
.BuildBytes();
|
||||
|
||||
byte[] rawData = serialDriver.SendAndWait(request, 1000);
|
||||
byte[] rawData = serialDriver.SendAndWait(request, 5000);
|
||||
if (rawData == null)
|
||||
return false;
|
||||
|
||||
@ -214,7 +223,9 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.communication
|
||||
// parse rawData
|
||||
var parser = new IperlHatFrameParser();
|
||||
IperlHatResponse decoded = parser.Parse(rawData);
|
||||
return decoded.IsOk;
|
||||
bool isOk = decoded.IsOk;
|
||||
log.Debug("SetOptTestMode isOK: " + isOk);
|
||||
return isOk;
|
||||
|
||||
}
|
||||
|
||||
@ -231,11 +242,13 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.communication
|
||||
}
|
||||
|
||||
//Set LED to state 1
|
||||
byte[] request = new IperlHatFrameBuilder()
|
||||
.AddDiagnosticLedState(DiagnosticLedState.StateOFF)
|
||||
var request = new IperlHatFrameBuilder()
|
||||
.RequestResponse(true)
|
||||
.AddDeviceCommand(ProtocolDeviceSubCommand.SetDiagnosticLEDState)
|
||||
.AddPayload(DiagnosticLedState.StateOFF)
|
||||
.BuildBytes();
|
||||
|
||||
byte[] rawData = serialDriver.SendAndWait(request, 2000);
|
||||
byte[] rawData = serialDriver.SendAndWait(request, 5000);
|
||||
if (rawData == null)
|
||||
return false;
|
||||
|
||||
@ -243,7 +256,41 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.communication
|
||||
// parse rawData
|
||||
var parser = new IperlHatFrameParser();
|
||||
IperlHatResponse decoded = parser.Parse(rawData);
|
||||
log.Debug("SetOptActiveMode isOK: " + decoded.IsOk);
|
||||
return decoded.IsOk;
|
||||
}
|
||||
|
||||
public string GetUnit(IperlHead iperlHead)
|
||||
{
|
||||
if (!serialDriver.IsOpen())
|
||||
{
|
||||
serialDriver.Open();
|
||||
}
|
||||
|
||||
var request = new IperlHatFrameBuilder()
|
||||
.RequestResponse(true)
|
||||
.AddCommand(ProtocolCommand.ViewFactoryId)
|
||||
.BuildBytes();
|
||||
|
||||
|
||||
byte[] rawData = serialDriver.SendAndWait(request, 10000);
|
||||
if (rawData == null)
|
||||
return null;
|
||||
|
||||
// parse rawData
|
||||
var parser = new IperlHatFrameParser();
|
||||
IperlHatResponse decoded = parser.Parse(rawData);
|
||||
if (decoded.IsOk)
|
||||
{
|
||||
string asciiPayload = decoded.GetAsciiPayload();
|
||||
if (iperlHead.ConfigStruct != null) // store mechanism
|
||||
{
|
||||
iperlHead.ConfigStruct.Unit = asciiPayload;
|
||||
}
|
||||
return asciiPayload;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -4,11 +4,13 @@ using System.Diagnostics;
|
||||
using System.IO.Ports;
|
||||
using System.Threading;
|
||||
using FluentNHibernate.Conventions;
|
||||
using TBF.Rig.TestMethods.iPerlCommunication.communication.C4.hexLogger;
|
||||
|
||||
namespace TBF.Rig.TestMethods.iPerlCommunication.communication.Utils
|
||||
{
|
||||
public class SerialDriver : IDisposable
|
||||
{
|
||||
readonly log4net.ILog log = log4net.LogManager.GetLogger(typeof(SerialDriver));
|
||||
public string ErrorMessage { get; private set; }
|
||||
private List<byte> SerialPortReadBuffer = new List<byte>();
|
||||
|
||||
@ -110,6 +112,8 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.communication.Utils
|
||||
ErrorMessage = $"COM error: Can't open {comPort}.";
|
||||
return false;
|
||||
}
|
||||
|
||||
log.Debug("SerialDriver opened successfully for port: " + comPort);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -172,6 +176,7 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.communication.Utils
|
||||
_serialPort.DiscardInBuffer();
|
||||
_binMessages.Clear();
|
||||
_responseReceived.Reset();
|
||||
SerialPortReadBuffer.Clear();
|
||||
_isReading = true;
|
||||
}
|
||||
|
||||
@ -188,7 +193,7 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.communication.Utils
|
||||
|
||||
try
|
||||
{
|
||||
Thread.Sleep(5);
|
||||
//Thread.Sleep(5);
|
||||
|
||||
if (!SerialPortReadBuffer.IsEmpty())
|
||||
{
|
||||
@ -204,13 +209,13 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.communication.Utils
|
||||
byte readByte = (byte)_serialPort.ReadByte();
|
||||
|
||||
//I have START
|
||||
if (readByte == TestMethods.iPerlCommunication.communication.C4.IperlHatProtocol.IperlHatProtocolConstants.Start)
|
||||
if (readByte == C4.IperlHatProtocol.IperlHatProtocolConstants.Start)
|
||||
{
|
||||
iWordCounter++;
|
||||
isStart = true;
|
||||
}
|
||||
// I have QUESTION
|
||||
if (readByte == TestMethods.iPerlCommunication.communication.C4.IperlHatProtocol.IperlHatProtocolConstants.Question)
|
||||
if (readByte == C4.IperlHatProtocol.IperlHatProtocolConstants.Question)
|
||||
{
|
||||
iWordCounter++;
|
||||
isQuestion = true;
|
||||
@ -231,12 +236,16 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.communication.Utils
|
||||
}
|
||||
|
||||
//If we have enough bytes
|
||||
if (isStart && iLength > 0 && SerialPortReadBuffer.Count >= iLength)
|
||||
if (isStart && iLength > 0
|
||||
&& (SerialPortReadBuffer.Count >= iLength ||
|
||||
readByte == C4.IperlHatProtocol.IperlHatProtocolConstants.End
|
||||
)
|
||||
)
|
||||
{
|
||||
break;
|
||||
}
|
||||
//if we read END
|
||||
if (isQuestion && readByte == TestMethods.iPerlCommunication.communication.C4.IperlHatProtocol.IperlHatProtocolConstants.End)
|
||||
if (isQuestion && readByte == C4.IperlHatProtocol.IperlHatProtocolConstants.End)
|
||||
{
|
||||
break;
|
||||
}
|
||||
@ -264,11 +273,18 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.communication.Utils
|
||||
if (!IsOpen())
|
||||
throw new InvalidOperationException("Serial port not open");
|
||||
|
||||
log.Debug("SendAndWait() - TX: " + HexFormatter.ToHex(data));
|
||||
PrepareReading();
|
||||
_serialPort.Write(data, 0, data.Length);
|
||||
|
||||
if (!_responseReceived.WaitOne(timeoutMs))
|
||||
{
|
||||
log.Error("SendAndWait() - Response timeout! Details: " +
|
||||
" SerialPortReadBuffer: " + HexFormatter.ToHex(SerialPortReadBuffer.ToArray()) +
|
||||
" _binMessages" + HexFormatter.ToHex(_binMessages.ToArray()) +
|
||||
"_responseReceived: " + _responseReceived.WaitOne(0)
|
||||
);
|
||||
|
||||
ErrorMessage = "COM error: response timeout";
|
||||
return null;
|
||||
}
|
||||
@ -283,5 +299,10 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.communication.Utils
|
||||
{
|
||||
CloseConnection();
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return "SerialDriver: " + _serialPort.PortName + " (opened status:" + _serialPort.IsOpen +")";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -838,14 +838,27 @@ namespace TBF.Rig.TestMethods.iPerlCommunication
|
||||
|
||||
/// Read configuration
|
||||
|
||||
if (OptoHeadTest.ReadConfiguration(ref ihead, DiagnosticLedState.StatusUnknown))
|
||||
if (ihead.OptoHeadTest.ReadConfiguration(DiagnosticLedState.State4))
|
||||
{
|
||||
error = CommErr.None;
|
||||
ihead.ConfigStruct = new ConfigStruct(); //.FromByteArray(config);
|
||||
resultStr = ihead.ConfigStruct.ToString(1);
|
||||
//read, set and create ConfigStruct is set directly in method ReadConfiguration
|
||||
//ihead.ConfigStruct = new ConfigStruct(); //.FromByteArray(config);
|
||||
if (ihead.ConfigStruct != null)
|
||||
{
|
||||
resultStr = ihead.ConfigStruct.ToString(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
resultStr = "Data not available";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
resultStr = "Failed to read configuration";
|
||||
}
|
||||
|
||||
return error + Math.Max(0, Math.Min(readRetVal, 4));
|
||||
//return error + Math.Max(0, Math.Min(readRetVal, 4));
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
@ -861,6 +874,7 @@ namespace TBF.Rig.TestMethods.iPerlCommunication
|
||||
/// <returns>true on success</returns>
|
||||
static CommErr SetTestMode(int threadId, IperlHead ihead, ref string resultStr)
|
||||
{
|
||||
log.Debug("SetTestMode threadId=" + threadId + ", ihead=" + ihead.ToString());
|
||||
if (ihead.ConfigStruct == null)
|
||||
{
|
||||
log.Debug("ConfigStruct is null - created new in SetTestMode()");
|
||||
@ -874,7 +888,7 @@ namespace TBF.Rig.TestMethods.iPerlCommunication
|
||||
///
|
||||
|
||||
//string testModeConfigStr = multiTestParams[currentActivityStep].Activity.Substring(SetTestModeStr.Length + 1);
|
||||
if (OptoHeadTest.SetTestMode(ref ihead))
|
||||
if (ihead.OptoHeadTest.SetTestMode())
|
||||
{
|
||||
log.Debug("test mode activated now");
|
||||
testModeConfig = ihead.ConfigStruct.OpthoStatusMode;
|
||||
@ -899,7 +913,7 @@ namespace TBF.Rig.TestMethods.iPerlCommunication
|
||||
error = CommErr.Verify;
|
||||
|
||||
//TODO BUMI use read config
|
||||
if (OptoHeadTest.ReadConfiguration(ref ihead, DiagnosticLedState.State4))
|
||||
if (ihead.OptoHeadTest.ReadConfiguration(DiagnosticLedState.State4))
|
||||
{
|
||||
if ((ihead.ConfigStruct.MeterState == ProtocolStatuses.Active) &&
|
||||
(ihead.ConfigStruct.TestModeConfig == testModeConfig))
|
||||
@ -924,11 +938,12 @@ namespace TBF.Rig.TestMethods.iPerlCommunication
|
||||
/// <returns>true on success</returns>
|
||||
static CommErr SetActiveMode(int threadId, IperlHead ihead, ref string resultStr)
|
||||
{
|
||||
log.Debug("SetActiveMode threadId=" + threadId);
|
||||
CommErr error = CommErr.CmdActive;
|
||||
|
||||
/// Switch to active mode
|
||||
|
||||
if (OptoHeadTest.SetActiveMode(ref ihead))
|
||||
if (ihead.OptoHeadTest.SetActiveMode())
|
||||
{
|
||||
error = CommErr.None;
|
||||
}
|
||||
@ -2651,7 +2666,7 @@ namespace TBF.Rig.TestMethods.iPerlCommunication
|
||||
switch (tag)
|
||||
{
|
||||
case "ReadPCB":
|
||||
txt = OptoHeadTest.ReadRequest_PCB(ref iHead);
|
||||
txt = iHead.OptoHeadTest.ReadRequest_PCB();
|
||||
break;
|
||||
case "WriteRequestPort_u8_Customer_Text":
|
||||
txt = "Not Supported NOW!";//OpticalHeadTest.WriteRequestPort_u8_Customer_Text(iHead);
|
||||
@ -2660,10 +2675,10 @@ namespace TBF.Rig.TestMethods.iPerlCommunication
|
||||
txt = "Not Supported NOW!";//OpticalHeadTest.OpenSealing(iHead);
|
||||
break;
|
||||
case "StartTestMode":
|
||||
txt = OptoHeadTest.SetTestMode(ref iHead, ref success);
|
||||
txt = iHead.OptoHeadTest.SetTestMode(ref success);
|
||||
break;
|
||||
case "TurnOffTestMode":
|
||||
txt = OptoHeadTest.SetActiveMode(ref iHead, ref success);
|
||||
txt = iHead.OptoHeadTest.SetActiveMode(ref success);
|
||||
break;
|
||||
case "TurnOffRadio":
|
||||
txt = "Not Supported NOW!";//OpticalHeadTest.TurnOffRadio(iHead);
|
||||
|
||||
@ -17,8 +17,8 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.iPerlHead
|
||||
public string PCBNumberString; // dynamic
|
||||
public ProtocolStatuses StatusMode; // byte
|
||||
public DiagnosticLedState OpthoStatusMode;// byte
|
||||
public string Unit; //dynamic
|
||||
public string Version; // dynamic
|
||||
|
||||
|
||||
public ConfigStruct()
|
||||
{
|
||||
@ -80,20 +80,25 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.iPerlHead
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format(
|
||||
"Config: V{0} PCB#={1} StatusMode={2}",
|
||||
Version,
|
||||
"Config: PCB#={0} StatusMode={1} Unit={2} V{3}",
|
||||
|
||||
GetPcbNrString(),
|
||||
StatusMode
|
||||
StatusMode,
|
||||
Unit,
|
||||
Version
|
||||
);
|
||||
}
|
||||
|
||||
public string ToString(int sel)
|
||||
{
|
||||
return string.Format("{0} PCB#={1} StatusMode={2}",
|
||||
Version,
|
||||
GetPcbNrString(),
|
||||
StatusMode
|
||||
);
|
||||
return string.Format(
|
||||
"Config: PCB#={0} StatusMode={1} Unit={2} V{3}",
|
||||
|
||||
GetPcbNrString(),
|
||||
StatusMode,
|
||||
Unit,
|
||||
Version
|
||||
);
|
||||
}
|
||||
|
||||
public virtual void WriteBinary(BinaryWriter writer)
|
||||
@ -115,16 +120,27 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.iPerlHead
|
||||
// 2) write string bytes
|
||||
writer.Write(PCBNumberStringBytes);
|
||||
|
||||
// Convert string to bytes (UTF8 is standard)
|
||||
byte[] unitBytes = Encoding.UTF8.GetBytes(Unit);
|
||||
// 1) write length
|
||||
writer.Write(unitBytes.Length);
|
||||
// 2) write string bytes
|
||||
writer.Write(unitBytes);
|
||||
//writer.Write(Version);
|
||||
|
||||
}
|
||||
|
||||
public virtual void ReadBinary(BinaryReader reader)
|
||||
{
|
||||
int ReadBytesCount = 0;
|
||||
// ---- Test Data type ----
|
||||
var readByte = reader.ReadByte();
|
||||
if (readByte != 0x11) return; // not correct version
|
||||
ReadBytesCount++;
|
||||
// ---- Version ----
|
||||
// 1) read length
|
||||
int length = reader.ReadInt32();
|
||||
ReadBytesCount += 4 + length;
|
||||
// 2) read string bytes
|
||||
byte[] versionBytes = reader.ReadBytes(length);
|
||||
// 3) convert back to string
|
||||
@ -132,11 +148,19 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.iPerlHead
|
||||
// ---- PCB Number ----
|
||||
// 1) read length
|
||||
int lengthPCB = reader.ReadInt32();
|
||||
ReadBytesCount += 4 + lengthPCB;
|
||||
// 2) read string bytes
|
||||
byte[] bytesPCB = reader.ReadBytes(lengthPCB);
|
||||
// 3) convert back to string
|
||||
PCBNumberString = Encoding.UTF8.GetString(bytesPCB);
|
||||
|
||||
// ---- Unit ----
|
||||
// 1) read length
|
||||
int lengthUnit = reader.ReadInt32();
|
||||
ReadBytesCount += 4 + lengthUnit;
|
||||
// 2) read string bytes
|
||||
byte[] bytesUnit = reader.ReadBytes(lengthUnit);
|
||||
// 3) convert back to string
|
||||
Unit = Encoding.UTF8.GetString(bytesUnit);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -11,40 +11,35 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.iPerlHead
|
||||
{
|
||||
private static readonly ILog log = LogManager.GetLogger(typeof(IperlHead));
|
||||
|
||||
const int FIFO_SIZE = 64; /// 8 sec. @ 8Hz
|
||||
const double MAX_OPTO_DROPOUT = 4.5; /// sec.
|
||||
|
||||
const int FIFO_SIZE = 64; // 8 sec @ 8Hz
|
||||
const double MAX_OPTO_DROPOUT = 4.5; // sec
|
||||
|
||||
Int64[] volumeRawFifo; /// Volume FIFO buffer
|
||||
Int64[] timestampFifo; /// Timestamp FIFO buffer
|
||||
private readonly double[] volumeRawFifo;
|
||||
private readonly double[] timestampFifo; // centered timestamps
|
||||
|
||||
int fifoCount; /// Number of valid FIFO items
|
||||
int fifoIx; /// Index of the next FIFO item
|
||||
DateTime lastFifoWriteTime; /// Time of the last write to FIFO
|
||||
private int fifoCount;
|
||||
private int fifoIx;
|
||||
private DateTime lastFifoWriteTime;
|
||||
|
||||
///
|
||||
/// Sums for linear regression calculation
|
||||
///
|
||||
decimal sumXX;
|
||||
decimal sumX;
|
||||
decimal sumXY;
|
||||
decimal sumY;
|
||||
decimal N;
|
||||
// regression sums (double is ideal here)
|
||||
private double sumXX;
|
||||
private double sumX;
|
||||
private double sumXY;
|
||||
private double sumY;
|
||||
|
||||
double minSlope; /// max. slope of the regressed line, always positive or 0
|
||||
double maxSlope; /// min. slope of the regressed line, always negative or 0
|
||||
private double minSlope;
|
||||
private double maxSlope;
|
||||
|
||||
// timestamp centering for numerical stability
|
||||
private double firstTimestamp = double.NaN;
|
||||
|
||||
public FlowDirectionDetection()
|
||||
{
|
||||
volumeRawFifo = new Int64[FIFO_SIZE];
|
||||
timestampFifo = new Int64[FIFO_SIZE];
|
||||
volumeRawFifo = new double[FIFO_SIZE];
|
||||
timestampFifo = new double[FIFO_SIZE];
|
||||
ClearFifo();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Clear FIFO data
|
||||
/// </summary>
|
||||
public void ClearFifo()
|
||||
{
|
||||
fifoCount = 0;
|
||||
@ -55,94 +50,93 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.iPerlHead
|
||||
sumX = 0;
|
||||
sumXY = 0;
|
||||
sumY = 0;
|
||||
N = 0;
|
||||
|
||||
minSlope = 0;
|
||||
maxSlope = 0;
|
||||
firstTimestamp = double.NaN;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Write data to FIFO
|
||||
/// Add sample to rolling FIFO and update regression sums
|
||||
/// </summary>
|
||||
/// <param name="volumeRaw">Volume</param>
|
||||
/// <param name="timestamp">Time stamp</param>
|
||||
public void WriteToFifo(Int64 volumeRaw, Int64 timestamp)
|
||||
public void WriteToFifo(double volumeRaw, double timestamp)
|
||||
{
|
||||
///
|
||||
/// Update sums for linear regression calculation
|
||||
///
|
||||
// establish time origin (CRITICAL for double precision)
|
||||
if (double.IsNaN(firstTimestamp))
|
||||
firstTimestamp = timestamp;
|
||||
|
||||
double x = timestamp - firstTimestamp; // centered time
|
||||
double y = volumeRaw;
|
||||
|
||||
// remove oldest sample if buffer full
|
||||
if (fifoCount == FIFO_SIZE)
|
||||
{
|
||||
/// Buffer is already full, the oldest item will be re-written
|
||||
sumXX -= timestampFifo[fifoIx] * timestampFifo[fifoIx];
|
||||
sumX -= timestampFifo[fifoIx];
|
||||
sumXY -= timestampFifo[fifoIx] * volumeRawFifo[fifoIx];
|
||||
sumY -= volumeRawFifo[fifoIx];
|
||||
N--;
|
||||
}
|
||||
sumXX += timestamp * timestamp;
|
||||
sumX += timestamp;
|
||||
sumXY += timestamp * volumeRaw;
|
||||
sumY += volumeRaw;
|
||||
N++;
|
||||
double oldX = timestampFifo[fifoIx];
|
||||
double oldY = volumeRawFifo[fifoIx];
|
||||
|
||||
sumXX -= oldX * oldX;
|
||||
sumX -= oldX;
|
||||
sumXY -= oldX * oldY;
|
||||
sumY -= oldY;
|
||||
}
|
||||
else
|
||||
{
|
||||
fifoCount++;
|
||||
}
|
||||
|
||||
// add new sample
|
||||
sumXX += x * x;
|
||||
sumX += x;
|
||||
sumXY += x * y;
|
||||
sumY += y;
|
||||
|
||||
// store sample
|
||||
timestampFifo[fifoIx] = x;
|
||||
volumeRawFifo[fifoIx] = y;
|
||||
|
||||
///
|
||||
/// Save new values to FIFO
|
||||
///
|
||||
volumeRawFifo[fifoIx] = volumeRaw;
|
||||
timestampFifo[fifoIx] = timestamp;
|
||||
fifoIx = (fifoIx + 1) % FIFO_SIZE;
|
||||
fifoCount = Math.Min(fifoCount + 1, FIFO_SIZE);
|
||||
lastFifoWriteTime = DateTime.Now;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Determine whether there are enough recent FIFO data
|
||||
/// </summary>
|
||||
/// <returns>true when data valid</returns>
|
||||
public bool AreFifoDataValid()
|
||||
{
|
||||
return (DateTime.Now.Subtract(lastFifoWriteTime).TotalSeconds <= MAX_OPTO_DROPOUT) && (fifoCount == FIFO_SIZE);
|
||||
return (DateTime.Now.Subtract(lastFifoWriteTime).TotalSeconds <= MAX_OPTO_DROPOUT)
|
||||
&& (fifoCount == FIFO_SIZE);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Verify whether the flow direction is correct
|
||||
/// </summary>
|
||||
/// <returns>OptoHeadState.OptoAndDirOK, OptoHeadState.OptoNok or OptoHeadState.DirNok</returns>
|
||||
public OptoHeadState CheckFlowDirection(Counting counting, string iPerlHeadName)
|
||||
{
|
||||
if (!AreFifoDataValid()) return OptoHeadState.OptoNok;
|
||||
if (!AreFifoDataValid())
|
||||
return OptoHeadState.OptoNok;
|
||||
|
||||
try
|
||||
{
|
||||
decimal numer = N * sumXY - sumX * sumY;
|
||||
decimal denom = N * sumXX - sumX * sumX;
|
||||
double N = fifoCount;
|
||||
|
||||
if (denom == 0) return OptoHeadState.DirNok;
|
||||
double numer = N * sumXY - sumX * sumY;
|
||||
double denom = N * sumXX - sumX * sumX;
|
||||
|
||||
if (Math.Abs(denom) < 1e-12)
|
||||
return OptoHeadState.DirNok;
|
||||
|
||||
double slope = numer / denom;
|
||||
|
||||
/// Calculate the slope of the regressed line, determine min. and max.
|
||||
double slope = (double)(numer / denom);
|
||||
if (slope > maxSlope) maxSlope = slope;
|
||||
if (slope < minSlope) minSlope = slope;
|
||||
|
||||
if ( counting == Counting.Arbitrary ||
|
||||
if (counting == Counting.Arbitrary ||
|
||||
(counting == Counting.Positive && maxSlope > Math.Abs(2 * minSlope)) ||
|
||||
(counting == Counting.Negative && minSlope < -Math.Abs(2 * maxSlope)))
|
||||
{
|
||||
return OptoHeadState.OptoAndDirOK;
|
||||
}
|
||||
else
|
||||
{
|
||||
return OptoHeadState.DirNok;
|
||||
}
|
||||
|
||||
return OptoHeadState.DirNok;
|
||||
}
|
||||
catch (Exception)
|
||||
catch (Exception ex)
|
||||
{
|
||||
log.ErrorFormat("{0} : CheckFlowDirection() failed", iPerlHeadName);
|
||||
return OptoHeadState.DirNok; /// ???
|
||||
log.ErrorFormat("{0} : CheckFlowDirection() failed: {1}", iPerlHeadName, ex);
|
||||
return OptoHeadState.DirNok;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -13,10 +13,13 @@ using Sensus.iPerl.NfcHandler;
|
||||
using NHibernate;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Xml.Linq; // This line is correct and does not need to be changed.
|
||||
using System.Xml.Linq;
|
||||
using TBF.Rig.TestMethods.iPerlCommunication.communication; // This line is correct and does not need to be changed.
|
||||
using TBF.Rig.TestMethods.iPerlCommunication.communication.C4.diagnosticLed;
|
||||
using TBF.Rig.TestMethods.iPerlCommunication.communication.C4.diagnosticLed.parserer;
|
||||
using TBF.Rig.TestMethods.iPerlCommunication.communication.C4.diagnosticLed.utils;
|
||||
using TBF.Rig.TestMethods.iPerlCommunication.communication.C4.hexLogger;
|
||||
using TBF.Rig.TestMethods.iPerlCommunication.communication.Utils;
|
||||
using OptoTelegramFlags = TBF.Rig.TestMethods.iPerlCommunication.common.OptoTelegramFlags;
|
||||
using OptoTelegramRaw = TBF.Rig.TestMethods.iPerlCommunication.common.OptoTelegramRaw;
|
||||
|
||||
@ -28,6 +31,7 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.iPerlHead
|
||||
public class IperlHead : ComponentBase, IDevice,IRegReaderDatastream, ISessionDataMngmnt, IOperation
|
||||
{
|
||||
private static readonly ILog log = LogManager.GetLogger(typeof(IperlHead));
|
||||
private static readonly ILog logStream = LogManager.GetLogger("StreamData");
|
||||
public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); }
|
||||
|
||||
#if TURA_SPECIAL
|
||||
@ -41,6 +45,19 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.iPerlHead
|
||||
public const int StartEndFilterSamplesCount2 = 20; /// StartEndFilterSamplesCount = 2 * StartEndFilterSamplesCount2 + 1
|
||||
public const int FeatureVectorSize = 9;
|
||||
|
||||
private OptoHeadTest _optoHeadTest;
|
||||
|
||||
public OptoHeadTest OptoHeadTest
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_optoHeadTest == null)
|
||||
_optoHeadTest = new OptoHeadTest(this);
|
||||
return _optoHeadTest;
|
||||
}
|
||||
set { _optoHeadTest = value; }
|
||||
}
|
||||
|
||||
|
||||
readonly IperlHeadCfg iperlHeadCfg;
|
||||
|
||||
@ -103,8 +120,8 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.iPerlHead
|
||||
/// <summary>
|
||||
/// Passed to OptoTelegramRaw.UpdateFromString(...)
|
||||
/// </summary>
|
||||
Int64 volumeRawExtLast;
|
||||
Int64 timestampExtLast;
|
||||
double volumeRawExtLast;
|
||||
double timestampExtLast;
|
||||
|
||||
FlowDirectionDetection flowDirectionDetection;
|
||||
|
||||
@ -360,7 +377,7 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.iPerlHead
|
||||
///
|
||||
/// Timestamp from the opto telegram
|
||||
///
|
||||
private Int64 lastTimestamp;
|
||||
private double lastTimestamp;
|
||||
private double timestampSec;
|
||||
private double timestampSec0;
|
||||
|
||||
@ -383,7 +400,7 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.iPerlHead
|
||||
///
|
||||
/// Volume of water from the opto telegram
|
||||
///
|
||||
private Int64 lastVolumeRaw; /// Last read raw volume
|
||||
private double lastVolumeRaw; /// Last read raw volume
|
||||
private double volumeLtr;
|
||||
private double volumeLtr0;
|
||||
|
||||
@ -589,10 +606,10 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.iPerlHead
|
||||
{
|
||||
ResultCode = 0;
|
||||
|
||||
volumeLtr = 0;
|
||||
volumeLtr0 = 0;
|
||||
timestampSec = 0;
|
||||
timestampSec0 = 0;
|
||||
volumeLtr = Double.NaN;
|
||||
volumeLtr0 = Double.NaN;
|
||||
timestampSec = Double.NaN;
|
||||
timestampSec0 = Double.NaN;
|
||||
|
||||
extraDataPath = null;
|
||||
|
||||
@ -858,6 +875,7 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.iPerlHead
|
||||
endWMState = volumeLtr;
|
||||
wmVolume = Math.Abs(endWMState - beginWMState);
|
||||
wmPulses = (int)(wmVolume * (double)PulsesPerLtr + 0.5);
|
||||
log.Debug("wmPulses = " + wmPulses + "wmVolume = " + wmVolume + "PulsesPerLtr = " + PulsesPerLtr + "");
|
||||
wmRefPulses = StateMachine.ControlBoardMain.RefPulses;
|
||||
wmTestTime = timestampSec - timestampSec0;
|
||||
}
|
||||
@ -980,8 +998,8 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.iPerlHead
|
||||
{
|
||||
string line = optoSerialPort.ReadLine(); // string
|
||||
byte[] bytes = optoSerialPort.Encoding.GetBytes(line);
|
||||
|
||||
Console.WriteLine("RX ← " + HexFormatter.ToSerialHex(bytes));
|
||||
|
||||
log.Debug("ComPort: "+ OptoComPortNr +" OPTHO RX ← " + HexFormatter.ToSerialHex(bytes));
|
||||
|
||||
try
|
||||
{
|
||||
@ -989,6 +1007,7 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.iPerlHead
|
||||
if (optoState == DataStreamState.ProcessAndSave)
|
||||
{
|
||||
DiagnosticLedState4Data data = (DiagnosticLedState4Data)parser.ParseLine(line, false);
|
||||
//DiagnostigLedDataByUnit unitData = new DiagnostigLedDataByUnit(Common.Unit.m3, Common.Unit.m3, data);
|
||||
int bufferIx = BufferIdx(optoDataCount);
|
||||
|
||||
if (synchronized)
|
||||
@ -999,11 +1018,17 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.iPerlHead
|
||||
|
||||
if (data != null)
|
||||
{
|
||||
|
||||
//TODO BUMI UNITS
|
||||
// apply units
|
||||
log.Debug($"OPTHO {OptoComPortNr} Parsed optho data:" + data.ToString());
|
||||
logStream.Debug($"ID: {OptoComPortNr} " + data.ToString());
|
||||
|
||||
optoData[bufferIx].UpdateFromSmart(data, optoDataCount,
|
||||
Convert.ToSingle(Sequences.ProcessData.RefFlow.Val), ref volumeRawExtLast,
|
||||
ref timestampExtLast);
|
||||
|
||||
log.Debug("OPTHO UpdateFromSmart() volumeRawExtLast:" + volumeRawExtLast + " timestampExtLast:" + timestampExtLast);
|
||||
|
||||
/// CR+LF was found && (pos >= OptoTelegramRaw.Length - 2) && the telegram is OK
|
||||
flowDirectionDetection.WriteToFifo(volumeRawExtLast, timestampExtLast);
|
||||
OptoTelegramReceived(optoDataCount, true, volumeRawExtLast,
|
||||
@ -1056,31 +1081,31 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.iPerlHead
|
||||
}
|
||||
|
||||
|
||||
void OptoTelegramReceived(int currentIx, bool async, Int64 volumeRawExt, Int64 timestampRawExt)
|
||||
void OptoTelegramReceived(int currentIx, bool async, double volumeRawExt, double timestampRawExt)
|
||||
{
|
||||
currentTelegramIx = currentIx;
|
||||
|
||||
lastVolumeRaw = volumeRawExt;
|
||||
lastTimestamp = timestampRawExt;
|
||||
|
||||
if (volumeLtr == 0 && volumeLtr0 == 0)
|
||||
if (Double.IsNaN(volumeLtr) && Double.IsNaN(volumeLtr0))
|
||||
{
|
||||
volumeLtr = (double)lastVolumeRaw * ScalingFactor() / 16000.0;
|
||||
volumeLtr = lastVolumeRaw;
|
||||
volumeLtr0 = volumeLtr;
|
||||
}
|
||||
else
|
||||
{
|
||||
volumeLtr = (double)lastVolumeRaw * ScalingFactor() / 16000.0;
|
||||
volumeLtr = lastVolumeRaw;
|
||||
}
|
||||
|
||||
if (timestampSec == 0 && timestampSec0 == 0)
|
||||
if (Double.IsNaN(timestampSec)&& Double.IsNaN(timestampSec0))
|
||||
{
|
||||
timestampSec = (double)lastTimestamp / 8192.0;
|
||||
timestampSec = lastTimestamp;
|
||||
timestampSec0 = timestampSec;
|
||||
}
|
||||
else
|
||||
{
|
||||
timestampSec = (double)lastTimestamp / 8192.0;
|
||||
timestampSec = lastTimestamp;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1185,25 +1210,50 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.iPerlHead
|
||||
/// <returns>Filtered volume</returns>
|
||||
double VolumeFromSamples(OptoTelegramRaw[] optoData, int optoDataCount, int unwrappedIx, double scalingFactor, int samplesCount2 = 0)
|
||||
{
|
||||
if (samplesCount2 < 0) samplesCount2 = 0;
|
||||
if ((unwrappedIx - samplesCount2) < 0 || (unwrappedIx + samplesCount2) >= optoDataCount) return 0;
|
||||
|
||||
Int64 sum = 0;
|
||||
for (int i = unwrappedIx - samplesCount2; i <= unwrappedIx + samplesCount2; i++)
|
||||
log.Debug("-- Get VolumeFromSamples() --");
|
||||
if (unwrappedIx >= optoDataCount)
|
||||
{
|
||||
int wrappedIx = BufferIdx(i);
|
||||
|
||||
if (optoData[wrappedIx].Flags != OptoTelegramFlags.OK &&
|
||||
optoData[wrappedIx].Flags != OptoTelegramFlags.OK_TestStart &&
|
||||
optoData[wrappedIx].Flags != OptoTelegramFlags.OK_TestEnd)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
sum += optoData[wrappedIx].VolumeRawExt;
|
||||
log.Debug(
|
||||
$"-- FAILED VolumeFromSamples() - unwrappedIx {unwrappedIx} >= optoDataCount{optoDataCount}--");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wrappedIx = BufferIdx(unwrappedIx);
|
||||
|
||||
return 0.0000625 * scalingFactor * sum / (double)(2 * samplesCount2 + 1);
|
||||
if (optoData[wrappedIx].Flags != OptoTelegramFlags.OK &&
|
||||
optoData[wrappedIx].Flags != OptoTelegramFlags.OK_TestStart &&
|
||||
optoData[wrappedIx].Flags != OptoTelegramFlags.OK_TestEnd)
|
||||
{
|
||||
log.Debug($"-- Get VolumeFromSamples() - Quit because:{optoData[wrappedIx].Flags}--");
|
||||
return 0;
|
||||
}
|
||||
log.Debug($"Valid data VolumeRawExt: {optoData[wrappedIx].VolumeRawExt}");
|
||||
return optoData[wrappedIx].VolumeRawExt;
|
||||
|
||||
|
||||
|
||||
//
|
||||
// if (samplesCount2 < 0) samplesCount2 = 0;
|
||||
// if ((unwrappedIx - samplesCount2) < 0 || (unwrappedIx + samplesCount2) >= optoDataCount) return 0;
|
||||
//
|
||||
//
|
||||
// Int64 sum = 0;
|
||||
// for (int i = unwrappedIx - samplesCount2; i <= unwrappedIx + samplesCount2; i++)
|
||||
// {
|
||||
// int wrappedIx = BufferIdx(i);
|
||||
//
|
||||
// if (optoData[wrappedIx].Flags != OptoTelegramFlags.OK &&
|
||||
// optoData[wrappedIx].Flags != OptoTelegramFlags.OK_TestStart &&
|
||||
// optoData[wrappedIx].Flags != OptoTelegramFlags.OK_TestEnd)
|
||||
// {
|
||||
// return 0;
|
||||
// }
|
||||
//
|
||||
// sum += optoData[wrappedIx].VolumeRawExt;
|
||||
// }
|
||||
//
|
||||
// return 0.0000625 * scalingFactor * sum / (double)(2 * samplesCount2 + 1);
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -1214,25 +1264,45 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.iPerlHead
|
||||
/// <returns>Filtered time</returns>
|
||||
double TimeFromSamples(OptoTelegramRaw[] optoData, int optoDataCount, int unwrappedIx, int samplesCount2 = 0)
|
||||
{
|
||||
if (samplesCount2 < 0) samplesCount2 = 0;
|
||||
if ((unwrappedIx - samplesCount2) < 0 || (unwrappedIx + samplesCount2) >= optoDataCount) return 0;
|
||||
|
||||
Int64 sum = 0;
|
||||
for (int i = unwrappedIx - samplesCount2; i <= unwrappedIx + samplesCount2; i++)
|
||||
log.Debug("-- Get TimeFromSamples() --");
|
||||
if (unwrappedIx >= optoDataCount)
|
||||
{
|
||||
int wrappedIx = BufferIdx(i);
|
||||
|
||||
if (optoData[wrappedIx].Flags != OptoTelegramFlags.OK &&
|
||||
optoData[wrappedIx].Flags != OptoTelegramFlags.OK_TestStart &&
|
||||
optoData[wrappedIx].Flags != OptoTelegramFlags.OK_TestEnd)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
sum += optoData[wrappedIx].TimestampExt;
|
||||
log.Debug(
|
||||
$"-- FAILED TimeFromSamples() - unwrappedIx {unwrappedIx} >= optoDataCount{optoDataCount}--");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wrappedIx = BufferIdx(unwrappedIx);
|
||||
|
||||
return sum / (double)(8192 * (2 * samplesCount2 + 1));
|
||||
if (optoData[wrappedIx].Flags != OptoTelegramFlags.OK &&
|
||||
optoData[wrappedIx].Flags != OptoTelegramFlags.OK_TestStart &&
|
||||
optoData[wrappedIx].Flags != OptoTelegramFlags.OK_TestEnd)
|
||||
{
|
||||
log.Debug($"-- Get TimeFromSamples() - Quit because:{optoData[wrappedIx].Flags}--");
|
||||
return 0;
|
||||
}
|
||||
log.Debug($"Valid data TimestampExt: {optoData[wrappedIx].TimestampExt}");
|
||||
return optoData[wrappedIx].TimestampExt;
|
||||
|
||||
// if (samplesCount2 < 0) samplesCount2 = 0;
|
||||
// if ((unwrappedIx - samplesCount2) < 0 || (unwrappedIx + samplesCount2) >= optoDataCount) return 0;
|
||||
//
|
||||
// Int64 sum = 0;
|
||||
// for (int i = unwrappedIx - samplesCount2; i <= unwrappedIx + samplesCount2; i++)
|
||||
// {
|
||||
// int wrappedIx = BufferIdx(i);
|
||||
//
|
||||
// if (optoData[wrappedIx].Flags != OptoTelegramFlags.OK &&
|
||||
// optoData[wrappedIx].Flags != OptoTelegramFlags.OK_TestStart &&
|
||||
// optoData[wrappedIx].Flags != OptoTelegramFlags.OK_TestEnd)
|
||||
// {
|
||||
// return 0;
|
||||
// }
|
||||
//
|
||||
// sum += optoData[wrappedIx].TimestampExt;
|
||||
// }
|
||||
//
|
||||
// return sum / (double)(8192 * (2 * samplesCount2 + 1));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -1451,5 +1521,7 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.iPerlHead
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -83,10 +83,10 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.iPerlHead
|
||||
switch (rfidCommandComboBox.SelectedValue)
|
||||
{
|
||||
case "ReadPCB":
|
||||
rfidListItem.Text = $"PCB: {OptoHeadTest.ReadRequest_PCB(ref iPerlHead)}";
|
||||
rfidListItem.Text = $"PCB: {iPerlHead.OptoHeadTest.ReadRequest_PCB()}";
|
||||
break;
|
||||
case "SetTestMode":
|
||||
rfidListItem.Text = OptoHeadTest.SetTestMode(ref iPerlHead, ref isTestModeSuccessful);
|
||||
rfidListItem.Text = iPerlHead.OptoHeadTest.SetTestMode(ref isTestModeSuccessful);
|
||||
optoListBox.Items.Clear();
|
||||
stopWorkerThread = false;
|
||||
optoThread = new Thread(OptoWorker);
|
||||
@ -98,7 +98,7 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.iPerlHead
|
||||
break;
|
||||
case "SetActiveMode":
|
||||
|
||||
rfidListItem.Text = OptoHeadTest.SetActiveMode(ref iPerlHead, ref isTestModeSuccessful);
|
||||
rfidListItem.Text = iPerlHead.OptoHeadTest.SetActiveMode(ref isTestModeSuccessful);
|
||||
stopWorkerThread = true;
|
||||
iPerlHead.StopDataStreamProcessing(); // close opto port
|
||||
break;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user