name msxgri ; File MSXGRI.ASM ; Last modification: 20 April 1986 ; Grid Compass II support for MS-DOS Kermit 2.26 ; ; 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] page ,132 public serini, serrst, clrbuf, outchr, coms, vts, vtstat, dodel, ctlu public cmblnk, locate, prtchr, dobaud, clearl, lclini public dodisk, getbaud, beep, setkhlp, setktab public machnam, xofsnt, count, term, poscur public clrmod, putmod, puthlp, sendbr, showkey public ihosts, ihostr, dtrlow, dumpscr ; [jrd] include mssdef.h ; (new name, changed from msdefs.h for 2.28) false equ 0 true equ 1 gbuflen equ 10000 ; max bytes grid internal buffer holds mntrgh equ gbuflen*1/2 ; High point = 1/2 of buffer full. 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 gbrk equ 14 ; function 14 - break control gcts equ 19 ; function 19 - clear to send timeout gbrkon equ gbrk*100H+00H ; function 14 - set break on gbrkoff equ gbrk*100H+0ffH ; function 14 - set break off scnstrt equ 400h ; starting address of screen area (page 0) scnwrds equ 4800 ; number of words in screen memory area datas segment public 'datas' extrn drives:byte, flags:byte, trans:byte extrn portval:word, port1:byte, port2:byte, dmpname:byte ; [jrd] machnam db 'GRID COMPASS II version A' curini db 0 ; [gaw@prc] cursav db esc,'[s','$' ; [gaw@prc] curres db esc,'[u','$' ; [gaw@prc] curon db esc,'[3;3z','$' ; [gaw@prc] curoff db esc,'[3;4z','$' ; [gaw@prc] scrsav dw scnwrds DUP(?) erms20 db cr,lf,'?Warning: System has no disk drives$' ; [21a] 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,'$' ; [jrd] 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,'$' ; [jrd] rdbuf db 80 dup (?) ; temp buf [jrd] noimp db cr,lf,'?Not implemented.$' ; [jrd] delstr db BS,' ',BS,'$' ; Delete string. [21d] clrlin db cr,esc,'[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 0 ; Say if in service on XON/XOFF interrupt invseq db esc,'[7m$' ; Reverse video. nrmseq db esc,'[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$' atemsg db 'ATE1',cr atelen equ (this byte) - atemsg atvmsg db 'ATV1',cr atvlen equ (this byte) - atvmsg argadr dw ? ; address of arg blk uptrn db esc,'A' dntrn db esc,'B' rgtrn db esc,'C' lftrn db esc,'D' ; key redefinitions ktrntab dw ? ; address of translation table krpltab dw ? ; address of replacement table tmptab db 0eh,3bh ; scan code for bs, f1 ktlen dw ? setktab db 12 mkeyw 'BACKSPACE',0eh mkeyw 'F1',3bh mkeyw 'F2',3ch mkeyw 'F3',3dh mkeyw 'F4',3eh mkeyw 'F5',3fh mkeyw 'F6',40h mkeyw 'F7',41h mkeyw 'F8',42h mkeyw 'F9',43h mkeyw 'F10',44h mkeyw 'SCAN',-1 setkhlp db cr,lf,'Keyname: backspace, f1, ... f10, or "SCAN" follwed by ' db 'decimal scan code$' rbtrn db 7fH ; rubout shkbuf db 300 dup (?) ; room for definition shkmsg db ' Scan code: ' shkmln equ $-shkmsg shkms1 db cr,lf,' Definition: ' shkm1ln equ $-shkms1 ontab db 02H ; Two entries. db 03H,'OFF$' ; Should be alphabetized. [19a] dw 00H db 02H,'ON$' dw 01H ; Entries for choosing communications port. [19b] comptab db 04H db 01H,'1$' dw 01H db 01H,'2$' dw 00H db 04H,'COM1$' dw 01H db 04H,'COM2$' dw 00H ; this table is indexed by the baud rate definitions given in ; pcdefs. Unsupported baud rates should contain -1. ; (*) - only two supported on modem bddat label word dw -1 ; 45.5 baud -- Not supported. dw 0 ; 50 baud dw 1 ; 75 baud dw 2 ; 110 baud dw 3 ; 134.5 baud dw 4 ; 150 baud dw 5 ; 300 baud - (*) dw 6 ; 600 baud dw 7 ; 1200 baud - (*) dw 8 ; 1800 baud dw 9 ; 2000 baud dw 10 ; 2400 baud dw 12 ; 4800 baud dw 14 ; 9600 baud dw 15 ; 19200 baud dw -1 ; 38400 baud -- Not supported. ; 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. [16] [17c] clreol db esc,'[0K$' prttab dw com2,com1 com1 db 'COM1',0 com2 db 'COM2',0 blank db esc,'[2J$' movcur db esc,'[' colno db 20 dup (?) ten db 10 prthnd dw 0 tempbuf dw 10 dup(?) ourarg termarg <> datas ends code segment public 'code' extrn comnd:near, dopar:near, prserr:near, defkey:near extrn sleep:near ; [jrd] assume cs:code,ds:datas ; See how many disk drives we have. DODISK PROC NEAR mov ah,gcurdsk ; Current disk value to AL. int dos mov dl,al ; Put current disk in DL. mov ah,seldsk ; Select current disk. int dos ; Get number of drives in AL. mov drives,al ret DODISK ENDP ; Clear the input buffer before sending a packet. [20e] CLRBUF PROC NEAR cli mov ax,offset source mov bufin,ax mov bufout,ax mov count,0 sti clrb1: call prtchr ; get a character jmp clrb1 ; until there aren't any more nop ret CLRBUF ENDP ; Common routine to clear to end-of-line. [19a] CLEARL PROC NEAR mov dx,offset clreol mov ah,prstr int dos ret CLEARL ENDP ; Do a grid function call to the correct com port and return GRDFNC PROC NEAR 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 byte ptr 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 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 byte ptr 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 ret GRDFNC ENDP ; Set the baud rate for the current port, based on the value ; in the portinfo structure. Returns normally. DOBAUD PROC NEAR push ax ; save regs. [jrd] push bx push bp mov bp,portval mov temp1,ax ; Don't overwrite previous rate. [25] mov ax,ds:[bp].baud ; Check if new rate is valid. [25] mov tmp,2 mul tmp ; Get index into baud table. mov bx,offset bddat ; Start of table. add bx,ax mov ax,[bx] ; The data to output to port. cmp ax,0FFH ; Unimplemented baud rate. jne dobd0 dobd01: mov ax,temp1 ; Get back original value. mov ds:[bp].baud,ax ; Leave baud rate as is. mov ah,prstr mov dx,offset badbd ; Give an error message. int dos pop bp ; [jrd] pop bx pop ax ret dobd0: mov temp1,ax ; Remember value to output. [25] cmp flags.comflg,1 ; is it com1? je dobd1 ; yep, skip test for 300/1200 cmp ax,7 ; is it 1200 on com2? je dobd1 ; yep, go do it cmp ax,5 ; is it 300 on com2? je dobd1 ; yep, go do it jmp short dobd01 ; go give unimplemented msg dobd1: mov ah,gsbaud ; set up to set the port baudrate call grdfnc ; do a grid function call to a com port pop bp ; [jrd] pop bx pop ax ret DOBAUD ENDP ; Send a break out the current serial port. Returns normally. sendbr proc near push cx push ax xor cx,cx ; Clear loop counter. mov ax,gbrkon ; setup to do break on [gaw@prc] call grdfnc ; do break on pause: loop pause ; Wait a while. mov ax,gbrkoff ; setup to do break off [gaw@prc] call grdfnc ; do break off pop ax pop cx ret ; And return. sendbr endp outchr: mov bp,portval cmp ds:[bp].floflg,0 ; Are we doing flow control. je outch2 ; No, just continue. xor cx,cx ; clear counter cmp ah,byte ptr [bp].flowc ; sending xoff? [jrd] 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 byte ptr temp,ah ; put character in buffer push cx ; Save register. push di 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 jmp rskp ; This routine blanks the screen. CMBLNK PROC NEAR ; This is stolen from the IBM example. mov ah,prstr mov dx,offset blank int dos ret CMBLNK ENDP LOCATE PROC NEAR mov dx,0 ; Go to top left corner of screen. jmp poscur ; callret... LOCATE ENDP ; 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. [jrd] push bx ; [jrd] push cx ; [jrd] push dx ; [jrd] push bp ; [jrd] 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,offset bddat ; Find rate's offset into table. mov cl,0 ; Keep track of index. getb0: cmp ax,[bx] je getb1 inc cl cmp cl,baudsiz ; At the end of the list. jge getb2 add bx,2 jmp getb0 getb1: mov ch,0 mov bp,portval mov ds:[bp].baud,cx ; Set baud rate. jmp getb3 ; [jrd] ;;;[jrd] ret getb2: mov ah,prstr mov dx,offset erms40 int dos getb3: pop bp ; restore regs. [jrd] pop dx ; [jrd] pop cx ; [jrd] pop bx ; [jrd] pop ax ; [jrd] ret GETBAUD ENDP ; skip returns if no character available at port, ; otherwise returns with char in al, # of chars in buffer in dx. PRTCHR PROC NEAR push bx push cx push si push bp cmp count,0 ; no characters? jne prtch2 ; no, go fill buffer prtch1: push di 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 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 lodsb ; get character mov bufout,si ; update ptr mov bp,portval cmp ds:[bp].parflg,PARNON ; no parity? je prtch3 ; then don't strip and al,7fh ; else turn off parity prtch3: pop bp pop si pop cx pop bx ret prtch4: pop bp pop si pop cx pop bx jmp rskp ; no chars... PRTCHR 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 call outchr ; send it (release Host's output queue) nop ; outchr can do skip return nop nop ihosts1:call clrbuf ; clear out interrupt buffer mov ax,1 ; sleep for 1 second call sleep ; procedure sleep is in msscom.asm call prtchr ; check for char at port jmp ihosts1 ; have a char in al, repeat wait/read cycle nop ; prtchr does skip return on empty 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 call outchr ; send it (release Host's output queue) nop ; outchr can do skip return nop nop 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 jmp r ; not yet imp. call serhng ; drop DTR and RTS mov ah,prstr ; give a nice message ; not yet imp. mov dx,offset hngmsg mov dx,offset noimp ; for now int dos jmp rskp 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 is Not Yet Implemented. ; Position the cursor according to contents of DX. POSCUR PROC NEAR push ax ; save regs. [jrd] 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 ; [jrd] 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 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 ; and return nout endp ;NOUT PROC NEAR ; cbw ; extend to word ; div byte ptr ten ; divide by 10 ; or al,al ; any quotient? ; jz nout1 ; no, forget this ; push ax ; save current result ; call nout ; output high order ; pop ax ; restore ;nout1: mov al,ah ; get digit ; add al,'0' ; make printable ; stosb ; ret ; put in buffer and return ;NOUT endp ; 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 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 ret puthlp endp ; Perform a delete. DODEL PROC NEAR mov ah,prstr mov dx,offset delstr ; Erase weird character. int dos ret DODEL ENDP ; Perform a Control-U. CTLU PROC NEAR mov ah,prstr mov dx,offset clrlin int dos ret CTLU ENDP COMS PROC NEAR mov dx,offset comptab mov bx,offset comphlp mov ah,cmkey call comnd jmp r push bx mov ah,cmcfm call comnd ; Get a confirm. jmp comx ; Didn't get a confirm. nop pop bx mov flags.comflg,bl ; Set the comm port flag. cmp flags.comflg,1 ; Using Com 1? jne coms0 ; Nope. mov ax,offset port1 mov portval,ax ret coms0: mov ax,offset port2 mov portval,ax ret comx: pop bx ret COMS ENDP ; Set heath emulation on/off. VTS PROC NEAR mov dx,offset ontab mov bx,0 mov ah,cmkey call comnd jmp r push bx mov ah,cmcfm call comnd ; Get a confirm. jmp vt0 ; Didn't get a confirm. nop pop bx mov flags.vtflg,bl ; Set the VT52 emulation flag. ret vt0: pop bx ret VTS ENDP VTSTAT PROC NEAR ; For Status display [jrd] 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 ; [jrd] ret DUMPSCR ENDP ; local initialization lclini proc near mov flags.vtflg,0 ; turn off terminal emulation [gaw@prc] mov ax,0eH ; scan code for arrow key mov si,offset rbtrn ; translate to rubout mov cx,1 ; one char translation call defkey ret lclini 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 push es push ax ; save the ptr mov bx,ds mov es,bx ; address data segment cld showk1: mov dl,0ffh ; wait for input but don't echo mov ah,coninq int dos or al,al ; extended code? mov ah,0 jnz noalt ; no, skip getting 2nd char mov dl,0ffh ; get 2nd char mov ah,coninq int dos mov ah,08h ; fake, alt key in ah ; xor ah,ah ; call prtchr ; read a char ; nop ; nop ; nop ; or ax,ax ; get one? ; jz showk1 ; nope, wait ; push ax ; save the character ; call gss ; get shift state ; pop bx ; mov ah,al ; shift state to ah ; mov al,bh ; scan code to al noalt: push ax ; remember scan code mov di,offset shkbuf mov si,offset shkmsg mov cx,shkmln rep movsb ; copy in initial message call nout ; write out scan code mov si,offset shkms1 mov cx,shkm1ln ; second message rep movsb pop ax ; get scan code back pop bx ; and terminal arg block mov cx,[bx].klen ; and length jcxz showk2 ; no table, not defined push di ; remember output ptr mov di,[bx].ktab ; get key table repne scasw ; search for a definition for this mov si,di ; remember result ptr pop di ; get output ptr back jne showk2 ; not defined, forget it sub si,[bx].ktab ; compute offset from beginning sub si,2 ; minus 2 for pre-increment add si,[bx].krpl ; get index into replacement table mov si,[si] ; pick up replacement mov cl,[si] ; get length mov ch,0 inc si rep movsb ; copy into buffer showk2: mov ax,offset shkbuf ; this is buffer mov cx,di sub cx,ax ; length pop es ret ; and return showkey endp ; Common initialization for using serial port. SERINI PROC NEAR push es cmp portin,0 ; Did we initialize interrupt already? je serin0 ; No, skip exit jmp serin1 ; Yes, so just leave. [21c] serin0: cli ; Disable interrupts cld ; Do increments in string operations xor ax,ax ; get vector of clock tick int at 1CH mov es,ax mov bx,1Ch*4 mov ax,es:[bx] mov cs:savclko,ax add bx,2 mov ax,es:[bx] mov cs:savclks,ax ;-> all because cli doesn't disable clock tick interrupt! push es ; save pointer to segment part of vector push bx mov es,ax ; point to location with offset replaced mov bx,offset serint mov cl,es:[bx] ; save value in cl mov al,0CFh ; load al with IRET instruction mov es:[bx],al ; put at location with offset replace pop bx pop es sub bx,2 ; now point to offset part of vector mov ax,offset serint mov es:[bx],ax ; and load with offset of serint add bx,2 ; now point to segment part of vector mov ax,cs mov es:[bx],ax ; and load with code segement address mov ax,cs:savclks ; now restore byte at offset of serint mov es,ax mov bx,offset serint mov es:[bx],cl ;<- ; mov ax,cs ; set vector at 1CH to point to serint ; mov es:[bx],ax ; sub bx,2 ; mov ax,offset serint ; mov es:[bx],ax mov portin,1 ; Remember interrupt has been initialize. sti ; turn interrupts back on ; mov ah,ginit ; reset serial port to default values ; call grdfnc call dobaud ; reset baud just incase modem hung up 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 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 ;; cmp flags.comflg,1 ; Using Com 1? ;; je skipcmd ; Yep, skip commands to modem ;; ;; push di ;; ;; lea di,atemsg ; send an ATE=1 ;; mov cx,atelen ;; mov ah,gwrite ;; call grdfnc ;; ;; lea di,atvmsg ; send an ATV=1 ;; mov cx,atvlen ;; mov ah,gwrite ;; call grdfnc ;; ;; pop di ;; ;;skipcmd: call clrbuf ; Clear input buffer. [20e] serin1: pop es ret ; We're done. SERINI ENDP SERRST PROC NEAR ; mov ah,ginit ; reset serial port to default values ; call grdfnc cmp portin,0 ; Did we initialize interrupt already? je serrst0 ; No, skip resetting clock vector cli ; Disable interrupts ;-> all because cli doesn't disable clock tick interrupt! push es ; restore vector of clock tick int at 1CH mov ax,cs:savclks ; get pointer to location when segment replaced mov es,ax mov bx,offset serint mov cl,es:[bx] ; save value from there in cl mov al,0CFh ; load location with IRET mov es:[bx],al push es ; save segment pointer for later push bx xor ax,ax ; point to segment part of vector mov es,ax mov bx,(1Ch*4)+2 mov ax,cs:savclks ; replace with original value mov es:[bx],ax sub bx,2 ; now replace offset with original value mov ax,cs:savclko mov es:[bx],ax pop bx ; now restore location holding temporary IRET pop es mov es:[bx],cl pop es ; and clean up stack ;<- ; push es ; restore vector of clock tick int at 1CH ; xor ax,ax ; mov es,ax ; mov bx,1Ch*4 ; mov ax,cs:savclko ; mov es:[bx],ax ; add bx,2 ; mov ax,cs:savclks ; mov es:[bx],ax ; pop es mov portin,0 ; Remember interrupt has been reset. sti ; turn interrupts back on serrst0: ret ; All done. [21c] SERRST ENDP ; Comm port interrupt service routine to prevent grid buffer overflow ; sends Xoff if necessary if activated ; SERINT PROC NEAR push ax push bx push cx push dx push ds push es push si push di push bp pushf cld mov ax,seg datas mov ds,ax ; address data segment mov es,ax mov bp,portval cmp ds:[bp].floflg,0 ; Doing flow control? je retint ; No, just leave. jmp retint ; <<===<< temporary stub until grid problem resolved 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 sti ; flag set enable interrupts mov ah,grstat ; get the buffer count call grdfnc cmp xofsnt,true ; Have we sent an XOFF? je serint1 ; Yes. cmp cx,mntrgh ; Past the high trigger point? jbe intdone ; No, we're within our limit. mov ah,XOFF ; Get the XOFF. 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 ; call outchr ; Send it. ; nop ; nop ; nop ; ignore failure. mov xofsnt,true ; Remember we sent it. jmp intdone serint1: cmp cx,mntrgh ; below the high trigger point? ja intdone ; no, don't send XON mov ah,XON ; get the XON 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 ; call outchr ; send it ; nop ; ignore failure ; nop ; nop mov xofsnt,false ; remember we sent it intdone: mov insrvc,false ; set in service flag to false retint: sti popf pop bp pop di pop si pop es pop ds pop dx pop cx pop bx pop ax jmp dword ptr cs:savclko savclko dw ? ; save clock tick interrupt vector offset savclks dw ? ; save clock tick interrupt vector segment SERINT ENDP ; Generate a short beep. BEEP PROC NEAR mov dl,bell mov ah,conout int dos ret BEEP ENDP ; Jumping to this location is like retskp. It assumes the instruction ; after the call is a jmp addr. RSKP PROC NEAR pop bp add bp,3 push bp ret RSKP ENDP ; Jumping here is the same as a ret. R PROC NEAR ret R ENDP ; send the character in al out to the serial port ; handle echoing also... outprt proc near test flags,lclecho ; echoing? jz outpr1 ; no, forget it push ax ; save char mov dl,al and dl,7fh ; mask off parity for terminal mov ah,dconio int dos ; write out the character 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 argini proc near ; read passed arguments mov bx,argadr ; base of argument block mov al,[bx].flgs ; get flags and al,capt+emheath+havtt+trnctl+lclecho ; +modoff mov flags,al ; mask for allowable and save ; and flags1,not (prtscr) ; these are allowable ; (others remain). mov al,[bx].prt ; cmp al,portno ; using same port? ; je argin1 ; yes, go on ; and flags1,not inited ; else re-init stuff argin1: ; mov portno,al ; update port number ; mov ax,[bx].captr ; mov captrtn,ax ; buffer capture routine ; mov ax,[bx].belld ; mov beldiv,ax ; bell divisor mov ax,[bx].klen mov ktlen,ax ; length of key redef tbl mov ax,[bx].ktab mov ktrntab,ax ; save key translation table mov ax,[bx].krpl mov krpltab,ax ; mov al,[bx].escc ; mov esc_ch,al ret ; that's it argini endp term proc near push ax push es mov si,ax ; this is source mov di,offset ourarg ; place to store arguments mov ax,ds mov es,ax ; address destination segment mov cx,size termarg rep movsb ; copy into our arg blk pop es pop ax mov argadr,ax ; save argument ptr push es ; save caller's extra segment address mov ax,seg datas mov es,ax 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 cmp flags.vtflg,0 ; are we in emulation mode[gaw@prc] jne term1 ; if we are 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] term1: call prtchr jmp short term2 ; have a char... nop nop jmp short term3 ; no char, go on term2: push ax mov dl,al and dl,7fh ; mask off parity for terminal mov ah,dconio int dos ; write out the character pop ax test ourarg.flgs,capt ; capturing output? jz term3 ; no, forget it call ourarg.captr ; else call the routine term3: mov ah,dconio mov dl,0ffh int dos jz term1 ; no character, go on cmp al,ourarg.escc ; escape char? je term4 ; yes, exit or al,al ; extended code? mov bl,0 jnz no2nd ; no, skip getting 2nd char mov dl,0ffh ; get 2nd char mov ah,coninq int dos mov ah,al ; duplicate char in ah for "call turnout" mov bl,08h ; fake, alt key in bl for "call turnout" no2nd: call trnout ; translate if necessary ; push ax ; save char ; mov ah,al ;; or ah,80H ; ?? turn on hi bit so DOS doesn't interfere ; call outchr ; output the character ; nop ; nop ; nop ; pop ax ; test ourarg.flgs,lclecho ; echoing? ; jz term1 ; no, continue loop ; ; mov dl,al ; mov ah,dconio ; int dos jmp term1 ; else echo and keep going term4: cmp flags.vtflg,0 ; are we in emulation mode[gaw@prc] jne term5 ; if we are skip saving cursor[gaw@prc] 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] term5: ; [gaw@prc] call savescr ; save screen [gaw@prc] mov al,flags mov bx,argadr mov [bx].flgs,al ; update flags in arg block pop es ; restore segment register ret ; and return to caller term endp savescr proc near push es ; move ds base address to es push ds pop es mov di,offset scrsav ; point to start of screen save area push ds xor ax,ax ; point to base page with ds mov ds,ax mov si,scnstrt ; point to screen memory area mov cx,scnwrds ; setup word count rep movsw ; transfer image to save area pop ds ; restore registers and return pop es ret savescr endp restscr proc near push es ; point to base page with es mov dx,offset curoff ; turn cursor off mov ah,prstr int dos mov dx,offset blank ; clear screen to get rid of cursor mov ah,prstr int dos xor ax,ax ; restore screen mov es,ax mov di,scnstrt ; point to screen memory area mov si,offset scrsav ; point to start of screen save area mov cx,scnwrds ; setup word count rep movsw ; transfer image to screen mov dx,offset curon ; turn cursor back on mov ah,prstr int dos pop es ; restore register and return ret restscr endp ; translate the scan code in ah according to the translate table ; given in ktrntab/krpltab, output to port. If no translation, ; use ascii char in al. (should probably include shift state ; somewhere). Shift state is in bl. trnout proc near ; cmp ah,4eh ;*** plus key thing? ; je trnmod ; yes, go toggle mode line trnou1: test flags,havtt ; translate table given? jz trnou3 ; no, just output character push ax ; save original value mov al,ah ; put scan code into ah mov ah,bl ; shift state into top half. mov di,ktrntab ; pick up translate tbl mov cx,ktlen ; length of tbl repne scasw ; look for our key pop ax ; recover character jne trnou3 ; not found, forget it sub di,ktrntab ; get index into tbl sub di,2 ; (minus 2 for pre-increment) mov bx,krpltab ; get replacement table mov si,[bx][di] ; and addr of replacement mov cl,[si] ; get first byte (length) xor ch,ch ; clear high-order byte inc si ; point to translation string trnou2: lodsb ; get a byte push si push cx ; save important registers call outprt ; send to port pop cx pop si loop trnou2 ; send all chars ret ; and return trnou3: ; cmp al,0 ; is it a special code? ; jne trnou4 ; no, don't do this ; mov al,ah ; get scan code ; mov cx,lckeys ; length of table ; mov di,offset ckeys ; table address ; repne scasb ; mov al,0 ; ascii code was 0... ; jne trnou4 ; not found, keep going ; sub di,offset ckeys+1 ; get table offset ; shl di,1 ; shift for word offset ; jmp ckacts[di] ; jump to appropriate routine ;trnou4: call outprt ; just output single char ret ; and return ;trnmod: test flags,modoff ; mode line already off? ; jnz trnm1 ; yes, go turn on ; call clrmod ; no, clear mode line here ; or flags,modoff ; turn on flag ; ret ; and return ;trnm1: call modlin ; turn on mode line ; and flags,not modoff ; clear flag ; ret ; and return ; ;trnbrk: mov ah,dconio ; mov dl,0ffH ; int dos ; read the bogus ^C DOS gets. ; call sendbr ; ret ;trnprs: xor flags1,prtscr ; flip the flag ; and flags,not modoff ; turn on mode line ; mov si,offset prton ; mov cx,prtnlen ; test flags1,prtscr ; did it go on? ; jnz trnpr1 ; yes, say so ; mov si,offset prtoff ; mov cx,prtflen ;trnpr1: call modwrt ; write into mode line ; ret ; and return ; common entry for arrow keys trnarr: mov cx,2 ; length is always 2 jmp trnou2 ; go send definition trnupw: mov si,offset uptrn jmp trnarr trndnw: mov si,offset dntrn jmp trnarr trnlfw: mov si,offset lftrn jmp trnarr trnrgw: mov si,offset rgtrn jmp trnarr trnout endp code ends end