#!/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 = "750000047B48FC14";
#$data =  "14FC487B04000075";
# 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 transmitted crc:" .  sprintf("%04X",$crc16) . "\n";
}
#
exit 0;
