Refactor code structure for improved readability and maintainability
This commit is contained in:
93
DaireApplication/ViewModels/Error.cs
Normal file
93
DaireApplication/ViewModels/Error.cs
Normal file
@@ -0,0 +1,93 @@
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Threading;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using static DaireApplication.Views.MainWindow;
|
||||
|
||||
namespace DaireApplication.ViewModels
|
||||
{
|
||||
public class Error
|
||||
{
|
||||
public enum GridCondition
|
||||
{
|
||||
GridFrequencyHigh,
|
||||
GridFrequencyLow,
|
||||
GridVACHigh,
|
||||
GridVACLow,
|
||||
NoExternalPower,
|
||||
MissingPhase,
|
||||
PhaseSequence,
|
||||
LoadDisconnection,
|
||||
MotorDisconnection,
|
||||
NoBoardCom,
|
||||
NoInternetAccess,
|
||||
ComPort1,
|
||||
ComPort2,
|
||||
HiCurrNeut,
|
||||
HiCurrMot1,
|
||||
HiCurrMot2,
|
||||
}
|
||||
public DateTime errorDate { get; set; }
|
||||
public GridCondition Condition { get; set; }
|
||||
public bool isShowen { get; set; } = false;
|
||||
public bool isDeleted { get; set; } = false;
|
||||
|
||||
public string GetDisplayNames(GridCondition condition)
|
||||
{
|
||||
return condition switch
|
||||
{
|
||||
GridCondition.GridFrequencyHigh => "Grid Frequency High",
|
||||
GridCondition.GridFrequencyLow => "Grid Frequency Low",
|
||||
GridCondition.GridVACHigh => "Grid VAC High",
|
||||
GridCondition.GridVACLow => "Grid VAC Low",
|
||||
GridCondition.NoExternalPower => "No External Power",
|
||||
GridCondition.MissingPhase => "Missing Phase",
|
||||
GridCondition.PhaseSequence => "Phase Sequence",
|
||||
GridCondition.LoadDisconnection => "Load Disconnection",
|
||||
GridCondition.MotorDisconnection => "Motor Disconnection",
|
||||
GridCondition.NoBoardCom => "Communication Timeout",
|
||||
GridCondition.NoInternetAccess => "No InternetAccess",
|
||||
GridCondition.ComPort1 => "Com Port1",
|
||||
GridCondition.ComPort2 => "Com Port2",
|
||||
GridCondition.HiCurrNeut=> "Hi Curr Neut",
|
||||
GridCondition.HiCurrMot1=> "Hi Curr Mot1",
|
||||
GridCondition.HiCurrMot2=> "Hi Curr Mot2",
|
||||
_ => string.Empty
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
public static bool IsInternetAvailable()
|
||||
{
|
||||
try
|
||||
{
|
||||
var networkInterfaces = NetworkInterface.GetAllNetworkInterfaces();
|
||||
|
||||
foreach (var networkInterface in networkInterfaces)
|
||||
{
|
||||
if (networkInterface.OperationalStatus == OperationalStatus.Up)
|
||||
{
|
||||
using (var ping = new Ping())
|
||||
{
|
||||
var reply = ping.Send("8.8.8.8", 3000); // Pinging Google DNS server with a timeout of 3000ms
|
||||
if (reply != null && reply.Status == IPStatus.Success)
|
||||
{
|
||||
return true; // Internet is available
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return false; // Return false if there is any exception (e.g., no network interface found, or errors during checking)
|
||||
}
|
||||
|
||||
return false; // Return false if no network interfaces are available or no successful ping
|
||||
}
|
||||
}
|
||||
}
|
||||
20
DaireApplication/ViewModels/HoldingRegister.cs
Normal file
20
DaireApplication/ViewModels/HoldingRegister.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DaireApplication.ViewModels
|
||||
{
|
||||
public class HoldingRegister
|
||||
{
|
||||
public ushort resetError { get; set; } = 0;
|
||||
public ushort hvOut { get; set; } = 0;
|
||||
public ushort lvOut { get; set; } = 0;
|
||||
public ushort motor { get; set; } = 0;
|
||||
public int setTemp1 { get; set; } = -10000;
|
||||
public int setTemp2 { get; set; } = -10000;
|
||||
public int setTemp3 { get; set; } = -10000;
|
||||
public int setTemp4 { get; set; } = -10000;
|
||||
}
|
||||
}
|
||||
7
DaireApplication/ViewModels/MainWindowViewModel.cs
Normal file
7
DaireApplication/ViewModels/MainWindowViewModel.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
namespace DaireApplication.ViewModels
|
||||
{
|
||||
public class MainWindowViewModel : ViewModelBase
|
||||
{
|
||||
public string Greeting { get; } = "Welcome to Avalonia!";
|
||||
}
|
||||
}
|
||||
306
DaireApplication/ViewModels/ModBusMaster.cs
Normal file
306
DaireApplication/ViewModels/ModBusMaster.cs
Normal file
@@ -0,0 +1,306 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO.Ports;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AvaloniaApplication1.ViewModels
|
||||
{
|
||||
public class ModBusMaster
|
||||
{
|
||||
public byte slaveId { get; set; } = 0x01; // Slave ID (your ESP slave ID)
|
||||
//byte functionCode = 0x05; // Function code for Write Single Coil
|
||||
//byte coilAddressHigh = 0x00; // Coil address (MSB)
|
||||
//byte coilAddressLow = 0x00; // Coil address (LSB)
|
||||
//byte coilValueHigh = 0x00; // Coil value (0xFF00 to turn on, 0x0000 to turn off)
|
||||
//byte coilValueLow = 0x00;
|
||||
|
||||
// Function to read coils
|
||||
public async Task<bool[]> ReadCoils(SerialPort port, ushort startAddress, ushort numberOfCoils)
|
||||
{
|
||||
try
|
||||
{
|
||||
byte functionCode = 0x01; // Function code for Read Coils
|
||||
byte[] frame = new byte[6]; // Request frame size (without CRC)
|
||||
|
||||
// Construct the request frame
|
||||
frame[0] = slaveId; // Slave address
|
||||
frame[1] = functionCode; // Function code (0x01 for Read Coils)
|
||||
frame[2] = (byte)(startAddress >> 8); // Start address high byte
|
||||
frame[3] = (byte)(startAddress & 0xFF); // Start address low byte
|
||||
frame[4] = (byte)(numberOfCoils >> 8); // Number of coils high byte
|
||||
frame[5] = (byte)(numberOfCoils & 0xFF); // Number of coils low byte
|
||||
|
||||
// Calculate CRC and append it to the frame
|
||||
byte[] crc = CalculateCRC(frame);
|
||||
byte[] fullFrame = new byte[frame.Length + crc.Length];
|
||||
Array.Copy(frame, fullFrame, frame.Length);
|
||||
Array.Copy(crc, 0, fullFrame, frame.Length, crc.Length);
|
||||
|
||||
// Send the frame over the serial port
|
||||
port.DiscardOutBuffer();
|
||||
port.DiscardInBuffer();
|
||||
|
||||
port.Write(fullFrame, 0, fullFrame.Length);
|
||||
Thread.Sleep(500);
|
||||
Console.WriteLine("Read Coils request sent.");
|
||||
|
||||
// Buffer for the response (modbus slave response size can vary)
|
||||
byte[] response = new byte[256];
|
||||
int bytesRead = port.Read(response, 0, response.Length);
|
||||
Console.WriteLine("Response Coils sent.");
|
||||
|
||||
|
||||
// Ensure that the response is valid (check slave address and function code)
|
||||
if (response[0] != slaveId || response[1] != functionCode)
|
||||
{
|
||||
Console.WriteLine("Invalid response or error in slave response.");
|
||||
return null;
|
||||
}
|
||||
|
||||
// Calculate the number of bytes based on the number of coils
|
||||
int expectedByteCount = (numberOfCoils + 7) / 8;
|
||||
if (response[2] != expectedByteCount)
|
||||
{
|
||||
Console.WriteLine("Incorrect byte count in the response.");
|
||||
return null;
|
||||
}
|
||||
|
||||
// The response bytes are in bit form, and we need to extract them
|
||||
bool[] coilStates = new bool[numberOfCoils]; // Array to store the coil states
|
||||
int byteIndex = 3; // Start reading from byte 3 (after slave ID and function code)
|
||||
byte coilByte = response[byteIndex]; // The byte representing the coil states
|
||||
|
||||
// Loop over all coils and check the corresponding bit
|
||||
for (int coilIndex = 0; coilIndex < numberOfCoils; coilIndex++)
|
||||
{
|
||||
// Check the state of the coil by checking the corresponding bit in coilByte
|
||||
coilStates[coilIndex] = coilByte == 1 ? true : false; /*(coilByte & (1 << (7 - coilIndex))) != 0;*/
|
||||
}
|
||||
if (coilStates==null)
|
||||
{
|
||||
Console.WriteLine("status wael: null");
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine($"status: {coilStates[0]}");
|
||||
|
||||
}
|
||||
|
||||
return coilStates;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"error wael: {ex.Message}");
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Function to write a single coil
|
||||
public async Task<byte[]> WriteSingleCoil(ushort coilAddress, bool state)
|
||||
{
|
||||
byte functionCode = 0x05;
|
||||
byte[] frame = new byte[6];
|
||||
|
||||
frame[0] = slaveId; // Slave address
|
||||
frame[1] = functionCode; // Function code
|
||||
frame[2] = (byte)(coilAddress >> 8); // Coil address high byte
|
||||
frame[3] = (byte)(coilAddress & 0xFF); // Coil address low byte
|
||||
frame[4] = (byte)(state ? 0xFF : 0x00); // Coil value (ON=0xFF, OFF=0x00)
|
||||
frame[5] = (byte)(0x00); // Coil value (ON=0xFF, OFF=0x00)
|
||||
|
||||
// Calculate CRC and append it
|
||||
byte[] crc = CalculateCRC(frame);
|
||||
byte[] fullFrame = new byte[frame.Length + crc.Length];
|
||||
Array.Copy(frame, fullFrame, frame.Length);
|
||||
Array.Copy(crc, 0, fullFrame, frame.Length, crc.Length);
|
||||
|
||||
return fullFrame;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Function to write multiple coils
|
||||
public byte[] WriteMultipleCoils( ushort startAddress, bool[] coilValues)
|
||||
{
|
||||
byte functionCode = 0x0F;
|
||||
int byteCount = (coilValues.Length + 7) / 8; // Calculate the number of bytes needed
|
||||
byte[] frame = new byte[5 + byteCount]; // Basic frame without CRC
|
||||
|
||||
frame[0] = slaveId; // Slave address
|
||||
frame[1] = functionCode; // Function code
|
||||
frame[2] = (byte)(startAddress >> 8); // Start address high byte
|
||||
frame[3] = (byte)(startAddress & 0xFF); // Start address low byte
|
||||
frame[4] = (byte)(coilValues.Length); // Number of coils
|
||||
|
||||
frame[5] = (byte)byteCount; // Number of bytes to follow (coil values)
|
||||
for (int i = 0; i < coilValues.Length; i++)
|
||||
{
|
||||
int byteIndex = 5 + 1 + (i / 8); // Start at byte 6, accounting for byte count
|
||||
if (coilValues[i])
|
||||
{
|
||||
frame[byteIndex] |= (byte)(1 << (i % 8)); // Set the bit corresponding to the coil
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate CRC and append it
|
||||
byte[] crc = CalculateCRC(frame);
|
||||
byte[] fullFrame = new byte[frame.Length + crc.Length];
|
||||
Array.Copy(frame, fullFrame, frame.Length);
|
||||
Array.Copy(crc, 0, fullFrame, frame.Length, crc.Length);
|
||||
|
||||
return fullFrame;
|
||||
}
|
||||
// Function to write multiple registers
|
||||
public async Task<byte[]> WriteSingleRegister(ushort startAddress, int value)
|
||||
{
|
||||
byte functionCode = 0x06; // Function code for writing a single register
|
||||
byte[] frame = new byte[6]; // Basic frame without CRC
|
||||
|
||||
frame[0] = slaveId; // Slave address
|
||||
frame[1] = functionCode; // Function code
|
||||
frame[2] = (byte)(startAddress >> 8); // Start address high byte
|
||||
frame[3] = (byte)(startAddress & 0xFF); // Start address low byte
|
||||
frame[4] = (byte)(value >> 8); // Register value high byte
|
||||
frame[5] = (byte)(value & 0xFF); // Register value low byte
|
||||
|
||||
// Calculate CRC and append it
|
||||
byte[] crc = CalculateCRC(frame);
|
||||
byte[] fullFrame = new byte[frame.Length + crc.Length];
|
||||
Array.Copy(frame, fullFrame, frame.Length);
|
||||
Array.Copy(crc, 0, fullFrame, frame.Length, crc.Length);
|
||||
|
||||
return fullFrame;
|
||||
}
|
||||
public async Task<byte[]> WriteSingleRegister(ushort startAddress, ushort value)
|
||||
{
|
||||
byte functionCode = 0x06; // Function code for writing a single register
|
||||
byte[] frame = new byte[6]; // Basic frame without CRC
|
||||
|
||||
frame[0] = slaveId; // Slave address
|
||||
frame[1] = functionCode; // Function code
|
||||
frame[2] = (byte)(startAddress >> 8); // Start address high byte
|
||||
frame[3] = (byte)(startAddress & 0xFF); // Start address low byte
|
||||
frame[4] = (byte)(value >> 8); // Register value high byte
|
||||
frame[5] = (byte)(value & 0xFF); // Register value low byte
|
||||
|
||||
// Calculate CRC and append it
|
||||
byte[] crc = CalculateCRC(frame);
|
||||
byte[] fullFrame = new byte[frame.Length + crc.Length];
|
||||
Array.Copy(frame, fullFrame, frame.Length);
|
||||
Array.Copy(crc, 0, fullFrame, frame.Length, crc.Length);
|
||||
|
||||
return fullFrame;
|
||||
}
|
||||
public async Task<byte[]> ReadHoldingRegister(ushort startAddress, ushort numberOfRegisters)
|
||||
{
|
||||
byte functionCode = 0x03; // Function code for reading holding registers
|
||||
byte[] frame = new byte[6]; // Basic frame without CRC
|
||||
|
||||
frame[0] = slaveId; // Slave address
|
||||
frame[1] = functionCode; // Function code
|
||||
frame[2] = (byte)(startAddress >> 8); // Start address high byte
|
||||
frame[3] = (byte)(startAddress & 0xFF); // Start address low byte
|
||||
frame[4] = (byte)(numberOfRegisters >> 8); // Number of registers high byte
|
||||
frame[5] = (byte)(numberOfRegisters & 0xFF); // Number of registers low byte
|
||||
|
||||
// Calculate CRC and append it
|
||||
byte[] crc = CalculateCRC(frame);
|
||||
byte[] fullFrame = new byte[frame.Length + crc.Length];
|
||||
Array.Copy(frame, fullFrame, frame.Length);
|
||||
Array.Copy(crc, 0, fullFrame, frame.Length, crc.Length);
|
||||
|
||||
return fullFrame;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public async Task<byte[]> ReadInputRegisters(ushort startAddress, ushort numberOfRegisters)
|
||||
{
|
||||
byte functionCode = 0x04; // Function code for reading input registers
|
||||
byte[] frame = new byte[6]; // Basic frame without CRC
|
||||
|
||||
frame[0] = slaveId; // Slave address
|
||||
frame[1] = functionCode; // Function code
|
||||
frame[2] = (byte)(startAddress >> 8); // Start address high byte
|
||||
frame[3] = (byte)(startAddress & 0xFF); // Start address low byte
|
||||
frame[4] = (byte)(numberOfRegisters >> 8); // Number of registers high byte
|
||||
frame[5] = (byte)(numberOfRegisters & 0xFF); // Number of registers low byte
|
||||
|
||||
// Calculate CRC and append it
|
||||
byte[] crc = CalculateCRC(frame);
|
||||
byte[] fullFrame = new byte[frame.Length + crc.Length];
|
||||
Array.Copy(frame, fullFrame, frame.Length);
|
||||
Array.Copy(crc, 0, fullFrame, frame.Length, crc.Length);
|
||||
|
||||
return fullFrame;
|
||||
}
|
||||
|
||||
|
||||
public async Task<byte[]> WriteMultipleRegisters(ushort startAddress, float[] values)
|
||||
{
|
||||
byte functionCode = 0x10; // Function code for writing multiple registers
|
||||
byte byteCount = (byte)(values.Length * 2); // Total number of bytes for values
|
||||
byte[] frame = new byte[7 + byteCount]; // Frame without CRC
|
||||
|
||||
frame[0] = slaveId; // Slave address
|
||||
frame[1] = functionCode; // Function code
|
||||
frame[2] = (byte)(startAddress >> 8); // Start address high byte
|
||||
frame[3] = (byte)(startAddress & 0xFF); // Start address low byte
|
||||
frame[4] = (byte)(values.Length >> 8); // Number of registers high byte
|
||||
frame[5] = (byte)(values.Length & 0xFF); // Number of registers low byte
|
||||
frame[6] = byteCount; // Byte count
|
||||
|
||||
for (int i = 0; i < values.Length; i++)
|
||||
{
|
||||
short val = unchecked((short)values[i]);
|
||||
frame[7 + i * 2] = (byte)(val >> 8); // Register value high byte
|
||||
frame[8 + i * 2] = (byte)(val & 0xFF); // Register value low byte1
|
||||
}
|
||||
|
||||
// Calculate CRC and append it
|
||||
byte[] crc = CalculateCRC(frame);
|
||||
byte[] fullFrame = new byte[frame.Length + crc.Length];
|
||||
Array.Copy(frame, fullFrame, frame.Length);
|
||||
Array.Copy(crc, 0, fullFrame, frame.Length, crc.Length);
|
||||
|
||||
return fullFrame;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Function to calculate CRC16 for Modbus RTU frame
|
||||
public byte[] CalculateCRC(byte[] data)
|
||||
{
|
||||
ushort crc = 0xFFFF;
|
||||
|
||||
foreach (byte byteData in data)
|
||||
{
|
||||
crc ^= byteData;
|
||||
|
||||
for (int i = 8; i > 0; i--)
|
||||
{
|
||||
if ((crc & 0x0001) == 0x0001)
|
||||
{
|
||||
crc >>= 1;
|
||||
crc ^= 0xA001;
|
||||
}
|
||||
else
|
||||
{
|
||||
crc >>= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new byte[] { (byte)(crc & 0xFF), (byte)((crc >> 8) & 0xFF) };
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
8
DaireApplication/ViewModels/ViewModelBase.cs
Normal file
8
DaireApplication/ViewModels/ViewModelBase.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
using ReactiveUI;
|
||||
|
||||
namespace DaireApplication.ViewModels
|
||||
{
|
||||
public class ViewModelBase : ReactiveObject
|
||||
{
|
||||
}
|
||||
}
|
||||
69
DaireApplication/ViewModels/X11CursorHider.cs
Normal file
69
DaireApplication/ViewModels/X11CursorHider.cs
Normal file
@@ -0,0 +1,69 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
public class X11CursorHider
|
||||
{
|
||||
const string X11Lib = "libX11.so";
|
||||
|
||||
[DllImport(X11Lib)]
|
||||
static extern IntPtr XOpenDisplay(IntPtr display);
|
||||
|
||||
[DllImport(X11Lib)]
|
||||
static extern int XCloseDisplay(IntPtr display);
|
||||
|
||||
[DllImport(X11Lib)]
|
||||
static extern IntPtr XCreatePixmap(IntPtr display, IntPtr drawable, uint width, uint height, uint depth);
|
||||
|
||||
[DllImport(X11Lib)]
|
||||
static extern IntPtr XCreateBitmapFromData(IntPtr display, IntPtr drawable, byte[] data, uint width, uint height);
|
||||
|
||||
[DllImport(X11Lib)]
|
||||
static extern IntPtr XCreatePixmapCursor(IntPtr display, IntPtr source, IntPtr mask, ref XColor foreground, ref XColor background, uint x, uint y);
|
||||
|
||||
[DllImport(X11Lib)]
|
||||
static extern int XDefineCursor(IntPtr display, IntPtr window, IntPtr cursor);
|
||||
|
||||
[DllImport(X11Lib)]
|
||||
static extern int XFreeCursor(IntPtr display, IntPtr cursor);
|
||||
|
||||
[DllImport(X11Lib)]
|
||||
static extern int XFlush(IntPtr display);
|
||||
|
||||
[DllImport(X11Lib)]
|
||||
static extern IntPtr XDefaultRootWindow(IntPtr display);
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
struct XColor
|
||||
{
|
||||
public ulong pixel;
|
||||
public ushort red, green, blue;
|
||||
public byte flags;
|
||||
public byte pad;
|
||||
}
|
||||
|
||||
public static void HideCursor()
|
||||
{
|
||||
IntPtr display = XOpenDisplay(IntPtr.Zero);
|
||||
if (display == IntPtr.Zero)
|
||||
{
|
||||
Console.WriteLine("Cannot open X display");
|
||||
return;
|
||||
}
|
||||
|
||||
IntPtr root = XDefaultRootWindow(display);
|
||||
|
||||
byte[] emptyData = new byte[1] { 0 }; // 1x1 empty bitmap
|
||||
IntPtr pixmap = XCreateBitmapFromData(display, root, emptyData, 1, 1);
|
||||
|
||||
XColor dummy = new XColor();
|
||||
|
||||
IntPtr invisibleCursor = XCreatePixmapCursor(display, pixmap, pixmap, ref dummy, ref dummy, 0, 0);
|
||||
|
||||
XDefineCursor(display, root, invisibleCursor);
|
||||
XFlush(display);
|
||||
|
||||
// Keep the cursor hidden until app closes, remember to call:
|
||||
// XFreeCursor(display, invisibleCursor);
|
||||
// XCloseDisplay(display);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user