		page	80,132

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

false	equ	0
true	equ	1
instat	equ	6
rddev	equ	3fH
open	equ	3dH
close	equ	3eH

; external variables used:
; drives - # of disk drives on system
; flags - global flags as per flginfo structure defined in pcdefs
; trans - global transmission parameters, trinfo struct defined in pcdefs
; portval - pointer to current portinfo structure (currently either port1
;    or port2)
; port1, port2 - portinfo structures for the corresponding ports

; global variables defined in this module:
; xofsnt, xofrcv - tell whether we saw or sent an xoff.

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

machnam	db	'HP-110$'
erms20	db	cr,lf,'?Warning: System has no disk drives$' ; [21a]
erms40	db	cam	db	'HP-110$'
erms20	db	cr,lf,'?Warning: System has no disk drives$' ; [21a]
erms40	db	cr,lf,'?Warning: Unrecognized baud rate$'
erms41	db	cr,lf,'?Warning: Cannot open com port$'
erms50	db	cr,lf,'Error reading from device$'
badbd	db	cr,lf,'Unimplemented baud rate$'
badpar	db	cr,lf,'Unimplemented parity$'
noimp	db	cr,lf,'Command not implemented.$'
shkmsg	db	'Not implemented.'
shklen	equ	$-shkmsg
baudstr	db	'SB'			; string used in setting baud rate
baudx	db	0,';'
par_str	db	'P'			; string used to set parity
par_x	db	0,';'
brk_on	db	'B1;'			; start sending breaks
brk_off	db	'B0;'			; stop sending breaks
chk_msg	db	0BFH,';'		; check serial buffer
ini_msg	db	'M1;C2;LI1;'		; serial port, XON/XOFF, DTR on
setktab	db	0
setkhlp	db	0
crlf    db      cr,lf,'$'
delstr	db	BS,' ',BS,'$'
clrlin	db	cr,esc,'K$'
clreol	db	esc,'K$'
telflg	db	0		; non-zero if we're a terminal.
xofsnt	db	0		; Say if we sent an XOFF.
xofrcv	db	0		; Say if we received an XOFF.
invseq	db	esc,'&dB$'	; Reverse video
nrmseq	db	esc,'&d@$'	; Normal video
ivlseq	db	80 dup (' '),cr,'$'	; make line inverse video
prthnd	dw	0		; Port handle.
tempbuf	dw	10 dup(?)
prttab	dw	com2,com1
com1	db	'COM1',0
com2	db	'COM2',0
blank	db	esc,'H',esc,'J$'
movcur	db	esc,'&a'
colno	db	20 dup(?)
ten	db	10
tmp	db	?,'$'
temp	dw	0
temp1   dw      ?               ; Temporary storage.
temp2   dw      ?               ; Temporary storage.
rdbuf	db	20 dup(?)	; Buffer for input.

; 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 interupt handler

source	db	bufsiz	DUP(?)	; buffer for data from port
bufout	dw	0		; buffer removal pointer
count	dw	0		; number of chars in int buffer
bufin	dw	0		; buffer insertion pointer


ourarg	termarg	<>

datas	ends

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

; this is called by Kermit initialization.  It checks the
; number of disks on the system, sets the drives variable
; appropriately.  Returns normally.  

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. This throws away all the characters in the
; serial interrupt buffer.  This is particularly important when
; talking to servers, since NAKs can accumulate in the buffer.
; Returns normally.

CLRBUF	PROC	NEAR
	cli
	mov	ax,offset source
	mov	bufin,ax
	mov	bufout,ax
	mov	count,0
	sti
	ret
CLRBUF	ENDP

; Clear to the end of the current line.  Returns normally.

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

; Put the char in AH to the serial port.
; Skip returns on
; success, returns normally if the character cannot be written.

outchr:	mov	bp,portval
	cmp	ds:[bp].floflg,0	; Are we doing flow control.
	je	outch2		; No, just continue.
	xor	cx,cx		; clear counter
outch1:	cmp	xofrcv,true		; Are we being held?
	jne	outch2		; No - it's OK to go on.
	loop	outch1		; held, try for a while
	mov	xofrcv,false	; timed out, force it off and fall thru.
outch2:	push	dx			; Save register.
	push	cx
	push	bx
	cmp	prthnd,0	; do we have a port handle?
	jne	outch3		; yes, go on
	push	ax
	call	opnprt		; open the port
	pop	ax
outch3:	mov	dl,ah
	mov	ah,punout		; Output char in DL to comm port.
	int	dos
	pop	bx
	pop	cx
	pop	dx
	jmp	rskp

; This routine blanks the screen.  Returns normally.

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

; Homes the cursor.  Returns normally.

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

; Write a line 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,0F00h	; now address line 15
	call	poscur
	mov	dx,offset invseq	; put into inverse video
	mov	ah,prstr
	int	dos
	pop	dx		; get message back
	int	dos		; print it
	mov	dx,offset nrmseq	; normal video
	int	dos
	ret
putmod	endp

; clear the mode line written by putmod.  Returns normally.
clrmod	proc	near
	mov	dx,0F00h
	call	poscur		; Go to bottom row.
	call	clearl		; Clear to end of line.
	ret
clrmod	endp

; Put a help message on the screen.  
; Pass the message in ax, terminated by a null.  Returns normally.
puthlp	proc	near
	push	ax		; preserve this
	mov 	ah,prstr
	mov 	dx,offset crlf
	int 	dos
	pop	si		; point to string again
puth0:	mov	ah,prstr
	mov	dx,offset invseq	; put into reverse video
	int	dos
	mov	ah,prstr
	mov	dx,offset ivlseq	; make line inverse video
	int	dos
puth1:	lodsb			; get a byte
	cmp	al,0		; end of string?
	je	puth2
	mov 	dl,al
	mov	ah,conout
	int	dos		; else write to screen
	cmp	al,lf		; line feed?
	je	puth0		; yes, clear the next line
	jmp	puth1
puth2:	mov 	ah,prstr
	mov 	dx,offset crlf
	int 	dos
	mov	dx,offset nrmseq	; normal video
	int	dos
	ret
puthlp	endp

; Set the baud rate for the current port, based on the value
; in the portinfo structure.  Returns normally.

DOBAUD	PROC	NEAR
	mov	bx,portval
	mov	dx,[bx].baud		; get baud rate from table
	cmp	dx,0
	jb	bd_bd
	cmp	dx,10
	je	bd_bd
	cmp	dx,15
	ja	bd_bd
;
	cmp	dx,10
	jb	baud_4
	cmp	dx,11
	jne	baud_1
	mov	dl,'A'
	jmp	baud_5
baud_1:	cmp	dx,12
	jne	baud_2
	mov	dx,'C'
	jmp	baud_5
baud_2:	cmp	dx,13
	jne	baud_3
	mov	dx,'E'
	jmp	baud_5
baud_3:	cmp	dx,14
	jne	bd_bd
	mov	dx,'F'
	jmp	baud_5
baud_4:	add	dl,'0'			; make # printable
baud_5:	mov	baudx,dl		; put into baud rate message
	mov	cx,4
	mov	dx,offset baudstr	; point to message
	call	w_ioctl			; write to ioctl of serial port
	ret				; ...and return
;
bd_bd:	mov	ah,prstr
	mov	dx,offset badbd		; Say it's not implemented.
	int	dos
	mov	bx,portval
	mov	[bx].baud,0FFFFH	; So it's not a recognized value.
	ret				; Must be set before starting Kermit.
DOBAUD	ENDP

DOPARITY PROC	NEAR
	mov	bx,portval
	mov	dl,[bx].parflg		; get parity flag
	cmp	dl,0
	jne	par_1
	mov	dx,'0'		; even parity
	jmp	par_3
par_1:	cmp	dx,2
	jne	par_2
	mov	dx,'4'		; no parity
	jmp	par_3
par_2:	cmp	dx,3
	jne	bd_par
	mov	dx,'1'		; odd parity
par_3:	mov	par_x,dl	; set up string
	mov	dx,offset par_str	; point to string
	mov	cx,3		; 3 lettters in string
	call	w_ioctl		; ...to serial port ioctl
	ret
bd_par:	mov	bx,portval
	mov	[bx].parflg,0
	mov	ah,prstr
	mov	dx,offset badpar
	int	dos
	ret
DOPARITY ENDP

; Get the current baud rate from the serial card and set it
; in the portinfo structure for the current port.  Returns normally.
; This is used during initialization.

GETBAUD	PROC	NEAR
	ret			; Can't do this.
GETBAUD	ENDP
;
;	write cx bytes to ioctl of serial port
;
W_IOCTL PROC	NEAR
	mov	ah,ioctl
	mov	al,3
	mov	bx,prthnd
	int	dos
	ret
W_IOCTL ENDP
;
;	read cx bytes from ioctl of serial port to tempbuf
;
R_IOCTL PROC	NEAR
	mov	ah,ioctl
	mov	al,2
	mov	bx,prthnd
	mov	dx,offset tempbuf
	int	dos
	ret
R_IOCTL	ENDP
;
;	check serial port for characters and return number in al
;
CHK_BUFF PROC	NEAR
	mov	dx,offset chk_msg
	mov	cx,2
	call	w_ioctl
	mov	cx,1
	call	r_ioctl
	mov	ax,tempbuf
	ret
CHK_BUFF ENDP


; Use for DOS 2.0 and above.  Check the port status.  If no data, skip
; return.  Else, read in a char and return.
PRTCHR	PROC    NEAR
	push	bx
	push	cx
	push	si
	push	bp
	cmp	count,0			; any chars in buffer?
	jne	prtch2			; ...yes, get one
	cmp	prthnd,0		; got a handle
	jne	prtch1
	call	opnprt			; open port if not
prtch1:	call	chk_buff			; any chars at port?
	or	al,al
	jz	prtch4		; no, go to skip return
	mov	ah,0
	mov	cx,1
	mov	count,cx
	mov	bx,prthnd
	mov	ah,rddev
	mov	dx,offset source
	int	dos
	jc	prt3x
	mov	bufout,offset source
prtch2:	dec	count
	mov	si,bufout
	lodsb
	mov	bufout,si
	mov	bp,portval
	cmp	ds:[bp].parflg,PARNON	; no parity?
	je	prtch3		; then don't strip
	and	al,7fh		; else turn off parity
prtch3:	pop	bp
	pop	si
	pop	cx
	pop	bx
	ret
prt3x:	mov	ah,prstr
	mov	dx,offset erms50
	int	dos
prtch4:	pop	bp
	pop	si
	pop	cx
	pop	bx
	jmp	rskp		; no chars...
PRTCHR  ENDP

; Send a break out the current serial port.  Returns normally.
SENDBR	PROC	NEAR
	mov	dx,offset brk_on
	mov	cx,3
	call	w_ioctl
	mov	dx,offset brk_off
	mov	cx,3
	call	w_ioctl
	ret
SENDBR	ENDP

; Position the cursor according to contents of DX:
; DH contains row, DL contains column.  Returns normally.
POSCUR	PROC	NEAR
	mov	ax,ds
	mov	es,ax			; address data segment!!
	cld
	mov	di,offset colno
	mov	al,dl			; column
	call	nout
	mov	al,'x'
	stosb
	mov	al,dh			; row
	call	nout
	mov	al,'Y'
	stosb
	mov	al,'$'
	stosb
	mov	dx,offset movcur
	mov	ah,prstr
	int	dos			; print the sequence
	ret
POSCUR	ENDP

NOUT	PROC	NEAR
	cbw			; extend the word
	div	byte ptr ten	; divide by ten
	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			; put in buffer
	ret			; and return
NOUT	ENDP

; Delete a character from the terminal.  This works by printing
; backspaces and spaces.  Returns normally.

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

; Move the cursor to the left margin, then clear to end of line.
; Returns normally.

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

; Set the current port.  

COMS	PROC	NEAR
        mov	dx,offset comptab
        mov	bx,0
        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

; Set heath emulation on/off.

VTS	PROC	NEAR
	jmp	notimp
VTS	ENDP

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

; Initialize variables to values used by the generic MS DOS version.

lclini:	mov	flags.vtflg,0	; Don't do terminal emulation.
	call	opnprt		; Get file handle for comm port.
	mov	bx,offset port1
	mov	[bx].baud,13	; port1 -> 9600 baud
	mov	[bx].parflg,0	;	   even parity
	mov	bx,offset port2
	mov	[bx].baud,6	; port2 ->  300 baud
	mov	[bx].parflg,0	;	   even parity
	ret

; Get a file handle for the communications port.  Use DOS call to get the
; next available handle.  If it fails, ask user what value to use (there
; should be a predefined handle for the port, generally 3).  The open
; will fail if the system uses names other than "COM1" or "COM2".
opnprt:	mov	al,flags.comflg
	mov	ah,0
	mov	si,ax
	shl	si,1		; double index
	mov	dx,prttab[si]
	mov	ah,open
	mov	al,2
	int	dos
	jnc	opnpr1
	mov	ah,prstr		; It didn't like the string.
	mov	dx,offset erms41
	int	dos
	ret
opnpr1:	mov	prthnd,ax		; Call succeeded.
	ret

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

; Initialization for using serial port.  Returns normally.
SERINI	PROC	NEAR
	cld			; Do increments in string operations
	call	opnprt		; open handle
	call	clrbuf		; Clear input buffer. 
	mov	dx,offset ini_msg
	mov	cx,10
	call	w_ioctl
	call	dobaud		; set baud rate
	call	doparity	; set parity
	ret			; We're done.
SERINI	ENDP

; Reset the serial port.  This is the opposite of serini.  Calling
; this twice without intervening calls to serini should be harmless.
; Returns normally.

SERRST	PROC	NEAR
	mov	bx,prthnd
	cmp	bx,0		; none there?
	je	serr_1		; no, don't try to close
	mov	ah,close
	int	dos		; close handle
	mov	prthnd,0
serr_1:	ret			; All done.
SERRST	ENDP

; Produce a short beep.  The PC DOS bell is long enough to cause a loss
; of data at the port.  Returns normally.

BEEP	PROC	NEAR
	mov	dl,bell
	mov	ah,dconio
	int	dos
	ret
BEEP	ENDP 
 
; Dumb terminal emulator.  Doesn't work too well above 1200 baud (and
; even at 1200 baud you sometimes lose the first one or two characters
; on a line).  
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:	push	ax
	and	al,7fh		; mask off parity for terminal
	mov	dl,al
	mov	ah,conout
	int	dos			; go print it
	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
	jz	term1		; no character, go on
	cmp	al,ourarg.escc	; escape char?
	je	term4		; yes, exit
	push	ax			; save char
	mov	ah,al
	or	ah,80H		; turn on hi bit so DOS doesn't interfere
	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

; 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

code	ends 
	end
