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 ; tell keyboard for status stent ; 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 port2 prtinfo port3 prtinfo 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