#ifndef lint static char *rcsid="$Header: /mit/hst/src/event/RCS/Event.c,v 2.4 91/01/10 17:18:12 tldavis Exp $"; #endif /* * Event.c: Copyright 1990 Timothy L. Davis * * These functions deal with interaction between the simulation, * the user interface, and the operating system. * The main top-level loop DispatchDataAndEvents() is also here. * * To use zephyr windowgrams to report errors, define the symbol "ZEPHYR". * To use a pipe to store simulation data, define the symbol "USEPIPE". * * $Log: Event.c,v $ * Revision 2.4 91/01/10 17:18:12 tldavis * Fixed problem with POLLING. If there is nothing to do, * the simulator will now BLOCK in XtNextEvent() instead of constantly * checking XPending() and checking if more simulation data is needed. * (This bug was in DispatchDataAndEvents().) * , * * Revision 2.3 90/08/28 14:36:15 tldavis * Fixed error file posting. * * Revision 2.1 90/08/18 18:32:20 tldavis * General cleanup. * */ #include #include #include #ifdef RSAIX extern void *malloc(), *realloc(); #else #ifdef __STDC__ #include #else #include #endif #endif #include "../sim/CVDefs.h" #include "../data/Parameter.h" #include "Event.h" extern char *CVLib; /* from Main.c */ /* samn includes */ #include #include /* end samn includes */ #ifdef NOTDEF #define ZEPHYR /* Use zwrite for Project Athena error notification. */ #endif extern int simulate(); extern Display *dpy; extern Widget paramWidget; /* from ../cv/Interface.c */ extern caddr_t paramWinData; /* from ../cv/Interface.c */ extern void ShowParameters();/* from ../cv/Interface.c */ /* * record of window and update/data procs */ typedef struct { Widget widget; void (*modProc)(); void (*dataProc)(); } DataWidgetRec; static int FPERROR = 0; /*PUBLIC*/ /*ARGSUSED*/ #ifdef SVR4 void fpe_in_simulate(int foo) #else int fpe_in_simulate(int foo) #endif { PostErrorString("Floating Point Error in simulate.c"); FPERROR = 1; /* Not an extern variable, so OK for Sun-4 -O3 optimization */ #ifndef SVR4 return(0); #endif } /*PUBLIC*/ void PostErrorString(s) char *s; { #ifdef ZEPHYR char ss[256]; sprintf(ss, "zwrite -q $USER -m %s\n",s); system(ss); #else XtWarning(s); #endif } /*PUBLIC*/ void PostErrorFile(s) char *s; { #ifdef ZEPHYR char ss[256]; sprintf(ss,"zwrite -q $USER < %s",s); system(ss); #else int c; FILE *file; char buf[2048], *p, *end; XtWarning("SIMULATOR ERROR:\n"); if ((file = fopen(s,"r")) != NULL) { p = buf; end = &buf[2047]; while ((c=getc(file))!=EOF && p < end) *p++ = (char) c; fclose(file); *p++ = '\n'; XtWarning(buf); } #endif } static double x[10]; /*PUBLIC*/ int Stopped; static DataWidgetRec *DWlist = (DataWidgetRec *)0, *dwLast; static int DWlen = 0, DWactive = 0; /* * Register a widget to receive simulation data from DispatchData() * Takes widget window, parameter modification handler modProc(), and * data reception handler dataProc(): * * void (*modProc)(Widget widget,double x[], int place,int type, double value); * void (*dataProc)(Widget widget, double[] pressures); */ /*PUBLIC*/ void AddDataWidget(widget, modProc, dataProc) Widget widget; void (*modProc)(), (*dataProc)(); { int l = DWlen; DWactive++; if (l) { while (l--) if (DWlist[l].widget == (Widget) 0) {/*0 means unused record (deleted) */ DWlist[l].widget = widget; DWlist[l].modProc = modProc; DWlist[l].dataProc = dataProc; return; } DWlist = (DataWidgetRec *)realloc((char *)DWlist, (2+DWlen)*sizeof(DataWidgetRec)); } else { DWlist = (DataWidgetRec *)malloc((2+DWlen)*sizeof(DataWidgetRec)); } DWlist[DWlen].widget = widget; DWlist[DWlen].modProc = modProc; DWlist[DWlen].dataProc = dataProc; DWlist[++DWlen].widget = (Widget)0; /* end of list */ dwLast = &DWlist[DWlen]; } /* * Remove widget from the list of those receiving data packets */ /*PUBLIC*/ void DeleteDataWidget(widget) Widget widget; { int l = DWlen; while (l--) if (DWlist[l].widget && (DWlist[l].widget == widget || XtParent(DWlist[l].widget) == widget)) { DWlist[l].widget = (Widget)0; /* delete this entry */ DWactive--; } } void UpdateParamWindow() { if (paramWidget) ShowParameters((Widget)0, paramWinData, (caddr_t)0); } /* * Get data from pipe fd, and broadcast it to all widgets which have requested * a simulation data stream (used in DispatchDataAndEvents). */ static double currentTime = 0.0; /* the current time for Reset() */ #ifdef USEPIPE static void DispatchData(fd, dataWidget) int fd; DataWidgetRec *dataWidget; { char dataType; double pressures[10]; fd_set readfds; struct timeval timeout; DataWidgetRec *dw; if (!DWactive) return; if (DWactive < 0 || DWlen < 0) fprintf(stderr,"Bad DataPlot list!\n"); FD_ZERO(&readfds); FD_SET(fd, &readfds); timerclear(&timeout); while (select(FD_SETSIZE, &readfds,(fd_set *)0,(fd_set *)0,&timeout) != 0) { read(fd, &dataType, sizeof(dataType)); switch (dataType) { case DATA: if (read(fd,pressures,sizeof(pressures[0])*10)==sizeof(pressures[0])*10){ currentTime = pressures[6]; for (dw = dataWidget; dw != dwLast; dw++) if (dw->widget) (*dw->dataProc)(dw->widget, pressures); } break; } } } #else #define SIMBUFLENGTH 110 static double SimBuffer[SIMBUFLENGTH]; /* Storage for simulation data between * data production and plotting. */ static int SimBufHead = 0, SimBufTail = 0; static void DispatchData(dataWidget) DataWidgetRec *dataWidget; { double pressures[10]; DataWidgetRec *dw; int i; if (!DWactive) return; if (DWactive < 0 || DWlen < 0) fprintf(stderr,"Bad DataPlot list!\n"); while (SimBufHead != SimBufTail) { for (i=0; i<10; i++) { pressures[i] = SimBuffer[SimBufHead++]; if (SimBufHead >= SIMBUFLENGTH) SimBufHead -= SIMBUFLENGTH; if (SimBufHead == SimBufTail) i=100; } if (i < 100) { /* Got a complete set of pressures to dispatch */ currentTime = pressures[6]; for (dw = dataWidget; dw != dwLast; dw++) if (dw->widget) (*dw->dataProc)(dw->widget, pressures); } } } #endif static Boolean Flushing=False; /* Whether to flush simulation data or use it*/ /*PUBLIC*/ void SimDataEnq(pressures) double *pressures; { if (Flushing==True || FPERROR) return; else #ifndef USEPIPE { register int i; for (i = 0; i < 10 ; i++) { SimBuffer[SimBufTail++] = pressures[i]; if (SimBufTail >= SIMBUFLENGTH) SimBufTail -= SIMBUFLENGTH; if (SimBufTail == SimBufHead) { PostErrorString("Simulation Buffer Overflow!"); SimBufTail--; } } } #else { int c, len; char *start; static char header=DATA; while (write(SimToPlotPipe[1], &header, sizeof(char)) < sizeof(char)) ; start = (char *) pressures; len=sizeof(pressures[0])*10; while ((c=write(SimToPlotPipe[1], start, len)) != len) { len -= c; start += c; } } #endif } /*************************************************************************/ /* * * The following help the simulator to communicate with the plot process. * */ #ifdef USEPIPE static int SimToPlotPipe[2]; /* pipe from simulator -> plotting process */ #endif /* * This is the main top-level control loop. Process all X events, then * get the next data from the simulator process if there are any active * plots. If no active plots exist, the loop will block in XtNextEvent() * processing only user interactions, without polling, to save CPU time * for other possible processes. */ /*PUBLIC*/ void DispatchDataAndEvents() /* never returns */ { XEvent ev; double old_x[10]; int failures = 0, i; #ifdef USEPIPE if (fd) SimToPlotPipe[0] = fd; #endif for (;;) { while (XPending(dpy) || !DWactive || Stopped) /* Allow to block only if we have no reason to calculate data */ { XNextEvent(dpy, &ev); XtDispatchEvent(&ev); } #ifdef USEPIPE DispatchData(SimToPlotPipe[0], DWlist); #else DispatchData(DWlist); #endif /* Compute the next bit of simulation data, taking care to * restart on the event of a simulation failure. */ x[6] = currentTime; Flushing = False; if (simulate(x, 10)) { for (i = 0; i < 10; i++) old_x[i] = x[i]; failures = 0; currentTime = x[6]; } else if (++failures > 50 || FPERROR) { /* hope the user resets a parameter, but if not */ char path[1024]; sprintf(path,"%s/convergence.failure", CVLib); PostErrorFile(path); Stopped = 1; /* quit simultion process; user must re-start */ failures = 0; FPERROR = 0; for (i = 0; i<10; i++) x[i] = old_x[i]; } } } /*PUBLIC*/ void SimFlush() /* Clears data queue. */ { #ifdef USEPIPE DispatchData(SimToPlotPipe[0], DWlist); #else DispatchData(DWlist); #endif } /* * PUBLIC routines handling communication with the SIMULATOR through * Unix pipes or a manually-handled buffer. * */ /*PUBLIC*/ void SendToSim(place, type, value) /*send param change to sim.proc*/ int place, type; double value; { setval(x, place, type, value); } /*PUBLIC*/ void MakeSimulator(parameters, starttime) SIMULATION *parameters; double starttime; { static int i; #ifdef USEPIPE static int devnull =-1; if (pipe(SimToPlotPipe) != 0) { fprintf(stderr, "Pipe creation failed.\n"); } if (devnull < 0) devnull = open("/dev/null",O_WRONLY, 0); #endif initeqnvars(parameters); setupCoeffs(); btconst(); estimate(parameters, x); /* sets x[9] to 0, start a new beat. */ Flushing = True; for (i=0; i < 4; i++) simulate(x, TBLSEGS); Flushing = False; Stopped = 0; x[6] = currentTime = starttime; } /* send signal to pause simulation */ /*PUBLIC*/ void StopSimulator() { Stopped = 1; } /* resume simulation where we left off, no steady-state finding. */ /*PUBLIC*/ int ResumeSimulator() { Stopped = 0; #ifdef USEPIPE return(SimToPlotPipe[0]); #else return(1); #endif } /* Reset simulator with a new data state. Find new steady state. */ /*PUBLIC*/ void ResetSimulator(parameters) SIMULATION *parameters; { #ifdef USEPIPE close(SimToPlotPipe[0]);/* discard the data in the pipe. */ close(SimToPlotPipe[1]); #endif MakeSimulator(parameters, currentTime); /* Continue from current time */ }