page 80,132 public serini, serrst, clrbuf, outchr, coms, vts, dodel, public ctlu, cmblnk, locate, lclini, prtchr, dobaud, clearl, public dodisk, getbaud, beep public count, xofsnt, puthlp, putmod, clrmod, poscur public sendbr, term, machnam, setktab, setkhlp, showkey include msdefs.h false equ 0 true equ 1 instat equ 6 rddev equ 3fH open equ 3dH close equ 3eH ; external variables used: ; drives - # of disk drives on system ; flags - global flags as per flginfo structure defined in pcdefs ; trans - global transmission parameters, trinfo struct defined in pcdefs ; portval - pointer to current portinfo structure (currently either port1 ; or port2) ; port1, port2 - portinfo structures for the corresponding ports ; global variables defined in this module: ; xofsnt, xofrcv - tell whether we saw or sent an xoff. datas segment public 'datas' extrn drives:byte,flags:byte, trans:byte extrn portval:word, port1:byte, port2:byte machnam db 'HP-110$' erms20 db cr,lf,'?Warning: System has no disk drives$' ; [21a] erms40 db cam db 'HP-110$' erms20 db cr,lf,'?Warning: System has no disk drives$' ; [21a] 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$' badbd db cr,lf,'Unimplemented baud rate$' badpar db cr,lf,'Unimplemented parity$' noimp db cr,lf,'Command not implemented.$' shkmsg db 'Not implemented.' shklen equ $-shkmsg baudstr db 'SB' ; string used in setting baud rate baudx db 0,';' par_str db 'P' ; string used to set parity par_x db 0,';' brk_on db 'B1;' ; start sending breaks brk_off db 'B0;' ; stop sending breaks chk_msg db 0BFH,';' ; check serial buffer ini_msg db 'M1;C2;LI1;' ; serial port, XON/XOFF, DTR on setktab db 0 setkhlp db 0 crlf db cr,lf,'$' delstr db BS,' ',BS,'$' clrlin db cr,esc,'K$' clreol db esc,'K$' 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 esc,'&dB$' ; Reverse video nrmseq db esc,'&d@$' ; Normal video ivlseq db 80 dup (' '),cr,'$' ; make line inverse video prthnd dw 0 ; Port handle. tempbuf dw 10 dup(?) prttab dw com2,com1 com1 db 'COM1',0 com2 db 'COM2',0 blank db esc,'H',esc,'J$' movcur db esc,'&a' colno db 20 dup(?) ten db 10 tmp db ?,'$' temp dw 0 temp1 dw ? ; Temporary storage. temp2 dw ? ; Temporary storage. rdbuf db 20 dup(?) ; Buffer for input. ; 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 ; variables for serial interupt handler source db bufsiz 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 ourarg termarg <> datas ends code segment public extrn comnd:near, dopar:near, prserr:near, atoi:near, prompt:near assume cs:code,ds:datas ; this is called by Kermit initialization. It checks the ; number of disks on the system, sets the drives variable ; appropriately. Returns normally. 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. 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 cli mov ax,offset source mov bufin,ax mov bufout,ax mov count,0 sti ret CLRBUF ENDP ; Clear to the end of the current line. Returns normally. CLEARL PROC NEAR mov ah,prstr mov dx,offset clreol int dos ret CLEARL ENDP ; Put the char in AH to the serial port. ; Skip returns on ; success, returns normally if the character cannot be written. outchr: mov bp,portval cmp ds:[bp].floflg,0 ; Are we doing flow control. je outch2 ; No, just continue. xor cx,cx ; clear counter 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. push cx push bx cmp prthnd,0 ; do we have a port handle? jne outch3 ; yes, go on push ax call opnprt ; open the port pop ax outch3: mov dl,ah mov ah,punout ; Output char in DL to comm port. int dos pop bx pop cx pop dx jmp rskp ; This routine blanks the screen. Returns normally. CMBLNK PROC NEAR mov ah,prstr mov dx,offset blank int dos 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,0F00h ; now address line 15 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,0F00h 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 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 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 ret puthlp endp ; Set the baud rate for the current port, based on the value ; in the portinfo structure. Returns normally. DOBAUD PROC NEAR mov bx,portval mov dx,[bx].baud ; get baud rate from table cmp dx,0 jb bd_bd cmp dx,10 je bd_bd cmp dx,15 ja bd_bd ; cmp dx,10 jb baud_4 cmp dx,11 jne baud_1 mov dl,'A' jmp baud_5 baud_1: cmp dx,12 jne baud_2 mov dx,'C' jmp baud_5 baud_2: cmp dx,13 jne baud_3 mov dx,'E' jmp baud_5 baud_3: cmp dx,14 jne bd_bd mov dx,'F' jmp baud_5 baud_4: add dl,'0' ; make # printable baud_5: mov baudx,dl ; put into baud rate message mov cx,4 mov dx,offset baudstr ; point to message call w_ioctl ; write to ioctl of serial port ret ; ...and return ; bd_bd: mov ah,prstr mov dx,offset badbd ; Say it's not implemented. int dos mov bx,portval mov [bx].baud,0FFFFH ; So it's not a recognized value. ret ; Must be set before starting Kermit. DOBAUD ENDP DOPARITY PROC NEAR mov bx,portval mov dl,[bx].parflg ; get parity flag cmp dl,0 jne par_1 mov dx,'0' ; even parity jmp par_3 par_1: cmp dx,2 jne par_2 mov dx,'4' ; no parity jmp par_3 par_2: cmp dx,3 jne bd_par mov dx,'1' ; odd parity par_3: mov par_x,dl ; set up string mov dx,offset par_str ; point to string mov cx,3 ; 3 lettters in string call w_ioctl ; ...to serial port ioctl ret bd_par: mov bx,portval mov [bx].parflg,0 mov ah,prstr mov dx,offset badpar int dos ret DOPARITY 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 ; ; write cx bytes to ioctl of serial port ; W_IOCTL PROC NEAR mov ah,ioctl mov al,3 mov bx,prthnd int dos ret W_IOCTL ENDP ; ; read cx bytes from ioctl of serial port to tempbuf ; R_IOCTL PROC NEAR mov ah,ioctl mov al,2 mov bx,prthnd mov dx,offset tempbuf int dos ret R_IOCTL ENDP ; ; check serial port for characters and return number in al ; CHK_BUFF PROC NEAR mov dx,offset chk_msg mov cx,2 call w_ioctl mov cx,1 call r_ioctl mov ax,tempbuf 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 push bx push cx push si push bp cmp count,0 ; any chars in buffer? jne prtch2 ; ...yes, get one cmp prthnd,0 ; got a handle jne prtch1 call opnprt ; open port if not prtch1: call chk_buff ; any chars at port? or al,al jz prtch4 ; no, go to skip return mov ah,0 mov cx,1 mov count,cx mov bx,prthnd mov ah,rddev mov dx,offset source int dos jc prt3x mov bufout,offset source prtch2: dec count mov si,bufout lodsb mov bufout,si 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 prt3x: mov ah,prstr mov dx,offset erms50 int dos prtch4: pop bp pop si pop cx pop bx jmp rskp ; no chars... PRTCHR ENDP ; Send a break out the current serial port. Returns normally. SENDBR PROC NEAR mov dx,offset brk_on mov cx,3 call w_ioctl mov dx,offset brk_off mov cx,3 call w_ioctl ret SENDBR ENDP ; Position the cursor according to contents of DX: ; DH contains row, DL contains column. Returns normally. POSCUR PROC NEAR 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 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 mov ah,prstr mov dx,offset delstr ; Erase weird character. int dos ret DODEL ENDP ; Move the cursor to the left margin, then clear to end of line. ; Returns normally. CTLU PROC NEAR mov ah,prstr mov dx,offset clrlin int dos call clearl ret CTLU ENDP ; Set the current port. COMS PROC NEAR mov dx,offset comptab mov bx,0 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 jmp notimp VTS ENDP notimp: mov ah,prstr mov dx,offset noimp int dos jmp prserr ; Initialize variables to values used by the generic MS DOS version. lclini: mov flags.vtflg,0 ; Don't do terminal emulation. call opnprt ; Get file handle for comm port. mov bx,offset port1 mov [bx].baud,13 ; port1 -> 9600 baud mov [bx].parflg,0 ; even parity mov bx,offset port2 mov [bx].baud,6 ; port2 -> 300 baud mov [bx].parflg,0 ; even parity ret ; 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" or "COM2". opnprt: mov al,flags.comflg mov ah,0 mov si,ax shl si,1 ; double index mov dx,prttab[si] mov ah,open mov al,2 int dos jnc opnpr1 mov ah,prstr ; It didn't like the string. mov dx,offset erms41 int dos ret opnpr1: mov prthnd,ax ; Call succeeded. ret showkey: mov ax,offset shkmsg mov cx,shklen ret ; Initialization for using serial port. Returns normally. SERINI PROC NEAR cld ; Do increments in string operations call opnprt ; open handle call clrbuf ; Clear input buffer. mov dx,offset ini_msg mov cx,10 call w_ioctl call dobaud ; set baud rate call doparity ; set parity ret ; We're done. 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 mov bx,prthnd cmp bx,0 ; none there? je serr_1 ; no, don't try to close mov ah,close int dos ; close handle mov prthnd,0 serr_1: ret ; All done. 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). term proc near 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 term1: call prtchr jmp short term2 ; have a char... nop nop jmp short term3 ; no char, go on term2: push ax and al,7fh ; mask off parity for terminal mov dl,al mov ah,conout int dos ; go print it 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 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: ret term 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 code ends end