TestMethods.GenesisHead and TestMethods.GenHead folders added.
This commit is contained in:
parent
bef4928162
commit
58df07300e
197
TBF/BenchControl/TestMethods/GenHead/CalibrationStruct.cs
Normal file
197
TBF/BenchControl/TestMethods/GenHead/CalibrationStruct.cs
Normal file
@ -0,0 +1,197 @@
|
||||
///
|
||||
/// Copyright (c) 2015-2017 Sensus Metering Systems
|
||||
///
|
||||
using System;
|
||||
|
||||
namespace TBF.BenchControl.TestMethods.GenesisCommunication.GenesisHead
|
||||
{
|
||||
public class CalibrationStruct
|
||||
{
|
||||
public static readonly int Length = 35;
|
||||
|
||||
public Byte Version;
|
||||
public MeterType MeterType;
|
||||
public UInt16 Calibration;
|
||||
public VolumeUnits VolumeUnits;
|
||||
public FlowArrow FlowArrow;
|
||||
public UInt16 FWVersion;
|
||||
public UInt16[] TargetField;
|
||||
public UInt16 RecipMeanCurrent;
|
||||
public UInt16 ThresholdVolume;
|
||||
public UInt16 ThresholdTime;
|
||||
public UInt16 FlowActivationThr;
|
||||
public UInt16 VolumeArrowThr;
|
||||
public UInt32 CalibrationTime;
|
||||
public ulong SerialNumber;
|
||||
public MeterSealed MeterSealed;
|
||||
public byte CheckSum;
|
||||
|
||||
|
||||
public CalibrationStruct()
|
||||
{
|
||||
TargetField = new UInt16[3];
|
||||
}
|
||||
|
||||
public byte[] ToByteArray()
|
||||
{
|
||||
byte[] result = new byte[Length];
|
||||
|
||||
result[0] = Version;
|
||||
result[1] = (byte)MeterType;
|
||||
|
||||
result[2] = (byte)(Calibration & 0x00FF);
|
||||
result[3] = (byte)((Calibration >> 8) & 0x00FF);
|
||||
|
||||
result[4] = (byte)VolumeUnits;
|
||||
|
||||
result[5] = (byte)FlowArrow;
|
||||
|
||||
result[6] = (byte)(FWVersion & 0x00FF);
|
||||
result[7] = (byte)((FWVersion >> 8) & 0x00FF);
|
||||
|
||||
result[8] = (byte)( TargetField[0] & 0x00FF);
|
||||
result[9] = (byte)((TargetField[0] >> 8) & 0x00FF);
|
||||
result[10] = (byte)( TargetField[1] & 0x00FF);
|
||||
result[11] = (byte)((TargetField[1] >> 8) & 0x00FF);
|
||||
result[12] = (byte)( TargetField[2] & 0x00FF);
|
||||
result[13] = (byte)((TargetField[2] >> 8) & 0x00FF);
|
||||
|
||||
result[14] = (byte)(RecipMeanCurrent & 0x00FF);
|
||||
result[15] = (byte)((RecipMeanCurrent >> 8) & 0x00FF);
|
||||
|
||||
result[16] = (byte)(ThresholdVolume & 0x00FF);
|
||||
result[17] = (byte)((ThresholdVolume >> 8) & 0x00FF);
|
||||
|
||||
result[18] = (byte)(ThresholdTime & 0x00FF);
|
||||
result[19] = (byte)((ThresholdTime >> 8) & 0x00FF);
|
||||
|
||||
result[20] = (byte)(FlowActivationThr & 0x00FF);
|
||||
result[21] = (byte)((FlowActivationThr >> 8) & 0x00FF);
|
||||
|
||||
result[22] = (byte)(VolumeArrowThr & 0x00FF);
|
||||
result[23] = (byte)((VolumeArrowThr >> 8) & 0x00FF);
|
||||
|
||||
result[24] = (byte)(CalibrationTime & 0x000000FF);
|
||||
result[25] = (byte)((CalibrationTime >> 8) & 0x000000FF);
|
||||
result[26] = (byte)((CalibrationTime >> 16) & 0x000000FF);
|
||||
result[27] = (byte)((CalibrationTime >> 24) & 0x000000FF);
|
||||
|
||||
result[28] = (byte)(SerialNumber & 0x00000000000000FF);
|
||||
result[29] = (byte)((SerialNumber >> 8) & 0x00000000000000FF);
|
||||
result[30] = (byte)((SerialNumber >> 16) & 0x00000000000000FF);
|
||||
result[31] = (byte)((SerialNumber >> 24) & 0x00000000000000FF);
|
||||
result[32] = (byte)((SerialNumber >> 32) & 0x00000000000000FF);
|
||||
|
||||
result[33] = (byte)MeterSealed;
|
||||
result[34] = CheckSum;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a calibration structure from a complete byte array
|
||||
/// </summary>
|
||||
/// <param name="data">A complete byte array data</param>
|
||||
/// <returns>CalibrationStruct or null when byte array was not complete</returns>
|
||||
public static CalibrationStruct FromByteArray(byte[] data)
|
||||
{
|
||||
if (data.Length != Length) return null;
|
||||
|
||||
CalibrationStruct result = new CalibrationStruct();
|
||||
|
||||
result.Version = data[0];
|
||||
result.MeterType = (MeterType)data[1];
|
||||
result.Calibration = (UInt16)(data[2] + 256 * data[3]);
|
||||
result.VolumeUnits = (VolumeUnits)data[4];
|
||||
result.FlowArrow = (FlowArrow)data[5];
|
||||
result.FWVersion = (UInt16)(data[6] + 256 * data[7]);
|
||||
result.TargetField[0] = (UInt16)(data[8] + 256 * data[9]);
|
||||
result.TargetField[1] = (UInt16)(data[10] + 256 * data[11]);
|
||||
result.TargetField[2] = (UInt16)(data[12] + 256 * data[13]);
|
||||
result.RecipMeanCurrent = (UInt16)(data[14] + 256 * data[15]);
|
||||
result.ThresholdVolume = (UInt16)(data[16] + 256 * data[17]);
|
||||
result.ThresholdTime = (UInt16)(data[18] + 256 * data[19]);
|
||||
result.FlowActivationThr = (UInt16)(data[20] + 256 * data[21]);
|
||||
result.VolumeArrowThr = (UInt16)(data[22] + 256 * data[23]);
|
||||
result.CalibrationTime = (((UInt32)data[27] * 256 + data[26]) * 256 + data[25]) * 256 + data[24];
|
||||
result.SerialNumber = ((((UInt64)data[32] * 256 + data[31]) * 256 + data[30]) * 256 + data[29]) * 256 + data[28];
|
||||
result.MeterSealed = (MeterSealed)data[33];
|
||||
result.CheckSum = data[34];
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update the calibration structure from an incomplete byte array
|
||||
/// </summary>
|
||||
/// <param name="data">Byte array data</param>
|
||||
/// <param name="offset">Offset of byte array data in CalibrationStruct</param>
|
||||
/// <returns>true when successful, false when data are not appropriate</returns>
|
||||
public bool Update(byte[] data, int offset)
|
||||
{
|
||||
if (offset == 2 && data.Length == 2)
|
||||
{
|
||||
/// Data containing iPerl calibration factor
|
||||
Calibration = (UInt16)(data[2 - offset] + 256 * data[3 - offset]);
|
||||
return true;
|
||||
}
|
||||
else if (offset == 0 && data.Length == Length)
|
||||
{
|
||||
/// Data containing a complete CalibrationStruct
|
||||
Version = data[0];
|
||||
MeterType = (MeterType)data[1];
|
||||
Calibration = (UInt16)(data[2] + 256 * data[3]);
|
||||
VolumeUnits = (VolumeUnits)data[4];
|
||||
FlowArrow = (FlowArrow)data[5];
|
||||
FWVersion = (UInt16)(data[6] + 256 * data[7]);
|
||||
TargetField[0] = (UInt16)(data[8] + 256 * data[9]);
|
||||
TargetField[1] = (UInt16)(data[10] + 256 * data[11]);
|
||||
TargetField[2] = (UInt16)(data[12] + 256 * data[13]);
|
||||
RecipMeanCurrent = (UInt16)(data[14] + 256 * data[15]);
|
||||
ThresholdVolume = (UInt16)(data[16] + 256 * data[17]);
|
||||
ThresholdTime = (UInt16)(data[18] + 256 * data[19]);
|
||||
FlowActivationThr = (UInt16)(data[20] + 256 * data[21]);
|
||||
VolumeArrowThr = (UInt16)(data[22] + 256 * data[23]);
|
||||
CalibrationTime = (((UInt32)data[27] * 256 + data[26]) * 256 + data[25]) * 256 + data[24];
|
||||
SerialNumber = ((((UInt64)data[32] * 256 + data[31]) * 256 + data[30]) * 256 + data[29]) * 256 + data[28];
|
||||
MeterSealed = (MeterSealed)data[33];
|
||||
CheckSum = data[34];
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
public string FWVersionStr()
|
||||
{
|
||||
int d1 = (FWVersion >> 8) & 0x000F;
|
||||
int d2 = (FWVersion >> 12) & 0x000F;
|
||||
int d3 = (FWVersion >> 4) & 0x000F;
|
||||
int d4 = FWVersion & 0x000F;
|
||||
return string.Format("{0}.{1}{2}{3}", d1, d2, d3, d4);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format("Calibration: V{0} Type={1} Cal={2} Units={3} FlowArrow.{4} FW={5} Hi={6} Norm={7} Low={8} RMC={9} ThrVol={10} ThrTime={11} FlActThr={12} VolArrThr={13} CalTm={14} SN={15} MeterSealed={16} Chksum={17}",
|
||||
Version,
|
||||
MeterType,
|
||||
Calibration,
|
||||
VolumeUnits,
|
||||
FlowArrow,
|
||||
FWVersion,
|
||||
TargetField[0],
|
||||
TargetField[1],
|
||||
TargetField[2],
|
||||
RecipMeanCurrent,
|
||||
ThresholdVolume,
|
||||
ThresholdTime,
|
||||
FlowActivationThr,
|
||||
VolumeArrowThr,
|
||||
CalibrationTime,
|
||||
SerialNumber,
|
||||
MeterSealed,
|
||||
CheckSum.ToString("X2"));
|
||||
}
|
||||
}
|
||||
}
|
||||
225
TBF/BenchControl/TestMethods/GenHead/ConfigStruct.cs
Normal file
225
TBF/BenchControl/TestMethods/GenHead/ConfigStruct.cs
Normal file
@ -0,0 +1,225 @@
|
||||
///
|
||||
/// Copyright (c) 2015-2017 Sensus Metering Systems
|
||||
///
|
||||
using System;
|
||||
|
||||
namespace TBF.BenchControl.TestMethods.GenesisCommunication.GenesisHead
|
||||
{
|
||||
public class ConfigStruct
|
||||
{
|
||||
public const int Length = 32;
|
||||
|
||||
public Byte Version; /// 0: 1 byte
|
||||
public MeterState MeterState; /// 1: 1 byte
|
||||
public UInt32 TargetTimeVeryLowBatt; /// 2: 4 bytes in seconds
|
||||
public UInt32 TargetTimeLowBatt; /// 6: 4 bytes, in seconds
|
||||
public UInt32 TestModeTime; /// 10: 4 bytes, Max. test mode time in seconds
|
||||
public UInt16 EmptyPipeThreshold; /// 14: 2 bytes
|
||||
public byte[] PCBNumber; /// 16: 5 bytes
|
||||
public byte TestModeConfig; /// 21: 1 byte
|
||||
public UInt32 RadioAddress; /// 22: 4 bytes
|
||||
public UInt16 TempCalibration; /// 26: 2 bytes
|
||||
public UInt16 AlarmMask; /// 28: 2 bytes, Default 0xA3F7
|
||||
public UInt16 ConfigCheckSum; /// 30: 2 bytes
|
||||
|
||||
public ConfigStruct()
|
||||
{
|
||||
PCBNumber = new byte[5];
|
||||
}
|
||||
|
||||
public byte[] ToByteArray()
|
||||
{
|
||||
byte[] result = new byte[Length];
|
||||
|
||||
result[0] = Version;
|
||||
result[1] = (byte)MeterState;
|
||||
|
||||
result[2] = (byte)(TargetTimeVeryLowBatt & 0x000000FF);
|
||||
result[3] = (byte)((TargetTimeVeryLowBatt >> 8) & 0x000000FF);
|
||||
result[4] = (byte)((TargetTimeVeryLowBatt >> 16) & 0x000000FF);
|
||||
result[5] = (byte)((TargetTimeVeryLowBatt >> 24) & 0x000000FF);
|
||||
|
||||
result[6] = (byte)(TargetTimeLowBatt & 0x000000FF);
|
||||
result[7] = (byte)((TargetTimeLowBatt >> 8) & 0x000000FF);
|
||||
result[8] = (byte)((TargetTimeLowBatt >> 16) & 0x000000FF);
|
||||
result[9] = (byte)((TargetTimeLowBatt >> 24) & 0x000000FF);
|
||||
|
||||
result[10] = (byte)(TestModeTime & 0x000000FF);
|
||||
result[11] = (byte)((TestModeTime >> 8) & 0x000000FF);
|
||||
result[12] = (byte)((TestModeTime >> 16) & 0x000000FF);
|
||||
result[13] = (byte)((TestModeTime >> 24) & 0x000000FF);
|
||||
|
||||
result[14] = (byte)(EmptyPipeThreshold & 0x00FF);
|
||||
result[15] = (byte)((EmptyPipeThreshold >> 8) & 0x00FF);
|
||||
|
||||
result[16] = PCBNumber[0];
|
||||
result[17] = PCBNumber[1];
|
||||
result[18] = PCBNumber[2];
|
||||
result[19] = PCBNumber[3];
|
||||
result[20] = PCBNumber[4];
|
||||
|
||||
result[21] = TestModeConfig;
|
||||
|
||||
result[22] = (byte)(RadioAddress & 0x000000FF);
|
||||
result[23] = (byte)((RadioAddress >> 8) & 0x000000FF);
|
||||
result[24] = (byte)((RadioAddress >> 16) & 0x000000FF);
|
||||
result[25] = (byte)((RadioAddress >> 24) & 0x000000FF);
|
||||
|
||||
result[26] = (byte)(TempCalibration & 0x00FF);
|
||||
result[27] = (byte)((TempCalibration >> 8) & 0x00FF);
|
||||
|
||||
result[28] = (byte)(AlarmMask & 0x00FF);
|
||||
result[29] = (byte)((AlarmMask >> 8) & 0x00FF);
|
||||
|
||||
result[30] = (byte)(ConfigCheckSum & 0x00FF);
|
||||
result[31] = (byte)((ConfigCheckSum >> 8) & 0x00FF);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a configuration structure from a complete byte array
|
||||
/// </summary>
|
||||
/// <param name="data">A complete byte array data</param>
|
||||
/// <returns>ConfigStruct or null when byte array was not complete</returns>
|
||||
public static ConfigStruct FromByteArray(byte[] data)
|
||||
{
|
||||
if (data.Length != Length) return null;
|
||||
|
||||
ConfigStruct result = new ConfigStruct();
|
||||
|
||||
result.Version = data[0];
|
||||
result.MeterState = (MeterState)data[1];
|
||||
result.TargetTimeVeryLowBatt = (((UInt32)data[5] * 256 + data[4]) * 256 + data[3]) * 256 + data[2];
|
||||
result.TargetTimeLowBatt = (((UInt32)data[9] * 256 + data[8]) * 256 + data[7]) * 256 + data[6];
|
||||
result.TestModeTime = (((UInt32)data[13] * 256 + data[12]) * 256 + data[11]) * 256 + data[10];
|
||||
result.EmptyPipeThreshold = (UInt16)(data[15] * 256 + data[14]);
|
||||
result.PCBNumber[0] = data[16];
|
||||
result.PCBNumber[1] = data[17];
|
||||
result.PCBNumber[2] = data[18];
|
||||
result.PCBNumber[3] = data[19];
|
||||
result.PCBNumber[4] = data[20];
|
||||
result.TestModeConfig = data[21];
|
||||
result.RadioAddress = (((UInt32)data[25] * 256 + data[24]) * 256 + data[23]) * 256 + data[22];
|
||||
result.TempCalibration = (UInt16)(data[27] * 256 + data[26]);
|
||||
result.AlarmMask = (UInt16)(data[29] * 256 + data[28]);
|
||||
result.ConfigCheckSum = (UInt16)(data[31] * 256 + data[30]);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update the configuration structure from an incomplete byte array
|
||||
/// </summary>
|
||||
/// <param name="offset">Offset of byte array data in ConfigStruct</param>
|
||||
/// <param name="data">Byte array data</param>
|
||||
/// <returns>true when successful, false when data are not appropriate</returns>
|
||||
public bool Update(int offset, byte[] data)
|
||||
{
|
||||
if (offset == 0 && data.Length == 2)
|
||||
{
|
||||
/// iPerl mode of function
|
||||
Version = data[0];
|
||||
MeterState = (MeterState)data[1];
|
||||
return true;
|
||||
}
|
||||
else if (offset == 0 && data.Length == 4)
|
||||
{
|
||||
/// iPerl mode of function and extra 2 bytes
|
||||
Version = data[0];
|
||||
MeterState = (MeterState)data[1];
|
||||
return true;
|
||||
}
|
||||
else if (offset == 21 && data.Length == 1)
|
||||
{
|
||||
/// TestModeConfig value
|
||||
TestModeConfig = data[21 - offset];
|
||||
return true;
|
||||
}
|
||||
else if (offset == 0 && data.Length == Length)
|
||||
{
|
||||
/// Complete ConfigStruct
|
||||
Version = data[0];
|
||||
MeterState = (MeterState)data[1];
|
||||
TargetTimeVeryLowBatt = (((UInt32)data[5] * 256 + data[4]) * 256 + data[3]) * 256 + data[2];
|
||||
TargetTimeLowBatt = (((UInt32)data[9] * 256 + data[8]) * 256 + data[7]) * 256 + data[6];
|
||||
TestModeTime = (((UInt32)data[13] * 256 + data[12]) * 256 + data[11]) * 256 + data[10];
|
||||
EmptyPipeThreshold = (UInt16)(data[15] * 256 + data[14]);
|
||||
PCBNumber[0] = data[16];
|
||||
PCBNumber[1] = data[17];
|
||||
PCBNumber[2] = data[18];
|
||||
PCBNumber[3] = data[19];
|
||||
PCBNumber[4] = data[20];
|
||||
TestModeConfig = data[21];
|
||||
RadioAddress = (((UInt32)data[25] * 256 + data[24]) * 256 + data[23]) * 256 + data[22];
|
||||
TempCalibration = (UInt16)(data[27] * 256 + data[26]);
|
||||
AlarmMask = (UInt16)(data[29] * 256 + data[28]);
|
||||
ConfigCheckSum = (UInt16)(data[31] * 256 + data[30]);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns PCB number string (12 characters, 12 decimal digits)
|
||||
/// </summary>
|
||||
/// <returns>PCB number STRING</returns>
|
||||
public string GetPcbNrString()
|
||||
{
|
||||
return PCBNumber2String(this.PCBNumber);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts PCBNumber to string (12 characters, 12 decimal digits)
|
||||
/// </summary>
|
||||
/// <param name="pcbNumber"></param>
|
||||
/// <returns>PCB number string</returns>
|
||||
public static string PCBNumber2String(byte[] pcbNumber)
|
||||
{
|
||||
if (pcbNumber.Length != 5) return string.Empty;
|
||||
|
||||
Int64 number = 0;
|
||||
for (int i = 4; i >= 0; i--)
|
||||
{
|
||||
number = 256 * number + (Int64)pcbNumber[i];
|
||||
}
|
||||
|
||||
return number.ToString();
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format("Config: V{0} State={1} VLoBattT={2}s LoBattT={3}s TestModeT={4}s EPThld={5} PCB#={6} TMCfg={7} RadioAddr={8} TempCalib={9} AlarmMask={10} CfgCheckSum={11}",
|
||||
Version,
|
||||
MeterState,
|
||||
TargetTimeVeryLowBatt,
|
||||
TargetTimeLowBatt,
|
||||
TestModeTime,
|
||||
EmptyPipeThreshold,
|
||||
GetPcbNrString(),
|
||||
TestModeConfig.ToString("X2"),
|
||||
RadioAddress,
|
||||
TempCalibration,
|
||||
AlarmMask.ToString("X4"),
|
||||
ConfigCheckSum.ToString("X4"));
|
||||
}
|
||||
|
||||
public string ToString(int sel)
|
||||
{
|
||||
return string.Format("{1} PCB#={6} TMCfg={7}",
|
||||
Version,
|
||||
MeterState,
|
||||
TargetTimeVeryLowBatt,
|
||||
TargetTimeLowBatt,
|
||||
TestModeTime,
|
||||
EmptyPipeThreshold,
|
||||
GetPcbNrString(),
|
||||
TestModeConfig.ToString("X2"),
|
||||
RadioAddress,
|
||||
TempCalibration,
|
||||
AlarmMask.ToString("X4"),
|
||||
ConfigCheckSum.ToString("X4"));
|
||||
}
|
||||
}
|
||||
}
|
||||
110
TBF/BenchControl/TestMethods/GenHead/Enums.cs
Normal file
110
TBF/BenchControl/TestMethods/GenHead/Enums.cs
Normal file
@ -0,0 +1,110 @@
|
||||
///
|
||||
/// Copyright (c) 2015-2017 Sensus Metering Systems
|
||||
///
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace TBF.BenchControl.TestMethods.GenesisCommunication.GenesisHead
|
||||
{
|
||||
public enum MessageID
|
||||
{
|
||||
Calibration = 0x00, /// Access to stCalibration
|
||||
Configuration = 0x01, /// Access to stConfig
|
||||
Status = 0x02, /// Access to stStaus, read only
|
||||
Power = 0x03, /// Access to stPower, containing power info from both processors
|
||||
LCD = 0x04, /// Access to stLCD
|
||||
EventData = 0x05, /// NOT USED
|
||||
IntervalData = 0x06, /// NOT USED
|
||||
Diagnostics = 0x07, /// Access tostMetroDiagArray, read onl
|
||||
MetrologyMemory = 0x08, /// Memory block access, read only
|
||||
Error_LongAck = 0x09, /// Error message
|
||||
Command = 0x0A, /// Command to execute, with no arguments
|
||||
Parameterizing = 0x0B, /// Parameterizing message is used in MCI-SPI interface only
|
||||
Error_ShortAck = 0x0C, /// Short acknowledge message is used in MCI-SPI interface only
|
||||
ChanelAlive = 0x0D, /// Channel alive message is used in MCI-SPI interface only
|
||||
RadioPassthrough = 0x0E, /// RFID <-> Metrology <-> Radio passthrough message
|
||||
ASICRegisterReadTest = 0x0F, /// ASIC Register read test
|
||||
IMIDebugMessagesAccess = 0x10, /// IMI debug messages read test
|
||||
ProductionChecksumsRead = 0x11, /// Production checksum read: Calibration (1 byte), Configuration (2 bytes), spare (4 bytes)
|
||||
HardwareParametersTest = 0x12, /// Hardware Parameters Testing: User configurable fixed field drive time (1 byte)
|
||||
/// <summary>
|
||||
/// Notes:
|
||||
/// 1. Short Ack message contains 1-byte error code and all the fields (Offset, Payload length, payload and password) will not be present.
|
||||
/// 2. Channel Alive message does not contain the fields (Offset, Payload length, payload and password).
|
||||
/// 3. Except the above two special messages, rest all the messages in the above table will follow the message format mentioned in sections 3.1 and 3.2.
|
||||
/// </summary>
|
||||
Count /// Number of MessageID-s
|
||||
}
|
||||
|
||||
public enum MeterType : byte
|
||||
{
|
||||
DN15 = 0,
|
||||
CoaxManifold = 1,
|
||||
DN20 = 2,
|
||||
DN25 = 3,
|
||||
DN26 = 4, /// DN25*
|
||||
DN32 = 5,
|
||||
DN40 = 6,
|
||||
AutoDetect,
|
||||
Count /// Number of meter types
|
||||
}
|
||||
|
||||
public enum VolumeUnits : byte
|
||||
{
|
||||
m3 = 0,
|
||||
UK_gallon = 1,
|
||||
US_gallon = 2,
|
||||
Count /// Number of volume units
|
||||
}
|
||||
|
||||
public enum FlowArrow : byte
|
||||
{
|
||||
No = 0,
|
||||
Right = 1,
|
||||
Left = 2,
|
||||
Count /// Number of flow arrows
|
||||
}
|
||||
|
||||
public enum MeterSealed : byte
|
||||
{
|
||||
InProduction = 0x00,
|
||||
OutOfProduction = 0xA5,
|
||||
Sealed = 0x5A,
|
||||
}
|
||||
|
||||
public enum MeterState : byte
|
||||
{
|
||||
None = 0,
|
||||
Idle = 1,
|
||||
Active = 2,
|
||||
Test = 3,
|
||||
EndOfLife = 4,
|
||||
Count /// Number of meter states
|
||||
}
|
||||
|
||||
public enum FlowState : byte
|
||||
{
|
||||
No = 0,
|
||||
Reverse = 1,
|
||||
Forward = 2,
|
||||
EmptyPipe = 3,
|
||||
Count /// Number of flow states
|
||||
}
|
||||
|
||||
public enum OptoTelegramFlags : byte
|
||||
{
|
||||
OK = 0,
|
||||
OK_TestStart,
|
||||
OK_TestEnd,
|
||||
InvalidTelegram, /// Wrong telegram format of checksum error
|
||||
SyncError,
|
||||
}
|
||||
|
||||
public enum OptoState
|
||||
{
|
||||
Read,
|
||||
Flush,
|
||||
}
|
||||
}
|
||||
26
TBF/BenchControl/TestMethods/GenHead/Factory.cs
Normal file
26
TBF/BenchControl/TestMethods/GenHead/Factory.cs
Normal file
@ -0,0 +1,26 @@
|
||||
///
|
||||
/// Copyright (c) 2015-2017 Sensus Metering Systems
|
||||
///
|
||||
using System.Collections.Generic;
|
||||
using TBF.BenchControl.Generic;
|
||||
|
||||
namespace TBF.BenchControl.TestMethods.GenesisCommunication.GenesisHead
|
||||
{
|
||||
public class Factory : IComponentFactory
|
||||
{
|
||||
public string ClassName { get { return "RegisterReader for Genesis"; } }
|
||||
|
||||
public void ResetStaticProperties() { GenesisHead.ResetStaticProperties(); }
|
||||
|
||||
public IComponent DummyComponent() { return new GenesisHead(); }
|
||||
|
||||
public IComponent GetComponent(IComponentCfg cfg, IList<IComponent> components) { return new GenesisHead(cfg); }
|
||||
|
||||
public IComponentCfg DefaultConfig() { return new GenesisHeadCfg(this); }
|
||||
|
||||
public IComponentCfg CmpntCfgFromCmpntEntity(Config.Entities.Component component)
|
||||
{
|
||||
return ComponentCfgBase.CreateFromDbEntity(GenesisHeadCfg.Serializer, component, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
549
TBF/BenchControl/TestMethods/GenHead/GenesisHead.cs
Normal file
549
TBF/BenchControl/TestMethods/GenHead/GenesisHead.cs
Normal file
@ -0,0 +1,549 @@
|
||||
///
|
||||
/// Copyright (c) 2015-2018 Sensus Slovensko a.s.
|
||||
///
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.IO.Ports;
|
||||
using System.Threading;
|
||||
using System.Windows.Forms;
|
||||
using log4net;
|
||||
using Config.Entities;
|
||||
using TBF.BenchControl;
|
||||
using TBF.BenchControl.Generic;
|
||||
using TBF.Resources;
|
||||
using Xylem.Common.Hardware.WaterMeter;
|
||||
using Xylem.Common.Hardware.WaterMeter.Genesis;
|
||||
using TBF.BenchControl.GenericDevices;
|
||||
|
||||
namespace TBF.BenchControl.TestMethods.GenesisCommunication.GenesisHead
|
||||
{
|
||||
public static class GenesisHeadBatch
|
||||
{
|
||||
public static readonly Lazy<MeterBatch> BatchHolder = new Lazy<MeterBatch>(() =>
|
||||
{
|
||||
return new MeterBatch();
|
||||
});
|
||||
|
||||
internal static bool Start(IRegisterReader[] registerReaders, string[] lastSNTexts)
|
||||
{
|
||||
int index = 0;
|
||||
var ret = false;
|
||||
foreach (var rr in registerReaders)
|
||||
{
|
||||
if (rr is TestMethods.GenesisCommunication.GenesisHead.GenesisHead)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(lastSNTexts[index]))
|
||||
{
|
||||
var myGenesis = ((TestMethods.GenesisCommunication.GenesisHead.GenesisHead)rr).SetUp();
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
index = index + 1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// This component = instance of this class is a placeholder for a combined main watermeter
|
||||
/// </summary>
|
||||
public class GenesisHead : ComponentBase, IDevice, GenericDevices.IRegisterReader, IOperation
|
||||
{
|
||||
private static readonly ILog log = LogManager.GetLogger(typeof(GenesisHead));
|
||||
public override string ToString() { return string.Format("Genesis({0})", Cfg.ToString(1)); }
|
||||
|
||||
public Config.Entities.RegisterReaderType RegisterReaderType { get { return Config.Entities.RegisterReaderType.DataStream; } }
|
||||
|
||||
|
||||
readonly GenesisHeadCfg genesisHeadCfg;
|
||||
public int SlotNr { get { return genesisHeadCfg.SlotNr; } }
|
||||
public double PulsesPerLtr { get { return 1000.0; } }
|
||||
public double LtrsPerPulse { get { return 1 / PulsesPerLtr; } }
|
||||
|
||||
#if ORACLE_DB
|
||||
public int WMType_ID { get { return iperlHeadCfg.ProcParams.WMType_ID; } } /// Required by Oracle DB
|
||||
public int WMType_Rev { get { return iperlHeadCfg.ProcParams.WMType_Rev; } } /// Required by Oracle DB
|
||||
#endif
|
||||
public float CalibTarget { get { return (ushort)genesisHeadCfg.ProcParams.CalibTarget; } }
|
||||
public ushort FactorLimitLo { get { return (ushort)genesisHeadCfg.ProcParams.FactorLimitLo; } }
|
||||
public ushort FactorLimitHi { get { return (ushort)genesisHeadCfg.ProcParams.FactorLimitHi; } }
|
||||
|
||||
/// Properties set by the Begin and the End form
|
||||
//todo rd implement
|
||||
public string SerialNr;
|
||||
|
||||
|
||||
public string EndState
|
||||
{
|
||||
get { return endState; }
|
||||
set { endState = value; }
|
||||
}
|
||||
string endState;
|
||||
|
||||
public string BeginState
|
||||
{
|
||||
get { return beginState; }
|
||||
set { beginState = value; }
|
||||
}
|
||||
string beginState;
|
||||
|
||||
public bool Disabled
|
||||
{
|
||||
get { return disabled; }
|
||||
set { disabled = value; }
|
||||
}
|
||||
bool disabled;
|
||||
|
||||
public bool CommFailed
|
||||
{
|
||||
get { return commFailed; }
|
||||
set { commFailed = value; }
|
||||
}
|
||||
bool commFailed;
|
||||
|
||||
public int ResultCode
|
||||
{
|
||||
get { return resultCode; }
|
||||
}
|
||||
int resultCode;
|
||||
|
||||
|
||||
/// <summary> ConfigStruct of the water meter obtained or updated by iPerlCommunication </summary>
|
||||
public ConfigStruct ConfigStruct
|
||||
{
|
||||
get { return configStruct; }
|
||||
set { configStruct = value; }
|
||||
}
|
||||
ConfigStruct configStruct;
|
||||
|
||||
/// <summary> CalibrationStruct of the water meter obtained or updated by iPerlCommunication </summary>
|
||||
public CalibrationStruct CalibrationStruct
|
||||
{
|
||||
get { return calibrationStruct; }
|
||||
set { calibrationStruct = value; }
|
||||
}
|
||||
CalibrationStruct calibrationStruct;
|
||||
|
||||
public ushort OrigCalibFactor;
|
||||
public ushort CalibFactor { get { return (CalibrationStruct != null) ? CalibrationStruct.Calibration : (ushort)0; } }
|
||||
|
||||
public double Q2ErrWOCorrection;
|
||||
public bool Q2CorrectionDone;
|
||||
public double Q2Correction;
|
||||
public int Q2CorrRFlow;
|
||||
public int Q2CorrLFlow;
|
||||
|
||||
public double Diff2Hz8Hz;
|
||||
public bool Hz2CorrectionDone;
|
||||
public int Hz2Correction;
|
||||
|
||||
public string FWVersion { get { return (CalibrationStruct != null) ? CalibrationStruct.FWVersionStr() : string.Empty; } }
|
||||
|
||||
|
||||
/// <summary> Result of the last test used to calculate Q2 correction factors, etc </summary>
|
||||
public Results.Entities.MeterTestRslt LastTestResult2;
|
||||
public Results.Entities.MeterTestRslt LastTestResult;
|
||||
public double NominalTestFlowLph; /// in liter per hour
|
||||
|
||||
|
||||
///
|
||||
/// Required for IRegisterReader interface
|
||||
///
|
||||
public int WMPulses { get { return wmPulses; } }
|
||||
public int WMRefPulses { get { return wmRefPulses; } }
|
||||
public double WMVolume { get { return wmVolume; } }
|
||||
public double BeginWMState { get { return beginWMState; } }
|
||||
public double EndWMState { get { return endWMState; } }
|
||||
public double WMTestTime { get { return wmTestTime; } }
|
||||
|
||||
|
||||
double beginWMState;
|
||||
double endWMState;
|
||||
double wmVolume;
|
||||
int wmPulses;
|
||||
int wmRefPulses;
|
||||
double wmTestTime;
|
||||
|
||||
|
||||
/// <summary> Name set by the test, to be used as a part of the opto-data log file name </summary>
|
||||
public string TestName;
|
||||
|
||||
/// <summary> Name set by the test, to be used as a part of the opto-data log file name </summary>
|
||||
public string BenchName;
|
||||
|
||||
///
|
||||
/// Volume of water from the opto telegram
|
||||
///
|
||||
private Int64 lastVolumeRaw; /// Last read raw volume
|
||||
private double volumeLtr; ///
|
||||
private double volumeLtr0;
|
||||
|
||||
|
||||
///
|
||||
/// Timestamp from the opto telegram
|
||||
///
|
||||
private double timestampSec;
|
||||
private double timestampSec0;
|
||||
|
||||
public bool NoSamples { get { return (timestampSecEnd - timestampSecStart) < float.Epsilon; } }
|
||||
public double TimestampSecStart { get { return timestampSecStart; } }
|
||||
public double TimestampSecEnd { get { return timestampSecEnd; } }
|
||||
double timestampSecStart;
|
||||
double timestampSecEnd;
|
||||
|
||||
public GenesisHead()
|
||||
{
|
||||
}
|
||||
|
||||
public GenesisHead(Generic.IComponentCfg cfg)
|
||||
: base(cfg)
|
||||
{
|
||||
ClearData();
|
||||
|
||||
genesisHeadCfg = cfg as GenesisHeadCfg;
|
||||
|
||||
log.Debug(this.ToString());
|
||||
}
|
||||
|
||||
|
||||
GenesisMeter myGenesis = null;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public GenesisMeter SetUp()
|
||||
{
|
||||
if (myGenesis != null)
|
||||
{
|
||||
myGenesis.DisposeMeter();
|
||||
}
|
||||
//add for gen
|
||||
|
||||
myGenesis = new GenesisMeter();
|
||||
myGenesis.SetupFromConfigFile(SlotNr);
|
||||
|
||||
GenesisHeadBatch.BatchHolder.Value.AddMeter(myGenesis);
|
||||
myGenesis.LogRawData(true);
|
||||
return myGenesis;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clear data related to a specific water meter
|
||||
/// </summary>
|
||||
public void ClearData()
|
||||
{
|
||||
resultCode = 0;
|
||||
|
||||
disabled = false;
|
||||
commFailed = false;
|
||||
endState = string.Empty;
|
||||
beginState = string.Empty;
|
||||
|
||||
configStruct = null;
|
||||
calibrationStruct = null;
|
||||
|
||||
LastTestResult = null;
|
||||
NominalTestFlowLph = 0;
|
||||
|
||||
OrigCalibFactor = 0;
|
||||
Q2ErrWOCorrection = 0;
|
||||
Q2CorrectionDone = false;
|
||||
Q2CorrRFlow = 0;
|
||||
}
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
ClearData();
|
||||
|
||||
if (DebugLevel == DebugMode.Normal)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public void RunDeviceBefore()
|
||||
{
|
||||
|
||||
|
||||
////todo: RD- Login??
|
||||
//if (DebugLevel == DebugMode.Normal)
|
||||
//{
|
||||
|
||||
|
||||
// if (myGenesis != null)
|
||||
// {
|
||||
// Log("TBF RunDeviceBefore");
|
||||
// //myGenesis.Login();
|
||||
// //myGenesis.InitMeasurement();
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// throw new Exception("No meter was bound!");
|
||||
// }
|
||||
//}
|
||||
//else if (DebugLevel == DebugMode.FailureDuringOperation)
|
||||
//{
|
||||
//}
|
||||
}
|
||||
|
||||
public void RunDeviceAfter() { }
|
||||
|
||||
public void StopDevice()
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
if (DebugLevel == DebugMode.Normal && myGenesis != null)
|
||||
{
|
||||
myGenesis.DisposeMeter();
|
||||
|
||||
GenesisHeadBatch.BatchHolder.Value.RemoveMeter(myGenesis);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public void StopDevice2() { }
|
||||
|
||||
/// <summary>
|
||||
/// Events: Event.ReadRegisterDone, Event.Error
|
||||
/// </summary>
|
||||
/// <returns>ReadWaterMeter instance reference casted to IOperaton</returns>
|
||||
public IOperation ReadRegisterOp()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clear data/counters related to a specific tests
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
resultCode = 0;
|
||||
|
||||
sampleNr = 0;
|
||||
|
||||
volumeLtr = 0;
|
||||
volumeLtr0 = 0;
|
||||
timestampSec = 0;
|
||||
timestampSec0 = 0;
|
||||
|
||||
ReadPulses();
|
||||
}
|
||||
|
||||
public void TestCompleted()
|
||||
{
|
||||
/// TODO: Implement
|
||||
}
|
||||
|
||||
|
||||
int sampleNr; /// This is to determine when the test start sample should be taken
|
||||
bool StoreStartPackage = false;
|
||||
bool StoreEndPackage = false;
|
||||
bool Enable = false;
|
||||
public bool IsCalibration = false;
|
||||
/// <summary>Start this operation</summary>
|
||||
public void Start()
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
public void StartRead(string TestName)
|
||||
{
|
||||
StoreStartPackage = false;
|
||||
StoreEndPackage = false;
|
||||
//Start mesurement
|
||||
if (DebugLevel == DebugMode.Normal)
|
||||
{
|
||||
if (myGenesis != null)
|
||||
{
|
||||
IsCalibration = false;
|
||||
Log("TBF Start Measurement");
|
||||
if (TestName.ToLower().Contains("calib"))
|
||||
{
|
||||
IsCalibration = true;
|
||||
myGenesis.StartCalibration();
|
||||
}
|
||||
else
|
||||
{
|
||||
myGenesis.StartMeasurement();
|
||||
}
|
||||
|
||||
StoreStartPackage = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Log(string text)
|
||||
{
|
||||
if (DebugLevel == DebugMode.Normal)
|
||||
{
|
||||
if (myGenesis != null)
|
||||
{
|
||||
myGenesis.WriteLog(text);
|
||||
}
|
||||
}
|
||||
}
|
||||
void readOutResults(Xylem.Common.Hardware.WaterMeter.CommonMeterDefinitions.MeasurementResults results)
|
||||
{
|
||||
|
||||
//if (StoreStartPackage)
|
||||
//{
|
||||
|
||||
// volumeLtr0 = results.StartData.GetVolumeQm() * 1000;
|
||||
// timestampSec0 = results.StartData.GetTimeS();
|
||||
// StoreStartPackage = false;
|
||||
//}
|
||||
//else if (!StoreEndPackage)
|
||||
//{
|
||||
|
||||
volumeLtr = results.EndData.GetVolumeQm() * 1000;
|
||||
timestampSec = results.EndData.GetTimeS();
|
||||
wmTestTime = results.TotalTimeS;
|
||||
wmVolume = results.TotalVolumeQm * 1000;
|
||||
ReadPulses();
|
||||
//}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// <summary>Run this operation</summary>
|
||||
/// <returns>eventDone</returns>
|
||||
public Event Run()
|
||||
{
|
||||
if (DebugLevel == DebugMode.Normal)
|
||||
{
|
||||
if (myGenesis != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
//var results = myGenesis.GetIntermediateMeasurementResult();
|
||||
//readOutResults(results);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return Event.ReadRegisterDone;
|
||||
}
|
||||
public double RefVolume = 0.0;
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
//Stop(null);
|
||||
if (DebugLevel == DebugMode.Normal && myGenesis != null)
|
||||
{
|
||||
if (IsCalibration)
|
||||
{
|
||||
myGenesis.StopCalibration();
|
||||
}
|
||||
else
|
||||
{
|
||||
myGenesis.StopMeasurement();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Stop this operation</summary>
|
||||
public void Stop(Double? testTimeS = null)
|
||||
{
|
||||
|
||||
if (DebugLevel == DebugMode.Normal && myGenesis != null)
|
||||
{
|
||||
Log("TBF Stop Measurement");
|
||||
if (IsCalibration)
|
||||
{
|
||||
//myGenesis.StopCalibration();
|
||||
int retryCounter = 400;
|
||||
while (myGenesis.GetCalibrationState() != Xylem.Common.Hardware.WaterMeter.CommonMeterDefinitions.ActionStates.IsCompleted)
|
||||
{
|
||||
if (retryCounter < 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
Thread.Sleep(10);
|
||||
retryCounter = retryCounter - 1;
|
||||
}
|
||||
try
|
||||
{
|
||||
var results = myGenesis.GetCalibrationResult();
|
||||
readOutResults(results[0]);
|
||||
if (RefVolume != 0.0)
|
||||
{
|
||||
myGenesis.CalculateCalibrationWithVol(RefVolume,0);
|
||||
myGenesis.SaveCalculatedCalibration(false);
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MarkAsError();
|
||||
Log("Error while Stop Calib " + ex.Message);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int retryCounter = 400;
|
||||
//myGenesis.StopMeasurement();
|
||||
while (myGenesis.GetMeasurementState() != Xylem.Common.Hardware.WaterMeter.CommonMeterDefinitions.ActionStates.IsCompleted)
|
||||
{
|
||||
if (retryCounter < 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
Thread.Sleep(10);
|
||||
retryCounter = retryCounter - 1;
|
||||
}
|
||||
try
|
||||
{
|
||||
var results = myGenesis.GetMeasurementResult(testTimeS);
|
||||
readOutResults(results);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MarkAsError();
|
||||
Log("Error while Stop Measurement " + ex.Message);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
StoreEndPackage = true;
|
||||
|
||||
}
|
||||
}
|
||||
void MarkAsError()
|
||||
{
|
||||
volumeLtr = 100;
|
||||
timestampSec = 1;
|
||||
wmTestTime = 1;
|
||||
wmVolume = 100;
|
||||
ReadPulses();
|
||||
}
|
||||
|
||||
void ReadPulses()
|
||||
{
|
||||
beginWMState = volumeLtr0;
|
||||
endWMState = volumeLtr;
|
||||
wmPulses = (int)(wmVolume * (double)PulsesPerLtr + 0.5);
|
||||
wmRefPulses = StateMachine.ControlBoard.EtPulses(0);
|
||||
}
|
||||
|
||||
|
||||
bool optoSerialPortParsingEnabled;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
62
TBF/BenchControl/TestMethods/GenHead/GenesisHeadCfg.cs
Normal file
62
TBF/BenchControl/TestMethods/GenHead/GenesisHeadCfg.cs
Normal file
@ -0,0 +1,62 @@
|
||||
///
|
||||
/// Copyright (c) 2015-2017 Sensus Metering Systems
|
||||
///
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Xml.Serialization;
|
||||
using Config.Entities;
|
||||
using TBF.BenchControl.Generic;
|
||||
using TBF.Resources;
|
||||
|
||||
namespace TBF.BenchControl.TestMethods.GenesisCommunication.GenesisHead
|
||||
{
|
||||
public class GenesisHeadCfg : ComponentCfgBase, Generic.IComponentCfg
|
||||
{
|
||||
public static XmlSerializer Serializer = XmlSerializer.FromTypes(new[] { typeof(GenesisHeadCfg) })[0];
|
||||
public override XmlSerializer GetSerializer() { return Serializer; }
|
||||
|
||||
|
||||
public IComponentCfgCtrl GetControl() { return new GenesisHeadCfgCtrl(); }
|
||||
|
||||
///
|
||||
/// Serialized parameters
|
||||
///
|
||||
public int SlotNr; /// Number written to QuidoRS to connct the watermeter to RfidComPort, 1 .. 10
|
||||
|
||||
/// <summary> Procedure parameters </summary>
|
||||
[XmlIgnore]
|
||||
public ProcParams ProcParams;
|
||||
public override IParamsProvider GetRuntimeProcParamsProvider() { return ProcParams; }
|
||||
public override IParamsProvider CreateProcParamsProvider() { return new ProcParams(true); }
|
||||
|
||||
[XmlIgnore]
|
||||
public MeterType MeterType { get { return (ProcParams != null) ? ProcParams.MeterType : MeterType.AutoDetect; } }
|
||||
|
||||
|
||||
/// Private parameterless constructor invoked by all other (public) constructors
|
||||
GenesisHeadCfg()
|
||||
{
|
||||
Name = "Genesis";
|
||||
ParentName = string.Empty;
|
||||
SlotNr = 0;
|
||||
ProcParams = new ProcParams(true);
|
||||
}
|
||||
|
||||
public GenesisHeadCfg(IComponentFactory factory)
|
||||
: this()
|
||||
{
|
||||
this.Factory = factory;
|
||||
}
|
||||
|
||||
public string ToString(int i)
|
||||
{
|
||||
return string.Format("{0} SlotNr={1}",
|
||||
Name,
|
||||
SlotNr
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
90
TBF/BenchControl/TestMethods/GenHead/GenesisHeadCfgCtrl.cs
Normal file
90
TBF/BenchControl/TestMethods/GenHead/GenesisHeadCfgCtrl.cs
Normal file
@ -0,0 +1,90 @@
|
||||
///
|
||||
/// Copyright (c) 2015-2017 Sensus Metering Systems
|
||||
///
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Windows.Forms;
|
||||
using log4net;
|
||||
using TBF.BenchControl.Generic;
|
||||
using TBF.Resources;
|
||||
using Config.Entities;
|
||||
|
||||
namespace TBF.BenchControl.TestMethods.GenesisCommunication.GenesisHead
|
||||
{
|
||||
public partial class GenesisHeadCfgCtrl : UserControl, IComponentCfgCtrl
|
||||
{
|
||||
static readonly ILog log = LogManager.GetLogger(typeof(GenesisHeadCfgCtrl));
|
||||
|
||||
public bool ShowMore { get { return false; } }
|
||||
|
||||
GenesisHeadCfg config;
|
||||
public IComponentCfg Config
|
||||
{
|
||||
get { return config as IComponentCfg; }
|
||||
set
|
||||
{
|
||||
config = value as GenesisHeadCfg;
|
||||
Redraw();
|
||||
}
|
||||
}
|
||||
|
||||
public GenesisHeadCfgCtrl()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void WaterMeterCfgCtrl_Load(object sender, EventArgs e)
|
||||
{
|
||||
nameLabel.Text = Strings.Name;
|
||||
classNameLabel.Text = config.Factory.ClassName;
|
||||
Redraw();
|
||||
}
|
||||
|
||||
public void Closing()
|
||||
{
|
||||
}
|
||||
|
||||
void Redraw()
|
||||
{
|
||||
if (config == null) return; /// Control was not loaded, settings were not changed
|
||||
nameTextBox.Text = config.Name;
|
||||
|
||||
|
||||
}
|
||||
|
||||
public void Unlock()
|
||||
{
|
||||
nameTextBox.Enabled = true;
|
||||
slotNrTextBox.Enabled = true;
|
||||
}
|
||||
|
||||
public CfgUpdateFlags VerifyCfg(ref string message)
|
||||
{
|
||||
CfgUpdateFlags flags = CfgUpdateFlags.None;
|
||||
|
||||
int dummy;
|
||||
|
||||
if (!int.TryParse(slotNrTextBox.Text, out dummy) || dummy < 1 || dummy > 7)
|
||||
{
|
||||
flags |= CfgUpdateFlags.Error;
|
||||
message += Environment.NewLine + string.Format(Strings.Invalid_0, muxBoardNrLabel.Text);
|
||||
}
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
public CfgUpdateFlags UpdateCfg()
|
||||
{
|
||||
CfgUpdateFlags flags = CfgUpdateFlags.RestartRqrd;
|
||||
|
||||
if (config == null) return CfgUpdateFlags.Error; /// Control was not loaded, settings were not changed
|
||||
|
||||
config.Name = nameTextBox.Text;
|
||||
|
||||
config.SlotNr = int.Parse(slotNrTextBox.Text);
|
||||
|
||||
return flags;
|
||||
}
|
||||
}
|
||||
}
|
||||
121
TBF/BenchControl/TestMethods/GenHead/GenesisHeadCfgCtrl.designer.cs
generated
Normal file
121
TBF/BenchControl/TestMethods/GenHead/GenesisHeadCfgCtrl.designer.cs
generated
Normal file
@ -0,0 +1,121 @@
|
||||
///
|
||||
/// Copyright (c) 2015-2017 Sensus Metering Systems
|
||||
///
|
||||
namespace TBF.BenchControl.TestMethods.GenesisCommunication.GenesisHead
|
||||
{
|
||||
partial class GenesisHeadCfgCtrl
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Component Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.nameTextBox = new System.Windows.Forms.TextBox();
|
||||
this.nameLabel = new System.Windows.Forms.Label();
|
||||
this.classNameLabel = new System.Windows.Forms.Label();
|
||||
this.slotNrTextBox = new System.Windows.Forms.TextBox();
|
||||
this.muxBoardNrLabel = new System.Windows.Forms.Label();
|
||||
this.label3 = new System.Windows.Forms.Label();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// nameTextBox
|
||||
//
|
||||
this.nameTextBox.Enabled = false;
|
||||
this.nameTextBox.Location = new System.Drawing.Point(135, 40);
|
||||
this.nameTextBox.Name = "nameTextBox";
|
||||
this.nameTextBox.Size = new System.Drawing.Size(121, 20);
|
||||
this.nameTextBox.TabIndex = 2;
|
||||
//
|
||||
// nameLabel
|
||||
//
|
||||
this.nameLabel.AutoSize = true;
|
||||
this.nameLabel.Location = new System.Drawing.Point(25, 43);
|
||||
this.nameLabel.Name = "nameLabel";
|
||||
this.nameLabel.Size = new System.Drawing.Size(35, 13);
|
||||
this.nameLabel.TabIndex = 1;
|
||||
this.nameLabel.Text = "Name";
|
||||
//
|
||||
// classNameLabel
|
||||
//
|
||||
this.classNameLabel.AutoSize = true;
|
||||
this.classNameLabel.Location = new System.Drawing.Point(132, 16);
|
||||
this.classNameLabel.Name = "classNameLabel";
|
||||
this.classNameLabel.Size = new System.Drawing.Size(60, 13);
|
||||
this.classNameLabel.TabIndex = 0;
|
||||
this.classNameLabel.Text = "ClassName";
|
||||
//
|
||||
// slotNrTextBox
|
||||
//
|
||||
this.slotNrTextBox.Enabled = false;
|
||||
this.slotNrTextBox.Location = new System.Drawing.Point(135, 63);
|
||||
this.slotNrTextBox.Name = "slotNrTextBox";
|
||||
this.slotNrTextBox.Size = new System.Drawing.Size(34, 20);
|
||||
this.slotNrTextBox.TabIndex = 9;
|
||||
//
|
||||
// muxBoardNrLabel
|
||||
//
|
||||
this.muxBoardNrLabel.AutoSize = true;
|
||||
this.muxBoardNrLabel.Location = new System.Drawing.Point(25, 66);
|
||||
this.muxBoardNrLabel.Name = "muxBoardNrLabel";
|
||||
this.muxBoardNrLabel.Size = new System.Drawing.Size(37, 13);
|
||||
this.muxBoardNrLabel.TabIndex = 8;
|
||||
this.muxBoardNrLabel.Text = "Slot nr";
|
||||
//
|
||||
// label3
|
||||
//
|
||||
this.label3.AutoSize = true;
|
||||
this.label3.Location = new System.Drawing.Point(176, 66);
|
||||
this.label3.Name = "label3";
|
||||
this.label3.Size = new System.Drawing.Size(31, 13);
|
||||
this.label3.TabIndex = 13;
|
||||
this.label3.Text = "1 .. 6";
|
||||
//
|
||||
// GenesisHeadCfgCtrl
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.Controls.Add(this.label3);
|
||||
this.Controls.Add(this.slotNrTextBox);
|
||||
this.Controls.Add(this.muxBoardNrLabel);
|
||||
this.Controls.Add(this.nameTextBox);
|
||||
this.Controls.Add(this.nameLabel);
|
||||
this.Controls.Add(this.classNameLabel);
|
||||
this.Name = "GenesisHeadCfgCtrl";
|
||||
this.Size = new System.Drawing.Size(396, 123);
|
||||
this.Load += new System.EventHandler(this.WaterMeterCfgCtrl_Load);
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.TextBox nameTextBox;
|
||||
private System.Windows.Forms.Label nameLabel;
|
||||
private System.Windows.Forms.Label classNameLabel;
|
||||
private System.Windows.Forms.TextBox slotNrTextBox;
|
||||
private System.Windows.Forms.Label muxBoardNrLabel;
|
||||
private System.Windows.Forms.Label label3;
|
||||
}
|
||||
}
|
||||
120
TBF/BenchControl/TestMethods/GenHead/GenesisHeadCfgCtrl.resx
Normal file
120
TBF/BenchControl/TestMethods/GenHead/GenesisHeadCfgCtrl.resx
Normal file
@ -0,0 +1,120 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
||||
@ -0,0 +1,20 @@
|
||||
///
|
||||
/// Copyright (c) 2015-2017 Sensus Metering Systems
|
||||
///
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace TBF.BenchControl.TestMethods.GenesisCommunication.GenesisHead
|
||||
{
|
||||
public class OptoReceivedEventArgs : EventArgs
|
||||
{
|
||||
public string Data;
|
||||
|
||||
public OptoReceivedEventArgs(string data)
|
||||
{
|
||||
this.Data = data;
|
||||
}
|
||||
}
|
||||
}
|
||||
296
TBF/BenchControl/TestMethods/GenHead/OptoTelegramRaw.cs
Normal file
296
TBF/BenchControl/TestMethods/GenHead/OptoTelegramRaw.cs
Normal file
@ -0,0 +1,296 @@
|
||||
///
|
||||
/// Copyright (c) 2015-2017 Sensus Metering Systems
|
||||
///
|
||||
using System;
|
||||
using System.Globalization;
|
||||
|
||||
namespace TBF.BenchControl.TestMethods.GenesisCommunication.GenesisHead
|
||||
{
|
||||
public class OptoTelegramRaw
|
||||
{
|
||||
public static readonly int Length = 42;
|
||||
private static CultureInfo culture;
|
||||
|
||||
|
||||
///
|
||||
/// Strobed value
|
||||
///
|
||||
public static decimal TestStartTimestampDec;
|
||||
|
||||
///
|
||||
/// Stored values
|
||||
///
|
||||
public OptoTelegramFlags Flags;
|
||||
|
||||
public DateTime DateTime; /// From PC
|
||||
public float RefFlow; /// [m3/h]
|
||||
public int Counter;
|
||||
|
||||
public UInt32 EmfRaw; /// From iPerl opto data
|
||||
public Int16 MagneticFieldRaw;
|
||||
public Int16 FlowRaw;
|
||||
public UInt32 VolumeRaw;
|
||||
public Int64 VolumeRawExt;
|
||||
public Int16 Impedance;
|
||||
public UInt32 Timestamp;
|
||||
public Int64 TimestampExt;
|
||||
public byte CheckSum;
|
||||
|
||||
///
|
||||
/// Calculated values
|
||||
///
|
||||
public double EMF()
|
||||
{
|
||||
Int32 signedEmf = (EmfRaw > 0x7FFFFF) ? ((int)EmfRaw - 0x1000000) : (int)EmfRaw;
|
||||
return 0.000000333 * (double)signedEmf;
|
||||
}
|
||||
public double MagneticField() { return (double)MagneticFieldRaw; }
|
||||
public double Flow(double scalingFactor) { return 0.225 * scalingFactor * (double)FlowRaw; }
|
||||
public double Volume(double scalingFactor) { return 0.0000625 * scalingFactor * (double)VolumeRawExt; }
|
||||
public Int32 FlipTime() { return Impedance; }
|
||||
public decimal TimestampDec() { return (decimal)TimestampExt / (decimal)8192; }
|
||||
public double VolumeDelta(double scalingFactor, OptoTelegramRaw previous) { return (previous == null) ? 0 : Volume(scalingFactor) - previous.Volume(scalingFactor); }
|
||||
public decimal TimeDelta() { return TimestampDec() - TestStartTimestampDec; }
|
||||
public string Label()
|
||||
{
|
||||
if (Flags == OptoTelegramFlags.OK_TestStart) return "#### start test ####";
|
||||
else if (Flags == OptoTelegramFlags.OK_TestEnd) return "#### end of test ####";
|
||||
else return string.Empty;
|
||||
}
|
||||
|
||||
|
||||
static OptoTelegramRaw()
|
||||
{
|
||||
culture = CultureInfo.CreateSpecificCulture("DE"); /// This is to use comma as decimal number separator
|
||||
}
|
||||
|
||||
public OptoTelegramRaw()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses optical telegram and returns OptoTelegramRaw object
|
||||
/// </summary>
|
||||
/// <description>
|
||||
/// Create a configuration structure from a complete byte array
|
||||
///
|
||||
/// Telegram description:
|
||||
///
|
||||
/// AAAAAA[tab]BBBB[tab]CCCC[tab]DDDDDD[tab]EEEE[tab]FFFFFFFF[tab]GG[cr][lf] (42 bytes)
|
||||
///
|
||||
/// Data Comment Type Calculate to decimal
|
||||
/// ----------------------------------------------------------------
|
||||
/// AAAAAA EMF Int24 Value * 0.000000333
|
||||
/// BBBB Magnetic field Int16 Value
|
||||
/// CCCC Flow Int16 Value * 0.225 * Scalig factor
|
||||
/// DDDDDD Volume Int24 Value / 16000 * Scaling factor
|
||||
/// EEEE Impedance Int16 Value
|
||||
/// FFFFFFFF Timestamp Uint32 Value / 8192
|
||||
/// GG Checksum Byte
|
||||
/// ----------------------------------------------------------------
|
||||
///
|
||||
/// Example:
|
||||
/// FFFFFE 51EA 0000 65324E 0087 F6319DFF 86
|
||||
/// FFDD3A 51F9 0000 65324E 0088 F631A60B 45
|
||||
/// ...
|
||||
/// </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, ref Int64 volumeRawExtLast, ref Int64 timestampExtLast)
|
||||
{
|
||||
DateTime = DateTime.Now;
|
||||
Counter = counter;
|
||||
RefFlow = (float)Sequences.ProcessData.RefFlow.Val;
|
||||
|
||||
if ((telegram == null) || (telegram.Length < Length) ||
|
||||
(telegram[6] != '\t') || (telegram[11] != '\t') || (telegram[16] != '\t') ||
|
||||
(telegram[23] != '\t') || (telegram[28] != '\t') || (telegram[37] != '\t') ||
|
||||
(telegram[40] != '\r') || (telegram[41] != '\n'))
|
||||
{
|
||||
Flags = OptoTelegramFlags.InvalidTelegram;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool f1 = UInt32.TryParse(telegram.Substring(0, 6), NumberStyles.HexNumber, CultureInfo.CurrentCulture, out EmfRaw);
|
||||
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);
|
||||
|
||||
bool allOk = f1 && f2 && f3 && f4 && f5 && f6 && f7;
|
||||
Flags = allOk ? OptoTelegramFlags.OK : OptoTelegramFlags.InvalidTelegram;
|
||||
|
||||
///
|
||||
/// 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;
|
||||
}
|
||||
|
||||
return allOk;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Alternative to UpdateFromString(...) when data are flushed
|
||||
/// </summary>
|
||||
public bool UpdateFromStringDummy(string telegram)
|
||||
{
|
||||
DateTime = DateTime.Now;
|
||||
RefFlow = (float)Sequences.ProcessData.RefFlow.Val;
|
||||
|
||||
if ((telegram == null) || (telegram.Length < Length) ||
|
||||
(telegram[6] != '\t') || (telegram[11] != '\t') || (telegram[16] != '\t') ||
|
||||
(telegram[23] != '\t') || (telegram[28] != '\t') || (telegram[37] != '\t') ||
|
||||
(telegram[40] != '\r') || (telegram[41] != '\n'))
|
||||
{
|
||||
Flags = OptoTelegramFlags.InvalidTelegram;
|
||||
return false;
|
||||
}
|
||||
|
||||
//bool f1 = UInt32.TryParse(telegram.Substring(0, 6), NumberStyles.HexNumber, CultureInfo.CurrentCulture, out EmfRaw);
|
||||
//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);
|
||||
//return f1 && f2 && f3 && f4 && f5 && f6 && f7;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public void SetFlags(OptoTelegramFlags flags)
|
||||
{
|
||||
this.Flags = flags;
|
||||
}
|
||||
|
||||
|
||||
public string ToString(double scalingFactor, OptoTelegramRaw previous)
|
||||
{
|
||||
if (Flags == OptoTelegramFlags.SyncError)
|
||||
{
|
||||
return "Sychronization error";
|
||||
}
|
||||
else if (Flags == OptoTelegramFlags.InvalidTelegram)
|
||||
{
|
||||
return "Invalid telegram";
|
||||
}
|
||||
else /// if (flags == OptoTelegramFlags.OK / OptoTelegramFlags.OK_TestStart / OptoTelegramFlags.OK_TestEnd)
|
||||
{
|
||||
return string.Format("{0}:{1}:{2}.{3}\t{4} :\t{5}\t{6}\t{7}\t{8}\t{9}\t{10}\t{11}\t{12}\t{13}\t{14}\t{15}\t{16}\t{17}\t{18}\t{19}\t{20}\t{21}\t{22}",
|
||||
DateTime.Hour.ToString("D2"),
|
||||
DateTime.Minute.ToString("D2"),
|
||||
DateTime.Second.ToString("D2"),
|
||||
DateTime.Millisecond.ToString("D4"),
|
||||
Counter,
|
||||
EmfRaw.ToString("X6"),
|
||||
MagneticFieldRaw.ToString("X4"),
|
||||
FlowRaw.ToString("X4"),
|
||||
VolumeRaw.ToString("X6"),
|
||||
Impedance.ToString("X4"),
|
||||
Timestamp.ToString("X8"),
|
||||
CheckSum.ToString("X2"),
|
||||
EMF().ToString("F4", culture),
|
||||
MagneticField().ToString("F0", culture),
|
||||
Flow(scalingFactor).ToString("F2", culture),
|
||||
Volume(scalingFactor).ToString("F4", culture),
|
||||
FlipTime().ToString("F0", culture),
|
||||
TimestampDec().ToString("F4", culture),
|
||||
(RefFlow * 1000).ToString("F2", culture),
|
||||
VolumeDelta(scalingFactor, previous).ToString("F4", culture),
|
||||
TimeDelta().ToString("F3", culture),
|
||||
scalingFactor.ToString("F1", culture),
|
||||
Label());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Filter RefFlow data in an array of OptoTelegramRaw objects by a FIR filter:
|
||||
///
|
||||
/// kSize = 5, kSize2 = 2
|
||||
///
|
||||
/// i k
|
||||
/// ---------------------------------------------------------------------------
|
||||
/// 0 -5 filtered[0] = data[0]
|
||||
/// 1 -4 filtered[1] = data[1]
|
||||
/// 2 -3 filtered[2] = data[0]*k[0] + ... + data[4]*k[4]
|
||||
/// 3 -2 filtered[3] = data[1]*k[0] + ... + data[5]*k[4]
|
||||
/// 4 -1 filtered[4] = data[2]*k[0] + ... + data[6]*k[4]
|
||||
/// 5 0 data[0] = filtered[0], filtered[0] = data[3]*k[0] + ... + data[7]*k[4]
|
||||
/// 6 1 data[1] = filtered[1], filtered[1] = data[4]*k[0] + ... + data[8]*k[4]
|
||||
/// 7 ...
|
||||
/// </summary>
|
||||
/// <param name="optoData">array of OptoTelegramRaw objects</param>
|
||||
/// <param name="optoDataCount">number of objects to process</param>
|
||||
public static void FIRFilterFlow(OptoTelegramRaw[] optoData, int optoDataCount)
|
||||
{
|
||||
float[] kernel = new float[] { 0.1f, 0.2f, 0.4f, 0.2f, 0.1f };
|
||||
int kSize = kernel.Length;
|
||||
int kSize2 = kernel.Length / 2;
|
||||
|
||||
float[] filtered = new float[kSize];
|
||||
|
||||
for (int i = 0; i < optoDataCount; i++)
|
||||
{
|
||||
int k = i - kSize;
|
||||
if (k >= 0) optoData[k].RefFlow = filtered[i % kSize];
|
||||
|
||||
if (i < kSize2 || i >= optoDataCount - kSize2)
|
||||
{
|
||||
filtered[i % kSize] = optoData[i].RefFlow;
|
||||
}
|
||||
else
|
||||
{
|
||||
float weoightedSum = 0;
|
||||
for (int j = -kSize2; j <= kSize2; j++)
|
||||
weoightedSum += optoData[i + j].RefFlow * kernel[j + kSize2];
|
||||
|
||||
filtered[i % kSize] = weoightedSum;
|
||||
}
|
||||
}
|
||||
|
||||
for (int k = optoDataCount - kSize; k < optoDataCount; k++)
|
||||
{
|
||||
if (k >= 0) optoData[k].RefFlow = filtered[k % kSize];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
183
TBF/BenchControl/TestMethods/GenHead/ProcParams.cs
Normal file
183
TBF/BenchControl/TestMethods/GenHead/ProcParams.cs
Normal file
@ -0,0 +1,183 @@
|
||||
///
|
||||
/// Copyright (c) 2015-2017 Sensus Metering Systems
|
||||
///
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Xml.Serialization;
|
||||
using Config.Entities;
|
||||
using TBF.BenchControl.Generic;
|
||||
using TBF.Resources;
|
||||
|
||||
namespace TBF.BenchControl.TestMethods.GenesisCommunication.GenesisHead
|
||||
{
|
||||
public class ProcParams : ProcedureParamsBase, IParamsProvider, IProcedureParams
|
||||
{
|
||||
public static XmlSerializer Serializer = XmlSerializer.FromTypes(new[] { typeof(ProcParams) })[0];
|
||||
public override XmlSerializer GetSerializer() { return Serializer; }
|
||||
|
||||
public MeterType MeterType;
|
||||
public float CalibTarget; /// Target error after calibration in [%]
|
||||
public int FactorLimitLo; /// Lower limit for the calibration factor
|
||||
public int FactorLimitHi; /// Upper limit for the calibration factor
|
||||
#if ORACLE_DB
|
||||
public int WMType_ID; /// Required for Oracle DB: ID_WZTyp in table VT_PRUEFPUNKT_SOLL_SD
|
||||
public int WMType_Rev; /// Required for Oracle DB: Rev_WZTyp in table VT_PRUEFPUNKT_SOLL_SD
|
||||
#endif
|
||||
|
||||
|
||||
public override void InitializeAll()
|
||||
{
|
||||
MeterType = MeterType.AutoDetect;
|
||||
CalibTarget = 0;
|
||||
FactorLimitLo = 1000;
|
||||
FactorLimitHi = 8000;
|
||||
#if ORACLE_DB
|
||||
WMType_ID = 2; /// Value for iPerl DN15
|
||||
WMType_Rev = 1; /// Value for iPerl DN15
|
||||
#endif
|
||||
}
|
||||
|
||||
string[] paramNames = new string[]
|
||||
{
|
||||
"iPerl type",
|
||||
"Calib. target [%]",
|
||||
"Calib. factor Lo",
|
||||
"Calib. factor Hi",
|
||||
#if ORACLE_DB
|
||||
"WMType ID",
|
||||
"WMType Rev.",
|
||||
#endif
|
||||
};
|
||||
public override string ParamName(int i) { return paramNames[i]; }
|
||||
public override int ParamsCount() { return paramNames.Length; }
|
||||
|
||||
public override string ToString(int i)
|
||||
{
|
||||
switch (i)
|
||||
{
|
||||
case 0: return MeterType.ToString();
|
||||
case 1: return CalibTarget.ToString();
|
||||
case 2: return FactorLimitLo.ToString();
|
||||
case 3: return FactorLimitHi.ToString();
|
||||
#if ORACLE_DB
|
||||
case 4: return WMType_ID.ToString();
|
||||
case 5: return WMType_Rev.ToString();
|
||||
#endif
|
||||
default: return string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
public CfgUpdateFlags UpdateParam(int i, string strValue)
|
||||
{
|
||||
switch (i)
|
||||
{
|
||||
case 0:
|
||||
for (MeterType mt = 0; mt < MeterType.Count; mt++)
|
||||
{
|
||||
if (mt.ToString().Equals(strValue)) { MeterType = mt; return CfgUpdateFlags.AnyChange; }
|
||||
}
|
||||
break;
|
||||
case 1: CalibTarget = Utils.ParseSFloat(strValue); return CfgUpdateFlags.AnyChange;
|
||||
case 2: FactorLimitLo = int.Parse(strValue); return CfgUpdateFlags.AnyChange;
|
||||
case 3: FactorLimitHi = int.Parse(strValue); return CfgUpdateFlags.AnyChange;
|
||||
#if ORACLE_DB
|
||||
case 4: WMType_ID = int.Parse(strValue); return;
|
||||
case 5: WMType_Rev = int.Parse(strValue); return;
|
||||
#endif
|
||||
default: return CfgUpdateFlags.None;
|
||||
}
|
||||
return CfgUpdateFlags.None;
|
||||
|
||||
}
|
||||
|
||||
public bool ValidateParam(int i, string strValue, out string message)
|
||||
{
|
||||
message = string.Empty;
|
||||
|
||||
int iDummy;
|
||||
float fDummy;
|
||||
|
||||
switch (i)
|
||||
{
|
||||
case 0:
|
||||
for (MeterType mt = 0; mt < MeterType.Count; mt++) if (mt.ToString().Equals(strValue)) return true;
|
||||
break;
|
||||
case 1:
|
||||
if (Utils.TryParseSFloat(strValue, out fDummy) && fDummy >= -10.0f && fDummy <= 10.0f) return true;
|
||||
break;
|
||||
case 2:
|
||||
case 3:
|
||||
if (int.TryParse(strValue, out iDummy) && iDummy >= 1000 && iDummy <= 8000) return true;
|
||||
break;
|
||||
|
||||
#if ORACLE_DB
|
||||
case 4: /// WMType_ID
|
||||
case 5: /// WMType_Rev
|
||||
if (int.TryParse(strValue, out iDummy)) return true;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
message = "Invalid index";
|
||||
return false;
|
||||
}
|
||||
|
||||
message = ParamName(i) + " is invalid";
|
||||
return false;
|
||||
}
|
||||
|
||||
void CopyContentTo(ProcParams prms)
|
||||
{
|
||||
prms.MeterType = this.MeterType;
|
||||
prms.CalibTarget = this.CalibTarget;
|
||||
prms.FactorLimitLo = this.FactorLimitLo;
|
||||
prms.FactorLimitHi = this.FactorLimitHi;
|
||||
#if ORACLE_DB
|
||||
prms.WMType_ID = this.WMType_ID;
|
||||
prms.WMType_Rev = this.WMType_Rev;
|
||||
#endif
|
||||
}
|
||||
|
||||
public IParamsProvider Clone()
|
||||
{
|
||||
ProcParams pars = new ProcParams();
|
||||
CopyContentTo(pars);
|
||||
return pars;
|
||||
}
|
||||
|
||||
public void UpdateProcedureParams(ComponentProcedure dbEntity)
|
||||
{
|
||||
if (dbEntity == null) return;
|
||||
try
|
||||
{
|
||||
ProcParams tmp = Serializer.Deserialize(new StringReader(dbEntity.Parameters)) as ProcParams;
|
||||
|
||||
procedureParamsEntity = dbEntity;
|
||||
componentName = dbEntity.CmpntName;
|
||||
procedure = dbEntity.Procedure;
|
||||
|
||||
if (tmp != null) tmp.CopyContentTo(this);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public ProcParams()
|
||||
{
|
||||
}
|
||||
|
||||
public ProcParams(bool initialize)
|
||||
{
|
||||
if (initialize) InitializeAll();
|
||||
}
|
||||
|
||||
public ProcParams(ComponentProcedure procParamsEntity, string componentName, Procedure procedure)
|
||||
{
|
||||
this.procedureParamsEntity = procParamsEntity;
|
||||
this.componentName = componentName;
|
||||
this.procedure = procedure;
|
||||
}
|
||||
}
|
||||
}
|
||||
160
TBF/BenchControl/TestMethods/GenHead/StatusStruct.cs
Normal file
160
TBF/BenchControl/TestMethods/GenHead/StatusStruct.cs
Normal file
@ -0,0 +1,160 @@
|
||||
///
|
||||
/// Copyright (c) 2015-2017 Sensus Metering Systems
|
||||
///
|
||||
using System;
|
||||
|
||||
namespace TBF.BenchControl.TestMethods.GenesisCommunication.GenesisHead
|
||||
{
|
||||
public class StatusStruct
|
||||
{
|
||||
public static readonly int Length = 48;
|
||||
|
||||
public Byte Version;
|
||||
public FlowState FlowState;
|
||||
public UInt32 BillingVolume;
|
||||
public UInt32 ForwardVolume;
|
||||
public UInt32 ReverseVolume;
|
||||
public UInt32 SecondsActive;
|
||||
public UInt32 SecondsIdle;
|
||||
public UInt32 SecondsUsed;
|
||||
public UInt32 UTC;
|
||||
public Int32 ScaledAvgFlowRate;
|
||||
public UInt16 PeakFlowRate;
|
||||
public UInt16 AlarmState;
|
||||
public byte RebootCount;
|
||||
public byte[] AlarmCount;
|
||||
public UInt16 FlipTime;
|
||||
|
||||
|
||||
public StatusStruct()
|
||||
{
|
||||
AlarmCount = new byte[7];
|
||||
}
|
||||
|
||||
public byte[] ToByteArray()
|
||||
{
|
||||
byte[] result = new byte[Length];
|
||||
|
||||
result[0] = Version;
|
||||
result[1] = (byte)FlowState;
|
||||
|
||||
result[2] = (byte)(BillingVolume & 0x000000FF);
|
||||
result[3] = (byte)((BillingVolume >> 8) & 0x000000FF);
|
||||
result[4] = (byte)((BillingVolume >> 16) & 0x000000FF);
|
||||
result[5] = (byte)((BillingVolume >> 24) & 0x000000FF);
|
||||
|
||||
result[6] = (byte)(ForwardVolume & 0x000000FF);
|
||||
result[7] = (byte)((ForwardVolume >> 8) & 0x000000FF);
|
||||
result[8] = (byte)((ForwardVolume >> 16) & 0x000000FF);
|
||||
result[9] = (byte)((ForwardVolume >> 24) & 0x000000FF);
|
||||
|
||||
result[10] = (byte)(ReverseVolume & 0x000000FF);
|
||||
result[11] = (byte)((ReverseVolume >> 8) & 0x000000FF);
|
||||
result[12] = (byte)((ReverseVolume >> 16) & 0x000000FF);
|
||||
result[13] = (byte)((ReverseVolume >> 24) & 0x000000FF);
|
||||
|
||||
result[14] = (byte)(SecondsActive & 0x000000FF);
|
||||
result[15] = (byte)((SecondsActive >> 8) & 0x000000FF);
|
||||
result[16] = (byte)((SecondsActive >> 16) & 0x000000FF);
|
||||
result[17] = (byte)((SecondsActive >> 24) & 0x000000FF);
|
||||
|
||||
result[18] = (byte)(SecondsIdle & 0x000000FF);
|
||||
result[19] = (byte)((SecondsIdle >> 8) & 0x000000FF);
|
||||
result[20] = (byte)((SecondsIdle >> 16) & 0x000000FF);
|
||||
result[21] = (byte)((SecondsIdle >> 24) & 0x000000FF);
|
||||
|
||||
result[22] = (byte)(SecondsUsed & 0x000000FF);
|
||||
result[23] = (byte)((SecondsUsed >> 8) & 0x000000FF);
|
||||
result[24] = (byte)((SecondsUsed >> 16) & 0x000000FF);
|
||||
result[25] = (byte)((SecondsUsed >> 24) & 0x000000FF);
|
||||
|
||||
result[26] = (byte)(UTC & 0x000000FF);
|
||||
result[27] = (byte)((UTC >> 8) & 0x000000FF);
|
||||
result[28] = (byte)((UTC >> 16) & 0x000000FF);
|
||||
result[29] = (byte)((UTC >> 24) & 0x000000FF);
|
||||
|
||||
result[30] = (byte)(ScaledAvgFlowRate & 0x000000FF);
|
||||
result[31] = (byte)((ScaledAvgFlowRate >> 8) & 0x000000FF);
|
||||
result[32] = (byte)((ScaledAvgFlowRate >> 16) & 0x000000FF);
|
||||
result[33] = (byte)((ScaledAvgFlowRate >> 24) & 0x000000FF); /// TODO: test with negative value
|
||||
|
||||
result[34] = (byte)(PeakFlowRate & 0x00FF);
|
||||
result[35] = (byte)((PeakFlowRate >> 8) & 0x00FF);
|
||||
|
||||
result[36] = (byte)(AlarmState & 0x00FF);
|
||||
result[37] = (byte)((AlarmState >> 8) & 0x00FF);
|
||||
|
||||
result[38] = RebootCount;
|
||||
|
||||
result[39] = AlarmCount[0];
|
||||
result[40] = AlarmCount[1];
|
||||
result[41] = AlarmCount[2];
|
||||
result[42] = AlarmCount[3];
|
||||
result[43] = AlarmCount[4];
|
||||
result[44] = AlarmCount[5];
|
||||
result[45] = AlarmCount[6];
|
||||
|
||||
result[46] = (byte)(FlipTime & 0x00FF);
|
||||
result[47] = (byte)((FlipTime >> 8) & 0x00FF);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static StatusStruct FromByteArray(byte[] data)
|
||||
{
|
||||
if (data.Length != Length) return null;
|
||||
|
||||
StatusStruct result = new StatusStruct();
|
||||
|
||||
result.Version = data[0];
|
||||
result.FlowState = (FlowState)data[1];
|
||||
result.BillingVolume = (((UInt32)data[5] * 256 + data[4]) * 256 + data[3]) * 256 + data[2];
|
||||
result.ForwardVolume = (((UInt32)data[9] * 256 + data[8]) * 256 + data[7]) * 256 + data[6];
|
||||
result.ReverseVolume = (((UInt32)data[13] * 256 + data[12]) * 256 + data[11]) * 256 + data[10];
|
||||
result.SecondsActive = (((UInt32)data[17] * 256 + data[16]) * 256 + data[15]) * 256 + data[14];
|
||||
result.SecondsIdle = (((UInt32)data[21] * 256 + data[20]) * 256 + data[19]) * 256 + data[18];
|
||||
result.SecondsUsed = (((UInt32)data[25] * 256 + data[24]) * 256 + data[23]) * 256 + data[22];
|
||||
result.UTC = (((UInt32)data[29] * 256 + data[28]) * 256 + data[27]) * 256 + data[26];
|
||||
result.ScaledAvgFlowRate = (((Int32)data[33] * 256 + data[32]) * 256 + data[31]) * 256 + data[30]; /// TODO: test with negative value
|
||||
result.PeakFlowRate = (UInt16)(data[34] + 256 * data[35]);
|
||||
result.AlarmState = (UInt16)(data[36] + 256 * data[37]);
|
||||
result.RebootCount = data[38];
|
||||
result.AlarmCount[0] = data[39];
|
||||
result.AlarmCount[1] = data[40];
|
||||
result.AlarmCount[2] = data[41];
|
||||
result.AlarmCount[3] = data[42];
|
||||
result.AlarmCount[4] = data[43];
|
||||
result.AlarmCount[5] = data[44];
|
||||
result.AlarmCount[6] = data[45];
|
||||
result.FlipTime = (UInt16)(data[46] * 256 + data[47]);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format("Status: V{0} Flow={1} BillVol={2} ForwVol={3} RevVol={4} SecActive={5}s SecIdle={6}s SecUsed={7}s UTC={8} AvgFlowRate={9} PeekFlowRate={10} AlarmState={11} RebootCount={12} A0={13} A1={14} A2={15} A3={16} A4={17} A5={18} A6={19} FlipTime={20}",
|
||||
Version,
|
||||
FlowState,
|
||||
BillingVolume,
|
||||
ForwardVolume,
|
||||
ReverseVolume,
|
||||
SecondsActive,
|
||||
SecondsIdle,
|
||||
SecondsUsed,
|
||||
UTC,
|
||||
ScaledAvgFlowRate,
|
||||
PeakFlowRate,
|
||||
AlarmState,
|
||||
RebootCount,
|
||||
AlarmCount[0],
|
||||
AlarmCount[1],
|
||||
AlarmCount[2],
|
||||
AlarmCount[3],
|
||||
AlarmCount[4],
|
||||
AlarmCount[5],
|
||||
AlarmCount[6],
|
||||
FlipTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
197
TBF/BenchControl/TestMethods/GenesisHead/CalibrationStruct.cs
Normal file
197
TBF/BenchControl/TestMethods/GenesisHead/CalibrationStruct.cs
Normal file
@ -0,0 +1,197 @@
|
||||
///
|
||||
/// Copyright (c) 2015-2017 Sensus Metering Systems
|
||||
///
|
||||
using System;
|
||||
|
||||
namespace TBF.BenchControl.TestMethods.GenesisCommunication.GenesisHead
|
||||
{
|
||||
public class CalibrationStruct
|
||||
{
|
||||
public static readonly int Length = 35;
|
||||
|
||||
public Byte Version;
|
||||
public MeterType MeterType;
|
||||
public UInt16 Calibration;
|
||||
public VolumeUnits VolumeUnits;
|
||||
public FlowArrow FlowArrow;
|
||||
public UInt16 FWVersion;
|
||||
public UInt16[] TargetField;
|
||||
public UInt16 RecipMeanCurrent;
|
||||
public UInt16 ThresholdVolume;
|
||||
public UInt16 ThresholdTime;
|
||||
public UInt16 FlowActivationThr;
|
||||
public UInt16 VolumeArrowThr;
|
||||
public UInt32 CalibrationTime;
|
||||
public ulong SerialNumber;
|
||||
public MeterSealed MeterSealed;
|
||||
public byte CheckSum;
|
||||
|
||||
|
||||
public CalibrationStruct()
|
||||
{
|
||||
TargetField = new UInt16[3];
|
||||
}
|
||||
|
||||
public byte[] ToByteArray()
|
||||
{
|
||||
byte[] result = new byte[Length];
|
||||
|
||||
result[0] = Version;
|
||||
result[1] = (byte)MeterType;
|
||||
|
||||
result[2] = (byte)(Calibration & 0x00FF);
|
||||
result[3] = (byte)((Calibration >> 8) & 0x00FF);
|
||||
|
||||
result[4] = (byte)VolumeUnits;
|
||||
|
||||
result[5] = (byte)FlowArrow;
|
||||
|
||||
result[6] = (byte)(FWVersion & 0x00FF);
|
||||
result[7] = (byte)((FWVersion >> 8) & 0x00FF);
|
||||
|
||||
result[8] = (byte)( TargetField[0] & 0x00FF);
|
||||
result[9] = (byte)((TargetField[0] >> 8) & 0x00FF);
|
||||
result[10] = (byte)( TargetField[1] & 0x00FF);
|
||||
result[11] = (byte)((TargetField[1] >> 8) & 0x00FF);
|
||||
result[12] = (byte)( TargetField[2] & 0x00FF);
|
||||
result[13] = (byte)((TargetField[2] >> 8) & 0x00FF);
|
||||
|
||||
result[14] = (byte)(RecipMeanCurrent & 0x00FF);
|
||||
result[15] = (byte)((RecipMeanCurrent >> 8) & 0x00FF);
|
||||
|
||||
result[16] = (byte)(ThresholdVolume & 0x00FF);
|
||||
result[17] = (byte)((ThresholdVolume >> 8) & 0x00FF);
|
||||
|
||||
result[18] = (byte)(ThresholdTime & 0x00FF);
|
||||
result[19] = (byte)((ThresholdTime >> 8) & 0x00FF);
|
||||
|
||||
result[20] = (byte)(FlowActivationThr & 0x00FF);
|
||||
result[21] = (byte)((FlowActivationThr >> 8) & 0x00FF);
|
||||
|
||||
result[22] = (byte)(VolumeArrowThr & 0x00FF);
|
||||
result[23] = (byte)((VolumeArrowThr >> 8) & 0x00FF);
|
||||
|
||||
result[24] = (byte)(CalibrationTime & 0x000000FF);
|
||||
result[25] = (byte)((CalibrationTime >> 8) & 0x000000FF);
|
||||
result[26] = (byte)((CalibrationTime >> 16) & 0x000000FF);
|
||||
result[27] = (byte)((CalibrationTime >> 24) & 0x000000FF);
|
||||
|
||||
result[28] = (byte)(SerialNumber & 0x00000000000000FF);
|
||||
result[29] = (byte)((SerialNumber >> 8) & 0x00000000000000FF);
|
||||
result[30] = (byte)((SerialNumber >> 16) & 0x00000000000000FF);
|
||||
result[31] = (byte)((SerialNumber >> 24) & 0x00000000000000FF);
|
||||
result[32] = (byte)((SerialNumber >> 32) & 0x00000000000000FF);
|
||||
|
||||
result[33] = (byte)MeterSealed;
|
||||
result[34] = CheckSum;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a calibration structure from a complete byte array
|
||||
/// </summary>
|
||||
/// <param name="data">A complete byte array data</param>
|
||||
/// <returns>CalibrationStruct or null when byte array was not complete</returns>
|
||||
public static CalibrationStruct FromByteArray(byte[] data)
|
||||
{
|
||||
if (data.Length != Length) return null;
|
||||
|
||||
CalibrationStruct result = new CalibrationStruct();
|
||||
|
||||
result.Version = data[0];
|
||||
result.MeterType = (MeterType)data[1];
|
||||
result.Calibration = (UInt16)(data[2] + 256 * data[3]);
|
||||
result.VolumeUnits = (VolumeUnits)data[4];
|
||||
result.FlowArrow = (FlowArrow)data[5];
|
||||
result.FWVersion = (UInt16)(data[6] + 256 * data[7]);
|
||||
result.TargetField[0] = (UInt16)(data[8] + 256 * data[9]);
|
||||
result.TargetField[1] = (UInt16)(data[10] + 256 * data[11]);
|
||||
result.TargetField[2] = (UInt16)(data[12] + 256 * data[13]);
|
||||
result.RecipMeanCurrent = (UInt16)(data[14] + 256 * data[15]);
|
||||
result.ThresholdVolume = (UInt16)(data[16] + 256 * data[17]);
|
||||
result.ThresholdTime = (UInt16)(data[18] + 256 * data[19]);
|
||||
result.FlowActivationThr = (UInt16)(data[20] + 256 * data[21]);
|
||||
result.VolumeArrowThr = (UInt16)(data[22] + 256 * data[23]);
|
||||
result.CalibrationTime = (((UInt32)data[27] * 256 + data[26]) * 256 + data[25]) * 256 + data[24];
|
||||
result.SerialNumber = ((((UInt64)data[32] * 256 + data[31]) * 256 + data[30]) * 256 + data[29]) * 256 + data[28];
|
||||
result.MeterSealed = (MeterSealed)data[33];
|
||||
result.CheckSum = data[34];
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update the calibration structure from an incomplete byte array
|
||||
/// </summary>
|
||||
/// <param name="data">Byte array data</param>
|
||||
/// <param name="offset">Offset of byte array data in CalibrationStruct</param>
|
||||
/// <returns>true when successful, false when data are not appropriate</returns>
|
||||
public bool Update(byte[] data, int offset)
|
||||
{
|
||||
if (offset == 2 && data.Length == 2)
|
||||
{
|
||||
/// Data containing iPerl calibration factor
|
||||
Calibration = (UInt16)(data[2 - offset] + 256 * data[3 - offset]);
|
||||
return true;
|
||||
}
|
||||
else if (offset == 0 && data.Length == Length)
|
||||
{
|
||||
/// Data containing a complete CalibrationStruct
|
||||
Version = data[0];
|
||||
MeterType = (MeterType)data[1];
|
||||
Calibration = (UInt16)(data[2] + 256 * data[3]);
|
||||
VolumeUnits = (VolumeUnits)data[4];
|
||||
FlowArrow = (FlowArrow)data[5];
|
||||
FWVersion = (UInt16)(data[6] + 256 * data[7]);
|
||||
TargetField[0] = (UInt16)(data[8] + 256 * data[9]);
|
||||
TargetField[1] = (UInt16)(data[10] + 256 * data[11]);
|
||||
TargetField[2] = (UInt16)(data[12] + 256 * data[13]);
|
||||
RecipMeanCurrent = (UInt16)(data[14] + 256 * data[15]);
|
||||
ThresholdVolume = (UInt16)(data[16] + 256 * data[17]);
|
||||
ThresholdTime = (UInt16)(data[18] + 256 * data[19]);
|
||||
FlowActivationThr = (UInt16)(data[20] + 256 * data[21]);
|
||||
VolumeArrowThr = (UInt16)(data[22] + 256 * data[23]);
|
||||
CalibrationTime = (((UInt32)data[27] * 256 + data[26]) * 256 + data[25]) * 256 + data[24];
|
||||
SerialNumber = ((((UInt64)data[32] * 256 + data[31]) * 256 + data[30]) * 256 + data[29]) * 256 + data[28];
|
||||
MeterSealed = (MeterSealed)data[33];
|
||||
CheckSum = data[34];
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
public string FWVersionStr()
|
||||
{
|
||||
int d1 = (FWVersion >> 8) & 0x000F;
|
||||
int d2 = (FWVersion >> 12) & 0x000F;
|
||||
int d3 = (FWVersion >> 4) & 0x000F;
|
||||
int d4 = FWVersion & 0x000F;
|
||||
return string.Format("{0}.{1}{2}{3}", d1, d2, d3, d4);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format("Calibration: V{0} Type={1} Cal={2} Units={3} FlowArrow.{4} FW={5} Hi={6} Norm={7} Low={8} RMC={9} ThrVol={10} ThrTime={11} FlActThr={12} VolArrThr={13} CalTm={14} SN={15} MeterSealed={16} Chksum={17}",
|
||||
Version,
|
||||
MeterType,
|
||||
Calibration,
|
||||
VolumeUnits,
|
||||
FlowArrow,
|
||||
FWVersion,
|
||||
TargetField[0],
|
||||
TargetField[1],
|
||||
TargetField[2],
|
||||
RecipMeanCurrent,
|
||||
ThresholdVolume,
|
||||
ThresholdTime,
|
||||
FlowActivationThr,
|
||||
VolumeArrowThr,
|
||||
CalibrationTime,
|
||||
SerialNumber,
|
||||
MeterSealed,
|
||||
CheckSum.ToString("X2"));
|
||||
}
|
||||
}
|
||||
}
|
||||
225
TBF/BenchControl/TestMethods/GenesisHead/ConfigStruct.cs
Normal file
225
TBF/BenchControl/TestMethods/GenesisHead/ConfigStruct.cs
Normal file
@ -0,0 +1,225 @@
|
||||
///
|
||||
/// Copyright (c) 2015-2017 Sensus Metering Systems
|
||||
///
|
||||
using System;
|
||||
|
||||
namespace TBF.BenchControl.TestMethods.GenesisCommunication.GenesisHead
|
||||
{
|
||||
public class ConfigStruct
|
||||
{
|
||||
public const int Length = 32;
|
||||
|
||||
public Byte Version; /// 0: 1 byte
|
||||
public MeterState MeterState; /// 1: 1 byte
|
||||
public UInt32 TargetTimeVeryLowBatt; /// 2: 4 bytes in seconds
|
||||
public UInt32 TargetTimeLowBatt; /// 6: 4 bytes, in seconds
|
||||
public UInt32 TestModeTime; /// 10: 4 bytes, Max. test mode time in seconds
|
||||
public UInt16 EmptyPipeThreshold; /// 14: 2 bytes
|
||||
public byte[] PCBNumber; /// 16: 5 bytes
|
||||
public byte TestModeConfig; /// 21: 1 byte
|
||||
public UInt32 RadioAddress; /// 22: 4 bytes
|
||||
public UInt16 TempCalibration; /// 26: 2 bytes
|
||||
public UInt16 AlarmMask; /// 28: 2 bytes, Default 0xA3F7
|
||||
public UInt16 ConfigCheckSum; /// 30: 2 bytes
|
||||
|
||||
public ConfigStruct()
|
||||
{
|
||||
PCBNumber = new byte[5];
|
||||
}
|
||||
|
||||
public byte[] ToByteArray()
|
||||
{
|
||||
byte[] result = new byte[Length];
|
||||
|
||||
result[0] = Version;
|
||||
result[1] = (byte)MeterState;
|
||||
|
||||
result[2] = (byte)(TargetTimeVeryLowBatt & 0x000000FF);
|
||||
result[3] = (byte)((TargetTimeVeryLowBatt >> 8) & 0x000000FF);
|
||||
result[4] = (byte)((TargetTimeVeryLowBatt >> 16) & 0x000000FF);
|
||||
result[5] = (byte)((TargetTimeVeryLowBatt >> 24) & 0x000000FF);
|
||||
|
||||
result[6] = (byte)(TargetTimeLowBatt & 0x000000FF);
|
||||
result[7] = (byte)((TargetTimeLowBatt >> 8) & 0x000000FF);
|
||||
result[8] = (byte)((TargetTimeLowBatt >> 16) & 0x000000FF);
|
||||
result[9] = (byte)((TargetTimeLowBatt >> 24) & 0x000000FF);
|
||||
|
||||
result[10] = (byte)(TestModeTime & 0x000000FF);
|
||||
result[11] = (byte)((TestModeTime >> 8) & 0x000000FF);
|
||||
result[12] = (byte)((TestModeTime >> 16) & 0x000000FF);
|
||||
result[13] = (byte)((TestModeTime >> 24) & 0x000000FF);
|
||||
|
||||
result[14] = (byte)(EmptyPipeThreshold & 0x00FF);
|
||||
result[15] = (byte)((EmptyPipeThreshold >> 8) & 0x00FF);
|
||||
|
||||
result[16] = PCBNumber[0];
|
||||
result[17] = PCBNumber[1];
|
||||
result[18] = PCBNumber[2];
|
||||
result[19] = PCBNumber[3];
|
||||
result[20] = PCBNumber[4];
|
||||
|
||||
result[21] = TestModeConfig;
|
||||
|
||||
result[22] = (byte)(RadioAddress & 0x000000FF);
|
||||
result[23] = (byte)((RadioAddress >> 8) & 0x000000FF);
|
||||
result[24] = (byte)((RadioAddress >> 16) & 0x000000FF);
|
||||
result[25] = (byte)((RadioAddress >> 24) & 0x000000FF);
|
||||
|
||||
result[26] = (byte)(TempCalibration & 0x00FF);
|
||||
result[27] = (byte)((TempCalibration >> 8) & 0x00FF);
|
||||
|
||||
result[28] = (byte)(AlarmMask & 0x00FF);
|
||||
result[29] = (byte)((AlarmMask >> 8) & 0x00FF);
|
||||
|
||||
result[30] = (byte)(ConfigCheckSum & 0x00FF);
|
||||
result[31] = (byte)((ConfigCheckSum >> 8) & 0x00FF);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a configuration structure from a complete byte array
|
||||
/// </summary>
|
||||
/// <param name="data">A complete byte array data</param>
|
||||
/// <returns>ConfigStruct or null when byte array was not complete</returns>
|
||||
public static ConfigStruct FromByteArray(byte[] data)
|
||||
{
|
||||
if (data.Length != Length) return null;
|
||||
|
||||
ConfigStruct result = new ConfigStruct();
|
||||
|
||||
result.Version = data[0];
|
||||
result.MeterState = (MeterState)data[1];
|
||||
result.TargetTimeVeryLowBatt = (((UInt32)data[5] * 256 + data[4]) * 256 + data[3]) * 256 + data[2];
|
||||
result.TargetTimeLowBatt = (((UInt32)data[9] * 256 + data[8]) * 256 + data[7]) * 256 + data[6];
|
||||
result.TestModeTime = (((UInt32)data[13] * 256 + data[12]) * 256 + data[11]) * 256 + data[10];
|
||||
result.EmptyPipeThreshold = (UInt16)(data[15] * 256 + data[14]);
|
||||
result.PCBNumber[0] = data[16];
|
||||
result.PCBNumber[1] = data[17];
|
||||
result.PCBNumber[2] = data[18];
|
||||
result.PCBNumber[3] = data[19];
|
||||
result.PCBNumber[4] = data[20];
|
||||
result.TestModeConfig = data[21];
|
||||
result.RadioAddress = (((UInt32)data[25] * 256 + data[24]) * 256 + data[23]) * 256 + data[22];
|
||||
result.TempCalibration = (UInt16)(data[27] * 256 + data[26]);
|
||||
result.AlarmMask = (UInt16)(data[29] * 256 + data[28]);
|
||||
result.ConfigCheckSum = (UInt16)(data[31] * 256 + data[30]);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update the configuration structure from an incomplete byte array
|
||||
/// </summary>
|
||||
/// <param name="offset">Offset of byte array data in ConfigStruct</param>
|
||||
/// <param name="data">Byte array data</param>
|
||||
/// <returns>true when successful, false when data are not appropriate</returns>
|
||||
public bool Update(int offset, byte[] data)
|
||||
{
|
||||
if (offset == 0 && data.Length == 2)
|
||||
{
|
||||
/// iPerl mode of function
|
||||
Version = data[0];
|
||||
MeterState = (MeterState)data[1];
|
||||
return true;
|
||||
}
|
||||
else if (offset == 0 && data.Length == 4)
|
||||
{
|
||||
/// iPerl mode of function and extra 2 bytes
|
||||
Version = data[0];
|
||||
MeterState = (MeterState)data[1];
|
||||
return true;
|
||||
}
|
||||
else if (offset == 21 && data.Length == 1)
|
||||
{
|
||||
/// TestModeConfig value
|
||||
TestModeConfig = data[21 - offset];
|
||||
return true;
|
||||
}
|
||||
else if (offset == 0 && data.Length == Length)
|
||||
{
|
||||
/// Complete ConfigStruct
|
||||
Version = data[0];
|
||||
MeterState = (MeterState)data[1];
|
||||
TargetTimeVeryLowBatt = (((UInt32)data[5] * 256 + data[4]) * 256 + data[3]) * 256 + data[2];
|
||||
TargetTimeLowBatt = (((UInt32)data[9] * 256 + data[8]) * 256 + data[7]) * 256 + data[6];
|
||||
TestModeTime = (((UInt32)data[13] * 256 + data[12]) * 256 + data[11]) * 256 + data[10];
|
||||
EmptyPipeThreshold = (UInt16)(data[15] * 256 + data[14]);
|
||||
PCBNumber[0] = data[16];
|
||||
PCBNumber[1] = data[17];
|
||||
PCBNumber[2] = data[18];
|
||||
PCBNumber[3] = data[19];
|
||||
PCBNumber[4] = data[20];
|
||||
TestModeConfig = data[21];
|
||||
RadioAddress = (((UInt32)data[25] * 256 + data[24]) * 256 + data[23]) * 256 + data[22];
|
||||
TempCalibration = (UInt16)(data[27] * 256 + data[26]);
|
||||
AlarmMask = (UInt16)(data[29] * 256 + data[28]);
|
||||
ConfigCheckSum = (UInt16)(data[31] * 256 + data[30]);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns PCB number string (12 characters, 12 decimal digits)
|
||||
/// </summary>
|
||||
/// <returns>PCB number STRING</returns>
|
||||
public string GetPcbNrString()
|
||||
{
|
||||
return PCBNumber2String(this.PCBNumber);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts PCBNumber to string (12 characters, 12 decimal digits)
|
||||
/// </summary>
|
||||
/// <param name="pcbNumber"></param>
|
||||
/// <returns>PCB number string</returns>
|
||||
public static string PCBNumber2String(byte[] pcbNumber)
|
||||
{
|
||||
if (pcbNumber.Length != 5) return string.Empty;
|
||||
|
||||
Int64 number = 0;
|
||||
for (int i = 4; i >= 0; i--)
|
||||
{
|
||||
number = 256 * number + (Int64)pcbNumber[i];
|
||||
}
|
||||
|
||||
return number.ToString();
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format("Config: V{0} State={1} VLoBattT={2}s LoBattT={3}s TestModeT={4}s EPThld={5} PCB#={6} TMCfg={7} RadioAddr={8} TempCalib={9} AlarmMask={10} CfgCheckSum={11}",
|
||||
Version,
|
||||
MeterState,
|
||||
TargetTimeVeryLowBatt,
|
||||
TargetTimeLowBatt,
|
||||
TestModeTime,
|
||||
EmptyPipeThreshold,
|
||||
GetPcbNrString(),
|
||||
TestModeConfig.ToString("X2"),
|
||||
RadioAddress,
|
||||
TempCalibration,
|
||||
AlarmMask.ToString("X4"),
|
||||
ConfigCheckSum.ToString("X4"));
|
||||
}
|
||||
|
||||
public string ToString(int sel)
|
||||
{
|
||||
return string.Format("{1} PCB#={6} TMCfg={7}",
|
||||
Version,
|
||||
MeterState,
|
||||
TargetTimeVeryLowBatt,
|
||||
TargetTimeLowBatt,
|
||||
TestModeTime,
|
||||
EmptyPipeThreshold,
|
||||
GetPcbNrString(),
|
||||
TestModeConfig.ToString("X2"),
|
||||
RadioAddress,
|
||||
TempCalibration,
|
||||
AlarmMask.ToString("X4"),
|
||||
ConfigCheckSum.ToString("X4"));
|
||||
}
|
||||
}
|
||||
}
|
||||
110
TBF/BenchControl/TestMethods/GenesisHead/Enums.cs
Normal file
110
TBF/BenchControl/TestMethods/GenesisHead/Enums.cs
Normal file
@ -0,0 +1,110 @@
|
||||
///
|
||||
/// Copyright (c) 2015-2017 Sensus Metering Systems
|
||||
///
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace TBF.BenchControl.TestMethods.GenesisCommunication.GenesisHead
|
||||
{
|
||||
public enum MessageID
|
||||
{
|
||||
Calibration = 0x00, /// Access to stCalibration
|
||||
Configuration = 0x01, /// Access to stConfig
|
||||
Status = 0x02, /// Access to stStaus, read only
|
||||
Power = 0x03, /// Access to stPower, containing power info from both processors
|
||||
LCD = 0x04, /// Access to stLCD
|
||||
EventData = 0x05, /// NOT USED
|
||||
IntervalData = 0x06, /// NOT USED
|
||||
Diagnostics = 0x07, /// Access tostMetroDiagArray, read onl
|
||||
MetrologyMemory = 0x08, /// Memory block access, read only
|
||||
Error_LongAck = 0x09, /// Error message
|
||||
Command = 0x0A, /// Command to execute, with no arguments
|
||||
Parameterizing = 0x0B, /// Parameterizing message is used in MCI-SPI interface only
|
||||
Error_ShortAck = 0x0C, /// Short acknowledge message is used in MCI-SPI interface only
|
||||
ChanelAlive = 0x0D, /// Channel alive message is used in MCI-SPI interface only
|
||||
RadioPassthrough = 0x0E, /// RFID <-> Metrology <-> Radio passthrough message
|
||||
ASICRegisterReadTest = 0x0F, /// ASIC Register read test
|
||||
IMIDebugMessagesAccess = 0x10, /// IMI debug messages read test
|
||||
ProductionChecksumsRead = 0x11, /// Production checksum read: Calibration (1 byte), Configuration (2 bytes), spare (4 bytes)
|
||||
HardwareParametersTest = 0x12, /// Hardware Parameters Testing: User configurable fixed field drive time (1 byte)
|
||||
/// <summary>
|
||||
/// Notes:
|
||||
/// 1. Short Ack message contains 1-byte error code and all the fields (Offset, Payload length, payload and password) will not be present.
|
||||
/// 2. Channel Alive message does not contain the fields (Offset, Payload length, payload and password).
|
||||
/// 3. Except the above two special messages, rest all the messages in the above table will follow the message format mentioned in sections 3.1 and 3.2.
|
||||
/// </summary>
|
||||
Count /// Number of MessageID-s
|
||||
}
|
||||
|
||||
public enum MeterType : byte
|
||||
{
|
||||
DN15 = 0,
|
||||
CoaxManifold = 1,
|
||||
DN20 = 2,
|
||||
DN25 = 3,
|
||||
DN26 = 4, /// DN25*
|
||||
DN32 = 5,
|
||||
DN40 = 6,
|
||||
AutoDetect,
|
||||
Count /// Number of meter types
|
||||
}
|
||||
|
||||
public enum VolumeUnits : byte
|
||||
{
|
||||
m3 = 0,
|
||||
UK_gallon = 1,
|
||||
US_gallon = 2,
|
||||
Count /// Number of volume units
|
||||
}
|
||||
|
||||
public enum FlowArrow : byte
|
||||
{
|
||||
No = 0,
|
||||
Right = 1,
|
||||
Left = 2,
|
||||
Count /// Number of flow arrows
|
||||
}
|
||||
|
||||
public enum MeterSealed : byte
|
||||
{
|
||||
InProduction = 0x00,
|
||||
OutOfProduction = 0xA5,
|
||||
Sealed = 0x5A,
|
||||
}
|
||||
|
||||
public enum MeterState : byte
|
||||
{
|
||||
None = 0,
|
||||
Idle = 1,
|
||||
Active = 2,
|
||||
Test = 3,
|
||||
EndOfLife = 4,
|
||||
Count /// Number of meter states
|
||||
}
|
||||
|
||||
public enum FlowState : byte
|
||||
{
|
||||
No = 0,
|
||||
Reverse = 1,
|
||||
Forward = 2,
|
||||
EmptyPipe = 3,
|
||||
Count /// Number of flow states
|
||||
}
|
||||
|
||||
public enum OptoTelegramFlags : byte
|
||||
{
|
||||
OK = 0,
|
||||
OK_TestStart,
|
||||
OK_TestEnd,
|
||||
InvalidTelegram, /// Wrong telegram format of checksum error
|
||||
SyncError,
|
||||
}
|
||||
|
||||
public enum OptoState
|
||||
{
|
||||
Read,
|
||||
Flush,
|
||||
}
|
||||
}
|
||||
26
TBF/BenchControl/TestMethods/GenesisHead/Factory.cs
Normal file
26
TBF/BenchControl/TestMethods/GenesisHead/Factory.cs
Normal file
@ -0,0 +1,26 @@
|
||||
///
|
||||
/// Copyright (c) 2015-2017 Sensus Metering Systems
|
||||
///
|
||||
using System.Collections.Generic;
|
||||
using TBF.BenchControl.Generic;
|
||||
|
||||
namespace TBF.BenchControl.TestMethods.GenesisCommunication.GenesisHead
|
||||
{
|
||||
public class Factory : IComponentFactory
|
||||
{
|
||||
public string ClassName { get { return "RegisterReader for Genesis"; } }
|
||||
|
||||
public void ResetStaticProperties() { GenesisHead.ResetStaticProperties(); }
|
||||
|
||||
public IComponent DummyComponent() { return new GenesisHead(); }
|
||||
|
||||
public IComponent GetComponent(IComponentCfg cfg, IList<IComponent> components) { return new GenesisHead(cfg); }
|
||||
|
||||
public IComponentCfg DefaultConfig() { return new GenesisHeadCfg(this); }
|
||||
|
||||
public IComponentCfg CmpntCfgFromCmpntEntity(Config.Entities.Component component)
|
||||
{
|
||||
return ComponentCfgBase.CreateFromDbEntity(GenesisHeadCfg.Serializer, component, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
547
TBF/BenchControl/TestMethods/GenesisHead/GenesisHead.cs
Normal file
547
TBF/BenchControl/TestMethods/GenesisHead/GenesisHead.cs
Normal file
@ -0,0 +1,547 @@
|
||||
///
|
||||
/// Copyright (c) 2015-2018 Sensus Slovensko a.s.
|
||||
///
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.IO.Ports;
|
||||
using System.Threading;
|
||||
using System.Windows.Forms;
|
||||
using log4net;
|
||||
using Config.Entities;
|
||||
using TBF.BenchControl;
|
||||
using TBF.BenchControl.Generic;
|
||||
using TBF.Resources;
|
||||
using Xylem.Common.Hardware.WaterMeter;
|
||||
using Xylem.Common.Hardware.WaterMeter.Genesis;
|
||||
using TBF.BenchControl.GenericDevices;
|
||||
|
||||
namespace TBF.BenchControl.TestMethods.GenesisCommunication.GenesisHead
|
||||
{
|
||||
public static class GenesisHeadBatch
|
||||
{
|
||||
public static readonly Lazy<MeterBatch> BatchHolder = new Lazy<MeterBatch>(() =>
|
||||
{
|
||||
return new MeterBatch();
|
||||
});
|
||||
|
||||
internal static bool Start(IRegisterReader[] registerReaders, string[] lastSNTexts)
|
||||
{
|
||||
int index = 0;
|
||||
var ret = false;
|
||||
foreach (var rr in registerReaders)
|
||||
{
|
||||
if (rr is TestMethods.GenesisCommunication.GenesisHead.GenesisHead)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(lastSNTexts[index]))
|
||||
{
|
||||
var myGenesis = ((TestMethods.GenesisCommunication.GenesisHead.GenesisHead)rr).SetUp();
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
index = index + 1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// This component = instance of this class is a placeholder for a combined main watermeter
|
||||
/// </summary>
|
||||
public class GenesisHead : ComponentBase, IDevice, GenericDevices.IRegisterReader, IOperation
|
||||
{
|
||||
private static readonly ILog log = LogManager.GetLogger(typeof(GenesisHead));
|
||||
public override string ToString() { return string.Format("Genesis({0})", Cfg.ToString(1)); }
|
||||
|
||||
|
||||
readonly GenesisHeadCfg genesisHeadCfg;
|
||||
public int SlotNr { get { return genesisHeadCfg.SlotNr; } }
|
||||
public double PulsesPerLtr { get { return 1000.0; } }
|
||||
public double LtrsPerPulse { get { return 1 / PulsesPerLtr; } }
|
||||
|
||||
#if ORACLE_DB
|
||||
public int WMType_ID { get { return iperlHeadCfg.ProcParams.WMType_ID; } } /// Required by Oracle DB
|
||||
public int WMType_Rev { get { return iperlHeadCfg.ProcParams.WMType_Rev; } } /// Required by Oracle DB
|
||||
#endif
|
||||
public float CalibTarget { get { return (ushort)genesisHeadCfg.ProcParams.CalibTarget; } }
|
||||
public ushort FactorLimitLo { get { return (ushort)genesisHeadCfg.ProcParams.FactorLimitLo; } }
|
||||
public ushort FactorLimitHi { get { return (ushort)genesisHeadCfg.ProcParams.FactorLimitHi; } }
|
||||
|
||||
/// Properties set by the Begin and the End form
|
||||
//todo rd implement
|
||||
public string SerialNr;
|
||||
|
||||
|
||||
public string EndState
|
||||
{
|
||||
get { return endState; }
|
||||
set { endState = value; }
|
||||
}
|
||||
string endState;
|
||||
|
||||
public string BeginState
|
||||
{
|
||||
get { return beginState; }
|
||||
set { beginState = value; }
|
||||
}
|
||||
string beginState;
|
||||
|
||||
public bool Disabled
|
||||
{
|
||||
get { return disabled; }
|
||||
set { disabled = value; }
|
||||
}
|
||||
bool disabled;
|
||||
|
||||
public bool CommFailed
|
||||
{
|
||||
get { return commFailed; }
|
||||
set { commFailed = value; }
|
||||
}
|
||||
bool commFailed;
|
||||
|
||||
public int ResultCode
|
||||
{
|
||||
get { return resultCode; }
|
||||
}
|
||||
int resultCode;
|
||||
|
||||
|
||||
/// <summary> ConfigStruct of the water meter obtained or updated by iPerlCommunication </summary>
|
||||
public ConfigStruct ConfigStruct
|
||||
{
|
||||
get { return configStruct; }
|
||||
set { configStruct = value; }
|
||||
}
|
||||
ConfigStruct configStruct;
|
||||
|
||||
/// <summary> CalibrationStruct of the water meter obtained or updated by iPerlCommunication </summary>
|
||||
public CalibrationStruct CalibrationStruct
|
||||
{
|
||||
get { return calibrationStruct; }
|
||||
set { calibrationStruct = value; }
|
||||
}
|
||||
CalibrationStruct calibrationStruct;
|
||||
|
||||
public ushort OrigCalibFactor;
|
||||
public ushort CalibFactor { get { return (CalibrationStruct != null) ? CalibrationStruct.Calibration : (ushort)0; } }
|
||||
|
||||
public double Q2ErrWOCorrection;
|
||||
public bool Q2CorrectionDone;
|
||||
public double Q2Correction;
|
||||
public int Q2CorrRFlow;
|
||||
public int Q2CorrLFlow;
|
||||
|
||||
public double Diff2Hz8Hz;
|
||||
public bool Hz2CorrectionDone;
|
||||
public int Hz2Correction;
|
||||
|
||||
public string FWVersion { get { return (CalibrationStruct != null) ? CalibrationStruct.FWVersionStr() : string.Empty; } }
|
||||
|
||||
|
||||
/// <summary> Result of the last test used to calculate Q2 correction factors, etc </summary>
|
||||
public Results.Entities.MeterTestRslt LastTestResult2;
|
||||
public Results.Entities.MeterTestRslt LastTestResult;
|
||||
public double NominalTestFlowLph; /// in liter per hour
|
||||
|
||||
|
||||
///
|
||||
/// Required for IRegisterReader interface
|
||||
///
|
||||
public int WMPulses { get { return wmPulses; } }
|
||||
public int WMRefPulses { get { return wmRefPulses; } }
|
||||
public double WMVolume { get { return wmVolume; } }
|
||||
public double BeginWMState { get { return beginWMState; } }
|
||||
public double EndWMState { get { return endWMState; } }
|
||||
public double WMTestTime { get { return wmTestTime; } }
|
||||
|
||||
|
||||
double beginWMState;
|
||||
double endWMState;
|
||||
double wmVolume;
|
||||
int wmPulses;
|
||||
int wmRefPulses;
|
||||
double wmTestTime;
|
||||
|
||||
|
||||
/// <summary> Name set by the test, to be used as a part of the opto-data log file name </summary>
|
||||
public string TestName;
|
||||
|
||||
/// <summary> Name set by the test, to be used as a part of the opto-data log file name </summary>
|
||||
public string BenchName;
|
||||
|
||||
///
|
||||
/// Volume of water from the opto telegram
|
||||
///
|
||||
private Int64 lastVolumeRaw; /// Last read raw volume
|
||||
private double volumeLtr; ///
|
||||
private double volumeLtr0;
|
||||
|
||||
|
||||
///
|
||||
/// Timestamp from the opto telegram
|
||||
///
|
||||
private double timestampSec;
|
||||
private double timestampSec0;
|
||||
|
||||
public bool NoSamples { get { return (timestampSecEnd - timestampSecStart) < float.Epsilon; } }
|
||||
public double TimestampSecStart { get { return timestampSecStart; } }
|
||||
public double TimestampSecEnd { get { return timestampSecEnd; } }
|
||||
double timestampSecStart;
|
||||
double timestampSecEnd;
|
||||
|
||||
public GenesisHead()
|
||||
{
|
||||
}
|
||||
|
||||
public GenesisHead(Generic.IComponentCfg cfg)
|
||||
: base(cfg)
|
||||
{
|
||||
ClearData();
|
||||
|
||||
genesisHeadCfg = cfg as GenesisHeadCfg;
|
||||
|
||||
log.Debug(this.ToString());
|
||||
}
|
||||
|
||||
|
||||
GenesisMeter myGenesis = null;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public GenesisMeter SetUp()
|
||||
{
|
||||
if (myGenesis != null)
|
||||
{
|
||||
myGenesis.DisposeMeter();
|
||||
}
|
||||
//add for gen
|
||||
|
||||
myGenesis = new GenesisMeter();
|
||||
myGenesis.SetupFromConfigFile(SlotNr);
|
||||
|
||||
GenesisHeadBatch.BatchHolder.Value.AddMeter(myGenesis);
|
||||
myGenesis.LogRawData(true);
|
||||
return myGenesis;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clear data related to a specific water meter
|
||||
/// </summary>
|
||||
public void ClearData()
|
||||
{
|
||||
resultCode = 0;
|
||||
|
||||
disabled = false;
|
||||
commFailed = false;
|
||||
endState = string.Empty;
|
||||
beginState = string.Empty;
|
||||
|
||||
configStruct = null;
|
||||
calibrationStruct = null;
|
||||
|
||||
LastTestResult = null;
|
||||
NominalTestFlowLph = 0;
|
||||
|
||||
OrigCalibFactor = 0;
|
||||
Q2ErrWOCorrection = 0;
|
||||
Q2CorrectionDone = false;
|
||||
Q2CorrRFlow = 0;
|
||||
}
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
ClearData();
|
||||
|
||||
if (DebugLevel == DebugMode.Normal)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public void RunDeviceBefore()
|
||||
{
|
||||
|
||||
|
||||
////todo: RD- Login??
|
||||
//if (DebugLevel == DebugMode.Normal)
|
||||
//{
|
||||
|
||||
|
||||
// if (myGenesis != null)
|
||||
// {
|
||||
// Log("TBF RunDeviceBefore");
|
||||
// //myGenesis.Login();
|
||||
// //myGenesis.InitMeasurement();
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// throw new Exception("No meter was bound!");
|
||||
// }
|
||||
//}
|
||||
//else if (DebugLevel == DebugMode.FailureDuringOperation)
|
||||
//{
|
||||
//}
|
||||
}
|
||||
|
||||
public void RunDeviceAfter() { }
|
||||
|
||||
public void StopDevice()
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
if (DebugLevel == DebugMode.Normal && myGenesis != null)
|
||||
{
|
||||
myGenesis.DisposeMeter();
|
||||
|
||||
GenesisHeadBatch.BatchHolder.Value.RemoveMeter(myGenesis);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public void StopDevice2() { }
|
||||
|
||||
/// <summary>
|
||||
/// Events: Event.ReadRegisterDone, Event.Error
|
||||
/// </summary>
|
||||
/// <returns>ReadWaterMeter instance reference casted to IOperaton</returns>
|
||||
public IOperation ReadRegisterOp()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clear data/counters related to a specific tests
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
resultCode = 0;
|
||||
|
||||
sampleNr = 0;
|
||||
|
||||
volumeLtr = 0;
|
||||
volumeLtr0 = 0;
|
||||
timestampSec = 0;
|
||||
timestampSec0 = 0;
|
||||
|
||||
ReadPulses();
|
||||
}
|
||||
|
||||
public void TestCompleted()
|
||||
{
|
||||
/// TODO: Implement
|
||||
}
|
||||
|
||||
|
||||
int sampleNr; /// This is to determine when the test start sample should be taken
|
||||
bool StoreStartPackage = false;
|
||||
bool StoreEndPackage = false;
|
||||
bool Enable = false;
|
||||
public bool IsCalibration = false;
|
||||
/// <summary>Start this operation</summary>
|
||||
public void Start()
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
public void StartRead(string TestName)
|
||||
{
|
||||
StoreStartPackage = false;
|
||||
StoreEndPackage = false;
|
||||
//Start mesurement
|
||||
if (DebugLevel == DebugMode.Normal)
|
||||
{
|
||||
if (myGenesis != null)
|
||||
{
|
||||
IsCalibration = false;
|
||||
Log("TBF Start Measurement");
|
||||
if (TestName.ToLower().Contains("calib"))
|
||||
{
|
||||
IsCalibration = true;
|
||||
myGenesis.StartCalibration();
|
||||
}
|
||||
else
|
||||
{
|
||||
myGenesis.StartMeasurement();
|
||||
}
|
||||
|
||||
StoreStartPackage = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Log(string text)
|
||||
{
|
||||
if (DebugLevel == DebugMode.Normal)
|
||||
{
|
||||
if (myGenesis != null)
|
||||
{
|
||||
myGenesis.WriteLog(text);
|
||||
}
|
||||
}
|
||||
}
|
||||
void readOutResults(Xylem.Common.Hardware.WaterMeter.CommonMeterDefinitions.MeasurementResults results)
|
||||
{
|
||||
|
||||
//if (StoreStartPackage)
|
||||
//{
|
||||
|
||||
// volumeLtr0 = results.StartData.GetVolumeQm() * 1000;
|
||||
// timestampSec0 = results.StartData.GetTimeS();
|
||||
// StoreStartPackage = false;
|
||||
//}
|
||||
//else if (!StoreEndPackage)
|
||||
//{
|
||||
|
||||
volumeLtr = results.EndData.GetVolumeQm() * 1000;
|
||||
timestampSec = results.EndData.GetTimeS();
|
||||
wmTestTime = results.TotalTimeS;
|
||||
wmVolume = results.TotalVolumeQm * 1000;
|
||||
ReadPulses();
|
||||
//}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// <summary>Run this operation</summary>
|
||||
/// <returns>eventDone</returns>
|
||||
public Event Run()
|
||||
{
|
||||
if (DebugLevel == DebugMode.Normal)
|
||||
{
|
||||
if (myGenesis != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
//var results = myGenesis.GetIntermediateMeasurementResult();
|
||||
//readOutResults(results);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return Event.ReadRegisterDone;
|
||||
}
|
||||
public double RefVolume = 0.0;
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
//Stop(null);
|
||||
if (DebugLevel == DebugMode.Normal && myGenesis != null)
|
||||
{
|
||||
if (IsCalibration)
|
||||
{
|
||||
myGenesis.StopCalibration();
|
||||
}
|
||||
else
|
||||
{
|
||||
myGenesis.StopMeasurement();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Stop this operation</summary>
|
||||
public void Stop(Double? testTimeS = null)
|
||||
{
|
||||
|
||||
if (DebugLevel == DebugMode.Normal && myGenesis != null)
|
||||
{
|
||||
Log("TBF Stop Measurement");
|
||||
if (IsCalibration)
|
||||
{
|
||||
//myGenesis.StopCalibration();
|
||||
int retryCounter = 400;
|
||||
while (myGenesis.GetCalibrationState() != Xylem.Common.Hardware.WaterMeter.CommonMeterDefinitions.ActionStates.IsCompleted)
|
||||
{
|
||||
if (retryCounter < 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
Thread.Sleep(10);
|
||||
retryCounter = retryCounter - 1;
|
||||
}
|
||||
try
|
||||
{
|
||||
var results = myGenesis.GetCalibrationResult();
|
||||
readOutResults(results[0]);
|
||||
if (RefVolume != 0.0)
|
||||
{
|
||||
myGenesis.CalculateCalibrationWithVol(RefVolume,0);
|
||||
myGenesis.SaveCalculatedCalibration(false);
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MarkAsError();
|
||||
Log("Error while Stop Calib " + ex.Message);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int retryCounter = 400;
|
||||
//myGenesis.StopMeasurement();
|
||||
while (myGenesis.GetMeasurementState() != Xylem.Common.Hardware.WaterMeter.CommonMeterDefinitions.ActionStates.IsCompleted)
|
||||
{
|
||||
if (retryCounter < 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
Thread.Sleep(10);
|
||||
retryCounter = retryCounter - 1;
|
||||
}
|
||||
try
|
||||
{
|
||||
var results = myGenesis.GetMeasurementResult(testTimeS);
|
||||
readOutResults(results);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MarkAsError();
|
||||
Log("Error while Stop Measurement " + ex.Message);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
StoreEndPackage = true;
|
||||
|
||||
}
|
||||
}
|
||||
void MarkAsError()
|
||||
{
|
||||
volumeLtr = 100;
|
||||
timestampSec = 1;
|
||||
wmTestTime = 1;
|
||||
wmVolume = 100;
|
||||
ReadPulses();
|
||||
}
|
||||
|
||||
void ReadPulses()
|
||||
{
|
||||
beginWMState = volumeLtr0;
|
||||
endWMState = volumeLtr;
|
||||
wmPulses = (int)(wmVolume * (double)PulsesPerLtr + 0.5);
|
||||
wmRefPulses = StateMachine.ControlBoard.EtPulses(0);
|
||||
}
|
||||
|
||||
|
||||
bool optoSerialPortParsingEnabled;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
66
TBF/BenchControl/TestMethods/GenesisHead/GenesisHeadCfg.cs
Normal file
66
TBF/BenchControl/TestMethods/GenesisHead/GenesisHeadCfg.cs
Normal file
@ -0,0 +1,66 @@
|
||||
///
|
||||
/// Copyright (c) 2015-2017 Sensus Metering Systems
|
||||
///
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Xml.Serialization;
|
||||
using Config.Entities;
|
||||
using TBF.BenchControl.Generic;
|
||||
using TBF.Resources;
|
||||
|
||||
namespace TBF.BenchControl.TestMethods.GenesisCommunication.GenesisHead
|
||||
{
|
||||
public class GenesisHeadCfg : ComponentCfgBase, Generic.IComponentCfg
|
||||
{
|
||||
public static XmlSerializer Serializer = XmlSerializer.FromTypes(new[] { typeof(GenesisHeadCfg) })[0];
|
||||
protected override XmlSerializer GetSerializer() { return Serializer; }
|
||||
|
||||
public IComponentCfgCtrl GetControl() { return new GenesisHeadCfgCtrl(); }
|
||||
|
||||
///
|
||||
/// Serialized parameters
|
||||
///
|
||||
public int SlotNr; /// Number written to QuidoRS to connct the watermeter to RfidComPort, 1 .. 10
|
||||
|
||||
/// <summary> Procedure parameters </summary>
|
||||
[XmlIgnore]
|
||||
public ProcParams ProcParams;
|
||||
public override IParamsProvider GetProcedureParams() { return ProcParams; }
|
||||
public override IParamsProvider CreateProcedureParams(Procedure procedure)
|
||||
{
|
||||
ProcParams procParams = new ProcParams(true);
|
||||
procParams.UpdateProcedureParams(Name, procedure);
|
||||
return procParams;
|
||||
}
|
||||
|
||||
[XmlIgnore]
|
||||
public MeterType MeterType { get { return (ProcParams != null) ? ProcParams.MeterType : MeterType.AutoDetect; } }
|
||||
|
||||
|
||||
/// Private parameterless constructor invoked by all other (public) constructors
|
||||
GenesisHeadCfg()
|
||||
{
|
||||
Name = "Genesis";
|
||||
ParentName = string.Empty;
|
||||
SlotNr = 0;
|
||||
ProcParams = new ProcParams(true);
|
||||
}
|
||||
|
||||
public GenesisHeadCfg(IComponentFactory factory)
|
||||
: this()
|
||||
{
|
||||
this.Factory = factory;
|
||||
}
|
||||
|
||||
public string ToString(int i)
|
||||
{
|
||||
return string.Format("{0} SlotNr={1}",
|
||||
Name,
|
||||
SlotNr
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,89 @@
|
||||
///
|
||||
/// Copyright (c) 2015-2017 Sensus Metering Systems
|
||||
///
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Windows.Forms;
|
||||
using log4net;
|
||||
using TBF.BenchControl.Generic;
|
||||
using TBF.Resources;
|
||||
|
||||
namespace TBF.BenchControl.TestMethods.GenesisCommunication.GenesisHead
|
||||
{
|
||||
public partial class GenesisHeadCfgCtrl : UserControl, IComponentCfgCtrl
|
||||
{
|
||||
static readonly ILog log = LogManager.GetLogger(typeof(GenesisHeadCfgCtrl));
|
||||
|
||||
public bool ShowMore { get { return false; } }
|
||||
|
||||
GenesisHeadCfg config;
|
||||
public IComponentCfg Config
|
||||
{
|
||||
get { return config as IComponentCfg; }
|
||||
set
|
||||
{
|
||||
config = value as GenesisHeadCfg;
|
||||
Redraw();
|
||||
}
|
||||
}
|
||||
|
||||
public GenesisHeadCfgCtrl()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void WaterMeterCfgCtrl_Load(object sender, EventArgs e)
|
||||
{
|
||||
nameLabel.Text = Strings.Name;
|
||||
classNameLabel.Text = config.Factory.ClassName;
|
||||
Redraw();
|
||||
}
|
||||
|
||||
public void Closing()
|
||||
{
|
||||
}
|
||||
|
||||
void Redraw()
|
||||
{
|
||||
if (config == null) return; /// Control was not loaded, settings were not changed
|
||||
nameTextBox.Text = config.Name;
|
||||
|
||||
|
||||
}
|
||||
|
||||
public void Unlock()
|
||||
{
|
||||
nameTextBox.Enabled = true;
|
||||
slotNrTextBox.Enabled = true;
|
||||
}
|
||||
|
||||
public CfgUpdateFlags VerifyCfg(ref string message)
|
||||
{
|
||||
CfgUpdateFlags flags = CfgUpdateFlags.None;
|
||||
|
||||
int dummy;
|
||||
|
||||
if (!int.TryParse(slotNrTextBox.Text, out dummy) || dummy < 1 || dummy > 7)
|
||||
{
|
||||
flags |= CfgUpdateFlags.Error;
|
||||
message += Environment.NewLine + string.Format(Strings.Invalid_0, muxBoardNrLabel.Text);
|
||||
}
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
public CfgUpdateFlags UpdateCfg()
|
||||
{
|
||||
CfgUpdateFlags flags = CfgUpdateFlags.RestartRqrd;
|
||||
|
||||
if (config == null) return CfgUpdateFlags.Error; /// Control was not loaded, settings were not changed
|
||||
|
||||
config.Name = nameTextBox.Text;
|
||||
|
||||
config.SlotNr = int.Parse(slotNrTextBox.Text);
|
||||
|
||||
return flags;
|
||||
}
|
||||
}
|
||||
}
|
||||
121
TBF/BenchControl/TestMethods/GenesisHead/GenesisHeadCfgCtrl.designer.cs
generated
Normal file
121
TBF/BenchControl/TestMethods/GenesisHead/GenesisHeadCfgCtrl.designer.cs
generated
Normal file
@ -0,0 +1,121 @@
|
||||
///
|
||||
/// Copyright (c) 2015-2017 Sensus Metering Systems
|
||||
///
|
||||
namespace TBF.BenchControl.TestMethods.GenesisCommunication.GenesisHead
|
||||
{
|
||||
partial class GenesisHeadCfgCtrl
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Component Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.nameTextBox = new System.Windows.Forms.TextBox();
|
||||
this.nameLabel = new System.Windows.Forms.Label();
|
||||
this.classNameLabel = new System.Windows.Forms.Label();
|
||||
this.slotNrTextBox = new System.Windows.Forms.TextBox();
|
||||
this.muxBoardNrLabel = new System.Windows.Forms.Label();
|
||||
this.label3 = new System.Windows.Forms.Label();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// nameTextBox
|
||||
//
|
||||
this.nameTextBox.Enabled = false;
|
||||
this.nameTextBox.Location = new System.Drawing.Point(135, 40);
|
||||
this.nameTextBox.Name = "nameTextBox";
|
||||
this.nameTextBox.Size = new System.Drawing.Size(121, 20);
|
||||
this.nameTextBox.TabIndex = 2;
|
||||
//
|
||||
// nameLabel
|
||||
//
|
||||
this.nameLabel.AutoSize = true;
|
||||
this.nameLabel.Location = new System.Drawing.Point(25, 43);
|
||||
this.nameLabel.Name = "nameLabel";
|
||||
this.nameLabel.Size = new System.Drawing.Size(35, 13);
|
||||
this.nameLabel.TabIndex = 1;
|
||||
this.nameLabel.Text = "Name";
|
||||
//
|
||||
// classNameLabel
|
||||
//
|
||||
this.classNameLabel.AutoSize = true;
|
||||
this.classNameLabel.Location = new System.Drawing.Point(132, 16);
|
||||
this.classNameLabel.Name = "classNameLabel";
|
||||
this.classNameLabel.Size = new System.Drawing.Size(60, 13);
|
||||
this.classNameLabel.TabIndex = 0;
|
||||
this.classNameLabel.Text = "ClassName";
|
||||
//
|
||||
// slotNrTextBox
|
||||
//
|
||||
this.slotNrTextBox.Enabled = false;
|
||||
this.slotNrTextBox.Location = new System.Drawing.Point(135, 63);
|
||||
this.slotNrTextBox.Name = "slotNrTextBox";
|
||||
this.slotNrTextBox.Size = new System.Drawing.Size(34, 20);
|
||||
this.slotNrTextBox.TabIndex = 9;
|
||||
//
|
||||
// muxBoardNrLabel
|
||||
//
|
||||
this.muxBoardNrLabel.AutoSize = true;
|
||||
this.muxBoardNrLabel.Location = new System.Drawing.Point(25, 66);
|
||||
this.muxBoardNrLabel.Name = "muxBoardNrLabel";
|
||||
this.muxBoardNrLabel.Size = new System.Drawing.Size(37, 13);
|
||||
this.muxBoardNrLabel.TabIndex = 8;
|
||||
this.muxBoardNrLabel.Text = "Slot nr";
|
||||
//
|
||||
// label3
|
||||
//
|
||||
this.label3.AutoSize = true;
|
||||
this.label3.Location = new System.Drawing.Point(176, 66);
|
||||
this.label3.Name = "label3";
|
||||
this.label3.Size = new System.Drawing.Size(31, 13);
|
||||
this.label3.TabIndex = 13;
|
||||
this.label3.Text = "1 .. 6";
|
||||
//
|
||||
// GenesisHeadCfgCtrl
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.Controls.Add(this.label3);
|
||||
this.Controls.Add(this.slotNrTextBox);
|
||||
this.Controls.Add(this.muxBoardNrLabel);
|
||||
this.Controls.Add(this.nameTextBox);
|
||||
this.Controls.Add(this.nameLabel);
|
||||
this.Controls.Add(this.classNameLabel);
|
||||
this.Name = "GenesisHeadCfgCtrl";
|
||||
this.Size = new System.Drawing.Size(396, 123);
|
||||
this.Load += new System.EventHandler(this.WaterMeterCfgCtrl_Load);
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.TextBox nameTextBox;
|
||||
private System.Windows.Forms.Label nameLabel;
|
||||
private System.Windows.Forms.Label classNameLabel;
|
||||
private System.Windows.Forms.TextBox slotNrTextBox;
|
||||
private System.Windows.Forms.Label muxBoardNrLabel;
|
||||
private System.Windows.Forms.Label label3;
|
||||
}
|
||||
}
|
||||
120
TBF/BenchControl/TestMethods/GenesisHead/GenesisHeadCfgCtrl.resx
Normal file
120
TBF/BenchControl/TestMethods/GenesisHead/GenesisHeadCfgCtrl.resx
Normal file
@ -0,0 +1,120 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
||||
@ -0,0 +1,20 @@
|
||||
///
|
||||
/// Copyright (c) 2015-2017 Sensus Metering Systems
|
||||
///
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace TBF.BenchControl.TestMethods.GenesisCommunication.GenesisHead
|
||||
{
|
||||
public class OptoReceivedEventArgs : EventArgs
|
||||
{
|
||||
public string Data;
|
||||
|
||||
public OptoReceivedEventArgs(string data)
|
||||
{
|
||||
this.Data = data;
|
||||
}
|
||||
}
|
||||
}
|
||||
296
TBF/BenchControl/TestMethods/GenesisHead/OptoTelegramRaw.cs
Normal file
296
TBF/BenchControl/TestMethods/GenesisHead/OptoTelegramRaw.cs
Normal file
@ -0,0 +1,296 @@
|
||||
///
|
||||
/// Copyright (c) 2015-2017 Sensus Metering Systems
|
||||
///
|
||||
using System;
|
||||
using System.Globalization;
|
||||
|
||||
namespace TBF.BenchControl.TestMethods.GenesisCommunication.GenesisHead
|
||||
{
|
||||
public class OptoTelegramRaw
|
||||
{
|
||||
public static readonly int Length = 42;
|
||||
private static CultureInfo culture;
|
||||
|
||||
|
||||
///
|
||||
/// Strobed value
|
||||
///
|
||||
public static decimal TestStartTimestampDec;
|
||||
|
||||
///
|
||||
/// Stored values
|
||||
///
|
||||
public OptoTelegramFlags Flags;
|
||||
|
||||
public DateTime DateTime; /// From PC
|
||||
public float RefFlow; /// [m3/h]
|
||||
public int Counter;
|
||||
|
||||
public UInt32 EmfRaw; /// From iPerl opto data
|
||||
public Int16 MagneticFieldRaw;
|
||||
public Int16 FlowRaw;
|
||||
public UInt32 VolumeRaw;
|
||||
public Int64 VolumeRawExt;
|
||||
public Int16 Impedance;
|
||||
public UInt32 Timestamp;
|
||||
public Int64 TimestampExt;
|
||||
public byte CheckSum;
|
||||
|
||||
///
|
||||
/// Calculated values
|
||||
///
|
||||
public double EMF()
|
||||
{
|
||||
Int32 signedEmf = (EmfRaw > 0x7FFFFF) ? ((int)EmfRaw - 0x1000000) : (int)EmfRaw;
|
||||
return 0.000000333 * (double)signedEmf;
|
||||
}
|
||||
public double MagneticField() { return (double)MagneticFieldRaw; }
|
||||
public double Flow(double scalingFactor) { return 0.225 * scalingFactor * (double)FlowRaw; }
|
||||
public double Volume(double scalingFactor) { return 0.0000625 * scalingFactor * (double)VolumeRawExt; }
|
||||
public Int32 FlipTime() { return Impedance; }
|
||||
public decimal TimestampDec() { return (decimal)TimestampExt / (decimal)8192; }
|
||||
public double VolumeDelta(double scalingFactor, OptoTelegramRaw previous) { return (previous == null) ? 0 : Volume(scalingFactor) - previous.Volume(scalingFactor); }
|
||||
public decimal TimeDelta() { return TimestampDec() - TestStartTimestampDec; }
|
||||
public string Label()
|
||||
{
|
||||
if (Flags == OptoTelegramFlags.OK_TestStart) return "#### start test ####";
|
||||
else if (Flags == OptoTelegramFlags.OK_TestEnd) return "#### end of test ####";
|
||||
else return string.Empty;
|
||||
}
|
||||
|
||||
|
||||
static OptoTelegramRaw()
|
||||
{
|
||||
culture = CultureInfo.CreateSpecificCulture("DE"); /// This is to use comma as decimal number separator
|
||||
}
|
||||
|
||||
public OptoTelegramRaw()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses optical telegram and returns OptoTelegramRaw object
|
||||
/// </summary>
|
||||
/// <description>
|
||||
/// Create a configuration structure from a complete byte array
|
||||
///
|
||||
/// Telegram description:
|
||||
///
|
||||
/// AAAAAA[tab]BBBB[tab]CCCC[tab]DDDDDD[tab]EEEE[tab]FFFFFFFF[tab]GG[cr][lf] (42 bytes)
|
||||
///
|
||||
/// Data Comment Type Calculate to decimal
|
||||
/// ----------------------------------------------------------------
|
||||
/// AAAAAA EMF Int24 Value * 0.000000333
|
||||
/// BBBB Magnetic field Int16 Value
|
||||
/// CCCC Flow Int16 Value * 0.225 * Scalig factor
|
||||
/// DDDDDD Volume Int24 Value / 16000 * Scaling factor
|
||||
/// EEEE Impedance Int16 Value
|
||||
/// FFFFFFFF Timestamp Uint32 Value / 8192
|
||||
/// GG Checksum Byte
|
||||
/// ----------------------------------------------------------------
|
||||
///
|
||||
/// Example:
|
||||
/// FFFFFE 51EA 0000 65324E 0087 F6319DFF 86
|
||||
/// FFDD3A 51F9 0000 65324E 0088 F631A60B 45
|
||||
/// ...
|
||||
/// </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, ref Int64 volumeRawExtLast, ref Int64 timestampExtLast)
|
||||
{
|
||||
DateTime = DateTime.Now;
|
||||
Counter = counter;
|
||||
RefFlow = (float)Sequences.ProcessData.RefFlow.Val;
|
||||
|
||||
if ((telegram == null) || (telegram.Length < Length) ||
|
||||
(telegram[6] != '\t') || (telegram[11] != '\t') || (telegram[16] != '\t') ||
|
||||
(telegram[23] != '\t') || (telegram[28] != '\t') || (telegram[37] != '\t') ||
|
||||
(telegram[40] != '\r') || (telegram[41] != '\n'))
|
||||
{
|
||||
Flags = OptoTelegramFlags.InvalidTelegram;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool f1 = UInt32.TryParse(telegram.Substring(0, 6), NumberStyles.HexNumber, CultureInfo.CurrentCulture, out EmfRaw);
|
||||
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);
|
||||
|
||||
bool allOk = f1 && f2 && f3 && f4 && f5 && f6 && f7;
|
||||
Flags = allOk ? OptoTelegramFlags.OK : OptoTelegramFlags.InvalidTelegram;
|
||||
|
||||
///
|
||||
/// 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;
|
||||
}
|
||||
|
||||
return allOk;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Alternative to UpdateFromString(...) when data are flushed
|
||||
/// </summary>
|
||||
public bool UpdateFromStringDummy(string telegram)
|
||||
{
|
||||
DateTime = DateTime.Now;
|
||||
RefFlow = (float)Sequences.ProcessData.RefFlow.Val;
|
||||
|
||||
if ((telegram == null) || (telegram.Length < Length) ||
|
||||
(telegram[6] != '\t') || (telegram[11] != '\t') || (telegram[16] != '\t') ||
|
||||
(telegram[23] != '\t') || (telegram[28] != '\t') || (telegram[37] != '\t') ||
|
||||
(telegram[40] != '\r') || (telegram[41] != '\n'))
|
||||
{
|
||||
Flags = OptoTelegramFlags.InvalidTelegram;
|
||||
return false;
|
||||
}
|
||||
|
||||
//bool f1 = UInt32.TryParse(telegram.Substring(0, 6), NumberStyles.HexNumber, CultureInfo.CurrentCulture, out EmfRaw);
|
||||
//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);
|
||||
//return f1 && f2 && f3 && f4 && f5 && f6 && f7;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public void SetFlags(OptoTelegramFlags flags)
|
||||
{
|
||||
this.Flags = flags;
|
||||
}
|
||||
|
||||
|
||||
public string ToString(double scalingFactor, OptoTelegramRaw previous)
|
||||
{
|
||||
if (Flags == OptoTelegramFlags.SyncError)
|
||||
{
|
||||
return "Sychronization error";
|
||||
}
|
||||
else if (Flags == OptoTelegramFlags.InvalidTelegram)
|
||||
{
|
||||
return "Invalid telegram";
|
||||
}
|
||||
else /// if (flags == OptoTelegramFlags.OK / OptoTelegramFlags.OK_TestStart / OptoTelegramFlags.OK_TestEnd)
|
||||
{
|
||||
return string.Format("{0}:{1}:{2}.{3}\t{4} :\t{5}\t{6}\t{7}\t{8}\t{9}\t{10}\t{11}\t{12}\t{13}\t{14}\t{15}\t{16}\t{17}\t{18}\t{19}\t{20}\t{21}\t{22}",
|
||||
DateTime.Hour.ToString("D2"),
|
||||
DateTime.Minute.ToString("D2"),
|
||||
DateTime.Second.ToString("D2"),
|
||||
DateTime.Millisecond.ToString("D4"),
|
||||
Counter,
|
||||
EmfRaw.ToString("X6"),
|
||||
MagneticFieldRaw.ToString("X4"),
|
||||
FlowRaw.ToString("X4"),
|
||||
VolumeRaw.ToString("X6"),
|
||||
Impedance.ToString("X4"),
|
||||
Timestamp.ToString("X8"),
|
||||
CheckSum.ToString("X2"),
|
||||
EMF().ToString("F4", culture),
|
||||
MagneticField().ToString("F0", culture),
|
||||
Flow(scalingFactor).ToString("F2", culture),
|
||||
Volume(scalingFactor).ToString("F4", culture),
|
||||
FlipTime().ToString("F0", culture),
|
||||
TimestampDec().ToString("F4", culture),
|
||||
(RefFlow * 1000).ToString("F2", culture),
|
||||
VolumeDelta(scalingFactor, previous).ToString("F4", culture),
|
||||
TimeDelta().ToString("F3", culture),
|
||||
scalingFactor.ToString("F1", culture),
|
||||
Label());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Filter RefFlow data in an array of OptoTelegramRaw objects by a FIR filter:
|
||||
///
|
||||
/// kSize = 5, kSize2 = 2
|
||||
///
|
||||
/// i k
|
||||
/// ---------------------------------------------------------------------------
|
||||
/// 0 -5 filtered[0] = data[0]
|
||||
/// 1 -4 filtered[1] = data[1]
|
||||
/// 2 -3 filtered[2] = data[0]*k[0] + ... + data[4]*k[4]
|
||||
/// 3 -2 filtered[3] = data[1]*k[0] + ... + data[5]*k[4]
|
||||
/// 4 -1 filtered[4] = data[2]*k[0] + ... + data[6]*k[4]
|
||||
/// 5 0 data[0] = filtered[0], filtered[0] = data[3]*k[0] + ... + data[7]*k[4]
|
||||
/// 6 1 data[1] = filtered[1], filtered[1] = data[4]*k[0] + ... + data[8]*k[4]
|
||||
/// 7 ...
|
||||
/// </summary>
|
||||
/// <param name="optoData">array of OptoTelegramRaw objects</param>
|
||||
/// <param name="optoDataCount">number of objects to process</param>
|
||||
public static void FIRFilterFlow(OptoTelegramRaw[] optoData, int optoDataCount)
|
||||
{
|
||||
float[] kernel = new float[] { 0.1f, 0.2f, 0.4f, 0.2f, 0.1f };
|
||||
int kSize = kernel.Length;
|
||||
int kSize2 = kernel.Length / 2;
|
||||
|
||||
float[] filtered = new float[kSize];
|
||||
|
||||
for (int i = 0; i < optoDataCount; i++)
|
||||
{
|
||||
int k = i - kSize;
|
||||
if (k >= 0) optoData[k].RefFlow = filtered[i % kSize];
|
||||
|
||||
if (i < kSize2 || i >= optoDataCount - kSize2)
|
||||
{
|
||||
filtered[i % kSize] = optoData[i].RefFlow;
|
||||
}
|
||||
else
|
||||
{
|
||||
float weoightedSum = 0;
|
||||
for (int j = -kSize2; j <= kSize2; j++)
|
||||
weoightedSum += optoData[i + j].RefFlow * kernel[j + kSize2];
|
||||
|
||||
filtered[i % kSize] = weoightedSum;
|
||||
}
|
||||
}
|
||||
|
||||
for (int k = optoDataCount - kSize; k < optoDataCount; k++)
|
||||
{
|
||||
if (k >= 0) optoData[k].RefFlow = filtered[k % kSize];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
181
TBF/BenchControl/TestMethods/GenesisHead/ProcParams.cs
Normal file
181
TBF/BenchControl/TestMethods/GenesisHead/ProcParams.cs
Normal file
@ -0,0 +1,181 @@
|
||||
///
|
||||
/// Copyright (c) 2015-2017 Sensus Metering Systems
|
||||
///
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Xml.Serialization;
|
||||
using Config.Entities;
|
||||
using TBF.BenchControl.Generic;
|
||||
using TBF.Resources;
|
||||
|
||||
namespace TBF.BenchControl.TestMethods.GenesisCommunication.GenesisHead
|
||||
{
|
||||
public class ProcParams : ProcedureParamsBase, IParamsProvider, IProcedureParams
|
||||
{
|
||||
public static XmlSerializer Serializer = XmlSerializer.FromTypes(new[] { typeof(ProcParams) })[0];
|
||||
protected override XmlSerializer GetSerializer() { return Serializer; }
|
||||
|
||||
public MeterType MeterType;
|
||||
public float CalibTarget; /// Target error after calibration in [%]
|
||||
public int FactorLimitLo; /// Lower limit for the calibration factor
|
||||
public int FactorLimitHi; /// Upper limit for the calibration factor
|
||||
#if ORACLE_DB
|
||||
public int WMType_ID; /// Required for Oracle DB: ID_WZTyp in table VT_PRUEFPUNKT_SOLL_SD
|
||||
public int WMType_Rev; /// Required for Oracle DB: Rev_WZTyp in table VT_PRUEFPUNKT_SOLL_SD
|
||||
#endif
|
||||
|
||||
|
||||
public override void InitializeAll()
|
||||
{
|
||||
MeterType = MeterType.AutoDetect;
|
||||
CalibTarget = 0;
|
||||
FactorLimitLo = 1000;
|
||||
FactorLimitHi = 8000;
|
||||
#if ORACLE_DB
|
||||
WMType_ID = 2; /// Value for iPerl DN15
|
||||
WMType_Rev = 1; /// Value for iPerl DN15
|
||||
#endif
|
||||
}
|
||||
|
||||
string[] paramNames = new string[]
|
||||
{
|
||||
"iPerl type",
|
||||
"Calib. target [%]",
|
||||
"Calib. factor Lo",
|
||||
"Calib. factor Hi",
|
||||
#if ORACLE_DB
|
||||
"WMType ID",
|
||||
"WMType Rev.",
|
||||
#endif
|
||||
};
|
||||
public override string ParamName(int i) { return paramNames[i]; }
|
||||
public override int ParamsCount() { return paramNames.Length; }
|
||||
|
||||
public override string ToString(int i)
|
||||
{
|
||||
switch (i)
|
||||
{
|
||||
case 0: return MeterType.ToString();
|
||||
case 1: return CalibTarget.ToString();
|
||||
case 2: return FactorLimitLo.ToString();
|
||||
case 3: return FactorLimitHi.ToString();
|
||||
#if ORACLE_DB
|
||||
case 4: return WMType_ID.ToString();
|
||||
case 5: return WMType_Rev.ToString();
|
||||
#endif
|
||||
default: return string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateParam(int i, string strValue)
|
||||
{
|
||||
switch (i)
|
||||
{
|
||||
case 0:
|
||||
for (MeterType mt = 0; mt < MeterType.Count; mt++)
|
||||
{
|
||||
if (mt.ToString().Equals(strValue)) { MeterType = mt; return; }
|
||||
}
|
||||
break;
|
||||
case 1: CalibTarget = Utils.ParseSFloat(strValue); return;
|
||||
case 2: FactorLimitLo = int.Parse(strValue); return;
|
||||
case 3: FactorLimitHi = int.Parse(strValue); return;
|
||||
#if ORACLE_DB
|
||||
case 4: WMType_ID = int.Parse(strValue); return;
|
||||
case 5: WMType_Rev = int.Parse(strValue); return;
|
||||
#endif
|
||||
default: return;
|
||||
}
|
||||
}
|
||||
|
||||
public bool ValidateParam(int i, string strValue, out string message)
|
||||
{
|
||||
message = string.Empty;
|
||||
|
||||
int iDummy;
|
||||
float fDummy;
|
||||
|
||||
switch (i)
|
||||
{
|
||||
case 0:
|
||||
for (MeterType mt = 0; mt < MeterType.Count; mt++) if (mt.ToString().Equals(strValue)) return true;
|
||||
break;
|
||||
case 1:
|
||||
if (Utils.TryParseSFloat(strValue, out fDummy) && fDummy >= -10.0f && fDummy <= 10.0f) return true;
|
||||
break;
|
||||
case 2:
|
||||
case 3:
|
||||
if (int.TryParse(strValue, out iDummy) && iDummy >= 1000 && iDummy <= 8000) return true;
|
||||
break;
|
||||
|
||||
#if ORACLE_DB
|
||||
case 4: /// WMType_ID
|
||||
case 5: /// WMType_Rev
|
||||
if (int.TryParse(strValue, out iDummy)) return true;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
message = "Invalid index";
|
||||
return false;
|
||||
}
|
||||
|
||||
message = ParamName(i) + " is invalid";
|
||||
return false;
|
||||
}
|
||||
|
||||
void CopyContentTo(ProcParams prms)
|
||||
{
|
||||
prms.MeterType = this.MeterType;
|
||||
prms.CalibTarget = this.CalibTarget;
|
||||
prms.FactorLimitLo = this.FactorLimitLo;
|
||||
prms.FactorLimitHi = this.FactorLimitHi;
|
||||
#if ORACLE_DB
|
||||
prms.WMType_ID = this.WMType_ID;
|
||||
prms.WMType_Rev = this.WMType_Rev;
|
||||
#endif
|
||||
}
|
||||
|
||||
public IParamsProvider Clone()
|
||||
{
|
||||
ProcParams pars = new ProcParams();
|
||||
CopyContentTo(pars);
|
||||
return pars;
|
||||
}
|
||||
|
||||
public override void UpdateProcedureParams(ComponentProcedure dbEntity)
|
||||
{
|
||||
if (dbEntity == null) return;
|
||||
try
|
||||
{
|
||||
ProcParams tmp = Serializer.Deserialize(new StringReader(dbEntity.Parameters)) as ProcParams;
|
||||
|
||||
procedureParamsEntity = dbEntity;
|
||||
componentName = dbEntity.CmpntName;
|
||||
procedure = dbEntity.Procedure;
|
||||
|
||||
if (tmp != null) tmp.CopyContentTo(this);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public ProcParams()
|
||||
{
|
||||
}
|
||||
|
||||
public ProcParams(bool initialize)
|
||||
{
|
||||
if (initialize) InitializeAll();
|
||||
}
|
||||
|
||||
public ProcParams(ComponentProcedure procParamsEntity, string componentName, Procedure procedure)
|
||||
{
|
||||
this.procedureParamsEntity = procParamsEntity;
|
||||
this.componentName = componentName;
|
||||
this.procedure = procedure;
|
||||
}
|
||||
}
|
||||
}
|
||||
160
TBF/BenchControl/TestMethods/GenesisHead/StatusStruct.cs
Normal file
160
TBF/BenchControl/TestMethods/GenesisHead/StatusStruct.cs
Normal file
@ -0,0 +1,160 @@
|
||||
///
|
||||
/// Copyright (c) 2015-2017 Sensus Metering Systems
|
||||
///
|
||||
using System;
|
||||
|
||||
namespace TBF.BenchControl.TestMethods.GenesisCommunication.GenesisHead
|
||||
{
|
||||
public class StatusStruct
|
||||
{
|
||||
public static readonly int Length = 48;
|
||||
|
||||
public Byte Version;
|
||||
public FlowState FlowState;
|
||||
public UInt32 BillingVolume;
|
||||
public UInt32 ForwardVolume;
|
||||
public UInt32 ReverseVolume;
|
||||
public UInt32 SecondsActive;
|
||||
public UInt32 SecondsIdle;
|
||||
public UInt32 SecondsUsed;
|
||||
public UInt32 UTC;
|
||||
public Int32 ScaledAvgFlowRate;
|
||||
public UInt16 PeakFlowRate;
|
||||
public UInt16 AlarmState;
|
||||
public byte RebootCount;
|
||||
public byte[] AlarmCount;
|
||||
public UInt16 FlipTime;
|
||||
|
||||
|
||||
public StatusStruct()
|
||||
{
|
||||
AlarmCount = new byte[7];
|
||||
}
|
||||
|
||||
public byte[] ToByteArray()
|
||||
{
|
||||
byte[] result = new byte[Length];
|
||||
|
||||
result[0] = Version;
|
||||
result[1] = (byte)FlowState;
|
||||
|
||||
result[2] = (byte)(BillingVolume & 0x000000FF);
|
||||
result[3] = (byte)((BillingVolume >> 8) & 0x000000FF);
|
||||
result[4] = (byte)((BillingVolume >> 16) & 0x000000FF);
|
||||
result[5] = (byte)((BillingVolume >> 24) & 0x000000FF);
|
||||
|
||||
result[6] = (byte)(ForwardVolume & 0x000000FF);
|
||||
result[7] = (byte)((ForwardVolume >> 8) & 0x000000FF);
|
||||
result[8] = (byte)((ForwardVolume >> 16) & 0x000000FF);
|
||||
result[9] = (byte)((ForwardVolume >> 24) & 0x000000FF);
|
||||
|
||||
result[10] = (byte)(ReverseVolume & 0x000000FF);
|
||||
result[11] = (byte)((ReverseVolume >> 8) & 0x000000FF);
|
||||
result[12] = (byte)((ReverseVolume >> 16) & 0x000000FF);
|
||||
result[13] = (byte)((ReverseVolume >> 24) & 0x000000FF);
|
||||
|
||||
result[14] = (byte)(SecondsActive & 0x000000FF);
|
||||
result[15] = (byte)((SecondsActive >> 8) & 0x000000FF);
|
||||
result[16] = (byte)((SecondsActive >> 16) & 0x000000FF);
|
||||
result[17] = (byte)((SecondsActive >> 24) & 0x000000FF);
|
||||
|
||||
result[18] = (byte)(SecondsIdle & 0x000000FF);
|
||||
result[19] = (byte)((SecondsIdle >> 8) & 0x000000FF);
|
||||
result[20] = (byte)((SecondsIdle >> 16) & 0x000000FF);
|
||||
result[21] = (byte)((SecondsIdle >> 24) & 0x000000FF);
|
||||
|
||||
result[22] = (byte)(SecondsUsed & 0x000000FF);
|
||||
result[23] = (byte)((SecondsUsed >> 8) & 0x000000FF);
|
||||
result[24] = (byte)((SecondsUsed >> 16) & 0x000000FF);
|
||||
result[25] = (byte)((SecondsUsed >> 24) & 0x000000FF);
|
||||
|
||||
result[26] = (byte)(UTC & 0x000000FF);
|
||||
result[27] = (byte)((UTC >> 8) & 0x000000FF);
|
||||
result[28] = (byte)((UTC >> 16) & 0x000000FF);
|
||||
result[29] = (byte)((UTC >> 24) & 0x000000FF);
|
||||
|
||||
result[30] = (byte)(ScaledAvgFlowRate & 0x000000FF);
|
||||
result[31] = (byte)((ScaledAvgFlowRate >> 8) & 0x000000FF);
|
||||
result[32] = (byte)((ScaledAvgFlowRate >> 16) & 0x000000FF);
|
||||
result[33] = (byte)((ScaledAvgFlowRate >> 24) & 0x000000FF); /// TODO: test with negative value
|
||||
|
||||
result[34] = (byte)(PeakFlowRate & 0x00FF);
|
||||
result[35] = (byte)((PeakFlowRate >> 8) & 0x00FF);
|
||||
|
||||
result[36] = (byte)(AlarmState & 0x00FF);
|
||||
result[37] = (byte)((AlarmState >> 8) & 0x00FF);
|
||||
|
||||
result[38] = RebootCount;
|
||||
|
||||
result[39] = AlarmCount[0];
|
||||
result[40] = AlarmCount[1];
|
||||
result[41] = AlarmCount[2];
|
||||
result[42] = AlarmCount[3];
|
||||
result[43] = AlarmCount[4];
|
||||
result[44] = AlarmCount[5];
|
||||
result[45] = AlarmCount[6];
|
||||
|
||||
result[46] = (byte)(FlipTime & 0x00FF);
|
||||
result[47] = (byte)((FlipTime >> 8) & 0x00FF);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static StatusStruct FromByteArray(byte[] data)
|
||||
{
|
||||
if (data.Length != Length) return null;
|
||||
|
||||
StatusStruct result = new StatusStruct();
|
||||
|
||||
result.Version = data[0];
|
||||
result.FlowState = (FlowState)data[1];
|
||||
result.BillingVolume = (((UInt32)data[5] * 256 + data[4]) * 256 + data[3]) * 256 + data[2];
|
||||
result.ForwardVolume = (((UInt32)data[9] * 256 + data[8]) * 256 + data[7]) * 256 + data[6];
|
||||
result.ReverseVolume = (((UInt32)data[13] * 256 + data[12]) * 256 + data[11]) * 256 + data[10];
|
||||
result.SecondsActive = (((UInt32)data[17] * 256 + data[16]) * 256 + data[15]) * 256 + data[14];
|
||||
result.SecondsIdle = (((UInt32)data[21] * 256 + data[20]) * 256 + data[19]) * 256 + data[18];
|
||||
result.SecondsUsed = (((UInt32)data[25] * 256 + data[24]) * 256 + data[23]) * 256 + data[22];
|
||||
result.UTC = (((UInt32)data[29] * 256 + data[28]) * 256 + data[27]) * 256 + data[26];
|
||||
result.ScaledAvgFlowRate = (((Int32)data[33] * 256 + data[32]) * 256 + data[31]) * 256 + data[30]; /// TODO: test with negative value
|
||||
result.PeakFlowRate = (UInt16)(data[34] + 256 * data[35]);
|
||||
result.AlarmState = (UInt16)(data[36] + 256 * data[37]);
|
||||
result.RebootCount = data[38];
|
||||
result.AlarmCount[0] = data[39];
|
||||
result.AlarmCount[1] = data[40];
|
||||
result.AlarmCount[2] = data[41];
|
||||
result.AlarmCount[3] = data[42];
|
||||
result.AlarmCount[4] = data[43];
|
||||
result.AlarmCount[5] = data[44];
|
||||
result.AlarmCount[6] = data[45];
|
||||
result.FlipTime = (UInt16)(data[46] * 256 + data[47]);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format("Status: V{0} Flow={1} BillVol={2} ForwVol={3} RevVol={4} SecActive={5}s SecIdle={6}s SecUsed={7}s UTC={8} AvgFlowRate={9} PeekFlowRate={10} AlarmState={11} RebootCount={12} A0={13} A1={14} A2={15} A3={16} A4={17} A5={18} A6={19} FlipTime={20}",
|
||||
Version,
|
||||
FlowState,
|
||||
BillingVolume,
|
||||
ForwardVolume,
|
||||
ReverseVolume,
|
||||
SecondsActive,
|
||||
SecondsIdle,
|
||||
SecondsUsed,
|
||||
UTC,
|
||||
ScaledAvgFlowRate,
|
||||
PeakFlowRate,
|
||||
AlarmState,
|
||||
RebootCount,
|
||||
AlarmCount[0],
|
||||
AlarmCount[1],
|
||||
AlarmCount[2],
|
||||
AlarmCount[3],
|
||||
AlarmCount[4],
|
||||
AlarmCount[5],
|
||||
AlarmCount[6],
|
||||
FlipTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user