; ; *** SMODEM53 *** ; for the Xerox 820-II and Hayes 1200 or 300 ; ; CP/M SMARTMODEM program ; ========================= ; Version 5.30 by D Howard ; Version 5.20 by TF Buchanan ; Version 5.10 by JP Sojak ; Version 3.00 by W Bladey ; ; THIS PROGRAM WAS ORIGINALLY MODEM7.MAC WRITTEN BY ; WARD CHRISTENSEN AND REVISED BY M.ZEIGER AND J.MILLS FOR THE ; PMMI MODEM BOARD. FULL CREDITS FOR EXPERIENCE AND TALENT THAT ; MADE THIS program POSSIBLE, BELONG SOLELY TO THESE PEOPLE. ; ; MANY ADDITIONAL ROUTINES INCLUDED ARE COPYRIGHTED (1980) BY ; MARK M.ZEIGER AND J.MILLS. PERMISSION IS GRANTED TO USE ; BUT NOT SELL THESE ROUTINES. ; ; FOR FULL INFORMATION ON THE USE OF 'SMODEM3', PLEASE REFER TO ; THE FILE 'SMODEM3.DOC'. ; ;****************************************************************************** ;03/12/8³ Thió versioî oæ Smodeí haó beeî especiallù designed » foò thå Xeroø 820-II® Aî addeä bonuó awaitó thå ne÷ owneró of ; the DC Hayes Smartmodem 1200. You can use both the 300 and 1200 ; baud in this program. You can change baud by simply typing 'S3' ; or 'S12'. A tip of the hat goes to Chris Neal of Dallas, Tx for his ; concept of the 300-1200 feature within this program. » Thå Disconnecô featurå haó beeî correcteä tï worë ; properly--it never has correctly worked right beforehand. Those ; of you wanting to use this program with MCI or SPRINT, these features ; have been maintained for your useage. » Tï accesó thå Commanä Mode¬ simplù uså thå key to allow a cntrl-P with Compuserve. » Thå equatå SWITCÈ allowó thå internaì selectioî oæ 30° oò 120° ; baud® Thoså oæ yoõ witè otheò machineó shoulä appropriatelù changeä ; the information sent to your SIO registers and Baud Port--again, ; these are correct for the Xerox 820-II with an SIO-0 chip. ; +++ David Howard +++ ; Dallas, Texas ; ;2/2/83 PERSISTENT BUGS: CRC error may cause crash dur- ; ing download. In terminal mode, when memory ; buffer fills automatically begins dump (normal) ; but continues to dump memory contents over & ; over (apparently forever). Does not properly dial ; typed phone numbers if alt. LD system used. TFB ; Renamed SMODEM52. ; Š;2/2/83 Removed modem reset on initialization because ; ineffectual. Changed ALTEXIT to false. Changed ; OFFLIN from 'O' to 'E'. Bypassed all ECOTOG to ; avoid conflict (Now exits term mode with '^E' ; rather than or '^O' for greater compatibi- ; lity with modem programs. TFB ; ;1/13/83 Added modem reset on initialization. Alternate ; LD mode now differentiates between SPRINT, MCI, ; etc., if 'S/' or 'M/' used as appropriate. ; Renamed SMODEM51A. TFB ; ;1/8/83 Changed '~' to '-' in redial. Changed 'S/' ; to 'A/' for alt. LD dialing. Incorporated ; FASCK into modem command routines. Added ; supplementary 1200 baud directory. CONINLP ; modified to allow lower case. TFB ; ;1/3/83 Default to expert mode following load. Revised ; phone directory (TYMNET & PALATINE). TFB ; ;12/21/82 Removed UART error detection. Altered phone ; directory. TFB ; ;12/14/82 Added 8251 UART initialization, SIO 2-2 port ; addresses, UART error detection, & removed ; minor errors. Changed "Sprint" to "Alternate ; Long distance & TFB ; Renamed SMODM51A. ; ;10/08/82 Added conditional for Southern Pacific Communications ; 'Sprint' service to the dialing routine. You must ; insert your local access and Sprint account numbers ; in the 'spntnun' and 'loclnum' labels if this ; conditional switch is on. This feature ia accessed ; by a S/ in the dialing routine before the library ; or the dialed number. Tagged this version 'smodem51'. ; Fixed the bug that would not allow the 'R' option on ; the phone number - (reverse org to ans mode). ; ;01/01/82 Added Osborne 1 conditional. These routines have been ; tested in 'smodem3', but not in 'smodem5', keep an ; eyeout for bugs. Added conditional for selecting an ; ascii for terminal mode exit instead of the ^E ; ;09-28/82 Added a re-dial upon 'NO CARRIER'. Removed the exit to ; 'terminal' mode in favor of 'menu' mode after a disconnect ; (^D or 'dsc'). Added code to allow an ascii comma <,> to ; pass thru on the dial routine. (The comma tells the Smodem ; to pause.). Sorry, could not take the 'programme', changed ; these to 'program'. Tagged this version 'smodem5.asm'. ; ;08-29/82 Zapped a few bugs that destroyed the smodem3 memory immage ; when ^R was used to recieve text files, scrolled both the ; menues and number library off the screen. Cleaned up the Š; code somewhat (removed last traces of M80, and refor- ; matted the 'asm listing, deleted garbage comments, etc) ; Added initialization for Motorola 6850 type usarts, 450 ; baud, on a TDL SMB II 'tty' port. (450 baud if you hoogie ; the baud rate geeneerator control pin foils) ; ; JP Sojak ;****************************************************************************** ; TRUE EQU 0FFH FALSE EQU 0 CPM2 EQU TRUE ;TRUE=CP/M 2+...FALSE=CP/M 1+ DBFSIZ SET 16 ;DISK BUFFER SIZE IN 128 BYTE SECTORS ;CHANGE THIS TO 8 FOR A 32K SYSTEM ; set for the Osborne 1 ERRLIM EQU 5 ; NUMBER OF TIMES TO RETRY ; SEND/RECEIVE ERRORS BEFORE QUIT DJBRD EQU FALSE ; TRUE=DISK-JOCKEY CONTROLER RS232 I/O PORTIO EQU TRUE ; TRUE=RS232 I/O OTHER THAN DISK-JOCKEY INLZE EQU FALSE ; TRUE=RS232 I/O PORT INITIALIZATION SMBII EQU FALSE ; TDL SMBII 6850 USARTS ; (port,inlze & smbII = true) CHEK EQU FALSE ; TRUE=OVERRUN,FRAMING AND PARITY ; CHECKS NEEDED...ONLY SET TO TRUE IF ; PORTIO=TRUE. OSBORNE EQU FALSE ; IS IT AN OSBORNE 1 ? ; (all above false for osborne = true) IF OSBORNE DBFSIZ SET 10 ;LEAVE GOBS OF ROOM AT THE TOP FOR I/O ENDIF SWITCH EQU TRUE ; ALLOWS SELECTING 300 OR 1200 BAUD IN ; THE PROGRAM ALTEXIT EQU TRUE ; CHOOSE AN INSTEAD OF ^O TO COMMAND ALTLD EQU FALSE ;USE ALTERNATE LD DIALING PRINTR EQU 1BH ; ESC = LIST DEVICE TOGGLE-ASCII ESCAPE ECOTOG EQU 'E'-40H ; ^E = TERM/ECHO TOGGLE ALTCHR EQU 7FH ; ^[ = ASCII DELETE OFFLIN EQU 'O'-40H ; ^O = OFFLINE WITHOUT DISCONNECT DISCCHR EQU 'D'-40H ; ^D = DISCONNECT TRANCHR EQU 'T'-40H ; ^T = TRANSFER CHARACTER DIALCHR EQU 'A'-40H ; ^A = Re-dial CAN EQU 'X'-40H ; ^X = CANCEL SEND/RECEIVE EOFCHAR EQU 'Z'-40H ; ^Z = END OF FILE SAVECHR EQU 'R'-40H ; ^Y = RECEIVE CHARACTER XOFF EQU 'S'-40H ; ^S = XOFF CHARACTER XON EQU 'Q'-40H ; ^Q = XON CHARACTER CRC EQU 'C' ; CRC CHECK INSTEAD OF CHECKSUM SOH EQU 1 ; START OF HEADER EOT EQU 4 ; END OF TEXT ŠACK EQU 6 ; ACKNOWLEDGE NAK EQU 15H ; NOT ACKNOWLEDGE BDNMCH EQU 75H ; BAD NAME MATCH OKNMCH EQU ACK ; OKAY NAME MATCH LF EQU 0AH ; LINEFEED CR EQU 0DH ; CARRIAGE RETURN FF EQU 0CH ; FORM FEEDE BELL EQU 7 ; BELL CHARACTER YES EQU 59H NO EQU 4EH ORG 0100H JMP START ; BEGINNING OF program ; ; IF YOU HAVE ALTERNATE LD SERVICE, FILL IN THESE DEFINE BYTES ; IF YOU WISH SMODEM5 TO DIAL THE NUMBERS FOR YOU (ONLY IF ; THE SWITCH ABOVE IS ; ;MODRST DB '+++$ATZ',CR,'$' ; MODEM INITIALIZATION RESET **DIS** MCINUM DB '--------' ; PUT YOUR LOCAL ALD OFFICE PHONE NUMBER HERE DB ',,,,,' ; ADJUST THE COMMAS FOR YOUR LOCAL ALD OFFIFE MCICOD DB '-----' ; PUT YOUR ALTERNATE LD CODE NUMBER HERE DB ',$' ; ...TERMINATOR (MUST BE HERE) SPRNUM DB '--------' ; SAME, FOR SPRINT DB ',,,,,' SPRCOD DB '------' DB ',$' ; 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 ; 52 NUMBERS ARE ALLOWED. ; ; '----5---10---15---20---25---30' NUMBLIB:DB 'A= Mississauga 1-416-826-5394' ;'A' DB 'B= Bruce Rs RCP 1-201-272-1874' ;'B' DB 'C= Houston Xerox1-713-789-3243' ;'C' DB 'D= Dave Crane 931-8274' ;'D' DB 'E= Aims RCPM 1-312-789-0499' ;'E' DB 'F= Compuserve THREE 761-9040' ;'F' DB 'G= Compuserve TWELVE 761-0599' ;'G' DB 'H= Hull Eng 011-44-482-859169' ;'H' DB 'I= Allentwn RCPM1-215-398-3937' ;'I' DB 'J= Time & Temp 844-4444' ;'J' DB 'K= Kelly Smith 1-805-527-9321' ;'K' DB 'L= Maxicom ONE 931-0323' ;'L' DB 'M= Atlanta CBBS 1-404-394-4220' ;'M' DB 'N= BHEC RCPM 1-301-661-4447' ;'N' DB 'O= Tech. CBBS 1-313-846-6127' ;'O' Š DB 'P= CBBS 352-4147' ;'P' DB 'Q= WestfallHstn 1-713-469-8893' ;'Q' DB 'R= Rochester NY 1-716-425-1785' ;'R' DB 'S= Amrad 1-703-734-1387' ;'S' DB 'T= Flanders RCPM1-201-584-9227' ;'T' DB 'U= NEI RCPM 1-312-949-6189' ;'U' DB 'V= PalatineRCPM 1-312-359-8080' ;'V' DB 'W= Toronto-A 1-416-231-9538' ;'W' DB 'X= Toronto-B 1-416-231-1262' ;'X' DB 'Y= Chicago CBBS 1-312-545-8086' ;'Y' DB 'Z= CPMUG CBBS 1-312-849-1132' ;'Z' ; '----5---10---15---20---25---30' DB 'a= Superbrain 1-617-862-0781' ;'a' DB 'b= IBM-PC BBS 1-312-647-7636' ;'b' DB 'c= Mission HUG 1-913-362-9583' ;'c' DB 'd= Los Angeles 1-213-296-5927' ;'d' DB 'e= GFRN Palos V 1-213-541-2503' ;'e' DB 'f= MOG-UR HBBS 1-213-366-1238' ;'f' DB 'g= San Diego 1-619-273-4354' ;'g' DB 'h= GFRN G Grove 1-714-534-1547' ;'h' DB 'i= AnaHug RCPM 1-714-774-7860' ;'i' DB 'j= DataTech HUG 1-415-595-0541' ;'j' DB 'k= Colo Springs 1-303-634-1158' ;'k' DB 'l= Pinecliff 1-303-642-3034' ;'l' DB 'm= College Sta 1-713-693-3462' ;'m' DB 'n= C Forsberg 1-503-621-3193' ;'n' ; DB 'o= ...........................' ;'o' ; DB 'p= ...........................' ;'p' ; DB 'q= ...........................' ;'q' ; DB 'r= ...........................' ;'r' ; DB 's= ...........................' ;'s' ; DB 't= ...........................' ;'t' ; DB 'u= ...........................' ;'u' ; DB 'v= ...........................' ;'v' ; DB 'w= ...........................' ;'w' ; DB 'x= ...........................' ;'x' ; DB 'y= ...........................' ;'y' ; DB 'z= ...........................' ;'z' DB 0,'$' ; end ; ; this is a supplemental number library ; ; ; FORUM Union NJ 1201-688-7117' ;'F' ; Tim Nicholas 1-516-698-8619R' ;'N' ; Bruce Ratoff 1-201-272-1874' ;'R' ; ACGNJ ABBS 1-201-968-1074' ;'S' DB 0,'$' ; end ; 'STYLE' DEFINES THE DIALING COMMAND THAT WILL BE SENT ; TO THE HAYES SMARTMODEM WHEN USING THE AUTO DIALING OPTION. ; 'AT'= ATTENTION...'D'= DIAL. ; AND THE '$'= END OF COMMAND LINE (MUST BE IN PLACE). ; COMMANDS TO HAYES MAY ALSO BE ENTERED DIRECTLY IN TERMINAL OR Š; ECHO MODES. 4 EXTRA BYTES ARE ALLOTED FOR LONGER COMMANDS. STYLE: DB 'ATDT $' ; MODEM DIALING COMMAND...ENTER A 'P' DS 4 ; OR 'T' FOR PULSE OR TOUCH AFTER THE ; 'D' IF DESIRED. the is reqd. ; 'OFFHK'DEFINES THE ESCAPE AND HANG-UP CODE SENT TO THE ; SMARTMODEM. '+++'= THE HAYES DEFAULT ESCAPE CODE TO ; RE-ENTER THE COMMAND STATE, AND 'ATH'= THE HANG-UP COMMND. ; THE '$'= END COMMAND LINE (MUST BE IN PLACE). OFFHK: DB '+++$ATH',CR,'$' ; MODEM ESCAPE AND DS 4 ; HANG-UP CODE FASCLK: DB true ; 2 MZ OPERATION = FALSE...4 MZ = TRUE FASCK EQU FALSE BKBYTE: DB TRUE ; TRUE = MAKE .BAK FILE XPRFLG: DB TRUE ; FALSE = PRINT MENU ON INITIALIZATION LSTFLG: DB 0 ; LIST DEVICE FLAG MACFLG: DB 0 ; SEND/RECEIVE OBJECT CODE FLAG DIALFLG DB 0 ; RE-DIAL ACTIVE FLAG CONTFLG DB 0FFh ; CONNECT FLAG DLYDIA DB 0 ; DELAY STORAGE FOR RE-DIAL COMMAND ; PRESENTLY SET FOR DJ BOARD I/O IF DJBRD ; IF DISKJOCKEY BOARD MODATP EQU 0D3F8H ; MODEM DATA PORT MOCTLP EQU 0D3F9H ; MODEM CONTROL PORT MOSNDB EQU 8 ; MODEM SEND BIT MOSNDR EQU 0 ; MODEM SEND READY MORCVB EQU 4 ; MODEM RECEIVE BIT MORCVR EQU 0 ; MODEM RECEIVE READY ; I/O ROUTINES FOR DJ BOARD SERIAL PORT INCTLP: LDA MOCTLP ; in modem control port RET OTDATP: CMA ; out modem data port STA MODATP CMA RET ANSNDB: ANI MOSNDB ; bit to test/send ready RET CPSNDR: CPI MOSNDR ; value send bit/ready RET INDATP: LDA MODATP ; in modem data port CMA RET ANRCVB: ANI MORCVB ; bit test receive ready Š RET CPRCVR: CPI MORCVR ; value receive ready RET OTCTLP: LDA MOCTLP ; modem output control port RET ENDIF ; DJBOARD IF OSBORNE MODATP EQU 2A01h ; MODEM DATA PORT MOCTLP EQU 2A00h ; MODEM CONTROL PORT MOSNDB EQU 2 ; MODEM SEND BIT MOSNDR EQU 2 ; MODEM SEND READY MORCVB EQU 1 ; MODEM RECEIVE BIT MORCVR EQU 1 ; MODEM RECEIVE READY ; ; I/O ROUTINES FOR OSBORNE SERIAL RS232 PORT ; ; 'X' pins 2 & 3. use ONLY pins 1,2,3,7 else smoke ; INCTLP: JMP SSTAT DB ' INCTLP PATCH AREA' OTDATP: JMP SOUT DB ' OTDATP PATCH AREA' ANSNDB: ANI MOSNDB ; bit to test/send ready RET CPSNDR: CPI MOSNDR ; value send bit/ready RET INDATP: JMP SIN DB ' INDATP PATCH AREA' ANRCVB: ANI MORCVB ; bit test receive ready RET CPRCVR: CPI MORCVR ; value receive ready RET OTCTLP JMP SSTAT DB ' OTCTLP PATCH AREA' ENDIF ; OSBORNE ; ; SET THESE THE FOLLOWING EQUATES TO MATCH YOUR SERIAL ; I/O ASSIGNMENTS, AND DELETE THE ONES NOT USED. ; Š IF PORTIO ; IF OTHER THAN DJBOARD IF SMBII PORT EQU 70h ; BASE ADDRESS MOCTLP EQU PORT ; MODEM CONTROL PORT MOSNDB EQU 2 ; MODEM SEND READY BIT MOSNDR EQU 2 ; VALUE WHEN MODEM SEND READY MORCVB EQU 1 ; MODEM RECEIVE READY BIT MORCVR EQU 1 ; VALUE WHEN MODEM RECEIVE READY MODATP EQU PORT+1 ; MODEM DATA PORT BAUDRP EQU PORT+1 ; BAUD RATE PORT MOCTL2 EQU PORT+1 ; 2ND MODEM CONTROL PORT ENDIF ;SMBII IF NOT SMBII ; SET THESE THE FOLLOWING EQUATES TO MATCH YOUR SERIAL ; I/O ASSIGNMENTS, AND DELETE THE ONES NOT USED. PORT EQU 06H ; PUT YOUR PORT BASE ADDRESS HERE MOSTAT EQU 06H ; STATUS PORT AGAIN LISTED MOCTLP EQU 06H ; MODEM CONTROL PORT HERE MOSNDB EQU 04H ; MODEM SEND READY BIT (MASK) MOSNDR EQU 04H ; VALUE WHEN MODEM SEND READY MORCVB EQU 01H ; MODEM RECEIVE READY BIT (MASK) MORCVR EQU 01H ; VALUE WHEN MODEM RECEIVE READY MODATP EQU 04H ; MODEM DATA PORT HERE BAUDRP EQU 00H ; BAUD RATE PORT HERE MOCTL2 EQU 07H ; 2ND MODEM CONTROL PORT, IF ANY, HERE BAUD EQU 00H ; BAUD RATE PORT AGAIN ENDIF ;NOT SMBII IF CHEK FRMER EQU 00H ; FRAMING ERROR MASK ORUNER EQU 00H ; OVERRUN ERROR MASK PARER EQU 00H ; PARITY ERROR MASK ERRMSK EQU 00H ; MASK TO BLOCK ALL BITS EXCEPT ENDIF ;CHEK ; I/O ROUTINES FOR SERIAL PORTS OTHER THAN DJ BOARD INCTLP: IN MOCTLP ; in modem control port RET OTDATP: OUT MODATP ; out modem data port RET ANSNDB: ANI MOSNDB ; bit to test/send ready RET CPSNDR: CPI MOSNDR ; value send bit/ready RET INDATP: IN MODATP ; in modem data port RET ANRCVB: ANI MORCVB ; bit test receive ready RET CPRCVR: CPI MORCVR ; value receive ready RET ŠOTCTLP: IN MOCTLP ; modem output control port RET ; IF YOUR SERIAL PORTS MUST BE INITIALIZED SET THESE EQUATES IF INLZE OR SMBII INITC1 EQU 00h INITC2 EQU 00h INITC3 EQU 00H ENDIF ; INLZE OR SMBII ; THE FOLLOWING ROUTINE ADDRESSES THE SIO-0 Z80 UART IN THE XEROX 820-II. ; IT IS SETUP FOR THE COMMUNICATIONS PORT AND ALLOWS THE CALLER TO ; SELECTIVELY CHOOSE BETWEEN 1200 OR 300 BAUD (IF HE HAS A SMARTMODEM 1200). ; USERS WITH ONLY A 300 BAUD MODEM SHOULD SELECT ONLY "S3" IN THE COMMAND ; MODE. IF SWITCH SET300B: CALL ILPRT DB '++ BAUD RATE NOW 300 ++',CR,LF,0 MVI A,18H ;SET Z80 SIO FOR WORD FORMAT OUT MOSTAT MVI A,4 ;SELECT REGISTER 4 OUT MOSTAT MVI A,44H OUT MOSTAT MVI A,3 ;SELECT REGISTER 3 OUT MOSTAT MVI A,0E1H OUT MOSTAT MVI A,5 ;SELECT REGISTER 5 OUT MOSTAT MVI A,0EAH OUT MOSTAT MVI A,5 ;300 BAUD OUT BAUD JMP XPRT ENDIF ;SWITCH IF SWITCH SET120B: CALL SETDFLT JMP XPRT ENDIF ;SWITCH IF SWITCH SETDFLT: CALL ILPRT DB '++ BAUD RATE NOW 1200 ++',CR,LF,0 MVI A,18H ;SET Z80 SIO FOR WORD FORMAT OUT MOSTAT MVI A,4 ;SELECT REGISTER 4 Š OUT MOSTAT MVI A,44H OUT MOSTAT MVI A,3 ;SELECT REGISTER 3 OUT MOSTAT MVI A,0E1H OUT MOSTAT MVI A,5 ;SELECT REGISTER 5 OUT MOSTAT MVI A,0EAH OUT MOSTAT MVI A,7 ;1200 BAUD OUT BAUD RET ENDIF ;SWITCH ;***************************************************************************** ; END OF USER DEFINABLE ROUTINES --ACTUAL PROGRAM IS BELOW ;***************************************************************************** START: LXI H,0 DAD SP ; GET CP/M'S STACK SHLD STACK ; SAVE IT LXI SP,STACK ; START LOCAL STACK IF OSBORNE MVI B,OLENG ; move the I/O routines up in ram LXI H,0A000H LXI D,OSCODE MOVVE LDAX D ; Z80 where are you (this is the hard way)??? MOV M,A INX H INX D DCR B JNZ MOVVE call ilprt db cr,lf,'Osborne Smartmodem',cr,lf db cr,lf,'Be sure the serial RS232' db cr,lf,'is set at 300 baud',cr,lf db cr,lf,' (hit any key)',cr,lf,lf,0 jmp time0 db 'adjust the osborne banner display time with' db 'the byte following the <06>, (mimimum of 01)-->' time0 mvi b,2 call time1 ENDIF ; osborne MVI A,' ' STA FCB3+1 CALL START1 Š START1: CALL INITDR ; INITIALIZE ADDRESSES MVI A,TRUE ; 0FFH STA NFLFLG CMA ; 0 STA SAVFLG CALL PROCOPT ; PROCESS CONTROL OPTIONS LDA OPTION ; GET MAIN OPTION CPI 'X' ; EXPERT FLAG? JNZ RESTAR ; NO MVI A,TRUE ; YES STA XPRFLG ; MAKE EXPERT JMP MENU RESTAR: LDA OPTION ; GET MAIN OPTION CPI ' ' ; NO OPTION SPEC'D? JZ MENU CPI 'M' ; MENU ASKED FOR? JZ MENU ; YES, GO MENU CALL MOVEFCB MVI A,FALSE STA NFLFLG CALL INDATP ; GOBBLE UP GARBAGE.. CALL INDATP ; ..CHARACTERS ON LINE LDA OPTION ; PROCESS MAIN OPTION CPI 'C' JZ DIALPL 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 DNTCB ; YES, DISCONNECT & GO MENU CPI 'K' ; KILL FILE? JZ KILFIL ; YES, KILL FILE ON DISK JMP MENU ; NO OPTION SPEC'D, GO MENU ; REVISED TERMINAL ROUTINE ALLOWING MEMORY SAVE DSKSAVE:LDA NFLFLG ; 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 NFLFLG CMA STA SAVFLG JMP TERM GOODNM: CALL ILPRT DB CR,LF,'++ IS INCOMING FILE OBJECT CODE? >>',0 LXI D,CMDBUF CALL INBUFF CALL CRLF LDA CMDBUF+2 CPI NO JZ GODNM2 CPI YES JZ GODNM1 CALL ILPRT DB CR,LF,'++ ANSWER YES OR NO ONLY PLEASE! ++',CR,LF,0 JMP GOODNM GODNM1: MVI A,0FFH STA MACFLG ; SET CODE FLAG ON GODNM2: CALL ERASFIL CALL MOVE2 LXI D,FCB3 MVI C,MAKE CALL BDOS LXI D,FCB3 MVI C,OPEN CALL BDOS LXI H,BOTRAM SHLD HLSAVE MVI A,FALSE STA NFLFLG TERM: CALL STAT ; KEYPRESS? JZ TERML ; NO, CHECK LINE CALL KEYIN ; GET CHAR FROM KBD CPI ECOTOG ; ^E? JNZ TERM10 CALL ILPRT DB CR,LF,'++ ECHO ON ++',CR,LF,0 JMP TRMECHO ; YES, GO ECHO MODE TERM10: IF NOT ALTEXIT CPI OFFLIN ; ^O? Š ELSE CPI ALTCHR ; ASCII ESCAPE ENDIF JZ MENU ; YES, RETURN TO MENU cpi dialchr ; re-dial character? jz redial ; yes, do it CPI DISCCHR ; ^D? JZ DNTCB ; YES, DISCONNECT & RETURN TO MENU LST: CPI PRINTR ; esc? JNZ TERCON ; NO OUTPUT TO LIST DEV...CONT. LDA LSTFLG ; GET LIST DEV.TOGGLE CMA ; MAKE TOGGLE STA LSTFLG ; SAVE IT INR A JNZ LST1 CALL ILPRT DB CR,LF,'++ PRINTER ON ++',CR,LF,0 JMP TERM LST1: CALL ILPRT DB CR,LF,'++ PRINTER OFF ++',CR,LF,0 JMP TERM TERCON: CPI TRANCHR ; ^T TEST FOR TRANSFER REQUEST CZ TRANSFER ; SEND-A-FILE (BLIND SEND) JZ TERM ; LOOP CPI SAVECHR ; ^R TEST FOR RECEIVE REQUEST JNZ NOTOG ; NO, CONT. LDA NFLFLG ; YES BUT, DO NOT ALLOW SAVE IF.. CPI TRUE ; ..THIS FLAG IS SET. JZ TERML LDA SAVFLG ; SAVE DATA TO DISK? CMA ; MAKE TOGGLE STA SAVFLG ; SAVE IT INR A JNZ PRR1 CALL ILPRT DB CR,LF,'++ RECEIVE ON ++',CR,LF,0 JMP TERML PRR1: CALL ILPRT DB CR,LF,'++ RECEIVE OFF ++',CR,LF,0 JMP TERML redial lda contflg ; any change allowed ?? ora a Š jnz terml ; no, must be 'CONNECT' or error lda dialflg ; toggle the flag ora a jz dsdial ebldial xra a sta dialflg call ilprt db CR,LF,'++ RE-DIAL DISABLED ++',cr,lf,0 jmp terml dsdial dcr a ; 00-> FF sta dialflg sta pswtmp ; flag initial re-dial call ilprt db CR,LF,'++ RE-DIAL ENABLED ++',cr,lf db 'Enter delay 0-9 (0~3 Min) ? ... ',0 getdly mvi c,1 ; console input (dont know the 'equ' and too call bdos ; too lazy to look for it ani 7Fh cpi '0' ; > '0' jc getdly cpi '9'+1 ; < '9' +1 jnc getdly push psw call ilprt db ' ... ok',cr,lf,0 pop psw cmc ani 00001111B push psw add a ; 2x add a ; 4x add a ; 8x mov b,a ; save 8x add a ; 16x add b ; 16x+8x=24x mov b,a ; save 24x pop psw ; 1x add b ; +1x+24x=25x ora a jnz nonzro mvi a,1 ; fix for zero nonzro sta dlydia ; delay constant 1-255 (0-3 minutes @ 5.6 Mhz) mvi a,cr ; give the modem something to abort dial call otdatp onemor lxi b,1250*40 ; 4 seconds or so should do it waitn call timerl ; get a character or timeout jz dodial ; timed out, the modem is in command mode jmp onemor ; wait for time out Šdodial call ilprt db CR,LF,'NO CARRIER ' db cr,lf,'(any key to abort timeout)',cr,lf,0 lda dlydia ; delay constant mov b,a call time1 call indatp ; gobble garbage in both buffers call indatp jmp dialp1 ; and do a dial ; universal delay sets zero on timeout, carry if aborted ; seconds in , crushed unless abort, then =char typed time1 push b ; save existing push h ; and time1y mvi c,3 ; for a 1 sec delay time1x lxi h,0FFFFh ; trim here time2 dcx h mov a,h ora l jnz time2 push psw push b mvi c,11 ; key press call 0005 ; abort ?? ora a jnz timeabt pop b pop psw dcr c ; set up for 'c'th pass jnz time1x ; do it if not zero ; 1 sec has passed dcr b ; seconds jnz time1y ; again ? pop h ; nope, exit pop b stc ; be sure it is off cmc ret ; ; keypress abort time loop ; timeabt mvi c,1 ; clear the port call bdos ani 7Fh Š stc ; flag abort pop b ; fix stack... pop b ; ... ditto pop h ; restore pop b ; and ret ; exit NOTOG: CALL OTDATP TERML: CALL INCTLP CALL ANRCVB CALL CPRCVR JNZ TERM CALL INDATP PUSH PSW ; SAVE ORG.CHAR. LDA MACFLG ; GET MACHINE LANG.FLAG INR A ; MACHINE LANG.COMING THROUGH? JZ TERML9 ; YES...SKIP FILTER POP PSW ; SAVE ORIG.CHAR CPI 00H ; CHECK FOR NULLS JZ TERM ; DON'T PROCESS THEM ANI 7FH ; STRIP PARITY PUSH PSW ; SAVE FILTERED CHAR. ; ; The following code in lower case is responsible for ; the re-dial. Don't bother with the 'non-verbose' ; mode as it is a LOT of grief. Just grab the ascii ; and parse it for 'o carrier'. Abort on all else. lda contflg ; reedial allowed?? ora a jnz terml9 ; not allowed, quit lda dialflg ; re-dial flag set ? ora a jz terml9 ; no, quit pop psw ; look for the 1st ascii char only push psw cpi 'N' ; was it a 'NO CARRIER' ? jz doadial ; if so, do a redial cpi 'C' ; or a 'CONNECT' ? jz killdl ; kill the redial pending cpi 'O' ; or an 'OK' ?? (what) jz killdl cpi 'E' ; or an 'ERROR' jz killdl jmp terml9 ; none of these, echo it and get another Š killdl xra a sta dialflg ; clear the re-dial flag dcr a ; set the no redial not allowed flag sta contflg jmp terml9 doadial pop psw ; fix stack mvi a,0FFh sta dialflg ; reset the re-dial flag call ilprt db cr,lf,'NO CARRIER ',cr,lf,0 ; give the exchange time to get its act together lda dlydia ; delay constant mov b,a call time1 jnc nokill mvi a,cr ; give the modem a cr call otdatp nokill call indatp ; gobble, gobble call indatp jmp dialp1 ; redial TERML9: POP PSW ; SAVE FILTERED OR ORG.CHAR. PUSH PSW ; SAVE IT AGAIN CALL TYPE LDA LSTFLG INR A JNZ PUSHON POP PSW CALL LISTDV JMP TERM PUSHON: LDA SAVFLG ; save mode INR A JNZ NOSAVE ; no, skip the memory write POP PSW lhld hlsave ; 8-13/82 fix ^R crushing smodem3.com MOV M,A INX H SHLD HLSAVE ; MENU COMMAND DESTROYS HL-REG.. ; ..GET HL WHEN ENTERING VIA 'RET' CMD. CPI LF ; IF NO FRONT PANEL, THEN.. JNZ NOCOLON ; ..TYPE ":" AFTER EACH LINE FEED.. MVI A,':' ; ..WHEN MEMORY SAVE ACTIVE. CALL TYPE NOCOLON:LDA 07H ; CHECK TO SEE IF.. DCR A ; ..PAGE BELOW BDOS HAS BEEN.. CMP H ; ..REACHED AND DISKSAVE IS NEEDED. CZ INTDSSV Š JMP TERM NOSAVE: POP PSW JMP TERM SAVFLG: DB FALSE LSTBY1: DB 0 LSTBY2: DB 0 INTDSSV:MVI A,XOFF ; SEND A CTRL-S TO STOP.. CALL OTDATP ; ..REMOTE COMPUTER OUTPUT. MVI D,0 ; D IS THE BUFFER COUNT CALL INMODEM ; GET LAST BYTES SENT.. STA LSTBY1 ; ..AFTER CTRL-S. CALL INMODEM ; ADD MORE CALLS TO INMODEM.. STA LSTBY2 ; ..AND STA LASTBYT# IF YOU ARE.. ; ..LOSING BYTES WHEN MEMORY IS FULL. PUSH D CALL NMREC1 CALL WRTDSK ; WRITE THE RECORDS POP D LXI H,BOTRAM INR D DCR D ; TEST BUFFER COUNT FOR ZERO JZ CTRLQ LDA LSTBY1 ; GET THE LAST BYTES THAT WERE.. MOV M,A ; ..SAVED AND PUT THEM IN.. INX H ;..BOTRAM. CALL TYPE DCR D JZ CTRLQ LDA LSTBY2 MOV M,A INX H CALL TYPE CTRLQ: MVI A,XON ; SEND START CHARACTER.. CALL OTDATP ; ..TO REMOTE COMPUTER. RET ; ; 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 "INTDSSV" ; ABOVE). ; INMODEM:LXI B,1250 TIMERL: CALL INCTLP CALL ANRCVB CALL CPRCVR Š JZ GETBYTE DCX B MOV A,B ORA C JNZ TIMERL RET GETBYTE:CALL INDATP INR D RET NMRECS:MVI M,EOFCHAR INX H LXI D,127 DAD D NMREC1:LXI D,-(BOTRAM) 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 ; RETRNS WITH NUMBER OF.. RET ; ..128 BYTE RECORDS IN HL. WRTDSK: LXI D,BOTRAM 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 INITFCB 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 INITFCB ; INITIALIZES FCBS POINTED.. LXI H,FCB+16 ;..TO BY HL REG. CALL INITFCB GET: CALL GETNAME LDA CMDBUF+2 ; WAS FILE ENTERED CPI 20H JZ TRNSL2 CALL MOVE4 CALL OPEN4 CPI 0FFH ; RETURN WITH 0FFH MEANS JNZ CONTIN ; FILE DOES NOT EXIST TRNSL1:CALL ILPRT DB CR,LF,'++ FILE DOES NOT EXIST ++',CR,LF,0 TRNSL2:CALL ILPRT DB ' ...TYPE ''R'' TO RETURN TO MODEM ++',CR,LF DB ' ...TYPE ''A'' TO RE-ENTER NAME ',CR,LF DB ' COMMAND >>',BELL,0 CALL KEYIN CALL UCASE Š CALL TYPE ; ECHO RESPONSE CALL CRLF CPI 'A' JZ GET CPI 'R' JZ RETURN JMP TRNSL2 CONTIN: LXI D,80H MVI C,STDMA CALL BDOS READMR: CALL READ80 CPI 1 ; END OF FILE JZ RETRNS CPI 2 ; BAD READ JZ RETRNU CALL SEND80C CPI EOFCHAR ; END OF FILE - OMIT IF OBJECT.. JZ RETRNS ; ..CODE IS TO BE SENT. CPI CAN ;CANCELLATION? JZ TRANCAN JMP READMR RETRNS:CALL ILPRT DB CR,LF,'++ FILE TRANSFER COMPLETED ++',CR,LF,BELL,0 JMP RETURN RETRNU:CALL ILPRT DB CR,LF,'++ FILE TRANSFER UNSUCCESSFUL ++',CR,LF,BELL,0 JMP RETURN TRANCAN:CALL ILPRT DB CR,LF,'++ TRANSFER CANCELLED ++',CR,LF,BELL,0 RETURN: XRA A STA MACFLG POP PSW POP B POP D POP H RET ; ENTRY AT +2 WILL LEAVE.. INITFCB: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,'++ IS OUTGOING FILE OBJECT CODE? >>',0 LXI D,CMDBUF CALL INBUFF CALL CRLF LDA CMDBUF+2 CPI NO JZ GTNAM2 CPI YES JZ GTNAM1 CALL ILPRT DB CR,LF,'ANSWER YES OR NO ONLY PLEASE!',CR,LF,0 JMP GETNAME GTNAM1: MVI A,0FFH STA MACFLG ; SET CODE FLAG ON GTNAM2: CALL ILPRT DB CR,LF,'++ ENTER FILE NAME TO BE TRANSFERRED...C/R TO QUIT ++ ',CR,LF DB ' COMMAND >>',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:PUSH B PUSH D PUSH H Š CALL INDATP CPI XOFF JNZ SNDCH9 TWO: CALL STAT JZ THREE CALL KEYIN CPI CAN JZ SNDCH9 THREE: CALL INDATP CPI XON JNZ TWO SNDCH9: POP H POP D POP B CPI CAN RZ MOV A,M CALL MODOUT PUSH PSW LDA MACFLG INR A JZ SNDC1 POP PSW CPI EOFCHAR RZ PUSH PSW SNDC1: POP PSW ; RESTORE STACK 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 MODOTL: CALL OTCTLP CALL ANSNDB CALL CPSNDR JNZ MODOTL POP PSW CALL OTDATP CALL TYPE Š RET FCB4: DS 33 ; TERMINAL ECHO MODE TRMECHO:CALL INCTLP CALL ANRCVB CALL CPRCVR JNZ KEYBRD LINECHR:CALL INDATP LINEC2: CALL MODOUT PUSH PSW LDA LSTFLG INR A JNZ KYCONT POP PSW CALL LISTDV PUSH PSW KYCONT: POP PSW CPI CR JNZ TRMECHO MVI A,LF JMP LINEC2 KEYBRD: CALL STAT JZ TRMECHO CALL KEYIN CPI ECOTOG JNZ KEYBR3 CALL ILPRT DB CR,LF,'++ ECHO OFF ++',CR,LF,0 JMP TERM KEYBR3: IF NOT ALTEXIT CPI OFFLIN ELSE CPI ALTCHR ENDIF JZ MENU CPI DISCCHR JZ DNTCB CPI PRINTR ; ^P? JNZ KEYBR2 ; NO OUTPUT TO LIST DEV...CONT. Š LDA LSTFLG ; GET LIST DEV.TOGGLE CMA ; MAKE TOGGLE STA LSTFLG ; SAVE IT JMP TRMECHO KEYBR2: CALL MODOUT CPI CR JNZ TRMECHO MVI A,LF JMP KEYBR2 ;RESET DISKS ROUTINE NEWDSK: PUSH PSW PUSH B PUSH D PUSH H MVI C,RCDSK CALL BDOS STA SCDSK MVI C,RESET ;RESET THE DISKS CALL BDOS LDA SCDSK ;GET BACK ORIGINAL LOGGED DISK MOV E,A MVI C,SELDSK ;...LOG IT IN AGAIN CALL BDOS POP H POP D POP B POP PSW RET ;LOG DRIVE ROUTINE LOGON: LDA CMDBUF+6 ;GET DRIVE CPI ' ' ;NO DRIVE SPECIFIED JZ XPRT9 ;THEN LEAVE SUI 41H ;MAKE DRIVE # MOV E,A MVI C,SELDSK ;AND LOG IT CALL BDOS JMP XPRT9 ; ERASE A FILE FROM DISK KILFIL: LDA FCB+1 CPI ' ' JZ BLKFILE LXI D,FCB MVI C,SRCHF CALL BDOS INR A JNZ KILFL2 CALL ILPRT DB CR,LF,'++ FILE DOES NOT EXIST ++',CR,LF,0 JMP XPRT KILFL2: LXI D,FCB MVI C,ERASE Š CALL BDOS JMP XPRT ; SEND A CP/M FILE SENDFIL: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 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 ; CRC REQUEST? ORA A CZ SNDCRC ; YES...SEND CRC CHECKS CNZ SENDCKS ; NO...SEND CHECKSUMS CALL GETACK JC SENDRPT JMP SENDLP SENDEOF:MVI A,EOT CALL SEND CALL GETACK JC SENDEOF JMP DONE ; RECEIVE A FILE RCVFIL: 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 QFLG ORA A JZ RCVFST LDA BATCHFLG ORA A ; DON'T PRINT MSSG IF.. JZ RCVFST ; ...IN MULTI AND QUIET MODE. CALL ILPRT DB CR,LF,'++ FILE OPEN, READY TO RECEIVE ++',CR,LF,0 RCVFST: LDA CRCFLG ORA A MVI A,NAK JNZ RCVFL2 MVI A,CRC RCVFL2: CALL SEND 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 CR,LF,'++ 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 SNDNM1: 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 SKCSR1 CALL ILPRT DB CR,LF,'++ CHECKSUM ERROR ++',CR,LF,0 SKCSR1:MVI E,80 ; DO HANDSHAKING OVER CALL WAITNLP ; DON'T PRINT "AWAITING NAK" MSG MVI A,ACK CALL SEND JMP SNDNM1 NAMEOK: MVI A,OKNMCH ; GOOD NAME-TELL RECEIVER CALL SEND POP H RET GETFN: LXI H,FCB CALL INITFCB+2 ; DOES NOT INITIALIZE DRIVE LDA QFLG ORA A JZ GNAMELP CALL ILPRT DB CR,LF,'++ 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 NMRNMG ORA A ; CLEAR CARRY RET NMRNMG: 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 CR,LF,'++ 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 INITFCB+2 ; ..SINCE IT MIGHT BE DAMAGED.. LDA QFLG ; ..BY TOO MANY CHARS. ORA A JZ GCKSR1 CALL ILPRT DB CR,LF,'++ CHECKSUM ERROR ++',CR,LF,0 GCKSR1:CALL HSNAK ; DO HANDSHAKING OVER JC GCKSR1 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 CAN ; IF SENDER ABORTS.. JZ ABORT ; ..DURING NAME TRANSFER. CPI ACK ; IF NAK,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 SCNLP1: INX H DCR B JZ DNSCAN MOV A,M CPI 20H JNZ SCNLP1 SCNLP2: INX H ; EAT EXTRA SPACES DCR B JZ DNSCAN MOV A,M CPI 20H JZ SCNLP2 SHLD BGNMS ; SAVE START OF NAMES IN CMDBUF INR B DCX H SCNLP3: INX H DCR B JZ DNSCAN MOV A,M CPI 20H JNZ SCNLP3 LDA NAMECT ; COUNTS NAMES INR A STA NAMECT SCNLP4: INX H ; EAT SPACES DCR B JZ DNSCAN MOV A,M CPI 20H JZ SCNLP4 JMP SCNLP3 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 MOV A,L ; TRANSFER VERSION # W.B. 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 BKBYTE ORA A RZ MVI C,SRCHF LXI D,FCB CALL BDOS INR A RZ ; FILE NOT FOUND JMP PLANCHG ; IN "CKCPM2" - RET DONE THERE ; ;------------------------------------------------------------------------------ ; MFACCESS MACRO ROUTINES ; ; MFFLG1 IS NOT SET LOCAL BECAUSE IT MUST BE RESET Š; IN MAIN MODEM PROGRAM ON AN ABORT ; ; MULTI-FILE ACCESS SUBROUTINE. ALLOWS PROCESSING ; OF MULTIPLE FILES (I.E. *.ASM) FROM DISK. THIS ; ROUTINE BUILDS THE PROPER NAME IN THE FCB EACH ; TIME IT IS CALLED. THIS COMMAND WOULD BE USED ; IN SUCH PROGRAMS AS MODEM TRANSFER, TAPE SAVE, ; ETC IN WHICH YOU WANT TO PROCESS SINGLE OR ; MULTIPLE FILES. ; ; THE FCB WILL BE SET UP WITH THE NEXT NAME, READY TO ; DO NORMAL PROCESSING (OPEN, READ, ETC.) WHEN ROUTINE IS CALLED. ; ; CARRY IS SET IF NO MORE NAMES CAN BE FOUND ; DEFINE DATA MOVE MACRO MOV1 MACRO ?F,?T,?L,?I IF NOT NUL ?F LXI H,?F ENDIF IF NOT NUL ?T LXI D,?T ENDIF IF NOT NUL ?L LXI B,?L ENDIF IF NOT NUL ?I LOCAL ?N,?Z CALL ?Z ?N: DB ?I ?Z: POP H ; GET TO LXI B,?Z-?N ENDIF CALL MOVER MF SET -1 ;; SHOW EXPANSION ENDM ; DEFINE CP/M MACRO - CPM FNC,PARM CPM MACRO ?F,?P PUSH B PUSH D PUSH H IF NOT NUL ?F MVI C,?F Š ENDIF IF NOT NUL ?P LXI D,?P ENDIF CALL BDOS POP H POP D POP B ENDM ; ;--------------------------------------------------- ; MULTI-FILE ACCESS SUBROUTINE ; ; THE ROUTINE IS COMMENTED IN PSEUDO CODE, ; EACH PSEUDO CODE STATEMENT IS IN ;<<...>> ; MFNAME EQU $ ;; <> CPM STDMA,80H XRA A STA FCBEXT ; <> LDA MFFLG1 ORA A JNZ MFN01 ; <> MVI A,1 STA MFFLG1 ; <> MOV1 FCB,MFREQ,12 ; SAVE ORIG REQ LDA FCB STA MFCUR ; SAVE DISK IN CURR FCB ; <> MOV1 MFREQ,FCB,12 CPM SRCHF,FCB ; <> Š JMP MFN02 MFN01 EQU $ ; <> MOV1 MFCUR,FCB,12 CPM SRCHF,FCB ; <> MOV1 MFREQ,FCB,12 CPM SRCHN,FCB ; <> MFN02 EQU $ ; <> INR A STC JNZ MFFIX1 STA MFFLG1 RET ;FIX BY M.Z. MFFIX1 EQU $ ; <> DCR A ANI 3 ADD A ADD A ADD A ADD A ADD A ADI 81H MOV L,A MVI H,0 PUSH H ; SAVE NAME POINTER MOV1 ,MFCUR+1,11 ; <> POP H MOV1 ,FCB+1,11 ; <> Š XRA A STA FCBEXT STA FCBRNO ;FIX BY M.Z. ; <> RET ; MULTI-FILE ACCESS WORK AREA MFFLG1: DB 0 ;1ST TIME SW MFREQ: DS 12 ;REQ NAME MFCUR: DS 12 ;CURR NAME ;------------------------------------------------ ; MOVE SUBROUTINE MOVER: MOV A,M STAX D INX H INX D DCX B MOV A,B ORA C JNZ MOVER RET ; END OF MFACCESS ROUTINES ;-------------------------------------------------------------- RCVSECT:XRA A STA ERRCT RCVRPT: XRA A ; FOR ERROR CHECK RS232 STA ERRCDE LDA QFLG ORA A JZ RCVSQ CALL ILPRT DB ' AWAITING SECTOR...',0 PUSH H LHLD SECTNO INX H CALL DECOUT CALL ILPRT DB ' (',0 CALL DHXOUT CALL ILPRT DB 'H)',CR,0 Š MOV A,L POP H RCVSQ: MVI B,10 ; 10 IN ORIG PROG CALL RECV JC RCVSTOT IF CHEK CALL RCVERR ; FOR ERROR CHECK RS232 JC RCVDER ENDIF ; CHEK CPI CAN ; CHECK FOR CANCEL.. JZ ABORT ; ..REQUEST FROM SENDER. 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: CALL CRLF MOV A,B CALL HEXO CALL ILPRT DB 'H RECEIVED, NOT (SOH) ++',CR,LF,0 RCVSERR:MVI B,1 CALL RECV JNC RCVSERR LDA CRCFLG ; WB...REPEAT CRC REQUEST ORA A ; IN CASE SENDER WAS SLOW IN MVI A,NAK ; GETTING STARTED. JNZ RCVS1 MVI A,CRC RCVS1: 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 this routine returns with ; carry flag set. IF CHEK RCVERR: PUSH PSW ; SAVE CHAR TRANSMITTED LDA ERRCDE ; GET RECEIVE ERROR CODE ANA A ; IS IT ZERO? JZ RCVER2 ; YES, NO RECEIVE ERROR POP PSW ; RESTORE CHAR TRANSMITTED STC ; SET CARRY ON TO INDICATE AN ERROR RET RCVER2: POP PSW ; RESTORE CHAR TRANSMITTED RET ; RCVDER: Checks for a receive error and displays appropriate ; error message. Then goes to RCVSERR to purge the line and ; send a NAK. RCVDER: LDA VSEEFLG ; VIEWING Š ORA A ; ...MODE? JZ RCVDEP ; YES,..PRT MSG LDA QFLG ; QUIET... ORA A ; ...MODE? JZ RCVSERR ; YES, NO MSG RCVDEP: CALL ILPRT DB CR,LF,0 LDA ERRCDE ; GET RECEIVE ERR CODE ANI FRMER ; WAS THERE A FRAMING ERROR? JZ RCVDE2 ; NO, GO CHECK FOR OVERRUN CALL ILPRT DB '++ FRAMING ERROR...',0 CALL RCVDE5 ; PRINT # OF ERROR RCVDE2: LDA ERRCDE ; GET RECEIVE ERR CODE ANI ORUNER ; WAS THERE AN OVERRUN JZ RCVDE3 ; NO, GO CHECK FOR PARITY ERROR CALL ILPRT DB LF,'++ OVERRUN ERROR...',0 CALL RCVDE5 RCVDE3: LDA ERRCDE ; GET RECEIVE ERR CODE ANI PARER ; WAS THERE A PARITY ERROR? JZ RCVDE4 ; NO, GO PURGE LINE CALL ILPRT DB LF,'++ PARITY ERROR...',0 CALL RCVDE5 RCVDE4: JMP RCVSERR ; GO PURGE LINE, SEND NAK ; Display number of error, do a carriage return and line feed. RCVDE5: LDA ERRCT ; GET ERROR NUMBER CALL HEXO ; DISPLAY IT CALL CRLF ; DO CR, LF RET ENDIF ; CHEK RCVSOH: MVI B,1 CALL RECV JC RCVSTOT IF CHEK CALL RCVERR ; RS232 ERROR CHECK JC RCVDER ENDIF ; CHEK Š MOV D,A MVI B,1 CALL RECV JC RCVSTOT IF CHEK CALL RCVERR ; RS232 ERROR CHECK JC RCVDER ENDIF ; CHEK 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 NUMBER IN HEADER ++',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 IF CHEK CALL RCVERR ; RS232 ERROR CHECK JC RCVDER ENDIF ; CHEK 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 Š IF CHEK CALL RCVERR ; RS232 ERROR CHECK JC RCVDER ENDIF ; CHEK CMP D JNZ RCVCERR CHKSNM: LDA RCVSNO MOV B,A LDA SECTNO CMP B JZ RECVACK INR A CMP B JNZ ABORT RET RCVCRC: MVI E,2 ; NUMBER OF CRC BYTES RCVCR2: MVI B,1 CALL RECV JC RCVSTOT IF CHEK CALL RCVERR ; RS232 ERROR CHECK JC RCVDER ENDIF ; CHEK DCR E JNZ RCVCR2 CALL CHKCRC ORA A JZ CHKSNM 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 CR,LF,'++ CHECKSUM 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 ' SENDING SECTOR...',0 PUSH H LHLD SECTNO CALL DECOUT CALL ILPRT DB ' (0',0 CALL DHXOUT CALL ILPRT DB 'H)',CR,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 SNDCRC: CALL FINCRC MOV A,D CALL SEND MOV A,E CALL SEND XRA A RET GETACK: MVI B,10 CALL RECVDG JC GETATOT CPI ACK RZ MOV B,A ANI 7FH CPI CAN JZ ABORT LDA QFLG ORA A JZ ACKERR CALL CRLF MOV A,B CALL HEXO CALL ILPRT DB 'H RECEIVED...NOT (ACK) ++',CR,LF,0 ACKERR: LDA ERRCT INR A STA ERRCT CPI ERRLIM RC ; REACHED ERROR LIMIT 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: 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,0 MVI A,'B' ; TURN MULTI-FILE MODE.. STA BATCHFLG ; ..OFF SO ROUTINE ENDS. JMP DNTCE INCRSNO:PUSH H LHLD SECTNO INX H SHLD SECTNO 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 CR,LF,'++ FILES 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 LXI B,0FFFFH DELAY: DCX B MOV A,B ORA C JNZ DELAY JMP MENU MAKEFIL:LXI D,FCB MVI C,MAKE CALL BDOS INR A RNZ CALL ERXIT DB CR,LF,'++ CAN''T MAKE FILE...DIRECTORY FULL ++',CR,LF,'$' IF CPM2 CNREC: MVI C,FILSIZ ; COMPUTE FILE SIZE FUNC 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 ; CPM2 IF NOT CPM2 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 CR,LF,'++ FILE NOT FOUND ++',CR,LF,'$' ; 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 ; NOT CPM2 Š OPENFIL:LXI D,FCB MVI C,OPEN CALL BDOS INR A JNZ OPENOK CALL ERXIT DB CR,LF,'++ CAN''T OPEN FILE...NOT FOUND ON DISK ++',CR,LF,'$' OPENOK: LDA BATCHFLG ORA A JNZ OPNOK1 LDA QFLG ORA A RZ OPNOK1:CALL ILPRT DB CR,LF,'++ FILE OPEN...SIZE: ',0 LHLD RCNT ; RECORD COUNT CALL DECOUT ; PRINT SECTORS IN DECIMAL CALL ILPRT 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 CR,LF,'++ CAN''T CLOSE FILE...NOT FOUND ON DISK ++',CR,LF,'$' 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 CR,LF,'++ READ ERROR...END OF FILE ++',CR,LF,'$' RDSECOK:LXI H,80H DAD D XCHG INR C MOV A,C CPI DBFSIZ*8 ; BUFFER 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 DBFSIZ*8 ; BUFFER 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 CR,LF,'++ WRITE ERROR...DISK FULL ++',CR,LF,'$' RECVDG EQU $ CALL INDATP CALL INDATP RECV: PUSH D LDA FASCLK ; DOUBLE UP THE LOOP COUNTER IF ORA A ; 4 MZ OR GREATER JZ MSEC MOV A,B ADD A MOV B,A MSEC: LXI D,15000 ; 60% OF ORIG 50000 CALL CKABORT MWTI: CALL INCTLP CALL ANRCVB CALL CPRCVR JZ MCHAR Š DCR E JNZ MWTI DCR D JNZ MWTI DCR B JNZ MSEC POP D STC RET IF CHEK MCHAR: CALL INDATP ANI ERRMSK STA ERRCDE ELSE MCHAR: CALL INDATP ENDIF ; CHEK POP D PUSH PSW CALL UPDCRC ; CALCULATE 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 ; CALCULATE CRC ADD C MOV C,A SENDW: CALL OTCTLP CALL ANSNDB CALL CPSNDR JNZ SENDW POP PSW CALL OTDATP RET WAITNAK:LDA VSEEFLG ORA A JZ WAITNPR LDA QFLG ORA A JZ WAITNLP WAITNPR:CALL ILPRT DB CR,LF,'++ AWAITING INITIAL (NAK) ++',CR,LF,0 WAITNLP:CALL CKABORT MVI B,1 CALL RECV CPI NAK RZ CPI CRC JZ WAITCRC DCR E JZ ABORT JMP WAITNLP WAITCRC:CALL ILPRT DB CR,LF,'++ (CRC) REQUEST RECEIVED ++',CR,LF,BELL,0 XRA A STA CRCFLG RET INITDR: LHLD 1 LXI D,3 DAD D SHLD VSTAT+1 DAD D SHLD VKEYIN+1 DAD D SHLD VTYPE+1 DAD D SHLD VLISTD+1 Š IF INLZE ; ENTER WHATEVER OTHER MVI A,INITC1 ; INIT. ROUTINES ARE REQUIRED OUT MOCTLP MVI A,INITC2 OUT MOCTLP MVI A,INITC3 OUT MOCTLP ENDIF ; INLZE IF SWITCH CALL SETDFLT ENDIF ;SWITCH 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 ENDOP2 LDA OPTION CPI 'R' JNZ BADOPT ; CRC ONLY ALLOWED IN RECEIVE MODE ENDOP2: LDA VSEEFLG ORA A RNZ STA QFLG RET DONE: LDA BATCHFLG ORA A JNZ DNTCC 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,0 ; 13 SPACES NMSTRNS:LDA FCB ; SAVE DRIVE NO. STA DISKNO LXI H,FCB ; BLANK OUT FILE CONTROL BLOCKS CALL INITFCB LDA DISKNO ; PUT DRIVE NUMBER BACK STA FCB LXI H,RESTSN ; RESTORE SECTORE NUMBERS.. LXI D,SECTNB ; ..FOR NEW FILE TRANSFER. MVI B,SECTNE-SECTNB ; 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. DNTCC: MVI A,TRUE ; INDICATE NO FILES BEING.. STA FSTFLG ; RESET MULTIFILE TRANS STA NFLFLG ; ..USED IN TERMINAL ROUTINE. CMA STA SAVFLG ; STOP MEM.SAVE IN TERM ROUTINE. LDA VSEEFLG ORA A JZ DONETC LDA QFLG ORA A JZ DNTCA DONETC: CALL ILPRT DB CR,LF,'++ ALL TRANSFERS COMPLETED ++',CR,LF,BELL,BELL,BELL,0 DNTCA: LDA DISCFLG ; see if disconnect when thru ORA A JNZ DNTCE ; no, don't disconnect DNTCB: LXI D,80H MVI C,STDMA CALL BDOS CALL TIMER CALL TIMER CALL TIMER CALL TIMER CALL TIMER CALL TIMER Š CALL TIMER LXI D,OFFHK CALL OFF1 JMP OFF5 OFF1: LDAX D CPI '$' JZ OFF2 CALL MODOUT INX D JMP OFF1 OFF2: MVI B,15 OFF3: CALL TIMER DCR B JNZ OFF3 INX D OFF4: LDAX D CPI '$' RZ CALL MODOUT INX D JMP OFF4 OFF5: CALL TIMER CALL INDATP CALL TIMER CALL ILPRT DB '++ DISCONNECTED ++',CR,LF,0 JMP menu ; used to be TERM DNTCE: LDA TERMFLG ; SEE IF RETURN TO.. ORA A ; ..TERMINAL MODE.. JZ TERM LDA ECHOFLG ORA A JNZ MENU ; ..AFTER X'FER. JMP TRMECHO 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 LISTDV: PUSH B PUSH D PUSH H MOV C,A VLISTD: CALL $-$ POP H POP D POP B RET 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 DECOT2: DAD B INX D JC DECOT2 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: PUSH H PUSH PSW MOV A,H Š CALL HEXO MOV A,L CALL HEXO 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 ; RETRNS 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 CR,LF,'++ MULTIPLE ERRORS ENCOUNTERED',CR,LF DB ' ...TYPE ''Q'' TO QUIT',CR,LF DB ' ...TYPE ''R'' TO RETRY',CR,LF DB ' COMMAND >>',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 DNTCE MVI A,'Q' ; RESET QFLG STA QFLG JMP ABORT ; ABORT OTHER COMPUTER EXIT: LXI D,80H MVI C,STDMA CALL BDOS JMP 0 MOVE128:MVI B,80H MOVE: MOV A,M STAX D INX H INX D DCR B JNZ MOVE RET ; DIALING ROUTINE MODIFIED FOR HAYES SMART MODEM DIALPL xra a ; allow a re-dial, a new call sta contflg LXI H,CMDBUF+1 ; POINT # OF CHARS IN BUFF MOV A,M ; GET # OF CHARS CPI 4 ; 4 OR MORE CHARS BEFORE ? JC ENTNM ; NO, ASK FOR NUMBER LXI H,CMDBUF+5 ; POINT TO NUMBER TO DIAL JMP DIAL10 ; CHECK IF LIB #, & DIAL ; this is all the set-up for the print at entnm2. ENTNM: CALL ILPRT DB FF DB ' *** PHONE DIRECTORY ***',CR,LF DB '===============================================================',CR,LF,0 Š mvi c,26 ; number of lines to move lxi h,numblib ; address of source memory lxi d,dbuf ; address of target memory stax d ; +LF inx d ; and bump it ENTNM1: mvi b,30 ; number of bytes to move call move ; move to buffer call spaces ; 2 entries + 3 spaces=63 chars. mvi b,30 call move call newline dcr c ; number of lines to print jz entnm2 jmp entnm1 ; puts CR-LF at memory pointed by DE NEWLINE: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 ENTNM2: mvi a,'$' stax d mvi c,print lxi d,dbuf ; point to table of numbers to print call bdos call crlf CALL ILPRT DB CR,'++ ENTER NUMBER OR LETTER ' IF ALTLD DB CR,LF,'(~/number or letter for Alternate LD dial) ' ENDIF DB '>>',0 LXI D,CMDBUF ; get the command line CALL INBUFF DIALP1: lda dialflg ; don't capture the redial Š sta pswtmp ; don't upset stack xra a ; correct 'R' reverse ans/org mode bug sta nubrflg if altld sta altldflg sta nubr1flg sta nubr2flg endif LDA CMDBUF+1 ORA A ; NULL MEANS WAS TYPED JZ MENU ; ABORT DIALING, RETURN TO MENU ; THIS ROUTINE SENDS THE PROPER DIALING INITIATION ; COMMANDS TO THE HAYES SMARTMODEM. IT CAN BE CHANGED BY ; ALTERING THE 'STYLE' OPTION AT THE BEGINNING OF THIS PRGM. MVI A,CR CALL MODOUT ; give the modem a PUSH D LXI D,STYLE ONW1: LDAX D ; hen the 'ATDT' bs CPI '$' JZ ONW2 CALL MODOUT INX D JMP ONW1 ONW2: POP D LXI H,CMDBUF+2 ; FIRST CHAR OF DIAL LINE if altld inx h ; 2nd char of the buffer mov a,m dcx h cpi '/' ; '/' ? jnz dial10 mvi a,0FFh ; set alt LD flag active sta altldflg mov a,m ; 1st char of the buffer cpi 'M' ; MCI? jz mci cpi 'S' ; SPRINT? jz sprint jmp skip mci lxi h,mcinum ; dial the MCI number jmp sdial sprint lxi h,sprnum ; dial the SPRINT number jmp sdial Šsdial mov a,m inx h cpi '$' ; terminated ? jz nxtsdl call modout ; SEND IT jmp sdial nxtsdl call indatp ; gobble call ilprt db cr,lf,lf,0 skip: lxi h,cmdbuf+4 ; one past the '/' endif ; ENTER THIS ROUTINE WITH HL POINTING TO DIAL LINE DIAL10: MVI B,'A' ; FIRST LETTER OF ALPHABET MVI E,0 ; COUNTS NO. OF LETTERS TO MATCH MVI C,52 ; NUMBER OF LETTERS IN ALPHABET MOV A,M ; GET CHAR BUFFER DIAL11: CMP B ; NUMBER FROM TABLE? JZ LIBSET PUSH PSW ; SAVE ORIGINAL MOV A,B ; MOVE ALPHABET CHAR.TO 'A' CPI 'Z' ; END OF UPPER CASE? JNZ DL11 ; NO...CONT. ADI 6 ; YES...JUMP TO LOWER CASE CHRS. MOV B,A ; PUT BACK IN 'A' DL11: POP PSW INR B ; MAKE NEXT LETTER (A-Z) INR E ; COUNT UP DCR C ; COUNT DOWN JZ DIALPX ; 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 ADD 30 TO HL ORA A ; SET FLAGS JZ DIAL13 DIAL12: MOV A,M ; GET FIRST CHAR OF LIB ENTRY ORA A ; SET FLAGS JZ DIALP2 ; SEND BADLIB MSG DAD B ; INCREMENT HL BY 30 DCR E ; COUNTDOWN JNZ DIAL12 ; NOT THERE YET, LOOP DIAL13: MVI E,30 ; NO. OF CHAR TO GET FROM TABLE JMP DIALP2 ŠDIALPX: LDA CMDBUF+1 MOV E,A ; NUMBER OF CHARS IN BUFF LXI H,CMDBUF+2 ; POINT FIRST CHAR if altld lda altldflg ora a jz dialp2 ; not a alt LD dial dcr e ; skip the 'S/' if it is a alt LD dial dcr e inx h inx h endif DIALP2: MOV A,M ; GET FIRST # FROM BUFFER ; ROUTINE 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 MENU ; 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 ABORT ; YES, ABORT INX H ; BUMP POINTER DCR E ; COUNT DOWN CHARS IN BUFF JNZ DIALP2 ; NOT DONE, LOOP JZ DIALDN ; DIALING DONE TIMER: PUSH PSW ; TIME INTERVAL BETWEEN EACH PUSH B ; NUMBER SENT TO THE MODEM LXI B,5000H ;ORG. 3500H IF FASCK ;DOUBLE COUNTDOWN IF 4 MHZ LXI B,6A00H ENDIF TIMER2: DCX B MOV A,B ORA C JNZ TIMER2 POP B POP PSW Š RET NUBRFLG DB 0 ; SEEN A NUMBER if altld altldflg db 0 ; alt LD dial flag nubr2flg db 0 nubr1flg db 0 endif ; AUTO DIALER DIAL: CPI ',' ; ALLOW A COMMA JZ OK2SND CPI 48 JC DIA1 ; DIGIT MUST BE AT LEAST 0.. CPI 58 JNC DIA1 ; ..AND NOT MORE THAN 9 if altld mov b,a ; save it lda altldflg ora a mov a,b jz ok2snd ; not alt LD mode lda nubr1flg ; seen a number before ? ora a mov a,b jnz ok2snd ; yes, skip the rest sta nubr1flg ; set this as being the first cpi '1' ; leading ascii <1> ? jnz ok2snd ; nope, send it... jmp type ; ...else type and kill it endif ok2snd STA NUBRFLG ; hmm... set the first number flag CALL MODOUT ; NUMBERS PRINTED IN THIS ROUTINE RET DIA1: MOV B,A ; SAVE IT LDA NUBRFLG ORA A MOV A,B JZ TYPE ; NO NUMBER YET, TYPE AND EXIT HERE CPI 'R' ; 'R' FOR REVERSE ANS/ORG MODE?? JNZ TYPE ; NOPE, TYPE IT AND EXIT JMP MODOUT ; DONE, SEND IT echo and exit here DIALDN: CALL ILPRT DB CR,LF,'++ DIAL COMPLETED...NOW IN TERMINAL MODE ++',CR,LF,0 Š MVI A,CR CALL MODOUT ; COMPLETE THE DIALING CALL INDATP ; GOBBLE GARBAGE clrdial lda pswtmp ; let's see, what mode were we in? sta dialflg JMP TERM pswtmp ds 1 BADLIB: DB CR,LF,'++ BAD LIBRARY NUMBER CALLED ++',CR,LF,'$' ; 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 'C' ; RETURN IF AUTO DIALER OPTION RZ CPI 'E' ; RETURN IF ECHO OPTION RZ CPI 'M' ; RETURN TO MENU RZ CPI 'T' JZ TERMSEL CPI 'K' ; RETURN IF FILE ERASE OPTION JZ CKFILE 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 ',CR,LF DB 'COMMAND >>',BELL,0 LXI D,CMDBUF CALL INBUFF Š JMP SETFCB TERMSEL:LDA FCB+17 CPI ' ' JNZ SAVAGN MVI A,FALSE STA SAVFLG MVI A,TRUE STA NFLFLG CMA RET SAVAGN: MVI A,FALSE STA NFLFLG RET ; ; CRCSUBS (Cyclic Redundancy Code Subroutines) version 1.20 ; 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 synchr. transmission protocols XRI 21H ; is X^16 + X^15 + X^2 + 1. This may be MOV L,A ; used by subst, XOR 80H for XOR 10H and SKIPIT: DCR B ; XOR 05H for XOR 21H in the adj, 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 BADOPT: CALL ILPRT DB CR,LF,'++ INVALID OPTION ++',CR,LF,BELL,0 LXI B,0FFFFH DELAY2: DCX B MOV A,B ORA C JNZ DELAY2 MENU: LXI H,RESTSN ; RESTORE SECTORE NUMBERS.. LXI D,SECTNB ; ..FOR NEW FILE TRANSFER. MVI B,SECTNE-SECTNB 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.. STA LSTFLG STA MACFLG sta dialflg ; be sure the redial flag is reset CMA ; ..AND MULTI TRANS IN CASE.. STA FSTFLG ; ..OF ABORT. MENU1: LDA XPRFLG ; TEST IF MENU SHOULD BE SHOWN ORA A JNZ XPRT1 CALL ILPRT DB FF,CR DB '== Commands in Menu Mode ======== Secondary Options ========',cr,lf DB 'WRT - Write informal file | ...B - Batch file mode',cr,lf DB 'DEL - Erase informal file | ...S - show as Sent',cr,lf DB 'DSC - Disconnect phone | ...R - show as Received',cr,lf DB 'LOG - Login new disk drive | ...V - View as sent/recd',cr,lf DB 'CAL - Autodial from direct. | ...Q - Quiet, no messages',cr,lf DB 'XPR - Expert mode (on/off) | ...T - return to Terminal mode',cr,lf DB 'DIR - Disk directory | ...E - return to Echo mode',cr,lf DB 'CPM - Exit to CP/M | ...D - Disconnect phone',cr,lf DB 'K - Kill disk file [fn.ext]| ...C - CRC check/not checksum',cr,lf DB 'S...- Send file [fn.ext] | (receive option only)',cr,lf DB 'R...- Receive file [fn.ext] | S3 - 300 Baud to the Modem',cr,lf DB 'T - Terminal mode [fn.ext] | S12 - 1200 Baud to the Modem',cr,lf DB 'E - Terminal modem w/echo | ^C - Reset the Drives',cr,lf DB '============== Commands in Terminal Mode ================',cr,lf DB '-Off line/return to menu| ^Z - END of file',cr,lf DB '^S - XOFF character | ^Q - XON character',cr,lf DB '^D - Disconnect phone | - Printer (on/off-rcv mode)',cr,lf DB '^T - Transmit informal file | ^R - Receive Informal File',cr,lf DB '^X - Cancel send/receive | ^E - Terminal/Echo (on/off)',cr,lf DB '^A - Re-dial (toggle on/off)|',cr,lf,0 CALL ILPRT DB CR,LF,0 JMP XPRT9 XPRT1: CALL ILPRT DB FF,0 XPRT: CALL ILPRT DB CR,LF,0 XPRT9: MVI C,25 ; CURRENT DISK FUNCTION CALL BDOS ADI 41H ; MAKE ASCII CALL TYPE Š CALL ILPRT DB ': PRIMARY OPTION >>',0 GETCMD: LXI D,CMDBUF ; ENTER COMMAND CALL INBUFF CALL CRLF LXI D,CMDBUF+2 ; POINT TO COMMAND CALL ILCOMP DB 'DSC',0 JNC DNTCB CALL ILCOMP DB 'CPM',0 JNC EXIT CALL ILCOMP DB 'DIR',0 JNC DIR IF SWITCH CALL ILCOMP DB 'S3',0 JNC SET300B CALL ILCOMP DB 'S12',0 JNC SET120B ENDIF; SWITCH CALL ILCOMP DB 'RET',0 JC NXTOPT1 ; CARRY SET = NO MATCH LHLD HLSAVE ; RETURN TO TERMINAL.. JMP TERM ; ..MODE WITH SAVE OPTION.. ; ..IF PREVIOUSLY ENABLED. NXTOPT1:CALL ILCOMP DB 'WRT',0 JNC WRTFIL CALL ILCOMP DB 'XPR',0 JNC XPRMODE CALL ILCOMP DB 'LOG',0 JNC LOGON CALL ILCOMP DB 'DEL',0 JNC NEWFILE CALL ILCOMP DB 'CAL',0 Š JC NXTPT2 MVI A,1 STA CMDBUF+1 JMP DOOPT NXTPT2: 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 RESTAR ; ..AS IF PROGRAM WERE CALLED WITH.. 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 NFLFLG ;..SAVE SINCE NO FILE.. CMA ;..SPECIFIED. STA SAVFLG LXI H,FCB3 CALL INITFCB JMP MENU1 WRTFIL: LDA NFLFLG CPI TRUE JZ MENU1 LDA FCB3+1 ; CHECK THAT FILE WAS REQUESTED CPI ' ' JZ MENU1 LHLD HLSAVE CALL NMRECS ; DISK WRITE ROUTINE AS USED IN.. CALL WRTDSK ; ..IN THE INTDSSV ROUTINE. CALL CLOSE3 MVI A,TRUE STA NFLFLG CMA STA MACFLG ; RESET OBLECT FILE SAVE FLAG STA SAVFLG LXI H,FCB3 CALL INITFCB ; 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. RETRNS 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', 'K' ILCOMP: XTHL ; POINT HL TO 1ST CHAR. PUSH D ILCMPL: MOV A,M ; HL POINTS TO IN-LINE STRING. ORA A ; END OF STRING IF ZERO. JZ SAME LDAX D CMP M JNZ NOTSAME INX H INX D JMP ILCMPL NOTSAME:MVI A,0 ; IF NOT SAME, FINISH THRU.. NSLP: INX H ; ..STRING SO RETURN WILL.. CMP M ; ..GO TO INSTRUCTION AFTER.. JNZ NSLP ; ..STRING AND NOT REMAINDER OF STRING. STC SAME: POP D INX H ; AVOIDS A NOP INSTRUCTION.. XTHL ; ..WHEN RETURNING. RET INBUFF: PUSH PSW PUSH H PUSH B PUSH D ; DE REGISTERS MUST BE PUSHED LAST STRT: CALL CLEAR ; CLEAR THE BUFFER AREA POP D ; GET ADDRESS OF BUFFER ON RETRIES PUSH D ; RESTORE STACK XRA A INX D ; ADDRESS COUNT FIELD STAX D ; INITIALIZE WITH A ZERO IN COUNT BYTE INX D XCHG ; ADDRESS FIRST BUFFER BYTE WITH HL INBUFA: CALL CONIN CPI 'C'-40H ;RESET DISKS? CZ NEWDSK ;YES,DO IT CPI 0DH ; IS IT A RETURN? JZ INBUFR ; IF SO, THEN RETURN CPI 7FH ; IS IT A DELETE? Š JZ DELETE CPI 8 ; CTRL-H WILL BACKSPACE.. JZ DELETE ; ..OVER DELETED CHAR. CPI 'U'-40H ; IS IT A CTRL-U JZ INBUFO ; OUTPUT # CR LF AND START OVER CPI 'R'-40H ; CTRL-R RETYPES LINE JZ RETYPE CPI 'E'-40H JZ PCRLF CPI 20H ; NO CONTROL CHARACTERS OTHER.. JC INBUFA ; ..THAN ABOVE ALLOWED. MOV B,A ; SAVE INPUTTED CHARACTER XCHG ; SAVE HL IN DE POP H ; GET ADDRESS OF BUFFER IN HL PUSH H ; RESTORE STACK INX H ; ADDRESS COUNT BYTE INR M ; INCREASE COUNT BYTE DCX H ; ADDRESS MAXIMUM MOV A,M ; PUT MAXIMUM IN A INX H ; ADDRESS COUNT CMP M ; COMPARE COUNT TO MAXIMUM JC ALERT ; IF MAXIMUM, RING BELL AND WAIT FOR CR XCHG ; RESTORE BUFFER POINTER TO HL MOV M,B ; PUT INPUTTED CHARACTER IN BUFFER MOV A,B ; OUTPUT IT CALL CONOUT INX H ; BUMP POINTER JMP INBUFA ; GET NEXT CHARACTER DELETE: XCHG ; SAVE BUFFER POINTER IN DE POP H ; ADDRESS BEGINNING OF BUFFER PUSH H ; RESTORE STACK INX H ; ADDRESS COUNT FIELD MOV B,A ; SAVE DELETE CHAR - 7FH OR 08H MOV A,M SUI 1 ; DECREASE COUNT MOV M,A JC NODEL ; DON'T DELETE PAST BEGINING OF BUFFER. XCHG ; RESTORE BUFFER POINTER TO HL DCX H ; POINT TO LAST BYTE INPUTTED MOV A,B ; GET BACK EITHER 7FH OR 08H MOV B,M ; GET CHARACTER BEING DELETED MVI M,20H ; RESTORE BLANK CPI 08H JZ BKSPC MOV A,B ; ECHO CHAR IF 7FH CALL CONOUT JMP INBUFA ; GET NEXT CHARACTER NODEL: INR M ; DON'T LEAVE COUNT NEGATIVE XCHG ; RESTORE POINTER TO HL JMP INBUFA BKSPC: CALL CONOUT ; TRUE ERASE IF 08H MVI A,20H CALL CONOUT MVI A,08 Š CALL CONOUT JMP INBUFA INBUFO: MVI A,'#' CALL CONOUT MVI A,0DH CALL CONOUT MVI A,0AH CALL CONOUT JMP STRT RETYPE: POP D PUSH D INX D ; POINT TO CURRENT NUMBER.. LDAX D ; ..OF CHARACTERS. MOV B,A MVI A,'#' CALL CONOUT MVI A,0DH CALL CONOUT MVI A,0AH CALL CONOUT MOV A,B ; TEST IF ZERO INPUT ORA A JZ INBUFA CTLRLP: INX D LDAX D CALL CONOUT DCR B JNZ CTLRLP JMP INBUFA ALERT: MVI A,7 CALL CONOUT DCR M XCHG JMP INBUFA PCRLF: MVI A,0DH CALL CONOUT MVI A,0AH CALL CONOUT JMP INBUFA INBUFR: MVI A,0DH CALL CONOUT MVI A,0AH CALL CONOUT POP D POP B POP H POP PSW RET CLEAR: POP D ; ACCOUNTS FOR CALL Š POP H ; ADDRESS BUFFER IN HL PUSH H ; RESTORE.. PUSH D ; ..STACK MOV B,M ; SAVE MAXIMUM IN B INX H ; POINT TO FIRST.. INX H ; ..BUFFER BYTE. MVI A,20H CLEARL: MOV M,A INX H DCR B JNZ CLEARL RET CONIN: PUSH H PUSH D PUSH B CONINLP:CALL CONSTAT ORA A JZ CONINLP CALL CONIN1 ; IF YOU WISH ALL COMMANDS GOING TO THE BUFFER TO BE CONVERTED ; TO UPPER CASE THEN RE-INITIALIZE THE FOLLOWING CODE, BUT ; THE PHONE DIRECTORY WILL THEN ONLY RECOGNIZE THE UPPER CASE ; ALPHABET ; ; CPI 61H ; CHANGE TO UPPER.. ; JC NOUCASE ; ..CASE SINCE CP/M.. ; CPI 7BH ; ..DOES THE SAME. ; JNC NOUCASE ; ANI 5FH NOUCASE:POP B POP D POP H RET CONIN1: LHLD 1 LXI D,6 DAD D PCHL CONSTAT:PUSH H PUSH D PUSH B CALL CONST1 POP B POP D POP H RET CONST1: LHLD 1 LXI D,3 DAD D PCHL CONOUT: PUSH H Š PUSH D PUSH B PUSH PSW CALL CONOT1 POP PSW POP B POP D POP H RET CONOT1: LHLD 1 LXI D,9 DAD D MOV C,A PCHL CPMLINE:PUSH PSW PUSH B PUSH D PUSH H CALL INIT ; FILLS FCBS WITH BLANKS AND NULLS XCHG ; GET START OF COMMAND LINE IN HL. INX H ; ADDRESS # BYTES IN CMD LINE. MOV E,M ; LOAD DE PAIR WITH # BYTES. MVI D,0 INX H DAD D ; POINT TO BYTE AFTER LAST CHAR.. MVI M,0DH ; ..IN CMD LINE AND STORE DELIMITER. POP H ; RESTORE HL AND DE. POP D PUSH D PUSH H INX D ; ADDRESS START OF COMMAND. INX D CALL DRIV NAME1: MVI C,8 ; TRANSFER FIRST FILENAME TO FCB. CALL TRANS CPI 0DH JZ DONE2 CPI 20H ; IF SPACE, THEN START OF.. JZ NAME2 ; ..SECOND FILENAME. TYPE1: POP H ; FILETYPE MUST BE AFTER.. PUSH H ; ..EIGHTH BYTE OF NAME. LXI B,9 DAD B MVI C,3 ; TRANSFER TYPE OF FIRST FILE CALL TRANS CPI 0DH JZ DONE2 NAME2: LDAX D ; EAT MULTIPLE SPACES.. Š CPI 20H ; ..BETWEEN NAMES. JNZ NAME2C INX D JMP NAME2 LDAX D CPI 0DH ; TEST IF FIRST NAME.. JZ DONE2 ; ..ONLY AND THEN SPACE. NAME2C: POP H ; SECOND NAME STARTS IN 16TH BYTE. PUSH H ; POINT HL TO THIS BYTE. LXI B,16 DAD B CALL DRIV MVI C,8 CALL TRANS CPI 0DH JZ DONE2 TYPE2: POP H ; SECOND TYPE STARTS IN 25TH BYTE. PUSH H LXI B,25 DAD B MVI C,3 CALL TRANS DONE2: POP H PUSH H INX H ; POINT TO FIRST CHAR OF FIRST NAME IN FCB. CALL SCANM ; CHECK FOR * (AMBIGUOUS NAMES). POP H PUSH H LXI B,17 ; POINT TO FIRST CHAR OF SECOND NAME IN FCB. DAD B CALL SCANM POP H POP D POP B POP PSW RET INIT: PUSH H ; INITIALIZES FCB WITH 1 NULL (FOR FIRST DRIV). PUSH B ; ..11 BLANKS, 4 NULLS, 1 NULL (FOR 2ND DRIV),. MVI M,0 ; ..11 BLANKS, AND 4 NULLS. INX H MVI B,11 MVI A,20H CALL INTFIL MVI B,5 MVI A,0 CALL INTFIL MVI B,11 MVI A,20H CALL INTFIL MVI B,4 MVI A,0 CALL INTFIL Š POP B POP H RET INTFIL: MOV M,A INX H DCR B JNZ INTFIL RET DRIV: INX D ; CHECK 2ND BYTE OF FILENAME. IF IT.. LDAX D ; ..IS A ":", THEN DRIV WAS SPECIFIED. DCX D CPI ':' JNZ DEFDR ; ELSE ZERO DEFAULT DRIV ('INIT' PUT ZERO) LDAX D ANI 5FH SUI 40H ; CALCULATE DRIV (A=1, B=2,...).. MOV M,A ; ..AND PLACE IT IN FCB. INX D ; ADDRESS FIRST BYTE OF.. INX D ; ..IN CMD LINE,.. DEFDR: INX H ; ..AND NAME FIELD IN FCB. RET TRANS: LDAX D ; TRANSFER FROM CMD LINE TO FCB.. INX D ; ..UP TO NUMBER OF CHARS SPECIFIED.. CPI 0DH ; ..BY C-REG. KEEP SCANNING FIELD.. RZ ; ..WITHOUT TRANSFER UNTIL DELIMITING.. CPI '.' ; ..FIELD CHAR SUCH AS '.', BLANK, OR.. RZ ; ..C/R (FOR END OF CMD LINE). CPI 20H RZ DCR C JM TRANS ; ONCE C-REG IS LESS THAN ZERO, KEEP READING.. MOV M,A ; ..CMD LINE BUT DO NOT TRANSFER TO FCB. INX H JMP TRANS SCANM: MVI B,8 ; SCAN FILE NAME ADDRESSED BY HL. TSTNAM: MOV A,M CPI '*' ; IF '*' FOUND, FILL IN REST OF FIELD.. JZ FILL1 ; ..WITH '?' FOR AMBIGUOUS NAME. INX H DCR B JNZ TSTNAM JMP TSTTYP FILL1: CALL FILL TSTTYP: MVI B,3 ; SCAN AND FILL TYPE FIELD FOR NAME.. TSTYPL: MOV A,M ; ..SPECIFIED ABOVE. CPI '*' JZ FILL2 INX H DCR B RZ Š JMP TSTYPL FILL2: CALL FILL RET FILL: MVI M,'?' ; ROUTINE TRANSFERS '?'. INX H DCR B JNZ FILL RET DIRLST: LXI D,CMDBUF ; PUT COMMAND LINE IN FCB LXI H,5CH CALL CPMLINE LXI H,SRCHFCB CALL INITFCB LDA 6CH ; GET DRIVE # STA SRCHFCB LDA 6DH CPI 20H ; IF BLANK GET ALL NAMES PUSH PSW CZ QSTMARK POP PSW CNZ MVNM ; ELSE MOVE NAME INTO FCB CALL DRIVE LXI D,80H MVI C,STDMA CALL BDOS XRA A STA NAMCT ; CR AFTER 4 NAMES LXI D,SRCHFCB MVI C,SRCHF ; DO FIRST SEARCH CALL BDOS CPI 0FFH JZ NOFILE DIRLP: CALL GETADD LXI D,15 ; OFFSET FOR RECORD COUNT DAD D MOV A,M ORA A JZ NEXTSR ; NO LIST IF FILE IS ZERO LENGTH LXI D,-5 DAD D ; POINT TO $SYS ATTRIB BYTE MOV A,M ANI 80H JNZ NEXTSR ; NO LIST IF $SYS FILE LXI D,-10 DAD D ; POINT TO BEGINNING OF NAME INX H ; POINT TO FIRST LETTER LXI D,PRNTNM MVI B,8 CALL MOVE INX D MVI B,3 Š CALL MOVE CALL ILPRT PRNTNM: DB ' ',' ',' ', ' | ', 0 ;8,1,3 SPACES LDA NAMCT INR A STA NAMCT ANI 03H ORA A CZ CRLF NEXTSR: LXI D,SRCHFCB MVI C,SRCHN ; DO NEXT SEARCH CALL BDOS CPI 0FFH JZ DIRDONE JMP DIRLP NOFILE: CALL ILPRT DB CR,LF,'++ FILE NOT FOUND ++',0 DIRDONE:CALL CRLF RET ; SCDSK: DB 0 ; QSTMARK:MVI A,'?' ; IF BLANK IN FCB, PUT IN 11 ?'s MVI B,11 LXI H,SRCHFCB+1 QSTLP: MOV M,A INX H DCR B JNZ QSTLP RET MVNM: LXI H,6DH LXI D,SRCHFCB+1 MVI B,11 CALL MOVE ; MOVE IN CP/M PROGRAM RET GETADD: ANI 03H ; GET MOD4 FOR CP/M 1.4 ADD A ADD A ADD A ; ADD 32 ADD A ADD A MOV E,A MVI D,0 LXI H,80H ; ADD DMA OFFSET DAD D RET DRIVE: LDA SRCHFCB ; IF NO DRIVE, CAL ORA A ; LOGGED IN DRIVE Š JZ CALCDR ADI 40H JMP PRNTHD CALCDR: MVI C,25 CALL BDOS ADI 41H PRNTHD: STA DRNAME CALL ILPRT DB CR,LF,'++ DRIVE ' DRNAME: DB ' :',CR,LF,0 RET IF OSBORNE OSCODE EQU $ OFSET EQU 0A000H ; OUT OF HARMS WAY SIN EQU $-OSCODE+OFSET DI OUT 0 ; MOV B,A LDA 2A01H OUT 1 EI RET SOUT EQU $-OSCODE+OFSET DI OUT 0 ; MOV B,A STA 2A01H OUT 1 ; MOV A,B EI RET SSTAT EQU $-OSCODE+OFSET DI OUT 0 LDA 2A00H OUT 1 EI RET OLENG EQU $-OSCODE+1 ENDIF ; OSBORNE SRCHFCB:DS 33 NAMCT: DS 1 ŠNFLFLG:DB FALSE ; NORMALLY SET TO FALSE. ALLOWS WRITE TO.. ; ..MEMORY IN TERMINAL MODE. OPTION: DB 0 OPTBL EQU $ DISCFLG:DB 'D' QFLG: DB 'Q' RSEEFLG:DB 'R' SSEEFLG:DB 'S' VSEEFLG:DB 'V' TERMFLG:DB 'T' ECHOFLG:DB 'E' CRCFLG: DB 'C' 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 'D','Q','R','S','V','T','E','C','B' RESTSN: DB 0,0,0,0,0,0 DW DBUF DB 0,0,0,0,0,0 SECTNB 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 SECTNE EQU $ FSTFLG: DB TRUE CMDBUF: DB 80H,0 DS 80H HLSAVE: DS 2 DISKNO: DS 1 SENDFLG:DS 1 NBSAVE: DS 2 BGNMS: DS 2 FILECT: DS 1 NAMECT: DS 1 DS 60 STACK: DS 2 FCB3: DS 33 ŠFCBBUF: DS 15 BOTRAM EQU $ ; BOTTOM OF SMODEM3 RAM DBUF EQU $ ; DISK BUFFER...DBFSIZ SET AT ; BEGINNING NAMEBUF EQU DBUF+(DBFSIZ*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 RESET EQU 13 SELDSK EQU 14 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 RCDSK EQU 25 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 END