📄 ecosynth.tcl
字号:
# {{{ Banner
# ============================================================================
#
# ecosynth.tcl
#
# The eCos synthetic target I/O auxiliary
#
# ============================================================================
# ####COPYRIGHTBEGIN####
#
# ----------------------------------------------------------------------------
# Copyright (C) 2002 Bart Veer
#
# This file is part of the eCos host tools.
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, write to the Free Software Foundation, Inc.,
# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
# ----------------------------------------------------------------------------
#
# ####COPYRIGHTEND####
# ============================================================================
# #####DESCRIPTIONBEGIN####
#
# Author(s): bartv
# Contact(s): bartv
# Date: 2002/08/05
# Version: 0.01
# Description:
# The main script for the eCos synthetic target auxiliary. This should
# only ever be invoked from inside ecosynth.
#
# ####DESCRIPTIONEND####
# ============================================================================
# }}}
# {{{ Overview
# When an eCos synthetic target application runs it will usually
# fork/execve an auxiliary program, ecosynth, to provide certain
# I/O functionality. This happens as part of hardware initialization.
#
# The ecosynth executable in turn runs this ecosynth.tcl script which
# either does most of the real work or delegates it to other scripts.
# Those other scripts may in turn exec other programs to perform any
# I/O operations that cannot easily be done at the Tcl level. For
# example performing low-level ethernet operations generally requires
# working at the C level or equivalent, so a separate executable would
# be appropriate. The ecosynth executable will transfer control to
# this script after the appinit() call, which should have performed
# certain initialization steps.
#
# 1) the Tcl interpreter will be fully initialized.
#
# 2) usually Tk will have been loaded and initialized as well. This
# can be suppressed using a command-line option -nw.
#
# 3) there will be a namespace synth:: for use by ecosynth.tcl
# Auxiliary scripts are expected to use their own namespace
# where possible.
#
# 4) there will be two channels synth::_channel_from_app and
# synth::_channel_to_app. These correspond to a pipe between
# the eCos application and the auxiliary. The application will
# send requests using this pipe and expect replies. I/O
# operations are always initiated by a request from the
# application, but the auxiliary can raise an interrupt via
# the SIGIO signal.
#
# Other standard channels stdin, stdout and stderr will have
# been inherited from the eCos application.
#
# 5) some Tcl commands implemented in C will have been added to the
# interpreter. The most notable is synth::_send_SIGIO, used to
# raise an interrupt within the application.
#
# 6) similarly some variables will have been added to the interpreter.
#
#
# Configuring everything can get somewhat complicated. It is the eCos
# application that knows what I/O facilities within the auxiliary it
# wants to access, but it may not know all the details. The eCos
# component architecture makes things a bit more complicated still,
# generic code such as this ecosynth.tcl script has no way of knowing
# what I/O facilities might be provided by some package or other.
#
# For example, a target-side ethernet driver may want to send outgoing
# ethernet packets to some script or program on the host and receive
# incoming ethernet packets. However it does not necessarily know what
# the host-side should do with those ethernet packets, e.g. use a
# spare Linux ethernet device, use the Linux kernel's ethertap
# facility, ... Although that kind of information could be handled by
# target-side configury, host-side configuration files will often be
# more appropriate. Specifically it would allow a single eCos
# synthetic target application to run in a variety of environments,
# using different ways to provide the I/O, with no need to do any
# reconfiguring or rebuilding of the target side.
#
#
# The basic approach that is taken is:
#
# 1) the eCos application tells the auxiliary what I/O facilities
# it is interested in. This should happen as a result
# of static constructors or of device driver initialization
# routines. The application has no control over the implementation
# of the I/O facilities, it just expects something on the other
# end to respond sensibly to requests.
#
# For example, a synthetic target ethernet driver will supply
# an initialization routine via its NETDEVTAB_ENTRY. This
# routine will send a request to the auxiliary asking for a
# device of type ethernet, id "eth0", provided by
# CYGPKG_DEVS_ETH_ECOSYNTH, version current. The auxiliary will
# now attempt to load a suitable Tcl script ethernet.tcl from a
# location determined using the package name and version.
#
# 2) there is a primary target definition file which can be
# specified as the final argument on the command line, with
# "default" being the default value. The code will look for
# this file with or without a .tdf extension, first in the
# current directory, then in ~/.ecos/synth/. This file is
# actually a Tcl script that gets executed in the current
# interpreter. However typically it will only contain
# entries such as:
#
# synth_device eth0 {
# ...
# }
#
# 3) There are additional optional configuration files
# ~/.ecos/synth/initrc.tcl and ~/.ecos/synth/mainrc.tcl which can
# be used for further customization. initrc.tcl will get run
# early on, mainrc.tcl will get run once initialization is
# complete. Specifically the target-side code will send an
# appropriate request after invoking all the static constructors.
# At this time the auxiliary will run mainrc.tcl, and in addition
# it may issue warnings about unused arguments etc.
#
# 4) there may also be separate configuration files for GUI
# preferences etc. These are distinct from the initrc and
# mainrc files in that they are generated rather than
# hand-written.
# }}}
# {{{ Basic initialization
# ----------------------------------------------------------------------------
# There should be two channels corresponding to the pipe between the
# eCos application and the auxiliary. These should be configured
# appropriately. If either channel does not exist then that is a
# very good indication that the system is not properly initialized,
# i.e. that this script is not being run by the ecosynth executable
# and by implication that no eCos application is involved.
if {([info exists synth::_channel_to_app] == 0) ||
([info exists synth::_channel_from_app] == 0) ||
([info exists synth::_ecosynth_version] == 0) ||
([info exists synth::_ppid] == 0) ||
([info exists synth::_ecosynth_repository] == 0) ||
([info exists synth::_ecosynth_libexecdir] == 0) ||
([info exists synth::_ecosynth_package_dir] == 0) ||
([info exists synth::_ecosynth_package_version] == 0) ||
([info exists synth::_ecosynth_package_install] == 0) ||
([info commands synth::_send_SIGIO] == "") ||
([info commands synth::_send_SIGKILL] == "") } {
puts stderr "ecosynth.tcl: the current interpreter has not been properly initialized."
puts stderr " This script should only be invoked by the ecosynth executable when"
puts stderr " an eCos synthetic target application is run."
exit 1
}
# Is the script currently being executed the most recent version?
# This check should only happen if an environment variable
# ECOSYNTH_DEVEL is set, because the installed tools may have come
# from somewhere other than the current repository.
if { [info exists ::env(ECOSYNTH_DEVEL)] } {
set _orig_name [file join $synth::_ecosynth_repository $synth::_ecosynth_package_dir $synth::_ecosynth_package_version \
"host" [file tail [info script]]]
if { [file exists $_orig_name] && [file readable $_orig_name] && ($_orig_name != [info script]) } {
if { [file mtime $_orig_name] >= [file mtime [info script]] } {
puts "$_orig_name is more recent than install: executing that."
source $_orig_name
return
}
}
unset _orig_name
}
fconfigure $synth::_channel_to_app -buffering none
fconfigure $synth::_channel_from_app -encoding binary
fconfigure $synth::_channel_to_app -encoding binary
fconfigure $synth::_channel_from_app -translation binary
fconfigure $synth::_channel_to_app -translation binary
# Define additional globals and procedures inside the synth:: namespace.
# Variables and functions that begin with an _ are considered internal
# and should not be used directly.
namespace eval synth {
# Unfortunately the name of the eCos executable is lost at this stage.
# Within the eCos application it was held in argv[0], but that has been
# overridden with the name of the auxiliary. However we have access to the
# parent process id so we can use /proc to get the required information.
variable ecos_appname ""
catch {
set synth::ecos_appname [file readlink "/proc/[set synth::_ppid]/exe"]
set synth::ecos_appname [file tail $synth::ecos_appname]
}
# The install location can be determined from the script name.
# This is used for e.g. loading bitmaps, even if ECOSYNTH_DEVEL
# is set, because some of the files may be generated.
# ECOSYNTH_DEVEL only affects Tcl scripts.
variable install_dir [file join $synth::_ecosynth_libexecdir "ecos" $synth::_ecosynth_package_install]
# Is the eCos application still running? This is worth keeping
# track of so that send_reply and raise_interrupt do not try to
# interact with a program that is no longer running.
variable ecos_running 1
# This variable is used to enter the event loop
variable _ecosynth_exit 0
# Is GUI mode enabled?
variable flag_gui [expr { "" != [info commands "tk"] } ]
# When running in GUI mode the GUI should stay up even after the application
# has exited, so that the user can take a good look around. When running in
# non-GUI mode this program should exit as soon it has finished cleaning up.
variable flag_immediate_exit [expr { 0 == $synth::flag_gui} ]
# Is the GUI ready to accept output?
variable flag_gui_ready 0
# Flags and variables related to command-line arguments
variable flag_help 0
variable flag_keep_going 0
variable flag_no_rc 0
variable flag_verbose 0
variable flag_debug 0
variable logfile ""
variable target_definition ""
variable geometry "<none>"
}
# }}}
# {{{ Hooks & atexit support
# ----------------------------------------------------------------------------
# A lot of the flexibility of ecosynth is provided by hooks. Device scripts
# and, more importantly, the per-user initrc and mainrc scripts can install
# hooks that get called when an event occurs, for example when the eCos
# applications attempts to transmit an ethernet packet.
#
# A special hook is used to implement atexit handling. This involves redefining
# the "exit" command so that it will invoke the appropriate hooks first.
namespace eval synth {
# All hooks are held in an array, indexed by the hook name, with each
# array entry being a list of functions to be invoked.
array set _hooks [list]
proc hook_define { name } {
if { [info exists synth::_hooks($name)] } {
synth::report_error "Attempt to create hook $name which already exists.\n"
} else {
set synth::_hooks($name) [list]
}
}
proc hook_defined { name } {
return [info exists synth::_hooks($name)]
}
proc hook_add { name function } {
if { ! [info exists synth::_hooks($name)] } {
synth::report_error "Attempt to attach a function to an unknown hook $name\n"
set synth::_hooks($name) [list]
}
lappend synth::_hooks($name) $function
}
proc hook_call { name args } {
if { ! [info exists synth::_hooks($name) ] } {
synth::report_error "Attempt to invoke unknown hook $name\n"
} else {
foreach function $synth::_hooks($name) {
$function $args
}
}
}
# Define an initial set of hooks
synth::hook_define "exit" ;# The auxiliary is exiting
synth::hook_define "ecos_exit" ;# The eCos application has exited
synth::hook_define "ecos_initialized" ;# eCos static constructors have run
synth::hook_define "help" ;# --help
}
# Rename the builtin exit command so that it can still be accessed.
rename exit _hook_real_exit
# And define a replacement for exit which will invoke the appropriate
# hook. Care has to be taken in case of recursive exit calls, each
# hook function is only called once.
proc exit { { code 0 } } {
while { [llength $synth::_hooks(exit)] > 0 } {
set handler [lindex $synth::_hooks(exit) end]
set synth::_hooks(exit) [lrange $synth::_hooks(exit) 0 end-1]
# For now assume no errors - it is not clear what could be done
# about them anyway.
catch { eval $handler [list]}
}
_hook_real_exit $code
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -