#!/usr/bin/tclsh8.2 # used like this: # liberator:hostside> ssh bessar 'cd things/trains-bessar/hostside && ./stopgap-controller' | ./gui-displayer - set testonly 0 #set testonly 1 set port /dev/ttya0 #set port /dev/ttyS0 set ch(funcsevery) 10 set ch(speeddirnevery) 30 set ch(scale) 1 set ch(minint) 5000 #unset pointasked # 0 1 (settings) M0 M1 (manual, settings) unset (random) M (manual) set nmrawhich 0 set lastptchosen xx set polmsg(l) 908000 set polmsg(x) 90f802 set polmsg(y) 90807c set pname l set m {} set nmradiv 0 set segs {xx yy} set segsasgot {xx yy} set pq {} ;# unset: cdu charged and waiting set speeddirn ff7f #set speeddirn ffff80c3fbcced7f #set speeddirn_fixed {speed126 2 80 0} set speeddirn_fixed {} set funcs ff7f # unset pointpos($point) # unset segdetect($seg) ;# unset: shown D0; {}: shown D1; or: after id, D1->0 proc gui {m} { puts "GUI $m" } proc gui_init {} { global watchdog polarity segdetect gui "M A2 0" gui "M A5 0 J" gui "M A6 0 J" gui "EOE" if {[info exists watchdog]} { gui "P 1" } gui_polarity foreach seg [array names segdetect] { gui "D1 $seg" } } proc debug {m} { puts $m } proc tellpic_q {m} { global p testonly if {$testonly} return set b [binary format H* $m] puts -nonewline $p $b } proc tellpic {m} { puts ">> $m" tellpic_q $m } proc bgerror {m} { if {[catch { global errorInfo errorCode puts stderr "$m\n$errorCode\n$errorInfo" fail "bgerror $m" } emsg]} { exit 127 } } proc fail_now {} { global p debug "failing now" fconfigure $p -blocking yes gui "P 0" tellpic 10 exit 1 } proc fail {m} { global watchdog p catch { after cancel $watchdog; unset watchdog } puts "failing $m" tellpic 9801 ;# 16ms after 1000 fail_now fileevent $p readable {} } proc gui_polarity {} { global pname set 1 {} switch -exact $pname { l { lappend 0 X1 X3 X5 X7 X9; lappend 0 X2 X4 X6 X8 X10 } x { lappend 1 X1 X3 X5 X7 X9; lappend 0 X2 X4 X6 X8 X10 } y { lappend 0 X1 X3 X5 X7 X9; lappend 1 X2 X4 X6 X8 X10 } } foreach v {0 1} { foreach seg [set $v] { gui "R $v $seg" } } } proc polarity {newpname} { global pname polmsg debug "polarising $newpname" if {![string compare $pname $newpname]} return tellpic $polmsg($newpname) set pname $newpname gui_polarity } proc pt_now {how point pos xtra} { set msg a0[lindex $point $pos] debug "$how point $point pos=$pos msg=$msg$xtra" gui "M [lindex $point 2] [expr {!$pos}]" tellpic $msg } proc pt_must {point newpos} { upvar #0 pointpos($point) pos global pq if {[info exists pos] && $pos == $newpos} return set pos $newpos if {[info exists pq]} { lappend pq [list $point $pos] debug "queue point $point pos=$pos l=[llength $pq]" return } pt_now immed $point $pos {} set pq {} } proc pt_ifthenmust {ifpoint ifposwant thenpoint thenpos} { upvar #0 pointpos($ifpoint) ifpos if {![info exists ifpos] || $ifpos != $ifposwant} return pt_must $thenpoint $thenpos } proc badwatchdog {} { global pq puts "watchdog - oh well" if {![info exists pq]} { set pq {} } } proc pm_charged {} { global pq if {[llength $pq]} { set v [lindex $pq 0] set pq [lrange $pq 1 end] pt_now nowdo [lindex $v 0] [lindex $v 1] " l=[llength $pq]" } else { debug "cdu-charged" unset pq } } proc randbyte {} { global rand set c [read $rand 1]; if {![string length $c]} { error "eof on rand" } binary scan $c H* x return $x } proc pt_maybe {point oneisright} { global pointasked lastptchosen if {![info exists pointasked]} { if {![string compare $point $lastptchosen]} return set lastptchosen $point set x [randbyte] set pos [expr [regexp {^[89a-f]} $x] ? 1 : 0] debug "chose point $point pos=$pos (x=$x)" } elseif {[regexp {^M([01])$} $pointasked dummy pos]} { if {[lsearch -exact {40 02} [lindex $point 0]] >= 0} { set pos [expr {!$pos}] debug "chose point $point pos=$pos manual-rl" } else { debug "chose point $point pos=$pos manual-lr" } set pointasked M } elseif {![string compare $pointasked M]} { debug "leave point $point pos=$pos manual" return } else { debug "fixed point $point pos=$pos" set pos $pointasked } pt_must $point $pos } proc s0 {v seg} { upvar #0 segdetect($seg) segd if {![info exists segd]} { debug "segment $seg = already" } elseif {[string length $segd]} { debug "segment $seg = pending already" } else { debug "segment $seg = soon" set segd [after 100 s0t $seg] } } proc s0t {seg} { upvar #0 segdetect($seg) segd debug "segment $seg = now" unset segd gui "D0 $seg" } proc s1 {v seg} { upvar #0 segdetect($seg) segd if {![info exists segd]} { pm_detect $v debug "segment $seg ! (overwrites =)" } elseif {[string length $segd]} { debug "segment $seg ! (cancels =)" after cancel $segd } else { debug "segment $seg ! already" return } gui "D1 $seg" set segd {} } proc pm_maydetect {d seg} { switch -exact $seg { 06 { s$d $seg X10 } 09 { s$d $seg X8 } 0a { s$d $seg X6 } 04 { s$d $seg X5 } 02 { s$d $seg X7 } 07 { s$d $seg X9 } 14 { s$d $seg A5 } 20 { s$d $seg A6 } 1a { s$d $seg A4 } 10 { s$d $seg A2 } 03 { s$d $seg X1 } 05 { s$d $seg X3 } 16 { s$d $seg A3 } 1c { s$d $seg A1 } 08 { s$d $seg X2 } 0b { s$d $seg X4 } } } #proc pm_nodetect {seg} { # global segsasgot # if {![string compare $seg [lindex $segsasgot 1]]} { # set segsasgot [list [lindex $segsasgot 1] [lindex $segsasgot 0]] # } #} proc pm_detect {seg} { global segs pname segsasgot if {[string compare $seg [lindex $segsasgot 1]]} { set segsasgot [list [lindex $segsasgot 1] $seg] } if {[lsearch -exact $segs $seg] < 0} { set segs $segsasgot } debug "pm_detect $seg ($segsasgot) ($segs) $pname$seg" # if {[lsearch -exact { # 06 09 0a 04 02 07 14 20 # 0b 08 1c 16 # 1a 10 03 05 # } $seg] < 0} return switch -exact $pname$seg { l16 - l1c - l08 - l0b { polarity y } l10 - l1a - l03 - l05 { polarity x } x07 - x04 - x0a { polarity l } x16 - x1c - x14 - x0b { polarity y } y06 - y04 - y0a { polarity l } y20 - y10 - y1a - y05 { polarity x } } switch -exact $seg { 04 - 0a { pt_must "00 01 X7" 1; pt_must "40 41 X8" 1 } 05 { pt_must "00 01 X7" 0 } 0b { pt_must "40 41 X8" 0 } 16 - 1c { pt_must "02 03 A5" 0 } 1a - 10 { pt_must "42 43 A6" 0 } 14 { pt_ifthenmust "02 03 A5" 1 "42 43 A6" 1 } 20 { pt_ifthenmust "42 43 A6" 1 "02 03 A5" 1 } } switch -exact [join $segs -] { 02-07 { pt_maybe "02 03 A5" 1 } 07-02 { pt_maybe "00 01 X7" 0 } 09-06 { pt_maybe "42 43 A6" 0 } 06-09 { pt_maybe "40 41 X8" 1 } } } proc tellnmra {m} { # global nmrawhich speeddirn funcs # set m 0x$m # for {set i 0} {$i < $m} {incr i} { # tellpic_q [lindex [list $speeddirn $funcs] $nmrawhich] # set nmrawhich [expr {!$nmrawhich}] # } } proc watchdog {} { global watchdog testonly speeddirn funcs nmradiv catch { after cancel $watchdog } set watchdog [after 50 watchdog] tellpic_q 9808 ;# 128ms if {[incr nmradiv] > 35} { tellpic_q $speeddirn$funcs set nmradiv 0 } } proc pm_hello {} { debug "got hello, starting up" tellpic 11 gui "P 1" watchdog changewhat tellnmra 01 } proc fp {m} { debug "<< $m" } proc frompic {m} { set v [lindex $m 1] switch -glob [lindex $m 0] { 01 - 02 { tellnmra $m } 09 { fp $m; pm_hello } 07 { puts "short circuit"; exit 1 } 0d { fp $m; badwatchdog } 28 { fp $m; pm_charged } 9[0-7] { fp $m; pm_maydetect 0 $v } 9? { fp $m; pm_maydetect 1 $v } 0a - [234567]? { puts "pic debug $m" } * { fp $m; fail "pic unknown $m" } } } proc onreadp_test {} { if {![gets stdin m]} { return } frompic $m } proc onreadp {} { global p m rand while 1 { set c [read $p 1] if {![string length $c]} { if {[eof $p]} { error "eof on device" } return } binary scan $c H* x if {![info exists rand]} { fp ...$x return } lappend m $x if {[regexp {^[0-7]} $x]} { if {![regexp {^x} $m]} { frompic $m } set m {} } } } proc newspeeddirn {} { set b1 0x[randbyte] set speed [expr {round(($b1 * $b1) / 65535.0 * 100.0 + 26.0)}] set b2 0x[randbyte] set dirn [expr {$b2 / 128}] set dirn 0 debug "speeddirn b1=$b1 speed=$speed b2=$b2 dirn=$dirn" return "speed126 2 $speed $dirn" } proc newfuncs {} { set b3 0x[randbyte] set value [expr {($b3 & 127) * 16}] debug "funcs b3=$b3 value=[format %x $value]" return "funcs5to8 2 $value" } proc maybechange {thing} { global $thing ch upvar #0 ${thing}_fixed fixed if {![info exists fixed]} { set rb 0x[randbyte][randbyte] if { $rb / 65536.0 > 1.0 / (($ch(${thing}every) - $ch(minint)*0.001) * $ch(scale)) } { debug "maybechange $thing rb=$rb no" return 0 } debug "maybechange $thing rb=$rb yes ..." set l [new$thing] } else { debug "fixed $thing $fixed" set l $fixed if {![llength $l]} { return 0 } } set bin [eval exec ./hostside-old -s/dev/stdout $l] binary scan $bin H* x debug "changed $thing=$x" set $thing ff$x return 1 } proc changewhat {} { global ch chwa catch { after cancel $chwa } if {[maybechange speeddirn] || [maybechange funcs]} { set interval $ch(minint) } else { set interval 1000 } set chwa [after $interval changewhat] } proc onreadcmd {} { if {[gets stdin l] < 0} { if {[eof stdin]} { puts "GUI exit 0" fail "stopgap-controller got eof, quitting" fileevent stdin readable {} } return } eval $l } proc setup {} { global port p testonly if {!$testonly} { set p [open $port {RDWR NONBLOCK} 0] exec stty -F $port min 1 time 0 -istrip -ocrnl -onlcr -onocr -opost \ -ctlecho -echo -echoe -echok -echonl -iexten -isig \ -icanon -icrnl \ 9600 clocal cread crtscts -hup -parenb cs8 -cstopb \ -ixoff bs0 cr0 ff0 nl0 -ofill -olcuc fconfigure $p -encoding binary -translation binary \ -blocking false -buffering none fileevent $p readable onreadp fconfigure stdin -blocking false fileevent stdin readable onreadcmd } else { set p stdin fconfigure stdin -blocking false fileevent stdin readable onreadp_test } after 250 setup_complete } proc setup_complete {} { global rand set rand [open /dev/urandom {RDONLY} 0] fconfigure $rand -encoding binary -translation binary tellpic 0a } #---------- # for keyboard control proc ask_fast {} { global speeddirn_fixed; set speeddirn_fixed {speed126 2 126 0} } proc ask_slow {} { global speeddirn_fixed; set speeddirn_fixed {speed126 2 10 0} } proc ask_randspeed {} { global speeddirn_fixed; catch { unset speeddirn_fixed } } proc ask_manual {rightp} { global pointasked; set pointasked M$rightp } proc ask_figureeightt {rightp} { global pointasked; set pointasked 0 } proc ask_loop {rightp} { global pointasked; set pointasked 1 } proc ask_randpath {rightp} { global pointasked; catch { unset pointasked } } setup gui_init vwait end