2021-10-01 09:09:20 +00:00
|
|
|
|
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;
|
|
|
|
|
|
using Xylem.Common.Utils.ProcessExec;
|
|
|
|
|
|
using Xylem.Common.Utils.ProcessExec.EventArguments;
|
|
|
|
|
|
|
|
|
|
|
|
namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
|
|
|
|
|
|
{
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Genesis meter file operations
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public class MeterFile : IProcessState
|
|
|
|
|
|
{
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Port scan result event for message dispatcher to caller
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public event EventHandler<ProcessExecEventArgs> OnProcessUpdate;
|
|
|
|
|
|
|
|
|
|
|
|
//the raw data size is limited by the meter input buffer size, removed protocol length
|
|
|
|
|
|
private const Int32 MaxRawDataSize = 56;
|
|
|
|
|
|
private const Int32 ExtremeFileWriteTimeoutMs = 30000;
|
|
|
|
|
|
private const Int32 ExtendedFileIoTimeoutMs = 5000;
|
|
|
|
|
|
private const Int32 CommandWriteRetries = 2;
|
|
|
|
|
|
//timeout value loaded dynamically starting with extended timeout, on retry to extreme timeout
|
|
|
|
|
|
private Int32 _fileWriteTimeOutMs = ExtendedFileIoTimeoutMs;
|
|
|
|
|
|
|
|
|
|
|
|
private readonly GenesisMeter _currentGenesis;
|
2022-04-06 08:42:16 +00:00
|
|
|
|
public Int32 _filePointer;
|
2021-10-01 09:09:20 +00:00
|
|
|
|
private const String StrNewFileReadWriteMode = "wb+";
|
|
|
|
|
|
private const String StrOpenFileReadOnlyMode = "rb";
|
|
|
|
|
|
private const String StrOpenFileReadWriteMode = "rb+";
|
|
|
|
|
|
private String _fileName;
|
|
|
|
|
|
private Int32 _overallBytesCtr;
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Drive zero of meter.
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public const String StrMeterDrive0 = "0\\";
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Drive one of meter.
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public const String StrMeterDrive1 = "1\\";
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// String delimiter of files from Genesis.
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public const Char StringDelimiter = '\0';
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Wildcard for search all.
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public const Char WildcardAll = '*';
|
|
|
|
|
|
// public const String StrWildcardAll = "*";
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Processed bytes counter
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public Int32 ProcessedBytesCtr;
|
|
|
|
|
|
|
|
|
|
|
|
private Boolean _stopProcess;
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Increase timeout to extreme value
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <remarks date="2020-Dec-19" author="Thomas Wiedebusch">
|
|
|
|
|
|
/// - Timeout decreased to speed up stop operation.
|
|
|
|
|
|
/// </remarks>
|
|
|
|
|
|
public void SetExtremeFileWriteTimeout()
|
|
|
|
|
|
{
|
|
|
|
|
|
_fileWriteTimeOutMs = ExtremeFileWriteTimeoutMs;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Set timeout back to default timeout
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <remarks date="2020-Dec-19" author="Thomas Wiedebusch">
|
|
|
|
|
|
/// - Timeout decreased to speed up stop operation.
|
|
|
|
|
|
/// </remarks>
|
|
|
|
|
|
public void SetDefaultFileWriteTimeout()
|
|
|
|
|
|
{
|
|
|
|
|
|
_fileWriteTimeOutMs = ExtendedFileIoTimeoutMs;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Stop process
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <remarks date="2020-Dec-17" author="Thomas Wiedebusch">
|
|
|
|
|
|
/// - Timeout decreased to speed up stop operation.
|
|
|
|
|
|
/// </remarks>
|
|
|
|
|
|
public Boolean StopProcess
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _stopProcess;
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
_currentGenesis?.TransmitProtocol.SetDefaultResponseTimeout();
|
|
|
|
|
|
_stopProcess = value;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Ctor for genesis meter file operations
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="genesisMeter"></param>
|
|
|
|
|
|
/// <remarks date="2019-Jun-20" author="Thomas Wiedebusch">
|
|
|
|
|
|
/// - Initial
|
|
|
|
|
|
/// </remarks>
|
|
|
|
|
|
/// <remarks date="2019-Jun-27" author="Thomas Wiedebusch">
|
|
|
|
|
|
/// - Stop process added
|
|
|
|
|
|
/// </remarks>
|
|
|
|
|
|
public MeterFile(GenesisMeter genesisMeter)
|
|
|
|
|
|
{
|
|
|
|
|
|
_currentGenesis = genesisMeter;
|
|
|
|
|
|
_fileName = "";
|
|
|
|
|
|
_stopProcess = false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Process counter in percent
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <remarks date="2019-Jun-24" author="Thomas Wiedebusch">
|
|
|
|
|
|
/// - Initial
|
|
|
|
|
|
/// </remarks>
|
|
|
|
|
|
public Double ProcessCtrPercent => 100.0 * ProcessedBytesCtr / (_overallBytesCtr > 0 ? _overallBytesCtr : 1);
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Writing a file to the meter
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="fileName">file name as string</param>
|
|
|
|
|
|
/// <param name="dataBytes">data to store</param>
|
|
|
|
|
|
/// <param name="fileOffset">for partial file write procedures this is the offset to the file pointer</param>
|
|
|
|
|
|
/// <returns>true, if file can be find and stored and, if required, read back and verified</returns>
|
|
|
|
|
|
/// <remarks date="2019-Jun-20" author="Thomas Wiedebusch">
|
|
|
|
|
|
/// - Initial
|
|
|
|
|
|
/// </remarks>
|
|
|
|
|
|
/// <remarks date="2019-Jun-22" author="Thomas Wiedebusch">
|
|
|
|
|
|
/// - Early return on failed communication
|
|
|
|
|
|
/// </remarks>
|
|
|
|
|
|
/// <remarks date="2019-Jun-24" author="Thomas Wiedebusch">
|
|
|
|
|
|
/// - Added overall bytes counter for single file processing information
|
|
|
|
|
|
/// </remarks>
|
|
|
|
|
|
/// <remarks date="2019-Jun-27" author="Thomas Wiedebusch">
|
|
|
|
|
|
/// - Stop process added
|
|
|
|
|
|
/// </remarks>
|
|
|
|
|
|
/// <remarks date="2019-Jul-01" author="Thomas Wiedebusch">
|
|
|
|
|
|
/// - CHeck if file exists
|
|
|
|
|
|
/// </remarks>
|
|
|
|
|
|
/// <remarks date="2019-Nov-29" author="Thomas Wiedebusch">
|
|
|
|
|
|
/// - Extended response timeout
|
|
|
|
|
|
/// </remarks>
|
|
|
|
|
|
/// <remarks date="2019-Dec-02/03" author="Thomas Wiedebusch">
|
|
|
|
|
|
/// - Register read/write retry 0 implemented.
|
|
|
|
|
|
/// </remarks>
|
|
|
|
|
|
/// <remarks date="2019-Dec-12" author="Thomas Wiedebusch">
|
|
|
|
|
|
/// - Stop FWrite if FWrite failed,
|
|
|
|
|
|
/// - FClose if FWrite failed,
|
|
|
|
|
|
/// - avoid FTell if FWrite failed
|
|
|
|
|
|
/// </remarks>
|
|
|
|
|
|
/// <remarks date="2020-Jan-17" author="Thomas Wiedebusch">
|
|
|
|
|
|
/// - Retries changed for and back on different position,
|
|
|
|
|
|
/// - Timeout changed for and back on different position,
|
|
|
|
|
|
/// - Dummy read removed.
|
|
|
|
|
|
/// </remarks>
|
|
|
|
|
|
/// <remarks date="2020-Dec-10" author="Thomas Wiedebusch">
|
|
|
|
|
|
/// - Event on changed process counter.
|
|
|
|
|
|
/// </remarks>
|
|
|
|
|
|
/// <remarks date="2020-Dec-19" author="Thomas Wiedebusch">
|
|
|
|
|
|
/// - Dynamic timeout load from extended to extreme timeout on retries.
|
|
|
|
|
|
/// </remarks>
|
|
|
|
|
|
public Boolean WriteMeterFile(String fileName, Byte[] dataBytes, Int32 fileOffset = 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
var returnValue = false;
|
|
|
|
|
|
|
|
|
|
|
|
//set processing counter
|
|
|
|
|
|
ProcessedBytesCtr = 0;
|
|
|
|
|
|
//inform the caller of changed statue
|
|
|
|
|
|
OnProcessUpdate?.Invoke(this, new ProcessExecEventArgs("", 0));
|
|
|
|
|
|
_overallBytesCtr = dataBytes.Length;
|
|
|
|
|
|
|
|
|
|
|
|
//check if file is unlocked for write
|
|
|
|
|
|
if (_fileName != fileName) return false;
|
|
|
|
|
|
|
|
|
|
|
|
if (fileOffset == 0 && OpenMeterFile(fileName, StrNewFileReadWriteMode)
|
|
|
|
|
|
|| fileOffset > 0 && OpenMeterFile(fileName, StrOpenFileReadWriteMode))
|
|
|
|
|
|
{
|
|
|
|
|
|
returnValue = true;
|
|
|
|
|
|
|
|
|
|
|
|
//adjust file pointer if offset is required
|
|
|
|
|
|
if (fileOffset > 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
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();
|
|
|
|
|
|
}
|
|
|
|
|
|
//else
|
|
|
|
|
|
//{
|
|
|
|
|
|
// //read DUMMY to overcome FW malfunction
|
|
|
|
|
|
// _currentGenesis.ReadRegister(Register.System.MonotonicSeconds);
|
|
|
|
|
|
//}
|
|
|
|
|
|
|
|
|
|
|
|
//set timeout back to default value
|
|
|
|
|
|
_currentGenesis.TransmitProtocol.SetDefaultResponseTimeout();
|
|
|
|
|
|
CommunicationConfig.RequestRetries = CommunicationConfig.DefaultRequestRetries;
|
|
|
|
|
|
|
|
|
|
|
|
if (writtenBytes != ProcessedBytesCtr || returnedFileOffset != fileOffset + writtenBytes)
|
|
|
|
|
|
returnValue = false;
|
|
|
|
|
|
}
|
|
|
|
|
|
}//file open
|
|
|
|
|
|
|
|
|
|
|
|
returnValue &= CloseMeterFile();
|
|
|
|
|
|
|
|
|
|
|
|
//processed bytes not longer needed
|
|
|
|
|
|
OnProcessUpdate?.Invoke(this, new ProcessExecEventArgs("", 0));
|
|
|
|
|
|
ProcessedBytesCtr = 0;
|
|
|
|
|
|
_overallBytesCtr = 0;
|
|
|
|
|
|
|
|
|
|
|
|
return returnValue;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Read file from the meter
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="fileName">file name as string</param>
|
|
|
|
|
|
/// <param name="readBackData">empty list of data</param>
|
|
|
|
|
|
/// <param name="readBackCount">size to read</param>
|
|
|
|
|
|
/// <returns>file content as byte array</returns>
|
|
|
|
|
|
/// <remarks date="2019-Jun-20" author="Thomas Wiedebusch">
|
|
|
|
|
|
/// - Initial
|
|
|
|
|
|
/// </remarks>
|
|
|
|
|
|
/// <remarks date="2019-Jun-27" author="Thomas Wiedebusch">
|
|
|
|
|
|
/// - Stop process added
|
|
|
|
|
|
/// </remarks>
|
|
|
|
|
|
/// <remarks date="2019-Nov-30" author="Thomas Wiedebusch">
|
|
|
|
|
|
/// - Register read/write retry 0 implemented,
|
|
|
|
|
|
/// - Extended communication timeout
|
|
|
|
|
|
/// </remarks>
|
|
|
|
|
|
/// <remarks date="2019-Dec-02/03/05" author="Thomas Wiedebusch">
|
|
|
|
|
|
/// - Command write retry 0 implemented,
|
|
|
|
|
|
/// - Extended timeout.
|
|
|
|
|
|
/// </remarks>
|
|
|
|
|
|
/// <remarks date="2020-Jan-17" author="Thomas Wiedebusch">
|
|
|
|
|
|
/// - Retries changed for and back,
|
|
|
|
|
|
/// - Timeout changed for and back,
|
|
|
|
|
|
/// - Dummy read removed.
|
|
|
|
|
|
/// </remarks>
|
|
|
|
|
|
/// <remarks date="2020-Jan-22" author="Thomas Wiedebusch">
|
|
|
|
|
|
/// - Wait after writing for response before reading!
|
|
|
|
|
|
/// </remarks>
|
|
|
|
|
|
/// <remarks date="2020-Sep-21" author="Thomas Wiedebusch">
|
|
|
|
|
|
/// - Check remaining size to abort operation.
|
|
|
|
|
|
/// </remarks>
|
|
|
|
|
|
/// <remarks date="2020-Dec-10" author="Thomas Wiedebusch">
|
|
|
|
|
|
/// - Event on changed process counter.
|
|
|
|
|
|
/// </remarks>
|
2022-04-06 08:42:16 +00:00
|
|
|
|
public Boolean ReadMeterFile(String fileName, out List<Byte> readBackData, Int32? readBackCount = null, string OpenFileReadOnlyModeOver = null)
|
2021-10-01 09:09:20 +00:00
|
|
|
|
{
|
2022-04-06 08:42:16 +00:00
|
|
|
|
if (String.IsNullOrEmpty(OpenFileReadOnlyModeOver))
|
|
|
|
|
|
{
|
|
|
|
|
|
OpenFileReadOnlyModeOver = StrOpenFileReadOnlyMode;
|
|
|
|
|
|
}
|
2021-10-01 09:09:20 +00:00
|
|
|
|
//set processing counter
|
|
|
|
|
|
ProcessedBytesCtr = 0;
|
|
|
|
|
|
OnProcessUpdate?.Invoke(this, new ProcessExecEventArgs("", 0));
|
|
|
|
|
|
|
|
|
|
|
|
readBackData = new List<Byte>();
|
2022-04-06 08:42:16 +00:00
|
|
|
|
var returnValue = OpenMeterFile(fileName, OpenFileReadOnlyModeOver);
|
2021-10-01 09:09:20 +00:00
|
|
|
|
|
|
|
|
|
|
if (returnValue)
|
|
|
|
|
|
{
|
2022-04-06 08:42:16 +00:00
|
|
|
|
// optical.fseek(handle, 0, 2)
|
|
|
|
|
|
//numbytes = optical.ftell(handle)
|
|
|
|
|
|
//optical.fseek(handle, 0, 0)
|
|
|
|
|
|
|
|
|
|
|
|
|
2021-10-01 09:09:20 +00:00
|
|
|
|
//set register write retries to 0 to avoid doubling of records
|
|
|
|
|
|
CommunicationConfig.RequestRetries = 0;
|
|
|
|
|
|
_currentGenesis.TransmitProtocol.SetResponseTimeout(ExtendedFileIoTimeoutMs);
|
|
|
|
|
|
|
2022-04-06 08:42:16 +00:00
|
|
|
|
int fixedReadBackCount;
|
|
|
|
|
|
|
|
|
|
|
|
if (readBackCount.HasValue)
|
|
|
|
|
|
{
|
|
|
|
|
|
fixedReadBackCount = readBackCount.Value;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
_currentGenesis.WriteRegister("CONFIGEXCHANGE_FSeek", _filePointer, false);
|
|
|
|
|
|
_currentGenesis.WriteRegister("CONFIGEXCHANGE_FSeek", 0, false);
|
|
|
|
|
|
_currentGenesis.WriteRegister("CONFIGEXCHANGE_FSeek", 2, false);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
_currentGenesis.WriteRegister("CONFIGEXCHANGE_FTell", _filePointer, false);
|
|
|
|
|
|
fixedReadBackCount = RegisterConverter.ConvertTo<Int32>(_currentGenesis.ReadRegister("CONFIGEXCHANGE_FTell")) + 1;
|
|
|
|
|
|
|
|
|
|
|
|
_currentGenesis.WriteRegister("CONFIGEXCHANGE_FSeek", _filePointer, false);
|
|
|
|
|
|
_currentGenesis.WriteRegister("CONFIGEXCHANGE_FSeek", 0, false);
|
|
|
|
|
|
_currentGenesis.WriteRegister("CONFIGEXCHANGE_FSeek", 0, false);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
2021-10-01 09:09:20 +00:00
|
|
|
|
//write size to 1
|
|
|
|
|
|
_currentGenesis.WriteRegister(Register.Configexchange.FileRead, 1, false);
|
|
|
|
|
|
//write counts to expected length
|
2022-04-06 08:42:16 +00:00
|
|
|
|
_currentGenesis.WriteRegister(Register.Configexchange.FileRead, fixedReadBackCount, false);
|
2021-10-01 09:09:20 +00:00
|
|
|
|
//write file pointer
|
|
|
|
|
|
_currentGenesis.WriteRegister(Register.Configexchange.FileRead, _filePointer);
|
|
|
|
|
|
|
|
|
|
|
|
//the preceding routine needs to wait for response, else this is always true!
|
2022-04-06 08:42:16 +00:00
|
|
|
|
while (fixedReadBackCount > 0 && returnValue)
|
2021-10-01 09:09:20 +00:00
|
|
|
|
{
|
|
|
|
|
|
returnValue = _stopProcess;
|
|
|
|
|
|
|
|
|
|
|
|
var remainingData = RegisterConverter.ConvertTo<Int32>(
|
|
|
|
|
|
_currentGenesis.ReadRegister(Register.Configexchange.FileRead));
|
|
|
|
|
|
|
2022-04-06 08:42:16 +00:00
|
|
|
|
fixedReadBackCount = remainingData > 0 ? fixedReadBackCount - remainingData : 0;
|
2021-10-01 09:09:20 +00:00
|
|
|
|
|
|
|
|
|
|
while (remainingData > 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
var size = remainingData > MaxRawDataSize ? MaxRawDataSize : remainingData;
|
|
|
|
|
|
readBackData.AddRange(_currentGenesis.ReadRegister(Register.Configexchange.FileRead, size));
|
|
|
|
|
|
remainingData -= size;
|
|
|
|
|
|
|
|
|
|
|
|
//set processed bytes for read loop
|
|
|
|
|
|
ProcessedBytesCtr += size;
|
|
|
|
|
|
|
|
|
|
|
|
//inform the caller of changed statue
|
|
|
|
|
|
var processCtrPercent = 100.0 * ProcessedBytesCtr / (_overallBytesCtr > 0 ? _overallBytesCtr : 1);
|
|
|
|
|
|
OnProcessUpdate?.Invoke(this, new ProcessExecEventArgs("", processCtrPercent));
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//set timeout back to default value
|
|
|
|
|
|
_currentGenesis.TransmitProtocol.SetDefaultResponseTimeout();
|
|
|
|
|
|
CommunicationConfig.RequestRetries = CommunicationConfig.DefaultRequestRetries;
|
|
|
|
|
|
|
|
|
|
|
|
}//file open succeeded
|
|
|
|
|
|
|
|
|
|
|
|
//dummy read to avoid 0x040B feedback from meter
|
|
|
|
|
|
//_currentGenesis.ReadRegister(Register.Configexchange.FileRead, 1);
|
|
|
|
|
|
|
|
|
|
|
|
returnValue &= CloseMeterFile();
|
|
|
|
|
|
|
|
|
|
|
|
//processed bytes not longer needed
|
|
|
|
|
|
ProcessedBytesCtr = 0;
|
|
|
|
|
|
OnProcessUpdate?.Invoke(this, new ProcessExecEventArgs("", 0));
|
|
|
|
|
|
|
|
|
|
|
|
//read raw data from meter
|
|
|
|
|
|
return returnValue;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Read catalog of all meter files
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="files">file names as string</param>
|
|
|
|
|
|
/// <param name="drive">e.g. "1\\" for drive 1</param>
|
|
|
|
|
|
/// <param name="wildcard">e.g. "upd*" all upgrade files on drive</param>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
/// <remarks date="2021-Feb-16" author="Thomas Wiedebusch">
|
|
|
|
|
|
/// - Initial.
|
|
|
|
|
|
/// </remarks>
|
|
|
|
|
|
public Boolean ReadMeterFileCatalog(out List<String> files, String drive, String wildcard)
|
|
|
|
|
|
{
|
|
|
|
|
|
files = new List<String>();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//write the initial key
|
|
|
|
|
|
var key = 0;
|
|
|
|
|
|
_stopProcess = false;
|
|
|
|
|
|
|
|
|
|
|
|
// if both key are identical, the last file has been listed
|
|
|
|
|
|
while (!_stopProcess)
|
|
|
|
|
|
{
|
|
|
|
|
|
// remind entry key as this will be changed with the read back
|
|
|
|
|
|
var lastKey = key;
|
2022-04-06 08:42:16 +00:00
|
|
|
|
//\\logindex".format(drive)
|
|
|
|
|
|
var searchPattern = wildcard + drive;
|
2021-10-01 09:09:20 +00:00
|
|
|
|
_currentGenesis.WriteRegister(Register.Configexchange.Catalogue, searchPattern);
|
|
|
|
|
|
_currentGenesis.WriteRegister(Register.Configexchange.Catalogue, key);
|
|
|
|
|
|
|
|
|
|
|
|
// initial read
|
|
|
|
|
|
var readData = "";
|
|
|
|
|
|
String backupData;
|
|
|
|
|
|
|
|
|
|
|
|
do
|
|
|
|
|
|
{
|
|
|
|
|
|
backupData = readData;
|
|
|
|
|
|
readData += RegisterConverter.ConvertTo<String>(
|
|
|
|
|
|
_currentGenesis.ReadRegister(Register.Configexchange.Catalogue));
|
|
|
|
|
|
} while (!readData.Contains(StringDelimiter) && backupData != readData);
|
|
|
|
|
|
|
|
|
|
|
|
if (!string.IsNullOrEmpty(readData))
|
|
|
|
|
|
{
|
|
|
|
|
|
//read new key
|
|
|
|
|
|
key = RegisterConverter.ConvertTo<Int32>(
|
|
|
|
|
|
_currentGenesis.ReadRegister(Register.Configexchange.Catalogue));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (key == lastKey) break;
|
|
|
|
|
|
// remove the "\0"
|
|
|
|
|
|
var strMeterFile = readData.Split(StringDelimiter);
|
|
|
|
|
|
// avoid identical files repetition
|
|
|
|
|
|
var filePathName = drive + strMeterFile[0];
|
|
|
|
|
|
files.Add(filePathName);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return files.Count > 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Create an empty meter file as placeholder for space in the file system.
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="fileName">file name as string</param>
|
|
|
|
|
|
/// <param name="fileSize">the file size for the file pointer</param>
|
|
|
|
|
|
/// <returns>true, if file can be find and stored and, if required, read back and verified</returns>
|
|
|
|
|
|
/// <remarks date="2021-Jun-20" author="Thomas Wiedebusch">
|
|
|
|
|
|
/// - Initial
|
|
|
|
|
|
/// </remarks>
|
|
|
|
|
|
public Boolean CreateEmptyMeterFile(String fileName, Int32 fileSize = 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
var returnValue = false;
|
|
|
|
|
|
|
|
|
|
|
|
//check if file is unlocked for write
|
|
|
|
|
|
if (_fileName != fileName) return false;
|
|
|
|
|
|
|
|
|
|
|
|
if (OpenMeterFile(fileName, StrNewFileReadWriteMode))
|
|
|
|
|
|
{
|
|
|
|
|
|
returnValue = true;
|
|
|
|
|
|
|
|
|
|
|
|
//adjust file pointer if offset is required
|
|
|
|
|
|
if (fileSize > 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
// adjust file pointer to the end of file
|
|
|
|
|
|
returnValue = SetFilePointerOffset(fileSize - 1);
|
|
|
|
|
|
//read file pointer offset
|
|
|
|
|
|
returnValue &= (fileSize - 1) == 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 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();
|
|
|
|
|
|
}
|
|
|
|
|
|
//else
|
|
|
|
|
|
//{
|
|
|
|
|
|
// //read DUMMY to overcome FW malfunction
|
|
|
|
|
|
// _currentGenesis.ReadRegister(Register.System.MonotonicSeconds);
|
|
|
|
|
|
//}
|
|
|
|
|
|
|
|
|
|
|
|
//set timeout back to default value
|
|
|
|
|
|
_currentGenesis.TransmitProtocol.SetDefaultResponseTimeout();
|
|
|
|
|
|
CommunicationConfig.RequestRetries = CommunicationConfig.DefaultRequestRetries;
|
|
|
|
|
|
|
|
|
|
|
|
if (returnedFileOffset != fileSize) returnValue = false;
|
|
|
|
|
|
}
|
|
|
|
|
|
}//file open
|
|
|
|
|
|
|
|
|
|
|
|
returnValue &= CloseMeterFile();
|
|
|
|
|
|
return returnValue;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Meter file verification against given data
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="fileName">file name as string</param>
|
|
|
|
|
|
/// <param name="dataBytes">data to store</param>
|
|
|
|
|
|
/// <returns>true: file found and verified</returns>
|
|
|
|
|
|
/// <remarks date="2019-Jun-20" author="Thomas Wiedebusch">
|
|
|
|
|
|
/// - Initial
|
|
|
|
|
|
/// </remarks>
|
|
|
|
|
|
public Boolean VerifyMeterFile(String fileName, Byte[] dataBytes)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!OpenMeterFile(fileName, StrOpenFileReadOnlyMode)) return false;
|
|
|
|
|
|
//TODO THW implement
|
|
|
|
|
|
//read raw data from meter
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Erase file from the meter
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="fileName">file name as string</param>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
/// <remarks date="2019-Jun-20" author="Thomas Wiedebusch">
|
|
|
|
|
|
/// - Initial
|
|
|
|
|
|
/// </remarks>
|
|
|
|
|
|
/// <remarks date="2019-Dec-03" author="Thomas Wiedebusch">
|
|
|
|
|
|
/// - Extended timeout.
|
|
|
|
|
|
/// </remarks>
|
|
|
|
|
|
/// <remarks date="2021-May-18" author="Thomas Wiedebusch">
|
|
|
|
|
|
/// - Removed retries to speed up erasure as it returns error code 0x040B.
|
|
|
|
|
|
/// </remarks>
|
|
|
|
|
|
public Boolean EraseMeterFile(String fileName)
|
|
|
|
|
|
{
|
|
|
|
|
|
//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);
|
|
|
|
|
|
CommunicationConfig.RequestRetries = 0;
|
|
|
|
|
|
//write "remove-command" to meter, wait for result and read back (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;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Two stage unlock sequence for meter file write or erase access
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="fileName">file name as string</param>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
/// <remarks date="2019-Jun-20" author="Thomas Wiedebusch">
|
|
|
|
|
|
/// - Initial
|
|
|
|
|
|
/// </remarks>
|
|
|
|
|
|
public Boolean UnlockEraseWriteMeterFile(String fileName)
|
|
|
|
|
|
{
|
|
|
|
|
|
//check if logged on to meter and access level is as expected
|
|
|
|
|
|
if (_currentGenesis == null || !_currentGenesis.IsLoggedOn) return false;
|
|
|
|
|
|
//remind file name being unlocked
|
|
|
|
|
|
_fileName = fileName;
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// FSeek implementation of genesis meter
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="filePointerOffset"></param>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
/// <remarks date="2019-Jun-20" author="Thomas Wiedebusch">
|
|
|
|
|
|
/// - Initial
|
|
|
|
|
|
/// </remarks>
|
|
|
|
|
|
/// <remarks date="2019-Nov-30" author="Thomas Wiedebusch">
|
|
|
|
|
|
/// - Command write retry implemented.
|
|
|
|
|
|
/// </remarks>
|
|
|
|
|
|
/// <remarks date="2019-Dec-03" author="Thomas Wiedebusch">
|
|
|
|
|
|
/// - Extended timeout.
|
|
|
|
|
|
/// </remarks>
|
|
|
|
|
|
/// <remarks date="2020-Jan-17/18" author="Thomas Wiedebusch">
|
|
|
|
|
|
/// - Retries changed for and back,
|
|
|
|
|
|
/// - Timeout changed for and back.
|
|
|
|
|
|
/// </remarks>
|
|
|
|
|
|
private Boolean SetFilePointerOffset(Int32 filePointerOffset)
|
|
|
|
|
|
{
|
|
|
|
|
|
Boolean returnValue;
|
|
|
|
|
|
var retryCtr = 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;
|
|
|
|
|
|
|
|
|
|
|
|
returnValue = _currentGenesis.WriteRegister(Register.Configexchange.SetFilePointerOffset,
|
|
|
|
|
|
_filePointer, false);
|
|
|
|
|
|
returnValue &= _currentGenesis.WriteRegister(Register.Configexchange.SetFilePointerOffset,
|
|
|
|
|
|
filePointerOffset, false);
|
|
|
|
|
|
returnValue &= _currentGenesis.WriteRegister(Register.Configexchange.SetFilePointerOffset,
|
|
|
|
|
|
0, 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();
|
|
|
|
|
|
CommunicationConfig.RequestRetries = CommunicationConfig.DefaultRequestRetries;
|
|
|
|
|
|
} while (!returnValue && retryCtr++ < CommandWriteRetries);
|
|
|
|
|
|
|
|
|
|
|
|
return returnValue;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// FTell implementation
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <returns>file pointer offset</returns>
|
|
|
|
|
|
/// <remarks date="2019-Jun-20" author="Thomas Wiedebusch">
|
|
|
|
|
|
/// - Initial
|
|
|
|
|
|
/// </remarks>
|
|
|
|
|
|
/// <remarks date="2019-Nov-30" author="Thomas Wiedebusch">
|
|
|
|
|
|
/// - Command write retry implemented.
|
|
|
|
|
|
/// </remarks>
|
|
|
|
|
|
/// <remarks date="2019-Dec-03" author="Thomas Wiedebusch">
|
|
|
|
|
|
/// - Extended timeout.
|
|
|
|
|
|
/// </remarks>
|
|
|
|
|
|
/// <remarks date="2020-Jan-17/18" author="Thomas Wiedebusch">
|
|
|
|
|
|
/// - Retries changed for and back,
|
|
|
|
|
|
/// - Timeout changed for and back.
|
|
|
|
|
|
/// </remarks>
|
|
|
|
|
|
private Int32 ReadFilePointerOffset()
|
|
|
|
|
|
{
|
|
|
|
|
|
Boolean returnValue;
|
|
|
|
|
|
var retryCtr = 0;
|
|
|
|
|
|
Int32 filePointerOffset;
|
|
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
|
|
//read file pointer offset
|
|
|
|
|
|
returnValue = _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);
|
|
|
|
|
|
|
|
|
|
|
|
return filePointerOffset;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// FOpen implementation of genesis meter
|
|
|
|
|
|
/// Open a file of the meter and sets the file pointer
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="fileName"></param>
|
|
|
|
|
|
/// <param name="accessMode"></param>
|
|
|
|
|
|
/// <returns>true if filePointer higher than zero</returns>
|
|
|
|
|
|
/// <remarks date="2019-Jun-20" author="Thomas Wiedebusch">
|
|
|
|
|
|
/// - Initial
|
|
|
|
|
|
/// </remarks>
|
|
|
|
|
|
/// <remarks date="2019-Dec-02/03/05" author="Thomas Wiedebusch">
|
|
|
|
|
|
/// - Extended timeouts,
|
|
|
|
|
|
/// - Read DUMMY to overcome FW malfunction.
|
|
|
|
|
|
/// </remarks>
|
|
|
|
|
|
/// <remarks date="2020-Jan-17/18" author="Thomas Wiedebusch">
|
|
|
|
|
|
/// - Retries changed for and back,
|
|
|
|
|
|
/// - Timeout changed for and back.
|
|
|
|
|
|
/// </remarks>
|
2022-04-06 08:42:16 +00:00
|
|
|
|
public Boolean OpenMeterFile(String fileName, String accessMode)
|
2021-10-01 09:09:20 +00:00
|
|
|
|
{
|
|
|
|
|
|
//check if logged on to meter and access level is as expected
|
|
|
|
|
|
if (_currentGenesis == null || !_currentGenesis.IsLoggedOn) return false;
|
|
|
|
|
|
Boolean returnValue;
|
|
|
|
|
|
var retryCtr = 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;
|
|
|
|
|
|
|
|
|
|
|
|
//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);
|
|
|
|
|
|
|
|
|
|
|
|
//get the file pointer
|
|
|
|
|
|
_filePointer = RegisterConverter.ConvertTo<Int32>(_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;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// FClose implementation of genesis meter
|
|
|
|
|
|
/// Close the _filePointer referenced file of the meter
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
/// <remarks date="2019-Jun-20" author="Thomas Wiedebusch">
|
|
|
|
|
|
/// - Initial
|
|
|
|
|
|
/// </remarks>
|
|
|
|
|
|
/// <remarks date="2019-Nov-30" author="Thomas Wiedebusch">
|
|
|
|
|
|
/// - Command write retry implemented.
|
|
|
|
|
|
/// </remarks>
|
|
|
|
|
|
/// <remarks date="2019-Dec-03" author="Thomas Wiedebusch">
|
|
|
|
|
|
/// - Extended timeout.
|
|
|
|
|
|
/// </remarks>
|
|
|
|
|
|
/// <remarks date="2020-Jan-17/18" author="Thomas Wiedebusch">
|
|
|
|
|
|
/// - Retries changed for and back,
|
|
|
|
|
|
/// - Timeout changed for and back,
|
|
|
|
|
|
/// - Command retry removed.
|
|
|
|
|
|
/// </remarks>
|
|
|
|
|
|
/// <remarks date="2020-Jan-22" author="Thomas Wiedebusch">
|
|
|
|
|
|
/// - Wait after writing for response before reading!
|
|
|
|
|
|
/// </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);
|
|
|
|
|
|
CommunicationConfig.RequestRetries = 0;
|
|
|
|
|
|
|
|
|
|
|
|
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));
|
|
|
|
|
|
}
|
|
|
|
|
|
//set timeout back to default value
|
|
|
|
|
|
_currentGenesis.TransmitProtocol.SetDefaultResponseTimeout();
|
|
|
|
|
|
CommunicationConfig.RequestRetries = CommunicationConfig.DefaultRequestRetries;
|
|
|
|
|
|
|
|
|
|
|
|
return returnValue;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|