wdtj has asked for the wisdom of the Perl Monks concerning the following question:

I'm having some problems calculating a checksum for a DNP3 link using Digest::CRC.
The spec says it's a 2 octet CRC based on the polynomial X^16 + X^13 + X^12 + X^11 + X^10 + X^8 + X^6 + X^5 + X^2 + 1. It's also inverted and put in the data block LSB first.
With Perl's Digest package, I set up the algorithm as:
my $ctx = Digest::CRC->new(width=>16, init=>0, xorout=>0xffff, refin=>1, refout=>1, poly=>0x3d65, cont=>0xea82); $ctx->add(0x05); $ctx->add(0x64); $ctx->add(0x05); $ctx->add(0xF2); $ctx->add(0x01); $ctx->add(0x00); $ctx->add(0x00); $ctx->add(0x00); my $x=$ctx->digest; printf("x=%04x\n",$x);
The example in the spec shown for the header: 05 64 05 F2 01 00 00 00 the checksum should be 52 0C. I get x=91fc. I've tried playing with all the parameters but can't seem to get it to come out. Any suggestions?

Replies are listed 'Best First'.
Re: Using Digest::CRC to calculate DNP3 checksums
by dasgar (Priest) on Sep 08, 2016 at 05:34 UTC

    I thought I'd challenge myself to see if I could figure this out. As I started looking into CRC algorithms, I quickly found myself in over my head. But I think that I was actually able to figure it out.

    Looking at the source code of Digest::CRC, I took a guess that the value for 'const' should be 0 instead of '0xea82'. That got me closer for ASCII input. Combining that with the suggestion from the Anonymous Monk got me closer for hex input. In both cases what I mean by getting closer is that I got the right characters, but in the wrong order. Basically, I needed to reverse the output by bits. For example, with your sample header, I was getting 'c52' instead of '520c'. The two bits here are '0c' and '52'. Reversing the two bits of 'c52' (or '0c52') produces '520c'.

    In searching for references for CRC-DNP checksums, I found an online checksum calculator (found here). I used it to 'verify' the output of the following code.

    That produced the following output:

    Calculating CRC-DNP checksum for '056405F201000000': ASCII input: 99fc Hex input: 520c Calculating CRC-DNP checksum for '56405F201000000': ASCII input: 0751 Hex input: 11e3

    I've tried a few other examples to compare the output of my code versus the online calculator and I'm getting the same values for the CRC-DNP checksums.

    Perhaps more knowledgeable monks might be able to identify issues with my code, but I think it should help you get further along with what you're trying to do.

    UPDATE: Since the OP was cross posted, I cross posted this response (see here) as well to the same site.

Re: Using Digest::CRC to calculate DNP3 checksums
by Corion (Patriarch) on Sep 07, 2016 at 17:56 UTC
Re: Using Digest::CRC to calculate DNP3 checksums
by Anonymous Monk on Sep 07, 2016 at 21:06 UTC
    I'm just gonna guess that you should try $ctx->add(chr(0x05))