home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ftp.barnyard.co.uk
/
2015.02.ftp.barnyard.co.uk.tar
/
ftp.barnyard.co.uk
/
cpm
/
walnut-creek-CDROM
/
CPM
/
MODEMS
/
MODEM2
/
MODM221A.ASM
< prev
next >
Wrap
Assembly Source File
|
2000-06-30
|
88KB
|
3,384 lines
;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