first commit

This commit is contained in:
2026-09-02 16:31:50 +08:00
commit a461727193
911 changed files with 692450 additions and 0 deletions
@@ -0,0 +1,547 @@
using JSMachine.WMS.Infrastructure.Helper;
using NModbus;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
namespace JSMachine.WMS.PLC
{
/// <summary>
/// Modbus TCP 通信引擎基类,封装 PLC 连接、重连以及寄存器/线圈读写操作。
/// </summary>
public abstract class ModbusEngineBase : IModbusEngine
{
private IModbusMaster _modbusMaster { get; set; }
private string _ip { get; set; }
private int _port { get; set; }
/// <summary>
/// 保存 PLC 网络端点,实际连接在首次通信或显式连接时建立。
/// </summary>
/// <param name="ip">PLC IP 地址。</param>
/// <param name="port">PLC TCP 端口。</param>
/// <returns>当前通信引擎实例。</returns>
public virtual IModbusEngine Init(string ip, int port)
{
_ip = ip;
_port = port;
return this;
}
private object _locker = new();
private TcpClient _tcpClient = new();
/// <summary>
/// 建立 PLC TCP 连接;连接过程加锁以避免并发重连,超时时间为 2 秒。
/// </summary>
/// <returns>当前通信引擎实例。</returns>
public IModbusEngine Connet()
{
lock (_locker)
{
if (!_tcpClient.Connected)
{
try
{
_tcpClient = new();
IAsyncResult asyncResult = _tcpClient.BeginConnect(IPAddress.Parse(_ip), _port, null, null);
if (asyncResult.AsyncWaitHandle.WaitOne(2000))
{
_tcpClient.EndConnect(asyncResult);
ModbusFactory factory = new();
_modbusMaster = factory.CreateMaster(_tcpClient);
}
else
{
_tcpClient.Close();
LogHelper.Error($"连接 PLC {_ip}:{_port} 超时");
}
}
catch (Exception ex)
{
_tcpClient.Close();
_modbusMaster = null;
}
}
}
return this;
}
/// <summary>
/// 判断 Modbus 主站是否已初始化。
/// </summary>
/// <returns>主站对象不为空时返回 <see langword="true"/>。</returns>
public bool IsConneted()
{
return !(_modbusMaster == null);
}
/// <summary>
/// 批量读取线圈值
/// </summary>
/// <param name="slaveAddress"></param>
/// <param name="startAddress"></param>
/// <param name="numberOfPoints"></param>
/// <returns></returns>
public bool[] ReadCoils(byte slaveAddress, ushort startAddress, ushort numberOfPoints)
{
if (_modbusMaster == null)
{
this.Connet();
return null;
}
try
{
return _modbusMaster.ReadCoils(slaveAddress, startAddress, numberOfPoints);
}
catch (Exception ex)
{
LogHelper.Error($"批量读取PLC信息失败,错误消息:{ex.Message}");
this.Connet();
return null;
}
}
/// <summary>
/// 批量读取线圈值(异步)
/// </summary>
/// <param name="slaveAddress"></param>
/// <param name="startAddress"></param>
/// <param name="numberOfPoints"></param>
/// <returns></returns>
public async Task<bool[]> ReadCoilsAsync(byte slaveAddress, ushort startAddress, ushort numberOfPoints)
{
if (_modbusMaster == null)
{
this.Connet();
return null;
}
try
{
return await _modbusMaster.ReadCoilsAsync(slaveAddress, startAddress, numberOfPoints);
}
catch (Exception ex)
{
LogHelper.Error($"批量读取PLC信息失败,错误消息:{ex.Message}");
this.Connet();
return null;
}
}
/// <summary>
/// 无符号读取
/// </summary>
/// <param name="slaveAddress"></param>
/// <param name="startAddress"></param>
/// <param name="numberOfPoints"></param>
/// <returns></returns>
public ushort[] ReadUshorts(byte slaveAddress, ushort startAddress, ushort numberOfPoints)
{
if (_modbusMaster == null)
{
this.Connet();
return null;
}
try
{
ushort[] data = _modbusMaster.ReadHoldingRegisters(slaveAddress, startAddress, numberOfPoints);
return data;
}
catch (Exception ex)
{
LogHelper.Error($"无符号读取PLC信息失败,错误消息:{ex.Message}");
this.Connet();
return null;
}
}
/// <summary>
/// 无符号读取(异步)
/// </summary>
/// <param name="slaveAddress"></param>
/// <param name="startAddress"></param>
/// <param name="numberOfPoints"></param>
/// <returns></returns>
public async Task<ushort[]> ReadUshortsAsync(byte slaveAddress, ushort startAddress, ushort numberOfPoints)
{
if (_modbusMaster == null)
{
this.Connet();
return null;
}
try
{
ushort[] data = await _modbusMaster.ReadHoldingRegistersAsync(slaveAddress, startAddress, numberOfPoints);
return data;
}
catch (Exception ex)
{
LogHelper.Error($"无符号读取PLC信息失败,错误消息:{ex.Message}");
this.Connet();
return null;
}
}
/// <summary>
/// 有符号读取
/// </summary>
/// <param name="slaveAddress"></param>
/// <param name="startAddress"></param>
/// <param name="numberOfPoints"></param>
/// <returns></returns>
public short[] ReadShorts(byte slaveAddress, ushort startAddress, ushort numberOfPoints)
{
try
{
ushort[] data = ReadUshorts(slaveAddress, startAddress, numberOfPoints);
if (data == null)
return null;
//计算补码
short[] rtn = data.Select(p => BitConverter.ToInt16(BitConverter.GetBytes(p))).ToArray();
return rtn;
}
catch (Exception ex)
{
LogHelper.Error($"有符号读取PLC信息失败,错误消息:{ex.Message}");
return null;
}
}
/// <summary>
/// 有符号读取(异步)
/// </summary>
/// <param name="slaveAddress"></param>
/// <param name="startAddress"></param>
/// <param name="numberOfPoints"></param>
/// <returns></returns>
public async Task<short[]> ReadShortsAsync(byte slaveAddress, ushort startAddress, ushort numberOfPoints)
{
try
{
ushort[] data = await ReadUshortsAsync(slaveAddress, startAddress, numberOfPoints);
if (data == null)
return null;
//计算补码
short[] rtn = data.Select(p => BitConverter.ToInt16(BitConverter.GetBytes(p))).ToArray();
return rtn;
}
catch (Exception ex)
{
LogHelper.Error($"有符号读取PLC信息失败,错误消息:{ex.Message}");
return null;
}
}
/// <summary>
/// 写单个无符号值
/// </summary>
/// <param name="slaveAddress"></param>
/// <param name="startAddress"></param>
/// <param name="data"></param>
/// <returns></returns>
public bool WriteUshortOne(byte slaveAddress, ushort startAddress, ushort data)
{
if (_modbusMaster == null)
{
this.Connet();
return false;
}
try
{
_modbusMaster.WriteSingleRegister(slaveAddress, startAddress, data);
return true;
}
catch (Exception ex)
{
LogHelper.Error($"写单个PLC信息失败,错误消息:{ex.Message}");
this.Connet();
return false;
}
}
/// <summary>
/// 写单个无符号值(异步)
/// </summary>
/// <param name="slaveAddress"></param>
/// <param name="startAddress"></param>
/// <param name="data"></param>
/// <returns></returns>
public async Task<bool> WriteUshortOneAsync(byte slaveAddress, ushort startAddress, ushort data)
{
if (_modbusMaster == null)
{
this.Connet();
return false;
}
try
{
await _modbusMaster.WriteSingleRegisterAsync(slaveAddress, startAddress, data);
return true;
}
catch (Exception ex)
{
LogHelper.Error($"写单个PLC信息失败,错误消息:{ex.Message}");
this.Connet();
return false;
}
}
/// <summary>
/// 写单个有符号值
/// </summary>
/// <param name="slaveAddress"></param>
/// <param name="startAddress"></param>
/// <param name="data"></param>
/// <returns></returns>
public bool WriteShortOne(byte slaveAddress, ushort startAddress, short data)
{
if (_modbusMaster == null)
{
this.Connet();
return false;
}
try
{
ushort writeData = BitConverter.ToUInt16(new ReadOnlySpan<byte>(BitConverter.GetBytes(data)));
_modbusMaster.WriteSingleRegister(slaveAddress, startAddress, writeData);
return true;
}
catch (Exception ex)
{
LogHelper.Error($"写单个PLC信息失败,错误消息:{ex.Message}");
this.Connet();
return false;
}
}
/// <summary>
/// 写单个线圈值
/// </summary>
/// <param name="slaveAddress"></param>
/// <param name="startAddress"></param>
/// <param name="data"></param>
/// <returns></returns>
public bool WriteCoilOne(byte slaveAddress, ushort startAddress, bool data)
{
if (_modbusMaster == null)
{
this.Connet();
return false;
}
try
{
_modbusMaster.WriteSingleCoil(slaveAddress, startAddress, data);
return true;
}
catch (Exception ex)
{
LogHelper.Error($"写单个线圈值失败,错误消息:{ex.Message}");
this.Connet();
return false;
}
}
/// <summary>
/// 写单个线圈值
/// </summary>
/// <param name="slaveAddress"></param>
/// <param name="startAddress"></param>
/// <param name="data"></param>
/// <returns></returns>
public async Task<bool> WriteCoilOneAsync(byte slaveAddress, ushort startAddress, bool data)
{
if (_modbusMaster == null)
{
this.Connet();
return false;
}
try
{
await _modbusMaster.WriteSingleCoilAsync(slaveAddress, startAddress, data);
return true;
}
catch (Exception ex)
{
LogHelper.Error($"写单个线圈值失败,错误消息:{ex.Message}");
this.Connet();
return false;
}
}
/// <summary>
/// 写单个有符号值(异步)
/// </summary>
/// <param name="slaveAddress"></param>
/// <param name="startAddress"></param>
/// <param name="data"></param>
/// <returns></returns>
public async Task<bool> WriteShortOneAsync(byte slaveAddress, ushort startAddress, short data)
{
if (_modbusMaster == null)
{
this.Connet();
return false;
}
try
{
ushort writeData = BitConverter.ToUInt16(new ReadOnlySpan<byte>(BitConverter.GetBytes(data)));
await _modbusMaster.WriteSingleRegisterAsync(slaveAddress, startAddress, writeData);
return true;
}
catch (Exception ex)
{
LogHelper.Error($"写单个PLC信息失败,错误消息:{ex.Message}");
this.Connet();
return false;
}
}
/// <summary>
/// 写多个无符号值
/// </summary>
/// <param name="slaveAddress"></param>
/// <param name="startAddress"></param>
/// <param name="data"></param>
/// <returns></returns>
public bool WriteUshortsMany(byte slaveAddress, ushort startAddress, ushort[] data)
{
if (_modbusMaster == null)
{
this.Connet();
return false;
}
try
{
_modbusMaster.WriteMultipleRegisters(slaveAddress, startAddress, data);
return true;
}
catch (Exception ex)
{
LogHelper.Error($"写多个PLC信息失败,错误消息:{ex.Message}");
this.Connet();
return false;
}
}
/// <summary>
/// 写多个无符号值(异步)
/// </summary>
/// <param name="slaveAddress"></param>
/// <param name="startAddress"></param>
/// <param name="data"></param>
/// <returns></returns>
public async Task<bool> WriteUshortsManyAsync(byte slaveAddress, ushort startAddress, ushort[] data)
{
if (_modbusMaster == null)
{
this.Connet();
return false;
}
try
{
await _modbusMaster.WriteMultipleRegistersAsync(slaveAddress, startAddress, data);
return true;
}
catch (Exception ex)
{
LogHelper.Error($"写多个PLC信息失败,错误消息:{ex.Message}");
this.Connet();
return false;
}
}
/// <summary>
/// 写多个有符号值
/// </summary>
/// <param name="slaveAddress"></param>
/// <param name="startAddress"></param>
/// <param name="data"></param>
/// <returns></returns>
public bool WriteShortsMany(byte slaveAddress, ushort startAddress, short[] data)
{
if (_modbusMaster == null)
{
this.Connet();
return false;
}
if (data == null || data.Length == 0)
{
return false;
}
try
{
ushort[] writeData = data.Select(p => BitConverter.ToUInt16(new ReadOnlySpan<byte>(BitConverter.GetBytes(p)))).ToArray();
_modbusMaster.WriteMultipleRegisters(slaveAddress, startAddress, writeData);
return true;
}
catch (Exception ex)
{
LogHelper.Error($"写多个PLC信息失败,错误消息:{ex.Message}");
this.Connet();
return false;
}
}
/// <summary>
/// 写多个有符号值(异步)
/// </summary>
/// <param name="slaveAddress"></param>
/// <param name="startAddress"></param>
/// <param name="data"></param>
/// <returns></returns>
public async Task<bool> WriteShortsManyAsync(byte slaveAddress, ushort startAddress, short[] data)
{
if (_modbusMaster == null)
{
this.Connet();
return false;
}
if (data == null || data.Length == 0)
{
return false;
}
try
{
ushort[] writeData = data.Select(p => BitConverter.ToUInt16(new ReadOnlySpan<byte>(BitConverter.GetBytes(p)))).ToArray();
await _modbusMaster.WriteMultipleRegistersAsync(slaveAddress, startAddress, writeData);
return true;
}
catch (Exception ex)
{
LogHelper.Error($"写多个PLC信息失败,错误消息:{ex.Message}");
this.Connet();
return false;
}
}
}
}