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

I need to calculate CRC-16/X25 checksum/digest in order to communicate with some instrument. I am using Digest::CRC module and https://crccalc.com/ site for both the source of appropriate parameters and to check the result. (The examples in the instrument manual agree with results on csccalc.com.) However, I cannot seem to get correct results. Here is a snippet of may code:

use Digest::CRC; my ($crc, $input, $width, $init, $xorout, $refout, $poly, $refin, $con +t, $digest, $ctx); $width = 16; $init = 0xffff; $xorout = 0xffff; $refout = 1; $poly = 0x1021; $refin = 1; $cont = 0; # ??? $input = 0xaabbccdd; $ctx = Digest::CRC->new(width=>$width, init=>$init, xorout=>$xorout, refout=>$refout, poly=>$poly, refin=>$refin, cont=>$cont); $ctx->add($input); $digest = $ctx->hexdigest; say $digest;
I am either interpreting the parameters incorrectly, on missunderstand the arcana of pack/unpack functions and the need for them, or something else entirely. A bit of enlightenment would be appreciated.

Replies are listed 'Best First'.
Re: CRC-16/X25 problem
by pryrt (Abbot) on Mar 16, 2024 at 20:07 UTC
    I haven't been able to figure out how to enter a 32bit number, like your $input = 0xaabbccdd; into the website.(edit: holdover from my first draft; first line should not have been posted, since I figured it out before posting)

    But if I want to match the results that the website gets for "AABBCCDD" as HEX input (https://crccalc.com/?crc=AABBCCDD&method=CRC-16/X-25&datatype=hex&outtype=0), which gives 0xF486, I use $cont=0 (I believe the cont parameter is "continue", and since you aren't adding to the string, but using it as the whole message, you want cont=>0 ) and $input = "\xAA\xBB\xCC\xDD" and it gives the same 0x4FCB that the online tool gives.

    Fixing your cont->$cont typo to cont=>$cont , and adding a few different test cases, the test_it function has the right setup to get the same results as the online tool, as shown by the Test::More results.

    #!perl.exe use 5.014; # //, strict, say, s///r use warnings; use Digest::CRC; my ($crc, $input, $width, $init, $xorout, $refout, $poly, $refin, $con +t, $digest, $ctx, $exp); $width = 16; $init = 0xffff; $xorout = 0xffff; $refout = 1; $poly = 0x1021; $refin = 1; $cont = 0; # ??? $input = 0xaabbccdd; $ctx = Digest::CRC->new(width=>$width, init=>$init, xorout=>$xorout, refout=>$refout, poly=>$poly, refin=>$refin, cont=>$cont); $ctx->add($input); $digest = $ctx->hexdigest; say $digest; use Test::More; use feature 'fc'; use Data::Dump qw/pp/; sub test_it { my($in, $cont, $expect) = @_; my $ctx = Digest::CRC->new(width=>$width, init=>$init, xorout=>$xo +rout, refout=>$refout, poly=>$poly, refin=>$refin, cont=>$cont); $ctx->add($in); my $got = $ctx->hexdigest; is fc($got), fc($expect), sprintf("test_it(%s, %s, %s)", pp($in), +$cont, $expect); } test_it("AABBCCDD", 0, '1D8D'); # https://crccalc.com/?crc=AABBCCDD&me +thod=CRC-16/X-25&datatype=ascii&outtype=0 test_it("\xAA", 0, 'FA28'); # https://crccalc.com/?crc=AA&method=C +RC-16/X-25&datatype=hex&outtype=0 test_it("\xAA\xBB\xCC\xDD", 0, '4FCB'); # https://crccalc.com/?crc=AA +BBCCDD&method=CRC-16/X-25&datatype=hex&outtype=0 test_it("\xDD\xCC\xBB\xAA", 0, 'F486'); # https://crccalc.com/?crc=DD +CCBBAA&method=CRC-16/X-25&datatype=hex&outtype=0 done_testing;

    __END__ 1680 ok 1 - test_it("AABBCCDD", 0, 1D8D) ok 2 - test_it("\xAA", 0, FA28) ok 3 - test_it("\xAA\xBB\xCC\xDD", 0, 4FCB) ok 4 - test_it("\xDD\xCC\xBB\xAA", 0, F486) 1..4

    I would have expected either test3 or test4 to match your 0xAABBCCDD input, but neither did.

    And then I realized: 0xAABBCCDD is the integer 2864434397, which Perl stringifies into "2864434397", so if I try that string input, the tool gives 0x1680, which is what Digest::CRC gives for your $input = 0xaabbccdd; input.

    Digest::CRC is built to work on a series of octets (because that's what it gets from reading a file), so when you pass in a number, it lets Perl stringify it into a string, which it treats as a series of octets; it doesn't deal with the raw octets for the integer (that would open the big-/little-/middle-endian can of worms). (Presumably, you could pack your integer as well, but that is left as an exercise for the reader.)

Re: CRC-16/X25 problem
by Danny (Chaplain) on Mar 16, 2024 at 19:39 UTC
    Not sure if it was a typo in your post or in your code, but cont->$cont should be cont=>$cont.
      In my post. Thanks for the eagle eye. - Corrected.

        It is usual to include a notice when you edit or update you node. Something like:

        "Update: fixed typo - thanks Danny"

        added to the bottom of your node. Not a major issue in this case, but in general it helps avoid disconnects between replies and the current state of your node.

        Optimising for fewest key strokes only makes sense transmitting to Pluto or beyond
Re: CRC-16/X25 problem
by bonzi (Acolyte) on Mar 16, 2024 at 19:57 UTC
    It seems to be the second of the options above - when I submit an ASCII string, I get the expected result. So, it would seem that I need to "ASCII-fy" my data. Time for pack/unpack tutorial...
      What answer do you expect your example to give?