|
|
@@ -0,0 +1,456 @@ |
|
|
|
using BPASmartClient.Message; |
|
|
|
using NModbus; |
|
|
|
using System; |
|
|
|
using System.Collections.Generic; |
|
|
|
using System.Linq; |
|
|
|
using System.Net.Sockets; |
|
|
|
using System.Threading; |
|
|
|
|
|
|
|
|
|
|
|
namespace BPASmartClient.Modbus |
|
|
|
{ |
|
|
|
public class ModbusTcpHelper |
|
|
|
{ |
|
|
|
|
|
|
|
private volatile static ModbusTcpHelper _Instance; |
|
|
|
public static ModbusTcpHelper GetInstance => _Instance ?? (_Instance = new ModbusTcpHelper()); |
|
|
|
private ModbusTcpHelper() { } |
|
|
|
|
|
|
|
private ModbusFactory modbusFactory; |
|
|
|
private IModbusMaster master; |
|
|
|
private TcpClient tcpClient; |
|
|
|
private string IPAdress; |
|
|
|
private int Port; |
|
|
|
|
|
|
|
//public Action ConnectOk { get; set; } |
|
|
|
|
|
|
|
/// <summary> |
|
|
|
/// 判断是否连接成功 |
|
|
|
/// </summary> |
|
|
|
public bool Connected => tcpClient == null ? false : tcpClient.Connected; |
|
|
|
|
|
|
|
/// <summary> |
|
|
|
/// ModbusTcp 连接设备 |
|
|
|
/// </summary> |
|
|
|
/// <param name="ip">ip 地址</param> |
|
|
|
/// <param name="port">端口号,默认502</param> |
|
|
|
public void ModbusTcpConnect(string ip, int port = 502) |
|
|
|
{ |
|
|
|
MessageLog.GetInstance.Show($"设备【{ip}:{port}】连接中。。。。"); |
|
|
|
IPAdress = ip; |
|
|
|
Port = port; |
|
|
|
modbusFactory = new ModbusFactory(); |
|
|
|
Connect(); |
|
|
|
master.Transport.ReadTimeout = 2000;//读取超时时间 |
|
|
|
master.Transport.WriteTimeout = 2000;//写入超时时间 |
|
|
|
master.Transport.Retries = 10;//重试次数 |
|
|
|
//ActionManage.GetInstance.Send("ConnectOk"); |
|
|
|
//ActionManage.GetInstance.Send($"{GVL.GeneralConfig.DeviceType.ToString()}/ConnectOk"); |
|
|
|
MessageLog.GetInstance.Show($"设备【{ip}:{port}】连接成功"); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private void Connect() |
|
|
|
{ |
|
|
|
bool ErrorFlag = false; |
|
|
|
while (!Connected) |
|
|
|
{ |
|
|
|
try |
|
|
|
{ |
|
|
|
tcpClient = new TcpClient(IPAdress, Port); |
|
|
|
master = modbusFactory.CreateMaster(tcpClient); |
|
|
|
} |
|
|
|
catch (Exception ex) |
|
|
|
{ |
|
|
|
if (!ErrorFlag) |
|
|
|
{ |
|
|
|
MessageLog.GetInstance.ShowEx($"ModbusTcp 连接失败,IP = {IPAdress},Port = {Port}"); |
|
|
|
MessageLog.GetInstance.ShowEx(ex.ToString()); |
|
|
|
ErrorFlag = true; |
|
|
|
} |
|
|
|
Thread.Sleep(3000); |
|
|
|
} |
|
|
|
} |
|
|
|
MessageLog.GetInstance.Show("ModbusTcp 连接成功!"); |
|
|
|
} |
|
|
|
|
|
|
|
public int GetBoolAddress(string address) |
|
|
|
{ |
|
|
|
if (address != null && address.Length >= 4) |
|
|
|
{ |
|
|
|
var res = address.Substring(1).Split('.'); |
|
|
|
if (res != null && res.Length == 2) |
|
|
|
{ |
|
|
|
if (int.TryParse(res[0], out int firstAddress) && int.TryParse(res[1], out int ExitAddress)) |
|
|
|
{ |
|
|
|
if (ExitAddress >= 0 && ExitAddress <= 7) |
|
|
|
{ |
|
|
|
return (firstAddress * 8) + 320 + ExitAddress; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
return -1; |
|
|
|
} |
|
|
|
|
|
|
|
public int GetWordAddress(string address) |
|
|
|
{ |
|
|
|
if (address != null && address.Length > 3) |
|
|
|
{ |
|
|
|
var res = address.Substring(2); |
|
|
|
if (res != null && int.TryParse(res, out int tempAddress)) |
|
|
|
{ |
|
|
|
return (tempAddress / 2) + 100; |
|
|
|
} |
|
|
|
} |
|
|
|
return -1; |
|
|
|
} |
|
|
|
|
|
|
|
public void Readbool(ushort startAddress, ushort len, Action<bool[]> action) |
|
|
|
{ |
|
|
|
object result; |
|
|
|
result = Read(startAddress, ReadType.Coils, len); |
|
|
|
if (result != null) |
|
|
|
{ |
|
|
|
if (result is bool[] bools) |
|
|
|
{ |
|
|
|
if (bools.Length == len) |
|
|
|
{ |
|
|
|
action(bools); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
public object Read(ushort startAddress, ReadType readType, ushort num = 1, byte slaveAddress = 1) |
|
|
|
{ |
|
|
|
object result = new object(); |
|
|
|
if (tcpClient == null) return result; |
|
|
|
if (num <= 0) return result; |
|
|
|
try |
|
|
|
{ |
|
|
|
switch (readType) |
|
|
|
{ |
|
|
|
case ReadType.Coils: |
|
|
|
result = master.ReadCoils(slaveAddress, startAddress, num); |
|
|
|
break; |
|
|
|
case ReadType.Inputs: |
|
|
|
result = master.ReadInputs(slaveAddress, startAddress, num); |
|
|
|
break; |
|
|
|
case ReadType.HoldingRegisters: |
|
|
|
result = master.ReadHoldingRegisters(slaveAddress, startAddress, num); |
|
|
|
break; |
|
|
|
case ReadType.InputRegisters: |
|
|
|
result = master.ReadInputRegisters(slaveAddress, startAddress, num); |
|
|
|
break; |
|
|
|
default: |
|
|
|
break; |
|
|
|
} |
|
|
|
if (result == null) return new object(); |
|
|
|
if (result is bool[] bools) |
|
|
|
{ |
|
|
|
if (bools.Length == 1) |
|
|
|
return bools[0]; |
|
|
|
else |
|
|
|
return bools; |
|
|
|
} |
|
|
|
if (result is ushort[] ushorts) |
|
|
|
{ |
|
|
|
if (ushorts.Length == 1) |
|
|
|
return ushorts[0]; |
|
|
|
else |
|
|
|
return ushorts; |
|
|
|
} |
|
|
|
} |
|
|
|
catch (Exception ex) |
|
|
|
{ |
|
|
|
MessageLog.GetInstance.ShowEx(ex.ToString()); |
|
|
|
if (ex.InnerException is SocketException) |
|
|
|
{ |
|
|
|
tcpClient = null; |
|
|
|
Connect(); |
|
|
|
} |
|
|
|
} |
|
|
|
return result; |
|
|
|
} |
|
|
|
|
|
|
|
public bool Write(ushort startAddress, WriteType writeType, object InputValue, byte slaveAddress = 1) |
|
|
|
{ |
|
|
|
bool result = false; |
|
|
|
if (tcpClient == null) return result; |
|
|
|
if (!(InputValue is bool || InputValue is bool[] || InputValue is ushort || InputValue is ushort[])) return result; |
|
|
|
try |
|
|
|
{ |
|
|
|
switch (writeType) |
|
|
|
{ |
|
|
|
case WriteType.Coils: |
|
|
|
if (InputValue is bool boolValue) |
|
|
|
master.WriteSingleCoil(slaveAddress, startAddress, boolValue); |
|
|
|
|
|
|
|
if (InputValue is bool[] boolsValue) |
|
|
|
master.WriteMultipleCoils(slaveAddress, startAddress, boolsValue); |
|
|
|
break; |
|
|
|
case WriteType.HoldingRegisters: |
|
|
|
if (InputValue is ushort ushortValue) |
|
|
|
master.WriteSingleRegister(slaveAddress, startAddress, ushortValue); |
|
|
|
|
|
|
|
if (InputValue is ushort[] ushortsValue) |
|
|
|
{ |
|
|
|
int len = 100; |
|
|
|
if (ushortsValue.Length > len) |
|
|
|
{ |
|
|
|
List<ushort[]> ushortLists = new List<ushort[]>(); |
|
|
|
for (int i = 0; i < ushortsValue.Length / len; i++) |
|
|
|
{ |
|
|
|
ushortLists.Add(ushortsValue.Skip(0).Take(len).ToArray()); |
|
|
|
} |
|
|
|
int y = ushortsValue.Length % len; |
|
|
|
|
|
|
|
if (y > 0) |
|
|
|
{ |
|
|
|
ushortLists.Add(ushortsValue.Skip(ushortsValue.Length - y).Take(y).ToArray()); |
|
|
|
} |
|
|
|
foreach (var item in ushortLists) |
|
|
|
{ |
|
|
|
master.WriteMultipleRegisters(slaveAddress, startAddress, item); |
|
|
|
startAddress += (ushort)item.Length; |
|
|
|
} |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
master.WriteMultipleRegisters(slaveAddress, startAddress, ushortsValue); |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
break; |
|
|
|
default: |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
catch (Exception ex) |
|
|
|
{ |
|
|
|
MessageLog.GetInstance.ShowEx(ex.ToString()); |
|
|
|
if (ex.InnerException is SocketException) |
|
|
|
{ |
|
|
|
tcpClient = null; |
|
|
|
Connect(); |
|
|
|
} |
|
|
|
return false; |
|
|
|
} |
|
|
|
return true; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
#region 批量数据读取 |
|
|
|
/// <summary> |
|
|
|
/// 读取多个线圈 |
|
|
|
/// </summary> |
|
|
|
/// <param name="startAddress"></param> |
|
|
|
/// <param name="num"></param> |
|
|
|
/// <param name="slaveAddress"></param> |
|
|
|
/// <returns></returns> |
|
|
|
public bool[] ReadCoils(ushort startAddress, ushort num, byte slaveAddress = 1) |
|
|
|
{ |
|
|
|
return master.ReadCoils(slaveAddress, startAddress, num); |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary> |
|
|
|
/// 读取多个输入线圈 |
|
|
|
/// </summary> |
|
|
|
/// <param name="startAddress"></param> |
|
|
|
/// <param name="num"></param> |
|
|
|
/// <param name="slaveAddress"></param> |
|
|
|
/// <returns></returns> |
|
|
|
public bool[] ReadInputs(ushort startAddress, ushort num, byte slaveAddress = 1) |
|
|
|
{ |
|
|
|
return master.ReadInputs(slaveAddress, startAddress, num); |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary> |
|
|
|
/// 读取多个保持寄存器 |
|
|
|
/// </summary> |
|
|
|
/// <param name="startAddress"></param> |
|
|
|
/// <param name="num"></param> |
|
|
|
/// <param name="slaveAddress"></param> |
|
|
|
/// <returns></returns> |
|
|
|
public ushort[] ReadHoldingRegisters(ushort startAddress, ushort num, byte slaveAddress = 1) |
|
|
|
{ |
|
|
|
return master.ReadHoldingRegisters(slaveAddress, startAddress, num); |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary> |
|
|
|
/// 读取多个输入寄存器 |
|
|
|
/// </summary> |
|
|
|
/// <param name="startAddress"></param> |
|
|
|
/// <param name="num"></param> |
|
|
|
/// <param name="slaveAddress"></param> |
|
|
|
/// <returns></returns> |
|
|
|
public ushort[] ReadInputRegisters(ushort startAddress, ushort num, byte slaveAddress = 1) |
|
|
|
{ |
|
|
|
return master.ReadInputRegisters(slaveAddress, startAddress, num); |
|
|
|
} |
|
|
|
#endregion |
|
|
|
|
|
|
|
#region 批量数据写入 |
|
|
|
/// <summary> |
|
|
|
/// 写入多个线圈 |
|
|
|
/// </summary> |
|
|
|
/// <param name="startAddress"></param> |
|
|
|
/// <param name="value"></param> |
|
|
|
/// <param name="slaveAddress"></param> |
|
|
|
public void WriteMultipleCoils(ushort startAddress, bool[] value, byte slaveAddress = 1) |
|
|
|
{ |
|
|
|
master.WriteMultipleCoils(slaveAddress, startAddress, value); |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary> |
|
|
|
/// 写入多个寄存器 |
|
|
|
/// </summary> |
|
|
|
/// <param name="startAddress"></param> |
|
|
|
/// <param name="value"></param> |
|
|
|
/// <param name="slaveAddress"></param> |
|
|
|
public void WriteMultipleRegisters(ushort startAddress, ushort[] value, byte slaveAddress = 1) |
|
|
|
{ |
|
|
|
master.WriteMultipleRegisters(slaveAddress, startAddress, value); |
|
|
|
} |
|
|
|
#endregion |
|
|
|
|
|
|
|
#region 单个数据读取 |
|
|
|
/// <summary> |
|
|
|
/// 读取单个线圈 |
|
|
|
/// </summary> |
|
|
|
/// <param name="startAddress"></param> |
|
|
|
/// <param name="slaveAddress"></param> |
|
|
|
/// <returns></returns> |
|
|
|
public bool ReadCoils(ushort startAddress, byte slaveAddress = 1) |
|
|
|
{ |
|
|
|
var result = master.ReadCoils(slaveAddress, startAddress, 1); |
|
|
|
if (result == null) return false; |
|
|
|
if (result.Length == 1) return result[0]; |
|
|
|
return false; |
|
|
|
//return master.ReadCoils(slaveAddress, startAddress, 1)[0]; |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary> |
|
|
|
/// 读取单个输入线圈 |
|
|
|
/// </summary> |
|
|
|
/// <param name="startAddress"></param> |
|
|
|
/// <param name="slaveAddress"></param> |
|
|
|
/// <returns></returns> |
|
|
|
public bool ReadInputs(ushort startAddress, byte slaveAddress = 1) |
|
|
|
{ |
|
|
|
var result = master.ReadInputs(slaveAddress, startAddress, 1); |
|
|
|
if (result == null) return false; |
|
|
|
if (result.Length == 1) return result[0]; |
|
|
|
return false; |
|
|
|
//return master.ReadInputs(slaveAddress, startAddress, 1)[0]; |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary> |
|
|
|
/// 读取单个保持寄存器 |
|
|
|
/// </summary> |
|
|
|
/// <param name="startAddress"></param> |
|
|
|
/// <param name="slaveAddress"></param> |
|
|
|
/// <returns></returns> |
|
|
|
public ushort ReadHoldingRegisters(ushort startAddress, byte slaveAddress = 1) |
|
|
|
{ |
|
|
|
if (tcpClient == null) return 0; |
|
|
|
ushort[] result = null; |
|
|
|
try |
|
|
|
{ |
|
|
|
result = master.ReadHoldingRegisters(slaveAddress, startAddress, 1); |
|
|
|
} |
|
|
|
catch (Exception ex) |
|
|
|
{ |
|
|
|
MessageLog.GetInstance.Show(ex.ToString()); |
|
|
|
tcpClient = null; |
|
|
|
Connect(); |
|
|
|
} |
|
|
|
|
|
|
|
if (result == null) return 0; |
|
|
|
if (result.Length == 1) return result[0]; |
|
|
|
return 0; |
|
|
|
//return master.ReadHoldingRegisters(slaveAddress, startAddress, 1)[0]; |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary> |
|
|
|
/// 读取单个输入寄存器 |
|
|
|
/// </summary> |
|
|
|
/// <param name="startAddress"></param> |
|
|
|
/// <param name="slaveAddress"></param> |
|
|
|
/// <returns></returns> |
|
|
|
public ushort ReadInputRegisters(ushort startAddress, byte slaveAddress = 1) |
|
|
|
{ |
|
|
|
var result = master.ReadInputRegisters(slaveAddress, startAddress, 1); |
|
|
|
if (result == null) return 0; |
|
|
|
if (result.Length == 1) return result[0]; |
|
|
|
return 0; |
|
|
|
//return master.ReadInputRegisters(slaveAddress, startAddress, 1)[0]; |
|
|
|
} |
|
|
|
#endregion |
|
|
|
|
|
|
|
#region 单个数据写入 |
|
|
|
/// <summary> |
|
|
|
/// 写入单个线圈 |
|
|
|
/// </summary> |
|
|
|
/// <param name="startAddress"></param> |
|
|
|
/// <param name="value"></param> |
|
|
|
/// <param name="slaveAddress"></param> |
|
|
|
public void WriteSingleCoil(ushort startAddress, bool value, byte slaveAddress = 1) |
|
|
|
{ |
|
|
|
master.WriteSingleCoil(slaveAddress, startAddress, value); |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary> |
|
|
|
/// 写入单个寄存器 |
|
|
|
/// </summary> |
|
|
|
/// <param name="startAddress"></param> |
|
|
|
/// <param name="value"></param> |
|
|
|
/// <param name="slaveAddress"></param> |
|
|
|
public void WriteSingleRegister(ushort startAddress, ushort value, byte slaveAddress = 1) |
|
|
|
{ |
|
|
|
master.WriteSingleRegister(slaveAddress, startAddress, value); |
|
|
|
} |
|
|
|
#endregion |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public enum ReadType |
|
|
|
{ |
|
|
|
/// <summary> |
|
|
|
/// 读线圈 |
|
|
|
/// </summary> |
|
|
|
Coils, |
|
|
|
/// <summary> |
|
|
|
/// 读输入线圈 |
|
|
|
/// </summary> |
|
|
|
Inputs, |
|
|
|
/// <summary> |
|
|
|
/// 读保持寄存器 |
|
|
|
/// </summary> |
|
|
|
HoldingRegisters, |
|
|
|
/// <summary> |
|
|
|
/// 读输入寄存器 |
|
|
|
/// </summary> |
|
|
|
InputRegisters, |
|
|
|
} |
|
|
|
|
|
|
|
public enum WriteType |
|
|
|
{ |
|
|
|
/// <summary> |
|
|
|
/// 写线圈 |
|
|
|
/// </summary> |
|
|
|
Coils, |
|
|
|
/// <summary> |
|
|
|
/// 写保持寄存器 |
|
|
|
/// </summary> |
|
|
|
HoldingRegisters, |
|
|
|
} |
|
|
|
|
|
|
|
} |