TITLE   'MEX Cermetek Infomate 212a overlay V1.1'
;
; (DELETE ABOVE TITLE LINE IF ASSEMBLING WITH ASM)
;
; Cermetek overlay for MEX: revision 1.1
; Written 08/22/84 by Paul Traina with grateful thanks to Ronald G. Fowler
; Last revision: 08/24/84 (PST)
;
; This modules adapts MEX for the Cermetek Infomate 212a Intelligent Modem.
; The main function of this module is to provide dialing capability; the
; disconnect vector is ancillary.
;
;----------------------------------------------------------------
;
; 08/24/84      Updated for MEX version 1.1             -- Paul Traina
;
; 08/22/84      This is based upon original work by RGF.  I can take
;               no credit for the intelligence needed to make this module,
;               but if there is some blame for it malfunctioning, I'll take
;               that, because I was the one who performed the cut-job.
;                                                       -- Paul Traina
;
;----------------------------------------------------------------
;
; This overlay will work with any modem overlay that terminates
; prior to 0900H
;
; System Constants
;
DIALV   EQU     0162H           ; Location of DIAL vector in overlay
DISCV   EQU     0165H           ; Location of DISCONNECT vector in overlay
DIALOC  EQU     0900H           ; Dialing code goes here
MEX     EQU     0D00H           ; "CALL MEX"
;
; Following are function codes for the MEX service call processor
;
INMDM   EQU     255             ; Return char form MDM in A, CY=no chr in 100ms
TIMER   EQU     254             ; Wait B*100ms
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)
ILP     EQU     240             ; Inline print routine
;
CR      EQU     13              ; Ascii carriage-return
LF      EQU     10              ; Ascii line-feed
APPOS   EQU     027H            ; Ascii appostrophe
;
       ORG     DIALV           ; Overlay the dialing vector
       JMP     DIAL
;
; 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. Thus,
; the overlay may use these values to "block" the number, holding it
; in a buffer until it is completely assembled (in fact, that's the
; scheme employed here for the Smartmodem).
;
; 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 Smartmodem, 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
;       5 - No ring detected (only for modems that can detect this condition)
;       6 - No dial tone (only for modems that can detect this condition)
;
; <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 pointer
       RET                     ; All done
;
; Here on a start-dial sequence
;
STDIAL: LXI     H,DIALBF        ; Set up buffer pointer
       SHLD    DIALPT
       RET
;
; Here on an end-dial sequence
;
ENDIAL: MVI     M,0             ; Terminate buffer
       CALL    IMLRN           ; Learn new baud rate
       LXI     H,IMDIAL        ; Point to dialing string
       CALL    IMSEND          ; Send it
       LXI     H,IMEND         ; Point to terminal part of string
       CALL    IMSEND
       MVI     C,INMDM
       CALL    MEX             ; Catch any output from the modem
;
; The following loop waits for a result from the modem (up to
; 60 seconds: You may change this value in the following line)
;
RESULT: MVI     C,60            ; <<== MAXIMUM TIME TO WAIT FOR RESULT
IMWLP:  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     IMTEST          ; Jump if modem had a char
       PUSH    B               ; No, test for ^C from console
       MVI     C,CHEKCC
       CALL    MEX
       POP     B
       JNZ     IMNEXT          ; If not, jump
       CALL    DISCV           ; Disconnect for 1 second if possible
       LXI     H,IMABRT        ; Send abort string
       CALL    IMSEND
WTABRT: MVI     C,INMDM         ; Wait for any garbage
       CALL    MEX
       JNC     WTABRT
       MVI     A,3             ; Return abort code
       RET
IMNEXT: DCR     C               ; No
       JNZ     IMWLP           ; Continue
;
; One minute with no modem response
;
IMTIMO: MVI     A,4             ; Return with modem error
       RET
;
; Modem gave us a result, check it
;
IMTEST: ANI     127             ; Ignore any parity
       CALL    IMANAL          ; Test the result
       JC      RESULT          ; Go try again if unknown response
       MOV     A,B             ; A=result
       PUSH    PSW             ; Save it
IMTLP:  MVI     C,INMDM         ; Eat any additional chars from modem
       CALL    MEX
       JNC     IMTLP           ; Until 100ms of quiet time
       POP     PSW             ; Return the code
       RET
;
IMANAL: MVI     B,0             ; Prep connect code              B=0
       CPI     'A'             ; Answer?
       RZ
       MVI     B,1             ; Prep busy code                 B=1
       CPI     'B'             ; Busy?
       RZ
       MVI     B,2             ; Prep no connect message        B=2
       CPI     'N'             ; No answer?
       RZ
       MVI     B,4             ; Prep error                     B=4
       CPI     'W'             ; Wrong baud rate?
       RZ
       MVI     B,6             ; Prep no dial tone              B=6
       CPI     'X'             ; No phone connected?
       RZ
;
       CPI     'V'             ; Voice (which mex does not support)
       JNZ     WTCR            ; Error
       PUSH    D               ; Message
       PUSH    H
       MVI     C,ILP
       CALL    MEX
       DB      'VOICE ',0
       POP     H
       POP     D
;
; Unknown response, return carry to caller, do not flush unknown response
;
WTCR:   STC                     ; Set flag if so
       RET
;
; Utility routine, learn baud rate
;
IMLRN:  LXI     H,IMLERN
IMLRN1: MVI     C,SNDRDY        ; Wait for modem ready
       CALL    MEX
       JNZ     IMLRN1
       PUSH    H               ; Wait 200ms
       MVI     B,2
       MVI     C,TIMER
       CALL    MEX
       POP     H
       MOV     A,M             ; Fetch next character
       INX     H
       ORA     A               ; End?
       RZ                      ; Done if so
       MOV     B,A             ; No, position for sending
       MVI     C,SNDCHR        ; Nope, send the character
       CALL    MEX
       JMP     IMLRN1
;
; Utility routine: send string to modem
;
IMSEND: MVI     C,SNDRDY        ; Wait for modem ready
       CALL    MEX
       JNZ     IMSEND
       MOV     A,M             ; Fetch next character
       INX     H
       ORA     A               ; End?
       RZ                      ; Done if so
       MOV     B,A             ; No, position for sending
       MVI     C,SNDCHR        ; Nope, send the character
       CALL    MEX
       JMP     IMSEND
;
; DATA AREA
;
IMDIAL: DB      CR,'N'-40H,'N ~',CR,CR,CR ; Init to new attn character
       DB      '~U 1',CR,CR,CR ; Unlisten
       DB      '~D ',APPOS     ; ~D 'num'^M
DIALBF: DS      52              ; 2* 24 char max,+cr+null+slop
DIALPT: DS      2               ; Dial position pointer
IMEND:  DB      APPOS,CR,0      ; End part of dial string
IMABRT: DB      '~',CR,'~',CR,CR,0 ; Abort string
IMLERN: DB      '  XY',CR,0     ; Learn baud rate
;
       END