refactored RTU response event to offload message processing to a single function

This commit is contained in:
nikzori
2024-12-12 15:14:13 +03:00
parent 4ee185b333
commit 330d943b5d
5 changed files with 372 additions and 224 deletions

View File

@@ -25,12 +25,12 @@ namespace Gidrolock_Modbus_Scanner
Device device = App.device; Device device = App.device;
List<Entry> entries; List<Entry> entries;
int activeEntryIndex; // entry index for modbus responses int activeEntryIndex; // entry index for modbus responses
SerialPort port = App.port; SerialPort port = Modbus.port;
bool closed = false; bool closed = false;
public Datasheet(byte slaveID) public Datasheet(byte slaveID)
{ {
App.port.DataReceived += new System.IO.Ports.SerialDataReceivedEventHandler(PublishResponse); Modbus.ResponseReceived += PublishResponse;
this.slaveID = slaveID; this.slaveID = slaveID;
entries = device.entries; entries = device.entries;
@@ -105,33 +105,22 @@ namespace Gidrolock_Modbus_Scanner
await delay; await delay;
} }
void PublishResponse(object sender, EventArgs e) void PublishResponse(object sender, ModbusResponseEventArgs e)
{ {
Console.WriteLine("Received data on port.");
if (isAwaitingResponse) if (isAwaitingResponse)
{ {
isAwaitingResponse = false; isAwaitingResponse = false;
if (!isProcessingResponse)
{
isProcessingResponse = true;
try try
{ {
message = new byte[255];
port.Read(message, 0, 3); byte length = e.message[2];
int length = (int)message[2]; Console.WriteLine("Data length is:" + length);
for (int i = 0; i < length + 2; i++)
{
port.Read(message, i + 3, 1);
}
byte[] data = new byte[length]; byte[] data = new byte[length];
for (int i = 0; i < length; i++) for (int i = 0; i < length; i++)
{ data[i] = e.message[i + 3];
data[i] = message[i+3];
} Console.WriteLine("Data after processing in Datasheet.cs: " + Modbus.ByteArrayToString(data));
Console.WriteLine("Received message: " + Modbus.ByteArrayToString(message));
Console.WriteLine("Data trimmed: " + Modbus.ByteArrayToString(data));
string dataCleaned = Modbus.ByteArrayToString(message);
switch (entries[activeEntryIndex].dataType) switch (entries[activeEntryIndex].dataType)
{ {
@@ -159,14 +148,12 @@ namespace Gidrolock_Modbus_Scanner
//MessageBox.Show("Получен ответ от устройства: " + dataCleaned, "Успех", MessageBoxButtons.OK); //MessageBox.Show("Получен ответ от устройства: " + dataCleaned, "Успех", MessageBoxButtons.OK);
port.DiscardInBuffer(); port.DiscardInBuffer();
isProcessingResponse = false;
} }
catch (Exception err) catch (Exception err)
{ {
MessageBox.Show(err.Message, "Event Error"); //MessageBox.Show(err.Message, "Event Error");
isProcessingResponse = false;
}
} }
} }
} }
} }

21
Json.cs
View File

@@ -13,11 +13,12 @@ namespace Gidrolock_Modbus_Scanner
public string name; public string name;
public string description; public string description;
public List<Entry> entries; public List<Entry> entries;
public CheckEntry checkEntry;
public Device(string name, string description, List<Entry> entries) public Device(string name, string description, CheckEntry checkEntry, List<Entry> entries)
{ {
this.name = name; this.name = name;
this.description = description; this.description = description;
this.checkEntry = checkEntry;
this.entries = entries; this.entries = entries;
} }
} }
@@ -40,5 +41,21 @@ namespace Gidrolock_Modbus_Scanner
this.readOnce = readOnce; this.readOnce = readOnce;
} }
} }
public struct CheckEntry
{
public RegisterType registerType;
public ushort address;
public ushort length;
public string dataType;
public string expectedValue;
public CheckEntry(RegisterType registerType, ushort address, ushort length, string dataType, string expectedValue)
{
this.registerType = registerType;
this.address = address;
this.length = length;
this.dataType = dataType;
this.expectedValue = expectedValue;
}
}
public enum RegisterType { Coil = 1, Discrete = 2, Holding = 3, Input = 4} public enum RegisterType { Coil = 1, Discrete = 2, Holding = 3, Input = 4}
} }

94
Main.Designer.cs generated
View File

@@ -80,9 +80,11 @@
this.groupBox4 = new System.Windows.Forms.GroupBox(); this.groupBox4 = new System.Windows.Forms.GroupBox();
this.Radio_Ethernet = new System.Windows.Forms.RadioButton(); this.Radio_Ethernet = new System.Windows.Forms.RadioButton();
this.Radio_SerialPort = new System.Windows.Forms.RadioButton(); this.Radio_SerialPort = new System.Windows.Forms.RadioButton();
this.Label_ConfigTip = new System.Windows.Forms.Label();
this.Button_LoadConfig = new System.Windows.Forms.Button(); this.Button_LoadConfig = new System.Windows.Forms.Button();
this.label12 = new System.Windows.Forms.Label(); this.groupBox1 = new System.Windows.Forms.GroupBox();
this.Label_Config = new System.Windows.Forms.Label(); this.Label_ConfPath = new System.Windows.Forms.Label();
this.button1 = new System.Windows.Forms.Button();
this.GBox_Serial.SuspendLayout(); this.GBox_Serial.SuspendLayout();
this.panel11.SuspendLayout(); this.panel11.SuspendLayout();
this.panel10.SuspendLayout(); this.panel10.SuspendLayout();
@@ -105,6 +107,7 @@
this.panel17.SuspendLayout(); this.panel17.SuspendLayout();
this.panel18.SuspendLayout(); this.panel18.SuspendLayout();
this.groupBox4.SuspendLayout(); this.groupBox4.SuspendLayout();
this.groupBox1.SuspendLayout();
this.SuspendLayout(); this.SuspendLayout();
// //
// GBox_Serial // GBox_Serial
@@ -115,7 +118,7 @@
this.GBox_Serial.Controls.Add(this.panel7); this.GBox_Serial.Controls.Add(this.panel7);
this.GBox_Serial.Controls.Add(this.panel2); this.GBox_Serial.Controls.Add(this.panel2);
this.GBox_Serial.Controls.Add(this.panel1); this.GBox_Serial.Controls.Add(this.panel1);
this.GBox_Serial.Location = new System.Drawing.Point(12, 12); this.GBox_Serial.Location = new System.Drawing.Point(12, 92);
this.GBox_Serial.Name = "GBox_Serial"; this.GBox_Serial.Name = "GBox_Serial";
this.GBox_Serial.Size = new System.Drawing.Size(490, 65); this.GBox_Serial.Size = new System.Drawing.Size(490, 65);
this.GBox_Serial.TabIndex = 0; this.GBox_Serial.TabIndex = 0;
@@ -315,7 +318,7 @@
// //
this.Button_Connect.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) this.Button_Connect.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right))); | System.Windows.Forms.AnchorStyles.Right)));
this.Button_Connect.Location = new System.Drawing.Point(402, 155); this.Button_Connect.Location = new System.Drawing.Point(402, 235);
this.Button_Connect.Name = "Button_Connect"; this.Button_Connect.Name = "Button_Connect";
this.Button_Connect.Size = new System.Drawing.Size(100, 25); this.Button_Connect.Size = new System.Drawing.Size(100, 25);
this.Button_Connect.TabIndex = 4; this.Button_Connect.TabIndex = 4;
@@ -325,7 +328,7 @@
// //
// TextBox_Log // TextBox_Log
// //
this.TextBox_Log.Location = new System.Drawing.Point(12, 192); this.TextBox_Log.Location = new System.Drawing.Point(12, 269);
this.TextBox_Log.Multiline = true; this.TextBox_Log.Multiline = true;
this.TextBox_Log.Name = "TextBox_Log"; this.TextBox_Log.Name = "TextBox_Log";
this.TextBox_Log.ReadOnly = true; this.TextBox_Log.ReadOnly = true;
@@ -340,7 +343,7 @@
this.groupBox2.Controls.Add(this.Button_SendCommand); this.groupBox2.Controls.Add(this.Button_SendCommand);
this.groupBox2.Controls.Add(this.panel3); this.groupBox2.Controls.Add(this.panel3);
this.groupBox2.Controls.Add(this.panel4); this.groupBox2.Controls.Add(this.panel4);
this.groupBox2.Location = new System.Drawing.Point(12, 316); this.groupBox2.Location = new System.Drawing.Point(12, 393);
this.groupBox2.Name = "groupBox2"; this.groupBox2.Name = "groupBox2";
this.groupBox2.Size = new System.Drawing.Size(490, 63); this.groupBox2.Size = new System.Drawing.Size(490, 63);
this.groupBox2.TabIndex = 5; this.groupBox2.TabIndex = 5;
@@ -465,7 +468,7 @@
this.GBox_Ethernet.Controls.Add(this.panel16); this.GBox_Ethernet.Controls.Add(this.panel16);
this.GBox_Ethernet.Controls.Add(this.panel17); this.GBox_Ethernet.Controls.Add(this.panel17);
this.GBox_Ethernet.Controls.Add(this.panel18); this.GBox_Ethernet.Controls.Add(this.panel18);
this.GBox_Ethernet.Location = new System.Drawing.Point(12, 82); this.GBox_Ethernet.Location = new System.Drawing.Point(12, 162);
this.GBox_Ethernet.Name = "GBox_Ethernet"; this.GBox_Ethernet.Name = "GBox_Ethernet";
this.GBox_Ethernet.Size = new System.Drawing.Size(334, 65); this.GBox_Ethernet.Size = new System.Drawing.Size(334, 65);
this.GBox_Ethernet.TabIndex = 6; this.GBox_Ethernet.TabIndex = 6;
@@ -551,7 +554,7 @@
// //
this.groupBox4.Controls.Add(this.Radio_Ethernet); this.groupBox4.Controls.Add(this.Radio_Ethernet);
this.groupBox4.Controls.Add(this.Radio_SerialPort); this.groupBox4.Controls.Add(this.Radio_SerialPort);
this.groupBox4.Location = new System.Drawing.Point(348, 82); this.groupBox4.Location = new System.Drawing.Point(348, 162);
this.groupBox4.Name = "groupBox4"; this.groupBox4.Name = "groupBox4";
this.groupBox4.Size = new System.Drawing.Size(154, 65); this.groupBox4.Size = new System.Drawing.Size(154, 65);
this.groupBox4.TabIndex = 7; this.groupBox4.TabIndex = 7;
@@ -582,44 +585,67 @@
this.Radio_SerialPort.UseVisualStyleBackColor = true; this.Radio_SerialPort.UseVisualStyleBackColor = true;
this.Radio_SerialPort.CheckedChanged += new System.EventHandler(this.Radio_SerialPort_CheckedChanged); this.Radio_SerialPort.CheckedChanged += new System.EventHandler(this.Radio_SerialPort_CheckedChanged);
// //
// Label_ConfigTip
//
this.Label_ConfigTip.AutoSize = true;
this.Label_ConfigTip.Location = new System.Drawing.Point(8, 16);
this.Label_ConfigTip.Name = "Label_ConfigTip";
this.Label_ConfigTip.Size = new System.Drawing.Size(94, 13);
this.Label_ConfigTip.TabIndex = 10;
this.Label_ConfigTip.Text = "Выбранный путь:";
//
// Button_LoadConfig // Button_LoadConfig
// //
this.Button_LoadConfig.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) this.Button_LoadConfig.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right))); | System.Windows.Forms.AnchorStyles.Right)));
this.Button_LoadConfig.Location = new System.Drawing.Point(292, 155); this.Button_LoadConfig.Location = new System.Drawing.Point(415, 43);
this.Button_LoadConfig.Name = "Button_LoadConfig"; this.Button_LoadConfig.Name = "Button_LoadConfig";
this.Button_LoadConfig.Size = new System.Drawing.Size(100, 25); this.Button_LoadConfig.Size = new System.Drawing.Size(69, 25);
this.Button_LoadConfig.TabIndex = 8; this.Button_LoadConfig.TabIndex = 11;
this.Button_LoadConfig.Text = "Выбрать"; this.Button_LoadConfig.Text = "Файл";
this.Button_LoadConfig.UseVisualStyleBackColor = true; this.Button_LoadConfig.UseVisualStyleBackColor = true;
this.Button_LoadConfig.Click += new System.EventHandler(this.LoadConfig); this.Button_LoadConfig.Click += new System.EventHandler(this.LoadConfig);
// //
// label12 // groupBox1
// //
this.label12.AutoSize = true; this.groupBox1.Controls.Add(this.Label_ConfPath);
this.label12.Location = new System.Drawing.Point(9, 161); this.groupBox1.Controls.Add(this.button1);
this.label12.Name = "label12"; this.groupBox1.Controls.Add(this.Button_LoadConfig);
this.label12.Size = new System.Drawing.Size(83, 13); this.groupBox1.Controls.Add(this.Label_ConfigTip);
this.label12.TabIndex = 9; this.groupBox1.Location = new System.Drawing.Point(12, 12);
this.label12.Text = "Конфигурация:"; this.groupBox1.Name = "groupBox1";
this.groupBox1.Size = new System.Drawing.Size(490, 74);
this.groupBox1.TabIndex = 13;
this.groupBox1.TabStop = false;
this.groupBox1.Text = "Конфигурация";
// //
// Label_Config // Label_ConfPath
// //
this.Label_Config.AutoSize = true; this.Label_ConfPath.Location = new System.Drawing.Point(9, 29);
this.Label_Config.Location = new System.Drawing.Point(90, 161); this.Label_ConfPath.Name = "Label_ConfPath";
this.Label_Config.Name = "Label_Config"; this.Label_ConfPath.Size = new System.Drawing.Size(400, 39);
this.Label_Config.Size = new System.Drawing.Size(66, 13); this.Label_ConfPath.TabIndex = 14;
this.Label_Config.TabIndex = 1; this.Label_ConfPath.Text = "Файл не выбран.";
this.Label_Config.Text = "не выбрана"; this.Label_ConfPath.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
//
// button1
//
this.button1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.button1.Location = new System.Drawing.Point(415, 12);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(69, 25);
this.button1.TabIndex = 13;
this.button1.Text = "Папка";
this.button1.UseVisualStyleBackColor = true;
this.button1.Click += new System.EventHandler(this.LoadFolder);
// //
// App // App
// //
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(514, 391); this.ClientSize = new System.Drawing.Size(514, 467);
this.Controls.Add(this.Label_Config); this.Controls.Add(this.groupBox1);
this.Controls.Add(this.label12);
this.Controls.Add(this.Button_LoadConfig);
this.Controls.Add(this.groupBox4); this.Controls.Add(this.groupBox4);
this.Controls.Add(this.GBox_Ethernet); this.Controls.Add(this.GBox_Ethernet);
this.Controls.Add(this.groupBox2); this.Controls.Add(this.groupBox2);
@@ -669,6 +695,8 @@
this.panel18.PerformLayout(); this.panel18.PerformLayout();
this.groupBox4.ResumeLayout(false); this.groupBox4.ResumeLayout(false);
this.groupBox4.PerformLayout(); this.groupBox4.PerformLayout();
this.groupBox1.ResumeLayout(false);
this.groupBox1.PerformLayout();
this.ResumeLayout(false); this.ResumeLayout(false);
this.PerformLayout(); this.PerformLayout();
@@ -727,9 +755,11 @@
private System.Windows.Forms.GroupBox groupBox4; private System.Windows.Forms.GroupBox groupBox4;
private System.Windows.Forms.RadioButton Radio_Ethernet; private System.Windows.Forms.RadioButton Radio_Ethernet;
private System.Windows.Forms.RadioButton Radio_SerialPort; private System.Windows.Forms.RadioButton Radio_SerialPort;
private System.Windows.Forms.Label Label_ConfigTip;
private System.Windows.Forms.Button Button_LoadConfig; private System.Windows.Forms.Button Button_LoadConfig;
private System.Windows.Forms.Label label12; private System.Windows.Forms.GroupBox groupBox1;
private System.Windows.Forms.Label Label_Config; private System.Windows.Forms.Button button1;
private System.Windows.Forms.Label Label_ConfPath;
} }
} }

226
Main.cs
View File

@@ -8,17 +8,12 @@ using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Windows.Forms; using System.Windows.Forms;
using System.IO.Ports; using System.IO.Ports;
using System.Drawing.Drawing2D;
using System.Threading;
using System.Runtime;
using System.Web;
using System.Windows.Forms.Automation;
using System.Diagnostics;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Net.Sockets; using System.Net.Sockets;
using System.IO; using System.IO;
using Newtonsoft.Json; using Newtonsoft.Json;
namespace Gidrolock_Modbus_Scanner namespace Gidrolock_Modbus_Scanner
{ {
public partial class App : Form public partial class App : Form
@@ -32,18 +27,33 @@ namespace Gidrolock_Modbus_Scanner
byte[] message = new byte[255]; byte[] message = new byte[255];
public bool isAwaitingResponse = false; public bool isAwaitingResponse = false;
public bool isProcessingResponse = false;
public short[] res = new short[12]; public short[] res = new short[12];
public static SerialPort port = new SerialPort(); SerialPort port = Modbus.port;
public int expectedLength = 0; public int expectedLength = 0;
Datasheet datasheet; Datasheet datasheet;
public SelectedPath selectedPath = SelectedPath.Folder;
public static Device device; public static Device device; // Deserialized .json object
string path = String.Empty; // Path to selected file/folder
string defaultPath = Application.StartupPath + "\\Configs"; // Default folder path
OpenFileDialog ofd = new OpenFileDialog();
FolderBrowserDialog fbd = new FolderBrowserDialog();
Dictionary<CheckEntry, List<Device>> juju = new Dictionary<CheckEntry, List<Device>>(); // dictionary for device identification
string[] configs;
public byte[] latestMessage;
#region Initialization #region Initialization
public App() public App()
{ {
InitializeComponent(); InitializeComponent();
port.DataReceived += new System.IO.Ports.SerialDataReceivedEventHandler(PortDataReceived); Modbus.Init();
Modbus.ResponseReceived += OnResponseReceived;
ofd.InitialDirectory = Application.StartupPath;
ofd.Filter = "JSON files (*.json)|*.json";
ofd.FilterIndex = 2;
ofd.RestoreDirectory = true;
this.UpDown_ModbusID.Value = 30; this.UpDown_ModbusID.Value = 30;
TextBox_Log.Text = "Приложение готово к работе."; TextBox_Log.Text = "Приложение готово к работе.";
@@ -102,6 +112,22 @@ namespace Gidrolock_Modbus_Scanner
TBox_IP.Text = "192.168.3.7"; TBox_IP.Text = "192.168.3.7";
TBox_Port.Text = "8887"; TBox_Port.Text = "8887";
TBox_Timeout.Text = "3"; TBox_Timeout.Text = "3";
if (Directory.GetDirectories(Application.StartupPath).Contains(Application.StartupPath + "\\Configs") == false)
{
Task.Delay(1500).ContinueWith(t =>
{
MessageBox.Show("Приложение не нашло стандартную папку для конфигураций. Была создана папка 'Configs' в папке с приложением.");
Directory.CreateDirectory(Application.StartupPath + "\\Configs");
Console.WriteLine("New initial directory for OpenFile: " + ofd.InitialDirectory);
});
}
ofd.InitialDirectory = Application.StartupPath + "\\Configs";
path = defaultPath;
UpdatePathLabel();
}
void UpdatePathLabel()
{
Label_ConfPath.Text = path;
} }
void App_FormClosed(object sender, FormClosedEventArgs e) void App_FormClosed(object sender, FormClosedEventArgs e)
{ {
@@ -205,10 +231,18 @@ namespace Gidrolock_Modbus_Scanner
private async void ButtonConnect_Click(object sender, EventArgs e) private async void ButtonConnect_Click(object sender, EventArgs e)
{ {
if (device is null) if (path == String.Empty)
MessageBox.Show("Выберите конфигурацию для подключения и опроса устройства.");
else
{ {
MessageBox.Show("Выберите конфигурацию для подключения и опроса устройства.");
return;
}
if (CBox_Ports.SelectedItem.ToString() == "COM1")
{
DialogResult res = MessageBox.Show("Выбран серийный порт COM1, который обычно является портом PS/2 или RS-232, не подключенным к Modbus устройству. Продолжить?", "Внимание", MessageBoxButtons.OKCancel);
if (res == DialogResult.Cancel)
return;
}
/* - Port Setup - */ /* - Port Setup - */
if (port.IsOpen) if (port.IsOpen)
port.Close(); port.Close();
@@ -227,6 +261,81 @@ namespace Gidrolock_Modbus_Scanner
message = new byte[255]; message = new byte[255];
port.Open(); port.Open();
/* - Checking - */
if (selectedPath == SelectedPath.File)
{
var fileContent = string.Empty;
var filePath = string.Empty;
//Read the contents of the file into a stream
var fileStream = ofd.OpenFile();
using (StreamReader reader = new StreamReader(fileStream))
{
fileContent = reader.ReadToEnd();
}
try
{
device = JsonConvert.DeserializeObject<Device>(fileContent);
Label_ConfigTip.Text = device.name;
}
catch (Exception err)
{
MessageBox.Show(err.Message);
}
}
else
{
string[] _configs = Directory.GetFiles(path, "*.json");
if (configs != _configs)
{
// something changed in the config folder, or we haven't gone through configs,
// remake the dictionary
configs = _configs;
juju = new Dictionary<CheckEntry, List<Device>>();
var fileContent = string.Empty;
FileStream fileStream;
Device _device;
foreach (string path in configs)
{
fileStream = File.OpenRead(path);
using (StreamReader reader = new StreamReader(fileStream))
fileContent = reader.ReadToEnd();
// get device object from .json
_device = JsonConvert.DeserializeObject<Device>(fileContent);
// compare device object to key of each dictionary;
// add to that dictionary if device's check entry registers match the key
foreach (CheckEntry ce in juju.Keys)
{
if (_device.checkEntry.address == ce.address && _device.checkEntry.length == ce.length && _device.checkEntry.dataType == ce.dataType)
{
juju[ce].Add(_device);
break;
}
}
}
}
// all configs are sorted out, we can poll for each checkEntry
foreach (CheckEntry ce in juju.Keys)
{
byte[] response;
// send read request to device,
// check for error codes or timeouts
// if we get normal response, go through
}
// with dictionaries arranged, go through every key, discarding those that return error
// if device returns a coherent reply, go through expected values associated with the key
}
AddLog("Попытка подключиться к устройству " + device.name); AddLog("Попытка подключиться к устройству " + device.name);
try try
{ {
@@ -242,7 +351,7 @@ namespace Gidrolock_Modbus_Scanner
await SendMessageAsync(FunctionCode.InputRegister, 200, 6); await SendMessageAsync(FunctionCode.InputRegister, 200, 6);
//else EthernetParse(); //else EthernetParse();
*/ */
}
} }
async void EthernetParse() async void EthernetParse()
@@ -267,7 +376,6 @@ namespace Gidrolock_Modbus_Scanner
// set up an event listener to receive the response // set up an event listener to receive the response
await SocketDataTransfer(data); await SocketDataTransfer(data);
} }
} }
@@ -278,50 +386,11 @@ namespace Gidrolock_Modbus_Scanner
CBox_Ports.Items.AddRange(SerialPort.GetPortNames()); CBox_Ports.Items.AddRange(SerialPort.GetPortNames());
} }
void PortDataReceived(object sender, EventArgs e) void OnResponseReceived(object sender, ModbusResponseEventArgs e)
{ {
if (datasheet is null)
return;
if (datasheet.Enabled)
return;
Console.WriteLine("Data receieved on Serial Port");
isAwaitingResponse = false; isAwaitingResponse = false;
TextBox_Log.Invoke((MethodInvoker)delegate { AddLog("Получен ответ: " + Modbus.ByteArrayToString(e.message)); });
if (!isProcessingResponse) TextBox_Log.Invoke((MethodInvoker)delegate { AddLog("UTF8: " + Encoding.UTF8.GetString(e.message)); });
{
isProcessingResponse = true;
try
{
port.Read(message, 0, 3);
int length = (int)message[2];
for (int i = 0; i < length + 2; i++)
{
port.Read(message, i + 3, 1);
}
byte[] data = new byte[length];
for (int i = 0; i < length; i++)
{
data[i] = message[i + 3];
}
string dataCleaned = Modbus.ByteArrayToString(message);
TextBox_Log.Invoke((MethodInvoker)delegate { AddLog("Получен ответ: " + dataCleaned); });
TextBox_Log.Invoke((MethodInvoker)delegate { AddLog("ASCII: " + "wip"); });
port.DiscardInBuffer();
isProcessingResponse = false;
}
catch (Exception err)
{
MessageBox.Show(err.Message);
isProcessingResponse = false;
}
}
else Console.WriteLine("Already processing incoming message!");
//port.Close();
} }
void AddLog(string message) void AddLog(string message)
@@ -391,42 +460,31 @@ namespace Gidrolock_Modbus_Scanner
private void LoadConfig(object sender, EventArgs e) private void LoadConfig(object sender, EventArgs e)
{ {
var fileContent = string.Empty; if (ofd.ShowDialog() == DialogResult.OK)
var filePath = string.Empty;
using (OpenFileDialog openFileDialog = new OpenFileDialog())
{
openFileDialog.InitialDirectory = Application.StartupPath;
openFileDialog.Filter = "JSON files (*.json)|*.json";
openFileDialog.FilterIndex = 2;
openFileDialog.RestoreDirectory = true;
if (openFileDialog.ShowDialog() == DialogResult.OK)
{ {
//Get the path of specified file //Get the path of specified file
filePath = openFileDialog.FileName; path = ofd.FileName;
Label_ConfPath.Text = ofd.FileName;
//Read the contents of the file into a stream selectedPath = SelectedPath.File;
var fileStream = openFileDialog.OpenFile(); }
UpdatePathLabel();
using (StreamReader reader = new StreamReader(fileStream))
{
fileContent = reader.ReadToEnd();
} }
try private void LoadFolder(object sender, EventArgs e)
{ {
device = JsonConvert.DeserializeObject<Device>(fileContent);
Label_Config.Text = device.name; fbd.RootFolder = Environment.SpecialFolder.MyComputer;
} if (fbd.ShowDialog() == DialogResult.OK)
catch (Exception err)
{ {
MessageBox.Show(err.Message); path = fbd.SelectedPath;
} Label_ConfPath.Text = fbd.SelectedPath;
} selectedPath = SelectedPath.Folder;
} }
UpdatePathLabel();
} }
} }
} }
public enum FunctionCode { ReadCoil = 1, ReadDiscrete = 2, ReadHolding = 3, ReadInput = 4, WriteCoil = 5, WriteRegister = 6, WriteMultCoils = 15, WriteMultRegisters = 16}; public enum FunctionCode { ReadCoil = 1, ReadDiscrete = 2, ReadHolding = 3, ReadInput = 4, WriteCoil = 5, WriteRegister = 6, WriteMultCoils = 15, WriteMultRegisters = 16 };
public enum SelectedPath { File, Folder };

View File

@@ -1,17 +1,23 @@
using System; using System;
using System.IO.Ports; using System.IO.Ports;
using System.Runtime;
using System.Collections.Generic;
using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Windows.Forms; using System.Windows.Forms;
using System.Threading;
namespace Gidrolock_Modbus_Scanner namespace Gidrolock_Modbus_Scanner
{ {
public static class Modbus public static class Modbus
{ {
public static SerialPort port = new SerialPort();
public static event EventHandler<ModbusResponseEventArgs> ResponseReceived = delegate { };
public static void Init()
{
port.DataReceived += new System.IO.Ports.SerialDataReceivedEventHandler(PortDataReceived);
}
#region Build Message #region Build Message
public static byte[] BuildMessage(byte modbusID, byte functionCode, ushort address, ushort length, ref byte[] message) public static byte[] BuildMessage(byte modbusID, byte functionCode, ushort address, ushort length, ref byte[] message)
{ {
@@ -116,20 +122,7 @@ namespace Gidrolock_Modbus_Scanner
public static string ByteArrayToString(byte[] bytes) public static string ByteArrayToString(byte[] bytes)
{ {
int length = bytes.Length - 1; byte[] res = CleanByteArray(bytes);
// snip off the empty bytes at the end
for (int i = length; i >= 0; i--)
{
if (bytes[i] != 0)
{
length = i + 1;
break;
}
}
byte[] res = new byte[length];
for (int i = 0; i < length; i++)
res[i] = bytes[i];
string dataString = BitConverter.ToString(res); string dataString = BitConverter.ToString(res);
string result = ""; string result = "";
@@ -142,6 +135,25 @@ namespace Gidrolock_Modbus_Scanner
return result; return result;
} }
public static byte[] CleanByteArray(byte[] bytes)
{
int length = bytes.Length - 1;
// snip off the empty bytes at the end
for (int i = length; i >= 0; i--)
{
if (bytes[i] != 0)
{
length = i + 1;
break;
}
}
byte[] res = new byte[length];
for (int i = 0; i < length; i++) { res[i] = bytes[i]; }
return res;
}
#region CRC Computation #region CRC Computation
static void GetCRC(byte[] message, ref byte[] CRC) static void GetCRC(byte[] message, ref byte[] CRC)
@@ -170,5 +182,49 @@ namespace Gidrolock_Modbus_Scanner
CRC[0] = CRCLow = (byte)(CRCFull & 0xFF); CRC[0] = CRCLow = (byte)(CRCFull & 0xFF);
} }
#endregion #endregion
static void PortDataReceived(object sender, EventArgs e)
{
Console.WriteLine("Data receieved on Serial Port");
try
{
byte[] message = new byte[port.BytesToRead];
port.Read(message, 0, 3);
int length = (int)message[2];
for (int i = 0; i < length + 2; i++)
{
port.Read(message, i + 3, 1);
} }
Console.WriteLine("Raw data from port: " + BitConverter.ToString(message));
byte[] data = new byte[length];
for (int i = 0; i < length; i++)
{
data[i] = message[i + 3];
}
string dataCleaned = ByteArrayToString(message);
Console.WriteLine("Received response: " + dataCleaned);
Console.WriteLine("UTF8: " + Encoding.UTF8.GetString(data));
port.DiscardInBuffer();
ResponseReceived.Invoke(null, new ModbusResponseEventArgs(message));
}
catch (Exception err)
{
MessageBox.Show(err.Message);
}
}
}
public class ModbusResponseEventArgs : EventArgs
{
public byte[] message { get; set; }
public ModbusResponseEventArgs(byte[] message)
{
this.message = message;
}
}
} }