/* Copyright (C) Magna Carta Software, Inc. 1990, 1991. All Rights Reserved CCTARNET.C -- CCT01.C modified to support the ARNET MULTIPORT card. CAPABILITY: Dumb terminal program that uses interrupt driven reception from 1 to 8 ports on the ARNET card. The "Plus-4" extension may be installed on the card. General Procedures for ARNET use in CCT (illustrated below): 1) Call init_port() once for each port; 2) Call install_ipr() once for each interrupt type on the ARNET port that you wish to install; 3) Declare the global variable arnet_option_addr, and initialize it to the option address that the board is configured to; 4) Call install_isr() ONCE ONLY to install the ARNET ISR as shown below. Note that it does not matter which COMM_PORT you reference when you install the ISR, providing you reference the same COMM_PORT when you call deinit_port(); 5) At the end of your program call deinit_port() once for each port on the ARNET card, but call deinit_port() for the COMM_PORT that you used to install the ISR, last. NOTE: Once installed, you use the same functions to do serial I/O and other operations (such as file transfer and terminal emulation) that you do normally. That is, the fact that you are addressing an ARNET board is transparent. */ #include #include #include #include /* MANIFEST CONSTANTS AND MACROS */ #define MENU ALT_M /* key for menu */ /* FUNCTION PROTOTYPES */ void INTERRUPT_ arnet_rx_int(void); void cdecl far c_rx_int(COMM_PORT far *p); short menu(void); void term(COMM_PORT *p); /* GLOBAL VARIABLES */ COMM_PORT a_port[8]; /* COMM_PORT structures */ BYTE rxbuf[8][2048]; /* RECEIVE BUFFERS */ short vers = 1; WORD arnet_option_addr = 0X310; /* ------------------------ PROGRAM BEGINS HERE --------------------------- */ int main(void) { /* STAGE 1: CALL INIT_PORT ONCE FOR EACH PORT ON THE ARNET CARD NOTE: WE ASSUME THAT THE ARNET BASE ADDRESS IS 0X280 (you can change this), and that each port is configured to the same speed and data format (you can change this too). */ init_port(&a_port[0], 0X280, 2400L, DATABITS8, PARITY_NONE, STOPBITS1); init_port(&a_port[1], 0X288, 2400L, DATABITS8, PARITY_NONE, STOPBITS1); init_port(&a_port[2], 0X290, 2400L, DATABITS8, PARITY_NONE, STOPBITS1); init_port(&a_port[3], 0X298, 2400L, DATABITS8, PARITY_NONE, STOPBITS1); init_port(&a_port[4], 0X2A0, 2400L, DATABITS8, PARITY_NONE, STOPBITS1); init_port(&a_port[5], 0X2A8, 2400L, DATABITS8, PARITY_NONE, STOPBITS1); init_port(&a_port[6], 0X2B0, 2400L, DATABITS8, PARITY_NONE, STOPBITS1); init_port(&a_port[7], 0X2B8, 2400L, DATABITS8, PARITY_NONE, STOPBITS1); /* STAGE 2: CALL install_ipr() TO INSTALL THE DESIRED "INTERRUPT PROCESSING ROUTINE" */ /* HERE, WE INSTALL RECEIVE INTERRUPTS ONLY */ install_ipr(&a_port[0], RECEIVE, c_rx_int, rxbuf[0], sizeof(rxbuf[0])); install_ipr(&a_port[1], RECEIVE, c_rx_int, rxbuf[1], sizeof(rxbuf[1])); install_ipr(&a_port[2], RECEIVE, c_rx_int, rxbuf[2], sizeof(rxbuf[2])); install_ipr(&a_port[3], RECEIVE, c_rx_int, rxbuf[3], sizeof(rxbuf[3])); install_ipr(&a_port[4], RECEIVE, c_rx_int, rxbuf[4], sizeof(rxbuf[4])); install_ipr(&a_port[5], RECEIVE, c_rx_int, rxbuf[5], sizeof(rxbuf[5])); install_ipr(&a_port[6], RECEIVE, c_rx_int, rxbuf[6], sizeof(rxbuf[6])); install_ipr(&a_port[7], RECEIVE, c_rx_int, rxbuf[7], sizeof(rxbuf[7])); /* FINALLY, INSTALL THE INTERRUPT SERVICE ROUTINE THAT IS CALLED WHEN AN INTERRUPT OCCURS ON THE BOARD. NOTE THAT, SINCE THE BOARD USES ONE IRQ, WE ONLY CALL install_isr() ONCE. WE CAN REFERENCE ANY PORT, SO WE MAKE IT PORT 0 ON THE ARNET CARD. IN THIS EXAMPLE, WE ASSUME IRQ7 (you can change this). NOTE: We install our special ARNET ISR (see below). */ install_isr(&a_port[0], 7, arnet_rx_int); /* USE CORRECT IRQ */ printf("CCT-COMM Version %d: Press Alt-M for a list of commands\n", vers); /* NORMAL TERMINAL MODE. NOTE THAT WE CAN RUN THE TERMINAL ON ANY PORT THAT WE HAVE INITIALIZED. HERE WE USE PORT 7 (you can change this). */ term(&a_port[7]); printf("\nEnd of CCT-COMM%d\n", vers); /* AT THE END OF YOUR PROGRAM (or the world) CALL deinit_port(). THE ONLY RULE HERE --- AND IT IS CRUCIAL -- IS THAT YOU DEINITIALIZE THE PORT WITH THE ISR, LAST (recall that that was port 0, in this example). */ deinit_port(&a_port[1]); deinit_port(&a_port[2]); deinit_port(&a_port[3]); deinit_port(&a_port[4]); deinit_port(&a_port[5]); deinit_port(&a_port[6]); deinit_port(&a_port[7]); /* PORT WITH ISR DEINSTALLED LAST */ deinit_port(&a_port[0]); /* ESSENTIAL -- DEINSTALL INTERRUPTS, ETC. */ return (0); } /* TERM -- The terminal emulation routine. Simply polls the COM port and the keyboard alternately for characters. */ void term(COMM_PORT *p) { short c; /* must be signed to detect a -1 return */ for (;;) { /* CHECK SERIAL PORT FOR BYTE */ if ( (c = c_inchar(p)) != EOF) { putchar(c); fflush(stdout); } /* CHECK KEYBOARD FOR A KEY PRESS */ if ( (c = inkey()) != EOF) { if (c == MENU) { if (menu()) break; } else c_putc(p, c); } } } #define EXIT 'Q' /* key to exit from main */ short menu(void) { int c, retval = 0; static char *menus[] = { "\tQ. EXIT from TERM.", NULL /* null string terminates list */ }; char **p_menu; c = !EXIT; while (c != EXIT && c != LF) { puts("\n\n"); for (p_menu = menus; *p_menu != NULL; p_menu++) printf("%s\n", *p_menu); printf("\n\t\t Enter selection (CR to quit menu) : "); c = getchar(); c = toupper(c); switch (c) { case EXIT: retval = 1; break; default: break; } } puts("\nExiting menu"); return (retval); /* will be zero except if EXIT */ } /* ARNET_RX_INT -- interrupt processing routine for receive data. Called directly from the receive ISR. Note the prototype and use this as a template for your own IPRs to handle situations not envisaged by IPRs supplied with the toolkit. NOTE: TC gives an erroneous warning about "possibly incorrect assignment". */ void INTERRUPT_ arnet_rx_int(void) { static BYTE c, status; static WORD i, shift; COMM_PORT far *p; while (status = (BYTE) ~inp(arnet_option_addr+2)) { shift = 1; for (i=0; i < 8; i++, shift <<= 1) { if (status & shift) { p = mcport[i]; c = inp(p->uart.u8250.iir_addr); if (!(c &1)) (* (void ((far *)(COMM_PORT far *))) p->a_ipr[(c &= 7) >> 1])(p); } } }; outp(EOINT, 0X20); } /* C_RX_INT -- interrupt processing routine for receive data. Called directly from the receive ISR. Note the prototype and use this as a template for your own IPRs to handle situations not envisaged by IPRs supplied with the toolkit. */ void cdecl far c_rx_int(COMM_PORT far *p) { static BYTE c; static BYTE far *b_ptr; c = (BYTE) inp(p->udata_reg_addr); b_ptr = (BYTE far *) p->rxbufhead + 1; if (b_ptr > p->rxbufend) b_ptr = (BYTE far *) p->rxbuf; if (!(b_ptr == p->rxbuftail)) { /* buffer is full */ *p->rxbufhead = c; p->rxbufhead = b_ptr; } }