Beefy Boxes and Bandwidth Generously Provided by pair Networks
Come for the quick hacks, stay for the epiphanies.
 
PerlMonks  

Re: Using Digest::CRC to calculate DNP3 checksums

by dasgar (Priest)
on Sep 08, 2016 at 05:34 UTC ( [id://1171362]=note: print w/replies, xml ) Need Help??


in reply to Using Digest::CRC to calculate DNP3 checksums

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.

use strict; use warnings; use feature 'say'; use Digest::CRC; sub Left_Pad { my $value = shift; if (length($value) % 2) {$value = '0'.$value;} return $value; } sub Bitwise_Reverse { my $value = shift; $value = Left_Pad($value); my $offset = length($value); my $reversed; while ($offset > 0) { $offset -= 2; my $string = substr($value,$offset,2); $reversed .= $string; } return $reversed; } sub CRC_DNP_ASCII { my $value = shift; my $ctx = Digest::CRC->new(width=>16, init=>0x0, xorout=>0xffff, r +efin=>1, refout=>1, poly=>0x3d65, cont=>0); $ctx->add($value); my $digest = $ctx->hexdigest; my $crc = Bitwise_Reverse($digest); return $crc; } sub CRC_DNP_HEX { my $value = shift; my $ctx = Digest::CRC->new(width=>16, init=>0x0, xorout=>0xffff, r +efin=>1, refout=>1, poly=>0x3d65, cont=>0); my $offset = 0; while ($offset < length($value)) { my $string = substr($value,$offset,2); $ctx->add(chr(hex($string))); $offset += 2; } my $digest = $ctx->hexdigest; my $crc = Bitwise_Reverse($digest); return $crc; } my @data_list = ('056405F201000000','56405F201000000'); foreach my $data (@data_list) { say "Calculating CRC-DNP checksum for '$data':"; my $ascii = CRC_DNP_ASCII($data); say " ASCII input: $ascii"; my $hex = CRC_DNP_HEX($data); say " Hex input: $hex\n"; }

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.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://1171362]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others drinking their drinks and smoking their pipes about the Monastery: (6)
As of 2024-04-23 12:55 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found