/* Copyright (C) Magna Carta Software, Inc. 1988, 1989. All Rights Reserved CCT11.C CAPABILITY: 1) Uses interrupt driven reception; 2) Data transfer rate can be set at run time; 3) Data format can be adjusted at run time; 4) Formatted serial input is used; 5) Formatted serial output is used; 6) Direct control over the modem; NEW: A logon script facility. This program dials the Magna Carta Software BBS and logs you on automatically. NOTE: This will entail a toll call outside the Dallas, Tx. area. You should modify the number to suit if you are calling from Dallas or from outside the United States. You may modify the first name, last name, and password fields in the script below to correspond to your logon on the Magna Carta BBS. The present script logs you on as "New User" with password "newuser". NOTE: We may change our BBS logon bulletins. Therefore this script may go out of date without notice. If this happens, log on to the BBS manually for the latest version of CCT11.C. Install a user-defined interrupt processing routine. The routine is at the bottom of this source file. This illustrates how to call your own C interrupt-processing routines from the default CCt assembly language interrupt service routines. All other options must be changed in the source code and the source recompiled to change them. */ #include #include #include #include #include #include typedef char *SCRIPT[][3]; /* MANIFEST CONSTANTS AND MACROS */ #define DO_MENU ALT_M /* key for command summary */ /* FUNCTION PROTOTYPES */ void far CDECL_ c_rx_int(void); /* prototype for the IPR */ void do_data_menu(COMM_PORT * p_port); short do_modem_menu(COMM_PORT *p_port); long do_speed_menu(COMM_PORT * p_port); void far CDECL_ lsr_int(COMM_PORT far *p); short start_transfer(COMM_PORT *p, SCRIPT file); void term(COMM_PORT *p); short menu(COMM_PORT *p); /* GLOBAL VARIABLES */ COMM_PORT port1; char phone_number[] = "226-8088";/* MAGNA CARTA BBS (change if nec.) */ BYTE rxbuf[2048]; /* RECEIVE BUFFER */ int vers = 11; MODEM m1; #include "menus.c" /* ------------------------ PROGRAM BEGINS HERE --------------------------- */ int main(void) { init_port(&port1, COM1, 19200L, DATABITS8, PARITY_NONE, STOPBITS1); /* HERE WE INSTALL THE RECEIVE INTERRUPT PROCESSING ROUTINE BUT, UNLIKE EARLIER EXAMPLES, WE INSTALL OUR OWN IPR WRITTEN IN "C". IT IS AT THE BOTTOM OF THIS SOURCE FILE. THIS ILLUSTRATES HOW TO INSTALL YOUR OWN IPR, WHICH IS CALLED DIRECTLY FROM THE INTERRUPT HANDLER AND DOES THE PROCESSING YOU WANT BEFORE RETURNING TO THE INTERRUPT HANDLER. THIS ALLOWS YOU TO DO UNUSUAL THINGS ON RECEIPT OF AN INTERRUPT WITHOUT HAVING TO MODIFY THE INTERRUPT SERVICE ROUTINE DIRECTLY. */ install_ipr(&port1, RECEIVE, (void far *) c_rx_int, rxbuf, sizeof(rxbuf)); 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); 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, ON); for (;;) { /* CHECK SERIAL PORT FOR BYTE */ 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 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_port) { short c, retval = 0, DONE = FALSE; static char *menus[] = { "\tD. Data Format", "\tS. Data Transfer Rate.", "\tM. Modem Commands.", "\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 DATA_FORMAT: do_data_menu(p_port); break; case DATA_SPEED: do_speed_menu(p_port); break; case MODEM_MENU: DONE = do_modem_menu(p_port); break; default: DONE = TRUE; break; } } puts("\nExiting menu"); set_tx_xlat(p_port, LOCAL_ECHO, FALSE); return (retval); /* will be zero except if EXIT */ } /* The Magna Carta BBS logon script. Use "as is" ro logon as "new user: or enter the approriate information for your first name, last name, and password. */ SCRIPT magna_carta_bbs = { {"What is your FIRST name: ", "new\r", "15"}, {"What is your LAST name: ", "user\r", "5"}, {"New User [Y,n]? ", "Y\r", "5"}, {"Password: ", "newuser\r", "10"}, {"Press ENTER to continue", "\r", "15"}, #if 0 {"Select:", "ma1\r", "30"}, /* messages...area change...area 1 */ {"SELECT:", "\r", "30"}, /* read next message */ #endif {NULL, "", ""} }; /* DO_MODEM_MENU -- Send commands to the modem. */ short do_modem_menu(COMM_PORT *p_port) { short key; short DONE=FALSE, ret = 0; do { puts("\nSEND COMMANDS TO THE MODEM"); puts("\nD. Dial"); puts("H. Hangup"); puts("I. Initialize"); puts("O. Go Offline"); puts("R. Reset"); puts("S. Start Script to Magna Carta BBS\n"); puts("\nAny other key exits"); key = get_key(_KEYBRD_READ) & 0XFF; switch (toupper(key)) { case 'D': modem_dial(p_port, "226-8088"); ret = 1; DONE = TRUE; break; case 'H': modem_hangup(p_port); break; case 'I': set_dtr(p_port, HIGH); modem_init(p_port, modem_type(p_port)); break; case 'O': modem_go_cmd(p_port, (short) atoi(&((MODEM *)p_port->modem)->escape[3])); break; case 'R': modem_reset(p_port); break; case 'S': if (start_transfer(p_port, magna_carta_bbs) == EOF) set_dtr(p_port, LOW); else ret = 1; DONE = TRUE; break; default: DONE = TRUE; break; } } while (!DONE); return (ret); } short run_script(COMM_PORT *p, SCRIPT s) { short i = 0; while (s[i][0] != NULL) { if (c_waits(p, s[i][0], 1000*atoi(s[i][2])) < 0) return (-i); c_puts(p, s[i][1]); i++; } return (0); } short script_icmd(COMM_PORT *p, char *s, char *resp, WORD duration) { short ret; ret = c_waits(p, s, duration); if (!ret) c_puts(p, resp); return (ret); } /* START_TRANSFER -- Main routine to handle modem file transfer. Return value: 0 -- success; EOF -- error; */ short start_transfer(COMM_PORT *p, SCRIPT file) { short ret; char sxlat[XLAT_SIZE]; save_xlat(p, sxlat); set_rx_xlat(p, LOCAL_ECHO, TRUE); set_tx_xlat(p, LOCAL_ECHO, OFF); ret = modem_dial(p, phone_number); if (ret < 0 || (ret >= 13 && ret <= 16) || ret == 18 || ret == 19) return (EOF); c_putc(p, CR); ret = run_script(p, file); if (!ret) { set_rx_xlat(p, TRAILINGBYTE_DELAY, 2000); script_icmd(p, "Press to continue...", "\r", 10000); script_icmd(p, "Select: ", "ma1\r", 5000); } puts("\nScript finished."); restore_xlat(p, sxlat); return (ret); } /* 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 FAR_ CDECL_ c_rx_int(void) { static BYTE c; static BYTE far *b_ptr; c = (BYTE) inp(port1.udata_reg_addr); b_ptr = (BYTE far *) port1.rxbufhead + 1; if (b_ptr > port1.rxbufend) b_ptr = (BYTE far *) port1.rxbuf; if (!(b_ptr == port1.rxbuftail)) { /* buffer is full */ *port1.rxbufhead = c; port1.rxbufhead = b_ptr; } } void far CDECL_ lsr_int(COMM_PORT far *p) { static WORD far *screen = (WORD far *) 0XB8000200L; 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; }