	public  serini, serrst, clrbuf, outchr, coms, vts, dodel, ctlu
        public  cmblnk, locate, lclini, prtchr, dobaud, clearl
        public  dodisk, getbaud, beep, term, puthlp
	public	count, poscur, machnam, sendbr, putmod, clrmod
	public	setktab, setkhlp, xofsnt, showkey
        include msdefs.h

false   equ     0
true	equ	1	

ctrla	equ	1		; Control-A.

auxin	equ	3
auxout	equ	4
auxfil	equ	3		; file number of aux file.
iordy	equ	6		; input ready function
write	equ	40h
wbios	equ	88h
settrp	equ	02h
clrtrp	equ	03h
chrrdy	equ	01h
txrdy	equ	02h

rcvdat	equ	1080h
rcvstat equ	1082h
rcvmod	equ	1084h
rcvcmd	equ	1086h
trdat	equ	1088h
trmod	equ	108ch
wrcmd	equ	108eh

; mode bits
mod1	equ	4dh			; clock rate, 8 bits, 1 stop bit
mod2	equ	30h			; internal clock

; command register bits
txen	equ	01h
dtr	equ	02h
rxen	equ	04h
brk	equ	08h
clrerr	equ	10h
rts	equ	20h


datas   segment public 'datas'
        extrn   drives:byte, flags:byte, trans:byte
	extrn	portval:word, port1:byte, port2:byte

portin	db	0
crlf    db      cr,lf,'$'
machnam	db	'FIELD TEST Wang$'
noimp	db	cr,lf,'Command not implemented.$'
shkmsg	db	'Not implemented.'
shklen	equ	$-shkmsg
xofsnt	db	0		; Say if we sent an XOFF.
xofrcv	db	0		; Say if we received an XOFF.
setktab	db	0
setkhlp	db	0
invseq	db	esc,'[7m$'	; Reverse video on.
nrmseq	db	esc,'[0m$'	; Reverse video off.
ivlseq	db	79 dup (' '),cr,'$' 	; Make a line inverse video
comphlp db      cr,lf,'1 (COM1)   2 (COM2)$'    
delstr  db      BS,' ',BS,'$' 	; Delete string.
clrlin	db	cr,esc,'[K$'
tmp     db      ?,'$'
temp    dw      0
temp1   dw      ?               ; Temporary storage.
temp2   dw      ?               ; Temporary storage.

; Entries for choosing communications port. [19b]
comptab db      04H
        db      01H,'1$'
        dw      01H
        db      01H,'2$'
        dw      00H
        db      04H,'COM1$'
        dw      01H
        db      04H,'COM2$'
        dw      00H

; variables for serial interrupt handler

source  db      bufsiz DUP(?)   ; Buffer for data from port.
bufout  dw      0               ; buffer removal ptr
count   dw      0               ; Number of chars in int buffer.
bufin   dw      0               ; buffer insertion ptr
telflg  db      0               ; Are we acting as a terminal. [16] [17c]
clreol  db      esc,'[0K$'
blank	db	esc,'[H',esc,'[J$'
movcur  db      esc,'['
colno   db      20 dup (?)
ten     db      10
prthnd  dw      0
ourarg  termarg <>
; must parallel baud rate defs in pcdefs.
baudtab db	0ffh		; 45.5 baud (not supported)
	db	0		; 50
	db	1		; 75
	db	2		; 110
	db	3		; 134.5
	db	4		; 150
	db	5		; 300
	db	6		; 600
	db	7		; 1200
	db	8		; 1800
	db	9		; 2000
	db	10		; 2400
	db	12		; 4800
	db	14		; 9600
	db	15		; 19.2k
	db	0ffh		; 38.4k (ha)

nbaud	equ	$-baudtab
qid	dw	?
prtcnt	dw	?
trqid	dw	?
tmqid	dw	?
brflg	db	?
datas   ends

code    segment public
        extrn   comnd:near, dopar:near, prserr:near
        assume  cs:code,ds:datas

DODISK  PROC    NEAR
	mov ah,gcurdsk			; Current disk value to AL.
	int dos
	mov dl,al			; Put current disk in DL.
	mov ah,seldsk			; Select current disk.
	int dos				; Get number of drives in AL.
	mov drives,al
	ret
DODISK  ENDP

; Clear the input buffer before sending a packet. [20e]

CLRBUF  PROC    NEAR
	mov	ah,ioctl
	mov	bx,auxfil
	mov	al,iordy
	int	dos
	cmp	al,0ffh
	jne	clrb1			; not ready, keep going
	mov	ah,auxin
	int	dos
	jmp	clrbuf			; read char and keep going.
clrb1:	mov	count,0
	mov ax,offset source
	mov bufin,ax
        mov bufout,ax
        ret
CLRBUF  ENDP

; Common routine to clear to end-of-line. [19a]

CLEARL  PROC    NEAR
        mov dx,offset clreol
        mov ah,prstr
        int dos
        ret
CLEARL  ENDP

; This routine should set the baud rate for the current port but it
; is actually done in SERINI.
dobaud	proc	near
	ret
dobaud  endp

; Send a break out the current serial port.  Returns normally.
sendbr:	push dx
	push ax
	push cx
	push ds			; preserve data segment
	mov ax,cs
	mov ds,ax		; handler is in code segment
	mov al,settrp
	mov bx,txrdy		; interrupt on transmitter empty
	mov cx,0		; interrupt immediately
	mov dx,offset sendb1	; handler routine
	int wbios
	pop ds
	mov trqid,bx
	push ds
	mov ax,cs
	mov ds,ax
	mov al,settrp
	mov bx,0		; 10 ms timer
	mov cx,21		; after 21 times - approx 200 ms.
	mov dx,offset sendb2	; timer interrupt
	int wbios
	pop ds
	mov tmqid,bx

	mov brflg,1
	mov dx,rcvcmd
	in al,dx		; Read command register.
	or al,brk+txen		; Set send-break bit.
	mov dx,wrcmd		; Write command register.
	out dx,al
pause:	cmp brflg,0
	jne pause		; while non-zero, keep going
	mov al,clrtrp		; clear the trap
	mov bx,trqid
	int wbios
	mov al,clrtrp
	mov bx,tmqid
	int wbios
	pop cx
	pop ax
	pop dx
	ret

sendb1	proc	far
	ret
sendb1	endp

sendb2	proc	far
	push ax
	push ds
	mov ax,seg datas
	mov ds,ax
	mov brflg,0
	mov dx,rcvcmd
	in al,dx
	and al,not (txen + brk)
	mov dx,wrcmd
	out dx,al
	pop ds
	pop ax
	ret
sendb2	endp


; Write a line in inverse video at the bottom of the screen...
; the line is passed in dx, terminated by a $.  Returns normally.
putmod	proc	near
	push	dx		; preserve message
	mov	dx,24 * 100H	; line 24
	call	poscur
	mov	dx,offset invseq ; put into inverse video
	mov	ah,prstr
	int	dos
	pop	dx
	int 	dos
	mov	dx,offset nrmseq ; normal videw
	int	dos
	ret			; and return
putmod	endp

; Clear the mode line written by putmod.  Returns normally.
clrmod	proc	near
	mov	dx,24 * 100H
	call	poscur
	call	clearl
	ret
clrmod	endp

; Put a help message one the screen in reverse video.  Pass
; the message in AX, terminated by a null.  Returns normally.
; The message is put wherever the cursor currently is located.
puthlp	proc	near
	push ax
	mov ah,prstr		; Leave some room before the message.
	mov dx,offset crlf
	int dos
	mov dx,offset invseq	; Put into reverse video.
	int dos
	pop si			; Put message address here.
puth0:	mov ah,prstr
	mov dx,offset ivlseq	; Make line inverse video
	int dos
puth1:	lodsb
	cmp al,0		; Terminated with a null.
	je puth2
	mov dl,al
	mov ah,conout
	int dos	
	cmp al,lf		; Line feed?
	je puth0		; Yes, clear the next line.
	jmp puth1		; Else, just keep on writing.
puth2:	mov dx,offset nrmseq	; Normal video.
	mov ah,prstr
	int dos
	mov dx,offset crlf
	int dos
	ret
puthlp	endp

outchr: push dx                 ; Save register.
	mov al,ah
	call dopar
	mov dl,al
	mov ah,auxout
	int dos
	pop	dx
	jmp rskp


; This routine blanks the screen.

CMBLNK	PROC	NEAR
        mov ah,prstr
        mov dx,offset blank
        int dos
        ret
CMBLNK  ENDP

LOCATE  PROC    NEAR
        mov dx,0                ; Go to top left corner of screen.
        jmp poscur              ; callret...
LOCATE  ENDP

GETBAUD PROC    NEAR
	cld
	mov dx,rcvmod
	in al,dx
	in al,dx		; get second mode word
	and	al,0fh		; isolate baud rate
	mov cx,nbaud
	mov di,offset baudtab
	mov bx,ds
	mov es,bx		; address correct segment
	mov bx,portval
	repne scasb		; look for baud rate
	jne getb1		; mystery baud rate...
	sub di,offset baudtab + 1
	mov [bx].baud,di	; store baud rate in comm area
	ret			; and return
getb1:	mov [bx].baud,-1	; unknown baud rate
        ret
GETBAUD ENDP

; skip returns if no character available at port,
; otherwise returns with char in al, # of chars in buffer in dx.
PRTCHR  PROC    NEAR
prtchx: cmp count,0
	je prtch4		; empty buffer, forget it.
	mov si,bufout
	lodsb
	cmp si,offset source + bufsiz
	jb prtch1
	mov si,offset source
prtch1: mov bufout,si
	dec count
	push bx
	mov bx,portval
        cmp [bx].parflg,PARNON ; no parity?
        je prtch3               ; then don't strip
        and al,7fh              ; else turn off parity
prtch3: mov dx,count		; chars left in buffer
	pop bx
        ret
prtch4: jmp rskp		; no chars...
PRTCHR  ENDP

; Position the cursor according to contents of DX.

POSCUR  PROC    NEAR
        mov     ax,ds
        mov     es,ax                   ; address data segment!!!
        cld
        mov     di,offset colno
        mov     al,dh                   ; row
	inc	al
        call    nout
        mov     al,';'
        stosb
        mov     al,dl                   ; col
	inc	al
        call    nout
        mov     al,'H'
        stosb
        mov     al,'$'
        stosb
        mov     dx,offset movcur
        mov     ah,prstr
        int     dos                     ; print the sequence
        ret
POSCUR  ENDP

NOUT	PROC	NEAR
        cbw                     ; extend to word
        div     byte ptr ten    ; divide by 10
        or      al,al           ; any quotient?
        jz      nout1           ; no, forget this
        push    ax              ; save current result
        call    nout            ; output high order
        pop     ax              ; restore
nout1:  mov     al,ah           ; get digit
        add     al,'0'          ; make printable
        stosb
        ret                     ; put in buffer and return
NOUT    endp

; Perform a delete.

DODEL   PROC    NEAR
        mov ah,prstr
        mov dx,offset delstr    ; Erase weird character.
        int dos                 
        ret
DODEL   ENDP

; Perform a Control-U.

CTLU    PROC    NEAR
        mov ah,prstr
        mov dx,offset clrlin
        int dos
        ret
CTLU    ENDP

COMS    PROC    NEAR
        mov dx,offset comptab
        mov bx,offset comphlp
        mov ah,cmkey
        call comnd
         jmp r
        push bx
        mov ah,cmcfm
        call comnd              ; Get a confirm.
         jmp comx               ;  Didn't get a confirm.
	 nop
	pop bx
        mov flags.comflg,bl     ; Set the comm port flag.
	cmp flags.comflg,1	; Using Com 1?
	jne coms0		; Nope.
	mov ax,offset port1
	mov portval,ax
	ret
coms0:	mov ax,offset port2
	mov portval,ax
        ret
comx:	pop bx
	ret
COMS    ENDP

VTS     PROC    NEAR
	jmp notimp
VTS     ENDP

notimp:	mov ah,prstr
	mov dx,offset noimp
	int dos
	jmp prserr

lclini: mov trans.escchr,ctrla	; Use Control-A as escape char.
	ret

showkey:
	mov ax,offset shkmsg
	mov cx,shklen
	ret


;     Common initialization for using serial port.

SERINI  PROC    NEAR
	cmp portin,0		; already inited?
	jne serin1		; yes, skip it
	mov portin,1		; remember inited
	mov dx,rcvcmd
	in al,dx		; read cmd register to reset mode ptr.
	mov dx,trmod
	mov al,mod1
	out dx,al
	push bx
	mov bx,portval
	mov si,[bx].baud
	pop bx
	mov al,baudtab[si]
	or al,mod2
	out dx,al
	mov dx,wrcmd
	mov al,txen+dtr+rxen+clrerr+rts
	out dx,al		; enable transmit and receive
	call clrbuf		; empty buffer
	mov al,settrp
	mov bx,chrrdy		; interrupt on character ready
	mov cx,0		; interrupt immediately
	mov dx,offset serint	; handler routine
	mov prtcnt,0		; no characters in yet
	push ds
	mov si,cs
	mov ds,si
	int wbios
	pop ds
	or al,al
	jne serin1
	mov qid,bx		; preserve trap identification
serin1: ret			; We're done. [21c]
SERINI  ENDP

SERRST  PROC    NEAR
	cmp portin,0		; already de-inited?
	je serrs1		; yes, skip this
	mov portin,0
	mov al,clrtrp
	mov bx,qid
	int wbios
serrs1:	ret
SERRST  ENDP

; serial interrupt handler
serint	proc	far
	push ds
	push ax
	push dx
	push di
	mov ax,seg datas
	mov ds,ax
	mov di,bufin
	mov dx,rcvdat
	in al,dx
	mov [di],al
	inc di
	cmp di,offset source + bufsiz
	jb sernt1
	mov di,offset source
sernt1: mov bufin,di
	inc count
	pop di
	pop dx
	pop ax
	pop ds
	ret
serint	endp


; Generate a short beep.

BEEP    PROC    NEAR
        mov dl,bell
        mov ah,conout
        int dos 
        ret
BEEP    ENDP 
 
; Jumping to this location is like retskp.  It assumes the instruction
;   after the call is a jmp addr.
 
RSKP    PROC    NEAR
        pop bp
        add bp,3
        push bp
        ret
RSKP    ENDP
 
; Jumping here is the same as a ret.
 
R       PROC    NEAR
        ret
R       ENDP

term    proc    near
        mov si,ax               ; this is source
        mov di,offset ourarg    ; place to store arguments
        mov ax,ds
        mov es,ax               ; address destination segment
        mov cx,size termarg
        rep movsb               ; copy into our arg blk
term1:  call prtchr
        jmp short term2         ; have a char...
        nop
        nop
        jmp short term3         ; no char, go on
term2:	and al,7fh
	push ax
        mov dl,al
	mov ah,dconio
        int dos                 ; write out the character
        pop ax
        test ourarg.flgs,capt   ; capturing output?
        jz term3                ; no, forget it
        call ourarg.captr       ; else call the routine
term3:  mov ah,dconio
        mov dl,0ffh
        int dos
	or al,al
        jz term1                ; no character, go on
        cmp al,ourarg.escc      ; escape char?
        je term4                ; yes, exit
        push ax                 ; save char
        mov ah,al
        call outchr             ; output the character
        nop
        nop
        nop
        pop ax
        test ourarg.flgs,lclecho ; echoing?
        jz term1                ; no, continue loop
        mov dl,al
        mov ah,dconio
        int dos
        jmp term1               ; else echo and keep going
term4:	ret
term    endp
code	ends
        end
