using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace IStation.DataDockingSocket
{
//ModBus RTU标准:
static public class ModBusRtuHelper
{
///
/// 得到16位的CRC检验码:低位在前[0],高位在后[1]
///
/// 注意输入的消息长度要求包含CRC的2位,否则计算出来CRC不正确
///
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];
}
///
/// 写入多个
///
///
///
///
///
///
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];
}
///
/// 写入单个
///
///
///
///
///
///
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;
}
///
///
///
///
///
///
///
///
public static byte[] BuildSendMessage(byte address, byte func, ushort start, ushort registers)
{
byte[] message = null;
BuildSendMessage(address, func, start, registers,ref message);
return message;
}
///
/// 得到收到的信息中的数据
///
///
///
///
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 rValueList = new List();
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;
}
}
}