You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
297 lines
6.4 KiB
297 lines
6.4 KiB
using EasyModbus;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.ComponentModel;
|
|
using System.Data;
|
|
using System.Drawing;
|
|
using System.Linq;
|
|
using System.Net.NetworkInformation;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
using System.Windows.Forms;
|
|
using System.Timers;
|
|
using ModbusSlave.Dialog;
|
|
|
|
namespace ModbusSlave
|
|
{
|
|
public partial class MainForm : Form
|
|
{
|
|
private readonly int DATA_COUNT = 20;
|
|
private ModbusServer server = new ModbusServer();
|
|
private System.Timers.Timer updateTimer;
|
|
|
|
private bool isFirstLog = true;
|
|
|
|
public MainForm()
|
|
{
|
|
InitializeComponent();
|
|
InitInstance();
|
|
}
|
|
|
|
private void btnRun_Click(object sender, EventArgs e)
|
|
{
|
|
try
|
|
{
|
|
server = new ModbusServer();
|
|
server.Port = (int)nudPort.Value;
|
|
server.UnitIdentifier = Convert.ToByte(nudIdentifier.Value);
|
|
|
|
if (!CheckPortInUse(server.Port))
|
|
{
|
|
Log("[WARNING] unavailable port");
|
|
return;
|
|
}
|
|
|
|
server.Listen();
|
|
Log("--- Server start ---");
|
|
|
|
btnRun.Enabled = false;
|
|
nudIdentifier.Enabled = false;
|
|
nudPort.Enabled = false;
|
|
|
|
tbStatus.Text = "Run";
|
|
tbStatus.BackColor = Color.Lime;
|
|
|
|
updateTimer.Start();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Log("[ERROR] " + ex.Message);
|
|
}
|
|
}
|
|
|
|
private void btnStop_Click(object sender, EventArgs e)
|
|
{
|
|
try
|
|
{
|
|
server.StopListening();
|
|
Log("--- Server stop ---");
|
|
|
|
btnRun.Enabled = true;
|
|
nudIdentifier.Enabled = true;
|
|
nudPort.Enabled = true;
|
|
|
|
tbStatus.Text = "Stop";
|
|
tbStatus.BackColor = Color.Silver;
|
|
|
|
updateTimer.Stop();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Log("[ERROR] " + ex.Message);
|
|
}
|
|
}
|
|
|
|
private void btnClear_Click(object sender, EventArgs e)
|
|
{
|
|
ClearLog();
|
|
}
|
|
|
|
private void Lv_MouseDoubleClick(object sender, MouseEventArgs e)
|
|
{
|
|
if (btnRun.Enabled)
|
|
return;
|
|
|
|
ListView lv = sender as ListView;
|
|
if (lv.SelectedItems.Count < 1)
|
|
return;
|
|
|
|
int idx = lv.SelectedItems[0].Index;
|
|
short tmp = 0;
|
|
InputValueDialog dlg = new InputValueDialog();
|
|
dlg.Value = lv.SelectedItems[0].SubItems[1].Text;
|
|
dlg.StartPosition = FormStartPosition.CenterParent;
|
|
switch (lv.Name)
|
|
{
|
|
case "lv0x":
|
|
server.coils[idx + 1] = !server.coils[idx + 1];
|
|
break;
|
|
case "lv1x":
|
|
server.discreteInputs[idx + 1] = !server.discreteInputs[idx + 1];
|
|
break;
|
|
case "lv3x":
|
|
if (dlg.ShowDialog() != DialogResult.OK)
|
|
return;
|
|
|
|
if (!short.TryParse(dlg.Value, out tmp))
|
|
{
|
|
Log($"[ERROR] Value should be a number and in range of {short.MinValue} to {short.MaxValue}");
|
|
return;
|
|
}
|
|
server.inputRegisters[idx + 1] = tmp;
|
|
break;
|
|
case "lv4x":
|
|
if (dlg.ShowDialog() != DialogResult.OK)
|
|
return;
|
|
|
|
if (!short.TryParse(dlg.Value, out tmp))
|
|
{
|
|
Log($"[ERROR] Value should be a number and in range of {short.MinValue} to {short.MaxValue}");
|
|
return;
|
|
}
|
|
server.holdingRegisters[idx + 1] = tmp;
|
|
break;
|
|
}
|
|
}
|
|
|
|
private void InitInstance()
|
|
{
|
|
server = new ModbusServer();
|
|
updateTimer = new System.Timers.Timer();
|
|
updateTimer.Interval = 1000;
|
|
updateTimer.Elapsed += UpdateTimer_Elapsed;
|
|
|
|
lv0x.MouseDoubleClick += Lv_MouseDoubleClick;
|
|
lv1x.MouseDoubleClick += Lv_MouseDoubleClick;
|
|
lv3x.MouseDoubleClick += Lv_MouseDoubleClick;
|
|
lv4x.MouseDoubleClick += Lv_MouseDoubleClick;
|
|
|
|
InitListView();
|
|
}
|
|
|
|
private void UpdateTimer_Elapsed(object sender, ElapsedEventArgs e)
|
|
{
|
|
UpdateListView(0);
|
|
UpdateListView(1);
|
|
UpdateListView(3);
|
|
UpdateListView(4);
|
|
}
|
|
|
|
private void Log(string text)
|
|
{
|
|
rtbLog.AppendText((isFirstLog ? "" : Environment.NewLine) + text);
|
|
isFirstLog = false;
|
|
|
|
ScrollToEnd();
|
|
}
|
|
|
|
private void ScrollToEnd()
|
|
{
|
|
if (!chkAutoScroll.Checked)
|
|
return;
|
|
|
|
rtbLog.SelectionStart = rtbLog.Text.Length;
|
|
rtbLog.ScrollToCaret();
|
|
}
|
|
|
|
private void ClearLog()
|
|
{
|
|
rtbLog.Clear();
|
|
isFirstLog = true;
|
|
ScrollToEnd();
|
|
}
|
|
|
|
private bool CheckPortInUse(int port)
|
|
{
|
|
bool isAvailable = true;
|
|
var ipGlobalProperties = IPGlobalProperties.GetIPGlobalProperties();
|
|
var tcpListenerArray = ipGlobalProperties.GetActiveTcpListeners();
|
|
|
|
foreach (var ip in tcpListenerArray)
|
|
{
|
|
if (ip.Port == port)
|
|
{
|
|
isAvailable = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return isAvailable;
|
|
}
|
|
|
|
private void InitListView()
|
|
{
|
|
for (int i = 0; i < 5; i++)
|
|
{
|
|
if (i == 2)
|
|
continue;
|
|
|
|
string controlName = $"lv{i}x";
|
|
Control[] foundControls = this.Controls.Find(controlName, true);
|
|
if (foundControls.Length < 1 || !(foundControls[0] is ListView))
|
|
continue;
|
|
|
|
ListView listView = foundControls[0] as ListView;
|
|
listView.GetType()
|
|
.GetProperty("DoubleBuffered", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic)
|
|
.SetValue(listView, true, null);
|
|
listView.BeginUpdate();
|
|
listView.Items.Clear();
|
|
|
|
for (int j = 0; j < DATA_COUNT; j++)
|
|
{
|
|
ListViewItem item = new ListViewItem();
|
|
|
|
switch(i)
|
|
{
|
|
case 0: // 0x: 00001 ~ 00010
|
|
item.Text = string.Format("{0:D5}", j + 1);
|
|
break;
|
|
case 1: // 1x: 10001 ~ 10010
|
|
item.Text = (10000 + j + 1).ToString();
|
|
break;
|
|
case 3: // 3x: 30001 ~ 30010
|
|
item.Text = (30000 + j + 1).ToString();
|
|
break;
|
|
case 4: // 4x: 40001 ~ 40010
|
|
item.Text = (40000 + j + 1).ToString();
|
|
break;
|
|
}
|
|
|
|
item.SubItems.Add("0");
|
|
listView.Items.Add(item);
|
|
}
|
|
|
|
listView.Columns[0].Width = -2;
|
|
listView.Columns[1].Width = -2;
|
|
|
|
listView.EndUpdate();
|
|
}
|
|
}
|
|
|
|
private void UpdateListView(int regNum)
|
|
{
|
|
string controlName = $"lv{regNum}x";
|
|
Control[] foundControls = this.Controls.Find(controlName, true);
|
|
if (foundControls.Length < 1 || !(foundControls[0] is ListView))
|
|
return;
|
|
|
|
ListView listView = foundControls[0] as ListView;
|
|
if (listView.InvokeRequired)
|
|
{
|
|
listView.BeginInvoke(new MethodInvoker(delegate
|
|
{
|
|
UpdateListView(regNum);
|
|
}));
|
|
|
|
return;
|
|
}
|
|
|
|
listView.BeginUpdate();
|
|
|
|
for (int i = 0; i < DATA_COUNT; i++)
|
|
{
|
|
string value = "";
|
|
switch (regNum)
|
|
{
|
|
case 0:
|
|
value = server.coils[i + 1] ? "1" : "0";
|
|
break;
|
|
case 1:
|
|
value = server.discreteInputs[i + 1] ? "1" : "0";
|
|
break;
|
|
case 3:
|
|
value = server.inputRegisters[i + 1].ToString();
|
|
break;
|
|
case 4:
|
|
value = server.holdingRegisters[i + 1].ToString();
|
|
break;
|
|
}
|
|
|
|
listView.Items[i].SubItems[1].Text = value;
|
|
}
|
|
|
|
listView.EndUpdate();
|
|
}
|
|
}
|
|
}
|
|
|