141 lines
4.4 KiB
C#
141 lines
4.4 KiB
C#
using Common.Attributes;
|
|
using DeviceCommand.Base;
|
|
using Logger;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace DeviceCommand.Device
|
|
{
|
|
[BOBCommand]
|
|
public class IOBoard : ModbusTcp
|
|
{
|
|
public IOBoard(string Ip地址, int 端口, int 发送超时, int 接收超时)
|
|
{
|
|
ConfigureDevice(Ip地址, 端口, 发送超时, 接收超时);
|
|
}
|
|
#region 心跳
|
|
private CancellationTokenSource _cancellationTokenSource;
|
|
private Task? _heartbeatTask;
|
|
private const int HeartbeatInterval = 3000;
|
|
public bool IsActive = false;
|
|
public int ReConnectionAttempts = 0;
|
|
public const int MaxReconnectAttempts = 10;
|
|
public override async Task<bool> ConnectAsync(CancellationToken ct = default)
|
|
{
|
|
await _commLock.WaitAsync(ct);
|
|
try
|
|
{
|
|
if (TcpClient != null && !TcpClient.Connected) TcpClient = new();
|
|
if (TcpClient.Connected)
|
|
{
|
|
return true;
|
|
}
|
|
await TcpClient.ConnectAsync(IPAddress, Port, ct);
|
|
IsActive = true;
|
|
StartHeartbeat();
|
|
return true;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
return false;
|
|
}
|
|
finally
|
|
{
|
|
_commLock.Release();
|
|
}
|
|
}
|
|
public override void Close()
|
|
{
|
|
if (!TcpClient.Connected)
|
|
{
|
|
throw new InvalidOperationException("TCP 没有连接成功");
|
|
}
|
|
if (TcpClient.Connected)
|
|
{
|
|
TcpClient.Close();
|
|
StopHeartbeat();
|
|
}
|
|
}
|
|
// 启动设备的心跳
|
|
public void StartHeartbeat()
|
|
{
|
|
if (_heartbeatTask != null)
|
|
return;
|
|
if (_cancellationTokenSource == null || _cancellationTokenSource.IsCancellationRequested)
|
|
_cancellationTokenSource = new();
|
|
_heartbeatTask = Task.Run(() => HeartbeatLoop(_cancellationTokenSource.Token));
|
|
}
|
|
|
|
// 停止设备的心跳
|
|
public void StopHeartbeat()
|
|
{
|
|
IsActive = false;
|
|
_cancellationTokenSource.Cancel();
|
|
_heartbeatTask = null;
|
|
}
|
|
|
|
private async Task HeartbeatLoop(CancellationToken ct)
|
|
{
|
|
while (!ct.IsCancellationRequested)
|
|
{
|
|
await Task.Delay(HeartbeatInterval, ct);
|
|
|
|
try
|
|
{
|
|
await WriteSingleRegisterAsync(1, 0, 1);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
IsActive = false;
|
|
ReConnectionAttempts++;
|
|
if (MaxReconnectAttempts < ReConnectionAttempts)
|
|
{
|
|
StopHeartbeat();
|
|
return;
|
|
}
|
|
await ReconnectDevice(ct);
|
|
}
|
|
}
|
|
}
|
|
private async Task ReconnectDevice(CancellationToken ct)
|
|
{
|
|
try
|
|
{
|
|
bool resultConnect = await ConnectAsync(ct);
|
|
if (resultConnect)
|
|
{
|
|
ReConnectionAttempts = 0;
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
|
|
public virtual async Task 写单一输出(byte 从站地址, ushort 起始地址, ushort 值)
|
|
{
|
|
await WriteSingleRegisterAsync(从站地址, 起始地址, 值);
|
|
}
|
|
|
|
public virtual async Task 写多输出(byte 从站地址, ushort 起始地址, ushort[] 值数组)
|
|
{
|
|
await WriteMultipleRegistersAsync(从站地址, 起始地址, 值数组);
|
|
}
|
|
public virtual async Task<ushort> 读单一输入(byte 从站地址, ushort 起始地址, CancellationToken ct = default)
|
|
{
|
|
var result = await ReadInputRegistersAsync(从站地址, 起始地址, 1, ct);
|
|
return result[0];
|
|
}
|
|
public virtual async Task<ushort[]> 读多个输入(byte 从站地址, ushort 起始地址, ushort 数量, CancellationToken ct = default)
|
|
{
|
|
return await ReadInputRegistersAsync(从站地址, 起始地址, 数量, ct);
|
|
}
|
|
}
|
|
}
|