;
; MODULE: T3T-24-1 (Telephone Interface) for Hayes-compatible 2400bps modems
; Author: David McCord/Richard Conn
; Version: 1.0
; Date: 23 May 86
; Previous Versions: Richard Conn wrote T3TI-SM v1.2, which this is based on.
; Comments: This TI supports 300/1200/2400bps Hayes-compatible modems.  A key
;           compatibility point is that the modem return the terse result code
;           "10" on CONNECT 2400.  Modems that should work with this TI include
;           the Hayes 2400, USR Courier 2400, and Racal-Vadic 2400V.  Developed
;           and tested on a Courier 2400.  Baud rate is automatically set upon
;           connection in answer or originate modes.  The answer routines have
;           been rewritten from the original to NOT use modem auto-answer
;           functions, as this can lead to the modem answering the phone when
;           it shouldn't.
;
       ORG     700H            ; BASE ADDRESS (700H - 9FFH)
;
;  ACCESS TO FILER$SERVER WITHIN T3ANSWER, T3DIAL, T3HANGUP, T3INIT
;
FILER$SERVER    EQU     11AH    ; ADDRESS OF ADDRESS
FS$GETSPEED     EQU     0       ; GET PROCESSOR SPEED
FS$WAIT1S       EQU     1       ; WAIT 1 SEC
FS$WAITP1S      EQU     2       ; WAIT 0.1 SEC
FS$WAIT1MS      EQU     3       ; WAIT 0.001 SEC
FS$CST          EQU     4       ; CONSOLE STATUS (Z=RDA)
FS$CIN          EQU     5       ; CONSOLE INPUT
FS$COUT         EQU     6       ; CONSOLE OUTPUT (CHAR IN C)
;
;  ACCESS TO MODEM OVERLAY ROUTINES
;
M1$INIT         EQU     600H            ; INITIALIZE MODEM
M1$ISTAT        EQU     M1$INIT+3       ; INPUT STATUS
M1$OSTAT        EQU     M1$ISTAT+3      ; OUTPUT STATUS
M1$IN           EQU     M1$OSTAT+3      ; INPUT BYTE
M1$OUT          EQU     M1$IN+3         ; OUTPUT BYTE
M1$BREAK        EQU     M1$OUT+3        ; SEND BREAK
M1$CST          EQU     M1$BREAK+3      ; CARRIER STATUS DETECT
M1$SPTAB        EQU     M1$CST+3        ; SPEED BYTE
;
;  ASCII CONSTANTS
;
CR      EQU     0DH
CTRLC   EQU     'C'-'@'
;
;  Telephone System Interface Routines
;
TI$INIT:
       JP      STI$INIT        ; INITIALIZATION
TI$ANS:
       JP      STI$ANS         ; SET ANSWER MODE
TI$HANG:
       JP      STI$HANG        ; HANG UP PHONE
TI$RST:
       JP      STI$RST         ; RING STATUS DETECT
TI$DSTRT:
       JP      STI$DSTRT       ; START DIALING
TI$DSTOP:
       JP      STI$DSTOP       ; STOP DIALING
TI$DIGIT:
       JP      STI$DIGIT       ; DIAL DIGIT
TI$PREPANS:
       JP      STI$PREPANS     ; PREPARE FOR ANSWERING PHONE
TI$GETBAUD:
       JP      STI$GETBAUD     ; RETURN CURRENT BAUD RATE VALUE
;
;  FILER$SERVER INTERFACE FOR TELEPHONE INTERFACE OVERLAY
;  FILER$SERVER CODE IS IN A
;
TI$FS:
       PUSH    HL              ; SAVE HL
       LD      HL,TI$FSRET     ; SET RETURN ADDRESS
       PUSH    HL              ; ... ON STACK
       LD      HL,(FILER$SERVER)       ; GET ADDRESS OF FILER$SERVER
       JP      (HL)            ; "CALL" ROUTINE
TI$FSRET:
       POP     HL              ; RESTORE HL
       RET
;
;  SEND 'ATx' COMMAND TO SMARTMODEM
;
CMD$SEND:
       PUSH    AF              ; SAVE CMD
       LD      A,FS$WAIT1S     ; CODE TO WAIT 1 SECOND
       CALL    TI$FS           ; FILER$SERVER
       LD      A,'A'           ; SEND 'AT'
       CALL    CMD$SEND1
       LD      A,'T'
       CALL    CMD$SEND1
       POP     AF              ; GET CMD
;
;  SEND FURTHER COMMAND CHARS TO SMARTMODEM
;
CMD$SEND1:
       PUSH    AF              ; SAVE CHAR
       CALL    M1$OUT          ; SEND CHAR IN A
       push    bc
       ld      b,10            ; do this 10 times...
cmd$send2:
       ld      a,fs$wait1ms
       call    ti$fs           ; wait a millisecond
       djnz    cmd$send2
       pop     bc              ; when we get here, we waited 10ms for echo
       CALL    FLUSH           ; flush the echo
       POP     AF
       RET
;
;  END SMARTMODEM COMMAND SEQUENCE
;
CMD$END:
       PUSH    AF              ; SAVE A
       LD      A,0DH           ; SEND <CR> AND WAIT FOR <CR>
       CALL    CMD$SEND1       ; SEND CHAR WITH ECHO
       POP     AF              ; RESTORE A
       RET
;
;  WAIT FOR RESPONSE FROM SMARTMODEM COMMAND
;    RETURN DIGIT UNLESS ERROR:
;       A=0FFH if TIMEOUT
;       A=0FEH if USER ABORT
;
ssresponse:
       push    hl
       ld      hl,500          ; super short delay for response (.5 sec)
       jr      respe
SRESPONSE:
       PUSH    HL
       LD      HL,2000         ; SHORT DELAY FOR RESPONSE (2 secs)
       JR      RESPE
RESPONSE:
       PUSH    HL              ; SAVE HL
       LD      HL,30000        ; LARGE DELAY FOR RESPONSE (30 secs)
RESPE:
       LD      (RESP$DELAY),HL
RESP1:
       LD      HL,(RESP$DELAY) ; DELAY FOR RESPONSE
RESP2:
       CALL    M1$ISTAT        ; INPUT CHAR FROM MODEM?
       JR      NZ,RESPM
       LD      A,FS$CST        ; CONSOLE STATUS
       CALL    TI$FS           ; USER ABORT?
       JR      Z,RESP3
       ld      a,fs$wait1ms
       call    ti$fs           ; wait 0.001 sec
       DEC     HL              ; COUNT DOWN
       LD      A,H             ; DONE?
       OR      L
       JR      NZ,RESP2
       POP     HL
       OR      0FFH            ; TIMEOUT CODE
       RET
RESP$DELAY:
       DS      2               ; RESPONSE DELAY
;
; PROCESS USER CHAR
;
RESP3:
       LD      A,FS$CIN        ; GET USER INPUT
       CALL    TI$FS           ; USE FILER$SERVER
       AND     7FH             ; MASK
       CP      CTRLC           ; ABORT?
       JR      NZ,RESP2
       POP     HL              ; RESTORE HL
       LD      A,0FEH          ; USER ABORT
       OR      A
       RET
;
; PROCESS MODEM CHAR
;
RESPM:
       CALL    M1$IN           ; GET CHAR
       AND     7FH             ; MASK
       JR      Z,RESP1         ; FLUSH NULL
       POP     HL              ; RESTORE HL
       RET
;
;  ATTRACT ATTENTION OF SMARTMODEM
;
ATTENTION:
       CALL    M1$CST          ; DO NOTHING IF NO CARRIER
       RET     Z
       CALL    FLUSH           ; FLUSH ANY CHAR
       LD      A,0             ; SEND AT LEAST ONE CHAR FIRST
       CALL    M1$OUT
       LD      A,FS$WAIT1S     ; WAIT 1 SEC
       CALL    TI$FS           ; USE FILER$SERVER
       LD      A,'+'           ; ATTRACT MODEM'S ATTENTION
       CALL    M1$OUT
       CALL    M1$OUT
       CALL    M1$OUT
       CALL    sresponse       ; WAIT FOR RESPONSE OR TIMEOUT
       RET
;
;  FLUSH ANY GARBAGE CHARS FROM COMMAND LINE
;
FLUSH:
       CALL    M1$ISTAT        ; ANY CHARS?
       RET     Z               ; RETURN IF NONE
       CALL    M1$IN           ; GET CHAR
       RET
;
;  Telephone Interface Initialization
;       Function:  Initialize the Modem/UART Interface
;       Input Parameters:  None
;       Output Parameters:  None
;
STI$INIT:
       PUSH    AF              ; SAVE A
       CALL    ATTENTION       ; GET MODEM'S ATTENTION
       LD      A,'Z'           ; RESET MODEM
       CALL    CMD$SEND        ; SEND COMMAND
       CALL    CMD$END         ; SEND <CR>
       CALL    OK              ; GET OK/USER ABORT
       CP      0FEH            ; USER ABORT?
       JR      Z,STI$INI1
       LD      A,'V'           ; SET NON-VERBOSE MODE
       CALL    CMD$SEND        ; SEND COMMAND
       LD      A,'0'           ; V0 COMMAND
       CALL    CMD$SEND1
       LD      A,'X'           ; SET EXTENDED COMMAND SET
       CALL    CMD$SEND1       ; SEND COMMAND
       LD      A,'4'           ; Enable result codes 0 thru 10
       CALL    CMD$SEND1
       ld      a,'S'           ; disable auto-answer if turned on somehow
       call    cmd$send1
       ld      a,'0'
       call    cmd$send1
       ld      a,'='
       call    cmd$send1
       ld      a,'0'
       call    cmd$send1
       CALL    CMD$END         ; SEND <CR>
       CALL    OK1             ; GET OK/USER ABORT
STI$INI1:
       CALL    FLUSH           ; FLUSH RESPONSES
       POP     AF              ; RESTORE A
       RET
;
; GET RESPONSE CODE OF 'OK' OR '0'
;
OK:
       CALL    sresponse       ; GET FIRST CHAR
       CP      0FEH            ; USER ABORT?
       RET     Z
       CP      '0'             ; DIGIT '0'?
       JR      Z,OK1A
       CP      'O'             ; LETTER 'O'?
       JR      NZ,OK
       CALL    sresponse       ; GET 'K'
       CP      0FEH            ; USER ABORT?
       RET     Z
       CALL    sresponse       ; GET <CR>
       CP      0FEH            ; USER ABORT?
       RET     Z
       CALL    sresponse       ; GET <LF>
       RET
;
; GET RESPONSE CODE OF '0'
;
OK1:
       CALL    sresponse       ; GET FIRST CHAR
       CP      0FEH            ; USER ABORT?
       RET     Z
       CP      '0'             ; OK?
       JR      NZ,OK1
OK1A:
       CALL    sresponse       ; GET <CR>
       RET
;
;  Prepare Modem to Answer Phone
;       Function:  To condition modem for answering phone
;       Input Parameters:  None
;       Output Parameters:  None
;
STI$PREPANS:
       PUSH    AF
       LD      A,3             ; SELECT 2400 BAUD
       LD      (STI$BRATE),A   ; SET FLAG
       CALL    M1$INIT
       POP     AF
       RET
;
;  Set Modem to Answer
;       Function:  Set Modem to Answer Mode
;       Input Parameters:  None
;       Output Parameters:  A=0 IF NOT SUCCESSFUL, A=0FFH IF SUCCESSFUL
;
STI$ANS:
       XOR     A               ; SET NO BAUD RATE
       LD      (STI$BRATE),A
       ld      a,'A'           ; prepare to send ATA command
       call    cmd$send        ; send it
       call    cmd$end
STI$ANS1:
       call    response
       CP      CR              ; <CR>?
       JR      Z,STI$ANS1
       cp      '1'             ; is it "1" or "10" (300 or 2400)?
       jr      z,sti$ans324    ; If Z, process further
       CP      '5'             ; CONNECT 1200?
       JR      Z,STI$ans12
       xor     a               ; make A 0 (we didn't get a connect)
       ret
sti$ans324:
       call    ssresponse      ; we should have at least a CR or a 0 pending
       cp      cr              ; is it CR?
       jr      z,sti$ans3      ; must be 300 if Z
sti$ans24:
       ld      a,3             ; select 2400 bps
       jr      sti$ansset
STI$ans3:
       LD      A,1             ; SELECT 300 BAUD
       JR      STI$ansSET
STI$ans12:
       LD      A,2             ; SELECT 1200 BAUD
STI$ansSET:
       LD      (STI$BRATE),A   ; SET BAUD RATE
       CALL    M1$INIT         ; INIT USART BAUD RATE
       OR      A,0ffh          ; RETURN CONNECT CODE
       RET
;
;  Hang up telephone
;       Function:  Place the telephone on hook
;       Input Parameters:  None
;       Output Parameters:  None
;
STI$HANG:
       PUSH    AF
       CALL    M1$CST          ; DO NOT HANG UP IF NO CARRIER
       JR      Z,STI$HANG1
       CALL    STI$HANG3       ; HANG UP PHONE
       CP      0FEH            ; USER ABORT?
       JR      Z,STI$HANG1
       CALL    M1$CST          ; STILL CARRIER?
       JR      Z,STI$HANG1
       CALL    STI$HANG3       ; TRY A SECOND TIME TO HANG UP
STI$HANG1:
       POP     AF              ; DO NOTHING SINCE WE ARE ALREADY OFFLINE
       RET
STI$HANG3:
       CALL    ATTENTION       ; GET SMARTMODEM'S ATTENTION
       LD      A,'H'           ; HANG UP PHONE
       CALL    CMD$SEND
       CALL    CMD$END         ; END OF COMMAND
       CALL    sresponse       ; FLUSH RESPONSE DIGIT
       CP      0FEH            ; USER ABORT
       RET     Z
       CALL    sresponse       ; FLUSH RESPONSE <CR>
       RET
;
;  YES and NO Return Codes
;
STI$YES:
       OR      0FFH            ; SET FLAGS
       RET
STI$NO:
       XOR     A               ; NO ANSWER
       RET
;
;  Ring Status Detect
;       Function:  Determines if phone is ringing or not.
;       Input Parameters:  None
;       Output Parameters:  A=0FFH no ring, A=0 ring, A=0FEH user abort
;
STI$RST:
       CALL    ssresponse      ; GET RETURN CODE
       cp      0dh             ; cr?
       jr      z,sti$rst
       CP      '2'             ; RING?
       JR      Z,STI$RST3
       CP      0FEH            ; USER ABORT?
       JR      Z,STI$RST2
STI$RST1:
       LD      A,0FFH          ; RETURN NO RING
STI$RST2:
       OR      A               ; SET FLAGS
       RET
sti$rst3:
       call    ssresponse      ; get trailing CR
       cp      0feh            ; user abort?
       jr      z,sti$rst2
       xor     a
       ret
;
;  Start Dialing
;       Function:  Initiate the dialing process
;       Input Parameters:  None
;       Output Parameters:  A=0 if no dial tone, A=0FFH if dial tone
;
STI$DSTRT:
       CALL    FLUSH           ; FLUSH CHAR IF PRESENT
       LD      A,3             ; SELECT 2400 BAUD
       LD      (STI$BRATE),A   ; SET BAUD RATE
       CALL    M1$INIT
       LD      A,'D'           ; START DIALING
       CALL    CMD$SEND        ; SEND COMMAND
       LD      A,'T'           ; TOUCH TONE DIALING
       CALL    CMD$SEND1
       JP      STI$YES         ; fake dial tone OK, even though we aren't
                               ; off-hook yet
;
;  Stop Dialing
;       Function:  Terminate the dialing process with answer or user abort,
;                  and set baud rate based on result code if answer.
;       Input Parameters:  None
;       Output Parameters:  A=0 and Z if answer, NZ and error code if no ans
;                               Error Code: 0FFH=Timeout, 0FEH=User Abort
;                                       Other=TI Return Code
;
STI$DSTOP:
       ld      a,cr            ; end dial string
       call    cmd$send1
STI$DS1:
       LD      A,FS$CST        ; CHECK CONSOLE STATUS
       CALL    TI$FS           ; USE FILER$SERVER
       JR      Z,STI$DS2       ; NO CONNECTION IF USER ABORT
STI$DSLOOP:
       CALL    RESPONSE        ; ANSWER?
       CP      0FFH            ; TIMEOUT?
       JR      Z,STI$DS1
       CP      0FEH            ; USER ABORT
       JR      Z,STI$DS2E
       CP      '2'             ; RING?
       JR      Z,STI$DSLOOP
       CP      CR              ; <CR>
       JR      Z,STI$DSLOOP
       CP      '9'+1           ; CHECK RANGE
       JR      NC,STI$DS1
       CP      '0'             ; CHECK RANGE
       JR      C,STI$DS1
       CP      '1'             ; is it a "1" or "10"?
       JR      Z,STI$DS324     ; process more if so
       CP      '5'             ; CONNECTED AT 1200 BAUD?
       ret     nz
       LD      A,2             ; SELECT 1200 BAUD
STI$DSB:
       LD      (STI$BRATE),A   ; SET BAUD RATE FLAG
       CALL    M1$INIT         ; SET BAUD RATE
       XOR     A               ; RETURN CONNECT CODE
       RET
STI$DS2:
       LD      A,FS$CIN        ; GET CHAR
       CALL    TI$FS           ; USE FILER$SERVER
       AND     7FH
       CP      CTRLC           ; ABORT?
       JR      NZ,STI$DS1
STI$DS2E:
       LD      A,0FEH          ; SET USER ABORT
       OR      A
       RET
sti$ds324:
       call    ssresponse      ; there is at least a CR or 0 pending
       cp      cr              ; was it cr, not 0?
       jr      z,sti$ds3       ; if yes, go set 300 baud
sti$ds24:
       ld      a,3             ; select 2400 bps
       jr      sti$dsb
STI$DS3:
       LD      A,1             ; SELECT 300 BAUD
       JR      STI$DSB
;
;  Dial Digit
;       Function:  Dial an individual digit
;       Input Parameters:  A=ASCII for digit to dial
;       Output Parameters:  None
;
STI$DIGIT:
       PUSH    AF
       CP      ' '             ; DON'T SEND SPACES
       jr      z,sti$digit1
       cp      '-'             ; don't send dashes
       jr      z,sti$digit1
       cp      '('             ; don't send parenthesis
       jr      z,sti$digit1
       cp      ')'             ; other kind
       jr      z,sti$digit1
       CALL    CMD$SEND1       ; SEND DIGIT WITH ECHO
sti$digit1:
       POP     AF
       RET
;
;  Get Baud
;       Function:  Return current baud rate value (from answer or dial)
;       Input Parameters: None
;       Output Parameters: A = Baud Rate and Z flag set
;               A = 0 means undefined
;               A = 1 means  300 baud
;               A = 2 means 1200 baud
;
STI$GETBAUD:
       LD      A,(STI$BRATE)   ; GET VALUE
       OR      A               ; SET FLAGS
       RET
;
;  BAUD RATE FLAG
;       A = 0 IF NONE
;       A = 1 IF  300 BAUD
;       A = 2 IF 1200 BAUD
;
STI$BRATE:
       DB      0               ; FLAG BUFFER
;
;               END of Telephone Interface Routines
;
       DB      'End of TI-2400'

       END