📄 ecosynth.c
字号:
// Similarly ignore SIGTSTP if running in graphical mode, it would
// be inappropriate for the GUI to freeze if the eCos application is
// suspended. If running in text mode then it is better for both
// the application and the I/O auxiliary to freeze, halting any further
// output.
if (!no_windows) {
signal(SIGTSTP, SIG_IGN);
}
Tcl_Main(argc+1, new_argv, &ecosynth_appinit);
return EXIT_SUCCESS;
}
// ----------------------------------------------------------------------------
// Commands for the Tcl interpreter. These are few and far between because
// as much work as possible is done in Tcl.
// Send a SIGIO signal to the parent process. This is done whenever a new
// interrupt is pending. There is a possibility of strange behaviour if
// the synthetic target application is exiting at just the wrong moment
// and this process has become a zombie. An alternative approach would
// involve loading the Extended Tcl extension.
static int
ecosynth_send_SIGIO(ClientData clientData __attribute__ ((unused)),
Tcl_Interp* interp,
int argc,
char** argv __attribute__ ((unused)))
{
if (1 != argc) {
Tcl_SetResult(interp, "wrong # args: should be \"usbtest::_send_SIGIO\"" , TCL_STATIC);
return TCL_ERROR;
}
(void) kill(parent_pid, SIGIO);
return TCL_OK;
}
// Similarly send a SIGKILL (-9) to the parent process. This allows the GUI
// code to kill of the eCos application
static int
ecosynth_send_SIGKILL(ClientData clientData __attribute__ ((unused)),
Tcl_Interp* interp,
int argc,
char** argv __attribute__ ((unused)))
{
if (1 != argc) {
Tcl_SetResult(interp, "wrong # args: should be \"usbtest::_send_SIGIO\"" , TCL_STATIC);
return TCL_ERROR;
}
(void) kill(parent_pid, SIGKILL);
return TCL_OK;
}
// ----------------------------------------------------------------------------
// Application-specific initialization.
static int
ecosynth_appinit(Tcl_Interp* interp)
{
Tcl_Channel from_app;
Tcl_Channel to_app;
// Tcl library initialization. This has the effect of executing init.tcl,
// thus setting up package load paths etc. Not all of that initialization
// is necessarily appropriate for ecosynth, but some devices may well want
// to load in additional packages or whatever.
if (Tcl_Init(interp) == TCL_ERROR) {
return TCL_ERROR;
}
// Optionally initialize Tk as well. This can be suppressed by an
// argument -nw. Possibly this could be done by the Tcl script
// instead using dynamic loading.
//
// There is a problem with the way that Tk does its argument processing.
// By default it will accept abbreviations for the standard wish arguments,
// so if the user specifies e.g. -v then the Tk code will interpret this
// as an abbreviation for -visual, and will probably complain because
// -visual takes an argument whereas ecosynth's -v is just a flag.
//
// The Tk argument processing can be suppressed simply by temporarily
// getting rid of the argv variable. The disadvantage is that some
// standard arguments now have to be processed explicitly:
//
// -colormap map ignored, of little interest these days
// -display display currently ignored. This would have to be
// implemented at the C level, not the Tcl level,
// since Tk_Init() will start interacting with the
// X server. Its implementation would involve a
// setenv() call.
// -geometry geom implemented in the Tcl code using "wm geometry"
// -name name ignored for now.
// -sync ignored, of little interest to typical users
// -use id ignored, probably of little interest for now
// -visual visual ignored, of little interest these days
//
// so actually the only extra work that is required is for the Tcl code
// to process -geometry.
if (!no_windows) {
Tcl_Obj* argv = Tcl_GetVar2Ex(interp, "argv", NULL, TCL_GLOBAL_ONLY);
Tcl_IncrRefCount(argv);
Tcl_UnsetVar(interp, "argv", TCL_GLOBAL_ONLY);
if (Tk_Init(interp) == TCL_ERROR) {
return TCL_ERROR;
}
Tcl_SetVar2Ex(interp, "argv", NULL, argv, TCL_GLOBAL_ONLY);
Tcl_DecrRefCount(argv);
}
// Create the synth:: namespace. Currently this does not seem to be possible from
// inside C.
if (TCL_OK != Tcl_Eval(interp,
"namespace eval synth {\n"
" variable channel_from_app 0\n"
" variable channel_to_app 0\n"
"}\n")) {
fprintf(stderr, PROGNAME ": internal error, failed to create Tcl synth:: namespace\n");
fprintf(stderr, " Please check Tcl version (8.3 or later required).\n");
exit(EXIT_FAILURE);
}
// The pipe to/from the application is exposed to Tcl, allowing
// the main communication to be handled at the Tcl level and
// specifically via the event loop. This requires two additional
// Tcl channels to be created for file descriptors 3 and 4.
from_app = Tcl_MakeFileChannel((ClientData) 3, TCL_READABLE);
if (NULL == from_app) {
fprintf(stderr, PROGNAME ": internal error, failed to create Tcl channel for pipe from application.\n");
exit(EXIT_FAILURE);
}
Tcl_RegisterChannel(interp, from_app);
// The channel name will be something like file0. Add a variable to the
// interpreter to store this name.
if (NULL == Tcl_SetVar(interp, "synth::_channel_from_app", Tcl_GetChannelName(from_app), TCL_GLOBAL_ONLY)) {
fprintf(stderr, PROGNAME ": internal error, failed to create Tcl variable from application channel 0\n");
exit(EXIT_FAILURE);
}
// Repeat for the channel to the application.
to_app = Tcl_MakeFileChannel((ClientData) 4, TCL_WRITABLE);
if (NULL == to_app) {
fprintf(stderr, PROGNAME ": internal error, failed to create Tcl channel for pipe to application.\n");
exit(EXIT_FAILURE);
}
Tcl_RegisterChannel(interp, to_app);
if (NULL == Tcl_SetVar(interp, "synth::_channel_to_app", Tcl_GetChannelName(to_app), TCL_GLOBAL_ONLY)) {
fprintf(stderr, PROGNAME ": internal error, failed to create Tcl variable from application channel 1\n");
exit(EXIT_FAILURE);
}
// The auxiliary may spawn additional programs, via
// device-specific scripts. Those programs should not have
// direct access to the pipe - that would just lead to
// confusion.
fcntl(3, F_SETFD, FD_CLOEXEC);
fcntl(4, F_SETFD, FD_CLOEXEC);
// Add synthetic target-specific commands to the Tcl interpreter.
Tcl_CreateCommand(interp, "synth::_send_SIGIO", &ecosynth_send_SIGIO, (ClientData)NULL, (Tcl_CmdDeleteProc*) NULL);
Tcl_CreateCommand(interp, "synth::_send_SIGKILL", &ecosynth_send_SIGKILL, (ClientData)NULL, (Tcl_CmdDeleteProc*) NULL);
// Define additional variables.
// The version, from the AM_INIT_AUTOMAKE() macro in configure.in
Tcl_SetVar(interp, "synth::_ecosynth_version", ECOSYNTH_VERSION, TCL_GLOBAL_ONLY);
// The parent process id, i.e. that for the eCos application itself.
Tcl_SetVar2Ex(interp, "synth::_ppid", NULL, Tcl_NewIntObj(getppid()), TCL_GLOBAL_ONLY);
// The various directories
Tcl_SetVar(interp, "synth::_ecosynth_repository", ECOS_REPOSITORY, TCL_GLOBAL_ONLY);
Tcl_SetVar(interp, "synth::_ecosynth_libexecdir", LIBEXECDIR, TCL_GLOBAL_ONLY);
Tcl_SetVar(interp, "synth::_ecosynth_package_dir", PACKAGE_DIR, TCL_GLOBAL_ONLY);
Tcl_SetVar(interp, "synth::_ecosynth_package_version", PACKAGE_VERSION, TCL_GLOBAL_ONLY);
Tcl_SetVar(interp, "synth::_ecosynth_package_install", PACKAGE_INSTALL, TCL_GLOBAL_ONLY);
return TCL_OK;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -