/* FFFFFFF A CCCCCC TTTTTTTTTTT CCCCCC * F A A C T C * FFFFF A A C T C * F A AAA A C T C * F A A C T .. C * F A A CCCCCC T .. CCCCCC * * FACT.C -- FIFO Asynchronous Communication Test Program for * NS16550 and NS16552 UARTs * * Greg DeJager Ver 1.0 1/31/89 * * Adapted from LBT.C -- LoopBack Test Rev 1.1 * Developed By: Brian A. Berg * Berg Software Design * October 1988 * */ #include #include #include #include #include "stdhdr.h" #include "serio.h" /* define some macros for use herein */ /* program test name for user prompt and help screen */ #define TESTNAME "NS16550/NS16552 FIFO Asynchronous Communications Test (FACT)" /* clear the RBR, LSR and IIR registers (used at start and before exit) */ #define CLEAR_REGS() ((void)rdRBR(), (void)rdRBR(), \ (void)rdLSR(), (void)rdIIR(), (void)wrMCR(0), \ (void)wrFCR(CLR_FIFO)) /* GET ctrl-break/ctrl-c checking flag status via "INT 21H" */ #define GETBRK() (regs.h.ah = 0x33, regs.h.al = 0, \ intdos(®s, ®s), regs.h.dl) /* SET ctrl-break/ctrl-c checking flag to argument via "INT 21H" */ #define SETBRK(brk) (regs.h.ah = 0x33, regs.h.al = 1, \ regs.h.dl = (brk), intdos(®s, ®s)) /* COMx-dependent parameters */ UINT comvnum[COM_CNT] = {0x0C, 0x0B, 0x0B}; /* int. vector nos. for COMx */ UINT uartbadd[COM_CNT] = {0x3F8, 0x2F8, 0x3220}; /* UART base adds. for COMx */ UINT picmsk[COM_CNT] = {0xEF, 0xF7, 0xF7}; /* PIC masks for COMx: IRQ4,3 */ /* declare parameters and default values; override via invocation line args. */ /* argument 1: COM number */ int com = COM_DEF; UINT ivnum; /* int. vector number (set as comvnum[com-1]) */ UINT ubase; /* UART base address (set as uartbadd[com-1]) */ /* argument 2: baud rate divisor */ int baudiv = BAUDIV_DEF; UCHAR bytwr = 0; /* write byte counter (goes from 0 to 255) */ UCHAR bytrd = 0; /* read byte counter (goes from 0 to 255) */ UCHAR iir, lsr; /* storage for IIR and LSR */ UCHAR bytin; /* input byte storage */ UINT errflag = FALSE; /* error indication and ID */ /* storage for original environment parameters */ void far *savect; /* interrupt vector */ UCHAR savbrk; /* ctrl-break flag */ UINT savmsk; /* PIC mask */ UCHAR savier; /* IER register */ UCHAR savlcr; /* LCR register */ UCHAR savmcr; /* MCR register */ UCHAR savdll; /* DLL register */ UCHAR savdlm; /* DLM register */ CNVTR cnvtr; /* handy union for data type conversions */ union REGS regs; /* 16- and 8-bit registers for intdos() */ int finit = FALSE; /* boolean for program termination */ /* globals which control the tick mark on the screen */ int tick = FALSE; /* boolean for display of "tick" on CRT */ int tick_ff = 0; /* tick flip-flop (either 0 or 1) */ int bytick = 0; /* helps determine when to set tick boolean */ UCHAR *tickstr[] = {"\b*", "\b$"}; /* "tick" mark strings */ /* Routines contained herein: */ void main(int, char **); /* main program */ void interrupt far serint(void); /* serial interrupt handler */ void procarg(int, char **); /* process invocation arguments */ void savepar(void); /* save our environment parameters */ void rstrpar(void); /* restore our environment parameters */ void dspstr(UCHAR *); /* display a string to console */ void usage(void); /* display usage info and exit */ /* * main(): main program */ void main(argc, argv) int argc; char **argv; { /* process invocation args., and set up int vector no. and UART base add */ procarg(argc, argv); /* get com# and baudrate from argument string */ CLEAR_REGS(); /* clear RBR, LSR, IIR, MCR, and FIFOs */ savepar(); /* save our environment parameters */ /* set baud rate */ wrLCR(0x80); /* set DLAB */ cnvtr.intval[0] = baudiv; outp(DLL, cnvtr.chrval[0]); outp(DLM, cnvtr.chrval[1]); wrLCR(0x0B); /* 8 data, 1 stop, odd parity */ printf("\n\n %s\n\n",TESTNAME); /*startup message*/ /* wait loop to insure other machine has cleared its registers */ printf("\nHit a key when other program has been started.\n\n"); while( !(kbhit() && getch()) ); /* set up registers for our environment */ wrFCR(CLR_FIFO); /* clear transmitter and receiver FIFOs */ wrFCR(FIFO_EN); /* enable FIFOs, set Rx trigger at 14 bytes */ if ( (rdIIR() & 0xc0) != 0xc0) /* ensure FIFOs present */ { printf("\nFatal Error. FIFOs not present\n"); errflag = ENDPROG; } wrMCR(OUT2); /* enable PIC interrupt (OUT2) */ wrIER(IER_VAL1); /* Enable LSI and RDAI */ wrMCR(0x0a); /* Assert RTS (and OUT2) */ printf("Waiting for first 'Request To Send' from other machine...\n\n"); while (!(rdMSR() & CTS)); /* wait for other machine to assert RTS */ printf("\n\nHit non-control key to stop: "); /* Enable Tx interupts; loop until int. handler finished or any key struck */ wrIER(IER_VAL2); while (!errflag) { if (kbhit() && getch()) errflag = ENDPROG; if (tick) /* display tick mark */ { /* display the tick mark */ printf("%s",tickstr[tick_ff]); tick_ff = 1 - tick_ff; /* update tick flip-flop */ tick = FALSE; } } wrIER(0); /* disable UART interrupts */ while ( !(rdLSR() & TEMT) ); /* wait for Tx FIFO to clear */ CLEAR_REGS(); /* clear RBR, LSR, MCR and IIR registers before we exit */ /* Output error message represented by 'errflag' variable */ switch (errflag) { case ENDPROG: /* keyboard hit or fatal error */ break; case FALSEINT: /* IIR shows no interrupt active */ printf("\nFalse interrupt. No UART interrupt active.\n"); break; case STATUSERR: /* Line Status interrupt generated */ printf("\nLine Status interrupt. LSR = %x\n",lsr); printf("Byte causing LSI = %x\n",bytin); break; case MISMATCH: /* Data received did not match data expected */ printf("\nData mismatch\n"); printf("Byte expected = %x\n",--bytrd); printf("Byte received = %x\n",bytin); break; case RX_ERROR: /* RDAI generated but DR was not set */ printf("\nError: RDAI but no DR indication\n"); break; case TX_ERROR: /* THREI generated but THRE was not set */ printf("\nError: THREI but no THRE indication\n"); break; case IIR_ERROR: /* Invalid IIR */ printf("\nIIR invalid\n"); break; case TIMEOUT: /* Character Timeout Interrupt */ printf("\nCharacter Timeout.\n"); break; case TIMEOUT_ERR: /* False Character Timeout Interrupt */ printf("\nError: False Character Timeout Interrupt.\n"); break; default: break; } /* end of switch */ rstrpar(); /* restore our environment parameters */ printf("\n\n\nEnd of program; Environment parameters restored.\n"); } /* end of main() */ /* * serint(): serial port interrupt handler */ void interrupt far serint() { int bytecnt=0; /* if errflag has been set, ignore the interrupt */ if (errflag) { wrIER(0); outp(PICTRL, EOI); /* send EOI to 8259A PIC */ return; } /* here's the code to handle each of the various interrupt types */ switch (iir = rdIIR()) { case F_NOIP: /* NO Interrupt Pending */ errflag = FALSEINT; break; case F_RLST: /* Receiver Line STatus interrupt */ lsr = rdLSR(); bytin = rdRBR(); /* read byte with error */ errflag = STATUSERR; break; case F_RDAV: /* Received Data AVailable */ wrMCR(OUT2); /* clear RTS */ lsr = rdLSR(); /* read bytes from FIFO and compare them with expected values */ while (rdLSR() & DR) { bytin = rdRBR(); if (bytin != bytrd++) { errflag = MISMATCH; break; /* error, stop reading FIFO */ } else /* display "tick" after reading 2560 bytes */ if (!bytrd && ++bytick == 10) { bytick = 0; tick = TRUE; /* turn on "tick" boolean */ } } if (!errflag) wrMCR(0x0a); /* reassert RTS */ break; case F_IIR_THRE: /* Transmitter Holding Register Empty */ lsr = rdLSR(); bytecnt = 0; if (lsr & LSR_THRE) { while (rdMSR() & CTS) /* while CTS, fill FIFO */ if (bytecnt++ <= 15) wrTHR(bytwr++); else break; } else errflag = TX_ERROR; /* THREI without THRE set */ break; case F_CHR_TIMEOUT: /* no characters received for 4 character times */ errflag = TIMEOUT; if (rdLSR() & DR) while (rdLSR() & DR) /* clear all of FIFO */ { bytin = rdRBR(); if (bytin != bytrd++) { errflag = MISMATCH; break; /* error, stop reading FIFO */ } } else errflag = TIMEOUT_ERR; /* false timeout interrupt */ break; default: /* IIR default case: FATAL ERROR */ errflag = IIR_ERROR; break; } /* Toggle INTR line of UART to create edge if multiple ints pending */ wrIER(0); if (!errflag) wrIER(IER_VAL2); outp(PICTRL, EOI); /* send EOI to 8259A PIC */ } /* end of serint() */ /* * procarg(): process invocation arguments */ void procarg(argc, argv) int argc; char **argv; { int badarg = TRUE; /* boolean: improper invocation arg. */ switch (argc) { case 3: /* baud rate divisor */ baudiv = atoi(argv[2]); if (!MN_MX(baudiv, BAUDIV_MIN, BAUDIV_MAX)) break; case 2: /* COM number */ com = atoi(argv[1]); if (!MN_MX(com, COM_MIN, COM_MAX)) break; case 1: /* no arguments => go with defaults */ badarg = FALSE; break; default: /* illegal argument count */ break; } if (badarg) usage(); /* never returns */ /* set up interrupt vector number and UART base address */ ivnum = comvnum[com-1]; ubase = uartbadd[com-1]; /* verify existence of COM port */ savlcr = (UCHAR)inp(LCR); /* save original LCR */ wrLCR(0x33); /* write test value to LCR */ if (inp(LCR) != 0x33) { printf("FATAL ERROR: COM%d not present\n", com); exit(1); } } /* end of procarg() */ /* * savepar(): save our environment parameters */ void savepar() { /* handle interrupt vector: save original and plug in our own address */ savect = _dos_getvect(ivnum); /* save original int. vector */ _dos_setvect(ivnum, serint); /* handle ctrl-break/ctrl-c status: save original flag and disable it */ savbrk = GETBRK(); SETBRK(0); /* handle PIC mask: save original mask and allow COMx to interrupt */ savmsk = inp(PICMSK); outp(PICMSK, inp(PICMSK) & picmsk[com-1]); /* save registers */ /* NOTE: LCR already saved in procarg() */ wrLCR(0x80); /* set DLAB */ savdll = (UCHAR)inp(DLL); /* save baud */ savdlm = (UCHAR)inp(DLM); /* rate */ savier = (UCHAR)inp(IER); /* save original IER */ } /* end of savepar() */ /*****************************************************************************/ /* * rstrpar(): restore our environment parameters */ void rstrpar() { /* restore registers */ outp(LCR, 0x80); /* set DLAB */ outp(DLL, savdll); /* restore baud */ outp(DLM, savdlm); /* rate */ outp(LCR, 0); /* clear DLAB */ outp(IER, savier); outp(LCR, savlcr); /* restore original address to interrupt vector */ _dos_setvect(ivnum, savect); /* restore original ctrl-break/ctrl-c checking flag */ SETBRK(savbrk); /* restore original PIC mask */ outp(PICMSK, savmsk); } /* end of rstrpar() */ /*****************************************************************************/ /* * usage(): display program usage information and terminate (never return) */ void usage() { printf("\n** HELP Screen for %s **\n\n", TESTNAME); printf("USAGE: fact [ []]\n"); printf(" arg1 arg2 \n"); printf(" ('fact' may be followed by no args, arg1, or arg1+2)\n\n"); printf(" ARGUMENT MINIMUM VALUE MAXIMUM VALUE DEFAULT VALUE \n"); printf("============ =============== =============== ==============\n"); printf(" COM-number %d (for COM%d) %d (for COM%d) %d \n", COM_MIN, COM_MIN, COM_MAX, COM_MAX, COM_DEF); printf(" (serial line %d) (serial line %d) (COM%d)\n\n", COM_MIN-1, COM_MAX-1, COM_DEF); printf(" baudrate- %d (56000 baud) %d (%ld baud) %4d \n", BAUDIV_MIN, BAUDIV_MAX, BAUDRATE(BAUDIV_MAX), BAUDIV_DEF); printf(" divisor (based on 1.8432 MHz crystal) (%ld baud) \n", BAUDRATE(BAUDIV_DEF)); printf(" * Sample baudrate divisors: for baud= 1200, use 96 * \n"); printf(" * 2400 48 * \n"); printf(" * 4800 24 * \n"); printf(" * 9600 12 * \n"); printf(" * 19200 6 * \n"); exit(1); } /* end of usage() */ /* end of act.c */