; ;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