evtdump.c, prepare data gathering for callbacks similar to sending data via the ancient ipc channel

This commit is contained in:
h_vogt 2017-06-03 09:40:44 +02:00 committed by Holger Vogt
parent b621875abf
commit 3e52cdd8c1
2 changed files with 269 additions and 2 deletions

View File

@ -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)
{}

View File

@ -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