source: tol/tolsh/tolsh.vfs/lib/tcllib1.10/crc/crc16.tcl @ 8597867d

1941-docker-image-to-testdevel
Last change on this file since 8597867d was 8597867d, checked in by Jorge Pérez <josp.jorge@…>, 16 years ago

closes #976, se incluye tcllib1.10, base64 debe eliminarse del raiz de lib ya que esta incluido en tcllib

git-svn-id: ​https://www.tol-project.org/svn/tolp/trunk@2556 be4846ae-f051-483a-831f-b64e7d08527f

  • Property mode set to 100644
File size: 10.1 KB
Line 
1# crc16.tcl -- Copyright (C) 2002 Pat Thoyts <patthoyts@users.sourceforge.net>
2#
3# Cyclic Redundancy Check - this is a Tcl implementation of a general
4# table-driven CRC implementation. This code should be able to generate
5# the lookup table and implement the correct algorithm for most types
6# of CRC. CRC-16, CRC-32 and the CCITT version of CRC-16. [1][2][3]
7# Most transmission CRCs use the CCITT polynomial (including X.25, SDLC
8# and Kermit).
9#
10# [1] http://www.microconsultants.com/tips/crc/crc.txt for the reference
11#     implementation
12# [2] http://www.embedded.com/internet/0001/0001connect.htm
13#     for another good discussion of why things are the way they are.
14# [3] "Numerical Recipes in C", Press WH et al. Chapter 20.
15#
16# Checks: a crc for the string "123456789" should give:
17#   CRC16:     0xBB3D
18#   CRC-CCITT: 0x29B1
19#   XMODEM:    0x31C3
20#   CRC-32:    0xCBF43926
21#
22# eg: crc::crc16 "123456789"
23#     crc::crc-ccitt "123456789"
24# or  crc::crc16 -file tclsh.exe
25#
26# Note:
27#  The CCITT CRC can very easily be checked for the accuracy of transmission
28#  as the CRC of the message plus the CRC values will be 0. That is:
29#   % set msg {123456789]
30#   % set crc [crc::crc-ccitt $msg]
31#   % crc::crc-ccitt $msg[binary format S $crc]
32#   0
33#
34#  The same is true of other CRCs but some operate in reverse bit order:
35#   % crc::crc16 $msg[binary format s [crc::crc16 $msg]]
36#   0
37#
38# -------------------------------------------------------------------------
39# See the file "license.terms" for information on usage and redistribution
40# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
41# -------------------------------------------------------------------------
42# $Id: crc16.tcl,v 1.15 2006/04/20 10:19:51 patthoyts Exp $
43
44# @mdgen EXCLUDE: crcc.tcl
45
46package require Tcl 8.2;                # tcl minimum version
47
48namespace eval ::crc {
49   
50    namespace export crc16 crc-ccitt crc-32
51
52    variable crc16_version 1.1.1
53
54    # Standard CRC generator polynomials.
55    variable polynomial
56    set polynomial(crc16) [expr {(1<<16) | (1<<15) | (1<<2) | 1}]
57    set polynomial(ccitt) [expr {(1<<16) | (1<<12) | (1<<5) | 1}]
58    set polynomial(crc32) [expr {(1<<32) | (1<<26) | (1<<23) | (1<<22)
59                                 | (1<<16) | (1<<12) | (1<<11) | (1<<10)
60                                 | (1<<8) | (1<<7) | (1<<5) | (1<<4)
61                                 | (1<<2) | (1<<1) | 1}]
62
63    # Array to hold the generated tables
64    variable table
65    if {![info exists table]} { array set table {}}
66
67    # calculate the sign bit for the current platform.
68    variable signbit
69    if {![info exists signbit]} {
70        variable v
71        for {set v 1} {int($v) != 0} {set signbit $v; set v [expr {$v<<1}]} {}
72        unset v
73    }
74}
75
76# -------------------------------------------------------------------------
77# Generate a CRC lookup table.
78# This creates a CRC algorithm lookup table for a 'width' bits checksum
79# using the 'poly' polynomial for all values of an input byte.
80# Setting 'reflected' changes the bit order for input bytes.
81# Returns a list or 255 elements.
82#
83# CRC-32:      Crc_table 32 $crc::polynomial(crc32) 1
84# CRC-16:      Crc_table 16 $crc::polynomial(crc16) 1
85# CRC16/CCITT: Crc_table 16 $crc::polynomial(ccitt) 0
86#
87proc ::crc::Crc_table {width poly reflected} {
88    set tbl {}
89    if {$width < 32} {
90        set mask   [expr {(1 << $width) - 1}]
91        set topbit [expr {1 << ($width - 1)}]
92    } else {
93        set mask   0xffffffff
94        set topbit 0x80000000
95    }
96
97    for {set i 0} {$i < 256} {incr i} {
98        if {$reflected} {
99            set r [reflect $i 8]
100        } else {
101            set r $i
102        }
103        set r [expr {$r << ($width - 8)}]
104        for {set k 0} {$k < 8} {incr k} {
105            if {[expr {$r & $topbit}] != 0} {
106                set r [expr {($r << 1) ^ $poly}]
107            } else {
108                set r [expr {$r << 1}]
109            }
110        }
111        if {$reflected} {
112            set r [reflect $r $width]
113        }
114        lappend tbl [expr {$r & $mask}]
115    }
116    return $tbl
117}
118
119# -------------------------------------------------------------------------
120# Calculate the CRC checksum for the data in 's' using a precalculated
121# table.
122#  s the input data
123#  width - the width in bits of the CRC algorithm
124#  table - the name of the variable holding the calculated table
125#  init  - the start value (or the last CRC for sequential blocks)
126#  xorout - the final value may be XORd with this value
127#  reflected - a boolean indicating that the bit order is reversed.
128#              For hardware optimised CRC checks, the bits are handled
129#              in transmission order (ie: bit0, bit1, ..., bit7)
130proc ::crc::Crc {s width table {init 0} {xorout 0} {reflected 0}} {
131    upvar $table tbl
132    variable signbit
133    set signmask [expr {~$signbit>>7}]
134
135    if {$width < 32} {
136        set mask   [expr {(1 << $width) - 1}]
137        set rot    [expr {$width - 8}]
138    } else {
139        set mask   0xffffffff
140        set rot    24
141    }
142
143    set crc $init
144    binary scan $s c* data
145    foreach {datum} $data {
146        if {$reflected} {
147            set ndx [expr {($crc ^ $datum) & 0xFF}]
148            set lkp [lindex $tbl $ndx]
149            set crc [expr {($lkp ^ ($crc >> 8 & $signmask)) & $mask}]
150        } else {
151            set ndx [expr {(($crc >> $rot) ^ $datum) & 0xFF}]
152            set lkp [lindex $tbl $ndx]
153            set crc [expr {($lkp ^ ($crc << 8 & $signmask)) & $mask}]
154        }
155    }
156
157    return [expr {$crc ^ $xorout}]
158}
159
160# -------------------------------------------------------------------------
161# Reverse the bit ordering for 'b' bits of the input value 'v'
162proc ::crc::reflect {v b} {
163    set t $v
164    for {set i 0} {$i < $b} {incr i} {
165        set v [expr {($t & 1) ? ($v | (1<<(($b-1)-$i))) : ($v & ~(1<<(($b-1)-$i))) }]
166        set t [expr {$t >> 1}]
167    }
168    return $v
169}
170
171# -------------------------------------------------------------------------
172# Description:
173#  Pop the nth element off a list. Used in options processing.
174#
175proc ::crc::Pop {varname {nth 0}} {
176    upvar $varname args
177    set r [lindex $args $nth]
178    set args [lreplace $args $nth $nth]
179    return $r
180}
181
182# -------------------------------------------------------------------------
183# Specialisation of the general crc procedure to perform the standard CRC16
184# checksum
185proc ::crc::CRC16 {s {seed 0}} {
186    variable table
187    if {![info exists table(crc16)]} {
188        variable polynomial
189        set table(crc16) [Crc_table 16 $polynomial(crc16) 1]
190    }
191
192    return [Crc $s 16 [namespace current]::table(crc16) $seed 0 1]
193}
194
195# -------------------------------------------------------------------------
196# Specialisation of the general crc procedure to perform the CCITT telecoms
197# flavour of the CRC16 checksum
198proc ::crc::CRC-CCITT {s {seed 0} {xor 0}} {
199    variable table
200    if {![info exists table(ccitt)]} {
201        variable polynomial
202        set table(ccitt) [Crc_table 16 $polynomial(ccitt) 0]
203    }
204
205    return [Crc $s 16 [namespace current]::table(ccitt) $seed $xor 0]
206}
207
208# -------------------------------------------------------------------------
209# Demostrates the parameters used for the 32 bit checksum CRC-32.
210# This can be used to show the algorithm is working right by comparison with
211# other crc32 implementations
212proc ::crc::CRC-32 {s {seed 0xFFFFFFFF}} {
213    variable table
214    if {![info exists table(crc32)]} {
215        variable polynomial
216        set table(crc32) [Crc_table 32 $polynomial(crc32) 1]
217    }
218
219    return [Crc $s 32 [namespace current]::table(crc32) $seed 0xFFFFFFFF 1]
220}
221
222# -------------------------------------------------------------------------
223# User level CRC command.
224proc ::crc::crc {args} {
225    array set opts [list filename {} channel {} chunksize 4096 \
226                        format %u  seed 0 \
227                        impl [namespace origin CRC16]]
228   
229    while {[string match -* [set option [lindex $args 0]]]} {
230        switch -glob -- $option {
231            -fi*  { set opts(filename) [Pop args 1] }
232            -cha* { set opts(channel) [Pop args 1] }
233            -chu* { set opts(chunksize) [Pop args 1] }
234            -fo*  { set opts(format) [Pop args 1] }
235            -i*   { set opts(impl) [uplevel 1 namespace origin [Pop args 1]] }
236            -s*   { set opts(seed) [Pop args 1] }
237            --    { Pop args ; break }
238            default {
239                set options [join [lsort [array names opts]] ", -"]
240                return -code error "bad option $option:\
241                       must be one of -$options"
242            }
243        }
244        Pop args
245    }
246
247    if {$opts(filename) != {}} {
248        set opts(channel) [open $opts(filename) r]
249        fconfigure $opts(channel) -translation binary
250    }
251
252    if {$opts(channel) != {}} {
253        set r $opts(seed)
254        set trans [fconfigure $opts(channel) -translation]
255        fconfigure $opts(channel) -translation binary
256        while {![eof $opts(channel)]} {
257            set chunk [read $opts(channel) $opts(chunksize)]
258            set r [$opts(impl) $chunk $r]
259        }
260        fconfigure $opts(channel) -translation $trans
261        if {$opts(filename) != {}} {
262            close $opts(channel)
263        }
264    } else {
265        if {[llength $args] != 1} {
266            return -code error "wrong \# args: should be\
267                   \"crc16 ?-format string? ?-seed value? ?-impl procname?\
268                   -file name | data\""
269        }
270        set r [$opts(impl) [lindex $args 0] $opts(seed)]
271    }
272    return [format $opts(format) $r]
273}
274
275# -------------------------------------------------------------------------
276# The user commands. See 'crc'
277#
278proc ::crc::crc16 {args} {
279    return [eval [list crc -impl [namespace origin CRC16]] $args]
280}
281
282proc ::crc::crc-ccitt {args} {
283    return [eval [list crc -impl [namespace origin CRC-CCITT] -seed 0xFFFF]\
284                $args]
285}
286
287proc ::crc::xmodem {args} {
288    return [eval [list crc -impl [namespace origin CRC-CCITT] -seed 0] $args]
289}
290
291proc ::crc::crc-32 {args} {
292    return [eval [list crc -impl [namespace origin CRC-32] -seed 0xFFFFFFFF]\
293                $args]
294}
295
296# -------------------------------------------------------------------------
297
298package provide crc16 $crc::crc16_version
299
300# -------------------------------------------------------------------------
301#
302# Local variables:
303#   mode: tcl
304#   indent-tabs-mode: nil
305# End:
Note: See TracBrowser for help on using the repository browser.