/// /// Copyright (c) 2015 Sensus Metering Systems /// Author: Milan Hanajík /// using System; namespace TBF.BenchControl.WaterMeters.iPerl { public class ConfigStruct { public static readonly int Length = 32; public Byte Version; public MeterState MeterState; public UInt32 TargetTimeVeryLowBatt; /// in seconds public UInt32 TargetTimeLowBatt; /// in seconds public UInt32 TestModeTime; /// Max. test mode time in seconds public UInt16 EmptyPipeThreshold; public byte[] PCBNumber; /// 5 bytes public byte TestModeConfig; public UInt32 RadioAddress; public UInt16 TempCalibration; public UInt16 AlarmMask; /// Default 0xA3F7 public UInt16 ConfigCheckSum; 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; } /// /// Create a configuration structure from a complete byte array /// /// A complete byte array data /// ConfigStruct or null when byte array was not complete 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; } /// /// Update the configuration structure from an incomplete byte array /// /// Offset of byte array data in ConfigStruct /// Byte array data /// true when successful, false when data are not appropriate 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; } /// /// Converts PCBNumber to string /// /// /// PCB number string 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(); } /// /// Converts PCBNumber to string /// /// PCB number string public string PCBNumber2String() { return ConfigStruct.PCBNumber2String(PCBNumber); } 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, PCBNumber2String(), 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, PCBNumber2String(), TestModeConfig.ToString("X2"), RadioAddress, TempCalibration, AlarmMask.ToString("X4"), ConfigCheckSum.ToString("X4")); } } }