TITLE 'MDM705 (02/27/83) -- CP/M MODEM PROGRAM' ; ; THIS PROGRAM ORIGINATED IN 1977. WRITTEN BY WARD CHRISTENSEN, IT ; HAS SINCE UNDERGONE EXTENSIVE REVISIONS. SO MANY PEOPLE HAVE ADDED ; USEFUL FEATURES IT WOULD BE DIFFICULT TO LIST THEM ALL. OTHER VER- ; SIONS OF THE ORIGINAL PROGRAM HAVE BEEN MADE, THIS ONE CATERING TO ; THOSE USING THE 'PMMI' AUTO-DIALING S-100 MODEM. THOSE HAVING OTHER ; MODEMS CAN READILY USE IT, LOSING ONLY THE AUTO-DIALING FEATURE. BE ; CAREFUL TO SET THE PORTS AND OTHER OPTIONS CORRECTLY. OVERLAYS HAVE ; BEEN MADE ALLOWING RAPID ADAPTATION TO COMPUTERS NOT USING THE S-100 ; BUS. IT CONFORMS READILY TO NORMAL UARTS AND OTHER I/O DEVICES SUCH ; AS THE 2661, 8250, 8251, ETC. ; ; NOTE: If upgrading this program, please add modest comments that ; describe the changes and the date they were made. Then send ; to TCBBS in Dearborn (313) 846-6127. ; ; GENERAL INTEREST: When transferring files modem-to-modem, the batch ; mode is extremely useful. It not only speeds things up, but there ; is no timeout at the receiving end while the other person prepares ; to send. With normal single program transfer, the receiving end ; switches to checksum in one minute and times out completely in 100 ; seconds. This offers ample opportunity to transfer programs between ; individuals. Remember the batch mode can be used for single files ; or with wildcards. Many outstanding optional features have been ; added by various people throughout its development. Our thanks to ; all those who have - and will - contribute. ; - Irv Hoff, W6FFC ; ;*********************************************************************** ; ; 830326:0825 ; Delay between dialled numbers increased from 2 to 8 units ; MDM705P for use with old 416-48x-xxxx exchange that gets lost if ; one dials too fast. ; Various magic numbers in Break and Dialler routines replaced ; with appropriate equates (mods NOT marked). ; Option PAR added for the PMMI-only section to toggle the ; terminal mode between 8 bits no parity (default) and 7 bits ; even parity as required by dear old primitive IBM front end. ; - Greg Louis ; ; 02/27/83 'V' mode corrected. When CTL-B is used to change Baudrate ; on-the-fly, the Baudrate remains the same when going to-from ; MDM705 the "T" mode now. (Previously it would often ignore CTL-B ; entirely if the "T" mode had been selected with no Baudrate ; included, leading to notices regarding "flakey operation".) ; Thanks to Frank Gaude'. Deleted some superfluous coding. ; Fixed quiet mode timing for suitable use with "BYE", etc. ; - Irv Hoff ; ; 02/13/83 1. 'D' option (if PMMI) auto-disconnects the phone line at ; the end of a transfer if included in command. (Pre- ; viously said "Press return to disconnect"). ; MDM704 2. Added an 'X' option that auto-disconnects at the end of ; a transfer and jumps to 'BYEBYE' which reboots back to ; CP/M. Does a cold boot if CLDBOOT has been entered. ; 3. Fixed the "quiet mode" so that only those messages which ; can interfere with the BYE protocol are suppressed. ; - R. L. Plouffe ; ; 02/07/83 Reworked the "quiet" mode (used in conjunction with "BYE" on ; some occasions for batch mode, etc.) Protection added for ; MDM703 quiet mode to insure returning to command prompt after file ; transfer even if "T" was inadvertently selected. Added nor- ; mal method of changing user area as well as with LOG. Other ; modest changes. Thanks to Frank Gaude' for suggestions and ; testing. - Irv Hoff ; ; 01/27/83 Rstores original drive and user area when returning to CP/M. ; Reorganized the PMMI dialing section, fixing several long- ; MDM702 standing bugs in the auto-redialing system. Also can now ; (finally) auto-redial off the menu command line, including ; ringback numbers. Number of dialing attempts now displayed. ; Added triple protection against inadvertently erasing all ; files on a disk with improper use of "*" or "?" wildcards. ; Batch mode rejected except when using "S" or "R". If send- ; ing a file in "T" mode (via CTL-T), line feeds are displayed ; but not sent. Line delays are triggered from CR characters. ; - Irv Hoff ; ; 01/10/83 Added some of the features in the current COMM 7.13 version. ; It is now simple to abort while in send or receive. Clock ; MDM701 speeds up to 25.5 MHz may be used, in 0.1 MHz increments. ; Several glitches fixed. Particular thanks to Frank Gaude' ; for permission to adapt some of his routines, plus his help ; and continued interest. - Irv Hoff ; ; 01/01/83 First version. This is similar to MODEM 7.98 but with the ; macro library now integral in the program. It assembles via ; MDM700 ASM or MAC as well as with other popular assemblers. Those ; contributing heavily to recent development leading to MODEM ; 7.98 were Bruce Ratoff, Paul Kelley, Frank Gaude', Mark Pul- ; ver, Bob Plouffe and myself. Many others have made large ; contributions in previous years. MDM700 was selected as a ; name to commence a new series of version numbers. This also ; can readily be placed on data bank systems that limit file ; names to a total of 6 characters. ; - Irv Hoff ; ;*********************************************************************** ; ; TRUE EQU 0FFH FALSE EQU 0 ; ; DBUFSIZ: EQU 16 ;buffer size for file transfer in Kbytes ; ERRCRC: EQU 6 ;number of times to try CRC mode.. ;..before switching to CHECKSUM ; ; PMMI EQUATES (The first 8 lines are also of particular interest to ; non-PMMI users.) ; PORT: EQU 0C0H ;*PMMI base address (0C0H is typical) ; MODCTLP: EQU PORT ;modem control port MODDATP: EQU PORT+1 ;*modem data port BAUDRP: EQU PORT+2 ;modem baud rate port MODCTL2: EQU PORT+3 ;modem 2nd control port MODRCVB: EQU 02H ;modem receive bit (DAV) MODRCVR: EQU 02H ;modem receive ready MODSNDB: EQU 01H ;modem send bit (transmit buffer empty) MODSNDR: EQU 01H ;modem send ready bit ; ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; 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 but error codes FRMER: EQU 20H ;mask for framing error ORUNER: EQU 10H ;mask for overrun error PARER: EQU 08H ;mask for parity error ; ANSWMOD: EQU 1EH ;answer mode ORIGMOD: EQU 1DH ;originate mode ORIG7E EQU 29H ;orig mode, 7 bits, even parity BDNMCH: EQU 75H ;bad name match LIBLEN: EQU 34 ;length of each phone library entry RUB: EQU 7FH ;rub WAITCTS: EQU 100 ;number of seconds (x5) to wait for the ;computer to answer after PMMI auto-dial ;100=20 sec, 150=30 sec, 255=51 sec. ;any number 0-255 acceptable CRC: EQU 'C' ;requests '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 = ok 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 or receive EOFCHAR: EQU 'Z'-40H ;^Z = end of file ; BOTTRAM SET LAST+100H AND 0FF00H ; ; ORG 0100H ; ; JMP START ;skip the data area below ; ; 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, false=non-PMMI modem ; CLOCK: DB 40 ;*clock speed x10, up to 25.5 mhz. ;2 MHz=20, 3.68 MH=37, 4 MHz=40, etc. MSPEED: DB 1 ;*sets display time for sending a file ;0=110 1=300 2=450 3=600 4=710 ;5=1200 6=2400 7=4800 8=9600 BYTDLY: DB 5 ;default time to send character in ;terminal mode file transfer (0-9) ;0=0 delay, 1=10 ms, 5=50 ms, 9=90 ms CRDLY: DB 5 ;end-of-line delay after CRLF in terminal ;mode file transfer for slow BBS systems ;0=0 delay, 1=100 ms, 5=500 ms, 9=900 ms NOOFCOL: DB 5 ;number of directory columns SETUPTST: DB FALSE ;true=non-PMMI setup routine SCRNTEST: DB TRUE ;*true=if home cursor and clear screen ;routine at CLRSCRN 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 cmd if EXTCHR precedes ;false=not local cmd 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 sending a file in terminal mode XONWAIT: DB FALSE ;true=wait for XON aftersending CR while ;transmitting a file in terminal mode TOGXOFF: DB TRUE ;true=allow toggling of XOFF testing 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 250 ;125 for 20pps, 250 for 10pps on PMMI ;not used if PMMI FALSE CLDBOOT: DW 00000H ;warm reboot address - put your own ;address for a cold reboot if preferred 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 DB 0,0,0,0,0,0,0 ;spares if needed for non-PMMI OUT$MODDATP: OUT MODDATP ! RET ;out modem data port DB 0,0,0,0,0,0,0 ;spares if needed for non-PMMI IN$MODDATP: IN MODDATP ! RET ;in modem data port DB 0,0,0,0,0,0,0 ;spares if needed for non-PMMI 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 ; ; MOD(BGL) FOR PARITY SWITCH DURING CONVERSATIONAL TRANSMISSION PARTY: DB ORIGMOD PARTOG: DB ORIGMOD+ORIG7E ; ; Clear sequences are for Televideo, Lear Siegler, etc. Change to match ; your terminal. (Heath uses ESC 4AH for clear to end of screen, ESC 45H ; to clear screen. Lear Siegler and others use ESC 79H for clear to end ; of screen and ESC 3AH to clear screen.) Room allowed for four bytes. ; (Last zero needed for stopping the string display. Any extra 0's just ; act as NOP's.) ; CLREOS: CALL ILPRT DB 'O'-40H,0,0,0,0 RET ;..... ; ; CLRSCRN: CALL ILPRT DB 'L'-40H,0,0,0,0 RET ;..... ; ; ; NEXT FIVE LINES SHOULD NOT BE CHANGED BY USER OVERLAY ; JMP$ILPRT: JMP ILPRT JMP$INLNCOMP: JMP INLNCOMP JMP$INBUF: JMP INBUF JMP$SYSVER: JMP SYSVER JMP$DIAL: JMP DIAL JMP$DISCONNT: JMP DISCONNT ; ; ; Send version number and date ; 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 ;PUT IN PMMI CONTROL PORT NUMBER 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. CAN BE ANY LENGTH DESIRED. MUST END WITH 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: ; ; ; SETS THE BAUD RATE FOR THE PMMI BOARD (IF ONE IS SPECIFIED) ; SETBAUD: LDA PMMIBYTE ORA A RZ ;IF NOT PMMI S-100 BOARD, IGNORE REST ; LDA ANSWFLG ;IF 'O' OR 'A' NOT REQUESTED AND ORA A ; BAUDRATE NOT SPECIFIED, RETURNS JZ FIXBAUD ; WITH CURRENT MODE AND RATE LDA ORIGFLG ;IF OPTION REQUESTED, A BLANK FORCES 300 ORA A ; BAUD AS DOES A NULL FROM NEWBAUD RNZ ;NO CHANGE IF NEITHER 'O' OR 'A' SHOWN ; FIXBAUD: CALL GETBAUD MOV B,A ;SAVE THE BAUD RATE VALUE CALL OUT$BAUDRP ;SET THE PMMI BOARD TO THAT BAUDRATE CALL CHGMSPD ;GET THE 'MSPEED' VALUE MOV A,C ;IT COMES BACK IN THE 'C' REG. STA MSPEED ;SET THE CORRECT 'MSPEED' MOV A,B ;GET THE BAUD RATE VALUE BACK CPI 52 MVI A,5FH ;DTR (FILTER FOR OVER 300 BAUD) JC GT300 ;YES, GREATER THAN MVI A,7FH ;DTR (FILTER FOR 300 AND LESS BAUD) ; GT300: CALL OUT$MODCTL2 STA MODCTLB ;SAVE MODEM CONTROL BYTE LDA UARTFLG ;UART CONROL BYTE FOR 'A' OR 'O' ORA A ; MOD(BGL)*** LDA PARTY ;GET ORIGINATE MODE JZ OFFHOOK ;EXIT IF 'O' SET MVI A,ANSWMOD ; OFFHOOK: LXI H,7500 ; OFFDLY: DCR L JNZ OFFDLY DCR H JNZ OFFDLY CALL OUT$MODCTLP RET ;..... ; ; ;----------------------------------------------------------------------- ; ; Phone number library table for PMMI auto-dialing. Each number must be ; as long as "LIBLEN" (EQU at start of program). Some areas require ex- ; tra characters such as: 1-313-846-7127. Room is left for those. ; ; '----5---10---15---20---25---30--34' NUMBLIB: DB 'A=Amrad...............703-734-1387' ;'A' DB 'B= ' ;'B' DB 'C=CBBS Pasadena.......213-799-1632' ;'C' DB 'D=PMMI................703-379-0303' ;'D' DB 'E=Edward Huang........415-595-0541' ;'E' DB 'F= ' ;'F' DB 'G=Gasnet NASA.........301-344-9156' ;'G' DB 'H=Dave Hardy..........313-846-6127' ;'H' DB 'I=Wayne Hammerly......301-953-3753' ;'I' DB 'J=RBBS Pasadena.......213-356-1034' ;'J' DB 'K=Bob Kuhman..........408-732-2433' ;'K' DB 'L=Program Store.......202-337-4694' ;'L' DB 'M=Dick Mead...........213-799-1632' ;'M' DB 'N=Mtn/View PICONET....415-965-4097' ;'N' DB 'O=Bob Plouffe.........703-524-2549' ;'O' DB 'P=Keith Petersen.....313-759-6569R' ;'P' DB 'Q=Bruce Ratoff........201-272-1874' ;'Q' DB 'R=Mark Pulver.........312-789-0499' ;'R' DB 'S=Paul Traina.........408-867-1243' ;'S' DB 'T=TCBBS, Dearborn.....313-846-7127' ;'T' DB 'U= ' ;'U' DB 'V= ' ;'V' DB 'W=Ward Christensen....312-545-8086' ;'W' DB 'X= ' ;'X' DB 'Y= ' ;'Y' DB 'Z= ' ;'Z' DB 0 ;end ; '----5---10---15---20---25---30--34' ;..... ; ; ;*********************************************************************** ; ; P - R - O - G - R - A - M S - T - A - R - T - S H - E - R - E ; ;*********************************************************************** ; ; START: POP H ;GET THE STACK RETURN TO CCP SHLD EXIT1+1 ;ENABLES RETURN TO CCP LXI SP,STACK ;START LOCAL STACK CALL ILPRT DB CR,LF,'MDM705 - 02/27/83',CR,LF,0 CALL INITADR ;INITIALIZE ADDRESSES CALL JMP$SYSVER ;GIVE CONFIGURATION MESSAGE CALL GETUSER ;GET CURRENT USER NUMBER STA OLDUSER MVI A,TRUE ;0FFH STA NFILFLG ;RESET THE NO FILE FLAG TO SHOW NO FILE CMA ;0 STA ORIGMOD ;SET INITIALLY FOR ORIGINATE MODE 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 COUNT ; 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 - LGNG 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 ;MOD(BGL)*** LDA PARTY 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$DIAL ;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 NTVLDMSG ;SAY NOT A VALID OPTION JMP MENU ;NO VALID OPTION SPEC'D, GO MENU ; ; ; Revised terminal routine allowing memory save. First checks for bad ; options, to prevent wiping out the disk with accidental memory save. ; DSKSAVE: LDA BATCHFLG ;BATCH FLAG SET? ORA A JNZ DSKSAVE1 XRA A STA BATCHFLG JMP NOTVLD ;IF YES, ERROR FOR "E", "L" OR "T" ; DSKSAVE1: LDA FCB+1 ;FIRST CHARACTER OF FILENAME (IF ANY) CPI ' ' ;FILE SPECIFIED? JNZ GOODNM ;YES, GOOD NAME MVI A,TRUE ;0FFH STA NFILFLG CMA 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 ;SHOW NOW SAVING TO MEMORY FOR DISK FILE STA LISTMOR ;STOP ANY BUFFERED PRINTER OUTPUT ; TERM: LDA UARTFLG STA ORIGSAV ORA A MVI A,ANSWMOD JNZ TERM1 ;MOD(BGL)*** LDA PARTY ;GET DEFAULT PARITY ; TERM1: 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 NTEXAFLG ;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 ;... ; ; NTEXAFLG: 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 ;GOING TO USE THE EXTERNAL PRINTER? ORA A JZ NOLST ;IF NOT, SKIP THIS AREA LDA LSTCHR ;GET THE PRINTER CONTROL-CHARACTER CMP B ;DID WE JUST ASK FOR PRINTER CONTROL? JNZ NOLST ;IF NOT, EXIT LDA LISTFLG ;OTHERWISE RESET THE PRINTER TOGGLE CMA STA LISTFLG ;AND STORE CALL CRLF CALL CRLF CALL LSTMSG ;TELL IF PRINTER IS ON OR OFF NOW CALL CRLF JMP TERML ;BACK TO THE TERMINAL MODE AGAIN ;..... ; ; NOLST: LDA PMMIBYTE ;USING A PMMI BOARD? ORA A JZ S2 ;IF NOT, SKIP THE NEXT FEW LINES 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 ;..... ; ; ;*********************************************************************** ; ; SEND A CP/M FILE ; ;*********************************************************************** ; ; SENDFIL: MVI A,TRUE ;ALWAYS FORCE CHECKSUM MODE.. STA CRCFLAG ;..INITIALLY ON SEND ; 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,100 CALL WAITNAK ; SENDLP: CALL CKABORT ;WANT TO TERMINATE WHLE SENDING FILE? CALL RDRECD JC SENDEOF CALL INCRRNO MVI A,1 STA ERRCT ; SENDRPT: CALL CKABORT ;WANT TO TERMINATE WHILE SENDING FILE? CALL SENDHDR CALL SENDREC LDA CRCFLAG 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 CRCFLAG ;STORE IT ; RCVFIL1: CALL PARITY ;SET PARITY IF REQUESTED LDA BATCHFLG ;USING BATCH TRANSFER? ORA A JNZ RCVC1 ;IF NOT, EXIT MVI A,FALSE ;FLAG WHERE TO RETURN.. STA SENDFLG ;..FOR NEXT FILE TRANS. CALL GETFN ;GET THE FILE NAME. JNC RCVC2 ;CARRY SET MEANS NO MORE FILES. MVI A,'B' ;STOP BATCH.. STA BATCHFLG ;..MODE OPTION. JMP DONE ;... ; ; RCVC1: LDA FCB+1 ;MAKE SURE FILE IS NAMED CPI ' ' JZ BLKFILE JMP RCVC3 ;... ; ; RCVC2: CALL CKCPM2 CALL CKBAKUP ; RCVC3: CALL ERASFIL CALL MAKEFIL LDA BATCHFLG ;USING BATCH TRANSFER? ORA A JZ RCVC4 ;IF YES, DO NOT PRINT MESSAGE CALL ILPRT DB 'File open, ready to receive',0 ; RCVC4: LDA CRCFLAG ;USING CRC MODE? PUSH PSW ;SAVE THE FLAG'S VALUE ORA A JZ RCVC5 ;IF YES, EXIT CALL ILPRT ;OTHERWISE IN CHECKSUM MODE DB CR,LF,'CHECKSUM in effect',CR,LF,0 JMP RCVC6 ;... ; ; RCVC5: CALL ILPRT DB CR,LF,'CRC in effect',CR,LF,0 LDA QFLG ;IN QUIET MODE NOW? ORA A CZ CRLF ;AN EXTRA CRLF FOR QUIET MODE ; RCVC6: POP PSW ;GET THE FLAG'S VALUE BACK ORA A ;IN CRC MODE? MVI A,CRC JZ RCVC7 ;IF YES, EXIT MVI A,NAK ;NAK FOR CHECKSUM MODE ; RCVC7: CALL SEND ;NOW SEND THE 'CRC' (OR 'NAK') ; RCVLP: CALL RCVRECD JC RCVEOT CALL WRRECD CALL INCRRNO CALL SENDACK JMP RCVLP ;..... ; ; RCVEOT: CALL WRBLOCK CALL SENDACK CALL CLOSFIL JMP DONE ;..... ; ; ;*********************************************************************** ; ; 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 NAME OF FILE TO SEND IN "T" (TERMINAL) MODE ; GET: CALL ILPRT DB CR,LF,'File name to send? (RET to quit): ',0 LXI D,CMDBUF CALL INBUF LDA CMDBUF+2 ;WAS FILE ENTERED? CPI ' ' JZ TRANSL2 LXI D,CMDBUF LXI H,FCB4 CALL CMDLINE LXI D,FCB4 MVI C,OPEN CALL BDOS CPI 0FFH ;RETURN WITH 0FFH MEANS JZ TRANSL1 ;FILE DOES NOT EXIST ; ; ; CHOICE OF NORMAL SPEED OR DELAYS BETWEEN CHARACTERS / LINES ; CALL ILPRT DB 'Want to include time delays? (Y/N): ',0 CALL KBDCHR CPI 'N' ;IF 'N' SEND NORMAL SPEED JZ GET1 XRA A ;OTHERWISE USE CHARACTER / LINE DELAYS ; GET1: STA DLYFLG ;STORE THE DECISION CALL CRLF LXI D,80H MVI C,SETDMA CALL BDOS ; ; ; GET 128-BYTE RECORD ; READMR: LXI D,FCB4 MVI C,READ CALL BDOS CPI 1 ;END OF FILE JZ RETURNS CPI 2 ;BAD READ JZ RETURNU ; CALL SEND80C ;SEND ONE 128-CHAR RECORD ; CPI EOFCHAR ;END OF FILE - OMIT IF OBJECT.. JZ RETURNS ;..CODE IS TO BE SENT. CPI CAN ;CANCELLATION? JNZ READMR ; TRANCAN: CALL ILPRT DB CR,LF,LF,'++ Transfer cancelled ++',CR,LF,BELL,0 ; RETURN: POP PSW POP B POP D POP H RET ;..... ; ; RETURNS: CALL ILPRT DB CR,LF,'[Transfer completed]',CR,LF,BELL,0 JMP RETURN ;..... ; ; RETURNU: CALL ILPRT DB CR,LF,'++ File transfer unsuccessful ++',CR,LF,BELL,0 JMP RETURN ;..... ; ; TRANSL1: CALL ILPRT DB CR,LF,'++ No file with that name ++',CR,LF,0 ; TRANSL2: CALL ILPRT DB CR,LF,'"R" - return to modem',CR,LF DB '"A" - re-enter a name: ',BELL,0 CALL KBDCHR CPI CR JZ TRANSL2 CALL CRLF CPI 'A' JZ GET ;GET A FILE NAME AND START OVER CPI 'R' JNZ TRANSL2 JMP RETURN ;IF AN 'R', ALL DONE ;..... ; ; ; SEND ONE 128-BYTE RCORD ; SEND80C: MVI B,80H LXI H,80H ; SENDCH1: PUSH D CALL SPEED ;0-90 MS. DELAY BETWEEN CHARACTERS POP D MOV A,M CPI LF ;LF CHAR? JZ SKIP22 CALL MODOUT ;SEND THE CHARACTER TO MODEM 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 ;... ; ; SKIP22: CALL TYPE ;SHOW LF ON CRT, DO NOT SEND TO MODEM JMP SKIP12 ;GET NEXT CHAR ;... ; ; ; Send the character to the output ; MODOUT: PUSH PSW ; MODOUTL: LDA XOFFTST ORA A CNZ TXOFF CALL SENDRDY JNZ MODOUTL POP PSW CALL OUT$MODDATP ;SEND CHARACTER TO MODEM CALL TYPE ;SEND CHARACTER TO CRT CPI CR ;WAS IT AN END OF LINE? RNZ ;IF YES, GIVE A HEFTY DELAY ; ; ; Delay to allow slow BBS systems (most use BASIC) to enter the line. ; Choice of 0-9 for about 100 ms. each, maximum of 900 ms. ; MODOUTN: LDA XONWAIT ;WAIT FOR XON AFTER CR ? ORA A JNZ WAITXON ;IF YES, HANDLE SEPARATELY MVI D,10 ; MODOUTT: PUSH D CALL SPEED1 ;10 MS DELAY POP D DCR D JNZ MODOUTT ;10 LOOPS FOR 100 MS. RET ;..... ; ; ; Add from 0 to 90 ms. delay between characters for slow (most use ; BASIC) bulletin board systems. Also used to add 0-900 ms. delay ; between lines. ; SPEED: LDA BYTDLY ;GET DELAY BETWEEN CHARACTERS (0-9) JMP SPEED1+3 ;1=10 MS, 5=50 MS, 9=90 MS, ETC. ; SPEED1: LDA CRDLY ;GET DELAY AFTER CRLF (0-9) ORA A ;100 MS, 5=500 MS, 9=900 MS, ETC. RZ ;IF NO DELAY NEEDED, RETURN MOV C,A ;STORE NUMBER REQUESTED IN C-REG. LDA DLYFLG ;WANT ANY DELAYS THIS FILE? ORA A RNZ ;IF NOT, SKIP THIS SECTION ; SPEED2: CALL SPEED3 ;OUTER LOOP DCR C JNZ SPEED2 RET ;DONE WHENEVER THE C-REG. IS ZERO ;... ; ; SPEED3: PUSH H LXI H,14 ;10 MILLISECONDS LDA XOFFTST ORA A JZ SPEED4 ; LXI H,10 ;7 MILLISECONDS FOR XOFF TESTING LDA ECHOFLG ORA A JZ SPEED4 ; LDA LOCFLG ;7 MILLISECONDS (SAME AS ECHOFLG) ORA A JZ SPEED4 ; LXI H,75 ;5 MILLISECONDS FOR REMOTE ECHO ; SPEED4: CALL FIXCNT ;MULTIPLY DELAY BY CLOCK SPEED PUSH H POP D ;GET THE HL-COUNT INTO DE PAIR POP H ;PUT STACK BACK TO NORMAL ; SPEED5: DCX D ;INNER LOOP LDA XOFFTST ORA A CNZ TXOFF MOV A,E ORA D JNZ SPEED5 RET ;... ; ; TXOFF: CALL RCVREADY RNZ CALL IN$MODDATP ANI 7FH CPI XOFF CZ WAITXON RET ;..... ; ; WAITXON: CALL RCVREADY JNZ WAITXON CALL IN$MODDATP ANI 7FH CPI XON RZ ; WTXON2: CALL STAT ;TEST TO SEE IF REQUESTING CANCELLATION ORA A JZ WAITXON CALL KEYIN ;CAN ABORT IF THE X-ON NEVER COMES CPI CAN JNZ WAITXON RZ ;..... ; ; ;*********************************************************************** ; ; SUBROUTINES ; ;*********************************************************************** ; SENDFN: CALL ILPRT DB 'Awaiting name NAK',CR,LF,0 MVI E,100 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: LDA QFLG ;IN QUIET MODE NOW? ORA A JNZ SKPMON ;IF NOT, EXIT LDA NSEEFLG ;SET FLAG FOR NO SEND TO MODEM ; SKPMON: MOV A,M ;SEND NAME ANI 7FH ;STRIP HIGH ORDER BIT SO CP/M 2.. CALL SEND ;..WON'T SEND R/O FILE DESIGNATION. MVI A,TRUE STA NSEEFLG LDA QFLG ORA A MOV A,M CNZ 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 CALL ILPRT DB CR,LF,'++ CHECKSUM error ++',CR,LF,0 MVI E,100 ;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 INITFCB+2 ;DOES NOT INITIALIZE DRIVE CALL ILPRT DB 'Awaiting FILENAME',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 ;WAIT AWHILE FOR FILE NAME CALL RECV ;GET CHAR JNC GETNM2 CALL ILPRT DB CR,LF,'Time out receiving FILENAME',CR,LF,0 JMP GCKSER ;..... ; ; GETNM2: 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 CALL FTYTST PUSH B ;SAVE CKSUM MVI A,ACK ;ACK GETTING LETTERS 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 INITFCB+2 ;..SINCE IT MIGHT BE DAMAGED.. CALL ILPRT DB CR,LF,'++ 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 CMDLINE ;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 64+1 ;NO MORE THAN 64 TRANSFERS RC MVI A,64 ;ONLY X'FER FIRST 64 STA FILECT RET ;..... ; ; BUFMSG: CALL ILPRT DB CR,LF,'** Memory buffer ',0 LDA SAVEFLG ORA A JZ BUFMSG2 CALL ILPRT DB 'open **',CR,LF,':',BELL,0 RET ;..... ; ; BUFMSG2: CALL ILPRT DB 'closed **',CR,LF,BELL,0 RET ;..... ; ; EXITMEN: CALL CRLF CALL CLREOS ;CLEAR LINE TO CLEAN UP ANY MESS JMP MENU0 ;..... ; ; SENDRDY: CALL IN$MODCTLP CALL ANI$MODSNDB JMP CPI$MODSNDR ;..... ; ; SENDLF: CALL SENDRDY 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 SENDRDY JNZ NOSENLOG ;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 ;... ; ; NOSENLOG: 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 ;SEE IF PRINTER SHOULD BE ON OR OFF 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 .. ; ;..ORA BDOS HAS BEEN.. SUB1: DCR A ;..REACHED AND DISKSAVE IS NEEDED RET ;..... ; ; CHKPRNT: LDA LISTFLG ;OUT TO PRINTER? ORA A RZ ;RETURN IF NOT LDA NFILFLG ;IS BUFFER USED FOR FILE? ORA A ;IF YES DON'T BUFFER PRINTER, HOWEVER.. CALL GETMAX ;..CHARACTERS WILL BE LOST IF PRINTER LHLD HLSAVE1 ;..SLOWER THAN MODEM 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 ORA A RZ ;RETURN IF PRINTER NOT READY MOV C,B ;ELSE PRINT CHARACTER JMP LISTER ; GOLIST: CALL LSTSTAT ORA A RZ ;RETURN IF PRINTER NOT READY 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 THE ; 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 CTL-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 CTL-S. CALL INMODEM ;ADD MORE CALLS TO INMODEM.. STA LASTBYT2 ;..AND STA LASTBYT# IF YOU ARE.. PUSH D CALL NUMREC1 ;GET NUMBER OF RECORDS TO PUT ON DISK CALL WRTDSK ;WRITE THE RECORDS POP D LXI H,BOTTRAM INR D DCR D ;TEST BUFFER COUNT FOR ZERO JZ CTLQ LDA LASTBYT1 ;GET THE LAST BYTES THAT WERE.. MOV M,A ;..SAVED AND PUT THEM IN.. INX H ;..BOTTRAM. CALL TYPE DCR D JZ CTLQ LDA LASTBYT2 MOV M,A INX H CALL TYPE ; CTLQ: 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 BRKMSK ;SET THE TRANSMIT BREAK BIT LOW CALL OUT$MODCTL2 ;SEND IT TO THE MODEM PUSH H LXI H,48 ;100 MS. BREAK 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,48 ;100 MILLISECONDS 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 RECORDS 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. ;..... ; ; ; WRITE TO DISK BUT FIRST CHECK TO SEE IF ANYTHING TO WRITE. IF NOT, ; CLOSE THE EMPTY FILE. ; WRTDSK: LXI D,BOTTRAM ;GET FIRST CHARACTER LDAX D ;GET THE CHARACTER AT START OF BUFFER CPI EOFCHAR ;END OF FILE CHARACTER? JZ NOWRITE ;DO NOT WRITE IF NO DATA TO STORE MOV A,H ;MAKE SURE THERE IS SOMETHING TO STORE ORA L JZ NOWRITE ;DO NOT WRITE IF NO DATA TO STORE ; NEXTWRT: MVI C,SETDMA 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 ;..... ; ; ; IF NO DATA TO STORE ON DISK, CLOSE THE EMPTY FILE AND ERASE IT ; NOWRITE: CALL CLOSFIL ;CLOSE THE EMPTY FILE CALL NOASK ;ERASE THE EMPTY FILE CALL ILPRT DB '++ Nothing to save, erasing the file ++' DB CR,LF,BELL,0 JMP DONETCA ;RESET ANY FLAGS, RETURN TO MENU ;..... ; ; 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 INITFCB LXI H,FCB LXI D,FCB3 MVI B,12 JMP MOVE ;..... ; ; INITFCB: MVI M,0 ;ENTRY AT +2 WILL LEAVE 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 ;..... ; ; ; 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,' ' LXI H,CMDBUF+1 MOV B,M INR B INR B ; SCANLP1: INX H DCR B JZ DNSCAN MOV A,M CPI ' ' JNZ SCANLP1 ; SCANLP2: INX H ;EAT EXTRA SPACES DCR B JZ DNSCAN MOV A,M CPI ' ' 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 ' ' JNZ SCANLP3 LDA NAMECT ;COUNTS NAMES INR A STA NAMECT ; SCANLP4: INX H ;EAT SPACES DCR B JZ DNSCAN MOV A,M CPI ' ' JZ SCANLP4 JMP SCANLP3 ;..... ; ; DNSCAN: MVI M,' ' ;SPACE AFTER LAST CHAR POP H RET ;..... ; ; ; PLACES NEXT NAME IN BUFFER SO 'CMDLINE' MAY PARSE IT ; TRTOBUF: LHLD BGNMS MVI B,0 LXI D,FCBBUF+2 ; TBLP: MOV A,M CPI ' ' 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 ' ' 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,CPMVER ;BDOS 12 -- VERSION NUMBER -- CP/M 2.2? CALL BDOS ORA A RZ MVI C,SETDMA LXI D,80H CALL BDOS MVI C,SRCHF LXI D,FCB CALL BDOS CPI 0FFH RZ ; ADD A ADD A ADD A ADD A ;..32 TO FIND.. ADD A ;..NAME IN DMA. LXI H,80H ADD L MOV L,A ;'HL' POINTS TO DIRECTORY NAME LXI D,9 DAD D ;POINT TO R/O ATTRIBUTE BYTE MOV A,M ANI 80H ;TEST MOST SIGNIFICANT BYTE JNZ MKCHG ;IF SET, MAKE CHANGE INX H ;CHECK SYSTEM ATTRIBUTE BYTE MOV A,M ANI 80H RZ ;NOT $SYS OR $R/O ATTRIBUTE DCX H ; MKCHG: LXI D,-8 DAD D ;POINT HL TO FILENAME + 1 LXI D,FCB+1 ;MOVE DIRECTORY NAME TO FCB.. MVI B,11 ;..WITHOUT CHANGING DRIVE. CALL MOVE LXI H,FCB+9 ;R/O ATTRIBUTE MOV A,M ANI 7FH ;STRIP R/O ATTRIBUTE MOV M,A INX H ;SYSTEM ATTRIBUTE MOV A,M ANI 7FH MOV M,A LXI D,FCB MVI C,30 ;SET NEW ATTRIBUTES IN DIRECTORY CALL BDOS ; ; ; CALLED BY CKBAKUP BELOW, RETURN DONE HERE THROUGH BDOS JUMP ; PLANCHG: LXI H,FCB ;CHANGE NAME TO TYPE "BAK" LXI D,FCB2 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,FCB2 MVI C,ERASE ;ERASE ANY PREV BACKUPS CALL BDOS LXI H,FCB2 ;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 ;..... ; ; ;*********************************************************************** ; ; RECEIVE A RECORD FROM SENDING STATION ; ;*********************************************************************** ; ; RCVRECD: MVI A,1 STA ERRCT XRA A STA ONERR ; RCVRPT: XRA A ;ZERO ACCUM STA ERRCDE ;CLEAR RECEIVE ERROR CODE CALL CKABORT ;WANT TO STOP RECEIVING FILE? LDA QFLG ORA A JZ RCVSQ CALL ILPRT DB CR,'Awaiting # ',0 PUSH H ;SAVE IT LHLD RECDNO ;GET RECORD NUMBER INX H ;BUMP IT CALL DECOUT ;PRINT RECORD NUMBER IN DECIMAL CALL ILPRT DB ' (', 0 CALL DHXOUT ;16-BIT HEX CONVERSION AND OUTPUT CALL ILPRT DB 'H) ',0 MOV A,L ;ONLY LOW BYTE USED BY PROGRAM POP H ;RESTORE IT ; ; ; If CRC is in effect, there is a 10-second timeout to the first SOH. ; It then tries several more times to let the sender know the system is ; capable of receiving a CRC check. At the end of that time a NAK is ; sent which tells the sender to use CHECKSUM checking instead of CRC. ; This allows automatic compatability with systems implementing CRC - ; (Cyclic Redundancy Checking). ; ; During this time incoming CRC and NAK characters are ignored as these ; may be the ones we are sending at each timeout, coming back from the ; full duplex system. ; RCVSQ: MVI B,10-1 ;10-SECOND WAIT FOR 'SOH' OR 'EOT' CHAR. CALL RECV ;..(EXTRA 1 SECOND FROM RCVSERR) JC RCVSTOT ;SEND TIMEOUT MSG IF NO CHAR. IN 10 SEC. CALL RCVERR ;SEE IF IT WAS AN I/O ERROR CPI SOH ;GET A START OF HEADER? JZ RCVSOH ORA A JZ RCVSQ CPI CRC ;IGNORE OUR OWN 'CRC' CHAR. IF ANY JZ RCVSQ ;DO NOT COUNT THIS AS A TIMEOUT CPI NAK ;IGNORE OUR OWN 'NAK' CHAR. IF ANY JZ RCVSQ ;DO NOT COUNT THIS AS A TIMEOUT CPI EOT STC RZ ; MOV B,A LDA BATCHFLG ;USING BATCH MODE NOW? ORA A JNZ RCVSQ1 ;IF NOT, EXIT LDA ONERR ;THIS THE FIRST ERROR THIS TRANSFER? ORA A JNZ RCVSQ1 ;IF NOT, HANDLE NORMALLY^ STA ERRCT ;RESET THE ERROR COUT TO EXCLUDE THIS CMA ;IF YES, IGNORE THIS ERROR STA ONERR ;SET THE FLAG JMP RCVSERR ; RCVSQ1: CALL RCVQERR ;SEE IF QUIET MODE ; RCVSQ2: MOV A,B CALL CRLF CALL HEXO CALL ILPRT DB 'H received not SOH - ',0 ; RCVPRN: CALL SHOWERR ;DISPLAY ERROR COUNT ; RCVSERR: MVI B,1 ;1 SECOND WAIT AFTER ANY CHAR. IS SENT.. CALL RECV ;..TO INSURE SENDER IS WAITING TO COPY JNC RCVSERR ;IF STILL SENDING, IGNORE ALL CHARS. CALL CKABORT ;WANT TO STOP RECEIVING NOW? LDA CRCFLAG ;GET 'CRC' FLAG ORA A ;'CRC' IN EFFECT? MVI A,NAK ;PUT 'NAK' IN ACCUM JNZ RCVSER1 ;NO, SEND THE 'NAK' LDA FIRSTME ;GET FIRST TIME SWITCH ORA A ;HAS FIRST SOH BEEN RECEIVED? MVI A,NAK JZ RCVSER1 ;YES, THEN SEND 'NAK' MVI A,CRC ;TELL SENDER 'CRC' IS IN EFFECT ; RCVSER1: CALL SEND ;SEND THE 'NAK' OR 'CRC' REQUEST LDA ERRCT ;INCREMENT THE ERROR COUNT INR A STA ERRCT CPI 10+1 ;IF 10 ALREADY, ABORT JC RCVRPT ;IF LESS THAN 10, KEEP GOING JMP ABORT ;..... ; ; RCVQERR: LDA QFLG ;SEE IF QUIET MODE NOW ORA A RNZ ;IF NOT, PROCEED NORMALLY POP H ;RESET STACK FOR 'CALL' JMP RCVSERR ;..... ; ; RCVSABT: LXI SP,STACK ;RESET THE STACK JUST IN CASE CALL CLOSFIL ;CLOSE THE PARTIAL FILE CALL NOASK ;DELETE PARTIAL FILE CALL ILPRT DB CR,LF,LF DB '++ RECEIVED FILE CANCELLED ++',CR,LF,BELL DB '++ UNFINISHED FILE DELETED ++',CR,LF,0 JMP DONETCA ;..... ; ; ; TIMEOUT ROUTINE EACH 10 SECONDS OF NO 'SOH' (START-OF-HEADER) ; RCVSTOT: MVI A,TRUE STA ONERR LDA QFLG ORA A JZ RCVSTOT1 CALL ILPRT DB CR,LF,'++ Timeout ',0 CALL SHOWERR ;DISPLAY THE CURRENT ERROR COUNT ; ; ; ROUTINE WILL SWITCH FROM CRC TO CHECKSUM IF ERCNT REACHES ERRCRC AND ; CURRENTLY IN CRC MODE. ; RCVSTOT1: LDA ERRCT ;GET THE ERROR COUNT CPI ERRCRC ;SEE IF LESS THAN CRC-ERROR TRY LIMIT JC RCVSTOT2 ;IF YES, KEEP TRYING LDA FIRSTME ;OTHERWISE SEE IF WE ALREADY GOT A SOH ORA A JZ RCVSTOT2 ;IF YES, DON'T SWITCH TO CHECKSUM LDA CRCFLAG ;IF NOT, SEE IF ALREADY IN CHECKSUM ORA A JNZ RCVSTOT2 MVI A,TRUE ;SHOW IN CHECKSUM NOW STA CRCFLAG ;CHANGE FROM CRC TO CHECKSUM STA CKSUMDFLT ;OPTION FLAG NOW SHOWS CHECKSUM... CALL ILPRT ;...FOR FUTURE FILES DB '++ Switching to CHECKSUM mode ++',CR,LF,BELL,0 ; RCVSTOT2: JMP RCVSERR ;INCREMENT ERROR COUNT ;..... ; ; ; GET THE ERROR COUNT AND DISPLAY ON CRT ; SHOWERR: PUSH H ;SAVE THE CURRENT ADDRESS LHLD ERRCT ;GET THE CURRENT ERROR NUMBER MVI H,0 ;ONLY A 8-BIT NUMBER, NOW IN 'L' REG. CALL DECOUT ;DISPLAY THE ERROR IN DECIMAL POP H ;RESTORE THE CURRENT ADDRESS CALL ILPRT DB ' ++',CR,LF,0 ;FINISH THE ERROR MESSAGE 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 CHARACTER RECEIVED LDA ERRCDE ;CHECK FOR ANY RECEIVE ERROR ORA A JNZ RCVDERR ;IF AN ERROR GO SHOW WHICH ERROR IT IS POP PSW ;IF NO ERROR, GET RECEIVED CHAR. BACK RET ;... ; ; ;----> RCVDERR: Checks for a receive error and displays an appropriate ; error message. Then goes to RCVSERR to purge the line ; and send a NAK. ; RCVDERR: STA ONERR POP PSW ;CLEAR STACK OF "PUSH PSW" IN 'RCVERR' POP PSW ;CLEAR STACK OF "CALL RCVERR" CALL RCVQERR ;SEE IF QUIET MODE LDA ERRCDE ;GET RECEIVE ERR CODE ANI FRMER ;WAS THERE A FRAMING ERROR? JZ RCVDERR1 ;NO, GO CHECK FOR OVERRUN CALL ILPRT DB CR,LF,'++ Framing error ',0 JMP RCVPRN ;PRINT # OF ERROR ; RCVDERR1: LDA ERRCDE ;GET RECEIVE ERR CODE ANI ORUNER ;WAS THERE AN OVERRUN JZ RCVDERR2 ;NO, GO CHECK FOR PARITY ERROR CALL ILPRT DB CR,LF,'++ Overrun error ',0 JMP RCVPRN ;PRINT # OF ERROR ; RCVDERR2: LDA ERRCDE ;GET RECEIVE ERR CODE ANI PARER ;WAS THERE A PARITY ERROR? JZ RCVRPT ;NO, GO PURGE LINE CALL ILPRT DB CR,LF,'++ Parity error ',0 JMP RCVPRN ;PRINT # OF ERROR ;..... ; ; ; GOT SOH - GET BLOCK #, BLOCK # COMPLEMENTED ; RCVSOH: XRA A ;ZERO ACCUM STA FIRSTME ;INDICATE FIRST SOH RECV'D MVI B,1 ;1-SECOND DELAY CALL RECV ;GET RECORD JC RCVSTOT ;GOT TIMEOUT CALL RCVERR ;CHECK FOR RECEIVE ERROR MOV D,A MVI B,1 CALL RECV JC RCVSTOT CALL RCVERR ;CHECK FOR RECEIVE ERROR CMA CMP D JZ RCVDATA CALL RCVQERR CALL ILPRT DB CR,LF,'++ Bad sector # in header',0 JMP RCVPRN ;..... ; ; RCVDATA: MOV A,D STA RCVRNO 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 MOV M,A INR L JNZ RCVCHR XRA A STA DATAFLG LDA CRCFLAG ;IN 'CRC' MODE? ORA A JZ RCVCRC ;IF YES, EXIT MOV D,C MVI B,1 CALL RECV JC RCVSTOT CALL RCVERR ;CHECK FOR RECEIVE ERROR CMP D JNZ RCVCERR ; CHKSNUM: LDA RCVRNO MOV B,A LDA RECDNO CMP B JZ RECVACK INR A CMP B JNZ ABORT RET ;..... ; ; RCVCRC: MVI E,2 ;NUMBER OF CRC BYTES ; RCVCRC1: MVI B,1 CALL RECV JC RCVSTOT CALL RCVERR ;SEE IF ANY RECEIVE ERRORS DCR E JNZ RCVCRC1 CALL CHKCRC ;CHECK 'CRC' BYTES OF RECEIVED MESSAGE ORA A JZ CHKSNUM ;IF OK, EXIT CALL RCVQERR ;SEE IF QUIET MODE CALL ILPRT ;IF NOT, SHOW ERROR MESSAGE DB CR,LF,'++ CRC error ',0 JMP RCVPRN ;SHOW ERROR NUMBER ;..... ; ; RCVCERR: CALL RCVQERR ;SEE IF QUIET MODE CALL ILPRT ;IF NOT, SHOW ERROR MESSAGE DB CR,LF,'++ CHECKSUM error ++ ',0 JMP RCVPRN ;SHOW ERROR NUMBER ;..... ; ; RECVACK: CALL SENDACK JMP RCVRECD ;..... ; ; SENDACK: MVI A,ACK CALL SEND RET ;..... ; ; SENDHDR: LDA QFLG ORA A JZ SENDHNM CALL ILPRT DB CR,'Sending # ',0 PUSH H ;STORE CURRENT ADDRESS LHLD RECDNO ;GET RECORD 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 ;RESTORE CURRENT ADDRESS ; SENDHNM: MVI A,SOH ;SEND 'SOH' CHARACTER TO THE OUTPUT CALL SEND LDA RECDNO ;SEND RECORD NUMBER TO THE OUTPUT CALL SEND LDA RECDNO CMA ;COMPLEMENT THE RECORD NUMBER JMP SEND ;SEND THIS VALUE TO THE OUTPUT ;..... ; ; SENDREC: 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 MAXIMUM WAIT TIME CALL RECVDG JC GETATOT CPI ACK RZ ;ALL DONE IF 'ACK' CHARACTER RECEIVED MOV B,A ;OTHERWISE SHOW WHAT THE CHARACTER WAS LDA QFLG ORA A JZ ACKERR MOV A,B CALL CRLF CPI NAK ;IS IT A NAK? JZ GETACK1 ;SHOW 'NAK' IN THAT CASE CALL HEXO CALL ILPRT DB 'H',0 JMP GETACK2 ; GETACK1: CALL ILPRT DB 'NAK',0 ; GETACK2: CALL ILPRT ;PRINT THE ERROR MESSAGE DB ' received not ACK - ',0 CALL SHOWERR ;SHOW THE ERROR NUMBER ; ACKERR: LDA ERRCT ;INCREMENT THE ERROR COUNT INR A STA ERRCT CPI 10+1 ;SEE IF AT THE LIMIT OF 10 ERRORS YET RC ;IF NOT, RETURN CALL ERXIT DB CR,LF,'++ SEND-FILE CANCELLED ++','$' ;..... ; ; ; TIME-OUT MESSAGE ON ACK ; GETATOT: CALL ILPRT DB CR,LF,'TIMEOUT on ACK',CR,LF,0 JMP ACKERR ;..... ; ; CKABORT: LDA QFLG ORA A RZ CALL STAT RZ CALL KEYIN CPI CAN RNZ ; ; ; ABORTS SEND OR RECEIVE ROUTINES AND RETURNS TO COMMAND LINE ; ABORT: LXI SP,STACK ; ABORTL: MVI B,1 ;1-SECOND DELAY TO CLEAR INPUT CALL RECV JNC ABORTL MVI A,CAN ;SHOW YOU ARE CANCELLING CALL SEND ; ABORTW: MVI B,1 ;1-SECOND DELAY TO CLEAR INPUT CALL RECV JNC ABORTW MVI A,' ' CALL SEND MVI A,'B' ;TURN MULTI-FILE MODE.. STA BATCHFLG ;..OFF SO ROUTINE ENDS. MVI A,TRUE STA ABORTFLG ;SHOWS AN ABORT WAS MADE STA NFILFLG ;STOP COPY INTO CRT LDA OPTION ;RECEIVING A FILE NOW? CPI 'R' JZ RCVSABT ;IF YES, CANCEL THE UNFINISHED FILE CALL ILPRT DB CR,LF,LF,'++ FILE CANCELLED ++',CR,LF,BELL,0 JMP DONETCA ;..... ; ; INCRRNO: PUSH H LHLD RECDNO ;GET RECORD NUMBER INX H ;BUMP IT SHLD RECDNO ;STORE IT MOV A,L POP H RET ;..... ; ; ; First check for any wild cards and disallow, just to be safe. Do not ; want a group of files being accidently erased. ; ERASFIL: LXI H,FCB ;FILE NAME IS STORED HERE MVI B,11 ;MAXIMUM OF 11 CHARS FOR FILENAME.EXT ; ERASFIL1: INX H ;NEXT LOCATION IN FILE NAME MOV A,M ;GET THE CHAR. CPI '?' ;CHECK FOR ANY WILD CARD CHARS. JZ ERRORW ;ERROR IF ONE IS FOUND DCR B ;NUMBER OF TRIES LEFT JNZ ERASFIL1 ;IF NOT ZERO, KEEP CHECKING 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 ;FILE ERASED OK, RETURN CALL ILPRT ;OTHERWISE MAKE SURE IT'S OK DB 'File exists - erase? (Y/N): ',BELL,0 CALL KBDCHR CPI 'Y' JNZ MENU ;IF NOT A 'Y' DO NOT ERASE CALL CRLF ;OTHERWISE ERASE THE FILE ; NOASK: LXI D,FCB MVI C,ERASE JMP BDOS ;..... ; ; ERRORW: POP H ;RESTORE STACK FROM "CALL ERASFIL" CALL ILPRT DB '++ NO WILDCARDS ALLOWED FOR TEXT FILES ++' DB CR,LF,BELL,0 JMP MENU ;..... ; ; BLKFILE: CALL ILPRT ;ROUTINE IF NO FILE IS NAMED FOR ; ;"SEND" OR "RECEIVE" DB '++ 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 open file ++',CR,LF DB '++ Directory is likely full ++','$' ; 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 ; ;..... ; ; OPENFIL: XRA A STA FCBEXT LXI D,FCB MVI C,OPEN CALL BDOS INR A JNZ SENDTIME ;SEND TRANSFER TIME, # OF RECORDS, ETC. CALL ERXIT ;FILE DID NOT OPEN DB '++ FILE NOT FOUND ++','$' ; ;..... ; ; CLOSFIL: LXI D,FCB MVI C,CLOSE CALL BDOS INR A RNZ CALL ERXIT DB CR,LF,'++ UNABLE TO CLOSE FILE ++','$' ;..... ; ; ; UPDATE RECORD READ ; RDRECD: LDA RECINBF DCR A STA RECINBF JM RDBLOCK LHLD RECPTR LXI D,80H CALL MOVE128 SHLD RECPTR RET ;..... ; ; ; BUFFER EMPTY SO READ IN ANOTHER BLOCK (UP TO 16K OR 128 RECORDS) ; RDBLOCK: LDA EOFLG CPI 1 STC RZ MVI C,0 LXI D,DBUF ; RDRECLP: PUSH B PUSH D MVI C,SETDMA CALL BDOS LXI D,FCB MVI C,READ CALL BDOS POP D POP B ORA A JZ RDRECOK DCR A JZ REOF CALL ERXIT DB '++ FILE READ ERROR ++','$' ; RDRECOK: LXI H,80H DAD D XCHG INR C MOV A,C CPI DBUFSIZ*8 ;BUFFER SIZE IN 128 BYTE RECORDS JZ RDBFULL JMP RDRECLP ;... ; ; REOF: MVI A,1 STA EOFLG MOV A,C ; ; ; BUFFER FULL OR RECEIVED EOF ; RDBFULL: STA RECINBF LXI H,DBUF SHLD RECPTR LXI D,80H MVI C,SETDMA CALL BDOS JMP RDRECD ;..... ; ; ; WRITE A RECORD ; WRRECD: LHLD RECPTR XCHG LXI H,80H CALL MOVE128 XCHG SHLD RECPTR LDA RECINBF INR A STA RECINBF CPI DBUFSIZ*8 ;BUFFER SIZE IN 128 BYTE RECORDS RNZ ; ; ; WRITE A 16K BLOCK TO DISK (128 RECORDS) ; WRBLOCK: LDA RECINBF ORA A RZ MOV C,A LXI D,DBUF ; DKWRLP: PUSH H PUSH D PUSH B MVI C,SETDMA 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 RECINBF LXI H,DBUF SHLD RECPTR RET ;..... ; ; ; ERROR WHILE WRITING A RECORD, SHOW WHY IT IS ABORTING ; WRERR: MVI C,CAN CALL SEND CALL ERXIT DB CR,LF,'++ FILE WRITE ERROR ++','$' ;..... ; ; ;----> 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: CALL IN$MODDATP CALL IN$MODDATP ; RECV: PUSH D ;SAVE ANY CURRENT VALUES MOV A,B ;MULTIPLY 'B' BY 4 FOR EXTRA DELAY RAL RAL MOV B,A ; MSEC: CALL CKABORT ;WANT TO INTENTIONALLY ABORT? PUSH H LXI H,175 ;MASTER DELAY FACTOR CALL FIXCNT PUSH H ;SAVE THE DELAY VALUE NOW IN 'HL' POP D ;GET IT BACK, BUT IN 'DE' POP H ;RESTORE THE STACK TO NORMAL ; MWTI: CALL RCVREADY ;INPUT HAVE A CHARACTER READY? JZ MCHAR ;IF YES, EXIT DCR E JNZ MWTI DCR D JNZ MWTI DCR B ;NUMBER OF SECONDS WANTED JNZ MSEC ;IF NOT ZERO, DO 1-SECOND LOOP AGAIN POP D ;RESTORE ORIGINAL VALUES STC ;NO CHARACTER SO SET CARRY BIT RET ;..... ; ; MCHAR: LDA PMMIBYTE ;USING A PMMI MODEM? ORA A JZ MCHAR1 ;IF NOT, SKIP THE FOLLOWING LINES 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 ;RESTORE ORIGINAL VALUES 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 A CHARACTER TO THE MODEM ; SEND: PUSH PSW LDA NSEEFLG ORA A JZ MONOUT 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 LDA NSEEFLG ;NOT SENDING TO MODEM? ORA A JZ SENDW1 ;IF YES, EXIT ; SENDW: CALL SENDRDY JNZ SENDW POP PSW JMP OUT$MODDATP ; SENDW1: POP PSW ;RESTORE STACK RET ;..... ; ; ; WAITS FOR THE FIRST CHARACTER RECEIVED WHILE WAITING TO SEND A FILE. ; IF A CHARACTER IS NOT RECEIVED IN ONE SECOND, IT LOOPS AGAIN UNTIL A ; CHAR IS RECEIVED OR IT TIMES OUT. THE COUNT IS SET FOR 100 SECONDS ; BEFORE TIMEOUT. THIS GIVES ENOUGH THE RECEIVING STATION AMPLE TIME ; TO NAME A FILE, ETC. ; WAITNAK: CALL ILPRT DB 'Awaiting CRC request',CR,LF,0 ; WAITNLP: CALL CKABORT MVI B,1 CALL RECV CPI CAN ;WANT TO QUIT? JZ ABORT CPI CRC ;CRC REQUEST? JZ WAITCRC ;YES, GO SET CRC FLAG CPI NAK RZ DCR E JNZ WAITNLP JMP ABORT ;... ; ; WAITCRC: CALL ILPRTQ DB 'CRC request received',CR,LF,0 XRA A STA CRCFLAG ;MAKE SURE IN 'CRC' MODE THEN RET ;..... ; ; ;--->PARITY: Routine to setup PMMI for odd/even parity. ; PARITY: LDA PMMIBYTE ;IS MODEM A PMMI? ORA A ;SET FLAGS RZ ;NO, RETURN ;MOD(BGL)*** LDA PARTY ;CURRENTLY 8/NONE? CPI ORIGMOD ;IF NOT, IGNORE RNZ 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 ;..... ; ;MOD(BGL)*** TOGLPAR: LXI H,PARTOG MOV A,M DCX H SUB M MOV M,A STA UARTCTLB CALL OUT$MODCTLP JMP XPRT ;..... ; ; INITADR: LHLD 1 ;BIOS WARM REBOOT JUMP VECTOR LXI D,3 DAD D SHLD VSTAT+1 ;BIOS CONSOLE STATUS JUMP VECTOR DAD D SHLD VKEYIN+1 ;BIOS CONSOLE KEYBOARD JUMP VECTOR DAD D SHLD VTYPE+1 ;BIOS CONSOLE CRT JUMP VECTOR DAD D SHLD VLIST+1 ;BIOS LIST DEVICE JUMP VECTOR LXI D,30 DAD D SHLD VLSTAT+1 ;BIOS LIST DEVICE STATUS JUMP VECTOR LDA PMMIBYTE ORA A RZ ;SKIP THE REST IF NOT PMMI LDA IN$MODCTLP+1 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 NTVLDMSG POP PSW ;PRESERVE STACK JMP MENU ; ENDOPT: LDA VSEEFLG ORA A RNZ STA QFLG ;QUITE MODE FOR DATA ITEMS RET ;..... ; ; DONE: LDA BATCHFLG ;IN BATCH MODE? ORA A JNZ DONETC ;EXIT IF NOT 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,BELL,0 ; 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 RECORD NUMBERS.. LXI D,RECDNOB ;..FOR NEW FILE TRANSFER. MVI B,RECDNOE-RECDNOB ;ROUTINE ALSO DONE IN MENU. CALL MOVE CALL IN$MODDATP CALL IN$MODDATP 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 CKABORT ;SLIGHT DELAY FOR NEXT MESSAGE CALL ILPRT DB CR,LF,'[Transfer Completed]',CR,LF,BELL,0 ; DONETCA: LDA XITFLG ;SPECIAL 'X' FLAG SET? ORA A JZ BYEBYE ;IF YES, DISCONNECT AND REBOOT LDA DISCFLG ;NORMAL 'D' FLAG SET? ORA A JZ DONETCC ;IF YES, DISCONNECT, GET NEXT COMMAND ; DONETCB: CALL NOPARIT ;RESET TO NO PARITY MVI A,CRC STA CRCFLAG ;TURNS OFF CRC OPTION 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 LXI H,QFLG ;IN QUIET MODE? MOV A,M ORA A MVI M,'Q' ;RESET THE FLAG TO NORMAL JZ MENU ;IF YES, GO BACK TO COMMAND LINE LDA ABORTFLG ;COME HERE FROM A TIMEOUT? ORA A JNZ MENU ;IF YES, GO TO COMMANDE MODE LDA TERMFLG ;SEE IF RETURN TO.. ORA A ;..TERMINAL MODE.. JNZ MENU ;..AFTER X'FER. CALL CRLF JMP TERM ;..... ; ; DONETCC: CALL ILPRT DB CR,LF,'<< DISCONNECTED >>',CR,LF,0 CALL JMP$DISCONNT ;HANG-UP THE PMMI JMP MENU ;BACK TO COMMAND LINE ;..... ; ; 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 ;..... ; ; STAT: PUSH B PUSH D PUSH H ; VSTAT: CALL $-$ ;BIOS CONSTAT ADDRESS, FILLED IN.. POP H ;..BY INITADR ROUTINE POP D POP B ORA A RET ;..... ; ; KEYIN: PUSH B PUSH D PUSH H ; VKEYIN: CALL $-$ ;BIOS CONIN ADDRESS, FILLED IN.. POP H ;..BY INITADR ROUTINE POP D POP B RET ;..... ; ; LISTER: PUSH B PUSH D PUSH H ; VLIST: CALL $-$ ;BIOS LIST OUT ADDRESS, FILLED IN.. POP H ;..BY INITADR ROUTINE POP D POP B RET ;..... ; ; LSTSTAT: PUSH B PUSH D PUSH H ; VLSTAT: CALL $-$ ;BIOS LIST DEVICE STATUS ADDRESS,.. POP H ;..FILLED IN BY INITADR ROUTINE POP D POP B RET ;..... ; ; TYPE: PUSH PSW PUSH B PUSH D PUSH H MOV C,A ; VTYPE: CALL $-$ ;BIOS CONOUT ADDRESS, FILLED IN.. POP H ;..BY INITADR ROUTINE POP D POP B POP PSW RET ;..... ; ; GET A CHARACTER FROM THE KEYBOARD, CONVERT TO UPPER CASE IF NEEDED, ; AND SHOW ON CRT ; KBDCHR: CALL KEYIN ;GET A KEYBOARD CHARACTER CALL UCASE ;CONVERT TO UPPER CASE IF NEEDED CALL TYPE ;SHOW ON CRT RET ;..... ; ; UCASE: CPI 61H ;CHANGES LOWER CASE CHARACTER.. RC ;..IN A-REG TO UPPER CASE. CPI 7AH+1 ;SEE IF MORE THAN SMALL 'Z' 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 ;..... ; ; ; PRINTS A HEX VALUE IN 'A' ON THE CRT ; HEXO: PUSH PSW RAR RAR RAR RAR CALL NIBBL POP PSW ; NIBBL: ANI 0FH CPI 10 JC ISNUM ADI 7 ; ISNUM: ADI '0' ;ADD IN ASCII BIAS JMP CTYPE ;..... ; ; ; DISPLAYS THE CONTROL-CHARACTERS SHOWN IN THE MENU ; SHFTYPE: PUSH PSW CALL ILPRT DB 'CTL-',0 POP PSW ADI 40H ;CONVERT BINARY TO ASCII CHARS. CALL TYPE ;SHOW ON THE CRT JMP ILPRT ;..... ; ; ; WRITE A STRING OF CHARACTERS ; ILPRT: XTHL ; ILPRT1: MOV A,M ;GET THE CHARACTER ORA A ;SEE IF A "0" FOR END OF STRING JZ ILPRT2 ;IF YES, ALL DONE CALL CTYPE ;SHOW ON CRT INX H ;GET THE NEXT LOCATION IN THE STRING JMP ILPRT1 ; ILPRT2: XTHL ;RESTORE THE ADDRESS RET ;..... ; ; ; WRITE A STRING OF CHARACTERS UNLESS IN QUIET MODE ; ILPRTQ: XTHL ; ILPRTQ1: MOV A,M ;GET THE CHARACTER ORA A ;SEE IF A "0" FOR END OF STRING JZ ILPRTQ2 ;IF YES, ALL DONE LDA QFLG ORA A MOV A,M CNZ CTYPE ;SHOW ON CRT IF NOT IN QUITE MODE INX H ;GET THE NEXT LOCATION IN THE STRING JMP ILPRTQ1 ; ILPRTQ2: XTHL ;RESTORE THE ADDRESS RET ;..... ; ; PRTMSG: MVI C,PRINT ;PRINT THE STRING JMP BDOS ;..... ; ; ; DISPLAYS ERROR STATEMENT THEN RETURNS TO COMMAND MODE ; ERXIT: POP D CALL PRTMSG MVI A,BELL CALL TYPE CALL CRLF MVI A,TRUE STA ABORTFLG ;SHOWS AN UNINTENTIONAL ABORT LDA BATCHFLG ;IN BATCH MODE? ORA A JNZ DONETCB ;IF NOT, EXIT JMP ABORT ;ABORT OTHER COMPUTER ;..... ; ; ; EXITS DIRECTLY TO CP/M, WITH NO REBOOT UNLESS YOU ALLOW POSSIBLE ; OVERWRITING OF CCP. ; EXIT: LDA OLDUSER ;GET ORIGINAL USER NUMBER BACK MOV E,A CALL SETUSER LXI D,80H ;RESTORE ORIGINAL BUFFER AREA MVI C,SETDMA CALL BDOS LDA SAVCCP ;WAS CCP LEFT INTACT? ORA A JZ 0000H ;IF NOT, WARM REBOOT JUST IN CASE ; EXIT1: JMP $-$ ;OVERWRITTEN WITH CCP RETURN BY "START" ;..... ; ; 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 CMDLINE CALL PROCOPT 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,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 '++ Enter primary option plus file name ++' DB CR,LF,BELL,0 POP H ;RESET STACK FROM 'CALL SETFCB' JMP MENU ;ABORT TO COMMAND LINE ;..... ; ; 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 ;..... ; ; ; CHANGE BAUDRATE ON-THE-FLY WITH CTL-B (WHILE IN TERMINAL MODE) ; NEWBAUD: LDA PMMIBYTE ORA A RZ CALL ILPRT DB CR,LF,'Enter new Baudrate: ',0 LXI H,FCB+9 MVI M,0 ;DEFAULTS TO 300 BAUD IF NO ANSWER TYPED ; NEWBAUD1: CALL KEYIN ;GET THE BAUD RATE CPI CR ;CARRIAGE RET FINISHES BAUD RATE ENTRY JNZ CONNEWB ;GOES TO THE ESTABLISHED ROUTINE CALL CRLF ;PROGRAM IS DONE THERE. JMP FIXBAUD ;GO CHANGE THE BAUD RATE ;..... ; ; CONNEWB: CPI '0' ;NUMERALS ARE 0-9 JC NEWBAUD1 CPI '9'+1 JNC NEWBAUD1 ;IF NOT A NUMERAL, IGNORE, ASK AGAIN MOV M,A ;STORE ANSWER STARTING AT FCB+9 CALL TYPE ;SHOW THE NUMERAL ON THE CRT INX H ;NEXT STORAGE LOCATION IN FCB JMP NEWBAUD1 ;GET THE NEXT NUMERAL ;..... ; ; ; ADJUSTS LOOP COUNTERS FOR THE SELECTED CLOCK SPEED ; FIXCNT: LDA CLOCK ;GET THE USER'S CLOCK SPEED PUSH D PUSH H POP D ; CNTMUL: DAD D DCR A JNZ CNTMUL POP D ;RETURN WITH ANSWER IN 'HL' RET ;..... ; ; ;======================================================================= ; ; LOADS A COMMAND LINE ADDRESSED BY DE REGISTERS (MAX # CHARACTERS IN ; LINE IN DE, NUMBER OF CHARS IN LINE IN DE+1, LINE STARTS IN DE+2) INTO ; FCB ADDRESSED BY HL REGISTERS. THE FCB SHOULD BE AT LEAST 33 BYTES IN ; LENGTH. THE COMMAND LINE BUFFER MUST HAVE A MAXIMUM LENGTH AT LEAST ; ONE MORE THAN THE GREATEST NUMBER OF CHARACTERS THAT WILL BE NEEDED. CMDLINE: PUSH PSW PUSH B PUSH D PUSH H CALL INITIAL ;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,CR ;..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 DRIVE ; NAME1: MVI C,8 ;TRANSFER FIRST FILENAME TO FCB. CALL TRANS CPI CR JZ DONEL CPI ' ' ;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 CR JZ DONEL ; NAME2: LDAX D ;EAT MULTIPLE SPACES.. CPI ' ' ;..BETWEEN NAMES. JNZ NAME2C INX D JMP NAME2 ; NAME2C: POP H ;SECOND NAME STARTS IN 16TH BYTE. PUSH H ;POINT HL TO THIS BYTE. LXI B,16 DAD B CALL DRIVE MVI C,8 CALL TRANS CPI CR JZ DONEL ; TYPE2: POP H ;SECOND TYPE STARTS IN 25TH BYTE. PUSH H LXI B,25 DAD B MVI C,3 CALL TRANS ; DONEL: POP H PUSH H INX H ;POINT TO 1ST CHAR OF 1ST NAME IN FCB.. CALL SCANL ;CHECK FOR * (AMBIGUOUS NAMES). POP H PUSH H LXI B,17 ;..TO 1ST CHAR OF SECOND NAME IN FCB. DAD B CALL SCANL POP H POP D POP B POP PSW RET ;..... ; ; ; SUBROUTINES FOR CMDLINE SECTION ; INITIAL: PUSH H ;INITIALIZES FCB WITH 1 NULL (FOR FIRST DRIVE).. PUSH B ;..11 BLANKS, 4 NULLS, 1 NULL (FOR 2ND DRIVE).. MVI M,0 ;..11 BLANKS, AND 4 NULLS. INX H MVI B,11 MVI A,' ' CALL INITFILL MVI B,5 XRA A CALL INITFILL MVI B,11 MVI A,' ' CALL INITFILL MVI B,4 XRA A CALL INITFILL POP B POP H RET ;..... ; ; INITFILL: MOV M,A INX H DCR B JNZ INITFILL RET ;..... ; ; DRIVE: INX D ;CHECK 2ND BYTE OF FILENAME. IF IT.. LDAX D ;..IS A ":", THEN DRIVE WAS SPECIFIED.. DCX D CPI ':' JNZ DEFDR ;..ELSE ZERO FOR DEFAULT DRIVE .. LDAX D ;..('INIT' PUT ZERO) ANI 5FH SUI 40H ;CALCULATE DRIVE (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 CR ;..BY C-REG. KEEP SCANNING FIELD.. RZ ;..WITHOUT TRANSFER UNTIL A DELIMITING.. ; CPI '.' ;..FIELD CHAR SUCH AS '.', BLANK, OR.. RZ ;..C/R (FOR END OF CMD LINE). CPI ' ' RZ DCR C JM TRANS ;ONCE C-REG IS LESS THAN ZERO, KEEP.. MOV M,A ;..READING CMD LINE BUT DO NOT.. INX H ;..TRANSFER TO FCB. JMP TRANS ;... ; ; SCANL: 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.. ; TSTTYPL: MOV A,M ;..SPECIFIED ABOVE. CPI '*' JZ FILL2 ; INX H DCR B JNZ TSTTYPL RET ;..... ; ; FILL2: CALL FILL RET ;..... ; ; FILL: MVI M,'?' ;ROUTINE TRANSFERS '?'. INX H DCR B JNZ FILL RET ;======================================================================= ; ; LISTS DIRECTORY AND GIVES FREE SPACE REMAINING ON THE REQUESTED DRIVE. ; ; ; Disk system reset - currently bypassed, if you wish this feature, put ; JMP DIRLIST2 instead of JMP DIRLIST3 in the eighth line. The ; current disk (plus the A: drive) will then reset each DIR re- ; quest. You can also reset the disk with the LOG command when ; when inserting a different one. This saves a reset each time ; DIR might be requested. ; DIRLIST: MVI C,CURDSK ;CURRENT DEFAULT DISK, 25. CALL BDOS PUSH PSW ;SAVE DEFAULT DISK LETTER ADI 41H ;MAKE IT ASCII AND.. STA DRNAME ;..STORE HERE AND.. STA DEFDRV ;..HERE. ; DIRLIST1: JMP DIRLIST3 ; DIRLIST2: MVI C,RESET ;13 RESET DISK SYSTEM (RESETDK) CALL BDOS ; DIRLIST3: POP PSW ;GET DEFAULT LETTER BACK AND.. MOV E,A ;..PUT FOR SELECT. MVI C,SELDSK ;SELECT DISK AGAIN AS DEFAULT (SELDK) CALL BDOS ; ; ; Directory list routine ; LXI D,CMDBUF ;PUT COMMAND LINE IN FCB.. LXI H,FCB ;..ADDRESSED BY HL-REG.. CALL CMDLINE ;..AND THEN... LXI H,FCB4 CALL INITFCB LDA FCB2 ;GET DRIVE NUMBER STA FCB4 LDA FCB2+1 CPI ' ' ;IF A SPACE (BLANK) GET ALL NAMES PUSH PSW CZ QSTMARK POP PSW CNZ MOVNAME ;ELSE MOVE NAME INTO FCB CALL DRIVEL LXI D,80H MVI C,SETDMA CALL BDOS LDA NOOFCOL ;NUMBER OF COLUMNS INTO REG-A STA NAMECT ;CRLF AFTER "NOOFCOL" NUMBER OF COLUMNS LXI D,FCB4 MVI C,SRCHF ;DO FIRST SEARCH CALL BDOS INR A ;FFH --> 0 IF NO FILE(S) FOUND JNZ DIRLOOP CALL ILPRT DB '++ FILE NOT FOUND ++',0 JMP STORAGE ;STILL SHOW STORAGE ON DEFAULT DRIVE ; DIRLOOP: CALL GETADD INX H ;POINT TO FIRST LETTER OF FILENAME LXI D,PRTNAME LXI B,8 CALL MOVER INX D LXI B,3 CALL MOVER CALL ILPRT ; PRTNAME: DB ' ','.',' ',0 ; 8 SPACES, PERIOD, 3 SPACES ; NEXTSR: LXI D,FCB4 MVI C,SRCHN ;DO NEXT SEARCH CALL BDOS INR A ;IF 0FFH --> 0 THEN.. JZ STORAGE ;..DIRECTORY-READ FINISHED. PUSH PSW PUSH D PUSH H LDA NAMECT DCR A STA NAMECT ;NAME COUNT UPDATED ORA A CZ CRLF ;TERMINATE LINE OF FILE NAMES JNZ FENCE LDA NOOFCOL ;RESTART COLUMNS-PER-LINE COUNT STA NAMECT JMP NOFENCE ;FENCE NOT NEEDED ; FENCE: CALL ILPRT DB ' : ',0 ;FENCE IF NOT AT END OF LINE OR.. ; ;..LAST FILENAME NOFENCE: POP H POP D POP PSW JMP DIRLOOP ;..... ; ; ; DETERMINE STORAGE REMAINING ON DEFAULT DRIVE ; STORAGE: CALL CRLF MVI C,DSKPAR ;CURRENT DISK PARAMETER BLOCK CALL BDOS INX H INX H MOV A,M ;GET BLOCK SHIFT FACTOR STA BSHIFTF INX H ;BUMP TO BLOCK MASK MOV A,M ;GET IT STA BMASK INX H INX H MOV E,M ;GET MAX BLOCK NUMBER INX H MOV D,M XCHG SHLD BMAX ;PUT IT AWAY MVI C,DSKALL ;ADDRESS OF CP/M ALLOCATION VECTOR CALL BDOS XCHG ;GET ITS LENGTH LHLD BMAX INX H LXI B,0 ;INITIALIZE BLOCK COUNT TO ZERO ; GSPBYT: PUSH D ;SAVE ALLOCATION ADDRESS LDAX D MVI E,8 ;SET TO PROCESS 8 BLOCKS ; GSPLUP: RAL ;TEST BIT JC NOTFRE INX B ; NOTFRE: MOV D,A ;SAVE BITS DCX H MOV A,L ORA H JZ ENDALC ;QUIT IF OUT OF BLOCKS MOV A,D ;RESTORE BITS DCR E ;COUNT DOWN 8 BITS JNZ GSPLUP ;DO ANOTHER BIT POP D ;BUMP TO NEXT COUNT.. INX D ;..OF ALLOCATION VECTOR. JMP GSPBYT ;PROCESS IT ; ENDALC: POP D ;CLEAR ALLOC VECTOR POINTER FROM STACK MOV L,C ;COPY BLOCK TO HL MOV H,B LDA BSHIFTF ;GET BLOCK SHIFT FACTOR SUI 3 ;CONVERT FROM RECORDS TO THOUSANDS (K) JZ PRTFREE ;SKIP SHIFTS IF 1K BLOCKS ; FREKLP: DAD H ;MULTIPLY BLOCKS BY K PER BLOCK DCR A JNZ FREKLP ; PRTFREE: CALL DECOUT ;(# OF FREE K BYTES IN HL) LXI D,FREEMSG CALL PRTMSG CALL GETUSER ;GET USER NUMBER MVI H,0 MOV L,A CALL DECOUT ;PRINT USER NUMBER LXI D,DEFUSR JMP PRTMSG ;..... ; ; ; SUBROUTINES FOR DIRLIST SECTION ; QSTMARK: MVI A,'?' ;IF BLANK IN FCB, PUT IN 11 ?'S. MVI B,11 LXI H,FCB4+1 ; QSTLP: MOV M,A INX H DCR B JNZ QSTLP RET ;..... ; ; MOVNAME: LXI H,FCB2+1 LXI D,FCB4+1 LXI B,11 CALL MOVER RET ;..... ; ; GETADD: DCR A ;UN-DO THE INR ABOVE ADD A ;TIMES 32 ADD A ADD A ADD A ADD A ADI 80H ;ADD DMA (CMDBUF) OFFSET MOV L,A MVI H,0 RET ;..... ; ; DRIVEL: LDA FCB4 ;IF NO DRIVE, USE ORA A ;DEFAULT DRIVE IN DRNAME. JZ PRNTHD ADI 40H ;MAKE 1=A, 2=B, ETC., AND.. STA DRNAME ;..OVERWRITE DEFAULT STORED BELOW. ; PRNTHD: CALL ILPRT DB 'Drive ' ; DRNAME: DB ' ',CR,LF,0 RET ;..... ; ; ; INITIALIZED STORAGE ; FREEMSG: DB 'k Bytes free on default drive ' DEFDRV: DB ' $' DEFUSR: DB ':',CR,LF,'$' ; ; ; UNINITIALIZED STORAGE ; BMAX: DS 2 ;HIGHEST BLOCK NUMBER ON DRIVE BMASK: DS 1 ;REC/BLK - 1 BSHIFTF: DS 1 ;NUMBER OF SHIFTS TO MULTIPLY BY REC/BLK ;..... ; ; ;======================================================================= ; ; DUPLICATES 'READ BUFFER' ROUTINE SAME AS CP/M FUNCTION 10, BUT DOES ; NOT USE CTL-C (REASON FOR THE ROUTINE). DOES ALLOW CONTROLS U, R, E ; AND H (BACKSPACE). OUTPUTS BELL IF THE INPUT IS GREATER THAN THE ; BUFFER. ; INBUF: PUSH PSW PUSH H PUSH B PUSH D ;DE REGISTERS MUST BE PUSHED LAST ; INBUFA: CALL CLEARBUF ;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 ; INBUFB: CALL KEYIN ;(WAITS FOR CHAR) CALL UCASE ;..DITTO. CPI CR ;IS IT (ENTER COMMAND)? JZ INBUFR ;IF SO, THEN RETURN. CPI 7FH ;IS IT A DELETE? JZ DELETE CPI 8 ;CTR-H BACKSPACES.. JZ DELETE ;..OVER DELETED CHAR. CPI 'U'-40H ;IS IT A CTL-U? JZ INBUFO ;OUTPUT #, CR, LF, AND START OVER CPI 'R'-40H ;CTL-R RETYPES LINE JZ RETYPE CPI 'E'-40H ;CTL-E OUTPUTS A CRLF JZ PCRLF CPI ' ' ;NO CONTROL CHARACTERS OTHER.. JC INBUFB ;..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 ALERTL ;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 TYPE INX H ;BUMP POINTER JMP INBUFB ;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 7FH OR 08H MOV B,M ;GET CHARACTER BEING DELETED MVI M,' ' ;RESTORE BLANK CPI 8 JZ BKSPC CPI 7FH JZ BKSPC0 JMP INBUFB ;GET NEXT CHARACTER ;..... ; ; NODEL: INR M ;DON'T LEAVE COUNT NEGATIVE XCHG ;RESTORE POINTER TO HL JMP INBUFB ;..... ; ; BKSPC0: MVI A,08H ; BKSPC: CALL TYPE ;TRUE ERASE IF 08H MVI A,' ' CALL TYPE MVI A,8 CALL TYPE JMP INBUFB ;..... ; ; INBUFO: MVI A,'#' ;ANNOUNCES THE LINE HAS BEEN REMOVED CALL TYPE CALL CRLF JMP INBUFA ;..... ; ; RETYPE: POP D PUSH D INX D ;POINT TO CURRENT NUMBER.. LDAX D ;..OF CHARACTERS. MOV B,A MVI A,'#' CALL TYPE CALL CRLF MOV A,B ;TEST IF ZERO INPUT ORA A JZ INBUFB ;... ; ; CTLRLP: INX D LDAX D CALL TYPE DCR B JNZ CTLRLP JMP INBUFB ;..... ; ; ALERTL: MVI A,BELL ;ALARM FOR FULL BUFFER CALL TYPE DCR M XCHG JMP INBUFB ;..... ; ; PCRLF: CALL CRLF JMP INBUFB ;..... ; ; INBUFR: CALL CRLF ;1ST NEW LINE AFTER A COMMAND CHARACTER POP D POP B POP H POP PSW RET ;..... ; ; CLEARBUF: 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,' ' ; CLEARL: MOV M,A INX H DCR B JNZ CLEARL RET ;..... ; ; ;======================================================================= ; ; IN-LINE COMPARE. COMPARES STRING ADDRESSED BY DE-REG TO STRING AFTER ; CALL (ENDS WITH ZERO). RETURN WITH CARRY SET MEANS STRINGS NOT THE ; SAME. ALL REGISTERS EXCEPT A-REG ARE UNAFFECTED. ; INLNCOMP: XTHL ;POINT HL TO 1ST CHAR. PUSH D ; ILCOMPL: 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 ILCOMPL ;... ; ; NOTSAME: XRA A ;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 ;..... ; ; ;======================================================================= ; ; MULTI-FILE ACCESS SUBROUTINE. ALLOWS PROCESSING OF MULTIPLE FILES ; (I.E., *.ASM) FROM DISK. BUILDS THE CORRECT NAME IN THE FCB EACH TIME ; IT IS CALLED. THE COMMAND IS USED IN PROGRAMS TO PROCESS SINGLE OR ; MULTIPLE FILES. THE FCB IS 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 ARE FOUND. MFNAME: PUSH B PUSH D PUSH H MVI C,SETDMA LXI D,80H CALL BDOS POP H POP D POP B XRA A STA FCBEXT LDA MFFLG1 ORA A JNZ MFNAME1 MVI A,1 STA MFFLG1 LXI H,FCB LXI D,MFNAME5 LXI B,12 CALL MOVER LDA FCB STA MFNAME6 ;SAVE DISK IN CURR FCB LXI H,MFNAME5 LXI D,FCB LXI B,12 CALL MOVER PUSH B PUSH D PUSH H MVI C,SRCHF LXI D,FCB CALL BDOS POP H POP D POP B JMP MFNAME2 ;... ; ; MFNAME1: LXI H,MFNAME6 LXI D,FCB LXI B,12 CALL MOVER PUSH B PUSH D PUSH H MVI C,SRCHF LXI D,FCB CALL BDOS POP H POP D POP B LXI H,MFNAME5 LXI D,FCB LXI B,12 CALL MOVER PUSH B PUSH D PUSH H MVI C,SRCHN LXI D,FCB CALL BDOS POP H POP D POP B ; MFNAME2: INR A STC JNZ MFNAME3 STA MFFLG1 RET ;..... ; ; MFNAME3: 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 LXI D,MFNAME6+1 LXI B,11 CALL MOVER POP H LXI D,FCB+1 LXI B,11 CALL MOVER XRA A STA FCBEXT STA FCBRNO RET ;..... ; ; MOVER: MVI A,2 INR A JPE MFNAME4 DB 0EDH,0B0H ;Z-80 'LDIR' INSTUCTION RET ;..... ; ; MFNAME4: MOV A,M ;USED IF AN 8080 CPU IS ACTIVE STAX D INX H INX D DCX B MOV A,B ORA C JNZ MFNAME4 RET ;..... ; ; ;======================================================================= ; ; SHOWS BAUD RATES SET FOR 'TIME TO SEND' FILE TRANSFER. ; PRTBAUD: LXI H,BAUDSPD MVI D,0 LDA MSPEED ;GET BAUD RATE CODE MOV E,A ;X1 ADD A ;X2 ADD A ;X4 ADD E ;X5 MOV E,A DAD D ;POINT TO CORRECT RATE XCHG MVI C,PRINT CALL BDOS CALL ILPRT DB ' baud',CR,LF,0 RET ;..... ; ; BAUDSPD DB '110$',0,'300$',0,'450$',0,'600$',0,'710$',0 DB '1200$','2400$','4800$','9600$' ;..... ; ; ;======================================================================= ; ; SHOWS THE TIME TO TRANSFER A FILE AT VARIOUS BAUD RATES. (110-9600) ; SENDTIME: CALL ILPRT ;PRINT FOLLOWING MESSAGE: DB 'File open: ',0 LHLD RCNT ;GET RECORD COUNT. CALL DECOUT ;PRINT DECIMAL NUMBER OF RECORDS CALL ILPRT DB ' (',0 CALL DHXOUT ;NOW PRINT SIZE IN HEX. CALL ILPRT DB 'H) records',CR,LF DB 'Send time: ',0 LDA MSPEED ;GET THE SPEED INDICATOR MVI D,0 MOV E,A ;SET UP FOR TABLE ACCESS LXI H,BTABLE ;POINT TO BAUD FACTOR TABLE DAD D ;INDEX TO PROPER FACTOR DAD D ;FACTOR IN DE MOV E,M INX H MOV D,M LHLD RCNT ;GET # OF RECORDS CALL DVHLDE ;DIVIDE 'HL' BY VALUE IN DE (RECORDS/MIN) PUSH H MOV L,C MOV H,B CALL DECOUT ;PRINT THE MINUTES PORTION CALL ILPRT DB ' mins, ',0 LXI H,RECDBL ;POINT TO DIVISORS FOR SECONDS LXI D,0 ; CALCULATION LDA MSPEED ;GET INDEX FOR BAUD RATE MOV E,A DAD D ;INDEX INTO TABLE MOV A,M ;GET MULTIPLIER POP H ;GET REMAINDER CALL MULHLA ;MULTIPLY THE 'HL' X 'A' CALL SHFTHL CALL SHFTHL CALL SHFTHL CALL SHFTHL MVI H,0 CALL DECOUT ;PRINT THE SECONDS PORTION CALL ILPRT DB ' secs at ',0 CALL PRTBAUD CALL ILPRT DB 'To cancel: use CTL-X',CR,LF,0 RET ;..... ; ; BTABLE: DW 5,13,19,25,29,48,96,192,384,0 ;RECORDS/MIN FOR.. RECDBL: DB 192,74,51,38,33,20,11,5,3,0 ;..110-9600 BAUD ; ; ;----> DVHLDE: DIVIDES 'HL' BY VALUE IN 'DE', ; UPON EXIT: 'BC'=QUOTIENT,'L'=REMAINDER ; DVHLDE: PUSH D ; SAVE DIVISOR MOV A,E CMA ; NEGATE DIVISOR MOV E,A MOV A,D CMA MOV D,A INX D ; DE IS NOW TWOS COMPLEMENTED LXI B,0 ; INIT QUOTIENT ; DIVL1: DAD D ; SUBTRACT DIVISOR FROM DIVIDEND INX B ; BUMP QUOTIENT JC DIVL1 ; LOOP TILL SIGN CHANGES DCX B ; ADJUST QUOTIENT POP D ; RETRIEVE DIVISOR DAD D ; ADJUST REMAINDER RET ;..... ; ; ;----> MULHLA: MULTIPLY THE VALUE IN 'HL' BY THE VALUE IN 'A' ; RETURN WITH ANSWER IN 'HL' ; MULHLA: XCHG ; MULTIPLICAND TO DE LXI H,0 ; INIT PRODUCT INR A ; ADJUST MULTIPLIER FOR ZERO TEST ; MULLP: DCR A RZ ; DAD D JMP MULLP ;..... ; ; ; SHIFT 'HL' REGISTER PAIR ONE BIT TO THE RIGHT ; SHFTHL: MOV A,L RAR MOV L,A ORA A ;CLEAR THE CARRY MOV A,H RAR MOV H,A RNC MVI A,80H ORA L MOV L,A RET ;..... ; ; ;======================================================================= ; ; PMMI BAUD RATE INITIALZATION ; ;======================================================================= ; GETBAUD: LDA FCB+9 ;GET 1ST DIGIT OF REQUESTED BAUDRATE CPI ' ' ;IF A SPACE RETURN WITH 300 BAUD MVI A,52 RZ LDA FCB+9 ORA A ;IF A NULL RETURN WITH 300 BAUD MVI A,52 RZ LXI D,FCB+9 LXI H,0 ; DECLP: LDAX D INX D CPI ' ' JZ DECLP CPI '0' ;NUMERALS ARE 0-9 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 ;250000/16 LXI B,-1 ; DIVLP: INX B DAD D JC DIVLP MOV A,B ORA A MOV A,C RZ ; BADRATE: CALL ERXIT DB '++ INVALID BAUDRATE ++$' ;... ; ; CHGMSPD: MVI C,0 ;CHANGES PMMI MSPEED FOR 110-1200 BAUD CPI 100 ;<300 BAUD RNC INR C ;C=1 FOR 300 BAUD CPI 40 ;<450 BAUD RNC INR C ;C=2 FOR 450 BAUD CPI 30 ;<600 BAUD RNC INR C ;C=3 FOR 600 BAUD CPI 24 ;<710 BAUD RNC INR C ;C=4 FOR 710 BAUD RET ;..... ; ; ; The non-PMMI setup routines can go here. The following is a starting ; point. Several hundreds of bytes are available. ; SETUPR: RET ;..... ; ; ;======================================================================= ; ; PMMI DIALING ROUTINES ; ;======================================================================= ; ; 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 35 ;7 SECONDS TO WAIT TIL NO-RING-HEARD MSG RBWAIT: EQU 50 ;5 SECOND DELAY BEFORE REDIALING NUMBER TMPUL: EQU 80H ;TIMER PULSES MASK BIT TRATE: EQU 250 ;VALUE FOR 0.1 SECOND ;..... ; ; Dialing routine ; DIAL: LDA PMMIBYTE ;USING A PMMI MODEM? ORA A RZ ;IF NOT, SKIP AUTO-DIALING ROUTINE ; XRA A STA CRFLAG ;ZERO THE CONTINUOUS DIAL FLAG STA RINGBKFL ;ZERO THE RINGBACK FLAG LXI H,0 SHLD DIALCT ;ZERO THE DIAL COUNT LXI H,CMDBUF+1 ;POINT TO THE NUMBER OF CHARACTERS IN.. MOV A,M ;..THE BUFFER, THEN GET THE NUMBER CPI 3+1 ;ANYTHING TYPED AFTER "CAL"? JC DIAL1 ;IF NOT, GO THROUGH LIBRARY ROUTINE ; ; ; If there were only 3 characters, then "CAL" was typed -- the user ; obviously expecting to get a phone number (or letter) from the library ; file. If 4 or more, a number (or letter) was typed in from the menu ; command line, so move the characters down 4 to compensate. Needed for ; auto-redialing of menu command line entries. ; MOV C,A ;PUT INTO THE 'C' REG. MVI B,0 ;WILL MOVE ORIGINAL NUMBER DOWN 4 SUI 4 ;ELIMINATE THE "CAL " PORTION MOV M,A ;STORE NEW COUNT AT CMDBUF+1 INX H ;CMDBUF+2 (FIRST CHAR. OF STRING) XCHG ;'DE' NOW HAS CMDBUF+2 LXI H,CMDBUF+6 ;POINT TO NUMBER (OR LETTER) TO DIAL CALL MOVER ;MOVE THE GROUP DOWN 4 PLACES JMP DIAL4 ;CHECK IF LIBRARY NUMBER, THEN DIAL ;... ; ; ; Comes here if no phone number was manually entered after "CAL" and if ; no phone library letter was entered. Displays the phone number library ; then asks for an entry. ; DIAL1: MVI C,13 ;NUMBER OF LINES TO MOVE LXI H,NUMBLIB ;START OF PHONE NUMBER LIBRARY LXI D,DBUF ;BUFFER ADDRESS TO STORE THEM TEMPORARILY CALL NEWLINE ;START WITH CRLF STAX D ;+LF INX D ;AND BUMP IT ; DIAL2: MVI B,LIBLEN ;NUMBER OF BYTES TO MOVE CALL MOVE ;MOVE TO BUFFER CALL SPACES ;2 ENTRIES + 3 SPACES = 71 CHARACTERS MVI B,LIBLEN CALL MOVE CALL NEWLINE DCR C ;ONE LESS LINE TO PRINT JNZ DIAL2 ;IF NOT ZERO, PRINT ANOTHER ; DIAL3: MVI A,'$' ;BDOS PRINT ROUTINE TERMINATE CHARACTER STAX D ;STORE IN BUFFER CALL CLRTST MVI C,PRINT LXI D,DBUF ;PRINT THE LIBRARY ON THE CRT CALL BDOS CALL ILPRT ;ASK WHICH ONE IS WANTED DB CR,LF,'Enter number or library letter - ' DB 'when finished,',CR,LF DB 'CTL-X cancels while dialing: ',0 LXI D,CMDBUF CALL INBUF ; ; You now have either a library letter or a manually entered phone num- ; ber. These either came from the menu command line or from the library ; command line. Next we see if a letter, if so, get the corresponding ; line with phone number from the library. If a number we ignore the ; library look-up. (Ringback numbers must end with letter 'R'.) ; DIAL4: LXI H,CMDBUF+1 ;NUBER OF CHARACTERS IN BUFFER MOV A,M ORA A ;NULL MEAND WAS TYPED JZ DIALEXIT ;ABORT DIALING, RETURN TO MENU INX H ;FIRST TYPED CHAR OF NUMBER TO DIAL CALL DIALBGN ;DISCONNECT, RECONNECT, WAIT FOR TONE JC DIALEXIT ;IF NO DIALTONE, PONDER NEXT MOVE 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 ; DIAL5: CMP B ;NUMBER FROM TABLE? JZ DIAL6 INR B ;MAKE NEXT LETTER (A-Z) INR E ;COUNT UP DCR C ;COUNT DOWN JZ DIAL9 ;WAS NOT A-Z SO EXIT JMP DIAL5 ;LOOP ; ; ; Now have a match between the requested letter and one in the library ; 'E' holds the decimal equivalent (1-26) of the letter (A-Z). ; DIAL6: LXI H,NUMBLIB ;PHONE NUMBER LIBRARY LXI B,LIBLEN ;LENGTH OF LIBRARY ENTRY MOV A,E ;NUMBER OF TIMES TO LIBRARY LENGTH TO HL ORA A ;SET FLAGS JZ DIAL8 ; DIAL7: MOV A,M ;GET FIRST CHAR OF SELECTED LIB ENTRY ORA A ;SET FLAGS JZ DIALBAD ;SEND BAD LIBRARY MSG AND ABORT DAD B ;INCREMENT 'HL' BY LIBRARY LENGTH DCR E ;COUNTDOWN JNZ DIAL7 ;NOT THERE YET, LOOP ; ; ; Now have the line in the phone number library matching the requested ; letter so store that line starting at 'CMDBUF+1' ; DIAL8: MVI B,LIBLEN ;NUMBER OF CHARACTERS TO GET FROM TABLE LXI D,CMDBUF+1 ;POINT TO BUFFER XCHG ;'HL' POINTS TO CMDBUF+1 MOV M,B ;LENGTH OF EACH TABLE ENTRY XCHG ;RESTORE THE REGISTERS INX D ;POINT TO FIRST CHAR POSITION IN BUFFER CALL MOVE ;MOVE THE TABLE ENTRY TO THE BUFFER ; ; ; Now have the full line including phone number in 'CMDBUF' area. ; DIAL9: LXI H,CMDBUF+1 MOV E,M ;NUMBER OF CHARS IN BUFF INX H ;POINT TO 1ST CHAR. TO DIAL ; DIAL10: MOV A,M ;GET FIRST NUMBER FROM THE BUFFER ORA A ;SET FLAGS JZ DIALBAD ;BUM NUMBER IF A NULL ; ; ; Dial a digit, check keyboard for abort ; CALL DIALA ;SHOW THE STRING, DIAL THE NUMBER ; CALL STAT ;KEYPRESS? ORA A ;SET FLAGS CNZ KEYIN ;YES, GO GET IT CPI CAN ;CTL-X? JZ DIALEXIT ;YES, ABORT INX H ;BUMP POINTER PUSH D ;SAVE DE PUSH H ;SAVE HL MVI B,1 ;WAIT 0.1 SECOND (ONE TIMER INTERVAL) CALL TIMER POP H ;RESTORE HL POP D ;RESTORE DE DCR E ;ONE LESS CHARACTER TO GO JNZ DIAL10 ;IF NOT DONE, LOOP ; ; ; Show the number of dial attempts ; CALL ILPRT DB ' try #',0 LHLD DIALCT ;INCREMENT THE DIAL COUNT INX H SHLD DIALCT CALL DECOUT ;SHOW NUMBER OF ATTEMPTS SO FAR ; ; ; Dialing is all done ; CALL CRLF MVI A,07FH ;TURN ON 'DTR' CALL OUT$MODCTL2 ;TIMER RATE? MVI B,1 ;0.1 SECOND PER INTERVAL CALL TIMER ;WAIT FOR MODEM TO TURN ON 'DTR' ;MOD(BGL)*** LDA PARTY ;DEFAULT PARITY SET, NORMALLY ;..1 STOP BIT, NO PARITY, 8 DATA ;..BITS, NO DISCON. AFTER 17 SEC CALL OUT$MODCTLP MVI D,4 ;CLEAR TO SEND MASK MVI C,WAITCTS ;WAIT TIME FOR CTS.. CALL WAIT ;..(30 SECONDS, CAN SET 'WAITCTS' FOR ; ;..UP TO 51 SECONDS FOR EUROPEAN USE) ; ; If connection made, go get options for starting communications ; JNC CONMADE ;CONNECTION MADE ; ; ; Connection not made, see if a redial is desired ; CALL DISCONNT ;HANG-UP SO WE CAN REDIAL IF DESIRED ; DIALAGN: LDA CRFLAG ;CONTINUOUS REDIAL FLAG ORA A JNZ DIALAGN1 ;IF ALREADY SET, GO DIAL AGAIN CALL ILPRT ;IF NOT, SEE IF SHOULD REDIAL AGAIN DB CR,LF,'No answer after time-out. Redial? ' DB '(Y/N/C): ',BELL,0 CALL KBDCHR CALL CRLF ;NEW LINE CPI 'N' ;REDIAL? JZ MENU ;NO, GO MENU CPI 'Y' ;REDIAL? JZ DIALAGN1 ;YES, REDIAL CPI 'C' ;CONTINUOUS REDIAL? JNZ DIALAGN ;INVALID RESPONSE, ASK AGAIN MVI A,TRUE ;SET TRUE STA CRFLAG ;CONTINUOUS REDIAL FLAG ; DIALAGN1: MVI B,RBWAIT ;5 SECONDS WAIT FOR PMMI RESET (OR BUSY) CALL TIMER ;OR BUSY TONE MAY BE SENSED AS DIALTONE LDA RINGBKFL ;RINGBACK FLAG SET? ORA A JZ DIAL4 ;IF NOT, GO REDIAL A NORMAL NUMBER STA CMDBUF+1 ;RESTORE ORIGINAL VALUE INCLUDING THE 'R' JMP DIAL4 ;REDIAL ENTRY POINT ;..... ; ; ; Connection has been made ; CONMADE: CALL ILPRT DB CR,LF,'Connection established - Select options: ' DB BELL,0 ; CONMAD1: CALL STAT ;KEYPRESS? ORA A ;SET FLAGS JNZ GETCMD ;KEY PRESSED, GO GET OPTIONS MVI A,BELL CALL TYPE ;RING BELL LXI B,2000H ; CONMAD2: DCR C JNZ CONMAD2 ;KILL SOME TIME FOR TERMINAL.. DCR B ;..PROCESS THE BELL JNZ CONMAD2 JMP CONMAD1 ;LOOP UNTIL CONNECTED ;..... ; ; ; Automatic dialing routine, prints the number being dialed ; DIALA: CALL TYPE ;PRINT WHATEVER CHARACTER, DASHES, ETC. CPI 'R' ;COULD IT BE A RINGBACK CHARACTER? JNZ DIALA1 ;IF NOT, PROBABLY A NUMBER SO EXIT PUSH PSW ;SAVE ACCUMULATOR & FLAGS MOV A,E ;GET THE CHARACTER COUNT. IS THIS "R".. CPI 1 ;..THE LAST CHARACTER IN THE STRING? JZ RINGBK ;YES, MUST BE RINGBACK CHAR, DO RINGBACK POP PSW ;EVERYTHING BACK AS IT WAS ; DIALA1: CPI '0' ;DIGITS ARE 0-9 RC ;EXIT LESS THAN ASCII '0' CPI '9'+1 RNC ;EXIT IF MORE THAN ASCII '9' SUI '0' ;STRIP ASCII -- COULD ALSO DO 'ANI 0FH' JNZ DIALA2 MVI A,10 ;CONVERT ZERO TO 10 PULSES ; DIALA2: MOV C,A LDA PULSERATE ;CONTAINS VALUE FOR DIAL SPEED CALL OUT$BAUDRP ; DIALA3: CALL IN$BAUDRP ANI TMPUL JNZ DIALA3 ; DIALA4: CALL IN$BAUDRP ANI TMPUL JZ DIALA4 ; DIALA5: MVI A,MAKEM CALL OUT$MODCTLP ; DIALA6: CALL IN$BAUDRP ANI TMPUL JNZ DIALA6 MVI A,BRKM CALL OUT$MODCTLP ; DIALA7: CALL IN$BAUDRP ANI TMPUL JZ DIALA7 DCR C JNZ DIALA5 MVI A,MAKEM CALL OUT$MODCTLP ;MOD(BGL)*** MVI B,8 ;0.1 SECOND PER TIMER INTERVAL JMP TIMER ;RETURN TO CALLER ;..... ; ; ; Print bad library number message and abort if a null is encountered. ; DIALBAD: CALL ILPRT DB CR,LF,'++ Bad library number called ++',CR,LF,0 ; DIALEXIT: CALL DISCONNT ;ABORT ROUTINE CALL CRLF JMP MENU ;..... ; ; ; Disconnect from the line, reconnect and wait for the dialtone. ; DIALBGN: 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,50 ;WAITS UP TO 10 SEC. FOR DIAL TONE CALL WAIT ;WAIT FOR DIAL TONE ; ; ; Wait subroutine will return with carry set if unable to get dialtone. ; If carry is not set, the dialtone was 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 ;SET THE CARRY BIT (NO DIALTONE) RET ;..... ; ; 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 (0.8 SEC) CALL TIMER ;0.1 SECOND PER TIMER INTERVAL POP B RET ;..... ; ; HANGUP: MVI A,CLEAR CALL OUT$MODCTL2 MVI A,0 CALL OUT$MODCTLP RET ;..... ; ; ; Handles the special ringback numbers. Dials, lets it ring only once, ; hangs up and then redials. ; RINGBK: POP PSW ;TO GET IT OFF THE STACK LDA CMDBUF+1 ;GET THE NUMBER OF CHARS. IN THE BUFFER STA RINGBKFL ;STORE ORIGINAL NUMBER INCLUDING THE 'R' SUI 1 ;SUBTRACT 1 TO AVOID THE RINGBACK CHAR STA CMDBUF+1 ;STORE THE NEW VALUE MVI D,DTMSK ;LOAD TONE DETECT MASK MVI C,RBLMT ;WAITS UP TO 7 SECONDS FOR A RING CALL WAIT JC RBTIME ;JUMP IF NO RING DETECTED MVI B,25 ;GOT A RING, WAIT 2.5 SEC CALL TIMER CALL IN$BAUDRP ;IS TONE STILL PRESENT? ANA D JZ DIALAGN ;YES, MUST BE BUSY ;..... ; ; ; Hang up, redial and listen for dial tone ; RNGBK1: CALL HANGUP ;HANG UP THE PHONE MVI B,RBWAIT ;WAIT 5 SECONDS BEFORE REDIALING.. CALL TIMER ;..FOR LINE TO CLEAR, ETC. CALL DIALBGN ;DISCONNECT, RECONNECT, WAIT FOR TONE JNC DIAL9 ;GO REDIAL NUMBER JMP DIALAGN ;NO DIAL TONE HEARD ;..... ; ; RBTIME: CALL CRLF JMP RNGBK1 ;HANGUP, REDIAL, & LISTEN FOR CARRIER ;..... ; ; ; PMMI timer routine. Waits 0.1 seconds for each unit in 'B' reg. ; TIMER: MVI A,TRATE ;TRATE 250, VALUE FOR .1 SEC INTERVAL CALL OUT$BAUDRP ;'B' CONTAINS NUMBER OF .1 SEC INTERVALS ; TIMER1: CALL IN$BAUDRP ;TO COUNT ANI TMPUL JZ TIMER1 ;WAIT FOR TIMER TO GO HIGH ; TIMER2: CALL IN$BAUDRP ANI TMPUL JNZ TIMER2 ;WAIT FOR TIMER TO GO LOW DCR B JNZ TIMER1 RET ;..... ; ; ; Time-out routine. Must be called with mask in 'D' reg. for input at ; relative port 2 and number of seconds (times 10) in 'C' reg. ; WAIT: MVI B,2 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 ;CTL-X TO INTENTIONALLY ABORT? 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 ;..... ; ; ; (END OF PMMI DIALING ROUTINE) ; ;======================================================================= ;*********************************************************************** ;* * ;* 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.997% of all 17- * ;* bit error bursts and 99.998% of all possible longer error bursts. * ;* (Ref: Computer Networks, Andrew S. Tanenbaum, Prentiss-Hall 1981) * ;* * ;* This program may be freely reproduced for non-profit use. * ;* Copyrighted 1981, Carpenter Associates, Bloomfield Hills, MI * ;* * ;*********************************************************************** ; ; ; ENTRY CLRCRC,UPDCRC,FINCRC,CHKCRC ; CLRCRC: PUSH H ;RESET CRC ACCUMULATOR FOR A NEW MESSAGE LXI H,0 SHLD CRCVAL POP H RET ;..... ; ; UPDCRC: PUSH PSW ;UPDATE CRC ACCUMULATOR USING BYTE IN 'A' 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 SYNCHRONQOUS TRANSMISSION XRI 21H ; PROTOCOLS IS X^16 + X^15 + X^2 + 1. MOV L,A ; THIS MAY BE USED BY SUBSTITUTING ; SKIPIT: DCR B ; XOR 80H FOR XOR 10H, AND XOR 05H FOR JNZ UPDLOOP ; 21H IN THE ADJACENT CODE. SHLD CRCVAL POP H POP B POP PSW RET ;..... ; ; FINCRC: PUSH PSW ;FINISH CRC CALCULATIONS FOR OUTPUT MSG XRA A CALL UPDCRC CALL UPDCRC PUSH H LHLD CRCVAL MOV D,H MOV E,L POP H POP PSW RET ;..... ; ; CHKCRC: PUSH H ;CHECK CRC BYTES OF RECEIVED MESSAGE LHLD CRCVAL MOV A,H ORA L POP H RZ MVI A,0FFH RET ;..... ; ; ;*********************************************************************** ; ; MENU ; ;*********************************************************************** ; ; MENU0: LDA NFILFLG ORA A JNZ MENU ;GO IF NO FILE ACTIVE CALL ILPRT ;ELSE PRINT MESSAGE DB CR,LF DB '** There may be text in the memory buffer. It will **' DB CR,LF DB '** be lost unless the NOL or WRT commands are used. **' DB CR,LF,BELL,0 JMP MENU1 ; MENU: XRA A STA ABORTFLG ;NULL THE FLAG LDA EXITFLG ORA A JNZ EXIT ;IF SET, EXIT ; MENU1: LXI H,RESTSN ;RESTORE RECORD NUMBERS.. LXI D,RECDNOB ;..FOR NEW FILE TRANSFER. MVI B,RECDNOE-RECDNOB CALL MOVE LXI H,RESTROPT ;RESTORE OPTION TABLE LXI D,OPTBL MVI B,OPTBE-OPTBL CALL MOVE XRA A STA MFFLG1 ;RESET MFACCESS ROUTINE.. CMA ;..AND MULTI TRANS IN CASE.. STA FSTFLG ;..OF ABORT. JMP XPRT ;..... ; ; ; * * * * * * * * * * * * * * * * * * ; ; THE COMMAND MENU ; ; * * * * * * * * * * * * * * * * * * ; MENU2: CALL CLRTST CALL ILPRT DB ' Single Letter Commands',CR,LF,LF DB ' ? - Display current settings',CR,LF DB ' H - Display this information',CR,LF DB ' E - Terminal mode with echo',CR,LF DB ' L - Terminal mode with local echo',CR,LF DB ' T - Terminal mode',CR,LF DB ' For copying text to disk use T (or E or L) ' DB 'FILENAME.TYP',CR,LF DB ' Start or Stop toggles described on subsequent ' DB 'screen.',CR,LF,LF DB ' R - Receive CP/M file using Christensen Protocol' DB CR,LF DB ' S - Send CP/M file using Christensen Protocol',CR,LF DB ' Command: R (or S) FILENAME.TYP',CR,LF,LF DB ' R and S can use the following subcommands:' DB CR,LF DB ' B - Bulk transfer using wildcards ' DB '(e.g., *.*)',CR,LF DB ' Q - Quiet mode (no messages to console)' DB CR,LF DB ' T - Return to terminal mode after ' DB 'transfer',CR,LF DB ' V - View bytes transferred on console' DB CR,LF,LF DB ' The single letter commands may also be used on ' DB 'the',CR,LF DB ' command line when the program is initially ' DB 'executed.',CR,LF,LF,0 ; CALL NXTSCRN ; LDA PMMIBYTE ORA A JZ THREELTR ;IF NOT PMMI, SKIP THIS SPECIAL PAGE CALL ILPRT DB ' Additional Subcommands for PMMI Modem' DB CR,LF,LF DB ' Modem control:',CR,LF DB ' A - Answer tone for send or receive',CR,LF DB ' O - Originate tone for send or receive',CR,LF DB ' D - Disconnect from the phone line',CR,LF DB ' X - Disconnect, then reboot to CP/M',CR,LF,LF DB ' Parity option:',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' DB CR,LF DB ' which are available only in R and S modes.' DB CR,LF DB ' The parity checking will be part of the' DB CR,LF DB ' file transfer protocol.',CR,LF,LF DB ' Speed Options:',CR,LF DB ' After entering your primary and secondary ' DB 'options,',CR,LF DB ' you can set the modem speed by placing a ' DB ' "." after',CR,LF DB ' the options followed by the speed e.g., ' DB '300, 1200.',CR,LF,LF DB ' EXAMPLE: SBOT.600 will set the modem for ' DB '600 baud',CR,LF,LF,0 ; CALL NXTSCRN ; THREELTR: CALL ILPRT DB ' Three Letter Commands',CR,LF DB 'CPM - Exit from this program to CP/M',CR,LF DB 'DIR - List directory and space free (may specify ' DB 'drive)',CR,LF DB 'ERA - Erase file (may specify drive)',CR,LF DB 'LOG - Change default drive/user no. (specify ' DB 'drive/user)',CR,LF DB ' and reset disks. e.g. LOG A0: or LOG B: ' DB '(user # unchanged)',CR,LF DB 'SPD - Set speed of file output in terminal mode' DB CR,LF,0 ; CALL SORPTST JNZ NOTIME CALL ILPRT DB 'TIM - Select Baud rate for "time-to-send" msg.',CR,LF,0 ; NOTIME: LDA TOGGLECRC ORA A JZ NOTOGCRC CALL ILPRT DB 'TCC - Toggle CRC/Checksum mode on receive',CR,LF,0 ; NOTOGCRC: LDA TOGGLEBK ORA A JZ NOTOGBK CALL ILPRT DB 'TBR - Toggle backspace to rubout 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 ' DB 'in "T" mode',CR,LF,0 ; NOTOGLF: LDA TOGXOFF ORA A JZ NOTOGXOF CALL ILPRT DB 'TXO - Toggle XOFF testing in terminal mode ' DB 'file output',CR,LF,0 ; NOTOGXOF: LDA PMMIBYTE ORA A JNZ NONUM CALL ILPRT DB 'NUM - List remote systems',CR,LF,0 LDA SETUPTST ORA A JZ NOPMMI CALL ILPRT DB 'SET - Set communication ports',CR,LF,0 ; NONUM: CALL ILPRT DB 'PAR - Toggle 8 bits no par/7 bits even par',CR,LF DB 'BYE - Disconnect, then reboot to CP/M',CR,LF DB 'CAL - Dial number',CR,LF DB 'DSC - Disconnect from the phone line',CR,LF,0 ; NOPMMI: CALL ILPRT DB CR,LF,' The following are terminal text ' DB 'buffer commands:',CR,LF,0 ; SKIPLF: CALL ILPRT DB 'DEL - Delete memory buffer and file',CR,LF DB 'NOL - Return to terminal mode - no loss of data ' DB 'in buffer',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' DB CR,LF,LF,0 LDA EXITCHR CALL SHFTYPE DB ' - Exit to command mode',CR,LF,0 ; LDA PMMIBYTE ORA A JZ S5A ; LDA DISCCHR CALL SHFTYPE DB ' - Disconnect from the phone line',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 NOTRNLOG LDA LOGCHR CALL SHFTYPE DB ' - Send log-on message',CR,LF,0 ; NOTRNLOG: 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,LF DB ' Start & Stop may be toggled as often as ' DB 'desired.',CR,LF DB ' A ":" at start of line indicates buffer ' DB 'is copying.',CR,LF DB ' XOFF automatically used to stop input ' DB 'when writing',CR,LF DB ' full buffer to disk, XON sent to ' DB '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' DB CR,LF,LF,0 JMP XPRT ; REMDFLT: CALL SHFTYPE DB ' - Next character will be used for local control' DB CR,LF,0 ; XPRT: CALL CRLF ;TURN UP A BLANK LINE TO LOOK NICE LDA NFILFLG ;HAVE A FILE OPEN FOR TEXT MODE COPY? ORA A JNZ XPRT1 ;IF NOT, EXIT CALL GETSPC ;OTHERWISE SHOW REMAINING SPACE CALL ILPRT DB ' Bytes of buffer free',CR,LF,0 ; XPRT1: MVI C,CURDSK ;CURRENT DISK FUNCTION CALL BDOS ADI 'A' ;MAKE ASCII CALL TYPE ; CALL GETUSER ;GET CURRENT USER NUMBER ORA A JZ XPRT2 ;SKIP IF USER 0 MVI H,0 MOV L,A CALL DECOUT ;SHOW USER CURRENT USER AREA ; XPRT2: MVI A,'>' CALL TYPE MVI A,' ' CALL TYPE CALL ILPRT DB 'COMMAND (H for Help): ',0 ; GETCMD: LXI D,CMDBUF ;ENTER COMMAND CALL INBUF LDA CMDBUF+3 CPI ':' ;SEE IF REQUEST FOR NEW DRIVER/USER JZ SETDRV LXI D,CMDBUF+2 ;POINT TO COMMAND CALL INLNCOMP DB 'CPM',0 JNC EXIT CALL CRLF ;(1ST CR,LF AT "INBUFR") CALL INLNCOMP DB 'LOG',0 JNC LOGNEW CALL INLNCOMP DB 'DIR',0 JNC DIR CALL INLNCOMP DB 'ERA',0 JNC ERASEF CALL INLNCOMP DB '?',0 JNC CURPAR CALL INLNCOMP DB 'SPD',0 JNC SETSPD CALL INLNCOMP DB 'TIM',0 JNC SETTIM CALL INLNCOMP DB 'TCC',0 JNC TOGCRC CALL INLNCOMP DB 'TBR',0 JNC TOGBKSP CALL INLNCOMP DB 'TLC',0 JNC TOGLOC CALL INLNCOMP DB 'TLF',0 JNC TOGLF CALL INLNCOMP DB 'TXO',0 JNC TOGTXOFF LDA PMMIBYTE ORA A JNZ NONUM2 CALL INLNCOMP DB 'NUM',0 JNC NUMPRN ; NONUM2: LDA SETUPTST ORA A JZ NOSETUP CALL INLNCOMP DB 'SET',0 JNC SETUPENT ; NOSETUP: CALL INLNCOMP 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 INLNCOMP DB 'WRT',0 JNC WRTFIL CALL INLNCOMP DB 'DEL',0 JNC NEWFILE CALL INLNCOMP DB 'BYE',0 JNC BYEBYE LDA PMMIBYTE ORA A JZ S6 ;MOD(BGL)*** CALL INLNCOMP DB 'PAR',0 JNC TOGLPAR CALL INLNCOMP ;'DE' SET FROM 1ST INLNCOMP CALL DB 'DSC',0 JNC DISCON1 CALL INLNCOMP DB 'CAL',0 JC S6 MVI A,' ' ;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 NTVLDMSG JMP XPRT ; ; NTVLDMSG: CALL ILPRT DB '++ Invalid command ++',CR,LF,BELL,0 RET ;..... ; ; BYEBYE: CALL ILPRT DB '<< Goodbye...back to CP/M >>',CR,LF,0 XRA A CALL OUT$MODCTLP CALL OUT$MODCTL2 LDA OLDUSER ;GET ORIGINAL USER NUMBER MVI E,A CALL SETUSER LHLD CLDBOOT PCHL ;DO A COLD REBOOT, DONE ;..... ; ; DIR: MVI C,CURDSK CALL BDOS STA DISKSAV CALL DIRLIST LDA DISKSAV MOV E,A MVI C,SELDSK CALL BDOS JMP XPRT ;..... ; ; DISCON1: CALL JMP$DISCONNT CALL ILPRT DB CR,LF,'<< Disconnected >>',CR,LF,BELL,0 JMP EXITMEN ;..... ; ERASEF: LXI D,CMDBUF ;PUT CMD LINE INTO FCB AT 'HL' LXI H,FCB CALL CMDLINE 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 ;..... ; ; LOGNEW: LDA NFILFLG ORA A JZ NORESET LDA CMDBUF+6 ;ANY DISK DRIVE SPECIFIED? CPI ' ' JNZ LOGNEW1 ;IF NOT A BLANK, EXIT CALL GETDISK ;IF NOT, USE CURRENT DRIVE ADI 'A' ;TO COMPENSATE FOR NEXT LINE ; LOGNEW1: SUI 'A' CPI 15+1 ;FOR DRIVES 0-15 JNC NOTVLD ;IF MORE THAN 15, DISPLAY ERROR MESSAGE STA DISKSAV ;STORE REQUESTED DRIVE CALL GETUSER ;PICK UP CURRENT USER NUMBER MOV B,A ;SAVE IT LDA CMDBUF+7 ;GET NEW USER NUMBER CALL CHRCHK ;CHECK THE CHAR. CALL FINDUSER LDA CMDBUF+8 ;GET 2ND DIGIT CALL CHRCHK ;CHECK THE CHAR. CALL FINDUSER+2 ; LOGNEW2: CALL SAVEUSER MVI C,RESET CALL BDOS LDA DISKSAV MOV E,A MVI C,SELDSK CALL BDOS LDA SAVUSR MOV E,A CALL SETUSER JMP XPRT ;..... ; ; CHRCHK: CPI ' ' JZ CHRCHK1 CPI ':' ;IN CASE OF A: OR A1: OR A11: (ETC.) RNZ ; CHRCHK1: POP PSW ;RESET THE 'CALL' ON THE STACK JMP LOGNEW2 ;..... ; ; FINDUSER: MVI B,0 ;ZERO THE 'B' REG. FOR 1ST TIME THROUGH CALL NUMCHK ;IF NEITHER, SEE IF A VALID NUMBER MOV C,A ;SAVE MOV A,B ;GET SAVE FIRST DIGIT ADD A ;X2 ADD A ;X4 ADD A ;X8 ADD B ;X9 ADD B ;X10 ADD C MOV B,A ;SAVE RET ;..... ; ; SAVEUSER: MOV A,B CPI 15+1 ;USER NUMBERS ARE 0-15 JNC NOTVLD STA SAVUSR RET ;..... ; ; NUMGET: LXI D,CMDBUF CALL INBUF LDA CMDBUF+2 ;GET NUMBER CPI ' ' RZ ; NUMCHK: SUI '0' ;REMOVE ASCII BIAS CPI 9+1 RC ;OK IF 9 OR LESS POP H ;REMOVE 1ST CALL FROM THE STACK POP H ;REMOVE 2ND CALL FROM THE STACK JMP NOTVLD ; GETUSER: MVI E,0FFH ;GET CURRENT USER ; SETUSER: MVI C,USER ;SET UP BDOS CALL JMP BDOS ;..... ; ; GETDISK: MVI C,CURDSK ;GET CURRENT DRIVE JMP BDOS ;..... ; ; NORESET: CALL ILPRT DB '++ Terminal mode file open ++',CR,LF DB '++ Use WRT or DEL before LOG command ++',CR,LF DB CR,LF,BELL,0 XRA A JMP XPRT ;..... ; ; SETSPD: CALL ILPRT DB 'Delay between chars. (0-9): ',0 ; NOKEYS: CALL STAT JZ NOKEYS CALL KEYIN CALL TYPE CALL SAVEA SUI '0' CPI 10 JNC NOTVLD STA BYTDLY ; CALL ILPRT DB 'Delay at end of line (0-9): ',0 ; NOKEYS1: CALL STAT JZ NOKEYS1 CALL KEYIN CALL TYPE CALL SAVEA SUI '0' CPI 10 JNC NOTVLD STA CRDLY ; SPDMSG: CALL ILPRT DB CR,LF,'Char. delay (terminal file mode) is: ',0 LDA BYTDLY MOV B,A MOV A,B PUSH H MOV L,A MVI H,0 CALL DECOUT POP H CALL ILPRT DB '0 ms. per character',CR,LF DB 'Line delay (terminal file mode) is: ',0 LDA CRDLY MOV B,A PUSH H MOV L,A MVI H,0 CALL DECOUT POP H CALL ILPRT DB '00 ms. per character',CR,LF,0 JMP XPRT ;...... ; ; SAVEA: PUSH PSW CALL ILPRT DB CR,LF,0 POP PSW RET ;..... ; ; SETDRV: LDA CMDBUF+2 ;GET THE DISK DRIVE SUI 'A' ;CONVERT TO BINARY VALUE CPI 15+1 ;FOR DRIVES 0-15 JNC NOTVLD MOV E,A MVI C,SELDSK ;SELECT REQUESTED DRIVE CALL BDOS LDA CMDBUF+5 ;GET USER NUMBER, IF ANY CPI ' ' ;KEEP CURRENT USER AREA? JZ XPRT SUI '0' ;CONVERT TO BINARY VALUE CPI 1 ;IF A '1', COULD BE UNITS OR TENS JNZ SETDRV1 ;IF NOT, NUMBERS STOP AT 15 SO EXIT LDA CMDBUF+6 ;CHECK FOR A 2ND DIGIT CPI '0' JC SETDRV2 ;IF LESS, NOT A VALID NUMBER, IGNORE SUI '0'-10 ;LEAVE THE '10' IN AS TWO DIGITS USED ; SETDRV1: CPI 15+1 ;USER AREAS ARE 0-15 JNC NOTVLD MOV E,A CALL SETUSER JMP XPRT ;BACK TO WORK ; SETDRV2: MVI A,1 JMP SETDRV1 ;..... ; ; SETTIM: CALL SORPTST JNZ NOTVLD CALL ILPRT DB 'Use 0-8 to give baud rate for ''S'' mode ' DB 'time-to-send message,',CR,LF DB 'where 0=110, 1=300, 2=450, 3=600, 4=710, 5=1200, ' DB '6=2400, ',CR,LF,'7=4800 AND 8=9600 Baud.' DB CR,LF,LF,'Enter value: ',0 CALL NUMGET CPI 8+1 ;ONLY LOOKING FOR 1-8 ANSWERS 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 PRTBAUD ;..... ; ; SORPTST: LDA SETUPTST MOV B,A LDA PMMIBYTE ORA B RET ;..... ; ; TOGCRC: LDA TOGGLECRC ORA A JZ NOTVLD LDA CKSUMDFLT CMA STA CKSUMDFLT CALL TOGCRC1 JMP XPRT ;..... ; ; TOGCRC1: 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 INBUF 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 INITFCB 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 ;START OF MEMORY BUFFER CALL NUMRECS ;DISK WRITE ROUTINE AS USED IN CALL WRTDSK ; THE 'INTDSKSV' ROUTINE CALL CLOSE3 MVI A,TRUE STA NFILFLG ;SHOW NO FILE OPEN NOW CMA STA SAVEFLG LXI H,FCB3 CALL INITFCB ;BLANK OUT FCB TO WRITTEN FILE LXI H,BOTTRAM ; CAN'T BE ERASED SHLD HLSAVE ;RESET TO BUFFER START FOR NEXT TIME 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' DB 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,LIBLEN-2 ;NUMBER OF BYTES TO MOVE CALL MOVE ;MOVE TO BUFFER CALL SPACES ;2 ENTRIES + 3 SPACES = 63 CHARACTERS INX H INX H MVI B,LIBLEN-2 CALL MOVE CALL NEWLINE DCR C ;NUMBER OF LINES TO PRINT JZ NUMPRN2 JMP NUMPRN1 ;..... ; ; NEWLINE: MVI A,CR ;PUTS CR-LF AT MEMORY POINTED BY 'DE' STAX D ;STORE IT MVI A,LF ;LF INX D ;BUMP POINTER STAX D ;STORE LF INX D ;BUMP POINTER RET ;..... ; ; SPACES: MVI A,' ' ;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 'C'-40H ;CONTROL-C TO ABORT? JNZ CLRTST POP H ;CLEAR STACK OF RETURN ADDRESS CALL CRLF ;TURN UP A BLANK LINE 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,0 LDA CKSUMDFLT ;SEE IF SET FOR 'CRC' OR 'CHECKSUM' CALL TOGCRC1 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 CRLF CALL CRLF 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 CALL DECOUT RET ;..... ; ; COMPLIST: DB 6, 'S', 'R', 'T', 'E', 'H', 'L' ;..... ; ; ;*********************************************************************** ; ; D - A - T - A A - R - E - A ; ;*********************************************************************** ; ; ; OPTION TABLE ; OPTBL: EQU $ ANSWFLG: DB 'A' BATCHFLG: DB 'B' ;SET TO 'B' BY MENU. DOES NOT ALLOW MULTI-FILE DISCFLG: DB 'D' LOCCHFLG: DB 'L' ORIGFLG: DB 'O' QFLG: DB 'Q' RSEEFLG: DB 'R' SSEEFLG: DB 'S' TERMFLG: DB 'T' VSEEFLG: DB 'V' XITFLG: DB 'X' EPARITY: DB '0' ;EVEN PARITY SUB-OPTION (ONLY IN S OR R MODE) OPARITY: DB '1' ;ODD PARITY SUB-OPTION (ONLY IN S OR R MODE) OPTBE: EQU $ ;..TRANSFER WHEN PROGRAM INITIALLY CALLED. ; ; ; The following must be in the same order as the table above: ; RESTROPT: DB 'A','B','D','L','O','Q','R','S','T','V','X','0','1' ; ; ; THE NEXT 13 BYTES EQUAL THE NUMBER OF BYTES BETWEEN RECDNOB AND ; RECDNOE ; RESTSN: DB 0,0,0,0,0,0 DW DBUF DB 0,0,0,0,0 ; RECDNOB EQU $ ;START OF TABLE MARKER RCVRNO: DB 0 ;\ RECDNO: DB 0,0 ; \ ERRCT: DB 0 ; \ ERRCDE: DB 0 ; \ EOFLG: DB 0 ; \ 13 BYTES BETWEEN TABLE MARKERS RECPTR: DW DBUF ; / RECINBF: DB 0 ; / MAXEXT: DB 0 ; / RCNT: DB 0,0 ; / DATAFLG: DB 0 ;/ RECDNOE EQU $ ;END OF TABLE MARKER ; CRCVAL: DW 0 DIALCT: DW 0 HLSAVE: DW BOTTRAM HLSAVE1: DW BOTTRAM HLSAVE2: DW BOTTRAM ; ABORTFLG: DB 0 CRCFLAG: DB TRUE CRFLAG: DB 0 ;CONTINUOUS REDIAL FLAG DLYFLG: DB 0 ECHOFLG: DB FALSE EXACFLG: DB 0 EXITFLG: DB TRUE FIRSTME: DB TRUE ;FIRST SOH RECEIVED SET FLAG TO ZERO FSTFLG: DB TRUE LASTBYT1: DB 0 LASTBYT2: DB 0 LISTFLG: DB FALSE LISTMOR: DB FALSE LOCFLG: DB FALSE MFFLG1: DB 0 ;1ST TIME SWITCH MODCTLB: DB 07FH NFILFLG: DB FALSE ;ALLOWS WRITE TO MEMORY IN TERMINAL MODE NSEEFLG: DB TRUE ;FALSE TO SEE FILE NAME IN QUIET MODE ONERR: DB 0 OPTION: DB 0 RINGBKFL: DB 0 SAVEFLG: DB FALSE UARTCTLB: DB ORIGMOD ;FOR ORIGINATE MODE UARTFLG: DB FALSE ;FOR ORIGINATE MODE CMDBUF: DB 80H,0 ;COMMAND BUFFER, TWO PAGES PLUS ONE BYTE ; DS 80H BGNMS: DS 2 DISKNO: DS 1 DISKSAV: DS 1 FILECT: DS 1 FTYCNT: DS 1 NAMECT: DS 1 NBSAVE: DS 2 OLDUSER: DS 1 ORIGSAV: DS 1 SENDFLG: DS 1 SAVUSR: DS 1 DS 100 ;STACK DEPTH STACK: DS 0 ; FCB3: DS 33 FCB4: DS 33 FCBBUF: DS 15 MFNAME5: DS 12 ;REQUESTED NAME MFNAME6: DS 12 ;CURRENT NAME DBUF EQU $ NAMEBUF EQU DBUF+(DBUFSIZ*1024) ;BUFFER FOR NAMES IN BATCH MODE. ;..... ; ; ; BDOS EQUATES ; RDCON: EQU 1 WRCON: EQU 2 LSTOUT: EQU 5 PRINT: EQU 9 RDBUF: EQU 10 CONST: EQU 11 CPMVER: EQU 12 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 SETDMA: EQU 26 DSKALL: EQU 27 DSKPAR: EQU 31 USER: EQU 32 FILSIZ: EQU 35 BDOS: EQU 0005H REIPL: EQU 0 FCB: EQU 5CH FCBEXT: EQU FCB+12 FCBSNO: EQU FCB+32 FCBRNO: EQU FCB+32 FCB2: EQU 6CH ; LAST END 100H