miker@wjvax.UUCP (Michael Ryan) (02/24/88)
interrupt driven serial communications had me stumped
but just a few weeks ago, before my vacation, I persevered.
the following program reads a stupid com1 port and does no
handshaking to control, in our case, a simple data line from a key pad.
the program has compiled, assembled, linked and run on a stock PC AT
with dos 3.3, Msoft C 5.0 , and Msoft Macro Assembler 5.0.
there are 3 files: serial.c , the main routine with the interrupt handler;
uart.asm, the uart initialization procedure; and file, the MAKE utility
data file.
you may look at the assembly portion and say 'hey, I could do that in
C with inp/outp statements.' well, so did I, but it does not function.
oh well.
WATCHOUT, this is a transcription from PC printout to
our R+D Optimum V system. there may be typos.
this may not be the greatest utility in the world, but it works.
our 'real' implementation does not print out the input characters, but
uses a ring buffer to process them.
NOTE: this code was PRODUCED on WJ time, and WJ and I do not guarantee
it or place copyright on it, or anything else really lame for such a small
piece of 'mostly borrowed' code.
I transcribed the code on my time.(ahem)
please use it in good health and if you can get it to work all in C then
please mail me the code.
michael ryan
...!wjvax!miker
O / cut here
-----------------o--------------------------------------------
O \
/*
file: serial.c
microsoft C 5.0
main routine and interrupt handler for serial com1
input. dumb routine with no handshaking and no ring
buffering. mostly an exercise in com1 control
and very dear to my heart as it saved the day.
call: serial [ loopcount ]
loopcount: optional loop count for input of data.
the larger the loop the more chars in, however , the
limit on chars in is 258 ( just because ).
*/
#include <dos.h>
#include <stdio.h>
#include <stdlib.h>
/* serial communications definitions, com 1 */
#define _COM1 0xc
#define COMBASE ((unsigned int) 0x3f8) /* com 1 */
#define RXREG (COMBASE)
#define INTEN (COMBASE + 1) /* int enable */
#define INTID (COMBASE + 2) /* int identification */
#define LSTAT (COMBASE + 5) /* line status */
#define MSTAT (COMBASE + 6) /* modem status */
#define PIC_EOI ((unsigned int) 0x20) /* PIC instruction address
and instruction for end of interrupt */
/* local control definitions */
#define TIMEOUT 100000L
#define MAXKEY 258
extern void far uart(); /* the assembler uart routine */
void interrupt far handler1(void); /* our interrupt handler */
void (interrupt far *oldcom1)(); /* var to hold old handler.
not real useful HERE, but good practice */
void (interrupt far *newhandler)(); /* var to hold address of new handler for
use in _dos_setvect. using the handler
identifier does not work, but this method
of indirection does */
static int pflag; /* interrupt received flag. why the name?
it had meaning, once */
main(argc,argv)
int argc;
char **argv;
{
/* yeah, redundant declarations,but I like to play it safe */
void interrupt far handler1;
extern void ( interrupt far *oldcom1)();
extern void ( interrupt far *newhandler)();
extern int pflag;
register long count, timeout;
int in; /* input variable */
char keys[MAXKEY]; /* input buffer */
int keycount;
timeout = TIMEOUT; /* default */
if ( argc > 1 ) { /* if arg try to use it as count */
timeout = atol(argv[1]);
if ( timeout == 0 ) /* paranoid */
timeout = TIMEOUT;
}/*fi*/
printf("starting .. %ld count.\n",timeout);
oldcom1 = _dos_getvect(_COM1); /* capture old handler */
newhandler = handler1; /* set variable indirection
as described by Msoft support people */
_dos_setvect(_COM1, newhandler );
uart(); /* asm procedure to set uart:
9600, odd, 8 data, 2 stop , interrupt on data ready */
for ( pflag=in=keycount=0,count=0L; count < timeout ; count += 1 ) {
if ( pflag ) {
_disable();
in = inp( RXREG ); /* read data from uart */
keys[keycount++] = (char) in;
if ( keycount >= MAXKEY )
break; /* get out to dos reset */
pflag = 0; /* reset flag */
_enable();
}/*fi*/
}/*rof*/
/* dos reset */
_dos_setvect(_COM1,oldcom1);
keys[keycount] = '\0' ; /* null terminate string */
printf("chars in: %s.\n",keys); /* print all keys in */
exit(0);
}/* eo main */
/*
handler1:
handle com1 interrupts by setting the pflag and resetting
the PIC
*/
void cdecl interrupt far handler1()
{
extern int pflag;
pflag =1;
_enable(); /* not done automatically by Msoft 'interrupt'
function construct */
(void) outp(PIC_EOI,PIC_EOI); /* reset pic */
}/*eo handler1 */
O / cut here
-----------------o--------------------------------------------
O \
; file: uart.asm
; microsoft macro assembler 5.0
;
; uart initialization file
; a lot lifted from mr. ray duncan.
DOSSEG
PAGE 58, 132
TITLE 'uart -- assembler module of serial.exe '
PUBLIC _uart
.MODEL large
; definitions for com 1
; not all used, but handy to know
comm_data equ 03f8h ; uart data
comm_ier equ 03f9h ; uart interrupt enable reg
comm_mcr equ 03fch ; uart modem control reg
comm_stat equ 03fdh ; line status
com_int equ 0ch ; com 1 interrupt
int_mask equ 010h ; mask for 8259
pic_mask equ 021h ; port address 8259 mask reg
pic_eoi equ 020h ; port address 8259 EOI instruction
.CODE
_uart proc far
xor dx, dx ; zero dx: com1 value
mov ah, 0 ; bios finit value
mov al, 0efh ; 9600 baud,odd parity,8 data,2 stop
int 14h ; bios service
mov dx, comm_mcr ; modem control, because it
; was in the ex and I have not
; tested without it
mov al, 0bh ; modem control DTR,RTS,OUT2
out dx, al
mov dx, comm_ier ; interrupt enable register
mov al, 1 ; on data ready
out dx, al
in al, pic_mask ; read current 8259 mask
and al, 0efh ; == not int_mask
nop ; insert clock ticks (3)
; may not be necessary
out pic_mask, al ; write the new one back
ret
_uart endp
end
O / cut here
-----------------o--------------------------------------------
O \
# file : file
# MAKE utility
# use: make file
# creates serial.exe
# creates asm output for inspection, links for debugging
CFLAGS=/AL /Fa /Zi /c
LFLAGS=/CO
MFLAGS=/Zi
# assumes Msoft cl, link, and masm in your path
CC=cl $(CFLAGS)
LN=link $(LFLAGS)
AS=masm $(MFLAGS)
.C.OBJ :
$(CC) $*.c
.ASM.OBJ :
$(AS) $*,,,;
serial.obj : serial.c
uart.obj : uart.asm
serial.exe : serial.obj uart.obj
$(LN) $**, $@;
--
==== *michael j ryan
*{..!pyramid,..!decwrl!qubix}!wjvax!miker
*Watkins-Johnson Co., San Jose CA : (408) 435 1400 x3079
* above views are not necessarily those of Watkins-Johnson Co.