/* Copyright (C) Magna Carta Software, Inc. 1990, 1991. All Rights Reserved CCT08.C: CCT07.C plus... 1) RTS-CTS flow control on transmit and receive; 2) Raw data (ASCII) file reception; 3) We install a user-written interrupt processing routine (IPR) on line status. This IPR is written in C, and shows both how to write an IPR and how to install it. NOTE: You must modify the screen address variable below to B000:0200 if you run this program on a monochrome monitor. NOTA BENE: In order to use RTS-CTS flow control, you cannot use a "standard" null modem connection. See the CCT manual for a full description of the correct null modem connection. Briefly, connect the RS-232 lines as follows: 2 -- 3 3 -- 2 4 -- 5 5 -- 4 7 -- 7 */ #include #include #include #if defined(__TURBOC__) || defined(__POWERC) #include #elif defined(MSC) #include #elif defined(__WATCOMC__) #include #endif #include #include #include #include /* MANIFEST CONSTANTS AND MACROS */ #define DO_MENU ALT_M /* key for command summary */ /* FUNCTION PROTOTYPES */ void do_data_menu(COMM_PORT * p); short do_modem_menu(COMM_PORT *p); short do_rxfile_menu(COMM_PORT *p); short do_txfile_menu(COMM_PORT *p); long do_speed_menu(COMM_PORT * p); void far lsr_int(COMM_PORT *p); short menu(COMM_PORT *p); void term(COMM_PORT *p); short transfer_progress(COMM_PORT *p, short status, unsigned long parm); /* GLOBAL VARIABLES */ BYTE rxbuf[1024]; /* RECEIVE BUFFER */ BYTE txbuf[20*1024]; /* TRANSMIT BUFFER */ int vers = 8; COMM_PORT port1; MODEM m1; XFER x; WORD far *screen = MK_FP(0XB800,0X200); #include "menus.c" #include "xfermsg.c" /* ------------------------ PROGRAM BEGINS HERE --------------------------- */ int main(void) { u8250_init(&port1, COM1, 38400L, DATABITS8, PARITY_NONE, STOPBITS1); install_ipr(&port1, RECEIVE, NULL, rxbuf, sizeof(rxbuf)); install_ipr(&port1, TRANSMIT, NULL, txbuf, sizeof(txbuf)); /* NOTE: IN ORDER TO USE TRANSMIT INTERRUPTS AND HARDWARE FLOW CONTROL, WE MUST INSTALL AN INTERRUPT PROCESSING ROUTINE FOR MODEM STATUS. THIS IS WHAT RESTARTS TRANSMISSION AFTER HARDWARE FLOW CONTROL STOPS IT. */ install_ipr(&port1, MODEM_STATUS, NULL, NULL, 0); /* OUR USER-WRITTEN IPR IS INSTALLED ON LINE STATUS TO REPORT LINE ERRORS. E.G. OVERRUN, PARITY, AND FRAMING ERRORS. */ install_ipr(&port1, LINE_STATUS, (void far *) lsr_int, NULL, 0); install_isr(&port1, 4, NULL); printf("CCT-COMM Version %d: Press Alt-M for a list of commands\n", vers); term(&port1); printf("\nEnd of CCT-COMM%d\n", vers); set_dtr(&port1, LOW); set_rts(&port1, LOW); 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 int to detect a -1 return */ set_rx_xlat(p, EOL, FALSE); set_rx_xlat(p, LOCAL_ECHO, TRUE); set_tx_xlat(p, FLOWCTL, XONXOFF); /* ASSERT flow control to sender */ set_rx_xlat(p, FLOWCTL, RTS_CTS); /* ACCEPT flow control from receiver */ for (;;) { /* CHECK SERIAL PORT FOR BYTE */ c = c_getc(p); /* CHECK KEYBOARD FOR A KEY PRESS */ if ((c = inkey()) != 0) { if (c == DO_MENU) { if (menu(p) == 1) break; } else c_putc(p, c); } } } #define DATA_FORMAT 'D' /* key to set speed */ #define RFILE_MENU 'R' /* key to receive files */ #define SFILE_MENU 'F' /* key to send files */ #define DATA_SPEED 'S' /* key to set speed */ #define MODEM_MENU 'M' /* key to send modem commands */ #define EXIT 'Q' /* key to exit from main */ short menu(COMM_PORT *p) { short c, retval = 0, DONE = FALSE; static char *menus[] = { "\tD. Data Format", "\tF. File Send Commands", "\tM. Modem Commands.", "\tR. File Receive Commands", "\tS. Data Transfer Rate.", "\tQ. EXIT from COMM.", NULL /* null string terminates list */ }; char **p_menu; c = !EXIT; while (!DONE) { 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; DONE = TRUE; break; case SFILE_MENU: DONE = do_txfile_menu(p); break; case RFILE_MENU: DONE = do_rxfile_menu(p); break; case DATA_FORMAT: do_data_menu(p); break; case DATA_SPEED: do_speed_menu(p); break; case MODEM_MENU: DONE = do_modem_menu(p); break; default: DONE = TRUE; break; } } puts("\nExiting menu"); return (retval); /* will be zero except if EXIT */ } /* DO_MODEM_MENU -- Send commands to the modem. */ short do_modem_menu(COMM_PORT *p) { short key; short DONE=FALSE, ret = 0; do { puts("\nSEND COMMANDS TO THE MODEM"); puts("\nA. Send ASCII"); puts("\nD. Dial"); puts("H. Hangup"); puts("I. Initialize"); puts("O. Go Offline"); puts("R. Reset\n"); puts("\nAny other key exits"); key = toupper(bios_key(_KEYBRD_READ) & 0XFF); switch (key) { case 'D': modem_dial(p, "226-8088"); ret = 1; DONE = TRUE; break; case 'H': modem_hangup(p); break; case 'I': modem_init(p, modem_type(p)); set_dtr(p, HIGH); break; case 'O': modem_go_cmd(p, (short) atoi(&((MODEM *)p->modem)->escape[3])); break; case 'R': modem_reset(p); break; default: DONE = TRUE; break; } } while (!DONE); return (ret); } /* DO_TXFILE_MENU -- Send a file to a remote system using ASCII. */ short do_txfile_menu(COMM_PORT *p) { short ret = 0; char filename[80], sxlat[XLAT_SIZE]; struct ffblk fb; /* SELECT THE FILE TO SEND */ filename[0] = '\0'; puts("\nSEND A FILE TO A REMOTE SYSTEM USING ASCII"); puts("\nEnter file name (ENTER to exit):"); scanf("%s", filename); if (filename[0] == CR) return (0); ret = findfirst(filename, &fb, FA_ARCH); if (ret == EOF) return (EOF); save_xlat(p, sxlat); /* save XLAT configuration */ set_tx_xlat(p, LOCAL_ECHO, OFF); set_rx_xlat(p, LOCAL_ECHO, ON); fqueue(&x, fb.ff_name); ret = fsend(p, &x, ASCII, 16*1024, xfer_progress); /* send the file */ rest_xlat(p, sxlat); /* restore XLAT configuration */ return (ret); } /* DO_RXFILE_MENU -- Receive a file from a remote system using ASCII */ short do_rxfile_menu(COMM_PORT *p) { short ret = 0; char filename[80], sxlat[XLAT_SIZE]; struct ffblk fb; if (x.xf != NULL) funqueue(&x, x.xf->fspec); /* GET THE FILENAME FROM THE KEYBOARD */ filename[0] = '\0'; puts("\nREADY TO RECEIVE A FILE FROM A REMOTE SYSTEM USING ASCII"); puts("\nEnter file name to save to:"); scanf("%s", filename); ret = findfirst(filename, &fb, FA_ARCH); if (ret == 0) { puts("\File already exists -- exiting"); return (EOF); } /* RECEIVE STARTS HERE */ save_xlat(p, sxlat); /* save XLAT configuration */ set_rx_xlat(p, LOCAL_ECHO, OFF); set_rx_xlat(p, INTERBYTE_DELAY, 5000); /* allow the other end to load */ /* RECEIVE -- BIG BUFFER SIZE */ /* ret = freceive(p, &x, ASCII, coreleft() - 4096, xsfer_progress); */ /* EXAMPLE OF SMALL BUFFER */ ret = freceive(p, &x, ASCII, 3096, xfer_progress); /* NOTE: FOR FILE TRANSFER PROTOCOLS THAT DO NOT SEND THE FILE NAME, CCT CREATES A TEMP. FILE USING THE NAME STORED IN ftempname. YOUR APPLICATION SHOULD RENAME THIS FILE ON RECEIPT. Viz: */ rename(ftempname, filename); rest_xlat(p, sxlat); /* restore XLAT configuration */ return (ret); } void far lsr_int(COMM_PORT *p) { BYTE val; val = (BYTE) inp(p->uart.u8250.lsr_addr); if (val & 2) *screen++ = (14 << 8) | 'o'; if (val & 4) *screen++ = (15 << 8) | 'p'; if (val & 8) *screen++ = (13 << 8) | 'f'; if (val & 16) *screen++ = (12 << 8) | 'b'; if (screen > (WORD far *) 0XB8000800L) screen = (WORD far *) 0XB8000200L; }