;                       CHAT.ASM ver 1.5
;                       (revised 1/2/81)
;
;    An interactive program to allow a remote user to "chat"
;      with the local Remote CP/M system operator.
;
;               Originally by Roderick W. Hart
;
;This program is to be used by a local RCPM operator to conduct two-way
;communications with a remote caller.  Operator acknowledges "chat"
;request by pressing the special code key designated at "ACK" below.
;
;When in the chat mode, lines are automatically limited to 63
;characters. A  CR and LF is inserted automatically on the first
;space typed after the 57th character.
;
;01/02/81 Fixed TRUE/FALSE equates (FALSE was never used), changed
;         signon message, fixed conditional on ORG statement,
;         cleaned up file. (KBP)
;
;12/20/80 Modified so no warm boot on exit, TRUE/FALSE equates
;         for ALTCPM, FASTCLK, MPMPRL, MINICBBS (or CBBS) message.
;         Also inform user to use CTL-C to exit.  By Kelly Smith.
;
;12/14/80 Modified to use direct calls to CBIOS I/O to make
;         compatible with CP/M 1.4, 2.x, and MP/M.  (KBP)
;
;12/09/80 Rewritten to optimize code, correct stack problems,
;         add backspace routine, reduce number of bells,
;         add user selectable operator acknowledge code,
;         eliminate unnecessary subroutines, add additional
;         comments and add base equare for ALTCPM.
;           By Keith Petersen W8SDZ, and Dave Hardy
;
FALSE   EQU     0         ;DEFINE FALSE
TRUE    EQU     NOT FALSE ;DEFINE TRUE
;
;Conditional assembly switches
;
STDCPM  EQU     TRUE    ;TRUE IF STANDARD CP/M
ALTCPM  EQU     FALSE   ;TRUE IF ALTERNATE CP/M (HEATH H8 & TRS-80 MODEL I)
MPMPRL  EQU     FALSE   ;TRUE IF MP/M PROGRAM RELOCATABLE FORMAT
FASTCLK EQU     FALSE   ;TRUE IF 4 MHZ SYSTEM CLOCK
CBBS    EQU     FALSE   ;TRUE IF CBBS MESSAGE (MINICBBS = FALSE)
;
;Define base address of system
;
       IF      STDCPM
BASE    EQU     0
       ENDIF
;
       IF      ALTCPM
BASE    EQU     4200H
       ENDIF
;
;Define operator acknowledge code
;
ACK     EQU     1BH     ;ESCAPE KEY
;
;Define number of alert attempts
;
ALERT   EQU     6       ;SIX SEEMS ENOUGH
;
;Define ASCII characters used
;
BEL     EQU     07H     ;BELL
CR      EQU     0DH     ;CARRIAGE RETURN
LF      EQU     0AH     ;LINE FEED
CONTC   EQU     03H     ;CONTROL-C, CHAT-MODE EXIT CHARACTER
BAKSP   EQU     08H     ;BACKSPACE
;
;BDOS equates
;
BDOS    EQU     BASE+5  ;BDOS CALL ADDRESS
PRINT   EQU     9       ;PRINT STRING FUNCTION
;
       IF      MPMPRL
       ORG     BASE
       ENDIF
;
       IF      NOT MPMPRL
       ORG     BASE+100H
       ENDIF
;
START:  LXI     H,0
       DAD     SP       ;GET OLD STACK POINTER
       SHLD    STACK    ;SAVE IT
       LXI     SP,STACK ;SET NEW STACK POINTER
;
;Initialize jumps to CBIOS for direct I/O
;
       LHLD    BASE+1   ;GET POINTER TO CBIOS
       LXI     D,3      ;READY FOR ADD
       DAD     D        ;HL = CONSTAT VECTOR
       SHLD    CSTAT+1  ;MODIFY JUMP
       DAD     D        ;HL = CONIN VECTOR
       SHLD    CONIN+1  ;MODIFY JUMP
       DAD     D        ;HL = CONOUT VECTOR
       SHLD    CONOUT+1 ;MODIFY JUMP
;
;Print signon message
;
       CALL    ILPRT   ;PRINT:
       DB      CR,LF,'CHAT ver 1.5 - Remote conversation utility.'
       DB      CR,LF,'Program returns to system in 30 seconds'
       DB      CR,LF,'if operator is unavailable.'
       DB      CR,LF,CR,LF,'Alerting operator now . ',0
;
;Attempt to alert operator
;
START1: CALL    ILPRT   ;PRINT BELL, PERIOD, SPACE
       DB      BEL,'. ',0
       CALL    DELAY   ;WAIT 5 SECONDS
       LDA     CNT     ;GET ATTEMPT COUNTER
       DCR     A       ;DONE WITH ALERT ATTEMPTS?
       STA     CNT     ;SAVE NEW COUNT
       JNZ     START1  ;NOT DONE WITH ATTEMPTS, DO MORE
       CALL    ILPRT   ;PRINT:
       DB      CR,LF,CR,LF,'Sorry, no operator available - ',CR,LF
       DB      'Please leave your request on '
;
       IF      CBBS
       DB      'CBBS'
       ENDIF
;
       IF      NOT CBBS
       DB      'MINICBBS'
       ENDIF
;
       DB      '.',CR,LF,0
       JMP     EXIT    ;EXIT TO CP/M
;
       IF      FASTCLK ;4 MHZ SYSTEM CLOCK
DELAY:  MVI     A,11    ;NUMBER OF 1 SECOND DELAYS +1 * 2
       ENDIF
;
       IF      NOT FASTCLK
DELAY:  MVI     A,6     ;NUMBER OF 1 SECOND DELAYS + 1
       ENDIF
;
DELAY1: LXI     H,0
       LXI     D,1     ;LOOP DELAY VALUES
;
WAIT:   DAD     D       ;WAIT BETWEEN BELL RINGS
       JNC     WAIT
       DCR     A       ;DONE?
       JNZ     DELAY1  ;NO, LOOP
;
       CALL    CSTAT   ;GET CONSOLE STATUS
       ORA     A       ;CHARACTER WAITING?
       RZ              ;NO, RETURN
       CALL    CONIN   ;GET CHARACTER
       CPI     ACK     ;WAS IT THE RIGHT ANSWER?
       RNZ             ;NO? THEN TRY AGAIN
;
       POP     PSW     ;FIX STACK
       CALL    ILPRT   ;PRINT:
       DB      CR,LF,CR,LF
       DB      'Operator is available, enter CTL-C to exit CHAT'
       DB      CR,LF,BEL,'Please go ahead:'
       DB      CR,LF,CR,LF,0
;
;Conversation routine - uses direct CBIOS I/O to
;prevent control characters from being echoed.
;
CONT:   CALL    CONIN   ;GET CONSOLE INPUT WITH NO ECHO
       CPI     CONTC   ;CONTROL-C ?
       JZ      EXIT    ;YES, EXIT TO CP/M
       CPI     CR      ;CARRIAGE RETURN?
       JZ      CRLF    ;YES, SEND CRLF
       CPI     BAKSP   ;BACKSPACE?
       JZ      BACKIT  ;YES, DO BACKSPACE SPACE BACKSPACE
       CPI     ' '     ;SPACE OR ABOVE?
       JC      CONT    ;IT'S A CTL CHARACTER, CONTINUE LOOPING
       PUSH    PSW     ;SAVE CHARACTER ON STACK
       MOV     C,A     ;CHARACTER TO C FOR CBIOS
       CALL    CONOUT  ;SEND CHARACTER TO CONSOLE
       POP     B       ;GET CHARACTER TO B FROM STACK
       LDA     LCNT    ;GET CHARACTER COUNT
       INR     A       ;INCREMENT COUNTER
       STA     LCNT    ;SAVE NEW COUNT
       CPI     63      ;AT END OF LINE LIMIT?
       JZ      CRLF    ;YES, GIVE AUTO CRLF
       CPI     58      ;NEAR END OF LINE LIMIT?
       JC      CONT    ;NO, CONTINUE LOOPING
       MOV     A,B     ;GET CHARACTER
       CPI     ' '     ;SPACE?
       JNZ     CONT    ;NO, CONTINUE LOOPING
;
CRLF:   CALL    ILPRT   ;PRINT:
       DB      CR,LF,0
       XRA     A       ;ZERO CHARACTER COUNTER
       STA     LCNT
       JMP     CONT    ;CONTINUE LOOPING
;
BACKIT: LDA     LCNT    ;GET CHARACTER COUNT
       DCR     A       ;SUBTRACT ONE BECAUSE OF BACKSPACE
       JM      CONT    ;DONT GO PAST ZERO
       STA     LCNT    ;SAVE NEW COUNT
       CALL    ILPRT   ;PRINT
       DB      BAKSP,' ',BAKSP,0
       JMP     CONT    ;CONTINUE LOOPING
;
;Inline print routine
;
ILPRT:  XTHL            ;SAVE HL, GET MSG
;
ILPLP:  MOV     C,M     ;GET CHAR
       PUSH    H
       CALL    CONOUT  ;OUTPUT IT
       POP     H
       INX     H       ;POINT TO NEXT
       MOV     A,M     ;TEST
       ORA     A       ;...FOR END
       JNZ     ILPLP
       XTHL            ;RESTORE HL, RETURN ADDRESS
       RET             ;RETURN PAST MESSAGE STRING
;
EXIT:   LHLD    STACK   ;GET OLD CP/M (OR MP/M) STACK
       SPHL            ;RESTORE OLD STACK POINTER
       RET             ;RETURN TO CCP
;
CSTAT:  JMP     $-$     ;MODIFIED AT INIT
;
CONIN:  JMP     $-$     ;MODIFIED AT INIT
;
CONOUT: JMP     $-$     ;MODIFIED AT INIT
;
CNT:    DB      ALERT   ;ALERT COUNTER
LCNT:   DB      0       ;LINE POSITION COUNTER
;
       DS      64      ;ROOM FOR 32 LEVEL STACK
STACK   DS      2       ;OLD CP/M (OR MP/M) STACK SAVED HERE
;
       IF      MPMPRL
       DB      0       ;FORCE ALLOCATION OF STORAGE SPACE
       ENDIF
;
       END     START