2024-12-05 15:57:07 +03:00
|
|
|
|
using System;
|
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
using System.ComponentModel;
|
|
|
|
|
|
using System.Data;
|
|
|
|
|
|
using System.Drawing;
|
2024-12-06 16:32:10 +03:00
|
|
|
|
using System.IO.Ports;
|
2024-12-05 15:57:07 +03:00
|
|
|
|
using System.Linq;
|
2024-12-09 16:24:02 +03:00
|
|
|
|
using System.Net;
|
2024-12-06 16:32:10 +03:00
|
|
|
|
using System.Runtime.Remoting.Messaging;
|
2024-12-05 15:57:07 +03:00
|
|
|
|
using System.Text;
|
|
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
|
using System.Windows.Forms;
|
|
|
|
|
|
|
|
|
|
|
|
namespace Gidrolock_Modbus_Scanner
|
|
|
|
|
|
{
|
|
|
|
|
|
public partial class Datasheet : Form
|
|
|
|
|
|
{
|
2024-12-16 11:35:20 +03:00
|
|
|
|
bool isPolling = false;
|
2024-12-09 16:24:02 +03:00
|
|
|
|
bool isAwaitingResponse = false;
|
|
|
|
|
|
byte[] message = new byte[255];
|
|
|
|
|
|
|
2024-12-06 16:32:10 +03:00
|
|
|
|
int timeout = 3000;
|
2024-12-05 15:57:07 +03:00
|
|
|
|
int pollDelay = 250; // delay between each entry poll, ms
|
2024-12-06 16:32:10 +03:00
|
|
|
|
byte slaveID;
|
2024-12-05 17:52:25 +03:00
|
|
|
|
Device device = App.device;
|
2024-12-06 16:32:10 +03:00
|
|
|
|
List<Entry> entries;
|
2024-12-09 16:24:02 +03:00
|
|
|
|
int activeEntryIndex; // entry index for modbus responses
|
2024-12-12 15:14:13 +03:00
|
|
|
|
SerialPort port = Modbus.port;
|
2024-12-09 16:24:02 +03:00
|
|
|
|
|
|
|
|
|
|
bool closed = false;
|
2024-12-06 16:32:10 +03:00
|
|
|
|
public Datasheet(byte slaveID)
|
2024-12-05 15:57:07 +03:00
|
|
|
|
{
|
2024-12-12 15:14:13 +03:00
|
|
|
|
Modbus.ResponseReceived += PublishResponse;
|
2024-12-06 16:32:10 +03:00
|
|
|
|
this.slaveID = slaveID;
|
|
|
|
|
|
entries = device.entries;
|
|
|
|
|
|
|
2024-12-05 17:52:25 +03:00
|
|
|
|
InitializeComponent();
|
2024-12-05 15:57:07 +03:00
|
|
|
|
|
2024-12-16 11:35:20 +03:00
|
|
|
|
Label_DeviceName.Text = device.name;
|
|
|
|
|
|
Label_Description.Text = device.description;
|
|
|
|
|
|
|
2024-12-06 16:32:10 +03:00
|
|
|
|
DGV_Device.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
|
|
|
|
|
|
DGV_Device.MultiSelect = false;
|
|
|
|
|
|
DGV_Device.AutoSizeRowsMode = DataGridViewAutoSizeRowsMode.DisplayedCellsExceptHeaders;
|
|
|
|
|
|
DGV_Device.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill;
|
2024-12-05 17:52:25 +03:00
|
|
|
|
|
2024-12-06 16:32:10 +03:00
|
|
|
|
DGV_Device.Columns.Add("#", "#");
|
|
|
|
|
|
DGV_Device.Columns[0].FillWeight = 20;
|
|
|
|
|
|
DGV_Device.Columns.Add("Name", "Имя");
|
|
|
|
|
|
DGV_Device.Columns[1].FillWeight = 40;
|
|
|
|
|
|
DGV_Device.Columns.Add("Value", "Значение");
|
|
|
|
|
|
DGV_Device.Columns[2].FillWeight = 60;
|
|
|
|
|
|
DGV_Device.Columns.Add("Address", "Адрес");
|
|
|
|
|
|
DGV_Device.Columns[3].FillWeight = 30;
|
|
|
|
|
|
DGV_Device.Columns.Add(new DataGridViewCheckBoxColumn());
|
|
|
|
|
|
DGV_Device.Columns[4].Name = "Опрос";
|
|
|
|
|
|
DGV_Device.Columns[4].FillWeight = 20;
|
2024-12-16 15:52:01 +03:00
|
|
|
|
DGV_Device.Columns[4].ValueType = typeof(bool);
|
|
|
|
|
|
|
2024-12-06 16:32:10 +03:00
|
|
|
|
for (int i = 0; i < entries.Count; i++)
|
2024-12-05 17:52:25 +03:00
|
|
|
|
{
|
2024-12-06 16:32:10 +03:00
|
|
|
|
DGV_Device.Rows.Add(i.ToString(), entries[i].name, "", entries[i].address);
|
2024-12-09 16:24:02 +03:00
|
|
|
|
DGV_Device.Rows[i].DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter;
|
2024-12-06 16:32:10 +03:00
|
|
|
|
}
|
2024-12-16 15:18:05 +03:00
|
|
|
|
|
|
|
|
|
|
foreach (DataGridViewColumn column in DGV_Device.Columns)
|
|
|
|
|
|
column.SortMode = DataGridViewColumnSortMode.NotSortable; // disabling sorting for now
|
|
|
|
|
|
|
2024-12-09 16:24:02 +03:00
|
|
|
|
FormClosing += (s, e) => { closed = true; };
|
|
|
|
|
|
Task.Run(() => AutoPollAsync());
|
2024-12-06 16:32:10 +03:00
|
|
|
|
}
|
2024-12-05 17:52:25 +03:00
|
|
|
|
|
2024-12-09 16:24:02 +03:00
|
|
|
|
public async void AutoPollAsync()
|
2024-12-06 16:32:10 +03:00
|
|
|
|
{
|
2024-12-09 16:24:02 +03:00
|
|
|
|
if (!port.IsOpen)
|
|
|
|
|
|
port.Open();
|
|
|
|
|
|
port.ReadTimeout = timeout;
|
|
|
|
|
|
try
|
2024-12-06 16:32:10 +03:00
|
|
|
|
{
|
2024-12-09 16:24:02 +03:00
|
|
|
|
while (!closed)
|
2024-12-06 16:32:10 +03:00
|
|
|
|
{
|
2024-12-16 11:35:20 +03:00
|
|
|
|
if (isPolling)
|
2024-12-06 16:32:10 +03:00
|
|
|
|
{
|
2024-12-16 11:35:20 +03:00
|
|
|
|
for (int i = 0; i < entries.Count; i++)
|
|
|
|
|
|
{
|
2024-12-16 15:52:01 +03:00
|
|
|
|
// holy fuck DGV is awful
|
|
|
|
|
|
DataGridViewCheckBoxCell chbox = DGV_Device.Rows[i].Cells[4] as DataGridViewCheckBoxCell;
|
|
|
|
|
|
if (Convert.ToBoolean(chbox.Value))
|
|
|
|
|
|
{
|
|
|
|
|
|
Console.WriteLine("Polling for " + device.entries[i].name);
|
|
|
|
|
|
activeEntryIndex = i;
|
|
|
|
|
|
await PollForEntry(entries[i]);
|
|
|
|
|
|
}
|
2024-12-16 11:35:20 +03:00
|
|
|
|
}
|
2024-12-06 16:32:10 +03:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2024-12-09 16:24:02 +03:00
|
|
|
|
catch (Exception err)
|
|
|
|
|
|
{
|
|
|
|
|
|
MessageBox.Show(err.Message);
|
|
|
|
|
|
}
|
2024-12-06 16:32:10 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
2024-12-09 16:24:02 +03:00
|
|
|
|
public async Task PollForEntry(Entry entry)
|
2024-12-06 16:32:10 +03:00
|
|
|
|
{
|
2024-12-09 17:58:37 +03:00
|
|
|
|
byte[] message = new byte[9];
|
2024-12-09 16:24:02 +03:00
|
|
|
|
var send = await Modbus.ReadRegAsync(port, slaveID, (FunctionCode)entry.registerType, entry.address, entry.length);
|
|
|
|
|
|
isAwaitingResponse = true;
|
2024-12-12 15:14:13 +03:00
|
|
|
|
|
2024-12-09 16:24:02 +03:00
|
|
|
|
Task delay = Task.Delay(timeout).ContinueWith((t) =>
|
2024-12-06 16:32:10 +03:00
|
|
|
|
{
|
2024-12-09 16:24:02 +03:00
|
|
|
|
if (isAwaitingResponse)
|
2024-12-06 16:32:10 +03:00
|
|
|
|
{
|
2024-12-09 16:24:02 +03:00
|
|
|
|
Console.WriteLine("Response timed out.");
|
|
|
|
|
|
isAwaitingResponse = false;
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
await delay;
|
|
|
|
|
|
}
|
2024-12-06 16:32:10 +03:00
|
|
|
|
|
2024-12-12 15:14:13 +03:00
|
|
|
|
void PublishResponse(object sender, ModbusResponseEventArgs e)
|
2024-12-09 16:24:02 +03:00
|
|
|
|
{
|
|
|
|
|
|
if (isAwaitingResponse)
|
|
|
|
|
|
{
|
|
|
|
|
|
isAwaitingResponse = false;
|
2024-12-12 15:14:13 +03:00
|
|
|
|
try
|
2024-12-16 11:35:20 +03:00
|
|
|
|
{
|
2024-12-12 15:14:13 +03:00
|
|
|
|
switch (entries[activeEntryIndex].dataType)
|
2024-12-09 16:24:02 +03:00
|
|
|
|
{
|
2024-12-12 15:14:13 +03:00
|
|
|
|
case ("bool"):
|
2024-12-16 11:35:20 +03:00
|
|
|
|
DGV_Device.Rows[activeEntryIndex].Cells[2].Value = e.Data[0] > 0x00 ? "true" : "false";
|
2024-12-12 15:14:13 +03:00
|
|
|
|
break;
|
|
|
|
|
|
case ("uint16"):
|
2024-12-16 15:18:05 +03:00
|
|
|
|
Array.Reverse(e.Data); // BitConverter.ToUInt is is little endian, so we need to flip the array
|
2024-12-16 11:35:20 +03:00
|
|
|
|
ushort test = BitConverter.ToUInt16(e.Data, 0);
|
2024-12-12 15:14:13 +03:00
|
|
|
|
Console.WriteLine("ushort parsed value: " + test);
|
|
|
|
|
|
DGV_Device.Rows[activeEntryIndex].Cells[2].Value = test;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case ("uint32"):
|
2024-12-16 11:35:20 +03:00
|
|
|
|
Array.Reverse(e.Data);
|
|
|
|
|
|
DGV_Device.Rows[activeEntryIndex].Cells[2].Value = BitConverter.ToUInt32(e.Data, 0);
|
2024-12-12 15:14:13 +03:00
|
|
|
|
break;
|
2024-12-16 14:43:50 +03:00
|
|
|
|
case ("string"):
|
2024-12-16 14:31:14 +03:00
|
|
|
|
List<byte> bytes = new List<byte>();
|
|
|
|
|
|
for (int i = 0; i < e.Data.Length; i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (e.Data[i] != 0)
|
|
|
|
|
|
bytes.Add(e.Data[i]);
|
|
|
|
|
|
}
|
|
|
|
|
|
DGV_Device.Rows[activeEntryIndex].Cells[2].Value = System.Text.Encoding.UTF8.GetString(bytes.ToArray());
|
2024-12-12 15:14:13 +03:00
|
|
|
|
break;
|
|
|
|
|
|
default:
|
|
|
|
|
|
MessageBox.Show("Wrong data type set for entry " + entries[activeEntryIndex].name);
|
|
|
|
|
|
break;
|
2024-12-06 16:32:10 +03:00
|
|
|
|
}
|
2024-12-12 15:14:13 +03:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//MessageBox.Show("Получен ответ от устройства: " + dataCleaned, "Успех", MessageBoxButtons.OK);
|
|
|
|
|
|
port.DiscardInBuffer();
|
2024-12-06 16:32:10 +03:00
|
|
|
|
}
|
2024-12-16 14:31:14 +03:00
|
|
|
|
catch { return; }
|
2024-12-12 15:14:13 +03:00
|
|
|
|
|
2024-12-05 17:52:25 +03:00
|
|
|
|
}
|
2024-12-05 15:57:07 +03:00
|
|
|
|
}
|
2024-12-16 11:35:20 +03:00
|
|
|
|
|
|
|
|
|
|
private void Button_StartStop_Click(object sender, EventArgs e)
|
|
|
|
|
|
{
|
|
|
|
|
|
isPolling = !isPolling;
|
|
|
|
|
|
Button_StartStop.Text = (isPolling ? "Стоп" : "Старт");
|
|
|
|
|
|
}
|
2024-12-05 15:57:07 +03:00
|
|
|
|
}
|
2024-12-09 16:24:02 +03:00
|
|
|
|
|
2024-12-06 16:32:10 +03:00
|
|
|
|
}
|