diff --git a/tcl/drivers/secop_4.tcl b/tcl/drivers/secop_4.tcl index 554231c..130a830 100644 --- a/tcl/drivers/secop_4.tcl +++ b/tcl/drivers/secop_4.tcl @@ -3,7 +3,10 @@ namespace eval secop {} { } -proc stdConfig::secop {{shownUnits ALL} {restart no}} { +proc stdConfig::secop {{shownUnits ALL} {restart no} {sepUnits ""}} { + # shown units: restrict units shown + # restart: whether to restart on reconnect + # sepUnits: append sepUnits to unis for different graphic window variable node variable name @@ -23,6 +26,7 @@ proc stdConfig::secop {{shownUnits ALL} {restart no}} { prop secopPath /$name prop active 0 prop shownUnits $shownUnits + prop sepUnits $sepUnits set node $node/tasks prop start secop::start @@ -48,7 +52,7 @@ proc secop::errorscript_ {} { return secop::update_ } sct connection_lost 1 - [sct controller] poll [sct secopPath] 1 + [sct controller] poll [sct secopPath] 5 error [sct result] } @@ -76,6 +80,7 @@ proc secop::writemsg {} { proc secop::readmsg_ {} { # ending with _: invisible on debug if {[sct connection_lost]} { + [sct controller] poll [sct] 0.001 sct connection_lost 0 return [secop::start] } @@ -90,14 +95,15 @@ proc secop::test {} { proc secop::check {} { if {[silent "" sct secopar] eq ""} return - set validator [silent {} sct validator] - eval $validator - lassign [split [hinfo [sct]] ","] type - set msg "change [sct secopar] [sct target]" - hsetprop [sct] secoprequested [sct target] - if {[string match "f:*" [sct secopar]]} { - clientput "REQ: $msg" + set value [sct target] + set validator [silent "" sct validator] + if {$validator ne ""} { + lappend validator $value + set value [eval $validator] } + lassign [split [hinfo [sct]] ","] type + set msg "change [sct secopar] $value" + hsetprop [sct] secoprequested [sct target] [sct controller] que [sct secopPath] write [list secop::queuedwrite $msg] } @@ -133,44 +139,80 @@ proc secop::get {} { return secop::update_ } -proc secop::check_range {min max {absolute_resolution 0} {relative_resolution 0}} { - set prec [expr max($absolute_resolution, $relative_resolution * abs([sct target]))] - if {[sct target] < $min} { - if {[sct target] >= $min - $prec} { - sct target $min - return +proc secop::check_double {datainfo value} { + set min [silent -inf dict get $datainfo min] + set max [silent inf dict get $datainfo max] + set absolute_resolution [silent 0 dict get $datainfo absolute_resolution] + set relative_resolution [silent 1.2e-7 dict get $datainfo relative_resolution] + set prec [expr max($absolute_resolution, $relative_resolution * abs($value))] + if {$value < $min} { + if {$value >= $min - $prec} { + return $min } - } elseif {[sct target] > $max} { - if {[sct target] <= $max + $prec} { - sct target $max - return + } elseif {$value > $max} { + if {$value <= $max + $prec} { + return $max } } else { - return + return $value } - error "[sct] value must be within \[$min, $max\]" + error "[sct]: value must be within \[$min, $max\]" } -proc secop::check_string {min max} { - set len [string length [sct target]] +proc secop::check_int {datainfo value} { + return [check_double $datainfo $value] +} + +proc secop::check_string {datainfo value} { + set len [string length $value] + set min [silent -inf dict get $datainfo minlen] + set max [silent inf dict get $datainfo maxlen] if {$len < $min || $len > $max} { - error "[sct] string length must be within \[$min, $max\]" + error "[sct]: string length must be within \[$min, $max\]" } - sct target [format {"%s"} [sct target]] + return [format {"%s"} $value] } -proc secop::check_bool {} { - switch -- [string tolower [sct target]] { - off - false - no - 0 - on - true - yes - 1 { - return + +proc secop::check_bool {datainfo value} { + switch -- [string tolower $value] { + off - false - no - 0 { + return 0 + } + on - true - yes - 1 { + return 1 } } - error "illegal value for boolean: [sct target]" + error "[sct]: illegal value for boolean: $value" } -proc secop::check_tuple args { - sct target [format {[%s]} [join [sct target] ,]] - clientput [sct target] +proc secop::check_tuple {datainfo value} { + set items [list] + foreach v $value dt [dict get $datainfo members] { + set type [dict get $dt type] + lappend items [check_$type $dt $v] + } + return [format {[%s]} [join $items ,]] +} + +proc secop::check_array {datainfo value} { + set items [list] + set dt [dict get $datainfo members] + set type [dict get $dt type] + foreach v $value { + lappend items [check_$type $dt $v] + } + return [format {[%s]} [join $items ,]] +} + +proc secop::check_struct {datainfo value} { + set items [list] + foreach {k dt} [dict get $datainfo members] { + set type [dict get $dt type] + set v [check_$type $dt [dict get $value $k]] + lappend items [format {"%s": %s} $k $v] + } + return [format {{%s}} [join $items ", "]] } proc secop::make_par {secopar desc {kind ""}} { @@ -201,9 +243,8 @@ proc secop::make_par {secopar desc {kind ""}} { # can not use SICS drivable for string set kind "" } - bool {set type text} + bool - tuple - array - struct {set type text} none {set type none} - tuple {set type text} default { clientput "unknown type for $secopar (use text): $secoptype ($datadesc)" set type text @@ -224,8 +265,17 @@ proc secop::make_par {secopar desc {kind ""}} { set fmtunit [format { [%s]} $unit] } if {$par eq "" || $par eq "target"} { + set label [join [split $secopar :] .] + set prevlabel [silent "" result graph_label [string tolower $label]] + if {$prevlabel ne ""} { + set label $prevlabel + } if {[sct shownUnits] eq "ALL" || [lsearch [sct shownUnits] $unit] >= 0} { - GraphAdd $path $unit [join [split $secopar :] .] + set sepUnits [silent "" sct sepUnits] + if {$sepUnits ne ""} { + set unit "${unit}_$sepUnits" + } + GraphAdd $path $unit $label } } } @@ -251,7 +301,7 @@ proc secop::make_par {secopar desc {kind ""}} { } hsetprop $path enum [join $enumprop ,] if {[silent "" hgetpropval $path type] eq "drivable"} { - hsetprop $path visible false + hsetprop $path visible readonly } if {$wid > 8} { hsetprop $path width $wid @@ -260,29 +310,18 @@ proc secop::make_par {secopar desc {kind ""}} { } bool { hsetprop $path enum 1 - hsetprop $path validator secop::check_bool + hsetprop $path validator [list secop::check_bool $datadesc] } double { - set min [silent -inf dict get $datadesc min] - set max [silent inf dict get $datadesc max] - set absolute_resolution [silent 0 dict get $datadesc absolute_resolution] - set relative_resolution [silent 1.2e-7 dict get $datadesc relative_resolution] - hsetprop $path validator [concat secop::check_range $min $max $absolute_resolution $relative_resolution] + hsetprop $path validator [list secop::check_double $datadesc] } int { - set min [silent -inf dict get $datadesc min] - set max [silent inf dict get $datadesc max] - hsetprop $path validator [concat secop::check_range $min $max] + hsetprop $path validator [list secop::check_int $datadesc] } - string { - set min [silent -inf dict get $datadesc min] - set max [silent inf dict get $datadesc max] - hsetprop $path width 16 - hsetprop $path validator [concat secop::check_string $min $max] - } - tuple { # TODO: make it work for more complex than number tuples - set args [dict get $datadesc members] - hsetprop $path validator [linsert $args 0 secop::check_tuple] + string - tuple - struct - array { + set type [dict get $datadesc type] + hsetprop $path width 36 + hsetprop $path validator [list secop::check_$type $datadesc] } } return $path @@ -349,12 +388,14 @@ proc secop::make_par0 {type path secopar desc {kind std}} { # logsetup $path 1 logsetup $path 5 if {[info exists props(value)]} { - clientput "VALUE in descr $path" if {[catch {hupdate /$path $props(value)} msg]} { clientput $msg } unset props(value) } + if {![catch {set fmtstr [dict get $props(datainfo) fmtstr]}]} { + hsetprop $path fmtstr $fmtstr + } foreach {prop item} [array get props] { hsetprop $path s_$prop $item } @@ -571,6 +612,7 @@ proc secop::update_ {} { if {$messagetype eq "changed"} { if {[string match *:target $par]} { hsetprop /$obj writestatus done + hsetprop /$obj changetime 0 } hsetprop $path changed 0 catch {hdelprop $path secoprequested} @@ -609,6 +651,7 @@ proc secop::update_ {} { set shown 0 } set writestatus [silent done hgetpropval $objpath writestatus] + set changetime [silent 0 hgetpropval $objpath changetime] if {$value < 100 || $value >= 400} { # error # updateerror $objpath $text_value catch { @@ -638,7 +681,12 @@ proc secop::update_ {} { } GraphItem shown $objpath $shown if {[silent "" hgetpropval $objpath/target logger_name] ne ""} { - GraphItem shown $objpath/target $shown + if {[string match *Drivable* [silent "" hgetpropval $objpath sm_interface_classes]] + && [silent "enum" hgetpropval $objpath/target secoptype] ne "enum"} { + GraphItem shown $objpath/target $shown + } else { + GraphItem shown $objpath/target 0 + } } set text_path [regsub {status_code$} $path status_text] if {[catch {updateval $text_path $text_value}]} { @@ -715,6 +763,7 @@ proc secop::update_ {} { hsetprop $path geterror "${etype}: $etext" } error_* { + clientlog $val lassign $val etype etext set requesttype [string range $messagetype 6 end] if {$requesttype eq "change" && $path ne ""} { @@ -768,6 +817,7 @@ proc secop::checklimits {} { [sct target] != [silent "x" hgetpropval [sct]/target target]} { hset [sct]/target [sct target] sct writestatus checked + sct changetime [DoubleTime] sct status run } } @@ -804,6 +854,7 @@ proc secop::halt {} { sct stop_issued [DoubleTime] } else { sct writestatus done + sct changetime 0 sct status idle } return idle @@ -816,6 +867,7 @@ proc secop::finish_halt {} { return idle } sct writestatus done + sct changetime 0 sct status idle return unpoll }