diff --git a/Common/.vs/config/applicationhost.config b/Common/.vs/config/applicationhost.config index ebc79eca..1b9332b4 100644 --- a/Common/.vs/config/applicationhost.config +++ b/Common/.vs/config/applicationhost.config @@ -155,7 +155,7 @@ - + diff --git a/Common/Common.sln.DotSettings b/Common/Common.sln.DotSettings index eded7968..588a89aa 100644 --- a/Common/Common.sln.DotSettings +++ b/Common/Common.sln.DotSettings @@ -18,6 +18,7 @@ True True True + True True True True diff --git a/Common/Hardware/Interfaces/Protocols/TransmitProtocol/UartTransmitProtocol.cs b/Common/Hardware/Interfaces/Protocols/TransmitProtocol/UartTransmitProtocol.cs index 12ef54f8..d7ac86d3 100644 --- a/Common/Hardware/Interfaces/Protocols/TransmitProtocol/UartTransmitProtocol.cs +++ b/Common/Hardware/Interfaces/Protocols/TransmitProtocol/UartTransmitProtocol.cs @@ -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 diff --git a/Common/Hardware/WaterMeter/Genesis/GenesisFile/Consts/FwUpdateState.cs b/Common/Hardware/WaterMeter/Genesis/GenesisFile/Consts/FwUpdateState.cs index 0adee651..5db4099a 100644 --- a/Common/Hardware/WaterMeter/Genesis/GenesisFile/Consts/FwUpdateState.cs +++ b/Common/Hardware/WaterMeter/Genesis/GenesisFile/Consts/FwUpdateState.cs @@ -22,6 +22,10 @@ /// StartInitial, /// + /// Erase test file as this reserves space for update over the air + /// + EraseTstFile, + /// /// Repeat FW update /// RepeatFwUpdate, diff --git a/Common/Hardware/WaterMeter/Genesis/GenesisFile/Consts/FwUpdateStateInfo.cs b/Common/Hardware/WaterMeter/Genesis/GenesisFile/Consts/FwUpdateStateInfo.cs index d6cf07e1..6ae3570a 100644 --- a/Common/Hardware/WaterMeter/Genesis/GenesisFile/Consts/FwUpdateStateInfo.cs +++ b/Common/Hardware/WaterMeter/Genesis/GenesisFile/Consts/FwUpdateStateInfo.cs @@ -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; diff --git a/Common/Hardware/WaterMeter/Genesis/GenesisFile/MeterFile.cs b/Common/Hardware/WaterMeter/Genesis/GenesisFile/MeterFile.cs index 2a7eec25..64eda829 100644 --- a/Common/Hardware/WaterMeter/Genesis/GenesisFile/MeterFile.cs +++ b/Common/Hardware/WaterMeter/Genesis/GenesisFile/MeterFile.cs @@ -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+"; /// /// FSeek for start of file @@ -57,6 +59,11 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile /// public const String StrMeterConfigFile = "0\\config"; + /// + /// The test file is for SENSUSRADIO as placeholder for update over the air. + /// + public const String StrMeterTstFile = "1\\tstfile"; + /// /// Engineering log index file of meter. /// @@ -80,7 +87,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile /// /// Wildcard for search all. /// - public const Char WildcardAll = '*'; + public const String WildcardAll = "*"; /// /// Processed bytes counter @@ -199,10 +206,17 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile /// /// - Add a NULL at the end of the file name. /// + /// + /// - Adapted to new ReadFilePointerOffset. + /// + /// + /// - Combined FOpen to one file open function, + /// - Using for multiple write access to register instead of 3 writes. + /// 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(); - dataByteList.AddRange(dataBytes); - var dataChunk = new List(); - 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( - _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(); + dataByteList.AddRange(dataBytes); + var dataChunk = new List(); + 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( + _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; } + /// + /// 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. + /// + /// + /// + /// + /// file content as byte array + /// + /// - Initial + /// + public static Byte[] BuildRpcInt32(Int32 first, Int32 second, Int32 last) + { + var rpc = new List(); + rpc.AddRange(BitConverter.GetBytes(first)); + rpc.AddRange(BitConverter.GetBytes(second)); + rpc.AddRange(BitConverter.GetBytes(last)); + return rpc.ToArray(); + } + /// /// Read file from the meter /// @@ -353,6 +397,16 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile /// /// - Speed up FOpen as read is not so critical. /// + /// + /// - Avoid reading of file size from FSeek is 0. + /// + /// + /// - Removed extended timeout. + /// + /// + /// - FClose added on failed GetFileSizeInternal. + /// - Using for multiple write access to register instead of 3 writes. + /// public Boolean ReadMeterFile(String fileName, out List 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(); - // 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( + _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( - _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(); } /// @@ -441,10 +495,13 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile /// /// - Default wildcard. /// - public Boolean ReadMeterFileCatalog(out List files, String drive, Char wildcard = WildcardAll) + public Boolean ReadMeterFileCatalog(out List files, String drive, String wildcard = WildcardAll) { files = new List(); + //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 /// /// - Add a NULL at the end of the file name. /// + /// + /// - Adapted to new ReadFilePointerOffset. + /// + /// + /// - Using for multiple write access to register instead of 3 writes. + /// 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; + + //exit immediately if file cannot be opened + if (!OpenMeterFile(fileName, StrNewFileReadWriteMode)) + return false; - if (OpenMeterFile(fileName, StrNewFileReadWriteMode)) + 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( + _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( - _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; } /// - /// Uses FSeek to get the file size. + /// Read the file size. /// /// file name as string /// file size of the given file - /// true: file found + /// true: file size could be read /// /// - Initial /// + /// + /// - Modified returns. + /// 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; } + /// + /// 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!!!!! + /// + /// file name as string + /// file size of the given file + /// true: file found + /// + /// - Initial + /// + 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; + } + /// /// 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 /// /// - Changed return value to false, if file could not be read. /// + /// + /// - Compare byte by byte until length of given buffer, as the returned buffer is always filled + /// up to the chunk size of 4. + /// 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 /// /// - Add a NULL at the end of the file name. /// + /// + /// - Removed extended timeout. + /// 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; } /// - /// 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. /// /// @@ -723,6 +829,12 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile /// /// - Extended FSeek for file end positioning. /// + /// + /// - Removed extended timeout. + /// + /// + /// - Using for multiple write access to register instead of 3 writes. + /// 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(_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. /// - private Int32 ReadFilePointerOffset() + /// + /// - Modified for return. + /// + /// + /// - Removed extended timeout. + /// + 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(_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; } /// @@ -822,7 +933,6 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile /// /// /// read, write eg, - /// disable high timeouts /// true if filePointer higher than zero /// /// - Initial @@ -838,48 +948,79 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile /// /// - Extended timings removed if high speed is active. /// - private Boolean OpenMeterFile(String fileName, String accessMode, Boolean highSpeed = false) + /// + /// - Removed retry dummy read. + /// + /// + /// - Removed extended timeout. + /// + /// + /// - 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. + /// + 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(); + 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) + //if (retryCtr > 0) + //{ + // //read DUMMY to overcome FW malfunction + // _currentGenesis.ReadRegister(Register.System.MonotonicSeconds); + // Thread.Sleep(1000); + //} + + //write file name to meter with meter open command, don't wait for response + var rpcString = new String(rpc.ToArray()); + rpcString += accessMode; + + // wait for response! + retValue = _currentGenesis.WriteRegister(Register.Configexchange.FileOpen, rpcString, false); + + ////write file name to meter with meter open command, don't wait for response + //retValue = _currentGenesis.WriteRegister(Register.Configexchange.FileOpen, fileName, false); + ////write access flag + //retValue &= _currentGenesis.WriteRegister(Register.Configexchange.FileOpen, accessMode, false); + + if (retValue) { - //read DUMMY to overcome FW malfunction - //_currentGenesis.ReadRegister(Register.Genesisflow.LedMode); - _currentGenesis.ReadRegister(Register.System.MonotonicSeconds); - Thread.Sleep(1000); + //get the file pointer + _filePointer = RegisterConverter.ConvertTo(_currentGenesis.ReadRegister( + Register.Configexchange.FileOpen)); } - //set extended timeout for file operations - if (highSpeed) - _currentGenesis.TransmitProtocol.SetResponseTimeout(ExtendedFileIoTimeoutMs); - CommunicationConfig.RequestRetries = 0; + } while ((_filePointer <= 0 || retValue == false) && retryCtr++ < CommandWriteRetries); - //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); + //set retries back to default value + CommunicationConfig.RequestRetries = CommunicationConfig.DefaultRequestRetries; - //get the file pointer - _filePointer = RegisterConverter.ConvertTo(_currentGenesis.ReadRegister( - Register.Configexchange.FileOpen)); - - //set timeout back to default value - _currentGenesis.TransmitProtocol.SetDefaultResponseTimeout(); - CommunicationConfig.RequestRetries = CommunicationConfig.DefaultRequestRetries; - - returnValue = 0 < _filePointer; - - } while (!returnValue && retryCtr++ < CommandWriteRetries); - - return returnValue; + return _filePointer > 0 && retValue; } /// @@ -910,26 +1051,41 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile /// /// - Removed extended timeout. /// + /// + /// - FClose retries. + /// 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( - _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( + _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; } - } } \ No newline at end of file diff --git a/Common/Hardware/WaterMeter/Genesis/GenesisFile/MeterFwUpdate.cs b/Common/Hardware/WaterMeter/Genesis/GenesisFile/MeterFwUpdate.cs index 45e10074..57a18ed3 100644 --- a/Common/Hardware/WaterMeter/Genesis/GenesisFile/MeterFwUpdate.cs +++ b/Common/Hardware/WaterMeter/Genesis/GenesisFile/MeterFwUpdate.cs @@ -98,11 +98,17 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile /// /// Core revision minimum as int32? with major * 100 + minor for comparison /// - public Int32? CoreRevisionMinimum { get; private set; } + public Int32? CoreRevisionMinimum + { + get; private set; + } /// /// Core revision maximum as int32? with major * 100 + minor for comparison /// - public Int32? CoreRevisionMaximum { get; private set; } + public Int32? CoreRevisionMaximum + { + get; private set; + } //reminder for the core minimum requirement as string private String _strCoreRevisionMinimum; @@ -635,7 +641,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile /// - Initial /// public String GetActualOperation() => _actualOperation; - + /// /// Returns the FW Update state /// @@ -1113,6 +1119,9 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile /// /// - Upload config file removed. /// + /// + /// - Erase test file introduced. + /// 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 } } + /// + /// 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. + /// + /// + /// + /// - Initial + /// + 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); + } + } + /// /// Download and result handling for update files /// diff --git a/Common/Hardware/WaterMeter/Genesis/GenesisFile/Properties/Resources.Designer.cs b/Common/Hardware/WaterMeter/Genesis/GenesisFile/Properties/Resources.Designer.cs index 3bb58940..d08a31f0 100644 --- a/Common/Hardware/WaterMeter/Genesis/GenesisFile/Properties/Resources.Designer.cs +++ b/Common/Hardware/WaterMeter/Genesis/GenesisFile/Properties/Resources.Designer.cs @@ -60,6 +60,15 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile.Properties { } } + /// + /// Looks up a localized string similar to Erase test file. + /// + public static string StrEraseTstFile { + get { + return ResourceManager.GetString("StrEraseTstFile", resourceCulture); + } + } + /// /// Looks up a localized string similar to Build Update Files. /// diff --git a/Common/Hardware/WaterMeter/Genesis/GenesisFile/Properties/Resources.de.resx b/Common/Hardware/WaterMeter/Genesis/GenesisFile/Properties/Resources.de.resx index 29e6c483..98af0467 100644 --- a/Common/Hardware/WaterMeter/Genesis/GenesisFile/Properties/Resources.de.resx +++ b/Common/Hardware/WaterMeter/Genesis/GenesisFile/Properties/Resources.de.resx @@ -186,4 +186,7 @@ Lade Einstellungen + + Lösche Testdatei + \ No newline at end of file diff --git a/Common/Hardware/WaterMeter/Genesis/GenesisFile/Properties/Resources.resx b/Common/Hardware/WaterMeter/Genesis/GenesisFile/Properties/Resources.resx index ddfa14c6..8491c106 100644 --- a/Common/Hardware/WaterMeter/Genesis/GenesisFile/Properties/Resources.resx +++ b/Common/Hardware/WaterMeter/Genesis/GenesisFile/Properties/Resources.resx @@ -156,7 +156,7 @@ Upload Update Files - + Waiting.... @@ -186,4 +186,7 @@ Upload configuration file + + Erase test file + \ No newline at end of file diff --git a/Common/Tools/Tools.JsonToXlsHelper/obj/Debug/Tools.JsonToXlsHelper.csproj.CoreCompileInputs.cache b/Common/Tools/Tools.JsonToXlsHelper/obj/Debug/Tools.JsonToXlsHelper.csproj.CoreCompileInputs.cache index 2634cdb8..0028f628 100644 --- a/Common/Tools/Tools.JsonToXlsHelper/obj/Debug/Tools.JsonToXlsHelper.csproj.CoreCompileInputs.cache +++ b/Common/Tools/Tools.JsonToXlsHelper/obj/Debug/Tools.JsonToXlsHelper.csproj.CoreCompileInputs.cache @@ -1 +1 @@ -81d60b90addc793525740e9993e19bf6665bd401 +f64d563def603c89cafafa61a3219ba97e1e344c diff --git a/Common/Ui/GenesisToolBox/FrmFwUpdate.Designer.cs b/Common/Ui/GenesisToolBox/FrmFwUpdate.Designer.cs index e7fb4a55..22a98395 100644 --- a/Common/Ui/GenesisToolBox/FrmFwUpdate.Designer.cs +++ b/Common/Ui/GenesisToolBox/FrmFwUpdate.Designer.cs @@ -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); // diff --git a/Common/Ui/GenesisToolBox/FrmLowLevelTools.cs b/Common/Ui/GenesisToolBox/FrmLowLevelTools.cs index aa348cf5..a07345a8 100644 --- a/Common/Ui/GenesisToolBox/FrmLowLevelTools.cs +++ b/Common/Ui/GenesisToolBox/FrmLowLevelTools.cs @@ -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(_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( + _currentGenesis.ReadRegister("SYSTEM_CalendarSeconds"))); //add a blank line to separate next operation LogText(""); _currentGenesis.Logout(); } + /// + /// Calculate and log Cordonel time. + /// + /// + /// - Init. + /// + 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}"); + } + /// /// Clear history window. /// @@ -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(); if (File.Exists("Status.json")) { var dict = JsonConvert.DeserializeObject>(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( + _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); + }); } /// @@ -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); }); diff --git a/ServiceFwUpdate/Ui/ServiceFwUpdateSw/FrmServiceFwUpdateSw.cs b/ServiceFwUpdate/Ui/ServiceFwUpdateSw/FrmServiceFwUpdateSw.cs index 3f9a62b7..5b7c0911 100644 --- a/ServiceFwUpdate/Ui/ServiceFwUpdateSw/FrmServiceFwUpdateSw.cs +++ b/ServiceFwUpdate/Ui/ServiceFwUpdateSw/FrmServiceFwUpdateSw.cs @@ -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]); }