name msxgri ; File MSXGRI.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. ; Grid Compass dependent file for MS-DOS Kermit ; Use with msugri.asm keyboard translator file. ; Edit history ; 2 March 1991 version 3.10 ; Last edit: ; 2 March 1991 ; Dec. 7, 1990. Put modem in verbose mode at startup. ; Change machnm from GRID to GRiD. ; Nov. 27, 1990. Add call to getbaud in serini. ; Nov. 24, 1990. Remove reference to prserr to make link happy. ; Nov. 21, 1990. Fix so both serial and modem drivers need not be loaded ; if they are not used. [jan] ; October 1990. Cosmetic fixes. ; August 1990. Select tek enable/ disable in termtb ; 22 february 1990 Fix up baud setting and and string parsing ; procedurs [jan] ; 23 January 1990. Version 3. Fix up comnd calls. Chance PRTCHR so ; clc for character, stc for no character. clc in OUTPRT. Include ; baud table and portval. Add BAUDST from MSXIBM.ASM. Zap DODISK. [jan] ; 3 February 1989. ; Call "call cmblnk" call call to tekcls so tek screen is cleared ; even if it's not initialized ; Take out II in machnm since this also works on 1101 [jan] ; 5 January 1989. Fix up SERINT, SERINI, SERRST, and SENDBR. ; Implement GETMODEM and SERHNG. Send 'ATE1' to modem in LCLINI. [jan] ; 13 Dec 1988 Move screen clear and terminal type toggling to this file. ; Do other small cleanups. [jrd] ; ; John Nyenhuis Purdue University School of Electrical Engineering ; West Lafayette IN 47907 (317)494-3524 nyenhuis@ecn.purdue.edu ; November 1988 ; Fix up for Tektronix emulation ; User can specify screen size by set term 112x or set term 113x ; Call sbrk to get memory for Tektronix and ascii screen saves ; enable automatic entry into Tektronix emulator ; Most characters are now written to screen through bios rather than with DOS ; keyboard is checked once each 8 read of serial port for added speed ; Xon/Xoff flow control enabled ; vt52 terminal emulation taken out (all it did was to not restore the cursor) ; ; 1 July 1988 Version 2.31 ; 12 June 1988 Add error recovery if serial port fails to initialize, reduce ; serial port buffer to 1000 bytes. [jrd] ; 11 Jan 1988 Add 2.30 features. [jrd] ; 1 Jan 1988 version 2.30 ; ; Jim Noble ; Planning Research Corporation ; 1500 Planning Research Drive ; Mail Stop 5S3 ; McLean, VA 22102 ; May, 1985 ; Add global entry point vtstat for use by Status in mssset. ; Added register save/restore in procedure getbaud. ; 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] saveregs macro push ax push bx push cx push dx push es push di push si push ds pushf endm restoreregs macro popf pop ds pop si pop di pop es pop dx pop cx pop bx pop ax endm ;; 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, getflgs, setchtab cmcfm equ cmeol ; equates to account for 3.0 cmtxt equ cmline ; names changes in cmfile equ cmword ; mssdef.h baudsiz equ 18 ; entries in baud table false equ 0 true equ 1 print_out equ 05h ; dos function to print to printer prtscr equ 80h ; print screen pressed gbuflen equ 1000 ; max bytes grid internal buffer holds mntrgh equ gbuflen/2 ; High point = 1/2 of buffer full. mntrgl equ gbuflen/4 ; Low point = 1/4 buffer full. [jrd] CLK_INT equ 1ch*4 ; clock interrupt gserial equ 81h ; grid serial port interrupt gmodem equ 82h ; grid modem port interrupt ginit equ 0 ; function 0 - initialize port gread equ 1 ; function 1 - read data gwrite equ 2 ; function 2 - write data gwcmd equ 4 ; function 4 - write command grstat equ 5 ; function 5 - read status gflush equ 6 ; function 6 - buffer flush ggbaud equ 7 ; function 7 - get baud gsbaud equ 8 ; function 8 - set baud gspar equ 9 ; function 9 - set parity gsdata equ 10 ; function 10 - set data bits gssbit equ 11 ; function 11 - set stop bits gbufass equ 12 ; function 12 - buffer assign gcharto equ 13 ; function 13 - set character timeout gcts equ 19 ; function 19 - clear to send timeout gbrkon equ 0effH ; function 14 - set break on gbrkoff equ 0e00H ; function 14 - set break off scnstrt equ 400h ; starting address of screen area (page 0) maxscnwrds equ 256*32 ; max number of words in screen memory area tekonnum equ 18 ; enable tek auto entry tekoffnum equ 19 ttbig equ 12 ;big screen ttsmall equ 23 ;small screen data segment public 'data' extrn flags:byte, trans:byte extrn dmpname:byte extrn kbdflg:byte, rxtable:byte extrn tekflg:byte ; used in msggri [jan] extrn denyflg:word ; controls tek autoentry etc extrn dosnum:word extrn repflg:byte, diskio:byte ; for replay feature extrn kbdflg:byte ; in telnet ; 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 ; table with datacomm status for the status command vtstbl stent ; tell tek able/disable stent ; tell screen size dw 0 ; end of table tekstatustxt db 'Tek Auto Entry: $' tekbyte db tekonnum ; tek auto entry code screenstatustxt db 'Screen Size: $' screenbyte db ttsmall prtrdy db true ; when false, exit connect mode machnam db 'GRiD_COMPASS$' msmsg1 db cr,lf,' Modem is not ready: DSR is off$' msmsg2 db cr,lf,' Modem is ready: DSR is on$' msmsg3 db cr,lf,' no Carrier Detect: CD is off$' msmsg4 db cr,lf,' Carrier Detect: CD is on$' msmsg5 db cr,lf,' no Clear To Send: CTS is off$' msmsg6 db cr,lf,' Clear To Send: CTS is on$' msmsg7 db cr,lf,' Modem is not used by the Network$' mdmhand db 0 ;used by showmodem mdmstr db 'ATE1Q0V1S7=25,',cr,lf ;init modem string mdmstrlen equ $-mdmstr ;length of modem string ;;new stuff to scan escape sequences from comm port [jan] stringtab dw tekst1,tekst2 ; strings for matching numstrings equ 2 ; number of strings to match disptab dw toteknoplay,totekplay ; dispatch table 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] 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 scanning scnwrds dw 240*20 ;words in small screen [jan] scrsavseg dw ? ;segment for screen save [jan] bigscreen db 0 ;=1 for big [jan] prevport db 86 ;port number on previous connect portbusy db 0 ;serial port not yet busy save_ax dw ? ;temp location to save ax save_ds dw ? ;temp location to save ds curini db 0 ; [gaw@prc] cursav db ESCAPE,'[s','$' ; [gaw@prc] curres db ESCAPE,'[u','$' ; [gaw@prc] curon db ESCAPE,'[3;3z','$' ; [gaw@prc] curoff db ESCAPE,'[3;4z','$' ; [gaw@prc] erms20 db cr,lf,'?Warning: System has no disk drives$' erms40 db cr,lf,'?Warning: Unrecognized baud rate$' badbd db cr,lf,'Unimplemented baud rate$' crlf db cr,lf,'$' comphlp db cr,lf,'1 (SERIAL) 2 (MODEM)$' ; [19b] [gaw@prc] 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,'$' rdbuf db 80 dup (?) ; temp buf noimp db cr,lf,'?Not implemented.$' delstr db BS,' ',BS,'$' ; Delete string clrlin db cr,ESCAPE,'[0K','$' portin db 0 ; has clock int vector been initialized? xofsnt db 0 ; Say if we sent an XOFF. xofrcv db 0 ; Say if we received an XOFF. insrvc db false ; Say if in service on XON/XOFF interrupt parmsk db ? ; parity mask, 0ffh for no parity, 07f with. 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 invseq db ESCAPE,'[7m$' ; Reverse video. nrmseq db ESCAPE,'[0m$' ; Normal mode. ivlseq db 79 dup (' '),cr,'$' ; Make a line inverse video tmp db ?,'$' temp dw 0 temp1 dw ? ; Temporary storage. temp2 dw ? ; Temporary storage. fncerr db cr,lf,'Error on function ' fnctype db 'X with a status return of ' fncstat db 'Y$' argadr dw ? ; address of arg blk ; key redefinitions setktab db 0 setkhlp db 0 ; Entries for choosing communications port. comptab db 2 ; number of entries mkeyw 'Serial',1 mkeyw 'Modem',2 setchtab db 1; set file character-set table mkeyw 'CP437',437 termtb db 6 mkeyw '112x',ttsmall mkeyw '113x',ttbig mkeyw 'ANSI',ttgenrc mkeyw 'Tek4010',tttek mkeyw 'EnableTek',tekonnum mkeyw 'DisableTek', tekoffnum defbaud equ 7 ; defauld baud rate is 1200 port1 prtinfo port2 prtinfo portval dw port1 ; Default is to use port 1 bdtab db 16 ; 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 '2000',9 mkeyw '2400',10 mkeyw '3600',11 mkeyw '4800',12 mkeyw '7200',13 mkeyw '9600',14 mkeyw '19200',15 modbdtab db 2 ; baud entries legal for modem mkeyw '300',5 mkeyw '1200',7 ; variables for serial interrupt handler gbuffer db gbuflen DUP(?) ; large internal buffer for grid [gaw@prc] source db bufsiz DUP(?) ; Buffer for data from port bufout dw 0 ; buffer removal ptr count dw 0 ; Number of chars in int buffer bufin dw 0 ; buffer insertion ptr telflg db 0 ; Are we acting as a terminal clreol db ESCAPE,'[0K$' blank db ESCAPE,'[2J$' movcur db ESCAPE,'[' colno db 20 dup (?) ten db 10 ourarg termarg <> keydelay dw 0 ;for periodically checking the keyboard clkdelay dw 0 ;check flow control every 4th tick serclk db false ;clock interrupt resets-for xon/xoff charout dd ? ; pointer to direct screen write [jan] savclko dw ? ; save clock tick interrupt vector offset savclks dw ? ; save clock tick interrupt vector segment data ends code segment public 'code' extrn comnd:near, dopar:near, defkey:near extrn sleep:near, msuinit:near, keybd:near extrn tekcls:near extrn tekemu:near ; entry point to msggri [jan] extrn sbrk:near ; memory allocator in mssker [jan] extrn srchkw:near, statc:near assume cs:code,ds:data ; local initialization lclini proc near mov dosnum,200h ; force dosnum to 2.00 so replay proc works mov prtrdy,true ; port is ready push es ;first set up for direct screen writing [jan] push bx ; See page A1 of the GRiD DOS Manual mov ax,0 mov es,ax les bx,es:[200h] ; look in Bios for address of charout mov ax,es:[bx+20h] ; offset of charout in ax mov bx,es:[bx+22h] ; seg of charout routine in bx ; now store addr in a pointer that is used ; for indirect calls to charout mov word ptr charout,ax mov word ptr charout+2,bx pop bx ; restore the registers pop es ;we're all set up for direct screen write [jan] mov tekflg,0 ;tek emulator not initialized [jan] mov portin,0 ; serial port not yet initialized mov flags.vtflg,0 ; turn off terminal emulation [gaw@prc] call msuinit ; init keyboard translator call scrsavinit ;set up screen memory ; call serini ; initialize serial port ret lclini endp ;scrsavinit sets up memory block for saving tektronix and ; alpha screens two pages of screen memory are requested ; first page is for alpha, second is for tektronix scrsavinit proc near ;set up memory block to save [jan] push ax push cx push es push di mov ax,maxscnwrds*4+100 ; want 4*maxscnwrds bytes call sbrk ; ax will have the segment mov scrsavseg,ax ; put it in our data segment xor ax,ax ; ax=0--clear screen buffer mov di,ax ; di=0 mov cx,2*maxscnwrds+6 ; number of words to be 0 mov es,scrsavseg ; es points to memory segment rep stosw ; zero memory location [jrd] pop di pop es pop cx pop ax ret scrsavinit endp ; Clear the input buffer before sending a packet. CLRBUF PROC NEAR cmp repflg,0 ; doing replay? je clrb0 ; e => no replay ret ; don't clear if replaying clrb0: push ax ;need to save for CROSHAIR in msggri cli mov ax,offset source mov bufin,ax mov bufout,ax mov count,0 sti clrb1: call prtchr ; get a character jnc clrb1 ; until there aren't any more pop ax clc ret CLRBUF ENDP ; Common routine to clear to end-of-line CLEARL PROC NEAR mov dx,offset clreol mov ah,prstr int dos ret CLEARL ENDP ; SHOW MODEM, displays current status of lines DSR, CD, and CTS. ; Uses byte mdmhand, the modem line status register. [jrd] shomodem proc near mov ah,cmcfm ; get a confirm call comnd jnc shomod0 ret ; get out if error shomod0: mov dx,offset msmsg7 ; no modem status for network call getmodem ; get modem status mov mdmhand,al mov ah,prstr mov dx,offset msmsg1 ; modem ready msg test mdmhand,20h ; is DSR asserted? jz shomd1 ; z = no mov dx,offset msmsg2 ; say not asserted shomd1: int dos mov dx,offset msmsg3 ; CD asserted msg test mdmhand,80h ; CD asserted? jz shomd2 ; z = no mov dx,offset msmsg4 ; say not asserted shomd2: int dos mov dx,offset msmsg5 ; CTS asserted msg test mdmhand,40h ; CTS asserted? jz shomd3 ; z = no mov dx,offset msmsg6 ; say not asserted shomd3: mov ah,prstr int dos stc ret ; carry set upon failure shomodem endp ; Get modem status and set global byte mdmhand. Preserve all registers. ; status in al ; ax not preserved [jan] getmodem proc near push bx ;need to save everybody push cx push dx pushf mov ah,5 ;grid status call call grdfnc mov al,ah ;ah contains status if no error popf pop dx pop cx pop bx clc ; carry clear upon success ret getmodem endp ; Do a grid function call to the correct com port and return GRDFNC PROC NEAR or portbusy,1 ;so we know port is busy push es ; save es reg push ds ; then mov ds to es pop es push ax ; save function call and value in al add ah,"0" ; make function code printable mov fnctype,ah ; and save in error message pop ax ; restore ax cmp flags.comflg,1 ; serial port or modem? [gaw@prc] jne grdfnc1 ; if modem, do other int [gaw@prc] int gserial ; else do serial port function call [gaw@prc] jmp short grdfnc2 ; skip other int [gaw@prc] grdfnc1:int gmodem ; do modem port function call [gaw@prc] grdfnc2:jnc grdfnc3 ; skip error msg if carry not set add al,"0" ; make error code printable mov fncstat,al ; and put in error message mov ah,prstr push dx mov dx,offset fncerr ; Give an error message int dos pop dx grdfnc3:pop es ; restore es and portbusy,0feH ; clear bit 0 ret GRDFNC 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 for serial mov si,portval mov ax, offset port2 ; structure for modem cmp ax,si ; using the modem jne baudst1 ; ne= > yes, using modem mov dx, offset modbdtab baudst1:xor bx,bx ; help is the table itself mov ah,cmkey ; get keyword call comnd jc baudst2 ; c = failure push bx ; save result mov ah,cmeol ; get confirmation call comnd pop bx jc baudst2 ; c = failure mov si,portval ; get address of baud structure mov ax,[si].baud ; remember original value mov [si].baud,bx ; set the baud rate call dobaud ; use common code clc baudst2:restoreregs ret BAUDST ENDP ; Set the baud rate for the current port, based on the value ; in the portinfo structure. Returns normally. ; illegal rate not checked; baudst does this DOBAUD PROC NEAR saveregs mov bx,portval mov ax,[bx].baud ; ax has baud rate from bdtab mov ah,gsbaud ; set up to set the port baudrate call grdfnc ; do a grid function call to a com port restoreregs ret DOBAUD ENDP ; Send a break out the current serial port. Returns normally. sendbr proc near push ax mov ax,250 ;250 milliseconds long call sendbrt ;do a timed break pop ax ;restore ax ret sendbr endp ; Send a long break out the current serial port. Returns normally. sendbl proc near push ax mov ax,1400 ;1400 milliseconds long call sendbrt ;do a timed break pop ax ;restore ax ret sendbl endp ;send timed break. ax has length in milliseconds. sendbrt proc near mov portbusy,2 ; port is occupied push cx ; save cx push ax ; save length of break mov ax,gbrkon ; setup to do break on [gaw@prc] call grdfnc ; do break on pop ax ; get time to delay call pcwait ; wait awhile mov ax,gbrkoff ; setup to do break off [gaw@prc] call grdfnc ; do break off mov ax,50 call pcwait ; wait awhile pop cx ; restore mov portbusy,0 ; port no longer busy clc ret ; And return sendbrt endp ; Send char in ah out the serial port. Checks flow control. ; clc if success OUTCHR PROC NEAR push cx push bx cmp portin,0 ; port initialized? jne outchr0 ; ne=> not initialized call serini ; initialize port outchr0: mov bx,portval cmp [bx].floflg,0 ; Are we doing flow control pop bx je outch2 ; No, just continue 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: mov al,ah ; parity routine expects character in al call dopar ; do the parity [jan ] mov byte ptr temp,al ; put character in buffer push di ; Save register mov cx,1 ; set up to write one char to a grid port mov di,offset temp mov ah,gwrite call grdfnc ; go write a character pop di ; restore saved registers pop cx clc ret ; clc means success OUTCHR ENDP ; This routine blanks the screen. CMBLNK PROC NEAR push ax push dx mov ah,prstr mov dx,offset blank int dos pop dx pop ax clc ; stay in connect mode ret CMBLNK ENDP LOCATE PROC NEAR mov dx,0 ; Go to top left corner of screen. jmp poscur ; callret... LOCATE 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 push ax ; save some regs push bx push cx push dx mov ah,ggbaud ; set up to get port baud rate call grdfnc ; and go get it mov al,ah ; mov baudrate into al mov ah,0 ; and zero upper part of ax mov bx,portval mov [bx].baud,ax ; Set baud rate pop dx ; restore regs pop cx pop bx pop ax clc ; msxibm does this ret GETBAUD ENDP ; Returns with char in al, # of chars in buffer in dx and carry clear. ; Carry set means no character available. PRTCHR PROC NEAR cmp repflg,0 ; doing replay? je prtch0a ; e => not doing replay jmp getrepchr ; get replay character if in replay prtch0a: cmp portin,0 ; port not initialized jne prtch0b ; 0=> not initialized call serini prtch0b: cmp serclk,true ; should we check flow control? [jan][jrd] jne prtch0 ;ne = no call flowchek ;checkout flow control prtch0: push si cmp count,0 ; any characters? jne prtch2 ; ne = yes, get from buffer prtch1: push di push bx push cx mov cx,bufsiz ; set up to read from grid port buffer mov di,offset source mov ah,gread call grdfnc pop cx ; restore saved registers pop bx pop di mov count,ax ; reset count or ax,ax jz prtch4 ; still no chars mov bufout,offset source ; this is output ptr prtch2: dec count mov dx,count ; return count in dx mov si,bufout cld lodsb ; get character mov bufout,si ; update ptr pop si clc ; clc means a character ret prtch4: pop si stc ; stc means no characters ret PRTCHR ENDP ;FLOWCHEK --Check to see if we need to do flow control ;this gets called in connect mode each 4 ticks of the clock ;both SERINT and PRTCHR call this. SERINT will not call FLOWCHEK ;if the port is busy ; ; FLOWCHEK PROC NEAR or portbusy,2 ;bit 1 set if in flowchek ; code below largely taken from old SERINT push ax push bx push cx push dx push di cld mov bx,portval cmp [bx].floflg,0 ; Doing flow control? je intdone ; No, just leave. mov ah,grstat ; get the buffer count call grdfnc cmp xofsnt,true ; Have we sent an XOFF? je flowchek1 ; Yes. cmp cx,mntrgh ; Past the high trigger point? jbe intdone ; No, we're within our limit mov ah,flowoff ; Get the XOFF or ah,ah ; null (no flow control)? jz intdone ; z = yes, do nothing mov byte ptr temp,ah ; put character in buffer mov cx,1 ; set up to write one char to a grid port mov di,offset temp mov ah,gwrite call grdfnc ; go write a character mov xofsnt,true ; Remember we sent it jmp intdone flowchek1: cmp cx,mntrgl ; below the low trigger point? ja intdone ; no, don't send XON mov ah,flowon ; get the XON or ah,ah ; null? jz intdone ; z = yes, do nothing mov byte ptr temp,ah ; put character in buffer mov cx,1 ; set up to write one char to a grid port mov di,offset temp mov ah,gwrite call grdfnc ; go write a character mov xofsnt,false ; remember we sent it intdone:pop di pop dx pop cx pop bx pop ax mov serclk,false mov portbusy,0 ;port no longer busy ret FLOWCHEK 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,cmtxt ; 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 ret ; get out if error dtrlow1: call serhng ; drop DTR and RTS mov ah,prstr ; give a nice message mov dx,offset hngmsg int dos clc ret ; clear carry for success 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. SERHNG PROC NEAR ;[jan] or portbusy,2 ;port is occupied mov ax,150 call pcwait ;wait for next tick of clock cmp flags.comflg,1 ;serial(1) or modem(<>1) jne serhngm ;jne means we are using modem mov ax,01000H ;turn off rts with function 16 call grdfnc mov ax,100 call pcwait ;wait 100 mx mov ax,01100H ;turn off dtr with function 17 call grdfnc mov ax,500 ;wait 1/2 second call pcwait mov ax,010ffH ;turn on rts with function 16 call grdfnc mov ax,100 call pcwait mov ax,011ffH ;turn on dtr with function 17 call grdfnc jmp serhng1 serhngm: ;hang up modem mov ah,ginit call grdfnc ;hangup and initialize modem mov ax,500 call pcwait ;let relay settle down mov prevport,86 ;fake so serini will initialize call serini ;this reinitialzes modem serhng1:mov ax,300 ;wait to let things settle call pcwait mov portbusy,0 ;port is no longer occupied clc ; success ret SERHNG ENDP MODEMSTR PROC NEAR ;send initializing string to modem [jan] cmp flags.comflg,2 ; using modem je modemstr0a ; yes ret ; get out if serial modemstr0a: push ax ;save ax mov ax,200 call pcwait ;delay 200 ms before doing something push es ;save es and di push di push ds pop es ;es now points to our data segment mov di,offset mdmstr ;string to send to modem mov cx,mdmstrlen ;length of the string modemstr0: push cx ;save cx cmp byte ptr es:[di],',' ;delay 0.5 second on comma jne modemstr2 mov ax,500 ;delay for the comma call pcwait jmp modemstr3 ;onto next character modemstr2: mov ax,50 ;send out port call pcwait ;50 ms between characters mov cx,1 ;1 byte at a time mov ah,2 ;grid write call call grdfnc ;write it to modem modemstr3: inc di ;point to next byte pop cx ;get the count loop modemstr0 ;do the next byte if cx<>0 pop di ;restore di and es pop es pop ax ret MODEMSTR ENDP ; Wait for the # of milliseconds in ax, for non-IBM compatibles. ; Based on 4.77 Mhz 8088 processor speeds. ; 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. POSCUR PROC NEAR push ax ; save regs push dx push es push di mov ax,ds mov es,ax ; address data segment!!! cld mov di,offset colno mov al,dh ; row inc al ; adjust offset from 1 instead of 0 mov ah,0 ; zero up half of reg containing number call nout mov al,';' stosb mov al,dl ; column inc al ; adjust offset from 1 instead of 0 mov ah,0 ; zero up half of reg containing number call nout mov al,'H' stosb mov al,'$' stosb mov dx,offset movcur mov ah,prstr int dos ; print the sequence pop di pop es pop dx pop ax ret POSCUR ENDP ; put the number in ax into the buffer pointed to by di. Di is updated nout proc near push dx ; save registers push bx push ax cld mov dx,0 ; high order is always 0 mov bx,10 div bx ; divide to get digit push dx ; save remainder digit or ax,ax ; test quotient jz nout1 ; zero, no more of number call nout ; else call for rest of number nout1: pop ax ; get digit back add al,'0' ; make printable stosb ; drop it off pop ax ; restore all registers pop bx pop dx ret nout endp ; Write a line in inverse video at the bottom of the screen... ; the line is passed in dx, terminated by a $. Returns normally. putmod proc near push dx ; preserve message mov dx,26 * 100H ; line 26 call poscur mov dx,offset invseq ; put into inverse video mov ah,prstr int dos pop dx int dos mov dx,offset nrmseq ; normal videw int dos ret ; and return putmod endp ; Clear the mode line written by putmod. Returns normally. clrmod proc near mov dx,26 * 100H call poscur call clearl ret clrmod endp ; Put a help message one the screen in reverse video. Pass ; the message in AX, terminated by a null. Returns normally. ; The message is put wherever the cursor currently is located. puthlp proc near push ax mov ah,prstr ; Leave some room before the message mov dx,offset crlf int dos pop si ; Put message address here 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 cmp al,0 ; Terminated with a null je puth2 mov dl,al mov ah,conout int dos cmp al,lf ; Line feed? je puth0 ; Yes, clear the next line jmp puth1 ; Else, just keep on writing puth2: mov dx,offset crlf mov ah,prstr int dos mov dx,offset nrmseq ; Normal video int dos clc ret puthlp endp ; Perform a delete. DODEL PROC NEAR push ax push dx mov ah,prstr mov dx,offset delstr ; Erase character int dos pop dx pop ax ret DODEL ENDP ; Perform a Control-U. CTLU PROC NEAR push ax push dx mov ah,prstr mov dx,offset clrlin int dos pop dx pop ax ret CTLU ENDP ;; set the current port COMS PROC NEAR mov dx,offset comptab xor bx,bx ; help is the table itself mov ah,cmkey call comnd jnc coms00 ret ; get out if error coms00: push bx mov ah,cmcfm call comnd ; Get a confirm. jc comx ; carry set = failure pop bx mov flags.comflg,bl ; Set the comm port flag cmp flags.comflg,1 ; Using Com 1? jne coms0 ; ne = no mov portval,offset port1 clc ; carry clear for success ret coms0: mov portval,offset port2 clc ; carry clear for success ret comx: pop bx stc ; carry set for failure ret COMS ENDP ; Set heath emulation on/off. VTS PROC NEAR mov dx,offset termtb mov bx,0 mov ah,cmkey call comnd jnc vts0 ret ; get out if error vts0: push bx mov ah,cmcfm call comnd ; Get a confirm jc vt0 ; carry => didn't get a confirm pop bx cmp bl,ttbig ; using big screen? jne vt1 ;ne means its not big mov bigscreen,1 ; so we know screen is big mov screenbyte, bl ; for status mov scnwrds, 256*32 ; words in big screen mov tekflg,0 ; tek needs reinitialization clc ret vt1: cmp bl,ttsmall ;ne means its not small jne vt1a mov tekflg,0 ; tek needs reinitialization mov scnwrds, 240*20 ;words in small screen mov bigscreen,0 ;screen is not big, i.e. it's small mov screenbyte, bl ; for status clc ret vt1a: cmp bl,tekonnum ; enable tek? jne vt1b ; ne = no, don't enable and denyflg,not tekxflg ; clear tekx bit mov tekbyte,bl ; for status display clc ret vt1b: cmp bl,tekoffnum ; disable tek jne vt2 ; ne => don't disable or denyflg,tekxflg ; set tek deny bit mov tekbyte,bl ; for status display clc ret vt2: mov flags.vtflg,bl ; Set the Tektronix emulation flag [jan] mov tekflg,0 ; need to re-initialize tek emulator [jan] clc ; carry clear for success vt3: ret vt0: pop bx stc ; carry set for 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 termtog proc near ; toggle terminal type [jan] call savescr ; save present screen xor flags.vtflg,tttek ;toggle terminal type mov tekflg,0 ; we need to re-initialize tek emulator call restscr ; restore the previous screen clc ; do not exit Connect mode [jrd] ret 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 cmblnk ; blank for good measure [jan] 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 ; 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 ; [jrd] clc ret DUMPSCR ENDP ; show the definition of a key. The terminal argument block (which contains ; the address and length of the definition tables) is passed in ax. ; Returns a string to print in AX, length of same in CX. ; Returns normally. showkey proc near ret ; and return showkey endp ; Common initialization for using serial port. SERINI PROC NEAR mov portbusy,2 ;port is occupied-don't check flow mov clkdelay,0 ; restart flow check clock push es cmp portin,0 ; Did we initialize interrupt already? je serin0 ; No, skip exit jmp serin1 ; Yes, so just leave serin0: cli ; Disable interrupts cld ; Do increments in string operations xor ax,ax ;ax=0 mov es,ax ;es=0 mov bx,CLK_INT ;clock vector mov ax,es:[bx] ;get offset mov savclko,ax ;save clock int offset mov ax,es:[bx+2] ;get segment mov savclks,ax ;save clock int segment mov ax,offset serint mov es:[bx],ax ; and load with offset of serint mov ax,cs mov es:[bx+2],ax ; and load with code segement address ;clk vector now reset mov portin,1 ; Remember interrupt has been initialized sti ; turn interrupts back on serin1: call getbaud ; get existing baud rate call dobaud ; and reset it push bx mov bx,portval ; get port mov parmsk,0ffh ; parity mask, assume parity is None cmp [bx].parflg,parnon ; is it None? je serin2 ; e = yes mov parmsk,07fh ; no, pass lower 7 bits as data serin2: mov bx,[bx].flowc ; get flow control chars mov flowoff,bl ; xoff or null mov flowon,bh ; xon or null pop bx mov ah,flags.comflg ;get new com port cmp ah,prevport ;port changed? je serin3 ;no change so don't reinitialize mov prevport,ah ;remember we have changed xor ax,ax mov ah,gspar ; parity = none call grdfnc mov al,1 ; stopbit = 1 mov ah,gssbit call grdfnc mov al,8 ; data bits = 8 mov ah,gsdata call grdfnc mov dx,1 ; timeout on char read wait = 1ms mov ah,gcharto call grdfnc call modemstr ; init modem if on cmp flags.comflg,1 ; Using Com 1? jne skipcts ; Nope. mov dx,0 ; timeout on cts = 0 mov ah,gcts call grdfnc skipcts:mov ax,ds ; point to large buffer mov es,ax mov di,offset gbuffer mov cx,gbuflen mov ah,gbufass call grdfnc mov ah,gflush ; flush grid input buffer call grdfnc ;; call clrbuf ; Clear input buffer serin3: pop es mov portbusy,0 ;now able to do flow checking clc ; carry clear for success ret SERINI ENDP SERRST PROC NEAR ; reset the clock interrupt vector cmp portin,0 ; Did we initialize interrupt already? je serrst0 ; No, skip resetting clock vector cli ; Disable interrupts push es ; restore vector of clock tick int at 1CH xor ax,ax ; point to segment part of vector mov es,ax ; es=0 mov bx,CLK_INT ; clock interrupt =1ch*4 mov ax,savclko ; replace with original value mov es:[bx],ax ; restore offset mov ax,savclks mov es:[bx+2],ax ; restore segment pop es ; and clean up stack mov portin,0 ; Remember interrupt has been reset. sti ; turn interrupts back on serrst0: ret ; All done SERRST ENDP ; Comm port interrupt service routine to prevent grid buffer overflow ; Calls flowchek which sends Xoff if necessary if activated ;flow control is checked every 4 clock ticks, about 80 ms ; Modified by [jan] with helpful suggestions from [jrd] SERINT PROC FAR push ax ;all registers must be saved by SERINT push ds ;here, we put some words on the stack mov ax,data ;first we let the clock interrupt get called mov ds,ax ;then (maybe) come back to check flow control pop save_ds ;save ds pop save_ax ;save ax pushf ;save since they're changed by and instr. inc clkdelay ;just do flow control check mov ax,clkdelay ;once each 4 ticks of the clock and ax,3 ;for improved performance jnz serint0 ;nz means don't check this tick popf pushf ;restore flags and return to stack mov ax,cs ;put segment of return address on stack push ax ;clock will return here mov ax,offset serint1 ;offset of return address push ax ;is placed on stack pushf ;this will come off serint0:popf ;remove extra flags from stack mov ax,savclks ;put address of clock routine push ax ;on top of stack mov ax,savclko push ax mov ax,save_ax ;restore ax and ds mov ds,save_ds ret ;go to the clock routine ;we come back at serint1 ;once each 4 ticks ;;Clock interrupt returns here if (clkdelay and 3)=0 serint1: ;; entry point after clock routine push ax push bx push cx push dx push ds mov ax,data mov ds,ax mov serclk,true ;check out flow control at least once/4 tick cmp insrvc,true ; are we already doing interrupt service? je retint ; yes, then skip service until this one done mov insrvc,true ; nope, set in service flag cmp portbusy,0 ;is serial port available? jne serint5 ;don't stack calls ;grdfnc is non-reentrant sti ; flag set enable interrupts call flowchek ;do flow control checking mov serclk,false ;don't check until next tick serint5: mov insrvc,false ; set in service flag to false retint: pop ds pop dx pop cx pop bx pop ax iret ;iret since we have to remove flags SERINT ENDP ; Generate a short beep. BEEP PROC NEAR mov dl,bell mov ah,conout int dos ret BEEP ENDP ;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 the 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 call beep 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 ; 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:cmp repflg,0 ; replaying? je outtty2 ; e=> no replay ; mov ah,conout ; dostty screen mode ; mov dl,al ; write without intervention. ; int dos ; else let dos display char ; ret ; get out outtty2: 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 ; capture flag on? 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: call charout ;tell grid bios to write character[jan] ; 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 also... outprt proc near ; test flags,lclecho ; echoing? test ourarg.flgs,lclecho ; echoing? jz outpr1 ; 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 nop nop nop ; skip returns 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 ; nc => character at port portc0: clc ; no carry -> no character ret ; and return portc1: and al,parmsk ; apply 8/7 bit parity mask stc ; have a character ret ; and return portchr endp argini proc near ; read passed arguments mov bx,argadr ; base of argument block mov ax,[bx].captr mov captrtn,ax ; buffer capture routine mov parmsk,0ffh ; parity mask, assume parity = None cmp [bx].parity,parnon ; is parity None? je argin2 ; e = yes, keep all 8 bits mov parmsk,07fh ; else keep lower 7 bits argin2: call serini ; initialize port if necessary ret ; that's it argini endp getflgs proc near mov al,ourarg.flgs ;supply flags for msggri [jan] ret getflgs endp term proc near mov argadr,ax ; save argument ptr push es mov si,ax ; this is source mov di,offset ourarg ; place to store arguments push ds pop es ; address destination segment mov cx,size termarg cld rep movsb ; copy into our arg blk pop es call argini ; init options from arg address cmp curini,0 ; have we been in here before[gaw@prc] je term1 ; if not skip restoring cursor[gaw@prc] call restscr ; restore screen term1: cmp prtrdy,false ; ready to read port je term5 ; get out call portchr ; read char from serial port jnc term3 ; nc = no char, go on cmp flags.vtflg,tttek ; doing tek emulation? je term1a ; e=yes, already doing tek call stringchek ; ESC FF will turn on tek [jan] jnc term3 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] call keybd ; call keyboard xlator, send results jnc term1 ; nc = stay in Connect mode term5: ; [gaw@prc] call savescr ; save screen [gaw@prc] cmp prtrdy,true ; need to set kbdflg if wierd exit je term6 mov kbdflg,'C' ; so we exit connect mode mov prtrdy,true term6: ret term 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 clc 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 getkey proc near ; wait for a key to be typed mov ah,7 int dos ret getkey endp savescr proc near push es ; move ds base address to es push di push ax push dx xor ax,ax mov di,maxscnwrds*2 ;tek page by default cmp flags.vtflg,tttek je savsc1 mov di,0 ;point to 1st page for text mov ah,prstr ; send '[s' to ansi.sys[gaw@prc] mov dx,offset cursav ; [gaw@prc] int dos ; [gaw@prc] mov byte ptr curini,1 ; now we've saved the cursor[gaw@prc] mov dx,offset curoff ; turn off cursor mov ah,prstr int dos savsc1: mov ax,scrsavseg mov es,ax ;es points to screen save segment mov si,scnstrt ; point to screen memory area mov cx,scnwrds ; setup word count push ds xor ax,ax ; point to base page with ds mov ds,ax cld rep movsw ; transfer image to save area pop ds ; restore registers and return mov dx,offset curon ; turn on cursor mov ah,prstr int dos pop dx pop ax pop di pop es ret savescr endp restscr proc near mov dx,offset curoff ; turn off cursor mov ah,prstr int dos mov dx,offset blank ; clear screen to get rid of cursor mov ah,prstr int dos push es ; point to base page with es xor ax,ax ; restore screen mov es,ax xor ax,ax mov si,ax ;si=0 by default cmp flags.vtflg,tttek jne ressc1 ;ne means not tek mov si,maxscnwrds*2 ;point to second page if tek ressc1: mov di,scnstrt ; point to screen memory area mov cx,scnwrds ; setup word count mov ax,scrsavseg push ds mov ds,ax ;ds points to screen save area cld rep movsw ; transfer image to screen pop ds pop es cmp flags.vtflg,0 ; are we in emulation mode[gaw@prc] jne ressc2 ; to skip restoring cursor[gaw@prc] mov ah,prstr ; send '[u' to ansi.sys[gaw@prc] mov dx,offset curres ; [gaw@prc] int dos ; [gaw@prc] mov dx,offset curon ; turn on cursor mov ah,prstr int dos ressc2: ret restscr endp ; msu calls this to send keystroke in al 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 ; tell kermit we resume logging mov bx, offset argadr or [bx].flgs, capt pop bx klogn: clc ret klogon endp klogof proc near ; suspend logging (if any) and ourarg.flgs, not capt push bx mov bx, offset argadr and [bx].flgs, not capt ; turn off kermit's 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 code ends end