📄 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 + -