RegisterViewerForm.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Drawing;
  4. using System.Windows.Forms;
  5. using APS7100TestTool.Services;
  6. namespace APS7100TestTool.Forms
  7. {
  8. public partial class RegisterViewerForm : Form
  9. {
  10. private ModbusTcpServerService _modbusService;
  11. private System.Windows.Forms.Timer _refreshTimer;
  12. // 存储自定义监视的地址
  13. private List<CustomRegisterEntry> _customEntries = new List<CustomRegisterEntry>();
  14. private class CustomRegisterEntry
  15. {
  16. public int Address { get; set; }
  17. public string DataType { get; set; }
  18. }
  19. public RegisterViewerForm()
  20. {
  21. InitializeComponent();
  22. InitializeDataGridColumns();
  23. }
  24. public RegisterViewerForm(ModbusTcpServerService modbusService) : this()
  25. {
  26. _modbusService = modbusService;
  27. InitializeTimer();
  28. if (_modbusService != null)
  29. {
  30. LoadRegisterData();
  31. }
  32. }
  33. private void InitializeDataGridColumns()
  34. {
  35. dgvRegisters.Columns.Clear();
  36. dgvRegisters.Columns.Add(new DataGridViewTextBoxColumn
  37. {
  38. Name = "Source",
  39. HeaderText = "来源",
  40. Width = 80
  41. });
  42. dgvRegisters.Columns.Add(new DataGridViewTextBoxColumn
  43. {
  44. Name = "Address",
  45. HeaderText = "地址",
  46. Width = 80
  47. });
  48. dgvRegisters.Columns.Add(new DataGridViewTextBoxColumn
  49. {
  50. Name = "DataType",
  51. HeaderText = "类型",
  52. Width = 80
  53. });
  54. dgvRegisters.Columns.Add(new DataGridViewTextBoxColumn
  55. {
  56. Name = "Value",
  57. HeaderText = "当前值",
  58. Width = 120,
  59. DefaultCellStyle = new DataGridViewCellStyle
  60. {
  61. Alignment = DataGridViewContentAlignment.MiddleRight,
  62. Font = new Font("Consolas", 10F, FontStyle.Bold),
  63. ForeColor = Color.FromArgb(0, 100, 180)
  64. }
  65. });
  66. dgvRegisters.Columns.Add(new DataGridViewTextBoxColumn
  67. {
  68. Name = "Description",
  69. HeaderText = "描述",
  70. Width = 300
  71. });
  72. // 设置默认选中项
  73. if (cmbDataType.Items.Count > 0)
  74. {
  75. cmbDataType.SelectedIndex = 0;
  76. }
  77. }
  78. private void InitializeTimer()
  79. {
  80. if (DesignMode) return;
  81. _refreshTimer = new System.Windows.Forms.Timer();
  82. _refreshTimer.Interval = (int)numRefreshInterval.Value;
  83. _refreshTimer.Tick += RefreshTimer_Tick;
  84. if (chkAutoRefresh.Checked)
  85. {
  86. _refreshTimer.Start();
  87. }
  88. }
  89. private void LoadRegisterData()
  90. {
  91. if (_modbusService == null || !_modbusService.IsRunning)
  92. {
  93. lblStatus.Text = "状态: Modbus 服务未运行";
  94. lblStatus.ForeColor = Color.Red;
  95. return;
  96. }
  97. try
  98. {
  99. dgvRegisters.Rows.Clear();
  100. var registerData = _modbusService.ReadAllConfiguredRegisters();
  101. var mappings = _modbusService.GetMappings();
  102. // 添加配置中的寄存器
  103. foreach (var map in mappings)
  104. {
  105. string value = "N/A";
  106. if (registerData.TryGetValue(map.Address, out var data))
  107. {
  108. value = data.RawValue;
  109. }
  110. int rowIndex = dgvRegisters.Rows.Add(
  111. "配置",
  112. map.Address.ToString(),
  113. map.DataType ?? "Int16",
  114. value,
  115. map.Description ?? ""
  116. );
  117. if (map.OperationType == "Read")
  118. {
  119. dgvRegisters.Rows[rowIndex].DefaultCellStyle.BackColor = Color.FromArgb(230, 255, 230);
  120. }
  121. }
  122. // 添加自定义监视的寄存器
  123. foreach (var entry in _customEntries)
  124. {
  125. string value = ReadRegisterValue(entry.Address, entry.DataType);
  126. int rowIndex = dgvRegisters.Rows.Add(
  127. "自定义",
  128. entry.Address.ToString(),
  129. entry.DataType,
  130. value,
  131. "(自定义监视)"
  132. );
  133. dgvRegisters.Rows[rowIndex].DefaultCellStyle.BackColor = Color.FromArgb(230, 240, 255);
  134. }
  135. int totalCount = mappings.Count + _customEntries.Count;
  136. lblStatus.Text = $"状态: 配置 {mappings.Count} + 自定义 {_customEntries.Count} = 共 {totalCount} 个 | 最后刷新: {DateTime.Now:HH:mm:ss}";
  137. lblStatus.ForeColor = Color.Green;
  138. }
  139. catch (Exception ex)
  140. {
  141. lblStatus.Text = $"状态: 读取失败 - {ex.Message}";
  142. lblStatus.ForeColor = Color.Red;
  143. }
  144. }
  145. private string ReadRegisterValue(int address, string dataType)
  146. {
  147. try
  148. {
  149. if (dataType == "Float")
  150. {
  151. var value = _modbusService.ReadHoldingFloat((ushort)address);
  152. return value.HasValue ? value.Value.ToString("F4") : "N/A";
  153. }
  154. else
  155. {
  156. var value = _modbusService.ReadHoldingRegister((ushort)address);
  157. if (!value.HasValue) return "N/A";
  158. if (dataType == "Int16")
  159. return ((short)value.Value).ToString();
  160. else
  161. return value.Value.ToString();
  162. }
  163. }
  164. catch
  165. {
  166. return "读取失败";
  167. }
  168. }
  169. private void RefreshTimer_Tick(object sender, EventArgs e)
  170. {
  171. RefreshValues();
  172. }
  173. private void RefreshValues()
  174. {
  175. if (_modbusService == null || !_modbusService.IsRunning)
  176. {
  177. lblStatus.Text = "状态: Modbus 服务未运行";
  178. lblStatus.ForeColor = Color.Red;
  179. return;
  180. }
  181. try
  182. {
  183. var registerData = _modbusService.ReadAllConfiguredRegisters();
  184. foreach (DataGridViewRow row in dgvRegisters.Rows)
  185. {
  186. if (row.Cells["Address"].Value == null) continue;
  187. if (int.TryParse(row.Cells["Address"].Value.ToString(), out int address))
  188. {
  189. string oldValue = row.Cells["Value"].Value?.ToString() ?? "";
  190. string newValue = "";
  191. string source = row.Cells["Source"].Value?.ToString() ?? "";
  192. string dataType = row.Cells["DataType"].Value?.ToString() ?? "UInt16";
  193. if (source == "配置")
  194. {
  195. if (registerData.TryGetValue(address, out var data))
  196. {
  197. newValue = data.RawValue;
  198. }
  199. }
  200. else
  201. {
  202. newValue = ReadRegisterValue(address, dataType);
  203. }
  204. row.Cells["Value"].Value = newValue;
  205. if (oldValue != newValue && !string.IsNullOrEmpty(oldValue))
  206. {
  207. row.Cells["Value"].Style.BackColor = Color.Yellow;
  208. }
  209. else
  210. {
  211. row.Cells["Value"].Style.BackColor = Color.Empty;
  212. }
  213. }
  214. }
  215. int configCount = _modbusService.GetMappings().Count;
  216. lblStatus.Text = $"状态: 配置 {configCount} + 自定义 {_customEntries.Count} | 最后刷新: {DateTime.Now:HH:mm:ss}";
  217. lblStatus.ForeColor = Color.Green;
  218. }
  219. catch (Exception ex)
  220. {
  221. lblStatus.Text = $"状态: 刷新失败 - {ex.Message}";
  222. lblStatus.ForeColor = Color.Red;
  223. }
  224. }
  225. private void ChkAutoRefresh_CheckedChanged(object sender, EventArgs e)
  226. {
  227. if (_refreshTimer == null) return;
  228. if (chkAutoRefresh.Checked)
  229. {
  230. _refreshTimer.Start();
  231. }
  232. else
  233. {
  234. _refreshTimer.Stop();
  235. }
  236. }
  237. private void NumRefreshInterval_ValueChanged(object sender, EventArgs e)
  238. {
  239. if (_refreshTimer != null)
  240. {
  241. _refreshTimer.Interval = (int)numRefreshInterval.Value;
  242. }
  243. }
  244. private void BtnRefresh_Click(object sender, EventArgs e)
  245. {
  246. LoadRegisterData();
  247. }
  248. private void BtnClose_Click(object sender, EventArgs e)
  249. {
  250. this.Close();
  251. }
  252. private void BtnAddCustom_Click(object sender, EventArgs e)
  253. {
  254. int startAddr = (int)numStartAddr.Value;
  255. int count = (int)numCount.Value;
  256. string dataType = cmbDataType.SelectedItem?.ToString() ?? "UInt16";
  257. int added = 0;
  258. for (int i = 0; i < count; i++)
  259. {
  260. int addr = startAddr + i;
  261. if (dataType == "Float" && i > 0)
  262. {
  263. addr = startAddr + (i * 2);
  264. }
  265. bool exists = _customEntries.Exists(e => e.Address == addr);
  266. if (!exists)
  267. {
  268. _customEntries.Add(new CustomRegisterEntry
  269. {
  270. Address = addr,
  271. DataType = dataType
  272. });
  273. added++;
  274. }
  275. }
  276. if (added > 0)
  277. {
  278. LoadRegisterData();
  279. MessageBox.Show($"已添加 {added} 个自定义监视地址", "提示",
  280. MessageBoxButtons.OK, MessageBoxIcon.Information);
  281. }
  282. else
  283. {
  284. MessageBox.Show("所选地址已存在", "提示",
  285. MessageBoxButtons.OK, MessageBoxIcon.Information);
  286. }
  287. }
  288. private void BtnClearCustom_Click(object sender, EventArgs e)
  289. {
  290. if (_customEntries.Count == 0)
  291. {
  292. MessageBox.Show("没有自定义监视的地址", "提示",
  293. MessageBoxButtons.OK, MessageBoxIcon.Information);
  294. return;
  295. }
  296. var result = MessageBox.Show($"确定要清除所有 {_customEntries.Count} 个自定义监视地址吗?",
  297. "确认", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
  298. if (result == DialogResult.Yes)
  299. {
  300. _customEntries.Clear();
  301. LoadRegisterData();
  302. }
  303. }
  304. private void RegisterViewerForm_FormClosing(object sender, FormClosingEventArgs e)
  305. {
  306. _refreshTimer?.Stop();
  307. _refreshTimer?.Dispose();
  308. }
  309. }
  310. }