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 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(string address, ushort len = 1, byte slaveAddress = 1)
{
if (address == null || tcpClient == null) return default(object);
ushort startAddress = (ushort)GetAddress(address);
CommandType commandType = CommandType.Coils;
try
{
if (address.ToUpper().Contains("M"))
{
commandType = CommandType.Coils;
return master.ReadCoils(slaveAddress, startAddress, len);
}
else if (address.ToUpper().Contains("VW"))
{
commandType = CommandType.HoldingRegisters;
return master.ReadHoldingRegisters(slaveAddress, startAddress, len);
}
else if (address.ToUpper().Contains("I"))
{
commandType = CommandType.Inputs;
return master.ReadInputs(slaveAddress, startAddress, len);
}
}
catch (Exception ex)
{
MessageLog.GetInstance.ShowEx($"读取地址:【{address}:= {startAddress}】,读取类型:【{commandType.ToString()}】出错,{ex.ToString()}");
if (ex.InnerException is SocketException)
{
tcpClient = null;
Connect();
}
}
return default(object);
}
public void Write(string address, T value, byte slaveAddress = 1)
{
if (address == null || tcpClient == null) return;
ushort startAddress = (ushort)GetAddress(address);
CommandType commandType = CommandType.Coils;
try
{
if (address.ToUpper().Contains("M"))
{
commandType = CommandType.Coils;
if (value is bool boolValue)
master.WriteSingleCoil(slaveAddress, startAddress, boolValue);
else if (value is bool[] boolsValue)
master.WriteMultipleCoils(slaveAddress, startAddress, boolsValue);
}
else if (address.ToUpper().Contains("VW"))
{
commandType = CommandType.HoldingRegisters;
if (value is ushort ushortValue)
master.WriteSingleRegister(slaveAddress, startAddress, ushortValue);
else if (value 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);
}
}
}
else if (address.ToUpper().Contains("I"))
{
commandType = CommandType.Inputs;
}
}
catch (Exception ex)
{
MessageLog.GetInstance.ShowEx($"读写入地址:【{address}:= {startAddress}】,写入类型:【{commandType.ToString()}】出错,{ex.ToString()}");
if (ex.InnerException is SocketException)
{
tcpClient = null;
Connect();
}
}
}
//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 CommandType
{
///
/// 线圈操作
///
Coils,
///
/// 输入线圈操作
///
Inputs,
///
/// 保持寄存器操作
///
HoldingRegisters,
///
/// 输入寄存器操作
///
InputRegisters,
}
}