/* 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 #else #include #endif #include #undef RTS #undef DTR #include #include 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 #include #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