using System;
|
using System.Collections.Generic;
|
using System.Linq;
|
using System.Text;
|
|
namespace IStation.DataDockingSocket
|
{
|
//ModBus RTU标准:
|
static public class ModBusRtuHelper
|
{
|
/// <summary>
|
/// 得到16位的CRC检验码:低位在前[0],高位在后[1]
|
/// </summary>
|
/// <param name="message4PT">注意输入的消息长度要求包含CRC的2位,否则计算出来CRC不正确</param>
|
/// <param name="CRC"></param>
|
public static void GetCRC16(byte[] message, ref byte[] CRC)
|
{
|
//Function expects a modbus message4PT of any length as well as a 2 byte CRC array in which to
|
//return the CRC values:
|
if (CRC == null)
|
CRC = new byte[2];
|
|
ushort CRCFull = 0xFFFF;
|
byte CRCHigh = 0xFF, CRCLow = 0xFF;
|
char CRCLSB;
|
|
for (int i = 0; i < (message.Length) - 2; i++)
|
{
|
CRCFull = (ushort)(CRCFull ^ message[i]);
|
|
for (int j = 0; j < 8; j++)
|
{
|
CRCLSB = (char)(CRCFull & 0x0001);
|
CRCFull = (ushort)((CRCFull >> 1) & 0x7FFF);
|
|
if (CRCLSB == 1)
|
CRCFull = (ushort)(CRCFull ^ 0xA001);
|
}
|
}
|
CRC[1] = CRCHigh = (byte)((CRCFull >> 8) & 0xFF);
|
CRC[0] = CRCLow = (byte)(CRCFull & 0xFF);
|
}
|
|
//
|
// 摘要:
|
// 构建查询消息
|
//
|
// 参数:
|
// address设备地址,注意是byte格式,最大255
|
// func功能码
|
// startRegister 寄存器开始地址(用十进制的地址)
|
// numRegister 寄存器数量
|
//
|
// 返回结果
|
// 消息List类型,不成功返回NULL
|
public static void BuildSendMessage(byte address, byte func, ushort start, ushort registers, ref byte[] message)
|
{
|
//构建消息 message数据长度要求包含最后2位的校验码
|
message = new byte[8];
|
message[0] = address;
|
message[1] = func;
|
message[2] = (byte)(start >> 8);
|
message[3] = (byte)start;
|
message[4] = (byte)(registers >> 8);
|
message[5] = (byte)registers;
|
|
//计算16位的CRC校验码
|
byte[] CRC = new byte[2];
|
GetCRC16(message, ref CRC);
|
|
//赋值校验码
|
message[message.Length - 2] = CRC[0];
|
message[message.Length - 1] = CRC[1];
|
}
|
|
/// <summary>
|
/// 写入多个
|
/// </summary>
|
/// <param name="address"></param>
|
/// <param name="start"></param>
|
/// <param name="registers"></param>
|
/// <param name="v"></param>
|
/// <param name="message"></param>
|
public static void BuildSendMessage16(byte address, ushort start, ushort registers, float v, ref byte[] message)
|
{
|
byte[] bytes4Float = BitConverter.GetBytes(v);
|
|
// 09-03-08-40-40-00-00-40-40-00-00-EE-57
|
//构建消息 message数据长度要求包含最后2位的校验码
|
message = new byte[12];
|
message[0] = address;
|
message[1] = 0x10;
|
message[2] = (byte)(start >> 8);
|
message[3] = (byte)start;
|
message[4] = (byte)(registers >> 8);
|
message[5] = (byte)registers;
|
message[6] = (byte)04;//2个就*2
|
message[7] = bytes4Float[3];//要倒过来 0x40;
|
message[8] = bytes4Float[2];//要倒过来0x80;
|
message[9] = bytes4Float[1];//要倒过来0x00;
|
message[10] = bytes4Float[0];//要倒过来0x00;
|
|
//计算16位的CRC校验码
|
byte[] CRC = new byte[2];
|
GetCRC16(message, ref CRC);
|
|
//赋值校验码
|
message[message.Length - 2] = CRC[0];
|
message[message.Length - 1] = CRC[1];
|
}
|
|
/// <summary>
|
/// 写入单个
|
/// </summary>
|
/// <param name="address"></param>
|
/// <param name="start"></param>
|
/// <param name="registers"></param>
|
/// <param name="v"></param>
|
/// <param name="message"></param>
|
public static void BuildSendMessage06(byte address, ushort start, ushort registers, int v, ref byte[] message)
|
{
|
byte[] bytes4Value = BitConverter.GetBytes(v);
|
|
//构建消息 message数据长度要求包含最后2位的校验码
|
message = new byte[8];
|
message[0] = address;
|
message[1] = 0x06;
|
message[2] = (byte)(start >> 8);
|
message[3] = (byte)start;
|
|
message[4] = bytes4Value[1];//要倒过来0x00;
|
message[5] = bytes4Value[0];//要倒过来0x00;
|
|
//计算16位的CRC校验码
|
byte[] CRC = new byte[2];
|
GetCRC16(message, ref CRC);
|
|
//赋值校验码
|
message[message.Length - 2] = CRC[0];
|
message[message.Length - 1] = CRC[1];
|
}
|
|
/**
|
* 将int数值转换为占四个字节的byte数组,本方法适用于(低位在前,高位在后)的顺序。 和bytesToInt()配套使用
|
* @param value
|
* 要转换的int值
|
* @return byte数组
|
*/
|
public static byte[] intToBytes(int value)
|
{
|
byte[] src = new byte[2];
|
|
src[1] = (byte)((value >> 8) & 0xFF);
|
src[0] = (byte)(value & 0xFF);
|
return src;
|
}
|
/**
|
* 将int数值转换为占四个字节的byte数组,本方法适用于(高位在前,低位在后)的顺序。 和bytesToInt2()配套使用
|
*/
|
public static byte[] intToBytes2(int value)
|
{
|
byte[] src = new byte[2];
|
|
src[2] = (byte)((value >> 8) & 0xFF);
|
src[3] = (byte)(value & 0xFF);
|
return src;
|
}
|
/// <summary>
|
///
|
/// </summary>
|
/// <param name="address"></param>
|
/// <param name="func"></param>
|
/// <param name="start"></param>
|
/// <param name="registers"></param>
|
/// <returns></returns>
|
public static byte[] BuildSendMessage(byte address, byte func, ushort start, ushort registers)
|
{
|
byte[] message = null;
|
BuildSendMessage(address, func, start, registers,ref message);
|
return message;
|
}
|
|
/// <summary>
|
/// 得到收到的信息中的数据
|
/// </summary>
|
/// <param name="byteMessage"></param>
|
/// <param name="rValueArray"></param>
|
/// <returns></returns>
|
public static int GetReceivedDatas(byte[] byteMessage, out double[] rValueArray)
|
{
|
rValueArray = null;
|
|
string strMessage = BitConverter.ToString(byteMessage, 0, byteMessage.Length); // byte[] -> 16进制字符串
|
string[] strValueList = strMessage.Split('-');
|
|
int iReadAddress = -1;
|
if (strValueList.Length <= 6)
|
{
|
//!数据没有收完,直接返回
|
return -1;
|
}
|
try
|
{
|
iReadAddress = int.Parse(strValueList[0]); //!获得设备ID
|
|
//int iFunID = int.Parse(strValueList[1]);//!读取功能吗
|
|
int dataNum = int.Parse(strValueList[2]) / 2;//!获得数据长度(除以2就是数据个数)
|
if (dataNum < 1)
|
return -1;
|
|
List<double> rValueList = new List<double>();
|
for (int i = 0; i < dataNum; i++)
|
{
|
string strHigh = strValueList[3 + 2 * i];
|
string strLow = strValueList[3 + 2 * i + 1];
|
|
byte byteHigh = Convert.ToByte(strHigh);
|
byte byteLow = Convert.ToByte(strLow);
|
|
double rValue = byteHigh * 256.0 + byteLow;
|
|
// rValue = rValue * 10000 / Math.Pow(10, GetDecimalPlaces(1));
|
rValueList.Add(rValue);
|
}
|
|
rValueArray = rValueList.ToArray();
|
}
|
catch
|
{
|
return -1;
|
}
|
|
return iReadAddress;
|
}
|
|
//
|
// 摘要:
|
// 检查收到的信息的校验码是否正确
|
//
|
// 参数:
|
// 得到的二进制数据
|
//
|
// 返回结果:
|
// 是否成功
|
public static bool CheckReceivedMessage(byte[] byteMessage)
|
{
|
//计算校验码
|
byte[] CRC = new byte[2];
|
GetCRC16(byteMessage, ref CRC);
|
|
//比较是否和消息中的校验码一致
|
if (CRC[0] == byteMessage[byteMessage.Length - 2] && CRC[1] == byteMessage[byteMessage.Length - 1])
|
return true;
|
else
|
return false;
|
}
|
|
}
|
|
}
|