在 Java 中计算 CRC8-Maxim 校验和

Calculate CRC8-Maxim checksum in Java

我正在尝试在 java 中编写一个 CRC8-Maxim 计算器,但我被卡住了。我已经尝试了很多 API,比如 Jacksum,但没有一个像它应该的那样工作。 我唯一找到的是这个网站:http://www.sunshine2k.de/coding/javascript/crc/crc_js.html

如果我选择 CRC8-Maxim 设置,结果正是我需要的。 (例子:VR1,?,的校验和应该是D7)

您知道我如何在 java 中编写代码吗? 我的期末学校项目需要它,时间不多了。

提前致谢! 本尼迪克特

[编辑] 我用这段代码试过了。它与网站上的计算器具有相同的查找 table 和相同的多项式。

import java.io.UnsupportedEncodingException;

public final class Crc8 {

private static final short CRC8_POLYNOMIAL = 0x31;
private static final short CRC8_INIT_VALUE = 0x0;
private static final short[] CRC8_LOOKUP_TABLE = {
    0x00, 0x31, 0x62, 0x53, 0xC4, 0xF5, 0xA6, 0x97, 0xB9, 0x88, 0xDB, 0xEA, 0x7D, 0x4C, 0x1F, 0x2E,
    0x43, 0x72, 0x21, 0x10, 0x87, 0xB6, 0xE5, 0xD4, 0xFA, 0xCB, 0x98, 0xA9, 0x3E, 0x0F, 0x5C, 0x6D,
    0x86, 0xB7, 0xE4, 0xD5, 0x42, 0x73, 0x20, 0x11, 0x3F, 0x0E, 0x5D, 0x6C, 0xFB, 0xCA, 0x99, 0xA8,
    0xC5, 0xF4, 0xA7, 0x96, 0x01, 0x30, 0x63, 0x52, 0x7C, 0x4D, 0x1E, 0x2F, 0xB8, 0x89, 0xDA, 0xEB,
    0x3D, 0x0C, 0x5F, 0x6E, 0xF9, 0xC8, 0x9B, 0xAA, 0x84, 0xB5, 0xE6, 0xD7, 0x40, 0x71, 0x22, 0x13,
    0x7E, 0x4F, 0x1C, 0x2D, 0xBA, 0x8B, 0xD8, 0xE9, 0xC7, 0xF6, 0xA5, 0x94, 0x03, 0x32, 0x61, 0x50,
    0xBB, 0x8A, 0xD9, 0xE8, 0x7F, 0x4E, 0x1D, 0x2C, 0x02, 0x33, 0x60, 0x51, 0xC6, 0xF7, 0xA4, 0x95,
    0xF8, 0xC9, 0x9A, 0xAB, 0x3C, 0x0D, 0x5E, 0x6F, 0x41, 0x70, 0x23, 0x12, 0x85, 0xB4, 0xE7, 0xD6,
    0x7A, 0x4B, 0x18, 0x29, 0xBE, 0x8F, 0xDC, 0xED, 0xC3, 0xF2, 0xA1, 0x90, 0x07, 0x36, 0x65, 0x54,
    0x39, 0x08, 0x5B, 0x6A, 0xFD, 0xCC, 0x9F, 0xAE, 0x80, 0xB1, 0xE2, 0xD3, 0x44, 0x75, 0x26, 0x17,
    0xFC, 0xCD, 0x9E, 0xAF, 0x38, 0x09, 0x5A, 0x6B, 0x45, 0x74, 0x27, 0x16, 0x81, 0xB0, 0xE3, 0xD2,
    0xBF, 0x8E, 0xDD, 0xEC, 0x7B, 0x4A, 0x19, 0x28, 0x06, 0x37, 0x64, 0x55, 0xC2, 0xF3, 0xA0, 0x91,
    0x47, 0x76, 0x25, 0x14, 0x83, 0xB2, 0xE1, 0xD0, 0xFE, 0xCF, 0x9C, 0xAD, 0x3A, 0x0B, 0x58, 0x69,
    0x04, 0x35, 0x66, 0x57, 0xC0, 0xF1, 0xA2, 0x93, 0xBD, 0x8C, 0xDF, 0xEE, 0x79, 0x48, 0x1B, 0x2A,
    0xC1, 0xF0, 0xA3, 0x92, 0x05, 0x34, 0x67, 0x56, 0x78, 0x49, 0x1A, 0x2B, 0xBC, 0x8D, 0xDE, 0xEF,
    0x82, 0xB3, 0xE0, 0xD1, 0x46, 0x77, 0x24, 0x15, 0x3B, 0x0A, 0x59, 0x68, 0xFF, 0xCE, 0x9D, 0xAC
};

private final boolean useLookupTable;
private short crc8;

public Crc8() {
    this(true);
}

public Crc8(boolean use_lookup_table) {
    useLookupTable = use_lookup_table;
    reset();
}

public Crc8 reset() {
    crc8 = CRC8_INIT_VALUE;
    return (this);
}

public Crc8 update(byte b) {
    if (useLookupTable) {
        crc8 = CRC8_LOOKUP_TABLE[(crc8 ^ b) & 0xFF];
    } else {
        crc8 ^= b;
        crc8 &= 0xFF;
        for (int j = 0; j < 8; j++) {
            if ((crc8 & 1) == 1) {
                crc8 >>= 1;
                crc8 ^= CRC8_POLYNOMIAL;
            } else {
                crc8 >>= 1;
            }
        }
    }
    return (this);
}

public Crc8 update(byte[] data, int offset, int length) {
    for (int i = offset; i < length; i++) {
        update(data[i]);
    }
    return (this);
}

public Crc8 update(byte[] data) {
    return update(data, 0, data.length);
}

public Crc8 update(String s) {
    try {
        return update(s.getBytes("UTF-8"));
    } catch (UnsupportedEncodingException ex) {
        throw new RuntimeException(ex);
    }
}

public short get() {
    return ((short) (crc8 ^ 0xFF));
}

/**
 * Return calculated CRC8 in 2 capital hex digits with leading zeros.
 */
public String getHex() {
    return (String.format("%02X", get()));
}}

这是主要的-class

public static void main(String[] args) {
    Crc8 crc = new Crc8(true);
    String input = "VR1,?,";
    crc.update(input);
    System.out.println("Input: " + input);
    String result  = crc.getHex();
    System.out.println("Output: " + result);

}

但不幸的是结果是 E4 而不是 D7

请考虑 java 没有未签名的 ints。这将影响您的 right shift 运营商,>>=。这个link讲的是:What is the Java equivalent of unsigned?。我认为对于您要尝试做的事情来说,重要的部分是:

Signed vs unsigned shifts

An important exception is the right shift operator, represented by two "greater than" symbols: >>. In both C/C++ and Java, this operator performs sign extension: that is, as well as shifting the bits of the number one place to the right, it preserves the sign. Specifically, after performing the shift, it copies the sign bit (the leftmost bit) into the leftmost position.

Now, if we're treating an integer as unsigned, then we don't want to copy the sign bit, because it doesn't actually represent the sign! Instead, we want to leave it as zero. To achieve this, in Java, instead of writing >>, we write >>>. This variant of the shift is sometimes called a logical shift, and the previous variant— which takes account of the sign— an arithmetic shift. At the machine code level, most architectures in fact provide different instructions for the two shifts, and the C/C++ compiler chooses the appropriate one depending on whether we've declared the variable in question as unsigned. In Java, we must explicitly say which type we require.

编辑:尝试将这些十六进制值 5652312C3F2C 放入 Eric's Maxim/Dallas 1-Wire Online CRC Calculator 。它给出了 D7 并给出了一堆调试信息,应该可以帮助您找出问题所在。

好的,首先我要感谢尼古拉斯的巨大帮助:)

所以我从阳光网站(开源)的制作者那里查找了c#代码并将其转换为Java。我不得不用 int 替换所有字节类型,因为 Java 字节是有符号的,所以它们没有 c#-bytes 的范围。

但现在可以了。

这是最终代码(仅适用于多项式的 CRC8-Maxim:0x31)

package com.hydester.hopefullylastcrctest;

public class Crc8 {

private static Crc8 instance;
private final byte initial = 0x00;
private final byte finalXor = 0x00;
private final boolean inputReflected = true;
private final boolean resultReflected = true;

private final int[] crcTable = new int[]{0,49,98,83,196,245,166,151,185,136,219,234,125,76,31,46,67,114,33,16,135,182,229,212,250,203,152,169,62,15,92,109,134,183,228,213,66,115,32,17,63,14,93,108,251,202,153,168,197,244,167,150,1,48,99,82,124,77,30,47,184,137,218,235,61,12,95,110,249,200,155,170,132,181,230,215,64,113,34,19,126,79,28,45,186,139,216,233,199,246,165,148,3,50,97,80,187,138,217,232,127,78,29,44,2,51,96,81,198,247,164,149,248,201,154,171,60,13,94,111,65,112,35,18,133,180,231,214,122,75,24,41,190,143,220,237,195,242,161,144,7,54,101,84,57,8,91,106,253,204,159,174,128,177,226,211,68,117,38,23,252,205,158,175,56,9,90,107,69,116,39,22,129,176,227,210,191,142,221,236,123,74,25,40,6,55,100,85,194,243,160,145,71,118,37,20,131,178,225,208,254,207,156,173,58,11,88,105,4,53,102,87,192,241,162,147,189,140,223,238,121,72,27,42,193,240,163,146,5,52,103,86,120,73,26,43,188,141,222,239,130,179,224,209,70,119,36,21,59,10,89,104,255,206,157,172};

private Crc8(){}

public static Crc8 getInstance(){
    return instance == null ? instance = new Crc8() : instance;
}

public int compute(int[] bytes) {

    int crc = initial;
    for (int b : bytes) {
        int curByte = (inputReflected ? reflect8(b) : b);
        int data = (int) (curByte ^ crc);
        crc = (int) (crcTable[data]);
    }
    crc = (resultReflected ? reflect8(crc) : crc);
    return (int) (crc ^ finalXor);
}

private int reflect8(int val) {
    int resByte = 0;
    for (int i = 0; i < 8; i++) {
        if ((val & (1 << i)) != 0) {
            resByte |= (int) (1 << (7 - i));
        }
    }
    return resByte;
}}