autopolling works now

This commit is contained in:
nikzori
2024-12-09 16:24:02 +03:00
parent c26d6084f3
commit 38fb1dfa84
5 changed files with 118 additions and 44 deletions

View File

@@ -5,6 +5,7 @@ using System.Data;
using System.Drawing; using System.Drawing;
using System.IO.Ports; using System.IO.Ports;
using System.Linq; using System.Linq;
using System.Net;
using System.Runtime.Remoting.Messaging; using System.Runtime.Remoting.Messaging;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
@@ -14,14 +15,22 @@ namespace Gidrolock_Modbus_Scanner
{ {
public partial class Datasheet : Form public partial class Datasheet : Form
{ {
bool isAwaitingResponse = false;
bool isProcessingResponse = false;
byte[] message = new byte[255];
int timeout = 3000; int timeout = 3000;
int pollDelay = 250; // delay between each entry poll, ms int pollDelay = 250; // delay between each entry poll, ms
byte slaveID; byte slaveID;
Device device = App.device; Device device = App.device;
List<Entry> entries; List<Entry> entries;
int activeEntryIndex; // entry index for modbus responses
SerialPort port = App.port; SerialPort port = App.port;
bool closed = false;
public Datasheet(byte slaveID) public Datasheet(byte slaveID)
{ {
App.port.DataReceived += new System.IO.Ports.SerialDataReceivedEventHandler(PublishResponse);
this.slaveID = slaveID; this.slaveID = slaveID;
entries = device.entries; entries = device.entries;
@@ -44,56 +53,122 @@ namespace Gidrolock_Modbus_Scanner
DGV_Device.Columns[4].Name = "Опрос"; DGV_Device.Columns[4].Name = "Опрос";
DGV_Device.Columns[4].FillWeight = 20; DGV_Device.Columns[4].FillWeight = 20;
for (int i = 0; i < entries.Count; i++) for (int i = 0; i < entries.Count; i++)
{ {
DGV_Device.Rows.Add(i.ToString(), entries[i].name, "", entries[i].address); DGV_Device.Rows.Add(i.ToString(), entries[i].name, "", entries[i].address);
DGV_Device.Rows[i].DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter;
} }
Task.Delay(1000).ContinueWith(_ => AutoPollAsync()); FormClosing += (s, e) => { closed = true; };
Task.Run(() => AutoPollAsync());
} }
public async Task<bool> AutoPollAsync() public async void AutoPollAsync()
{ {
if (!port.IsOpen)
port.Open(); port.Open();
while (true) port.ReadTimeout = timeout;
try
{
while (!closed)
{ {
for (int i = 0; i < entries.Count; i++) for (int i = 0; i < entries.Count; i++)
{ {
if ((bool)DGV_Device.Rows[i].Cells[4].Value) activeEntryIndex = i;
{ await PollForEntry(entries[i]);
DGV_Device.Rows[i].Cells[2].Value = await PollForEntry(entries[i]);
await Task.Delay(pollDelay);
} }
} }
} }
}
public async Task<string> PollForEntry(Entry entry)
{
byte[] result = new byte[] { 0xFF };
try
{
await Modbus.ReadRegAsync(port, slaveID, (FunctionCode)entry.registerType, entry.address, entry.length);
var task = Task.Delay(10).ContinueWith(_ =>
{
result = new byte[port.BytesToRead];
port.Read(result, 0, port.BytesToRead);
});
if (await Task.WhenAny(Task.Delay(timeout + 10), task) == task)
{
if (result.Length > 5)
{
return Modbus.ByteArrayToString(result);
}
else return "N/A";
}
else return "N/A";
}
catch (Exception err) catch (Exception err)
{ {
MessageBox.Show(err.Message); MessageBox.Show(err.Message);
return "N/A"; }
}
public async Task PollForEntry(Entry entry)
{
byte[] message = new byte[7];
Console.WriteLine("Sending message: " + Modbus.ByteArrayToString(Modbus.BuildMessage(slaveID, (byte)entry.registerType, entry.address, entry.length, ref message)));
var send = await Modbus.ReadRegAsync(port, slaveID, (FunctionCode)entry.registerType, entry.address, entry.length);
isAwaitingResponse = true;
Task delay = Task.Delay(timeout).ContinueWith((t) =>
{
if (isAwaitingResponse)
{
Console.WriteLine("Response timed out.");
isAwaitingResponse = false;
}
});
await delay;
}
void PublishResponse(object sender, EventArgs e)
{
Console.WriteLine("Received data on port.");
if (isAwaitingResponse)
{
isAwaitingResponse = false;
if (!isProcessingResponse)
{
isProcessingResponse = true;
try
{
message = new byte[255];
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 - 2; i++)
{
data[i] = message[i+3];
}
Console.WriteLine("Received message: " + Modbus.ByteArrayToString(message));
Console.WriteLine("Data trimmed: " + Modbus.ByteArrayToString(data));
string dataCleaned = Modbus.ByteArrayToString(message);
switch (entries[activeEntryIndex].dataType)
{
case ("bool"):
DGV_Device.Rows[activeEntryIndex].Cells[2].Value = data[0] > 0x00 ? "true" : "false";
break;
case ("uint16"):
Array.Reverse(data); // BitConverter.ToUInt is is little endian, I guess, so we need to flip the array
ushort test = BitConverter.ToUInt16(data, 0);
Console.WriteLine("ushort parsed value: " + test);
DGV_Device.Rows[activeEntryIndex].Cells[2].Value = test;
break;
case ("uint32"):
Array.Reverse(data);
DGV_Device.Rows[activeEntryIndex].Cells[2].Value = BitConverter.ToUInt32(data, 0);
break;
case ("utf8"):
DGV_Device.Rows[activeEntryIndex].Cells[2].Value = System.Text.Encoding.UTF8.GetString(data);
break;
default:
MessageBox.Show("Wrong data type set for entry " + entries[activeEntryIndex].name);
break;
}
//MessageBox.Show("Получен ответ от устройства: " + dataCleaned, "Успех", MessageBoxButtons.OK);
port.DiscardInBuffer();
isProcessingResponse = false;
}
catch (Exception err)
{
MessageBox.Show(err.Message, "Event Error");
isProcessingResponse = false;
} }
} }
} }
} }
}
}

View File

@@ -30,7 +30,7 @@ namespace Gidrolock_Modbus_Scanner
public string dataType; public string dataType;
public bool readOnce; public bool readOnce;
public Entry(string name, RegisterType registerType, ushort address, ushort length, string dataType, bool readOnce) public Entry(string name, RegisterType registerType, ushort address, ushort length = 1, string dataType = "uint16", bool readOnce = false)
{ {
this.name = name; this.name = name;
this.registerType = registerType; this.registerType = registerType;

17
Main.cs
View File

@@ -36,6 +36,7 @@ namespace Gidrolock_Modbus_Scanner
public short[] res = new short[12]; public short[] res = new short[12];
public static SerialPort port = new SerialPort(); public static SerialPort port = new SerialPort();
public int expectedLength = 0; public int expectedLength = 0;
Datasheet datasheet;
public static Device device; public static Device device;
#region Initialization #region Initialization
@@ -157,13 +158,9 @@ namespace Gidrolock_Modbus_Scanner
{ {
try try
{ {
AddLog("Message goes here;");
var send = await Modbus.ReadRegAsync(port, (byte)UpDown_ModbusID.Value, functionCode, address, length); var send = await Modbus.ReadRegAsync(port, (byte)UpDown_ModbusID.Value, functionCode, address, length);
isAwaitingResponse = true; isAwaitingResponse = true;
Task timer = Task.Delay(port.ReadTimeout); await Task.Delay(port.ReadTimeout).ContinueWith(_ =>
await timer.ContinueWith(_ =>
{ {
if (isAwaitingResponse) if (isAwaitingResponse)
{ {
@@ -233,7 +230,7 @@ namespace Gidrolock_Modbus_Scanner
AddLog("Попытка подключиться к устройству " + device.name); AddLog("Попытка подключиться к устройству " + device.name);
try try
{ {
Datasheet datasheet = new Datasheet((byte)UpDown_ModbusID.Value); datasheet = new Datasheet((byte)UpDown_ModbusID.Value);
datasheet.Show(); datasheet.Show();
} }
catch (Exception err) catch (Exception err)
@@ -283,6 +280,9 @@ namespace Gidrolock_Modbus_Scanner
void PortDataReceived(object sender, EventArgs e) void PortDataReceived(object sender, EventArgs e)
{ {
if (datasheet.Enabled)
return;
Console.WriteLine("Data receieved on Serial Port"); Console.WriteLine("Data receieved on Serial Port");
isAwaitingResponse = false; isAwaitingResponse = false;
@@ -302,12 +302,11 @@ namespace Gidrolock_Modbus_Scanner
{ {
data[i] = message[i + 3]; data[i] = message[i + 3];
} }
Console.WriteLine("Data: " + Modbus.ByteArrayToString(data));
string dataCleaned = Modbus.ByteArrayToString(message);
string dataCleaned = Modbus.ByteArrayToString(message);
TextBox_Log.Invoke((MethodInvoker)delegate { AddLog("Получен ответ: " + dataCleaned); }); TextBox_Log.Invoke((MethodInvoker)delegate { AddLog("Получен ответ: " + dataCleaned); });
TextBox_Log.Invoke((MethodInvoker)delegate { AddLog("ASCII: " + "wip"); }); TextBox_Log.Invoke((MethodInvoker)delegate { AddLog("ASCII: " + "wip"); });
//MessageBox.Show("Получен ответ от устройства: " + dataCleaned, "Успех", MessageBoxButtons.OK);
port.DiscardInBuffer(); port.DiscardInBuffer();
isProcessingResponse = false; isProcessingResponse = false;
} }

View File

@@ -29,7 +29,7 @@ namespace Gidrolock_Modbus_Scanner
message[message.Length - 2] = CRC[0]; message[message.Length - 2] = CRC[0];
message[message.Length - 1] = CRC[1]; message[message.Length - 1] = CRC[1];
string msg = ByteArrayToString(message); string msg = ByteArrayToString(message);
Console.WriteLine("Message: " + msg); //Console.WriteLine("Message: " + msg);
return message; return message;
} }
#endregion #endregion

View File

@@ -40,7 +40,7 @@
// <20><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> // <20><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>: bool, uint16, uint32, utf8 // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>: bool, uint16, uint32, utf8
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>: uint16 // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>: uint16
"dataType": "utf8", "dataType": "uint16",
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
// <20><><EFBFBD> `false` <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD> // <20><><EFBFBD> `false` <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD>