home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
CP/M
/
CPM_CDROM.iso
/
cpm
/
mex
/
mxm-cd10.aqm
/
MXM-CD10.ASM
Wrap
Assembly Source File
|
1985-08-05
|
16KB
|
503 lines
TITLE 'MEX CONCORD DATA SYSTEMS 224 AD OVERLAY V1.0'
;
; (DELETE ABOVE TITLE LINE IF ASSEMBLING WITH ASM)
;
; MXM-CD10.ASM Current version 27 Nov 84
;
; Concord Data Systems 224 AD modem overlay for MEX v1.x
; Written 27 Nov 84 by Dave Mabry
; Adapted using information and excerps from Ron Fowler's
; overlay for the PMMI modem.
;
; Please leave any bug reports or requests on TCBBS in Dearborn,
; Michigan (313-846-6127) or Royal Oak RCPM (313-759-6569)
; or call me at 313-956-5703 (voice). mabry
;
; Updates:
; MXM-CD10.ASM
; 11/27/84...Original release.
;
; Note that unlike the Hayes modem, the Concord does not
; have an ascii command that will cause a disconnect. Therefore
; for that feature of MEX to work properly, your normal overlay
; for your machine must be able to toggle DTR in the DISCV routine.
;
; This overlay will work with any modem overlay that terminates
; prior to 0900H
;
VERS EQU 10 ; Version number
FALSE EQU 0
TRUE EQU 0FFH
;
;
; 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
SMINIT EQU 0D55H ; Vector to modem initialization routine
;
;
; MEX service processor stuff ... MEX supports an overlay service
; processor, located at 0D00H (and maintained at this address from
; version to version). If your overlay needs to call BDOS for any
; reason, it should call MEX instead; function calls below about
; 240 are simply passed on to the BDOS (console and list I/O calls
; are specially handled to allow modem port queueing, which is why
; you should call MEX instead of BDOS). MEX uses function calls
; above about 244 for special overlay services (described below).
;
; Some sophisticated overlays may need to do file I/O; if so, use
; the PARSFN MEX call with a pointer to the FCB in DE to parse out
; the name. This FCB should support a spare byte immediately pre-
; ceeding the actual FCB (to contain user # information). If you've
; used MEX-10 for input instead of BDOS-10 (or you're parsing part
; of a SET command line that's already been input), then MEX will
; take care of DU specs, and set up the FCB accordingly. There-
; after all file I/O calls done through the MEX service processor
; will handle drive and user with no further effort necessary on
; the part of the programmer.
;
MEX EQU 0D00H ;address of the service processor
INMDM EQU 255 ;get char from port to A, CY=no more in 100 ms
TIMER EQU 254 ;delay 100ms * reg 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)
LOOKUP EQU 247 ;table search: see CMDTBL comments for info
PARSFN EQU 246 ;parse filename from input stream
BDPARS 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 nxt char w/o removing from input
GNC EQU 241 ;get char from input, cy=1 if none
ILP EQU 240 ;inline print
DECOUT EQU 239 ;decimal output
PRBAUD EQU 238 ;print baud rate
PRNTBL EQU 237 ;print MEX format table (HL)
PRIN EQU 236 ;print MEX ID string on console
;
;
CONOUT EQU 2 ;simulated BDOS function 2: console char out
PRINT EQU 9 ;simulated BDOS function 9: print string
INBUF EQU 10 ;input buffer, same structure as BDOS 10
;
;
CR EQU 0DH
LF EQU 0AH
ESC EQU 1BH
;
;
MSPEED EQU 107H ; Modem speed byte
B1200 EQU 5 ; Byte for 1200 baud
B2400 EQU 6 ; Byte for 2400 baud
NEWBDV EQU 16EH ; Entry point for new baud routine
;
;
ORG SMINIT ; Overlay the initialization vector
DW INIT ; Just the address
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).
;
; 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 reported by modem
; 6 - No dial tone 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
INIT: ; Just to print a signon message
MVI C,PRINT
LXI D,SIGNON
CALL MEX
RET
;
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 ;SET UP BUFFER POINTER
SHLD DIALPT
RET
;
; Here on an end-dial sequence
;
ENDIAL:
MVI M,0 ; Terminate phone number string
XRA A ; Initialize baud flag
STA BDFLAG
;
; Since the modem may not be at the same rate as the hardware and
; we really have no way of knowing, we try the baud rate the
; hardware is at first, and if the modem fails to respond in
; about a half a second then assume it is at the other baud rate.
; So try that baud rate. If the modem still fails to respond, then
; return to mex with a MODEM ERROR code.
;
CLEAR:
MVI C,INMDM ; Clear out the data buffer in USART
CALL MEX
JNC CLEAR ; Get them all
LXI H,WAKEUP ; Get modem's attention
CALL CDSEND
MVI C,5 ; ~.5 second wait
CALL CATCHR ; Catch response from modem
ORA A ; Check response
JZ AROUND ; If there was a response, then modem
; and system were at same baud rate
CPI 3 ; User typed ^C ?
RZ ; If yes, abort to mex
LXI H,BDFLAG ; Check to see if we have tried this
MOV A,M ; before
ORA A ; True means yes
JNZ ERRET
MVI M,TRUE ; If false, then make it true now
LDA MSPEED ; Get original baud rate
STA MSSAVE ; Save it temporarily
CPI B1200 ; Was first try at 1200 baud ?
LXI H,BDCMD+1 ; Point to second char of baud set command
JZ CLR05 ; Yes, go try 2400
CPI B2400 ; Was first try at 2400 baud ?
JNZ ERRET ; If not one of the two, then error
MVI A,B1200
MVI M,'H' ; If changing baud to 1200, need to change
JMP CLR10 ; it back to 2400 later
CLR05:
MVI A,B2400 ; Now set to 2400 baud
MVI M,'L' ; Later must set back to 1200
CLR10:
CALL NEWBDV ; ***This must be in hardware overlay***
JMP CLEAR
AROUND:
LDA BDFLAG
ORA A ; Need to reset baud rate ?
JZ CLR15 ; No, just continue
LXI H,BDCMD ; Send modem speed command
CALL CDSEND
; Now must wait for last character to be fully shifted out of USART
MVI C,TIMER
MVI B,2 ; 200ms should be plenty of time
CALL MEX
LDA MSSAVE ; Get original baud rate
CALL NEWBDV ; Set hardware to old baud rate
MVI C,INMDM ; Clear out any characters we might
CALL MEX ; have missed while changing baud rates
JNC $-5 ; Loop til all bytes removed from USART
CLR15:
LXI H,DCMD ; Send "dial" command and # to modem
CALL CDSEND
CALL SENDCR ; Send <cr> to terminate phone number
;
; Here starts the main loop waiting for messages from the modem
; and interpreting them. Some are just passed to the console
; and others trigger a specific action.
;
DLOOP:
MVI C,255 ; Long wait here
CALL CATCHR ; Catch response from modem
ORA A ; Zero return code ?
JNZ IDLE ; No, disconnect and return error code
MOV A,B ; Get character count from CATCHR
ORA A ; Hope it isn't zero
JZ DLOOP ; If it is, then ignore this response
LXI H,RESPBF ; Point to string from modem
LXI D,RSPTBL ; Point to valid response table
CALL COMPR ; Find out which response we got
MOV A,B ; Get return value
CPI 255 ; No response match
JNZ DIAL05
ERRET:
MVI A,4 ; Error return to MEX
JMP IDLE ; Disconnect and return error code
DIAL05:
CPI 3 ; OK ?
JZ DLOOP ; Ignore this one
ORA A ; Need to know if 0 ==> connected
RZ ; Only this code can return w/o disconnecting
CPI 7 ; If <= 6 then let it return to MEX
JC IDLE
JNZ DIAL10 ; If not 7 (7 = voice)
MVI A,1
JMP IDLE ; Return BUSY code to MEX
DIAL10:
CPI 8 ; Call fail ?
JZ ERRET ; Return modem error code
CPI 13 ; Between 9 and 12 (inclusive) ?
JNC DLOOP ; Ignore 13 and above (13 = dial tone)
; At this point the match code from COMPR is between 9 and 12 inclusive.
; Use this number as an offset into a table of messages, print the
; appropriate message and continue to loop.
SUI 9 ; Now between 0 and 3
RLC ; *2
RLC ; *4
RLC ; *8
MVI B,0
MOV C,A ; BC contain offset
LXI H,MSGS ; Point to messages table
DAD B ; Index into it
XCHG ; Pointer to message into DE
MVI C,9 ; Let mex to string print
CALL MEX
LXI D,COMSP ; Print ", "
MVI C,9
CALL MEX
JMP DLOOP ; And continue to loop
;
IDLE:
;
; Forces modem into idle state by sending "idle" command and
; then toggling DTR using the user's DISCV entry.
; Preserves any return code that may be in register A.
;
PUSH PSW ; Preserve any return code
LXI H,IDLCMD ; Send abort character to modem
CALL CDSEND
CALL DISCV ; Make sure modem disconnects
POP PSW ; Retrieve return code
RET
SENDCR:
;
; Sends a carriage return character to the modem.
;
LXI H,CRMSG ; Send <cr> to modem
JMP CDSEND
; Table of valid responses from modem
RSPTBL:
DB 'IN',0 ; Initiating
DB 'BSY',0 ; Busy
DB 'NOA',0 ; No answer
DB 'OK',0 ; Signon
DB 'NOT',0 ; No answer tone
DB 'NOR',0 ; No ring
DB 'NDT',0 ; No dial tone
DB 'VDT',0 ; Voice detected
DB 'CFL',0 ; Call failed
DB 'DG',0 ; Dialing
DB 'RG',0 ; Ringing
DB 'AT',0 ; Answer tone
DB 'AR',0 ; Answer
DB 'DT',0 ; Dial tone
DB 0 ; Table terminator
; Table of messages for some of the entries in the above table.
; Each entry must be exactly eight characters including the "$".
MSGS:
DB 'dialing$'
DB 'ringing$'
DB 'anstone$'
DB 'answer$ '
COMSP:
DB ', $' ; To delimit messages
COMPR:
; Compares a string of characters in memory to a table of
; strings. Each entry of the table must be terminated by
; a zero byte, and the table must be terminated by another
; zero byte.
; Inputs: HL points to the string to look for
; DE points to the table
; Output: B contains the number of the table entry that
; matches the string, and a 255 if no entry matched.
;
MVI B,0 ; Init index
CMPR02:
PUSH H ; Save pointer to string in question
CMPR05:
LDAX D ; Fetch char from table
ORA A ; Is it end of table entry ?
JNZ CMPR10 ; Not end of entry
POP H
RET ; Return with match code in B
CMPR10:
CMP M ; Same as char in string ?
JNZ CMPR15 ; Jump if not this entry in table
INX H ; Else, point to next char in string
INX D ; and next char in table entry
JMP CMPR05 ; Check next char
CMPR15:
INR B ; Increment index
CMPR20:
INX D ; Next char in table
LDAX D ; Get next char from table
ORA A ; Is it last char in that entry ?
JNZ CMPR20 ; No, keep looking
INX D ; Yes, then point to first char of next one
LDAX D ; Now check for end of table
ORA A ; Zero delimits table
POP H ; Point to original string again
JNZ CMPR02 ; Go check next table entry
MVI B,255 ; No match return code
RET
CATCHR:
;
; Catch response from modem.
; Input: C delay allowed before timeout (multiples of 100ms)
; Output: Buffer (RESPBF) contains the string received from modem with
; any control characters filtered out.
; C count of characters received before <cr>
; A error code: 0 ==> normal return
; 2 ==> time out occurred
; 3 ==> user typed ^C
;
LXI H,RESPBF
PUSH H
MVI B,BUFLEN ; Length of character buffer
CRL10:
MVI M,0 ; Fill buffer with zeros
INX H
DCR B
JNZ CRL10
POP H ; Get original pointer
MVI B,0 ; Character counter
CRLOOP:
MOV D,C ; Initialize count down timer
CRL05:
PUSH B ; Save character counter
PUSH D ; Save time out count down
PUSH H ; Save buffer pointer
MVI C,CHEKCC ; See if user typed ^C
CALL MEX
JZ UABORT ; If yes, jump to user abort code
MVI C,INMDM ; Else, continue
CALL MEX ; Get char in 1ms if available
POP H ; Restore working registers
POP D
POP B
JC NOCHAR ; If no char in 1ms, handle it
ANI 7FH ; Mask any parity bit
CPI CR ; End of line from modem ?
JZ EOL ; If <cr> then end of line
MOV M,A ; Here we have a valid character
INX H ; so save it and bump pointer
INR B ; Increment character counter also
JMP CRLOOP ; Go get the next one
;
; Handle no character from modem in 1ms
;
NOCHAR:
DCR D ; Decrement time out counter
JNZ CRL05 ; If not to zero, wait some more
MOV C,B ; Else, return with what we have now
MVI A,2 ; Time-out error code
RET
;
; End of line from modem
;
EOL:
MOV C,B ; Character count
XRA A ; Return zero
RET
;
; User abort from ^C
;
UABORT:
CALL IDLE ; Force disconnect
POP H ; Since these are still on the stack
POP D
POP B
MOV C,B ; Count of characters up to now
MVI A,3 ; User abort code
RET
;
; Sends a string of characters pointed to by HL terminated by zero
;
CDSEND:
MVI C,SNDRDY ; Get modem send status
CALL MEX
JNZ CDSEND ; Wait for modem ready
MOV A,M ; Get character
INX H ; Point to next character
ORA A ; Is this the terminator ?
RZ ; If yes, done
MOV B,A ; Pass character in B
MVI C,SNDCHR ; Let MEX send to modem
CALL MEX
JMP CDSEND
;
; DATA AREA
;
SIGNON:
DB '(Modem overlay for Concord Data Systems 224 AutoDial V'
DB VERS/10 + '0', '.', (VERS MOD 10) + '0'
DB ')$'
; Wakeup string to put modem into "interactive DTE" mode
WAKEUP: DB ESC,CR,CR,'B',CR,0 ; String to wake up modem
IDLCMD: DB ESC,0 ; Idle command
BDCMD: DB 'SL' ; Set baud command
CRMSG: DB CR,0 ; Note, this is end of LSCMD also
DCMD: DB 'DM' ; Dial command to modem
DIALBF: DS 30 ; Phone number buffer
BUFLEN EQU 8 ; Length of response buffer
RESPBF: DS BUFLEN ; Response from modem
DIALPT: DS 2 ;DIAL POSITION POINTER
MSSAVE: DS 1 ; Save location for original baud rate
BDFLAG: DS 1 ; Flag for baud rate changed
;
END