2004-06-02 Adrian Dawe <adrian.dawe@multigig.com>
* src/frontend/com_dl.c src/frontend/com_dl.c src/frontend/commands.c: Add function xaltermod 2004-06-02 Stefan Jones <stefan.jones@multigig.com> * configure.in: Change to version 16 Disable GnuReadline in tclspice * src/tclspice.c: Added trigger and step callbacks Fix redef of sighandler_t * src/pkgIndex.tcl.in: set a global variable spice_version
This commit is contained in:
parent
3b794a57d1
commit
8bb830eff2
18
ChangeLog
18
ChangeLog
|
|
@ -1,3 +1,21 @@
|
||||||
|
2004-06-02 Adrian Dawe <adrian.dawe@multigig.com>
|
||||||
|
|
||||||
|
* src/frontend/com_dl.c src/frontend/com_dl.c src/frontend/commands.c:
|
||||||
|
Add function xaltermod
|
||||||
|
|
||||||
|
2004-06-02 Stefan Jones <stefan.jones@multigig.com>
|
||||||
|
|
||||||
|
* configure.in:
|
||||||
|
Change to version 16
|
||||||
|
Disable GnuReadline in tclspice
|
||||||
|
|
||||||
|
* src/tclspice.c:
|
||||||
|
Added trigger and step callbacks
|
||||||
|
Fix redef of sighandler_t
|
||||||
|
|
||||||
|
* src/pkgIndex.tcl.in:
|
||||||
|
set a global variable spice_version
|
||||||
|
|
||||||
2004-05-26 Stefan Jones <stefan.jones@multigig.com>
|
2004-05-26 Stefan Jones <stefan.jones@multigig.com>
|
||||||
|
|
||||||
* src/tclspice.c src/include/ngspice.h src/misc/tilde.c
|
* src/tclspice.c src/include/ngspice.h src/misc/tilde.c
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ dnl Create a configuration header
|
||||||
AM_CONFIG_HEADER(config.h)
|
AM_CONFIG_HEADER(config.h)
|
||||||
|
|
||||||
dnl Initialize automake stuff
|
dnl Initialize automake stuff
|
||||||
AM_INIT_AUTOMAKE(tclspice,0.2.15)
|
AM_INIT_AUTOMAKE(tclspice,0.2.16)
|
||||||
|
|
||||||
dnl --enable-ftedebug : enable frontend debug macros
|
dnl --enable-ftedebug : enable frontend debug macros
|
||||||
AC_ARG_ENABLE(ftedebug,
|
AC_ARG_ENABLE(ftedebug,
|
||||||
|
|
@ -435,9 +435,9 @@ if test "$enable_cluster" = "yes"; then
|
||||||
LIBS="$LIBS -lpthread"
|
LIBS="$LIBS -lpthread"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
dnl ---- Option to include GNU readline support in ngspice CLI ----
|
dnl ---- Option to include GNU readline support in ngspice CLI ----
|
||||||
if test "$with_readline" != "no"; then
|
if test "$with_readline" != "no" -a \
|
||||||
|
\( "x$with_tcl" == "x" -o "$with_tcl" == "no" \) ; then
|
||||||
AC_MSG_RESULT(Checking for readline:)
|
AC_MSG_RESULT(Checking for readline:)
|
||||||
AC_CHECK_HEADERS([readline/readline.h readline/history.h],
|
AC_CHECK_HEADERS([readline/readline.h readline/history.h],
|
||||||
[AC_DEFINE(HAVE_GNUREADLINE)],
|
[AC_DEFINE(HAVE_GNUREADLINE)],
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,18 @@
|
||||||
#include <../spicelib/devices/dev.h> /*for load library commands*/
|
#include <../spicelib/devices/dev.h> /*for load library commands*/
|
||||||
|
|
||||||
#ifdef XSPICE
|
#ifdef XSPICE
|
||||||
|
|
||||||
|
#include "mifproto.h"
|
||||||
|
#include "inpdefs.h"
|
||||||
|
#include "fteext.h"
|
||||||
|
#include "ifsim.h"
|
||||||
|
#include "dllitf.h"
|
||||||
|
#include "iferrmsg.h"
|
||||||
|
#include <iferrmsg.h>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void com_codemodel(wordlist *wl){
|
void com_codemodel(wordlist *wl){
|
||||||
wordlist *ww;
|
wordlist *ww;
|
||||||
for(ww = wl;ww;ww = ww->wl_next)
|
for(ww = wl;ww;ww = ww->wl_next)
|
||||||
|
|
@ -11,6 +23,138 @@ void com_codemodel(wordlist *wl){
|
||||||
fprintf(cp_err,"Error: Library %s couldn't be loaded!\n",ww->wl_word);
|
fprintf(cp_err,"Error: Library %s couldn't be loaded!\n",ww->wl_word);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void com_xaltermod(wordlist *wl){
|
||||||
|
wordlist *ww, *eqword, *words;
|
||||||
|
int i, err, typecode=-1;
|
||||||
|
GENinstance *devptr=(GENinstance *)NULL;
|
||||||
|
GENmodel *modptr=(GENmodel *)NULL;
|
||||||
|
IFdevice *device;
|
||||||
|
IFparm *opt;
|
||||||
|
IFvalue nval;
|
||||||
|
bool found;
|
||||||
|
char *dev, *p;
|
||||||
|
char *param;
|
||||||
|
|
||||||
|
if (!ft_curckt) {
|
||||||
|
fprintf(cp_err, "Error: no circuit loaded\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (!wl) {
|
||||||
|
fprintf(cp_err, "usage: xaltermod dev param = expression\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
words = wl;
|
||||||
|
while (words) {
|
||||||
|
p = words->wl_word;
|
||||||
|
eqword = words;
|
||||||
|
words = words->wl_next;
|
||||||
|
if (eq(p, "=")) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!words) {
|
||||||
|
fprintf(cp_err, "usage: xaltermod dev param = expression\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev = NULL;
|
||||||
|
param = NULL;
|
||||||
|
words = wl;
|
||||||
|
while (words != eqword) {
|
||||||
|
p = words->wl_word;
|
||||||
|
if (param) {
|
||||||
|
fprintf(cp_err, "Error: excess parameter name \"%s\" ignored.\n",p);
|
||||||
|
} else if (dev) {
|
||||||
|
param = words->wl_word;
|
||||||
|
} else {
|
||||||
|
dev = p;
|
||||||
|
}
|
||||||
|
words = words->wl_next;
|
||||||
|
}
|
||||||
|
if (!dev) {
|
||||||
|
fprintf(cp_err, "Error: no model name provided.\n" );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
words = eqword->wl_next;
|
||||||
|
|
||||||
|
INPretrieve(&dev,(INPtables *)ft_curckt->ci_symtab);
|
||||||
|
|
||||||
|
err = (*(ft_sim->findInstance))(ft_curckt->ci_ckt,&typecode,(void **)&devptr,dev,NULL,NULL);
|
||||||
|
|
||||||
|
if (err != OK) {
|
||||||
|
typecode = -1;
|
||||||
|
devptr = (void *)NULL;
|
||||||
|
err = (*(ft_sim->findModel))(ft_curckt->ci_ckt,&typecode,(void **)&modptr,dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (err != OK) {
|
||||||
|
printf("Error: no such model '%s'.\n",dev);
|
||||||
|
printf(" use spice::showmod all, to display all models\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
device = ft_sim->devices[typecode];
|
||||||
|
found = FALSE;
|
||||||
|
|
||||||
|
int id;
|
||||||
|
int numParams =0;
|
||||||
|
|
||||||
|
for(ww = words;ww;ww = ww->wl_next)
|
||||||
|
numParams ++;
|
||||||
|
|
||||||
|
for (i = 0; i < *(device->numModelParms); i++) {
|
||||||
|
opt = &device->modelParms[i];
|
||||||
|
|
||||||
|
if (strcmp(opt->keyword,param) == 0) {
|
||||||
|
id = opt->id;
|
||||||
|
nval.v.numValue = 0;
|
||||||
|
|
||||||
|
if (opt->dataType & IF_VECTOR) {
|
||||||
|
switch (opt->dataType & (IF_VARTYPES & ~IF_VECTOR))
|
||||||
|
{
|
||||||
|
case IF_STRING:
|
||||||
|
found = TRUE;
|
||||||
|
nval.v.vec.sVec = malloc((numParams +1) * sizeof(char *));
|
||||||
|
for(ww = words;ww;ww = ww->wl_next) {
|
||||||
|
nval.v.vec.sVec[nval.v.numValue] = ww->wl_word;
|
||||||
|
nval.v.numValue++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
printf("Error: xaltermod only supports vectors of strings.\n");
|
||||||
|
printf(" use spice::altermod\n");
|
||||||
|
return;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
printf("Error: xaltermod only supports vectors of strings.\n");
|
||||||
|
printf(" use spice::altermod\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (found == FALSE) {
|
||||||
|
printf("Error: no parameter '%s' in model '%s'.\n", param, dev);
|
||||||
|
printf(" use spice::showmod all, to list all model parameters\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = (*(ft_sim->setModelParm))((void *)ft_curckt->ci_ckt, (void *)modptr,
|
||||||
|
id, &nval, (IFvalue *)NULL);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
#ifdef DEVLIB
|
#ifdef DEVLIB
|
||||||
void com_use(wordlist *wl){
|
void com_use(wordlist *wl){
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
#ifdef XSPICE
|
#ifdef XSPICE
|
||||||
void com_codemodel(wordlist *wl);
|
void com_codemodel(wordlist *wl);
|
||||||
|
void com_xaltermod(wordlist *wl);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef DEVLIB
|
#ifdef DEVLIB
|
||||||
|
|
|
||||||
|
|
@ -184,6 +184,11 @@ struct comm spcp_coms[] = {
|
||||||
{ 040000, 040000, 040000, 040000 }, E_BEGINNING, 1, LOTS,
|
{ 040000, 040000, 040000, 040000 }, E_BEGINNING, 1, LOTS,
|
||||||
(void (*)()) NULL,
|
(void (*)()) NULL,
|
||||||
"library library ... : Loads the opus librarys." } ,
|
"library library ... : Loads the opus librarys." } ,
|
||||||
|
{ "xaltermod", com_xaltermod, FALSE, FALSE, TRUE,
|
||||||
|
{ 040000, 040000, 040000, 040000 }, E_BEGINNING, 1, LOTS,
|
||||||
|
(void (*)()) NULL,
|
||||||
|
"library library ... : Loads the opus librarys." } ,
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
#ifdef DEVLIB
|
#ifdef DEVLIB
|
||||||
{ "use", com_use, FALSE, FALSE, TRUE,
|
{ "use", com_use, FALSE, FALSE, TRUE,
|
||||||
|
|
|
||||||
|
|
@ -79,6 +79,7 @@ proc Loadspice { version dir } {
|
||||||
spicewish::init_gui $spicefile
|
spicewish::init_gui $spicefile
|
||||||
}
|
}
|
||||||
|
|
||||||
|
set ::spice_version $version
|
||||||
}
|
}
|
||||||
|
|
||||||
proc q { } { exit }
|
proc q { } { exit }
|
||||||
|
|
|
||||||
296
src/tclspice.c
296
src/tclspice.c
|
|
@ -53,9 +53,8 @@
|
||||||
|
|
||||||
/* To interupt a spice run */
|
/* To interupt a spice run */
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#ifndef sighandler_t
|
typedef void (*sighandler)(int);
|
||||||
typedef void (*sighandler_t)(int);
|
|
||||||
#endif
|
|
||||||
#include <setjmp.h>
|
#include <setjmp.h>
|
||||||
extern sigjmp_buf jbuf;
|
extern sigjmp_buf jbuf;
|
||||||
|
|
||||||
|
|
@ -109,14 +108,14 @@ typedef struct {
|
||||||
} vector;
|
} vector;
|
||||||
|
|
||||||
/*The current run (to get variable names, etc)*/
|
/*The current run (to get variable names, etc)*/
|
||||||
static runDesc *cur_run = NULL;
|
static runDesc *cur_run;
|
||||||
|
|
||||||
static vector *vectors = NULL;
|
static vector *vectors;
|
||||||
|
|
||||||
static int ownVectors = 0;
|
static int ownVectors;
|
||||||
|
|
||||||
/* save this each time called */
|
/* save this each time called */
|
||||||
static Tcl_Interp *spice_interp=NULL;
|
static Tcl_Interp *spice_interp;
|
||||||
#define save_interp() \
|
#define save_interp() \
|
||||||
do {\
|
do {\
|
||||||
spice_interp = interp;\
|
spice_interp = interp;\
|
||||||
|
|
@ -127,9 +126,9 @@ do {\
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
/*this holds the number of time points done (altered by spice)*/
|
/*this holds the number of time points done (altered by spice)*/
|
||||||
int steps_completed = 0;
|
int steps_completed;
|
||||||
/* number of bltvectors*/
|
/* number of bltvectors*/
|
||||||
static int blt_vnum = 0;
|
static int blt_vnum;
|
||||||
|
|
||||||
|
|
||||||
/*Native Tcl functions */
|
/*Native Tcl functions */
|
||||||
|
|
@ -303,6 +302,55 @@ static int lastVector TCL_CMDPROCARGS(clientData,interp,argc,argv) {
|
||||||
return TCL_OK;
|
return TCL_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*agr1: spice variable name
|
||||||
|
*arg2: index
|
||||||
|
*/
|
||||||
|
static int get_value TCL_CMDPROCARGS(clientData,interp,argc,argv) {
|
||||||
|
char *var;
|
||||||
|
int i, vindex, j;
|
||||||
|
double val=0;
|
||||||
|
if(argc != 3) {
|
||||||
|
Tcl_SetResult(interp,
|
||||||
|
"Wrong # args. spice::get_value spice_variable index",
|
||||||
|
TCL_STATIC);
|
||||||
|
return TCL_ERROR;
|
||||||
|
}
|
||||||
|
var = (char *)argv[1];
|
||||||
|
|
||||||
|
for(i=0;i < blt_vnum && strcmp(var,vectors[i].name);i++);
|
||||||
|
|
||||||
|
if(i == blt_vnum) {
|
||||||
|
Tcl_SetResult(interp, "Bad spice variable ",TCL_STATIC);
|
||||||
|
Tcl_AppendResult(interp, (char *)var, TCL_STATIC);
|
||||||
|
return TCL_ERROR;
|
||||||
|
} else vindex = i;
|
||||||
|
|
||||||
|
j = atoi(argv[2]);
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBPTHREAD
|
||||||
|
pthread_mutex_lock(&vectors[vindex].mutex);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if(j < 0 || j >= vectors[vindex].length) {
|
||||||
|
i = 1;
|
||||||
|
} else {
|
||||||
|
i = 0;
|
||||||
|
val = vectors[vindex].data[j];
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBPTHREAD
|
||||||
|
pthread_mutex_unlock(&vectors[vindex].mutex);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if(i) {
|
||||||
|
Tcl_SetResult(interp, "Index out of range",TCL_STATIC);
|
||||||
|
return TCL_ERROR;
|
||||||
|
} else {
|
||||||
|
Tcl_SetObjResult(interp,Tcl_NewDoubleObj(val));
|
||||||
|
return TCL_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*agr1: spice variable name
|
/*agr1: spice variable name
|
||||||
*arg2: blt_vector
|
*arg2: blt_vector
|
||||||
*arg3: start copy index, optional
|
*arg3: start copy index, optional
|
||||||
|
|
@ -310,7 +358,7 @@ static int lastVector TCL_CMDPROCARGS(clientData,interp,argc,argv) {
|
||||||
*/
|
*/
|
||||||
static int spicetoblt TCL_CMDPROCARGS(clientData,interp,argc,argv) {
|
static int spicetoblt TCL_CMDPROCARGS(clientData,interp,argc,argv) {
|
||||||
Blt_Vector *vec;
|
Blt_Vector *vec;
|
||||||
int index, i;
|
int j, i;
|
||||||
char *blt, *var;
|
char *blt, *var;
|
||||||
int start=0,end=-1,len;
|
int start=0,end=-1,len;
|
||||||
|
|
||||||
|
|
@ -328,7 +376,7 @@ static int spicetoblt TCL_CMDPROCARGS(clientData,interp,argc,argv) {
|
||||||
Tcl_SetResult(interp, "Bad spice variable ",TCL_STATIC);
|
Tcl_SetResult(interp, "Bad spice variable ",TCL_STATIC);
|
||||||
Tcl_AppendResult(interp, (char *)var, TCL_STATIC);
|
Tcl_AppendResult(interp, (char *)var, TCL_STATIC);
|
||||||
return TCL_ERROR;
|
return TCL_ERROR;
|
||||||
} else index = i;
|
} else j = i;
|
||||||
|
|
||||||
if(Blt_GetVector(interp,blt,&vec)){
|
if(Blt_GetVector(interp,blt,&vec)){
|
||||||
Tcl_SetResult(interp, "Bad blt vector ",TCL_STATIC);
|
Tcl_SetResult(interp, "Bad blt vector ",TCL_STATIC);
|
||||||
|
|
@ -341,12 +389,12 @@ static int spicetoblt TCL_CMDPROCARGS(clientData,interp,argc,argv) {
|
||||||
start = atoi(argv[3]);
|
start = atoi(argv[3]);
|
||||||
if(argc == 5)
|
if(argc == 5)
|
||||||
end = atoi(argv[4]);
|
end = atoi(argv[4]);
|
||||||
if(vectors[index].length) {
|
if(vectors[j].length) {
|
||||||
#ifdef HAVE_LIBPTHREAD
|
#ifdef HAVE_LIBPTHREAD
|
||||||
pthread_mutex_lock(&vectors[index].mutex);
|
pthread_mutex_lock(&vectors[j].mutex);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
len = vectors[index].length;
|
len = vectors[j].length;
|
||||||
|
|
||||||
if(start){
|
if(start){
|
||||||
start = start % len;
|
start = start % len;
|
||||||
|
|
@ -360,11 +408,11 @@ static int spicetoblt TCL_CMDPROCARGS(clientData,interp,argc,argv) {
|
||||||
|
|
||||||
len = abs(end - start + 1);
|
len = abs(end - start + 1);
|
||||||
|
|
||||||
Blt_ResetVector(vec,(vectors[index].data + start),len,
|
Blt_ResetVector(vec,(vectors[j].data + start),len,
|
||||||
len,TCL_VOLATILE);
|
len,TCL_VOLATILE);
|
||||||
|
|
||||||
#ifdef HAVE_LIBPTHREAD
|
#ifdef HAVE_LIBPTHREAD
|
||||||
pthread_mutex_unlock(&vectors[index].mutex);
|
pthread_mutex_unlock(&vectors[j].mutex);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
return TCL_OK;
|
return TCL_OK;
|
||||||
|
|
@ -422,7 +470,7 @@ static int _thread_stop(){
|
||||||
static int _run(int argc,char **argv){
|
static int _run(int argc,char **argv){
|
||||||
char buf[1024] = "";
|
char buf[1024] = "";
|
||||||
int i;
|
int i;
|
||||||
sighandler_t oldHandler;
|
sighandler oldHandler;
|
||||||
#ifdef HAVE_LIBPTHREAD
|
#ifdef HAVE_LIBPTHREAD
|
||||||
char *string;
|
char *string;
|
||||||
bool fl_bg = FALSE;
|
bool fl_bg = FALSE;
|
||||||
|
|
@ -1146,8 +1194,8 @@ struct triggerEvent {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
struct triggerEvent *eventQueue=NULL;
|
struct triggerEvent *eventQueue;
|
||||||
struct triggerEvent *eventQueueEnd=NULL;
|
struct triggerEvent *eventQueueEnd;
|
||||||
|
|
||||||
#ifdef HAVE_LIBPTHREAD
|
#ifdef HAVE_LIBPTHREAD
|
||||||
pthread_mutex_t triggerMutex;
|
pthread_mutex_t triggerMutex;
|
||||||
|
|
@ -1166,7 +1214,103 @@ struct watch {
|
||||||
double oV;
|
double oV;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct watch *watches=NULL;
|
struct watch *watches;
|
||||||
|
|
||||||
|
char *triggerCallback;
|
||||||
|
unsigned int triggerPollTime=1;
|
||||||
|
|
||||||
|
char *stepCallback;
|
||||||
|
unsigned int stepPollTime=1;
|
||||||
|
unsigned int stepCount=1;
|
||||||
|
int stepCallbackPending;
|
||||||
|
|
||||||
|
void stepEventSetup(ClientData clientData,int flags) {
|
||||||
|
Tcl_Time t;
|
||||||
|
if(stepCallbackPending) {
|
||||||
|
t.sec = 0;
|
||||||
|
t.usec = 0;
|
||||||
|
} else {
|
||||||
|
t.sec = stepPollTime / 1000;
|
||||||
|
t.usec = (stepPollTime % 1000) * 1000;
|
||||||
|
}
|
||||||
|
Tcl_SetMaxBlockTime(&t);
|
||||||
|
}
|
||||||
|
|
||||||
|
int stepEventHandler(Tcl_Event *evPtr, int flags) {
|
||||||
|
if(stepCallbackPending) {
|
||||||
|
stepCallbackPending = 0;
|
||||||
|
Tcl_Preserve((ClientData)spice_interp);
|
||||||
|
Tcl_Eval(spice_interp,stepCallback);
|
||||||
|
Tcl_ResetResult(spice_interp);
|
||||||
|
Tcl_Release((ClientData)spice_interp);
|
||||||
|
}
|
||||||
|
return TCL_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void stepEventCheck(ClientData clientData,int flags) {
|
||||||
|
if(stepCallbackPending) {
|
||||||
|
Tcl_Event *tclEvent;
|
||||||
|
tclEvent = (Tcl_Event *) ckalloc(sizeof(Tcl_Event));
|
||||||
|
tclEvent->proc = stepEventHandler;
|
||||||
|
Tcl_QueueEvent(tclEvent,TCL_QUEUE_TAIL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int triggerEventHandler(Tcl_Event *evPtr, int flags) {
|
||||||
|
static char buf[512];
|
||||||
|
int rtn=TCL_OK;
|
||||||
|
Tcl_Preserve((ClientData)spice_interp);
|
||||||
|
#ifdef HAVE_LIBPTHREAD
|
||||||
|
pthread_mutex_lock(&triggerMutex);
|
||||||
|
#endif
|
||||||
|
while(eventQueue) {
|
||||||
|
struct triggerEvent *event = eventQueue;
|
||||||
|
eventQueue = eventQueue->next;
|
||||||
|
|
||||||
|
snprintf(buf,512,"%s %s %g %d %d",triggerCallback,vectors[event->vector].name,
|
||||||
|
event->time,event->stepNumber,event->type);
|
||||||
|
rtn = Tcl_Eval(spice_interp,buf);
|
||||||
|
FREE(event);
|
||||||
|
if(rtn) {
|
||||||
|
goto quit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
eventQueueEnd = NULL;
|
||||||
|
quit:
|
||||||
|
#ifdef HAVE_LIBPTHREAD
|
||||||
|
pthread_mutex_unlock(&triggerMutex);
|
||||||
|
#endif
|
||||||
|
Tcl_ResetResult(spice_interp);
|
||||||
|
Tcl_Release((ClientData)spice_interp);
|
||||||
|
return TCL_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void triggerEventSetup(ClientData clientData,int flags) {
|
||||||
|
Tcl_Time t;
|
||||||
|
if(eventQueue) {
|
||||||
|
t.sec = 0;
|
||||||
|
t.usec = 0;
|
||||||
|
} else {
|
||||||
|
t.sec = triggerPollTime / 1000;
|
||||||
|
t.usec = (triggerPollTime % 1000) * 1000;
|
||||||
|
}
|
||||||
|
Tcl_SetMaxBlockTime(&t);
|
||||||
|
}
|
||||||
|
|
||||||
|
void triggerEventCheck(ClientData clientData,int flags) {
|
||||||
|
#ifdef HAVE_LIBPTHREAD
|
||||||
|
pthread_mutex_lock(&triggerMutex);
|
||||||
|
#endif
|
||||||
|
if(eventQueue) {
|
||||||
|
Tcl_Event *tclEvent;
|
||||||
|
tclEvent = (Tcl_Event *) ckalloc(sizeof(Tcl_Event));
|
||||||
|
tclEvent->proc = triggerEventHandler;
|
||||||
|
Tcl_QueueEvent(tclEvent,TCL_QUEUE_TAIL);
|
||||||
|
}
|
||||||
|
#ifdef HAVE_LIBPTHREAD
|
||||||
|
pthread_mutex_unlock(&triggerMutex);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
int Tcl_ExecutePerLoop() {
|
int Tcl_ExecutePerLoop() {
|
||||||
|
|
||||||
|
|
@ -1225,12 +1369,32 @@ int Tcl_ExecutePerLoop() {
|
||||||
pthread_mutex_unlock(&v->mutex);
|
pthread_mutex_unlock(&v->mutex);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(stepCallback && vectors[0].length % stepCount == 0) {
|
||||||
|
stepCallbackPending=1;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef HAVE_LIBPTHREAD
|
#ifdef HAVE_LIBPTHREAD
|
||||||
pthread_mutex_unlock(&triggerMutex);
|
pthread_mutex_unlock(&triggerMutex);
|
||||||
|
|
||||||
pthread_mutex_unlock(&vectors[0].mutex);
|
pthread_mutex_unlock(&vectors[0].mutex);
|
||||||
|
|
||||||
|
if(triggerCallback && eventQueue && bgtid != pthread_self()) {
|
||||||
|
triggerEventHandler(NULL,0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(stepCallback && stepCallbackPending && bgtid != pthread_self()) {
|
||||||
|
stepEventHandler(NULL,0);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if(triggerCallback && eventQueue) {
|
||||||
|
triggerEventHandler(NULL,0);
|
||||||
|
}
|
||||||
|
if(stepCallback && stepCallbackPending) {
|
||||||
|
triggerEventHandler(NULL,0);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -1261,6 +1425,83 @@ static int resetTriggers() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Registers a watch for a trigger
|
||||||
|
*arg0: Callback function (optional - none removes callback)
|
||||||
|
*arg1: Poll interval usec (optional - defaults to 500000 )
|
||||||
|
*/
|
||||||
|
static int registerTriggerCallback TCL_CMDPROCARGS(clientData,interp,argc,argv){
|
||||||
|
|
||||||
|
if (argc > 3) {
|
||||||
|
Tcl_SetResult(interp,
|
||||||
|
"Wrong # args. spice::registerTriggerCallback ?proc? ?ms?",
|
||||||
|
TCL_STATIC);
|
||||||
|
return TCL_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(triggerCallback) {
|
||||||
|
Tcl_DeleteEventSource(triggerEventSetup,triggerEventCheck,NULL);
|
||||||
|
free(triggerCallback);
|
||||||
|
triggerCallback = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(argc == 1) {
|
||||||
|
return TCL_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
triggerCallback = strdup(argv[1]);
|
||||||
|
Tcl_CreateEventSource(triggerEventSetup,triggerEventCheck,NULL);
|
||||||
|
|
||||||
|
if(argc == 3) {
|
||||||
|
triggerPollTime = atoi(argv[2]);
|
||||||
|
if(triggerPollTime == 0)
|
||||||
|
triggerPollTime = 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TCL_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Registers step counter callback
|
||||||
|
*arg0: Callback function (optional - none removes callback)
|
||||||
|
*arg1: Number of steps per Callback
|
||||||
|
*arg2: Poll interval usec (optional - defaults to 500000 )
|
||||||
|
*/
|
||||||
|
static int registerStepCallback TCL_CMDPROCARGS(clientData,interp,argc,argv){
|
||||||
|
|
||||||
|
if (argc > 4) {
|
||||||
|
Tcl_SetResult(interp,
|
||||||
|
"Wrong # args. spice::registerStepCallback ?proc? ?steps? ?ms?",
|
||||||
|
TCL_STATIC);
|
||||||
|
return TCL_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(stepCallback) {
|
||||||
|
Tcl_DeleteEventSource(stepEventSetup,stepEventCheck,NULL);
|
||||||
|
free(stepCallback);
|
||||||
|
stepCallback = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(argc == 1) {
|
||||||
|
return TCL_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
stepCallback = strdup(argv[1]);
|
||||||
|
Tcl_CreateEventSource(stepEventSetup,stepEventCheck,NULL);
|
||||||
|
|
||||||
|
if(argc >= 3) {
|
||||||
|
stepCount = atoi(argv[2]);
|
||||||
|
if(stepCount == 0)
|
||||||
|
stepCount = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(argc == 4) {
|
||||||
|
stepPollTime = atoi(argv[3]);
|
||||||
|
if(stepPollTime == 0)
|
||||||
|
stepPollTime = 50;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TCL_OK;
|
||||||
|
}
|
||||||
|
|
||||||
/* Registers a watch for a trigger
|
/* Registers a watch for a trigger
|
||||||
*arg0: Vector Name to watch
|
*arg0: Vector Name to watch
|
||||||
*arg1: Vmin
|
*arg1: Vmin
|
||||||
|
|
@ -1390,7 +1631,8 @@ static int popTriggerEvent TCL_CMDPROCARGS(clientData,interp,argc,argv){
|
||||||
popedEvent = eventQueue;
|
popedEvent = eventQueue;
|
||||||
|
|
||||||
eventQueue = popedEvent->next;
|
eventQueue = popedEvent->next;
|
||||||
|
if(eventQueue == NULL)
|
||||||
|
eventQueueEnd = NULL;
|
||||||
|
|
||||||
list = Tcl_NewListObj(0,NULL);
|
list = Tcl_NewListObj(0,NULL);
|
||||||
|
|
||||||
|
|
@ -1470,7 +1712,7 @@ int Spice_Init(Tcl_Interp *interp) {
|
||||||
char *key;
|
char *key;
|
||||||
Tcl_CmdInfo infoPtr;
|
Tcl_CmdInfo infoPtr;
|
||||||
char buf[256];
|
char buf[256];
|
||||||
sighandler_t old_sigint;
|
sighandler old_sigint;
|
||||||
|
|
||||||
ft_rawfile = NULL;
|
ft_rawfile = NULL;
|
||||||
ivars( );
|
ivars( );
|
||||||
|
|
@ -1563,6 +1805,7 @@ bot:
|
||||||
Tcl_CreateCommand(interp, TCLSPICE_prefix "spice_data", spice_data, (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);
|
Tcl_CreateCommand(interp, TCLSPICE_prefix "spice_data", spice_data, (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);
|
||||||
Tcl_CreateCommand(interp, TCLSPICE_prefix "spicetoblt", spicetoblt, (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);
|
Tcl_CreateCommand(interp, TCLSPICE_prefix "spicetoblt", spicetoblt, (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);
|
||||||
Tcl_CreateCommand(interp, TCLSPICE_prefix "lastVector", lastVector, (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);
|
Tcl_CreateCommand(interp, TCLSPICE_prefix "lastVector", lastVector, (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);
|
||||||
|
Tcl_CreateCommand(interp, TCLSPICE_prefix "get_value", get_value, (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);
|
||||||
Tcl_CreateCommand(interp, TCLSPICE_prefix "spice", _spice_dispatch, (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);
|
Tcl_CreateCommand(interp, TCLSPICE_prefix "spice", _spice_dispatch, (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);
|
||||||
Tcl_CreateCommand(interp, TCLSPICE_prefix "get_output", get_output, (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);
|
Tcl_CreateCommand(interp, TCLSPICE_prefix "get_output", get_output, (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);
|
||||||
Tcl_CreateCommand(interp, TCLSPICE_prefix "get_param", get_param, (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);
|
Tcl_CreateCommand(interp, TCLSPICE_prefix "get_param", get_param, (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);
|
||||||
|
|
@ -1576,16 +1819,21 @@ bot:
|
||||||
Tcl_CreateCommand(interp, TCLSPICE_prefix "plot_date", plot_date, (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);
|
Tcl_CreateCommand(interp, TCLSPICE_prefix "plot_date", plot_date, (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);
|
||||||
Tcl_CreateCommand(interp, TCLSPICE_prefix "plot_name", plot_name, (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);
|
Tcl_CreateCommand(interp, TCLSPICE_prefix "plot_name", plot_name, (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);
|
||||||
Tcl_CreateCommand(interp, TCLSPICE_prefix "plot_nvars", plot_nvars, (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);
|
Tcl_CreateCommand(interp, TCLSPICE_prefix "plot_nvars", plot_nvars, (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);
|
||||||
Tcl_CreateCommand(interp, TCLSPICE_prefix "registerTrigger", registerTrigger, (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);
|
|
||||||
Tcl_CreateCommand(interp, TCLSPICE_prefix "popTriggerEvent", popTriggerEvent, (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);
|
Tcl_CreateCommand(interp, TCLSPICE_prefix "registerTrigger", registerTrigger, (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);
|
||||||
|
Tcl_CreateCommand(interp, TCLSPICE_prefix "registerTriggerCallback", registerTriggerCallback, (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);
|
||||||
|
Tcl_CreateCommand(interp, TCLSPICE_prefix "popTriggerEvent", popTriggerEvent, (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);
|
||||||
Tcl_CreateCommand(interp, TCLSPICE_prefix "unregisterTrigger", unregisterTrigger, (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);
|
Tcl_CreateCommand(interp, TCLSPICE_prefix "unregisterTrigger", unregisterTrigger, (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);
|
||||||
Tcl_CreateCommand(interp, TCLSPICE_prefix "listTriggers", listTriggers, (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);
|
Tcl_CreateCommand(interp, TCLSPICE_prefix "listTriggers", listTriggers, (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);
|
||||||
|
|
||||||
|
Tcl_CreateCommand(interp, TCLSPICE_prefix "registerStepCallback", registerTriggerCallback, (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);
|
||||||
#ifdef HAVE_LIBPTHREAD
|
#ifdef HAVE_LIBPTHREAD
|
||||||
Tcl_CreateCommand(interp, TCLSPICE_prefix "bg", _tcl_dispatch, (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);
|
Tcl_CreateCommand(interp, TCLSPICE_prefix "bg", _tcl_dispatch, (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);
|
||||||
Tcl_CreateCommand(interp, TCLSPICE_prefix "halt", _tcl_dispatch, (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);
|
Tcl_CreateCommand(interp, TCLSPICE_prefix "halt", _tcl_dispatch, (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);
|
||||||
Tcl_CreateCommand(interp, TCLSPICE_prefix "running", running, (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);
|
Tcl_CreateCommand(interp, TCLSPICE_prefix "running", running, (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
Tcl_CreateCommand(interp, TCLSPICE_prefix "registerStepCallback", registerStepCallback, (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);
|
||||||
|
|
||||||
Tcl_LinkVar(interp, TCLSPICE_prefix "steps_completed", (char *)&steps_completed, TCL_LINK_READ_ONLY|TCL_LINK_INT);
|
Tcl_LinkVar(interp, TCLSPICE_prefix "steps_completed", (char *)&steps_completed, TCL_LINK_READ_ONLY|TCL_LINK_INT);
|
||||||
Tcl_LinkVar(interp, TCLSPICE_prefix "blt_vnum", (char *)&blt_vnum, TCL_LINK_READ_ONLY|TCL_LINK_INT);
|
Tcl_LinkVar(interp, TCLSPICE_prefix "blt_vnum", (char *)&blt_vnum, TCL_LINK_READ_ONLY|TCL_LINK_INT);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue