Merge branch 'BufferedConsole' into simhv3.8-2.rc2

Conflicts:
	scp.c
	sim_console.c
	sim_tmxr.c
This commit is contained in:
Mark Pizzolato 2011-04-15 09:22:37 -07:00
commit 87157dc737
6 changed files with 483 additions and 124 deletions

4
scp.c
View file

@ -395,10 +395,10 @@ static uint32 sim_rtime;
static int32 noqueue_time;
volatile int32 stop_cpu = 0;
t_value *sim_eval = NULL;
int32 sim_deb_close = 0; /* 1 = close debug */
FILE *sim_log = NULL; /* log file */
FILEREF *sim_log_ref = NULL; /* log file file reference */
FILE *sim_deb = NULL; /* debug file */
FILEREF *sim_deb_ref = NULL; /* debug file file reference */
static FILE *sim_gotofile;
static int32 sim_do_depth = 0;

View file

@ -23,7 +23,27 @@
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
20-Jan-11 MP Added support for BREAK key on Windows
20-Jan-11 MP Fixed support for BREAK key on Windows to account
for/ignore other keyboard Meta characters.
18-Jan-11 MP Added log file reference count support
17-Jan-11 MP Added support for a "Buffered" behaviors which include:
- If Buffering is enabled and Telnet is enabled, a
telnet connection is not required for simulator
operation (instruction execution).
- If Buffering is enabled, all console output is
written to the buffer at all times (deleting the
oldest buffer contents on overflow).
- when a connection is established on the console
telnet port, the whole contents of the Buffer is
presented on the telnet session and connection
will then proceed as if the connection had always
been there.
This concept allows a simulator to run in the background
and when needed a console session to be established.
The "when needed" case usually will be interested in
what already happened before looking to address what
to do, hence the buffer contents being presented.
28-Dec-10 MP Added support for BREAK key on Windows
30-Sep-06 RMS Fixed non-printable characters in KSR mode
22-Jun-06 RMS Implemented SET/SHOW PCHAR
31-May-06 JDB Fixed bug if SET CONSOLE DEBUG with no argument
@ -63,6 +83,12 @@
sim_putchar_s - output character to console, stall if congested
sim_set_console - set console parameters
sim_show_console - show console parameters
sim_set_cons_buff - set console buffered
sim_set_cons_unbuff -set console unbuffered
sim_set_cons_log - set console log
sim_set_cons_nolog - set console nolog
sim_show_cons_buff - show console buffered
sim_show_cons_log - show console log
sim_tt_inpcvt - convert input character per mode
sim_tt_outcvt - convert output character per mode
@ -105,8 +131,9 @@ TMLN sim_con_ldsc = { 0 }; /* console line descr */
TMXR sim_con_tmxr = { 1, 0, 0, &sim_con_ldsc }; /* console line mux */
extern volatile int32 stop_cpu;
extern int32 sim_quiet, sim_deb_close;
extern int32 sim_quiet;
extern FILE *sim_log, *sim_deb;
extern FILEREF *sim_log_ref, *sim_deb_ref;
extern DEVICE *sim_devices[];
/* Set/show data structures */
@ -130,9 +157,19 @@ static SHTAB show_con_tab[] = {
{ "BRK", &sim_show_kmap, KMAP_BRK },
{ "DEL", &sim_show_kmap, KMAP_DEL },
{ "PCHAR", &sim_show_pchar, 0 },
{ "LOG", &sim_show_log, 0 },
{ "LOG", &sim_show_cons_log, 0 },
{ "TELNET", &sim_show_telnet, 0 },
{ "DEBUG", &sim_show_debug, 0 },
{ "BUFFERED", &sim_show_cons_buff, 0 },
{ NULL, NULL, 0 }
};
static CTAB set_con_telnet_tab[] = {
{ "LOG", &sim_set_cons_log, 0 },
{ "NOLOG", &sim_set_cons_nolog, 0 },
{ "BUFFERED", &sim_set_cons_buff, 0 },
{ "NOBUFFERED", &sim_set_cons_unbuff, 0 },
{ "UNBUFFERED", &sim_set_cons_unbuff, 0 },
{ NULL, NULL, 0 }
};
@ -262,6 +299,7 @@ return SCPE_OK;
t_stat sim_set_logon (int32 flag, char *cptr)
{
char gbuf[CBUFSIZE];
t_stat r;
if ((cptr == NULL) || (*cptr == 0)) /* need arg */
return SCPE_2FARG;
@ -269,12 +307,14 @@ cptr = get_glyph_nc (cptr, gbuf, 0); /* get file name */
if (*cptr != 0) /* now eol? */
return SCPE_2MARG;
sim_set_logoff (0, NULL); /* close cur log */
sim_log = sim_fopen (gbuf, "a"); /* open log */
if (sim_log == NULL) /* error? */
return SCPE_OPENERR;
r = sim_open_logfile (gbuf, FALSE, &sim_log, &sim_log_ref); /* open log */
if (r != SCPE_OK) /* error? */
return r;
if (!sim_quiet)
printf ("Logging to file \"%s\"\n", gbuf);
fprintf (sim_log, "Logging to file \"%s\"\n", gbuf); /* start of log */
printf ("Logging to file \"%s\"\n",
sim_logfile_name (sim_log, sim_log_ref));
fprintf (sim_log, "Logging to file \"%s\"\n",
sim_logfile_name (sim_log, sim_log_ref)); /* start of log */
return SCPE_OK;
}
@ -288,8 +328,8 @@ if (sim_log == NULL) /* no log? */
return SCPE_OK;
if (!sim_quiet)
printf ("Log file closed\n");
fprintf (sim_log, "Log file closed\n"); /* close log */
fclose (sim_log);
fprintf (sim_log, "Log file closed\n");
sim_close_logfile (&sim_log_ref); /* close log */
sim_log = NULL;
return SCPE_OK;
}
@ -301,8 +341,8 @@ t_stat sim_show_log (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr)
if (cptr && (*cptr != 0))
return SCPE_2MARG;
if (sim_log)
fputs ("Logging enabled\n", st);
else fputs ("Logging disabled\n", st);
fprintf (st, "Logging enabled to %s\n", sim_logfile_name (sim_log, sim_log_ref));
else fprintf (st, "Logging disabled\n");
return SCPE_OK;
}
@ -310,34 +350,24 @@ return SCPE_OK;
t_stat sim_set_debon (int32 flag, char *cptr)
{
char *tptr, gbuf[CBUFSIZE];
char gbuf[CBUFSIZE];
t_stat r;
if ((cptr == NULL) || (*cptr == 0)) /* too few arguments? */
if ((cptr == NULL) || (*cptr == 0)) /* need arg */
return SCPE_2FARG;
tptr = get_glyph (cptr, gbuf, 0); /* get file name */
if (*tptr != 0) /* now eol? */
cptr = get_glyph_nc (cptr, gbuf, 0); /* get file name */
if (*cptr != 0) /* now eol? */
return SCPE_2MARG;
sim_set_deboff (0, NULL); /* close cur debug */
if (strcmp (gbuf, "LOG") == 0) { /* debug to log? */
if (sim_log == NULL) /* any log? */
return SCPE_ARG;
sim_deb = sim_log;
}
else if (strcmp (gbuf, "STDOUT") == 0) /* debug to stdout? */
sim_deb = stdout;
else if (strcmp (gbuf, "STDERR") == 0) /* debug to stderr? */
sim_deb = stderr;
else {
cptr = get_glyph_nc (cptr, gbuf, 0); /* reparse */
sim_deb = sim_fopen (gbuf, "a"); /* open debug */
if (sim_deb == NULL) /* error? */
return SCPE_OPENERR;
sim_deb_close = 1; /* need close */
}
r = sim_open_logfile (gbuf, FALSE, &sim_deb, &sim_deb_ref);
if (r != SCPE_OK)
return r;
if (!sim_quiet)
printf ("Debug output to \"%s\"\n", gbuf);
printf ("Debug output to \"%s\"\n",
sim_logfile_name (sim_deb, sim_deb_ref));
if (sim_log)
fprintf (sim_log, "Debug output to \"%s\"\n", gbuf);
fprintf (sim_log, "Debug output to \"%s\"\n",
sim_logfile_name (sim_deb, sim_deb_ref));
return SCPE_OK;
}
@ -345,18 +375,18 @@ return SCPE_OK;
t_stat sim_set_deboff (int32 flag, char *cptr)
{
t_stat r;
if (cptr && (*cptr != 0)) /* now eol? */
return SCPE_2MARG;
if (sim_deb == NULL) /* no log? */
return SCPE_OK;
r = sim_close_logfile (&sim_deb_ref);
sim_deb = NULL;
if (!sim_quiet)
printf ("Debug output disabled\n");
if (sim_log)
fprintf (sim_log, "Debug output disabled\n");
if (sim_deb_close) /* close if needed */
fclose (sim_deb);
sim_deb_close = 0;
sim_deb = NULL;
return SCPE_OK;
}
@ -367,20 +397,41 @@ t_stat sim_show_debug (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cpt
if (cptr && (*cptr != 0))
return SCPE_2MARG;
if (sim_deb)
fputs ("Debug output enabled\n", st);
else fputs ("Debug output disabled\n", st);
fprintf (st, "Debug output enabled\n", sim_logfile_name (sim_deb, sim_deb_ref));
else fprintf (st, "Debug output disabled\n");
return SCPE_OK;
}
/* Set console to Telnet port */
/* SET CONSOLE command */
t_stat sim_set_telnet (int32 flg, char *cptr)
/* Set console to Telnet port (and parameters) */
t_stat sim_set_telnet (int32 flag, char *cptr)
{
if ((cptr == NULL) || (*cptr == 0)) /* too few arguments? */
char *cvptr, gbuf[CBUFSIZE];
CTAB *ctptr;
t_stat r;
if ((cptr == NULL) || (*cptr == 0))
return SCPE_2FARG;
if (sim_con_tmxr.master) /* already open? */
return SCPE_ALATT;
return tmxr_open_master (&sim_con_tmxr, cptr); /* open master socket */
while (*cptr != 0) { /* do all mods */
cptr = get_glyph_nc (cptr, gbuf, ','); /* get modifier */
if (cvptr = strchr (gbuf, '=')) /* = value? */
*cvptr++ = 0;
get_glyph (gbuf, gbuf, 0); /* modifier to UC */
if (isdigit (*gbuf)) {
if (sim_con_tmxr.master) return SCPE_ALATT; /* already open? */
return tmxr_open_master (&sim_con_tmxr, gbuf); /* open master socket */
}
else
if (ctptr = find_ctab (set_con_telnet_tab, gbuf)) { /* match? */
r = ctptr->action (ctptr->arg, cvptr); /* do the rest */
if (r != SCPE_OK)
return r;
}
else return SCPE_NOPARAM;
}
return SCPE_OK;
}
/* Close console Telnet port */
@ -402,17 +453,167 @@ if (cptr && (*cptr != 0))
return SCPE_2MARG;
if (sim_con_tmxr.master == 0)
fprintf (st, "Connected to console window\n");
else if (sim_con_ldsc.conn == 0)
else {
if (sim_con_ldsc.conn == 0)
fprintf (st, "Listening on port %d\n", sim_con_tmxr.port);
else {
fprintf (st, "Listening on port %d, connected to socket %d\n",
sim_con_tmxr.port, sim_con_ldsc.conn);
tmxr_fconns (st, &sim_con_ldsc, -1);
}
tmxr_fstats (st, &sim_con_ldsc, -1);
}
return SCPE_OK;
}
/* Set console to Buffering */
t_stat sim_set_cons_buff (int32 flg, char *cptr)
{
char cmdbuf[CBUFSIZE];
sprintf(cmdbuf, "BUFFERED%c%s", cptr ? '=' : '\0', cptr ? cptr : "");
return tmxr_open_master (&sim_con_tmxr, cmdbuf); /* open master socket */
}
/* Set console to NoBuffering */
t_stat sim_set_cons_unbuff (int32 flg, char *cptr)
{
char cmdbuf[CBUFSIZE];
sprintf(cmdbuf, "UNBUFFERED%c%s", cptr ? '=' : '\0', cptr ? cptr : "");
return tmxr_open_master (&sim_con_tmxr, cmdbuf); /* open master socket */
}
/* Set console to Logging */
t_stat sim_set_cons_log (int32 flg, char *cptr)
{
char cmdbuf[CBUFSIZE];
sprintf(cmdbuf, "LOG%c%s", cptr ? '=' : '\0', cptr ? cptr : "");
return tmxr_open_master (&sim_con_tmxr, cmdbuf); /* open master socket */
}
/* Set console to NoLogging */
t_stat sim_set_cons_nolog (int32 flg, char *cptr)
{
char cmdbuf[CBUFSIZE];
sprintf(cmdbuf, "NOLOG%c%s", cptr ? '=' : '\0', cptr ? cptr : "");
return tmxr_open_master (&sim_con_tmxr, cmdbuf); /* open master socket */
}
t_stat sim_show_cons_log (FILE *st, DEVICE *dunused, UNIT *uunused, int32 flag, char *cptr)
{
if (cptr && (*cptr != 0))
return SCPE_2MARG;
if (sim_con_tmxr.ldsc->txlog)
fprintf (st, "Log File being written to %s\n", sim_con_tmxr.ldsc->txlogname);
else
fprintf (st, "No Logging\n");
return SCPE_OK;
}
t_stat sim_show_cons_buff (FILE *st, DEVICE *dunused, UNIT *uunused, int32 flag, char *cptr)
{
if (cptr && (*cptr != 0))
return SCPE_2MARG;
if (!sim_con_tmxr.buffered)
fprintf (st, "Unbuffered\n");
else
fprintf (st, "Buffer Size = %d\n", sim_con_tmxr.buffered);
return SCPE_OK;
}
/* Log File Open/Close/Show Support */
/* Open log file */
t_stat sim_open_logfile (char *filename, t_bool binary, FILE **pf, FILEREF **pref)
{
char *tptr, gbuf[CBUFSIZE];
*pref = NULL;
if ((filename == NULL) || (*filename == 0)) /* too few arguments? */
return SCPE_2FARG;
tptr = get_glyph (filename, gbuf, 0);
if (*tptr != 0) /* now eol? */
return SCPE_2MARG;
sim_close_logfile (pref);
*pf = NULL;
if (strcmp (gbuf, "LOG") == 0) { /* output to log? */
if (sim_log == NULL) /* any log? */
return SCPE_ARG;
*pf = sim_log;
*pref = sim_log_ref;
if (*pref)
++(*pref)->refcount;
}
else if (strcmp (gbuf, "DEBUG") == 0) { /* output to debug? */
if (sim_debug == NULL) /* any debug? */
return SCPE_ARG;
*pf = sim_deb;
*pref = sim_deb_ref;
if (*pref)
++(*pref)->refcount;
}
else if (strcmp (gbuf, "STDOUT") == 0) /* output to stdout? */
*pf = stdout;
else if (strcmp (gbuf, "STDERR") == 0) /* output to stderr? */
*pf = stderr;
else {
*pref = calloc (1, sizeof(**pref));
if (!*pref)
return SCPE_MEM;
get_glyph_nc (filename, gbuf, 0); /* reparse */
strncpy ((*pref)->name, gbuf, sizeof((*pref)->name)-1);
*pf = sim_fopen (gbuf, (binary ? "ab" : "a")); /* open file */
if (*pf == NULL) { /* error? */
free (*pref);
*pref = NULL;
return SCPE_OPENERR;
}
(*pref)->file = *pf;
(*pref)->refcount = 1; /* need close */
}
return SCPE_OK;
}
/* Close log file */
t_stat sim_close_logfile (FILEREF **pref)
{
if (NULL == *pref)
return SCPE_OK;
(*pref)->refcount = (*pref)->refcount - 1;
if ((*pref)->refcount > 0)
return SCPE_OK;
fclose ((*pref)->file);
free (*pref);
*pref = NULL;
return SCPE_OK;
}
/* Show logfile support routine */
const char *sim_logfile_name (FILE *st, FILEREF *ref)
{
if (!st)
return "";
if (st == stdout)
return "STDOUT";
if (st == stderr)
return "STDERR";
if (!ref)
return "";
return ref->name;
}
/* Check connection before executing */
t_stat sim_check_console (int32 sec)
@ -421,11 +622,16 @@ int32 c, i;
if (sim_con_tmxr.master == 0) /* not Telnet? done */
return SCPE_OK;
if (sim_con_ldsc.conn) { /* connected? */
if (sim_con_ldsc.conn || sim_con_ldsc.txbfd) { /* connected or buffered ? */
tmxr_poll_rx (&sim_con_tmxr); /* poll (check disconn) */
if (sim_con_ldsc.conn) /* still connected? */
if (sim_con_ldsc.conn || sim_con_ldsc.txbfd) { /* still connected? */
if (!sim_con_ldsc.conn) {
printf ("Running with Buffered Console\n"); /* print transition */
fflush (stdout);
}
return SCPE_OK;
}
}
for (i = 0; i < sec; i++) { /* loop */
if (tmxr_poll_conn (&sim_con_tmxr) >= 0) { /* poll connect */
sim_con_ldsc.rcve = 1; /* rcv enabled */
@ -456,8 +662,14 @@ int32 c;
c = sim_os_poll_kbd (); /* get character */
if ((c == SCPE_STOP) || (sim_con_tmxr.master == 0)) /* ^E or not Telnet? */
return c; /* in-window */
if (sim_con_ldsc.conn == 0) /* no Telnet conn? */
return SCPE_LOST;
if (sim_con_ldsc.conn == 0) { /* no Telnet conn? */
if (!sim_con_ldsc.txbfd) /* unbuffered? */
return SCPE_LOST; /* connection lost */
if (tmxr_poll_conn (&sim_con_tmxr) >= 0) /* poll connect */
sim_con_ldsc.rcve = 1; /* rcv enabled */
else /* fall through to poll reception */
return SCPE_OK; /* unconnected and buffered - nothing to receive */
}
tmxr_poll_rx (&sim_con_tmxr); /* poll for input */
if (c = tmxr_getc_ln (&sim_con_ldsc)) /* any char? */
return (c & (SCPE_BREAK | 0377)) | SCPE_KFLAG;
@ -468,12 +680,19 @@ return SCPE_OK;
t_stat sim_putchar (int32 c)
{
if (sim_con_tmxr.master == 0) { /* not Telnet? */
if (sim_log) /* log file? */
fputc (c, sim_log);
if (sim_con_tmxr.master == 0) /* not Telnet? */
return sim_os_putchar (c); /* in-window version */
if (sim_con_ldsc.conn == 0) /* no Telnet conn? */
return SCPE_LOST;
}
if (sim_log && !sim_con_ldsc.txlog) /* log file, but no line log? */
fputc (c, sim_log);
if (sim_con_ldsc.conn == 0) { /* no Telnet conn? */
if (!sim_con_ldsc.txbfd) /* unbuffered? */
return SCPE_LOST; /* connection lost */
if (tmxr_poll_conn (&sim_con_tmxr) >= 0) /* poll connect */
sim_con_ldsc.rcve = 1; /* rcv enabled */
}
tmxr_putc_ln (&sim_con_ldsc, c); /* output char */
tmxr_poll_tx (&sim_con_tmxr); /* poll xmt */
return SCPE_OK;
@ -486,8 +705,12 @@ t_stat r;
if (sim_log) fputc (c, sim_log); /* log file? */
if (sim_con_tmxr.master == 0) /* not Telnet? */
return sim_os_putchar (c); /* in-window version */
if (sim_con_ldsc.conn == 0) /* no Telnet conn? */
return SCPE_LOST;
if (sim_con_ldsc.conn == 0) { /* no Telnet conn? */
if (!sim_con_ldsc.txbfd) /* non-buffered Telnet conn? */
return SCPE_LOST; /* lost */
if (tmxr_poll_conn (&sim_con_tmxr) >= 0) /* poll connect */
sim_con_ldsc.rcve = 1; /* rcv enabled */
}
if (sim_con_ldsc.xmte == 0) /* xmt disabled? */
r = SCPE_STALL;
else r = tmxr_putc_ln (&sim_con_ldsc, c); /* no, Telnet output */

View file

@ -23,6 +23,7 @@
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
17-Jan-11 MP Added buffered line capabilities
22-Jun-06 RMS Implemented SET/SHOW PCHAR
22-Nov-05 RMS Added central input/output conversion support
05-Nov-04 RMS Moved SET/SHOW DEBUG under CONSOLE hierarchy
@ -57,6 +58,10 @@ t_stat sim_set_notelnet (int32 flag, char *cptr);
t_stat sim_set_logon (int32 flag, char *cptr);
t_stat sim_set_logoff (int32 flag, char *cptr);
t_stat sim_set_debon (int32 flag, char *cptr);
t_stat sim_set_cons_buff (int32 flg, char *cptr);
t_stat sim_set_cons_unbuff (int32 flg, char *cptr);
t_stat sim_set_cons_log (int32 flg, char *cptr);
t_stat sim_set_cons_nolog (int32 flg, char *cptr);
t_stat sim_set_deboff (int32 flag, char *cptr);
t_stat sim_set_pchar (int32 flag, char *cptr);
t_stat sim_show_console (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr);
@ -65,7 +70,12 @@ t_stat sim_show_telnet (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cp
t_stat sim_show_log (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr);
t_stat sim_show_debug (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr);
t_stat sim_show_pchar (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr);
t_stat sim_show_cons_buff (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr);
t_stat sim_show_cons_log (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr);
t_stat sim_check_console (int32 sec);
t_stat sim_open_logfile (char *filename, t_bool binary, FILE **pf, FILEREF **pref);
t_stat sim_close_logfile (FILEREF **pref);
const char *sim_logfile_name (FILE *st, FILEREF *ref);
t_stat sim_poll_kbd (void);
t_stat sim_putchar (int32 c);
t_stat sim_putchar_s (int32 c);

View file

@ -23,6 +23,7 @@
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
18-Jan-11 MP Added log file reference count support
21-Jul-08 RMS Removed inlining support
28-May-08 RMS Added inlining support
28-Jun-07 RMS Added IA64 VMS support (from Norm Lastovica)
@ -486,6 +487,13 @@ struct sim_debtab {
#define DEBUG_PRI(d,m) (sim_deb && (d.dctrl & (m)))
#define DEBUG_PRJ(d,m) (sim_deb && (d->dctrl & (m)))
/* File Reference */
struct sim_fileref {
char name[CBUFSIZE]; /* file name */
FILE *file; /* file handle */
int32 refcount; /* reference count */
};
/* The following macros define structure contents */
#define UDATA(act,fl,cap) NULL,act,NULL,NULL,NULL,0,0,(fl),(cap),0,0
@ -522,6 +530,7 @@ typedef struct sim_mtab MTAB;
typedef struct sim_schtab SCHTAB;
typedef struct sim_brktab BRKTAB;
typedef struct sim_debtab DEBTAB;
typedef struct sim_fileref FILEREF;
/* Function prototypes */

View file

@ -26,6 +26,7 @@
Based on the original DZ11 simulator by Thord Nilson, as updated by
Arthur Krewat.
17-Jan-11 MP Added Buffered line capabilities
16-Jan-11 MP Made option negotiation more reliable
20-Nov-08 RMS Added three new standardized SHOW routines
30-Sep-08 JDB Reverted tmxr_find_ldsc to original implementation
@ -154,9 +155,12 @@ int32 tmxr_poll_conn (TMXR *mp)
SOCKET newsock;
TMLN *lp;
int32 *op;
int32 i, j;
int32 i, j, psave;
uint32 ipaddr;
char cmsg[80];
char dmsg[80] = "";
char lmsg[80] = "";
char msgbuf[256];
static char mantra[] = {
TN_IAC, TN_WILL, TN_LINE,
TN_IAC, TN_WILL, TN_SGA,
@ -189,34 +193,38 @@ if (newsock != INVALID_SOCKET) { /* got a live one? */
lp = mp->ldsc + i; /* get line desc */
lp->conn = newsock; /* record connection */
lp->ipad = ipaddr; /* ip address */
sim_write_sock (newsock, mantra, sizeof(mantra));
sprintf (cmsg, "\n\r\nConnected to the %s simulator ", sim_name);
if (mp->dptr) { /* device defined? */
sprintf (dmsg, "%s device", /* report device name */
sim_dname (mp->dptr));
if (mp->lines > 1) /* more than one line? */
sprintf (lmsg, ", line %d", i); /* report the line number */
}
sprintf (msgbuf, "%s%s%s\r\n\n", cmsg, dmsg, lmsg);
lp->cnms = sim_os_msec (); /* time of conn */
lp->rxbpr = lp->rxbpi = 0; /* init buf pointers */
lp->txbpr = lp->txbpi = 0;
lp->rxcnt = lp->txcnt = 0; /* init counters */
if (!mp->buffered) {
lp->txbpi = 0; /* init buf pointers */
lp->txbpr = lp->txbsz - strlen (msgbuf);
lp->rxcnt = lp->txcnt = lp->txdrp = 0; /* init counters */
}
else
if (lp->txcnt > lp->txbsz)
lp->txbpr = (lp->txbpi + 1) % lp->txbsz;
else
lp->txbpr = lp->txbsz - strlen (msgbuf);
lp->tsta = 0; /* init telnet state */
lp->xmte = 1; /* enable transmit */
lp->dstb = 0; /* default bin mode */
sim_write_sock (newsock, mantra, sizeof (mantra));
tmxr_linemsg (lp, "\n\r\nConnected to the ");
tmxr_linemsg (lp, sim_name);
tmxr_linemsg (lp, " simulator ");
if (mp->dptr) { /* device defined? */
tmxr_linemsg (lp, sim_dname (mp->dptr)); /* report device name */
tmxr_linemsg (lp, " device");
if (mp->lines > 1) { /* more than one line? */
char line[20];
tmxr_linemsg (lp, ", line "); /* report the line number */
sprintf (line, "%i", i);
tmxr_linemsg (lp, line);
}
}
tmxr_linemsg (lp, "\r\n\n");
psave = lp->txbpi; /* save insertion pointer */
lp->txbpi = lp->txbpr; /* insert connection message */
tmxr_linemsg (lp, msgbuf); /* beginning of buffer */
lp->txbpi = psave; /* restore insertion pointer */
tmxr_poll_tx (mp); /* flush output */
lp->txcnt -= strlen (msgbuf); /* adjust statistics */
return i;
}
} /* end if newsock */
@ -233,6 +241,7 @@ tmxr_send_buffered_data (lp); /* send buffered data */
sim_close_sock (lp->conn, 0); /* reset conn */
lp->conn = lp->tsta = 0; /* reset state */
lp->rxbpr = lp->rxbpi = 0;
if (!lp->txbfd)
lp->txbpr = lp->txbpi = 0;
lp->xmte = 1;
lp->dstb = 0;
@ -419,7 +428,7 @@ return;
int32 tmxr_rqln (TMLN *lp)
{
return (lp->rxbpi - lp->rxbpr);
return (lp->rxbpi - lp->rxbpr + ((lp->rxbpi < lp->rxbpr)? TMXR_MAXBUF: 0));
}
/* Remove character p (and matching status) from line l input buffer */
@ -447,24 +456,29 @@ t_stat tmxr_putc_ln (TMLN *lp, int32 chr)
{
if (lp->txlog) /* log if available */
fputc (chr, lp->txlog);
if (lp->conn == 0) /* no conn? lost */
if ((lp->conn == 0) && (!lp->txbfd)) /* no conn & not buffered? */
if (lp->txlog) /* if it was logged, we got it */
return SCPE_OK;
else {
++lp->txdrp; /* lost */
return SCPE_LOST;
if (tmxr_tqln (lp) < (TMXR_MAXBUF - 1)) { /* room for char (+ IAC)? */
lp->txb[lp->txbpi] = (char) chr; /* buffer char */
lp->txbpi = lp->txbpi + 1; /* adv pointer */
if (lp->txbpi >= TMXR_MAXBUF) /* wrap? */
lp->txbpi = 0;
if ((char) chr == TN_IAC) { /* IAC? */
lp->txb[lp->txbpi] = (char) chr; /* IAC + IAC */
lp->txbpi = lp->txbpi + 1; /* adv pointer */
if (lp->txbpi >= TMXR_MAXBUF) /* wrap? */
lp->txbpi = 0;
}
if (tmxr_tqln (lp) > (TMXR_MAXBUF - TMXR_GUARD)) /* near full? */
#define TXBUF_AVAIL(lp) (lp->txbsz - tmxr_tqln (lp))
#define TXBUF_CHAR(lp, c) { \
lp->txb[lp->txbpi++] = (char)(c); \
lp->txbpi %= lp->txbsz; \
if (lp->txbpi == lp->txbpr) \
lp->txbpr = (1+lp->txbpr)%lp->txbsz, ++lp->txdrp; \
}
if ((lp->txbfd) || (TXBUF_AVAIL(lp) > 1)) { /* room for char (+ IAC)? */
if (TN_IAC == (char) chr) /* char == IAC ? */
TXBUF_CHAR (lp, TN_IAC); /* stuff extra IAC char */
TXBUF_CHAR (lp, chr); /* buffer char & adv pointer */
if ((!lp->txbfd) && (TXBUF_AVAIL (lp) <= TMXR_GUARD))/* near full? */
lp->xmte = 0; /* disable line */
return SCPE_OK; /* char sent */
}
lp->xmte = 0; /* no room, dsbl line */
++lp->txdrp; lp->xmte = 0; /* no room, dsbl line */
return SCPE_STALL; /* char not sent */
}
@ -510,10 +524,10 @@ if (nbytes) { /* >0? write */
sbytes = sim_write_sock (lp->conn, /* write all data */
&(lp->txb[lp->txbpr]), nbytes);
else sbytes = sim_write_sock (lp->conn, /* write to end buf */
&(lp->txb[lp->txbpr]), TMXR_MAXBUF - lp->txbpr);
&(lp->txb[lp->txbpr]), lp->txbsz - lp->txbpr);
if (sbytes != SOCKET_ERROR) { /* ok? */
lp->txbpr = (lp->txbpr + sbytes); /* update remove ptr */
if (lp->txbpr >= TMXR_MAXBUF) /* wrap? */
if (lp->txbpr >= lp->txbsz) /* wrap? */
lp->txbpr = 0;
lp->txcnt = lp->txcnt + sbytes; /* update counts */
nbytes = nbytes - sbytes;
@ -522,7 +536,7 @@ if (nbytes) { /* >0? write */
sbytes = sim_write_sock (lp->conn, lp->txb, nbytes);
if (sbytes != SOCKET_ERROR) { /* ok */
lp->txbpr = (lp->txbpr + sbytes); /* update remove ptr */
if (lp->txbpr >= TMXR_MAXBUF) /* wrap? */
if (lp->txbpr >= lp->txbsz) /* wrap? */
lp->txbpr = 0;
lp->txcnt = lp->txcnt + sbytes; /* update counts */
nbytes = nbytes - sbytes;
@ -536,7 +550,7 @@ return nbytes;
int32 tmxr_tqln (TMLN *lp)
{
return (lp->txbpi - lp->txbpr + ((lp->txbpi < lp->txbpr)? TMXR_MAXBUF: 0));
return (lp->txbpi - lp->txbpr + ((lp->txbpi < lp->txbpr)? lp->txbsz: 0));
}
/* Open master socket */
@ -548,6 +562,81 @@ SOCKET sock;
TMLN *lp;
t_stat r;
if (!isdigit(*cptr)) {
char gbuf[CBUFSIZE];
cptr = get_glyph (cptr, gbuf, '=');
if (0 == MATCH_CMD (gbuf, "LOG")) {
if ((NULL == cptr) || ('\0' == *cptr))
return SCPE_2FARG;
strncpy(mp->logfiletmpl, cptr, sizeof(mp->logfiletmpl)-1);
for (i = 0; i < mp->lines; i++) {
lp = mp->ldsc + i;
sim_close_logfile (&lp->txlogref);
lp->txlog = NULL;
lp->txlogname = realloc(lp->txlogname, CBUFSIZE);
if (mp->lines > 1)
sprintf(lp->txlogname, "%s_%d", mp->logfiletmpl, i);
else
strcpy(lp->txlogname, mp->logfiletmpl);
r = sim_open_logfile (lp->txlogname, TRUE, &lp->txlog, &lp->txlogref);
if (r == SCPE_OK)
setvbuf(lp->txlog, NULL, _IOFBF, 65536);
else {
free (lp->txlogname);
lp->txlogname = NULL;
break;
}
}
return r;
}
if ((0 == MATCH_CMD (gbuf, "NOBUFFERED")) ||
(0 == MATCH_CMD (gbuf, "UNBUFFERED"))) {
if (mp->buffered) {
mp->buffered = 0;
for (i = 0; i < mp->lines; i++) { /* default line buffers */
lp = mp->ldsc + i;
lp->txbsz = TMXR_MAXBUF;
lp->txb = (char *)realloc(lp->txb, lp->txbsz);
lp->txbfd = lp->txbpi = lp->txbpr = 0;
}
}
return SCPE_OK;
}
if (0 == MATCH_CMD (gbuf, "BUFFERED")) {
if ((NULL == cptr) || ('\0' == *cptr))
mp->buffered = 32768;
else {
i = (int32) get_uint (cptr, 10, 1024*1024, &r);
if ((r != SCPE_OK) || (i == 0))
return SCPE_ARG;
mp->buffered = i;
}
for (i = 0; i < mp->lines; i++) { /* initialize line buffers */
lp = mp->ldsc + i;
lp->txbsz = mp->buffered;
lp->txbfd = 1;
lp->txb = (char *)realloc(lp->txb, lp->txbsz);
lp->txbpi = lp->txbpr = 0;
}
return SCPE_OK;
}
if (0 == MATCH_CMD (gbuf, "NOLOG")) {
if ((NULL != cptr) && ('\0' != *cptr))
return SCPE_2MARG;
mp->logfiletmpl[0] = '\0';
for (i = 0; i < mp->lines; i++) { /* close line logs */
lp = mp->ldsc + i;
free(lp->txlogname);
lp->txlogname = NULL;
if (lp->txlog) {
sim_close_logfile (&lp->txlogref);
lp->txlog = NULL;
}
}
return SCPE_OK;
}
return SCPE_ARG;
}
port = (int32) get_uint (cptr, 10, 65535, &r); /* get port */
if ((r != SCPE_OK) || (port == 0))
return SCPE_ARG;
@ -564,7 +653,12 @@ for (i = 0; i < mp->lines; i++) { /* initialize lines */
lp->conn = lp->tsta = 0;
lp->rxbpi = lp->rxbpr = 0;
lp->txbpi = lp->txbpr = 0;
lp->rxcnt = lp->txcnt = 0;
if (!mp->buffered) {
lp->txbfd = lp->txbpi = lp->txbpr = 0;
lp->txbsz = TMXR_MAXBUF;
lp->txb = (char *)realloc(lp->txb, lp->txbsz);
}
lp->rxcnt = lp->txcnt = lp->txdrp = 0;
lp->xmte = 1;
lp->dstb = 0;
}
@ -577,8 +671,11 @@ t_stat tmxr_attach (TMXR *mp, UNIT *uptr, char *cptr)
{
char* tptr;
t_stat r;
char pmsg[20], bmsg[32] = "", lmsg[64+PATH_MAX] = "";
tptr = (char *) malloc (strlen (cptr) + 1); /* get string buf */
tptr = (char *) malloc (strlen (cptr) + /* get string buf */
sizeof(pmsg) +
sizeof(bmsg) + sizeof(lmsg));
if (tptr == NULL) /* no more mem? */
return SCPE_MEM;
r = tmxr_open_master (mp, cptr); /* open master socket */
@ -586,7 +683,12 @@ if (r != SCPE_OK) { /* error? */
free (tptr); /* release buf */
return SCPE_OPENERR;
}
strcpy (tptr, cptr); /* copy port */
sprintf (pmsg, "%d", mp->port); /* copy port */
if (mp->buffered)
sprintf (bmsg, ", buffered=%d", mp->buffered); /* buffer info */
if (mp->logfiletmpl[0])
sprintf (lmsg, ", log=%s", mp->logfiletmpl); /* logfile info */
sprintf (tptr, "%s%s%s", pmsg, bmsg, lmsg); /* assemble all */
uptr->filename = tptr; /* save */
uptr->flags = uptr->flags | UNIT_ATT; /* no more errors */
@ -696,16 +798,24 @@ static const char *enab = "on";
static const char *dsab = "off";
if (ln >= 0)
fprintf (st, "line %d: ", ln);
if (lp->conn) {
fprintf (st, "input (%s) queued/total = %d/%d, ",
fprintf (st, "line %d:\b", ln);
if (!lp->conn)
fprintf (st, "line disconnected\n");
if (lp->rxcnt)
fprintf (st, " input (%s) queued/total = %d/%d\n",
(lp->rcve? enab: dsab),
lp->rxbpi - lp->rxbpr, lp->rxcnt);
tmxr_rqln (lp), lp->rxcnt);
if (lp->txcnt || lp->txbpi)
fprintf (st, " output (%s) queued/total = %d/%d\n",
(lp->xmte? enab: dsab),
lp->txbpi - lp->txbpr, lp->txcnt);
}
else fprintf (st, "line disconnected\n");
tmxr_tqln (lp), lp->txcnt);
if (lp->txbfd)
fprintf (st, " output buffer size = %d\n", lp->txbsz);
if (lp->txcnt || lp->txbpi)
fprintf (st, " bytes in buffer = %d\n",
((lp->txcnt > 0) && (lp->txcnt > lp->txbsz)) ? lp->txbsz : lp->txbpi);
if (lp->txdrp)
fprintf (st, " dropped = %d\n", lp->txdrp);
return;
}
@ -758,7 +868,7 @@ lp->txlogname = (char *) calloc (CBUFSIZE, sizeof (char)); /* alloc namebuf */
if (lp->txlogname == NULL) /* can't? */
return SCPE_MEM;
strncpy (lp->txlogname, cptr, CBUFSIZE); /* save file name */
lp->txlog = fopen (cptr, "ab"); /* open log */
sim_open_logfile (cptr, TRUE, &lp->txlog, &lp->txlogref);/* open log */
if (lp->txlog == NULL) { /* error? */
free (lp->txlogname); /* free buffer */
return SCPE_OPENERR;
@ -779,7 +889,7 @@ lp = tmxr_find_ldsc (uptr, val, mp); /* find line desc */
if (lp == NULL)
return SCPE_IERR;
if (lp->txlog) { /* logging? */
fclose (lp->txlog); /* close log */
sim_close_logfile (&lp->txlogref); /* close log */
free (lp->txlogname); /* free namebuf */
lp->txlog = NULL;
lp->txlogname = NULL;

View file

@ -26,6 +26,7 @@
Based on the original DZ11 simulator by Thord Nilson, as updated by
Arthur Krewat.
17-Jan-11 MP Added buffered line capabilities
20-Nov-08 RMS Added three new standardized SHOW routines
27-May-08 JDB Added lnorder to TMXR structure,
added tmxr_set_lnorder and tmxr_set_lnorder
@ -62,11 +63,15 @@ struct tmln {
int32 txbpr; /* xmt buf remove */
int32 txbpi; /* xmt buf insert */
int32 txcnt; /* xmt count */
int32 txdrp; /* xmt drop count */
int32 txbsz; /* xmt buffer size */
int32 txbfd; /* xmt buffered flag */
FILE *txlog; /* xmt log file */
FILEREF *txlogref; /* xmt log file reference */
char *txlogname; /* xmt log file name */
char rxb[TMXR_MAXBUF]; /* rcv buffer */
char rbr[TMXR_MAXBUF]; /* rcv break */
char txb[TMXR_MAXBUF]; /* xmt buffer */
char *txb; /* xmt buffer */
};
typedef struct tmln TMLN;
@ -78,6 +83,8 @@ struct tmxr {
TMLN *ldsc; /* line descriptors */
int32 *lnorder; /* line connection order */
DEVICE *dptr; /* multiplexer device */
char logfiletmpl[FILENAME_MAX]; /* template logfile name */
int32 buffered; /* Buffered Line Behavior and Buffer Size Flag */
};
typedef struct tmxr TMXR;