Files
laatzen/Common/Hardware/WaterMeter/eRegister/Common.Hardware.WaterMeter.eRegister/ProgrammingTask.cs
T

328 lines
9.9 KiB
C#

namespace Common.Hardware.WaterMeter.eRegister
{
using Common.Hardware.Interfaces.Ports.SIRT;
using Common.Hardware.Interfaces.Ports.SIRT.Parameters;
using Common.Hardware.WaterMeter.eRegister.Data;
using System;
using System.Collections.Generic;
using System.Linq;
public class ProgrammingTask : SirtTask
{
private const String PENDING = nameof(PENDING);
private readonly ICollection<LAT> lats = new List<LAT>();
private readonly ICollection<BUP> bups = new List<BUP>();
private readonly ICollection<DEBUG> debugs = new List<DEBUG>();
private readonly ICollection<SEMI> semis = new List<SEMI>();
public event Action<ProgrammingTask> OnProgress;
public Byte[] EncryptionKey { get; set; }
public Int32 Slotno { get; internal set; }
public Int32 Rowno { get; internal set; }
public String Label { get; private set; }
public String RSSI { get; private set; }
public TaskState State { get; private set; } = TaskState.None;
public String PamNames { get; internal set; }
public override void PrepareForRun()
{
this.OnProgress?.Invoke(this);
base.PrepareForRun();
}
public override void ReceiveMessage(SirtMessage response, Int32 mhz)
{
if (this.EncryptionKey != null && this.EncryptionKey.Length == 16)
{
this.DecryptResponse(response);
}
if (this.State != TaskState.Success && response.Cmd == SirtMessage.FROMAIR)
{
var label = this.Label;
var state = this.State;
var data = response.Data;
var type = data[0];
if (type == SirtMessage.SEMI)
{
var semi = new SEMI(data, (UInt16)mhz);
label = semi.PAMStatus.ToString();
if (semi.PAMStatus == PAMStatus.OK)
{
state = TaskState.Success;
this.TaskStatus = TaskStatus.Completed;
}
else
{
state = TaskState.Error;
this.TaskStatus = TaskStatus.Cancelled;
}
this.semis.Add(semi);
}
else if (type == SirtMessage.BUP)
{
label = nameof(SirtMessage.BUP);
state = TaskState.Warning;
this.bups.Add(new BUP(data));
}
else if (type == SirtMessage.LAT)
{
label = nameof(SirtMessage.LAT);
state = TaskState.Warning;
this.lats.Add(new LAT(data));
}
else if (type == SirtMessage.DEBUG)
{
label = nameof(SirtMessage.DEBUG);
state = TaskState.Warning;
this.debugs.Add(new DEBUG(data));
}
this.Label = label;
this.State = state;
this.RSSI = SEMI.CalculateRSSI(response.P2, (UInt16)mhz);
}
this.OnProgress?.Invoke(this);
base.ReceiveMessage(response, mhz);
}
public override Byte[] ToByteArray()
{
if (this.EncryptionKey != null && this.EncryptionKey.Length == 16)
{
this.EncryptRequest();
}
return base.ToByteArray();
}
internal void Refresh()
{
var semi = this.semis.LastOrDefault();
if (semi != null)
{
this.Label = semi.PAMStatus.ToString();
if (semi.PAMStatus == PAMStatus.OK)
{
this.State = TaskState.Success;
}
else
{
this.State = TaskState.Error;
}
}
else if (this.LastPayload != null)
{
var last = new SirtMessage(this.LastPayload);
P11 p11 = last.P1;
if (p11.LenOverflow)
{
this.Label = "LEN OVERFLOW";
this.State = TaskState.Error;
}
else if (!p11.SrcChannel && p11.InvalidMod1)
{
this.Label = "MOD 1 CRC ERROR";
this.State = TaskState.Error;
}
else if (p11.SrcChannel && p11.InvalidMod2)
{
this.Label = "MOD 2 CRC ERROR";
this.State = TaskState.Error;
}
else
{
this.Label = nameof(PAMStatus.OK);
this.State = TaskState.Success;
}
}
else
{
this.Label = "NA";
this.State = TaskState.Error;
}
this.OnProgress?.Invoke(this);
}
internal Tuple<String, TaskState> CheckMBusStatus(ParameterSet parameterSet)
{
var label = $"{this.semis.LastOrDefault()?.MBusStatus} OK";
return new Tuple<String, TaskState>(label, TaskState.Success);
}
internal Tuple<String, TaskState> CheckBatteryVoltage(ParameterSet parameterSet)
{
var label = $"{this.debugs.LastOrDefault()?.BatteryVoltage:0.00} OK";
return new Tuple<String, TaskState>(label, TaskState.Success);
}
internal Tuple<String, TaskState> CheckBatteryRemaining(ParameterSet parameterSet)
{
var label = $"{this.semis.LastOrDefault()?.BatteryRemaining:0.0} OK";
return new Tuple<String, TaskState>(label, TaskState.Success);
}
internal Tuple<String, TaskState> CheckRadioFWVersion(ParameterSet parameterSet)
{
var label = $"{this.debugs.LastOrDefault()?.RadioFirmwareVersion} OK";
return new Tuple<String, TaskState>(label, TaskState.Success);
}
internal Tuple<String, TaskState> CheckMetrologyFWVersion(ParameterSet arg)
{
var label = $"{this.debugs.LastOrDefault()?.MetrologyFirmwareVersion} OK";
return new Tuple<String, TaskState>(label, TaskState.Success);
}
internal Tuple<String, TaskState> CheckReboots(ParameterSet parameterSet)
{
var label = $"{this.debugs.LastOrDefault()?.RebootCount} OK";
return new Tuple<String, TaskState>(label, TaskState.Success);
}
private void DecryptResponse(SirtMessage response)
{
var data = response.Data;
var length = data.Length;
if (length < 13)
{
return;
}
var bytes = new Byte[length];
var hex = BitConverter.ToString(bytes);
Array.Copy(data, 0, bytes, 0, length);
var token = bytes[1];
for (var x = 6; x < length; x++)
{
token += (Byte)(bytes[x - (token & 0x3) - 1] >> ((token >> 6) & 0x1));
bytes[x] ^= this.EncryptionKey[(token >> 2) & 0x0F];
if (token >= 0x80)
{
bytes[x] = (Byte)~bytes[x];
}
}
var crc = this.CalculateCRC(bytes, 5, length - 2);
if (crc == 0 || crc == UInt16.MaxValue)
{
response.Data = bytes;
}
}
private void EncryptRequest()
{
var data = this.Data;
var dataLength = data.Length;
var telegramLength = dataLength + 2;
var telegram = new Byte[telegramLength];
Array.Copy(data, 0, telegram, 0, dataLength);
var telegramForCRCLength = telegramLength + 4;
var telegramForCRC = new Byte[telegramForCRCLength];
var address = this.Address;
telegramForCRC[0] = (Byte)(address >> 24);
telegramForCRC[1] = (Byte)(address >> 16);
telegramForCRC[2] = (Byte)(address >> 8);
telegramForCRC[3] = (Byte)(address >> 0);
Array.Copy(telegram, 0, telegramForCRC, 4, telegramLength);
var telegramCRC = this.CalculateCRC(telegramForCRC, 1, telegramForCRCLength - 2);
telegram[telegramLength - 2] = (Byte)(telegramCRC >> 8);
telegram[telegramLength - 1] = (Byte)(telegramCRC >> 0);
var reference = address;
var token = (Byte)0xFF;
for (var i = 0; i < telegramLength; i++)
{
token += (Byte)(((reference >> ((token & 0x3) << 3)) & 0xFF) >> ((token >> 6) & 1));
reference = reference << 8;
reference += telegram[i];
telegram[i] ^= this.EncryptionKey[(token >> 2) & 0x0F];
if (token >= 0x80)
{
telegram[i] = (Byte)~telegram[i];
}
}
this.Data = telegram;
}
private UInt16 CalculateCRC(Byte[] data, Int32 start, Int32 length)
{
var crc = (UInt16)0xFFFF;
var dataLength = data?.Length ?? 0;
if (start + length > dataLength)
{
return crc;
}
for (var b = start; b < length; b++)
{
var _byte = data[b];
var token = (UInt16)((_byte << 8) & 0xFF00);
for (var i = 0; i < 8; i++)
{
if (0x8000 == ((crc ^ token) & 0x8000))
{
crc <<= 1;
crc ^= 0x1021;
}
else
{
crc <<= 1;
}
token <<= 1;
}
}
return crc;
}
}
}