crc16.tcl
Go to the documentation of this file.00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 
00028 
00029 
00030 
00031 
00032 
00033 
00034 
00035 
00036 
00037 
00038 
00039 
00040 
00041 
00042 
00043 
00044 
00045 
00046 package require Tcl 8.2;                
00047 
00048 namespace ::crc {
00049     
00050     namespace export crc16 crc-ccitt crc-32
00051 
00052     variable crc16_version 1.1.1
00053 
00054     
00055     variable polynomial
00056      polynomial = (crc16) [expr {(1<<16) | (1<<15) | (1<<2) | 1}]
00057      polynomial = (ccitt) [expr {(1<<16) | (1<<12) | (1<<5) | 1}]
00058      polynomial = (crc32) [expr {(1<<32) | (1<<26) | (1<<23) | (1<<22) 
00059                                  | (1<<16) | (1<<12) | (1<<11) | (1<<10)
00060                                  | (1<<8) | (1<<7) | (1<<5) | (1<<4)
00061                                  | (1<<2) | (1<<1) | 1}]
00062 
00063     
00064     variable table
00065     if {![info exists table]} { array  table =  {}}
00066 
00067     
00068     variable signbit
00069     if {![info exists signbit]} {
00070     variable v
00071         for { v =  1} {int($v) != 0} { signbit =  $v;  v =  [expr {$v<<1}]} {}
00072         un v = 
00073     }
00074 }
00075 
00076 
00077 
00078 
00079 
00080 
00081 
00082 
00083 
00084 
00085 
00086 
00087 ret  ::crc::Crc_table (type width , type poly , type reflected) {
00088     set tbl {}
00089     if {$width < 32} {
00090         set mask   [expr {(1 << $width) - 1}]
00091         set topbit [expr {1 << ($width - 1)}]
00092     } else {
00093         set mask   0xffffffff
00094         set topbit 0x80000000
00095     }
00096 
00097     for {set i 0} {$i < 256} {incr i} {
00098         if {$reflected} {
00099             set r [reflect $i 8]
00100         } else {
00101             set r $i
00102         }
00103         set r [expr {$r << ($width - 8)}]
00104         for {set k 0} {$k < 8} {incr k} {
00105             if {[expr {$r & $topbit}] != 0} {
00106                 set r [expr {($r << 1) ^ $poly}]
00107             } else {
00108                 set r [expr {$r << 1}]
00109             }
00110         }
00111         if {$reflected} {
00112             set r [reflect $r $width]
00113         }
00114         lappend tbl [expr {$r & $mask}]
00115     }
00116     return $tbl
00117 }
00118 
00119 
00120 
00121 
00122 
00123 
00124 
00125 
00126 
00127 
00128 
00129 
00130 ret  ::crc::Crc (type s , type width , type table , optional init =0 , optional xorout =0 , optional reflected =0) {
00131     upvar $table tbl
00132     variable signbit
00133     set signmask [expr {~$signbit>>7}]
00134 
00135     if {$width < 32} {
00136         set mask   [expr {(1 << $width) - 1}]
00137         set rot    [expr {$width - 8}]
00138     } else {
00139         set mask   0xffffffff
00140         set rot    24
00141     }
00142 
00143     set crc $init
00144     binary scan $s c* data
00145     foreach {datum} $data {
00146         if {$reflected} {
00147             set ndx [expr {($crc ^ $datum) & 0xFF}]
00148             set lkp [lindex $tbl $ndx]
00149             set crc [expr {($lkp ^ ($crc >> 8 & $signmask)) & $mask}]
00150         } else {
00151             set ndx [expr {(($crc >> $rot) ^ $datum) & 0xFF}]
00152             set lkp [lindex $tbl $ndx]
00153             set crc [expr {($lkp ^ ($crc << 8 & $signmask)) & $mask}]
00154         }
00155     }
00156 
00157     return [expr {$crc ^ $xorout}]
00158 }
00159 
00160 
00161 
00162 ret  ::crc::reflect (type v , type b) {
00163     set t $v
00164     for {set i 0} {$i < $b} {incr i} {
00165         set v [expr {($t & 1) ? ($v | (1<<(($b-1)-$i))) : ($v & ~(1<<(($b-1)-$i))) }]
00166         set t [expr {$t >> 1}]
00167     }
00168     return $v
00169 }
00170 
00171 
00172 
00173 
00174 
00175 ret  ::crc::Pop (type varname , optional nth =0) {
00176     upvar $varname args
00177     set r [lindex $args $nth]
00178     set args [lreplace $args $nth $nth]
00179     return $r
00180 }
00181 
00182 
00183 
00184 
00185 ret  ::crc::CRC16 (type s , optional seed =0) {
00186     variable table
00187     if {![info exists table(crc16)]} {
00188         variable polynomial
00189         set table(crc16) [Crc_table 16 $polynomial(crc16) 1]
00190     }
00191 
00192     return [Crc $s 16 [namespace current]::table(crc16) $seed 0 1]
00193 }
00194 
00195 
00196 
00197 
00198 ret  ::crc::CRC-CCITT (type s , optional seed =0 , optional xor =0) {
00199     variable table
00200     if {![info exists table(ccitt)]} {
00201         variable polynomial
00202         set table(ccitt) [Crc_table 16 $polynomial(ccitt) 0]
00203     }
00204 
00205     return [Crc $s 16 [namespace current]::table(ccitt) $seed $xor 0]
00206 }
00207 
00208 
00209 
00210 
00211 
00212 ret  ::crc::CRC-32 (type s , optional seed =0xFFFFFFFF) {
00213     variable table
00214     if {![info exists table(crc32)]} {
00215         variable polynomial
00216         set table(crc32) [Crc_table 32 $polynomial(crc32) 1]
00217     }
00218 
00219     return [Crc $s 32 [namespace current]::table(crc32) $seed 0xFFFFFFFF 1]
00220 }
00221 
00222 
00223 
00224 ret  ::crc::crc (type args) {
00225     array set opts [list filename {} channel {} chunksize 4096 \
00226                         format %u  seed 0 \
00227                         impl [namespace origin CRC16]]
00228     
00229     while {[string match -* [set option [lindex $args 0]]]} {
00230         switch -glob -- $option {
00231             -fi*  { set opts(filename) [Pop args 1] }
00232             -cha* { set opts(channel) [Pop args 1] }
00233             -chu* { set opts(chunksize) [Pop args 1] }
00234             -fo*  { set opts(format) [Pop args 1] }
00235             -i*   { set opts(impl) [uplevel 1 namespace origin [Pop args 1]] }
00236             -s*   { set opts(seed) [Pop args 1] }
00237             --    { Pop args ; break }
00238             default {
00239                 set options [join [lsort [array names opts]] ", -"]
00240                 return -code error "bad option $option:\
00241                        must be one of -$options"
00242             }
00243         }
00244         Pop args
00245     }
00246 
00247     if {$opts(filename) != {}} {
00248         set opts(channel) [open $opts(filename) r]
00249         fconfigure $opts(channel) -translation binary
00250     }
00251 
00252     if {$opts(channel) != {}} {
00253         set r $opts(seed)
00254         set trans [fconfigure $opts(channel) -translation]
00255         fconfigure $opts(channel) -translation binary
00256         while {![eof $opts(channel)]} {
00257             set chunk [read $opts(channel) $opts(chunksize)]
00258             set r [$opts(impl) $chunk $r]
00259         }
00260         fconfigure $opts(channel) -translation $trans
00261         if {$opts(filename) != {}} {
00262             close $opts(channel)
00263         }
00264     } else {
00265         if {[llength $args] != 1} {
00266             return -code error "wrong \# args: should be\
00267                    \"crc16 ?-format string? ?-seed value? ?-impl procname?\
00268                    -file name | data\""
00269         }
00270         set r [$opts(impl) [lindex $args 0] $opts(seed)]
00271     }
00272     return [format $opts(format) $r]
00273 }
00274 
00275 
00276 
00277 
00278 ret  ::crc::crc16 (type args) {
00279     return [eval [list crc -impl [namespace origin CRC16]] $args]
00280 }
00281 
00282 ret  ::crc::crc-ccitt (type args) {
00283     return [eval [list crc -impl [namespace origin CRC-CCITT] -seed 0xFFFF]\
00284                 $args]
00285 }
00286 
00287 ret  ::crc::xmodem (type args) {
00288     return [eval [list crc -impl [namespace origin CRC-CCITT] -seed 0] $args]
00289 }
00290 
00291 ret  ::crc::crc-32 (type args) {
00292     return [eval [list crc -impl [namespace origin CRC-32] -seed 0xFFFFFFFF]\
00293                 $args]
00294 }
00295 
00296 
00297 
00298 package provide crc16 $crc::crc16_version
00299 
00300 
00301 
00302 
00303 
00304 
00305 
00306