; Kermit system dependent module for ACT Apricot
 
        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
control	equ	0FCH			; System Control Device

; 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      'ACT Apricot$'
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$'
badbd   db      cr,lf,'Unimplemented baud rate$'
noimp   db      cr,lf,'Command not implemented.$'
shkmsg  db      'Not implemented.'
shklen  equ     $-shkmsg
setktab db      0
setkhlp db      0
crlf    db      cr,lf,'$'
delstr  db      BS,' ',BS,'$'           ; Delete string.
clrlin  db      cr,esc,'K$'             ; Clear line.
clreol  db      esc,'K$'                ; Clear line.
clrscr  db      esc,'H',esc,'J$'        ; Home and clear screen.
; Use high/low intensity rather than inverse video.
; It is kinder on the eyes....
invseq  db      esc,'($'                ; High intensity mode.
nrmseq  db      esc,')$'                ; Low intensity mode.
telflg  db      0                       ; non-zero if we're a terminal.
xofsnt	db	0			; Say if we sent an XOFF.
count	dw	0			; Number of chars in int buffer.
tmp     db      ?,'$'
temp    dw      0
temp1   dw      ?                       ; Temporary storage.
temp2   dw      ?                       ; Temporary storage.

;  This table is indexed by the baud rate definitions given in msdefs.h.
;  Unsupported baud rates should contain FF.
bddat   label   word
        dw      -1                      ;    45.5  Unsupported
        dw      1                       ;    50
        dw      2                       ;    75
        dw      3                       ;  dw      4                       ;   134.5
        dw      5                       ;   150
        dw      6                       ;   300
        dw600
        dw      8                       ;  1200
        dw      9                       ;  1800
        dw      -1                      ;  2000 ted
        dw      10                      ;  2400
        dw      12                      ;  4800    (Have to skip 3600)
        dw      14                      ;  9600    (Have to skip 7200)
        dw      15                      ; 19200
        dw      -1                          Unsupported

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
	mov	bx,34H			; Serial Device Driver
	mov	cx,2			; Read serial port
clrbf1:	int	control			; call System Control Device
	cmp	ax,-1			; Read anything ?
	jne	clrbf1			; Yes, try again
        ret
CLRBUF  ENDP
 
; Clear to the end of the current line.  Returns normally.
 
CLEARL  PROC    NEAR
        mov     dx,offset clreol
        jmp     tmsg                    ; Send terminal message
CLEARL  ENDP
 
; Put the char in AH to the serial port.  This assumes the
; port has been initialized.  XON/XOFF are handled by the port
; driver.  Skip returns on success, returns normally if the
; character cannot be written.
 
OUTCHR: push bx
        push cx
        push dx                 ; Save register.
        sub cx,cx
        mov al,ah               ; Parity routine works on AL.
        call dopar              ; Set parity appropriately.
        mov dl,al
        mov dh,0
        mov cx,1                ; Transmit char
        mov bx,34H              ; Serial Device Driver
        int control             ; System Control Device
        pop dx
        pop cx
        pop bx
        jmp rskp
 
; This routine blanks the screen.  Returns normally.
 
CMBLNK  PROC    NEAR
        mov     dx,offset clrscr
        jmp     tmsg            ; Send terminal message.
CMBLNK  ENDP
 
; Homes the cursor.  Returns normally.
 
LOCATE  PROC    NEAR
        mov dx,0000H            ; Go to top left corner of screen.
        jmp poscur
LOCATE  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 pointer.
        mov     dx,1700H        ; now address line 24
        call    poscur
        mov     dx,offset invseq ; Use high intensity rather than inverse video
        call    tmsg
        pop     dx              ; get message back
        call    tmsg            ; write it out
        mov     dx,offset nrmseq ; Normal (low) intensity again
        call    tmsg
        ret                     ; and return
PUTMOD  endp
 
; clear the mode line written by putmod.  Returns normally.
CLRMOD  proc    near
        mov     dx,1700H
        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     dx,offset crlf
        call    tmsg
        mov     dx,offset invseq ; High intensity rather than inverse video
        call    tmsg
        pop     si              ; point to string again
puthl3: lodsb                   ; get a byte
        cmp     al,0            ; end of string?
        je      puthl4          ; yes, stop
        mov     dl,al
        mov     ah,dconio
        int     dos             ; else write to screen
        jmp     puthl3          ; and keep going
puthl4: mov     dx,offset nrmseq ; Back to normal (low) intensity video
        call    tmsg
        mov     dx,offset crlf
        call    tmsg
        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     bp,portval
        mov     temp1,ax        ; Save new rate, don't zap old rate yet...
        mov     ax,ds:[bp].baud ; Check if new rate is valid.
        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 the port
        cmp     ax,0FFH         ; Unimplemented baud rate.
        jne     dobd0
        mov     ax,temp1        ; Get back original value.
        mov     ds:[bp].baud,ax ; Leave rate as is.
        mov     dx,offset badbd ; Give an error message.
        call    tmsg
        ret
;
dobd0:  mov     dx,ax
        mov     bx,34H          ; Serial Device Driver
        mov     cx,4            ; Set transmit baud rate
        int     control
        mov     cx,5            ; Set receive baud rate
        int     control
        mov     dx,1            ; Turn on XON/XOFF just in case...
        mov     cx,10           ; Transmit XON/XOFF
        int     control
        mov     cx,11           ; Receive XON/XOFF
        int     control
        mov     cx,3            ; Install changes, zap line, etc...
        ret
DOBAUD  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
        mov     bx,34H          ; Serial Device Driver
        mov     cx,4            ; Transmit baud rate
        mov     dx,-1           ; Fetch data
        int     control         ; Go speak to Control Device Driver
        mov     bx,offset bddat ; -> baud rate 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 ; Save rate index in port structure
        ret
getb2:  mov     dx,offset erms40
        call    tmsg
        ret
GETBAUD 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
        mov bx,34H
        mov cx,2
        int control             ; Read serial port
        cmp ax,-1               ; Character there ?
        jnz prtch1              ; Yes, process it...
        pop bp
        pop si
        pop cx
        pop bx
        jmp rskp                ; No character, skip return.
prtch1: 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
PRTCHR  ENDP
 
; Send a break out to the serial port.  Returns normally.
; Need to handle port directly since ACT's Control Device doesn't
; have a 'send break' facility.
SENDBR  PROC    NEAR
        mov     al,5
        out     62H,al          ; Select SIO write register 5
        mov     al,0FAH
        out     62H,al          ; Start break
        mov     bx,-1
sendb0: dec     bx
        jnz     sendb0
        mov     al,5
        out     62H,al          ; Select SIO write register 5
        mov     al,0EAH
        out     62H,al          ; Finished sending break
        ret
SENDBR  ENDP
 
;  Position the cursor according to contents of DX:
;  DH contains row, DL contains column.  Origin (top left) = 0, 0
;  Returns normally.
POSCUR  PROC    NEAR
        push    dx              ; Save row & column position
        mov     dl,esc          ; Start cursor positioning sequence
        call    tchr
        mov     dl,'Y'
        call    tchr
        pop     dx              ; Retrieve row position
        mov     al,dh
        call    poscr1
        mov     al,dl
poscr1: push    dx
        add     al,' '
        mov     dl,al
        call    tchr
        pop     dx
        ret
POSCUR  ENDP
 
; Delete a character from the terminal.  This works by printing
; backspaces and spaces.  Returns normally.
 
DODEL   PROC    NEAR
        mov dx,offset delstr    ; Erase weird character.
        jmp tmsg
DODEL   ENDP
 
; Move the cursor to the left margin, then clear to end of line.
; Returns normally.
 
CTLU    PROC    NEAR
        mov dx,offset clrlin
        jmp tmsg
CTLU    ENDP
 
; Set the current port.
 
COMS    PROC    NEAR
        jmp     notimp
COMS    ENDP
 
; Set heath emulation on/off.
 
VTS     PROC    NEAR
        jmp     notimp
VTS     ENDP
 
NOTIMP: mov     dx,offset noimp
        call    tmsg
        jmp     prserr
 
; Initialize local variables and communications port.

LCLINI: mov     flags.vtflg,0   ; Don't do terminal emulation.
        mov     bx,34H          ; Control Device Driver
        mov     cx,6            ; Set transmit bits per character
        mov     dx,8            ; to 8-bit bytes
        int     control
        mov     cx,8            ; Set receive bits per character
        mov     dx,7            ; to 8-bit bytes
        int     control
        mov     cx,8            ; Set number of stop bits
        mov     dx,1            ; to 1 stop bit
        int     control
        mov     cx,9            ; Set parity type
        mov     dx,0            ; to no parity.  Parity handled internally.
        int     control
        mov     cx,10           ; Transmit XON/XOFF
        mov     dx,1            ; Enabled
        int     control
        mov     cx,11           ; Receive XON/XOFF
        mov     dx,1            ; Enabled
        int     control
        mov     cx,3            ; Install changes
        int     control
        ret

SHOWKEY:
        mov ax,offset shkmsg
        mov cx,shklen
        ret
 
; Initialization for using serial port.  XON/XOFF has already been set by
; the local initialization routine.  Returns normally.
SERINI  PROC    NEAR
        cld                     ; Do increments in string operations
        call    clrbuf          ; Clear input buffer.
        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
        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.
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
        cld
        rep movsb               ; copy into our arg blk
        mov bx,34H
        mov dx,1
        mov cx,12               ; Turn on RTS
        int control
        mov cx,13               ; Turn on DTR
        int control
term1:  call prtchr
        jmp short term2         ; have a char...
        nop
        nop
        jmp short term3         ; no char, go on
term2:  and al,7FH
        push ax
        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
        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

; Print a message to the screen.  Returns normally.
TMSG    proc    near
        push    ax
        push    bx
        push    cx
        push    dx
        mov     ah,prstr
        int     dos
        pop     dx
        pop     cx
        pop     bx
        pop     ax
        ret
TMSG    endp

; Print a character to the screen.  Returns normally.
TCHR    proc    near
        push    ax
        push    bx
        push    cx
        push    dx
        mov     ah,conout
        int     dos
        pop     dx
        pop     cx
        pop     bx
        pop     ax
        ret
TCHR    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
