Browse Source
Remove all entries connected to IPC, an outdated (>30 years)
Remove all entries connected to IPC, an outdated (>30 years)
method to link ngspice to a now defunct controller (ATESSE).pre-master-46
25 changed files with 55 additions and 3393 deletions
-
1configure.ac
-
3src/Makefile.am
-
11src/frontend/inp.c
-
45src/frontend/inpcom.c
-
8src/frontend/resource.c
-
16src/frontend/runcoms.c
-
54src/spicelib/analysis/acan.c
-
38src/spicelib/analysis/cktdojob.c
-
35src/spicelib/analysis/dcop.c
-
81src/spicelib/analysis/dcpss.c
-
78src/spicelib/analysis/dctran.c
-
29src/spicelib/analysis/dctrcurv.c
-
58src/spicelib/analysis/noisean.c
-
57src/spicelib/analysis/span.c
-
2src/xspice/Makefile.am
-
252src/xspice/evt/evtdump.c
-
17src/xspice/ipc/Makefile.am
-
978src/xspice/ipc/ipc.c
-
309src/xspice/ipc/ipcaegis.c
-
756src/xspice/ipc/ipcsockets.c
-
77src/xspice/ipc/ipcstdio.c
-
520src/xspice/ipc/ipctiein.c
-
7visualc/sharedspice.vcxproj
-
7visualc/vngspice-fftw.vcxproj
-
7visualc/vngspice.vcxproj
@ -1,17 +0,0 @@ |
|||||
## Process this file with automake to produce Makefile.in
|
|
||||
#
|
|
||||
# JW 3/9/01 - had a go and makeing an autoconf script.
|
|
||||
|
|
||||
noinst_LTLIBRARIES = libipcxsp.la |
|
||||
|
|
||||
libipcxsp_la_SOURCES = \
|
|
||||
ipcaegis.c \
|
|
||||
ipc.c \
|
|
||||
ipcsockets.c \
|
|
||||
ipcstdio.c \
|
|
||||
ipctiein.c |
|
||||
|
|
||||
AM_CPPFLAGS = @AM_CPPFLAGS@ -I$(top_srcdir)/src/include -I$(top_srcdir)/src/spicelib/devices |
|
||||
AM_CFLAGS = $(STATIC) |
|
||||
|
|
||||
MAINTAINERCLEANFILES = Makefile.in |
|
||||
@ -1,978 +0,0 @@ |
|||||
/*============================================================================ |
|
||||
FILE IPC.c |
|
||||
|
|
||||
MEMBER OF process XSPICE |
|
||||
|
|
||||
Public Domain |
|
||||
|
|
||||
Georgia Tech Research Corporation |
|
||||
Atlanta, Georgia 30332 |
|
||||
PROJECT A-8503 |
|
||||
|
|
||||
AUTHORS |
|
||||
|
|
||||
9/12/91 Steve Tynor |
|
||||
|
|
||||
MODIFICATIONS |
|
||||
|
|
||||
6/13/92 Bill Kuhn Added some comments |
|
||||
|
|
||||
SUMMARY |
|
||||
|
|
||||
Provides compatibility for the new SPICE simulator to both the MSPICE user |
|
||||
interface and BCP (via ATESSE v.1 style AEGIS mailboxes) and the new ATESSE |
|
||||
v.2 Simulator Interface and BCP (via Bsd Sockets). |
|
||||
|
|
||||
The Interprocess Communications package provides functions |
|
||||
called to receive XSPICE decks from the ATESSE Simulator Interface |
|
||||
or Batch Control processes, and to return results to those |
|
||||
processes. Functions callable from the simulator packages include: |
|
||||
|
|
||||
ipc_initialize_server |
|
||||
ipc_terminate_server |
|
||||
ipc_get_line |
|
||||
ipc_send_line |
|
||||
ipc_send_data_prefix |
|
||||
ipc_send_data_suffix |
|
||||
ipc_send_dcop_prefix |
|
||||
ipc_send_dcop_suffix |
|
||||
ipc_send_evtdict_prefix |
|
||||
ipc_send_evtdict_suffix |
|
||||
ipc_send_evtdata_prefix |
|
||||
ipc_send_evtdata_suffix |
|
||||
ipc_send_errchk |
|
||||
ipc_send_end |
|
||||
ipc_send_boolean |
|
||||
ipc_send_int |
|
||||
ipc_send_double |
|
||||
ipc_send_complex |
|
||||
ipc_send_event |
|
||||
ipc_flush |
|
||||
|
|
||||
These functions communicate with a set of transport-level functions |
|
||||
that implement the interprocess communications under one of |
|
||||
the following protocol types determined by a compile-time option: |
|
||||
|
|
||||
BSD UNIX Sockets |
|
||||
HP/Apollo Mailboxes |
|
||||
|
|
||||
For each transport protocol, the following functions are written: |
|
||||
|
|
||||
ipc_transport_initialize_server |
|
||||
ipc_transport_get_line |
|
||||
ipc_transport_terminate_server |
|
||||
ipc_transport_send_line |
|
||||
|
|
||||
|
|
||||
|
|
||||
============================================================================*/ |
|
||||
|
|
||||
#include "ngspice/ngspice.h" |
|
||||
|
|
||||
#include <assert.h> |
|
||||
#include "ngspice/memory.h" /* NOTE: I think this is a Sys5ism (there is not man |
|
||||
* page for it under Bsd, but it's in /usr/include |
|
||||
* and it has a BSD copyright header. Go figure. |
|
||||
*/ |
|
||||
|
|
||||
#include "ngspice/ipc.h" |
|
||||
#include "ngspice/ipctiein.h" |
|
||||
#include "ngspice/ipcproto.h" |
|
||||
|
|
||||
|
|
||||
/* |
|
||||
* Conditional compilation sanity check: |
|
||||
*/ |
|
||||
#if !defined (IPC_AEGIS_MAILBOXES) && !defined (IPC_UNIX_SOCKETS)\ |
|
||||
&& !defined (IPC_DEBUG_VIA_STDIO) |
|
||||
" compiler error - must specify a transport mechanism"; |
|
||||
#endif |
|
||||
|
|
||||
/* |
|
||||
* static 'globals' |
|
||||
*/ |
|
||||
|
|
||||
/* typedef unsigned char Buffer_Char_t; */ |
|
||||
typedef char Buffer_Char_t; |
|
||||
|
|
||||
#define OUT_BUFFER_SIZE 1000 |
|
||||
#define MAX_NUM_RECORDS 200 |
|
||||
static int end_of_record_index [MAX_NUM_RECORDS]; |
|
||||
static int num_records; |
|
||||
static Buffer_Char_t out_buffer [OUT_BUFFER_SIZE]; |
|
||||
static int fill_count; |
|
||||
|
|
||||
static Ipc_Mode_t mode; |
|
||||
static Ipc_Protocol_t protocol; |
|
||||
static Ipc_Boolean_t end_of_deck_seen; |
|
||||
static int batch_fd; |
|
||||
|
|
||||
#define FMT_BUFFER_SIZE 80 |
|
||||
static char fmt_buffer [FMT_BUFFER_SIZE]; |
|
||||
|
|
||||
/*---------------------------------------------------------------------------*/ |
|
||||
Ipc_Boolean_t |
|
||||
kw_match (char *keyword, char *str) |
|
||||
/* |
|
||||
* returns IPC_TRUE if the first `strlen(keyword)' characters of `str' match |
|
||||
* the ones in `keyword' - case sensitive |
|
||||
*/ |
|
||||
{ |
|
||||
char *k = keyword; |
|
||||
char *s = str; |
|
||||
|
|
||||
/* |
|
||||
* quit if we run off the end of either string: |
|
||||
*/ |
|
||||
while (*s && *k) { |
|
||||
if (*s != *k) { |
|
||||
return IPC_FALSE; |
|
||||
} |
|
||||
s++; |
|
||||
k++; |
|
||||
} |
|
||||
/* |
|
||||
* if we get this far, it sould be because we ran off the end of the |
|
||||
* keyword else we didn't match: |
|
||||
*/ |
|
||||
return (*k == '\0'); |
|
||||
} |
|
||||
|
|
||||
/*---------------------------------------------------------------------------*/ |
|
||||
|
|
||||
/* |
|
||||
ipc_initialize_server |
|
||||
|
|
||||
This function creates the interprocess communication channel |
|
||||
server mailbox or socket. |
|
||||
*/ |
|
||||
|
|
||||
|
|
||||
Ipc_Status_t |
|
||||
ipc_initialize_server ( |
|
||||
char *server_name, /* Mailbox path or host/portnumber pair */ |
|
||||
Ipc_Mode_t m, /* Interactive or batch */ |
|
||||
Ipc_Protocol_t p ) /* Type of IPC protocol */ |
|
||||
/* |
|
||||
* For mailboxes, `server_name' would be the mailbox pathname; for |
|
||||
* sockets, this needs to be a host/portnumber pair. Maybe this should be |
|
||||
* automatically generated by the routine... |
|
||||
*/ |
|
||||
{ |
|
||||
Ipc_Status_t status; |
|
||||
char batch_filename [1025]; |
|
||||
|
|
||||
mode = m; |
|
||||
protocol = p; |
|
||||
end_of_deck_seen = IPC_FALSE; |
|
||||
|
|
||||
num_records = 0; |
|
||||
fill_count = 0; |
|
||||
|
|
||||
status = ipc_transport_initialize_server (server_name, m, p, |
|
||||
batch_filename); |
|
||||
|
|
||||
if (status != IPC_STATUS_OK) { |
|
||||
fprintf (stderr, "ERROR: IPC: error initializing server\n"); |
|
||||
return IPC_STATUS_ERROR; |
|
||||
} |
|
||||
|
|
||||
if (mode == IPC_MODE_BATCH) { |
|
||||
#ifdef IPC_AEGIS_MAILBOXES |
|
||||
strcat (batch_filename, ".log"); |
|
||||
#endif |
|
||||
batch_fd = open (batch_filename, O_WRONLY | O_CREAT, 0666); |
|
||||
if (batch_fd < 0) { |
|
||||
/* fprintf (stderr, "ERROR: IPC: Error opening batch output file: %s\n",batch_filename); */ |
|
||||
perror ("IPC"); |
|
||||
return IPC_STATUS_ERROR; |
|
||||
} |
|
||||
} |
|
||||
return status; |
|
||||
} |
|
||||
|
|
||||
/*---------------------------------------------------------------------------*/ |
|
||||
|
|
||||
/* |
|
||||
ipc_terminate_server |
|
||||
|
|
||||
This function deallocates the interprocess communication channel |
|
||||
mailbox or socket. |
|
||||
*/ |
|
||||
|
|
||||
|
|
||||
|
|
||||
Ipc_Status_t |
|
||||
ipc_terminate_server (void) |
|
||||
{ |
|
||||
return ipc_transport_terminate_server (); |
|
||||
} |
|
||||
|
|
||||
/*---------------------------------------------------------------------------*/ |
|
||||
|
|
||||
/* |
|
||||
ipc_get_line |
|
||||
|
|
||||
This function gets a SPICE deck input line from the interprocess |
|
||||
communication channel. Any special control commands in the deck |
|
||||
beginning with a ``>'' or ``#'' character are processed internally by |
|
||||
this function and not returned to SPICE. |
|
||||
*/ |
|
||||
|
|
||||
Ipc_Status_t |
|
||||
ipc_get_line ( |
|
||||
char *str, /* Text retrieved from IPC channel */ |
|
||||
int *len, /* Length of text string */ |
|
||||
Ipc_Wait_t wait ) /* Select blocking or non-blocking */ |
|
||||
/* |
|
||||
* Reads one SPICE line from the connection. Strips any control lines |
|
||||
* which cannot be interpretted by the simulator (e.g. >INQCON) and |
|
||||
* processes them. If such a line is read, it is processed and the next |
|
||||
* line is read. `ipc_get_line' does not return until a non-interceptable |
|
||||
* line is read or end of file. |
|
||||
* |
|
||||
* If `wait' is IPC_NO_WAIT and there is no data available on the |
|
||||
* connection, `ipc_get_line' returns IPC_STATUS_NO_DATA. If `wait' is |
|
||||
* IPC_WAIT, `ipc_get_line' will not return until there is data available |
|
||||
* or and end of file condition is reached or an error occurs. |
|
||||
* |
|
||||
* Intercepts and processes the following commands: |
|
||||
* #RETURNI, #MINTIME, #VTRANS, |
|
||||
* >PAUSE, >CONT, >STOP, >INQCON, >NETLIST, >ENDNET |
|
||||
* Other > records are silently ignored. |
|
||||
* |
|
||||
* Intercepts old-style .TEMP card generated by MSPICE |
|
||||
* |
|
||||
* Returns: |
|
||||
* IPC_STATUS_OK - for successful reads |
|
||||
* IPC_STATUS_NO_DATA - when NO_WAIT and no data available |
|
||||
* IPC_STATUS_END_OF_DECK - at end of deck (>ENDNET seen) |
|
||||
* IPC_STATUS_ERROR - otherwise |
|
||||
*/ |
|
||||
{ |
|
||||
Ipc_Status_t status; |
|
||||
Ipc_Boolean_t need_another = IPC_TRUE; |
|
||||
|
|
||||
do { |
|
||||
|
|
||||
status = ipc_transport_get_line (str, len, wait); |
|
||||
|
|
||||
switch (status) { |
|
||||
case IPC_STATUS_NO_DATA: |
|
||||
case IPC_STATUS_ERROR: |
|
||||
need_another = IPC_FALSE; |
|
||||
break; |
|
||||
case IPC_STATUS_END_OF_DECK: |
|
||||
assert (0); /* should never get this from the low-level get-line */ |
|
||||
status = IPC_STATUS_ERROR; |
|
||||
need_another = IPC_FALSE; |
|
||||
break; |
|
||||
case IPC_STATUS_OK: |
|
||||
/* |
|
||||
* Got a good line - check to see if it's one of the ones we need to |
|
||||
* intercept |
|
||||
*/ |
|
||||
if (str[0] == '>') { |
|
||||
if (kw_match (">STOP", str)) { |
|
||||
ipc_handle_stop(); |
|
||||
} else if (kw_match (">PAUSE", str)) { |
|
||||
/* assert (need_another); */ |
|
||||
/* |
|
||||
* once more around the loop to do a blocking wait for the >CONT |
|
||||
*/ |
|
||||
need_another = IPC_TRUE; |
|
||||
wait = IPC_WAIT; |
|
||||
} else if (kw_match (">INQCON", str)) { |
|
||||
ipc_send_line (">ABRTABL"); |
|
||||
ipc_send_line (">PAUSABL"); |
|
||||
ipc_send_line (">KEEPABL"); |
|
||||
status = ipc_flush (); |
|
||||
if (IPC_STATUS_OK != status) { |
|
||||
need_another = IPC_FALSE; |
|
||||
} |
|
||||
} else if (kw_match (">ENDNET", str)) { |
|
||||
end_of_deck_seen = IPC_TRUE; |
|
||||
need_another = IPC_FALSE; |
|
||||
status = IPC_STATUS_END_OF_DECK; |
|
||||
} else { |
|
||||
/* silently ignore */ |
|
||||
} |
|
||||
} else if (str[0] == '#') { |
|
||||
if (kw_match ("#RETURNI", str)) { |
|
||||
ipc_handle_returni (); |
|
||||
} else if (kw_match ("#MINTIME", str)) { |
|
||||
double d1/*,d2*/; |
|
||||
if (1 != sscanf (&str[8], "%lg", &d1)) { |
|
||||
status = IPC_STATUS_ERROR; |
|
||||
need_another = IPC_FALSE; |
|
||||
} else { |
|
||||
ipc_handle_mintime (d1); |
|
||||
} |
|
||||
} else if (kw_match ("#VTRANS", str)) { |
|
||||
char *tok1; |
|
||||
char *tok2; |
|
||||
char *tok3; |
|
||||
|
|
||||
tok1 = &str[8]; |
|
||||
for (tok2 = tok1; *tok2; tok2++) { |
|
||||
if (isspace_c(*tok2)) { |
|
||||
*tok2 = '\0'; |
|
||||
tok2++; |
|
||||
break; |
|
||||
} |
|
||||
} |
|
||||
for(tok3 = tok2; *tok3; tok3++) { |
|
||||
if(isspace_c(*tok3)) { |
|
||||
*tok3 = '\0'; |
|
||||
break; |
|
||||
} |
|
||||
} |
|
||||
ipc_handle_vtrans (tok1, tok2); |
|
||||
} else { |
|
||||
/* silently ignore */ |
|
||||
} |
|
||||
} else if (str[0] == '.') { |
|
||||
if (kw_match (".TEMP", str)) { |
|
||||
/* don't pass .TEMP card to caller */ |
|
||||
printf("Old-style .TEMP card found - ignored\n"); |
|
||||
} |
|
||||
else { |
|
||||
/* pass all other . cards to the caller */ |
|
||||
need_another = IPC_FALSE; |
|
||||
} |
|
||||
} else { |
|
||||
/* |
|
||||
* Not a '>' or '#' record - let the caller deal with it |
|
||||
*/ |
|
||||
need_another = IPC_FALSE; |
|
||||
} |
|
||||
break; |
|
||||
default: |
|
||||
/* |
|
||||
* some unknown status value! |
|
||||
*/ |
|
||||
assert (0); |
|
||||
status = IPC_STATUS_ERROR; |
|
||||
need_another = IPC_FALSE; |
|
||||
break; |
|
||||
} |
|
||||
} while (need_another); |
|
||||
|
|
||||
return status; |
|
||||
} |
|
||||
|
|
||||
/*---------------------------------------------------------------------------*/ |
|
||||
|
|
||||
/* |
|
||||
ipc_flush |
|
||||
|
|
||||
This function flushes the interprocess communication channel |
|
||||
buffer contents. |
|
||||
*/ |
|
||||
|
|
||||
Ipc_Status_t |
|
||||
ipc_flush (void) |
|
||||
/* |
|
||||
* Flush all buffered messages out the connection. |
|
||||
*/ |
|
||||
{ |
|
||||
Ipc_Status_t status; |
|
||||
int last = 0; |
|
||||
/*int bytes;*/ |
|
||||
int i; |
|
||||
|
|
||||
/* if batch mode */ |
|
||||
if (mode == IPC_MODE_BATCH) { |
|
||||
|
|
||||
assert (batch_fd >= 0); |
|
||||
|
|
||||
/* for number of records in buffer */ |
|
||||
for (i = 0; i < num_records; i++) { |
|
||||
|
|
||||
/* write the records to the .log file */ |
|
||||
if ((end_of_record_index [i] - last) != |
|
||||
write (batch_fd, &out_buffer[last], (size_t) (end_of_record_index [i] - last))) { |
|
||||
/* fprintf (stderr,"ERROR: IPC: Error writing to batch output file\n"); */ |
|
||||
perror ("IPC"); |
|
||||
return IPC_STATUS_ERROR; |
|
||||
} |
|
||||
|
|
||||
/* If the record is one of the batch simulation status messages, */ |
|
||||
/* send it over the ipc channel too */ |
|
||||
if( kw_match("#ERRCHK", &out_buffer[last]) || |
|
||||
kw_match(">ENDANAL", &out_buffer[last]) || |
|
||||
kw_match(">ABORTED", &out_buffer[last]) ) { |
|
||||
|
|
||||
status = ipc_transport_send_line (&out_buffer[last], |
|
||||
end_of_record_index [i] - last); |
|
||||
if (IPC_STATUS_OK != status) { |
|
||||
return status; |
|
||||
} |
|
||||
} |
|
||||
last = end_of_record_index [i]; |
|
||||
} |
|
||||
|
|
||||
/* else, must be interactive mode */ |
|
||||
} else { |
|
||||
/* send the full buffer over the ipc channel */ |
|
||||
status = ipc_transport_send_line (&out_buffer[0], |
|
||||
end_of_record_index [num_records - 1]); |
|
||||
if (IPC_STATUS_OK != status) { |
|
||||
return status; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
/* reset counts to zero and return */ |
|
||||
num_records = 0; |
|
||||
fill_count = 0; |
|
||||
return IPC_STATUS_OK; |
|
||||
} |
|
||||
|
|
||||
/*---------------------------------------------------------------------------*/ |
|
||||
Ipc_Status_t |
|
||||
ipc_send_line_binary ( |
|
||||
char *str, |
|
||||
int len ) |
|
||||
/* |
|
||||
* Same as `ipc_send_line' except does not expect the str to be null |
|
||||
* terminated. Sends exactly `len' characters. Use this for binary data |
|
||||
* strings that may have embedded nulls. |
|
||||
* |
|
||||
* Modified by wbk to append newlines for compatibility with |
|
||||
* ATESSE 1.0 |
|
||||
* |
|
||||
*/ |
|
||||
{ |
|
||||
int length = len + 1; |
|
||||
/*int diff;*/ |
|
||||
Ipc_Status_t status; |
|
||||
|
|
||||
/* |
|
||||
* If we can't add the whole str to the buffer, or if there are no more |
|
||||
* record indices free, flush the buffer: |
|
||||
*/ |
|
||||
if (((fill_count + length) >= OUT_BUFFER_SIZE) || |
|
||||
(num_records >= MAX_NUM_RECORDS)) { |
|
||||
status = ipc_flush (); |
|
||||
if (IPC_STATUS_OK != status) { |
|
||||
return status; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
/* |
|
||||
* make sure that the str will fit: |
|
||||
*/ |
|
||||
if (length + fill_count > OUT_BUFFER_SIZE) { |
|
||||
/* fprintf (stderr,"ERROR: IPC: String too long to fit in output buffer (> %d bytes) - truncated\n",OUT_BUFFER_SIZE); */ |
|
||||
length = OUT_BUFFER_SIZE - fill_count; |
|
||||
} |
|
||||
|
|
||||
/* |
|
||||
* finally, concatenate the str to the end of the buffer and add the newline: |
|
||||
*/ |
|
||||
memcpy (&out_buffer[fill_count], str, (size_t) len); |
|
||||
fill_count += len; |
|
||||
|
|
||||
out_buffer[fill_count] = '\n'; |
|
||||
fill_count++; |
|
||||
|
|
||||
end_of_record_index [num_records++] = fill_count; |
|
||||
|
|
||||
return IPC_STATUS_OK; |
|
||||
} |
|
||||
|
|
||||
/*---------------------------------------------------------------------------*/ |
|
||||
|
|
||||
/* |
|
||||
ipc_send_line |
|
||||
|
|
||||
This function sends a line of text over the interprocess |
|
||||
communication channel. |
|
||||
*/ |
|
||||
|
|
||||
|
|
||||
Ipc_Status_t |
|
||||
ipc_send_line (char *str ) /* The text to send */ |
|
||||
{ |
|
||||
int len; |
|
||||
int send_len; |
|
||||
|
|
||||
char *s; |
|
||||
|
|
||||
Ipc_Status_t status= IPC_STATUS_OK; |
|
||||
|
|
||||
|
|
||||
len = (int) strlen(str); |
|
||||
|
|
||||
/* if short string, send it immediately */ |
|
||||
if(len < 80) |
|
||||
status = ipc_send_line_binary (str, len); |
|
||||
else { |
|
||||
/* otherwise, we have to send it as multiple strings */ |
|
||||
/* because Mspice cannot handle things longer than 80 chars */ |
|
||||
s = str; |
|
||||
while(len > 0) { |
|
||||
if(len < 80) |
|
||||
send_len = len; |
|
||||
else |
|
||||
send_len = 79; |
|
||||
status = ipc_send_line_binary (str, send_len); |
|
||||
if(status != IPC_STATUS_OK) |
|
||||
break; |
|
||||
s += send_len; |
|
||||
len -= send_len; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
return(status); |
|
||||
} |
|
||||
|
|
||||
/*---------------------------------------------------------------------------*/ |
|
||||
|
|
||||
/* |
|
||||
ipc_send_data_prefix |
|
||||
|
|
||||
This function sends a ``>DATAB'' line over the interprocess |
|
||||
communication channel to signal that this is the beginning of a |
|
||||
results dump for the current analysis point. |
|
||||
*/ |
|
||||
|
|
||||
Ipc_Status_t |
|
||||
ipc_send_data_prefix (double time ) /* The analysis point for this data set */ |
|
||||
{ |
|
||||
char buffer[40]; |
|
||||
|
|
||||
sprintf (buffer, ">DATAB %.5E", time); |
|
||||
return ipc_send_line (buffer); |
|
||||
} |
|
||||
|
|
||||
/*---------------------------------------------------------------------------*/ |
|
||||
|
|
||||
/* |
|
||||
ipc_send_data_suffix |
|
||||
|
|
||||
This function sends a ``>ENDDATA'' line over the interprocess |
|
||||
communication channel to signal that this is the end of a results |
|
||||
dump from a particular analysis point. |
|
||||
*/ |
|
||||
|
|
||||
|
|
||||
Ipc_Status_t |
|
||||
ipc_send_data_suffix (void) |
|
||||
{ |
|
||||
Ipc_Status_t status; |
|
||||
|
|
||||
status = ipc_send_line (">ENDDATA"); |
|
||||
|
|
||||
if(status != IPC_STATUS_OK) |
|
||||
return(status); |
|
||||
|
|
||||
return(ipc_flush()); |
|
||||
} |
|
||||
|
|
||||
/*---------------------------------------------------------------------------*/ |
|
||||
|
|
||||
/* |
|
||||
ipc_send_dcop_prefix |
|
||||
|
|
||||
This function sends a ``>DCOPB'' line over the interprocess |
|
||||
communication channel to signal that this is the beginning of a |
|
||||
results dump from a DC operating point analysis. |
|
||||
*/ |
|
||||
|
|
||||
Ipc_Status_t |
|
||||
ipc_send_dcop_prefix (void) |
|
||||
{ |
|
||||
return ipc_send_line (">DCOPB"); |
|
||||
} |
|
||||
|
|
||||
/*---------------------------------------------------------------------------*/ |
|
||||
|
|
||||
/* |
|
||||
ipc_send_dcop_suffix |
|
||||
|
|
||||
This function sends a ``>ENDDATA'' line over the interprocess |
|
||||
communication channel to signal that this is the end of a results |
|
||||
dump from a particular analysis point. |
|
||||
*/ |
|
||||
|
|
||||
|
|
||||
Ipc_Status_t |
|
||||
ipc_send_dcop_suffix (void) |
|
||||
{ |
|
||||
Ipc_Status_t status; |
|
||||
|
|
||||
status = ipc_send_line (">ENDDCOP"); |
|
||||
|
|
||||
if(status != IPC_STATUS_OK) |
|
||||
return(status); |
|
||||
|
|
||||
return(ipc_flush()); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
/*---------------------------------------------------------------------------*/ |
|
||||
|
|
||||
/* |
|
||||
ipc_send_evtdict_prefix |
|
||||
|
|
||||
This function sends a ``>EVTDICT'' line over the interprocess |
|
||||
communication channel to signal that this is the beginning of an |
|
||||
event-driven node dictionary. |
|
||||
|
|
||||
The line is sent only if the IPC is configured |
|
||||
for UNIX sockets, indicating use with the V2 ATESSE SI process. |
|
||||
*/ |
|
||||
|
|
||||
Ipc_Status_t |
|
||||
ipc_send_evtdict_prefix (void) |
|
||||
{ |
|
||||
#ifdef IPC_AEGIS_MAILBOXES |
|
||||
return IPC_STATUS_OK; |
|
||||
#else |
|
||||
return ipc_send_line (">EVTDICT"); |
|
||||
#endif |
|
||||
} |
|
||||
|
|
||||
/*---------------------------------------------------------------------------*/ |
|
||||
|
|
||||
/* |
|
||||
ipc_send_evtdict_suffix |
|
||||
|
|
||||
This function sends a ``>ENDDICT'' line over the interprocess |
|
||||
communication channel to signal that this is the end of an |
|
||||
event-driven node dictionary. |
|
||||
|
|
||||
The line is sent only if the IPC is configured |
|
||||
for UNIX sockets, indicating use with the V2 ATESSE SI process. |
|
||||
*/ |
|
||||
|
|
||||
|
|
||||
Ipc_Status_t |
|
||||
ipc_send_evtdict_suffix (void) |
|
||||
{ |
|
||||
#ifdef IPC_AEGIS_MAILBOXES |
|
||||
return IPC_STATUS_OK; |
|
||||
#else |
|
||||
Ipc_Status_t status; |
|
||||
|
|
||||
status = ipc_send_line (">ENDDICT"); |
|
||||
|
|
||||
if(status != IPC_STATUS_OK) |
|
||||
return(status); |
|
||||
|
|
||||
return(ipc_flush()); |
|
||||
#endif |
|
||||
} |
|
||||
|
|
||||
|
|
||||
/*---------------------------------------------------------------------------*/ |
|
||||
|
|
||||
/* |
|
||||
ipc_send_evtdata_prefix |
|
||||
|
|
||||
This function sends a ``>EVTDATA'' line over the interprocess |
|
||||
communication channel to signal that this is the beginning of an |
|
||||
event-driven node data block. |
|
||||
|
|
||||
The line is sent only if the IPC is configured |
|
||||
for UNIX sockets, indicating use with the V2 ATESSE SI process. |
|
||||
*/ |
|
||||
|
|
||||
Ipc_Status_t |
|
||||
ipc_send_evtdata_prefix (void) |
|
||||
{ |
|
||||
#ifdef IPC_AEGIS_MAILBOXES |
|
||||
return IPC_STATUS_OK; |
|
||||
#else |
|
||||
return ipc_send_line (">EVTDATA"); |
|
||||
#endif |
|
||||
} |
|
||||
|
|
||||
/*---------------------------------------------------------------------------*/ |
|
||||
|
|
||||
/* |
|
||||
ipc_send_evtdata_suffix |
|
||||
|
|
||||
This function sends a ``>ENDDATA'' line over the interprocess |
|
||||
communication channel to signal that this is the end of an |
|
||||
event-driven node data block. |
|
||||
|
|
||||
The line is sent only if the IPC is configured |
|
||||
for UNIX sockets, indicating use with the V2 ATESSE SI process. |
|
||||
*/ |
|
||||
|
|
||||
|
|
||||
Ipc_Status_t |
|
||||
ipc_send_evtdata_suffix (void) |
|
||||
{ |
|
||||
#ifdef IPC_AEGIS_MAILBOXES |
|
||||
return IPC_STATUS_OK; |
|
||||
#else |
|
||||
Ipc_Status_t status; |
|
||||
|
|
||||
status = ipc_send_line (">ENDDATA"); |
|
||||
|
|
||||
if(status != IPC_STATUS_OK) |
|
||||
return(status); |
|
||||
|
|
||||
return(ipc_flush()); |
|
||||
#endif |
|
||||
} |
|
||||
|
|
||||
|
|
||||
/*---------------------------------------------------------------------------*/ |
|
||||
|
|
||||
/* |
|
||||
ipc_send_errchk |
|
||||
|
|
||||
This function sends a ``\ERRCHK [GO|NOGO]'' message over the |
|
||||
interprocess communication channel to signal that the initial |
|
||||
parsing of the input deck has been completed and to indicate |
|
||||
whether or not errors were detected. |
|
||||
*/ |
|
||||
|
|
||||
|
|
||||
Ipc_Status_t |
|
||||
ipc_send_errchk(void) |
|
||||
{ |
|
||||
char str[IPC_MAX_LINE_LEN+1]; |
|
||||
Ipc_Status_t status; |
|
||||
|
|
||||
if(g_ipc.errchk_sent) |
|
||||
return(IPC_STATUS_OK); |
|
||||
|
|
||||
if(g_ipc.syntax_error) |
|
||||
sprintf(str, "#ERRCHK NOGO"); |
|
||||
else |
|
||||
sprintf(str, "#ERRCHK GO"); |
|
||||
|
|
||||
g_ipc.errchk_sent = IPC_TRUE; |
|
||||
|
|
||||
status = ipc_send_line(str); |
|
||||
if(status != IPC_STATUS_OK) |
|
||||
return(status); |
|
||||
|
|
||||
return(ipc_flush()); |
|
||||
} |
|
||||
|
|
||||
/*---------------------------------------------------------------------------*/ |
|
||||
|
|
||||
/* |
|
||||
ipc_send_end |
|
||||
|
|
||||
This function sends either an ``>ENDANAL'' or an ``>ABORTED'' message |
|
||||
over the interprocess communication channel together with the |
|
||||
total CPU time used to indicate whether or not the simulation |
|
||||
completed normally. |
|
||||
*/ |
|
||||
|
|
||||
|
|
||||
Ipc_Status_t |
|
||||
ipc_send_end(void) |
|
||||
{ |
|
||||
char str[IPC_MAX_LINE_LEN+1]; |
|
||||
Ipc_Status_t status; |
|
||||
|
|
||||
if(g_ipc.syntax_error || g_ipc.run_error) |
|
||||
sprintf(str, ">ABORTED %.4f", g_ipc.cpu_time); |
|
||||
else |
|
||||
sprintf(str, ">ENDANAL %.4f", g_ipc.cpu_time); |
|
||||
|
|
||||
status = ipc_send_line(str); |
|
||||
if(status != IPC_STATUS_OK) |
|
||||
return(status); |
|
||||
|
|
||||
return(ipc_flush()); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
/*---------------------------------------------------------------------------*/ |
|
||||
int |
|
||||
stuff_binary_v1 ( |
|
||||
double d1, double d2, /* doubles to be stuffed */ |
|
||||
int n, /* how many of d1, d2 ( 1 <= n <= 2 ) */ |
|
||||
char *buf, /* buffer to stuff to */ |
|
||||
int pos ) /* index at which to stuff */ |
|
||||
{ |
|
||||
union { |
|
||||
float float_val[2]; |
|
||||
char ch[32]; |
|
||||
} trick; |
|
||||
int i, j; |
|
||||
|
|
||||
assert (protocol == IPC_PROTOCOL_V1); |
|
||||
assert (sizeof(float) == 4); |
|
||||
assert (sizeof(char) == 1); |
|
||||
assert ((n >= 1) && (n <= 2)); |
|
||||
|
|
||||
trick.float_val[0] = (float)d1; |
|
||||
if (n > 1) { |
|
||||
trick.float_val[1] = (float)d2; |
|
||||
} |
|
||||
for (i = 0, j = pos; i < n * (int) sizeof(float); j++, i++) |
|
||||
buf[j] = trick.ch[i]; |
|
||||
buf[0] = (char) ('A' + j - 1); |
|
||||
return j; |
|
||||
} |
|
||||
|
|
||||
/*---------------------------------------------------------------------------*/ |
|
||||
|
|
||||
|
|
||||
/* |
|
||||
ipc_send_double |
|
||||
|
|
||||
This function sends a double data value over the interprocess |
|
||||
communication channel preceded by a character string that |
|
||||
identifies the simulation variable. |
|
||||
*/ |
|
||||
|
|
||||
Ipc_Status_t |
|
||||
ipc_send_double ( |
|
||||
char *tag, /* The node or instance */ |
|
||||
double value ) /* The data value to send */ |
|
||||
{ |
|
||||
int len = 0; |
|
||||
|
|
||||
switch (protocol) { |
|
||||
case IPC_PROTOCOL_V1: |
|
||||
strcpy (fmt_buffer, " "); /* save room for the length byte */ |
|
||||
strcat (fmt_buffer, tag); |
|
||||
strcat (fmt_buffer, " "); |
|
||||
|
|
||||
/* If talking to Mentor tools, must force upper case for Mspice 7.0 */ |
|
||||
strtoupper(fmt_buffer); |
|
||||
|
|
||||
len = stuff_binary_v1 (value, 0.0, 1, fmt_buffer, (int) strlen(fmt_buffer)); |
|
||||
break; |
|
||||
case IPC_PROTOCOL_V2: |
|
||||
break; |
|
||||
} |
|
||||
return ipc_send_line_binary (fmt_buffer, len); |
|
||||
} |
|
||||
|
|
||||
/*---------------------------------------------------------------------------*/ |
|
||||
|
|
||||
/* |
|
||||
ipc_send_complex |
|
||||
|
|
||||
This function sends a complex data value over the interprocess |
|
||||
communication channel preceded by a character string that |
|
||||
identifies the simulation variable. |
|
||||
*/ |
|
||||
|
|
||||
|
|
||||
Ipc_Status_t |
|
||||
ipc_send_complex ( |
|
||||
char *tag, /* The node or instance */ |
|
||||
Ipc_Complex_t value ) /* The data value to send */ |
|
||||
{ |
|
||||
int len=0; |
|
||||
|
|
||||
switch (protocol) { |
|
||||
case IPC_PROTOCOL_V1: |
|
||||
strcpy (fmt_buffer, " "); /* save room for the length byte */ |
|
||||
strcat (fmt_buffer, tag); |
|
||||
strcat (fmt_buffer, " "); |
|
||||
|
|
||||
/* If talking to Mentor tools, must force upper case for Mspice 7.0 */ |
|
||||
strtoupper(fmt_buffer); |
|
||||
|
|
||||
len = stuff_binary_v1 (value.real, value.imag, 2, fmt_buffer, |
|
||||
(int) strlen(fmt_buffer)); |
|
||||
break; |
|
||||
case IPC_PROTOCOL_V2: |
|
||||
break; |
|
||||
} |
|
||||
return ipc_send_line_binary (fmt_buffer, len); |
|
||||
} |
|
||||
|
|
||||
/*---------------------------------------------------------------------------*/ |
|
||||
|
|
||||
/* |
|
||||
ipc_send_event |
|
||||
|
|
||||
This function sends data from an event-driven node over the interprocess |
|
||||
communication channel. The data is sent only if the IPC is configured |
|
||||
for UNIX sockets, indicating use with the V2 ATESSE SI process. |
|
||||
*/ |
|
||||
|
|
||||
|
|
||||
Ipc_Status_t |
|
||||
ipc_send_event ( |
|
||||
int ipc_index, /* Index used in EVTDICT */ |
|
||||
double step, /* Analysis point or timestep (0.0 for DC) */ |
|
||||
double plot_val, /* The value for plotting purposes */ |
|
||||
char *print_val, /* The value for printing purposes */ |
|
||||
void *ipc_val, /* The binary representation of the node data */ |
|
||||
int len ) /* The length of the binary representation */ |
|
||||
{ |
|
||||
#ifdef IPC_AEGIS_MAILBOXES |
|
||||
return IPC_STATUS_OK; |
|
||||
#else |
|
||||
char buff[OUT_BUFFER_SIZE]; |
|
||||
int i; |
|
||||
int buff_len; |
|
||||
char *buff_ptr; |
|
||||
char *temp_ptr; |
|
||||
float fvalue; |
|
||||
|
|
||||
/* Report error if size of data is too big for IPC channel block size */ |
|
||||
if((len + (int) strlen(print_val) + 100) >= OUT_BUFFER_SIZE) { |
|
||||
printf("ERROR - Size of event-driven data too large for IPC channel\n"); |
|
||||
return IPC_STATUS_ERROR; |
|
||||
} |
|
||||
|
|
||||
/* Place the index into the buffer with a trailing space */ |
|
||||
sprintf(buff, "%d ", ipc_index); |
|
||||
|
|
||||
assert(sizeof(float) == 4); |
|
||||
assert(sizeof(int) == 4); |
|
||||
|
|
||||
/* Put the analysis step bytes in */ |
|
||||
buff_len = (int) strlen(buff); |
|
||||
buff_ptr = buff + buff_len; |
|
||||
fvalue = (float)step; |
|
||||
temp_ptr = (char *) &fvalue; |
|
||||
for(i = 0; i < 4; i++) { |
|
||||
*buff_ptr = temp_ptr[i]; |
|
||||
buff_ptr++; |
|
||||
buff_len++; |
|
||||
} |
|
||||
|
|
||||
/* Put the plot value in */ |
|
||||
fvalue = (float)plot_val; |
|
||||
temp_ptr = (char *) &fvalue; |
|
||||
for(i = 0; i < 4; i++) { |
|
||||
*buff_ptr = temp_ptr[i]; |
|
||||
buff_ptr++; |
|
||||
buff_len++; |
|
||||
} |
|
||||
|
|
||||
/* Put the length of the binary representation in */ |
|
||||
temp_ptr = (char *) &len; |
|
||||
for(i = 0; i < 4; i++) { |
|
||||
*buff_ptr = temp_ptr[i]; |
|
||||
buff_ptr++; |
|
||||
buff_len++; |
|
||||
} |
|
||||
|
|
||||
/* Put the binary representation bytes in last */ |
|
||||
temp_ptr = (char*) ipc_val; |
|
||||
for(i = 0; i < len; i++) |
|
||||
buff_ptr[i] = temp_ptr[i]; |
|
||||
buff_ptr += len; |
|
||||
buff_len += len; |
|
||||
|
|
||||
/* Put the print value in */ |
|
||||
strcpy(buff_ptr, print_val); |
|
||||
buff_ptr += strlen(print_val); |
|
||||
buff_len += (int) strlen(print_val); |
|
||||
|
|
||||
/* Send the data to the IPC channel */ |
|
||||
return ipc_send_line_binary(buff, buff_len); |
|
||||
|
|
||||
#endif |
|
||||
} |
|
||||
|
|
||||
|
|
||||
@ -1,309 +0,0 @@ |
|||||
/*============================================================================ |
|
||||
FILE IPCaegis.c |
|
||||
|
|
||||
MEMBER OF process XSPICE |
|
||||
|
|
||||
Public Domain |
|
||||
|
|
||||
Georgia Tech Research Corporation |
|
||||
Atlanta, Georgia 30332 |
|
||||
PROJECT A-8503 |
|
||||
|
|
||||
AUTHORS |
|
||||
|
|
||||
9/12/91 Steve Tynor |
|
||||
|
|
||||
MODIFICATIONS |
|
||||
|
|
||||
<date> <person name> <nature of modifications> |
|
||||
|
|
||||
SUMMARY |
|
||||
|
|
||||
Provides compatibility for the new XSPICE simulator to both the MSPICE user |
|
||||
interface and BCP via ATESSE v.1 style AEGIS mailboxes. |
|
||||
|
|
||||
INTERFACES |
|
||||
|
|
||||
|
|
||||
REFERENCED FILES |
|
||||
|
|
||||
None. |
|
||||
|
|
||||
NON-STANDARD FEATURES |
|
||||
|
|
||||
None. |
|
||||
|
|
||||
============================================================================*/ |
|
||||
|
|
||||
#ifdef IPC_AEGIS_MAILBOXES |
|
||||
|
|
||||
#include <assert.h> |
|
||||
#include <apollo/base.h> |
|
||||
#include <apollo/mbx.h> |
|
||||
#include <apollo/error.h> |
|
||||
#include "ngspice/memory.h" |
|
||||
|
|
||||
#include "ngspice/ipc.h" |
|
||||
|
|
||||
|
|
||||
typedef unsigned char Buffer_char_t; |
|
||||
|
|
||||
static status_$t status; |
|
||||
typedef enum { |
|
||||
IPC_MBX_UNINITIALIZED, |
|
||||
IPC_MBX_INITIALIZED, |
|
||||
IPC_MBX_CONNECTED_TO_CLIENT, |
|
||||
} Ipc_Mbx_State_t; |
|
||||
|
|
||||
static void *mbx_handle; |
|
||||
static Ipc_Mbx_State_t mbx_state = IPC_MBX_UNINITIALIZED; |
|
||||
static mbx_$server_msg_t mbx_send_msg_buf; |
|
||||
static mbx_$server_msg_t mbx_recieve_msg_buf; |
|
||||
static mbx_$server_msg_t *mbx_ret_ptr; |
|
||||
static int mbx_ret_len; |
|
||||
static short mbx_chan; |
|
||||
|
|
||||
#include "ngspice/ipcproto.h" |
|
||||
|
|
||||
/*---------------------------------------------------------------------------*/ |
|
||||
|
|
||||
/* |
|
||||
ipc_transport_initialize_server |
|
||||
|
|
||||
This function creates an Aegis mailbox, and if successful, |
|
||||
calls ipc_get_line to wait for the first record sent which is |
|
||||
assumed to be the batch output filename. |
|
||||
*/ |
|
||||
|
|
||||
|
|
||||
|
|
||||
Ipc_Status_t ipc_transport_initialize_server (server_name, m, p, |
|
||||
batch_filename) |
|
||||
char *server_name; /* The mailbox pathname */ |
|
||||
Ipc_Mode_t m; /* Mode - interactive or batch */ |
|
||||
Ipc_Protocol_t p; /* Protocol type */ |
|
||||
char *batch_filename; /* Batch filename returned */ |
|
||||
{ |
|
||||
int len; |
|
||||
/* extern void *malloc(); */ |
|
||||
|
|
||||
assert (p == IPC_PROTOCOL_V1); |
|
||||
|
|
||||
mbx_$create_server (server_name, strlen (server_name), mbx_$serv_msg_max, |
|
||||
1, &mbx_handle, &status); |
|
||||
|
|
||||
if (status.all != status_$ok) { |
|
||||
fprintf (stderr, |
|
||||
"ERROR: IPC: Error creating mailbox server \"%s\"\n", |
|
||||
server_name); |
|
||||
error_$print (status); |
|
||||
mbx_state = IPC_MBX_UNINITIALIZED; |
|
||||
return IPC_STATUS_ERROR; |
|
||||
} else { |
|
||||
mbx_state = IPC_MBX_INITIALIZED; |
|
||||
/* |
|
||||
* First record is the name of the batch filename - whether we're in |
|
||||
* batch mode or not: |
|
||||
*/ |
|
||||
return ipc_get_line (batch_filename, &len, IPC_WAIT); |
|
||||
} |
|
||||
/* |
|
||||
* shouldn't get here |
|
||||
*/ |
|
||||
assert (0); |
|
||||
return IPC_STATUS_ERROR; |
|
||||
} |
|
||||
/*---------------------------------------------------------------------------*/ |
|
||||
Ipc_Status_t extract_msg (str, len) |
|
||||
char *str; |
|
||||
int *len; |
|
||||
{ |
|
||||
*len = mbx_ret_len - mbx_$serv_msg_hdr_len; |
|
||||
assert (*len >= 0); |
|
||||
|
|
||||
/* |
|
||||
* null terminate before copy: |
|
||||
*/ |
|
||||
mbx_ret_ptr->data [*len] = '\0'; |
|
||||
strcpy (str, mbx_ret_ptr->data); |
|
||||
|
|
||||
return IPC_STATUS_OK; |
|
||||
} |
|
||||
|
|
||||
/*---------------------------------------------------------------------------*/ |
|
||||
|
|
||||
/* |
|
||||
ipc_transport_get_line |
|
||||
|
|
||||
This function reads data sent by a client over the mailbox |
|
||||
channel. It also handles the initial opening of the |
|
||||
mailbox channel when requested by a client. |
|
||||
*/ |
|
||||
|
|
||||
|
|
||||
|
|
||||
Ipc_Status_t ipc_transport_get_line (str, len, wait) |
|
||||
char *str; /* The string text read from IPC channel */ |
|
||||
int *len; /* The length of str */ |
|
||||
Ipc_Wait_t wait; /* Blocking or non-blocking */ |
|
||||
{ |
|
||||
if (mbx_state == IPC_MBX_UNINITIALIZED) { |
|
||||
fprintf (stderr, |
|
||||
"ERROR: IPC: Attempted to read from non-initialized mailbox\n"); |
|
||||
return IPC_STATUS_ERROR; |
|
||||
} |
|
||||
|
|
||||
assert ((mbx_state == IPC_MBX_CONNECTED_TO_CLIENT) || |
|
||||
(mbx_state == IPC_MBX_INITIALIZED)); |
|
||||
|
|
||||
for (;;) { |
|
||||
if (wait == IPC_WAIT) { |
|
||||
mbx_$get_rec (mbx_handle, &mbx_recieve_msg_buf, mbx_$serv_msg_max, |
|
||||
&mbx_ret_ptr, &mbx_ret_len, &status); |
|
||||
} else { |
|
||||
mbx_$get_conditional (mbx_handle, &mbx_recieve_msg_buf, |
|
||||
mbx_$serv_msg_max, &mbx_ret_ptr, &mbx_ret_len, |
|
||||
&status); |
|
||||
if (status.all == mbx_$channel_empty) { |
|
||||
return IPC_STATUS_NO_DATA; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
if (status.all != status_$ok) { |
|
||||
fprintf (stderr, "ERROR: IPC: Error reading from mailbox\n"); |
|
||||
error_$print (status); |
|
||||
return IPC_STATUS_ERROR; |
|
||||
} |
|
||||
|
|
||||
switch (mbx_ret_ptr->mt) { |
|
||||
case mbx_$channel_open_mt: |
|
||||
if (mbx_state == IPC_MBX_CONNECTED_TO_CLIENT) { |
|
||||
/* |
|
||||
* we're already connected to a client... refuse the connection |
|
||||
*/ |
|
||||
mbx_send_msg_buf.mt = mbx_$reject_open_mt; |
|
||||
} else { |
|
||||
mbx_send_msg_buf.mt = mbx_$accept_open_mt; |
|
||||
mbx_state = IPC_MBX_CONNECTED_TO_CLIENT; |
|
||||
} |
|
||||
mbx_send_msg_buf.cnt = mbx_$serv_msg_hdr_len; |
|
||||
mbx_chan = mbx_ret_ptr->chan; |
|
||||
mbx_send_msg_buf.chan = mbx_chan; |
|
||||
|
|
||||
mbx_$put_rec (mbx_handle, &mbx_send_msg_buf, mbx_$serv_msg_hdr_len, |
|
||||
&status); |
|
||||
|
|
||||
if (status.all != status_$ok) { |
|
||||
fprintf (stderr, "ERROR: IPC: Error writing to mailbox\n"); |
|
||||
error_$print (status); |
|
||||
return IPC_STATUS_ERROR; |
|
||||
} |
|
||||
|
|
||||
/* |
|
||||
* check to see if there was a message buried in the open request: |
|
||||
*/ |
|
||||
if (mbx_ret_len > mbx_$serv_msg_hdr_len) { |
|
||||
return extract_msg (str, len); |
|
||||
} |
|
||||
break; |
|
||||
case mbx_$eof_mt: |
|
||||
mbx_chan = mbx_ret_ptr->chan; |
|
||||
mbx_$deallocate(mbx_handle, mbx_chan, &status); |
|
||||
|
|
||||
if (status.all != status_$ok) { |
|
||||
fprintf (stderr, "ERROR: IPC: Error deallocating mailbox\n"); |
|
||||
error_$print (status); |
|
||||
return IPC_STATUS_ERROR; |
|
||||
} |
|
||||
|
|
||||
mbx_state = IPC_MBX_INITIALIZED; |
|
||||
return IPC_STATUS_EOF; |
|
||||
break; |
|
||||
case mbx_$data_mt: |
|
||||
assert (mbx_state == IPC_MBX_CONNECTED_TO_CLIENT); |
|
||||
return extract_msg (str, len); |
|
||||
break; |
|
||||
case mbx_$data_partial_mt: |
|
||||
fprintf (stderr, "ERROR: IPC: Recieved partial data message - ignored\n"); |
|
||||
break; |
|
||||
default: |
|
||||
fprintf (stderr, "ERROR: IPC: Bad message type (0x%x) recieved\n", |
|
||||
mbx_ret_ptr->mt); |
|
||||
} |
|
||||
} |
|
||||
return IPC_STATUS_ERROR; |
|
||||
} |
|
||||
|
|
||||
/*---------------------------------------------------------------------------*/ |
|
||||
|
|
||||
/* |
|
||||
ipc_transport_terminate_server |
|
||||
|
|
||||
This function calls ipc\_transport\_get\_line until it |
|
||||
receives an EOF from the client, which concludes the |
|
||||
communication. |
|
||||
*/ |
|
||||
|
|
||||
|
|
||||
Ipc_Status_t ipc_transport_terminate_server () |
|
||||
{ |
|
||||
char buffer[300]; |
|
||||
int len; |
|
||||
Ipc_Status_t status; |
|
||||
|
|
||||
do { |
|
||||
status = ipc_transport_get_line (buffer, &len, IPC_WAIT); |
|
||||
} while ((status != IPC_STATUS_ERROR) && |
|
||||
(status != IPC_STATUS_EOF)); |
|
||||
return status; |
|
||||
} |
|
||||
|
|
||||
/*---------------------------------------------------------------------------*/ |
|
||||
|
|
||||
/* |
|
||||
ipc_transport_send_line |
|
||||
|
|
||||
This function sends a message to the current client through |
|
||||
the mailbox channel. |
|
||||
*/ |
|
||||
|
|
||||
|
|
||||
Ipc_Status_t ipc_transport_send_line (str, len) |
|
||||
char *str; /* The bytes to send */ |
|
||||
int len; /* The number of bytes from str to send */ |
|
||||
{ |
|
||||
long cnt; |
|
||||
|
|
||||
if (mbx_state != IPC_MBX_CONNECTED_TO_CLIENT) { |
|
||||
fprintf (stderr, |
|
||||
"ERROR: IPC: Attempted to write to non-open mailbox\n"); |
|
||||
return IPC_STATUS_ERROR; |
|
||||
} |
|
||||
|
|
||||
mbx_send_msg_buf.mt = mbx_$data_mt; |
|
||||
if (mbx_$serv_msg_hdr_len + len > mbx_$serv_msg_max) { |
|
||||
fprintf (stderr, |
|
||||
"ERROR: IPC: send_line message too long - truncating\n"); |
|
||||
len = mbx_$serv_msg_max - mbx_$serv_msg_hdr_len; |
|
||||
} |
|
||||
|
|
||||
mbx_send_msg_buf.cnt = mbx_$serv_msg_hdr_len + len; |
|
||||
mbx_send_msg_buf.chan = mbx_chan; |
|
||||
memcpy (mbx_send_msg_buf.data, str, len); |
|
||||
|
|
||||
cnt = mbx_send_msg_buf.cnt; |
|
||||
mbx_$put_rec (mbx_handle, &mbx_send_msg_buf, cnt, &status); |
|
||||
|
|
||||
if (status.all != status_$ok) { |
|
||||
fprintf (stderr, "ERROR: IPC: Error writing to mailbox\n"); |
|
||||
error_$print (status); |
|
||||
return IPC_STATUS_ERROR; |
|
||||
} |
|
||||
return IPC_STATUS_OK; |
|
||||
} |
|
||||
|
|
||||
#else |
|
||||
|
|
||||
int intDummy1; |
|
||||
|
|
||||
#endif /* IPC_AEGIS_MAILBOXES */ |
|
||||
@ -1,756 +0,0 @@ |
|||||
/*============================================================================= |
|
||||
|
|
||||
FILE IPCsockets.c |
|
||||
|
|
||||
Public Domain |
|
||||
|
|
||||
Georgia Tech Research Corporation |
|
||||
Atlanta, Georgia 30332 |
|
||||
PROJECT A-8503 |
|
||||
|
|
||||
AUTHOR |
|
||||
Stefan Roth July 1991 |
|
||||
|
|
||||
MODIFICATIONS |
|
||||
none |
|
||||
|
|
||||
SUMMARY |
|
||||
Generic Interprocess Communication module |
|
||||
Provides compatibility for the new SPICE simulator to both the MSPICE user |
|
||||
interface and BCP (via ATESSE v.1 style AEGIS mailboxes) and the new ATESSE |
|
||||
v.2 Simulator Interface and BCP (via BSD Sockets). This file contains the |
|
||||
BSD sockets version. |
|
||||
The Simulator is the server, while the SI and BCP will be the clients. |
|
||||
|
|
||||
|
|
||||
INTERFACES |
|
||||
|
|
||||
FILE ROUTINE CALLED |
|
||||
|
|
||||
IPC.c ipc_get_line(); |
|
||||
|
|
||||
|
|
||||
REFERENCED FILES |
|
||||
|
|
||||
Outputs to stderr. |
|
||||
|
|
||||
|
|
||||
=============================================================================*/ |
|
||||
|
|
||||
|
|
||||
/*============================================================================= |
|
||||
|
|
||||
DESCRIPTION OF FUNCTIONALITY: |
|
||||
|
|
||||
Outline of Initialize_Server function: |
|
||||
create socket; |
|
||||
bind name to socket; |
|
||||
getsockname; |
|
||||
listen; |
|
||||
sock_state = IPC_SOCK_INITIALIZED; |
|
||||
return ipc_get_line (); |
|
||||
|
|
||||
|
|
||||
Format of a message line: |
|
||||
bytes description |
|
||||
----- ------------------- |
|
||||
0 recognition character for beginning of line; value is BOL_CHAR. |
|
||||
1-4 message length (not including bytes 0-4); 32 bits in htonl |
|
||||
format; |
|
||||
if value = -1, then EOF and socket should be closed. |
|
||||
5-N+5 message body of length specified in bytes 1-4. |
|
||||
|
|
||||
The bytes before the message body are the message header. The header |
|
||||
length is specified as SOCK_MSG_HDR_LEN bytes. |
|
||||
|
|
||||
|
|
||||
Outline of Get_Line function: |
|
||||
read 5 characters; |
|
||||
verify that first char is BOL_CHAR; |
|
||||
interpret message length (N) from bytes 1-4; |
|
||||
do error checking on message header bytes; |
|
||||
read N characters as message body; |
|
||||
do error checking on message body read; |
|
||||
|
|
||||
|
|
||||
Outline of Send_Line function: |
|
||||
write BOL_CHAR; |
|
||||
write 4-byte message body length |
|
||||
write message body (N bytes) |
|
||||
do error checking after each write operation |
|
||||
|
|
||||
|
|
||||
Outline of Terminate_Server function: |
|
||||
Continue to read lines (with ipc_transport_get_line) and ignore |
|
||||
them until socket EOF is reached; |
|
||||
Close the socket. |
|
||||
|
|
||||
|
|
||||
=============================================================================*/ |
|
||||
|
|
||||
#include "ngspice/ngspice.h" |
|
||||
|
|
||||
#ifdef IPC_UNIX_SOCKETS |
|
||||
|
|
||||
/*=== INCLUDE FILES ===*/ |
|
||||
|
|
||||
#include <assert.h> |
|
||||
#include <errno.h> |
|
||||
|
|
||||
#include "ngspice/ipc.h" |
|
||||
#include "ngspice/ipctiein.h" |
|
||||
|
|
||||
|
|
||||
/*=== TYPE DEFINITIONS ===*/ |
|
||||
|
|
||||
typedef enum { |
|
||||
IPC_SOCK_UNINITIALIZED, |
|
||||
IPC_SOCK_INITIALIZED, |
|
||||
IPC_SOCK_CONNECTED_TO_CLIENT |
|
||||
} Ipc_Sock_State_t; |
|
||||
|
|
||||
|
|
||||
/*=== LOCAL VARIABLES ===*/ |
|
||||
|
|
||||
static int sock_desc; /* socket descriptor */ |
|
||||
static int msg_stream; /* socket stream */ |
|
||||
static Ipc_Sock_State_t sock_state = IPC_SOCK_UNINITIALIZED; |
|
||||
|
|
||||
|
|
||||
/*=== INCLUDE FILES ===*/ |
|
||||
|
|
||||
#include "ngspice/ipcproto.h" |
|
||||
|
|
||||
/*============================================================================= |
|
||||
|
|
||||
FUNCTION ipc_transport_initialize_server |
|
||||
|
|
||||
AUTHORS |
|
||||
|
|
||||
July 1991 Stefan Roth |
|
||||
|
|
||||
MODIFICATIONS |
|
||||
|
|
||||
NONE |
|
||||
|
|
||||
SUMMARY |
|
||||
|
|
||||
Creates and opens the BSD socket of the server. Listens for requests |
|
||||
by a client and then reads the first line message. |
|
||||
|
|
||||
INTERFACES |
|
||||
|
|
||||
Called by: (IPC.c) ipc_initialize_server(); |
|
||||
|
|
||||
RETURNED VALUE |
|
||||
|
|
||||
Ipc_Status_t - returns status of the socket connection. |
|
||||
|
|
||||
GLOBAL VARIABLES |
|
||||
|
|
||||
NONE |
|
||||
|
|
||||
NON-STANDARD FEATURES |
|
||||
|
|
||||
NONE |
|
||||
|
|
||||
=============================================================================*/ |
|
||||
|
|
||||
Ipc_Status_t |
|
||||
ipc_transport_initialize_server ( |
|
||||
char *server_name, /* not used */ |
|
||||
Ipc_Mode_t mode, /* not used */ |
|
||||
Ipc_Protocol_t protocol, /* IN - only used in assert */ |
|
||||
char *batch_filename ) /* OUT - returns a value */ |
|
||||
/* Note that unused parameters are required to maintain compatibility */ |
|
||||
/* with version 1 (mailboxes) functions of the same names. */ |
|
||||
{ |
|
||||
struct sockaddr_in server; /* Server specifications for socket*/ |
|
||||
socklen_t server_length; /* Size of server structure */ |
|
||||
int port_num; /* Port number converted from server_name */ |
|
||||
|
|
||||
NG_IGNORE(mode); |
|
||||
NG_IGNORE(protocol); |
|
||||
|
|
||||
/* assert (protocol == IPC_PROTOCOL_V2); */ /* allow v1 protocol - wbk */ |
|
||||
assert (sock_state == IPC_SOCK_UNINITIALIZED); |
|
||||
|
|
||||
/* convert server_name (from atesse_xspice invocation line) to a port */ |
|
||||
/* number */ |
|
||||
port_num = atoi(server_name); |
|
||||
if((port_num > 0) && (port_num < 1024)) { |
|
||||
/* Reserved port number */ |
|
||||
perror ("ERROR: IPC Port numbers below 1024 are reserved"); |
|
||||
sock_state = IPC_SOCK_UNINITIALIZED; |
|
||||
return IPC_STATUS_ERROR; |
|
||||
} |
|
||||
|
|
||||
|
|
||||
sock_desc = socket (AF_INET, SOCK_STREAM, 0); |
|
||||
|
|
||||
if (sock_desc < 0) { |
|
||||
/* Unsuccessful socket opening */ |
|
||||
perror ("ERROR: IPC Creating socket"); |
|
||||
sock_state = IPC_SOCK_UNINITIALIZED; |
|
||||
return IPC_STATUS_ERROR; |
|
||||
} |
|
||||
|
|
||||
/* Socket opened successfully */ |
|
||||
|
|
||||
server.sin_family = AF_INET; |
|
||||
server.sin_addr.s_addr = INADDR_ANY; |
|
||||
server.sin_port = SOCKET_PORT; |
|
||||
|
|
||||
server_length = sizeof (server); |
|
||||
if (bind (sock_desc, (struct sockaddr *)&server, server_length) |
|
||||
< 0) { |
|
||||
fprintf (stderr, "ERROR: IPC: Bind unsuccessful\n"); |
|
||||
perror ("ERROR: IPC"); |
|
||||
sock_state = IPC_SOCK_UNINITIALIZED; |
|
||||
return IPC_STATUS_ERROR; |
|
||||
} |
|
||||
|
|
||||
if (getsockname (sock_desc, (struct sockaddr *)&server, &server_length) |
|
||||
< 0) { |
|
||||
fprintf (stderr, "ERROR: IPC: getting socket name\n"); |
|
||||
perror ("ERROR: IPC"); |
|
||||
sock_state = IPC_SOCK_UNINITIALIZED; |
|
||||
return IPC_STATUS_ERROR; |
|
||||
} |
|
||||
|
|
||||
fprintf (stderr, "Socket port %d.\n", ntohs(server.sin_port)); |
|
||||
|
|
||||
listen (sock_desc, 5); |
|
||||
|
|
||||
sock_state = IPC_SOCK_INITIALIZED; |
|
||||
|
|
||||
/* Socket ok to use now */ |
|
||||
|
|
||||
/* |
|
||||
* First record is the name of the batch filename if we're in batch mode. |
|
||||
*/ |
|
||||
|
|
||||
if(g_ipc.mode == IPC_MODE_BATCH) { |
|
||||
int len; |
|
||||
return ipc_get_line (batch_filename, &len, IPC_WAIT); |
|
||||
} |
|
||||
|
|
||||
/* Return success */ |
|
||||
return IPC_STATUS_OK; |
|
||||
|
|
||||
} /* end ipc_transport_initialize_server */ |
|
||||
|
|
||||
|
|
||||
|
|
||||
/*============================================================================= |
|
||||
|
|
||||
FUNCTION bytes_to_integer |
|
||||
|
|
||||
AUTHORS |
|
||||
|
|
||||
July 1991 Stefan Roth |
|
||||
|
|
||||
MODIFICATIONS |
|
||||
|
|
||||
NONE |
|
||||
|
|
||||
SUMMARY |
|
||||
|
|
||||
Convert four bytes at START in the string STR |
|
||||
to a 32-bit unsigned integer. The string is assumed |
|
||||
to be in network byte order and the returned value |
|
||||
is converted to host byte order (with ntohl). |
|
||||
|
|
||||
INTERFACES |
|
||||
|
|
||||
Local to this file. |
|
||||
Called by: ipc_transport_get_line(); |
|
||||
|
|
||||
RETURNED VALUE |
|
||||
|
|
||||
u_long - unsigned 32 bit integer |
|
||||
|
|
||||
GLOBAL VARIABLES |
|
||||
|
|
||||
NONE |
|
||||
|
|
||||
NON-STANDARD FEATURES |
|
||||
|
|
||||
NONE |
|
||||
|
|
||||
=============================================================================*/ |
|
||||
|
|
||||
/* FIXME, |
|
||||
* this is seriously broken, |
|
||||
* once it was probably based upon htonl(), |
|
||||
* yet with broken types |
|
||||
* then the game has changed and strtoul() was used |
|
||||
* with a ascii representation of the length |
|
||||
* (probably as a hacky workaround, because it proved unreliable) |
|
||||
* but the buffer is not terminated properly |
|
||||
* Fix this when needed, currently this functionality looks like |
|
||||
* an unused ancient artefact |
|
||||
* Fix it with regard to ipc_transport_get_line() and ipc_transport_send_line() |
|
||||
* and in concert with the actual user at the other side of the socket |
|
||||
*/ |
|
||||
static u_long |
|
||||
bytes_to_integer ( |
|
||||
char *str, /* IN - string that contains the bytes to convert */ |
|
||||
int start ) /* IN - index into string where bytes are */ |
|
||||
{ |
|
||||
uint32_t u; /* Value to be returned */ |
|
||||
char buff[4]; /* Transfer str into buff to word align reqd data */ |
|
||||
int index; /* Index into str and buff for transfer */ |
|
||||
|
|
||||
/* Get the str+start character and cast it into a u_long and put |
|
||||
the value through the network-to-host-short converter and store |
|
||||
it in the variable u. */ |
|
||||
|
|
||||
index = 0; |
|
||||
while (index < (int) sizeof(u)) { |
|
||||
buff[index] = str[index+start]; |
|
||||
index++; |
|
||||
} |
|
||||
/* u = ntohl (*((u_long *) buff)); */ |
|
||||
u = (uint32_t) strtoul(buff, NULL, 10); |
|
||||
|
|
||||
return u; |
|
||||
} /* end bytes_to_integer */ |
|
||||
|
|
||||
|
|
||||
|
|
||||
/*============================================================================= |
|
||||
|
|
||||
FUNCTION handle_socket_eof |
|
||||
|
|
||||
AUTHORS |
|
||||
|
|
||||
July 1991 Stefan Roth |
|
||||
|
|
||||
MODIFICATIONS |
|
||||
|
|
||||
NONE |
|
||||
|
|
||||
SUMMARY |
|
||||
|
|
||||
Do processing when the socket reaches EOF or when a message from the |
|
||||
client states that EOF has been reached. |
|
||||
|
|
||||
INTERFACES |
|
||||
|
|
||||
Local to this file. |
|
||||
Called by: ipc_transport_get_line(); |
|
||||
|
|
||||
RETURNED VALUE |
|
||||
|
|
||||
Ipc_Status_t - always IPC_STATUS_EOF |
|
||||
|
|
||||
GLOBAL VARIABLES |
|
||||
|
|
||||
NONE |
|
||||
|
|
||||
NON-STANDARD FEATURES |
|
||||
|
|
||||
NONE |
|
||||
|
|
||||
=============================================================================*/ |
|
||||
|
|
||||
|
|
||||
static Ipc_Status_t |
|
||||
handle_socket_eof (void) |
|
||||
{ |
|
||||
close (msg_stream); |
|
||||
close (sock_desc); |
|
||||
|
|
||||
sock_state = IPC_SOCK_UNINITIALIZED; |
|
||||
|
|
||||
return IPC_STATUS_EOF; |
|
||||
} /* handle_socket_eof */ |
|
||||
|
|
||||
|
|
||||
|
|
||||
/*============================================================================= |
|
||||
|
|
||||
FUNCTION read_sock |
|
||||
|
|
||||
AUTHORS |
|
||||
|
|
||||
July 1991 Stefan Roth |
|
||||
|
|
||||
MODIFICATIONS |
|
||||
|
|
||||
NONE |
|
||||
|
|
||||
SUMMARY |
|
||||
|
|
||||
Read N bytes from a socket. Only returns when the read had an error, |
|
||||
when 0 bytes (EOF) could be read, or LENGTH bytes are read. |
|
||||
|
|
||||
INTERFACES |
|
||||
|
|
||||
Local to this file. |
|
||||
Called by: ipc_transport_get_line(); |
|
||||
|
|
||||
RETURNED VALUE |
|
||||
|
|
||||
int - Returns the total number of bytes read. |
|
||||
|
|
||||
GLOBAL VARIABLES |
|
||||
|
|
||||
NONE |
|
||||
|
|
||||
NON-STANDARD FEATURES |
|
||||
|
|
||||
NONE |
|
||||
|
|
||||
=============================================================================*/ |
|
||||
|
|
||||
|
|
||||
static int |
|
||||
read_sock ( |
|
||||
int stream, /* IN - Socket stream */ |
|
||||
char *buffer, /* OUT - buffer to store incoming data */ |
|
||||
int length, /* IN - Number of bytes to be read */ |
|
||||
Ipc_Wait_t wait, /* IN - type of read operation */ |
|
||||
int flags ) /* IN - Original socket flags for blocking read */ |
|
||||
{ |
|
||||
int count; /* Number of bytes read with last `read` */ |
|
||||
int totalcount; /* total number of bytes read */ |
|
||||
char *buf2; |
|
||||
|
|
||||
/* count = 0; */ |
|
||||
/* while (count < length) { */ |
|
||||
/* buffer[count] = 'x'; */ |
|
||||
/* count++; */ |
|
||||
/* } */ |
|
||||
count = (int) read (stream, buffer, (size_t) length); |
|
||||
if (wait == IPC_NO_WAIT) { |
|
||||
fcntl (stream, F_SETFL, flags); /* Revert to blocking read */ |
|
||||
} |
|
||||
if ((count <= 0) || (count == length)) { |
|
||||
/* If error or if read in reqd number of bytes: */ |
|
||||
return count; |
|
||||
} else { |
|
||||
/* Only got some of the bytes requested */ |
|
||||
totalcount = count; |
|
||||
buf2 = &buffer[totalcount]; |
|
||||
length = length - count; |
|
||||
while (length > 0) { |
|
||||
count = (int) read (stream, buf2, (size_t) length); |
|
||||
if (count <= 0) /* EOF or read error */ |
|
||||
break; |
|
||||
totalcount = totalcount + count; |
|
||||
buf2 = &buffer[totalcount]; |
|
||||
length = length - count; |
|
||||
} |
|
||||
if (length != 0) { |
|
||||
fprintf (stderr, "WARNING: READ_SOCK read %d bytes instead of %d\n", |
|
||||
totalcount, totalcount + length); |
|
||||
} |
|
||||
return totalcount; |
|
||||
} |
|
||||
} /* end read_sock */ |
|
||||
|
|
||||
|
|
||||
|
|
||||
/*============================================================================= |
|
||||
|
|
||||
FUNCTION ipc_transport_get_line |
|
||||
|
|
||||
AUTHORS |
|
||||
|
|
||||
July 1991 Stefan Roth |
|
||||
|
|
||||
MODIFICATIONS |
|
||||
|
|
||||
NONE |
|
||||
|
|
||||
SUMMARY |
|
||||
|
|
||||
Main function for reading one line from a socket. Requires that the |
|
||||
socket be open. Lines are mostly SPICE code, but commands may also |
|
||||
be embedded in the socket data and they are interpreted by this function. |
|
||||
Therefore, this function may cause the socket to be closed. |
|
||||
|
|
||||
INTERFACES |
|
||||
|
|
||||
Called by: ipc_transport_terminate_server(); |
|
||||
(IPC.c) ipc_get_line(); |
|
||||
|
|
||||
RETURNED VALUE |
|
||||
|
|
||||
Ipc_Status_t - returns status of the read operation |
|
||||
|
|
||||
GLOBAL VARIABLES |
|
||||
|
|
||||
NONE |
|
||||
|
|
||||
NON-STANDARD FEATURES |
|
||||
|
|
||||
NONE |
|
||||
|
|
||||
=============================================================================*/ |
|
||||
|
|
||||
|
|
||||
Ipc_Status_t |
|
||||
ipc_transport_get_line ( |
|
||||
char *str, /* returns the result, null terminated */ |
|
||||
int *len, /* length of str passed IN and passed OUT */ |
|
||||
Ipc_Wait_t wait ) /* IN - wait or dont wait on incoming msg */ |
|
||||
{ |
|
||||
int count = 0; /* number of bytes read */ |
|
||||
int message_length; /* extracted from message header */ |
|
||||
|
|
||||
if (sock_state == IPC_SOCK_UNINITIALIZED) { |
|
||||
fprintf (stderr, |
|
||||
"ERROR: IPC: Attempted to read from uninitialized socket\n"); |
|
||||
return IPC_STATUS_ERROR; |
|
||||
} |
|
||||
|
|
||||
assert ((sock_state == IPC_SOCK_CONNECTED_TO_CLIENT) || |
|
||||
(sock_state == IPC_SOCK_INITIALIZED)); |
|
||||
|
|
||||
if (sock_state == IPC_SOCK_INITIALIZED) { |
|
||||
/* We have an open socket but have not connected to a client. */ |
|
||||
/* Accept a connection from a client. */ |
|
||||
msg_stream = accept (sock_desc, (struct sockaddr *)0, (socklen_t*)0); |
|
||||
|
|
||||
if (msg_stream == -1) { |
|
||||
fprintf (stderr, "ERROR: IPC: Server accepting request\n"); |
|
||||
perror ("ERROR: IPC"); |
|
||||
return IPC_STATUS_ERROR; |
|
||||
} |
|
||||
sock_state = IPC_SOCK_CONNECTED_TO_CLIENT; |
|
||||
} |
|
||||
/*-----------------------------------------------------------------------*/ |
|
||||
/* First read in the message header. */ |
|
||||
{ |
|
||||
int flags; |
|
||||
flags = fcntl(msg_stream, F_GETFL, NULL); /* Blocking read mode */ |
|
||||
|
|
||||
if (wait == IPC_WAIT) { |
|
||||
/* Block here and wait for the next message */ |
|
||||
count = read_sock (msg_stream, str, SOCK_MSG_HDR_LEN, wait, flags); |
|
||||
if (count == 0) { |
|
||||
/* EOF, will this ever happen? */ |
|
||||
/* fprintf (stderr, "WARNING: IPC: Reached eof on socket\n"); */ |
|
||||
return handle_socket_eof (); |
|
||||
} |
|
||||
} else if (wait == IPC_NO_WAIT) { |
|
||||
/* Read message, but do not wait if none available. */ |
|
||||
|
|
||||
fcntl (msg_stream, F_SETFL, flags | O_NDELAY); |
|
||||
count = read_sock (msg_stream, str, SOCK_MSG_HDR_LEN, wait, flags); |
|
||||
|
|
||||
if (count == 0) { |
|
||||
/* EOF, will this ever happen? */ |
|
||||
/* fprintf (stderr, "WARNING: IPC: Reached eof on socket\n"); */ |
|
||||
return handle_socket_eof (); |
|
||||
} else if (count == -1) { |
|
||||
if (errno == EWOULDBLOCK) { |
|
||||
return IPC_STATUS_NO_DATA; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
} else { |
|
||||
/* Serious problem, since it is not reading anything. */ |
|
||||
fprintf (stderr, |
|
||||
"ERROR: IPC: invalid wait arg to ipc_transport_get_line\n"); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
/* Do more error checking on the read in values of the message header: */ |
|
||||
if (count == -1) { |
|
||||
fprintf (stderr, "ERROR: IPC: Reading from socket\n"); |
|
||||
perror ("ERROR: IPC"); |
|
||||
return IPC_STATUS_ERROR; |
|
||||
} else if (str[0] != BOL_CHAR) { |
|
||||
fprintf (stderr, |
|
||||
"ERROR: IPC: Did not find beginning of message header (%c)\n", |
|
||||
str[0]); |
|
||||
return IPC_STATUS_ERROR; |
|
||||
} else if ((message_length = (int) bytes_to_integer (str, 1)) == -1) { |
|
||||
/* fprintf (stderr, "WARNING: IPC: Reached eof on socket\n"); */ |
|
||||
return handle_socket_eof (); |
|
||||
} else if (message_length == 0) { |
|
||||
*len = 0; |
|
||||
return IPC_STATUS_NO_DATA; |
|
||||
|
|
||||
/* Invalid test... delete - wbk |
|
||||
} else if (message_length > *len) { |
|
||||
fprintf (stderr, |
|
||||
"ERROR: IPC: Buffer (%d) is too short for message (%d)\n", |
|
||||
*len, message_length); |
|
||||
return IPC_STATUS_ERROR; |
|
||||
*/ |
|
||||
|
|
||||
} |
|
||||
|
|
||||
/*-----------------------------------------------------------------------*/ |
|
||||
/* Now read in the message body. */ |
|
||||
/* Always block here since the message header was already read and */ |
|
||||
/* we must get the body. */ |
|
||||
|
|
||||
*len = message_length; |
|
||||
count = read_sock (msg_stream, str, message_length, IPC_WAIT, 0); |
|
||||
if (count == 0) { |
|
||||
/* EOF, will this ever happen? */ |
|
||||
/* fprintf (stderr, */ |
|
||||
/* "WARNING: IPC: Reached eof in message body on socket\n");*/ |
|
||||
return handle_socket_eof (); |
|
||||
} else if (count == -1) { |
|
||||
fprintf (stderr, "ERROR: IPC: reading message body from socket\n"); |
|
||||
perror ("ERROR: IPC"); |
|
||||
return IPC_STATUS_ERROR; |
|
||||
} |
|
||||
|
|
||||
/* Looks like we have a valid message here. Put in the string terminator. */ |
|
||||
*len = count; |
|
||||
str[count] = '\0'; |
|
||||
|
|
||||
return IPC_STATUS_OK; |
|
||||
|
|
||||
} /* end ipc_transport_get_line */ |
|
||||
|
|
||||
|
|
||||
|
|
||||
/*============================================================================= |
|
||||
|
|
||||
FUNCTION ipc_transport_send_line |
|
||||
|
|
||||
AUTHORS |
|
||||
|
|
||||
July 1991 Stefan Roth |
|
||||
|
|
||||
MODIFICATIONS |
|
||||
|
|
||||
NONE |
|
||||
|
|
||||
SUMMARY |
|
||||
Send a line of information. First sends a message header and |
|
||||
then the actual message body. |
|
||||
Error checking is done to make reasonably sure that the data was sent. |
|
||||
|
|
||||
|
|
||||
INTERFACES |
|
||||
|
|
||||
Called by: (IPC.c) ipc_flush (); |
|
||||
|
|
||||
RETURNED VALUE |
|
||||
|
|
||||
Ipc_Status_t - returns status of the send operation (typically |
|
||||
IPC_STATUS_ERROR or IPC_STATUS_OK). |
|
||||
|
|
||||
|
|
||||
GLOBAL VARIABLES |
|
||||
|
|
||||
NONE |
|
||||
|
|
||||
NON-STANDARD FEATURES |
|
||||
|
|
||||
NONE |
|
||||
|
|
||||
=============================================================================*/ |
|
||||
|
|
||||
|
|
||||
Ipc_Status_t |
|
||||
ipc_transport_send_line ( |
|
||||
char *str, /* IN - String to write */ |
|
||||
int len ) /* IN - Number of characters out of STR to write */ |
|
||||
{ |
|
||||
int count; /* Counts how many bytes were actually written */ |
|
||||
u_long u; /* 32-bit placeholder for transmission of LEN */ |
|
||||
char hdr_buff[5]; /* Buffer for building header message in */ |
|
||||
int i; /* Temporary counter */ |
|
||||
char *char_ptr; /* Pointer for int to bytes conversion */ |
|
||||
|
|
||||
if (sock_state != IPC_SOCK_CONNECTED_TO_CLIENT) { |
|
||||
fprintf (stderr, "ERROR: IPC: Attempt to write to non-open socket\n"); |
|
||||
return IPC_STATUS_ERROR; |
|
||||
} |
|
||||
|
|
||||
/* Write message body header with length: */ |
|
||||
hdr_buff[0] = BOL_CHAR; |
|
||||
u = htonl ((uint32_t) len); |
|
||||
char_ptr = (char *) &u; |
|
||||
for(i = 0; i < 4; i++) |
|
||||
hdr_buff[i+1] = char_ptr[i]; |
|
||||
|
|
||||
count = (int) write (msg_stream, hdr_buff, 5); |
|
||||
if (count != 5) { |
|
||||
fprintf (stderr, "ERROR: IPC: (%d) send line error 1\n", count); |
|
||||
return IPC_STATUS_ERROR; |
|
||||
} |
|
||||
|
|
||||
/* Write message body: */ |
|
||||
count = (int) write (msg_stream, str, (size_t) len); |
|
||||
if (count != len) { |
|
||||
fprintf (stderr, "ERROR: IPC: (%d) send line error 2\n", count); |
|
||||
return IPC_STATUS_ERROR; |
|
||||
} |
|
||||
|
|
||||
return IPC_STATUS_OK; |
|
||||
} /* end ipc_transport_send_line */ |
|
||||
|
|
||||
|
|
||||
|
|
||||
/*============================================================================= |
|
||||
|
|
||||
FUNCTION ipc_transport_terminate_server |
|
||||
|
|
||||
AUTHORS |
|
||||
|
|
||||
July 1991 Stefan Roth |
|
||||
|
|
||||
MODIFICATIONS |
|
||||
|
|
||||
NONE |
|
||||
|
|
||||
SUMMARY |
|
||||
|
|
||||
This function reads all pending incoming messages and discards them. |
|
||||
Reading continues until a read error occurs or EOF is reached, at which |
|
||||
time the socket is closed. |
|
||||
Note that this function does not actually close the socket. This is |
|
||||
done in ipc_transport_get_line, which is called in this function. |
|
||||
|
|
||||
In this function, the incoming line length is limited. See buffer below. |
|
||||
|
|
||||
INTERFACES |
|
||||
|
|
||||
Called by: (IPC.c) ipc_terminate_server(); |
|
||||
|
|
||||
RETURNED VALUE |
|
||||
|
|
||||
Ipc_Status_t - returns status of last read operation (always |
|
||||
IPC_STATUS_ERROR or IPC_STATUS_EOF). |
|
||||
|
|
||||
GLOBAL VARIABLES |
|
||||
|
|
||||
NONE |
|
||||
|
|
||||
NON-STANDARD FEATURES |
|
||||
|
|
||||
NONE |
|
||||
|
|
||||
=============================================================================*/ |
|
||||
|
|
||||
|
|
||||
Ipc_Status_t |
|
||||
ipc_transport_terminate_server (void) |
|
||||
{ |
|
||||
char buffer[17000]; /* temp buffer for incoming data */ |
|
||||
int len; /* placeholder var to as arg to function */ |
|
||||
Ipc_Status_t status; /* value to be returned from function */ |
|
||||
int max_size; /* Max length of buffer */ |
|
||||
|
|
||||
max_size = sizeof (buffer); |
|
||||
do { |
|
||||
len = max_size; |
|
||||
status = ipc_transport_get_line (buffer, &len, IPC_WAIT); |
|
||||
} while ((status != IPC_STATUS_ERROR) && |
|
||||
(status != IPC_STATUS_EOF)); |
|
||||
return status; |
|
||||
} |
|
||||
|
|
||||
#endif /* IPC_UNIX_SOCKETS */ |
|
||||
@ -1,77 +0,0 @@ |
|||||
/* |
|
||||
* Steve Tynor |
|
||||
* |
|
||||
* Generic Interprocess Communication module |
|
||||
* |
|
||||
* Used for debugging in absense of IPC interface. |
|
||||
* |
|
||||
*/ |
|
||||
|
|
||||
#include "ngspice/ngspice.h" |
|
||||
|
|
||||
#ifdef IPC_DEBUG_VIA_STDIO |
|
||||
|
|
||||
#include <stdio.h> |
|
||||
|
|
||||
|
|
||||
#include "ngspice/ipc.h" |
|
||||
|
|
||||
#include "ngspice/ipcproto.h" |
|
||||
|
|
||||
#include <assert.h> /* 12/1/97 jg */ |
|
||||
|
|
||||
/*---------------------------------------------------------------------------*/ |
|
||||
Ipc_Status_t ipc_transport_initialize_server ( |
|
||||
char *server_name, |
|
||||
Ipc_Mode_t m, |
|
||||
Ipc_Protocol_t p, |
|
||||
char *batch_filename ) |
|
||||
{ |
|
||||
NG_IGNORE(server_name); |
|
||||
NG_IGNORE(p); |
|
||||
NG_IGNORE(batch_filename); |
|
||||
|
|
||||
assert (m == IPC_MODE_INTERACTIVE); |
|
||||
printf ("INITIALIZE_SERVER\n"); |
|
||||
return IPC_STATUS_OK; |
|
||||
} |
|
||||
|
|
||||
/*---------------------------------------------------------------------------*/ |
|
||||
Ipc_Status_t ipc_transport_get_line ( |
|
||||
char *str, |
|
||||
int *len, |
|
||||
Ipc_Wait_t wait ) |
|
||||
{ |
|
||||
NG_IGNORE(wait); |
|
||||
|
|
||||
printf ("GET_LINE\n"); |
|
||||
fgets (str, 512, stdin); |
|
||||
char *tmp = strchr(str, '\n'); |
|
||||
if (tmp) |
|
||||
*tmp = '\0'; |
|
||||
*len = (int) strlen (str); |
|
||||
return IPC_STATUS_OK; |
|
||||
} |
|
||||
|
|
||||
/*---------------------------------------------------------------------------*/ |
|
||||
Ipc_Status_t ipc_transport_send_line ( |
|
||||
char *str, |
|
||||
int len ) |
|
||||
{ |
|
||||
int i; |
|
||||
|
|
||||
printf ("SEND_LINE: /"); |
|
||||
for (i = 0; i < len; i++) |
|
||||
putchar (str[i]); |
|
||||
printf ("/\n"); |
|
||||
return IPC_STATUS_OK; |
|
||||
} |
|
||||
|
|
||||
/*---------------------------------------------------------------------------*/ |
|
||||
Ipc_Status_t ipc_transport_terminate_server (void) |
|
||||
{ |
|
||||
return IPC_STATUS_OK; |
|
||||
} |
|
||||
|
|
||||
|
|
||||
#endif /* IPC_DEBUG_VIA_STDIO */ |
|
||||
@ -1,520 +0,0 @@ |
|||||
/*============================================================================ |
|
||||
FILE IPCtiein.c |
|
||||
|
|
||||
MEMBER OF process XSPICE |
|
||||
|
|
||||
Public Domain |
|
||||
|
|
||||
Georgia Tech Research Corporation |
|
||||
Atlanta, Georgia 30332 |
|
||||
PROJECT A-8503 |
|
||||
|
|
||||
AUTHORS |
|
||||
|
|
||||
9/12/91 Bill Kuhn |
|
||||
|
|
||||
MODIFICATIONS |
|
||||
|
|
||||
<date> <person name> <nature of modifications> |
|
||||
|
|
||||
SUMMARY |
|
||||
|
|
||||
Provides a protocol independent interface between the simulator |
|
||||
and the IPC method used to interface to CAE packages. |
|
||||
|
|
||||
INTERFACES |
|
||||
|
|
||||
g_ipc (global variable) |
|
||||
|
|
||||
ipc_handle_stop() |
|
||||
ipc_handle_returni() |
|
||||
ipc_handle_mintime() |
|
||||
ipc_handle_vtrans() |
|
||||
ipc_send_stdout() |
|
||||
ipc_send_stderr() |
|
||||
ipc_send_std_files() |
|
||||
ipc_screen_name() |
|
||||
ipc_get_devices() |
|
||||
ipc_free_devices() |
|
||||
ipc_check_pause_stop() |
|
||||
|
|
||||
REFERENCED FILES |
|
||||
|
|
||||
None. |
|
||||
|
|
||||
NON-STANDARD FEATURES |
|
||||
|
|
||||
None. |
|
||||
|
|
||||
============================================================================*/ |
|
||||
|
|
||||
|
|
||||
#define CONFIG |
|
||||
|
|
||||
#include "ngspice/ngspice.h" |
|
||||
#include "ngspice/inpdefs.h" |
|
||||
#include "ngspice/gendefs.h" |
|
||||
#include "ngspice/cktdefs.h" |
|
||||
#include "bjt/bjtdefs.h" |
|
||||
#include "jfet/jfetdefs.h" |
|
||||
#include "mos1/mos1defs.h" |
|
||||
#include "mos2/mos2defs.h" |
|
||||
#include "mos3/mos3defs.h" |
|
||||
#include "ngspice/mifproto.h" |
|
||||
#include "ngspice/ipc.h" |
|
||||
#include "ngspice/ipctiein.h" |
|
||||
|
|
||||
|
|
||||
|
|
||||
/* |
|
||||
Global variable g_ipc is used by the SPICE mods that take care of |
|
||||
interprocess communications activities. |
|
||||
*/ |
|
||||
|
|
||||
|
|
||||
Ipc_Tiein_t g_ipc = { |
|
||||
IPC_FALSE, /* enabled */ |
|
||||
IPC_MODE_INTERACTIVE, /* mode */ |
|
||||
IPC_ANAL_DCOP, /* analysis mode */ |
|
||||
IPC_FALSE, /* parse_error */ |
|
||||
IPC_FALSE, /* run_error */ |
|
||||
IPC_FALSE, /* errchk_sent */ |
|
||||
IPC_FALSE, /* returni */ |
|
||||
0.0, /* mintime */ |
|
||||
0.0, /* lasttime */ |
|
||||
0.0, /* cpu time */ |
|
||||
NULL, /* send array */ |
|
||||
NULL, /* log file */ |
|
||||
{ /* vtrans struct */ |
|
||||
0, /* size */ |
|
||||
NULL, /* vsrc_name array */ |
|
||||
NULL, /* device_name array */ |
|
||||
}, |
|
||||
IPC_FALSE, /* stop analysis */ |
|
||||
}; |
|
||||
|
|
||||
|
|
||||
|
|
||||
/* |
|
||||
ipc_handle_stop |
|
||||
|
|
||||
This function sets a flag in the g_ipc variable to signal that |
|
||||
a stop message has been received over the IPC channel. |
|
||||
*/ |
|
||||
|
|
||||
void ipc_handle_stop(void) |
|
||||
{ |
|
||||
g_ipc.stop_analysis = IPC_TRUE; |
|
||||
} |
|
||||
|
|
||||
|
|
||||
/* |
|
||||
ipc_handle_returni |
|
||||
|
|
||||
This function sets a flag in the g_ipc variable to signal that |
|
||||
a message has been received over the IPC channel specifying that |
|
||||
current values are to be returned in the results data sets. |
|
||||
*/ |
|
||||
|
|
||||
void ipc_handle_returni(void) |
|
||||
{ |
|
||||
g_ipc.returni = IPC_TRUE; |
|
||||
} |
|
||||
|
|
||||
|
|
||||
/* |
|
||||
ipc_handle_mintime |
|
||||
|
|
||||
This function sets a value in the g_ipc variable that specifies |
|
||||
how often data is to be returned as it is computed. If the |
|
||||
simulator takes timestep backups, data may still be returned |
|
||||
more often that that specified by 'mintime' so that glitches |
|
||||
are not missed. |
|
||||
*/ |
|
||||
|
|
||||
void ipc_handle_mintime(double time) |
|
||||
{ |
|
||||
g_ipc.mintime = time; |
|
||||
} |
|
||||
|
|
||||
|
|
||||
|
|
||||
/* |
|
||||
ipc_handle_vtrans |
|
||||
|
|
||||
This function processes arguments from a #VTRANS card received over |
|
||||
the IPC channel. The data on the card specifies that a particular |
|
||||
zero-valued voltage source name should be translated to the specified |
|
||||
instance name for which it was setup to monitor currents. |
|
||||
*/ |
|
||||
|
|
||||
void ipc_handle_vtrans( |
|
||||
char *vsrc, /* The name of the voltage source to be translated */ |
|
||||
char *dev) /* The device name the vsource name should be translated to */ |
|
||||
{ |
|
||||
int i; |
|
||||
int size; |
|
||||
|
|
||||
|
|
||||
if(g_ipc.vtrans.size == 0) { |
|
||||
g_ipc.vtrans.size = 1; |
|
||||
g_ipc.vtrans.vsrc_name = TMALLOC(char *, 1); |
|
||||
g_ipc.vtrans.device_name = TMALLOC(char *, 1); |
|
||||
g_ipc.vtrans.vsrc_name[0] = MIFcopy(vsrc); |
|
||||
g_ipc.vtrans.device_name[0] = MIFcopy(dev); |
|
||||
} |
|
||||
else { |
|
||||
g_ipc.vtrans.size++; |
|
||||
|
|
||||
size = g_ipc.vtrans.size; |
|
||||
i = g_ipc.vtrans.size - 1; |
|
||||
|
|
||||
g_ipc.vtrans.vsrc_name = TREALLOC(char *, g_ipc.vtrans.vsrc_name, size); |
|
||||
g_ipc.vtrans.device_name = TREALLOC(char *, g_ipc.vtrans.device_name, size); |
|
||||
g_ipc.vtrans.vsrc_name[i] = MIFcopy(vsrc); |
|
||||
g_ipc.vtrans.device_name[i] = MIFcopy(dev); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
|
|
||||
|
|
||||
/* |
|
||||
ipc_send_stdout |
|
||||
|
|
||||
This function sends the data written to stdout over the IPC channel. |
|
||||
This stream was previously redirected to a temporary file during |
|
||||
the simulation. |
|
||||
*/ |
|
||||
|
|
||||
void ipc_send_stdout(void) |
|
||||
{ |
|
||||
int c; |
|
||||
int len; |
|
||||
|
|
||||
char buf[IPC_MAX_LINE_LEN+1]; |
|
||||
|
|
||||
/* rewind the redirected stdout stream */ |
|
||||
rewind(stdout); |
|
||||
|
|
||||
/* Begin reading from the top of file and send lines */ |
|
||||
/* over the IPC channel. */ |
|
||||
|
|
||||
/* Don't send newlines. Also, if line is > IPC_MAX_LINE_LEN chars */ |
|
||||
/* we must wrap it because Mspice can't handle it */ |
|
||||
|
|
||||
len = 0; |
|
||||
while( (c=fgetc(stdout)) != EOF) { |
|
||||
if(c != '\n') { |
|
||||
buf[len] = (char) c; |
|
||||
len++; |
|
||||
} |
|
||||
if((c == '\n') || (len == IPC_MAX_LINE_LEN)) { |
|
||||
buf[len] = '\0'; |
|
||||
ipc_send_line(buf); |
|
||||
len = 0; |
|
||||
} |
|
||||
} |
|
||||
if(len > 0) { |
|
||||
buf[len] = '\0'; |
|
||||
ipc_send_line(buf); |
|
||||
} |
|
||||
|
|
||||
/* Finally, rewind file again to discard the data already sent */ |
|
||||
rewind(stdout); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
/* |
|
||||
ipc_send_stderr |
|
||||
|
|
||||
This function sends the data written to stderr over the IPC channel. |
|
||||
This stream was previously redirected to a temporary file during |
|
||||
the simulation. |
|
||||
*/ |
|
||||
|
|
||||
void ipc_send_stderr(void) |
|
||||
{ |
|
||||
int c; |
|
||||
int len; |
|
||||
|
|
||||
char buf[IPC_MAX_LINE_LEN+1]; |
|
||||
|
|
||||
/* rewind the redirected stderr stream */ |
|
||||
rewind(stderr); |
|
||||
|
|
||||
/* Begin reading from the top of file and send lines */ |
|
||||
/* over the IPC channel. */ |
|
||||
|
|
||||
/* Don't send newlines. Also, if line is > IPC_MAX_LINE_LEN chars */ |
|
||||
/* we must wrap it because Mspice can't handle it */ |
|
||||
|
|
||||
len = 0; |
|
||||
while( (c=fgetc(stderr)) != EOF) { |
|
||||
if(c != '\n') { |
|
||||
buf[len] = (char) c; |
|
||||
len++; |
|
||||
} |
|
||||
if((c == '\n') || (len == IPC_MAX_LINE_LEN)) { |
|
||||
buf[len] = '\0'; |
|
||||
ipc_send_line(buf); |
|
||||
len = 0; |
|
||||
} |
|
||||
} |
|
||||
if(len > 0) { |
|
||||
buf[len] = '\0'; |
|
||||
ipc_send_line(buf); |
|
||||
} |
|
||||
|
|
||||
/* Finally, rewind file again to discard the data already sent */ |
|
||||
rewind(stderr); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
/* |
|
||||
ipc_send_std_files |
|
||||
|
|
||||
This function sends the data written to stdout and stderr over the |
|
||||
IPC channel. These streams were previously redirected to temporary |
|
||||
files during the simulation. |
|
||||
*/ |
|
||||
|
|
||||
Ipc_Status_t ipc_send_std_files(void) |
|
||||
{ |
|
||||
ipc_send_stdout(); |
|
||||
ipc_send_stderr(); |
|
||||
|
|
||||
return(ipc_flush()); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
|
|
||||
/* |
|
||||
ipc_screen_name |
|
||||
|
|
||||
This function screens names of instances and nodes to limit the |
|
||||
data returned over the IPC channel. |
|
||||
*/ |
|
||||
|
|
||||
Ipc_Boolean_t ipc_screen_name(char *name, char *mapped_name) |
|
||||
{ |
|
||||
char *endp; |
|
||||
int i; |
|
||||
int len; |
|
||||
long l; |
|
||||
|
|
||||
/* Return FALSE if name is in a subcircuit */ |
|
||||
for(i = 0; name[i] != '\0'; i++) { |
|
||||
if(name[i] == ':') |
|
||||
return(IPC_FALSE); |
|
||||
} |
|
||||
|
|
||||
/* Determine if name is numeric and what value is */ |
|
||||
l = strtol(name, &endp, 10); |
|
||||
|
|
||||
/* If numeric */ |
|
||||
if(*endp == '\0') { |
|
||||
/* Return FALSE if >100,000 -> added by ms_server in ATESSE 1.0 */ |
|
||||
if(l >= 100000) |
|
||||
return(IPC_FALSE); |
|
||||
/* Otherwise, copy name to mapped name and return true */ |
|
||||
else { |
|
||||
strcpy(mapped_name,name); |
|
||||
return(IPC_TRUE); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
/* If node is an internal node from a semiconductor (indicated by a */ |
|
||||
/* trailing #collector, #source, ...), do not return its current. */ |
|
||||
/* Otherwise, map to upper case and eliminate trailing "#branch" if any. */ |
|
||||
for(i = 0; name[i]; i++) { |
|
||||
if(name[i] == '#') { |
|
||||
if(strcmp(name + i, "#branch") == 0) |
|
||||
break; |
|
||||
else |
|
||||
return(IPC_FALSE); |
|
||||
} |
|
||||
else { |
|
||||
if(islower_c(name[i])) |
|
||||
mapped_name[i] = toupper_c(name[i]); |
|
||||
else |
|
||||
mapped_name[i] = name[i]; |
|
||||
} |
|
||||
} |
|
||||
mapped_name[i] = '\0'; |
|
||||
len = i; |
|
||||
|
|
||||
/* If len != 8 or 6'th char not equal to $, then doesn't need vtrans */ |
|
||||
/* Otherwise, translate to device name that it monitors */ |
|
||||
if(len != 8) |
|
||||
return(IPC_TRUE); |
|
||||
else if(name[5] != '$') |
|
||||
return(IPC_TRUE); |
|
||||
else { |
|
||||
/* Scan list of prefixes in VTRANS table and convert name */ |
|
||||
for(i = 0; i < g_ipc.vtrans.size; i++) { |
|
||||
if(strncmp(mapped_name, g_ipc.vtrans.vsrc_name[i], 5) == 0) { |
|
||||
strcpy(mapped_name, g_ipc.vtrans.device_name[i]); |
|
||||
return(IPC_TRUE); |
|
||||
} |
|
||||
} |
|
||||
return(IPC_TRUE); |
|
||||
} |
|
||||
|
|
||||
} |
|
||||
|
|
||||
|
|
||||
|
|
||||
/* |
|
||||
ipc_get_devices |
|
||||
|
|
||||
This function is used to setup the OUTinterface data structure that |
|
||||
determines what instances will have data returned over the IPC channel. |
|
||||
*/ |
|
||||
|
|
||||
|
|
||||
int ipc_get_devices( |
|
||||
CKTcircuit *ckt, /* The circuit structure */ |
|
||||
char *device, /* The device name as it appears in the info struct */ |
|
||||
char ***names, /* Array of name strings to be built */ |
|
||||
double **modtypes) /* Array of types to be built */ |
|
||||
{ |
|
||||
int index; |
|
||||
int num_instances; |
|
||||
GENmodel *model; |
|
||||
GENinstance *here; |
|
||||
char *inst_name; |
|
||||
int inst_name_len; |
|
||||
int i; |
|
||||
|
|
||||
BJTmodel *BJTmod; |
|
||||
JFETmodel *JFETmod; |
|
||||
MOS1model *MOS1mod; |
|
||||
MOS2model *MOS2mod; |
|
||||
MOS3model *MOS3mod; |
|
||||
|
|
||||
/* Initialize local variables */ |
|
||||
num_instances = 0; |
|
||||
|
|
||||
/* Get the index into the circuit structure linked list of models */ |
|
||||
index = INPtypelook(device); |
|
||||
|
|
||||
/* Iterate through all models of this type */ |
|
||||
for(model = ckt->CKThead[index]; model; model = model->GENnextModel) { |
|
||||
|
|
||||
/* Iterate through all instance of this model */ |
|
||||
for(here = model->GENinstances; here; here = here->GENnextInstance) { |
|
||||
|
|
||||
/* Get the name of the instance */ |
|
||||
inst_name = here->GENname; |
|
||||
inst_name_len = (int) strlen(inst_name); |
|
||||
|
|
||||
/* Skip if it is a inside a subcircuit */ |
|
||||
for(i = 0; i < inst_name_len; i++) |
|
||||
if(inst_name[i] == ':') |
|
||||
break; |
|
||||
if(i < inst_name_len) |
|
||||
continue; |
|
||||
|
|
||||
/* Otherwise, add the name to the list */ |
|
||||
num_instances++; |
|
||||
if(num_instances == 1) |
|
||||
*names = TMALLOC(char *, 1); |
|
||||
else |
|
||||
*names = TREALLOC(char *, *names, num_instances); |
|
||||
(*names)[num_instances-1] = MIFcopy(inst_name); |
|
||||
|
|
||||
/* Then get the type if it is a Q J or M */ |
|
||||
if(num_instances == 1) |
|
||||
*modtypes = TMALLOC(double, 1); |
|
||||
else |
|
||||
*modtypes = TREALLOC(double, *modtypes, num_instances); |
|
||||
|
|
||||
if(strcmp(device,"BJT") == 0) { |
|
||||
BJTmod = (BJTmodel *) model; |
|
||||
(*modtypes)[num_instances-1] = BJTmod->BJTtype; |
|
||||
} |
|
||||
else if(strcmp(device,"JFET") == 0) { |
|
||||
JFETmod = (JFETmodel *) model; |
|
||||
(*modtypes)[num_instances-1] = JFETmod->JFETtype; |
|
||||
} |
|
||||
else if(strcmp(device,"Mos1") == 0) { |
|
||||
MOS1mod = (MOS1model *) model; |
|
||||
(*modtypes)[num_instances-1] = MOS1mod->MOS1type; |
|
||||
} |
|
||||
else if(strcmp(device,"Mos2") == 0) { |
|
||||
MOS2mod = (MOS2model *) model; |
|
||||
(*modtypes)[num_instances-1] = MOS2mod->MOS2type; |
|
||||
} |
|
||||
else if(strcmp(device,"Mos3") == 0) { |
|
||||
MOS3mod = (MOS3model *) model; |
|
||||
(*modtypes)[num_instances-1] = MOS3mod->MOS3type; |
|
||||
} |
|
||||
else { |
|
||||
(*modtypes)[num_instances-1] = 1.0; |
|
||||
} |
|
||||
|
|
||||
} /* end for all instances */ |
|
||||
} /* end for all models */ |
|
||||
|
|
||||
return(num_instances); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
|
|
||||
/* |
|
||||
ipc_free_devices |
|
||||
|
|
||||
This function frees temporary data created by ipc_get_devices(). |
|
||||
*/ |
|
||||
|
|
||||
|
|
||||
void ipc_free_devices( |
|
||||
int num_items, /* Number of things to free */ |
|
||||
char **names, /* Array of name strings to be built */ |
|
||||
double *modtypes) /* Array of types to be built */ |
|
||||
{ |
|
||||
int i; |
|
||||
|
|
||||
for(i = 0; i < num_items; i++) |
|
||||
{ |
|
||||
FREE(names[i]); |
|
||||
names[i] = NULL; |
|
||||
} |
|
||||
|
|
||||
if(num_items > 0) |
|
||||
{ |
|
||||
FREE(names); |
|
||||
FREE(modtypes); |
|
||||
|
|
||||
names = NULL; |
|
||||
modtypes = NULL; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
|
|
||||
/* |
|
||||
ipc_check_pause_stop |
|
||||
|
|
||||
This function is called at various times during a simulation to check |
|
||||
for incoming messages of the form >STOP or >PAUSE signaling that |
|
||||
simulation should be stopped or paused. Processing of the messages |
|
||||
is handled by ipc_get_line(). |
|
||||
*/ |
|
||||
|
|
||||
void ipc_check_pause_stop(void) |
|
||||
{ |
|
||||
char buf[1025]; |
|
||||
int len; |
|
||||
|
|
||||
/* If already seen stop analysis, don't call ipc_get_line, just return. */ |
|
||||
/* This is provided so that the function can be called multiple times */ |
|
||||
/* during the process of stopping */ |
|
||||
if(g_ipc.stop_analysis) |
|
||||
return; |
|
||||
|
|
||||
/* Otherwise do a non-blocking call to ipc_get_line() to check for messages. */ |
|
||||
/* We assume that the only possible messages at this point are >PAUSE */ |
|
||||
/* and >STOP, so we don't do anything with the returned text if any */ |
|
||||
ipc_get_line(buf, &len, IPC_NO_WAIT); |
|
||||
} |
|
||||
|
|
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue