#!/usr/bin/wish
#Draw draws a LFSR sequence with recursion "rec" and initial string "init"
#Assumes that the defining polynomial is irreducible and in 
#particular that "rec" ends in 1
#The procedure Draw2 draws two LFSR sequences and adds them. Same caveats
#apply. The auxiliary procedure lfsr generates the sequence with
#the same caveats and dec decimates it. You can also add strings and
#compute their Hamming weight

proc Draw {rec init} {
global m
set seq [lfsr $rec $init]
set m [string length $rec]
if {[winfo exists .c]} {
destroy .c
}
pack [canvas .c -height 200 -width 1000 -background #FF7533]
.c create line 0 100 1000 100
.c create line 0 150 1000 150
for {set i 1} {$i < 20} {incr i} {
.c create line [expr 50*$i] 100 [expr 50*$i] 150
}
.c create line [expr 975 - 50*$m] 100 [expr 975 - 50*$m] \
 75 975 75 975 100 -fill blue -arrow last
.c create text [expr 975 - 50*$m]  125 -text [string index $init 0] \
 -fill purple -font {helvetica 24 bold} -tag a
for {set i 1} {$i < $m} {incr i} {
if {[string index $rec [expr $m - 1 - $i]] == 1} {
.c create line [expr 975 - 50*($m - $i)] 100 [expr 975 - 50*($m - $i)] 75 \
-fill blue
.c create text [expr 975 - 50*($m - $i)]  125 -text [string index $init $i] \
 -fill purple -font {helvetica 24 bold} -tag a
.c create oval [expr 970 - 50*($m - $i)]  70 [expr 980 - 50*($m - $i)] \
80 -outline red
.c create line [expr 975 - 50*($m - $i)]  70 [expr 975 - 50*($m - $i)] \
80 -fill red
.c create line [expr 970 - 50*($m - $i)]  75 [expr 980 - 50*($m - $i)] \
75 -fill red
} else {
.c create text [expr 975 - 50*($m - $i)]  125 -text  [string index $init $i] \
-fill purple -font {helvetica 24 bold} -tag a
}
}
.c create text 975 125 -text [string index $seq $m] \
 -fill purple -font {helvetica 24 bold} -tag a
bind .c <1> "Next $rec $init"
}
proc Next {rec init} {
global m
incr m
set seq [lfsr $rec $init]
set n [string length $seq] 
.c move a -50 0
update idletasks
after 1000
.c create text 975 125 -text [string index $seq [expr $m%$n]] \
  -fill purple -font {helvetica 24 bold} -tag a
update idletasks
}

proc lfsr {rec init} {
set out $init
set m [string length $rec]
if {[string length $init] != $m} {
puts "error, initial string of wrong length"
} else {
set n $m
while {$n < [expr {pow(2,$m) - 1}]} {
set x 0
for {set i 0} {$i < $m} {incr i} {
set x [expr {$x+[string index $rec $i]*[string index $out [expr {$n - $i - 1}]]}]
}
incr n
append out [expr {$x%2}]
}
}
return $out
}

#decimation by d of a LFSR sequence given rec init and d

proc dec {rec init d} {
set m [string length $rec]
if {[string length $init] != $m} {
puts "error, initial string of wrong length"
} else {
set n [expr {int(pow(2,$m) - 1)}]
set seq [lfsr $rec $init]
for {set i 0} {$i < $n} {incr i} {
append out [string index $seq [expr ($i*$d)%$n]]
}
}
return $out
}


##########################
#the sum of a and b
##########################

proc Plus {a b} {
set t $a
set n [string length $b]
if {[string length $a] < $n} {
set n [string length $a]
set t $b
}
for {set i 0} {$i < $n} {incr i} {
append s [expr {[string index $a $i]^[string index $b $i]}]
}
append s [string range $t $n [string length $t]]
return $s
}

#hamming weight of a string

proc Weight {foo} {
set n [string length $foo]
set k 0
for {set i 0} {$i < $n} {incr i} {
if {[string index $foo $i] == 1 } {
incr k
}
}
return $k
}

#shift a string

proc shift {foo} {
set r [string range $foo 1 end]
append r [string index $foo 0]
return $r
}

proc Draw2 {rec1 init1 rec2 init2} {
global m
set seq1 [lfsr $rec1 $init1]
set seq2 [lfsr $rec2 $init2]
set m [string length $rec1]
if {[winfo exists .c]} {
destroy .c
}
pack [canvas .c -height 600 -width 1000 -background #FF6633]
.c create line 0 100 1000 100
.c create line 0 150 1000 150
.c create line 0 300 1000 300
.c create line 0 350 1000 350
.c create line 0 500 1000 500
.c create line 0 550 1000 550
for {set j 0} {$j < 3} {incr j} {
for {set i 1} {$i < 20} {incr i} {
.c create line [expr 50*$i] [expr 100 + 200*$j] [expr 50*$i] [expr 150 + 200*$j]
}}
.c create line [expr 975 - 50*$m] 100 [expr 975 - 50*$m] \
 75 975 75 975 100 -fill blue -arrow last
.c create line 975 150 975 300 -fill blue -arrow last
.c create line 975 500 975 350 -fill blue -arrow last
.c create text [expr 975 - 50*$m]  125 -text [string index $init1 0] \
 -fill purple -font {lucida 18 bold} -tag a
.c create line [expr 975 - 50*$m] 550 [expr 975 - 50*$m] \
 575 975 575 975 550 -fill blue -arrow last
.c create text [expr 975 - 50*$m]  525 -text [string index $init2 0] \
 -fill purple -font {lucida 18 bold} -tag a
.c create text [expr 975 - 50*$m]  325 \
-text [expr [string index $init1 0]^[string index $init2 0]] \
-fill purple -font {lucida 18 bold} -tag a

for {set i 1} {$i < $m} {incr i} {
if {[string index $rec1 [expr $m - 1 - $i]] == 1} {
.c create line [expr 975 - 50*($m - $i)] 100 [expr 975 - 50*($m - $i)] 75 \
-fill blue
.c create text [expr 975 - 50*($m - $i)]  125 -text [string index $init1 $i] \
 -fill purple -font {lucida 18 bold} -tag a
.c create oval [expr 970 - 50*($m - $i)]  70 [expr 980 - 50*($m - $i)] \
80 -outline red
.c create line [expr 975 - 50*($m - $i)]  70 [expr 975 - 50*($m - $i)] \
80 -fill red
.c create line [expr 970 - 50*($m - $i)]  75 [expr 980 - 50*($m - $i)] \
75 -fill red
} else {
.c create text [expr 975 - 50*($m - $i)]  125 -text  [string index $init1 $i] \
-fill purple -font {lucida 18 bold} -tag a
}
if {[string index $rec2 [expr $m - 1 - $i]] == 1} {
.c create line [expr 975 - 50*($m - $i)] 550 [expr 975 - 50*($m - $i)] 575 \
-fill blue
.c create text [expr 975 - 50*($m - $i)]  525 -text [string index $init2 $i] \
 -fill purple -font {lucida 18 bold} -tag a
.c create oval [expr 970 - 50*($m - $i)]  570 [expr 980 - 50*($m - $i)] \
580 -outline red
.c create line [expr 975 - 50*($m - $i)]  570 [expr 975 - 50*($m - $i)] \
580 -fill red
.c create line [expr 970 - 50*($m - $i)]  575 [expr 980 - 50*($m - $i)] \
575 -fill red
} else {
.c create text [expr 975 - 50*($m - $i)]  525 -text  [string index $init2 $i] \
-fill purple -font {lucida 18 bold} -tag a
}
.c create text [expr 975 - 50*($m - $i)]  325 \
-text  [expr [string index $init1 $i]^[string index $init2 $i]] \
-fill purple -font {lucida 18 bold} -tag a
}
.c create text 975 125 -text [string index $seq1 $m] \
 -fill purple -font {lucida 18 bold} -tag a
.c create text 975 525 -text [string index $seq2 $m] \
 -fill purple -font {lucida 18 bold} -tag a
.c create text 975 325 \
-text  [expr [string index $seq1 $i]^[string index $seq2 $i]] \
 -fill purple -font {lucida 18 bold} -tag a
bind .c <1> "Next2 $rec1 $init1 $rec2 $init2"
}
proc Next2 {rec1 init1 rec2 init2} {
global m
incr m
set seq1 [lfsr $rec1 $init1]
set seq2 [lfsr $rec2 $init2]
set n [string length $seq1] 
.c move a -50 0
update idletasks
after 1000
.c create text 975 125 -text [string index $seq1 [expr $m%$n]] \
  -fill purple -font {lucida 18 bold} -tag a
.c create text 975 525 -text [string index $seq2 [expr $m%$n]] \
  -fill purple -font {lucida 18 bold} -tag a
.c create text 975 325 \
-text [expr [string index $seq1 [expr $m%$n]]^[string index $seq2 [expr $m%$n]]] \
  -fill purple -font {lucida 18 bold} -tag a
update idletasks
}

Draw2 1101 1000 1011 1000
