CONSOLE/SERIAL: Properly rate limit output to console port

When the console is connected to a serial port or telnet sessions enable
speed setting, the bits being output are now paced a the desired speed.
Multi-line mux I/O is also correctly rate limited on all lines.

This should address the problems described in #545
This commit is contained in:
Mark Pizzolato 2018-04-06 04:12:38 -07:00
parent a47c04bcac
commit 81bcd6d319
3 changed files with 32 additions and 13 deletions

View file

@ -2842,9 +2842,7 @@ if (!sim_con_ldsc.conn) { /* no Telnet or serial c
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 */
r = tmxr_putc_ln (&sim_con_ldsc, c); /* Telnet output */
tmxr_poll_tx (&sim_con_tmxr); /* poll xmt */
return r; /* return status */
}

View file

@ -425,8 +425,9 @@ if (port == INVALID_HANDLE) {
return port;
}
status = (lp) ? tmxr_set_config_line (lp, config) /* set serial configuration */
: sim_config_serial (port, config); /* set serial configuration */
status = sim_config_serial (port, config); /* set serial configuration */
if ((lp) && (status == SCPE_OK)) /* line specified? */
status = tmxr_set_config_line (lp, config); /* set line speed parameters */
if (status != SCPE_OK) { /* port configuration error? */
sim_close_serial (port); /* close the port */

View file

@ -1430,7 +1430,7 @@ t_stat tmxr_set_port_speed_control (TMXR *mp)
{
int i;
if (mp->uptr && !(mp->uptr->flags & UNIT_ATT))
if (!mp->port_speed_control && mp->uptr && !(mp->uptr->flags & UNIT_ATT))
return sim_messagef (SCPE_ALATT, "Can't change speed mode while attached.\n:");
mp->port_speed_control = TRUE;
for (i=0; i<mp->lines; ++i)
@ -1448,7 +1448,7 @@ t_stat tmxr_clear_port_speed_control (TMXR *mp)
{
int i;
if (mp->uptr && !(mp->uptr->flags & UNIT_ATT))
if (mp->port_speed_control && mp->uptr && !(mp->uptr->flags & UNIT_ATT))
return sim_messagef (SCPE_ALATT, "Can't change speed mode while attached.\n:");
mp->port_speed_control = FALSE;
for (i=0; i<mp->lines; ++i)
@ -2139,6 +2139,9 @@ tmxr_debug_trace_line (lp, "tmxr_putc_ln()");
if (lp->txbpi == lp->txbpr) \
lp->txbpr = (1+lp->txbpr)%lp->txbsz, ++lp->txdrp; \
}
if ((lp->xmte == 0) && (TXBUF_AVAIL(lp) > 1) &&
((lp->txbps == 0) || (lp->txnexttime <= sim_gtime ())))
lp->xmte = 1; /* enable line transmit */
if ((lp->txbfd && !lp->notelnet) || (TXBUF_AVAIL(lp) > 1)) {/* room for char (+ IAC)? */
if ((TN_IAC == (u_char) chr) && (!lp->notelnet)) /* char == IAC in telnet session? */
TXBUF_CHAR (lp, TN_IAC); /* stuff extra IAC char */
@ -2252,7 +2255,7 @@ for (i = 0; i < mp->lines; i++) { /* loop thru lines */
#endif
if ((lp->xmte == 0) &&
((lp->txbps == 0) ||
(lp->txnexttime >= sim_gtime ())))
(lp->txnexttime <= sim_gtime ())))
lp->xmte = 1; /* enable line transmit */
}
} /* end for */
@ -4045,11 +4048,14 @@ for (i=0; i<mp->lines; i++) {
}
if ((uptr == lp->o_uptr) && /* output completion unit? */
(lp->txbps) && /* while rate limiting */
(tmxr_tqln(lp))) { /* with queued output data */
(lp->txnexttime)) { /* with queued output data */
if (lp->txnexttime > sim_gtime_now)
due = (int32)(lp->txnexttime - sim_gtime_now);
else
due = sim_processing_event ? 1 : 0; /* avoid potential infinite loop if called from service routine */
if (i == 0)
sooner = due;
else
sooner = MIN(sooner, due);
}
}
@ -4070,10 +4076,14 @@ if (sooner != interval) {
return _sim_activate (uptr, sooner); /* Handle the busy case */
}
#if defined(SIM_ASYNCH_MUX)
if (!sim_asynch_enabled)
if (!sim_asynch_enabled) {
sim_debug (TIMER_DBG_MUX, &sim_timer_dev, "scheduling %s after %d instructions\n", sim_uname (uptr), interval);
return _sim_activate (uptr, interval);
}
sim_debug (TIMER_DBG_MUX, &sim_timer_dev, "scheduling %s asynchronously instead of %d instructions\n", sim_uname (uptr), interval);
return SCPE_OK;
#else
sim_debug (TIMER_DBG_MUX, &sim_timer_dev, "scheduling %s after %d instructions\n", sim_uname (uptr), interval);
return _sim_activate (uptr, interval);
#endif
}
@ -4096,17 +4106,21 @@ if (!(uptr->dynflags & UNIT_TM_POLL))
sooner = _tmxr_activate_delay (uptr, 0x7FFFFFFF);
if (sooner != 0x7FFFFFFF) {
if (sooner < 0) {
sooner = _tmxr_activate_delay (uptr, 0x7FFFFFFF); /* Breakpoint here on unexpected value */
sim_debug (TIMER_DBG_MUX, &sim_timer_dev, "scheduling %s for %u usecs produced overflow interval %d instructions, sceduling for %d instructions\n", sim_uname (uptr), usecs_walltime, sooner, 0x7FFFFFFF);
sooner = _tmxr_activate_delay (uptr, 0x7FFFFFFF); /* Breakpoint here on unexpected value */
}
sim_debug (TIMER_DBG_MUX, &sim_timer_dev, "scheduling %s after %d instructions rather than %u usecs\n", sim_uname (uptr), sooner, usecs_walltime);
return _sim_activate (uptr, sooner); /* Handle the busy case directly */
}
#if defined(SIM_ASYNCH_MUX)
if (!sim_asynch_enabled)
if (!sim_asynch_enabled) {
sim_debug (TIMER_DBG_MUX, &sim_timer_dev, "scheduling %s after %u usecs\n", sim_uname (uptr), usecs_walltime);
return _sim_activate_after (uptr, (double)usecs_walltime);
}
sim_debug (TIMER_DBG_MUX, &sim_timer_dev, "scheduling %s asynchronously instead of %u usecs\n", sim_uname (uptr), usecs_walltime);
return SCPE_OK;
#else
sim_debug (TIMER_DBG_MUX, &sim_timer_dev, "scheduling %s after %u usecs\n", sim_uname (uptr), usecs_walltime);
return _sim_activate_after (uptr, (double)usecs_walltime);
#endif
}
@ -5202,5 +5216,11 @@ if ((dptr) && (dbits & dptr->dctrl)) {
else
sim_debug (dbits, dptr, "%s %d bytes '%s'\n", msg, bufsize, tmxr_debug_buf);
}
if ((lp->rxnexttime != 0.0) || (lp->txnexttime != 0.0))
if (lp->rxnexttime != 0.0)
sim_debug (dbits, dptr, " rxnexttime=%.0f", lp->rxnexttime);
if (lp->txnexttime != 0.0)
sim_debug (dbits, dptr, " txnexttime=%.0f", lp->txnexttime);
sim_debug (dbits, dptr, "\n");
}
}