        name msxap3
; File MSXAP3.ASM
; Last modification: 13 April 1986

; System dependent module for NEC APC III
;***********************************************************************
; Add global entry point vtstat for use by Status routine in mssset.
; 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 and RTS
; low in response to Kermit command Hangup. Yields 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]
;
;*
;*  RAL 6/12/85
;*
;* 7/3/85 Changed Poscur from NEC ROM BIOS to emulate VT100 cursor
;*        positioning....ROM version caused Kermit to lose characters
;*        for unknown reasons
;*
;*        Changed escape character from Control-A to Control-]
;*
;*                     Kermit for NEC APC III
;*
;***********************************************************************
        public  serini, serrst, clrbuf, outchr, coms, vts, vtstat, dodel, ctlu
        public  cmblnk, locate, lclini, prtchr, dobaud, clearl
        public  dodisk, getbaud, beep, puthlp
        public  count, poscur, machnam, sendbr, putmod, clrmod
        public  setktab, setkhlp, xofsnt, showkey
        public  term
        public  ihosts, ihostr, dtrlow, dumpscr                 ; [jrd]
        include mssdef.h

false   equ     0
true    equ     1

auxin   equ     3
auxout  equ     4
auxfil  equ     3               ; file number of aux file.
iordy   equ     6               ; input ready function

datas   segment public 'datas'
        extrn   drives:byte, flags:byte, trans:byte
        extrn   portval:word, port1:byte, port2:byte, dmpname:byte ; [jrd]

portin  db      0
crlf    db      cr,lf,'$'
machnam db      '* NEC APC III - RAL Version 2.0 *',cr,lf,'$'
badbd   db      cr,lf,'Unimplemented baud rate, Baud = 9600$'
noimp   db      cr,lf,'Command not implemented.$'
shkmsg  db      'Not implemented.'
shklen  equ     $-shkmsg
hngmsg  db      cr,lf,' The phone should have hungup.',cr,lf,'$' ; [jrd]
hnghlp  db      cr,lf,' The modem control lines DTR and RTS for the current'
        db      ' port are forced low (off)'
        db      cr,lf,' to hangup the phone. Normally, Kermit leaves them'
        db      ' high (on) when it exits.'
        db      cr,lf,'$'                                       ; [jrd]
rdbuf   db      80 dup (?)      ; temp buf [jrd]
xofsnt  db      0               ; Say if we sent an XOFF.
xofrcv  db      0               ; Say if we received an XOFF.
setktab db      0
setkhlp db      0
invseq  db      esc,'[7m$'      ; Reverse video on.
nrmseq  db      esc,'[0m',esc,'[33m$' ; Reverse video off.
ivlseq  db      esc,'[7m'
        db      79 dup (' '),cr,'$' ; Make a line inverse video
delstr  db      BS,' ',BS,'$'   ; Delete string...Used in DODEL........
clrlin  db      cr,esc,'[K$'    ; Erase line...Used in CTLU.....
tmp     db      ?,'$'
temp    dw      0
temp1   dw      ?               ; Temporary storage.
temp2   dw      ?               ; Temporary storage.

; variables for serial interrupt handler

source  db      bufsiz DUP(?)   ; Buffer for data from port.
bufout  dw      0               ; buffer removal ptr
count   dw      0               ; Number of chars in int buffer.
bufin   dw      0               ; buffer insertion ptr
telflg  db      0               ; Are we acting as a terminal. [16] [17c]
clreol  db      esc,'[0K$'      ; Clear to end of line.......
blank   db      esc,'[H',esc,'[J$' ; Home cursor, then Clear screen....
movcur  db      esc,'['
colno   db      20 dup (?)
ten     db      10
prthnd  dw      0

ourarg  termarg <>
; must parallel baud rate defs in pcdefs.
; Unsupported baud rates must be FF.....
; NEC APC has only 8 possible baud rates.......
; RAL....
;
baudtab db      0FFH            ; 45.5
        db      0FFH            ; 50
        db      0               ; 75
        db      0FFH            ; 110
        db      0FFH            ; 134.5
        db      1               ; 150
        db      2               ; 300
        db      3               ; 600
        db      4               ; 1200
        db      0FFH            ; 1800
        db      0FFH            ; 2000
        db      5               ; 2400
        db      6               ; 4800
        db      7               ; 9600
        db      0FFH            ; 19.2k
        db      0ffh            ; 38.4k (ha)

nbaud   equ     $-baudtab
first   db      true            ; RAL...Used in Get Baud......
qid     dw      ?
prtcnt  dw      ?
trqid   dw      ?
tmqid   dw      ?
brflg   db      ?
datas   ends

code    segment public 'code'
        extrn   comnd:near, dopar:near, prserr:near
        extrn   sleep:near                              ; [jrd]
        assume  cs:code,ds:datas

DODISK  PROC    NEAR
        mov ah,gcurdsk                  ; Current disk value to AL.
        int dos
        mov dl,al                       ; Put current disk in DL.
        mov ah,seldsk                   ; Select current disk.
        int dos                         ; Get number of drives in AL.
        mov drives,al
        ret
DODISK  ENDP

;*********************************************************************
; Clear the input buffer before sending a packet. [20e]
; RAL....
;*********************************************************************
CLRBUF  PROC    NEAR
        mov     ah,2            ; Get data length in CX...Page SE-12
        int     1AH             ; Call APC ROM BIOS
        or      ch,cl           ; check for zero in both halfs of CX
        cmp     ch,0            ; is CH 0?
        je      clrb1           ; If zero then buffer is clear else
        mov     ah,auxin        ; get character from auxiliary device
        int     dos
        jmp     clrbuf
clrb1:  mov     count,0
        ret
CLRBUF  ENDP

;*********************************************************************
; Common routine to clear to end-of-line. [19a]
CLEARL  PROC    NEAR
        mov dx,offset clreol
        mov ah,prstr
        int dos
        ret
CLEARL  ENDP

;*******************************************************************
; This routine should set the baud rate for the current port but it
; is actually done in SERINI.
dobaud  proc    near
        push si                 ; [jrd]
        push bx
        mov bx,portval
        mov si,[bx].baud        ; get baud rate index pointer..
        pop bx
        mov al,baudtab[si]      ; load up baud rate.........
        pop si                  ; [jrd]
        cmp al,0FFH             ; Is Baud Rate Possible??
        je badbaud
        call    serini          ; Simply re-init port with new baud rate
dbret:  ret
BadBaud: mov ah,prstr           ; MS-DOS Print String...
        mov dx,offset badbd     ; point at message
        int DOS
        push bx
        mov bx,portval
        mov [bx].baud,0Dh       ; Go back to 9600 baud.....
        pop bx
        jmp dbret
dobaud  endp

;*******************************************************************
; Send a break out the current serial port.  Returns normally.
sendbr:
        ret                     ; RAL Leave out for a while


;*******************************************************************
; 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                 ; save line pointer
        mov dh,24               ; Row...
        mov dl,0                ; Column...
        call poscur             ; Position cursor at bottom of screen

        mov ah,prstr
        mov dx,offset ivlseq    ; Put into reverse video.
        int dos

        pop dx
        mov ah,prstr
        int dos                 ; Print message.....

        mov ah,prstr
        mov dx,offset nrmseq    ; Normal video.
        int dos
        ret
putmod  endp

;********************************************************************
; Clear the mode line written by putmod.  Returns normally.
clrmod  proc    near
        mov dh,24
        mov dl,0
        call    poscur          ; Line 24, column 0...
        call    clearl          ; Clear Line......
        ret
clrmod  endp

;*****************************************************************
; Put a help message one the screen in reverse video.  Pass
; the message in AX, terminated by a null.  Returns normally.
; The message is put wherever the cursor currently is located.
puthlp  proc    near
        push ax
        mov ah,prstr            ; Leave some room before the message.
        mov dx,offset crlf      ; write CR,LF
        int dos

        pop si                  ; Put message address here.
        cld                     ; set direction for auto increment

puth0:  push si
        mov ah,prstr
        mov dx,offset ivlseq    ; Make line inverse video
        int dos
        pop si

puth1:  lodsb
        cmp al,0                ; End of String???
        je puth2
        push ax
        push si
        mov ah,14               ; Write Teletype...
        int 19h                 ; Call NEC Bios
        pop si
        pop ax
        cmp al,lf               ; Line feed?
        je puth0                ; Yes, clear the next line.
        jmp puth1               ; Else, just keep on writing.
puth2:
        mov dx,offset crlf      ; Next line.....
        mov ah,prstr
        int dos
        mov dx,offset nrmseq    ; Return to Normal video.
        int dos
        ret
puthlp  endp


;*********************************************************************
; This routine blanks the screen.
CMBLNK  PROC    NEAR
        mov ah,prstr
        mov dx,offset blank
        int dos
        ret
CMBLNK  ENDP

;*********************************************************************
;* Home cursor
LOCATE  PROC    NEAR
        mov dx,0                ; Go to top left corner of screen.
        jmp poscur              ; callret...
LOCATE  ENDP

;********************************************************************
;* RAL..This routine appears to be called every time a status is done.
;* I will set baud rate first time, and simply return from then on.
;*
;*  Page SA-2 APC III Programmer Reference Manual
GETBAUD PROC    NEAR
        mov al,First    ; Check to see if this is the first time....
        cmp al,false
        je GBRET        ; Quit if baud rate already known.....

        mov First,False ; Flip Flag...
        push bx
        mov bx,portval
        mov [bx].baud,0Dh ; Default to 9600 Baud.....
        pop bx
        call serini     ; Set up port........
GBRET:  ret
GETBAUD ENDP

;**********************************************************************
;* Position the cursor according to contents of DX.
;*  Page SE-4
;*  DH,DL -  Row, Column
;*  BH Page number - 0,1
;* Ral
;POSCUR  PROC    NEAR
;       mov bh,0                ; Use page 0
;       mov ah,2                ; set cursor position...
;       int 19h                 ; CRT IO with NEC APC ROM BIOS
;       ret
;POSCUR  ENDP


; Position the cursor according to contents of DX.

POSCUR  PROC    NEAR
        push    ax                      ; save regs. [jrd]
        push    di
        push    es
        mov     ax,ds
        mov     es,ax                   ; address data segment!!!
        cld
        mov     di,offset colno
        mov     al,dh                   ; row
        inc     al
        call    nout
        mov     al,';'
        stosb
        mov     al,dl                   ; col
        inc     al
        call    nout
        mov     al,'H'
        stosb
        mov     al,'$'
        stosb
        mov     dx,offset movcur
        mov     ah,prstr
        int     dos                     ; print the sequence
        pop     es                      ; [jrd]
        pop     di
        pop     ax
        ret
POSCUR  ENDP

NOUT    PROC    NEAR
        cbw                     ; extend to word
        div     byte ptr ten    ; divide by 10
        or      al,al           ; any quotient?
        jz      nout1           ; no, forget this
        push    ax              ; save current result
        call    nout            ; output high order
        pop     ax              ; restore
nout1:  mov     al,ah           ; get digit
        add     al,'0'          ; make printable
        stosb
        ret                     ; put in buffer and return
NOUT    endp


;******************************************************************
; Perform a delete.
DODEL   PROC    NEAR
        mov ah,prstr
        mov dx,offset delstr    ; Erase weird character.
        int dos
        ret
DODEL   ENDP

;********************************************************************
; Perform a Control-U.
CTLU    PROC    NEAR
        mov ah,prstr
        mov dx,offset clrlin
        int dos
        ret
CTLU    ENDP

;********************************************************************
;* Select various I/O ports for Kermit to use...Not Implemented....
COMS    PROC    NEAR
        jmp notimp              ; function in use....
COMS    ENDP

;********************************************************************
;* Set Heath-19 Emulation on & off
VTS     PROC    NEAR
        jmp notimp      ; Wasn't Implemented in original Wang..
VTS     ENDP

VTSTAT  PROC    NEAR    ; For Status display [jrd]
        ret             ; no emulator status to display
VTSTAT  ENDP

; Save the screen to a buffer and then append buffer to a disk file. [jrd]
; Default filename is Kermit.scn; actual file can be a device too. Filename
; is determined by mssset and is passed as pointer dmpname.

DUMPSCR PROC    NEAR    ; Dumps screen contents to a file. Just Beeps here
        call beep       ; [jrd]
        ret
DUMPSCR ENDP
;*********************************************************************
;* Print not implemented message.......
;*********************************************************************
notimp: mov ah,prstr
        mov dx,offset noimp
        int dos
        jmp prserr

;*********************************************************************
;* Perform initialization
;*********************************************************************
lclini: mov trans.escchr,1Dh    ; Use Control-] as escape char.
        mov flags.vtflg,0       ; Turn Heath Emulation Off.....
        mov ah,5                ; Select active page number
        mov al,0                ; use page 0..
        int 19h                 ; Call NEC ROM BIOS....
        ret
;********************************************************************
;*  Not implemented....RAL
showkey:
        jmp notimp

;************* RAL *****************************************************
;* Page SE-10 MS-DOS Programmers Manual
;* Performs Serial Port Initialization.............
;***********************************************************************
;     Common initialization for using serial port.
SERINI  PROC    NEAR
        push es
        push di

        mov AX,datas            ; point at start of this segement?
        mov ES,AX
        mov DI,offset source    ; Point at Serial Buffer....

        push bx
        mov bx,portval
        mov si,[bx].baud        ; get baud rate index pointer..
        mov ah,[bx].floflg
        pop bx

        mov al,baudtab[si]      ; load up baud rate.........

                                ; AH = 1 XON/XOFF flow control
                                ; AH = 0 No Flow control
                                ; Page SE-10 NEC Programmer Ref manual

        cmp     AH,0            ; doing flow control?
        je      NoFlow          ; 0 if not flow control

        mov ah,1                ; Init with Xon/Xoff

NoFlow:
        mov CH,01001110B        ; set up various parameters....
;              | | | |
;              | | | +--- Clock 10 x16, 11 x64
;              | | +----- Word Length 10 7, 11 8
;              | +------- Parity 00 None, 01 Odd, 11 Even
;              +--------- Stop Bits 01 1, 10 1.5, 11 2

        mov CL,00100111B        ; Page 24 Compupro System Support
                                ; appears to be same IC....

        mov dx,200              ; load with Buffer Size...
                                ; Buffer is actually 2048 long
                                ; but NEC Bios will not work that long..
                                ; Manual does not give much info
                                ; on this variable...Will leave at 200
                                ; until I learn more....

        mov bh,0                ; try defaults for these...
        mov bl,0

        int 1AH                 ; Call NEC Rom

        cmp ah,0                ; Did everything go ok??
        je serin1               ; continue if so...else
        call beep
serin1:
        call clrbuf             ; Clear Input buffer........
        pop di
        pop es
        ret                     ; We're done. [21c]
SERINI  ENDP

;*********************************************************************
;* Should reset serial port to settings before kermit, but its not
;* worth the trouble....RAL.......
SERRST  PROC    NEAR
serrs1: ret
SERRST  ENDP

;*********************************************************************
; Generate a short beep.

BEEP    PROC    NEAR
        mov dl,bell
        mov ah,conout
        int dos
        ret
BEEP    ENDP

;*********************************************************************
; Jumping to this location is like retskp.  It assumes the instruction
;   after the call is a jmp addr.

RSKP    PROC    NEAR
        pop bp
        add bp,3
        push bp
        ret
RSKP    ENDP

;*********************************************************************
; Jumping here is the same as a ret.

R       PROC    NEAR
        ret
R       ENDP

;*********************************************************************
;* Very simple Terminal Emulator.....RAL

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

;__________________ Terminal Emulator ______________________________
;* RAL 6/14/85
term1:  call prtchr             ; Try to get char from Serial port...
        jmp short term2         ; have a char...
        nop
        nop
        jmp short term3         ; no char, go on
term2:  and al,7fh              ; strip 8th bit - ral
        push ax
        call print              ; print character in AL..
        pop ax
        test ourarg.flgs,capt   ; capturing output?
        jz term3                ; no, forget it
        call ourarg.captr       ; else call the routine

term3:
        mov ah,1                ; Check to see if keyboard has a char
                                ; Page SE-1...
                                ; Zero Flag = 1....No Chars...
                                ; Zero Flag = 0...Character in queue
        int 18H                 ; Call NEC ROM
        jz term1                ; no character, restart terminal loop

        mov ah,0                ; Get char from queue in AL....
        int 18h                 ; Call NEC ROM

        cmp al,ourarg.escc      ; escape char?
        je term4                ; yes, exit
        push ax                 ; preserve AX
        mov ah,al
        call outchr             ; output the character
        nop
        nop
        nop
        pop ax                  ; Restore AX
        test ourarg.flgs,lclecho ; echoing?
        jz term1                ; no, continue loop
                                ; Echo Character...
        call print
        jmp term1               ; else echo and keep going
term4:  ret
Print:
        mov DL,AL
        mov ah,06               ; Print Character in DL on CRT
        int DOS
        ret
term    endp


;*******************************************************************
; skip returns if no character available at port,
; otherwise returns with char in al, # of chars in buffer in dx.
;* RAL 6/12/85 change get character from AUX port
PRTCHR  PROC    NEAR
        mov ah,2        ; Get data length in CX...Page SE-12
        int 1AH         ; Call APC ROM BIOS
        mov count,cx    ; save count
        or ch,cl        ; check for zero in both halfs of CX
        cmp ch,0        ; is CH 0?
        je prtc1        ; give up if no characters........

        mov ah,4        ; Receive Character...by way of NEC BIOS
        int 1AH
        mov al,ch       ; Character is returned in CH....
        dec count       ; show that we took character...
        mov dx,count    ; load dx with count for return
        ret
prtc1:  jmp rskp
PRTCHR  ENDP

;********************************************************************
;* Will send a character to the AUX port...
;* RAL
; Put the char in AH to the serial port. This assumes the
; port has been initialized. Should honor XON/XOFF...Skip returns on
; success, returns normally if character cannot be written...
OUTCHR PROC NEAR
        push dx
        mov al,ah               ; parity works on AH
        call dopar              ; do parity work before sending
        mov ah,3                ; NEC ROM BIOS send character in AL
        int 1AH                 ; send character...
        pop dx
        jmp rskp
OUTCHR ENDP

; IHOSTS - Initialize the host by sending XON, or equivalent, and enter the
; cycle of clear input buffer, wait 1 second, test if buffer empty then exit
; else repeat cycle. Requires that the port be initialized before hand.
; Ihosts is used by the local send-file routine just after initializing
; the serial port.
; 22 March 1986 [jrd]

IHOSTS  PROC    NEAR
        push    ax              ; save the registers
        push    bx
        push    cx
        push    dx
        mov     bx,portval      ; port indicator
        mov     ax,[bx].flowc   ; put Go-ahead flow control char in ah
        call    outchr          ; send it (release Host's output queue)
         nop                    ; outchr can do skip return
         nop
         nop
ihosts1:call    clrbuf          ; clear out interrupt buffer
        mov     ax,1            ; sleep for 1 second
        call    sleep           ; procedure sleep is in msscom.asm
        call    prtchr          ; check for char at port
         jmp    ihosts1         ; have a char in al, repeat wait/read cycle
         nop                    ; prtchr does skip return on empty buffer
        pop     dx              ; empty buffer. we are done here.
        pop     cx
        pop     bx
        pop     ax
        ret
IHOSTS  ENDP

; IHOSTR - initialize the remote host for our reception of a file by
; sending the flow-on character (XON typically) to release any held
; data. Called by receive-file code just after initializing the serial
; port.         22 March 1986 [jrd]
IHOSTR  PROC    NEAR
        push    ax              ; save regs
        push    bx
        push    cx
        mov     bx,portval      ; port indicator
        mov     ax,[bx].flowc   ; put Go-ahead flow control char in ah
        call    outchr          ; send it (release Host's output queue)
         nop                    ; outchr can do skip return
         nop
         nop
        pop     cx
        pop     bx
        pop     ax
        ret
IHOSTR  ENDP

DTRLOW  PROC    NEAR            ; Global proc to Hangup the Phone by making
                                ; DTR and RTS low.
        mov ah,cmtxt            ; allow text to be able to display help
        mov bx,offset rdbuf     ; dummy buffer
        mov dx,offset hnghlp    ; help message
        call comnd              ; get a confirm
         jmp r
;not yet imp.   call serhng             ; drop DTR and RTS
        mov ah,prstr            ; give a nice message
;not yet imp.   mov dx,offset hngmsg
        mov dx,offset noimp     ; say "not implemented" for now
        int dos
        jmp rskp
DTRLOW  ENDP

; Hang up the Phone. Similar to SERRST except it just forces DTR and RTS low
; to terminate the connection. 29 March 1986 [jrd]
; Calling this twice without intervening calls to serini should be harmless.
; Returns normally.
; SERHNG is Not Yet Implemented.


code    ends
        end
