home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
CP/M
/
CPM_CDROM.iso
/
simtel
/
sigm
/
vols000
/
vol007
/
modem926.asm
< prev
next >
Wrap
Assembly Source File
|
1984-04-29
|
46KB
|
1,989 lines
;
;MODEM.ASM V2.0, BY WARD CHRISTENSEN
; (revised 9/26/80)
;
;CP/M - CP/M FILE TRANSFER PROGRAM, AND
;TERMINAL PROGRAM.
;
;NOTE: THIS FILE WILL ASSEMBLE, WITHOUT NEED FOR
;EDITING, TO WORK WITH A D.C. HAYES 80-103A MODEM
;AT *NON-STANDARD* PORT 90H WITH 4MHZ Z80 CPU.
;SEE EQUATES FOR OTHER OPTIONS INCLUDING SYSTEM CLOCK
;FREQUENCY.
;
* * * * * * * * * * * * * * * * * * * * * * * * *
* *
* THIS PROGRAM DOCUMENTED IN "MODEM.DOC" *
* *
* * * * * * * * * * * * * * * * * * * * * * * * *
* THIS PROGRAM WAS "MODEM.ASM" BUT IS *
* TEMPORARILY NAMED "MODEM926.ASM" SO PEOPLE *
* WILL REALIZE IT IS AN ENHANCEMENT OF *
* THE ORIGINAL PROGRAM "MODEM.ASM" ON CP/M *
* USER'S GROUP DISK 25. *
* * * * * * * * * * * * * * * * * * * * * * * * *
;
;PLEASE PASS ON MODS, BUGS, ETC, SO YOUR
;FIXES OR ENHANCEMENTS MAY BE SHARED BY ALL,
; TO:
; Ward Christensen
; 688 E. 154th St. #5D
; Dolton, Il. 60419
;
; (312) 849-6279
;
;You may send a self-addressed stamped postcard
;to be informed of changes/bugs as they become
;known.
;
; --------------
;
; 09/23/77
;ORIGINALLY WRITTEN BY WARD CHRISTENSEN
;
; 04/26/79
;REWRITTEN BY WARD CHRISTENSEN TO COMBINE
;IMPROVEMENTS TO THE ORIGINAL MADE BY WARD
;AND BY KEITH PETERSEN, W8SDZ, AND SUGGESTIONS
;BY JIM BELL WHICH KEITH IMPLEMENTED. SEE
;MODEM.DOC FOR ADDITIONAL HISTORICAL
;INFORMATION AND DOCUMENTATION.
;
; 05/09/79
;ALLOW 'T' AND 'E' SUB-OPTIONS TO GO TO TERMINAL
;OR ECHO MODEM AFTER TRANSFERRING A FILE. (WLC)
;
; 05/22/79
;ADD FEATURE TO MAKE RECEIVE FILE ROUTINE SAY
;FILE SUCCESSFULLY OPENED, WHEN IN QUIET MODE.
;MOVE INITIAL GOBBLE GARBAGE INPUTS TO BEFORE
;COMMAND CPI'S SO ALL MODES ARE CLEARED. CHANGE
;INITIAL SEND WAIT TO 80 SECS TO ALLOW MORE TIME
;FOR RECEIVING END TO COME UP. ADD 'H' AFTER MSG
;THAT SHOWS NUMBER OF SECTORS IN EXTENT ABOUT TO
;BE SENT. (KBP)
;
; 05/24/79
;FIX MISSING RETURN INSTRUCTION AT END OF
;INITIALIZATION ROUTINE. (KBP)
;
; 07/01/79
;MODIFIED PROGRAM TO ALLOW FOR NON-STANDARD VERSIONS OF
;CP/M. ALL REFERENCES TO ENTRIES INTO CP/M SHOULD BE MADE
;RELATIVE TO THE VARIABLE SYMBOL CALL "BASE". FOR EXAMPLE,
;THE EQUATE TO BDOS SHOULD BE BASE+5 INSTEAD OF 5. BASE
;WILL BE SET TO 0 WHEN THE VARIABLE STDCPM IS SET TO TRUE.
;(BOB MATHIAS).
;
; 07/24/79
;MOVE INITIALIZE LOCAL STACK TO BEGINNING OF PROGRAM
;SO DEFAULT STACK IS NOT USED. ADD CONDITIONAL ASSEMBLY
;OPTION TO TERMINAL ROUTINE FOR TIMESHARE SYSTEMS.
;CORRECT ERROR IN LOCAL ABORT ROUTINE (WAS LOOKING FOR
;CONTROL E - NOW CORRECTLY LOOKS FOR CONTROL X). ADD
;REGISTER SAVES TO CONOUT, KEYIN AND AND KEYBOARD STATUS
;ROUTINES, AS SOME CBIOS ROUTINES CLOBBER THEM. (KBP)
;
; 08/05/79
;ADDED D. C. HAYES MODEM SUPPORT BY JIM BELL (KBP)
;
; 08/06/79
;ADDED EQUATES FOR EXTERNAL MODEM (NOT S-100 PLUG-IN)
;(KBP)
;
; 12/06/79
;CORRECTED ERROR IN HELP FILE. SAID T.110, NOW SAYS
;TO.110. BY WARD CHRISTENSEN. CORRECTED RECEIVE FILE
;ROUTINE SO TERMINAL OR ECHO MODE WORKS AFTER FILE
;TRANSFER IN QUIET MODE. MOVED CHECKS FOR "H" AND
;"X" OPTIONS SO MODEM IS NOT REINITIALIZED. (KBP)
;
; 05/27/80
;ELIMINATED CONTROL-X CANCEL OF SEND FEATURE, AT
;SUGGESTION OF WARD CHRISTENSEN. A LINE GLITCH COULD
;CAUSE PREMATURE ABORT WHEN THIS FEATURE WAS ACTIVE.
;ADDED EQUATES FOR FALSE AND TRUE TO MAKE ASSEMBLY
;OPTIONS CLEARER. REMOVED H8 PORT EQUATES (THEY CAN
;BE PUT IN EXTERNAL MODEM EQUATES). (KBP)
;
; 09/26/80
;ADDED AUTO-DIAL AND AUTO-REDIAL LOGIC FOR D.C. HAYES
;CONDITIONAL ASSEMBLY. DO I HEAR A VOLUNTEER TO ADAPT
;THIS TO PMMI? (BRUCE R. RATOFF)
;
;
;DEFINE FALSE AND TRUE
;
FALSE EQU 0
TRUE EQU NOT FALSE
;
STDCPM EQU TRUE ;TRUE, IS STANDARD CP/M
ALTCPM EQU FALSE ;TRUE, IS ALTERNATE CP/M FOR H8 OR TRS80
;
IF STDCPM
BASE EQU 0 ;CP/M BASE ADDRESS
ENDIF
;
IF ALTCPM
BASE EQU 4200H ;CP/M BASE ADDRESS FOR ALTERNATE CP/M
ENDIF
;
PMMI EQU FALSE ;TRUE, IS PMMI MODEM
;
DCH EQU TRUE ;TRUE, IS D.C. HAYES MODEM
;
IF PMMI
MODCTLP EQU 0C0H ;PMMI VALUES
MODSNDB EQU 1 ;BIT TO TEST FOR SEND
MODSNDR EQU 1 ;VALUE WHEN READY
MODRCVB EQU 2 ;BIT TO TEST FOR RECEIVE
MODRCVR EQU 2 ;VALUE WHEN READY
MODDATP EQU 0C1H ;DATA PORT
BAUDRP EQU 0C2H ;BAUD RATE OUTPUT
MODCTL2 EQU 0C3H ;SECOND CTL PORT
ENDIF
;
IF DCH
MODCTLP EQU 92H ;D. C. HAYES VALUES
MODSNDB EQU 2 ;BIT TO TEST FOR SEND
MODSNDR EQU 2 ;VALUE WHEN READY
MODRCVB EQU 1 ;BIT TO TEST FOR RECEIVE
MODRCVR EQU 1 ;VALUE WHEN READY
MODDATP EQU 90H ;DATA PORT
MODCTL2 EQU 91H ;SECOND CTL PORT
ENDIF
;
IF PMMI
ORIGMOD EQU 1DH ;8 DATA, NO PARITY, ORIG
ANSWMOD EQU 1EH ;8 DATA, NO PARITY, ANSW
ENDIF
;
;NOTE: IF DC HAYES THEN BAUD RATE DEFAULTS TO
;300 - 1 STOP BIT. DO NOT CHANGE NEXT EQUATES
IF DCH
ORIGMOD EQU 86H ;OFF HOOK, 110 BAUD, CAR. ON, ORIG.
ANSWMOD EQU 82H ;OFF HOOK, 110 BAUD, CAR. ON, ANSW.
ENDIF
;
;IF YOU ARE USING AN EXTERNAL MODEM (NOT S-100 PLUG-IN)
;CHANGE THESE EQUATES FOR YOUR MODEM PORT REQUIREMENTS
;
INITREQ EQU FALSE ;TRUE, IF MODEM PORT INIT. REQ'D
INITC1 EQU 64H ;1ST INIT CHAR TO CTL PORT
INITC2 EQU 64H ;2ND INIT CHAR TO CTL PORT
INITC3 EQU 64H ;3RD INIT CHAR TO CTL PORT
INITC4 EQU 64H ;4TH INIT CHAR TO CTL PORT
;
IF NOT PMMI AND NOT DCH
MODCTLP EQU 02H ;PUT YOUR MODEM CONTROL PORT HERE
MODSNDB EQU 80H ;YOUR BIT TO TEST FOR SEND
MODSNDR EQU 80H ;YOUR VALUE WHEN READY
MODRCVB EQU 40H ;YOUR BIT TO TEST FOR RECEIVE
MODRCVR EQU 40H ;YOUR VALUE WHEN READY
MODDATP EQU 03H ;YOUR MODEM DATA PORT
ENDIF ;END OF EXTERNAL MODEM EQUATES
;
ERRLIM EQU 10 ;MAX ALLOWABLE ERRORS
EXITCHR EQU 'E'-40H ;CTL-E EXIT FROM T OR C
DISCCHR EQU 'D'-40H ;CTL-D DISCONNECTS MODEM T/E
;
FASTCLK EQU TRUE ;TRUE FOR 4 MHZ CLOCK
;
;SOME TIME-SHARE COMPUTERS REQUIRE TERMINALS TO
;HAVE BIT 7 HIGH (MARKING), SO IN THE TERMINAL
;MODE WE FORCE IT TO HIGH IF THE FOLLOWING OPTION
;IS SELECTED:
;
TIMESHR EQU FALSE ;TRUE TO MAKE BIT 7 HIGH
;
;DEFINE ASCII CHARACTERS USED
;
SOH EQU 1 ;START OF HEADER
EOT EQU 4 ;END OF TRANSMISSION
ACK EQU 6 ;ACKNOWLEDGE
BEL EQU 7 ;BELL
NAK EQU 15H ;NEG ACKNOWLEDGE
CAN EQU 18H ;CANCEL
LF EQU 10 ;LINEFEED
CR EQU 13 ;CARRIAGE RETURN
;
ORG BASE+100H
;
;INIT PRIVATE STACK
LXI H,0 ;HL=0
DAD SP ;HL=STACK FROM CP/M
SHLD STACK ;..SAVE IT
LXI SP,STACK ;SP=MY STACK
CALL START ;GO PRINT ID
DB 'MODEM PROGRAM as of '
DB '09/26/80',CR,LF,'$'
;
START POP D ;GET ID MESSAGE
MVI C,PRINT
CALL BDOS ;PRINT ID MESSAGE
;
;INITIALIZE THE JMPS TO CP/M BIOS
;
CALL INITADR
;
LDA FCB+1 ;GET PRIMARY OPTION
CPI 'H' ;MODEM H(ELP)?
JZ HELP ;..YES, GIVE HELP
CPI 'X' ;MODEM X(AMPLES)?
JZ EXAM ;GIVE EXAMPLES
;
;SAVE PRIMARY OPTION, VALIDATE SECONDARY OPT.
;
CALL PROCOPT
;
;INIT THE MODEM OR SERIAL PORT
;
CALL INITMOD
;
;MOVE THE FILENAME FROM FCB 2 TO FCB 1
;
CALL MOVEFCB
;
IF DCH
CALL DIALMOD ; CHECK FOR PHONE # AND DIAL IT IF PRESENT
ENDIF
;
;GOBBLE UP GARBAGE CHARS FROM THE LINE
;PRIOR TO RECEIVE OR SEND
;
IN MODDATP
IN MODDATP
;
;JMP TO APPROPRIATE FUNCTION
;
LDA OPTION ;GET PRIMARY OPTION
;
CPI 'C' ;(COMPAT W/EARLIER
JZ TRMECHO ;OPTION "COMPUTER")
;
CPI 'E' ;TERMINAL IN ECHO
JZ TRMECHO ;..MODE?
;
CPI 'T' ;TERMINAL..
JZ TERM ;..MODE?
;
CPI 'D'
JZ DISCONN
;
CPI 'S' ;SEND..
JZ SENDFIL ;..A FILE?
;
CPI 'R' ;RECEIVE..
JZ RCVFIL ;..A FILE?
;
;INVALID OPTION
;
JMP BADOPT
;
* * * * * * * * * * * * * * * * * * * * *
* *
* TERM: TERMINAL MODE *
* *
* * * * * * * * * * * * * * * * * * * * *
;
;THIS PROGRAM SIMPLY SENDS KEYED CHARACTERS
;DOWN THE LINE, AND DISPLAYS CHARACTERS
;RECEIVED FROM THE LINE. THIS MAKES IT
;SUITABLE FOR COMMUNICATION WITH TIME SHARING
;COMPUTERS, CBBS'S, OR ANOTHER PROGRAM
;RUNING "MODEM E" (ECHO MODE)
;
;TYPE THE "EXITCHR" (ORIGINALLY CTL-E) TO EXIT.
;OR THE "DISCCHR" (ORIGINALLY CTL-D) TO DISCONN.
;
;A FUTURE ENHANCEMENT WILL BE TO WRITE THE
;RECEIVED DATA IN MEMORY, AND ALLOW IT TO
;BE WRITTEN TO DISK
;
TERM CALL STAT ;LOCAL CHAR KEYED?
JZ TERML ;..NO, CHECK LINE
CALL KEYIN ;GET CHAR
CPI EXITCHR ;TIME TO END?
JZ CKDIS ;YES, CK DISCONN
CPI DISCCHR ;DISCONNECT REQUEST?
JZ DISCONN ;YES, DO IT
IF TIMESHR
ORI 80H ;FORCE BIT 7 TO HIGH
ENDIF ;TIMESHR
OUT MODDATP ;SEND THE CHAR
;
;SEE IF CHAR FROM LINE
;
IF NOT DCH
TERML IN MODCTLP ;READ STATUS
ENDIF
;
IF DCH
TERML IN MODCTL2 ;READ STATUS
ENDIF
;
ANI MODRCVB ;ISOLATE BIT
CPI MODRCVR ;READY?
JNZ TERM ;..NO, LOOP
IN MODDATP ;READ DATA
ANI 7FH ;STRIP PARITY BIT
CALL TYPE ;TYPE IT
JMP TERM ;LOOP
;
* * * * * * * * * * * * * * * * * * * * *
* *
* TRMECHO: TERMINAL WITH ECHO *
* *
* * * * * * * * * * * * * * * * * * * * *
;
;TERMINAL PROGRAM WITH ECHO - SEE NOTES
;UNDER "TERM" ABOVE
;
;C A U T I O N DON'T RUN WITH BOTH COMPUTERS
;IN "ECHO" MODE - LINE ERRORS (OR ANY CHAR)
;WILL BE ECHOED BACK AND FORTH AD INFINITUM.
;
IF NOT DCH
TRMECHO IN MODCTLP ;GET STATUS
ENDIF
;
IF DCH
TRMECHO IN MODCTL2 ;GET STATUS
ENDIF
;
ANI MODRCVB ;ISOLATE READY BIT
CPI MODRCVR ;ARE WE READY?
JZ LINECHR ;YES, READ THE CHR
CALL STAT ;CHECK LOCAL KB
JZ TRMECHO ;..NO CHAR
CALL KEYIN ;GET LOCAL CHAR
CPI EXITCHR ;END?
JZ CKDIS ;YES, CK DISCONN, EXIT
CPI DISCCHR ;DISCONN?
JZ DISCONN ;..YES, DO IT.
OUT MODDATP ;SEND CHAR
CALL TYPE ;ECHO IT LOCALLY
JMP TRMECHO ;..AND LOOP
;
;GOT CHAR FROM LINE
;
LINECHR IN MODDATP ;GET CHAR
OUT MODDATP ;ECHO IT
ANI 7FH ;STRIP PARITY BIT
CALL TYPE ;TYPE IT
JMP TRMECHO ;LOOP
;
* * * * * * * * * * * * * * * * * * * * *
* *
* SENDFIL: SENDS A CP/M FILE *
* *
* * * * * * * * * * * * * * * * * * * * *
;
;THE CP/M FILE SPECIFIED IN THE MODEM COMMAND
;IS TRANSFERRED OVER THE PHONE TO ANOTHER
;COMPUTER RUNNING MODEM WITH THE "R" (RECEIVE)
;OPTION. THE DATA IS SENT ONE SECTOR AT A
;TIME WITH HEADERS AND CHECKSUMS, AND RE-
;TRANSMISSION ON ERRORS.
;
SENDFIL CALL OPENFIL ;OPEN THE FILE
MVI E,80 ;WAIT 80 SEC..
CALL WAITNAK ;..FOR INITIAL NAK
;
SENDLP CALL RDSECT ;READ A SECTOR
JC SENDEOF ;SEND EOF IF DONE
CALL INCRSNO ;BUMP SECTOR #
XRA A ;ZERO ERROR..
STA ERRCT ;..COUNT
;
SENDRPT CALL SENDHDR ;SEND A HEADER
CALL SENDSEC ;SEND DATA SECTOR
CALL SENDCKS ;SEND CKSUM
CALL GETACK ;GET THE ACK
JC SENDRPT ;REPEAT IF NO ACK
JMP SENDLP ;LOOP UNTIL EOF
;
;FILE SENT, SEND EOT'S
;
SENDEOF MVI A,EOT ;SEND..
CALL SEND ;..AN EOT
CALL GETACK ;GET THE ACK
JC SENDEOF ;LOOP IF NO ACK
JMP DONE ;ALL DONE
;
* * * * * * * * * * * * * * * * * * * * *
* *
* RCVFIL: RECEIVE A FILE *
* *
* * * * * * * * * * * * * * * * * * * * *
;
;RECEIVES A FILE IN BLOCK FORMAT AS SENT
;BY ANOTHER PERSON DOING "MODEM S FN.FT".
;
RCVFIL CALL ERASFIL ;ERASE THE FILE
CALL MAKEFIL ;..THEN MAKE NEW
CALL ILPRT ;PRINT:
DB 'FILE OPEN, READY TO RECEIVE',CR,LF,0
;
RCVLP CALL RCVSECT ;GET A SECTOR
JC RCVEOT ;GOT EOT
CALL WRSECT ;WRITE THE SECTOR
CALL INCRSNO ;BUMP SECTOR #
CALL SENDACK ;ACK THE SECTOR
JMP RCVLP ;LOOP UNTIL EOF
;
;GOT EOT ON SECTOR - FLUSH BUFFERS, END
;
RCVEOT CALL WRBLOCK ;WRITE THE LAST BLOCK
CALL SENDACK ;ACK THE SECTOR
CALL CLOSFIL ;CLOSE THE FILE
JMP DONE ;ALL DONE
;
* * * * * * * * * * * * * * * * * * * * *
* *
* SUBROUTINES *
* *
* * * * * * * * * * * * * * * * * * * * *
;
;
;----> RCVSECT: RECEIVE A SECTOR
;
;RETURNS WITH CARRY SET IF EOT RECEIVED.
;
RCVSECT XRA A ;GET 0
STA ERRCT ;INIT ERROR COUNT
;
RCVRPT LDA QFLG ;QUIET?
ORA A
JZ RCVSQ ;YES, NO STAT MSG.
CALL ILPRT ;PRINT:
DB 'AWAITING #',0
LDA SECTNO ;GET SECTOR #
INR A ;(REAL INR LATER)
CALL HEXO ;PRINT IN HEX
CALL CRLF ;..THEN CRLF
;
RCVSQ MVI B,10 ;10 SEC TIMEOUT
CALL RECV ;GET SOH/EOT
JC RCVSTOT ;TIMEOUT
CPI SOH ;GET SOH?
JZ RCVSOH ;..YES
;
;EARLIER VERS. OF MODEM PROG SENT SOME NULLS -
;IGNORE THEM
;
ORA A ;00 FROM SPEED CHECK?
JZ RCVSQ ;YES, IGNORE IT
CPI EOT ;END OF TRANSFER?
STC ;RETURN WITH CARRY..
RZ ;..SET IF EOT
;
;DIDN'T GET SOH OR EOT -
;
MOV B,A ;SAVE CHAR
LDA VSEEFLG ;VIEWING..
ORA A ;..MODE?
JZ RCVSEH ;YES, PRT.MSG
LDA QFLG ;QUIET..
ORA A ;..MODE?
JZ RCVSERR ;YES, SKIP MSG
RCVSEH MOV A,B ;GET CHAR
CALL HEXO ;SHOW IN HEX
CALL ILPRT ;PRINT:
DB 'H RCD, NOT SOH',CR,LF,0
;
;DIDN'T GET VALID HEADER - PURGE THE LINE,
;THEN SEND NAK.
;
RCVSERR MVI B,1 ;WAIT FOR 1 SEC..
CALL RECV ;..WITH NO CHARS
JNC RCVSERR ;LOOP UNTIL SENDER DONE
MVI A,NAK ;SEND..
CALL SEND ;..THE NAK
LDA ERRCT ;ABORT IF..
INR A ;..WE HAVE REACHED..
STA ERRCT ;..THE ERROR..
CPI ERRLIM ;..LIMIT?
JC RCVRPT ;..NO, TRY AGAIN
;
;10 ERRORS IN A ROW -
;
LDA VSEEFLG ;VIEWING..
ORA A ;..FILE?
JZ RCVCKQ ;YES, ASK RETRY/QUIT
LDA QFLG ;QUIET..
ORA A ;..MODE?
JZ RCVSABT ;ABORT
;
RCVCKQ CALL CKQUIT ;RETRY/QUIT?
JZ RCVSECT ;TRY AGAIN
;
RCVSABT CALL CLOSFIL ;KEEP WHATEVER WE GOT
CALL ERXIT
DB '++UNABLE TO RECEIVE BLOCK'
DB CR,LF,'++ABORTING++$'
;
;TIMEDOUT ON RECEIVE
;
RCVSTOT LDA VSEEFLG ;VIEWING..
ORA A ;..MODE?
JZ RCVSPT ;YES, PRT MSG
LDA QFLG ;QUIET..
ORA A ;..MODE?
JZ RCVSERR ;YES, NO MSG
;
RCVSPT CALL ILPRT
DB '++TIMEOUT++ ',0
;
RCVPRN LDA ERRCT ;PRINT ERROR..
CALL HEXO ;..COUNT
CALL CRLF
JMP RCVSERR ;BUMP ERR CT, ETC.
;
;GOT SOH - GET BLOCK #, BLOCK # COMPLEMENTED
;
RCVSOH MVI B,1 ;TIMEOUT = 1 SEC
CALL RECV ;GET SECTOR
JC RCVSTOT ;GOT TIMEOUT
MOV D,A ;D=BLK #
MVI B,1 ;TIMEOUT = 1 SEC
CALL RECV ;GET CMA'D SECT #
JC RCVSTOT ;TIMEOUT
CMA ;CALC COMPLEMENT
CMP D ;GOOD SECTOR #?
JZ RCVDATA ;YES, GET DATA
;
;GOT BAD SECTOR #
;
LDA VSEEFLG ;VIEWING..
ORA A ;..MODE?
JZ RCVBSE ;..YES, PRT MSG
LDA QFLG ;QUIET..
ORA A ;..MODE?
JZ RCVSERR ;..YES, NO MSG
;
RCVBSE CALL ILPRT ;PRINT:
DB '++BAD SECTOR # IN HDR',CR,LF,0
JMP RCVSERR ;BUMP ERROR CT.
;
RCVDATA MOV A,D ;GET SECTOR #
STA RCVSNO ;SAVE IT
MVI A,1 ;SHOW..
STA DATAFLG ;GETTING DATA
MVI C,0 ;INIT CKSUM
LXI H,BASE+80H ;POINT TO BUFFER
RCVCHR MVI B,1 ;1 SEC TIMEOUT
CALL RECV ;GET CHAR
JC RCVSTOT ;TIMEOUT
MOV M,A ;STORE CHAR
INR L ;DONE?
JNZ RCVCHR ;NO, LOOP
;
;VERIFY CHECKSUM
;
MOV D,C ;SAVE CHECKSUM
XRA A ;SHOW..
STA DATAFLG ;..END OF DATA
MVI B,1 ;TIMEOUT LEN.
CALL RECV ;GET CHECKSUM
JC RCVSTOT ;TIMEOUT
CMP D ;CHECKSUM OK?
JNZ RCVCERR ;NO, ERROR
;
;GOT A SECTOR, IT'S A DUP IF = PREV,
; OR OK IF = 1 + PREV SECTOR
;
LDA RCVSNO ;GET RECEIVED
MOV B,A ;SAVE IT
LDA SECTNO ;GET PREV
CMP B ;PREV REPEATED?
JZ RECVACK ;ACK TO CATCH UP
INR A ;CALC NEXT SECTOR #
CMP B ;MATCH?
JNZ ABORT ;NO MATCH - STOP SENDER, EXIT
RET ;CARRY OFF - NO ERRORS
;
;GOT CKSUM
;
RCVCERR LDA VSEEFLG ;VIEWING..
ORA A ;..MODE?
JZ RCVCPR ;..YES, PRT MSG
LDA QFLG ;QUIET..
ORA A ;..MODE?
JZ RCVSERR ;YES, NO MSG
;
RCVCPR CALL ILPRT
DB '++CKSUM++ ',0
JMP RCVPRN ;PRINT ERROR #
;
;PREV SECT REPEATED, DUE TO THE LAST ACK
;BEING GARBAGED. ACK IT SO SENDER WILL CATCH UP
;
RECVACK CALL SENDACK ;SEND THE ACK,
JMP RCVSECT ;GET NEXT BLOCK
;
;SEND AN ACK FOR THE SECTOR
;
SENDACK MVI A,ACK ;GET ACK
CALL SEND ;..AND SEND IT
RET
;
;----> SENDHDR: SEND THE SECTOR HEADER
;
;SEND: (SOH) (BLOCK #) (COMPLEMENTED BLOCK #)
;
SENDHDR LDA QFLG ;QUIET..
ORA A ;..MODE?
JZ SENDHNM ;YES, SKIP STATUS MSG.
CALL ILPRT ;PRINT:
DB 'SEND # ',0
LDA SECTNO ;PRINT..
CALL HEXO ;..SECT #
CALL CRLF ;..THEN CR/LF
;
SENDHNM MVI A,SOH ;SEND..
CALL SEND ;..SOH,
LDA SECTNO ;THEN SEND..
CALL SEND ;..SECTOR #
LDA SECTNO ;THEN SECTOR #
CMA ;..COMPLEMENTED..
CALL SEND ;..SECTOR #
RET ;FROM SENDHDR
;
;----> SENDSEC: SEND THE DATA SECTOR
;
;WHILE SENDING THE SECTOR, THE "DATAFLG" IS SET
;SUCH THAT IF "V" (VIEW THE FILE) WAS REQUESTED,
;THE "SHOW" ROUTINE WILL PRINT THE DATA, BUT NOT
;THE HDR OR CKSUM, OR ANY NON-FATAL MSGS.
;
SENDSEC MVI A,1 ;SHOW NOW AT DATA..
STA DATAFLG ;..FOR VIEW COMMAND
MVI C,0 ;INIT CKSUM
LXI H,BASE+80H ;POINT TO BUFFER
SENDC MOV A,M ;GET A CHAR
CALL SEND ;SEND IT
INR L ;POINT TO NEXT CHAR
JNZ SENDC ;LOOP IF <100H
XRA A ;SHOW NOT INTO DATA..
STA DATAFLG ;..FOR VIEW COMMAND
RET ;FROM SENDSEC
;
;----> SENDCKS: SEND THE CHECKSUM
;
SENDCKS MOV A,C ;SEND THE..
CALL SEND ;..CHECKSUM
RET ;FROM SENDCKS
;
;----> GETACK: GET THE ACK ON THE SECTOR
;
;RETURNS WITH CARRY CLEAR IF ACK RECEIVED.
;IF AN ACK IS NOT RECEIVED, THE ERROR COUNT
;IS INCREMENTED, AND IF LESS THAN "ERRLIM",
;CARRY IS SET AND CONTROL RETURNS. IF THE
;ERROR COUNT IS AT "ERRLIM", THE PROGRAM
;ABORTS IF IN "QUIET" MODE, OR ASKS THE
;USER FOR QUIT/RETRY IF NOT.
;
GETACK MVI B,10 ;WAIT 10 SECONDS MAX
CALL RECVDG ;RECV W/GARBAGE COLLECT
JC GETATOT ;TIMED OUT
CPI ACK ;OK? (CARRY OFF IF =)
RZ ;YES, RET FROM GETACK
MOV B,A ;SAVE CHAR
LDA QFLG ;QUIET..
ORA A ;..MODE?
JZ ACKERR ;..YES, NO MSG
MOV A,B ;GET CHAR
CALL HEXO ;PRINT IN HEX
CALL ILPRT ;PRINT:
DB 'H RCD, NOT ACK',CR,LF,0
;
;TIMEOUT OR ERROR ON ACK - BUMP ERROR COUNT
;
ACKERR LDA ERRCT ;GET COUNT
INR A ;BUMP IT
STA ERRCT ;SAVE BACK
CPI ERRLIM ;AT LIMIT?
RC ;NOT AT LIMIT
;
;REACHED ERROR LIMIT
;
LDA VSEEFLG ;VIEWING..
ORA A ;..FILE?
JZ GACKV ;YES, ASK QUIT/RETRY
LDA QFLG ;QUIET..
ORA A ;..MODE?
JZ CSABORT ;..YES, NO MSG
;
GACKV CALL CKQUIT ;SEE IF WANT TO QUIT
STC ;TO SHOW NO ACK
RZ ;KEEP ON TRYIN'
;
CSABORT CALL ERXIT
DB 'CAN''T SEND SECTOR '
DB '- ABORTING',CR,LF,'$'
;
;TIMEOUT GETTING ACK
;
GETATOT LDA QFLG ;QUIET..
ORA A ;..MODE?
JZ ACKERR ;YES, NO MSG
CALL ILPRT ;PRINT:
DB 'TIMEOUT ON ACK',CR,LF,0
JMP ACKERR
;
ABORT LXI SP,STACK
;
ABORTL MVI B,1 ;1 SEC. W/O CHARS.
CALL RECV
JNC ABORTL ;LOOP UNTIL SENDER DONE
MVI A,NAK ;NEGATIVE ACK
CALL SEND ;TELL SENDING END
CALL ILPRT ;EXIT WITH ABORT MSG
DB 'MODEM PROGRAM CANCELLED',CR,LF,0
JMP CKDIS ;CHECK FOR DISCONN.
;
;----> INCRSNO: INCREMENT SECTOR #
;
INCRSNO LDA SECTNO ;INCR..
INR A ;..SECT..
STA SECTNO ;..NUMBER
RET
;
;----> ERASFIL: ERASE THE INCOMING FILE.
;
;IF IT EXISTS, ASK IF IT MAY BE ERASED.
;
ERASFIL LXI D,FCB ;POINT TO CTL BLOCK
MVI C,SRCHF ;SEE IF IT..
CALL BDOS ;..EXISTS
INR A ;FOUND?
RZ ;..NO, RETURN
CALL ILPRT ;PRINT:
DB '++FILE EXISTS, TYPE Y TO ERASE: ',0
CALL KEYIN ;GET CHAR
PUSH PSW
CALL TYPE ;ECHO
CALL CRLF ;BACK TO START OF LINE
POP PSW
ANI 5FH ;MAKE UPPER CASE
CPI 'Y' ;WANT ERASED?
JNZ CKDIS ;QUIT IF NOT ERASE
;
;ERASE OLD FILE
;
LXI D,FCB ;POINT TO FCB
MVI C,ERASE ;GET BDOS FNC
CALL BDOS ;DO THE ERASE
RET ;FROM "ERASFIL"
;
;----> MAKEFIL: MAKES THE FILE TO BE RECEIVED
;
MAKEFIL LXI D,FCB ;POINT TO FCB
MVI C,MAKE ;GET BDOS FNC
CALL BDOS ;TO THE MAKE
INR A ;FF=BAD?
RNZ ;OPEN OK
;DIRECTORY FULL - CAN'T MAKE FILE
CALL ERXIT
DB '++ERROR - CAN''T MAKE FILE',CR,LF
DB '++DIRECTORY MUST BE FULL',CR,LF,'$'
;
;----> OPENFIL: OPENS THE FILE TO BE SENT
;
OPENFIL LXI D,FCB ;POINT TO FILE
MVI C,OPEN ;GET FUNCTION
CALL BDOS ;OPEN IT
INR A ;OPEN OK?
JNZ OPENOK ;..YES
CALL ERXIT ;..NO, ABORT
DB 'CAN''T OPEN FILE$'
;
OPENOK CALL ILPRT ;PRINT:
DB 'FILE OPEN, EXTENT LENGTH: ',0
LDA FCB+15 ;GET # SECTORS
CALL HEXO ;PRINT IN HEX
CALL ILPRT ;PRINT:
DB 'H',CR,LF,0
RET
;
;----> CLOSFIL: CLOSES THE RECEIVED FILE
;
CLOSFIL LXI D,FCB ;POINT TO FILE
MVI C,CLOSE ;GET FUNCTION
CALL BDOS ;CLOSE IT
INR A ;CLOSE OK?
RNZ ;..YES, RETURN
CALL ERXIT ;..NO, ABORT
DB 'CAN''T CLOSE FILE$'
;
;----> RDSECT: READS A SECTOR
;
;FOR SPEED, THIS ROUTINE BUFFERS UP 16
;SECTORS AT A TIME.
;
RDSECT LDA SECINBF ;GET # SECT IN BUFF.
DCR A ;DECREMENT..
STA SECINBF ;..IT
JM RDBLOCK ;EXHAUSTED? NEED MORE.
LHLD SECPTR ;GET POINTER
LXI D,BASE+80H ;TO DATA
CALL MOVE128 ;MOVE TO BUFFER
SHLD SECPTR ;SAVE BUFFER POINTER
RET ;FROM "READSEC"
;
;BUFFER IS EMPTY - READ IN ANOTHER BLOCK OF 16
;
RDBLOCK LDA EOFLG ;GET EOF FLAG
CPI 1 ;IS IT SET/
STC ;TO SHOW EOF
RZ ;GOT EOF
MVI C,0 ;SECTORS IN BLOCK
LXI D,DBUF ;TO DISK BUFFER
;
RDSECLP PUSH B
PUSH D
MVI C,STDMA ;SET DMA..
CALL BDOS ;..ADDR
LXI D,FCB
MVI C,READ
CALL BDOS
POP D
POP B
ORA A ;READ OK?
JZ RDSECOK ;YES
DCR A ;EOF?
JZ REOF ;GOT EOF
;
;READ ERROR
;
CALL ERXIT
DB '++FILE READ ERROR$'
;
RDSECOK LXI H,80H ;ADD LENGTH OF ONE SECTOR...
DAD D ;...TO NEXT BUFF
XCHG ;BUFF TO DE
INR C ;MORE SECTORS?
MOV A,C ;GET COUNT
CPI 16 ;DONE?
JZ RDBFULL ;..YES, BUFF IS FULL
JMP RDSECLP ;READ MORE
;
REOF MVI A,1
STA EOFLG ;SET EOF FLAG
MOV A,C
;
;BUFFER IS FULL, OR GOT EOF
;
RDBFULL STA SECINBF ;STORE SECTOR COUNT
LXI H,DBUF ;INIT BUFFER..
SHLD SECPTR ;..POINTER
LXI D,BASE+80H ;RESET..
MVI C,STDMA ;..DMA..
CALL BDOS ;..ADDR
JMP RDSECT ;PASS SECT TO CALLER
;
;----> WRSECT: WRITE A SECTOR
;
;WRITES THE SECTOR INTO A BUFFER. WHEN 16
;HAVE BEEN WRITTEN, WRITES THE BLOCK TO DISK.
;
;ENTRY POINT "WRBLOCK" FLUSHES THE BUFFER AT EOF.
;
WRSECT LHLD SECPTR ;GET BUFF ADDR
XCHG ;TO DE FOR MOVE
LXI H,BASE+80H ;FROM HERE
CALL MOVE128 ;MOVE TO BUFFER
XCHG ;SAVE NEXT..
SHLD SECPTR ;..BLOCK POINTER
LDA SECINBF ;BUMP THE..
INR A ;..SECTOR #..
STA SECINBF ;..IN THE BUFF
CPI 16 ;HAVE WE 16?
RNZ ;NO, RETURN
;
;----> WRBLOCK: WRITES A BLOCK TO DISK
;
WRBLOCK LDA SECINBF ;# SECT IN BUFFER
ORA A ;0 MEANS END OF FILE
RZ ;NONE TO WRITE
MOV C,A ;SAVE COUNT
LXI D,DBUF ;POINT TO DISK BUFF
;
DKWRLP PUSH H
PUSH D
PUSH B
MVI C,STDMA ;SET DMA
CALL BDOS ;TO BUFFER
LXI D,FCB ;THEN WRITE
MVI C,WRITE ;..THE..
CALL BDOS ;..BLOCK
POP B
POP D
POP H
ORA A
JNZ WRERR ;OOPS, ERROR
LXI H,80H ;LENGTH OF 1 SECT
DAD D ;HL= NEXT BUFF
XCHG ;TO DE FOR SETDMA
DCR C ;MORE SECTORS?
JNZ DKWRLP ;..YES, LOOP
XRA A ;GET A ZERO
STA SECINBF ;RESET # OF SECTORS
LXI H,DBUF ;RESET BUFFER..
SHLD SECPTR ;..POINTER
;
RSDMA LXI D,BASE+80H ;RESET..
MVI C,STDMA ;..DMA..
CALL BDOS ;..ADDR
RET
;
WRERR CALL RSDMA ;RESET DMA TO NORM.
CALL ILPRT ;PRINT:
DB '++ERROR WRITING FILE',CR,LF,0
JMP ABORT ;EXIT
;
;----> RECV: RECEIVE A CHARACTER
;
;TIMEOUT TIME IS IN B, IN SECONDS. ENTRY VIA
;"RECVDG" DELETES GARBAGE CHARACTERS ON THE
;LINE. FOR EXAMPLE, HAVING JUST SENT A SECTOR,
;CALLING RECVDG WILL DELETE ANY LINE-NOISE-INDUCED
;CHARACTERS "LONG" BEFORE THE ACK/NAK WOULD
;BE RECEIVED.
;
RECVDG EQU $ ;RECEIVE W/GARBAGE DELETE
IN MODDATP ;GET A CHAR
IN MODDATP ;..TOTALLY PURGE UART
;
RECV PUSH D ;SAVE
;
IF FASTCLK ;4MHZ?
MOV A,B ;GET TIME REQUEST
ADD A ;DOUBLE IT
MOV B,A ;NEW TIME IN B
ENDIF
;
MSEC LXI D,50000 ;1 SEC DCR COUNT
;
IF NOT DCH
MWTI IN MODCTLP ;CHECK STATUS
ENDIF
;
IF DCH
MWTI IN MODCTL2 ;CHECK STATUS
ENDIF
;
ANI MODRCVB ;ISOLATE BIT
CPI MODRCVR ;READY?
JZ MCHAR ;GOT CHAR
DCR E ;COUNT..
JNZ MWTI ;..DOWN..
DCR D ;..FOR..
JNZ MWTI ;..TIMEOUT
DCR B ;MORE SECONDS?
JNZ MSEC ;YES, WAIT
;
;MODEM TIMED OUT RECEIVING
;
POP D ;RESTORE D,E
STC ;CARRY SHOWS TIMEOUT
RET
;
;GOT CHAR FROM MODEM
;
MCHAR IN MODDATP ;READ THE CHAR
POP D ;RESTORE DE
;
;CALC CHECKSUM
;
PUSH PSW ;SAVE THE CHAR
ADD C ;ADD TO CHECKSUM
MOV C,A ;SAVE CHECKSUM
;
;CHECK IF MONITORING REC'D DATA
;
LDA RSEEFLG ;SEE RECEIVED..
ORA A ;..DATA?
JZ MONIN ;..YES
;
;CHECK IF "VIEWING" AND THIS IS A DATA CHAR
;
LDA VSEEFLG ;VIEWING..
ORA A ;..DATA?
JNZ NOMONIN ;..NO
;
;"VIEW" REQUESTED. SHOW THE CHAR IT IS DATA
;
LDA DATAFLG ;GET DATA FLAG
ORA A ;TEST IT
JZ NOMONIN ;..OFF, NOT DATA
;
MONIN POP PSW ;..IS DATA,
PUSH PSW ;GET IT,
CALL SHOW ;..AND SHOW IT
;
NOMONIN POP PSW ;RESTORE CHAR
ORA A ;CARRY OFF: NO ERROR
RET ;FROM "RECV"
;
;----> SEND: SEND A CHARACTER TO THE MODEM
;
SEND PUSH PSW ;SAVE THE CHAR
;
;CHECK IF MONITORING SENT DATA
;
LDA SSEEFLG ;CHECK IF MONITORING..
ORA A ;..SENT DATA
JZ MONOUT ;..YES
;
;CHECK IF "VIEWING" THE FILE
;
LDA VSEEFLG ;GET VIEW FLAG
ORA A ;TEST IT
JNZ NOMONOT ;NO
LDA DATAFLG ;IS THIS
ORA A ;..DATA?
JZ NOMONOT ;..NO.
;
MONOUT POP PSW ;GET THE CHAR
PUSH PSW ;SAVE IT
CALL SHOW ;SHOW IT
;
NOMONOT POP PSW ;RESTORE CHAR
PUSH PSW ;SAVE IT
ADD C ;CALC CKSUM
MOV C,A ;SAVE CKSUM
;
IF NOT DCH
SENDW IN MODCTLP ;GET STATUS
ENDIF
;
IF DCH
SENDW IN MODCTL2 ;GET STATUS
ENDIF
;
ANI MODSNDB ;ISOLATE READY BIT
CPI MODSNDR ;READY?
JNZ SENDW ;..NO, WAIT
POP PSW ;GET CHAR
OUT MODDATP ;OUTPUT IT
RET ;FROM "SEND"
;
;----> WAITNAK: WAITS FOR INITIAL NAK
;
;TO ENSURE NO DATA IS SENT UNTIL THE RECEIVING
;PROGRAM IS READY, THIS ROUTINE WAITS FOR THE
;THE FIRST TIMEOUT-NAK FROM THE RECEIVER.
;(E) CONTAINS THE # OF SECONDS TO WAIT.
;
WAITNAK LDA VSEEFLG ;VIEWING?
ORA A
JZ WAITNPR ;PRINT MSG
LDA QFLG ;QUIET..
ORA A ;..MODE?
JZ WAITNLP ;YES, SKIP MSG
;
WAITNPR CALL ILPRT ;PRINT:
DB 'AWAITING INITIAL NAK',CR,LF,0
;
WAITNLP MVI B,1 ;TIMEOUT DELAY
CALL RECV ;DID WE GET..
CPI NAK ;..A NAK?
RZ ;YES, SEND BLOCK
DCR E ;80 TRIES?
JZ ABORT ;YES, ABORT
JMP WAITNLP ;NO, LOOP
;
;----> INITADR: INIT'S CP/M BDOS ADDRESSES
;
;THIS ROUTINE FILLS IN THE ADDRESSES OF VARIOUS
;JMP AND CALL INSTRUCTIONS, SO THAT CP/M BDOS
;IS BYPASSED WHILE ACCESSING THE CONSOLE. THIS
;IS DONE TO ALLOW CHARACTERS SUCH AS CONTROL-C
;AND CONTROL-S TO BE KEYED WHILE IN TERMINAL
;MODE, WITHOUT CP/M INTERPRETING THEM.
;
INITADR LHLD BASE+1 ;GET WARM BOOT ADDR
LXI D,3 ;LENGTH OF A 'JMP'
DAD D ;TO CONSOLE STAT
SHLD VSTAT+1 ;MODIFY CALL
DAD D ;TO CONSOLE IN
SHLD VKEYIN+1 ;MODIFY CALL
DAD D ;TO CONSOLE OUT
SHLD VTYPE+1 ;MODIFY CALL
RET
;
;----> PROCOPT: PROCESS COMMAND OPTIONS
;
;1) SAVES THE PRIMARY OPTION IN 'OPTION';
;2) SCANS THE SUB-OPTION CHARACTERS, AND FOR
;EACH FOUND, ZEROS THE APPROPRIATE ENTRY IN
;THE OPTION TABLE. FOR EXAMPLE, IF 'D' IS
;CODED (DISCONNECT) THEN THE 'D' STORED AT
;'DISCFLG' IS SET TO 0 SO IT CAN BE TESTED
;LATER.
;
PROCOPT LXI D,FCB+1 ;TO PRIMARY OPT.
LDAX D ;GET PRIMARY
STA OPTION ;SAVE IT
;
OPTLP INX D ;TO SECONDARY OPTION
LDAX D ;GET CHAR
;
;IF YOU MOD THIS PROGRAM FOR >7 OPTIONS,
;YOU MUST CHANGE THE FOLLOWING, SINCE
;THERE WON'T BE A ' ' AFTER THE OPTION
;IF A BAUD RATE WAS SPECIFIED.
;
CPI ' ' ;NO MORE OPT'NS?
JZ ENDOPT ;..YES
;SET THE APPROP. OPT: STORE 0 IN IT
LXI H,OPTBL ;HL = ADDR OF 'OAQDSRV'
MVI B,OPTBE-OPTBL ;OPT TABLE LEN
;
OPTCK CMP M ;FOUND THE OPTION?
JNZ OPTNO ;NO, DON'T SET IT
MVI M,0 ;SET THE OPTION
JMP OPTLP ;GET NEXT OPTION
;
OPTNO INX H ;TO NEXT
DCR B ;MORE?
JNZ OPTCK
;OPTION NOT IN TABLE
JMP BADOPT ;SHOW BAD SUB OPTION
;
;IF "VIEW" WAS ASKED FOR, SET QUIET FLAG
;
ENDOPT LDA VSEEFLG ;VIEW..
ORA A ;..ASKED FOR?
RNZ ;..NO, RET FROM 'PROCOPT'
STA QFLG ;YES, NO HDR/CKSUM PRT
RET ;FROM 'PROCOPT'
;
;DONE - CLOSE UP SHOP
;
DONE LDA VSEEFLG ;VIEWING?
ORA A
JZ DONETC ;SHOW MSG
LDA QFLG ;QUIET
ORA A ;..MODE?
JZ DONECTE ;YES, CK TERM/ECHO
;
DONETC CALL ILPRT
DB CR,LF,'TRANSFER COMPLETE'
DB CR,LF,0
;
;CHECK IF TERMINAL OR ECHO SUB COMMAND
;WAS SPECIFIED
;
DONECTE LDA TERMFLG ;TERM?
ORA A
JZ TERM ;..YES
LDA ECHOFLG ;ECHO?
ORA A
JZ TRMECHO ;..YES
;
;FALL INTO 'CKDIS'
;
;----> CKDIS: CHECK IF DISCONNECT REQUESTED
;
;THIS ROUTINE IS JUMPED TO AT THE END OF
;PROCESSING, AND DISCONNECTS THE PHONE IF
;'D' WAS SPECIFIED AS A SUB-OPTION.
;
CKDIS LDA DISCFLG ;CHECK 'D' FLAG
ORA A ;REQUESTED?
;
IF PMMI OR DCH
JNZ NDIS ;..NO, JUST EXIT
ENDIF
;
IF NOT PMMI AND NOT DCH
JNZ EXIT
ENDIF
;
;AWAIT C/R TO DISC. SO WE DON'T LOSE THE PHONE
;
CALL ILPRT
DB CR,LF,'PRESS RETURN TO DISCONNECT:',0
CALL KEYIN
PUSH PSW
CALL CRLF
POP PSW
CPI CR
JNZ CKDIS ;ASK AGAIN
;
;----> DISCONN: DISCONNECT THE PHONE
;
DISCONN EQU $
;
IF PMMI
XRA A ;GET DISCONN VALUE
OUT MODCTLP ;RESET ORIG/ANSW
OUT MODCTL2 ;TURN OFF DTR, DO BREAK
ENDIF
;
IF DCH
XRA A ;GET DISCONNECT VALUE
OUT MODCTLP ;DISCONNECT
ENDIF
;
CALL ILPRT ;PRINT:
DB '++DISCONNECTED++',0
JMP EXIT
;
;NO DISCONNECT, TYPE MSG AS REMINDER THAT PHONE'S
;OFF HOOK
;
IF PMMI OR DCH
NDIS LDA QFLG ;QUIET..
ORA A ;..MODE?
JZ EXIT ;..YES, NO MSG
CALL ILPRT
DB CR,LF,'++DON''T FORGET - THE MODEM IS '
DB 'NOT DISCONNECTED++',CR,LF
DB 'USE "MODEM D" TO DISCONNECT',CR,LF,0
JMP EXIT
;
ENDIF
;
;----> INITMOD: INITIALIZES THE MODEM
;
;THIS ROUTINE IS USED TO INITIALIZE SERIAL
;BOARDS, OR SETUP S-100 MODEM BOARDS.
;JUST RETURNS IF NO INITIALIZATION REQUIRED.
;
INITMOD:
;
IF INITREQ ;REQUIRE INIT?
MVI A,INITC1 ;GET 1ST INIT CHAR
OUT MODCTLP ;OUTPUT IT
NOP ! NOP! NOP ;DELAY FOR USART
NOP ! NOP
MVI A,INITC2 ;GET 2ND INIT CHAR
OUT MODCTLP ;OUTPUT IT
NOP ! NOP! NOP ;DELAY FOR USART
NOP ! NOP
MVI A,INITC3 ;GET 3RD INIT CHAR
OUT MODCTLP ;OUTPUT IT
NOP ! NOP! NOP ;DELAY FOR USART
NOP ! NOP
MVI A,INITC4 ;GET 4TH INIT CHAR
OUT MODCTLP ;OUTPUT IT
NOP ! NOP! NOP ;DELAY FOR USART
NOP ! NOP
ENDIF
;
IF PMMI
CALL GETBAUD ;GET THE BAUD RATE
OUT BAUDRP ;OUT BAUD RATE PORT
ENDIF ;PMMI
;
IF DCH
CALL GETBAUD ;GET BAUD RATE
ENDIF ;DCH
;
IF PMMI
;SET THE MOTOROLA MODEM CHIP BIT FOR >300 IF REQ'D
;
CPI 52 ;>300?
MVI A,5FH ;VALUE FOR >300
JC GT300
MVI A,7FH ;VALUE FOR <= 300
;
GT300 OUT MODCTL2 ;SET IT
;
;SET ORIG/ANSW IF REQUESTED
;
LDA ORIGFLG ;ORIGINATE..
ORA A ;..MODE?
MVI A,ORIGMOD
JZ OFFHOOK ;..YES, DO IT
LDA ANSWFLG ;ANSWER..
ORA A ;..MODE?
MVI A,ANSWMOD
RNZ ;NEITHER ORIG NOR ANSW.
ENDIF ;PMMI
;
IF DCH
LDA ANSWFLG ;ANSWER..
ORA A
MVI B,ANSWMOD ;SET ANSWER MODE
JZ INITM1
LDA ORIGFLG ;GET ORIGINATE FLAG
ORA A
MVI B,ORIGMOD ;SET ORIGINATE MODE
JZ INITM1
LDA HOLDD ;NEITHER - GET LAST VALUE
MOV B,A ;STORE IN B
;
INITM1: MOV A,B ;GET MODE
STA HOLDD ;SAVE VALUE
MOV A,C ;GET BAUD RATE INDICATOR
ORA A ;ZEBO IF 110 BAUD
MOV A,B ;GET MODE
JZ OFFHOOK ;DO OFFHOOK
ORI 1 ;SET 300 BAUD
ENDIF ;DCH
;
IF PMMI OR DCH
;
;GO OFFHOOK IN REQUESTED (ORIG/ANSW) MODE
;
OFFHOOK LXI H,4000 ;DELAY AMT
;
OFFDLY DCR L
JNZ OFFDLY
DCR H
JNZ OFFDLY
OUT MODCTLP ;GO OFF HOOK
STA CURRMOD ;SAVE CURRENT MODE (NEEDED BY DIALMOD)
RET
ENDIF ;PMMI OR DCH
;
IF PMMI
;----> GETBAUD: GETS BAUD RATE FROM COMMAND
;
;THIS ROUTINE CHECKS IF A BAUD RATE HAS
;BEEN ASKED FOR, (SUCH AS MODEM T.450),
;AND IF SO, CALCULATES THE PMMI BAUD RATE
;VALUE TO BE OUTPUT. DEFAULTS TO 300.
;
GETBAUD LDA FCB+9 ;GET 'FILETYPE'
CPI ' ' ;DEFAULT?
MVI A,52 ;300 BAUD VALUE
RZ ;NO BAUD RATE, USE 300
;
;GOT BAUD RATE - CONVERT TO PROPER TIMER VALUE
;
;FIRST, CONVERT THE NUMBER TO BINARY
;
CALL CVBIN
;
;CALCULATE THE VALUE TO OUTPUT:
;
; RATE = 250000/16/BAUD RATE
;
; DIVIDE BY REPETITIVE SUBTRACTION
; ------
;COMPLEMENT THE BAUD RATE
;
MOV A,H ;GET HI
CMA ;COMPLEMENT
MOV D,A ;SAVE
MOV A,L ;GET LO
CMA ;COMPLEMENT
MOV E,A ;SAVE
INX D ;DE=2'S COMPLEMENT
;DIVIDE
LXI H,15625 ;250000/16
LXI B,-1 ;INIT QUOTIENT
;
DIVLP INX B ;BUMP QUOTIENT
DAD D ;'SUBTRACT'
JC DIVLP ;LOOP 'TILL DONE
;VALIDATE THE RESULT
MOV A,B ;CAN'T HAVE >255
ORA A
MOV A,C ;GET ACTUAL
RZ ;RET IF <256
JMP BADRATE ;INVALID
ENDIF ;PMMI
;
IF DCH
GETBAUD LDA FCB+9 ;GET FILETYPE
CPI ' ' ;DEFAULT?
JNZ GETBAU1 ;NO - DO BAUD RATE STUFF
MVI C,1 ;SET 300 BAUD
MVI B,17H ;SET 1 STOP BIT
JMP GETBAU2
;
; CONVERT BAUD RATE TO BINARY
GETBAU1 CALL CVBIN ;CONVERT TO BINARY
PUSH H ;SAVE BAUD RATE
MVI C,0 ;ANTICIPATE 110 BAUD
MVI B,1FH ;SET 2 STOP BITS
LXI D,-110 ;GET CONSTANT
DAD D ;SUBTRACT
MOV A,H
ORA L
POP H
JZ GETBAU2 ;110 BAUD
MVI B,17H ;SET 1 STOP BIT
INR C
LXI D,-300 ;GET CONSTANT
DAD D
MOV A,H
ORA L
JNZ BADRATE ;INVALID
;
GETBAU2 MOV A,B ;GET SET UP
OUT MODCTL2 ;INITIALIZE MODEM FOR STOP BITS..
RET ;..DATA BITS, ETC.
ENDIF ;DCH
;
IF PMMI OR DCH
; ROUTINE TO CONVERT BAUD RATE TO BINARY
;
CVBIN: LXI D,FCB+9 ;TO ASCII VALUE
LXI H,0 ;INIT BINARY RESULT
;
DECLP LDAX D ;GET ASCII DIGIT
INX D ;TO NEXT DIGIT
CPI ' ' ;BLANK ONE?
JZ DECLP ;..YES, SKIP IT
CPI '0' ;VALIDATE IT
JC BADRATE ;ERROR
CPI '9'+1 ;VALIDATE
JNC BADRATE ;ERROR
SUI '0' ;MAKE DIGIT BINARY
;
;MULTIPLY PREV VALUE BY 10
;
MOV B,H ;SET UP FOR
MOV C,L ;MULTIPLY BY 10
DAD H ;MULTIPLY BY 2
DAD H ;X 2 = 4
DAD B ;+ 1 = 5
DAD H ;X 2 = 10
ADD L ;ADD IN DIGIT
MOV L,A ;SAVE BACK
JNZ DIGNC ;NO CARRY?
INR H ;ADD IN CARRY
;CHECK IF DONE?
DIGNC MOV A,E ;SEE IF PAST
CPI FCB+12 ;..LAST DIGIT
JNZ DECLP ;NO, LOOP
RET
;
;INVALID BAUD RATE
;
BADRATE CALL ERXIT
DB '++INVALID BAUD RATE++$'
ENDIF ;PMMI OR DCH
;
;THE FOLLOWING PROVIDES A RETURN FROM INITMOD
IF NOT PMMI AND NOT DCH
RET ;**THIS MUST BE HERE**
ENDIF ;NOT PMMI AND NOT DCH
;
;----> MOVEFCB: MOVES FCB(2) TO FCB
;
;I ATTEMPTED TO MAKE THE MODEM COMMAND 'NATURAL',
;I.E. MODEM SEND FILENAME (MODEM S FN.FT) RATHER
;THAT MODEM FILENAME SEND (MODEM FN.FT S) SO THIS
;ROUTINE MOVES THE FILENAME FROM THE SECOND FCB
;TO THE FIRST
;
MOVEFCB LXI H,FCB+16 ;FROM
LXI D,FCB ;TO
MVI B,16 ;LEN
CALL MOVE ;DO THE MOVE
XRA A ;GET 0
STA FCBSNO ;ZERO SECTOR #
STA FCBEXT ;..AND EXTENT
RET
;
;----> SHOW: SHOWS CHAR SENT/RECEIVED
;
;CR, LF, AND TAB ARE SHOWN. ALL OTHER
;NON-PRINTABLE CHARACTERS ARE SHOWN IN
;HEX AS (XX)
;
SHOW CPI LF ;LF?
JZ CTYPE ;..YES, TYPE IT
CPI CR ;CR?
JZ CTYPE ;..YES, TYPE IT
CPI 09 ;TAB
JZ CTYPE ;..YES, TYPE IT
CPI ' ' ;CTL-CHR?
JC SHOWHEX ;YES, SHOW IN HEX
CPI 7FH ;DEL?
JC CTYPE ;NO, TYPE THE CHAR
;
SHOWHEX PUSH PSW ;SAVE THE CHAR
MVI A,'(' ;TYPE..
CALL CTYPE ;..'('
POP PSW ;THEN..
CALL HEXO ;..THE CHAR
MVI A,')' ;THEN..
JMP CTYPE ;..')' AND RETURN.
;
;----> CTYPE: TYPES VIA CP/M SO TABS ARE EXPANDED
;
CTYPE PUSH B ;SAVE..
PUSH D ;..ALL..
PUSH H ;..REGS
MOV E,A ;CHAR TO E
MVI C,WRCON ;GET BDOS FNC
CALL BDOS ;PRIN THE CHR
POP H ;RESTORE..
POP D ;..ALL..
POP B ;..REGS
RET ;FROM "CTYPE"
;
CRLF MVI A,CR
CALL TYPE
MVI A,LF
;
;----> TYPE: TYPE VIA DIRECT CBIOS ACCESS
;WE ASSUME CBIOS MAY DESTROY SOME REGISTERS,
;SO SAVE THEM ALL.
;
;THIS ROUTINE BYPASSES CP/M'S CTL-S, CTL-C
;TESTS.
;
TYPE PUSH PSW ;SAVE CHAR
PUSH B ;AND OTHER REGISTERS
PUSH D
PUSH H
MOV C,A ;FOR BIOS
VTYPE CALL $-$ ;MODIFIED AT INIT
POP H ;RESTORE REGISTERS
POP D
POP B
POP PSW ;..AND CHAR
RET ;FROM "TYPE"
;
;----> STAT: KEYBOARD STATUS
;
;SAVE ALL REGISTERS, EXCEPT A, IN CASE
;CBIOS CLOBBERS THEM.
;
STAT PUSH B
PUSH D
PUSH H
VSTAT CALL $-$ ;ADDR SET AT INIT
POP H
POP D
POP B
ORA A ;0 => NOT READY
RET
;
;----> KEYIN: KEYBOARD INPUT
;
;SAVE ALL REGISTERS, EXCEPT A, IN CASE
;CBIOS CLOBBERS THEM.
;
KEYIN PUSH B
PUSH D
PUSH H
VKEYIN CALL $-$ ;ADDR SET AT INIT
POP H
POP D
POP B
ANI 7FH ;STRIP PARITY IF THERE
RET ;FROM KEYIN
;
;----> HEXO: HEX OUTPUT
;
HEXO PUSH PSW ;SAVE FOR RIGHT DIGIT
RAR ;RIGHT..
RAR ;..JUSTIFY..
RAR ;..LEFT..
RAR ;..DIGIT..
CALL NIBBL ;PRINT LEFT DIGIT
POP PSW ;RESTORE RIGHT
;
NIBBL ANI 0FH ;ISOLATE DIGIT
CPI 10 ;IS IS <10?
JC ISNUM ;YES, NOT ALPHA
ADI 7 ;ADD ALPHA BIAS
;
ISNUM ADI '0' ;MAKE PRINTABLE
JMP TYPE ;..THEN TYPE IT
;
;----> CKQUIT: QUIT/RETRY AFTER MULTIPLE ERRS.
;
;RETURNS W/ ZERO SET IF "RETRY" ASKED FOR
;
CKQUIT XRA A ;ZERO..
STA ERRCT ;..ERROR COUNT
CALL ILPRT ;PRINT:
DB 'MULTIPLE ERRORS ENCOUNTERED. '
DB 'TYPE Q TO QUIT, R TO RETRY: ',0
CALL KEYIN ;QUIT/RETRY
PUSH PSW
CALL TYPE
CALL CRLF
POP PSW
ANI 5FH ;MAKE UPPER CASE
CPI 'R' ;RETRY?
RZ ;'KEEP ON TRUCKIN'
CPI 'Q' ;QUIT?
JNZ CKQUIT ;NO, ASK AGAIN
ORA A ;SET NON-ZERO
RET
;
;----> ILPRT: INLINE PRINT OF MSG
;
;THE CALL TO ILPRT IS FOLLOWED BY A MESSAGE,
;BINARY 0 AS THE END. BINARY 1 MAY BE USED TO
;PAUSE (MESSAGE 'PRESS RETURN TO CONTINUE')
;
ILPRT XTHL ;SAVE HL, GET HL=MSG
;
ILPLP MOV A,M ;GET CHAR
ORA A ;END OF MSG?
JZ ILPRET ;..YES, RETURN
CPI 1 ;PAUSE?
JZ ILPAUSE ;..YES
CALL CTYPE ;TYPE THE MSG
;
ILPNEXT INX H ;TO NEXT CHAR
JMP ILPLP ;LOOP
;
;PAUSE WHILE TYPING HELP SO INFO DOESN'T
; SCROLL OFF OF VIDEO SCREENS
;
ILPAUSE CALL ILPRT ;PRINT:
DB CR,LF,'PRESS RETURN TO CONTINUE'
DB CR,LF,0
CALL KEYIN ;GET ANY CHAR
CPI 'C'-40H ;REBOOT?
JZ EXIT ;YES.
JMP ILPNEXT ;LOOP
;
ILPRET XTHL ;RESTORE HL
RET ;PAST MSG
;
;----> PRTMSG: PRINTS MSG POINTED TO BY (DE)
;
;A '$' IS THE ENDING DELIMITER FOR THE PRINT.
;NO REGISTERS SAVED.
;
PRTMSG MVI C,PRINT ;GET BDOS FNC
JMP BDOS ;PRINT MESSAGE, RETURN
;
;----> ERXIT: EXIT PRINTING MSG FOLLOWING CALL
;
ERXIT POP D ;GET MESSAGE
CALL PRTMSG ;PRINT IT
CALL CKDIS ;DISCONNECT?
;
EXIT LHLD STACK ;GET ORIGINAL STACK
SPHL ;RESTORE IT
RET ;--EXIT-- TO CP/M
;
;MOVE 128 CHARACTERS
;
MOVE128 MVI B,128 ;SET MOVE COUNT
;
;MOVE FROM (HL) TO (DE) LENGTH IN (B)
;
MOVE MOV A,M ;GET A CHAR
STAX D ;STORE IT
INX H ;TO NEXT "FROM"
INX D ;TO NEXT "TO"
DCR B ;MORE?
JNZ MOVE ;..YES, LOOP
RET ;..NO, RETURN
; ----------------
;
;
;----> DIALMOD: DETECT PHONE # IN COMMAND LINE AND DIAL IT
;
;THIS ROUTINE (AND THE CALL TO IT) IS ENABLED ONLY WHEN 'DCH'
;IS TRUE BECAUSE I DON'T KNOW HOW TO MAKE THE OTHER MODEM
;BOARDS DIAL. MOST OF THE PHONE NUMBER LOGIC SHOULD CROSS
;OVER TO OTHER MODEM BOARDS IF SOMEBODY WILL GIVE IT A TRY.
;
;THE PHONE NUMBER IS THE LAST PARAMETER IN THE COMMAND LINE.
;FOR EXAMPLE: MODEM T 123-456-7890
; MODEM E 123-456-7890
; MODEM S ABCDEFGH.IJK 123-456-8790
; MODEM R ABCDEFGH.IJK 123-456-7890
;IF NO PHONE NUMBER IS GIVEN, THIS ROUTINE RETURNS WITHOUT
;DOING ANYTHING. THE DIALER RECOGNIZES THE DIGITS 0-9 AND
;ALSO AN ASTERISK (*), WHICH CAUSES A TWO SECOND DELAY.
;THIS IS USEFUL FOR SUCH THINGS AS WAITING FOR THE SECOND
;DIAL TONE IN A CENTREX SYSTEM.
;THE POUND SIGN CHARACTER (#) MAY BE USED IN PLACE OF A PHONE
;NUMBER TO RE-DIAL THE LAST-DIALED PHONE NUMBER. THIS OF COURSE
;WILL ONLY WORK IF NO OTHER PROGRAMS HAVE BEEN EXECUTED IN THE
;INTERIM.
;ALL OTHER CHARACTERS ARE IGNORED. (THIS INCLUDES THE DASHES
;IN THE ABOVE EXAMPLES, WHICH COULD HAVE BEEN OMITTED.)
;THE LENGTH OF THE DIAL STRING MUST BE AT LEAST 7 CHARACTERS
;TO BE RECOGNIZED, AND MAY CONSIST OF UP TO 20 CHARACTERS.
;
IF FASTCLK
DIALTIM EQU -3390 ;SET DELAY LOOP LENGTH FOR DIALING
ENDIF
IF NOT FASTCLK
DIALTIM EQU -1786
ENDIF
;
IF DCH
DIALMOD:LXI H,BASE+80H ;LOOK AT CP/M COMMAND TAIL
MOV B,M ;GET BYTE COUNT
INX H ;BUMP TO FIRST CHAR
CALL SKBLNK ;SKIP LEADING BLANKS
RC ;NOTHING LEFT...QUIT
CALL SKARG ;ALWAYS AT LEAST ONE ARG TO SKIP
RC ;NOTHING FOLLOWS...QUIT
LDA OPTION ;LOOK AT MAIN OPTION TO SEE IF
CPI 'T' ; IT HAS A SECOND PARAMETER
JZ ONEARG ;T HAS ONLY ONE
CPI 'E' ;SO DOES E
JZ ONEARG
CALL SKARG ;MUST BE R OR S, SO SKIP FILENAME
RC ;QUIT IF NOTHING LEFT
ONEARG: MOV A,M ;LOOK AT FIRST CHAR OF PHONE #
CPI '#' ;REDIAL FLAG?
JZ REDIAL ;IF SO, DON'T COPY NUMBER
LXI D,DIALBUF
CNLUP: STAX D ;COPY PHONE NUMBER TO DIALBUF
INX D
INX H
MOV A,M
DCR B
JNZ CNLUP
SUB A ;TAG END OF NUMBER WITH A NULL
STAX D
REDIAL: CALL ILPRT ;SAY WE'RE DIALING
DB CR,LF,'DIALING - ',0
LDA CURRMOD ;PICK UP MODEM COMMAND BYTE
ANI 8DH ;REMOVE CARRIER ENABLE
OUT MODCTLP
MVI B,40
CALL VARDLY ;GIVE 2 SECOND DELAY FOR DIALTONE
LXI H,DIALBUF
DL: MOV A,M ;PICK UP DIGIT
ORA A
JZ WAITANS ;NULL MEANS FINISHED
CALL TYPE ;ECHO DIGIT
CPI '*'
MVI B,40 ;IF STAR, DO 2 SECOND DELAY
CZ VARDLY
INX H ;BUMP POINTER
SUI '0' ;CONVERT DIGIT TO BINARY
JNZ NOTZ ;CHANGE 0 TO 10
MVI A,10
NOTZ: JC DL ;IGNORE NON-NUMERIC
CPI 11
JNC DL
PULSE: PUSH PSW ;SAVE PULSE COUNT
LDA CURRMOD
ANI 7DH ;DROP OFF-HOOK
OUT MODCTLP
CALL DELAY ;FOR ONE HALF PULSE TIME
ORI 80H
OUT MODCTLP ;GO BACK OFF HOOK
CALL DELAY ;FOR OTHER HALF PULSE TIME
POP PSW ;GET BACK PULSE COUNT
DCR A ;COUNT IT DOWN
JNZ PULSE ;LOOP TILL DIGIT IS OUT
MVI B,10 ;DELAY 500MS BETWEEN DIGITS
CALL VARDLY
JMP DL ;GO DO NEXT DIGIT
;
VARDLY: CALL DELAY ;DELAY (B) TIMES 50 MS.
DCR B
JNZ VARDLY
RET
;
DELAY: PUSH H ;DELAY FOR 50 MILLISECONDS
PUSH D
PUSH PSW
CALL STAT ;CHECK FOR CONTROL-D
CNZ KEYIN
CPI DISCCHR ;TO ABORT DIALING
JZ DISCONN
POP PSW
LXI D,1 ;SET UP FOR DELAY LOOP
LXI H,DIALTIM
DLYLP: XTHL ;KILL LOTSA TIME
XTHL
DAD D ;SLOW WAY TO DO AN INX
JNC DLYLP
POP D
POP H ;RESTORE REGS
RET ;DONE
;
; COME HERE AFTER DIALING TO WAIT FOR ANSWER
;
WAITANS:CALL CRLF ;SHOW NUMBER FINISHED
LXI D,600 ;WE'LL WAIT 30 SECONDS FOR ANSWER
LDA CURRMOD
MOV B,A ;SAVE CURRENT MODE
ANI 4 ;CHECK ORIG/ANS BIT
JNZ CARR ;IF ORIG, WAIT FOR ANSWERING CARRIER
MOV A,B ;IF ANS, GIVE OUR CARRIER, THEN WAIT
OUT MODCTLP
CARR: IN MODCTL2 ;WAIT FOR CARRIER DETECT
ANI 40H
JNZ GOTCARR
CALL DELAY
DCX D ;COUNT DOWN DELAY
MOV A,D
ORA E
JNZ CARR
CALL ILPRT ;SAY WE'RE GIVING UP
DB BEL,'NO ANSWER',CR,LF,0
JMP DISCONN ;HANG UP
;
GOTCARR:CALL ILPRT ;SAY WE GOT IT
DB BEL,'CONNECTION ESTABLISHED',CR,LF,0
LDA CURRMOD ;RESTORE WHOLE MODE BYTE
OUT MODCTLP
RET ;ALL DONE
;
SKBLNK: MOV A,M ;SCAN PAST BLANKS IN COMMAND LINE
CPI ' '
RNZ
INX H
DCR B
JNZ SKBLNK ;CONTINUE SCAN TILL CHARS EXHAUSTED
STC ;CARRY SET SAYS END OF COMMAND
RET
;
SKARG: MOV A,M ;SCAN PAST ONE ARGUMENT AND FOLLOWING BLANKS
CPI ' '
JZ SKBLNK ;GOT BLANK...GO SKIP BLANKS
INX H
DCR B ;SCAN TILL STRING GONE
JNZ SKARG
STC ;SET CARRY ON RETURN IF END OF STRING
RET
;
ENDIF ;(FOR DIALING LOGIC)
;
;
OPTION DB 0 ;PRIMARY OPTION
;
;DATAFLG IS USED BY THE "V" SUBCOMMAND -
;IT IS 0 WHEN A HEADER OR CKSUM IS BEING
;SENT/RCD, AND 1 IF "VIEWABLE" DATA (THE
;SECTOR ITSELF) IS
;
DATAFLG DB 0 ;AT HEADER, FIRST
;
;
;SUB-OPTION TABLE. IF AN OPTION IS IN EFFECT,
; THE CHARACTER IS SET TO BINARY 0
;
OPTBL EQU $
ANSWFLG DB 'A' ;ANSWER MODE
DISCFLG DB 'D' ;DISCONNECT WHEN DONE
ECHOFLG DB 'E' ;TO ECHO AFTER XFER
ORIGFLG DB 'O' ;ORIGINATE MODE
QFLG DB 'Q' ;QUIET TRANSFER (NO MSGS)
RSEEFLG DB 'R' ;SEE WHAT'S RECEIVED
SSEEFLG DB 'S' ;SEE WHAT'S SENT
TERMFLG DB 'T' ;TO TERM AFTER XFER
VSEEFLG DB 'V' ;VIEW MESSAGES (NO HDR, ETC)
OPTBE EQU $ ;END OF OPTIONS
;
RCVSNO DB 0 ;SECT # RECEIVED
SECTNO DB 0 ;CURRENT SECTOR NUMBER
ERRCT DB 0 ;ERROR COUNT
HOLDD DB 86H ;HOLD AREA - LAST DC HAYES CONT CHAR.
CURRMOD DB 86H ;CURRENT MODEM COMMAND BYTE
;
;FOLLOWING 3 USED BY DISK BUFFERING ROUTINES
EOFLG DB 0 ;EOF FLAG (1=TRUE)
SECPTR DW DBUF
SECINBF DB 0 ;# OF SECTORS IN BUFFER
DS 60 ;STACK AREA
STACK DS 2 ;STACK POINTER
;
;16 SECTOR DISK BUFFER (OVERLAYS HELP MSGS)
;
DBUF EQU $ ;16 SECTOR DISK BUFFER
;
;INVALID COMMAND
;
BADOPT CALL TYPE
CALL ILPRT ;EXIT W/ERROR
DB ': INVALID OPTION ON MODEM '
DB 'COMMAND - ',CR,LF
DB 'PRESS RETURN FOR HELP, CTL-C IF NOT',CR,LF,1,0
;
HELP CALL ILPRT
DB 'Format for command is:',cr,lf,cr,lf
DB 'MODEM ? FILENAME'
IF DCH
DB ' PHONENUM'
ENDIF
DB CR,LF,CR,LF
DB 'Where ? is a 1 character primary option,',cr,lf
DB ' which may be followed by sub-options,',cr,lf
DB ' and by ".xxx" to set baud rate to xxx.',CR,LF
DB 'FILENAME is any valid CP/M unambiguous drive and filespec.',CR,LF
DB ' It is used only for the "R" and "S" functions.',CR,LF
IF DCH
DB 'PHONENUM is an optional parameter which if present',CR,LF
DB ' is a telephone number to be automatically dialed.',CR,LF
DB ' A "*" may be used to cause a 2 second pause in dialing.',CR,LF
DB ' A "#" means to redial the last phone number attempted.',CR,LF
DB ' All other characters are ignored.'
ENDIF
DB cr,lf,cr,lf,1
DB 'Primary Options:',cr,lf
DB ' S to send a file',cr,lf
DB ' R to receive a file',cr,lf
DB ' T to act as a terminal',cr,lf
DB ' E to act as a computer (echo data)',cr,lf
DB ' D to disconnect the phone'
DB ' (S100 modems only)',cr,lf
DB ' H to print this help file'
DB cr,lf,cr,lf,1
DB 'Secondary options:',cr,lf
DB ' A answer mode',cr,lf
DB ' O originate mode',cr,lf
DB ' D disconnect after execution',cr,lf
DB ' T go to terminal mode after file xfer',cr,lf
DB ' E go to echo mode after file xfer',cr,lf
DB ' Q quiet mode - no status msgs',cr,lf
DB ' R show chars received',cr,lf
DB ' S show chars sent',cr,lf
DB ' V view file sent/received (no status)',cr,lf
DB CR,LF,'FOR EXAMPLES, TYPE: MODEM X',cr,lf,0
JMP EXIT
;
EXAM CALL ILPRT
DB 'Send file, originate mode, 300 baud:',CR,LF
DB ' MODEM SO fn.ft',cr,lf
DB 'Send another file:',CR,LF
DB ' MODEM S fn.ft',cr,lf
DB 'Then send a third file at 450 baud and disconnect:'
DB CR,LF,' MODEM SD.450 fn.ft',cr,lf
DB 'Act as a terminal, originate mode, at 110 baud:',cr,lf
DB ' MODEM TO.110',CR,LF
DB ' (Use ctl-D to disconnect)',cr,lf
DB 'Receive file, answer mode, view it, 600 baud:',cr,lf
DB ' MODEM RAV.600 fn.ft',cr,lf,0
JMP EXIT
;
;
DS 128-($ AND 127) ;FORCE NEXT SECTOR BOUNDARY
DIALBUF EQU $ ;STORAGE FOR NUMBER BEING DIALED
;
;
; BDOS EQUATES (VERSION 2)
;
RDCON EQU 1
WRCON EQU 2
PRINT EQU 9
CONST EQU 11 ;CONSOLE STAT
OPEN EQU 15 ;0FFH=NOT FOUND
CLOSE EQU 16 ; " "
SRCHF EQU 17 ; " "
SRCHN EQU 18 ; " "
ERASE EQU 19 ;NO RET CODE
READ EQU 20 ;0=OK, 1=EOF
WRITE EQU 21 ;0=OK, 1=ERR, 2=?, 0FFH=NO DIR SPC
MAKE EQU 22 ;0FFH=BAD
REN EQU 23 ;0FFH=BAD
STDMA EQU 26 ;SET DMA
BDOS EQU BASE+5
REIPL EQU BASE
FCB EQU BASE+5CH ;SYSTEM FCB
FCBEXT EQU FCB+12 ;FILE EXTENT
FCBSNO EQU FCB+32 ;SECTOR #
FCB2 EQU BASE+6CH ;SECOND FCB
END