Reduce log noise by setting iout = eInternal for macros. servlog.c Fixed timestamp in logfiles to get hours. hmm_configuration_common_1.tcl Added ML's mods to wombat config: ie BAT and FAT TABLE attributes and elements for multi-period acquisition and histo-streaming. Fixed "failed lsearch" bug. It's more robust to test for a non-successful lsearch instead of a failed lsearch. nxscripts_common_1.tcl SICS-297 Fixed Saving data series in a scratch file overwrites earlier entries. instdict_specification.tcl Added "scobj" kind and "sct_indexed_motor" sics object type for script context controllers and and objects. hipadaba_configuration_common.tcl Added sct_indexed_motor sics obj type to ::hdb::sobjadd and scobj kind to ::hdb::add_node sct_positmotor_common.tcl Update the index SICS variable when updating the current index value to make sure that the position is saved in the data file. You must now provide the hdb node_name when creating the sct posit motor. mk_sct_positmotor now sets the "param" and "long_name" attributes on the posit motor object util/utility.tcl Added ::utility::set_sct_indexed_motor_attributes to set SICS object attributes required for generating hdb info for an SCT_POSIT_MOTOR nxscript.c Merge the ansto mod to putslab (rev1.7) which adds support for saving unbuffered data from the histmem. sicshipadaba.c This incorporates the patch made to CommandSetCallback in rev1.10 so it can just be copied as is (ie no merge required). WARNING: There are changes to ListHdbNode to handle record separators which may affect us. Disabled sending hdb command start and stop messages because they break gumtree sicshdbfactory.c Disabled sending hdb command start and stop messages because they break gumtree hipadaba_configuration_common.tcl R2.4DEV The sct_posit_motor case of ::hdb::sobjadd is only needed to call add_node with kind=scobj. nxscripts_common_1.tcl R2.4DEV Added ::nexus::scobj::sdsinfo _gen_nxdict now skips nodes with data_type == "none" new util/script_context_util.tcl R2.4DEV Adds ::scobj::hinitprops command to initialise the hdb properties for script context object nodes. sct_positmotor_common.tcl R2.4DEV Use ::scobj::hinitprops utility command to initialise hdb properties on script context object parameter nodes. dynstring.c DynStringReplace should memcopy '\0', otherwise it can get the wrong length for iTextLen. Added DynStringReplaceWithLen to allow initialising a dynstring with char arrays which contain null chars and other non-ascii chars. Useful for read and write buffers in script context. ascon.c AsconRead return NULL for noResponse and AsconFailed otherwise the "result" node gets set with a spurious empty value. scriptcontext.c SctActionHandler only set the "result" node if there really is a reply. sicsobj.c Update from M.K. site_ansto.c Added galil and ordela hvps protocol handlers for scriptcontext. motor_dmc2280.c Allow home parameter to be outside of limits (for KOWARI) hardsup/makefile Added ordela HVPS protocol handler hardsup/sct_orhvpsprot.c New ordela HVPS protocol handler. Retries on NAKs and re-orders pot channels (ie toggles lower two bits). hardsup/sct_velselprot.c Start velocity selector protocol handler. hardsup/sct_galilprot.c Completed galil protocol handler. hipadaba_configuration_common.tcl Add new style SICS objects to hdb tree. instdict_specification.tcl Added scobj to kind list and sct_motor to sics object list. (and some housekeeping) hmm_configuration_common_1.tcl Added ratemaps to simulation. Fixe BAT_TABLE and added PERIOD_INDICES as per Mark Lesha's mods for multi-period acquisition. ratemaps now return float. sct_postimotor_common.tcl Now setting properties on the posit motor object so that it can be automatically added to the hdb tree. hrpd/config/motors/motor_configuration.tcl Fixed simulated msd motor so that it's handle properly in the hdb layer. sans/config/hmm/detector_ordela.tcl Updated the ordela calibration script to use the new sct_orhvpsprop.c script context controller. quokka_configuration.tcl Deleted lines which set the hdb properties for script context posit motors. This is now handled automatically as for other SICS objects. utility.tcl setpos now replaces the motor setpos subcommand. Added functions to set script context object attributes and sct_posit motor attributes. Created hparPath and hsibPath convenience commands for new-style SICS objects. script_context_util.tcl NEW! Adds hinitprops function to initialise the hdb properties for a script context object r2758 | ffr | 2008-12-12 17:53:53 +1100 (Fri, 12 Dec 2008) | 113 lines
1264 lines
43 KiB
Tcl
1264 lines
43 KiB
Tcl
##
|
|
# @file nxscripts_common_1.tcl
|
|
# @brief Defines functions to create and save a nexus datafile based on the hdb tree metadata
|
|
#
|
|
|
|
MakeNXScript
|
|
sicsdatafactory new nxscript_data
|
|
#mkVar name type access long_name nxsave klass control data
|
|
::utility::mkVar estart Text user start_time true entry false true
|
|
::utility::mkVar eend Text user end_time true entry false true
|
|
::utility::mkVar timestamp int user time_stamp true entry false true
|
|
::utility::mkVar data_run_number int user run_number true instrument false true
|
|
::utility::mkVar nexus_datatype text user DataType true data false true
|
|
::utility::mkVar file_set_list Text user file_set true experiment true true
|
|
sicslist setatt data_run_number mutable true
|
|
sicslist setatt timestamp mutable true
|
|
sicslist setatt timestamp units seconds
|
|
sicslist setatt nexus_datatype mutable false
|
|
|
|
namespace eval nexus {
|
|
variable data_gp_path "/data"
|
|
nexus_datatype "UNKNOWN"
|
|
set exports [list newfile closefile save data newfile_collection save_collection]
|
|
eval namespace export $exports
|
|
if 0 {datafilename}
|
|
|
|
variable filetypes
|
|
set filetypes [list BEAM_MONITOR HISTOPERIOD_XYT TOTAL_HISTOGRAM_XY TOTAL_HISTOGRAM_XT TOTAL_HISTOGRAM_YT TOTAL_HISTOGRAM_X TOTAL_HISTOGRAM_Y TOTAL_HISTOGRAM_T ]
|
|
|
|
##
|
|
# @brief This is the nexus dictionary generated by the gen_nxdict function
|
|
variable nxdictionary
|
|
##
|
|
# @brief Records the current Nexus file state.
|
|
variable state
|
|
|
|
##
|
|
# @brief Specifies the save policy with an optional list of data link sources.
|
|
#
|
|
# NOTE: The ::histogram_memory::horizontal_axis and ::histogram_memory::vertical_axis are aliases which
|
|
# must be set by the instrument specific histogram memory configuration.
|
|
#
|
|
# TODO Put the filetype_spec in a separate file.
|
|
variable bmon_filetype_spec
|
|
array set bmon_filetype_spec {
|
|
BEAM_MONITOR {
|
|
link {axis 1 data_run_number}
|
|
link {data_set monitor_counts}
|
|
save_policy {include @all exclude {hmm hmm_xy hmm_xt hmm_yt hmm_x hmm_y hmm_t}}
|
|
}
|
|
}
|
|
variable histmem_filetype_spec
|
|
array set histmem_filetype_spec {
|
|
HISTOGRAM_XYT {
|
|
link {axis 1 data_run_number}
|
|
link {axis 2 ::histogram_memory::time_channel}
|
|
link {axis 3 ::histogram_memory::vertical_axis}
|
|
link {axis 4 ::histogram_memory::horizontal_axis}
|
|
link {data_set hmm}
|
|
save_policy {include @all exclude {hmm_xy hmm_xt hmm_yt hmm_x hmm_y hmm_t}}
|
|
}
|
|
HISTOGRAM_XY {
|
|
link {axis 1 data_run_number}
|
|
link {axis 2 ::histogram_memory::vertical_axis}
|
|
link {axis 3 ::histogram_memory::horizontal_axis}
|
|
link {data_set hmm_xy}
|
|
save_policy {include @all exclude {hmm hmm_xt hmm_yt hmm_x hmm_y hmm_t}}
|
|
}
|
|
HISTOGRAM_XT {
|
|
link {axis 1 data_run_number}
|
|
link {axis 2 ::histogram_memory::time_channel}
|
|
link {axis 3 ::histogram_memory::horizontal_axis}
|
|
link {data_set hmm_xt}
|
|
save_policy {include @all exclude {hmm_xy hmm hmm_yt hmm_x hmm_y hmm_t}}
|
|
}
|
|
HISTOGRAM_YT {
|
|
link {axis 1 data_run_number}
|
|
link {axis 2 ::histogram_memory::time_channel}
|
|
link {axis 3 ::histogram_memory::vertical_axis}
|
|
link {data_set hmm_yt}
|
|
save_policy {include @all exclude {hmm_xy hmm_xt hmm hmm_x hmm_y hmm_t}}
|
|
}
|
|
HISTOGRAM_X {
|
|
link {axis 1 data_run_number}
|
|
link {axis 2 ::histogram_memory::horizontal_axis}
|
|
link {data_set hmm_x}
|
|
save_policy {include @all exclude {hmm_xy hmm_xt hmm_yt hmm hmm_y hmm_t}}
|
|
}
|
|
HISTOGRAM_Y {
|
|
link {axis 1 data_run_number}
|
|
link {axis 2 ::histogram_memory::vertical_axis}
|
|
link {data_set hmm_y}
|
|
save_policy {include @all exclude {hmm_xy hmm_xt hmm_yt hmm_x hmm hmm_t}}
|
|
}
|
|
HISTOGRAM_T {
|
|
link {axis 1 data_run_number}
|
|
link {axis 2 ::histogram_memory::time_channel}
|
|
link {data_set hmm_t}
|
|
save_policy {include @all exclude {hmm_xy hmm_xt hmm_yt hmm_x hmm_y hmm}}
|
|
}
|
|
}
|
|
|
|
variable filetype_spec [concat [array get bmon_filetype_spec] [array get histmem_filetype_spec] ]
|
|
}
|
|
|
|
##
|
|
# @brief Strips the output of a SICS command leaving only the value\n
|
|
# TODO Replace $cmd_output with [$cmd_output] so we can just pass the command name
|
|
#
|
|
# @param cmd_output The output from a command substitution
|
|
# @return The unadorned value returned by the SICS command which produced cmd_output
|
|
proc getVal {cmd_output} {
|
|
return [string trim [lindex [split $cmd_output =] 1 ] ]
|
|
}
|
|
|
|
proc ::nexus::datapath {} {
|
|
return [SplitReply [sicsdatapath]]
|
|
}
|
|
##
|
|
# @brief Generate a filename from sicsdatanumber and sicsdatapath
|
|
#
|
|
# @param postfix This is the filename suffix, must be one of: nx.hdf, hdf, h5, nx5, xml
|
|
proc newFileName {idNum postfix} {
|
|
|
|
array set inst_mnem {quokka QKK wombat WBT echidna ECH kowari KWR koala KOL taipan TPN platypus PLP pelican PLN}
|
|
# set prefix [SplitReply [sicsdataprefix]]
|
|
set date_time_arr [split [sicstime] " "]
|
|
set isodate [lindex $date_time_arr 0]
|
|
set isotime [string map {: -} [lindex $date_time_arr 1]]
|
|
return [format "%s/%s%07d.%s" [::nexus::datapath] $inst_mnem([instname]) $idNum $postfix]
|
|
}
|
|
|
|
proc ::nexus::process_filetype_policy {filetype filetype_spec} {
|
|
|
|
upvar $filetype_spec ft_spec
|
|
array set ft_spec_arr $ft_spec
|
|
if {[info exists ft_spec_arr($filetype)] == 0} {
|
|
error "$filetype is invalid, should be one of [array names ft_spec_arr]"
|
|
}
|
|
set ft_policy $ft_spec_arr($filetype)
|
|
::nexus::data clear
|
|
foreach {pol_type policy} $ft_policy {
|
|
switch $pol_type {
|
|
"link" {
|
|
::nexus::data $policy
|
|
}
|
|
"save_policy" {
|
|
foreach {save_action action_list} $policy {
|
|
switch $save_action {
|
|
"include" {
|
|
if {$action_list == "@all"} {
|
|
::hdb::set_save / true
|
|
} else {
|
|
foreach item $action_list {
|
|
if {[getatt $item type] == ""} {
|
|
error "ERROR: Unknown $item specified for inclusion in the data file"
|
|
}
|
|
::hdb::set_save [getatt $item hdb_path] true
|
|
}
|
|
}
|
|
}
|
|
"exclude" {
|
|
if {$action_list == "@all"} {
|
|
::hdb::set_save / false
|
|
} else {
|
|
foreach item $action_list {
|
|
if {[getatt $item type] == ""} {
|
|
error "ERROR: Unknown $item specified for exclusion from the data file"
|
|
}
|
|
::hdb::set_save [getatt $item hdb_path] false
|
|
}
|
|
}
|
|
}
|
|
default {
|
|
error "ERROR: Unknown save action $save_action specified in the save policy"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
default {
|
|
error "$pol_type is invalid, should be one of 'link' 'save_policy'"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
##
|
|
# @brief Initialise state variables
|
|
proc ::nexus::init {} {
|
|
variable state
|
|
variable nexusdic
|
|
variable currFilename
|
|
variable start_seconds_array
|
|
|
|
array set state {
|
|
file,open "false"
|
|
file,namestyle "data"
|
|
file,format "hdf"
|
|
file,fileset "false"
|
|
file,incr_datnum "false"
|
|
file,labels @singlefile
|
|
}
|
|
|
|
set nexusdic "nexus.dic"
|
|
array set currFilename ""
|
|
array set start_seconds_array ""
|
|
}
|
|
|
|
##
|
|
# @brief Create a nexus file
|
|
# This first generates a nexus dictionary file from the hdb tree and then creates a new
|
|
# nexus file based on that dictionary.
|
|
proc ::nexus::createfile {FileName} {
|
|
variable nexusdic
|
|
variable state
|
|
variable data_gp_path
|
|
|
|
if [ catch {
|
|
if {$state(file,open) == "true"} {
|
|
error "Can't create a new file because the current file is still open"
|
|
}
|
|
switch $state(file,format) {
|
|
"hdf" {set create_type create5}
|
|
"xml" {set create_type createxml}
|
|
default {
|
|
error "ERROR: Invalid file format $state(file,format)"
|
|
}
|
|
}
|
|
|
|
set nxdict_path [::nexus::gen_nxdict $nexusdic]
|
|
hsetprop $data_gp_path currentfiletype [::utility::hgetplainprop $data_gp_path datatype]
|
|
if {$state(file,incr_datnum) == true} {
|
|
sicsdatanumber incr
|
|
}
|
|
if [catch {nxscript $create_type $FileName $nxdict_path} message] {
|
|
killfile
|
|
error $message
|
|
}
|
|
set state(file,open) false
|
|
} message ] {
|
|
if {$::errorCode=="NONE"} {return $message}
|
|
return -code error $message
|
|
}
|
|
}
|
|
|
|
##
|
|
# @brief Checks if the given file type is defined.
|
|
#
|
|
# @return 1 on success, 0 on failure
|
|
proc ::nexus::isValidFileType {type} {
|
|
variable filetypes
|
|
if {[lsearch $filetypes $type] == -1} {
|
|
return 0
|
|
} else {
|
|
return 1
|
|
}
|
|
}
|
|
##
|
|
# @brief Setup file state info for writing a new file.
|
|
#
|
|
# @type data file type as defined in config/nexus/datafiletype.tcl or clear
|
|
# @param namestyle scratch or data, default=data\n
|
|
# If namestyle=data, the save command will create numbered files using the ANSTO
|
|
# file naming convention.\n
|
|
# If namestyle=scratch, the save command will create scratch files.
|
|
#
|
|
# postconditions:
|
|
# state(file,open) true
|
|
# /data/currentfiletype == UNKNOWN
|
|
proc ::nexus::newfile {type {namestyle data}} {
|
|
::nexus::newfile_collection -filetype $type -savetype $namestyle
|
|
}
|
|
|
|
##
|
|
# @brief Let's make a collection of files (ie a file-set) or just one.
|
|
#
|
|
# @param -labels L or {L1 L2 ..}, optional. A list of labels which identify a file-set
|
|
# If you don't specify a list of labels then only one file is created
|
|
proc ::nexus::newfile_collection {args} {
|
|
variable filetype_spec
|
|
variable state
|
|
variable data_gp_path
|
|
variable currFilename
|
|
|
|
set valid_options [list "-labels" "-filetype" "-savetype"]
|
|
set required_options [list "-filetype" "-savetype"]
|
|
if [ catch {
|
|
::utility::check_valid_options $args $valid_options
|
|
::utility::check_required_options $args $required_options
|
|
array set param $args
|
|
set file_suffix [SplitReply [SicsDataPostFix]]
|
|
switch $file_suffix {
|
|
hdf - nx.hdf - h5 - nx5 {set state(file,format) hdf}
|
|
xml {set state(file,format) xml}
|
|
default { error "ERROR: Invalid file suffix $file_suffix" }
|
|
}
|
|
set state(file,namestyle) $param(-savetype)
|
|
file_set_list "UNKNOWN"
|
|
if {$param(-savetype) == "scratch"} {
|
|
set state(file,isNewScratchFile) true
|
|
set state(file,incr_datnum) false
|
|
} else {
|
|
set state(file,isNewScratchFile) false
|
|
set state(file,incr_datnum) true
|
|
}
|
|
set idNum [expr 1 + [SplitReply [sicsdatanumber]]]
|
|
if [info exists param(-labels)] {
|
|
set state(file,fileset) "true"
|
|
set state(file,labels) $param(-labels)
|
|
if {$param(-savetype) == "scratch"} {
|
|
foreach fid $state(file,labels) {
|
|
set currFilename($fid) [format "%s/scratch_%s.%s" [::nexus::datapath] $fid $file_suffix]
|
|
lappend files $currFilename($fid)
|
|
}
|
|
} else {
|
|
foreach fid $state(file,labels) {
|
|
set currFilename($fid) [newFileName $idNum $file_suffix]
|
|
incr idNum
|
|
lappend files $currFilename($fid)
|
|
}
|
|
}
|
|
file_set_list [join $files ,]
|
|
} else {
|
|
set state(file,fileset) "false"
|
|
set state(file,labels) @singlefile
|
|
if {$param(-savetype) == "scratch"} {
|
|
set currFilename(@singlefile) [format "%s/scratch.%s" [::nexus::datapath] $file_suffix]
|
|
} else {
|
|
set currFilename(@singlefile) [newFileName $idNum $file_suffix]
|
|
}
|
|
}
|
|
hsetprop $data_gp_path currentfiletype UNKNOWN
|
|
if {$param(-filetype) == "clear"} {
|
|
::nexus::data clear
|
|
::hdb::set_save / false
|
|
hsetprop $data_gp_path currentfiletype UNKNOWN
|
|
hsetprop $data_gp_path datatype UNKNOWN
|
|
nexus_datatype "UNKNOWN"
|
|
} else {
|
|
::nexus::process_filetype_policy $param(-filetype) filetype_spec
|
|
nexus_datatype $param(-filetype)
|
|
}
|
|
} message ] {
|
|
if {$::errorCode=="NONE"} {return $message}
|
|
return -code error $message
|
|
} else {
|
|
return OK
|
|
}
|
|
}
|
|
|
|
##
|
|
# @brief Save data to the currently open file and then close it.
|
|
#
|
|
# @param point This is the array index for mutable data elements
|
|
#
|
|
# This function provides the top level call to the recursive ::nexus::savetree
|
|
# function, it should only be called by the ::nexus::save command.
|
|
#
|
|
# @see ::nexus::savetree
|
|
# @see ::nexus::save
|
|
proc ::nexus::save_data {point} {
|
|
set valid_caller "::nexus::save_collection"
|
|
|
|
debug_msg "save point $point in [dataFileName]"
|
|
if [ catch {
|
|
if {[info level]<2} {
|
|
error "ERROR: The [lindex [info level 0] 0] command is for internal use only"
|
|
}
|
|
set caller [namespace origin [lindex [info level -1] 0]]
|
|
if {$caller != $valid_caller} {
|
|
error "ERROR: [lindex [info level 0] 0] can only be called via the $valid_caller command, not by $caller"
|
|
}
|
|
foreach child [hlist /] {
|
|
if {[::utility::hgetplainprop /$child data] == "true"} {
|
|
::nexus::savetree $child $point
|
|
}
|
|
}
|
|
} message ] {
|
|
if {$::errorCode=="NONE"} {return $message}
|
|
return -code error $message
|
|
}
|
|
}
|
|
|
|
##
|
|
# @brief save data collected by last data acquisition command.
|
|
#
|
|
# @param point experimental point number, this is the array index for mutable
|
|
# datasets in the nexus file. Optional, default = 0
|
|
#
|
|
# A new file will be created if the new file state has been set to true, or
|
|
# if the current data type doesn't match the current file type.
|
|
proc ::nexus::save {{point 0}} {
|
|
if [ catch {
|
|
::nexus::save_collection -index $point
|
|
} message ] {
|
|
if {$::errorCode=="NONE"} {return $message}
|
|
return -code error $message
|
|
}
|
|
}
|
|
|
|
##
|
|
# @brief Save data in a file from a file-set
|
|
proc ::nexus::save_collection {args} {
|
|
variable state
|
|
variable data_gp_path
|
|
variable start_seconds
|
|
variable start_seconds_array
|
|
variable currFilename
|
|
|
|
set valid_options [list "-index" "-label"]
|
|
set required_options [list "-index"]
|
|
if [ catch {
|
|
::utility::check_valid_options $args $valid_options
|
|
::utility::check_required_options $args $required_options
|
|
array set param $args
|
|
set point $param(-index)
|
|
if {[string is integer $point] == 0} {
|
|
error_msg "save index must be an integer"
|
|
} elseif {$point < 0} {
|
|
error_msg "save index cannot be negative"
|
|
}
|
|
|
|
# ::data::gumtree_save -set run_number $point
|
|
data_run_number $point
|
|
|
|
set currFileType [::utility::hgetplainprop $data_gp_path currentfiletype]
|
|
set currDataType [::utility::hgetplainprop $data_gp_path datatype]
|
|
set dataTypeChanged [expr {$currFileType != $currDataType}]
|
|
if {$currDataType == "UNKNOWN"} {
|
|
error_msg "You must set the file type, eg 'newfile BEAM_MONITOR' or 'newfile BEAM_MONITOR scratch' "
|
|
}
|
|
|
|
if [info exists param(-label)] {
|
|
if {[lsearch -exact $state(file,labels) $param(-label)] == -1} {
|
|
error "ERROR: The label must be one of $state(file,labels)"
|
|
}
|
|
set data_label $param(-label)
|
|
} else {
|
|
if {$state(file,fileset) == "true"} {
|
|
error "ERROR: You must set -label when saving to a file-set"
|
|
}
|
|
set data_label @singlefile
|
|
}
|
|
if {! [file exists $currFilename($data_label)]} {
|
|
set isNewFile true
|
|
} else {
|
|
set isNewFile false
|
|
}
|
|
if {$isNewFile || $state(file,isNewScratchFile)} {
|
|
::nexus::createfile $currFilename($data_label)
|
|
dataFileName $currFilename($data_label)
|
|
estart [lindex [sicstime] 1]
|
|
eend [lindex [sicstime] 1]
|
|
array unset start_seconds_array
|
|
set start_seconds [clock seconds]
|
|
# set start_seconds_array($data_label) $start_seconds
|
|
timestamp 0
|
|
::nexus::nxreopenfile $currFilename($data_label)
|
|
::nexus::save_data $point
|
|
::nexus::makelinks
|
|
::nexus::set_plotdata_info
|
|
::nexus::nxclosefile $currFilename($data_label)
|
|
set state(file,isNewScratchFile) false
|
|
} else {
|
|
eend [lindex [sicstime] 1]
|
|
# timestamp [expr {[clock seconds] - $start_seconds_array($data_label)}]
|
|
timestamp [expr {[clock seconds] - $start_seconds}]
|
|
dataFileName $currFilename($data_label)
|
|
::nexus::nxreopenfile $currFilename($data_label)
|
|
::nexus::save_data $point
|
|
::nexus::nxclosefile $currFilename($data_label)
|
|
}
|
|
} message ] {
|
|
::nexus::nxclosefile $currFilename($data_label)
|
|
if {$::errorCode=="NONE"} {return $message}
|
|
return -code error $message
|
|
}
|
|
return
|
|
}
|
|
|
|
##
|
|
# @brief Reopen the current file, close it with nxclosefile
|
|
# this should only be called by the ::nexus::save command.
|
|
#
|
|
# @see nxclosefile
|
|
# @see ::nexus::save
|
|
proc ::nexus::nxreopenfile {filename} {
|
|
global cfPath
|
|
variable state
|
|
variable nexusdic
|
|
set valid_caller "::nexus::save_collection"
|
|
|
|
if [ catch {
|
|
if {[info level]<2} {
|
|
error "ERROR: The [lindex [info level 0] 0] command is for internal use only"
|
|
}
|
|
set caller [namespace origin [lindex [info level -1] 0]]
|
|
if {$caller != $valid_caller} {
|
|
error "ERROR: [lindex [info level 0] 0] can only be called via the $valid_caller command, not by $caller"
|
|
}
|
|
if {$state(file,open) == "false"} {
|
|
nxscript reopen $filename $cfPath(nexus)/$nexusdic
|
|
set state(file,open) true
|
|
}
|
|
} message ] {
|
|
if {$::errorCode=="NONE"} {return $message}
|
|
return -code error $message
|
|
}
|
|
}
|
|
|
|
##
|
|
# @brief Close the current file. You can reopen it with nxreopenfile
|
|
# this should only be called by the ::nexus::save command.
|
|
#
|
|
# @see nxreopenfile
|
|
# @see ::nexus::save
|
|
proc ::nexus::nxclosefile {filename} {
|
|
variable state
|
|
set valid_caller "::nexus::save_collection"
|
|
|
|
if [ catch {
|
|
if {[info level]<2} {
|
|
error "ERROR: The [lindex [info level 0] 0] command is for internal use only"
|
|
}
|
|
set caller [namespace origin [lindex [info level -1] 0]]
|
|
if {$caller != $valid_caller} {
|
|
error "ERROR: [lindex [info level 0] 0] can only be called via the $valid_caller command, not by $caller"
|
|
}
|
|
if {$state(file,open) == "true"} {
|
|
nxscript close
|
|
set state(file,open) false
|
|
set flist [split $filename "/"]
|
|
set fname [lindex $flist [expr [llength $flist] - 1] ]
|
|
clientput "$fname updated" "event"
|
|
}
|
|
} message ] {
|
|
if {$::errorCode=="NONE"} {return $message}
|
|
return -code error $message
|
|
}
|
|
}
|
|
##
|
|
# @brief Records that a given data source should be linked to nexus data target.
|
|
#
|
|
# NOTE: If a link has already been recorded then it does nothing. This allows you to
|
|
# override default links set by a command. eg A "count" command may link axis_1 to
|
|
# the run number but a "scan" command, which uses the count command, can link axis_1 to
|
|
# a scan variable.
|
|
#
|
|
# Usage:
|
|
# data data_set datsource
|
|
# Records that /data/data_set should be linked to datsource and sets a data type identifier
|
|
# data axis 1|2|3|4 datsource
|
|
# Records that /data/axisn should be linked to datsource
|
|
# data clear
|
|
# Clears all link targets and sets the data type identifier to unknown
|
|
# data alias <name>, remove alias <name>
|
|
# data alias <name> <target>, set <name> as an alias for <target> unless it has already been defined.
|
|
proc ::nexus::data {args} {
|
|
variable state
|
|
variable data_gp_path
|
|
|
|
if {[llength $args] == 1} {
|
|
set arguments [lindex $args 0]
|
|
} else {
|
|
set arguments $args
|
|
}
|
|
|
|
set dpath $data_gp_path
|
|
set opt [lindex $arguments 0]
|
|
set arglist [lrange $arguments 1 end]
|
|
|
|
switch $opt {
|
|
"axis" {
|
|
debug_msg "'axis' case of switch"
|
|
set link_target [lindex $arguments 2]
|
|
if {[getatt $link_target privilege] == "internal"} {
|
|
error "[info level 0], Cannot link $link_target because it doesn't have an hdb node."
|
|
}
|
|
set axnum [lindex $arguments 1]
|
|
if {[string is integer $axnum] == 0} {
|
|
error "ERROR: [info level -1]->data, index for data axis should be an integer, not $axnum"
|
|
}
|
|
if {[getatt $link_target type] == ""} {
|
|
error "Unknown link target $link_target"
|
|
}
|
|
set hp $dpath/axis_$axnum
|
|
# if {[::utility::hgetplainprop $hp link] == "@none"} {
|
|
hsetprop $hp link [getatt [lindex $arguments 2] id]
|
|
hsetprop $hp long_name [getatt [lindex $arguments 2] long_name]
|
|
# }
|
|
}
|
|
"data_set" {
|
|
debug_msg "'data_set' case of switch"
|
|
set link_target [lindex $arguments 1]
|
|
if {[getatt $link_target type] == ""} {
|
|
error "Unknown link target $link_target"
|
|
}
|
|
hsetprop $dpath datatype [lindex [info level -1] 0]
|
|
set hp $dpath/data_set
|
|
# if {[::utility::hgetplainprop $hp link] == "@none"} {
|
|
hsetprop $hp link [getatt $link_target id]
|
|
hsetprop $hp long_name [getatt $link_target long_name]
|
|
# }
|
|
}
|
|
"clear" {
|
|
debug_msg "'clear' case of switch"
|
|
foreach child [hlist $dpath] {
|
|
hsetprop $dpath/$child link @none
|
|
hsetprop $dpath/$child long_name @none
|
|
}
|
|
}
|
|
"alias" {
|
|
debug_msg "'alias' case of switch"
|
|
set alias_name [lindex $arglist 0]
|
|
set alias_target [lindex $arglist 1]
|
|
switch $alias_target {
|
|
"" {
|
|
if {[info exists state(data,alias,$alias_name)]} {
|
|
definealias $alias_name
|
|
set state(data,alias,$alias_name) @none
|
|
}
|
|
}
|
|
default {
|
|
if {[info exists state(data,alias,$alias_name)]} {
|
|
if { $state(data,alias,$alias_name) == "@none" } {
|
|
definealias $alias_name $alias_target
|
|
}
|
|
} else {
|
|
definealias $alias_name $alias_target
|
|
}
|
|
return
|
|
}
|
|
}
|
|
}
|
|
default {error "ERROR: [info level -1]->data, Unsupported option $opt"}
|
|
}
|
|
}
|
|
|
|
##
|
|
# @brief Make dataset links
|
|
#
|
|
proc ::nexus::makelinks {{hpath /}} {
|
|
if [ catch {
|
|
foreach child [hlist $hpath] {
|
|
if {$hpath == "/"} {
|
|
set newpath /$child
|
|
} else {
|
|
set newpath $hpath/$child
|
|
}
|
|
# clientput $newpath
|
|
array set p_arr [::utility::hlistplainprop $newpath]
|
|
if {$p_arr(data) == "true" && $p_arr(nxsave) == "true"} {
|
|
if {[info exists p_arr(type)] && $p_arr(type) == "nxvgroup"} {
|
|
if {$p_arr(link) != "@none"} {
|
|
# clientput "Link $p_arr(nxalias) to $p_arr(link)"
|
|
nxscript makelink $p_arr(nxalias) $p_arr(link)
|
|
}
|
|
}
|
|
::nexus::makelinks $newpath
|
|
}
|
|
}
|
|
} message ] {
|
|
if {$::errorCode=="NONE"} {return $message}
|
|
return -code error $message
|
|
}
|
|
}
|
|
##
|
|
# @brief Sets the "signal" and "axes" attributes on the plottable data
|
|
# Also sets the "axis" attribute for each of the axes.
|
|
proc ::nexus::set_plotdata_info {} {
|
|
variable data_gp_path
|
|
|
|
array unset axes
|
|
set hpath $data_gp_path
|
|
foreach child [hlist $hpath] {
|
|
array set p_arr [::utility::hlistplainprop $hpath/$child]
|
|
if {$p_arr(data) == true && $p_arr(nxsave) == true} {
|
|
if {[info exists p_arr(nxalias)]} {
|
|
if {[info exists p_arr(type)] && $p_arr(type) == "nxvgroup"} {
|
|
if {$p_arr(link) != "@none"} {
|
|
switch -glob $child {
|
|
"axis_*" {
|
|
set n [lindex [split $child _] 1]
|
|
set axes($n) [::utility::hgetplainprop $hpath/$child long_name]
|
|
nxscript putattribute $p_arr(link) axis $n
|
|
}
|
|
"data_set" {
|
|
nxscript putattribute $p_arr(link) signal 1
|
|
set data_set_alias $p_arr(link)
|
|
}
|
|
default {error "ERROR: [info level -1]->set_plotdata_info, Unsupported data path $hpath/$child"}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if {[info exists axes]} {
|
|
foreach n [lsort [array names axes]] {
|
|
lappend axes_list $axes($n)
|
|
}
|
|
nxscript putattribute $data_set_alias axes [join $axes_list :]
|
|
}
|
|
}
|
|
|
|
##
|
|
# @brief Traverse the hdb subtree from the given path and save the data in the currently open file
|
|
#
|
|
# @param hpath path of subtree to save, must not be "/"
|
|
# @param pt Current array index for mutable data (optional default=0)
|
|
proc ::nexus::savetree {hpath {pt 0}} {
|
|
set ::errorInfo ""
|
|
if [ catch {
|
|
foreach child [hlist /$hpath] {
|
|
array unset p_arr
|
|
array set p_arr [::utility::hlistplainprop /$hpath/$child]
|
|
if {[info exists p_arr(type)] && $p_arr(type) == "nxvgroup"} {
|
|
continue
|
|
}
|
|
set data_type [lindex [split [hinfo /$hpath/$child] , ] 0]
|
|
if {$p_arr(data) == true && $p_arr(nxsave) == true } {
|
|
if {[info exists p_arr(savecmd)] && [info exists p_arr(nxalias)] } {
|
|
if {[info exists p_arr(mutable)] && $p_arr(mutable) == "true" } {
|
|
$p_arr(savecmd) $p_arr(sicsdev) $p_arr(nxalias) $data_type point $pt
|
|
} else {
|
|
$p_arr(savecmd) $p_arr(sicsdev) $p_arr(nxalias) $data_type
|
|
}
|
|
} elseif {[info exists p_arr(nxalias)]} {
|
|
if {[info exists p_arr(mutable)] && $p_arr(mutable) == "true" } {
|
|
nxscript puthdb /$hpath/$child point $pt
|
|
} else {
|
|
nxscript puthdb /$hpath/$child
|
|
}
|
|
}
|
|
::nexus::savetree $hpath/$child $pt
|
|
}
|
|
}
|
|
} message ] {
|
|
set message "$message, hpath=$hpath/$child"
|
|
if {$::errorCode=="NONE"} {return $message}
|
|
return -code error $message
|
|
}
|
|
}
|
|
|
|
##
|
|
# @brief Recursive portion of gen_nxdict function
|
|
#
|
|
# @param hpath hdb subtree path to generate dictionary fragment from, must not be "/"
|
|
# @param dictPath parent path for nexus dictionary fragment.
|
|
# @param name name for child dictionary path
|
|
# @param nxc Nexus class name
|
|
#
|
|
# If the klass name doesn't begin with NX then construct the SDS name by replacing '/' with '_' in the
|
|
# hdb path
|
|
#
|
|
# @see gen_nxdict
|
|
proc ::nexus::_gen_nxdict {hpath dictPath name nxc} {
|
|
variable nxdictionary
|
|
if [ catch {
|
|
if {[::utility::hgetplainprop /$hpath data] == "false"} {
|
|
debug_msg "$hpath doesn't have a data property"
|
|
return
|
|
}
|
|
foreach child [hlist /$hpath] {
|
|
if {[::utility::hgetplainprop /$hpath/$child data] == true} {
|
|
set nxclass [::utility::hgetplainprop /$hpath/$child klass]
|
|
if {$nxc == "NXentry"} {
|
|
::nexus::_gen_nxdict $hpath/$child $dictPath $child $nxclass
|
|
} elseif {[string range $nxc 0 1] == "NX"} {
|
|
::nexus::_gen_nxdict $hpath/$child $dictPath/$name,$nxc $child $nxclass
|
|
} else {
|
|
::nexus::_gen_nxdict $hpath/$child $dictPath ${name}_$child $nxclass
|
|
}
|
|
}
|
|
}
|
|
array set p_arr [::utility::hlistplainprop /$hpath]
|
|
set data_type [lindex [split [hinfo /$hpath] , ] 0]
|
|
if {$data_type == "none"} {
|
|
return;
|
|
}
|
|
if {$p_arr(data) == "true" && $p_arr(nxsave) == "true" && [info exists p_arr(nxalias)]} {
|
|
set alias $p_arr(nxalias)
|
|
if {[info exists p_arr(sdsinfo)]} {
|
|
if {[info exists p_arr(mutable)] && $p_arr(mutable) == "true"} {
|
|
set nxdictionary($alias) "$dictPath/SDS $name [$p_arr(sdsinfo) $p_arr(sicsdev) $data_type mutable true]"
|
|
} else {
|
|
set nxdictionary($alias) "$dictPath/SDS $name [$p_arr(sdsinfo) $p_arr(sicsdev) $data_type mutable false]"
|
|
}
|
|
} elseif {[info exists p_arr(type)] && $p_arr(type) == "nxvgroup"} {
|
|
set nxdictionary($alias) "$dictPath/NXVGROUP"
|
|
}
|
|
}
|
|
} message ] {
|
|
if {$::errorCode=="NONE"} {return $message}
|
|
return -code error $message
|
|
}
|
|
}
|
|
|
|
##
|
|
# @brief Generate a nexus dictionary file from the hdb tree
|
|
#
|
|
# An entry in the nexus dictionary is generated for each node in the
|
|
# hdb tree which has the following properties and values, data=true and nxsave=true
|
|
#
|
|
# @param nexusdic Name of the nexus dictionary that will be created.
|
|
# @return Full path to the nexus dictionary.
|
|
proc ::nexus::gen_nxdict {nexusdic} {
|
|
global cfPath
|
|
variable nxdictionary
|
|
if [ catch {
|
|
set nxdict_path $cfPath(nexus)/$nexusdic
|
|
array unset nxdictionary
|
|
foreach hp [hlist /] {
|
|
if {[::utility::hgetplainprop /$hp data] == true} {
|
|
set nxclass [::utility::hgetplainprop /$hp klass]
|
|
::nexus::_gen_nxdict $hp /entry1,NXentry $hp $nxclass
|
|
}
|
|
}
|
|
set fh [open $nxdict_path w]
|
|
puts $fh "##NXDICT-1.0"
|
|
puts $fh padim0=0
|
|
puts $fh padim1=0
|
|
puts $fh padim2=0
|
|
foreach {n v} [array get nxdictionary] {
|
|
puts $fh "$n = $v"
|
|
}
|
|
close $fh
|
|
} message ] {
|
|
if {$::errorCode=="NONE"} {return $message}
|
|
return -code error $message
|
|
}
|
|
return $nxdict_path
|
|
}
|
|
|
|
##
|
|
# @brief Set SICS object attributes which are required for creating nexus data files.
|
|
proc ::nexus::set_sobj_attributes {} {
|
|
if [ catch {
|
|
# SICS commands
|
|
sicslist setatt nxscript privilege internal
|
|
# SICS data objects
|
|
sicslist setatt nxscript_data privilege internal
|
|
|
|
foreach sobj [lrange [sicslist type motor] 1 end] {
|
|
sicslist setatt $sobj savecmd ::nexus::motor::save
|
|
sicslist setatt $sobj sdsinfo ::nexus::motor::sdsinfo
|
|
}
|
|
foreach sobj [sicslist type configurablevirtualmotor] {
|
|
sicslist setatt $sobj savecmd ::nexus::motor::save
|
|
sicslist setatt $sobj sdsinfo ::nexus::motor::sdsinfo
|
|
}
|
|
foreach sobj [sicslist type histmem] {
|
|
sicslist setatt $sobj savecmd ::nexus::histmem::save
|
|
sicslist setatt $sobj sdsinfo ::nexus::histmem::sdsinfo
|
|
}
|
|
foreach sobj [sicslist type sicsvariable] {
|
|
sicslist setatt $sobj savecmd ::nexus::sicsvariable::save
|
|
sicslist setatt $sobj sdsinfo ::nexus::sicsvariable::sdsinfo
|
|
}
|
|
foreach sobj [sicslist type singlecounter] {
|
|
sicslist setatt $sobj savecmd ::nexus::singlecounter::save
|
|
sicslist setatt $sobj sdsinfo ::nexus::singlecounter::sdsinfo
|
|
}
|
|
foreach sobj [sicslist type environment_controller] {
|
|
sicslist setatt $sobj savecmd ::nexus::environment_controller::save
|
|
sicslist setatt $sobj sdsinfo ::nexus::environment_controller::sdsinfo
|
|
}
|
|
foreach sobj [sicslist type chopperadapter] {
|
|
sicslist setatt $sobj savecmd ::nexus::chopperadapter::save
|
|
sicslist setatt $sobj sdsinfo ::nexus::chopperadapter::sdsinfo
|
|
}
|
|
foreach sobj [sicslist kind script] {
|
|
sicslist setatt $sobj savecmd ::nexus::script::save
|
|
sicslist setatt $sobj sdsinfo ::nexus::script::sdsinfo
|
|
}
|
|
foreach sobj [sicslist kind getset] {
|
|
sicslist setatt $sobj savecmd ::nexus::macro::getset_save
|
|
sicslist setatt $sobj sdsinfo ::nexus::macro::getset_sdsinfo
|
|
}
|
|
} message ] {
|
|
if {$::errorCode=="NONE"} {return $message}
|
|
return -code error $message
|
|
}
|
|
}
|
|
|
|
namespace eval ::nexus::histmem {}
|
|
namespace eval ::nexus::motor {}
|
|
namespace eval ::nexus::environment_controller {}
|
|
namespace eval ::nexus::sicsvariable {}
|
|
namespace eval ::nexus::singlecounter {}
|
|
namespace eval ::nexus::script {}
|
|
|
|
##
|
|
# @brief Convert the given hdb type to Nexus data type
|
|
#
|
|
# @param dtype hdb data type
|
|
# @return Nexus data type
|
|
proc ::nexus::hdb2nx_type {dtype} {
|
|
switch $dtype {
|
|
int {return NX_INT32}
|
|
intar {return NX_INT32}
|
|
intvarar {return NX_INT32}
|
|
float {return NX_FLOAT32}
|
|
floatar {return NX_FLOAT32}
|
|
floatvarar {return NX_FLOAT32}
|
|
text {return NX_CHAR}
|
|
default {error "ERROR: [info level -1]->hdb2nx_type, Unknown type $dtype"}
|
|
}
|
|
}
|
|
|
|
##
|
|
# @brief Save command for histogram memory data.
|
|
#
|
|
# The savecmd attribute of any histogram memory objects should be set to this function
|
|
#
|
|
# @see set_sobj_attributes
|
|
proc ::nexus::histmem::save {hm nxalias data_type args} {
|
|
if [catch {
|
|
set rank [SplitReply [$hm configure rank]]
|
|
|
|
set datalen 1
|
|
set indStartList [lindex $args 1]
|
|
set indLenList [list 1]
|
|
for {set i 0} {$i < $rank} {incr i} {
|
|
lappend indStartList 0
|
|
set dim$i [SplitReply [$hm configure dim$i]]
|
|
lappend indLenList [set dim$i]
|
|
set datalen [expr $datalen * [set dim$i]]
|
|
nxscript updatedictvar padim$i [set dim$i]
|
|
}
|
|
set data_start 0
|
|
set bank 1
|
|
nxscript putslab $nxalias $indStartList $indLenList $hm $data_start $datalen $bank
|
|
}] {
|
|
return -code error $::errorInfo
|
|
}
|
|
}
|
|
|
|
# TODO Get rank from /data
|
|
proc ::nexus::histmem::sdsinfo {hm data_type args} {
|
|
array set param $args
|
|
set rank [SplitReply [$hm configure rank]]
|
|
|
|
for {set i 0} {$i < $rank} {incr i} {lappend dimstr "\$(padim$i)"}
|
|
set dimstr [join $dimstr ,]
|
|
if {$param(mutable) == true} {
|
|
return " -type NX_INT32 -LZW -rank [expr $rank+1] -dim {-1,$dimstr}"
|
|
} else {
|
|
return " -type NX_INT32 -LZW -rank $rank -dim {$dimstr}"
|
|
}
|
|
}
|
|
|
|
# The save commands are called with the sobj name and nxalias
|
|
# The sdsinfo commands provide the SDS description for an nxdic
|
|
|
|
proc ::nexus::motor::save {motor nxalias data_type args} {
|
|
if {[lindex $args 0] == "point"} {
|
|
set index [lindex $args 1]
|
|
nxscript_data clear
|
|
nxscript_data putfloat 0 [getVal [$motor] ]
|
|
nxscript putslab $nxalias [list $index] [list 1] nxscript_data
|
|
} else {
|
|
if {[getatt $motor type] == "motor"} {
|
|
nxscript putmot $nxalias $motor
|
|
} else {
|
|
nxscript putfloat $nxalias [SplitReply [$motor]]
|
|
}
|
|
}
|
|
}
|
|
proc ::nexus::motor::sdsinfo {motor data_type args} {
|
|
array set param $args
|
|
array set attribute [::utility::normalattlist $motor]
|
|
set dtype [::nexus::hdb2nx_type $data_type]
|
|
if {[info exists attribute(units)]} {
|
|
set units_att " -attr {units,$attribute(units)} "
|
|
} else {
|
|
set units_att " "
|
|
}
|
|
set name_att " -attr {long_name,$attribute(long_name)} "
|
|
if {$param(mutable) == true} {
|
|
return " -type $dtype -rank 1 -dim {-1} $units_att $name_att"
|
|
} else {
|
|
return " -type $dtype $units_att $name_att"
|
|
}
|
|
}
|
|
##
|
|
# @brief Save data from a 'getset macro'
|
|
#
|
|
# NOTE: Currently just saves floats
|
|
namespace eval ::nexus::macro {}
|
|
proc ::nexus::macro::getset_save {sobj nxalias data_type args} {
|
|
if [ catch {
|
|
if {[lindex $args 0] == "point"} {
|
|
set index [lindex $args 1]
|
|
nxscript_data clear
|
|
set val [getVal [$sobj] ]
|
|
switch $data_type {
|
|
int {nxscript_data putint 0 $val}
|
|
float {nxscript_data putfloat 0 $val}
|
|
text {error "ERROR: [info level 0] Saving an array of text values is not implemented"}
|
|
default {error "ERROR: [info level 0] unknown type $data_type when saving $sobj"}
|
|
}
|
|
nxscript putslab $nxalias [list $index] [list 1] nxscript_data
|
|
} else {
|
|
switch $data_type {
|
|
int {nxscript putint $nxalias [SplitReply [$sobj]]}
|
|
float {nxscript putfloat $nxalias [SplitReply [$sobj]]}
|
|
text {nxscript puttext $nxalias [SplitReply [$sobj]]}
|
|
default {error "ERROR: [info level 0] Unknown data type $data_type when saving $sobj"}
|
|
}
|
|
}
|
|
} message ] {
|
|
if {$::errorCode=="NONE"} {return $message}
|
|
return -code error "::nexus::macro::getset_save, $message"
|
|
}
|
|
}
|
|
|
|
##
|
|
# @brief Define the scientific data set path for the nexus dictionary.
|
|
proc ::nexus::macro::getset_sdsinfo {sobj data_type args} {
|
|
array set param $args
|
|
array set attribute [::utility::normalattlist $sobj]
|
|
set dtype [::nexus::hdb2nx_type $data_type]
|
|
if {[info exists attribute(units)]} {
|
|
set units_att " -attr {units,$attribute(units)} "
|
|
} else {
|
|
set units_att " "
|
|
}
|
|
set name_att " -attr {long_name,$attribute(long_name)} "
|
|
if {$param(mutable) == true} {
|
|
return " -type $dtype -rank 1 -dim {-1} $units_att $name_att"
|
|
} else {
|
|
return " -type $dtype $units_att $name_att"
|
|
}
|
|
}
|
|
####
|
|
proc ::nexus::environment_controller::save {evc nxalias data_type args} {
|
|
if {[lindex $args 0] == "point"} {
|
|
set index [lindex $args 1]
|
|
nxscript_data clear
|
|
nxscript_data putfloat 0 [getVal [$evc] ]
|
|
nxscript putslab $nxalias [list $index] [list 1] nxscript_data
|
|
} else {
|
|
nxscript putfloat $nxalias [SplitReply [$evc]]
|
|
}
|
|
}
|
|
proc ::nexus::environment_controller::sdsinfo {evc data_type args} {
|
|
array set param $args
|
|
array set attribute [::utility::normalattlist $evc]
|
|
set dtype [::nexus::hdb2nx_type $data_type]
|
|
if {[info exists attribute(units)]} {
|
|
set units_att " -attr {units,$attribute(units)} "
|
|
} else {
|
|
set units_att " "
|
|
}
|
|
set name_att " -attr {long_name,$attribute(long_name)} "
|
|
if {$param(mutable) == true} {
|
|
return " -type $dtype -rank 1 -dim {-1} $units_att $name_att"
|
|
} else {
|
|
return " -type $dtype $units_att $name_att"
|
|
}
|
|
}
|
|
|
|
namespace eval ::nexus {
|
|
}
|
|
|
|
proc ::nexus::sicsvariable::save {svar nxalias data_type args} {
|
|
if [ catch {
|
|
array set attribute [attlist $svar]
|
|
set val [SplitReply [$svar]]
|
|
if {[lindex $args 0] == "point"} {
|
|
set index [lindex $args 1]
|
|
nxscript_data clear
|
|
switch $data_type {
|
|
int {nxscript_data putint 0 $val}
|
|
float {nxscript_data putfloat 0 $val}
|
|
default {error "ERROR: [info level -1]->::nexus::sicsvariable::save, unknown type $data_type"}
|
|
}
|
|
nxscript putslab $nxalias [list $index] [list 1] nxscript_data
|
|
} else {
|
|
switch $data_type {
|
|
int {nxscript putint $nxalias $val}
|
|
float {nxscript putfloat $nxalias $val}
|
|
text {nxscript puttext $nxalias $val}
|
|
default {error "ERROR: [info level -1]->::nexus::sicsvariable::save, unknown type $data_type"}
|
|
}
|
|
}
|
|
if {[info exists attribute(units)]} {
|
|
nxscript putattribute $nxalias units $attribute(units)
|
|
}
|
|
} message ] {
|
|
if {$::errorCode=="NONE"} {return $message}
|
|
return -code error "::nexus::sicsvariable::save, $message"
|
|
}
|
|
}
|
|
|
|
# TODO Add optional units to sicsvariables
|
|
proc ::nexus::sicsvariable::sdsinfo {svar data_type args} {
|
|
array set param $args
|
|
set dtype [::nexus::hdb2nx_type $data_type]
|
|
if {$param(mutable) == true} {
|
|
return " -type $dtype -rank 1 -dim {-1}"
|
|
} else {
|
|
return " -type $dtype"
|
|
}
|
|
}
|
|
|
|
namespace eval ::nexus::scobj {}
|
|
proc ::nexus::scobj::sdsinfo {svar data_type args} {
|
|
array set param $args
|
|
set dtype [::nexus::hdb2nx_type $data_type]
|
|
if {$param(mutable) == true} {
|
|
return " -type $dtype -rank 1 -dim {-1}"
|
|
} else {
|
|
return " -type $dtype"
|
|
}
|
|
}
|
|
|
|
namespace eval ::nexus::chopperadapter { }
|
|
proc ::nexus::chopperadapter::save {sobj nxalias data_type args} {
|
|
array set attribute [attlist $sobj]
|
|
set val [SplitReply [$sobj]]
|
|
if {[lindex $args 0] == "point"} {
|
|
set index [lindex $args 1]
|
|
nxscript_data clear
|
|
switch $data_type {
|
|
int {nxscript_data putint 0 $val}
|
|
float {nxscript_data putfloat 0 $val}
|
|
default {error "ERROR: [info level -1]->::nexus::chopperadapter::save, unknown type $data_type"}
|
|
}
|
|
nxscript putslab $nxalias [list $index] [list 1] nxscript_data
|
|
} else {
|
|
switch $data_type {
|
|
int {nxscript putint $nxalias $val}
|
|
float {nxscript putfloat $nxalias $val}
|
|
text {nxscript puttext $nxalias $val}
|
|
default {error "ERROR: [info level -1]->::nexus::chopperadapter::save, unknown type $data_type"}
|
|
}
|
|
}
|
|
if {[info exists attribute(units)]} {
|
|
nxscript putattribute $nxalias units $attribute(units)
|
|
}
|
|
}
|
|
|
|
proc ::nexus::chopperadapter::sdsinfo {sobj data_type args} {
|
|
array set param $args
|
|
set dtype [::nexus::hdb2nx_type $data_type]
|
|
if {$param(mutable) == true} {
|
|
return " -type $dtype -rank 1 -dim {-1}"
|
|
} else {
|
|
return " -type $dtype"
|
|
}
|
|
}
|
|
proc ::nexus::singlecounter::save {counter nxalias data_type args} {
|
|
todo_msg "Save counter: $counter"
|
|
}
|
|
proc ::nexus::singlecounter::sdsinfo {counter data_type args} {
|
|
todo_msg "Get sdsinfo for counter: $counter"
|
|
}
|
|
|
|
##
|
|
# @brief Save command for hdb nodes associated with a tcl macro
|
|
#
|
|
# The macro must return a 1D associative array when called with -arrayname.
|
|
proc ::nexus::script::save {script nxalias data_type args} {
|
|
if [ catch {
|
|
array set attribute [attlist $script]
|
|
if {$attribute(klass) == "sensor"} {
|
|
if {[lindex $args 0] == "point"} {
|
|
set index [lindex $args 1]
|
|
nxscript_data clear
|
|
nxscript_data putfloat 0 [$script]
|
|
nxscript putslab $nxalias [list $index] [list 1] nxscript_data
|
|
} else {
|
|
nxscript putfloat $nxalias [$script]
|
|
}
|
|
} else {
|
|
set darray [$script -arrayname]
|
|
set size [array size $darray]
|
|
set size [SplitReply [$darray used]]
|
|
if {[lindex $args 0] == "point"} {
|
|
set index [lindex $args 1]
|
|
nxscript putslab $nxalias [list $index 0] [list 1 $size] $darray
|
|
} else {
|
|
nxscript putslab $nxalias [list 0] [list $size] $darray
|
|
}
|
|
if {[info exists attribute(units)]} {
|
|
nxscript putattribute $nxalias units $attribute(units)
|
|
}
|
|
}
|
|
} message ] {
|
|
if {$::errorCode=="NONE"} {return $message}
|
|
return -code error $message
|
|
}
|
|
}
|
|
|
|
proc ::nexus::script::sdsinfo {script data_type args} {
|
|
if [ catch {
|
|
array set param $args
|
|
set dtype [::nexus::hdb2nx_type $data_type]
|
|
if {[getatt $script klass] == "sensor"} {
|
|
if {$param(mutable) == true} {
|
|
return " -type $dtype -rank 1 -dim {-1}"
|
|
} else {
|
|
return " -type $dtype"
|
|
}
|
|
} else {
|
|
set darray [$script -arrayname]
|
|
set size [SplitReply [$darray used]]
|
|
if {$param(mutable) == true} {
|
|
return " -type $dtype -rank 2 -dim {-1,$size}"
|
|
} else {
|
|
return " -type $dtype -rank 1 -dim {$size}"
|
|
}
|
|
}
|
|
} message ] {
|
|
if {$::errorCode=="NONE"} {return $message}
|
|
return -code error $message
|
|
}
|
|
}
|
|
|
|
namespace import ::nexus::*
|
|
foreach expt $::nexus::exports {
|
|
publish $expt user
|
|
sicslist setatt $expt privilege internal
|
|
}
|
|
|
|
# TODO Return filename from nxcreatefile and call nxreopen nxclose etc
|
|
# TODO Make an nxscript namespace for all this.
|
|
|
|
# dictalias is a global hash which records the alias which the value of
|
|
# a sics object (eg motors) is written to. The has is indexed by the
|
|
# objects name. It is useful for making links to datasets.
|
|
# dim0 = vertical axis on detector
|
|
# dim1 = horizontal axis on detector
|
|
|
|
set tmpstr [string map {"$" ""} {$Name: not supported by cvs2svn $}]
|
|
set nx_content_release_tag [lindex $tmpstr [expr [llength $tmpstr] - 1]]
|
|
set tmpstr [string map {"$" ""} {$Revision: 1.46 $}]
|
|
set nx_content_revision_num [lindex $tmpstr [expr [llength $tmpstr] - 1]]
|
|
|
|
#namespace eval data {
|
|
# ##
|
|
# # @brief Nexus data save command for gumtree control interface
|
|
# #
|
|
# # @param run_number This is the run or scan point number, it serves as the array
|
|
# # index for nexus data sets which correspond to mutable data
|
|
# command gumtree_save {int: run_number} {
|
|
# ::nexus::save $run_number
|
|
# }
|
|
# sicslist setatt ::data::gumtree_save long_name save
|
|
# array set param [::data::gumtree_save -list param]
|
|
# ::utility::mkData $param(run_number) run_number instrument privilege READ_ONLY mutable true control false
|
|
# command gumtree_type {text:nx.hdf,xml type} {
|
|
# SicsDataPostFix $type
|
|
# }
|
|
# sicslist set ::data::gumtree_type long_name file_format
|
|
# ::data::gumtree_type -set type [SplitReply [SicsDataPostFix]]
|
|
#}
|
|
|
|
::nexus::init
|
|
publish ::nexus::data user
|