-1

I have source with checksum CRC16 in C++:

quint16 MainWindow::calculateCRC16(QByteArray buffer)
{
    quint16 newCrc;
    quint8 i;
    newCrc = 0xFFFF;

    for(i = 0; i < buffer.size(); i++){
        newCrc = this->crc16_update(newCrc, (quint8)buffer.at(i));
    }
    return newCrc;
}

quint16 MainWindow::crc16_update(quint16 crc, quint8 a)
{
    quint8 i;

    crc ^= a;

    for (i = 0; i < 8; ++i) {
        if (crc & 1)
            crc = (crc >> 1) ^ 0xA001;
        else
            crc = (crc >> 1);
    }
    return crc;
}

For example when we put:

QByteArray buffer = \x02\x14\x14\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00

The result is:

int result = 65535
QByteArray result = \x1d\x20

I tried to achieve the same result in Java, but without positive effect

First example:

int calculate_crc(byte[] bytes) {
    int i;
    int crc_value = 0;
    for (int len = 0; len < bytes.length; len++) {
        for (i = 0x80; i != 0; i >>= 1) {
            if ((crc_value & 0x8000) != 0) {
                crc_value = (crc_value << 1) ^ 0x8005;
            } else {
                crc_value = crc_value << 1;
            }
            if ((bytes[len] & i) != 0) {
                crc_value ^= 0x8005;
            }
        }
    }
    return crc_value;
}

Other one:

private int calculateCRC16(byte[] buffer)
{
    int newCrc;
    int i;
    newCrc = 0xFFFF;
    for(i = 0; i < buffer.length; i++) {
        newCrc = this.crc16_update(newCrc, buffer[i]);
    }
    return newCrc;
}

int crc16_update(int crc, int a)
{
    int i;
    crc ^= a;

    for (i = 0; i < 8; ++i) {
        if ((crc & 1) == 1){
            crc = (crc >> 1) ^ 0xA001;
        }
       else{
           crc = (crc >> 1);
        }
    }
    return crc;
}

For example when we put with two cases:

byte[] buffer = 0x2 0x14 0x14 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0

The result is:

int result = 26997
byte[] result = 0x69 0x75

Maybe somebody can help me to find proper way, i have no idea what is wrong ...

CubeJockey
  • 2,209
  • 8
  • 24
  • 31
ronin
  • 11
  • 1
  • My Java's a bit rusty, but I think you need a logical shift `>>>` to treat the values the way C++ treats unsigned values (filling with zero instead of the sign bit). – Mike Seymour May 05 '15 at 17:28
  • There"s better code than this. Have a look around for the tabular method. It's eight times as fast. – user207421 May 05 '15 at 18:23
  • The result you give for the C code is nonsensical: 65535 and 0x1D20 are not the same value. – Durandal May 05 '15 at 18:55
  • @MikeSeymour The accident is the java version is the signed extension of the bytes when passed to crc16_update. It could be fixed by masking the agument a with 0xFF. But since the example bytes are all positive the crc given by the java version should be unaffected by this oversight. – Durandal May 05 '15 at 19:00
  • @Durandal *Non sequitur.*. The CRC calculation can flip the sign bit. What do you think `^ 0xA001` does exactly? – user207421 May 06 '15 at 01:15
  • See [here](http://www.barrgroup.com/Embedded-Systems/How-To/CRC-Calculation-C-Code) for tabular code. – user207421 May 06 '15 at 01:36
  • @EJP And since when is bit 15 the sign bit in an int? – Durandal May 06 '15 at 13:18
  • @Durandal This is 16-bit code. – user207421 May 07 '15 at 01:50
  • @EJP No its not, the parameters of update_crc are declared as *int*. You are probably thinking about the C++ code, not on the TC's java port I'm talking about. Or if your mindset is that 0xA001 flips the sign bit of the short held in the int variable, thats of no concern as far as code correctness goes; because it will not affect the upper int half unexpectedly - as passing a byte with bit 7 set for argument a would (the line crc ^= a inverts the upper 24 bits of crc in that case, instead of just bit 7). We're talking about different things I believe. – Durandal May 07 '15 at 15:49

2 Answers2

1

0x6975 or decimal 26997 is the correct result. Your C++ results make no sense. (The hex and decimal aren't even the same value.)

Mark Adler
  • 101,978
  • 13
  • 118
  • 158
0

That's true ... it was my mistake.

Again I checked output and that was the point.

The result in C++ this is nothing more like quint16 size (unsigned int 2 bytes 0 to 65535)

I had printf it in wrong place.

But this is not one reason, other one was small difference between bytearray.

ronin
  • 11
  • 1