I received this from Frank Whaley ; he agreed with spreading the shar round. The shell archive attached may be corrupt since I didn't use any protection when I transferred it with my old-stylish modem; please tell me about this. Chris ------------------------------------------------------------------------- I disagree with only one point -- that interrupt-handling in C is unusable. In the US, a 25MHz 386SX is almost the minimum configuration. The attached code has been used by many people to build high-speed communication or data acquisition software. Frank Whaley Senior Programmer, Autodesk few@autodesk.com ----- #! /bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #! /bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create: # makefile # com.h # com.c # handler.c # term.c # This archive created: Sun Feb 9 18:24:20 1992 export PATH; PATH=/bin:/usr/bin:$PATH if test -f 'makefile' then echo shar: "will not over-write existing file 'makefile'" else sed 's/^X//' << \SHAR_EOF > 'makefile' X# X# makefile for dumb terminal emulator X# X X# set PORT to COM1 or COM2 XPORT = COM1 X X# set BAUD to baudrate value from com.h XBAUD = Baud2400 X X# set BITS to flags from com.h XBITS = ParityNone+Stop1+Data8 X X# set XMITINT to -DTXR_INT to include transmit interrupt code XXMITINT = X X XCFLAGS = -DPORT=$(PORT) -DBAUD=$(BAUD) -DBITS=$(BITS) $(XMITINT) X XOBJECTS = term.obj handler.obj com.obj X Xterm: term.exe X Xterm.exe: $(OBJECTS) X $(CC) $(OBJECTS) X Xhandler.obj: com.h Xcom.obj: com.h SHAR_EOF fi if test -f 'com.h' then echo shar: "will not over-write existing file 'com.h'" else sed 's/^X//' << \SHAR_EOF > 'com.h' X/* X * com.h - com port utility routines X */ X X/* port numbers */ X#define COM1 0 X#define COM2 1 X X/* funny business for MSC */ X#ifdef __TURBOC__ X#define INTERRUPT interrupt X#else X#define INTERRUPT interrupt far X#define inportb inp X#define outportb outp X#define getvect _dos_getvect X#define setvect _dos_setvect X#define disable _disable X#define enable _enable X#endif X X/* ports and masks */ X#define DLH(p) (p?0x2F9:0x3F9) /* Divisor Latch High */ X#define DLL(p) (p?0x2F8:0x3F8) /* Divisor Latch Low */ X#define IER(p) (p?0x2F9:0x3F9) /* Interrupt Enable Register */ X#define IIR(p) (p?0x2FA:0x3FA) /* Interrupt Ident Register */ X#define LCR(p) (p?0x2FB:0x3FB) /* Line Control Register */ X#define LSR(p) (p?0x2FD:0x3FD) /* Line Status Register */ X#define MCR(p) (p?0x2FC:0x3FC) /* Modem Control Register */ X#define MSR(p) (p?0x2FE:0x3FE) /* Modem Status Register */ X#define RBR(p) (p?0x2F8:0x3F8) /* Receiver Buffer Register */ X#define THR(p) (p?0x2F8:0x3F8) /* Transmit Holding Register */ X#define IMSK(p) (p?~0x08:~0x10) /* interrupt enable mask */ X#define VEC(p) (p?11:12) /* interrupt vector number */ X X/* IER bits */ X#define MSI 0x08 /* Modem Status Int */ X#define RLSI 0x04 /* Rx Line Status Int */ X#define THREI 0x02 /* THRE Int */ X#define DAI 0x01 /* Data Available Int */ X/* IIR bits */ X#define IID1 0x04 /* Int ID 1 */ X#define IID0 0x02 /* Int ID 0 */ X#define IP 0x01 /* Interrupt Pending */ X/* LCR bits */ X#define DLAB 0x80 /* Divisor Latch Access Bit */ X#define SB 0x40 /* Set Break */ X#define SP 0x20 /* Stick Parity */ X#define EPS 0x10 /* Even Parity Select */ X#define PEN 0x08 /* Parity Enable */ X#define STB 0x04 /* Stop Bits */ X#define WLS1 0x02 /* Word Length Select 1 */ X#define WLS0 0x01 /* Word Length Select 0 */ X/* LSR bits */ X#define TSRE 0x40 /* Tx Shift Register Empty */ X#define THRE 0x20 /* Tx Holding Register Empty */ X#define BI 0x10 /* Break Interrupt */ X#define FE 0x08 /* Framing Error */ X#define PE 0x04 /* Parity Error */ X#define OR 0x02 /* Overrun Error */ X#define DR 0x01 /* Data Ready */ X/* MCR bits */ X#define LOOP 0x10 /* Loopback */ X#define OUT1 0x08 /* Output 1 */ X#define OUT2 0x04 /* Output 2 */ X#define RTS 0x02 /* Request To Send */ X#define DTR 0x01 /* Data Terminal Ready */ X/* MSR bits */ X#define RLSD 0x80 /* Rx Line Signal Detect */ X#define RI 0x40 /* Ring Indicator */ X#define DSR 0x20 /* Data Set Ready */ X#define CTS 0x10 /* CTS line */ X#define DRLSD 0x08 /* Delta Rx Line Signal Detect */ X#define TERI 0x04 /* Trailing Edge Ring Indicator*/ X#define DDSR 0x02 /* Delta Data Set Ready */ X#define DCTS 0x01 /* Delta Clear To Send */ X X/* interrupt values */ X#define RSTATUS 0 /* Receiver Line Status */ X#define RDR IID1 /* Received Data Ready */ X#define TXR IID0 /* Transmit Ready */ X#define MSTATUS (IID0+IID1) /* Modem Status */ X X/* 8259 ports/flags */ X#define EOI 0x20 /* End of Interrupt */ X#define INTA00 0x20 /* interrupt controller */ X#define INTA01 0x21 /* interrupt mask */ X X/* baud rate divisors */ X#define Baud50 2304 X#define Baud75 1536 X#define Baud110 1047 X#define Baud134_5 857 X#define Baud150 768 X#define Baud300 384 X#define Baud600 192 X#define Baud1200 96 X#define Baud1800 64 X#define Baud2000 58 X#define Baud2400 48 X#define Baud3600 32 X#define Baud4800 24 X#define Baud7200 16 X#define Baud9600 12 X#define Baud19200 6 X#define Baud38400 3 X X#define ParityNone 0 /* pick one */ X#define ParityOdd PEN X#define ParityEven (PEN+EPS) X X#define Stop1 0 /* pick one */ X#define Stop2 STB /* 1-1/2 bits if 5 data bits */ X X#define Data5 0 /* pick one */ X#define Data6 WLS0 X#define Data7 WLS1 X#define Data8 (WLS0+WLS1) X X/* functions */ Xextern void ComOpen(int port, int baud, int bits, int ints, X void (INTERRUPT * handler)()); Xextern void ComClose(int port); X X/* END of com.h */ SHAR_EOF fi if test -f 'com.c' then echo shar: "will not over-write existing file 'com.c'" else sed 's/^X//' << \SHAR_EOF > 'com.c' X/* X * com.c - com port utility routines X */ X X#include X#include X X#include "com.h" X X /* place to save original vectors */ Xstatic void (INTERRUPT *oldvec[2])(); X X/* X-* ComOpen - open and init com port X */ X void XComOpen( X int port, /* port number, 0 or 1 */ X int baud, /* baud rate divisor */ X int bits, /* other parameter bits */ X int ints, /* interrupts to handle */ X void (INTERRUPT *handler)() /* interrupt handler */ X ) X{ X assert((port == COM1) || (port == COM2)); X /* set baud rate */ X outportb(LCR(port), DLAB); X outportb(DLL(port), baud); X outportb(DLH(port), baud >> 8); X /* set other parameters, clear DLAB */ X outportb(LCR(port), bits & ~DLAB); X /* no interrupts through this */ X outportb(IER(port), 0); X /* save original interrupt vector */ X oldvec[port] = getvect(VEC(port)); X /* install new handler */ X setvect(VEC(port), handler); X /* clear pending status */ X inportb(LSR(port)); X inportb(RBR(port)); X inportb(IIR(port)); X inportb(MSR(port)); X /* init MCR with DTR, RTS & OUT1 */ X outportb(MCR(port), inportb(MCR(port)) | (DTR+RTS+OUT1)); X /* set our interrupt mask */ X outportb(INTA01, inportb(INTA01) & IMSK(port)); X /* select interrupts */ X outportb(IER(port), ints); X} X X/* X-* ComClose - unhook interrupt handler X */ X void XComClose(int port) X{ X assert((port == COM1) || (port == COM2)); X /* turn off serial interrupts */ X outportb(IER(port), 0); X /* turn off MCR */ X outportb(MCR(port), 0); X /* reset interrupt mask */ X outportb(INTA01, inportb(INTA01) | ~IMSK(port)); X /* restore interrupt handler */ X setvect(VEC(port), oldvec[port]); X} X X/* END of com.c */ SHAR_EOF fi if test -f 'handler.c' then echo shar: "will not over-write existing file 'handler.c'" else sed 's/^X//' << \SHAR_EOF > 'handler.c' X/* X * handler.c - sample com port interrupt handler X * X * Demonstration of COM package X */ X X#include X#include X X#include "com.h" X X#ifdef TXR_INT X#define INTS MSI+RLSI+THREI+DAI X#else X#define INTS MSI+RLSI+DAI X#endif X X#define rBufSize 64 /* receive buffer size */ X#define sBufSize 16 /* send buffer size */ X X/* break flag */ Xunsigned char Break = 0; /* non-zero if break received */ X X/* buffer jazz */ Xstatic unsigned char rBuf[rBufSize]; /* receive buffer */ Xstatic int rBufCnt; Xstatic int rIn; Xstatic int rOut; Xstatic unsigned char sBuf[sBufSize]; /* send buffer */ Xstatic int sBufCnt; Xstatic int sIn; Xstatic int sOut; X X/* X * serial interrupt handler X */ X static void INTERRUPT Xhandler() X{ X register unsigned input; X X /* which interrupt ?? */ X switch ( inportb(IIR(PORT)) & (IID1+IID0) ) X { X case RSTATUS: /* Receiver Line Status */ X /* just check for break */ X if ( inportb(LSR(PORT)) & BI ) X Break++; X break; X X case RDR: /* Received Data Ready */ X /* drop RTS line */ X outportb(MCR(PORT), inportb(MCR(PORT)) & ~RTS); X /* get and buffer byte */ X input = inportb(RBR(PORT)); X if ( rBufCnt < rBufSize ) X { X rBufCnt++; X rBuf[rIn++] = input; X if ( rIn >= rBufSize ) X rIn = 0; X } X break; X X case TXR: /* Transmit Ready */ X#ifdef TXR_INT X /* anything there ?? */ X if ( sBufCnt ) X { X /* spit one from buffer */ X outportb(THR(PORT), sBuf[sOut++]); X sBufCnt--; X if ( sOut >= sBufSize ) X sOut = 0; X } X else X#endif X /* tell them to shut up */ X outportb(IER(PORT), inportb(IER(PORT)) & ~THREI); X break; X X case MSTATUS: /* Modem Status */ X inportb(MSR(PORT)); /* just clear */ X break; X } X X /* signal end-of-interrupt, twice for stacked interrupts */ X outportb(INTA00, EOI); X outportb(INTA00, EOI); X X/* X * Bug-fix thanks to Steve Miller (uunet!pictel!miller) and David Kessner X * (david@kessner.denver.co.us). This code solves the problem on some X * 'budget' serial cards which lock when a byte is received in the X * middle of a send. Unfortunately, it doesn't work everywhere. X */ X#if 0 X /* create interrupt edge */ X input = inportb(IER(PORT)); X outportb(IER(PORT), 0); X outportb(IER(PORT), input); X#endif X} X X/* X-* ComInstall - install com port handler X */ X void XComInstall() X{ X /* reset buffers */ X rBufCnt = rIn = rOut = 0; X sBufCnt = sIn = sOut = 0; X /* open com port */ X ComOpen(PORT, BAUD, BITS, INTS, handler); X} X X/* X-* ComRelease - release com port X */ X void XComRelease() X{ X /* unhook interrupts */ X ComClose(PORT); X} X X/* X-* ComGet - get byte from com port X */ X int XComGet() X{ X int c; X X /* just return byte if there */ X if ( rBufCnt ) X { X disable(); X c = rBuf[rOut++]; X rBufCnt--; X if ( rOut >= rBufSize ) X rOut = 0; X enable(); X return ( c ); X } X X /* raise RTS again */ X outportb(MCR(PORT), inportb(MCR(PORT)) | RTS); X /* no byte ready */ X return ( -1 ); X} X X/* X-* ComPut - output byte to com port X */ X int XComPut(unsigned char out) X{ X#ifdef TXR_INT X if ( sBufCnt < sBufSize ) X { X /* stuff into buffer */ X sBufCnt++; X sBuf[sIn++] = out; X if ( sIn >= sBufSize ) X sIn = 0; X /* make sure interrupts enabled */ X outportb(IER(PORT), inportb(IER(PORT)) | THREI); X /* good return */ X return ( 0 ); X } X X /* buffer overflow */ X return ( -1 ); X#else X unsigned timer = 0xFFFF; X X /* wait for ready state */ X while ( (!(inportb(LSR(PORT)) & THRE) || X !(inportb(MSR(PORT)) & CTS)) && X timer ) X { X timer--; X } X /* timeout ?? */ X if ( !timer ) X return ( -1 ); X X outportb(THR(PORT), out); X return ( 0 ); X#endif X} X X/* END of handler.c */ SHAR_EOF fi if test -f 'term.c' then echo shar: "will not over-write existing file 'term.c'" else sed 's/^X//' << \SHAR_EOF > 'term.c' X/* X * term.c - dumb terminal emulator X * X * Demonstration of COM package X */ X X#include X#include X X/* X * good old main X */ X void Xmain() X{ X int c; X X /* install handler */ X ComInstall(); X /* loop until Ctrl-X entered */ X for ( ;; ) X { X /* send kbd input if there */ X if ( kbhit() ) X { X c = getch(); X /* exit on Ctrl-X */ X if ( c == 24 ) X break; X else if ( ComPut(c) < 0 ) X putch(7); /* beep */ X } X X /* display host data if there */ X if ( (c = ComGet()) >= 0 ) X putch(c); X } X /* release handler */ X ComRelease(); X} X X/* END of term.c */ SHAR_EOF fi exit 0 # End of shell archive sbustd chbl (25):