/* ** --- term.c --- ** ** EXAMPLE CODE: Terminal emulator. Can transfer files using ** ASCII, XMODEM, YMODEM, and YMODEM-G protocols. ** ** See TERM.CFG for configuration parameters. ** ** Link with TERM_IO, MODEM_IO, DIR_IO, CRC, DOS, AMODEM, XYMODEM, ** and XYPACKET. See TERM makefiles. ** ** Do NOT select YMODEM-G when using a null modem cable unless you are ** certain that RTS & CTS are reversed ( this is usually not true ). ** ** This example program (not the PCL4C library) is donated to ** the Public Domain by MarshallSoft Computing, Inc. It is ** provided as an example of the use of the PCL4C. ** */ #include #include #include #include #include #include #include #include "term.cfg" #include "pcl4c.h" #include "ascii.h" #include "term.h" #include "dir_io.h" #include "term_io.h" #include "dos_io.h" #include "modem_io.h" #include "crc.h" #include "xymodem.h" #include "amodem.h" #include "term.h" #define FALSE 0 #define TRUE !FALSE #define NORMAL 0x07 #define INVERSE 0x70 #define MESSAGE_POS 48 /* local prototypes */ void MyStart(int Port,int BaudCode); int BaudMatch(char *ptr); void ProcessESC(void); void ShowMessage(int Pos,char *Msg); void ShowMenuMessage(void); void SayFilename(char *Text); /*** Global variables ***/ #define RX_BUFFER_SIZE 2048 #define TX_BUFFER_SIZE 2048 int Port; /* current COM port [0..3] */ char FileSpec[15]; /* file name specification */ char Filename[15]; /* file name buffer */ char Buffer[1024]; /* block buffer */ char RxBuf[RX_BUFFER_SIZE]; /* receive buffer */ char TxBuf[TX_BUFFER_SIZE]; /* transmit buffer */ char *BaudRate[10] = {"300","600","1200","2400","4800","9600", "19200","38400","57600","115200"}; int BaudCode; /* baud rate code ( index into BaudRate[] ) */ char *ModelText[4] = {"Small","Compact","Medium","Large"}; char NCGchar = NAK; int OneKflag = FALSE; int BatchFlag = FALSE; char Protocol = 'X'; char TermChar = 0x00; int CharPace = 0; int Timeout = 10; int EchoFlag = TRUE; /*** main program ***/ void main(int argc,char *argv[]) {int DataFlag = FALSE; char c; int i, k; int n, rc; int Delta; /* delta port status */ int Status; /* port status */ char Version; char temp[81]; /* right number of parameters ? */ if(argc!=3) {printf("Usage: 'TERM port baud' -- example 'TERM 1 9600'\n"); exit(1); } /* get port number from command line */ Port = atoi(argv[1]) - 1; if((Port<0) || (Port>15)) {printf("Port must be 1 to 16\n"); exit(1); } /* get baud rate from command line */ BaudCode = BaudMatch(argv[2]); if(BaudCode<0) {printf("Cannot recognize baud rate = %s\n",argv[2]); exit(1); } #if 0 /*** Custom Configuration: 4 port card ***/ SioIRQ(COM1,IRQ4); SioIRQ(COM2,IRQ3); /* use IRQ2 for COM3 & COM4 */ SioIRQ(COM3,IRQ2); SioIRQ(COM4,IRQ2); #endif #if 0 /*** Custom Configuration: DigiBoard PC/8 ***/ puts("Configuring DigiBoard as COM1-COM8 (IRQ5)"); SioDelay(18); /* use 0x140 for odd IRQs & 0x141 for even IRQs */ SioPorts(8,COM1,0x140,DIGIBOARD); /* set DigiBoard UART addresses */ ErrorCheck( SioUART(Port,0x100+8*Port) ); /* set DigiBoard for IRQ5 */ ErrorCheck( SioIRQ(Port,IRQ5) ); #endif #if 0 /*** Custom Configuration: BOCA 16 port dumbcard ***/ puts("Configuring BOCA Board as COM1-COM16 (IRQ5)"); SioDelay(18); /* use base port + 7 */ SioPorts(16,COM1,0x100+7,BOCABOARD); /* set BOCA Board UART addresses */ ErrorCheck( SioUART(Port,0x100+8*Port) ); /* set DigiBoard for IRQ5 */ ErrorCheck( SioIRQ(Port,IRQ5) ); #endif /********************************************************/ /* setup receive buffer */ ErrorCheck( SioRxBuf(Port,RxBuf,Size2K) ); #if 1 /* setup transmit buffer */ ErrorCheck( SioTxBuf(Port,TxBuf,Size2K) ); #endif /* set parms & reset (initialize) COM port */ ErrorCheck( SioParms(Port,NoParity,OneStopBit,WordLength8) ); MyStart(Port,BaudCode); /* set DTR and RTS */ SioDTR(Port,'S'); SioRTS(Port,'S'); /* init CRC table */ InitCRC(); /* initialize screen */ Scroll(0,0,24,79,0,NORMAL); /* display status message */ ShowMenuMessage(); Position(1,0); /* display some info */ puts("TERM 5/1/94"); Version = SioInfo('V'); printf("Library = %d.%d\n",Version/16,Version%16); printf("Memory Model = %s\n",ModelText[3&SioInfo('M')] ); printf("TX Interrupts = "); if(SioInfo('I')) puts("enabled."); else puts("not enabled."); #if RTS_CTS_CONTROL SioFlow(Port,7*ONE_SECOND); printf("Flow Control enabled. CTS = "); if(SioCTS(Port)) puts("ON"); else puts("OFF"); #endif /* Set FIFO level */ if( SioFIFO(Port,LEVEL_14) ) puts("INS16550 detected"); /* clear PCL4C receive buffer */ ErrorCheck( SioRxFlush(Port) ); /* see TERM.H for definition of AT_COMMAND_SET */ #if AT_COMMAND_SET /* wait for Modem to say its ready */ printf("...Waiting for Modem DSR.\n"); while( !SioDSR(Port) ) {if(SioKeyPress()||SioBrkKey()) MyExit(0,"Aborted by user"); putchar('.'); SioDelay(18); } printf("...DSR is high\n"); /* initialize (Hayes compatible) modem */ SendTo(Port,"!!AT E1 S7=60 S11=60 V1 X1 Q0 S0=1!"); if(WaitFor(Port,"OK",2*ONE_SECOND)) { #if 0 /* modem is ready */ puts("\n...MODEM READY"); #else /* dial MarshallSoft Computing BBS [prefix "1,205," to # below] */ if(!DialPhone(Port,"880,9748")) puts("...Did not CONNECT"); else puts("\n...ONLINE"); #endif } else printf("\n...WARNING: Expected OK not received\n"); #endif /* enter terminal loop */ SioRxFlush(Port); while(1) {/* Control-BREAK ? */ if(SioBrkKey()) MyExit(0,"User pressed Ctrl-BREAK"); /* was key pressed ? */ if(SioKeyPress()) {/* read key press */ i = SioKeyRead(); if((char)i==ESC) {/* process user's request */ ProcessESC(); ShowMenuMessage(); continue; } else PutChar(Port,(char)i); } /* was break detected ? */ if( SioBrkSig(Port,'D') ) DisplayLine("BREAK detected ",NULL,0); /* any incoming over serial port ? */ i = GetChar(Port,(char)0); if(i>-1) {/* good character */ if(DataFlag&((i<0x20)||(i>0x7e))) {MyCrtWrite('^'); MyCrtWrite((char)('@'+i)); } else MyCrtWrite((char)i); } /* any change in DCD or DSR ? */ Delta = SioModem(Port,DeltaDCD|DeltaDSR); if(Delta) {/* display new status */ Status = SioModem(Port,(char)(DCD|DSR)); if(!Status&DeltaDCD) MyExit(0,"Dropped DSD"); if(!Status&DeltaDSR) MyExit(0,"Dropped DSR"); } } /* end -- key pressed */ } /*** write to screen except for bottom line ***/ void MyCrtWrite(char ch) {/* write character */ SioCrtWrite(ch); /* scroll all but bottom line */ if(GetRow()==24) {Scroll(0,0,23,79,1,NORMAL); Position(23,0); } } /*** make multiple attempts to reset port ***/ void MyStart(int Port,int BaudCode) {int i, rc; /* try up to 3 times to reset COM port */ for(i=0;i<3;i++) {printf("Resetting COM%d at %s baud\n",Port+1,BaudRate[BaudCode]); if( (rc = SioReset(Port,BaudCode))==0) return; if(rc<0) MyExit(rc,"Error resetting port"); SioDone(Port); /* display errors */ if(rc&OverrunError) puts("Overrun Error"); if(rc&ParityError) puts("Parity Error"); if(rc&FramingError) puts("Framing Error"); if(rc&BreakDetect) puts("Break Detect"); } exit(1); } /*** find baud rate string in table ***/ int BaudMatch(char *ptr) {int i; /* find baud rate in table */ for(i=0;i<10;i++) if(strcmp(BaudRate[i],ptr)==0) return(i); return(-1); } /*** user pressed Escape */ void ProcessESC(void) {int i; int rc; int c1, c2; char Answer[2]; /* array for 1 char answer */ int row, col; /* user pressed */ Answer[0] = '?'; Answer[1] = '\0'; DisplayLine("Q)uit P)rotocol S)end R)eceive: ",Answer,1); if(strlen(Answer)) switch(toupper(Answer[0])) { case 'P': #if RTS_CTS_CONTROL DisplayLine("A)scii X)modem Y)modem ymodem-G): ",Answer,1); #else DisplayLine("A)scii X)modem Y)modem: ",Answer,1); #endif if(strlen(Answer)) switch( toupper(Answer[0]) ) { case 'A': Protocol = 'A'; ShowMenuMessage(); TermChar = 0x18; /* CAN or control-X */ CharPace = 0; /* no inter-byte delay */ Timeout = 7; /* timeout after 7 seconds */ EchoFlag = TRUE; /* do local echo */ DisplayLine("Protocol = ASCII",NULL,1); break; case 'X': Protocol = 'X'; ShowMenuMessage(); OneKflag = FALSE; BatchFlag = FALSE; NCGchar = NAK; DisplayLine("Protocol = XMODEM",NULL,1); break; case 'Y': Protocol = 'Y'; ShowMenuMessage(); OneKflag = TRUE; BatchFlag = TRUE; NCGchar = 'C'; DisplayLine("Protocol = YMODEM",NULL,1); break; #if RTS_CTS_CONTROL case 'G': Protocol = 'G'; ShowMenuMessage(); OneKflag = TRUE; BatchFlag = TRUE; NCGchar = 'G'; DisplayLine("Protocol = YMODEM-G",NULL,1); break; #endif default: DisplayLine("Must answer X, Y, or G",NULL,1); break; } break; case 'Q': MyExit(0,"User pressed ESC"); break; case 'R': ShowMessage(strlen(BaudRate[BaudCode])+9,"'CTRL-X aborts'"); if(Protocol=='A') {/* Ascii */ DisplayLine("Enter filename:",Filename,15); if(strlen(Filename)==0) break; RxAscii(Port,Filename,Buffer,1024,RX_BUFFER_SIZE,FALSE,TermChar,Timeout,EchoFlag); break; } /* XMODEM / YMODEM receive */ if(BatchFlag) {do {/* receive files till get empty filename */ RxyModem(Port,Filename,Buffer,NCGchar,BatchFlag); if(SioKeyPress()) break; } while(Filename[0]!='\0'); } else /* not Batch */ {DisplayLine("Enter filename:",Filename,15); if(strlen(Filename)==0) break; RxyModem(Port,Filename,Buffer,NCGchar,BatchFlag); } break; case 'S': ShowMessage(strlen(BaudRate[BaudCode])+9,"'CTRL-X aborts'"); DisplayLine("Enter filename:",FileSpec,15); if(strlen(FileSpec)==0) break; if(Protocol=='A') {/* Ascii */ TxAscii(Port,FileSpec,Buffer,1024,FALSE,CharPace,TermChar,EchoFlag); break; } if(BatchFlag) {/* YMODEM send */ if(FindFirst(FileSpec,Filename)) {SayFilename(Filename); TxyModem(Port,Filename,Buffer,OneKflag,BatchFlag); while(FindNext(Filename)) {SioDelay(4); SayFilename(Filename); TxyModem(Port,Filename,Buffer,OneKflag,BatchFlag); } /* send empty filename */ Filename[0] = '\0'; SioDelay(5); TxyModem(Port,Filename,Buffer,OneKflag,BatchFlag); } } else {/* XMODEM send */ TxyModem(Port,FileSpec,Buffer,OneKflag,BatchFlag); } break; default: DisplayLine("Must answer Q, P, S, or R",NULL,0); break; } /* end switch */ } /*** show menu message ***/ void ShowMenuMessage(void) {char temp[80]; sprintf(temp," COM%d %s %c 'ESC for menu' ",1+Port,BaudRate[BaudCode],Protocol); ShowMessage(0,temp); } /*** show chosen message ***/ void ShowMessage(int Pos,char *Msg) {int i; int SaveRow; int SaveCol; int Col; SaveRow = GetRow(); SaveCol = GetCol(); Col = MESSAGE_POS+Pos; for(i=0;i