📄 watchdog.tcl
字号:
.watchdog raise $watchdog::right_pupil $watchdog::right_eye } else { set watchdog::eyes "both" .watchdog raise $watchdog::left_eye $watchdog::background .watchdog raise $watchdog::left_pupil $watchdog::left_eye .watchdog raise $watchdog::right_eye $watchdog::background .watchdog raise $watchdog::right_pupil $watchdog::right_eye } } else { if { 0 == [expr int(8 * rand())] } { set watchdog::eyes "none" .watchdog lower $watchdog::left_eye $watchdog::background .watchdog lower $watchdog::right_eye $watchdog::background .watchdog lower $watchdog::left_pupil $watchdog::background .watchdog lower $watchdog::right_pupil $watchdog::background # There is no point in moving the pupils if both eyes are shut return } } set watchdog::pupils [expr int(9 * rand())] set new_pupil_x [lindex [lindex $watchdog::pupil_positions $watchdog::pupils] 0] set new_pupil_y [lindex [lindex $watchdog::pupil_positions $watchdog::pupils] 1] if { ("left" == $watchdog::eyes) || ("both" == $watchdog::eyes) } { .watchdog coords $watchdog::left_pupil \ [expr $watchdog::left_eye_x + $new_pupil_x] \ [expr $watchdog::left_eye_y + $new_pupil_y] \ [expr $watchdog::left_eye_x + $new_pupil_x + 2] \ [expr $watchdog::left_eye_y + $new_pupil_y + 2] } if { ("right" == $watchdog::eyes) || ("both" == $watchdog::eyes) } { .watchdog coords $watchdog::right_pupil \ [expr $watchdog::right_eye_x + $new_pupil_x] \ [expr $watchdog::right_eye_y + $new_pupil_y] \ [expr $watchdog::right_eye_x + $new_pupil_x + 2] \ [expr $watchdog::right_eye_y + $new_pupil_y + 2] } } # Cancel the gui display when the eCos application has exited. # The watchdog is allowed to go back to sleep. If the application # exited because of the watchdog then of course the alarm picture # should remain visible, otherwise it would be just a flash. proc gui_cancel { } { .watchdog lower $watchdog::left_eye $watchdog::background .watchdog lower $watchdog::right_eye $watchdog::background .watchdog lower $watchdog::left_pupil $watchdog::background .watchdog lower $watchdog::right_pupil $watchdog::background if { ! $watchdog::alarm_triggered } { .watchdog raise $watchdog::asleep $watchdog::background } } # Raise the alarm. This involves hiding the eyes and raising # the alarm picture. If sound is enabled, the sound player # should be invoked proc gui_alarm { } { .watchdog lower $watchdog::asleep $watchdog::background .watchdog lower $watchdog::left_eye $watchdog::background .watchdog lower $watchdog::right_eye $watchdog::background .watchdog lower $watchdog::left_pupil $watchdog::background .watchdog lower $watchdog::right_pupil $watchdog::background .watchdog raise $watchdog::alarm $watchdog::background if { "" != $watchdog::sound_file } { # Catch errors on the actual exec, e.g. if the sound player is # invalid, but play the sound in the background. If there are # problems actually playing the sound then the user should # still see a message on stderr. Blocking the entire auxiliary # for a few seconds is not acceptable. if { [catch { eval exec -- $watchdog::sound_player $watchdog::sound_file & } message] } { synth::report_warning "Watchdog device, failed to play alarm sound file\n $message\n" } } } set _watchdog_help [file join $synth::device_src_dir "doc" "devs-watchdog-synth.html"] if { ![file readable $_watchdog_help] } { synth::report_warning "Failed to locate synthetic watchdog documentation $_watchdog_help\n\ \ Help->Watchdog target menu option disabled.\n" set _watchdog_help "" } if { "" == $_watchdog_help } { .menubar.help add command -label "Watchdog" -state disabled } else { .menubar.help add command -label "Watchdog" -command [list synth::handle_help "file://$_watchdog_help"] } } # Now for the real work. By default the watchdog is asleep. The eCos # application can activate it with a start message, which results # in an "after" timer. That runs once a second to check whether or not # the watchdog should trigger, and also updates the GUI. # # The target-side code should perform a watchdog reset at least once # a second, which involves another message to this script and the # setting of the reset_received flag. # # The update handler gets information about the eCos application using # /proc/<pid>/stat (see man 5 proc). The "state" field is important: # a state of T indicates that the application is stopped, probably # inside gdb, so cannot reset the watchdog. The other important field # is utime, the total number of jiffies (0.01 seconds) executed in # user space. The code maintains an open file handle to the /proc file. variable reset_received 0 variable after_id "" variable proc_stat "" variable last_jiffies 0 set _filename "/proc/[set watchdog::ecos_pid]/stat" if { [catch { open $_filename "r" } proc_stat ] } { synth::report_error "Watchdog device, failed to open $_filename\n $proc_stat\n" set watchdog::init_ok 0 } unset _filename proc update { } { set watchdog::after_id [after $watchdog::resolution watchdog::update] if { $synth::flag_gui } { watchdog::gui_update } seek $watchdog::proc_stat 0 "start" set line [gets $watchdog::proc_stat] scan $line "%*d %*s %s %*d %*d %*d %*d %*d %*lu %*lu %*lu %*lu %*lu %lu" state jiffies # In theory it is possible to examine the state field (the third argument). # If set to T then that indicates the eCos application is traced or # stopped, probably inside gdb, and it would make sense to act as if # the application had sent a reset. Unfortunately the state also appears # to be set to T if the application is blocked in a system call while # being debugged - including the idle select(), making the test useless. # FIXME: figure out how to distinguish between being blocked inside gdb # and being in a system call. #if { "T" == $state } { # set watchdog::reset_received 1 # return #} # If there has been a recent reset the eCos application can continue to run for a bit longer. if { $watchdog::reset_received } { set watchdog::last_jiffies $jiffies set watchdog::reset_received 0 return } # We have not received a reset. If the watchdog is using wallclock time then # that is serious. If the watchdog is using elapsed cpu time then the eCos # application may not actually have consumed a whole second of cpu time yet. if { $watchdog::use_wallclock || (($jiffies - $watchdog::last_jiffies) > ($watchdog::resolution / 10)) } { set watchdog::alarm_triggered 1 # Report the situation via the main text window synth::report "Watchdog device: the eCos application has not sent a recent reset\n Raising SIGPWR signal.\n" # Then kill off the eCos application exec kill -PWR $watchdog::ecos_pid # There is no point in another run of the timer after cancel $watchdog::after_id # And if the GUI is running, raise the alarm visually if { $synth::flag_gui } { watchdog::gui_alarm } } } # When the eCos application has exited, cancel the timer and # clean-up the GUI. Also get rid of the open file since the # /proc/<pid>/stat file is no longer meaningful proc exit_hook { arg_list } { if { "" != $watchdog::after_id } { after cancel $watchdog::after_id } if { $synth::flag_gui } { watchdog::gui_cancel } close $watchdog::proc_stat } synth::hook_add "ecos_exit" watchdog::exit_hook proc handle_request { id reqcode arg1 arg2 reqdata reqlen reply_len } { if { 0x01 == $reqcode } { # A "start" request. If the watchdog has already started, # this request is a no-op. Otherwise a timer is enabled. # This is made to run almost immediately, so that the # GUI gets a quick update. Setting the reset_received flag # ensures that the watchdog will not trigger immediately set watchdog::reset_received 1 if { "" == $watchdog::after_id } { set watchdog::after_id [after 1 watchdog::update] } if { $synth::flag_gui } { .watchdog lower $watchdog::asleep $watchdog::background } } elseif { 0x02 == $reqcode } { # A "reset" request. Just set a flag, the update handler # will detect this next time it runs. set watchdog::reset_received 1 } } proc instantiate { id name data } { return watchdog::handle_request }}if { $watchdog::init_ok } { return watchdog::instantiate} else { synth::report "Watchdog cannot be instantiated, initialization failed.\n" return ""}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -