/* Copyright (C) Magna Carta Software, Inc. 1990. All Rights Reserved CCT21.C -- Commtech FASTCOM4 example file 1. This example shows how to use the Commtech FASTCOMM4 card in default mode. Tranmist on port 1, and receive on port 2. This version uses EasyMode for easy initialization of the COMM_PORT structures. NOTE: You may need to change the IRQs and I/O addresses below to suit your system. COMPATIBILITY: TURBOC v1.5+, POWERC v2.0+, MSC 5.0+/QUICK C, WATCOM C; */ #include #include #include #include #include /* MANIFEST CONSTANTS AND MACROS */ #define MENU ALT_M /* key for menu */ #define COMMTECH 0X200 /* the base address of the CommTech FASTCOMM4 */ #define MAX_COMMTECH_PORTS 4 /* number of COMMTECH ports */ /* FUNCTION PROTOTYPES */ short menu(COMM_PORT *p); void term(COMM_PORT *p); void cdecl far c_rx_int(COMM_PORT far *p); void INTERRUPT_ commtech_isr(void); short init_commtech(WORD addr, COMM_PORT *p[4]); /* GLOBAL VARIABLES */ COMM_PORT a_port[4]; /* Array of 4 CommTech ports */ BYTE rxbuf[4][1024]; /* Array of 4 RX buffers */ BYTE txbuf[4][1024]; /* Array of 4 TX buffers */ short vers = 21; /* ------------------------ PROGRAM BEGINS HERE --------------------------- */ int main(void) { short i; /* STAGE 1: CALL INIT_PORT ONCE FOR EACH PORT ON THE COMMTECH CARD NOTE: WE ASSUME THAT THE COMMTECH BASE ADDRESS IS 0X200 (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], 0X1A0, 2400L, DATABITS8, PARITY_NONE, STOPBITS1); init_port(&a_port[1], 0X1A8, 2400L, DATABITS8, PARITY_NONE, STOPBITS1); init_port(&a_port[2], 0X1B0, 2400L, DATABITS8, PARITY_NONE, STOPBITS1); init_port(&a_port[3], 0X1B8, 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])); /* 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 COMMTECH CARD. IN THIS EXAMPLE, WE ASSUME IRQ3 (you can change this). NOTE: We install our special COMMTECH ISR (see below) that uses the I-STAT register. */ install_isr(&a_port[0], 3, commtech_isr); /* USE CORRECT IRQ */ printf("CCT-COMM Version %d: Press Alt-M for a list of commands\n", vers); term(&a_port[1]); printf("\nEnd of CCT-COMM%d\n", vers); for (i=1; i<4; i++) deinit_port(&a_port[i]); /* 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 */ set_rx_xlat(p, LOCAL_ECHO, ON); for (;;) { /* CHECK SERIAL PORT FOR BYTE */ while (c_getc(p) != EOF); /* CHECK KEYBOARD FOR A KEY PRESS */ if ( (c = inkey()) != EOF) { if (c == MENU) { if (menu(p) != NULL) break; } else c_putc(p, c); } } } #define EXIT 'Q' /* key to exit from main */ short menu(COMM_PORT *p_port) { short c, retval = 0; static char *menus[] = { "\tQ. EXIT from TERM.", NULL }; char **p_menu; c = !EXIT; while (c != EXIT) { 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) : "); 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 */ } #if DEBUG static WORD far * screen = 0XB8000000L; #endif /* COMMTECH_ISR -- interrupt handler for CommTech FASTCOMM4 board. Strategy: Read the ISTAT register and use the result to set the I/O address of the port to read. Then, call the standard assembly language interrupt processing routines as usual. */ void INTERRUPT_ commtech_isr(void) { static BYTE c; COMM_PORT far *p; static BYTE istat; static WORD shift, i; while (istat = (BYTE) inp(COMMTECH+7)) { shift = 1; for (i=0; i < 4; i++, shift <<= 1) { if (istat & 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); #if 0 istat = inp(COMMTECH+7); #if DEBUG *screen++ = (15 << 8) | (istat | 0X30); #endif if (istat & 1) { p = mcport[0]; c = inp(p->uart.u8250.iir_addr); if (!(c & 1)) (* (void ((far *)(COMM_PORT *))) p->a_ipr[(c &= 7) >> 1])(p); } if (istat & 2) { p = mcport[1]; c = inp(p->uart.u8250.iir_addr); if (!(c & 1)) (* (void ((far *)(COMM_PORT *))) p->a_ipr[(c &= 7) >> 1])(p); } if (istat & 4) { p = mcport[2]; c = inp(p->uart.u8250.iir_addr); if (!(c & 1)) (* (void ((far *)(COMM_PORT *))) p->a_ipr[(c &= 7) >> 1])(p); } if (istat & 8) { p = mcport[3]; c = inp(p->uart.u8250.iir_addr); if (!(c & 1)) (* (void ((far *)(COMM_PORT *))) p->a_ipr[(c &= 7) >> 1])(p); } outp(EOINT, 0X20); /* Send EOI to 8259 */ #endif } /* 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; } }