;MODEM.ASM V2.21, ORIGINALLY BY WARD CHRISTENSEN ; This version will assemble directly for an Intel MDS Series II ; ; (REVISED 04/19/82) ; ;CP/M - CP/M FILE TRANSFER PROGRAM, AND TERMINAL PROGRAM. ; ; ;--PRESENT CONFIGURATION-- ;THIS FILE WILL ASSEMBLE WITHOUT EDITING FOR THE FOLLOWING: ; ; A 2 MHz clock ; External modem ; Ported I/O ; Standart CP/M ; Retry 10 times on block transfer error ; 5 drives (A-E) <-- see MAXDRV equate ; 16K disk buffer size ; Send stop 4 characters early for ascii capture ; Don't go to terminal mode before a file transfer. ; ;--> IF YOU CHANGE ANY CONDITIONALS ; PLEASE CHANGE THESE COMMENTS, TOO. ; ;--> SEE EQUATES FOR OTHER MODEMS & ADDITIONAL OPTIONS. ; ;* * * * * * * * * * * * * * * * * * * * * * * * * ;* * ;* THIS PROGRAM DOCUMENTED IN "MODEM.DOC" * ;* * ;* * * * * * * * * * * * * * * * * * * * * * * * * ;* THIS PROGRAM WAS "MODEM.ASM" BUT IS * ;* TEMPORARILY NAMED "MODEM2XX.ASM" SO PEOPLE * ;* WILL REALIZE IT IS AN ENHANCEMENT OF THE * ;* ORIGINAL PROGRAM "MODEM.ASM" ON CP/M USER'S * ;* GROUP DISK 25. * ;* * * * * * * * * * * * * * * * * * * * * * * * * ; ;MODIFICATIONS/FIXES: ;(IN REVERSE ORDER TO MINIMIZE READING TIME) ; (4/19/82) ; Added a section of code to reset the receiving ; device (usart, etc) on detection of an error ; (framing, parity, or overrun). The routine used ; is called RESRCVR ("reset receiver") and has ; conditional assemblies for the different types ; of devices. I have an i8251 usart and have ; implemented the particular code for that device, ; but since I no very little about the other ; commonly used devices, you will have to insert ; code for your device. ; This code was necessary for me since when toggling ; between terminal mode and send/receive mode it ; is very likely that the usart will detect an ; overrun error and since until now there was no ; reset to the usart, the one overrun would be ; detected as many times as the program "retried" ; the transfer and would always terminate. ; Again, remember to add your code if you don't ; have an i8251 usart. Put it in a conditional in ; the routine RESRCVR and put the reset code in ; the symbol RSTCODE. ; Dave Mabry ; ; 04/14/82 ;SET DMA TO DEFAULT BUFFER IN CNREC TO CALC PROG ;SIZE CORRECTLY AFTER ASCII CAPTURE AND BEFORE ;FILE XFER. LEAVE ROOM FOR CCP BEYOND ASCBUF BY ;FIXING MEMEND. SEPARATE EQUATES FOR X6850 AND X8251 ;FOR BASE I/O ADDRESS TO ALLOW BOTH IN FILE AT ;ONCE FOR MULTIPLE LOCAL MACHINES. MAKE FILE XFERS ;BUFFER SIZE ALTERABLE WITH DBUFSIZ EQUATE. CHECK ;FOR FILE ALREADY EXISTS ON ASCII CAPTURE THEN ;VERIFY BEFORE DELETING IT. PRINT OUT SECTOR #'S ;IN DECIMAL AND HEX ON SEND OR RECEIVE. ADJUST ;SEND AND RECEIVE MSG ALGORITHMS TO LEAVE CURSOR ;AT END OF MSG, NOT FRONT. ALL THE ABOVE CHANGES ;MADE BY ADAPTING THE SAME CODE FROM MODEM7X WHEN ;POSSIBLE TO FACILITATE FUTURE MAINTENANCE. ; ; THERE IS A TIMEOUT PROBLEM WITH CRC RECEIVE ;WHEN THE SENDING PROGRAM HAS A LARGE BUFFER, ;LIKE 16K. THE PROBLEM IS THAT THE RECEIVING ;PROGRAM SENDS THE INITIAL "C" INSTEAD OF NAK, ;THEN THE SENDING PROGRAM GOES INTO CRC MODE ;AND GOES OFF TO LOAD UP THE 1ST BUFFER OF FILE. ;IF THE SENDING PROGRAM TAKES MORE THAN THE ;COMMON TIMEOUT OF 3 SECONDS TO LOAD UP BEFORE ;SENDING THE 1ST SECTOR, THEN THE RECEIVING ;PROGRAM MAY DECIDE TO SWITCH TO CHECKSUM MODE, ;AND EXPECT A CHECKSUM AFTER THE 1ST SECTOR. ;THE SENDING PROGRAM SENDS A CRC INSTEAD, WHICH ;LOOKS LIKE A BAD CHECKSUM, SO THE RECEIVING ;PROGRAM NAK'S IT. THIS GOES ON UNTIL BOTH ;REACH THEIR ERROR LIMITS, THEN GIVE UP. WHY ;HASN'T THIS PROBLEM SHOWN UP BEFORE? THE COMMON ;XMODEM PROGRAM V4.7 AND UP HAS A 10 SEC TIMEOUT ;ON THE RESPONSE TO THE 1ST "C", NOT 3 SEC, ;WHICH SHOULD BE LONG ENUFF FOR 16K TO LOAD. ;FURTHUR, XMODEM AND MODEM2XX PROGRAMS TRADITIONALLY ;ONLY LOADED 2K BUFFERS, WHICH LOAD UP IN UNDER ;3 SECS. THE ONLY COMMON CASE WOULD BE TRANSFERRING ;A FILE OF 16K OR MORE BETWEEN TWO MODEM7X PROGRAMS, ;WITH CRC, WHERE THE RECEIVER HAD 3 SEC TIMEOUT. ;NOTE THAT IF CRC IS NOT SPECIFIED, THERE IS NO ;PROBLEM. MY VOTE IS TO LENGTHEN THE TIMEOUT ;EVERYWHERE TO 7 SEC OR SO, TO GIVE THE SENDER ;PLENTY OF TIME, BECAUSE THE 16K IS MUCH EASIER ;ON THE DISK, AND A SHADE FASTER TOO. SO THAT HAS ;BEEN DONE HERE. IF YOU GET BIT BY THIS, CHANGE ;DBUFSIZ TO 2K, AND THE 3 SEC LIMITATION SHOULD ;THEN SUFFICE. IF YOU CONTROL BOTH POINTS, WHICH ;SHOULD BE THE ONLY TIME TWO MODEMXX PROGRAMS ;TALK TO EACH OTHER, FIX BOTH ENDS. I REPEAT, ;THERE IS NO PROBLEM TALKING TO XMODEM. ; ; SINCE ASCII CAPTURE IS NOT IN EFFECT WHEN XFER ;IS GOING ON, EQUATE DBUF AND ASCBUF AT END OF ;PROGRAM. DID NOT CHANGE ASCBUF IN CASE FUTURE ;ENTERPRISING INDIVIDUALS CARE TO PRESERVE ASCII ;CAPTURE STATE OVER AN XFER. -- Steve Bogolub ; ; 3/31/82 ;Added code to convert lower case to upper case and ;trap any illegal characters in filename given for ;ASCII capture. Added MAXDRV equate so that a non- ;valid drive will be trapped here, rather that bomb ;out of modem program with a BDOS error. Added code ;to force ASCII capture file closed if it is open ;when terminal mode is exited, or disconnect command ;is given. Added several new messages. ; James Underwood (N6CFI) ; ; 3/28/82 ;Removed a call to PRINTER in the terminal mode that ;caused double printing of locally typed characters because ;they were printed when sent, and when echoed by the ;remote system. Also changed all occurances of 'H89' in IF ;statements to 'X8250' so that external 8250 chips are ;properly supported. Added a place for modem base port ;equate when X8250 and NOT H89 to eliminate an undefined ;symbol error. Fixed TRS and PMMI equates to eliminate ;doubly defined symbol errors. Cleaned up file and ;greatly simplified TRS and H89 sections. ; James Underwood (N6CFI) ; ; 2/21/82 ;Cleaned up file, corrected HELP menu, changed ;settings for more "standard" machine, set error ;retries back to 10, made all lines 80 chars or less, ;added check for null filename in capture routines, and ;since the program already suffers from the most advanced ;case of RAMPANT FEATUREITIS known, added VIDEO mode for ;for use on VIDEO terminals. (Error msgs will be printed ;on separate lines, but successful "awaiting" or "sending" ;messages will overprint.) The spooling function still doesn't ;work the way I think it should, but it does work the way the ;original author intended it to (I think). ; (Dave Hardy) ; ; 1/31/82 ;Implemented ascii capture feature and hardcopy ;option similar to that found in CCP. Added code ;for Heath H89/Zenith Z89 and for the 8250 ACE. ; (Mark McGee) ; ; 10/22/81 ;Changed PMMI port equates to be relative to the ;first port equ, thus to change PMMI port values ;one only has to change one address. Removed the ;PMMI from the IF for INITREQ since PMMI does not ;require port initialization and in fact if it is ;initialized with INITREQ, the line will be lost. ;Changed receive sector routine so that on the ;first time thru when CRC is being used, it only ;waits for 3 seconds to receive the SOH after ;sending the initial 'C'. If a character is not ;received in 3 seconds, then a NAK is sent and this ;program switches to checksum mode. This allows ;the CRC MODEM to be used with versions of XMODEM ;that do not support CRC, even when MODEM has ;specified a CRC transmission. The transmission ;will then take place using checksum instead of ;CRC. ; Changed the default baud rate for the PMMI ;to an equate. By changing the 'DEFBAUD EQU', the ;default baud rate for the PMMI can set to any rate. ;Grouped all of the EQU's for the PMMI under one 'IF' ;statement for ease of maintenance and documentation ;purposes. ; Added equate(TERMNL EQU) to give one the option ;of whether or not to go to terminal mode before a ;file transfer. ; (John Mahr) ; ; 10/19/81 ;FIXED 'SEND #' AND 'AWAITING #' STATEMENTS TO ;PROPERLY DISPLAY THE CURRENT SECTOR # BEING SENT OR ;RECEIVED. FIXED SEND MSG TO DISPLAY PROPER NUMBER ;OF RECORDS IN THE FILE TO BE SENT (FILES LARGER THAN ;1 EXTENT) USING THE SAME ROUTINES FOUND IN XMODEM43. ;IF NO OPTIONS SELECTED ON INITIAL ENTRY, JUMP TO ;'BADOPT' WITHOUT INITIALIZING MODEM. FIXED THE EQUATES ;FOR THE DCH ERROR MASKS FOR PARITY, OVERRUN & FRAMING. ;MADE A SEPARATE CONDITIONAL ASSEMBLY FOR DCH & X6850 ;UART EQUATES (JUST IN CASE THE X6850 INFO WAS CORRECT) ;AND ELIMINATED THE DCH "INITC1" THRU "INITC4" EQUATES ;SINCE THEY ARE NOT USED BY DCH DURING THE "INITMD" ;CONDITIONAL ASSEMBLY. (BILL ATEN) ; ; 10/12/81 ;ADDED CYCLIC REDUNDANCY CHECK OPTION ON THE FILE ;RECEIVE OPTION. THIS IN ANOTHER SECONDARY OPTION ;THAT IS SPECIFIED BY SPECIFYING A 'C'. ; MODEM RC.600 fn.ft ; MODEM ROC.300 fn.ft, etc. ; NOTE: CANNOT HAVE MORE THAN 6 SEC OPTIONS. ;WHEN THE FILE RECEIVE SPECIFIES CRC, THE LETTER 'C' IS ;SENT IN PLACE OF THE INITIAL NAK. THIS SIGNALS THE SENDER ;(XMODEM45+ or MODEM213+) THAT CRC IS IN EFFECT. THE SENDING ;PROGRAM WILL AUTOMATICALLY SWITCH TO CRC MODE. THE CRC ;WILL REPLACE THE CHECKSUM METHOD OF CHECKING FOR DATA ;INTEGRITY ON FILE TRANSMISSIONS. CRC WILL GIVE BETTER ;THAN A 99.99% PROBABILITY THAT THERE ARE NO DATA INTEGRITY ;ERRORS. ACKNOWLEDGEMENT AND THANKS TO PAUL HANSKNECHT ;WHO DESIGNED AND WROTE CRC120. IT IS THE CRC120 MACRO ;THAT WAS USED TO IMPLEMENT CRC IN THIS PROGRAM. ; (JOHN MAHR) ; ; 10/08/81 ;ADDED TRS80 MODEL I SUPPORT INCLUDING BAUD RATE ;SELECT FROM COMMAND LINE. (MARK C WEHMHOEFER) ; ; 10/02/81 ;FIXED RCVFILE BUG IN 10/1 VERSION. REVISED MOST ;MESSAGES TO UPPER & LOWER CASE. CHANGED RCVFILE SO ;IT SENDS THE INITIAL NAK AS SOON AS THE FILE IS OPEN, ;WITHOUT WAITING FOR A TIMEOUT FIRST. (DHH) ; *NOTE: A FILE TRANSFER WILL FAIL IF THE SEND ; END IS NOT STARTED BEFORE THE RECEIVE ; END WHEN THERE IS NO WAIT BEFORE ; SENDING THE INITIAL NAK OR CRC ; REQUEST. (10/12/81, JRM) ; ; 10/02/81 ;FIXED DUPLICATE EQUATE FOR BASE ADDRESS, REMOVED UNUSED ;EQUATE FOR H8CPM. (KBP) ; ; 10/01/81 ;ADDED ERROR MASKS FOR HAYES MICROMODEM & 6850 ACIA. ;ADDED "X6850" CONDITIONAL. ADDED "PORTED" CONDITIONAL ;TO ALLOW USE ON MEMORY-MAPPED SYSTEMS SUCH AS THE ;APPLE II. COLLECTED MODEM PRIMITIVE OPERATIONS TO ;FRONT OF PROGRAM. MADE RCV ERROR CHECKING ACTIVE FOR ;ALL MODEMS. (DAV HOLLE) ; ; 9/11/81 ;FIXED BUG IN 6/2 MOD. ADDED BELL TO CERTAIN ERROR MSGS. ;ADDED R & S OPTIONS MSGS. CHANGED MULTI TO X8251 ;CONDITIONAL & MOVED WITH MODEM TYPES. CHANGED SIGNON ;VERSION MESSAGE. (TED SHAPIN) ; ; 06/02/81 ;ADDED BELL WHEN TRANSFER IS FINISHED. SHORTENED LABELS ;TO 6 CHARS SO OTHER ASSEMBLERS WILL WORK. ;ADDED CALL TO 'TERM' FROM BOTH SEND AND RECEIVE. THIS ;LETS YOU CONTROL THE REMOTE SYSTEM BEFORE TRANSMISSION. ;AFTER YOU LOG ON, ETC., AND TYPE "XMODEM R FOO.ASM" ;OR WHATEVER. YOU CAN THEN TYPE CONTROL-E TO PUT THIS PROGRAM ;INTO SEND OR RECEIVE MODE. (TED SHAPIN, ORANGE, CA.) ; ; 05/07/81 ;ADDED TRAPS FOR AMBIGUOUS FILE NAME OR NONE AT ALL. ;REARRANGED EQUATES FOR GREATER CLARITY. CLEANED UP ;FILE. (KBP) ; ; 05/02/81 ;ADDED THE ABILITY TO DISPLAY MODEM STATUS ON A ;FRONT PANEL, IF ONE HAS ONE (SUCH AS AN ITHACA ;INTERSYSTEMS DPS-1). ; 1. FRNTPNL EQU TRUE TURNS IT ON ; 2. PANEL EQU 0FFH (SETS UP PORT ADDRESS ; OF FRONT PANEL) (JOHN MAHR) ; ; 05/01/81 ;RESTORED HELP DISPLAY. LOWER CASG CHARS AND TABS ;HAD BEEN TAKEN OUT. ADDED TYPICAL EXTERNAL PORT ;EQUATES AND INIT VALUES. REARRANGED ORDER OF ;MODIFICATION/FIXES INFO. (KBP) ; ; 04/18/81 ;ADDED DETECTION OF FRAMING ERRORS, OVERRUN ERRORS, ;PARITY ERRORS (IF PARITY IS USED) FOR THE RECEIVE ;FILE ROUTINE. THIS FEATURE IS ONLY ACTIVE FOR ;THE PMMI MODEM, SINCE I DO NOT KNOW WHAT THE MODEM ;STATUS BITS ARE FOR IDS AND D.C. HAYES MODEMS. ;IF THERE IS ONE OF THE MENTIONED ERRORS, THE LINE ;WILL BE PURGED FOR THAT BLOCK AND A NAK WILL BE ;SENT TO THE SENDER FOR THAT BLOCK. A MESSAGE TO ;OPERATOR WILL ALSO BE DISPLAYED. (BY JOHN MAHR) ; ; 05/27/80 ;ELIMINATED CONTROL-X CANCEL OF SEND FEATURE, AT ;SUGGESTION OF WARD CHRISTENSEN. A LINE GLITCH COULD ;CAUSE PREMATURE ABORT WHEN THIS FEATURE WAS ACTIVE. ;ADDED EQUATES FOR FALSE AND TRUE TO MAKE ASSEMBLY ;OPTIONS CLEARER. REMOVED H8 PORT EQUATES (THEY CAN ;BE PUT IN EXTERNAL MODEM EQUATES). (KBP) ; ; 12/06/79 ;CORRECTED ERROR IN HELP FILE. SAID T.110, NOW SAYS ;TO.110. BY WARD CHRISTENSEN. CORRECTED RECEIVE FILE ;ROUTINE SO TERMINAL OR ECHO MODE WORKS AFTER FILE ;TRANSFER IN QUIET MODE. MOVED CHECKS FOR "H" AND ;"X" OPTIONS SO MODEM IS NOT REINITIALIZED. (KBP) ; ; 08/06/79 ;ADDED EQUATES FOR EXTERNAL MODEM (NOT S-100 PLUG-IN) ;(KBP) ; ; 08/05/79 ;ADDED D.C. HAYES MODEM SUPPORT BY JIM BELL (KBP) ; ; 07/24/79 ;MOVE INITIALIZE LOCAL STACK TO BEGINNING OF PROGRAM ;SO DEFAULT STACK IS NOT USED. ADD CONDITIONAL ASSEMBLY ;OPTION TO TERMINAL ROUTINE FOR TIMESHARE SYSTEMS. ;CORRECT ERROR IN LOCAL ABORT ROUTINE (WAS LOOKING FOR ;CONTROL-E - NOW CORRECTLY LOOKS FOR CONTROL-X). ADD ;REGISTER SAVES TO CONOUT, KEYIN AND KEYBOARD STATUS ;ROUTINES, AS SOME CBIOS ROUTINES CLOBBER THEM. (KBP) ; ; 07/01/79 ;MODIFIED PROGRAM TO ALLOW FOR NON-STANDARD VERSIONS OF ;CP/M. ALL REFERENCES TO ENTRIES INTO CP/M SHOULD BE MADE ;RELATIVE TO THE VARIABLE SYMBOL CALLED "BASE". FOR EXAMPLE, ;THE EQUATE TO BDOS SHOULD BE BASE+5 INSTEAD OF 5. BASE ;WILL BE SET TO 0 WHEN THE VARIABLE STDCPM IS SET TO TRUE. ;(BOB MATHIAS). ; ; 05/24/79 ;FIXED MISSING RETURN INSTRUCTION AT END OF ;INITIALIZATION ROUTINE. (KBP) ; ; 05/22/79 ;ADDED FEATURE TO MAKE RECEIVE FILE ROUTINE SAY ;FILE SUCCESSFULLY OPENED, WHEN IN QUIET MODE. ;MOVED INITIAL 'GOBBLE GARBAGE INPUTS' TO BEFORE ;COMMAND CPI'S SO ALL MODES ARE CLEARED. CHANGED ;INITIAL SEND WAIT TO 80 SECS TO ALLOW MORE TIME ;FOR RECEIVING END TO COME UP. ADDED 'H' AFTER MSG ;THAT SHOWS NUMBER OF SECTORS IN EXTENT ABOUT TO ;BE SENT. (KBP) ; ; 05/09/79 ;ALLOW 'T' AND 'E' SUB-OPTIONS TO GO TO TERMINAL ;OR ECHO MODE AFTER TRANSFERRING A FILE. (WLC) ; ; 04/26/79 ;REWRITTEN BY WARD CHRISTENSEN TO COMBINE ;IMPROVEMENTS TO THE ORIGINAL MADE BY WARD ;AND BY KEITH PETERSEN, W8SDZ, AND SUGGESTIONS ;BY JIM BELL WHICH KEITH IMPLEMENTED. SEE ;MODEM.DOC FOR ADDITIONAL HISTORICAL ;INFORMATION AND DOCUMENTATION. ; ; 09/23/77 ;ORIGINALLY WRITTEN BY WARD CHRISTENSEN ; ; -------------- ; ;NOTE: IF YOU ADD IMPROVEMENTS OR OTHERWISE UPDATE ;THIS PROGRAM, PLEASE MODEM A COPY OF THE NEW FILE ;TO "TECHNICAL CBBS" IN DEARBORN, MICHIGAN - PHONE ;313-846-6127 (110, 300, 450 OR 600 BAUD). USE THE ;FILENAME MODEM.NEW. (KBP) ; ; -------------- ; DEFINE EQUATES ; FALSE EQU 0 TRUE EQU NOT FALSE ; STDCPM EQU TRUE ;TRUE, IS STANDARD CP/M ALTCPM EQU FALSE ;TRUE, IS ALTERNATE CP/M FOR H8 OR TRS80 DBUFSIZ EQU 16 ;BUFFER SIZE IN KBYTES ; ; DEFINE TYPE OF CP/M IN USE ; IF STDCPM BASE EQU 0 ;CP/M BASE ADDRESS ENDIF ; IF ALTCPM BASE EQU 4200H ;CP/M BASE ADDRESS FOR ALTERNATE CP/M ENDIF ; ; DEFINE MODEM INTERFACE ; DCH EQU FALSE ;TRUE, IS D.C. HAYES MODEM PMMI EQU FALSE ;TRUE, IS PMMI MODEM H89 EQU FALSE ;TRUE, IS HEATH H89 ;BE SURE X8250 IS ALSO TRUE TRS EQU FALSE ;TRUE FOR TRS80 MODEL I ;BE SURE X8251 IS ALSO TRUE ; X8250 EQU FALSE ;TRUE, IS EXTERNAL 8250 ACE X8251 EQU TRUE ;TRUE, IS EXTERNAL 8251 USART X6850 EQU FALSE ;TRUE, IS EXTERNAL 6850 ACIA ; PORTED EQU TRUE ;TRUE FOR IN/OUT PORTS, FALSE FOR LDA/STA INITREQ EQU TRUE ;TRUE IF PORT MODEM CONNECTED TO... ; ...REQUIRES INITIALIZATION. MAXDRV EQU 'E' ;MAX DRIVE ON SYSTEM ; ; DEFINE OTHER SYSTEM PARAMETERS ; FASTCLK EQU FALSE ;TRUE FOR 4 MHZ CLOCK, FALSE FOR 2 MHZ FRNTPNL EQU FALSE ;TRUE FOR FRONT PANEL DISPLAY VIDEO EQU FALSE ;TRUE FOR USE WITH VIDEO TERMINAL TERMNL EQU FALSE ;TRUE, GO TO TERMINAL MODE BEFORE.. ; ...FILE TRANSFER. ; IF FRNTPNL PANEL EQU 0FFH ;PORT ADDRESS FOR FRONT PANEL ENDIF ; ; SOME TIME-SHARE COMPUTERS REQUIRE TERMINALS TO ; HAVE BIT 7 HIGH (MARKING), SO IN THE TERMINAL ; MODE WE FORCE IT TO HIGH IF THE FOLLOWING OPTION ; IS SELECTED: ; TIMESHR EQU FALSE ;TRUE TO MAKE BIT 7 HIGH ;***************************************************************************** IF PMMI ; SET DCH=FALSE,H89=FALSE,PMMI=TRUE,X8250=FALSE,X8251=FALSE, ; X6850=FALSE,PORTED=TRUE,INITREQ=FALSE ; ; THESE EQUATES SET ALL OF THE VALUES NECESSARY TO USE A PMMI. ; THE ONLY ONE THAT SHOULD EVER HAVE TO BE CHANGED IS MDCTLP ; WHICH IS THE ADDRESS OF THE FIRST PORT ON THE PMMI. THIS ; ADDRESS IS SET BY SWITCHES ON THE PMMI CARD. ; MDCTLP EQU 0E0H ;PMMI VALUES (BASE ADDR OF I/O PORTS) MDDATP EQU MDCTLP+1 ;DATA PORT BAUDRP EQU MDCTLP+2 ;BAUD RATE OUTPUT MDCTL2 EQU MDCTLP+3 ;SECOND CTL PORT ORIGMD EQU 1DH ;8 DATA, NO PARITY, ORIG ANSWMD EQU 1EH ;8 DATA, NO PARITY, ANSW ; FRMER EQU 20H ;FRAMING ERROR MASK ORUNER EQU 10H ;OVERRUN ERROR MASK PARER EQU 08H ;PARITY ERROR MASK ; MDSNDB EQU 1 ;BIT TO TEST FOR SEND MDSNDR EQU 1 ;VALUE WHEN READY MDRCVB EQU 2 ;BIT TO TEST FOR RECEIVE MDRCVR EQU 2 ;VALUE WHEN READY ; DEFBAUD EQU 52 ;DEFAULT TO 300 BAUD ;USE 52 FOR 300 BAUD ;USE 26 FOR 600 BAUD ;USE 104 FOR 150 BAUD ;USE 142 FOR 110 BAUD ENDIF ;PMMI ;***************************************************************************** IF DCH MDCTLP EQU 82H ;D. C. HAYES VALUES MDDATP EQU 80H ;DATA PORT MDCTL2 EQU 81H ;SECOND CTL PORT ; ; NOTE: BAUD RATE DEFAULTS TO 300 - 1 STOP BIT. ; DO NOT CHANGE NEXT EQUATES: ; ORIGMD EQU 86H ;OFF HOOK, 110 BAUD, CAR. ON, ORIG. ANSWMD EQU 82H ;OFF HOOK, 110 BAUD, CAR. ON, ANSW. ENDIF ;DCH ;***************************************************************************** ; ; FOR APPLE CARDS: PORTED=FALSE AND X6850=TRUE, AND ; MDDATP IS 1 MORE THAN MDCTLP. FOR SSM AIO, APPLE COM ; CARD, OR CCS 7710 USE MDCTLP=0E0ACH (FOR SLOT 2), OR ; USE 0E0AEH FOR MICROMODEM II. FOR DIFFERENT SLOTS, ; ADD (SLOT-2)*10H TO THE ABOVE ADDRESSES. ; ;-->IF USING EXTERNAL MODEM WITH 8250, 8251 OR 6850 ;-->CHIP, CHANGE THESE EQUATES TO YOUR SYSTEM REQUIREMENTS ; IF X6850 MDCTLP EQU 0E0AEH ;MODEM CONTROL PORT MDDATP EQU MDCTLP+1 ;MODEM DATA PORT ENDIF ;X6850 ; IF X8251 MDCTLP EQU 0F7H ;MODEM CONTROL PORT MDDATP EQU MDCTLP-1 ;MODEM DATA PORT ENDIF ;X8251 ; IF X8250 AND NOT H89 MDDATP EQU 60H ;YOUR MODEM DATA PORT ENDIF ;X8250 AND NOT H89 ; ;-->END OF EXTERNAL MODEM BASE EQUATES ; ;***************************************************************************** IF H89 ;FOR H89 SET THESE TRUE, ALL OTHERS FALSE: ; H89,X8250,PORTED,STDCPM ; MDDATP EQU 0D8H ;HEATH MODEM PORT BASE ADDRESS ENDIF ;H89 ;***************************************************************************** IF TRS ;FOR TRS SET THESE TRUE, ALL OTHERS FALSE: ; TRS,X8251,PORTED,ALTCPM ; MDCTLP EQU 0EAH ;TRS-80 WITH RS232 VALUES MDDATP EQU 0EBH ;DATA PORT ENDIF ;H89 ;***************************************************************************** IF X8250 MDCTL1 EQU MDDATP+1 ;INTERRUPT CONTROL MDCTL3 EQU MDDATP+3 ;WORD CHARACTERISTICS MDCTL4 EQU MDDATP+4 ;LINE CONTROL MDCTL5 EQU MDDATP+5 ;LINE STATUS ENDIF ;X8250 ;***************************************************************************** ; ; THESE EQUATES SPECIFY THE INITIALIZATION SEQUENCE ; AND STATUS FLAGS USED BY YOUR TYPE OF MODEM. ; ; IF X8251 INITC1 EQU 00H ;1ST INIT CHAR TO 8251 CTL PORT INITC2 EQU 00H ;2ND INITC3 EQU 00H ;3RD INITC4 EQU 37H ;4TH ; RSTCODE EQU 37H ; Reset error, set DTR, ; enable receiver and ; transmitter ; FRMER EQU 20H ;FRAMING ERR MASK ORUNER EQU 10H ;OVERRUN ERR MASK PARER EQU 08H ;PARITY ERR MASK ; MDSNDB EQU 1 ;BIT TO TEST FOR SEND MDSNDR EQU 1 ;VALUE WHEN READY MDRCVB EQU 2 ;BIT TO TEST FOR RECEIVE MDRCVR EQU 2 ;VALUE WHEN READY ENDIF ;X8251 ;***************************************************************************** IF X8250 INITC1 EQU 83H ;ACCESS DIVISOR LATCHES INITC2 EQU 03H ;SET DTR AND RTS INITC3 EQU 80H ;LOW BAUD DIVISOR (300 BAUD) INITC4 EQU 01H ;HIGH BAUD DIVISOR (300 BAUD) INITC5 EQU 03H ;8 BITS,1 STOP, NO PARITY INITC6 EQU 00H ;DISABLE ALL INTERRUPTS ; FRMER EQU 08H ;FRAMING ERR MASK ORUNER EQU 02H ;OVERRUN ERR MASK PARER EQU 04H ;PARITY ERR MASK ; MDSNDB EQU 20H ;BIT TO TEST FOR SEND MDSNDR EQU 20H ;VALUE WHEN READY MDRCVB EQU 01H ;BIT TO TEST FOR RECEIVE MDRCVR EQU 01H ;VALUE WHEN READY ENDIF ;X8250 ****************************************************************************** IF DCH PARER EQU 04H ;PARITY ERR MASK FRMER EQU 08H ;FRAMING ERR MASK ORUNER EQU 10H ;OVERRUN ERR MASK ; MDSNDB EQU 2 ;BIT TO TEST FOR SEND MDSNDR EQU 2 ;VALUE WHEN READY MDRCVB EQU 1 ;BIT TO TEST FOR RECEIVE MDRCVR EQU 1 ;VALUE WHEN READY ENDIF ;DCH ;***************************************************************************** IF X6850 INITC1 EQU 3 ;1ST INIT CHAR TO 6850 CTL PORT INITC2 EQU 15H ;2ND, 8 DATA + 1 STOP + NO PARITY, ; 16X CLOCK. USE 16H FOR SAME WITH 64X ; CLOCK TO SWITCH FROM 1200 TO 300 BAUD, ; FOR EXAMPLE. INITC3 EQU INITC1 ;3RD (ONLY 2 NEEDED, REUSE 1 & 2) INITC4 EQU INITC2 ;4TH ; FRMER EQU 10H ;FRAMING ERR MASK ORUNER EQU 20H ;OVERRUN ERR MASK PARER EQU 40H ;PARITY ERR MASK ; MDSNDB EQU 2 ;BIT TO TEST FOR SEND MDSNDR EQU 2 ;VALUE WHEN READY MDRCVB EQU 1 ;BIT TO TEST FOR RECEIVE MDRCVR EQU 1 ;VALUE WHEN READY ENDIF ;X6850 ;***************************************************************************** ; ; DEFINE SOME OTHER THINGS (NORMALLY NOT CHANGED) ; ERRLIM EQU 10 ;MAX ALLOWABLE ERRORS (10 STANDARD) STPTIME EQU 4 ;SEND STOP THIS MANY CHARS EARLY CPTRKEY EQU 'Y'-40H ;CTL-Y TOGGLES ASCII CAPTURE MODE DISCCHR EQU 'D'-40H ;CTL-D DISCONNECTS MODEM T/E EXITCHR EQU 'E'-40H ;CTL-E EXIT FROM T OR E PRTCHAR EQU 'P'-40H ;CTL-P TOGGLES PRINTER OPTION STRTCHR EQU 'Q'-40H ;CTL-Q TO MAKE OTHER END RESUME (MOST SYSTEMS ;WILL ACCEPT ANY CHAR,SO CTL-Q IS TO INCLUDE ;THE XON/XOFF PROTOCALL) STOPCHR EQU 'S'-40H ;CTL-S TO MAKE OTHER END PAUSE ; ; DEFINE ASCII CHARACTERS USED ; SOH EQU 1 ;START OF HEADER EOT EQU 4 ;END OF TRANSMISSION ACK EQU 6 ;ACKNOWLEDGE NAK EQU 15H ;NEG ACKNOWLEDGE CRC EQU 'C' ;USED TO REQUEST CRC INSTEAD OF CHECKSUM CAN EQU 18H ;CANCEL LF EQU 10 ;LINEFEED CR EQU 13 ;CARRIAGE RETURN BELL EQU 'G'-40H ;BELLS ;***************************************************************************** ORG BASE+100H ; ;INIT PRIVATE STACK LXI H,0 ;HL=0 DAD SP ;HL=STACK FROM CP/M SHLD STACK ;..SAVE IT LXI SP,STACK ;SP=MY STACK LDA BASE+0007H ;BDOS PAGE ADDRESS SUI 8+1 ;ACCOUNT FOR CCP (2K) + 1 PG SLOP STA MEMEND ; AND SAVE THE RESULT CALL START ;GO PRINT ID DB 'MODEM ver 2.21A of 04/19/82' DB CR,LF,'$' ; ; MODEM I/O PRIMITIVES ; ; COLLECTED HERE FOR EASIER PATCHING & MAINTENANCE. ; PORTED I/O ROUTINES HAVE NOP'S TO LEAVE ROOM ; FOR LATER PATCHING TO LDA'S & STA'S IF NECESSARY. ; IF PORTED AND (NOT X8250) OUTDATA OUT MDDATP RET NOP INDATA IN MDDATP RET NOP OUTCTL OUT MDCTLP RET NOP INCTL IN MDCTLP RET NOP ENDIF ;PORTED AND (NOT X8250) ; IF PORTED AND X8250 OUTDATA OUT MDDATP RET NOP INDATA IN MDDATP RET NOP OUTCTL1 OUT MDCTL1 RET NOP OUTCTL3 OUT MDCTL3 RET NOP OUTCTL4 OUT MDCTL4 RET NOP INCTL5 IN MDCTL5 RET NOP ENDIF ;PORTED AND X8250 ; IF PORTED AND (DCH OR PMMI) OUTCT2 OUT MDCTL2 RET NOP INCT2 IN MDCTL2 RET NOP ENDIF ;PORTED AND (DCH OR PMMI) ; IF PORTED AND PMMI OUTBRP OUT BAUDRP RET NOP ENDIF ;PORTED AND PMMI ; IF PORTED AND FRNTPNL OUTPAN OUT PANEL RET NOP ENDIF ;PORTED AND FRNTPNL ; IF NOT PORTED OUTDATA STA MDDATP RET INDATA LDA MDDATP RET OUTCTL STA MDCTLP RET INCTL LDA MDCTLP RET ENDIF ;NOT PORTED ; IF (NOT PORTED) AND (DCH OR PMMI) OUTCT2 STA MDCTL2 RET INCT2 LDA MDCTL2 RET ENDIF ;(NOT PORTED) AND (DCH OR PMMI) ; IF PMMI AND NOT PORTED OUTBRP STA BAUDRP RET ENDIF ;PMMI AND NOT PORTED ; IF FRNTPNL AND NOT PORTED OUTPAN STA PANEL RET ENDIF ;FRNTPNL AND NOT PORTED ; START POP D ;GET ID MESSAGE MVI C,PRINT CALL BDOS ;PRINT ID MESSAGE ; ; INITIALIZE THE JMPS TO CP/M BIOS ; CALL INITADR ; LDA FCB+1 ;GET PRIMARY OPTION CPI 'H' ;MODEM H(ELP)? JZ HELP ;..YES, GIVE HELP CPI ' ' ;NO OPTIONS? JZ BADOPT ;..EXPLAIN & GIVE HELP CPI 'X' ;MODEM X(AMPLES)? JZ EXAM ;GIVE EXAMPLES ; ; SAVE PRIMARY OPTION, VALIDATE SECONDARY OPT. ; CALL PROCOPT ; ; INIT THE MODEM OR SERIAL PORT ; CALL INITMD ; ; MOVE THE FILENAME FROM FCB 2 TO FCB 1 ; CALL MOVEFCB ; ; GOBBLE UP GARBAGE CHARS FROM THE LINE ; PRIOR TO RECEIVE OR SEND ; CALL INDATA CALL INDATA ; ; JMP TO APPROPRIATE FUNCTION ; LDA OPTION ;GET PRIMARY OPTION ; CPI 'C' ;(COMPAT W/EARLIER JZ TRMECHO ;OPTION "COMPUTER") ; CPI 'E' ;TERMINAL IN ECHO JZ TRMECHO ;..MODE? ; CPI 'T' ;TERMINAL.. JZ TERM ;..MODE? ; CPI 'D' ;DISCONNECT? JZ DISCONN ; CPI 'S' ;SEND.. IF TERMNL ;GO TO TERMINAL MODE FIRST. JZ TSND ;..A FILE? ENDIF ; IF NOT TERMNL ;GO STRAIGHT TO FILE SEND JZ TERMX ;GO SEND A FILE ENDIF ; CPI 'R' ;RECEIVE.. ; IF TERMNL ;GO TO TERMINAL MODE FIRST JZ TRCV ;..A FILE? ENDIF ; IF NOT TERMNL ;GO STRAIGHT TO FILE RECEIVE JZ TERMX ;RECEIVE A FILE ENDIF ; ;INVALID OPTION ; JMP BADOPT ; TSND: CALL ILPRT DB 'In terminal mode, Ctl-E to start SEND',CR,LF,0 JMP TERM TRCV: CALL ILPRT DB 'In terminal mode, Ctl-E to start RECEIVE',CR,LF,0 ;FALL THRU TO TERM ; ;* * * * * * * * * * * * * * * * * * * * * ;* * ;* TERM: TERMINAL MODE * ;* * ;* * * * * * * * * * * * * * * * * * * * * ; ; THIS PROGRAM SIMPLY SENDS KEYED CHARACTERS ; DOWN THE LINE, AND DISPLAYS CHARACTERS ; RECEIVED FROM THE LINE. THIS MAKES IT ; SUITABLE FOR COMMUNICATION WITH TIME SHARING ; COMPUTERS, CBBS'S, OR ANOTHER PROGRAM ; RUNNING "MODEM E" (ECHO MODE) ; ; TYPE THE "EXITCHR" (ORIGINALLY CTL-E) TO LEAVE TERM MODE, ; OR THE "DISCCHR" (ORIGINALLY CTL-D) TO DISCONNECT. ; ; ASCII CAPTURE IS TOGGLED BY ENTERING CTL-Y, AT WHICH TIME ; THE PROGRAM WILL PROMPT FOR THE DESIRED FILE NAME. THE FILE ; IS CLOSED BY AGAIN ENTERING CTL-Y. ; ; THE PRINTER OPTION WORKS JUST AS IN CCP - ENTER CTL-P TO ; TURN THE PRINTER ON, AND AGAIN TO TURN IT OFF. ; TERM CALL STAT ;LOCAL CHAR KEYED? JZ TERML ;..NO, CHECK LINE CALL KEYIN ;GET CHAR CPI EXITCHR ;TIME TO END? JZ TERMX ;YES, LEAVE TERMINAL MODE CPI DISCCHR ;DISCONNECT REQUEST? JZ DISCONN ;YES, DO IT ; CPI CPTRKEY ;TOGGLE CAPTURE MODE? CZ CPTRTOG ;YES, DO IT JZ TERM01 ;IF CAPTURE MODE COMMAND, DON'T SEND IT CPI PRTCHAR ;TOGGLE PRINTER MODE? CZ PRTRTOG ;YES, DO IT JZ TERM01 ;IF PRINTER TOGGLE, DON'T SEND IT ; IF TIMESHR ORI 80H ;FORCE BIT 7 TO HIGH ENDIF ;TIMESHR ; CALL OUTDATA ;SEND THE CHAR TERM01 EQU $ ; ; SEE IF CHAR FROM LINE ; IF (NOT DCH) AND (NOT X8250) TERML CALL INCTL ;READ STATUS ENDIF ; IF X8250 TERML CALL INCTL5 ;READ STATUS ENDIF ; IF DCH TERML CALL INCT2 ;READ STATUS ENDIF ; IF FRNTPNL AND PMMI CALL OUTPAN ;DISPLAY STATUS ENDIF ; ANI MDRCVB ;ISOLATE BIT CPI MDRCVR ;READY? JNZ TERM ;..NO, LOOP CALL INDATA ;READ DATA ANI 7FH ;STRIP PARITY BIT CALL TYPE ;TYPE IT CALL PRINTER ;SEND TO PRINTER IF ENABLED CALL ASCPTR ;SAVE TO DISK IF ENABLED JMP TERM ;LOOP ; TERMX: LDA CPTRFLG ORA A CNZ CPTRTOG ;IF CAPTURE WAS ON, TURN OFF LDA FIRST ;DON'T JUMP INR A ;TO SEND OR RECEIVE STA FIRST ;MORE THAN ONCE JNZ CKDIS ;CHECK DISCONNECT LDA OPTION ;PRIMARY OPTION CPI 'S' ;SEND? JZ SENDFIL ;..A FILE CPI 'R' ;RECEIVE JZ RCVFIL ;A FILE JMP CKDIS ;REALLY EXIT ; ;* * * * * * * * * * * * * * * * * * * * * ;* * ;* TRMECHO: TERMINAL WITH ECHO * ;* * ;* * * * * * * * * * * * * * * * * * * * * ; ; TERMINAL PROGRAM WITH ECHO - SEE NOTES ; UNDER "TERM" ABOVE ; ; C A U T I O N DON'T RUN WITH BOTH COMPUTERS ; IN "ECHO" MODE - LINE ERRORS (OR ANY CHAR) ; WILL BE ECHOED BACK AND FORTH AD INFINITUM. ; ; ASCII CAPTURE IS TOGGLED BY ENTERING CTL-Y, AT WHICH TIME ; THE PROGRAM WILL PROMPT FOR THE DESIRED FILE NAME. THE FILE ; IS CLOSED BY AGAIN ENTERING CTL-Y. ; ; THE PRINTER OPTION WORKS JUST AS IN CCP - ENTER CTL-P TO ; TURN THE PRINTER ON, AND AGAIN TO TURN IT OFF. ; IF (NOT DCH) AND (NOT X8250) TRMECHO CALL INCTL ;GET STATUS ENDIF ; IF X8250 TRMECHO CALL INCTL5 ;GET STATUS ENDIF ; IF DCH TRMECHO CALL INCT2 ;GET STATUS ENDIF ; IF FRNTPNL AND PMMI OUT PANEL ;DISPLAY STATUS ENDIF ; ANI MDRCVB ;ISOLATE READY BIT CPI MDRCVR ;ARE WE READY? JZ LINECHR ;YES, READ THE CHR CALL STAT ;CHECK LOCAL KB JZ TRMECHO ;..NO CHAR CALL KEYIN ;GET LOCAL CHAR CPI EXITCHR ;END? JZ CKDIS ;YES, CK DISCONN, EXIT CPI DISCCHR ;DISCONN? JZ DISCONN ;..YES, DO IT. CPI CPTRKEY ;TOGGLE CAPTURE MODE? CZ CPTRTOG ;..YES, DO IT JZ TERM02 ;IF CAPTURE MODE COMMAND, DON'T SEND IT CPI PRTCHAR ;TOGGLE PRINTER MODE? CZ PRTRTOG ;..YES, DO IT JZ TERM02 ;IF PRINTER TOGGLE, DON'T SEND IT CALL OUTDATA ;SEND CHAR CALL TYPE ;ECHO IT LOCALLY CALL PRINTER ;SEND TO PRINTER IF ENABLED CALL ASCPTR ;SAVE IT TO DISK IF ENABLED TERM02 JMP TRMECHO ;..AND LOOP ; ; GOT CHAR FROM LINE ; LINECHR CALL INDATA ;GET CHAR ANI 7FH ;STRIP PARITY BIT CALL OUTDATA ;ECHO IT CALL TYPE ;TYPE IT CALL PRINTER ;SEND TO PRINTER IF ENABLED JMP TRMECHO ;LOOP ; ;* * * * * * * * * * * * * * * * * * * * * ;* * ;* SENDFIL: SENDS A CP/M FILE * ;* * ;* * * * * * * * * * * * * * * * * * * * * ; ; THE CP/M FILE SPECIFIED IN THE MODEM COMMAND ; IS TRANSFERRED OVER THE PHONE TO ANOTHER ; COMPUTER RUNNING MODEM WITH THE "R" (RECEIVE) ; OPTION. THE DATA IS SENT ONE SECTOR AT A ; TIME WITH HEADERS AND CHECKSUMS OR CYCLIC ; REDUNDANCY CHECKS. CYCLIC REDUNDANCY CHECK ; IS USED IF THE LETTER 'C' IS RECEIVED IN ; PLACE OF THE INITIAL NAK. IT IS INCORRECT ; TO SPECIFY CRC ON THE SEND (MODEM SC fn.ft), ; SINCE IT IS THE RECEIVER WHO DETERMINES ; WHETHER CRC IS TO BE USED. IF THERE IS AN ; ERROR, THE SECTOR IS RETRANSMITTED. ; SENDFIL CALL TRAP ;CHECK FOR NO NAME OR AMBIG. NAME CALL CNREC ;COMPUTE RECORD COUNT CALL OPENFIL ;OPEN THE FILE MVI E,80 ;WAIT 80 SEC.. CALL WAITNAK ;..FOR INITIAL NAK ; SENDLP CALL RDSECT ;READ A SECTOR JC SENDEOF ;SEND EOF IF DONE CALL INCRSNO ;BUMP SECTOR # XRA A ;ZERO ERROR.. STA ERRCT ;..COUNT ; SENDRPT CALL SENDHDR ;SEND A HEADER CALL SENDSEC ;SEND DATA SECTOR LDA CRCFLG ;GET CRC FLAG ORA A ;CRC IN EFFECT? CZ SENDCRC ;YES, GO SEND CRC CNZ SENDCKS ;NO, SEND CKSUM NOT CRC CALL GETACK ;GET THE ACK JC SENDRPT ;REPEAT IF NO ACK JMP SENDLP ;LOOP UNTIL EOF ; ; FILE SENT, SEND EOT'S ; SENDEOF MVI A,EOT ;SEND.. CALL SEND ;..AN EOT CALL GETACK ;GET THE ACK JC SENDEOF ;LOOP IF NO ACK JMP DONE ;ALL DONE ; ;----> CNREC: Computes record count, and saves it ; until successful file OPEN. ; ; LOOK UP THE FCB IN THE DIRECTORY CNREC: MVI C,STDMA ;SET DMA ADDR TO LXI D,BASE+80H ; DEF BUFFER CALL BDOS ; SO DIR INFO WHERE SHOULD BE MVI A,'?' ;MATCH ALL EXTENTS STA FCBEXT MVI A,0FFH STA MAXEXT ;INIT MAX EXT NO. MVI C,SRCHF ;GET 'SEARCH FIRST' FNC LXI D,FCB CALL BDOS ;READ FIRST INR A ;WERE THERE ANY? JNZ SOME ;GOT SOME CALL ERXIT DB '++File not found++',CR,LF,'$' ; ; READ MORE DIRECTORY ENTRIES MOREDIR MVI C,SRCHN ;SEARCH NEXT LXI D,FCB CALL BDOS ;READ DIR ENTRY INR A ;CHECK FOR END (0FFH) JNZ SOME ;NOT END OF DIR...PROCESS EXTENT LDA MAXEXT ;HIT END...GET HIGHEST EXTENT NO. SEEN MOV L,A ;WHICH GIVES EXTENT COUNT - 1 MVI H,0 MOV D,H LDA RCNT ;GET RECORD COUNT OF MAX EXTENT SEEN MOV E,A ;SAVE IT IN DE DAD H DAD H ;MULTIPLY # OF EXTENTS - 1 DAD H ; TIMES 128 DAD H DAD H DAD H DAD H DAD D ;ADD IN SIZE OF LAST EXTENT SHLD RCNT ;SAVE TOTAL RECORD COUNT RET ;AND EXIT ; ; POINT TO DIRECTORY ENTRY SOME DCR A ;UNDO PREV 'INR A' ANI 3 ;MAKE MODULUS 4 ADD A ;MULTIPLY... ADD A ;..BY 32 BECAUSE ADD A ;..EACH DIRECTORY ADD A ;..ENTRY IS 32 ADD A ;..BYTES LONG LXI H,BASE+80H ;POINT TO BUFFER ADD L ;POINT TO ENTRY ADI 15 ;OFFSET TO RECORD COUNT MOV L,A ;HL NOW POINTS TO REC COUNT MOV B,M ;GET RECORD COUNT DCX H DCX H ;BACK DOWN TO EXTENT NUMBER DCX H LDA MAXEXT ;COMPARE WITH CURRENT MAX. ORA A ;IF NO MAX YET JM BIGGER ;THEN SAVE RECORD COUNT ANYWAY CMP M JNC MOREDIR ; BIGGER: MOV A,B ;SAVE NEW RECORD COUNT STA RCNT MOV A,M ;SAVE NEW MAX. EXTENT NO. STA MAXEXT JMP MOREDIR ;GO FIND MORE EXTENTS ; ; ;* * * * * * * * * * * * * * * * * * * * * ;* * ;* RCVFIL: RECEIVE A FILE * ;* * ;* * * * * * * * * * * * * * * * * * * * * ; ; RECEIVES A FILE IN BLOCK FORMAT AS SENT ; BY ANOTHER PERSON DOING "MODEM S FN.FT". ; IF THE CRC SECONDARY OPTION (MODEM RC fn.ft) ; WAS CHOSEN, THE LETTER 'C' WILL BE SENT IN ; PLACE OF THE INITIAL NAK. IF A SECTOR IS ; RECEIVED IN ERROR, THEN A NAK IS SENT WHICH ; REQUESTS THAT THE SECTOR BE RESENT. ; RCVFIL CALL TRAP ;CHECK FOR NO NAME OR AMBIG. NAME CALL ERASFIL ;ERASE THE FILE CALL MAKEFIL ;..THEN MAKE NEW CALL ILPRT ;PRINT: DB 'File open, ready to receive',CR,LF,0 LDA CRCFLG ;GET CRC FLAG ORA A ;CRC BEING USED? MVI A,NAK ;PREPARE FOR CHECKSUM BEING IN EFFECT JNZ RCVFIL2 ;BRANCH IF CHECKSUM BEING USED MVI A,CRC ;REQUEST CYCLIC REDUNDANCY CHECK ; RCVFIL2 CALL SEND ;SEND INITIAL NAK (CHECKSUM) OR CRC REQUEST ; RCVLP CALL RCVSECT ;GET A SECTOR JC RCVEOT ;GOT EOT CALL WRSECT ;WRITE THE SECTOR CALL INCRSNO ;BUMP SECTOR # CALL SENDACK ;ACK THE SECTOR JMP RCVLP ;LOOP UNTIL EOF ; ; GOT EOT ON SECTOR - FLUSH BUFFERS, END ; RCVEOT CALL WRBLOCK ;WRITE THE LAST BLOCK CALL SENDACK ;ACK THE SECTOR CALL CLOSFIL ;CLOSE THE FILE JMP DONE ;ALL DONE ; ;* * * * * * * * * * * * * * * * * * * * * ;* * ;* SUBROUTINES * ;* * ;* * * * * * * * * * * * * * * * * * * * * ; ;----> TRAP: CHECK FOR NO FILE NAME OR AMBIGUOUS NAME ; TRAP LXI H,FCB+1 ;POINT TO FILE NAME MOV A,M ;GET FIRST CHAR OF FILE NAME CPI ' ' ;ANY THERE? JNZ ATRAP ;YES, CHECK FOR AMBIGOUS FILE NAME CALL ERXIT ;PRINT MSG, EXIT DB '++No file name specified++',CR,LF,'$' ; ATRAP MVI B,11 ;11 CHARS TO CHECK ; TRLOOP MOV A,M ;GET CHAR FROM FCB CPI '?' ;AMBIGUOUS? JZ TRERR ;YES, EXIT WITH ERROR MSG INX H ;POINT TO NEXT CHAR DCR B ;ONE LESS TO GO JNZ TRLOOP ;NOT DONE, CHECK SOME MORE RET ;NO AMBIGUOUS NAME, RETURN ; TRERR CALL ERXIT ;PRINT MSG, EXIT DB '++Can''t use wild card options++',CR,LF,'$' ; ;----> RCVSECT: RECEIVE A SECTOR ; ; RETURNS WITH CARRY SET IF EOT RECEIVED. ; RCVSECT XRA A ;GET 0 STA ERRCT ;INIT ERROR COUNT ; RCVRPT XRA A ;GET 0 STA ERRCDE ;CLEAR RECEIVE ERROR CODE LDA QFLG ;QUIET? ORA A JZ RCVSQ ;YES, NO STAT MSG. ; IF NOT VIDEO ;Then send CRLF CALL CRLF ENDIF ; IF VIDEO ;Then send only a CR MVI A,CR CALL TYPE ENDIF ; CALL ILPRT ;PRINT: DB 'Awaiting # ',0 PUSH H ;SAVE HL LHLD SECTNO ;GET SECTOR # INX H ;BUMP IT CALL DECOUT ;PRINT SECTOR # IN DECIMAL CALL ILPRT DB ' (',0 CALL DHXOUT ;16 BIT HEX CONV & OUTPUT CALL ILPRT DB 'H) ',0 MOV A,L ;ONLY LOW BYTE USED BY PROG POP H ;RESTORE HL ; RCVSQ LDA FIRSTME ;GET FIRST TIME SWITCH ORA A ;FIRST TIME THRU? JZ RCVSQ2 ;NO, SKIP TO RECEIVE SOH XRA A ;TURN OFF.. STA FIRSTME ;..FIRST TIME SWITCH LDA CRCFLG ;CRC IN.. ORA A ;..EFFECT? JNZ RCVSQ2 ;NO, DO LONG WAIT FOR SOH MVI B,7 ;WAIT FOR UP TO 7 SECONDS CALL RECV ;GET A CHARACTER JNC RCVSQ3 ;GOT A CHAR, GO SEE IF SOH CALL ILPRT DB '++Switching to CHECKSUM MODE++',CR,LF,0 MVI A,'C' ;TURN OFF... STA CRCFLG ;...CRC MODE MVI A,NAK ;SEND A NAK TO TELL SENDER CHECKSUM.. CALL SEND ;..IN EFFECT & START SENDING DATA. JMP RCVSECT ;GO START RECEIVING SECTOR ; RCVSQ2 MVI B,10 ;10 SEC TIMEOUT CALL RECV ;GET SOH/EOT JC RCVSTOT ;TIMEOUT rcvsq3 CALL RCVR ;TRANS ERROR? JC RCERR ;CARRY ON IF ERROR CPI SOH ;GET SOH? JZ RCVSOH ;..YES ; ; EARLIER VERSIONS OF MODEM PROG SENT SOME NULLS - ; IGNORE THEM ; ORA A ;00 FROM SPEED CHECK? JZ RCVSQ ;YES, IGNORE IT CPI EOT ;END OF TRANSFER? STC ;RETURN WITH CARRY.. RZ ;..SET IF EOT ; ; DIDN'T GET SOH OR EOT ; MOV B,A ;SAVE CHAR LDA VSEEFLG ;VIEWING.. ORA A ;..MODE? JZ RCVSEH ;YES, PRT.MSG LDA QFLG ;QUIET.. ORA A ;..MODE? JZ RCVSERR ;YES, SKIP MSG ; RCVSEH MOV A,B ;GET CHAR CALL HEXO ;SHOW IN HEX CALL ILPRT ;PRINT: DB 'H rcvd, not SOH',CR,LF,0 ; ; DIDN'T GET VALID HEADER - PURGE THE LINE, ; THEN SEND NAK. ; RCVSERR MVI B,1 ;WAIT FOR 1 SEC.. CALL RECV ;..WITH NO CHARS JNC RCVSERR ;LOOP UNTIL SENDER DONE LDA ERRCT ;ABORT IF.. INR A ;..WE HAVE REACHED.. STA ERRCT ;..THE ERROR.. CPI ERRLIM ;..LIMIT? JC RCVCQ2 ;..NO, TRY AGAIN (FIRST, SEND NAK) ; ; 10 ERRORS IN A ROW - ; LDA VSEEFLG ;VIEWING.. ORA A ;..FILE? JZ RCVCKQ ;YES, ASK RETRY/QUIT LDA QFLG ;QUIET.. ORA A ;..MODE? JZ RCVSABT ;ABORT ; RCVCKQ CALL CKQUIT ;RETRY/QUIT? JNZ RCVSABT ;QUIT, THEN ABORT ; ; LINE MUST BE PURGED BECAUSE SENDER PROBABLY STARTED ; RESENDING WHILE OPERATOR ANSWERED RETRY/QUIT PROMPT. ; RCVCQ2 MVI A,NAK ;SEND NAK TO CANCEL SECTOR CALL SEND JMP RCVRPT ;GO RE-RECEIVE SECTOR ; RCVSABT CALL CLOSFIL ;KEEP WHATEVER WE GOT CALL ERXIT DB '++Unable to receive block -- Aborting++',BELL,CR,LF,'$' ; ; TIMED OUT ON RECEIVE ; RCVSTOT LDA VSEEFLG ;VIEWING.. ORA A ;..MODE? JZ RCVSPT ;YES, PRT MSG LDA QFLG ;QUIET.. ORA A ;..MODE? JZ RCVSERR ;YES, NO MSG ; RCVSPT CALL ILPRT DB '++Timeout++ ',0 ; RCVPRN LDA ERRCT ;PRINT ERROR.. CALL HEXO ;..COUNT CALL CRLF JMP RCVSERR ;BUMP ERR CT, ETC. ; ;----> RCVR: CHECKS FOR FRAMING ERROR, OVERRUN ERROR, ; AND PARITY ERROR. ; 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, THE CARRY BIT IS SET ON. ; RCVR PUSH PSW ;SAVE CHAR TRANSMITTED LDA ERRCDE ;GET RECEIVE ERROR CODE ANA A ;IS IT ZERO? JZ RCVR2 ;YES, NO RECEIVE ERROR POP PSW ;RESTORE CHAR TRANSMITTED STC ;SET CARRY ON TO INDICATE AN ERROR RET ; RCVR2 POP PSW ;RESTORE CHAR TRANSMITTED ORA A ;CLEAR CARRY BIT RET ; ;----> RCERR: CHECKS FOR A RECEIVE ERROR AND DISPLAYS ; APROPRIATE ERROR MESSAGE. THEN GOES TO RCVSERR ; TO PURGE THE LINE AND SEND A NAK. ; RCERR LDA VSEEFLG ;VIEWING ORA A ;..MODE? JZ RCERRP ;YES,. PRT MSG LDA QFLG ;QUIET.. ORA A ;..MODE? JZ RCVSERR ;YES, NO MSG ; RCERRP: LDA ERRCDE ;GET RECEIVE ERR CODE ANI FRMER ;WAS THERE A FRAMING ERROR? CPI FRMER JNZ RCERR2 ;NO, GO CHECK FOR OVERRUN CALL ILPRT DB '++Framing error++ ',0 CALL RCERR5 ;PRINT # OF ERR ; RCERR2: LDA ERRCDE ;GET RECEIVE ERR CODE ANI ORUNER ;WAS THERE AN OVERRUN? CPI ORUNER JNZ RCERR3 ;NO, CHECK FOR PARITY ERR CALL ILPRT DB '++Overrun error++ ',0 CALL RCERR5 ; RCERR3: LDA ERRCDE ;GET RECEIVE ERR CODE ANI PARER ;WAS THERE A PARITY ERR? CPI PARER JNZ RCERR4 ;NO, GO PURGE LINE CALL ILPRT DB '++Parity error++ ',0 CALL RCERR5 ; RCERR4: JMP RCVSERR ;GO PURGE LINE, SEND NAK ; ; DISPLAY THE NUMBER OF THE ERROR, DO A CARRIAGE ; RETURN AND LINE FEED. ; RCERR5: LDA ERRCT ;GET ERROR NUMBER CALL HEXO ;DISPLAY IT CALL CRLF ;DO CR, LF RET ; ; ; GOT SOH - GET BLOCK #, BLOCK # COMPLEMENTED ; RCVSOH MVI B,1 ;TIMEOUT = 1 SEC CALL RECV ;GET SECTOR # JC RCVSTOT ;GOT TIMEOUT CALL RCVR ;TRANSMISSION ERROR? JC RCERR ;YES, GO DISP MSG, PURGE LINE MOV D,A ;D=BLK # MVI B,1 ;TIMEOUT = 1 SEC CALL RECV ;GET COMPLEMENTED SECTOR # JC RCVSTOT ;TIMEOUT CALL RCVR ;TRANSMISSION ERROR? JC RCERR ;YES IF CARRY ON CMA ;CALC COMPLEMENT CMP D ;GOOD SECTOR #? JZ RCVDATA ;YES, GET DATA ; ; GOT BAD SECTOR # ; LDA VSEEFLG ;VIEWING.. ORA A ;..MODE? JZ RCVBSE ;..YES, PRT MSG LDA QFLG ;QUIET.. ORA A ;..MODE? JZ RCVSERR ;..YES, NO MSG ; RCVBSE CALL ILPRT ;PRINT: DB '++Bad sector # in hdr',CR,LF,0 JMP RCVSERR ;BUMP ERROR CT. ; RCVDATA MOV A,D ;GET SECTOR # STA RCVSNO ;SAVE IT MVI A,1 ;SHOW.. STA DATAFLG ;GETTING DATA MVI C,0 ;INIT CKSUM CALL CLRCRC ;CLEAR CRC COUNTER LXI H,BASE+80H ;POINT TO BUFFER ; RCVCHR MVI B,1 ;1 SEC TIMEOUT CALL RECV ;GET CHAR JC RCVSTOT ;TIMEOUT CALL RCVR ;TRANSMISSION ERROR? JC RCERR ;YES IF CARRY ON MOV M,A ;STORE CHAR INR L ;DONE? JNZ RCVCHR ;NO, LOOP LDA CRCFLG ;GET CRC FLAG ORA A ;CRC IN EFFECT? JZ RCVCRC ;YES, GO GET CRC ; ; VERIFY CHECKSUM ; MOV D,C ;SAVE CHECKSUM XRA A ;SHOW.. STA DATAFLG ;..END OF DATA MVI B,1 ;TIMEOUT LEN. CALL RECV ;GET CHECKSUM JC RCVSTOT ;TIMEOUT CALL RCVR ;TRANSMISSION ERROR? JC RCERR ;YES IF CARRY ON CMP D ;CHECKSUM OK? JNZ RCVCERR ;NO, ERROR ; ; GOT A SECTOR, IT'S A DUP IF = PREV, ; OR OK IF = 1 + PREV SECTOR ; CHKSNUM LDA RCVSNO ;GET RECEIVED MOV B,A ;SAVE IT LDA SECTNO ;GET PREV CMP B ;PREV REPEATED? JZ RECVACK ;ACK TO CATCH UP INR A ;CALC NEXT SECTOR # CMP B ;MATCH? JNZ ABORT ;NO MATCH - STOP SENDER, EXIT RET ;CARRY OFF - NO ERRORS ; ; RECEIVE THE CYCLIC REDUNDANCY CHECK CHARACTERS (2 BYTES), ; AND CHECK TO SEE IF THE SENT CRC MATCHES THE CALCULATED ; CRC. IF THEY MATCH GET NEXT SECTOR, ELSE PRINT ERROR ; MESSAGE IF NOT IN QUIET MODE AND SEND A NAK REQUESTING ; THAT THE SECTOR BE RESENT. ; RCVCRC MVI E,2 ;NUMBER OF CRC BYTES TO RECEIVE ; RCVCRC2 MVI B,1 ;1 SEC TIMEOUT CALL RECV ;GET CRC BYTE JC RCVSTOT ;CARRY SET IF TIMEOUT CALL RCVR ;TRANSMISSION ERR? JC RCERR ;CARRY SET IF TRANS ERR DCR E ;GOT BOTH CRC BYTES? JNZ RCVCRC2 ;NO, GO GET 2ND BYTE CALL CHKCRC ;CHECK RECVD CRC AGAINST CALCD CRC ORA A ;IS CRC OKAY? JZ CHKSNUM ;YES, GO CHECK SECTOR NUMBERS ; ;PRINT CRC ERROR MESSAGE ; LDA VSEEFLG ;VIEWING.. ORA A ;..MODE? JZ RCVCRER ;..YES, PRINT MESSAGE LDA QFLG ;QUIET.. ORA A ;..MODE? JZ RCVSERR ;YES, NO MESSAGE ; RCVCRER CALL ILPRT DB '++CRC error++ ',0 JMP RCVPRN ; ; GOT CKSUM ; RCVCERR LDA VSEEFLG ;VIEWING.. ORA A ;..MODE? JZ RCVCPR ;..YES, PRT MSG LDA QFLG ;QUIET.. ORA A ;..MODE? JZ RCVSERR ;YES, NO MSG ; RCVCPR CALL ILPRT DB '++CKSUM error++ ',0 JMP RCVPRN ;PRINT ERROR # ; ; PREVIOUS SECTOR REPEATED, DUE TO THE LAST ACK ; BEING GARBAGED. ACK IT SO SENDER WILL CATCH UP ; RECVACK CALL SENDACK ;SEND THE ACK, JMP RCVSECT ;GET NEXT BLOCK ; ; SEND AN ACK FOR THE SECTOR ; SENDACK MVI A,ACK ;GET ACK CALL SEND ;..AND SEND IT RET ; ;----> SENDHDR: SEND THE SECTOR HEADER ; ; SEND: (SOH) (BLOCK #) (COMPLEMENTED BLOCK #) ; SENDHDR LDA QFLG ;QUIET.. ORA A ;..MODE? JZ SENDHNM ;YES, SKIP STATUS MSG. ; IF NOT VIDEO ;Then send CRLF CALL CRLF ENDIF ; IF VIDEO ;Then send only a CR MVI A,CR CALL TYPE ENDIF ; CALL ILPRT ;PRINT: DB 'Send # ',0 PUSH H ;SAVE HL LHLD SECTNO ;GET SECTOR # CALL DECOUT ;PRINT SECTOR # IN DECIMAL CALL ILPRT DB ' (',0 CALL DHXOUT ;16 BIT HEX CONV & OUTPUT CALL ILPRT DB 'H) ',0 POP H ;RESTORE HL ; SENDHNM MVI A,SOH ;SEND.. CALL SEND ;..SOH, LDA SECTNO ;THEN SEND.. CALL SEND ;..SECTOR # LDA SECTNO ;THEN SECTOR # CMA ;..COMPLEMENTED.. CALL SEND ;..SECTOR # RET ;FROM SENDHDR ; ;----> SENDSEC: SEND THE DATA SECTOR ; ; WHILE SENDING THE SECTOR, THE "DATAFLG" IS SET ; SUCH THAT IF "V" (VIEW THE FILE) WAS REQUESTED, ; THE "SHOW" ROUTINE WILL PRINT THE DATA, BUT NOT ; THE HDR OR CKSUM, OR ANY NON-FATAL MSGS. ; SENDSEC MVI A,1 ;SHOW NOW AT DATA.. STA DATAFLG ;..FOR VIEW COMMAND MVI C,0 ;INIT CKSUM CALL CLRCRC ;CLEAR CRC COUNTER LXI H,BASE+80H ;POINT TO BUFFER ; SENDC MOV A,M ;GET A CHAR CALL SEND ;SEND IT INR L ;POINT TO NEXT CHAR JNZ SENDC ;LOOP IF <100H XRA A ;SHOW NOT INTO DATA.. STA DATAFLG ;..FOR VIEW COMMAND RET ;FROM SENDSEC ; ;----> SENDCKS: SEND THE CHECKSUM ; SENDCKS MOV A,C ;SEND THE.. CALL SEND ;..CHECKSUM RET ;FROM SENDCKS ; ;----> SENDCRC: CALCULATE THE CYCLIC REDUNDANCY CHECK ; AND THEN SEND IT. FINCRC CALCS THE ; FINAL CRC AND PLACES IT IN D,E REGS. ; SENDCRC CALL FINCRC ;CALC CRC FOR THE SECTOR MOV A,D ;PUT FIRST CHAR OF CRC IN ACCUM CALL SEND ;SEND IT MOV A,E ;PUT SECOND CHAR OF CRC IN ACCUM CALL SEND XRA A ;MAKE SURE ZERO FLAG IS OFF RET ; ;----> GETACK: GET THE ACK ON THE SECTOR ; ; RETURNS WITH CARRY CLEAR IF ACK RECEIVED. ; IF AN ACK IS NOT RECEIVED, THE ERROR COUNT ; IS INCREMENTED, AND IF LESS THAN "ERRLIM", ; CARRY IS SET AOD CONTROL RETURNS. IF THE ; ERROR COUNT IS AT "ERRLIM", THE PROGRAM ; ABORTS IF IN "QUIET" MODE, OR ASKS THE ; USER FOR QUIT/RETRY IF NOT. ; GETACK MVI B,10 ;WAIT 10 SECONDS MAX CALL RECVDG ;RECV W/GARBAGE COLLECT JC GETATOT ;TIMED OUT CPI ACK ;OK? (CARRY OFF IF =) RZ ;YES, RET FROM GETACK MOV B,A ;SAVE CHAR LDA QFLG ;QUIET.. ORA A ;..MODE? JZ ACKERR ;..YES, NO MSG MOV A,B ;GET CHAR CALL HEXO ;PRINT IN HEX CALL ILPRT ;PRINT: DB 'H rcvd, not ACK',CR,LF,0 ; ; TIMEOUT OR ERROR ON ACK - BUMP ERROR COUNT ; ACKERR LDA ERRCT ;GET COUNT INR A ;BUMP IT STA ERRCT ;SAVE BACK CPI ERRLIM ;AT LIMIT? RC ;NOT AT LIMIT ; ; REACHED ERROR LIMIT ; LDA VSEEFLG ;VIEWING.. ORA A ;..FILE? JZ GACKV ;YES, ASK QUIT/RETRY LDA QFLG ;QUIET.. ORA A ;..MODE? JZ CSABORT ;..YES, NO MSG ; GACKV CALL CKQUIT ;SEE IF WANT TO QUIT STC ;TO SHOW NO ACK RZ ;KEEP ON TRYIN' ; CSABORT CALL ERXIT DB '++Can''t send sector -- Aborting++',BELL,CR,LF,'$' ; ; TIMEOUT GETTING ACK ; GETATOT LDA QFLG ;QUIET.. ORA A ;..MODE? JZ ACKERR ;YES, NO MSG CALL ILPRT ;PRINT: DB '++Timeout on ACK',CR,LF,0 JMP ACKERR ; ABORT LXI SP,STACK ; ABORTL MVI B,1 ;1 SEC. W/O CHARS. CALL RECV JNC ABORTL ;LOOP UNTIL SENDER DONE MVI A,NAK ;NEGATIVE ACK CALL SEND ;TELL SENDING END CALL ILPRT ;EXIT WITH ABORT MSG DB 'MODEM program cancelled',CR,LF,0 JMP CKDIS ;CHECK FOR DISCONN. ; ;----> INCRSNO: INCREMENT SECTOR # ; INCRSNO: PUSH H LHLD SECTNO ;GET SECTOR # INX H ;BOP IT SHLD SECTNO ;STORE UPDATED BACK MOV A,L ;COPY LOW TO ACC FOR CALLERS POP H RET ; ;----> ERASFIL: ERASE THE INCOMING FILE. ; ; IF IT EXISTS, ASK IF IT MAY BE ERASED. ; ERASFIL LXI D,FCB ;POINT TO CTL BLOCK MVI C,SRCHF ;SEE IF IT.. CALL BDOS ;..EXISTS INR A ;FOUND? RZ ;..NO, RETURN CALL ILPRT ;PRINT: DB '++File exists, type ''Y'' to erase: ',BELL,0 CALL KEYIN ;GET CHAR PUSH PSW CALL TYPE ;ECHO CALL CRLF ;BACK TO START OF LINE POP PSW ANI 5FH ;MAKE UPPER CASE CPI 'Y' ;WANT ERASED? JNZ CKDIS ;QUIT IF NOT ERASE ; ;ERASE OLD FILE ; LXI D,FCB ;POINT TO FCB MVI C,ERASE ;GET BDOS FNC CALL BDOS ;DO THE ERASE RET ;FROM "ERASFIL" ; ;----> MAKEFIL: MAKES THE FILE TO BE RECEIVED ; MAKEFIL LXI D,FCB ;POINT TO FCB MVI C,MAKE ;GET BDOS FNC CALL BDOS ;TO THE MAKE INR A ;FF=BAD? RNZ ;OPEN OK ; ; DIRECTORY FULL - CAN'T MAKE FILE ; CALL ERXIT DB '++ERROR -- Can''t make file',CR,LF DB '++Directory must be full',CR,LF,'$' ; ;----> OPENFIL: OPENS THE FILE TO BE SENT ; OPENFIL XRA A ;SET EXT & REC # TO 0 FOR PROPER OPEN STA FCBEXT STA FCBSNO LXI D,FCB ;POINT TO FILE MVI C,OPEN ;GET FUNCTION CALL BDOS ;OPEN IT INR A ;OPEN OK? JNZ OPENOK ;..YES CALL ERXIT ;..NO, ABORT DB '++Can''t open file',CR,LF,'$' ; OPENOK CALL ILPRT ;PRINT: DB 'File open - Size: ',0 LHLD RCNT ; Get record count. CALL DECOUT ;PRINT DECIMAL NUMBER OF SECTORS CALL ILPRT ;Print: DB ' (',0 CALL DHXOUT ;Now print size in hex. CALL ILPRT ;PRINT: DB 'H) sectors',CR,LF,0 RET ; ;----> DECOUT: Decimal output routine ; DECOUT: 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 RET ; ;----> DHXOUT: - double precision hex output routine. ; Call with hex value in HL. ; DHXOUT PUSH H ;Save H,L PUSH PSW ;Save A MOV A,H ;Get MS byte. CALL HEXO ;Output hi order byte. MOV A,L ;Get LS byte. CALL HEXO ;Output lo order byte. POP PSW ;Restore A POP H ;Restore H,L RET ;Return to caller. ; ; ; ;----> CLOSFIL: CLOSES THE RECEIVED FILE ; CLOSFIL LXI D,FCB ;POINT TO FILE MVI C,CLOSE ;GET FUNCTION CALL BDOS ;CLOSE IT INR A ;CLOSE OK? RNZ ;..YES, RETURN CALL ERXIT ;..NO, ABORT DB BELL,'++Can''t close file',CR,LF,'$' ; ;---> ASCPTR - CHECK TO SEE IF ASCII CAPTURE IS ENABLED-IF ; IT IS, SAVE THE INCOMING CHARACTER IN THE ; MEMORY BUFFER, WRITING IT WHEN FULL ; ASCPTR: PUSH PSW ;SAVE CHARACTER LDA CPTRFLG ;LOOK AT CAPTURE FLAG ORA A ;CAPTURE ENABLED? JZ ASCQEND ; NO, TAKE QUICK EXIT POP PSW ;GET THE CHARACTER PUSH PSW ; AND SAVE ALL THE REGISTERS PUSH B PUSH D PUSH H LHLD CAPPTR ;GET THE BUFFER POINTER MOV M,A ; PUT CHARACTER IN BUFFER INX H ; INCREMENT POINTER SHLD CAPPTR ; AND SAVE IT LDA MEMEND ;GET LAST PAGE ADDRESS CMP H ;ARE WE THERE YET? JZ ASCPTR1 ; YES, TIME TO WRITE THE BUFFER DCR A ;NEXT TO LAST PAGE ADDRESS CMP H ;NEARING THE END? JNZ ASCEND ; NO, EXIT ROUTINE MOV A,L ;CHECK LOWER BYTE OF ADDRESS CPI -STPTIME AND 0FFH JNZ ASCEND ;NOT TIME FOR STOP CHAR, SO EXIT MVI A,STOPCHR ;TELL OTHER END TO STOP CALL OUTDATA ; IN ADVANCE JMP ASCEND ASCPTR1 LXI D,ASCBUF LDA MEMEND SUB D MOV B,A ;NUMBER OF PAGES TO SAVE ASCPTR2 MOV C,2 ;NUMBER OF SECTORS/PAGE ASCPTR3 CALL AWRITE LXI H,128 DAD D XCHG ;MOVE TO NEXT SECTOR TO WRITE DCR C JNZ ASCPTR3 ;UNTIL PAGE IS WRITTEN DCR B JNZ ASCPTR2 ;UNTIL ALL PAGES ARE WRITTEN LXI H,ASCBUF ;RESET BUFFER POINTER SHLD CAPPTR MVI A,STRTCHR ;TELL OTHER END TO START CALL OUTDATA ASCEND POP H POP D POP B ASCQEND POP PSW RET AWRITE PUSH D MVI C,STDMA ;SET BUFFER ADDRESS CALL BDOS LXI D,ASCFCB MVI C,21 ;WRITE SEQUENTIAL CALL BDOS INR A JNZ AWRITE1 CALL ILPRT DB BELL,'++Out of disk space',CR,LF,0 AWRITE1 POP D RET ; ;----> RDSECT: READS A SECTOR ; ; FOR SPEED, THIS ROUTINE BUFFERS UP DBUFSIZ*8 ; SECTORS AT A TIME. ; RDSECT LDA SECINBF ;GET # SECT IN BUFF. DCR A ;DECREMENT.. STA SECINBF ;..IT JM RDBLOCK ;EXHAUSTED? NEED MORE. LHLD SECPTR ;GET POINTER LXI D,BASE+80H ;TO DATA CALL MOVE128 ;MOVE TO BUFFER SHLD SECPTR ;SAVE BUFFER POINTER RET ;FROM "READSEC" ; ; BUFFER IS EMPTY - READ IN ANOTHER BLOCK OF DBUFSIZ*8 ; RDBLOCK LDA EOFLG ;GET EOF FLAG CPI 1 ;IS IT SET/ STC ;TO SHOW EOF RZ ;GOT EOF MVI C,0 ;SECTORS IN BLOCK LXI D,DBUF ;TO DISK BUFFER ; RDSECLP PUSH B PUSH D MVI C,STDMA ;SET DMA.. CALL BDOS ;..ADDR LXI D,FCB MVI C,READ CALL BDOS POP D POP B ORA A ;READ OK? JZ RDSECOK ;YES DCR A ;EOF? JZ REOF ;GOT EOF ; ; READ ERROR ; CALL ERXIT DB BELL,'++File read error',CR,LF,'$' ; RDSECOK LXI H,80H ;ADD LENGTH OF ONE SECTOR... DAD D ;...TO NEXT BUFF XCHG ;BUFF TO DE INR C ;MORE SECTORS? MOV A,C ;GET COUNT CPI DBUFSIZ*8 ;DONE? JZ RDBFULL ;..YES, BUFF IS FULL JMP RDSECLP ;READ MORE ; REOF MVI A,1 STA EOFLG ;SET EOF FLAG MOV A,C ; ; BUFFER IS FULL, OR GOT EOF ; RDBFULL STA SECINBF ;STORE SECTOR COUNT LXI H,DBUF ;INIT BUFFER.. SHLD SECPTR ;..POINTER LXI D,BASE+80H ;RESET.. MVI C,STDMA ;..DMA.. CALL BDOS ;..ADDR JMP RDSECT ;PASS SECT TO CALLER ; ;----> WRSECT: WRITE A SECTOR ; ; WRITES THE SECTOR INTO A BUFFER. WHEN DBUFSIZ*8 ; HAVE BEEN WRITTEN, WRITES THE BLOCK TO DISK. ; ; ENTRY POINT "WRBLOCK" FLUSHES THE BUFFER AT EOF. ; WRSECT LHLD SECPTR ;GET BUFF ADDR XCHG ;TO DE FOR MOVE LXI H,BASE+80H ;FROM HERE CALL MOVE128 ;MOVE TO BUFFER XCHG ;SAVE NEXT.. SHLD SECPTR ;..BLOCK POINTER LDA SECINBF ;BUMP THE.. INR A ;..SECTOR #.. STA SECINBF ;..IN THE BUFF CPI DBUFSIZ*8 ;HAVE WE DBUFSIZ*8? RNZ ;NO, RETURN ; ;----> WRBLOCK: WRITES A BLOCK TO DISK ; WRBLOCK LDA SECINBF ;# SECT IN BUFFER ORA A ;0 MEANS END OF FILE RZ ;NONE TO WRITE MOV C,A ;SAVE COUNT LXI D,DBUF ;POINT TO DISK BUFF ; DKWRLP PUSH H PUSH D PUSH B MVI C,STDMA ;SET DMA CALL BDOS ;TO BUFFER LXI D,FCB ;THEN WRITE MVI C,WRITE ;..THE.. CALL BDOS ;..BLOCK POP B POP D POP H ORA A JNZ WRERR ;OOPS, ERROR LXI H,80H ;LENGTH OF 1 SECT DAD D ;HL= NEXT BUFF XCHG ;TO DE FOR SETDMA DCR C ;MORE SECTORS? JNZ DKWRLP ;..YES, LOOP XRA A ;GET A ZERO STA SECINBF ;RESET # OF SECTORS LXI H,DBUF ;RESET BUFFER.. SHLD SECPTR ;..POINTER ; RSDMA LXI D,BASE+80H ;RESET.. MVI C,STDMA ;..DMA.. CALL BDOS ;..ADDR RET ; WRERR CALL RSDMA ;RESET DMA TO NORM. CALL ILPRT ;PRINT: DB BELL,'++Error writing file',CR,LF,0 JMP ABORT ;EXIT ; ;----> RECV: RECEIVE A CHARACTER ; ; TIMEOUT TIME IS IN B, IN SECONDS. ENTRY VIA ; "RECVDG" DELETES GARBAGE CHARACTERS ON THE ; LINE. FOR EXAMPLE, HAVING JUST SENT A SECTOR, ; CALLING RECVDG WILL DELETE ANY LINE-NOISE-INDUCED ; CHARACTERS "LONG" BEFORE THE ACK/NAK WOULD ; BE RECEIVED. ; RECVDG EQU $ ;RECEIVE W/GARBAGE DELETE CALL INDATA ;GET A CHAR CALL INDATA ;..TOTALLY PURGE UART ; RECV PUSH D ;SAVE ; IF FASTCLK ;4MHZ? MOV A,B ;GET TIME REQUEST ADD A ;DOUBLE IT MOV B,A ;NEW TIME IN B ENDIF ; MSEC LXI D,50000 ;1 SEC DCR COUNT ; IF (NOT DCH) AND (NOT X8250) MWTI CALL INCTL ;CHECK STATUS ENDIF ; IF X8250 MWTI CALL INCTL5 ;CHECK STATUS ENDIF ; IF DCH MWTI CALL INCT2 ;CHECK STATUS ENDIF ; IF FRNTPNL AND PMMI CALL OUTPAN ;DISPLAY STATUS ENDIF ; ANI MDRCVB ;ISOLATE BIT CPI MDRCVR ;READY? JZ MCHAR ;GOT CHAR DCR E ;COUNT.. JNZ MWTI ;..DOWN.. DCR D ;..FOR.. JNZ MWTI ;..TIMEOUT DCR B ;MORE SECONDS? JNZ MSEC ;YES, WAIT ; ; MODEM TIMED OUT RECEIVING ; POP D ;RESTORE D,E STC ;CARRY SHOWS TIMEOUT RET ; ; GOT CHAR FROM MODEM ; ; CHECK TO SEE IF THERE WAS A FRAMING, OVERRUN, ; AND/OR PARITY ERROR. ; MCHAR: IF (NOT DCH) AND (NOT X8250) CALL INCTL ;GET STATUS ENDIF ; IF X8250 CALL INCTL5 ;GET STATUS ENDIF ; IF DCH CALL INCT2 ;GET STATUS ENDIF ; MOV D,A ;SAVE STATUS ANI FRMER ;FRAMING ERR? JZ MCHAR2 ;NO, CHECK FOR OVERRUN LDA ERRCDE ;GET RECV ERR CODE ORI FRMER ;TURN ON RECV ERR CODE STA ERRCDE ; MCHAR2: MOV A,D ;RESTORE STATUS ANI ORUNER ;OVERRUN ERR? JZ MCHAR3 ;NO, CHECK FOR PARITY LDA ERRCDE ;GET RECV ERR CODE ORI ORUNER ;TURN ON RECV ERR CODE STA ERRCDE ; MCHAR3: MOV A,D ;RESTORE STATUS ANI PARER ;PARITY ERR? JZ MCHAR4 ;NO, GET DATA CHAR LDA ERRCDE ;GET RECV ERR CODE ORI PARER ;TURN ON RECV ERR CODE STA ERRCDE ; ; Check for error and call reset code if yes ; MCHAR4: LDA ERRCDE ; Retrieve error code ORA A ; Set flags CNZ RESRCVR ; Reset if necessary ; ; GET THE DATA CHAR ; CALL INDATA ;GET MODEM DATA CHAR POP D ;RESTORE DE ; ; CALC CHECKSUM AND CYCLIC REDUNDANCY CHECK ; PUSH PSW ;SAVE THE CHAR CALL UPDCRC ;CALC CYCLIC REDUNDANCY CHECK ADD C ;ADD TO CHECKSUM MOV C,A ;SAVE CHECKSUM ; ; CHECK IF MONITORING REC'D DATA ; LDA RSEEFLG ;SEE RECEIVED.. ORA A ;..DATA? JZ MONIN ;..YES ; ; CHECK IF "VIEWING" AND THIS IS A DATA CHAR ; LDA VSEEFLG ;VIEWING.. ORA A ;..DATA? JNZ NOMONIN ;..NO ; ; "VIEW" REQUESTED. SHOW THE CHAR IF IT IS DATA ; LDA DATAFLG ;GET DATA FLAG ORA A ;TEST IT JZ NOMONIN ;..OFF, NOT DATA ; MONIN POP PSW ;..IS DATA, PUSH PSW ;GET IT, CALL SHOW ;..AND SHOW IT ; NOMONIN POP PSW ;RESTORE CHAR ORA A ;CARRY OFF: NO ERROR RET ;FROM "RECV" ; ; This is the section of code that resets the error ; bit in the receiving device. (from parity, framing, ; and overrun) ; NOTE: I have implemented the code for an Intel 8251 ; usart, but since I know nothing about other ; commonly used devices, you must add your own ; reset code here in a conditional. ; RESRCVR: IF X8251 MVI A,RSTCODE ; Load reset code CALL OUTCTL ; Send to control port ENDIF ; X8251 ; Add code here for other than 8251 !!!! RET ; <=== This "RET" must be here ; outside the conditional ! ; ;----> SEND: SEND A CHARACTER TO THE MODEM ; ; THE CHARACTER TO BE SENT IS SAVED ; IN REG D. IF VIEWING IS IN EFFECT, ; THE CHARACTER IS DISPLAYED. THEN ; BOTH THE CHECKSUM AND CRC ARE CALCU- ; LATED. ; SEND PUSH D ;SAVE D,E REGS MOV D,A ;SAVE THE CHAR ; ; CHECK IF MONITORING SENT DATA ; LDA SSEEFLG ;CHECK IF MONITORING.. ORA A ;..SENT DATA JZ MONOUT ;..YES ; ; CHECK IF "VIEWING" THE FILE ; LDA VSEEFLG ;GET VIEW FLAG ORA A ;TEST IT JNZ NOMONOT ;NO LDA DATAFLG ;IS THIS ORA A ;..DATA? JZ NOMONOT ;..NO. ; MONOUT MOV A,D ;GET THE CHAR CALL SHOW ;SHOW IT ; NOMONOT MOV A,D ;RESTORE THE CHAR CALL UPDCRC ;CALC CRC ADD C ;CALC CKSUM MOV C,A ;SAVE CKSUM ; IF (NOT DCH) AND (NOT X8250) SENDW CALL INCTL ;GET STATUS ENDIF ; IF X8250 SENDW CALL INCTL5 ;GET STATUS ENDIF ; IF DCH SENDW CALL INCT2 ;GET STATUS ENDIF ; IF FRNTPNL CALL OUTPAN ;DISPLAY STATUS ENDIF ; ANI MDSNDB ;ISOLATE READY BIT CPI MDSNDR ;READY? JNZ SENDW ;..NO, WAIT MOV A,D ;GET CHAR POP D ;RESTORE D,E CALL OUTDATA ;OUTPUT IT RET ;FROM "SEND" ; ;----> WAITNAK: WAITS FOR INITIAL NAK ; ; TO ENSURE NO DATA IS SENT UNTIL THE RECEIVING ; PROGRAM IS READY, THIS ROUTINE WAITS FOR ; THE FIRST TIMEOUT-NAK FROM THE RECEIVER/ ; (E) CONTAINS THE # OF SECONDS TO WAIT. ; WAITNAK LDA VSEEFLG ;VIEWING? ORA A JZ WAITNPR ;PRINT MSG LDA QFLG ;QUIET.. ORA A ;..MODE? JZ WAITNLP ;YES, SKIP MSG ; WAITNPR CALL ILPRT ;PRINT: DB 'Awaiting initial NAK or CRC request',CR,LF,0 ; WAITNLP MVI B,1 ;TIMEOUT DELAY CALL RECV ;DID WE GET.. CPI NAK ;..A NAK? RZ ;YES, SEND BLOCK CPI CRC ;CRC REQUEST? JZ WAITCRC ;YES, GO SET CRC FLAG DCR E ;80 TRIES? JZ ABORT ;YES, ABORT JMP WAITNLP ;NO, LOOP ; WAITCRC CALL ILPRT DB 'CRC request received',CR,LF,0 XRA A ;ZERO ACCUM STA CRCFLG ;INDICATE CRC IN EFFECT RET ; ;----> INITADR: INIT'S CP/M BIOS ADDRESSES ; ; THIS ROUTINE FILLS IN THE ADDRESSES OF VARIOUS ; JMP AND CALL INSTRUCTIONS, SO THAT CP/M BDOS ; IS BYPASSED WHILE ACCESSING THE CONSOLE. THIS ; IS DONE TO ALLOW CHARACTERS SUCH AS CONTROL-C ; AND CONTROL-S TO BE KEYED WHILE IN TERMINAL ; MODE, WITHOUT CP/M INTERPRETING THEM. ; INITADR LHLD BASE+1 ;GET WARM BOOT ADDR LXI D,3 ;LENGTH OF A 'JMP' DAD D ;TO CONSOLE STAT SHLD VSTAT+1 ;MODIFY CALL DAD D ;TO CONSOLE IN SHLD VKEYIN+1 ;MODIFY CALL DAD D ;TO CONSOLE OUT SHLD VTYPE+1 ;MODIFY CALL RET ; ;----> CPTRTOG - toggles ASCII capture mode on and off ; CPTRTOG PUSH H ;SAVE ALL REGISTERS PUSH D PUSH B PUSH PSW MVI A,STOPCHR CALL OUTDATA LDA CPTRFLG ;GET CAPTURE FLAG CMA ; INVERT IT STA CPTRFLG ; AND SAVE IT ORA A ;DO WE OPEN OR CLOSE A FILE? JZ CPTRCLS ; CAPTURE DISABLED, SO CLOSE LXI H,ASCBUF ;INITIALIZE BUFFER STARTING ADDRESS SHLD CAPPTR GETNAM CALL ILPRT DB CR,LF,'Enter ASCII capture file name --> ',BELL,0 LXI H,ASCFCB MVI M,0 ;DEFAULT DRIVE IF NOT SPECIFIED ; INX H ;POINT TO FILE NAME MVI B,11 ;FILL NAME AND TYPE WITH BLANKS MVI A,' ' CPTRT01 MOV M,A INX H DCR B JNZ CPTRT01 ; LXI H,ASCBUF ;GET FILE NAME FROM USER MVI M,15 ;MAX NUMBER OF CHARACTERS TO ACCEPT XCHG MVI C,10 ;USE READ CONSOLE BUFFER FUNCTION CALL BDOS ;TO GET INPUT ; MVI E,LF ;PUT USER BACK ON CLEAN LINE MVI C,2 CALL BDOS ; LXI H,ASCBUF INX H MOV B,M ;NUMBER OF CHARACTERS INPUT MOV A,B ;MAKE SURE SOMETHING WAS INPUT CPI 0 ;IF NOTHING INPUT, THEN JZ NULNAM ; ASK FOR FILENAME AGAIN... MVI C,0 ;NUMBER OF FCB CHARS FILLED INX H INX H ;LOOK AT 2ND CHARACTER INPUT MOV A,M CPI ':' ;DRIVE CODE SPECIFIED? DCX H ;POINT BACK TO 1ST CHAR INPUT JNZ CPTRSET ;SKIP IF NO DRIVE SPECIFIED MOV A,M ;GET DRIVE CODE CALL VFYCHR ;LEGAL CHARACTER ???? CPI 'A' JM BADDRV ;JUMP IF < A: CPI MAXDRV+1 JP BADDRV ;JUMP IF > MAXDRV ANI 0FH ;CONVERT FROM ASCII STA ASCFCB ;PUT IT IN THE FCB INX H INX H ;POINT TO FIRST CHAR OF FILE NAME DCR B DCR B ;ADJUST CHAR COUNT JZ NONAME CPTRSET LXI D,ASCFCB+1 ;START OF FILE NAME IN FCB CPTRSE1 MOV A,M ;GET CHAR CPI '.' ;END OF FILE NAME? JZ CPTRTYP CALL VFYCHR ;LEGAL CHARACTER ???? STAX D ;NO, STORE IT INX H INX D INR C DCR B JNZ CPTRSE1 ;LOOP IF MORE CHARS WERE INPUT JMP CPTROPN ;NO FILE TYPE GIVEN, SO USE BLANK DEFAULT ; CPTRTYP INX H ;MOVE PAST PERIOD IN SPECIFIED NAME LXI D,ASCFCB+9 ;POINT TO FILE TYPE IN FCB DCR B ;ACCOUNT FOR THE SKIPPED PERIOD JZ CPTROPN ;IF NO MORE, SKIP IT MOV A,M ;GET THE CHAR CALL VFYCHR ;LEGAL CHARACTER ???? STAX D ; AND SAVE IT INX H INX D DCR B JZ CPTROPN ;SKIP IF NO MORE MOV A,M ;GET NEXT CHAR CALL VFYCHR ;LEGAL CHARACTER ???? STAX D ; AND SAVE IT INX H INX D DCR B JZ CPTROPN ;SKIP IF NO MORE MOV A,M ;GET LAST CHAR CALL VFYCHR ;LEGAL CHARACTER ???? STAX D ; AND SAVE IT CPTROPN PUSH H LXI H,ASCFCB+1 ;POINT TO 1ST CHAR. IN NAME MOV A,M POP H CPI ' ' JZ NONAME ;IF = ' ' THEN NO NAME GIVEN MVI A,0 STA ASCFCB+12 ;CLEAR EXTENT STA ASCFCB+32 ; AND CURRENT RECORD LXI D,ASCFCB ;SEE IF THERE ALREADY MVI C,SRCHF CALL BDOS INR A JZ CPTRNF ;PASS IF NOT CALL ILPRT DB '++File exists, type ''Y'' to erase: ',BELL,0 CALL KEYIN ;GET RESPONSE PUSH PSW ;SAVE IT CALL TYPE ;ECHO IT CALL CRLF ; THEN EJECT LINE POP PSW ANI 5FH ;FOLD TO UPPER CASE CPI 'Y' ;GOT A YES? JNZ GETNAM ;ASK AGAIN IF NOT LXI D,ASCFCB ;PRE-DELETE FILE MVI C,ERASE CALL BDOS ; CPTRNF: LXI D,ASCFCB MVI C,22 ; MAKE FILE CALL BDOS INR A ;0FFH ERROR CODE BECOMES 00H JNZ CPTROP2 ;SKIP IF NO ERROR CALL ILPRT DB CR,LF,'++Directory full',CR,LF,0 XRA A STA CPTRFLG JMP CPTRRET CPTROP2 CALL ILPRT DB CR,LF,'ASCII capture now activated',CR,LF,0 JMP CPTRRET CPTRCLS LHLD CAPPTR ;GET CURRENT BUFFER POINTER CPTRCL1 MVI M,1AH ;FILL OUT THE RECORD WITH CTL-Z MOV A,L ANI 7FH ;ARE WE ON A MULTIPLE OF 128? JZ CPTRCL2 ; YES, EXIT LOOP INX H ;ELSE INCREMENT POINTER JMP CPTRCL1 ; AND CONTINUE CPTRCL2 LXI D,ASCBUF ;START OF BUFFER MOV A,D ;IF THE BUFFER IS EMPTY CMP H ; THEN DON'T WRITE ANYTHING JNZ CPTRCL3 ; AND CLOSE THE FILE MOV A,E CMP L JZ CPTRCL4 CPTRCL3 CALL AWRITE ;WRITE A RECORD LXI H,128 ;INCREMENT WRITE POINTER BY 1 SECTOR DAD D XCHG LDAX D ;GET THE FIRST CHAR OF NEXT SECTOR CPI 1AH ;END OF FILE? JNZ CPTRCL3 ; IF NOT, WRITE SOME MORE CPTRCL4 LXI D,ASCFCB MVI C,16 ; CLOSE FILE CALL BDOS INR A ;0FFH ERROR CODE BECOMES 00H JZ CPTRCL5 ;SKIP IF ERROR CALL ILPRT DB CR,LF,'ASCII capture now off, ' DB 'file closed',CR,LF,0 JMP CPTRRET CPTRCL5 CALL ILPRT DB CR,LF,'++Error in closing file',CR,LF,0 CPTRRET MVI A,STRTCHR CALL OUTDATA POP PSW POP B POP D POP H RET ; ;----> VFYCHR - CONVERT LOWER CASE TO UPPER, AND TRAP ;----> ALL ILLEGAL CHARACTERS IN FILE NAME VFYCHR ANI 7FH ;FORCE PARITY OFF CPI 061H JM VFYCH1 ;BEGIN LOWER->UPPER CPI 7BH JP VFYCH1 SUI 20H ;WAS LOWER, FIX IT VFYCH1 CPI ' ' JM BADNAM ;NO CTRL CHARS IN FILE NAME CPI '9'+1 JM VFYCH2 CPI '@' JM BADNAM VFYCH2 CPI 5FH JP BADNAM CPI '.' JZ BADNAM CPI ',' JZ BADNAM CPI '*' JZ BADNAM CPI '[' JZ BADNAM CPI ']' JZ BADNAM RET ;GOOD CHARACTER !!!! ; BADNAM CALL ILPRT DB '++Invalid character in ' DB 'file name++',BELL,CR,LF,LF,0 POP H ;REMOVE LAST CALL JMP GETNAM ; NULNAM CALL ILPRT DB '++Null file name specified,' DB ' ASCII capture not activated' DB '++',CR,LF,LF,0 XRA A STA CPTRFLG ;FORCE CPATURE OFF JMP CPTRRET ;EXIT ; BADDRV CALL ILPRT DB '++Invalid drive specified, ' DB 'try again++',BELL,CR,LF,0 JMP GETNAM ; NONAME CALL ILPRT DB '++Can''t specify filetype ' DB 'without a filename++',BELL,CR,LF,0 JMP GETNAM ; ; ;----> PRINTER - SEND A CHARACTER TO THE PRINTER ; PRINTER PUSH H ;SAVE REGISTERS PUSH D PUSH B PUSH PSW LDA PRTRFLG ;GET PRINTER FLAG ORA A ;ENABLED? JZ PRTREND ;NO, SKIP IT POP PSW ;GET THE CHAR PUSH PSW ; AND SAVE IT AGAIN MOV E,A MVI C,5 CALL BDOS ;PRINT IT PRTREND POP PSW ;RESTORE REGISTERS POP B POP D POP H RET ; ;----> PRTRTOG - ENABLE/DISABLE THE PRINTER ; PRTRTOG PUSH PSW LDA PRTRFLG CMA STA PRTRFLG POP PSW RET ; ;----> PROCOPT: PROCESS COMMAND OPTIONS ; ; 1) SAVED THE PRIMARY OPTION IN 'OPTION'; ; 2) SCANS THE SUB-OPTION CHARACTERS, AND FOR ; EACH FOUND, ZEROS THE APPROPRIATE ENTRY IN ; THE OPTION TABLE. FOR EXAMPLE, IF 'Q' IS ; CODED (QUIT/DISCONNECT) THEN THE 'D' STORED AT ; 'DISCFLG' IS SET TO 0 SO IT CAN BE TESTED ; LATER. ; PROCOPT LXI D,FCB+1 ;TO PRIMARY OPT. LDAX D ;GET PRIMARY STA OPTION ;SAVE IT ; OPTLP INX D ;TO SECONDARY OPTION LDAX D ;GET CHAR ; ; IF YOU MOD THIS PROGRAM FOR >7 OPTIONS, ; YOU MUST CHANGE THE FOLLOWING, SINCE ; THERE WON'T BE A ' ' AFTER THE OPTION ; IF A BAUD RATE WAS SPECIFIED. ; CPI ' ' ;NO MORE OPT'NS? JZ ENDOPT ;..YES ; ; SET THE APPROP. OPTION: STORE 0 IN IT ; LXI H,OPTBL ;HL = ADDR OF 'OAQDSRV' MVI B,OPTBE-OPTBL ;OPT TABLE LEN ; OPTCK CMP M ;FOUND THE OPTION? JNZ OPTNO ;NO, DON'T SET IT MVI M,0 ;SET THE OPTION JMP OPTLP ;GET NEXT OPTION ; OPTNO INX H ;TO NEXT DCR B ;MORE? JNZ OPTCK ; ; OPTION NOT IN TABLE ; JMP BADOPT ;SHOW BAD SUB OPTION ; ENDOPT LDA CRCFLG ;GET CRC FLAG ORA A ;CRC IN EFFECT? JNZ ENDOPT2 ;NO, EVERYTHING OKAY LDA OPTION ;GET PRIMARY OPTION CPI 'R' ;WAS IT 'FILE RECEIVE' JNZ BADOPT ;NO, CRC ONLY ALLOWED FOR RECV ; ; IF "VIEW" WAS ASKED FOR, SET QUIET FLAG ; ENDOPT2 LDA VSEEFLG ;VIEW.. ORA A ;..ASKED FOR? RNZ ;..NO, RET FROM 'PROCOPT' STA QFLG ;YES, NO HDR/CKSUM PRT RET ;FROM 'PROCOPT' ; ; DONE - CLOSE UP SHOP ; DONE LDA VSEEFLG ;VIEWING? ORA A JZ DONETC ;SHOW MSG LDA QFLG ;QUIET ORA A ;..MODE? JZ DONECTE ;YES, CK TERM/ECHO ; DONETC CALL ILPRT DB BELL,CR,LF,'Transfer complete' DB CR,LF,BELL,0 ; ; CHECK IF TERMINAL OR ECHO SUB COMMAND ; WAS SPECIFIED ; DONECTE LDA TERMFLG ;TERM? ORA A JZ TERM ;..YES LDA ECHOFLG ;ECHO? ORA A JZ TRMECHO ;..YES ; ; FALL INTO 'CKDIS' ; ;----> CKDIS: CHECK IF DISCONNECT REQUESTED ; ; THIS ROUTINE IS JUMPED TO AT THE END OW ; PROCESSING, AND DISCONNECTS THE PHONE IF ; 'D' WAS SPECIFIED AS A SUB-OPTION. ; CKDIS LDA DISCFLG ;CHECK 'D' FLAG ORA A ;REQUESTED? ; IF PMMI OR DCH JNZ NDIS ;..NO, JUST EXIT ENDIF ; IF NOT PMMI AND NOT DCH JNZ EXIT ENDIF ; ; AWAIT C/R TO DISC. SO WE DON'T LOSE THE PHONE ; CALL ILPRT DB CR,LF,'Press RETURN to disconnect:',0 CALL KEYIN PUSH PSW CALL CRLF POP PSW CPI CR JNZ CKDIS ;ASK AGAIN ; ;----> DISCONN: DISCONNECT THE PHONE ; DISCONN:LDA CPTRFLG ORA A CNZ CPTRTOG ;IF CAPTURE WAS ON, TURN OFF ; IF PMMI XRA A ;GET DISCONN VALUE CALL OUTCTL ;RESET ORIG/ANSW CALL OUTCT2 ;TURN OFF DTR, DO BREAK ENDIF ; IF DCH XRA A ;GET DISCONNECT VALUE CALL OUTCTL ;DISCONNECT ENDIF ; CALL ILPRT ;PRINT: DB '++Disconnected++',0 JMP EXIT ; ; NO DISCONNECT, TYPE MSG AS REMINDER THAT PHONE'S ; OFF HOOK ; IF PMMI OR DCH NDIS LDA QFLG ;QUIET.. ORA A ;..MODE? JZ EXIT ;..YES, NO MSG CALL ILPRT DB CR,LF,'++The MODEM is still connected++',CR,LF DB 'Use "MODEM D" to disconnect',CR,LF,0 JMP EXIT ENDIF ;PMMI OR DCH ; ;----> INITMOD: INITIALIZES THE MODEM ; ; THIS ROUTINE IS USED TO INITIALIZE SERIAL ; BOARDS, OR SETUP S-100 MODEM BOARDS. ; JUST RETURNS IF NO INITIALIZATION REQUIRED. ; INITMD: IF INITREQ AND (NOT DCH) AND (NOT X8250) MVI A,INITC1 ;GET 1ST INIT CHAR CALL OUTCTL ;OUTPUT IT NOP NOP ;DELAY FOR USART NOP NOP MVI A,INITC2 ;GET 2ND INIT CHAR CALL OUTCTL ;OUTPUT IT NOP NOP ;DELAY FOR USART NOP NOP MVI A,INITC3 ;GET 3RD INIT CHAR CALL OUTCTL ;OUTPUT IT NOP NOP ;DELAY FOR USART NOP NOP MVI A,INITC4 ;GET 4TH INIT CHAR CALL OUTCTL ;OUTPUT IT ENDIF ;INITREQ AND (NOT DCH) AND (NOT X8250) ; IF DCH CALL GETBAUD ;GET BAUD RATE ENDIF ; IF PMMI CALL GETBAUD ;GET BAUD RATE CALL OUTBRP ;OUT BAUD RATE PORT ; ; SET MODEM CHIP BIT FOR >300 BAUD IF REQ'D ; CPI 52 ;>300? MVI A,5FH ;VALUE FOR >300 JC GT300 MVI A,7FH ;VALUE FOR <=300 GT300 CALL OUTCT2 ;SET IT ; ; SET ORIG/ANSW IF REQUESTED ; LDA ORIGFLG ORA A ;ORIG MODE? MVI A,ORIGMD JZ OFFHOOK ;YES LDA ANSWFLG ORA A ;ANSW MODE? MVI A,ANSWMD RNZ ;NO ENDIF ;PMMI ; IF DCH LDA ANSWFLG ORA A ;ANSW MODE? MVI B,ANSWMD JZ INITM1 ;YES LDA ORIGFLG ORA A ;ORIG MODE? MVI B,ORIGMD JZ INITM1 ;YES LDA HOLDD ;NEITHER - GET LAST VALUE MOV B,A ;STORE IN B ; INITM1: MOV A,B ;GET MODE STA HOLDD ;SAVE VALUE MOV A,C ;GET BAUD RATE INDICATOR ORA A ;ZERO IF 110 BAUD MOV A,B ;GET MODE JZ OFFHOOK ;DO OFFHOOK ORI 1 ;SET 300 BAUD ENDIF ;DCH ; IF PMMI OR DCH ; ; GO OFFHOOK IN REQUESTED (ORIG/ANSW) MODE ; OFFHOOK LXI H,4000 ;DELAY AMT ; OFFDLY DCR L JNZ OFFDLY DCR H JNZ OFFDLY CALL OUTCTL ;GO OFF HOOK RET ENDIF ;PMMI OR DCH ; IF X8250 MVI A,INITC1 ;ACCESS DIVISOR LATCHES CALL OUTCTL3 MVI A,INITC2 ;SET DTR AND RTS CALL OUTCTL4 MVI A,INITC3 ;BAUD DIVISOR LOW BYTE CALL OUTDATA MVI A,INITC4 ;BAUD DIVISOR HIGH BYTE CALL OUTCTL1 MVI A,INITC5 ;DISABLE DIVISOR LATCHES, CALL OUTCTL3 ; SET 8 BIT WORD, 1 STOP, NO PAR MVI A,INITC6 ;DISABLE INTERRUPTS FROM 8250 CALL OUTCTL1 ENDIF ;X8250 ; ;----> GETBAUD: GETS BAUD RATE FROM COMMAND ; ; THIS ROUTINE CHECKS IF A BAUD RATE HAS ; BEEN ASKED FOR, (SUCH AS MODEM T.450), ; AND IF SO, CALCULATES THE PMMI BAUD RATE ; VALUE TO BE OUTPUT. DEFAULTS TO 300. ; IF PMMI GETBAUD LDA FCB+9 ;GET 'FILETYPE' CPI ' ' ;DEFAULT? MVI A,DEFBAUD ;DEFAULT BAUD RATE RZ ;NO BAUD RATE, USE 300 ; ; GOT BAUD RATE - CONVERT TO PROPER TIMER VALUE ; CALL CVBIN ;CONVERT NUMBER TO BINARY ; ; CALCULATE THE VALUE TO OUTPUT: ; RATE = 250000/16/BAUD RATE ; DIVIDE BY USING REPETITIVE SUBTRACTION ; ; COMPLEMENT THE BAUD RATE ; MOV A,H ;GET HI CMA ;COMPLEMENT MOV D,A ;SAVE MOV A,L ;GET LO CMA ;COMPLEMENT MOV E,A ;SAVE INX D ;DE=2'S COMPLEMENT ; DIVIDE LXI H,15625 ;250000/16 LXI B,-1 ;INIT QUOTIENT ; DIVLP INX B ;BUMP QUOTIENT DAD D ;'SUBTRACT' JC DIVLP ;LOOP TIL DOOE ; VALIDATE THE RESULT MOV A,B ;CAN'T HAVE >255 ORA A MOV A,C ;GET ACTUAL RZ ;RET IF <256 JMP BADRATE ;INVALID ENDIF ;PMMI ; IF DCH GETBAUD LDA FCB+9 ;GET 'FILETYPE' CPI ' ' ;DEFAULT? JNZ GETBAU1 ;NO - DO BAUD RATE STUFF MVI C,1 ;SET 300 BAUD MVI B,17H ;SET 1 STOP BIT JMP GETBAU2 ; GETBAU1 CALL CVBIN ;CONVERT TO BINARY PUSH H ;SAVE BAUD RATE MVI C,0 ;ANTICIPATE 110 BAUD MVI B,1FH ;SET 2 STOP BITS LXI D,-110 ;GET CONSTANT DAD D ;SUBTRACT MOV A,H ORA L POP H JZ GETBAU2 ;110 BAUD MVI B,17H ;SET 1 STOP BIT INR C LXI D,-300 ;GET CONSTANT DAD D MOV A,H ORA L JNZ BADRATE ;INVALID ; GETBAU2 MOV A,B ;GET SET UP CALL OUTCT2 ;INIT STOP & DATA BITS, ETC RET ENDIF ;DCH ; ; ROUTINE TO CONVERT BAUD RATE TO BINARY ; IF PMMI OR DCH CVBIN: LXI D,FCB+9 ;TO ASCII VALUE LXI H,0 ;INIT BINARY RESULT ; DECLP LDAX D ;GET ASCII DIGIT INX D ;TO NEXT DIGIT CPI ' ' ;BLANK ONE? JZ DECLP ;..YES, SKIP IT CPI '0' ;VAMIDATE IT JC BADRATE ;ERROR CPI '9'+1 ;VALIDATE JNC BADRATE ;ERROR SUI '0' ;MAKE DIGIT BINARY ; ; MULTIPLY PREV VALUE BY 10 ; MOV B,H ;SET UP FOR MOV C,L ;MULTIPLY BY 10 DAD H ;MULTIPLY BY 2 DAD H ;X 2 = 4 DAD B ;+ 1 = 5 DAD H ;X 2 = 10 ADD L ;ADD IN DIGIT MOV L,A ;SAVE BACK JNZ DIGNC ;NO CARRY? INR H ;ADD IN CARRY ; ; CHECK IF DONE ; DIGNC MOV A,E ;SEE IF PAST CPI FCB+12 ;..LAST DIGIT JNZ DECLP ;NO, LOOP RET ; ; INVALID BAUD RATE ; BADRATE CALL ERXIT DB '++Invalid baud rate++',CR,LF,'$' ENDIF ;PMMI OR DCH ; ; THE FOLLOWING PROVIDES A RETURN FROM INITMOD ; IF (NOT PMMI) AND (NOT DCH) RET ;**THIS MUST BE HERE** ENDIF ;(NOT PMMI) AND (NOT DCH) ; ;----> MOVEFCB: MOVES FCB(2) TO FCB ; ; I ATTEMPTED TO MAKE THE MODEM COMMAND 'NATURAL', ; I.E. MODEM SEND FILENAME (MODEM S FN.FT) RATHER ; THAN MODEM FILENAME SEND (MODEM FN.FT S) SO THIS ; ROUTINE MOVES THE FILENAME FROM THE SECOND FCB ; TO THE FIRST ; MOVEFCB LXI H,FCB+16 ;FROM LXI D,FCB ;TO MVI B,16 ;LEN CALL MOVE ;DO THE MOVE XRA A ;GET 0 STA FCBSNO ;ZERO SECTOR # STA FCBEXT ;..AND EXTENT RET ; ;----> SHOW: SHOWS CHAR SENT/RECEIVED ; ; CR, LF, AND TAB ARE SHOWN. ALL OTHER ; NON-PRINTABLE CHARACTERS ARE SHOWN IN ; HEX AS (XX) ; SHOW CPI LF ;LF? JZ CTYPE ;..YES, TYPE IT CPI CR ;CR? JZ CTYPE ;..YES, TYPE IT CPI 09 ;TAB JZ CTYPE ;..YES, TYPE IT CPI ' ' ;CTL-CHR? JC SHOWHEX ;YES, SHOW IN HEX CPI 7FH ;DEL? JC CTYPE ;NO, TYPE THE CHAR ; SHOWHEX PUSH PSW ;SAVE THE CHAR MVI A,'(' ;TYPE.. CALL CTYPE ;..'(' POP PSW ;THEN.. CALL HEXO ;..THE CHAR MVI A,')' ;THEN.. JMP CTYPE ;..')' AND RETURN. ; ;----> CTYPE: TYPES VIA CP/M SO TABS ARE EXPANDED ; CTYPE PUSH B ;SAVE.. PUSH D ;..ALL.. PUSH H ;..REGS MOV E,A ;CHAR TO E MVI C,WRCON ;GET BDOS FNC CALL BDOS ;PRIN THE CHR POP H ;RESTORE.. POP D ;..ALL.. POP B ;..REGS RET ;FROM "CTYPE" ; CRLF MVI A,CR CALL TYPE MVI A,LF ; ;----> TYPE: TYPE VIA DIRECT CBIOS ACCESS. ; WE ASSUME CBIOS MAY DESTROY SOME REGISTERS, ; SO SAVE THEM ALL. ; ; THIS ROUTINE BYPASSES CP/M'S CTL-S, CTL-C ; TESTS. ; TYPE PUSH PSW ;SAVE CHAR PUSH B ;AND OTHER REGISTERS PUSH D PUSH H MOV C,A ;FOR BIOS VTYPE CALL $-$ ;MODIFIED AT INIT POP H ;RESTORE REGISTERS POP D POP B POP PSW ;..AND CHAR RET ;FROM "TYPE" ; ;----> STAT: KEYBOARD STATUS ; ; SAVE ALL REGISTERS, EXCEPT A, IN CASE ; CBIOS CLOBBERS THEM. ; STAT PUSH B PUSH D PUSH H VSTAT CALL $-$ ;ADDR SET AT INIT POP H POP D POP B ORA A ;0 => NOT READY RET ; ;----> KEYIN: KEYBOARD INPUT ; ; SAVE ALL REGISTERS, EXCEPT A, IN CASE ; CBIOS CLOBBERS THEM. ; KEYIN PUSH B PUSH D PUSH H VKEYIN CALL $-$ ;ADDR SET AT INIT POP H POP D POP B ANI 7FH ;STRIP PARITY IF THERE RET ;FROM KEYIN ; ;----> HEXO: HEX OUTPUT ; HEXO PUSH PSW ;SAVE FOR RIGHT DIGIT RAR ;RIGHT.. RAR ;..JUSTIFY.. RAR ;..LEFT.. RAR ;..DIGIT.. CALL NIBBL ;PRINT LEFT DIGIT POP PSW ;RESTORE RIGHT ; NIBBL ANI 0FH ;ISOLATE DIGIT CPI 10 ;IS IS <10? JC ISNUM ;YES, NOT ALPHA ADI 7 ;ADD ALPHA BIAS ; ISNUM ADI '0' ;MAKE PRINTABLE JMP TYPE ;..THEN TYPE IT ; ;----> CKQUIT: QUIT/RETRY AFTER X8251 MULTIPLE ERRORS ; ; RETURNS W/ZERO SET IF "RETRY" ASKED FOR ; CKQUIT XRA A ;ZERO.. STA ERRCT ;..ERROR COUNT CALL ILPRT ;PRINT: DB BELL,'Multiple errors encountered. ' DB 'Type ''Q'' to quit, ''R'' to retry: ',0 CALL KEYIN ;QUIT/RETRY PUSH PSW CALL TYPE CALL CRLF POP PSW ANI 5FH ;MAKE UPPER CASE CPI 'R' ;RETRY? RZ ;'KEEP ON TRUCKIN' CPI 'Q' ;QUIT? JNZ CKQUIT ;NO, ASK AGAIN ORA A ;SET NON-ZERO RET ; ;----> ILPRT: INLINE PRINT OF MSG ; ; THE CALL TO ILPRT IS FOLLOWED BY A MESSAGE, ; BINARY 0 AS THE END. BINARY 1 MAY BE USED TO ; PAUSE (MESSAGE 'PRESS RETURN TO CONTINUE') ; ILPRT XTHL ;SAVE HL, GET HL=MSG ; ILPLP MOV A,M ;GET CHAR ORA A ;END OF MSG? JZ ILPRET ;..YES, RETURN CPI 1 ;PAUSE WITH MSG? JZ ILPAUSE ;..YES CPI 2 ;PAUSE, NO MSG? JZ ILPAUSE1 ;..YES CALL CTYPE ;TYPE THE MSG ; ILPNEXT INX H ;TO NEXT CHAR JMP ILPLP ;LOOP ; ; PAUSE WHILE TYPING HELP SO INFO DOESN'T ; SCROLL OFF OF VIDEO SCREENS ; ILPAUSE CALL ILPRT ;PRINT: DB CR,LF,'Press RETURN to continue: ',0 ILPAUSE1 CALL KEYIN ;GET ANY CHAR CPI 'C'-40H ;REBOOT? JZ EXIT ;YES. CALL ILPRT ;PRINT DB CR,LF,0 JMP ILPNEXT ;LOOP ; ILPRET XTHL ;RESTORE HL RET ;PAST MSG ; ;----> PRTMSG: PRINTS MSG POINTED TO BY (DE) ; ; A '$' IS THE ENDING DELIMITER FOR THE PRINT. ; NO REGISTERS SAVED. ; PRTMSG MVI C,PRINT ;GET BDOS FNC JMP BDOS ;PRINT MESSAGE, RETURN ; ;----> ERXIT: EXIT PRINTING MSG FOLLOWING CALL ; ERXIT POP D ;GET MESSAGE CALL PRTMSG ;PRINT IT CALL CKDIS ;DISCONNECT? ; EXIT CALL ILPRT ;PRINT: DB CR,LF,0 LHLD STACK ;GET ORIGINAL STACK SPHL ;RESTORE IT RET ;--EXIT-- TO CP/M ; ; MOVE 128 CHARACTERS ; MOVE128 MVI B,128 ;SET MOVE COUNT ; ; MOVE FROM (HL) TO (DE) LENGTH IN (B) ; MOVE MOV A,M ;GET A CHAR STAX D ;STORE IT INX H ;TO NEXT "FROM" INX D ;TO NEXT "TO" DCR B ;MORE? JNZ MOVE ;..YES, LOOP RET ;..NO, RETURN ;************************************************************************ ;* CRCSUBS (Cyclic Redundancy Code Subroutines) version 1.20 * ;* 8080 Mnemonics * ;* * ;* These subroutines will compute and check a true 16-bit * ;* Cyclic Redundancy Code for a message of arbitrary length. * ;* * ;* The use of this scheme will guarantee detection of all * ;* single and double bit errors, all errors with an odd * ;* number of error bits, all burst errors of length 16 or * ;* less, 99.9969% of all 17-bit error bursts, and 99.9984% * ;* of all possible longer error bursts. (Ref: Computer * ;* Networks, Andrew S. Tanenbaum, Prentiss-Hall, 1981) * ;* * ;* * ;* There are four entry points, which are used as follows: * ;* * ;* CLRCRC - A call to this entry resets the CRC accumulator. * ;* It must be called at the start of each message. * ;* * ;* Entry Parameters: None. * ;* * ;* Exit Conditions: CRC accumulator cleared. * ;* All registers preserved. * ;* * ;* * ;* UPDCRC - A call to this entry updates the CRC accumulator. * ;* It must be called once for each byte in the * ;* message for which the CRC is being calculated. * ;* * ;* Entry Parameters: (A) = a byte to be included * ;* in the CRC calculation. * ;* * ;* Exit Conditions: CRC accumulator updated. * ;* All registers preserved. * ;* * ;* * ;* FINCRC - A call to this entry finishes the CRC calculation * ;* for a message which is to be TRANSMITTED. It must * ;* be called after the last byte of the message has * ;* been passed thru UPDCRC. It returns the calculated * ;* CRC bytes, which must be transmitted as the final * ;* two bytes of the message (first D, then E). * ;* * ;* Entry Parameters: None. * ;* * ;* Exit Conditions: (DE) = calculated CRC bytes. * ;* All other registers preserved. * ;* * ;* * ;* CHKCRC - A call to this routine checks the CRC bytes of * ;* a RECEIVED message and returns a code to indicate * ;* whether the message was received correctly. It must * ;* be called after the message AND the two CRC bytes * ;* have been received AND passed thru UPDCRC. * ;* * ;* Entry Parameters: None. * ;* * ;* Exit Conditions: (A) = 0 if message ok. * ;* (A) = -1 if message garbled. * ;* All other registers preserved. * ;* * ;************************************************************************ ;* * ;* Designed & coded by Paul Hansknecht, June 13, 1981 * ;* * ;* * ;* Copyright (c) 1981, Carpenter Associates * ;* Box 451 * ;* Bloomfield Hills, MI 48013 * ;* 313/855-3074 * ;* * ;* This program may be freely reproduced for non-profit use. * ;* * ;************************************************************************ ; CLRCRC: EQU $ ; Reset CRC Accumulator for a new message. PUSH H LXI H,0 SHLD CRCVAL POP H RET ; UPDCRC: EQU $ ; Update CRC Accumulator using byte in (A). PUSH PSW PUSH B PUSH H MVI B,8 MOV C,A LHLD CRCVAL ; UPDLOOP:MOV A,C RLC MOV C,A MOV A,L RAL MOV L,A MOV A,H RAL MOV H,A JNC SKIPIT MOV A,H ; The generator is X^16 + X^12 + X^5 + 1 XRI 10H ; as recommended by CCITT. MOV H,A ; An alternate generator which is often MOV A,L ; used in synchronous transmission protocols XRI 21H ; is X^16 + X^15 + X^2 + 1. This may be MOV L,A ; used by substituting XOR 80H for XOR 10H SKIPIT: DCR B ; and XOR 05H for XOR 21H in the adjacent code. JNZ UPDLOOP SHLD CRCVAL POP H POP B POP PSW RET ; FINCRC: EQU $ ; Finish CRC calc for outbound message. PUSH PSW XRA A CALL UPDCRC CALL UPDCRC PUSH H LHLD CRCVAL MOV D,H MOV E,L POP H POP PSW RET ; CHKCRC: EQU $ ; Check CRC bytes of received message. PUSH H LHLD CRCVAL MOV A,H ORA L POP H RZ MVI A,0FFH RET ; CRCVAL DW 0 ;CRC VALUE STORAGE ; OPTION DB 0 ;PRIMARY OPTION ; ; DATAFLG IS USED BY THE "V" SUBCOMMAND - ; IT IS 0 WHEN A HEADER OR CKSUM IS BEING ; SENT/RCD, AND 1 IF "VIEWABLE" DATA (THE ; SECTOR ITSELF) ; DATAFLG DB 0 ;AT HEADER, FIRST ; ; SUB-OPTION TABLE. IF AN OPTION IS IN EFFECT, ; THE CHARACTER IS SET TO BINARY 0 ; OPTBL EQU $ ANSWFLG DB 'A' ;ANSWER MODE DISCFLG DB 'D' ;DISCONNECT WHEN DONE ECHOFLG DB 'E' ;TO ECHO AFTER XFER ORIGFLG DB 'O' ;ORIGINATE MODE QFLG DB 'Q' ;QUIET TRANSFER (NO MSGS) RSEEFLG DB 'R' ;SEE WHAT'S RECEIVED SSEEFLG DB 'S' ;SEE WHAT'S SENT TERMFLG DB 'T' ;TO TERM AFTER XFER VSEEFLG DB 'V' ;VIEW MESSAGES (NO HDR, ETC) CRCFLG DB 'C' ;USE CRC INSTEAD OF CHECKSUM OPTBE EQU $ ;END OF OPTIONS ; FIRST DB 0FFH ;FLAG FOR FIRST TIME THRU SND OR RCV FIRSTME DB 0FFH ;FLAG FOR FIRST SOH RCVD IN CRC MODE ; MAXEXT DB 0 ;EXT COUNT USED BY 'CNREC' RCNT DW 0 ;EXTENT RECORD COUNT USED BY 'CNREC' RCVSNO DB 0 ;SECT # RECEIVED SECTNO: DW 0 ;CURRENT SECTOR NUMBER (LO, THEN HI) ERRCT DB 0 ;ERROR COUNT ERRCDE DB 0 ;RECEIVE ERROR CODE HOLDD DB 86H ;DC HAYES MODEM DEFAULT HOLDING AREA ; ; FOLLOWING USED BY ASCII CAPTURE AND PRINTER FUNCTIONS ; CPTRFLG DB 0 ;CAPTURE ENABLED FLAG PRTRFLG DB 0 ;PRINTER ENABLED FLAG ASCFCB DS 33 ;CAPTURE FCB MEMEND DS 1 ;LAST PAGE OF TPA CAPPTR DS 2 ;BUFFER POINTER ; ; FOLLOWING 3 USED BY DISK BUFFERING ROUTINES ; EOFLG DB 0 ;EOF FLAG (1=TRUE) SECPTR DW DBUF SECINBF DB 0 ;# OF SECTORS IN BUFFER ; DB 055H,0AAH ;GUARD BYTES TO HELP ; IDENTIFY STACK OVERFLOWS, ; NOT USED BY PROGRAM, ONLY ; FOR DUMP ANALYSIS DS 128 ;STACK AREA STACK DS 2 ;STACK POINTER ; ; DISK BUFFER (OVERLAYS HELP MSGS), SIZE=128*DBUFSIZ*8. ; NO PROGRAM CHECK IS DONE TO VERIFY THAT THE BUFFER ; WILL NOT OVERLAY THE CCP AND/OR BDOS ON A GIVEN SYSTEM, ; SO THE BURDEN IS ON THE USER TO MAKE SURE OF THIS. ; A REASONABLE BUFFER SIZE IS 16K. TRADITIONALLY, BUFFER ; SIZE HAS BEEN 2K. ; DBUF EQU $ ; ; ASCII CAPTURE BUFFER, MUST START ON PAGE BOUNDARY ; ASCBUF: EQU DBUF+0FFH AND 0FF00H ;USE SAME DISK BUFFER FOR ASCII ;CAPTURE, SINCE CAPTURE NOT DONE ;WHILE XFER IN PROGRESS. TO HAVE SEPARATE BUFFERS LIKE IN ;MODEM220: ASCBUF EQU (DBUF+(DBUFSIZ*1024)+0FFH) AND 0FF00H ; ; INVALID COMMAND ; BADOPT PUSH PSW ;SAVE BAD OPTION CALL CRLF CALL ILPRT DB '++''',0 POP PSW ;RETRIEVE BAD OPTION CALL TYPE ;PRINT BAD OPTION CALL ILPRT ;EXIT W/ERROR DB ''' is an invalid MODEM command option++',CR,LF,CR,LF DB 'Press RETURN for help, Ctl-C to exit: ',2,0 ; HELP CALL ILPRT DB '(T)erminal and (E)cho mode commands:',CR,LF DB ' Ctl-Y = Ascii capture enable/disable toggle',CR,LF DB ' Ctl-E = Exit to CP/M',CR,LF DB ' Ctl-D = Disconnect phone',CR,LF DB ' Ctl-P = Printer enable/disable toggle',CR,LF,CR,LF DB 'Format for command is:',CR,LF,CR,LF DB 'MODEM # Filename',CR,LF,CR,LF DB 'Where # is a 1 character primary option,',CR,LF DB ' which may be followed by sub-options,',CR,LF DB ' and by ".xxx" to set baud rate to xxx',CR,LF,CR,LF,1 DB 'Primary Options:',CR,LF,CR,LF DB ' S to send a file',CR,LF DB ' R to receive a file',CR,LF DB ' T to act as a terminal',CR,LF DB ' E to act as a computer (echo data)',CR,LF DB ' D to disconnect the phone',CR,LF DB ' H to print this help file',CR,LF,CR,LF,1 DB 'Secondary options:',CR,LF DB ' A answer mode',CR,LF DB ' O originate mode',CR,LF DB ' D disconnect after execution',CR,LF DB ' T go to terminal mode after file xfer',CR,LF DB ' E go to echo mode after file xfer',CR,LF DB ' Q quiet mode - no status msgs',CR,LF DB ' R show chars received',CR,LF DB ' S show chars sent',CR,LF DB ' V view file sent/received (no status)',CR,LF DB ' C use cyclic redundancy check for file xfers',CR,LF DB CR,LF,'For examples, type: MODEM X',CR,LF,0 JMP EXIT ; EXAM CALL ILPRT DB 'Send file, originate mode, 300 baud:',CR,LF DB ' MODEM SO fn.ft',CR,LF DB 'Send another file:',CR,LF DB ' MODEM S fn/ft',CR,LF DB 'Then send a third file at 450 baud and disconnect:' DB CR,LF,' MODEM SD.450 fn.ft',CR,LF DB 'Act as a terminal, originate mode, at 110 baud:',CR,LF DB ' MODEM TO.110',CR,LF DB ' (Use ctl-D to disconnect)',CR,LF DB 'Receive file, answer mode, view it, 600 baud:',CR,LF DB ' MODEM RAV.600 fn.ft',CR,LF DB 'Receive file, use cyclic redundancy check, 600 baud:',CR,LF DB ' MODEM RC.600 fn,ft',CR,LF DB 'Turn printer mode on/off in terminal or echo mode:',CR,LF DB ' ^P (printer now toggled)',CR,LF DB 'Turn on ascii capture mode:',CR,LF DB ' ^Y ',CR,LF DB ' FILE NAME --> b:test.doc [CR] (file now open)',CR,LF DB 'Turn off ascii capture mode:',CR,LF DB ' ^Y (ascii capture disabled, file closed)',CR,LF,0 JMP EXIT ; ; BDOS EQUATES (VERSION 2) ; RDCON EQU 1 WRCON EQU 2 PRINT EQU 9 CONST EQU 11 ;CONSOLE STAT OPEN EQU 15 ;0FFH=NOT FOUND CLOSE EQU 16 ; " " SRCHF EQU 17 ; " " SRCHN EQU 18 ; " " ERASE EQU 19 ;NO RET CODE READ EQU 20 ;0=OK- 1=EOF WRITE EQU 21 ;0=OK, 1=ERR, 2=?, 0FFH=NO DIR SPC MAKE EQU 22 ;0FFH=BAD REN EQU 23 ;0FFH=BAD STDMA EQU 26 ;SET DMA BDOS EQU BASE+5 REIPL EQU BASE FCB EQU BASE+5CH ;SYSTEM FCB FCBEXT EQU FCB+12 ;FILE EXTENT FCBSNO EQU FCB+32 ;SECTOR # FCB2 EQU FCB+6CH ;2ND FCB END