646 lines
21 KiB
C#
646 lines
21 KiB
C#
namespace Common.UI.ViewModels
|
|
{
|
|
using Common.Hardware.SIRT;
|
|
using Common.Hardware.SIRT.Parameters;
|
|
using Common.Hardware.SIRT.Tasks;
|
|
using Common.Hardware.WaterMeter.eRegister;
|
|
using Common.Hardware.WaterMeter.eRegister.Features;
|
|
using Common.Hardware.WaterMeter.eRegister.Telegrams;
|
|
using Common.UI.Infrastructure;
|
|
|
|
using LaaPackages.SqlClient;
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Reflection;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using System.Windows.Input;
|
|
using System.Windows.Media;
|
|
|
|
public class SetMetrologyParametersVM : VM<SetMetrologyParametersVM>
|
|
{
|
|
private readonly Dictionary<string, PropertyVM> telegrams;
|
|
private readonly Dictionary<string, MeterSizeVM> meterSizes;
|
|
|
|
private CancellationTokenSource cancellationTokenSource;
|
|
private CancellationToken cancellationToken;
|
|
private Task cancellationTask;
|
|
private SIRTBroadcaster sirt;
|
|
private string portName;
|
|
private string sirtId;
|
|
private int frequency;
|
|
|
|
public SetMetrologyParametersVM()
|
|
{
|
|
AppHost.SIRTHub.Connected += this.SIRTHub_Connected;
|
|
AppHost.SIRTHub.Disconnected += this.SIRTHub_Disconnected;
|
|
|
|
var hours = this.TestModeHours;
|
|
|
|
if (hours == 0)
|
|
{
|
|
this.modeInfo = $"Test mode is off";
|
|
}
|
|
else
|
|
{
|
|
this.modeInfo = $"Test mode is on for {hours} h";
|
|
}
|
|
|
|
var min = this.LEDOnTime;
|
|
|
|
if (min == 0)
|
|
{
|
|
this.ledInfo = $"LED is off";
|
|
}
|
|
else
|
|
{
|
|
this.ledInfo = $"LED is on for {this.ledOnTime} min";
|
|
}
|
|
|
|
this.ActivateSIRTCommand = new Command<string>(this.ActivateSIRTCommandHandler);
|
|
this.SetMetrologyParametersCommand = new Command(this.SetMetrologyParametersCommandHandler);
|
|
this.SwitchSettingsVisibilityCommand = new Command(this.SwitchSettingsVisibilityCommandHandler);
|
|
|
|
this.meterSizes = SqlConnection
|
|
.CreateSqlConnection(Appsettings.GetSetting("ConnectionString"))
|
|
.CreateCommand($@"
|
|
SELECT TRIM(CONCAT(
|
|
mt.Title
|
|
, IIF(mt.Additive IS NULL, NULL, ' ')
|
|
, mt.Additive
|
|
, IIF(SUBSTRING(nw.Title, 1, 1) BETWEEN '0' AND '9', ' DN', ' ')
|
|
, nw.Title))
|
|
, mtnw.Value
|
|
, ms.Ruecklaufsperre
|
|
, ms.Volume_per_Pulse
|
|
, ms.Volume_per_LED_Pulse
|
|
FROM CSD.MeterType AS mt
|
|
JOIN CSD.MeterTypeNominalWidth AS mtnw
|
|
ON mt.ID = mtnw.MeterType_ID
|
|
JOIN CSD.NominalWidth AS nw
|
|
ON mtnw.NominalWidth_ID = nw.ID
|
|
JOIN eRegister_Metersize AS ms
|
|
ON mtnw.Value = ms.Metersize
|
|
WHERE ms.Volume_per_Pulse IS NOT NULL
|
|
ORDER BY mt.Value, mtnw.Value")
|
|
.ExecuteReader(x => new MeterSizeVM
|
|
{
|
|
Title = x.GetValue<string>(0),
|
|
Size = x.GetValue<byte>(1),
|
|
UseCandIRules = x.GetValue<bool>(2),
|
|
Vpp = x.GetValue<int>(3),
|
|
VppLED = x.GetValue<uint>(4),
|
|
})
|
|
.ToDictionary(x => x.Title, x => x);
|
|
this.meterSizes[string.Empty] = null;
|
|
this.MeterSizes = this.meterSizes.Keys.ToArray();
|
|
this.DecimalPlacesSource = Enum.GetNames(typeof(DecimalPointLocations));
|
|
this.telegrams = new Dictionary<string, PropertyVM>();
|
|
|
|
foreach (var property in typeof(SEMI).GetProperties(BindingFlags.Public | BindingFlags.Instance))
|
|
{
|
|
var name = property.Name;
|
|
|
|
this.telegrams[name] = new PropertyVM
|
|
{
|
|
Source = nameof(SEMI),
|
|
Name = name
|
|
};
|
|
}
|
|
|
|
foreach (var property in typeof(DEBUG).GetProperties(BindingFlags.Public | BindingFlags.Instance))
|
|
{
|
|
var name = property.Name;
|
|
|
|
this.telegrams[name] = new PropertyVM
|
|
{
|
|
Source = nameof(DEBUG),
|
|
Name = name
|
|
};
|
|
}
|
|
|
|
foreach (var property in typeof(BUP).GetProperties(BindingFlags.Public | BindingFlags.Instance))
|
|
{
|
|
var name = property.Name;
|
|
|
|
this.telegrams[name] = new PropertyVM
|
|
{
|
|
Source = nameof(BUP),
|
|
Name = name
|
|
};
|
|
}
|
|
|
|
foreach (var property in typeof(LAT).GetProperties(BindingFlags.Public | BindingFlags.Instance))
|
|
{
|
|
var name = property.Name;
|
|
|
|
this.telegrams[name] = new PropertyVM
|
|
{
|
|
Source = nameof(LAT),
|
|
Name = name
|
|
};
|
|
}
|
|
|
|
this.Properties = this.telegrams.Values.ToArray();
|
|
this.MessurementUnitsSource = Enum
|
|
.GetValues(typeof(MessurementUnits))
|
|
.Cast<MessurementUnits>()
|
|
.Where(x => (int)x < 10)
|
|
.Select(x => x.ToString())
|
|
.ToArray();
|
|
}
|
|
|
|
private string sirtInfo = "No SIRT is connected";
|
|
public string SIRTInfo
|
|
{
|
|
get => this.sirtInfo;
|
|
set => this.SetValue(x => x.sirtInfo = value);
|
|
}
|
|
|
|
private string modeInfo;
|
|
public string ModeInfo
|
|
{
|
|
get => this.modeInfo;
|
|
set => this.SetValue(x => x.modeInfo = value);
|
|
}
|
|
|
|
private uint address = 4291268719;
|
|
public uint Address
|
|
{
|
|
get => this.address;
|
|
set => this.SetValue(x => x.address = value);
|
|
}
|
|
|
|
private string meterSize;
|
|
public string MeterSize
|
|
{
|
|
get => this.meterSize;
|
|
set => this.SetValue(x =>
|
|
{
|
|
x.meterSize = value;
|
|
|
|
if (!string.IsNullOrWhiteSpace(x.meterSize) && this.meterSizes.TryGetValue(x.meterSize, out var ms))
|
|
{
|
|
this.VPP = ms.Vpp;
|
|
this.VPPLED = ms.VppLED;
|
|
this.UseCandIRules = ms.UseCandIRules;
|
|
this.Units = $"{MessurementUnits.Cubic_Meters}";
|
|
this.DecimalPlaces = $"{(ms.Vpp < 700 ? DecimalPointLocations.Three : DecimalPointLocations.Two)}";
|
|
}
|
|
else
|
|
{
|
|
this.VPP = default(int);
|
|
this.VPPLED = default(int);
|
|
this.UseCandIRules = default(bool);
|
|
this.Units = default(string);
|
|
this.DecimalPlaces = default(string);
|
|
}
|
|
});
|
|
}
|
|
|
|
private int vpp;
|
|
public int VPP
|
|
{
|
|
get => this.vpp;
|
|
set => this.SetValue(x => x.vpp = value);
|
|
}
|
|
|
|
private uint vppLED;
|
|
public uint VPPLED
|
|
{
|
|
get => this.vppLED;
|
|
set => this.SetValue(x => x.vppLED = value);
|
|
}
|
|
|
|
private int offsetFactor;
|
|
public int OffsetFactor
|
|
{
|
|
get => this.offsetFactor;
|
|
set => this.SetValue(x => x.offsetFactor = value);
|
|
}
|
|
|
|
private byte offsetTime;
|
|
public byte OffsetTime
|
|
{
|
|
get => this.offsetTime;
|
|
set => this.SetValue(x => x.offsetTime = value);
|
|
}
|
|
|
|
private byte factoryCalibration;
|
|
public byte FactoryCalibration
|
|
{
|
|
get => this.factoryCalibration;
|
|
set => this.SetValue(x => x.factoryCalibration = value);
|
|
}
|
|
|
|
private string units;
|
|
public string Units
|
|
{
|
|
get => this.units;
|
|
set => this.SetValue(x => x.units = value);
|
|
}
|
|
|
|
private string decimalPlaces;
|
|
public string DecimalPlaces
|
|
{
|
|
get => this.decimalPlaces;
|
|
set => this.SetValue(x => x.decimalPlaces = value);
|
|
}
|
|
|
|
private bool useCandIRules;
|
|
public bool UseCandIRules
|
|
{
|
|
get => this.useCandIRules;
|
|
set => this.SetValue(x => x.useCandIRules = value);
|
|
}
|
|
|
|
private string status;
|
|
public string Status
|
|
{
|
|
get => this.status;
|
|
set => this.SetValue(x => x.status = value);
|
|
}
|
|
|
|
private bool areSettingsVisible;
|
|
public bool AreSettingsVisible
|
|
{
|
|
get => this.areSettingsVisible;
|
|
set => this.SetValue(x => x.areSettingsVisible = value);
|
|
}
|
|
|
|
private bool stayAwake;
|
|
public bool StayAwake
|
|
{
|
|
get => this.stayAwake;
|
|
set => this.SetValue(x => x.stayAwake = value);
|
|
}
|
|
|
|
private bool changeMode;
|
|
public bool ChangeMode
|
|
{
|
|
get => this.changeMode;
|
|
set => this.SetValue(x => x.changeMode = value);
|
|
}
|
|
|
|
private byte testModeHours;
|
|
public byte TestModeHours
|
|
{
|
|
get
|
|
{
|
|
var testModeHoursString = Appsettings.GetSetting(nameof(this.TestModeHours));
|
|
|
|
_ = byte.TryParse($"{testModeHoursString}", out this.testModeHours);
|
|
|
|
return this.testModeHours;
|
|
}
|
|
set => this.SetValue(x =>
|
|
{
|
|
this.testModeHours = Math.Max(Math.Min(value, (byte)72), byte.MinValue);
|
|
|
|
if (this.testModeHours == 0)
|
|
{
|
|
this.ModeInfo = $"Test mode is off";
|
|
}
|
|
else
|
|
{
|
|
this.ModeInfo = $"Test mode is on for {this.testModeHours} h";
|
|
}
|
|
|
|
Appsettings.SetSetting(nameof(this.TestModeHours), $"{this.testModeHours}");
|
|
});
|
|
}
|
|
|
|
public string SIRT_433
|
|
{
|
|
get => Appsettings.GetSetting(nameof(this.SIRT_433));
|
|
set => Appsettings.SetSetting(nameof(this.SIRT_433), value);
|
|
}
|
|
|
|
public string SIRT_868
|
|
{
|
|
get => Appsettings.GetSetting(nameof(this.SIRT_868));
|
|
set => Appsettings.SetSetting(nameof(this.SIRT_868), value);
|
|
}
|
|
|
|
private string ledInfo;
|
|
public string LEDInfo
|
|
{
|
|
get => this.ledInfo;
|
|
set => this.SetValue(x => x.ledInfo = value);
|
|
}
|
|
|
|
private byte ledOnTime;
|
|
public byte LEDOnTime
|
|
{
|
|
get
|
|
{
|
|
var ledOnTimeString = Appsettings.GetSetting(nameof(this.LEDOnTime));
|
|
|
|
_ = byte.TryParse($"{ledOnTimeString}", out this.ledOnTime);
|
|
|
|
return this.ledOnTime;
|
|
}
|
|
set => this.SetValue(x =>
|
|
{
|
|
this.ledOnTime = Math.Max(Math.Min(value, byte.MaxValue), byte.MinValue);
|
|
|
|
if (this.ledOnTime == 0)
|
|
{
|
|
this.LEDInfo = $"LED is off";
|
|
}
|
|
else
|
|
{
|
|
this.LEDInfo = $"LED is on for {this.ledOnTime} min";
|
|
}
|
|
|
|
Appsettings.SetSetting(nameof(this.LEDOnTime), $"{this.ledOnTime}");
|
|
});
|
|
}
|
|
|
|
public ICommand ActivateSIRTCommand { get; }
|
|
|
|
public ICommand SetMetrologyParametersCommand { get; }
|
|
|
|
public ICommand SwitchSettingsVisibilityCommand { get; }
|
|
|
|
public string[] MeterSizes { get; }
|
|
|
|
public string[] DecimalPlacesSource { get; }
|
|
|
|
public PropertyVM[] Properties { get; }
|
|
|
|
public string[] MessurementUnitsSource { get; }
|
|
|
|
private void ActivateSIRTCommandHandler(string portName)
|
|
{
|
|
Task.Run(() =>
|
|
{
|
|
this.InvokeAsync(() =>
|
|
{
|
|
this.SIRTInfo = $"Disconnecting {this.portName} ...";
|
|
AppHost.SIRTHub.Close(this.portName);
|
|
});
|
|
})
|
|
.ContinueWith(_ =>
|
|
{
|
|
this.InvokeAsync(() =>
|
|
{
|
|
this.SIRTInfo = $"Connecting {portName} ...";
|
|
AppHost.SIRTHub.TryOpen(portName, out this.sirtId, out this.frequency);
|
|
});
|
|
});
|
|
}
|
|
|
|
private void SIRTHub_Connected(SIRTBroadcaster sirt)
|
|
{
|
|
this.sirt = sirt;
|
|
this.portName = this.sirt.PortName;
|
|
this.SIRTInfo = $"{this.sirt.Id}|{this.sirt.Frequency}Mhz";
|
|
}
|
|
|
|
private void Ertask_MessageReceived(byte[] bytes)
|
|
{
|
|
if (bytes is null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
var message = new SIRTMessage(bytes);
|
|
|
|
if (message.Command == SIRTConstants.FROM_AIR)
|
|
{
|
|
var p11 = new P11(message.P1);
|
|
var rssi = new RSSI(message.P2, (ushort)this.sirt.Frequency);
|
|
|
|
var data = message.Payload;
|
|
var length = data.Length;
|
|
|
|
if (length > 0)
|
|
{
|
|
var type = data[0];
|
|
var telegram = default(object);
|
|
var background = Brushes.White;
|
|
|
|
if (type == SIRTConstants.BUP)
|
|
{
|
|
telegram = new BUP(data, p11);
|
|
}
|
|
else if (type == SIRTConstants.LAT)
|
|
{
|
|
telegram = new LAT(data, p11);
|
|
}
|
|
else if (type == SIRTConstants.DEBUG)
|
|
{
|
|
telegram = new DEBUG(data, p11);
|
|
}
|
|
else if (type == SIRTConstants.SEMI)
|
|
{
|
|
telegram = new SEMI(data, this.sirt.Frequency, p11);
|
|
}
|
|
|
|
if (telegram != null)
|
|
{
|
|
var sourceType = telegram.GetType();
|
|
var sourceName = sourceType.Name;
|
|
|
|
foreach (var property in sourceType.GetProperties(BindingFlags.Public | BindingFlags.Instance))
|
|
{
|
|
var name = property.Name;
|
|
|
|
if (this.telegrams.TryGetValue(name, out var propertyVM))
|
|
{
|
|
propertyVM.Source = sourceName;
|
|
propertyVM.Value = $"{property.GetValue(telegram)}";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void SIRTHub_Disconnected(SIRTBroadcaster sirt)
|
|
{
|
|
this.sirt = null;
|
|
this.SIRTInfo = $"{sirt.PortName} disconnected";
|
|
}
|
|
|
|
private void SetMetrologyParametersCommandHandler()
|
|
{
|
|
this.Status = null;
|
|
|
|
foreach (var property in this.telegrams.Values)
|
|
{
|
|
property.Value = null;
|
|
}
|
|
|
|
if (this.sirt is null)
|
|
{
|
|
this.Status = "No SIRT is activated";
|
|
|
|
return;
|
|
}
|
|
|
|
var _vpp = (this.vpp * 65536) | 0x80_00_00_00;
|
|
var __vpp = (int)_vpp; // 625 = -2106523648
|
|
|
|
var task = new EregisterTask(this.sirt.Frequency)
|
|
{
|
|
DelPamSemi = true,
|
|
WakeUpCmd = true,
|
|
RequestAddress = this.Address,
|
|
};
|
|
|
|
try
|
|
{
|
|
task.SetCancelled();
|
|
this.cancellationTokenSource.Cancel();
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
this.Status = e.Message;
|
|
}
|
|
finally
|
|
{
|
|
this.cancellationTokenSource = null;
|
|
this.cancellationToken = default(CancellationToken);
|
|
this.cancellationTask = null;
|
|
}
|
|
|
|
this.cancellationTokenSource = new CancellationTokenSource();
|
|
this.cancellationToken = this.cancellationTokenSource.Token;
|
|
this.cancellationTask = Task.Run(() =>
|
|
{
|
|
void StateChanged(SIRTTask x)
|
|
{
|
|
this.Status = x.State.ToString();
|
|
}
|
|
|
|
task.MessageReceived += this.Ertask_MessageReceived;
|
|
task.StateChanged += StateChanged;
|
|
|
|
if (this.StayAwake)
|
|
{
|
|
task.WakeUpModul = this.StayAwake;
|
|
task.Data = new ChangeWakeUp
|
|
{
|
|
WakeUpMode = WakeUpMode.StayAwake
|
|
}
|
|
.Append(new ProvidePin
|
|
{
|
|
AuthLevel = AuthLevel.II
|
|
});
|
|
|
|
this.Status = "Changing wake status";
|
|
|
|
task.SetPending();
|
|
|
|
while (task.State != SIRTTaskState.Completed && task.State != SIRTTaskState.Cancelled)
|
|
{
|
|
AppHost.SIRTHub.Start(task);
|
|
task.Wait();
|
|
|
|
if (task.State == SIRTTaskState.Completed && task.State == SIRTTaskState.Cancelled)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
task.WakeUpModul = false;
|
|
}
|
|
|
|
if (!string.IsNullOrWhiteSpace(this.MeterSize))
|
|
{
|
|
task.Data = new SetMetrologyParameters
|
|
{
|
|
DecimalPoint = this.VPP < 700 ? DecimalPointLocations.Three : DecimalPointLocations.Two,
|
|
MeterSize = this.meterSizes.TryGetValue(this.MeterSize, out var ms) ? ms.Size : (byte)23,
|
|
FactoryCalibration = this.FactoryCalibration,
|
|
OffsetFactor = this.OffsetFactor,
|
|
OffsetTime = this.OffsetTime,
|
|
Units = Enum.TryParse<MessurementUnits>($"{this.Units}", out var units) ? units : MessurementUnits.Cubic_Meters,
|
|
UseCandIRules = this.UseCandIRules,
|
|
VppLED = this.vppLED * 65536,
|
|
Vpp = __vpp,
|
|
}
|
|
.Append(new ProvidePin
|
|
{
|
|
AuthLevel = AuthLevel.III
|
|
});
|
|
|
|
this.Status = "Changing metrology values";
|
|
|
|
task.SetPending();
|
|
|
|
while (task.State != SIRTTaskState.Completed && task.State != SIRTTaskState.Cancelled)
|
|
{
|
|
AppHost.SIRTHub.Start(task);
|
|
task.Wait();
|
|
|
|
if (task.State == SIRTTaskState.Completed && task.State == SIRTTaskState.Cancelled)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
task.Data = new OpticalTelegram
|
|
{
|
|
Minutes = this.ChangeMode ? byte.MinValue : this.LEDOnTime
|
|
}
|
|
.Append(new ProvidePin
|
|
{
|
|
AuthLevel = AuthLevel.III
|
|
});
|
|
|
|
this.Status = "Changing LED status";
|
|
|
|
task.SetPending();
|
|
|
|
while (task.State != SIRTTaskState.Completed && task.State != SIRTTaskState.Cancelled)
|
|
{
|
|
AppHost.SIRTHub.Start(task);
|
|
task.Wait();
|
|
|
|
if (task.State == SIRTTaskState.Completed && task.State == SIRTTaskState.Cancelled)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (this.ChangeMode)
|
|
{
|
|
task.Data = new ActivateMetrologyTestMode()
|
|
{
|
|
Hours = this.TestModeHours
|
|
}
|
|
.Append(new ProvidePin
|
|
{
|
|
AuthLevel = AuthLevel.I
|
|
});
|
|
|
|
task.SetPending();
|
|
|
|
while (task.State != SIRTTaskState.Completed && task.State != SIRTTaskState.Cancelled)
|
|
{
|
|
AppHost.SIRTHub.Start(task);
|
|
task.Wait();
|
|
|
|
if (task.State == SIRTTaskState.Completed && task.State == SIRTTaskState.Cancelled)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
task.StateChanged -= StateChanged;
|
|
task.MessageReceived -= this.Ertask_MessageReceived;
|
|
}, this.cancellationToken);
|
|
}
|
|
|
|
private void SwitchSettingsVisibilityCommandHandler()
|
|
=> this.AreSettingsVisible = !this.AreSettingsVisible;
|
|
}
|
|
}
|