home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Columbia Kermit
/
kermit.zip
/
a
/
msxhpx.asm
< prev
next >
Wrap
Assembly Source File
|
2020-01-01
|
71KB
|
2,522 lines
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