Files
sics/site_ansto/instrument/tas/config/tasmad/sicscommon/el734.tcl
2014-05-16 17:23:58 +10:00

489 lines
15 KiB
Tcl

#--------------------------------------------------------
# This is a scriptcontext based driver for the EL734
# motor controller. This is part of an ongoing effort to
# expire older drivers and to consolidate on the new
# scriptcontext system.
#
# Scriptchains:
# Rather then having long script chains many of the
# intricacies of the EL734 are handled via a command
# processing state machine. See the docs below for
# details
#
# copyright: see file COPYRIGHT
#
# Mark Koennecke, February 2011
#--------------------------------------------------------
namespace eval el734 {}
#---------------------------------------------------------
# The EL734 is a a tricky thing. Some special conditions
# apply:
# - On emergency stop an *ES is sent. But only the second
# response of this kind is valid because there can be
# spurious *ES on the line even when the emergency stop
# has been released.
# - If someone fingers the EL734 or after startup it is in
# local mode. Then two commands have to be sent in order to
# make it go into remote mode before retrying the command.
# - In some echo modes of the controller it sends a echo
# of the command. This has to be ignored in order to get at
# the real problem
#
# In order to deal with all this, el734::command is implemented
# as a state machine which calls another script when a valid
# reponse has actually been found.
# The state of the current command processing
# is saved in a node property comstate. The actual command to send
# is in the property comstring. The script to call if we actually
# have a valid response is stored in the property comresponse
#---------------------------------------------------------------
proc el734::setcommand {command responsescript {motno 0}} {
sct comresponse $responsescript
sct comstate start
sct comstring $command
sct commotno $motno
return command
}
#---------------------------------------------------------------
# As implemented now this can go in an endless loop if switching
# to local fails repeatedly. TODO: test if this happens with the
# real device
#---------------------------------------------------------------
proc el734::command {} {
set state [sct comstate]
switch $state {
start {
set com [sct comstring]
sct send $com
sct comstate waitresponse
}
waitstart {
wait 1
sct comstate start
return [el734::command]
}
waitresponse {
set reply [sct result]
if {[string first "*ES" $reply] >= 0} {
set com [sct comstring]
sct send $com
sct comstate waitES
return command
}
if {[string first "?LOC" $reply] >= 0} {
sct send "RMT 1"
sct comstate waitrmt
return command
}
if {[string first "?BSY" $reply] >= 0} {
set mot [sct commotno]
if {$mot != 0} {
set com [format "S %d" $mot]
} else {
set com "S"
}
sct send $com
sct comstate waitstart
return command
}
set com [sct comstring]
set idx [string first $com $reply]
if {[string first $com $reply] >= 0} {
sct send @@NOSEND@@
sct comstate waitresponse
return command
}
set responsescript [sct comresponse]
return [eval $responsescript]
}
waitES {
set reply [sct result]
if {[string first "*ES" $reply] >= 0} {
clientput "Emergency STOP ENGAGED, release to continue"
error "Emergency Stop ENGAGED"
}
set responsescript [sct comresponse]
return [eval $responsescript]
}
waitrmt {
sct send "ECHO 0"
sct comstate start
}
}
return command
}
#-------------------------------------------------------------------
proc el734::checkerror {} {
set err(?ADR) "Bad address"
set err(?CMD) "Bad command"
set err(?PAR) "Bad parameter"
set err(?RNG) "Parameter out of range"
set err(?BSY) "Motor busy"
set err(*MS) "Bad step"
set err(*ES) "Emergency stop engaged"
set reply [string trim [sct result]]
set errlist [array names err]
foreach entry $errlist {
if {[string first $entry $reply] >= 0} {
error $err($entry)
}
}
return $reply
}
#========================== Position ===============================
proc el734::readpos {num} {
set com [format "u %d" $num]
return [el734::setcommand $com el734::posresponse]
}
#-------------------------------------------------------------------
proc el734::posresponse {} {
set stat [catch {checkerror} reply]
if {$stat == 0} {
sct update $reply
return idle
} else {
clientput $reply
return idle
}
}
#-------------------------------------------------------------------
proc el734::setpos {name num} {
set newpos [sct target]
set com [format "p %d %f" $num $newpos]
hupdate /sics/${name}/status run
hupdate /sics/${name}/oredmsr 3
hupdate /sics/${name}/runfault 0
hupdate /sics/${name}/posfault 0
return [el734::setcommand $com "el734::setposresponse $name"]
}
#-------------------------------------------------------------------
proc el734::setposresponse {name} {
set stat [catch {checkerror} reply]
if {$stat == 0} {
[sct controller] queue /sics/${name}/status progress read
return idle
} else {
clientput $reply
return idle
}
}
#===================== Limits =====================================
proc el734::getlim {name num} {
set com [format "H %d" $num]
return [el734::setcommand $com "el734::limresponse $name"]
}
#-----------------------------------------------------------------
proc el734::limresponse {name} {
set stat [catch {checkerror} reply]
if {$stat == 0} {
stscan $reply "%f %f" low high
hupdate /sics/${name}/hardlowerlim $low
hupdate /sics/${name}/hardupperlim $high
return idle
} else {
clientput $reply
return idle
}
}
#------------------------------------------------------------------
proc el734::setlim {controller name num low high} {
set com [format "H %d %f %f" $num $low $high]
$controller send $com
$controller queue /sics/${name}/hardlowerlim progress read
wait 1
return Done
}
#======================== status ================================
proc el734::decodemsr {name msr} {
set oredata(0x02) idle:none
set oredata(0x10) error:lowlim
set oredata(0x20) error:hilim
set oredata(0x80) posfault:runfault
set oredata(0x200) posfault:posfault
set oredata(0x1000) "error:air cushion"
set oredata(0x40) "error:bad step"
set oredata(0x100) error:positionfault
set oredata(0x400) error:positionfault
set msrdata(0x20) hilim
set msrdata(0x10) lowlim
set msrdata(0x1000) "air cushion"
set msrdata(0x40) "Bad step"
set msrdata(0x100) posfault
set msrdata(0x400) posfault
set oredmsr [hval /sics/${name}/oredmsr]
if {$msr == 0} {
#-------- FINISHED
set pos [hval /sics/${name}/posfault]
set run [hval /sics/${name}/runfault]
if {$pos > 0 || $run > 0} {
return posfault
}
set orlist [array names oredata]
foreach code $orlist {
if {$oredmsr & $code} {
set l [split $oredata($code) :]
set txt [lindex $l 1]
set ret [lindex $l 0]
hupdate /sics/${name}/lasterror $txt
if {[string compare $ret error] == 0} {
clientput "ERROR: $txt on motor $name"
}
return $ret
}
}
if {$oredmsr == 0} {
return idle
}
} else {
#------------ Still Running.........
set msrlist [array names msrdata]
foreach code $msrlist {
if {$msr & $code} {
clientput "ERROR: $msrdata($code) on motor $name"
return error
}
}
if {$msr & 0x80} {
set val [hval /sics/${name}/runfault]
incr val
hupdate /sics/${name}/runfault $val
}
if {$msr & 0x200} {
set val [hval /sics/${name}/posfault]
incr val
hupdate /sics/${name}/posfault $val
}
hupdate /sics/${name}/oredmsr [expr $oredmsr | $msr]
return run
}
}
#----------------------------------------------------------------
proc el734::readstatus {num name} {
set com [format "msr %d" $num]
return [el734::setcommand $com "el734::statresponse $name $num"]
}
#----------------------------------------------------------------
proc el734::statresponse {name num} {
set stat [catch {checkerror} reply]
if {$stat == 0} {
stscan $reply "%d" msr
set status [el734::decodemsr $name $msr]
sct update $status
switch $status {
run {
set con [sct controller]
$con queue /sics/${name}/hardposition progress read
$con queue /sics/${name}/status progress read
}
idle {
set com [format "u %d" $num]
return [el734::setcommand $com "el734::posstat $name" ]
}
}
return idle
} else {
clientput $reply
return idle
}
}
#----------------------------------------------------------------
proc el734::posstat {name} {
set stat [catch {checkerror} reply]
if {$stat == 0} {
hupdate /sics/${name}/hardposition $reply
return idle
} else {
clientput $reply
return idle
}
}
#========================== Halt =================================
proc el734::halt {controller no} {
set com [format "S %d" $no]
$controller send $com
return Done
}
#========================= Speed ================================
proc el734::readspeed {num} {
set com [format "J %d" $num]
return [el734::setcommand $com el734::speedresponse]
}
#-------------------------------------------------------------------
proc el734::speedresponse {} {
set stat [catch {checkerror} reply]
if {$stat == 0} {
sct update $reply
return idle
} else {
clientput $reply
return idle
}
}
#-------------------------------------------------------------------
proc el734::setspeed {name num} {
set newpos [sct target]
set com [format "J %d %d" $num $newpos]
return [el734::setcommand $com "el734::setspeedresponse $name $num"]
}
#-------------------------------------------------------------------
proc el734::setspeedresponse {name num} {
set stat [catch {checkerror} reply]
if {$stat == 0} {
return [el734::readspeed $num]
} else {
clientput $reply
return idle
}
}
#========================= refnull ================================
proc el734::readref {num} {
set com [format "V %d" $num]
return [el734::setcommand $com el734::refresponse]
}
#-------------------------------------------------------------------
proc el734::refresponse {} {
set stat [catch {checkerror} reply]
if {$stat == 0} {
sct update $reply
return idle
} else {
clientput $reply
return idle
}
}
#-------------------------------------------------------------------
proc el734::setref {name num} {
set newpos [sct target]
set com [format "V %d %d" $num $newpos]
return [el734::setcommand $com "el734::setrefresponse $name $num"]
}
#-------------------------------------------------------------------
proc el734::setrefresponse {name num} {
set stat [catch {checkerror} reply]
if {$stat == 0} {
return [el734::readref $num]
} else {
clientput $reply
return idle
}
}
#============================= SS =================================
proc el734::readss {num} {
set com [format "SS %d" $num]
sct send $com
return ssread
}
#-----------------------------------------------------------------
proc el734::ssread {} {
sct update [sct result]
return idle
}
#======================== setpos ================================
proc el734::forcepos {controller name num newpos} {
set com [format "U %d %f" $num $newpos]
$controller send $com
$controller queue /sics/${name}/hardposition progress read
wait 1
return Done
}
#======================= refrun ==================================
proc el734::refrun {controller name num} {
clientput "Starting reference run"
$controller send [format "R %d" $num]
$controller queue /sics/${name}/ss progress read
while {1} {
wait 2
set ss [hval /sics/${name}/ss]
if { [string first ?BSY $ss] < 0} {
break
}
set rupt [getint]
if { [string compare $rupt continue] != 0} {
error "Refererence run interrupted"
}
$controller queue /sics/${name}/ss progress read
}
$controller queue /sics/${name}/hardposition progress read
wait 2
return "Reference run Finished"
}
#================================================================
proc el734::reset {name} {
set x [hval /sics/${name}/hardlowerlim]
hupdate /sics/${name}/softlowerlim $x
set x [hval /sics/${name}/hardupperlim]
hupdate /sics/${name}/softupperlim $x
hupdate /sics/${name}/softzero 0
hupdate /sics/${name}/fixed -1
}
#========================= Make ==================================
proc el734::make {name no controller} {
MakeSecMotor $name
hfactory /sics/${name}/oredmsr plain internal int
hfactory /sics/${name}/runfault plain internal int
hfactory /sics/${name}/posfault plain internal int
hfactory /sics/${name}/lasterror plain internal text
hsetprop /sics/${name}/hardposition read el734::readpos $no
hsetprop /sics/${name}/hardposition command el734::command
hsetprop /sics/${name}/hardposition write el734::setpos $name $no
hsetprop /sics/${name}/hardposition command el734::command
$controller write /sics/${name}/hardposition
hsetprop /sics/${name}/hardlowerlim read el734::getlim $name $no
hsetprop /sics/${name}/hardlowerlim command el734::command
$controller poll /sics/${name}/hardlowerlim 120
hsetprop /sics/${name}/status read el734::readstatus $no $name
hsetprop /sics/${name}/status command el734::command
$controller poll /sics/${name}/status 40
hfactory /sics/${name}/speed plain user int
hsetprop /sics/${name}/speed read el734::readspeed $no
hsetprop /sics/${name}/speed command el734::command
$controller poll /sics/${name}/speed 120
hsetprop /sics/${name}/speed write el734::setspeed $name $no
hsetprop /sics/${name}/speed command el734::command
$controller write /sics/${name}/speed
$name makescriptfunc halt "el734::halt $controller $no" user
$name makescriptfunc reset "el734::reset $name" user
$name makescriptfunc sethardlim "el734::setlim $controller $name $no" mugger
hfactory /sics/${name}/sethardlim/low plain mugger float
hfactory /sics/${name}/sethardlim/high plain mugger float
hfactory /sics/${name}/motno plain internal int
hupdate /sics/${name}/motno $no
}
#-------------------------------------------------------------------------------
proc el734::addrefstuff {name no controller} {
hfactory /sics/${name}/refnull plain user int
hsetprop /sics/${name}/refnull read el734::readref $no
hsetprop /sics/${name}/refnull command el734::command
$controller poll /sics/${name}/refnull 300
hsetprop /sics/${name}/refnull write el734::setref $name $no
hsetprop /sics/${name}/refnull command el734::command
$controller write /sics/${name}/refnull
hfactory /sics/${name}/ss plain internal text
hsetprop /sics/${name}/ss read el734::readss $no
hsetprop /sics/${name}/ss ssread el734::ssread
$controller poll /sics/${name}/ss 300
$name makescriptfunc refrun "el734::refrun $controller $name $no" user
}