MeterFile: - high speed file open

FrmLutUpdate, FrmFwUpdate, FrmLowLevelUpdate: - data base connection to connect task to have the progress bar active
This commit is contained in:
Thomas Wiedebusch
2023-01-03 09:52:40 +01:00
parent 4a9d300f4a
commit b48893ff06
10 changed files with 295 additions and 235 deletions
@@ -62,10 +62,6 @@
/// </summary>
PrepareUpdate,
/// <summary>
/// Read configuration file from meter
/// </summary>
UploadConfigFile,
/// <summary>
/// Delimiter for list
/// </summary>
FwUpdateStateListDelimiter
@@ -61,9 +61,6 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile.Consts
StateInfos[(Int32)FwUpdateState.PrepareUpdate].State = FwUpdateState.PrepareUpdate;
StateInfos[(Int32)FwUpdateState.PrepareUpdate].Message = Resources.StrFwUpdateStatePrepareUpdate;
StateInfos[(Int32)FwUpdateState.UploadConfigFile].State = FwUpdateState.UploadConfigFile;
StateInfos[(Int32)FwUpdateState.UploadConfigFile].Message = Resources.StrUploadConfigFile;
}
/// <summary>
@@ -108,7 +108,6 @@
<Compile Include="Consts\FwUpdateState.cs" />
<Compile Include="Consts\FwUpdateStateInfo.cs" />
<Compile Include="Consts\FwUpdateStateText.cs" />
<Compile Include="MeterConfigFile.cs" />
<Compile Include="MeterLutFile.cs" />
<Compile Include="MeterFileRestore.cs" />
<Compile Include="MeterFilesEraseRestore.cs" />
@@ -1,22 +0,0 @@
using System;
using System.Collections.Generic;
namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
{
/// <summary>
/// File for meter configuration
/// </summary>
public class MeterConfigFile
{
/// <summary>
/// Data length
/// </summary>
public UInt32 DataLength;
/// <summary>
/// Binary file content
/// </summary>
public List<Byte> BinData = new List<Byte>();
}
}
@@ -38,12 +38,12 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
private const String StrOpenFileReadOnlyMode = "rb";
//Open for both reading and writing in binary mode. If the file does not exist, FOpen returns NULL
private const String StrOpenFileReadWriteMode = "rb+";
/// <summary>
/// FSeek for start of file
/// </summary>
public const Int32 FSeekStartOfFile = 0;
/// <summary>
/// FSeek for end of file
/// </summary>
@@ -281,7 +281,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
_currentGenesis.ReadRegister(Register.Configexchange.FileWrite));
returnedFileOffset = ReadFilePointerOffset();
}
//set timeout back to default value
_currentGenesis.TransmitProtocol.SetDefaultResponseTimeout();
CommunicationConfig.RequestRetries = CommunicationConfig.DefaultRequestRetries;
@@ -341,6 +341,9 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
/// <remarks date="2023-Jan-02" author="Thomas Wiedebusch">
/// - Read data according to file size searched with FSeek.
/// </remarks>
/// <remarks date="2023-Jan-03" author="Thomas Wiedebusch">
/// - Speed up FOpen as read is not so critical.
/// </remarks>
public Boolean ReadMeterFile(String fileName, out List<Byte> readBackData)
{
//set processing counter
@@ -355,55 +358,58 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
// Get the current file size
var returnValue = GetFileSize(fileName, out var readBackCount);
returnValue &= OpenMeterFile(fileName, StrOpenFileReadOnlyMode);
if (returnValue)
{
//set register write retries to 0 to avoid doubling of records
CommunicationConfig.RequestRetries = 0;
_currentGenesis.TransmitProtocol.SetResponseTimeout(ExtendedFileIoTimeoutMs);
//write size to 1
_currentGenesis.WriteRegister(Register.Configexchange.FileRead, 1, false);
//write counts to expected length
_currentGenesis.WriteRegister(Register.Configexchange.FileRead, readBackCount, false);
//write file pointer
_currentGenesis.WriteRegister(Register.Configexchange.FileRead, _filePointer);
//use high speed access
returnValue &= OpenMeterFile(fileName, StrOpenFileReadOnlyMode, true);
//the preceding routine needs to wait for response, else this is always true!
while (readBackCount > 0 && !_stopProcess)
if (returnValue)
{
var remainingData = RegisterConverter.ConvertTo<Int32>(
_currentGenesis.ReadRegister(Register.Configexchange.FileRead));
//set register write retries to 0 to avoid doubling of records
CommunicationConfig.RequestRetries = 0;
_currentGenesis.TransmitProtocol.SetResponseTimeout(ExtendedFileIoTimeoutMs);
readBackCount = remainingData > 0 ? readBackCount - remainingData : 0;
//write size to 1
_currentGenesis.WriteRegister(Register.Configexchange.FileRead, 1, false);
//write counts to expected length
_currentGenesis.WriteRegister(Register.Configexchange.FileRead, readBackCount, false);
//write file pointer
_currentGenesis.WriteRegister(Register.Configexchange.FileRead, _filePointer);
while (remainingData > 0)
//the preceding routine needs to wait for response, else this is always true!
while (readBackCount > 0 && !_stopProcess)
{
var size = remainingData > MaxRawDataSize ? MaxRawDataSize : remainingData;
readBackData.AddRange(_currentGenesis.ReadRegister(Register.Configexchange.FileRead, size));
remainingData -= size;
var remainingData = RegisterConverter.ConvertTo<Int32>(
_currentGenesis.ReadRegister(Register.Configexchange.FileRead));
//set processed bytes for read loop
ProcessedBytesCtr += size;
readBackCount = remainingData > 0 ? readBackCount - remainingData : 0;
//inform the caller of changed statue
var processCtrPercent = 100.0 * ProcessedBytesCtr / (_overallBytesCtr > 0 ? _overallBytesCtr : 1);
OnProcessUpdate?.Invoke(this, new ProcessExecEventArgs("", processCtrPercent));
while (remainingData > 0)
{
var size = remainingData > MaxRawDataSize ? MaxRawDataSize : remainingData;
readBackData.AddRange(_currentGenesis.ReadRegister(Register.Configexchange.FileRead, size));
remainingData -= size;
//set processed bytes for read loop
ProcessedBytesCtr += size;
//inform the caller of changed statue
var processCtrPercent = 100.0 * ProcessedBytesCtr / (_overallBytesCtr > 0 ? _overallBytesCtr : 1);
OnProcessUpdate?.Invoke(this, new ProcessExecEventArgs("", processCtrPercent));
}
}
}
//set timeout back to default value
_currentGenesis.TransmitProtocol.SetDefaultResponseTimeout();
CommunicationConfig.RequestRetries = CommunicationConfig.DefaultRequestRetries;
//set timeout back to default value
_currentGenesis.TransmitProtocol.SetDefaultResponseTimeout();
CommunicationConfig.RequestRetries = CommunicationConfig.DefaultRequestRetries;
}//file open succeeded
}//file open succeeded
//dummy read to avoid 0x040B feedback from meter
//_currentGenesis.ReadRegister(Register.Configexchange.FileRead, 1);
returnValue &= CloseMeterFile();
returnValue &= CloseMeterFile();
}// file size unequal to 0
//processed bytes not longer needed
ProcessedBytesCtr = 0;
@@ -562,16 +568,16 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
public Boolean GetFileSize(String fileName, out Int32 fileSize)
{
fileSize = 0;
var returnValue = OpenMeterFile(fileName, StrOpenFileReadOnlyMode);
var returnValue = OpenMeterFile(fileName, StrOpenFileReadOnlyMode, true);
if (returnValue)
{
returnValue &= SetFilePointerOffset(fSeekPara: FSeekEndOfFile);
returnValue &= SetFilePointerOffset(fSeekPara: FSeekEndOfFile);
if (returnValue)
{
fileSize = ReadFilePointerOffset();
}
if (returnValue)
{
fileSize = ReadFilePointerOffset();
}
}
returnValue &= CloseMeterFile();
@@ -596,7 +602,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
{
var returnValue = true;
if (!ReadMeterFile(fileName, out var binData)|| binData == null || binData.Count == 0)
if (!ReadMeterFile(fileName, out var binData) || binData == null || binData.Count == 0)
return false;
// compare the entire buffer which also includes the header of the file, remind the original
@@ -609,11 +615,6 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
returnValue = false;
}
}
//if (dataBytes.Where((t, ctr) => t != binData[ctr]).Any())
//{
// returnValue = false;
//}
return returnValue;
}
@@ -704,7 +705,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
/// <remarks date="2023-Jan-02" author="Thomas Wiedebusch">
/// - Extended FSeek for file end positioning.
/// </remarks>
private Boolean SetFilePointerOffset(Int32 filePointerOffset = 0, Int32 fSeekPara = FSeekStartOfFile)
private Boolean SetFilePointerOffset(Int32 filePointerOffset = 0, Int32 fSeekPara = FSeekStartOfFile)
{
Boolean returnValue;
var retryCtr = 0;
@@ -802,7 +803,8 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
/// Open a file of the meter and sets the file pointer
/// </summary>
/// <param name="fileName"></param>
/// <param name="accessMode"></param>
/// <param name="accessMode">read, write eg,</param>
/// <param name="highSpeed">disable high timeouts</param>
/// <returns>true if filePointer higher than zero</returns>
/// <remarks date="2019-Jun-20" author="Thomas Wiedebusch">
/// - Initial
@@ -815,7 +817,10 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
/// - Retries changed for and back,
/// - Timeout changed for and back.
/// </remarks>
private Boolean OpenMeterFile(String fileName, String accessMode)
/// <remarks date="2023-Jan-03" author="Thomas Wiedebusch">
/// - Extended timings removed if high speed is active.
/// </remarks>
private Boolean OpenMeterFile(String fileName, String accessMode, Boolean highSpeed = false)
{
//check if logged on to meter and access level is as expected
if (_currentGenesis == null || !_currentGenesis.IsLoggedOn)
@@ -834,7 +839,9 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
}
//set extended timeout for file operations
_currentGenesis.TransmitProtocol.SetResponseTimeout(ExtendedFileIoTimeoutMs);
if (highSpeed)
_currentGenesis.TransmitProtocol.SetResponseTimeout(ExtendedFileIoTimeoutMs);
CommunicationConfig.RequestRetries = 0;
//write file name to meter with meter open command, don't wait for response
@@ -25,9 +25,6 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
{
#region Variables
// Look up table file
public MeterConfigFile ConfigFile;
/// <summary>
/// Port scan result event for message dispatcher to caller
/// </summary>
@@ -713,59 +710,6 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
}
}
/// <summary>
/// Upload the config file from meter
/// </summary>
/// <returns></returns>
/// <remarks date="2022-Apr-26" author="Thomas Wiedebusch">
/// - Initial
/// </remarks>
public Boolean UploadConfigFile()
{
//counters for actual process information
var retryCtr = 0;
ConfigFile = new MeterConfigFile();
_processedBytesCtr = 0;
_overallBytesCtr = 6;
_meterFile = new MeterFile(_genesisMeter);
if (_meterFile != null)
{
_meterFile.OnProcessUpdate += ProcessUpdate_Event;
}
_genesisMeter?.ReLogin();
_genesisMeter?.SetProcessState(DisplayCodes.FwUpdateActive, webRequest: false);
if (_genesisMeter == null || !_genesisMeter.IsLoggedOn || _meterFile == null)
return false;
var returnValue = true;
//read config file and retry if not successful
do
{
_actualOperation = Resources.StrUploadConfigFile;
// logout and re-login to clear all ongoing processes and clear the Genesis buffers
ReestablishMeterFileSystem();
if (!_meterFile.ReadMeterFile(StrConfigMeterFileName, out ConfigFile.BinData))
{
returnValue = false;
}
if (!returnValue)
{
ReestablishMeterFileSystem();
}
} while (!returnValue && retryCtr++ < FileWriteRetries && !StopUpdateProcess);
_meterFile.OnProcessUpdate -= ProcessUpdate_Event;
return !StopUpdateProcess && returnValue;
}
/// <summary>
/// Update meter firmware
/// </summary>
@@ -1170,6 +1114,9 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
/// - Prepare update added,
/// - Upload config file added.
/// </remarks>
/// <remarks date="2023-Jan-02" author="Thomas Wiedebusch">
/// - Upload config file removed.
/// </remarks>
private void FwUpdateStateMachine()
{
if (_fwBackupUpdateState == _fwUpdateState)
@@ -1185,12 +1132,6 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
case FwUpdateState.Idle:
break;
case FwUpdateState.UploadConfigFile:
_fwUpdateState = UploadConfigFile()
? FwUpdateState.Idle
: FwUpdateState.StepFailed;
break;
case FwUpdateState.StartInitial:
_updateProcedureRetryCtr = 0;
_fwUpdateState = FwUpdateState.BuildFileApps;