/* i7000_con.c: IBM 7000 Inquiry Console. | |
Copyright (c) 2005-2016, Richard Cornwell | |
Permission is hereby granted, free of charge, to any person obtaining a | |
copy of this software and associated documentation files (the "Software"), | |
to deal in the Software without restriction, including without limitation | |
the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
and/or sell copies of the Software, and to permit persons to whom the | |
Software is furnished to do so, subject to the following conditions: | |
The above copyright notice and this permission notice shall be included in | |
all copies or substantial portions of the Software. | |
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
RICHARD CORNWELL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER | |
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | |
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |
This is the standard inquiry or console interface. | |
These units each buffer one record in local memory and signal | |
ready when the buffer is full or empty. The channel must be | |
ready to recieve/transmit data when they are activated since | |
they will transfer their block during chan_cmd. All data is | |
transmitted as BCD characters. | |
*/ | |
#include "i7000_defs.h" | |
#include "sim_card.h" | |
#include "sim_defs.h" | |
#ifdef NUM_DEVS_CON | |
/* std devices. data structures | |
cdr_dev Card Reader device descriptor | |
cdr_unit Card Reader unit descriptor | |
cdr_reg Card Reader register list | |
cdr_mod Card Reader modifiers list | |
*/ | |
/* Device status information stored in u5 */ | |
struct _con_data | |
{ | |
uint8 ibuff[145]; /* Input line buffer */ | |
uint8 inptr; | |
} | |
con_data[NUM_DEVS_CON]; | |
uint32 con_cmd(UNIT *, uint16, uint16); | |
void con_ini(UNIT *, t_bool); | |
t_stat con_srv(UNIT *); | |
t_stat con_help(FILE *, DEVICE *, UNIT *, int32, const char *); | |
const char *con_description(DEVICE *dptr); | |
extern char ascii_to_six[128]; | |
UNIT con_unit[] = { | |
{UDATA(con_srv, UNIT_S_CHAN(CHAN_CHUREC), 0), 0}, /* A */ | |
}; | |
DEVICE con_dev = { | |
"INQ", con_unit, NULL, NULL, | |
NUM_DEVS_CON, 8, 15, 1, 8, 8, | |
NULL, NULL, NULL, NULL, NULL, NULL, | |
&con_dib, DEV_DISABLE | DEV_DEBUG, 0, dev_debug, | |
NULL, NULL, &con_help, NULL, NULL, &con_description | |
}; | |
/* | |
*Console printer routines. | |
*/ | |
void | |
con_ini(UNIT *uptr, t_bool f) { | |
int u = (uptr - con_unit); | |
con_data[u].inptr = 0; | |
uptr->u5 = 0; | |
sim_activate(uptr, 1000); | |
} | |
uint32 | |
con_cmd(UNIT * uptr, uint16 cmd, uint16 dev) | |
{ | |
int chan = UNIT_G_CHAN(uptr->flags); | |
int u = (uptr - con_unit); | |
/* Are we currently tranfering? */ | |
if (uptr->u5 & (URCSTA_READ|URCSTA_WRITE|URCSTA_BUSY)) | |
return SCPE_BUSY; | |
switch (cmd) { | |
/* Test ready */ | |
case IO_TRS: | |
sim_debug(DEBUG_CMD, &con_dev, "%d: Cmd TRS\n", u); | |
return SCPE_OK; | |
/* Get record from CPU */ | |
case IO_WRS: | |
sim_putchar('R'); | |
sim_putchar(' '); | |
sim_debug(DEBUG_CMD, &con_dev, "%d: Cmd WRS\n", u); | |
chan_set_sel(chan, 1); | |
uptr->u5 |= URCSTA_WRITE; | |
uptr->u3 = 0; | |
return SCPE_OK; | |
/* Send record to CPU */ | |
case IO_RDS: | |
if (uptr->u5 & URCSTA_INPUT) | |
return SCPE_BUSY; | |
if (con_data[u].inptr == 0) { | |
/* Activate input so we can get response */ | |
uptr->u5 |= URCSTA_INPUT; | |
sim_putchar('I'); | |
sim_putchar(' '); | |
} | |
sim_debug(DEBUG_CMD, &con_dev, "%d: Cmd RDS\n", u); | |
chan_set_sel(chan, 0); | |
uptr->u5 |= URCSTA_READ; | |
uptr->u3 = 0; | |
return SCPE_OK; | |
} | |
chan_set_attn(chan); | |
return SCPE_IOERR; | |
} | |
/* Handle transfer of data for printer */ | |
t_stat | |
con_srv(UNIT *uptr) { | |
int chan = UNIT_G_CHAN(uptr->flags); | |
uint8 ch; | |
int u = (uptr - con_unit); | |
t_stat r; | |
/* Waiting for disconnect */ | |
if (uptr->u5 & URCSTA_WDISCO) { | |
if (chan_stat(chan, DEV_DISCO)) { | |
sim_debug(DEBUG_DETAIL, &con_dev, " Disco\n"); | |
chan_clear(chan, DEV_SEL|DEV_WEOR); | |
uptr->u5 &= ~ URCSTA_WDISCO; | |
sim_activate(uptr, 25); | |
return SCPE_OK; | |
} else { | |
/* No disco yet, try again in a bit */ | |
sim_activate(uptr, 50); | |
return SCPE_OK; | |
} | |
} | |
uptr->u5 &= ~URCSTA_BUSY; /* Clear busy */ | |
/* Copy next column over */ | |
if (uptr->u5 & URCSTA_WRITE) { | |
switch(chan_read_char(chan, &ch, 0)) { | |
case TIME_ERROR: | |
case END_RECORD: | |
sim_putchar('\r'); | |
sim_putchar('\n'); | |
sim_debug(DEBUG_EXP, &con_dev, "\n\r"); | |
uptr->u5 |= URCSTA_WDISCO|URCSTA_BUSY; | |
uptr->u5 &= ~URCSTA_WRITE; | |
break; | |
case DATA_OK: | |
ch &= 077; | |
sim_debug(DEBUG_EXP, &con_dev, "%c", sim_six_to_ascii[ch]); | |
sim_putchar(sim_six_to_ascii[ch]); | |
break; | |
} | |
sim_activate(uptr, 100); | |
return SCPE_OK; | |
} | |
/* Copy next column over */ | |
if ((uptr->u5 & URCSTA_INPUT) == 0 && uptr->u5 & URCSTA_READ) { | |
sim_debug(DEBUG_DATA, &con_dev, "%d: Char > %02o %x\n", u, | |
con_data[u].ibuff[uptr->u3], chan_flags[chan]); | |
switch(chan_write_char(chan, &con_data[u].ibuff[uptr->u3], | |
((uptr->u3+1) == con_data[u].inptr)? DEV_REOR: 0)) { | |
case TIME_ERROR: | |
case END_RECORD: | |
uptr->u5 |= URCSTA_WDISCO|URCSTA_BUSY; | |
uptr->u5 &= ~URCSTA_READ; | |
sim_debug(DEBUG_EXP, &con_dev, "EOR"); | |
chan_clear_attn_inq(chan); | |
con_data[u].inptr = 0; | |
break; | |
case DATA_OK: | |
uptr->u3++; | |
break; | |
} | |
sim_activate(uptr, 10); | |
return SCPE_OK; | |
} | |
r = sim_poll_kbd(); | |
if (r & SCPE_KFLAG) { | |
ch = r & 0377; | |
if (uptr->u5 & URCSTA_INPUT) { | |
/* Handle end of buffer */ | |
switch (ch) { | |
case '\r': | |
case '\n': | |
uptr->u5 &= ~URCSTA_INPUT; | |
sim_putchar('\r'); | |
sim_putchar('\n'); | |
chan_set_attn_inq(chan); | |
break; | |
case 033: | |
uptr->u5 &= ~URCSTA_INPUT; | |
con_data[u].inptr = 0; | |
break; | |
case '\b': | |
if (con_data[u].inptr != 0) { | |
con_data[u].inptr--; | |
sim_putchar(ch); | |
} | |
break; | |
default: | |
if (con_data[u].inptr < sizeof(con_data[u].ibuff)) { | |
ch = sim_ascii_to_six[0177&ch]; | |
if (ch == 0xff) { | |
sim_putchar('\007'); | |
break; | |
} | |
sim_putchar(sim_six_to_ascii[ch]); | |
con_data[u].ibuff[con_data[u].inptr++] = ch; | |
} | |
break; | |
} | |
} else { | |
if (ch == 033) { | |
if (con_data[u].inptr != 0) { | |
chan_clear_attn_inq(chan); | |
} else { | |
#ifdef I7070 | |
chan_set_attn_inq(chan); | |
#endif | |
sim_putchar('I'); | |
sim_putchar(' '); | |
uptr->u5 |= URCSTA_INPUT; | |
} | |
con_data[u].inptr = 0; | |
} | |
} | |
} | |
sim_activate(uptr, 500); | |
return SCPE_OK; | |
} | |
t_stat | |
con_help(FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr) | |
{ | |
fprintf (st, "Supervisory Printer\n\n"); | |
fprintf (st, "This is the interface from the operator to the system. The printer\n"); | |
fprintf (st, "operated in a half duplex mode. To request the system to accept input\n"); | |
fprintf (st, "press the <esc> key and wait until the system responds with a line with\n"); | |
fprintf (st, "I as the first character. When you have finished typing your line, press\n"); | |
fprintf (st, "return or enter key. Backspace will delete the last character.\n"); | |
fprintf (st, "All responses from the system are prefixed with a R and blank as the\n"); | |
fprintf (st, "first character\n"); | |
return SCPE_OK; | |
} | |
const char * | |
con_description(DEVICE *dptr) | |
{ | |
return "Supervisory Printer"; | |
} | |
#endif | |