我想解码从modbus通信接收的字节数组。这是表示字节数组的十六进制字符串:
01 11 0C 46 57 35 32 39 37 30 31 52 30 2E 35 FE 27
我想分成3部分:
为了从字节转换为十六进制,我使用以下方法:
#region ByteToHex
/// <summary>
/// method to convert a byte array into a hex string
/// </summary>
/// <param name="comByte">byte array to convert</param>
/// <returns>a hex string</returns>
public string ByteToHex(byte[] comByte)
{
//create a new StringBuilder object
StringBuilder builder = new StringBuilder(comByte.Length * 3);
//loop through each byte in the array
foreach (byte data in comByte)
//convert the byte to a string and add to the stringbuilder
builder.Append(Convert.ToString(data, 16).PadLeft(2, '0').PadRight(3, ' '));
//return the converted value
return builder.ToString().ToUpper();
}
如何从该方法拆分返回的字符串以返回: 前3个字节是:
接下来的N个字节(见3.)是有效载荷;最后2个是CRC16。
我需要找到有效载荷;它是一个字符串。
答案 0 :(得分:3)
部分答案:
如果字节返回表示结构化数据,则不将所有字节转换为字符串。而是根据其含义转换字节:
int serverId = Convert.ToInt32(byte[0]);
int functionCode = Convert.ToInt32(byte[1]);
int byteCount = Convert.ToInt32(byte[2]);
只要知道数据部分的长度,就可以解码这些数据:
for(int i = 0; i < byteCount; i++)
{
// do something with byte[3+i]
}
答案 1 :(得分:3)
将输入转换为十六进制字符串毫无意义。您需要解码字节保存的信息。他们所持有的东西完全取决于您只是转述的文档。我会小心翼翼地说:
public class ModbusRequest
{
public byte ServerId { get; set; }
public byte FunctionCode { get; set; }
public string Payload { get; set; }
}
public ModbusRequest DecodeMessage(byte[] message)
{
var result = new ModbusRequest();
// Simply copy bytes 0 and 1 into the destination structure.
result.ServerId = message[0];
result.FunctionCode = message[1];
byte stringLength = message[2];
// Assuming ASCII encoding, see docs.
result.Payload = Encoding.ASCII.GetString(message, 3, stringLength);
// Get the CRC bytes.
byte[] crc = new byte[2];
Buffer.BlockCopy(message, 4 + stringLength, crc, 0, 2);
// TODO: verify CRC.
return result;
}
要验证CRC,请找出正在使用的格式。我建议使用classless-hasher来实现各种CRC变体。
答案 2 :(得分:0)
string str = ByteToHex(comByte);
string partOne = str.Substring(0, 8);
string partTwo = str.Substring(9, 35);
string partThree = str.Substring(45, 5);
答案 3 :(得分:0)
首先更改现有ByteToHex
方法的签名,使输入参数为IEnumerable<byte>
而不是byte[]
。
然后使用:
var str1 = ByteToHex(new ArraySegment<byte>(yourBytes, 0, 3));
var str2 = ByteToHex(new ArraySegment<byte>(yourBytes, 3, 12));
var str3 = ByteToHex(new ArraySegment<byte>(yourBytes, 15, 2));
从.NET 4.5(Visual Studio 2012)开始,可以使用ArraySegment<>
。
PS!该方法的整个主体可以简化:
public static string ByteToHex(IEnumerable<byte> comByte)
{
return string.Join(" ", comByte.Select(b => b.ToString("X2")));
}
此处首都X
表示带有大写&#34;数字&#34;的十六进制格式A到F,2
表示填充零,长度为2。
答案 4 :(得分:0)
如果要拆分字节数组,则直接在数组上执行 - 不要事先转换为字符串!生成的代码将更容易理解。
之后,您仍然可以将部分内容转换为十六进制字符串,或者在您的情况下转换为带编码的文本字符串,而不是十六进制。
对于Subarrays,我有这个小扩展:
// Returns the SubArray starting from index and covering the amount of length items.
public static T[] SubArray<T>(this T[] data, int index, int length)
{
T[] result = new T[length];
System.Array.Copy(data, index, result, 0, length);
return result;
}
正如在另一个答案中提到的那样,从.NET 4.5开始,您也可以使用新的ArraySegment。
有了这个,您可以简单地拆分:
const int HEADER_LENGTH = 3; //1 Byte ServerId, 1 Byte Function Code, 1 Byte ByteCount
const int CRC_LENGTH = 2;
var bytes = new byte[]{0x01, 0x11, 0x0C, 0x46, 0x57, 0x35, 0x32, 0x39, 0x37, 0x30, 0x31, 0x52, 0x30, 0x2E, 0x35, 0xFE, 0x27};
int payloadLength = bytes.Count() - HEADER_LENGTH - CRC_LENGTH;
//.NET 4.5 solution
var textbytes = new ArraySegment<byte>(bytes, HEADER_LENGTH, payloadLength).ToArray();
//pre 4.5 solution with extension
var textbytes = bytes.SubArray(HEADER_LENGTH, payloadLength);
var text = Encoding.ASCII.GetString(textbytes); //FW529701R0.5