;*; Updated on 25-Nov-91 at 8:21 AM by Michele Tonti; edit time: 0:00:25
;*************************** AMUS Program Label ******************************
; Filename: INPTMR.M68 Date: 11/25/91
; Category: SBR Hash Code: 446-237-522-113 Version:
; Initials: RELI/AM Name: MIKE SELVY
; Company: REL, Inc. Telephone #: 5039292704
; Related Files: INPTMR.BAS,INPTMR.DOC
; Min. Op. Sys.: Expertise Level:
; Special: Requires NOECHO
; Description: Routine obtains input from the job's terminal input buffer,
; timing out if a given number of seconds passes. Timing aborts if character
; from buffer is C/R or ^C.
;*****************************************************************************
;
; NAME: INPTMR.M68 09/11/19/MCS
;
; AUTHOR: Mike Selvy
; EDIT HISTORY:
; When Who What
; 11/16/84 TAD Tom Dahlquist wrote TIMEIN.M68/.SBR
; 09/11/91 MCS Mike Selvy plagiarized TIMEIN.M68
; 11/21/91 MCS now timeout from last char, not start of routine
; 11/23/91 MCS handles ^C immediately instead of after timeout
; 11/24/91 MCS sets noecho and image mode
; 11/24/91 MCS if TIMEOUT>1 echo char; if TIMEOUT<1 noecho char
;
OBJNAM .SBR
;
; FUNCTION: This routine obtains input from the job's terminal
; input buffer, timing out if a given number of seconds passes.
; Timing aborts if the character from the input buffer is a [c/r]
; (carriage return) or ^C. The timeout restarts from the last
; character received.
;
; CALLING SEQUENCE:
; XCALL INPTMR,BUFFER,TIMEOUT where
; Name Type Use
; BUFFER Any This is where the characters are returned. The
; size of this field implies the maximum # of
; bytes that can be returned.
; TIMEOUT Float This is how long to wait for input before returning
; to Basic. If this number is negative, character
; will not be echoed back to user. NOTE: The # of
; characters received is returned in this field. (If
; routine timed-out or a ^C, then -1 is returned
; instead of char count).
SEARCH SYS
SEARCH SYSSYM
SEARCH TRM
; Map of timer queue block usage
ASECT
TLINK: BLKL 1 ; used by system...-> next in q
TCOUNT: BLKL 1 ; used by system...timer count
TADDR: BLKL 1 ; address of routine to execute
TJCB: BLKL 1 ; address of our JCB
TFLAG: BLKL 1 ; address of flag to set on timeout
PSECT
VMAJOR=1. ; System version (BBS SYSTEM)
VMINOR=1. ; Program version
VSUB=2. ; Tested flag (should match thru system)
VEDIT=110. ; (any change)
INPTMR: PHDR -1,PV$RSM!PV$WSM,PH$REU!PH$REE
CMPW (A3)+,#2 ; must be two args...
JNE RETURN ; die if not.
LEA A3,2(A3) ; skip arg. type (s/b string)
MOV (A3)+,A0 ; A0 -> buffer...
MOV (A3)+,D2 ; D2 = length of buffer...
DEC D2 ; D2 = length of buffer - 1...
MOVW (A3)+,D6 ; test type of last arg...
ANDW #7,D6 ; must be float...
CMPW D6,#4
JNE RETURN ; die of not.
MOV @A3,A1 ; A0 -> float #
FFTOL @A1,D0 ; D0 now contains timeout value
MOV D0,D5 ; save number in D5 for later
CMP D0,#0 ; timeout less than 0?
JEQ RETURN ; (timeout=0? that was dumb...)
BPL GRZRO ; if not<0 skip to GRZRO
CLR D0 ; put a 0 in D0
SUB D5,D0 ; sub D5 from 0, D0 now positive
GRZRO: MOV D2,D6 ; D6 = length of buffer - 1...
MOV A0,A6 ; A6 -> buffer...
CLEAR: CLRB (A6)+ ; clear out return buffer...
DBF D6,CLEAR
CLR D3 ; D3 used to count chars received.
; CLR D1 ; D1 is char received from input buffer
JOBIDX A6 ; keep address of trmdef in A5...
MOV JOBTRM(A6),A5
ORW #T$IMI,T.STS(A5) ; set image mode (auto-reset at exit)
ORW #T$ECS,T.STS(A5) ; set noecho mode (auto-reset at exit)
;
; OK, set up a timer queue block, then loop looking for characters.
; If/when input buffer (terminal) is empty, we goto sleep via a JWAIT.
; When awakened, one of the following has happened: a) input buffer
; has chars. in it; or b) elapsed time has expired. We can tell which
; by checking a flag byte. If timed out, check how much time since
; last character was received. If greater than our timeout number,
; we return, otherwise requeue the timer block with a new value.
;
CALL SETQ ; set up timer Q block...
TIMTCK: TST T.ICC(A5) ; looking for characters...
BEQ NOPE ; if Y (no chars), br out of loop
TIMKBD: KBD TIMQT ; (else) get char, (br TIMQT if ^C)
CMPB D1,#15 ; check if <c/r>
BEQ TIMQT ; if Y, br out of TIMTCK loop
CMP D5,#0 ; timeout less than 0?
BMI TINCHO ; then dont echo character
TTY ; (char already in D1)
TINCHO: MOVB D1,(A0)+ ; store it,
INC D3 ; count it,
DBF D2,TIMTCK ; if D2 > -1, dec D2 and loop again
TIMQT: CALL UNSETQ ; get rid of timer Q block...
BR STOREL ; and leave.
NOPE: GTIMEI D4 ; D4 = current time...
NOPE2: TST T.ICC(A5) ; look again, is anything now there?
BNE TIMKBD ; if N (= chars), br into TIMTCK loop
JWAIT: JWAIT J.TIW ; (else) sleepy time...
TSTB @A4 ; did we time out?
BEQ TIMKBD ; if N, br into TIMTCK loop
; ; (else:)
GTIMEI D6 ; D6 = current time
SUB D4,D6 ; D6 = time elapsed since last char
MOV D0,D7 ; D7 = timeout seconds
SUB D6,D7 ; D7 = difference
BLE TIMOUT ; if zero or neg, we timed out
MOV D0,D7 ; RESET TIMER WITH OLD TIMEOUT
MUL D7,#10000. ; (else) requeue block with
MOV D7,TCOUNT(A1) ; new count...
CLRB @A4 ; clear out flag byte...
TIMER @A1 ; requeue it...
BR NOPE2 ; look again, then back to sleep
TIMOUT: QRET A1 ; get rid of Q block...
NOWAIT: TST T.ICC(A5) ; last look for chars
BEQ NOCR ; if Y (no chars), br to exit
KBD NOCR ; (else) get char (br NOCR if ^C)
CMPB D1,#15 ; check if <c/r>
BEQ STOREL ; if Y, br to exit
CMP D5,#0 ; timeout less than 0?
BMI NONCHO ; then dont echo character
TTY ; (char already in D1)
NONCHO: MOVB D1,(A0)+ ; store it,
INC D3 ; count it,
DBF D2,NOWAIT ; if D2 > -1, dec and last look again
NOCR: CLR D3 ; clear char count and decrement
DEC D3 ; return -1 if timed out
;
; Store character count and return.
;
STOREL: MOV @A3,A0 ; A0 -> TIMEOUT variable
FLTOF D3,@A0 ; store char. count in TIMEOUT
RETURN: RTN ; exit back to basic
;
; Set up a timer Q block and start the clock ticking.....
;
SETQ: QGET A1 ; get a system Q block...
BNE DIEQ ; die if none available...
JOBIDX A6 ; A6 -> our JCB...
MOV A6,TJCB(A1)
MOV D0,D7
MUL D7,#10000. ; convert secs to timer ticks...
MOV D7,TCOUNT(A1)
LEA A6,WAKEME ; A6 -> timer exit routine...
MOV A6,TADDR(A1)
MOV A4,TFLAG(A1) ; A4 -> flag byte (in BASIC area)
CLRB @A4 ; clear flag byte...
TIMER @A1 ; start timer...
RTN
DIEQ: EXIT
;
; Come here to get rid of timer Q entry. This is complicated due to
; three possibilities: 1) we don't find our entry in the timer Q--don't
; do anything; 2) we find it and it is the first entry--we stick a
; substitute exit routine into the Q block itself which just returns
; the block to the system when called; 3) we find it and it is not the
; first block in the Q--we remove it, add its time to the next block
; in the Q, and return it to the system.
;
UNSETQ: SUPVR
SVLOK
MOV TIMQUE,D6 ; A6 -> first timer Q block...
BEQ DONEDQ ; if none, all done.
MOV D6,A6
CMP A6,A1 ; ours first?
BEQ CHGQ ; go change it if so...
DQLOOP: MOV A6,A2 ; A2 -> previous Q block...
MOV @A6,D6
BEQ DONEDQ ; if no more, all done.
MOV D6,A6
CMP A6,A1 ; ours?
BNE DQLOOP ; if not, go get next...
MOV @A1,A6 ; A6 -> next block in Q...
MOV A6,@A2 ; remove us from Q, and
BEQ 1$ ; if there is a next block we
MOV TCOUNT(A1),D6
ADD D6,TCOUNT(A6) ; add our timer count to its.
1$: QRET A1 ; return Q block to system...
DONEDQ: LSTS #0 ; user mode, allow interrupts
RTN
CHGQ: MOV #DEQL-1,D1 ; length of dummy exit routine...
LEA A6,TJCB(A1) ; where to move it...
MOV A6,TADDR(A1)
LEA A2,DEQSTF
CQLOOP: MOVB (A2)+,(A6)+
DBF D1,CQLOOP
LSTS #0 ; user mode, allow interrupts
RTN
DEQSTF: SUB #14,A0
QRET A0
RTN
DEQL = .-DEQSTF
;
; This is the timer exit routine. It sets the flag byte and returns.
;
WAKEME: MOV TFLAG-14(A0),A6 ; A6 -> flag byte...
SETB @A6 ; set flag...
MOV TJCB-14(A0),A0 ; A0 -> our JCB...
JRUN J.TIW+J.NXT ; run job...
RTN