.COMMENT \ *** SMODEM3 *** CP/M SMARTMODEM PROGRAMME ========================= Version 3.6 by Walter Blady THIS PROGRAMME 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 PROGRAMME 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. THIS VERSION WAS PREPARED BY WALTER BLADY FOR USE WITH THE HAYES SMARTMODEM USING RS232 I/O ON THE DISC JOCKEY CONTROLLER BOARD. AN EXTENDED AND MORE FLEXIBLE AUTO-DIAL FEATURE WAS ADDED. THE USER NOW HAS THE ABILITY TO KEEP SEVERAL TELEPHONE DIRECTORIES ON THE DISK AND THESE MAY BE EDDITED WHEN NEW INFORMATION MUST BE ADDED. THE ORIGIONAL SOURCE CODE WAS PREPARED FOR THE MAC ASSEMBLER. THIS VERSION HAS BEEN ADAPTED FOR COMPILATION WITH MICROSOFT'S M80 ASSEMBLER. FOR FULL INFORMATION ON THE USE OF 'SMODEM3', PLEASE REFER TO THE FILE 'SMODEM3.DQC'. TO ASSEMBLE THIS PROGRAMME AND CREATE A CP/M 'COM' FILE, USE THE FOLLOWING COMMANDS: M80 =SMODEM3 L80 /P:100,SMODEM3,SMODEM3/N/E ***** \ .8080 ;ASSEMBLE USING 8080 CODE RECOGNITION TRUE EQU 0FFH FALSE EQU 0 CPM2+ EQU TRUE ;TRUE=CP/M 2+...FALSE=CP/M 1+ DBFSIZ EQU 16 ;DISK BUFFER SIZE IN 128 BYTE SECTORS ;CHANGE THIS TO 8 FOR A 32K SYSTEM BOTRAM EQU 2C00H ;BOTTOM + OF SMODEM3 ERRLIM EQU 10 ;NUMBER OF TIMES TO RETRY ;SEND/RECEIVE ERRORS BEFORE QUIT DJBRD EQU TRUE ;TRUE=DISK-JOCKEY CONTROLER RS232 I/O PORTIO EQU FALSE ;TRUE=RS232 I/O OTHER THAN DISK-JOCKEY INLZE EQU FALSE ;TRUE=RS232 I/O PORT INITIALIZATION ;IS NEEDED CHEK EQU FALSE ;TRUE=OVERRUN,FRAMING AND PARITY ;CHECKS NEEDED...ONLY SET TO TRUE IF ;PORTIO=TRUE. PRINTR EQU 'P'-40H ; ^P = LIST DEVICE TOGGLE ECOTOG EQU 'E'-40H ; ^E = TERM/ECHO TOGGLE OFFLIN EQU 'O'-40H ; ^O = OFFLINE 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 '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 ; JMP START ;BEGINNING OF PROGRAMME .COMMENT \ '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 'ATD $' ;MODEM DIALING COMMAND...ENTER A 'P' DS 4 ;OR 'T' FOR PULSE OR TOUCH AFTER THE ;'D' IF DESIRED. .COMMENT \ '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 FALSE ;2 MZ OPERATION = FALSE...4 MZ = TRUE BKBYTE: DB TRUE ;TRUE = MAKE .BAK FILE XPRFLG: DB FALSE ;FALSE = PRINT MENU ON INITIALIZATION LSTFLG: DB 0 ;LIST DEVICE FLAG MACFLG: DB 0 ;SEND/RECEIVE OBJECT CODE FLAG ;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 .COMMENT \ SET THESE THE FOLLOWING EQUATES TO MATCH YOUR SERIAL I/O ASSIGNMENTS, AND DELETE THE ONES NOT USED. \ IF PORTIO ;IF OTHER THAN DJBOARD PORT EQU 000H ;BASE ADDRESS MOCTLP EQU PORT ;MODEM CONTROL PORT MOSNDB EQU 0 ;MODEM SEND READY BIT MOSNDR EQU 0 ;VALUE WHEN MODEM SEND READY MORCVB EQU 0 ;MODEM RECEIVE READY BIT MORCVR EQU 0 ;VALUE WHEN MODEM RECEIVE READY MODATP EQU PORT+? ;MODEM DATA PORT BAUDRP EQU PORT+? ;BAUD RATE PORT MOCTL2 EQU PORT+? ;2ND MODEM CONTROL PORT 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 ENDIF ;PORTIO ;IF YOUR SERIAL PORTS MUST BE INITIALIZED SET THESE EQUATES IF INLZE INITC1 EQU 00H INITC2 EQU 00H ENDIF ;INLZE START: LXI H,0 DAD SP ;GET CP/M'S STACK SHLD STACK ;SAVE IT LXI SP,STACK ;START LOCAL STACK 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 CPI 'C' JNZ RSTR1 LXI H,80H ;POINT TO CP/M CMDBUF LXI D,CMDBUF+1 MOV B,M ;GET LENGTH OF COMMD.LINE INR B ;UP ONE FOR CHAR.COUNTER CALL MOVE JMP DIALPL RSTR1: CPI 'E' ;ECHO MODE? JZ TRMECHO ;YES CPI 'D' ;DISCONNECT? JZ DNTCB ;YES, DISCONNECT & 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 'T' ;TERMINAL MODE? JZ DSKSAVE ;YES CPI 'S' ;SEND A FILE? JZ SENDFIL ;YES CPI 'R' ;RECEIVE A FILE? JZ RCVFIL ;YES CPI 'K' ;KILL A FILE? JZ KILFIL ; YES, GO DO IT 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 ; 0 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,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: CPI OFFLIN ;^O? JZ MENU ;YES, RETURN TO MENU CPI DISCCHR ;^D? JZ DNTCB ;YES, DISCONNECT & RETURN TO MENU LST: CPI PRINTR ;^P? 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 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. 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 INR A JNZ NOSAVE POP PSW 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 .COMMENT \ 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,LF,0 TRNSL2:CALL ILPRT DB ' ...TYPE ''R'' TO RETURN TO MODEM ++',CR,LF DB ' ...TYPE ''A'' TO RE-ENTER NAME ',CR,LF,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 'ANSWER YES OR NO ONLY PLEASE!',CR,LF,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 TRANSFERED...C/R TO QUIT ++',CR,LF,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: CPI OFFLIN 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 ; 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. ;REINITIALIZE THIS CODE IF YOU WANT THE ABILITY TO ABORT ;WHILE RECEIVING. ; 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 .COMMENT \ ------------------------------------------------------------- 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 IFNB ; NOT NUL ?F LXI H,?F ENDIF IFNB ; NOT NUL ?T LXI D,?T ENDIF IFNB ; NOT NUL ?L LXI B,?L ENDIF IFNB ; 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 IFNB ; NOT NUL ?F MVI C,?F ENDIF IFNB ; NOT NUL ?P LXI D,?P ENDIF CALL BDOS POP H POP D POP B ENDM .COMMENT \ ------------------------------------------------ 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 .COMMENT \ 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,BELL,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 ;ERASE A FILE FROM DISK, MENU MODE KILFIL: MVI A,TRUE STA NFLFLG CMA STA SAVFLG 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 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 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,'$' IFNB ;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+ IFB 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 ERRCDMSK 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 ENDIF ;INLZE 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,0 DNTCA: MVI A,TRUE STA NFLFLG CMA STA SAVFLG LDA DISCFLG ;DISCONNECT WHEN THROUGH? ORA A JNZ DNTCE ;...NO, CONT. DNTCB: CALL ILPRT DB CR,LF,'++ DISCONNECTED ++',CR,LF,0 LXI D,80H ;RESET DMA AND SEND '+++' MVI C,STDMA ;...ESCAPE CODE TO SMARTMO. CALL BDOS LXI D,OFFHK OFF1: LDAX D CPI '$' JZ OFF2 CALL MODOUT INX D JMP OFF1 OFF2: CALL CRLF ;C/R COMPLETES ESCAPE MVI B,15 ;2 SECOND DELAY FOR SMARTMO. OFF3: CALL TIMER ;...TO RESPOND. DCR B JNZ OFF3 INX D OFF4: LDAX D ;SEND ON-HOOK COMMAND TOO CPI '$' JZ OFF5 CALL MODOUT INX D JMP OFF4 OFF5: CALL TIMER ;SHORT DELAY AT THE END CALL INDATP ;...TIDY UP JMP TERM ;...CLOSE UP SHOP. DNTCE: LDA TERMFLG ;SEE IF RETURN TO.. ORA A ;..TERMINAL MODE.. JZ TERM LDA ECHOFLG ORA A JNZ MENU ;..AFTER X'FER. JMP TRMECHO TIMER: PUSH PSW ;TIME INTERVAL BETWEEN ESCAPE PUSH B ;CODE AND ON-HOOK COMMAND LXI B,3500H TIMER2: DCX B MOV A,B ORA C JNZ TIMER2 POP B POP PSW RET ;INITMOD: 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,LF DB ' ...TYPE ''Q'' TO QUIT',CR,LF DB ' ...TYPE ''R'' TO RETRY',CR,LF,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 ; DIRNAM: DB 'PHONE 001' DILFLG: DB FALSE ;THIS ROUTINE CHECKS TO SEE IF A DIRECTORY LETTER OR A ;PHONE NUMBER WAS ENTERED IN THE COMMAND LINE. DIALPL: MVI A,FALSE ;CLEAR DEFAULT DIAL FLAG STA DILFLG LXI H,CMDBUF+1 ;POINT # OF CHARS IN BUFF MOV A,M ;GET # OF CHARS CPI 4 ;WAS A NUMBER OR LETTER ENTRD.? JC ENTNM ;NO, DISPLAY DIREC.& ASK SUI 3 ;REDUCE COUNT FOR 'CAL' MOV M,A ;PUT IT BACK MVI A,TRUE ;SET DEFAULT DIAL FLAG STA DILFLG LXI H,CMDBUF+5 ;POINT TO NUMBER TO DIAL DI8: MOV A,M ;GET CHAR.OR NUMBER CPI 32 ;SPACE? JNZ DI9 ;...NO, INX H ;BUMP THE CMDBUF UP, PUSH H LXI H,CMDBUF+1 DCR M ;...AND THE CHAR.COUNTER DOWN. POP H JZ ERROR3 ;ERROR IF NO MORE CHARS. JMP DI8 ;CHECK AGAIN DI9: CPI 48 ;LOWER THAN A NUMBER? JC ERROR3 ;...YES, HOPP IT! CPI 58 ;IS IT A NUMBER? JC DIALPX ;...YES, DIAL DIRECT JMP ENTM2 ;...NO, LOAD DEFAULT FILE '001' ;ASKS FOR DIRECTORY NAME THEN MOVES IT TO THE FCB. ENTNM: CALL ILPRT DB '++ ENTER DIRECTORY NAME >>',0 LXI D,CMDBUF ;GET FILE NAME CALL INBUFF LDA CMDBUF+2 CPI 32 JZ MENU ;ZERO MEANS 'NO ENTRY MADE' LXI H,FCB4 CALL INITFCB CALL MOVE4 JMP DI1 ;LOAD THE DEFAULT FILE NAME FROM DEFAULT DRIVE ENTM2: PUSH H LXI H,FCB4 CALL INITFCB ;INITIALIZE FCB LXI D,FCB4+1 LXI H,DIRNAM MVI B,11 ;COUNT CALL MOVE ;GET CHARS.IN POP H ;THIS ROUTINE READS THE FILE TO THE DBUF DI1: PUSH H MVI C,RESET CALL BDOS ;RESET IN CASE OF DISK CHANGE CALL OPEN4 POP H INR A ;OPEN OK? JZ ERROR2 ;...NO, PRINT NO FILE. PUSH H LXI D,DBUF ;SET DMA. DI2: PUSH D MVI C,STDMA CALL BDOS CALL READ80 ;128 BYTES SEQUENTIAL POP D ;ONCE MORE INTO THE BREACH LXI H,128 ;LOAD DMA INCREMENT DAD D ;AND INCREMENT IN 'HL' XCHG ;GIVE IT BACK TO 'DE' ORA A ;END OF FILE? JZ DI2 ;...NO, CONT. POP H LDA DILFLG INR A ;DIRECT DIAL TO DEFAULT FILE? JZ DIAL10 ;...YES, DON''T PRINT DIR. ;THIS ROUTINE PRINTS THE DIRECTORY TO THE SCREEN CALL ILPRT DB FF DB ' *** PHONE DIRECTORY ***',CR,LF DB '===============================================================',CR,LF,0 MVI C,PRINT ;PRINT TO SCREEN LXI D,DBUF CALL BDOS ;THIS ROUTINE ASKS FOR NUMBER TO DIAL COMMD: CALL ILPRT DB '++ ENTER NUMBER/LETTER...C/R TO QUIT >>',0 LXI D,CMDBUF CALL INBUFF CALL CRLF LDA CMDBUF+1 ;NO.OF CHARS.IN BUFFER ORA A ;NULL MEANS WAS TYPED JZ MENU ;ABORT DIALING, RETURN TO MENU LXI H,CMDBUF+2 ;FIRST CHAR.OF NO.TO DIAL ; ENTER THIS ROUTINE WITH HL POINTING TO DIAL LINE DIAL10: MOV A,M ;GET CHAR.OR NUMBER CPI 32 ;SPACE? JNZ DI6 ;...NO, INX H ;BUMP THE CMDBUF UP, PUSH H LXI H,CMDBUF+1 DCR M ;...AND THE CHAR.COUNTER DOWN. POP H JZ ERROR4 JMP DIAL10 ;CHECK AGAIN DI6: CPI 48 ;LOWER THAN A NUMBER? JC ERROR4 CPI 58 ;IS IT A NUMBER? JC DIALPX ;...YES, DIAL DIRECT CPI 91 ;IS IT UPPER CASE? JC DI3 ;...YES, GO POINT TO IT. SUI 6 ;READY FOR LOWER CASE CPI 117 ;IS IT LOWER CASE? JC DI3 ;...YES, POINT. DI5: XRA A ;NO, MAKE NULL JMP DILP2 ;PRINT ERROR MESSAGE DI3: SUI 64 ;MAKE INDEX NO. MOV B,A ;LOAD INDEX NUMBER LXI H,DBUF ;POINT TO START OF DBUF LXI D,31 ;LOAD INCREMENT DI4: DCR B ;ARE WE THERE? JZ DIAL13 ;...YES, DIAL IT. DAD D ;INCREMENT TO NEXT LINE JMP DI4 ;DO AGAIN DIAL13: MVI E,29 ;NO. OF CHAR TO GET FROM TABLE JMP DIALP2 ;GO DIAL DIALPX: LDA CMDBUF+1 ;LOAD CDMBUF COUNT MOV E,A ;...& PUT HERE ;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. DIALP2: PUSH D MVI A,CR CALL MODOUT LXI D,STYLE ONW1: LDAX D CPI '$' ;SEND 'ATD' TO SMARTMODEM JZ ONW2 CALL MODOUT INX D JMP ONW1 ONW2: POP D ;DIAL DIGIT OR ABORT IF NULL ENCOUNTERED DILP2: MOV A,M ;GET FIRST # FROM BUFFER ORA A ;FAULTY DIRECTORY ENTRY? JZ ERROR1 ;...YES, ABORT DIAL. CALL DIAL ;DIAL IT INX H ;BUMP POINTER DCR E ;COUNT DOWN CHARS IN BUFF JNZ DILP2 ;NOT DONE, LOOP JMP DIALDN ;DIALING DONE ;AUTO DIALER DIAL: CPI 48 JC DIA1 ;DIGIT MUST BE AT LEAST 0.. CPI 58 JNC DIA1 ;..AND NOT MORE THAN 9 CALL MODOUT ;NUMBERS PRINTED IN THIS ROUTINE RET DIA1: CALL TYPE ;PRINT ALL EXCEPT NUMBERS RET DIALDN: CALL ILPRT DB CR,LF,'++ DIAL COMPLETED...NOW IN TERMINAL MODE ++',CR,LF,BELL,0 ;ROUTINE TO SEND C/R TO SMARTMODEM AT END OF DIAL MVI A,CR CALL MODOUT ;COMPLETE THE DIALING CALL INDATP ;GOBBLE GARBAGE CALL INDATP MVI C,STDMA LXI D,80H CALL BDOS ;RESTORE ORIG.DMA MVI A,TRUE STA NFLFLG CMA STA SAVFLG JMP TERM ERROR1: CALL ILPRT DB CR,LF,'++ FAULTY NUMBER...INSPECT DIRECTORY ++',CR,LF,LF,0 JMP XPRT9 ERROR2: CALL ILPRT DB CR,LF,'++ FILE DOSN''T EXIST ++',CR,LF,LF,0 JMP XPRT9 ERROR3: CALL ILPRT DB CR,LF,'++ BAD NUMBER...CALL AGAIN ++',CR,LF,LF,0 JMP XPRT9 ERROR4: CALL ILPRT DB CR,LF,'++ BAD NUMBER...TRY AGAIN ++',CR,LF,LF,0 JMP COMMD ;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' 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,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 .COMMENT \ 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 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 XRA A STA MFFLG1 ;RESET MFACCESS ROUTINE.. STA LSTFLG STA MACFLG 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 *** SMODEM3 *** ',CR,LF DB '=======================',CR,LF DB 'WRT - Write informal file to disk',CR,LF DB 'DEL - Erase informal file from disk',CR,LF DB 'DSC - Disconnect phone (SMARTMODEM)',CR,LF DB 'RET - Return to terminal mode (no data loss)',CR,LF DB 'CAL - Auto dial from phone directory (SMARTMODEM)',CR,LF DB 'XPR - Expert mode (Toggle menu on/off)',CR,LF DB 'DIR - Disk directory ',CR,LF DB 'CPM - Exit to CP/M',CR,LF DB 'K - Kill disk file [fn.ext]',CR,LF DB 'S... - Send CP/M file [fn.ext] SECONDARY OPTIONS',CR,LF DB 'R... - Receive CP/M file [fn.ext] =================',CR,LF DB 'T - Terminal mode ...B - Batch file mode',CR,LF DB 'E - terminal mode with Echo ...S - show as Sent',CR,LF DB ' ...R - show as Received',CR,LF DB 'COMMANDS - IN TERMINAL MODE ...V - View as sent/received',CR,LF DB '=========================== ...Q - Quiet, no messages',CR,LF DB '^O - Off line/return to menu ...T - return to Terminal mode',CR,LF DB '^Z - END of file ...E - return to Echo mode',CR,LF DB '^S - XOFF character ...D - Disconnect phone',CR,LF DB '^Q - XON character ...C - CRC check/not checksum',CR,LF DB '^P - Printer (toggle on/off) (receive option only)',CR,LF DB '^T - Transmit informal file',CR,LF DB '^R - Receive informal file (toggle on/off)',CR,LF DB '^X - Cancel send/receive',CR,LF DB '^D - Disconnect phone (SMARTMODEM)',CR,LF DB '^E - Terminal/Echo (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 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 'DEL',0 JNC NEWFILE CALL ILCOMP DB 'CAL',0 JNC DIALPL 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 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 AUTO-DIAL ROUTINES AND PHONE DIRECTORY FORMAT WILL HAVE ;TO BE CHANGED AS WELL. ; 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 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,LF,0 RET 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 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 OPEN EQU 15 CLOSE EQU 16 SRCHF EQU 17 SRCHNCON 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 END