OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-2.0/] [packages/] [devs/] [watchdog/] [synth/] [v2_0/] [host/] [watchdog.tcl] - Blame information for rev 454

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 27 unneback
# {{{  Banner                                                   
2
 
3
# ============================================================================
4
# 
5
#      watchdog.tcl
6
# 
7
#      Watchdog support for the eCos synthetic target I/O auxiliary
8
# 
9
# ============================================================================
10
# ####COPYRIGHTBEGIN####
11
#                                                                           
12
#  ----------------------------------------------------------------------------
13
#  Copyright (C) 2002 Bart Veer
14
# 
15
#  This file is part of the eCos host tools.
16
# 
17
#  This program is free software; you can redistribute it and/or modify it 
18
#  under the terms of the GNU General Public License as published by the Free 
19
#  Software Foundation; either version 2 of the License, or (at your option) 
20
#  any later version.
21
#  
22
#  This program is distributed in the hope that it will be useful, but WITHOUT 
23
#  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
24
#  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for 
25
#  more details.
26
#  
27
#  You should have received a copy of the GNU General Public License along with
28
#  this program; if not, write to the Free Software Foundation, Inc., 
29
#  59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
30
# 
31
#  ----------------------------------------------------------------------------
32
#                                                                           
33
# ####COPYRIGHTEND####
34
# ============================================================================
35
# #####DESCRIPTIONBEGIN####
36
# 
37
#  Author(s):   bartv
38
#  Contact(s):  bartv
39
#  Date:        2002/09/04
40
#  Version:     0.01
41
#  Description:
42
#      Implementation of the watchdog device. This script should only ever
43
#      be run from inside the ecosynth auxiliary.
44
# 
45
# ####DESCRIPTIONEND####
46
# ============================================================================
47
 
48
# }}}
49
 
50
namespace eval watchdog {
51
 
52
    # Was initialization successful?
53
    variable init_ok 1
54
 
55
    # Has the alarm triggered?
56
    variable alarm_triggered 0
57
 
58
    # The eCos application process id. This is needed to send a SIGPWR signal
59
    # if the watchdog triggers, and to access /proc/<pid>/stat to obtain
60
    # timing information. Strictly speaking _ppid is not exported by
61
    # the I/O auxiliary.
62
    if { ! [info exists synth::_ppid] } {
63
        synth::report_error "Watchdog initialization failed, _ppid variable required"
64
        return ""
65
    }
66
    variable ecos_pid $synth::_ppid
67
 
68
    # Resolution, i.e. how long to go between checks. Currently this is hard-wired
69
    # to one second, or 1000 ms. This may become configurable, either on the
70
    # target-side via CDL or on the host-side via the target definition file.
71
    # Note that currently the watchdog device and the GUI get updated via the
72
    # same timer. If the resolution is changed to e.g. 10 seconds then it might
73
    # be a good idea to update the GUI more frequently, although there are
74
    # arguments for keeping the animation in step with the real work.
75
    variable resolution 1000
76
 
77
    # Options from the target definition file
78
    variable use_wallclock 0
79
    variable window_pack   "-in .main.n -side right"
80
    variable sound_file    ""
81
    variable sound_player  "play"
82
 
83
    if { [synth::tdf_has_device "watchdog"] } {
84
        if { [synth::tdf_has_option "watchdog" "use"] } {
85
            set _use [synth::tdf_get_option "watchdog" "use"]
86
            if { "wallclock_time" == $_use } {
87
                set watchdog::use_wallclock 1
88
            } elseif { "consumed_cpu_time" == $_use } {
89
                set watchdog::use_wallclock 0
90
            } else {
91
                synth::report_error "Invalid entry in target definition file $synth::target_definition\n\
92
                                    \    Device watchdog, option \"use\" should be \"wallclock_time\" or \"consumed_cpu_time\"\n"
93
            }
94
            unset _use
95
        }
96
        if { [synth::tdf_has_option "watchdog" "watchdog_pack"] } {
97
            set watchdog::window_pack [synth::tdf_get_option "watchdog" "watchdog_pack"]
98
            # Too complicated to validate here, instead leave it to a catch statement
99
            # when the window actually gets packed
100
        }
101
        if { [synth::tdf_has_option "watchdog" "sound"] } {
102
            set _sound_file [synth::tdf_get_option "watchdog" "sound"]
103
            # Look for this sound file in the install tree first, then absolute or relative
104
            if { [file exists [file join $synth::device_install_dir $_sound_file] ] } {
105
                set _sound_file [file join $synth::device_install_dir $_sound_file]
106
            }
107
            if { ![file exists $_sound_file] } {
108
                synth::report_error "Invalid entry in target definition file $synth::target_definition\n\
109
                                    \    Device watchdog, option \"sound\", failed to find $_sound_file\n"
110
            } elseif { ! [file readable $_sound_file] } {
111
                synth::report_error "Invalid entry in target definition file $synth::target_definition\n\
112
                                    \    Device watchdog, option \"sound\", no read access to file $_sound_file\n"
113
            } else {
114
                set watchdog::sound_file $_sound_file
115
            }
116
            unset _sound_file
117
        }
118
        if { [synth::tdf_has_option "watchdog" "sound_player"] } {
119
            set watchdog::sound_player [synth::tdf_get_option "watchdog" "sound_player"]
120
        }
121
    }
122
 
123
    # There is no point in creating the watchdog window if any of the image files are missing
124
    if { $synth::flag_gui } {
125
        foreach _image [list "doghouse.gif" "alarm.gif" "eye.gif" "asleep.gif"] {
126
            variable image_[file rootname $_image]
127
            if { ! [synth::load_image "watchdog::image_[file rootname $_image]" [file join $synth::device_install_dir $_image]] } {
128
                synth::report_error "Watchdog device, unable to load image $_image\n\
129
                                    \    This file should have been installed in $synth::device_install_dir\n"
130
                set watchdog::init_ok 0
131
            }
132
        }
133
    }
134
    if { $synth::flag_gui && $watchdog::init_ok } {
135
        canvas .watchdog -width [image width $image_doghouse] -height [image height $image_doghouse] \
136
            -borderwidth 0
137
        variable background [.watchdog create image 0 0 -anchor nw -image $image_doghouse]
138
 
139
        # Eye positions inside the doghouse. The eye is an 8x10 gif,
140
        # mostly white but transparent around the corners
141
        variable left_eye_x         48
142
        variable left_eye_y         70
143
        variable right_eye_x        58
144
        variable right_eye_y        70
145
 
146
        # Pupil positions relative to the eye. The pupils are 3x3 rectangles.
147
        # The dog can look in one of nine different directions, with both eyes
148
        # looking in the same direction (if visible)
149
        variable pupil_positions { { 1 6 } { 1 5 } { 1 3 } { 3 1 } { 3 4 } { 3 6 } { 4 3 } { 4 5 } { 4 6 } }
150
 
151
        # Which eyes are currently visible: none, left, right or both
152
        variable eyes "none"
153
        # What is the current pupil position?
154
        variable pupils 4
155
 
156
        variable left_eye  [.watchdog create image $left_eye_x $left_eye_y -anchor nw -image $image_eye]
157
        variable right_eye [.watchdog create image $right_eye_x $right_eye_y -anchor nw -image $image_eye]
158
 
159
        variable left_pupil \
160
            [.watchdog create rectangle \
161
                 [expr $left_eye_x + [lindex [lindex $pupil_positions $pupils] 0]]     \
162
                 [expr $left_eye_y + [lindex [lindex $pupil_positions $pupils] 1]]     \
163
                 [expr $left_eye_x + [lindex [lindex $pupil_positions $pupils] 0] + 2] \
164
                 [expr $left_eye_y + [lindex [lindex $pupil_positions $pupils] 1] + 2] \
165
                 -fill black]
166
        variable right_pupil \
167
            [.watchdog create rectangle \
168
                 [expr $right_eye_x + [lindex [lindex $pupil_positions $pupils] 0]]     \
169
                 [expr $right_eye_y + [lindex [lindex $pupil_positions $pupils] 1]]     \
170
                 [expr $right_eye_x + [lindex [lindex $pupil_positions $pupils] 0] + 2] \
171
                 [expr $right_eye_y + [lindex [lindex $pupil_positions $pupils] 1] + 2] \
172
                 -fill black]
173
 
174
 
175
        # The dog is asleep until the eCos application activates the watchdog device
176
        .watchdog lower $left_eye $background
177
        .watchdog lower $right_eye $background
178
        .watchdog lower $left_pupil $background
179
        .watchdog lower $right_pupil $background
180
 
181
        # Prepare for an alarm, but obviously the alarm picture should be hidden for now.
182
        variable alarm [.watchdog create image 30 56 -anchor nw -image $image_alarm]
183
        .watchdog lower $alarm $background
184
 
185
        # Start asleep
186
        variable asleep [.watchdog create image 48 70 -anchor nw -image $image_asleep]
187
 
188
        # Now try to pack the watchdog window using the option provided by the
189
        # user. If that fails, report the error and pack in a default window.
190
        if { [catch { eval pack .watchdog $watchdog::window_pack } message] } {
191
            synth::report_error "Watchdog device, failed to pack window in $watchdog::window_pack\n    $message"
192
            pack .watchdog -in .main.n -side right
193
        }
194
 
195
        # Updating the display. This happens once a second.
196
        # If neither eye is visible, choose randomly between
197
        # left-only, right-only or both. Otherwise there is
198
        # a one in eight chance of blinking, probably switching
199
        # to one of the other eye modes
200
        #
201
        # Also, the visible pupil(s) will move every second, to one
202
        # of nine positions
203
        proc gui_update { } {
204
 
205
            if { "none" == $watchdog::eyes} {
206
                set rand [expr int(3 * rand())]
207
                if { 0 == $rand } {
208
                    set watchdog::eyes "left"
209
                    .watchdog raise $watchdog::left_eye   $watchdog::background
210
                    .watchdog raise $watchdog::left_pupil $watchdog::left_eye
211
                } elseif { 1 == $rand } {
212
                    set watchdog::eyes "right"
213
                    .watchdog raise $watchdog::right_eye   $watchdog::background
214
                    .watchdog raise $watchdog::right_pupil $watchdog::right_eye
215
                } else {
216
                    set watchdog::eyes "both"
217
                    .watchdog raise $watchdog::left_eye    $watchdog::background
218
                    .watchdog raise $watchdog::left_pupil  $watchdog::left_eye
219
                    .watchdog raise $watchdog::right_eye   $watchdog::background
220
                    .watchdog raise $watchdog::right_pupil $watchdog::right_eye
221
                }
222
            } else {
223
                if { 0 == [expr int(8 * rand())] } {
224
                    set watchdog::eyes "none"
225
                    .watchdog lower $watchdog::left_eye    $watchdog::background
226
                    .watchdog lower $watchdog::right_eye   $watchdog::background
227
                    .watchdog lower $watchdog::left_pupil  $watchdog::background
228
                    .watchdog lower $watchdog::right_pupil $watchdog::background
229
 
230
                    # There is no point in moving the pupils if both eyes are shut
231
                    return
232
                }
233
            }
234
 
235
            set watchdog::pupils [expr int(9 * rand())]
236
            set new_pupil_x [lindex [lindex $watchdog::pupil_positions $watchdog::pupils] 0]
237
            set new_pupil_y [lindex [lindex $watchdog::pupil_positions $watchdog::pupils] 1]
238
 
239
            if { ("left" == $watchdog::eyes) || ("both" == $watchdog::eyes) } {
240
                .watchdog coords $watchdog::left_pupil              \
241
                    [expr $watchdog::left_eye_x + $new_pupil_x]     \
242
                    [expr $watchdog::left_eye_y + $new_pupil_y]     \
243
                    [expr $watchdog::left_eye_x + $new_pupil_x + 2] \
244
                    [expr $watchdog::left_eye_y + $new_pupil_y + 2]
245
            }
246
            if { ("right" == $watchdog::eyes) || ("both" == $watchdog::eyes) } {
247
                .watchdog coords $watchdog::right_pupil              \
248
                    [expr $watchdog::right_eye_x + $new_pupil_x]     \
249
                    [expr $watchdog::right_eye_y + $new_pupil_y]     \
250
                    [expr $watchdog::right_eye_x + $new_pupil_x + 2] \
251
                    [expr $watchdog::right_eye_y + $new_pupil_y + 2]
252
            }
253
        }
254
 
255
        # Cancel the gui display when the eCos application has exited.
256
        # The watchdog is allowed to go back to sleep. If the application
257
        # exited because of the watchdog then of course the alarm picture
258
        # should remain visible, otherwise it would be just a flash.
259
        proc gui_cancel { } {
260
            .watchdog lower $watchdog::left_eye    $watchdog::background
261
            .watchdog lower $watchdog::right_eye   $watchdog::background
262
            .watchdog lower $watchdog::left_pupil  $watchdog::background
263
            .watchdog lower $watchdog::right_pupil $watchdog::background
264
            if { ! $watchdog::alarm_triggered } {
265
                .watchdog raise $watchdog::asleep      $watchdog::background
266
            }
267
        }
268
 
269
        # Raise the alarm. This involves hiding the eyes and raising
270
        # the alarm picture. If sound is enabled, the sound player
271
        # should be invoked
272
        proc gui_alarm { } {
273
            .watchdog lower $watchdog::asleep      $watchdog::background
274
            .watchdog lower $watchdog::left_eye    $watchdog::background
275
            .watchdog lower $watchdog::right_eye   $watchdog::background
276
            .watchdog lower $watchdog::left_pupil  $watchdog::background
277
            .watchdog lower $watchdog::right_pupil $watchdog::background
278
            .watchdog raise $watchdog::alarm       $watchdog::background
279
 
280
            if { "" != $watchdog::sound_file } {
281
                # Catch errors on the actual exec, e.g. if the sound player is
282
                # invalid, but play the sound in the background. If there are
283
                # problems actually playing the sound then the user should
284
                # still see a message on stderr. Blocking the entire auxiliary
285
                # for a few seconds is not acceptable.
286
                if { [catch { eval exec -- $watchdog::sound_player $watchdog::sound_file & } message] } {
287
                    synth::report_warning "Watchdog device, failed to play alarm sound file\n    $message\n"
288
                }
289
            }
290
        }
291
 
292
        set _watchdog_help [file join $synth::device_src_dir "doc" "devs-watchdog-synth.html"]
293
        if { ![file readable $_watchdog_help] } {
294
            synth::report_warning "Failed to locate synthetic watchdog documentation $_watchdog_help\n\
295
                                  \    Help->Watchdog target menu option disabled.\n"
296
            set _watchdog_help ""
297
        }
298
        if { "" == $_watchdog_help } {
299
            .menubar.help add command -label "Watchdog" -state disabled
300
        } else {
301
            .menubar.help add command -label "Watchdog" -command [list synth::handle_help "file://$_watchdog_help"]
302
        }
303
    }
304
 
305
    # Now for the real work. By default the watchdog is asleep. The eCos
306
    # application can activate it with a start message, which results
307
    # in an "after" timer. That runs once a second to check whether or not
308
    # the watchdog should trigger, and also updates the GUI.
309
    #
310
    # The target-side code should perform a watchdog reset at least once
311
    # a second, which involves another message to this script and the
312
    # setting of the reset_received flag.
313
    #
314
    # The update handler gets information about the eCos application using
315
    # /proc/<pid>/stat (see man 5 proc). The "state" field is important:
316
    # a state of T indicates that the application is stopped, probably
317
    # inside gdb, so cannot reset the watchdog. The other important field
318
    # is utime, the total number of jiffies (0.01 seconds) executed in
319
    # user space. The code maintains an open file handle to the /proc file.
320
 
321
    variable reset_received     0
322
    variable after_id           ""
323
    variable proc_stat          ""
324
    variable last_jiffies       0
325
 
326
    set _filename "/proc/[set watchdog::ecos_pid]/stat"
327
    if { [catch { open $_filename "r" } proc_stat ] } {
328
        synth::report_error "Watchdog device, failed to open $_filename\n    $proc_stat\n"
329
        set watchdog::init_ok 0
330
    }
331
    unset _filename
332
 
333
    proc update { } {
334
        set watchdog::after_id [after $watchdog::resolution watchdog::update]
335
        if { $synth::flag_gui } {
336
            watchdog::gui_update
337
        }
338
        seek $watchdog::proc_stat 0 "start"
339
        set line [gets $watchdog::proc_stat]
340
        scan $line "%*d %*s %s %*d %*d %*d %*d %*d %*lu %*lu %*lu %*lu %*lu %lu" state jiffies
341
 
342
        # In theory it is possible to examine the state field (the third argument).
343
        # If set to T then that indicates the eCos application is traced or
344
        # stopped, probably inside gdb, and it would make sense to act as if
345
        # the application had sent a reset. Unfortunately the state also appears
346
        # to be set to T if the application is blocked in a system call while
347
        # being debugged - including the idle select(), making the test useless.
348
        # FIXME: figure out how to distinguish between being blocked inside gdb
349
        # and being in a system call.
350
        #if { "T" == $state } {
351
        #    set watchdog::reset_received 1
352
        #    return
353
        #}
354
 
355
        # If there has been a recent reset the eCos application can continue to run for a bit longer.
356
        if { $watchdog::reset_received } {
357
            set watchdog::last_jiffies $jiffies
358
            set watchdog::reset_received 0
359
            return
360
        }
361
 
362
        # We have not received a reset. If the watchdog is using wallclock time then
363
        # that is serious. If the watchdog is using elapsed cpu time then the eCos
364
        # application may not actually have consumed a whole second of cpu time yet.
365
        if { $watchdog::use_wallclock || (($jiffies - $watchdog::last_jiffies) > ($watchdog::resolution / 10)) } {
366
            set watchdog::alarm_triggered 1
367
            # Report the situation via the main text window
368
            synth::report "Watchdog device: the eCos application has not sent a recent reset\n    Raising SIGPWR signal.\n"
369
            # Then kill off the eCos application
370
            exec kill -PWR $watchdog::ecos_pid
371
            # There is no point in another run of the timer
372
            after cancel $watchdog::after_id
373
            # And if the GUI is running, raise the alarm visually
374
            if { $synth::flag_gui } {
375
                watchdog::gui_alarm
376
            }
377
        }
378
    }
379
 
380
    # When the eCos application has exited, cancel the timer and
381
    # clean-up the GUI. Also get rid of the open file since the
382
    # /proc/<pid>/stat file is no longer meaningful
383
    proc exit_hook { arg_list } {
384
        if { "" != $watchdog::after_id } {
385
            after cancel $watchdog::after_id
386
        }
387
        if { $synth::flag_gui } {
388
            watchdog::gui_cancel
389
        }
390
        close $watchdog::proc_stat
391
    }
392
    synth::hook_add "ecos_exit" watchdog::exit_hook
393
 
394
    proc handle_request { id reqcode arg1 arg2 reqdata reqlen reply_len } {
395
        if { 0x01 == $reqcode } {
396
            # A "start" request. If the watchdog has already started,
397
            # this request is a no-op. Otherwise a timer is enabled.
398
            # This is made to run almost immediately, so that the
399
            # GUI gets a quick update. Setting the reset_received flag
400
            # ensures that the watchdog will not trigger immediately
401
            set watchdog::reset_received 1
402
            if { "" == $watchdog::after_id } {
403
                set watchdog::after_id [after 1 watchdog::update]
404
            }
405
            if { $synth::flag_gui } {
406
                .watchdog lower $watchdog::asleep $watchdog::background
407
            }
408
        } elseif { 0x02 == $reqcode } {
409
            # A "reset" request. Just set a flag, the update handler
410
            # will detect this next time it runs.
411
            set watchdog::reset_received 1
412
        }
413
    }
414
 
415
    proc instantiate { id name data } {
416
        return watchdog::handle_request
417
    }
418
}
419
 
420
if { $watchdog::init_ok } {
421
    return watchdog::instantiate
422
} else {
423
    synth::report "Watchdog cannot be instantiated, initialization failed.\n"
424
    return ""
425
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.