eregister prüfung abschlus ~

This commit is contained in:
Stoyan Zlatev
2024-12-06 15:18:49 +01:00
parent a385f35efd
commit d8c2d776a5
48 changed files with 1368 additions and 413 deletions
@@ -74,5 +74,8 @@
<ItemGroup>
<Content Include="test.txt" />
</ItemGroup>
<ItemGroup>
<Folder Include="Tasks\" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>
+118 -9
View File
@@ -1,24 +1,133 @@
namespace CommonConsole
{
using Common.Hardware.Ports;
using Common.Hardware.SIRT;
using Common.Hardware.SIRT.Parameters;
using Common.Hardware.WaterMeter.eRegister;
using Common.Hardware.WaterMeter.eRegister.Features;
using Newtonsoft.Json;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
public class Program
{
public static void Main()
{
byte val = 31;
// 1 1 1 1 1 0 0 0
var y = val.GetBitsLE().GetByteLE(0, 3);
var x = 0;
x ^= (byte)(val >> 0);
x ^= (byte)(val >> 1);
x ^= (byte)(val >> 2);
foreach (var property in typeof(Pam).GetFields(BindingFlags.Public | BindingFlags.Static))
{
Console.WriteLine($"{property.Name}: {property.GetValue(null)}");
}
Console.WriteLine(y);
//var client = new SIRTClient("COM6");
//client.OpenConnection();
//Console.ReadKey();
//client.CloseConnection();
}
}
public class SIRTClient
{
private readonly ConcurrentDictionary<uint, EregisterTask> activateable;
private readonly ConcurrentDictionary<uint, EregisterTask> tasks;
private readonly SIRTBroadcaster broadcaster;
public SIRTClient(string comPort)
{
this.activateable = new ConcurrentDictionary<uint, EregisterTask>(new Dictionary<uint, EregisterTask>
{
// 433
{ 875770417, null },
{ 4291267283, null },
{ 4291317405, null },
// 868
// { 4291631647, null },
});
this.tasks = new ConcurrentDictionary<uint, EregisterTask>();
this.broadcaster = new SIRTBroadcaster(comPort);
this.broadcaster.Activated += this.Broadcaster_Activated;
this.broadcaster.Connected += this.Broadcaster_Connected;
this.broadcaster.Disconnected += this.Broadcaster_Disconnected;
this.broadcaster.Logging += this.Broadcaster_Logging;
this.broadcaster.MessageReceived += this.Broadcaster_MessageReceived;
}
internal void CloseConnection()
{
this.broadcaster.Close();
}
internal void OpenConnection()
{
this.broadcaster.Open();
}
private void Broadcaster_Activated()
{
Console.WriteLine(nameof(Broadcaster_Activated));
foreach (var kvp in this.activateable)
{
this.tasks.GetOrAdd(kvp.Key, _ =>
{
var task = new EregisterTask(433, 3000)
{
Cmd = SIRTMessage.W_PAM,
P1 = new P811
{
DelPamSemi = true,
},
Data = new OpticalTelegram
{
Minutes = 1
}.Append(new ProvidePin
{
AuthLevel = AuthLevel.III
}),
RequestAddress = kvp.Key
};
task.Completed += this.Task_Completed;
this.broadcaster.EnqueueTask(task);
return task;
});
}
}
private void Broadcaster_Connected()
{
Console.WriteLine(nameof(Broadcaster_Connected));
}
private void Broadcaster_Disconnected()
{
Console.WriteLine(nameof(Broadcaster_Disconnected));
}
private void Broadcaster_Logging(string message)
{
}
private void Broadcaster_MessageReceived(SIRTMessage message)
{
}
private void Task_Completed(SIRTTask task)
{
task.Completed -= this.Task_Completed;
Console.WriteLine($"Task_Completed: {task}");
File.WriteAllText($"..\\..\\Tasks\\{task.RequestAddress}.json", JsonConvert.SerializeObject(task, new JsonSerializerSettings
{
Formatting = Formatting.Indented
}));
}
}
}
@@ -32,6 +32,7 @@
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="Newtonsoft.Json, Version=6.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL" />
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
@@ -1,7 +1,7 @@
namespace Common.Hardware.SIRT.Parameters
{
using Common.Hardware.Ports;
using System;
using System.Text;
public class PAMStatus
@@ -60,6 +60,8 @@
public static byte OK = 0;
public static byte EXPIREDAUTH = 4;
public static implicit operator byte(PAMStatus status)
=> status?.bits?.GetByteLE() ?? 0xFF;
@@ -28,5 +28,9 @@
public double Dbm { get; }
public double Percent { get; }
public override string ToString() => $"{this.Dbm}dBm ({this.Percent:0.0}%)";
public static implicit operator string(RSSI rssi) => rssi?.ToString();
}
}
@@ -33,12 +33,12 @@
}
else
{
this.Logging?.Invoke($"SIRT on {this.COMPort} not identified.");
// this.Logging?.Invoke($"SIRT on {this.COMPort} not identified.");
}
}
else
{
this.Logging?.Invoke($"SIRT on {this.COMPort} not activated.");
// this.Logging?.Invoke($"SIRT on {this.COMPort} not activated.");
}
}
@@ -72,26 +72,37 @@
private void OnStateChanged(SIRTTask task)
{
if (task.State != SIRTTaskState.Cancelled)
if (task.State == SIRTTaskState.Completed)
{
this.TaskRemoveEventHandlers(task);
if (this.tasks.TryGetValue(task.RequestAddress, out var requestTasks))
{
requestTasks.TryDequeue(out var _);
if (requestTasks.TryDequeue(out var _))
{
this.TaskRemoveEventHandlers(task);
}
}
else if (this.tasks.TryGetValue(task.ResponseAddress, out var responseTasks))
{
responseTasks.TryDequeue(out var _);
if (responseTasks.TryDequeue(out var _))
{
this.TaskRemoveEventHandlers(task);
}
}
}
else if (task.State == SIRTTaskState.Cancelled)
{
this.TaskRemoveEventHandlers(task);
this.OnTaskTimeout(task);
}
}
private void OnTaskTimeout(SIRTTask task)
{
var deleteRequestAddress = SIRTTask.DeleteFromPamPool(task.RequestAddress);
this.TryRun(deleteRequestAddress);
var deleteResponseAddress = SIRTTask.DeleteFromPamPool(task.ResponseAddress);
this.TryRun(deleteResponseAddress);
}
private void OnTaskUpdated(SIRTTask task)
@@ -100,13 +111,7 @@
{
foreach (var _task in tasksQueue.AsEnumerable())
{
if (_task.State != SIRTTaskState.Pending)
{
_task.P1 = task.P1;
_task.P2 = task.P2;
_task.RequestAddress = task.RequestAddress;
_task.ResponseAddress = task.ResponseAddress;
}
_task.UpdateFrom(task);
}
}
}
@@ -116,8 +121,8 @@
this.cancellationTokenSource = new CancellationTokenSource();
this.cancellationToken = this.cancellationTokenSource.Token;
Task.Factory.StartNew((Action)this.StartReadingMessages, this.cancellationToken);
Task.Factory.StartNew((Action)this.ActivateSIRT, this.cancellationToken);
Task.Factory.StartNew(this.StartReadingMessages, this.cancellationToken);
Task.Factory.StartNew(this.ActivateSIRT, this.cancellationToken);
this.Connected?.Invoke();
}
@@ -136,8 +141,10 @@
this.Disconnected?.Invoke();
}
private void SerialPort_Logging(string e)
=> this.Logging?.Invoke(e);
private void SerialPort_Logging(string e)
{
//this.Logging?.Invoke(e);
}
private void SIRTConnection_MessageReceived(SIRTMessage message)
{
@@ -146,10 +153,9 @@
if (tasksQueue.TryPeek(out var task))
{
task.PushResponse(message);
this.Logging?.Invoke(message.ToString());
}
}
this.Logging?.Invoke(message.ToString());
}
private void StartProcessingTasksAsync()
@@ -165,18 +171,15 @@
foreach (var tasksQueue in connection.tasks.Values.ToArray())
{
if (tasksQueue.TryPeek(out var task))
{
if (task.State == SIRTTaskState.Pending)
{
connection.serialPort.Write(task.Start());
this.Logging?.Invoke(task.ToString());
}
}
totalTasksCount += tasksQueue.Count;
await Task.Delay(10);
if (tasksQueue.TryPeek(out var task) && task.State == SIRTTaskState.Pending)
{
connection.serialPort.Write(task.Start());
this.Logging?.Invoke(task.ToString());
}
await Task.Delay(50);
}
if (totalTasksCount <= 0)
@@ -298,7 +301,7 @@
task.Completed += taskStateChanged;
this.serialPort.Write(task.Start());
this.Logging?.Invoke(task.ToString());
// this.Logging?.Invoke(task.ToString());
manualResetEventSlim.Wait(task.Timeout);
manualResetEventSlim.Reset();
@@ -80,7 +80,7 @@
if (task.RequestAddress != task.ResponseAddress)
{
this.tasks.AddOrUpdate(task.ResponseAddress, requestTasks, (k, v) => requestTasks);
this.tasks.AddOrUpdate(task.ResponseAddress, requestTasks, (_, _requestTasks) => _requestTasks);
}
if (!this.processingWaitHandle.IsSet)
@@ -10,7 +10,7 @@
private readonly ConcurrentDictionary<string, SIRTBroadcaster> connections
= new ConcurrentDictionary<string, SIRTBroadcaster>();
public event Action<string> Log;
public event Action<string> Logging;
public void CloseConnection(string portName)
{
@@ -52,12 +52,13 @@
if (this.connections.TryAdd(comPort, connection))
{
connection.Logging += message => this.Log?.Invoke(message);
connection.Logging += message => this.Logging?.Invoke(message);
connection.Open();
}
else
{
connection = null;
this.Logging?.Invoke($"Cann't connect SIRT to {comPort}");
}
}
@@ -1,8 +1,7 @@
namespace Common.Hardware.SIRT
{
using Common.Hardware.Ports;
using Common.Hardware.SIRT.Parameters;
using Newtonsoft.Json;
using System;
public class SIRTMessage
@@ -62,6 +61,7 @@
public byte Length => this.bytes[8];
[JsonIgnore]
public byte[] Data
{
get
@@ -89,6 +89,8 @@
public ushort CRC => this.bytes.ToUInt16BE(this.bytes.Length - 3);
public string Content => this.ToString();
public byte[] ToByteArray()
{
var length = this.bytes.Length;
@@ -23,7 +23,7 @@
internal class AnswerTask : SIRTTask
{
public AnswerTask() : base(0, 3000)
public AnswerTask() : base(0, 1000)
{
}
@@ -6,8 +6,8 @@
public partial class SIRTTask
{
protected readonly ConcurrentStack<SIRTMessage> responses;
protected readonly SIRTMessage request;
public readonly ConcurrentStack<SIRTMessage> responses;
public readonly SIRTMessage request;
protected readonly Timer timeoutTimer;
public SIRTTask(int frequency, int timeout = 5_000)
@@ -33,7 +33,7 @@
public byte Cmd
{
get => this.request.Cmd;
protected set => this.request.Cmd = value;
set => this.request.Cmd = value;
}
public byte P1
@@ -74,27 +74,42 @@
public void PushResponse(SIRTMessage response)
{
var address = response.Address;
if (address == this.RequestAddress || address == this.ResponseAddress)
if (this.State == SIRTTaskState.Cancelled)
{
this.responses.Push(response);
return;
}
if (address == this.ResponseAddress)
this.responses.Push(response);
if (response.Length >= 13)
{
var responseAddress = response.Address;
if (responseAddress != this.RequestAddress)
{
var requestAddress = this.RequestAddress;
this.RequestAddress = this.ResponseAddress;
this.ResponseAddress = requestAddress;
this.NotifyUpdated();
}
this.ProcessResponse(response);
}
this.ProcessResponse(response);
}
public virtual byte[] ToByteArray() => this.request.ToByteArray();
public override string ToString() => BitConverter.ToString(this.ToByteArray());
public virtual void UpdateFrom(SIRTTask task)
{
this.P1 = task.P1;
this.P2 = task.P2;
this.RequestAddress = task.RequestAddress;
this.ResponseAddress = task.ResponseAddress;
}
protected void NotifyCancelled() => this.Cancelled?.Invoke(this);
protected void NotifyCompleted() => this.Completed?.Invoke(this);
@@ -5,9 +5,6 @@
Pending = 0,
Running = 1,
Completed = 2,
Timeouted = 3,
Cancelled = 4,
ErrorSEMI = 5,
ErrorP11 = 6,
Cancelled = 4
}
}
@@ -0,0 +1,10 @@
namespace Common.Hardware.WaterMeter.eRegister.Attributes
{
using System;
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public class ComparePropertyAttribute : Attribute
{
}
}
@@ -0,0 +1,9 @@
namespace Common.Hardware.WaterMeter.eRegister.Attributes
{
using System;
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public class EregisterFeatureAttribute : Attribute
{
}
}
@@ -56,11 +56,13 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Attributes\EregisterFeatureAttribute.cs" />
<Compile Include="Eregister.cs" />
<Compile Include="EregisterBatch.cs" />
<Compile Include="EregisterCheckFinalizationTask.cs" />
<Compile Include="EregisterCheckInitializationTask.cs" />
<Compile Include="EregisterExtensions.cs" />
<Compile Include="EregisterCheckStateTask.cs" />
<Compile Include="EregisterTask.cs" />
<Compile Include="Features\ActivateMetrologyTestMode.cs" />
<Compile Include="Features\AlarmPersistence.cs" />
@@ -139,9 +141,10 @@
<Compile Include="Features\SingleBytePam.cs" />
<Compile Include="Features\WakeUpMode.cs" />
<Compile Include="Features\WirelessMBusMode.cs" />
<Compile Include="Models\ComparePropertyAttribute.cs" />
<Compile Include="Attributes\ComparePropertyAttribute.cs" />
<Compile Include="Models\EregisterDebugFeatures.cs" />
<Compile Include="Models\EregisterFeatures.cs" />
<Compile Include="Models\EregisterAvailableParametersParser.cs" />
<Compile Include="Models\EregisterProgrammingParameters.cs" />
<Compile Include="Models\EregisterProgrammingParametersList.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
@@ -134,10 +134,23 @@
this.runningTasks.Clear();
var frequency = this.features.Frequency;
var pams = this.features.BuildPams();
var wakeUP = true;
foreach (var pam in pams)
this.runningTasks.Enqueue(new EregisterCheckStateTask(frequency)
{
SlotNr = this.features.SlotNr,
PoNr = this.features.PoNr,
SerialNr = this.features.SerialNr,
P1 = new P811
{
DelPamSemi = true,
WakeUpCmd = true,
},
RequestAddress = this.features.RequestAddress,
ResponseAddress = this.features.ResponseAddress,
EncryptionKey = this.features.EncryptionKey
});
foreach (var pam in this.features.BuildPamsFull())
{
this.runningTasks.Enqueue(new EregisterTask(frequency)
{
@@ -148,15 +161,12 @@
P1 = new P811
{
DelPamSemi = true,
WakeUpCmd = wakeUP,
},
RequestAddress = this.features.RequestAddress,
ResponseAddress = this.features.ResponseAddress,
Data = pam.Value,
EncryptionKey = this.features.EncryptionKey
});
wakeUP = false;
}
}
}
@@ -10,12 +10,12 @@
public class EregisterBatch
{
private readonly SIRTFactory broadcaster;
private readonly SIRTFactory sirtFactory;
private readonly ICollection<Eregister> eregisters;
public EregisterBatch(SIRTFactory broadcaster)
{
this.broadcaster = broadcaster;
this.sirtFactory = broadcaster;
this.eregisters = new List<Eregister>();
}
@@ -26,10 +26,10 @@
foreach (var parameters in parametersList)
{
var features = parameters.LoadCustomFeatures();
var eregister = new Eregister(features, this.broadcaster.EnqueueTask);
var eregister = new Eregister(features, this.sirtFactory.EnqueueTask);
this.broadcaster.DequeueTasks(features.RequestAddress);
this.broadcaster.DequeueTasks(features.ResponseAddress);
this.sirtFactory.DequeueTasks(features.RequestAddress);
this.sirtFactory.DequeueTasks(features.ResponseAddress);
this.eregisters.Add(eregister);
yield return eregister.LoadCustomTasks(parameters);
@@ -43,10 +43,10 @@
foreach (var parameters in parametersList)
{
var features = parameters.LoadInspectionFinalizationFeatures();
var eregister = new Eregister(features, this.broadcaster.EnqueueTask);
var eregister = new Eregister(features, this.sirtFactory.EnqueueTask);
this.broadcaster.DequeueTasks(features.RequestAddress);
this.broadcaster.DequeueTasks(features.ResponseAddress);
this.sirtFactory.DequeueTasks(features.RequestAddress);
this.sirtFactory.DequeueTasks(features.ResponseAddress);
this.eregisters.Add(eregister);
yield return eregister.LoadInspectionFinalizationTasks(parameters);
@@ -60,10 +60,10 @@
foreach (var parameters in parametersList)
{
var features = parameters.LoadInspectionInitializationFeatures();
var eregister = new Eregister(features, this.broadcaster.EnqueueTask);
var eregister = new Eregister(features, this.sirtFactory.EnqueueTask);
this.broadcaster.DequeueTasks(features.RequestAddress);
this.broadcaster.DequeueTasks(features.ResponseAddress);
this.sirtFactory.DequeueTasks(features.RequestAddress);
this.sirtFactory.DequeueTasks(features.ResponseAddress);
this.eregisters.Add(eregister);
yield return eregister.LoadInspectionInitializationTasks(parameters);
@@ -86,7 +86,7 @@
{
foreach (var eregister in this.eregisters)
{
this.broadcaster.DequeueTasks(eregister.Address);
this.sirtFactory.DequeueTasks(eregister.Address);
eregister.Clear();
}
@@ -2,8 +2,10 @@
{
using Common.Hardware.Ports;
using Common.Hardware.SIRT;
using Common.Hardware.WaterMeter.eRegister.Attributes;
using Common.Hardware.WaterMeter.eRegister.Features;
using Common.Hardware.WaterMeter.eRegister.Models;
using System;
using System.Linq;
using System.Reflection;
@@ -20,7 +22,8 @@
this.requestParameters = requestParameters;
this.pendingState = SIRTTaskState.Completed;
this.Name = "Final Check";
this.Data = new RequestDebugTelegram();
this.Data = new OpticalTelegram { Minutes = 0 }
.Append(new ProvidePin { AuthLevel = AuthLevel.III });
}
protected override void EndProcessResponse(SIRTMessage response)
@@ -43,14 +46,27 @@
foreach (var property in comparebleProperties)
{
var requestValue = property.GetValue(this.requestParameters);
var responseValue = property.GetValue(responseParameters);
var requestValue = $"{property.GetValue(this.requestParameters)}"
.ToString()
.Trim('\0')
.Trim();
var responseValue = $"{property.GetValue(responseParameters)}"
.ToString()
.Trim('\0')
.Trim();
if ($"{requestValue}".Trim('\0').Trim() != $"{responseValue}".Trim('\0').Trim())
if (requestValue != responseValue)
{
errors += $"- {property.Name}: request value {requestValue} != response value {responseValue}{Environment.NewLine}";
}
}
var volumeDifference = Math.Abs((int)this.requestParameters.DisplayVolume - (int)responseParameters.DisplayVolume);
if (volumeDifference > 10)
{
errors += $"- {nameof(this.requestParameters.DisplayVolume)}: request value {this.requestParameters.DisplayVolume} != response value {responseParameters.DisplayVolume}{Environment.NewLine}";
}
}
if (errors.Length > 0)
@@ -97,7 +113,7 @@
OffsetFactor = (byte)this.DEBUG.OffsetFactor, // TODO: normalize debug or parameter value
OffsetTime = this.DEBUG.OffsetTime,
FactoryCalibration = (byte)(this.DEBUG.FactoryCalibration * 10), // TODO: normalize debug or parameter value
UnitsOfMessure = (byte)this.SEMI.Units, // TODO: normalize debug or parameter value
UnitsOfMessureSEMI = (byte)this.SEMI.Units, // TODO: normalize debug or parameter value
MeterSize = this.SEMI.MeterSize,
Alarm_Backflow = alarms.Backflow,
Alarm_Broken_Pipe = alarms.BrokenPipe,
@@ -18,11 +18,9 @@
{
this.parameters = parameters;
this.pendingState = SIRTTaskState.Completed;
this.Name = "Programming Check";
this.Data = new OpticalTelegram
{
Minutes = 1
};
this.Name = "Initial Check";
this.Data = new OpticalTelegram { Minutes = 0, } // parameters.LED_On_Minutes }
.Append(new ProvidePin { AuthLevel = AuthLevel.III });
}
protected override void EndProcessResponse(SIRTMessage response)
@@ -32,6 +30,7 @@
if (this.State == this.pendingState)
{
this.State = SIRTTaskState.Running;
this.Name = "Initial Check - ✓";
var message = new StringBuilder();
message.AppendLine();
@@ -113,6 +112,7 @@
{
Minutes = 0
};
this.Name = "Initial Check ✘";
this.NotifyTimeouted();
}
@@ -0,0 +1,34 @@
namespace Common.Hardware.WaterMeter.eRegister
{
using Common.Hardware.SIRT;
using Common.Hardware.SIRT.Parameters;
using Common.Hardware.WaterMeter.eRegister.Telegrams;
public class EregisterCheckStateTask : EregisterTask
{
public EregisterCheckStateTask(int frequency)
: base(frequency)
=> this.Name = "Check State";
protected override void ProcessResponse(SIRTMessage response)
{
base.ProcessResponse(response);
if (this.SEMI != null)
{
var isEncrypted = this.IsEncrypted;
this.IsEncrypted = this.SEMI.PAMStatus == PAMStatus.OK && this.SEMI.Crc != 0;
if (this.IsEncrypted != isEncrypted)
{
var data = response.Data.DecryptResponse(this.EncryptionKey);
this.SEMI = new SEMI(data, this.Frequency, response.P1);
this.Label = this.SEMI.PAMStatus.ToString();
this.NotifyTelegram(this.SEMI);
this.NotifyUpdated();
}
}
}
}
}
@@ -114,6 +114,93 @@
});
}
public static IEnumerable<KeyValuePair<string, byte[]>> BuildPamsFull(this EregisterFeatures eregister)
{
var pamList = new List<KeyValuePair<string, byte[]>>();
var debugList = new List<KeyValuePair<string, byte[]>>();
var pamNames = new Dictionary<byte, string>();
var pamAttribute = default(PamAttribute);
var cmd = default(byte);
var bytes = default(byte[]);
var value = default(object);
foreach (var field in typeof(Pam).GetFields(BindingFlags.Public | BindingFlags.Static))
{
value = field.GetValue(null);
if (value is byte cmdByte)
{
pamNames[cmdByte] = field.Name;
}
}
foreach (var eregisterProperty in typeof(EregisterFeatures).GetProperties())
{
pamAttribute = eregisterProperty.GetCustomAttribute<PamAttribute>();
if (pamAttribute is null)
{
continue;
}
value = eregisterProperty.GetValue(eregister);
if (value is null)
{
continue;
}
if (eregisterProperty.Name == nameof(eregister.Debug))
{
var debugValue = default(object);
foreach (var debugProperty in typeof(EregisterDebugFeatures).GetProperties())
{
debugValue = debugProperty.GetValue(value);
if (debugValue is null)
{
continue;
}
if (debugValue is Pam pam)
{
pam.Append(new ProvidePin { AuthLevel = pamAttribute.AuthLevel });
bytes = pam.ToByteArray();
cmd = bytes[0];
if (pamNames.TryGetValue(cmd, out var name))
{
debugList.Add(new KeyValuePair<string, byte[]>($"{cmd} - {debugProperty.Name}", bytes));
}
}
}
}
else if (value is Pam pam)
{
pam.Append(new ProvidePin { AuthLevel = pamAttribute.AuthLevel });
bytes = pam.ToByteArray();
cmd = bytes[0];
if (pamNames.TryGetValue(cmd, out var name))
{
pamList.Add(new KeyValuePair<string, byte[]>($"{cmd} - {eregisterProperty.Name}", bytes));
}
}
}
var sortedPams = pamList
.OrderBy(x => x.Value[0])
.ToList();
var sortedDebugs = debugList
.OrderByDescending(x => x.Value[2])
.ToList();
sortedPams.AddRange(sortedDebugs);
return sortedPams;
}
public static byte[] AuthBytes(this AuthLevel authLevel)
{
var bytes = new byte[] { };
@@ -1,8 +1,9 @@
namespace Common.Hardware.WaterMeter.eRegister
{
using Common.Hardware.Ports;
using Common.Hardware.SIRT;
using Common.Hardware.SIRT.Parameters;
using Common.Hardware.WaterMeter.eRegister.Features;
using Common.Hardware.WaterMeter.eRegister.Models;
using Common.Hardware.WaterMeter.eRegister.Telegrams;
using System;
@@ -10,11 +11,16 @@
public class EregisterTask : SIRTTask
{
public EregisterTask(int frequency, int timeout = 5_000)
: base(frequency, timeout)
=> this.Cmd = SIRTMessage.W_PAM;
public EregisterTask(int frequency, int timeout = 6_000)
: base(frequency, timeout)
{
this.Cmd = SIRTMessage.W_PAM;
this.RSSI = new RSSI(0, frequency);
this.Label = nameof(SIRTTaskState.Pending);
}
public event Action<EregisterTask> Changed;
public event Action<object> Telegram;
public int SlotNr { get; internal set; }
@@ -40,17 +46,40 @@
public DEBUG DEBUG { get; private set; }
public SEMI SEMI { get; private set; }
public SEMI SEMI { get; protected set; }
public bool IsEncrypted { get; set; }
public byte[] EncryptionKey { get; set; }
public StateModes Mode { get; set; }
public override void UpdateFrom(SIRTTask task)
{
base.UpdateFrom(task);
if (task is EregisterTask etask)
{
this.Mode = etask.Mode;
this.IsEncrypted = etask.IsEncrypted;
if (this.Mode == StateModes.Shipment)
{
this.Data = new EregisterAvailableParametersParser(this.Data);
}
}
}
public override byte[] ToByteArray()
{
var data = this.request.Data;
if (this.IsEncrypted)
// if (this.SEMI?.PAMStatus?.WRONG_AUTH == true || this.Mode == StateModes.Shipment)
{
data = new EregisterAvailableParametersParser(data);
}
if (this.IsEncrypted || this.Mode == StateModes.Shipment)
{
data = data.EncryptRequest(this.EncryptionKey, this.RequestAddress);
}
@@ -88,21 +117,11 @@
var dataLength = data?.Length ?? 0;
this.P11 = new P11(response.P1);
this.RSSI = SEMI.CalculateRSSI(response.P2, (ushort)this.Frequency);
this.RSSI = new RSSI(response.P2, (ushort)this.Frequency);
if (dataLength > 0)
{
var type = data[0];
var crc = data.ToInt16BE(dataLength - 2);
if (!this.IsEncrypted)
{
this.IsEncrypted = (type <= SIRTMessage.LAT && crc != 0)
|| (type == SIRTMessage.DEBUG && dataLength >= 53)
|| (type == SIRTMessage.SEMI && dataLength >= 93);
this.NotifyUpdated();
}
if (this.IsEncrypted)
{
@@ -113,26 +132,30 @@
{
this.Label = nameof(SIRTMessage.BUP);
this.BUP = new BUP(data, this.P11);
this.NotifyTelegram(this.BUP);
}
else if (type == SIRTMessage.LAT)
{
this.Label = nameof(SIRTMessage.LAT);
this.LAT = new LAT(data, this.P11);
this.NotifyTelegram(this.LAT);
}
else if (type == SIRTMessage.DEBUG)
{
this.Label = nameof(SIRTMessage.DEBUG);
this.DEBUG = new DEBUG(data, this.P11);
this.NotifyTelegram(this.DEBUG);
this.Mode = (StateModes)(this.DEBUG.FactoryState - 1);
this.IsEncrypted = this.Mode == StateModes.Shipment;
this.NotifyUpdated();
}
else if (type == SIRTMessage.SEMI)
{
this.SEMI = new SEMI(data, this.Frequency, this.P11);
this.Label = this.SEMI.PAMStatus.ToString();
this.ProcessSEMI(data);
if (this.SEMI.PAMStatus == PAMStatus.OK)
if (this.State == SIRTTaskState.Completed || this.State == SIRTTaskState.Cancelled)
{
this.State = SIRTTaskState.Completed;
this.EndProcessResponse(response);
}
}
@@ -152,10 +175,54 @@
this.Label = "NA";
}
this.Changed?.Invoke(this);
this.NotifyChanged();
}
protected virtual void EndProcessResponse(SIRTMessage response)
=> base.ProcessResponse(response);
protected void NotifyChanged() => this.Changed?.Invoke(this);
protected void NotifyTelegram(object value) => this.Telegram?.Invoke(value);
private void ProcessSEMI(byte[] data)
{
this.SEMI = new SEMI(data, this.Frequency, this.P11);
if (this.SEMI.PAMStatus == PAMStatus.OK)
{
this.State = SIRTTaskState.Completed;
this.Label = this.SEMI.PAMStatus.ToString();
}
else
{
var isEncrypted = this.IsEncrypted;
this.IsEncrypted = this.SEMI.Crc != 0;
if (this.IsEncrypted != isEncrypted)
{
data = data.DecryptResponse(this.EncryptionKey);
}
this.SEMI = new SEMI(data, this.Frequency, this.P11);
if (this.SEMI.PAMStatus == PAMStatus.OK)
{
this.State = SIRTTaskState.Completed;
this.Label = this.SEMI.PAMStatus.ToString();
}
else if (this.SEMI.PAMStatus == PAMStatus.EXPIREDAUTH)
{
this.State = SIRTTaskState.Cancelled;
this.Label = this.SEMI.PAMStatus.ToString();
this.timeoutTimer.Stop();
}
this.Label = this.SEMI.PAMStatus.ToString();
}
this.NotifyTelegram(this.SEMI);
this.NotifyUpdated();
}
}
}
@@ -3,10 +3,15 @@
public enum MessurementUnits : byte
{
CubicMeters = 0,
m3 = 19,
CubicFeet = 1,
CF = 35,
USGallons = 4,
GAL = 24,
ImperialGallons = 5,
IGAL = 144,
AcreFeet = 6,
Kiloliters = 7
Kiloliters = 7,
kl = 19,
}
}
@@ -5,14 +5,17 @@
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public class PamAttribute : Attribute
{
public PamAttribute(AuthLevel authLevel, bool isSingleCmd = false)
public PamAttribute(AuthLevel authLevel, bool isSingleCmd = false, bool onlyProductionMode = false)
{
this.AuthLevel = authLevel;
this.IsSingleCmd = isSingleCmd;
this.OnlyProductionMode = onlyProductionMode;
}
public AuthLevel AuthLevel { get; }
public bool IsSingleCmd { get; }
public bool OnlyProductionMode { get; }
}
}
@@ -22,7 +22,7 @@
{
var bytes = BitConverter.GetBytes((UInt64)value);
Array.Copy(bytes, 0, this.bytes, 1, 5);
Array.Copy(bytes, 1, this.bytes, 1, 5);
}
}
}
@@ -1,12 +0,0 @@
namespace Common.Hardware.WaterMeter.eRegister.Models
{
using System.ComponentModel.DataAnnotations;
public class ComparePropertyAttribute : ValidationAttribute
{
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
return base.IsValid(value, validationContext);
}
}
}
@@ -0,0 +1,125 @@
namespace Common.Hardware.WaterMeter.eRegister.Models
{
using System.Collections.Generic;
public class EregisterAvailableParametersParser : List<byte>
{
public EregisterAvailableParametersParser(byte[] bytes)
{
var bytesLength = bytes.Length;
var available = default(bool);
var cmdLength = default(int);
var index = default(int);
while (bytesLength > index)
{
var cmd = bytes[index++];
_ = EregisterAvailableParametersParser.cmdLengths.TryGetValue(cmd, out cmdLength);
_ = cmdAvailableAfterSeal.TryGetValue(cmd, out available);
if (available)
{
this.Add(cmd);
}
for (var i = 0; i < cmdLength; i++)
{
if (available)
{
this.Add(bytes[index]);
}
index++;
}
}
}
public static implicit operator byte[] (EregisterAvailableParametersParser parser) => parser.ToArray();
private static readonly IDictionary<byte, bool> cmdAvailableAfterSeal = new Dictionary<byte, bool>
{
{ 0, true },
{ 1, false },
{ 2, true },
{ 3, false },
{ 4, true },
{ 5, true },
{ 6, true },
{ 7, true },
{ 10, true },
{ 11, true },
{ 12, false },
{ 14, true },
{ 16, true },
{ 17, true },
{ 19, true },
{ 20, true },
{ 21, true },
{ 22, false },
{ 31, true },
{ 32, true },
{ 33, true },
{ 48, false },
{ 49, false },
{ 50, true },
{ 51, true },
{ 52, true },
{ 53, true },
{ 54, false },
{ 64, true },
{ 65, true },
{ 66, true },
{ 67, true },
{ 68, true },
{ 69, true },
{ 72, true },
{ 73, true },
{ 80, true },
{ 108, true },
{ 146, false },
};
private static readonly IDictionary<byte, int> cmdLengths = new Dictionary<byte, int>
{
{ 0, 1 },
{ 1, 1 },
{ 2, 1 },
{ 3, 1 },
{ 4, 1 },
{ 5, 1 },
{ 6, 1 },
{ 7, 1 },
{ 10, 1 },
{ 11, 1 },
{ 12, 1 },
{ 14, 1 },
{ 16, 2 },
{ 17, 2 },
{ 19, 2 },
{ 20, 2 },
{ 21, 2 },
{ 22, 2 },
{ 31, 2 },
{ 32, 3 },
{ 33, 2 },
{ 48, 4 },
{ 49, 4 },
{ 50, 4 },
{ 51, 4 },
{ 52, 4 },
{ 53, 4 },
{ 54, 4 },
{ 64, 5 },
{ 65, 5 },
{ 66, 5 },
{ 67, 5 },
{ 68, 6 },
{ 69, 6 },
{ 72, 7 },
{ 73, 7 },
{ 80, 9 },
{ 108, 16 },
{ 146, 16 },
};
}
}
@@ -4,52 +4,52 @@
public class EregisterDebugFeatures
{
[Pam(AuthLevel.III, true)]
[Pam(AuthLevel.III, isSingleCmd: true)]
public RequestDebugTelegram RequestDebugTelegram { get; set; }
[Pam(AuthLevel.III, true)]
[Pam(AuthLevel.III, isSingleCmd: true)]
public ChangeState ChangeState { get; set; }
[Pam(AuthLevel.III, true)]
[Pam(AuthLevel.III, isSingleCmd: true)]
public ResetCredits ResetCredits { get; set; }
[Pam(AuthLevel.III, true)]
[Pam(AuthLevel.III, isSingleCmd: true)]
public DisableCredits DisableCredits { get; set; }
[Pam(AuthLevel.III, true)]
[Pam(AuthLevel.III, isSingleCmd: true)]
public SerialOutput SerialOutput { get; set; }
[Pam(AuthLevel.III, true)]
[Pam(AuthLevel.III, isSingleCmd: true)]
public SetAlarms SetAlarm { get; set; }
[Pam(AuthLevel.III, true)]
[Pam(AuthLevel.III, isSingleCmd: true)]
public SetSpecificError SetSpecificError { get; set; }
[Pam(AuthLevel.III, true)]
[Pam(AuthLevel.III, isSingleCmd: true)]
public OpticalTelegram OpticalTelegram { get; set; }
[Pam(AuthLevel.III, true)]
[Pam(AuthLevel.III, isSingleCmd: true)]
public FactoryComplete FactoryComplete { get; set; }
[Pam(AuthLevel.III, true)]
[Pam(AuthLevel.III, isSingleCmd: true)]
public EnableCredits EnableCredits { get; set; }
[Pam(AuthLevel.III, true)]
[Pam(AuthLevel.III, isSingleCmd: true)]
public SetBatteryUsageTestOffset SetBatteryUsageTestOffset { get; set; }
[Pam(AuthLevel.III, true)]
[Pam(AuthLevel.III, isSingleCmd: true)]
public SetTestFastActivityBupTiming SetTestFastActivityBupTiming { get; set; }
[Pam(AuthLevel.III, true)]
[Pam(AuthLevel.III, isSingleCmd: true)]
public SetActivityCreditLimits SetActivityCreditLimits { get; set; }
[Pam(AuthLevel.III, true)]
[Pam(AuthLevel.III, isSingleCmd: true)]
public SetActivationByThreshold SetActivationByThreshold { get; set; }
[Pam(AuthLevel.III, true)]
[Pam(AuthLevel.III, isSingleCmd: true)]
public DisableOTAFirmwareUpdate DisableOTAFirmwareUpdate { get; set; }
[Pam(AuthLevel.III, true)]
[Pam(AuthLevel.III, isSingleCmd: true)]
public SetMeterType SetMeterType { get; set; }
}
}
@@ -23,14 +23,11 @@
[Pam(AuthLevel.II)]
public ChangeWakeUp ChangeWakeUp { get; set; }
[Pam(AuthLevel.O)]
public SetPowerLevel SetPowerLevelSensusRF0 { get; set; }
[Pam(AuthLevel.O)]
public SetPowerLevel SetPowerLevelFlexNet0 { get; set; }
[Pam(AuthLevel.O, onlyProductionMode: true)]
public SetPowerLevel SetPowerLevelSensusRF { get; set; }
[Pam(AuthLevel.III)]
public SetPowerLevel SetPowerLevelFlexNetIII { get; internal set; }
public SetPowerLevel SetPowerLevelFlexNet { get; internal set; }
[Pam(AuthLevel.II)]
public ChangeNumberOfLatWindows ChangeNumberOfLatWindows { get; set; }
@@ -38,7 +35,7 @@
[Pam(AuthLevel.I)]
public ResetAlarms ResetAlarms { get; set; }
[Pam(AuthLevel.II, true)]
[Pam(AuthLevel.II, isSingleCmd: true)]
public DeactivateTransmitter DeactivateTransmiter { get; set; }
[Pam(AuthLevel.II)]
@@ -59,7 +56,7 @@
[Pam(AuthLevel.I)]
public SetHistoricalErrorLimit SetHistoricalErrorLimit { get; set; }
[Pam(AuthLevel.III, true)]
[Pam(AuthLevel.III, isSingleCmd: true)]
public Reset Reset { get; set; }
[Pam(AuthLevel.II)]
@@ -68,31 +65,31 @@
[Pam(AuthLevel.II)]
public OpenMeteringTransmitionIntervalWMBus OpenMeteringTransmitionIntervalWMBus { get; set; }
[Pam(AuthLevel.III, true)]
[Pam(AuthLevel.III, isSingleCmd: true)]
public SendBubbleUpBurst SendBubbleUpBurst { get; set; }
[Pam(AuthLevel.III, true)]
[Pam(AuthLevel.III, isSingleCmd: true)]
public SetFrequencyOffset SetFrequencyOffset { get; set; }
[Pam(AuthLevel.I)]
public ActivateMetrologyTestMode ActivateMetrologyTestMode { get; set; }
[Pam(AuthLevel.III)]
[Pam(AuthLevel.III, onlyProductionMode: true)]
public SetRebootCount SetRebootCount { get; set; }
[Pam(AuthLevel.III, true)]
[Pam(AuthLevel.III, isSingleCmd: true)]
public EregisterDebugFeatures Debug { get; set; }
[Pam(AuthLevel.O)]
public ChangeFixedDateReadingSettings ChangeFixedDateReadingSettings { get; set; }
[Pam(AuthLevel.II, true)]
[Pam(AuthLevel.II, isSingleCmd: true)]
public GetCustomerDebug GetCustomerDebug { get; set; }
[Pam(AuthLevel.III)]
[Pam(AuthLevel.III, onlyProductionMode: true)]
public ChangeMeterReading ChangeMeterReading { get; set; }
[Pam(AuthLevel.III)]
[Pam(AuthLevel.III, onlyProductionMode: true)]
public ChangeMeterId ChangeMeterId { get; set; }
[Pam(AuthLevel.I)]
@@ -107,37 +104,37 @@
[Pam(AuthLevel.III)]
public ChangeRadioId ChangeRadioId { get; set; }
[Pam(AuthLevel.III)]
[Pam(AuthLevel.III, onlyProductionMode: true)]
public SetPcbId SetPcbId { get; set; }
[Pam(AuthLevel.O, true)]
[Pam(AuthLevel.O, isSingleCmd: true)]
public RequestFixedDateReading RequestFixedDateReading { get; set; }
[Pam(AuthLevel.O, true)]
[Pam(AuthLevel.O, isSingleCmd: true)]
public RequestLoggingData RequestLoggingData { get; set; }
[Pam(AuthLevel.I, true)]
[Pam(AuthLevel.I, isSingleCmd: true)]
public ChangePin ChangePinI { get; set; }
[Pam(AuthLevel.II, true)]
[Pam(AuthLevel.II, isSingleCmd: true)]
public ChangePin ChangePinII { get; set; }
[Pam(AuthLevel.III, true)]
[Pam(AuthLevel.III, isSingleCmd: true)]
public ChangePin ChangePinIII { get; set; }
[Pam(AuthLevel.O)]
public ProvidePin ProvidePin { get; set; }
[Pam(AuthLevel.III, true)]
[Pam(AuthLevel.III, isSingleCmd: true)]
public SendTestPattern SendTestPattern { get; set; }
[Pam(AuthLevel.III, true)]
[Pam(AuthLevel.III, isSingleCmd: true)]
public RequestMemoryDump RequestMemoryDump { get; set; }
[Pam(AuthLevel.III, true)]
[Pam(AuthLevel.III, isSingleCmd: true)]
public SendSequenceOfTestTelegrams SendSequenceOfTestTelegrams { get; set; }
[Pam(AuthLevel.III, true)]
[Pam(AuthLevel.III, isSingleCmd: true)]
public ReceiveSequenceOfTestTelegrams ReceiveSequenceOfTestTelegrams { get; set; }
[Pam(AuthLevel.II)]
@@ -152,10 +149,10 @@
[Pam(AuthLevel.O)]
public SetTFXParameters SetTFXParameters { get; set; }
[Pam(AuthLevel.III, true)]
[Pam(AuthLevel.III, isSingleCmd: true, onlyProductionMode: true)]
public SetMetrologyParameters SetMetrologyParameters { get; set; }
[Pam(AuthLevel.O, true)]
[Pam(AuthLevel.O, isSingleCmd: true)]
public Ping Ping { get; set; }
[Pam(AuthLevel.III)]
@@ -1,6 +1,7 @@
namespace Common.Hardware.WaterMeter.eRegister.Models
{
using Common.Hardware.Ports;
using Common.Hardware.WaterMeter.eRegister.Attributes;
using Common.Hardware.WaterMeter.eRegister.Features;
using Common.Hardware.WaterMeter.eRegister.Telegrams;
@@ -69,9 +70,11 @@
[CompareProperty]
public byte LATWindowsFinalization { get; set; }
public byte UnitsOfMessure { get; set; }
[CompareProperty]
public byte UnitsOfMessure { get; set; }
public byte UnitsOfMessureSEMI { get; set; }
public byte DecimalPoint { get; set; }
@@ -209,8 +212,7 @@
public float UTC_Offset { get; set; }
public byte Wake_Up_Interval { get; set; }
[CompareProperty]
public uint DisplayVolume { get; set; }
public bool Encrypted { get; set; }
@@ -232,42 +234,43 @@
[CompareProperty]
public string CustomerSpecificText { get; set; }
internal EregisterFeatures LoadCustomFeatures()
=> new EregisterFeatures
public bool Sealed { get; set; }
public uint RequestAddress => (uint)(this.TempAdresse % 10_000_000_000);
public uint ResponseAddress => (uint)(this.Adresse % 10_000_000_000);
internal EregisterFeatures LoadCustomFeatures()
{
var features = new EregisterFeatures
{
SlotNr = this.Slotno,
SerialNr = this.SerienNr,
PoNr = this.FertigungsauftragNr,
RequestAddress = (uint)(this.TempAdresse % 10_000_000_000),
ResponseAddress = (uint)(this.Adresse % 10_000_000_000),
RequestAddress = this.RequestAddress,
ResponseAddress = this.ResponseAddress,
Frequency = this.Frequency,
Sealed = this.Encrypted,
EncryptionKey = this.EncryptionKey.GetEncryptionKey(),
ActivateMetrologyTestMode = new ActivateMetrologyTestMode
//ChangeWakeUp = new ChangeWakeUp
//{
// WakeUpMode = WakeUpMode.StayAwake
//},
//ChangeNumberOfLatWindows = new ChangeNumberOfLatWindows
//{
// N = 1
//},
//ChangeTransmissionInterval = new ChangeTransmissionInterval
//{
// Seconds = 1
//}
ChangeRadioId = new ChangeRadioId
{
Mode = 0
},
Reset = new Reset
{
Mode = 0
},
Debug = new EregisterDebugFeatures
{
RequestDebugTelegram = new RequestDebugTelegram
{
},
ChangeState = new ChangeState
{
Mode = StateModes.Production
},
OpticalTelegram = new OpticalTelegram
{
Minutes = 1
}
Address = this.ResponseAddress
}
};
return features;
}
internal EregisterFeatures LoadInspectionFinalizationFeatures()
{
@@ -276,10 +279,9 @@
SlotNr = this.Slotno,
SerialNr = this.SerienNr,
PoNr = this.FertigungsauftragNr,
RequestAddress = (uint)(this.TempAdresse % 10_000_000_000),
ResponseAddress = (uint)(this.Adresse % 10_000_000_000),
RequestAddress = this.RequestAddress,
ResponseAddress = this.ResponseAddress,
Frequency = this.Frequency,
Sealed = this.Encrypted,
EncryptionKey = this.EncryptionKey.GetEncryptionKey(),
};
@@ -288,21 +290,33 @@
return features;
}
features.ChangeRadioId = new ChangeRadioId(this.ResponseAddress);
features.ChangeMeterId = new ChangeMeterId(this.MeterId);
features.ChangeMeterReading = new ChangeMeterReading((uint)this.DisplayVolume);
features.SetPowerLevelSensusRF0 = new SetPowerLevel
features.ChangeMeterReading = new ChangeMeterReading(this.DisplayVolume);
features.SetPowerLevelSensusRF = new SetPowerLevel
{
Value = (byte)(this.PowerLevelHex & 127)
};
features.SetPowerLevelFlexNet0 = new SetPowerLevel
features.SetPowerLevelFlexNet = new SetPowerLevel
{
Value = (byte)(this.PowerLevelHex | 128)
};
features.SetPowerLevelFlexNetIII = new SetPowerLevel
features.Debug = new EregisterDebugFeatures
{
Value = (byte)(this.PowerLevelHex | 128)
DisableOTAFirmwareUpdate = new DisableOTAFirmwareUpdate
{
Mode = (OTAMode)this.DisableOTA
},
SetActivationByThreshold = new SetActivationByThreshold
{
Rotations = this.ActivationByThreshold
},
ChangeState = new ChangeState
{
Mode = StateModes.Shipment
}
};
features.ChangeRadioId = new ChangeRadioId((uint)(this.Adresse % 10_000_000_000));
features.DeactivateAlarms = new DeactivateAlarms
{
Backflow = this.Alarm_Backflow,
@@ -315,7 +329,10 @@
SpecificError = this.Alarm_Specific_Error,
};
features.ResetAlarms = new ResetAlarms(0xFF);
features.ChangeCustomerText = new ChangeCustomerText();
features.ChangeCustomerText = new ChangeCustomerText
{
Text = this.CustomerSpecificText
};
features.ParameterizeLeakageDetection = new ParameterizeLeakageDetection
{
Value = (byte)(this.LeakagePeriod | (this.LeakageThreshold * (byte)Math.Pow(2, 3)))
@@ -370,21 +387,6 @@
}
};
features.WirelessMBusMode = new WirelessMBusMode(this.MBusStatus);
features.Debug = new EregisterDebugFeatures
{
DisableOTAFirmwareUpdate = new DisableOTAFirmwareUpdate
{
Mode = (OTAMode)this.DisableOTA
},
//SetActivationByThreshold = new SetActivationByThreshold
//{
// Rotations = this.ActivationByThreshold
//},
//ChangeState = new ChangeState
//{
// Mode = StateModes.Shipment
//}
};
features.OpenMeteringTransmitionIntervalWMBus = new OpenMeteringTransmitionIntervalWMBus
{
Seconds = this.OpenMeteringTransmissionIntervalSeconds
@@ -407,41 +409,40 @@
internal EregisterFeatures LoadInspectionInitializationFeatures()
{
var address = (uint)(this.Adresse % 10_000_000_000);
var tempAddress = (uint)(this.TempAdresse % 10_000_000_000);
var features = new EregisterFeatures
{
SlotNr = this.Slotno,
SerialNr = this.SerienNr,
PoNr = this.FertigungsauftragNr,
RequestAddress = tempAddress,
ResponseAddress = address,
RequestAddress = this.RequestAddress,
ResponseAddress = this.ResponseAddress,
Frequency = this.Frequency,
EncryptionKey = this.EncryptionKey.GetEncryptionKey(),
ChangeWakeUp = new ChangeWakeUp(WakeUpMode.StayAwake),
ChangeTransmissionInterval = new ChangeTransmissionInterval(this.TransmissionIntervalInitialization),
ChangeNumberOfLatWindows = new ChangeNumberOfLatWindows(this.LatWindowsInitialization),
WirelessMBusMode = new WirelessMBusMode(this.MBusStatus),
ChangeMeterReading = new ChangeMeterReading(111111111),
SetMetrologyParameters = new SetMetrologyParameters
};
features.ChangeWakeUp = new ChangeWakeUp(WakeUpMode.StayAwake);
features.ChangeTransmissionInterval = new ChangeTransmissionInterval(this.TransmissionIntervalInitialization);
features.ChangeNumberOfLatWindows = new ChangeNumberOfLatWindows(this.LatWindowsInitialization);
features.WirelessMBusMode = new WirelessMBusMode(this.MBusStatus);
features.ChangeMeterReading = new ChangeMeterReading(111111111);
features.SetMetrologyParameters = new SetMetrologyParameters
{
UseCandIRules = this.Use_CandI_Rules == 1,
DecimalPoint = (DecimalPointLocations)this.DecimalPoint,
FactoryCalibration = this.FactoryCalibration,
MeterSize = this.MeterSize,
OffsetFactor = this.OffsetFactor,
OffsetTime = this.OffsetTime,
Units = (MessurementUnits)this.UnitsOfMessure,
Vpp = this.VolumePerPulse,
VppLED = (uint)this.VolumePerLedPulse
};
features.Debug = new EregisterDebugFeatures
{
SetMeterType = new SetMeterType
{
UseCandIRules = this.Use_CandI_Rules == 1,
DecimalPoint = (DecimalPointLocations)this.DecimalPoint,
FactoryCalibration = this.FactoryCalibration,
MeterSize = this.MeterSize,
OffsetFactor = this.OffsetFactor,
OffsetTime = this.OffsetTime,
Units = (MessurementUnits)this.UnitsOfMessure,
Vpp = this.VolumePerPulse,
VppLED = (uint)this.VolumePerLedPulse
Type = (MeterTypes)this.Use_CandI_Rules
},
Debug = new EregisterDebugFeatures
{
SetMeterType = new SetMeterType
{
Type = (MeterTypes)this.Use_CandI_Rules
}
}
};
return features;
@@ -6,6 +6,6 @@
m3 = 19,
CF = 35,
GAL = 24,
IGAL = 144
IGAL = 144,
}
}
@@ -12,7 +12,7 @@
public SEMI(byte[] payload, int mhz, P11 p11) : base(payload, p11)
{
this.PAMStatus = new PAMStatus(payload[11]);
this.RSSI = CalculateRSSI(payload[12], mhz);
this.RSSI = new RSSI(payload[12], mhz);
this.MeterType = payload[13];
this.TransmissionInterval = payload.ToUInt16BE(14);
this.LATInterval = payload[16];
@@ -65,7 +65,7 @@
public PAMStatus PAMStatus { get; }
public string RSSI { get; }
public RSSI RSSI { get; }
public byte MeterType { get; }
@@ -142,12 +142,5 @@
public ushort TimeOfLogReset { get; }
public byte MeterSize { get; }
public static string CalculateRSSI(byte value, int mhz)
{
var rssi = new RSSI(value, mhz);
return $"{rssi.Dbm:0}dBm ({rssi.Percent:0.0}%)";
}
}
}
+2 -1
View File
@@ -6,7 +6,8 @@
<appSettings>
<add key="ConnectionString" value="Server=SLASQL01.emea.sensus.net; Database=Auftrag; User ID=sa; Password=sqlserver;" />
<add key="EncryptionKeisUrl" value="http://sla12iis01.emea.sensus.net/LaaProductionWeb/api/eregister/radiokey/byserialno/{0}" />
<add key="SIRTComPorts" value="COM3" />
<add key="SIRTComPorts" value="COM6, COM8" />
<add key="PSNR" value="1" />
</appSettings>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
+21 -2
View File
@@ -8,6 +8,7 @@
using System;
using System.Diagnostics;
using System.Windows;
using System.Windows.Controls;
public partial class App : Application
{
@@ -19,10 +20,28 @@
if (!this.ShutdownRunningInstance())
{
var mainWindow = new MainWindow();
var args = e.Args;
if (e.Args?.Length > 0)
if (args?.Length > 0)
{
// TODO: set main window startup page
var source = $"Pages/{args[0]}.xaml";
var sourceUri = new Uri(source, UriKind.RelativeOrAbsolute);
if (args?.Length > 1)
{
mainWindow.Navigated += (_, eargs) =>
{
if (eargs.Content is Page page)
{
if (int.TryParse($"{args[1]}", out var sharedId))
{
page.Tag = sharedId;
}
}
};
}
mainWindow.NavigationService.Navigate(sourceUri, args[1]);
}
AppHost.ConfigureServices(services =>
+9 -1
View File
@@ -121,6 +121,9 @@
<DependentUpon>GridLayout.xaml</DependentUpon>
</Compile>
<Compile Include="Infrastructure\BooleanToBorderConverter.cs" />
<Compile Include="Pages\EregisterFinalize.xaml.cs">
<DependentUpon>EregisterFinalize.xaml</DependentUpon>
</Compile>
<Compile Include="Pages\EregisterManuelProgramming.xaml.cs">
<DependentUpon>EregisterManuelProgramming.xaml</DependentUpon>
</Compile>
@@ -143,11 +146,12 @@
<Compile Include="Pages\Settings.xaml.cs">
<DependentUpon>Settings.xaml</DependentUpon>
</Compile>
<Compile Include="ViewModels\EregisterFinalizeVM.cs" />
<Compile Include="ViewModels\EregisterHeaderVM.cs" />
<Compile Include="ViewModels\EregisterInitializeVM.cs" />
<Compile Include="Models\EregisterPropertiesModel.cs" />
<Compile Include="ViewModels\EregisterTaskVM.cs" />
<Compile Include="ViewModels\EregisterViewModel.cs" />
<Compile Include="ViewModels\EregisterVM.cs" />
<Compile Include="ViewModels\GridItem.cs" />
<Compile Include="ViewModels\GridItem[T].cs" />
<Compile Include="ViewModels\HomeViewModel.cs" />
@@ -167,6 +171,10 @@
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Pages\EregisterFinalize.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Pages\EregisterManuelProgramming.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
@@ -23,6 +23,7 @@
{
switch (label)
{
case nameof(SIRTTaskState.Pending):; break;
case nameof(SIRTMessage.BUP): brush = warning; break;
case nameof(SIRTMessage.LAT): brush = warning; break;
case nameof(SIRTMessage.DEBUG): brush = info; break;
@@ -18,6 +18,7 @@
{
switch (label)
{
case nameof(SIRTTaskState.Pending):; break;
case nameof(SIRTMessage.BUP): brush = Brushes.DarkOrange; break;
case nameof(SIRTMessage.LAT): brush = Brushes.DarkOrange; break;
case nameof(SIRTMessage.DEBUG): brush = Brushes.DarkBlue; break;
+1 -1
View File
@@ -2,6 +2,6 @@
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
ShowsNavigationUI="False"
Source="Pages/EregisterInitialize.xaml"
Source="Pages/Home.xaml"
Title="TestBench UI">
</NavigationWindow>
+3 -3
View File
@@ -1,6 +1,6 @@
<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ViewModels="clr-namespace:Common.UI.ViewModels"
xmlns:VM="clr-namespace:Common.UI.ViewModels"
xmlns:Views="clr-namespace:Common.UI.Views"
xmlns:Themes="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Aero2" x:Class="Common.UI.Pages.Eregister"
WindowTitle="UI / Eregister test environment"
@@ -449,7 +449,7 @@
</Style>
</Page.Resources>
<Page.DataContext>
<ViewModels:EregisterViewModel />
<VM:EregisterVM />
</Page.DataContext>
<Grid>
<Grid.RowDefinitions>
@@ -626,7 +626,7 @@
VerticalScrollBarVisibility="Auto">
<ItemsControl ItemsSource="{Binding EregisterProperties}">
<ItemsControl.ItemTemplate>
<DataTemplate DataType="{x:Type ViewModels:KvpViewModel}">
<DataTemplate DataType="{x:Type VM:KvpViewModel}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="210" />
@@ -0,0 +1,289 @@
<Page x:Class="Common.UI.Pages.EregisterFinalize"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:Controls="clr-namespace:Common.UI.Controls"
xmlns:VM="clr-namespace:Common.UI.ViewModels"
xmlns:V="clr-namespace:Common.UI.Views"
WindowTitle="TestBench UI / Eregister finalize">
<Page.DataContext>
<VM:EregisterFinalizeVM />
</Page.DataContext>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<V:SIRTBroadcasters Grid.Row="0" />
<ScrollViewer Grid.Row="1"
HorizontalAlignment="Stretch"
HorizontalScrollBarVisibility="Disabled"
VerticalAlignment="Stretch"
VerticalScrollBarVisibility="Auto">
<Controls:GridLayout Background="WhiteSmoke" ItemsSource="{Binding ProgrammingTasks}">
<Controls:GridLayout.Resources>
<DataTemplate DataType="{x:Type VM:EregisterTaskVM}" >
<Border Background="{Binding Label, Converter={StaticResource TaskStateToBG}}"
BorderBrush="LightGray"
BorderThickness="0, 0, 1, 1"
Margin="0"
Padding="10, 5">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="20" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="20" />
<RowDefinition Height="20" />
<RowDefinition Height="20" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Path Fill="{Binding Label, Converter={StaticResource TaskStateToFG}}"
Grid.Column="0"
Grid.Row="0"
Height="13"
HorizontalAlignment="Left"
Stretch="Uniform"
VerticalAlignment="Center"
Width="13">
<Path.Data>
<PathGeometry Figures="M3.05 3.05a7 7 0 0 0 0 9.9.5.5 0 0 1-.707.707 8 8 0 0 1 0-11.314.5.5 0 0 1 .707.707m2.122 2.122a4 4 0 0 0 0 5.656.5.5 0 1 1-.708.708 5 5 0 0 1 0-7.072.5.5 0 0 1 .708.708m5.656-.708a.5.5 0 0 1 .708 0 5 5 0 0 1 0 7.072.5.5 0 1 1-.708-.708 4 4 0 0 0 0-5.656.5.5 0 0 1 0-.708m2.122-2.12a.5.5 0 0 1 .707 0 8 8 0 0 1 0 11.313.5.5 0 0 1-.707-.707 7 7 0 0 0 0-9.9.5.5 0 0 1 0-.707zM6 8a2 2 0 1 1 2.5 1.937V15.5a.5.5 0 0 1-1 0V9.937A2 2 0 0 1 6 8" />
</Path.Data>
</Path>
<Label Content="{Binding Address}"
FontFamily="Consolas"
Foreground="{Binding Label, Converter={StaticResource TaskStateToFG}}"
Grid.Column="1"
Grid.Row="0"
HorizontalAlignment="Left"
Margin="0"
Padding="0"
VerticalAlignment="Center"/>
<Path Fill="{Binding Label, Converter={StaticResource TaskStateToFG}}"
Grid.Column="0"
Grid.Row="1"
Height="12"
HorizontalAlignment="Left"
Stretch="Uniform"
VerticalAlignment="Center"
Width="12">
<Path.Data>
<GeometryGroup>
<PathGeometry Figures="M14 1a1 1 0 0 1 1 1v12a1 1 0 0 1-1 1H2a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1zM2 0a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2z" />
<PathGeometry Figures="M5.5 12a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0m-3-8.5a1 1 0 0 1 1-1c5.523 0 10 4.477 10 10a1 1 0 1 1-2 0 8 8 0 0 0-8-8 1 1 0 0 1-1-1m0 4a1 1 0 0 1 1-1 6 6 0 0 1 6 6 1 1 0 1 1-2 0 4 4 0 0 0-4-4 1 1 0 0 1-1-1" />
</GeometryGroup>
</Path.Data>
</Path>
<Label Content="{Binding RSSI}"
FontFamily="Consolas"
Foreground="{Binding Label, Converter={StaticResource TaskStateToFG}}"
Grid.Column="1"
Grid.Row="1"
HorizontalAlignment="Left"
Margin="0"
Padding="0"
VerticalAlignment="Center"/>
<Path Fill="{Binding Label, Converter={StaticResource TaskStateToFG}}"
Grid.Column="0"
Grid.Row="2"
Height="13"
HorizontalAlignment="Left"
Stretch="Uniform"
VerticalAlignment="Center"
Width="13">
<Path.Data>
<PathGeometry FillRule="EvenOdd" Figures="M10.478 1.647a.5.5 0 1 0-.956-.294l-4 13a.5.5 0 0 0 .956.294zM4.854 4.146a.5.5 0 0 1 0 .708L1.707 8l3.147 3.146a.5.5 0 0 1-.708.708l-3.5-3.5a.5.5 0 0 1 0-.708l3.5-3.5a.5.5 0 0 1 .708 0m6.292 0a.5.5 0 0 0 0 .708L14.293 8l-3.147 3.146a.5.5 0 0 0 .708.708l3.5-3.5a.5.5 0 0 0 0-.708l-3.5-3.5a.5.5 0 0 0-.708 0" />
</Path.Data>
</Path>
<Label Content="{Binding Name}"
FontFamily="Consolas"
Foreground="{Binding Label, Converter={StaticResource TaskStateToFG}}"
Grid.Column="1"
Grid.Row="2"
HorizontalAlignment="Left"
Margin="0"
Padding="0"
VerticalAlignment="Center"/>
<Path Fill="{Binding Label, Converter={StaticResource TaskStateToFG}}"
Grid.Column="0"
Grid.Row="3"
Height="13"
HorizontalAlignment="Left"
Stretch="Uniform"
VerticalAlignment="Center"
Width="13">
<Path.Data>
<PathGeometry FillRule="EvenOdd" Figures="M5 11.5a.5.5 0 0 1 .5-.5h9a.5.5 0 0 1 0 1h-9a.5.5 0 0 1-.5-.5m0-4a.5.5 0 0 1 .5-.5h9a.5.5 0 0 1 0 1h-9a.5.5 0 0 1-.5-.5m0-4a.5.5 0 0 1 .5-.5h9a.5.5 0 0 1 0 1h-9a.5.5 0 0 1-.5-.5M3.854 2.146a.5.5 0 0 1 0 .708l-1.5 1.5a.5.5 0 0 1-.708 0l-.5-.5a.5.5 0 1 1 .708-.708L2 3.293l1.146-1.147a.5.5 0 0 1 .708 0m0 4a.5.5 0 0 1 0 .708l-1.5 1.5a.5.5 0 0 1-.708 0l-.5-.5a.5.5 0 1 1 .708-.708L2 7.293l1.146-1.147a.5.5 0 0 1 .708 0m0 4a.5.5 0 0 1 0 .708l-1.5 1.5a.5.5 0 0 1-.708 0l-.5-.5a.5.5 0 0 1 .708-.708l.146.147 1.146-1.147a.5.5 0 0 1 .708 0" />
</Path.Data>
</Path>
<Label Content="{Binding Label}"
FontFamily="Consolas"
Foreground="{Binding Label, Converter={StaticResource TaskStateToFG}}"
Grid.Column="1"
Grid.Row="3"
HorizontalAlignment="Left"
Margin="0"
Padding="0"
VerticalAlignment="Center"/>
</Grid>
</Border>
</DataTemplate>
<DataTemplate DataType="{x:Type VM:EregisterHeaderVM}" >
<Border Background="WhiteSmoke"
BorderBrush="LightGray"
BorderThickness="0, 0, 1, 1"
Margin="0"
Padding="10, 5">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="20" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="20" />
<RowDefinition Height="20" />
<RowDefinition Height="20" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Path Fill="DarkSlateGray"
Grid.Column="0"
Grid.Row="0"
Height="13"
HorizontalAlignment="Left"
Margin="2, 0, 0, 0"
Stretch="Uniform"
VerticalAlignment="Center"
Width="13">
<Path.Data>
<PathGeometry FillRule="EvenOdd" Figures="M8 1a3 3 0 1 0 0 6 3 3 0 0 0 0-6M4 4a4 4 0 1 1 4.5 3.969V13.5a.5.5 0 0 1-1 0V7.97A4 4 0 0 1 4 3.999zm2.493 8.574a.5.5 0 0 1-.411.575c-.712.118-1.28.295-1.655.493a1.3 1.3 0 0 0-.37.265.3.3 0 0 0-.057.09V14l.002.008.016.033a.6.6 0 0 0 .145.15c.165.13.435.27.813.395.751.25 1.82.414 3.024.414s2.273-.163 3.024-.414c.378-.126.648-.265.813-.395a.6.6 0 0 0 .146-.15l.015-.033L12 14v-.004a.3.3 0 0 0-.057-.09 1.3 1.3 0 0 0-.37-.264c-.376-.198-.943-.375-1.655-.493a.5.5 0 1 1 .164-.986c.77.127 1.452.328 1.957.594C12.5 13 13 13.4 13 14c0 .426-.26.752-.544.977-.29.228-.68.413-1.116.558-.878.293-2.059.465-3.34.465s-2.462-.172-3.34-.465c-.436-.145-.826-.33-1.116-.558C3.26 14.752 3 14.426 3 14c0-.599.5-1 .961-1.243.505-.266 1.187-.467 1.957-.594a.5.5 0 0 1 .575.411" />
</Path.Data>
</Path>
<Label Content="{Binding SlotNr}"
FontFamily="Consolas"
FontWeight="Bold"
Foreground="DarkSlateGray"
Grid.Column="1"
Grid.Row="0"
HorizontalAlignment="Left"
Margin="0"
Padding="0"
VerticalAlignment="Center"/>
<Path Fill="DarkSlateGray"
Grid.Column="0"
Grid.Row="1"
Height="12"
HorizontalAlignment="Left"
Stretch="Uniform"
VerticalAlignment="Center"
Width="12">
<Path.Data>
<PathGeometry Figures="M8.186 1.113a.5.5 0 0 0-.372 0L1.846 3.5 8 5.961 14.154 3.5zM15 4.239l-6.5 2.6v7.922l6.5-2.6V4.24zM7.5 14.762V6.838L1 4.239v7.923zM7.443.184a1.5 1.5 0 0 1 1.114 0l7.129 2.852A.5.5 0 0 1 16 3.5v8.662a1 1 0 0 1-.629.928l-7.185 2.874a.5.5 0 0 1-.372 0L.63 13.09a1 1 0 0 1-.63-.928V3.5a.5.5 0 0 1 .314-.464z" />
</Path.Data>
</Path>
<Label Content="{Binding PoNr}"
FontFamily="Consolas"
FontWeight="Bold"
Foreground="DarkSlateGray"
Grid.Column="1"
Grid.Row="1"
HorizontalAlignment="Left"
Margin="0"
Padding="0"
VerticalAlignment="Center"/>
<Path Fill="DarkSlateGray"
Grid.Column="0"
Grid.Row="2"
Height="12"
HorizontalAlignment="Left"
Stretch="Uniform"
VerticalAlignment="Center"
Width="12">
<Path.Data>
<PathGeometry Figures="M3 4.5a.5.5 0 0 1 1 0v7a.5.5 0 0 1-1 0zm2 0a.5.5 0 0 1 1 0v7a.5.5 0 0 1-1 0zm2 0a.5.5 0 0 1 1 0v7a.5.5 0 0 1-1 0zm2 0a.5.5 0 0 1 .5-.5h1a.5.5 0 0 1 .5.5v7a.5.5 0 0 1-.5.5h-1a.5.5 0 0 1-.5-.5zm3 0a.5.5 0 0 1 1 0v7a.5.5 0 0 1-1 0z" />
</Path.Data>
</Path>
<Label Content="{Binding SerialNr}"
FontFamily="Consolas"
FontWeight="Bold"
Foreground="DarkSlateGray"
Grid.Column="1"
Grid.Row="2"
HorizontalAlignment="Left"
Margin="0"
Padding="0"
VerticalAlignment="Center"/>
<Path Fill="DarkSlateGray"
Grid.Column="0"
Grid.Row="3"
Height="13"
HorizontalAlignment="Left"
Stretch="Uniform"
VerticalAlignment="Center"
Width="13">
<Path.Data>
<PathGeometry Figures="M3.05 3.05a7 7 0 0 0 0 9.9.5.5 0 0 1-.707.707 8 8 0 0 1 0-11.314.5.5 0 0 1 .707.707m2.122 2.122a4 4 0 0 0 0 5.656.5.5 0 1 1-.708.708 5 5 0 0 1 0-7.072.5.5 0 0 1 .708.708m5.656-.708a.5.5 0 0 1 .708 0 5 5 0 0 1 0 7.072.5.5 0 1 1-.708-.708 4 4 0 0 0 0-5.656.5.5 0 0 1 0-.708m2.122-2.12a.5.5 0 0 1 .707 0 8 8 0 0 1 0 11.313.5.5 0 0 1-.707-.707 7 7 0 0 0 0-9.9.5.5 0 0 1 0-.707zM10 8a2 2 0 1 1-4 0 2 2 0 0 1 4 0" />
</Path.Data>
</Path>
<Label Content="{Binding Frequency}"
FontFamily="Consolas"
FontWeight="Bold"
Foreground="DarkSlateGray"
Grid.Column="1"
Grid.Row="3"
HorizontalAlignment="Left"
Margin="0"
Padding="0"
VerticalAlignment="Center"/>
</Grid>
</Border>
</DataTemplate>
<DataTemplate DataType="{x:Type VM:GridItem}" >
<Border BorderBrush="LightGray"
BorderThickness="0, 0, 1, 1"
Margin="0"
MinHeight="20"
Padding="10, 5">
<Label Content="{Binding Label}"
FontFamily="Consolas"
FontWeight="Bold"
Foreground="DarkSlateGray"
HorizontalAlignment="Left"
Margin="0"
Padding="0"
VerticalAlignment="Center"/>
</Border>
</DataTemplate>
</Controls:GridLayout.Resources>
</Controls:GridLayout>
</ScrollViewer>
<Border BorderBrush="LightGray"
BorderThickness="0, 1, 0, 0"
Grid.Row="2" >
<StackPanel Orientation="Horizontal" Margin="5">
<Button Content="Start Programming"
Command="{Binding StartProgrammingCommand}"
Grid.Row="2"
HorizontalAlignment="Left"
IsEnabled="{Binding StartEnabled}"
Margin="0, 0, 5, 0"
Padding="20, 3"/>
<Button Content="Stop Programming"
Command="{Binding StopProgrammingCommand}"
Grid.Row="2"
HorizontalAlignment="Left"
IsEnabled="{Binding StopEnabled}"
Margin="0, 0, 5, 0"
Padding="20, 3"/>
<Label FontWeight="Bold"
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Center"
Margin="0"
Padding="10, 0"
Content="{Binding TimeElapsed}"
VerticalAlignment="Stretch"
VerticalContentAlignment="Center" />
</StackPanel>
</Border>
</Grid>
</Page>
@@ -0,0 +1,28 @@
namespace Common.UI.Pages
{
using Common.UI.ViewModels;
using System.Windows;
using System.Windows.Controls;
public partial class EregisterFinalize : Page
{
public EregisterFinalize()
{
this.InitializeComponent();
this.Loaded += EregisterInitialize_Loaded;
}
private void EregisterInitialize_Loaded(object sender, RoutedEventArgs e)
{
if (this.DataContext is EregisterFinalizeVM eregisterInitializeVM)
{
if (this.Tag is int sharedId)
{
eregisterInitializeVM.StartProgramming(sharedId);
}
}
}
}
}
@@ -3,7 +3,8 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:Controls="clr-namespace:Common.UI.Controls"
xmlns:VM="clr-namespace:Common.UI.ViewModels"
xmlns:V="clr-namespace:Common.UI.Views">
xmlns:V="clr-namespace:Common.UI.Views"
WindowTitle="TestBench UI / Eregister initialize">
<Page.DataContext>
<VM:EregisterInitializeVM />
</Page.DataContext>
@@ -1,9 +1,28 @@
namespace Common.UI.Pages
{
using Common.UI.ViewModels;
using System.Windows;
using System.Windows.Controls;
public partial class EregisterInitialize : Page
{
public EregisterInitialize() => this.InitializeComponent();
public EregisterInitialize()
{
this.InitializeComponent();
this.Loaded += EregisterInitialize_Loaded;
}
private void EregisterInitialize_Loaded(object sender, RoutedEventArgs e)
{
if (this.DataContext is EregisterInitializeVM eregisterInitializeVM)
{
if (this.Tag is int sharedId)
{
eregisterInitializeVM.StartProgramming(sharedId);
}
}
}
}
}
@@ -0,0 +1,39 @@
namespace Common.UI.ViewModels
{
using Common.Hardware.WaterMeter.eRegister.Models;
using System;
using System.Threading.Tasks;
internal class EregisterFinalizeVM : EregisterInitializeVM
{
protected override async Task StartProgrammingAsync(EregisterProgrammingParametersList parametersList)
{
var programmingTasksEnumerable = this.eregisterFactory.LoadInspectionFinalizationTasks(parametersList);
this.LoadUIComponenets(programmingTasksEnumerable);
await Task.Delay(3000);
this.TimeElapsed = null;
this.timestamp = DateTime.Now;
this.timer.Start();
this.programmingTask = this.eregisterFactory
.StartProgrammingAsync(this.cancellationToken)
.ContinueWith(_ =>
{
this.timer.Stop();
this.StartEnabled = true;
this.StopEnabled = false;
})
.ContinueWith(async _ =>
{
await Task.Delay(1_000);
this.sirtFactory.CloseConnections();
// this.InvokeAsync(App.Current.Shutdown);
});
}
}
}
@@ -20,14 +20,15 @@
internal class EregisterInitializeVM : ViewModel<EregisterInitializeVM>
{
private readonly ILogger logger;
private readonly System.Timers.Timer timer;
private readonly SIRTFactory broadcaster;
private readonly EregisterBatch eregisterFactory;
protected readonly System.Timers.Timer timer;
protected readonly SIRTFactory sirtFactory;
protected readonly EregisterBatch eregisterFactory;
private CancellationTokenSource cancellationTokenSource;
private CancellationToken cancellationToken;
private Task programmingTask;
private DateTime timestamp;
protected CancellationToken cancellationToken;
protected Task programmingTask;
protected DateTime timestamp;
private int sharedId;
public EregisterInitializeVM()
{
@@ -39,9 +40,9 @@
};
this.timer.Elapsed += this.Timer_Elapsed;
this.logger = AppHost.GetService<ILogger>();
this.broadcaster = AppHost.GetService<SIRTFactory>();
this.broadcaster.Log += x => this.logger.Debug(x);
this.eregisterFactory = new EregisterBatch(this.broadcaster);
this.sirtFactory = AppHost.GetService<SIRTFactory>();
this.sirtFactory.Logging += x => this.logger.Debug(x);
this.eregisterFactory = new EregisterBatch(this.sirtFactory);
this.ProgrammingTasks = new ObservableCollection<EregisterTaskVM>();
this.StartProgrammingCommand = new Command(this.LoadProgrammingTasks);
this.StopProgrammingCommand = new Command(this.StopProgrammingCommandHandler);
@@ -80,64 +81,14 @@
set => this.Set(vm => vm.programmingTasks = value);
}
private void LoadProgrammingTasks()
internal void StartProgramming(int sharedId)
{
this.StartEnabled = false;
this.StopEnabled = true;
this.sharedId = sharedId;
this.cancellationTokenSource = new CancellationTokenSource();
this.cancellationToken = this.cancellationTokenSource.Token;
Task.Run(async () =>
{
var parametersList = default(EregisterProgrammingParametersList);
var pendingAction = AuftragDbContext.P2000Shared.LoadPendingActions(1);
var sharedId = pendingAction?.Id ?? 0;
var actions = AuftragDbContext.Eregister_Shared.LoadActions(sharedId);
parametersList = AuftragDbContext.LoadEregisterProgrammingParametersListForSharedId(sharedId);
var uriFormat = Appsettings.Get("EncryptionKeisUrl");
var httpClient = new HttpClient();
foreach (var epp in parametersList)
{
epp.Adresse = actions.FirstOrDefault(x => x.SerialNr == epp.SerienNr).FinalAddress;
epp.TempAdresse = actions.FirstOrDefault(x => x.SerialNr == epp.SerienNr).TempAddress;
using (var httpResponeMessage = await httpClient.GetAsync(string.Format(uriFormat, epp.SerienNr)))
{
if (httpResponeMessage.IsSuccessStatusCode)
{
var content = await httpResponeMessage.Content?.ReadAsStringAsync();
epp.EncryptionKey = content?.Trim('"');
}
}
}
var programmingTasksEnumerable = this.eregisterFactory.LoadInspectionFinalizationTasks(parametersList);
this.LoadUIComponenets(programmingTasksEnumerable);
await Task.Delay(1000);
this.TimeElapsed = null;
this.timestamp = DateTime.Now;
this.timer.Start();
this.programmingTask = this.eregisterFactory
.StartProgrammingAsync(this.cancellationToken)
.ContinueWith(_ =>
{
this.timer.Stop();
this.StartEnabled = true;
this.StopEnabled = false;
});
}, this.cancellationToken);
this.LoadProgrammingTasks();
}
private void LoadUIComponenets(IEnumerable<IEnumerable<EregisterTask>> programmingTasksEnumerable)
protected void LoadUIComponenets(IEnumerable<IEnumerable<EregisterTask>> programmingTasksEnumerable)
{
var col = 0;
var row = 0;
@@ -182,6 +133,82 @@
this.ProgrammingTasks = tasks;
}
protected virtual async Task StartProgrammingAsync(EregisterProgrammingParametersList parametersList)
{
var programmingTasksEnumerable = this.eregisterFactory.LoadInspectionInitializationTasks(parametersList);
this.LoadUIComponenets(programmingTasksEnumerable);
await Task.Delay(3000);
this.TimeElapsed = null;
this.timestamp = DateTime.Now;
this.timer.Start();
this.programmingTask = this.eregisterFactory
.StartProgrammingAsync(this.cancellationToken)
.ContinueWith(_ =>
{
this.timer.Stop();
this.StartEnabled = true;
this.StopEnabled = false;
})
.ContinueWith(async _ =>
{
await Task.Delay(1_000);
this.sirtFactory.CloseConnections();
// this.InvokeAsync(App.Current.Shutdown);
});
}
private void LoadProgrammingTasks()
{
this.StartEnabled = false;
this.StopEnabled = true;
this.cancellationTokenSource = new CancellationTokenSource();
this.cancellationToken = this.cancellationTokenSource.Token;
Task.Run(async () =>
{
var parametersList = default(EregisterProgrammingParametersList);
if (this.sharedId <= 0 && int.TryParse($"{Appsettings.Get("PSNR")}", out var psnr))
{
var pendingAction = AuftragDbContext.P2000Shared.LoadPendingActions(psnr);
this.sharedId = pendingAction?.Id ?? 0;
}
var actions = AuftragDbContext.Eregister_Shared.LoadActions(this.sharedId);
parametersList = AuftragDbContext.LoadEregisterProgrammingParametersListForSharedId(this.sharedId);
var uriFormat = Appsettings.Get("EncryptionKeisUrl");
var httpClient = new HttpClient();
foreach (var epp in parametersList)
{
var finalAddress = actions.FirstOrDefault(x => x.SerialNr == epp.SerienNr).FinalAddress;
var tempAddress = actions.FirstOrDefault(x => x.SerialNr == epp.SerienNr).TempAddress;
epp.Adresse = finalAddress;
epp.TempAdresse = tempAddress;
using (var httpResponeMessage = await httpClient.GetAsync(string.Format(uriFormat, epp.SerienNr)))
{
if (httpResponeMessage.IsSuccessStatusCode)
{
var content = await httpResponeMessage.Content?.ReadAsStringAsync();
epp.EncryptionKey = content?.Trim('"');
}
}
}
await this.StartProgrammingAsync(parametersList);
}, this.cancellationToken);
}
private void StopProgrammingCommandHandler()
{
this.timer.Stop();
@@ -6,16 +6,17 @@
using Common.Hardware.WaterMeter.eRegister;
using Common.Hardware.WaterMeter.eRegister.Features;
using Common.Hardware.WaterMeter.eRegister.Models;
using Common.Hardware.WaterMeter.eRegister.Telegrams;
using Common.UI.Data;
using Common.UI.Infrastructure;
using Common.UI.Models;
using System.Collections.ObjectModel;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using System.Windows.Input;
internal class EregisterViewModel : ViewModel<EregisterViewModel>
internal class EregisterVM : ViewModel<EregisterVM>
{
private readonly SIRTFactory sirtFactory;
private readonly DeviceManager deviceManager;
@@ -23,7 +24,7 @@
private SIRTBroadcaster broadcaster;
public EregisterViewModel() : base()
public EregisterVM() : base()
{
this.IsConnectEnabled = true;
this.eregister = new EregisterPropertiesModel();
@@ -144,7 +145,6 @@
this.broadcaster.Disconnected += this.Broadcaster_Disconnected;
this.broadcaster.Logging += this.Broadcaster_Log;
this.broadcaster.MessageReceived += this.GetAvailableAddresses;
this.broadcaster.MessageReceived += this.UpdateCurrentTask;
this.IsConnected = false;
this.IsConnectEnabled = false;
@@ -152,53 +152,6 @@
}
}
private void UpdateCurrentTask(SIRTMessage message)
{
if (message.Address == this.Address)
{
var data = message.Data.DecryptResponse("E6C88800DEB868C0D6A84880CE982840".GetEncryptionKey());
var length = data.Length;
if (length > 0)
{
var messageType = data[0];
var payload = default(Payload);
if (messageType == SIRTMessage.BUP)
{
payload = new BUP(data, message.P1);
}
else if (messageType == SIRTMessage.LAT)
{
payload = new LAT(data, message.P1);
}
else if (messageType == SIRTMessage.DEBUG)
{
payload = new DEBUG(data, message.P1);
}
else if (messageType == SIRTMessage.SEMI)
{
payload = new SEMI(data, this.broadcaster.Frequency, message.P1);
}
if (payload != null)
{
this.eregister.AddMessage(payload);
var eregisterPropertiesKvp = this.eregister.GetProperties();
foreach (var kvp in this.EregisterProperties)
{
if (eregisterPropertiesKvp.TryGetValue(kvp.Key, out var value))
{
kvp.Value = value;
}
}
}
}
}
}
private void GetAvailableAddresses(SIRTMessage message)
{
if (message.Cmd != SIRTMessage.FROMAIR)
@@ -269,7 +222,6 @@
this.broadcaster.Disconnected -= this.Broadcaster_Disconnected;
this.broadcaster.Logging -= this.Broadcaster_Log;
this.broadcaster.MessageReceived -= this.GetAvailableAddresses;
this.broadcaster.MessageReceived -= this.UpdateCurrentTask;
}
private void Broadcaster_Connected()
@@ -337,29 +289,104 @@
this.AddressSelected = false;
}
private void StartProgrammingCommandHandler()
private async void StartProgrammingCommandHandler()
{
var task = new EregisterTask(this.broadcaster.Frequency)
var parametersList = AuftragDbContext.LoadEregisterProgrammingParametersListForSharedId(1);
var parameters = parametersList.FirstOrDefault();
if (parameters is null)
{
RequestAddress = 4291189262,
Data = new EregisterFeatures
return;
}
var encryptionKey = default(string);
var uriFormat = Appsettings.Get("EncryptionKeisUrl");
var httpClient = new HttpClient();
using (var httpResponeMessage = await httpClient.GetAsync(string.Format(uriFormat, parameters.SerienNr)))
{
if (httpResponeMessage.IsSuccessStatusCode)
{
Debug = new EregisterDebugFeatures
{
OpticalTelegram = new OpticalTelegram
{
Minutes = 5
}
},
var content = await httpResponeMessage.Content?.ReadAsStringAsync();
encryptionKey = content?.Trim('"');
}
}
var features = new EregisterFeatures
{
SlotNr = parameters.Slotno,
SerialNr = parameters.SerienNr,
PoNr = parameters.FertigungsauftragNr,
RequestAddress = parameters.RequestAddress,
ResponseAddress = parameters.ResponseAddress,
Frequency = parameters.Frequency,
EncryptionKey = parameters.EncryptionKey.GetEncryptionKey(),
//ChangeRadioId = new ChangeRadioId
//{
// Address = 2000000000
//},
//ChangeMeterReading = new ChangeMeterReading
//{
// DisplayVolume = parameters.DisplayVolume
//}
Debug = new EregisterDebugFeatures
{
RequestDebugTelegram = new RequestDebugTelegram()
}
.BuildPams()
.FirstOrDefault()
.Value,
IsEncrypted = true,
EncryptionKey = "E6C88800DEB868C0D6A84880CE982840".GetEncryptionKey()
};
this.broadcaster.EnqueueTask(task);
var pams = features.BuildPams();
foreach (var pam in features.BuildPams())
{
var task = new EregisterTask(this.broadcaster.Frequency)
{
P1 = new P811
{
DelPamSemi = true,
WakeUpCmd = true
},
RequestAddress = 4291189262,
ResponseAddress = 2000000000,
Data = pam.Value,
IsEncrypted = true,
EncryptionKey = encryptionKey.GetEncryptionKey()
};
task.Telegram += this.UpdateParameters;
task.Completed += this.TaskCompleted;
this.broadcaster.EnqueueTask(task);
}
}
private void TaskCompleted(SIRTTask task)
{
if (task is EregisterTask _task)
{
_task.Telegram -= this.UpdateParameters;
_task.Completed -= this.TaskCompleted;
}
}
private void UpdateParameters(object telegram)
{
if (telegram != null)
{
this.InvokeAsync(() =>
{
this.eregister.AddMessage(telegram);
foreach (var kvp in this.eregister.GetProperties())
{
var property = this.EregisterProperties.FirstOrDefault(x => x.Key == kvp.Key);
if (property != null)
{
property.Value = kvp.Value;
}
}
});
}
}
}
}
@@ -126,7 +126,7 @@
private void AddSIRTs()
{
var portNames = Appsettings
.Get("SIRTComPortNames")
.Get("SIRTComPorts")
?.Split(new[] { ';', ',', ' ' })
?.Select(x => x?.Trim())
?.ToArray() ?? new string[0];
@@ -136,15 +136,21 @@
.Intersect(portNames)
.ToArray();
foreach (var portName in portNames)
Task.Run(async () =>
{
var connection = this.broadcaster.ConnectSIRT(portName);
var sirtVM = new SIRTConnectionVM(connection);
this.Connections.Add(sirtVM);
this.ClearEnabled = true;
foreach (var portName in portNames)
{
this.InvokeAsync(() =>
{
var connection = this.broadcaster.ConnectSIRT(portName);
var sirtVM = new SIRTConnectionVM(connection);
this.Connections.Add(sirtVM);
this.ClearEnabled = true;
});
Thread.Sleep(500);
}
await Task.Delay(500);
}
});
}
private void UpdatePortNames()
+5 -1
View File
@@ -7,5 +7,9 @@
</Menu.DataContext>
<MenuItem Header="Home" Command="{Binding NavigateCommand}" CommandParameter="Pages/Home.xaml" />
<MenuItem Header="Settings" Command="{Binding NavigateCommand}" CommandParameter="Pages/Settings.xaml" />
<MenuItem Header="Eregister" Command="{Binding NavigateCommand}" CommandParameter="Pages/Eregister.xaml" />
<MenuItem Header="Eregister">
<MenuItem Header="Manual Programming" Command="{Binding NavigateCommand}" CommandParameter="Pages/Eregister.xaml" />
<MenuItem Header="Inspection Initialization" Command="{Binding NavigateCommand}" CommandParameter="Pages/EregisterInitialize.xaml" />
<MenuItem Header="Inspection Finalization" Command="{Binding NavigateCommand}" CommandParameter="Pages/EregisterFinalize.xaml" />
</MenuItem>
</Menu>