recipe name filter
This commit is contained in:
167
Plugins/Siemens/B24SiemensEmulator/TcpClient.cs
Normal file
167
Plugins/Siemens/B24SiemensEmulator/TcpClient.cs
Normal file
@@ -0,0 +1,167 @@
|
||||
using System;
|
||||
using System.Net.Sockets;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Timer = System.Threading.Timer;
|
||||
|
||||
namespace B24SiemensEmulator
|
||||
{
|
||||
public class SiemensTcpClient : IDisposable
|
||||
{
|
||||
private TcpClient? _tcpClient;
|
||||
private NetworkStream? _stream;
|
||||
private Timer? _sendTimer;
|
||||
private bool _isConnected = false;
|
||||
private bool _isRunning = false;
|
||||
private readonly object _lock = new object();
|
||||
|
||||
public event Action<bool>? ConnectionStatusChanged;
|
||||
public event Action<PLCPacket>? ResponseReceived;
|
||||
public event Action<string>? ErrorOccurred;
|
||||
|
||||
private readonly string _serverHost = "localhost";
|
||||
private readonly int _serverPort = 42010;
|
||||
private readonly int _sendIntervalMs = 1000;
|
||||
|
||||
public Func<PLCPacket>? GetPacketToSend;
|
||||
|
||||
public bool IsConnected => _isConnected;
|
||||
public bool IsRunning => _isRunning;
|
||||
|
||||
public async Task<bool> ConnectAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_isConnected)
|
||||
return true;
|
||||
|
||||
_tcpClient = new TcpClient();
|
||||
await _tcpClient.ConnectAsync(_serverHost, _serverPort);
|
||||
_stream = _tcpClient.GetStream();
|
||||
|
||||
lock (_lock)
|
||||
{
|
||||
_isConnected = true;
|
||||
}
|
||||
|
||||
ConnectionStatusChanged?.Invoke(true);
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ErrorOccurred?.Invoke($"Connection failed: {ex.Message}");
|
||||
await DisconnectAsync();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task DisconnectAsync()
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
_isConnected = false;
|
||||
}
|
||||
|
||||
_stream?.Close();
|
||||
_stream?.Dispose();
|
||||
_stream = null;
|
||||
|
||||
_tcpClient?.Close();
|
||||
_tcpClient?.Dispose();
|
||||
_tcpClient = null;
|
||||
|
||||
ConnectionStatusChanged?.Invoke(false);
|
||||
}
|
||||
|
||||
public void StartSending()
|
||||
{
|
||||
if (_isRunning)
|
||||
return;
|
||||
|
||||
_isRunning = true;
|
||||
_sendTimer = new Timer(SendPacketCallback, null, 0, _sendIntervalMs);
|
||||
}
|
||||
|
||||
public void StopSending()
|
||||
{
|
||||
_isRunning = false;
|
||||
_sendTimer?.Dispose();
|
||||
_sendTimer = null;
|
||||
}
|
||||
|
||||
private async void SendPacketCallback(object? state)
|
||||
{
|
||||
if (!_isConnected || GetPacketToSend == null)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
var packet = GetPacketToSend();
|
||||
await SendPacketAsync(packet);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ErrorOccurred?.Invoke($"Send failed: {ex.Message}");
|
||||
await HandleConnectionLoss();
|
||||
}
|
||||
}
|
||||
|
||||
private async Task SendPacketAsync(PLCPacket packet)
|
||||
{
|
||||
if (_stream == null || !_isConnected)
|
||||
throw new InvalidOperationException("Not connected");
|
||||
|
||||
var data = packet.Serialize();
|
||||
await _stream.WriteAsync(data, 0, data.Length);
|
||||
|
||||
// Read response
|
||||
var responseBuffer = new byte[19]; // PLCPacket is 19 bytes
|
||||
int totalBytesRead = 0;
|
||||
|
||||
while (totalBytesRead < responseBuffer.Length)
|
||||
{
|
||||
int bytesRead = await _stream.ReadAsync(responseBuffer, totalBytesRead,
|
||||
responseBuffer.Length - totalBytesRead);
|
||||
|
||||
if (bytesRead == 0)
|
||||
throw new Exception("Server disconnected");
|
||||
|
||||
totalBytesRead += bytesRead;
|
||||
}
|
||||
|
||||
var responsePacket = PLCPacket.Deserialize(responseBuffer);
|
||||
ResponseReceived?.Invoke(responsePacket);
|
||||
}
|
||||
|
||||
private async Task HandleConnectionLoss()
|
||||
{
|
||||
await DisconnectAsync();
|
||||
|
||||
// Wait 1 second before trying to reconnect
|
||||
await Task.Delay(1000);
|
||||
|
||||
if (_isRunning)
|
||||
{
|
||||
var reconnected = await ConnectAsync();
|
||||
if (!reconnected)
|
||||
{
|
||||
// Schedule another reconnection attempt
|
||||
_ = Task.Run(async () =>
|
||||
{
|
||||
await Task.Delay(1000);
|
||||
if (_isRunning && !_isConnected)
|
||||
{
|
||||
await HandleConnectionLoss();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
StopSending();
|
||||
DisconnectAsync().Wait(1000);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user