TITLE 'CP/M MODEM PROGRAM Version 7.6' ; ;THE FOLLOWING IS AN EXTENSIVE REVISION OF THE CP/M MODEM PROGRAM ;CREATED BY WARD CHRISTENSEN FOR THE CP/M USERS LIBRARY. ;IT ALSO INCORPORATES ROUTINES FOUND IN THE POTOMAC MICRO-MAGIC MODEM ;MANUAL WHICH MAY BE USED IF YOU HAVE A PMMI MODEM BOARD. ;4/12/82 Merged in changes/enhancements from versions 7.32 ;and 7.4 and MODEM75.FIX. This should hopefully give us one ;"master" version again. B. R. Ratoff ;Summary: ; @7.32 - Delay loop at DILAGN1 to allow "smart" terminals time ; to process bell character. ; ; @MODEM75.FIX - Maintain originate mode on RET command after ; transferring files (at TERM:). Restore option tables correctly ; on control-D command (at DIR). Issue "file open" message on ; receive (at RCVC3). ; @7.41 - Make CRC/checksum switching on Receive automatic.... ; assumes CRC and defaults to checksum on timeout. ; ;2/20/82 Changes at TERM and START1 marked by ; @7.5 fix a ;long standing bug in MODEM7x that causes abort at the end of a ;batch file transfer or an attempt to transfer a non-existent ;file. The call to NOPARIT in DONETCE caused a computer that was ;in answer mode (but not explicitly by command option) to switch ;to originate mode thus causing the two ends to no longer communicate ;with each other. Also added SAVCCP byte and code to prevent ;overwriting of the CCP at the users option. R. L. Plouffe ;1/23/82 The following changes have been made in this version. ; RLP ;Extensive cleanup of the file including colons after all labels ;for easier search with screen editor for the purposes of debug. ;Also set file capture mode so as not to overwite the CCP and ;changed EXIT to return to the CCP instead of doing warm boot. ; ;TERML routine fix: ;Added Rick Kawala's fix so that fewer framing errors will occur ;with hosts that send out characters with high bit set. ; ;CAL command fix: ; All versions of MODEM7 including MODEM73 are supposed to be ;able to accept "CAL n" (where n is either a library letter or ;a phone-number string) as a valid form of the CAL command. In ;fact, however, the "n" will simply be ignored. This is because ;routine DIALPL checks for a command length >= 4 as a signal to ;skip the library display, but the menu routine, after ;recognizing CAL, sets the length to 1 so the L in CAL doesn't ;look like an illegal secondary option. ; The following kludge repairs this defect. In routine ;DIALPL, two lines above label DIALPL0, change CMDBUF+5 to ;CMDBUF+6. Also, in routine GETCMD, three lines above label ;NXTOPT2, change MVI A,1 to MVI A,20H and change the next line ;from STA CMDBUF+1 to STA CMDBUF+4. This makes the command ;look to the option processor like "CA n", and since A is a ;legal secondary option (which in this case is never used) the ;line passes muster. If an actual telephone number is used, ;you have to type an extra blank: CAL 000-0000, whereas ;with library numbers one blank only must be typed: CAL A. ;12/16/81 Removed stack imbalance bug at COLONB by adding ; a JMP BRK1. Change is marked by ;@ R. L. Plouffe ;11/21/81 Fixed code so byte received is on same line when ; messages "XXH RCD, NOT SOH" or "XXH RCD, NOT ACK" ; are displayed. Also changed stack size to 50H. ; (P.L.Kelley) ;10/29/81 Changed receive sector routine so that on the first ;time through when CRC is being used, it only waits 3 seconds ;to receive the SOH after sending the initial 'C'. If a ;character is not received within 3 seconds, then a NAK is ;sent and this program switches to CHECKSUM mode. The sending ;of the NAK causes XMODEM or MODEM to start sending the file ;using checksum checking. This allows the CRC MODEM7 program ;to be used with versions of XMODEM, MODEM, and MODEM7 that ;do not use CRC, even when MODEM7 has specified a CRC ;transmission. (John Mahr) ;10/18/81 Added CRC option. This is another secondary option ;that is specified by giving a 'C'. ; MODEM RC.600 fn.ft ; MODEM ROC.300 fn.ft etc. ; note: cannot have more than 6 secondary options. ;When the file receive cmd. specifies CRC, the ltr. 'C' is ;sent in place of the initial NAK. This signals the sender ;(XMODEM54 or equiv.) that CRC is in effect. The sending ;program will repalce the checksum with the CRC 2 bytes. ;CRC will give better than a 99.99% probability that there ;are no data errors. Code copied from MODEM213, thanks to ;John Mahr and Paul Hansknecht for the implementation. (WDE) ;10/11/81 Add first NAK to RCVFIL to speed up start ;Removed monitor scroll from good block messages ;CTL-^ forces send of next char in T mode (for ctl-E,ctl-D) (WDE) ;07/05/81 Added BRR ctrl char chgs, my number list (Bill Earnest) ;06/05/81 Deleted some unneeded messages in the dial routines. (Bob Clyne) ;05/31/81 Added detection of framing, overrun, and parity errors for ; Receive file routine. (A modified version of the routines in ; MODEM V2.06) ; Added provisions to send and receive either even or odd parity ; bit with PMMI modem in the 'S'end or 'R'eceive file modes - resets ; to no parity in other modes. Use of the parity feature will slow ; transfers slightly due to the extra (parity) bit being sent with ; each character. Also this is the only program that I KNOW OF that ; actually sends, or sets up the PMMI to receive, the parity bit. ; Both ends must be set to the same parity for it to work. Parity ; is invoked by adding a '0' (ASCII) for even parity or a '1' (ASCII) ; for odd parity to the 'S'end or 'R'eceive command string eg. R0.600. ; Changed timing for sending 'B'reak in the terminal mode. ; Changed the code so that the 'M'enu command works from the keyboard ; even when in XPR (expert) mode. ; Added display of hex in addition to decimal numbers for file length ; and sector numbers. ; Removed provision for remote cancel of file transfers in the 'S'end ; and 'R'eceive modes to prevent line noise from aborting a transfer. ; (Bob Clyne) ;02/15/81 Patched in the ringback routines from DIAL6/23. It doesn't ; seem to be able to recognize when the other phone is ringing ; though so it is a little shakey. ; Put in routines to calculate file sizes and sector numbers in ; decimal. ; Put in code to transmit a "BREAK" with a PMMI for use with ; computers which use BREAK instead of Control S to suspend ; output. Control P is now the baudrate change request key ; and Control @ is the BREAK key.. (Bob Clyne) ;12/18/80 Changed disconnect timing. ;10/26/80 Minor revision to allow 25-second 'wait' after PMMI ; autodial -- longer time required for Chicago CBBS*. Jim Mills. ; * CBBS is a trademark of Ward Christensen and Randy Suess. MACLIB MODEM7 ;CONTAINS CMDLINE, INBUF, INLNCOMP, ;DIR, AND MFACCESS ROUTINES ;changed to MODEM.LIB by Jim Mills ;to differentiate from other 'MACROS.LIB' TRUE EQU 0FFH FALSE EQU 0 CPM2X EQU TRUE ;true if CP/M 2.X DBUFSIZ EQU 16 ;BUFFER SIZE IN KBYTES ; PMMI EQUATES PORT EQU 0C0H ;PMMI BASE ADDRESS MODCTLP EQU PORT ;MODEM CONTROL PORT MODSNDB EQU 1 ;MODEM SEND BIT (XMIT BUFF EMPTY) MODSNDR EQU 1 ;MODEM SEND READY MODRCVB EQU 2 ;MODEM RECEIVE BIT (DAV) MODRCVR EQU 2 ;MODEM RECEIVE READY MODDATP EQU PORT+1 ;MODEM DATA PORT BAUDRP EQU PORT+2 ;BAUD RATE PORT MODCTL2 EQU PORT+3 ;2ND MODEM CONTROL PORT ORIGMOD EQU 1DH ;ORIGINATE MODE ANSWMOD EQU 1EH ;ANSWER MODE BRKMSK EQU 0FBH ;MASK TO SET BREAK FRMER EQU 20H ;FRAMING ERROR MASK ORUNER EQU 10H ;OVERRUN ERROR MASK PARER EQU 08H ;PARITY ERROR MASK ODPARMSK EQU 0CFH ;MASK TO SET ODD PARITY EVPARMSK EQU 20H ;MASK TO SET EVEN PARITY NOPARMSK EQU 10H ;MASK TO RESET TO NO PARITY ERRCDMSK EQU 38H ;MASK FOR ALL BITS EXCEPT ERROR CODES WAITCTS EQU 255 ;number of seconds X 10 to wait for computer ;tone after pmmi auto-dial function, 255 MAX. CHGBAUD EQU 'P'-40H ;USED IN TERMINAL MODE TO CHANGE ;BAUD RATE 'ON THE FLY' ERRLIM EQU 10 ;NUMBER OF TIMES TO RETRY ;SEND/RECEIVE ERRORS BEFORE QUIT BRKCHR EQU '@'-40H ; ^@ = TRANSMIT "BREAK" WITH PMMI EXITCHR EQU 'E'-40H ; ^E = EXIT WITHOUT DISCONNECT DISCCHR EQU 'D'-40H ; ^D = DISCONNECT TRANCHR EQU 'T'-40H ; ^T = TRANSFER CHARACTER CAN EQU 'X'-40H ; ^X = CANCEL SEND/RECEIVE EOFCHAR EQU 'Z'-40H ; ^Z = END OF FILE SAVECHR EQU 'Y'-40H ; ^Y = SAVE CHARACTER XOFF EQU 'S'-40H ; ^S = XOFF CHARACTER XON EQU 'Q'-40H ; ^Q = XON CHARACTER EXTCHR EQU '^'-40H ; ^^ = SEND NXT CHR SOH EQU 1 ; START OF HEADER EOT EQU 4 ; END OF TEXT ACK EQU 6 ; ACKNOWLEDGE NAK EQU 15H ; NOT ACKNOWLEDGE CRC EQU 'C' ;USED TO RQST CRC INSTEAD OF CLSUM BDNMCH EQU 75H ; BAD NAME MATCH OKNMCH EQU ACK ; OKAY NAME MATCH LF EQU 10 ; LINEFEED CR EQU 13 ; CARRIAGE RETURN BELL EQU 7 ; BELL CHARACTER FRONTPAN EQU 0FFH ; IMSAI FRONT PANEL BOTTRAM SET LAST+100H AND 0FF00H ORG 100H JMP START ;THESE ROUTINES ARE AT THE BEGINNING OF THE PROGRAM SO ;THEY CAN BE PATCHED BY A MONITER WITHOUT RE-ASSEMBLING ;THE PROGRAM. PMMIBYTE: DB TRUE ;true=pmmi modem IMSAIBYTE: DB FALSE ;true=imsai front panel FASTCLK: DB TRUE ;4 MHz or greater BAKUPBYTE: DB FALSE ;true=make .BAK file XPRFLG: DB TRUE ;true=no menu, false=print menu PULSERATE: DB 125 ;125 FOR 20PPS, 250 FOR 10PPS dialing SAVCCP DB TRUE ;true=do not overwrite CCP IN$MODCTLP: IN MODCTLP ! RET ;in modem control port OUT$MODDATP: OUT MODDATP ! RET ;out modem data port ANI$MODSNDB: ANI MODSNDB ! RET ;bit to test for send ready CPI$MODSNDR: CPI MODSNDR ! RET ;value of send bit when ready IN$MODDATP: IN MODDATP ! RET ;in modem data port ANI$MODRCVB: ANI MODRCVB ! RET ;bit to test for receive ready CPI$MODRCVR: CPI MODRCVR ! RET ;value of receive bit when ready JMP$INITMOD: JMP INITMOD ;to initialize port, if necessary IN$BAUDRP: IN BAUDRP ! RET ;in baudrate port OUT$BAUDRP: OUT BAUDRP ! RET ;out baudrate port OUT$MODCTL2: OUT MODCTL2 ! RET ;out modem control port #2 OUT$MODCTLP: OUT MODCTLP ! STA UARTCTLB ! RET ;out modem control port ;and store control byte CRFLAG: DB 0 ;CONTINUOUS REDIAL FLAG ; PHONE NUMBER LIBRARY TABLE FOR DIALING FROM LIBRARY ; OF NUMBERS STORED IN THESE DB'S AT ASSEMBLY-TIME. ; EACH DB MUST BE 30 CHARACTERS LONG FOR PROPER OPERATION. ; A 'DB 0' INDICATES NO DIALING, PROGRAM WILL DISCONNECT ; AND RETURN TO COMMAND MODE. LAST DB MUST BE DB 0. UP TO ; 26 NUMBERS ARE ALLOWED. NUMBLIB: ; '----5---10---15---20---25---30' DB 'A=Amrad 703-734-1387' ;'A' DB 'B=Ben Bronson 312-955-4493' ;'B' DB 'C= ' ;'C' DB 'D=C.Cliff C.C. 312-234-9257' ;'D' DB 'E=Ron Fowler 313-729-1905R' ;'E' DB 'F= ' ;'F' DB 'G=Gasnet NASA 301-344-9156' ;'G' DB 'H=Dave Hardy 313-846-6127' ;'H' DB 'I=Wayne Hammerly 301-953-3753' ;'I' DB 'J= ' ;'J' DB 'K=David Kozinn 216-334-4604' ;'K' DB 'L=Program Store 202-337-4694' ;'L' DB 'M=Kelly Smith 805-527-9321' ;'M' DB 'N= ' ;'N' DB 'O=SYSOP Sys 313-885-0506' ;'O' DB 'P=K.Petersen 313-759-6569R' ;'P' DB 'Q=R.Plouffe 703-524-2549' ;'Q' DB 'R=Bruce Ratoff 201-272-1874' ;'R' DB 'S= ' ;'S' DB 'T=Tech. CBBS 313-846-6127' ;'T' DB 'U=PMMI 703-379-0303' ;'U' DB 'V= ' ;'V' DB 'W= ' ;'W' DB 'X= ' ;'X' DB 'Y= ' ;'Y' DB 'Z= ' ;'Z' DB 0 ; end START: LXI H,0 DAD SP ;GET CP/M'S STACK SHLD STACK ;SAVE IT LXI SP,STACK ;START LOCAL STACK CALL START1 DB CR,LF,'MODEM 7.6 as of 4/12/82',cr,lf DB 'Originally Written by Ward Christensen',cr,lf,'$' START1: POP D ;GET ADDRESS OF ABOVE MESSAGE MVI C,PRINT ; 9 CALL BDOS CALL INITADR ;INITIALIZE ADDRESSES MVI A,TRUE ; 0FFH STA NFILFLG CMA ; 0 STA SAVEFLG OUT FRONTPAN ; IMSAI CALL PROCOPT ;PROCESS CONTROL OPTIONS LDA ORIGFLG ; @7.5 ORA A ; @7.5 MVI A,ANSWMOD ; @7.5 STA UARTCTLB ; @7.5 JNZ START2 ; @7.5 MVI A,ORIGMOD ; @7.5 STA UARTCTLB ; @7.5 START2: LDA OPTION ;GET MAIN OPTION CPI 'X' ;EXPERT FLAG? JNZ RESTART ;NO MVI A,TRUE ;YES STA XPRFLG ;MAKE EXPERT JMP MENU RESTART: LDA OPTION ;GET MAIN OPTION MOV B,A ;SAVE IT LDA PMMIBYTE ;PMMI? ORA A ;SET FLAGS MOV A,B ;GET OPTION BACK JZ S1 ;NOT PMMI CPI 'C' ;CALL (DIAL) FUNCTION? JZ DIALPL ;YES, GO TO IT S1: CPI ' ' ;NO OPTION SPEC'D? JZ MENU ;TRUE, GO MENU CPI 'M' ;MENU ASKED FOR? JZ MENU2 ;YES, GO MENU CALL JMP$INITMOD CALL MOVEFCB MVI A,FALSE STA NFILFLG CALL IN$MODDATP ;GOBBLE UP GARBAGE.. CALL IN$MODDATP ;..CHARACTERS ON LINE LDA OPTION ;PROCESS MAIN OPTION CPI 'E' ;ECHO MODE? JZ TRMECHO ;YES CPI 'T' ;TERMINAL MODE? JZ DSKSAVE ;YES CPI 'S' ;SEND A FILE? JZ SENDFIL ;YES CPI 'R' ;RECEIVE A FILE? JZ RCVFIL ;YES CPI 'D' ;DISCONNECT? JZ DISCON1 ;YES, DISCONNECT & GO MENU JMP MENU ;NO OPTION SPEC'D, GO MENU ;REVISED TERMINAL ROUTINE ALLOWING MEMORY SAVE DSKSAVE: LDA NFILFLG ;NEW FILE FLAG CPI TRUE ;OFFH? (TRUE=NORMAL TERMINAL MODE) JZ TERM ;YES LDA FCB+1 ;FIRST CHAR OF FILENAME CPI ' ' ;FILE SPEC'D JNZ GOODNM ;YES, GOOD NAME MVI A,TRUE ;0FFH STA NFILFLG ; OUT FRONTPAN ;0FFH PORT FOR IMSAI FRONT PANEL CMA ; 0 STA SAVEFLG ; JMP TERM ; GOODNM: CALL ERASFIL CALL MOVE2 LXI D,FCB3 MVI C,MAKE CALL BDOS LXI D,FCB3 MVI C,OPEN CALL BDOS LXI H,BOTTRAM SHLD HLSAVE MVI A,FALSE STA NFILFLG TERM: LDA ORIGFLG ; @7.5 sta origsav ; @MODEM75.FIX ORA A ; @7.5 MVI A,ANSWMOD ; @7.5 STA UARTCTLB ; @7.5 JNZ TERM2 ; @7.5 MVI A,ORIGMOD ; @7.5 STA UARTCTLB ; @7.5 TERM2: CALL STAT ;KEYPRESS? JZ TERML ;NO, CHECK LINE CALL KEYIN ;GET CHAR FROM KBD MOV B,A ;SAVE LDA EXACFL ORA A ;EXACT? MVI A,0 STA EXACFL ;CLR FOR NEXT TIME MOV A,B ;RESTORE JNZ NOTOG CPI EXITCHR ;^E? JZ MENU ;YES, RETURN TO MENU CPI DISCCHR ;^D? JZ DISCON1 ;YES, DISCONNECT & RETURN TO MENU CPI EXTCHR ;^^? JZ EXTFLG ;YES, SET FLAG FOR NXT CHAR CPI TRANCHR ;TEST FOR TRANSFER REQUEST (^T) CZ TRANSFER ;SEND-A-FILE (BLIND SEND) JZ TERM ;LOOP MOV B,A LDA PMMIBYTE ORA A MOV A,B JZ S2 CPI BRKCHR ;BREAK? JZ BREAK CPI CHGBAUD PUSH PSW PUSH H CZ NEWBAUD POP H POP PSW JZ TERML S2: CPI SAVECHR JNZ NOTOG LDA NFILFLG ;DO NOT ALLOW SAVE IF.. CPI TRUE ;..THIS FLAG IS SET. JZ TERML LDA SAVEFLG CMA STA SAVEFLG JMP TERML EXTFLG: MVI A,TRUE STA EXACFL JMP TERML NOTOG: CALL OUT$MODDATP TERML: CALL IN$MODCTLP CALL ANI$MODRCVB CALL CPI$MODRCVR JNZ TERM CALL IN$MODDATP ANI 7FH ;STRIP PARITY JZ TERM CALL TYPE PUSH PSW LDA SAVEFLG CPI FALSE JZ NOSAVE POP PSW MOV M,A INX H SHLD HLSAVE ;MENU COMMAND DESTROYS HL-REG.. ;..GET HL WHEN ENTERING VIA 'RET' CMD. MOV B,A LDA IMSAIBYTE ORA A MOV A,B JZ COLON CMA ;FRONT PANEL SHOWS CHARS WHEN.. OUT FRONTPAN ;..MEMORY SAVE IS ACTIVE. JMP NOCOLON COLON: CPI LF ;IF NO FRONT PANEL, THEN.. JNZ NOCOLON ;..TYPE ":" AFTER EACH LINE FEED.. MVI A,':' ;..WHEN MEMORY SAVE ACTIVE. CALL TYPE NOCOLON: LDA 7 ;CHECK TO SEE IF.. PUSH PSW LDA SAVCCP ORA A JZ SUB1 POP PSW SBI 8 ;..PAGE BELOW CCP .. SUB1: DCR A ;..OR BDOS HAS BEEN.. CMP H ;..REACHED AND DISKSAVE IS NEEDED. CZ INTDSKSV JMP TERM NOSAVE: POP PSW JMP TERM SAVEFLG: DB FALSE LASTBYT1: DB 0 LASTBYT2: DB 0 INTDSKSV: MVI A,XOFF ;SEND A CTRL-S TO STOP.. CALL OUT$MODDATP ;..REMOTE COMPUTER OUTPUT. MVI D,0 ;D IS THE BUFFER COUNT CALL INMODEM ;GET LAST BYTES SENT.. STA LASTBYT1 ;..AFTER CTRL-S. CALL INMODEM ;ADD MORE CALLS TO INMODEM.. STA LASTBYT2 ;..AND STA LASTBYT# IF YOU ARE.. ;..LOSING BYTES WHEN MEMORY IS FULL. PUSH D CALL NUMREC1 CALL WRTDSK ;WRITE THE RECORDS POP D LXI H,BOTTRAM INR D DCR D ;TEST BUFFER COUNT FOR ZERO JZ CTRLQ LDA LASTBYT1 ;GET THE LAST BYTES THAT WERE.. MOV M,A ;..SAVED AND PUT THEM IN.. INX H ;..BOTTRAM. CALL TYPE DCR D JZ CTRLQ LDA LASTBYT2 MOV M,A INX H CALL TYPE CTRLQ: MVI A,XON ;SEND START CHARACTER.. CALL OUT$MODDATP ;..TO REMOTE COMPUTER. RET BREAK: PUSH D ;SAVE IT LXI D,0 ;ZERO IT LDA MODCTLB ;GET THE LAST MODEM CONTROL BYTE ANI 0FBH ;SET THE TRANSMIT BREAK BIT LOW - ACTIVE LOW CALL OUT$MODCTL2 ;SEND IT TO THE MODEM LDA FASTCLK ;GET FAST CLOCK FLAG ORA A ;SET FLAGS LXI B,450 ;BREAK DELAY COUNTER FOR SLOW CLOCK JZ BRK1 ;JUMP IF NOT FAST CLOCK LXI B,900 ;BREAK DELAY COUNTER FOR FAST CLOCK BRK1: CALL TIMERL JZ BRK2 ;IF TIME IS UP RESET BREAK CPI 0 ;CHECK FOR NULLS JZ BRK1 ;DON'T PROCESS THEM ANI 7FH ;STRIP PARITY CALL TYPE PUSH PSW LDA SAVEFLG CPI FALSE JZ NOSAVEB POP PSW MOV M,A INX H SHLD HLSAVE ;MENU COMMAND DESTROYS HL-REG.. ;..GET HL WHEN ENTERING VIA 'RET' CMD. PUSH D MOV D,A LDA IMSAIBYTE ORA A MOV A,D POP D JZ COLONB CMA ;FRONT PANEL SHOWS CHARS WHEN.. OUT FRONTPAN ;..MEMORY SAVE IS ACTIVE. JMP BRK1 COLONB: CPI LF ;IF NO FRONT PANEL, THEN.. JNZ BRK1 ;..TYPE ":" AFTER EACH LINE FEED.. MVI A,':' ;..WHEN MEMORY SAVE ACTIVE. CALL TYPE JMP BRK1 ;@ NOSAVEB: POP PSW ;RESTORE IT JMP BRK1 BRK2: LDA MODCTLB ;GET MODEM CONTROL BYTE CALL OUT$MODCTL2 POP D LHLD HLSAVE ;LAST ADDRESS WRITTEN IF DATA BEING SAVED LDA 7 ;CHECK TO SEE IF.. PUSH PSW LDA SAVCCP ORA A JZ SUB2 POP PSW SBI 8 ;..PAGE BELOW CCP .. SUB2: DCR A ;..OR BDOS HAS BEEN .. CMP H ;..REACHED AND DISKSAVE IS NEEDED. JNZ TERM ;NO PROBLEM - GO BACK TO NORMAL ROUTINE CALL ILPRT DB CR,LF,'Memory save buffer full',CR,LF,BELL,0 JMP TERM ;THIS SUBROUTINE WILL LOOP UNTIL THE MODEM RECEIVES A CHARACTER ;OR 100 MILLISECONDS. IF A CHARACTER IS RECEIVED, A FLAG IS SET ;TO STORE THE CHARACTER. A MAXIMUM OF TWO CHARACTERS ARE STORED, ;BUT MORE MAY BE STORED IF DESIRED (SEE COMMENT IN "INTDSKSV" ;ABOVE). INMODEM: LDA FASTCLK ORA A LXI B,1250 JZ TIMERL LXI B,2500 TIMERL: CALL IN$MODCTLP CALL ANI$MODRCVB CALL CPI$MODRCVR JZ GETBYTE DCX B MOV A,B ORA C JNZ TIMERL RET GETBYTE: CALL IN$MODDATP INR D RET NUMRECS: MVI M,EOFCHAR INX H LXI D,127 DAD D NUMREC1: LXI D,-(BOTTRAM) DAD D MOV A,L ;DIVIDE HL BY 128.. ORA A RAL ;..TO GET THE.. MOV L,H ;..NUMBER OF SECTORS MVI H,0 PUSH PSW DAD H POP PSW MVI A,0 ADC L MOV L,A ;RETURNS WITH NUMBER OF.. RET ;..128 BYTE RECORDS IN HL. WRTDSK: LXI D,BOTTRAM NEXTWRT: MVI C,STDMA CALL BDOSRT PUSH D LXI D,FCB3 MVI C,WRITE CALL BDOSRT POP D XCHG PUSH D LXI D,128 DAD D POP D XCHG DCX H MOV A,H ORA L JNZ NEXTWRT RET CLOSE3: LXI D,FCB3 MVI C,CLOSE CALL BDOS RET BDOSRT: PUSH B ! PUSH D ! PUSH H ! PUSH PSW CALL BDOS POP PSW ! POP H ! POP D ! POP B RET MOVE2: LXI H,FCB3 CALL INITFCBS LXI H,FCB LXI D,FCB3 MVI B,12 CALL MOVE RET ;FILE TRANSFER ROUTINE - CALLED WITH ;CONTROL-T FROM TERMINAL ROUTINE. ;TRANSFER MAY BE CANCELLED WHILE SENDING BY USING CONTROL-X. TRANSFER: PUSH H ! PUSH D ! PUSH B ! PUSH PSW LXI H,FCB4 CALL INITFCBS ;INITIALIZES FCBS POINTED.. LXI H,FCB+16 ;..TO BY HL REG. CALL INITFCBS GET: CALL GETNAME LDA CMDBUF+2 ;WAS FILE ENTERED CPI 20H JZ TRANSL2 CALL MOVE4 CALL OPEN4 CPI 0FFH ;RETURN WITH 0FFH MEANS JNZ CONTIN ;FILE DOES NOT EXIST TRANSL1: CALL ILPRT DB CR,LF,'++File does not exist++',CR,LF,0 TRANSL2: CALL ILPRT DB 'Type "R" to return to modem',CR,LF DB 'Type "A" to re-enter name: ',BELL,0 CALL KEYIN CALL UCASE CALL TYPE ;ECHO RESPONSE CALL CRLF CPI 'A' JZ GET CPI 'R' JZ RETURN JMP TRANSL2 CONTIN: LXI D,80H MVI C,STDMA CALL BDOS READMR: CALL READ80 CPI 1 ;END OF FILE JZ RETURNS CPI 2 ;BAD READ JZ RETURNU CALL SEND80C CPI EOFCHAR ;END OF FILE - OMIT IF OBJECT.. JZ RETURNS ;..CODE IS TO BE SENT. CPI CAN ;CANCELLATION? JZ TRANCAN JMP READMR RETURNS: CALL ILPRT DB CR,LF,'++File transfer completed++',CR,LF,BELL,0 JMP RETURN RETURNU: CALL ILPRT DB CR,LF,'++File transfer unsuccessful++',CR,LF,BELL,0 JMP RETURN TRANCAN: CALL ILPRT DB CR,LF,CR,LF,'++ Transfer cancelled ++',CR,LF,BELL,0 RETURN: POP PSW ! POP B ! POP D ! POP H RET INITFCBS: ;ENTRY AT +2 WILL LEAVE.. MVI M,0 ;..DRIVE NO. INTACT. INX H ;WILL INITIALIZE AN FCB.. MVI B,11 ;..POINTED TO BY HL-REG. FILLS 1ST POS LOOP10: MVI M,' ' ;..WITH 0, NEXT 11 WITH.. INX H ;..WITH BLANKS, AND LAST.. DCR B ;..21 WITH NULLS. JNZ LOOP10 MVI B,21 LOOP11: MVI M,0 INX H DCR B JNZ LOOP11 RET GETNAME: CALL ILPRT DB CR,LF,'Enter file name to be transferred - C/R TO QUIT: ',0 LXI D,CMDBUF CALL INBUFF CALL CRLF RET MOVE4: LXI D,CMDBUF LXI H,FCB4 CALL CPMLINE RET OPEN4: LXI D,FCB4 MVI C,OPEN CALL BDOS RET READ80: LXI D,FCB4 MVI C,READ CALL BDOS RET SEND80C: MVI B,80H LXI H,80H SENDCH1: MOV A,M CALL MODOUT CPI EOFCHAR RZ CALL STAT ;TEST TO SEE IF ORA A ;CANCELLATION REQUESTED JZ SKIP12 CALL KEYIN CPI CAN RZ SKIP12: INX H DCR B JNZ SENDCH1 RET MODOUT: PUSH PSW MODOUTL: CALL IN$MODCTLP CALL ANI$MODSNDB CALL CPI$MODSNDR JNZ MODOUTL POP PSW CALL OUT$MODDATP CALL TYPE RET FCB4: DS 33 ;TERMINAL ECHO MODE TRMECHO: CALL IN$MODCTLP CALL ANI$MODRCVB CALL CPI$MODRCVR JZ LINECHR CALL STAT JZ TRMECHO CALL KEYIN CPI EXITCHR JZ MENU MOV B,A LDA PMMIBYTE ORA A MOV A,B JZ S3 CPI CHGBAUD ;SAME ROUTINE AS IN TERMINAL MODE PUSH PSW CZ NEWBAUD POP PSW CPI CHGBAUD JZ TRMECHO S3: CALL OUT$MODDATP CALL TYPE JMP TRMECHO LINECHR: CALL IN$MODDATP CALL OUT$MODDATP CALL TYPE JMP TRMECHO ; SEND A CP/M FILE SENDFIL: CALL PARITY ;SET PARITY IF REQUESTED LDA BATCHFLG ;CHECK IF MULTIPLE FILE.. ORA A ;..MODE IS SET. JNZ SENDC1 MVI A,TRUE ;INDICATE BATCH SEND STA SENDFLG LDA FSTFLG ;IF FIRST TIME THRU.. ORA A ;..SCAN THE COMMAND LINE.. CNZ TNMBUF ;..FOR MULTIPLE NAMES. CALL SENDFN ;SENDS FILE NAME TO RECEIVER JNC SENDC2 ;CARRY SET MEANS NO MORE FILES. MVI A,'B' ;STOP BATCH.. STA BATCHFLG ;..MODE OPTION. MVI A,EOT ;FINAL XFER END CALL SEND JMP DONE SENDC1: LDA FCB+1 CPI ' ' JZ BLKFILE SENDC2: CALL CNREC ;GET NUMBER OF RECORDS CALL OPENFIL MVI E,80 CALL WAITNAK SENDLP: CALL RDSECT JC SENDEOF CALL INCRSNO XRA A STA ERRCT SENDRPT: CALL SENDHDR CALL SENDSEC LDA CRCFLG ORA A CZ SENDCRC CNZ SENDCKS CALL GETACK JC SENDRPT JMP SENDLP SENDEOF: MVI A,EOT CALL SEND CALL GETACK JC SENDEOF JMP DONE ; RECEIVE A FILE RCVFIL: xra a ;@7.41 - default to CRC mode sta CRCFLG ;@7.41 CALL PARITY ;SET PARITY IF REQUESTED LDA BATCHFLG ;CHECK IF MULT.. ORA A ;..FILE MODE. JNZ RCVC1 MVI A,FALSE ;FLAG WHERE TO RETURN.. STA SENDFLG ;..FOR NEXT FILE TRANS. CALL GETFN ;GET THE FILE NAME. JNC RCVC2 ;CARRY SET MEANS NO MORE FILES. MVI A,'B' ;STOP BATCH.. STA BATCHFLG ;..MODE OPTION. JMP DONE RCVC1: LDA FCB+1 ;MAKE SURE FILE IS NAMED CPI ' ' JZ BLKFILE JMP RCVC3 RCVC2: CALL CKCPM2 CALL CKBAKUP RCVC3: CALL ERASFIL CALL MAKEFIL lda batchflg;@75.FIX................. ora a ;DON'T PRINT MSSG IF.. jnz rcvc4 ;..IN MULTI AND QUIET. lda qflg ora a jz rcvfst rcvc4: CALL ILPRT ;@75.FIX................. DB 'File open, ready to receive',CR,LF,0 RCVFST: LDA CRCFLG ORA A MVI A,NAK JNZ RCVFIL2 MVI A,CRC ; RCVFIL2: CALL SEND lda CRCFLG ;@7.41............................... ora a jnz RCVNAKM ;if in CRC mode call ILPRT ;then say so DB 'CRC in effect',cr,lf,0 jmp RCVLP RCVNAKM: call ILPRT ;else say checksum mode DB 'Checksum in effect',cr,lf,0 ;@7.41............................... RCVLP: CALL RCVSECT JC RCVEOT CALL WRSECT CALL INCRSNO CALL SENDACK JMP RCVLP RCVEOT: CALL WRBLOCK CALL SENDACK CALL CLOSFIL JMP DONE ;SUBROUTINES SENDFN: LDA QFLG ORA A JZ SWNAK CALL ILPRT DB 'Awaiting name NAK',CR,LF,0 SWNAK: MVI E,80 CALL WAITNLP MVI A,ACK ;GOT NAK, SEND ACK CALL SEND LXI H,FILECT DCR M JM NOMRNM LHLD NBSAVE ;GET FILE NAME.. LXI D,FCB ;..IN FCB MVI B,12 CALL MOVE SHLD NBSAVE CALL SENDNM ;SEND IT ORA A ;CLEAR CARRY RET NOMRNM: MVI A,EOT CALL SEND STC RET SENDNM: PUSH H SENDNM1: MVI D,11 ;COUNT CHARS IN NAME MVI C,0 ;INIT CHECKSUM LXI H,FCB+1 ;ADDRESS NAME NAMLPS: MOV A,M ;SEND NAME ANI 7FH ;STRIP HIGH ORDER BIT SO CP/M 2.. CALL SEND ;..WON'T SEND R/O FILE DESIGNATION. LDA QFLG ;SHOW NAME IF.. ORA A ;..QFLG NOT SET. MOV A,M CNZ TYPE ACKLP: PUSH B ;SAVE CKSUM MVI B,1 ;WAIT FOR RECEIVER.. CALL RECV ;..TO ACKNOWLEDGE.. POP B ;..GETTING LETTER. JC SCKSER CPI ACK JNZ ACKLP INX H ;NEXT CHAR DCR D JNZ NAMLPS MVI A,EOFCHAR ;TELL RECEIVER END OF NAME CALL SEND LDA QFLG ORA A CNZ CRLF MOV D,C ;SAVE CHECKSUM MVI B,1 CALL RECV ;GET CHECKSUM.. CMP D ;..FROM RECEIVER. JZ NAMEOK SCKSER: MVI A,BDNMCH ;BAD NAME-TELL RECEIVER CALL SEND LDA QFLG ORA A JZ SKCSER1 CALL ILPRT DB 'Checksum error',CR,LF,0 SKCSER1: MVI E,80 ;DO HANDSHAKING OVER CALL WAITNLP ;DON'T PRINT "AWAITING NAK" MSG MVI A,ACK CALL SEND JMP SENDNM1 NAMEOK: MVI A,OKNMCH ;GOOD NAME-TELL RECEIVER CALL SEND POP H RET GETFN: LXI H,FCB CALL INITFCBS+2 ;DOES NOT INITIALIZE DRIVE LDA QFLG ORA A JZ GNAMELP CALL ILPRT DB 'Awaiting file name',CR,LF,0 GNAMELP: CALL HSNAK JC GNAMELP CALL GETNM ;GET THE NAME CPI EOT ;IF EOT, THEN NO MORE FILES JZ NOMRNMG ORA A ;CLEAR CARRY RET NOMRNMG: STC RET GETNM: PUSH H GETNM1: MVI C,0 ;INIT CHECKSUM LXI H,FCB+1 NAMELPG: MVI B,5 CALL RECV ;GET CHAR JNC GETNM3 LDA QFLG ORA A JZ GETNM2 CALL ILPRT DB 'Time out receiving filename',CR,LF,0 GETNM2: JMP GCKSER GETNM3: CPI EOT ;IF EOT, THEN NO MORE FILES JZ GNRET CPI EOFCHAR ;GOT END OF NAME JZ ENDNAME MOV M,A ;PUT NAME IN FCB LDA QFLG ;TYPE IT IF NO QFLG ORA A MOV A,M CNZ TYPE PUSH B ;SAVE CKSUM MVI A,ACK ;ACK GETTING LETTER CALL SEND POP B INX H ;GET NEXT CHAR MOV A,L ;DON'T LET NOISE... CPI 7FH ;..CAUSE OVERFLOW.. JZ GCKSER ;..INTO PROGRAM AREA. JMP NAMELPG ENDNAME: LDA QFLG ORA A CNZ CRLF MOV A,C ;SEND CHECKSUM CALL SEND MVI B,1 CALL RECV ;CHECKSUM GOOD? CPI OKNMCH ;YES IF OKNMCH SENT.. JZ GNRET ;..ELSE DO OVER. GCKSER: LXI H,FCB ;CLEAR FCB (EXCEPT DRIVE).. CALL INITFCBS+2 ;..SINCE IT MIGHT BE DAMAGED.. LDA QFLG ;..BY TOO MANY CHARS. ORA A JZ GCKSER1 CALL ILPRT DB 'Checksum error',CR,LF,0 GCKSER1: CALL HSNAK ;DO HANDSHAKING OVER JC GCKSER1 JMP GETNM1 GNRET: POP H RET HSNAK: MVI A,NAK ;SEND NAK UNTIL.. CALL SEND ;..RECEIVING ACK. CALL CKABORT ;DON'T GET HUNG UP HERE MVI B,2 ;WAIT 2 SECONDS.. CALL RECV ;..IN RECEIVE. CPI ACK ;IF ACK,RETURN WITH.. RZ ;..CARRY CLEAR. STC RET TNMBUF: MVI A,FALSE ;CALL FROM SENDFIL ONLY ONCE. STA FSTFLG STA FILECT CALL SCAN LXI H,NAMEBUF SHLD NBSAVE ;SAVE ADDR OF 1ST NAME TNLP1: CALL TRTOBUF LXI H,FCB LXI D,FCBBUF CALL CPMLINE ;PARSE NAME TO CP/M FORMAT TNLP2: CALL MFNAME ;SEARCH FOR NAMES (* FORMAT) JC NEXTNM LDA FCB+10 ;IF CP/M 2 $SYS FILE.. ANI 80H ;..DON'T SEND JNZ TNLP2 LHLD NBSAVE ;GET NAME LXI D,FCB ;MOVE IT TO FCB XCHG MVI B,12 CALL MOVE XCHG SHLD NBSAVE ;ADDR OF NEXT NAME LXI H,FILECT ;COUNT FILES FOUND INR M JMP TNLP2 ; NEXTNM: LXI H,NAMECT ;COUNT NAMES FOUND DCR M JNZ TNLP1 LXI H,NAMEBUF ;SAVE START OF BUFFER SHLD NBSAVE LDA FILECT CPI 65 ;NO MORE THAN 64 TRANSFERS RC MVI A,64 ;ONLY X'FER FIRST 64 STA FILECT RET ;SCANS CMDBUF COUNTING NAMES AND PUTTING DELIMITER (SPACE) ;AFTER LAST NAME SCAN: PUSH H LXI H,NAMECT MVI M,0 LXI H,CMDBUF+1 ;FIND END OF CMD LINE.. MOV C,M ;..AND PUT SPACE THERE. MVI B,0 LXI H,CMDBUF+2 DAD B MVI M,20H LXI H,CMDBUF+1 MOV B,M INR B INR B SCANLP1: INX H DCR B JZ DNSCAN MOV A,M CPI 20H JNZ SCANLP1 SCANLP2: INX H ;EAT EXTRA SPACES DCR B JZ DNSCAN MOV A,M CPI 20H JZ SCANLP2 SHLD BGNMS ;SAVE START OF NAMES IN CMDBUF INR B DCX H SCANLP3: INX H DCR B JZ DNSCAN MOV A,M CPI 20H JNZ SCANLP3 LDA NAMECT ;COUNTS NAMES INR A STA NAMECT SCANLP4: INX H ;EAT SPACES DCR B JZ DNSCAN MOV A,M CPI 20H JZ SCANLP4 JMP SCANLP3 ; DNSCAN: MVI M,20H ;SPACE AFTER LAST CHAR POP H RET ;PLACES NEXT NAME IN BUFFER SO CPMLINE MAY PARSE IT TRTOBUF: LHLD BGNMS MVI B,0 LXI D,FCBBUF+2 TBLP: MOV A,M CPI 20H JZ TRBFEND STAX D INX H INX D INR B ;COUNT CHARS IN NAME JMP TBLP ; TRBFEND: INX H MOV A,M ;EAT EXTRA SPACES CPI 20H JZ TRBFEND SHLD BGNMS LXI H,FCBBUF+1 ;PUT # CHARS BEFORE NAME MOV M,B RET ;IN CP/M V.2, IF FILE IS R/O OR SYS, IT IS CHANGED TO 'BAK'. CKCPM2: MVI C,12 CALL BDOS ORA A ;RETURN 0 MEANS CP/M 1 RZ MVI C,STDMA LXI D,80H CALL BDOS MVI C,SRCHF ;SEARCH FOR FILE LXI D,FCB CALL BDOS CPI 0FFH RZ ADD A ! ADD A ;MULT A-REG BY.. ADD A ! ADD A ;..32 TO FIND.. ADD A ;..NAME IN DMA. LXI H,80H ADD L MOV L,A ;HL POINTS TO DIR NAME LXI D,9 DAD D ;POINT TO R/O ATTRIB BYTE MOV A,M ANI 80H ;TEST MSB JNZ MKCHG ;IF SET, MAKE CHANGE INX H ;CHECK SYSTEM ATTRIB BYTE MOV A,M ANI 80H RZ ;NOT $SYS OR $R/O DCX H MKCHG: LXI D,-8 DAD D ;POINT HL TO FILENAME + 1 LXI D,FCB+1 ;MOVE DIR NAME TO FCB.. MVI B,11 ;..WITHOUT CHANGING DRIVE. CALL MOVE LXI H,FCB+9 ;R/O ATTRIB MOV A,M ANI 7FH ;STRIP R/O ATTRIB MOV M,A INX H ;SYS ATTRIB MOV A,M ANI 7FH MOV M,A LXI D,FCB MVI C,30 ;SET NEW ATTRIBS IN DIR CALL BDOS ;MAY BE CALLED BY CKBAKUP BELOW. ITS RETURN DONE HERE PLANCHG: LXI H,FCB ;CHANGE NAME TO TYPE "BAK" LXI D,6CH MVI B,9 ;MOVE DRIVE AND NAME (NOT TYPE) CALL MOVE LXI H,75H ;START OF TYPE IN FCB2 MVI M,'B' INX H MVI M,'A' INX H MVI M,'K' LXI D,6CH MVI C,ERASE ;ERASE ANY PREV BACKUPS CALL BDOS LXI H,6CH ;FCB2 DR FIELD SHOULD.. MVI M,0 ;..0 FOR RENAME. LXI D,FCB MVI C,23 ;RENAME CALL BDOS RET CKBAKUP: LDA BAKUPBYTE ORA A RZ MVI C,SRCHF LXI D,FCB CALL BDOS INR A RZ ;FILE NOT FOUND JMP PLANCHG ;IN "CKCPM2" - RET DONE THERE ;MULTI-FILE ACCESS SUBROUTINE FROM CP/M USER'S GROUP ;FIXED BY MARK ZEIGER 8/17/80 ;CARRY IS SET IF NO MORE NAMES CAN BE FOUND MFNAME: MFACCESS ;A MACRO IN MACROS.LIB RCVSECT: XRA A STA ERRCT RCVRPT: XRA A ;ZERO ACCUM STA ERRCDE ;CLEAR RECEIVE ERROR CODE LDA QFLG ORA A JZ RCVSQ CALL ILPRT DB CR,'Awaiting # ',0 PUSH H ;SAVE IT LHLD SECTNO ;GET SECTOR NUMBER INX H ;BUMP IT CALL DECOUT ;PRINT SECTOR NUMBER IN DECIMAL CALL ILPRT DB ' (', 0 CALL DHXOUT ;16 BIT HEX CONVERSION & OUTPUT CALL ILPRT DB 'H)',0 MOV A,L ;ONLY LOW BYTE USED BY PROGRAM POP H ;RESTORE IT ; ;----> RCVSQ: ; If CRC is in effect, there is only a 3 second wait ; for the first SOH. If the SOH is not received within ; 3 seconds, then a NAK is sent which tells the sender ; to use checksum checking instead of CRC. This allows ; automatic compatability with versions of XMODEM that ; do not implement Cyclic Redundancy Checking(CRC). ; RCVSQ: LDA FIRSTME ;first SOH... ORA A ;...been received? JZ RCVSQ2 ;yes, go get next SOH XRA A ;turn off... STA FIRSTME ;...first soh recvd switch LDA CRCFLG ;CRC in... ORA A ;...effect? JNZ RCVSQ2 ;no, do long wait for first SOH MVI B,3 ;wait for upto 3 seconds CALL RECV ;get a character from modem JNC RCVSQ3 ;got a char, go see if SOH CALL ILPRT DB CR,LF,'++Switching to CHECKSUM MODE++',CR,LF,0 MVI A,'C' ;turn off... STA CRCFLG ;...CRC mode. MVI A,NAK ;send NAK to tell sender checksum CALL SEND ;...is in effect & to start sending. JMP RCVSECT ;go start receiving sector ; RCVSQ2: MVI B,7 ;10 IN ORIG PROG CALL RECV JC RCVSTOT ; RCVSQ3: CALL RCVERR ;CHECK FOR ERRORS JC RCVDERR ;JUMP IF THERE WAS AN ERROR CPI SOH JZ RCVSOH ORA A JZ RCVSQ CPI EOT STC RZ MOV B,A LDA VSEEFLG ORA A JZ RCVSEH LDA QFLG ORA A JZ RCVSERR RCVSEH: MOV A,B CALL CRLF CALL HEXO CALL ILPRT DB 'H recv''d, not SOH',CR,LF,0 RCVSERR: MVI B,1 CALL RECV JNC RCVSERR MVI A,NAK CALL SEND LDA ERRCT INR A STA ERRCT CPI ERRLIM JC RCVRPT LDA VSEEFLG ORA A JZ RCVCKQ LDA QFLG ORA A JZ RCVSABT RCVCKQ: CALL CKQUIT JZ RCVSECT RCVSABT: CALL CLOSFIL CALL ERXIT DB CR,LF,'++Unable to receive block - Aborting++',CR,LF,'$' RCVSTOT: LDA VSEEFLG ORA A JZ RCVSPT LDA QFLG ORA A JZ RCVSERR RCVSPT: CALL ILPRT DB CR,LF,'++ Timeout ++ ',0 RCVPRN: LDA ERRCT CALL HEXO CALL CRLF JMP RCVSERR ;----> RCVERR: ; Checks for framing, overrun, and parity errors. Parity errors ; cannot be detected unless the parity option has been selected. ; 1.Error code (ERRCDE) was set in RECV routine. ; 2.ERRCDE=0 for no errors, ERRCDE<>0 for errors. ; 3.If there is an error, routine returns with carry flag set. RCVERR: PUSH PSW ;SAVE CHAR TRANSMITTED LDA ERRCDE ;GET RECEIVE ERROR CODE ANA A ;IS IT ZERO? JZ RCVERR2 ;YES, NO RECEIVE ERROR POP PSW ;RESTORE CHAR TRANSMITTED STC ;SET CARRY ON TO INDICATE AN ERROR RET RCVERR2: POP PSW ;RESTORE CHAR TRANSMITTED RET ;----> RCVDERR: Checks for a receive error and displays appropriate error ; message. Then goes to RCVSERR to purge the line and send a NAK. RCVDERR: LDA VSEEFLG ;VIEWING ORA A ;...MODE? JZ RCVDERRP ;YES,..PRT MSG LDA QFLG ;QUIET... ORA A ;...MODE? JZ RCVSERR ;YES, NO MSG RCVDERRP: CALL ILPRT DB CR,LF,0 LDA ERRCDE ;GET RECEIVE ERR CODE ANI FRMER ;WAS THERE A FRAMING ERROR? JZ RCVDERR2 ;NO, GO CHECK FOR OVERRUN CALL ILPRT DB '++Framing error++ ',0 CALL RCVDERR5 ;PRINT # OF ERROR RCVDERR2: LDA ERRCDE ;GET RECEIVE ERR CODE ANI ORUNER ;WAS THERE AN OVERRUN JZ RCVDERR3 ;NO, GO CHECK FOR PARITY ERROR CALL ILPRT DB '++Overrun error++ ',0 CALL RCVDERR5 RCVDERR3: LDA ERRCDE ;GET RECEIVE ERR CODE ANI PARER ;WAS THERE A PARITY ERROR? JZ RCVDERR4 ;NO, GO PURGE LINE CALL ILPRT DB '++Parity error++ ',0 CALL RCVDERR5 RCVDERR4: JMP RCVSERR ;GO PURGE LINE, SEND NAK ;Display the number of the error, do a carriage return and line feed. RCVDERR5: LDA ERRCT ;GET ERROR NUMBER CALL HEXO ;DISPLAY IT CALL CRLF ;DO CR, LF RET RCVSOH: MVI B,1 CALL RECV JC RCVSTOT CALL RCVERR ;CHECK FOR RECEIVE ERROR JC RCVDERR MOV D,A MVI B,1 CALL RECV JC RCVSTOT CALL RCVERR ;CHECK FOR RECEIVE ERROR JC RCVDERR CMA CMP D JZ RCVDATA LDA VSEEFLG ORA A JZ RCVBSE LDA QFLG ORA A JZ RCVSERR RCVBSE: CALL ILPRT DB CR,LF,'++ Bad sector # in Hdr',CR,LF,0 JMP RCVSERR RCVDATA: MOV A,D STA RCVSNO MVI A,1 STA DATAFLG MVI C,0 CALL CLRCRC ;clear crc counter LXI H,80H RCVCHR: MVI B,1 CALL RECV JC RCVSTOT CALL RCVERR ;CHECK FOR RECEIVE ERROR JC RCVDERR MOV M,A INR L JNZ RCVCHR LDA CRCFLG ORA A JZ RCVCRC MOV D,C XRA A STA DATAFLG MVI B,1 CALL RECV JC RCVSTOT CALL RCVERR ;CHECK FOR RECEIVE ERROR JC RCVDERR CMP D JNZ RCVCERR CHKSNUM: LDA RCVSNO MOV B,A LDA SECTNO CMP B JZ RECVACK INR A CMP B JNZ ABORT RET ; RCVCRC: MVI E,2 ;nr of crc bytes ; RCVCRC2: MVI B,1 CALL RECV JC RCVSTOT CALL RCVERR JC RCVDERR DCR E JNZ RCVCRC2 CALL CHKCRC ORA A JZ CHKSNUM LDA VSEEFLG ORA A JZ RCVCRER LDA QFLG ORA A JZ RCVSERR ; RCVCRER: CALL ILPRT DB CR,LF,'++CRC error++',0 JMP RCVPRN RCVCERR: LDA VSEEFLG ORA A JZ RCVCPR LDA QFLG ORA A JZ RCVSERR RCVCPR: CALL ILPRT DB '++Cksum error++ ',0 JMP RCVPRN RECVACK: CALL SENDACK JMP RCVSECT SENDACK: MVI A,ACK CALL SEND RET SENDHDR: LDA QFLG ORA A JZ SENDHNM CALL ILPRT DB CR,'Send # ',0 PUSH H LHLD SECTNO ;GET SECTOR NUMBER CALL DECOUT ;PRINT IT IN DECIMAL CALL ILPRT DB ' (',0 CALL DHXOUT ;16 BIT HEX CONVERSION & OUTPUT CALL ILPRT DB 'H)',0 POP H SENDHNM: MVI A,SOH CALL SEND LDA SECTNO CALL SEND LDA SECTNO CMA CALL SEND RET SENDSEC: MVI A,1 STA DATAFLG MVI C,0 CALL CLRCRC LXI H,80H SENDC: MOV A,M CALL SEND INR L JNZ SENDC XRA A STA DATAFLG RET SENDCKS: MOV A,C CALL SEND RET SENDCRC: CALL FINCRC MOV A,D CALL SEND MOV A,E CALL SEND XRA A RET GETACK: MVI B,7 ;10 IN ORIG PROG CALL RECVDG JC GETATOT CPI ACK RZ MOV B,A LDA QFLG ORA A JZ ACKERR MOV A,B CALL CRLF CALL HEXO CALL ILPRT DB 'H Recv''d, not ACK',CR,LF,0 ACKERR: LDA ERRCT INR A STA ERRCT CPI ERRLIM RC LDA VSEEFLG ORA A JZ GACKV LDA QFLG ORA A JZ CSABORT GACKV: CALL CKQUIT STC RZ CSABORT: CALL ERXIT DB CR,LF,'Can''t send sector -- Aborting',CR,LF,'$' ; GETATOT: LDA QFLG ORA A JZ ACKERR CALL ILPRT DB CR,LF,'Timeout on ACK',CR,LF,0 JMP ACKERR CKABORT: LDA VSEEFLG ORA A JZ CKABGO LDA QFLG ORA A RZ CKABGO: CALL STAT RZ CALL KEYIN CPI CAN RNZ ABORT: LXI SP,STACK ABORTL: MVI B,1 CALL RECV JNC ABORTL MVI A,CAN CALL SEND ABORTW: MVI B,1 CALL RECV JNC ABORTW MVI A,' ' CALL SEND CALL ILPRT DB CR,LF,'Routine cancelled',CR,LF,BELL,0 MVI A,'B' ;TURN MULTI-FILE MODE.. STA BATCHFLG ;..OFF SO ROUTINE ENDS. JMP DONETCE INCRSNO: PUSH H LHLD SECTNO ;GET SECTOR NUMBER INX H ;BUMP IT SHLD SECTNO ;STORE IT MOV A,L POP H RET ERASFIL: LDA BATCHFLG ;DON'T ASK FOR ERASE.. ORA A ;..IN MULTI-FILE MODE,.. JZ NOASK ;..JUST DO IT. LXI D,FCB MVI C,SRCHF CALL BDOS INR A RZ CALL ILPRT DB 'File exists -- Type ''Y'' to erase: ',BELL,0 CALL KEYIN PUSH PSW CALL TYPE POP PSW CALL UCASE CPI 'Y' JNZ MENU CALL CRLF ; NOASK: LXI D,FCB MVI C,ERASE CALL BDOS RET BLKFILE: CALL ILPRT ;ROUTINE IF NO FILE IS NAMED FOR "SEND" OR "RECEIVE" DB CR,LF,'No file specified',CR,LF,BELL,0 JMP MENU MAKEFIL: LXI D,FCB MVI C,MAKE CALL BDOS INR A RNZ CALL ERXIT DB 'Error - Can''t make file',CR,LF DB 'Directory must be full',CR,LF,'$' IF CPM2X CNREC: MVI C,FILSIZ ;COMPUTE FILE SIZE FUNCTION IN CP/M 2.x LXI D,FCB ;POINT TO FILE CONTROL BLOCK CALL BDOS LHLD FCB+33 ;GET RECORD COUNT SHLD RCNT ;STORE IT LXI H,0 ;ZERO HL SHLD FCB+33 ;RESET RANDOM RECORD IN FCB RET ENDIF IF NOT CPM2X CNREC: MVI A,'?' ;MATCH ALL EXTENTS STA FCBEXT MVI A,0FFH STA MAXEXT ;INIT MAX EXT NO. MVI C,SRCHF ;GET 'SEARCH FIRST' FNC LXI D,FCB CALL BDOS ;READ FIRST INR A ;WERE THERE ANY? JNZ SOME ;GOT SOME CALL ERXIT DB '++File not found++$' ;READ MORE DIRECTORY ENTRIES MOREDIR: MVI C,SRCHN ;SEARCH NEXT LXI D,FCB CALL BDOS ;READ DIR ENTRY INR A ;CHECK FOR END (0FFH) JNZ SOME ;NOT END OF DIR...PROCESS EXTENT LDA MAXEXT ;HIT END...GET HIGHEST EXTENT NO. SEEN MOV L,A ;WHICH GIVES EXTENT COUNT -1 MVI H,0 MOV D,H LDA RCNT ;GET RECORD COUNT OF MAX EXTENT SEEN MOV E,A ;SAVE IT IN DE DAD H DAD H ;MULTIPLY # OF EXTENTS -1 DAD H ; TIMES 128 DAD H DAD H DAD H DAD H DAD D ;ADD IN SIZE OF LAST EXTENT SHLD RCNT ;SAVE TOTAL RECORD COUNT RET ;AND EXIT ;POINT TO DIRECTORY ENTRY SOME: DCR A ;UNDO PREV 'INR A' ANI 3 ;MAKE MODULUS 4 ADD A ;MULTIPLY... ADD A ;..BY 32 BECAUSE ADD A ;..EACH DIRECTORY ADD A ;..ENTRY IS 32 ADD A ;..BYTES LONG LXI H,80H ;POINT TO BUFFER ADD L ;POINT TO ENTRY ADI 15 ;OFFSET TO RECORD COUNT MOV L,A ;HL NOW POINTS TO REC COUNT MOV B,M ;GET RECORD COUNT DCX H DCX H ;BACK DOWN TO EXTENT NUMBER DCX H LDA MAXEXT ;COMPARE WITH CURRENT MAX. ORA A ;IF NO MAX YET JM BIGGER ;THEN SAVE RECORD COUNT ANYWAY CMP M JNC MOREDIR BIGGER: MOV A,B ;SAVE NEW RECORD COUNT STA RCNT MOV A,M ;SAVE NEW MAX. EXTENT NO. STA MAXEXT JMP MOREDIR ;GO FIND MORE EXTENTS ENDIF OPENFIL: LXI D,FCB MVI C,OPEN CALL BDOS INR A JNZ OPENOK CALL ERXIT DB 'Can''t open file$' OPENOK: LDA BATCHFLG ORA A JNZ OPENOK1 LDA QFLG ORA A RZ OPENOK1: CALL ILPRT DB 'File open, size: ',0 LHLD RCNT ;GET RECORD COUNT CALL DECOUT ;PRINT NUMBER OF SECTORS IN DECIMAL CALL ILPRT ;PRINT DB ' (',0 CALL DHXOUT CALL ILPRT DB 'H) sectors',CR,LF,0 RET CLOSFIL: LXI D,FCB MVI C,CLOSE CALL BDOS INR A RNZ CALL ERXIT DB 'Can''t close file$' RDSECT: LDA SECINBF DCR A STA SECINBF JM RDBLOCK LHLD SECPTR LXI D,80H CALL MOVE128 SHLD SECPTR RET RDBLOCK: LDA EOFLG CPI 1 STC RZ MVI C,0 LXI D,DBUF RDSECLP: PUSH B PUSH D MVI C,STDMA CALL BDOS LXI D,FCB MVI C,READ CALL BDOS POP D POP B ORA A JZ RDSECOK DCR A JZ REOF CALL ERXIT DB '++ File read error ++$' RDSECOK: LXI H,80H DAD D XCHG INR C MOV A,C CPI DBUFSIZ*8 ;BUFFER SIZE IN 128 BYTE SECTORS JZ RDBFULL JMP RDSECLP REOF: MVI A,1 STA EOFLG MOV A,C RDBFULL: STA SECINBF LXI H,DBUF SHLD SECPTR LXI D,80H MVI C,STDMA CALL BDOS JMP RDSECT ; WRSECT: LHLD SECPTR XCHG LXI H,80H CALL MOVE128 XCHG SHLD SECPTR LDA SECINBF INR A STA SECINBF CPI DBUFSIZ*8 ;BUFFER SIZE IN 128 BYTE SECTORS RNZ ; WRBLOCK: LDA SECINBF ORA A RZ MOV C,A LXI D,DBUF DKWRLP: PUSH H PUSH D PUSH B MVI C,STDMA CALL BDOS LXI D,FCB MVI C,WRITE CALL BDOS POP B POP D POP H ORA A JNZ WRERR LXI H,80H DAD D XCHG DCR C JNZ DKWRLP XRA A STA SECINBF LXI H,DBUF SHLD SECPTR RET WRERR: MVI C,CAN CALL SEND CALL ERXIT DB 'Error writing file',CR,LF,'$' ;----> 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 $ CALL IN$MODDATP CALL IN$MODDATP RECV: PUSH D LDA FASTCLK ORA A JZ MSEC MOV A,B ADD A MOV B,A MSEC: LXI D,15000 ;60% OF ORIG 50000 CALL CKABORT MWTI: CALL IN$MODCTLP CALL ANI$MODRCVB CALL CPI$MODRCVR JZ MCHAR DCR E JNZ MWTI DCR D JNZ MWTI DCR B JNZ MSEC POP D STC RET MCHAR: LDA PMMIBYTE ;IS THE MODEM A PMMI? ORA A ;SET FLAGS JZ MCHAR1 ;YES, JUMP CALL IN$MODCTLP ;GET ERROR-STATUS BYTE ANI ERRCDMSK ;MASK OUT ALL EXCEPT ERROR BITS (3-5) STA ERRCDE ;SAVE THE ERROR CODE MCHAR1: CALL IN$MODDATP POP D PUSH PSW CALL UPDCRC ;calc crc ADD C MOV C,A LDA RSEEFLG ORA A JZ MONIN LDA VSEEFLG ORA A JNZ NOMONIN LDA DATAFLG ORA A JZ NOMONIN MONIN: POP PSW PUSH PSW CALL SHOW NOMONIN: POP PSW ORA A RET SEND: PUSH PSW LDA SSEEFLG ORA A JZ MONOUT LDA VSEEFLG ORA A JNZ NOMONOT LDA DATAFLG ORA A JZ NOMONOT MONOUT: POP PSW PUSH PSW CALL SHOW NOMONOT: POP PSW PUSH PSW CALl UPDCRC ;calc crc ADD C MOV C,A SENDW: CALL IN$MODCTLP CALL ANI$MODSNDB CALL CPI$MODSNDR JNZ SENDW POP PSW CALL OUT$MODDATP RET WAITNAK: LDA VSEEFLG ORA A JZ WAITNPR LDA QFLG ORA A JZ WAITNLP WAITNPR: CALL ILPRT DB 'Awaiting initial NAK',CR,LF,0 WAITNLP: CALL CKABORT MVI B,1 CALL RECV CPI NAK RZ CPI CRC ;crc request? JZ WAITCRC ;yes, go set crc flag DCR E JZ ABORT JMP WAITNLP ; WAITCRC: CALL ILPRT DB 'CRC request received',CR,LF,0 XRA A STA CRCFLG RET ; ;--->PARITY: Routine to setup PMMI for odd/even parity. PARITY: LDA PMMIBYTE ;IS MODEM A PMMI? ORA A ;SET FLAGS RZ ;NO, RETURN LDA OPARITY ;GET ODD PARITY REQUEST BYTE ORA A ;SET FLAGS JNZ EVENPAR ;IF NOT ODD SEE IF IT IS EVEN LDA UARTCTLB ;GET UART/MODEM CONTROL BYTE ANI ODPARMSK JMP PARITY1 EVENPAR: LDA EPARITY ;GET EVEN PARITY REQUEST BYTE ORA A ;SET FLAGS RNZ ;IF EVEN PARITY NOT SPECIFIED RETURN LDA UARTCTLB ;GET UART/MODEM CONTROL BYTE ANI ODPARMSK ;SET FOR PARITY ORI EVPARMSK ;NOW SET FOR EVEN PARITY PARITY1: JMP OUT$MODCTLP ;SEND TO PMMI - ;WHEN OUT$MODCTLP DOES RET IT ;WILL GO BACK TO CALLING ROUTINE NOPARIT: LDA PMMIBYTE ORA A RZ LDA UARTCTLB ;GET UART/MODEM CONTROL BYTE ORI NOPARMSK ;RESET PARITY BIT ON PMMI JMP OUT$MODCTLP INITADR: LHLD 1 LXI D,3 DAD D SHLD VSTAT+1 DAD D SHLD VKEYIN+1 DAD D SHLD VTYPE+1 LDA PMMIBYTE ORA A JZ JMP$INITMOD ;RETURN DONE FROM THIS ROUTINE.. LDA IN$MODCTLP+1 ;..IF NOT PMMI STA OUT$MODCTLP+1 INR A STA OUT$MODDATP+1 STA IN$MODDATP+1 INR A STA IN$BAUDRP+1 STA OUT$BAUDRP+1 INR A STA OUT$MODCTL2+1 RET PROCOPT: LXI D,FCB+1 LDAX D STA OPTION OPTLP: INX D LDAX D CPI ' ' JZ ENDOPT LXI H,OPTBL MVI B,OPTBE-OPTBL OPTCK: CMP M JNZ OPTNO MVI M,0 JMP OPTLP OPTNO: INX H DCR B JNZ OPTCK JMP BADOPT ENDOPT: LDA CRCFLG ORA A JNZ ENDOPT2 LDA OPTION CPI 'R' JNZ BADOPT ;crc only allowed for recv ; ENDOPT2: LDA VSEEFLG ORA A RNZ STA QFLG RET DONE: LDA BATCHFLG ORA A JNZ DONETCC LDA QFLG ORA A JZ NMSTRNS LXI H,FCB+1 ;PUT FILE NAME IN.. LXI D,FTRNMSG ;..SPACES IN MESSAGE.. MVI B,8 ;..BELOW. CALL MOVE INX D ;PUT FILE TYPE AFTER.. MVI B,3 ;..SKIPPING ONE SPACE.. CALL MOVE ;..BELOW. CALL ILPRT FTRNMSG: DB ' transferred',CR,LF,CR,LF,0 ;13 SPACES NMSTRNS: LDA FCB ;SAVE DRIVE NO. STA DISKNO LXI H,FCB ;BLANK OUT FILE CONTROL BLOCKS CALL INITFCBS LDA DISKNO ;PUT DRIVE NUMBER BACK STA FCB LXI H,RESTSN ;RESTORE SECTORE NUMBERS.. LXI D,SECTNOB ;..FOR NEW FILE TRANSFER. MVI B,SECTNOE-SECTNOB ;ROUTINE ALSO DONE IN MENU. CALL MOVE LDA SENDFLG ;GOES TO EITHER SEND OR.. ORA A ;..RECEIVE FILE, DEPENDING.. JNZ SENDFIL ;..UPON WHICH ROUTINE SET.. JMP RCVFIL ;..THE FLAG IN MULTI-FILE MODE. DONETCC: MVI A,TRUE ;INDICATE NO FILES BEING.. STA FSTFLG ;RESET MULTIFILE TRANS STA NFILFLG ;..USED IN TERMINAL ROUTINE. CMA OUT FRONTPAN STA SAVEFLG ;STOP MEMORY SAVE IN TERM ROUTINE. LDA VSEEFLG ORA A JZ DONETC LDA QFLG ORA A JZ DONETCA DONETC: CALL ILPRT DB CR,LF,'All transfers completed' DB CR,LF,BELL,0 DONETCA: LDA DISCFLG ;see if disconnect when thru ORA A JNZ DONETCE ;no, don't disconnect DONETCB: CALL ILPRT DB CR,LF,'++Press RETURN to disconnect++',BELL,CR,LF,0 MVI C,RDCON CALL BDOS ;wait for response CPI 0DH ;carriage return JNZ DONETCB ;nope CALL ILPRT DB CR,LF,'++Disconnected++',CR,LF,0 CALL DISCONNT ;hang-up the pmmi JMP EXIT ;go to CP/M DONETCE: CALL NOPARIT ;RESET TO NO PARITY mvi a,crc ;@7.41.................... sta CRCFLG ;turn off CRC option mvi a,0FFH sta FIRSTME ;set first-time flag ;@7.41.................... LDA TERMFLG ;SEE IF RETURN TO.. ORA A ;..TERMINAL MODE.. JNZ MENU ;..AFTER X'FER. CALL CRLF JMP TERM INITMOD: SETBAUD: LDA PMMIBYTE ORA A RZ LDA ANSWFLG ;IF ANSWER OR ORIGINATE MODE.. ORA A ;..IS NOT REQUESTED OR NO.. JNZ SKIPB1 ;..BAUDRATE SPECIFIED, THEN.. CALL GETBAUD ;..ROUTINE RETURNS WITH CHANGE.. JMP FIXBAUD ;..OF BAUD. IF OPT REQUESTED,.. SKIPB1: LDA ORIGFLG ;..A BLANK FORCES 300 BAUD.. ORA A ;..ELSE A 0 FROM NEWBAUD.. RNZ ;..FORCES 300 BAUD. CALL GETBAUD FIXBAUD: CALL OUT$BAUDRP CPI 52 MVI A,5FH JC GT300 MVI A,7FH GT300: CALL OUT$MODCTL2 STA MODCTLB ;SAVE MODEM CONTROL BYTE LDA ORIGFLG ORA A MVI A,ORIGMOD JZ OFFHOOK LDA ANSWFLG ORA A MVI A,ANSWMOD RNZ OFFHOOK: LXI H,4000 OFFDLY: DCR L JNZ OFFDLY DCR H JNZ OFFDLY CALL OUT$MODCTLP RET GETBAUD: LDA FCB+9 CPI ' ' MVI A,52 RZ LDA FCB+9 CPI 0 MVI A,52 RZ LXI D,FCB+9 LXI H,0 DECLP: LDAX D INX D CPI ' ' JZ DECLP CPI '0' JC BADRATE CPI '9'+1 JNC BADRATE SUI '0' MOV B,H MOV C,L DAD H DAD H DAD B DAD H ADD L MOV L,A JNZ DIGNC INR H DIGNC: MOV A,E CPI FCB+12 JNZ DECLP MOV A,H CMA MOV D,A MOV A,L CMA MOV E,A INX D LXI H,15625 LXI B,-1 DIVLP: INX B DAD D JC DIVLP MOV A,B ORA A MOV A,C RZ BADRATE: CALL ERXIT DB '++ Invalid baud rate ++$' MOVEFCB: LXI H,FCB+16 LXI D,FCB MVI B,16 CALL MOVE XRA A STA FCBSNO STA FCBEXT RET SHOW: CPI LF JZ CTYPE CPI CR JZ CTYPE CPI 9 JZ CTYPE CPI ' ' JC SHOWHEX CPI 7FH JC CTYPE SHOWHEX: PUSH PSW MVI A,'(' CALL CTYPE POP PSW CALL HEXO MVI A,')' JMP CTYPE CTYPE: PUSH B PUSH D PUSH H MOV E,A MVI C,WRCON CALL BDOS POP H POP D POP B RET CRLF: PUSH PSW MVI A,CR CALL TYPE MVI A,LF CALL TYPE POP PSW RET TYPE: PUSH PSW PUSH B PUSH D PUSH H MOV C,A VTYPE: CALL $-$ POP H POP D POP B POP PSW RET STAT: PUSH B PUSH D PUSH H VSTAT: CALL $-$ POP H POP D POP B ORA A RET KEYIN: PUSH B PUSH D PUSH H VKEYIN: CALL $-$ POP H POP D POP B RET UCASE: CPI 61H ;CHANGES LOWER CASE CHARACTER.. RC ;..IN A-REG TO UPPER CASE. CPI 7BH RNC ANI 5FH RET DECOUT: PUSH PSW PUSH B PUSH D PUSH H LXI B,-10 LXI D,-1 DECOU2: DAD B INX D JC DECOU2 LXI B,10 DAD B XCHG MOV A,H ORA L CNZ DECOUT MOV A,E ADI '0' CALL CTYPE POP H POP D POP B POP PSW RET ;----> DHXOUT: - double precision hex output routine. DHXOUT: PUSH H PUSH PSW MOV A,H ;GET MS BYTE CALL HEXO ;OUTPUT HIGH ORDER BYTE MOV A,L ;GET LS BYTE CALL HEXO ;OUTPUT LOW ORDER BYTE POP PSW POP H RET HEXO: PUSH PSW RAR RAR RAR RAR CALL NIBBL POP PSW NIBBL: ANI 0FH CPI 10 JC ISNUM ADI 7 ISNUM: ADI '0' JMP TYPE ;RETURNS W/ ZERO SET IF RETRY ASKED. IF MULTI-FILE MODE, THEN ;NO QUESTIONS ASKED, JUST QUIT CKQUIT: LDA BATCHFLG ORA A JNZ CKQTASK ;ASK FOR RETRY INR A ;RESET ZERO FLG RET CKQTASK: XRA A STA ERRCT CALL ILPRT DB 'Multiple errors encountered.',CR,LF DB 'Type Q to quit, R to retry: ',BELL,0 CALL KEYIN PUSH PSW CALL CRLF POP PSW CALL UCASE ;INSTEAD OF "ANI 5FH" CPI 'R' RZ CPI 'Q' JNZ CKQUIT ORA A RET ILPRT: XTHL ILPLP: MOV A,M ORA A JZ ILPRET CALL CTYPE INX H JMP ILPLP ILPRET: XTHL RET PRTMSG: MVI C,PRINT JMP BDOS ERXIT: POP D CALL PRTMSG CALL ILPRT DB BELL,0 LDA BATCHFLG ORA A JNZ DONETCE MVI A,'Q' ;RESET QFLG STA QFLG JMP ABORT ;ABORT OTHER COMPUTER EXIT: LXI D,80H MVI C,STDMA CALL BDOS LHLD STACK SPHL LDA SAVCCP ORA A JZ 0 ;WARM BOOT RET MOVE128: MVI B,128 MOVE: MOV A,M STAX D INX H INX D DCR B JNZ MOVE RET ;DIALING ROUTINES TAKEN (AND GREATLY MODIFIED) FROM PMMI MANUAL. ;MODEM CONTROL COMMAND WORDS CLEAR EQU 3FH ;IDLE MODE MAKEM EQU 1 ;TELE LINE MAKE (OFF HOOK) BRKM EQU 0 ;TELE LINE ON HOOK (BREAK DURING DIALING) DTMSK EQU 1 ;DIAL TONE MASK RBLMT EQU 70 ;# OF SEC*10 TO WAIT BEFORE GIVING NO RING HEARG MSG RBWAIT EQU 50 ;# OF SEC*10 DELAY BEFORE REDIALING NUMBER TMPUL EQU 80H ;TIMER PULSES MASK BIT TRATE EQU 250 ;VALUE FOR 0.1 SECOND DIALPL: LDA PMMIBYTE ;FLAG FOR PMMI OPERATION ORA A ;SET FLAGS RZ ;PMMI FALSE, RETURN XRA A ; 0 STA CRFLAG ;CONTINUOUS REDIAL FLAG CALL DIALPL0 ; DISCONNECT, RECONNECT, WAIT DIAL TONE JC DILAGN ;ASK IF TRY AGAIN LXI H,CMDBUF+1 ;POINT # OF CHARS IN BUFF MOV A,M ;GET # OF CHARS CPI 4 ;4 OR MORE CHARS TYPED BEFORE ? JC ENTNUM ;NO, ASK FOR NUMBER LXI H,CMDBUF+6 ;POINT TO NUMBER TO DIAL JMP DIAL10 ;CHECK IF LIB #, & DIAL DIALPL0: CALL DISCONNT CALL ILPRT DB CR,LF,'Waiting for dial tone',CR,LF,0 MVI A,MAKEM ;MAKE MAKE (OFF-HOOK) CALL OUT$MODCTLP ;DO IT MVI D,DTMSK ;DIAL TONE MASK MVI C,100 ;10 SECOND WAIT CALL WAIT ;WAIT FOR DIAL TONE NOP ;DELAY ; WAIT SUBROUTINE WILL RETURN WITH CARRY SET IF UNABLE TO ; GET DIALTONE, ELSE CARRY NOT SET MEANS DIALTONE RECEIVED RNC ;IF DIAL TONE WITHIN 10 SECONDS CALL ILPRT ;ELSE, MESSAGE AND RETURN WITH CARRY SET DB CR,LF DB '++No dial tone after 10 seconds++',CR,LF,0 STC RET ENTNUM: ;this is all the set-up for the print at entnum2. MVI C,13 ;number of lines to move LXI H,NUMBLIB ;address of source memory LXI D,DBUF ;address of target memory CALL NEWLINE ;start with CRLF STAX D ;+LF INX D ;and bump it ENTNUM1: MVI B,30 ;number of bytes to move CALL MOVE ;move to buffer CALL SPACES ;2 entries + 3 spaces = 63 characters MVI B,30 CALL MOVE CALL NEWLINE DCR C ;number of lines to print JZ ENTNUM2 JMP ENTNUM1 NEWLINE: ;puts CR-LF at memory pointed by DE MVI A,CR ;CR STAX D ;store it MVI A,LF ;LF INX D ;bump pointer STAX D ;store LF INX D ;bump pointer RET SPACES: MVI A,20H ;space STAX D ! INX D ; 1 STAX D ! INX D ; 2 STAX D ! INX D ; 3 RET ENTNUM2: MVI A,'$' STAX D MVI C,PRINT LXI D,DBUF ;point to table of numbers to print CALL BDOS CALL CRLF CALL ILPRT DB 'Enter number or library letter - Type C/R when finished,',CR,LF DB 'CTRL-X cancels while dialing: ',0 LXI D,CMDBUF CALL INBUFF DIALLP1: LDA CMDBUF+1 ORA A ;NULL MEANS WAS TYPED JZ BORTIT ;ABORT DIALING, RETURN TO MENU LXI H,CMDBUF+2 ;FIRST TYPED CHAR OF NUMBER TO DIAL ; ; ENTER THIS ROUTINE WITH HL POINTING TO NUMBER TO DIAL ; DIAL10: MVI B,'A' ;FIRST LETTER OF ALPHABET MVI E,0 ;COUNTS NUMBER OF LETTERS TO MATCH MVI C,26 ;NUMBER OF LETTERS IN ALPHABET MOV A,M ;GET CHAR BUFFER DIAL11: CMP B ;NUMBER FROM TABLE? JZ LIBSET INR B ;MAKE NEXT LETTER (A-Z) INR E ;COUNT UP DCR C ;COUNT DOWN JZ DIALLPX ;NOT A LETTER JMP DIAL11 ;LOOP LIBSET: LXI H,NUMBLIB ;PHONE NUMBER LIBRARY LXI B,30 ;LENGTH OF LIBRARY ENTRY MOV A,E ;NUMBER OF TIMES TO ADD 30 TO HL ORA A ;SET FLAGS JZ DIAL13 DIAL12: MOV A,M ;GET FIRST CHAR OF SELECTED LIB ENTRY ORA A ;SET FLAGS JZ DIALLP2 ;SEND BADLIB MSG DAD B ;INCREMENT HL BY 30 DCR E ;COUNTDOWN JNZ DIAL12 ;NOT THERE YET, LOOP DIAL13: MVI B,30 ;NUMBER OF CHARACTERS TO GET FROM TABLE LXI D,CMDBUF+1 ;POINT TO BUFFER XCHG ;HL POINTS TO CMDBUF+1 MOV M,B ;STORE # OF BYTES IN A TABLE ENTRY XCHG ;RESTORE REG. INX D ;POINT TO FIRST CHAR POSITION IN BUFFER CALL MOVE ;MOVE TABLE ENTRY TO BUFFER DIALLPX: LDA CMDBUF+1 MOV E,A ;NUMBER OF CHARS IN BUFF LXI H,CMDBUF+2 ;POINT FIRST CHAR DIALLP2: MOV A,M ;GET FIRST # FROM BUFFER ; ; ROUTINE TO PRINT 'BADLIB' MESSAGE AND ABORT IF NULL ENCOUNTERED ; ORA A ;SET FLAGS PUSH D ;SAVE DE REGISTERS LXI D,BADLIB ;BAD LIBRARY NUMBER IF NULL MVI C,PRINT ; 9 PUSH PSW ;SAVE A AND FLAGS CZ BDOS POP PSW ;RESTORE A AND FLAGS POP D ;RESTORE DE REGISTERS JZ BORTIT ;ABORT ; ; DIAL A DIGIT, CHECK KBD FOR ABORT ; CALL DIAL ;DIAL IT CALL STAT ; KEYPRESS? ORA A ;SET FLAGS CNZ KEYIN ;YES, GO GET IT CPI CAN ; ^X? JZ BORTIT ;YES, ABORT INX H ;BUMP POINTER PUSH D ;SAVE DE PUSH H ;SAVE HL MVI B,1 ;WAIT 1 TIME INTERVAL CALL TIMER POP H ;RESTORE HL POP D ;RESTORE DE DCR E ;COUNT DOWN CHARS IN BUFF JNZ DIALLP2 ;NOT DONE, LOOP JZ DIALDN ;DIALING DONE DISCONNT: XRA A ;0 CALL OUT$MODCTL2 ;CLEAR DAV, ESD, ETC CALL OUT$MODCTLP ;HANG-UP PUSH B MVI B,8 ;wait for PMMI to disconnect CALL TIMER POP B RET TIMER: MVI A,TRATE ;TRATE 250, VALUE FOR .1 SEC INTERVAL CALL OUT$BAUDRP ;B-REG CONTAINS NUMBER OF .1 SEC INTERVALS TIMES: CALL IN$BAUDRP ;TO COUNT ANI TMPUL JZ TIMES ;WAIT FOR TIMER TO GO HIGH TIMEE: CALL IN$BAUDRP ANI TMPUL JNZ TIMEE ;WAIT FOR TIMER TO GO LOW DCR B JNZ TIMES RET BORTIT: CALL DISCONNT JMP MENU ;AUTO DIALER DIAL: CALL TYPE ;PRINT WHATEVER CHARACTER, DASHES, ETC. CPI 30H RC ;DIGIT MUST BE AT LEAST 0.. CPI 'R' ;COULD IT BE A RINGBACK CHARACTER JNZ DIAL1 ;NO? - JUMP PUSH PSW ;SAVE ACCUMULATOR & FLAGS MOV A,E ;GET # OF CHAR LEFT INTO ACC. CPI 01H ;IS THIS THE LAST CHARACTER? JZ RINGBK ;IF SO, IT MUST BE RINGBACK CHAR - DO RINGBACK POP PSW ;EVERYTHING BACK AS IT WAS DIAL1: CPI 3AH RNC ;..AND NOT MORE THAN 9 ANI 0FH ;STRIP ASCII -- COULD ALSO DO SUI 30H ('0') JNZ DIALS MVI A,10 ;CONVERT ZERO TO 10 PULSES DIALS: MOV C,A LDA PULSERATE ;CONTAINS VALUE FOR DIAL SPEED CALL OUT$BAUDRP DIALC: CALL IN$BAUDRP ANI TMPUL JNZ DIALC DIALB: CALL IN$BAUDRP ANI TMPUL JZ DIALB MAKEP: MVI A,MAKEM CALL OUT$MODCTLP TIMEM: CALL IN$BAUDRP ANI TMPUL JNZ TIMEM MVI A,BRKM CALL OUT$MODCTLP TIMEB: CALL IN$BAUDRP ANI TMPUL JZ TIMEB DCR C JNZ MAKEP MVI A,MAKEM CALL OUT$MODCTLP MVI B,2 CALL TIMER RET RINGBK: POP PSW ;TO GET IT OFF THE STACK LDA CMDBUF+1 ;GET # OF CHAR IN BUFFER SUI 01 ;SUBTRACT 1 TO AVOID THE RINGBACK CHAR STA CMDBUF+1 ;STORE THE NEW VALUE MVI D,DTMSK ;LOAD TONE DETECT MASK MVI C,RBLMT ;SET TIMER FOR RBLMT NUMBER OF SECONDS CALL WAIT JC RBTIME ;JUMP IF NO RING DETECTED MVI B,25 ;WAIT 2.5 SEC CALL TIMER CALL IN$BAUDRP ;IS TONE STILL PRESENT? ANA D JNZ RNGBK1 JMP DILAGN ;YES, MUST BE BUSY RNGBK1: CALL HANGP ;HANG UP THE PHONE MVI B,RBWAIT ;WAIT X SEC CALL TIMER CALL DIALPL0 ;GO OFF HOOK & LISTEN FOR DIAL TONE JNC DIALLPX ;GO REDIAL NUMBER JMP DILAGN ;NO DIAL TONE HEARD RBTIME: CALL CRLF JMP RNGBK1 ;HANGUP, REDIAL, & LISTEN FOR CARRIER ;TIME OUT ROUTINE. MUST BE CALLED WITH MASK IN D REG FOR INPUT ;AT RELATIVE PORT 2 AND NUMBER OF SECONDS * 10 IN C REG. WAIT: MVI B,1 CALL TIMER ;WAIT FOR TIMER TO GO HIGH THEN LOW CALL IN$BAUDRP ;PMMIADDR+2 (MODEM STATUS PORT) ANA D ;(CTS or DIALTONE MASK) RZ ;ACTIVE LOW, SO RETURN ON 0 PUSH B ;SAVE.. PUSH D ;..ACTIVE REG'S CALL STAT ;KEYPRESS? ORA A ;SET FLAGS CNZ KEYIN ;YES, GET CHAR CPI CAN ;^X? JZ WAIT1 ;YES, DISCONNECT, JMP TO MENU POP D ;RESTORE.. POP B ;..REGS DCR C ;COUNT-DOWN JNZ WAIT STC ;SET CARRY TO INDICATE MASK NOT SET RET WAIT1: POP D ;RESET.. POP B ;..STACK JMP DISCON1 ;DISCONNECT HANGP: MVI A,CLEAR CALL OUT$MODCTL2 MVI A,0 CALL OUT$MODCTLP RET DIALDN: CALL CRLF MVI A,07FH ;TURN ON DTR CALL OUT$MODCTL2 ;TIMER RATE? MVI B,1 CALL TIMER ;WAIT FOR MODEM TO TURN ON DTR MVI A,5DH ;2 STOP BITS, NO PARITY, 8 DATA BITS ;+ NO DISCONNECT AFTER 17 SECS CALL OUT$MODCTLP MVI D,4 ;CLEAR TO SEND MASK MVI C,WAITCTS ;wait time for cts (25.5 SEC MAX) CALL WAIT JNC CONMADE ;CONNECTION MADE CALL DISCONNT DILAGN: LDA CRFLAG ;CONTINUOUS REDIAL FLAG ORA A JNZ DILAGN0 CALL ILPRT DB CR,LF,'No answer after time-out. Redial? (Y/N/C): ',BELL,0 CALL KEYIN ;GET RESPONSE CALL TYPE ;ECHO IT CALL UCASE ;ANI 5FH CALL CRLF ;NEW LINE CPI 'N' ;REDIAL? JZ MENU ;NO, GO MENU CPI 'Y' ;REDIAL? JZ DILAGN0 ;YES, REDIAL CPI 'C' ;CONTINUOUS REDIAL? JNZ DILAGN ;INVALID RESPONSE, ASK AGAIN XRA A ! CMA ;0FFH STA CRFLAG ;CONTINUOUS REDIAL FLAG DILAGN0: MVI B,50 ;5 seconds wait for pmmi reset CALL TIMER ;else busy tone may be sensed as dialtone CALL DIALPL0 ;WAIT FOR DIAL TONE JNC DIALLP1 ;DIAL NUMBER JMP DILAGN ;NO DIAL TONE AFTER 10 SECS CONMADE: CALL ILPRT DB CR,LF,'Connection established - Select options: ',BELL,0 DILAGN1: CALL STAT ;KEYPRESS? ORA A ;SET FLAGS JNZ GETCMD ;KEY PRESSED, GO GET OPTIONS MVI A,BELL CALL TYPE ;RING BELL LXI B,2000H DILAGN2: ;@7.32......... DCR C JNZ DILAGN2 ;KILL SOME TIME FOR TERMINAL TO PROCESS BELL DCR B JNZ DILAGN2 ;@7.32......... JMP DILAGN1 ;LOOP ;INITIALIZES CP/M FILE CONTROL BLOCKS AT 5CH AND 6CH SETFCB: LXI D,CMDBUF LXI H,FCB CALL CPMLINE CALL PROCOPT CHECKNM: LDA FCB+1 ;CHECK ON THE PRIMARY OPTION CPI 'E' ;RETURN IF ECHO OPTION RZ CPI 'M' ;RETURN TO MENU RZ MOV B,A LDA PMMIBYTE ORA A MOV A,B JZ S4 CPI 'C' RZ S4: CPI 'T' JZ TERMSEL CPI 'S' JZ CKFILE CPI 'R' JNZ BDOPT LDA BATCHFLG ;IF MULT FILE MODE, THEN.. ORA A ;..RECV OPT DOES NOT NEED.. RZ ;..NAME. JMP CKFILE BDOPT: CALL ILPRT DB CR,LF,'++Bad Option++',CR,LF,0 JMP REENT CKFILE: LDA FCB+17 ;IF OPTION THAT NEEDS FILE NAME,.. CPI ' ' ;..THEN CHECK TO SEE IF NAME.. RNZ ;..EXISTS. IF NOT.. REENT: CALL ILPRT ;..DO EVERYTHING OVER. DB CR,LF,'Re-enter PRIMARY option and file name only: ',BELL,0 LXI D,CMDBUF CALL INBUFF JMP SETFCB TERMSEL: LDA FCB+17 CPI ' ' JNZ SAVAGN MVI A,FALSE STA SAVEFLG MVI A,TRUE STA NFILFLG CMA OUT FRONTPAN RET SAVAGN: MVI A,FALSE STA NFILFLG RET NEWBAUD: LDA PMMIBYTE ORA A RZ CALL ILPRT DB 'Enter New Baudrate: ',0 LXI H,FCB+9 MVI M,0 ;PUTS A ZERO IN FIRST POSITION SO AS TO LOOP5: CALL KEYIN ;FORCE THE DEFAULT OPTION OF 300 BAUD. CPI CR ;CARRIAGE RET ENTERS BAUD RATE JNZ CONNEWB ;GOES TO THE ESTABLISHED ROUTINE - RETURN TO MAIN CALL CRLF ;PROGRAM IS DONE THERE. JMP SETBAUD CONNEWB: CPI 30H ;MAKE SURE IT'S.. JC LOOP5 ;..A DIGIT, ELSE.. CPI 3AH ;..DON'T ACCEPT IT. JNC LOOP5 MOV M,A MOV C,A CALL TYPE ;ECHO THE CHARACTER ENTERED INX H JMP LOOP5 ; ;**************************************************************** ;* CRCSUBS (Cyclic Redundancy Code Subroutines) version 1.20 * ;* 8080 Mnemonics * ;* * ;* These subroutines will compute and check a true 16-bit * ;* Cyclic Redundancy Code for a message of arbitrary length. * ;* * ;* The use of this scheme will guarantee detection of all * ;* single and double bit errors, all errors with an odd * ;* number of error bits, all burst errors of length 16 or * ;* less, 99.9969% of all 17-bit error bursts, and 99.9984% * ;* of all possible longer error bursts. (Ref: Computer * ;* Networks, Andrew S. Tanenbaum, Prentiss-Hall, 1981) * ;* * ;* Designed & coded by Paul Hansknecht, June 13, 1981 * ;* * ;* Copyright (c) 1981, Carpenter Associates * ;* Box 451 * ;* Bloomfield Hills, MI 48013 * ;* 313/855-3074 * ;* * ;* This program may be freely reproduced for non-profit use. * ;* * ;**************************************************************** ; ; ENTRY CLRCRC,UPDCRC,FINCRC,CHKCRC ; CLRCRC: EQU $ ;Reset CRC Accumulator for a new message. PUSH H LXI H,0 SHLD CRCVAL POP H RET ; UPDCRC: EQU $ ;Update CRC Accumulator using byte in (A). PUSH PSW PUSH B PUSH H MVI B,8 MOV C,A LHLD CRCVAL ; UPDLOOP: MOV A,C RLC MOV C,A MOV A,L RAL MOV L,A MOV A,H RAL MOV H,A JNC SKIPIT MOV A,H ;The generator is X^16 + X^12 + X^5 + 1 XRI 10H ;as recommended by CCITT. MOV H,A ;An alternate generator which is often MOV A,L ;used in synchronous transmission protocols XRI 21H ;is X^16 + X^15 + X^2 + 1. This may be MOV L,A ;used by substituting XOR 80H for XOR 10H SKIPIT: DCR B ;and XOR 05H for XOR 21H in the adjacent code. JNZ UPDLOOP SHLD CRCVAL POP H POP B POP PSW RET ; FINCRC: EQU $ ; Finish CRC calc for outbound message. PUSH PSW XRA A CALL UPDCRC CALL UPDCRC PUSH H LHLD CRCVAL MOV D,H MOV E,L POP H POP PSW RET ; CHKCRC: EQU $ ; Check CRC bytes of received message. PUSH H LHLD CRCVAL MOV A,H ORA L POP H RZ MVI A,0FFH RET ; CRCVAL: DW 0 ; MENU: LXI H,RESTSN ;RESTORE SECTORE NUMBERS.. LXI D,SECTNOB ;..FOR NEW FILE TRANSFER. MVI B,SECTNOE-SECTNOB CALL MOVE LXI H,RESTROPT ;RESTORE OPTION TABLE LXI D,OPTBL MVI B,OPTBE-OPTBL CALL MOVE MVI A,0 STA MFFLG1 ;RESET MFACCESS ROUTINE.. CMA ;..AND MULTI TRANS IN CASE.. STA FSTFLG ;..OF ABORT. MENU1: LDA XPRFLG ;TEST IF MENU SHOULD BE SHOWN ORA A JNZ XPRT MENU2: CALL ILPRT DB CR,LF,CR,LF DB 'WRT - Write file to disk (from terminal mode)',CR,LF DB 'DEL - Erase present file (from terminal mode)',CR,LF DB 'RET - Return to terminal mode with no loss of data',CR,LF,0 LDA PMMIBYTE ORA A JZ S5 CALL ILPRT DB 'DSC - Disconnect',CR,LF DB 'CAL - Dial number',CR,LF,0 S5: CALL ILPRT DB 'XPR - Toggle expert mode (Menu on/off)',CR,LF DB 'DIR - List directory (may specify drive)',CR,LF DB 'CPM - Exit to CP/M',CR,LF DB 'S - Send CP/M file',CR,LF DB 'R - Receive CP/M file',CR,LF DB 'T - Terminal mode (optional file name)',CR,LF DB 'E - Terminal mode with echo',CR,LF,0 XPRT: CALL ILPRT DB CR,LF,CR,LF,'DEFAULT DRIVE: ',0 MVI C,25 ;CURRENT DISK FUNCTION CALL BDOS ADI 41H ;MAKE ASCII CALL TYPE CALL ILPRT DB CR,LF,CR,LF,'Command: ' DB 0 GETCMD: LXI D,CMDBUF ;ENTER COMMAND CALL INBUFF CALL CRLF LXI D,CMDBUF+2 ;POINT TO COMMAND CALL ILCOMP DB 'CPM',0 JNC EXIT CALL ILCOMP DB 'DIR',0 JNC DIR CALL ILCOMP DB 'RET',0 JC NXTOPT1 ;CARRY SET = NO MATCH lda origsav ;@MODEM75.FIX sta origflg ;@MODEM75.FIX LHLD HLSAVE ;RETURN TO TERMINAL.. JMP TERM ;..MODE WITH SAVE OPTION.. ;..IF PREVIOUSLY ENABLED. NXTOPT1: LDA PMMIBYTE ORA A JZ S6 CALL ILCOMP ;DE SET FROM 1ST ILCOMP CALL DB 'DSC',0 JNC DISCON1 S6: CALL ILCOMP DB 'WRT',0 JNC WRTFIL CALL ILCOMP DB 'XPR',0 JNC XPRMODE CALL ILCOMP DB 'DEL',0 JNC NEWFILE LDA PMMIBYTE ORA A JZ NXTOPT2 CALL ILCOMP DB 'CAL',0 JC NXTOPT2 MVI A,20H ;FOOL THE SYSTEM''' STA CMDBUF+4 ;..CMDBUF SO THAT IT.. JMP DOOPT ;..LOOKS AT OPTION FOR DIAL NXTOPT2: PUSH H LDA CMDBUF+2 LXI H,COMPLIST CALL COMPARE ;COMPARES LIST POINTED TO BY HL.. POP H ;..TO CHAR IN A-REG. JC MENU1 ;CARRY SET = NO MATCH DOOPT: PUSH H ;LOAD ORIGINAL FCB WITH TRANSFER.. CALL SETFCB ;..CMDS AND GO TO BEGINNING OF.. POP H ;..PROGRAM. WILL FOLLOW SAME LOGIC.. JMP RESTART ;..AS IF PROGRAM WERE CALLED WITH.. ;..CP/M COMMAND LINE. DISCON1: LDA PMMIBYTE ORA A JZ MENU CALL DISCONNT CALL ILPRT DB CR,LF,'++Disconnected++',CR,LF,BELL,0 JMP MENU ;@MODEM75.FIX (was MENU1) - restore option tables DIR: CALL DIRLST JMP XPRT NEWFILE: LDA FCB3+1 CPI ' ' JZ MENU1 ;IF NO FILE, DON'T ERASE LXI D,FCB3 MVI C,ERASE CALL BDOSRT MVI A,TRUE ;DO NOT ALLOW TERMINAL.. STA NFILFLG ;..SAVE SINCE NO FILE.. CMA ;..SPECIFIED. STA SAVEFLG OUT FRONTPAN LXI H,FCB3 CALL INITFCBS JMP MENU1 WRTFIL: LDA NFILFLG CPI TRUE JZ MENU1 LDA FCB3+1 ;CHECK THAT FILE WAS REQUESTED CPI ' ' JZ MENU1 LHLD HLSAVE CALL NUMRECS ;DISK WRITE ROUTINE AS USED IN.. CALL WRTDSK ;..IN THE INTDSKSV ROUTINE. CALL CLOSE3 MVI A,TRUE STA NFILFLG CMA STA SAVEFLG OUT FRONTPAN LXI H,FCB3 CALL INITFCBS ;BLANK OUT FCB SO WRITTEN FILE.. JMP MENU1 ;..CAN'T BE ERASED. XPRMODE: LDA XPRFLG CMA STA XPRFLG JMP MENU1 COMPARE: MOV B,M ;COMPARES A-REG WITH LIST.. COMPLP: INX H ;..ADDRESSED BY HL. FIRST ELEMENT.. CMP M ;..OF LIST MUST BE NUMBER OF ELEMENTS.. JZ VALID ;..BEING COMPARED. RETURNS WITH.. DCR B ;..CARRY SET IF A-REG DOES NOT.. JNZ COMPLP ;.. CONTAIN AN ELEMENT IN LIST. STC VALID: RET COMPLIST: DB 5, 'S', 'R', 'T', 'E', 'M' ILCOMP: INLNCOMP ;A MACRO IN MACROS.LIB INBUFF: INBUF ;A MACRO IN "MACROS.LIB" ;IF ABOVE ROUTINE DOES NOT LET YOU EDIT IN A PROPER MANNER, ;THEN THE MACRO MAY BE SUBSTITUTED FOR THE FOLLOWING ROUTINE: ;INBUFF: ; MVI C,RDBUF ; CALL BDOSRT ; RET ;BUT BE CAREFUL OF CONTROL-C CPMLINE: CMDLINE ;A MACRO IN "MACROS.LIB" DIRLST: DIRLIST ;A MACRO IN "MACROS.LIB" NFILFLG: DB FALSE ;NORMALLY SET TO FALSE. ALLOWS WRITE TO.. ;..MEMORY IN TERMINAL MODE. OPTION: DB 0 OPTBL: EQU $ ANSWFLG: DB 'A' DISCFLG: DB 'D' ORIGFLG: DB 'O' QFLG: DB 'Q' RSEEFLG: DB 'R' SSEEFLG: DB 'S' VSEEFLG: DB 'V' TERMFLG: DB 'T' EPARITY: DB '0' ;EVEN PARITY SUB-OPTION - ONLY AVAILABLE IN 'S' AND 'R' MODES OPARITY: DB '1' ;ODD PARITY SUB-OPTION - ONLY AVAILABLE IN 'S' AND 'R' MODES BATCHFLG: DS 1 ;SET TO 'B' BY MENU. DOES NOT ALLOW MULTI-.. OPTBE: EQU $ ;..FILE XFER WHEN PROGRAM INITIALLY CALLED. RESTROPT: ;MUST BE IN SAME ORDER AS TABLE ABOVE DB 'A','D','O','Q','R','S','V','T' ; DB 'C' ;@7.41 DB '0','1','B' CRCFLG: DB 'C' ;use CRC instead of cksum ;@7.41 (moved) RESTSN: DB 0,0,0,0,0,0 DW DBUF DB 0,0,0,0,0 SECTNOB: EQU $ RCVSNO: DB 0 SECTNO: DW 0 ERRCT: DB 0 ERRCDE: DB 0 EOFLG: DB 0 SECPTR: DW DBUF SECINBF: DB 0 MAXEXT: DB 0 RCNT: DW 0 DATAFLG: DB 0 EXACFL: DB 0 SECTNOE: EQU $ BADOPT: CALL ILPRT DB 'Invalid option',CR,LF,BELL,0 JMP MENU FSTFLG: DB TRUE FIRSTME: DB 0FFH ;first SOH received switch(it is zero after 1rst SOH) CMDBUF: DB 80H,0 DS 80H BADLIB: DB CR,LF,'++Bad library number called++',CR,LF,'$' HLSAVE: DS 2 DISKNO: DS 1 SENDFLG: DS 1 NBSAVE: DS 2 BGNMS: DS 2 FILECT: DS 1 NAMECT: DS 1 origsav: ds 1 ;@MODEM75.FIX MODCTLB: DB 07FH UARTCTLB: DB ANSWMOD ; @7.5 (was previously ORIGMOD) DS 100 STACK: DS 2 FCB3: DS 33 FCBBUF: DS 15 DBUF: EQU $ NAMEBUF: EQU DBUF+(DBUFSIZ*1024) ;BUFFER FOR NAMES IN BATCH MODE. OVERFLOWS.. ;..ABOVE PROGRAM CODE. ; BDOS EQUATES RDCON EQU 1 WRCON EQU 2 PRINT EQU 9 RDBUF EQU 10 CONST EQU 11 OPEN EQU 15 CLOSE EQU 16 SRCHF EQU 17 SRCHN EQU 18 ERASE EQU 19 READ EQU 20 WRITE EQU 21 MAKE EQU 22 REN EQU 23 STDMA EQU 26 FILSIZ EQU 35 BDOS EQU 5 REIPL EQU 0 FCB EQU 5CH FCBEXT EQU FCB+12 FCBSNO EQU FCB+32 FCBRNO EQU FCB+32 FCB2 EQU 6CH LAST END 100H