1 # tksm - tk system monitor
2 # By #ohm, la resistance
7 array set refresh_fragments [list]
8 set refresh_pin [sid::pin::new]
13 proc any_stop_pins_p {} {
15 return [llength $stop_pins]
18 array set triggerpoint_action [list]
19 array set triggerpoint_info [list]
21 # $components(name) = component-handle
22 array set components [list]
24 proc cfgroot_component {} {
26 return $components(main)
29 proc component_names {} {
31 return [array names components]
35 # ---------------------------------------------------------------------------
36 # State save/restore support data
38 # $state_snapshots($slot,$name) = state-snapshot
39 array set state_snapshots [list]
40 proc save_state {slot} {
41 global components state_snapshots
42 foreach name [component_names] {
43 set comp $components($name)
44 set state [sid::component::attribute_value $comp state-snapshot]
45 set state_snapshots($slot,$name) $state
49 proc restore_state {slot} {
50 global components state_snapshots
52 foreach name [component_names] {
53 set comp $components($name)
54 if {! [info exists state_snapshots($slot,$name)]} then { continue }
55 set state $state_snapshots($slot,$name)
56 if {$state == ""} then { continue }
57 set status [sid::component::set_attribute_value $comp state-snapshot $state]
58 if {$status != "ok"} then { lappend failed "${name}:${status}" }
60 if {[llength $failed] > 0} then {
61 tk_dialog .oops3 Error "Cannot restore state to some components: $failed" error 0 "oh well"
65 proc zap_state {slot} {
66 global state_snapshots
67 foreach name [component_names] {
68 if {[info exists state_snapshots($slot,$name)]} then {
69 unset state_snapshots($slot,$name)
77 proc push_new_state {} {
78 global num_state_slots
80 save_state $num_state_slots
81 .control.statenum configure -text $num_state_slots
83 proc zap_top_state {} {
84 global num_state_slots
85 if {$num_state_slots == 0} then { return }
86 zap_state $num_state_slots
87 incr num_state_slots -1
88 .control.statenum configure -text $num_state_slots
90 proc peek_top_state {} {
91 global num_state_slots
92 if {$num_state_slots == 0} then { return }
93 restore_state $num_state_slots
99 set comp [cfgroot_component]
100 set stoppin [sid::component::find_pin $comp "stop!"]
101 if {$stoppin != ""} then {sid::pin::driven_h4 $stoppin 1}
105 # ---------------------------------------------------------------------------
107 # Configuration graphing interface
109 # Create a "dot" format description of the current configuration graph
112 set dot "digraph sid \{\n"
114 append dot "// nodes\n"
115 append dot "node \[shape=\"box\"\];\n"
117 # collect pin/bus/component-handle -> dot-node-name mapping table
118 foreach name [component_names] {
119 set comp $components($name)
122 append dot "subgraph \"cluster $cn\" \{ label=\"$name\";\n"
125 if {[sid::component::pin_names $comp] != ""} then {
126 append dot " subgraph \"cluster $name-pins\" \{ label=\"pins\"; \n"
127 foreach pin_nm [sid::component::pin_names $comp] {
128 set ph [sid::component::find_pin $comp $pin_nm]
129 set pn "$cn pin $pin_nm"
130 append dot " \"$pn\" \[label=\"$pin_nm\"\];\n"
131 if {$ph != ""} then { ;# input pin
135 append dot " \} // pins\n"
138 if {[sid::component::bus_names $comp] != ""} then {
139 append dot " subgraph \"cluster $name-buses\" \{ label=\"buses\"; \n"
140 foreach bus_nm [sid::component::bus_names $comp] {
141 set bh [sid::component::find_bus $comp $bus_nm]
142 set bn "$cn bus $bus_nm"
143 append dot " \"$bn\" \[label=\"$bus_nm\"\];\n"
146 append dot " \} // buses\n"
149 if {[sid::component::accessor_names $comp] != ""} then {
150 append dot " subgraph \"cluster $name-accessors\" \{ label=\"accessors\"; \n"
151 foreach acc_nm [sid::component::accessor_names $comp] {
152 set an "$cn accessor $acc_nm"
153 append dot " \"$an\" \[label=\"$acc_nm\"\];\n"
155 append dot " \} // accessors\n"
158 if {[sid::component::relationship_names $comp] != ""} then {
159 append dot " subgraph \"cluster $name-relations\" \{ label=\"relations\"; \n"
160 foreach rel_nm [sid::component::relationship_names $comp] {
161 set rn "$cn relation $rel_nm"
162 append dot " \"$rn\" \[label=\"$rel_nm\"\];\n"
164 append dot " \} // relations\n"
166 append dot "\} // component\n"
169 append dot "// edges\n"
171 # generate pin/bus/relation edges
172 foreach name [component_names] {
173 set comp $components($name)
176 foreach pin_nm [sid::component::pin_names $comp] {
177 set pn "$cn pin $pin_nm"
178 foreach conn_pin [sid::component::connected_pins $comp $pin_nm] {
179 if {[info exists pins($conn_pin)]} then {
180 append dot "\"$pn\" -> \"$pins($conn_pin)\"; \n"
182 append dot "\"$pn\" -> \"anonymous-pin\"; \n"
187 foreach acc_nm [sid::component::accessor_names $comp] {
188 set an "$cn accessor $acc_nm"
189 set acc_bus [sid::component::connected_bus $comp $acc_nm]
190 if {$acc_bus != ""} {
191 if {[info exists buses($acc_bus)]} then {
192 append dot "\"$an\" -> \"$buses($acc_bus)\"; \n"
194 append dot "\"$an\" -> \"anonymous-bus\"; \n"
199 foreach rel_nm [sid::component::relationship_names $comp] {
200 set rn "$cn relation $rel_nm"
201 foreach rel_comp [sid::component::related_components $comp $rel_nm] {
202 if {[info exists comps($rel_comp)]} then {
203 append dot "\"$rn\" -> \"$comps($rel_comp)\"; \n"
205 append dot "\"$rn\" -> \"anonymous-component\"; \n"
211 append dot "\} // digraph\n"
216 proc show_polkadot {} {
218 set filename "/tmp/dot.[clock seconds]"
219 set file [open $filename w]
222 catch {exec dotty $filename &}
224 set now [clock seconds]
225 while {($now + 5) > [clock seconds]} { }
226 file delete $filename
231 # ---------------------------------------------------------------------------
232 # Top-level window layout
234 wm title . "System Monitor"
236 #scrollbar .x -orient horizontal
237 #scrollbar .y -orient vertical
238 #pack .x -side bottom -fill x
239 #pack .y -side right -fill y
241 frame .control -borderwidth 2
242 checkbutton .control.autorefresh -variable refresh_ok -text "Auto refresh"
243 # button .control.graph -text "Graphviz" -command {show_polkadot}
244 # pack .control.autorefresh .control.graph -side left
245 pack .control.autorefresh -side left -padx 20
246 label .control.state -text "State"
247 label .control.statenum -text "0"
248 button .control.statepush -padx 4 -borderwidth 1 -text "save" -command {push_new_state}
249 button .control.statepop -padx 4 -borderwidth 1 -text "restore" -command {peek_top_state}
250 button .control.statezap -padx 4 -borderwidth 1 -text "discard" -command {zap_top_state}
251 pack .control.state .control.statenum .control.statepush .control.statepop .control.statezap -side left
252 pack .control -side top
253 bind .control <Destroy> {stop_tksm}
256 # Ask user to fill in a number of text fields.
260 # result: list of field values (or empty list if cancelled)
261 proc tk_ask {w title text bitmap args} {
263 global tkask_disposition
267 set tkask_vars($a) {}
270 # destroy/recreate window
272 toplevel $w -class Dialog
274 wm iconname $w Dialog
275 wm protocol $w WM_DELETE_WINDOW {set tkask_disposition -1}
276 wm transient $w [winfo toplevel [winfo parent $w]]
278 # create window skeleton
282 if {$tcl_platform(platform) == "unix"} {
283 $w.bot configure -relief raised -bd 1
284 $w.mid configure -relief raised -bd 1
285 $w.top configure -relief raised -bd 1
287 pack $w.bot -side bottom -fill both
288 pack $w.top $w.mid -side top -fill both -expand 1
292 option add *Dialog.msg.wrapLength 3i widgetDefault
293 label $w.msg -justify left -text $text
294 if {$tcl_platform(platform) == "macintosh"} {
295 $w.msg configure -font system
297 $w.msg configure -font {Times 18}
299 pack $w.msg -in $w.top -side right -expand 1 -fill both -padx 3m -pady 3m
301 if {($tcl_platform(platform) == "macintosh") && ($bitmap == "error")} {
304 label $w.bitmap -bitmap $bitmap
305 pack $w.bitmap -in $w.top -side left -padx 3m -pady 3m
312 label $w.mid$i.l -text $a
313 entry $w.mid$i.r -width 20 -textvariable tkask_vars($a)
314 pack $w.mid$i.l -side left
315 pack $w.mid$i.r -side right
316 grid $w.mid$i -in $w.mid -column 0 -row $i -sticky ew -pady 10
322 foreach but {ok cancel} {
323 button $w.button$i -text $but -command "set tkask_disposition $i"
325 $w.button$i configure -default active
327 $w.button$i configure -default normal
329 grid $w.button$i -in $w.bot -column $i -row 0 -sticky ew -padx 10
330 grid columnconfigure $w.bot $i
331 # We boost the size of some Mac buttons for l&f
332 if {$tcl_platform(platform) == "macintosh"} {
333 set tmp [string tolower $but]
334 if {($tmp == "ok") || ($tmp == "cancel")} {
335 grid columnconfigure $w.bot $i -minsize [expr 59 + 20]
342 # handle <Return>,<Destroy>
344 $w.button0 configure -state active -relief sunken
347 set tkask_disposition 0
349 bind $w <Destroy> {set tkask_disposition -1}
351 # withdraw & resize dialog
354 set x [expr {[winfo screenwidth $w]/2 - [winfo reqwidth $w]/2 \
355 - [winfo vrootx [winfo parent $w]]}]
356 set y [expr {[winfo screenheight $w]/2 - [winfo reqheight $w]/2 \
357 - [winfo vrooty [winfo parent $w]]}]
364 set oldGrab [grab current $w]
365 if {$oldGrab != ""} {
366 set grabStatus [grab status $oldGrab]
372 tkwait variable tkask_disposition
373 catch {focus $oldFocus}
378 if {$oldGrab != ""} {
379 if {$grabStatus == "global"} {
380 grab -global $oldGrab
387 if {$tkask_disposition != 0} then {
392 lappend r $tkask_vars($a)
400 # Take a component name and/or attribute name, and mangle it into something
401 # unique and safe for use as a tk widget path.
402 set unique_wn_suffix 0
403 proc widgetname {base args} {
404 global unique_wn_suffix
407 regsub -all {[^a-z0-9]} $a {_} mangled
408 set name "${name}_${mangled}"
410 incr unique_wn_suffix
411 set name "${base}.${name}_${unique_wn_suffix}"
412 # puts "$args -> $name"
417 proc have_none_p {comp category} {
418 set registers [sid::component::attribute_names_in_category $comp $category]
419 if {[llength $registers] == 0} then { return 1 } else { return 0 }
422 proc not_watchable_p {comp attribute} {
423 foreach w [sid::component::attribute_names_in_category $comp watchable] {
424 if {$w == $attribute} then { return 0 }
430 proc refresh_all {} {
431 global refresh_fragments
432 set search [array startsearch refresh_fragments]
433 while {[array anymore refresh_fragments $search]} {
434 set name [array nextelement refresh_fragments $search]
435 set script $refresh_fragments($name)
438 array donesearch refresh_fragments $search
439 # update may fail if top level window was closed
445 proc open_component_window { category name type comp } {
447 set wn [widgetname "" $name $category]
450 wm title $wn "$name $category list"
451 #wm resizable $wn 0 0
453 # scrollbar $wn.y -orient vertical
454 # pack $wn.y -side right -fill y
456 set registers [sid::component::attribute_names_in_category $comp $category]
457 if {[llength $registers] == 0} then {
458 tk_dialog .oops2 Oops "Nothing to show for $name $category list." warning 0 "oh well"
463 # set refreshcmds "puts \"refreshing $name $category\""
465 frame $wn.regs -relief raised -borderwidth 2
467 foreach r $registers {
468 set subwidgetname [widgetname $wn $r]
470 frame $subwidgetname -relief sunken -borderwidth 2
471 label $subwidgetname.label -text $r
472 entry $subwidgetname.value -width 20
475 set prev_value \[$subwidgetname.value get\]
476 set value \[sid::component::attribute_value $comp [list $r]\]
477 $subwidgetname.value delete 0 end
478 $subwidgetname.value insert 0 \$value
479 if {\$value == \$prev_value} then { set c black } else { set c red }
480 $subwidgetname.label configure -foreground \$c"
481 bind $subwidgetname.value <Escape> "
482 set value \[sid::component::attribute_value $comp [list $r]\]
483 $subwidgetname.value delete 0 end
484 $subwidgetname.value insert 0 \$value
485 $subwidgetname.label configure -foreground blue"
486 bind $subwidgetname.value <Return> "
487 set value \[$subwidgetname.value get\]
488 set prev_value \[sid::component::attribute_value $comp [list $r] \]
489 set status \[sid::component::set_attribute_value $comp [list $r] \$value\]
490 if {\$status != \"ok\"} then {
491 tk_dialog .oops Error \"Error setting $name $category [list $r] to \$value: \$status\" error 0 ok
492 set new_value \[sid::component::attribute_value $comp [list $r]\]
493 if {\$new_value != \$prev_value} then {
494 set status2 \[sid::component::set_attribute_value $comp [list $r] \$prev_value\]
495 if {\$status2 != \"ok\"} then {
496 tk_dialog .oops Error \"Error restoring $name $category [list $r] back to \$prev_value: \$status\" error 0 damn
500 $subwidgetname.label configure -foreground green"
501 bind $subwidgetname.value <Enter> "global refresh_ok ; set refresh_ok 0"
502 bind $subwidgetname.value <Leave> "global refresh_ok ; set refresh_ok 1"
507 .m add command -label {Watch change} -command {
508 add_triggerpoint $subwidgetname $comp [list $r] change
510 .m add command -label {Watch value} -command {
511 add_triggerpoint $subwidgetname $comp [list $r] value
513 .m add command -label {Watch mask/value} -command {
514 add_triggerpoint $subwidgetname $comp [list $r] mask/value
516 .m add command -label {Watch range} -command {
517 add_triggerpoint $subwidgetname $comp [list $r] range
519 if \[not_watchable_p $comp [list $r]\] { .m entryconfigure 0 -state disabled
520 .m entryconfigure 1 -state disabled
521 .m entryconfigure 2 -state disabled
522 .m entryconfigure 3 -state disabled }
524 bind $subwidgetname.label <Button-1> $event_command
525 bind $subwidgetname.label <Button-3> $event_command
526 bind $subwidgetname.label <Enter> "$subwidgetname.label configure -foreground yellow"
527 bind $subwidgetname.label <Leave> "$subwidgetname.label configure -foreground black"
529 pack $subwidgetname.label -side left -fill none
530 pack $subwidgetname.value -ipadx 20 -side right -fill none
531 pack $subwidgetname -side top -fill x
533 pack $wn.regs -side top -fill x
535 global refresh_fragments
537 set refresh_fragments($wn) $refreshcmds
539 if {\"%W\" == \"$wn\"} then {
540 global refresh_fragments
541 if {[info exists refresh_fragments($wn)]} { unset refresh_fragments($wn) }
545 button $wn.buttons.refresh -text Refresh -command {refresh_all}
546 button $wn.buttons.regen -text Regenerate -command "destroy $wn ; open_component_window $category $name $type $comp"
547 button $wn.buttons.close -text "M'kay" -command "destroy $wn"
548 pack $wn.buttons.refresh $wn.buttons.regen -side left
549 pack $wn.buttons.close -side right
550 pack $wn.buttons -side bottom -fill x
555 set component_gui_number 0
556 proc open_component_gui { gui name type comp } {
557 global component_gui_number
558 global compgui_pending_relations
560 incr component_gui_number
562 # perform work by instantiating component of choice
564 set comptype [sid::component::attribute_value $comp $gui]
565 set compname tksm-gui-${component_gui_number}
567 # leave a mark for `proc relate' to inform new gui component
568 set compgui_pending_relations($compname,component) $comp
569 set compgui_pending_relations($compname,relation) "$type $name"
571 set r [sid::component::set_attribute_value [cfgroot_component] "config-line!" "new \"$comptype\" \"$compname\" "]
572 if {$r != "ok"} then { tk_dialog .oops Error "Cannot create gui component $comptype" error 0 ok; return }
577 proc remove_triggerpoint { component watcher_name pin } {
578 global triggerpoint_action
579 global triggerpoint_info
580 unset triggerpoint_action($pin)
581 unset triggerpoint_info($pin)
582 set s [sid::component::disconnect_pin $component $watcher_name $pin]
583 if {$s != "ok"} then {
584 tk_dialog .oops3 Oops "Cannot remove $watcher_name: $s" "error" 0 "oh well"
590 proc tp_ignore_enter { pin } {
591 global triggerpoint_info
592 set triggerpoint_info($pin) "not"
595 proc tp_ignore { pin } {
599 proc tp_count_enter { pin } {
600 global triggerpoint_info
601 set triggerpoint_info($pin) 0
604 proc tp_count { pin } {
605 global triggerpoint_info
606 incr triggerpoint_info($pin)
609 proc tp_stop_enter { pin } {
610 global triggerpoint_info
611 set triggerpoint_info($pin) "waiting"
614 proc tp_stop { pin } {
615 global triggerpoint_info
617 # clear other tp_stop pins' "hit-stopping" indications
618 global triggerpoint_action
619 set search [array startsearch triggerpoint_action]
620 while {[array anymore triggerpoint_action $search]} {
621 set otherpin [array nextelement triggerpoint_action $search]
622 set action $triggerpoint_action($otherpin)
623 if {$action == "tp_stop"} then { tp_stop_enter $otherpin }
625 array donesearch triggerpoint_action $search
627 set triggerpoint_info($pin) "stopping"
629 foreach s $stop_pins {
630 sid::pin::driven_h4 $s 0
635 proc tp_switch { pin } {
636 global triggerpoint_action
637 set a $triggerpoint_action($pin)
638 eval "${a}_enter $pin"
644 # mirror map_watchable_name in sidwatchutil.h
645 proc map_watchable_name { name } {
647 for {set i 0} {$i < [string length $name]} {incr i} {
648 set c [string index $name $i]
649 if {($c >= "a" && $c <= "z") ||
650 ($c >= "A" && $c <= "Z") ||
651 ($c >= "0" && $c <= "9") ||
655 set hex "0123456789ABCDEF"
657 if {$c == ""} then { set cnum 0 } else { scan $c %c cnum }
658 append out [string index $hex [expr {($cnum >> 4) & 0x0f}]]
659 append out [string index $hex [expr {$cnum & 0x0f}]]
666 proc add_triggerpoint { parentwidget component watchable mode } {
667 if {$mode == "change"} then {
669 } elseif {$mode == "value"} then {
670 set v [tk_ask .tpq "Triggerpoint details" "Enter triggerpoint specification" info "value" ]
671 if {[llength $v] == 0} then { return }
672 set args ":[lindex $v 0]"
673 } elseif {$mode == "mask/value"} then {
674 set v [tk_ask .tpq "Triggerpoint details" "Enter triggerpoint specification" info "mask" "value" ]
675 if {[llength $v] == 0} then { return }
676 set args ":[lindex $v 0]:[lindex $v 1]"
677 } elseif {$mode == "range"} then {
678 set v [tk_ask .tpq "Triggerpoint details" "Enter triggerpoint specification" info "low" "high" ]
679 if {[llength $v] == 0} then { return }
680 set args ":[lindex $v 0]:[lindex $v 1]"
683 set recepient_pin [sid::pin::new]
684 set mapped [map_watchable_name $watchable]
685 set watcher_name "watch:${mapped}:${mode}${args}"
687 set s [sid::component::connect_pin $component $watcher_name $recepient_pin]
688 if {$s == "ok"} then {
689 set wn [widgetname $parentwidget $watchable]
690 label $wn -text "(wait)"
692 global triggerpoint_info
693 set triggerpoint_info($recepient_pin) {}
694 global triggerpoint_action
695 set triggerpoint_action($recepient_pin) tp_ignore
696 tp_switch $recepient_pin
698 set my_refresh_fragment "
699 global triggerpoint_info
700 set i \$triggerpoint_info($recepient_pin)
701 if {\$i == \"\"} then {
702 $wn configure -text \"(watch $mode$args)\"
704 $wn configure -text \"(watch $mode$args: \$i)\"
707 global refresh_fragments
708 set refresh_fragments($wn) $my_refresh_fragment
710 # must quote "%" in $watcher_name since bind does textual substitutions
711 regsub -all {%} $watcher_name {%%} watcher_name2
713 if {\"%W\" == \"$wn\"} {
714 remove_triggerpoint $component $watcher_name2 $recepient_pin
715 global refresh_fragments
716 if {[info exists refresh_fragments($wn)]} { unset refresh_fragments($wn) }
720 "global triggerpoint_action
723 menu .m.action -tearoff 0
724 .m add cascade -label {Action} -menu .m.action
725 .m.action add radiobutton -label {Ignore} -variable triggerpoint_action($recepient_pin) -value tp_ignore -command \"tp_switch $recepient_pin\"
726 .m.action add radiobutton -label {Count} -variable triggerpoint_action($recepient_pin) -value tp_count -command \"tp_switch $recepient_pin\"
727 .m.action add radiobutton -label {Stop} -variable triggerpoint_action($recepient_pin) -value tp_stop -command \"tp_switch $recepient_pin\"
728 if {! \[any_stop_pins_p\]} then { .m.action entryconfigure 2 -state disabled }
729 .m add command -label {Reset} -command \"tp_switch $recepient_pin\"
730 .m add command -label {Delete} -command \"pack forget $wn ; destroy $wn\"
732 bind $wn <Button-1> $event_command
733 bind $wn <Button-3> $event_command
734 bind $wn <Enter> "$wn configure -foreground yellow"
735 bind $wn <Leave> "$wn configure -foreground black"
738 pack $wn -side right -fill none
740 tk_dialog .oops3 Oops "Cannot set a $mode triggerpoint on $watchable: $s" "error" 0 "oh well"
748 # XXX: proc unrelate {rel comp} { }
750 proc relate {rel comp} {
751 # XXX: what if type or name has a space in it?
752 set type [lindex $rel 0]
753 set name [lindex $rel 1]
756 set components($name) $comp
758 # handle any pending relations for gui components
759 global compgui_pending_relations
760 if {[info exists compgui_pending_relations($name,component)]} then {
761 sid::component::relate $comp \
762 $compgui_pending_relations($name,relation) \
763 $compgui_pending_relations($name,component)
766 # puts "$name $type $comp"
768 frame .c_$name -relief sunken -borderwidth 2
769 label .c_$name.name -text $name
770 label .c_$name.type -text $type
771 pack .c_$name.name -side left
772 pack .c_$name.type -side right
773 pack .c_$name -side top -fill x -ipadx 20
779 menu .m.views -tearoff 0
780 .m add cascade -label {View} -menu .m.views
781 .m.views add command -label Registers -command \"open_component_window register $name $type $comp; destroy .m\"
783 if \[have_none_p $comp register\] { .m.views entryconfigure 0 -state disabled }
784 .m.views add command -label Pins -command \"open_component_window pin $name $type $comp; destroy .m\"
785 if \[have_none_p $comp pin\] { .m.views entryconfigure 1 -state disabled }
786 .m.views add command -label Settings -command \"open_component_window setting $name $type $comp; destroy .m\"
787 if \[have_none_p $comp setting\] { .m.views entryconfigure 2 -state disabled }
789 menu .m.guis -tearoff 0
790 .m add cascade -label {GUIs} -menu .m.guis"
791 foreach gui [sid::component::attribute_names_in_category $comp gui] {
792 append event_command "
793 .m.guis add command -label \"$gui\" -command \"open_component_gui {$gui} {$name} {$type} {$comp}; destroy .m\" "
796 append event_command "
797 if \[have_none_p $comp gui\] { .m entryconfigure 3 -state disabled }
800 bind .c_$name.name <Button-1> $event_command
801 bind .c_$name.name <Button-3> $event_command
802 bind .c_$name.type <Button-1> $event_command
803 bind .c_$name.type <Button-3> $event_command
804 bind .c_$name.name <Enter> ".c_$name.name configure -foreground yellow"
805 bind .c_$name.name <Leave> ".c_$name.name configure -foreground black"
806 bind .c_$name.type <Enter> ".c_$name.type configure -foreground yellow"
807 bind .c_$name.type <Leave> ".c_$name.type configure -foreground black"
811 proc find_pin { name } {
812 # triggerpoint pins don't have to be listed here
814 if {$name == "refresh" } then { return $refresh_pin }
819 # triggerpoint pins don't have to be listed here
820 return [list "refresh"]
823 proc driven_h4 {pin value} {
824 global triggerpoint_action
825 if {[info exists triggerpoint_action($pin)]} then {
826 eval $triggerpoint_action($pin) $pin
827 # global triggerpoint_info
828 # puts "$triggerpoint_action($pin) $pin -> $triggerpoint_info($pin)"
833 if {$pin == $refresh_pin && $refresh_ok == 1} then {
839 proc connect_pin {name pin} {
840 if {$name == "triggerpoint-hit"} then {
842 lappend stop_pins $pin
848 proc disconnect_pin {name pin} {
849 if {$name == "triggerpoint-hit"} then {
851 set ix [lsearch -exact stop_pins $pin]
853 lreplace stop_pins $ix $ix
862 proc connected_pins {name} {
863 if {$name == "triggerpoint-hit"} then {
869 proc bus_names {} { return "" }
870 proc find_bus {b} { return "" }
872 # stubs that allow this component to be listed safely in itself
873 proc attribute_names_in_category { category } {
874 if {$category == "auto-print"} then {
875 return [list "warning"]
880 proc attribute_names {} {
881 return [list "warning"]
883 proc attribute_value {name} {
884 if {$name == "warning"} then {
885 return "WARNING: TKSM is experimental and is recommended for advanced users only."
890 proc set_attribute_value {name} { return bad_value }
892 proc accessor_names {} { return [list] }
893 proc relationship_names {} { return [list] }