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

Does anybody know how to calculate the 16 bit Dallas/Maxim crc value using perl and perhaps Digest::CRC?

I have a text string of hexadecimal bytes (e.g. "142C00040000AFBD5E83") where the first 8 bytes is data and the last 2 is the crc. The example is actual data recived from the device. I have recived the same string more than once, so the crc value is proberbly correct.

Thanks in advance

Kim

Replies are listed 'Best First'.
Re: Dallas/Maxim crc
by roboticus (Chancellor) on Mar 13, 2013 at 13:23 UTC

    Googling "dallas maxim crc" turned up a few links, one of which http://arduino.cc/forum/index.php?topic=37648.0;wap2 offers:

    // Dallas 1-wire 16-bit CRC calculation. Developed from Maxim Applicat +ion Note 27. uint16_t crc16( uint8_t *data, uint8_t len) { uint16_t crc=0; for (uint8_t i=0; i<len;i++) { uint8_t inbyte = data[i]; for (uint8_t j=0;j<8;j++) { uint8_t mix = (byte(crc)^ inbyte) & 0x01; crc = crc >> 1; if (mix) crc = crc ^ 0xA001; inbyte = inbyte >> 1; } } return crc; }

    Just translate it to perl, and you're done...

    ...roboticus

    When your only tool is a hammer, all problems look like your thumb.

Re: Dallas/Maxim crc
by anita2R (Scribe) on Nov 28, 2013 at 04:47 UTC

    I came upon this post when looking for a Perl script to calculate an 8 bit crc for a Dallas/Maxim scratchpad data read. Although this post is old, there was no 'answer' at least not in Perl, so having created scripts for calculating the crc's I decided to post anyway. I managed to create a script for the 8 bit crc, and to respond to this post I modified the code to work for the 16 bit crc. I have only tested this on the one data/crc combination given in the question so I can't be sure it's correct. Anyway here it is & any feedback is welcome:

    #!/usr/bin/perl # # Script to calculate the Dallas/Maxim 16 bit crc # The data block is 8 bytes and the crc is 2 bytes # # The script compares a calculated 16 bit crc with the # transmitted crc # # LS = least significant # MS = most significant # XOR = bitwise exclusive OR # use strict; # # variables my ($data, $crc16); # input data & input crc my $crc; # calculated crc my $test; # initial XOR of bit 1 of data & crc my ($byte, $bit); # each byte of data & each bit of byte my ($i, $n); # loop counters # ########################################################### # Sample data (8 bytes in hex) $data = "142C00040000AFBD"; # Sample crc (correct crc for the sample data above) # in MSbyte, LSbyte order $crc16 = "835E"; ########################################################### # # set initial crc for calculation (16 bits all zero) $crc = 0b0000000000000000; # # loop through data bytes for ($i = 0; $i <= 14; $i+=2) { #convert pairs of hex digits into number $byte = hex(substr $data, $i, 2); # sub-loop to read 8 bits from byte for ($n = 0; $n <= 7; $n++) { # # get LSbit of byte by applying mask $bit = $byte & 0b00000001; # # XOR the LS bit of the crc with # the current data bit $test = $crc ^ $bit; # apply mask to get LS bit only $test = $test & 0b00000001; # # test if result was 1 or 0 if ($test) { # result was 1 so need to XOR, right shift # & make MS bit 1 # # XOR crc with 0b0100000000000010 $crc = $crc ^ 0b0100000000000010; # right shift $crc = $crc >> 1; # make MS bit 1 by OR'ing with 0b1000000000000000 $crc = $crc | 0b1000000000000000; } else { # result was zero, so just right shift crc # (MS bit will be 0) $crc = $crc >> 1; } # shift data byte to right so next bit # is in LS bit position $byte = ( $byte >> 1 ); } } # # complement calculated crc # & mask off all but lowest 16 bits $crc = ~$crc & 0b1111111111111111; # # compare calculated crc to transmitted crc if ($crc == hex($crc16)) { print "Result ". sprintf("%X",$crc) . " is correct\n"; } else { print "Result " . sprintf("%X",$crc) . " does not match the trans +mitted crc:" . sprintf("%04X",$crc16) . "\n"; } # exit 0;

    I hope that this script is of some use. I will shortly post the code for the 8 bit crc. The method of calculating the crc is slightly different to the code from 'arduino.cc/forum code', but in it's 8 bit format it works consistently

      As a follow-up to the script for the 16 bit crc, here is a script for the Dallas/Maxim 8 bit crc. The sample data & crc comes from a DS1822 1-wire digital thermometer. I use the code in a slightly modified format as a function in a larger program, with data and transmitted crc passed to the function, which returns 'OK' or 'Error' back to the main program.

      #!/usr/bin/perl # # Script to calculate the Dallas/Maxim 8 bit crc # The data block is 8 bytes and the crc is 1 byte # Sample data is from a DS1822 scratchpad read # # The script compares a calculated 8 bit crc with the # transmitted crc # # LS = least significant # MS = most significant # XOR = bitwise exclusive OR # use strict; # # variables my ($data, $crc8); # input data & input crc my $crc; # calculated crc my $test; # initial XOR of bit 1 of data & crc my ($byte, $bit); # each byte of data & each bit of byte my ($i, $n); # loop counters # ########################################################### # Sample data (8 bytes in hex) $data = "4E014B467FFF0210"; # Sample crc (correct crc for the sample data above) $crc8 = "D9"; ########################################################### # # set initial crc for calculation (8 bits all zero) $crc = 0b00000000; # # loop through data bytes for ($i = 0; $i <= 14; $i+=2) { #convert pairs of hex digits into number $byte = hex(substr $data, $i, 2); # sub-loop to read 8 bits from byte for ($n = 0; $n <= 7; $n++) { # # get LSbit of byte by applying mask $bit = $byte & 0b00000001; # # XOR the LS bit of the crc with # the current data bit $test = $crc ^ $bit; # apply mask to get LS bit only $test = $test & 0b00000001; # # test if result was 1 or 0 if ($test) { # result was 1 so need to XOR, right shift # & make MS bit 1 # # XOR crc with 0b00011000 $crc = $crc ^ 0b00011000; # right shift $crc = $crc >> 1; # make MS bit 1 by OR'ing with 0b10000000 $crc = $crc | 0b10000000; } else { # result was zero, so just right shift crc # (MS bit will be 0) $crc = $crc >> 1; } # shift data byte to right so next bit # is in LS bit position $byte = ( $byte >> 1 ); } } # # compare calculated crc to transmitted crc if ($crc == hex($crc8)) { print "Result ". sprintf("%X",$crc) . " is correct\n"; } else { print "Result " . sprintf("%X",$crc) . " does not match the trans +mitted crc:" . sprintf("%02X",$crc8) . "\n"; } # exit 0;