1

我正在尝试为遥控飞机建造一个简单的地面控制站。我几乎完成了它,但是我在校验和计算方面遇到了很多麻烦。我了解 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。

如果有人能告诉我哪里出错了,我将不胜感激。

感谢您的帮助,卡梅伦

4

1 回答 1

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 中没有无符号数字类型,因此您必须通过使用下一个更大的数字类型而不是ushortandbyte并根据需要屏蔽高位来解决这个问题。您也可以直接删除,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.

于 2012-09-24T02:08:08.093 回答