TITLE 'CP/M MODEM PROGRAM Version 7.98 12/31/82' ; ;THE FOLLOWING IS AN EXTENSIVE REVISION OF THE CP/M MODEM PROGRAM ;CREATED BY WARD CHRISTENSEN FOR THE CP/M USERS LIBRARY. IT ALSO ;INCORPORATES ROUTINES FOUND IN THE POTOMAC MICRO-MAGIC MODEM ;MANUAL WHICH MAY BE USED IF YOU HAVE A PMMI MODEM BOARD. ; ; ********* N O T I C E S ********* ; ; Revisers releasing new versions should only ; change the version number by 1 digit in the ; last place. ; ; Except for PMMI routines, revisers should ; only make nonspecialized changes for ; distribution. Please make configuration files, ; such as MCNFG7xx.ASM and MCOSB7xx.ASM, for ; particular computers, uarts or modems. ; ; ********************************** ; ;##### This file requires MODEM797.LIB and MAC.COM to assemble. ##### ; ;##### The file MCNFG797.ASM can be used to overlay the HEX ##### ;##### or COM file versions with your own modem routines and ##### ;##### configuration options. The file MODEM797.SET can be used ##### ;##### as a reference for directly setting the modem equates ##### ;##### and configuration options with the S command in DDT. ##### ; ;Fix log in MODEM797.HIS ; ; MACLIB MODEM797 ;Contains the CMDLINE, INBUF, INLNCOMP, ;DIRLIST, SENDTIME, PRTBAUD, and MFACCESS ;routines. ; ;Note that the library has not been changed since version 7.97. ; ; TRUE EQU 0FFH FALSE EQU 0 ; CPM2X EQU TRUE ;TRUE IF CP/M 2.X DBUFSIZ EQU 16 ;BUFFER SIZE FOR FILE TRANSFER IN KBYTES ; ERRCRC EQU 6 ;NUMBER OF TIMES TO TRY CRC MODE BEFORE ;SWITCHING TO CHECKSUM ERRLIM EQU 10 ;NUMBER OF TIMES TO RETRY ;SEND/RECEIVE ERRORS BEFORE QUIT ; ; PMMI EQUATES PORT EQU 0C0H ;PMMI BASE ADDRESS ; MODCTLP EQU PORT ;MODEM CONTROL PORT MODDATP EQU PORT+1 ;MODEM DATA PORT BAUDRP EQU PORT+2 ;BAUD RATE PORT MODCTL2 EQU PORT+3 ;2ND MODEM CONTROL PORT MODRCVB EQU 02H ;MODEM RECEIVE BIT (DAV) MODRCVR EQU 02H ;MODEM RECEIVE READY MODSNDB EQU 01H ;MODEM SEND BIT (XMIT BUFF EMPTY) MODSNDR EQU 01H ;MODEM SEND READY NOPARMSK EQU 10H ;MASK TO RESET TO NO PARITY EVPARMSK EQU 20H ;MASK TO SET EVEN PARITY ODPARMSK EQU 0CFH ;MASK TO SET ODD PARITY BRKMSK EQU 0FBH ;MASK TO SET BREAK ERRCDMSK EQU 38H ;MASK TO BLOCK ALL BITS EXCEPT ERROR CODES FRMER EQU 20H ;FRAMING ERROR MASK ORUNER EQU 10H ;OVERRUN ERROR MASK PARER EQU 08H ;PARITY ERROR MASK ANSWMOD EQU 1EH ;ANSWER MODE ORIGMOD EQU 1DH ;ORIGINATE MODE WAITCTS EQU 255 ;NUMBER OF SECONDS X 10 TO WAIT FOR COMPUTER ;TONE AFTER PMMI AUTO-DIAL FUNCTION 255 MAX. ; CRC EQU 'C' ;USED TO REQUEST 'CRC' INSTEAD OF 'CKSUM' ESC EQU '['-40H ; ^[ = ESCAPE SOH EQU 'A'-40H ; ^A = START OF HEADER EOT EQU 'D'-40H ; ^D = END OF TEXT ACK EQU 'F'-40H ; ^F = ACKNOWLEDGE OKNMCH EQU 'F'-40H ; ^F = OKAY NAME MATCH BELL EQU 'G'-40H ; ^G = BELL CHARACTER BKSP EQU 'H'-40H ; ^H = BACKSPACE LF EQU 'J'-40H ; ^J = LINEFEED CR EQU 'M'-40H ; ^M = CARRIAGE RETURN XON EQU 'Q'-40H ; ^Q = XON CHARACTER XOFF EQU 'S'-40H ; ^S = XOFF CHARACTER NAK EQU 'U'-40H ; ^U = NOT ACKNOWLEDGE CAN EQU 'X'-40H ; ^X = CANCEL SEND/RECEIVE EOFCHAR EQU 'Z'-40H ; ^Z = END OF FILE BDNMCH EQU 75H ; BAD NAME MATCH RUB EQU 7FH ; RUB ; BOTTRAM SET LAST+100H AND 0FF00H ; ORG 0100H ; JMP START ; ;THESE ROUTINES AND EQUATES ARE AT THE BEGINNING OF THE PROGRAM SO ;THEY CAN BE PATCHED BY A MONITOR OR OVERLAY FILE WITHOUT RE-ASSEMBLING ;THE PROGRAM. ; PMMIBYTE: DB TRUE ;true=PMMI modem SETUPTST: DB FALSE ;true=non-PMMI setup routine SCRNTEST: DB FALSE ;true=if home cursor and clear screen ;routine at CLRSCRN CLOCK: DB 4 ;clock speed in MHz, 8 MHz maximum BAKUPBYTE: DB FALSE ;true=make .BAK file CKSUMDFLT: DB FALSE ;true=default to Checksum checking ;false=default to CRC checking TOGGLECRC: DB TRUE ;true=allow toggling of Checksum to CRC CONVBKSP: DB FALSE ;true=convert backspace to rub TOGGLEBK: DB TRUE ;true=allow toggling of bksp to rub ADDLF: DB FALSE ;true=add LF after CR TOGGLELF: DB TRUE ;true=allow toggling of LF after CR TRANLOGON: DB FALSE ;true=allow transmission of logon ;write logon sequence at location LOGON SAVCCP: DB TRUE ;true=do not overwrite CCP LOCONEXTCHR: DB FALSE ;true=local command if EXTCHR precedes ;false=not local command if EXTCHR precedes TOGGLELOC: DB TRUE ;true=allow toggling of LOCONEXTCHR LSTTST: DB TRUE ;true=allow toggling of printer on/off ;in terminal mode. Set to false if your ;printer can't keep up with the modem XOFFTST: DB FALSE ;true=allow testing of XOFF from remote ;while transmitting a file in terminal mode XONWAIT: DB FALSE ;true=wait for XON after sending CR while ;transmitting a file in terminal mode TOGXOFF: DB TRUE ;true=allow toggling of XOFF/XON testing MSPEED: DB 1 ;sets the display time to send a file ;0=110 1=300 2=450 3=600 4=710 5=1200 ;6=2400 7=4800 8=9600 BYTDLY: DB 0 ;default time to send character in ;terminal mode file transfer ;0=0 delay, 1=0.02 sec, -- ,9=0.18 sec CRDLY: DB 0 ;default time for extra wait after CR ;in terminal mode file transfer ;0=0 delay, 1=0.02 sec, -- ,9=0.18 sec BELRPT: DB 30 ;bell repeat time = value*0.03 sec EXITCHR: DB 'E'-40H ; ^E = Exit without disconnect LOGCHR: DB 'O'-40H ; ^O = Send logon LSTCHR: DB 'P'-40H ; ^P = Toggle printer UNSAVECHR: DB 'R'-40H ; ^R = Close input text buffer TRANCHR: DB 'T'-40H ; ^T = Transmit file to remote SAVECHR: DB 'Y'-40H ; ^Y = Open input text buffer EXTCHR: DB '^'-40H ; ^^ = Send next character ; ;Equates used only by PMMI routines grouped together here. PULSERATE: DB 125 ;125 for 20pps, 250 for 10pps on PMMI ;not used if PMMI FALSE CLDBOOT: DW 00000H ;currently set to warm boot with ;BYE routine for PMMI, put your cold ;boot entry here if you have one and ;desire to do on BYE BRKCHR: DB '@'-40H ; ^@ = Transmit "BREAK" with PMMI CHGBAUD: DB 'B'-40H ; ^B = Used with PMMI in terminal ; mode to change baud rate on fly DISCCHR: DB 'D'-40H ; ^D = PMMI Disconnect ; ; IN$MODCTLP: IN MODCTLP ! RET ;in modem control port OUT$MODDATP: OUT MODDATP ! RET ;out modem data port IN$MODDATP: IN MODDATP ! RET ;in modem data port ANI$MODSNDB: ANI MODSNDB ! RET ;bit to test for send ready CPI$MODSNDR: CPI MODSNDR ! RET ;value of send bit when ready ANI$MODRCVB: ANI MODRCVB ! RET ;bit to test for receive ready CPI$MODRCVR: CPI MODRCVR ! RET ;value of receive bit when ready ; ;THE FOLLOWING ARE TYPICALLY USED ONLY BY PMMI IN$BAUDRP: IN BAUDRP ! RET ;in baudrate port OUT$BAUDRP: OUT BAUDRP ! RET ;out baudrate port OUT$MODCTL2: OUT MODCTL2 ! RET ;out modem control port #2 OUT$MODCTLP: OUT MODCTLP ;out modem control port STA UARTCTLB ! RET ;and store control byte ; LOGONPTR: DW LOGON JMP$INITMOD: JMP INITMOD JMP$SETUPR: JMP SETUPR ;Clear sequences are for H19. Change to yours. CLREOS: CALL JMP$ILPRT DB ESC,'J',0,0,0 RET CLRSCRN: CALL JMP$ILPRT DB ESC,'E',0,0,0 RET ; ;NEXT THREE LINES SHOULD NOT BE CHANGED BY USER OVERLAY JMP$ILPRT: JMP ILPRT JMP$ILCOMP: JMP ILCOMP JMP$INBUFF: JMP INBUFF JMP$SYSVER: JMP SYSVER JMP$DIALPL: JMP DIALPL JMP$DISCONNT: JMP DISCONNT ; SYSVER: LDA PMMIBYTE ;USING THE PMMI S-100 MODEM? ORA A JZ SYSVER1 ;GO IF NOT CALL ILPRT DB 'Version for: PMMI S-100 MODEM Starting at Port ',0 LDA IN$MODCTLP+1 CALL HEXO CALL ILPRT DB 'H',CR,LF,0 RET ; SYSVER1: CALL ILPRT ;IF NOT USING THE PMMI S-100 BOARD DB 'Version for: Non-PMMI MODEM',CR,LF,0 RET ; ;INSERT YOUR LOGON HERE, MUST END IN 0. LOGON: DB 0 ; ;INSERT YOUR INITIALIZATION ROUTINE HERE IF NEEDED. ;CAN REPLACE THE FOLLOWING SECTION WHICH IS PRESENTLY ;USED FOR THE PMMI BOARD. ; INITMOD: LDA PMMIBYTE ORA A RZ LDA ANSWFLG ;IF ANSWER OR ORIGINATE MODE.. ORA A ;..IS NOT REQUESTED OR NO.. JNZ SKIPB1 ;..BAUDRATE SPECIFIED, THEN.. CALL GETBAUD ;..ROUTINE RETURNS WITH CHANGE.. JMP FIXBAUD ;..OF BAUD. IF OPT REQUESTED,.. ; SKIPB1: LDA ORIGFLG ;..A BLANK FORCES 300 BAUD.. ORA A ;..ELSE A 0 FROM NEWBAUD.. RNZ ;..FORCES 300 BAUD. CALL GETBAUD FIXBAUD: CALL OUT$BAUDRP CALL CHGMSPD MOV A,C STA MSPEED MOV A,B CPI 52 MVI A,5FH JC GT300 MVI A,7FH GT300: CALL OUT$MODCTL2 STA MODCTLB ;SAVE MODEM CONTROL BYTE LDA ORIGFLG ORA A MVI A,ORIGMOD JZ OFFHOOK LDA ANSWFLG ORA A MVI A,ANSWMOD RNZ OFFHOOK: LXI H,4000 OFFDLY: DCR L JNZ OFFDLY DCR H JNZ OFFDLY CALL OUT$MODCTLP RET ; GETBAUD: LDA FCB+9 CPI ' ' MVI A,52 RZ LDA FCB+9 CPI 0 MVI A,52 RZ LXI D,FCB+9 LXI H,0 DECLP: LDAX D INX D CPI ' ' JZ DECLP CPI '0' JC BADRATE CPI '9'+1 JNC BADRATE SUI '0' MOV B,H MOV C,L DAD H DAD H DAD B DAD H ADD L MOV L,A JNZ DIGNC INR H DIGNC: MOV A,E CPI FCB+12 JNZ DECLP MOV A,H CMA MOV D,A MOV A,L CMA MOV E,A INX D LXI H,15625 LXI B,-1 DIVLP: INX B DAD D JC DIVLP MOV A,B ORA A MOV A,C RZ BADRATE: CALL ERXIT DB '++ Invalid baud rate ++$' ; CHGMSPD: ;CHANGES MSPEED FOR 110-710 BAUD MVI C,0 ;CONTAINS MSPEED MOV B,A ;SAVE BAUD RATE DIVISOR CPI 100 ; < 300 BAUD RNC INR C CPI 40 ; < 450 BAUD RNC INR C CPI 30 ; < 600 BAUD RNC INR C CPI 24 ; < 710 BAUD RNC INR C ;MUST BE 710 BAUD RET ; ;DIALING ROUTINES TAKEN (AND GREATLY MODIFIED) FROM PMMI MANUAL. ;MODEM CONTROL COMMAND WORDS ; CLEAR EQU 3FH ;IDLE MODE MAKEM EQU 1 ;TELE LINE MAKE (OFF HOOK) BRKM EQU 0 ;TELE LINE ON HOOK (BREAK DURING DIALING) DTMSK EQU 1 ;DIAL TONE MASK RBLMT EQU 70 ;# OF SEC*10 TO WAIT BEFORE GIVING NO RING HEARD MSG RBWAIT EQU 50 ;# OF SEC*10 DELAY BEFORE REDIALING NUMBER TMPUL EQU 80H ;TIMER PULSES MASK BIT TRATE EQU 250 ;VALUE FOR 0.1 SECOND ; DIALPL: LDA PMMIBYTE ;FLAG FOR PMMI OPERATION ORA A ;SET FLAGS RZ ;PMMI FALSE, RETURN XRA A ;0 STA CRFLAG ;CONTINUOUS REDIAL FLAG DPL1: LXI H,CMDBUF+1 ;POINT # OF CHARS IN BUFF MOV A,M ;GET # OF CHARS CPI 4 ;4 OR MORE CHARS TYPED BEFORE ? JC ENTNUM ;NO, ASK FOR NUMBER LXI H,CMDBUF+6 ;POINT TO NUMBER TO DIAL JMP DIAL10 ;CHECK IF LIB #, & DIAL ; DIALPL0: CALL DISCONNT CALL ILPRT DB CR,LF,'Waiting for dial tone',CR,LF,0 MVI A,MAKEM ;MAKE MAKE (OFF-HOOK) CALL OUT$MODCTLP ;DO IT MVI D,DTMSK ;DIAL TONE MASK MVI C,100 ;10 SECOND WAIT CALL WAIT ;WAIT FOR DIAL TONE NOP ;DELAY ; ; WAIT SUBROUTINE WILL RETURN WITH CARRY SET IF UNABLE TO ; GET DIALTONE, ELSE CARRY NOT SET MEANS DIALTONE RECEIVED ; RNC ;IF DIAL TONE WITHIN 10 SECONDS CALL ILPRT ;ELSE, MESSAGE AND RETURN WITH CARRY SET DB CR,LF,'<< No dial tone >>',CR,LF,0 CALL DISCONNT STC RET ; ;THIS IS ALL THE SET-UP FOR THE PRINT AT 'ENTNUM2'. ; ENTNUM: MVI C,13 ;NUMBER OF LINES TO MOVE LXI H,NUMBLIB ;ADDRESS OF SOURCE MEMORY LXI D,DBUF ;ADDRESS OF TARGET MEMORY CALL NEWLINE ;START WITH CRLF STAX D ;+LF INX D ;AND BUMP IT ENTNUM1: MVI B,32 ;NUMBER OF BYTES TO MOVE CALL MOVE ;MOVE TO BUFFER CALL SPACES ;2 ENTRIES + 3 SPACES = 67 CHARACTERS MVI B,32 CALL MOVE CALL NEWLINE DCR C ;NUMBER OF LINES TO PRINT JZ ENTNUM2 JMP ENTNUM1 ; ENTNUM2: MVI A,'$' STAX D CALL CLRTST MVI C,PRINT LXI D,DBUF ;POINT TO TABLE OF NUMBERS TO PRINT CALL BDOS CALL ILPRT DB CR,LF,'Enter number or library letter - when finished,' DB CR,LF,'Ctrl-X cancels while dialing: ',0 LXI D,CMDBUF CALL INBUFF DIALLP1: LDA CMDBUF+1 ORA A ;NULL MEANS WAS TYPED JZ BORTIT ;ABORT DIALING, RETURN TO MENU LXI H,CMDBUF+2 ;FIRST TYPED CHAR OF NUMBER TO DIAL ; ; ENTER THIS ROUTINE WITH HL POINTING TO NUMBER TO DIAL ; DIAL10: PUSH H ;SAVE HL CALL DIALPL0 ;DISCONNECT, RECONNECT, WAIT FOR DIAL TONE POP H ;GET HL JC DILAGN ;NO DIALTONE?, ASK RETRY MVI B,'A' ;FIRST LETTER OF ALPHABET MVI E,0 ;COUNTS NUMBER OF LETTERS TO MATCH MVI C,26 ;NUMBER OF LETTERS IN ALPHABET MOV A,M ;GET CHAR BUFFER DIAL11: CMP B ;NUMBER FROM TABLE? JZ LIBSET INR B ;MAKE NEXT LETTER (A-Z) INR E ;COUNT UP DCR C ;COUNT DOWN JZ DIALLPX ;NOT A LETTER JMP DIAL11 ;LOOP ; LIBSET: LXI H,NUMBLIB ;PHONE NUMBER LIBRARY LXI B,32 ;LENGTH OF LIBRARY ENTRY MOV A,E ;NUMBER OF TIMES TO ADD 32 TO HL ORA A ;SET FLAGS JZ DIAL13 DIAL12: MOV A,M ;GET FIRST CHAR OF SELECTED LIB ENTRY ORA A ;SET FLAGS JZ DIALLPA ;SEND BAD LIBRARY MSG AND ABORT DAD B ;INCREMENT HL BY 32 DCR E ;COUNTDOWN JNZ DIAL12 ;NOT THERE YET, LOOP DIAL13: MVI B,32 ;NUMBER OF CHARACTERS TO GET FROM TABLE LXI D,CMDBUF+1 ;POINT TO BUFFER XCHG ;HL POINTS TO CMDBUF+1 MOV M,B ;STORE # OF BYTES IN A TABLE ENTRY XCHG ;RESTORE REG. INX D ;POINT TO FIRST CHAR POSITION IN BUFFER CALL MOVE ;MOVE TABLE ENTRY TO BUFFER DIALLPX: LDA CMDBUF+1 MOV E,A ;NUMBER OF CHARS IN BUFF LXI H,CMDBUF+2 ;POINT FIRST CHAR DIALLP2: MOV A,M ;GET FIRST # FROM BUFFER ORA A ;SET FLAGS JNZ NOBLMSG ; ; PRINT BAD LIBRARY MESSAGE AND ABORT IF NULL ENCOUNTERED DIALLPA: CALL ILPRT DB CR,LF,'++ Bad library number called ++',CR,LF,0 JMP BORTIT ;ABORT ; ; DIAL A DIGIT, CHECK KBD FOR ABORT ; NOBLMSG: CALL DIAL ;DIAL IT CALL STAT ; KEYPRESS? ORA A ;SET FLAGS CNZ KEYIN ;YES, GO GET IT CPI CAN ;^X? JZ BORTIT ;YES, ABORT INX H ;BUMP POINTER PUSH D ;SAVE DE PUSH H ;SAVE HL MVI B,1 ;WAIT 1 TIME INTERVAL CALL TIMER POP H ;RESTORE HL POP D ;RESTORE DE DCR E ;COUNT DOWN CHARS IN BUFF JNZ DIALLP2 ;NOT DONE, LOOP JZ DIALDN ;DIALING DONE DISCONNT: XRA A ;0 CALL OUT$MODCTL2 ;CLEAR DAV, ESD, ETC CALL OUT$MODCTLP ;HANG-UP PUSH B MVI B,8 ;WAIT FOR PMMI TO DISCONNECT CALL TIMER POP B RET TIMER: MVI A,TRATE ;TRATE 250, VALUE FOR .1 SEC INTERVAL CALL OUT$BAUDRP ;B-REG CONTAINS NUMBER OF .1 SEC INTERVALS TIMES: CALL IN$BAUDRP ;TO COUNT ANI TMPUL JZ TIMES ;WAIT FOR TIMER TO GO HIGH TIMEE: CALL IN$BAUDRP ANI TMPUL JNZ TIMEE ;WAIT FOR TIMER TO GO LOW DCR B JNZ TIMES RET BORTIT: CALL DISCONNT CALL CRLF JMP MENU ; ;AUTO DIALER ; DIAL: CALL TYPE ;PRINT WHATEVER CHARACTER, DASHES, ETC. CPI 30H RC ;DIGIT MUST BE AT LEAST 0.. CPI 'R' ;COULD IT BE A RINGBACK CHARACTER JNZ DIAL1 ;NO? - JUMP PUSH PSW ;SAVE ACCUMULATOR & FLAGS MOV A,E ;GET # OF CHAR LEFT INTO ACC. CPI 01H ;IS THIS THE LAST CHARACTER? JZ RINGBK ;IF SO, IT MUST BE RINGBACK CHAR - DO RINGBACK POP PSW ;EVERYTHING BACK AS IT WAS DIAL1: CPI 3AH RNC ;..AND NOT MORE THAN 9 ANI 0FH ;STRIP ASCII -- COULD ALSO DO SUI 30H ('0') JNZ DIALS MVI A,10 ;CONVERT ZERO TO 10 PULSES DIALS: MOV C,A LDA PULSERATE ;CONTAINS VALUE FOR DIAL SPEED CALL OUT$BAUDRP DIALC: CALL IN$BAUDRP ANI TMPUL JNZ DIALC DIALB: CALL IN$BAUDRP ANI TMPUL JZ DIALB MAKEP: MVI A,MAKEM CALL OUT$MODCTLP TIMEM: CALL IN$BAUDRP ANI TMPUL JNZ TIMEM MVI A,BRKM CALL OUT$MODCTLP TIMEB: CALL IN$BAUDRP ANI TMPUL JZ TIMEB DCR C JNZ MAKEP MVI A,MAKEM CALL OUT$MODCTLP MVI B,2 CALL TIMER RET ; RINGBK: POP PSW ;TO GET IT OFF THE STACK LDA CMDBUF+1 ;GET # OF CHAR IN BUFFER SUI 01H ;SUBTRACT 1 TO AVOID THE RINGBACK CHAR STA CMDBUF+1 ;STORE THE NEW VALUE MVI D,DTMSK ;LOAD TONE DETECT MASK MVI C,RBLMT ;SET TIMER FOR RBLMT NUMBER OF SECONDS CALL WAIT JC RBTIME ;JUMP IF NO RING DETECTED MVI B,25 ;WAIT 2.5 SEC CALL TIMER CALL IN$BAUDRP ;IS TONE STILL PRESENT? ANA D JNZ RNGBK1 JMP DILAGN ;YES, MUST BE BUSY ; RNGBK1: CALL HANGP ;HANG UP THE PHONE MVI B,RBWAIT ;WAIT X SEC CALL TIMER CALL DIALPL0 ;GO OFF HOOK & LISTEN FOR DIAL TONE JNC DIALLPX ;GO REDIAL NUMBER JMP DILAGN ;NO DIAL TONE HEARD ; RBTIME: CALL CRLF JMP RNGBK1 ;HANGUP, REDIAL, & LISTEN FOR CARRIER ; ;TIME OUT ROUTINE. MUST BE CALLED WITH MASK IN D REG FOR INPUT ;AT RELATIVE PORT 2 AND NUMBER OF SECONDS * 10 IN C REG. ; WAIT: MVI B,1 CALL TIMER ;WAIT FOR TIMER TO GO HIGH THEN LOW CALL IN$BAUDRP ;PMMIADDR+2 (MODEM STATUS PORT) ANA D ;(CTS or DIALTONE MASK) RZ ;ACTIVE LOW, SO RETURN ON 0 PUSH B ;SAVE.. PUSH D ;..ACTIVE REG'S CALL STAT ;KEYPRESS? ORA A ;SET FLAGS CNZ KEYIN ;YES, GET CHAR CPI CAN ;^X? JZ WAIT1 ;YES, DISCONNECT, JMP TO MENU POP D ;RESTORE.. POP B ;..REGS DCR C ;COUNT-DOWN JNZ WAIT STC ;SET CARRY TO INDICATE MASK NOT SET RET ; WAIT1: POP D ;RESET.. POP B ;..STACK JMP DISCON1 ;DISCONNECT ; HANGP: MVI A,CLEAR CALL OUT$MODCTL2 MVI A,0 CALL OUT$MODCTLP RET ; DIALDN: CALL CRLF MVI A,07FH ;TURN ON DTR CALL OUT$MODCTL2 ;TIMER RATE? MVI B,1 CALL TIMER ;WAIT FOR MODEM TO TURN ON DTR MVI A,5DH ;2 STOP BITS, NO PARITY, 8 DATA BITS CALL OUT$MODCTLP MVI D,4 ;CLEAR TO SEND MASK MVI C,WAITCTS ;WQAIT TIME FOR CTS (25.5 SEC MAX) CALL WAIT JNC CONMADE ;CONNECTION MADE CALL DISCONNT DILAGN: LDA CRFLAG ;CONTINUOUS REDIAL FLAG ORA A JNZ DILAGN0 CALL ILPRT DB CR,LF,'No answer after time-out. Redial? (Y/N/C): ',BELL,0 CALL KEYIN ;GET RESPONSE CALL TYPE ;ECHO IT CALL UCASE ;ANI 5FH CALL CRLF ;NEW LINE CPI 'N' ;REDIAL? JZ MENU ;NO, GO MENU CPI 'Y' ;REDIAL? JZ DILAGN0 ;YES, REDIAL CPI 'C' ;CONTINUOUS REDIAL? JNZ DILAGN ;INVALID RESPONSE, ASK AGAIN XRA A CMA ;0FFH STA CRFLAG ;CONTINUOUS REDIAL FLAG DILAGN0: MVI B,70 ;7 SECONDS WAIT FOR PMMI RESET CALL TIMER ;ELSE BUSY TONE MAY BE SENSED AS DIALTONE LXI H,CMDBUF+1 ;CHECK IF 'CAL LIBNUM' MOV A,M CPI 4 ;MORE THAN 4 CHARACTERS TYPED JC DIALLP1 ;NO, THEN GET MENU CHOICE JMP DPL1 ;YES, THEN USE CAL LETTER ; CONMADE: CALL ILPRT DB CR,LF,'Connection established - Select options: ',BELL,0 DILAGN1: CALL STAT ;KEYPRESS? ORA A ;SET FLAGS JNZ GETCMD ;KEY PRESSED, GO GET OPTIONS MVI A,BELL CALL TYPE ;RING BELL LXI B,2000H DILAGN2: DCR C JNZ DILAGN2 ;KILL SOME TIME FOR TERMINAL TO PROCESS BELL DCR B JNZ DILAGN2 JMP DILAGN1 ;LOOP ; CRFLAG: DB 0 ;CONTINUOUS REDIAL FLAG ; ; END OF PMMI ROUTINES ; ; ;THE NON PMMI SETUP ROUTINES ARE INTENDED TO COME FROM ;THE USER OVERLAY. THE FOLLOWING IS A SAFETY NET ; SETUPR: RET ; ; PHONE NUMBER LIBRARY TABLE FOR DIALING FROM LIBRARY ; OF NUMBERS STORED IN THESE DB'S AT ASSEMBLY-TIME. ; EACH DB MUST BE 32 CHARACTERS LONG FOR PROPER OPERATION. ; A 'DB 0' INDICATES NO DIALING, PROGRAM WILL DISCONNECT ; AND RETURN TO COMMAND MODE. LAST DB MUST BE DB 0. UP TO ; 26 NUMBERS ARE ALLOWED. ; NUMBLIB: ; '----5---10---15---20---25-----32' DB 'A=Amrad 1-703-734-1387' ;'A' DB 'B=Ben Bronson 1-312-955-4493' ;'B' DB 'C=CBBS Pasadena 1-213-799-1632' ;'C' DB 'D=PMMI 1-703-379-0303' ;'D' DB 'E=Tech. CBBS 1-313-846-6127' ;'E' DB 'F=Ron Fowler 1-313-729-1905R' ;'F' DB 'G=Gasnet NASA 1-301-344-9156' ;'G' DB 'H=Dave Hardy 1-313-846-6127' ;'H' DB 'I=Wayne Hammerly 1-301-953-3753' ;'I' DB 'J=RBBS Pasadena 1-213-356-1034' ;'J' DB 'K=David Kozinn 1-216-334-4604' ;'K' DB 'L=Program Store 1-202-337-4694' ;'L' DB 'M=Kelly Smith 1-805-527-9321' ;'M' DB 'N=SuperBrain Sys 1-617-862-0781' ;'N' DB 'O=R.L.Plouffe 1-703-524-2549' ;'O' DB 'P=K.Petersen 1-313-759-6569R' ;'P' DB 'Q=Bruce Ratoff 1-201-272-1874' ;'Q' DB 'R=Mark Pulver 1-312-789-0499' ;'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 ; '----5---10---15---20---25-----32' ; START: LXI H,0 DAD SP ;GET CP/M'S STACK SHLD STACK ;SAVE IT LXI SP,STACK ;START LOCAL STACK CALL ILPRT DB CR,LF,'MODEM 7.98 - 12/31/82',CR,LF,0 CALL INITADR ;INITIALIZE ADDRESSES CALL JMP$SYSVER ;GIVE CONFIGURATION MESSAGE CALL GETUSR ;GET USER STA SAVUSR ;SAVE FOR EXIT MVI A,TRUE ;0FFH STA NFILFLG CMA ;0 STA SAVEFLG LDA FCB+1 ;IS THERE A COMMAND TAIL? STA OPTION CPI ' ' JNZ START0 ;IF YES, DIGEST IT SUB A STA EXITFLG ;ELSE SAY WE WANT MENU JMP START1 START0: LXI H,80H ;SIMULATE COMMAND LINE INPUT FROM MENU MOV B,M ;SAVE CHAR CNT STARTA: INX H MOV A,M ;SKIP OVER LEADING SPACES IN COMMAND TAIL CPI ' ' JNZ STARTB DCR B JMP STARTA STARTB: MOV A,B STA CMDBUF+1 ;STORE COMMAND CHAR COUNT LESS LEADING SPACES INR B ;MOVE 1 EXTRA BYTE (SHOULD BE A NULL) LXI D,CMDBUF+2 CALL MOVE CALL SETFCB ;DIGEST COMMAND LINE AND OPTIONS START1: LDA UARTFLG ORA A MVI A,ANSWMOD STA UARTCTLB JNZ RESTART MVI A,ORIGMOD STA UARTCTLB ; RESTART: LXI SP,STACK;MAKE SURE WE HAVE A CLEAN STACK LXI D,CMDBUF+1 ;MAY BE USEFUL WHERE WE ARE GOING LDA OPTION ;GET MAIN OPTION MOV B,A ;SAVE IT LDA PMMIBYTE ;PMMI? ORA A ;SET FLAGS MOV A,B ;GET OPTION BACK JZ S1 ;NOT PMMI CPI 'C' ;CALL (DIAL) FUNCTION? JZ JMP$DIALPL ;YES, GO TO IT CPI 'D' ;DISCONNECT? JZ DISCON1 ;YES, DISCONNECT & GO MENU S1: CPI ' ' ;NO OPTION SPEC'D? JZ MENU ;TRUE, GO MENU CPI 'H' ;MENU ASKED FOR? JZ MENU2 ;YES, GO MENU2 CALL JMP$INITMOD CALL MOVEFCB CALL IN$MODDATP ;GOBBLE UP GARBAGE.. CALL IN$MODDATP ;..CHARACTERS ON LINE XRA A STA ECHOFLG ;RESET ECHO FLAG STA LOCFLG ;RESET LOCAL FLAG LDA OPTION ;PROCESS MAIN OPTION CPI 'E' ;ECHO MODE? JNZ NOECH ;JUMP IF NOT MVI A,TRUE ;SET ECHO TO TRUE STA ECHOFLG JMP DSKSAVE NOECH: CPI 'L' ;LOCAL ECHO MODE JNZ NOLOC MVI A,TRUE STA LOCFLG JMP DSKSAVE NOLOC: CPI 'T' ;TERMINAL MODE? JZ DSKSAVE ;YES CPI 'S' ;SEND A FILE? JZ SENDFIL ;YES CPI 'R' ;RECEIVE A FILE? JZ RCVFIL ;YES CALL NOTVLDMSG ;SAY NOT A VALID OPTION JMP MENU ;NO VALID OPTION SPEC'D, GO MENU ; ;REVISED TERMINAL ROUTINE ALLOWING MEMORY SAVE ; DSKSAVE: LDA FCB+1 ;FIRST CHAR OF FILENAME CPI ' ' ;FILE SPEC'D JNZ GOODNM ;YES, GOOD NAME MVI A,TRUE ;0FFH STA NFILFLG CMA ;0 STA SAVEFLG JMP TERM ; GOODNM: CALL ERASFIL CALL MOVE2 LXI D,FCB3 MVI C,MAKE CALL BDOS LXI D,FCB3 MVI C,OPEN CALL BDOS LXI H,BOTTRAM SHLD HLSAVE XRA A STA NFILFLG STA LISTMOR ;STOP ANY BUFFERED PRINTER OUTPUT TERM: LDA UARTFLG STA ORIGSAV ORA A MVI A,ANSWMOD STA UARTCTLB JNZ TERM2 MVI A,ORIGMOD STA UARTCTLB TERM2: LDA LISTMOR ;ANY BUFFERED PRINTER OUTPUT? ORA A CNZ GOLIST ;GO IF SO CALL STAT ;KEYPRESS? JZ TERML ;NO, CHECK LINE CALL KEYIN ;GET CHAR FROM KBD CPI ' ' JNC NOTOG ;GO IF NOT CONTROL CHARACTER MOV B,A ;SAVE CPI BKSP ;TEST FOR BACKSPACE JNZ NOBKSP LDA CONVBKSP ;CONVERT BACKSPACE TO RUB? ORA A JZ NOBKSP ;GO IF NO CONVERSION MVI A,RUB JMP NOTOG NOBKSP: LDA EXACFLG ORA A ;EXACT? MVI A,0 STA EXACFLG ;CLR FOR NEXT TIME JZ NOTEXAFLG ;GO OF EXAFLG FALSE LDA LOCONEXTCHR ORA A ;SHOULD WE SEND ON EXAFLG? MOV A,B JZ NOTOG ;YES, IF LOCONEXTCHR FALSE LDA EXTCHR ;WE WANT TO SEND EXTCHR IN ANY CASE CMP B MOV A,B JZ NOTOG ;SEND IF EXTCHR JMP LOCCHK ;OTHERWISE DO LOCAL STUFF NOTEXAFLG: LDA EXTCHR ;TREAT NEXT CHARACTER IN SPECIAL WAY? CMP B JZ EXTFLG ;YES, SET EXAFLG FOR NEXT CHAR LDA LOCONEXTCHR ORA A ;SHOULD WE SEND IF NOT EXAFLG MOV A,B JNZ NOTOG ;YES, IF LOCONEXTCHR TRUE LOCCHK: LDA EXITCHR ;RETURN TO MENU? CMP B JZ EXITMEN ;YES, RETURN TO MENU LDA TRANCHR ;OUTPUT TEXT FILE TO REMOTE? CMP B CZ TRANSFER ;SEND-A-FILE (BLIND SEND) JZ TERM2 ;LOOP LDA TRANLOGON ORA A JZ SKPLOGON LDA LOGCHR ;SEND LOGON? CMP B JZ SENDLOG SKPLOGON: LDA LSTTST ORA A JZ NOLST LDA LSTCHR CMP B JNZ NOLST LDA LISTFLG CMA STA LISTFLG CALL CRLF CALL CRLF CALL LSTMSG CALL CRLF JMP TERML NOLST: LDA PMMIBYTE ORA A JZ S2 LDA DISCCHR ;PMMI DISCONNECT? CMP B JZ DISCON1 ;YES, DISCONNECT & RETURN TO MENU LDA BRKCHR ;PMMI BREAK? CMP B JZ BREAK LDA CHGBAUD ;PMMI CHANGE BAUD? CMP B PUSH PSW PUSH H CZ NEWBAUD POP H POP PSW JZ TERML S2: LDA UNSAVECHR ;CLOSE INPUT BUFFER? CMP B JZ S2A ;IF YES, DISABLE COPY LDA SAVECHR ;OPEN INPUT BUFFER? CMP B MOV A,B ;RESTORE CHARACTER TYPED JNZ NOTOG LDA NFILFLG ;DO NOT ALLOW SAVE IF.. CPI TRUE ;..THIS FLAG IS SET. JZ TERML MVI A,TRUE ;0FFH -- ALLOW COPY INTO FILE JMP S2B S2A: MVI A,FALSE ;0 -- STOP COPY INTO FILE S2B: STA SAVEFLG CALL BUFMSG JMP TERML ; BUFMSG: CALL ILPRT DB CR,LF,LF,'** Memory buffer ',0 LDA SAVEFLG ORA A JZ BUFMSG2 CALL ILPRT DB 'open **',CR,LF,LF,':',BELL,0 RET ; BUFMSG2: CALL ILPRT DB 'closed **',CR,LF,LF,BELL,0 RET ; EXITMEN: CALL CRLF CALL CLREOS ;CLEAR TO END OF SCREEN TO CLEAN UP ANY MESS JMP MENU0 ; SENDREADY: CALL IN$MODCTLP CALL ANI$MODSNDB JMP CPI$MODSNDR ; SENDLF: CALL SENDREADY JNZ NOLFYET ;GO IF NOT READY FOR OUTPUT YET MVI A,LF JMP NOTOG ;SEND LF NOLFYET: CALL EXITTEST JNC EXITMEN ;GO IF SO, SO DON'T GET HUNG UP JMP SENDLF ;ELSE KEEP TRYING TO SEND LF ; SENDLOG: PUSH H LHLD LOGONPTR ;HL POINTS TO START OF LOGON MESSAGE LOGLP: CALL SENDREADY JNZ NOSENDLOG ;GO IF NOT READY MOV A,M ;GET LOGON BYTE INX H CPI 0 ;IS IT THE END? JZ ENDLOG ;GO IF SO CALL OUT$MODDATP JMP LOGLP NOSENDLOG: CALL EXITTEST ;TEST SO DON'T GET HUNG UP JNC EXITLOG ;GO IF OPERATOR WANTS EXIT JMP LOGLP ; ENDLOG: POP H JMP TERML ; EXITLOG: POP H JMP EXITMEN ; EXITTEST: CALL STAT ;KEYPRESS? JZ NOKEY CALL KEYIN MOV B,A LDA EXITCHR ;SEE IF OPERATOR WANTS EXIT CMP B JNZ NOKEY ;GO IF WRONG KEY STC CMC ;RESET FOR EXIT RET NOKEY: STC ;SET FOR NO KEY OR WRONG KEY RET ; EXTFLG: MVI A,TRUE STA EXACFLG JMP TERML ; RCVREADY: CALL IN$MODCTLP CALL ANI$MODRCVB JMP CPI$MODRCVR ; LSTMSG: LDA LISTFLG ORA A JZ LSTMSG2 CALL ILPRT DB 'Printer is on',CR,LF,0 RET LSTMSG2: CALL ILPRT DB 'Printer is off',CR,LF,0 RET ; NOTOG: CALL OUT$MODDATP MOV B,A LDA LOCFLG ORA A JNZ LTYPE LDA ECHOFLG ORA A JZ CHKCR LTYPE: MOV A,B CALL TYPE CALL CHKSAVE ;TO STORE LOCAL IF BUFFER OPEN CALL CHKPRNT CHKCR: MVI A,CR CMP B JNZ TERML LDA ADDLF ORA A JZ TERML JMP SENDLF ; TERML: CALL RCVREADY ;TEST FOR RECEIVED CHARACTER JNZ TERM2 CALL IN$MODDATP ANI 7FH ;STRIP PARITY JZ TERM2 GIVLF: CALL TYPE MOV B,A CALL CHKSAVE CALL CHKPRNT LDA ECHOFLG ORA A JZ NOECHO MOV A,B CALL OUT$MODDATP NOECHO: MVI A,CR CMP B JNZ TERM2 LDA ADDLF JZ TERM2 LDA ECHOFLG ORA A JNZ SENDLF MVI A,LF JMP GIVLF ; CHKSAVE: LDA SAVEFLG ORA A RZ MOV M,B INX H SHLD HLSAVE ;MENU COMMAND DESTROYS HL-REG.. MVI A,LF CMP B JNZ NOCOLON ;..TYPE ":" AFTER EACH LINE FEED.. MVI A,':' ;..WHEN MEMORY SAVE ACTIVE. CALL TYPE NOCOLON: CALL GETMAX CMP H PUSH B CZ INTDSKSV POP B RET ; GETMAX: LDA SAVCCP ORA A LDA 7 JZ SUB1 SBI 8 ;..PAGE BELOW CCP .. SUB1: DCR A ;..OR BDOS HAS BEEN.. RET ;..REACHED AND DISKSAVE IS NEEDED. ; CHKPRNT: LDA LISTFLG ;OUT TO PRINTER? ORA A RZ ;RETURN IF NOT LDA NFILFLG ;IS BUFFER USED FOR FILE? ORA A JZ NOBUFF ;DON'T BUFFER PRINTER IF SO, HOWEVER CHARACTERS ;WILL BE LOST IF PRINTER IS SLOWER THAN MODEM CALL GETMAX ;GET MAXIMUM FOR BUFFER LHLD HLSAVE1 CMP H ;ARE WE THERE? JNZ NOTMAX ;GO IF NOT LXI H,BOTTRAM ;FLUSH BUFFER SHLD HLSAVE1 SHLD HLSAVE2 NOTMAX: MOV M,B ;SAVE CHARACTER IN BUFFER INX H ;INCREMENT END OF BUFFER SHLD HLSAVE1 MVI A,TRUE ;SET FLAG FOR PRINTER OUTPUT STA LISTMOR RET ; NOBUFF: CALL LSTSTAT RZ ;RETURN IF PRINTER BUSY MOV C,B ;ELSE PRINT CHARACTER JMP LISTER ; GOLIST: CALL LSTSTAT RZ ;RETURN IF PRINTER BUSY LHLD HLSAVE2 ;GET LOCATION OF NEXT CHARACTER TO PRINT MOV C,M ;GET CHARACTER INX H ;INCREMENT POINTER SHLD HLSAVE2 CALL CMPBUFF ;CHECK FOR END OF BUFFER JMP LISTER ;PRINT ; ;ROUTINE CHECKS FOR END OF BUFFER, RESETS BUFFER IF SO AND STOPS ;PRINTER OUTPUT ; CMPBUFF: LHLD HLSAVE2 XCHG LHLD HLSAVE1 MOV A,L SUB E MOV L,A MOV A,H SBB D ORA L RNZ LXI H,BOTTRAM SHLD HLSAVE1 SHLD HLSAVE2 XRA A STA LISTMOR RET ; INTDSKSV: MVI A,XOFF ;SEND A CTRL-S TO STOP.. CALL OUT$MODDATP ;..REMOTE COMPUTER OUTPUT. MVI D,0 ;D IS THE BUFFER COUNT CALL INMODEM ;GET LAST BYTES SENT.. STA LASTBYT1 ;..AFTER CTRL-S. CALL INMODEM ;ADD MORE CALLS TO INMODEM.. STA LASTBYT2 ;..AND STA LASTBYT# IF YOU ARE.. PUSH D CALL NUMREC1 CALL WRTDSK ;WRITE THE RECORDS POP D LXI H,BOTTRAM INR D DCR D ;TEST BUFFER COUNT FOR ZERO JZ CTRLQ LDA LASTBYT1 ;GET THE LAST BYTES THAT WERE.. MOV M,A ;..SAVED AND PUT THEM IN.. INX H ;..BOTTRAM. CALL TYPE DCR D JZ CTRLQ LDA LASTBYT2 MOV M,A INX H CALL TYPE CTRLQ: MVI A,XON ;SEND START CHARACTER.. JMP OUT$MODDATP ;..TO REMOTE COMPUTER. ; BREAK: PUSH D ;SAVE IT LXI D,0 ;ZERO IT LDA MODCTLB ;GET THE LAST MODEM CONTROL BYTE ANI 0FBH ;SET THE TRANSMIT BREAK BIT LOW - ACTIVE LOW CALL OUT$MODCTL2 ;SEND IT TO THE MODEM PUSH H LXI H,225 CALL FIXCNT PUSH H POP B POP H BRK1: CALL TIMERL JZ BRK2 ;IF TIME IS UP RESET BREAK CPI 0 ;CHECK FOR NULLS JZ BRK1 ;DON'T PROCESS THEM ANI 7FH ;STRIP PARITY CALL TYPE PUSH PSW LDA SAVEFLG CPI FALSE JZ NOSAVEB POP PSW MOV M,A INX H SHLD HLSAVE ;MENU COMMAND DESTROYS HL-REG.. ;..GET HL WHEN ENTERING VIA 'NOL' CMD. COLONB: CPI LF JNZ BRK1 ;..TYPE ":" AFTER EACH LINE FEED.. MVI A,':' ;..WHEN MEMORY SAVE ACTIVE. CALL TYPE JMP BRK1 ; NOSAVEB: POP PSW ;RESTORE IT JMP BRK1 ; BRK2: LDA MODCTLB ;GET MODEM CONTROL BYTE CALL OUT$MODCTL2 POP D LHLD HLSAVE ;LAST ADDRESS WRITTEN IF DATA BEING SAVED LDA SAVCCP ORA A JZ SUB2 LDA 7 ;CHECK TO SEE IF.. SBI 8 ;..PAGE BELOW CCP .. JMP SUB2A ; SUB2: LDA 7 SUB2A: DCR A ;..OR BDOS HAS BEEN .. CMP H ;..REACHED AND DISKSAVE IS NEEDED. JNZ TERM2 ;NO PROBLEM - GO BACK TO NORMAL ROUTINE CALL ILPRT DB CR,LF,'Memory save buffer full',CR,LF,BELL,0 JMP TERM2 ; ;THIS SUBROUTINE WILL LOOP UNTIL THE MODEM RECEIVES A CHARACTER ;OR 100 MILLISECONDS. IF A CHARACTER IS RECEIVED, A FLAG IS SET ;TO STORE THE CHARACTER. A MAXIMUM OF TWO CHARACTERS ARE STORED, ;BUT MORE MAY BE STORED IF DESIRED (SEE COMMENT IN "INTDSKSV" ;ABOVE). ; INMODEM: PUSH H LXI H,625 CALL FIXCNT PUSH H POP B POP H TIMERL: CALL RCVREADY JZ GETBYTE DCX B MOV A,B ORA C JNZ TIMERL RET ; GETBYTE: CALL IN$MODDATP INR D RET ; NUMRECS: MVI M,EOFCHAR INX H LXI D,127 DAD D NUMREC1: LXI D,-(BOTTRAM) DAD D MOV A,L ;DIVIDE HL BY 128.. ORA A RAL ;..TO GET THE.. MOV L,H ;..NUMBER OF SECTORS MVI H,0 PUSH PSW DAD H POP PSW MVI A,0 ADC L MOV L,A ;RETURNS WITH NUMBER OF.. RET ;..128 BYTE RECORDS IN HL. ; WRTDSK: LXI D,BOTTRAM NEXTWRT: MVI C,STDMA CALL BDOSRT PUSH D LXI D,FCB3 MVI C,WRITE CALL BDOSRT POP D XCHG PUSH D LXI D,128 DAD D POP D XCHG DCX H MOV A,H ORA L JNZ NEXTWRT RET ; CLOSE3: LXI D,FCB3 MVI C,CLOSE JMP BDOS ; BDOSRT: PUSH B PUSH D PUSH H PUSH PSW CALL BDOS POP PSW POP H POP D POP B RET ; MOVE2: LXI H,FCB3 CALL INITFCBS LXI H,FCB LXI D,FCB3 MVI B,12 JMP MOVE ; ;FILE TRANSFER ROUTINE - CALLED WITH ;CONTROL-T FROM TERMINAL ROUTINE. ;TRANSFER MAY BE CANCELLED WHILE SENDING BY USING CONTROL-X. ; TRANSFER: PUSH H PUSH D PUSH B PUSH PSW LXI H,FCB4 CALL INITFCBS ;INITIALIZES FCBS POINTED.. LXI H,FCB+16 ;..TO BY HL REG. CALL INITFCBS GET: CALL GETNAME LDA CMDBUF+2 ;WAS FILE ENTERED CPI 20H JZ TRANSL2 CALL MOVE4 CALL OPEN4 CPI 0FFH ;RETURN WITH 0FFH MEANS JNZ CONTIN ;FILE DOES NOT EXIST TRANSL1: CALL ILPRT DB CR,LF,'++File does not exist++',CR,LF,0 TRANSL2: CALL ILPRT DB 'Type "R" to return to modem',CR,LF DB 'Type "A" to re-enter name: ',BELL,0 CALL KEYIN CALL UCASE CALL TYPE ;ECHO RESPONSE CALL CRLF CPI 'A' JZ GET CPI 'R' JZ RETURN JMP TRANSL2 ; CONTIN: LXI D,80H MVI C,STDMA CALL BDOS READMR: CALL READ80 CPI 1 ;END OF FILE JZ RETURNS CPI 2 ;BAD READ JZ RETURNU CALL SEND80C CPI EOFCHAR ;END OF FILE - OMIT IF OBJECT.. JZ RETURNS ;..CODE IS TO BE SENT. CPI CAN ;CANCELLATION? JZ TRANCAN JMP READMR ; RETURNS: CALL ILPRT DB CR,LF,'++File transfer completed++',CR,LF,BELL,0 JMP RETURN ; RETURNU: CALL ILPRT DB CR,LF,'++File transfer unsuccessful++',CR,LF,BELL,0 JMP RETURN ; TRANCAN: CALL ILPRT DB CR,LF,LF,'++ Transfer cancelled ++',CR,LF,BELL,0 RETURN: POP PSW POP B POP D POP H RET ; INITFCBS: ;ENTRY AT +2 WILL LEAVE.. MVI M,0 ;..DRIVE NO. INTACT. INX H ;WILL INITIALIZE AN FCB.. MVI B,11 ;..POINTED TO BY HL-REG. FILLS 1ST POS LOOP10: MVI M,' ' ;..WITH 0, NEXT 11 WITH.. INX H ;..WITH BLANKS, AND LAST.. DCR B ;..21 WITH NULLS. JNZ LOOP10 MVI B,21 LOOP11: MVI M,0 INX H DCR B JNZ LOOP11 RET ; GETNAME: CALL ILPRT DB CR,LF,'Enter file name to be transferred - C/R TO QUIT: ',0 LXI D,CMDBUF CALL INBUFF JMP CRLF ; MOVE4: LXI D,CMDBUF LXI H,FCB4 JMP CPMLINE ; OPEN4: LXI D,FCB4 MVI C,OPEN JMP BDOS ; READ80: LXI D,FCB4 MVI C,READ JMP BDOS ; SEND80C: MVI B,80H LXI H,80H SENDCH1: PUSH D CALL SPEED POP D MOV A,M CALL MODOUT CPI EOFCHAR RZ CALL STAT ;TEST TO SEE IF ORA A ;CANCELLATION REQUESTED JZ SKIP12 CALL KEYIN CPI CAN RZ SKIP12: INX H DCR B JNZ SENDCH1 RET ; MODOUT: PUSH PSW MODOUTL: LDA XOFFTST ORA A CNZ TXOFF CALL SENDREADY JNZ MODOUTL POP PSW CALL OUT$MODDATP CALL TYPE CPI CR JZ DLYCR RET ; DLYCR: INX H ;ALWAYS DISPLAY LF AFTER CR MVI A,LF CMP M DCX H JZ LFSKIP CALL TYPE LFSKIP: LDA XONWAIT ;WAIT FOR XON AFTER CR? ORA A JNZ WAITXON LDA CRDLY ;EXTRA DELAY AFTER CR JMP DLYCR2 ; SPEED: LDA BYTDLY ;GET SPEED VALUE (0-9) ;DELAY IS FROM 0.02 SEC FOR SPDVAL = 1 ;TO 0.18 SEC FOR SPDVAL = 9 DLYCR2: ORA A RZ ;RETURN IF 0 MOV C,A SPDLP: CALL SPD1 ;OUTER LOOP DCR C RZ JMP SPDLP ; SPD1: PUSH H LXI H,357 ;ABOUT 0.02 SEC AT 2 MHZ LDA XOFFTST ORA A JZ SPD2 LXI H,102 ;ADJUST FOR XOFF TESTING LDA ECHOFLG ORA A JZ SPD2 LDA LOCFLG ORA A JZ SPD2 LXI H,76 ;ADJUST AGAIN FOR REMOTE ECHO SPD2: CALL FIXCNT PUSH H POP D POP H SPDLP1: DCX D ;INNER LOOP LDA XOFFTST ORA A CNZ TXOFF MOV A,E ORA D RZ JMP SPDLP1 ; TXOFF: CALL RCVREADY RNZ CALL IN$MODDATP ANI 7FH CPI XOFF CZ WAITXON RET ; WAITXON: CALL RCVREADY JNZ WTXON2 CALL IN$MODDATP ANI 7FH CPI XON RZ WTXON2: CALL STAT ;TEST TO SEE IF ORA A ;CANCELLATION REQUESTED JZ WAITXON ;SO DON'T GET HUNG UP CALL KEYIN CPI CAN RZ JMP WAITXON ; ;SEND A CP/M FILE ; SENDFIL: MVI A,TRUE ;ALWAYS FORCE CHECKSUM MODE INITIALLY ON SEND STA CKSUMFLG SENDFIL1: CALL PARITY ;SET PARITY IF REQUESTED LDA BATCHFLG ;CHECK IF MULTIPLE FILE.. ORA A ;..MODE IS SET. JNZ SENDC1 MVI A,TRUE ;INDICATE SEND FOR BATCH MODE STA SENDFLG LDA FSTFLG ;IF FIRST TIME THRU.. ORA A ;..SCAN THE COMMAND LINE.. CNZ TNMBUF ;..FOR MULTIPLE NAMES. CALL SENDFN ;SENDS FILE NAME TO RECEIVER JNC SENDC2 ;CARRY SET MEANS NO MORE FILES. MVI A,'B' ;STOP BATCH.. STA BATCHFLG ;..MODE OPTION. MVI A,EOT ;FINAL XFER END CALL SEND JMP DONE ; SENDC1: LDA FCB+1 CPI ' ' JZ BLKFILE SENDC2: CALL CNREC ;GET NUMBER OF RECORDS CALL OPENFIL MVI E,80 CALL WAITNAK SENDLP: CALL RDSECT JC SENDEOF CALL INCRSNO MVI A,1 STA ERRCT SENDRPT: CALL SENDHDR CALL SENDSEC LDA CKSUMFLG ORA A CZ SENDCRC CNZ SENDCKS CALL GETACK JC SENDRPT JMP SENDLP ; SENDEOF: MVI A,EOT CALL SEND CALL GETACK JC SENDEOF JMP DONE ; ;RECEIVE A FILE ; RCVFIL: LDA CKSUMDFLT ;GET MODE REQUESTED BY OPERATOR STA CKSUMFLG ;STORE IT RCVFIL1: CALL PARITY ;SET PARITY IF REQUESTED LDA BATCHFLG ;CHECK IF MULT.. ORA A ;..FILE MODE. JNZ RCVC1 MVI A,FALSE ;FLAG WHERE TO RETURN.. STA SENDFLG ;..FOR NEXT FILE TRANS. CALL GETFN ;GET THE FILE NAME. JNC RCVC2 ;CARRY SET MEANS NO MORE FILES. MVI A,'B' ;STOP BATCH.. STA BATCHFLG ;..MODE OPTION. JMP DONE ; RCVC1: LDA FCB+1 ;MAKE SURE FILE IS NAMED CPI ' ' JZ BLKFILE ; RCVC2: CALL CKCPM2 CALL CKBAKUP RCVC3: CALL ERASFIL CALL MAKEFIL LDA BATCHFLG ORA A ;DON'T PRINT MSG IF.. JZ RCVFST ;..IN BATCH CALL ILPRT DB 'File open, ready to receive',CR,LF,0 RCVFST: LDA CKSUMFLG ORA A MVI A,NAK JNZ RCVFIL2 MVI A,CRC RCVFIL2: CALL SEND LDA QFLG ORA A JZ RCVLP LDA CKSUMFLG ORA A JNZ RCVNAKM ;IF IN CRC MODE CALL ILPRT ;THEN SAY SO DB 'CRC in effect',CR,LF,0 JMP RCVLP RCVNAKM: CALL ILPRT ;ELSE SAY CHECKSUM MODE DB 'Checksum in effect',CR,LF,0 RCVLP: CALL RCVSECT JC RCVEOT CALL WRSECT CALL INCRSNO CALL SENDACK JMP RCVLP ; RCVEOT: CALL WRBLOCK CALL SENDACK CALL CLOSFIL JMP DONE ; ;SUBROUTINES ; SENDFN: LDA QFLG ORA A JZ SWNAK CALL ILPRT DB 'Awaiting name NAK',CR,LF,0 SWNAK: MVI E,80 CALL WAITNLP MVI A,ACK ;GOT NAK, SEND ACK CALL SEND LXI H,FILECT DCR M JM NOMRNM LHLD NBSAVE ;GET FILE NAME.. LXI D,FCB ;..IN FCB MVI B,12 CALL MOVE SHLD NBSAVE CALL SENDNM ;SEND IT ORA A ;CLEAR CARRY RET ; NOMRNM: MVI A,EOT CALL SEND STC RET ; SENDNM: PUSH H SENDNM1: MVI D,11 ;COUNT CHARS IN NAME MVI C,0 ;INIT CHECKSUM MOV A,C STA FTYCNT ;INITIATE FILE TYPE COUNT 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 JZ ACKLP CALL FTYTST ;TYPE CHARACTER ETC. ACKLP: PUSH B ;SAVE CKSUM MVI B,1 ;WAIT FOR RECEIVER.. CALL RECV ;..TO ACKNOWLEDGE.. POP B ;..GETTING LETTER. JC SCKSER CPI ACK JNZ ACKLP INX H ;NEXT CHAR DCR D JNZ NAMLPS MVI A,EOFCHAR ;TELL RECEIVER END OF NAME CALL SEND LDA QFLG ORA A CNZ CRLF MOV D,C ;SAVE CHECKSUM MVI B,1 CALL RECV ;GET CHECKSUM.. CMP D ;..FROM RECEIVER. JZ NAMEOK SCKSER: MVI A,BDNMCH ;BAD NAME-TELL RECEIVER CALL SEND LDA QFLG ORA A JZ SKCSER1 CALL ILPRT DB 'Checksum error',CR,LF,0 SKCSER1: MVI E,80 ;DO HANDSHAKING OVER CALL WAITNLP ;DON'T PRINT "AWAITING NAK" MSG MVI A,ACK CALL SEND JMP SENDNM1 ; NAMEOK: MVI A,OKNMCH ;GOOD NAME-TELL RECEIVER CALL SEND POP H RET ; GETFN: LXI H,FCB CALL INITFCBS+2 ;DOES NOT INITIALIZE DRIVE LDA QFLG ORA A JZ GNAMELP CALL ILPRT DB 'Awaiting file name',CR,LF,0 GNAMELP: CALL HSNAK JC GNAMELP CALL GETNM ;GET THE NAME CPI EOT ;IF EOT, THEN NO MORE FILES JZ NOMRNMG ORA A ;CLEAR CARRY RET ; NOMRNMG: STC RET ; GETNM: PUSH H GETNM1: MVI C,0 ;INIT CHECKSUM MOV A,C STA FTYCNT ;INITIATE COUNT FOR FILE TYPE LXI H,FCB+1 NAMELPG: MVI B,5 CALL RECV ;GET CHAR JNC GETNM3 LDA QFLG ORA A JZ GETNM2 CALL ILPRT DB 'Time out receiving filename',CR,LF,0 GETNM2: JMP GCKSER ; GETNM3: CPI EOT ;IF EOT, THEN NO MORE FILES JZ GNRET CPI EOFCHAR ;GOT END OF NAME JZ ENDNAME MOV M,A ;PUT NAME IN FCB LDA QFLG ;CAN TYPE IT IF NO QFLG ORA A JZ SKPTYP CALL FTYTST SKPTYP: 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 ; FTYTST: LDA FTYCNT INR A STA FTYCNT CPI 9 ;ARE WE AT THE FILE TYPE? JZ SPCTST ;GO IF SO ENDSPT: MOV A,M CPI ' ' ;TEST FOR SPACE CNZ TYPE ;TYPE IF NOT RET ; SPCTST: MOV A,M CPI ' ' ;TEST FOR SPACE IN FIRST FILE TYPE BYTE RZ ;DON'T OUTPUT PERIOD IF SPACE MVI A,'.' CALL TYPE JMP ENDSPT ;OUTPUT FIRST FILE TYPE BYTE ; ENDNAME: LDA QFLG ORA A CNZ CRLF MOV A,C ;SEND CHECKSUM CALL SEND MVI B,1 CALL RECV ;CHECKSUM GOOD? CPI OKNMCH ;YES IF OKNMCH SENT.. JZ GNRET ;..ELSE DO OVER. GCKSER: LXI H,FCB ;CLEAR FCB (EXCEPT DRIVE).. CALL INITFCBS+2 ;..SINCE IT MIGHT BE DAMAGED.. LDA QFLG ;..BY TOO MANY CHARS. ORA A JZ GCKSER1 CALL ILPRT DB 'Checksum error',CR,LF,0 GCKSER1: CALL HSNAK ;DO HANDSHAKING OVER JC GCKSER1 JMP GETNM1 ; GNRET: POP H RET ; HSNAK: MVI A,NAK ;SEND NAK UNTIL.. CALL SEND ;..RECEIVING ACK. CALL CKABORT ;DON'T GET HUNG UP HERE MVI B,2 ;WAIT 2 SECONDS.. CALL RECV ;..IN RECEIVE. CPI ACK ;IF ACK,RETURN WITH.. RZ ;..CARRY CLEAR. STC RET ; TNMBUF: MVI A,FALSE ;CALL FROM SENDFIL ONLY ONCE. STA FSTFLG STA FILECT CALL SCAN LXI H,NAMEBUF SHLD NBSAVE ;SAVE ADDR OF 1ST NAME TNLP1: CALL TRTOBUF LXI H,FCB LXI D,FCBBUF CALL CPMLINE ;PARSE NAME TO CP/M FORMAT TNLP2: CALL MFNAME ;SEARCH FOR NAMES (* FORMAT) JC NEXTNM LDA FCB+10 ;IF CP/M 2 $SYS FILE.. ANI 80H ;..DON'T SEND JNZ TNLP2 LHLD NBSAVE ;GET NAME LXI D,FCB ;MOVE IT TO FCB XCHG MVI B,12 CALL MOVE XCHG SHLD NBSAVE ;ADDR OF NEXT NAME LXI H,FILECT ;COUNT FILES FOUND INR M JMP TNLP2 ; NEXTNM: LXI H,NAMECT ;COUNT NAMES FOUND DCR M JNZ TNLP1 LXI H,NAMEBUF ;SAVE START OF BUFFER SHLD NBSAVE LDA FILECT CPI 65 ;NO MORE THAN 64 TRANSFERS RC MVI A,64 ;ONLY X'FER FIRST 64 STA FILECT RET ; ;SCANS CMDBUF COUNTING NAMES AND PUTTING DELIMITER (SPACE) ;AFTER LAST NAME ; SCAN: PUSH H LXI H,NAMECT MVI M,0 LXI H,CMDBUF+1 ;FIND END OF CMD LINE.. MOV C,M ;..AND PUT SPACE THERE. MVI B,0 LXI H,CMDBUF+2 DAD B MVI M,20H LXI H,CMDBUF+1 MOV B,M INR B INR B SCANLP1: INX H DCR B JZ DNSCAN MOV A,M CPI 20H JNZ SCANLP1 SCANLP2: INX H ;EAT EXTRA SPACES DCR B JZ DNSCAN MOV A,M CPI 20H JZ SCANLP2 SHLD BGNMS ;SAVE START OF NAMES IN CMDBUF INR B DCX H SCANLP3: INX H DCR B JZ DNSCAN MOV A,M CPI 20H JNZ SCANLP3 LDA NAMECT ;COUNTS NAMES INR A STA NAMECT SCANLP4: INX H ;EAT SPACES DCR B JZ DNSCAN MOV A,M CPI 20H JZ SCANLP4 JMP SCANLP3 ; DNSCAN: MVI M,20H ;SPACE AFTER LAST CHAR POP H RET ; ;PLACES NEXT NAME IN BUFFER SO 'CPMLINE' MAY PARSE IT ; TRTOBUF: LHLD BGNMS MVI B,0 LXI D,FCBBUF+2 TBLP: MOV A,M CPI 20H JZ TRBFEND STAX D INX H INX D INR B ;COUNT CHARS IN NAME JMP TBLP ; TRBFEND: INX H MOV A,M ;EAT EXTRA SPACES CPI 20H JZ TRBFEND SHLD BGNMS LXI H,FCBBUF+1 ;PUT # CHARS BEFORE NAME MOV M,B RET ; ;IN CP/M V.2, IF FILE IS R/O OR SYS, IT IS CHANGED TO 'BAK'. ; CKCPM2: MVI C,12 CALL BDOS ORA A ;RETURN 0 MEANS CP/M 1 RZ MVI C,STDMA LXI D,80H CALL BDOS MVI C,SRCHF ;SEARCH FOR FILE LXI D,FCB CALL BDOS CPI 0FFH RZ ADD A ADD A ;MULT A-REG BY.. ADD A ADD A ;..32 TO FIND.. ADD A ;..NAME IN DMA. LXI H,80H ADD L MOV L,A ;HL POINTS TO DIR NAME LXI D,9 DAD D ;POINT TO R/O ATTRIB BYTE MOV A,M ANI 80H ;TEST MSB JNZ MKCHG ;IF SET, MAKE CHANGE INX H ;CHECK SYSTEM ATTRIB BYTE MOV A,M ANI 80H RZ ;NOT $SYS OR $R/O DCX H MKCHG: LXI D,-8 DAD D ;POINT HL TO FILENAME + 1 LXI D,FCB+1 ;MOVE DIR NAME TO FCB.. MVI B,11 ;..WITHOUT CHANGING DRIVE. CALL MOVE LXI H,FCB+9 ;R/O ATTRIB MOV A,M ANI 7FH ;STRIP R/O ATTRIB MOV M,A INX H ;SYS ATTRIB MOV A,M ANI 7FH MOV M,A LXI D,FCB MVI C,30 ;SET NEW ATTRIBS IN DIR CALL BDOS ; ;MAY BE CALLED BY CKBAKUP BELOW. ITS RETURN DONE HERE ; PLANCHG: LXI H,FCB ;CHANGE NAME TO TYPE "BAK" LXI D,6CH MVI B,9 ;MOVE DRIVE AND NAME (NOT TYPE) CALL MOVE LXI H,75H ;START OF TYPE IN FCB2 MVI M,'B' INX H MVI M,'A' INX H MVI M,'K' LXI D,6CH MVI C,ERASE ;ERASE ANY PREV BACKUPS CALL BDOS LXI H,6CH ;FCB2 DR FIELD SHOULD.. MVI M,0 ;..0 FOR RENAME. LXI D,FCB MVI C,23 ;RENAME JMP BDOS ; CKBAKUP: LDA BAKUPBYTE ORA A RZ MVI C,SRCHF LXI D,FCB CALL BDOS INR A RZ ;FILE NOT FOUND JMP PLANCHG ;IN "CKCPM2" - RET DONE THERE ; ;MULTI-FILE ACCESS SUBROUTINE FROM CP/M USER'S GROUP ;FIXED BY MARK ZEIGER 8/17/80 ;CARRY IS SET IF NO MORE NAMES CAN BE FOUND ; MFNAME: MFACCESS ;A MACRO IN MACROS.LIB ; RCVSECT: MVI A,1 STA ERRCT RCVRPT: XRA A ;ZERO ACCUM STA ERRCDE ;CLEAR RECEIVE ERROR CODE LDA QFLG ORA A JZ RCVSQ CALL ILPRT DB CR,'Awaiting # ',0 PUSH H ;SAVE IT LHLD SECTNO ;GET SECTOR NUMBER INX H ;BUMP IT CALL DECOUT ;PRINT SECTOR NUMBER IN DECIMAL CALL ILPRT DB ' (', 0 CALL DHXOUT ;16 BIT HEX CONVERSION & OUTPUT CALL ILPRT DB 'H)',0 MOV A,L ;ONLY LOW BYTE USED BY PROGRAM POP H ;RESTORE IT ; RCVSQ: ;WAIT FOR SOH OR EOT MVI B,10 ;10 SECONDS CALL RECV JC RCVSTOT CALL RCVERR ;CHECK FOR ERRORS JC RCVDERR ;JUMP IF THERE WAS AN ERROR CPI SOH JZ RCVSOH ORA A JZ RCVSQ CPI EOT STC RZ MOV B,A LDA QFLG ORA A JZ RCVSERR RCVSEH: MOV A,B CALL CRLF CALL HEXO CALL ILPRT DB 'H recv''d, not SOH',CR,LF,0 RCVSERR: MVI B,1 ;WAIT FOR 1 SEC.. CALL RECV ;..WITH NO CHARS JNC RCVSERR ;LOOP UNTIL SENDER DONE LDA CKSUMFLG ;GET CHECKSUM FLAG ORA A ;CRC IN EFFECT? MVI A,NAK ;PUT NAK IN ACCUM JNZ RCVSER2 ;NO, SEND THE NAK LDA FIRSTME ;GET FIRST TIME SWITCH ORA A ;HAS FIRST SOH BEEN RECEIVED? MVI A,NAK ;PUT NAK IN ACCUM JZ RCVSER2 ;YES, THEN SEND NAK MVI A,CRC ;TELL SENDER CRC IS IN EFFECT RCVSER2: CALL SEND ;..THE NAK or CRC request LDA ERRCT ;ABORT IF.. INR A ;..WE HAVE REACHED.. STA ERRCT ;..THE ERROR.. CPI ERRLIM ;..LIMIT? JC RCVRPT ;..NO, TRY AGAIN 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 QFLG ORA A JZ RCVSCRC RCVSPT: CALL ILPRT DB CR,LF,'++ Timeout ++ ',0 RCVPRN: LDA ERRCT PUSH H MVI H,0 MOV L,A CALL DECOUT POP H CALL CRLF RCVSCRC: CALL RCVSCRC2 JMP RCVSERR ; ;ROUTINE WILL SWITCH FROM CRC TO CHECKSUM IF ERCNT REACHES ERRCRC ;AND FIRSTME IS TRUE ; RCVSCRC2: LDA ERRCT CPI ERRCRC RNZ LDA FIRSTME ORA A RZ LDA CKSUMFLG ORA A RNZ CMA STA CKSUMFLG STA CKSUMDFLT LDA QFLG ORA A RZ CALL ILPRT DB '++ Switching to Checksum mode ++',CR,LF DB '++ Sender may not be CRC capable ++',CR,LF,BELL,0 RET ; ;----> RCVERR: ; ; Checks for framing, overrun, and parity errors. Parity errors ; cannot be detected unless the parity option has been selected. ; 1.Error code (ERRCDE) was set in RECV routine. ; 2.ERRCDE=0 for no errors, ERRCDE<>0 for errors. ; 3.If there is an error, routine returns with carry flag set. ; RCVERR: PUSH PSW ;SAVE CHAR TRANSMITTED LDA ERRCDE ;GET RECEIVE ERROR CODE ANA A ;IS IT ZERO? JZ RCVERR2 ;YES, NO RECEIVE ERROR POP PSW ;RESTORE CHAR TRANSMITTED STC ;SET CARRY ON TO INDICATE AN ERROR RET RCVERR2: POP PSW ;RESTORE CHAR TRANSMITTED RET ; ;----> RCVDERR: Checks for a receive error and displays appropriate ; error message. Then goes to RCVSERR to purge the line ; and send a NAK. ; RCVDERR: LDA QFLG ;QUIET... ORA A ;...MODE? JZ RCVSERR ;YES, NO MSG RCVDERRP: CALL ILPRT DB CR,LF,0 LDA ERRCDE ;GET RECEIVE ERR CODE ANI FRMER ;WAS THERE A FRAMING ERROR? JZ RCVDERR2 ;NO, GO CHECK FOR OVERRUN CALL ILPRT DB '++ Framing error ++ ',0 CALL RCVDERR5 ;PRINT # OF ERROR RCVDERR2: LDA ERRCDE ;GET RECEIVE ERR CODE ANI ORUNER ;WAS THERE AN OVERRUN JZ RCVDERR3 ;NO, GO CHECK FOR PARITY ERROR CALL ILPRT DB '++ Overrun error ++ ',0 CALL RCVDERR5 RCVDERR3: LDA ERRCDE ;GET RECEIVE ERR CODE ANI PARER ;WAS THERE A PARITY ERROR? JZ RCVDERR4 ;NO, GO PURGE LINE CALL ILPRT DB '++ Parity error ++ ',0 CALL RCVDERR5 RCVDERR4: JMP RCVSERR ;GO PURGE LINE, SEND NAK ; ;Display the number of the error, do a carriage return and line feed. ; RCVDERR5: LDA ERRCT ;GET ERROR NUMBER PUSH H MVI H,0 MOV L,A CALL DECOUT ;DISPLAY IT POP H JMP CRLF ;DO CR, LF ; ;Got SOH - get block #, block # complemented ; RCVSOH: XRA A ;ZERO ACCUM STA FIRSTME ;INDICATE FIRST SOH RECV'D MVI B,1 ;TIMEOUT = 1 SEC CALL RECV ;GET SECTOR JC RCVSTOT ;GOT TIMEOUT CALL RCVERR ;CHECK FOR RECEIVE ERROR JC RCVDERR MOV D,A MVI B,1 CALL RECV JC RCVSTOT CALL RCVERR ;CHECK FOR RECEIVE ERROR JC RCVDERR CMA CMP D JZ RCVDATA LDA QFLG ORA A JZ RCVSERR RCVBSE: CALL ILPRT DB CR,LF,'++ Bad sector # in Hdr',CR,LF,0 JMP RCVSERR ; RCVDATA: MOV A,D STA RCVSNO MVI A,1 STA DATAFLG MVI C,0 CALL CLRCRC ;CLEAR CRC COUNTER LXI H,80H RCVCHR: MVI B,1 CALL RECV JC RCVSTOT CALL RCVERR ;CHECK FOR RECEIVE ERROR JC RCVDERR MOV M,A INR L JNZ RCVCHR LDA CKSUMFLG ORA A JZ RCVCRC MOV D,C XRA A STA DATAFLG MVI B,1 CALL RECV JC RCVSTOT CALL RCVERR ;CHECK FOR RECEIVE ERROR JC RCVDERR CMP D JNZ RCVCERR CHKSNUM: LDA RCVSNO MOV B,A LDA SECTNO CMP B JZ RECVACK INR A CMP B JNZ ABORT RET ; RCVCRC: MVI E,2 ;NUMBER OF CRC BYTES RCVCRC2: MVI B,1 CALL RECV JC RCVSTOT CALL RCVERR JC RCVDERR DCR E JNZ RCVCRC2 CALL CHKCRC ORA A JZ CHKSNUM LDA QFLG ORA A JZ RCVSERR RCVCRER: CALL ILPRT DB CR,LF,'++ CRC error ++',0 JMP RCVPRN ; RCVCERR: 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 JMP SEND ; SENDHDR: LDA QFLG ORA A JZ SENDHNM CALL ILPRT DB CR,'Sending # ',0 PUSH H LHLD SECTNO ;GET SECTOR NUMBER CALL DECOUT ;PRINT IT IN DECIMAL CALL ILPRT DB ' (',0 CALL DHXOUT ;16 BIT HEX CONVERSION & OUTPUT CALL ILPRT DB 'H)',0 POP H SENDHNM: MVI A,SOH CALL SEND LDA SECTNO CALL SEND LDA SECTNO CMA JMP SEND ; 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 JMP SEND ; SENDCRC: CALL FINCRC MOV A,D CALL SEND MOV A,E CALL SEND XRA A RET ; GETACK: MVI B,10 ;10 SECONDS CALL RECVDG JC GETATOT CPI ACK RZ MOV B,A LDA QFLG ORA A JZ ACKERR MOV A,B CALL CRLF CALL HEXO CALL ILPRT DB 'H Recv''d, not ACK',CR,LF,0 ACKERR: LDA ERRCT INR A STA ERRCT DCR A CPI ERRLIM RC LDA QFLG ORA A JZ CSABORT GACKV: CALL CKQUIT STC RZ CSABORT: CALL ERXIT DB CR,LF,'Can''t send sector -- Aborting',CR,LF,'$' GETATOT: LDA QFLG ORA A JZ ACKERR CALL ILPRT DB CR,LF,'Timeout on ACK',CR,LF,0 JMP ACKERR ; CKABORT: LDA QFLG ORA A RZ CKABGO: CALL STAT RZ CALL KEYIN CPI CAN RNZ ABORT: LXI SP,STACK ABORTL: MVI B,1 CALL RECV JNC ABORTL MVI A,CAN CALL SEND ABORTW: MVI B,1 CALL RECV JNC ABORTW MVI A,' ' CALL SEND CALL ILPRT DB CR,LF,'Routine cancelled',CR,LF,BELL,0 MVI A,'B' ;TURN MULTI-FILE MODE.. STA BATCHFLG ;..OFF SO ROUTINE ENDS. JMP DONETCE ; INCRSNO: PUSH H LHLD SECTNO ;GET SECTOR NUMBER INX H ;BUMP IT SHLD SECTNO ;STORE IT MOV A,L POP H RET ; ERASFIL: LDA BATCHFLG ;DON'T ASK FOR ERASE.. ORA A ;..IN MULTI-FILE MODE,.. JZ NOASK ;..JUST DO IT. LXI D,FCB MVI C,SRCHF CALL BDOS INR A RZ CALL ILPRT DB 'File exists -- Type ''Y'' to erase: ',BELL,0 CALL KEYIN PUSH PSW CALL TYPE POP PSW CALL UCASE CPI 'Y' JNZ MENU CALL CRLF NOASK: LXI D,FCB MVI C,ERASE JMP BDOS ; BLKFILE: CALL ILPRT ;ROUTINE IF NO FILE IS NAMED FOR "SEND" OR "RECEIVE" DB CR,LF,'No file specified',CR,LF,BELL,0 JMP MENU MAKEFIL: LXI D,FCB MVI C,MAKE CALL BDOS INR A RNZ CALL ERXIT DB 'Error - Can''t make file',CR,LF DB 'Directory is likely full',CR,LF,'$' ; IF CPM2X ; CNREC: MVI C,FILSIZ ;COMPUTE FILE SIZE FUNCTION IN CP/M 2.x LXI D,FCB ;POINT TO FILE CONTROL BLOCK CALL BDOS LHLD FCB+33 ;GET RECORD COUNT SHLD RCNT ;STORE IT LXI H,0 ;ZERO HL SHLD FCB+33 ;RESET RANDOM RECORD IN FCB RET ; ENDIF ;CPM2X ; IF NOT CPM2X ; CNREC: MVI A,'?' ;MATCH ALL EXTENTS STA FCBEXT MVI A,0FFH STA MAXEXT ;INIT MAX EXT NO. MVI C,SRCHF ;GET 'SEARCH FIRST' FNC LXI D,FCB CALL BDOS ;READ FIRST INR A ;WERE THERE ANY? JNZ SOME ;GOT SOME CALL ERXIT DB '++ File not found ++$' ; ;READ MORE DIRECTORY ENTRIES ; MOREDIR: MVI C,SRCHN ;SEARCH NEXT LXI D,FCB CALL BDOS ;READ DIR ENTRY INR A ;CHECK FOR END (0FFH) JNZ SOME ;NOT END OF DIR...PROCESS EXTENT LDA MAXEXT ;HIT END...GET HIGHEST EXTENT NO. SEEN MOV L,A ;WHICH GIVES EXTENT COUNT -1 MVI H,0 MOV D,H LDA RCNT ;GET RECORD COUNT OF MAX EXTENT SEEN MOV E,A ;SAVE IT IN DE DAD H DAD H ;MULTIPLY # OF EXTENTS -1 DAD H ; TIMES 128 DAD H DAD H DAD H DAD H DAD D ;ADD IN SIZE OF LAST EXTENT SHLD RCNT ;SAVE TOTAL RECORD COUNT RET ;AND EXIT ; ;POINT TO DIRECTORY ENTRY ; SOME: DCR A ;UNDO PREV 'INR A' ANI 3 ;MAKE MODULUS 4 ADD A ;MULTIPLY... ADD A ;..BY 32 BECAUSE ADD A ;..EACH DIRECTORY ADD A ;..ENTRY IS 32 ADD A ;..BYTES LONG LXI H,80H POINT TO BUFFER ADD L ;POINT TO ENTRY ADI 15 ;OFFSET TO RECORD COUNT MOV L,A ;HL NOW POINTS TO REC COUNT MOV B,M ;GET RECORD COUNT DCX H DCX H ;BACK DOWN TO EXTENT NUMBER DCX H LDA MAXEXT ;COMPARE WITH CURRENT MAX. ORA A ;IF NO MAX YET JM BIGGER ;THEN SAVE RECORD COUNT ANYWAY CMP M JNC MOREDIR BIGGER: MOV A,B ;SAVE NEW RECORD COUNT STA RCNT MOV A,M ;SAVE NEW MAX. EXTENT NO. STA MAXEXT JMP MOREDIR ;GO FIND MORE EXTENTS ; ENDIF ;NOT CPM2X ; OPENFIL: XRA A STA FCBEXT LXI D,FCB MVI C,OPEN CALL BDOS INR A JNZ OPENOK CALL ERXIT DB 'Can''t open file$' OPENOK: LDA BATCHFLG ORA A ;ONLY IF SINGLE FILE... RZ JMP SENDTIM ;A LIB MACRO SHOWS TIME TO SEND ; CLOSFIL: LXI D,FCB MVI C,CLOSE CALL BDOS INR A RNZ CALL ERXIT DB 'Can''t close file$' RDSECT: LDA SECINBF DCR A STA SECINBF JM RDBLOCK LHLD SECPTR LXI D,80H CALL MOVE128 SHLD SECPTR RET ; RDBLOCK: LDA EOFLG CPI 1 STC RZ MVI C,0 LXI D,DBUF RDSECLP: PUSH B PUSH D MVI C,STDMA CALL BDOS LXI D,FCB MVI C,READ CALL BDOS POP D POP B ORA A JZ RDSECOK DCR A JZ REOF CALL ERXIT DB '++ File read error ++$' RDSECOK: LXI H,80H DAD D XCHG INR C MOV A,C CPI DBUFSIZ*8 ;BUFFER SIZE IN 128 BYTE SECTORS JZ RDBFULL JMP RDSECLP ; REOF: MVI A,1 STA EOFLG MOV A,C RDBFULL: STA SECINBF LXI H,DBUF SHLD SECPTR LXI D,80H MVI C,STDMA CALL BDOS JMP RDSECT ; WRSECT: LHLD SECPTR XCHG LXI H,80H CALL MOVE128 XCHG SHLD SECPTR LDA SECINBF INR A STA SECINBF CPI DBUFSIZ*8 ;BUFFER SIZE IN 128 BYTE SECTORS RNZ WRBLOCK: LDA SECINBF ORA A RZ MOV C,A LXI D,DBUF DKWRLP: PUSH H PUSH D PUSH B MVI C,STDMA CALL BDOS LXI D,FCB MVI C,WRITE CALL BDOS POP B POP D POP H ORA A JNZ WRERR LXI H,80H DAD D XCHG DCR C JNZ DKWRLP XRA A STA SECINBF LXI H,DBUF SHLD SECPTR RET ; WRERR: MVI C,CAN CALL SEND CALL ERXIT DB CR,LF,'Error writing file',CR,LF,'$' ; ;----> RECV: Receive a character ; ;Timeout time is in B, in seconds. Entry via 'RECVDG' deletes garbage ;characters on the line. For example, having just sent a sector, calling ;RECVDG will delete any line noise induced characters LONG before the ;ACK/NAK would be received. ; RECVDG: EQU $ CALL IN$MODDATP CALL IN$MODDATP RECV: PUSH D MSEC: PUSH H LXI H,7500 CALL FIXCNT PUSH H POP D POP H CALL CKABORT MWTI: CALL RCVREADY JZ MCHAR DCR E JNZ MWTI DCR D JNZ MWTI DCR B JNZ MSEC POP D STC RET ; MCHAR: LDA PMMIBYTE ;IS THE MODEM A PMMI? ORA A ;SET FLAGS JZ MCHAR1 ;YES, JUMP CALL IN$MODCTLP ;GET ERROR-STATUS BYTE ANI ERRCDMSK ;MASK OUT ALL EXCEPT ERROR BITS (3-5) STA ERRCDE ;SAVE THE ERROR CODE MCHAR1: CALL IN$MODDATP POP D PUSH PSW CALL UPDCRC ;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 SENDREADY JNZ SENDW POP PSW JMP OUT$MODDATP ; WAITNAK: LDA QFLG ORA A JZ WAITNLP CALL ILPRT DB 'Awaiting initial NAK',CR,LF,0 WAITNLP: CALL CKABORT MVI B,1 CALL RECV CPI NAK RZ CPI CRC ;CRC REQUEST? JZ WAITCRC ;YES, GO SET CRC FLAG CPI CAN ;CANCEL? JZ ABORT DCR E JZ ABORT JMP WAITNLP ; WAITCRC: LDA QFLG ORA A JZ WAITCRC1 CALL ILPRT DB 'CRC request received',CR,LF,0 WAITCRC1: XRA A STA CKSUMFLG RET ; ;--->PARITY: Routine to setup PMMI for odd/even parity. ; PARITY: LDA PMMIBYTE ;IS MODEM A PMMI? ORA A ;SET FLAGS RZ ;NO, RETURN LDA OPARITY ;GET ODD PARITY REQUEST BYTE ORA A ;SET FLAGS JNZ EVENPAR ;IF NOT ODD SEE IF IT IS EVEN LDA UARTCTLB ;GET UART/MODEM CONTROL BYTE ANI ODPARMSK JMP PARITY1 ; EVENPAR: LDA EPARITY ;GET EVEN PARITY REQUEST BYTE ORA A ;SET FLAGS RNZ ;IF EVEN PARITY NOT SPECIFIED RETURN LDA UARTCTLB ;GET UART/MODEM CONTROL BYTE ANI ODPARMSK ;SET FOR PARITY ORI EVPARMSK ;NOW SET FOR EVEN PARITY PARITY1: JMP OUT$MODCTLP ;SEND TO PMMI - ;WHEN OUT$MODCTLP DOES RET IT ;WILL GO BACK TO CALLING ROUTINE ; NOPARIT: LDA PMMIBYTE ORA A RZ LDA UARTCTLB ;GET UART/MODEM CONTROL BYTE ORI NOPARMSK ;RESET PARITY BIT ON PMMI JMP OUT$MODCTLP ; INITADR: LHLD 1 LXI D,3 DAD D SHLD VSTAT+1 DAD D SHLD VKEYIN+1 DAD D SHLD VTYPE+1 DAD D SHLD VLIST+1 LXI D,30 DAD D SHLD VLSTAT+1 LDA PMMIBYTE ORA A RZ ;RETURN DONE FROM THIS ROUTINE.. LDA IN$MODCTLP+1 ;..IF NOT PMMI STA OUT$MODCTLP+1 INR A STA OUT$MODDATP+1 STA IN$MODDATP+1 INR A STA IN$BAUDRP+1 STA OUT$BAUDRP+1 INR A STA OUT$MODCTL2+1 RET ; ; CHECK OPTIONS, PUT 0 IN APPROPRIATE PLACES IN OPTION TABLE ; IF OPTION SELECTED ; 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 CPI 'O' JNZ OPTCK1 XRA A STA UARTFLG JMP OPTCK2 ; OPTCK1: CPI 'A' JNZ OPTCK2 MVI A,TRUE STA UARTFLG OPTCK2: MVI M,0 JMP OPTLP ; OPTNO: INX H DCR B JNZ OPTCK CALL NOTVLDMSG POP PSW ;PRESERVE STACK JMP MENU ; ENDOPT: LDA VSEEFLG ORA A RNZ STA QFLG ;IF VIEWING SUPPRESS ALL ELSE RET ; DONE: LDA BATCHFLG ORA A JNZ DONETC LDA QFLG ORA A JZ NMSTRNS MVI B,12 ;ZERO OUT FTRNMSG LXI H,FTRNMSG MVI A,0 ZEROLP: MOV M,A INX H DCR B JNZ ZEROLP MVI B,12 ;PUT FILE NAME IN FTRNMSG LXI H,FCB+1 LXI D,FTRNMSG LOADMSG: MVI A,4 ;START OF FILE TYPE? CMP B JZ PERIOD ;PUT IN PERIOD IF SO MOV A,M CPI ' ' ;DON'T PUT IN SPACE JZ SKPSP STAX D ;STORE IN FTRNMSG INX D SKPSP: INX H DCR B MOV A,B ORA A ;END OF FILE NAME? JZ FTRNMSG0 ;DISPLAY FILE NAME JMP LOADMSG ;LOOP FOR ANOTHER CHARACTER ; PERIOD: MOV A,M CPI ' ' ;IS FILE TYPE EMPTY? JZ FTRNMSG0 ;GO IF SO MVI A,'.' ;ELSE PUT PERIOD IN MESSAGE STAX D INX D DCR B JMP LOADMSG ; FTRNMSG0: CALL ILPRT DB CR,LF FTRNMSG: DS 12 DB 0 CALL ILPRT DB ' Transferred',CR,LF,LF,0 NMSTRNS: LDA FCB ;SAVE DRIVE NO. STA DISKNO LXI H,FCB ;BLANK OUT FILE CONTROL BLOCKS CALL INITFCBS LDA DISKNO ;PUT DRIVE NUMBER BACK STA FCB LXI H,RESTSN ;RESTORE SECTORE NUMBERS.. LXI D,SECTNOB ;..FOR NEW FILE TRANSFER. MVI B,SECTNOE-SECTNOB ;ROUTINE ALSO DONE IN MENU. CALL MOVE LDA SENDFLG ;GOES TO EITHER SEND OR.. ORA A ;..RECEIVE FILE, DEPENDING.. JNZ SENDFIL1 ;..UPON WHICH ROUTINE SET.. JMP RCVFIL1 ;..THE FLAG IN MULTI-FILE MODE. ; DONETC: CALL ILPRT DB CR,LF,'Transfer completed',CR,LF,BELL,0 DONETCA: LDA DISCFLG ;SEE IF DISCONNECT WHEN THROUGH ORA A JNZ DONETCE ;NO, DON'T DISCONNECT DONETCB: CALL ILPRT DB CR,LF,'Press RETURN to disconnect',BELL,CR,LF,0 MVI C,RDCON CALL BDOS ;WAIT FOR RESPONSE CPI 0DH ;CARRIAGE RETURN JNZ DONETCB ;NOPE CALL ILPRT DB CR,LF,'Disconnected',CR,LF,0 CALL JMP$DISCONNT ;HANG-UP THE PMMI JMP EXIT ;GO TO CP/M ; DONETCE: CALL NOPARIT ;RESET TO NO PARITY MVI A,TRUE STA FIRSTME ;SET FIRST-TIME FLAG STA FSTFLG ;RESET MULTIFILE TRANS STA NFILFLG ;..USED IN TERMINAL ROUTINE CMA STA SAVEFLG ;STOP MEMORY SAVE IN TERM ROUTINE STA LISTMOR ;STOP ANY BUFFERED OUTPUT TO PRINTER LXI H,BOTTRAM ;RESET PRINTER BUFFER POINTERS SHLD HLSAVE1 SHLD HLSAVE2 LDA TERMFLG ;SEE IF RETURN TO.. ORA A ;..TERMINAL MODE.. JNZ MENU ;..AFTER X'FER. CALL CRLF JMP TERM ; MOVEFCB: LXI H,FCB+16 LXI D,FCB MVI B,16 CALL MOVE XRA A STA FCBSNO STA FCBEXT RET ; SHOW: CPI LF JZ CTYPE CPI CR JZ CTYPE CPI 9 JZ CTYPE CPI ' ' JC SHOWHEX CPI 7FH JC CTYPE SHOWHEX: PUSH PSW MVI A,'(' CALL CTYPE POP PSW CALL HEXO MVI A,')' JMP CTYPE ; CTYPE: PUSH B PUSH D PUSH H MOV E,A MVI C,WRCON CALL BDOS POP H POP D POP B RET ; CRLF: PUSH PSW MVI A,CR CALL TYPE MVI A,LF CALL TYPE POP PSW RET ; TYPE: PUSH PSW PUSH B PUSH D PUSH H MOV C,A VTYPE: CALL $-$ POP H POP D POP B POP PSW RET ; STAT: PUSH B PUSH D PUSH H ; VSTAT: CALL $-$ POP H POP D POP B ORA A RET ; KEYIN: PUSH B PUSH D PUSH H VKEYIN: CALL $-$ POP H POP D POP B RET ; LISTER: PUSH B PUSH D PUSH H VLIST: CALL $-$ POP H POP D POP B RET ; LSTSTAT: PUSH B PUSH D PUSH H VLSTAT: CALL $-$ POP H POP D POP B ORA A RET ; UCASE: CPI 61H ;CHANGES LOWER CASE CHARACTER.. RC ;..IN A-REG TO UPPER CASE. CPI 7BH RNC ANI 5FH RET ; DECOUT: PUSH PSW PUSH B PUSH D PUSH H LXI B,-10 LXI D,-1 DECOU2: DAD B INX D JC DECOU2 LXI B,10 DAD B XCHG MOV A,H ORA L CNZ DECOUT MOV A,E ADI '0' CALL CTYPE POP H POP D POP B POP PSW RET ; ;----> DHXOUT: - DOUBLE PRECISION HEX OUTPUT ROUTINE. ; DHXOUT: PUSH H PUSH PSW MOV A,H ;GET MS BYTE CALL HEXO ;OUTPUT HIGH ORDER BYTE MOV A,L ;GET LS BYTE CALL HEXO ;OUTPUT LOW ORDER BYTE POP PSW POP H RET ; HEXO: PUSH PSW RAR RAR RAR RAR CALL NIBBL POP PSW NIBBL: ANI 0FH CPI 10 JC ISNUM ADI 7 ISNUM: ADI '0' JMP TYPE ; ;RETURNS W/ ZERO SET IF RETRY ASKED. IF MULTI-FILE MODE, THEN ;NO QUESTIONS ASKED, JUST QUIT ; CKQUIT: LDA BATCHFLG ORA A JNZ CKQTASK ;ASK FOR RETRY INR A ;RESET ZERO FLG RET ; CKQTASK: MVI A,1 STA ERRCT CALL ILPRT DB CR,LF,'Multiple errors encountered.',CR,LF DB 'Type Q to quit, R to retry: ',BELL,0 CALL KEYIN PUSH PSW CALL CRLF POP PSW CALL UCASE ;INSTEAD OF "ANI 5FH" CPI 'R' RZ CPI 'Q' JNZ CKQUIT ORA A RET ; SHFTYPE: PUSH PSW CALL ILPRT DB 'ctrl-',0 POP PSW ADI 40H CALL TYPE ; ;WRITE A STRING OF CHARACTERS ; 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 MVI A,BELL CALL TYPE LDA BATCHFLG ORA A JNZ DONETCE MVI A,'Q' ;RESET QFLG STA QFLG JMP ABORT ;ABORT OTHER COMPUTER ; EXIT: CALL ILPRT DB '%%% Exiting MODEM %%%',0 LDA SAVUSR MOV E,A CALL SETUSR LXI D,80H MVI C,STDMA CALL BDOS LHLD STACK SPHL LDA SAVCCP ORA A JZ 0 ;WARM BOOT RET ; MOVE128: MVI B,128 MOVE: MOV A,M STAX D INX H INX D DCR B JNZ MOVE RET ; ;INITIALIZES CP/M FILE CONTROL BLOCKS AT 5CH AND 6CH ; SETFCB: LXI D,CMDBUF LXI H,FCB CALL CPMLINE CALL PROCOPT CHECKNM: LDA FCB+1 ;CHECK ON THE PRIMARY OPTION CPI 'E' ;RETURN IF ECHO OPTION RZ CPI 'H' ;RETURN IF HELP OPTION RZ CPI 'L' ;RETURN IF LOCAL ECHO OPTION RZ MOV B,A LDA PMMIBYTE ORA A MOV A,B JZ S4 CPI 'C' RZ S4: CPI 'T' JZ TERMSEL CPI 'S' JZ CKFILE CPI 'R' JNZ BDOPT LDA BATCHFLG ;IF MULT FILE MODE, THEN.. ORA A ;..RECV OPT DOES NOT NEED.. RZ ;..NAME. JMP CKFILE BDOPT: CALL ILPRT DB CR,LF,'++ Bad Option ++',CR,LF,0 JMP REENT CKFILE: LDA FCB+17 ;IF OPTION THAT NEEDS FILE NAME,.. CPI ' ' ;..THEN CHECK TO SEE IF NAME.. RNZ ;..EXISTS. IF NOT.. REENT: CALL ILPRT ;..DO EVERYTHING OVER. DB CR,LF,'Re-enter PRIMARY option and file name only: ',BELL,0 LXI D,CMDBUF CALL INBUFF JMP SETFCB ; TERMSEL: LDA FCB+17 CPI ' ' JNZ SAVAGN MVI A,FALSE STA SAVEFLG MVI A,TRUE STA NFILFLG RET ; SAVAGN: MVI A,FALSE STA NFILFLG RET ; NEWBAUD: LDA PMMIBYTE ORA A RZ CALL ILPRT DB CR,LF,'Enter New Baudrate: ',0 LXI H,FCB+9 MVI M,0 ;PUTS A ZERO IN FIRST POSITION SO AS TO LOOP5: CALL KEYIN ;FORCE THE DEFAULT OPTION OF 300 BAUD. CPI CR ;CARRIAGE RET ENTERS BAUD RATE JNZ CONNEWB ;GOES TO THE ESTABLISHED ROUTINE - RETURN TO MAIN CALL CRLF ;PROGRAM IS DONE THERE. JMP JMP$INITMOD ; CONNEWB: CPI 30H ;MAKE SURE IT'S.. JC LOOP5 ;..A DIGIT, ELSE.. CPI 3AH ;..DON'T ACCEPT IT. JNC LOOP5 MOV M,A MOV C,A CALL TYPE ;ECHO THE CHARACTER ENTERED INX H JMP LOOP5 ; ;**************************************************************** ;* * ;* CRCSUBS (Cyclic Redundancy Code Subroutines) version 1.20 * ;* 8080 Mnemonics * ;* * ;* These subroutines will compute and check a true 16-bit * ;* Cyclic Redundancy Code for a message of arbitrary length. * ;* * ;* The use of this scheme will guarantee detection of all * ;* single and double bit errors, all errors with an odd * ;* number of error bits, all burst errors of length 16 or * ;* less, 99.9969% of all 17-bit error bursts, and 99.9984% * ;* of all possible longer error bursts. (Ref: Computer * ;* Networks, Andrew S. Tanenbaum, Prentiss-Hall, 1981) * ;* * ;* Designed & coded by Paul Hansknecht, June 13, 1981 * ;* * ;* Copyright (c) 1981, Carpenter Associates * ;* Box 451 * ;* Bloomfield Hills, MI 48013 * ;* 313/855-3074 * ;* * ;* This program may be freely reproduced for non-profit use. * ;* * ;**************************************************************** ; ; ENTRY CLRCRC,UPDCRC,FINCRC,CHKCRC ; CLRCRC: EQU $ ;RESET CRC ACCUMULATOR FOR A NEW MESSAGE. PUSH H LXI H,0 SHLD CRCVAL POP H RET ; UPDCRC: EQU $ ;UPDATE CRC ACCUMULATOR USING BYTE IN (A). PUSH PSW PUSH B PUSH H MVI B,8 MOV C,A LHLD CRCVAL UPDLOOP: MOV A,C RLC MOV C,A MOV A,L RAL MOV L,A MOV A,H RAL MOV H,A JNC SKIPIT MOV A,H ;THE GENERATOR IS X^16 + X^12 + X^5 + 1 XRI 10H ;AS RECOMMENDED BY CCITT. MOV H,A ;AN ALTERNATE GENERATOR WHICH IS OFTEN MOV A,L ;USED IN SYNCHRONOUS TRANSMISSION PROTOCOLS XRI 21H ;IS X^16 + X^15 + X^2 + 1. THIS MAY BE MOV L,A ;USED BY SUBSTITUTING XOR 80H FOR XOR 10H SKIPIT: DCR B ;AND XOR 05H FOR XOR 21H IN THE ADJACENT CODE JNZ UPDLOOP SHLD CRCVAL POP H POP B POP PSW RET ; FINCRC: EQU $ ;FINISH CRC CALCULATION FOR OUTPUT 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 ; MENU0: LDA NFILFLG ORA A JNZ MENU ;GO IF NO FILE ACTIVE CALL ILPRT ;ELSE PRINT MESSAGE DB CR,LF,LF DB '** There may be text in the memory buffer **',CR,LF DB '** It will be lost unless NOL or WRT commands are used **' DB CR,LF,BELL,0 MVI B,2 ;2 MORE BELLS BLOOP: LDA BELRPT ;GET TIME MOV C,A BCLOOP: LXI H,1000 ;ABOUT 0.03 SECONDS CALL FIXCNT BILOOP: MOV A,L ORA H DCX H JNZ BILOOP DCR C JNZ BCLOOP MVI A,BELL CALL TYPE DCR B JNZ BLOOP JMP MENU1 ; MENU: LDA EXITFLG ORA A JNZ EXIT MENU1: LXI H,RESTSN ;RESTORE SECTOR NUMBERS.. LXI D,SECTNOB ;..FOR NEW FILE TRANSFER. MVI B,SECTNOE-SECTNOB CALL MOVE LXI H,RESTROPT ;RESTORE OPTION TABLE LXI D,OPTBL MVI B,OPTBE-OPTBL CALL MOVE MVI A,0 STA MFFLG1 ;RESET MFACCESS ROUTINE.. CMA ;..AND MULTI TRANS IN CASE.. STA FSTFLG ;..OF ABORT. JMP XPRT ; MENU2: CALL CLRTST CALL ILPRT DB ' Single Letter Commands',CR,LF,LF DB ' H - Display this information',CR,LF DB ' ? - Display current settings',CR,LF,LF DB ' T - Terminal mode',CR,LF DB ' E - Terminal mode with echo',CR,LF DB ' L - Terminal mode with local echo',CR,LF DB ' For capturing text use T(or E or L) FILENAME.TYP and' DB CR,LF DB ' Start & Stop toggles described on subsequent screen.' DB CR,LF,LF DB ' R - Receive file using Christensen Protocol',CR,LF DB ' S - Send file using Christensen Protocol',CR,LF DB ' Command is: R(or S) FILENAME.TYP',CR,LF DB ' R and S can use the following subcommands:',CR,LF DB ' B - Bulk transfer using wildcards (e.g. *.*)',CR,LF DB ' Q - Quiet mode (no messages to console)',CR,LF DB ' T - Return to terminal mode after transfer',CR,LF DB ' V - View bytes transferred on console',CR,LF,LF DB 'The single letter commands may also be used on the',CR,LF DB 'command line when the program is initially executed.' DB CR,LF,LF,0 ; CALL NXTSCRN ; LDA PMMIBYTE ORA A JZ THREELTR CALL ILPRT DB ' Additional Subcommands for PMMI Modem',CR,LF,LF DB ' Modem control:',CR,LF DB ' O - Send or receive on Originate tone',CR,LF DB ' A - Send or receive on Answer tone',CR,LF DB ' D - Disconnect option',CR,LF,LF DB ' Parity options:',CR,LF DB ' 1 - Set and check for odd parity',CR,LF DB ' 0 - Set and check for even parity',CR,LF DB ' Both ends must be capable of these options',CR,LF DB ' which are available only in S and R modes.',CR,LF DB ' The parity checking will be part of the',CR,LF DB ' file transfer protocol.',CR,LF,LF DB ' Speed Options:',CR,LF DB ' After entering your primary and secondary options,' DB CR,LF DB ' you can set the modem speed by placing a "." after' DB CR,LF DB ' the options followed by the speed e.g. 110, 300.',CR,LF DB ' For example: SBO1T.600 will set the modem to run',CR,LF DB ' at 600 baud.',CR,LF,LF,0 ; CALL NXTSCRN ; THREELTR: CALL ILPRT DB ' Three Letter Commands',CR,LF,LF DB 'DIR - List directory and space free (may specify drive)' DB CR,LF DB 'END - Exit from this program',CR,LF DB 'ERA - Erase file (may specify drive)',CR,LF DB 'LOG - Change default drive/user (specify drive/user)' DB CR,LF DB ' and reset disks. e.g. LOG A0, LOG B (user unchanged)' DB CR,LF DB 'SPD - Set speed of file output in terminal mode',CR,LF,0 ; CALL SORPTST JNZ NOTIME CALL ILPRT DB 'TIM - Set S mode time-to-send message',CR,LF,0 ; NOTIME: LDA TOGGLECRC ORA A JZ NOTOGCRC CALL ILPRT DB 'TCC - Toggle Checksum/CRC mode on receive',CR,LF,0 ; NOTOGCRC: LDA TOGGLEBK ORA A JZ NOTOGBK CALL ILPRT DB 'TBR - Toggle backspace to rub conversion',CR,LF,0 ; NOTOGBK: LDA TOGGLELOC ORA A JZ NOTOGLOC CALL ILPRT DB 'TLC - Toggle 1) local command immediate',CR,LF DB ' 2) local command after ',0 LDA EXTCHR CALL SHFTYPE DB CR,LF,0 ; NOTOGLOC: LDA TOGGLELF ORA A JZ NOTOGLF CALL ILPRT DB 'TLF - Toggle send linefeed after carriage return',CR,LF,0 ; NOTOGLF: LDA TOGXOFF ORA A JZ NOTOGXOFF CALL ILPRT DB 'TXO - Toggle XOFF/XON testing in terminal mode file output' DB CR,LF,0 ; NOTOGXOFF: LDA PMMIBYTE ORA A JNZ NONUM CALL ILPRT DB 'NUM - List remote systems',CR,LF,0 LDA SETUPTST ORA A JZ NOSETUP CALL ILPRT DB 'SET - Set communication ports',CR,LF,0 ; NOSETUP: MVI A,LF CALL TYPE JMP NOPMMI ; NONUM: CALL ILPRT DB 'CAL - Dial number',CR,LF DB 'DSC - Disconnect',CR,LF DB 'BYE - Disconnect and reboot',CR,LF,LF,0 ; NOPMMI: CALL ILPRT DB ' The following are terminal text buffer commands:' DB CR,LF,0 LDA PMMIBYTE ORA A JNZ SKIPLF MVI A,LF CALL TYPE SKIPLF: CALL ILPRT DB 'DEL - Delete memory buffer and file',CR,LF DB 'NOL - Return to terminal mode - no loss of data in buffer' DB CR,LF DB 'WRT - Write memory buffer to disk file',CR,LF,LF,0 CALL NXTSCRN ; CALL ILPRT DB ' Local Commands while in Terminal Mode',CR,LF,LF,0 LDA EXITCHR CALL SHFTYPE DB ' - Exit to command mode',CR,LF,LF,0 ; LDA PMMIBYTE ORA A JZ S5A ; LDA DISCCHR CALL SHFTYPE DB ' - Disconnect',CR,LF,0 LDA BRKCHR CALL SHFTYPE DB ' - Send break',CR,LF,0 LDA CHGBAUD CALL SHFTYPE DB ' - Change baud rate',CR,LF,0 ; S5A: LDA TRANLOGON ORA A JZ NOTRANLOG LDA LOGCHR CALL SHFTYPE DB ' - Transmit logon',CR,LF,0 ; NOTRANLOG: LDA LSTTST ORA A JZ NOLST2 LDA LSTCHR CALL SHFTYPE DB ' - Toggle printer',CR,LF,0 ; NOLST2: MVI A,LF CALL TYPE LDA SAVECHR CALL SHFTYPE DB ' - Start copy into buffer',CR,LF,0 LDA UNSAVECHR CALL SHFTYPE DB ' - Stop copy into buffer',CR,LF DB ' Start & Stop may be toggled as often as desired.',CR,LF DB ' A ":" at start of line indicates buffer is open.',CR,LF DB ' XOFF automatically used to stop input when writing',CR,LF DB ' full buffer to disk, XON sent to resume.',CR,LF,LF,0 LDA TRANCHR CALL SHFTYPE DB ' - Transfer ASCII file to remote',CR,LF,LF,0 LDA LOCONEXTCHR ORA A LDA EXTCHR JNZ REMDFLT CALL SHFTYPE DB ' - Send local control character to remote',CR,LF,0 JMP XPRT REMDFLT: CALL SHFTYPE DB ' - Next character will be used for local control',CR,LF,0 ; XPRT: CALL ILPRT DB CR,LF,'Drive ',0 MVI C,CURDSK ;CURRENT DISK FUNCTION CALL BDOS ADI 'A' ;MAKE ASCII CALL TYPE ; IF CPM2X ;IF CPM VER 2.X ; CALL GETUSR ;GET CURRENT USER NUMBER CPI 0 JZ SR3B ;SKIP IF USER 0 PUSH PSW CALL ILPRT DB ', User ',0 POP PSW MVI H,0 MOV L,A CALL DECOUT ;REPORT USER ; ENDIF ;CPM2X ; SR3B: CALL CRLF LDA NFILFLG ORA A JNZ NOBUFMSG CALL GETSPC CALL ILPRT DB ' bytes of buffer free',CR,LF,0 NOBUFMSG: CALL ILPRT DB 'COMMAND (H for Help): ',0 GETCMD: LXI D,CMDBUF ;ENTER COMMAND CALL INBUFF CALL CRLF LXI D,CMDBUF+2 ;POINT TO COMMAND CALL ILCOMP DB 'END',0 JNC EXIT CALL ILCOMP DB 'LOG',0 JNC LOGNEW CALL ILCOMP DB 'DIR',0 JNC DIR CALL ILCOMP DB 'ERA',0 JNC ERASEF CALL ILCOMP DB '?',0 JNC CURPAR CALL ILCOMP DB 'SPD',0 JNC SETSPD CALL ILCOMP DB 'TIM',0 JNC SETTIM CALL ILCOMP DB 'TCC',0 JNC TOGCRC CALL ILCOMP DB 'TBR',0 JNC TOGBKSP CALL ILCOMP DB 'TLC',0 JNC TOGLOC CALL ILCOMP DB 'TLF',0 JNC TOGLF CALL ILCOMP DB 'TXO',0 JNC TOGTXOFF LDA PMMIBYTE ORA A JNZ NONUM2 CALL ILCOMP DB 'NUM',0 JNC NUMPRN NONUM2: LDA SETUPTST ORA A JZ NOSETUP2 CALL ILCOMP DB 'SET',0 JNC SETUPENT NOSETUP2: CALL ILCOMP DB 'NOL',0 JC NXTOPT1 ;CARRY SET = NO MATCH LDA NFILFLG ORA A JNZ NOFILOPN ;GO TELL OPERATOR IF NO FILE OPEN LDA ORIGSAV STA ORIGFLG CALL BUFMSG 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 'DEL',0 JNC NEWFILE LDA PMMIBYTE ORA A JZ S6 CALL ILCOMP ;DE SET FROM 1ST ILCOMP CALL DB 'DSC',0 JNC DISCON1 CALL ILCOMP DB 'BYE',0 JNC BYEBYE CALL ILCOMP DB 'CAL',0 JC S6 MVI A,20H ;FOOL THE SYSTEM STA CMDBUF+4 ;..CMDBUF SO THAT IT.. JMP DOOPT ;..LOOKS AT OPTION FOR DIAL S6: PUSH H LDA CMDBUF+2 LXI H,COMPLIST CALL COMPARE ;COMPARES LIST POINTED TO BY HL.. POP H ;..TO CHAR IN A-REG. JC NOTVLD ;CARRY SET = NO MATCH DOOPT: PUSH H ;LOAD ORIGINAL FCB WITH TRANSFER.. CALL SETFCB ;..CMDS AND GO TO BEGINNING OF.. POP H ;..PROGRAM. WILL FOLLOW SAME LOGIC.. JMP RESTART ;..AS IF PROGRAM WERE CALLED WITH.. ;..CP/M COMMAND LINE. ; NOTVLD: CALL NOTVLDMSG JMP XPRT ; NOTVLDMSG: CALL ILPRT DB '++ Invalid Command ++',CR,LF,BELL,0 RET ; DISCON1: CALL JMP$DISCONNT CALL ILPRT DB CR,LF,'<< Disconnected >>',CR,LF,BELL,0 JMP EXITMEN ; BYEBYE: CALL ILPRT DB CR,LF,'Goodbye...',CR,LF,0 XRA A CALL OUT$MODCTLP CALL OUT$MODCTL2 LDA SAVUSR MOV E,A CALL SETUSR LHLD CLDBOOT ;GET COLD BOOT PROM ADDRESS OR WARM BOOT PCHL ;JUMP TO IT ; DIR: MVI C,CURDSK CALL BDOS STA DISKSAV CALL DIRLST LDA DISKSAV MOV E,A MVI C,SELDSK CALL BDOS JMP XPRT ; LOGNEW: LDA NFILFLG ORA A JZ NORESET LDA CMDBUF+6 CPI ' ' JNZ SPECIFD MVI C,CURDSK CALL BDOS ADI 'A' SPECIFD: SUI 'A' STA DISKSAV CPI 16 JNC NOTVLD ; IF CPM2X ;IF CPM VER. 2.X ; CALL GETUSR ;PICK UP CURRENT USER NUMBER MOV B,A ;SAVE IT LDA CMDBUF+7 ;GET NEW USER NUMBER CPI ' ' ;CHECK FOR SPACE JZ SR7B ;EXIT IF NO NEW USER NUMBER SPECIFIED CALL NUMCHK ;CHECK TO SEE IF IT IS A NUMBER MOV B,A ;SAVE LDA CMDBUF+8 ;GET SECOND DIGIT CPI ' ' JZ SR7B ;GO IF SPACE CALL NUMCHK MOV C,A ;SAVE MOV A,B ;GET SAVED FIRST DIGIT ADD A ; X2 ADD A ; X4 ADD A ; X8 ADD B ; X9 ADD B ; X10 ADD C MOV B,A ;SAVE LDA CMDBUF+9 ;GET THIRD DIGIT CPI ' ' JZ SR7B ;GO IF SPACE CALL NUMCHK MOV C,A ;SAVE MOV A,B ;GET SAVED FIRST & SECOND DIGIT ADD A ; X2 ADD A ; X4 ADD A ; X8 ADD B ; X9 ADD B ; X10 ADD C ; CPI 16 ;CHECK FOR < 16 ; JNC NOTVLD ;GO IF NOT MOV B,A SR7B: MOV A,B STA SAVUSR ; ENDIF ;CPM2X ; CALL ILPRT DB 'Insert disk for drive ',0 LDA DISKSAV ADI 'A' CALL TYPE NOTCR: CALL ILPRT DB CR,LF,'Hit return when ready',0 CALL KEYIN CPI 3 ;CTL-C ABORTS LOGIN JZ XPRT CPI CR JNZ NOTCR CALL CRLF MVI C,RESET CALL BDOS LDA DISKSAV MOV E,A MVI C,SELDSK CALL BDOS ; IF CPM2X LDA SAVUSR MOV E,A CALL SETUSR ENDIF ; JMP XPRT ; IF CPM2X ; GETUSR: MVI E,0FFH ;GET CURRENT USER SETUSR: MVI C,USER ;SET-UP FUNCTION CALL JMP BDOS ;NUMBER IN RETURNED IN A ; ENDIF ;CPM2X ; NORESET: CALL ILPRT DB '++ Terminal mode file open ++',CR,LF DB '++ Use WRT or DEL before LOG command ++',CR,LF DB CR,LF,LF,BELL,0 XRA A JMP XPRT ; ERASEF: LXI D,CMDBUF ;PUT CMD LINE INTO FCB AT HL LXI H,FCB CALL CPMLINE CALL MOVEFCB ;MOVE FCB+16 TO FCB LDA FCB+1 CPI ' ' JZ NOTVLD ;GO IF NO FILE SPECIFIED LXI D,FCB MVI C,SRCHF CALL BDOS INR A ;0 IF FILE NOT FOUND JNZ ERAFILE ;OK, GO ERASE CALL ILPRT DB '++ File not found ++',CR,LF,BELL,0 JMP XPRT ; ERAFILE: LXI D,FCB MVI C,ERASE CALL BDOS CALL ILPRT DB 'File erased',CR,LF,0 JMP XPRT ; SETSPD: CALL ILPRT DB 'Enter character output delay [0(none) - 9(longest delay)]: ',0 CALL NUMGET JNC NOCHG1 STA BYTDLY NOCHG1: CALL SPDMSG CALL ILPRT DB CR,LF,'Enter additional delay after [0-9]: ',0 CALL NUMGET JNC NOCHG2 RLC ;X2 RLC ;X4 STA CRDLY NOCHG2: CALL CRDLYMSG JMP XPRT ; NUMGET: LXI D,CMDBUF CALL INBUFF LDA CMDBUF+2 ;GET NUMBER CPI ' ' RZ NUMCHK: SUI '0' CPI 10 RC POP PSW ;PRESERVE STACK JMP NOTVLD ; SPDMSG: CALL ILPRT DB 'Terminal mode file output delay is 0.',0 LDA BYTDLY CALL GIVNUM CALL ILPRT DB ' seconds per character',CR,LF,0 RET ; CRDLYMSG: CALL ILPRT DB 'Additional delay after is 0.',0 LDA CRDLY CALL GIVNUM CALL ILPRT DB ' seconds',CR,LF,0 RET ; GIVNUM: ADD A ;2X CPI 10 MOV B,A JNC NOZERO MVI A,'0' CALL TYPE MOV A,B NOZERO: PUSH H MOV L,A MVI H,0 CALL DECOUT POP H RET ; SETTIM: CALL SORPTST JNZ NOTVLD CALL ILPRT DB 'Use 0-8 to give baud rate for S mode time-to-send message,' DB CR,LF DB 'where 0=110, 1=300, 2=450, 3=600, 4=710, 5=1200, 6=2400,' DB CR,LF DB ' 7=4800, and 8=9600 Baud.' DB CR,LF,LF,'Enter value: ',0 CALL NUMGET CPI 9 JNC NOTVLD STA MSPEED CALL SETTIM2 JMP XPRT ; SETTIM2: CALL SORPTST JNZ SETTIM3 CALL ILPRT DB 'Rate for the S mode time-to-send message is set to ',0 JMP SETTIM4 SETTIM3: CALL ILPRT DB 'Modem speed is ',0 SETTIM4: JMP BAUDPRT ; SORPTST: LDA SETUPTST MOV B,A LDA PMMIBYTE ORA B RET ; TOGCRC: LDA TOGGLECRC ORA A JZ NOTVLD LDA CKSUMDFLT CMA STA CKSUMDFLT CALL TOGCRC2 JMP XPRT ; TOGCRC2: ORA A JNZ CHEKMSG CALL ILPRT DB 'CRC mode set',CR,LF,0 RET ; CHEKMSG: CALL ILPRT DB 'Checksum mode set',CR,LF,0 RET ; TOGBKSP: LDA TOGGLEBK ORA A JZ NOTVLD LDA CONVBKSP CMA STA CONVBKSP CALL TOGBKSP2 JMP XPRT ; TOGBKSP2: LDA CONVBKSP ORA A JZ NORUBMSG CALL ILPRT DB 'Backspace is rub',CR,LF,0 RET ; NORUBMSG: CALL ILPRT DB 'Backspace is backspace',CR,LF,0 RET ; TOGLOC: LDA TOGGLELOC ORA A JZ NOTVLD LDA LOCONEXTCHR CMA STA LOCONEXTCHR CALL TOGLOC2 JMP XPRT ; TOGLOC2: CALL ILPRT DB 'Use ',0 LDA LOCONEXTCHR ORA A LDA EXTCHR JZ LOCMSG CALL SHFTYPE DB ' before local command',CR,LF,0 RET ; LOCMSG: CALL SHFTYPE DB ' to send local command to remote',CR,LF,0 RET ; TOGLF: LDA TOGGLELF ORA A JZ NOTVLD LDA ADDLF CMA STA ADDLF CALL TOGLF2 JMP XPRT ; TOGLF2: CALL ILPRT DB 'Linefeed ',0 LDA ADDLF ORA A JNZ LFMSG CALL ILPRT DB 'NOT ',0 LFMSG: CALL ILPRT DB 'sent after ',CR,LF,0 RET ; TOGTXOFF: LDA TOGXOFF ORA A JZ NOTVLD CALL ILPRT DB 'Use XOFF testing? (Y/N): ',0 CALL GETANS JC NOCHG3 STA XOFFTST NOCHG3: CALL XOFFMSG CALL ILPRT DB CR,LF,'Use XON waiting after (Y/N): ',0 CALL GETANS JC NOCHG4 STA XONWAIT NOCHG4: CALL XONMSG LDA XONWAIT ORA A JZ XPRT CMA STA XOFFTST ;DON'T ALLOW BOTH CALL ILPRT DB 'Therefore ',0 CALL XOFFMSG JMP XPRT ; GETANS: LXI D,CMDBUF CALL INBUFF LDA CMDBUF+2 ;GET ANSWER CPI ' ' CMC RZ MOV B,A CPI 'N' MVI A,FALSE RZ MOV A,B CPI 'Y' MVI A,TRUE RZ POP PSW ;PRESERVE STACK JMP NOTVLD ; XOFFMSG: CALL ILPRT DB 'XOFF testing ',0 LDA XOFFTST ORA A JNZ XOTSTON CALL ILPRT DB 'NOT ',0 XOTSTON: CALL ILPRT DB 'used',0 XONMSG3: CALL ILPRT DB ' in terminal mode file output',CR,LF,0 RET ; XONMSG: CALL ILPRT DB 'XON ',0 LDA XONWAIT ORA A JNZ XONMSG2 CALL ILPRT DB 'NOT ',0 XONMSG2: CALL ILPRT DB 'automatically tested after ',0 JMP XONMSG3 ; SETUPENT: LDA SETUPTST ORA A JZ NOTVLD LXI D,CMDBUF+1 CALL JMP$SETUPR JMP XPRT ; NEWFILE: LDA NFILFLG ORA A JNZ NOFILOPN LDA FCB3+1 ;CHECK THAT FILE WAS REQUESTED CPI ' ' JZ NOFILOPN ;IF NO FILE, DON'T ERASE LXI D,FCB3 MVI C,ERASE CALL BDOSRT MVI A,TRUE ;DO NOT ALLOW TERMINAL.. STA NFILFLG ;..SAVE SINCE NO FILE.. CMA ;..SPECIFIED. STA SAVEFLG LXI H,FCB3 CALL INITFCBS LXI H,BOTTRAM SHLD HLSAVE JMP XPRT ; WRTFIL: LDA NFILFLG CPI TRUE JZ NOFILOPN LDA FCB3+1 ;CHECK THAT FILE WAS REQUESTED CPI ' ' JZ NOFILOPN LHLD HLSAVE CALL NUMRECS ;DISK WRITE ROUTINE AS USED IN.. CALL WRTDSK ;..IN THE INTDSKSV ROUTINE. CALL CLOSE3 MVI A,TRUE STA NFILFLG CMA STA SAVEFLG LXI H,FCB3 CALL INITFCBS ;BLANK OUT FCB SO WRITTEN FILE CAN'T BE ERASED. LXI H,BOTTRAM SHLD HLSAVE JMP XPRT ; NOFILOPN: CALL ILPRT DB '++ No File Open ++',CR,LF,BELL,0 JMP XPRT ; ;THIS ROUTINE DISPLAYS THE PHONE NUMBERS IN THE LIBRARY ; NUMPRN: PUSH H CALL CLRTST CALL ILPRT DB ' Library of Phone Numbers of Remote Systems',0 MVI C,13 ;NUMBER OF LINES TO MOVE LXI H,NUMBLIB ;ADDRESS OF SOURCE MEMORY LXI D,DBUF ;ADDRESS OF TARGET MEMORY CALL NEWLINE ;START WITH CRLF STAX D ;+LF INX D ;AND BUMP IT NUMPRN1: INX H ;SKIP PMMI DIALING LETTER INX H ;AND EQUAL SIGN MVI B,30 ;NUMBER OF BYTES TO MOVE CALL MOVE ;MOVE TO BUFFER CALL SPACES ;2 ENTRIES + 3 SPACES = 63 CHARACTERS INX H INX H MVI B,30 CALL MOVE CALL NEWLINE DCR C ;NUMBER OF LINES TO PRINT JZ NUMPRN2 JMP NUMPRN1 ; NEWLINE: ;PUTS CR-LF AT MEMORY POINTED BY 'DE' MVI A,CR ;CR STAX D ;STORE IT MVI A,LF ;LF INX D ;BUMP POINTER STAX D ;STORE LF INX D ;BUMP POINTER RET ; SPACES: MVI A,20H ;SPACE STAX D INX D ;1 STAX D INX D ;2 STAX D INX D ;3 RET ; NUMPRN2: MVI A,'$' STAX D MVI C,PRINT LXI D,DBUF ;POINT TO TABLE OF NUMBERS TO PRINT CALL BDOS CALL CRLF CALL CRLF POP H JMP XPRT ; COMPARE: MOV B,M ;COMPARES A-REG WITH LIST.. COMPLP: INX H ;..ADDRESSED BY HL. FIRST ELEMENT.. CMP M ;..OF LIST MUST BE NUMBER OF ELEMENTS.. JZ VALID ;..BEING COMPARED. RETURNS WITH.. DCR B ;..CARRY SET IF A-REG DOES NOT.. JNZ COMPLP ;.. CONTAIN AN ELEMENT IN LIST. STC VALID: RET ; NXTSCRN: CALL ILPRT DB 'HIT any KEY to CONTINUE',0 NOKEY1: CALL STAT ;GET KEYBOARD STATUS JZ NOKEY1 ;KEEP LOOPING UNTIL KEYPRESS CALL KEYIN ;GOBBLE UP KEYPRESS CPI 3 ;QUIT? JNZ CLRTST POP PSW ;CLEAN RETURN ADR OFF OF STACK JMP XPRT ; CLRTST: LDA SCRNTEST ORA A JNZ CLRSCRN ; LOTSALF: MVI A,CR CALL TYPE MVI B,12 MVI A,LF LFLOOP: CALL TYPE DCR B JNZ LFLOOP RET ; CURPAR: CALL CLRTST CALL ILPRT DB ' Current Settings',CR,LF,LF,LF,0 LDA CKSUMDFLT CALL TOGCRC2 LDA LSTTST ORA A JZ NOLST3 CALL LSTMSG NOLST3: CALL SETTIM2 CALL TOGBKSP2 CALL TOGLF2 CALL TOGLOC2 CALL ILPRT DB 'Terminal mode file buffer is ',0 LDA NFILFLG ORA A JZ ACTIVE CALL ILPRT DB 'in',0 ACTIVE: CALL ILPRT DB 'active',CR,LF,'Unused portion of buffer is ',0 CALL GETSPC CALL ILPRT DB ' bytes',CR,LF,0 CALL XOFFMSG CALL XONMSG CALL SPDMSG CALL CRDLYMSG CALL CRLF JMP XPRT ; GETSPC: CALL GETMAX MOV B,A LHLD HLSAVE STC CMC MVI A,0 SBB L MOV L,A MOV A,B SBB H MOV H,A JMP DECOUT ; ;ADJUSTS LOOP COUNTERS FOR VARIOUS CLOCK SPEEDS ; FIXCNT: LDA CLOCK CPI 1 RZ PUSH D PUSH H POP D CNTMUL: DAD D DCR A JNZ CNTMUL POP D RET ; COMPLIST: DB 6, 'S', 'R', 'T', 'E', 'H', 'L' ILCOMP: INLNCOMP ;A LIB MACRO INBUFF: INBUF ;A LIB MACRO ; ;IF ABOVE ROUTINE DOES NOT LET YOU EDIT IN A PROPER MANNER, ;THEN THE MACRO MAY BE SUBSTITUTED FOR THE FOLLOWING ROUTINE: ; ;INBUFF: ; MVI C,RDBUF ; JMP BDOSRT ;BUT BE CAREFUL OF CONTROL-C ; CPMLINE: CMDLINE ;A LIB MACRO DIRLST: DIRLIST ;A LIB MACRO SENDTIM: SENDTIME ;A LIB MACRO BAUDPRT: PRTBAUD ;A LIB MACRO NFILFLG: DB FALSE ;NORMALLY SET TO FALSE. ALLOWS WRITE TO.. ; ;..MEMORY IN TERMINAL MODE. OPTION: DB 0 ; OPTBL EQU $ ; ANSWFLG: DB 'A' DISCFLG: DB 'D' ORIGFLG: DB 'O' QFLG: DB 'Q' RSEEFLG: DB 'R' SSEEFLG: DB 'S' VSEEFLG: DB 'V' TERMFLG: DB 'T' LOCCHFLG: DB 'L' EPARITY: DB '0' ;EVEN PARITY SUB-OPTION ;ONLY AVAILABLE IN 'S' AND 'R' MODES OPARITY: DB '1' ;ODD PARITY SUB-OPTION ;ONLY AVAILABLE IN 'S' AND 'R' MODES BATCHFLG: DB 'B' ;BATCH FLAG (WHY WAS THIS DISABLED IN EARLIER VERS?) OPTBE EQU $ RESTROPT: ;MUST BE IN SAME ORDER AS TABLE ABOVE DB 'A','D','O','Q','R','S','V','T','L' DB '0','1','B' ; ;THE NEXT 13 BYTES EQUAL THE NUMBER OF BYTES BETWEEN SECTNOB AND SECTNOE RESTSN: DB 0,0,0,0,0,0 DW DBUF DB 0,0,0,0,0 ; SECTNOB EQU $ ;START OF TABLE MARKER RCVSNO: DB 0 ;\ SECTNO: DW 0 ; \ ERRCT: DB 0 ; \ ERRCDE: DB 0 ; \ EOFLG: DB 0 ; \ 13 BYTES BETWEEN TABLE MARKERS SECPTR: DW DBUF ; / SECINBF: DB 0 ; / MAXEXT: DB 0 ; / RCNT: DW 0 ; / DATAFLG: DB 0 ;/ SECTNOE EQU $ ;END OF TABLE MARKER ; MODCTLB: DB 07FH UARTFLG: DB TRUE UARTCTLB: DB ANSWMOD ;(WAS PREVIOUSLY ORIGMOD) SAVEFLG: DB FALSE LASTBYT1: DB 0 LASTBYT2: DB 0 EXACFLG: DB 0 ECHOFLG: DB FALSE LOCFLG: DB FALSE CKSUMFLG: DB TRUE LISTFLG: DB FALSE LISTMOR: DB FALSE FSTFLG: DB TRUE FIRSTME: DB TRUE ;FIRST SOH RECEIVED SWITCH (ZERO AFTER 1ST SOH) EXITFLG: DB TRUE HLSAVE: DW BOTTRAM HLSAVE1: DW BOTTRAM HLSAVE2: DW BOTTRAM CMDBUF: DB 80H,0 DS 80H DISKNO: DS 1 DISKSAV: DS 1 SAVUSR: DS 1 SENDFLG: DS 1 NBSAVE: DS 2 BGNMS: DS 2 FILECT: DS 1 NAMECT: DS 1 ORIGSAV: DS 1 FTYCNT: DS 1 DS 100 STACK: DS 2 FCB3: DS 33 FCB4: DS 33 FCBBUF: DS 15 DBUF EQU $ NAMEBUF EQU DBUF+(DBUFSIZ*1024) ;BUFFER FOR NAMES IN BATCH MODE. ; ;OVERFLOWS ABOVE PROGRAM CODE. ; ; BDOS EQUATES ; RDCON EQU 1 WRCON EQU 2 LSTOUT EQU 5 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 CURDSK EQU 25 STDMA EQU 26 USER EQU 32 FILSIZ EQU 35 BDOS EQU 5 REIPL EQU 0 FCB EQU 5CH FCBEXT EQU FCB+12 FCBSNO EQU FCB+32 FCBRNO EQU FCB+32 FCB2 EQU 6CH ; LAST END 100H