/*
Copyright (C) Magna Carta Software, Inc. 1990, 1991. All Rights Reserved.
Code for the DigiBoard DigiCHANNEL COM/Xi family of products (i.e. the
COM/4i & COM/8i).
This file contains functions that interface the DigiBoard, Inc. M232.DOC
source code to Magna Carta Software's C Communications Toolkit. This file
is the DigiBoard analog of INS8250.C. Each function begins with the prefix
"comxi_" to indicate that it is specific to the DigiBoard COM/Xi series of
FEP cards.
*/
#if (defined(__TURBOC__) || defined(__POWERC))
#include <dos.h>
#else
#include <conio.h>
#endif
#include <digixi0.h>
#undef RTS
#undef DTR
#include <comm.h>
#include <digixi1.h>
static WORD baud_xlat_table[][2] = {{50, 9}, {75, 10}, {110, 1}, {134, 11},
{150, 2}, {200, 12}, {300, 3}, {600, 4}, {1200, 5}, {1800, 13},
{2000, 14}, {2400, 6}, {3600, 15}, {4800, 7}, {7200, 16}, {9600, 8},
{19200, 17}, {0X9600, 18}};
static short comxi_xlat_parity[] = {NPARITY, OPARITY, EPARITY, (OPARITY | SPARITY), (EPARITY | SPARITY)};
static short nelem = sizeof(baud_xlat_table)/(sizeof(WORD) * 2);
/*
COMXI_GET -- General purpose function to return values for the DigiBoard
COM/Xi family.
Return values:
Success: The value of the UART register that sets stopbits;
EOF : Invalid number of stopbits specified;
*/
short comxi_get(COMM_PORT *p, short cmd)
{
short ret = EOF;
switch (cmd) {
/* DATA FORMAT */
case SPEED:
break;
case DATABITS:
ret = p->rxdatabits;
break;
case STOPBITS:
ret = p->stopbits;
break;
case PARITY:
ret = p->parity;
break;
/* RS-232 */
case CTS:
break;
case DCD:
break;
case DSR:
break;
case DTR:
ret = p->dtr;
break;
case RI:
break;
case RTS:
ret = p->rts;
break;
case OUT1:
break;
case OUT2:
break;
}
return (ret);
}
/*
COMXI_GET_RX_XLAT -- Query the setting of each of the input translation
variables used in c_getc().
*/
short comxi_get_rx_xlat(COMM_PORT *p, short item)
{
short ret = 0;
switch (item) {
case XLAT: ret = isrxxlat(p); break; /* OFF or ON */
case LOCAL_ECHO: ret = isrxecholocal(p); break; /* OFF or ON */
case REMOTE_ECHO: ret = isrxechoremote(p); break;/* OFF or ON */
case PRINTER_ECHO: ret = isrxechoprn(p); break; /* OFF or ON */
case CAPTURE_BUFFER_ECHO: ret = isrxechobuf(p); break; /* OFF or ON */
/*
EOL is one of: FALSE, LF2CR, CR2LF, EOL2SP,
STRIPEOL, LF2CRLF, CR2CRLF, CRLF2LF, CRLF2CR
*/
case EOL: ret = p->rx_eol; break;
case CASE: ret = p->rx_case_convert; break;
case ASCII_ONLY: ret = p->rx_ascii_only; break;
case INTERBYTE_DELAY: ret = p->rx_ibdelay; break;
case FLOWCTL: ret = p->flowctl & RX; break; /* OFF or ON */
case XONCHAR: ret = p->xonchar; break; /* ASCII value */
case XOFFCHAR: ret = p->xoffchar; break; /* ASCII value */
case ABORT_KEY: ret = p->abort_key; break;
default: ret = EOF; break;
}
return (ret);
}
/*
COMXI_GET_TX_XLAT -- Return the value of various transmit data translation
parameters.
*/
short comxi_get_tx_xlat(COMM_PORT *p, short item)
{
short ret = 0;
switch (item) {
case LOCAL_ECHO: ret = istxecholocal(p); break; /* OFF or ON */
case REMOTE_ECHO: ret = istxechoremote(p);break; /* OFF or ON */
case PRINTER_ECHO: ret = istxechoprn(p); break; /* OFF or ON */
case CAPTURE_BUFFER_ECHO:
ret = istxechobuf(p); break; /* OFF or ON */
case XLAT: ret = istxxlat(p); break; /* OFF or ON */
/*
EOL is one of: FALSE, LF2CR, CR2LF, EOL2SP,
STRIPEOL, LF2CRLF, CR2CRLF, CRLF2LF, CRLF2CR
*/
case EOL: ret = p->tx_eol; break;
case CASE: ret = p->tx_case_convert; break;
case ASCII_ONLY: ret = p->tx_ascii_only; break;
/* INTERBYTE AND INTERLINE DELAYS (in ms.). */
case INTERBYTE_DELAY: ret = p->tx_ibdelay; break;
case INTERLINE_DELAY: ret = p->tx_ildelay; break;
/* CHARACTER TO TRIGGER INTERLINE DELAY */
case INTERLINE_DELAY_CHAR: ret = p->tx_ildelay_ch; break;
case FLOWCTL:
ret = p->flowctl & TX;
break;
case TX_DELAY:
ret = p->tx_delay;
break;
case TX_DELAYCHAR:
ret = p->tx_delaych;
break;
case XONCHAR: ret = p->xonchar; break; /* ASCII value */
case XOFFCHAR: ret = p->xoffchar; break; /* ASCII value */
/* ASCII CODE OF KEY TO ABORT XOFF */
case ABORT_KEY: ret = p->abort_key; break;
default: ret = EOF; break;
}
return (ret);
}
/*
COMXI_INIT -- Initialize the COM/Xi board and integrate it into the toolkit.
Parameters:
WORD port -- board I/O port address;
WORD seg -- board memory address to use;
WORD size -- board RX,TX buffer size (0-2 for M232);
Return value:
0 -- success;
NOTWARM (-4) -- Module not loaded;
BADVERSN (-8) -- ?
BUSYHML (-5) -- FEP busy (0h not written to "mailbox");
TMOERROR (-2) -- Module did not start executing;
or ... -- timeout error during initialization;
*/
short comxi_init(COMXI *c, WORD port, WORD seg, WORD size)
{
short ret;
ret = resetcomxi(port, seg);
if (!ret) {
ret = excM232(port, seg, size);
if (!ret) {
c->base_addr = seg;
c->port_addr = port;
}
}
return (ret);
}
/*
COMXI_INIT_CHANNEL -- Initialize one port on the COM/Xi board.
Parameters:
COMM_PORT *p -- pointer to the COMM_PORT structure for this port;
Return value:
*/
short comxi_init_channel(COMM_PORT *p, COMXI *c, WORD portnum, long speed,
WORD databits, WORD parity, WORD stopbits)
{
if (p->open) return (PORT_OPEN);
if (c->base_addr == 0) return (-2);
p->utype = DIGIBOARD_COMXI;
p->rxdatabits = databits;
p->txdatabits = databits;
p->parity = parity;
p->stopbits = stopbits;
p->speed = speed;
p->dtr = HIGH;
p->rts = HIGH;
p->abort_key = ESCAPE;
p->ubase_addr = c->port_addr; /* "port" is assigned to ubase_addr */
p->user1 = c->base_addr; /* "seg" is assigned to p->user1 */
p->user2 = portnum; /* channel # assigned to p->user2 */
/* INITIALIZE DEVICE-SPECIFIC FUNCTION POINTERS */
p->set = comxi_set;
p->get = comxi_get;
p->get_rx_xlat = comxi_get_rx_xlat;
p->set_rx_xlat = comxi_set_rx_xlat;
p->get_tx_xlat = comxi_get_tx_xlat;
p->set_tx_xlat = comxi_set_tx_xlat;
p->set_speed = comxi_set_speed;
p->get_speed = (long (*)(struct comm_port *)) comxi_get;
p->rxstat = (short (*)(struct comm_port *)) comxi_ret;
p->txstat = comxi_txstat;
p->c_read = comxi_read;
p->c_write = comxi_write;
p->enable_comm_int = (short (*)(struct comm_port *, WORD)) comxi_ret;
p->disable_comm_int = (short (*)(struct comm_port *, WORD))comxi_ret;
p->install_ipr = (short (*)(struct comm_port *, WORD, void FAR_ *, BYTE FAR_ *, WORD))comxi_ret;
p->deinstall_ipr = (short (*)(struct comm_port *, WORD))comxi_ret;
p->deinit_port = (short (*)(struct comm_port *)) comxi_ret;
p->enable_comm_int = (short (*)(struct comm_port *, WORD))comxi_ret;
p->disable_comm_int = (short (*)(struct comm_port *, WORD))comxi_ret;
/* OPEN THE PORT */
return (c_open_(p));
}
short comxi_read(COMM_PORT *p)
{
short ret;
ret = rdch(p->ubase_addr, p->user1, p->user2);
if (ret < 0) {
global_com_error = ret;
ret = EOF;
}
return (ret);
}
/*
COMXI_RET -- Dummy do-nothing function to handle COMM_PORT function pointers
not supported by the COM/Xi.
*/
short comxi_ret(void)
{
return (EOF);
}
short comxi_rxstat(COMM_PORT *p)
{
short ret;
ret = rdch(p->ubase_addr, p->user1, p->user2);
if (ret < 0) {
global_com_error = ret;
ret = EOF;
}
return (ret);
}
/*
COMXI_SEND_BREAK -- Send a BREAK signal to the designated port of the COM/Xi.
Parameters:
COMM_PORT *p -- ptr. to the COMM_PORT structure;
WORD duration -- duration in ms. (calibrated to nearest 55ms.);
Return values:
0 -- success;
CMDQFUL (-9) -- Command buffer full;
*/
short comxi_send_break(COMM_PORT *p, WORD duration)
{
duration = (duration < 55) ? 1 : duration/18;
wrtbcmd(p->user1, SBRKCNT, p->user2, duration, 0);
return(wrtbcmd(p->user1, SBREAK, p->user2, 0, 0));
}
/*
COMXI_SET -- General purpose command dispatcher for the DigiBoard COM/Xi
family.
Return values:
0 -- success;
EOF -- invalid 'cmd' specified;
*/
short comxi_set(COMM_PORT *p, short cmd, short value)
{
short ret = EOF;
switch (cmd) {
/* DATA FORMAT */
case DATABITS:
ret = comxi_set_databits(p, value);
break;
case STOPBITS:
ret = comxi_set_stopbits(p, value);
break;
case PARITY:
ret = comxi_set_parity(p, value);
break;
/* RS-232 */
case DTR:
comxi_set_dtr(p, value);
break;
case RTS:
comxi_set_rts(p, value);
break;
case BREAK:
comxi_send_break(p, value);
break;
case LOOPBACK:
break;
case OUT1:
break;
case OUT2:
break;
}
return (ret);
}
/*
COMXI_SET_DATABITS -- Set the number of databits for the designated serial
port to the designated value.
Return values:
Success: The value of the UART register that sets stopbits;
EOF : Invalid number of stopbits specified;
*/
short comxi_set_databits(COMM_PORT *p, short value)
{
short stops, parity;
switch (value) {
case DATABITS5: value = DATA5; break;
case DATABITS6: value = DATA6; break;
case DATABITS7: value = DATA7; break;
case DATABITS8: value = DATA8; break;
default: return (EOF);
}
parity = comxi_xlat_parity[p->parity];
stops = (p->stopbits == 1) ? 0 : 4;
value = parity | stops | value;
wrtbcmd(p->user1, SBAUDATA, p->user2, comxi_xlat_baud(p->speed), value);
return (0);
}
/*
COMXI_SET_DTR -- Set the value of the DTR line for the designated serial
port to the designated value.
Return values:
Success: The value of the UART register that sets stopbits;
EOF : Invalid value for "value" specified;
*/
short comxi_set_dtr(COMM_PORT *p, short value)
{
if (value == HIGH) wrtbcmd(p->user1, SMODEM, p->user2, '\x1', 0);
else if (value == LOW) wrtbcmd(p->user1, SMODEM, p->user2, '\x0', '\x1');
else return (EOF);
return (0);
}
/*
COMXI_SET_FLOWCTL -- Set flow control off or on.
"flowtype" is an ORing of the values in DIGIXI0.H for function 0X1B.
"state"
*/
short comxi_set_flowctl(COMM_PORT *p, short flowtype, short state)
{
short ret;
if (state == OFF) ret = wrtbcmd(p->user1, SHNDSHK, p->user2, '\0', flowtype);
else ret = wrtbcmd(p->user1, SHNDSHK, p->user2, flowtype, '\0');
return (ret);
}
/*
COMXI_SET_PARITY -- Set the parity of the designated serial port to the
designated value.
Return values:
Success: The value of the UART register that sets stopbits;
EOF : Invalid number of stopbits specified;
*/
short comxi_set_parity(COMM_PORT *p, short value)
{
short stops;
switch (value) {
case PARITY_NONE: value = NPARITY; break;
case PARITY_ODD: value = OPARITY; break;
case PARITY_EVEN: value = EPARITY; break;
case PARITY_MARK: value = (OPARITY | SPARITY); break;
case PARITY_SPACE: value = (EPARITY | SPARITY); break;
default:
return (EOF);
}
stops = (p->stopbits == 1) ? 0 : 4;
value = (p->rxdatabits - 5) | stops | value;
wrtbcmd(p->user1, SBAUDATA, p->user2, comxi_xlat_baud(p->speed), value);
return (0);
}
/*
COMXI_SET_RTS -- Set the value of the RTS line for the designated serial
port to the designated value.
Return values:
Success: The value of the UART register that sets stopbits;
EOF : Invalid value for "value" specified;
*/
short comxi_set_rts(COMM_PORT *p, short value)
{
if (value == HIGH) wrtbcmd(p->user1, SMODEM, p->user2, '\x2', 0);
else if (value == LOW) wrtbcmd(p->user1, SMODEM, p->user2, '\x0', '\x2');
else return (EOF);
return (0);
}
/*
COMXI_SET_RX_XLAT -- Specify the type of input translation used by c_getc()
and c_gets().
*/
short comxi_set_rx_xlat(COMM_PORT *p, short item, short value)
{
short parm, ret = 0;
switch (item) {
case LOCAL_ECHO:
case REMOTE_ECHO:
case PRINTER_ECHO:
case CAPTURE_BUFFER_ECHO:
if (value) p->echo |= item;
else p->echo &= ~item;
break;
/*
EOL is one of: FALSE, LF2CR, CR2LF, EOL2SP,
STRIPEOL, LF2CRLF, CR2CRLF, CRLF2LF, CRLF2CR
*/
case EOL:
p->rx_eol = value;
break;
case CASE: /* UPPER, LOWER, FALSE */
p->rx_case_convert = value; break;
case ASCII_ONLY:
p->rx_ascii_only = value; break;
case INTERBYTE_DELAY:
p->rx_ibdelay = value; break;
case TRAILINGBYTE_DELAY:
p->rx_tbdelay = value; break;
case FLOWCTL:
switch(value) {
case XONXOFF:
parm = (SHND | OHND);
break;
case RTS_CTS:
parm = (HHND | OHND);
break;
default:
ret = EOF;
}
if (!ret) comxi_set_flowctl(p, parm, value);
break;
case FLOWHIGH:
p->flowhigh = value;
break;
case XONCHAR: /* value to be considered an XON */
if (value == XON_ALL) comxi_set_flowctl(p, (SHND | OHND | XAKP), value);
else ret = wrtbcmd(p->user1, SONOFF, p->user2, (BYTE) value, (BYTE) p->xoffchar);
p->xonchar = value; /* a specific char. */
break;
case XOFFCHAR:
ret = wrtbcmd(p->user1, SONOFF, p->user2, p->xonchar, value);
p->xoffchar = value;
break;
case RX_BUFFER_LWM:
wrtbcmd(p->user1, SRXLWTR, p->user2, value & 0XFF, value >> 8);
ret = EOF;
break;
case RX_BUFFER_HWM:
/* work in progress */
ret = EOF;
break;
/* SCAN CODE/CHARACTER CODE OF KEY TO ABORT */
case ABORT_KEY: p->abort_key = value; break;
default: ret = EOF; break;
}
if (!ret) {
if (value) p->rx_xlat = 1;
else p->rx_xlat = isrxxlat(p);
}
return (ret);
}
/*
COMXI_SET_SPEED -- Set the data rate (bps) for the deignated port.
Return value:
SUCCESS (0) -- OK;
EOF -- Invalid speed value;
CMDQFUL (-9) -- Command buffer full;
*/
short comxi_set_speed(COMM_PORT *p, long value)
{
short stops, parity, parms;
parity = comxi_xlat_parity[p->parity];
stops = (p->stopbits == 1) ? 0 : 4;
parms = (p->rxdatabits - 5) | stops | parity;
if ((value = comxi_xlat_baud(value)) != EOF)
return (wrtbcmd(p->user1, SBAUDATA, p->user2, (WORD) value, parms));
return (EOF);
}
/*
COMXI_SET_STOPBITS -- Set the number of stopbits for the designated serial
port to the designated value.
Return values:
Success: The value of the UART register that sets stopbits;
EOF : Invalid number of stopbits specified;
*/
short comxi_set_stopbits(COMM_PORT *p, short value)
{
short parity;
switch (value) {
case STOPBITS1: value = STOP1; break;
case STOPBITS2: value = STOP2; break;
case STOPBITS15:
default:
return (EOF);
}
parity = comxi_xlat_parity[p->parity];
value = (p->rxdatabits - 5) | parity | value;
wrtbcmd(p->user1, SBAUDATA, p->user2, comxi_xlat_baud(p->speed), (BYTE) value);
return (0);
}
/*
COMXI_SET_TX_XLAT -- Assign values to data translation parameters.
*/
short comxi_set_tx_xlat(COMM_PORT *p, short item, short value)
{
short parm, ret = 0;
switch (item) {
case LOCAL_ECHO:
case REMOTE_ECHO:
case PRINTER_ECHO:
case CAPTURE_BUFFER_ECHO:
if (value) p->echo |= (item << 4);
else p->echo &= ~(item << 4);
break;
/*
EOL is one of: FALSE, LF2CR, CR2LF, EOL2SP,
STRIPEOL, LF2CRLF, CR2CRLF, CRLF2LF, CRLF2CR
*/
case EOL:
p->tx_eol = value;
break;
case CASE: /* UPPER, LOWER, NORMAL */
p->tx_case_convert = value;
break;
case ASCII_ONLY:
p->tx_ascii_only = value;
break;
case INTERBYTE_DELAY:
p->tx_ibdelay = value;
break;
case TX_DELAY:
p->tx_delay = value;
break;
case TX_DELAYCHAR:
p->tx_delaych = value;
break;
case INTERLINE_DELAY:
p->tx_ildelay = value;
break;
case INTERLINE_DELAY_CHAR:
p->tx_ildelay_ch = value;
break;
case FLOWCTL:
switch(value) {
case XONXOFF:
parm = (SHND | IHND);
break;
case RTS_CTS:
parm = (HHND | IHND);
break;
default:
ret = EOF;
}
if (!ret) comxi_set_flowctl(p, parm, value);
break;
case XONCHAR: /* value to be considered an XON */
ret = wrtbcmd(p->user1, SONOFF, p->user2, value, p->xoffchar);
p->xonchar = value; /* a specific char. */
break;
case XOFFCHAR:
ret = wrtbcmd(p->user1, SONOFF, p->user2, p->xonchar, value);
p->xoffchar = value;
break; /* ASCII value */
/* SCAN CODE/CHARACTER CODE OF KEY TO ABORT XOFF */
case ABORT_KEY:
p->abort_key = value;
break;
case TX_BUFFER_LWM:
/* work in progress */
ret = EOF;
break;
default:
ret = EOF;
break;
}
if (!ret) {
if (value) p->tx_xlat = 1;
else p->tx_xlat = istxxlat(p);
}
return (ret);
}
short comxi_txstat(COMM_PORT *p)
{
WORD port = p->ubase_addr;
WORD seg = p->user1;
WORD chn = p->user2;
WORD a;
a = btbl(seg)[chn].BWIND;
if (a != (inp(port) & 0X0f)) {
if (swindow(port, seg, a)) return (FALSE);
}
a = btbl(seg)[chn].TXHD;
if (++a > btbl(seg)[chn].TXMAX) a = btbl(seg)[chn].TXSTRT;
if (a != btbl(seg)[chn].TXTL) return (TRUE);
else return (FALSE);
}
/*
COMXI_WRITE -- Low level function to write a byte. This function is just a
binding function to call wrtch().
*/
void comxi_write(COMM_PORT *p, short ch)
{
wrtch(p->ubase_addr, p->user1, p->user2, ch);
}
/*
COMXI_XLAT_BAUD -- Convert a data transfer rate expressed as a number to a
DigiBoard manifest constant.
Return value:
>0 -- DigiBoard speed specification;
EOF -- Invalid value for "value";
*/
short comxi_xlat_baud(long value)
{
short i;
for (i=0; i < nelem; i++) {
if (baud_xlat_table[i][0] == (WORD) value) return (baud_xlat_table[i][1]);
}
return (EOF);
}
#if defined(CCT_TEST)
/* NOT USER-RUNABLE -- RUN CCTDIGIx.C TO TEST CCT WITH THE BOARD */
#include <conio.h>
#include <ctype.h>
#define MENU ALT_M /* key for command summary */
/* FUNCTION PROTOTYPES */
void term(COMM_PORT *p); /* the main program loop */
short menu(void); /* the function that handles the menu */
/* GLOBAL VARIABLES */
short vers = 0; /* the version number of "CCT-COMM" */
COMM_PORT d0, d1, d2, d3, d4, d5, d6, d7;
COMM_PORT *digi[] = {&d0, &d1, &d2, &d3, &d4, &d5, &d6, &d7, NULL};
void main(void)
{
short ret;
clrscr();
ret = comxi_init(digi, 0X320, 0XD800, 0);
printf("\nResult of comxi_init() is: %d", ret);
set_speed(digi[0], 2400L);
set_databits(digi[0], 8);
set_stopbits(digi[0], 1);
set_parity(digi[0], PARITY_NONE);
set_rts(digi[0], HIGH);
set_dtr(digi[0], HIGH);
printf("\nCCT-COMM Version %d: Press Alt-M for a list of commands\n", vers);
term(digi[0]);
printf("\nEnd of CCT-COMM%d\n", vers);
set_rts(digi[0], LOW);
set_dtr(digi[0], LOW);
}
/*
TERM -- The terminal emulation routine. Simply polls the COM port and the
keyboard alternately for characters.
*/
void term(COMM_PORT *p_port)
{
short c; /* must be int to detect a -1 return */
for (;;) {
/* CHECK SERIAL PORT FOR BYTE */
if ( (c = c_inchar(p_port)) != EOF)
putchar(c);
/* CHECK KEYBOARD FOR A KEY PRESS */
if ( (c = inkey()) != EOF) {
if (c == MENU) {
if (menu()) break;
}
else c_putc(p_port, c);
}
}
}
#define EXIT 'Q' /* key to exit from menu */
short menu(void)
{
int c, retval = 0;
static char *menus[] = {
"\tQ. EXIT from TERM.",
NULL /* null string terminates list */
};
char **menup;
c = !EXIT;
while (c != EXIT) {
puts("\n\n");
for (menup = menus; *menup != NULL; menup++) printf("%s\n", *menup);
printf("\n\t\t Enter selection (CR to quit menu) : ");
if ( (c = getch()) == CR) break; /* return to term */
c = toupper(c);
switch (c) {
case EXIT:
retval = 1;
break;
default:
puts("Invalid choice\n\007");
break;
}
}
puts("\nExiting menu");
return (retval); /* will be zero except if EXIT */
}
#endif