using BPASmartClient.Message;
using NModbus;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;
namespace BPASmartClient.Modbus
{
public class ModbusTcp
{
//private volatile static ModbusTcp _Instance;
//public static ModbusTcp GetInstance => _Instance ?? (_Instance = new ModbusTcp());
//private ModbusTcp() { }
private ModbusFactory modbusFactory;
private IModbusMaster master;
private TcpClient tcpClient;
private string IPAdress;
private int Port;
//public Action ConnectOk { get; set; }
///
/// 判断是否连接成功
///
public bool Connected => tcpClient == null ? false : tcpClient.Connected;
///
/// ModbusTcp 连接设备
///
/// ip 地址
/// 端口号,默认502
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;//重试次数
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 连接成功!");
}
///
/// 获取 M 区 和 VW 区的Modbus的地址
///
///
///
public int GetAddress(string address)
{
if (address == null) return -1;
if (address.Length > 0)
{
if (address.ToUpper().Contains("M") && 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;
}
}
}
}
else if (address.ToUpper().Contains("VW") && address.Length >= 3)
{
var res = address.Substring(2);
if (res != null && int.TryParse(res, out int tempAddress))
{
return (tempAddress / 2) + 100;
}
}
}
return -1;
}
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 action)
{
object result;
result = Read(startAddress, CommandType.Coils, len);
if (result != null)
{
if (result is bool[] bools)
{
if (bools.Length == len)
{
action(bools);
}
}
else if (result is bool bl)
{
List boolLists = new List();
boolLists.Add(bl);
action(boolLists.ToArray());
}
}
}
public object Read(ushort startAddress, CommandType 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 CommandType.Coils:
result = master.ReadCoils(slaveAddress, startAddress, num);
break;
case CommandType.Inputs:
result = master.ReadInputs(slaveAddress, startAddress, num);
break;
case CommandType.HoldingRegisters:
result = master.ReadHoldingRegisters(slaveAddress, startAddress, num);
break;
case CommandType.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($"读取地址:【{startAddress}】,读取类型:【{readType}】出错,{ex.ToString()}");
if (ex.InnerException is SocketException)
{
tcpClient = null;
Connect();
}
}
return result;
}
public bool Write(ushort startAddress, CommandType 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 CommandType.Coils:
if (InputValue is bool boolValue)
master.WriteSingleCoil(slaveAddress, startAddress, boolValue);
if (InputValue is bool[] boolsValue)
master.WriteMultipleCoils(slaveAddress, startAddress, boolsValue);
break;
case CommandType.HoldingRegisters:
if (InputValue is ushort ushortValue)
master.WriteSingleRegister(slaveAddress, startAddress, ushortValue);
if (InputValue is ushort[] ushortsValue)
{
int len = 100;
if (ushortsValue.Length > len)
{
List ushortLists = new List();
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 批量数据读取
///
/// 读取多个线圈
///
///
///
///
///
public bool[] ReadCoils(ushort startAddress, ushort num, byte slaveAddress = 1)
{
return master.ReadCoils(slaveAddress, startAddress, num);
}
///
/// 读取多个输入线圈
///
///
///
///
///
public bool[] ReadInputs(ushort startAddress, ushort num, byte slaveAddress = 1)
{
return master.ReadInputs(slaveAddress, startAddress, num);
}
///
/// 读取多个保持寄存器
///
///
///
///
///
public ushort[] ReadHoldingRegisters(ushort startAddress, ushort num, byte slaveAddress = 1)
{
return master.ReadHoldingRegisters(slaveAddress, startAddress, num);
}
///
/// 读取多个输入寄存器
///
///
///
///
///
public ushort[] ReadInputRegisters(ushort startAddress, ushort num, byte slaveAddress = 1)
{
return master.ReadInputRegisters(slaveAddress, startAddress, num);
}
#endregion
#region 批量数据写入
///
/// 写入多个线圈
///
///
///
///
public void WriteMultipleCoils(ushort startAddress, bool[] value, byte slaveAddress = 1)
{
master.WriteMultipleCoils(slaveAddress, startAddress, value);
}
///
/// 写入多个寄存器
///
///
///
///
public void WriteMultipleRegisters(ushort startAddress, ushort[] value, byte slaveAddress = 1)
{
master.WriteMultipleRegisters(slaveAddress, startAddress, value);
}
#endregion
#region 单个数据读取
///
/// 读取单个线圈
///
///
///
///
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];
}
///
/// 读取单个输入线圈
///
///
///
///
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];
}
///
/// 读取单个保持寄存器
///
///
///
///
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];
}
///
/// 读取单个输入寄存器
///
///
///
///
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 单个数据写入
///
/// 写入单个线圈
///
///
///
///
public void WriteSingleCoil(ushort startAddress, bool value, byte slaveAddress = 1)
{
master.WriteSingleCoil(slaveAddress, startAddress, value);
}
///
/// 写入单个寄存器
///
///
///
///
public void WriteSingleRegister(ushort startAddress, ushort value, byte slaveAddress = 1)
{
master.WriteSingleRegister(slaveAddress, startAddress, value);
}
#endregion
}
public enum ReadType
{
///
/// 读线圈
///
Coils,
///
/// 读输入线圈
///
Inputs,
///
/// 读保持寄存器
///
HoldingRegisters,
///
/// 读输入寄存器
///
InputRegisters,
}
public enum WriteType
{
///
/// 写线圈
///
Coils,
///
/// 写保持寄存器
///
HoldingRegisters,
}
public enum CommandType
{
///
/// 线圈操作
///
Coils,
///
/// 输入线圈操作
///
Inputs,
///
/// 保持寄存器操作
///
HoldingRegisters,
///
/// 输入寄存器操作
///
InputRegisters,
}
}