#---------------------------------------------------------------------------- # Scan command implementation for TOPSI # Test version, Mark Koennecke, February 1997 #---------------------------------------------------------------------------- set home /data/koenneck/src/sics/tcl set datapath /data/koenneck/src/sics/tmp set recoverfil /data/koenneck/src/sics/recover.dat bpOn source $home/utils.tcl source $home/base.tcl source $home/inherit.tcl source $home/obtcl.tcl #-------------------------- some utility functions ------------------------- proc MC { t n } { set string $t for { set i 1 } { $i < $n } { incr i } { set string [format "%s%s" $string $t] } return $string } #-------------------------------------------------------------------------- proc GetNum { text } { set list [split $text =] return [lindex $list 1] } #-------------------------- String list for writing ------------------------ class DataSet DataSet method init { } { instvar N instvar Data next set Data(0) " Bla" set N 0 } DataSet method add { text } { instvar N instvar Data set Data($N) $text incr N } DataSet method ins { text i } { instvar Data instvar N if { $i >= $N } { set N [expr $i + 1] } else { unset Data($i) } set Data($i) $text } DataSet method put { file } { instvar Data instvar N for { set i 0 } { $i < $N } { incr i } { puts $file $Data($i) } } DataSet method clear { } { instvar Data instvar N unset Data set Data(0) "Bla" set N 0 } DataSet method GetN { } { instvar N return $N } #--------------------------------------------------------------------------- # scan class initialization class ScanCommand ScanCommand method init { counter } { instvar ScanData instvar [DataSet new Data] instvar Active instvar Recover next set ScanData(Mode) Timer set ScanData(NP) 1 set ScanData(counter) $counter set ScanData(NoVar) 0 set ScanData(Preset) 10. set ScanData(File) Default.dat set ScanData(Counts) " " set ScanData(cinterest) " " set ScanData(pinterest) " " set Active 0 set Recover 0 } #-------------add scan variables--------------------------------------------- ScanCommand method var { name start step } { instvar ScanData instvar ScanVar instvar Active # check for activity if {$Active} { ClientPut "ERROR: cannot change parameters while scanning" error return } # check parameters set t [SICSType $name] if { [string compare $t DRIV] != 0 } { ClientPut [format "ERROR: %s is not drivable" $name] error return 0 } set t [SICSType $start] if { [string compare $t NUM] != 0 } { ClientPut [format "ERROR: %s is no number!" $start] error return 0 } set t [SICSType $step] if { [string compare $t NUM] != 0 } { ClientPut [format "ERROR: %s is no number!" $step] error return 0 } # install the variable set i $ScanData(NoVar) set ScanData(NoVar) [incr ScanData(NoVar)] set ScanVar($i,Var) $name set ScanVar($i,Start) $start set ScanVar($i,Step) $step set ScanVar($i,Value) " " $self SendInterest pinterest ScanVarChange ClientPut OK } #---------------------- getvars ------------------------------------------ ScanCommand method getvars {} { instvar ScanData instvar ScanVar set list "" for {set i 0} { $i < $ScanData(NoVar) } { incr i} { lappend list $ScanVar($i,Var) } return [format "scan.Vars = %s -END-" $list] } #------------------------------------------------------------------------ ScanCommand method xaxis {} { instvar ScanData instvar ScanVar if { $ScanData(NoVar) <= 0} { #---- default Answer set t [format "%s.xaxis = %f %f" $self 0 1] } else { set t [format "%s.xaxis = %f %f" $self $ScanVar(0,Start) \ $ScanVar(0,Step)] } ClientPut $t } #--------------------- modvar -------------------------------------------- ScanCommand method modvar {name start step } { instvar ScanData instvar ScanVar for {set i 0} { $i < $ScanData(NoVar) } { incr i} { if { [string compare $name $ScanVar($i,Var)] == 0} { set t [SICSType $start] if { [string compare $t NUM] != 0 } { ClientPut [format "ERROR: %s is no number!" $start] error return 0 } set t [SICSType $step] if { [string compare $t NUM] != 0 } { ClientPut [format "ERROR: %s is no number!" $step] error return 0 } #-------- do it set ScanVar($i,Start) $start set ScanVar($i,Step) $step return OK } } error [format "Scan Variable %s NOT found" $name] } #----------------- interests ---------------------------------------------- ScanCommand method cinterest {} { instvar ScanData set nam [GetNum [config MyName]] lappend ScanData(cinterest) $nam } #-------------------------------------------------------------------------- ScanCommand method pinterest {} { instvar ScanData set nam [GetNum [config MyName]] lappend ScanData(pinterest) $nam } #------------------------------------------------------------------------- ScanCommand method SendInterest { type text } { instvar ScanData #------ check list first set l1 $ScanData($type) set l2 "" foreach e $l1 { set b [string trim $e] set g [string trim $b "{}"] set ret [SICSType $g] if { [string first COM $ret] >= 0 } { lappend l2 $e } } #-------- update scan data and write set ScanData($type) $l2 foreach e $l2 { set b [string trim $e] $b put $text } } #---------------- Change Mode ---------------------------------------------- ScanCommand method Mode { {NewVal NULL } } { instvar ScanData instvar Active if { [string compare $NewVal NULL] == 0 } { set val [format "%.Mode = %s" $self $ScanData(Mode)] ClientPut $val return $val } else { # check for activity if {$Active} { ClientPut "ERROR: cannot change parameters while scanning" error return } if { ([string compare $NewVal "Timer"] == 0) || \ ([string compare $NewVal Monitor] ==0) } { set ScanData(Mode) $NewVal ClientPut OK } else { ClientPut [format "ERROR: %s not recognized as ScanMode" $NewVal] } } } #----------------------------- NP ------------------------------------------- ScanCommand method NP { { NewVal NULL } } { instvar ScanData instvar Active if { [string compare $NewVal NULL] == 0 } { set val [format "%s.NP = %d" $self $ScanData(NP)] ClientPut $val return $val } else { # check for activity if {$Active} { ClientPut "ERROR: cannot change parameters while scanning" error return } set t [SICSType $NewVal] if { [string compare $t NUM] != 0 } { ClientPut [format "ERROR: %s is no number" $NewVal] error return } set ScanData(NP) $NewVal ClientPut OK } } #------------------------------ Preset ------------------------------------ ScanCommand method Preset { {NewVal NULL} } { instvar ScanData instvar Active if { [string compare $NewVal NULL] == 0 } { set val [format "%s.Preset = %f" $self $ScanData(Preset)] ClientPut $val return $val } else { # check for activity if {$Active} { ClientPut "ERROR: cannot change parameters while scanning" error return } set ScanData(Preset) $NewVal set t [SICSType $NewVal] if { [string compare $t NUM] != 0} { ClientPut [format "ERROR: %s is no number" $NewVal] error return } ClientPut OK } } #------------------------------ File ------------------------------------ ScanCommand method File { {NewVal NULL} } { instvar ScanData if { [string compare $NewVal NULL] == 0 } { set val [format "%s.File = %s" $self $ScanData(File)] ClientPut $val return $val } else { set ScanData(File) $NewVal ClientPut OK } } #--------------------------- Count --------------------------------------- # These and the commands below are for use in recovery only ScanCommand method RecoCount { val } { instvar Recover instvar ScanData if { ! $Recover } { ClientPut \ "ERROR: This command may only be used in Recovery Operations" \ error return } set ScanData(Counts) $val } #--------------------------- monitor ------------------------------------- ScanCommand method RecoMonitor { val } { instvar Recover instvar ScanData if { ! $Recover } { ClientPut \ "ERROR: This command may only be used in Recovery Operations" \ error return } set ScanData(Monitor) $val } #--------------------------- var ------------------------------------- ScanCommand method RecoVar { var val } { instvar Recover instvar ScanData instvar ScanVar if { ! $Recover } { ClientPut \ "ERROR: This command may only be used in Recovery Operations" \ error return } set ScanVar($var,Value) $val } #--------------------------- WriteRecover -------------------------------- ScanCommand method WriteRecover { } { instvar ScanData instvar ScanVar global recoverfil set fd [open $recoverfil w] puts $fd [format "%s Preset %s " $self $ScanData(Preset)] puts $fd [format "%s Mode %s " $self $ScanData(Mode)] puts $fd [format "%s NP %s " $self $ScanData(NP)] puts $fd [format "%s File %s " $self $ScanData(File)] for { set i 0 } { $i < $ScanData(NoVar) } { incr i } { puts $fd [format "%s var %s %s %s" $self $ScanVar($i,Var) \ $ScanVar($i,Start) $ScanVar($i,Step)] puts $fd [format "%s RecoVar %d %s" $self $i [list $ScanVar($i,Value)]] } puts $fd [format "%s RecoCount %s" $self [list $ScanData(Counts)]] puts $fd [format "%s RecoMonitor %s" $self [list $ScanData(Monitor)]] close $fd } #-------------------------- list ------------------------------------------ ScanCommand method list { } { instvar ScanData instvar ScanVar ClientPut [format "%s.Preset = %f" $self $ScanData(Preset)] ClientPut [format "%s.Mode = %s" $self $ScanData(Mode)] ClientPut [format "%s.File = %s" $self $ScanData(File)] ClientPut [format "%s.NP = %d" $self $ScanData(NP)] ClientPut "ScanVariables:" for { set i 0 } {$i < $ScanData(NoVar) } { incr i } { ClientPut [format " %s %f %f" $ScanVar($i,Var) $ScanVar($i,Start) \ $ScanVar($i,Step)] } } #--------------------------------- clear --------------------------------- ScanCommand method clear { } { instvar ScanData instvar ScanVar instvar Data instvar Active # check for activity if {$Active} { ClientPut "ERROR: cannot clear running scan" error return } set ScanData(NP) 0 set ScanData(NoVar) 0 set ScanData(Counts) " " set ScanData(Monitor) " " Data clear $self SendInterest pinterest ScanVarChange ClientPut OK } #--------------------------- Store Initial data ----------------------------- ScanCommand method SaveHeader { } { instvar Data instvar ScanData instvar ScanVar Data clear # administrative header Data add [format "%s TOPSI Data File %s" [MC * 30] \ [MC * 30]] Data add [Title] Data add [User] Data add [format "File created: %s" [sicstime]] Data add [MC * 75] Data add [format " %s Setting %s " [MC * 30] [MC * 30]] # settings of instrument variables Data add [format "%s Monochromator %s" [MC - 30] [MC - 30]] Data add [lambda] Data add [MTL position] Data add [MTU position] Data add [MGU position] # diaphragm should go here # sample info Data add [format "%s Sample %s" [MC - 30] [MC - 30]] Data add [STL position] Data add [STU position] Data add [SGL position] Data add [SGU position] Data add [MC * 75] # counter info Data add [format "CountMode = %s" $ScanData(Mode)] Data add [format "Count Preset = %s" $ScanData(Preset)] Data add [MC * 75] Data add [format "%s DATA %s" [MC * 30] [MC * 30]] set val "Variables scanned: " for { set i 0 } { $i < $ScanData(NoVar) } { incr i} { append val " " $ScanVar($i,Var) } Data add "$val" append t [LeftAlign NP 5] append t [LeftAlign Counts 12] for { set i 0 } { $i < $ScanData(NoVar) } { incr i} { append t [LeftAlign $ScanVar($i,Var) 10] } Data add $t set ScanData(Ptr) [Data GetN] } #----------------------------------------------------------------------------- ScanCommand method ConfigureDevices { } { instvar ScanData $ScanData(counter) SetMode $ScanData(Mode) $ScanData(counter) SetPreset $ScanData(Preset) } #---------------------------------------------------------------------------- ScanCommand method StoreScanPoint { } { instvar ScanData instvar Data instvar ScanVar lappend ScanData(Counts) [GetNum [$ScanData(counter) GetCounts]] lappend ScanData(Monitor) [GetNum [$ScanData(counter) GetMonitor 1]] #------------ get Scan Var Values for { set i 0 } { $i < $ScanData(NoVar) } { incr i } { lappend ScanVar($i,Value) [GetNum [$ScanVar($i,Var) position]] } set iFile $ScanData(Ptr) #------------ write it set length [llength $ScanData(Counts)] for { set i 0 } { $i < $length} { incr i} { set t " " append t [LeftAlign $i 5] append t [LeftAlign [lindex $ScanData(Counts) $i ] 12] for { set ii 0 } { $ii < $ScanData(NoVar) } { incr ii} { append t [LeftAlign [lindex $ScanVar($ii,Value) $i] 10] } Data ins $t $iFile incr iFile } set fd [open $ScanData(File) w] Data put $fd close $fd } #-------------------------------------------------------------------------- ScanCommand method GetCounts { } { instvar ScanData #------- get data available set length [llength $ScanData(Counts)] for { set i 0 } { $i < $length } { incr i} { lappend result [lindex $ScanData(Counts) $i] } #------ put zero in those which are not yet measured if { $length < $ScanData(NP) } { for { set i $length } { $i < $ScanData(NP) } { incr i } { lappend result 0 } } return "scan.Counts= $result" } #--------------------------------------------------------------------------- ScanCommand method EndScan { } { instvar Data instvar ScanData instvar ScanVar Data add [format "%s End of Data %s" [MC * 30] [MC * 30]] set fd [open $ScanData(File) w] Data put $fd close $fd } #------------------------------------------------------------------------- ScanCommand method EvalInt { } { set int [GetInt] ClientPut [format "Interrupt %s detected" $int] switch -exact $int { continue { return OK } abortop { SetInt continue return SKIP } abortscan { SetInt continue return ABORT } default { return ABORT } } } #-------------------------------------------------------------------------- ScanCommand method DriveTo { iNP } { instvar ScanData instvar ScanVar set command "drive " for { set i 0 } { $i < $ScanData(NoVar) } { incr i } { set ScanVar($i,NewVal) [expr $ScanVar($i,Start) + $iNP * \ $ScanVar($i,Step)] # append ScanVar($i,Value) " " $ScanVar($i,NewVal) append command " " $ScanVar($i,Var) " " $ScanVar($i,NewVal) } set ret [catch {eval $command } msg ] if { $ret != 0 } { ClientPut $msg error return [$self EvalInt] } return OK } #------------------------------------------------------------------------ ScanCommand method CheckScanBounds { } { instvar ScanData instvar ScanVar for { set i 0} { $i < $ScanData(NP) } { incr i } { for { set ii 0 } { $ii < $ScanData(NoVar) } { incr ii } { set NewVal [expr $ScanVar($ii,Start) + $i*$ScanVar($ii,Step)] set iRet [catch {SICSBounds $ScanVar($ii,Var) $NewVal} msg] if { $iRet != 0 } { ClientPut $msg error return 0 } } } return 1 } #------------------------------------------------------------------------- ScanCommand method Count { } { instvar ScanData set command $ScanData(counter) append command " Count " append command $ScanData(Preset) set ret [catch {eval $command } msg ] if { $ret != 0 } { ClientPut $msg error return [$self EvalInt] } return OK } #------------------------------------------------------------------------- proc LeftAlign { text iField } { set item $text append item [MC " " $iField] return [string range $item 0 $iField] } #------------------------------------------------------------------------- ScanCommand method ScanStatusHeader { } { instvar ScanData instvar ScanVar append t [LeftAlign NP 5] append t [LeftAlign Counts 12] for { set i 0 } { $i < $ScanData(NoVar) } { incr i} { append t [LeftAlign $ScanVar($i,Var) 10] } ClientPut $t status } #------------------------------------------------------------------------ ScanCommand method ProgressReport { i } { instvar ScanData instvar ScanVar $self ScanStatusHeader append t [LeftAlign $i 5] append t [LeftAlign [lindex $ScanData(Counts) $i ] 12] for { set i 0 } { $i < $ScanData(NoVar) } { incr i} { append t [LeftAlign $ScanVar($i,NewVal) 10] } ClientPut $t status } #------------------------------------------------------------------------- ScanCommand method MakeFile { } { global datapath instvar ScanData SicsDataNumber incr set num1 [SicsDataNumber] set num [GetNum $num1] set fil [ format "%s/topsi%4.4d%2.2d.dat" $datapath $num 97] set ScanData(File) $fil } #-------------------------------------------------------------------------- ScanCommand method run { } { instvar ScanData instvar Data instvar ScanVar instvar Active # start with error checking if { $ScanData(NP) < 1 } { ClientPut "ERROR: Insufficient Number of ScanPoints" return } if { $ScanData(NoVar) < 1 } { ClientPut "ERROR: No variables to scan given!" return } #------- check for activity if {$Active} { ClientPut "ERROR: Scan already in progress" error return } #------- check Bounds if { [$self CheckScanBounds] != 1 } { return } # clean data space from relicts of previous scans Data clear set ScanData(Counts) " " set ScanData(Monitor) " " for {set i 0} { $i < $ScanData(NoVar) } { incr i } { set ScanVar($i,Value) " " } # configure and save data header $self ConfigureDevices $self MakeFile $self SaveHeader ClientPut [format "Writing %s" $ScanData(File)] # the actual scan loop SetStatus Scanning $self SendInterest cinterest NewScan set Active 1 for { set i 0 } { $i < $ScanData(NP) } { incr i } { #---- driving set ret [$self DriveTo $i] switch -exact $ret { OK { } SKIP { continue } ABORT { ClientPut "\nERROR: Scan Aborted at drive" SetStatus Eager set Active 0 error "Abort" } } #---- counting set ret [$self Count] switch -exact $ret { OK { } SKIP { continue } ABORT { ClientPut "\nERROR: Scan Aborted at counting" SetStatus Eager set Active 0 error "Abort" } } #--- save data $self StoreScanPoint $self WriteRecover #--- invoke interests $self SendInterest cinterest [$self GetCounts] #--- Status Report $self ProgressReport $i } #---- final processing $self EndScan ClientPut "OK" SetStatus Eager set Active 0 } #-------------------------------------------------------------------------- ScanCommand method Recover { } { instvar ScanData instvar Data instvar ScanVar instvar Active instvar Recover global recoverfil # ---- read Recover Information set Recover 1 $self clear source $recoverfil # configure and save data header $self ConfigureDevices $self SaveHeader # Write scan start info $self ScanStatusHeader # --- figure out where we are set Recover 0 set pos [llength $ScanData(Counts)] # ----------------------the actual scan loop set OldStat [status] SetStatus Scanning set Active 1 for { set i $pos } { $i < $ScanData(NP) } { incr i } { #---- driving set ret [$self DriveTo $i] switch -exact $ret { OK { } SKIP { continue } ABORT { ClientPut "\nERROR: Scan Aborted" SetStatus $OldStat set Active 0 return } } #---- counting set ret [$self Count] switch -exact $ret { OK { } SKIP { continue } ABORT { ClientPut "\nERROR: Scan Aborted" SetStatus $OldStat set Active 0 return } } #--- save data $self StoreScanPoint $self WriteRecover #--- Status Report $self ProgressReport $i } #---- final processing $self EndScan ClientPut "OK" SetStatus $OldStat set Active 0 } #--------------------------------------------------------------------------- # finally initialise the scan command ScanCommand new scan counter #--------------------------------------------------------------------------- # a new user command which allows status clients to read the counts in a scan # This is just to circumvent the user protection on scan proc ScanCounts { } { set status [ catch {scan GetCounts} result] if { $status == 0 } { return $result } else { return "scan.Counts= 0" } } #--------------------------------------------------------------------------- # This is just another utilility function which helps in implementing the # status display client proc TextStatus { } { set text [status] return [format "Status = %s" $text] } #--------------------------------------------------------------------------- # Dumps time in a useful format proc sftime {} { return [format "sicstime = %s" [sicstime]] }