;       TITLE   'MEX DATEC 212 OVERLAY V1.0'
;
; Datec 212 overlay for MEX: revision 1.0
; Modified from MXO-SM10.ASM by Ted H. Emigh 25 May 1984 (emigh@ecsvax)
;
; Last revision: 25 May 1984, THE
;
; This modules adapts MEX for the Datec 212.  The main function
; of this module is to provide dialing capability; the disconnect
; vector is ancillary.
;
; The only conditional you might want to change in this
; module is the DISC equate below -- if left on, MEX will
; use the Datec 212's disconnect code.  If you prefer to
; provide your own in your overlay's DISCV vector (e.g.,
; by dropping DTR), then set DISC to FALSE and re-assemble.
; (If you don't understand this, then play it safe, and
; leave the equate set as it is).
;
; This overlay will work with any modem overlay that terminates
; prior to 0B00H
;
FALSE   EQU     0
TRUE    EQU     NOT FALSE
;
;
DISC    EQU     TRUE            ;<<== CHANGE TO FALSE IF YOU DISC. WITH DTR
ECHOSW  EQU     TRUE            ;<<== TRUE IF COMMANDS TO MODEM ARE ECHOED
                               ;       BY THE MODEM
VERBOS  EQU     TRUE            ;<<== TRUE IF MODEM MESSAGES ARE ECHOED ON
                               ;       THE CONSOLE
LFSW    EQU     TRUE            ;<<== TRUE IF CR/LF AFTER DATEC MESSAGES
;
; SYSTEM CONSTANTS
;
TPULSE  EQU     0105H           ;TONE/PULSE FLAG IN MODEM OVERLAY
DIALV   EQU     0162H           ;LOCATION OF DIAL VECTOR IN OVERLAY
DISCV   EQU     0165H           ;LOCATION OF DISCONNECT VECTOR IN OVERLAY
DIALOC  EQU     0B00H           ;DIALING CODE GOES HERE
MEX     EQU     0D00H           ;"CALL MEX"
;
; FOLLOWING ARE FUNCTION CODES FOR THE MEX SERVICE CALL PROCESSOR
;
INMDM   EQU     255             ;RETURN CHAR FROM MDM IN A, CY=NO CHR IN 100MS
TIMER   EQU     254             ;DELAY 100 MS*REGISTER 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)
CONOUT  EQU     2               ;SIMULATED BDOS FUNCTION 2: CONSOLE OUTPUT
;
CR      EQU     13
LF      EQU     10
;
;
;
       ORG     TPULSE
       DB      'T'             ;T=touch, P=pulse
;
       ORG     DIALV           ;OVERLAY THE DIALING VECTOR
       JMP     DIAL
;
       IF      DISC            ;IF PROVIDING DISCONNECT CODE
       ORG     DISCV           ;OVERLAY THE VECTOR
       JMP     DISCON
       ENDIF
;
; This is the DIAL routine called by MEX to dial a digit. The digit
; to be dialed is passed in the A register.  Note that two special
; codes must be intercepted as non-digits: 254 (start dial sequence)
; and 255 (end-dial sequence).  Mex will always call DIAL with 254
; in the accumulator prior to dialing a number.  Mex will also call
; dial with 255 in A as an indication that dialing is complete.
;
; After the 254-start-dial sequence, MEX will call the overlay with
; digits, one-at-a-time.  MEX will make no assumptions about the dig-
; its, and will send each to the DIAL routine un-inspected (some modems,
; like the Datec 212, allow special non-numeric characters in the
; phone number, and MEX may make no assumptions about these).
;
; After receiving the end-dial sequence (255) the overlay must take
; whatever end-of-dial actions are necessary *including* waiting for
; carrier at the distant end.  The overlay should monitor the keyboard
; during this wait (using the MEX keystat service call), and return
; an exit code to MEX in the A register, as follows:
;
;       0 - Carrier detected, connection established
;       1 - Far end busy (only for modems that can detect this condition)
;       2 - No answer (or timed out waiting for modem response)
;       3 - Keyboard abort (^C only: all others should be ignored)
;       4 - Error reported by modem
;
; <No other codes should be returned after an end-dial sequence>
;
; The overlay should not loop forever in the carrier-wait routine, but
; instead use either the overlay timer vector, or the INMDMV (timed 100
; ms character wait) service call routine.
;
; The DIAL routine is free to use any of the registers, but must return
; the above code after an end-dial sequence
;
       ORG     DIALOC
;
DIAL:   LHLD    DIALPT          ;FETCH POINTER
       CPI     254             ;START DIAL?
       JZ      STDIAL          ;JUMP IF SO
       CPI     255             ;END DIAL?
       JZ      ENDIAL          ;JUMP IF SO
;
; Not start or end sequence, must be a digit to be sent to the modem
;
       MOV     M,A             ;PUT CHAR IN BUFFER
       INX     H               ;ADVANCE POINTER
       SHLD    DIALPT          ;STUFF PNTR
       RET                     ;ALL DONE
;
; Here on a start-dial sequence
;
STDIAL: LXI     H,DIALBF+1      ;SET UP BUFFER POINTER
       SHLD    DIALPT
       RET
;
; Here on an end-dial sequence
;
ENDIAL: XRA     A               ;RESET DISCONNECT FLAG
       STA     DSCFLG
       MVI     M,CR            ;STUFF END-OF-LINE INTO BUFFER
       INX     H               ;FOLLOWED BY TERMINATOR
       MVI     M,0
       LDA     TPULSE          ;GET OVERLAY'S TOUCH-TONE FLAG
       STA     DIALBF          ;PUT INTO STRING
       LXI     H,ATTN          ;GET MODEM'S ATTENTION
       CALL    MSEND
       MVI     A,3             ;WAIT 3 SECONDS FOR RESPONSE
       STA     TIME
       CALL    RESPON
       CPI     6               ;SEE IF MODEM IS READY
       MVI     A,4             ;SET FOR MODEM ERROR
       RNZ
       LXI     H,DIALBF        ;POINT TO DIALING STRING
       CALL    MSEND           ;SEND IT
       CALL    RESPON          ;WAIT 3 SECONDS FOR RESPONSE
       CPI     7               ;SEE IF MESSAGE "NUMBER STORED"
       MVI     A,4             ;SET FOR MODEM ERROR
       RNZ
       LXI     H,DIALCM        ;FINALLY, DIAL THE NUMBER
       CALL    MSEND           ;SEND IT
       CALL    RESPON          ;WAIT 3 SECONDS FOR A RESPONSE
       CPI     5               ;SEE IF MODEM IS DIALING
       MVI     A,4             ;SET FOR MODEM ERROR
       RNZ
       MVI     A,60            ;WAIT 60 SECONDS FOR RESPONSE
       STA     TIME
       CALL    RESPON
       CPI     5               ;ADJUST RESPONSE TO 0-4
       RC
       MVI     A,4             ;RESPONSE ABOVE 4 ARE ERRORS
       RET
;
; THE FOLLOWING LOOP WAITS FOR A RESPONSE FROM THE MODEM (UP TO
; 60 SECONDS: YOU MAY CHANGE THIS VALUE IN THE FOLLOWING LINE)
;
RESPON: XRA     A               ;ZERO THE MESSAGE FLAG
       STA     MSGFLG
       LDA     TIME            ;GET MAXIMUM TIME TO WAIT FOR RESPONSE
       MOV     C,A
MWLP:   PUSH    B
       MVI     B,1             ;CHECK FOR A CHAR, UP TO 1 SEC WAIT
       MVI     C,TMDINP        ;DO TIMED INPUT
       CALL    MEX
       POP     B
       JNC     MTEST           ;JUMP IF MODEM HAD A CHAR
       PUSH    B               ;NO, TEST FOR CONTROL-C FROM CONSOLE
       MVI     C,CHEKCC
       CALL    MEX
       POP     B
       JNZ     MNEXT           ;IF NOT, JUMP
       LDA     DSCFLG          ;SEE IF ^C ALREADY HIT
       ORA     A
       JNZ     MWLP            ;ALREADY HIT, IGNORE THIS ONE
       DCR     A               ;SET DSCFLG
       STA     DSCFLG
       LXI     H,DISCD         ;MAKE THIS ROUTINE EXIT THROUGH DISCD
       PUSH    H
       JMP     MWLP            ;WAIT FOR ANOTHER MODEM CHARACTER
MNEXT:  DCR     C               ;NO
       JNZ     MWLP            ;CONTINUE
;
; ONE MINUTE WITH NO MODEM RESPONSE (OR NO CONNECTION)
;
MTIMO:  MVI     A,2             ;RETURN TIMEOUT CODE
       RET
;
; DATA USED DURING WAIT FOR RESPONSE FROM MODEM
;
TIME:   DB      0               ;TIME (IN SECONDS) TO WAIT
;
; MODEM GAVE US A RESPONSE, CHECK IT
;
MTEST:
;
IF VERBOS
       CALL    CDISP           ;DISPLAY THE CHARACTER
ENDIF
;
       ANI     7FH             ;IGNORE ANY PARITY
       CALL    MANAL           ;TEST THE RESPONSE
       JC      MWLP            ;GO TRY AGAIN IF UNKNOWN RESPONSE
       MOV     A,B             ;A=RESPONSE
       PUSH    PSW             ;SAVE IT
MTLP:   MVI     C,INMDM         ;EAT ANY ADDITIONAL CHARS FROM DATEC
       CALL    MEX
;
IF VERBOS
       CNC     CDISP           ;DISPLAY THE CHARACTER (DOES NOT EFFECT CARRY)
ENDIF
;
       JNC     MTLP            ;UNTIL 100MS OF QUIET TIME
       POP     PSW             ;RETURN THE CODE
       RET
;
MANAL:  MOV     B,A             ;SAVE CHARACTER
       LDA     MSGFLG          ;SEE IF CONTINUATION OF MESSAGE
       ORA     A
       JNZ     CMSG            ;CONTINUATIN OF MESSAGE
       MOV     A,B             ;RESTORE CHARACTER
       CPI     'O'             ;"ON LINE" OR "OFF LINE"?
       JZ      OMSG
       CPI     'N'             ;"NO CARRIER", "NUMBER STORED", OR
                               ;"NO NUMBER STORED"
       JZ      NMSG
;
; RETURN CODE 0
;
       MVI     B,0             ;PREP CONNECT CODE
       CPI     '1'             ;NUMERIC VERSION OF "ON LINE"
       RZ
;
; RETURN CODE 2
;
       MVI     B,2
       CPI     '3'             ;NUMERIC VERSION OF "NO CARRIER"
       RZ
;
; RETURN CODE 4
;
       MVI     B,4             ;PREP MODEM ERROR
       CPI     'E'             ;"ERROR"?
       RZ
       CPI     '4'             ;NUMERIC VERSION OF "ERROR"
       RZ
;
; RETURN CODE 5
;
       INR     B
       CPI     'D'             ;"DIALING'?
       RZ
       CPI     '5'             ;NUMERIC VERSION OF "DIALING"
       RZ
       CPI     '6'             ;NUMERIC VERSION OF "DIALING 1ST NUMBER"
       RZ
       CPI     '7'             ;NUMERIC VERSION OF "DIALING 2ND NUMBER"
       RZ
;
; RETURN CODE 6
;
       INR     B
       CPI     'R'             ;USED FOR THIS ROUTINE FOR
       RZ                      ;"READY"?
       CPI     '0'             ;NUMERIC VERSION OF "READY"
       RZ
;
; RETURN CODE 7
;
       INR     B
       CPI     '8'             ;NUMERIC VERSION OF "NUMBER STORED"
       RZ
;
; RETURN CODE 8
;
       INR     B
       CPI     '9'             ;NUMERIC VERSION OF "OFF LINE"
       RZ
;
; RETURN CODE 9
;
       INR     B
       CPI     'A'             ;NUMERIC VERSION OF "NO NUMBER STORED"
       RZ
;
; FINISHED WITH RECOGNIZABLE CODES
;
       CPI     CR              ;IGNORE CARRIAGE RETURNS
       STC
       RZ
;
; UNKNOWN RESPONSE, RETURN CARRY TO CALLER. BUT FIRST,
; FLUSH THE UNKNOWN RESPONSE LINE FROM THE MODEM.
;
WTLF:   CPI     LF              ;LINEFEED?
       STC
       RZ                      ;END IF SO
WTLF1:  MVI     C,INMDM         ;NO. GET NEXT CHAR
       CALL    MEX
;
IF VERBOS
       CNC     CDISP           ;DISPLAY THE CHARACTER (DOES NOT EFFECT PSW)
ENDIF
;
       JNC     WTLF            ;UNLESS BUSY, LOOP
       RET
;
; CONTINUATION OF MESSAGE -- NOT ABLE TO DISTINGUISH
; WITH THE FIRST LETTER.  USE THE FOURTH LETTER FOR "N"
; MESSAGES AND THE SECOND LETTER WITH "O" MESSAGES
;
CMSG:   RAL                     ;SEE IF "O" OR "N" MESSAGE
       JNC     CNMSG           ;"N" MESSAGE
;
; RETURN CODE 0
;
       STA     MSGFLG          ;RESET MESSAGE FLAG
       MOV     A,B             ;GET CHARACTER
       MVI     B,0
       CPI     'N'             ;"ON LINE"
       RZ
;
; RETURN CODE 8
;
       MVI     B,8
       CPI     'F'             ;"OFF LINE"
       RZ
       JMP     WTLF            ;UNKNOWN RESPONSE
;
; CHECK FOURTH LETTER FOR "N" MESSAGES
;
CNMSG:  RAR
       INR     A               ;A = LETTER #
       CPI     4
       JC      GETNXT          ;IGNORE THIS LETTER, GET ANOTHER
       MOV     A,B
;
; RETURN CODE 2
;
       MVI     B,2
       CPI     'C'             ;"NO CARRIER"
       RZ
;
; RETURN CODE 7
;
       MVI     B,7
       CPI     'B'             ;"NUMBER STORED"
       RZ
;
; RETURN CODE 9
;
       MVI     B,9
       CPI     'N'             ;"NO NUMBER STORED"
       RZ
       JMP     WTLF            ;UNRECOGNIZED RESPONSE
;
; GET THE NEXT CHARACTER IN THE MESSAGE
;
GETNXT: STA     MSGFLG          ;UPDATE MESSAGE FLAG
       RET                     ;CARRY FLAG IS SET
;
; INITIALIZE THE "O" MESSAGE SEARCH
;
OMSG:   MVI     A,80H           ;SET THE MESSAGE FLAG FOR "O" MESSAGE
       STA     MSGFLG
       STC                     ;GET ANOTHER CHARACTER
       RET
;
; INITIALIZE THE "N" MESSAGE SEARCH
;
NMSG:   MVI     A,1             ;SET THE MESSAGE FLAG FOR "N" MESSAGE
       STA     MSGFLG
       STC                     ;GET ANOTHER CHARACTER
       RET
;
; MESSAGE FLAG
;  SIGNALS WHETHER OR NOT A RESOLUTION OF AN "O" OR "N" MESSAGE
;  IS IN PROGRESS
MSGFLG: DS      1
;
; SEND A TO THE CONSOLE FOR VERBOS OPTION
;
IF VERBOS
CDISP:  PUSH    PSW
       PUSH    H
       PUSH    D
       PUSH    B
       ANI     7FH             ;STRIP HIGH BIT
       MOV     E,A
       MVI     C,CONOUT
       CALL    MEX             ;SEND TO THE CONSOLE
       POP     B
       POP     D
       POP     H
       POP     PSW
       RET
ENDIF
;
; FOLLOWING ROUTINE DISCONNECTS THE MODEM USING DATEC
; CODES. ALL REGISTERS ARE AVAILABLE FOR THIS FUNCTION
; NOTHING RETURNED TO CALLER
;
DISCD:  CALL    DISCV           ;DISCONNECT THE MODEM
                               ;GO TO DISCV IN CASE DISC=FALSE
       MVI     A,3             ;^C CODE FOR DIAL ROUTINE
       RET
;
DSCFLG: DB      0               ;DISCONNECT FLAG
;
IF      DISC
;
DISCON: LXI     H,MATN          ;SEND '^D^D^D'
       CALL    MSEND
       MVI     A,60            ;MAXIMUM OF 60 SECONDS TO WAIT
       STA     TIME            ;__FOR MODEM TO DISCONNECT
       CALL    RESPON
       RET
;
MATN:   DB      'D'-40H,'D'-40H,'D'-40H,0
;
ENDIF
;
; DATEC UTILITY ROUTINE: SEND STRING TO MODEM
;
MSEND:  MOV     A,M             ;FETCH NEXT CHARACTER
       INX     H
       ORA     A               ;END?
       RZ                      ;DONE
       PUSH    H
       PUSH    PSW             ;SAVE CHARACTER
MSEND1: MVI     C,SNDRDY        ;WAIT FOR MODEM READY
       CALL    MEX
       JNZ     MSEND1
       POP     B               ;GET CHARACTER
       MVI     C,SNDCHR        ;SEND THE CHARACTER
       CALL    MEX
;
IF ECHOSW
       MVI     C,INMDM         ;DELAY TIL ECHO, OR 100MS
       CALL    MEX
ENDIF
;
       POP     H
       JMP     MSEND
;
; DATA AREA
;
ATTN:   DB      'AT',0          ;GET THE MODEM'S ATTENTION
DIALCM: DB      'A/',0          ;DIAL THE NUMBER
DIALPT: DS      2               ;DIAL POSITION POINTER
DIALBF: DS      50              ;NUMBER BUFFER (48 CHAR MAX+CR+NULL+SLOP)
;
       END