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:
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user