Mini8TabViewModel.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371
  1. using CommunityToolkit.Mvvm.ComponentModel;
  2. using CommunityToolkit.Mvvm.Input;
  3. using GeneralData;
  4. using Mini8SlaveSim.Configuration;
  5. using Mini8SlaveSim.Services;
  6. using System.Collections.ObjectModel;
  7. using System.Windows.Controls;
  8. using System.Windows.Threading;
  9. namespace Mini8SlaveSim.ViewModels;
  10. public partial class RowItem : ObservableObject
  11. {
  12. [ObservableProperty]
  13. private string _name = string.Empty;
  14. [ObservableProperty]
  15. private string _ch1 = string.Empty;
  16. [ObservableProperty]
  17. private string _ch2 = string.Empty;
  18. [ObservableProperty]
  19. private string _ch3 = string.Empty;
  20. [ObservableProperty]
  21. private string _ch4 = string.Empty;
  22. [ObservableProperty]
  23. private string _ch5 = string.Empty;
  24. [ObservableProperty]
  25. private string _ch6 = string.Empty;
  26. [ObservableProperty]
  27. private string _ch7 = string.Empty;
  28. [ObservableProperty]
  29. private string _ch8 = string.Empty;
  30. [ObservableProperty]
  31. private string _ch9 = string.Empty;
  32. [ObservableProperty]
  33. private string _ch10 = string.Empty;
  34. [ObservableProperty]
  35. private string _ch11 = string.Empty;
  36. [ObservableProperty]
  37. private string _ch12 = string.Empty;
  38. [ObservableProperty]
  39. private string _ch13 = string.Empty;
  40. [ObservableProperty]
  41. private string _ch14 = string.Empty;
  42. [ObservableProperty]
  43. private string _ch15 = string.Empty;
  44. [ObservableProperty]
  45. private string _ch16 = string.Empty;
  46. }
  47. enum DataType
  48. {
  49. UShort = 1,
  50. Float = 2
  51. }
  52. public partial class Mini8TabViewModel : ObservableObject
  53. {
  54. private readonly ISharedConfig _sharedConfig;
  55. private readonly ISlaveManagementService _slaveManagementService;
  56. private readonly byte _slaveId = 0;
  57. private readonly Dictionary<string, Dictionary<byte, (ushort, DataType)>> _pointNamePosition = [];
  58. private readonly DispatcherTimer _timer;
  59. [ObservableProperty]
  60. private ObservableCollection<RowItem> _rowItems = [];
  61. [ObservableProperty]
  62. private string _registerName = string.Empty;
  63. [ObservableProperty]
  64. private string _channelNumber = string.Empty;
  65. [ObservableProperty]
  66. private string _writeValue = string.Empty;
  67. public Mini8TabViewModel(ISharedConfig sharedConfig, ISlaveManagementService slaveManagementService)
  68. {
  69. _sharedConfig = sharedConfig;
  70. _slaveManagementService = slaveManagementService;
  71. _slaveId = _slaveManagementService.WaitingForCreating;
  72. _timer = new(TimeSpan.FromSeconds(1), DispatcherPriority.Normal, OnTimeup, App.Current.Dispatcher);
  73. Initialize();
  74. }
  75. [RelayCommand]
  76. private void CellClick(SelectedCellsChangedEventArgs e)
  77. {
  78. var added = e.AddedCells.FirstOrDefault();
  79. if (added.Column is null || added.Item is null)
  80. {
  81. return;
  82. }
  83. var row = (RowItem)added.Item;
  84. var header = added.Column.Header.ToString() ?? string.Empty;
  85. if (string.IsNullOrWhiteSpace(header))
  86. {
  87. return;
  88. }
  89. string chStr = string.Empty;
  90. for (int i = 0; i < header.Length; i++)
  91. {
  92. if (Char.IsDigit(header[i]))
  93. {
  94. chStr += header[i];
  95. }
  96. }
  97. if (string.IsNullOrWhiteSpace(chStr))
  98. {
  99. return;
  100. }
  101. RegisterName = row.Name;
  102. ChannelNumber = chStr;
  103. }
  104. [RelayCommand]
  105. private void Write()
  106. {
  107. if (!_pointNamePosition.TryGetValue(RegisterName, out var register) || register is null)
  108. {
  109. return;
  110. }
  111. if (!byte.TryParse(ChannelNumber, out var number))
  112. {
  113. return;
  114. }
  115. if (!register.TryGetValue(number, out var posDatatype))
  116. {
  117. return;
  118. }
  119. var slave = _slaveManagementService.Slaves[_slaveId];
  120. var dataStore = slave.SlaveDataStore;
  121. if (posDatatype.Item2 == DataType.UShort)
  122. {
  123. if (!ushort.TryParse(WriteValue, out var finalValue))
  124. {
  125. return;
  126. }
  127. slave.TryWriteValues(dataStore.HoldingRegisters, posDatatype.Item1, [finalValue]);
  128. return;
  129. }
  130. if (posDatatype.Item2 == DataType.Float)
  131. {
  132. if (!float.TryParse(WriteValue, out var floatValue))
  133. {
  134. return;
  135. }
  136. var bytes = BitConverter.GetBytes(floatValue);
  137. if(BitConverter.IsLittleEndian)
  138. {
  139. Array.Reverse(bytes);
  140. }
  141. var high = BitConverter.ToUInt16([bytes[1],bytes[0]], 0);
  142. var low = BitConverter.ToUInt16([bytes[3], bytes[2]], 0);
  143. slave.TryWriteValues(dataStore.HoldingRegisters, posDatatype.Item1, [high, low]);
  144. }
  145. }
  146. private void OnTimeup(object? sender, EventArgs e)
  147. {
  148. var slave = _slaveManagementService.Slaves[_slaveId];
  149. var dataStore = slave.SlaveDataStore;
  150. foreach (var point in _pointNamePosition)
  151. {
  152. var pointName = point.Key;
  153. var chs = point.Value;
  154. foreach (var ch in chs)
  155. {
  156. var chNumber = ch.Key;
  157. var registerPos = ch.Value.Item1;
  158. var usedRegister = (ushort)ch.Value.Item2;
  159. var rst = slave.TryReadValues(dataStore.HoldingRegisters, registerPos, usedRegister, out var outPoints);
  160. if (!rst || outPoints is null)
  161. {
  162. continue;
  163. }
  164. string valueStr = string.Empty;
  165. foreach (var item in outPoints)
  166. {
  167. var ushortStr = Convert.ToString(item, 2).PadLeft(16, '0');
  168. valueStr += ushortStr;
  169. }
  170. if (usedRegister == (int)DataType.UShort)
  171. {
  172. var value = Convert.ToUInt16(valueStr, 2);
  173. if (pointName == "AutoTuneStatus")
  174. {
  175. valueStr = value switch
  176. {
  177. (ushort)AutoTuneStatus.Unavailable => AutoTuneStatus.Unavailable.ToString(),
  178. (ushort)AutoTuneStatus.Ready => AutoTuneStatus.Ready.ToString(),
  179. (ushort)AutoTuneStatus.Triggered => AutoTuneStatus.Triggered.ToString(),
  180. (ushort)AutoTuneStatus.Tuning => AutoTuneStatus.Tuning.ToString(),
  181. (ushort)AutoTuneStatus.Complete => AutoTuneStatus.Complete.ToString(),
  182. (ushort)AutoTuneStatus.Aborted => AutoTuneStatus.Aborted.ToString(),
  183. (ushort)AutoTuneStatus.Timeout => AutoTuneStatus.Timeout.ToString(),
  184. (ushort)AutoTuneStatus.Overflow => AutoTuneStatus.Overflow.ToString(),
  185. _ => throw new NotImplementedException(),
  186. };
  187. }
  188. else if (pointName == "SensorBreakAlarm1" || pointName == "SensorBreakAlarm2")
  189. {
  190. valueStr = value switch
  191. {
  192. (ushort)TcBorken.Normal => TcBorken.Normal.ToString(),
  193. (ushort)TcBorken.Error => TcBorken.Error.ToString(),
  194. _ => throw new NotImplementedException(),
  195. };
  196. }
  197. else if (pointName == "ActiveTuneSet")
  198. {
  199. valueStr = value switch
  200. {
  201. (ushort)ActiveTuneSet.AutoTune => ActiveTuneSet.AutoTune.ToString(),
  202. (ushort)ActiveTuneSet.Running => ActiveTuneSet.Running.ToString(),
  203. _ => throw new NotImplementedException(),
  204. };
  205. }
  206. else if (pointName == "Inhibit")
  207. {
  208. valueStr = value switch
  209. {
  210. (ushort)Inhibit.Enable => Inhibit.Enable.ToString(),
  211. (ushort)Inhibit.Disable => Inhibit.Disable.ToString(),
  212. _ => throw new NotImplementedException(),
  213. };
  214. }
  215. else if(pointName == "ActiveAutoTune")
  216. {
  217. valueStr = value switch
  218. {
  219. (ushort)AutotuneActive.OFF => AutotuneActive.OFF.ToString(),
  220. (ushort)AutotuneActive.Active => AutotuneActive.Active.ToString(),
  221. _ => throw new NotImplementedException(),
  222. };
  223. }
  224. else
  225. {
  226. valueStr = value.ToString();
  227. }
  228. }
  229. if (usedRegister == (int)DataType.Float)
  230. {
  231. uint intValue = Convert.ToUInt32(valueStr, 2);
  232. byte[] bytes = BitConverter.GetBytes(intValue);
  233. var value = BitConverter.ToSingle(bytes, 0);
  234. valueStr = value.ToString();
  235. }
  236. var rowitem = RowItems.First(item => item.Name == pointName);
  237. switch (chNumber)
  238. {
  239. case 1:
  240. if (rowitem.Ch1 != valueStr) rowitem.Ch1 = valueStr;
  241. break;
  242. case 2:
  243. if (rowitem.Ch2 != valueStr) rowitem.Ch2 = valueStr;
  244. break;
  245. case 3:
  246. if (rowitem.Ch3 != valueStr) rowitem.Ch3 = valueStr;
  247. break;
  248. case 4:
  249. if (rowitem.Ch4 != valueStr) rowitem.Ch4 = valueStr;
  250. break;
  251. case 5:
  252. if (rowitem.Ch5 != valueStr) rowitem.Ch5 = valueStr;
  253. break;
  254. case 6:
  255. if (rowitem.Ch6 != valueStr) rowitem.Ch6 = valueStr;
  256. break;
  257. case 7:
  258. if (rowitem.Ch7 != valueStr) rowitem.Ch7 = valueStr;
  259. break;
  260. case 8:
  261. if (rowitem.Ch8 != valueStr) rowitem.Ch8 = valueStr;
  262. break;
  263. case 9:
  264. if (rowitem.Ch9 != valueStr) rowitem.Ch9 = valueStr;
  265. break;
  266. case 10:
  267. if (rowitem.Ch10 != valueStr) rowitem.Ch10 = valueStr;
  268. break;
  269. case 11:
  270. if (rowitem.Ch11 != valueStr) rowitem.Ch11 = valueStr;
  271. break;
  272. case 12:
  273. if (rowitem.Ch12 != valueStr) rowitem.Ch12 = valueStr;
  274. break;
  275. case 13:
  276. if (rowitem.Ch13 != valueStr) rowitem.Ch13 = valueStr;
  277. break;
  278. case 14:
  279. if (rowitem.Ch14 != valueStr) rowitem.Ch14 = valueStr;
  280. break;
  281. case 15:
  282. if (rowitem.Ch15 != valueStr) rowitem.Ch15 = valueStr;
  283. break;
  284. case 16:
  285. if (rowitem.Ch16 != valueStr) rowitem.Ch16 = valueStr;
  286. break;
  287. default:
  288. break;
  289. }
  290. }
  291. }
  292. }
  293. private void Initialize()
  294. {
  295. if (_slaveId <= 0)
  296. {
  297. return;
  298. }
  299. var mini8Chs = _sharedConfig.HardwareAddress.Mini8ChannelsAddress[_slaveId];
  300. foreach (var ch in mini8Chs)
  301. {
  302. AddData(nameof(ch.Value.PV), ch.Key, ch.Value.PV, DataType.Float);
  303. AddData(nameof(ch.Value.WorkingOutput), ch.Key, ch.Value.WorkingOutput, DataType.Float);
  304. AddData(nameof(ch.Value.AutoTuneStatus), ch.Key, ch.Value.AutoTuneStatus, DataType.UShort);
  305. AddData(nameof(ch.Value.AutoTune_P), ch.Key, ch.Value.AutoTune_P, DataType.Float);
  306. AddData(nameof(ch.Value.AutoTune_I), ch.Key, ch.Value.AutoTune_I, DataType.Float);
  307. AddData(nameof(ch.Value.AutoTune_D), ch.Key, ch.Value.AutoTune_D, DataType.Float);
  308. AddData(nameof(ch.Value.SensorBreakAlarm1), ch.Key, ch.Value.SensorBreakAlarm1, DataType.UShort);
  309. AddData(nameof(ch.Value.SensorBreakAlarm2), ch.Key, ch.Value.SensorBreakAlarm2, DataType.UShort);
  310. AddData(nameof(ch.Value.SetPoint), ch.Key, ch.Value.SetPoint, DataType.Float);
  311. AddData(nameof(ch.Value.ActiveTuneSet), ch.Key, ch.Value.ActiveTuneSet, DataType.UShort);
  312. AddData(nameof(ch.Value.Running_P), ch.Key, ch.Value.Running_P, DataType.Float);
  313. AddData(nameof(ch.Value.Running_I), ch.Key, ch.Value.Running_I, DataType.Float);
  314. AddData(nameof(ch.Value.Running_D), ch.Key, ch.Value.Running_D, DataType.Float);
  315. AddData(nameof(ch.Value.Inhibit), ch.Key, ch.Value.Inhibit, DataType.UShort);
  316. AddData(nameof(ch.Value.ActiveAutoTune), ch.Key, ch.Value.ActiveAutoTune, DataType.UShort);
  317. AddData(nameof(ch.Value.SetpointUpRate), ch.Key, ch.Value.SetpointUpRate, DataType.Float);
  318. AddData(nameof(ch.Value.SetpointDownRate), ch.Key, ch.Value.SetpointDownRate, DataType.Float);
  319. AddData(nameof(ch.Value.Caps), ch.Key, ch.Value.Caps, DataType.UShort);
  320. AddData(nameof(ch.Value.Floor), ch.Key, ch.Value.Floor, DataType.UShort);
  321. AddData(nameof(ch.Value.CapsWarning), ch.Key, ch.Value.CapsWarning, DataType.UShort);
  322. AddData(nameof(ch.Value.FloorWarning), ch.Key, ch.Value.FloorWarning, DataType.UShort);
  323. }
  324. _timer.Start();
  325. }
  326. private void AddData(string name, byte key, ushort value, DataType dataType)
  327. {
  328. if (!_pointNamePosition.ContainsKey(name))
  329. {
  330. _pointNamePosition[name] = [];
  331. RowItems.Add(new RowItem() { Name = name });
  332. }
  333. _pointNamePosition[name].Add(key, (value, dataType));
  334. }
  335. }