; MXO-MR11.ASM -- MEX Port Overlay file for the Morrow Descision 11  03-OCT-85
;-----------------------------------------------------------------------------;
; This overlay adapts the MEX modem program for the Morrow Micro  Decision 11.
; This MEX Port overlay digresses from pure by encompassing a Hayes Smartmodem
; feature in  the SET command.  If this offends you in anyway,  set the SMODEM
; flag to "NO" to eliminate.
;
; The SET command used in this overlay will allow the setting of the baud rate
; (speed) of the modem hardware port. As mentioned, the Smartmodem speaker is
; setable by the user  to one of three setting: OFF: such that  the speaker is
; always off, HALF: such that the  speaker is on during the  dialing sequence,
; but turns off when the carrier is detected,  and FULL: the speaker stays  on
; when carrier detected. This is useful when one doesn't wish the stereo to be
; drowned out by the Smartmodem dialing.
;
; A more  detailed description of the calling conventions used by this overlay
; overlay can be found in the PMMI modem overlay (MXO-PMxx.ASM where the  "xx"
; is the current version number).
;-----------------------------------------------------------------------------;
; History as a MEX overlay
;
; 10/02/85 - Stolen from MXO-SZ20.ASM                 (V1.1)    - Stuart Rose
;
;-----------------------------------------------------------------------------;
;
OVERSION        equ     1       ; overlay version number
OREVISION       equ     1       ; overlay revision level
;
;=============================================================================;
; CP/M system addresses                                                       ;
;=============================================================================;
;
WBOOT           equ     0000H   ; address of warm boot jump vector
TPA             equ     0100H   ; address of transient program area
;
;=============================================================================;
; MEX system bytes. This overlay helps MEX remember the baud rate of the      ;
; modem port and speaker volume of the Smartmodem when hopping in and out of  ;
; MEX **DURING THE SAME CALL**. These values are used instead of the overlay  ;
; defaults (MSPEED and VOLUME respectively) when a call-in-progress is de-    ;
; tected on MEX startup. Then these values are used. To protect them, they    ;
; live in the system page (0000H-00FFH), in a location not used by the OS     ;
; (operating system). Generally 0040H-004FH is reserved for CBIOSes and is    ;
; fine for uses, as long as your CBIOS doesn't use it. If you are really un-  ;
; sure, set both values to 0000H, and this feature will be eliminated.        ;
;=============================================================================;
;
MEXBAUD         equ     004FH   ; address of system byte for MEX baud rate
MEXSPKR         equ     004EH   ; address of system byte for MEX speaker volume
;
;=============================================================================;
; MEX service processor address and functions                                 ;
;=============================================================================;
;
MEX             equ     0D00H   ; address of the MEX service processor
INMDM           equ     255     ; A = char from modem,CARRY = no char in 100 ms
TIMER           equ     254     ; delay B, in 100 ms units
TMDINP          equ     253     ; wait B seconds for char, CARRY = no char
CHEKCC          equ     252     ; check for ^C from keyboard, ZERO = 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     ; receive a character from modem (after rcvrdy)
LOOKUP          equ     247     ; table search: see CMDTBL comments for info
PARSFN          equ     246     ; parse filename from input stream
PARSBD          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 next char w/o removing from input stream
GNC             equ     241     ; get next char from input stream, CARRY = none
ILP             equ     240     ; inline print
DECOUT          equ     239     ; decimal output
PRBAUD          equ     238     ; print baud rate
PRNTBL          equ     237     ; print command table CARRY SET for ^C abort
PRID            equ     236     ; print current MEX ID string on console
PRINT           equ     9       ; BDOS/MEX print-string function call
CONOUT          equ     2       ; BDOS/MEX output a character to console call
;
;=============================================================================;
; Define new MEX modes (granted in MEX V1.10 and up)                          ;
;=============================================================================;
;
CMDMOD  equ     0               ; 00 - MEX is in command mode
TRMMOD  equ     1               ; 01 - MEX is in terminal mode
SNDMOD  equ     2               ; 02 - SENDOUT active
KEYMOD  equ     3               ; 03 - Keystring being transmitted
XMDMSND equ     4               ; 04 - File transfer: Christensen-protocol send
XMDMRCV equ     5               ; 05 - File transfer: Christensen-protocol rcv
CISSND  equ     6               ; 06 - File transfer: CIS-protocol send
CISRCV  equ     7               ; 07 - File transfer: CIS-protocol receive
;
;=============================================================================;
; define some ASCII control characters                                        ;
;=============================================================================;
;
NULL            equ     '@'-'@' ; (^@) null
BELL            equ     'G'-'@' ; (^G) bell
TAB             equ     'I'-'@' ; (^I) tab
CR              equ     'M'-'@' ; (^M) carriage return
LF              equ     'J'-'@' ; (^J) line feed
ESC             equ     '['-'@' ; (^[) escape
CTRL$Z          equ     'Z'-'@' ; (^Z) control Z
DEL             equ     7FH     ; delete
EOS             equ     DEL     ; SNDLIN end-of-string character
;
;=============================================================================;
; define some boolean variables                                               ;
;=============================================================================;
;
YES             equ     0ffH    ; affirmative response
NO              equ     000H    ; negative response
TRUE            equ     YES     ; true (affirmative) response
FALSE           equ     NO      ; false (negative) response
;
;=============================================================================;
; MEX dial subroutine return error codes                                      ;
;=============================================================================;
;
CARRIER         equ     0       ; CARRIER DETECTED return code
BUSY            equ     1       ; FAR END BUSY return code
NOANSWER        equ     2       ; NO ANSWER return code
ABORT           equ     3       ; KEYBOARD ABORT return code
ERROR           equ     4       ; MODEM ERROR return code
NORING          equ     5       ; NO RING return code
NODIALTONE      equ     6       ; NO DIAL TONE return code

;=============================================================================;
; MEX system page parameters (are correct for MEX V1.1x)                      ;
; see MEXPATxx for current values.                                            ;
;=============================================================================;
;
PROMPT          equ     MEX+13H ; addr of address of id prompt
CANCHR          equ     MEX+1CH ; addr of cancel character
ERRID           equ     MEX+2EH ; addr of error id flag (0 = no id in err msg)
;
;=============================================================================;
; miscellaneous equates                                                       ;
;=============================================================================;
;
OFF             equ     '0'     ; Smartmodem code for speaker always off
HALF            equ     '1'     ; Smartmodem code for speaker on until CD
FULL            equ     '2'     ; Smartmodem code for speaker always on
;
;=============================================================================;
; MEX format baud rates                                                       ;
;=============================================================================;
;
MEX110          equ     0       ; MEX baud rate of 110
MEX300          equ     1       ; MEX baud rate of 300
MEX450          equ     2       ; MEX baud rate of 450
MEX600          equ     3       ; MEX baud rate of 600
MEX710          equ     4       ; MEX baud rate of 710
MEX1200         equ     5       ; MEX baud rate of 1200
MEX2400         equ     6       ; MEX baud rate of 2400
MEX4800         equ     7       ; MEX baud rate of 4800
MEX9600         equ     8       ; MEX baud rate of 9600
MEX19200        equ     9       ; MEX baud rate of 19200
;
;=============================================================================;
; Baud rate parameters for Morrow Descision 11 Zilog DART                     ;
;=============================================================================;
;
BD300           equ     0C4H    ; 300 baud
BD600           equ     084H    ; 600 baud
BD1200          equ     044H    ; 1200 baud
BD19200         equ     004H    ; 19200 baud
;
;=============================================================================;
; Morrow Descision 11 base port for modem serial port                         ;
;=============================================================================;
;
BASE            equ     062H    ; base port of modem port for MD-11
;
;=============================================================================;
; Morrow initialization values for modem port baud rate, and the Hayes        ;
; Smartmodem speaker volume (the last two values take on values stored in     ;
; the MEX scratch area of the system parameter page when re-entering MEX      ;
; with a call-in-progress).                                                   ;
;=============================================================================;
;
MD$BAUD         equ     MEX1200 ; initial baud rate (speed) for Morrow modem
MD$SPKR         equ     OFF     ; initial speaker volume, speaker always off
;
;=============================================================================;
; Port offsets (from BASE)                                                    ;
;=============================================================================;
;
DPORT           equ     0       ; data port
SPORT           equ     1       ; status port
CPORT           equ     1       ; control port
;
;=============================================================================;
; UAR/T status bits (for Zilog and Plymouth DART)                             ;
;=============================================================================;
;
TBMT            equ     04H     ; transmit buffer empty
DAV             equ     01H     ; data available
DCDLIN          equ     08H     ; carrier detect (use DCD line itself)
;DCDLIN         equ     20H     ; carrier detect (use CTS line)
;
;=============================================================================;
;  Overlay starts here                                                        ;
;=============================================================================;
;
       org     TPA
;
;=============================================================================;
; MDM7xx/MEX parameter page                                                   ;
;=============================================================================;
;
JMPMEX: DS      3               ;(for "jmp START" instruction)          100H
PMODEM: DB      NO              ;yes=PMMI S-100 Modem                   103H
SMODEM: DB      YES             ;yes=HAYES Smartmodem, no=non-PMMI      104H
TPULSE: DB      'T'             ;T=touch, P=pulse (Smartmodem-only)     105H
CLOCK:  DB      40              ;clock speed in MHz x10, 25.5 MHz max.  106H
                               ;20=2 MHh, 37=3.68 MHz, 40=4 MHz, etc.
MSPEED: DB      MD$BAUD         ;0=110 1=300 2=450 3=600 4=710 5=1200   107H
                               ;6=2400 7=4800 8=9600 9=19200 default
BYTDLY: DB      0               ;0=0 delay  1=10ms  5=50 ms - 9=90 ms   108H
                               ;default time to send character in ter-
                               ;minal mode file transfer for slow BBS.
CRDLY:  DB      0               ;0=0 delay 1=100 ms 5=500 ms - 9=900 ms 109H
                               ;default time for extra wait after CRLF
                               ;in terminal mode file transfer
COLUMS: DB      5               ;number of DIR columns shown            10AH
SETFLG: DB      YES             ;yes=user-added Setup routine           10BH
SCRTST: DB      YES             ;Cursor control routine                 10CH
ACKNAK: DB      YES             ;yes=resend a record after any non-ACK  10DH
                               ;no=resend a record after a valid-NAK
BAKFLG: DB      NO              ;yes=change any file same name to .BAK  10EH
CRCDFL: DB      YES             ;yes=default to CRC checking            10FH
TOGCRC: DB      YES             ;yes=allow toggling of CRC to Checksum  110H
CVTBS:  DB      NO              ;yes=convert backspace to rub           111H
TOGLBK: DB      YES             ;yes=allow toggling of bksp to rub      112H
ADDLF:  DB      NO              ;no=no LF after CR to send file in      113H
                               ;terminal mode (added by remote echo)
TOGLF:  DB      YES             ;yes=allow toggling of LF after CR      114H
LOGOK:  DB      NO              ;yes=allow transmission of logon        115H
                               ;write logon sequence at location LOGON
SAVCCP: DB      YES             ;yes=do not overwrite CCP               116H
LOCXCHR:DB      NO              ;yes=local command if EXTCHR precedes   117H
                               ;no=external command if EXTCHR precedes
TOGEXC: DB      YES             ;yes=allow toggling of EXTCHR           118H
LSTTST: DB      YES             ;yes=printer available on printer port  119H
XOFTST: DB      YES             ;yes=checks for XOFF from remote while  11AH
                               ;sending a file in terminal mode
XONWT:  DB      NO              ;yes=wait for XON after CR while        11BH
                               ;sending a file in terminal mode
TOGXOF: DB      YES             ;yes=allow toggling of XOFF checking    11CH
IGNCTL: DB      NO              ;yes=CTL-chars above ^M not displayed   11DH
EXTRA1: DB      0               ;for future expansion                   11EH
;
;=============================================================================;
; Terminal mode escape character (for MDM7xx only)                            ;
;=============================================================================;
;
EXITCHR DB      'E'-'@'         ; ^E = Exit to main menu                11FH
BRKCHR  DB      '@'-'@'         ; ^@ = Send 300 ms. break tone          120H
NOCONN  DB      'N'-'@'         ; ^N = Disconnect from the phone line   121H
LOGCHR  DB      'L'-'@'         ; ^L = Send logon                       122H
LSTCHR  DB      'P'-'@'         ; ^P = Toggle printer                   123H
UNSAVE  DB      'Z'-'@'         ; ^Z = Close input text buffer          124H
TRNCHR  DB      'T'-'@'         ; ^T = Transmit file to remote          125H
SAVCHR  DB      'A'-'@'         ; ^A = Open input text buffer           126H
EXTCHR  DB      '\'-'@'         ; ^\ = Send next character              127H
;
;=============================================================================;
; Overlay parameter page (unused by MEX)                                      ;
;=============================================================================;
;
       ds      2               ;
;
;=============================================================================;
; Modem I/O routines                                                          ;
;=============================================================================;
;
MDMSTAT:JMP     INPSP           ; get modem status                      12AH
       DS      7
;
MDMOUT: JMP     OUTDP           ; output a character to the modem       134H
       DS      7
;
MDMIN:  JMP     INPDP           ; input a character from the modem      13EH
       DS      7
;
;=============================================================================;
; Modem status register send/receive bit test routines                        ;
;=============================================================================;
;
MASKR:  ANI     DAV     ! RET   ; bit to test for receive ready         148H
TESTR:  CPI     DAV     ! RET   ; value of receive bit when ready       14BH
MASKS:  ANI     TBMT    ! RET   ; bit to test for send ready            14EH
TESTS:  CPI     TBMT    ! RET   ; value of send bit when ready          151H
       DS      14              ;                                       154H
;
;=============================================================================;
; MEX subroutine jump table                                                   ;
;=============================================================================;
;
DIALV:  ds      3               ; Smartmodem dial a number              162H
DISCV:  jmp     DISCON          ; disconnect from target system         165H
GOODBV: jmp     GOODBYE         ; MEX un-initialization subroutine      168H
INMODV: jmp     HELLO           ; MEX initialization subroutine         16BH
NEWBDV: jmp     BAUD            ; new baud rate subroutine              16EH
NOPARV: RET ! NOP ! NOP         ; no parity subroutine                  171H
PARITV: RET ! NOP ! NOP         ; new parity subroutine                 174H
SETUPV: jmp     SETCMD          ; Spider/Z SET command subroutine       177H
SMENUV: DS      3               ; not used by MEX                       17AH
VERSNV: jmp     OVRVER          ; display overlay version subroutine    17DH
BREAKV: jmp     SBREAK          ; send a break tone subroutine          180H
ILPRTV: DS      3               ; inline print      (gone by MEX V2.0)  183H
INBUFV: DS      3               ; input buffer      (gone by MEX V2.0)  186H
ILCMPV: DS      3               ; line compare      (gone by MEX V2.0)  189H
INMDMV: DS      3               ; timed modem input (gone by MEX V2.0)  18CH
NXTSNV: DS      3               ; next screen       (gone by MEX V2.0)  18FH
TIMERV: DS      3               ; timer routine     (gone by MEX V2.0)  192H
;
;=============================================================================;
; CLREOS subroutine                                                           ;
; This subroutine will clear the console screen from the current cursor       ;
; position, to the end of the console screen (insure that SCRTST (010AH)      ;
; is set to YES if you wish to use this subroutine).                          ;
;=============================================================================;
;
CLREOS: lxi     D,CLRE          ; clear to end-of-screen                195H
       mvi     C,PRINT         ;
       call    MEX             ;
       ret                     ;
;
;=============================================================================;
; CLRSCN subroutine                                                           ;
; This subroutine will clear the console screen (insure that SCRTST (010AH)   ;
; is set to YES if you wish to use this subroutine).                          ;
;=============================================================================;
;
CLRSCN: lxi     D,CLRS          ; clear screen                          19EH
       mvi     C,PRINT         ;
       call    MEX             ;
       ret                     ;
;
;=============================================================================;
; BOLD subroutine                                                             ;
; This subroutine will turn on the bold attri
bute (insure that SCRTST (010AH) ;
; is set to YES if you wish to use this subroutine).                          ;
;=============================================================================;
;
BOLD:   lda     SCRTST          ; termcap?
       cpi     YES             ;
       rnz                     ; nope
       lxi     D,BLD           ; yep, turn bold on
       mvi     C,PRINT         ;
       call    MEX             ;
       ret                     ;
;
;=============================================================================;
; UNBOLD subroutine                                                           ;
; This subroutine will turn off the bold attribute (insure that SCRTST (010AH);
; is set to YES if you wish to use this subroutine).                          ;
;=============================================================================;
;
UNBOLD: lda     SCRTST          ; termcap?
       cpi     YES             ;
       rnz                     ; nope
       lxi     D,UNBLD         ; yep, turn bold off
       mvi     C,PRINT         ;
       call    MEX             ;
       ret                     ;
;
;=============================================================================;
; Escape sequences for MD-11s                                                 ;
;=============================================================================;
;
CLRE:   db      ESC,'Y','$'     ; clear to end-of-screen
CLRS:   db      ESC,'*','$'     ; clear screen
BLD:    db      '$'             ; turn on character bold attribute
UNBLD:  db      '$'             ; turn off character bold attribute
;
;=============================================================================;
; OVRVER subroutine                                                           ;
; This subroutine will print the overlay id and version on the console.       ;
;=============================================================================;
;
OVRVER: mvi     C,ILP           ; print overlay id and version number
       call    MEX
       db      'Morrow Micro Decision 11 Computer Port Overlay V'
       db      OVERSION + '0','.',OREVISION + '0',CR,LF,0
       call    CIPMSG          ; display "call in progress" if need be
       rc                      ;
       mvi     C,ILP           ; aestetic newline
       call    MEX             ;
       db      CR,LF,0         ;
       ret
;
;=============================================================================;
; GOODBYE subroutine                                                          ;
; This subroutine is executed just prior to exiting from MEX to CP/M. All un- ;
; initialization procedures are done here.                                    ;
;============================================================================;
;
GOODBYE:call    CIPMSG          ; echo "call in progess" if need be
       ret                     ;
;
;=============================================================================;
; CIPMSG subroutine                                                           ;
; This subroutine will display the "call in progress" message (Spider/Z users ;
; are forgetful) if BOTH a carriet is detected AND the current MEX modem port ;
; is not the current CP/M console.                                            ;
;=============================================================================;
;
CIPMSG: call    CDTEST          ; gotta carrier?
       rnc                     ; nope, then don't display "call in progress"
       call    BOLD            ; use bolding if possible
       mvi     C,ILP           ; print a newline
       call    MEX             ;
       db      CR,LF,0         ;
       call    IDMSG           ; blapp out ID prompt if need be
       mvi     C,ILP           ; print "call in progess" message
       call    MEX             ;
       db      '[call in progress]',BELL,CR,LF,0
       call    UNBOLD          ; undo bolding damage if need be
       stc                     ; show "call in progess" message printed
       ret
;
;=============================================================================;
; SBREAK subroutine                                                           ;
; This routine will mimic the function of the BREAK key by sending an         ;
; interrupt to the modem (transmit line held high) for a period of 300 ms.    ;
;=============================================================================;
;
SBREAK: push    H               ; save registers
       push    D               ;
       push    B               ;
       push    PSW             ;
       mvi     A,0FAH          ; force break for 300 ms
       mvi     B,3             ; set duration for 300 ms
       call    TOUTCP          ; do it!
       pop     PSW             ; restore registers
       pop     B               ;
       pop     D               ;
       pop     H               ;
       ret                     ;
;
;=============================================================================;
; DISCON subroutine                                                           ;
; This subroutine will disconnect the modem from the target computer. This    ;
; is done by dropping the DTR line to the modem for a period of 1.5 seconds   ;
; in theory, 300 ms is more than sufficient (this is what a BREAK key does),  ;
; but when the Smartmodem is dialing, a 300 ms pulse is not long enough to be ;
; recognized.                                                                 ;
;=============================================================================;
;
DISCON: push    H               ; save registers
       push    D               ;
       push    B               ;
       push    PSW             ;
       mvi     A,06AH          ; turn off DTR, no break sent
       mvi     B,15            ; set duration for 1.5 seconds
       call    TOUTCP          ; do it!
       pop     PSW             ; restore registers
       pop     B               ;
       pop     D               ;
       pop     H               ;
       ret                     ;
;
;=============================================================================;
; TOUTCP subroutine                                                           ;
; This is a timed output to command port (OUTCP) subroutine. The value in the ;
; A register is output to the command port, then a time delay equal to the    ;
; value of the B register (in 100 ms units) is done.                          ;
;=============================================================================;
;
TOUTCP: push    PSW             ; save UAR/T command
       mvi     A,5             ; write to control register 5
       call    OUTCP           ;
       pop     PSW             ; restore UAR/T command
       call    OUTCP           ; send passed byte to CPORT
       mvi     C,TIMER         ; wait alotted time
       call    MEX             ;
       mvi     A,5             ; write to control register 5
       call    OUTCP           ;
       mvi     A,0EAH          ; turn DTR back on, no break
       call    OUTCP           ;
       ret                     ;
;
;=============================================================================;
; HELLO subroutine                                                            ;
; This subroutine is used to initialize the modem and the modem port. This    ;
; is done via using some of the system reserved bytes in the CP/M system      ;
; parameter page (0000H - 00FFH). There is a 16 byte system scratch area      ;
; (0040H - 004FH) that is never referenced by CP/M. For the Spizer/Z, the     ;
; addresses 0040H - 0042H are reserved for the Jade Double-D Floppy Disk      ;
; Controller. All others are scratch. MEX uses 004FH as the byte reserved     ;
; for stating the current baud rate for the modem port, while 004EH is        ;
; reserved for the current Smartmodem speaker volume. These locations can     ;
; can be checked whenever re-entering MEX. Protocol used:                     ;
;                                                                             ;
;       if a call is in progress (determined by the testing for a             ;
;       carrier detect (CDTEST)), MEX then uses the values stored in          ;
;       then MEX system reserved bytes for modem baud rate (the value         ;
;       is stored in MEX compatible format), and the Smartmodem speaker       ;
;       volume.                                                               ;
;                                                                             ;
;       otherwise set the modem baud rate and Smartmodem speaker volume       ;
;       to the preset values (values set in this overlay or current values    ;
;       when CLONEing MEX).                                                   ;
;                                                                             ;
;=============================================================================;
;
HELLO:  call    CDTEST          ; check for call in progress
       jnc     COLDMEX         ; nope, initialize the modem and port

GETBAUD:lxi     H,MEXBAUD       ; valid MEX baud byte?
       mov     A,H             ;
       ora     L               ;
       jz      GETSPKR         ; nope
       lda     MEXBAUD         ; yep, get the system byte for MEX baud rate
       sta     MSPEED          ; save it

GETSPKR:lxi     H,MEXSPKR       ; valid MEX speaker byte?
       mov     A,H             ;
       ora     L               ;
       rz                      ; nope
       lda     MEXSPKR         ; yep, get the system byte for MEX speaker volume
       sta     VOLUME          ; save it

       ret                     ;
;
; cold starting MEX. load the baud rate and speaker volume with those values
; specified by this overlay.
;
COLDMEX:lda     MSPEED          ; get the initial baud rate
       call    BAUD            ; set it up
       lda     VOLUME          ; get the initial speaker volume
       call    SPEAKER         ; set it up
       ret
;
;=============================================================================;
; IDMSG subroutine                                                            ;
; this subroutine will check whether or not the ID prompt should be displayed ;
; prior to an error message. If so, the prompt will be displayed.             ;
;=============================================================================;
;
IDMSG:  push    H               ; save registers
       push    D               ;
       push    B               ;
       push    PSW             ;
       lda     ERRID           ; ID printed in "call in progress" message?
       cpi     NO              ;
       jz      IDRET           ; nope, then don't!
       mvi     C,PRID          ; yep, then print it!
       call    MEX             ;
IDRET:  pop     PSW             ; restore registers
       pop     B               ;
       pop     D               ;
       pop     H               ;
       ret                     ;
;
;=============================================================================;
; CDTEST subroutine                                                           ;
; This routine will test for a carrier detected on the designated modem       ;
; status line (eithe DCD or DSR, depending on the overlay equates). If a      ;
; carrier is detect then thus subroutine returns with the CARRY set.          ;
;=============================================================================;
;
CDTEST: mvi     A,0             ; read status register 0
       call    OUTCP           ;
       call    INPSP           ; look at the modem port status register
       ani     DCDLIN          ; is there a carrier?
       rz                      ; nope, then return
       stc                     ; yep, set the CARRY and return
       ret                     ;
;
;=============================================================================;
; SET COMMAND:                                                                ;
;                                                                             ;
; This command will allow the user to set a number of hardware dependent      ;
; functions. At the moment the allowable parameters are:                      ;
;                                                                             ;
;       BAUD RATE:      This will allow the baud rate of the current user     ;
;                       port to be changed on the fly. Valid baud rates       ;
;                       are 300, 600, 1200, 19200.                            ;
;                                                                             ;
;       SPEAKER VOLUME: This will allow the user to change the volume of      ;
;                       the speaker of the Hayes Smartmodem. Valid volumes    ;
;                       are OFF = speaker is always off, HALF = speaker       ;
;                       is on until carrier is detected, FULL = speaker       ;
;                       is always on.                                         ;
;                                                                             ;
;       usage:                                                                ;
;                                                                             ;
;                       SET BAUD 9600                                         ;
;                       SET SPEAKER OFF                                       ;
;                                                                             ;
;=============================================================================;
;
SETCMD: call    GETARG          ; any arguments?
       jc      SHWALL          ; if not, go display set parmeters
       LXI     D,CMDTBL
       MVI     C,LOOKUP
       CALL    MEX             ;parse argument
       PUSH    H               ;save any parsed argument adrs on stack
       RNC                     ;if we have one, return to it
       POP     H               ;oops, input not found in table
       jmp     SETERR          ;
;
; Argument table (note last character of set parameter MUST have the MSB
; turned on. MEX uses this as a flag for the end-of-parameter).
;
CMDTBL: DB      '?'+80H                 ; help
       DW      SETHELP
       DB      'BAU','D'+80H           ; "set baud"
       DW      SETBAUD
       DB      'SPEAKE','R'+80H        ; "set speaker"
       DW      SETSPKR
       DB      0                       ;<<=== table terminator
;
;=============================================================================;
; "SET" command (equates to a "SHOW ALL" command)                             ;
;=============================================================================;
;
SHWALL: call    NEWLINE         ; start off with a newline character
       call    BOLD            ; bold the console output
       call    SHWBAUD         ; show the current baud rate
       call    SHWSPKR         ; show the current speaker volume
       call    UNBOLD          ; unbold the console output
       call    NEWLINE         ; terminate with a newline character
       ret                     ;
;
;=============================================================================;
; "SET ?" command (output HELP message to console)                            ;
;=============================================================================;
;
SETHELP:lda     SCRTST          ; cursor control ability?
       cpi     NO              ;
       cnz     CLRSCN          ; yep, then clear the screen
       mvi     C,ILP           ; print out help message to console
       call    MEX             ;
       db      CR,LF
       db      'SET BAUD ',0
       call    BOLD
       mvi     C,ILP
       call    MEX
       db      '<baud-rate>',CR,LF,0
       call    UNBOLD
       lda     SMODEM          ; got a Smartmodem?
       cpi     NO              ;
       jz      NOSM01          ; nope, then don't show "SET SPEAKER"
       call    UNBOLD
       mvi     C,ILP
       call    MEX
       db      'SET SPEAKER ',0
       call    BOLD
       mvi     C,ILP
       call    MEX
       db      '<volume>',CR,LF,0
NOSM01: mvi     C,ILP
       call    MEX
       db      CR,LF
       db      'Baud rate is one of:',CR,LF,0
       call    UNBOLD
       mvi     C,ILP
       call    MEX
       db      '300 600 1200 19200',CR,LF
       db      CR,LF,0
       lda     SMODEM          ; got a Smartmodem?
       cpi     NO              ;
       jz      NOSM02          ; nope, then don't show volume value
       call    BOLD
       mvi     C,ILP
       call    MEX
       db      'Volume is one of:',CR,LF,0
       call    UNBOLD
       mvi     C,ILP
       call    MEX
       db      'OFF     : Smartmodem speaker is always off',CR,LF
       db      'HALF    : Smartmodem speaker is on until carrier detect',CR,LF
       db      'FULL    : Smartmodem speaker is always on',CR,LF
       db      CR,LF,0
NOSM02: ret                     ;
;
;=============================================================================;
; "SET BAUD" command                                                          ;
;=============================================================================;
;
SETBAUD:MVI     C,PARSBD        ;nope, function code: parse a baudrate
       CALL    MEX             ;let MEX look up code
       JC      BAUDERR         ;jump if invalid code
       CALL    BAUD            ;no, try to set it
       JC      BAUDERR         ;if not one of ours, bomb out
       call    NEWLINE         ;show the current baud rate
       call    SHWBAUD         ;
       ret                     ;
;
;=============================================================================;
; "SHOW BAUD" command                                                         ;
;=============================================================================;
;
SHWBAUD:mvi     C,ILP           ; nope, then display current baud rate
       call    MEX             ;
       db      'Modem baud rate is set to ',0
       lda     MSPEED          ; get current baud rate
       mvi     C,PRBAUD        ; let MEX print it
       call    MEX
       call    NEWLINE         ; terminate with newline character
       ret
;
;=============================================================================;
; BAUD subroutine                                                             ;
; This subroutine will set the baud of the current modem port. The new baud   ;
; rate is passed in the A register, and is also stored in the MEX parameter   ;
; page (MSPEED), and the MEX system reserved byte (MEXBAUD). If the new baud  ;
; rate specified is either illegal or not supported, this subroutine returns  ;
; with the CARRY set.                                                         ;
;=============================================================================;
;
BAUD:   PUSH    H               ;don't alter anybody
       PUSH    D
       PUSH    B

       MOV     E,A             ;MSPEED code to DE
       MVI     D,0

       LXI     H,BAUDTBL       ; nope, then fine offset into table
       DAD     D
       MOV     A,M             ;fetch code
       ORA     A               ;0? (means unsupported code)
       jz      BADBAUD         ;yep, show it!
       PUSH    PSW             ;no, set the rate
       mvi     A,0             ; setup control register 0
       call    OUTCP           ;
       mvi     A,0             ;
       call    OUTCP           ;
       mvi     A,1             ; setup control register 1
       call    OUTCP           ;
       mvi     A,0             ;
       call    OUTCP           ;
       mvi     A,2             ; setup control register 2
       call    OUTCP           ;
       mvi     A,0             ;
       call    OUTCP           ;
       mvi     A,3             ; setup control register 3
       call    OUTCP           ;
       mvi     A,0C1H          ; Rx 8 bits, Rx enable
       call    OUTCP           ;
       mvi     A,4             ; setup control register 4
       call    OUTCP           ;
       pop     PSW             ; clock for baud rate, 1 stop bit, no parity
       call    OUTCP           ;
       mvi     A,5             ; setup control register 5
       call    OUTCP           ;
       mvi     A,0EAH          ; DTR on, Tx 8 bits, no break, Tx enable, RTS on
       call    OUTCP           ;
       mvi     A,6             ; setup control register 6
       call    OUTCP           ;
       mvi     A,0             ;
       call    OUTCP           ;
       mvi     A,7             ; setup control register 7
       call    OUTCP           ;
       mvi     A,0             ;
       call    OUTCP           ;
       MOV     A,E             ; get MEX format baud rate
       STA     MSPEED          ; store in MEX
       lxi     H,MEXBAUD       ; valid MEX baud byte in system page?
       mov     A,H             ;
       ora     L               ;
       mov     A,E             ;
       jz      NOMEXB          ; nope
       STA     MEXBAUD         ; store it in the system byte for MEX baud rate
NOMEXB: ORA     A               ; return no-errors
       jmp     BDEXIT          ;

BADBAUD:stc                     ; set CARRY to show bad baud rate specified

BDEXIT: POP     B
       POP     D
       POP     H
       RET
;
; this is the baud rate converstion table. The MEX format baud rate value is
; used as an offset into this table. The grabbed value is the Interfacer 4
; mode register format containing the new baud rate.
;
BAUDTBL:DB      0               ;110 (not supported)
       DB      BD300           ;300
       DB      0               ;450 (not supported)
       DB      BD600           ;600
       DB      0               ;710 (not supported)
       DB      BD1200          ;1200
       DB      0               ;2400 (not supported)
       DB      0               ;4800 (not supported)
       DB      0               ;9600 (not supported)
       DB      BD19200         ;19200
;
;=============================================================================;
; "SET SPEAKER" command                                                       ;
;=============================================================================;
;
SETSPKR:lda     SMODEM          ; got a Smartmodem?
       cpi     NO              ;
       jz      SETERR          ; nope, then show a SET error

       mvi     C,SBLANK        ; yep, then scan for volume argument
       call    MEX
       jc      SPKRERR         ; if no argument, let user know
       lxi     D,SPKTBL        ; parse the argument
       mvi     C,LOOKUP
       call    MEX             ; parse argument
       jc      SPKRERR         ; bad volume argument

       mov     A,L             ; store the new speaker volume
       call    SPEAKER         ; set the Smartmodem speaker volume
       call    NEWLINE         ; show the new speaker volume
       call    SHWSPKR         ;
       ret                     ;
;
; speaker table f
or MEX table search
;
SPKTBL: db      'OF','F'+80H    ; turn speaker off keyword
       db      OFF,OFF         ; Smartmodem ATM code for it
       db      'HAL','F'+80H   ; turn speaker off after carrier detect keyword
       db      HALF,HALF       ; Smartmodem ATM code for it
       db      'FUL','L'+80H   ; turn speaker on keyword
       db      FULL,FULL       ; Smartmodem ATM code for it
       db      0               ; argument table terminator
;
;=============================================================================;
; "SHOW SPEAKER" command                                                      ;
;=============================================================================;
;
SHWSPKR:lda     SMODEM          ; got a Smartmodem?
       cpi     NO              ;
       rz                      ; nope, then don't show speaker volume

       mvi     C,ILP           ; yep, then show the speaker volume
       call    MEX             ;
       db      'Smartmodem speaker ',0
       mvi     C,ILP           ;
       lda     VOLUME          ;
       cpi     OFF             ; speaker always off
       jz      SPKOFF          ;
       cpi     HALF            ; speaker on until carrier detect
       jz      SPKHALF         ;
       cpi     FULL            ; speaker always on
       jz      SPKFULL         ;
SPKUNKN:call    MEX             ; speaker volume status unknown
       db      'volume status not known',CR,LF,0
       ret                     ;
SPKOFF: call    MEX             ; speaker is turned off
       db      'is always turned off',CR,LF,0
       ret                     ;
SPKHALF:call    MEX             ; speaker is set to half
       db      'is turned on until carrier detected',CR,LF,0
       ret                     ;
SPKFULL:call    MEX             ; speaker is set to full
       db      'is always turned on',CR,LF,0
       ret                     ;
;
;=============================================================================;
; SPEAKER subroutine                                                          ;
; This subroutine will set the Smartmodem speaker to the requested volume.    ;
; The new volume value is passed in the A register, and is also stored in the ;
; MEX parameter page (VOLUME), and the MEX system reserved byte (MEXSPKR).    ;
;=============================================================================;
;
SPEAKER:push    H               ; save registers
       push    D               ;
       push    B               ;
       mov     E,A             ; save the new speaker volume

       lda     SMODEM          ; got a Smartmodem?
       cpi     NO              ;
       jz      SPKRET          ; nope, then don't change the speaker volume

       mov     A,E             ; restore the new speaker volume
       sta     VOLUME          ; store the current volume for MEX
       lxi     H,MEXSPKR       ; valid MEX speaker byte in system page?
       mov     A,H             ;
       ora     L               ;
       mov     A,E             ;
       jz      NOMEXS          ; nope
       sta     MEXSPKR         ; store the current volume in reserved byte

NOMEXS: call    SNDESC          ; send the Smartmodem escape seq. if need be
       call    SNDATM          ; send the Smartmodem speaker volume code
       call    SNDATO          ; send the Smartmodem on-line code if need be

SPKRET: pop     B               ; restore registers
       pop     D               ;
       pop     H               ;
       ret
;
;=============================================================================;
; xxxERR subroutines                                                          ;
; These routines blapp out error messages on the console if the user somehow  ;
; screwed up the SET command line (bad syntax, or bad keyword values).        ;
;=============================================================================;
;
SETERR: call    IDMSG           ;print ID prompt if need be
       MVI     C,ILP           ;inline print
       CALL    MEX             ;
       DB      '++ bad SET parameter specified ++',BELL,CR,LF,0
       RET
;
BAUDERR:call    IDMSG           ;print ID prompt if need be
       MVI     C,ILP           ;inline print
       CALL    MEX             ;
       DB      '++ bad baud rate specifed ++',BELL,CR,LF,0
       RET
;
SPKRERR:call    IDMSG           ;print ID prompt if need be
       MVI     C,ILP           ;inline print
       CALL    MEX             ;
       DB      '++ bad speaker volume specifed ++',BELL,CR,LF,0
       RET
;
;=============================================================================;
; SNDSEC subroutine                                                           ;
; This subroutine will place the Smartmodem in command state. If a carrier    ;
; is detected, the Smartmodem escape sequence is sent, sandwiched between     ;
; two guard time delays. An initial null is sent just incase we are in the    ;
; "just CONNECTed" case (IE: Smartmodem has connected to target computer,     ;
; but Morrow hasn't sent anything yet). If there is no carrier, then this   ;
; routine merely returns.                                                     ;
;=============================================================================;
;
SNDESC: call    CDTEST          ; check for call in progress
       rnc                     ; nope, then return
       lxi     H,SMNULL        ; yep, send a null (just CONNECTed case)
       call    SNDLIN          ;
       mvi     B,12            ; yep, goto command mode
       mvi     C,TIMER         ; wait 1.2 seconds
       call    MEX             ;
       lxi     H,SMESCAP       ; send '+++'
       call    SNDLIN          ;
       mvi     B,12            ; wait 1.2 seconds
       mvi     C,TIMER         ;
       call    MEX             ;
       call    EATCODE         ; eat result code
       ret                     ;
;
;=============================================================================;
; SNDCAN subroutine                                                           ;
; This subroutine will send the CANCEL character to the target computer       ;
; system. The primary use of this subroutine is to cancel the Smartmodem      ;
; escape sequence sent to the target system to place the Smartmodem in        ;
; command state. At the target computer end, there is an un-terminated        ;
; command ("+++") that should not be executed.                                ;
;=============================================================================;
;
SNDCAN: lda     CANCHR          ; get the CANCEL character
       sta     CANMSG          ; store in the CANCEL character message
       lxi     H,CANMSG        ; get the CANCEL character message address
       call    SNDLIN          ; send it
       ret                     ;
;
;=============================================================================;
; SNDATM subroutine                                                           ;
; This routine will send the Smartmodem code to set the speaker volume        ;
;=============================================================================;
;
SNDATM: lxi     H,ATMCODE       ; send 'ATM'
       call    SNDLIN          ;
       lxi     H,VOLUME        ; send the volume code
       call    SNDLIN          ;
       call    EATCODE         ; eat result code
       ret                     ;
;
;=============================================================================;
; SNDATO subroutine                                                           ;
; This subroutine will send the code to place the Smartmodem back to on-line  ;
; state ONLY if a carrier is detected. If no carrier is detected, then this   ;
; subroutine merely returns.                                                  ;
;=============================================================================;
;
SNDATO: call    CDTEST          ; check for call in progess
       rnc                     ; nope, then return
       lxi     H,ATOCODE       ; yep, then send 'ATO' (goto on-line mode)
       call    SNDLIN          ;
       call    EATCODE         ; eat result code
       call    SNDCAN          ; send the cancel character (cancel SNDESC)
       ret                     ;
;
;=============================================================================;
; EATCODE subroutine                                                          ;
; This subroutine will eat all the characters recieved from the modem until   ;
; a 100 ms "quiet" period is detected (used to eat Smartmodem result codes).  ;
; The initial delay is for the Smartmodem result code turn-around time).      ;
;=============================================================================;
;
EATCODE:mvi     B,2             ; wait 200 ms for Smartmodem turn-around
       mvi     C,TIMER         ;
       call    MEX             ;
EATCHAR:mvi     C,INMDM         ; eat a character
       call    MEX             ;
       jnc     EATCHAR         ; if more, then eat another character
       ret                     ; otherwise return
;
;=============================================================================;
; GETARG subroutine                                                           ;
; This subroutine will scan the input stream for an argument. If no argument  ;
; present, then this subroutine returns with the CARRY set                    ;
;=============================================================================;
;
GETARG: mvi     C,SBLANK        ; scan input stream for <key-word>
       call    MEX             ;
       ret                     ; and simply return
;
;=============================================================================;
; EATARG subroutine                                                           ;
; This subroutine will eat (throw away) the remaining characters in the       ;
; current argument. This is an aid for other routines which do not need to    ;
; (and thus do not) check the entire argument for a unique match to be made   ;
; (EG: "SET PORT C" and "SET PORT CONSOLE" will do the same thing, execept    ;
; the SBLANK MEX function will see the next "argument" as being "ONSOLE"      ;
; opposed to the line terminator).                                            ;
;=============================================================================;
;
EATARG: mvi     C,LKAHED        ; look ahead to next character in command line
       call    MEX             ;
       rc                      ; return if done (burp)
       cpi     ' '             ; is it a blank?
       rz                      ; yep, then we've finished eating the argument
       mvi     C,GNC           ; nope, eat the next character in command line
       call    MEX             ;
       jmp     EATARG          ; check the next character in command line
;
;=============================================================================;
; NEWLINE subroutine                                                          ;
; This subroutine will send a newline character (CR-LF pair) to the console   ;
;=============================================================================;
;
NEWLINE:mvi     C,ILP           ; output a newline character to console
       call    MEX             ;
       db      CR,LF,0         ;
       ret                     ;
;
;=============================================================================;
; SNDLIN subroutine                                                           ;
; This routine will send a string to the modem port. Works similar to the     ;
; BDOS 9 function. The string start address is in the HL register pair, and   ;
; the end-of-string character is set to EOS.                                  ;
;=============================================================================;
;
SNDLIN: mvi     C,SNDRDY        ; is modem ready to read another character?
       call    MEX             ;
       jnz     SNDLIN          ; nope, wait for it
       mov     A,M             ; yep, get next character to send to modem
       cpi     EOS             ; end-of-string character?
       rz                      ; yep, then return
       mov     B,A             ; nope, get the next character to send
       mvi     C,SNDCHR        ;
       call    MEX             ; send it!
       inx     H               ; bump up the string point
       jmp     SNDLIN          ; send the next character
;
;=============================================================================;
; Smartmodem codes to do what we want it do (for "SNDATx" routines)           ;
;=============================================================================;
;
SMNULL: db      NULL,EOS        ; null for justed CONNNECTed case
SMESCAP:db      '+++',EOS       ; Smartmodem code for goto command state
CANMSG: db      '?',EOS         ; cancel character message string
ATMCODE:db      'ATM',EOS       ; Smartmodem code for speaker volume
VOLUME: db      MD$SPKR,CR,EOS  ; initial speaker volume
ATOCODE:db      'ATO',CR,EOS    ; Smartmodem code for goto on-line state
;
;=============================================================================;
; Modem input (get a character or status) driver                              ;
;=============================================================================;
;
INPSP:  MVI     A,SPORT         ; get modem status
       JMP     INP1
INPDP:  MVI     A,DPORT         ; get a character from the modem
       JMP     INP1            ;

INP1:   PUSH    B               ; save BC register pair
       MOV     C,A             ; save port offset
       mvi     A,BASE          ; get the base port
       ADD     C               ; add offset for desired port (data/status)
       STA     INP2+1          ; store for IN command
INP2:   IN      0               ; input data/status
       POP     B               ; restore BC register pair
       RET                     ; and return
;
;=============================================================================;
; Modem output (put a character or command) driver                            ;
;=============================================================================;
;
OUTDP:  push    B               ; save the BC register pair
       mvi     C,DPORT         ; put a character to the modem
       jmp     OUT1            ;
OUTCP:  push    B               ; save the BC register pair
       mvi     C,CPORT         ; change modem control register
       jmp     OUT1            ;

OUT1:   mov     B,A             ; save the output character
       mvi     A,BASE          ; get the base port address
       ADD     C               ; add offset for desired port (data/ctrl)
       sta     OUT2+1          ; store for OUT command
       mov     A,B             ; restore the output character
OUT2:   out     0               ; send it (or change mode/control port)
       pop     B               ; restore the BC register pair
       ret                     ; return

       end