Title   'MEX overlay for the U.S. Robotics 212A version 1.0'
;
;       06/17/85 by Gary MacKay Converted MXM-US13.ASM to MXM-USR2.ASM
;                       for use with the U.S. Robotics 212A. Also cleaned up
;                       the fancy video rtns to work better on my TVI925 term.
;       08/30/84 added parity routines
;       08/29/84 added fancy video conditionals
;       08/27/84 by Don Wilke
;
REV     EQU     10              ; Overlay revision level
;
; Misc equates
;
NO      EQU     0
YES     EQU     0FFH
BELL    EQU     07H             ; Bell
TAB     EQU     09H             ; Tab
LF      EQU     0AH             ; Line feed
CR      EQU     0DH             ; Carriage return
ESC     EQU     1BH             ; Escape
TPA     EQU     100H            ; Transient prog area
MEX     EQU     0D00H           ; Address of the service processor
ATTRIB  EQU     YES             ; Yes if fancy video supported
;
; USR port equates
;
PORT    EQU     060H            ; Base I/O address for my 8251 DART card
MODCT1  EQU     064H            ; 8251 control port
MODDAT  EQU     063H            ; 8251 data port
MDDCDB  EQU     10000000B       ; Carrier detect bit
MDDCDA  EQU     10000000B       ; Value when active
MDRCVB  EQU     00000010B       ; Bit to test for receive
MDRCVR  EQU     00000010B       ; Value when ready
MDSNDB  EQU     00000001B       ; Bit to test for send
MDSNDR  EQU     00000001B       ; Value when ready
MMODEA  EQU     01001110B       ; 8 bits, clock/16, 1 stop bit
MMODEB  EQU     11001111B       ; 8 bits, clock/64, 2 stop bits
MMCMDA  EQU     00110111B       ; RTS hi, error reset, DTR hi, enable TX/RX
MMCMDB  EQU     00010111B       ; Error reset, DTR hi, enable TX/RX
MRESET  EQU     01000000B       ; 8251 reset
;
; Following are function codes for the MEX service call processor
;
INMDM   EQU     255             ; Get char from port to A, CY=no more in 100 ms
TIMER   EQU     254             ; Delay 100ms * reg B
TMDINP  EQU     253             ; B=# secs to wait for char, cy=no char
CHEKCC  EQU     252             ; Check for ^C from KBD, Z=present
SNDRDY  EQU     251             ; Test for modem-send ready
RCVRDY  EQU     250             ; Test for modem-receive ready
SNDCHR  EQU     249             ; Send a character to the modem (after sndrdy)
RCVCHR  EQU     248             ; Recv a char from modem (after rcvrdy)
LOOKUP  EQU     247             ; Table search: see CMDTBL comments for info
PARSFN  EQU     246             ; Parse filename from input stream
BDPARS  EQU     245             ; Parse baud-rate from input stream
SBLANK  EQU     244             ; Scan input stream to next non-blank
EVALA   EQU     243             ; Evaluate numeric from input stream
LKAHED  EQU     242             ; Get nxt char w/o removing from input
GNC     EQU     241             ; Get char from input, cy=1 if none
ILP     EQU     240             ; Inline print
DECOUT  EQU     239             ; Decimal output
PRBAUD  EQU     238             ; Print baud rate
;
CONOUT  EQU     2               ; Simulated BDOS function 2: console char out
PRINT   EQU     9               ; Simulated BDOS function 9: print string
INBUF   EQU     10              ; Input buffer,same structure as BDOS 10

       ORG     TPA             ; We begin
;
       DS      3               ; MEX has a JMP START here
;
; The following variables are located at the beginning of the program
; to facilitate modification without the need of re-assembly. They will
; be moved in MEX 2.0.
;
PMODEM: DB      NO              ; Yes=PMMI modem \ / These 2 locations are not
SMODEM: DB      YES             ; Yes=Smartmodem / \ referenced by MEX
TPULSE: DB      'T'             ; T=touch,P=pulse (not referenced by MEX)
CLOCK:  DB      40              ; Clock speed x .1, up to 25.5 mhz.
MSPEED: DB      5               ; Sets display time for sending a file
                               ; 0=110 1=300  2=450  3=600  4=710
                               ; 5=1200 6=2400 7=4800 8=9600 9=19200
BYTDLY: DB      5               ; Default time to send character in
                               ; terminal mode file transfer (0-9)
                               ; 0=0 delay, 1=10 ms, 5=50 ms, 9=90 ms
CRDLY:  DB      5               ; End-of-line delay after CRLF in terminal
                               ; mode file transfer for slow BBS systems
                               ; 0=0 delay, 1=100 ms, 5=500 ms, 9=900 ms
COLUMS: DB      5               ; Number of directory columns
SETFL:  DB      YES             ; Yes=user-defined SET command
SCRTST: DB      YES             ; Yes=if home cursor and clear screen
                               ; routine at CLRSCRN
       DB      0               ; Was once ACKNAK,now spare
BAKFLG: DB      NO              ; Yes=make .BAK file
CRCDFL: DB      YES             ; Yes=default to CRC checking
                               ; No=default to Checksum checking
TOGCRC: DB      YES             ; Yes=allow toggling of Checksum to CRC
CVTBS:  DB      NO              ; Yes=convert backspace to rub
TOGLBK: DB      YES             ; Yes=allow toggling of bksp to rub
ADDLF:  DB      NO              ; No=no LF after CR to send file in
                               ; terminal mode (added by remote echo)
TOGLF:  DB      YES             ; Yes=allow toggling of LF after CR
TRNLOG: DB      YES             ; Yes=allow transmission of logon
                               ; write logon sequence at location LOGON
SAVCCP: DB      YES             ; Yes=do not overwrite CCP
LOCNXT: DB      NO              ; Yes=local cmd if EXTCHR precedes
                               ; No=not local cmd if EXTCHR precedes
TOGLOC: DB      YES             ; Yes=allow toggling of LOCNXTCHR
LSTTST: DB      YES             ; Yes=allow toggling of printer on/off
                               ; in terminal mode. Set to no if using
                               ; the printer port for the modem
XOFTST: DB      NO              ; Yes=allow testing of XOFF from remote
                               ; while sending a file in terminal mode
XONWT:  DB      NO              ; Yes=wait for XON after sending CR while
                               ; transmitting a file in terminal mode
TOGXOF: DB      YES             ; Yes=allow toggling of XOFF testing
IGNCTL: DB      YES             ; Yes=do not send control characters
                               ; above CTL-M to CRT in terminal mode
                               ; no=send any incoming CTL-char to CRT
EXTRA1: DB      0               ; For future expansion
EXTRA2: DB      0               ; For future expansion
BRKCHR: DB      '@'-40H         ; ^@ = Send a 300 ms. break tone
NOCONN: DB      'N'-40H         ; ^N = Disconnect from phone line
LOGCHR: DB      'L'-40H         ; ^L = Send logon
LSTCHR: DB      'P'-40H         ; ^P = Toggle printer
UNSVCH: DB      'R'-40H         ; ^R = Close input text buffer
TRNCHR: DB      'T'-40H         ; ^T = Transmit file to remote
SAVCHR: DB      'Y'-40H         ; ^Y = Open input text buffer
EXTCHR: DB      '^'-40H         ; ^^ = Send next character
;
; Equates used only by PMMI routines grouped together here.
;
PRATE:  DB      250             ; 125=20pps dialing, 250=10pps
       DB      0               ; Not used
;
; Low-level modem I/O routines: this will be replaced with
; a jump table in MEX 2.0 (you can insert jumps here to longer
; routines if you'd like ... I'd recommend NOT putting part of
; a routine in this area,then jumping to the rest of the routine
; in the non-fixed area; that will complicate the 2.0 conversion)
;
INCTL1: IN      MODCT1          ; In modem control port
       RET
       DB      0,0,0,0,0,0,0   ; Spares if needed for non-PMMI
;
OTDATA: OUT     MODDAT          ; Out modem data port
       RET
       DB      0,0,0,0,0,0,0   ; Spares if needed for non=PMMI
;
INPORT: IN      MODDAT          ; In modem data port
       RET
       DB      0,0,0,0,0,0,0   ; Spares if needed for non-PMMI
;
; Bit-test routines.  These will be merged with the above
; routines in MEX 2.0 to provide a more reasonable format
;
MASKR:  ANI MDRCVB ! RET        ; Bit to test for receive ready
TESTR:  CPI MDRCVR ! RET        ; Value of receive bit when ready
MASKS:  ANI MDSNDB ! RET        ; Bit to test for send ready
TESTS:  CPI MDSNDR ! RET        ; Value of send bit when ready
;
;
; Unused area: was once used for special PMMI functions,
; Now used only to retain compatibility with MDM overlays.
; You may use this area for any miscellaneous storage you'd
; like but the length of the area *must* be 12 bytes.
;
       DS      12
;
; Special modem function jump table: if your overlay cannot handle
; some of these, change the jump to "DS 3", so the code present in
; MEX will be retained.  Thus, if your modem can't dial, change the
; JMP PDIAL at DIALV to DS 3, and MEX will print a "not-implemented"
; diagnostic for any commands that require dialing.
;
; DIALV  dials the digit in A. See the comments at PDIAL for specs.
;
; DISCV  disconnects the modem
;
; GOODBV is called just before MEX exits to CP/M.  If your overlay
;        requires some exit cleanup, do it here.
;
; INMODV is called when MEX starts up; use INMODV to initialize the modem.
;
; NEWBDV is used for phone-number baud rates and is called with a baud-rate
;        code in the A register, value as follows:
;
;        A=0:   110 baud       A=1:   300 baud      A=2:   450 baud
;        A=3:   600 baud       A=4:   710 baud      A=5:  1200 baud
;        A=6:  2400 baud       A=7:  4800 baud      A=8: 19200 baud
;
;        If your overlay supports the passed baud rate,it should store the
;        value passed in A at MSPEED (107H), and set the requested rate. If
;        the value passed is not supported, you should simply return (with-
;        out modifying MSPEED) -or- optionally request a baud-rate from the
;        user interactively.
;
; NOPARV is called at the end of each file transfer; your overlay may simply
;        return here, or you may want to restore parity if you set no-parity
;        in the following vector (this is the case with the PMMI overlay).
;
; PARITV is called at the start of each file transfer; your overlay may simply
;        return here, or you may want to enable parity detection (this is the
;        case with the PMMI overlay).
;
; SETUPV is the user-defined command ... to use this routine to build your own
;        MEX command, set the variable SETFL (117H) non-zero,and add your SET
;        code.  You can use the routine presented in the PMMI overlay as a
;        guide for parsing, table lookup, etc.
;
; SPMENU is provided only for MDM compatibility, and is not used by MEX 1.0
;        for any purpose (it will be gone in MEX 2).
;
; VERSNV is called immediately after MEX prints its sign-on message at cold
;        startup -- use this to identify your overlay in the sign-on message
;        (include overlay version number in the line).
;
; BREAKV is provided for sending a BREAK (<ESC>-B in terminal mode).  If your
;        modem doesn't support BREAK, or you don't care to code a BREAK rou-
;        tine, you may simply execute a RET instruction.
;
LOGON:  DS      2               ; Needed for MDM compat, not ref'd by MEX
DIALV:  DS      3               ; Dial digit in A
DISCV:  DS      3               ; Disconnect the modem
GOODBV: JMP     GOODBYE         ; Called before exit to CP/M
INMODV: JMP     NITMOD          ; Initialization. Called at cold-start
NEWBDV: JMP     PBAUD           ; Set baud rate
NOPARV: RET ! NOP ! NOP         ; Set modem for no-parity
PARITV: RET ! NOP ! NOP         ; Set modem parity
SETUPV: JMP     SETCMD          ; SET cmd
SPMENV: RET ! NOP ! NOP         ; Not used with MEX
VERSNV: JMP     SYSVER          ; Overlay's voice in the sign-on message
BREAKV: JMP     PBREAK          ; Send a break
;
; The following jump vector provides the overlay with access to special
; routines in the main program (retained and supported in the main pro-
; gram for MDM overlay compatibility). These should not be modified by
; the overlay.
;
; Note that for MEX 2.0 compatibility, you should not try to use these
; routines, since this table will go away with MEX 2.0 (use the MEX
; service call processor instead).
;
ILPRTV: DS      3               ; Replace with MEX function 9
INBUFV: DS      3               ; Replace with MEX function 10
ILCMPV: DS      3               ; Replace with table lookup funct. 247
INMDMV: DS      3               ; Replace with MEX function 255
NXSCRV: DS      3               ; Not supported by MEX (returns w/no action)
TIMERV: DS      3               ; Replace with MEX function 254
;
; Routine to clear to end of screen.  If using CLREOS and CLRSCRN, set
; SCRNTEST to YES at 010AH (above).  Each routine must use the
; full 9 bytes alloted (may be padded with nulls).
;
; These routines (and other screen routines that MEX 2.0 will sup-
; port) will be accessed through a jump table in 2.0, and will be
; located in an area that won't tie the screen functions to the
; modem overlay (as the MDM format does).
;
CLREOS: LXI     D,EOSMSG        ; Point to clear to EOS msg
       MVI     C,PRINT         ; MEX print string funct #
       CALL    MEX             ; Let MEX do it
       RET
;
CLS:    LXI     D,CLSMSG        ; Point to clear screen msg
       MVI     C,PRINT         ; MEX print string funct #
       CALL    MEX             ; Let MEX do it
       RET
;
; The following routine sends a break "character" to the remote computer
; for 300 ms.  The "MSPEED" value is needed to decide whether the modem
; is at 300, 600, or 1200 baud.  The routine must know this because U.S.R.
; sets up the RTS bit of the command register as a baud rate selection bit,
; and this routine must be careful not to change it, or the user will end up
; at a different baud rate after the break "character" is sent.  Note that
; the "MVI A,01FH" does not change any flags.
;
PBREAK: LDA     MSPEED          ; Get speed byte
       CPI     3               ; Are we at 600 baud?
       MVI     A,01FH          ; Set up for 600 (no flag changes)
       JZ      PBRK2           ; And if we are, go do that
       MVI     A,03FH          ; Otherwise,set up for 300/1200
PBRK2:  OUT     MODCT1          ; Send break
       PUSH    PSW             ; Save value
       MVI     B,3             ; 300 ms delay value
       MVI     C,TIMER         ; MEX service function #254
       CALL    MEX             ; Wait that long
       POP     PSW             ; Restore command byte
       ANI     0F7H            ; Turn off break bit
       OUT     MODCT1          ; Send command byte to UART
       RET
;
; The U.S.R. 212A does not have a "quick-disconnect" feature like
; the Hayes does (by lowering DTR).  Therefore, "GOODBYE" is not
; implemented.  Yet control-N still works to hang up (see note
; above in introduction)
;
GOODBYE:
       LXI     D,DISC1         ; Point to disconnect message
       CALL    PMSG            ; Send it
       MVI     B,15            ; Wait 1.5 sec
       MVI     C,TIMER         ; MEX service function #254
       CALL    MEX             ; Wait for USR212A to wake up
       LXI     D,DISC2         ; Point to rest of disconnect message
       CALL    PMSG            ; Send it too
       MVI     B,15            ; Wait 1.5 sec
       MVI     C,TIMER         ; MEX service function #254
       CALL    MEX             ; Wait for USR212A to wake up
       LXI     H,INITBL        ; Point to beginning of 8251 chip init table
       LXI     B,4             ; Only want first 4 commands this time
GBOUT:  MOV     A,M             ; Get character
       INX     H               ; Bump up pointer
       OUT     MODCT1          ; Send command to port
       DCX     B               ; Counter -1
       MOV     A,C             ; Move C into accum.
       ORA     B               ; Test for zero
       JNZ     GBOUT           ; Nope, keep sending
       RET
;
DISC1:  DB      '+++','$'       ; To get modems attention
DISC2:  DB      'ATH',CR,'$'    ; To hang up modem
;
; *     *       *       *       *       *       *       *       *
;
; You can use this area for any special initialization or setup you may
; wish to include.  Each must stop with a RET.  This initialization
; sets up 1200 baud, 8 data bits, 1 stop bit, no parity.
;
NITMOD: DB      3EH             ; "MVI,A" OP-CODE
BDCODE: DB      33H             ; Default to 1200 baud
       OUT     PORT            ; Send to 8251 buad rate port
       LXI     H,INITBL        ; Point to beginning of 8251 chip init table
       LXI     B,INITBLL       ; Point to length of table
UOUT:   MOV     A,M             ; Get character
       INX     H               ; Bump up pointer
       OUT     MODCT1          ; Send command to port
       DCX     B               ; Counter -1
       MOV     A,C             ; Move C into accum.
       ORA     B               ; Test for zero
       JNZ     UOUT            ; Nope, keep sending
       LXI     H,INISTR        ; Yep, point to modem init string
       LXI     B,MDMTBLL       ; Get length of table
MDM:    MOV     A,M             ; Get character
       INX     H               ; Bump up pointer
       PUSH    PSW             ; Save command
MDM1:   IN      MODCT1          ; Get modem status
       ANI     085H            ; Ready?
       CPI     085H            ;
       JNZ     MDM1            ; Nope, wait
       POP     PSW             ; Recall command
       OUT     MODDAT          ; Send command
       DCX     B               ; Decrement counter
       MOV     A,C             ; Move C to accum.
       ORA     B               ; Test for zero
       JNZ     MDM             ; Nope, keep sending
       RET                     ; Yep, return to caller
;
INITBL: DB      0,0,0           ; Three nulls to reset modem
       DB      40H             ; 8251 UART reset command
MODEBT: DB      4EH             ; 8 bits, 1 stop bit, clock/16, no parity
CMDBT:  DB      37H             ; RTS hi, Error reset, DTR hi, Enable TX/RX
INITBLL EQU     $-INITBL        ; Length of table
;
;
; Command string sent to modem after I/O initialization
;
INISTR: DB      'AT'            ; Get modem's attention
       DB      'X1'            ; Send extended result codes
SPBYTE: DB      'M1'            ; Speaker on 'til connect
WABYTE: DB      'S7=30'         ; Wait for 30 seconds for carrier
       DB      CR,'$'          ; End of command string
MDMTBLL EQU     $-INISTR        ; LENGTH OF STRING TO SEND
;
;....
;
PBAUD:  CPI     8               ; 8=9600 baud
       JZ      OK9600          ; Set to 9600 baud
       CPI     7               ; 7=4800
       JZ      OK4800          ; Set to 4800 baud
       CPI     6               ; 6=2400
       JZ      OK2400          ; Set to 2400 baud
       CPI     5               ; 5=1200 baud
       JZ      OK1200          ; Set to 1200 baud
       CPI     1               ; 1=300 baud
       JZ      OK300           ; Set to 300 baud
                               ; Else set up for 110 baud  * sigh!
OK110:  CALL    WAIT90          ; Set even longer wait for carrier
       MVI     A,MMODEA        ; Get default mode byte
       STA     MODEBT          ; Reinit for 8 bits, 1 stp bit, no parity
       MVI     B,00H           ; Initializer for 110 baud
       MVI     A,0             ; 110 baud
       JMP     LOADBD          ; Go load it
                               ;
OK300:  CALL    WAIT60          ; Set longer wait for carrier
       MVI     A,MMODEA        ; Get default mode byte
       STA     MODEBT          ; Reinit for 8 bits, 1 stp bit, no parity
       MVI     B,22H           ; Initializer for 300 baud
       MVI     A,1             ; 300 baud value
       JMP     LOADBD          ; Go load it
                               ;
OK1200: CALL    WAIT30          ; Set short wait for carrier
       MVI     A,MMODEA        ; Get default mode byte
       STA     MODEBT          ; Reinit for 8 bits, 1 stp bit, no parity
       MVI     B,33H           ; Initializer for 1200 baud
       MVI     A,5             ; 1200 baud value
       JMP     LOADBD          ; Go load it
                               ;
OK2400: CALL    WAIT10          ; Set short wait for carrier
       MVI     A,MMODEA        ; Get default mode byte
       STA     MODEBT          ; Reinit for 8 bits, 1 stp bit, no parity
       MVI     B,55H           ; Initializer for 2400 baud
       MVI     A,6             ; 2400 baud value
       JMP     LOADBD          ; Go load it
                               ;
OK4800: CALL    WAIT10          ; Set short wait for carrier
       MVI     A,MMODEA        ; Get default mode byte

       STA     MODEBT          ; Reinit for 8 bits, 1 stp bit, no parity
       MVI     B,66H           ; Initializer for 4800 baud
       MVI     A,7             ; 4800 baud value
       JMP     LOADBD          ; Go load it
                               ;
OK9600: CALL    WAIT10          ; Set short wait for carrier
       MVI     A,MMODEA        ; Get default mode byte
       STA     MODEBT          ; Reinit for 8 bits, 1 stp bit, no parity
       MVI     B,77H           ; Initializer for 9600 baud
       MVI     A,8             ; 9600 baud value
                               ;
LOADBD: STA     MSPEED          ; Change baud rate code value
       MOV     A,B             ; Get mode byte value
       STA     BDCODE          ; Change mode byte
       CALL    NITMOD          ; (Re)initialize the modem
       LDA     SETFLG          ; Get setflg
       CPI     0FFH            ; Is it a 'SET'
       JNZ     PBPSA           ; No, print bps in dial prompt
       RET                     ; Yes, just return
PBPSA:
        IF     ATTRIB
       LXI     D,INDVID        ; Set video attribute
       CALL    PMSG            ; Issue attribute to term
        ENDIF  ;ATTRIB
       JMP     PBPS            ; Print bps rate
;.....
;
;WAIT FOR CARRIER 30/60 SECONDS
;
WAIT10: MVI     A,'1'           ; SET UP FOR REAL SHORT WAIT
       JMP     SWAIT           ; JUMP AROUND
WAIT30: MVI     A,'3'           ; SET UP FOR SHORT WAIT
       JMP     SWAIT           ; JUMP AROUND
WAIT60: MVI     A,'6'           ; SET UP FOR LONG WAIT
       JMP     SWAIT           ; JUMP AROUND
WAIT90: MVI     A,'9'           ; SET UP FOR LONG LONG WAIT
SWAIT:  STA     WABYTE+3        ; STORE THE WAIT MSB VALUE
       MVI     A,'0'           ; FAKE LSBYTE
       STA     WABYTE+4        ; STORE THE WAIT LSB VALUE
       RET                     ;
;....
;
; Sign-on message
;
SYSVER:  IF     ATTRIB          ; IF ATTRIB
       LXI     D,INVID         ; Set video attribute
       CALL    PMSG            ; Issue attribute to term
        ENDIF                  ; ENDIF ATTRIB
                               ;
       LXI     D,SOMESG        ; Point to signon message
       CALL    PMSG            ; Print message on term
                               ;
CARRSH:  IF     ATTRIB          ; IF ATTRIB
       LXI     D,NORVID        ; Reset video attribute
       CALL    PMSG            ; Issue attribute to term
        ENDIF                  ; ENDIF ATTRIB
                               ;
       CALL    CRLF            ; Print crlf
                               ;
       LXI     D,NOMESG        ; Tell about carrier
       CALL    CARRCK          ; Check for it
       CZ      PMSG            ; Print the "No" if no carrier
       LXI     D,CARMSG        ; Print "carrier present"
       CALL    PMSG            ; Print message on term
                               ;
        IF     ATTRIB          ; IF ATTRIB
       LXI     D,NORVID        ; Reset video attribute
        ENDIF                  ; ENDIF ATTRIB
                               ;
        IF     NOT ATTRIB      ; IF NOT ATRIB
       RET                     ; Return
        ENDIF                  ; ENDIF NOT ATTRIB
                               ;
PMSG:   MVI     C,PRINT         ; Get print funct #
       CALL    MEX             ; Let MEX do it
       RET
;
SOMESG: DB      ' U. S. Robotics 212A  '
       DB      ' Autodial Version '
       DB      REV/10+'0','.'
       DB      REV MOD 10+'0',' ','$'
;
NOMESG: DB      'No$'
CARMSG: DB      ' carrier present '
       DB      CR,LF,'$'
;
; Strings to clear-to-end-of-screen, and clear-screen
;
EOSMSG: DB      ESC,79H,'$'     ; ANSI clear EOS
CLSMSG: DB      ESC,'+$'        ; ANSI clear screen
;
; Strings for setting video attributes
;
UNVID:  DB      ESC,'G8$'       ; ANSI underscore
INDVID: DB      ESC,'G4$'       ; ANSI inverse
INVID:  DB      ESC,'G4$'       ; ANSI bold, inverse
BLVID:  DB      ESC,'G6$'       ; ANSI bold, inverse, blinking
NORVID: DB      ESC,'G0$'       ; ANSI return to normal video
;
; Check the USR for carrier-present (Z=no)
;
CARRCK: IN      MODCT1          ; Get status byte
       ANI     MDDCDB
       RET
;
; Newline on console
;
CRLF:   MVI     A,CR
       CALL    TYPE
       MVI     A,LF            ; Fall into TYPE
;
; Type char in A on console
;
TYPE:   PUSH    H               ; Save 'em
       PUSH    D
       PUSH    B
       MOV     E,A             ; Align output character
       MVI     C,CONOUT        ; Print via MEX
       CALL    MEX
       POP     B
       POP     D
       POP     H
       RET
;
; The remainder of this overlay implements a very versatile
; SET command -- if you prefer not to write a SET for your
; modem, you may delete the code from here to the END statement.
;
; Control is passed here after MEX parses a SET command.
;
SETCMD: PUSH    PSW             ; Save modem speed code
       MVI     A,0FFH          ; Get all ones
       STA     SETFLG          ; Set setflg
       POP     PSW             ; Get modem spd back
       MVI     C,SBLANK        ; Any arguments?
       CALL    MEX
       JC      SETSHO          ; If not, go print out values
       LXI     D,CMDTBL        ; Parse command
       CALL    TSRCH           ; From table
       PUSH    H               ; Any address on stack
       RNC                     ; If we have one, execute it
       POP     H               ; Nope, fix stack
                               ;
SETERR: CALL    CRLF            ; Print crlf
       LXI     D,SPCS2         ; Point to spaces
       CALL    PMSG            ; Print them
                               ;
        IF     ATTRIB          ; IF ATTRIB
       LXI     D,BLVID         ; Set video attribute
       CALL    PMSG            ; Issue attribute to term
        ENDIF                  ; ENDIF ATTRIB
                               ;
       LXI     D,SETEMS        ; Point to error msg
       CALL    PMSG            ; Print message on term
                               ;
        IF     ATTRIB          ; IF ATTRIB
       LXI     D,NORVID        ; Reset video attribute
       CALL    PMSG            ; Issue attribute to term
        ENDIF                  ; ENDIF ATTRIB
                               ;
       CALL    CRLF            ; Print crlf
                               ;
       CALL    STHELP          ; Print help on error
                               ;
       MVI     A,0             ; Clear acc
       STA     SETFLG          ; Reset setflg
       RET
;
SETEMS: DB      BELL,'  SET COMMAND ERROR  $'
;
; SET command table ... note that tables are constructed of command-
; name (terminated by high bit=1) followed by word-data-value returned
; in HL by MEX service processor LOOKUP.  Table must be terminated by
; a binary zero.
;
; Note that LOOKUP attempts to find the next item in the input stream
; in the table passed to it in HL ... if found, the table data item is
; returned in HL; if not found, LOOKUP returns carry set.
;
CMDTBL: DB      '?'+80H         ; "set ?"
       DW      STHELP
       DB      'BAU','D'+80H   ; "set baud"
       DW      STBAUD
       DB      'PARIT','Y'+80H ; "set parity"
       DW      STPAR
       DB      'SPK','R'+80H   ; "set spkr"
       DW      STSPKR
       DB      'WAI','T'+80H   ; "set wait"
       DW      STWAIT
       DB      'DIA','L'+80H   ; "set dial"
       DW      STDIAL
       DB      0               ; <<=== table terminator
;
; SET <no-args>: print current statistics
;
SETSHO: CALL    CRLF            ; Print crlf
       CALL    CARRSH          ; Show carrier present/not present
       LXI     H,SHOTBL        ; Get table of SHOW subroutines
SETSLP: MOV     E,M             ; Get table address
       INX     H
       MOV     D,M
       INX     H
       MOV     A,D             ; End of table?
       ORA     E
       JZ      SETEXT          ; Exit if so
       PUSH    H               ; Save table pointer
       XCHG                    ; Adrs to HL
       CALL    GOHL            ; Do it
       CALL    CRLF            ; Print newline
       MVI     C,CHEKCC        ; Check for console abort
       CALL    MEX
       POP     H               ; It's done
       JNZ     SETSLP          ; Continue if no abort
       CALL    CRLF            ; Abort and send crlf
       RET
;
GOHL:   PCHL
;
SETEXT: CALL    CRLF            ; Print crlf
       RET                     ; Return to caller
;
; table of SHOW subroutines
;
SHOTBL: DW      BDSHOW
       DW      PASHOW
       DW      SPSHOW
       DW      WASHOW
       DW      DISHOW
       DW      0               ; <<== table terminator
;
; SET ?  processor
;
STHELP:
       CALL    CRLF            ; Print message on term
       CALL    CRLF            ; Print message on term
                               ;
       LXI     D,SPCS1         ; Point to spaces
       CALL    PMSG            ; Print them
                               ;
        IF     ATTRIB          ; IF ATTRIB
       LXI     D,UNVID         ; Set video attribute
       CALL    PMSG            ; Issue attribute to term
        ENDIF                  ; ENDIF ATTRIB
                               ;
       LXI     D,HLPHDR        ; Point to HELP header
       CALL    PMSG            ; Print message on term
                               ;
        IF     ATTRIB          ; IF ATTRIB
       LXI     D,NORVID        ; Reset video attribute
       CALL    PMSG            ; Issue attribute to term
        ENDIF                  ; ENDIF ATTRIB
                               ;
       CALL    CRLF            ; Print message on term
       CALL    CRLF            ; Print message on term
                               ;
       LXI     D,HLPMSG        ; Point to HELP msg
       CALL    PMSG            ; Print message on term
                               ;
       CALL    CRLF            ; Print message on term
                               ;
       LXI     D,SPCS1         ; Point to spaces
       CALL    PMSG            ; Print them
                               ;
        IF     ATTRIB          ; IF ATTRIB
       LXI     D,INDVID        ; Set video attribute
       CALL    PMSG            ; Issue attribute to term
        ENDIF                  ; ENDIF ATTRIB
                               ;
       LXI     D,HLPNOT        ; Point to HELP note
       CALL    PMSG            ; Print message on term
                               ;
        IF     ATTRIB          ; IF ATTRIB
       LXI     D,NORVID        ; Reset video attribute
       CALL    PMSG            ; Issue attribute to term
        ENDIF                  ; ENDIF ATTRIB
                               ;
       CALL    CRLF            ; Print CR,LF on term
       CALL    CRLF            ; Print another CR,LF on term
       RET                     ; Return to caller
;
; The help message
;
HLPHDR: DB      'THE FOLLOWING ARE VALID SET COMMANDS:$'
;
HLPMSG: DB      '     SET BAUD <110>  or <300>  or <1200>',CR,LF
       DB      '              <2400> or <4800) or <9600>',CR,LF
       DB      '     SET PARITY <NONE> or <ODD> or <EVEN>',CR,LF
       DB      '     SET SPKR <OFF> or <ON> or <DEBUG>',CR,LF
       DB      '     SET WAIT <10> or <30> or <60> or <90>',CR,LF
       DB      '     SET DIAL <TOUCH> or <PULSE>',CR,LF,'$'
;
HLPNOT: DB      'NOTE: SET BAUD defaults to NO parity.$'
;
SPCS1:  DB      '  $'
SPCS2:  DB      '         $'
;
SETFLG: DB      0               ; SET command flag
;
;....
;
; SET BAUD processor
;
STBAUD: MVI     C,BDPARS        ; Function code
       CALL    MEX             ; Let MEX look up code
       JC      SETERR          ; Invalid code
       CALL    PBAUD           ; No, try to set it
       JC      SETERR          ; Not-supported code
       JMP     SETSHO          ; review parameters
;
BDSHOW: LDA     SETFLG          ; Get setflg
       CPI     0FFH            ; Is it a 'SET' operation?
       JNZ     PBPS            ; No, must be dial - just display bps
       CALL    ILPRT           ; Yes, display the 'Baud' prompt
       DB      'Baud rate: ',0
PBPS:   LDA     MSPEED          ; Load modem speed code
       MVI     C,PRBAUD        ; Use MEX function #
       CALL    MEX             ; To print bps
       LXI     D,NORVID        ; Reset video attribute
       CALL    PMSG            ; Issue attribute to term
       MVI     E,' '           ; Followed by space
       MVI     C,CONOUT        ; Use MEX function #
       CALL    MEX             ; Let MEX do it
       MVI     A,0             ; Clear acc
       STA     SETFLG          ; Reset setflg
       RET
;
;....
;
; SET PARITY PROCESSOR
;
STPAR:  LXI     D,PARTBL        ; Point to parity table
       CALL    TSRCH           ; Lookup next input item in table
       JC      SETERR          ; If NOT found, error
       PUSH    PSW             ; A=byte from table
       LDA     MODEBT          ; Get old mode byte
       ANI     0C3H            ; Strip off parity bits, word length
       MOV     B,A             ; Old modebt into B
       POP     PSW             ; Get table entry back
       ANI     3CH             ; Mask parity bits, word length
       ADD     B               ; Adjust new parity values
       STA     MODEBT          ; Store the new mode byte
       CALL    NITMOD          ; (Re)initialize the modem
       JMP     SETSHO          ; Review parameters
;
PASHOW: CALL    ILPRT           ; Show parity mode
       DB      'Parity: ',0
       LDA     MODEBT          ; Get mode byte
       ANI     30H             ; Mask off parity bits
       CPI     10H             ; Bit 4 hi?
       JZ      ODDPAR          ; Yes, ODD parity
       CPI     30H             ; Bits 4,5 hi?
       JZ      EVPAR           ; Yes, EVEN parity
                               ; Else NO parity
NOPAR:  CALL    ILPRT           ; In-line print
       DB      'NONE',0        ; Message
       RET                     ; Return
EVPAR:  CALL    ILPRT           ; In-line print
       DB      'EVEN',0        ; Message
       RET                     ; Return
ODDPAR: CALL    ILPRT           ; In-line print
       DB      'ODD',0         ; Message
       RET                     ; Return
;
PARTBL: DB      'NON','E'+80H   ; Set parity NONE
       DB      0CH,0           ; 8 Bit word length
       DB      'EVE','N'+80H   ; Set parity EVEN
       DB      38H,0           ; Bits 5,4,3 hi (7 bit word length)
       DB      'OD','D'+80H    ; Set parity ODD
       DB      18H,0           ; Bits 4,3 hi (7 bit word length)
       DB      0               ; <<==== TABLE TERMINATOR
;....
;
; SET SPKR processor
;
STSPKR: LXI     D,SPKTBL        ; lookup next input item in table
       CALL    TSRCH
       JC      SETERR          ; if not found, error
       STA     SPBYTE+1        ; store the spkr command
       CALL    NITMOD          ; (re)initialize modem
       JMP     SETSHO          ; review parameters
;
SPSHOW: CALL    ILPRT           ; show spkr mode
       DB      'Speaker: ',0
       LDA     SPBYTE+1        ; get spkr byte
       CPI     '1'
       JZ      SPONPT          ; spkr on part-time
       CPI     '2'
       JZ      SPON            ; spkr on continuously
;
SPOFF:  CALL    ILPRT
       DB      'OFF',0
       RET
;
SPONPT: CALL    ILPRT
       DB      'ON until connect',0
       RET
;
SPON:   CALL    ILPRT
       DB      'ON always',0
       RET
;
SPKTBL: DB      'OF','F'+80H    ; set spkr off
       DB      '0',0
       DB      'O','N'+80H     ; set spkr on 'til connect
       DB      '1',0
       DB      'DEBU','G'+80H  ; set spkr on continuously
       DB      '2',0
       DB      0               ; <<=== table terminator
;
; SET WAIT PROCESSOR
;
STWAIT: LXI     D,WAITBL        ; LOOKUP NEXT INPUT ITEM IN TABLE
       CALL    TSRCH           ;
       JC      SETERR          ; IF NOT FOUND, ERROR
       STA     WABYTE+3        ; STORE THE WAIT MSB VALUE
       MVI     A,'0'           ; FAKE LSB BYTE
       STA     WABYTE+4        ; STORE THE WAIT LSB VALUE
       CALL    NITMOD          ; (RE) INITIALIZE MODEM
       JMP     SETSHO          ; REVIEW PARAMETERS
                               ;
WASHOW: CALL    ILPRT
       DB      'Wait: ',0
       LDA     WABYTE+3
       CALL    TYPE            ; SHOW MSB OF VALUE
       LDA     WABYTE+4        ;
       CALL    TYPE            ; SHOW LSB OF VALUE
       CALL    ILPRT
       DB      ' seconds for carrier',0
       RET                     ;
;
WAITBL: DB      '1','0'+80H     ; "SET WAIT 10"
       DB      '1',0
       DB      '3','0'+80H     ; "SET WAIT 30"
       DB      '3',0
       DB      '6','0'+80H     ; "SET WAIT 60"
       DB      '6',0
       DB      '9','0'+80H     ; "SET WAIT 90"
       DB      '9',0
       DB      0
;
;.....
;
; SET DIAL PROCESSOR
;
STDIAL: LXI     D,DIATBL        ; LOOKUP NEXT INPUT ITEM IN TABLE
       CALL    TSRCH
       JC      SETERR          ; IF NOT FOUND, ERROR
       STA     TPULSE          ; STORE THE DIAL COMMAND
       CALL    NITMOD          ; (RE) INITIALIZE MODEM
       JMP     SETSHO          ; REVIEW PARAMETERS
                               ;
DISHOW: CALL    ILPRT           ; SHOW DIAL MODE
       DB      'Dial:  ',0
       LDA     TPULSE          ; GET DIAL BYTE
       CPI     'T'             ;
       JZ      TTONE           ; TOUCH TONE
                               ;
PDIAL:  CALL    ILPRT           ; PRINT
       DB      'Pulse',0       ; PULSE DIAL MESSAGE
       RET                     ; AND RETURN
                               ;
TTONE:  CALL    ILPRT           ; PRINT
       DB      'Touch Tone',0  ; TONE DIAL MESSAGE
       RET                     ; AND RETURN
                               ;
; DIAL ARGUMENT TABLE
;
DIATBL: DB      'TOUC','H'+80H  ; TOUCH TONE
       DB      'T',0
       DB      'PULS','E'+80H  ; PULSE DIAL
       DB      'P',0
       DB      0
;
;.....
;
; Compare next input-stream item in table @DE; CY=1
; if not found, else HL=matched data item
;
TSRCH:  MVI     C,LOOKUP        ; Get function code
       JMP     MEX             ; Pass to MEX processor
;
;....
; Print in-line message ... blows away C register
;
ILPRT:  MVI     C,ILP           ; Get function code
       JMP     MEX             ; Go do it
;
;....
;
; NOTE:  Must terminate prior to 0B00H
;
         END