You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

353 lines
13 KiB
C#

2 years ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net.Sockets;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Web.Configuration;
namespace Rs.Framework
{
public class ModbusTcp
{
Socket m_socket;
string m_ip;
int m_port;
bool isConnected = false;
int timeout = 2000;
Stopwatch stopWatch = new Stopwatch();
public ModbusTcp(string ip, int port)
{
m_ip = ip;
m_port = port;
m_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
}
public string GetIp()
{
return m_ip;
}
public bool Connect()
{
try
{
IPEndPoint ipaddr = new IPEndPoint(IPAddress.Parse(m_ip), m_port);
m_socket.Connect(ipaddr);
isConnected = true;
return true;
}
catch (Exception)
{
return false;
}
}
/// <summary>
/// 获取读取报文
/// </summary>
/// <param name="deviceID"></param>
/// <param name="funCode"></param>
/// <param name="startAddr"></param>
/// <param name="readLen"></param>
/// <returns></returns>
public byte[] GetReadCommand(int deviceID, FunCode funCode, int startAddr, int readLen)
{
List<byte> readData = new List<byte>();
//添加通信标识
readData.Add(0x00);
readData.Add(0x00);
//添加协议标识
readData.Add(0x00);
readData.Add(0x00);
//报文长度读取报文的长度是固定的6个字节
readData.Add(0x00);
readData.Add(0x06);
//添加设备编号
readData.Add((byte)deviceID);
//添加功能码
readData.Add((byte)funCode);
//添加读取地址
readData.Add((byte)(startAddr >> 8));
readData.Add((byte)startAddr);
//添加读取长度
readData.Add((byte)(readLen >> 8));
readData.Add((byte)readLen);
return readData.ToArray();
}
private byte[] GetWriteCommand(int deviceID, FunCode funCode, int startAddr, byte[] writeData, int datalen = 0)
{
List<byte> readData = new List<byte>();
//添加通信标识
readData.Add(0x00);
readData.Add(0x00);
//添加协议标识
readData.Add(0x00);
readData.Add(0x00);
//计算后面报文的长度
if (funCode == FunCode.WriteSingleCoil || funCode == FunCode.WriteSingleRegister)
{
readData.Add(0x00);
readData.Add(0x06);
}
else if (funCode == FunCode.WriteMultiCoil || funCode == FunCode.WriteMultiRegister)
{
int len = 6 + 1 + writeData.Length;
readData.Add((byte)(len >> 8));
readData.Add((byte)len);
}
//添加设备编号
readData.Add((byte)deviceID);
//添加功能码
readData.Add((byte)funCode);
//添加写入地址
readData.Add((byte)(startAddr >> 8));
readData.Add((byte)startAddr);
//添加要写入的线圈的数量
if (funCode == FunCode.WriteMultiCoil || funCode == FunCode.WriteMultiRegister)
{
readData.Add((byte)(datalen >> 8));
readData.Add((byte)datalen);
//添加要写入数据的字节数
readData.Add((byte)writeData.Length);
}
//添加真实要写入的数据
readData.AddRange(writeData);
return readData.ToArray();
}
public ModbusErrorCode ReadUshortArr(int deviceID, FunCode funCode, int startAddr, int readLen, out int[] result)
{
result = new int[readLen];
if (isConnected)
{
List<byte> receiveBuffer = new List<byte>();
byte[] readDatas = GetReadCommand(deviceID, funCode, startAddr, readLen);
try
{
int len = m_socket.Send(readDatas);
if (len > 0)
{
//开始接收数据
stopWatch.Restart();
while (true && stopWatch.ElapsedMilliseconds <= timeout)
{
int receiveDataLen = m_socket.Available;
if (receiveDataLen > 0)
{
byte[] buffer = new byte[receiveDataLen];
len = m_socket.Receive(buffer, receiveDataLen, SocketFlags.None);
if (len > 0)
{
receiveBuffer.AddRange(buffer);
//判断数据是否接收完毕,
if (receiveBuffer.Count >= 6)
{
//读取报文长度
int packetLen = receiveBuffer[4] << 8 | receiveBuffer[5];
if (receiveBuffer.Count == packetLen + 6)
{
int dataLen = receiveBuffer[8];
//代表数据已经接受完毕,开始解析数据
for (int i = 0; i < dataLen / 2; i++)
{
result[i] = receiveBuffer[(i * 2) + 9] << 8 | receiveBuffer[(i * 2) + 10];
}
}
}
return ModbusErrorCode.OK;
}
}
}
if (stopWatch.ElapsedMilliseconds >= timeout)
{
return ModbusErrorCode.TIMEOUT;
}
}
else
{
return ModbusErrorCode.SENDFAIL;
}
}
catch (Exception ex)
{
return ModbusErrorCode.EXCEPTION;
}
return ModbusErrorCode.OK;
}
else
{
//未连接
return ModbusErrorCode.NOCONNECT;
}
}
public ModbusErrorCode WriteSingleCoil(int deviceID, int startAddr, bool flag)
{
byte[] writeData = new byte[2] { 0x00, 0x00 };
List<byte> receiveBuffer = new List<byte>();
if (flag)
{
writeData[0] = 0xFF;
writeData[1] = 0x00;
}
return Write(deviceID, FunCode.WriteSingleCoil, startAddr, writeData);
}
public ModbusErrorCode WriteCoils(int deviceID, int startAddr, bool[] flags)
{
byte[] writeData = new byte[((flags.Length - 1) / 8) + 1];
int val = 0;
for (int i = 0; i < flags.Length; i++)
{
if (flags[i])
val = val | 1 << i;
else
val = val | 0 << i;
}
for (int i = 0; i < writeData.Length; i++)
{
writeData[i] = (byte)(val >> (i * 8));
}
return Write(deviceID, FunCode.WriteMultiCoil, startAddr, writeData, flags.Length);
}
public ModbusErrorCode WriteSingleRegister(int deviceID, int startAddr, ushort value)
{
byte[] writeData = new byte[2] { 0x00, 0x00 };
List<byte> receiveBuffer = new List<byte>();
writeData[0] = (byte)(value >> 8);
writeData[1] = (byte)value;
return Write(deviceID, FunCode.WriteSingleRegister, startAddr, writeData);
}
public ModbusErrorCode WriteMultiHoldRegister(int deviceID, int startAddr, ushort[] values)
{
byte[] writeData = new byte[values.Length * 2];
for (int i = 0; i < values.Length; i++)
{
writeData[(i * 2)] = (byte)(values[i] >> 8);
writeData[(i * 2) + 1] = (byte)(values[i]);
}
return Write(deviceID, FunCode.WriteMultiRegister, startAddr, writeData, values.Length);
}
private ModbusErrorCode Write(int deviceID, FunCode funCode, int startAddr, byte[] writeData, int writeLen = 0)
{
if (isConnected)
{
lock (this)
{
byte[] readDatas = GetWriteCommand(deviceID, funCode, startAddr, writeData, writeLen);
try
{
List<byte> receiveBuffer = new List<byte>();
int len = m_socket.Send(readDatas);
if (len > 0)
{
//开始接收数据
stopWatch.Restart();
while (true && stopWatch.ElapsedMilliseconds <= timeout)
{
int receiveDataLen = m_socket.Available;
if (receiveDataLen > 0)
{
byte[] buffer = new byte[receiveDataLen];
len = m_socket.Receive(buffer, receiveDataLen, SocketFlags.None);
if (len > 0)
{
receiveBuffer.AddRange(buffer);
if (receiveBuffer.Count >= 6)
{
////判断数据是否接收完毕
int framelen = receiveBuffer[4] << 8 | receiveBuffer[5];
if (framelen + 6 == receiveBuffer.Count)
{
return ModbusErrorCode.OK;
}
}
}
}
}
if (stopWatch.ElapsedMilliseconds >= timeout)
{
return ModbusErrorCode.TIMEOUT;
}
}
else
{
return ModbusErrorCode.SENDFAIL;
}
}
catch (Exception ex)
{
return ModbusErrorCode.EXCEPTION;
}
return ModbusErrorCode.OK;
}
}
else
{
//未连接
return ModbusErrorCode.NOCONNECT;
}
}
}
public enum FunCode
{
/// <summary>
/// 读取 多个线圈(位)
/// </summary>
ReadMultiCoil = 01,
/// <summary>
/// 读取 多个离散量输入量(位)
/// </summary>
ReadMultiInput = 02,
/// <summary>
/// 读取 多个保持寄存器(16进制整型)
/// </summary>
ReadMultiHoldRegister = 03,
/// <summary>
/// 读取 多个输入寄存器(16进制整型)
/// </summary>
ReadMultiInputRegister = 04,
/// <summary>
/// 写入 单个线圈(位)
/// </summary>
WriteSingleCoil = 05,
/// <summary>
/// 写入 单个寄存器(16进制整型)
/// </summary>
WriteSingleRegister = 06,
/// <summary>
/// 写入 多个线圈(位)
/// </summary>
WriteMultiCoil = 15,
/// <summary>
/// 写入 多个寄存器(16进制整型)
/// </summary>
WriteMultiRegister = 16
}
public enum ModbusErrorCode
{
OK,
NOCONNECT,
SENDFAIL,
EXCEPTION,
TIMEOUT
}
}