	name msxhpx
; File MSXHPX.ASM
	include mssdef.h
;       Copyright (C) 1982,1991, Trustees of Columbia University in the
;       City of New York.  Permission is granted to any individual or
;       institution to use, copy, or redistribute this software as long as
;       it is not sold for profit and this copyright notice is retained.
; Edit history:
; 2 March 1991 version 3.10
; 2 Dec 2, 1990 Modify serhng so hangup works on serial port in connect mode.
; Nov. 24, 1990. Reemove reference to prserr to make link happy.
; Last edit Aug. 17, 1990
; August 9, 1990. Fix klogon and klogof.
; July 1990. Put in correct delay times for breaks. Thanks to Fred Lipschultz.
; June 1990. Install screen save for HP 110 and fixup dial command.[jan]
; February 1990. Major rewrite. Fix up for tektronix grapahics and 3.0.
; John Nyenhuis, Purdue EE 317-494-3524 nyenhuis@ecn.purdue.edu
; Binary works on both 110 and Plus.
; Change naming of ports to serial, modem, and 82164A
; Read keyboard less often and use BIOS screen write on plus for speed.
; 1 July 1988 Version 2.31
; 1 Jan 1988 version 2.30
; 25 May 1987 Add keyboard translator, input translation, cleanups. [jrd]
; 1 Oct 86 Version 2.29a
; 30 Sept 1986 Reject DEL char at serial port reception level to avoid
;  problems when DEL is used as a filler char (by Emacs). [jrd]
; 28 Sept 1986 Revise procedure Term to permit capturing, printer ready
;  testing, debug display. Revised other port procedures slightly too;
;  especially to set port into binary mode via ioctl. [jrd]
; 22 Sept 1986 Add modifications from Mike Mellinger: outchr, serhng.
;   Introduce COM3 as additional choice. Startup 8 bits, no parity. [jrd]
; 4 Sept 1986 Add Bob Goeke's change to move comms port table to a system
;   dependent module (typ msx---) to allow 3+ ports and localized idents. [jrd]

; Date: 15 Oct 85
; HP Portable Kermit
;	for HP110 and HP Portable Plus
;	Port 1: Serial, Port 2: internal modem
;	Defaults: even parity, 1200 baud: serial, 1200 internal modem
;	Internal modem code only works on HP Portable Plus
;	15 Nov 85:
;	   Added code to shut off serial port and modem when quitting Kermit
;	11 Jan 86;
;	   change msdefs.h to mssdef.h for kermit 2.28 jrd
;
; Add global entry point vtstat for use by Status in mssset.
; Also trimmed off trailing commas in publics. Joe R. Doupnik 12 March 1986
; Add global procedures ihosts and ihostr to handle host initialization
; when packets are to be sent or received by us,resp. 24 March 1986
; Add global procedure dtrlow (without worker serhng) to force DTR & RTS low
; in support of Kermit command Hangup. Says Not Yet Implemented. [jrd]
; Add global procedure Dumpscr, called by Ter in file msster, to dump screen
;   to a file. Just does a beep for now. 13 April 1986 [jrd]
; In proc Outchr add override of xon from chkxon sending routine.
;   This makes a hand typed Xoff supress the xon flow control character sent
;   automatically as the receiver buffer empties. 20 April 1986 [jrd]
; Fix port selector table, comptab, (from original version) to properly
;   hold port name AUX. 23 April 1986 [jrd]
;
;	Fixed error in resetting the serial port, 25 April 1986
;
		page	80,132


; mov a string	 all registers preserved
   movsmac macro xsource,  xdestination, xlength
    push cx
    push di
    push si
    mov	   si,offset xsource
    mov	   di, offset xdestination
    mov	   cx,xlength
    cld		      ; move forward
    rep movsb	      ; do the move
    pop	  si
    pop	  di
    pop	  cx
endm
writechar   macro saying
    push  dx
    push  ax
    mov	  ah,2
    mov	  dl,saying
    int	  dos
    pop	  ax
    pop	  dx
endm

writestring   macro saying
	push ax
	push dx
	mov  ah,prstr
	mov  dx,offset saying
	int  dos
	pop  dx
	pop  ax
 endm

saveregs macro
      pushf
      push  ax
      push  bx
      push  cx
      push  dx
      push  es
      push  di
      push  si
      push  ds
      push  bp
endm

restoreregs  macro
     pop   bp
     pop   ds
     pop   si
     pop   di
     pop   es
     pop   dx
     pop   cx
     pop   bx
     pop   ax
     popf
endm

mul10  macro register  ; multiply register other then ax by 10
    push ax
    mov ax,register
    mov temp1,ax
    shl ax,1
    shl ax,1
    shl ax,1
    add ax,temp1
    add ax,temp1
      mov temp1,ax
    pop ax
      mov register,temp1
endm
    
  delay macro number
   push ax
   push cx
   mov ax,number
   call pcwait
   pop cx
   pop ax
   endm


; structure for status information table sttab.
stent	struc
sttyp	dw  ?	   ; type (actually routine to call)
msg	dw  ?	   ; message to print
val2	dw  ?	   ; needed value: another message, or tbl addr
tstcel	dw  ?	   ; address of cell to test, in data segment
basval	dw  0	   ; base value, if non-zero
stent	ends



;; below 40 publics are the minimum necessary
       public  baudst,ihostr,bdtab,getbaud,chrout
       public  pcwait,putmod,serrst,trnprs,prtchr
       public  poscur,outchr,dtrlow,vts,puthlp
       public	vtstat,coms,cquery,ctlu,shomodem
       public  portval,getmodem,term,dumpscr,cmblnk
       public  cquit,locate,clearl,machnam,lclini
       public  sendbl,comptab,sendbr,clrmod,cstatus
       public  termtb,serhng,clrbuf,beep, serini
;;additional system dependent publics
	public	klogon,kdos,snull,klogof
	public bigscreen		; bigscreen=1 if it's big [jan]
	public	termtog			; toggle terminal types [jan]
	public	kclrscn, ourhelp, getflgs, dial_number, sethpkey, setaltkey
	public	setkeyboard, vtstbl, setchtab

false	equ	0
true	equ	1
instat	equ	6
print_out equ	05h			; dos function to print to printer
prtscr	equ	80h			; print screen pressed
hpkeynum	equ  11
altkeynum	equ  12
tekonnum	equ  13
tekoffnum	equ  14

data   segment public 'data'
	extrn	flags:byte, trans:byte
	extrn	dmpname:byte
	extrn	kbdflg:byte, rxtable:byte
	extrn	lclexit:word	   ; call when quitting kermit
	extrn	lclsusp:word	   ; call when pushing to dos
	extrn	lclrest:word	   ; call when exiting from dos
	extrn	tekflg:byte,denyflg:word
	extrn	dosnum:word
	extrn	repflg:byte, diskio:byte  ; for replay feature
	extrn	kbdflg:byte  ;	in telnet 

; hp110/ portable plus specific
machnam db	'Can Not Identify Terminal ','$'  ; should never see this
hp110_name db	   'HP_110$'
lenhp110_name equ   $-hp110_name
plus_name   db 'HP_Portable_Plus$'
lenplus_name equ $-plus_name

; num_rows and bigscreen must be set by lclini everything else is
; determined by the program
;; everybody defaults to 110
num_rows	dw	  16		; default
bigscreen	db	  1		; 1 for plus 0 for 110
graph_bytes	dw	  25*60*8	; size of graphics screen

erms20	db	cr,lf,'?Warning: System has no disk drives$'
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$'
serierr db	cr,lf,'Can not initialize port $'
write2err db	cr,lf,'Can not write to com port $'
badbd	db	cr,lf,'Unimplemented baud rate$'
badpar	db	cr,lf,'Unimplemented parity$'
noimp	db	cr,lf,'Command not implemented.$'
hngmsg	db	cr,lf,' The phone should have hungup.',cr,lf,'$'
hnghlp	db	cr,lf,' The modem control lines DTR and RTS for the current'
	db	' port are forced low (off)'
	db	cr,lf,' to hangup the phone. Normally, Kermit leaves them'
	db	' high (on) when it exits.'
	db	cr,lf,'$'
msmsg1	db	cr,lf,' Communications port is not ready.$'
msmsg2	db	cr,lf,' Communications port is ready.$'
rdbuf	db	80 dup (?)		; temp buf
shkmsg	db	'Not implemented.'
shklen	equ	$-shkmsg
baudstr db	'SB'			; string used in setting baud rate
baudx	db	0,';' ,'$'
flo_str db	'C'			; string used to set flow
flo_x	db	'0',';','$'		; 0=no flow 2=xon/xoff
brk_on	db	'B1;'			; start sending breaks
brk_off db	'B0;'			; stop sending breaks
chk_msg db	0BFH,';'		; check serial buffer
ask_cursor    db escape,'[6n','$'
badcursor     db 'Unable to get cursor position ',cr,lf,'$'
ask_modem_status db 'MS;'
transmiton    db 'Transmit On ',cr,lf,'$'
offhook	      db 'Modem is off hook ',cr,lf,'$'
modemenabled	   db 'Modem is Enabled  ',cr,lf,'$'
dial_msg db	'MR;'
$m0	db	'M0;SW0;P4;SS0;LI1;'
len_$m0	 equ $-$m0
$m1	db	'M1;SW0;P4;SS0;LI1;'
len_$m1	 equ $-$m1
$off_m	db	'C2;P0;SS0;SW1;M3;M5;'	; turn off portable plus
off_len equ	$-$off_m
$off_m110  db  'C2;P0;SS0;SW1;MH;'	; string to turn off 110 modem
len$off_m110  equ $-$off_m110
need_to_set_baud db  true	       ; only set baud when needed
;;need_to_set_flow db  true		 ; need to update flow control
;
setktab db	0
setkhlp db	0
crlf	db	cr,lf,'$'
delstr	db	BS,escape,'P','$'
clrlin	db	cr,ESCAPE,'K$'
clreol	db	ESCAPE,'K$'
hpkey	db	escape,'&k0\$'		; hp keyboard
altkey	db	escape,'&k1\$'		; alternate keyboard
tekstatustxt db 'Tek Auto Entry: $'
tekbyte db tekonnum
keystatustxt db 'Keyboard: $'
keyflg	db   altkeynum
; escape sequences for turning on the alpha display
; on the 110, we also need to load the character set
; id_terminal will decide which one to use

alpha_disp  db	 escape,'[=8h',escape,'[10m','$','xxxxxxxxxxx','$'  ; default
alpha_110  db	escape,'[=8h',escape,'[10m','$'	 ; for 110
lenalpha_110 equ $-alpha_110			   ; Its length
alpha_plus   db escape,'[=8h',escape,'*dK','$'		       ; for plus
lenalpha_plus	equ $-alpha_plus		  ; Its length
cursav	    db	escape,'[s','$'		; save the cursor
curres	    db	escape,'[u','$'		; restore cursor
curon	    db	escape,'*dQ','$'       ; turn on cursor
curoff	    db	escape,'*dR','$'       ; turn off the cursor
old_cursor  dw	?		 ; store alpha cursor position
transfcn    db	escape,'&s0A$'	 ; transmit functions,
dialcode    db	32  ;  16 for pulse 32 for tone
termidfail  db escape,'Kermit can not identify terminal type ',cr,lf,'$'
ask_id	    db	escape,'*s^','$'   ; is it 110 or plus
dial_saying db 'Enter Number to dial ,=delay ;=cancel P=pulse T=tone.',cr,lf,'$'

rdbuffstrt  dw	 ?   ; start of rdbuff for dial_number
canceldial  db	'Dial Cancelled ',cr,lf,'$'
modem_saying db	 'Set port to internal modem before dialing ',cr,lf,'$'
onhook_saying db 'Modem is already connected  ',cr,lf,'$'
w_ioctlerr   db cr,lf,'Error in writing to ioctl  ',7,'$'
r_ioctlerr   db cr,lf,'Error in reading ioctl ',7,'$'
io_notready  db cr,lf,'Not ready to write to ioctl ','$'
helpini	     db cr,lf,'Press Extended f1 for help in connect mode ',cr,lf,'$'
ourhelptxt   db cr,lf ,'Some Special Keys in Connect Mode: '
	     db cr,lf,'Menu clears screen'
   db cr,lf,'User System toggles between alpha and tektronix screens. '
   db cr,lf,'Extended B sends a break ','$'
helpplus  db cr,lf, 'Extended = also clears the screen '
  db cr,lf,'Extended - also toggles between alpha and tektronix screens','$'
help110	  db cr,lf, 'Press Extended D to dial a number ','$'
helpend	  db  cr,lf,cr,lf,'Press any key to return to connect mode','$'
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	ESCAPE,'&dB$'	; Reverse video
nrmseq	db	ESCAPE,'&d@$'	; Normal video
ivlseq	db	80 dup (' '),cr,'$'	; make line inverse video
prthnd	dw	0		; Port handle
argadr	dw	?		; address of arg blk from msster.asm
parmsk	db	?		; 8/7 bit parity mask, for reception
flowoff db	?		; flow-off char, Xoff or null (if no flow)
flowon	db	?		; flow-on char, Xon or null
captrtn dw	?		; routine to call for captured output
tempbuf dw	10 dup(?)
prttab	dw	com1,com2,com3
com1	db	'COM1',0
com2	db	'COM1',0    ; this gets changed on plus
com3	db	'COM2',0
blank	db	ESCAPE,'H',ESCAPE,'J$'
movcur	db	ESCAPE,'&a'
colno	db	20 dup(?)
ten	db	10
temp	dw	0
temp1	dw	0		; Temporary storage
temp2	dw	0		; Temporary storage
tempbyte db	0

;;new stuff to scan escape sequences from comm port  [jan]
stringtab	 dw    tekst1,tekst2	 ; strings for matching
		 dw    badst1,badst2
numstrings	equ   4			; number of strings to match
disptab		dw    toteknoplay,totekplay	  ; dispatch table
		dw    ignoreall, ignoreall
tekst1		db    escape,'[?38h',0	;1st string to get into tek mode [jan]
tekst2		db    escape,FF,0	;2nd string to get into tek mode [jan]

badst1 db   escape,'[=8h',0		; ignore alpha on sequence
badst2 db   escape,'[=10h',0		; ignore graph on sequence

stringchekbuff	   db	 16 dup (0)
stringchekcnt	   dw	 0		   ;characters already in buffer
matchsofar	dw    false		; no match yet
match		dw    0
playem		db    false		;don't play back switch characters
; end of data for string scannine
prtrdy	       db   true		 ; if false, we get out of connect mode

keydelay	dw    0

scrsavseg	dw  ?		     ; segment of screen memory
line_len	dw  ?		     ; words in a line
line_ofs	dw  ?		     ; ofset between adjacent lines
num_lines	dw  ?		     ; number of lines in screen memory

ints_set       db    false	     ; interrupts vectors set?
need_break     db    false
brk_int		equ  58h	     ; break key interrupt
savbrko		dw   ?		     ; save offset of break interrupt
savbrks		dw   ?		     ; save segment of break interrupt

vtstbl	stent <srchkw,keystatustxt,termtb,keyflg> ; tell keyboard for status
	stent <srchkw,tekstatustxt,termtb,tekbyte> ; tell keyboard for status
	dw	0				; end of table

; Entries for choosing communications port. [19b]
comptab db	3		; 7 entries. Rewritten by [jrd]
	mkeyw	'Serial',1
	mkeyw	'Modem',2
	mkeyw	'82164A',3	     ; 3 is hpil

setchtab  db 1	  ; set file character-set table
	mkeyw  'CP437',437

termtb	db	6
	mkeyw	'HP2621',ttgenrc
	mkeyw	'Tek4010',tttek
	mkeyw	'HpKeyBoard',hpkeynum
	mkeyw	'AltKeyBoard',altkeynum
	mkeyw	'EnableTek', tekonnum
	mkeyw	'DisableTek',tekoffnum

defbaud equ  7				; default baud rate
port1	prtinfo <defbaud,0,defpar,1,0,defhand,floxon,0>
port2	prtinfo <defbaud,0,defpar,1,0,defhand,floxon,0>
port3	prtinfo <defbaud,0,defpar,1,0,defhand,floxon,0>
portval dw	port2			; Default is to use port 1

bdtab	db	15			; Baud rate table

	mkeyw	'50',0
	mkeyw	'75',1
	mkeyw	'110',2
	mkeyw	'134',3
	mkeyw	'150',4
	mkeyw	'300',5
	mkeyw	'600',6
	mkeyw	'1200',7
	mkeyw	'1800',8
	mkeyw	'2400',9
	mkeyw	'3600',10
	mkeyw	'4800',11
	mkeyw	'7200',12
	mkeyw	'9600',13
	mkeyw	'19200',14
ourbdtab db '1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'

;	variables for serial interupt handler

source	db	260  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
; variable for fast write on plus
plus_char  db 'R',0

ourarg	termarg <>
asciitab  db '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'


data   ends

code	segment public 'code'
	extrn	comnd:near, dopar:near, atoi:near, prompt:near
	extrn	sleep:near
	extrn	tekcls:near
	extrn	msuinit:near, keybd:near	; in msuhpx
	extrn	tekemu:near,tekini:near
	extrn	sbrk:near			; memory allocator
	extrn	statc:near, srchkw:near

	assume	cs:code,ds:data,es:data

;check string to see if we need to do something special

stringchek  proc  near
       cmp   stringchekcnt,0	 ; nobody in yet?
       jne   stringchek1	 ; ne => already have characters
       cmp   al,escape		 ; is this escape?
       je    stringchek1	 ; it is escape, so go and process
       cmp   al,escape+80h	 ; in case parity is odd
       je    stringchek1	 ; process escape
       stc			 ; display the character
       ret			 ; return quickly if nothing to do
stringchek1:			 ; here is escape already in
       saveregs
       and     al,07fh		 ;strip high bit
       mov     bx,stringchekcnt
       mov     stringchekbuff[bx],al  ;put character in buffer
       inc     stringchekcnt	      ;one more character in buffer
       call    stringtest	 ; does the string in stringchekbuff match?
       cmp	match,0		 ; 0 means no match
       je      stringchek2
       mov     si,match		   ; here means we have a match
       shl     si,1		   ; multiply by 2
       dec     si
       dec     si		   ; 1=0, 2=1 etc
       call    disptab[si]	   ; call appropriate function
       call    stringbuffplay	      ; play back the buffer
       clc			   ; don't display
       jmp     stringchek3	   ; return and don't display character
stringchek2:
	 clc			  ; don not display
	 cmp   matchsofar,true	  ; do we have a match so far
	 je    stringchek3	     ; e=true , get out
	 mov   playem,true
	 call  stringbuffplay	       ; clean out the buffer
	 clc			   ; don't display character
stringchek3:
	 restoreregs
	 ret
stringchek   endp

;test to see if input string is a match to toggle terminal  [jan]


; stringtab gives addresses of 0 terminated strings
; teststring in stringchekbuff
;numstrings is the number to checked
; matchsofar will have be true if there is a possilbe match
; match will be non-zero 1, 2, 3 indicating number of match if a match
; if no match yet, match will be 0
; severaal registers get destroyed
stringtest proc near
	mov	matchsofar, false	  ; assume no match
	mov	match,0			; no match
	xor	si,si			; pointer to string tab
	dec	si
	dec	si			; step back 1 item
	mov	cx,0			; cx points to number of string
strtst1:
	inc	cx			; strings number
	cmp	cx,numstrings		; done parsing table?
	ja	strtst5			; we're done, get out of here
	mov	di, offset stringchekbuff
	inc	si
	inc	si			; point to next item
	mov	bx,stringtab[si]	; offset of string
strtst2:
	mov	al,[di]			; stringchekbuff in al
	mov	ah,[bx]			; string element to test in ah
	cmp	al,0			; end of stringchekbuff
	jne	strtst2a		; ne=> not at end of buffer
	mov	matchsofar,true		; we have a match so far
	jmp	strtst5			; return to caller
strtst2a:
	cmp	ah,0			; at end of string?
	je	strtst1			; failure, go to next string
	cmp	ah,al			; match?
	jne	strtst1			; no match, on to next string
					; here if match
	mov	ah,[bx+1]		; next byte from string
	cmp	ah,0			; are we done with string?
	je	strtst3			; e => yes, a match
	inc	bx			; next element in string
	inc	di			; next character in stringchekbuff
	jmp	strtst2			; check next item in string
strtst3:				; here if we have a match
	 mov	match,cx		;
	 mov	matchsofar,true		;
strtst5:
	ret
stringtest endp



;play back characters in string buffer ..called by stringchek
stringbuffplay proc near
      xor      bx,bx	      ;bx=0
      mov      cx,stringchekcnt
stringbuffplay1:
      mov      al,stringchekbuff[bx]
      cmp      playem,true    ;playback characters?
      jne      stringbuffplay2	 ;ne = no don't play back
      push     bx	      ; save index
      push     cx	      ; save count
      call     outtty	      ; print the character
      pop      cx	      ; restore count
      pop      bx	      ; restore index
stringbuffplay2:
     mov      stringchekbuff[bx],0  ;set to 0
     inc      bx	      ;point to next character
     loop     stringbuffplay1	 ;repeat until buffer is empty
     mov      stringchekcnt,0	 ;now no characters in buffer
     ret
stringbuffplay endp

ignoretek proc near	       ; ignore this escape sequence in tek mode
    mov playem,false
    cmp flags.vtflg,tttek      ; are in in tek emulation
    je	ignoretek1	       ; e=yes do not play back
    mov playem,true
ignoretek1:
     ret
ignoretek endp

ignoreall proc near   ; always ignore this escape sequence
     mov playem,false
     writechar bell
     ret
ignoreall endp

totekplay proc near	       ; turn on tektronix
      mov playem,true	       ; play back characters
      jmp totek
totekplay endp

toteknoplay proc near
     mov playem,false
     jmp  totek
toteknoplay endp


totek proc near		   ; turn on tektronix
       test    denyflg,tekxflg	 ;tek auto entry enabled?
       jz     totek1
       mov playem,true		; play back characters
       ret
totek1:

   cmp	flags.vtflg,tttek	; already doing tek
   je	totek2
   call termtog			; toggle to tektronix
totek2:
    ret
totek endp


setkeyboard proc   near	     ; set appropriate keyboard
     cmp   keyflg,altkeynum	; want alternate keyboard
     je	  setkbd1	    ; e=> set altkeyboard
     call  sethpkey
     ret
setkbd1:call setaltkey
     ret
setkeyboard endp

sethpkey  proc	near
    writestring hpkey
    ret
sethpkey  endp

setaltkey proc near
     writestring altkey
     ret
setaltkey endp

scrsavinit   proc  near	     ; set up memory block to save screen memory [jan]
    saveregs
    mov	     ax,num_rows

    mov	     cl,9
    shl	     ax,cl
    mov	     bx,ax	     ; bx=512*num_rows
    mov	     ax,num_rows
    mov	     cl,7
    shl	     ax,cl	     ; ax=128*num_rows
    add	     ax, bx	     ; ax=640*numrows
    mov	     cx,ax	     ; save num bytes in cx
    push     cx
    call     sbrk	     ; memory manager
    pop	     cx		     ; recover number of bytes
    shr	     cx,1	     ; cx has number of words
    mov	     scrsavseg,ax    ; save it
    xor	     ax,ax
    mov	     di,ax
    mov	     es,scrsavseg
    rep	     stosw
    restoreregs
    clc
    ret
scrsavinit endp

savescr	     proc     near	; save dislply memory
     saveregs			; save the registers
     mov    di,0		; tek page by default
     mov    line_len,60		; bytes in tek line
     mov    line_ofs,64		; bytes between adjacent tek lines
     mov    ax, num_rows	; number of rows
     shl    ax,1		  ; each row has 8 lines
     shl    ax,1		  ; so multipy by 8
     shl    ax,1
     mov    num_lines,ax
     xor    si,si		; tek display starts at 8000:0000
     xor    dx,dx		; dx points to offset of current line
     cmp    flags.vtflg,tttek	; doing tek emulation?

     je	    savesc1		; je means yes we are doing tek
     cmp    bigscreen,0		; don't save for 110
     jne     savesca		; ne=> we have a plus
;;    here if saving for hp110
      mov di,graph_bytes   ; here if saving 110 screen
      mov    line_len,128     ; each line is 128 bytes
      mov    line_ofs, 128    ; lines offset by 128 bytes
     call    askcursor		; cursor location in dx
     mov    old_cursor,dx	 ; save old cursora
     writestring  curoff	; turn off the cursor
     in	    al,0e6h		 ; get row number at display top
      and     al,63		; insurance
     xor     ah,ah
     mov     cl,7
     shl     ax,cl
     mov     dx,ax
     mov     si,dx
     mov     ax,num_rows
     mov     num_lines,ax
     jmp     savesc1		; do the save
savesca:
     mov    di,graph_bytes	  ; here if saving alpha screen
     mov    line_len,160	; bytes in alpha line
     mov    line_ofs,256	; bytes between adjacent alpha lines
     call    askcursor		; cursor location in dx
     mov    old_cursor,dx	 ; save old cursora
     writestring  curoff	; turn off the cursor
     in	    al,83h		; get row number of display top
     mov    ah,al		; multiply by 256 to get byte number
     xor    al,al
     mov    dx,ax		 ; offset of alpha display start in dx
     mov    si,dx
     mov    ax,num_rows
     mov    num_lines,ax	 ; each row is one line in alpha
savesc1:
     mov     ax,scrsavseg      ; screen save segment
     mov     es,ax
     mov     cx,num_lines
savesc2:
     push    cx			 ; save number of lines
     mov     cx,line_len
     shr     cx,1		 ; words = bytes/2
     mov     ax,8000h		 ; screen memory segment
     push    ds
     mov     ds,ax
     cld
     rep     movsw		 ; move line
     pop     ds			 ; get back kermit's ds
     pop     cx			 ; get back line number
     add     dx,line_ofs	 ; point to beginning of next line
;  check for wrap on hp110
     cmp     bigscreen,1	 ; is it a plus?
     je	     savesc2a		 ; = means yes, it is a plus
     cmp     flags.vtflg,tttek	 ; tek emulation?
     je	     savesc2a		 ; e=> yes, don't worry about wrap
     cmp     dx,128*48		 ; ready to wrap around on hp110?
     jb	    savesc2a		; ne=> not there yet
     mov     dx,0		 ; point to first line on hp110 display
;  end of wrap check on hp110
savesc2a:
     mov     si,dx
     loop savesc2		 ; do the next line
     cmp    flags.vtflg,tttek	 ; doing tek emulation
     je	    savesc3		 ; yes, don't turn on cursor

     writestring  curon		 ; turn on the cursor
savesc3:
savescrex:
     restoreregs		 ; restore the registers
     clc			 ; all ok
     ret
savescr	 endp


restscr	     proc     near	; move ds:si(memory)  to es:di (screen)
     saveregs			; save the registers
     mov    si,0		; tek page by default
     mov    line_len,60		; bytes in tek line
     mov    line_ofs,64		; bytes between adjacent tek lines
     mov    ax, num_rows	; number of rows
     shl    ax,1		  ; each row has 8 lines
     shl    ax,1		  ; so multipy by 8
     shl    ax,1
     mov    num_lines,ax
     xor    di,di		; tek starts at 8000:0000
     xor    dx,dx		; dx points to offset of current line
     cmp    flags.vtflg,tttek	; doing tek emulation?
     je	    restsc1		; je means yes we are doing tek
     writestring alpha_disp	  ; reload the hp character set
     cmp     bigscreen,0	 ; using the 110  ?
     jne     restsca		 ; ne=> we have the plus
     call    cmblnk		; blank display	 on 110
     writestring  curoff	; turn off the cursor

     mov    si,graph_bytes	  ; here if restoring alpha screen
     mov    line_len,128	; bytes in alpha line
     mov    line_ofs,128	; bytes between adjacent alpha lines
     in	    al,0e6h		 ; get row number of display top
	and  al,63		; insurance
     mov    cl,7	       ; multiply by 128 to get byte number
     xor    ah,ah
     shl    ax,cl
     mov    dx,ax		 ; dx points to start of line
     mov    di,dx		 ; offset of alpha display start
     mov    ax,num_rows
     mov    num_lines,ax
     jmp    restsc1

restsca:
     call    cmblnk		; blank display
     writestring  curoff	; turn off the cursor

     mov    si,graph_bytes	  ; here if restoring alpha screen
     mov    line_len,160	; bytes in alpha line
     mov    line_ofs,256	; bytes between adjacent alpha lines
     in	    al,83h		; get row number of display top
     mov    ah,al		; multiply by 256 to get byte number
     xor    al,al
     mov    di,ax		  ; offset of alpha display start
     mov    dx,di		 ; dx points to start of line
     mov    ax,num_rows
     mov    num_lines,ax
restsc1:
     mov     cx,num_lines
restsc2:
     push    cx			 ; save number of lines
     mov     cx,line_len
     shr     cx,1		 ; words = bytes/2
     mov     ax,8000h		 ; screen memory segment
     mov     es,ax		 ; es:di points to display memory
     cld
     mov     ax,scrsavseg	 ;
     push    ds			 ; save kermit's ds
     mov     ds,ax		 ; ds points to screen save memory
     rep     movsw		 ; move line
     pop     ds			 ; get back kermit's ds
     pop     cx			 ; get back line number
     add     dx,line_ofs	 ; dx points to begin of next lien
     mov     di,dx		 ; point to next line in desplay
;  check for wrap around on hp110
     cmp     bigscreen,1	 ; using a plus
     je	     restsc2a		 ;  e=> yes its a plus
     cmp     flags.vtflg,tttek	 ; doing tek
     je	     restsc2a		 ; e=> yes, dont worry about 110 wrap
     cmp     dx,48*128		 ; need to wrap
     jb	    restsc2a		; ne=> no
     mov     dx,0
     mov     di,dx
; end of wrap around check on hp110
restsc2a:
     loop restsc2		 ; do the next line
     cmp   flags.vtflg,tttek	 ; doing tek emulation
     je	   restsc3		 ; yes, skip the cursor stuff

      mov  dx,old_cursor
      call  poscur
     writestring  curon		 ; turn on the cursor
restsc3:
restscrex:
     restoreregs		 ; restore the registers
     clc			 ; all ok
     ret
restscr	 endp

;  identify wether we have hp110 or portable plus
;  if plus then bigscreen = 1 else bigscreen =0
id_terminal proc near
      saveregs
      call clear_key_buffer	    ; clear the keyboard buffer if needed
      writestring ask_id	    ; ansi termial ask string
      push     ds
      pop      es		    ; es=ds for string moves
      call     getkey		    ; first key in string is 1 or 4
      cmp  al,'1'		    ; 1 for hp110
      jne  id_ter2		    ; ne means its a plus
      mov  bigscreen,0
      mov  num_rows,16		    ; it's a 110
      mov  graph_bytes,16*60*8	      ; bytes in graphics screen
      movsmac hp110_name, machnam, lenhp110_name  ; move name
      movsmac alpha_110, alpha_disp, lenalpha_110  ; mov alpha message
      jmp id_ter4		    ; normal exit
id_ter2: mov bigscreen,1	     ; its a plus
	mov num_rows,25
	mov graph_bytes,25*60*8		; bytes in graphics screen
	movsmac plus_name machnam lenplus_name ; move machine name
	movsmac alpha_plus alpha_disp lenalpha_plus ; alpha message
	mov   bx,offset com2
	mov   al,'3'
	mov   [bx+3],al		 ; com2 is always modem
      jmp id_ter4		     ; normal exit
id_tererr: writestring termidfail
id_ter4: call clear_key_buffer
	restoreregs
	clc
	ret
id_terminal  endp

modem_status_byte proc	 near  ; get status byte on 110
	cmp    bigscreen,0	     ; is this a 110
	je     modembyte1	     ; => yes it is
	mov    al,0		     ; no status on plus
	ret
modembyte1:
	saveregs
	mov    dx, offset ask_modem_status
	mov    cx,3			    ; 3 bytes
	call   w_ioctl			    ; ask the status
	mov    cx,1			    ; 1 byte to read
	call   r_ioctl
	restoreregs
	mov    ax, tempbuf		   ; retrive the status byte
	clc
	ret
modem_status_byte  endp

modem_status proc near	; get modem status
       saveregs
       call    modem_status_byte	   ; al will contain status
       test   al,2			   ; transmit enabled
       jz     modem_stat1
       writestring transmiton
modem_stat1:
       test   al,8		      ; is modem off hook?
       jz  modem_stat2
      writestring offhook
modem_stat2:
       test   al,128			; is the modem enabled?
       jz  modem_stat3
       writestring  modemenabled
modem_stat3:
       restoreregs
       clc
       ret
modem_status endp

dial_number proc near	    ; dial a number
    cmp	 bigscreen,0	      ; is this a 110?
    je	 dial_numa	      ; e=> yes, do the dial
 ;;   ret			; don't do anything if its a plus
dial_numa:		      ; start code which runs only on 110
    saveregs
    call savescr
    writestring alpha_disp
 ;;   call cmblnk		   ; give a nice screen to work with

    cmp	 flags.comflg,2	       ; using port 2?
    je dial_num0	      ; e => yes, we are

    writestring modem_saying   ;
    mov	  ax,500	       ; wait a second
    call  pcwait
    jmp dial_ex		      ; can't dial until port set right
dial_num0:
       call modem_status_byte
       test    al,128	       ; is the modem on?
       jz      dial_num1       ; it's not on so ok to dial
       writestring onhook_saying ; tell user he can't dial with modem on
       mov    ax,500
       call   pcwait
       jmp    dial_ex
dial_num1:
      call modem_status
      mov ax,offset rdbuf   ; rdbuf is work buffer
      push ds
      pop es		     ; es points to data segment
      mov di,ax		       ; let rdbuf be our buffer
      call clear_key_buffer
      writestring dial_saying
      mov    al,'M'
      mov    [di],al
      inc    di
       mov    al,'D'
       mov    [di],al
       inc    di
	mov   rdbuffstrt,di	    ; the start location of new characters
      mov    dl,16		    ; tone dial is default
dial_num2:
      call getkey		    ; get key from user
      cmp   al,8		    ; backspace?
      je   dial_num2b		    ;  backspace, so erase previous char.
      cmp   al,127		    ; delete is also legal backspace
      jne   dial_num2c		    ; ne => no backspace
;  here to handle backspace
dial_num2b:
      cmp   di,rdbuffstrt	   ; any characters in the command buffer?
      je    dial_num2		   ; nobody in yet, so do nothing
      call  dodel		   ; write a backspace
      dec   di			   ; remove last character from buffer
      jmp   dial_num2		   ; get the next character
; end of backspace handler
dial_num2c:
  ;;	writechar al			   ; display for user
      cmp  al,cr		    ; are we done
      je dial_num8
      cmp  al,';'		    ; ':' cancels dial command
      je   dial_num2c1
       cmp al,3			    ; control c cancels
      je   dial_num2c1
       cmp  al,escape		    ; escape also cancels
       je  dial_num2c1
       jmp  dial_num2d		    ; continue
dial_num2c1:	   jmp	dial_ex	    ; cancel dial command
dial_num2d:
      cmp  al,','		    ; pause command
      jne  dial_num2e
      writechar	  al		    ; write comma to screen
      mov  al,2			    ; 2 second delay
      mov  [di],al
      inc  di			   ; point to next byte in rdbuf
      jmp  dial_num2
dial_num2e:
      cmp  al,'p'		    ; pulse?
      jne  dial_num3
      mov  dl,32
dial_num3: cmp al,'P'		   ; pulse ?
     jne dial_num4
      mov  dl,32
dial_num4: cmp al,'t'		    ; tone?
       jne dial_num5
	 mov dl,16
dial_num5: cmp al,'T'		    ; again tone
	jne dial_num6
	mov dl,16
dial_num6: cmp al,'0'
	jb dial_num2		  ; ignore this one
	 cmp al,'9'		  ; is it too big
	 ja dial_num2		  ; yes, too big, so ignore
	 writechar al		  ; write it on screen
	 sub  al,'0'		  ; convert ascii to binary
	 add   al,dl		  ; add dial code
	 mov [di],al		  ; put in the read buffer
	 inc di			  ; next byte in readbuffer
       jmp dial_num2		  ; get next key from user
dial_num8:
	  mov al,2		  ; 2 second delay
	  mov  [di],al
	   inc	di
	   mov al,80		  ; enable transmit tone
	   mov	[di],al
	   inc	di
	   mov al,64		   ; enable originate mode
	   mov	[di],al
	    inc di
	   mov	al,255		   ; terminate dial sequence
	    mov [di],al
	   inc di
	    mov al,';'		  ; add semicolon
	   mov [di],al
	   inc di
	   mov al,' '		   ; finish with a blank
	   mov	[di],al
	     inc di
	     mov al,'$'
	     mov [di],al
	  ;;  writestring rdbuf

;; now dial string is safely in rdbuf and size in dh
	  mov cx,di
	  mov  ax,offset rdbuf	     ; start of string
	  sub  cx,ax	     ; cx has bytes in buffer
	 push  cx		; save the number to write
	 mov   dx, offset dial_msg
	 mov   cx,3
	 call  w_ioctl	 ; tell pc we want to dial a number
	 mov ax,50	 ; wait to let things settle
	 call pcwait		 ; wait 50 ms
	 mov  dx,offset	 rdbuf
	 pop  cx	     ; number of byres
	 call  w_ioctl
	  call modem_status    ; tell user the status

	  jmp dial_ok		; all ok
dial_ex: writestring canceldial
dial_ok:

	 mov ax,1000		; give user time to read message
	 call pcwait		; wait a short while
	 cmp  flags.vtflg,tttek ; doing tek
	 jne  dial_tog
	 call tekini		; need to reinitialize emulator
dial_tog:
	 call restscr
	 restoreregs
	 clc			  ; stay in connect
	 ret
dial_number  endp



     askcursor proc near       ; return curor row in dh, column in dl
       mov dx,257	       ; default
       saveregs
      call clear_key_buffer    ;
      writestring ask_cursor	    ; ansi ask cursor message
       mov ax,50
       call pcwait		    ; wait a whill
       xor cx,cx
askcur1:
       call getkey
       inc cx
       cmp cx,20
       ja askcurex
       cmp al,'['
       jne askcur1
      xor bx,bx			 ; keep row number in bx

askcur2:
      call getkey
      cmp al,';'		   ; this signifies start of column report
      je askcur3
      sub al,'0'		   ; make binary
      mul10 bx			   ; multiply by 10
      add bl,al
       inc cx
       cmp cx,20
       ja askcurex
      jmp askcur2		   ; repeat until done

askcur3: mov dh,bl		   ; row in dh
       xor bx,bx		   ; now get column
askcur4:  call getkey
      cmp al,'R'		   ; this signifies start of column report
      je askcur5
      sub al,'0'		   ; make binary
      mul10 bx			   ; multiply by 10
      add bl,al
	inc cx
	cmp cx,20
	ja askcurex
      jmp askcur4		   ; repeat until done
askcur5: mov dl,bl		    ; column in dl
	  jmp askcur7
askcurex: writestring badcursor
askcur7: clc
	 mov temp1,dx
	 restoreregs
	  mov dx,temp1
	  dec  dh   ; map (1,1) to (0,0)
	  dec  dl
	 ret
askcursor endp


 getkey proc near    ; wait for a key to be typed
  mov ah,7
  int dos
  ret
getkey endp

clear_key_buffer  proc	near
       saveregs
clear_key1:
       mov ax,0600h
       mov dx,0ffffh
       int dos
       jnz clear_key1
       restoreregs
       clc
       ret
clear_key_buffer  endp

ourhelp proc near   ; give user some help
     saveregs
     call savescr	 ; save current screen
     writestring alpha_disp; be sure alpha is on
     call cmblnk    ; blank the screen
     writestring  ourhelptxt
     cmp  bigscreen,1	   ; do we have a plus ?
     je	  ourhelp1
     writestring   help110
     jmp  ourhelp2
ourhelp1: writestring helpplus
ourhelp2: writestring  helpend
      call getkey	 ; user types a key when done reading
      cmp   flags.vtflg,tttek  ; doing tek emulation
      jne   ourhelp3	       ; ne => we're doing alpha screen
      call  tekini	       ; need to reinitialize the emulator
ourhelp3:
      call restscr	 ; give him back his previous screen
      restoreregs
      clc		 ; stat in connect mode
      ret
ourhelp endp

getrepchr proc	near	      ; get replay character for file
      mov    ah,readf2	      ; read from replay file
      mov    bx,diskio.handle
      mov    cx,1	      ; read 1 character
      mov    dx,offset rdbuf  ; to this buffer
      int    dos
      jc     getrepchr1	      ; c => failure
      cmp    ax,cx	      ; read the byte?
      jne    getrepchr1
      mov    al,rdbuf	      ; al has character
      clc		      ; character available in al
      ret
      

getrepchr1:
      call   beep	     ; announce file is done
      call   beep
      call   getkey	     ; wait for a key to be pressed
      mov    prtrdy,false    ; so we exit connect mode
      stc
      ret		     ; no character available
getrepchr    endp

repchrout  proc	 near		; process key in al  while replaying
	and   al,7fh		; strip parity
repchrout1:
	cmp   al,'C'-40h	; Control C?(to exit playback mode)
	je    repchrout3	; e=> yes, return failure
	cmp   al,XOFF		; user wants to stop?
	jne   repchrout2	; ne => ok to continue
	call  getkey		; wait and get a key
	jmp   repchrout1	; now process this key
repchrout2:
	clc			; return success
	ret
repchrout3:
	mov   prtrdy,false	; exit terminal
	stc			; exit connect mode
	ret
repchrout  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
	cmp	repflg,0  ; don't clear if replaying
	je	clrbuf0
	ret
clrbuf0:
	push	ax	  ; necessary for msghpx
	mov	bufin,offset source
	mov	bufout,offset source
	mov	count,0
clrbuf1: call prtchr	; empty out firmware buffer
	 jnc clrbuf1
	 pop  ax
	 ret
CLRBUF	ENDP

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

CLEARL	PROC	NEAR
	push	ax			; save regs
	push	dx
	mov	ah,prstr
	mov	dx,offset clreol
	int	dos
	pop	dx
	pop	ax
	ret
CLEARL	ENDP
; Put the char in AH to the serial port.  This assumes the
; port has been initialized.  Should honor xon/xoff.
; clc upon success (for 3.00)
OUTCHR	 PROC  NEAR
	 push cx		 ; save regs
	or ah,ah		; sending a null?
	jz outch2		; z = yes
	xor cx,cx		; clear counter
	cmp ah,flowoff		; sending xoff?
	jne outch1		; ne = no
	mov xofsnt,false	; supress xon from chkxon buffer routine
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
	mov al,ah		; Parity routine works on AL
	call dopar		; Set parity appropriately
				; Begin revised output routine
      ;;  and al,07fh
	mov byte ptr temp,al	; put data there
	cmp prthnd,0		; Got a handle yet?
	jne outch3		; Yup just go on
	call opnprt		; Else 'open' the port
outch3: push	bx
	mov	bx,prthnd	; port handle
	mov	cx,1		; one byte to write
	mov	dx,offset temp	; place where data will be found
	mov	ah,write2	; dos 2 write to file/device
	int	dos
	pop	bx		; end of revised routine
	pop dx
	pop cx
	jc   outch4		; stc => failure
	clc			; clc for success
	ret
outch4: writestring write2err
	stc
	ret
OUTCHR	ENDP
; This routine blanks the screen.   Returns normally.

CMBLNK	PROC	NEAR
	push	ax		; save regs
	push	dx
	mov	ah,prstr
	mov	dx,offset blank
	int	dos
	pop	dx
	pop	ax
	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,1800H	; assume plus
	 cmp	bigscreen,0	; is it a 110?
	 jne	putmod1		; ne => its a plus
	mov	dx,0F00H	; now address line 15
putmod1:
	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,1800H       ; plus by default
	cmp	bigscreen,0    ; is it a 110?
	jne	clrmod1	       ; ne => it is a plus
	mov	dx,0F00H
clrmod1:
	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	dx		; save regs
	push	si
	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
	cld
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
	pop	si
	pop	dx
	ret
puthlp	endp


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

BAUDST	PROC	NEAR
      saveregs
	mov	dx,offset bdtab		; baud rate table, ascii
	xor	bx,bx			; help is the table itself
	mov	ah,cmkey		; get keyword
	call	comnd
	jc	baudst3			; c = failure
	push	bx			; save result
	mov	ah,cmeol		; get confirmation
	call	comnd
	pop	bx
	jc	baudst3			; c = failure
	mov	si,portval
	mov	ax, offset port2
	cmp	ax,si			; using the modem?
	jne	 baudst2		 ; ne => no
	cmp	bigscreen,1		; using plus?
	je	baudst1			; e => yes
	mov	bx,5		      ; only 300 baud legal on 110 modem
	jmp	baudst2
baudst1:cmp	bx,5		      ; 300 baud
	je	baudst2			; 300 baud is ok
	mov	bx,7		      ; if not 300, then it's 1200
baudst2:
	mov	ax,[si].baud		; remember original value
	mov	[si].baud,bx		; set the baud rate
      ;;  call	  dobaud		  ; use common code
      ; we set baud rate in SERINI
	mov need_to_set_baud, true	; we need to update the baud rate

	clc
baudst3: restoreregs
	 ret
BAUDST	ENDP

; Set the baud rate for the current port, based on the value
; in the portinfo structure.	  Returns normally.
; it is assumed the port is open else w_ioctl returns error

DOBAUD	PROC	NEAR
	cmp  need_to_set_baud, true    ; do we need to update the baud ?
	je  dobaud1		       ; e=> yes, update baud rate
	clc			       ; success
	ret			       ; return if not needed
dobaud1:saveregs
	mov	bx,portval
	mov	dx,[bx].baud
	mov	bx,offset ourbdtab
	add	bx,dx			 ; point to character in baud tabble
	mov	dx,[bx]
	mov	baudx,dl		; put into baud rate messge
	mov	cx,4
	mov	dx,offset baudstr	; point to message
	call w_ioctl
	mov need_to_set_baud, false	; don't need to reset baud rate
	restoreregs
	ret				; Must be set before starting Kermit
DOBAUD	ENDP

; USe hardware flow control [jan]... it is assumed the port is open
DOFLOW PROC   NEAR
	saveregs
	mov	bx,portval
	mov  dl,'0'		       ; default is no flow control
	cmp  [bx].floflg,0	       ; doing flow control ?
	je   doflow1		       ; e => no flow control
	mov	dl,'2'
doflow1:mov   flo_x,dl
	mov    dx, offset flo_str	; C is first character
	mov	cx,3			; 3 lettters in string
       ;;  writestring flo_str
	call w_ioctl
	restoreregs
	clc				 ; success
	ret
doflow	 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

; SHOW MODEM - displays status of modem lines DSR, CD, CTS, in this case
; it just says whether or not the port is ready for i/o.
shomodem proc	near
	mov	ah,CMEOL	; get a confirm
	call	comnd
	jnc	shmod00		; nc=> success
	ret			; get out if failure
shmod00:
	cmp	prthnd,0	; Got a handle yet?
	jne	shmod0		; Yup just go on
	call	opnprt		; Else 'open' the port
shmod0: mov	dx,offset msmsg1 ; say port is not ready
	mov	bx,prthnd
	mov	al,7		; output status command
	mov	ah,ioctl	; ask DOS to look for us
	int	dos
	jc	shmod1		; c = call failed, device not ready
	or	al,al
	jz	shmod1		; not ready
	mov	dx,offset msmsg2 ; say port is ready
shmod1: mov	ah,prstr
	int	dos
	 stc
	 ret			  ; carry set upon failure
shomodem endp

getmodem proc	near
	mov	al,0		; no modem status
	ret
getmodem endp


; this is not used, but is left in to aid future debugging
printal proc near   ; print the value in al
push di
push ax
push bx
push dx
push ax
push ax
; print a leading space
mov ah,2
mov dl,' '
int dos
;
pop  ax
and  al, 0f0h	; high nibble
shr al,1
shr al,1
shr al,1
shr al,1  ; high nibble to low nibble
mov di, offset asciitab
xor bx, bx   ; bx=0
mov bl, al
mov dl, [di+bx]
mov ah,2   ; print char
int dos		       ; print high nibble
; now the low nibble
pop ax	 ; get back original char
and al, 0fh
mov bl,al
mov dl, [di+bx]
mov ah, 2
int dos		   ; print low nibble
pop dx
pop bx
pop ax
pop di
ret
printal endp

;;end of msxhpx.h include file
;
;	write cx bytes to ioctl of serial port
;
W_IOCTL PROC	NEAR
	cmp	prthnd,0	; port opened?
	jne	w_ioctl1b	; ne => yes it is open
	writechar 'I'
	ret
w_ioctl1b:
	push	ax		; save regs
	push	bx
	push	cx
	mov	cx,1000		; knock at port until ready
w_ioctla:

       mov     ah,ioctl	       ; first check
	mov	bx, prthnd
	mov	al,7		; check status
	int	dos
	cmp	al,0ffh		; ok?
	loopne	 w_ioctla	; try again
	cmp	 al,0ffh
	jne	w_ioctl3	;ne =>	 error
	pop	cx		; retrieve number to write
	mov	ah, ioctl	; now do write
	mov	   al,3
	mov	bx,prthnd
	int	dos
	jnc	w_ioctl2
w_ioctl1:
	writestring w_ioctlerr	; failure
	stc			; failure
	jmp   w_ioctl2
w_ioctl3:writestring io_notready
	 pop  cx
	 stc
w_ioctl2:
	pop	bx
	pop	ax
	ret
W_IOCTL ENDP
;
;	read cx bytes from ioctl of serial port to tempbuf
;
R_IOCTL PROC	NEAR
	cmp	prthnd,0		; port opened?
	jne	r_ioctl0		; ne => it is open
	writechar 'R'
	ret
r_ioctl0:
	push	ax			; save regs
	push	bx
	mov	ah,ioctl
	mov	al,2
	mov	bx,prthnd
	mov	dx,offset tempbuf
	int	dos
	jnc	r_ioctl1       ; all ok
	writestring r_ioctlerr
r_ioctl1:
	pop	bx
	pop	ax
	ret
R_IOCTL ENDP
;
;	check serial port for characters and return number in al
;
CHK_BUFF PROC	NEAR
	push	cx
	push	dx
	mov	dx,offset chk_msg
	mov	cx,2
	call	w_ioctl
	jc	chk_buff1      ; failure
	mov	cx,1
	call	r_ioctl
	jc	chk_buff1	; failure
	mov	ax,tempbuf
	pop	dx
	pop	cx
	ret
chk_buff1: pop	dx
	   pop	cx
	   xor	ax,ax	    ; no characters upon failure
	   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
	cmp	repflg,0		; doing replay?
	je	prtch0			; e => not doing replay
	jmp	getrepchr		; get replay character if in replay
prtch0:
	push	bx
	push	cx
	push	si
	cmp	prthnd,0		; got a handle
	jne	prtch1			; ne = yes
	call	opnprt			; open port if not
	jc	 prt3x			; exit if error
prtch1: cmp	count,0			; any chars in buffer?
	jne	prtch2			; ...yes, get one
	call	chk_buff		; any chars at port?
	or	al,al			; ax has characters available
	jz	prtch4			; no, go to skip return
	mov	ah,0
	 mov	cx,ax			; read as many as are available
;	 mov	 cx,1			 ; read one char
	mov	count,cx
	mov	bx,prthnd
	mov	ah,readf2		; DOS read from file/device
	mov	dx,offset source
	int	dos
	jc	prt3x			; c = failure
	mov	count,ax		; number of bytes read
	mov	bufout,offset source
prtch2: dec	count
	mov	si,bufout
	cld
	lodsb
	mov	bufout,si
prtch3: ;;call printal	 ; print character from port
	pop	si
	pop	cx
	pop	bx
	clc
	ret				; return success
prt3x:	mov	ah,prstr
	mov	dx,offset erms50
	int	dos
prtch4: pop	si
	pop	cx
	pop	bx
	stc				     ; stc means no characters
	ret
PRTCHR	ENDP

tprn  proc near
     ret
tprn endp

breakkey proc near			   ; handle pressing of break key
	push  ax
	push  ds
	mov  ax,data
	mov  ds,ax			   ; get correct data segment
	mov  need_break,true		   ; flag that break needs setting
	pop   ds
	pop   ax
	iret
breakkey endp

; Send a break out the current serial port.	Returns normally.
; sendbrw is worker routine time in milliseconds in ax
SENDBRW	 PROC	 NEAR
	push	cx
	push	dx
	push	ax	     ; save time of break
	mov	dx,offset brk_on
	mov	cx,3
	call	w_ioctl
	pop	ax	     ; restore time
	call	pcwait	     ; delay the appropriate time
	mov	dx,offset brk_off
	mov	cx,3
	call	w_ioctl
	pop	dx
	pop	cx
	mov  need_break,false	     ; don't need to do break
sendbrw1: clc			     ; clear carry to stay in Connect mode
	ret
SENDBRW	 ENDP

SENDBR	PROC	NEAR			; Send a Break
	mov	ax,275			; 275 ms for normal break
	jmp	sendbrw			; go to worker routine
SENDBR	ENDP

SENDBL	PROC	NEAR			; Send a Long Break
	mov	ax,1800			; 1800 ms for long break
	jmp	sendbrw			; go to worker routine
SENDBL	ENDP

; IHOSTS - Initialize the host by sending XON, or equivalent, and enter the
; cycle of clear input buffer, wait 1 second, test if buffer empty then exit
; else repeat cycle. Requires that the port be initialized before hand.
; Ihosts is used by the local send-file routine just after initializing
; the serial port.
; 22 March 1986 [jrd]

IHOSTS	PROC	NEAR
	push	ax		; save the registers
	push	bx
	push	cx
	push	dx
	mov	bx,portval	; port indicator
	mov	ax,[bx].flowc	; put Go-ahead flow control char in ah
	or	ah,ah		; don't send null if flow = none
	jz	ihosts1		; z = null
	call	outchr		; send it (release Host's output queue)
	 nop			; outchr can do skip return
	 nop
	 nop
ihosts1:call	clrbuf		; clear out interrupt buffer
	pop	dx		; empty buffer. we are done here
	pop	cx
	pop	bx
	pop	ax
	ret
IHOSTS	ENDP

; IHOSTR - initialize the remote host for our reception of a file by
; sending the flow-on character (XON typically) to release any held
; data. Called by receive-file code just after initializing the serial
; port.		22 March 1986 [jrd]
IHOSTR	PROC	NEAR
	push	ax		; save regs
	push	bx
	push	cx
	mov	bx,portval	; port indicator
	mov	ax,[bx].flowc	; put Go-ahead flow control char in ah
	or	ah,ah		; don't send null if flow = none
	jz	ihostr1		; z = null
	call	outchr		; send it (release Host's output queue)
	 nop			; outchr can do skip return
	 nop
	 nop
ihostr1:pop	cx
	pop	bx
	pop	ax
	ret
IHOSTR	ENDP

DTRLOW	PROC	NEAR		; Global proc to Hangup the Phone by making
				; DTR and RTS low.
	mov ah,CMLINE		; allow text to be able to display help
	mov bx,offset rdbuf	; dummy buffer
	mov dx,offset hnghlp	; help message
	call comnd		; get a confirm
	jnc  dtrlow1		; nc => success
	ret			; get out if failure
dtrlow1:
	call serhng		; drop DTR and RTS
	mov ah,prstr		; give a nice message
	mov dx,offset hngmsg
	int dos
	clc		       ; carry clear for success
	ret
DTRLOW	ENDP

; Hang up the Phone. Similar to SERRST except it just forces DTR and RTS low
; to terminate the connection. 29 March 1986 [jrd]
; Calling this twice without intervening calls to serini should be harmless.
; Returns normally.
; Adapted from recommendation by Mike Mellinger. [jrd]
SERHNG	PROC	NEAR
	saveregs
	cmp	prthnd,0	; is the port open
	je	serhn1		; e => it is closed
      ;	 mov	 ax,offset port3
      ;	 cmp	 ax,portval
      ; je	serhn4		; don't do anything for 82164A
	cmp	bigscreen,1	; do we have the plus?
	je	serhn2		; yes we do
	mov	dx,offset $off_m110  ; separate hangup for 110
	mov	cx,len$off_m110
	jmp	serhn3
serhn2:
	mov	dx,offset $off_m ; magic words to turn off DTR
	mov	cx,off_len	; their length
serhn3:
	 call w_ioctl		 ; write them
serhn4:	 mov	 bx,prthnd	  ; close port
	 mov	 ah,close2	 ; close the device
	int	dos
	mov	prthnd,0	; port no longer open
	mov	ax,1000
	call	pcwait		 ; delay so hangup can work
serhn1:
	restoreregs
	ret
SERHNG	ENDP

; Wait for the # of milliseconds in ax, for non-IBM compatibles.
; Thanks to Bernie Eiben for this one.
pcwait	proc	near
	mov	cx,240		; inner loop counter for 1 millisecond
pcwai1: sub	cx,1		; inner loop takes 20 clock cycles
	jnz	pcwai1
	dec	ax		; outer loop counter
	jnz	pcwait		; wait another millisecond
	ret
pcwait	endp


; Position the cursor according to contents of DX:
; DH contains row, DL contains column.	Returns normally.
POSCUR	PROC	NEAR
	push	ax			; save regs
	push	dx
	push	di
	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
	pop	di
	pop	dx
	pop	ax
	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
	push	ax			; save regs
	push	dx
	mov	ah,prstr
	mov	dx,offset delstr	; Erase weird character
	int	dos
	pop	dx
	pop	ax
	ret
DODEL	ENDP

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

CTLU	PROC	NEAR
	push	ax			; save regs
	push	dx
	mov	ah,prstr
	mov	dx,offset clrlin
	int	dos
	call	clearl
	pop	dx
	pop	ax
	ret
CTLU	ENDP

; Set the current port.

COMS	PROC	NEAR
	mov	dx,offset comptab	; table of comms ports
	mov	bx,0			; use keywords as help
	mov	ah,cmkey		; parse a keyword
	call	comnd
	jnc	coms1			; nc => success
	ret				; get out if failure
coms1:	push	bx
	mov	ah,CMEOL
	call	comnd			; Get a confirm
	jc   comx		       ; carry => failure

	call	serr_x			; force close on serial port

	pop	bx
	mov	flags.comflg,bl		; Set the comm port flag
	cmp	flags.comflg,1		; Using Com 1?
	jne	coms2			; ne = no
	mov	portval,offset port1
	clc				; carry clear for success
	ret
coms2:	cmp	bl,2			; using com2?
	jne	coms3			; ne = no
	mov	portval,offset port2
	clc				; success [jan]
	ret
coms3:
	mov	portval,offset port3
	clc				 ; success [jan]
	ret
comx:	pop	bx
	stc				 ; carry set for failure [jan]
	ret
COMS	ENDP

; Set tektronix emulation on/off

VTS	PROC	NEAR
      mov     dx,offset termtb
      mov     bx,0
      mov     ah,cmkey
      call    comnd
      jnc    vts00		  ; nc => success
      ret			  ; return if failure
vts00: push    bx
      mov     ah,CMEOL
      call    comnd		  ; Get a confirm
      jc      vtx		  ; carry => didn't get a confirm
      pop     bx
      cmp     bl,hpkeynum	  ; want hpkeyboard
      jne     vts0		  ; ne => no
      mov     keyflg,hpkeynum
      call    setkeyboard
      clc
      ret
vts0: cmp     bl,altkeynum	   ; want alt keyboard?
      jne     vts0a		   ; ne=> no
      mov     keyflg,altkeynum	   ; turn on altkeyboard
      call    setkeyboard
      clc
      ret
vts0a:	cmp   bl, tekonnum	   ; enable tek ?
      jne   vts0b		   ; ne => don't enable
      and   denyflg, not tekxflg   ; clear tekxflgbit
      mov tekbyte, bl		   ; for status display
      clc
      ret
vts0b: cmp bl, tekoffnum	   ; disable tek ?
	jne vts1		   ; ne=> don't disable
	or  denyflg, tekxflg	   ; set deny tek bit
	mov  tekbyte, bl	   ; for status
	clc
	ret
vts1:
      mov     flags.vtflg,bl	   ; Set the Tektronix emulation flag [jan]
      mov     tekflg,0		   ;need to re-initialize tek emulator [jan]
      clc			   ; success
      ret
vtx:  pop bx
      stc			  ; carry set => failure
      ret
VTS	ENDP

VTSTAT	PROC	NEAR	; For Status display [jrd]
       mov  bx,offset vtstbl  ; table of things to show
       jmp  statc	      ; common status code
      ;;  ret		  ; no emulator status to display
VTSTAT	ENDP

; Save the screen to a buffer and then append buffer to a disk file. [jrd]
; Default filename is Kermit.scn; actual file can be a device too. Filename
; is determined by mssset and is passed as pointer dmpname.

DUMPSCR PROC	NEAR	; Dumps screen contents to a file. Just Beeps here
	call	beep
	ret
DUMPSCR ENDP


; Initialize variables to values used by the generic MS DOS version.
lclose	proc  near
	 call sethpkey	   ; turn on hp keyboard
	 ret
lclose	 endp

lpop	 proc  near	      ; executed when returing from dos
	 call  setkeyboard    ; turn on the appropriate keyboard
	 ret
lpop	 endp

lpush	proc  near	   ; call before pushing to dos
	call  sethpkey	; turn on hp keyboard
	ret
lpush	endp

lclini	 proc	near
	saveregs
	mov	dosnum,200h	; force dosnum to 2.00 so replay proc works
	mov	prtrdy,true	; port is ready
	call	msuinit		; init keyboard translator
	mov	lclexit, offset lclose ; let mssker know that lclose exists
	mov	lclsusp, offset lpush  ; for mssker (optional)
	mov	lclrest, offset lpop
	mov	flags.vtflg,0	; Don't do terminal emulation
 ;;	mov	prthnd,0      ; no port handle yet. [jrd]
 ;;	call	opnprt	      ; Get file handle for comm port
;;	mov portval, offset port2
;;	mov flags.comflg,2    ; modem on at startup
	mov	portval, offset port1
	mov	flags.comflg, 1	  ; serial port is default at startup
	call	setkeyboard    ; turn on keyboard
	call	id_terminal    ; do we have 110 or portable plus?
	cmp	bigscreen,1    ; using a plus
	je	lclini1	       ; e=> yes we are
	mov	bx,offset port2
	mov	[bx].baud,5    ; modem on 110 = 300 baud

lclini1:
	call	scrsavinit	   ; initialize memory for screen save
	writestring alpha_disp	   ; turn on the alpha display
	call	savescr		   ; save an alpha screen to initialize
	writestring helpini
	restoreregs
	clc
	ret

lclini	 endp

; 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", "COM2", "COM3","AUX".
opnprt proc near
	call serr_x		; close port if already open
	mov	ax, portval
	cmp	ax, offset port1
	jne	opnprt0
	mov	flags.comflg,1
	jmp	opnprt0d	  ; proceed with the open
opnprt0:
	mov	ax, portval
	cmp	ax, offset port2
	jne	opnprt0a
	mov	flags.comflg,2
	jmp	opnprt0d	  ; proceed with the open
opnprt0a:
	mov	ax, portval
	cmp	ax, offset port3
	jne	opnprt0b
	mov	flags.comflg,3
	jmp	opnprt0d	  ; proceed with the open
opnprt0b: mov portval, offset port1  ; if all else fails
	  mov flags.comflg, 1

opnprt0d:
	mov	al,flags.comflg


	dec	al		; flags.comflg = 1 for com1, 2 com2, 3 com3
	mov	ah,0
	mov	si,ax
	shl	si,1			; double index
	mov	dx,prttab[si]
	mov	ah,open2
	mov	al,2
	int	dos
	jnc	opnpr1
	mov	ah,prstr		; It didn't like the string
	mov	dx,offset erms41
	int	dos
	mov	prthnd,0		; clear port file handle
	stc				; carry set for failure
	ret
opnpr1: mov	prthnd,ax		; Call succeeded
	mov	ah,ioctl
	mov	al,00h			; get device info
	xor	dx,dx
	xor	cx,cx			; 0 bytes to read/write
	mov	bx,prthnd		; port's handle
	int	dos
	or	dl,20h			; set binary mode in device info
	xor	cx,cx			; 0 bytes to read/write
	mov	dh,0
	mov	ah,ioctl
	mov	al,01h			; set device info
	int	dos
	mov	ax,portval
	cmp	ax,offset port3		; using 82164A
	jne	 opnpr2
	clc			 ; don't need to write to 82164a
	ret
opnpr2:
	cmp	ax,offset port1		; using port1 (serial) ?
	jne	 opnpr3			  ; ne => no, not using port 1
	mov	dx,offset $m1
	mov	cx,len_$m1
	call	 w_ioctl
	clc
	ret
opnpr3: cmp ax, offset port2	      ; using modem
	jne   opnpr4		      ; ne => not using modem
	 mov	 dx,offset $m0
	mov	cx,len_$m0
	call	w_ioctl
	clc
	ret

opnpr4: clc
	ret				; carry clear for success
opnprt	 endp

  ; set the interrupt vectors

setints	   proc	 near
;    save break vector and set to breakkey
;    first save the break existing interrupt
	cmp	ints_set,true	       ; interrupt vectors set?
	je	setints1	       ; je=>yes, don't reset!
	push	ax
	push	bx
	push	dx
	push	es
	mov	al, brk_int
	mov	ah,35h		       ; get interrupt vector
	int	dos		       ; es:bx has long pointer
	mov	savbrko,bx	       ; offset of routine
	mov	savbrks,es	       ; segment
	pop	es
; now set the break interrupt
	push	ds
	mov	dx,offset breakkey     ; address of interrupt routine
	push	cs		       ; segment of breakkey is code
	pop	ds		       ; ds=cs
	mov	ah,25h		       ; set vector call
	mov	al,brk_int	       ; break key interrupt
	int	21h		       ; set the vector
	pop	ds		       ; restore data segment
; end of setting break vector
setints1:
       mov  ints_set,true	     ; we have set the interrupts
       pop     dx
       pop     bx
       pop     ax
       clc
       ret
setints	 endp

restoreints  proc near		    ; restore interrupts
       cmp   ints_set,false	    ; have we set interrupts?
       je     restoreints1	    ; don't restore if not set!

;     resotore break key interrupt
       push   ds
       mov    dx,savbrko	      ; original offset
       mov    ax,savbrks	      ; original segment
       mov    ds,ax		      ; original segment to ds
       mov     ah,25h		      ;
       mov    al,brk_int
       int    dos		      ; restore original interrupt
       pop    ds
;;end of restore


restoreints1: mov ints_set,false
	      clc
	      ret
restoreints   endp



; Initialization for using serial port.	 Returns normally.
SERINI	PROC	NEAR
	cld				; Do increments in string operations
	cmp	prthnd,0		; Got Handle already?
	jne	ser_x			; ne = yes, skip open
    ;;	call	setints			; set interrupt vectors
	call	opnprt			; open handle
	jc	serin2			; carry set = failure

ser_x:
	call	dobaud			; set baud rate
	jc	serin2
	call	doflow			 ; set hardware flow control
	jc	serin2
	push	bx
	mov	bx,portval		; get port
	mov	parmsk,0ffh		; parity mask, assume parity is None
	cmp	[bx].parflg,parnon	; is it None?
	je	serin1			; e = yes
	mov	parmsk,07fh		; no, pass lower 7 bits as data
serin1: mov	bx,[bx].flowc		; get flow control chars
	mov	flowoff,bl		; xoff or null
	mov	flowon,bh		; xon or null
	pop	bx

	clc			       ; carry clear for success
	ret
serin2: writestring serierr	       ; error message

	call serr_x		       ; force close on bad port
	stc
	ret
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
	cmp	flags.extflg,0
	jne	serr_x
	ret
serr_x: call serhng		; close files and hangup
    ;;	  mov  need_to_set_flow, true ; need to update flow control
	mov  need_to_set_baud, true ; need to update baud rate
	ret
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). Does capture (logging), local echo, debug display, tests
; for printer/logging device not ready. 27 Sept 86 [jrd].
term	proc	near
	saveregs

	mov	argadr,ax		; save argument ptr
	mov	si,ax			; this is source
	mov	di,offset ourarg	; place to store arguments
	push	es			; save register
	push	ds
	pop	es			; set es to data segment
	mov	cx,size termarg
	cld
	rep	movsb			; copy into our arg blk
	pop	es			; restore reg
	and	ourarg.flgs,not (prtscr) ; no screen printing at startup
	mov	ax,ourarg.captr
	mov	captrtn,ax		; buffer capture routine
	call	setints			; set interrupts for connect mode
term0a:
	cmp	flags.vtflg,tttek      ; tek emulation on?
	jne	term0
	 call tekini
term0:
	call	restscr			; restore the screen
	mov	parmsk,0ffh		; parity mask, assume parity = None
	cmp	ourarg.parity,parnon	; is parity None?
	je	term1			; e = yes, keep all 8 bits
	mov	parmsk,07fh		; else keep lower 7 bits

term1:
	cmp prtrdy,false		 ; ready to read port?
	je  term5			; get out
	call	portchr			; read char from serial port
	jnc	short term3		; nc = no char, go on
	cmp	flags.vtflg,tttek	; doing tek emulation?
	je	term1a		       ;e=yes, already doing tek
	call stringchek		    ; check for special escape strings
	jnc   short term3	    ; nc => don't display
term1a: call	outtty		 ; display and capture char [jrd]
term3:
	inc keydelay		       ;just check keyboard once
	mov ax,keydelay		       ;each eight reads of the port
	and ax,7		       ;should speed things up
	jnz term1		      ;at higher baud rates [jan]
	cmp	need_break,false      ; do we need to send a break?
	je     term3a		      ;e=> no, get next key
	call sendbr		      ; do the required break
term3a:
	call	keybd			; call keyboard xlator, send results
	jnc	term1			; nc = stay in Connect mode
term5:					; [gaw@prc]
	call	savescr			; save screen [gaw@prc]
	cmp   flags.vtflg,tttek
	jne   term6		       ; skip string write if not in tek
	writestring  alpha_disp		; turn on alpha display for kermit
term6:
	cmp   prtrdy, true		; need to set kbdflg if wierd exit
	je    term7
	mov  kbdflg,'C'		       ; so we exit connect mode
	mov  prtrdy,true
term7:
	call  restoreints		; restore connect mode interrupts
	restoreregs
	ret				; and return to caller
term	endp


termtog proc  near		; toggle terminal type [jan]
	call	savescr		; save present screen
	cmp	flags.vtflg,tttek ; doing tek emulation ?
	jne	termtog1	  ; ne means  doing tek
	writestring  alpha_disp
	mov	flags.vtflg,ttgenrc ; turn on alpha display
	call	restscr		   ; restore previous alpha display
	clc
	ret
termtog1:
	mov	flags.vtflg,tttek  ; turn on tek display
	call tekini
	call	restscr		; restore the previous screen
	clc			; do not exit Connect mode [jrd]
	ret			; stay in connect mode
termtog endp

kclrscn proc	near		; clear screen in text or Tek mode [jrd]
	cmp	flags.vtflg,tttek ; doing Tek emulation?
	jne	kclrsc1		; ne = no
	call	tekcls		; blank and some more
	clc			; stay in Connect mode
	ret
kclrsc1:call	cmblnk		; blank screen
	clc			; stay in Connect mode
	ret
kclrscn endp

getflgs	 proc  near
	 mov al,ourarg.flgs	       ;supply flags for msggri [jan]
	 ret
getflgs	 endp

; put the character in al to the screen, do capture and printing,
; does translation for Set Input command.
; Adapted from msyibm.asm [jrd]
outtty	proc	near
	cmp	flags.vtflg,tttek	; doing tektronix emulation?
	jne	outtty1			; ne= not doing tek emulation
	jmp	tekemu			; do tekemu and return
outtty1:
   ;;	  call printal			  ; debug
	test	flags.remflg,d8bit	; keep 8 bits for displays?
	jnz	outnp8			; nz = yes, 8 bits if possible
	and	al,7fh			; remove high bit
outnp8: cmp	rxtable+256,0		; is translation off?
	je	outnp7			; e = yes, off
	push	bx			; Translate incoming char [jrd]
	mov	bx,offset rxtable	; address of translate table [jrd]
	xlatb				; new char is in al
	pop	bx
outnp7:
	test	ourarg.flgs,capt	; capturing output? Can be shut off
	jz	outnoc			; no, forget this part
	push	ax			; save char
	call	captrtn			; give it captured character
	pop	ax			; restore character and keep going
outnoc: test	ourarg.flgs,prtscr	; should we be printing?
	jz	outnop			; no, keep going
	push	ax
	mov	ah,print_out		; write to system printer device
	mov	dl,al
	int	dos
	pop	ax
	jnc	outnop			; nc = successful print
	push	ax
	call	beep			; else make a noise and
	call	trnprs			;  turn off printing
	pop	ax
outnop: cmp	flags.vtflg,0		; emulating a terminal?
	jnz	outnop1			; nz = yup, go do something smart
	test	ourarg.flgs,trnctl	; debug? if so use dos tty mode
	jz	outnp5			; z = no
	mov	ah,conout
	cmp	al,7fh			; Ascii Del char or greater?
	jb	outnp1			; b = no
	je	outnp0			; e = Del char
	push	ax			; save the char
	mov	dl,7eh			; output a tilde for 8th bit
	int	dos
	pop	ax			; restore char
	and	al,7fh			; strip high bit
outnp0: cmp	al,7fh			; is char now a DEL?
	jne	outnp1			; ne = no
	and	al,3fH			; strip next highest bit (Del --> '?')
	jmp	outnp2			; send, preceded by caret
outnp1: cmp	al,' '			; control char?
	jae	outnp3			; ae = no
	add	al,'A'-1		; make visible
outnp2: push	ax			; save char
	mov	dl,5eh			; caret
	int	dos			; display it
	pop	ax			; recover the non-printable char
outnp3: mov	dl,al
	int	dos
	ret
;outnp4: ;cmp	  al,bell		  ; bell (Control G)? [jrd]
	;jne	 outnp5			 ; ne = no
       ; jmp	 beep			 ; use short beep, avoid char loss.
outnop1:
outnp5:
	cmp	bigscreen, 1		; do we have the plus
	jne	outnp5a			; ne => we just have a 110
	cmp	al,14			; is the character CTRL N?
	je	outnp6			; e=> yes, do not print CTRL N
					; (CTRL N on Plus messes up character
					; set)
	push	 si			; print character on plus
	mov	plus_char,al		; where si expects it
	mov	bx,6			; don't know why
	mov	si,offset plus_char	; write the character
	int	50h			; special interrupt
	pop	si
	ret

outnp5a:
	mov	ah,conout		; dostty screen mode
	mov	dl,al			; write without intervention.
	int	dos			; else let dos display char
outnp6: ret				; and return
outtty	endp



; send the character in al out to the serial port; handle echoing.
; Can send an 8 bit char while displaying only 7 bits locally.
outprt	proc	near
	test	ourarg.flgs,lclecho	; echoing?
	jz	outpr1			; z = no, forget it
	push	ax			; save char
	call	outtty			; print it
	pop	ax			; restore
outpr1: mov	ah,al			; this is where outchr expects it
	call	outchr			; output to the port
	ret
outprt	endp

; Get a char from the serial port manager
; returns with carry on if a character is available
portchr proc	near
	call	prtchr			; character at port?
	jnc   portc1
portc0: clc				; no carry -> no character
	ret				; and return
portc1: and	al,parmsk		; apply 8/7 bit parity mask
; don't catch anybody [jan]
       ; or	 al,al			 ; catch nulls
       ; jz	 portc0			 ; z = null, ignore it
       ; cmp	 al,del			 ; catch dels
       ; je	 portc0			 ; e = del, ignore it
	stc				; have a character
	ret				; and return
portchr endp

;; keyboard translator action routines, system dependent, called from msugen.
; These are invoked by a jump instruction. Return carry clear for normal
; processing, return carry set to exit Connect mode (kbdflg has transfer char)

;  msu calls this to send keystroke out the port
chrout	proc  near
	cmp	repflg,0		; in replay mode?
	je	chrout1			; e=> not doing replay
	jmp	repchrout	      ; display the replay character
chrout1:call	outprt		       ; put char in al to serial port
	clc				; stay in Connect mode
	ret
chrout	endp

trnprs: push	ax			; toggle Copy screen to printer
	test	ourarg.flgs,prtscr	; are we currently printing?
	jnz	trnpr2			; nz = yes, its on and going off
	mov	ah,ioctl
	mov	al,7			; get output status of printer
	push	bx
	mov	bx,4			; file handle for system printer
	int	dos
	pop	bx
	jc	trnpr1			; c = printer not ready
	cmp	al,0ffh			; Ready status?
	je	trnpr2			; e = Ready
trnpr1: call	beep			; Not Ready, complain
	jmp	trnpr3			; and ignore request
trnpr2: xor	ourarg.flgs,prtscr	; flip the flag
trnpr3: pop	ax
	clc
	ret

klogon	proc	near			; resume logging (if any)
	test	flags.capflg,logses	; session logging enabled?
	jz	klogn			; z = no, forget it
	or	ourarg.flgs,capt	; turn on capture flag
	push	bx
	mov	bx, argadr		; update kermits capture flag
	or	[bx].flgs, capt
	pop	bx
klogn:	clc
	ret
klogon	endp

klogof	proc	near			; suspend logging (if any)
	and	ourarg.flgs,not capt	; stop capturing
	push	bx
	mov	bx, argadr
	and	[bx].flgs, not capt	 ; update kermits capture flag
	pop	bx

klogo:	clc
	ret
klogof	endp

snull:	mov	ah,0			; send a null
	call	outchr			; send without echo or logging
	clc
	ret

kdos:	mov	al,'P'			; Push to DOS
	jmp	short cmdcom
cstatus:mov	al,'S'			; these commands exit Connect mode
	jmp	short cmdcom
cquit:	mov	al,'C'
	jmp	short cmdcom
cquery: mov	al,'?'
	jmp	short cmdcom
cmdcom: mov	kbdflg,al		; pass char to msster.asm via kbdflg
	stc				; say exit Connect mode
	ret

; Jumping here is the same as a ret.

R	PROC	NEAR
	ret
R	ENDP

code	ends
	end
