Я пытаюсь написать интерпретатор NRPE для платы Netduino. Это плата типа Arduino, работающая под управлением .NET Micro Framework 4.3. У меня возникли проблемы с вычислением CRC, который требует протокол, который выглядит так (фрагмент исходного файла заголовка C++):
typedef struct packet_struct {
int16_t packet_version;
int16_t packet_type;
uint32_t crc32_value;
int16_t result_code;
char buffer[1024];
} packet;
Определенно есть проблемы с порядком байтов, потому что я перехожу от прямого порядка байтов (сеть) к прямому порядку байтов (Netduino/.Net). Я пытался быть осторожным, чтобы реверсировать и реверсировать Int16 и Uint32, когда они входят и выходят из моей структуры. Когда я повторно вывожу пакет, который я прочитал из сети, он идентичен, поэтому я считаю, что многое обрабатывается правильно. Но CRC, который я вычисляю для него, не является. Я вызываю процедуру Utility.ComputeCRC из платформы Micro
У других были аналогичные проблемы в этой области, поэтому мне повезло, что я имею некоторые подсказки, в чем может быть проблема:
Запись Stack Overflow о CRC-записях NRPE в Python
Например, кажется очевидным, что исходное сообщение составляет 1034 байта, дополненное до 1036. Мне не так повезло, так это то, что я нахожусь в ограниченной среде Micro, и весь пример кода для CRC, который я могу найти, обычно включает шаблоны, Linq или другие библиотеки, к которым у меня нет доступа.
Вся помощь приветствуется. Вот пример кода, в котором я безуспешно пытаюсь повторно вычислить CRC из существующего допустимого пакета.
Вывод кода:
Original 1036 bytes: 0002000174D13FD5426E5F4E5250455F434845434B0000000000000000...
Original CRC: 3FD574D1
1036 bytes with zeroed out checksum: 0002000100000000426E5F4E5250455F434845434B00000000000000....
Re-computed checksum (0xFFFF seed): F5B1C55A
Фактический код:
using System;
using System.Text;
// .NET Micro Framework 4.3
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
namespace TestApp
{
public class Program
{
/// <summary>
/// These are the bytes as-received from the wire, hex encoded for readability here.
/// </summary>
private const string OriginalNetworkBytes = "0002000174D13FD5426E5F4E5250455F434845434B00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000";
/// <summary>
/// Index the CRC starts at in the original message
/// </summary>
private const int CrcIndex = 4;
public static void Main()
{
byte[] bufferBytes = StringToByteArrayFastest(OriginalNetworkBytes);
PrintBytesInHex("Original " + bufferBytes.Length + " bytes: ", bufferBytes);
UInt32 originalCrc = ParseSwappedUInt32(bufferBytes, CrcIndex);
Debug.Print("Original CRC: " + originalCrc.ToString("X"));
// Zero out CRC, then attempt to recompute the CRC
ZeroOutChecksum(bufferBytes);
PrintBytesInHex(bufferBytes.Length + " bytes with zeroed out checksum: ", bufferBytes);
uint computedCrc = Utility.ComputeCRC(bufferBytes, 0, bufferBytes.Length, 0xFFFF);
Debug.Print("Re-computed checksum (0xFFFF seed): " + computedCrc.ToString("X"));
}
/// <summary>
/// From this fine Stack Overflow post:
/// https://stackoverflow.com/questions/321370/convert-hex-string-to-byte-array
/// Because as the author points out, "also works on .NET Micro Framework where (in SDK4.3) byte.Parse(string) only
/// permits integer formats."
/// </summary>
/// <param name="hex"></param>
/// <returns></returns>
public static byte[] StringToByteArrayFastest(string hex)
{
if (hex.Length%2 == 1)
throw new Exception("The binary key cannot have an odd number of digits");
var arr = new byte[hex.Length >> 1];
for (int i = 0; i < hex.Length >> 1; ++i)
{
arr[i] = (byte) ((GetHexVal(hex[i << 1]) << 4) + (GetHexVal(hex[(i << 1) + 1])));
}
return arr;
}
public static int GetHexVal(char hex)
{
int val = hex;
//For uppercase A-F letters:
return val - (val < 58 ? 48 : 55);
//For lowercase a-f letters:
//return val - (val < 58 ? 48 : 87);
//Or the two combined, but a bit slower:
//return val - (val < 58 ? 48 : (val < 97 ? 55 : 87));
}
public static UInt32 ParseSwappedUInt32(byte[] byteArray, int arrayIndex)
{
byte[] swappedBytes = ByteSwapper(byteArray, arrayIndex, 4);
return BitConverter.ToUInt32(swappedBytes, 0);
}
public static byte[] ByteSwapper(byte[] array, int incomingArrayIndex, int countOfBytesToSwap)
{
if (countOfBytesToSwap%2 != 0)
{
throw new Exception("Bytes to be swapped must be divisible by 2; you requested " + countOfBytesToSwap);
}
int outgoingArrayIndex = 0;
byte lastByte = 0;
var arrayToReturn = new byte[countOfBytesToSwap];
int finalArrayIndex = incomingArrayIndex + countOfBytesToSwap;
for (int arrayIndex = incomingArrayIndex; arrayIndex < finalArrayIndex; arrayIndex++)
{
bool isEvenIndex = arrayIndex%2 == 0 || arrayIndex == 0;
byte currentByte = array[arrayIndex];
if (isEvenIndex)
{
// Store current byte for next pass through
lastByte = currentByte;
}
else
{
// Swap two bytes, put into outgoing array
arrayToReturn[outgoingArrayIndex] = currentByte;
arrayToReturn[outgoingArrayIndex + 1] = lastByte;
outgoingArrayIndex += 2;
}
}
return arrayToReturn;
}
private static void ZeroOutChecksum(byte[] messageBytesToClear)
{
messageBytesToClear[CrcIndex] = 0;
messageBytesToClear[CrcIndex + 1] = 0;
messageBytesToClear[CrcIndex + 2] = 0;
messageBytesToClear[CrcIndex + 3] = 0;
}
/// <summary>
/// Debug function to output the message as a hex string
/// </summary>
public static void PrintBytesInHex(string messageLabel, byte[] messageBytes)
{
string hexString = BytesToHexString(messageBytes);
Debug.Print(messageLabel + hexString);
}
private static string BytesToHexString(byte[] messageBytes)
{
var sb = new StringBuilder();
foreach (byte b in messageBytes)
{
sb.Append(b.ToString("X2"));
}
string hexString = sb.ToString();
return hexString;
}
}
}