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.