diff --git a/site_ansto/instrument/config/environment/magneticField/sct_green_magnet.tcl b/site_ansto/instrument/config/environment/magneticField/sct_green_magnet.tcl index 9d478e96..e066439d 100644 --- a/site_ansto/instrument/config/environment/magneticField/sct_green_magnet.tcl +++ b/site_ansto/instrument/config/environment/magneticField/sct_green_magnet.tcl @@ -1,342 +1,192 @@ -# Define procs in ::scobj::xxx namespace -# MakeSICSObj $obj SCT_ -# The MakeSICSObj cmd adds a /sics/$obj node. NOTE the /sics node is not browsable. +## +# @file Green Magnetic Controller +# +# This is a driver for SICS to make following communication with the Labview Green Magnet device +# +# 1. read some system parameters from the device +# 2. set the magnet value +# 3. abort the magnet value setting during its processing +# +# Author: Jing Chen (jgn@ansto.gov.au) July 2011 +# +### - -namespace eval ::scobj::green_magnet { -# Environment controllers should have at least the following nodes -# /envcont/setpoint -# /envcont/sensor/value - proc debug_log {args} { - set fd [open "/tmp/green_magnet.log" a] - puts $fd "[clock format [clock seconds] -format "%T"] $args" +# @record data in the log files +proc debug_log {args} { + set d1 [clock format [clock seconds] -format %d%h%Y] + set fd [open "../log/green_magnet$d1.log" a] + puts $fd "[clock format [clock seconds] -format "%D %T"] $args" close $fd - } +} -# issue a command with a value in the target property of the variable - proc setPoint {tc_root nextState cmd} { - debug_log "setPoint: nextState=$nextState, cmd=$cmd, sct=[sct] $tc_root" - set par "[sct target]" - sct send "s $par\r\n?" - debug_log "setPoint: write \"s $par\"" - sct driving 1 - sct time_check [clock seconds] - if {$par != [sct oldval]} { - sct oldval $par - sct update [sct target] - sct utime readtime - debug_log "setPoint: new data for $tc_root [sct] result=$par" - } - return $nextState - } +namespace eval ::scobj::green { +} -# issue a command to read and expect a value response - proc getValue {tc_root nextState cmd} { - if { [hpropexists [sct] geterror] } { - hdelprop [sct] geterror - } - debug_log "getValue $cmd sct=[sct] root=$tc_root nextState=$nextState" - sct send "$cmd" - return $nextState - } - - proc rdValue {tc_root} { - debug_log "rdValue tc_root=$tc_root sct=[sct]" - set data [sct result] - if {[ catch { - debug_log "rdValue $tc_root [sct] result=$data" - } catch_message ]} { - debug_log "rdValue $tc_root failure" - } - if {[string equal -nocase -length 7 $data "ASCERR:"]} { - sct geterror "$data" - set nextState idle - } elseif {[string equal -nocase -length 1 $data "?"]} { - sct geterror "Error: $data" - set nextState idle - } else { - if { [hpropexists [sct] geterror] } { - hdelprop [sct] geterror - } - set rslt [scan $data %f data] - debug_log "rdValue $tc_root Green_Magnet result=$data" - if {$data != [sct oldval]} { - sct oldval $data - sct update $data - sct utime readtime - debug_log "rdValue new data for $tc_root [sct] result=$data" - } - } - return idle - } - - proc noResponse {} { - debug_log "noResponse" - return idle - } - -# check that a target is within allowable limits - proc check {tc_root} { - set setpoint [sct target] - set lolimit [hval $tc_root/lowerlimit] - set hilimit [hval $tc_root/upperlimit] - if {$setpoint < $lolimit || $setpoint > $hilimit} { - sct driving 0 - error "setpoint violates limits" - } - return OK - } - -# Check that the sensor is reading within tolerance of the setpoint. -# Return 1 or 0 if it is or is not, respectively. - proc checktol {tc_root currtime timecheck} { - debug_log "checktol $tc_root $currtime $timecheck" - set field [hval $tc_root/sensor/value] - set lofield [expr {[hval $tc_root/setpoint] - [hval $tc_root/tolerance]}] - set hifield [expr {[hval $tc_root/setpoint] + [hval $tc_root/tolerance]}] - debug_log "checktol: field = $field, lofield = $lofield, hifield = $hifield" - if { $field < $lofield || $field > $hifield} { - if {[hval $tc_root/emon/isintol] != 0} { - hset $tc_root/emon/isintol 0 - } - set rslt 0 - } else { - set timeout [hval $tc_root/tolerance/settletime] - if { ($currtime - $timecheck) > $timeout } { - if {[hval $tc_root/emon/isintol] != 1} { - hset $tc_root/emon/isintol 1 - } - } - set rslt 1 - } - debug_log "checktol: result = $rslt" - return $rslt - } - -## -# @brief Implement the checkstatus command for the drivable interface -# -# NOTE: The drive adapter initially sets the writestatus to "start" and will -# only call this when writestatus!="start" - proc drivestatus {tc_root} { - if {[sct driving]} { - if {[hval $tc_root/drive_state] == "HALT"} { - hset $tc_root/drive_state "" - hsetprop $tc_root/setpoint driving 0 - return idle - } - set intol [checktol $tc_root [clock seconds] [sct time_check]] - if {$intol == 0} { - sct time_check [clock seconds] - } - if {[hval $tc_root/emon/isintol] == 1} { - sct driving 0 - } - return busy - } else { - sct print "drivestatus: idle" - return idle - } - } - - proc halt {tc_root} { - debug_log "halt $tc_root" - sct print "halt $tc_root" - set my_driving [SplitReply [hgetprop $tc_root/setpoint driving]] - hset $tc_root/drive_state "HALT" - if { $my_driving } { - return read - } - return idle - } - -## -# @brief createNode() creates a node for the given nodename with the properties and virtual -# function names provided -# @param scobj_hpath string variable holding the path to the object's base node in sics (/sample/tc1) -# @param sct_controller name of the scriptcontext object (typically sct_xxx_yyy) -# @param cmdGroup subdirectory (below /sample/tc*/) in which the node is to be created -# @param varName name of the actual node typically representing one device command -# @param readable set to 1 if the node represents a query command, 0 if it is not -# @param writable set to 1 if the node represents a request for a change in settings sent to the device -# @param drivable if set to 1 it prepares the node to provide a drivable interface -# @param dataType data type of the node, must be one of none, int, float, text -# @param permission defines what user group may read/write to this node (is one of spy, user, manager) -# @param rdCmd actual device query command to be sent to the device -# @param rdFunc nextState Function to be called after the getValue function, typically rdValue() -# @param wrCmd actual device write command to be sent to the device -# @param wrFunc Function to be called to send the wrCmd to the device, typically setValue() -# @param allowedValues allowed values for the node data - does not permit other -# @param klass Nexus class name (?) -# @return OK - proc createNode {scobj_hpath sct_controller cmdGroup varName readable writable\ - drivable dataType permission rdCmd rdFunc wrCmd\ - wrFunc allowedValues klass} { - - set catch_status [ catch { - set ns "[namespace current]" - set nodeName "$scobj_hpath/$cmdGroup/$varName" - if {1 > [string length $cmdGroup]} { - set nodeName "$scobj_hpath/$varName" - } - debug_log "Creating node $nodeName" - hfactory $nodeName plain $permission $dataType - if {$readable > 0} { - hsetprop $nodeName read ${ns}::getValue $scobj_hpath $rdFunc $rdCmd - hsetprop $nodeName $rdFunc ${ns}::$rdFunc $scobj_hpath - set poll_period 30 - if { $readable >= 0 && $readable <= 9 } { - set poll_period [lindex [list 0 1 2 3 4 5 10 15 20 30] $readable] - } - debug_log "Registering node $nodeName for poll at $poll_period seconds" - $sct_controller poll $nodeName $poll_period - } - if {$writable == 1} { - set parts [split "$wrFunc" "."] - if { [llength $parts] == 2 } { - set func_name [lindex $parts 0] - set next_state [lindex $parts 1] - hsetprop $nodeName write ${ns}::$func_name $scobj_hpath $next_state $wrCmd - hsetprop $nodeName $next_state ${ns}::$next_state $scobj_hpath - } else { - hsetprop $nodeName write ${ns}::$wrFunc $scobj_hpath noResponse $wrCmd - hsetprop $nodeName noResponse ${ns}::noResponse - } - hsetprop $nodeName writestatus UNKNOWN - debug_log "Registering node $nodeName for write callback" - $sct_controller write $nodeName - } - switch -exact $dataType { - "none" { } - "int" { hsetprop $nodeName oldval -1 } - "float" { hsetprop $nodeName oldval -1.0 } - default { hsetprop $nodeName oldval UNKNOWN } - } - if {1 < [string length $allowedValues]} { - hsetprop $nodeName values $allowedValues - } - # Drive adapter interface - if {$drivable == 1} { - hsetprop $nodeName check ${ns}::check $scobj_hpath - hsetprop $nodeName driving 0 - hsetprop $nodeName checklimits ${ns}::check $scobj_hpath - hsetprop $nodeName checkstatus ${ns}::drivestatus $scobj_hpath - hsetprop $nodeName halt ${ns}::halt $scobj_hpath - } - } message ] - if {$catch_status != 0} { - return -code error "in createNode $message" - } - return OK - } - - proc mk_sct_green_magnet {sct_controller klass tempobj tol} { - set catch_status [ catch { - set ns "[namespace current]" - - MakeSICSObj $tempobj SCT_OBJECT - sicslist setatt $tempobj klass $klass - sicslist setatt $tempobj long_name $tempobj - - set scobj_hpath /sics/$tempobj - - set deviceCommand {\ - {} setpoint 0 1 1 float user {} {} {} {setPoint} {}\ - sensor value 1 0 0 float internal {?} {rdValue} {} {} {}\ - {} status 1 0 0 text internal {t} {rdValue} {} {} {}\ - {} voltage 1 0 0 text internal {v} {rdValue} {} {} {}\ - } - - hfactory $scobj_hpath/sensor plain spy none - - foreach {cmdGroup varName readable writable drivable dataType permission rdCmd rdFunc wrCmd wrFunc allowedValues} $deviceCommand { - createNode $scobj_hpath $sct_controller $cmdGroup $varName $readable $writable $drivable $dataType $permission $rdCmd $rdFunc $wrCmd $wrFunc $allowedValues $klass - } - - hfactory $scobj_hpath/tolerance plain user float - hsetprop $scobj_hpath/tolerance units "T" - hfactory $scobj_hpath/tolerance/settletime plain user float - hset $scobj_hpath/tolerance/settletime 5.0 - hsetprop $scobj_hpath/tolerance/settletime units "s" - hset $scobj_hpath/tolerance $tol - - hfactory $scobj_hpath/lowerlimit plain mugger float - hsetprop $scobj_hpath/lowerlimit units "T" - hset $scobj_hpath/lowerlimit 0 - - hfactory $scobj_hpath/upperlimit plain mugger float - hsetprop $scobj_hpath/upperlimit units "T" - hset $scobj_hpath/upperlimit 6 - - hfactory $scobj_hpath/emon plain spy none - hfactory $scobj_hpath/emon/monmode plain user text - hsetprop $scobj_hpath/emon/monmode values idle,drive,monitor,error - hset $scobj_hpath/emon/monmode "idle" - hfactory $scobj_hpath/emon/isintol plain user int - hset $scobj_hpath/emon/isintol 1 - hfactory $scobj_hpath/emon/errhandler plain user text - hset $scobj_hpath/emon/errhandler "pause" - - hfactory $scobj_hpath/drive_state plain mugger text - hset $scobj_hpath/drive_state "UNKNOWN" - - hsetprop $scobj_hpath type part - foreach snsr {sensor} { - foreach {rootpath hpath klass priv} "\ - $scobj_hpath $snsr NXsensor spy\ - $scobj_hpath $snsr/value sensor user\ - " { - hsetprop $rootpath/$hpath klass $klass - hsetprop $rootpath/$hpath privilege $priv - hsetprop $rootpath/$hpath control true - hsetprop $rootpath/$hpath data true - hsetprop $rootpath/$hpath nxsave true - } - hsetprop $scobj_hpath/$snsr type part - hsetprop $scobj_hpath/$snsr/value nxalias tc1_${snsr}_value - hsetprop $scobj_hpath/$snsr/value mutable true - hsetprop $scobj_hpath/$snsr/value sdsinfo ::nexus::scobj::sdsinfo - } - hsetprop $scobj_hpath privilege spy - ::scobj::hinitprops $tempobj setpoint - if {[SplitReply [magnetic_simulation]]=="false"} { - hsetprop $scobj_hpath/setpoint type drivable - ansto_makesctdrive ${tempobj}_driveable $scobj_hpath/setpoint $scobj_hpath/sensor/value $sct_controller - } - } catch_message ] - if {$catch_status != 0} { - return -code error $catch_message - } - } - namespace export mk_sct_green_magnet +# @brief Request a state report from the Oxford Device by sending a Magnetic Field request command +proc ::scobj::green::queryGreenMagnetFunc {} { + set comm "getAll\r\n" + sct send $comm + return rdState } ## -# @brief Create a Green Magnet power supply controller -# -# @param name, the name of the power supply controller (eg tc1) -# @param IP, the IP address of the device, this can be a hostname, (eg ca1-kowari) -# @param port, the IP protocol port number of the device -# @param _tol (optional), this is the initial tolerance setting -proc add_green_magnet {name IP port {_tol 5.0}} { - set fd [open "/tmp/green_magnet.log" a] - if {[SplitReply [magnetic_simulation]]=="false"} { - puts $fd "makesctcontroller green_magnet std ${IP}:$port \"\r\n\"" - makesctcontroller green_magnet std ${IP}:$port "\r\n" +# @brief Read and record the greeni Magnet values from the Device +proc ::scobj::green::rqGreenMagnetFunc {basePath} { + set replyStr [sct result] + debug_log $replyStr + #broadcast "getT reply:$replyStr\n" + if {[string first "Error" $replyStr] != -1} { + broadcast "Error: cannot get the Magnetific Temperature value from the Oxford Labview server, check again!" + } elseif {[string first "failed" $replyStr] != -1} { + broadcast "Error: Connection to Oxford Labview server failed, check connection!" + } elseif {[string first "read timeout" $replyStr] != -1} { + broadcast "Error: read timeout on the connectiion to the Oxford Labview server" + } else { + set s1 [string trimright $replyStr "\n"] + set s2 [split $s1 "=;"] + array set paraArr $s2 + hset $basePath/output $paraArr(Output) + hset $basePath/PSU_Vol $paraArr(PSU_Vol) + hset $basePath/ramping_rate $paraArr(Rate) + hset $basePath/insTarget $paraArr(Target) + hset $basePath/setPoint [hval $basePath/insTarget] + hset $basePath/status $paraArr(Status) + hset $basePath/Bmax $paraArr(Bmax) + hset $basePath/msg $paraArr(Msg) } - puts $fd "mk_sct_green_magnet green_magnet environment $name $_tol" - mk_sct_green_magnet green_magnet environment $name $_tol - puts $fd "makesctemon $name /sics/$name/emon/monmode /sics/$name/emon/isintol /sics/$name/emon/errhandler" - makesctemon $name /sics/$name/emon/monmode /sics/$name/emon/isintol /sics/$name/emon/errhandler - close $fd + + return idle } -puts stdout "file evaluation of sct_green_magnet.tcl" -set fd [open "/tmp/green_magnet.log" w] -puts $fd "file evaluation of sct_green_magnet.tcl" -close $fd +## +# @brief Make a Green Magnet Controller +# +# @param argList, {name "magnetic" IP localhost PORT 65123 tuning 1 interval 1} +# +# name: name of green magnet controller object +# IP: IP address of RF generator moxa box +# POT: Port number assigned to the generator on the moxa-box +# tuning: boolean, set tuning=1 to allow instrument scientists to set the axe positions +# interval: polling and ramping interval in seconds. -namespace import ::scobj::green_magnet::* +proc ::scobj::green::mkGreen {argList} { +# Generate parameter array from the argument list + foreach {k v} $argList { + set KEY [string toupper $k] + set pa($KEY) $v + } + + MakeSICSObj $pa(NAME) SCT_OBJECT + sicslist setatt $pa(NAME) klass environment + sicslist setatt $pa(NAME) long_name $pa(NAME) + + set scobj_hpath /sics/$pa(NAME) + + hfactory $scobj_hpath/output plain user float + hfactory $scobj_hpath/PSU_Vol plain user float + hfactory $scobj_hpath/ramping_rate plain user text + hfactory $scobj_hpath/insTarget plain user float + hfactory $scobj_hpath/status plain user text + hfactory $scobj_hpath/Bmax plain user float + hfactory $scobj_hpath/msg plain user text + hfactory $scobj_hpath/pollNode plain user text + + + hsetprop $scobj_hpath/output units "V" + hsetprop $scobj_hpath/output uplimit 100 + hsetprop $scobj_hpath/output lowlimit 0 + + hsetprop $scobj_hpath/status values idle,busy + hset $scobj_hpath/status idle + + hsetprop $scobj_hpath tuning $pa(TUNING) + + # Setting Green Magnet Voltage + hfactory $scobj_hpath/setPoint plain user float + + # make data structure here + ::scobj::set_required_props $scobj_hpath + hsetprop $scobj_hpath klass environment + hsetprop $scobj_hpath privilege spy + hsetprop $scobj_hpath type part + hsetprop $scobj_hpath control true + hsetprop $scobj_hpath data true + + foreach {hpath klass control data nxsave mutable priv alias} { + output NXenvironment true true true true user green_output + PSU_Vol NXenvironment true true true true user green_PSU_Vol + setPoint NXenvironment true true true true user green_setPoint + } { + hsetprop $scobj_hpath/$hpath nxalias $alias + hsetprop $scobj_hpath/$hpath klass $klass + hsetprop $scobj_hpath/$hpath privilege $priv + hsetprop $scobj_hpath/$hpath control $control + hsetprop $scobj_hpath/$hpath data $data + hsetprop $scobj_hpath/$hpath nxsave $nxsave + hsetprop $scobj_hpath/$hpath mutable $mutable + hsetprop $scobj_hpath/$hpath sdsinfo ::nexus::scobj::sdsinfo + } + + ::scobj::hinitprops $pa(NAME) + + makesctcontroller sct_green std $pa(IP):$pa(PORT) + + hsetprop $scobj_hpath/pollNode read ::scobj::green::queryGreenMagnetFunc + hsetprop $scobj_hpath/pollNode rdState ::scobj::green::rqGreenMagnetFunc /sics/$pa(NAME) + + #if {[SplitReply [environment_simulation]]=="false"} { + sct_green poll $scobj_hpath/pollNode $pa(INTERVAL) + #} +} + +# Set the magnetic voltage field +proc greenVol {{vol ""} args} { + set NAME "green_magnet" + + if {$vol == ""} { + broadcast "Output = [hval /sample/$NAME/output]" + } else { + if {$vol<[SplitReply [hgetprop /sample/$NAME/output lowlimit]] || \ + $vol>[SplitReply [hgetprop /sample/$NAME/output uplimit]]} { + return -code error "setpoint violates limits" + } else { + if {$vol > [hval /sample/$NAME/Bmax]} { + broadcast "Maximum field limit is [hval /sample/$NAME/Bmax], reset again!" + return + } else { + #hset /sample/$NAME/setPoint $vol + set comm "set $vol\r\n" + sct_green send $comm + #after 2000 + #while {[hval /sample/$NAME/status] == "busy"} { + # broadcast "Magnet Ramping at [hval /sample/$NAME/output]" + # after 3000 + #} + } + } + } + return +} + +# abort a magnet voltage setting during its proceeding +proc greenAbortSetting {} { + set NAME "green" + + set comm "abort\r\n" + sct_green send $comm + return +} + +publish greenAbortSetting user +publish greenVol user + +#IP 137.157.204.8 +#PORT 22 +::scobj::green::mkGreen { + name "green_magnet" + IP 137.157.204.57 + PORT 22 + tuning 1 + interval 3 +} -#add_green_magnet magnet 137.157.201.213 502 5 -#add_green_magnet magnet localhost 30509 0.001