# Author: Ferdi Franceschini # Based on the examples in the hs_test.tcl sample configuration by Mark Lesha. # http://gumtree.ansto.gov.au:9080/nbicms/bragg-systems/histogram-server/hs_test.tcl/view ## # @file Provides generic code and parameters for configuring the ANSTO histogram memory server # The instrument specific histogram memory configuration files must define an initialisation # function with the following signature # @code proc ::histogram_memory::initialize {} # this function should call the generic initalisation function, # ::histogram_memory::ic_initialize # #@see ::histogram_memory::ic_initialize source $cfPath(hmm)/hmm_object.tcl namespace eval histogram_memory { # Common config variables variable histmem_simulation variable ic_count_methods variable ic_fsrce_values variable preset_mult variable monitor_controlled variable oscmd_controlled set monitor_controlled "false" set oscmd_controlled "false" # Instrument Specific Config variables set histmem_simulation [SplitReply [hmm_simulation]] proc init_hmm_objs {} { variable histmem_simulation variable ic_count_methods variable ic_fsrce_values variable default_frame_source_when_there_is_no_frame_signal variable default_frame_source_always_internal if [ catch { set ic_fsrce_values [ list INTERNAL EXTERNAL ] set ic_count_methods [concat [list time unlimited period count frame] $::counter::isc_beam_monitor_list ] if {$histmem_simulation == "true"} { MakeHM hmm SIM hmm configure daq Stopped hmm configure statuscheck false hmm configure num_events_filled_to_histo 12345 hmm configure acq_dataset_active_sec 9.8 hmm configure ratemap_xy_max_bin 123 hmm configure ratemap_xy_total 321 hmm configure maximum_period 0 foreach bm $::counter::isc_beam_monitor_list { set bm_num [string index $bm end] if [string is integer $bm_num] { hmm configure bm${bm_num}_status DISABLED hmm configure bm${bm_num}_counts 12345 hmm configure bm${bm_num}_event_rate 50 } } proc hmc {_start _preset _mode _pause pauseval} { if [ catch { bm mode $_mode bm preset $_preset hmm countblock } message ] { return -code error "([info level 0]) $message" } } } else { ANSTO_MakeHM hmm anstohttp MakeHMControl_ANSTO hmc bm hmm; } # Frame source for each instrument if freq = 0, this can happen when automatically # setting frequencies from choppers. array set default_frame_source_when_there_is_no_frame_signal { echidna INTERNAL koala INTERNAL kowari EXTERNAL pelican INTERNAL platypus EXTERNAL quokka INTERNAL taipan INTERNAL wombat INTERNAL } array set default_frame_source_always_internal { echidna "true" koala "false" kowari "false" pelican "false" platypus "false" quokka "false" taipan "false" wombat "false" } ::utility::mkVar detector_active_height_mm Float user active_height true detector true true sicslist setatt detector_active_height_mm units mm ::utility::mkVar detector_active_width_mm Float user active_width true detector true true sicslist setatt detector_active_width_mm units mm ::utility::mkVar hmm_user_configpath Text manager user_configpath false detector false false hmm_user_configpath ../user_config/hmm ::utility::mkVar hmm_mode Text user mode true detector true true ::utility::mkVar hmm_preset Float user preset true detector true true } message ] { return -code error "([info level 0]) $message" } } ############################################## # Creating the histogram memories in SICS ############################################## # Make a histogram memory object hmm, allows control of the # remote histogram server via http, and acquisition # of histogram period data. ############################################## # Configuring the histogram server ############################################## # Procedure to read a single config (or any) file, return content as a string. proc returnconfigfile {filename} { if [ catch { set fh [open $filename] set xml [read $fh] close $fh set cfg [subst $xml] } message ] { return -code error "([info level 0]) $message" } return $cfg } # Here, define a function to let us read back the value of dictionary items from the hmm # such as OAT dimensions. proc hmmdictitemval {histomem dictitem} { if [ catch { set resp [$histomem configure $dictitem] set retn [lindex [split $resp " "] 2] } message ] { return -code error "([info level 0]) $message" } return $retn } ## # @brief Use histogram server to control acquisitions proc set_termination_conditions {count_method count_size count_stop} { if [ catch { hmm configure FAT_COUNT_METHOD $count_method hmm configure FAT_COUNT_SIZE $count_size hmm configure FAT_COUNT_STOP $count_stop hmm init } message ] { return -code error "([info level 0]) $message" } } # Simulated counter. No error rate. Required for technical reasons... # The simulated counter is used only to block execution till the bm count is actually reached, # for the scan example using hmc and bm objects to control the acquisition duration from SICS. MakeCounter blockctr SIM -1.0 blockctr SetExponent 0 blockctr SetMode timer blockctr SetPreset 0 ############################################## # Support for using expanded histogram period # to create interlaced/overlapped histograms ############################################## # Define an OAT offset variable to use with both scans: # It is possible to effectively offset the histogram filler's # OAT table by an arbitrary amount. For overlapped data acquisitions, we can # configure an oversized histogram period using the EXPAND_OAT parameters # in the FAT. Then at each scan stop, before acqisition commences the offset # can be adjusted using the OFFSET_OAT paramters of the FAT. By progressively # stepping the OFFSET_OAT, an overlapped image can be built up. # The global variable oatoffset is defined for this purpose. # During the scan, this variable is incremented and can be passed # in to an argument of set_oat_offset to provide progressively # increasing offset, producing an overlapped histogram. # global oatoffset # #Function to apply OAT offsets to the histogram server. proc set_oat_offset {oatoff_x oatoff_y oatoff_t} { if [ catch { hmm configure FAT_OFFSET_OAT_X $oatoff_x hmm configure FAT_OFFSET_OAT_Y $oatoff_y hmm configure FAT_OFFSET_OAT_T $oatoff_t hmm init } message ] { return -code error "([info level 0]) $message" } } ############################################## # Support for data acquisition ############################################## # A simple procedure to read the histogram data through SICS # and dump the data to a numbered file. proc savehistodata {histomem filename} { set ::errorInfo "" set fh [open $filename "w"] # To get the whole memory, we don't need to specify the start or end arguments. # But we need to specify the bank number, this sets the type of data to be read. # set histodata [$histomem get [hmmdictitemval $histomem bank]] # clientput $histodata value puts -nonewline $fh $histodata close $fh return } ############################################## ############################################## ## Scan Callback Procedures ## ############################################## ############################################## proc set_sobj_attributes {} { if [ catch { # SICS commands sicslist setatt blockctr privilege internal; # histogram memory macros sicslist setatt ::histogram_memory::set_oat_offset privilege internal; sicslist setatt ::histogram_memory::scan2_runb privilege internal; sicslist setatt ::histogram_memory::scan2_runa privilege internal; sicslist setatt ::histogram_memory::returnconfigfile privilege internal; sicslist setatt ::histogram_memory::save privilege internal; } message ] { return -code error "([info level 0]) $message" } } ## # @brief Returns the histogram memory server clock scale. # # NOTE: The histmem server doesn't provide the clock scale to SICS\n # so we just hardwire 1000 nanoseconds which is the current (10/01/08)\n # value on all the servers. proc clock_scale {args} { switch $args { "" { return [expr [SplitReply [hmm configure fat_clock_scale]]/1000.0] } "units" { return "microseconds"} default { return -code error "[info level 0]: Invalid argument $args" } } } proc get_clock_scale {} { return [SplitReply [hmm configure fat_clock_scale]] } proc set_clock_scale {val} { set catch_status [ catch { if {[string is integer $val] == 0} { error "ERROR: clock scale should be an integer. NOTE: The clock base is in nanoseconds" } hmm configure fat_clock_scale $val ::histogram_memory::stop hmm init } message ] handle_exception $catch_status $message } ## @brief Use boundaries or centres to calculate axis values # # @param axis_name x_bin, y_bin, x_pixel_offset, y_pixel_offset, two_theta # @param type centres or boundaries proc set_graphtype {axis_name type} { variable state switch -- $type { "centres" { set state($axis_name,graph_type) "centres" } "boundaries" { set state($axis_name,graph_type) "boundaries" } default { error "ERROR: Unknown graph type $type" } } } proc get_graphtype {axis_name} { variable state return $state($axis_name,graph_type) } ## @brief Calculate axis array from a given list of bin boundaries # Generates a sicsdata array # # @param axis_name Fully qualified name of the calling procedure # @param scale_factor axis scale factor or @none # @param offset axis offset or @none # @param boundaries list of bin boundaries or @none proc calc_axis {axis_name scale_factor offset boundaries {bb_zero_offset 0}} { variable state set bin_array ::histogram_memory::${axis_name}_array if [ catch { set i 0 $bin_array clear if {$state($axis_name,graph_type) == "boundaries"} { foreach bb $boundaries { set val [expr {$scale_factor*($bb+$bb_zero_offset) + $offset}] $bin_array putfloat $i $val incr i } } else { foreach b0 [lrange $boundaries 0 end-1] b1 [lrange $boundaries 1 end] { set val [expr {$scale_factor*($bb_zero_offset + ($b1 + $b0)/2.0) + $offset}] $bin_array putfloat $i $val incr i } } } message ] { return -code error "([info level 0]) $message" } } sicsdatafactory new ::histogram_memory::y_bin_array ## # @brief Provides y_bin boundary array for data axes proc y_bin {args} { if [ catch { ::histogram_memory::calc_axis "y_bin" 1.0 0.0 [OAT_TABLE Y -getdata BOUNDARIES] if {$args == "-get_data_ref"} { set binarray "::histogram_memory::y_bin_array" } else { set binarray [::histogram_memory::y_bin_array used] } } message ] { return -code error "([info level 0]) $message" } return $binarray } set script_name ::histogram_memory::y_bin publish $script_name user sicslist setatt $script_name privilege user sicslist setatt $script_name kind script sicslist setatt $script_name access read_only sicslist setatt $script_name dtype floatvarar sicslist setatt $script_name dlen 100 sicslist setatt $script_name klass detector sicslist setatt $script_name control false sicslist setatt $script_name data true sicslist setatt $script_name nxsave true sicslist setatt $script_name mutable false sicslist setatt $script_name long_name y_bin unset script_name sicsdatafactory new ::histogram_memory::x_bin_array ## # @brief Provides x_bin boundary array for data axes proc x_bin {args} { if [ catch { ::histogram_memory::calc_axis "x_bin" 1.0 0.0 [OAT_TABLE X -getdata BOUNDARIES] if {$args == "-get_data_ref"} { set binarray "::histogram_memory::x_bin_array" } else { set binarray [::histogram_memory::x_bin_array used] } } message ] { return -code error "([info level 0]) $message" } return $binarray } set script_name ::histogram_memory::x_bin publish $script_name user sicslist setatt $script_name privilege user sicslist setatt $script_name kind script sicslist setatt $script_name access read_only sicslist setatt $script_name dtype floatvarar sicslist setatt $script_name dlen 100 sicslist setatt $script_name klass detector sicslist setatt $script_name control false sicslist setatt $script_name data true sicslist setatt $script_name nxsave true sicslist setatt $script_name mutable false sicslist setatt $script_name long_name x_bin unset script_name # requires detector_active_width_mm det_radius_mm sicsdatafactory new ::histogram_memory::y_pixel_offset_array proc y_pixel_offset {args} { variable state if [ catch { set det_height_mm [SplitReply [detector_active_height_mm]] set max_chan [OAT_TABLE Y -getdata MAX_CHAN] set scale_factor [expr {$det_height_mm / $max_chan}] set offset 0.0 ::histogram_memory::calc_axis "y_pixel_offset" $scale_factor $offset [OAT_TABLE Y -getdata BOUNDARIES] if {$args == "-get_data_ref"} { set binarray "::histogram_memory::y_pixel_offset_array" } else { set binarray [::histogram_memory::y_pixel_offset_array used] } } message ] { return -code error "([info level 0]) $message" } return $binarray } set script_name ::histogram_memory::y_pixel_offset publish $script_name user sicslist setatt $script_name privilege user sicslist setatt $script_name kind script sicslist setatt $script_name access read_only sicslist setatt $script_name dtype floatvarar sicslist setatt $script_name dlen 100 sicslist setatt $script_name klass detector sicslist setatt $script_name control false sicslist setatt $script_name data true sicslist setatt $script_name nxsave true sicslist setatt $script_name mutable false sicslist setatt $script_name long_name y_pixel_offset sicslist setatt $script_name units "mm" unset script_name # requires detector_active_width_mm det_radius_mm sicsdatafactory new ::histogram_memory::x_pixel_offset_array proc x_pixel_offset {args} { variable state if [ catch { set det_width_mm [SplitReply [detector_active_width_mm]] set max_chan [OAT_TABLE X -getdata MAX_CHAN] set scale_factor [expr {$det_width_mm / $max_chan}] set offset 0.0 ::histogram_memory::calc_axis "x_pixel_offset" $scale_factor $offset [OAT_TABLE X -getdata BOUNDARIES] if {$args == "-get_data_ref"} { set binarray "::histogram_memory::x_pixel_offset_array" } else { set binarray [::histogram_memory::x_pixel_offset_array used] } } message ] { return -code error "([info level 0]) $message" } return $binarray } set script_name ::histogram_memory::x_pixel_offset publish $script_name user sicslist setatt $script_name privilege user sicslist setatt $script_name kind script sicslist setatt $script_name access read_only sicslist setatt $script_name dtype floatvarar sicslist setatt $script_name dlen 100 sicslist setatt $script_name klass detector sicslist setatt $script_name control false sicslist setatt $script_name data true sicslist setatt $script_name nxsave true sicslist setatt $script_name mutable false sicslist setatt $script_name long_name x_pixel_offset sicslist setatt $script_name units "mm" unset script_name sicsdatafactory new ::histogram_memory::time_channel_array proc time_channel {args} { variable state if [ catch { ::histogram_memory::calc_axis "time_channel" [::histogram_memory::clock_scale] 0.0 [OAT_TABLE T -getdata BOUNDARIES] if {$args == "-get_data_ref"} { set binarray "::histogram_memory::time_channel_array" } else { set binarray [::histogram_memory::time_channel_array used] } } message ] { return -code error "([info level 0]) $message" } return $binarray } set script_name ::histogram_memory::time_channel publish $script_name user sicslist setatt $script_name privilege user sicslist setatt $script_name kind script sicslist setatt $script_name access read_only sicslist setatt $script_name dtype floatvarar sicslist setatt $script_name dlen 100 sicslist setatt $script_name klass detector sicslist setatt $script_name control false sicslist setatt $script_name data true sicslist setatt $script_name nxsave true sicslist setatt $script_name mutable false sicslist setatt $script_name long_name time_of_flight sicslist setatt $script_name units [::histogram_memory::clock_scale units] unset script_name } ################################# # Must always specify number of channels # bb list len <= channels+1 # Calculate the boundaries after successfully uploading a configuration. # set values [OAT_TABLE -get X] # set channels [OAT_TABLE -get NXC] # OAT_TABLE X -setdata BOUNDARIES [calc_boundaries $values $channels] proc ::histogram_memory::calc_boundaries {values channels} { if [ catch { set bbnum [llength $values] set maxbblen [expr $channels+1] set maxchan [expr $channels - 1] if {$bbnum > $maxbblen} { error "ERROR: The number of bin boundaries must be less than or equal to $maxbblen" } set BOUNDARIES "" if {$bbnum > 2} { set BOUNDARIES $values } elseif {$bbnum == 2} { foreach {leftbb rightbb} $values {} set bstep [expr {$rightbb-$leftbb}] if {$bstep == 0} { error "ERROR: The generating bin boundaries are equal" } set startbin [expr ($leftbb+$rightbb)/2.0] # FIXME This check doesn't work for time, T # if {$startbin < 0.0 || $startbin > $maxchan} { # error "ERROR: $leftbb and $rightbb must bound a channel >= 0 or <= $maxchan" # } for {set bb $leftbb; set i 0} {$i < $maxbblen} {incr i; set bb [expr {$bb + $bstep}]} { lappend BOUNDARIES $bb } } else { error "ERROR: You must specify at least two bin boundaries" } } message ] { return -code error $message } return $BOUNDARIES } set hmm_xml "" ## # @brief Provides a standard set of subcommands for the histogram server table # configuration commands. # # @param tag Table identifier, one of BAT CAT FAT NAT OAT SAT SRV # @param attributes Defines the list of attributes which you will be allowed to set. # @param element_list Defines the list of elements which you will be allowed to set. # Use "" if your table doesn't contain any elements. # @param args This can be empty, or a list of name value pairs for the attributes # and elements which you want to set or one of the subcommands listed below. # If args is empty this function will simply return an xml fragment for the named table, # # Subcommands\n # -clear clears the table\n # -init A list of name value pairs. If you use attribute or element names then # the corresponding table entries will be initilised to the given values, any # attributes or elements which aren't specified will be cleared. You can also # specify extra parameters to store in the table which might be required to # specify limits or constants which may be necessary for deriving configuration # parameters.\n # -get return the value for the named attribute or element\n # -attlist list all of the attributes with their values.\n # TODO Maintain "proposed" and "current" tables. Provide a setcurrent command which can # only be called by the upload_config command to set the proposed tables as current # TODO Allow for top level content in tables and attributes in sub-elements proc HISTMEM_TABLE {tpath args} { global hmm_xml if [ catch { set retVal "" set tpath [string toupper $tpath] foreach {opt arglist} [::utility::get_opt_arglist $args] {} switch -- $opt { "-dump" { foreach {k v} $hmm_xml {clientput $k; foreach {name val} $v {clientput "$name: $val"}} } "-allowed_attributes" { if {[llength $arglist] == 0} { set retVal [::utility::tabget hmm_xml $tpath/_ALLOWED_ATTRIBUTES_] } else { ::utility::tabset hmm_xml $tpath/_ALLOWED_ATTRIBUTES_ [lindex $arglist 0] } } "-allowed_elements" { if {[llength $arglist] == 0} { set retVal [::utility::tabget hmm_xml $tpath/_ALLOWED_ELEMENTS_] } else { ::utility::tabset hmm_xml $tpath/_ALLOWED_ELEMENTS_ [lindex $arglist 0] ::utility::tabset hmm_xml $tpath/_ELEMENTS_ [lindex $arglist 0] } } "-setel" { set element [lindex $arglist 0] set value [lindex $arglist 1] if {[lsearch [::utility::tabget hmm_xml $tpath/_ALLOWED_ELEMENTS_] $element] >= 0} { ::utility::tabset hmm_xml $tpath/$element/_CONTENT_ $value } else { error "ERROR: $element is not an allowed element in $tpath" } } "-setatt" { set attname [lindex $arglist 0] set value [lindex $arglist 1] if {[lsearch [::utility::tabget hmm_xml $tpath/_ALLOWED_ATTRIBUTES_] $attname] >= 0} { ::utility::tabset hmm_xml $tpath/_ATTLIST_/$attname $value } else { error "ERROR: $attname is not an allowed attribute in $tpath" } } "-getel" { set element [lindex $arglist 0] set retVal [::utility::tabget hmm_xml $tpath/$element/_CONTENT_] } "-getatt" { set attribute [lindex $arglist 0] set retVal [::utility::tabget hmm_xml $tpath/_ATTLIST_/$attribute] } "-delel" { set element [lindex $arglist 0] ::utility::tabdel hmm_xml $tpath/$element } "-delatt" { set attribute [lindex $arglist 0] ::utility::tabdel hmm_xml $tpath/_ATTLIST_/$attribute } "-clear" { ::utility::tabdel hmm_xml $tpath/_ATTLIST_ ::utility::tabdel hmm_xml $tpath/_CONTENT_ foreach element [::utility::tabget hmm_xml $tpath/_ELEMENTS_] { ::utility::tabdel hmm_xml $tpath/$element } } "-setdata" { if {[llength $arglist] == 1} { set arglist [lindex $arglist 0] } foreach {name value} $arglist { if {$value == ""} { error "ERROR: No value supplied when setting $name at $tpath in the histogram memory table" } ::utility::tabset hmm_xml $tpath/_DATA_/$name $value } } "-getdata" { if {[llength $arglist] == 1} { set arglist [lindex $arglist 0] } if {[llength $arglist] <= 1} { set retVal [::utility::tabget hmm_xml $tpath/_DATA_/$arglist] } else { foreach name $arglist { lappend values [::utility::tabget hmm_xml $tpath/_DATA_/$name] } set retVal $values } } "-getxml" { set retVal [::utility::tabxml hmm_xml $tpath] } } } message ] { return -code error "([info level 0]) $message" } else { return $retVal } } ## # @brief Base Address Table configuration parameters as maintained by SICS # proc BAT_TABLE {args} { if [ catch { set attributes { NO_BAT_ENTRIES NO_BAT_PERIODS NO_REPEAT_ENTRY NO_REPEAT_TABLE NO_EXECUTE_TABLE } set elements {{PERIOD_INDICES }} set tag BAT foreach {opt arglist} [::utility::get_opt_arglist $args] {} switch -- $opt { "" { return [HISTMEM_TABLE $tag -getxml] } "-init" { HISTMEM_TABLE $tag -allowed_elements $elements HISTMEM_TABLE $tag -allowed_attributes [concat $attributes $arglist] } "-set" { set allowed_atts [HISTMEM_TABLE $tag -allowed_attributes] set allowed_els [HISTMEM_TABLE $tag -allowed_elements] foreach {arg val} $arglist { set index [lsearch -exact $allowed_els $arg] if {$index >= 0} { incr index HISTMEM_TABLE $tag -setel $arg $val } else { set attname $arg set index [lsearch -exact $allowed_atts $attname] if {$index >= 0} { incr index HISTMEM_TABLE $tag -setatt $attname $val } } } } "-get" { set allowed_atts [HISTMEM_TABLE $tag -allowed_attributes] set allowed_els [HISTMEM_TABLE $tag -allowed_elements] foreach arg $arglist { set index [lsearch -exact $allowed_els $arg] if {$index >= 0} { lappend values [HISTMEM_TABLE $tag -getel $arg] } else { set attname $arg set index [lsearch -exact $allowed_atts $attname] if {$index >= 0} { lappend values [HISTMEM_TABLE $tag -getatt $attname] } } } if {[llength $values] == 1} { return [lindex $values 0] } else { return $values } } "-del" { foreach att [lindex $attributes 0] el [lindex $elements 0] { set index [lsearch -exact $arglist $el] if {$index >= 0} { HISTMEM_TABLE $tag -delel $el } set index [lsearch -exact $arglist $att] if {$index >= 0} { HISTMEM_TABLE $tag -delatt $att } } } "-setdata" { HISTMEM_TABLE $tag -setdata $arglist } "-getdata" { return [HISTMEM_TABLE $tag -getdata $arglist] } "-clear" { HISTMEM_TABLE $tag -clear } default { error "ERROR: Unknown subcommand $opt" } } } message ] { if {$::errorCode=="NONE"} {return $message} return -code error "([info level 0]) $message" } } ## # @brief CAlibration Table configuration parameters as maintained by SICS # proc CAT_TABLE {args} { if [ catch { set attributes { FRAME_FREQUENCY SIZE_PERIOD COUNT_METHOD COUNT_SIZE READ_DATA_TYPE } set elements {{MESYTEC_MPSD8_CHANNEL_GAINS MESYTEC_MPSD8_THRESHOLDS MESYTEC_TUBE_PAIR_RESISTANCE_RATIOS MESYTEC_TUBE_MAGNIFICATIONS MESYTEC_TUBE_OFFSETS MESYTEC_TUBE_HISTOGRAM_WEIGHTS }} set tag CAT foreach {opt arglist} [::utility::get_opt_arglist $args] {} switch -- $opt { "" { return [HISTMEM_TABLE $tag -getxml] } "-init" { HISTMEM_TABLE $tag -allowed_elements $elements HISTMEM_TABLE $tag -allowed_attributes [concat $attributes $arglist] } "-set" { set allowed_atts [HISTMEM_TABLE $tag -allowed_attributes] set allowed_els [HISTMEM_TABLE $tag -allowed_elements] foreach {arg val} $arglist { set index [lsearch -exact $allowed_els $arg] if {$index >= 0} { incr index HISTMEM_TABLE $tag -setel $arg $val } else { set attname $arg set index [lsearch -exact $allowed_atts $attname] if {$index >= 0} { incr index HISTMEM_TABLE $tag -setatt $attname $val } } } } "-get" { set allowed_atts [HISTMEM_TABLE $tag -allowed_attributes] set allowed_els [HISTMEM_TABLE $tag -allowed_elements] foreach arg $arglist { set index [lsearch -exact $allowed_els $arg] if {$index >= 0} { lappend values [HISTMEM_TABLE $tag -getel $arg] } else { set attname $arg set index [lsearch -exact $allowed_atts $attname] if {$index >= 0} { lappend values [HISTMEM_TABLE $tag -getatt $attname] } } } if {[llength $values] == 1} { return [lindex $values 0] } else { return $values } } "-del" { foreach att [lindex $attributes 0] el [lindex $elements 0] { set index [lsearch -exact $arglist $el] if {$index >= 0} { HISTMEM_TABLE $tag -delel $el } set index [lsearch -exact $arglist $att] if {$index >= 0} { HISTMEM_TABLE $tag -delatt $att } } } "-setdata" { HISTMEM_TABLE $tag -setdata $arglist } "-getdata" { return [HISTMEM_TABLE $tag -getdata $arglist] } "-clear" { HISTMEM_TABLE $tag -clear } default { error "ERROR: Unknown subcommand $opt" } } } message ] { if {$::errorCode=="NONE"} {return $message} return -code error "([info level 0]) $message" } } ## # @brief Frequency Address Table configuration parameters as maintained by SICS # proc FAT_TABLE {args} { if [ catch { set attributes { FRAME_FREQUENCY FRAME_BUFFER FRAME_DUTYCYCLE SIZE_PERIOD NOS_PERIODS COUNT_METHOD COUNT_SIZE READ_DATA_TYPE VIEW_MAG_X VIEW_MAG_Y HISTO_STREAMING P7888_PLL_FREQ_CARD_X P7888_PLL_FREQ_CARD_Y P7888_CARD_MODE_X P7888_CARD_MODE_Y RAW_HISTO_XMIN RAW_HISTO_XMAX RAW_HISTO_YMIN RAW_HISTO_YMAX TEST_HISTO_1D_SIZES TEST_HISTO_2D_SIZES P7888_PLL_SYNC_METHOD } set elements {{ }} set tag FAT foreach {opt arglist} [::utility::get_opt_arglist $args] {} switch -- $opt { "" { return [HISTMEM_TABLE $tag -getxml] } "-init" { HISTMEM_TABLE $tag -allowed_elements $elements HISTMEM_TABLE $tag -allowed_attributes [concat $attributes $arglist] } "-set" { set allowed_atts [HISTMEM_TABLE $tag -allowed_attributes] set allowed_els [HISTMEM_TABLE $tag -allowed_elements] foreach {arg val} $arglist { set index [lsearch -exact $allowed_els $arg] if {$index >= 0} { incr index HISTMEM_TABLE $tag -setel $arg $val } else { set attname $arg set index [lsearch -exact $allowed_atts $attname] if {$index >= 0} { incr index HISTMEM_TABLE $tag -setatt $attname $val } } } } "-get" { set allowed_atts [HISTMEM_TABLE $tag -allowed_attributes] set allowed_els [HISTMEM_TABLE $tag -allowed_elements] foreach arg $arglist { set index [lsearch -exact $allowed_els $arg] if {$index >= 0} { lappend values [HISTMEM_TABLE $tag -getel $arg] } else { set attname $arg set index [lsearch -exact $allowed_atts $attname] if {$index >= 0} { lappend values [HISTMEM_TABLE $tag -getatt $attname] } } } if {[llength $values] == 1} { return [lindex $values 0] } else { return $values } } "-del" { foreach att [lindex $attributes 0] el [lindex $elements 0] { set index [lsearch -exact $arglist $el] if {$index >= 0} { HISTMEM_TABLE $tag -delel $el } set index [lsearch -exact $arglist $att] if {$index >= 0} { HISTMEM_TABLE $tag -delatt $att } } } "-setdata" { HISTMEM_TABLE $tag -setdata $arglist } "-getdata" { return [HISTMEM_TABLE $tag -getdata $arglist] } "-clear" { HISTMEM_TABLE $tag -clear } default { error "ERROR: Unknown subcommand $opt" } } } message ] { if {$::errorCode=="NONE"} {return $message} return -code error "([info level 0]) $message" } } ## # @brief Offset Address Table configuration parameters as maintained by SICS # # @param -clear clears OAT_TABLE XML fragment # @param -init X_MIN X_MAX Y_MIN Y_MAX # Initialise minimum and maximum bin boundaries. # @param -get # @param -attlist # @param -clear clears the oat table and the fat table SIZE_PERIOD # # Sets X_BOUNDARIES, Y_BOUNDARIES and T_BOUNDARIES proc OAT_TABLE {args} { if [ catch { array set attlookup {NXC NO_OAT_X_CHANNELS NYC NO_OAT_Y_CHANNELS NTC NO_OAT_T_CHANNELS} set elements {{ X Y T }} set tag OAT set element [lindex $args 0] if {[ lsearch [lindex $elements 0] $element] == -1} { unset element } else { set tag $tag/$element set args [lrange $args 1 end] } foreach {opt arglist} [::utility::get_opt_arglist $args] {} switch -- $opt { "" { return [HISTMEM_TABLE $tag -getxml] } "-init" { HISTMEM_TABLE $tag -allowed_elements $elements foreach {n v} [array get attlookup] { lappend attributes $v } HISTMEM_TABLE $tag -allowed_attributes [concat $attributes $arglist] } "-set" { set allowed_atts [HISTMEM_TABLE $tag -allowed_attributes] set allowed_els [HISTMEM_TABLE $tag -allowed_elements] foreach {arg val} $arglist { set index [lsearch -exact $allowed_els $arg] if {$index >= 0} { incr index HISTMEM_TABLE $tag -setel $arg $val } else { if [info exists attlookup($arg)] { set attname $attlookup($arg) } else { set attname $arg } set index [lsearch -exact $allowed_atts $attname] if {$index >= 0} { incr index HISTMEM_TABLE $tag -setatt $attname $val } } } foreach {nxc nyc} [OAT_TABLE -get NXC NYC] {} set max_nxc [::histogram_memory::max_chan_num X] set max_nyc [::histogram_memory::max_chan_num Y] if {$nxc > $max_nxc} { gumput "WARNING: Reducing NO_OAT_X_CHANNELS from $nxc to maximum $max_nxc" warning OAT_TABLE -set NXC $max_nxc } if {$nyc > $max_nyc} { gumput "WARNING: Reducing NO_OAT_Y_CHANNELS from $nyc to maximum $max_nyc" warning OAT_TABLE -set NYC $max_nyc } foreach axis {X Y T} { set bins [::histogram_memory::oat_bins $axis] set nch [::histogram_memory::number_of_channels $axis] OAT_TABLE $axis -setdata BOUNDARIES [::histogram_memory::calc_boundaries $bins $nch] } } "-get" { set allowed_atts [HISTMEM_TABLE $tag -allowed_attributes] set allowed_els [HISTMEM_TABLE $tag -allowed_elements] foreach arg $arglist { set index [lsearch -exact $allowed_els $arg] if {$index >= 0} { lappend values [HISTMEM_TABLE $tag -getel $arg] } else { if [info exists attlookup($arg)] { set attname $attlookup($arg) } else { set attname $arg } set index [lsearch -exact $allowed_atts $attname] if {$index >= 0} { lappend values [HISTMEM_TABLE $tag -getatt $attname] } } } if {[llength $values] == 1} { return [lindex $values 0] } else { return $values } } "-del" { foreach att [array names attlookup] el [lindex $elements 0] { set index [lsearch -exact $arglist $el] if {$index >= 0} { HISTMEM_TABLE $tag -delel $el } set index [lsearch -exact $arglist $att] if {$index >= 0} { HISTMEM_TABLE $tag -delatt $attlookup($att) } } } "-setdata" { HISTMEM_TABLE $tag -setdata $arglist } "-getdata" { return [HISTMEM_TABLE $tag -getdata $arglist] } "-clear" { HISTMEM_TABLE $tag -clear } default { error "ERROR: Unknown subcommand $opt" } } } message ] { if {$::errorCode=="NONE"} {return $message} return -code error "([info level 0]) $message" } } # @brief Spatial Allocation Table configuration parameters as maintained by SICS # # Only one element, ie SPLIT with no content just attributes. proc SAT_TABLE {args} { if [ catch { set attributes { APPLY MIDPOINT DIRECTION WRAP SWAP} set elements {{ SPLIT }} set tag SAT set attpath SAT/SPLIT foreach {opt arglist} [::utility::get_opt_arglist $args] {} switch -- $opt { "" { return [HISTMEM_TABLE $tag -getxml] } "-init" { HISTMEM_TABLE $tag -allowed_elements $elements HISTMEM_TABLE $attpath -allowed_attributes [concat $attributes $arglist] } "-set" { set allowed_atts [HISTMEM_TABLE $attpath -allowed_attributes] set allowed_els [HISTMEM_TABLE $tag -allowed_elements] foreach {arg val} $arglist { set index [lsearch -exact $allowed_els $arg] if {$index >= 0} { incr index HISTMEM_TABLE $tag -setel $arg $val } else { set attname $arg set index [lsearch -exact $allowed_atts $attname] if {$index >= 0} { incr index HISTMEM_TABLE $attpath -setatt $attname $val } } } } "-get" { set allowed_atts [HISTMEM_TABLE $attpath -allowed_attributes] set allowed_els [HISTMEM_TABLE $tag -allowed_elements] foreach arg $arglist { set index [lsearch -exact $allowed_els $arg] if {$index >= 0} { lappend values [HISTMEM_TABLE $tag -getel $arg] } else { set attname $arg set index [lsearch -exact $allowed_atts $attname] if {$index >= 0} { lappend values [HISTMEM_TABLE $tag -getatt $attname] } } } if {[llength $values] == 1} { return [lindex $values 0] } else { return $values } } "-del" { foreach att $attributes { set index [lsearch -exact $arglist $att] if {$index >= 0} { HISTMEM_TABLE $attpath -delatt $att } } } "-setdata" { HISTMEM_TABLE $tag -setdata $arglist } "-getdata" { return [HISTMEM_TABLE $tag -getdata $arglist] } "-clear" { HISTMEM_TABLE $tag -clear HISTMEM_TABLE $attpath -allowed_attributes $attributes } default { error "ERROR: Unknown subcommand $opt" } } } message ] { if {$::errorCode=="NONE"} {return $message} return -code error "([info level 0]) $message" } } proc ::histogram_memory::pre_count {} {} proc ::histogram_memory::post_count {} {} ## # @brief Resolve dependencies between the histogram memory tables proc ::histogram_memory::synch_tables {} { if [ catch { set noxch [OAT_TABLE -get NXC] set noych [OAT_TABLE -get NYC] set notch [OAT_TABLE -get NTC] FAT_TABLE -set SIZE_PERIOD [expr $noxch*$noych*$notch] } message ] { return -code error "([info level 0]) $message" } } proc ::histogram_memory::clear_tables {} { if [ catch { set ::errorInfo "" BAT_TABLE -clear CAT_TABLE -clear FAT_TABLE -clear OAT_TABLE -clear SAT_TABLE -clear } message ] { return -code error "([info level 0]) $message" } } ## # @brief Calculate the maximum number of oat channels from the generating bin # boundaries of the given axis proc ::histogram_memory::max_chan_num {axis} { if [ catch { set bins [OAT_TABLE -get $axis] set numb_bins [llength $bins] if {$numb_bins < 2} { error "ERROR: $axis must have at least two bin boundaries" } elseif {$numb_bins > 2} { return $numb_bins } else { foreach {leftbb rightbb} $bins {} set bstep [expr $rightbb - $leftbb] if {$bstep == 0} { error "ERROR: Bin boundaries for $axis must not be equal" } elseif {$bstep < 0} { set binlim [OAT_TABLE $axis -getdata BMIN] } else { set binlim [OAT_TABLE $axis -getdata BMAX] } } set numb_bins [expr {int(floor(($binlim - $leftbb)/$bstep))}] return $numb_bins } message ] { if {$::errorCode=="NONE"} {return $message} return -code error "([info level 0]) $message" } } ## # @brief When called without arguments this returns the name of the filler defaults file # for the histogram server. When called with an argument it sets the current name of the # filler defaults file. # # When anstohm_linked.xml is uploaded to the histogram server it calls this via # command substitution to set the name of the filler defaults file. proc ::histogram_memory::filler_defaults {args} { variable hmm_def_filename if [ catch { if {[llength $args] > 0} { set hmm_def_filename $args } } message ] { return -code error "([info level 0]) $message" } return $hmm_def_filename } ## # @brief Returns the oat table bin boundaries. # This function can be replaced with an instrument specific definition # in the instrumenent specific configuration file. proc ::histogram_memory::oat_bins {axis} { if [ catch { set bins [OAT_TABLE -get $axis] } message ] { return -code error "([info level 0]) $message" } return $bins } ## # @brief Returns the current number of channels for a given axis. # This function can be replaced with an instrument specific definition # in the instrumenent specific configuration file. proc ::histogram_memory::number_of_channels {axis} { array set channID {X NXC Y NYC T NTC} if [ catch { set nchans [OAT_TABLE -get $channID($axis)] } message ] { return -code error "([info level 0]) $message" } return $nchans } # TODO Set current oat table after uploading proposed oat_table proc ::histogram_memory::upload_config {filler_defaults} { if [ catch { ::histogram_memory::synch_tables ::histogram_memory::filler_defaults $filler_defaults hmm stop hmm configure init 1 hmm init # Restore the init level to 0 # subesquent inits will only upload specified FAT settings to histogram server. hmm configure init 0 hmm init # Now issue stop to the server. # This not only makes sure it's stopped, but lets us see certain configuration variables # which get placed in the dictionary as part of the status checking done during the stop. hmm configure statuscheck true hmm stop hmm configure statuscheck false # ::histogram_memory::configure_dims # foreach axis {X Y T} { # set bins [oat_bins $axis] # set nch [number_of_channels $axis] # OAT_TABLE $axis -setdata BOUNDARIES [calc_boundaries $bins $nch] # } clientput "histmem configuration uploaded" } message ] { if {$::errorCode=="NONE"} { return $message } else { return -code error "([info level 0]) $message" } } } ## # @brief If set to true then the frame_source will always be set to INTERNAL. # # @see ::histogram_memory::set_frame_source proc ::histogram_memory::frame_source_always_internal {args} { variable fs_always_internal if [ catch { if {$args == ""} { return $fs_always_internal } set flag [lindex $args 0] if {[string is boolean $flag] == 0} { error "ERROR: $args must be a boolean" } else { set fs_always_internal $flag } } message ] { if {$::errorCode=="NONE"} {return $message} return -code error "([info level 0]) $message" } } publish ::histogram_memory::frame_source_always_internal mugger ## # @brief Return the last frame source which SICS attempted to set proc ::histogram_memory::get_frame_source {} { if [ catch { if [::histogram_memory::frame_source_always_internal] { clientput "WARNING: The frame source is set to always_internal" value clientput "Use ::histogram_memory::frame_source_always_internal to change this." value return INTERNAL } else { return [SplitReply [hmm configure fat_frame_source]] } } message ] { if {$::errorCode=="NONE"} {return $message} return -code error "([info level 0]) $message" } } ## # @brief Sets the histogram memory frame source to the given value. # # @param srce EXTERNAL or INTERNAL # @param always_internal true or false (optional) (default false) proc ::histogram_memory::set_frame_source {srce} { variable ic_fsrce_values if [ catch { if {[lsearch $ic_fsrce_values $srce] == -1} { error "ERROR: $srce is invalid, valid values are \"$ic_fsrce_values\"" } if [::histogram_memory::frame_source_always_internal] { clientput "WARNING: The frame source is set to always_internal" value clientput "Use ::histogram_memory::frame_source_always_internal to change this." value hmm configure fat_frame_source INTERNAL } else { hmm configure fat_frame_source $srce } ::histogram_memory::stop hmm init } message ] { return -code error "([info level 0]) $message" } } ## # @brief Return the last frame frequency which SICS attempted to set proc ::histogram_memory::get_frame_freq {} { if [ catch { set frameFreq [SplitReply [hmm configure fat_frame_frequency]] } message ] { return -code error "([info level 0]) $message" } return $frameFreq } ## # @brief Sets the histogram memory frame frequency to the given value. # # @param freq Frequency in Hz.\n # @param frame_source INTERNAL or EXTERNAL(default) # # If freq=0 then it sets the frequency to 50Hz with an internal frame source. This is useful # if you are setting the frequency from a chopper which is stopped. proc ::histogram_memory::set_frame_freq {freq {frame_source EXTERNAL}} { variable state variable default_frame_source_when_there_is_no_frame_signal if [ catch { if {[string is double $freq] == 0 || $freq < 0} { error "ERROR: Frequency must be a non-negative floating point number" } #TODO Add tolerance parameters to choppercontroller if {abs($freq - 0) <= [expr {2.0/60.0}]} { set zf_frame_source $default_frame_source_when_there_is_no_frame_signal([instname]) if {$zf_frame_source == "INTERNAL"} { clientput "WARNING: A histmem frame frequency of zero was requested, setting frequency to 50Hz instead" value } else { clientput "WARNING: A histmem frame frequency of zero was requested, setting frequency to 50Hz instead" value clientput "WARNING: You must provide an external oscillator" value } ::histogram_memory::set_frame_source $zf_frame_source set newfreq 50 } else { ::histogram_memory::set_frame_source [string toupper $frame_source] ::set newfreq $freq } ::histogram_memory::stop hmm configure fat_frame_frequency $newfreq hmm init } message ] { return -code error "([info level 0]) $message" } } publish ::histogram_memory::set_frame_freq user proc ::histogram_memory::t_max {} { if [ catch { set frame_freq [SplitReply [hmm configure fat_frame_frequency]] } message ] { return -code error "([info level 0]) $message" } } ## # @brief Total counts in histogram defined by the OAT table. ::utility::macro::getset int ::histogram_memory::total_counts {} { return "total_counts = [SplitReply [hmm configure num_events_filled_to_histo]]" } sicslist setatt ::histogram_memory::total_counts klass detector sicslist setatt ::histogram_memory::total_counts long_name total_counts sicslist setatt ::histogram_memory::total_counts mutable true sicslist setatt ::histogram_memory::total_counts units count sicslist setatt ::histogram_memory::total_counts link data_set ## # @brief Histogram memory acquisition time ::utility::macro::getset float ::histogram_memory::time {} { return "time = [SplitReply [hmm configure acq_dataset_active_sec]]" } sicslist setatt ::histogram_memory::time klass detector sicslist setatt ::histogram_memory::time long_name time sicslist setatt ::histogram_memory::time mutable true sicslist setatt ::histogram_memory::time units seconds ::utility::macro::getset float ::histogram_memory::ratemap_xy_max_bin {} { return "ratemap_xy_max_bin = [lindex [hmm configure ratemap_xy_max_bin] 2]" } sicslist setatt ::histogram_memory::ratemap_xy_max_bin klass detector sicslist setatt ::histogram_memory::ratemap_xy_max_bin long_name max_binrate sicslist setatt ::histogram_memory::ratemap_xy_max_bin mutable true ::utility::macro::getset float ::histogram_memory::ratemap_xy_total {} { return "ratemap_xy_total = [lindex [hmm configure ratemap_xy_total] 2]" } sicslist setatt ::histogram_memory::ratemap_xy_total klass detector sicslist setatt ::histogram_memory::ratemap_xy_total long_name total_maprate sicslist setatt ::histogram_memory::ratemap_xy_total mutable true ## # @brief Update the beam monitors when the histmem has finished counting. proc ::histogram_memory::countend_event {} { ::histogram_memory::post_count ::histogram::histmem_cmd -set feedback status IDLE bm status } publish ::histogram_memory::countend_event user ## # @brief Sets histogram server to default configuration, initialises SICS histogram memory # dictionary values and clears SICS OAT BAT CAT FAT ... tables proc ::histogram_memory::ic_initialize {} { variable default_frame_source_when_there_is_no_frame_signal variable default_frame_source_always_internal set ::errorInfo "" if [ catch { # Generate beam monitor feedback macros foreach bm $::counter::isc_beam_monitor_list { set bm_num [string index $bm end] if [string is integer $bm_num] { set bm_status bm${bm_num}_status ::utility::macro::getset text $bm_status {} [subst -nocommands { return "$bm_status = [SplitReply [hmm configure $bm_status]]" }] sicslist setatt $bm_status klass monitor sicslist setatt $bm_status long_name $bm_status sicslist setatt $bm_status mutable false set bm_event_rate bm${bm_num}_event_rate ::utility::macro::getset float $bm_event_rate {} [subst -nocommands { return "$bm_event_rate = [lindex [hmm configure $bm_event_rate] 2]" }] sicslist setatt $bm_event_rate klass monitor sicslist setatt $bm_event_rate long_name $bm_event_rate sicslist setatt $bm_event_rate mutable true sicslist setatt $bm_event_rate units "count/sec" } else { error "ERROR: Failed to get beam monitor number" } } set configuration "::histogram_memory::returnconfigfile config/hmm/anstohm_linked.xml" ::histogram_memory::set_graphtype "y_bin" "boundaries" ::histogram_memory::set_graphtype "x_bin" "boundaries" ::histogram_memory::set_graphtype "y_pixel_offset" "boundaries" ::histogram_memory::set_graphtype "x_pixel_offset" "boundaries" ::histogram_memory::set_graphtype "time_channel" "boundaries" ::histogram_memory::clear_tables # FAT_TABLE -set VIEW_MAG_X -1 VIEW_MAG_Y -1 foreach hm_obj [sicslist type histmem] { $hm_obj configure hmaddress http://das1-[instname].nbi.ansto.gov.au:8080 $hm_obj configure username SICS $hm_obj configure password SICS $hm_obj configure histmode transparent } ::histogram_memory::initialise_dictionary ::histogram_memory::frame_source_always_internal $default_frame_source_always_internal([instname]) ::histogram_memory::set_frame_freq 50 ::histogram_memory::set_clock_scale 1000 ::histogram_memory::set_frame_source $default_frame_source_when_there_is_no_frame_signal([instname]) ::histogram_memory::count_method unlimited ::histogram_memory::count_size 0 ::histogram_memory::softveto false hmm configure hmDataPath ../HMData hmm configure hmconfigscript $configuration #XXX ::histogram_memory::configure_dims scriptcallback connect hmm COUNTEND ::histogram_memory::countend_event } message ] { return -code error "([info level 0]) $message" } } Publish ::histogram_memory::set_oat_offset user Publish ::histogram_memory::scan2_runb user Publish ::histogram_memory::scan2_runa user Publish ::histogram_memory::returnconfigfile user Publish ::histogram_memory::save user Publish BAT_TABLE user Publish CAT_TABLE user Publish FAT_TABLE user Publish OAT_TABLE user Publish SAT_TABLE user ## # @brief Start an acquisition, non-blocking by default # # @param block (optional) default="noblock" proc ::histogram_memory::start {{blocking "noblock"}} { variable histmem_simulation variable monitor_controlled variable oscmd_controlled if [ catch { set options [list block noblock] if {[lsearch $options $blocking] == -1} { error "ERROR: Valid options are $options" } ::histogram_memory::pre_count hmm init if {$monitor_controlled == "true"} { hmm count } else { bm setmode timer bm setpreset 32000000 if {$oscmd_controlled == "true"} { hmm count } else { hmc start 1000000000 timer pause 1 } } set reply [SplitReply [hmm configure daq]] if {$histmem_simulation==false && $reply != "Started"} { error "ERROR: Histogram server failed to start" } clientput "histmem started" value if {$blocking == "block"} { blockctr count 0 ::histogram_memory::pause } } message ] { return -code error "([info level 0]) $message" } } proc ::histogram_memory::softveto {{enable ""}} { variable state if {$enable == ""} { return $state(veto) } if {[string is boolean $enable] == 0} { error "ERROR: $enable must be a boolean" } else { if {$enable} { hmm configure FAT_SOFT_VETO_1 ENABLE } else { hmm configure FAT_SOFT_VETO_1 DISABLE } } } proc ::histogram_memory::veto {action} { switch $action { "on" { if {[status] == "status = Counting"} { hmm veto } else { error "ERROR: veto only allowed while counting" } } "off" { if {[status] == "status = Paused"} { hmm noveto } else { error "ERROR: disabling veto not allowed in this state" } } default { error "ERROR: $action must be 'on' or 'off'" } } } ## # @brief This sends the magic incantation which stops the histogram server. proc ::histogram_memory::stop {} { variable histmem_simulation if [ catch { hmm pause hmm configure statuscheck true hmm stop hmm configure statuscheck false set reply [SplitReply [hmm configure daq]] if {$histmem_simulation==false && $reply != "Stopped"} { error "ERROR: Histogram server failed to stop" } } message ] { return -code error "([info level 0]) $message" } clientput "histmem stopped" value } ## # @brief Allows resume if MULTIPLE_DATASETS=DISABLE, otherwise if MULTIPLE_DATASETS=ENABLE # (the default) this acts like a stop but allows a fast restart. proc ::histogram_memory::pause {} { variable histmem_simulation if [ catch { hmm pause ::histogram_memory::post_count set reply [SplitReply [hmm configure daq]] if {$histmem_simulation==false && $reply != "Paused"} { error "ERROR: Histogram server failed to pause" } } message ] { return -code error "([info level 0]) $message" } clientput "histmem paused" value } ## # @brief Choose method for controlling acquisition duration. # # @param method Set histmem mode or return current mode if blank proc ::histogram_memory::count_method {{method ""}} { variable ic_count_methods variable preset_mult variable monitor_controlled if {$method==""} { return [SplitReply [hmm_mode]] } if [ catch { set modes $ic_count_methods if {[lsearch $modes $method] == -1} { error "ERROR: Count mode, $method, must be one of $modes" } if {$method == "time"} { set preset_mult 100 } else { set preset_mult 1 } hmm configure FAT_COUNT_METHOD $method if {[string range $method 0 [string first "R_" $method]] == "MONITOR"} { hmm configure FAT_${method}_CONTROL ENABLE set bmchan [expr [string index $method end] - 1] bm setchannel $bmchan set monitor_controlled "true" } else { set monitor_controlled "false" } hmm stop hmm init hmm_mode $method } message ] { return -code error "([info level 0]) $message" } } ## # @brief Count until the preset count size has been reached. # # @param preset: The interpretation of the preset depends on the count method. # @see count_method proc ::histogram_memory::count_size {{preset ""}} { variable state variable preset_mult if [ catch { if {$preset == ""} { return $state(preset) } else { if {[string is double $preset] == 0 || $preset < 0} { error "ERROR: The preset must be a non-negative floating point number" } hmm configure FAT_COUNT_SIZE [expr {$preset_mult * $preset}] hmm init set state(preset) $preset hmm_preset $preset } } message ] { if {$::errorCode=="NONE"} {return $message} return -code error "([info level 0]) $message" } } ## # @brief Check histogram memory status # # @return Stopped, Paused, Started, or raises a Tcl error proc ::histogram_memory::hmm_status {} { if [ catch { set reply [SplitReply [hmm configure daq]] } message ] { return -code error "([info level 0]) $message" } return $reply } ## # @brief Set stop condition for histogram memory # # @param condition proc ::histogram_memory::stop_condition {condition} { variable state if [ catch { array set count_stop {immediate IMMEDIATE period AT_END_OF_PERIOD} if {$condition == ""} { return $state(stop_cond) } else { hmm configure FAT_COUNT_STOP $count_stop($condition) hmm init set state(stop_cond) $condition } } message ] { if {$::errorCode=="NONE"} {return $message} return -code error "([info level 0]) $message" } } namespace eval ::histogram_memory { #TODO Create GumTree commands to setup, start and stop the histmem ## # @brief Choose method for controlling acquisition duration. #command mode {text:time,monitor,unlimited,period,count,frame method} {} ## # @brief Count until the preset count size has been reached. # # @param preset: The interpretation of the preset depends on the count method. # @see count_method #command preset {float: pre} {} ## # @brief Set stop condition for histogram memory # # @param condition #command stop_condition {text:immediate,period condition} } ## # @brief Convenience command providing user interface to histogram control # # @param cmd is one of start, stop, pause, mode, preset, fsrce, status, loadconf # @param args is an optional list of arguments for the given command proc _histmem {cmd args} { #TODO Add "continue" set reply "" if [ catch { switch $cmd { "start" { eval "::histogram_memory::start $args" } "stop" { ::histogram_memory::stop } "pause" { ::histogram_memory::pause } "veto" { eval "::histogram_memory::veto $args" } "mode" { if {$args == ""} { set reply [::histogram_memory::count_method ] } else { eval "::histogram_memory::count_method $args" } } "preset" { if {$args == ""} { set reply [::histogram_memory::count_size ] } else { eval "::histogram_memory::count_size $args" } } "clockscale" { if {$args == ""} { set reply [::histogram_memory::get_clock_scale ] } else { eval "::histogram_memory::set_clock_scale $args" } } "freq" { if {$args == ""} { set reply [::histogram_memory::get_frame_freq ] } else { eval "::histogram_memory::set_frame_freq $args" } } "fsrce" { if {$args == ""} { set reply [::histogram_memory::get_frame_source ] } else { eval "::histogram_memory::set_frame_source $args" } } "status" { set reply [::histogram_memory::hmm_status] } "loadconf" { # Loads configuration tables (OAT, FAT, ...) to histogram server if {$args == ""} { ::histogram_memory::upload_config Filler_defaults } else { eval "::histogram_memory::upload_config $args" } } default { error "ERROR: Available commands are, start stop pause mode preset freq fsrce status loadconf" } } } message ] { return -code error "([info level 0]) $message" } return $reply }