MeterFile:

- Added '\0' string delimiter to file name, is essential for erase/write and read operation,
- Ignored return from file close write as it is often false and the following read returns a correct answer,
GenesisMeter:
- Removed doubled outputs
MeterRegisters:
- corrected parsing of registers
FrmLutUpdate:
- output of region and frequency,
MeterLutUpdate:
- For comparison of file content after reading back taking the different size of original and receive buffer, which is an integer division by 4, into account.
This commit is contained in:
Thomas Wiedebusch
2022-04-01 14:22:54 +02:00
parent d95a85f0b7
commit 8b9ccc17dd
7 changed files with 160 additions and 113 deletions
@@ -1194,21 +1194,9 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
var versionString = fm.IsInstalled
? $"V: {fm.StrVersion} - CRC: 0x{fm.Crc:X4}" : "Not installed";
_logger.Info($"AppId: 0x{fm.AppId:X2} - {versionString} - AppName: {fm.AppName}");
if (fm.AppName.ToUpper() == "SENSUSRADIO" && fm.IsInstalled)
{
var radioFrequency = ReadRegister(Register.Sensusradio.FrequencyIndicator);
var tmpList = radioFrequency.ToList();
tmpList.Reverse();
var strRawResult = BitConverter.ToString(tmpList.ToArray());
RegionRadio = $"EMEA_{strRawResult}";
}
}
//read radio frequency
_logger.Info("Region and radio frequency[Mhz]: " + RegionRadio);
//safe temporary registers from file to compare first and last version with application version read from meter and
_logger.Info($"Meter size: {MeterSize}");
//remove unused registers with invalid version
var tempConfigRegisters = _configRegister.MeterRegisterDic.ToList();
//tempConfigRegisters.ToList()
@@ -9718,30 +9718,6 @@
"maximum": 17
},
"statictype": "static"
},
{
"type": "enum8",
"privilege": {
"lvl1": "RO",
"lvl2": "RO",
"lvl3": "RO",
"lvl4": "RO",
"lvl5": "RO",
"lvl6": "RO",
"lvl7": "RW",
"lvl8": "RW"
},
"description": "The meter pipe size",
"version": {
"first": 601,
"last": 303
},
"values": {
"default": 1,
"minimum": 0,
"maximum": 17
},
"statictype": "static"
}
]
},
@@ -16917,4 +16893,4 @@
}
}
}
}
}
@@ -30,8 +30,13 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
private readonly GenesisMeter _currentGenesis;
private Int32 _filePointer;
private const String StrNewFileReadWriteMode = "wb+";
//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";
//Open for reading in binary mode. If the file does not exist, fopen( ) returns NULL
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+";
private String _fileName;
private Int32 _overallBytesCtr;
@@ -55,7 +60,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
/// Wildcard for search all.
/// </summary>
public const Char WildcardAll = '*';
// public const String StrWildcardAll = "*";
// public const String StrWildcardAll = "*";
/// <summary>
/// Processed bytes counter
@@ -171,6 +176,9 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
/// <remarks date="2020-Dec-19" author="Thomas Wiedebusch">
/// - Dynamic timeout load from extended to extreme timeout on retries.
/// </remarks>
/// <remarks date="2022-Apr-01" author="Thomas Wiedebusch">
/// - Add a NULL at the end of the file name.
/// </remarks>
public Boolean WriteMeterFile(String fileName, Byte[] dataBytes, Int32 fileOffset = 0)
{
var returnValue = false;
@@ -181,8 +189,11 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
OnProcessUpdate?.Invoke(this, new ProcessExecEventArgs("", 0));
_overallBytesCtr = dataBytes.Length;
//add file name delimiter
fileName += StringDelimiter;
//check if file is unlocked for write
if (_fileName != fileName) return false;
if (_fileName != fileName)
return false;
if (fileOffset == 0 && OpenMeterFile(fileName, StrNewFileReadWriteMode)
|| fileOffset > 0 && OpenMeterFile(fileName, StrOpenFileReadWriteMode))
@@ -319,12 +330,18 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
/// <remarks date="2020-Dec-10" author="Thomas Wiedebusch">
/// - Event on changed process counter.
/// </remarks>
/// <remarks date="2022-Apr-01" author="Thomas Wiedebusch">
/// - Add a NULL at the end of the file name.
/// </remarks>
public Boolean ReadMeterFile(String fileName, out List<Byte> readBackData, Int32 readBackCount)
{
//set processing counter
ProcessedBytesCtr = 0;
OnProcessUpdate?.Invoke(this, new ProcessExecEventArgs("", 0));
//add file name delimiter
fileName += StringDelimiter;
readBackData = new List<Byte>();
var returnValue = OpenMeterFile(fileName, StrOpenFileReadOnlyMode);
@@ -431,7 +448,8 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
_currentGenesis.ReadRegister(Register.Configexchange.Catalogue));
}
if (key == lastKey) break;
if (key == lastKey)
break;
// remove the "\0"
var strMeterFile = readData.Split(StringDelimiter);
// avoid identical files repetition
@@ -451,12 +469,19 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
/// <remarks date="2021-Jun-20" author="Thomas Wiedebusch">
/// - Initial
/// </remarks>
/// <remarks date="2022-Apr-01" author="Thomas Wiedebusch">
/// - Add a NULL at the end of the file name.
/// </remarks>
public Boolean CreateEmptyMeterFile(String fileName, Int32 fileSize = 0)
{
var returnValue = false;
//add file name delimiter
fileName += StringDelimiter;
//check if file is unlocked for write
if (_fileName != fileName) return false;
if (_fileName != fileName)
return false;
if (OpenMeterFile(fileName, StrNewFileReadWriteMode))
{
@@ -509,7 +534,8 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
_currentGenesis.TransmitProtocol.SetDefaultResponseTimeout();
CommunicationConfig.RequestRetries = CommunicationConfig.DefaultRequestRetries;
if (returnedFileOffset != fileSize) returnValue = false;
if (returnedFileOffset != fileSize)
returnValue = false;
}
}//file open
@@ -526,9 +552,16 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
/// <remarks date="2019-Jun-20" author="Thomas Wiedebusch">
/// - Initial
/// </remarks>
/// <remarks date="2022-Apr-01" author="Thomas Wiedebusch">
/// - Add a NULL at the end of the file name.
/// </remarks>
public Boolean VerifyMeterFile(String fileName, Byte[] dataBytes)
{
if (!OpenMeterFile(fileName, StrOpenFileReadOnlyMode)) return false;
//add file name delimiter
fileName += StringDelimiter;
if (!OpenMeterFile(fileName, StrOpenFileReadOnlyMode))
return false;
//TODO THW implement
//read raw data from meter
return true;
@@ -548,12 +581,19 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
/// <remarks date="2021-May-18" author="Thomas Wiedebusch">
/// - Removed retries to speed up erasure as it returns error code 0x040B.
/// </remarks>
/// <remarks date="2022-Apr-01" author="Thomas Wiedebusch">
/// - Add a NULL at the end of the file name.
/// </remarks>
public Boolean EraseMeterFile(String fileName)
{
//add file name delimiter
fileName += StringDelimiter;
//check if file is unlocked for erase
if (_fileName != fileName) return false;
if (_fileName != fileName)
return false;
//check if logged on to meter and access level is as expected
if (_currentGenesis == null || !_currentGenesis.IsLoggedOn) return false;
if (_currentGenesis == null || !_currentGenesis.IsLoggedOn)
return false;
//set extended timeout for file operations
_currentGenesis.TransmitProtocol.SetResponseTimeout(ExtendedFileIoTimeoutMs);
@@ -576,10 +616,16 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
/// <remarks date="2019-Jun-20" author="Thomas Wiedebusch">
/// - Initial
/// </remarks>
/// <remarks date="2022-Apr-01" author="Thomas Wiedebusch">
/// - Add a NULL at the end of the file name.
/// </remarks>
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 (_currentGenesis == null || !_currentGenesis.IsLoggedOn)
return false;
//remind file name being unlocked
_fileName = fileName;
return true;
@@ -713,7 +759,8 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
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;
if (_currentGenesis == null || !_currentGenesis.IsLoggedOn)
return false;
Boolean returnValue;
var retryCtr = 0;
@@ -773,25 +820,23 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
/// <remarks date="2020-Jan-22" author="Thomas Wiedebusch">
/// - Wait after writing for response before reading!
/// </remarks>
/// <remarks date="2022-Apr-01" author="Thomas Wiedebusch">
/// - Ignore file close write return!
/// </remarks>
private Boolean CloseMeterFile()
{
//avoid file close if file pointer assignment failed
if (_filePointer <= 0) return false;
if (_filePointer <= 0)
return false;
//set extended timeout for file operations
_currentGenesis.TransmitProtocol.SetResponseTimeout(ExtendedFileIoTimeoutMs);
CommunicationConfig.RequestRetries = 0;
_currentGenesis.WriteRegister(Register.Configexchange.FileClose, _filePointer);
var returnValue = _currentGenesis.WriteRegister(Register.Configexchange.FileClose,
_filePointer);
//the preceding routine needs to wait for response, else this is always true!
if (returnValue)
{
//function call returns 0 if FClose successfully executed
returnValue &= 0 == RegisterConverter.ConvertTo<Int32>(
_currentGenesis.ReadRegister(Register.Configexchange.FileClose));
}
//function call returns 0 if FClose successfully executed
var returnValue = 0 == RegisterConverter.ConvertTo<Int32>(
_currentGenesis.ReadRegister(Register.Configexchange.FileClose));
//set timeout back to default value
_currentGenesis.TransmitProtocol.SetDefaultResponseTimeout();
CommunicationConfig.RequestRetries = CommunicationConfig.DefaultRequestRetries;
@@ -679,7 +679,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
_meterFilesDrive1 = new List<String>();
}
_meterFilesDrive1.Clear();
Thread.Sleep(500);
Thread.Sleep(2000);
OnProcessUpdate?.Invoke(this, new ProcessExecEventArgs("Read meter files drive 1"));
if (!_meterFile.ReadMeterFileCatalog(out var meterFilesDrive1, MeterFile.StrMeterDrive1,
@@ -703,16 +703,13 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
/// <remarks date="2022-Mar-04" author="Thomas Wiedebusch">
/// - Initial
/// </remarks>
private Boolean EraseFile(String fileDriveName)
private Boolean EraseFileAndVerifyErasure(String fileDriveName)
{
OnProcessUpdate?.Invoke(this, new ProcessExecEventArgs($"Erasing {fileDriveName}"));
var returnValue = _meterFile.UnlockEraseWriteMeterFile(fileDriveName);
// erase returns always TRUE, even if the erasure failed! Check with catalogue
_meterFile.EraseMeterFile(fileDriveName);
// give the meter a certain time to erase
Thread.Sleep(500);
if (ReadMeterFilesDrive1())
{
if (_meterFilesDrive1.Contains(fileDriveName))
@@ -774,7 +771,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
_operationCtr++;
_actualOperation = $"Erase {fileToErase}";
if (EraseFile(fileToErase))
if (EraseFileAndVerifyErasure(fileToErase))
{
ErrorMessage = "";
continue;
@@ -830,7 +827,6 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
ReestablishMeterFileSystem();
_meterFile.UnlockEraseWriteMeterFile(fileToDownload);
Thread.Sleep(500);
var txt = $"{fileToDownload} successfully written";
if (_meterFile.WriteMeterFile(fileToDownload, LutFile.BinData.ToArray()))
{
@@ -889,6 +885,9 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
/// <remarks date="2022-Mar-04" author="Thomas Wiedebusch">
/// - Initial
/// </remarks>
/// <remarks date="2022-Apr-01" author="Thomas Wiedebusch">
/// - Take the different size of original and receive buffer, which is an integer division by 4, into account.
/// </remarks>
private Boolean UploadAndCompareLutFiles()
{
//counters for actual process information
@@ -915,26 +914,30 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
if (_meterFile.ReadMeterFile(fileToUpload, out var binData, SizeLutFile))
{
// compare the entire buffer which also includes the header of the file
if (!binData.SequenceEqual(LutFile.BinData))
// compare the entire buffer which also includes the header of the file, remind the original
// buffer may be smaller due to the chunk size of the communication (always dividable by 4),
// meaning the receive buffer is always and integer of this chunk size!
if (LutFile.BinData.Where((t, ctr) => t != binData[ctr]).Any())
{
ErrorMessage = $"Meter LUT file is unequal to downloaded {fileToUpload}!";
returnValue = false;
_operationCtr--;
}
else
if (returnValue)
{
OnProcessUpdate?.Invoke(this,
OnProcessUpdate?.Invoke(this,
new ProcessExecEventArgs($"LUT file {fileToUpload} of meter successfully compared!"));
}
continue;
}
else
{
ErrorMessage += $"Reading of {fileToUpload} failed!";
returnValue = false;
_operationCtr--;
ErrorMessage += $"Reading of {fileToUpload} failed!";
returnValue = false;
_operationCtr--;
}
}
if (!returnValue)
@@ -88,6 +88,16 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.Registers
{
var reg = GetRegisterDefinitionByName(register);
if (!MeterRegisterDic.ContainsKey(reg)) return null;
if (MeterRegisterDic.Count(f => f.Key.GetIdent() == register) > 1)
{
if (MeterRegisterDic.Any(f => f.Key.GetIdent() == register && f.Value != null))
{
var regDs = MeterRegisterDic.Last(f => f.Key.GetIdent() == register && f.Value != null);
return regDs.Value;
}
}
var regD = MeterRegisterDic.First(f => f.Key.GetIdent() == register);
return regD.Value;
}