Category : Tutorials + Patches
Archive   : NAT_UART.ZIP
Filename : ACTB.C

 
Output of file : ACTB.C contained in archive : NAT_UART.ZIP
/* A CCCCCC TTTTTTTTTTT BBBBB CCCCCC
* A A C T B B C
* A A C T BBBBB C
* A AAA A C T B B C
* A A C T B B C
* A A CCCCCC T BBBBB .. CCCCCC
*
* ACTB.C -- Asynchronous Communication Test Program for
* INS8250 and INS8250N-B UARTs
*
* Greg DeJager Ver 1.0 2/15/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 "INS8250/INS8250N-B Asynchronous Communications Test (ACTB)"
/* 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))

/* 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 (default divisor = 96 giving 1200 baud) */
int baudiv = BAUDIV_DEFB;

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; /* error indication and ID */
UINT flowcntr=0, test=0;

/* 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() */

/* 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 */

/* globals for debug to determine the ordering and number of interrupts */
#define INTYPS 6
UCHAR *Intlbl[INTYPS] = {"finit", "NOIP", "RLST", "RDAV", "THRE", "default"};
UINT Intcnt[INTYPS] = {0, 0, 0, 0, 0, 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 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);

CLEAR_REGS(); /* clear RBR, LSR, IIR, and MCR */

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 */
wrMCR(OUT2); /* enable PIC interrupt (OUT2) */
wrLCR(0x0B); /* 8 data, 1 stop bit, odd parity, clear DLAB */
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 the tick mark */
dspstr(tickstr[tick_ff]);
tick_ff = 1 - tick_ff; /* update tick flip-flop */
tick = FALSE;
}
}
wrIER(0);
CLEAR_REGS(); /* clear RBR, LSR, MCR and IIR registers before we exit */
printf("Receiver interrupt serviced %d times",test);

/* Output error message represented by 'errflag' variable */
switch (errflag)
{
case ENDPROG: /* no error; keyboard hit to end program */
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");

default:
break;
} /* end of switch */

printf("\n\n\nEnd of program; Environment parameters restored.\n");

rstrpar(); /* restore our environment parameters */

} /* end of main() */

/*
* serint(): serial port interrupt handler
*/

void interrupt far serint()
{

/* 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 NOIP: /* NO Interrupt Pending */
errflag = FALSEINT;
break;

case RLST: /* Receiver Line STatus interrupt */
lsr = rdLSR();
bytin = rdRBR();
errflag = STATUSERR;
break;

case RDAV: /* Received Data AVailable */
wrMCR(OUT2); /* clear RTS */
test++;
lsr = rdLSR();
/* if data is ready, read it and compare it with expected value */
if (lsr & DR)
{
bytin = rdRBR();
if (bytin != bytrd++)
errflag = MISMATCH;
else
/* display "tick" after reading 2560 bytes */
if (!bytrd && ++bytick == 10)
{
bytick = 0;
tick = TRUE; /* turn on "tick" boolean */
}
}
else if (iir == RDAV)
errflag = RX_ERROR; /* Receive int but no DR set */

if (!errflag)
wrMCR(0x0a); /* reassert RTS */
break;

case IIR_THRE: /* Transmitter Holding Register Empty */
if (!(rdLSR() & LSR_THRE))
errflag = TX_ERROR;
else
if (rdMSR() & CTS) /* insure CTS active */
{
wrTHR(bytwr++);
flowcntr = 0;
}
else
if ((++flowcntr) >= 50) /* timeout check */
errflag = ENDPROG;
break;

default: /* IIR default case: FATAL ERROR */
errflag = IIR_ERROR;
break;
}

/* fix of 8250 asynchronous bug */
if (rdLSR() & LSR_THRE)
{
wrIER(IER_VAL1);
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() */

/*
* dspstr(): display a string of characters on the console
*/
void dspstr(chrstr)
UCHAR *chrstr;
{
UCHAR *ptr = chrstr;

for( ; *ptr; )
{
regs.x.bx = 7; /* display page and attribute */
regs.h.ah = 0x0E; /* write char. in TTY mode */
regs.h.al = *ptr++; /* get char. and inc. ptr. */
int86(0x10, ®s, ®s); /* perform "INT 10H" */
}

} /* end of dspstr() */

/*****************************************************************************/

/*
* usage(): display program usage information and terminate (never return)
*/

void usage()
{
printf("\n** HELP Screen for %s **\n\n", TESTNAME);
printf("USAGE: actb [ []]\n");
printf(" arg1 arg2 \n");
printf(" ('actb' 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= 300, use 384 * \n");
printf(" * 600 192 * \n");
printf(" * 1200 96 * \n");
printf(" * 2400 48 * \n");
printf(" * 4800 24 * \n");
exit(1);

} /* end of usage() */

/* end of actb.c */


  3 Responses to “Category : Tutorials + Patches
Archive   : NAT_UART.ZIP
Filename : ACTB.C

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. 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/