MeterFile improved:

- Multiple write used for all file operations where single sequential writes applied,
Cordonel "Low Level Tools":
- List files,
- List log files and analyze content,
FwUpdate:
- Erase tstfile, as this consumes 252 kB of space
This commit is contained in:
Thomas Wiedebusch
2023-01-13 12:27:29 +01:00
parent 07a59d3ccd
commit b6655ae270
14 changed files with 585 additions and 323 deletions
+1 -1
View File
@@ -155,7 +155,7 @@
</site>
<site name="MeterProcessState" id="2">
<application path="/" applicationPool="Clr4IntegratedAppPool">
<virtualDirectory path="/" physicalPath="C:\ProgrammeSensus\Repo\Lab\La_Operations\laa_production\Common\Service\MeterProcessState" />
<virtualDirectory path="/" physicalPath="D:\Projekte\SENSUS_GitLab\laa_production\Common\Service\MeterProcessState" />
</application>
<bindings>
<binding protocol="http" bindingInformation="*:56011:localhost" />
+1
View File
@@ -18,6 +18,7 @@
<s:Boolean x:Key="/Default/UserDictionary/Words/=accu/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Applic/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Approver/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=artefact/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Battey/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=binfile/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=BUGFIX/@EntryIndexedValue">True</s:Boolean>
@@ -25,9 +25,7 @@ namespace Xylem.Common.Hardware.Interfaces.Protocols.TransmitProtocol
private const Int32 UartSyncByteLength = 1; //length of syncByte
private const Int32 UartHeaderLength = 4; //length excluding syncByte and CRC
private const Int32 UartCrcLength = 2;
private const Int32 UartProtocolFrameLength = UartSyncByteLength + UartHeaderLength
+ UartCrcLength;
private const Int32 UartProtocolFrameLength = UartSyncByteLength + UartHeaderLength + UartCrcLength;
private const Byte UartSyncByte = 0x5B;
//The UART length covers all bytes excluding the syncByte length
@@ -22,6 +22,10 @@
/// </summary>
StartInitial,
/// <summary>
/// Erase test file as this reserves space for update over the air
/// </summary>
EraseTstFile,
/// <summary>
/// Repeat FW update
/// </summary>
RepeatFwUpdate,
@@ -32,6 +32,9 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile.Consts
StateInfos[(Int32)FwUpdateState.StartInitial].State = FwUpdateState.StartInitial;
StateInfos[(Int32)FwUpdateState.StartInitial].Message = Resources.StrFwUpdateStateStartInitial;
StateInfos[(Int32)FwUpdateState.EraseTstFile].State = FwUpdateState.EraseTstFile;
StateInfos[(Int32)FwUpdateState.EraseTstFile].Message = Resources.StrEraseTstFile;
StateInfos[(Int32)FwUpdateState.RepeatFwUpdate].State = FwUpdateState.RepeatFwUpdate;
StateInfos[(Int32)FwUpdateState.RepeatFwUpdate].Message = Resources.StrFwUpdateStateRepeatFwUpdate;
@@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore;
using Xylem.Common.Hardware.WaterMeter.Genesis.Registers;
using Xylem.Common.Hardware.WaterMeter.Genesis.GenesisConfig;
@@ -33,11 +32,14 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
//TODO THW test only private const String StrNewFileReadWriteMode = "wb+";
//wb open file for writing in binary mode, if file exists its contents will be overwritten,
//if file does not exist it will be created
private const String StrNewFileReadWriteMode = "wb";
//private const String StrNewFileReadWriteMode = "wb";
private const String StrNewFileReadWriteMode = "w";
//Open for reading in binary mode. If the file does not exist, FOpen returns NULL
private const String StrOpenFileReadOnlyMode = "rb";
//private const String StrOpenFileReadOnlyMode = "rb";
private const String StrOpenFileReadOnlyMode = "r";
//Open for both reading and writing in binary mode. If the file does not exist, FOpen returns NULL
private const String StrOpenFileReadWriteMode = "rb+";
//private const String StrOpenFileReadWriteMode = "rb+";
private const String StrOpenFileReadWriteMode = "r+";
/// <summary>
/// FSeek for start of file
@@ -57,6 +59,11 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
/// </summary>
public const String StrMeterConfigFile = "0\\config";
/// <summary>
/// The test file is for SENSUSRADIO as placeholder for update over the air.
/// </summary>
public const String StrMeterTstFile = "1\\tstfile";
/// <summary>
/// Engineering log index file of meter.
/// </summary>
@@ -80,7 +87,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
/// <summary>
/// Wildcard for search all.
/// </summary>
public const Char WildcardAll = '*';
public const String WildcardAll = "*";
/// <summary>
/// Processed bytes counter
@@ -199,10 +206,17 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
/// <remarks date="2022-Apr-01" author="Thomas Wiedebusch">
/// - Add a NULL at the end of the file name.
/// </remarks>
/// <remarks date="2023-Jan-06" author="Thomas Wiedebusch">
/// - Adapted to new ReadFilePointerOffset.
/// </remarks>
/// <remarks date="2023-Jan-12" author="Thomas Wiedebusch">
/// - Combined FOpen to one file open function,
/// - Using <see cref="BuildRpcInt32"></see> for multiple write access to register instead of 3 writes.
/// </remarks>
public Boolean WriteMeterFile(String fileName, Byte[] dataBytes, Int32 fileOffset = 0)
{
var returnValue = false;
//set to true to enter the cyclic write routines, will be overwritten with file pointer adjustment
var returnValue = true;
//set processing counter
ProcessedBytesCtr = 0;
//inform the caller of changed statue
@@ -210,106 +224,136 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
_overallBytesCtr = dataBytes.Length;
//add file name delimiter
fileName += StringDelimiter;
//check if file is unlocked for write
if (!fileName.Contains(StringDelimiter))
fileName += StringDelimiter;
//check if file is unlocked for write access
if (_fileName != fileName)
return false;
if ((fileOffset == 0 && OpenMeterFile(fileName, StrNewFileReadWriteMode))
|| (fileOffset > 0 && OpenMeterFile(fileName, StrOpenFileReadWriteMode)))
var accessMode = fileOffset == 0 ? StrNewFileReadWriteMode : StrOpenFileReadWriteMode;
//file open as new or additional write with immediately return if file cannot be opened
if (!OpenMeterFile(fileName, accessMode))
return false;
//adjust file pointer if offset is required
if (fileOffset > 0)
{
returnValue = true;
returnValue = SetFilePointerOffset(fileOffset);
//adjust file pointer if offset is required
if (fileOffset > 0)
if (returnValue)
{
returnValue = SetFilePointerOffset(fileOffset);
//read file pointer offset
returnValue &= fileOffset == ReadFilePointerOffset();
}
if (returnValue && !_stopProcess)
{
//set extended timeout for file operations to extended timeout
_currentGenesis.TransmitProtocol.SetResponseTimeout(_fileWriteTimeOutMs);
//set register write retries to 0 to avoid doubling of records, if wakeup message from
//serial communication routine received, one retry will kicked off in the request protocol
CommunicationConfig.RequestRetries = 0;
//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)
{
chunkCounts += 1;
}
var dataByteList = new List<Byte>();
dataByteList.AddRange(dataBytes);
var dataChunk = new List<Byte>();
var ctr = 0;
//the preceding routine needs to wait for response, else this is always true!
while (returnValue && ctr < chunkCounts && !_stopProcess)
{
var index = ctr * MaxRawDataSize;
var size = index + MaxRawDataSize > dataByteList.Count ? dataByteList.Count - index : MaxRawDataSize;
//prepare data to write
dataChunk.Clear();
dataChunk.AddRange(dataByteList.GetRange(index, size));
//break on failed write of this part
returnValue = _currentGenesis.WriteRegister(Register.Configexchange.FileWrite, dataChunk.ToArray());
//set processed bytes for write loop
ProcessedBytesCtr += size;
//inform the caller of changed statue
var processCtrPercent = 100.0 * ProcessedBytesCtr / (_overallBytesCtr > 0 ? _overallBytesCtr : 1);
OnProcessUpdate?.Invoke(this, new ProcessExecEventArgs("", processCtrPercent));
ctr++;
}
//read back bytes written
var writtenBytes = 0;
var returnedFileOffset = 0;
//the preceding routine needs to wait for response, else this is always true!
if (returnValue)
{
writtenBytes = RegisterConverter.ConvertTo<Int32>(
_currentGenesis.ReadRegister(Register.Configexchange.FileWrite));
returnedFileOffset = ReadFilePointerOffset();
}
//set timeout back to default value
_currentGenesis.TransmitProtocol.SetDefaultResponseTimeout();
CommunicationConfig.RequestRetries = CommunicationConfig.DefaultRequestRetries;
if (writtenBytes != ProcessedBytesCtr || returnedFileOffset != fileOffset + writtenBytes)
if (!ReadFilePointerOffset(out var readBackFilePointerOffset) ||
fileOffset != readBackFilePointerOffset)
returnValue = false;
}
}//file open
}
returnValue &= CloseMeterFile();
if (returnValue && !_stopProcess)
{
//set extended timeout for file operations to extended timeout
_currentGenesis.TransmitProtocol.SetResponseTimeout(_fileWriteTimeOutMs);
//set register write retries to 0 to avoid doubling of records, if wakeup message from
//serial communication routine received, one retry will kicked off in the request protocol
CommunicationConfig.RequestRetries = 0;
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)
{
chunkCounts += 1;
}
var dataByteList = new List<Byte>();
dataByteList.AddRange(dataBytes);
var dataChunk = new List<Byte>();
var ctr = 0;
//the preceding routine needs to wait for response, else this is always true!
while (returnValue && ctr < chunkCounts && !_stopProcess)
{
var index = ctr * MaxRawDataSize;
var size = index + MaxRawDataSize > dataByteList.Count ? dataByteList.Count - index : MaxRawDataSize;
//prepare data to write
dataChunk.Clear();
dataChunk.AddRange(dataByteList.GetRange(index, size));
//break on failed write of this part
returnValue = _currentGenesis.WriteRegister(Register.Configexchange.FileWrite, dataChunk.ToArray());
//set processed bytes for write loop
ProcessedBytesCtr += size;
//inform the caller of changed statue
var processCtrPercent = 100.0 * ProcessedBytesCtr / (_overallBytesCtr > 0 ? _overallBytesCtr : 1);
OnProcessUpdate?.Invoke(this, new ProcessExecEventArgs("", processCtrPercent));
ctr++;
}
//read back bytes written
var writtenBytes = 0;
var returnedFileOffset = 0;
//the preceding routine needs to wait for response, else this is always true!
if (returnValue)
{
writtenBytes = RegisterConverter.ConvertTo<Int32>(
_currentGenesis.ReadRegister(Register.Configexchange.FileWrite));
ReadFilePointerOffset(out returnedFileOffset);
}
//set timeout back to default value
_currentGenesis.TransmitProtocol.SetDefaultResponseTimeout();
CommunicationConfig.RequestRetries = CommunicationConfig.DefaultRequestRetries;
if (writtenBytes != ProcessedBytesCtr || returnedFileOffset != fileOffset + writtenBytes)
return false;
}
//processed bytes not longer needed
OnProcessUpdate?.Invoke(this, new ProcessExecEventArgs("", 0));
ProcessedBytesCtr = 0;
_overallBytesCtr = 0;
returnValue &= CloseMeterFile();
return returnValue;
}
/// <summary>
/// Build RPC (remote procedure call) for 3 Int32 parameters.
/// This routine concatenates these 3 Int32 to one byte array to have a multiple read or
/// write operation to the register instead of having 3 simple register write accesses.
/// </summary>
/// <param name="first"></param>
/// <param name="second"></param>
/// <param name="last"></param>
/// <returns>file content as byte array</returns>
/// <remarks date="2023-Jan-12" author="Thomas Wiedebusch">
/// - Initial
/// </remarks>
public static Byte[] BuildRpcInt32(Int32 first, Int32 second, Int32 last)
{
var rpc = new List<Byte>();
rpc.AddRange(BitConverter.GetBytes(first));
rpc.AddRange(BitConverter.GetBytes(second));
rpc.AddRange(BitConverter.GetBytes(last));
return rpc.ToArray();
}
/// <summary>
/// Read file from the meter
/// </summary>
@@ -353,6 +397,16 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
/// <remarks date="2023-Jan-03" author="Thomas Wiedebusch">
/// - Speed up FOpen as read is not so critical.
/// </remarks>
/// <remarks date="2023-Jan-06" author="Thomas Wiedebusch">
/// - Avoid reading of file size from FSeek is 0.
/// </remarks>
/// <remarks date="2023-Jan-07" author="Thomas Wiedebusch">
/// - Removed extended timeout.
/// </remarks>
/// <remarks date="2023-Jan-12" author="Thomas Wiedebusch">
/// - FClose added on failed GetFileSizeInternal.
/// - Using <see cref="BuildRpcInt32"></see> for multiple write access to register instead of 3 writes.
/// </remarks>
public Boolean ReadMeterFile(String fileName, out List<Byte> readBackData)
{
//set processing counter
@@ -360,63 +414,60 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
OnProcessUpdate?.Invoke(this, new ProcessExecEventArgs("", 0));
//add file name delimiter
fileName += StringDelimiter;
if (!fileName.Contains(StringDelimiter))
fileName += StringDelimiter;
readBackData = new List<Byte>();
// Get the current file size
var returnValue = GetFileSize(fileName, out var readBackCount);
//use high speed access
if (!OpenMeterFile(fileName, StrOpenFileReadOnlyMode))
return false;
if (returnValue)
//get the current file size, the size of 0 is a valid file size, but reading is not necessary
if (!GetFileSizeInternal(fileName, out var fileSize))
{
// here the file is already opened and has to be closed to avoid error 0x040E "TOO_MANY_OPEN"
CloseMeterFile();
return false;
}
//use high speed access
returnValue &= OpenMeterFile(fileName, StrOpenFileReadOnlyMode, true);
//set register write retries to 0 to avoid doubling of records
CommunicationConfig.RequestRetries = 0;
if (returnValue)
if (fileSize > 0)
{
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)
{
//set register write retries to 0 to avoid doubling of records
CommunicationConfig.RequestRetries = 0;
_currentGenesis.TransmitProtocol.SetResponseTimeout(ExtendedFileIoTimeoutMs);
var remainingData = RegisterConverter.ConvertTo<Int32>(
_currentGenesis.ReadRegister(Register.Configexchange.FileRead));
//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);
fileSize = remainingData > 0 ? fileSize - remainingData : 0;
//the preceding routine needs to wait for response, else this is always true!
while (readBackCount > 0 && !_stopProcess)
while (remainingData > 0)
{
var remainingData = RegisterConverter.ConvertTo<Int32>(
_currentGenesis.ReadRegister(Register.Configexchange.FileRead));
var size = remainingData > MaxRawDataSize ? MaxRawDataSize : remainingData;
readBackData.AddRange(_currentGenesis.ReadRegister(Register.Configexchange.FileRead, size));
remainingData -= size;
readBackCount = remainingData > 0 ? readBackCount - remainingData : 0;
//set processed bytes for read loop
ProcessedBytesCtr += size;
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));
}
//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;
}//file open succeeded
returnValue &= CloseMeterFile();
}
}// file size unequal to 0
@@ -424,8 +475,11 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
ProcessedBytesCtr = 0;
OnProcessUpdate?.Invoke(this, new ProcessExecEventArgs("", 0));
//set timeout back to default value
CommunicationConfig.RequestRetries = CommunicationConfig.DefaultRequestRetries;
//read raw data from meter
return returnValue;
return CloseMeterFile();
}
/// <summary>
@@ -441,10 +495,13 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
/// <remarks date="2023-Jan-04" author="Thomas Wiedebusch">
/// - Default wildcard.
/// </remarks>
public Boolean ReadMeterFileCatalog(out List<String> files, String drive, Char wildcard = WildcardAll)
public Boolean ReadMeterFileCatalog(out List<String> files, String drive, String wildcard = WildcardAll)
{
files = new List<String>();
//add file name delimiter
if (!wildcard.Contains(StringDelimiter))
wildcard += StringDelimiter;
//write the initial key
var key = 0;
_stopProcess = false;
@@ -486,6 +543,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
files.Add(filePathName);
}
files.Sort();
return files.Count > 0;
}
@@ -501,104 +559,140 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
/// <remarks date="2022-Apr-01" author="Thomas Wiedebusch">
/// - Add a NULL at the end of the file name.
/// </remarks>
/// <remarks date="2023-Jan-06" author="Thomas Wiedebusch">
/// - Adapted to new ReadFilePointerOffset.
/// </remarks>
/// <remarks date="2023-Jan-12" author="Thomas Wiedebusch">
/// - Using <see cref="BuildRpcInt32"></see> for multiple write access to register instead of 3 writes.
/// </remarks>
public Boolean CreateEmptyMeterFile(String fileName, Int32 fileSize = 0)
{
var returnValue = false;
//check if logged on to meter and access level is as expected
if (_currentGenesis == null || !_currentGenesis.IsLoggedOn)
return false;
//add file name delimiter
fileName += StringDelimiter;
if (!fileName.Contains(StringDelimiter))
fileName += StringDelimiter;
//check if file is unlocked for write
if (_fileName != fileName)
return false;
if (OpenMeterFile(fileName, StrNewFileReadWriteMode))
//exit immediately if file cannot be opened
if (!OpenMeterFile(fileName, StrNewFileReadWriteMode))
return false;
var returnValue = true;
//adjust file pointer if offset is required
if (fileSize > 0)
{
returnValue = true;
// adjust file pointer to the end of file
returnValue = SetFilePointerOffset(fileSize - 1);
//read file pointer offset
returnValue &= ReadFilePointerOffset(out var readBackFileSize);
returnValue &= (fileSize - 1) == readBackFileSize;
}
//adjust file pointer if offset is required
if (fileSize > 0)
if (returnValue && !_stopProcess)
{
//set extended timeout for file operations to extended timeout
_currentGenesis.TransmitProtocol.SetResponseTimeout(_fileWriteTimeOutMs);
//set register write retries to 0 to avoid doubling of records, if wakeup message from
//serial communication routine received, one retry will kicked off in the request protocol
CommunicationConfig.RequestRetries = 0;
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);
//read back bytes written
var returnedFileOffset = 0;
//the preceding routine needs to wait for response, else this is always true!
if (returnValue)
{
// adjust file pointer to the end of file
returnValue = SetFilePointerOffset(fileSize - 1);
//read file pointer offset
returnValue &= (fileSize - 1) == ReadFilePointerOffset();
RegisterConverter.ConvertTo<Int32>(
_currentGenesis.ReadRegister(Register.Configexchange.FileWrite));
ReadFilePointerOffset(out returnedFileOffset);
}
if (returnValue && !_stopProcess)
{
//set extended timeout for file operations to extended timeout
_currentGenesis.TransmitProtocol.SetResponseTimeout(_fileWriteTimeOutMs);
//set register write retries to 0 to avoid doubling of records, if wakeup message from
//serial communication routine received, one retry will kicked off in the request protocol
CommunicationConfig.RequestRetries = 0;
//set timeout back to default value
_currentGenesis.TransmitProtocol.SetDefaultResponseTimeout();
CommunicationConfig.RequestRetries = CommunicationConfig.DefaultRequestRetries;
//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);
//read back bytes written
var returnedFileOffset = 0;
//the preceding routine needs to wait for response, else this is always true!
if (returnValue)
{
RegisterConverter.ConvertTo<Int32>(
_currentGenesis.ReadRegister(Register.Configexchange.FileWrite));
returnedFileOffset = ReadFilePointerOffset();
}
//set timeout back to default value
_currentGenesis.TransmitProtocol.SetDefaultResponseTimeout();
CommunicationConfig.RequestRetries = CommunicationConfig.DefaultRequestRetries;
if (returnedFileOffset != fileSize)
returnValue = false;
}
}//file open
if (returnedFileOffset != fileSize)
returnValue = false;
}
returnValue &= CloseMeterFile();
return returnValue;
}
/// <summary>
/// Uses FSeek to get the file size.
/// Read the file size.
/// </summary>
/// <param name="fileName">file name as string</param>
/// <param name="fileSize">file size of the given file</param>
/// <returns>true: file found </returns>
/// <returns>true: file size could be read </returns>
/// <remarks date="2023-Jan-02" author="Thomas Wiedebusch">
/// - Initial
/// </remarks>
/// <remarks date="2023-Jan-06" author="Thomas Wiedebusch">
/// - Modified returns.
/// </remarks>
public Boolean GetFileSize(String fileName, out Int32 fileSize)
{
fileSize = 0;
//check if logged on to meter and access level is as expected
if (_currentGenesis == null || !_currentGenesis.IsLoggedOn)
return false;
//add file name delimiter
fileName += StringDelimiter;
if (!fileName.Contains(StringDelimiter))
fileName += StringDelimiter;
var returnValue = OpenMeterFile(fileName, StrOpenFileReadOnlyMode, true);
if (returnValue)
{
returnValue &= SetFilePointerOffset(fSeekPara: FSeekEndOfFile);
if (returnValue)
{
fileSize = ReadFilePointerOffset();
}
}
//return immediately, if file cannot be opened
if (!OpenMeterFile(fileName, StrOpenFileReadOnlyMode))
return false;
var returnValue = SetFilePointerOffset(fSeekPara: FSeekEndOfFile);
returnValue &= ReadFilePointerOffset(out fileSize);
returnValue &= CloseMeterFile();
return returnValue;
}
/// <summary>
/// Uses FSeek to get the file size.
/// For this function the file has to be opened in advance!
/// For correct access, the file pointer has to be set after detection of the
/// file size back to the start of the file!!!!!
/// </summary>
/// <param name="fileName">file name as string</param>
/// <param name="fileSize">file size of the given file</param>
/// <returns>true: file found </returns>
/// <remarks date="2023-Jan-06" author="Thomas Wiedebusch">
/// - Initial
/// </remarks>
private Boolean GetFileSizeInternal(String fileName, out Int32 fileSize)
{
fileSize = 0;
var returnValue = SetFilePointerOffset(fSeekPara: FSeekEndOfFile);
returnValue &= ReadFilePointerOffset(out fileSize);
//set the file pointer back to the start of file!!!!!
returnValue &= SetFilePointerOffset();
return returnValue;
}
/// <summary>
/// Meter file verification against given data
/// Takes into account, that the read file is always integer dividable by 4 due to the chunk size
@@ -613,12 +707,20 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
/// <remarks date="2022-Apr-21" author="Thomas Wiedebusch">
/// - Changed return value to false, if file could not be read.
/// </remarks>
/// <remarks date="2023-Jan-07" author="Thomas Wiedebusch">
/// - Compare byte by byte until length of given buffer, as the returned buffer is always filled
/// up to the chunk size of 4.
/// </remarks>
public Boolean VerifyMeterFile(String fileName, Byte[] dataBytes)
{
//check if logged on to meter and access level is as expected
if (_currentGenesis == null || !_currentGenesis.IsLoggedOn)
return false;
var returnValue = true;
//add file name delimiter
fileName += StringDelimiter;
if (!fileName.Contains(StringDelimiter))
fileName += StringDelimiter;
if (!ReadMeterFile(fileName, out var binData) || binData == null || binData.Count == 0)
return false;
@@ -653,25 +755,29 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
/// <remarks date="2022-Apr-01" author="Thomas Wiedebusch">
/// - Add a NULL at the end of the file name.
/// </remarks>
/// <remarks date="2023-Jan-07" author="Thomas Wiedebusch">
/// - Removed extended timeout.
/// </remarks>
public Boolean EraseMeterFile(String fileName)
{
//add file name delimiter
fileName += StringDelimiter;
//check if file is unlocked for erase
if (_fileName != fileName)
return false;
//check if logged on to meter and access level is as expected
if (_currentGenesis == null || !_currentGenesis.IsLoggedOn)
return false;
//set extended timeout for file operations
_currentGenesis.TransmitProtocol.SetResponseTimeout(ExtendedFileIoTimeoutMs);
//add file name delimiter
if (!fileName.Contains(StringDelimiter))
fileName += StringDelimiter;
//check if file is unlocked for erase
if (_fileName != fileName)
return false;
//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
//ATTENTION: read back returns FALSE because of unreadable content
_currentGenesis.WriteRegister(Register.Configexchange.FileRemove, fileName, true, true);
//set timeout back to default value
_currentGenesis.TransmitProtocol.SetDefaultResponseTimeout();
CommunicationConfig.RequestRetries = CommunicationConfig.DefaultRequestRetries;
return true;
@@ -691,17 +797,17 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
public Boolean UnlockEraseWriteMeterFile(String fileName)
{
//add file name delimiter
fileName += StringDelimiter;
//check if logged on to meter and access level is as expected
if (_currentGenesis == null || !_currentGenesis.IsLoggedOn)
return false;
if (!fileName.Contains(StringDelimiter))
fileName += StringDelimiter;
//remind file name being unlocked
_fileName = fileName;
return true;
}
/// <summary>
/// FSeek implementation of genesis meter. FOpen has to be executed in advance to get
/// FSeek implementation of genesis meter.
/// ATTENTION: FOpen has to be executed in advance to get
/// the file pointer.
/// </summary>
/// <param name="filePointerOffset"></param>
@@ -723,6 +829,12 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
/// <remarks date="2023-Jan-02" author="Thomas Wiedebusch">
/// - Extended FSeek for file end positioning.
/// </remarks>
/// <remarks date="2023-Jan-07" author="Thomas Wiedebusch">
/// - Removed extended timeout.
/// </remarks>
/// <remarks date="2023-Jan-12" author="Thomas Wiedebusch">
/// - Using <see cref="BuildRpcInt32"></see> for multiple write access to register instead of 3 writes.
/// </remarks>
private Boolean SetFilePointerOffset(Int32 filePointerOffset = 0, Int32 fSeekPara = FSeekStartOfFile)
{
Boolean returnValue;
@@ -734,31 +846,30 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
do
{
if (retryCtr > 0)
{
//read DUMMY to overcome FW malfunction
//_currentGenesis.ReadRegister(Register.Genesisflow.LedMode);
_currentGenesis.ReadRegister(Register.System.MonotonicSeconds);
Thread.Sleep(1000);
}
//set extended timeout for file operations
_currentGenesis.TransmitProtocol.SetResponseTimeout(ExtendedFileIoTimeoutMs);
//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;
returnValue = _currentGenesis.WriteRegister(Register.Configexchange.SetFilePointerOffset,
_filePointer, false);
returnValue &= _currentGenesis.WriteRegister(Register.Configexchange.SetFilePointerOffset,
filePointerOffset, false);
returnValue &= _currentGenesis.WriteRegister(Register.Configexchange.SetFilePointerOffset,
fSeekPara, false);
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<UInt32>(_currentGenesis.ReadRegister(
Register.Configexchange.SetFilePointerOffset));
//set timeout back to default value
_currentGenesis.TransmitProtocol.SetDefaultResponseTimeout();
//set back to default value
CommunicationConfig.RequestRetries = CommunicationConfig.DefaultRequestRetries;
} while (!returnValue && retryCtr++ < CommandWriteRetries);
@@ -782,38 +893,38 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
/// - Retries changed for and back,
/// - Timeout changed for and back.
/// </remarks>
private Int32 ReadFilePointerOffset()
/// <remarks date="2023-Jan-06" author="Thomas Wiedebusch">
/// - Modified for return.
/// </remarks>
/// <remarks date="2023-Jan-07" author="Thomas Wiedebusch">
/// - Removed extended timeout.
/// </remarks>
private Boolean ReadFilePointerOffset(out Int32 filePointerOffset)
{
Boolean returnValue;
var retryCtr = 0;
Int32 filePointerOffset;
//request retries on single write register access, needs to be zero to hold the sequence
CommunicationConfig.RequestRetries = 0;
do
{
if (retryCtr > 0)
{
//read DUMMY to overcome FW malfunction
//_currentGenesis.ReadRegister(Register.Genesisflow.LedMode);
_currentGenesis.ReadRegister(Register.System.MonotonicSeconds);
Thread.Sleep(1000);
}
//set extended timeout for file operations
_currentGenesis.TransmitProtocol.SetResponseTimeout(ExtendedFileIoTimeoutMs);
CommunicationConfig.RequestRetries = 0;
//if (retryCtr > 0)
//{
// //read DUMMY to overcome FW malfunction
// _currentGenesis.ReadRegister(Register.System.MonotonicSeconds);
// Thread.Sleep(1000);
//}
//read file pointer offset
returnValue = _currentGenesis.WriteRegister(Register.Configexchange.GetFilePointerOffset,
_currentGenesis.WriteRegister(Register.Configexchange.GetFilePointerOffset,
_filePointer, false);
filePointerOffset = RegisterConverter.ConvertTo<Int32>(_currentGenesis.ReadRegister(
Register.Configexchange.GetFilePointerOffset));
//set timeout back to default value
_currentGenesis.TransmitProtocol.SetDefaultResponseTimeout();
CommunicationConfig.RequestRetries = CommunicationConfig.DefaultRequestRetries;
} while (!returnValue && retryCtr++ < CommandWriteRetries);
} while (filePointerOffset <= 0 && retryCtr++ < CommandWriteRetries);
return filePointerOffset;
//set timeout back to default value
CommunicationConfig.RequestRetries = CommunicationConfig.DefaultRequestRetries;
return filePointerOffset > 0;
}
/// <summary>
@@ -822,7 +933,6 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
/// </summary>
/// <param name="fileName"></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
@@ -838,48 +948,79 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
/// <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)
/// <remarks date="2023-Jan-07" author="Thomas Wiedebusch">
/// - Removed retry dummy read.
/// </remarks>
/// <remarks date="2023-Jan-07" author="Thomas Wiedebusch">
/// - Removed extended timeout.
/// </remarks>
/// <remarks date="2023-Jan-12" author="Thomas Wiedebusch">
/// - Make sure NULL terminator is at the end of the file name and access mode.
/// - Combined filename and access mode to use one write access to the register
/// instead of two.
/// </remarks>
private Boolean OpenMeterFile(String fileName, String accessMode)
{
//check if logged on to meter and access level is as expected
if (_currentGenesis == null || !_currentGenesis.IsLoggedOn)
return false;
Boolean returnValue;
//add file name delimiter
if (!fileName.Contains(StringDelimiter))
fileName += StringDelimiter;
//add access mode delimiter
if (!accessMode.Contains(StringDelimiter))
accessMode += StringDelimiter;
var rpc = new List<Char>();
rpc.AddRange(fileName.ToCharArray());
// fill it padded to the chunk size
while (rpc.Count % RegisterDefinition.ChunkSize != 0)
{
rpc.Add(StringDelimiter);
}
var retryCtr = 0;
Boolean retValue;
//request retries on single write register access, needs to be zero to hold the sequence
CommunicationConfig.RequestRetries = 0;
do
{
if (retryCtr > 0)
{
//read DUMMY to overcome FW malfunction
//_currentGenesis.ReadRegister(Register.Genesisflow.LedMode);
_currentGenesis.ReadRegister(Register.System.MonotonicSeconds);
Thread.Sleep(1000);
}
//set extended timeout for file operations
if (highSpeed)
_currentGenesis.TransmitProtocol.SetResponseTimeout(ExtendedFileIoTimeoutMs);
CommunicationConfig.RequestRetries = 0;
//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
_currentGenesis.WriteRegister(Register.Configexchange.FileOpen, fileName, false);
//write access flag
_currentGenesis.WriteRegister(Register.Configexchange.FileOpen, accessMode, false);
var rpcString = new String(rpc.ToArray());
rpcString += accessMode;
//get the file pointer
_filePointer = RegisterConverter.ConvertTo<Int32>(_currentGenesis.ReadRegister(
Register.Configexchange.FileOpen));
// wait for response!
retValue = _currentGenesis.WriteRegister(Register.Configexchange.FileOpen, rpcString, false);
//set timeout back to default value
_currentGenesis.TransmitProtocol.SetDefaultResponseTimeout();
CommunicationConfig.RequestRetries = CommunicationConfig.DefaultRequestRetries;
////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);
returnValue = 0 < _filePointer;
if (retValue)
{
//get the file pointer
_filePointer = RegisterConverter.ConvertTo<Int32>(_currentGenesis.ReadRegister(
Register.Configexchange.FileOpen));
}
} while (!returnValue && retryCtr++ < CommandWriteRetries);
return returnValue;
} while ((_filePointer <= 0 || retValue == false) && retryCtr++ < CommandWriteRetries);
//set retries back to default value
CommunicationConfig.RequestRetries = CommunicationConfig.DefaultRequestRetries;
return _filePointer > 0 && retValue;
}
/// <summary>
@@ -910,26 +1051,41 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
/// <remarks date="2023-Jan-04" author="Thomas Wiedebusch">
/// - Removed extended timeout.
/// </remarks>
/// <remarks date="2023-Jan-12" author="Thomas Wiedebusch">
/// - FClose retries.
/// </remarks>
private Boolean CloseMeterFile()
{
//avoid file close if file pointer assignment failed
if (_filePointer <= 0)
return false;
//set extended timeout for file operations
//_currentGenesis.TransmitProtocol.SetResponseTimeout(ExtendedFileIoTimeoutMs);
//request retries on single write register access, needs to be zero to hold the sequence
CommunicationConfig.RequestRetries = 0;
_currentGenesis.WriteRegister(Register.Configexchange.FileClose, _filePointer);
//function call returns 0 if FClose successfully executed
var returnValue = 0 == RegisterConverter.ConvertTo<Int32>(
_currentGenesis.ReadRegister(Register.Configexchange.FileClose));
var retryCtr = 0;
Boolean retValue;
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
retValue &= 0 == RegisterConverter.ConvertTo<Int32>(
_currentGenesis.ReadRegister(Register.Configexchange.FileClose));
}while ( retValue == false && retryCtr++ < CommandWriteRetries);
//set timeout back to default value
//_currentGenesis.TransmitProtocol.SetDefaultResponseTimeout();
CommunicationConfig.RequestRetries = CommunicationConfig.DefaultRequestRetries;
return returnValue;
return retValue;
}
}
}
@@ -98,11 +98,17 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
/// <summary>
/// Core revision minimum as int32? with major * 100 + minor for comparison
/// </summary>
public Int32? CoreRevisionMinimum { get; private set; }
public Int32? CoreRevisionMinimum
{
get; private set;
}
/// <summary>
/// Core revision maximum as int32? with major * 100 + minor for comparison
/// </summary>
public Int32? CoreRevisionMaximum { get; private set; }
public Int32? CoreRevisionMaximum
{
get; private set;
}
//reminder for the core minimum requirement as string
private String _strCoreRevisionMinimum;
@@ -1113,6 +1119,9 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
/// <remarks date="2023-Jan-02" author="Thomas Wiedebusch">
/// - Upload config file removed.
/// </remarks>
/// <remarks date="2023-Jan-13" author="Thomas Wiedebusch">
/// - Erase test file introduced.
/// </remarks>
private void FwUpdateStateMachine()
{
if (_fwBackupUpdateState == _fwUpdateState)
@@ -1130,6 +1139,11 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
case FwUpdateState.StartInitial:
_updateProcedureRetryCtr = 0;
_fwUpdateState = FwUpdateState.EraseTstFile;
break;
case FwUpdateState.EraseTstFile:
EraseTstFile();
_fwUpdateState = FwUpdateState.BuildFileApps;
break;
@@ -1495,6 +1509,28 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
}
}
/// <summary>
/// Erase the test file which is an EMEA placeholder for update over the air.
/// This has a very large size to keep the space reserved for all applications
/// needed to be downloaded. This file can be erased as it will be automatically
/// regenerated after reboot by the SENSUSRADIO app.
/// </summary>
/// <returns></returns>
/// <remarks date="2023-Jan-13" author="Thomas Wiedebusch">
/// - Initial
/// </remarks>
private void EraseTstFile()
{
if (_meterFile == null || _genesisMeter == null)
return;
// erase always, because it may be left as artefact by changing from NA to EMEA or vice versa!
//if (_genesisMeter.Region.Contains("EMEA"))
{
_meterFile.UnlockEraseWriteMeterFile(MeterFile.StrMeterTstFile);
_meterFile.EraseMeterFile(MeterFile.StrMeterTstFile);
}
}
/// <summary>
/// Download and result handling for update files
/// </summary>
@@ -60,6 +60,15 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile.Properties {
}
}
/// <summary>
/// Looks up a localized string similar to Erase test file.
/// </summary>
public static string StrEraseTstFile {
get {
return ResourceManager.GetString("StrEraseTstFile", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Build Update Files.
/// </summary>
@@ -186,4 +186,7 @@
<data name="StrUploadConfigFile" xml:space="preserve">
<value>Lade Einstellungen</value>
</data>
<data name="StrEraseTstFile" xml:space="preserve">
<value>Lösche Testdatei</value>
</data>
</root>
@@ -156,7 +156,7 @@
<data name="StrFwUpdateStateUploadFileApps" xml:space="preserve">
<value>Upload Update Files</value>
</data>
<data name="StrWaiting" xml:space="preserve">
<data name="StrWaiting" xml:space="preserve">
<value>Waiting....</value>
</data>
<data name="StrWaitingForReboot" xml:space="preserve">
@@ -186,4 +186,7 @@
<data name="StrUploadConfigFile" xml:space="preserve">
<value>Upload configuration file</value>
</data>
<data name="StrEraseTstFile" xml:space="preserve">
<value>Erase test file</value>
</data>
</root>
@@ -1 +1 @@
81d60b90addc793525740e9993e19bf6665bd401
f64d563def603c89cafafa61a3219ba97e1e344c
+1 -1
View File
@@ -260,7 +260,7 @@
this.btnClearDisplay.Name = "btnClearDisplay";
this.btnClearDisplay.Size = new System.Drawing.Size(116, 25);
this.btnClearDisplay.TabIndex = 0;
this.btnClearDisplay.Text = "Clear Display";
this.btnClearDisplay.Text = "Release Display";
this.btnClearDisplay.UseVisualStyleBackColor = true;
this.btnClearDisplay.Click += new System.EventHandler(this.btnClearDisplay_Click);
//
+77 -28
View File
@@ -535,19 +535,28 @@ namespace Xylem.Common.Ui.GenesisToolBox
var msg = $@"{dt:yyyy-MM-dd hh:mm:ss}";
LogText($@"PC date time [UTC]: {msg}");
var secSince2000 =
RegisterConverter.ConvertTo<Int32>(_currentGenesis.ReadRegister("SYSTEM_CalendarSeconds"));
var ts = TimeSpan.FromSeconds(secSince2000);
var meterDateTime = new DateTime(2000, 1, 1, 0, 0, 0).Add(ts);
msg = $@"{meterDateTime:yyyy-MM-dd hh:mm:ss}";
tbxDateTime.Text = msg;
LogText($@"Meter date time [UTC]: {msg}");
CalculateMeterDateTime(RegisterConverter.ConvertTo<Int32>(
_currentGenesis.ReadRegister("SYSTEM_CalendarSeconds")));
//add a blank line to separate next operation
LogText("");
_currentGenesis.Logout();
}
/// <summary>
/// Calculate and log Cordonel time.
/// </summary>
/// <remarks date="2023-Jan-06" author="Thomas Wiedebusch">
/// - Init.
/// </remarks>
private void CalculateMeterDateTime(Int32 secSince2000)
{
var ts = TimeSpan.FromSeconds(secSince2000);
var meterDateTime = new DateTime(2000, 1, 1, 0, 0, 0).Add(ts);
var msg = $@"{meterDateTime:yyyy-MM-dd hh:mm:ss}";
Invoke(new Action(() => { tbxDateTime.Text = msg; }));
LogText($@"Meter date time [UTC]: {msg}");
}
/// <summary>
/// Clear history window.
/// </summary>
@@ -799,6 +808,9 @@ namespace Xylem.Common.Ui.GenesisToolBox
if (_currentGenesis == null)
return;
//reset timer
_startTime = DateTimeOffset.UtcNow;
var msg = @"Fix battery settings";
LogText(msg);
lblOverall.Text = msg;
@@ -843,6 +855,9 @@ namespace Xylem.Common.Ui.GenesisToolBox
if (_currentGenesis == null)
return;
//reset timer
_startTime = DateTimeOffset.UtcNow;
var msg = @"Store all configurations in meter";
LogText(msg);
lblActualProcess.Text = msg;
@@ -874,7 +889,7 @@ namespace Xylem.Common.Ui.GenesisToolBox
return;
}
// reset the time
//reset timer
_startTime = DateTimeOffset.UtcNow;
var msg = @"Reboot meter with pseudo FW update";
@@ -921,6 +936,9 @@ namespace Xylem.Common.Ui.GenesisToolBox
if (_meterFile == null)
_meterFile = new MeterFile(_currentGenesis);
//reset timer
_startTime = DateTimeOffset.UtcNow;
LowLevelActionControl(true);
var msg = @"Upload configuration file from meter";
@@ -1013,13 +1031,17 @@ namespace Xylem.Common.Ui.GenesisToolBox
if (_meterFile == null)
_meterFile = new MeterFile(_currentGenesis);
//reset timer
_startTime = DateTimeOffset.UtcNow;
var statusMap = new Dictionary<Int32, String>();
if (File.Exists("Status.json"))
{
var dict = JsonConvert.DeserializeObject<Dictionary<String, JObject>>(File.ReadAllText("Status.json"));
foreach (var item in dict)
{
statusMap.Add(int.Parse(item.Value.First.Values().First().ToString()), item.Key);
if (item.Value.First != null)
statusMap.Add(int.Parse(item.Value.First.Values().First().ToString()), item.Key);
}
}
@@ -1036,6 +1058,9 @@ namespace Xylem.Common.Ui.GenesisToolBox
SetActualProcessAndLog(@"Flushing the logger");
_currentGenesis.WriteRegister("LOGGER_TriggerLogFlush", 1);
CalculateMeterDateTime(RegisterConverter.ConvertTo<Int32>(
_currentGenesis.ReadRegister("SYSTEM_CalendarSeconds")));
SetActualProcessAndLog(@"Reading log index file");
_meterFile.ReadMeterFile(MeterFile.StrMeterEngLogIndexFile, out var data);
@@ -1054,14 +1079,24 @@ namespace Xylem.Common.Ui.GenesisToolBox
fileNames.Add(name);
}
fileNames.Sort();
foreach (var fileName in fileNames)
{
msg = $"1\\{fileName}";
SetActualProcessAndLog($@"Reading {msg}");
_meterFile.ReadMeterFile(msg, out data);
var success = _meterFile.ReadMeterFile(msg, out data);
LogText("Data:");
LogText($"{ByteArrayStyle.ByteStyler.ToString(data.ToArray())}");
if (!success)
{
_currentGenesis.Logout();
_currentGenesis.ReLogin();
}
if (data.Count > 0)
{
LogText($"Data: {ByteArrayStyle.ByteStyler.ToString(data.ToArray())}");
}
if (data.Count >= 5)
{
@@ -1083,22 +1118,31 @@ namespace Xylem.Common.Ui.GenesisToolBox
case 2:
msg = $"({logType}) Critical";
break;
default:
msg = $"({logType}) Unknown log type";
break;
}
LogText($"Log type:{msg}");
LogText($"Log type: {msg}");
LogText(statusMap.ContainsKey(status)
? $"Status: ({status}) {statusMap[status]}"
: $"Status:{status}");
LogText($"Count:{count}");
LogText($"Extra data size:{extraDataSize}");
: $"Status: {status}");
LogText($"Count: {count}");
LogText($"Extra data size: {extraDataSize}");
//avoid access beyond the buffer and check for data to display
if (ctr + 5 + extraDataSize < data.Count && extraDataSize > 0)
{
var extraData = data.GetRange(ctr + 5, extraDataSize);
LogText($"Extra data: {ByteArrayStyle.ByteStyler.ToString(extraData.ToArray())}");
}
var extraData = data.GetRange(ctr + 5, extraDataSize);
LogText("Extra data:");
LogText($"{ByteArrayStyle.ByteStyler.ToString(extraData.ToArray())}");
LogText(" ");
ctr += (5 + extraDataSize);
//exit if index for next run is out of range
if (ctr + 5 >= data.Count) break;
if (ctr + 5 >= data.Count)
break;
}
}
else
@@ -1107,13 +1151,12 @@ namespace Xylem.Common.Ui.GenesisToolBox
}
}
}).ContinueWith(delegate
{
{
//add a blank line to separate next operation
LogText("");
_currentGenesis.Logout();
LowLevelActionControl(false);
});
_currentGenesis.Logout();
LowLevelActionControl(false);
});
}
/// <summary>
@@ -1129,6 +1172,9 @@ namespace Xylem.Common.Ui.GenesisToolBox
if (_meterFile == null)
_meterFile = new MeterFile(_currentGenesis);
//reset timer
_startTime = DateTimeOffset.UtcNow;
LowLevelActionControl(true);
var msg = @"List file details from meter";
@@ -1163,11 +1209,14 @@ namespace Xylem.Common.Ui.GenesisToolBox
LogText(success ? $@"File name: {fileName}, File size: {fileSize} byte"
: $@"File name: {fileName} Unable to access file");
if (success) continue;
_currentGenesis.Logout();
_currentGenesis.ReLogin();
}
}).ContinueWith(delegate
{
//add a blank line to separate next operation
LogText("");
//add a blank line to separate next operation
LogText("");
_currentGenesis.Logout();
LowLevelActionControl(false);
});
@@ -2947,7 +2947,7 @@ namespace Xylem.ServiceFwUpdate.Ui.ServiceFwUpdateSw
foreach (var meterFileToEraseMask in _meterFilesEraseRestore.Erase.Where(
x => x.Contains(MeterFile.WildcardAll)))
{
var wildcardMask = meterFileToEraseMask.Split(MeterFile.WildcardAll);
var wildcardMask = meterFileToEraseMask.Split('*');
wildcardList.Add(wildcardMask[0]);
}