我正在尝试为遥控飞机建造一个简单的地面控制站。我差不多完成了它,但是我在校验和计算方面遇到了很多麻烦。据我所知,Java和C#的数据类型不同。我试图解释这个,但我不确定我是否成功了。该程序使用CRC-16-CCITT方法。
这是我的端口:
public int crc_accumulate(int b, int crc) {
int ch = (b ^ (crc & 0x00ff));
ch = (ch ^ (ch << 4));
return ((crc >> 8) ^ (ch << 8) ^ (ch << 3) ^ (ch >> 4));
}
public byte[] crc_calculate() {
int[] pBuffer=new int[]{255,9,19,1,1,0,0,0,0,0,2,3,81,4,3};
int crcEx=0;
int clength=pBuffer.length;
int[] X25_INIT_CRC=new int[]{255,255};
byte[] crcTmp=new byte[]{(byte)255,(byte)255};
int crcTmp2 = ((crcTmp[0] & 0xff) << 8) | (crcTmp[1] & 0xff);
crcTmp[0]=(byte)crcTmp2;
crcTmp[1]=(byte)(crcTmp2 >> 8);
System.out.println("pre-calculation: 0x"+Integer.toHexString((crcTmp[0]&0xff))+" 0x"+Integer.toHexString((crcTmp[1]&0xff))+"; ushort: "+crcTmp2);
if (clength < 1) {
System.out.println("clength < 1");
return crcTmp;
}
for (int i=1; i<clength; i++) {
crcTmp2 = crc_accumulate(pBuffer[i], crcTmp2);
}
crcTmp[0]=(byte)crcTmp2;
crcTmp[1]=(byte)(crcTmp2 >> 8);
System.out.print("crc calculation: 0x"+Integer.toHexString((crcTmp[0]&0xff))+" 0x"+Integer.toHexString((crcTmp[1]&0xff))+"; ushort: "+crcTmp2);
if (crcEx!=-1) {
System.out.println(" extraCRC["+crcEx+"]="+extraCRC[crcEx]);
crcTmp2=crc_accumulate(extraCRC[crcEx], crcTmp2);
crcTmp[0]=(byte)crcTmp2;
crcTmp[1]=(byte)(crcTmp2 >> 8);
System.out.println("with extra CRC: 0x"+Integer.toHexString((crcTmp[0]&0xff))+" 0x"+Integer.toHexString((crcTmp[1]&0xff))+"; ushort: "+crcTmp2+"\n\n");
}
return crcTmp;
}
这是原始的C#文件:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ArdupilotMega
{
class MavlinkCRC
{
const int X25_INIT_CRC = 0xffff;
const int X25_VALIDATE_CRC = 0xf0b8;
public static ushort crc_accumulate(byte b, ushort crc)
{
unchecked
{
byte ch = (byte)(b ^ (byte)(crc & 0x00ff));
ch = (byte)(ch ^ (ch << 4));
return (ushort)((crc >> 8) ^ (ch << 8) ^ (ch << 3) ^ (ch >> 4));
}
}
public static ushort crc_calculate(byte[] pBuffer, int length)
{
if (length < 1)
{
return 0xffff;
}
// For a "message" of length bytes contained in the unsigned char array
// pointed to by pBuffer, calculate the CRC
// crcCalculate(unsigned char* pBuffer, int length, unsigned short* checkConst) < not needed
ushort crcTmp;
int i;
crcTmp = X25_INIT_CRC;
for (i = 1; i < length; i++) // skips header U
{
crcTmp = crc_accumulate(pBuffer[i], crcTmp);
//Console.WriteLine(crcTmp + " " + pBuffer[i] + " " + length);
}
return (crcTmp);
}
}
}
我很确定我的端口中的问题位于第1行和第5行之间。我希望得到输出0x94 0x88,但程序输出0x2D 0xF4。
如果有人能告诉我出错的地方,我将不胜感激。
感谢您的帮助, 卡梅伦
答案 0 :(得分:2)
好吧,首先让我们清理C#代码:
const int X25_INIT_CRC = 0xffff;
public static ushort crc_accumulate(byte b, ushort crc)
{
unchecked
{
byte ch = (byte)(b ^ (byte)(crc & 0x00ff));
ch = (byte)(ch ^ (ch << 4));
return (ushort)((crc >> 8) ^ (ch << 8) ^ (ch << 3) ^ (ch >> 4));
}
}
public static ushort crc_calculate(byte[] pBuffer)
{
ushort crcTmp = X25_INIT_CRC;
for (int i = 1; i < pBuffer.Length; i++) // skips header U
crcTmp = crc_accumulate(pBuffer[i], crcTmp);
return crcTmp;
}
现在最大的问题是Java中没有未签名的数字类型,因此您必须使用下一个更大的数字类型而不是ushort
和byte
来解决这个问题。根据需要高位。您也可以删除unchecked
,因为Java无论如何都没有溢出检查。最终结果是这样的:
public static final int X25_INIT_CRC = 0xffff;
public static int crc_accumulate(short b, int crc) {
short ch = (short)((b ^ crc) & 0xff);
ch = (short)((ch ^ (ch << 4)) & 0xff);
return ((crc >> 8) ^ (ch << 8) ^ (ch << 3) ^ (ch >> 4)) & 0xffff;
}
public static int crc_calculate(short[] pBuffer) {
int crcTmp = X25_INIT_CRC;
for (int i = 1; i < pBuffer.length; i++) // skips header U
crcTmp = crc_accumulate(pBuffer[i], crcTmp);
return crcTmp;
}
对于问题中的输入({ 255, 9, 19, 1, 1, 0, 0, 0, 0, 0, 2, 3, 81, 4, 3 }
)原始C#,清理C#和Java都会生成0xfc7e
。