From 16aadef4c7794d8360ece50d0d23e65b89d00843 Mon Sep 17 00:00:00 2001 From: Giles Atkinson <“gatk555@gmail.com”> Date: Tue, 25 Mar 2025 17:50:24 +0000 Subject: [PATCH] Add two new functions to the shared library API. ngSpice_Raw_Evt() requests a callback that returns all the XSPICE events for a specific node that occurred during the last timestep. ngSpice_Decode_Evt() provides numeric and string versions of the event data. Also fix some warnings in sharedspice.c. --- src/include/ngspice/evtproto.h | 12 +++--- src/include/ngspice/sharedspice.h | 38 +++++++++++++++++++ src/sharedspice.c | 63 ++++++++++++++++++++++++++----- src/xspice/evt/evtplot.c | 1 + 4 files changed, 100 insertions(+), 14 deletions(-) diff --git a/src/include/ngspice/evtproto.h b/src/include/ngspice/evtproto.h index 033db4226..1ec0e3228 100644 --- a/src/include/ngspice/evtproto.h +++ b/src/include/ngspice/evtproto.h @@ -148,16 +148,18 @@ void EVTcancel_value_call(const char *node, Evt_New_Value_Cb_t fn, void *ctx); -/* Internal utility functions. */ - -void Evt_purge_free_outputs(void); - -/* Parse a node name with member and find the node index. */ +/* Parse a node name with member and return the node index and type. */ struct node_parse { char *node; char *member; + int udn_index; }; int Evt_Parse_Node(const char *node, struct node_parse *result); + +/* Internal utility functions. */ + +void Evt_purge_free_outputs(void); + #endif diff --git a/src/include/ngspice/sharedspice.h b/src/include/ngspice/sharedspice.h index a65501384..c625de068 100644 --- a/src/include/ngspice/sharedspice.h +++ b/src/include/ngspice/sharedspice.h @@ -357,6 +357,18 @@ typedef int (SendInitEvtData)(int, int, char*, char*, int, void*); int identification number of calling ngspice shared lib void* return pointer received from caller */ + +/* Upon time step finished, all events that occurred on a node. + * A non-zero return value cancels further reports for tis node. + */ + +typedef int (SendRawEvtData)(double, void *, void *, int); +/* + double event time + void* pointer to the node's value (a Digital_t for digital nodes) + void* return pointer received from caller + int zero if another event report for the same node follows +*/ #endif /* ngspice initialization, @@ -415,6 +427,32 @@ userData: pointer to user-defined data, will not be modified, but handed over back to caller during Callback, e.g. address of calling object */ IMPEXP int ngSpice_Init_Evt(SendEvtData* sevtdata, SendInitEvtData* sinitevtdata, void* userData); + +/* Request callback for every event on a specific XSPICE event node. + * A single callback function pointer is stored, with all calls directed + * to the function specified last. + * The return value identifies the node data type or is -1 on error. + * + * node name of an event node. + * srawevt pointer to callback function. + * userData pointer to user-defined data. + */ + +IMPEXP +int ngSpice_Raw_Evt(const char* node, SendRawEvtData* srawevt, void* userData); + +/* Decode raw event node data. Return 0 on success. + * evt pointer to event data (a reported node value). + * type node type index, return value from ngSpice_Raw_Evt(). + * pplotval pointer to a double, the "plotting value" is returned. NULL OK. + * printval pointer to a char pointer that is updated to point to a + * readonly string describing the value. If evt is NULL, a string + * identifying the node data type is returned. NULL is OK. + */ + +IMPEXP +int ngSpice_Decode_Evt(void* evt, int type, + double *pplotval, const char **pprintval); #endif diff --git a/src/sharedspice.c b/src/sharedspice.c index f48d96323..059e4a3e2 100644 --- a/src/sharedspice.c +++ b/src/sharedspice.c @@ -182,6 +182,8 @@ typedef void (*sighandler)(int); #ifdef XSPICE #include "ngspice/evtshared.h" +#include "ngspice/evtproto.h" +#include "ngspice/evtudn.h" extern bool wantevtdata; #endif @@ -222,7 +224,7 @@ extern struct comm spcp_coms[]; struct comm* cp_coms = spcp_coms; /* Main options */ -static bool ft_servermode = FALSE; + bool ft_batchmode = FALSE; bool ft_pipemode = FALSE; bool rflag = FALSE; /* has rawfile */ @@ -341,6 +343,8 @@ void sh_delete_myvec(void); #ifdef XSPICE void shared_send_event(int, double, double, char *, void *, int, int); void shared_send_dict(int, int, char*, char*); + +static int evt_shim(double time, Mif_Value_t *vp, void *ctx, int last); #endif #if !defined(low_latency) @@ -397,6 +401,7 @@ static int intermj = 1; #ifdef XSPICE static SendInitEvtData* sendinitevt; static SendEvtData* sendevt; +static SendRawEvtData *sendrawevt; #endif static void* euserptr; static wordlist *shcontrols; @@ -1387,6 +1392,41 @@ int ngSpice_Init_Evt(SendEvtData* sevtdata, SendInitEvtData* sinitevtdata, void return(TRUE); } +/* Set callback address for raw XSPICE events. + * The return value identifies the node data type or is -1 on error. + */ + +IMPEXP +int ngSpice_Raw_Evt(const char* node, SendRawEvtData* srawevt, void* userData) +{ + struct node_parse np; + + if (Evt_Parse_Node(node, &np) < 0 || np.member) + return -1; // Invalid node name. + sendrawevt = srawevt; + EVTnew_value_call(node, evt_shim, Evt_Cbt_Raw, userData); + return np.udn_index; +} + +IMPEXP +int ngSpice_Decode_Evt(void* evt, int type, + double *pplotval, const char **ppprintval) +{ + if (type >= g_evt_num_udn_types) + return 1; + if (!evt) { + if (!ppprintval) + return 2; + *ppprintval = g_evt_udn_info[type]->name; + return 0; + } + if (pplotval) + g_evt_udn_info[type]->plot_val(evt, "", pplotval); + if (ppprintval) + g_evt_udn_info[type]->print_val(evt, "", (char **)ppprintval); + return 0; +} + /* Get info about the event node vector. If node_name is NULL, just delete previous data */ IMPEXP @@ -1467,7 +1507,7 @@ sh_vfprintf(FILE *f, const char *fmt, va_list args) { char buf[1024]; char *p/*, *s*/; - int nchars, /*escapes,*/ result; + int nchars; size_t size; @@ -1547,7 +1587,7 @@ sh_vfprintf(FILE *f, const char *fmt, va_list args) Spice_Init() from caller of ngspice.dll */ - result = sh_fputs(p, f); + sh_fputs(p, f); if (p != buf) tfree(p); @@ -1929,7 +1969,6 @@ void SetAnalyse( || defined (HAVE_FTIME) PerfTime timenow; /* actual time stamp */ int diffsec, diffmillisec; /* differences actual minus prev. time stamp */ - int result; /* return value from callback function */ char* s; /* outputs to callback function */ int OldPercent; /* Previous progress value */ char OldAn[128]; /* Previous analysis type */ @@ -1994,7 +2033,7 @@ void SetAnalyse( if (!strcmp(Analyse, "tran")) { if (ckt && (ckt->CKTtime > ckt->CKTfinalTime - ckt->CKTmaxStep)) { sprintf(s, "--ready--"); - result = statfcn(s, ng_ident, userptr); + statfcn(s, ng_ident, userptr); tfree(s); return; } @@ -2007,7 +2046,7 @@ void SetAnalyse( return; } sprintf( s, "--ready--"); - result = statfcn(s, ng_ident, userptr); + statfcn(s, ng_ident, userptr); tfree(s); return; } @@ -2056,7 +2095,7 @@ void SetAnalyse( } /* ouput only after a change */ if (strcmp(olds, s)) - result = statfcn(s, ng_ident, userptr); + statfcn(s, ng_ident, userptr); if(thread1) strcpy(olds1, s); else @@ -2065,11 +2104,10 @@ void SetAnalyse( tfree(s); #else char* s; - int result; static bool havesent = FALSE; if (!havesent) { s = copy("No usage info available"); - result = statfcn(s, ng_ident, userptr); + statfcn(s, ng_ident, userptr); tfree(s); havesent = TRUE; } @@ -2460,6 +2498,13 @@ void shared_send_dict(int index, int no_of_nodes, char* name, char*type) if (sendinitevt) sendinitevt(index, no_of_nodes, name, type, ng_ident, euserptr); } + +static int evt_shim(double time, Mif_Value_t *vp, void *ctx, int last) +{ + if (sendrawevt) + return sendrawevt(time, vp->pvalue, ctx, last); // Strip Mif_value. + return 1; +} #endif static int totalreset(void) diff --git a/src/xspice/evt/evtplot.c b/src/xspice/evt/evtplot.c index d0e272496..eca87aec5 100644 --- a/src/xspice/evt/evtplot.c +++ b/src/xspice/evt/evtplot.c @@ -114,6 +114,7 @@ int Evt_Parse_Node(const char *node, struct node_parse *result) tfree(name); return -1; } + result->udn_index = node_table[i]->udn_index; return i; }