⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 watchdog.tcl

📁 开放源码实时操作系统源码.
💻 TCL
📖 第 1 页 / 共 2 页
字号:
                    .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 + -