Category : Tutorials + Patches
Archive   : NAT_UART.ZIP
Filename : LBT.C
* L BBBBBB TTTTTTT CCCCC
* L B B T C C
* L B B T C
* L BBBBBB T C
* L B B T C
* L B B T .. C C
* LLLLLL BBBBBB T .. CCCCC
*
* lbt.c -- Loop Back Test Program for NSC's NS16450 UART
*
* Author: Brian A. Berg
* Berg Software Design
* October 1988
*
* Developed for: National Semiconductor Corp.
*/
#include
#include
#include
#include
#include "stdhdr.h"
#include "serio.h"
#define TESTNAME "NS16450 UART Loop Back Test Rev 1.0"
#define IH_VALUES(typ) (++Intcnt[typ], Inthist[Inthcnt++] = typ)
/* 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}; /* int. vector nos. for COMx */
/* NOTE: these base addresses are also stored in 0:400 and 0:402 */
UINT uartbadd[COM_CNT] = {0x3F8, 0x2F8}; /* UART base adds. for COMx */
UINT picmsk[COM_CNT] = {0xEF, 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: termination error count */
int termerr = TERMERR_DEF;
/* argument 3: baud rate divisor */
int baudiv = BAUDIV_DEF;
/* argument 4: debug display line boolean */
int dbgdspl = FALSE;
UCHAR bytwr = 0; /* write byte counter */
UCHAR bytrd = 0; /* read byte counter */
UINT sec = 0; /* status error count */
UINT dec = 0; /* data error count */
/* 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; /* union for data type conversions */
union REGS regs; /* 16- and 8-bit registers */
int finit = FALSE; /* boolean for program termination */
int tick = FALSE; /* boolean for display of "tick" on CRT */
int tick_ff = 0; /* tick flip-flop (either 0 or 1) */
UCHAR *tickstr[] = {"\b\b .", "\b\b. "}; /* "bouncing" dot */
#define INTYPS 6
UCHAR *Intlbl[INTYPS] = {"finit", "NOIP", "RLST", "RDAV", "THRE", "default"};
ULONG Intcnt[INTYPS] = {0L, 0L, 0L, 0L, 0L, 0L};
int Inthist[256];
UCHAR Inthcnt = 0;
/* 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 usage(void); /* display usage info and exit */
/*
* main(): main program
*/
void main(argc, argv)
int argc;
char **argv;
{
int lp;
/* process invocation args., and set up int vector no. and UART base add */
procarg(argc, argv);
savepar(); /* save our environment parameters */
/* set baud rate */
outp(LCR, 0x80); /* set DLAB */
cnvtr.intval[0] = baudiv;
outp(DLL, cnvtr.chrval[0]);
outp(DLM, cnvtr.chrval[1]);
/* set up registers for our environment */
outp(MCR, 0x08); /* enable PIC interrupt (OUT2) */
outp(LCR, 0x0B); /* 8 data, 1 stop bit, odd parity, clear DLAB */
/* read the RBR, LSR and IIR registers to clear them before we start */
(void)rdRBR();
(void)rdRBR();
(void)rdLSR();
(void)rdIIR();
printf("%s - Hit any non-control key to stop: ", TESTNAME);
/* start loop back; loop until int. handler finished or any key struck */
outp(IER, IER_VAL2);
while (!finit && !(kbhit() && getch()))
if (tick)
{
/* display the "bouncing" dot */
printf("%s", tickstr[tick_ff]);
tick_ff = 1 - tick_ff; /* update tick flip-flop */
tick = FALSE;
}
finit = TRUE; /* insure finit is TRUE in case key struck */
/* wait for TEMT in the LSR to be set or any key to be struck */
while (!(rdLSR() & TEMT) && !(kbhit() && getch()))
;
/* read the RBR, LSR and IIR registers to clear them before we exit */
(void)rdRBR();
(void)rdRBR();
(void)rdLSR();
(void)rdIIR();
/* if debug display line boolean is ON, display interrupt type counts */
if (dbgdspl)
{
printf("\nCounts of each interrupt type:\n ");
for (lp = 0; lp < INTYPS; ++lp)
printf("%s:%lu ", Intlbl[lp], Intcnt[lp]);
}
#ifdef DEBUG
printf("\n%d interrupts (4 => THRE, 3 => RDA):\n", Inthcnt);
for (lp = 0; lp < Inthcnt; ++lp)
printf("%d:%d ", lp, Inthist[lp]);
#endif
printf("\n");
if (dec || sec)
printf("Data errors=%d Status errors=%d\n", dec, sec);
rstrpar(); /* restore our environment parameters */
} /* end of main() */
/*
* serint(): serial port interrupt handler
*/
void interrupt far serint()
{
UCHAR iir, lsr; /* storage for IIR and LSR */
UCHAR bytin; /* input byte storage */
/* if finit flag has been set, record the fact but ignore the interrupt */
if (finit)
{
IH_VALUES(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 NOIP: /* NO Interrupt Pending */
IH_VALUES(1);
++sec; /* shouldn't get this interrupt */
break;
case RLST: /* Receiver Line STatus interrupt */
IH_VALUES(2);
case RDAV: /* Received Data AVailable */
if (iir == RDAV)
{
IH_VALUES(3);
}
lsr = rdLSR();
/* handle receiver-error-bits by incrementing error counter */
if (lsr & PE || lsr & FE)
++sec;
if (lsr & OE || lsr & BI)
++dec;
/* if data is ready, read it and compare it with expected value */
if (lsr & DR)
{
bytin = rdRBR();
if (bytin != ++bytrd)
++dec;
}
else if (iir == RDAV)
/* RDAV int., but DR not set */
++sec;
/* these two lines overcome UART bug by forcing IIR update: */
outp(IER, IER_VAL1);
outp(IER, IER_VAL2);
break;
case IIR_THRE: /* Transmitter Holding Register Empty */
IH_VALUES(4);
lsr = rdLSR();
if (lsr & LSR_THRE)
wrTHR(++bytwr);
else
/* THRE int., but THRE not set */
++sec;
if (!(Intcnt[4]%700L))
tick = TRUE; /* display "tick" every 700 bytes */
break;
default: /* IIR default case: FATAL ERROR */
IH_VALUES(5);
++sec; /* this shouldn't happen */
break;
}
/* terminate program if there have been any status errors
* or if data error count has hit termination error count */
if (sec || (dec >= termerr && termerr))
finit = TRUE;
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 5: /* debug display line boolean (undocumented) */
dbgdspl = TRUE;
case 4: /* baud rate divisor */
baudiv = atoi(argv[3]);
if (!MN_MX(baudiv, BAUDIV_MIN, BAUDIV_MAX))
break;
case 3: /* termination error count */
termerr = atoi(argv[2]);
if (!MN_MX(termerr, TERMERR_MIN, TERMERR_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 */
outp(LCR, 0); /* clear DLAB */
savier = (UCHAR)inp(IER); /* save original IER */
outp(IER, IER_VAL1); /* write test value to IER */
if (inp(IER) != IER_VAL1)
{
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]);
#ifdef DBG
printf("Saving iv(%#x)=%#lx->%#lx ctl-brk/c=%d->%d PIC mask=%#x->%#x\n",
ivnum, savect, _dos_getvect(ivnum),
savbrk, GETBRK(), savmsk, inp(PICMSK));
#endif
/* save registers */
/* NOTE: LCR and IER were already saved in procarg() */
savmcr = (UCHAR)inp(MCR);
outp(LCR, 0x80); /* set DLAB */
savdll = (UCHAR)inp(DLL); /* save baud */
savdlm = (UCHAR)inp(DLM); /* rate */
} /* 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);
outp(MCR, savmcr);
/* 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);
#ifdef DBG
printf("Restored: iv(%#x)=%#lx ctl-brk/c=%d PIC mask=%#x\n",
ivnum, _dos_getvect(ivnum), GETBRK(), inp(PICMSK));
#endif
} /* 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: lbt [
printf(" arg1 arg2 arg3 \n");
printf(" ('lbt' may be followed by no args, arg1, arg1+2 or arg1+2+3)\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("term-err-cnt %d (infinite) %d %d \n",
TERMERR_MIN, TERMERR_MAX, TERMERR_DEF);
printf(" (number of data errors before (%d error) \n",
TERMERR_DEF);
printf(" program will terminate) \n\n");
printf(" baudrate- %d (56000 baud) %d (%ld baud) %4d \n",
BAUDIV_MIN, BAUDIV_MAX, BAUD_NUMER/(long)BAUDIV_MAX, BAUDIV_DEF);
printf(" divisor (based on 1.8432 MHz crystal) (%ld baud) \n",
BAUD_NUMER/(long)BAUDIV_DEF);
exit(1);
} /* end of usage() */
/* end of lbt.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/