Category : Tutorials + Patches
Archive   : NAT_UART.ZIP
Filename : FACT.C
* 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 [
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 */
Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!
This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.
But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/