using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using GeneralData; using Mini8SlaveSim.Configuration; using Mini8SlaveSim.Services; using System.Collections.ObjectModel; using System.Windows.Controls; using System.Windows.Threading; namespace Mini8SlaveSim.ViewModels; public partial class RowItem : ObservableObject { [ObservableProperty] private string _name = string.Empty; [ObservableProperty] private string _ch1 = string.Empty; [ObservableProperty] private string _ch2 = string.Empty; [ObservableProperty] private string _ch3 = string.Empty; [ObservableProperty] private string _ch4 = string.Empty; [ObservableProperty] private string _ch5 = string.Empty; [ObservableProperty] private string _ch6 = string.Empty; [ObservableProperty] private string _ch7 = string.Empty; [ObservableProperty] private string _ch8 = string.Empty; [ObservableProperty] private string _ch9 = string.Empty; [ObservableProperty] private string _ch10 = string.Empty; [ObservableProperty] private string _ch11 = string.Empty; [ObservableProperty] private string _ch12 = string.Empty; [ObservableProperty] private string _ch13 = string.Empty; [ObservableProperty] private string _ch14 = string.Empty; [ObservableProperty] private string _ch15 = string.Empty; [ObservableProperty] private string _ch16 = string.Empty; } enum DataType { UShort = 1, Float = 2 } public partial class Mini8TabViewModel : ObservableObject { private readonly ISharedConfig _sharedConfig; private readonly ISlaveManagementService _slaveManagementService; private readonly byte _slaveId = 0; private readonly Dictionary> _pointNamePosition = []; private readonly DispatcherTimer _timer; [ObservableProperty] private ObservableCollection _rowItems = []; [ObservableProperty] private string _registerName = string.Empty; [ObservableProperty] private string _channelNumber = string.Empty; [ObservableProperty] private string _writeValue = string.Empty; public Mini8TabViewModel(ISharedConfig sharedConfig, ISlaveManagementService slaveManagementService) { _sharedConfig = sharedConfig; _slaveManagementService = slaveManagementService; _slaveId = _slaveManagementService.WaitingForCreating; _timer = new(TimeSpan.FromSeconds(1), DispatcherPriority.Normal, OnTimeup, App.Current.Dispatcher); Initialize(); } [RelayCommand] private void CellClick(SelectedCellsChangedEventArgs e) { var added = e.AddedCells.FirstOrDefault(); if (added.Column is null || added.Item is null) { return; } var row = (RowItem)added.Item; var header = added.Column.Header.ToString() ?? string.Empty; if (string.IsNullOrWhiteSpace(header)) { return; } string chStr = string.Empty; for (int i = 0; i < header.Length; i++) { if (Char.IsDigit(header[i])) { chStr += header[i]; } } if (string.IsNullOrWhiteSpace(chStr)) { return; } RegisterName = row.Name; ChannelNumber = chStr; } [RelayCommand] private void Write() { if (!_pointNamePosition.TryGetValue(RegisterName, out var register) || register is null) { return; } if (!byte.TryParse(ChannelNumber, out var number)) { return; } if (!register.TryGetValue(number, out var posDatatype)) { return; } var slave = _slaveManagementService.Slaves[_slaveId]; var dataStore = slave.SlaveDataStore; if (posDatatype.Item2 == DataType.UShort) { if (!ushort.TryParse(WriteValue, out var finalValue)) { return; } slave.TryWriteValues(dataStore.HoldingRegisters, posDatatype.Item1, [finalValue]); return; } if (posDatatype.Item2 == DataType.Float) { if (!float.TryParse(WriteValue, out var floatValue)) { return; } var bytes = BitConverter.GetBytes(floatValue); if(BitConverter.IsLittleEndian) { Array.Reverse(bytes); } var high = BitConverter.ToUInt16([bytes[1],bytes[0]], 0); var low = BitConverter.ToUInt16([bytes[3], bytes[2]], 0); slave.TryWriteValues(dataStore.HoldingRegisters, posDatatype.Item1, [high, low]); } } private void OnTimeup(object? sender, EventArgs e) { var slave = _slaveManagementService.Slaves[_slaveId]; var dataStore = slave.SlaveDataStore; foreach (var point in _pointNamePosition) { var pointName = point.Key; var chs = point.Value; foreach (var ch in chs) { var chNumber = ch.Key; var registerPos = ch.Value.Item1; var usedRegister = (ushort)ch.Value.Item2; var rst = slave.TryReadValues(dataStore.HoldingRegisters, registerPos, usedRegister, out var outPoints); if (!rst || outPoints is null) { continue; } string valueStr = string.Empty; foreach (var item in outPoints) { var ushortStr = Convert.ToString(item, 2).PadLeft(16, '0'); valueStr += ushortStr; } if (usedRegister == (int)DataType.UShort) { var value = Convert.ToUInt16(valueStr, 2); if (pointName == "AutoTuneStatus") { valueStr = value switch { (ushort)AutoTuneStatus.Unavailable => AutoTuneStatus.Unavailable.ToString(), (ushort)AutoTuneStatus.Ready => AutoTuneStatus.Ready.ToString(), (ushort)AutoTuneStatus.Triggered => AutoTuneStatus.Triggered.ToString(), (ushort)AutoTuneStatus.Tuning => AutoTuneStatus.Tuning.ToString(), (ushort)AutoTuneStatus.Complete => AutoTuneStatus.Complete.ToString(), (ushort)AutoTuneStatus.Aborted => AutoTuneStatus.Aborted.ToString(), (ushort)AutoTuneStatus.Timeout => AutoTuneStatus.Timeout.ToString(), (ushort)AutoTuneStatus.Overflow => AutoTuneStatus.Overflow.ToString(), _ => throw new NotImplementedException(), }; } else if (pointName == "SensorBreakAlarm1" || pointName == "SensorBreakAlarm2") { valueStr = value switch { (ushort)TcBorken.Normal => TcBorken.Normal.ToString(), (ushort)TcBorken.Error => TcBorken.Error.ToString(), _ => throw new NotImplementedException(), }; } else if (pointName == "ActiveTuneSet") { valueStr = value switch { (ushort)ActiveTuneSet.AutoTune => ActiveTuneSet.AutoTune.ToString(), (ushort)ActiveTuneSet.Running => ActiveTuneSet.Running.ToString(), _ => throw new NotImplementedException(), }; } else if (pointName == "Inhibit") { valueStr = value switch { (ushort)Inhibit.Enable => Inhibit.Enable.ToString(), (ushort)Inhibit.Disable => Inhibit.Disable.ToString(), _ => throw new NotImplementedException(), }; } else if(pointName == "ActiveAutoTune") { valueStr = value switch { (ushort)AutotuneActive.OFF => AutotuneActive.OFF.ToString(), (ushort)AutotuneActive.Active => AutotuneActive.Active.ToString(), _ => throw new NotImplementedException(), }; } else { valueStr = value.ToString(); } } if (usedRegister == (int)DataType.Float) { uint intValue = Convert.ToUInt32(valueStr, 2); byte[] bytes = BitConverter.GetBytes(intValue); var value = BitConverter.ToSingle(bytes, 0); valueStr = value.ToString(); } var rowitem = RowItems.First(item => item.Name == pointName); switch (chNumber) { case 1: if (rowitem.Ch1 != valueStr) rowitem.Ch1 = valueStr; break; case 2: if (rowitem.Ch2 != valueStr) rowitem.Ch2 = valueStr; break; case 3: if (rowitem.Ch3 != valueStr) rowitem.Ch3 = valueStr; break; case 4: if (rowitem.Ch4 != valueStr) rowitem.Ch4 = valueStr; break; case 5: if (rowitem.Ch5 != valueStr) rowitem.Ch5 = valueStr; break; case 6: if (rowitem.Ch6 != valueStr) rowitem.Ch6 = valueStr; break; case 7: if (rowitem.Ch7 != valueStr) rowitem.Ch7 = valueStr; break; case 8: if (rowitem.Ch8 != valueStr) rowitem.Ch8 = valueStr; break; case 9: if (rowitem.Ch9 != valueStr) rowitem.Ch9 = valueStr; break; case 10: if (rowitem.Ch10 != valueStr) rowitem.Ch10 = valueStr; break; case 11: if (rowitem.Ch11 != valueStr) rowitem.Ch11 = valueStr; break; case 12: if (rowitem.Ch12 != valueStr) rowitem.Ch12 = valueStr; break; case 13: if (rowitem.Ch13 != valueStr) rowitem.Ch13 = valueStr; break; case 14: if (rowitem.Ch14 != valueStr) rowitem.Ch14 = valueStr; break; case 15: if (rowitem.Ch15 != valueStr) rowitem.Ch15 = valueStr; break; case 16: if (rowitem.Ch16 != valueStr) rowitem.Ch16 = valueStr; break; default: break; } } } } private void Initialize() { if (_slaveId <= 0) { return; } var mini8Chs = _sharedConfig.HardwareAddress.Mini8ChannelsAddress[_slaveId]; foreach (var ch in mini8Chs) { AddData(nameof(ch.Value.PV), ch.Key, ch.Value.PV, DataType.Float); AddData(nameof(ch.Value.WorkingOutput), ch.Key, ch.Value.WorkingOutput, DataType.Float); AddData(nameof(ch.Value.AutoTuneStatus), ch.Key, ch.Value.AutoTuneStatus, DataType.UShort); AddData(nameof(ch.Value.AutoTune_P), ch.Key, ch.Value.AutoTune_P, DataType.Float); AddData(nameof(ch.Value.AutoTune_I), ch.Key, ch.Value.AutoTune_I, DataType.Float); AddData(nameof(ch.Value.AutoTune_D), ch.Key, ch.Value.AutoTune_D, DataType.Float); AddData(nameof(ch.Value.SensorBreakAlarm1), ch.Key, ch.Value.SensorBreakAlarm1, DataType.UShort); AddData(nameof(ch.Value.SensorBreakAlarm2), ch.Key, ch.Value.SensorBreakAlarm2, DataType.UShort); AddData(nameof(ch.Value.SetPoint), ch.Key, ch.Value.SetPoint, DataType.Float); AddData(nameof(ch.Value.ActiveTuneSet), ch.Key, ch.Value.ActiveTuneSet, DataType.UShort); AddData(nameof(ch.Value.Running_P), ch.Key, ch.Value.Running_P, DataType.Float); AddData(nameof(ch.Value.Running_I), ch.Key, ch.Value.Running_I, DataType.Float); AddData(nameof(ch.Value.Running_D), ch.Key, ch.Value.Running_D, DataType.Float); AddData(nameof(ch.Value.Inhibit), ch.Key, ch.Value.Inhibit, DataType.UShort); AddData(nameof(ch.Value.ActiveAutoTune), ch.Key, ch.Value.ActiveAutoTune, DataType.UShort); AddData(nameof(ch.Value.SetpointUpRate), ch.Key, ch.Value.SetpointUpRate, DataType.Float); AddData(nameof(ch.Value.SetpointDownRate), ch.Key, ch.Value.SetpointDownRate, DataType.Float); AddData(nameof(ch.Value.Caps), ch.Key, ch.Value.Caps, DataType.UShort); AddData(nameof(ch.Value.Floor), ch.Key, ch.Value.Floor, DataType.UShort); AddData(nameof(ch.Value.CapsWarning), ch.Key, ch.Value.CapsWarning, DataType.UShort); AddData(nameof(ch.Value.FloorWarning), ch.Key, ch.Value.FloorWarning, DataType.UShort); } _timer.Start(); } private void AddData(string name, byte key, ushort value, DataType dataType) { if (!_pointNamePosition.ContainsKey(name)) { _pointNamePosition[name] = []; RowItems.Add(new RowItem() { Name = name }); } _pointNamePosition[name].Add(key, (value, dataType)); } }