Files
sics/site_ansto/instrument/util/genmotconf_procs.tcl

246 lines
7.5 KiB
Tcl
Executable File

# @brief Parse motor attribute file and make list of motor attributes and controllers
# @param fname Name of two column csv file of motor attribute names and values
# @param fhr Report log file-handle.
# @param fhe Error log file-handle.
# Requires The global ::ENC_ATTLIST
# Creates the following globals,
# ::mn(matt) is an array of motor attributes where mn = motor name and matt = the attribute name
# ::mn_encatts(matt) is an array of encoder attributes where mn = motor name and matt = an attributed from ENC_ATTLIST
# ::controllers(cn) Counts number of axes used on each controller, cn = controller name.
# ::motor_attcnt(mn) The keys of this array provide a list of motor names and each value is a count of attributes found for each motor.
proc parse_file {fname fhr fhe} {
puts $fhr "\nPARSE '$fname'"
set lcount 0
set fh [open $fname "r"]
while {[gets $fh line] >= 0} {
incr lcount
foreach {name val} [split $line {,}] {}
if [regexp {(_?[a-zA-Z][a-zA-Z0-9]*[0-9]*)_([a-zA-Z0-9_]+)} $name rem mn matt] {
puts $fhr "Processing '$line'"
if {[lsearch $::ENC_ATTLIST $matt] != -1} {
puts $fhr "Add ::${mn}_encatts($matt) = $val"
set ::${mn}_encatts($matt) $val
} else {
puts $fhr "Add ::${mn}_attarr($matt) = $val"
set ::${mn}_attarr($matt) $val
}
incr ::motor_attcnt($mn)
if { $matt == "mc" } {
incr ::controllers($val)
}
} else {
incr ::ERRCNT
puts $fhe "Failed to match '$line'"
}
}
close $fh
puts -nonewline $fhr "CONTROLLER USAGE COUNT: "
foreach {cont} [lsort -dictionary [array names ::controllers]] {
set count $::controllers($cont)
puts -nonewline $fhr "$cont count=$count; "
}
puts $fhr ""
puts $fhr "PARSED $lcount lines in '$fname'; failed $::ERRCNT lines"
puts $fhe "$::ERRCNT ERRORS IN PARSE STAGE '$fname'. PROCESSED $lcount lines"
}
# @brief Generate motor configuration file header and make asyncqueues
# @param fhmc Motor configuration file handle.
# Requires the following globals,
# ::argv0, ::argv, ::file_list, and ::controllers
proc mk_cfg_header {fhmc} {
puts $fhmc "#### SICS motor driver configuration ####"
puts $fhmc "# Generated by: $::argv0 $::argv"
# puts $fhmc "# Date: [clock format [clock seconds] -format %Y-%m-%dT%H:%M:%S]"
puts $fhmc "# Generated from the following files,"
foreach f $::file_list {
incr fcntr
puts $fhmc "# file$fcntr: $f"
}
puts $fhmc ""
puts $fhmc "# Load motor driver configuration parameters"
puts $fhmc "set flist \[list\\"
foreach f $::file_list {
puts $fhmc " \{$f\}\\"
}
puts $fhmc " \]"
puts $fhmc {
foreach fattfile $flist {
if [catch {
set fattpath config/motors/$fattfile
set fh [open $fattpath RDONLY]
while {[gets $fh line] >= 0} {
eval "set [split $line {,}]"
}
close $fh
} msg] {
clientput ERROR: $msg
}
}
}
puts $fhmc {set sim_mode [SplitReply [motor_simulation]]}
# Setup addresses of Galil DMC2280 controllers.
puts $fhmc {
if {$sim_mode == true} {
set motor_driver_type asim
} else {
set motor_driver_type DMC2280
}
}
puts $fhmc "if {\$sim_mode == false} \{"
foreach cont [lsort -dictionary [array names ::controllers]] {
set index [string toupper $cont]
puts $fhmc " [subst -nocommands {MakeAsyncQueue $cont DMC2280 [dict get \$::MOTOR_HOSTPORT $index HOST] [dict get \$::MOTOR_HOSTPORT $index PORT]}]"
}
puts $fhmc \}
}
# @brief Generate motor driver configuration
# @param mot Motor name
# @param fh Motor configuration file handle
# @param absEnc boolean, generate absolute encoder configuration if true.
# @param posnum Number of discrete positions
# @param posit_list Name of global list of name value pairs, "posit_n pos". Can be empty.
proc mk_motconf {mot fh absEnc posnum posit_list} {
set mc [set ::${mot}_attarr(mc)]
set axis [set ::${mot}_attarr(axis)]
set units ${mot}_units
set hardlowerlim ${mot}_rev_lim
set hardupperlim ${mot}_fwd_lim
set softlowerlim ${mot}_rev_lim
set softupperlim ${mot}_fwd_lim
set maxSpeed ${mot}_maxspeed
set maxAccel ${mot}_maxaccel
set maxDecel ${mot}_maxdecel
set stepsPerX ${mot}_steps_per_x
set cntsPerX ${mot}_cnts_per_x
set absEncHome ${mot}_absenchome
set home ${mot}_home
set part ${mot}_part
set long_name $mot
puts $fh "# $mot configuration"
if [info exists ::${mot}_attarr(description)] {
puts $fh "# [string trim [set ::${mot}_attarr(description)]]"
}
if [info exists ::${mot}_attarr(axis_number)] {
puts $fh "# Axis number [set ::${mot}_attarr(axis_number)]"
}
puts $fh "Motor $mot \$motor_driver_type \[params\\"
puts $fh " asyncqueue $mc\\"
puts $fh " axis $axis\\"
puts $fh " units \$$units\\"
puts $fh " hardlowerlim \$$hardlowerlim\\"
puts $fh " hardupperlim \$$hardupperlim\\"
puts $fh " maxSpeed \$$maxSpeed\\"
puts $fh " maxAccel \$$maxAccel\\"
puts $fh " maxDecel \$$maxDecel\\"
puts $fh " stepsPerX \$$stepsPerX\\"
puts $fh " posit_count $posnum\\"
foreach positline $::posit_list {
puts $fh " $positline\\"
}
if {$absEnc} {
puts $fh " absEnc 1\\"
puts $fh " absEncHome \$$absEncHome\\"
puts $fh " cntsPerX \$$cntsPerX\]"
} else {
puts $fh " absEnc 0\]"
}
puts $fh "$mot softlowerlim \$$softlowerlim"
puts $fh "$mot softupperlim \$$softupperlim"
puts $fh "$mot home \$$home"
puts $fh "$mot part \$$part"
puts $fh "$mot long_name $long_name"
if [info exists ::${mot}_attarr(dflt_speed_steps)] {
puts $fh "$mot speed \$${mot}_speed"
}
if [info exists ::${mot}_attarr(dflt_accel_steps)] {
puts $fh "$mot accel \$${mot}_accel"
}
if [info exists ::${mot}_attarr(dflt_decel_steps)] {
puts $fh "$mot decel \$${mot}_decel"
}
puts $fh ""
}
################################################################################
# UTILITY FUNCTIONS
################################################################################
# @brief Difference between sets A and B, ie A\B
# Invalid sets are allowed. Doesn't check for repetition.
# @return list of elements in A but not in B
proc setdiff {A B} {
set diff {}
foreach e $A {
if { [lsearch $B $e] == -1 } {
lappend diff $e
}
}
return $diff
}
# @brief Tests if A is subset of B
# The sets must be sorted
# Doesn't check if sets are valid, eg repetition is allowed.
proc subset {A B} {
set Alen [llength $A]
set Blen [llength $B]
if { $Alen > $Blen } {
return false
}
set Aend [expr {$Alen - 1}]
set Bend [expr {$Blen - 1}]
set asi 0
set aei 0
set bsi 0
set bei 0
while { $asi <= [expr {$Aend - $aei}] } {
# puts "A = [lrange $A $asi end-$aei]"
set firstmatch false
set lastmatch false
while { $bsi <= [expr {$Bend - $bei}] } {
# puts " B = [lrange $B $bsi end-$bei]"
if { $firstmatch == false } {
set aval [lindex $A $asi]
set bval [lindex $B $bsi]
if { $aval == $bval} {
set firstmatch true
# puts " firstmatch = $firstmatch"
} elseif {$aval < $bval} {
return false
}
incr bsi
}
if { $lastmatch == false } {
set aval [lindex $A end-$aei]
set bval [lindex $B end-$bei]
if { $aval == $bval } {
set lastmatch true
# puts " lastmatch = $lastmatch"
} elseif {$aval > $bval} {
return false
}
incr bei
}
if { ($firstmatch == true) && ($lastmatch == true) } {
break
}
}
if { ($firstmatch == false) && ($lastmatch == false) } {
return false
}
incr asi
incr aei
}
return true
}