Add SerialFirmwareDownloadTask to NfcC7_DLL for firmware upgrade handling

This commit is contained in:
Michal Buzik 2025-10-09 11:01:08 +02:00
parent 96408eaef3
commit 0a45d66c0b
16 changed files with 2807 additions and 18 deletions

View File

@ -0,0 +1,7 @@
namespace NfcC7_DLL.NfcHanler;
public enum ArchEventId: sbyte
{
Arch_EventId_Invalid = -2,
Arch_EventId_DataContinuation = -1,
}

View File

@ -0,0 +1,17 @@
using System.Collections;
namespace NfcC7_DLL.NfcHanler;
public class ComCompare : IComparer
{
int IComparer.Compare(Object x, Object y)
{
string sx = (string)x;
string sy = (string)y;
int intx = int.Parse(sx.Substring(3));
int inty = int.Parse(sy.Substring(3));
return (intx.CompareTo(inty));
}
}

View File

@ -0,0 +1,561 @@
using System.Globalization;
using Sensus.Protocols.FlexNet.FNv2;
namespace NfcC7_DLL.NfcHanler
{
class DiagTask
{
private static readonly string ERASED_MEMORY = "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF";
private MessageEngine messageEngine;
private WindowViewModel windowViewModel = null;
private TaskCompletionCallbackDelegate taskCompletionCallback;
private TaskProgressCallbackDelegate taskProgessCallback;
private TaskLogCallbackDelegate taskLogCallback;
private bool haltExecution;
private System.Threading.Timer timer;
/// <summary>
/// Progress and status
/// </summary>
private int progress = 0;
private string status = string.Empty;
/// <summary>
/// Memory read variables
/// </summary>
private UInt32 address;
private UInt32 endAddress;
private UInt16 addressInc;
/// <summary>
/// Specifies the number of times to execute a wait loop
/// </summary>
private int waitCount;
public TaskProgressCallbackDelegate TaskProgressCallback
{
set
{
taskProgessCallback = value;
}
}
public TaskLogCallbackDelegate TaskLogCallback
{
set
{
taskLogCallback = value;
}
}
private enum AlgorithmState
{
Idle,
ReadAllTags,
ReadStats,
SaveStats,
ReadEvents,
SaveEvents,
GetEventLogMemory,
NextEventLogMemory,
SaveEventLogMemory,
GetReadingLogMemory,
NextReadingLogMemory,
SaveReadingLogMemory,
GetTraceMemory,
NextTraceMemory,
SaveTraceMemory,
GetSemi,
Finished
};
AlgorithmState timerState = AlgorithmState.Idle;
bool waitingForAck = false;
string folder = string.Empty;
public DiagTask(MessageEngine messageEngine)
{
this.messageEngine = messageEngine;
taskProgessCallback = null;
timer = new System.Threading.Timer(TimerCb, null, Timeout.Infinite, Timeout.Infinite);
}
public string MapFile { get; set; }
public string OutputFile { get; set; }
public WindowViewModel ViewModel
{
set
{
windowViewModel = value;
windowViewModel.LogWithDescription = true;
windowViewModel.LogWithHexString = true;
windowViewModel.LogChargingData = false;
}
}
public bool Start(TaskCompletionCallbackDelegate taskCompletionCallback)
{
bool retValue = false;
folder = Path.GetDirectoryName(OutputFile);
this.taskCompletionCallback = taskCompletionCallback;
if (messageEngine != null)
{
// Write to log upgrade details
Utility.Log.Write("" + System.Environment.NewLine);
Utility.Log.Write("# -----------------------------------------------------" + System.Environment.NewLine);
Utility.Log.Write("# Extracting Diagnostic Info" + System.Environment.NewLine);
Utility.Log.Write("# -----------------------------------------------------" + System.Environment.NewLine);
if (taskProgessCallback != null)
{
taskProgessCallback(this, 0, "Starting...");
}
ReadAllTags();
timer.Change(1000, Timeout.Infinite);
retValue = true;
}
return retValue;
}
public void Stop()
{
// Signal to halt execution
haltExecution = true;
// Signal completion but not successful
ExtractComplete(false);
}
private void ExtractComplete(bool successful)
{
timerState = AlgorithmState.Idle;
timer.Change(Timeout.Infinite, Timeout.Infinite);
if (haltExecution || !successful)
{
Utility.Log.Write("" + System.Environment.NewLine);
Utility.Log.Write("# -----------------------------------------------------" + System.Environment.NewLine);
Utility.Log.Write("# Aborting Diagnostic Extraction." + System.Environment.NewLine);
Utility.Log.Write("# -----------------------------------------------------" + System.Environment.NewLine);
}
else if (successful)
{
Utility.Log.Write("");
Utility.Log.Write("# -----------------------------------------------------" + System.Environment.NewLine);
Utility.Log.Write("# Diagnostic Extraction Completed Successfully." + System.Environment.NewLine);
Utility.Log.Write("# -----------------------------------------------------" + System.Environment.NewLine);
}
else
{
Utility.Log.Write("");
Utility.Log.Write("# -----------------------------------------------------" + System.Environment.NewLine);
Utility.Log.Write("# Diagnostic Extraction Failed." + System.Environment.NewLine);
Utility.Log.Write("# -----------------------------------------------------" + System.Environment.NewLine);
}
if (taskCompletionCallback != null)
{
taskCompletionCallback(this, successful);
}
if (taskProgessCallback != null)
{
taskProgessCallback(this, 0, "Diagnostic info extracted");
}
}
private void TimerCb(object state)
{
int dueTime = 1000;
switch (timerState)
{
case AlgorithmState.Idle:
break;
case AlgorithmState.ReadAllTags:
{
status = "Saved all tags";
String fileName = messageEngine.TagsToCsv(folder);
// Append tags to output file
try
{
File.AppendAllText(OutputFile, File.ReadAllText(fileName));
}
catch (Exception e)
{
status = e.Message;
Utility.Log.Write(e.Message);
Utility.Log.Write(e.StackTrace);
}
Utility.Log.Write(DateTime.Now.ToString(MessageEngine.TimeFormatString) + " : Tags saved to " + fileName + "\n");
timerState = AlgorithmState.ReadStats;
}
break;
case AlgorithmState.ReadStats:
{
status = "Reading statistics";
messageEngine.StatsLogCommand("Start");
waitCount = 30;
timerState= AlgorithmState.SaveStats;
}
break;
case AlgorithmState.SaveStats:
{
if (!windowViewModel.StatsLogActive || --waitCount <= 0)
{
status = "Saved statistics";
messageEngine.StatsLogCommand("Stop");
string fileName = messageEngine.StatsLogToCsv(folder);
// Append stats to output file
try
{
File.AppendAllText(OutputFile, File.ReadAllText(fileName));
}
catch (Exception e)
{
status = e.Message;
Utility.Log.Write(e.Message);
Utility.Log.Write(e.StackTrace);
}
Utility.Log.Write(DateTime.Now.ToString(MessageEngine.TimeFormatString) + " : Stats log saved to " + fileName + "\n");
timerState = AlgorithmState.ReadEvents;
dueTime = 0;
}
}
break;
case AlgorithmState.ReadEvents:
{
status = "Getting event log";
windowViewModel.EventLogTimeFrameSelectedValue = "Full";
messageEngine.EventLogCommand("Start");
waitCount = 20;
timerState = AlgorithmState.SaveEvents;
}
break;
case AlgorithmState.SaveEvents:
{
if (!windowViewModel.EventLogActive || --waitCount <= 0)
{
status = "Saved event log";
messageEngine.EventLogCommand("Stop");
string fileName = messageEngine.EventLogToCsv(folder);
// Append events to output file
try
{
File.AppendAllText(OutputFile, File.ReadAllText(fileName));
}
catch (Exception e)
{
status = e.Message;
Utility.Log.Write(e.Message);
Utility.Log.Write(e.StackTrace);
}
Utility.Log.Write(DateTime.Now.ToString(MessageEngine.TimeFormatString) + " : Event log saved to " + fileName + "\n");
timerState = AlgorithmState.GetEventLogMemory;
dueTime = 0;
}
}
break;
case AlgorithmState.GetEventLogMemory:
{
status = "Getting event log memory";
address = 0x08066000;
endAddress = 0x0806C000;
addressInc = 0x0080;
windowViewModel.MemoryReadData = string.Empty;
MemoryReadCommand memoryReadCmd = new MemoryReadCommand();
memoryReadCmd.NumBytes = 128;
memoryReadCmd.Source = 0;
memoryReadCmd.Address = address;
messageEngine.SendNa2wSerial(memoryReadCmd, false);
timerState = AlgorithmState.NextEventLogMemory;
dueTime = 100;
}
break;
case AlgorithmState.NextEventLogMemory:
{
address += addressInc;
if ( (address >= endAddress) ||
windowViewModel.MemoryReadData.Contains(ERASED_MEMORY) )
{
timerState = AlgorithmState.SaveEventLogMemory;
dueTime = 0;
}
else
{
status = $"Reading@{address.ToString("X8")}";
MemoryReadCommand memoryReadCmd = new MemoryReadCommand();
memoryReadCmd.NumBytes = 128;
memoryReadCmd.Source = 0;
memoryReadCmd.Address = address;
messageEngine.SendNa2wSerial(memoryReadCmd, false);
dueTime = 100;
}
}
break;
case AlgorithmState.SaveEventLogMemory:
{
status = "Saved event log memory";
try
{
File.AppendAllText(OutputFile, windowViewModel.MemoryReadData);
}
catch (Exception ex)
{
status = ex.Message;
Utility.Log.Write(ex.ToString());
Utility.Log.Write(ex.StackTrace);
}
timerState = AlgorithmState.GetReadingLogMemory;
dueTime = 0;
}
break;
case AlgorithmState.GetReadingLogMemory:
{
status = "Reading Log";
windowViewModel.MemoryReadData = string.Empty;
address = 0x0806C000;
endAddress = 0x08070000;
addressInc = 0x0080;
MemoryReadCommand memoryReadCmd = new MemoryReadCommand();
memoryReadCmd.NumBytes = 128;
memoryReadCmd.Source = 0;
memoryReadCmd.Address = address;
messageEngine.SendNa2wSerial(memoryReadCmd, false);
timerState = AlgorithmState.NextReadingLogMemory;
dueTime = 100;
}
break;
case AlgorithmState.NextReadingLogMemory:
{
address += addressInc;
if ( (address >= endAddress) ||
windowViewModel.MemoryReadData.Contains(ERASED_MEMORY) )
{
timerState = AlgorithmState.SaveReadingLogMemory;
dueTime = 0;
}
else
{
status = $"Reading@{address.ToString("X8")}";
MemoryReadCommand memoryReadCmd = new MemoryReadCommand();
memoryReadCmd.NumBytes = 128;
memoryReadCmd.Source = 0;
memoryReadCmd.Address = address;
messageEngine.SendNa2wSerial(memoryReadCmd, false);
dueTime = 100;
}
}
break;
case AlgorithmState.SaveReadingLogMemory:
{
status = "Saved reading log memory";
try
{
File.AppendAllText(OutputFile, windowViewModel.MemoryReadData);
}
catch (Exception ex)
{
status = ex.Message;
Utility.Log.Write(ex.ToString());
Utility.Log.Write(ex.StackTrace);
}
timerState = AlgorithmState.GetTraceMemory;
dueTime = 0;
}
break;
case AlgorithmState.GetTraceMemory:
{
UInt32 traceStart = 0x2000745c;
if (!string.IsNullOrWhiteSpace(MapFile) && File.Exists(MapFile))
{
string[] map = File.ReadAllLines(MapFile);
string[] lines = Array.FindAll(map, p => p.Contains("WMBusTrack__Log"));
if (lines.Length > 0)
{
foreach (string line in lines)
{
if (!line.Contains("__LogEntry") && line.Contains("0x"))
{
string hexString = line.Substring(line.IndexOf("0x") + 2, 8);
traceStart = UInt32.Parse(hexString, NumberStyles.HexNumber);
break;
}
}
}
}
UInt32 traceEnd = traceStart + 0x180;
address = traceStart;
endAddress = traceEnd;
addressInc = 0x80;
windowViewModel.MemoryReadData = string.Empty;
status = $"Reading trace memory@{traceStart.ToString("X8")}";
MemoryReadCommand memoryReadCmd = new MemoryReadCommand();
memoryReadCmd.NumBytes = 128;
memoryReadCmd.Source = 0;
memoryReadCmd.Address = address;
messageEngine.SendNa2wSerial(memoryReadCmd, false);
timerState = AlgorithmState.NextTraceMemory;
dueTime = 100;
}
break;
case AlgorithmState.NextTraceMemory:
{
address += addressInc;
if (address < endAddress)
{
status = $"Reading@{address.ToString("X8")}";
MemoryReadCommand memoryReadCmd = new MemoryReadCommand();
memoryReadCmd.NumBytes = 128;
memoryReadCmd.Source = 0;
memoryReadCmd.Address = address;
messageEngine.SendNa2wSerial(memoryReadCmd, false);
dueTime = 100;
}
else if (address == endAddress)
{
status = $"Reading@{address.ToString("X8")}";
MemoryReadCommand memoryReadCmd = new MemoryReadCommand();
memoryReadCmd.NumBytes = 4;
memoryReadCmd.Source = 0;
memoryReadCmd.Address = address;
messageEngine.SendNa2wSerial(memoryReadCmd, false);
dueTime = 100;
}
else
{
timerState = AlgorithmState.SaveTraceMemory;
dueTime = 0;
}
}
break;
case AlgorithmState.SaveTraceMemory:
{
status = "Saved trace memory";
try
{
File.AppendAllText(OutputFile, "\n" + windowViewModel.MemoryReadData);
Utility.Log.Write(DateTime.Now.ToString(MessageEngine.TimeFormatString) + " : Trace memory saved to " + OutputFile + "\n");
}
catch (Exception ex)
{
status = ex.Message;
Utility.Log.Write(ex.ToString());
Utility.Log.Write(ex.StackTrace);
}
timerState = AlgorithmState.GetSemi;
dueTime = 0;
}
break;
case AlgorithmState.GetSemi:
{
windowViewModel.SRfKeySelectedItem = "None";
windowViewModel.SRfAuthSelectedItem = "Default";
windowViewModel.PamPayload = "00";
messageEngine.SensusRfCommand("CustomPam");
timerState = AlgorithmState.Finished;
dueTime = 0;
}
break;
case AlgorithmState.Finished:
{
status = "Diagnostic extraction finished.";
progress = 99;
ExtractComplete(true);
dueTime = Timeout.Infinite;
}
break;
} // end switch
if (taskProgessCallback != null)
{
taskProgessCallback(this, ++progress, status);
}
timer.Change(dueTime, Timeout.Infinite);
}
private void ReadAllTags()
{
timerState = AlgorithmState.ReadAllTags;
progress = 1;
status = "Reading all tags";
if (taskProgessCallback != null)
{
taskProgessCallback(this, progress, status);
}
messageEngine.ReadAllTags();
}
} // end class
}

View File

@ -0,0 +1,459 @@
using NfcC7_DLL.NfcHanler.FieldLogicStaging;
using Sensus;
using Sensus.Protocols.FlexNet;
using Sensus.Protocols.FlexNet.FNv2;
using Sensus.Protocols.FlexNet.FNv2.NA2WParameters;
using Sensus.Protocols.FlexNet.Serial.FNv2;
namespace NfcC7_DLL.NfcHanler
{
class EventLogTask
{
private MessageEngine messageEngine;
private TaskCompletionCallbackDelegate taskCompletionCallback;
private TaskProgressCallbackDelegate taskProgessCallback;
private TaskLogCallbackDelegate taskLogCallback;
private ushort blocksPerCommand = 1;
private bool haltExecution;
private System.Threading.Timer timer;
public TaskProgressCallbackDelegate TaskProgressCallback
{
set
{
taskProgessCallback = value;
}
}
public TaskLogCallbackDelegate TaskLogCallback
{
set
{
taskLogCallback = value;
}
}
private enum AlgorithmState
{
IDLE,
READ_SERIAL_NUMBER,
READ_EVENTS
};
public bool AckLoadBlock { get; set; }
public UInt32 TimeFrame { get; set; }
AlgorithmState timerState = AlgorithmState.IDLE;
bool waitingForAck = false;
UInt64 extractTime = 0x0000;
UInt16 eventCount = 0;
UInt64 serialNumber = 0;
UInt32 numberOfEvents = 0;
List<byte> fragments = new List<byte>();
public EventLogTask(MessageEngine messageEngine)
{
this.messageEngine = messageEngine;
TimeFrame = 0xffffffff;
taskProgessCallback = null;
timer = new System.Threading.Timer(TimerCb, null, Timeout.Infinite, Timeout.Infinite);
}
public bool Start(TaskCompletionCallbackDelegate taskCompletionCallback)
{
bool retValue = false;
this.taskCompletionCallback = taskCompletionCallback;
extractTime = 0;
eventCount = 0;
numberOfEvents = 0;
fragments = new List<byte>();
if (messageEngine != null)
{
// Write to log upgrade details
Utility.Log.Write("" + System.Environment.NewLine);
Utility.Log.Write("# -----------------------------------------------------" + System.Environment.NewLine);
Utility.Log.Write("# Extracting Event Log" + System.Environment.NewLine);
Utility.Log.Write("# -----------------------------------------------------" + System.Environment.NewLine);
if (taskProgessCallback != null)
{
taskProgessCallback(this, 0, "Starting...");
}
SendSessionQueryCmd();
timer.Change(1000, Timeout.Infinite);
retValue = true;
}
return retValue;
}
public void Stop()
{
// Signal to halt execution
haltExecution = true;
// Signal completion but not successful
ExtractComplete(false);
}
private void ExtractComplete(bool successful)
{
timerState = AlgorithmState.IDLE;
timer.Change(Timeout.Infinite, Timeout.Infinite);
if (haltExecution || !successful)
{
Utility.Log.Write("" + System.Environment.NewLine);
Utility.Log.Write("# -----------------------------------------------------" + System.Environment.NewLine);
Utility.Log.Write("# Aborting Log Extraction." + System.Environment.NewLine);
Utility.Log.Write("# -----------------------------------------------------" + System.Environment.NewLine);
}
else if (successful)
{
Utility.Log.Write("");
Utility.Log.Write("# -----------------------------------------------------" + System.Environment.NewLine);
Utility.Log.Write("# Log Extraction Completed Successfully." + System.Environment.NewLine);
Utility.Log.Write("# -----------------------------------------------------" + System.Environment.NewLine);
}
else
{
Utility.Log.Write("");
Utility.Log.Write("# -----------------------------------------------------" + System.Environment.NewLine);
Utility.Log.Write("# Log Extraction Failed." + System.Environment.NewLine);
Utility.Log.Write("# -----------------------------------------------------" + System.Environment.NewLine);
}
if (taskCompletionCallback != null)
{
taskCompletionCallback(this, successful);
}
if (taskProgessCallback != null)
{
taskProgessCallback(this, 0, eventCount.ToString() + " event extracted");
}
}
private void TimerCb(object state)
{
if (timerState != AlgorithmState.IDLE)
{
SendEventReadCmd();
}
}
private void ProcessReply(NA2WSerialFrame message)
{
UnknownResponse unknownResponse = message.Unwrap<UnknownResponse>();
if ((null != unknownResponse) && (unknownResponse.CommandCode == 0x12))
{
// Event Data Response
byte[] payload = unknownResponse.Contents;
UInt64 messageTimeMs = (UInt64)payload.Read<UInt32>((1 * 8) + 0, 32) * 1000; // Message time in payload is in seconds
byte numberOfEvents = payload.Read<byte>((5 * 8) + 0, 7);
if (numberOfEvents == 0)
{
ExtractComplete(true);
}
else
{
timer.Change(1000, Timeout.Infinite);
uint offset = 6;
while (numberOfEvents != 0)
{
UInt16 dataLength = payload.Read<UInt16>((offset + 9) * 8 + 0, 16);
if (taskLogCallback != null)
{
sbyte id = payload.Read<sbyte>((offset * 8) + 0, 8);
if (id == (sbyte) ArchEventId.Arch_EventId_Invalid)
{
ExtractComplete(true);
}
else
{
UInt64 timeStampMs = payload.Read<UInt64>((offset + 1) * 8 + 0, 64);
UInt16 fileID = payload.Read<UInt16>((offset + 11) * 8 + 0, 16);
UInt16 lineNumber = payload.Read<UInt16>((offset + 13) * 8 + 0, 16);
byte[] data = new byte[dataLength];
Array.Copy(payload, offset + 15, data, 0, dataLength);
GlobalIPerlEvent iPerlEvent = new GlobalIPerlEvent(id, data, fileID, lineNumber);
DateTime dateTime = DateTime.Now;
// Calculate time of event. Message Time should allows be greater than event time
if (messageTimeMs > timeStampMs)
{
Double timeDiffMs = (Double)timeStampMs - (Double)messageTimeMs; // Time in past
dateTime = dateTime.AddMilliseconds(timeDiffMs);
}
EventNotification eventNotification = new EventNotification();
eventNotification.Id = iPerlEvent.Name;
eventNotification.File = iPerlEvent.File;
eventNotification.Line = lineNumber.ToString();
eventNotification.TimeStamp = dateTime.ToString();
eventNotification.Description = iPerlEvent.Description;
eventNotification.Data = data.ToHexString();
taskLogCallback(this, eventNotification);
extractTime = timeStampMs + 1;
eventCount++;
}
}
numberOfEvents--;
offset += (uint)dataLength + 15U;
}
}
}
else if (message.Payload is NetworkResponse networkResponse)
{
if (networkResponse.Payload is ParameterReadResponse parameterReadResponse)
{
if (parameterReadResponse.TagMap == TagMap.GlobalIPerl)
{
List<NA2WParameter> na2wParameterList = parameterReadResponse.Parameters;
foreach (NA2WParameter na2wParameter in na2wParameterList)
{
switch (na2wParameter.Tag)
{
case ((byte)GlobalIPerlTag.SerialNumber):
{
serialNumber = na2wParameter.Value.Read<UInt64>(0);
SendInitialEventReadCmd();
}
break;
default:
break;
}
}
}
}
else if (networkResponse.Payload is FragmentedFrame fragment)
{
var tmp = fragment.Code;
tmp = fragment.CommandCode;
var payloadLength = fragment.PayloadLength;
byte[] payload = fragment.Content;
byte version = payload.Read<byte>(0, 4);
byte map = payload.Read<byte>(0 + 4, 4);
UInt32 messageTime = payload.Read<UInt32>(8 * 1) * 1000;
byte numberEvents = payload.Read<byte>(8 * 5, 7);
if (numberEvents > numberOfEvents)
{
numberOfEvents = numberEvents;
}
#if false
else
{
eventCount = Convert.ToUInt16(numberOfEvents - numberEvents);
if (eventCount == 0)
{
ExtractComplete(true);
}
}
fragments.AddRange(payload);
#else
fragments.AddRange(payload);
for (uint offset = 6; offset < payloadLength && numberEvents > 0; )
{
try
{
// event
sbyte id = payload.Read<sbyte>((offset * 8) + 0, 8);
if (id == (sbyte)ArchEventId.Arch_EventId_Invalid)
{
ExtractComplete(true);
break;
}
else if ((offset + 15) < payload.Length)
{
UInt64 timeStampMs = payload.Read<UInt64>((offset + 1) * 8 + 0, 64);
UInt16 dataLength = payload.Read<UInt16>((offset + 9) * 8 + 0, 16);
UInt16 fileID = payload.Read<UInt16>((offset + 11) * 8 + 0, 16);
UInt16 lineNumber = payload.Read<UInt16>((offset + 13) * 8 + 0, 16);
byte[] data = new byte[dataLength];
if ((offset + 15 + dataLength) > payloadLength)
{
dataLength = Convert.ToUInt16(payloadLength - offset - 15);
}
Array.Copy(payload, offset + 15, data, 0, dataLength);
GlobalIPerlEvent iPerlEvent = new GlobalIPerlEvent(id, data, fileID, lineNumber);
DateTime dateTime = DateTime.Now;
// Calculate time of event. Message Time should allows be greater than event time
if (messageTime > timeStampMs)
{
Double timeDiffMs = (Double)timeStampMs - (Double)messageTime; // Time in past
dateTime = dateTime.AddMilliseconds(timeDiffMs);
}
EventNotification eventNotification = new EventNotification();
eventNotification.Id = iPerlEvent.Name;
eventNotification.File = iPerlEvent.File;
eventNotification.Line = lineNumber.ToString();
eventNotification.TimeStamp = dateTime.ToString();
eventNotification.Description = iPerlEvent.Description;
eventNotification.Data = data.ToHexString();
taskLogCallback(this, eventNotification);
extractTime = timeStampMs + 1;
eventCount++;
offset += dataLength + 15U;
numberEvents--;
}
else
{
if ((offset + 14) < payloadLength)
{
UInt64 timeStampMs = payload.Read<UInt64>((offset + 1) * 8 + 0, 64);
byte dataLength = payload.Read<byte>((offset + 9) * 8 + 0, 16);
UInt16 fileID = payload.Read<UInt16>((offset + 11) * 8 + 0, 16);
UInt16 lineNumber = payload.Read<UInt16>((offset + 13) * 8 + 0, 16);
}
else if ((offset + 12) < payloadLength)
{
UInt64 timeStampMs = payload.Read<UInt64>((offset + 1) * 8 + 0, 64);
byte dataLength = payload.Read<byte>((offset + 9) * 8 + 0, 16);
UInt16 fileID = payload.Read<UInt16>((offset + 11) * 8 + 0, 16);
}
else if ((offset + 10) < payloadLength)
{
UInt64 timeStampMs = payload.Read<UInt64>((offset + 1) * 8 + 0, 64);
byte dataLength = payload.Read<byte>((offset + 9) * 8 + 0, 16);
}
else if ((offset + 9) < payloadLength)
{
UInt64 timeStampMs = payload.Read<UInt64>((offset + 1) * 8 + 0, 64);
}
}
offset = payloadLength;
}
catch (Exception ex)
{
Utility.Log.Write($"Exception: {ex.Message}\n{ex.StackTrace}\n");
timer.Change(1000, Timeout.Infinite);
}
}
#endif
timer.Change(1000, Timeout.Infinite);
}
else
{
// TBD:
timer.Change(1000, Timeout.Infinite);
}
}
else
{
// TBD:
timer.Change(1000, Timeout.Infinite);
}
}
private void SendSessionQueryCmd()
{
List<byte> tagList = new List<byte>();
tagList.Add((byte)GlobalIPerlTag.SerialNumber);
timerState = AlgorithmState.READ_SERIAL_NUMBER;
if (taskProgessCallback != null)
{
taskProgessCallback(this, 0, "Read Serial Number Sent");
}
// Send message request
ParameterReadCommand parameterReadCommand = new ParameterReadCommand(TagMap.GlobalIPerl, tagList);
NA2WSerialFrame response = messageEngine.SendNa2wSerial(parameterReadCommand, ParameterReadResponse._Code);
if (null != response)
{
ProcessReply(response);
}
}
private void SendInitialEventReadCmd()
{
EventReadV1 eventReadV1 = new EventReadV1();
eventReadV1.Time = TimeFrame;
eventReadV1.ReadAfterTime = true;
// eventReadV1.NumberOfEvents = 127;
eventReadV1.NumberOfEvents = 9; // Limit to 9 because fragments over NFC not working. 250ish is MTU size.
timerState = AlgorithmState.READ_EVENTS;
// Send message request
NA2WSerialFrame response = messageEngine.SendNa2wSerial(eventReadV1, true);
if (taskProgessCallback != null)
{
taskProgessCallback(this, 0, "Initial EventRead sent");
}
if (null != response)
{
ProcessReply(response);
}
}
private void SendEventReadCmd()
{
EventReadV0 eventReadV0 = new EventReadV0();
eventReadV0.Time = extractTime;
eventReadV0.ReadAfterTime = true;
// eventReadV0.NumberOfEvents = 127;
eventReadV0.NumberOfEvents = 9; // Limit to 9 because fragments over NFC not working. 250ish is MTU size.
timerState = AlgorithmState.READ_EVENTS;
// Send message request
NA2WSerialFrame response = messageEngine.SendNa2wSerial(eventReadV0, true);
if (taskProgessCallback != null)
{
taskProgessCallback(this, 0, eventCount.ToString() + " events extracted");
}
if (null != response)
{
ProcessReply(response);
}
}
}
}

View File

@ -0,0 +1,232 @@
using Sensus;
namespace NfcC7_DLL.NfcHanler;
public class GlobalIPerlEvent
{
public static readonly string[] ApplicationEventIDNames =
{
"ApplicationEvent_SelfTestCompleted"
};
public static readonly string[] SterlingEventIDNames =
{
"SterlingEvent_CtrlInit",
"SterlingEvent_CtrlStart",
"SterlingEvent_CtrlStop",
"SterlingEvent_CtrlReset",
"SterlingEvent_DrvInit",
"SterlingEvent_DrvReset" ,
"SterlingEvent_DrvResetFailure",
"SterlingEvent_DrvSampleError",
"SterlingEvent_DrvFifoOverrun",
"SterlingEvent_FieldChanged",
"SterlingEvent_AsicError",
"SterlingEvent_ConfigError",
"SterlingEvent_MetrologyError",
"SterlingEvent_HWError",
"SterlingEvent_IrqOverlap",
"SterlingEvent_FieldNegativeOrZero",
"SterlingEvent_HeartbeatMissing",
"SterlingEvent_MetrologyDebug",
};
// Add possible file names to dictionary below
// Dictionary uses the first byte of the given fileID to identify the
// module, then indexing into the list associated with the specific module
// with the file index will retrieve appropriate file label
private static readonly Dictionary<byte, List<string>> FileLabels = new Dictionary<byte, List<string>>()
{
{ ((byte)ModuleID.ModuleID_Application), new List<string> { "Application - factory", } },
{ ((byte)ModuleID.ModuleID_Sterling), new List<string> { "Sterling - IPerlAsicDriver",
"Sterling - IPerlAsicFieldControl",
"Sterling - SterlingWaterRegisterMetrology",} },
};
// Add possible architecture-defined event ID names to dictionary below
// Dictionary uses the first byte of the given fileID to identify the
// module, then extracts associated string
private static readonly Dictionary<sbyte, string> archEventIDLabels = new Dictionary<sbyte, string>()
{
{ ((sbyte)ArchEventId.Arch_EventId_Invalid), "Event ID invalid" },
{ ((sbyte)ArchEventId.Arch_EventId_DataContinuation), "Event ID data continuation" },
};
// Add possible event ID names to dictionary below
// Dictionary uses the first byte of the given fileID to identify the
// module, then indexing into the list associated with the specific module
// with the file index will retrieve appropriate file label
private static readonly Dictionary<byte, List<string>> eventIDLabels = new Dictionary<byte, List<string>>()
{
{ ((byte)ModuleID.ModuleID_Application), new List<string>(ApplicationEventIDNames) },
{ ((byte)ModuleID.ModuleID_Sterling), new List<string>(SterlingEventIDNames) },
};
// Sterling driver errors
private static readonly Dictionary<sbyte, string> sterlingDriverErrorLabels = new Dictionary<sbyte, string>()
{
{ ((sbyte)SterlingDriverError.SterlingDvr_Error_BlockInvalid), "Block invalid" },
{ ((sbyte)SterlingDriverError.SterlingDvr_Error_ResetFailed), "Reset failed" },
{ ((sbyte)SterlingDriverError.SterlingDvr_Error_Timeout), "Timeout" },
{ ((sbyte)SterlingDriverError.SterlingDvr_Error_CommsFailure), "Communications failure" },
{ ((sbyte)SterlingDriverError.SterlingDvr_Error_ConfigInvalid), "Configuration invalid" },
{ ((sbyte)SterlingDriverError.SterlingDvr_Error_None), "No error" },
{ ((sbyte)SterlingDriverError.SterlingDvr_Error_StateAlreadyValid), "State already valid" },
{ ((sbyte)SterlingDriverError.SterlingDvr_Error_Retried), "Retried" },
};
public static string GetFileLabel(ushort encodedFileID)
{
byte module = (byte)(encodedFileID >> 8); // First 8 bits
byte fileIndex = (byte)(encodedFileID & 0xFF); // Last 8 bits
if (!FileLabels.TryGetValue(module, out var labels))
{
return "Unknown module ID";
}
if (fileIndex >= labels.Count)
{
return "Unknown file index";
}
return labels[fileIndex];
}
public static string GetEventIDLabel(ushort encodedFileID, sbyte id)
{
// Check if this is an architecture-defined event (Arch. event IDs will be negative)
if(id < 0)
{
if (!archEventIDLabels.TryGetValue(id, out string archIdLabel))
{
return "Unknown event ID";
}
return archIdLabel;
}
byte module = (byte)(encodedFileID >> 8);
if (!eventIDLabels.TryGetValue(module, out var idLabels))
{
return "Unknown event ID";
}
if (id >= idLabels.Count)
{
return "Unknown event ID";
}
return idLabels[id];
}
public GlobalIPerlEvent(sbyte id, byte[] data, UInt16 fileID, UInt16 lineNumber)
{
_id = id;
_data = data;
_fileID = fileID;
_lineNumber = lineNumber;
Name = "Unknown";
Description = string.Empty;
File = string.Empty;
try
{
File = GetFileLabel(_fileID);
Name = GetEventIDLabel(_fileID, _id);
switch (Name)
{
case ("ApplicationEvent_SelfTestCompleted"):
{
Description = "Line number: " + (_lineNumber.ToString());
Description += Environment.NewLine + "Tests executed: " + (_data.Read<UInt32>((0 * 8) + 0, 32).ToString()) +
Environment.NewLine + "Tests failed: " + (_data.Read<UInt32>((4 * 8) + 0, 32).ToString());
}
break;
case ("SterlingEvent_FieldNegativeOrZero"):
{
Description = "Line number: " + (_lineNumber.ToString());
Description += Environment.NewLine + "Field per drive time (micro-Gauss): " + (_data.Read<Int32>(0, 32).ToString()); // signed 4 bytes of uG data
}
break;
case ("SterlingEvent_DrvInit"):
case ("SterlingEvent_DrvReset"):
case ("SterlingEvent_DrvResetFailure"):
case ("SterlingEvent_DrvSampleError"):
case ("SterlingEvent_DrvFifoOverrun"):
case ("SterlingEvent_HWError"):
case ("SterlingEvent_AsicError"):
case ("SterlingEvent_MetrologyDebug"):
{
if ((_data.Length == 0))
{
Description = "Line number: " + (_lineNumber.ToString());
break;
}
// Sterling driver event data:
// bytes[0:3] - ErrorCode (of type SterlingDriverError)
// bytes[4:7] - ErrorLine (specific to sterling driver that uses this error struct)
// bytes[8:11] - Context data (if any)
Description = "Line number: " + (_data.Read<Int32>((4 * 8) + 0, 32).ToString());
sbyte errorCode = (sbyte)_data.Read<Int32>((0 * 8) + 0, 32);
if (!sterlingDriverErrorLabels.TryGetValue(errorCode, out string ErrorName))
{
ErrorName = "unknown error";
}
Description += Environment.NewLine + "Event context: " + ErrorName + ". Code: " + errorCode.ToString();
UInt32 additionalData = _data.Read<UInt32>((8 * 8) + 0, 32);
if (additionalData != UInt32.MaxValue)
{
Description += Environment.NewLine + "Context data: " + additionalData.ToString();
}
}
break;
default:
Description = "Line number: " + (_lineNumber.ToString());
break;
}
}
catch
{
File = "Parsing Error (" + (SByte)fileID + ")";
Name = "Parsing Error (" + (SByte)id + ")";
}
}
public String Name
{
private set;
get;
}
public String File
{
private set;
get;
}
public String Description
{
private set;
get;
}
sbyte _id;
byte[] _data;
UInt16 _fileID;
UInt16 _lineNumber;
}

View File

@ -17,6 +17,7 @@ using Sensus.Protocols.FlexNet.FNv2;
using Sensus.Protocols.FlexNet.FNv2.NA2WParameters;
using Sensus.Protocols.FlexNet.Serial;
using Sensus.Protocols.FlexNet.Serial.FNv2;
using Conversion = NfcC7_DLL.NfcHanler.Utils.Conversion;
using Log = NfcC7_DLL.NfcHanler.Utils.Log;
using MeterSize = NfcC7_DLL.NfcHanler.FieldLogicStaging.SterlingMetrologyTags.MeterSize;
using NA2WProductType = NfcC7_DLL.NfcHanler.FieldLogicStaging.NA2WProductType;
@ -538,7 +539,7 @@ namespace NfcC7_DLL.NfcHanler
{
TemperatureCalibration tempCal =
new TemperatureCalibration();
tempCal.TemperatureCal = calibration;
//tempCal.TemperatureCal = calibration;
na2wParamList.Add(tempCal);
// Update corrected temperature
@ -1724,7 +1725,7 @@ namespace NfcC7_DLL.NfcHanler
byte revision = Byte.Parse(windowViewModel.StatsLogCollection[windowViewModel.StatsLogSelectedIndex].Revision);
byte[] data = Conversion.HexStringToBytes(windowViewModel.StatsLogCollection[windowViewModel.StatsLogSelectedIndex].Data);
windowViewModel.StatsParseText = GlobalIPerlStatistics.Parse((ModuleId)moduleId, revision, data);
//windowViewModel.StatsParseText = GlobalIPerlStatistics.Parse((ModuleId)moduleId, revision, data);
}
else
{
@ -1999,7 +2000,7 @@ namespace NfcC7_DLL.NfcHanler
{
// Send Factory Sleep Open command
FactoryTestOpen factoryTestOpen = new FactoryTestOpen();
factoryTestOpen.SleepTime = GlobalIPerlUtility.Properties.Settings.Default.SleepTime;
factoryTestOpen.SleepTime = 0x10;
SendNa2wSerial(factoryTestOpen, ParameterReadResponse._Code);
}
@ -3308,7 +3309,7 @@ namespace NfcC7_DLL.NfcHanler
manufacturerIdAscii[2] = (byte)(((manufacturerIdRaw) & 0x001F) + 64);
byte version = payload[block1Offset + 8];
Utility.WMBusDeviceType deviceType = (Utility.WMBusDeviceType)(payload[block1Offset + 9]);
WMBusDeviceType deviceType = (WMBusDeviceType)(payload[block1Offset + 9]);
description = "WMBUS, " + packetTypeStr + ", " + String.Format("{0:D8}, (0x{1:X8}), ", meterId, meterIdRaw);
description += deviceType.ToString() + " - " + manufacturerIdAscii.ToASCIIString() + String.Format(" - 0x{0:X2}", version);
@ -3370,11 +3371,11 @@ namespace NfcC7_DLL.NfcHanler
eventNotification.TimeStamp = DateTime.Now.ToLongTimeString(); // String.Format("{0}", timeStamp);
eventNotification.Data = eventData.ToHexString();
GlobalIPerlEvent iPerlEvent = new GlobalIPerlEvent(idNum, eventData, fileIdNum, lineNum);
/*GlobalIPerlEvent iPerlEvent = new GlobalIPerlEvent(idNum, eventData, fileIdNum, lineNum);
eventNotification.Id = iPerlEvent.Name;
eventNotification.File = iPerlEvent.File;
eventNotification.Line = fileIdNum.ToString();
eventNotification.Description = iPerlEvent.Description;
eventNotification.Description = iPerlEvent.Description;*/
windowViewModel.Add(eventNotification);
}
@ -3749,7 +3750,7 @@ namespace NfcC7_DLL.NfcHanler
public void SaveDefaultConfigurationValues()
{
GlobalIPerlUtility.Properties.Settings.Default.Configuration_DeviceId = windowViewModel.DeviceIdNew;
/* GlobalIPerlUtility.Properties.Settings.Default.Configuration_DeviceId = windowViewModel.DeviceIdNew;
GlobalIPerlUtility.Properties.Settings.Default.Configuration_SerialNumber = windowViewModel.SerialNumberNew;
GlobalIPerlUtility.Properties.Settings.Default.Configuration_ManufacturingNote = windowViewModel.ManufacturingNoteNew;
@ -3763,11 +3764,11 @@ namespace NfcC7_DLL.NfcHanler
GlobalIPerlUtility.Properties.Settings.Default.Configuration_TcxoCorrection = windowViewModel.TcxoCorrectionNew;
GlobalIPerlUtility.Properties.Settings.Default.Configuration_PaOffPowerLevel = windowViewModel.RfPowerLevelNew;
GlobalIPerlUtility.Properties.Settings.Default.Configuration_ButtonPressAction = windowViewModel.ButtonPressAction;
}
*/ }
public void LoadDefaultConfigurationValues()
{
windowViewModel.DeviceIdNew = GlobalIPerlUtility.Properties.Settings.Default.Configuration_DeviceId;
/* windowViewModel.DeviceIdNew = GlobalIPerlUtility.Properties.Settings.Default.Configuration_DeviceId;
windowViewModel.SerialNumberNew = GlobalIPerlUtility.Properties.Settings.Default.Configuration_SerialNumber;
windowViewModel.ManufacturingNoteNew = GlobalIPerlUtility.Properties.Settings.Default.Configuration_ManufacturingNote;
@ -3781,11 +3782,11 @@ namespace NfcC7_DLL.NfcHanler
windowViewModel.RfPowerLevelNew = GlobalIPerlUtility.Properties.Settings.Default.Configuration_PaOffPowerLevel;
windowViewModel.ButtonPressAction = GlobalIPerlUtility.Properties.Settings.Default.Configuration_ButtonPressAction;
}
*/ }
public void SaveDefaultCommandValues()
{
GlobalIPerlUtility.Properties.Settings.Default.Command_TxEngFrequency = windowViewModel.TxEng_Frequency;
/*GlobalIPerlUtility.Properties.Settings.Default.Command_TxEngFrequency = windowViewModel.TxEng_Frequency;
GlobalIPerlUtility.Properties.Settings.Default.Command_TxEngDuration = windowViewModel.TxEng_Duration;
GlobalIPerlUtility.Properties.Settings.Default.Command_TxEngTransceiverPower = windowViewModel.TxEng_TransceiverPower;
GlobalIPerlUtility.Properties.Settings.Default.Command_TxEngModulation = windowViewModel.TxEng_Modulation;
@ -3798,11 +3799,11 @@ namespace NfcC7_DLL.NfcHanler
GlobalIPerlUtility.Properties.Settings.Default.Command_RxModulation = windowViewModel.Rx_Modulation;
GlobalIPerlUtility.Properties.Settings.Default.Command_RxSensitivity = windowViewModel.Rx_Sensitivity;
}
*/ }
public void LoadDefaultCommandValues()
{
windowViewModel.TxEng_Frequency = GlobalIPerlUtility.Properties.Settings.Default.Command_TxEngFrequency;
/* windowViewModel.TxEng_Frequency = GlobalIPerlUtility.Properties.Settings.Default.Command_TxEngFrequency;
windowViewModel.TxEng_Duration = GlobalIPerlUtility.Properties.Settings.Default.Command_TxEngDuration;
windowViewModel.TxEng_TransceiverPower = GlobalIPerlUtility.Properties.Settings.Default.Command_TxEngTransceiverPower;
windowViewModel.TxEng_Modulation = GlobalIPerlUtility.Properties.Settings.Default.Command_TxEngModulation;
@ -3815,7 +3816,7 @@ namespace NfcC7_DLL.NfcHanler
windowViewModel.Rx_Modulation = GlobalIPerlUtility.Properties.Settings.Default.Command_RxModulation;
windowViewModel.Rx_Sensitivity = GlobalIPerlUtility.Properties.Settings.Default.Command_RxSensitivity;
}
*/ }
public void FwdlTaskProgressCallback(Object task, Double percentDone, String statusString)
{

View File

@ -25,7 +25,7 @@ using Log = NfcC7_DLL.NfcHanler.Utils.Log;
namespace GlobalIPerlUtility
{
class MeterTestHatLink : ISerialConnection, IDisposable
public class MeterTestHatLink : ISerialConnection, IDisposable
{
private SerialManager serialManager = null;
private UInt16 sessionId = 0;

View File

@ -0,0 +1,76 @@
namespace NfcC7_DLL.NfcHanler;
public enum ModuleId
{
Statistics = 0,
FlexNetTransmitter = 1,
FlexNetReceiver = 2,
FlexNetCommandProcess = 3,
WbDbProcess = 4,
Scheduler = 5,
Si446xRadio = 6,
SensusRfTransmitter = 7,
SensusRfReceiver = 8,
MomComProcess = 9,
TfwChannel = 10,
SensusRfProcess = 11,
TfxHost = 12,
System = 13,
Board = 14,
UpgradeProcess = 15,
Sensor = 16,
Ads1220 = 17,
BatChan = 18,
Eeprom = 19,
Flash = 20,
MeChan = 21,
ReChan = 22,
DailyTimeSync = 23,
CpDriver = 24,
NvProcess = 25,
WaterStack = 26,
GasStack = 27,
WaterChannel = 28,
GasChannel = 29,
RectifierMonitorStack = 30,
AskDriver = 31,
UnlicensedFlexnet = 32,
Application = 33,
FlexNetV1Parser = 34,
SensusRfEndpoint = 35,
SensusRfMetrology = 36,
FlexNetV1Upgrade = 37,
FlexNetSerialUpgrade = 38,
UpgradeProcessFlexNetV1 = 39,
UpgradeProcessSerial = 40,
UpgradeImage = 41,
UpgradeFlasher = 42,
GasRegister = 43,
NfcTag = 44,
IrdaAdapter = 45,
Ui1236Slave = 46,
Na2wIrdaRegister = 47,
Na2wIrdaStack = 48,
Valve = 49,
SensusRfLink = 50,
Bq25713Driver = 51,
Bt121Driver = 52,
CommunicationDevice = 53,
WMBusStack = 54,
CriticalRead = 55,
FnUdp = 56,
WiredCommsStack = 57,
RawMetrologyChannel = 58,
WaterStackAgnostic = 59,
St25DvxxDriver = 60,
FskRailDriver = 61,
WaterStackEncoder = 62,
FbProcess = 63,
WMBusTracker = 64,
}
public enum ModuleID
{
ModuleID_Application = 33,
ModuleID_Sterling = 71,
}

View File

@ -0,0 +1,62 @@
# Program tbfDBBackup
Program is designed to backup, upgrade, compare and restore database.
Only for advanced users!
* Program is written in C# and .NET 8.0.
* Program is using MySql.Data.MySqlClient.
* Program using mysqldump.exe in some cases.
* Program is designed for Windows.
* Program is designed to use with MySQL.
## Program features
* Backup database.
* Upgrade database.
* Compare database.
* Restore database.
### Backup database.
We can use this program to define a backup procedure. Can work like a cron job, or services to run backup procedure.
### Upgrade database.
We can use this program to define an upgrade procedure. Can work cyclic or one time per run.
# Description about program parameters
The program operates as a command-line driver, accepting parameters to control its behavior.
## Configuration
When using a configuration file, the program can function autonomously, execute a single-use procedure, or encapsulate the operation as an opaque process.
## Dirrect commnad-line
### List of cmd commands
## Cmd Help
### Connect to database via cmd
```aiignore
mysql -h 127.0.0.1 -P 3306 -u root
```
Under database, we can create our own schema or use standard SQL syntax. For example:
```aiignore
"CREATE DATABASE slm-end;"
```
### Reload dump to new schema
```aiignore
PS C:\xampp\mysql\bin> Get-Content "C:\Users\micha\git\sensus\tbfDBBackup\tbfDBBackup\bin\Debug\net8.0\old.sql" |
>> .\mysql.exe -h 127.0.0.1 -P 3306 -u root --one-database slm-end
```
```aiignore
PS C:\xampp\mysql\bin> Get-Content "C:\Users\micha\git\sensus\tbfDBBackup\tbfDBBackup\bin\Debug\net8.0\old-r.sql" |
>> .\mysql.exe -h 127.0.0.1 -P 3306 -u root --one-database slm-end-r
```
##Release Examples
###Transitions tables to update
```aiignore
PS tbfDBBackup_Release> .\tbfDBBackup.exe update-by-schema slm50-250709-1549.sql schema-mapping-transition.json
```

View File

@ -0,0 +1,810 @@
using System.Diagnostics;
using NfcC7_DLL.NfcHanler.FieldLogicStaging;
using Sensus;
using Sensus.Protocols.FlexNet;
using Sensus.Protocols.FlexNet.FNv2;
using Sensus.Protocols.FlexNet.Serial;
using Sensus.Protocols.FlexNet.Serial.FNv2;
using NA2WProductType = Sensus.Protocols.FlexNet.NA2WProductType;
namespace NfcC7_DLL.NfcHanler
{
public delegate void TaskCompletionCallbackDelegate(Object task, bool successfullyCompleted);
public delegate void TaskProgressCallbackDelegate(Object task, Double percentDone, String statusString);
public delegate void TaskLogCallbackDelegate(Object task, EventNotification eventNotification);
class SerialFirmwareDownloadTask
{
private String fwFileName;
private Utils.FirmwareImage fwImage;
private MessageEngine messageEngine;
private TaskCompletionCallbackDelegate taskCompletionCallback;
private TaskProgressCallbackDelegate taskProgessCallback;
private ushort blocksPerCommand = 1;
private bool haltExecution;
private System.Threading.Timer timer;
private UInt16 currentBlock;
private UInt16 currentMissingBlock;
private UInt16[] missingBlock;
private UInt16 interBlockDelayMs = 300;
private UInt16 checkImageTimeOutMs = 15000;
private UInt16 loadStartTimeOutMs = 30000;
private UInt16 flashDeviceTimeOutMs = 15000;
public TaskProgressCallbackDelegate TaskProgressCallback
{
set
{
taskProgessCallback = value;
}
}
private enum AlgorithmState
{
IDLE,
BEGIN,
LOAD_START,
BLOCKS,
CHECK_IMAGE,
MISSING_BLOCKS,
FLASH,
CANCEL,
RESET
};
public bool AckLoadBlock { get; set; }
AlgorithmState timerState = AlgorithmState.IDLE;
bool waitingForAck = false;
UInt16 sessionId = 0;
Stopwatch stopwatch;
public SerialFirmwareDownloadTask(String fwFileName, MessageEngine messageEngine, ushort blocksPerCommand)
{
this.fwFileName = fwFileName;
this.fwImage = new Utils.FirmwareImage(fwFileName);
this.messageEngine = messageEngine;
this.blocksPerCommand = blocksPerCommand;
AckLoadBlock = true;
taskProgessCallback = null;
timer = new System.Threading.Timer(TimerCb, null, Timeout.Infinite, Timeout.Infinite);
}
public SerialFirmwareDownloadTask(String fwFileName, MessageEngine messageEngine) : this(fwFileName, messageEngine, 1)
{
}
public bool Start(TaskCompletionCallbackDelegate taskCompletionCallback)
{
bool retValue = false;
this.taskCompletionCallback = taskCompletionCallback;
if (messageEngine != null)
{
// Write to log upgrade details
Utility.Log.Write("" + System.Environment.NewLine);
Utility.Log.Write("# -----------------------------------------------------" + System.Environment.NewLine);
Utility.Log.Write("# Performing Firmware Upgrade to:" + System.Environment.NewLine);
Utility.Log.Write("# Filename\t\t= " + fwFileName + System.Environment.NewLine);
DeviceType devType = (DeviceType)fwImage.DeviceType;
Utility.Log.Write("# Device Type\t\t= " + fwImage.DeviceType.ToString() + " - " + devType.ToString() + System.Environment.NewLine);
if (fwImage.Version != null)
{
Utility.Log.Write("# FW Version\t\t= " + fwImage.Version.ToString() + System.Environment.NewLine);
Utility.Log.Write("# Compatability\t= " + fwImage.Compatibility.ToString() + System.Environment.NewLine);
NA2WProductType prodType = (NA2WProductType)fwImage.Compatibility;
Utility.Log.Write("# Product Type\t= " + fwImage.Compatibility + " - " + prodType.ToString() + System.Environment.NewLine);
}
Utility.Log.Write("# File CRC\t\t= " + fwImage.CRC.ToString() + " (" + fwImage.CRC.ToString("X8") + ")" + System.Environment.NewLine);
Utility.Log.Write("# File Size\t\t= " + fwImage.ImageSize.ToString() + System.Environment.NewLine);
Utility.Log.Write("# Num Blocks\t\t= " + fwImage.BlockCount.ToString() + System.Environment.NewLine);
Utility.Log.Write("# -----------------------------------------------------" + System.Environment.NewLine);
timerState = AlgorithmState.BEGIN;
timer.Change(500, Timeout.Infinite);
if (taskProgessCallback != null)
{
taskProgessCallback(this, 0, "Starting upgrade...");
}
if (DeviceType.SLCLightController == devType)
{
interBlockDelayMs = 150;
}
stopwatch = new Stopwatch();
stopwatch.Start();
retValue = true;
}
return retValue;
}
public void Cancel()
{
// TODO:
}
public void Reset()
{
// TODO:
}
public void Stop()
{
// Send a Cancel
timerState = AlgorithmState.RESET; // AlgorithmState.CANCEL;
// Signal to halt execution
//haltExecution = true;
// Signal completion but not successful
//FirmwareDownloadComplete(false);
}
private void TimerCb(object state)
{
if (haltExecution)
{
timerState = AlgorithmState.IDLE;
}
if (AlgorithmState.BEGIN == timerState)
{
SendLoadStartCmd();
}
else if (AlgorithmState.BLOCKS == timerState)
{
if (fwImage.BlockCount > currentBlock)
{
ISerialCommand blockLoadCommand;
// Send next block
if (blocksPerCommand <= 1)
{
blockLoadCommand = CreateLoadBlockCmd(currentBlock);
currentBlock++;
}
else
{
blockLoadCommand = CreateLoadBlockCmd(currentBlock, blocksPerCommand);
currentBlock += blocksPerCommand;
}
// Make sure currentBlock is not greater than block count
if (currentBlock > fwImage.BlockCount)
{
currentBlock = fwImage.BlockCount;
}
// Update task bar
if (taskProgessCallback != null)
{
Double percent = ((Double)currentBlock) * 100 / fwImage.BlockCount;
String statusString = "" + (currentBlock) + "/" + (fwImage.BlockCount - currentBlock);
taskProgessCallback(this, percent, statusString);
}
waitingForAck = true;
timer.Change(
(blocksPerCommand <= 1 ? interBlockDelayMs : 3 * interBlockDelayMs),
Timeout.Infinite
);
// Send message request
NA2WSerialFrame response = messageEngine.SendNa2wSerial(blockLoadCommand, true, (uint)(blocksPerCommand <= 1 ? interBlockDelayMs : 3 * interBlockDelayMs));
if (null != response)
{
ProcessReply(response);
}
}
else
{
timerState = AlgorithmState.CHECK_IMAGE;
timer.Change(checkImageTimeOutMs, Timeout.Infinite);
SendCheckImageCommand();
}
}
else if (AlgorithmState.CHECK_IMAGE == timerState)
{
timerState = AlgorithmState.CHECK_IMAGE;
timer.Change(checkImageTimeOutMs, Timeout.Infinite);
SendCheckImageCommand();
}
else if (AlgorithmState.MISSING_BLOCKS == timerState)
{
if (currentMissingBlock < missingBlock.Length)
{
// Send next block
ISerialCommand blockLoadCommand = CreateLoadBlockCmd(missingBlock[currentMissingBlock]);
// Send message request
NA2WSerialFrame response = messageEngine.SendNa2wSerial(blockLoadCommand, true);
// Update task bar
if (taskProgessCallback != null)
{
taskProgessCallback(this, 100, "Block Load backfill");
}
// Update state
currentMissingBlock++;
timer.Change(interBlockDelayMs, Timeout.Infinite);
if (null != response)
{
ProcessReply(response);
}
}
else
{
timerState = AlgorithmState.CHECK_IMAGE;
timer.Change(checkImageTimeOutMs, Timeout.Infinite);
SendCheckImageCommand();
}
}
else if (AlgorithmState.CANCEL == timerState)
{
timerState = AlgorithmState.IDLE;
timer.Change(500, Timeout.Infinite);
SendCancelCmd();
}
else if (AlgorithmState.RESET == timerState)
{
timerState = AlgorithmState.IDLE;
timer.Change(500, Timeout.Infinite);
SendResetCmd();
}
else
{
Utility.Log.Write("Timeout Occurred During Upgrade." + System.Environment.NewLine);
// Signal to halt execution
haltExecution = true;
// Signal completion but not successful
FirmwareDownloadComplete(false);
}
}
private void FirmwareDownloadComplete(bool successful)
{
timerState = AlgorithmState.IDLE;
timer.Change(Timeout.Infinite, Timeout.Infinite);
stopwatch.Stop();
// Get the elapsed time as a TimeSpan value.
TimeSpan ts = stopwatch.Elapsed;
// Format and display the TimeSpan value.
string elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}",
ts.Hours, ts.Minutes, ts.Seconds,
ts.Milliseconds / 10);
if (haltExecution || !successful)
{
Utility.Log.Write("" + System.Environment.NewLine);
Utility.Log.Write("# -----------------------------------------------------" + System.Environment.NewLine);
Utility.Log.Write("# Aborting Firmware Upgrade." + System.Environment.NewLine);
}
else if (successful)
{
Utility.Log.Write("");
Utility.Log.Write("# -----------------------------------------------------" + System.Environment.NewLine);
Utility.Log.Write("# Upgrade Completed Successfully." + System.Environment.NewLine);
}
else
{
Utility.Log.Write("");
Utility.Log.Write("# -----------------------------------------------------" + System.Environment.NewLine);
Utility.Log.Write("# Upgrade Completed Failed." + System.Environment.NewLine);
}
Utility.Log.Write("# " + elapsedTime + System.Environment.NewLine);
Utility.Log.Write("# -----------------------------------------------------" + System.Environment.NewLine);
if (taskCompletionCallback != null)
{
taskCompletionCallback(this, successful);
}
if (taskProgessCallback != null)
{
taskProgessCallback(this, 0, "");
}
}
private void ProcessReply(ClassicSerialMessageFrame message)
{
// Is this an Ack/Nck
if ((0x01 == message.MessageAddress) && (0x01 == message.PayloadLength))
{
byte commandCode = message.CommandCode;
// Is this an Ack
if (0x00 == (message.Payload[0] & 0x80))
{
// Message ACKed. React based on command type.
switch (commandCode)
{
case (0xb8):
{
if (AlgorithmState.LOAD_START == timerState)
{
// Load Start ACKed. Start sending blocks.
currentBlock = 0;
timerState = AlgorithmState.BLOCKS;
timer.Change(interBlockDelayMs, Timeout.Infinite);
}
else if (AlgorithmState.FLASH == timerState)
{
// Flash ACKed. We are done.
FirmwareDownloadComplete(true);
}
}
break;
case (0xb9):
{
if (AlgorithmState.BLOCKS == timerState)
{
if (waitingForAck)
{
waitingForAck = false;
// Force next load block to be sent
timer.Change(0, Timeout.Infinite);
}
}
}
break;
}
}
else
{
// Message NACKed. React based on command type.
switch (commandCode)
{
case (0xb8):
{
if (timerState == AlgorithmState.LOAD_START)
{
// Load Start NACKed. Cancel.
FirmwareDownloadComplete(false);
}
else if (AlgorithmState.FLASH == timerState)
{
// Flash NACKed. Cancel.
FirmwareDownloadComplete(false);
}
}
break;
}
}
}
else if ((0x01 == message.MessageAddress) && (0xb8 == message.CommandCode) && (0x02 == message.Payload[0]))
{
// Check image reponse. Subcommand in serial response field.
if (0x01 == message.PayloadLength)
{
// This is an ACK to the check image command. Assume ready to FLASH
timerState = AlgorithmState.FLASH;
timer.Change(flashDeviceTimeOutMs, Timeout.Infinite);
SendFlashImageCmd();
}
else
{
// Check Image response
byte numberOfRecords = message.Payload[1];
UInt16 firstMissingBlock = (UInt16)(message.Payload[2] + (message.Payload[3] << 8));
if (0 == numberOfRecords)
{
timerState = AlgorithmState.FLASH;
timer.Change(flashDeviceTimeOutMs, Timeout.Infinite);
SendFlashImageCmd();
}
else if ((1 == numberOfRecords) && (0xffff == firstMissingBlock))
{
Utility.Log.Write("" + System.Environment.NewLine);
Utility.Log.Write("# -----------------------------------------------------" + System.Environment.NewLine);
Utility.Log.Write("# CRC Mismatch. Download corrupted." + System.Environment.NewLine);
Utility.Log.Write("# -----------------------------------------------------" + System.Environment.NewLine);
FirmwareDownloadComplete(false);
}
else
{
missingBlock = new UInt16[numberOfRecords];
for (int i = 0; i < numberOfRecords; i++)
{
UInt16 block = (UInt16)(message.Payload[2 + 2 * i] + (message.Payload[3 + 2 * i] << 8));
missingBlock[i] = block;
}
currentMissingBlock = 0;
timerState = AlgorithmState.MISSING_BLOCKS;
timer.Change(interBlockDelayMs, Timeout.Infinite);
}
}
} // else if ((0x01 == frame.MessageAddress) && (0xb8 == frame.CommandCode) && (0x00 == frame.Payload[0]) && (0x02 == frame.Payload[1]))
else if ((0x01 == message.MessageAddress) && (0xb8 == message.CommandCode) && (0x16 == message.Payload.Length))
{
// Check image reponse with incorrect format from legacy products. No subcommand. Length is fixed to 0x16 bytes. Status
// in first byte. Rest of check image response (number of blocks) starts at second byte.
byte numberOfRecords = message.Payload[1];
UInt16 firstMissingBlock = (UInt16)(message.Payload[2] + (message.Payload[3] << 8));
if (0 == numberOfRecords)
{
timerState = AlgorithmState.FLASH;
timer.Change(flashDeviceTimeOutMs, Timeout.Infinite);
SendFlashImageCmd();
}
else if ((1 == numberOfRecords) && (0xffff == firstMissingBlock))
{
Utility.Log.Write("" + System.Environment.NewLine);
Utility.Log.Write("# -----------------------------------------------------" + System.Environment.NewLine);
Utility.Log.Write("# CRC Mismatch. Download corrupted." + System.Environment.NewLine);
Utility.Log.Write("# -----------------------------------------------------" + System.Environment.NewLine);
FirmwareDownloadComplete(false);
}
else
{
missingBlock = new UInt16[numberOfRecords];
for (int i = 0; i < numberOfRecords; i++)
{
UInt16 block = (UInt16)(message.Payload[2 + 2 * i] + (message.Payload[3 + 2 * i] << 8));
missingBlock[i] = block;
}
currentMissingBlock = 0;
timerState = AlgorithmState.MISSING_BLOCKS;
timer.Change(interBlockDelayMs, Timeout.Infinite);
}
} // else if ((0x01 == frame.MessageAddress) && (0xb8 == frame.CommandCode) && (0x00 == frame.Payload[0]) && (0x02 == frame.Payload[1]))
else if ((0x01 == message.MessageAddress) && (0xb8 == message.CommandCode) && (0x00 == message.Payload[0]) && (0x02 == message.Payload[1]))
{
// Check image reponse with incorrect format that was in early versions of Omni ER+ and Sonix IQ. Subcommand in byte after serial
// response field. Subcommand should be in serial response field.
if (0x02 == message.PayloadLength)
{
// This is an ACK to the check image command. Assume ready to FLASH
timerState = AlgorithmState.FLASH;
timer.Change(flashDeviceTimeOutMs, Timeout.Infinite);
SendFlashImageCmd();
}
else
{
// Check Image response
byte numberOfRecords = message.Payload[2];
UInt16 firstMissingBlock = (UInt16)(message.Payload[3] + (message.Payload[4] << 8));
if (0 == numberOfRecords)
{
timerState = AlgorithmState.FLASH;
timer.Change(flashDeviceTimeOutMs, Timeout.Infinite);
SendFlashImageCmd();
}
else if ((1 == numberOfRecords) && (0xffff == firstMissingBlock))
{
Utility.Log.Write("" + System.Environment.NewLine);
Utility.Log.Write("# -----------------------------------------------------" + System.Environment.NewLine);
Utility.Log.Write("# CRC Mismatch. Download corrupted." + System.Environment.NewLine);
Utility.Log.Write("# -----------------------------------------------------" + System.Environment.NewLine);
FirmwareDownloadComplete(false);
}
else
{
missingBlock = new UInt16[numberOfRecords];
for (int i = 0; i < numberOfRecords; i++)
{
UInt16 block = (UInt16)(message.Payload[3 + 2 * i] + (message.Payload[4 + 2 * i] << 8));
missingBlock[i] = block;
}
currentMissingBlock = 0;
timerState = AlgorithmState.MISSING_BLOCKS;
timer.Change(interBlockDelayMs, Timeout.Infinite);
}
}
} // else if ((0x01 == frame.MessageAddress) && (0xb8 == frame.CommandCode) && (0x00 == frame.Payload[0]) && (0x02 == frame.Payload[1]))
else if ((0x01 == message.MessageAddress) && (0xb8 == message.CommandCode) && (0x00 == message.Payload[0]) && (0x03 == message.Payload.Length))
{
// Load Flash ACK with time to flash value. Time value in Payload[1] and Payload[2]. For example: 1B 01 B8 03 00 19 00 F0 28
if (AlgorithmState.FLASH == timerState)
{
// Flash ACKed. We are done.
FirmwareDownloadComplete(true);
}
}
}
private void ProcessReply(NA2WSerialFrame message)
{
if (message.Payload is NetworkResponse)
{
NetworkResponse networkResponse = (NetworkResponse)message.Payload;
if (networkResponse.Payload is CommandErrorResponse)
{
Utility.Log.Write("" + System.Environment.NewLine);
Utility.Log.Write("# -----------------------------------------------------" + System.Environment.NewLine);
Utility.Log.Write("# Error." + System.Environment.NewLine);
Utility.Log.Write("# -----------------------------------------------------" + System.Environment.NewLine);
FirmwareDownloadComplete(false);
}
else if (networkResponse.Payload is FwMaintenanceResponse_MissingBlocks)
{
// Utility.Log.Write("Missing " + System.Environment.NewLine);
FwMaintenanceResponse_MissingBlocks missingBlocksRsp = (FwMaintenanceResponse_MissingBlocks)networkResponse.Payload;
// Check Image response
byte blockCount = missingBlocksRsp.BlockCount;
if (0 == blockCount)
{
timerState = AlgorithmState.FLASH;
timer.Change(flashDeviceTimeOutMs, Timeout.Infinite);
SendFlashImageCmd();
}
else if ((1 == blockCount) && (0xffff == missingBlocksRsp.Block[0]))
{
Utility.Log.Write("" + System.Environment.NewLine);
Utility.Log.Write("# -----------------------------------------------------" + System.Environment.NewLine);
Utility.Log.Write("# CRC Mismatch. Download corrupted." + System.Environment.NewLine);
Utility.Log.Write("# -----------------------------------------------------" + System.Environment.NewLine);
FirmwareDownloadComplete(false);
}
else
{
missingBlock = new UInt16[blockCount];
for (int i = 0; i < blockCount; i++)
{
missingBlock[i] = missingBlocksRsp.Block[i];
}
currentMissingBlock = 0;
timerState = (AlgorithmState.LOAD_START == timerState ? AlgorithmState.BLOCKS : AlgorithmState.MISSING_BLOCKS);
timer.Change(interBlockDelayMs, Timeout.Infinite);
}
} // else if (networkResponse.Payload is FwMaintenanceResponse_MissingBlocks)
else if (networkResponse.Payload is FwMaintenanceResponse_Status)
{
// Utility.Log.Write("Status " + System.Environment.NewLine);
FwMaintenanceResponse_Status status = (FwMaintenanceResponse_Status)networkResponse.Payload;
if ( ((AlgorithmState.BLOCKS == timerState) || ((AlgorithmState.MISSING_BLOCKS == timerState))) && (status.State == 1 /* Active */))
{
if (waitingForAck)
{
waitingForAck = false;
// Force next load block to be sent
timer.Change(0, Timeout.Infinite);
}
}
else if ((AlgorithmState.FLASH == timerState) && (status.State == 2 /* Flashing */))
{
// Flash ACKed. We are done.
FirmwareDownloadComplete(true);
}
}
}
}
private void SendLoadStartCmd()
{
FwMaintenance_LoadStartV1 fwLoadStart = new FwMaintenance_LoadStartV1();
fwLoadStart.DeviceType = (byte)fwImage.DeviceType;
fwLoadStart.ImageCrc = fwImage.CRC;
fwLoadStart.ImageSize = fwImage.ImageSize;
fwLoadStart.ProductType = fwImage.Compatibility;
fwLoadStart.ProductTypeVersion = fwImage.Version.ToShort().ReverseByteOrder();
timerState = AlgorithmState.LOAD_START;
timer.Change(loadStartTimeOutMs, Timeout.Infinite);
if (taskProgessCallback != null)
{
taskProgessCallback(this, 0, "Load Start Sent");
}
// Send message request
NA2WSerialFrame response = messageEngine.SendNa2wSerial(fwLoadStart, true, loadStartTimeOutMs);
if (null != response)
{
ProcessReply(response);
}
}
private ISerialCommand CreateLoadBlockCmd(UInt16 blockNum)
{
FwMaintenance_LoadBlockV1 firmwareBlockLoad = new FwMaintenance_LoadBlockV1();
firmwareBlockLoad.DeviceType = (byte)fwImage.DeviceType;
firmwareBlockLoad.ProductType = (byte)fwImage.Compatibility;
firmwareBlockLoad.BlockSize = 19;
int blockCount = 1;
firmwareBlockLoad.BlockCount = (byte)blockCount;
byte[] data = new byte[21];
int block = 0;
data.Write<UInt16>((UInt16)(blockNum + block), 0, 16);
Array.Copy(fwImage.Blocks[blockNum + block].ToArray(), 0, data, 2, 19);
firmwareBlockLoad.Payload = new Frame(data);
return firmwareBlockLoad;
}
private ISerialCommand CreateLoadBlockCmd(UInt16 blockNum, int blocksPerCommand)
{
FwMaintenance_LoadBlockV1 firmwareBlockLoad = new FwMaintenance_LoadBlockV1();
firmwareBlockLoad.DeviceType = (byte)fwImage.DeviceType;
firmwareBlockLoad.ProductType = (byte)fwImage.Compatibility;
firmwareBlockLoad.BlockSize = 19;
// Limit blocks based on number remaining
int blockCount = blocksPerCommand;
if (blockCount > fwImage.BlockCount - blockNum)
{
blockCount = fwImage.BlockCount - blockNum;
}
firmwareBlockLoad.BlockCount = (byte)blockCount;
byte[] data = new byte[blockCount * (2 + 19)];
// Copy blocks into payload
int block = 0;
for (; block < blockCount; block++)
{
data.Write<UInt16>((UInt16)(blockNum + block), (uint)(block * 21 * 8), 16);
Array.Copy(fwImage.Blocks[blockNum + block].ToArray(), 0, data, (21 * block) + 2, 19);
}
firmwareBlockLoad.Payload = new Frame(data);
return firmwareBlockLoad;
}
private void SendCheckImageCommand()
{
FwMaintenance_CheckImageV1 checkImage = new FwMaintenance_CheckImageV1();
checkImage.DeviceType = (byte)fwImage.DeviceType;
checkImage.ProductType = fwImage.Compatibility;
checkImage.ImageBlocks = fwImage.BlockCount;
checkImage.ImageCrc = fwImage.CRC;
if (taskProgessCallback != null)
{
taskProgessCallback(this, 100, "Check Image Sent");
}
// Send message request
NA2WSerialFrame response = messageEngine.SendNa2wSerial(checkImage, true);
if (null != response)
{
ProcessReply(response);
}
}
private void SendFlashImageCmd()
{
FwMaintenance_LoadFlashV1 loadFlash = new FwMaintenance_LoadFlashV1();
loadFlash.DeviceType = (byte)fwImage.DeviceType;
loadFlash.ProductType = fwImage.Compatibility;
loadFlash.ImageBlocks = fwImage.BlockCount;
loadFlash.ImageCrc = fwImage.CRC;
loadFlash.SegmentCount = fwImage.SegmentCount;
int numSegs = fwImage.SegmentCount;
byte[] segmentDescriptorData = new byte[0];
for (int seg = 0; seg < numSegs; seg++)
{
FwMaintenance_SegmentDescriptor segmentDescriptor = new FwMaintenance_SegmentDescriptor(
(uint)(fwImage.Segments[seg].Address),
(ushort)(fwImage.Segments[seg].BlockCount)
);
segmentDescriptorData = segmentDescriptorData.Concat(segmentDescriptor.ToBytes()).ToArray();
}
loadFlash.Payload = new Frame(segmentDescriptorData);
if (taskProgessCallback != null)
{
taskProgessCallback(this, 100, "Load Flash Sent");
}
// Send message request
NA2WSerialFrame response = messageEngine.SendNa2wSerial(loadFlash, true);
if (null != response)
{
ProcessReply(response);
}
}
private void SendCancelCmd()
{
FwMaintenance_CancelV1 cancel = new FwMaintenance_CancelV1();
cancel.DeviceType = (byte)fwImage.DeviceType;
cancel.ProductType = fwImage.Compatibility;
if (taskProgessCallback != null)
{
taskProgessCallback(this, 100, "Cancel Sent");
}
// Send message request
NA2WSerialFrame response = messageEngine.SendNa2wSerial(cancel, true);
if (null != response)
{
ProcessReply(response);
}
}
private void SendResetCmd()
{
FwMaintenance_ResetV1 reset = new FwMaintenance_ResetV1();
reset.DeviceType = (byte)fwImage.DeviceType;
reset.ProductType = fwImage.Compatibility;
if (taskProgessCallback != null)
{
taskProgessCallback(this, 100, "Reset Sent");
}
// Send message request
NA2WSerialFrame response = messageEngine.SendNa2wSerial(reset, true);
if (null != response)
{
ProcessReply(response);
}
}
}
}

View File

@ -0,0 +1,71 @@
namespace NfcC7_DLL.NfcHanler
{
class Session
{
public Session()
{
}
/// <summary>
/// Deserialize RF_Offsetts file
/// </summary>
/// <param name="filename">file to be deserialized</param>
/// <returns>object type RF_Offsetts with information read</returns>
public bool Load(string filename)
{
#if false
try
{
// Create an instance of the XmlSerializer specifying type and namespace.
XmlSerializer serializer = new XmlSerializer(typeof(ConfigurationData));
// A FileStream is needed to read the XML document.
FileStream fs = new FileStream(filename, FileMode.Open);
XmlReader reader = XmlReader.Create(fs);
// Use the Deserialize method to restore the object's state.
ConfigurationData = (ConfigurationData)serializer.Deserialize(reader);
fs.Close();
}
catch (Exception ex)
{
return false;
}
#endif
return true;
}
/// <summary>
/// Serialize RF_Offsetts object and save it to file
/// </summary>
/// <param name="settings">object to be serialized </param>
/// <param name="filename">File to write data to</param>
/// <returns>false on error</returns>
public bool Save(string filename)
{
#if false
try
{
XmlSerializer serializer = new XmlSerializer(typeof(ConfigurationData));
/* Create a StreamWriter to write with.
* First create a FileStream object, and create the StreamWriter specifying an Encoding to use. */
FileStream fs = new FileStream(filename, FileMode.Create);
TextWriter writer = new StreamWriter(fs, new UTF8Encoding());
// Serialize using the XmlTextWriter.
serializer.Serialize(writer, ConfigurationData);
writer.Close();
}
catch (Exception ex)
{
return false;
}
#endif
return true;
}
}
}

View File

@ -0,0 +1,390 @@
using NfcC7_DLL.NfcHanler.FieldLogicStaging;
using Sensus;
using Sensus.Protocols.FlexNet;
using Sensus.Protocols.FlexNet.FNv2;
using Sensus.Protocols.FlexNet.FNv2.NA2WParameters;
using Sensus.Protocols.FlexNet.Serial.FNv2;
namespace NfcC7_DLL.NfcHanler
{
public delegate void StatsLogCallbackDelegate(Object task, StatisticsEntry statisticsEntry);
public class ModuleStatisticsDescriptor
{
public UInt16 ModuleId { get; set; }
public Byte StatisticsRevision { get; set; }
public UInt16 NumberOfBytes { get; set; }
public byte[] Data { get; set; }
}
class StatsLogTask
{
private MessageEngine messageEngine;
private TaskCompletionCallbackDelegate taskCompletionCallback;
private TaskProgressCallbackDelegate taskProgessCallback;
private StatsLogCallbackDelegate taskLogCallback;
private bool haltExecution;
private System.Threading.Timer timer;
private List<ModuleStatisticsDescriptor> moduleDescriptorList = new List<ModuleStatisticsDescriptor>();
public TaskProgressCallbackDelegate TaskProgressCallback
{
set
{
taskProgessCallback = value;
}
}
public StatsLogCallbackDelegate TaskLogCallback
{
set
{
taskLogCallback = value;
}
}
private enum AlgorithmState
{
IDLE,
READ_SERIAL_NUMBER,
READ_OVERVIEW,
READ_STATISTICS
};
public bool AckLoadBlock { get; set; }
public UInt32 TimeFrame { get; set; }
AlgorithmState timerState = AlgorithmState.IDLE;
UInt16 moduleIndex = 0;
UInt64 serialNumber = 0;
public StatsLogTask(MessageEngine messageEngine)
{
this.messageEngine = messageEngine;
TimeFrame = 0xffffffff;
taskProgessCallback = null;
timer = new System.Threading.Timer(TimerCb, null, Timeout.Infinite, Timeout.Infinite);
}
public bool Start(TaskCompletionCallbackDelegate taskCompletionCallback)
{
bool retValue = false;
this.taskCompletionCallback = taskCompletionCallback;
moduleIndex = 0;
if (messageEngine != null)
{
// Write to log upgrade details
Utility.Log.Write("" + System.Environment.NewLine);
Utility.Log.Write("# -----------------------------------------------------" + System.Environment.NewLine);
Utility.Log.Write("# Extracting Statistics" + System.Environment.NewLine);
Utility.Log.Write("# -----------------------------------------------------" + System.Environment.NewLine);
if (taskProgessCallback != null)
{
taskProgessCallback(this, 0, "Starting...");
}
SendSessionQueryCmd();
timer.Change(1000, Timeout.Infinite);
retValue = true;
}
return retValue;
}
public void Stop()
{
// Signal to halt execution
haltExecution = true;
// Signal completion but not successful
ExtractComplete(false);
}
private void ExtractComplete(bool successful)
{
timerState = AlgorithmState.IDLE;
timer.Change(Timeout.Infinite, Timeout.Infinite);
if (haltExecution || !successful)
{
Utility.Log.Write("" + System.Environment.NewLine);
Utility.Log.Write("# -----------------------------------------------------" + System.Environment.NewLine);
Utility.Log.Write("# Aborting Statistics Extraction." + System.Environment.NewLine);
Utility.Log.Write("# -----------------------------------------------------" + System.Environment.NewLine);
}
else if (successful)
{
Utility.Log.Write("");
Utility.Log.Write("# -----------------------------------------------------" + System.Environment.NewLine);
Utility.Log.Write("# Statistics Extraction Completed Successfully." + System.Environment.NewLine);
Utility.Log.Write("# -----------------------------------------------------" + System.Environment.NewLine);
}
else
{
Utility.Log.Write("");
Utility.Log.Write("# -----------------------------------------------------" + System.Environment.NewLine);
Utility.Log.Write("# Statistics Extraction Failed." + System.Environment.NewLine);
Utility.Log.Write("# -----------------------------------------------------" + System.Environment.NewLine);
}
if (taskCompletionCallback != null)
{
taskCompletionCallback(this, successful);
}
if (taskProgessCallback != null)
{
taskProgessCallback(this, 0, moduleIndex.ToString() + " modules extracted");
}
}
private void TimerCb(object state)
{
if (timerState == AlgorithmState.READ_SERIAL_NUMBER)
{
SendSessionQueryCmd();
}
else if (timerState == AlgorithmState.READ_OVERVIEW)
{
SendStatisticsOverviewCmd();
}
else if (timerState == AlgorithmState.READ_STATISTICS)
{
SendModuleStatisticsCmd();
}
}
private void ProcessReply(NA2WSerialFrame message)
{
UnknownResponse unknownResponse = message.Unwrap<UnknownResponse>();
if ((null != unknownResponse) && (unknownResponse.CommandCode == 0x14))
{
byte[] payload = unknownResponse.Contents;
byte reportId = payload.Read<byte>(0);
switch (reportId)
{
case (0): // Statistics Overview
{
UInt16 moduleCount = payload.Read<UInt16>(8 * 4);
moduleDescriptorList = new List<ModuleStatisticsDescriptor>();
uint offset = 6;
int payloadBytes = (int)(payload.Length - offset);
while (payloadBytes >= 5)
{
UInt16 moduleId = payload.Read<UInt16>(8 * (offset));
Byte statisticsRevision = payload.Read<Byte>(8 * (offset + 2));
UInt16 numberOfBytes = payload.Read<UInt16>(8 * (offset + 3));
ModuleStatisticsDescriptor moduleDescriptor = new ModuleStatisticsDescriptor();
moduleDescriptor.ModuleId = moduleId;
moduleDescriptor.StatisticsRevision = statisticsRevision;
moduleDescriptor.NumberOfBytes = numberOfBytes;
moduleDescriptorList.Add(moduleDescriptor);
offset += 5;
payloadBytes -= 5;
}
SendModuleStatisticsCmd();
}
break;
case (1): // Module Statistics
{
ModuleStatisticsDescriptor moduleDescriptor = moduleDescriptorList[moduleIndex];
byte productType = payload.Read<byte>(8 * 1);
UInt16 moduleId = payload.Read<UInt16>(8 * 2);
if (moduleDescriptor.ModuleId == moduleId)
{
byte statisticsRevistion = payload.Read<byte>(8 * 4);
UInt16 byteOffset = payload.Read<UInt16>(8 * 5);
UInt16 byteCount = payload.Read<UInt16>(8 * 7);
if (null != moduleDescriptor.Data)
{
if (byteOffset == moduleDescriptor.Data.Length)
{
byte[] data = new byte[byteOffset + byteCount];
Array.Copy(moduleDescriptor.Data, 0, data, 0, moduleDescriptor.Data.Length);
Array.Copy(payload, 9, data, byteOffset, byteCount);
moduleDescriptor.Data = data;
}
}
else
{
byte[] data = new byte[byteCount];
Array.Copy(payload, 9, data, 0, byteCount);
moduleDescriptor.Data = data;
}
if (moduleDescriptor.NumberOfBytes == moduleDescriptor.Data.Length)
{
StatisticsEntry statisticsEntry = new StatisticsEntry();
statisticsEntry.Id = ((ModuleId)(moduleDescriptor.ModuleId)).ToString() + " (" + moduleDescriptor.ModuleId.ToString() + ")";
statisticsEntry.Revision = moduleDescriptor.StatisticsRevision.ToString();
statisticsEntry.ByteCount = moduleDescriptor.Data.Length.ToString();
statisticsEntry.Data = moduleDescriptor.Data.ToHexString();
taskLogCallback(this, statisticsEntry);
moduleIndex++;
}
SendModuleStatisticsCmd();
}
}
break;
}
if (moduleDescriptorList.Count == 0)
{
ExtractComplete(true);
}
}
else if (message.Payload is NetworkResponse)
{
NetworkResponse networkResponse = (NetworkResponse)message.Payload;
if (networkResponse.Payload is ParameterReadResponse)
{
ParameterReadResponse parameterReadResponse = (ParameterReadResponse)networkResponse.Payload;
if (parameterReadResponse.TagMap == TagMap.GlobalIPerl)
{
List<NA2WParameter> na2wParameterList = parameterReadResponse.Parameters;
foreach (NA2WParameter na2wParameter in na2wParameterList)
{
switch (na2wParameter.Tag)
{
case ((byte)GlobalIPerlTag.SerialNumber):
{
serialNumber = na2wParameter.Value.Read<UInt64>(0);
SendStatisticsOverviewCmd();
}
break;
default:
break;
}
}
}
}
}
}
private void SendSessionQueryCmd()
{
List<byte> tagList = new List<byte>();
tagList.Add((byte)GlobalIPerlTag.SerialNumber);
timerState = AlgorithmState.READ_SERIAL_NUMBER;
timer.Change(1000, Timeout.Infinite);
if (taskProgessCallback != null)
{
taskProgessCallback(this, 0, "Read Serial Number Sent");
}
// Send message request
ParameterReadCommand parameterReadCommand = new ParameterReadCommand(TagMap.GlobalIPerl, tagList);
NA2WSerialFrame response = messageEngine.SendNa2wSerial(parameterReadCommand, ParameterReadResponse._Code);
if (null != response)
{
ProcessReply(response);
}
}
private void SendStatisticsOverviewCmd()
{
DataReportRequest_StatisticsOverview statisticsOverview = new DataReportRequest_StatisticsOverview();
timerState = AlgorithmState.READ_OVERVIEW;
timer.Change(1000, Timeout.Infinite);
// Send message request
NA2WSerialFrame response = messageEngine.SendNa2wSerial(statisticsOverview, true);
if (taskProgessCallback != null)
{
taskProgessCallback(this, 0, "Statistics Overview sent");
}
if (null != response)
{
ProcessReply(response);
}
}
private void SendModuleStatisticsCmd()
{
if (moduleDescriptorList.Count > moduleIndex)
{
ModuleStatisticsDescriptor moduleDescriptor = moduleDescriptorList[moduleIndex];
uint byteOffset = 0;
uint numberOfBytes = moduleDescriptor.NumberOfBytes;
if (null != moduleDescriptor.Data)
{
byteOffset = (uint)moduleDescriptor.Data.Length;
numberOfBytes -= (uint)moduleDescriptor.Data.Length;
}
if (numberOfBytes > 100)
{
numberOfBytes = 100;
}
DataReportRequest_ModuleStatistics moduleStatistics = new DataReportRequest_ModuleStatistics();
moduleStatistics.ModuleId = moduleDescriptor.ModuleId;
moduleStatistics.ByteOffset = (ushort)byteOffset;
moduleStatistics.ByteCount = (ushort)numberOfBytes;
timerState = AlgorithmState.READ_STATISTICS;
timer.Change(1000, Timeout.Infinite);
// Send message request
NA2WSerialFrame response = messageEngine.SendNa2wSerial(moduleStatistics, true);
if (taskProgessCallback != null)
{
taskProgessCallback(this, 0, moduleIndex.ToString() + " events extracted");
}
if (null != response)
{
ProcessReply(response);
}
}
else
{
ExtractComplete(true);
}
}
}
}

View File

@ -0,0 +1,14 @@
namespace NfcC7_DLL.NfcHanler;
public enum SterlingDriverError
{
SterlingDvr_Error_BlockInvalid = -5, //< A block read from the hardware was invalid. Potential comms or hardware failure.
SterlingDvr_Error_ResetFailed = -4, //< The reset of the hardware failed. This is a critical error!
SterlingDvr_Error_Timeout = -3, //< A timeout of some kind occurred in the driver
SterlingDvr_Error_CommsFailure = -2, //< A communications failure occurred between the host micro and the hardware
SterlingDvr_Error_ConfigInvalid = -1, //< Configuration did not pass validation
SterlingDvr_Error_None = 0, //< No errors reported on the last operation
SterlingDvr_Error_StateAlreadyValid = 1, //< The state was already valid so a function was most than likely called twice
SterlingDvr_Error_Retried = 2, //< The operation succeeded but required a retry at some point
}

View File

@ -1,4 +1,5 @@
using System.Text;
using System.Security.Cryptography;
using System.Text;
namespace NfcC7_DLL.NfcHanler.Utils
@ -518,7 +519,7 @@ namespace NfcC7_DLL.NfcHanler.Utils
public static Boolean verifyGFTsha(BinaryReader bRdr)
{
using (SHA256Cng fileSHA = new SHA256Cng())
using (SHA256 fileSHA = SHA256.Create())
{
bRdr.BaseStream.Position = 0;
byte[] computedSHA = fileSHA.ComputeHash(bRdr.ReadBytes(sha256Chunk.numBytesInSHA));
@ -661,7 +662,7 @@ namespace NfcC7_DLL.NfcHanler.Utils
// SHA-256 starts at numBytesInSignature + 1 because the verification block version number is fisrt
Array.Copy(decompBlockData, numBytesInSignature + 1, verfBuf, 0, _SIG_LEN/2);
using (SHA256Cng blockSHA = new SHA256Cng())
using (SHA256 blockSHA = SHA256.Create())
{
byte[] computedSHA = blockSHA.ComputeHash(decompBlockData, 0, numBytesInSignature);
for (int i = 0; i < computedSHA.Length; i++)

View File

@ -0,0 +1,87 @@
namespace NfcC7_DLL.NfcHanler
{
public enum WMBusDeviceType
{
Other = 0x00,
Oil = 0x01,
Electricity = 0x02,
Gas = 0x03,
Head = 0x04,
Stream = 0x05,
WarmWater_30_90 = 0x06,
Water = 0x07,
HeatCostAllocator = 0x08,
#if false
static String (self):
if (self.address[5] >= 0x40):
return 'Reserved'
return {
0x00: 'Other',
0x01: 'Oil',
0x02: 'Electricity',
0x03: 'Gas',
0x04: 'Head',
0x05: 'Steam ',
0x06: 'Warm water (30-90 °C)',
0x07: 'Water ',
0x08: 'Heat cost allocator ',
0x09: 'Compressed air ',
0x0A: 'Cooling load meter (Volume measured at return temperature: outlet)',
0x0B: 'Cooling load meter (Volume measured at flow temperature: inlet)',
0x0C: 'Heat (Volume measured at flow temperature: inlet)',
0x0D: 'Heat / Cooling load meter',
0x0E: 'Bus / System component',
0x0F: 'Unknown medium',
0x10: 'Reserved for consumption meter',
0x11: 'Reserved for consumption meter',
0x12: 'Reserved for consumption meter',
0x13: 'Reserved for consumption meter',
0x14: 'Calorific value',
0x15: 'Hot water ( 90 °C)',
0x16: 'Cold water',
0x17: 'Dual register (hot/cold) water meter',
0x18: 'Pressure',
0x19: 'A/D Converter',
0x1A: 'Smoke detector',
0x1B: 'Room sensor (eg temperature or humidity)',
0x1C: 'Gas detector',
0x1D: 'Reserved for sensors',
0x1F: 'Reserved for sensors',
0x20: 'Breaker (electricity)',
0x21: 'Valve (gas or water)',
0x22: 'Reserved for switching devices',
0x23: 'Reserved for switching devices',
0x24: 'Reserved for switching devices',
0x25: 'Customer unit (display device)',
0x26: 'Reserved for customer units',
0x27: 'Reserved for customer units',
0x28: 'Waste water',
0x29: 'Garbage',
0x2A: 'Reserved for Carbon dioxide',
0x2B: 'Reserved for environmental meter',
0x2C: 'Reserved for environmental meter',
0x2D: 'Reserved for environmental meter',
0x2E: 'Reserved for environmental meter',
0x2F: 'Reserved for environmental meter',
0x30: 'Reserved for system devices',
0x31: 'Reserved for communication controller',
0x32: 'Reserved for unidirectional repeater',
0x33: 'Reserved for bidirectional repeater',
0x34: 'Reserved for system devices',
0x35: 'Reserved for system devices',
0x36: 'Radio converter (system side)',
0x37: 'Radio converter (meter side)',
0x38: 'Reserved for system devices',
0x39: 'Reserved for system devices',
0x3A: 'Reserved for system devices',
0x3B: 'Reserved for system devices',
0x3C: 'Reserved for system devices',
0x3D: 'Reserved for system devices',
0x3E: 'Reserved for system devices',
0x3F: 'Reserved for system devices'
}.get(self.address[5], 'get_device_type(): type unknown')
#endif
}
}

View File

@ -3,6 +3,7 @@ using System.ComponentModel;
using System.Text.Json;
using System.Text.Json.Serialization;
using NfcC7_DLL.NfcHanler;
using NfcC7_DLL.NfcHanler.Utils;
using ICommand = System.Windows.Input.ICommand;
namespace NfcC7_DLL