diff --git a/Common/Hardware/WaterMeter/Genesis/GenesisFile/MeterFile.cs b/Common/Hardware/WaterMeter/Genesis/GenesisFile/MeterFile.cs index 64eda829..fffb75f2 100644 --- a/Common/Hardware/WaterMeter/Genesis/GenesisFile/MeterFile.cs +++ b/Common/Hardware/WaterMeter/Genesis/GenesisFile/MeterFile.cs @@ -69,6 +69,28 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile /// public const String StrMeterEngLogIndexFile = "1\\logindex"; + /// + /// EMEA log files which can be removed on NA installation + /// + public static readonly String[] EmeaLogs = { "1\\fdrdata", "1\\logdata", "1\\evtdata" }; + + /// + /// NA log files which can be removed on EMEA installation + /// + public static readonly String[] NaLogs = + { "1\\NAalarm", "1\\NAconfig", "1\\NApress", "1\\NAstate", "1\\NAtempC", "1\\NAwater" }; + + /// + /// Essential files which have to be kept + /// + public static readonly String[] FilesToKeep = + { "0\\password", StrMeterConfigFile, "1\\logindex", "1\\mettbl", "1\\mettbl_b" }; + + /// + /// Files which always can be removed to clean the file system up "tidy file" + /// + public static readonly String[] FilesToRemove = { "1\\upg", "1\\upgrade", StrMeterTstFile }; + /// /// Drive zero of meter. /// @@ -262,13 +284,6 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile var rpc = BuildRpcInt32(1, dataBytes.Length, _filePointer); returnValue = _currentGenesis.WriteRegister(Register.Configexchange.FileWrite, rpc); - ////write size to 1 - //returnValue = _currentGenesis.WriteRegister(Register.Configexchange.FileWrite, 1, false); - ////write counts to data size - //returnValue &= _currentGenesis.WriteRegister(Register.Configexchange.FileWrite, dataBytes.Length, false); - ////write file pointer - //returnValue &= _currentGenesis.WriteRegister(Register.Configexchange.FileWrite, _filePointer); - //calculate records to send based on MaxRawDataSize var chunkCounts = dataBytes.Length / MaxRawDataSize; if (0 != dataBytes.Length % MaxRawDataSize) @@ -439,13 +454,6 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile var rpc = BuildRpcInt32(1, fileSize, _filePointer); _currentGenesis.WriteRegister(Register.Configexchange.FileRead, rpc); - ////write size to 1 - //_currentGenesis.WriteRegister(Register.Configexchange.FileRead, 1, false); - ////write counts to expected length - //_currentGenesis.WriteRegister(Register.Configexchange.FileRead, fileSize, false); - ////write file pointer - //_currentGenesis.WriteRegister(Register.Configexchange.FileRead, _filePointer); - //the preceding routine needs to wait for response, else this is always true! while (fileSize > 0 && !_stopProcess) { @@ -605,12 +613,6 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile var rpc = BuildRpcInt32(1, 1, _filePointer); returnValue = _currentGenesis.WriteRegister(Register.Configexchange.FileWrite, rpc); - ////write size to 1 - //returnValue = _currentGenesis.WriteRegister(Register.Configexchange.FileWrite, 1, false); - ////write block of data to 1 as only one byte needed to be at the end of file - //returnValue &= _currentGenesis.WriteRegister(Register.Configexchange.FileWrite, 1, false); - ////write file pointer - //returnValue &= _currentGenesis.WriteRegister(Register.Configexchange.FileWrite, _filePointer); //write one byte at the end of file returnValue &= _currentGenesis.WriteRegister(Register.Configexchange.FileWrite, 0xFF); @@ -774,7 +776,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile //request retries on single write register access, needs to be zero to hold the sequence CommunicationConfig.RequestRetries = 0; - //write "remove-command" to meter, wait for result and read back + //write "remove-command" to meter, return is always false! //ATTENTION: read back returns FALSE because of unreadable content _currentGenesis.WriteRegister(Register.Configexchange.FileRemove, fileName, true, true); //set timeout back to default value @@ -846,25 +848,12 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile do { - //if (retryCtr > 0) - //{ - // //read DUMMY to overcome FW malfunction - // _currentGenesis.ReadRegister(Register.System.MonotonicSeconds); - // Thread.Sleep(1000); - //} //request retries on single write register access, needs to be zero to hold the sequence CommunicationConfig.RequestRetries = 0; var rpc = BuildRpcInt32(_filePointer, filePointerOffset, fSeekPara); returnValue = _currentGenesis.WriteRegister(Register.Configexchange.SetFilePointerOffset, rpc); - //returnValue = _currentGenesis.WriteRegister(Register.Configexchange.SetFilePointerOffset, - // _filePointer, false); - //returnValue &= _currentGenesis.WriteRegister(Register.Configexchange.SetFilePointerOffset, - // filePointerOffset, false); - //returnValue &= _currentGenesis.WriteRegister(Register.Configexchange.SetFilePointerOffset, - // fSeekPara, false); - //function call returns 0 if FSeek successfully set returnValue &= 0 == RegisterConverter.ConvertTo(_currentGenesis.ReadRegister( Register.Configexchange.SetFilePointerOffset)); @@ -907,12 +896,6 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile do { - //if (retryCtr > 0) - //{ - // //read DUMMY to overcome FW malfunction - // _currentGenesis.ReadRegister(Register.System.MonotonicSeconds); - // Thread.Sleep(1000); - //} //read file pointer offset _currentGenesis.WriteRegister(Register.Configexchange.GetFilePointerOffset, _filePointer, false); @@ -988,13 +971,6 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile do { - //if (retryCtr > 0) - //{ - // //read DUMMY to overcome FW malfunction - // _currentGenesis.ReadRegister(Register.System.MonotonicSeconds); - // Thread.Sleep(1000); - //} - //write file name to meter with meter open command, don't wait for response var rpcString = new String(rpc.ToArray()); rpcString += accessMode; @@ -1002,11 +978,6 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile // wait for response! retValue = _currentGenesis.WriteRegister(Register.Configexchange.FileOpen, rpcString, false); - ////write file name to meter with meter open command, don't wait for response - //retValue = _currentGenesis.WriteRegister(Register.Configexchange.FileOpen, fileName, false); - ////write access flag - //retValue &= _currentGenesis.WriteRegister(Register.Configexchange.FileOpen, accessMode, false); - if (retValue) { //get the file pointer @@ -1068,13 +1039,6 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile do { - //if (retryCtr > 0) - //{ - // //read DUMMY to overcome FW malfunction - // _currentGenesis.ReadRegister(Register.System.MonotonicSeconds); - // Thread.Sleep(1000); - //} - retValue = _currentGenesis.WriteRegister(Register.Configexchange.FileClose, _filePointer); //function call returns 0 if FClose successfully executed diff --git a/Common/Ui/GenesisToolBox/FrmLowLevelTools.Designer.cs b/Common/Ui/GenesisToolBox/FrmLowLevelTools.Designer.cs index 1e37333c..4e08351d 100644 --- a/Common/Ui/GenesisToolBox/FrmLowLevelTools.Designer.cs +++ b/Common/Ui/GenesisToolBox/FrmLowLevelTools.Designer.cs @@ -68,8 +68,9 @@ this.label7 = new System.Windows.Forms.Label(); this.saveConfigFile = new System.Windows.Forms.SaveFileDialog(); this.groupBox2 = new System.Windows.Forms.GroupBox(); - this.btnReadLogFiles = new System.Windows.Forms.Button(); this.btnListFileDetails = new System.Windows.Forms.Button(); + this.btnReadLogFiles = new System.Windows.Forms.Button(); + this.btnTidyFile = new System.Windows.Forms.Button(); this.grpSetup.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit(); this.groupBox1.SuspendLayout(); @@ -348,6 +349,7 @@ // // groupBox1 // + this.groupBox1.Controls.Add(this.btnTidyFile); this.groupBox1.Controls.Add(this.btnGetDateTime); this.groupBox1.Controls.Add(this.btnSetDateTime); this.groupBox1.Controls.Add(this.btnRebootMeter); @@ -465,6 +467,16 @@ this.groupBox2.TabStop = false; this.groupBox2.Text = "Log"; // + // btnListFileDetails + // + this.btnListFileDetails.Location = new System.Drawing.Point(10, 84); + this.btnListFileDetails.Name = "btnListFileDetails"; + this.btnListFileDetails.Size = new System.Drawing.Size(116, 25); + this.btnListFileDetails.TabIndex = 39; + this.btnListFileDetails.Text = "List File Details"; + this.btnListFileDetails.UseVisualStyleBackColor = true; + this.btnListFileDetails.Click += new System.EventHandler(this.btnListFileDetails_Click); + // // btnReadLogFiles // this.btnReadLogFiles.Location = new System.Drawing.Point(10, 54); @@ -475,15 +487,15 @@ this.btnReadLogFiles.UseVisualStyleBackColor = true; this.btnReadLogFiles.Click += new System.EventHandler(this.btnReadLogFiles_Click); // - // btnListFileDetails + // btnTidyFile // - this.btnListFileDetails.Location = new System.Drawing.Point(10, 84); - this.btnListFileDetails.Name = "btnListFileDetails"; - this.btnListFileDetails.Size = new System.Drawing.Size(116, 25); - this.btnListFileDetails.TabIndex = 39; - this.btnListFileDetails.Text = "List File Details"; - this.btnListFileDetails.UseVisualStyleBackColor = true; - this.btnListFileDetails.Click += new System.EventHandler(this.btnListFileDetails_Click); + this.btnTidyFile.Location = new System.Drawing.Point(10, 174); + this.btnTidyFile.Name = "btnTidyFile"; + this.btnTidyFile.Size = new System.Drawing.Size(116, 25); + this.btnTidyFile.TabIndex = 39; + this.btnTidyFile.Text = "Tidy File System"; + this.btnTidyFile.UseVisualStyleBackColor = true; + this.btnTidyFile.Click += new System.EventHandler(this.btnTidyFile_Click); // // FrmLowLevelTools // @@ -568,5 +580,6 @@ private System.Windows.Forms.Button btnGetDateTime; private System.Windows.Forms.Button btnReadLogFiles; private System.Windows.Forms.Button btnListFileDetails; + private System.Windows.Forms.Button btnTidyFile; } } \ No newline at end of file diff --git a/Common/Ui/GenesisToolBox/FrmLowLevelTools.cs b/Common/Ui/GenesisToolBox/FrmLowLevelTools.cs index a07345a8..3e03dfe8 100644 --- a/Common/Ui/GenesisToolBox/FrmLowLevelTools.cs +++ b/Common/Ui/GenesisToolBox/FrmLowLevelTools.cs @@ -16,6 +16,7 @@ using Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile; using Xylem.Common.Hardware.WaterMeter.Genesis.Registers; using Xylem.Common.Hardware.WaterMeter.WaterMeterCore; using Xylem.Common.Utils.ProcessExec.EventArguments; +using String = System.String; namespace Xylem.Common.Ui.GenesisToolBox @@ -35,8 +36,8 @@ namespace Xylem.Common.Ui.GenesisToolBox private MeterFile _meterFile; - private String _lastFwUpdateState; - private Int32 _lastSingleProgress; + //private String _lastFwUpdateState; + //private Int32 _lastSingleProgress; private Boolean _progressBarOn; private DateTimeOffset _startTime; private Boolean _resetTimeMeasurement; @@ -155,6 +156,7 @@ namespace Xylem.Common.Ui.GenesisToolBox btnUploadConfig.Enabled = false; btnReadLogFiles.Enabled = false; btnListFileDetails.Enabled = false; + btnTidyFile.Enabled = false; } /// @@ -171,6 +173,7 @@ namespace Xylem.Common.Ui.GenesisToolBox btnUploadConfig.Enabled = true; btnReadLogFiles.Enabled = true; btnListFileDetails.Enabled = true; + btnTidyFile.Enabled = true; } /// @@ -436,7 +439,7 @@ namespace Xylem.Common.Ui.GenesisToolBox lblOverall.Visible = true; barOverallProgressUpdate.Visible = true; barSingleProgressUpdate.Visible = true; - _lastFwUpdateState = ""; + //_lastFwUpdateState = ""; tmrProgressUpdate.Enabled = true; SetControlsLowLevelOpOngoing(); } @@ -447,7 +450,7 @@ namespace Xylem.Common.Ui.GenesisToolBox barOverallProgressUpdate.Visible = false; barSingleProgressUpdate.Visible = false; tmrProgressUpdate.Enabled = false; - _lastFwUpdateState = ""; + //_lastFwUpdateState = ""; lblWaitingForMeterResponse.Visible = false; lblActualProcess.Text = ""; lblOverall.Text = ""; @@ -470,7 +473,7 @@ namespace Xylem.Common.Ui.GenesisToolBox { Invoke(new Action(() => { - _lastFwUpdateState = ""; + //_lastFwUpdateState = ""; ViewProcessControl(true); tmrProgressUpdate.Enabled = true; })); @@ -635,7 +638,7 @@ namespace Xylem.Common.Ui.GenesisToolBox #endregion - #region Checks + #region Tools private void CheckUpdateEnabled() { @@ -649,6 +652,111 @@ namespace Xylem.Common.Ui.GenesisToolBox SetCordonelAccessLocked(); } + /// + /// List all meter files + /// + /// + /// - Initial + /// + private List ListMeterFiles() + { + SetActualProcessAndLog(@"List meter files drive 0"); + _meterFile.ReadMeterFileCatalog(out var fileNamesDrive0, MeterFile.StrMeterDrive0); + if (fileNamesDrive0.Count == 0) + { + LogText(@"Could not read drive 0"); + } + else + { + foreach (var fileName in fileNamesDrive0) + { + LogText(fileName); + } + } + + SetActualProcessAndLog(@"List meter files drive 1"); + _meterFile.ReadMeterFileCatalog(out var fileNamesDrive1, MeterFile.StrMeterDrive1); + + if (fileNamesDrive1.Count == 0) + { + LogText(@"Could not read drive 1"); + } + else + { + foreach (var fileName in fileNamesDrive1) + { + LogText(fileName); + } + } + + var fileNames = new List(); + fileNames.AddRange(fileNamesDrive0); + fileNames.AddRange(fileNamesDrive1); + + return fileNames; + } + /// + /// List all meter log files covered by the log index file + /// + /// + /// - Initial + /// + private List ListLogFiles() + { + SetActualProcessAndLog(@"Flushing the logger"); + _currentGenesis.WriteRegister("LOGGER_TriggerLogFlush", 1); + + CalculateMeterDateTime(RegisterConverter.ConvertTo( + _currentGenesis.ReadRegister("SYSTEM_CalendarSeconds"))); + + SetActualProcessAndLog(@"Reading log index file"); + _meterFile.ReadMeterFile(MeterFile.StrMeterEngLogIndexFile, out var data); + + var fileNames = new List(); + var rawData = data.ToArray(); + var sample = new Byte[4]; + for (var ctr = 0; ctr < data.Count; ctr += 4) + { + for (var x = 0; x < 4; x++) + { + sample[x] = rawData[ctr + x]; + } + + var name = $"1\\{RegisterConverter.ConvertTo(sample):X8}"; + LogText($"Log file catalogue: {name}"); + fileNames.Add(name); + } + + fileNames.Sort(); + return fileNames; + } + + /// + /// Analyze all meter files + /// + /// + /// - Initial + /// + private void AnalyzeMeterFiles(List meterFiles) + { + if (meterFiles.Count == 0) + return; + + LogText("Analyzing meter files"); + foreach (var fileName in meterFiles) + { + Invoke(new Action(() => { lblActualProcess.Text = $@"Analyze file {fileName}"; })); + var success = _meterFile.GetFileSize(fileName, out var fileSize); + + LogText(success + ? $@"File name: {fileName}, File size: {fileSize} byte" + : $@"File name: {fileName} Unable to access file"); + if (success) + continue; + _currentGenesis.Logout(); + _currentGenesis.ReLogin(); + } + } #endregion #region Events @@ -690,7 +798,7 @@ namespace Xylem.Common.Ui.GenesisToolBox var singleProgress = (Int32)(_meterResetPsu?.SingleFileProcessCtrPercent ?? 0); barSingleProgressUpdate.Value = singleProgress > 100 ? 100 : singleProgress; - _lastSingleProgress = singleProgress; + //_lastSingleProgress = singleProgress; barSingleProgressUpdate.Update(); } @@ -1019,7 +1127,7 @@ namespace Xylem.Common.Ui.GenesisToolBox } /// - /// Read engineering log file from meter. + /// Read engineering log files from meter and analyzes the contents. /// /// /// - Initial @@ -1055,37 +1163,12 @@ namespace Xylem.Common.Ui.GenesisToolBox { _currentGenesis.ReLogin(); - SetActualProcessAndLog(@"Flushing the logger"); - _currentGenesis.WriteRegister("LOGGER_TriggerLogFlush", 1); - - CalculateMeterDateTime(RegisterConverter.ConvertTo( - _currentGenesis.ReadRegister("SYSTEM_CalendarSeconds"))); - - SetActualProcessAndLog(@"Reading log index file"); - _meterFile.ReadMeterFile(MeterFile.StrMeterEngLogIndexFile, out var data); - - var fileNames = new List(); - var rawData = data.ToArray(); - var sample = new Byte[4]; - for (var ctr = 0; ctr < data.Count; ctr += 4) - { - for (var x = 0; x < 4; x++) - { - sample[x] = rawData[ctr + x]; - } - - var name = RegisterConverter.ConvertTo(sample).ToString("X8"); - LogText(name); - fileNames.Add(name); - } - - fileNames.Sort(); + var fileNames = ListLogFiles(); foreach (var fileName in fileNames) { - msg = $"1\\{fileName}"; - SetActualProcessAndLog($@"Reading {msg}"); - var success = _meterFile.ReadMeterFile(msg, out data); + SetActualProcessAndLog($@"Reading and analyzing {fileName}"); + var success = _meterFile.ReadMeterFile(fileName, out var data); if (!success) { @@ -1162,7 +1245,7 @@ namespace Xylem.Common.Ui.GenesisToolBox /// /// List file details from meter. /// - /// + /// /// - Initial /// private void btnListFileDetails_Click(Object sender, EventArgs e) @@ -1177,42 +1260,15 @@ namespace Xylem.Common.Ui.GenesisToolBox LowLevelActionControl(true); - var msg = @"List file details from meter"; + var msg = @"List file details of meter"; LogText(msg); lblOverall.Text = msg; Task.Factory.StartNew(() => { _currentGenesis.ReLogin(); - var fileNames = new List(); - Invoke(new Action(() => { lblActualProcess.Text = @"List meter files drive 0"; })); - _meterFile.ReadMeterFileCatalog(out var fileNamesDrive0, MeterFile.StrMeterDrive0); - if (fileNamesDrive0.Count == 0) - { - LogText(@"Could not read drive 0"); - } - - Invoke(new Action(() => { lblActualProcess.Text = @"List meter files drive 1"; })); - _meterFile.ReadMeterFileCatalog(out var fileNamesDrive1, MeterFile.StrMeterDrive1); - - if (fileNamesDrive1.Count == 0) - { - LogText(@"Could not read drive 1"); - } - - fileNames.AddRange(fileNamesDrive0); - fileNames.AddRange(fileNamesDrive1); - foreach (var fileName in fileNames) - { - Invoke(new Action(() => { lblActualProcess.Text = $@"Analyze file {fileName}"; })); - var success = _meterFile.GetFileSize(fileName, out var fileSize); - - LogText(success ? $@"File name: {fileName}, File size: {fileSize} byte" - : $@"File name: {fileName} Unable to access file"); - if (success) continue; - _currentGenesis.Logout(); - _currentGenesis.ReLogin(); - } + var fileNames = ListMeterFiles(); + AnalyzeMeterFiles(fileNames); }).ContinueWith(delegate { //add a blank line to separate next operation @@ -1221,8 +1277,121 @@ namespace Xylem.Common.Ui.GenesisToolBox LowLevelActionControl(false); }); } - #endregion + /// + /// Tidy the file system: + /// - Erasing upgrade files left over from unsuccessfully FW update, + /// - Erase logging files for versions not covered by the actual region as + /// during development a reprogramming from EMEA to NA and vice versa will + /// leave the logs for thr other version in, + /// - Remove the test file for EMEA, as this is the placeholder for the FW + /// update over the air to keep the space reserved for this process (250 kB), + /// - Keep important files listed in the log index. + /// + /// + /// - Initial + /// + private void btnTidyFile_Click(Object sender, EventArgs e) + { + if (_currentGenesis == null) + return; + if (_meterFile == null) + _meterFile = new MeterFile(_currentGenesis); + + //reset timer + _startTime = DateTimeOffset.UtcNow; + + LowLevelActionControl(true); + + var msg = @"Tidy file system"; + LogText(msg); + lblOverall.Text = msg; + + Task.Factory.StartNew(() => + { + _currentGenesis.ReLogin(); + + // catalogue before cleaning + SetActualProcessAndLog(@"List meter files before cleaning"); + + // build file erase candidates for all releases + var fileEraseCandidates = new List(); + + // put initially all files in as erase candidates + var meterFiles = ListMeterFiles(); + AnalyzeMeterFiles(meterFiles); + fileEraseCandidates.AddRange(meterFiles); + + // build list of files needed to keep + var filesToKeep = new List(); + filesToKeep.AddRange(MeterFile.FilesToKeep); + + // for EMEA the NALogs are waste + if (_currentGenesis.Region.Contains("EMEA")) + { + LogText("EMEA version detected"); + filesToKeep.AddRange(MeterFile.EmeaLogs); + } + + // for EMEA the EMEALogs are waste + if (_currentGenesis.Region.Contains("NA")) + { + LogText("NA version detected"); + filesToKeep.AddRange(MeterFile.NaLogs); + } + + // red the log files and leave it in + var logFiles = ListLogFiles(); + filesToKeep.AddRange(logFiles); + + // remove files which should be kept in place + foreach (var meterFile in meterFiles) + { + foreach (var fileToKeep in filesToKeep) + { + if (meterFile.Contains(fileToKeep)) + fileEraseCandidates.Remove(meterFile); + } + } + // check if something to clean + if (fileEraseCandidates.Count == 0) + { + LogText("File system is clean"); + } + + else + { + // erase files + foreach (var fileToErase in fileEraseCandidates) + { + Invoke(new Action(() => { lblActualProcess.Text = $@"Erase {fileToErase}"; })); + _meterFile.UnlockEraseWriteMeterFile(fileToErase); + var success = _meterFile.EraseMeterFile(fileToErase); + + LogText(success + ? $@"File {fileToErase} successfully erased" + : $@"File {fileToErase} erasure failed"); + + if (success) continue; + _currentGenesis.Logout(); + _currentGenesis.ReLogin(); + } + // catalogue after cleaning + SetActualProcessAndLog(@"List meter files after cleaning"); + ListMeterFiles(); + + LogText("File system is cleaned up"); + } + }).ContinueWith(delegate + { + //add a blank line to separate next operation + LogText(""); + _currentGenesis.Logout(); + LowLevelActionControl(false); + }); + + } + #endregion } }