Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

CRC16 for DNP3

77 views
Skip to first unread message

david.s...@teamsimoco.com

unread,
Jul 14, 2015, 6:37:53 AM7/14/15
to
Hi. Hoping for a little advise with the CRC16 package, I'm trying to get DNP3 CRCs out but what ever I do it comes back incorrect.

I've tried this:
crc::crc16 -format 0x%X -seed 1001111010110010 E0C0810000 which gave 0xF4E4

and this:
crc::crc16 -format 0x%X -seed 0x9E2B E0C0810000 which gave 0x6DC0

What I understand to be correct DNO-CRC for E0C0810000 is 0xC1F0

The 9E2B and the 1001111010110010 are what I believe are the Hex and Bin seeds for DNP3 but I may be wrong.

The Polynomial is :
x^16 + x^13 + x^12 + x^11 + x^10 + x^8 + x^6 + x^5 + x^2 + 1

Can anyone help please with correct syntax. Thanks in advance.

Dave

Christian Gollwitzer

unread,
Jul 15, 2015, 1:41:18 AM7/15/15
to
Am 14.07.15 um 12:37 schrieb david.s...@teamsimoco.com:
> Hi. Hoping for a little advise with the CRC16 package, I'm trying to get DNP3 CRCs out but what ever I do it comes back incorrect.
>
> I've tried this:
> crc::crc16 -format 0x%X -seed 1001111010110010 E0C0810000 which gave 0xF4E4

This interprets the seed as a big decimal number.

>
> and this:
> crc::crc16 -format 0x%X -seed 0x9E2B E0C0810000 which gave 0x6DC0

I believe that with "E0C0810000" you mean 5 bytes with the values 0xE0,
0xC0, ... ? Your call interprets the message as 10 bytes, with the
values 'E', '0', 'C', .... since the crc package expects a binary string
in the message. Therefore, that should be

crc::crc16 -format 0x%X -seed 0x9E2B [binary format H* E0C0810000]

I think for your "real" application, the data will come in from a file
or a variable already in binary, so probably you won't need the binary
format there - unless you really get a string with hexadecimal digits.


> What I understand to be correct DNO-CRC for E0C0810000 is 0xC1F0
>
> The 9E2B and the 1001111010110010 are what I believe are the Hex and Bin seeds for DNP3 but I may be wrong.

I can't comment on this one.


> The Polynomial is :
> x^16 + x^13 + x^12 + x^11 + x^10 + x^8 + x^6 + x^5 + x^2 + 1
>
> Can anyone help please with correct syntax. Thanks in advance.

Here you are unlucky: poking into the implementation of crc16,
https://github.com/tcltk/tcllib/blob/master/modules/crc/crc16.tcl#L51
your polynomial is not in the predefined ones. Nevertheless it should be
possible to do it by writing a procedure analogous to the predefined
ones. Just copy this

https://github.com/tcltk/tcllib/blob/master/modules/crc/crc16.tcl#L181

and replace your polynomial there, e.g.

proc DNO-CRC {s {seed 0x9E2B}} {
variable DNOtable
if {![info exists DNOtable]} {
set poly [expr {(1<<16) | (1<<13) | (1<<12) | 1<<11 | 1<<10 | 1<<8 |
1<<6 | 1<<5 | 1<<2 | 1}]

set DNOtable [crc::Crc_table 16 $poly 1]
}

return [crc::Crc $s 16 DNOtable $seed 0 1]
}

This still comes back with a different answer:

(Sources) 77 % DNO-CRC [binary format H* E0C0810000]
28022
(Sources) 78 % format %X 28022
6D76

Maybe it has to do with the various flags passed into the table
generator and Crc. My knowledge of CRCs is too weak, though, to debug it
further.

Christian

david.s...@teamsimoco.com

unread,
Jul 15, 2015, 10:55:52 AM7/15/15
to
Hi Christian.

I too have had some time to explore the CRC package in the Lib and I agree with you regards it not being capable in it's current state to do what I need so I'm currently hacking it about to do the DNP CRC...I sort it eventually.

Much appreciate you time and comments and I'll post the solution once I've sorted it in case any person might need it.

Thanks again Dave

david.s...@teamsimoco.com

unread,
Jul 16, 2015, 12:36:51 PM7/16/15
to
CRC-DNP calculator
Not sure if it's any use to anyone but this is the solution I've come up with which could probably be tidier but there ya go.

proc Littendian {num} {

set size [string length $num]
if {$size == 4} {
set num1 0
set num2 1
set num3 2
set num4 3
} elseif {$size == 8} {
set num1 0
set num2 3
set num3 4
set num4 7
} else {
return "size needs to be 4 or 8"
}
set backNum [string range $num $num1 $num2]
set frontNum [string range $num $num3 $num4]
append var $frontNum $backNum
return $var
}


proc padBinary {args} {
set length [lindex $args 0]
set binaryNum [lindex $args 1]
set diff [expr $length - [string length $binaryNum]]

for {set i 0} {$i < $diff} {incr i} {
append extraZeros 0
}
return [append extraZeros $binaryNum]
}

proc Crc_table {poly} {
set tbl {}

for {set b 0} {$b < 256} {incr b} {
set v $b

for {set i 0} {$i < 8} {incr i} {
if {[expr {$v & 1}] != 0} {
set v [expr {($v >> 1) ^ $poly}]
} else {
set v [expr {$v >> 1}]
}
}
lappend table $v
}
return $table
}

set mCrcTable [Crc_table 0xa6bc]

proc calculate {msg mCrcTable} {
puts $mCrcTable
puts $msg
set i 0
set count [string length $msg]
puts $count
set crc 0

while {$i < $count} {

set DecyNum [format %d 0x[string range $msg $i [expr $i + 1]]]
set dividedNum [expr {$crc ^ $DecyNum}]
set entry [expr $dividedNum & 255]
set crc [expr {$crc >> 8} ^ [lrange $mCrcTable $entry $entry]]
incr i 2
}

set crc [expr $crc ^ 0xffff]
set crc [Littendian [format %.4x $crc]]

return $crc;
}

##setting the number to which the CRC will apply.
set num E0C0810000

#Calling the calculator
puts [calculate $num $mCrcTable]

And thanks again Christian
0 new messages