evtdump.c, prepare data gathering for callbacks similar to sending data via the ancient ipc channel
This commit is contained in:
parent
b621875abf
commit
3e52cdd8c1
|
|
@ -231,6 +231,7 @@ static bool immediate = FALSE;
|
|||
static bool coquit = FALSE;
|
||||
static jmp_buf errbufm, errbufc;
|
||||
static int intermj = 1;
|
||||
bool wantevtdata = FALSE;
|
||||
|
||||
|
||||
// thread IDs
|
||||
|
|
@ -968,6 +969,8 @@ bool ngSpice_SetBkpt(double time)
|
|||
IMPEXP
|
||||
int ngSpice_Init_Evt(SendEvtData* sevtdata, SendInitEvtData* sinitevtdata, void* userData)
|
||||
{
|
||||
if (sevtdata)
|
||||
wantevtdata = TRUE;
|
||||
}
|
||||
|
||||
/* Get info about the event node vector.
|
||||
|
|
@ -1933,3 +1936,7 @@ sharedsync(double *pckttime, double *pcktdelta, double olddelta, double finalt,
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
void shared_send_event(int index, double step, double dvalue, char *svalue, void *pvalue, int len)
|
||||
{}
|
||||
|
||||
|
|
|
|||
|
|
@ -55,7 +55,22 @@ NON-STANDARD FEATURES
|
|||
#include "ngspice/ipctiein.h"
|
||||
#include "ngspice/ipcproto.h"
|
||||
|
||||
#ifdef SHARED_MODULE
|
||||
/* global flag, TRUE if callback is used */
|
||||
extern bool wantevtdata;
|
||||
extern void shared_send_event(int, double, double, char *, void *, int);
|
||||
static void EVTshareddump(
|
||||
CKTcircuit *ckt, /* The circuit structure */
|
||||
Ipc_Anal_t mode, /* The analysis mode for this call */
|
||||
double step); /* The sweep step for a DCTRCURVE analysis, or */
|
||||
/* 0.0 for DCOP and TRAN */
|
||||
|
||||
static void EVTsharedsend_line(
|
||||
int ipc_index, /* The index used in the dictionary */
|
||||
double step, /* The analysis step */
|
||||
void *node_value, /* The node value */
|
||||
int udn_index); /* The user-defined node index */
|
||||
#endif
|
||||
|
||||
static void EVTsend_line(
|
||||
int ipc_index, /* The index used in the dictionary */
|
||||
|
|
@ -136,11 +151,18 @@ void EVTdump(
|
|||
|
||||
Mif_Boolean_t equal;
|
||||
|
||||
|
||||
#ifdef SHARED_MODULE
|
||||
if((! g_ipc.enabled) && (!wantevtdata))
|
||||
return;
|
||||
if ((!g_ipc.enabled) && (wantevtdata)) {
|
||||
EVTshareddump(ckt, mode, step);
|
||||
return;
|
||||
}
|
||||
#else
|
||||
/* Return immediately if IPC is not enabled */
|
||||
if(! g_ipc.enabled)
|
||||
return;
|
||||
|
||||
#endif
|
||||
/* Get number of event-driven nodes */
|
||||
num_nodes = ckt->evt->counts.num_nodes;
|
||||
|
||||
|
|
@ -345,3 +367,241 @@ static void EVTsend_line(
|
|||
/* Send it to the IPC channel */
|
||||
ipc_send_event(ipc_index, step, dvalue, svalue, pvalue, len);
|
||||
}
|
||||
|
||||
|
||||
#ifdef SHARED_MODULE
|
||||
static void EVTshareddump(
|
||||
CKTcircuit *ckt, /* The circuit structure */
|
||||
Ipc_Anal_t mode, /* The analysis mode for this call */
|
||||
double step) /* The sweep step for a DCTRCURVE analysis, or */
|
||||
/* 0.0 for DCOP and TRAN */
|
||||
{
|
||||
static evtdump_dict_t *node_dict = NULL;
|
||||
static int num_send_nodes;
|
||||
|
||||
int i;
|
||||
int j;
|
||||
int num_nodes;
|
||||
int num_modified;
|
||||
int index;
|
||||
|
||||
char *name;
|
||||
int name_len;
|
||||
|
||||
Mif_Boolean_t firstcall;
|
||||
|
||||
Evt_Node_Data_t *node_data;
|
||||
|
||||
Evt_Node_t *rhsold;
|
||||
Evt_Node_t **head;
|
||||
Evt_Node_t *here;
|
||||
|
||||
Evt_Node_Info_t **node_table;
|
||||
|
||||
char buff[10000];
|
||||
|
||||
Mif_Boolean_t equal;
|
||||
|
||||
/* Get number of event-driven nodes */
|
||||
num_nodes = ckt->evt->counts.num_nodes;
|
||||
|
||||
/* Exit immediately if no event-driven nodes in circuit */
|
||||
if (num_nodes <= 0)
|
||||
return;
|
||||
|
||||
|
||||
/* Get pointers for fast access to event data */
|
||||
node_data = ckt->evt->data.node;
|
||||
node_table = ckt->evt->info.node_table;
|
||||
rhsold = node_data->rhsold;
|
||||
head = node_data->head;
|
||||
|
||||
|
||||
/* Determine if this is the first call */
|
||||
if (node_dict == NULL)
|
||||
firstcall = MIF_TRUE;
|
||||
else
|
||||
firstcall = MIF_FALSE;
|
||||
|
||||
|
||||
/* If this is the first call, get the dictionary info */
|
||||
if (firstcall) {
|
||||
|
||||
/* Allocate local data structure used to process nodes */
|
||||
node_dict = TMALLOC(evtdump_dict_t, num_nodes);
|
||||
|
||||
/* Loop through all nodes to determine which nodes should be sent. */
|
||||
/* Only nodes not within subcircuits qualify. */
|
||||
|
||||
num_send_nodes = 0;
|
||||
for (i = 0; i < num_nodes; i++) {
|
||||
|
||||
/* Get the name of the node. */
|
||||
name = node_table[i]->name;
|
||||
|
||||
/* If name is in a subcircuit, mark that node should not be sent */
|
||||
/* and continue to next node. */
|
||||
name_len = (int)strlen(name);
|
||||
for (j = 0; j < name_len; j++) {
|
||||
if (name[j] == ':')
|
||||
break;
|
||||
}
|
||||
if (j < name_len) {
|
||||
node_dict[i].send = MIF_FALSE;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Otherwise, fill in info in dictionary. */
|
||||
node_dict[i].send = MIF_TRUE;
|
||||
node_dict[i].ipc_index = num_send_nodes;
|
||||
node_dict[i].node_name_str = name;
|
||||
node_dict[i].udn_type_str = g_evt_udn_info[node_table[i]->udn_index]->name;
|
||||
|
||||
/* Increment the count of nodes to be sent. */
|
||||
num_send_nodes++;
|
||||
} /* end for */
|
||||
} /* end if first call */
|
||||
|
||||
/* Exit if there are no nodes to be sent */
|
||||
if (num_send_nodes <= 0)
|
||||
return;
|
||||
|
||||
/* If this is the first call, send the dictionary */
|
||||
if (firstcall) {
|
||||
ipc_send_evtdict_prefix();
|
||||
for (i = 0; i < num_nodes; i++) {
|
||||
if (node_dict[i].send) {
|
||||
sprintf(buff, "%d %s %s", node_dict[i].ipc_index,
|
||||
node_dict[i].node_name_str,
|
||||
node_dict[i].udn_type_str);
|
||||
ipc_send_line(buff);
|
||||
}
|
||||
}
|
||||
ipc_send_evtdict_suffix();
|
||||
}
|
||||
|
||||
/* If this is the first call, send the operating point solution */
|
||||
/* and return. */
|
||||
if (firstcall) {
|
||||
ipc_send_evtdata_prefix();
|
||||
for (i = 0; i < num_nodes; i++) {
|
||||
if (node_dict[i].send) {
|
||||
EVTsend_line(node_dict[i].ipc_index,
|
||||
step,
|
||||
rhsold[i].node_value,
|
||||
node_table[i]->udn_index);
|
||||
}
|
||||
}
|
||||
ipc_send_evtdata_suffix();
|
||||
return;
|
||||
}
|
||||
|
||||
/* Otherwise, this must be DCTRCURVE or TRAN mode and we need to */
|
||||
/* send only stuff that has changed since the last call. */
|
||||
/* The determination of what to send is modeled after code in */
|
||||
/* EVTop_save() for DCTRCURVE and EVTaccept() for TRAN. */
|
||||
|
||||
if (mode == IPC_ANAL_DCTRCURVE) {
|
||||
/* Send data prefix */
|
||||
ipc_send_evtdata_prefix();
|
||||
/* Loop through event nodes */
|
||||
for (i = 0; i < num_nodes; i++) {
|
||||
/* If dictionary indicates this node should be sent */
|
||||
if (node_dict[i].send) {
|
||||
/* Locate end of node data */
|
||||
here = head[i];
|
||||
for (;;) {
|
||||
if (here->next)
|
||||
here = here->next;
|
||||
else
|
||||
break;
|
||||
}
|
||||
/* Compare entry at end of list to rhsold */
|
||||
g_evt_udn_info[node_table[i]->udn_index]->compare(
|
||||
rhsold[i].node_value,
|
||||
here->node_value,
|
||||
&equal);
|
||||
/* If value in rhsold is different, send it */
|
||||
if (!equal) {
|
||||
EVTsend_line(node_dict[i].ipc_index,
|
||||
step,
|
||||
rhsold[i].node_value,
|
||||
node_table[i]->udn_index);
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Send data suffix and return */
|
||||
ipc_send_evtdata_suffix();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (mode == IPC_ANAL_TRAN) {
|
||||
/* Send data prefix */
|
||||
ipc_send_evtdata_prefix();
|
||||
/* Loop through list of nodes modified since last time */
|
||||
num_modified = node_data->num_modified;
|
||||
for (i = 0; i < num_modified; i++) {
|
||||
/* Get the index of the node modified */
|
||||
index = node_data->modified_index[i];
|
||||
/* If dictionary indicates this node should be sent */
|
||||
if (node_dict[index].send) {
|
||||
/* Scan through new events and send the data for each event */
|
||||
here = *(node_data->last_step[index]);
|
||||
while ((here = here->next) != NULL) {
|
||||
EVTsend_line(node_dict[index].ipc_index,
|
||||
here->step,
|
||||
here->node_value,
|
||||
node_table[index]->udn_index);
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Send data suffix and return */
|
||||
ipc_send_evtdata_suffix();
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
EVTsharedsend_line
|
||||
|
||||
This function formats the event node data and sends it to the caller via sharedspice.c.
|
||||
*/
|
||||
|
||||
|
||||
static void EVTsharedsend_line(
|
||||
int ipc_index, /* The index used in the dictionary */
|
||||
double step, /* The analysis step */
|
||||
void *node_value, /* The node value */
|
||||
int udn_index) /* The user-defined node index */
|
||||
{
|
||||
double dvalue;
|
||||
char *svalue;
|
||||
void *pvalue;
|
||||
int len;
|
||||
|
||||
/* Get the data to send */
|
||||
if (g_evt_udn_info[udn_index]->plot_val)
|
||||
g_evt_udn_info[udn_index]->plot_val(node_value, "", &dvalue);
|
||||
else
|
||||
dvalue = 0.0;
|
||||
|
||||
if (g_evt_udn_info[udn_index]->print_val)
|
||||
g_evt_udn_info[udn_index]->print_val(node_value, "", &svalue);
|
||||
else
|
||||
svalue = "";
|
||||
|
||||
if (g_evt_udn_info[udn_index]->ipc_val)
|
||||
g_evt_udn_info[udn_index]->ipc_val(node_value, &pvalue, &len);
|
||||
else {
|
||||
pvalue = NULL;
|
||||
len = 0;
|
||||
}
|
||||
|
||||
/* Send it to the IPC channel */
|
||||
shared_send_event(ipc_index, step, dvalue, svalue, pvalue, len);
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Reference in New Issue