using System; using System.Linq; using Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore.Consts; using Xylem.Common.Hardware.WaterMeter.Genesis.Registers; namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore { /// /// Read of required registers and calculation of power correction /// public class PowerCorrectionCalc { private readonly GenesisMeter _currentGenesis; private readonly PowerCorrection _powCorr; /// /// Ctor /// /// /// /// true if successful public PowerCorrectionCalc(GenesisMeter currentGenesis, PowerCorrection powCorr) { _currentGenesis = currentGenesis; _powCorr = powCorr; } /// /// Calculate the values for power correction /// /// true if successful /// /// - Initial /// public Boolean PowerCorrEstimation() { if (_currentGenesis == null || _powCorr == null) return false; var logOnReminder = _currentGenesis.IsLoggedOn; var retVal = _currentGenesis.ReLogin(); if (retVal) { _powCorr.CorrectedTotalUsedCharge_uAs = null; // read registers _powCorr.ActualPulseSequenceCounter = RegisterConverter.ByteArrayToValue( _currentGenesis.ReadRegister(Register.Irda.PulseSequence)); _powCorr.ActualPulseEvenDistribution = RegisterConverter.ByteArrayToValue( _currentGenesis.ReadRegister(Register.Metrologyasst.PulseEvenDistribution)); _powCorr.ActualPulseMode = RegisterConverter.ByteArrayToValue( _currentGenesis.ReadRegister(Register.Metrologyasst.PulseMode)); _powCorr.ActualRadioSystemState = RegisterConverter.ByteArrayToValue( _currentGenesis.ReadRegister(Register.Sensusradio.SystemState)); _powCorr.ActualTotalUsedSeconds_s = RegisterConverter.ByteArrayToValue( _currentGenesis.ReadRegister(Register.Powermon.BatteryExceededSeconds)); _powCorr.ActualTotalUsedCharge_uAs = RegisterConverter.ByteArrayToValue( _currentGenesis.ReadRegister(Register.Powermon.BatteryDrainedLoad, 8)); _powCorr.BatteryQuantity = RegisterConverter.ByteArrayToValue( _currentGenesis.ReadRegister(Register.Powermon.BatteryQuantity)); _powCorr.InitialBatteryLoad_mAh = RegisterConverter.ByteArrayToValue( _currentGenesis.ReadRegister(Register.Powermon.BatteryInitialLoad)); if (!logOnReminder) _currentGenesis.Logout(); // get actual time from PC _powCorr.ActualDateTimeUtc = DateTime.UtcNow; // skip if indicated that a pulse adapter never has been installed _powCorr.PulseAdapterMarkedAsInstalled = _powCorr.ProductionPulseAdapterIsInstalled || _powCorr.ActualPulseAdapterIsInstalled; if (!_powCorr.PulseAdapterMarkedAsInstalled) return true; // calculate post production used seconds if (_powCorr.ProductionTotalUsedSeconds_s > _powCorr.ActualTotalUsedSeconds_s) _powCorr.PostProductionTotalUsedSeconds_s = _powCorr.ActualTotalUsedSeconds_s; else _powCorr.PostProductionTotalUsedSeconds_s = _powCorr.ActualTotalUsedSeconds_s - _powCorr.ProductionTotalUsedSeconds_s; // preset production used charge if not received from DB as logging of this value // in early production processes was not granted if (_powCorr.ProductionTotalUsedCharge_uAs == 0) _powCorr.ProductionTotalUsedCharge_uAs = (UInt64)(_powCorr.ProductionTotalUsedSeconds_s * PowCorrConst.FixProductionCurrent_uA); // calculate pulse report length if ((_powCorr.ActualPulseMode >= 1 && _powCorr.ActualPulseMode <= 4) || (_powCorr.ProductionPulseMode >= 1 && _powCorr.ProductionPulseMode <= 4)) { _powCorr.PulseReportLength = PowCorrConst.PulseReportLengthMode1To4Even0; if (_powCorr.ActualPulseEvenDistribution) _powCorr.PulseReportLength = PowCorrConst.PulseReportLengthMode1To4Even1; } else if ((_powCorr.ActualPulseMode >= 5 && _powCorr.ActualPulseMode <= 6) || (_powCorr.ProductionPulseMode >= 5 && _powCorr.ProductionPulseMode <= 6)) { _powCorr.PulseReportLength = PowCorrConst.PulseReportLengthMode5To6Even0; if (_powCorr.ActualPulseEvenDistribution) _powCorr.PulseReportLength = PowCorrConst.PulseReportLengthMode5To6Even1; } // calculate overestimation based on pulse report length _powCorr.OverestimatedTotalUsedCharge_uAs = 0; if ((_powCorr.ActualPulseMode >= 1 && _powCorr.ActualPulseMode <= 6) || (_powCorr.ProductionPulseMode >= 1 && _powCorr.ProductionPulseMode <= 6)) { _powCorr.OverestimatedTotalUsedCharge_uAs = (UInt64)(_powCorr.PulseReportLength * PowCorrConst.PulseReportLengthEstimate_uA * _powCorr.PostProductionTotalUsedSeconds_s); } Byte radioSystemState = 0; if (_powCorr.ActualRadioSystemState != null) { radioSystemState = (Byte)_powCorr.ActualRadioSystemState; } else if (_powCorr.ProductionRadioSystemState != null) { radioSystemState = (Byte)_powCorr.ProductionRadioSystemState; } if (_currentGenesis.Region == "NA") { _powCorr.MinimumTotalUsedCharge_uAs = (UInt64)(_powCorr.ActualTotalUsedSeconds_s * PowCorrConst.MinNaCurrent_uA); _powCorr.FixedEstimateTotalUsedCharge_uAs = (UInt64)(_powCorr.ActualTotalUsedSeconds_s * PowCorrConst.FixNaCurrent_uA); } else if (_currentGenesis.Region == "EMEA" && (radioSystemState & PowCorrConst.SensusRadioSystemStateTfXModeMask) == PowCorrConst.SensusRadioSystemStateTfXModeMask) { _powCorr.MinimumTotalUsedCharge_uAs = (UInt64)(_powCorr.ActualTotalUsedSeconds_s * PowCorrConst.MinEmeaRadioTfxModeCurrent_uA); _powCorr.FixedEstimateTotalUsedCharge_uAs = (UInt64)(_powCorr.ActualTotalUsedSeconds_s * PowCorrConst.FixEmeaRadioTfxModeCurrent_uA); } else if (_currentGenesis.Region == "EMEA" && (radioSystemState & PowCorrConst.SensusRadioSystemStateTfXModeMask) != PowCorrConst.SensusRadioSystemStateTfXModeMask) { _powCorr.MinimumTotalUsedCharge_uAs = (UInt64)(_powCorr.ActualTotalUsedSeconds_s * PowCorrConst.MinEmeaRadioRfModeCurrent_uA); _powCorr.FixedEstimateTotalUsedCharge_uAs = (UInt64)(_powCorr.ActualTotalUsedSeconds_s * PowCorrConst.FixEmeaRadioRfModeCurrent_uA); } if (_powCorr.OverestimatedTotalUsedCharge_uAs > _powCorr.ActualTotalUsedCharge_uAs) _powCorr.CorrectedTotalUsedCharge_uAs = 0; else _powCorr.CorrectedTotalUsedCharge_uAs = _powCorr.ActualTotalUsedCharge_uAs - _powCorr.OverestimatedTotalUsedCharge_uAs; } return retVal; } /// /// Calculate the values for power correction /// /// true if successful /// /// - Initial /// public Boolean CorrectPowerConsumption() { if (_currentGenesis == null || _powCorr == null || _powCorr.CorrectedTotalUsedCharge_uAs == null) return false; // check which value should be applied and set the CorrectedTotalUsedCharge_uAs if (_powCorr.ProductionPulseAdapterIsInstalled) { // avoid undershot below smallest value if (_powCorr.CorrectedTotalUsedCharge_uAs < _powCorr.MinimumTotalUsedCharge_uAs) _powCorr.CorrectedTotalUsedCharge_uAs = _powCorr.MinimumTotalUsedCharge_uAs; } else // retrofitted { // correct to smaller value and mark corrected = actual to log that correction not needed _powCorr.CorrectedTotalUsedCharge_uAs = _powCorr.ActualTotalUsedCharge_uAs > _powCorr.FixedEstimateTotalUsedCharge_uAs ? _powCorr.FixedEstimateTotalUsedCharge_uAs : _powCorr.ActualTotalUsedCharge_uAs; } if (_powCorr.ActualTotalUsedCharge_uAs == _powCorr.CorrectedTotalUsedCharge_uAs) return true; // save corrected power consumption data to meter var logOnReminder = _currentGenesis.IsLoggedOn; var retVal = _currentGenesis.ReLogin(); if (retVal) { var retriesLeft = 2; do { // write the new calculated value retVal = _currentGenesis.WriteRegister(Register.Powermon.BatteryDrainedLoad, RegisterConverter.ValueToByteArray(_powCorr.CorrectedTotalUsedCharge_uAs)); if (!retVal) continue; // store configuration retVal = _currentGenesis.WriteRegister(Register.Powermon.StoreConfiguration, 1); if (!retVal) continue; var readResult = _currentGenesis.ReadRegister(Register.Powermon.StoreConfiguration); retVal = readResult != null && readResult.ToList().All(array => array == 0x00); } while (!retVal && retriesLeft-- > 0); } if (!logOnReminder) _currentGenesis.Logout(); return retVal; } } }