[comp.sources.amiga] v90i176: st - interrupt-driven serial i/o testbed, Part01/01

Amiga-Request@cs.odu.edu (Amiga Sources/Binaries Moderator) (06/04/90)

Submitted-by: jcs@crash.uucp
Posting-number: Volume 90, Issue 176
Archive-name: util/st/part01

  This code directly accesses the hardware and achieves very high
baud rates without errors.  This code should be legal if the serial
device is first opened and exclusive access is granted.  Speeds of
over 130k baud between a stock, nofastmem 500 and a 25mhz GVP 68030
have been achieved.  The '030 Amiga can go much faster; it can read
at least 223,720 baud.  The 500 poops out at 132,575 baud.  Writing
fast is no problem, reading eats up some bandwidth, and is thus
the bottleneck.  Polled I/O (yuk) can yield faster rates. These
baud rates were accomplished with a direct 2,3,7 wire, 50 foot
shielded cable.  Max baud rates may vary depending on cable and
hardware configurations.

#!/bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 1 (of 1)."
# Contents:  input.c input.h inputhandler.a makefile readme serial.a
#   st.c
# Wrapped by tadguy@xanth on Sun Jun  3 20:05:27 1990
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'input.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'input.c'\"
else
echo shar: Extracting \"'input.c'\" \(2035 characters\)
sed "s/^X//" >'input.c' <<'END_OF_FILE'
X/* input.c
X   created by John Schultz, 10-Sep-89
X   
X*/
X
X#include <exec/types.h>
X#include <exec/io.h>  
X#include <exec/ports.h>
X#include <exec/interrupts.h>  
X#include <proto/exec.h>
X#include <proto/graphics.h>
X#include <devices/input.h>
X#include <devices/inputevent.h>
X#include "input.h"
X
Xunsigned short volatile raw; /* raw key value */
X
Xstruct MsgPort indevport;
Xstruct MsgPort * indevportptr;
Xstruct IOStdReq * inreqblockptr;
Xstruct Interrupt inhandler;
Xstruct InputEvent * eventp;
X
Xextern void totalinput();
X
Xint createti(void) {
X
X  indevportptr = CreatePort("indevport",0);
X  if (!indevportptr) {
X    return 0;
X  }
X
X  inreqblockptr = CreateStdIO((struct MsgPort *)indevportptr);
X  if (!inreqblockptr) {
X   DeletePort(indevportptr); 
X   return 0;
X  }
X
X  inhandler.is_Data = (APTR)&raw;
X  inhandler.is_Code = totalinput;
X  inhandler.is_Node.ln_Pri = 51; /* One ahead of Intuition */
X
X  if (OpenDevice("input.device",0L,
X                 (struct IORequest *)inreqblockptr,0L)) {
X    DeletePort(indevportptr);
X    DeleteStdIO(inreqblockptr);
X    return 0; 
X  }
X
X  inreqblockptr->io_Command = IND_ADDHANDLER;
X  inreqblockptr->io_Data    = (APTR)&inhandler;
X  
X  if (DoIO((struct IORequest *)inreqblockptr)) {
X    DeletePort(indevportptr);
X    DeleteStdIO(inreqblockptr);
X    CloseDevice((struct IORequest *)inreqblockptr);
X    return 0;
X  }
X
X  GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",0);
X  if(!GfxBase) {
X    DeletePort(indevportptr);
X    DeleteStdIO(inreqblockptr);
X    CloseDevice((struct IORequest *)inreqblockptr);
X    return 0;
X  }
X  FreeSprite(0);
X
X  CloseLibrary((struct Library *)GfxBase);
X
X  return 1;  
X
X} /* end createti */
X
Xvoid deleteti(void) {
X
X  if ((indevportptr) && (inreqblockptr)) {
X    inreqblockptr->io_Command = IND_REMHANDLER;
X    inreqblockptr->io_Data = (APTR)&inhandler;
X    DoIO((struct IORequest *)inreqblockptr);
X    CloseDevice((struct IORequest *)inreqblockptr);
X    DeleteStdIO(inreqblockptr);
X    DeletePort(indevportptr);
X  } /* end if */
X
X} /* END deleteti */
X
X
X/* END input.c */
END_OF_FILE
if test 2035 -ne `wc -c <'input.c'`; then
    echo shar: \"'input.c'\" unpacked with wrong size!
fi
# end of 'input.c'
fi
if test -f 'input.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'input.h'\"
else
echo shar: Extracting \"'input.h'\" \(241 characters\)
sed "s/^X//" >'input.h' <<'END_OF_FILE'
X/* input.h - total input
X   created by John Schultz, 10-Sep-89
X*/
X
X#ifndef INPUTTI
X#define INPUTTI
X
Xextern unsigned short volatile raw;  /* raw key input */
X
Xextern int createti(void);
X
Xextern void deleteti(void);
X
X#endif
X
X/* end input.h */
END_OF_FILE
if test 241 -ne `wc -c <'input.h'`; then
    echo shar: \"'input.h'\" unpacked with wrong size!
fi
# end of 'input.h'
fi
if test -f 'inputhandler.a' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'inputhandler.a'\"
else
echo shar: Extracting \"'inputhandler.a'\" \(418 characters\)
sed "s/^X//" >'inputhandler.a' <<'END_OF_FILE'
X; Input Handler
X; created by John Schultz, 17-Sep-89
X
X	section	"TotalInput",code
X
X	xdef	_totalinput
X
X; Input event structure offsets
X
XIECLASS	equ	4
XIECODE	equ	6
X
X; A0 = inputevent pointer
X; A1 = data pointer
X
X_totalinput:
X	cmp.b	#1,IECLASS(A0)	; event->ie_Class == IECLASS_RAWKEY ?
X	bne.b	notrawkey
X	move.w	IECODE(A0),(A1)	; raw = event->ie_Code
Xnotrawkey:
X	moveq.l	#0,D0		; don't pass events to intuition
X	rts
X
X	END
X
END_OF_FILE
if test 418 -ne `wc -c <'inputhandler.a'`; then
    echo shar: \"'inputhandler.a'\" unpacked with wrong size!
fi
# end of 'inputhandler.a'
fi
if test -f 'makefile' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'makefile'\"
else
echo shar: Extracting \"'makefile'\" \(352 characters\)
sed "s/^X//" >'makefile' <<'END_OF_FILE'
X# serial makefile, created by John Schultz, 17-Sep-89
X
Xst: st.o serial.o input.o inputhandler.o
X  blink from lib:c.o+st.o+serial.o+input.o+inputhandler.o to st \
X             lib lib:lc.lib sc sd nd
X
Xst.o: st.c
X  lc -O st.c
X
Xserial.o: serial.a
X  asm serial.a
X
Xinput.o: input.h input.c
X  lc input.c
X
Xinputhandler.o: inputhandler.a
X  asm inputhandler.a
X
END_OF_FILE
if test 352 -ne `wc -c <'makefile'`; then
    echo shar: \"'makefile'\" unpacked with wrong size!
fi
# end of 'makefile'
fi
if test -f 'readme' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'readme'\"
else
echo shar: Extracting \"'readme'\" \(2076 characters\)
sed "s/^X//" >'readme' <<'END_OF_FILE'
X
X                Interrupt-driven Serial I/O Testbed
X                          by John Schultz
X                              4/16/90
X
X  This code directly accesses the hardware and achieves very high
Xbaud rates without errors.  This code should be legal if the serial
Xdevice is first opened and exclusive access is granted.  Speeds of
Xover 130k baud between a stock, nofastmem 500 and a 25mhz GVP 68030
Xhave been achieved.  The '030 Amiga can go much faster; it can read
Xat least 223,720 baud.  The 500 poops out at 132,575 baud.  Writing
Xfast is no problem, reading eats up some bandwidth, and is thus
Xthe bottleneck.  Polled I/O (yuk) can yield faster rates. These
Xbaud rates were accomplished with a direct 2,3,7 wire, 50 foot
Xshielded cable.  Max baud rates may vary depending on cable and
Xhardware configurations.
X  The current test code, ST (Serial Test), writes characters typed
Xon the keyboard 10 times.  Errors at high speed show up when less
Xthan 10 characters are received or funny characters are inserted.
X  I can run DNet and leave it running while I run this code!  DNet
Xmust be idling, and the baud rate must be the same as DNet's (usually
X19200) the last time you run ST.  This is very useful as quiting and
Xrestarting DNet is not necessary.
X  Part of the original assembly code came from the Amiga Transactor,
XSeptember 1989: Volume 2, Issue 6,pp 42-44, by Mike Schwartz.  The 
Xexample changed the AutoVectors directly, and had a few typos. I use
XSetIntVector(), and do things a little differently with the rbf and
Xtbe code. This was pretty much the first assembly language program I
Xwrote, so experts feel free to point out improvements. 
X  I wrote the code using Lattice 5.04.  I currently use the Cape
Xor Devpac assemblers for speed, but for this example used Lattice's
Xasm (everyone with Lattice should have it).
X
X  As always, please point out any optimizations, errors, or illegal
Xacts committed in this code. If you enhance the code, please email me
Xa copy.
X
X  Use this code as you wish; no strings, ropes, cables, or
Xbungee cords attached.
X
X
X
X    John
END_OF_FILE
if test 2076 -ne `wc -c <'readme'`; then
    echo shar: \"'readme'\" unpacked with wrong size!
fi
# end of 'readme'
fi
if test -f 'serial.a' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'serial.a'\"
else
echo shar: Extracting \"'serial.a'\" \(5691 characters\)
sed "s/^X//" >'serial.a' <<'END_OF_FILE'
X; Serial.a
X; created by John Schultz, 17-Sep-89
X; last modified 17-April-90
X
X	section	Serial,CODE
X
X	xref	_raw
X
X	xdef	_baudper
X	xdef	_openserial
X	xdef	_closeserial
X	xdef	_sendser
X	xdef	_readser
X	xdef	_checkser
X	xdef	_rawtoascii
X	xdef	_sendsernobuff
X
X
X_LVOSetIntVector equ	$FFFFFF5E
X
XESCAPE		equ	69		; input-handler rawkey code
X
XCLOCK		equ	3579545
X_baudper	dc.w 	(CLOCK/19200)-1	; defaualt
X
XCUSTOM		equ	$dff000
XSERDATR		equ	$000018
XSERDAT		equ	$000030
XSERPER		equ	$000032
X
XINTENA		equ	$00009a
XINTENAR		equ	$00001c
XINTREQ		equ	$00009c
X
XTBEQSIZE	equ	128		; buffer size in bytes,
XRBFQSIZE	equ	128		; increase or decrease as needed
X
XLED		equ	$bfe001		; toggle power led, audio filter
X
Xledroll		dc.b	%00010001	; flash every 4 bytes
Xledpad		dc.b	0
X
Xoldintena	dc.w	0
X
Xtbequeue	ds.b	TBEQSIZE	; circular queue
Xtbeqend
Xtbehead		dc.l	tbequeue
Xtbetail   	dc.l	tbequeue
X
Xoldtbeinterrupt	dc.l	0
Xoldrbfinterrupt	dc.l	0
X
Xtbeinterrupt
X	dc.l	0	; ln_succ
X	dc.l	0	; ln_prec
X	dc.b	2	; NT_INTERRUPT
X	dc.b	127	; ln_pri
X	dc.l	0	; ln_name
X	dc.l	tbehead	; is_data
X	dc.l	tbehandler ; is_code
X
Xrbfinterrupt
X	dc.l	0	; ln_succ
X	dc.l	0	; ln_prec
X	dc.b	2	; NT_INTERRUPT
X	dc.b	127	; ln_pri
X	dc.l	0	; ln_name
X	dc.l	rbftail	; is_data
X	dc.l	rbfhandler ; is_code
X
X
Xtbehandler	
X	move.w	#1,INTREQ(a0)		; clear TBE interrupt
X	move.l	(a1),a1			; a1 = tbehead, (a1) = pointer
X	cmp.l	tbetail,a1		; now a1 = pointer
X	beq.b	99$
X	move.w	SERDATR(a0),d0		; check to make sure emtpy
X	btst	#13,d0
X	beq.b	99$
X	move.w	#$100,d0
X	move.b	(a1)+,d0		; get byte from queue
X	move.w	d0,SERDAT(a0)		; send byte
X	cmpa.l	#tbeqend,a1
X	bne.b	10$
X	lea	tbequeue(pc),a1
X10$	move.l	a1,tbehead
X99$
X	rts
X
Xrbfqueue	ds.b	RBFQSIZE
Xrbfqend	
Xrbfhead		dc.l	rbfqueue
Xrbftail		dc.l	rbfqueue
X
Xrbfhandler
X	move.w	SERDATR(a0),d0		; a0 = custom
X	move.w	#$800,INTREQ(a0)	; clear RBF interrupt
X	move.l	(a1),a0			; a1 = rbftail, get pointer
X	move.b	d0,(a0)+		; write byte to buffer
X	cmpa.l	#rbfqend,a0
X	bne.b	10$
X	lea	rbfqueue(pc),a0
X10$	move.l	a0,(a1)			; a1 = rbftail
X
X;99$
X;	move.b	ledroll(pc),d0		; remove from 99$-100$ for more
X;	rol.b	#1,d0			; speed
X;	move.b	d0,ledroll
X;	btst	#1,d0
X;	beq.b	100$
X;	bchg.b	#1,LED			; toggle power led / audio filter
X;100$
X	rts
X
X_openserial
X	move.l	a6,-(sp)
X	lea	CUSTOM,a0
X	move.w	#$4000,INTENA(a0)	; disable
X	move.l	$4,a6			; execbase
X	lea	rbfinterrupt(pc),a1
X	moveq.l	#11,d0
X	jsr	_LVOSetIntVector(a6)
X	move.l	d0,oldrbfinterrupt
X	lea	tbeinterrupt(pc),a1
X	moveq.l	#0,d0
X	jsr	_LVOSetIntVector(a6)
X	move.l	d0,oldtbeinterrupt
X
X	lea	CUSTOM,a0
X	move.w	_baudper,SERPER(a0)	; set period
X
X	move.w	#$3fff,$bfd0fe		; init handshake lines
X	move.w	INTENAR(a0),oldintena
X	move.w	#$8801,INTENA(a0)	; turn on RBF and TBE INTENA
X	move.w	#$0801,INTREQ(a0)	; clear RBF and TBE INTREQ
X	move.w	#$c000,INTENA(a0)	; enable
X	move.l	(sp)+,a6
X	rts
X
X
X_closeserial
X	move.l	a6,-(sp)
X	lea	CUSTOM,a0
X	move.w	#$4000,INTENA(a0)	; disable
X	move.l	$4,a6			; execbase
X	move.l	oldrbfinterrupt,a1
X	moveq.l	#11,d0
X	jsr	_LVOSetIntVector(a6)
X	move.l	oldtbeinterrupt,a1
X	moveq.l	#0,d0
X	jsr	_LVOSetIntVector(a6)
X
X	lea	CUSTOM,a0
X	move.w	#$0801,INTENA(a0)	; turn off RBF and TBE INTENA
X	move.w	oldintena,d0
X	and.w	#$0801,d0		; mask for bit 11 and bit 1.
X	bset	#15,d0			; set/clr = 1 (set)
X	move.w	d0,INTENA(a0) 		; reset old RBF and TBE INTENA
X
X	bclr.b	#1,LED
X
X	move.w	#$0801,INTREQ(a0)	; clear RBF and TBE INTREQ
X	move.w	#$c000,INTENA(a0)	; enable
X	move.l	(sp)+,a6
X	rts
X
X_sendser
X	lea	CUSTOM,a0
X	move.w	#$4000,INTENA(a0)
X
X	move.l	tbetail,a1
X	cmpa.l	tbehead,a1
X	beq.b	5$
X	move.w	#$8001,INTREQ(a0)	; generate a tbe interrupt
X5$
X	move.b	d0,(a1)+		; queue up byte
X	cmpa.l	#tbeqend,a1
X	bne.b	10$
X	lea	tbequeue(pc),a1
X10$	move.l	a1,tbetail
X	
X	move.w	#$c000,INTENA(a0)
X	rts
X
X
X; send byte in d0 to serial port, non-buffered.
X_sendsernobuff
X	lea	CUSTOM,a0
X	move.w	#$4000,INTENA(a0)
X1$	move.w	SERDATR,d1
X	btst	#13,d1			; check TBE
X	beq.b	1$			; buffer busy
X	
X	move.w	#$100,d1
X	move.b	d0,d1
X	move.w	d1,SERDAT(a0)
X2$	move.w	SERDATR(a0),d1
X	btst	#13,d1			; check TBE
X	beq.b	2$			; buffer busy
X	move.w	#$001,INTREQ(a0)	; clear TBE interrupt
X
X	move.w	#$c000,INTENA(a0)
X	rts
X
X
X; uses a0
X_readser
X	cmp.w	#ESCAPE,_raw	; quits on ESC from input handler
X	beq.b	20$
X	move.l	rbfhead,a0
X	cmpa.l	rbftail,a0
X	beq.b	_readser
X	move.b	(a0)+,d0
X	cmpa.l	#rbfqend,a0
X	bne.b	10$
X	lea	rbfqueue(pc),a0
X10$	move.l	a0,rbfhead
X20$
X	rts
X
X_checkser
X	move.l	rbfhead,a0
X	cmpa.l	rbftail,a0
X	bne.b	dataisin
X	moveq.l	#0,d0
X	rts
Xdataisin
X	moveq.l	#1,d0
X	rts
X
X
X; rawkey in d0
X; ascii returned in d0
X_rawtoascii
X	cmp.b	#79,d0
X	bls.b	getascii	
X	moveq.l	#0,d0
X	rts
Xgetascii
X	lea	asciitable,a0
X	move.b	0(a0,d0),d0
X	rts
X
X
X	section	asciitable,data
X
X; This is a quick trick, don't do this for anything other than
X; home use, boys and girls.  Use rawkeyconvert, etc.
X
Xasciitable
X	dc.b	'`'	; backquote `
X	dc.b	'1'
X	dc.b	'2'
X	dc.b	'3'
X	dc.b	'4'
X	dc.b	'5'
X	dc.b	'6'
X	dc.b	'7'
X	dc.b	'8'
X	dc.b	'9'
X	dc.b	'0'
X	dc.b	'-'
X	dc.b	'='
X	dc.b	$0D	; \
X	dc.b	0
X	dc.b	'0'	; keypad 0
X	dc.b	'q'
X	dc.b	'w'
X	dc.b	'e'
X	dc.b	'r'
X	dc.b	't'
X	dc.b	'y'
X	dc.b	'u'
X	dc.b	'i'
X	dc.b	'o'
X	dc.b	'p'
X	dc.b	'['
X	dc.b	']'
X	dc.b	0
X	dc.b	'1'
X	dc.b	'2'
X	dc.b	'3'
X	dc.b	'a'
X	dc.b	's'
X	dc.b	'd'
X	dc.b	'f'
X	dc.b	'g'
X	dc.b	'h'
X	dc.b	'j'
X	dc.b	'k'
X	dc.b	'l'
X	dc.b	';'
X	dc.b	$27	; ' single quote
X	dc.b	0
X	dc.b	0
X	dc.b	'4'
X	dc.b	'5'
X	dc.b	'6'
X	dc.b	0
X	dc.b	'z'
X	dc.b	'x'
X	dc.b	'c'
X	dc.b	'v'
X	dc.b	'b'
X	dc.b	'n'
X	dc.b	'm'
X	dc.b	','
X	dc.b	'.'
X	dc.b	'/'
X	dc.b	0
X	dc.b	'.'	; keypad
X	dc.b	'7'
X	dc.b	'8'
X	dc.b	'9'
X	dc.b	' '
X	dc.b	$8	; backspace
X	dc.b	$9	; tab
X	dc.b	$D	; enter  cr
X	dc.b	$D	; return cr
X	dc.b	$1B	; ESC
X	dc.b	$7f	; delete
X	dc.b	''
X	dc.b	0
X	dc.b	0
X	dc.b	'-'	; keypad
X	dc.b	0
X	dc.b	0	
X	dc.b	$b	; up arrow
X	dc.b	$a	; down arrow
X	dc.b	$20	; rt arrow
X	dc.b	$8	; left arrow
X	
X	END
END_OF_FILE
if test 5691 -ne `wc -c <'serial.a'`; then
    echo shar: \"'serial.a'\" unpacked with wrong size!
fi
# end of 'serial.a'
fi
if test -f 'st.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'st.c'\"
else
echo shar: Extracting \"'st.c'\" \(1882 characters\)
sed "s/^X//" >'st.c' <<'END_OF_FILE'
X/* ST.c : Serial Test */
X/* Created by John Schultz, 4/16/90 */
X/* Interrupt driven serial I/O testbed */
X
X#include <stdio.h>
X#include <dos.h>
X#include "input.h"
X
X#define CLOCK 3579545
X
X#define MINBAUD 300        /* Change these at will */
X#define MAXBAUD 230000
X
X#define BUFFSIZE 80
X
X#define ESCAPE 69
X
Xextern void openserial(void);
Xextern void __asm sendser(register __d0 char c);
Xextern void __asm sendsernobuff(register __d0 char c);
Xextern char __asm readser(void);
Xextern short __asm checkser(void);
Xextern char __asm rawtoascii(register __d0 char c);
X
Xextern short far baudper;
X
Xvoid main(int argc,char ** argv) {
Xshort i = 0;
Xlong console;
Xlong baud;
Xchar traw;
Xshort notquit = 1;
Xchar buffer[BUFFSIZE];
X
X
X  if (argc != 2) {
X    printf("USAGE: st <baud>\n");
X    exit(0);
X  }
X
X  baud = atoi(argv[1]);
X  if (baud < MINBAUD)
X    baud = MINBAUD;
X  else if (baud > MAXBAUD)
X    baud = MAXBAUD;
X
X  printf("Setting baud to %d. Press ESC to quit.\n",baud);
X  
X  baudper = (CLOCK / baud)-1;
X
X  console = _dopen("*",MODE_OLDFILE);
X  if (console == -1) {
X    printf("Couldn't open console.\n");
X    exit(0);
X  }
X
X  if (createti()) {
X    openserial();
X    traw = 0;
X    raw = 0;
X
X    while (notquit) {
X      if (raw) {
X        traw = raw;
X        raw = 0;
X	if (traw == ESCAPE) notquit = 0;    /* ESC */
X        traw = rawtoascii(traw);
X        sendser(traw);
X        sendser(traw);
X        sendser(traw);
X        sendser(traw);
X        sendser(traw);
X        sendser(traw);
X        sendser(traw);
X        sendser(traw);
X        sendser(traw);
X        sendser(traw);
X
X      }
X
X      if (checkser())
X        for (i = 0;
X            (i < BUFFSIZE) && (checkser());
X            buffer[i++] = readser());
X      
X      if (i > 0) _dwrite(console,buffer,i);
X
X      i = 0;
X
X    } /* while notquit */
X
X    closeserial();
X    deleteti();
X  } /* if createti */
X
X  printf("\n");
X
X} /* END ST.c */
END_OF_FILE
if test 1882 -ne `wc -c <'st.c'`; then
    echo shar: \"'st.c'\" unpacked with wrong size!
fi
# end of 'st.c'
fi
echo shar: End of archive 1 \(of 1\).
cp /dev/null ark1isdone
MISSING=""
for I in 1 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have the archive.
    rm -f ark[1-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0
-- 
Mail submissions (sources or binaries) to <amiga@cs.odu.edu>.
Mail comments to the moderator at <amiga-request@cs.odu.edu>.
Post requests for sources, and general discussion to comp.sys.amiga.