using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Wit.SDK.Modular.Sensor.Utils
{
///
/// Modbus16工具类
///
public class Modbus16Utils
{
///
/// 获得CRC16_Modbus效验,低位在前,高位在后
///
/// 要进行计算的字节数组
/// 计算后的数组
public static byte[] GetCrc16(byte[] bytes)
{
byte crcRegister_H = 0xFF, crcRegister_L = 0xFF;// 预置一个值为 0xFFFF 的 16 位寄存器
byte polynomialCode_H = 0xA0, polynomialCode_L = 0x01;// 多项式码 0xA001
for (int i = 0; i < bytes.Length; i++)
{
crcRegister_L = (byte)(crcRegister_L ^ bytes[i]);
for (int j = 0; j < 8; j++)
{
byte tempCRC_H = crcRegister_H;
byte tempCRC_L = crcRegister_L;
crcRegister_H = (byte)(crcRegister_H >> 1);
crcRegister_L = (byte)(crcRegister_L >> 1);
// 高位右移前最后 1 位应该是低位右移后的第 1 位:如果高位最后一位为 1 则低位右移后前面补 1
if ((tempCRC_H & 0x01) == 0x01)
{
crcRegister_L = (byte)(crcRegister_L | 0x80);
}
if ((tempCRC_L & 0x01) == 0x01)
{
crcRegister_H = (byte)(crcRegister_H ^ polynomialCode_H);
crcRegister_L = (byte)(crcRegister_L ^ polynomialCode_L);
}
}
}
return new byte[] { crcRegister_L, crcRegister_H };
}
///
/// 获得CRC16_Modbus效验,低位在前,高位在后
///
/// 要进行计算的字节数组
/// 长度
/// 计算后的数组
public static byte[] GetCrc16(byte[] byteData, int length)
{
byte[] CRC = new byte[2];
ushort wCrc = 0xFFFF;
for (int i = 0; i < length; i++)
{
wCrc ^= Convert.ToUInt16(byteData[i]);
for (int j = 0; j < 8; j++)
{
if ((wCrc & 0x0001) == 1)
{
wCrc >>= 1;
wCrc ^= 0xA001;//异或多项式
}
else
{
wCrc >>= 1;
}
}
}
CRC[1] = (byte)((wCrc & 0xFF00) >> 8);//高位在后
CRC[0] = (byte)(wCrc & 0x00FF); //低位在前
return CRC;
}
///
/// 获得写入的modbus指令
///
///
///
///
///
/// 成功返回0
public static int GetWrite(byte addr, int reg, int value, out byte[] resultBytes)
{
byte[] reghl = GetHL(reg);
byte[] valuehl = GetHL(value);
resultBytes = new byte[] { addr, 0x06, reghl[0], reghl[1], valuehl[0], valuehl[1] };
resultBytes = resultBytes.Concat(GetCrc16(resultBytes)).ToArray();
return 0;
}
///
/// 写入的modbus指令
///
///
///
///
///
public static byte[] GetWrite(byte addr, int reg, int value)
{
byte[] resultBytes = null;
GetWrite(addr, reg, value, out resultBytes);
return resultBytes;
}
///
/// 读取的modbus指令
///
///
///
///
///
/// 成功返回0
public static int GetRead(byte addr, int reg, int count, out byte[] resultBytes)
{
byte[] reghl = GetHL(reg);
byte[] counthl = GetHL(count);
resultBytes = new byte[] { addr, 0x03, reghl[0], reghl[1], counthl[0], counthl[1] };
resultBytes = resultBytes.Concat(GetCrc16(resultBytes)).ToArray();
return 0;
}
///
/// 读取的modbus指令
///
///
///
///
///
public static byte[] GetRead(byte addr, int reg, int count)
{
byte[] resultBytes = null;
GetRead(addr,reg,count, out resultBytes);
return resultBytes;
}
///
/// 获得高低位,高位在前
///
///
///
public static byte[] GetHL(int value)
{
return new byte[] { (byte)(value >> 8), (byte)(value << 8 >> 8) };
}
///
/// 获得高低位,低位在前
///
///
///
public static byte[] GetLH(int value)
{
return new byte[] { (byte)(value << 8 >> 8), (byte)(value >> 8) };
}
///
/// 检查校验位
///
///
///
public static bool CheckModbusCrc16(byte[] data)
{
if (data == null)
{
return false;
}
if (data.Length < 3)
{
return false;
}
byte[] v = GetCrc16(data, data.Length - 2);
if (v.Length < 2)
{
return false;
}
if (v[0] != data[data.Length - 2])
{
return false;
}
if (v[1] != data[data.Length - 1])
{
return false;
}
return true;
}
///
/// 查询返回的字节里有没有发送的命令的回传
///
///
///
///
/// 查找成功返回true,查找失败返回false
public static bool FindModbus(byte[] sendByte, byte[] returnByte, out byte[] modbus)
{
int height = sendByte[4];
int low = sendByte[5];
// 得到长度
int len = 5 + (height << 8 | low) * 2;
// 如果没有返回结果,或者返回结果根本不够长
if (returnByte == null || returnByte.Length < len)
{
modbus = new byte[0];
return false;
}
// 遍历返回结果查找
for (int i = 0; i <= returnByte.Length - len; i++)
{
byte rAddr = returnByte[i];
byte mark = 0x03;
byte[] cCrc = GetCrc16(returnByte.Skip(i).Take(len - 2).ToArray());
byte rCrcH = returnByte[i + len - 2];
byte rCrcL = returnByte[i + len - 1];
// 如果全部通过
if (sendByte[0] == rAddr && mark == sendByte[1] && rCrcH == cCrc[0] && rCrcL == cCrc[1])
{
modbus = returnByte.Skip(i).Take(len).ToArray();
return true;
}
}
modbus = new byte[0];
return false;
}
}
}