## # @file Scan functionality and common high level commands are defined here. # # namespace variables\n # ::scan::save_filetype data/scratch, controls if data will be saved to a scratch file. # ::scan::reset_position true/false (default=true), drive motor back to start position at end of scan #TODO Get rid of duplication in bmonscan and hmscan code MakeScanCommand hmscan bm $cfPath(scan)/scan_common_1.hdd recover.bin MakeScanCommand bmonscan bm $cfPath(scan)/scan_common_1.hdd recover.bin namespace eval scan { variable save_filetype variable reset_position set save_filetype "data" set reset_position "false" proc scan_collect {sobj uobj point} { } } ## # @brief Returns an error if a scan variable target position exceeds the limits. proc ::scan::check_limit {scan_variable limit_name target} { switch $limit_name { "hardlowerlim" - "softlowerlim" { set limit [SplitReply [$scan_variable $limit_name]] if { $target < $limit} { return -code error "Final position of $target violates $limit_name $limit for $scan_variable" } } "hardupperlim" - "softupperlim" { set limit [SplitReply [$scan_variable $limit_name]] if { $target > $limit} { return -code error "Final position of $target violates $limit_name $limit for $scan_variable" } } default { return -code error "Invalid limit name $limit_name" } } } ## \brief check final position against scan variable limits # # NOTE: The sics scan object alread checks if a variable is drivable # so we don't have to. # TODO We can't check limits of virtual motors yet because the # configurablevirtualmotor doesn't set a checklimits function. proc ::scan::check_scanvar {sobj uobj} { set vlist [split [$sobj getvarpar 0] = ]; set NP [SplitReply [$sobj np]] set scan_variable [string trim [lindex [split [lindex $vlist 0] . ] 1]] set scan_start [lindex $vlist 1]; set scan_increment [lindex $vlist 2]; if {[getatt $scan_variable type] == "motor"} { if {[SplitReply [$scan_variable fixed]] >= 0} { return -code error "Can't drive scan variable, $scan_variable position is set to 'fixed'" } set target [expr $scan_start + $NP * $scan_increment] if [catch { ::scan::check_limit $scan_variable hardlowerlim $target ::scan::check_limit $scan_variable hardupperlim $target ::scan::check_limit $scan_variable softlowerlim $target ::scan::check_limit $scan_variable softupperlim $target }] { return -code error $::errorInfo } } } ## # @brief Instrument specific scan configurations can override this procedure to perform some setup # before running a scan, eg setting hmm frame frequency. # # NOTES\n # Returning an error will cause the scan to abort before it starts\n # eg\n # return -code error "error message" proc ::scan::pre_hmm_scan_prepare {} {} ## # @brief Do some pre-scan checks and prime the DAE proc ::scan::hmm_scan_prepare {sobj uobj} { variable scan_pt_start_time variable save_filetype if {[::plc::inst_ready] != 1} { return -code error "HMSCAN ABORTED: Instrument not ready" } if [catch { ::scan::check_scanvar $sobj $uobj ::scan::pre_hmm_scan_prepare }] { abortbatch return -code error "HMSCAN ABORTED: $::errorInfo" } if [catch { set numpoints [SplitReply [$sobj np]] set vlist [split [$sobj getvarpar 0] = ] set scanstart [lindex $vlist 1] set scanstep [lindex $vlist 2] ::scan::hdb_hmscan -set NP $numpoints ::scan::hdb_hmscan -set scan_variable [string trim [lindex [split [lindex $vlist 0] . ] 1]] ::scan::hdb_hmscan -set scan_start $scanstart ::scan::hdb_hmscan -set scan_increment $scanstep set scan_pt_start_time [sicstime] ::scan::hdb_hmscan -set feedback status BUSY ::nexus::newfile HISTOGRAM_XYT $save_filetype data axis 1 [::scan::hdb_hmscan -set scan_variable] clientput "Scan start: $scanstart, Scan step: $scanstep, Number of points: $numpoints" clientput "Filetype: HISTOGRAM_XYT" # Prime DAE hmm pause }] { return -code error $::errorInfo } } proc ::scan::hmm_count {sobj uobj point mode preset} { ::scan::hdb_hmscan -set mode $mode ::scan::hdb_hmscan -set preset $preset ::scan::hdb_hmscan -set feedback scanpoint $point ::scan::hdb_hmscan -set feedback mode $mode ::scan::hdb_hmscan -set feedback preset $preset ::scan::hdb_hmscan -set feedback scan_variable_value [SplitReply [[::scan::hdb_hmscan -set scan_variable]]] # Start histogram and block until count is complete ::histogram_memory::start block } proc ::scan::hmm_scan_finish {sobj uobj} { variable save_filetype variable reset_position set $save_filetype "data" ::histogram_memory::stop ::scan::hdb_hmscan -set feedback status IDLE # Make sure that the next save command doesn't overwrite our scan data. # and clear any data links ::nexus::newfile clear data if {$reset_position == "true"} { set reset_position "false" set svar [::scan::hdb_hmscan -get scan_variable] set svtype [getatt $svar type] if {$svtype == "motor" || $svtype == "configurablevirtualmotor"} { drive $svar [::scan::hdb_hmscan -get scan_start] } } # ::histogram_memory::configure_server Filler_defaults } proc ::scan::bm_scan_finish {sobj uobj} { variable reset_position ::scan::hdb_bmonscan -set feedback status IDLE # Make sure that the next save command doesn't overwrite our scan data. # and clear any data links ::nexus::newfile clear data if {$reset_position == "true"} { set reset_position "false" set svar [::scan::hdb_bmonscan -get scan_variable] set svtype [getatt $svar type] if {$svtype == "motor" || $svtype == "configurablevirtualmotor"} { drive $svar [::scan::hdb_bmonscan -get scan_start] } } } # Add an nxentry for the current scan point #TODO Is this obsolete? proc ::scan::write_nxentry {nxentryCmd point} { variable scan_pt_start_time; save $point } proc ::scan::bm_writepoint {sobj uobj pt} { ::nexus::save $pt ::scan::hdb_bmonscan -set feedback counts [SplitReply [bm getcounts]]; } #TODO Feedback for Histogram memory scan proc ::scan::hmm_writepoint {sobj uobj pt} { variable save_filetype # Write hdb tree ::nexus::save $pt } proc ::scan::donothing {args} {} proc ::scan::bm_count {sobj uobj point mode preset} { ::scan::hdb_bmonscan -set mode $mode ::scan::hdb_bmonscan -set preset $preset ::scan::hdb_bmonscan -set feedback scanpoint $point; ::scan::hdb_bmonscan -set feedback mode $mode; ::scan::hdb_bmonscan -set feedback preset $preset; ::scan::hdb_bmonscan -set feedback scan_variable_value [SplitReply [[::scan::hdb_bmonscan -set scan_variable]]] ::monitor::count $mode $preset } proc ::scan::bm_scan_prepare {sobj uobj} { variable scan_pt_start_time if {[::plc::inst_ready] != 1} { return -code error "HMSCAN ABORTED: Instrument not ready" } if [catch { ::scan::check_scanvar $sobj $uobj ::scan::pre_hmm_scan_prepare }] { abortbatch return -code error "BMONSCAN ABORTED: $::errorInfo" } #TODO Parameterise varindex in some way set varindex 0; set numpoints [SplitReply [$sobj np]] set vlist [split [$sobj getvarpar $varindex] = ] set scanstart [lindex $vlist 1] set scanstep [lindex $vlist 2] ::scan::hdb_bmonscan -set feedback filename [SplitReply [dataFileName]] ::scan::hdb_bmonscan -set NP $numpoints ::scan::hdb_bmonscan -set scan_variable [string trim [lindex [split [lindex $vlist 0] . ] 1]]; ::scan::hdb_bmonscan -set scan_start $scanstart ::scan::hdb_bmonscan -set scan_increment $scanstep set scanvar_pts [SplitReply [$sobj getvardata $varindex]] todo_msg "SET START TIME [sicstime]" ::scan::hdb_bmonscan -set feedback status BUSY array set bm_fb [::scan::hdb_bmonscan -list feedback] ::nexus::newfile BEAM_MONITOR data ::nexus::data axis 1 [::scan::hdb_bmonscan -set scan_variable] #stdscan prepare $sobj $uobj; clientput "Scan start: $scanstart, Scan step: $scanstep, Number of points: $numpoints" clientput "Filetype: BEAM_MONITOR" } Publish ::scan::scan_collect user Publish ::scan::write_nxentry user Publish ::scan::hmm_count user Publish ::scan::hmm_scan_prepare user Publish ::scan::hmm_scan_finish user Publish ::scan::hmm_writepoint user Publish ::scan::donothing user Publish ::scan::bm_scan_prepare user Publish ::scan::bm_scan_finish user Publish ::scan::bm_writepoint user Publish ::scan::bm_count user bmonscan configure script bmonscan function writeheader ::scan::donothing bmonscan function writepoint ::scan::bm_writepoint bmonscan function count ::scan::bm_count #bmonscan function collect ::scan::scan_collect bmonscan function prepare ::scan::bm_scan_prepare bmonscan function finish ::scan::bm_scan_finish hmscan configure script #hmscan function prepare hdbprepare #hmscan function collect hdbcollect hmscan function writeheader ::scan::donothing hmscan function writepoint ::scan::hmm_writepoint hmscan function count ::scan::hmm_count #hmscan function collect ::scan::scan_collect hmscan function prepare ::scan::hmm_scan_prepare hmscan function finish ::scan::hmm_scan_finish namespace eval scan { command hdb_bmonscan { text:drivable scan_variable float: scan_start float: scan_increment int: NP text:monitor,timer mode float: preset int:0,2 channel} { bmonscan clear # bmonscan configure script bmonscan add $scan_variable $scan_start $scan_increment bmonscan setchannel $channel; set status [catch {bmonscan run $NP $mode $preset} msg] # bmonscan configure soft if {$status == 0} { return $msg } else { return -code error "ERROR [info level 0]" } } ::scan::hdb_bmonscan -addfb text filename text mode float preset float scan_variable_value int scanpoint int counts text status ::scan::hdb_bmonscan -set feedback status IDLE command hdb_hmscan { text:drivable scan_variable float: scan_start float: scan_increment int: NP text:monitor,timer mode float: preset int:0,2 channel} { hmscan clear hmscan add $scan_variable $scan_start $scan_increment hmscan setchannel $channel; set status [catch {hmscan run $NP $mode $preset} msg] if {$status == 0} { return $msg } else { return -code error "ERROR [info level 0]" } } ::scan::hdb_hmscan -addfb text filename text mode float preset float scan_variable_value int scanpoint int counts text status ::scan::hdb_hmscan -set feedback status IDLE } sicslist setatt ::scan::hdb_bmonscan long_name bmonscan sicslist setatt ::scan::hdb_hmscan long_name hmscan namespace eval scan { namespace export runscan VarMake ::scan::runscan_reset_position Text internal ::scan::runscan_reset_position false proc runscan {scanvar start stop numpoints mode preset {savetype "save"} } { variable save_filetype variable reset_position set reset_position [SplitReply [::scan::runscan_reset_position]] if {[is_drivable $scanvar] == 0} { return -code error "The scan variable <$scanvar> must be drivable" } if {[string is integer $numpoints] != 1} { return -code error "Number of points <$numpoints> must be an integer" } if { $numpoints < 1 } { return -code error "Number of points <$numpoints> must not be less than one" } ::histogram_memory::count_method $mode ::histogram_memory::count_size $preset if {$numpoints == 1} { set step 0 } else { set step [expr double($stop - $start)/($numpoints - 1.0)] } if {$step == 0 && $numpoints > 1} { clientput "WARNING:Scan step is zero and number of points > 1. Adjusting numpoints to one" set numpoints 1 } switch $savetype { "save" { set save_filetype data } "nosave" { set save_filetype scratch } default { return -code error "$savetype should be 'save' or 'nosave'" } } hmscan clear hmscan add $scanvar $start $step # hmscan ignores mode and preset, we use FAT_COUNT_METHOD and FAT_COUNT_STOP set status [catch {hmscan run $numpoints timer 0} msg] if {$status == 0} { return $msg } else { return -code error "ERROR [info level 0]\n$msg" } } } namespace import ::scan::runscan publish runscan user sicslist setatt runscan privilege internal